diff --git a/contracts/ProxyLogics/MCD/InstaMcdMigrate.sol b/contracts/ProxyLogics/MCD/InstaMcdMigrate.sol index 752db08..ac15268 100644 --- a/contracts/ProxyLogics/MCD/InstaMcdMigrate.sol +++ b/contracts/ProxyLogics/MCD/InstaMcdMigrate.sol @@ -45,7 +45,12 @@ interface UniswapExchange { uint256 maxEthSold, uint256 deadline, address tokenAddr - ) external returns (uint256 tokensSold); + ) external returns (uint256 tokensSold); + function ethToTokenSwapOutput(uint256 tokensBought, uint256 deadline) external payable returns (uint256 ethSold); +} + +interface UniswapFactoryInterface { + function getExchange(address token) external view returns (address exchange); } interface MCDInterface { @@ -58,6 +63,16 @@ interface PoolInterface { function paybackToken(address[] calldata ctknAddr, bool isCompound) external payable; } +interface OtcInterface { + function getPayAmount(address, address, uint) external view returns (uint); + function buyAllAmount( + address, + uint, + address, + uint + ) external; +} + contract DSMath { @@ -112,6 +127,20 @@ contract Helpers is DSMath { dai = 0x448a5065aeBB8E423F0896E6c5D525C040f59af3; } + /** + * @dev get Compound WETH Address + */ + function getWETHAddress() public pure returns (address wethAddr) { + wethAddr = 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2; // main + } + + /** + * @dev get Compound OTC Address + */ + function getOtcAddress() public pure returns (address otcAddr) { + otcAddr = 0x39755357759cE0d7f32dC8dC45414CCa409AE24e; // main + } + /** * @dev get uniswap MKR exchange */ @@ -126,6 +155,13 @@ contract Helpers is DSMath { ude = 0x09cabEC1eAd1c0Ba254B09efb3EE13841712bE14; } + /** + * @dev get uniswap factory + */ + function getUniswapFactory() public pure returns (address addr) { + addr = 0xc0a47dFe034B400B47bDaD5FecDa2621de6c4d95; + } + /** * @dev get InstaDApp Liquidity Address */ @@ -134,10 +170,14 @@ contract Helpers is DSMath { } /** - * @dev get CDP bytes by CDP ID + * @dev setting allowance to compound for the "user proxy" if required */ - function getCDPBytes(uint cdpNum) public pure returns (bytes32 cup) { - cup = bytes32(cdpNum); + function setApproval(address erc20, uint srcAmt, address to) internal { + TokenInterface erc20Contract = TokenInterface(erc20); + uint tokenAllowance = erc20Contract.allowance(address(this), to); + if (srcAmt > tokenAllowance) { + erc20Contract.approve(to, 2**255); + } } } @@ -149,7 +189,41 @@ contract SCDResolver is Helpers { cup = TubInterface(getSaiTubAddress()).open(); } - function lock(bytes32 cup, uint jam) public payable { + function wipe(bytes32 cup, uint _wad) internal { + if (_wad > 0) { + TubInterface tub = TubInterface(getSaiTubAddress()); + TokenInterface dai = tub.sai(); + TokenInterface mkr = tub.gov(); + + (address lad,,,) = tub.cups(cup); + require(lad == address(this), "cup-not-owned"); + + setAllowance(dai, getSaiTubAddress()); + setAllowance(mkr, getSaiTubAddress()); + + tub.wipe(cup, _wad); + } + } + + function free(bytes32 cup, uint jam) internal { + if (jam > 0) { + address tubAddr = getSaiTubAddress(); + + TubInterface tub = TubInterface(tubAddr); + TokenInterface peth = tub.skr(); + + uint ink = rdiv(jam, tub.per()); + ink = rmul(ink, tub.per()) <= jam ? ink : ink - 1; + tub.free(cup, ink); + + setAllowance(peth, tubAddr); + + tub.exit(ink); + // weth.withdraw(freeJam); // No need because we will lock it in small cdp + } + } + + function lock(bytes32 cup, uint jam) internal { if (jam > 0) { address tubAddr = getSaiTubAddress(); @@ -160,7 +234,7 @@ contract SCDResolver is Helpers { (address lad,,,) = tub.cups(cup); require(lad == address(this), "cup-not-owned"); - weth.deposit.value(jam)(); + // weth.deposit.value(msg.value)(); // no need because withdrawn Weth is not convert back uint ink = rdiv(jam, tub.per()); ink = rmul(ink, tub.per()) <= jam ? ink : ink - 1; @@ -173,73 +247,13 @@ contract SCDResolver is Helpers { } } - function free(bytes32 cup, uint jam) public { - if (jam > 0) { - address tubAddr = getSaiTubAddress(); - - TubInterface tub = TubInterface(tubAddr); - TokenInterface peth = tub.skr(); - TokenInterface weth = tub.gem(); - - uint ink = rdiv(jam, tub.per()); - ink = rmul(ink, tub.per()) <= jam ? ink : ink - 1; - tub.free(cup, ink); - - setAllowance(peth, tubAddr); - - tub.exit(ink); - uint freeJam = weth.balanceOf(address(this)); // withdraw possible previous stuck WETH as well - weth.withdraw(freeJam); - } - } - - function draw(bytes32 cup, uint _wad) public { + function draw(bytes32 cup, uint _wad) internal { if (_wad > 0) { TubInterface tub = TubInterface(getSaiTubAddress()); tub.draw(cup, _wad); } } - function wipe(bytes32 cup, uint _wad) public { - if (_wad > 0) { - TubInterface tub = TubInterface(getSaiTubAddress()); - UniswapExchange daiEx = UniswapExchange(getUniswapDAIExchange()); - UniswapExchange mkrEx = UniswapExchange(getUniswapMKRExchange()); - TokenInterface dai = tub.sai(); - TokenInterface mkr = tub.gov(); - - (address lad,,,) = tub.cups(cup); - require(lad == address(this), "cup-not-owned"); - - setAllowance(dai, getSaiTubAddress()); - setAllowance(mkr, getSaiTubAddress()); - setAllowance(dai, getUniswapDAIExchange()); - - (bytes32 val, bool ok) = tub.pep().peek(); - - //Check Thrilok - // MKR required for wipe = Stability fees accrued in Dai / MKRUSD value - uint mkrFee = wdiv(rmul(_wad, rdiv(tub.rap(cup), tub.tab(cup))), uint(val)); - - uint daiFeeAmt = daiEx.getTokenToEthOutputPrice(mkrEx.getEthToTokenOutputPrice(mkrFee)); - uint daiAmt = add(_wad, daiFeeAmt); - require(dai.transferFrom(msg.sender, address(this), daiAmt), "not-approved-yet"); - - if (ok && val != 0) { - daiEx.tokenToTokenSwapOutput( - mkrFee, - daiAmt, - uint(999000000000000000000), - uint(1899063809), // 6th March 2030 GMT // no logic - address(mkr) - ); - } - - tub.wipe(cup, _wad); - - } - } - function setAllowance(TokenInterface _token, address _spender) private { if (_token.allowance(address(this), _spender) != uint(-1)) { _token.approve(_spender, uint(-1)); @@ -249,7 +263,53 @@ contract SCDResolver is Helpers { } -contract MCDResolver is SCDResolver { +contract MkrResolver is SCDResolver { + function swapToMkrOtc(address tokenAddr, uint govFee) internal { + TokenInterface mkr = TubInterface(getSaiTubAddress()).gov(); + uint payAmt = OtcInterface(getOtcAddress()).getPayAmount(tokenAddr, address(mkr), govFee); + if (tokenAddr == getWETHAddress()) { + TokenInterface weth = TokenInterface(getWETHAddress()); + weth.deposit.value(payAmt)(); + } else { + require(TokenInterface(tokenAddr).transferFrom(msg.sender, address(this), payAmt), "Tranfer-failed"); + } + setApproval(tokenAddr, payAmt, getOtcAddress()); + OtcInterface(getOtcAddress()).buyAllAmount( + address(mkr), + govFee, + tokenAddr, + payAmt + ); + } + + function swapToMkrUniswap(address tokenAddr, uint govFee) internal { + UniswapExchange mkrEx = UniswapExchange(getUniswapMKRExchange()); + address uniSwapFactoryAddr = 0xc0a47dFe034B400B47bDaD5FecDa2621de6c4d95; + TokenInterface mkr = TubInterface(getSaiTubAddress()).gov(); + + if (tokenAddr == getWETHAddress()) { + uint ethNeeded = mkrEx.getEthToTokenOutputPrice(govFee); + mkrEx.ethToTokenSwapOutput.value(ethNeeded)(govFee, uint(1899063809)); + } else { + address buyTknExAddr = UniswapFactoryInterface(uniSwapFactoryAddr).getExchange(tokenAddr); + UniswapExchange buyTknEx = UniswapExchange(buyTknExAddr); + uint tknAmt = buyTknEx.getTokenToEthOutputPrice(mkrEx.getEthToTokenOutputPrice(govFee)); //Check thrilok is this correct + require(TokenInterface(tokenAddr).transferFrom(msg.sender, address(this), tknAmt), "not-approved-yet"); + setApproval(tokenAddr, tknAmt, buyTknExAddr); + buyTknEx.tokenToTokenSwapOutput( + govFee, + tknAmt, + uint(999000000000000000000), + uint(1899063809), // 6th March 2030 GMT // no logic + address(mkr) + ); + } + + } +} + + +contract MCDResolver is MkrResolver { function swapDaiToSai( address payable scdMcdMigration, // Migration contract address uint wad // Amount to swap @@ -268,7 +328,6 @@ contract MCDResolver is SCDResolver { address payable scdMcdMigration, // Migration contract address bytes32 cup, // SCD CDP Id to migrate address payGem // Token address (only if gov fee will be paid with another token) - // uint maxPayAmt // Max amount of payGem to sell for govFee needed (only if gov fee will be paid with another token) ) internal returns (uint cdp) { TubInterface tub = TubInterface(getSaiTubAddress()); @@ -281,10 +340,8 @@ contract MCDResolver is SCDResolver { uint govFee = wdiv(tub.rap(cup), uint(val)); if (payGem != address(0)) { - // Swap ETH to WETH => WETH TO MKR - + swapToMkrOtc(payGem, govFee); } else { - // Else get MKR from the user's wallet and transfer to Migration contract require(tub.gov().transferFrom(msg.sender, address(this), govFee), "transfer-failed"); } require(tub.gov().transfer(address(scdMcdMigration), govFee), "transfer-failed"); @@ -296,6 +353,7 @@ contract MCDResolver is SCDResolver { contract MigrateResolver is MCDResolver { + event LogMigrate(uint scdCdp, uint toConvert, address payFeeWith, uint mcdCdp); function migrate( bytes32 scdCup, // uint mcdCDP, for merge @@ -307,13 +365,14 @@ contract MigrateResolver is MCDResolver { TubInterface tub = TubInterface(getSaiTubAddress()); uint _jam = rmul(tub.ink(scdCup), tub.per()); uint _wad = tub.tab(scdCup); - if (toConvert >= 10**18) { + if (toConvert < 10**18) { uint initialPoolBal = sub(getPoolAddress().balance, 10000000000); bytes32 splitCup = TubInterface(getSaiTubAddress()).open(); _jam = wmul(_jam, toConvert); _wad = wmul(_wad, toConvert); + uint[] memory _wadArr = new uint[](1); _wadArr[0] = _wad; @@ -323,13 +382,21 @@ contract MigrateResolver is MCDResolver { // Get liquidity assets to payback user wallet borrowed assets PoolInterface(getPoolAddress()).accessToken(addrArr, _wadArr, false); + (bytes32 val, bool ok) = tub.pep().peek(); + + if (ok && val != 0) { + // MKR required for wipe = Stability fees accrued in Dai / MKRUSD value + uint mkrFee = wdiv(rmul(_wad, rdiv(tub.rap(scdCup), tub.tab(scdCup))), uint(val)); + swapToMkrUniswap(payFeeWith, mkrFee); + } + wipe(scdCup, _wad); free(scdCup, _jam); lock(splitCup, _jam); draw(splitCup, _wad); - require(TokenInterface(getSaiAddress()).transfer(getPoolAddress(), _wad), "Not-enough-amt"); + require(TokenInterface(getSaiAddress()).transfer(getPoolAddress(), _wad), "Not-enough-dai"); PoolInterface(getPoolAddress()).paybackToken(addrArr, false); uint finalPoolBal = getPoolAddress().balance; @@ -339,6 +406,12 @@ contract MigrateResolver is MCDResolver { } else { cdp = migrateToMCD(scdMcdMigration, scdCup, payFeeWith); } + emit LogMigrate( + uint(scdCup), + toConvert, + payFeeWith, + cdp + ); } }