RedeemableToken.sol
1 pragma solidity >=0.6.0; 2 pragma experimental ABIEncoderV2; 3 4 import "../utils/Arrays.sol"; 5 import "../utils/ERC20.sol"; 6 import "../utils/MoreMath.sol"; 7 import "../interfaces/IOptionsExchange.sol"; 8 9 abstract contract RedeemableToken is ERC20 { 10 11 using SafeMath for uint; 12 13 IOptionsExchange internal exchange; 14 15 function redeemAllowed() virtual public view returns(bool); 16 17 function redeem(address owner) external returns (uint value) { 18 19 address[] memory owners = new address[](1); 20 owners[0] = owner; 21 value = redeem(owners); 22 } 23 24 function redeem(address[] memory owners) public returns (uint value) { 25 26 require(redeemAllowed(), "redeem not allowed"); 27 28 uint valTotal = exchange.balanceOf(address(this)); 29 uint supplyTotal = _totalSupply; 30 uint supplyRemaining = _totalSupply; 31 32 for (uint i = 0; i < owners.length; i++) { 33 if (owners[i] != address(0)) { 34 (uint bal, uint val) = redeem(valTotal, supplyTotal, owners[i]); 35 value = value.add(val); 36 supplyRemaining = supplyRemaining.sub(bal); 37 } 38 } 39 40 _totalSupply = supplyRemaining; 41 } 42 43 function redeem(uint valTotal, uint supplyTotal, address owner) 44 private 45 returns (uint bal, uint val) 46 { 47 bal = balanceOf(owner); 48 49 if (bal > 0) { 50 uint b = 1e3; 51 val = MoreMath.round(valTotal.mul(bal.mul(b)).div(supplyTotal), b); 52 removeBalance(owner, bal); 53 exchange.transferBalance(owner, val); 54 } 55 56 afterRedeem(owner, bal, val); 57 } 58 59 function afterRedeem(address owner, uint bal, uint) virtual internal { 60 61 emitTransfer(owner, address(0), bal); 62 } 63 }