diff --git a/contracts/ProxyLogics/InstaCompound.sol b/contracts/ProxyLogics/InstaCompound.sol new file mode 100644 index 0000000..5c179d9 --- /dev/null +++ b/contracts/ProxyLogics/InstaCompound.sol @@ -0,0 +1,321 @@ +pragma solidity ^0.5.7; + +interface CTokenInterface { + function redeem(uint redeemTokens) external returns (uint); + function redeemUnderlying(uint redeemAmount) external returns (uint); + function borrow(uint borrowAmount) external returns (uint); + function liquidateBorrow(address borrower, uint repayAmount, address cTokenCollateral) external returns (uint); + function liquidateBorrow(address borrower, address cTokenCollateral) external payable; + function exchangeRateCurrent() external returns (uint); + function getCash() external view returns (uint); + function totalBorrowsCurrent() external returns (uint); + function borrowRatePerBlock() external view returns (uint); + function supplyRatePerBlock() external view returns (uint); + function totalReserves() external view returns (uint); + function reserveFactorMantissa() external view returns (uint); + + function totalSupply() external view returns (uint256); + function balanceOf(address owner) external view returns (uint256 balance); + function allowance(address, 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 CERC20Interface { + function mint(uint mintAmount) external returns (uint); // For ERC20 + function repayBorrow(uint repayAmount) external returns (uint); // For ERC20 + function repayBorrowBehalf(address borrower, uint repayAmount) external returns (uint); // For ERC20 + function borrowBalanceCurrent(address account) external returns (uint); +} + +interface CETHInterface { + function mint() external payable; // For ETH + function repayBorrow() external payable; // For ETH + function repayBorrowBehalf(address borrower) external payable; // For ETH + function borrowBalanceCurrent(address account) external returns (uint); +} + +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 ComptrollerInterface { + function enterMarkets(address[] calldata cTokens) external returns (uint[] memory); + function exitMarket(address cTokenAddress) external returns (uint); + function getAssetsIn(address account) external view returns (address[] memory); + function getAccountLiquidity(address account) external view returns (uint, uint, 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; + } + +} + + +contract Helpers is DSMath { + + /** + * @dev setting allowance to compound for the "user proxy" if required + */ + function setApproval(address erc20, uint srcAmt, address to) internal { + ERC20Interface erc20Contract = ERC20Interface(erc20); + uint tokenAllowance = erc20Contract.allowance(address(this), to); + if (srcAmt > tokenAllowance) { + erc20Contract.approve(to, 2**255); + } + } + + /** + * @dev get ethereum address for trade + */ + function getAddressETH() public pure returns (address eth) { + eth = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE; + } + + /** + * @dev get Compound Comptroller Address + */ + function getComptrollerAddress() public pure returns (address troller) { + troller = 0x3d9819210A31b4961b30EF54bE2aeD79B9c9Cd3B; + // troller = 0x2EAa9D77AE4D8f9cdD9FAAcd44016E746485bddb; // Rinkeby + } + + /** + * @dev Transfer ETH/ERC20 to user + */ + function transferToken(address erc20) internal { + if (erc20 == getAddressETH()) { + msg.sender.transfer(address(this).balance); + } else { + ERC20Interface erc20Contract = ERC20Interface(erc20); + uint srcBal = erc20Contract.balanceOf(address(this)); + if (srcBal > 0) { + erc20Contract.transfer(msg.sender, srcBal); + } + } + } + +} + + +contract CompoundResolver is Helpers { + + event LogMint(address erc20, address cErc20, uint tokenAmt, address owner); + event LogRedeem(address erc20, address cErc20, uint tokenAmt, address owner); + event LogBorrow(address erc20, address cErc20, uint tokenAmt, address owner); + event LogRepay(address erc20, address cErc20, uint tokenAmt, address owner); + event LogRepayBehalf(address erc20, address cErc20, uint tokenAmt, address owner, address borrower); + + /** + * @dev Enter Compound Market to start borrowing + */ + function enterMarkets(address[] calldata cTokensAdd) external returns (uint[] memory isSuccess) { + isSuccess = ComptrollerInterface(getComptrollerAddress()).enterMarkets(cTokensAdd); + } + + /** + * @dev Exit Compound Market to stop borrowing + */ + function exitMarket(address cTokensAdd) external returns (uint isSuccess) { + isSuccess = ComptrollerInterface(getComptrollerAddress()).exitMarket(cTokensAdd); + } + + /** + * @dev Deposit ETH/ERC20 and mint Compound Tokens + */ + function mintCToken(address erc20, address cErc20, uint tokenAmt) external payable { + if (erc20 == getAddressETH()) { + CETHInterface cToken = CETHInterface(cErc20); + cToken.mint.value(msg.value)(); + } else { + ERC20Interface token = ERC20Interface(erc20); + uint toDeposit = token.balanceOf(msg.sender); + if (toDeposit > tokenAmt) { + toDeposit = tokenAmt; + } + token.transferFrom(msg.sender, address(this), toDeposit); + CERC20Interface cToken = CERC20Interface(cErc20); + setApproval(erc20, toDeposit, cErc20); + assert(cToken.mint(toDeposit) == 0); + } + emit LogMint( + erc20, + cErc20, + tokenAmt, + msg.sender + ); + } + + /** + * @dev Redeem ETH/ERC20 and burn Compound Tokens + * @param cTokenAmt Amount of CToken To burn + */ + function redeemCToken(address erc20, address cErc20, uint cTokenAmt) external { + CTokenInterface cToken = CTokenInterface(cErc20); + uint toBurn = cToken.balanceOf(address(this)); + if (toBurn > cTokenAmt) { + toBurn = cTokenAmt; + } + setApproval(cErc20, toBurn, cErc20); + require(cToken.redeem(toBurn) == 0, "something went wrong"); + transferToken(erc20); + uint tokenReturned = wmul(cToken.balanceOf(address(this)), cToken.exchangeRateCurrent()); + emit LogRedeem( + erc20, + cErc20, + tokenReturned, + address(this) + ); + } + + /** + * @dev Redeem ETH/ERC20 and mint Compound Tokens + * @param tokenAmt Amount of token To Redeem + */ + function redeemUnderlying(address erc20, address cErc20, uint tokenAmt) external { + CTokenInterface cToken = CTokenInterface(cErc20); + setApproval(cErc20, 10**50, cErc20); + require(cToken.redeemUnderlying(tokenAmt) == 0, "something went wrong"); + transferToken(erc20); + emit LogRedeem( + erc20, + cErc20, + tokenAmt, + address(this) + ); + } + + /** + * @dev borrow ETH/ERC20 + */ + function borrow(address erc20, address cErc20, uint tokenAmt) external { + require(CTokenInterface(cErc20).borrow(tokenAmt) == 0, "got collateral?"); + transferToken(erc20); + emit LogBorrow( + erc20, + cErc20, + tokenAmt, + address(this) + ); + } + + /** + * @dev Pay Debt ETH/ERC20 + */ + function repayToken(address erc20, address cErc20, uint tokenAmt) external payable { + if (erc20 == getAddressETH()) { + CETHInterface cToken = CETHInterface(cErc20); + uint toRepay = msg.value; + uint borrows = cToken.borrowBalanceCurrent(address(this)); + if (toRepay > borrows) { + toRepay = borrows; + msg.sender.transfer(msg.value - toRepay); + } + cToken.repayBorrow.value(msg.value)(); + } else { + CERC20Interface cToken = CERC20Interface(cErc20); + ERC20Interface token = ERC20Interface(erc20); + uint toRepay = token.balanceOf(msg.sender); + uint borrows = cToken.borrowBalanceCurrent(address(this)); + if (toRepay > tokenAmt) { + toRepay = tokenAmt; + } + if (toRepay > borrows) { + toRepay = borrows; + } + setApproval(erc20, toRepay, cErc20); + token.transferFrom(msg.sender, address(this), toRepay); + require(cToken.repayBorrow(toRepay) == 0, "transfer approved?"); + } + emit LogRepay( + erc20, + cErc20, + tokenAmt, + address(this) + ); + } + + /** + * @dev Pay Debt for someone else + */ + function repaytokenBehalf( + address borrower, + address erc20, + address cErc20, + uint tokenAmt + ) external payable + { + if (erc20 == getAddressETH()) { + CETHInterface cToken = CETHInterface(cErc20); + uint toRepay = msg.value; + uint borrows = cToken.borrowBalanceCurrent(address(this)); + if (toRepay > borrows) { + toRepay = borrows; + msg.sender.transfer(msg.value - toRepay); + } + cToken.repayBorrowBehalf.value(msg.value)(borrower); + } else { + CERC20Interface cToken = CERC20Interface(cErc20); + ERC20Interface token = ERC20Interface(erc20); + uint toRepay = token.balanceOf(msg.sender); + uint borrows = cToken.borrowBalanceCurrent(address(this)); + if (toRepay > tokenAmt) { + toRepay = tokenAmt; + } + if (toRepay > borrows) { + toRepay = borrows; + } + setApproval(erc20, toRepay, cErc20); + token.transferFrom(msg.sender, address(this), toRepay); + require(cToken.repayBorrowBehalf(borrower, tokenAmt) == 0, "transfer approved?"); + } + emit LogRepayBehalf( + erc20, + cErc20, + tokenAmt, + address(this), + borrower + ); + } + +} + + +contract InstaCompound is CompoundResolver { + + uint public version; + + /** + * @dev setting up variables on deployment + * 1...2...3 versioning in each subsequent deployments + */ + constructor(uint _version) public { + version = _version; + } + + function() external payable {} + +} \ No newline at end of file diff --git a/contracts/ProxyLogics/InstaMaker.sol b/contracts/ProxyLogics/InstaMaker.sol index c336dfe..fa29733 100644 --- a/contracts/ProxyLogics/InstaMaker.sol +++ b/contracts/ProxyLogics/InstaMaker.sol @@ -117,6 +117,7 @@ contract CDPResolver is Helpers { event LogLock(uint cdpNum, uint amtETH, uint amtPETH, address owner); event LogFree(uint cdpNum, uint amtETH, uint amtPETH, address owner); event LogDraw(uint cdpNum, uint amtDAI, address owner); + event LogDrawSend(uint cdpNum, uint amtDAI, address to); event LogWipe(uint cdpNum, uint daiAmt, uint mkrFee, uint daiFee, address owner); event LogShut(uint cdpNum); @@ -208,6 +209,20 @@ contract CDPResolver is Helpers { } } + function drawSend(uint cdpNum, uint _wad, address to) public { + require(to != address(0x0), "address-not-valid"); + bytes32 cup = bytes32(cdpNum); + if (_wad > 0) { + TubInterface tub = TubInterface(getSaiTubAddress()); + + tub.draw(cup, _wad); + tub.sai().transfer(to, _wad); + + emit LogDraw(cdpNum, _wad, address(this)); + emit LogDrawSend(cdpNum, _wad, to); + } + } + function wipe(uint cdpNum, uint _wad) public { if (_wad > 0) { TubInterface tub = TubInterface(getSaiTubAddress()); diff --git a/contracts/ProxyLogics/InstaSave.sol b/contracts/ProxyLogics/InstaSave.sol index db1b67f..9f53027 100644 --- a/contracts/ProxyLogics/InstaSave.sol +++ b/contracts/ProxyLogics/InstaSave.sol @@ -319,10 +319,10 @@ contract GetDetails is MakerHelpers { function getMax(uint cdpID) public view returns (uint maxColToFree, uint maxDaiToDraw, uint ethInUSD) { bytes32 cup = bytes32(cdpID); (uint ethCol, uint daiDebt, uint usdPerEth) = getCDPStats(cup); - uint colToUSD = wmul(ethCol, usdPerEth) - 10; - uint minColNeeded = wmul(daiDebt, 1500000000000000000) + 10; + uint colToUSD = sub(wmul(ethCol, usdPerEth), 10); + uint minColNeeded = add(wmul(daiDebt, 1500000000000000000), 10); maxColToFree = wdiv(sub(colToUSD, minColNeeded), usdPerEth); - uint maxDebtLimit = wdiv(colToUSD, 1500000000000000000) - 10; + uint maxDebtLimit = sub(wdiv(colToUSD, 1500000000000000000), 10); maxDaiToDraw = sub(maxDebtLimit, daiDebt); ethInUSD = usdPerEth; } @@ -371,14 +371,13 @@ contract GetDetails is MakerHelpers { bool canSave ) { - uint colToUSD = wmul(ethCol, usdPerEth) - 10; - uint minColNeeded = wmul(daiDebt, 1500000000000000000) + 10; + uint colToUSD = sub(wmul(ethCol, usdPerEth), 10); + uint minColNeeded = add(wmul(daiDebt, 1500000000000000000), 10); uint colToFree = wdiv(sub(colToUSD, minColNeeded), usdPerEth); if (ethToSwap < colToFree) { colToFree = ethToSwap; } (uint expectedRate,) = KyberInterface(getAddressKyber()).getExpectedRate(getAddressETH(), getAddressDAI(), colToFree); - expectedRate = wdiv(wmul(expectedRate, 99750000000000000000), 100000000000000000000); uint expectedDAI = wmul(colToFree, expectedRate); if (expectedDAI < daiDebt) { finalEthCol = sub(ethCol, colToFree); @@ -406,14 +405,13 @@ contract GetDetails is MakerHelpers { bool canLeverage ) { - uint colToUSD = wmul(ethCol, usdPerEth) - 10; - uint maxDebtLimit = wdiv(colToUSD, 1500000000000000000) - 10; + uint colToUSD = sub(wmul(ethCol, usdPerEth), 10); + uint maxDebtLimit = sub(wdiv(colToUSD, 1500000000000000000), 10); uint debtToBorrow = sub(maxDebtLimit, daiDebt); if (daiToSwap < debtToBorrow) { debtToBorrow = daiToSwap; } (uint expectedRate,) = KyberInterface(getAddressKyber()).getExpectedRate(getAddressDAI(), getAddressETH(), debtToBorrow); - expectedRate = wdiv(wmul(expectedRate, 99750000000000000000), 100000000000000000000); uint expectedETH = wmul(debtToBorrow, expectedRate); if (ethCol != 0) { finalEthCol = add(ethCol, expectedETH); @@ -470,11 +468,9 @@ contract Save is GetDetails { } uint thisBalance = address(this).balance; free(cdpID, colToFree); - uint ethToSwap = wdiv(wmul(colToFree, 99750000000000000000), 100000000000000000000); - getAddressAdmin().transfer(sub(colToFree, ethToSwap)); - uint destAmt = KyberInterface(getAddressKyber()).trade.value(ethToSwap)( + uint destAmt = KyberInterface(getAddressKyber()).trade.value(colToFree)( getAddressETH(), - ethToSwap, + colToFree, getAddressDAI(), address(this), daiDebt, @@ -484,11 +480,11 @@ contract Save is GetDetails { wipe(cdpID, destAmt); if (thisBalance < address(this).balance) { - uint balToLock = address(this).balance - thisBalance; + uint balToLock = sub(address(this).balance, thisBalance); lock(cdpID, balToLock); } - emit LogSaveCDP(cdpID, ethToSwap, destAmt); + emit LogSaveCDP(cdpID, colToFree, destAmt); emit LogTrade( 0, @@ -521,9 +517,7 @@ contract Save is GetDetails { 0, getAddressAdmin() ); - uint ethToDeposit = wdiv(wmul(destAmt, 99750000000000000000), 100000000000000000000); - getAddressAdmin().transfer(sub(destAmt, ethToDeposit)); - lock(cdpID, ethToDeposit); + lock(cdpID, destAmt); emit LogLeverageCDP(cdpID, debtToBorrow, destAmt);