diff --git a/contracts/DODOPrivatePool/impl/DPPStorage.sol b/contracts/DODOPrivatePool/impl/DPPStorage.sol new file mode 100644 index 0000000..db6f926 --- /dev/null +++ b/contracts/DODOPrivatePool/impl/DPPStorage.sol @@ -0,0 +1,90 @@ +/* + + Copyright 2020 DODO ZOO. + SPDX-License-Identifier: Apache-2.0 + +*/ + +pragma solidity 0.6.9; +pragma experimental ABIEncoderV2; + +import {InitializableOwnable} from "../../lib/InitializableOwnable.sol"; +import {SafeMath} from "../../lib/SafeMath.sol"; +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 {IERC20} from "../../intf/IERC20.sol"; +import {RState} from "../../lib/PMMPricing.sol"; + +/** + * @title Storage + * @author DODO Breeder + * + * @notice Local Variables + */ +contract DPPStorage is InitializableOwnable, ReentrancyGuard { + using SafeMath for uint256; + + // ============ Variables for Control ============ + + IExternalValue public _GAS_PRICE_LIMIT_; + + // ============ Advanced Controls ============ + + bool public _BUYING_CLOSE_; + bool public _SELLING_CLOSE_; + + IPermissionManager public _TRADE_PERMISSION_; + + // ============ Core Address ============ + + address public _MAINTAINER_; // collect maintainer fee + + IERC20 public _BASE_TOKEN_; + IERC20 public _QUOTE_TOKEN_; + + uint256 public _BASE_RESERVE_; + uint256 public _QUOTE_RESERVE_; + uint256 public _BASE_TARGET_; + uint256 public _QUOTE_TARGET_; + RState public _RState_; + + // ============ Variables for Pricing ============ + + IFeeRateModel public _LP_FEE_RATE_MODEL_; + IFeeRateModel public _MT_FEE_RATE_MODEL_; + IExternalValue public _K_; + IExternalValue public _I_; + + // ============ Setting Functions ============ + + function setLpFeeRateModel(address newLpFeeRateModel) external onlyOwner { + _LP_FEE_RATE_MODEL_ = IFeeRateModel(newLpFeeRateModel); + } + + function setMtFeeRateModel(address newMtFeeRateModel) external onlyOwner { + _MT_FEE_RATE_MODEL_ = IFeeRateModel(newMtFeeRateModel); + } + + function setTradePermissionManager(address newTradePermissionManager) external onlyOwner { + _TRADE_PERMISSION_ = IPermissionManager(newTradePermissionManager); + } + + function setMaintainer(address newMaintainer) external onlyOwner { + _MAINTAINER_ = newMaintainer; + } + + function setGasPriceSource(address newGasPriceLimitSource) external onlyOwner { + _GAS_PRICE_LIMIT_ = IExternalValue(newGasPriceLimitSource); + } + + function setBuy(bool open) external onlyOwner { + _BUYING_CLOSE_ = !open; + } + + function setSell(bool open) external onlyOwner { + _SELLING_CLOSE_ = !open; + } +} diff --git a/contracts/DODOPrivatePool/impl/DPPTrader.sol b/contracts/DODOPrivatePool/impl/DPPTrader.sol new file mode 100644 index 0000000..a071273 --- /dev/null +++ b/contracts/DODOPrivatePool/impl/DPPTrader.sol @@ -0,0 +1,162 @@ +/* + + Copyright 2020 DODO ZOO. + SPDX-License-Identifier: Apache-2.0 + +*/ + +pragma solidity 0.6.9; +pragma experimental ABIEncoderV2; + +import {DPPVault} from "./DPPVault.sol"; +import {SafeMath} from "../../lib/SafeMath.sol"; +import {DecimalMath} from "../../lib/DecimalMath.sol"; +import {RState, PMMState, PMMPricing} from "../../lib/PMMPricing.sol"; + +contract DPPTrader is DPPVault { + using SafeMath for uint256; + + // ============ Modifiers ============ + + modifier isBuyAllow(address trader) { + require(!_BUYING_CLOSE_ && _TRADE_PERMISSION_.isAllowed(trader), "TRADER_BUY_NOT_ALLOWED"); + _; + } + + modifier isSellAllow(address trader) { + require( + !_SELLING_CLOSE_ && _TRADE_PERMISSION_.isAllowed(trader), + "TRADER_SELL_NOT_ALLOWED" + ); + _; + } + + modifier limitGasPrice() { + require(tx.gasprice <= _GAS_PRICE_LIMIT_.get(), "GAS_PRICE_EXCEED"); + _; + } + + // ============ Trade Functions ============ + + // todo 看看怎么能加上flash loan + + function sellBase(address to) + external + preventReentrant + limitGasPrice + isSellAllow(to) + returns (uint256 receiveQuoteAmount) + { + uint256 baseInput = getBaseInput(); + uint256 mtFee; + uint256 newBaseTarget; + RState newRState; + (receiveQuoteAmount, mtFee, newRState, newBaseTarget) = querySellBase(tx.origin, baseInput); + + _transferQuoteOut(to, receiveQuoteAmount); + _transferQuoteOut(_MAINTAINER_, mtFee); + + // update TARGET + if (_RState_ != newRState) { + _RState_ = newRState; + _BASE_TARGET_ = newBaseTarget; + } + + _syncReserve(); + + return receiveQuoteAmount; + } + + function sellQuote(address to) + external + preventReentrant + limitGasPrice + isBuyAllow(to) + returns (uint256 receiveBaseAmount) + { + uint256 quoteInput = getQuoteInput(); + uint256 mtFee; + uint256 newQuoteTarget; + RState newRState; + (receiveBaseAmount, mtFee, newRState, newQuoteTarget) = querySellBase( + tx.origin, + quoteInput + ); + + _transferBaseOut(to, receiveBaseAmount); + _transferBaseOut(_MAINTAINER_, mtFee); + + // update TARGET + if (_RState_ != newRState) { + _RState_ = newRState; + _QUOTE_TARGET_ = newQuoteTarget; + } + + _syncReserve(); + + return receiveBaseAmount; + } + + // ============ Query Functions ============ + + function querySellBase(address trader, uint256 payBaseAmount) + public + view + returns ( + uint256 receiveQuoteAmount, + uint256 mtFee, + RState newRState, + uint256 newBaseTarget + ) + { + PMMState memory state = getPMMState(); + (receiveQuoteAmount, newRState) = PMMPricing.sellBaseToken(state, payBaseAmount); + + uint256 lpFeeRate = _LP_FEE_RATE_MODEL_.getFeeRate(trader); + uint256 mtFeeRate = _MT_FEE_RATE_MODEL_.getFeeRate(trader); + mtFee = DecimalMath.mulCeil(receiveQuoteAmount, mtFeeRate); + receiveQuoteAmount = DecimalMath.mulFloor( + receiveQuoteAmount, + DecimalMath.ONE.sub(mtFeeRate).sub(lpFeeRate) + ); + + return (receiveQuoteAmount, mtFee, newRState, state.B0); + } + + function querySellQuote(address trader, uint256 payQuoteAmount) + public + view + returns ( + uint256 receiveBaseAmount, + uint256 mtFee, + RState newRState, + uint256 newQuoteTarget + ) + { + PMMState memory state = getPMMState(); + (receiveBaseAmount, newRState) = PMMPricing.sellQuoteToken(state, payQuoteAmount); + + uint256 lpFeeRate = _LP_FEE_RATE_MODEL_.getFeeRate(trader); + uint256 mtFeeRate = _MT_FEE_RATE_MODEL_.getFeeRate(trader); + mtFee = DecimalMath.mulCeil(receiveBaseAmount, mtFeeRate); + receiveBaseAmount = DecimalMath.mulFloor( + receiveBaseAmount, + DecimalMath.ONE.sub(mtFeeRate).sub(lpFeeRate) + ); + return (receiveBaseAmount, mtFee, newRState, state.Q0); + } + + // ============ Helper Functions ============ + + function getPMMState() public view returns (PMMState memory state) { + state.i = _I_.get(); + state.K = _K_.get(); + state.B = _BASE_RESERVE_; + state.Q = _QUOTE_RESERVE_; + state.B0 = _BASE_TARGET_; + state.Q0 = _QUOTE_TARGET_; + state.R = _RState_; + PMMPricing.adjustedTarget(state); + return state; + } +} diff --git a/contracts/DODOPrivatePool/impl/DPPVault.sol b/contracts/DODOPrivatePool/impl/DPPVault.sol new file mode 100644 index 0000000..070196e --- /dev/null +++ b/contracts/DODOPrivatePool/impl/DPPVault.sol @@ -0,0 +1,110 @@ +/* + + Copyright 2020 DODO ZOO. + SPDX-License-Identifier: Apache-2.0 + +*/ + +pragma solidity 0.6.9; +pragma experimental ABIEncoderV2; + +import {DPPStorage} from "./DPPStorage.sol"; +import {IERC20} from "../../intf/IERC20.sol"; +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"; + +contract DPPVault is DPPStorage { + using SafeMath for uint256; + using SafeERC20 for IERC20; + + // input + + function getInput() public view returns (uint256 baseInput, uint256 quoteInput) { + return ( + _BASE_TOKEN_.balanceOf(address(this)).sub(_BASE_RESERVE_), + _QUOTE_TOKEN_.balanceOf(address(this)).sub(_QUOTE_RESERVE_) + ); + } + + function getBaseInput() public view returns (uint256 input) { + return _BASE_TOKEN_.balanceOf(address(this)).sub(_BASE_RESERVE_); + } + + function getQuoteInput() public view returns (uint256 input) { + return _QUOTE_TOKEN_.balanceOf(address(this)).sub(_QUOTE_RESERVE_); + } + + // ============ Set Status ============ + + function _syncReserve() internal { + _BASE_RESERVE_ = _BASE_TOKEN_.balanceOf(address(this)); + _QUOTE_RESERVE_ = _QUOTE_TOKEN_.balanceOf(address(this)); + } + + function setTarget(uint256 baseTarget, uint256 quoteTarget) public onlyOwner { + _BASE_TARGET_ = baseTarget; + _QUOTE_TARGET_ = quoteTarget; + _checkStatus(); + } + + // todo 这里需要考虑,怎么一个tx同时更新k i 和 fee并reset + function reset() public onlyOwner { + _BASE_TARGET_ = _BASE_TOKEN_.balanceOf(address(this)); + _QUOTE_TARGET_ = _QUOTE_TOKEN_.balanceOf(address(this)); + _BASE_RESERVE_ = _BASE_TARGET_; + _QUOTE_RESERVE_ = _QUOTE_TARGET_; + } + + function _checkStatus() internal view { + require( + !(_BASE_RESERVE_ < _BASE_TARGET_ && _QUOTE_RESERVE_ < _QUOTE_TARGET_), + "STATUS_WRONG" + ); + } + + // ============ Assets Transfer ============ + + 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 _transferBaseOut(address to, uint256 amount) internal { + if (amount > 0) { + _BASE_TOKEN_.safeTransfer(to, amount); + } + } + + function _transferQuoteOut(address to, uint256 amount) internal { + if (amount > 0) { + _QUOTE_TOKEN_.safeTransfer(to, amount); + } + } + + // 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) { + to.transfer(amount); + } else { + IERC20(token).safeTransfer(msg.sender, amount); + } + } +} diff --git a/contracts/DODOVendorMachine/impl/DVM.sol b/contracts/DODOVendorMachine/impl/DVM.sol index 4b437ad..fb4630f 100644 --- a/contracts/DODOVendorMachine/impl/DVM.sol +++ b/contracts/DODOVendorMachine/impl/DVM.sol @@ -10,7 +10,8 @@ pragma experimental ABIEncoderV2; import {IFeeRateModel} from "../../intf/IFeeRateModel.sol"; import {IPermissionManager} from "../../lib/PermissionManager.sol"; -import {IGasPriceSource} from "../../lib/GasPriceSource.sol"; +import {IExternalValue} from "../../lib/ExternalValue.sol"; +import {IERC20} from "../../intf/IERC20.sol"; import {DVMTrader} from "./DVMTrader.sol"; import {DVMFunding} from "./DVMFunding.sol"; import {DVMVault} from "./DVMVault.sol"; @@ -19,7 +20,8 @@ contract DVM is DVMTrader, DVMFunding { function init( address owner, address maintainer, - address vault, + address baseTokenAddress, + address quoteTokenAddress, address lpFeeRateModel, address mtFeeRateModel, address tradePermissionManager, @@ -28,16 +30,32 @@ contract DVM is DVMTrader, DVMFunding { uint256 k ) external { initOwner(owner); - _VAULT_ = DVMVault(vault); - _BASE_TOKEN_ = _VAULT_._BASE_TOKEN_(); - _QUOTE_TOKEN_ = _VAULT_._QUOTE_TOKEN_(); + _BASE_TOKEN_ = IERC20(baseTokenAddress); + _QUOTE_TOKEN_ = IERC20(quoteTokenAddress); _LP_FEE_RATE_MODEL_ = IFeeRateModel(lpFeeRateModel); _MT_FEE_RATE_MODEL_ = IFeeRateModel(mtFeeRateModel); _TRADE_PERMISSION_ = IPermissionManager(tradePermissionManager); - _GAS_PRICE_LIMIT_ = IGasPriceSource(gasPriceSource); + _GAS_PRICE_LIMIT_ = IExternalValue(gasPriceSource); _MAINTAINER_ = maintainer; _I_ = i; _K_ = k; + + string memory connect = "_"; + string memory suffix = "DLP"; + string memory uid = string(abi.encodePacked(address(this))); + name = string( + abi.encodePacked( + suffix, + connect, + _BASE_TOKEN_.symbol(), + connect, + _QUOTE_TOKEN_.symbol(), + connect, + uid + ) + ); + symbol = "DLP"; + decimals = _BASE_TOKEN_.decimals(); } // ============ Version Control ============ diff --git a/contracts/DODOVendorMachine/impl/DVMFunding.sol b/contracts/DODOVendorMachine/impl/DVMFunding.sol index a169ae0..9da7915 100644 --- a/contracts/DODOVendorMachine/impl/DVMFunding.sol +++ b/contracts/DODOVendorMachine/impl/DVMFunding.sol @@ -8,17 +8,17 @@ pragma solidity 0.6.9; pragma experimental ABIEncoderV2; -import {DVMStorage} from "./DVMStorage.sol"; +import {DVMVault} from "./DVMVault.sol"; import {DecimalMath} from "../../lib/DecimalMath.sol"; import {IDODOCallee} from "../../intf/IDODOCallee.sol"; -contract DVMFunding is DVMStorage { +contract DVMFunding is DVMVault { function buyShares(address to) external preventReentrant returns (uint256) { - uint256 baseInput = _VAULT_.getBaseInput(); - uint256 quoteInput = _VAULT_.getQuoteInput(); + uint256 baseInput = getBaseInput(); + uint256 quoteInput = getQuoteInput(); require(baseInput > 0, "NO_BASE_INPUT"); - uint256 baseReserve = _VAULT_._BASE_RESERVE_(); - uint256 quoteReserve = _VAULT_._QUOTE_RESERVE_(); + uint256 baseReserve = _BASE_RESERVE_; // may save gas? 待确认 + uint256 quoteReserve = _QUOTE_RESERVE_; uint256 mintAmount; // case 1. initial supply if (baseReserve == 0 && quoteReserve == 0) { @@ -27,7 +27,7 @@ contract DVMFunding is DVMStorage { // case 2. supply when quote reserve is 0 if (baseReserve > 0 && quoteReserve == 0) { uint256 mintRatio = DecimalMath.divFloor(baseInput, baseReserve); - mintAmount = DecimalMath.mulFloor(_VAULT_.totalSupply(), mintRatio); + mintAmount = DecimalMath.mulFloor(totalSupply, mintRatio); } // case 3. normal case if (baseReserve > 0 && quoteReserve > 0) { @@ -36,15 +36,15 @@ contract DVMFunding is DVMStorage { uint256 mintRatio = baseInputRatio > quoteInputRatio ? quoteInputRatio : baseInputRatio; // 在提币的时候向下取整。因此永远不会出现,balance为0但totalsupply不为0的情况 // 但有可能出现,reserve>0但totalSupply=0的场景 - uint256 totalShare = _VAULT_.totalSupply(); + uint256 totalShare = totalSupply; if (totalShare > 0) { mintAmount = DecimalMath.mulFloor(totalShare, mintRatio); } else { mintAmount = baseInput; } } - _VAULT_.mint(to, mintAmount); - _VAULT_.sync(); + _mint(to, mintAmount); + _sync(); } function sellShares( @@ -52,26 +52,34 @@ contract DVMFunding is DVMStorage { uint256 shareAmount, bytes calldata data ) external preventReentrant returns (uint256) { - require(_VAULT_.balanceOf(msg.sender) >= shareAmount, "SHARES_NOT_ENOUGH"); - (uint256 baseBalance, uint256 quoteBalance) = _VAULT_.getVaultBalance(); - uint256 totalShares = _VAULT_.totalSupply(); - _VAULT_.burn(msg.sender, shareAmount); + require(_SHARES_[msg.sender] >= shareAmount, "SHARES_NOT_ENOUGH"); + (uint256 baseBalance, uint256 quoteBalance) = getVaultBalance(); + uint256 totalShares = totalSupply; + _burn(msg.sender, shareAmount); uint256 baseAmount = baseBalance.mul(shareAmount).div(totalShares); uint256 quoteAmount = quoteBalance.mul(shareAmount).div(totalShares); - _VAULT_.transferBaseOut(to, baseAmount); - _VAULT_.transferQuoteOut(to, quoteAmount); - _VAULT_.sync(); - if (data.length > 0) IDODOCallee(msg.sender).DVMSellShareCall(to, shareAmount, baseAmount, quoteAmount, data); + _transferBaseOut(to, baseAmount); + _transferQuoteOut(to, quoteAmount); + _sync(); + if (data.length > 0) + IDODOCallee(msg.sender).DVMSellShareCall( + to, + shareAmount, + baseAmount, + quoteAmount, + data + ); } - function retrieve(address to) external preventReentrant { - (uint256 baseBalance, uint256 quoteBalance) = _VAULT_.getVaultBalance(); - (uint256 baseReserve, uint256 quoteReserve) = _VAULT_.getVaultReserve(); - if (baseBalance.sub(baseReserve) > 0) { - _VAULT_.transferBaseOut(to, baseBalance.sub(baseReserve)); - } - if (quoteBalance.sub(quoteReserve) > 0) { - _VAULT_.transferQuoteOut(to, quoteBalance.sub(quoteReserve)); - } - } + // 高级功能,需要讨论加不加 + // function retrieve(address to) external preventReentrant { + // (uint256 baseBalance, uint256 quoteBalance) = getVaultBalance(); + // (uint256 baseReserve, uint256 quoteReserve) = getVaultReserve(); + // if (baseBalance.sub(baseReserve) > 0) { + // transferBaseOut(to, baseBalance.sub(baseReserve)); + // } + // if (quoteBalance.sub(quoteReserve) > 0) { + // transferQuoteOut(to, quoteBalance.sub(quoteReserve)); + // } + // } } diff --git a/contracts/DODOVendorMachine/impl/DVMStorage.sol b/contracts/DODOVendorMachine/impl/DVMStorage.sol index ea67c83..b1f1afb 100644 --- a/contracts/DODOVendorMachine/impl/DVMStorage.sol +++ b/contracts/DODOVendorMachine/impl/DVMStorage.sol @@ -14,16 +14,16 @@ import {SafeMath} from "../../lib/SafeMath.sol"; import {DODOMath} from "../../lib/DODOMath.sol"; import {DecimalMath} from "../../lib/DecimalMath.sol"; import {IPermissionManager} from "../../lib/PermissionManager.sol"; -import {IGasPriceSource} from "../../lib/GasPriceSource.sol"; +import {IExternalValue} from "../../lib/ExternalValue.sol"; import {IFeeRateModel} from "../../intf/IFeeRateModel.sol"; -import {IDVMVault} from "../intf/IDVMVault.sol"; +import {IERC20} from "../../intf/IERC20.sol"; contract DVMStorage is InitializableOwnable, ReentrancyGuard { using SafeMath for uint256; // ============ Variables for Control ============ - IGasPriceSource public _GAS_PRICE_LIMIT_; + IExternalValue public _GAS_PRICE_LIMIT_; // ============ Advanced Controls ============ @@ -36,8 +36,21 @@ contract DVMStorage is InitializableOwnable, ReentrancyGuard { address public _MAINTAINER_; // collect maintainer fee - address public _BASE_TOKEN_; - address public _QUOTE_TOKEN_; + IERC20 public _BASE_TOKEN_; + IERC20 public _QUOTE_TOKEN_; + + uint256 public _BASE_RESERVE_; + uint256 public _QUOTE_RESERVE_; + + // ============ Shares ============ + + string public symbol; + uint256 public decimals; + string public name; + + uint256 public totalSupply; + mapping(address => uint256) internal _SHARES_; + mapping(address => mapping(address => uint256)) internal _ALLOWED_; // ============ Variables for Pricing ============ @@ -46,41 +59,6 @@ contract DVMStorage is InitializableOwnable, ReentrancyGuard { uint256 public _K_; uint256 public _I_; - IDVMVault public _VAULT_; - - // ============ Modifiers ============ - - modifier isBuyAllow(address trader) { - require(!_BUYING_CLOSE_ && _TRADE_PERMISSION_.isAllowed(trader), "TRADER_BUY_NOT_ALLOWED"); - _; - } - - modifier isSellAllow(address trader) { - require( - !_SELLING_CLOSE_ && _TRADE_PERMISSION_.isAllowed(trader), - "TRADER_SELL_NOT_ALLOWED" - ); - _; - } - - modifier limitGasPrice() { - require(tx.gasprice <= _GAS_PRICE_LIMIT_.getGasPrice(), "GAS_PRICE_EXCEED"); - _; - } - - // ============ Helper Functions ============ - - function calculateBase0(uint256 baseAmount, uint256 quoteAmount) public view returns (uint256) { - uint256 fairAmount = DecimalMath.divFloor(quoteAmount, _I_); - return DODOMath._SolveQuadraticFunctionForTarget(baseAmount, _K_, fairAmount); - } - - function getBase0() public view returns (uint256) { - (uint256 baseAmount, uint256 quoteAmount) = _VAULT_.getVaultReserve(); - uint256 fairAmount = DecimalMath.divFloor(quoteAmount, _I_); - return DODOMath._SolveQuadraticFunctionForTarget(baseAmount, _K_, fairAmount); - } - // ============ Setting Functions ============ function setLpFeeRateModel(address newLpFeeRateModel) external onlyOwner { @@ -100,7 +78,7 @@ contract DVMStorage is InitializableOwnable, ReentrancyGuard { } function setGasPriceSource(address newGasPriceLimitSource) external onlyOwner { - _GAS_PRICE_LIMIT_ = IGasPriceSource(newGasPriceLimitSource); + _GAS_PRICE_LIMIT_ = IExternalValue(newGasPriceLimitSource); } function setBuy(bool open) external onlyOwner { diff --git a/contracts/DODOVendorMachine/impl/DVMTrader.sol b/contracts/DODOVendorMachine/impl/DVMTrader.sol index cd79126..63f2803 100644 --- a/contracts/DODOVendorMachine/impl/DVMTrader.sol +++ b/contracts/DODOVendorMachine/impl/DVMTrader.sol @@ -8,15 +8,38 @@ pragma solidity 0.6.9; pragma experimental ABIEncoderV2; -import {DVMStorage} from "./DVMStorage.sol"; +import {DVMVault} from "./DVMVault.sol"; import {SafeMath} from "../../lib/SafeMath.sol"; import {DecimalMath} from "../../lib/DecimalMath.sol"; import {DODOMath} from "../../lib/DODOMath.sol"; import {IDODOCallee} from "../../intf/IDODOCallee.sol"; +import {RState, PMMState, PMMPricing} from "../../lib/PMMPricing.sol"; -contract DVMTrader is DVMStorage { +contract DVMTrader is DVMVault { using SafeMath for uint256; + // ============ Modifiers ============ + + modifier isBuyAllow(address trader) { + require(!_BUYING_CLOSE_ && _TRADE_PERMISSION_.isAllowed(trader), "TRADER_BUY_NOT_ALLOWED"); + _; + } + + modifier isSellAllow(address trader) { + require( + !_SELLING_CLOSE_ && _TRADE_PERMISSION_.isAllowed(trader), + "TRADER_SELL_NOT_ALLOWED" + ); + _; + } + + modifier limitGasPrice() { + require(tx.gasprice <= _GAS_PRICE_LIMIT_.get(), "GAS_PRICE_EXCEED"); + _; + } + + // ============ Execute ============ + function sellBase(address to) external preventReentrant @@ -24,14 +47,12 @@ contract DVMTrader is DVMStorage { isSellAllow(to) returns (uint256 receiveQuoteAmount) { - uint256 baseInput = _VAULT_.getBaseInput(); + uint256 baseInput = getBaseInput(); uint256 mtFee; - (receiveQuoteAmount, mtFee) = querySellBase(to, baseInput); - _VAULT_.transferQuoteOut(to, receiveQuoteAmount); - if (mtFee > 0) { - _VAULT_.transferQuoteOut(_MAINTAINER_, mtFee); - } - _VAULT_.sync(); + (receiveQuoteAmount, mtFee) = querySellBase(tx.origin, baseInput); + _transferQuoteOut(to, receiveQuoteAmount); + _transferQuoteOut(_MAINTAINER_, mtFee); + _sync(); return receiveQuoteAmount; } @@ -42,31 +63,31 @@ contract DVMTrader is DVMStorage { isBuyAllow(to) returns (uint256 receiveBaseAmount) { - uint256 quoteInput = _VAULT_.getQuoteInput(); + uint256 quoteInput = getQuoteInput(); uint256 mtFee; - (receiveBaseAmount, mtFee) = querySellQuote(to, quoteInput); - _VAULT_.transferBaseOut(to, receiveBaseAmount); - if (mtFee > 0) { - _VAULT_.transferBaseOut(_MAINTAINER_, mtFee); - } - _VAULT_.sync(); + (receiveBaseAmount, mtFee) = querySellQuote(tx.origin, quoteInput); + _transferBaseOut(to, receiveBaseAmount); + _transferBaseOut(_MAINTAINER_, mtFee); + _sync(); return receiveBaseAmount; } + // 这是一个试验性质的函数 + // 没有走标准库,需要仔细考虑下 function flashLoan( uint256 baseAmount, uint256 quoteAmount, address assetTo, bytes calldata data ) external preventReentrant { - _VAULT_.transferBaseOut(assetTo, baseAmount); - _VAULT_.transferQuoteOut(assetTo, quoteAmount); + _transferBaseOut(assetTo, baseAmount); + _transferQuoteOut(assetTo, quoteAmount); if (data.length > 0) IDODOCallee(assetTo).DVMFlashLoanCall(msg.sender, baseAmount, quoteAmount, data); - (uint256 baseReserve, uint256 quoteReserve) = _VAULT_.getVaultReserve(); - (uint256 baseBalance, uint256 quoteBalance) = _VAULT_.getVaultBalance(); + (uint256 baseReserve, uint256 quoteReserve) = getVaultReserve(); + (uint256 baseBalance, uint256 quoteBalance) = getVaultBalance(); uint256 mtFeeRate = _MT_FEE_RATE_MODEL_.getFeeRate(assetTo); uint256 lpFeeRate = _LP_FEE_RATE_MODEL_.getFeeRate(assetTo); @@ -76,7 +97,7 @@ contract DVMTrader is DVMStorage { DecimalMath.ONE.sub(mtFeeRate).sub(lpFeeRate) ); baseBalance = baseReserve.sub(validBaseOut); - _VAULT_.transferBaseOut(_MAINTAINER_, DecimalMath.mulCeil(validBaseOut, mtFeeRate)); + _transferBaseOut(_MAINTAINER_, DecimalMath.mulCeil(validBaseOut, mtFeeRate)); } if (quoteBalance < quoteReserve) { uint256 validQuoteOut = DecimalMath.divCeil( @@ -84,7 +105,7 @@ contract DVMTrader is DVMStorage { DecimalMath.ONE.sub(mtFeeRate).sub(lpFeeRate) ); quoteBalance = quoteReserve.sub(validQuoteOut); - _VAULT_.transferQuoteOut(_MAINTAINER_, DecimalMath.mulCeil(validQuoteOut, mtFeeRate)); + _transferQuoteOut(_MAINTAINER_, DecimalMath.mulCeil(validQuoteOut, mtFeeRate)); } require( @@ -92,7 +113,7 @@ contract DVMTrader is DVMStorage { "FLASH_LOAN_FAILED" ); - _VAULT_.sync(); + _sync(); } function querySellBase(address trader, uint256 payBaseAmount) @@ -100,17 +121,15 @@ contract DVMTrader is DVMStorage { view returns (uint256 receiveQuoteAmount, uint256 mtFee) { - (uint256 baseReserve, uint256 quoteReserve) = _VAULT_.getVaultReserve(); - uint256 B0 = calculateBase0(baseReserve, quoteReserve); - - uint256 B1 = baseReserve.add(payBaseAmount); - require(B0 >= B1, "DODO_BASE_BALANCE_NOT_ENOUGH"); - uint256 Q = DODOMath._GeneralIntegrate(B0, B1, baseReserve, _I_, _K_); + (receiveQuoteAmount, ) = PMMPricing.sellBaseToken(getPMMState(), payBaseAmount); uint256 lpFeeRate = _LP_FEE_RATE_MODEL_.getFeeRate(trader); uint256 mtFeeRate = _MT_FEE_RATE_MODEL_.getFeeRate(trader); - mtFee = DecimalMath.mulCeil(Q, mtFeeRate); - receiveQuoteAmount = Q.sub(mtFee).sub(DecimalMath.mulCeil(Q, lpFeeRate)); + mtFee = DecimalMath.mulCeil(receiveQuoteAmount, mtFeeRate); + receiveQuoteAmount = DecimalMath.mulFloor( + receiveQuoteAmount, + DecimalMath.ONE.sub(mtFeeRate).sub(lpFeeRate) + ); return (receiveQuoteAmount, mtFee); } @@ -120,78 +139,96 @@ contract DVMTrader is DVMStorage { view returns (uint256 receiveBaseAmount, uint256 mtFee) { - (uint256 baseReserve, uint256 quoteReserve) = _VAULT_.getVaultReserve(); - uint256 B0 = calculateBase0(baseReserve, quoteReserve); + (receiveBaseAmount, ) = PMMPricing.sellQuoteToken(getPMMState(), payQuoteAmount); - uint256 fairAmount = DecimalMath.divFloor(payQuoteAmount, _I_); - uint256 deltaBase = DODOMath._SolveQuadraticFunctionForTrade( - B0, - baseReserve, - fairAmount, - false, - _K_ - ); uint256 lpFeeRate = _LP_FEE_RATE_MODEL_.getFeeRate(trader); uint256 mtFeeRate = _MT_FEE_RATE_MODEL_.getFeeRate(trader); - mtFee = DecimalMath.mulCeil(deltaBase, mtFeeRate); - receiveBaseAmount = deltaBase.sub(mtFee).sub(DecimalMath.mulCeil(deltaBase, lpFeeRate)); - return (receiveBaseAmount, mtFee); - } - - // 这是一个仅供查询的合约,所有交易都是基于先给input,再输出output的 - // 所以想要买10ETH,这个函数可以给你一个大概的成本,你用这个成本输入,最后能否得到10ETH是要看情况的 - function queryBuyBase(address trader, uint256 receiveBaseAmount) - public - view - returns (uint256 payQuoteAmount) - { - uint256 mtFeeRate = _MT_FEE_RATE_MODEL_.getFeeRate(trader); - uint256 lpFeeRate = _LP_FEE_RATE_MODEL_.getFeeRate(trader); - uint256 validReceiveBaseAmount = DecimalMath.divCeil( + mtFee = DecimalMath.mulCeil(receiveBaseAmount, mtFeeRate); + receiveBaseAmount = DecimalMath.mulFloor( receiveBaseAmount, DecimalMath.ONE.sub(mtFeeRate).sub(lpFeeRate) ); - (uint256 baseReserve, uint256 quoteReserve) = _VAULT_.getVaultReserve(); - require(baseReserve > validReceiveBaseAmount, "DODO_BASE_BALANCE_NOT_ENOUGH"); - - uint256 B0 = calculateBase0(baseReserve, quoteReserve); - uint256 B2 = baseReserve.sub(validReceiveBaseAmount); - payQuoteAmount = DODOMath._GeneralIntegrate(B0, baseReserve, B2, _I_, _K_); - return payQuoteAmount; + return (receiveBaseAmount, mtFee); } - function queryBuyQuote(address trader, uint256 receiveQuoteAmount) - public - view - returns (uint256 payBaseAmount) - { - uint256 mtFeeRate = _MT_FEE_RATE_MODEL_.getFeeRate(trader); - uint256 lpFeeRate = _LP_FEE_RATE_MODEL_.getFeeRate(trader); - uint256 validReceiveQuoteAmount = DecimalMath.divCeil( - receiveQuoteAmount, - DecimalMath.ONE.sub(mtFeeRate).sub(lpFeeRate) - ); - (uint256 baseReserve, uint256 quoteReserve) = _VAULT_.getVaultReserve(); - require(quoteReserve > validReceiveQuoteAmount, "DODO_QUOTE_BALANCE_NOT_ENOUGH"); + // // 这是一个仅供查询的合约,所有交易都是基于先给input,再输出output的 + // // 所以想要买10ETH,这个函数可以给你一个大概的成本,你用这个成本输入,最后能否得到10ETH是要看情况的 + // function queryBuyBase(address trader, uint256 receiveBaseAmount) + // public + // view + // returns (uint256 payQuoteAmount) + // { + // uint256 mtFeeRate = _MT_FEE_RATE_MODEL_.getFeeRate(trader); + // uint256 lpFeeRate = _LP_FEE_RATE_MODEL_.getFeeRate(trader); + // uint256 validReceiveBaseAmount = DecimalMath.divCeil( + // receiveBaseAmount, + // DecimalMath.ONE.sub(mtFeeRate).sub(lpFeeRate) + // ); + // (uint256 baseReserve, uint256 quoteReserve) = getVaultReserve(); + // require(baseReserve > validReceiveBaseAmount, "DODO_BASE_BALANCE_NOT_ENOUGH"); - uint256 B0 = calculateBase0(baseReserve, quoteReserve); - uint256 fairAmount = DecimalMath.divFloor(validReceiveQuoteAmount, _I_); - payBaseAmount = DODOMath._SolveQuadraticFunctionForTrade( - B0, - baseReserve, - fairAmount, - true, - _K_ - ); - return payBaseAmount; - } + // uint256 B0 = calculateBase0(baseReserve, quoteReserve); + // uint256 B2 = baseReserve.sub(validReceiveBaseAmount); + // payQuoteAmount = DODOMath._GeneralIntegrate(B0, baseReserve, B2, _I_, _K_); + // return payQuoteAmount; + // } + + // function queryBuyQuote(address trader, uint256 receiveQuoteAmount) + // public + // view + // returns (uint256 payBaseAmount) + // { + // uint256 mtFeeRate = _MT_FEE_RATE_MODEL_.getFeeRate(trader); + // uint256 lpFeeRate = _LP_FEE_RATE_MODEL_.getFeeRate(trader); + // uint256 validReceiveQuoteAmount = DecimalMath.divCeil( + // receiveQuoteAmount, + // DecimalMath.ONE.sub(mtFeeRate).sub(lpFeeRate) + // ); + // (uint256 baseReserve, uint256 quoteReserve) = getVaultReserve(); + // require(quoteReserve > validReceiveQuoteAmount, "DODO_QUOTE_BALANCE_NOT_ENOUGH"); + + // uint256 B0 = calculateBase0(baseReserve, quoteReserve); + // uint256 fairAmount = DecimalMath.divFloor(validReceiveQuoteAmount, _I_); + // payBaseAmount = DODOMath._SolveQuadraticFunctionForTrade( + // B0, + // baseReserve, + // fairAmount, + // true, + // _K_ + // ); + // return payBaseAmount; + // } function getMidPrice() public view returns (uint256 midPrice) { - (uint256 baseReserve, uint256 quoteReserve) = _VAULT_.getVaultReserve(); + (uint256 baseReserve, uint256 quoteReserve) = getVaultReserve(); uint256 B0 = calculateBase0(baseReserve, quoteReserve); uint256 offsetRatio = DecimalMath.ONE.mul(B0).div(baseReserve).mul(B0).div(baseReserve); uint256 offset = DecimalMath.ONE.sub(_K_).add(DecimalMath.mulFloor(offsetRatio, _K_)); return DecimalMath.mulFloor(_I_, offset); } + + // ============ Helper Functions ============ + + function getPMMState() public view returns (PMMState memory state) { + state.i = _I_; + state.K = _K_; + state.B = _BASE_RESERVE_; + state.Q = _QUOTE_RESERVE_; + state.B0 = calculateBase0(state.B, state.Q); + state.Q0 = 0; + state.R = RState.ABOVE_ONE; + return state; + } + + function calculateBase0(uint256 baseAmount, uint256 quoteAmount) public view returns (uint256) { + uint256 fairAmount = DecimalMath.divFloor(quoteAmount, _I_); + return DODOMath._SolveQuadraticFunctionForTarget(baseAmount, _K_, fairAmount); + } + + function getBase0() public view returns (uint256) { + (uint256 baseAmount, uint256 quoteAmount) = getVaultReserve(); + uint256 fairAmount = DecimalMath.divFloor(quoteAmount, _I_); + return DODOMath._SolveQuadraticFunctionForTarget(baseAmount, _K_, fairAmount); + } } diff --git a/contracts/DODOVendorMachine/impl/DVMVault.sol b/contracts/DODOVendorMachine/impl/DVMVault.sol index cc256c8..8a60262 100644 --- a/contracts/DODOVendorMachine/impl/DVMVault.sol +++ b/contracts/DODOVendorMachine/impl/DVMVault.sol @@ -12,27 +12,12 @@ import {IERC20} from "../../intf/IERC20.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 {InitializableOwnable} from "../../lib/InitializableOwnable.sol"; +import {DVMStorage} from "./DVMStorage.sol"; -contract DVMVault is InitializableOwnable { +contract DVMVault is DVMStorage { using SafeMath for uint256; using SafeERC20 for IERC20; - address public _BASE_TOKEN_; - address public _QUOTE_TOKEN_; - - uint256 public _BASE_RESERVE_; - uint256 public _QUOTE_RESERVE_; - - string public symbol; - uint256 public decimals; - string public name; - - uint256 public totalSupply; - mapping(address => uint256) internal _SHARES_; - mapping(address => mapping(address => uint256)) internal _ALLOWED_; - // ============ Events ============ event Transfer(address indexed from, address indexed to, uint256 amount); @@ -43,40 +28,10 @@ contract DVMVault is InitializableOwnable { event Burn(address indexed user, uint256 value); - // init functions - function init( - address owner, - address _baseToken, - address _quoteToken - ) public notInitialized { - initOwner(owner); - string memory connect = "_"; - string memory suffix = "DLP"; - string memory uid = string(abi.encodePacked(address(this))); - name = string( - abi.encodePacked( - suffix, - connect, - IERC20(_baseToken).symbol(), - connect, - IERC20(_quoteToken).symbol(), - connect, - uid - ) - ); - symbol = "DLP"; - decimals = IERC20(_baseToken).decimals(); - _BASE_TOKEN_ = _baseToken; - _QUOTE_TOKEN_ = _quoteToken; - } - // Vault related function getVaultBalance() public view returns (uint256 baseBalance, uint256 quoteBalance) { - return ( - IERC20(_BASE_TOKEN_).balanceOf(address(this)), - IERC20(_QUOTE_TOKEN_).balanceOf(address(this)) - ); + return (_BASE_TOKEN_.balanceOf(address(this)), _QUOTE_TOKEN_.balanceOf(address(this))); } function getVaultReserve() public view returns (uint256 baseReserve, uint256 quoteReserve) { @@ -84,22 +39,22 @@ contract DVMVault is InitializableOwnable { } function getBaseBalance() public view returns (uint256 baseBalance) { - return IERC20(_BASE_TOKEN_).balanceOf(address(this)); + return _BASE_TOKEN_.balanceOf(address(this)); } function getQuoteBalance() public view returns (uint256 quoteBalance) { - return IERC20(_QUOTE_TOKEN_).balanceOf(address(this)); + return _QUOTE_TOKEN_.balanceOf(address(this)); } function getBaseInput() public view returns (uint256 input) { - return IERC20(_BASE_TOKEN_).balanceOf(address(this)).sub(_BASE_RESERVE_); + return _BASE_TOKEN_.balanceOf(address(this)).sub(_BASE_RESERVE_); } function getQuoteInput() public view returns (uint256 input) { - return IERC20(_QUOTE_TOKEN_).balanceOf(address(this)).sub(_QUOTE_RESERVE_); + return _QUOTE_TOKEN_.balanceOf(address(this)).sub(_QUOTE_RESERVE_); } - function sync() public onlyOwner { + function _sync() internal { (uint256 baseBalance, uint256 quoteBalance) = getVaultBalance(); if (baseBalance != _BASE_RESERVE_) { _BASE_RESERVE_ = baseBalance; @@ -109,15 +64,15 @@ contract DVMVault is InitializableOwnable { } } - function transferBaseOut(address to, uint256 amount) public onlyOwner { + function _transferBaseOut(address to, uint256 amount) internal { if (amount > 0) { - IERC20(_BASE_TOKEN_).safeTransfer(to, amount); + _BASE_TOKEN_.safeTransfer(to, amount); } } - function transferQuoteOut(address to, uint256 amount) public onlyOwner { + function _transferQuoteOut(address to, uint256 amount) internal { if (amount > 0) { - IERC20(_QUOTE_TOKEN_).safeTransfer(to, amount); + _QUOTE_TOKEN_.safeTransfer(to, amount); } } @@ -191,14 +146,14 @@ contract DVMVault is InitializableOwnable { return _ALLOWED_[owner][spender]; } - function mint(address user, uint256 value) external onlyOwner { + function _mint(address user, uint256 value) internal { _SHARES_[user] = _SHARES_[user].add(value); totalSupply = totalSupply.add(value); emit Mint(user, value); emit Transfer(address(0), user, value); } - function burn(address user, uint256 value) external onlyOwner { + function _burn(address user, uint256 value) internal { _SHARES_[user] = _SHARES_[user].sub(value); totalSupply = totalSupply.sub(value); emit Burn(user, value); diff --git a/contracts/DODOVendorMachine/intf/IDVM.sol b/contracts/DODOVendorMachine/intf/IDVM.sol index cfca4e0..affbfbd 100644 --- a/contracts/DODOVendorMachine/intf/IDVM.sol +++ b/contracts/DODOVendorMachine/intf/IDVM.sol @@ -12,7 +12,8 @@ interface IDVM { function init( address owner, address maintainer, - address vault, + address baseTokenAddress, + address quoteTokenAddress, address lpFeeRateModel, address mtFeeRateModel, address tradePermissionManager, diff --git a/contracts/DODOVendorMachine/intf/IDVMVault.sol b/contracts/DODOVendorMachine/intf/IDVMVault.sol deleted file mode 100644 index de8a251..0000000 --- a/contracts/DODOVendorMachine/intf/IDVMVault.sol +++ /dev/null @@ -1,71 +0,0 @@ -/* - - Copyright 2020 DODO ZOO. - SPDX-License-Identifier: Apache-2.0 - -*/ - -pragma solidity 0.6.9; -pragma experimental ABIEncoderV2; - -interface IDVMVault { - function init( - address owner, - address _baseToken, - address _quoteToken - ) external; - - function _BASE_TOKEN_() external returns (address); - - function _QUOTE_TOKEN_() external returns (address); - - function _BASE_RESERVE_() external returns (address); - - function _QUOTE_RESERVE_() external returns (address); - - function symbol() external returns (string memory); - - function decimals() external returns (uint256); - - function name() external returns (string memory); - - function totalSupply() external returns (uint256); - - function getVaultBalance() external view returns (uint256 baseBalance, uint256 quoteBalance); - - function getVaultReserve() external view returns (uint256 baseReserve, uint256 quoteReserve); - - function getBaseBalance() external view returns (uint256 baseBalance); - - function getQuoteBalance() external view returns (uint256 quoteBalance); - - function getBaseInput() external view returns (uint256 input); - - function getQuoteInput() external view returns (uint256 input); - - function sync() external; - - function transferBaseOut(address to, uint256 amount) external; - - function transferQuoteOut(address to, uint256 amount) external; - - function transfer(address to, uint256 amount) external returns (bool); - - function balanceOf(address owner) external view returns (uint256 balance); - - function shareRatioOf(address owner) external view returns (uint256 shareRatio); - - function transferFrom( - address from, - address to, - uint256 amount - ) external returns (bool); - - function approve(address spender, uint256 amount) external returns (bool); - - function allowance(address owner, address spender) external view returns (uint256); - - function mint(address user, uint256 value) external; - - function burn(address user, uint256 value) external; -} diff --git a/contracts/Factory/DVMFactory.sol b/contracts/Factory/DVMFactory.sol index a8d4312..5836113 100644 --- a/contracts/Factory/DVMFactory.sol +++ b/contracts/Factory/DVMFactory.sol @@ -12,12 +12,10 @@ import {Ownable} from "../lib/Ownable.sol"; import {ICloneFactory} from "../lib/CloneFactory.sol"; import {IConstFeeRateModel} from "../lib/ConstFeeRateModel.sol"; import {IDVM} from "../DODOVendorMachine/intf/IDVM.sol"; -import {IDVMVault} from "../DODOVendorMachine/intf/IDVMVault.sol"; import {IPermissionManager} from "../lib/PermissionManager.sol"; contract DVMFactory is Ownable { address public _CLONE_FACTORY_; - address public _VAULT_TEMPLATE_; address public _DVM_TEMPLATE_; address public _FEE_RATE_MODEL_TEMPLATE_; address public _PERMISSION_MANAGER_TEMPLATE_; @@ -29,14 +27,12 @@ contract DVMFactory is Ownable { constructor( address cloneFactory, - address vaultTemplate, address dvmTemplate, address feeRateModelTemplate, address permissionManagerTemplate, address defaultGasPriceSource ) public { _CLONE_FACTORY_ = cloneFactory; - _VAULT_TEMPLATE_ = vaultTemplate; _DVM_TEMPLATE_ = dvmTemplate; _FEE_RATE_MODEL_TEMPLATE_ = feeRateModelTemplate; _PERMISSION_MANAGER_TEMPLATE_ = permissionManagerTemplate; @@ -53,13 +49,11 @@ contract DVMFactory is Ownable { ) external returns (address newVendorMachine) { newVendorMachine = ICloneFactory(_CLONE_FACTORY_).clone(_DVM_TEMPLATE_); - address vault = ICloneFactory(_CLONE_FACTORY_).clone(_VAULT_TEMPLATE_); - - IDVMVault(vault).init(newVendorMachine, baseToken, quoteToken); // vault owner is controller IDVM(newVendorMachine).init( msg.sender, msg.sender, - vault, + baseToken, + quoteToken, createConstFeeRateModel(msg.sender, lpFeeRate), createConstFeeRateModel(msg.sender, mtFeeRate), createPermissionManager(msg.sender), diff --git a/contracts/SmartRoute/SmartRoute.sol b/contracts/SmartRoute/SmartRoute.sol index 5e0d958..5bc1ecd 100644 --- a/contracts/SmartRoute/SmartRoute.sol +++ b/contracts/SmartRoute/SmartRoute.sol @@ -25,11 +25,7 @@ contract SmartRoute is Ownable { uint256 baseAmount, uint256 minReceive ) public returns (uint256 receiveAmount) { - IERC20(DVM(DVMAddress)._BASE_TOKEN_()).safeTransferFrom( - msg.sender, - address(DVM(DVMAddress)._VAULT_()), - baseAmount - ); + IERC20(DVM(DVMAddress)._BASE_TOKEN_()).safeTransferFrom(msg.sender, DVMAddress, baseAmount); receiveAmount = DVM(DVMAddress).sellBase(to); require(receiveAmount >= minReceive, "RECEIVE_NOT_ENOUGH"); return receiveAmount; @@ -43,7 +39,7 @@ contract SmartRoute is Ownable { ) public returns (uint256 receiveAmount) { IERC20(DVM(DVMAddress)._QUOTE_TOKEN_()).safeTransferFrom( msg.sender, - address(DVM(DVMAddress)._VAULT_()), + DVMAddress, quoteAmount ); receiveAmount = DVM(DVMAddress).sellQuote(to); @@ -57,10 +53,10 @@ contract SmartRoute is Ownable { uint256 baseAmount, uint256 quoteAmount ) public returns (uint256 shares) { - address vault = address(DVM(DVMAddress)._VAULT_()); + address vault = DVMAddress; uint256 adjustedBaseAmount; uint256 adjustedQuoteAmount; - (uint256 baseReserve, uint256 quoteReserve) = DVM(DVMAddress)._VAULT_().getVaultReserve(); + (uint256 baseReserve, uint256 quoteReserve) = DVM(DVMAddress).getVaultReserve(); if (quoteReserve == 0 && baseReserve == 0) { adjustedBaseAmount = baseAmount; diff --git a/contracts/intf/IDODOCallee.sol b/contracts/intf/IDODOCallee.sol index 5bde65f..2b98585 100644 --- a/contracts/intf/IDODOCallee.sol +++ b/contracts/intf/IDODOCallee.sol @@ -23,4 +23,11 @@ interface IDODOCallee { uint256 quoteAmount, bytes calldata data ) external; + + function DPPWithdrawCall( + address sender, + uint256 baseAmount, + uint256 quoteAmount, + bytes calldata data + ) external; } diff --git a/contracts/lib/DODOMath.sol b/contracts/lib/DODOMath.sol index 6a726ae..be219d8 100644 --- a/contracts/lib/DODOMath.sol +++ b/contracts/lib/DODOMath.sol @@ -34,6 +34,7 @@ library DODOMath { uint256 i, uint256 k ) internal pure returns (uint256) { + require(V0 > 0, "TARGET_IS_ZERO"); uint256 fairAmount = DecimalMath.mul(i, V1.sub(V2)); // i*delta uint256 V0V0V1V2 = DecimalMath.divCeil(V0.mul(V0).div(V1), V2); uint256 penalty = DecimalMath.mul(k, V0V0V1V2); // k(V0^2/V1/V2) @@ -62,6 +63,7 @@ library DODOMath { bool deltaBSig, uint256 k ) internal pure returns (uint256) { + require(Q0 > 0, "TARGET_IS_ZERO"); // calculate -b value and sig // -b = (1-k)Q1-kQ0^2/Q1+i*deltaB uint256 kQ02Q1 = DecimalMath.mul(k, Q0).mul(Q0).div(Q1); // kQ0^2/Q1 diff --git a/contracts/lib/ExternalValue.sol b/contracts/lib/ExternalValue.sol new file mode 100644 index 0000000..d229253 --- /dev/null +++ b/contracts/lib/ExternalValue.sol @@ -0,0 +1,29 @@ +/* + + Copyright 2020 DODO ZOO. + SPDX-License-Identifier: Apache-2.0 + +*/ + +pragma solidity 0.6.9; +pragma experimental ABIEncoderV2; + +import {Ownable} from "./Ownable.sol"; + +interface IExternalValue { + function set(uint256) external; + + function get() external view returns (uint256); +} + +contract ExternalValue is IExternalValue, Ownable { + uint256 public _VALUE_; + + function set(uint256 value) external override { + _VALUE_ = value; + } + + function get() external override view returns (uint256) { + return _VALUE_; + } +} diff --git a/contracts/lib/GasPriceSource.sol b/contracts/lib/GasPriceSource.sol deleted file mode 100644 index d1a71a5..0000000 --- a/contracts/lib/GasPriceSource.sol +++ /dev/null @@ -1,29 +0,0 @@ -/* - - Copyright 2020 DODO ZOO. - SPDX-License-Identifier: Apache-2.0 - -*/ - -pragma solidity 0.6.9; -pragma experimental ABIEncoderV2; - -import {Ownable} from "./Ownable.sol"; - -interface IGasPriceSource { - function setGasPrice(uint256) external; - - function getGasPrice() external view returns (uint256); -} - -contract GasPriceSource is IGasPriceSource, Ownable { - uint256 public _GAS_PRICE_; - - function setGasPrice(uint256 gasPrice) external override { - _GAS_PRICE_ = gasPrice; - } - - function getGasPrice() external override view returns (uint256) { - return _GAS_PRICE_; - } -} diff --git a/contracts/lib/PMMPricing.sol b/contracts/lib/PMMPricing.sol index b2a1f81..69ce049 100644 --- a/contracts/lib/PMMPricing.sol +++ b/contracts/lib/PMMPricing.sol @@ -213,6 +213,7 @@ library PMMPricing { // ============ Helper functions ============ + // todo 我不确定这个函数是不是能改state的状态 function adjustedTarget(PMMState memory state) public pure { if (state.R == RState.BELOW_ONE) { uint256 fairAmount = DecimalMath.mulFloor(state.B.sub(state.B0), state.i);