pragma solidity ^0.5.7; interface RegistryInterface { function proxies(address) external view returns (address); } interface UserWalletInterface { function owner() external view returns (address); } interface ERC20Interface { 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 CTokenInterface { function mint(uint mintAmount) external returns (uint); // For ERC20 function redeem(uint redeemTokens) external returns (uint); function borrow(uint borrowAmount) external returns (uint); function transfer(address, uint) external returns (bool); function transferFrom(address, address, uint) external returns (bool); function repayBorrow(uint repayAmount) external returns (uint); // For ERC20 function underlying() external view returns (address); } interface CETHInterface { function mint() external payable; // For ETH function repayBorrow() external payable; // For ETH function transfer(address, uint) external returns (bool); } interface ComptrollerInterface { function enterMarkets(address[] calldata cTokens) external returns (uint[] memory); function exitMarket(address cTokenAddress) external returns (uint); } 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; } function sub(uint a, uint b) internal pure returns (uint c) { require(b <= a, "SafeMath: subtraction overflow"); c = a - b; } } contract Helper is DSMath { address public ethAddr = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE; address public daiAddr = 0x89d24A6b4CcB1B6fAA2625fE562bDD9a23260359; address public usdcAddr = 0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48; address public registry = 0x498b3BfaBE9F73db90D252bCD4Fa9548Cd0Fd981; address public comptrollerAddr = 0x3d9819210A31b4961b30EF54bE2aeD79B9c9Cd3B; address payable public adminOne = 0xd8db02A498E9AFbf4A32BC006DC1940495b4e592; address payable public adminTwo = 0x0f0EBD0d7672362D11e0b6d219abA30b0588954E; address public cEth = 0x4Ddc2D193948926D02f9B1fE9e1daa0718270ED5; address public cDai = 0xF5DCe57282A584D2746FaF1593d3121Fcac444dC; address public cUsdc = 0x39AA39c021dfbaE8faC545936693aC917d5E7563; } contract ProvideLiquidity is Helper { /** * @dev user's address => CToken Address => CToken Amount Deposited */ mapping (address => mapping (address => uint)) public deposits; event LogDepositCToken(address user, address ctknAddr, uint amt); event LogWithdrawCToken(address user, address ctknAddr, uint amt); /** * @dev Deposit CToken for liquidity */ function depositCTkn(address ctknAddr, uint amt) public { require(CTokenInterface(ctknAddr).transferFrom(msg.sender, address(this), amt), "Nothing to deposit"); deposits[msg.sender][ctknAddr] += amt; emit LogDepositCToken(msg.sender, ctknAddr, amt); } /** * @dev Withdraw CToken from liquidity */ function withdrawCTkn(address ctknAddr, uint amt) public returns(uint withdrawAmt) { require(deposits[msg.sender][ctknAddr] != 0, "Nothing to Withdraw"); withdrawAmt = amt < deposits[msg.sender][ctknAddr] ? amt : deposits[msg.sender][ctknAddr]; assert(CTokenInterface(ctknAddr).transfer(msg.sender, withdrawAmt)); deposits[msg.sender][ctknAddr] -= withdrawAmt; emit LogWithdrawCToken(msg.sender, ctknAddr, withdrawAmt); } } contract AccessLiquidity is ProvideLiquidity { event LogBorrowTknAndTransfer(address tknAddr, address ctknAddr, uint amt); event LogPayBorrowBack(address tknAddr, address ctknAddr, uint amt); /** * FOR SECURITY PURPOSE * checks if only InstaDApp contract wallets can access the bridge */ modifier isUserWallet { address userAdd = UserWalletInterface(msg.sender).owner(); address walletAdd = RegistryInterface(registry).proxies(userAdd); require(walletAdd != address(0), "not-user-wallet"); require(walletAdd == msg.sender, "not-wallet-owner"); _; } /** * @dev Borrow token and use them on InstaDApp's contract wallets */ function borrowTknAndTransfer(address ctknAddr, uint tknAmt) public isUserWallet { if (tknAmt > 0) { CTokenInterface ctknContract = CTokenInterface(ctknAddr); if (ctknAddr != cEth) { address tknAddr = ctknContract.underlying(); assert(ctknContract.borrow(tknAmt) == 0); assert(ERC20Interface(tknAddr).transfer(msg.sender, tknAmt)); emit LogBorrowTknAndTransfer(tknAddr, ctknAddr, tknAmt); } else { assert(ctknContract.borrow(tknAmt) == 0); msg.sender.transfer(tknAmt); emit LogBorrowTknAndTransfer(ethAddr, ctknAddr, tknAmt); } } } /** * @dev Payback borrowed token and from InstaDApp's contract wallets */ function payBorrowBack(address ctknAddr, uint tknAmt) public payable isUserWallet { if (tknAmt > 0) { if (ctknAddr != cEth) { CTokenInterface ctknContract = CTokenInterface(ctknAddr); address tknAddr = ctknContract.underlying(); assert(ctknContract.repayBorrow(tknAmt) == 0); emit LogPayBorrowBack(tknAddr, ctknAddr, tknAmt); } else { CETHInterface cEthContract = CETHInterface(ctknAddr); cEthContract.repayBorrow.value(tknAmt); emit LogPayBorrowBack(ethAddr, ctknAddr, tknAmt); } } } } contract AdminStuff is AccessLiquidity { modifier isAdmin { require(msg.sender == adminOne || msg.sender == adminTwo, "Not admin address"); _; } /** * Give approval to other addresses */ function setApproval(address erc20, address to) public isAdmin { ERC20Interface(erc20).approve(to, uint(-1)); } /** * (HIGHLY UNLIKELY TO HAPPEN) * collecting ETH if this contract has it */ function collectEth() public isAdmin { msg.sender.transfer(address(this).balance); } /** * Enter Compound Market to enable borrowing */ function enterMarket(address[] memory cTknAddrArr) public isAdmin { ComptrollerInterface troller = ComptrollerInterface(comptrollerAddr); troller.enterMarkets(cTknAddrArr); } /** * Enter Compound Market to disable borrowing */ function exitMarket(address cErc20) public isAdmin { ComptrollerInterface troller = ComptrollerInterface(comptrollerAddr); troller.exitMarket(cErc20); } } contract Liquidity is AdminStuff { /** * @dev setting up all required token approvals */ constructor() public { ERC20Interface(daiAddr).approve(cDai, uint(-1)); ERC20Interface(usdcAddr).approve(cUsdc, uint(-1)); ERC20Interface(cDai).approve(cDai, uint(-1)); ERC20Interface(cUsdc).approve(cUsdc, uint(-1)); ERC20Interface(cEth).approve(cEth, uint(-1)); } function() external payable {} }