diff --git a/contracts/SmartRoute/DODOV1Proxy01.sol b/contracts/SmartRoute/DODOV1Proxy01.sol index 5cbb5c4..46f47a0 100644 --- a/contracts/SmartRoute/DODOV1Proxy01.sol +++ b/contracts/SmartRoute/DODOV1Proxy01.sol @@ -10,12 +10,14 @@ pragma solidity 0.6.9; import {IERC20} from "../intf/IERC20.sol"; import {UniversalERC20} from "./lib/UniversalERC20.sol"; import {SafeMath} from "../lib/SafeMath.sol"; -import {IDODOSellHelper} from "./intf/IDODOSellHelper.sol"; -import {IDODOApprove} from "../intf/IDODOApprove.sol"; import {IDODOV1} from "./intf/IDODOV1.sol"; +import {IDODOSellHelper} from './helper/DODOSellHelper.sol'; import {IWETH} from "../intf/IWETH.sol"; +import {IDODOApprove} from "../intf/IDODOApprove.sol"; +import {IDODOV1Proxy01} from "./intf/IDODOV1Proxy01.sol"; +// import {ReentrancyGuard} from "../lib/ReentrancyGuard.sol"; -contract DODOV1Proxy01 { +contract DODOV1Proxy01 is IDODOV1Proxy01 { using SafeMath for uint256; using UniversalERC20 for IERC20; @@ -60,7 +62,7 @@ contract DODOV1Proxy01 { address[] memory dodoPairs, uint8[] memory directions, uint256 deadline - ) external payable judgeExpired(deadline) returns (uint256 returnAmount) { + ) external virtual override payable judgeExpired(deadline) returns (uint256 returnAmount) { if (fromToken != ETH_ADDRESS) { IDODOApprove(dodoApprove).claimTokens( fromToken, @@ -92,15 +94,13 @@ contract DODOV1Proxy01 { } } - if (toToken == ETH_ADDRESS) { - uint256 wethAmount = IWETH(_WETH_).balanceOf(address(this)); - IWETH(_WETH_).withdraw(wethAmount); - } - returnAmount = IERC20(toToken).universalBalanceOf(address(this)); - require(returnAmount >= minReturnAmount, "DODOV1Proxy01: Return amount is not enough"); + + if (toToken == ETH_ADDRESS) + IWETH(_WETH_).withdraw(returnAmount); IERC20(toToken).universalTransfer(msg.sender, returnAmount); + emit OrderHistory( fromToken, toToken, @@ -120,7 +120,7 @@ contract DODOV1Proxy01 { uint256 minReturnAmount, bytes memory callDataConcat, uint256 deadline - ) external payable judgeExpired(deadline) returns (uint256 returnAmount) { + ) external virtual override payable judgeExpired(deadline) returns (uint256 returnAmount) { if (fromToken != ETH_ADDRESS) { IDODOApprove(dodoApprove).claimTokens( fromToken, diff --git a/contracts/SmartRoute/DODOV2Proxy01.sol b/contracts/SmartRoute/DODOV2Proxy01.sol index f5f02c2..4a83eac 100644 --- a/contracts/SmartRoute/DODOV2Proxy01.sol +++ b/contracts/SmartRoute/DODOV2Proxy01.sol @@ -9,12 +9,16 @@ pragma solidity 0.6.9; import {IDODOV2Proxy01} from "./intf/IDODOV2Proxy01.sol"; import {IDODOV2} from "./intf/IDODOV2.sol"; +import {IDODOV1} from "./intf/IDODOV1.sol"; +import {IDODOApprove} from '../intf/IDODOApprove.sol'; +import {IDODOSellHelper} from './helper/DODOSellHelper.sol'; import {IERC20} from "../intf/IERC20.sol"; import {IWETH} from "../intf/IWETH.sol"; import {SafeMath} from "../lib/SafeMath.sol"; import {UniversalERC20} from "./lib/UniversalERC20.sol"; import {SafeERC20} from "../lib/SafeERC20.sol"; import {DecimalMath} from "../lib/DecimalMath.sol"; +// import {ReentrancyGuard} from "../lib/ReentrancyGuard.sol"; contract DODOV2Proxy01 is IDODOV2Proxy01 { using SafeMath for uint256; @@ -23,6 +27,7 @@ contract DODOV2Proxy01 is IDODOV2Proxy01 { address constant ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE; address payable public _WETH_; address public dodoApprove; + address public dodoSellHelper; address public dvmFactory; address public dppFactory; @@ -35,7 +40,7 @@ contract DODOV2Proxy01 is IDODOV2Proxy01 { receive() external payable {} - //============================== events ================================== + event OrderHistory( address indexed fromToken, address indexed toToken, @@ -45,18 +50,18 @@ contract DODOV2Proxy01 is IDODOV2Proxy01 { uint256 timeStamp ); - //======================================================================== - constructor( address _dvmFactory, address _dppFactory, address payable _weth, - address _dodoApprove + address _dodoApprove, + address _dodoSellHelper ) public { dvmFactory = _dvmFactory; dppFactory = _dppFactory; _WETH_ = _weth; dodoApprove = _dodoApprove; + dodoSellHelper = _dodoSellHelper; } function createDODOVendingMachine( @@ -179,7 +184,7 @@ contract DODOV2Proxy01 is IDODOV2Proxy01 { (shares, , ) = IDODOV2(_dvm).buyShares(to); } - + // ===================== Permit ====================== function removeDVMLiquidity( address DVMAddress, address payable to, @@ -201,8 +206,6 @@ contract DODOV2Proxy01 is IDODOV2Proxy01 { } } - - // ================ Permit ====================== function removeDVMLiquidityWithPermit( address DVMAddress, address payable to, @@ -352,7 +355,7 @@ contract DODOV2Proxy01 is IDODOV2Proxy01 { uint8[] memory directions, uint256 deadline ) external virtual override judgeExpired(deadline) returns (uint256 returnAmount) { - IDODOV2(dodoApprove).claimTokens(fromToken, msg.sender, dodoPairs[0], fromTokenAmount); + IDODOApprove(dodoApprove).claimTokens(fromToken, msg.sender, dodoPairs[0], fromTokenAmount); for (uint256 i = 0; i < dodoPairs.length; i++) { if (i == dodoPairs.length - 1) { @@ -394,7 +397,7 @@ contract DODOV2Proxy01 is IDODOV2Proxy01 { uint256 deadline ) external virtual override judgeExpired(deadline) returns (uint256 returnAmount) { uint256 originToTokenBalance = IERC20(toToken).balanceOf(msg.sender); - IDODOV2(dodoApprove).claimTokens(fromToken, msg.sender, dodoPairs[0], fromTokenAmount); + IDODOApprove(dodoApprove).claimTokens(fromToken, msg.sender, dodoPairs[0], fromTokenAmount); for (uint256 i = 0; i < dodoPairs.length; i++) { if (i == dodoPairs.length - 1) { @@ -434,7 +437,7 @@ contract DODOV2Proxy01 is IDODOV2Proxy01 { uint256 deadline ) external virtual override payable judgeExpired(deadline) returns (uint256 returnAmount) { if (fromToken != ETH_ADDRESS) { - IDODOV2(dodoApprove).claimTokens(fromToken, msg.sender, address(this), fromTokenAmount); + IDODOApprove(dodoApprove).claimTokens(fromToken, msg.sender, address(this), fromTokenAmount); IERC20(fromToken).universalApproveMax(approveTarget, fromTokenAmount); } @@ -461,6 +464,51 @@ contract DODOV2Proxy01 is IDODOV2Proxy01 { ); } + function dodoSwap( + address fromToken, + address toToken, + uint256 fromTokenAmount, + uint256 minReturnAmount, + address[] memory dodoPairs, + uint8[] memory directions, + uint256 deadline + ) external virtual override payable judgeExpired(deadline) returns (uint256 returnAmount) { + _deposit(msg.sender,address(this),fromToken,fromTokenAmount, fromToken == ETH_ADDRESS); + + for (uint256 i = 0; i < dodoPairs.length; i++) { + address curDodoPair = dodoPairs[i]; + if (directions[i] == 0) { + address curDodoBase = IDODOV1(curDodoPair)._BASE_TOKEN_(); + uint256 curAmountIn = IERC20(curDodoBase).balanceOf(address(this)); + IERC20(curDodoBase).universalApproveMax(curDodoPair, curAmountIn); + IDODOV1(curDodoPair).sellBaseToken(curAmountIn, 0, ""); + } else { + address curDodoQuote = IDODOV1(curDodoPair)._QUOTE_TOKEN_(); + uint256 curAmountIn = IERC20(curDodoQuote).balanceOf(address(this)); + IERC20(curDodoQuote).universalApproveMax(curDodoPair, curAmountIn); + uint256 canBuyBaseAmount = IDODOSellHelper(dodoSellHelper).querySellQuoteToken( + curDodoPair, + curAmountIn + ); + IDODOV1(curDodoPair).buyBaseToken(canBuyBaseAmount, curAmountIn, ""); + } + } + + returnAmount = IERC20(toToken).universalBalanceOf(address(this)); + require(returnAmount >= minReturnAmount, "DODOV2Proxy01: Return amount is not enough"); + + _withdraw(msg.sender, toToken, returnAmount, toToken == ETH_ADDRESS); + + emit OrderHistory( + fromToken, + toToken, + msg.sender, + fromTokenAmount, + returnAmount, + block.timestamp + ); + } + function _deposit( address from, address to, @@ -471,10 +519,11 @@ contract DODOV2Proxy01 is IDODOV2Proxy01 { if (isETH) { if (amount > 0) { IWETH(_WETH_).deposit{value: amount}(); - SafeERC20.safeTransfer(IERC20(_WETH_), to, amount); + if(to != address(this)) + SafeERC20.safeTransfer(IERC20(_WETH_), to, amount); } } else { - IDODOV2(dodoApprove).claimTokens(token, from, to, amount); + IDODOApprove(dodoApprove).claimTokens(token, from, to, amount); } } diff --git a/contracts/SmartRoute/helper/DODOSellHelper.sol b/contracts/SmartRoute/helper/DODOSellHelper.sol index 7f2ea00..f517f72 100644 --- a/contracts/SmartRoute/helper/DODOSellHelper.sol +++ b/contracts/SmartRoute/helper/DODOSellHelper.sol @@ -20,6 +20,12 @@ import {DecimalMath} from "../../lib/DecimalMath.sol"; // import {DODOMath} from "../lib/DODOMath.sol"; +interface IDODOSellHelper { + function querySellQuoteToken(address dodo, uint256 amount) external view returns (uint256); + + function querySellBaseToken(address dodo, uint256 amount) external view returns (uint256); +} + library DODOMath { using SafeMath for uint256; diff --git a/contracts/SmartRoute/intf/IDODOSellHelper.sol b/contracts/SmartRoute/intf/IDODOSellHelper.sol deleted file mode 100644 index 69fa9b4..0000000 --- a/contracts/SmartRoute/intf/IDODOSellHelper.sol +++ /dev/null @@ -1,14 +0,0 @@ -/* - - Copyright 2020 DODO ZOO. - SPDX-License-Identifier: Apache-2.0 - -*/ - -pragma solidity 0.6.9; -pragma experimental ABIEncoderV2; - -interface IDODOSellHelper { - function querySellQuoteToken(address dodo, uint256 amount) external view returns (uint256); - function querySellBaseToken(address dodo, uint256 amount) external view returns (uint256); -} diff --git a/contracts/SmartRoute/intf/IDODOV1Proxy01.sol b/contracts/SmartRoute/intf/IDODOV1Proxy01.sol new file mode 100644 index 0000000..01867d9 --- /dev/null +++ b/contracts/SmartRoute/intf/IDODOV1Proxy01.sol @@ -0,0 +1,32 @@ +/* + + Copyright 2020 DODO ZOO. + SPDX-License-Identifier: Apache-2.0 + +*/ + +pragma solidity 0.6.9; +pragma experimental ABIEncoderV2; + +interface IDODOV1Proxy01 { + function dodoSwap( + address fromToken, + address toToken, + uint256 fromTokenAmount, + uint256 minReturnAmount, + address[] memory dodoPairs, + uint8[] memory directions, + uint256 deadline + ) external payable returns (uint256 returnAmount); + + function externalSwap( + address fromToken, + address toToken, + address approveTarget, + address to, + uint256 fromTokenAmount, + uint256 minReturnAmount, + bytes memory callDataConcat, + uint256 deadline + ) external payable returns (uint256 returnAmount); +} diff --git a/contracts/SmartRoute/intf/IDODOV2.sol b/contracts/SmartRoute/intf/IDODOV2.sol index 1d57c03..52f9a88 100644 --- a/contracts/SmartRoute/intf/IDODOV2.sol +++ b/contracts/SmartRoute/intf/IDODOV2.sol @@ -35,14 +35,14 @@ interface IDODOV2 { uint256 i, uint256 k ) external returns (address newVendingMachine); + + function buyShares(address to) external returns (uint256,uint256,uint256); // ============= permit ================= function permit(address owner, address spender, uint value, uint deadline, uint8 v, bytes32 r, bytes32 s) external; + function sellShares(address to) external returns (uint256,uint256); // ====================================== - function buyShares(address to) external returns (uint256,uint256,uint256); - - function sellShares(address to) external returns (uint256,uint256); //========== DODOPrivatePool =========== @@ -68,12 +68,4 @@ interface IDODOV2 { uint256 baseOutAmount, uint256 quoteOutAmount ) external; - - - //========== IDODOApprove ============= - - function claimTokens(address token,address who,address dest,uint256 amount) external; - - function getDODOProxy() external view returns (address); - } \ No newline at end of file diff --git a/contracts/SmartRoute/intf/IDODOV2Proxy01.sol b/contracts/SmartRoute/intf/IDODOV2Proxy01.sol index 43a155c..bf12941 100644 --- a/contracts/SmartRoute/intf/IDODOV2Proxy01.sol +++ b/contracts/SmartRoute/intf/IDODOV2Proxy01.sol @@ -8,7 +8,9 @@ pragma solidity 0.6.9; pragma experimental ABIEncoderV2; -interface IDODOV2Proxy01 { +import {IDODOV1Proxy01} from './IDODOV1Proxy01.sol'; + +interface IDODOV2Proxy01 is IDODOV1Proxy01 { function dodoSwapETHToToken( address payable assetTo, address toToken, @@ -40,17 +42,6 @@ interface IDODOV2Proxy01 { uint256 deadline ) external returns (uint256 returnAmount); - function externalSwap( - address fromToken, - address toToken, - address approveTarget, - address to, - uint256 fromTokenAmount, - uint256 minReturnAmount, - bytes memory callDataConcat, - uint256 deadline - ) external payable returns (uint256 returnAmount); - function createDODOVendingMachine( address assetTo, address baseToken, @@ -82,6 +73,8 @@ interface IDODOV2Proxy01 { uint256 quoteAdjustedInAmount ); + // ==================== Permit ================================ + function removeDVMLiquidity( address DVMAddress, address payable to, @@ -92,7 +85,6 @@ interface IDODOV2Proxy01 { uint256 deadline ) external returns (uint256 baseOutAmount, uint256 quoteOutAmount); - // ==================== Permit ================================ function removeDVMLiquidityWithPermit( address DVMAddress, address payable to, diff --git a/test/Proxy/proxy.dpp.test.ts b/test/Proxy/proxy.dpp.test.ts index dd39e01..2ad3958 100644 --- a/test/Proxy/proxy.dpp.test.ts +++ b/test/Proxy/proxy.dpp.test.ts @@ -259,7 +259,6 @@ describe("DODOProxyV2.0", () => { assert.equal(a_USDT,"149474926"); }); - it("swap - two jump", async () => { await ctx.mintTestToken(trader, ctx.DODO, decimalStr("1000")); var b_DOOD = await ctx.DODO.methods.balanceOf(trader).call(); @@ -355,7 +354,5 @@ describe("DODOProxyV2.0", () => { "3760778359898791539" ) }); - - }); }); diff --git a/test/utils/ProxyContext.ts b/test/utils/ProxyContext.ts index 098c03d..c58cf7b 100644 --- a/test/utils/ProxyContext.ts +++ b/test/utils/ProxyContext.ts @@ -28,6 +28,7 @@ export class ProxyContext { DPPFactory: Contract; SmartApprove: Contract; DODOCalleeHelper: Contract; + DODOSellHelper: Contract; //token DODO: Contract; @@ -94,12 +95,17 @@ export class ProxyContext { ] ) + this.DODOSellHelper = await contracts.newContract( + contracts.DODO_SELL_HELPER + ); + this.DODOProxy = await contracts.newContract(contracts.DODO_PROXY_NAME, [ this.DVMFactory.options.address, this.DPPFactory.options.address, this.WETH.options.address, - this.SmartApprove.options.address + this.SmartApprove.options.address, + this.DODOSellHelper.options.address ] );