From 38f5fe142bd934dd8ac7510eddf2307369d24a9a Mon Sep 17 00:00:00 2001 From: owen05 Date: Tue, 26 Jan 2021 17:53:49 +0800 Subject: [PATCH] fix apdater && add approve proxy --- contracts/DODOPrivatePool/impl/DPPAdmin.sol | 10 +- contracts/DODOPrivatePool/impl/DPPVault.sol | 1 - contracts/Factory/DPPFactory.sol | 12 +- contracts/SmartRoute/DODOApproveProxy.sol | 91 ++ contracts/SmartRoute/DODOV1Proxy04.sol | 283 ++++++ contracts/SmartRoute/DODOV2Proxy02.sol | 805 ++++++++++++++++++ .../SmartRoute/adapter/DODOV1Adapter.sol | 9 +- deploy-detail-v1.5.txt | 12 + deploy-detail-v2.0.txt | 79 +- kovan-mock-v2.0.txt | 12 + migrations/2_deploy_v1.5.js | 28 +- migrations/3_deploy_v2.js | 122 ++- migrations/4_deploy_v2_mock.js | 38 +- test/utils/Contracts.ts | 3 +- test/utils/ProxyContextV2.ts | 15 +- truffle-config.js | 5 +- 16 files changed, 1417 insertions(+), 108 deletions(-) create mode 100644 contracts/SmartRoute/DODOApproveProxy.sol create mode 100644 contracts/SmartRoute/DODOV1Proxy04.sol create mode 100644 contracts/SmartRoute/DODOV2Proxy02.sol diff --git a/contracts/DODOPrivatePool/impl/DPPAdmin.sol b/contracts/DODOPrivatePool/impl/DPPAdmin.sol index 24d26cb..037b3e4 100644 --- a/contracts/DODOPrivatePool/impl/DPPAdmin.sol +++ b/contracts/DODOPrivatePool/impl/DPPAdmin.sol @@ -9,7 +9,7 @@ pragma solidity 0.6.9; pragma experimental ABIEncoderV2; import {IDPP} from "../intf/IDPP.sol"; -import {IDODOApprove} from "../../intf/IDODOApprove.sol"; +import {IDODOApproveProxy} from "../../SmartRoute/DODOApproveProxy.sol"; import {InitializableOwnable} from "../../lib/InitializableOwnable.sol"; /** @@ -21,7 +21,7 @@ import {InitializableOwnable} from "../../lib/InitializableOwnable.sol"; contract DPPAdmin is InitializableOwnable { address public _DPP_; address public _OPERATOR_; - address public _DODO_APPROVE_; + address public _DODO_APPROVE_PROXY_; uint256 public _FREEZE_TIMESTAMP_; @@ -34,12 +34,12 @@ contract DPPAdmin is InitializableOwnable { address owner, address dpp, address operator, - address dodoApprove + address dodoApproveProxy ) external { initOwner(owner); _DPP_ = dpp; _OPERATOR_ = operator; - _DODO_APPROVE_ = dodoApprove; + _DODO_APPROVE_PROXY_ = dodoApproveProxy; } function sync() external notFreezed onlyOwner { @@ -74,7 +74,7 @@ contract DPPAdmin is InitializableOwnable { ) external notFreezed returns (bool) { require( msg.sender == _OWNER_ || - (msg.sender == IDODOApprove(_DODO_APPROVE_).getDODOProxy() && + (IDODOApproveProxy(_DODO_APPROVE_PROXY_).isAllowedProxy(msg.sender) && operator == _OPERATOR_), "RESET FORBIDDEN!" ); diff --git a/contracts/DODOPrivatePool/impl/DPPVault.sol b/contracts/DODOPrivatePool/impl/DPPVault.sol index c1e808e..46126eb 100644 --- a/contracts/DODOPrivatePool/impl/DPPVault.sol +++ b/contracts/DODOPrivatePool/impl/DPPVault.sol @@ -14,7 +14,6 @@ import {IDODOCallee} from "../../intf/IDODOCallee.sol"; import {SafeMath} from "../../lib/SafeMath.sol"; import {DecimalMath} from "../../lib/DecimalMath.sol"; import {SafeERC20} from "../../lib/SafeERC20.sol"; -import {Ownable} from "../../lib/Ownable.sol"; import {PMMPricing} from "../../lib/PMMPricing.sol"; contract DPPVault is DPPStorage { diff --git a/contracts/Factory/DPPFactory.sol b/contracts/Factory/DPPFactory.sol index 7c4d52d..727f4e7 100644 --- a/contracts/Factory/DPPFactory.sol +++ b/contracts/Factory/DPPFactory.sol @@ -26,7 +26,7 @@ contract DPPFactory is InitializableOwnable { address public immutable _CLONE_FACTORY_; address public immutable _DEFAULT_MAINTAINER_; address public immutable _DEFAULT_MT_FEE_RATE_MODEL_; - address public immutable _DODO_APPROVE_; + address public immutable _DODO_APPROVE_PROXY_; address public _DPP_TEMPLATE_; address public _DPP_ADMIN_TEMPLATE_; @@ -55,14 +55,14 @@ contract DPPFactory is InitializableOwnable { address dppAdminTemplate, address defaultMaintainer, address defaultMtFeeRateModel, - address dodoApprove + address dodoApproveProxy ) public { _CLONE_FACTORY_ = cloneFactory; _DPP_TEMPLATE_ = dppTemplate; _DPP_ADMIN_TEMPLATE_ = dppAdminTemplate; _DEFAULT_MAINTAINER_ = defaultMaintainer; _DEFAULT_MT_FEE_RATE_MODEL_ = defaultMtFeeRateModel; - _DODO_APPROVE_ = dodoApprove; + _DODO_APPROVE_PROXY_ = dodoApproveProxy; } // ============ Functions ============ @@ -87,7 +87,7 @@ contract DPPFactory is InitializableOwnable { creator, _dppAddress, creator, - _DODO_APPROVE_ + _DODO_APPROVE_PROXY_ ); IDPP(_dppAddress).init( adminModel, @@ -111,10 +111,10 @@ contract DPPFactory is InitializableOwnable { address owner, address dpp, address operator, - address dodoApprove + address dodoApproveProxy ) internal returns (address adminModel) { adminModel = ICloneFactory(_CLONE_FACTORY_).clone(_DPP_ADMIN_TEMPLATE_); - IDPPAdmin(adminModel).init(owner, dpp, operator, dodoApprove); + IDPPAdmin(adminModel).init(owner, dpp, operator, dodoApproveProxy); } // ============ Admin Operation Functions ============ diff --git a/contracts/SmartRoute/DODOApproveProxy.sol b/contracts/SmartRoute/DODOApproveProxy.sol new file mode 100644 index 0000000..de1ae79 --- /dev/null +++ b/contracts/SmartRoute/DODOApproveProxy.sol @@ -0,0 +1,91 @@ +/* + + Copyright 2020 DODO ZOO. + SPDX-License-Identifier: Apache-2.0 + +*/ + +pragma solidity 0.6.9; +pragma experimental ABIEncoderV2; + +import {IDODOApprove} from "../intf/IDODOApprove.sol"; +import {InitializableOwnable} from "../lib/InitializableOwnable.sol"; + +interface IDODOApproveProxy { + function isAllowedProxy(address _proxy) external view returns (bool); + function claimTokens(address token,address who,address dest,uint256 amount) external; +} + +/** + * @title DODOApproveProxy + * @author DODO Breeder + * + * @notice Allow different version dodoproxy to claim from DODOApprove + */ +contract DODOApproveProxy is InitializableOwnable { + + // ============ Storage ============ + uint256 private constant _TIMELOCK_DURATION_ = 3 days; + mapping (address => bool) public _IS_ALLOWED_PROXY_; + uint256 public _TIMELOCK_; + address public _PENDING_ADD_DODO_PROXY_; + address public immutable _DODO_APPROVE_; + + // ============ Modifiers ============ + modifier notLocked() { + require( + _TIMELOCK_ <= block.timestamp, + "SetProxy is timelocked" + ); + _; + } + + constructor(address dodoApporve) public { + _DODO_APPROVE_ = dodoApporve; + } + + function init(address owner, address[] memory proxies) external { + initOwner(owner); + for(uint i = 0; i < proxies.length; i++) + _IS_ALLOWED_PROXY_[proxies[i]] = true; + } + + function unlockAddProxy(address newDodoProxy) public onlyOwner { + _TIMELOCK_ = block.timestamp + _TIMELOCK_DURATION_; + _PENDING_ADD_DODO_PROXY_ = newDodoProxy; + } + + function lockAddProxy() public onlyOwner { + _PENDING_ADD_DODO_PROXY_ = address(0); + _TIMELOCK_ = 0; + } + + + function addDODOProxy() external onlyOwner notLocked() { + _IS_ALLOWED_PROXY_[_PENDING_ADD_DODO_PROXY_] = true; + lockAddProxy(); + } + + function removeDODOProxy (address oldDodoProxy) public onlyOwner { + _IS_ALLOWED_PROXY_[oldDodoProxy] = false; + } + + function claimTokens( + address token, + address who, + address dest, + uint256 amount + ) external { + require(_IS_ALLOWED_PROXY_[msg.sender], "DODOApproveProxy:Access restricted"); + IDODOApprove(_DODO_APPROVE_).claimTokens( + token, + who, + dest, + amount + ); + } + + function isAllowedProxy(address _proxy) external view returns (bool) { + return _IS_ALLOWED_PROXY_[_proxy]; + } +} diff --git a/contracts/SmartRoute/DODOV1Proxy04.sol b/contracts/SmartRoute/DODOV1Proxy04.sol new file mode 100644 index 0000000..697091b --- /dev/null +++ b/contracts/SmartRoute/DODOV1Proxy04.sol @@ -0,0 +1,283 @@ +/* + + Copyright 2020 DODO ZOO. + SPDX-License-Identifier: Apache-2.0 + +*/ + +pragma solidity 0.6.9; + +import {IERC20} from "../intf/IERC20.sol"; +import {UniversalERC20} from "./lib/UniversalERC20.sol"; +import {SafeMath} from "../lib/SafeMath.sol"; +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 {IDODOApproveProxy} from "./DODOApproveProxy.sol"; +import {IDODOV1Proxy02} from "./intf/IDODOV1Proxy02.sol"; +import {InitializableOwnable} from "../lib/InitializableOwnable.sol"; + +/** + * @title DODOV1Proxy04 + * @author DODO Breeder + * + * @notice Entrance of trading in DODO platform + */ +contract DODOV1Proxy04 is IDODOV1Proxy02, InitializableOwnable { + using SafeMath for uint256; + using UniversalERC20 for IERC20; + + // ============ Storage ============ + + address constant _ETH_ADDRESS_ = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE; + address public immutable _DODO_APPROVE_PROXY_; + address public immutable _DODO_SELL_HELPER_; + address public immutable _WETH_; + address public immutable _CHI_TOKEN_; + uint256 public _GAS_DODO_MAX_RETURN_ = 10; + uint256 public _GAS_EXTERNAL_RETURN_ = 5; + mapping (address => bool) public isWhiteListed; + + // ============ Events ============ + + event OrderHistory( + address indexed fromToken, + address indexed toToken, + address indexed sender, + uint256 fromAmount, + uint256 returnAmount + ); + + // ============ Modifiers ============ + + modifier judgeExpired(uint256 deadLine) { + require(deadLine >= block.timestamp, "DODOV1Proxy04: EXPIRED"); + _; + } + + constructor( + address dodoApproveProxy, + address dodoSellHelper, + address weth, + address chiToken + ) public { + _DODO_APPROVE_PROXY_ = dodoApproveProxy; + _DODO_SELL_HELPER_ = dodoSellHelper; + _WETH_ = weth; + _CHI_TOKEN_ = chiToken; + } + + fallback() external payable {} + + receive() external payable {} + + function updateGasReturn(uint256 newDodoGasReturn, uint256 newExternalGasReturn) public onlyOwner { + _GAS_DODO_MAX_RETURN_ = newDodoGasReturn; + _GAS_EXTERNAL_RETURN_ = newExternalGasReturn; + } + + function addWhiteList (address contractAddr) public onlyOwner { + isWhiteListed[contractAddr] = true; + } + + function removeWhiteList (address contractAddr) public onlyOwner { + isWhiteListed[contractAddr] = false; + } + + function dodoSwapV1( + address fromToken, + address toToken, + uint256 fromTokenAmount, + uint256 minReturnAmount, + address[] memory dodoPairs, + uint256 directions, + uint256 deadLine + ) external override payable judgeExpired(deadLine) returns (uint256 returnAmount) { + require(dodoPairs.length > 0, "DODOV1Proxy04: PAIRS_EMPTY"); + require(minReturnAmount > 0, "DODOV1Proxy04: RETURN_AMOUNT_ZERO"); + require(fromToken != _CHI_TOKEN_, "DODOV1Proxy04: NOT_SUPPORT_SELL_CHI"); + require(toToken != _CHI_TOKEN_, "DODOV1Proxy04: NOT_SUPPORT_BUY_CHI"); + + uint256 originGas = gasleft(); + + if (fromToken != _ETH_ADDRESS_) { + IDODOApproveProxy(_DODO_APPROVE_PROXY_).claimTokens( + fromToken, + msg.sender, + address(this), + fromTokenAmount + ); + } else { + require(msg.value == fromTokenAmount, "DODOV1Proxy04: ETH_AMOUNT_NOT_MATCH"); + IWETH(_WETH_).deposit{value: fromTokenAmount}(); + } + + for (uint256 i = 0; i < dodoPairs.length; i++) { + address curDodoPair = dodoPairs[i]; + if (directions & 1 == 0) { + address curDodoBase = IDODOV1(curDodoPair)._BASE_TOKEN_(); + require(curDodoBase != _CHI_TOKEN_, "DODOV1Proxy04: NOT_SUPPORT_CHI"); + uint256 curAmountIn = IERC20(curDodoBase).balanceOf(address(this)); + IERC20(curDodoBase).universalApproveMax(curDodoPair, curAmountIn); + IDODOV1(curDodoPair).sellBaseToken(curAmountIn, 0, ""); + } else { + address curDodoQuote = IDODOV1(curDodoPair)._QUOTE_TOKEN_(); + require(curDodoQuote != _CHI_TOKEN_, "DODOV1Proxy04: NOT_SUPPORT_CHI"); + uint256 curAmountIn = IERC20(curDodoQuote).balanceOf(address(this)); + IERC20(curDodoQuote).universalApproveMax(curDodoPair, curAmountIn); + uint256 canBuyBaseAmount = IDODOSellHelper(_DODO_SELL_HELPER_).querySellQuoteToken( + curDodoPair, + curAmountIn + ); + IDODOV1(curDodoPair).buyBaseToken(canBuyBaseAmount, curAmountIn, ""); + } + directions = directions >> 1; + } + + if (toToken == _ETH_ADDRESS_) { + returnAmount = IWETH(_WETH_).balanceOf(address(this)); + IWETH(_WETH_).withdraw(returnAmount); + } else { + returnAmount = IERC20(toToken).tokenBalanceOf(address(this)); + } + + require(returnAmount >= minReturnAmount, "DODOV1Proxy04: Return amount is not enough"); + IERC20(toToken).universalTransfer(msg.sender, returnAmount); + + emit OrderHistory(fromToken, toToken, msg.sender, fromTokenAmount, returnAmount); + + uint256 _gasDodoMaxReturn = _GAS_DODO_MAX_RETURN_; + if(_gasDodoMaxReturn > 0) { + uint256 calcGasTokenBurn = originGas.sub(gasleft()) / 65000; + uint256 gasTokenBurn = calcGasTokenBurn > _gasDodoMaxReturn ? _gasDodoMaxReturn : calcGasTokenBurn; + if(gasleft() > 27710 + gasTokenBurn * 6080) + IChi(_CHI_TOKEN_).freeUpTo(gasTokenBurn); + } + } + + function externalSwap( + address fromToken, + address toToken, + address approveTarget, + address swapTarget, + uint256 fromTokenAmount, + uint256 minReturnAmount, + bytes memory callDataConcat, + uint256 deadLine + ) external override payable judgeExpired(deadLine) returns (uint256 returnAmount) { + require(minReturnAmount > 0, "DODOV1Proxy04: RETURN_AMOUNT_ZERO"); + require(fromToken != _CHI_TOKEN_, "DODOV1Proxy04: NOT_SUPPORT_SELL_CHI"); + require(toToken != _CHI_TOKEN_, "DODOV1Proxy04: NOT_SUPPORT_BUY_CHI"); + + address _fromToken = fromToken; + address _toToken = toToken; + + uint256 toTokenOriginBalance = IERC20(_toToken).universalBalanceOf(msg.sender); + + if (_fromToken != _ETH_ADDRESS_) { + IDODOApproveProxy(_DODO_APPROVE_PROXY_).claimTokens( + _fromToken, + msg.sender, + address(this), + fromTokenAmount + ); + IERC20(_fromToken).universalApproveMax(approveTarget, fromTokenAmount); + } + + require(isWhiteListed[swapTarget], "DODOV1Proxy04: Not Whitelist Contract"); + (bool success, ) = swapTarget.call{value: _fromToken == _ETH_ADDRESS_ ? msg.value : 0}(callDataConcat); + + require(success, "DODOV1Proxy04: External Swap execution Failed"); + + IERC20(_toToken).universalTransfer( + msg.sender, + IERC20(_toToken).universalBalanceOf(address(this)) + ); + returnAmount = IERC20(_toToken).universalBalanceOf(msg.sender).sub(toTokenOriginBalance); + require(returnAmount >= minReturnAmount, "DODOV1Proxy04: Return amount is not enough"); + + emit OrderHistory(_fromToken, _toToken, msg.sender, fromTokenAmount, returnAmount); + + uint256 _gasExternalReturn = _GAS_EXTERNAL_RETURN_; + if(_gasExternalReturn > 0) { + if(gasleft() > 27710 + _gasExternalReturn * 6080) + IChi(_CHI_TOKEN_).freeUpTo(_gasExternalReturn); + } + } + + + function mixSwapV1( + address fromToken, + address toToken, + uint256 fromTokenAmount, + uint256 minReturnAmount, + address[] memory mixPairs, + uint256[] memory directions, + address[] memory portionPath, + uint256 deadLine + ) external override payable judgeExpired(deadLine) returns (uint256 returnAmount) { + require(mixPairs.length == directions.length, "DODOV1Proxy04: PARAMS_LENGTH_NOT_MATCH"); + require(mixPairs.length > 0, "DODOV1Proxy04: PAIRS_EMPTY"); + require(minReturnAmount > 0, "DODOV1Proxy04: RETURN_AMOUNT_ZERO"); + require(fromToken != _CHI_TOKEN_, "DODOV1Proxy04: NOT_SUPPORT_SELL_CHI"); + require(toToken != _CHI_TOKEN_, "DODOV1Proxy04: NOT_SUPPORT_BUY_CHI"); + + uint256 toTokenOriginBalance = IERC20(toToken).universalBalanceOf(msg.sender); + + if (fromToken != _ETH_ADDRESS_) { + IDODOApproveProxy(_DODO_APPROVE_PROXY_).claimTokens( + fromToken, + msg.sender, + address(this), + fromTokenAmount + ); + } else { + require(msg.value == fromTokenAmount, "DODOV1Proxy04: ETH_AMOUNT_NOT_MATCH"); + IWETH(_WETH_).deposit{value: fromTokenAmount}(); + } + + for (uint256 i = 0; i < mixPairs.length; i++) { + address curPair = mixPairs[i]; + if (directions[i] == 0) { + address curDodoBase = IDODOV1(curPair)._BASE_TOKEN_(); + require(curDodoBase != _CHI_TOKEN_, "DODOV1Proxy04: NOT_SUPPORT_CHI"); + 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_(); + require(curDodoQuote != _CHI_TOKEN_, "DODOV1Proxy04: NOT_SUPPORT_CHI"); + 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 { + require(portionPath[0] != _CHI_TOKEN_, "DODOV1Proxy04: NOT_SUPPORT_CHI"); + uint256 curAmountIn = IERC20(portionPath[0]).balanceOf(address(this)); + IERC20(portionPath[0]).universalApproveMax(curPair, curAmountIn); + IUni(curPair).swapExactTokensForTokens(curAmountIn,0,portionPath,address(this),deadLine); + } + } + + IERC20(toToken).universalTransfer( + msg.sender, + IERC20(toToken).universalBalanceOf(address(this)) + ); + + returnAmount = IERC20(toToken).universalBalanceOf(msg.sender).sub(toTokenOriginBalance); + require(returnAmount >= minReturnAmount, "DODOV1Proxy04: Return amount is not enough"); + + emit OrderHistory(fromToken, toToken, msg.sender, fromTokenAmount, returnAmount); + + uint256 _gasExternalReturn = _GAS_EXTERNAL_RETURN_; + if(_gasExternalReturn > 0) { + if(gasleft() > 27710 + _gasExternalReturn * 6080) + IChi(_CHI_TOKEN_).freeUpTo(_gasExternalReturn); + } + } +} diff --git a/contracts/SmartRoute/DODOV2Proxy02.sol b/contracts/SmartRoute/DODOV2Proxy02.sol new file mode 100644 index 0000000..c301db4 --- /dev/null +++ b/contracts/SmartRoute/DODOV2Proxy02.sol @@ -0,0 +1,805 @@ +/* + + Copyright 2020 DODO ZOO. + SPDX-License-Identifier: Apache-2.0 + +*/ + +pragma solidity 0.6.9; + +import {IDODOV2Proxy01} from "./intf/IDODOV2Proxy01.sol"; +import {IDODOV2} from "./intf/IDODOV2.sol"; +import {IDODOV1} from "./intf/IDODOV1.sol"; +import {IDODOApproveProxy} from "./DODOApproveProxy.sol"; +import {IDODOSellHelper} from "./helper/DODOSellHelper.sol"; +import {IERC20} from "../intf/IERC20.sol"; +import {IWETH} from "../intf/IWETH.sol"; +import {IUni} from "./intf/IUni.sol"; +import {IChi} from "./intf/IChi.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"; +import {InitializableOwnable} from "../lib/InitializableOwnable.sol"; +import {IDODOIncentive} from "../DODOToken/DODOIncentive.sol"; +import {IDODOAdapter} from "./intf/IDODOAdapter.sol"; + +/** + * @title DODOV2Proxy02 + * @author DODO Breeder + * + * @notice Entrance of trading in DODO platform + */ +contract DODOV2Proxy02 is IDODOV2Proxy01, ReentrancyGuard, InitializableOwnable { + using SafeMath for uint256; + using UniversalERC20 for IERC20; + + // ============ Storage ============ + + address constant _ETH_ADDRESS_ = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE; + address public immutable _WETH_; + address public immutable _DODO_APPROVE_PROXY_; + address public immutable _DODO_SELL_HELPER_; + address public immutable _DVM_FACTORY_; + address public immutable _DPP_FACTORY_; + address public immutable _CP_FACTORY_; + address public immutable _DODO_INCENTIVE_; + address public immutable _CHI_TOKEN_; + uint256 public _GAS_DODO_MAX_RETURN_ = 0; + uint256 public _GAS_EXTERNAL_RETURN_ = 0; + mapping (address => bool) public isWhiteListed; + + // ============ Events ============ + + event OrderHistory( + address fromToken, + address toToken, + address sender, + uint256 fromAmount, + uint256 returnAmount + ); + + // ============ Modifiers ============ + + modifier judgeExpired(uint256 deadLine) { + require(deadLine >= block.timestamp, "DODOV2Proxy02: EXPIRED"); + _; + } + + fallback() external payable {} + + receive() external payable {} + + constructor( + address dvmFactory, + address dppFactory, + address cpFactory, + address payable weth, + address dodoApproveProxy, + address dodoSellHelper, + address chiToken, + address dodoIncentive + ) public { + _DVM_FACTORY_ = dvmFactory; + _DPP_FACTORY_ = dppFactory; + _CP_FACTORY_ = cpFactory; + _WETH_ = weth; + _DODO_APPROVE_PROXY_ = dodoApproveProxy; + _DODO_SELL_HELPER_ = dodoSellHelper; + _CHI_TOKEN_ = chiToken; + _DODO_INCENTIVE_ = dodoIncentive; + } + + function addWhiteList (address contractAddr) public onlyOwner { + isWhiteListed[contractAddr] = true; + } + + function removeWhiteList (address contractAddr) public onlyOwner { + isWhiteListed[contractAddr] = false; + } + + function updateGasReturn(uint256 newDodoGasReturn, uint256 newExternalGasReturn) public onlyOwner { + _GAS_DODO_MAX_RETURN_ = newDodoGasReturn; + _GAS_EXTERNAL_RETURN_ = newExternalGasReturn; + } + + // ============ DVM Functions (create & add liquidity) ============ + + function createDODOVendingMachine( + address baseToken, + address quoteToken, + uint256 baseInAmount, + uint256 quoteInAmount, + uint256 lpFeeRate, + uint256 i, + uint256 k, + bool isOpenTWAP, + uint256 deadLine + ) + external + override + payable + preventReentrant + judgeExpired(deadLine) + returns (address newVendingMachine, uint256 shares) + { + { + address _baseToken = baseToken == _ETH_ADDRESS_ ? _WETH_ : baseToken; + address _quoteToken = quoteToken == _ETH_ADDRESS_ ? _WETH_ : quoteToken; + newVendingMachine = IDODOV2(_DVM_FACTORY_).createDODOVendingMachine( + _baseToken, + _quoteToken, + lpFeeRate, + i, + k, + isOpenTWAP + ); + } + + { + address _baseToken = baseToken; + address _quoteToken = quoteToken; + _deposit( + msg.sender, + newVendingMachine, + _baseToken, + baseInAmount, + _baseToken == _ETH_ADDRESS_ + ); + _deposit( + msg.sender, + newVendingMachine, + _quoteToken, + quoteInAmount, + _quoteToken == _ETH_ADDRESS_ + ); + } + + (shares, , ) = IDODOV2(newVendingMachine).buyShares(msg.sender); + } + + function addDVMLiquidity( + address dvmAddress, + uint256 baseInAmount, + uint256 quoteInAmount, + uint256 baseMinAmount, + uint256 quoteMinAmount, + uint8 flag, // 0 - ERC20, 1 - baseInETH, 2 - quoteInETH + uint256 deadLine + ) + external + override + payable + preventReentrant + judgeExpired(deadLine) + returns ( + uint256 shares, + uint256 baseAdjustedInAmount, + uint256 quoteAdjustedInAmount + ) + { + address _dvm = dvmAddress; + (baseAdjustedInAmount, quoteAdjustedInAmount) = _addDVMLiquidity( + _dvm, + baseInAmount, + quoteInAmount + ); + require( + baseAdjustedInAmount >= baseMinAmount && quoteAdjustedInAmount >= quoteMinAmount, + "DODOV2Proxy02: deposit amount is not enough" + ); + + _deposit(msg.sender, _dvm, IDODOV2(_dvm)._BASE_TOKEN_(), baseAdjustedInAmount, flag == 1); + _deposit(msg.sender, _dvm, IDODOV2(_dvm)._QUOTE_TOKEN_(), quoteAdjustedInAmount, flag == 2); + + (shares, , ) = IDODOV2(_dvm).buyShares(msg.sender); + // refund dust eth + if (flag == 1 && msg.value > baseAdjustedInAmount) msg.sender.transfer(msg.value - baseAdjustedInAmount); + if (flag == 2 && msg.value > quoteAdjustedInAmount) msg.sender.transfer(msg.value - quoteAdjustedInAmount); + } + + function _addDVMLiquidity( + address dvmAddress, + uint256 baseInAmount, + uint256 quoteInAmount + ) internal view returns (uint256 baseAdjustedInAmount, uint256 quoteAdjustedInAmount) { + (uint256 baseReserve, uint256 quoteReserve) = IDODOV2(dvmAddress).getVaultReserve(); + if (quoteReserve == 0 && baseReserve == 0) { + baseAdjustedInAmount = baseInAmount; + quoteAdjustedInAmount = quoteInAmount; + } + if (quoteReserve == 0 && baseReserve > 0) { + baseAdjustedInAmount = baseInAmount; + quoteAdjustedInAmount = 0; + } + if (quoteReserve > 0 && baseReserve > 0) { + uint256 baseIncreaseRatio = DecimalMath.divFloor(baseInAmount, baseReserve); + uint256 quoteIncreaseRatio = DecimalMath.divFloor(quoteInAmount, quoteReserve); + if (baseIncreaseRatio <= quoteIncreaseRatio) { + baseAdjustedInAmount = baseInAmount; + quoteAdjustedInAmount = DecimalMath.mulFloor(quoteReserve, baseIncreaseRatio); + } else { + quoteAdjustedInAmount = quoteInAmount; + baseAdjustedInAmount = DecimalMath.mulFloor(baseReserve, quoteIncreaseRatio); + } + } + } + + // ============ DPP Functions (create & reset) ============ + + function createDODOPrivatePool( + address baseToken, + address quoteToken, + uint256 baseInAmount, + uint256 quoteInAmount, + uint256 lpFeeRate, + uint256 i, + uint256 k, + bool isOpenTwap, + uint256 deadLine + ) + external + override + payable + preventReentrant + judgeExpired(deadLine) + returns (address newPrivatePool) + { + newPrivatePool = IDODOV2(_DPP_FACTORY_).createDODOPrivatePool(); + + address _baseToken = baseToken; + address _quoteToken = quoteToken; + _deposit(msg.sender, newPrivatePool, _baseToken, baseInAmount, _baseToken == _ETH_ADDRESS_); + _deposit( + msg.sender, + newPrivatePool, + _quoteToken, + quoteInAmount, + _quoteToken == _ETH_ADDRESS_ + ); + + if (_baseToken == _ETH_ADDRESS_) _baseToken = _WETH_; + if (_quoteToken == _ETH_ADDRESS_) _quoteToken = _WETH_; + + IDODOV2(_DPP_FACTORY_).initDODOPrivatePool( + newPrivatePool, + msg.sender, + _baseToken, + _quoteToken, + lpFeeRate, + k, + i, + isOpenTwap + ); + } + + function resetDODOPrivatePool( + address dppAddress, + uint256[] memory paramList, //0 - newLpFeeRate, 1 - newI, 2 - newK + uint256[] memory amountList, //0 - baseInAmount, 1 - quoteInAmount, 2 - baseOutAmount, 3- quoteOutAmount + uint8 flag, // 0 - ERC20, 1 - baseInETH, 2 - quoteInETH, 3 - baseOutETH, 4 - quoteOutETH + uint256 minBaseReserve, + uint256 minQuoteReserve, + uint256 deadLine + ) external override payable preventReentrant judgeExpired(deadLine) { + _deposit( + msg.sender, + dppAddress, + IDODOV2(dppAddress)._BASE_TOKEN_(), + amountList[0], + flag == 1 + ); + _deposit( + msg.sender, + dppAddress, + IDODOV2(dppAddress)._QUOTE_TOKEN_(), + amountList[1], + flag == 2 + ); + + require(IDODOV2(IDODOV2(dppAddress)._OWNER_()).reset( + msg.sender, + paramList[0], + paramList[1], + paramList[2], + amountList[2], + amountList[3], + minBaseReserve, + minQuoteReserve + ), "Reset Failed"); + + _withdraw(msg.sender, IDODOV2(dppAddress)._BASE_TOKEN_(), amountList[2], flag == 3); + _withdraw(msg.sender, IDODOV2(dppAddress)._QUOTE_TOKEN_(), amountList[3], flag == 4); + } + + // ============ Swap ============ + + function dodoSwapV2ETHToToken( + address toToken, + uint256 minReturnAmount, + address[] memory dodoPairs, + uint256 directions, + bool isIncentive, + uint256 deadLine + ) + external + override + payable + judgeExpired(deadLine) + returns (uint256 returnAmount) + { + require(dodoPairs.length > 0, "DODOV2Proxy02: PAIRS_EMPTY"); + require(minReturnAmount > 0, "DODOV2Proxy02: RETURN_AMOUNT_ZERO"); + uint256 originGas = gasleft(); + + uint256 originToTokenBalance = IERC20(toToken).balanceOf(msg.sender); + IWETH(_WETH_).deposit{value: msg.value}(); + IWETH(_WETH_).transfer(dodoPairs[0], msg.value); + + for (uint256 i = 0; i < dodoPairs.length; i++) { + if (i == dodoPairs.length - 1) { + if (directions & 1 == 0) { + IDODOV2(dodoPairs[i]).sellBase(msg.sender); + } else { + IDODOV2(dodoPairs[i]).sellQuote(msg.sender); + } + } else { + if (directions & 1 == 0) { + IDODOV2(dodoPairs[i]).sellBase(dodoPairs[i + 1]); + } else { + IDODOV2(dodoPairs[i]).sellQuote(dodoPairs[i + 1]); + } + } + directions = directions >> 1; + } + + returnAmount = IERC20(toToken).balanceOf(msg.sender).sub(originToTokenBalance); + require(returnAmount >= minReturnAmount, "DODOV2Proxy02: Return amount is not enough"); + + _dodoGasReturn(originGas); + + _execIncentive(isIncentive, _ETH_ADDRESS_, toToken); + + emit OrderHistory( + _ETH_ADDRESS_, + toToken, + msg.sender, + msg.value, + returnAmount + ); + } + + function dodoSwapV2TokenToETH( + address fromToken, + uint256 fromTokenAmount, + uint256 minReturnAmount, + address[] memory dodoPairs, + uint256 directions, + bool isIncentive, + uint256 deadLine + ) + external + override + judgeExpired(deadLine) + returns (uint256 returnAmount) + { + require(dodoPairs.length > 0, "DODOV2Proxy02: PAIRS_EMPTY"); + require(minReturnAmount > 0, "DODOV2Proxy02: RETURN_AMOUNT_ZERO"); + uint256 originGas = gasleft(); + + IDODOApproveProxy(_DODO_APPROVE_PROXY_).claimTokens(fromToken, msg.sender, dodoPairs[0], fromTokenAmount); + + for (uint256 i = 0; i < dodoPairs.length; i++) { + if (i == dodoPairs.length - 1) { + if (directions & 1 == 0) { + IDODOV2(dodoPairs[i]).sellBase(address(this)); + } else { + IDODOV2(dodoPairs[i]).sellQuote(address(this)); + } + } else { + if (directions & 1 == 0) { + IDODOV2(dodoPairs[i]).sellBase(dodoPairs[i + 1]); + } else { + IDODOV2(dodoPairs[i]).sellQuote(dodoPairs[i + 1]); + } + } + directions = directions >> 1; + } + returnAmount = IWETH(_WETH_).balanceOf(address(this)); + require(returnAmount >= minReturnAmount, "DODOV2Proxy02: Return amount is not enough"); + IWETH(_WETH_).withdraw(returnAmount); + msg.sender.transfer(returnAmount); + + _dodoGasReturn(originGas); + + _execIncentive(isIncentive, fromToken, _ETH_ADDRESS_); + + emit OrderHistory( + fromToken, + _ETH_ADDRESS_, + msg.sender, + fromTokenAmount, + returnAmount + ); + } + + function dodoSwapV2TokenToToken( + address fromToken, + address toToken, + uint256 fromTokenAmount, + uint256 minReturnAmount, + address[] memory dodoPairs, + uint256 directions, + bool isIncentive, + uint256 deadLine + ) + external + override + judgeExpired(deadLine) + returns (uint256 returnAmount) + { + require(dodoPairs.length > 0, "DODOV2Proxy02: PAIRS_EMPTY"); + require(minReturnAmount > 0, "DODOV2Proxy02: RETURN_AMOUNT_ZERO"); + uint256 originGas = gasleft(); + + uint256 originToTokenBalance = IERC20(toToken).balanceOf(msg.sender); + IDODOApproveProxy(_DODO_APPROVE_PROXY_).claimTokens(fromToken, msg.sender, dodoPairs[0], fromTokenAmount); + + for (uint256 i = 0; i < dodoPairs.length; i++) { + if (i == dodoPairs.length - 1) { + if (directions & 1 == 0) { + IDODOV2(dodoPairs[i]).sellBase(msg.sender); + } else { + IDODOV2(dodoPairs[i]).sellQuote(msg.sender); + } + } else { + if (directions& 1 == 0) { + IDODOV2(dodoPairs[i]).sellBase(dodoPairs[i + 1]); + } else { + IDODOV2(dodoPairs[i]).sellQuote(dodoPairs[i + 1]); + } + } + directions = directions >> 1; + } + returnAmount = IERC20(toToken).balanceOf(msg.sender).sub(originToTokenBalance); + require(returnAmount >= minReturnAmount, "DODOV2Proxy02: Return amount is not enough"); + + _dodoGasReturn(originGas); + + _execIncentive(isIncentive, fromToken, toToken); + + emit OrderHistory( + fromToken, + toToken, + msg.sender, + fromTokenAmount, + returnAmount + ); + } + + function externalSwap( + address fromToken, + address toToken, + address approveTarget, + address swapTarget, + uint256 fromTokenAmount, + uint256 minReturnAmount, + bytes memory callDataConcat, + bool isIncentive, + uint256 deadLine + ) + external + override + payable + judgeExpired(deadLine) + returns (uint256 returnAmount) + { + require(minReturnAmount > 0, "DODOV2Proxy02: RETURN_AMOUNT_ZERO"); + require(fromToken != _CHI_TOKEN_, "DODOV2Proxy02: NOT_SUPPORT_SELL_CHI"); + require(toToken != _CHI_TOKEN_, "DODOV2Proxy02: NOT_SUPPORT_BUY_CHI"); + + uint256 toTokenOriginBalance = IERC20(toToken).universalBalanceOf(msg.sender); + if (fromToken != _ETH_ADDRESS_) { + IDODOApproveProxy(_DODO_APPROVE_PROXY_).claimTokens( + fromToken, + msg.sender, + address(this), + fromTokenAmount + ); + IERC20(fromToken).universalApproveMax(approveTarget, fromTokenAmount); + } + + require(isWhiteListed[swapTarget], "DODOV2Proxy02: Not Whitelist Contract"); + (bool success, ) = swapTarget.call{value: fromToken == _ETH_ADDRESS_ ? msg.value : 0}(callDataConcat); + + require(success, "DODOV2Proxy02: External Swap execution Failed"); + + IERC20(toToken).universalTransfer( + msg.sender, + IERC20(toToken).universalBalanceOf(address(this)) + ); + + returnAmount = IERC20(toToken).universalBalanceOf(msg.sender).sub(toTokenOriginBalance); + require(returnAmount >= minReturnAmount, "DODOV2Proxy02: Return amount is not enough"); + + _externalGasReturn(); + + _execIncentive(isIncentive, fromToken, toToken); + + emit OrderHistory( + fromToken, + toToken, + msg.sender, + fromTokenAmount, + returnAmount + ); + } + + function dodoSwapV1( + address fromToken, + address toToken, + uint256 fromTokenAmount, + uint256 minReturnAmount, + address[] memory dodoPairs, + uint256 directions, + bool isIncentive, + uint256 deadLine + ) + external + override + payable + judgeExpired(deadLine) + returns (uint256 returnAmount) + { + require(dodoPairs.length > 0, "DODOV2Proxy02: PAIRS_EMPTY"); + require(minReturnAmount > 0, "DODOV2Proxy02: RETURN_AMOUNT_ZERO"); + require(fromToken != _CHI_TOKEN_, "DODOV2Proxy02: NOT_SUPPORT_SELL_CHI"); + require(toToken != _CHI_TOKEN_, "DODOV2Proxy02: NOT_SUPPORT_BUY_CHI"); + + uint256 originGas = gasleft(); + + address _fromToken = fromToken; + address _toToken = toToken; + + _deposit(msg.sender, address(this), _fromToken, fromTokenAmount, _fromToken == _ETH_ADDRESS_); + + for (uint256 i = 0; i < dodoPairs.length; i++) { + address curDodoPair = dodoPairs[i]; + if (directions & 1 == 0) { + address curDodoBase = IDODOV1(curDodoPair)._BASE_TOKEN_(); + require(curDodoBase != _CHI_TOKEN_, "DODOV2Proxy02: NOT_SUPPORT_CHI"); + uint256 curAmountIn = IERC20(curDodoBase).balanceOf(address(this)); + IERC20(curDodoBase).universalApproveMax(curDodoPair, curAmountIn); + IDODOV1(curDodoPair).sellBaseToken(curAmountIn, 0, ""); + } else { + address curDodoQuote = IDODOV1(curDodoPair)._QUOTE_TOKEN_(); + require(curDodoQuote != _CHI_TOKEN_, "DODOV2Proxy02: NOT_SUPPORT_CHI"); + uint256 curAmountIn = IERC20(curDodoQuote).balanceOf(address(this)); + IERC20(curDodoQuote).universalApproveMax(curDodoPair, curAmountIn); + uint256 canBuyBaseAmount = IDODOSellHelper(_DODO_SELL_HELPER_).querySellQuoteToken( + curDodoPair, + curAmountIn + ); + IDODOV1(curDodoPair).buyBaseToken(canBuyBaseAmount, curAmountIn, ""); + } + directions = directions >> 1; + } + + + if (_toToken == _ETH_ADDRESS_) { + returnAmount = IWETH(_WETH_).balanceOf(address(this)); + IWETH(_WETH_).withdraw(returnAmount); + } else { + returnAmount = IERC20(_toToken).tokenBalanceOf(address(this)); + } + + require(returnAmount >= minReturnAmount, "DODOV2Proxy02: Return amount is not enough"); + IERC20(_toToken).universalTransfer(msg.sender, returnAmount); + + _dodoGasReturn(originGas); + + _execIncentive(isIncentive, _fromToken, _toToken); + + emit OrderHistory(_fromToken, _toToken, msg.sender, fromTokenAmount, returnAmount); + } + + + 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 override 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; + + require(_fromToken != _CHI_TOKEN_, "DODOV2Proxy02: NOT_SUPPORT_SELL_CHI"); + require(_toToken != _CHI_TOKEN_, "DODOV2Proxy02: NOT_SUPPORT_BUY_CHI"); + + uint256 originGas = gasleft(); + 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"); + + _dodoGasReturn(originGas); + + _execIncentive(isIncentive, _fromToken, _toToken); + + emit OrderHistory( + _fromToken, + _toToken, + msg.sender, + _fromTokenAmount, + returnAmount + ); + } + + //============ CrowdPooling Functions (create & bid) ============ + + function createCrowdPooling( + address baseToken, + address quoteToken, + uint256 baseInAmount, + uint256[] memory timeLine, + uint256[] memory valueList, + bool isOpenTWAP, + uint256 deadLine + ) external override payable preventReentrant judgeExpired(deadLine) returns (address payable newCrowdPooling) { + address _baseToken = baseToken; + address _quoteToken = quoteToken == _ETH_ADDRESS_ ? _WETH_ : quoteToken; + + newCrowdPooling = IDODOV2(_CP_FACTORY_).createCrowdPooling(); + + _deposit( + msg.sender, + newCrowdPooling, + _baseToken, + baseInAmount, + false + ); + + newCrowdPooling.transfer(msg.value); + + IDODOV2(_CP_FACTORY_).initCrowdPooling( + newCrowdPooling, + msg.sender, + _baseToken, + _quoteToken, + timeLine, + valueList, + isOpenTWAP + ); + } + + function bid( + address cpAddress, + uint256 quoteAmount, + uint8 flag, // 0 - ERC20, 1 - quoteInETH + uint256 deadLine + ) external override payable preventReentrant judgeExpired(deadLine) { + _deposit(msg.sender, cpAddress, IDODOV2(cpAddress)._QUOTE_TOKEN_(), quoteAmount, flag == 1); + IDODOV2(cpAddress).bid(msg.sender); + } + + + function addLiquidityToV1( + address pair, + uint256 baseAmount, + uint256 quoteAmount, + uint256 baseMinShares, + uint256 quoteMinShares, + uint8 flag, // 0 erc20 In 1 baseInETH 2 quoteIn ETH + uint256 deadLine + ) external override payable preventReentrant judgeExpired(deadLine) returns(uint256 baseShares, uint256 quoteShares) { + address _baseToken = IDODOV1(pair)._BASE_TOKEN_(); + address _quoteToken = IDODOV1(pair)._QUOTE_TOKEN_(); + + _deposit(msg.sender, address(this), _baseToken, baseAmount, flag == 1); + _deposit(msg.sender, address(this), _quoteToken, quoteAmount, flag == 2); + + + if(baseAmount > 0) { + IERC20(_baseToken).universalApproveMax(pair, baseAmount); + baseShares = IDODOV1(pair).depositBaseTo(msg.sender, baseAmount); + } + if(quoteAmount > 0) { + IERC20(_quoteToken).universalApproveMax(pair, quoteAmount); + quoteShares = IDODOV1(pair).depositQuoteTo(msg.sender, quoteAmount); + } + + require(baseShares >= baseMinShares && quoteShares >= quoteMinShares,"DODOV2Proxy02: Return DLP is not enough"); + } + + + function _deposit( + address from, + address to, + address token, + uint256 amount, + bool isETH + ) internal { + if (isETH) { + if (amount > 0) { + IWETH(_WETH_).deposit{value: amount}(); + if (to != address(this)) SafeERC20.safeTransfer(IERC20(_WETH_), to, amount); + } + } else { + IDODOApproveProxy(_DODO_APPROVE_PROXY_).claimTokens(token, from, to, amount); + } + } + + function _withdraw( + address payable to, + address token, + uint256 amount, + bool isETH + ) internal { + if (isETH) { + if (amount > 0) { + IWETH(_WETH_).withdraw(amount); + to.transfer(amount); + } + } else { + if (amount > 0) { + SafeERC20.safeTransfer(IERC20(token), to, amount); + } + } + } + + function _dodoGasReturn(uint256 originGas) internal { + uint256 _gasDodoMaxReturn = _GAS_DODO_MAX_RETURN_; + if(_gasDodoMaxReturn > 0) { + uint256 calcGasTokenBurn = originGas.sub(gasleft()) / 65000; + uint256 gasTokenBurn = calcGasTokenBurn > _gasDodoMaxReturn ? _gasDodoMaxReturn : calcGasTokenBurn; + if(gasTokenBurn >= 3 && gasleft() > 27710 + gasTokenBurn * 6080) + IChi(_CHI_TOKEN_).freeUpTo(gasTokenBurn); + } + } + + function _externalGasReturn() internal { + uint256 _gasExternalReturn = _GAS_EXTERNAL_RETURN_; + if(_gasExternalReturn > 0) { + if(gasleft() > 27710 + _gasExternalReturn * 6080) + IChi(_CHI_TOKEN_).freeUpTo(_gasExternalReturn); + } + } + + function _execIncentive(bool isIncentive, address fromToken,address toToken) internal { + if(isIncentive && gasleft() > 30000) { + IDODOIncentive(_DODO_INCENTIVE_).triggerIncentive(fromToken, toToken, msg.sender); + } + } + +} diff --git a/contracts/SmartRoute/adapter/DODOV1Adapter.sol b/contracts/SmartRoute/adapter/DODOV1Adapter.sol index 747571a..b8a07bd 100644 --- a/contracts/SmartRoute/adapter/DODOV1Adapter.sol +++ b/contracts/SmartRoute/adapter/DODOV1Adapter.sol @@ -9,6 +9,7 @@ pragma solidity 0.6.9; import {IERC20} from "../../intf/IERC20.sol"; import {IDODOV1} from "../intf/IDODOV1.sol"; +import {SafeERC20} from "../../lib/SafeERC20.sol"; import {IDODOSellHelper} from "../helper/DODOSellHelper.sol"; import {UniversalERC20} from "../lib/UniversalERC20.sol"; import {SafeMath} from "../../lib/SafeMath.sol"; @@ -26,18 +27,18 @@ contract DODOV1Adapter is IDODOAdapter { function sellBase(address to, address pool) external override { address curBase = IDODOV1(pool)._BASE_TOKEN_(); - uint256 curAmountIn = IERC20(curBase).balanceOf(address(this)); + uint256 curAmountIn = IERC20(curBase).tokenBalanceOf(address(this)); IERC20(curBase).universalApproveMax(pool, curAmountIn); IDODOV1(pool).sellBaseToken(curAmountIn, 0, ""); if(to != address(this)) { address curQuote = IDODOV1(pool)._QUOTE_TOKEN_(); - IERC20(curQuote).transfer(to,IERC20(curQuote).balanceOf(address(this))); + SafeERC20.safeTransfer(IERC20(curQuote), to, IERC20(curQuote).tokenBalanceOf(address(this))); } } function sellQuote(address to, address pool) external override { address curQuote = IDODOV1(pool)._QUOTE_TOKEN_(); - uint256 curAmountIn = IERC20(curQuote).balanceOf(address(this)); + uint256 curAmountIn = IERC20(curQuote).tokenBalanceOf(address(this)); IERC20(curQuote).universalApproveMax(pool, curAmountIn); uint256 canBuyBaseAmount = IDODOSellHelper(_DODO_SELL_HELPER_).querySellQuoteToken( pool, @@ -46,7 +47,7 @@ contract DODOV1Adapter is IDODOAdapter { IDODOV1(pool).buyBaseToken(canBuyBaseAmount, curAmountIn, ""); if(to != address(this)) { address curBase = IDODOV1(pool)._BASE_TOKEN_(); - IERC20(curBase).transfer(to,IERC20(curBase).balanceOf(address(this))); + SafeERC20.safeTransfer(IERC20(curBase), to, canBuyBaseAmount); } } } \ No newline at end of file diff --git a/deploy-detail-v1.5.txt b/deploy-detail-v1.5.txt index 9d412e0..10ef18c 100644 --- a/deploy-detail-v1.5.txt +++ b/deploy-detail-v1.5.txt @@ -100,3 +100,15 @@ Deploy time: 2021/1/20 上午10:58:55 Deploy type: Proxy DODOV1Proxy03 Address: 0x9A9942458754bDf65dCbCd0B6B4B842a7D4031AB Set DODOProxy Owner tx: 0x2fd5f1abb016536e4557d609bdf52e2b790cbac85dead5097128e77b4357252d +==================================================== +network type: bsclive +Deploy time: 2021/1/26 下午5:28:55 +Deploy type: Proxy +DODOV1Proxy04 Address: 0xbe9a66e49503e84ae59a4d0545365AABedf33b40 +Set DODOProxy Owner tx: 0xe5dd7a963446bb6a826c89a0c987baf0db463a649f3949fce6ef39b4d9649808 +==================================================== +network type: live +Deploy time: 2021/1/26 下午5:41:41 +Deploy type: Proxy +DODOV1Proxy04 Address: 0xa2CB66EBB947D217f61510882096F6e95c1DE97D +Set DODOProxy Owner tx: 0xe49234c67bc710a7f4797aacbb2ef26fac458832f101e856d8113cc21721cd81 diff --git a/deploy-detail-v2.0.txt b/deploy-detail-v2.0.txt index baff773..83b513d 100644 --- a/deploy-detail-v2.0.txt +++ b/deploy-detail-v2.0.txt @@ -393,15 +393,6 @@ Deploy time: 2021/1/22 下午12:12:05 Deploy type: V2 - Callee DODOCalleeHelperAddress: 0x8085e9a80edb737a08c158bd018683c7Ad3c082B ==================================================== -network type: bsclive -Deploy time: 2021/1/22 下午1:51:45 -==================================================== -network type: bsclive -Deploy time: 2021/1/22 下午1:54:22 -==================================================== -network type: bsclive -Deploy time: 2021/1/22 下午1:57:54 -==================================================== network type: kovan Deploy time: 2021/1/22 下午3:53:35 Deploy type: V2 @@ -436,7 +427,7 @@ DefaultMtFeeRateAddress: 0x18DFdE99F578A0735410797e949E8D3e2AFCB9D2 DefaultPermissionAddress: 0x729f7f44bf64Ce814716b6261e267DbE6cdf021c Init DefaultPermissionAddress Tx: 0x2fb909748e2afcc040becccae128256d264cd56f713329b49742255b9e478a2c DvmTemplateAddress: 0xC3BeD579CaB3EC29B22D9AB99F4E586af42496b9 -DppTemplateAddress: 0x550B2e7bD9605b8dcdd20d01bA73f1feB6ce289b +DppTemplateAddress: 0x85351262f7474Ebe23FfAcD633cf20A491F1325D DppAdminTemplateAddress: 0x989DcAA95801C527C5B73AA65d3962dF9aCe1b0C CpTemplateAddress: 0x041ABa00c57Dd47abC37A2931dF569a2A2cc57Be DODOApprove Address: 0x72d220cE168C4f361dD4deE5D826a01AD8598f6C @@ -462,7 +453,7 @@ DefaultMtFeeRateAddress: 0x5e84190a270333aCe5B9202a3F4ceBf11b81bB01 DefaultPermissionAddress: 0x6B208E08dcF6BD51F50C5Da09d15B2D8E5C46Cf2 Init DefaultPermissionAddress Tx: 0x235d8c2a5eea61edc73d4e7de1f13f7a4d0479935e4a72c7d400d1844a141071 DvmTemplateAddress: 0x2BBD66fC4898242BDBD2583BBe1d76E8b8f71445 -DppTemplateAddress: 0x18DFdE99F578A0735410797e949E8D3e2AFCB9D2 +DppTemplateAddress: 0xB76de21f04F677f07D9881174a1D8E624276314C DppAdminTemplateAddress: 0x729f7f44bf64Ce814716b6261e267DbE6cdf021c CpTemplateAddress: 0x18b0bD918b55f995Fd404B872404378A62cb403b DODOApprove Address: 0xC3BeD579CaB3EC29B22D9AB99F4E586af42496b9 @@ -485,3 +476,69 @@ Deploy type: V2 - Adapter DODOV1Adapter Address: 0xb57Dd5c265dBb13CA014F2332069E90CD0e22e65 DODOV2Adapter Address: 0xE55154D09265b18aC7CDAC6E646672A5460389a1 UniAdapter Address: 0x043957f7554275b90c5178872faE851dcfC1089D +==================================================== +network type: live +Deploy time: 2021/1/24 下午5:23:15 +Deploy type: V2 - ERC20 Factory +ERC20TemplateAddress: 0x85351262f7474Ebe23FfAcD633cf20A491F1325D +MintableERC20TemplateAddress: 0x0596908263Ef2724fBfBcAfA1c983FCD7a629038 +ERC20FactoryAddress: 0x44D5dF24d5Ef52A791D6436Fa45A8D426f6de34e +==================================================== +network type: live +Deploy time: 2021/1/25 下午7:40:34 +Deploy type: V2 - Adapter +DODOV1Adapter Address: 0x9B64c81ba54eA51e1f6B7fefb3cfF8AA6F1e2A09 +==================================================== +network type: bsclive +Deploy time: 2021/1/25 下午7:51:54 +Deploy type: V2 - Adapter +DODOV1Adapter Address: 0x0596908263Ef2724fBfBcAfA1c983FCD7a629038 +==================================================== +network type: kovan +Deploy time: 2021/1/25 下午7:54:22 +Deploy type: V2 - Adapter +DODOV1Adapter Address: 0xfbA45094b82AAdA3297712073Ee0920b4090cd7c +==================================================== +network type: kovan +Deploy time: 2021/1/26 上午11:02:21 +Deploy type: V2 +DppAdminTemplateAddress: 0x10AAaeE8B802FaEBEC5dE37dc581490d86Fb07A5 +DODOApprove Address: 0x8acF28D9d8124B20b645893b6102950B488dfd29 +DODOApproveProxy Address: 0x7Dac4ec78D4349FBD9E031a56E92B724B8AFA9B3 +DppFactoryAddress: 0x6DAb26dFE83E484DCC5126F812E3e6AA8e7eEf4D +Init DppFactory Tx: 0x019975d4e881fc929ab8c7f4ecfcec4f54785df20f369848c34ad07462a3fe27 +DODOV2RouteHelper Address: 0xE2dbE9CF7bEb0484F464281D2DcbF6bF98D865Fd +DODOV2Proxy02 Address: 0x3457A15B9ab57FC754789EE83E4BD2BD8f4F50C8 +Init DODOProxyV2 Tx: 0xd888ac726780d59c0902a3d2e0b1d057d740b6d0113a9b574b6e602aaae9c36c +DODOApproveProxy Init tx: 0x269cca5af1c412592439ddce1ff4d4963c5f361251a0e24437f6478a05da9cd9 +DODOApprove Init tx: 0x8883928f79a11fdf1c96a07d2a6c3c8034e1bcf5cfea87342fb5084cc22eb406 +DODOIncentive ChangeProxy tx: 0x1b01057283954629021d23586ba04278c64ada46c899f62b1f53364546d0fa88 +DODOIncentive OpenSwitch tx: 0x336c69f91d6f0b547e432498d3848f8308fe3164925444aca98951876e68a89c +==================================================== +network type: bsclive +Deploy time: 2021/1/26 下午4:25:33 +Deploy type: V2 +DppAdminTemplateAddress: 0x44D5dF24d5Ef52A791D6436Fa45A8D426f6de34e +DODOApproveProxy Address: 0xB76de21f04F677f07D9881174a1D8E624276314C +DppFactoryAddress: 0x9B64c81ba54eA51e1f6B7fefb3cfF8AA6F1e2A09 +Init DppFactory Tx: 0xf2037cb6bbf6b6fccf524e21af55e76f54edf8ae08e5c99e9310afa9192d75e1 +DODOV2RouteHelper Address: 0x335aC99bb3E51BDbF22025f092Ebc1Cf2c5cC619 +DODOV2Proxy02 Address: 0x6B4Fa0bc61Eddc928e0Df9c7f01e407BfcD3e5EF +Init DODOProxyV2 Tx: 0xb30622bdf50144d11d25b0c7c267270f6c6ef6a6eb89efee97f2d31f6e7986e6 +==================================================== +network type: live +Deploy time: 2021/1/26 下午5:07:20 +Deploy type: V2 +DppAdminTemplateAddress: 0x5515363c0412AdD5c72d3E302fE1bD7dCBCF93Fe +DODOApproveProxy Address: 0x335aC99bb3E51BDbF22025f092Ebc1Cf2c5cC619 +DppFactoryAddress: 0x6B4Fa0bc61Eddc928e0Df9c7f01e407BfcD3e5EF +Init DppFactory Tx: 0x3f0ada4251c74ba5f793c1d653a9be7818674daac19291619ce7b5defd232240 +DODOV2RouteHelper Address: 0xbe9a66e49503e84ae59a4d0545365AABedf33b40 +DODOV2Proxy02 Address: 0xa356867fDCEa8e71AEaF87805808803806231FdC +Init DODOProxyV2 Tx: 0xf8e511f50c2f27836ace72e65d8a10e6253f5d5094a9e1f2e5fa5181d3c05f08 +==================================================== +network type: bsclive +Deploy time: 2021/1/26 下午5:29:51 +==================================================== +network type: live +Deploy time: 2021/1/26 下午5:42:23 diff --git a/kovan-mock-v2.0.txt b/kovan-mock-v2.0.txt index 56847a1..20adee7 100644 --- a/kovan-mock-v2.0.txt +++ b/kovan-mock-v2.0.txt @@ -430,3 +430,15 @@ Create DPP: 0xd8C30a4E866B188F16aD266dC3333BD47F34ebaE-0x43688f367eb83697c3ca5d0 Create DPP: 0xd8C30a4E866B188F16aD266dC3333BD47F34ebaE-0x156595bAF85D5C29E91d959889B022d952190A64 Pool:0x67841b1553Ed349111659E56897Cd8480DA88f8c Tx: 0x165e682bdc696a6af5821944718508dfd7fc953f1e21e213a741d52ced53ab03 Create DPP: 0xd7f02D1b4F9495B549787808503Ecfd231C3fbDA-0x43688f367eb83697c3ca5d03c5055b6bd6f6ac4b Pool:0x3e8DB146423f2Df1Bb3f07C9D7Cf3e76D2C74446 Tx: 0x090746636f90cda0f12435e8cb29d325eb1c730e87e9b8746455b4071fcc2a9f Create DPP: 0xd7f02D1b4F9495B549787808503Ecfd231C3fbDA-0x156595bAF85D5C29E91d959889B022d952190A64 Pool:0xbD0CCdbC8FECcc68934Bf884fBe85AB7B51A15eb Tx: 0xdbda4038d439060f9ef3fc09df58f80758d38a81e246cbbc0c88a6b7c275b2ed +==================================================== +network type: kovan +Deploy time: 2021/1/26 上午11:13:49 +Mock POOL Tx: V2 +Approve:0xd8C30a4E866B188F16aD266dC3333BD47F34ebaE Tx: 0x21319fc7b2010f495706d835fe0d20177a51c4aa9e787ad4efb151f4a83b0b97 +Approve:0xd7f02D1b4F9495B549787808503Ecfd231C3fbDA Tx: 0x0219e34cf6be4d9f1384034ce4c35bc030f67d00e9e380b4b0acec64ecd553c1 +Approve:0x43688f367eb83697c3ca5d03c5055b6bd6f6ac4b Tx: 0x2c0a25770e0cc6a48d63a8c8f9067213695c8c1b657326379b58b6090d4c7b13 +Approve:0x156595bAF85D5C29E91d959889B022d952190A64 Tx: 0xe0b9870564d2037c75b3f345a9dd93d80d9405a949094459c5b34f94acd3ac61 +Create DPP: 0xd8C30a4E866B188F16aD266dC3333BD47F34ebaE-0x43688f367eb83697c3ca5d03c5055b6bd6f6ac4b Pool:0xF2b06A3A58CEd368ebc6e5BB578503ECC9d50043 Tx: 0x4671da84177eb8a69c2cce7ce42101f3e2f0cfc221100b5613d0a0d5565e8c79 +Create DPP: 0xd8C30a4E866B188F16aD266dC3333BD47F34ebaE-0x156595bAF85D5C29E91d959889B022d952190A64 Pool:0x1D690066fc3F2D808555839B630a89da118B9466 Tx: 0x5e3609531f6a6918bcc2f9d91b154d78f0b15d8b229da00cda960a380fd909dd +Create DPP: 0xd7f02D1b4F9495B549787808503Ecfd231C3fbDA-0x43688f367eb83697c3ca5d03c5055b6bd6f6ac4b Pool:0x7B0d1D528a08619B370eb5c920298F74465b1982 Tx: 0x1dffacc99a0ce542425eb5fd977da570dae26246abb929e2a4eb04fcdee6a994 +Create DPP: 0xd7f02D1b4F9495B549787808503Ecfd231C3fbDA-0x156595bAF85D5C29E91d959889B022d952190A64 Pool:0x3997576b46e26D3fCEa7C4A76a62146AE5A903F3 Tx: 0x07dc666596b9c47522ed8dfb194cfcc9d673c0c63ec4d456d7b7485ea7eca57b diff --git a/migrations/2_deploy_v1.5.js b/migrations/2_deploy_v1.5.js index 3004e16..14a024e 100644 --- a/migrations/2_deploy_v1.5.js +++ b/migrations/2_deploy_v1.5.js @@ -3,15 +3,15 @@ const { deploySwitch } = require('../truffle-config.js') const file = fs.createWriteStream("../deploy-detail-v1.5.txt", { 'flags': 'a' }); let logger = new console.Console(file, file); -const DODOApprove = artifacts.require("DODOApprove"); -const DODOV1Proxy03 = artifacts.require("DODOV1Proxy03"); +const DODOApproveProxy = artifacts.require("DODOApproveProxy"); +const DODOV1Proxy04 = artifacts.require("DODOV1Proxy04"); const DODOSellHelper = artifacts.require("DODOSellHelper"); const DODOSwapCalcHelper = artifacts.require("DODOSwapCalcHelper"); module.exports = async (deployer, network, accounts) => { let DODOSellHelperAddress = ""; let WETHAddress = ""; - let DODOApproveAddress = ""; + let DODOApproveProxyAddress = ""; let chiAddress = ""; let DODOSwapCalcHelperAddress = ""; let ownerAddress = "" @@ -19,20 +19,20 @@ module.exports = async (deployer, network, accounts) => { DODOSellHelperAddress = "0xbdEae617F2616b45DCB69B287D52940a76035Fe3"; WETHAddress = "0x5eca15b12d959dfcf9c71c59f8b467eb8c6efd0b"; DODOSwapCalcHelperAddress = "0x0473FFd7039435F1FC794281F2a05830A1a0108a"; - DODOApproveAddress = ""; + DODOApproveProxyAddress = ""; chiAddress = "0x0000000000004946c0e9f43f4dee607b0ef1fa1c"; ownerAddress = accounts[0]; } else if (network == "live") { DODOSellHelperAddress = "0x533da777aedce766ceae696bf90f8541a4ba80eb"; WETHAddress = "0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2"; - DODOApproveAddress = "0xCB859eA579b28e02B87A1FDE08d087ab9dbE5149"; + DODOApproveProxyAddress = "0x335aC99bb3E51BDbF22025f092Ebc1Cf2c5cC619"; chiAddress = "0x0000000000004946c0e9F43F4Dee607b0eF1fA1c"; DODOSwapCalcHelperAddress = "0x3C02477f1B3C70D692be95a6e3805E02bba71206"; ownerAddress = "0x95C4F5b83aA70810D4f142d58e5F7242Bd891CB0"; } else if (network == "bsclive") { DODOSellHelperAddress = "0x0F859706AeE7FcF61D5A8939E8CB9dBB6c1EDA33"; WETHAddress = "0xbb4CdB9CBd36B01bD1cBaEBF2De08d9173bc095c"; - DODOApproveAddress = "0xa128Ba44B2738A558A1fdC06d6303d52D3Cef8c1"; + DODOApproveProxyAddress = "0xB76de21f04F677f07D9881174a1D8E624276314C"; chiAddress = "0x0000000000000000000000000000000000000000"; DODOSwapCalcHelperAddress = "0xb0199C2c8ADF1E6c1e41De60A62E993406Cb8C02"; ownerAddress = "0x4073f2b9bB95774531b9e23d206a308c614A943a"; @@ -46,10 +46,10 @@ module.exports = async (deployer, network, accounts) => { var tx; logger.log("Deploy type: Proxy"); - if (DODOApproveAddress == "") { - await deployer.deploy(DODOApprove); - DODOApproveAddress = DODOApprove.address; - logger.log("DODOApprove Address: ", DODOApproveAddress); + if (DODOApproveProxyAddress == "") { + await deployer.deploy(DODOApproveProxy); + DODOApproveProxyAddress = DODOApproveProxy.address; + logger.log("DODOApproveProxy Address: ", DODOApproveDODOApproveProxyAddressAddress); } if (DODOSellHelperAddress == "") { await deployer.deploy(DODOSellHelper); @@ -62,14 +62,14 @@ module.exports = async (deployer, network, accounts) => { } await deployer.deploy( - DODOV1Proxy03, - DODOApproveAddress, + DODOV1Proxy04, + DODOApproveProxyAddress, DODOSellHelperAddress, WETHAddress, chiAddress ); - logger.log("DODOV1Proxy03 Address: ", DODOV1Proxy03.address); - const DODOProxyInstance = await DODOV1Proxy03.at(DODOV1Proxy03.address); + logger.log("DODOV1Proxy04 Address: ", DODOV1Proxy04.address); + const DODOProxyInstance = await DODOV1Proxy04.at(DODOV1Proxy04.address); tx = await DODOProxyInstance.initOwner(ownerAddress); logger.log("Set DODOProxy Owner tx: ", tx.tx); diff --git a/migrations/3_deploy_v2.js b/migrations/3_deploy_v2.js index 4fdddcc..0013aef 100644 --- a/migrations/3_deploy_v2.js +++ b/migrations/3_deploy_v2.js @@ -12,12 +12,17 @@ const DppTemplate = artifacts.require("DPP"); const DppAdminTemplate = artifacts.require("DPPAdmin"); const CpTemplate = artifacts.require("CP"); +const ERC20Template = artifacts.require("InitializableERC20"); +const MintableERC20Template = artifacts.require("InitializableMintableERC20"); +const ERC20Factory = artifacts.require("ERC20Factory"); + const DvmFactory = artifacts.require("DVMFactory"); const DppFactory = artifacts.require("DPPFactory"); const CpFactory = artifacts.require("CrowdPoolingFactory"); const DODOApprove = artifacts.require("DODOApprove"); -const DODOProxyV2 = artifacts.require("DODOV2Proxy01"); +const DODOApproveProxy = artifacts.require("DODOApproveProxy"); +const DODOProxyV2 = artifacts.require("DODOV2Proxy02"); const DODOIncentive = artifacts.require("DODOIncentive"); const DODOSellHelper = artifacts.require("DODOSellHelper"); const DODOCalleeHelper = artifacts.require("DODOCalleeHelper"); @@ -52,6 +57,7 @@ module.exports = async (deployer, network, accounts) => { let CpFactoryAddress = ""; //Approve let DODOApproveAddress = ""; + let DODOApproveProxyAddress = ""; //Incentive let DODOIncentiveAddress = ""; let DODOTokenAddress = ""; @@ -59,31 +65,37 @@ module.exports = async (deployer, network, accounts) => { let multiSigAddress = ""; let defaultMaintainer = ""; + //ERC20 + let ERC20TemplateAddress = ""; + let MintableERC20TemplateAddress = ""; + let ERC20FactoryAddress = ""; + if (network == "kovan") { //Helper DODOSellHelperAddress = "0xbdEae617F2616b45DCB69B287D52940a76035Fe3"; WETHAddress = "0x5eca15b12d959dfcf9c71c59f8b467eb8c6efd0b"; chiAddress = "0x0000000000004946c0e9f43f4dee607b0ef1fa1c"; - DODOCalleeHelperAddress = ""; + DODOCalleeHelperAddress = "0xf45e57FE0c0Bf759E34152179B2dA0a4e1a6BC9B"; DODOV1PmmHelperAddress = "0xC972069473a686b1c11Bd9347D719c87e6745d39"; DODORouteV2HelperAddress = ""; //Template CloneFactoryAddress = "0xf7959fe661124C49F96CF30Da33729201aEE1b27"; - DefaultMtFeeRateAddress = ""; + DefaultMtFeeRateAddress = "0x2F7e3B1c22C1baE2224Cef9F8BFe6B13789Fd0F7"; DefaultPermissionAddress = "0xACc7E23368261e1E02103c4e5ae672E7D01f5797"; - DvmTemplateAddress = ""; - DppTemplateAddress = ""; + DvmTemplateAddress = "0xA6384D1501842e9907D43148E2ca0d50E4ad56E2"; + DppTemplateAddress = "0x044b48D64E77Ab8854C46c8456dC05C540c9dd53"; DppAdminTemplateAddress = ""; - CpTemplateAddress = ""; + CpTemplateAddress = "0x81c802080c3CE0dE98fcb625670A14Eb8440184a"; //Factory - DvmFactoryAddress = ""; + DvmFactoryAddress = "0xE842d8c9A54B23C4D0cf208daCA3882c0c311353"; DppFactoryAddress = ""; - CpFactoryAddress = ""; + CpFactoryAddress = "0xD25e0A9A464f50191d9C879bE818FbA44680E980"; //Approve DODOApproveAddress = ""; - DODOIncentiveAddress = ""; + DODOApproveProxyAddress = ""; + DODOIncentiveAddress = "0x1f69E3CEAbDc464Ab11bceB15726530CD8AC535E"; DODOTokenAddress = "0xfF2985D13953Cb92ecc585aA2B6A4AF8cB46068f"; //Account multiSigAddress = accounts[0]; @@ -102,16 +114,17 @@ module.exports = async (deployer, network, accounts) => { DefaultPermissionAddress = "0x6B208E08dcF6BD51F50C5Da09d15B2D8E5C46Cf2"; DvmTemplateAddress = "0x2BBD66fC4898242BDBD2583BBe1d76E8b8f71445"; - DppTemplateAddress = "0x18DFdE99F578A0735410797e949E8D3e2AFCB9D2"; - DppAdminTemplateAddress = "0x729f7f44bf64Ce814716b6261e267DbE6cdf021c"; + DppTemplateAddress = "0xB76de21f04F677f07D9881174a1D8E624276314C"; + DppAdminTemplateAddress = ""; CpTemplateAddress = "0x18b0bD918b55f995Fd404B872404378A62cb403b"; //Factory - DvmFactoryAddress = ""; + DvmFactoryAddress = "0x72d220cE168C4f361dD4deE5D826a01AD8598f6C"; DppFactoryAddress = ""; - CpFactoryAddress = ""; + CpFactoryAddress = "0xE8C9A78725D0451FA19878D5f8A3dC0D55FECF25"; //Proxy - DODOApproveAddress = "0xC3BeD579CaB3EC29B22D9AB99F4E586af42496b9"; - DODOIncentiveAddress = ""; + DODOApproveAddress = "0xCB859eA579b28e02B87A1FDE08d087ab9dbE5149"; + DODOApproveProxyAddress = ""; + DODOIncentiveAddress = "0x989DcAA95801C527C5B73AA65d3962dF9aCe1b0C"; DODOTokenAddress = "0x43Dfc4159D86F3A37A5A4B3D4580b888ad7d4DDd"; //Account multiSigAddress = "0x95C4F5b83aA70810D4f142d58e5F7242Bd891CB0"; @@ -121,25 +134,26 @@ module.exports = async (deployer, network, accounts) => { DODOSellHelperAddress = "0x0F859706AeE7FcF61D5A8939E8CB9dBB6c1EDA33"; WETHAddress = "0xbb4CdB9CBd36B01bD1cBaEBF2De08d9173bc095c"; chiAddress = "0x0000000000000000000000000000000000000000"; - DODOCalleeHelperAddress = ""; + DODOCalleeHelperAddress = "0xDfaf9584F5d229A9DBE5978523317820A8897C5A"; DODORouteV2HelperAddress = ""; - DODOV1PmmHelperAddress = ""; + DODOV1PmmHelperAddress = "0x2BBD66fC4898242BDBD2583BBe1d76E8b8f71445"; //Template CloneFactoryAddress = "0x03E2427859119E497EB856a166F616a2Ce5f8c88"; - DefaultMtFeeRateAddress = ""; - DefaultPermissionAddress = ""; + DefaultMtFeeRateAddress = "0x18DFdE99F578A0735410797e949E8D3e2AFCB9D2"; + DefaultPermissionAddress = "0x729f7f44bf64Ce814716b6261e267DbE6cdf021c"; - DvmTemplateAddress = ""; - DppTemplateAddress = ""; + DvmTemplateAddress = "0xC3BeD579CaB3EC29B22D9AB99F4E586af42496b9"; + DppTemplateAddress = "0x85351262f7474Ebe23FfAcD633cf20A491F1325D"; DppAdminTemplateAddress = ""; - CpTemplateAddress = ""; + CpTemplateAddress = "0x041ABa00c57Dd47abC37A2931dF569a2A2cc57Be"; //Factory - DvmFactoryAddress = ""; + DvmFactoryAddress = "0xf50BDc9E90B7a1c138cb7935071b85c417C4cb8e"; DppFactoryAddress = ""; - CpFactoryAddress = ""; + CpFactoryAddress = "0x9aE501385Bc7996A2A4a1FBb00c8d3820611BCB5"; //Proxy - DODOApproveAddress = ""; - DODOIncentiveAddress = ""; + DODOApproveAddress = "0xa128Ba44B2738A558A1fdC06d6303d52D3Cef8c1"; + DODOApproveProxyAddress = ""; + DODOIncentiveAddress = "0x80930Cb1849F7D42531506fF45E66724338A821b"; DODOTokenAddress = "0x497A44c951fCCF92ADfdeD0a5b0162256F147647"; //Account multiSigAddress = "0x4073f2b9bB95774531b9e23d206a308c614A943a"; @@ -161,11 +175,29 @@ module.exports = async (deployer, network, accounts) => { logger.log("UniAdapter Address: ", UniAdapter.address); } - if (deploySwitch.CALLEE) { - logger.log("Deploy type: V2 - Callee"); - await deployer.deploy(DODOCalleeHelper, WETHAddress); - DODOCalleeHelperAddress = DODOCalleeHelper.address; - logger.log("DODOCalleeHelperAddress: ", DODOCalleeHelperAddress); + if (deploySwitch.ERC20) { + logger.log("Deploy type: V2 - ERC20 Factory"); + if (ERC20TemplateAddress == "") { + await deployer.deploy(ERC20Template); + ERC20TemplateAddress = ERC20Template.address; + logger.log("ERC20TemplateAddress: ", ERC20TemplateAddress); + } + if (MintableERC20TemplateAddress == "") { + await deployer.deploy(MintableERC20Template); + MintableERC20TemplateAddress = MintableERC20Template.address; + logger.log("MintableERC20TemplateAddress: ", MintableERC20TemplateAddress); + } + + if (ERC20FactoryAddress == "") { + await deployer.deploy( + ERC20Factory, + CloneFactoryAddress, + ERC20TemplateAddress, + MintableERC20TemplateAddress + ); + ERC20FactoryAddress = ERC20Factory.address; + logger.log("ERC20FactoryAddress: ", ERC20FactoryAddress); + } } if (deploySwitch.DEPLOY_V2) { @@ -239,6 +271,12 @@ module.exports = async (deployer, network, accounts) => { logger.log("DODOApprove Address: ", DODOApproveAddress); } + if (DODOApproveProxyAddress == "") { + await deployer.deploy(DODOApproveProxy, DODOApproveAddress); + DODOApproveProxyAddress = DODOApproveProxy.address; + logger.log("DODOApproveProxy Address: ", DODOApproveProxyAddress); + } + //Incentive if (DODOIncentiveAddress == "") { await deployer.deploy(DODOIncentive, DODOTokenAddress); @@ -273,7 +311,7 @@ module.exports = async (deployer, network, accounts) => { DppAdminTemplateAddress, defaultMaintainer, DefaultMtFeeRateAddress, - DODOApproveAddress + DODOApproveProxyAddress ); DppFactoryAddress = DppFactory.address; logger.log("DppFactoryAddress: ", DppFactoryAddress); @@ -312,24 +350,28 @@ module.exports = async (deployer, network, accounts) => { DppFactoryAddress, CpFactoryAddress, WETHAddress, - DODOApproveAddress, + DODOApproveProxyAddress, DODOSellHelperAddress, chiAddress, DODOIncentiveAddress ); - logger.log("DODOProxyV2 Address: ", DODOProxyV2.address); + logger.log("DODOV2Proxy02 Address: ", DODOProxyV2.address); const DODOProxyV2Instance = await DODOProxyV2.at(DODOProxyV2.address); var tx = await DODOProxyV2Instance.initOwner(multiSigAddress); logger.log("Init DODOProxyV2 Tx:", tx.tx); - const DODOApproveInstance = await DODOApprove.at(DODOApproveAddress); - var tx = await DODOApproveInstance.init(multiSigAddress, DODOProxyV2.address); - logger.log("DODOApprove Init tx: ", tx.tx); - - if (network == 'kovan') { - //1. Proxy whiteList + + const DODOApproveProxyInstance = await DODOApproveProxy.at(DODOApproveProxyAddress); + var tx = await DODOApproveProxyInstance.init(multiSigAddress, [DODOProxyV2.address]); + logger.log("DODOApproveProxy Init tx: ", tx.tx); + + + const DODOApproveInstance = await DODOApprove.at(DODOApproveAddress); + var tx = await DODOApproveInstance.init(multiSigAddress, DODOApproveProxy.address); + logger.log("DODOApprove Init tx: ", tx.tx); + //2. ChangeDODO Incentive proxy const DODOIncentiveInstance = await DODOIncentive.at(DODOIncentiveAddress); diff --git a/migrations/4_deploy_v2_mock.js b/migrations/4_deploy_v2_mock.js index 49a2d1b..f368b69 100644 --- a/migrations/4_deploy_v2_mock.js +++ b/migrations/4_deploy_v2_mock.js @@ -64,10 +64,10 @@ module.exports = async (deployer, network, accounts) => { let MintableERC20TemplateAddress = "0xA45a64DAba80757432fA4d654Df12f65f020C13C"; let ERC20FactoryAddress = "0xCb1A2f64EfB02803276BFB5a8D511C4D950282a0"; - let DPPFactoryAddress = "0xaFC7F3Ef4f8609411653FbF1Dd6D583A8Ae1f0fA"; + let DPPFactoryAddress = "0x6DAb26dFE83E484DCC5126F812E3e6AA8e7eEf4D"; let DVMFactoryAddress = "0xE842d8c9A54B23C4D0cf208daCA3882c0c311353"; - let DODOApproveAddress = "0x6FB6313cafaFe38acA19Be0B8151d6354F74A340"; - let DODOProxyV2Address = "0xfDEDc04A641DE9CEeb4eD2F24d98faa22418Bd94"; + let DODOApproveAddress = "0x8acF28D9d8124B20b645893b6102950B488dfd29"; + let DODOProxyV2Address = "0x3457A15B9ab57FC754789EE83E4BD2BD8f4F50C8"; @@ -193,22 +193,22 @@ module.exports = async (deployer, network, accounts) => { // const quoteInAmount = web3.utils.toWei("0.5", 'ether'); const deadline = Math.floor(new Date().getTime() / 1000 + 60 * 10); //DVM Pool - for (var i = 0; i < POOL_PARAM.length; i++) { - tx = await DODOProxyV2Instance.createDODOVendingMachine( - POOL_PARAM[i].baseAddr, - POOL_PARAM[i].quoteAddr, - baseInAmount, - 0, - POOL_PARAM[i].lpFeeRate, - POOL_PARAM[i].i, - POOL_PARAM[i].k, - false, - deadline - ); - var poolAddress = await DVMFactoryInstance._REGISTRY_(POOL_PARAM[i].baseAddr, POOL_PARAM[i].quoteAddr, 0); - logger.log("Create DVM: " + POOL_PARAM[i].baseAddr + "-" + POOL_PARAM[i].quoteAddr + " Pool:" + poolAddress + " Tx:", tx.tx); - } - //DVM Pool + // for (var i = 0; i < POOL_PARAM.length; i++) { + // tx = await DODOProxyV2Instance.createDODOVendingMachine( + // POOL_PARAM[i].baseAddr, + // POOL_PARAM[i].quoteAddr, + // baseInAmount, + // 0, + // POOL_PARAM[i].lpFeeRate, + // POOL_PARAM[i].i, + // POOL_PARAM[i].k, + // false, + // deadline + // ); + // var poolAddress = await DVMFactoryInstance._REGISTRY_(POOL_PARAM[i].baseAddr, POOL_PARAM[i].quoteAddr, 0); + // logger.log("Create DVM: " + POOL_PARAM[i].baseAddr + "-" + POOL_PARAM[i].quoteAddr + " Pool:" + poolAddress + " Tx:", tx.tx); + // } + //DPP Pool for (var i = 0; i < POOL_PARAM.length; i++) { tx = await DODOProxyV2Instance.createDODOPrivatePool( POOL_PARAM[i].baseAddr, diff --git a/test/utils/Contracts.ts b/test/utils/Contracts.ts index f5bd3e0..5842d33 100644 --- a/test/utils/Contracts.ts +++ b/test/utils/Contracts.ts @@ -35,11 +35,12 @@ export const DVM_PROXY_NAME = "DVMProxy" export const CONST_FEE_RATE_MODEL_NAME = "ConstFeeRateModel" export const PERMISSION_MANAGER_NAME = "PermissionManager" export const EXTERNAL_VALUE_NAME = "ExternalValue" -export const DODO_PROXY_NAME = "DODOV2Proxy01" +export const DODO_PROXY_NAME = "DODOV2Proxy02" export const FEE_RATE_MODEL_NAME = "FeeRateModel" export const DPP_NAME = "DPP" export const DPP_FACTORY_NAME = "DPPFactory" export const SMART_APPROVE = "DODOApprove" +export const SMART_APPROVE_PROXY = "DODOApproveProxy" export const DODO_SELL_HELPER = "DODOSellHelper" export const DPP_ADMIN_NAME = "DPPAdmin" export const DODO_CALLEE_HELPER_NAME = "DODOCalleeHelper" diff --git a/test/utils/ProxyContextV2.ts b/test/utils/ProxyContextV2.ts index 3d36d85..ada49e0 100644 --- a/test/utils/ProxyContextV2.ts +++ b/test/utils/ProxyContextV2.ts @@ -28,6 +28,7 @@ export class ProxyContext { DPPFactory: Contract; CPFactory: Contract; DODOApprove: Contract; + DODOApproveProxy: Contract; DODOCalleeHelper: Contract; DODOSellHelper: Contract; @@ -95,6 +96,11 @@ export class ProxyContext { contracts.SMART_APPROVE ); + this.DODOApproveProxy = await contracts.newContract( + contracts.SMART_APPROVE_PROXY, + [this.DODOApprove.options.address] + ) + //DODO Incentive this.DODOIncentive = await contracts.newContract( contracts.DODO_INCENTIVE, @@ -108,7 +114,7 @@ export class ProxyContext { dppAdminTemplate.options.address, this.Deployer, mtFeeRateModelTemplate.options.address, - this.DODOApprove.options.address + this.DODOApproveProxy.options.address ] ) @@ -134,7 +140,7 @@ export class ProxyContext { this.DPPFactory.options.address, this.CPFactory.options.address, this.WETH.options.address, - this.DODOApprove.options.address, + this.DODOApproveProxy.options.address, this.DODOSellHelper.options.address, "0x0000000000000000000000000000000000000000", this.DODOIncentive.options.address @@ -142,9 +148,10 @@ export class ProxyContext { ); await this.DODOProxyV2.methods.initOwner(this.Deployer).send(this.sendParam(this.Deployer)); - await this.DODOApprove.methods.init(this.Deployer,this.DODOProxyV2.options.address).send(this.sendParam(this.Deployer)); + await this.DODOApprove.methods.init(this.Deployer,this.DODOApproveProxy.options.address).send(this.sendParam(this.Deployer)); + await this.DODOApproveProxy.methods.init(this.Deployer, [this.DODOProxyV2.options.address]).send(this.sendParam(this.Deployer)); + await this.DODOIncentive.methods.initOwner(this.Deployer).send(this.sendParam(this.Deployer)); - await this.DODOIncentive.methods.changeDODOProxy(this.DODOProxyV2.options.address).send(this.sendParam(this.Deployer)); this.DODOCalleeHelper = await contracts.newContract( diff --git a/truffle-config.js b/truffle-config.js index 380aa46..5559589 100644 --- a/truffle-config.js +++ b/truffle-config.js @@ -38,15 +38,14 @@ module.exports = { * $ truffle test --network */ deploySwitch: { - DEPLOY_V1: false, + DEPLOY_V1: true, DEPLOY_V2: false, ADAPTER: false, MOCK_TOKEN: false, MOCK_V2_POOL: false, MOCK_V2_SWAP: false, MANUAL_ADD_POOL: false, - MOCK_TARGET_POOL: false, - CALLEE: false, + MOCK_TARGET_POOL: false }, networks: {