From fcd938b93fa58c43965c8d3ece3f7b243335e1fc Mon Sep 17 00:00:00 2001 From: owen05 Date: Wed, 18 Nov 2020 21:47:06 +0800 Subject: [PATCH 1/4] update universalERC20 code --- contracts/SmartRoute/SmartSwap.sol | 33 +++++++++----- contracts/lib/UniversalERC20.sol | 71 ++++++------------------------ test/Route/Route.test.ts | 10 ++--- truffle-config.js | 19 ++++++++ 4 files changed, 58 insertions(+), 75 deletions(-) diff --git a/contracts/SmartRoute/SmartSwap.sol b/contracts/SmartRoute/SmartSwap.sol index 5d05dc7..2ad9d9d 100644 --- a/contracts/SmartRoute/SmartSwap.sol +++ b/contracts/SmartRoute/SmartSwap.sol @@ -27,6 +27,12 @@ contract SmartSwap is Ownable { IDODOSellHelper public dodoSellHelper; address payable public _WETH_; + + modifier judgeExpired(uint256 deadline) { + require(deadline >= block.timestamp, 'DODO SmartSwap: EXPIRED'); + _; + } + event OrderHistory( IERC20 indexed fromToken, IERC20 indexed toToken, @@ -57,15 +63,16 @@ contract SmartSwap is Ownable { uint256 fromTokenAmount, uint256 minReturnAmount, address[] memory dodoPairs, - uint256[] memory directions - ) public payable returns (uint256 returnAmount) { - require(minReturnAmount > 0, "Min return should be bigger then 0."); - require(dodoPairs.length > 0, "pairs should exists."); + uint256[] memory directions, + uint256 deadline + ) public payable judgeExpired(deadline) returns (uint256 returnAmount) { + require(minReturnAmount > 0, "DODO SmartSwap: Min return should be bigger then 0."); + require(dodoPairs.length > 0, "DODO SmartSwap: pairs should exists."); if (fromToken != ETH_ADDRESS) { - smartApprove.claimTokens(fromToken, msg.sender, address(this), fromTokenAmount); + smartApprove.claimTokens(fromToken, msg.sender, address(this),fromTokenAmount); } else { - require(msg.value == fromTokenAmount, "ETH_AMOUNT_NOT_MATCH"); + require(msg.value == fromTokenAmount, "DODO SmartSwap: ETH_AMOUNT_NOT_MATCH"); IWETH(_WETH_).deposit{value: fromTokenAmount}(); } @@ -97,7 +104,7 @@ contract SmartSwap is Ownable { returnAmount = toToken.universalBalanceOf(address(this)); - require(returnAmount >= minReturnAmount, "Return amount is not enough"); + require(returnAmount >= minReturnAmount, "DODO SmartSwap: Return amount is not enough"); toToken.universalTransfer(msg.sender, returnAmount); emit OrderHistory(fromToken, toToken, msg.sender, fromTokenAmount, returnAmount); } @@ -110,9 +117,11 @@ contract SmartSwap is Ownable { uint256 gasSwap, uint256 fromTokenAmount, uint256 minReturnAmount, - bytes memory callDataConcat - ) public payable returns (uint256 returnAmount) { - require(minReturnAmount > 0, "Min return should be bigger then 0."); + bytes memory callDataConcat, + uint256 deadline + ) public payable judgeExpired(deadline) returns (uint256 returnAmount) { + + require(minReturnAmount > 0, "DODO SmartSwap: Min return should be bigger then 0."); if (fromToken != ETH_ADDRESS) { smartApprove.claimTokens(fromToken, msg.sender, address(this), fromTokenAmount); @@ -123,12 +132,12 @@ contract SmartSwap is Ownable { callDataConcat ); - require(success, "Contract Swap execution Failed"); + require(success, "DODO SmartSwap: Contract Swap execution Failed"); fromToken.universalTransfer(msg.sender, fromToken.universalBalanceOf(address(this))); returnAmount = toToken.universalBalanceOf(address(this)); - require(returnAmount >= minReturnAmount, "Return amount is not enough"); + require(returnAmount >= minReturnAmount, "DODO SmartSwap: Return amount is not enough"); toToken.universalTransfer(msg.sender, returnAmount); emit OrderHistory(fromToken, toToken, msg.sender, fromTokenAmount, returnAmount); emit ExternalRecord(to, msg.sender); diff --git a/contracts/lib/UniversalERC20.sol b/contracts/lib/UniversalERC20.sol index 9557cd8..1d7534a 100644 --- a/contracts/lib/UniversalERC20.sol +++ b/contracts/lib/UniversalERC20.sol @@ -18,48 +18,26 @@ library UniversalERC20 { IERC20 private constant ZERO_ADDRESS = IERC20(0x0000000000000000000000000000000000000000); IERC20 private constant ETH_ADDRESS = IERC20(0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE); - function universalTransfer( - IERC20 token, - address to, - uint256 amount - ) internal { - universalTransfer(token, to, amount, false); + function isETH(IERC20 token) internal pure returns (bool) { + return (token == ZERO_ADDRESS || token == ETH_ADDRESS); } - function universalTransfer( - IERC20 token, - address to, - uint256 amount, - bool mayFail - ) internal returns (bool) { - if (amount == 0) { - return true; - } - if (token == ZERO_ADDRESS || token == ETH_ADDRESS) { - if (mayFail) { - return address(uint160(to)).send(amount); + function universalTransfer(IERC20 token, address payable to, uint256 amount) internal { + if (amount > 0) { + if (isETH(token)) { + to.transfer(amount); } else { - address(uint160(to)).transfer(amount); - return true; + token.safeTransfer(to, amount); } - } else { - token.safeTransfer(to, amount); - return true; } } - function universalApprove( - IERC20 token, - address to, - uint256 amount - ) internal { - if (token != ZERO_ADDRESS && token != ETH_ADDRESS) { - if (amount == 0) { - token.safeApprove(to, 0); - return; - } - + function universalApprove(IERC20 token, address to, uint256 amount) internal { + require(!isETH(token), "ETH Don't need approve"); + if (amount == 0) { + token.safeApprove(to, 0); + } else { uint256 allowance = token.allowance(address(this), to); if (allowance < amount) { if (allowance > 0) { @@ -70,31 +48,8 @@ library UniversalERC20 { } } - function universalTransferFrom( - IERC20 token, - address from, - address to, - uint256 amount - ) internal { - if (amount == 0) { - return; - } - - if (token == ZERO_ADDRESS || token == ETH_ADDRESS) { - require(from == msg.sender && msg.value >= amount, "msg.value is zero"); - if (to != address(this)) { - address(uint160(to)).transfer(amount); - } - if (msg.value > amount) { - msg.sender.transfer(msg.value.sub(amount)); - } - } else { - token.safeTransferFrom(from, to, amount); - } - } - function universalBalanceOf(IERC20 token, address who) internal view returns (uint256) { - if (token == ZERO_ADDRESS || token == ETH_ADDRESS) { + if (isETH(token)) { return who.balance; } else { return token.balanceOf(who); diff --git a/test/Route/Route.test.ts b/test/Route/Route.test.ts index 16463bb..20126db 100644 --- a/test/Route/Route.test.ts +++ b/test/Route/Route.test.ts @@ -105,11 +105,10 @@ async function calcRoute(ctx: DODOContext, fromTokenAmount: string, slippage: nu } } - let toAmount = new BigNumber(swapAmount).multipliedBy(1 - slippage).toFixed(0, BigNumber.ROUND_DOWN) - console.log("minAmount:", toAmount); - // console.log("dodoPairs",dodoPairs); - // console.log("directions",directions); + let toAmount = new BigNumber(swapAmount).multipliedBy(1 - slippage).toFixed(0, BigNumber.ROUND_DOWN) + console.log("minAmount:",toAmount); + let deadline = Math.floor(new Date().getTime()/1000 + 60 * 10); return ctx.SmartSwap.methods.dodoSwap( routes[0].address, @@ -117,7 +116,8 @@ async function calcRoute(ctx: DODOContext, fromTokenAmount: string, slippage: nu fromTokenAmount, toAmount, dodoPairs, - directions + directions, + deadline ) } diff --git a/truffle-config.js b/truffle-config.js index 28d7b65..79f4fb7 100644 --- a/truffle-config.js +++ b/truffle-config.js @@ -51,6 +51,25 @@ module.exports = { gas: 0xfffffffffff, gasPrice: 1, }, + kovan: { + provider: function() { + return new HDWalletProvider(privKey, "https://kovan.infura.io/v3/" + infuraId); + }, + gas: 8000000, + gasPrice: 1000000000, + network_id: 42, + skipDryRun: true + }, + live: { + networkCheckTimeout: 100000, + provider: function() { + return new HDWalletProvider(privKey, "https://mainnet.infura.io/v3/" + infuraId); + }, + gas: 4000000, + gasPrice: 22000000000, + network_id: 1, + skipDryRun: true + }, coverage: { host: "127.0.0.1", port: 6545, From 93c227007680dc9e072cd897dc003edc911aa772 Mon Sep 17 00:00:00 2001 From: owen05 Date: Thu, 19 Nov 2020 16:11:51 +0800 Subject: [PATCH 2/4] ing --- contracts/SmartRoute/SmartSwap.sol | 2 -- package-lock.json | 16 ---------------- 2 files changed, 18 deletions(-) diff --git a/contracts/SmartRoute/SmartSwap.sol b/contracts/SmartRoute/SmartSwap.sol index 2ad9d9d..27d4863 100644 --- a/contracts/SmartRoute/SmartSwap.sol +++ b/contracts/SmartRoute/SmartSwap.sol @@ -8,7 +8,6 @@ pragma solidity 0.6.9; import {Ownable} from "../lib/Ownable.sol"; -import {ExternalCall} from "../lib/ExternalCall.sol"; import {IERC20} from "../intf/IERC20.sol"; import {UniversalERC20} from "../lib/UniversalERC20.sol"; import {SafeMath} from "../lib/SafeMath.sol"; @@ -20,7 +19,6 @@ import {IWETH} from "../intf/IWETH.sol"; contract SmartSwap is Ownable { using SafeMath for uint256; using UniversalERC20 for IERC20; - using ExternalCall for address; IERC20 constant ETH_ADDRESS = IERC20(0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE); ISmartApprove public smartApprove; diff --git a/package-lock.json b/package-lock.json index af6f651..123b1ea 100644 --- a/package-lock.json +++ b/package-lock.json @@ -6121,12 +6121,6 @@ "integrity": "sha1-74y/QI9uSCaGYzRTBcaswLd4cC4=", "dev": true }, - "lodash.isequal": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/lodash.isequal/-/lodash.isequal-4.5.0.tgz", - "integrity": "sha1-QVxEePK8wwEgwizhDtMib30+GOA=", - "dev": true - }, "lodash.toarray": { "version": "4.4.0", "resolved": "https://registry.npmjs.org/lodash.toarray/-/lodash.toarray-4.4.0.tgz", @@ -8916,16 +8910,6 @@ "resolved": "https://registry.npmjs.org/trim-right/-/trim-right-1.0.1.tgz", "integrity": "sha1-yy4SAwZ+DI3h9hQJS5/kVwTqYAM=" }, - "truffle-assertions": { - "version": "0.9.2", - "resolved": "https://registry.npmjs.org/truffle-assertions/-/truffle-assertions-0.9.2.tgz", - "integrity": "sha512-9g2RhaxU2F8DeWhqoGQvL/bV8QVoSnQ6PY+ZPvYRP5eF7+/8LExb4mjLx/FeliLTjc3Tv1SABG05Gu5qQ/ErmA==", - "dev": true, - "requires": { - "assertion-error": "^1.1.0", - "lodash.isequal": "^4.5.0" - } - }, "truffle-hdwallet-provider": { "version": "1.0.17", "resolved": "https://registry.npmjs.org/truffle-hdwallet-provider/-/truffle-hdwallet-provider-1.0.17.tgz", From 857e4fc01ab096a41bc1da8be5c980ec906e360a Mon Sep 17 00:00:00 2001 From: owen05 Date: Fri, 20 Nov 2020 11:05:41 +0800 Subject: [PATCH 3/4] add todo && smartSwap event update --- contracts/DODOPrivatePool/impl/DPPVault.sol | 3 +++ contracts/DODOVendingMachine/impl/DVMFunding.sol | 1 + contracts/DODOVendingMachine/impl/DVMStorage.sol | 1 + contracts/DODOVendingMachine/impl/DVMTrader.sol | 1 + contracts/Factory/DVMFactory.sol | 4 ++++ contracts/SmartRoute/SmartSwap.sol | 7 ++++--- deploy-detail.txt | 8 ++++++++ migrations/2_deploy.js | 5 ++--- truffle-config.js | 10 ++++++---- 9 files changed, 30 insertions(+), 10 deletions(-) diff --git a/contracts/DODOPrivatePool/impl/DPPVault.sol b/contracts/DODOPrivatePool/impl/DPPVault.sol index 6b7a852..ea6ac3f 100644 --- a/contracts/DODOPrivatePool/impl/DPPVault.sol +++ b/contracts/DODOPrivatePool/impl/DPPVault.sol @@ -50,7 +50,9 @@ contract DPPVault is DPPStorage { _checkStatus(); } + //TODO: Route queryfunc 以及 withdraw and reset // todo 这里需要考虑,怎么一个tx同时更新k i 和 fee并reset + //TODO: 修改feerate等 function reset() public onlyOwner { _BASE_TARGET_ = _BASE_TOKEN_.balanceOf(address(this)); _QUOTE_TARGET_ = _QUOTE_TOKEN_.balanceOf(address(this)); @@ -67,6 +69,7 @@ contract DPPVault is DPPStorage { // ============ Assets Transfer ============ + //TODO:确定Amount后,内部调用 function withdraw( address to, uint256 baseAmount, diff --git a/contracts/DODOVendingMachine/impl/DVMFunding.sol b/contracts/DODOVendingMachine/impl/DVMFunding.sol index 79d8406..d185d85 100644 --- a/contracts/DODOVendingMachine/impl/DVMFunding.sol +++ b/contracts/DODOVendingMachine/impl/DVMFunding.sol @@ -31,6 +31,7 @@ contract DVMFunding is DVMVault { } // case 3. normal case if (baseReserve > 0 && quoteReserve > 0) { + //TODO: (Route合约配合实现) uint256 baseInputRatio = DecimalMath.divFloor(baseInput, baseReserve); uint256 quoteInputRatio = DecimalMath.divFloor(quoteInput, quoteReserve); uint256 mintRatio = baseInputRatio > quoteInputRatio ? quoteInputRatio : baseInputRatio; diff --git a/contracts/DODOVendingMachine/impl/DVMStorage.sol b/contracts/DODOVendingMachine/impl/DVMStorage.sol index d938f28..0eddcaf 100644 --- a/contracts/DODOVendingMachine/impl/DVMStorage.sol +++ b/contracts/DODOVendingMachine/impl/DVMStorage.sol @@ -61,6 +61,7 @@ contract DVMStorage is InitializableOwnable, ReentrancyGuard { // ============ Setting Functions ============ + //TODO: owner权限问题论证 function setLpFeeRateModel(address newLpFeeRateModel) external onlyOwner { _LP_FEE_RATE_MODEL_ = IFeeRateModel(newLpFeeRateModel); } diff --git a/contracts/DODOVendingMachine/impl/DVMTrader.sol b/contracts/DODOVendingMachine/impl/DVMTrader.sol index 5885547..627df2c 100644 --- a/contracts/DODOVendingMachine/impl/DVMTrader.sol +++ b/contracts/DODOVendingMachine/impl/DVMTrader.sol @@ -49,6 +49,7 @@ contract DVMTrader is DVMVault { { uint256 baseInput = getBaseInput(); uint256 mtFee; + //TODO:tx.origin 的潜在风险,直接写to (receiveQuoteAmount, mtFee) = querySellBase(tx.origin, baseInput); _transferQuoteOut(to, receiveQuoteAmount); _transferQuoteOut(_MAINTAINER_, mtFee); diff --git a/contracts/Factory/DVMFactory.sol b/contracts/Factory/DVMFactory.sol index 029ea1a..312282e 100644 --- a/contracts/Factory/DVMFactory.sol +++ b/contracts/Factory/DVMFactory.sol @@ -39,6 +39,7 @@ contract DVMFactory is Ownable { _DEFAULT_GAS_PRICE_SOURCE_ = defaultGasPriceSource; } + function createStandardDODOVendingMachine( address baseToken, address quoteToken, @@ -62,6 +63,9 @@ contract DVMFactory is Ownable { k ); + //TODO: Create2 + //TODO: DVM作为Mapping的字段,维护自身属性 + //TODO: 创建者索引,便于my pool查询 _REGISTRY_[baseToken][quoteToken].push(newVendorMachine); return newVendorMachine; } diff --git a/contracts/SmartRoute/SmartSwap.sol b/contracts/SmartRoute/SmartSwap.sol index 27d4863..80b8185 100644 --- a/contracts/SmartRoute/SmartSwap.sol +++ b/contracts/SmartRoute/SmartSwap.sol @@ -36,7 +36,8 @@ contract SmartSwap is Ownable { IERC20 indexed toToken, address indexed sender, uint256 fromAmount, - uint256 returnAmount + uint256 returnAmount, + uint256 timeStamp ); event ExternalRecord(address indexed to, address indexed sender); @@ -104,7 +105,7 @@ contract SmartSwap is Ownable { require(returnAmount >= minReturnAmount, "DODO SmartSwap: Return amount is not enough"); toToken.universalTransfer(msg.sender, returnAmount); - emit OrderHistory(fromToken, toToken, msg.sender, fromTokenAmount, returnAmount); + emit OrderHistory(fromToken, toToken, msg.sender, fromTokenAmount, returnAmount, block.timestamp); } function externalSwap( @@ -137,7 +138,7 @@ contract SmartSwap is Ownable { require(returnAmount >= minReturnAmount, "DODO SmartSwap: Return amount is not enough"); toToken.universalTransfer(msg.sender, returnAmount); - emit OrderHistory(fromToken, toToken, msg.sender, fromTokenAmount, returnAmount); + emit OrderHistory(fromToken, toToken, msg.sender, fromTokenAmount, returnAmount, block.timestamp); emit ExternalRecord(to, msg.sender); } } diff --git a/deploy-detail.txt b/deploy-detail.txt index e69de29..3946e74 100644 --- a/deploy-detail.txt +++ b/deploy-detail.txt @@ -0,0 +1,8 @@ +==================================================== +network type: kovan +Deploy time: 2020/11/20 上午10:58:49 +Deploy type: Smart Route +SmartApprove Address: 0x0E5cf0e4658E371f93a6bDB7E72d6789Aff08666 +DODOSellHelper Address: 0xbdEae617F2616b45DCB69B287D52940a76035Fe3 +SmartSwap Address: 0x767A6FB2f5e908c4E573CaA2bc7f53D468ffd78E +SmartApprovce setSmartSwap tx: 0xc9efe8b60cba3a2d288d487a7e512a3cfcdd017a25a923477323067546fbbec2 diff --git a/migrations/2_deploy.js b/migrations/2_deploy.js index 89350a9..5b4af25 100644 --- a/migrations/2_deploy.js +++ b/migrations/2_deploy.js @@ -21,7 +21,7 @@ module.exports = async (deployer, network, accounts) => { DODOSellHelperAddress = "0xbdEae617F2616b45DCB69B287D52940a76035Fe3"; DODOZooAddress = "0x92230e929a2226b29ed3441ae5524886347c60c8"; WETHAddress = "0x5eca15b12d959dfcf9c71c59f8b467eb8c6efd0b"; - SmartApproveAddress = "0x5627b7DEb3055e1e899003FDca0716b32C382084"; + SmartApproveAddress = ""; } else if (network == "live") { DODOSellHelperAddress = "0x533da777aedce766ceae696bf90f8541a4ba80eb"; DODOZooAddress = "0x3a97247df274a17c59a3bd12735ea3fcdfb49950"; @@ -35,7 +35,7 @@ module.exports = async (deployer, network, accounts) => { if (DEPLOY_ROUTE) { logger.log("Deploy type: Smart Route"); - if (SmartApprove == "") { + if (SmartApproveAddress == "") { await deployer.deploy(SmartApprove); SmartApproveAddress = SmartApprove.address; } @@ -45,7 +45,6 @@ module.exports = async (deployer, network, accounts) => { } logger.log("SmartApprove Address: ", SmartApproveAddress); logger.log("DODOSellHelper Address: ", DODOSellHelperAddress); - await deployer.deploy( SmartSwap, SmartApproveAddress, diff --git a/truffle-config.js b/truffle-config.js index 79f4fb7..fbe8759 100644 --- a/truffle-config.js +++ b/truffle-config.js @@ -18,8 +18,9 @@ * */ -// const HDWalletProvider = require('@truffle/hdwallet-provider'); -// const infuraKey = "fj4jll3k....."; +var HDWalletProvider = require("truffle-hdwallet-provider"); +var privKey = process.env.privKey; +var infuraId = process.env.infuraId; // // const fs = require('fs'); // const mnemonic = fs.readFileSync(".secret").toString().trim(); @@ -52,6 +53,7 @@ module.exports = { gasPrice: 1, }, kovan: { + networkCheckTimeout: 100000, provider: function() { return new HDWalletProvider(privKey, "https://kovan.infura.io/v3/" + infuraId); }, @@ -65,8 +67,8 @@ module.exports = { provider: function() { return new HDWalletProvider(privKey, "https://mainnet.infura.io/v3/" + infuraId); }, - gas: 4000000, - gasPrice: 22000000000, + gas: 3000000, + gasPrice: 60000000000, network_id: 1, skipDryRun: true }, From f2656d6b2adf54b5b5e7f5d17b3af85bfa2b8283 Mon Sep 17 00:00:00 2001 From: owen05 Date: Sun, 22 Nov 2020 18:20:09 +0800 Subject: [PATCH 4/4] DPP factory and init --- contracts/DODOPrivatePool/impl/DPP.sol | 51 ++++++++ contracts/DODOPrivatePool/impl/DPPStorage.sol | 14 +- contracts/DODOPrivatePool/impl/DPPTrader.sol | 14 +- contracts/DODOPrivatePool/impl/DPPVault.sol | 68 ++++++---- contracts/DODOPrivatePool/intf/IDPP.sol | 34 +++++ contracts/DODOVendingMachine/impl/DVM.sol | 8 +- .../DODOVendingMachine/impl/DVMStorage.sol | 10 +- contracts/DODOZoo.sol | 2 +- contracts/Factory/DPPFactory.sol | 122 ++++++++++++++++++ contracts/Factory/DVMFactory.sol | 1 - contracts/SmartRoute/DVMProxy.sol | 18 +++ contracts/SmartRoute/SmartApprove.sol | 4 + contracts/helper/CloneFactory.sol | 33 ----- contracts/intf/IFeeRateModel.sol | 13 -- contracts/intf/ISmartApprove.sol | 1 + contracts/lib/CloneFactory.sol | 17 +++ contracts/lib/ConstFeeRateModel.sol | 12 +- contracts/lib/ExternalValue.sol | 19 ++- contracts/lib/FeeRateModel.sol | 44 +++++++ 19 files changed, 376 insertions(+), 109 deletions(-) create mode 100644 contracts/DODOPrivatePool/impl/DPP.sol create mode 100644 contracts/DODOPrivatePool/intf/IDPP.sol create mode 100644 contracts/Factory/DPPFactory.sol delete mode 100644 contracts/helper/CloneFactory.sol delete mode 100644 contracts/intf/IFeeRateModel.sol create mode 100644 contracts/lib/FeeRateModel.sol diff --git a/contracts/DODOPrivatePool/impl/DPP.sol b/contracts/DODOPrivatePool/impl/DPP.sol new file mode 100644 index 0000000..5d2e65c --- /dev/null +++ b/contracts/DODOPrivatePool/impl/DPP.sol @@ -0,0 +1,51 @@ +/* + + Copyright 2020 DODO ZOO. + SPDX-License-Identifier: Apache-2.0 + +*/ + +pragma solidity 0.6.9; +pragma experimental ABIEncoderV2; + +import {IFeeRateModel} from "../../lib/FeeRateModel.sol"; +import {IPermissionManager} from "../../lib/PermissionManager.sol"; +import {IExternalValue} from "../../lib/ExternalValue.sol"; +import {IERC20} from "../../intf/IERC20.sol"; +import {DPPTrader} from "./DPPTrader.sol"; +import {ISmartApprove} from "../../intf/ISmartApprove.sol"; + +contract DPP is DPPTrader { + + constructor() public { + _FACTORY_ = msg.sender; + } + + function init( + address owner, + address maintainer, + address baseTokenAddress, + address quoteTokenAddress, + address iSmartApprove, + address[] memory configAddresses + ) external { + require(msg.sender == _FACTORY_, 'INIT FORBIDDEN'); + initOwner(owner); + _MAINTAINER_ = maintainer; + _BASE_TOKEN_ = IERC20(baseTokenAddress); + _QUOTE_TOKEN_ = IERC20(quoteTokenAddress); + _DODO_SMART_APPROVE_ = ISmartApprove(iSmartApprove); + _LP_FEE_RATE_MODEL_ = IFeeRateModel(configAddresses[0]); + _MT_FEE_RATE_MODEL_ = IFeeRateModel(configAddresses[1]); + _GAS_PRICE_LIMIT_ = IExternalValue(configAddresses[2]); + _I_ = IExternalValue(configAddresses[3]); + _K_ = IExternalValue(configAddresses[4]); + _TRADE_PERMISSION_ = IPermissionManager(configAddresses[5]); + _resetTargetAndReserve(); + } + + // ============ Version Control ============ + function version() external pure returns (uint256) { + return 100; // 1.0.0 + } +} diff --git a/contracts/DODOPrivatePool/impl/DPPStorage.sol b/contracts/DODOPrivatePool/impl/DPPStorage.sol index 62408dd..7f2c4b3 100644 --- a/contracts/DODOPrivatePool/impl/DPPStorage.sol +++ b/contracts/DODOPrivatePool/impl/DPPStorage.sol @@ -14,7 +14,8 @@ import {DecimalMath} from "../../lib/DecimalMath.sol"; import {ReentrancyGuard} from "../../lib/ReentrancyGuard.sol"; import {IPermissionManager} from "../../lib/PermissionManager.sol"; import {IExternalValue} from "../../lib/ExternalValue.sol"; -import {IFeeRateModel} from "../../intf/IFeeRateModel.sol"; +import {IFeeRateModel} from "../../lib/FeeRateModel.sol"; +import {ISmartApprove} from "../../intf/ISmartApprove.sol"; import {IERC20} from "../../intf/IERC20.sol"; import {PMMPricing} from "../../lib/PMMPricing.sol"; @@ -27,6 +28,9 @@ import {PMMPricing} from "../../lib/PMMPricing.sol"; contract DPPStorage is InitializableOwnable, ReentrancyGuard { using SafeMath for uint256; + address public _FACTORY_; + ISmartApprove public _DODO_SMART_APPROVE_; + // ============ Variables for Control ============ IExternalValue public _GAS_PRICE_LIMIT_; @@ -80,6 +84,14 @@ contract DPPStorage is InitializableOwnable, ReentrancyGuard { _GAS_PRICE_LIMIT_ = IExternalValue(newGasPriceLimitSource); } + function setISource(address newISource) external onlyOwner { + _I_ = IExternalValue(newISource); + } + + function setKSource(address newKSource) external onlyOwner { + _K_ = IExternalValue(newKSource); + } + function setBuy(bool open) external onlyOwner { _BUYING_CLOSE_ = !open; } diff --git a/contracts/DODOPrivatePool/impl/DPPTrader.sol b/contracts/DODOPrivatePool/impl/DPPTrader.sol index b3119c5..c5050dc 100644 --- a/contracts/DODOPrivatePool/impl/DPPTrader.sol +++ b/contracts/DODOPrivatePool/impl/DPPTrader.sol @@ -25,10 +25,7 @@ contract DPPTrader is DPPVault { } modifier isSellAllow(address trader) { - require( - !_SELLING_CLOSE_ && _TRADE_PERMISSION_.isAllowed(trader), - "TRADER_SELL_NOT_ALLOWED" - ); + require(!_SELLING_CLOSE_ && _TRADE_PERMISSION_.isAllowed(trader),"TRADER_SELL_NOT_ALLOWED"); _; } @@ -50,7 +47,8 @@ contract DPPTrader is DPPVault { uint256 mtFee; uint256 newBaseTarget; PMMPricing.RState newRState; - (receiveQuoteAmount, mtFee, newRState, newBaseTarget) = querySellBase(tx.origin, baseInput); + //TODO: confirm + (receiveQuoteAmount, mtFee, newRState, newBaseTarget) = querySellBase(to, baseInput); _transferQuoteOut(to, receiveQuoteAmount); _transferQuoteOut(_MAINTAINER_, mtFee); @@ -76,11 +74,9 @@ contract DPPTrader is DPPVault { uint256 quoteInput = getQuoteInput(); uint256 mtFee; uint256 newQuoteTarget; + PMMPricing.RState newRState; - (receiveBaseAmount, mtFee, newRState, newQuoteTarget) = querySellQuote( - tx.origin, - quoteInput - ); + (receiveBaseAmount, mtFee, newRState, newQuoteTarget) = querySellQuote(to,quoteInput); _transferBaseOut(to, receiveBaseAmount); _transferBaseOut(_MAINTAINER_, mtFee); diff --git a/contracts/DODOPrivatePool/impl/DPPVault.sol b/contracts/DODOPrivatePool/impl/DPPVault.sol index ea6ac3f..bfd802c 100644 --- a/contracts/DODOPrivatePool/impl/DPPVault.sol +++ b/contracts/DODOPrivatePool/impl/DPPVault.sol @@ -20,7 +20,7 @@ contract DPPVault is DPPStorage { using SafeMath for uint256; using SafeERC20 for IERC20; - // input + // ============ Get Input ============ function getInput() public view returns (uint256 baseInput, uint256 quoteInput) { return ( @@ -39,27 +39,41 @@ contract DPPVault is DPPStorage { // ============ Set Status ============ - function _syncReserve() internal { - _BASE_RESERVE_ = _BASE_TOKEN_.balanceOf(address(this)); - _QUOTE_RESERVE_ = _QUOTE_TOKEN_.balanceOf(address(this)); - } - + //TODO:对应前端哪个操作? function setTarget(uint256 baseTarget, uint256 quoteTarget) public onlyOwner { _BASE_TARGET_ = baseTarget; _QUOTE_TARGET_ = quoteTarget; _checkStatus(); } + + function _syncReserve() internal { + _BASE_RESERVE_ = _BASE_TOKEN_.balanceOf(address(this)); + _QUOTE_RESERVE_ = _QUOTE_TOKEN_.balanceOf(address(this)); + } - //TODO: Route queryfunc 以及 withdraw and reset - // todo 这里需要考虑,怎么一个tx同时更新k i 和 fee并reset - //TODO: 修改feerate等 - function reset() public onlyOwner { + function _resetTargetAndReserve() internal { _BASE_TARGET_ = _BASE_TOKEN_.balanceOf(address(this)); _QUOTE_TARGET_ = _QUOTE_TOKEN_.balanceOf(address(this)); _BASE_RESERVE_ = _BASE_TARGET_; _QUOTE_RESERVE_ = _QUOTE_TARGET_; } + function reset( + uint256 newLpFeeRate, + uint256 newMtFeeRate, + uint256 newI, + uint256 newK + ) public { + //TODO: 讨论 + require(msg.sender == _DODO_SMART_APPROVE_.getSmartSwap() || msg.sender == _OWNER_, "RESET FORBIDDEN!"); + require(newK > 0 && newK <= 10**18, "K OUT OF RANGE!"); + _resetTargetAndReserve(); + _LP_FEE_RATE_MODEL_.setFeeRate(newLpFeeRate); + _MT_FEE_RATE_MODEL_.setFeeRate(newMtFeeRate); + _I_.set(newI); + _K_.set(newK); + } + function _checkStatus() internal view { require( !(_BASE_RESERVE_ < _BASE_TARGET_ && _QUOTE_RESERVE_ < _QUOTE_TARGET_), @@ -69,21 +83,21 @@ contract DPPVault is DPPStorage { // ============ Assets Transfer ============ - //TODO:确定Amount后,内部调用 - function withdraw( - address to, - uint256 baseAmount, - uint256 quoteAmount, - bytes calldata data - ) public onlyOwner { - _transferBaseOut(to, baseAmount); - _transferQuoteOut(to, quoteAmount); - _BASE_TARGET_ = _BASE_TARGET_.sub(baseAmount); - _QUOTE_TARGET_ = _QUOTE_TARGET_.sub(quoteAmount); - if (data.length > 0) { - IDODOCallee(to).DPPWithdrawCall(msg.sender, baseAmount, quoteAmount, data); - } - } + // function withdraw( + // address to, + // uint256 baseAmount, + // uint256 quoteAmount, + // bytes calldata data + // ) public onlyOwner { + // _transferBaseOut(to, baseAmount); + // _transferQuoteOut(to, quoteAmount); + // _BASE_TARGET_ = _BASE_TARGET_.sub(baseAmount); + // _QUOTE_TARGET_ = _QUOTE_TARGET_.sub(quoteAmount); + // _syncReserve(); + // if (data.length > 0) { + // IDODOCallee(to).DPPWithdrawCall(msg.sender, baseAmount, quoteAmount, data); + // } + // } function _transferBaseOut(address to, uint256 amount) internal { if (amount > 0) { @@ -97,15 +111,13 @@ contract DPPVault is DPPStorage { } } - // todo 高级功能,需要讨论 - // 如果单独执行这个功能会导致状态失衡 function retrieve( address payable to, address token, uint256 amount ) external onlyOwner { require(to != address(_BASE_TOKEN_) && to != address(_QUOTE_TOKEN_), "USE_WITHDRAW"); - if (token == 0x000000000000000000000000000000000000000E) { + if (token == 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE) { to.transfer(amount); } else { IERC20(token).safeTransfer(msg.sender, amount); diff --git a/contracts/DODOPrivatePool/intf/IDPP.sol b/contracts/DODOPrivatePool/intf/IDPP.sol new file mode 100644 index 0000000..16761be --- /dev/null +++ b/contracts/DODOPrivatePool/intf/IDPP.sol @@ -0,0 +1,34 @@ +/* + + Copyright 2020 DODO ZOO. + SPDX-License-Identifier: Apache-2.0 + +*/ + +pragma solidity 0.6.9; +pragma experimental ABIEncoderV2; + +interface IDPP { + // function init( + // address owner, + // address maintainer, + // address baseTokenAddress, + // address quoteTokenAddress, + // address lpFeeRateModel, + // address mtFeeRateModel, + // address tradePermissionManager, + // address gasPriceSource, + // address iSource, + // address kSource, + // address iSmartApprove + // ) external; + + function init( + address owner, + address maintainer, + address baseTokenAddress, + address quoteTokenAddress, + address iSmartApprove, + address[] memory configAddresses + ) external; +} diff --git a/contracts/DODOVendingMachine/impl/DVM.sol b/contracts/DODOVendingMachine/impl/DVM.sol index fb4630f..5f95151 100644 --- a/contracts/DODOVendingMachine/impl/DVM.sol +++ b/contracts/DODOVendingMachine/impl/DVM.sol @@ -7,8 +7,8 @@ pragma solidity 0.6.9; pragma experimental ABIEncoderV2; - -import {IFeeRateModel} from "../../intf/IFeeRateModel.sol"; +//TODO:讨论 是否应使用FeeRateModel +import {IConstFeeRateModel} from "../../lib/ConstFeeRateModel.sol"; import {IPermissionManager} from "../../lib/PermissionManager.sol"; import {IExternalValue} from "../../lib/ExternalValue.sol"; import {IERC20} from "../../intf/IERC20.sol"; @@ -32,8 +32,8 @@ contract DVM is DVMTrader, DVMFunding { initOwner(owner); _BASE_TOKEN_ = IERC20(baseTokenAddress); _QUOTE_TOKEN_ = IERC20(quoteTokenAddress); - _LP_FEE_RATE_MODEL_ = IFeeRateModel(lpFeeRateModel); - _MT_FEE_RATE_MODEL_ = IFeeRateModel(mtFeeRateModel); + _LP_FEE_RATE_MODEL_ = IConstFeeRateModel(lpFeeRateModel); + _MT_FEE_RATE_MODEL_ = IConstFeeRateModel(mtFeeRateModel); _TRADE_PERMISSION_ = IPermissionManager(tradePermissionManager); _GAS_PRICE_LIMIT_ = IExternalValue(gasPriceSource); _MAINTAINER_ = maintainer; diff --git a/contracts/DODOVendingMachine/impl/DVMStorage.sol b/contracts/DODOVendingMachine/impl/DVMStorage.sol index 0eddcaf..1993db7 100644 --- a/contracts/DODOVendingMachine/impl/DVMStorage.sol +++ b/contracts/DODOVendingMachine/impl/DVMStorage.sol @@ -15,7 +15,7 @@ import {DODOMath} from "../../lib/DODOMath.sol"; import {DecimalMath} from "../../lib/DecimalMath.sol"; import {IPermissionManager} from "../../lib/PermissionManager.sol"; import {IExternalValue} from "../../lib/ExternalValue.sol"; -import {IFeeRateModel} from "../../intf/IFeeRateModel.sol"; +import {IConstFeeRateModel} from "../../lib/ConstFeeRateModel.sol"; import {IERC20} from "../../intf/IERC20.sol"; contract DVMStorage is InitializableOwnable, ReentrancyGuard { @@ -54,8 +54,8 @@ contract DVMStorage is InitializableOwnable, ReentrancyGuard { // ============ Variables for Pricing ============ - IFeeRateModel public _LP_FEE_RATE_MODEL_; - IFeeRateModel public _MT_FEE_RATE_MODEL_; + IConstFeeRateModel public _LP_FEE_RATE_MODEL_; + IConstFeeRateModel public _MT_FEE_RATE_MODEL_; uint256 public _K_; uint256 public _I_; @@ -63,11 +63,11 @@ contract DVMStorage is InitializableOwnable, ReentrancyGuard { //TODO: owner权限问题论证 function setLpFeeRateModel(address newLpFeeRateModel) external onlyOwner { - _LP_FEE_RATE_MODEL_ = IFeeRateModel(newLpFeeRateModel); + _LP_FEE_RATE_MODEL_ = IConstFeeRateModel(newLpFeeRateModel); } function setMtFeeRateModel(address newMtFeeRateModel) external onlyOwner { - _MT_FEE_RATE_MODEL_ = IFeeRateModel(newMtFeeRateModel); + _MT_FEE_RATE_MODEL_ = IConstFeeRateModel(newMtFeeRateModel); } function setTradePermissionManager(address newTradePermissionManager) external onlyOwner { diff --git a/contracts/DODOZoo.sol b/contracts/DODOZoo.sol index c47cc10..d536cef 100644 --- a/contracts/DODOZoo.sol +++ b/contracts/DODOZoo.sol @@ -10,7 +10,7 @@ pragma experimental ABIEncoderV2; import {Ownable} from "./lib/Ownable.sol"; import {IDODO} from "./intf/IDODO.sol"; -import {ICloneFactory} from "./helper/CloneFactory.sol"; +import {ICloneFactory} from "./lib/CloneFactory.sol"; /** diff --git a/contracts/Factory/DPPFactory.sol b/contracts/Factory/DPPFactory.sol new file mode 100644 index 0000000..f88a4d1 --- /dev/null +++ b/contracts/Factory/DPPFactory.sol @@ -0,0 +1,122 @@ +/* + + Copyright 2020 DODO ZOO. + SPDX-License-Identifier: Apache-2.0 + +*/ + +pragma solidity 0.6.9; +pragma experimental ABIEncoderV2; + +import {Ownable} from "../lib/Ownable.sol"; +import {ICloneFactory} from "../lib/CloneFactory.sol"; +import {IFeeRateModel} from "../lib/FeeRateModel.sol"; +import {IExternalValue} from "../lib/ExternalValue.sol"; +import {IDPP} from "../DODOPrivatePool/intf/IDPP.sol"; +import {IPermissionManager} from "../lib/PermissionManager.sol"; + +contract DPPFactory is Ownable { + address public _CLONE_FACTORY_; + address public _DODO_SMART_APPROVE_; + address public _DPP_TEMPLATE_; + address public _FEE_RATE_MODEL_TEMPLATE_; + address public _PERMISSION_MANAGER_TEMPLATE_; + address public _VALUE_SOURCE_; + + struct DPPInfo{ + address creator; + uint256 createTimeStamp; + //TODO:other tags + } + + // base -> quote -> DPP address list + mapping(address => mapping(address => address[])) _REGISTRY_; + // token0 -> token1 -> DPP address list + mapping(address => mapping(address => address[])) _SORT_REGISTRY_; + // creator -> DPP address list + mapping(address => address[]) _USER_REGISTRY_; + // DPP address -> info + mapping(address => DPPInfo) _DPP_INFO_; + + constructor( + address cloneFactory, + address dodoSmartApprove, + address dppTemplate, + address defautFeeRateModelTemplate, + address defaultPermissionManagerTemplate, + address defaultExternalValueTemplate + ) public { + _CLONE_FACTORY_ = cloneFactory; + _DODO_SMART_APPROVE_ = dodoSmartApprove; + _DPP_TEMPLATE_ = dppTemplate; + _FEE_RATE_MODEL_TEMPLATE_ = defautFeeRateModelTemplate; + _PERMISSION_MANAGER_TEMPLATE_ = defaultPermissionManagerTemplate; + _VALUE_SOURCE_ = defaultExternalValueTemplate; + } + + function createStandardDODOPrivatePool( + address baseToken, + address quoteToken, + address[] memory valueTemplates, //feeeRateAddr,mtRateAddr,gasPriceAddr,kAddr,iAddr + uint256[] memory values // feeRate,mtRate,gasPrice,k,i + ) external returns (address newPrivatePool) { + require(valueTemplates.length == 5 && values.length == 5, "Incorrect number of initialization parameters"); + + (address token0, address token1) = baseToken < quoteToken ? (baseToken, quoteToken) : (quoteToken, baseToken); + uint256 len = _SORT_REGISTRY_[token0][token1].length; + bytes32 salt = keccak256(abi.encodePacked(token0, token1, len)); + newPrivatePool = ICloneFactory(_CLONE_FACTORY_).clone2(_DPP_TEMPLATE_,salt); + + address[] memory configAddresses = new address[](6); + configAddresses[0] = (valueTemplates[0] == address(0) ? createFeeRateModel(newPrivatePool, values[0]) : valueTemplates[0]); + configAddresses[1] = (valueTemplates[1] == address(0) ? createFeeRateModel(newPrivatePool, values[1]) : valueTemplates[1]); + configAddresses[2] = (valueTemplates[2] == address(0) ? createExternalValueModel(newPrivatePool, values[2]) : valueTemplates[2]); + configAddresses[3] = (valueTemplates[3] == address(0) ? createExternalValueModel(newPrivatePool, values[3]) : valueTemplates[3]); + configAddresses[4] = (valueTemplates[4] == address(0) ? createExternalValueModel(newPrivatePool, values[4]) : valueTemplates[4]); + configAddresses[5] = createPermissionManager(msg.sender); + + IDPP(newPrivatePool).init( + msg.sender, + msg.sender, + baseToken, + quoteToken, + _DODO_SMART_APPROVE_, + configAddresses + ); + + _REGISTRY_[baseToken][quoteToken].push(newPrivatePool); + _SORT_REGISTRY_[token0][token1].push(newPrivatePool); + _USER_REGISTRY_[msg.sender].push(newPrivatePool); + _DPP_INFO_[newPrivatePool] = ( + DPPInfo({ + creator: msg.sender, + createTimeStamp: block.timestamp + }) + ); + return newPrivatePool; + } + + function createFeeRateModel(address owner, uint256 feeRate) + public + returns (address feeRateModel) + { + feeRateModel = ICloneFactory(_CLONE_FACTORY_).clone(_FEE_RATE_MODEL_TEMPLATE_); + IFeeRateModel(feeRateModel).init(owner, feeRate); + return feeRateModel; + } + + function createPermissionManager(address owner) public returns (address permissionManager) { + permissionManager = ICloneFactory(_CLONE_FACTORY_).clone(_PERMISSION_MANAGER_TEMPLATE_); + IPermissionManager(permissionManager).initOwner(owner); + return permissionManager; + } + + function createExternalValueModel(address owner, uint256 value) + public + returns (address valueModel) + { + valueModel = ICloneFactory(_CLONE_FACTORY_).clone(_VALUE_SOURCE_); + IExternalValue(valueModel).init(owner, value); + return valueModel; + } +} diff --git a/contracts/Factory/DVMFactory.sol b/contracts/Factory/DVMFactory.sol index 312282e..df99dea 100644 --- a/contracts/Factory/DVMFactory.sol +++ b/contracts/Factory/DVMFactory.sol @@ -39,7 +39,6 @@ contract DVMFactory is Ownable { _DEFAULT_GAS_PRICE_SOURCE_ = defaultGasPriceSource; } - function createStandardDODOVendingMachine( address baseToken, address quoteToken, diff --git a/contracts/SmartRoute/DVMProxy.sol b/contracts/SmartRoute/DVMProxy.sol index 78ff714..4aaf56a 100644 --- a/contracts/SmartRoute/DVMProxy.sol +++ b/contracts/SmartRoute/DVMProxy.sol @@ -17,6 +17,24 @@ contract DVMProxy { using SafeMath for uint256; using SafeERC20 for IERC20; + //TODO: dodoSwap + + //TODO: externalSwap + + //TODO: createDVM + + //TODO: addLiquidityToDVM + + //TODO: removeLiquidityToDVM + + //TODO: createDPP + + //TODO: resetDPP + + //TODO: addLiquidityToClassical + + //TODO: removeLiquidityToClassical + function sellBaseOnDVM( address DVMAddress, address to, diff --git a/contracts/SmartRoute/SmartApprove.sol b/contracts/SmartRoute/SmartApprove.sol index 0fcc38b..a894b94 100644 --- a/contracts/SmartRoute/SmartApprove.sol +++ b/contracts/SmartRoute/SmartApprove.sol @@ -19,6 +19,10 @@ contract SmartApprove is Ownable { smartSwap = _smartSwap; } + function getSmartSwap() public view returns (address) { + return smartSwap; + } + function claimTokens( IERC20 token, address who, diff --git a/contracts/helper/CloneFactory.sol b/contracts/helper/CloneFactory.sol deleted file mode 100644 index fd8f755..0000000 --- a/contracts/helper/CloneFactory.sol +++ /dev/null @@ -1,33 +0,0 @@ -/* - - Copyright 2020 DODO ZOO. - SPDX-License-Identifier: Apache-2.0 - -*/ - -pragma solidity 0.6.9; -pragma experimental ABIEncoderV2; - -interface ICloneFactory { - function clone(address prototype) external returns (address proxy); -} - -// introduction of proxy mode design: https://docs.openzeppelin.com/upgrades/2.8/ -// minimum implementation of transparent proxy: https://eips.ethereum.org/EIPS/eip-1167 - -contract CloneFactory is ICloneFactory { - function clone(address prototype) external override returns (address proxy) { - bytes20 targetBytes = bytes20(prototype); - assembly { - let clone := mload(0x40) - mstore(clone, 0x3d602d80600a3d3981f3363d3d373d3d3d363d73000000000000000000000000) - mstore(add(clone, 0x14), targetBytes) - mstore( - add(clone, 0x28), - 0x5af43d82803e903d91602b57fd5bf30000000000000000000000000000000000 - ) - proxy := create(0, clone, 0x37) - } - return proxy; - } -} diff --git a/contracts/intf/IFeeRateModel.sol b/contracts/intf/IFeeRateModel.sol deleted file mode 100644 index 076c316..0000000 --- a/contracts/intf/IFeeRateModel.sol +++ /dev/null @@ -1,13 +0,0 @@ -/* - - Copyright 2020 DODO ZOO. - SPDX-License-Identifier: Apache-2.0 - -*/ - -pragma solidity 0.6.9; -pragma experimental ABIEncoderV2; - -interface IFeeRateModel { - function getFeeRate(address trader) external view returns (uint256); -} diff --git a/contracts/intf/ISmartApprove.sol b/contracts/intf/ISmartApprove.sol index 6ee509f..24631d7 100644 --- a/contracts/intf/ISmartApprove.sol +++ b/contracts/intf/ISmartApprove.sol @@ -12,4 +12,5 @@ import {IERC20} from "./IERC20.sol"; interface ISmartApprove { function claimTokens(IERC20 token,address who,address dest,uint256 amount) external; + function getSmartSwap() external view returns (address); } \ No newline at end of file diff --git a/contracts/lib/CloneFactory.sol b/contracts/lib/CloneFactory.sol index fd8f755..8837a5e 100644 --- a/contracts/lib/CloneFactory.sol +++ b/contracts/lib/CloneFactory.sol @@ -10,6 +10,7 @@ pragma experimental ABIEncoderV2; interface ICloneFactory { function clone(address prototype) external returns (address proxy); + function clone2(address prototype,bytes32 salt) external returns (address proxy); } // introduction of proxy mode design: https://docs.openzeppelin.com/upgrades/2.8/ @@ -30,4 +31,20 @@ contract CloneFactory is ICloneFactory { } return proxy; } + + + function clone2(address prototype, bytes32 salt) external override returns (address proxy) { + bytes20 targetBytes = bytes20(prototype); + assembly { + let clone := mload(0x40) + mstore(clone, 0x3d602d80600a3d3981f3363d3d373d3d3d363d73000000000000000000000000) + mstore(add(clone, 0x14), targetBytes) + mstore( + add(clone, 0x28), + 0x5af43d82803e903d91602b57fd5bf30000000000000000000000000000000000 + ) + proxy := create2(0, clone, 0x37, salt) + } + return proxy; + } } diff --git a/contracts/lib/ConstFeeRateModel.sol b/contracts/lib/ConstFeeRateModel.sol index 36d36ca..f5744bd 100644 --- a/contracts/lib/ConstFeeRateModel.sol +++ b/contracts/lib/ConstFeeRateModel.sol @@ -8,17 +8,15 @@ pragma solidity 0.6.9; pragma experimental ABIEncoderV2; -import {IFeeRateModel} from "../intf/IFeeRateModel.sol"; -import {Ownable} from "../lib/Ownable.sol"; import {InitializableOwnable} from "../lib/InitializableOwnable.sol"; -interface IConstFeeRateModel is IFeeRateModel { +interface IConstFeeRateModel { function init(address owner, uint256 feeRate) external; - function setFeeRate(uint256 newFeeRate) external; + function getFeeRate(address trader) external view returns (uint256); } -contract ConstFeeRateModel is InitializableOwnable, IFeeRateModel { +contract ConstFeeRateModel is InitializableOwnable { uint256 public _FEE_RATE_; function init(address owner, uint256 feeRate) external { @@ -26,11 +24,11 @@ contract ConstFeeRateModel is InitializableOwnable, IFeeRateModel { _FEE_RATE_ = feeRate; } - function setFeeRate(uint256 newFeeRate) external { + function setFeeRate(uint256 newFeeRate) external onlyOwner { _FEE_RATE_ = newFeeRate; } - function getFeeRate(address) external override view returns (uint256) { + function getFeeRate(address trader) external view returns (uint256) { return _FEE_RATE_; } } diff --git a/contracts/lib/ExternalValue.sol b/contracts/lib/ExternalValue.sol index 641dcf4..ae381fd 100644 --- a/contracts/lib/ExternalValue.sol +++ b/contracts/lib/ExternalValue.sol @@ -8,23 +8,28 @@ pragma solidity 0.6.9; pragma experimental ABIEncoderV2; -import {Ownable} from "./Ownable.sol"; -import {InitializableOwnable} from "./InitializableOwnable.sol"; +import {InitializableOwnable} from "../lib/InitializableOwnable.sol"; interface IExternalValue { - function set(uint256) external; - + function init(address owner, uint256 value) external; + function set(uint256 value) external; function get() external view returns (uint256); } -contract ExternalValue is IExternalValue, InitializableOwnable { + +contract ExternalValue is InitializableOwnable { uint256 public _VALUE_; - function set(uint256 value) external override onlyOwner { + function init(address owner, uint256 value) external { + initOwner(owner); _VALUE_ = value; } - function get() external override view returns (uint256) { + function set(uint256 value) external onlyOwner { + _VALUE_ = value; + } + + function get() external view returns (uint256) { return _VALUE_; } } diff --git a/contracts/lib/FeeRateModel.sol b/contracts/lib/FeeRateModel.sol new file mode 100644 index 0000000..5529b21 --- /dev/null +++ b/contracts/lib/FeeRateModel.sol @@ -0,0 +1,44 @@ +/* + + Copyright 2020 DODO ZOO. + SPDX-License-Identifier: Apache-2.0 + +*/ + +pragma solidity 0.6.9; +pragma experimental ABIEncoderV2; + +import {InitializableOwnable} from "../lib/InitializableOwnable.sol"; + +interface IFeeRateModel { + function getFeeRate(address trader) external view returns (uint256); + function init(address owner, uint256 feeRate) external; + function setFeeRate(uint256 newFeeRate) external; +} + +contract FeeRateModel is InitializableOwnable { + //DEFAULT + uint256 public _FEE_RATE_; + mapping(address => uint256) feeMapping; + + function init(address owner, uint256 feeRate) external { + initOwner(owner); + _FEE_RATE_ = feeRate; + } + + function setSpecificFeeRate(address trader, uint256 feeRate) external onlyOwner { + require(trader != address(0), "INVALID ADDRESS!"); + feeMapping[trader] = feeRate; + } + + function setFeeRate(uint256 newFeeRate) external onlyOwner { + _FEE_RATE_ = newFeeRate; + } + + function getFeeRate(address trader) external view returns (uint256) { + uint256 feeRate = feeMapping[trader]; + if(feeRate == 0) + return _FEE_RATE_; + return feeRate; + } +}