From 00032d696d9ddfa847ba08ba1df4a11b72505825 Mon Sep 17 00:00:00 2001 From: Thrilok Kumar Date: Fri, 1 May 2020 21:32:17 +0530 Subject: [PATCH] Added instaPool connector --- contracts/protocols/instaPool.sol | 315 ++++++++++++++++++++++++++++++ 1 file changed, 315 insertions(+) create mode 100644 contracts/protocols/instaPool.sol diff --git a/contracts/protocols/instaPool.sol b/contracts/protocols/instaPool.sol new file mode 100644 index 0000000..5d04380 --- /dev/null +++ b/contracts/protocols/instaPool.sol @@ -0,0 +1,315 @@ +pragma solidity ^0.6.0; +pragma experimental ABIEncoderV2; + +interface LiqudityInterface { + function deposit(address, uint) external payable; + function withdraw(address, uint) external; + + function accessLiquidity(address[] calldata, uint[] calldata) external; + function returnLiquidity(address[] calldata) external payable; + + function isTknAllowed(address) external view returns(bool); + function tknToCTkn(address) external view returns(address); + function liquidityBalance(address, address) external view returns(uint); +} + +interface CTokenInterface { + function borrowBalanceCurrent(address account) external returns (uint); + function balanceOf(address owner) external view returns (uint256 balance); + function repayBorrowBehalf(address borrower, uint repayAmount) external returns (uint); // For ERC20 +} + +interface CETHInterface { + function borrowBalanceCurrent(address account) external returns (uint); + function repayBorrowBehalf(address borrower) external payable; +} + + +interface TokenInterface { + function allowance(address, address) external view returns (uint); + function balanceOf(address) external view returns (uint); + function approve(address, uint) external; + function transfer(address, uint) external returns (bool); + function transferFrom(address, address, uint) external returns (bool); +} + +interface MemoryInterface { + function getUint(uint _id) external returns (uint _num); + function setUint(uint _id, uint _val) external; +} + +interface EventInterface { + function emitEvent(uint _connectorType, uint _connectorID, bytes32 _eventCode, bytes calldata _eventData) external; +} + +contract DSMath { + + function add(uint x, uint y) internal pure returns (uint z) { + require((z = x + y) >= x, "math-not-safe"); + } + + function mul(uint x, uint y) internal pure returns (uint z) { + require(y == 0 || (z = x * y) / y == x, "math-not-safe"); + } + + uint constant WAD = 10 ** 18; + + function wmul(uint x, uint y) internal pure returns (uint z) { + z = add(mul(x, y), WAD / 2) / WAD; + } + + function wdiv(uint x, uint y) internal pure returns (uint z) { + z = add(mul(x, WAD), y / 2) / y; + } + +} + + +contract Helpers is DSMath { + /** + * @dev Return ethereum address + */ + function getAddressETH() internal pure returns (address) { + return 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE; // ETH Address + } + + /** + * @dev Return Memory Variable Address + */ + function getMemoryAddr() internal pure returns (address) { + return 0x8a5419CfC711B2343c17a6ABf4B2bAFaBb06957F; // InstaMemory Address + } + + /** + * @dev Return InstaEvent Address. + */ + function getEventAddr() internal pure returns (address) { + return 0x2af7ea6Cb911035f3eb1ED895Cb6692C39ecbA97; // InstaEvent Address + } + + /** + * @dev Get Uint value from InstaMemory Contract. + */ + function getUint(uint getId, uint val) internal returns (uint returnVal) { + returnVal = getId == 0 ? val : MemoryInterface(getMemoryAddr()).getUint(getId); + } + + /** + * @dev Set Uint value in InstaMemory Contract. + */ + function setUint(uint setId, uint val) internal { + if (setId != 0) MemoryInterface(getMemoryAddr()).setUint(setId, val); + } + + /** + * @dev Connector Details + */ + function connectorID() public pure returns(uint _type, uint _id) { + (_type, _id) = (1, 8); + } +} + + +contract LiquidityHelpers is Helpers { + /** + * @dev Return InstaPool address + */ + function getLiquidityAddress() internal pure returns (address) { + return 0x1879BEE186BFfBA9A8b1cAD8181bBFb218A5Aa61; + } +} + + +contract LiquidityManage is LiquidityHelpers { + + event LogDepositLiquidity(address indexed token, uint256 tokenAmt, uint256 getId, uint256 setId); + event LogWithdrawLiquidity(address indexed token, uint256 tokenAmt, uint256 getId, uint256 setId); + + /** + * @dev Deposit Liquidity in InstaPool. + * @param token token address.(For ETH: 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE) + * @param amt token amount. + * @param getId Get token amount at this ID from `InstaMemory` Contract. + * @param setId Set token amount at this ID in `InstaMemory` Contract. + */ + function deposit(address token, uint amt, uint getId, uint setId) external payable { + uint _amt = getUint(getId, amt); + + uint ethAmt; + if (token == getAddressETH()) { + _amt = _amt == uint(-1) ? address(this).balance : _amt; + ethAmt = _amt; + } else { + _amt = _amt == uint(-1) ? TokenInterface(token).balanceOf(address(this)) : _amt; + TokenInterface(token).approve(getLiquidityAddress(), _amt); + } + + LiqudityInterface(getLiquidityAddress()).deposit.value(ethAmt)(token, _amt); + setUint(setId, _amt); + + emit LogDepositLiquidity(token, _amt, getId, setId); + bytes32 _eventCode = keccak256("LogDepositLiquidity(address,uint256,uint256,uint256)"); + bytes memory _eventParam = abi.encode(token, _amt, getId, setId); + (uint _type, uint _id) = connectorID(); + EventInterface(getEventAddr()).emitEvent(_type, _id, _eventCode, _eventParam); + } + + /** + * @dev Withdraw Liquidity in InstaPool. + * @param token token address.(For ETH: 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE) + * @param amt token amount. + * @param getId Get token amount at this ID from `InstaMemory` Contract. + * @param setId Set token amount at this ID in `InstaMemory` Contract. + */ + function withdraw(address token, uint amt, uint getId, uint setId) external payable { + uint _amt = getUint(getId, amt); + + LiqudityInterface(getLiquidityAddress()).withdraw(token, _amt); + setUint(setId, _amt); + + emit LogWithdrawLiquidity(token, _amt, getId, setId); + bytes32 _eventCode = keccak256("LogWithdrawLiquidity(address,uint256,uint256,uint256)"); + bytes memory _eventParam = abi.encode(token, _amt, getId, setId); + (uint _type, uint _id) = connectorID(); + EventInterface(getEventAddr()).emitEvent(_type, _id, _eventCode, _eventParam); + } +} + + +contract LiquidityAccess is LiquidityManage { + event LogFlashBorrow(address indexed token, uint256 tokenAmt, uint256 getId, uint256 setId); + event LogFlashPayback(address indexed token, uint256 tokenAmt, uint256 getId, uint256 setId); + + /** + * @dev Access Token Liquidity from InstaPool. + * @param token token address.(For ETH: 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE) + * @param amt token amount. + * @param getId Get token amount at this ID from `InstaMemory` Contract. + * @param setId Set token amount at this ID in `InstaMemory` Contract. + */ + function flashBorrow(address token, uint amt, uint getId, uint setId) external payable { + uint _amt = getUint(getId, amt); + + address[] memory _tknAddrs = new address[](1); + _tknAddrs[0] = token; + uint[] memory _amts = new uint[](1); + _amts[0] = _amt; + + LiqudityInterface(getLiquidityAddress()).accessLiquidity(_tknAddrs, _amts); + + setUint(setId, _amt); + + emit LogFlashBorrow(token, _amt, getId, setId); + bytes32 _eventCode = keccak256("LogFlashBorrow(address,uint256,uint256,uint256)"); + bytes memory _eventParam = abi.encode(token, _amt, getId, setId); + (uint _type, uint _id) = connectorID(); + EventInterface(getEventAddr()).emitEvent(_type, _id, _eventCode, _eventParam); + } + + /** + * @dev Return Token Liquidity from InstaPool. + * @param token token address.(For ETH: 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE) + * @param getId Get token amount at this ID from `InstaMemory` Contract. + * @param setId Set token amount at this ID in `InstaMemory` Contract. + */ + function flashPayback(address token, uint getId, uint setId) external payable { + LiqudityInterface liquidityContract = LiqudityInterface(getLiquidityAddress()); + uint _amt; + + if (token == getAddressETH()) { + CETHInterface cethContract = CETHInterface(liquidityContract.tknToCTkn(token)); + _amt = cethContract.borrowBalanceCurrent(address(liquidityContract)); + cethContract.repayBorrowBehalf.value(_amt)(address(liquidityContract)); + } else { + CTokenInterface ctokenContract = CTokenInterface(liquidityContract.tknToCTkn(token)); + _amt = ctokenContract.borrowBalanceCurrent(address(liquidityContract)); + TokenInterface(token).approve(address(ctokenContract), _amt); + require(ctokenContract.repayBorrowBehalf(address(liquidityContract), _amt) == 0, "repay-failed"); + } + + setUint(setId, _amt); + + emit LogFlashPayback(token, _amt, getId, setId); + bytes32 _eventCode = keccak256("LogFlashPayback(address,uint256,uint256,uint256)"); + bytes memory _eventParam = abi.encode(token, _amt, getId, setId); + (uint _type, uint _id) = connectorID(); + EventInterface(getEventAddr()).emitEvent(_type, _id, _eventCode, _eventParam); + } + + /** + * @dev Access Multiple Token liquidity from InstaPool. + * @param tokens Array of token addresses.(For ETH: 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE) + * @param amts Array of token amount. + * @param getId get token amounts at this IDs from `InstaMemory` Contract. + * @param setId set token amounts at this IDs in `InstaMemory` Contract. + */ + function flashMultiBorrow( + address[] calldata tokens, + uint[] calldata amts, + uint[] calldata getId, + uint[] calldata setId + ) external payable { + uint _length = tokens.length; + uint[] memory _amts = new uint[](_length); + for (uint i = 0; i < _length; i++) { + _amts[i] = getUint(getId[i], amts[i]); + } + + LiqudityInterface(getLiquidityAddress()).accessLiquidity(tokens, _amts); + + for (uint i = 0; i < _length; i++) { + setUint(setId[i], _amts[i]); + + emit LogFlashBorrow(tokens[i], _amts[i], getId[i], setId[i]); + bytes32 _eventCode = keccak256("LogFlashBorrow(address,uint256,uint256,uint256)"); + bytes memory _eventParam = abi.encode(tokens[i], _amts[i], getId[i], setId[i]); + (uint _type, uint _id) = connectorID(); + EventInterface(getEventAddr()).emitEvent(_type, _id, _eventCode, _eventParam); + } + } + + /** + * @dev Return Multiple token liquidity from InstaPool. + * @param tokens Array of token addresses.(For ETH: 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE) + * @param getId get token amounts at this IDs from `InstaMemory` Contract. + * @param setId set token amounts at this IDs in `InstaMemory` Contract. + */ + function flashMultiPayback(address[] calldata tokens, uint[] calldata getId, uint[] calldata setId) external payable { + LiqudityInterface liquidityContract = LiqudityInterface(getLiquidityAddress()); + + uint _length = tokens.length; + + for (uint i = 0; i < _length; i++) { + + for (uint j = 0; j < _length; j++) { + if (tokens[i] == tokens[j] && i != j) require(false, "tkn-repeated"); + } + + uint _amt; + + if (tokens[i] == getAddressETH()) { + CETHInterface cethContract = CETHInterface(liquidityContract.tknToCTkn(tokens[i])); + _amt = cethContract.borrowBalanceCurrent(address(liquidityContract)); + cethContract.repayBorrowBehalf.value(_amt)(address(liquidityContract)); + } else { + CTokenInterface ctokenContract = CTokenInterface(liquidityContract.tknToCTkn(tokens[i])); + _amt = ctokenContract.borrowBalanceCurrent(address(liquidityContract)); + TokenInterface(tokens[i]).approve(address(ctokenContract), _amt); + require(ctokenContract.repayBorrowBehalf(address(liquidityContract), _amt) == 0, "repay-failed"); + } + + setUint(setId[i], _amt); + + emit LogFlashPayback(tokens[i], _amt, getId[i], setId[i]); + bytes32 _eventCode = keccak256("LogFlashPayback(address,uint256,uint256,uint256)"); + bytes memory _eventParam = abi.encode(tokens[i], _amt, getId[i], setId[i]); + (uint _type, uint _id) = connectorID(); + EventInterface(getEventAddr()).emitEvent(_type, _id, _eventCode, _eventParam); + } + } +} + + +contract ConnectInstaPool is LiquidityAccess { + string public name = "InstaPool-v1.1"; +} \ No newline at end of file