diff --git a/contracts/DODOPrivatePool/impl/DPPOracle/DPPOracle.sol b/contracts/DODOPrivatePool/impl/DPPOracle/DPPOracle.sol index 086e9dd..adf676e 100644 --- a/contracts/DODOPrivatePool/impl/DPPOracle/DPPOracle.sol +++ b/contracts/DODOPrivatePool/impl/DPPOracle/DPPOracle.sol @@ -20,6 +20,9 @@ import {DPPTrader} from "./DPPTrader.sol"; */ contract DPPOracle is DPPTrader { + event ToggleOracleStatus(bool isEnabled); + event ChangeOracle(address indexed oracle); + function init( address owner, address maintainer, @@ -28,8 +31,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 +47,36 @@ 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 toggleOracleStatus(bool enabled) public preventReentrant onlyOwner returns (bool) { + _IS_ORACLE_ENABLED = enabled; + emit ToggleOracleStatus(enabled); + return enabled; + } function tuneParameters( uint256 newLpFeeRate, + uint256 newI, uint256 newK, uint256 minBaseReserve, uint256 minQuoteReserve @@ -67,18 +87,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 index 94042d9..95aa681 100644 --- a/contracts/DODOPrivatePool/impl/DPPOracle/DPPOracleAdmin.sol +++ b/contracts/DODOPrivatePool/impl/DPPOracle/DPPOracleAdmin.sol @@ -62,9 +62,28 @@ contract DPPOracleAdmin is InitializableOwnable { IDPPOracle(_DPP_).retrieve(to, token, amount); } + function changeOracle(address newOracle) external notFreezed { + require( + msg.sender == _OWNER_ || + (IDODOApproveProxy(_DODO_APPROVE_PROXY_).isAllowedProxy(msg.sender)), + "CHANGEORACLE FORBIDDEN!" + ); + IDPPOracle(_DPP_).changeOracle(newOracle); + } + + function toggleOracleStatus(bool enabled) external notFreezed { + require( + msg.sender == _OWNER_ || + (IDODOApproveProxy(_DODO_APPROVE_PROXY_).isAllowedProxy(msg.sender)), + "CHANGEORACLE FORBIDDEN!" + ); + IDPPOracle(_DPP_).toggleOracleStatus(enabled); + } + function tuneParameters( address operator, uint256 newLpFeeRate, + uint256 newI, uint256 newK, uint256 minBaseReserve, uint256 minQuoteReserve @@ -78,16 +97,38 @@ contract DPPOracleAdmin is InitializableOwnable { return IDPPOracle(_DPP_).tuneParameters( newLpFeeRate, + newI, newK, minBaseReserve, minQuoteReserve ); } + function tunePrice( + address operator, + uint256 newI, + uint256 minBaseReserve, + uint256 minQuoteReserve + ) external notFreezed returns (bool) { + require( + msg.sender == _OWNER_ || + (IDODOApproveProxy(_DODO_APPROVE_PROXY_).isAllowedProxy(msg.sender) && + operator == _OPERATOR_), + "TUNEPRICE FORBIDDEN!" + ); + return + IDPPOracle(_DPP_).tunePrice( + newI, + minBaseReserve, + minQuoteReserve + ); + } + function reset( address operator, uint256 newLpFeeRate, + uint256 newI, uint256 newK, uint256 baseOutAmount, uint256 quoteOutAmount, @@ -104,6 +145,7 @@ contract DPPOracleAdmin is InitializableOwnable { IDPPOracle(_DPP_).reset( _OWNER_, //only support asset transfer out to owner newLpFeeRate, + newI, newK, baseOutAmount, quoteOutAmount, @@ -115,6 +157,6 @@ contract DPPOracleAdmin is InitializableOwnable { // ============ Admin Version Control ============ function version() external pure returns (string memory) { - return "DPPOracle Admin 1.0.0"; // 1.0.0 + return "DPPOracle Admin 1.1.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..19420a2 100644 --- a/contracts/DODOPrivatePool/impl/DPPOracle/DPPTrader.sol +++ b/contracts/DODOPrivatePool/impl/DPPOracle/DPPTrader.sol @@ -38,9 +38,11 @@ contract DPPTrader is DPPVault { event RChange(PMMPricing.RState newRState); - modifier isOraclePriceValid() { - bool isFeasible = IOracle(_I_).isFeasible(address(_BASE_TOKEN_)); - require(isFeasible, "ORACLE_PRICE_INVALID"); + modifier isPriceValid() { + if (_IS_ORACLE_ENABLED) { + bool isFeasible = IOracle(_I_).isFeasible(address(_BASE_TOKEN_)); + require(isFeasible, "ORACLE_PRICE_INVALID"); + } _; } @@ -49,7 +51,7 @@ contract DPPTrader is DPPVault { function sellBase(address to) external preventReentrant - isOraclePriceValid + isPriceValid returns (uint256 receiveQuoteAmount) { uint256 baseBalance = _BASE_TOKEN_.balanceOf(address(this)); @@ -85,7 +87,7 @@ contract DPPTrader is DPPVault { function sellQuote(address to) external preventReentrant - isOraclePriceValid + isPriceValid returns (uint256 receiveBaseAmount) { uint256 quoteBalance = _QUOTE_TOKEN_.balanceOf(address(this)); @@ -126,7 +128,7 @@ contract DPPTrader is DPPVault { uint256 quoteAmount, address _assetTo, bytes calldata data - ) external isOraclePriceValid preventReentrant { + ) external isPriceValid 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/OracleAdapter.sol b/contracts/DODOPrivatePool/impl/DPPOracle/OracleAdapter.sol new file mode 100644 index 0000000..e222ea9 --- /dev/null +++ b/contracts/DODOPrivatePool/impl/DPPOracle/OracleAdapter.sol @@ -0,0 +1,42 @@ +/* + + 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 OracleAdapter 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) { + 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..4619684 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,19 @@ 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 toggleOracleStatus(bool enabled) external; }