FastPoolManagement.sol
1 pragma solidity >=0.6.0; 2 pragma experimental ABIEncoderV2; 3 4 import "./PoolManagementProposal.sol"; 5 import "../interfaces/IGovernableLiquidityPool.sol"; 6 import "../interfaces/IProposalManager.sol"; 7 import "../interfaces/IProposalWrapper.sol"; 8 import "../utils/SafeERC20.sol"; 9 10 contract FastPoolManagement { 11 using SafeERC20 for IERC20_2; 12 using SafeMath for uint256; 13 14 struct FPMLimitOrder { 15 address stableToken; 16 uint256 stableTokenValue; 17 bool isDeposit; 18 address proposalManagerAddr; 19 bytes _code; 20 bytes[] _executionBytes; 21 IProposalManager.Quorum quorum; 22 IProposalManager.VoteType voteType; 23 uint expiresAt; 24 address optionsExchangeAddr; 25 bytes[] _executionCreateOptionsBytes; 26 } 27 28 function deployProposeVoteExecute( 29 address proposalManagerAddr, 30 bytes memory _code, 31 bytes[] memory _executionBytes, 32 address poolAddress, 33 IProposalManager.Quorum quorum, 34 IProposalManager.VoteType voteType, 35 uint expiresAt, 36 bool isExecuteVote 37 ) public returns (address) { 38 address pmpAddr; 39 bytes memory _pmpBytes = _code; 40 //deploy proposal manager 41 assembly { 42 // create(v, p, n) 43 // v = amount of ETH to send 44 // p = pointer in memory to start of code 45 // n = size of code 46 pmpAddr := create(callvalue(), add(_pmpBytes, 0x20), mload(_pmpBytes)) 47 } 48 // return address 0 on error 49 require(pmpAddr != address(0), "proposasl failed init"); 50 51 //initialize proposal manager with propsoal data 52 PoolManagementProposal(pmpAddr).setExecutionBytes(_executionBytes); 53 54 //registered proposal 55 (uint pid, address proposalWrapperAddr) = IProposalManager(proposalManagerAddr).registerProposal( 56 pmpAddr, 57 poolAddress, 58 quorum, 59 voteType, 60 expiresAt 61 ); 62 63 //TODO: DOES NOT WORK IF TOKENS HAVE NOT BEEN TRANSFERED TO THIS CONTRACT, MAY NEED TO HAVE A WAY TO DELEGATE FOR POOL VOTES? 64 if (isExecuteVote) { 65 //vote on proposal 66 IProposalWrapper(proposalWrapperAddr).castVote(true); 67 68 //close proposal 69 IProposalWrapper(proposalWrapperAddr).close(); 70 } 71 72 return proposalWrapperAddr; 73 } 74 75 function bulkRegisterSymbols( 76 address optionsExchangeAddr, 77 bytes[] memory _executionBytes 78 ) public { 79 for (uint i=0; i< _executionBytes.length; i++) { 80 (bool success, ) = optionsExchangeAddr.call(_executionBytes[i]); 81 } 82 } 83 84 function createSyntheticLimitOrder( 85 FPMLimitOrder memory fpmOrder 86 ) public returns (address) { 87 /* 88 NOTE: MAY NOT WORK BECAUSE IT MAY USE TOO MUCH GAS 89 - POOL CREATION == HIGH GAS 90 - OPTION SYMBOL REGISTRATION == HIGH GAS 91 - PROPOSAL == HIGH GAS? 92 PROCESS: 93 - create pool (if pool does not exist for user) 94 - how to name params? default to addrs used for interaction? 95 - deposit collateral? 96 - approve fpm contract 97 - only needs to be done once for every new fpm deployment 98 - send stabls to fpm 99 - send stables to pool from fpm 100 -fpm sends llp to msg.sender 101 - bulkRegisterSymbols 102 - deployProposeVoteExecute 103 - if deposit, then no extra gov tx's needed 104 */ 105 106 bool isExecuteVote = false; 107 uint256 llpValueToTransfer = 0; 108 address poolAddr; 109 string memory poolName = toAsciiString(msg.sender); 110 poolAddr = IOptionsExchange(fpmOrder.optionsExchangeAddr).getPoolAddress(poolName); 111 112 if (poolAddr == address(0)) { 113 poolAddr = IOptionsExchange(fpmOrder.optionsExchangeAddr).createPool(poolName, poolName, false, address(0)); 114 } 115 116 // deposit collateral? 117 if(fpmOrder.isDeposit == true) { 118 llpValueToTransfer = processDeposit(poolAddr, fpmOrder.stableToken, fpmOrder.stableTokenValue); 119 isExecuteVote = true; 120 } 121 122 //register option symbols 123 bulkRegisterSymbols(fpmOrder.optionsExchangeAddr, fpmOrder._executionCreateOptionsBytes); 124 125 //create pool proposal 126 address proposalWrapperAddr = deployProposeVoteExecute( 127 fpmOrder.proposalManagerAddr, 128 fpmOrder._code, 129 fpmOrder._executionBytes, 130 poolAddr, 131 fpmOrder.quorum, 132 fpmOrder.voteType, 133 fpmOrder.expiresAt, 134 isExecuteVote 135 ); 136 137 // if vote was excuted, transfer llp tokens to msg.sender 138 if (isExecuteVote == true) { 139 IERC20_2(poolAddr).transfer(msg.sender, llpValueToTransfer); 140 } 141 142 return proposalWrapperAddr; 143 } 144 145 function processDeposit(address poolAddr, address stableToken, uint256 stableTokenValue) private returns (uint256) { 146 IERC20_2(stableToken).safeTransferFrom(msg.sender, address(this), stableTokenValue); 147 IERC20_2(stableToken).safeApprove(address(poolAddr), stableTokenValue); 148 149 // send stables to pool from fpm, fpm recives llp 150 //NOTE: IF FPM gets LLP, then FPM can auto close proposal 151 uint256 balBefore = IERC20_2(poolAddr).balanceOf(address(this)); 152 IGovernableLiquidityPool(poolAddr).depositTokens(address(this), stableToken, stableTokenValue); 153 uint256 balAfter = IERC20_2(poolAddr).balanceOf(address(this)); 154 uint256 llpValueToTransfer = balAfter.sub(balBefore); 155 156 return llpValueToTransfer; 157 } 158 159 function toAsciiString(address x) internal pure returns (string memory) { 160 bytes memory s = new bytes(40); 161 for (uint i = 0; i < 20; i++) { 162 bytes1 b = bytes1(uint8(uint(uint160(x)) / (2**(8*(19 - i))))); 163 bytes1 hi = bytes1(uint8(b) / 16); 164 bytes1 lo = bytes1(uint8(b) - 16 * uint8(hi)); 165 s[2*i] = char(hi); 166 s[2*i+1] = char(lo); 167 } 168 return string(s); 169 } 170 171 function char(bytes1 b) internal pure returns (bytes1 c) { 172 if (uint8(b) < 10) return bytes1(uint8(b) + 0x30); 173 else return bytes1(uint8(b) + 0x57); 174 } 175 }