/ contracts / finance / OptionToken.sol
OptionToken.sol
  1  pragma solidity >=0.6.0;
  2  pragma experimental ABIEncoderV2;
  3  
  4  import "../deployment/Deployer.sol";
  5  import "../finance/RedeemableToken.sol";
  6  import "../utils/ERC20.sol";
  7  import "../utils/Arrays.sol";
  8  import "../utils/SafeMath.sol";
  9  import "../interfaces/IUnderlyingVault.sol";
 10  
 11  contract OptionToken is RedeemableToken {
 12  
 13      using SafeMath for uint;
 14  
 15      mapping(address => uint) private _issued;
 16  
 17      string private constant _prefix = "DeFi Options DAO Option Redeemable Token: ";
 18      string private _symbol;
 19      uint private _unliquidatedVolume;
 20      address vaultAddr;
 21  
 22      constructor(string memory _sb, address _issuer, address _deployer)
 23          ERC20(string(abi.encodePacked(_prefix, _sb)))
 24          public
 25      {    
 26          _symbol = _sb;
 27          exchange = IOptionsExchange(_issuer);
 28          Deployer deployer = Deployer(_deployer);
 29          vaultAddr = deployer.getContractAddress("UnderlyingVault");
 30      }
 31  
 32      function name() override external view returns (string memory) {
 33          return string(abi.encodePacked(_prefix, _symbol));
 34      }
 35  
 36      function symbol() override external view returns (string memory) {
 37  
 38          return _symbol;
 39      }
 40  
 41      function issue(address from, address to, uint value) external {
 42  
 43          require(msg.sender == address(exchange), "issuance unallowed");
 44          _issued[from] = _issued[from].add(value);
 45          addBalance(to, value);
 46          _totalSupply = _totalSupply.add(value);
 47          _unliquidatedVolume = _unliquidatedVolume.add(value);
 48          emit Transfer(address(0), to, value);
 49      }
 50  
 51      function burn(uint value) external {
 52  
 53          burn(msg.sender, value);
 54      }
 55  
 56      function burn(address owner, uint value) public {
 57  
 58          require(
 59              msg.sender == owner || msg.sender == address(exchange),
 60              "burn sender unallowed"
 61          );
 62  
 63          uint b = balanceOf(owner);
 64          uint w = _issued[owner];
 65          require(
 66              b >= value && w >= value || (msg.sender == address(exchange) && w >= value),
 67              "invalid burn value"
 68          );
 69  
 70          if (msg.sender == owner) {
 71              removeBalance(owner, value);
 72              _totalSupply = _totalSupply.sub(value);
 73          }
 74          
 75          uint uc = uncoveredVolume(owner);
 76          uint coll = MoreMath.min(value, uc);
 77  
 78          w = w.sub(value);
 79          _issued[owner] = w;
 80          _unliquidatedVolume = _unliquidatedVolume.sub(value);
 81  
 82          uint udl = value > uc ? value.sub(uc) : 0;
 83  
 84          exchange.release(owner, udl, coll);
 85          exchange.cleanUp(owner, address(this));
 86  
 87          if (msg.sender == owner) {
 88              emit Transfer(owner, address(0), value);
 89          }
 90      }
 91  
 92      function writtenVolume(address owner) external view returns (uint) {
 93  
 94          return _issued[owner];
 95      }
 96  
 97      function totalWrittenVolume() public view returns (uint) {
 98          return _unliquidatedVolume;
 99      }
100  
101      function uncoveredVolume(address owner) public view returns (uint) {
102          uint covered = IUnderlyingVault(vaultAddr).balanceOf(owner, address(this));
103          uint w = _issued[owner];
104          return w > covered ? w.sub(covered) : 0;
105      }
106  
107      function redeemAllowed() override public view returns (bool) {
108          
109          return _unliquidatedVolume == 0;
110      }
111  
112      function afterRedeem(address owner, uint bal, uint) override internal {
113          exchange.cleanUp(owner, address(this));
114          emit Transfer(owner, address(0), bal);
115      }
116  
117      function emitTransfer(address from, address to, uint value) override internal {
118  
119          exchange.transferOwnership(_symbol, from, to, value);
120          emit Transfer(from, to, value);
121      }
122  }