diff --git a/contracts/SmartRoute/adapter/DepthAdapter.sol b/contracts/SmartRoute/adapter/DepthAdapter.sol deleted file mode 100644 index bf0eb25..0000000 --- a/contracts/SmartRoute/adapter/DepthAdapter.sol +++ /dev/null @@ -1,47 +0,0 @@ -/* - - Copyright 2020 DODO ZOO. - SPDX-License-Identifier: Apache-2.0 - -*/ - -pragma solidity 0.6.9; - -import {IDODOAdapter} from "../intf/IDODOAdapter.sol"; -import {IDepth} from "../intf/IDepth.sol"; -import {IERC20} from "../../intf/IERC20.sol"; -import {SafeMath} from "../../lib/SafeMath.sol"; - -contract DepthUnderlyingAdapter is IDODOAdapter { - using SafeMath for uint; - - //fromToken == token[0], underlying - function sellBase(address to, address pool) external override { - address baseToken = IDepth(pool).underlying_coins(0); - uint256 sellBaseAmount = IERC20(baseToken).balanceOf(address(this)); - - // approve - IERC20(baseToken).approve(pool, sellBaseAmount); - // swap - IDepth(pool).exchange_underlying(0, 1, sellBaseAmount, 0); - if(to != address(this)) { - address curQuote = IDepth(pool).underlying_coins(1); - SafeERC20.safeTransfer(IERC20(curQuote), to, IERC20(curQuote).tokenBalanceOf(address(this))); - } - } - - //fromToken == token[1], underlying - function sellQuote(address to, address pool) external override { - address quoteToken = IDepth(pool).underlying_coins(1); - uint256 sellQuoteAmount = IERC20(quoteToken).balanceOf(address(this)); - - // approve - IERC20(quoteToken).approve(pool, sellQuoteAmount); - // swap - IDepth(pool).exchange_underlying(1, 0, sellQuoteAmount, 0); - if(to != address(this)) { - address curBase = IDepth(pool).underlying_coins(0); - SafeERC20.safeTransfer(IERC20(curBase), to, IERC20(curBase).tokenBalanceOf(address(this))); - } - } -} \ No newline at end of file diff --git a/contracts/SmartRoute/adapter/DepthUnderlyingAdapter.sol b/contracts/SmartRoute/adapter/DepthUnderlyingAdapter.sol new file mode 100644 index 0000000..f4154a8 --- /dev/null +++ b/contracts/SmartRoute/adapter/DepthUnderlyingAdapter.sol @@ -0,0 +1,52 @@ +/* + + Copyright 2020 DODO ZOO. + SPDX-License-Identifier: Apache-2.0 + +*/ + +pragma solidity 0.6.9; + +import {IDODOAdapter} from "../intf/IDODOAdapter.sol"; +import {IDepth} from "../intf/IDepth.sol"; +import {IERC20} from "../../intf/IERC20.sol"; +import {SafeMath} from "../../lib/SafeMath.sol"; +import {UniversalERC20} from "../lib/UniversalERC20.sol"; +import {SafeERC20} from "../../lib/SafeERC20.sol"; + +// for two tokens +contract DepthUnderlyingAdapter is IDODOAdapter { + using SafeMath for uint; + + //fromToken == token[0], underlying + function sellBase(address to, address pool, bytes memory moreInfo) external override { + (address fromToken, address toToken, int128 i, int128 j) = abi.decode(moreInfo, (address, address, int128, int128)); + require(fromToken == IDepth(pool).underlying_coins(i), 'DepthAdapter: WRONG_TOKEN'); + require(toToken == IDepth(pool).underlying_coins(j), 'DepthAdapter: WRONG_TOKEN'); + uint256 sellBaseAmount = IERC20(fromToken).balanceOf(address(this)); + + // approve + IERC20(fromToken).approve(pool, sellBaseAmount); + // swap + IDepth(pool).exchange_underlying(i, j, sellBaseAmount, 0); + if(to != address(this)) { + SafeERC20.safeTransfer(IERC20(toToken), to, IERC20(toToken).balanceOf(address(this))); + } + } + + //fromToken == token[1], underlying + function sellQuote(address to, address pool, bytes memory moreInfo) external override { + (address fromToken, address toToken, int128 i, int128 j) = abi.decode(moreInfo, (address, address, int128, int128)); + require(fromToken == IDepth(pool).underlying_coins(i), 'DepthAdapter: WRONG_TOKEN'); + require(toToken == IDepth(pool).underlying_coins(j), 'DepthAdapter: WRONG_TOKEN'); + uint256 sellQuoteAmount = IERC20(toToken).balanceOf(address(this)); + + // approve + IERC20(toToken).approve(pool, sellQuoteAmount); + // swap + IDepth(pool).exchange_underlying(i, j, sellQuoteAmount, 0); + if(to != address(this)) { + SafeERC20.safeTransfer(IERC20(fromToken), to, IERC20(fromToken).balanceOf(address(this))); + } + } +} \ No newline at end of file diff --git a/contracts/SmartRoute/adapter/UniAdapter.sol b/contracts/SmartRoute/adapter/UniAdapter.sol index 324e195..8cfc184 100644 --- a/contracts/SmartRoute/adapter/UniAdapter.sol +++ b/contracts/SmartRoute/adapter/UniAdapter.sol @@ -24,10 +24,13 @@ contract UniAdapter is IDODOAdapter { uint balance0 = IERC20(baseToken).balanceOf(pool); uint sellBaseAmount = balance0 - reserveIn; + uint receiveQuoteAmount = 0; + { uint sellBaseAmountWithFee = sellBaseAmount.mul(997); uint numerator = sellBaseAmountWithFee.mul(reserveOut); uint denominator = reserveIn.mul(1000).add(sellBaseAmountWithFee); - uint receiveQuoteAmount = numerator / denominator; + receiveQuoteAmount = numerator / denominator; + } IUni(pool).swap(0, receiveQuoteAmount, to, new bytes(0)); } @@ -40,10 +43,13 @@ contract UniAdapter is IDODOAdapter { uint balance1 = IERC20(quoteToken).balanceOf(pool); uint sellQuoteAmount = balance1 - reserveIn; + uint receiveBaseAmount = 0; + { uint sellQuoteAmountWithFee = sellQuoteAmount.mul(997); uint numerator = sellQuoteAmountWithFee.mul(reserveOut); uint denominator = reserveIn.mul(1000).add(sellQuoteAmountWithFee); - uint receiveBaseAmount = numerator / denominator; + receiveBaseAmount = numerator / denominator; + } IUni(pool).swap(receiveBaseAmount, 0, to, new bytes(0)); } } \ No newline at end of file diff --git a/contracts/SmartRoute/proxies/DODORouteProxy.sol b/contracts/SmartRoute/proxies/DODORouteProxy.sol index 51c3c56..47b5e56 100644 --- a/contracts/SmartRoute/proxies/DODORouteProxy.sol +++ b/contracts/SmartRoute/proxies/DODORouteProxy.sol @@ -33,6 +33,15 @@ contract DODORouteProxy { address public immutable _WETH_; address public immutable _DODO_APPROVE_PROXY_; + struct PoolInfo { + uint256 direction; + uint256 poolEdition; + uint256 weight; + address pool; + address adapter; + bytes moreInfo; + } + // ============ Events ============ event OrderHistory( @@ -62,6 +71,59 @@ contract DODORouteProxy { _DODO_APPROVE_PROXY_ = dodoApproveProxy; } + function mixSwap( + address fromToken, + address toToken, + uint256 fromTokenAmount, + uint256 minReturnAmount, + address[] memory mixAdapters, + address[] memory mixPairs, + address[] memory assetTo, + uint256 directions, + bool isIncentive, + uint256 deadLine + ) external payable judgeExpired(deadLine) returns (uint256 returnAmount) { + require(mixPairs.length > 0, "DODOV2Proxy02: PAIRS_EMPTY"); + require(mixPairs.length == mixAdapters.length, "DODOV2Proxy02: PAIR_ADAPTER_NOT_MATCH"); + require(mixPairs.length == assetTo.length - 1, "DODOV2Proxy02: PAIR_ASSETTO_NOT_MATCH"); + require(minReturnAmount > 0, "DODOV2Proxy02: RETURN_AMOUNT_ZERO"); + + address _fromToken = fromToken; + address _toToken = toToken; + uint256 _fromTokenAmount = fromTokenAmount; + + uint256 toTokenOriginBalance = IERC20(_toToken).universalBalanceOf(msg.sender); + + _deposit(msg.sender, assetTo[0], _fromToken, _fromTokenAmount, _fromToken == _ETH_ADDRESS_); + + for (uint256 i = 0; i < mixPairs.length; i++) { + if (directions & 1 == 0) { + IDODOAdapter(mixAdapters[i]).sellBase(assetTo[i + 1],mixPairs[i], ""); + } else { + IDODOAdapter(mixAdapters[i]).sellQuote(assetTo[i + 1],mixPairs[i], ""); + } + directions = directions >> 1; + } + + if(_toToken == _ETH_ADDRESS_) { + returnAmount = IWETH(_WETH_).balanceOf(address(this)); + IWETH(_WETH_).withdraw(returnAmount); + msg.sender.transfer(returnAmount); + }else { + returnAmount = IERC20(_toToken).tokenBalanceOf(msg.sender).sub(toTokenOriginBalance); + } + + require(returnAmount >= minReturnAmount, "DODOV2Proxy02: Return amount is not enough"); + + emit OrderHistory( + _fromToken, + _toToken, + msg.sender, + _fromTokenAmount, + returnAmount + ); + } + function dodoMutliSwap( uint256 fromTokenAmount, uint256 minReturnAmount, @@ -119,27 +181,34 @@ contract DODORouteProxy { uint256 curTotalWeight = totalWeight[i-1]; for(uint256 j = splitNumber[i-1]; j < splitNumber[i]; j++) { - (address pool, address adapter, uint256 mixPara) = abi.decode(swapSequence[j], (address, address, uint256)); - uint256 direction = mixPara >> 17; - uint256 weight = (0xffff & mixPara) >> 9; - uint256 poolEdition = (0xff & mixPara); + PoolInfo memory curPoolInfo; + { + (address pool, address adapter, uint256 mixPara, bytes memory moreInfo) = abi.decode(swapSequence[j], (address, address, uint256, bytes)); + + curPoolInfo.direction = mixPara >> 17; + curPoolInfo.weight = (0xffff & mixPara) >> 9; + curPoolInfo.poolEdition = (0xff & mixPara); + curPoolInfo.pool = pool; + curPoolInfo.adapter = adapter; + curPoolInfo.moreInfo = moreInfo; + } if(assetFrom[i-1] == address(this)) { - uint256 curAmount = curTotalAmount.div(curTotalWeight).mul(weight); + uint256 curAmount = curTotalAmount.div(curTotalWeight).mul(curPoolInfo.weight); - if(poolEdition == 1) { - //For using transferFrom pool (like dodoV1) - IERC20(midToken[i]).transfer(adapter, curAmount); + if(curPoolInfo.poolEdition == 1) { + //For using transferFrom pool (like dodoV1, Curve) + IERC20(midToken[i]).transfer(curPoolInfo.adapter, curAmount); } else { //For using transfer pool (like dodoV2) - IERC20(midToken[i]).transfer(pool, curAmount); + IERC20(midToken[i]).transfer(curPoolInfo.pool, curAmount); } } - if(direction == 0) { - IDODOAdapter(adapter).sellBase(assetFrom[i], pool, ""); + if(curPoolInfo.direction == 0) { + IDODOAdapter(curPoolInfo.adapter).sellBase(assetFrom[i], curPoolInfo.pool, curPoolInfo.moreInfo); } else { - IDODOAdapter(adapter).sellQuote(assetFrom[i], pool, ""); + IDODOAdapter(curPoolInfo.adapter).sellQuote(assetFrom[i], curPoolInfo.pool, curPoolInfo.moreInfo); } } } diff --git a/deploy-detail-periphery.txt b/deploy-detail-periphery.txt index a76dc45..26fa3d1 100644 --- a/deploy-detail-periphery.txt +++ b/deploy-detail-periphery.txt @@ -475,3 +475,8 @@ network type: heco Deploy time: 2021/4/29 上午10:33:01 Deploy type: DODOCpProxy CpProxy address: 0x8930101c6cFbe0f3cb31E7526a16E72255388E97 +==================================================== +network type: heco +Deploy time: 2021/5/7 下午5:07:08 +Deploy type: test - Adapter +test_Adapter Address: 0x31AC053c31a77055b2ae2d3899091C0A9c19cE3a diff --git a/migrations/4_deploy_periphery.js b/migrations/4_deploy_periphery.js index 6422ed7..617c3ed 100644 --- a/migrations/4_deploy_periphery.js +++ b/migrations/4_deploy_periphery.js @@ -28,13 +28,14 @@ const DODOV2RouteHelper = artifacts.require("DODOV2RouteHelper"); const ERC20Mine = artifacts.require("ERC20Mine"); const vDODOMine = artifacts.require("vDODOMine"); +const DepthAdapter = artifacts.require("DepthUnderlyingAdapter"); + module.exports = async (deployer, network, accounts) => { let CONFIG = GetConfig(network, accounts) if (CONFIG == null) return; let WETHAddress = CONFIG.WETH; let DODOTokenAddress = CONFIG.DODO; - let WETHAddress = CONFIG.WETH; let DODOApproveProxyAddress = CONFIG.DODOApproveProxy; let DspTemplateAddress = CONFIG.DSP; @@ -374,7 +375,7 @@ module.exports = async (deployer, network, accounts) => { logger.log("===================================================="); logger.log("network type: " + network); logger.log("Deploy time: " + new Date().toLocaleString()); - logger.log("Deploy type: RAB - Adapter"); + logger.log("Deploy type: MaxHops - Adapter"); await deployer.deploy( RABSwap, @@ -382,6 +383,17 @@ module.exports = async (deployer, network, accounts) => { DODOApproveProxyAddress ); - logger.log("DODORAB Address: ", RABSwap.address); + logger.log("DODOMaxHops Address: ", RABSwap.address); + } + + if(deploySwitch.test_ADAPTER) { + logger.log("===================================================="); + logger.log("network type: " + network); + logger.log("Deploy time: " + new Date().toLocaleString()); + logger.log("Deploy type: test - Adapter"); + + await deployer.deploy(DepthAdapter); + + logger.log("test_Adapter Address: ", DepthAdapter.address); } };