diff --git a/contracts/DODOPrivatePool/impl/DPPOracle/DPPOracle.sol b/contracts/DODOPrivatePool/impl/DPPOracle/DPPOracle.sol index 086e9dd..f2019af 100644 --- a/contracts/DODOPrivatePool/impl/DPPOracle/DPPOracle.sol +++ b/contracts/DODOPrivatePool/impl/DPPOracle/DPPOracle.sol @@ -20,6 +20,10 @@ import {DPPTrader} from "./DPPTrader.sol"; */ contract DPPOracle is DPPTrader { + event EnableOracle(); + event DisableOracle(uint256 newI); + event ChangeOracle(address indexed oracle); + function init( address owner, address maintainer, @@ -28,8 +32,10 @@ contract DPPOracle is DPPTrader { uint256 lpFeeRate, address mtFeeRateModel, uint256 k, - address i, - bool isOpenTWAP + uint256 i, + address o, + bool isOpenTWAP, + bool isOracleEnabled ) external { initOwner(owner); @@ -42,21 +48,42 @@ contract DPPOracle is DPPTrader { require(lpFeeRate <= 1e18, "LP_FEE_RATE_OUT_OF_RANGE"); require(k <= 1e18, "K_OUT_OF_RANGE"); - require(i != address(0), "INVALID_ORACLE"); + require(i > 0 && i <= 1e36, "I_OUT_OF_RANGE"); + require(o != address(0), "INVALID_ORACLE"); _LP_FEE_RATE_ = uint64(lpFeeRate); _K_ = uint64(k); - _I_ = i; + _I_ = uint128(i); + _O_ = o; _IS_OPEN_TWAP_ = isOpenTWAP; + _IS_ORACLE_ENABLED = isOracleEnabled; if(isOpenTWAP) _BLOCK_TIMESTAMP_LAST_ = uint32(block.timestamp % 2**32); _resetTargetAndReserve(); } + function changeOracle(address newOracle) public preventReentrant onlyOwner { + require(newOracle != address(0), "INVALID_ORACLE"); + _O_ = newOracle; + emit ChangeOracle(newOracle); + } + + function enableOracle() public preventReentrant onlyOwner { + _IS_ORACLE_ENABLED = true; + emit EnableOracle(); + } + + function disableOracle(uint256 newI) public preventReentrant onlyOwner { + require(newI > 0 && newI <= 1e36, "I_OUT_OF_RANGE"); + _I_ = uint128(newI); + _IS_ORACLE_ENABLED = false; + emit DisableOracle(newI); + } function tuneParameters( uint256 newLpFeeRate, + uint256 newI, uint256 newK, uint256 minBaseReserve, uint256 minQuoteReserve @@ -67,18 +94,34 @@ contract DPPOracle is DPPTrader { ); require(newLpFeeRate <= 1e18, "LP_FEE_RATE_OUT_OF_RANGE"); require(newK <= 1e18, "K_OUT_OF_RANGE"); + require(newI > 0 && newI <= 1e36, "I_OUT_OF_RANGE"); _LP_FEE_RATE_ = uint64(newLpFeeRate); _K_ = uint64(newK); + _I_ = uint128(newI); emit LpFeeRateChange(newLpFeeRate); return true; } + function tunePrice( + uint256 newI, + uint256 minBaseReserve, + uint256 minQuoteReserve + ) public preventReentrant onlyOwner returns (bool) { + require( + _BASE_RESERVE_ >= minBaseReserve && _QUOTE_RESERVE_ >= minQuoteReserve, + "RESERVE_AMOUNT_IS_NOT_ENOUGH" + ); + require(newI > 0 && newI <= 1e36, "I_OUT_OF_RANGE"); + _I_ = uint128(newI); + return true; + } + // ============ Version Control ============ function version() external pure returns (string memory) { - return "DPP Oracle 1.0.0"; + return "DPP Oracle 1.1.0"; } } diff --git a/contracts/DODOPrivatePool/impl/DPPOracle/DPPOracleAdmin.sol b/contracts/DODOPrivatePool/impl/DPPOracle/DPPOracleAdmin.sol deleted file mode 100644 index 94042d9..0000000 --- a/contracts/DODOPrivatePool/impl/DPPOracle/DPPOracleAdmin.sol +++ /dev/null @@ -1,120 +0,0 @@ -/* - - Copyright 2021 DODO ZOO. - SPDX-License-Identifier: Apache-2.0 - -*/ - -pragma solidity 0.6.9; -pragma experimental ABIEncoderV2; - -import {IDPPOracle} from "../../intf/IDPPOracle.sol"; -import {IDODOApproveProxy} from "../../../SmartRoute/DODOApproveProxy.sol"; -import {InitializableOwnable} from "../../../lib/InitializableOwnable.sol"; - -/** - * @title DPPOracleAdmin - * @author DODO Breeder - * - * @notice Admin of Oracle DODOPrivatePool - */ -contract DPPOracleAdmin is InitializableOwnable { - address public _DPP_; - address public _OPERATOR_; - address public _DODO_APPROVE_PROXY_; - uint256 public _FREEZE_TIMESTAMP_; - - - modifier notFreezed() { - require(block.timestamp >= _FREEZE_TIMESTAMP_, "ADMIN_FREEZED"); - _; - } - - function init( - address owner, - address dpp, - address operator, - address dodoApproveProxy - ) external { - initOwner(owner); - _DPP_ = dpp; - _OPERATOR_ = operator; - _DODO_APPROVE_PROXY_ = dodoApproveProxy; - } - - function sync() external notFreezed onlyOwner { - IDPPOracle(_DPP_).ratioSync(); - } - - function setFreezeTimestamp(uint256 timestamp) external notFreezed onlyOwner { - _FREEZE_TIMESTAMP_ = timestamp; - } - - function setOperator(address newOperator) external notFreezed onlyOwner { - _OPERATOR_ = newOperator; - } - - function retrieve( - address payable to, - address token, - uint256 amount - ) external notFreezed onlyOwner { - IDPPOracle(_DPP_).retrieve(to, token, amount); - } - - function tuneParameters( - address operator, - uint256 newLpFeeRate, - uint256 newK, - uint256 minBaseReserve, - uint256 minQuoteReserve - ) external notFreezed returns (bool) { - require( - msg.sender == _OWNER_ || - (IDODOApproveProxy(_DODO_APPROVE_PROXY_).isAllowedProxy(msg.sender) && - operator == _OPERATOR_), - "TUNEPARAMS FORBIDDEN!" - ); - return - IDPPOracle(_DPP_).tuneParameters( - newLpFeeRate, - newK, - minBaseReserve, - minQuoteReserve - ); - } - - - function reset( - address operator, - uint256 newLpFeeRate, - uint256 newK, - uint256 baseOutAmount, - uint256 quoteOutAmount, - uint256 minBaseReserve, - uint256 minQuoteReserve - ) external notFreezed returns (bool) { - require( - msg.sender == _OWNER_ || - (IDODOApproveProxy(_DODO_APPROVE_PROXY_).isAllowedProxy(msg.sender) && - operator == _OPERATOR_), - "RESET FORBIDDEN!" - ); - return - IDPPOracle(_DPP_).reset( - _OWNER_, //only support asset transfer out to owner - newLpFeeRate, - newK, - baseOutAmount, - quoteOutAmount, - minBaseReserve, - minQuoteReserve - ); - } - - // ============ Admin Version Control ============ - - function version() external pure returns (string memory) { - return "DPPOracle Admin 1.0.0"; // 1.0.0 - } -} diff --git a/contracts/DODOPrivatePool/impl/DPPOracle/DPPStorage.sol b/contracts/DODOPrivatePool/impl/DPPOracle/DPPStorage.sol index 3396579..a04c57d 100644 --- a/contracts/DODOPrivatePool/impl/DPPOracle/DPPStorage.sol +++ b/contracts/DODOPrivatePool/impl/DPPOracle/DPPStorage.sol @@ -21,6 +21,7 @@ contract DPPStorage is InitializableOwnable, ReentrancyGuard { using SafeMath for uint256; bool public _IS_OPEN_TWAP_ = false; + bool public _IS_ORACLE_ENABLED = true; // ============ Core Address ============ @@ -45,12 +46,17 @@ contract DPPStorage is InitializableOwnable, ReentrancyGuard { uint64 public _LP_FEE_RATE_; uint64 public _K_; - address public _I_; + uint128 public _I_; + address public _O_; // ============ Helper Functions ============ function getPMMState() public view returns (PMMPricing.PMMState memory state) { - state.i = IOracle(_I_).prices(address(_BASE_TOKEN_)); + if (_IS_ORACLE_ENABLED) { + state.i = IOracle(_O_).prices(address(_BASE_TOKEN_)); + } else { + state.i = _I_; + } state.K = _K_; state.B = _BASE_RESERVE_; state.Q = _QUOTE_RESERVE_; diff --git a/contracts/DODOPrivatePool/impl/DPPOracle/DPPTrader.sol b/contracts/DODOPrivatePool/impl/DPPOracle/DPPTrader.sol index e379a94..71f0006 100644 --- a/contracts/DODOPrivatePool/impl/DPPOracle/DPPTrader.sol +++ b/contracts/DODOPrivatePool/impl/DPPOracle/DPPTrader.sol @@ -38,18 +38,12 @@ contract DPPTrader is DPPVault { event RChange(PMMPricing.RState newRState); - modifier isOraclePriceValid() { - bool isFeasible = IOracle(_I_).isFeasible(address(_BASE_TOKEN_)); - require(isFeasible, "ORACLE_PRICE_INVALID"); - _; - } // ============ Trade Functions ============ function sellBase(address to) external preventReentrant - isOraclePriceValid returns (uint256 receiveQuoteAmount) { uint256 baseBalance = _BASE_TOKEN_.balanceOf(address(this)); @@ -85,7 +79,6 @@ contract DPPTrader is DPPVault { function sellQuote(address to) external preventReentrant - isOraclePriceValid returns (uint256 receiveBaseAmount) { uint256 quoteBalance = _QUOTE_TOKEN_.balanceOf(address(this)); @@ -126,7 +119,7 @@ contract DPPTrader is DPPVault { uint256 quoteAmount, address _assetTo, bytes calldata data - ) external isOraclePriceValid preventReentrant { + ) external preventReentrant { address assetTo = _assetTo; _transferBaseOut(assetTo, baseAmount); _transferQuoteOut(assetTo, quoteAmount); diff --git a/contracts/DODOPrivatePool/impl/DPPOracle/DPPVault.sol b/contracts/DODOPrivatePool/impl/DPPOracle/DPPVault.sol index 78495b9..0fc8c73 100644 --- a/contracts/DODOPrivatePool/impl/DPPOracle/DPPVault.sol +++ b/contracts/DODOPrivatePool/impl/DPPOracle/DPPVault.sol @@ -123,6 +123,7 @@ contract DPPVault is DPPStorage { function reset( address assetTo, uint256 newLpFeeRate, + uint256 newI, uint256 newK, uint256 baseOutAmount, uint256 quoteOutAmount, @@ -135,9 +136,11 @@ contract DPPVault is DPPStorage { ); require(newLpFeeRate <= 1e18, "LP_FEE_RATE_OUT_OF_RANGE"); require(newK <= 1e18, "K_OUT_OF_RANGE"); + require(newI > 0 && newI <= 1e36, "I_OUT_OF_RANGE"); _LP_FEE_RATE_ = uint64(newLpFeeRate); _K_ = uint64(newK); + _I_ = uint128(newI); _transferBaseOut(assetTo, baseOutAmount); _transferQuoteOut(assetTo, quoteOutAmount); diff --git a/contracts/DODOPrivatePool/impl/DPPOracle/WooOracleAdapter.sol b/contracts/DODOPrivatePool/impl/DPPOracle/WooOracleAdapter.sol new file mode 100644 index 0000000..14eb47f --- /dev/null +++ b/contracts/DODOPrivatePool/impl/DPPOracle/WooOracleAdapter.sol @@ -0,0 +1,43 @@ +/* + + Copyright 2021 DODO ZOO. + SPDX-License-Identifier: Apache-2.0 + +*/ + +pragma solidity 0.6.9; +pragma experimental ABIEncoderV2; + +import {IOracle} from "../../intf/IOracle.sol"; + +interface IWooracle { + function timestamp() external view returns (uint256); + function isFeasible(address base) external view returns (bool); + function getPrice(address base) external view returns (uint256); + function price(address base) external view returns (uint256 priceNow, bool feasible); +} + +contract WooOracleAdapter is IOracle { + IWooracle oracle; + + constructor(address oracleAddress) public { + oracle = IWooracle(oracleAddress); + } + + function getPrice(address base) external override view returns (uint256 latestPrice,bool isValid,bool isStale,uint256 timestamp) { + latestPrice = oracle.getPrice(base); + isValid = oracle.isFeasible(base); + isStale = !isValid; + timestamp = oracle.timestamp(); + return (latestPrice, isValid, isStale, timestamp); + } + + function prices(address base) external override view returns (uint256) { + require(oracle.isFeasible(base), "ORACLE NOT FEASIBLE"); + return oracle.getPrice(base); + } + + function isFeasible(address base) external override view returns (bool) { + return oracle.isFeasible(base); + } +} \ No newline at end of file diff --git a/contracts/DODOPrivatePool/intf/IDPPOracle.sol b/contracts/DODOPrivatePool/intf/IDPPOracle.sol index fc542b4..181b700 100644 --- a/contracts/DODOPrivatePool/intf/IDPPOracle.sol +++ b/contracts/DODOPrivatePool/intf/IDPPOracle.sol @@ -35,6 +35,7 @@ interface IDPPOracle { function reset( address assetTo, uint256 newLpFeeRate, + uint256 newI, uint256 newK, uint256 baseOutAmount, uint256 quoteOutAmount, @@ -45,8 +46,21 @@ interface IDPPOracle { function tuneParameters( uint256 newLpFeeRate, + uint256 newI, uint256 newK, uint256 minBaseReserve, uint256 minQuoteReserve ) external returns (bool); + + function tunePrice( + uint256 newI, + uint256 minBaseReserve, + uint256 minQuoteReserve + ) external returns (bool); + + function changeOracle(address newOracle) external; + + function enableOracle() external; + + function disableOracle(uint256 newI) external; }