From e9e1b61f2c9ea542defb62d01354f4603df92684 Mon Sep 17 00:00:00 2001 From: owen05 Date: Fri, 11 Dec 2020 18:09:12 +0800 Subject: [PATCH] add mixSwapV1 --- .../DODOVendingMachine/impl/DVMAdmin.sol | 8 ++ contracts/SmartRoute/DODOV1Proxy01.sol | 82 +++++++++++++++++-- contracts/SmartRoute/DODOV2Proxy01.sol | 14 ++++ contracts/SmartRoute/intf/IChi.sol | 9 +- contracts/SmartRoute/intf/IDODOV1Proxy01.sol | 11 +++ contracts/SmartRoute/intf/IUni.sol | 12 +++ 6 files changed, 123 insertions(+), 13 deletions(-) create mode 100644 contracts/SmartRoute/intf/IUni.sol diff --git a/contracts/DODOVendingMachine/impl/DVMAdmin.sol b/contracts/DODOVendingMachine/impl/DVMAdmin.sol index 45cb869..4c6e76a 100644 --- a/contracts/DODOVendingMachine/impl/DVMAdmin.sol +++ b/contracts/DODOVendingMachine/impl/DVMAdmin.sol @@ -15,6 +15,12 @@ import {IExternalValue} from "../../lib/ExternalValue.sol"; contract DVMAdmin is InitializableOwnable { address public _DVM_; + // ============ Events ============ + + event SetLpFeeRate(uint256 newLpFeeRate); + + event SetMtFeeRate(uint256 newMtFeeRate); + function init(address owner, address dvm) external { initOwner(owner); _DVM_ = dvm; @@ -26,6 +32,7 @@ contract DVMAdmin is InitializableOwnable { function setLpFeeRateValue(uint256 newLpFeeRate) external onlyOwner { IExternalValue(IDVM(_DVM_)._LP_FEE_RATE_MODEL_()).set(newLpFeeRate); + emit SetLpFeeRate(newLpFeeRate); } // function setMtFeeRateModel(address newMtFeeRateModel) external onlyOwner { @@ -34,6 +41,7 @@ contract DVMAdmin is InitializableOwnable { function setMtFeeRateValue(uint256 newMtFeeRate) external onlyOwner { IExternalValue(IDVM(_DVM_)._MT_FEE_RATE_MODEL_()).set(newMtFeeRate); + emit SetMtFeeRate(newMtFeeRate); } // function setTradePermissionManager(address newTradePermissionManager) external onlyOwner { diff --git a/contracts/SmartRoute/DODOV1Proxy01.sol b/contracts/SmartRoute/DODOV1Proxy01.sol index 94a515a..fbeb681 100644 --- a/contracts/SmartRoute/DODOV1Proxy01.sol +++ b/contracts/SmartRoute/DODOV1Proxy01.sol @@ -14,6 +14,7 @@ import {IDODOV1} from "./intf/IDODOV1.sol"; import {IDODOSellHelper} from "./helper/DODOSellHelper.sol"; import {IWETH} from "../intf/IWETH.sol"; import {IChi} from "./intf/IChi.sol"; +import {IUni} from "./intf/IUni.sol"; import {IDODOApprove} from "../intf/IDODOApprove.sol"; import {IDODOV1Proxy01} from "./intf/IDODOV1Proxy01.sol"; import {ReentrancyGuard} from "../lib/ReentrancyGuard.sol"; @@ -104,7 +105,7 @@ contract DODOV1Proxy01 is IDODOV1Proxy01, ReentrancyGuard, Ownable { IWETH(_WETH_).deposit{value: fromTokenAmount}(); } - for (uint256 i = 0; i < dodoPairs.length; i++) { + for (uint8 i = 0; i < dodoPairs.length; i++) { address curDodoPair = dodoPairs[i]; if (directions[i] == 0) { address curDodoBase = IDODOV1(curDodoPair)._BASE_TOKEN_(); @@ -148,7 +149,7 @@ contract DODOV1Proxy01 is IDODOV1Proxy01, ReentrancyGuard, Ownable { address fromToken, address toToken, address approveTarget, - address to, + address swapTarget, uint256 fromTokenAmount, uint256 minReturnAmount, bytes memory callDataConcat, @@ -169,10 +170,10 @@ contract DODOV1Proxy01 is IDODOV1Proxy01, ReentrancyGuard, Ownable { IERC20(_fromToken).universalApproveMax(approveTarget, fromTokenAmount); } - require(isWhiteListed[to], "DODOV1Proxy01: Not Whitelist Contract"); - (bool success, ) = to.call{value: _fromToken == _ETH_ADDRESS_ ? msg.value : 0}(callDataConcat); + require(isWhiteListed[swapTarget], "DODOV1Proxy01: Not Whitelist Contract"); + (bool success, ) = swapTarget.call{value: _fromToken == _ETH_ADDRESS_ ? msg.value : 0}(callDataConcat); - require(success, "DODOV1Proxy01: Contract Swap execution Failed"); + require(success, "DODOV1Proxy01: External Swap execution Failed"); IERC20(_fromToken).universalTransfer( msg.sender, @@ -194,4 +195,75 @@ contract DODOV1Proxy01 is IDODOV1Proxy01, ReentrancyGuard, Ownable { IChi(_CHI_TOKEN_).freeUpTo(_gasExternalReturn); } } + + + function mixSwapV1( + address fromToken, + address toToken, + uint256 fromTokenAmount, + uint256 minReturnAmount, + address[] memory mixPairs, + uint8[] memory directions, + address[] memory portionPath, + uint256 deadLine + ) external override payable judgeExpired(deadLine) returns (uint256 returnAmount) { + require(mixPairs.length == directions.length, "DODOV1Proxy01: PARAMS_LENGTH_NOT_MATCH"); + uint256 toTokenOriginBalance = IERC20(toToken).universalBalanceOf(msg.sender); + + if (fromToken != _ETH_ADDRESS_) { + IDODOApprove(_DODO_APPROVE_).claimTokens( + fromToken, + msg.sender, + address(this), + fromTokenAmount + ); + } else { + require(msg.value == fromTokenAmount, "DODOV1Proxy01: ETH_AMOUNT_NOT_MATCH"); + IWETH(_WETH_).deposit{value: fromTokenAmount}(); + } + + for (uint8 i = 0; i < mixPairs.length; i++) { + address curPair = mixPairs[i]; + if (directions[i] == 0) { + address curDodoBase = IDODOV1(curPair)._BASE_TOKEN_(); + uint256 curAmountIn = IERC20(curDodoBase).balanceOf(address(this)); + IERC20(curDodoBase).universalApproveMax(curPair, curAmountIn); + IDODOV1(curPair).sellBaseToken(curAmountIn, 0, ""); + } else if(directions[i] == 1){ + address curDodoQuote = IDODOV1(curPair)._QUOTE_TOKEN_(); + uint256 curAmountIn = IERC20(curDodoQuote).balanceOf(address(this)); + IERC20(curDodoQuote).universalApproveMax(curPair, curAmountIn); + uint256 canBuyBaseAmount = IDODOSellHelper(_DODO_SELL_HELPER_).querySellQuoteToken( + curPair, + curAmountIn + ); + IDODOV1(curPair).buyBaseToken(canBuyBaseAmount, curAmountIn, ""); + } else { + uint256 curAmountIn = IERC20(portionPath[0]).balanceOf(address(this)); + IERC20(portionPath[0]).universalApproveMax(curPair, curAmountIn); + IUni(curPair).swapExactTokensForTokens(curAmountIn,0,portionPath,address(this),deadLine); + } + } + + IERC20(fromToken).universalTransfer( + msg.sender, + IERC20(fromToken).universalBalanceOf(address(this)) + ); + + IERC20(toToken).universalTransfer( + msg.sender, + IERC20(toToken).universalBalanceOf(address(this)) + ); + + returnAmount = IERC20(toToken).universalBalanceOf(msg.sender).sub(toTokenOriginBalance); + require(returnAmount >= minReturnAmount, "DODOV1Proxy01: Return amount is not enough"); + + emit OrderHistory(fromToken, toToken, msg.sender, fromTokenAmount, returnAmount); + + uint8 _gasExternalReturn = _GAS_EXTERNAL_RETURN_; + if(_gasExternalReturn > 0) { + if(gasleft() > 27710 + _gasExternalReturn * 6080) + IChi(_CHI_TOKEN_).freeUpTo(_gasExternalReturn); + } + } } diff --git a/contracts/SmartRoute/DODOV2Proxy01.sol b/contracts/SmartRoute/DODOV2Proxy01.sol index 0d808b2..de845a9 100644 --- a/contracts/SmartRoute/DODOV2Proxy01.sol +++ b/contracts/SmartRoute/DODOV2Proxy01.sol @@ -537,6 +537,20 @@ contract DODOV2Proxy01 is IDODOV2Proxy01, ReentrancyGuard, Ownable { emit OrderHistory(fromToken, toToken, msg.sender, fromTokenAmount, returnAmount); } + //TODO: + function mixSwapV1( + address fromToken, + address toToken, + uint256 fromTokenAmount, + uint256 minReturnAmount, + address[] memory mixPairs, + uint8[] memory directions, + address[] memory portionPath, + uint256 deadLine + ) external override payable judgeExpired(deadLine) returns (uint256 returnAmount) { + return 0; + } + function addLiquidityToV1( address to, diff --git a/contracts/SmartRoute/intf/IChi.sol b/contracts/SmartRoute/intf/IChi.sol index 0478701..f82576a 100644 --- a/contracts/SmartRoute/intf/IChi.sol +++ b/contracts/SmartRoute/intf/IChi.sol @@ -1,13 +1,6 @@ -/* - - Copyright 2020 DODO ZOO. - SPDX-License-Identifier: Apache-2.0 - -*/ - pragma solidity 0.6.9; pragma experimental ABIEncoderV2; interface IChi { function freeUpTo(uint256 value) external returns (uint256); -} +} \ No newline at end of file diff --git a/contracts/SmartRoute/intf/IDODOV1Proxy01.sol b/contracts/SmartRoute/intf/IDODOV1Proxy01.sol index 8522581..0c4d88c 100644 --- a/contracts/SmartRoute/intf/IDODOV1Proxy01.sol +++ b/contracts/SmartRoute/intf/IDODOV1Proxy01.sol @@ -29,4 +29,15 @@ interface IDODOV1Proxy01 { bytes memory callDataConcat, uint256 deadLine ) external payable returns (uint256 returnAmount); + + function mixSwapV1( + address fromToken, + address toToken, + uint256 fromTokenAmount, + uint256 minReturnAmount, + address[] memory mixPairs, + uint8[] memory directions, + address[] memory portionPath, + uint256 deadLine + ) external payable returns (uint256 returnAmount); } diff --git a/contracts/SmartRoute/intf/IUni.sol b/contracts/SmartRoute/intf/IUni.sol new file mode 100644 index 0000000..b18799b --- /dev/null +++ b/contracts/SmartRoute/intf/IUni.sol @@ -0,0 +1,12 @@ +pragma solidity 0.6.9; +pragma experimental ABIEncoderV2; + +interface IUni { + function swapExactTokensForTokens( + uint amountIn, + uint amountOutMin, + address[] calldata path, + address to, + uint deadline + ) external returns (uint[] memory amounts); +} \ No newline at end of file