From 65a97fa1d007376572169e2678d51689bbd198ca Mon Sep 17 00:00:00 2001 From: Sowmayjain Date: Thu, 28 Mar 2019 04:26:19 +0530 Subject: [PATCH] Added previous InstaMaker contract. --- contracts/ProxyLogics/InstaMaker.sol | 369 ++++++++++++--------------- 1 file changed, 159 insertions(+), 210 deletions(-) diff --git a/contracts/ProxyLogics/InstaMaker.sol b/contracts/ProxyLogics/InstaMaker.sol index 3941a64..4218731 100644 --- a/contracts/ProxyLogics/InstaMaker.sol +++ b/contracts/ProxyLogics/InstaMaker.sol @@ -2,6 +2,7 @@ pragma solidity ^0.5.0; library SafeMath { + function mul(uint256 a, uint256 b) internal pure returns (uint256) { if (a == 0) { return 0; @@ -10,255 +11,203 @@ library SafeMath { require(c / a == b, "Assertion Failed"); return c; } + + function div(uint256 a, uint256 b) internal pure returns (uint256) { + require(b > 0, "Assertion Failed"); + uint256 c = a / b; + return c; + } + } contract IERC20 { - function balanceOf(address who) public view returns (uint256); - function allowance(address _owner, address _spender) public view returns (uint256); - function transfer(address to, uint256 value) public returns (bool); - function approve(address spender, uint256 value) public returns (bool); - function transferFrom(address from, address to, uint256 value) public returns (bool); + function balanceOf(address who) external view returns (uint256); + function transfer(address to, uint256 value) external returns (bool); + function approve(address spender, uint256 value) external returns (bool); + function transferFrom(address from, address to, uint256 value) external returns (bool); } -contract KyberInterface { - function trade( - address src, - uint srcAmount, - address dest, - address destAddress, - uint maxDestAmount, - uint minConversionRate, - address walletId - ) public payable returns (uint); - - function getExpectedRate( - address src, - address dest, - uint srcQty - ) public view returns (uint, uint); +contract MakerCDP { + function open() external returns (bytes32 cup); + function join(uint wad) external; // Join PETH + function exit(uint wad) external; // Exit PETH + function give(bytes32 cup, address guy) external; + function lock(bytes32 cup, uint wad) external; + function free(bytes32 cup, uint wad) external; + function draw(bytes32 cup, uint wad) external; + function wipe(bytes32 cup, uint wad) external; + function per() external view returns (uint ray); + function lad(bytes32 cup) external view returns (address); } -contract Helper { +contract PriceInterface { + function peek() external view returns (bytes32, bool); +} + + +contract WETHFace { + function deposit() external payable; + function withdraw(uint wad) external; +} + + +contract Helpers { using SafeMath for uint; using SafeMath for uint256; - /** - * @dev get ethereum address for trade - */ - function getAddressETH() public pure returns (address eth) { - eth = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE; + function getETHRate() public view returns (uint) { + PriceInterface ethRate = PriceInterface(getAddress("ethfeed")); + bytes32 ethrate; + (ethrate, ) = ethRate.peek(); + return uint(ethrate); } - /** - * @dev get kyber proxy address - */ - function getAddressKyber() public pure returns (address kyber) { - kyber = 0x692f391bCc85cefCe8C237C01e1f636BbD70EA4D; + function getCDP(address borrower) public view returns (uint, bytes32) { + return (uint(cdps[borrower]), cdps[borrower]); } - /** - * @dev get admin address - */ - function getAddressAdmin() public pure returns (address admin) { - admin = 0x7284a8451d9a0e7Dc62B3a71C0593eA2eC5c5638; + function approveERC20() public { + IERC20 wethTkn = IERC20(getAddress("weth")); + wethTkn.approve(cdpAddr, 2**256 - 1); + IERC20 pethTkn = IERC20(getAddress("peth")); + pethTkn.approve(cdpAddr, 2**256 - 1); + IERC20 mkrTkn = IERC20(getAddress("mkr")); + mkrTkn.approve(cdpAddr, 2**256 - 1); + IERC20 daiTkn = IERC20(getAddress("dai")); + daiTkn.approve(cdpAddr, 2**256 - 1); } - /** - * @dev get fees to trade // 200 => 0.2% - */ - function getUintFees() public pure returns (uint fees) { - fees = 200; - } - /** - * @dev gets ETH & token balance - * @param src is the token being sold - * @return ethBal - if not erc20, eth balance - * @return tknBal - if not eth, erc20 balance - */ - function getBal(address src, address _owner) public view returns (uint, uint) { - uint tknBal; - if (src != getAddressETH()) { - tknBal = IERC20(src).balanceOf(address(_owner)); - } - return (address(_owner).balance, tknBal); - } - - /** - * @dev getting rates from Kyber - * @param src is the token being sold - * @param dest is the token being bought - * @param srcAmt is the amount of token being sold - * @return expectedRate - the current rate - * @return slippageRate - rate with 3% slippage - */ - function getExpectedRate( - address src, - address dest, - uint srcAmt - ) public view returns ( - uint expectedRate, - uint slippageRate - ) - { - (expectedRate, slippageRate) = KyberInterface(getAddressKyber()).getExpectedRate(src, dest, srcAmt); - slippageRate = (slippageRate / 97) * 99; // changing slippage rate upto 99% - } - - /** - * @dev fetching token from the trader if ERC20 - * @param trader is the trader - * @param src is the token which is being sold - * @param srcAmt is the amount of token being sold - */ - function getToken(address trader, address src, uint srcAmt) internal returns (uint ethQty) { - if (src == getAddressETH()) { - require(msg.value == srcAmt, "not-enough-src"); - ethQty = srcAmt; - } else { - manageApproval(src, srcAmt); - IERC20(src).transferFrom(trader, address(this), srcAmt); - } - } - - /** - * @dev setting allowance to kyber for the "user proxy" if required - * @param token is the token address - */ - function setApproval(address token) internal returns (uint) { - IERC20(token).approve(getAddressKyber(), 2**255); - } - - /** - * @dev configuring token approval with user proxy - * @param token is the token - */ - function manageApproval(address token, uint srcAmt) internal returns (uint) { - uint tokenAllowance = IERC20(token).allowance(address(this), getAddressKyber()); - if (srcAmt > tokenAllowance) { - setApproval(token); - } - } - } -contract Swap is Helper { +contract IssueLoan is Helpers { - /** - * @param what 0 for BUY & 1 for SELL - */ - event LogTrade( - uint what, - address src, - uint srcAmt, - address dest, - uint destAmt, - address beneficiary, - uint minConversionRate, - address affiliate - ); + event LockedETH(address borrower, uint lockETH, uint lockPETH, address lockedBy); + event LoanedDAI(address borrower, uint loanDAI, address payTo); + event NewCDP(address borrower, bytes32 cdpBytes); - /** - * @dev buying token where destAmt is fixed - * @param src - token to sell - * @param dest - token to buy - * @param srcAmt - token amount to sell - * @param maxDestAmt is the max amount of token to be bought - */ - function buy( - address src, - address dest, - uint srcAmt, - uint maxDestAmt - ) public payable returns (uint destAmt) - { - uint ethQty = getToken(msg.sender, src, srcAmt); - (, uint slippageRate) = getExpectedRate(src, dest, srcAmt); + function pethPEReth(uint ethNum) public view returns (uint rPETH) { + MakerCDP loanMaster = MakerCDP(cdpAddr); + rPETH = (ethNum.mul(10 ** 27)).div(loanMaster.per()); + } - // (uint ethBal, uint tknBal) = getBal(src, address(this)); + function borrow(uint daiDraw, address beneficiary) public payable { + if (msg.value > 0) {lockETH(msg.sender);} + if (daiDraw > 0) {drawDAI(daiDraw, beneficiary);} + } - destAmt = KyberInterface(getAddressKyber()).trade.value(ethQty)( - src, - srcAmt, - dest, - msg.sender, - maxDestAmt, - slippageRate, - getAddressAdmin() + function lockETH(address borrower) public payable { + MakerCDP loanMaster = MakerCDP(cdpAddr); + if (cdps[borrower] == blankCDP) { + require(msg.sender == borrower, "Creating CDP for others is not permitted at the moment."); + cdps[msg.sender] = loanMaster.open(); + emit NewCDP(msg.sender, cdps[msg.sender]); + } + WETHFace wethTkn = WETHFace(getAddress("weth")); + wethTkn.deposit.value(msg.value)(); // ETH to WETH + uint pethToLock = pethPEReth(msg.value); + loanMaster.join(pethToLock); // WETH to PETH + loanMaster.lock(cdps[borrower], pethToLock); // PETH to CDP + emit LockedETH( + borrower, msg.value, pethToLock, msg.sender ); + } - // maxDestAmt usecase implementated on user proxy + function drawDAI(uint daiDraw, address beneficiary) public { + require(!freezed, "Operation Disabled"); + MakerCDP loanMaster = MakerCDP(cdpAddr); + loanMaster.draw(cdps[msg.sender], daiDraw); + IERC20 daiTkn = IERC20(getAddress("dai")); + address payTo = msg.sender; + if (payTo != address(0)) { + payTo = beneficiary; + } + daiTkn.transfer(payTo, daiDraw); + emit LoanedDAI(msg.sender, daiDraw, payTo); + } + +} + + +contract RepayLoan is IssueLoan { + + event WipedDAI(address borrower, uint daiWipe, uint mkrCharged, address wipedBy); + event UnlockedETH(address borrower, uint ethFree); + + function repay(uint daiWipe, uint ethFree) public payable { + if (daiWipe > 0) {wipeDAI(daiWipe, msg.sender);} + if (ethFree > 0) {unlockETH(ethFree);} + } + + function wipeDAI(uint daiWipe, address borrower) public payable { + address dai = getAddress("dai"); + address mkr = getAddress("mkr"); + address eth = getAddress("eth"); + + IERC20 daiTkn = IERC20(dai); + IERC20 mkrTkn = IERC20(mkr); + + uint contractMKR = mkrTkn.balanceOf(address(this)); // contract MKR balance before wiping + daiTkn.transferFrom(msg.sender, address(this), daiWipe); // get DAI to pay the debt + MakerCDP loanMaster = MakerCDP(cdpAddr); + loanMaster.wipe(cdps[borrower], daiWipe); // wipe DAI + uint mkrCharged = contractMKR - mkrTkn.balanceOf(address(this)); // MKR fee = before wiping bal - after wiping bal + + // claiming paid MKR back + if (msg.value > 0) { // Interacting with Kyber to swap ETH with MKR + swapETHMKR( + eth, mkr, mkrCharged, msg.value + ); + } else { // take MKR directly from address + mkrTkn.transferFrom(msg.sender, address(this), mkrCharged); // user paying MKR fees + } + + emit WipedDAI( + borrower, daiWipe, mkrCharged, msg.sender + ); + } + + function unlockETH(uint ethFree) public { + require(!freezed, "Operation Disabled"); + uint pethToUnlock = pethPEReth(ethFree); + MakerCDP loanMaster = MakerCDP(cdpAddr); + loanMaster.free(cdps[msg.sender], pethToUnlock); // CDP to PETH + loanMaster.exit(pethToUnlock); // PETH to WETH + WETHFace wethTkn = WETHFace(getAddress("weth")); + wethTkn.withdraw(ethFree); // WETH to ETH + msg.sender.transfer(ethFree); + emit UnlockedETH(msg.sender, ethFree); + } + + function swapETHMKR( + address eth, + address mkr, + uint mkrCharged, + uint ethQty + ) internal + { + InstaKyber instak = InstaKyber(getAddress("InstaKyber")); + uint minRate; + (, minRate) = instak.getExpectedPrice(eth, mkr, ethQty); + uint mkrBought = instak.executeTrade.value(ethQty)( + eth, mkr, ethQty, minRate, mkrCharged + ); + require(mkrCharged == mkrBought, "ETH not sufficient to cover the MKR fees."); if (address(this).balance > 0) { msg.sender.transfer(address(this).balance); - } else if (src != getAddressETH()) { - IERC20 srcTkn = IERC20(src); - uint srcBal = srcTkn.balanceOf(address(this)); - if (srcBal > 0) { - srcTkn.transfer(msg.sender, srcBal); - } } - - emit LogTrade( - 0, - src, - srcAmt, - dest, - destAmt, - msg.sender, - slippageRate, - getAddressAdmin() - ); - } - /** - * @dev selling token where srcAmt is fixed - * @param src - token to sell - * @param dest - token to buy - * @param srcAmt - token amount to sell - */ - function sell( - address src, - address dest, - uint srcAmt - ) public payable returns (uint destAmt) - { - uint ethQty = getToken(msg.sender, src, srcAmt); - (, uint slippageRate) = getExpectedRate(src, dest, srcAmt); - KyberInterface swapCall = KyberInterface(getAddressKyber()); - destAmt = swapCall.trade.value(ethQty)( - src, - srcAmt, - dest, - msg.sender, - 2**255, - slippageRate, - getAddressAdmin() - ); - - emit LogTrade( - 1, - src, - srcAmt, - dest, - destAmt, - msg.sender, - slippageRate, - getAddressAdmin() - ); - - } } - -contract InstaTrade is Swap { +contract InstaMaker is BorrowTasks { uint public version;