/ contracts / pools / FastPoolManagement.sol
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  }