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 }