diff --git a/README.md b/README.md index 1c869f8..863a2da 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,14 @@ # DODO V2: Help 1 Trillion People Issue Token <<<<<<< HEAD +<<<<<<< HEAD +======= + +## Audit Report + +[Audited by Peckshield](https://github.com/DODOEX/contractV2/blob/main/audit/PeckShield-Audit-DODOV2-v1.0.pdf) + +>>>>>>> eb0b6ca13dc60f040673a1b62f1b5e6b84a3543e ## Bug Bounty 💰 ### Rewards @@ -29,6 +37,7 @@ Anyone who reports a unique, previously-unreported vulnerability that results in ## Contact Us Send E-mail to contact@dodoex.io +<<<<<<< HEAD ======= ## Audit Report @@ -63,3 +72,6 @@ Anyone who reports a unique, previously-unreported vulnerability that results in Send E-mail to contact@dodoex.io >>>>>>> a525e0a839159ddb4d35f4a3ea398e9f74a0df6e +======= + +>>>>>>> eb0b6ca13dc60f040673a1b62f1b5e6b84a3543e 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/DODOToken/vDODOToken.sol b/contracts/DODOToken/vDODOToken.sol new file mode 100644 index 0000000..f7a6c9a --- /dev/null +++ b/contracts/DODOToken/vDODOToken.sol @@ -0,0 +1,331 @@ +/* + + Copyright 2020 DODO ZOO. + SPDX-License-Identifier: Apache-2.0 + +*/ +pragma solidity 0.6.9; +pragma experimental ABIEncoderV2; + +import {IERC20} from "../intf/IERC20.sol"; +import {SafeMath} from "../lib/SafeMath.sol"; +import {DecimalMath} from "../lib/DecimalMath.sol"; +import {InitializableOwnable} from "../lib/InitializableOwnable.sol"; +import {SafeERC20} from "../lib/SafeERC20.sol"; +import {ReentrancyGuard} from "../lib/ReentrancyGuard.sol"; +import {IDODOApproveProxy} from "../SmartRoute/DODOApproveProxy.sol"; + +interface IGovernance { + function governanceCall(address account, uint256 amount,bytes calldata data) external returns (bool); +} + + +interface IDODOLockedHelper { + function getDodoLockedAmount() external returns (uint256); +} + + +contract vDODOToken is InitializableOwnable ,ReentrancyGuard{ + using SafeMath for uint256; + using SafeERC20 for IERC20; + + // ============ Storage(ERC20) ============ + + string public name; + string public symbol; + uint8 public decimals; + uint256 public totalSupply; + mapping(address => mapping(address => uint256)) internal _ALLOWED_; + + + // ============ Storage ============ + address immutable _DODO_LOCKED_HELPER_; + address immutable _DODO_TOKEN_; + address immutable _DODO_APPROVE_PROXY_; + address public _DOOD_GOV_; + bool cantransfer; + uint256 public dodoPerBlock; + + uint256 constant public _MAG_SP_AMOUNT_ = 10; // 0.1 + + uint256 constant public _MIN_X_ = 10**18; + uint256 constant public _MAX_X_ = 10 * 10**18; + uint256 constant public _MIN_Y_ = 5 * 10**18; + uint256 constant public _MAX_Y_ = 15 * 10**18; + + uint256 public alpha = 100; + uint256 public lastRewardBlock; + uint256 public dodoFeeDestroyRatio; + mapping(address => bool) public operater; + mapping(address => UserInfo) public userInfo; + + struct UserInfo { + address superior; + uint256 vdodoAmount; + uint256 overdraft; + bool hasParticipateGov; //是否正在参与治理,是的话就不可以提币 + } + + // ============ Events ============ + event ParticipatoryGov(address user, uint256 amount); + event Deposit(address user,address superior, uint256 amount); + event Withdraw(address user, uint256 amount); + event SetCantransfer(bool allowed); + event RemoveOperation(address operater); + event AddOperation(address operater); + event ChangePerReward(uint256 dodoPerBlock); + event UpdateDodoFeeDestroyRatio(uint256 dodoFeeDestroyRatio); + + event Transfer(address indexed from, address indexed to, uint256 amount); + event Approval(address indexed owner, address indexed spender, uint256 amount); + + + // ============ Modifiers ============ + //TODO: 是否需要operator的白名单设计? + modifier onlyOperater() { + require(cantransfer || operater[msg.sender] , "vDODOToken: not allowed transfer"); + _; + } + + constructor( + address _dodoGov, + address _dodoToken, + address _dodoLockedHelper, + address _dodoApproveProxy, + string memory _name, + string memory _symbol) + public { + name = _name; + symbol = _symbol; + decimals = 18; + _DODO_APPROVE_PROXY_ = _dodoApproveProxy; + _DOOD_GOV_ = _dodoGov; + _DODO_LOCKED_HELPER_ = _dodoLockedHelper; + _DODO_TOKEN_ = _dodoToken; + lastRewardBlock = block.number; + } + + // ============ Ownable Functions ============` + + function setCantransfer(bool _allowed) public onlyOwner { + cantransfer = _allowed; + emit SetCantransfer(_allowed); + } + + function addOperationAddress(address _operater) public onlyOwner { + operater[_operater] = true; + emit AddOperation(_operater); + } + + function removeOperation(address _operater) public onlyOwner { + operater[_operater] = false; + emit RemoveOperation(_operater); + } + + function changePerReward(uint256 _dodoPerBlock) public onlyOwner { + _updateAlpha(); + dodoPerBlock = _dodoPerBlock; + emit ChangePerReward(dodoPerBlock); + } + + function updateDodoFeeDestroyRatio(uint256 _dodoFeeDestroyRatio) public onlyOwner { + dodoFeeDestroyRatio = _dodoFeeDestroyRatio; + emit UpdateDodoFeeDestroyRatio(_dodoFeeDestroyRatio); + } + + // ============ Functions ============ + function participatoryGov( + uint256 _amount, + bytes calldata _data + ) external preventReentrant { + UserInfo storage user = userInfo[msg.sender]; + require(user.vdodoAmount > _amount, "vDODOToken: no enough vdodo"); + if (_data.length > 0) + IGovernance(_DOOD_GOV_).governanceCall(msg.sender, _amount, _data); + + user.vdodoAmount = user.vdodoAmount.sub(_amount); + user.hasParticipateGov = true; + //TODO: 是否减掉总量? + totalSupply = totalSupply.sub(_amount); + + emit ParticipatoryGov(msg.sender, _amount); + } + + + function deposit(uint256 _dodoAmount,address _superiorAddress) public preventReentrant { + require(_dodoAmount > 0, "vDODOToken: must deposit greater than 0"); + IDODOApproveProxy(_DODO_APPROVE_PROXY_).claimTokens( + _DODO_TOKEN_, + msg.sender, + address(this), + _dodoAmount + ); + + _updateAlpha(); + + UserInfo storage user = userInfo[msg.sender]; + user.vdodoAmount = user.vdodoAmount.add(_dodoAmount.div(alpha)); + + if(user.superior == address(0) && _superiorAddress != address(0) && _superiorAddress != msg.sender){ + user.superior = _superiorAddress; + } + uint256 _dodoAmountDivAlpha = DecimalMath.divFloor(_dodoAmount, alpha); + + if(user.superior != address(0)){ + UserInfo storage superiorUser = userInfo[user.superior]; + + superiorUser.vdodoAmount = superiorUser.vdodoAmount.add(_dodoAmountDivAlpha.mul(_MAG_SP_AMOUNT_).div(100)); + + superiorUser.overdraft = superiorUser.overdraft.add(_dodoAmount.mul(_MAG_SP_AMOUNT_).div(100)); + + totalSupply = totalSupply.add(_dodoAmountDivAlpha.mul(_MAG_SP_AMOUNT_ + 100).div(100)); + }else { + totalSupply = totalSupply.add(_dodoAmountDivAlpha); + } + + emit Deposit(msg.sender, _superiorAddress, _dodoAmount); + } + + + function withdraw(uint256 _vDodoAmount) public preventReentrant { + UserInfo storage user = userInfo[msg.sender]; + uint256 userAmount = user.vdodoAmount; + require(userAmount >= _vDodoAmount, "vDODOToken: no enough vdodo token"); + require(!user.hasParticipateGov, "vDODOToken: hasParticipateGov"); + + _updateAlpha(); + + user.vdodoAmount = userAmount.sub(_vDodoAmount); + + if(user.superior != address(0)) { + UserInfo storage superiorUser = userInfo[user.superior]; + superiorUser.vdodoAmount = superiorUser.vdodoAmount.sub(_vDodoAmount.mul(_MAG_SP_AMOUNT_).div(100)); + + uint256 _overdraft = _vDodoAmount.mul(alpha).mul(_MAG_SP_AMOUNT_).div(100); + superiorUser.overdraft = superiorUser.overdraft.sub(_overdraft); + + totalSupply = totalSupply.sub(_vDodoAmount.mul(_MAG_SP_AMOUNT_ + 100).div(100)); + } else { + totalSupply = totalSupply.sub(_vDodoAmount); + } + + uint256 feeRatio = _checkReward(); + + uint256 withdrawDodoAmount = alpha.mul(_vDodoAmount); + + uint256 withdrawFeeAmount = DecimalMath.mulCeil(withdrawDodoAmount,feeRatio).div(100); + uint256 dodoReceive = withdrawDodoAmount.sub(withdrawFeeAmount); + + IERC20(_DODO_TOKEN_).transfer(msg.sender, dodoReceive); + + if(dodoFeeDestroyRatio > 0){ + uint256 destroyDodoAmount = DecimalMath.mulCeil(withdrawDodoAmount,dodoFeeDestroyRatio).div(100); + _transfer(address(this), address(0), destroyDodoAmount); + withdrawFeeAmount = withdrawFeeAmount.sub(destroyDodoAmount); + } + + alpha = alpha.add(withdrawFeeAmount.div(totalSupply)); + emit Withdraw(msg.sender, _vDodoAmount); + } + + // ============ Functions(ERC20) ============ + function balanceOf(address _address) public view returns (uint256 balance) { + UserInfo memory user = userInfo[_address]; + balance = user.vdodoAmount.sub(user.overdraft.div(alpha)); + } + + function transfer(address to, uint256 amount) public returns (bool) { + _transfer(msg.sender, to, amount); + return true; + } + + function approve(address spender, uint256 amount) public returns (bool) { + _approve(msg.sender, spender, amount); + return true; + } + + function transferFrom(address from, address to, uint256 amount) public returns (bool) { + require(amount <= _ALLOWED_[from][msg.sender], "ALLOWANCE_NOT_ENOUGH"); + _transfer(from, to, amount); + _ALLOWED_[from][msg.sender] = _ALLOWED_[from][msg.sender].sub(amount); + emit Transfer(from, to, amount); + return true; + } + + function _approve( + address owner, + address spender, + uint256 amount + ) private onlyOperater { + _ALLOWED_[owner][spender] = amount; + emit Approval(owner, spender, amount); + } + + function allowance(address owner, address spender) public view returns (uint256) { + return _ALLOWED_[owner][spender]; + } + + function _transfer(address from, address to, uint256 _amount) internal onlyOperater { + require(from != address(0), " transfer from the zero address"); + require(to != address(0), " transfer to the zero address"); + require(balanceOf(from) >= _amount,"no enough to transfer"); + + UserInfo storage user = userInfo[from]; + user.vdodoAmount= user.vdodoAmount.sub(_amount); + + address fromSuperiorAddr = user.superior; + + if(fromSuperiorAddr != address(0)) { + UserInfo storage fromSuperior = userInfo[fromSuperiorAddr]; + fromSuperior.vdodoAmount = fromSuperior.vdodoAmount.sub(_amount.mul(_MAG_SP_AMOUNT_).div(100)); + } + + UserInfo storage toUser = userInfo[to]; + toUser.vdodoAmount = toUser.vdodoAmount.add(_amount); + + address toSuperiorAddr = toUser.superior; + if(toSuperiorAddr != address(0)) { + UserInfo storage toSuperior = userInfo[toSuperiorAddr]; + toUser.vdodoAmount =toSuperior.vdodoAmount.add(_amount.mul(_MAG_SP_AMOUNT_).div(100)); + } + + emit Transfer(from, to, _amount); + } + + // ============ View Functions ============ + function canWithDraw(address _address) public view returns (uint256 withDrawAmount) { + UserInfo memory user = userInfo[_address]; + withDrawAmount = user.vdodoAmount.mul(alpha).sub(user.overdraft); + } + + + // ============ internal function ============ + function _updateAlpha() internal { + uint256 accuDODO = dodoPerBlock * (block.number.sub(lastRewardBlock)); + if(totalSupply > 0){ + alpha = alpha.add(accuDODO.div(totalSupply)); + } + lastRewardBlock = block.number; + } + + // ============= Helper and calculation function =============== + function _checkReward() internal returns (uint256) { + uint256 dodoTotalLockedAmout = IDODOLockedHelper(_DODO_LOCKED_HELPER_).getDodoLockedAmount(); + // (x - 1)^2 / 81 + (y - 15)^2 / 100 = 1 ==> y = sqrt(100* (x*x +2x ) / 81)) +15 + // y = 5 (x ≤ 1) + // y = 15 (x ≥ 10) + uint256 x = DecimalMath.divCeil(dodoTotalLockedAmout,totalSupply); + if( x <= _MIN_X_){ + return _MIN_Y_; + }else if(x >= _MAX_X_){ + return _MAX_Y_; + }else{ + uint256 xSubOne = x.sub(10**18); + uint256 rewardAmount = uint256(81 * 10**18).sub(xSubOne.mul(xSubOne)).mul(100).div(81).sqrt().add(15); + return rewardAmount; + } + } +} + + +//TODO: donate function? \ No newline at end of file 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/contracts/VDODO/VDODOChef.sol b/contracts/VDODO/VDODOChef.sol deleted file mode 100644 index fda7398..0000000 --- a/contracts/VDODO/VDODOChef.sol +++ /dev/null @@ -1,1057 +0,0 @@ -/* - - Copyright 2020 DODO ZOO. - SPDX-License-Identifier: Apache-2.0 - -*/ - -pragma solidity 0.6.9; -pragma experimental ABIEncoderV2; - -/** - * @title SafeMath - * @author DODO Breeder - * - * @notice Math operations with safety checks that revert on error - */ -library SafeMath { - function mul(uint256 a, uint256 b) internal pure returns (uint256) { - if (a == 0) { - return 0; - } - - uint256 c = a * b; - require(c / a == b, "MUL_ERROR"); - - return c; - } - - function div(uint256 a, uint256 b) internal pure returns (uint256) { - require(b > 0, "DIVIDING_ERROR"); - return a / b; - } - - function divCeil(uint256 a, uint256 b) internal pure returns (uint256) { - uint256 quotient = div(a, b); - uint256 remainder = a - quotient * b; - if (remainder > 0) { - return quotient + 1; - } else { - return quotient; - } - } - - function sub(uint256 a, uint256 b) internal pure returns (uint256) { - require(b <= a, "SUB_ERROR"); - return a - b; - } - - function add(uint256 a, uint256 b) internal pure returns (uint256) { - uint256 c = a + b; - require(c >= a, "ADD_ERROR"); - return c; - } - - function sqrt(uint256 x) internal pure returns (uint256 y) { - uint256 z = x / 2 + 1; - y = x; - while (z < y) { - y = z; - z = (x / z + z) / 2; - } - } -} - -pragma solidity 0.6.9; -/** - * @title DecimalMath - * @author DODO Breeder - * - * @notice Functions for fixed point number with 18 decimals - */ -library DecimalMath { - using SafeMath for uint256; - - uint256 internal constant ONE = 10**18; - uint256 internal constant ONE2 = 10**36; - - function mulFloor(uint256 target, uint256 d) internal pure returns (uint256) { - return target.mul(d) / (10**18); - } - - function mulCeil(uint256 target, uint256 d) internal pure returns (uint256) { - return target.mul(d).divCeil(10**18); - } - - function divFloor(uint256 target, uint256 d) internal pure returns (uint256) { - return target.mul(10**18).div(d); - } - - function divCeil(uint256 target, uint256 d) internal pure returns (uint256) { - return target.mul(10**18).divCeil(d); - } - - function reciprocalFloor(uint256 target) internal pure returns (uint256) { - return uint256(10**36).div(target); - } - - function reciprocalCeil(uint256 target) internal pure returns (uint256) { - return uint256(10**36).divCeil(target); - } -} -// File: @openzeppelin/contracts/access/Ownable.sol - - - -pragma solidity 0.6.9; -/** - * @title Ownable - * @author DODO Breeder - * - * @notice Ownership related functions - */ -contract Ownable { - address public _OWNER_; - address public _NEW_OWNER_; - - // ============ Events ============ - - event OwnershipTransferPrepared(address indexed previousOwner, address indexed newOwner); - - event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); - - // ============ Modifiers ============ - - modifier onlyOwner() { - require(msg.sender == _OWNER_, "NOT_OWNER"); - _; - } - - // ============ Functions ============ - - constructor() internal { - _OWNER_ = msg.sender; - emit OwnershipTransferred(address(0), _OWNER_); - } - - function transferOwnership(address newOwner) external onlyOwner { - emit OwnershipTransferPrepared(_OWNER_, newOwner); - _NEW_OWNER_ = newOwner; - } - - function claimOwnership() external { - require(msg.sender == _NEW_OWNER_, "INVALID_CLAIM"); - emit OwnershipTransferred(_OWNER_, _NEW_OWNER_); - _OWNER_ = _NEW_OWNER_; - _NEW_OWNER_ = address(0); - } -} - - -pragma solidity 0.6.9; - -/** - * @title ReentrancyGuard - * @author DODO Breeder - * - * @notice Protect functions from Reentrancy Attack - */ -contract ReentrancyGuard { - // https://solidity.readthedocs.io/en/latest/control-structures.html?highlight=zero-state#scoping-and-declarations - // zero-state of _ENTERED_ is false - bool private _ENTERED_; - - modifier preventReentrant() { - require(!_ENTERED_, "REENTRANT"); - _ENTERED_ = true; - _; - _ENTERED_ = false; - } -} - -// File: @openzeppelin/contracts/token/ERC20/IERC20.sol - - - -pragma solidity 0.6.9; - -/** - * @dev Interface of the ERC20 standard as defined in the EIP. - */ -interface IERC20 { - /** - * @dev Returns the amount of tokens in existence. - */ - function totalSupply() external view returns (uint256); - - /** - * @dev Returns the amount of tokens owned by `account`. - */ - function balanceOf(address account) external view returns (uint256); - - /** - * @dev Moves `amount` tokens from the caller's account to `recipient`. - * - * Returns a boolean value indicating whether the operation succeeded. - * - * Emits a {Transfer} event. - */ - function transfer(address recipient, uint256 amount) external returns (bool); - - /** - * @dev Returns the remaining number of tokens that `spender` will be - * allowed to spend on behalf of `owner` through {transferFrom}. This is - * zero by default. - * - * This value changes when {approve} or {transferFrom} are called. - */ - function allowance(address owner, address spender) external view returns (uint256); - - /** - * @dev Sets `amount` as the allowance of `spender` over the caller's tokens. - * - * Returns a boolean value indicating whether the operation succeeded. - * - * IMPORTANT: Beware that changing an allowance with this method brings the risk - * that someone may use both the old and the new allowance by unfortunate - * transaction ordering. One possible solution to mitigate this race - * condition is to first reduce the spender's allowance to 0 and set the - * desired value afterwards: - * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 - * - * Emits an {Approval} event. - */ - function approve(address spender, uint256 amount) external returns (bool); - - /** - * @dev Moves `amount` tokens from `sender` to `recipient` using the - * allowance mechanism. `amount` is then deducted from the caller's - * allowance. - * - * Returns a boolean value indicating whether the operation succeeded. - * - * Emits a {Transfer} event. - */ - function transferFrom(address sender, address recipient, uint256 amount) external returns (bool); - - /** - * @dev Emitted when `value` tokens are moved from one account (`from`) to - * another (`to`). - * - * Note that `value` may be zero. - */ - event Transfer(address indexed from, address indexed to, uint256 value); - - /** - * @dev Emitted when the allowance of a `spender` for an `owner` is set by - * a call to {approve}. `value` is the new allowance. - */ - event Approval(address indexed owner, address indexed spender, uint256 value); -} - -pragma solidity 0.6.9; - -/* - * @dev Provides information about the current execution context, including the - * sender of the transaction and its data. While these are generally available - * via msg.sender and msg.data, they should not be accessed in such a direct - * manner, since when dealing with GSN meta-transactions the account sending and - * paying for execution may not be the actual sender (as far as an application - * is concerned). - * - * This contract is only required for intermediate, library-like contracts. - */ -abstract contract Context { - function _msgSender() internal view virtual returns (address payable) { - return msg.sender; - } - - function _msgData() internal view virtual returns (bytes memory) { - this; // silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691 - return msg.data; - } -} - -pragma solidity 0.6.9; -/** - * @title SafeERC20 - * @dev Wrappers around ERC20 operations that throw on failure (when the token - * contract returns false). Tokens that return no value (and instead revert or - * throw on failure) are also supported, non-reverting calls are assumed to be - * successful. - * To use this library you can add a `using SafeERC20 for ERC20;` statement to your contract, - * which allows you to call the safe operations as `token.safeTransfer(...)`, etc. - */ -library SafeERC20 { - using SafeMath for uint256; - - function safeTransfer( - IERC20 token, - address to, - uint256 value - ) internal { - _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value)); - } - - function safeTransferFrom( - IERC20 token, - address from, - address to, - uint256 value - ) internal { - _callOptionalReturn( - token, - abi.encodeWithSelector(token.transferFrom.selector, from, to, value) - ); - } - - function safeApprove( - IERC20 token, - address spender, - uint256 value - ) internal { - // safeApprove should only be called when setting an initial allowance, - // or when resetting it to zero. To increase and decrease it, use - // 'safeIncreaseAllowance' and 'safeDecreaseAllowance' - // solhint-disable-next-line max-line-length - require( - (value == 0) || (token.allowance(address(this), spender) == 0), - "SafeERC20: approve from non-zero to non-zero allowance" - ); - _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value)); - } - - /** - * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement - * on the return value: the return value is optional (but if data is returned, it must not be false). - * @param token The token targeted by the call. - * @param data The call data (encoded using abi.encode or one of its variants). - */ - function _callOptionalReturn(IERC20 token, bytes memory data) private { - // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since - // we're implementing it ourselves. - - // A Solidity high level call has three parts: - // 1. The target address is checked to verify it contains contract code - // 2. The call itself is made, and success asserted - // 3. The return value is decoded, which in turn checks the size of the returned data. - // solhint-disable-next-line max-line-length - - // solhint-disable-next-line avoid-low-level-calls - (bool success, bytes memory returndata) = address(token).call(data); - require(success, "SafeERC20: low-level call failed"); - - if (returndata.length > 0) { - // Return data is optional - // solhint-disable-next-line max-line-length - require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed"); - } - } -} - -// File: @openzeppelin/contracts/utils/Address.sol -pragma solidity 0.6.9; - -/** - * @dev Collection of functions related to the address type - */ -library Address { - /** - * @dev Returns true if `account` is a contract. - * - * [IMPORTANT] - * ==== - * It is unsafe to assume that an address for which this function returns - * false is an externally-owned account (EOA) and not a contract. - * - * Among others, `isContract` will return false for the following - * types of addresses: - * - * - an externally-owned account - * - a contract in construction - * - an address where a contract will be created - * - an address where a contract lived, but was destroyed - * ==== - */ - function isContract(address account) internal view returns (bool) { - // According to EIP-1052, 0x0 is the value returned for not-yet created accounts - // and 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470 is returned - // for accounts without code, i.e. `keccak256('')` - bytes32 codehash; - bytes32 accountHash = 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470; - // solhint-disable-next-line no-inline-assembly - assembly { codehash := extcodehash(account) } - return (codehash != accountHash && codehash != 0x0); - } - - /** - * @dev Replacement for Solidity's `transfer`: sends `amount` wei to - * `recipient`, forwarding all available gas and reverting on errors. - * - * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost - * of certain opcodes, possibly making contracts go over the 2300 gas limit - * imposed by `transfer`, making them unable to receive funds via - * `transfer`. {sendValue} removes this limitation. - * - * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more]. - * - * IMPORTANT: because control is transferred to `recipient`, care must be - * taken to not create reentrancy vulnerabilities. Consider using - * {ReentrancyGuard} or the - * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern]. - */ - function sendValue(address payable recipient, uint256 amount) internal { - require(address(this).balance >= amount, "Address: insufficient balance"); - - // solhint-disable-next-line avoid-low-level-calls, avoid-call-value - (bool success, ) = recipient.call{ value: amount }(""); - require(success, "Address: unable to send value, recipient may have reverted"); - } - - /** - * @dev Performs a Solidity function call using a low level `call`. A - * plain`call` is an unsafe replacement for a function call: use this - * function instead. - * - * If `target` reverts with a revert reason, it is bubbled up by this - * function (like regular Solidity function calls). - * - * Returns the raw returned data. To convert to the expected return value, - * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`]. - * - * Requirements: - * - * - `target` must be a contract. - * - calling `target` with `data` must not revert. - * - * _Available since v3.1._ - */ - function functionCall(address target, bytes memory data) internal returns (bytes memory) { - return functionCall(target, data, "Address: low-level call failed"); - } - - /** - * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with - * `errorMessage` as a fallback revert reason when `target` reverts. - * - * _Available since v3.1._ - */ - function functionCall(address target, bytes memory data, string memory errorMessage) internal returns (bytes memory) { - return _functionCallWithValue(target, data, 0, errorMessage); - } - - /** - * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], - * but also transferring `value` wei to `target`. - * - * Requirements: - * - * - the calling contract must have an ETH balance of at least `value`. - * - the called Solidity function must be `payable`. - * - * _Available since v3.1._ - */ - function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) { - return functionCallWithValue(target, data, value, "Address: low-level call with value failed"); - } - - /** - * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but - * with `errorMessage` as a fallback revert reason when `target` reverts. - * - * _Available since v3.1._ - */ - function functionCallWithValue(address target, bytes memory data, uint256 value, string memory errorMessage) internal returns (bytes memory) { - require(address(this).balance >= value, "Address: insufficient balance for call"); - return _functionCallWithValue(target, data, value, errorMessage); - } - - function _functionCallWithValue(address target, bytes memory data, uint256 weiValue, string memory errorMessage) private returns (bytes memory) { - require(isContract(target), "Address: call to non-contract"); - - // solhint-disable-next-line avoid-low-level-calls - (bool success, bytes memory returndata) = target.call{ value: weiValue }(data); - if (success) { - return returndata; - } else { - // Look for revert reason and bubble it up if present - if (returndata.length > 0) { - // The easiest way to bubble the revert reason is using memory via assembly - - // solhint-disable-next-line no-inline-assembly - assembly { - let returndata_size := mload(returndata) - revert(add(32, returndata), returndata_size) - } - } else { - revert(errorMessage); - } - } - } -} - -pragma solidity 0.6.9; - -/** - * @dev Implementation of the {IERC20} interface. - * - * This implementation is agnostic to the way tokens are created. This means - * that a supply mechanism has to be added in a derived contract using {_mint}. - * For a generic mechanism see {ERC20PresetMinterPauser}. - * - * TIP: For a detailed writeup see our guide - * https://forum.zeppelin.solutions/t/how-to-implement-erc20-supply-mechanisms/226[How - * to implement supply mechanisms]. - * - * We have followed general OpenZeppelin guidelines: functions revert instead - * of returning `false` on failure. This behavior is nonetheless conventional - * and does not conflict with the expectations of ERC20 applications. - * - * Additionally, an {Approval} event is emitted on calls to {transferFrom}. - * This allows applications to reconstruct the allowance for all accounts just - * by listening to said events. Other implementations of the EIP may not emit - * these events, as it isn't required by the specification. - * - * Finally, the non-standard {decreaseAllowance} and {increaseAllowance} - * functions have been added to mitigate the well-known issues around setting - * allowances. See {IERC20-approve}. - */ -contract ERC20 is Context, IERC20 { - using SafeMath for uint256; - using Address for address; - - bool cantransfer; - uint256 private _totalSupply; - string private _name; - string private _symbol; - uint8 private _decimals; - - mapping (address => uint256) private _balances; - mapping (address => mapping (address => uint256)) private _allowances; - mapping(address => bool) public operater; - // ============ Modifiers ============ - modifier onlyOperater() { - require(cantransfer || operater[msg.sender] , "not allowed transfer"); - _; - } - - /** - * @dev Sets the values for {name} and {symbol}, initializes {decimals} with - * a default value of 18. - * - * To select a different value for {decimals}, use {_setupDecimals}. - * - * All three of these values are immutable: they can only be set once during - * construction. - */ - constructor (string memory name, string memory symbol) public { - _name = name; - _symbol = symbol; - _decimals = 18; - } - - /** - * @dev Returns the name of the token. - */ - function name() public view returns (string memory) { - return _name; - } - - /** - * @dev Returns the symbol of the token, usually a shorter version of the - * name. - */ - function symbol() public view returns (string memory) { - return _symbol; - } - - /** - * @dev Returns the number of decimals used to get its user representation. - * For example, if `decimals` equals `2`, a balance of `505` tokens should - * be displayed to a user as `5,05` (`505 / 10 ** 2`). - * - * Tokens usually opt for a value of 18, imitating the relationship between - * Ether and Wei. This is the value {ERC20} uses, unless {_setupDecimals} is - * called. - * - * NOTE: This information is only used for _display_ purposes: it in - * no way affects any of the arithmetic of the contract, including - * {IERC20-balanceOf} and {IERC20-transfer}. - */ - function decimals() public view returns (uint8) { - return _decimals; - } - - /** - * @dev See {IERC20-totalSupply}. - */ - function totalSupply() public view override returns (uint256) { - return _totalSupply; - } - - /** - * @dev See {IERC20-balanceOf}. - */ - function balanceOf(address account) public view virtual override returns (uint256) { - return _balances[account]; - } - - /** - * @dev See {IERC20-transfer}. - * - * Requirements: - * - * - `recipient` cannot be the zero address. - * - the caller must have a balance of at least `amount`. - */ - function transfer(address recipient, uint256 amount) public virtual override returns (bool) { - _transfer(_msgSender(), recipient, amount); - return true; - } - - /** - * @dev See {IERC20-allowance}. - */ - function allowance(address owner, address spender) public view virtual override returns (uint256) { - return _allowances[owner][spender]; - } - - /** - * @dev See {IERC20-approve}. - * - * Requirements: - * - * - `spender` cannot be the zero address. - */ - function approve(address spender, uint256 amount) public virtual override returns (bool) { - _approve(_msgSender(), spender, amount); - return true; - } - - /** - * @dev See {IERC20-transferFrom}. - * - * Emits an {Approval} event indicating the updated allowance. This is not - * required by the EIP. See the note at the beginning of {ERC20}; - * - * Requirements: - * - `sender` and `recipient` cannot be the zero address. - * - `sender` must have a balance of at least `amount`. - * - the caller must have allowance for ``sender``'s tokens of at least - * `amount`. - */ - function transferFrom(address sender, address recipient, uint256 amount) public virtual override returns (bool) { - _transfer(sender, recipient, amount); - _approve(sender, _msgSender(), _allowances[sender][_msgSender()].sub(amount)); - return true; - } - - /** - * @dev Atomically increases the allowance granted to `spender` by the caller. - * - * This is an alternative to {approve} that can be used as a mitigation for - * problems described in {IERC20-approve}. - * - * Emits an {Approval} event indicating the updated allowance. - * - * Requirements: - * - * - `spender` cannot be the zero address. - */ - function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) { - _approve(_msgSender(), spender, _allowances[_msgSender()][spender].add(addedValue)); - return true; - } - - /** - * @dev Atomically decreases the allowance granted to `spender` by the caller. - * - * This is an alternative to {approve} that can be used as a mitigation for - * problems described in {IERC20-approve}. - * - * Emits an {Approval} event indicating the updated allowance. - * - * Requirements: - * - * - `spender` cannot be the zero address. - * - `spender` must have allowance for the caller of at least - * `subtractedValue`. - */ - function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) { - _approve(_msgSender(), spender, _allowances[_msgSender()][spender].sub(subtractedValue)); - return true; - } - - /** - * @dev Moves tokens `amount` from `sender` to `recipient`. - * - * This is internal function is equivalent to {transfer}, and can be used to - * e.g. implement automatic token fees, slashing mechanisms, etc. - * - * Emits a {Transfer} event. - * - * Requirements: - * - * - `sender` cannot be the zero address. - * - `recipient` cannot be the zero address. - * - `sender` must have a balance of at least `amount`. - */ - function _transfer(address sender, address recipient, uint256 amount) internal onlyOperater virtual { - require(sender != address(0), "ERC20: transfer from the zero address"); - require(recipient != address(0), "ERC20: transfer to the zero address"); - - _beforeTokenTransfer(sender, recipient, amount); - - _balances[sender] = _balances[sender].sub(amount); - _balances[recipient] = _balances[recipient].add(amount); - emit Transfer(sender, recipient, amount); - } - - /** @dev Creates `amount` tokens and assigns them to `account`, increasing - * the total supply. - * - * Emits a {Transfer} event with `from` set to the zero address. - * - * Requirements - * - * - `to` cannot be the zero address. - */ - function _mint(address account, uint256 amount) internal virtual { - require(account != address(0), "ERC20: mint to the zero address"); - - _beforeTokenTransfer(address(0), account, amount); - - _totalSupply = _totalSupply.add(amount); - _balances[account] = _balances[account].add(amount); - emit Transfer(address(0), account, amount); - } - - /** - * @dev Destroys `amount` tokens from `account`, reducing the - * total supply. - * - * Emits a {Transfer} event with `to` set to the zero address. - * - * Requirements - * - * - `account` cannot be the zero address. - * - `account` must have at least `amount` tokens. - */ - function _burn(address account, uint256 amount) internal virtual { - require(account != address(0), "ERC20: burn from the zero address"); - - _beforeTokenTransfer(account, address(0), amount); - - _balances[account] = _balances[account].sub(amount); - _totalSupply = _totalSupply.sub(amount); - emit Transfer(account, address(0), amount); - } - - /** - * @dev Sets `amount` as the allowance of `spender` over the `owner`s tokens. - * - * This is internal function is equivalent to `approve`, and can be used to - * e.g. set automatic allowances for certain subsystems, etc. - * - * Emits an {Approval} event. - * - * Requirements: - * - * - `owner` cannot be the zero address. - * - `spender` cannot be the zero address. - */ - function _approve(address owner, address spender, uint256 amount) internal onlyOperater virtual { - require(owner != address(0), "ERC20: approve from the zero address"); - require(spender != address(0), "ERC20: approve to the zero address"); - - _allowances[owner][spender] = amount; - emit Approval(owner, spender, amount); - } - - /** - * @dev Sets {decimals} to a value other than the default one of 18. - * - * WARNING: This function should only be called from the constructor. Most - * applications that interact with token contracts will not expect - * {decimals} to ever change, and may work incorrectly if it does. - */ - function _setupDecimals(uint8 decimals_) internal { - _decimals = decimals_; - } - - function _setCantransfer(bool _cantransfer) internal { - cantransfer = _cantransfer; - } - - function _addOperation(address _operater) internal { - operater[_operater] = true; - } - function _removeOperation(address _operater) internal { - operater[_operater] = false; - } - - /** - * @dev Hook that is called before any transfer of tokens. This includes - * minting and burning. - * - * Calling conditions: - * - * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens - * will be to transferred to `to`. - * - when `from` is zero, `amount` tokens will be minted for `to`. - * - when `to` is zero, `amount` of ``from``'s tokens will be burned. - * - `from` and `to` are never both zero. - * - * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks]. - */ - function _beforeTokenTransfer(address from, address to, uint256 amount) internal virtual { } -} -pragma solidity 0.6.9; -interface IGovernance { - function governanceCall(address account, uint256 amount,bytes calldata data) external returns (bool); - -} -pragma solidity 0.6.9; -contract SpToken is ERC20("StakingPowerToken", "SPT"), Ownable ,ReentrancyGuard{ - using SafeMath for uint256; - using SafeERC20 for IERC20; - - address govAddr; - IERC20 dodo; - - uint256 public alpha = 1; - uint256 public totalSp; - uint256 public totalOverdraft; - - uint256 public _DODOPERBLOCK_ = 1e18;//TODO - uint256 constant public _MAG_SP_AMOUNT_ = 10; - uint256 constant public _MAG_TOTALSP_AMOUNT_ = 110; - uint256 constant public _BASE_AMOUNT_ = 100; - - struct UserInfo { - uint256 dodoAmount; - address upline; - uint256 spAmount; - uint256 overdraft; - uint256 lastRewardBlock; - uint256 totalRedeem; - bool hasParticipateGov; //是否正在参与治理,是的话就不可以提币 - } - - mapping (address => UserInfo) public userInfo; - -// ============ Events ============ - event ParticipatoryGov(address indexed user, uint256 amount); - event Deposit(address indexed user,address indexed upline, uint256 amount); - event Redeem(address indexed user, uint256 amount); - event SetCantransfer(bool allowed); - event RemoveOperation(address indexed _operater); - event AddOperation(address indexed _operater); - - receive() external payable { - revert(); - } - // ============ Functions ============ - constructor( - address _govAddr, - address _dodo - - ) public { - govAddr = _govAddr; - dodo = IERC20(_dodo); - } - - - function mint(address _to, uint256 _amount) public onlyOwner { - _mint(_to, _amount); - } - function burn(address _to, uint256 amount) public onlyOwner{ - _burn(_to,amount); - } - function setCantransfer(bool _allowed) public onlyOwner { - _setCantransfer(_allowed); - emit SetCantransfer(_allowed); - } - function addOperationAddress(address _operationAddress) public onlyOwner { - _addOperation(_operationAddress); - emit AddOperation(_operationAddress); - } - function removeOperation(address _operationAddress) public onlyOwner { - _removeOperation(_operationAddress); - emit RemoveOperation(_operationAddress); - } - - function participatoryGov( - uint256 _amount, - bytes calldata _data - ) external preventReentrant { - UserInfo storage user = userInfo[msg.sender]; - require(user.spAmount>_amount,"no enough sp"); - if (_data.length > 0) - IGovernance(govAddr).governanceCall(msg.sender, _amount, _data); - user.spAmount = user.spAmount.sub(_amount); - user.hasParticipateGov = true; - emit ParticipatoryGov(msg.sender, _amount); - } - - //TODO _uplineAddress??? deposit again???? - //TODO round up /down - function deposit(uint256 _amount,address _uplineAddress) public preventReentrant{ - require(_amount>0,"must deposit greater than 0"); - - dodo.transferFrom(msg.sender, address(this), _amount); - - UserInfo storage user = userInfo[msg.sender]; - if(user.dodoAmount==0){ - user.lastRewardBlock = block.number; - } - user.dodoAmount = user.dodoAmount.add(_amount); - // accuDODO = _DODOPERBLOCK_*(block-lastRewardBlock) - uint256 accuDODO = _DODOPERBLOCK_ * (block.number.sub(user.lastRewardBlock)); - //TODO FIRST DEPOSIT??? - if(totalSp > 0){ - // alpha = alpha + accuDODO/totalSp (round down) - alpha = alpha.add(accuDODO.div(totalSp)); - } - - // 自己的sp + x/alpha - uint256 newSpAmount = _amount.div(alpha); - - _mint(msg.sender,newSpAmount); - // spToken.mint(msg.sender,newSpAmount); - - user.spAmount = user.spAmount.add(newSpAmount); - if(user.upline==address(0x0)){ - user.upline = _uplineAddress; - } - UserInfo storage uplineUser = userInfo[user.upline]; - // 上级sp +( x/alpha)* 0.1 (round up) - uplineUser.spAmount = uplineUser.spAmount.add( - _amount.mul(alpha) - .mul(_MAG_SP_AMOUNT_).div(_BASE_AMOUNT_)); - - // 上级DODO欠款 + x*0.1 (round up) - uint256 overdraft = _amount.mul(_MAG_SP_AMOUNT_).div(_BASE_AMOUNT_); - uplineUser.overdraft = uplineUser.overdraft.add(overdraft); - - totalOverdraft = totalOverdraft.add(overdraft); - // total sp + x/alpha*1.1 - totalSp = totalSp.add(_amount.div(alpha).mul(_MAG_TOTALSP_AMOUNT_).div(_BASE_AMOUNT_)); - emit Deposit(msg.sender,_uplineAddress, _amount); - } - //TODO round up /down - - function redeem(uint256 _amount) public preventReentrant{ - UserInfo storage user = userInfo[msg.sender]; - require(user.spAmount>_amount,"no enough sp token"); - require(!user.hasParticipateGov,"hasParticipateGov"); - - - // accuDODO = _DODOPERBLOCK_*(block-lastRewardBlock) - uint256 accuDODO = _DODOPERBLOCK_ * (block.number.sub(user.lastRewardBlock)); - // alpha = alpha + accuDODO/totalSp (round down) - alpha = alpha.add(accuDODO.div(totalSp)); - // 自己的sp - x - _burn(msg.sender,_amount); - // spToken.burn(msg.sender,_amount); - - user.spAmount = user.spAmount.sub(_amount); - - UserInfo storage uplineUser = userInfo[user.upline]; - // 上级sp - (x)*0.1(round down) - uplineUser.spAmount = uplineUser.spAmount.sub( - _amount.mul(_MAG_SP_AMOUNT_).div(_BASE_AMOUNT_)); - - // 上级DODO欠款 - x*alpha*0.1 (round down) - uint256 overdraft = _amount.mul(alpha).mul(_MAG_SP_AMOUNT_).div(_BASE_AMOUNT_); - uplineUser.overdraft = uplineUser.overdraft.sub(overdraft); - - totalOverdraft = totalOverdraft.sub(overdraft); - - // total sp - x*1.1 - totalSp = totalSp.sub(_amount.mul(_MAG_TOTALSP_AMOUNT_).div(_BASE_AMOUNT_)); - - user.lastRewardBlock = block.number; - - uint256 feeRatio = checkReward(_amount); - - // x * 80% transfer to user - uint256 receiveAmount = _amount.mul(_BASE_AMOUNT_.sub(feeRatio).div(_BASE_AMOUNT_)); - - dodo.safeTransferFrom(address(this), msg.sender, receiveAmount); - user.dodoAmount = user.dodoAmount.sub(receiveAmount); - user.totalRedeem = user.totalRedeem.add(receiveAmount); - - // alpha = alpha + x * 20% /totalSp - uint256 feeAmount = _amount.mul(feeRatio.div(_BASE_AMOUNT_)); - alpha = alpha.add(feeAmount.div(totalSp)); - - //TODO 3. 这部分税会继续拆成两部分,第一部分销毁,第二部分分给所有vDODO持有人 - - - emit Redeem(msg.sender, _amount); - } - - //TODO - function checkReward(uint256 _amount) internal returns(uint256) { - - // (x - 1)^2 / 81 + (y - 15)^2 / 100 = 1 (5≤ y ≤ 15) - - // y = 5 (x ≤ 1) - - // y = 15 (x ≥ 10) - } - - // balanceOf = sp-DODO欠款/alpha - function balanceOf(address _address) public view override returns (uint256 balance) { - UserInfo memory user = userInfo[_address]; - balance = user.spAmount.sub(user.overdraft.div(alpha)); - } - - function transfer(address recipient, uint256 amount) public virtual override returns (bool) { - _transfer(_msgSender(), recipient, amount); - return true; - } - - function _transfer(address sender, address recipient, uint256 _amount) internal onlyOperater virtual override { - require(sender != address(0), " transfer from the zero address"); - require(recipient != address(0), " transfer to the zero address"); - // require(balanceOf(from)≥amount) - require(balanceOf(sender) >= _amount,"no enough to sp transfer"); - UserInfo storage user = userInfo[sender]; - // sp[msg.sender] -= amount - user.spAmount = user.spAmount.sub(_amount); - - // sp[上级[from]] -= amount*0.1 (round down) - UserInfo storage uplineUser = userInfo[user.upline]; - uplineUser.spAmount = uplineUser.spAmount.sub(_amount.mul(_MAG_SP_AMOUNT_).div(_BASE_AMOUNT_)); - - UserInfo storage recipientUser = userInfo[recipient]; - // sp[to] += amount - recipientUser.spAmount = recipientUser.spAmount.add(_amount); - - UserInfo storage recipientUplineUser = userInfo[recipientUser.upline]; - recipientUplineUser.spAmount =recipientUplineUser.spAmount.add(_amount.mul(_MAG_SP_AMOUNT_).div(_BASE_AMOUNT_)); - emit Transfer(sender, recipient, _amount); - } - - // 可提取DODO数额 = sp*alpha - DODO欠款 - function canWithDraw(address _address) public view returns (uint256 withDrawAmount) { - UserInfo memory user = userInfo[_address]; - withDrawAmount = user.spAmount.mul(alpha).sub(user.overdraft); - } - - function checkUserInfo(address _userAddress) public view returns(uint256,address,uint256,uint256,uint256,uint256,bool) { - UserInfo memory user = userInfo[_userAddress]; - return (user.dodoAmount, user.upline, user.spAmount, user.overdraft,user.lastRewardBlock,user.totalRedeem,user.hasParticipateGov); - - } - - - -} -// deposit 是否需要输入上级地址 -// round up & round down -//vDODO的分红 -// - 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: {