diff --git a/contracts/ProxyLogics/InstaSave.sol b/contracts/ProxyLogics/InstaSave.sol index 2e69cf9..7fd1a34 100644 --- a/contracts/ProxyLogics/InstaSave.sol +++ b/contracts/ProxyLogics/InstaSave.sol @@ -43,7 +43,6 @@ interface UniswapExchange { ) external returns (uint256 tokensSold); } - interface TokenInterface { function allowance(address, address) external view returns (uint); function balanceOf(address) external view returns (uint); @@ -527,38 +526,102 @@ contract SaveResolver is GetDetails { ); } - function loopSwap(uint srcAmt) internal returns (uint destAmt) { - (,uint isBest) = getBest(getAddressETH(), getAddressDAI(), srcAmt); - if (isBest == 0) { - setAllowance(TokenInterface(getAddressDAI()), getAddressEth2Dai()); - destAmt = Eth2DaiInterface(getAddressEth2Dai()).sellAllAmount( + // function loopSwap(uint srcAmt) internal returns (uint destAmt) { + // (,uint isBest) = getBest(getAddressETH(), getAddressDAI(), srcAmt); + // if (isBest == 0) { + // setAllowance(TokenInterface(getAddressDAI()), getAddressEth2Dai()); + // destAmt = Eth2DaiInterface(getAddressEth2Dai()).sellAllAmount( + // getAddressDAI(), + // srcAmt, + // getAddressWETH(), + // 0 + // ); + // destAmt = recursiveloop(srcAmt, 0); + // TokenInterface weth = TokenInterface(getAddressWETH()); + // setAllowance(weth, getSaiTubAddress()); + // weth.withdraw(destAmt); + // } else { + // setAllowance(TokenInterface(getAddressDAI()), getAddressKyber()); + // destAmt = KyberInterface(getAddressKyber()).trade.value(srcAmt)( + // getAddressDAI(), + // srcAmt, + // getAddressETH(), + // address(this), + // 2**255, + // 0, + // getAddressAdmin() + // ); + // } + // emit LogSwap( + // isBest, + // getAddressDAI(), + // srcAmt, + // getAddressETH(), + // destAmt + // ); + // } + + function loopSwap(uint srcAmt, uint finalAmt, uint splitAmt) internal returns (uint destAmt) { + // (,uint isBest) = getBest(getAddressETH(), getAddressDAI(), srcAmt); + if (srcAmt > splitAmt) { + uint nextSrc = srcAmt - splitAmt; + uint swappedAmt = splitSwap(getAddressDAI(), getAddressETH(), splitAmt); + // uint swappedAmt = Eth2DaiInterface(getAddressEth2Dai()).sellAllAmount( + // getAddressDAI(), + // 15000000000000000000000, + // getAddressWETH(), + // 0 + // ); + uint nextFinal = finalAmt + swappedAmt; + destAmt = recursiveloop(nextSrc, nextFinal); + } else { + uint swappedAmt = Eth2DaiInterface(getAddressEth2Dai()).sellAllAmount( getAddressDAI(), srcAmt, getAddressWETH(), 0 ); - TokenInterface weth = TokenInterface(getAddressWETH()); - setAllowance(weth, getSaiTubAddress()); - weth.withdraw(destAmt); + destAmt = finalAmt + swappedAmt; + } + } + + function recursiveloop(uint srcAmt, uint finalAmt) internal returns (uint destAmt) { + if (srcAmt > 15000000000000000000000) { + uint nextSrc = srcAmt - 15000000000000000000000; + uint swappedAmt = Eth2DaiInterface(getAddressEth2Dai()).sellAllAmount( + getAddressDAI(), + 15000000000000000000000, + getAddressWETH(), + 0 + ); + uint nextFinal = finalAmt + swappedAmt; + destAmt = recursiveloop(nextSrc, nextFinal); } else { - setAllowance(TokenInterface(getAddressDAI()), getAddressKyber()); - destAmt = KyberInterface(getAddressKyber()).trade.value(srcAmt)( + uint swappedAmt = Eth2DaiInterface(getAddressEth2Dai()).sellAllAmount( getAddressDAI(), srcAmt, - getAddressETH(), - address(this), - 2**255, - 0, - getAddressAdmin() + getAddressWETH(), + 0 ); + destAmt = finalAmt + swappedAmt; } - emit LogSwap( - isBest, - getAddressDAI(), - srcAmt, - getAddressETH(), - destAmt - ); + } + + function splitSwap(address src, address dest, uint srcAmt) internal returns (uint destAmt) { + (,uint isBest) = getBest(getAddressETH(), getAddressDAI(), srcAmt); + if (isBest) + } + + function eth2DaiSwap() internal returns (uint destAmt) { + + } + + function uniswapSwap() internal returns (uint destAmt) { + + } + + function kyberSwap() internal returns (uint destAmt) { + } } diff --git a/contracts/ProxyLogics/SplitSwap/SplitSwap.sol b/contracts/ProxyLogics/SplitSwap/SplitSwap.sol new file mode 100644 index 0000000..b87fb53 --- /dev/null +++ b/contracts/ProxyLogics/SplitSwap/SplitSwap.sol @@ -0,0 +1,313 @@ +pragma solidity ^0.5.7; + +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); + function deposit() external payable; + function withdraw(uint) external; +} + +interface UniswapExchange { + function getEthToTokenInputPrice(uint ethSold) external view returns (uint tokenBought); + function getTokenToEthInputPrice(uint tokenSold) external view returns (uint ethBought); + function ethToTokenSwapInput(uint minTokens, uint deadline) external payable returns (uint tokenBought); + function tokenToEthSwapInput(uint tokenSold, uint minEth, uint deadline) external returns (uint ethBought); +} + +interface KyberInterface { + function trade( + address src, + uint srcAmount, + address dest, + address destAddress, + uint maxDestAmount, + uint minConversionRate, + address walletId + ) external payable returns (uint); + + function getExpectedRate( + address src, + address dest, + uint srcQty + ) external view returns (uint, uint); +} + +interface Eth2DaiInterface { + function getBuyAmount(address dest, address src, uint srcAmt) external view returns(uint); + function getPayAmount(address src, address dest, uint destAmt) external view returns (uint); + function sellAllAmount( + address src, + uint srcAmt, + address dest, + uint minDest + ) external returns (uint destAmt); + function buyAllAmount( + address dest, + uint destAmt, + address src, + uint maxSrc + ) external returns (uint srcAmt); +} + + +contract DSMath { + + function add(uint x, uint y) internal pure returns (uint z) { + require((z = x + y) >= x, "math-not-safe"); + } + + function sub(uint x, uint y) internal pure returns (uint z) { + require((z = x - y) <= x, "ds-math-sub-underflow"); + } + + 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; + uint constant RAY = 10 ** 27; + + function rmul(uint x, uint y) internal pure returns (uint z) { + z = add(mul(x, y), RAY / 2) / RAY; + } + + function rdiv(uint x, uint y) internal pure returns (uint z) { + z = add(mul(x, RAY), y / 2) / y; + } + + 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 Helper is DSMath { + + address public eth2daiAddr = 0x39755357759cE0d7f32dC8dC45414CCa409AE24e; + address public uniswapAddr = 0x09cabEC1eAd1c0Ba254B09efb3EE13841712bE14; // Uniswap DAI exchange + address public kyberAddr = 0x818E6FECD516Ecc3849DAf6845e3EC868087B755; + address public ethAddr = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE; + address public wethAddr = 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2; + address public daiAddr = 0x89d24A6b4CcB1B6fAA2625fE562bDD9a23260359; + address public admin = 0xa7615CD307F323172331865181DC8b80a2834324; + uint public maxSplitAmtEth = 50000000000000000000; + uint public maxSplitAmtDai = 20000000000000000000000; + + function setAllowance(TokenInterface _token, address _spender) internal { + if (_token.allowance(address(this), _spender) != uint(-1)) { + _token.approve(_spender, uint(-1)); + } + } + + modifier isAdmin { + require(msg.sender == admin, "Not an Admin"); + _; + } + +} + + +contract AdminStuffs is Helper { + + function setSplitEth(uint amt) public isAdmin { + maxSplitAmtEth = amt; + } + + function setSplitDai(uint amt) public isAdmin { + maxSplitAmtDai = amt; + } + + function withdrawToken(address token) public isAdmin { + uint daiBal = TokenInterface(token).balanceOf(address(this)); + TokenInterface(token).transfer(msg.sender, daiBal); + } + + function withdrawEth() public payable isAdmin { + msg.sender.transfer(address(this).balance); + } + +} + + +contract SplitsRead is Helper { + + function getBest(address src, address dest, uint srcAmt) public returns (uint bestExchange, uint destAmt) { + uint eth2DaiPrice = getRateEth2Dai(src, dest, srcAmt); + uint kyberPrice = getRateKyber(src, dest, srcAmt); + uint uniswapPrice = getRateUniswap(src, dest, srcAmt); + if (eth2DaiPrice > kyberPrice && eth2DaiPrice > uniswapPrice) { + destAmt = eth2DaiPrice; + bestExchange = 0; + } else if (kyberPrice > uniswapPrice && kyberPrice > eth2DaiPrice) { + destAmt = kyberPrice; + bestExchange = 1; + } else { + destAmt = uniswapPrice; + bestExchange = 2; + } + require(destAmt != 0, "Dest Amt = 0"); + } + + function getRateEth2Dai(address src, address dest, uint srcAmt) public returns (uint destAmt) { + if (src == ethAddr) { + destAmt = Eth2DaiInterface(eth2daiAddr).getBuyAmount(dest, wethAddr, srcAmt); + } else if (dest == ethAddr) { + destAmt = Eth2DaiInterface(eth2daiAddr).getBuyAmount(wethAddr, src, srcAmt); + } + } + + function getRateKyber(address src, address dest, uint srcAmt) public returns (uint destAmt) { + (uint kyberPrice,) = KyberInterface(kyberAddr).getExpectedRate(src, dest, srcAmt); + destAmt = wmul(srcAmt, kyberPrice); + } + + function getRateUniswap(address src, address dest, uint srcAmt) public returns (uint destAmt) { + if (src == ethAddr) { + destAmt = UniswapExchange(uniswapAddr).getEthToTokenInputPrice(srcAmt); + } else if (dest == ethAddr) { + destAmt = UniswapExchange(uniswapAddr).getTokenToEthInputPrice(srcAmt); + } + } + +} + + +contract SplitResolver is SplitsRead { + + function ethToDaiLoop(uint srcAmt, uint splitAmt, uint finalAmt) internal returns (uint destAmt) { + if (srcAmt > splitAmt) { + uint amtToSwap = splitAmt; + uint nextSrcAmt = srcAmt - splitAmt; + (uint bestExchange,) = getBest(ethAddr, daiAddr, amtToSwap); + uint ethBought = finalAmt; + if (bestExchange == 0) { + ethBought += swapEth2Dai(wethAddr, daiAddr, amtToSwap); + } else if (bestExchange == 1) { + ethBought += swapKyber(ethAddr, daiAddr, amtToSwap); + } else { + ethBought += swapUniswap(ethAddr, daiAddr, amtToSwap); + } + destAmt = daiToEthLoop(nextSrcAmt, splitAmt, ethBought); + } else if (srcAmt > 0) { + (uint bestExchange,) = getBest(ethAddr, daiAddr, srcAmt); + destAmt = finalAmt; + if (bestExchange == 0) { + destAmt += swapEth2Dai(wethAddr, daiAddr, srcAmt); + } else if (bestExchange == 1) { + destAmt += swapKyber(ethAddr, daiAddr, srcAmt); + } else { + destAmt += swapUniswap(ethAddr, daiAddr, srcAmt); + } + } else { + destAmt = finalAmt; + } + } + + function daiToEthLoop(uint srcAmt, uint splitAmt, uint finalAmt) internal returns (uint destAmt) { + if (srcAmt > splitAmt) { + uint amtToSwap = splitAmt; + uint nextSrcAmt = srcAmt - splitAmt; + (uint bestExchange,) = getBest(daiAddr, ethAddr, amtToSwap); + uint ethBought = finalAmt; + if (bestExchange == 0) { + ethBought += swapEth2Dai(daiAddr, wethAddr, amtToSwap); + } else if (bestExchange == 1) { + ethBought += swapKyber(daiAddr, ethAddr, amtToSwap); + } else { + ethBought += swapUniswap(daiAddr, ethAddr, amtToSwap); + } + destAmt = daiToEthLoop(nextSrcAmt, splitAmt, ethBought); + } else if (srcAmt > 0) { + (uint bestExchange,) = getBest(daiAddr, ethAddr, srcAmt); + destAmt = finalAmt; + if (bestExchange == 0) { + destAmt += swapEth2Dai(daiAddr, wethAddr, srcAmt); + } else if (bestExchange == 1) { + destAmt += swapKyber(daiAddr, ethAddr, srcAmt); + } else { + destAmt += swapUniswap(daiAddr, ethAddr, srcAmt); + } + } else { + TokenInterface wethContract = TokenInterface(wethAddr); + uint balanceWeth = wethContract.balanceOf(address(this)); + wethContract.withdraw(balanceWeth); + destAmt = finalAmt; + } + } + + function swapEth2Dai(address src, address dest, uint srcAmt) internal returns (uint destAmt) { + if (src == wethAddr) { + TokenInterface(wethAddr).deposit.value(srcAmt)(); + } + destAmt = Eth2DaiInterface(eth2daiAddr).sellAllAmount( + src, + srcAmt, + dest, + 0 + ); + } + + function swapKyber(address src, address dest, uint srcAmt) internal returns (uint destAmt) { + destAmt = KyberInterface(kyberAddr).trade.value(srcAmt)( + src, + srcAmt, + dest, + address(this), + 2**255, + 0, + admin + ); + } + + function swapUniswap(address src, address dest, uint srcAmt) internal returns (uint destAmt) { + if (src == ethAddr) { + destAmt = UniswapExchange(uniswapAddr).ethToTokenSwapInput.value(srcAmt)(uint(0), uint(1899063809)); + } else if (dest == ethAddr) { + destAmt = UniswapExchange(uniswapAddr).tokenToEthSwapInput(srcAmt, uint(0), uint(1899063809)); + } + } + +} + + +contract SplitSwap is SplitResolver { + + function ethToDaiSwap(uint splitAmt, uint slippageAmt) public payable returns (uint destAmt) { // srcAmt = msg.value + require(maxSplitAmtEth >= splitAmt, "split amt > max"); + destAmt = ethToDaiLoop(msg.value, splitAmt, 0); + require(destAmt > slippageAmt, "Dest Amt < slippage"); + require(TokenInterface(daiAddr).transfer(msg.sender, destAmt), "Not enough DAI to transfer"); + } + + function daiToEthSwap(uint srcAmt, uint splitAmt, uint slippageAmt) public payable returns (uint destAmt) { + require(maxSplitAmtDai >= splitAmt, "split amt > max"); + require(TokenInterface(daiAddr).transferFrom(msg.sender, address(this), srcAmt), "Token Approved?"); + destAmt = daiToEthLoop(srcAmt, splitAmt, 0); + require(destAmt > slippageAmt, "Dest Amt < slippage"); + msg.sender.transfer(destAmt); + } + +} + + +contract InstaSwap is SplitSwap { + + constructor(uint _version) public { + setAllowance(TokenInterface(daiAddr), eth2daiAddr); + setAllowance(TokenInterface(daiAddr), kyberAddr); + setAllowance(TokenInterface(daiAddr), uniswapAddr); + setAllowance(TokenInterface(wethAddr), eth2daiAddr); + setAllowance(TokenInterface(wethAddr), wethAddr); + } + + function() external payable {} + +} \ No newline at end of file