From 299b67b972a875f324faf07c928c0521209584e1 Mon Sep 17 00:00:00 2001 From: mingda Date: Fri, 23 Oct 2020 17:11:50 +0800 Subject: [PATCH] dvm init commit --- contracts/DODOVenderMachine/DVMFactory.sol | 14 +++ .../DODOVenderMachine/impl/DVMTrader.sol | 109 ++++++++++-------- contracts/DODOVenderMachine/impl/DVMVault.sol | 4 + contracts/SmartRoute/SmartRoute.sol | 83 +++++++++++++ test/Admin.test.ts | 2 +- test/Attacks.test.ts | 2 +- test/DODOEthProxyAsBase.test.ts | 2 +- test/DODOEthProxyAsQuote.test.ts | 2 +- test/DODOZoo.test.ts | 2 +- test/LiquidityProvider.test.ts | 2 +- test/LongTailTokenlMode.test.ts | 2 +- test/Mining.test.ts | 2 +- test/Rebalance.test.ts | 2 +- test/StableCoinMode.test.ts | 2 +- test/TokenLock.test.ts | 2 +- test/Trader.test.ts | 2 +- test/UniswapArbitrageur.test.ts | 2 +- test/utils/{Context.ts => DVMContext.ts} | 6 +- 18 files changed, 179 insertions(+), 63 deletions(-) create mode 100644 contracts/SmartRoute/SmartRoute.sol rename test/utils/{Context.ts => DVMContext.ts} (98%) diff --git a/contracts/DODOVenderMachine/DVMFactory.sol b/contracts/DODOVenderMachine/DVMFactory.sol index 178ca7e..5218a23 100644 --- a/contracts/DODOVenderMachine/DVMFactory.sol +++ b/contracts/DODOVenderMachine/DVMFactory.sol @@ -18,6 +18,19 @@ contract DVMFactory is Ownable { address public _VAULT_TEMPLATE_; address public _CONTROLLER_TEMPLATE_; + // base -> quote -> DVM address list + mapping(address => mapping(address => address[])) _REGISTRY_; + + constructor( + address cloneFactory, + address vaultTemplate, + address controllerTemplate + ) public { + _CLONE_FACTORY_ = cloneFactory; + _VAULT_TEMPLATE_ = vaultTemplate; + _CONTROLLER_TEMPLATE_ = controllerTemplate; + } + function createDODOVenderMachine( address maintainer, address baseToken, @@ -46,6 +59,7 @@ contract DVMFactory is Ownable { ); newVenderMachine = address(controller); + _REGISTRY_[baseToken][quoteToken].push(newVenderMachine); return newVenderMachine; } } diff --git a/contracts/DODOVenderMachine/impl/DVMTrader.sol b/contracts/DODOVenderMachine/impl/DVMTrader.sol index 9a6aea9..6fd4ab0 100644 --- a/contracts/DODOVenderMachine/impl/DVMTrader.sol +++ b/contracts/DODOVenderMachine/impl/DVMTrader.sol @@ -12,58 +12,71 @@ import {DVMStorage} from "./DVMStorage.sol"; import {SafeMath} from "../../lib/SafeMath.sol"; import {DecimalMath} from "../../lib/DecimalMath.sol"; import {DODOMath} from "../../lib/DODOMath.sol"; - + contract DVMTrader is DVMStorage { - using SafeMath for uint256; + using SafeMath for uint256; - function sellBase (address to) external returns(uint256 receiveQuoteAmount){ - uint256 baseInput = _VAULT_.getBaseInput(); - uint256 mtFee; - (receiveQuoteAmount, mtFee) = querySellBase(baseInput); - _VAULT_.transferQuoteOut(to, receiveQuoteAmount); - if (mtFee>0){ - _VAULT_.transferQuoteOut(_MAINTAINER_, mtFee); + function sellBase(address to) external returns (uint256 receiveQuoteAmount) { + uint256 baseInput = _VAULT_.getBaseInput(); + uint256 mtFee; + (receiveQuoteAmount, mtFee) = querySellBase(baseInput); + _VAULT_.transferQuoteOut(to, receiveQuoteAmount); + if (mtFee > 0) { + _VAULT_.transferQuoteOut(_MAINTAINER_, mtFee); + } + _VAULT_.sync(); + _updateBase0(); // 这里需要想想,原则上不需要update B0. 但精度问题,或者用户往合约里充值,可能导致需要updateBase0 + return receiveQuoteAmount; } - _VAULT_.sync(); - _updateBase0(); // 这里需要想想,原则上不需要update B0. 但精度问题,或者用户往合约里充值,可能导致需要updateBase0 - return receiveQuoteAmount; - } - function sellQuote(address to) external returns(uint256 receiveBaseAmount){ - uint256 quoteInput = _VAULT_.getQuoteInput(); - uint256 mtFee; - (receiveBaseAmount, mtFee) = querySellQuote(quoteInput); - _VAULT_.transferBaseOut(to, receiveBaseAmount); - if (mtFee>0){ - _VAULT_.transferBaseOut(_MAINTAINER_, mtFee); + function sellQuote(address to) external returns (uint256 receiveBaseAmount) { + uint256 quoteInput = _VAULT_.getQuoteInput(); + uint256 mtFee; + (receiveBaseAmount, mtFee) = querySellQuote(quoteInput); + _VAULT_.transferBaseOut(to, receiveBaseAmount); + if (mtFee > 0) { + _VAULT_.transferBaseOut(_MAINTAINER_, mtFee); + } + _VAULT_.sync(); + _updateBase0(); + return receiveBaseAmount; } - _VAULT_.sync(); - _updateBase0(); - return receiveBaseAmount; - } - function querySellBase(uint256 payBaseAmount) public view returns(uint256 receiveQuoteAmount, uint256 mtFee){ - uint256 B2 = _VAULT_._BASE_RESERVE_(); - uint256 B1 = B2.add(payBaseAmount); - require(_BASE0_>=B1, "DODO_BASE_BALANCE_NOT_ENOUGH"); - uint256 Q = DODOMath._GeneralIntegrate(_BASE0_, B1, B2, _I_, _K_); - uint256 lpFeeRate = _LP_FEE_RATE_MODEL_.getFeeRate(Q); - uint256 mtFeeRate = _MT_FEE_RATE_MODEL_.getFeeRate(Q); - mtFee = DecimalMath.mulCeil(Q, mtFeeRate); - receiveQuoteAmount = Q.sub(mtFee).sub(DecimalMath.mulCeil(Q, lpFeeRate)); - return (receiveQuoteAmount, mtFee); - } + function querySellBase(uint256 payBaseAmount) + public + view + returns (uint256 receiveQuoteAmount, uint256 mtFee) + { + uint256 B2 = _VAULT_._BASE_RESERVE_(); + uint256 B1 = B2.add(payBaseAmount); + require(_BASE0_ >= B1, "DODO_BASE_BALANCE_NOT_ENOUGH"); + uint256 Q = DODOMath._GeneralIntegrate(_BASE0_, B1, B2, _I_, _K_); + uint256 lpFeeRate = _LP_FEE_RATE_MODEL_.getFeeRate(Q); + uint256 mtFeeRate = _MT_FEE_RATE_MODEL_.getFeeRate(Q); + mtFee = DecimalMath.mulCeil(Q, mtFeeRate); + receiveQuoteAmount = Q.sub(mtFee).sub(DecimalMath.mulCeil(Q, lpFeeRate)); + return (receiveQuoteAmount, mtFee); + } - function querySellQuote(uint256 payQuoteAmount) public view returns(uint256 receiveBaseAmount, uint256 mtFee){ - uint256 B1 = _VAULT_._BASE_RESERVE_(); - uint256 fairAmount = DecimalMath.divFloor(payQuoteAmount, _I_); - uint256 newBaseReserve = DODOMath._SolveQuadraticFunctionForTrade(_BASE0_,B1,fairAmount,false, _K_); - uint256 deltaBase = B1.sub(newBaseReserve); - uint256 lpFeeRate = _LP_FEE_RATE_MODEL_.getFeeRate(payQuoteAmount); - uint256 mtFeeRate = _MT_FEE_RATE_MODEL_.getFeeRate(payQuoteAmount); - mtFee = DecimalMath.mulCeil(deltaBase, mtFeeRate); - receiveBaseAmount = deltaBase.sub(mtFee).sub(DecimalMath.mulCeil(deltaBase, lpFeeRate)); - return (receiveBaseAmount, mtFee); - } - -} \ No newline at end of file + function querySellQuote(uint256 payQuoteAmount) + public + view + returns (uint256 receiveBaseAmount, uint256 mtFee) + { + uint256 B1 = _VAULT_._BASE_RESERVE_(); + uint256 fairAmount = DecimalMath.divFloor(payQuoteAmount, _I_); + uint256 newBaseReserve = DODOMath._SolveQuadraticFunctionForTrade( + _BASE0_, + B1, + fairAmount, + false, + _K_ + ); + uint256 deltaBase = B1.sub(newBaseReserve); + uint256 lpFeeRate = _LP_FEE_RATE_MODEL_.getFeeRate(payQuoteAmount); + uint256 mtFeeRate = _MT_FEE_RATE_MODEL_.getFeeRate(payQuoteAmount); + mtFee = DecimalMath.mulCeil(deltaBase, mtFeeRate); + receiveBaseAmount = deltaBase.sub(mtFee).sub(DecimalMath.mulCeil(deltaBase, lpFeeRate)); + return (receiveBaseAmount, mtFee); + } +} diff --git a/contracts/DODOVenderMachine/impl/DVMVault.sol b/contracts/DODOVenderMachine/impl/DVMVault.sol index 0461d82..2f6c968 100644 --- a/contracts/DODOVenderMachine/impl/DVMVault.sol +++ b/contracts/DODOVenderMachine/impl/DVMVault.sol @@ -77,6 +77,10 @@ contract DVMVault is InitializableOwnable { ); } + function getVaultReserve() public view returns (uint256 baseReserve, uint256 quoteReserve) { + return (_BASE_RESERVE_, _QUOTE_RESERVE_); + } + function getBaseBalance() public view returns (uint256 baseBalance) { return IERC20(_BASE_TOKEN_).balanceOf(address(this)); } diff --git a/contracts/SmartRoute/SmartRoute.sol b/contracts/SmartRoute/SmartRoute.sol new file mode 100644 index 0000000..f4fa579 --- /dev/null +++ b/contracts/SmartRoute/SmartRoute.sol @@ -0,0 +1,83 @@ +/* + + Copyright 2020 DODO ZOO. + SPDX-License-Identifier: Apache-2.0 + +*/ + +pragma solidity 0.6.9; + +import {Ownable} from "../lib/Ownable.sol"; +import {DVMController} from "../DODOVenderMachine/impl/DVMController.sol"; +import {DVMVault} from "../DODOVenderMachine/impl/DVMVault.sol"; +import {IERC20} from "../intf/IERC20.sol"; +import {SafeERC20} from "../lib/SafeERC20.sol"; +import {SafeMath} from "../lib/SafeMath.sol"; +import {DecimalMath} from "../lib/DecimalMath.sol"; + +contract SmartRoute is Ownable { + using SafeMath for uint256; + using SafeERC20 for IERC20; + + function sellBaseOnDVM( + address DVM, + address to, + uint256 baseAmount, + uint256 minReceive + ) public returns (uint256 receiveAmount) { + IERC20(DVMController(DVM)._BASE_TOKEN_()).safeTransferFrom( + msg.sender, + address(DVMController(DVM)._VAULT_()), + baseAmount + ); + receiveAmount = DVMController(DVM).sellBase(to); + require(receiveAmount >= minReceive, "RECEIVE_NOT_ENOUGH"); + return receiveAmount; + } + + function sellQuoteOnDVM( + address DVM, + address to, + uint256 quoteAmount, + uint256 minReceive + ) public returns (uint256 receiveAmount) { + IERC20(DVMController(DVM)._QUOTE_TOKEN_()).safeTransferFrom( + msg.sender, + address(DVMController(DVM)._VAULT_()), + quoteAmount + ); + receiveAmount = DVMController(DVM).sellBase(to); + require(receiveAmount >= minReceive, "RECEIVE_NOT_ENOUGU"); + return receiveAmount; + } + + function depositToDVM( + address DVM, + uint256 baseAmount, + uint256 quoteAmount + ) public returns (uint256 shares) { + uint256 adjustedBaseAmount; + uint256 adjustedQuoteAmount; + (uint256 baseReserve, uint256 quoteReserve) = DVMController(DVM) + ._VAULT_() + .getVaultReserve(); + + if (quoteReserve == 0 && baseReserve == 0) { + adjustedBaseAmount = baseAmount; + adjustedQuoteAmount = quoteAmount; + } + + if (quoteReserve == 0 && baseReserve > 0) { + adjustedBaseAmount = baseAmount; + adjustedQuoteAmount = 0; + } + + if (quoteReserve > 0 && baseReserve > 0) { + uint256 baseIncreaseRatio = DecimalMath.divFloor(baseAmount, baseReserve); + uint256 quoteIncreaseRatio = DecimalMath.divFloor(quoteAmount, quoteReserve); + uint256 increaseRatio = baseIncreaseRatio>quoteIncreaseRatio?quoteIncreaseRatio:baseIncreaseRatio + adjustedBaseAmount = baseAmount; + adjustedQuoteAmount = 0; + } + } +} diff --git a/test/Admin.test.ts b/test/Admin.test.ts index 491f335..4d750ef 100644 --- a/test/Admin.test.ts +++ b/test/Admin.test.ts @@ -7,7 +7,7 @@ import * as assert from 'assert'; -import { DODOContext, getDODOContext } from './utils/Context'; +import { DODOContext, getDODOContext } from './utils/DVMContext'; import { decimalStr } from './utils/Converter'; let lp1: string; diff --git a/test/Attacks.test.ts b/test/Attacks.test.ts index 21552bb..8bb42b5 100644 --- a/test/Attacks.test.ts +++ b/test/Attacks.test.ts @@ -5,7 +5,7 @@ */ -import { DODOContext, getDODOContext } from './utils/Context'; +import { DODOContext, getDODOContext } from './utils/DVMContext'; import { decimalStr, gweiStr } from './utils/Converter'; import BigNumber from "bignumber.js"; import * as assert from "assert" diff --git a/test/DODOEthProxyAsBase.test.ts b/test/DODOEthProxyAsBase.test.ts index 85d674b..06c6a8d 100644 --- a/test/DODOEthProxyAsBase.test.ts +++ b/test/DODOEthProxyAsBase.test.ts @@ -13,7 +13,7 @@ import { DefaultDODOContextInitConfig, DODOContext, getDODOContext, -} from './utils/Context'; +} from './utils/DVMContext'; import * as contracts from './utils/Contracts'; import { decimalStr, MAX_UINT256 } from './utils/Converter'; import { logGas } from './utils/Log'; diff --git a/test/DODOEthProxyAsQuote.test.ts b/test/DODOEthProxyAsQuote.test.ts index 1941803..9345c96 100644 --- a/test/DODOEthProxyAsQuote.test.ts +++ b/test/DODOEthProxyAsQuote.test.ts @@ -13,7 +13,7 @@ import { DefaultDODOContextInitConfig, DODOContext, getDODOContext, -} from './utils/Context'; +} from './utils/DVMContext'; import * as contracts from './utils/Contracts'; import { decimalStr, MAX_UINT256 } from './utils/Converter'; import { logGas } from './utils/Log'; diff --git a/test/DODOZoo.test.ts b/test/DODOZoo.test.ts index eca2bac..f4a5a3a 100644 --- a/test/DODOZoo.test.ts +++ b/test/DODOZoo.test.ts @@ -5,7 +5,7 @@ */ -import { DODOContext, getDODOContext } from './utils/Context'; +import { DODOContext, getDODOContext } from './utils/DVMContext'; import * as assert from "assert" import { newContract, TEST_ERC20_CONTRACT_NAME, getContractWithAddress, DODO_CONTRACT_NAME } from './utils/Contracts'; diff --git a/test/LiquidityProvider.test.ts b/test/LiquidityProvider.test.ts index 6ba239b..fbda240 100644 --- a/test/LiquidityProvider.test.ts +++ b/test/LiquidityProvider.test.ts @@ -7,7 +7,7 @@ import * as assert from 'assert'; -import { DODOContext, getDODOContext } from './utils/Context'; +import { DODOContext, getDODOContext } from './utils/DVMContext'; import { decimalStr } from './utils/Converter'; import { logGas } from './utils/Log'; diff --git a/test/LongTailTokenlMode.test.ts b/test/LongTailTokenlMode.test.ts index 152b6dc..284c95c 100644 --- a/test/LongTailTokenlMode.test.ts +++ b/test/LongTailTokenlMode.test.ts @@ -5,7 +5,7 @@ */ -import { DODOContext, getDODOContext } from './utils/Context'; +import { DODOContext, getDODOContext } from './utils/DVMContext'; import { decimalStr, gweiStr } from './utils/Converter'; import * as assert from "assert" diff --git a/test/Mining.test.ts b/test/Mining.test.ts index 9b04679..70436bb 100644 --- a/test/Mining.test.ts +++ b/test/Mining.test.ts @@ -5,7 +5,7 @@ */ -import { DODOContext, getDODOContext } from './utils/Context'; +import { DODOContext, getDODOContext } from './utils/DVMContext'; import { decimalStr, MAX_UINT256 } from './utils/Converter'; // import * as assert from "assert" import { newContract, DODO_TOKEN_CONTRACT_NAME, DODO_MINE_NAME, TEST_ERC20_CONTRACT_NAME, getContractWithAddress, DODO_MINE_READER_NAME } from './utils/Contracts'; diff --git a/test/Rebalance.test.ts b/test/Rebalance.test.ts index a99b4ce..5d953cf 100644 --- a/test/Rebalance.test.ts +++ b/test/Rebalance.test.ts @@ -8,7 +8,7 @@ import * as assert from 'assert'; import { Contract } from 'web3-eth-contract'; -import { DODOContext, getDODOContext } from './utils/Context'; +import { DODOContext, getDODOContext } from './utils/DVMContext'; import { DODO_REBALANCER_NAME, newContract } from './utils/Contracts'; import { decimalStr } from './utils/Converter'; diff --git a/test/StableCoinMode.test.ts b/test/StableCoinMode.test.ts index 2373ec7..84c5514 100644 --- a/test/StableCoinMode.test.ts +++ b/test/StableCoinMode.test.ts @@ -5,7 +5,7 @@ */ -import { DODOContext, getDODOContext } from './utils/Context'; +import { DODOContext, getDODOContext } from './utils/DVMContext'; import { decimalStr, gweiStr } from './utils/Converter'; import * as assert from "assert" diff --git a/test/TokenLock.test.ts b/test/TokenLock.test.ts index b82e52b..6cd6f05 100644 --- a/test/TokenLock.test.ts +++ b/test/TokenLock.test.ts @@ -5,7 +5,7 @@ */ -import { DODOContext, getDODOContext } from './utils/Context'; +import { DODOContext, getDODOContext } from './utils/DVMContext'; import { decimalStr, MAX_UINT256 } from './utils/Converter'; // import * as assert from "assert" import { newContract, DODO_TOKEN_CONTRACT_NAME, LOCKED_TOKEN_VAULT_CONTRACT_NAME } from './utils/Contracts'; diff --git a/test/Trader.test.ts b/test/Trader.test.ts index 5e04c6e..fecc73c 100644 --- a/test/Trader.test.ts +++ b/test/Trader.test.ts @@ -7,7 +7,7 @@ import * as assert from 'assert'; -import { DODOContext, getDODOContext } from './utils/Context'; +import { DODOContext, getDODOContext } from './utils/DVMContext'; import { decimalStr } from './utils/Converter'; import { logGas } from './utils/Log'; diff --git a/test/UniswapArbitrageur.test.ts b/test/UniswapArbitrageur.test.ts index eae0670..19e2ffe 100644 --- a/test/UniswapArbitrageur.test.ts +++ b/test/UniswapArbitrageur.test.ts @@ -8,7 +8,7 @@ import * as assert from 'assert'; import { Contract } from 'web3-eth-contract'; -import { DODOContext, getDODOContext } from './utils/Context'; +import { DODOContext, getDODOContext } from './utils/DVMContext'; import { newContract, UNISWAP_ARBITRAGEUR_CONTRACT_NAME, diff --git a/test/utils/Context.ts b/test/utils/DVMContext.ts similarity index 98% rename from test/utils/Context.ts rename to test/utils/DVMContext.ts index 2bf61ae..3ee430f 100644 --- a/test/utils/Context.ts +++ b/test/utils/DVMContext.ts @@ -19,10 +19,11 @@ BigNumber.config({ DECIMAL_PLACES: 80, }); -export interface DODOContextInitConfig { +export interface DVMContextInitConfig { lpFeeRate: string; mtFeeRate: string; k: string; + i: string; gasPriceLimit: string; } @@ -43,6 +44,7 @@ export let DefaultDODOContextInitConfig = { lpFeeRate: decimalStr("0.002"), mtFeeRate: decimalStr("0.001"), k: decimalStr("0.1"), + i: decimalStr("100"), gasPriceLimit: gweiStr("100"), }; @@ -61,7 +63,7 @@ export class DODOContext { Maintainer: string; spareAccounts: string[]; - constructor() {} + constructor() { } async init(config: DODOContextInitConfig) { this.EVM = new EVM();