diff --git a/src/OevOracle.sol b/src/OevOracle.sol index 09d9c77..345020a 100644 --- a/src/OevOracle.sol +++ b/src/OevOracle.sol @@ -15,38 +15,38 @@ abstract contract OevOracle is IOevOracle { } function updateAnswer() public { - require(_canUpdate(cachedLatestTimestamp)); + require(canUpdate(msg.sender, cachedLatestTimestamp)); int256 _latestAnswer = sourceAdapter.latestAnswer(); uint256 _latestTimestamp = sourceAdapter.latestTimestamp(); require(_latestAnswer != cachedLatestAnswer || _latestTimestamp != cachedLatestTimestamp); - require(_validateUpdate(_latestAnswer, _latestTimestamp)); + require(validateUpdate(_latestAnswer, _latestTimestamp)); cachedLatestAnswer = _latestAnswer; cachedLatestTimestamp = _latestTimestamp; } function rawLatestAnswer() public view override returns (int256) { - if (_canReturnCachedValue(cachedLatestTimestamp)) return cachedLatestAnswer; + if (canReturnCachedValue(cachedLatestTimestamp)) return cachedLatestAnswer; return sourceAdapter.latestAnswer(); } function rawLatestTimestamp() public view override returns (uint256) { - if (_canReturnCachedValue(cachedLatestTimestamp)) return cachedLatestTimestamp; + if (canReturnCachedValue(cachedLatestTimestamp)) return cachedLatestTimestamp; return sourceAdapter.latestTimestamp(); } function setSourceOracleAdapter(IBaseOracleAdapter _sourceAdapter) external { - require(_canSetSourceOracleAdapter()); + require(canSetSourceOracleAdapter(msg.sender)); sourceAdapter = _sourceAdapter; } - function _canUpdate(uint256 cachedLatestTimestamp) internal view virtual returns (bool); + function canUpdate(address caller, uint256 cachedLatestTimestamp) public view virtual returns (bool); - function _validateUpdate(int256 _latestAnswer, uint256 _latestTimestamp) internal view virtual returns (bool); + function validateUpdate(int256 _latestAnswer, uint256 _latestTimestamp) public view virtual returns (bool); - function _canReturnCachedValue(uint256 _cachedValue) internal view virtual returns (bool); + function canReturnCachedValue(uint256 _cachedValue) public view virtual returns (bool); - function _canSetSourceOracleAdapter() internal view virtual returns (bool); + function canSetSourceOracleAdapter(address caller) public view virtual returns (bool); } diff --git a/src/adapters/BaseDestinationOracleAdapter.sol b/src/adapters/BaseDestinationOracleAdapter.sol index 63fca97..755fd0f 100644 --- a/src/adapters/BaseDestinationOracleAdapter.sol +++ b/src/adapters/BaseDestinationOracleAdapter.sol @@ -1,10 +1,10 @@ pragma solidity 0.8.17; -import "../controllers/BaseUpdateController.sol"; +import "../controllers/BaseController.sol"; import "../interfaces/IBaseOracleAdapter.sol"; -contract BaseDestinationOracleAdapter is BaseUpdateController, IBaseOracleAdapter { - constructor(address _sourceAdapter) BaseUpdateController(_sourceAdapter) {} +contract BaseDestinationOracleAdapter is BaseController, IBaseOracleAdapter { + constructor(address _sourceAdapter) BaseController(_sourceAdapter) {} function decimals() public view override returns (uint8) { return 18; diff --git a/src/adapters/chainlink/ChainlinkDestinationOracleAdapter.sol b/src/adapters/chainlink/ChainlinkDestinationOracleAdapter.sol index 4ad82ac..0571041 100644 --- a/src/adapters/chainlink/ChainlinkDestinationOracleAdapter.sol +++ b/src/adapters/chainlink/ChainlinkDestinationOracleAdapter.sol @@ -1,16 +1,16 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity 0.8.17; -import "../../controllers/BaseUpdateController.sol"; +import "../../controllers/BaseController.sol"; import "../../interfaces/IBaseOracleAdapter.sol"; import "../../interfaces/chainlink/IAggregatorV3.sol"; import "../../OevOracle.sol"; -contract ChainlinkDestinationOracleAdapter is IAggregatorV3, BaseUpdateController { +contract ChainlinkDestinationOracleAdapter is IAggregatorV3, BaseController { uint8 public override decimals; // This should sit between OSM and spotter. - constructor(uint8 _decimals, address _sourceAdapter) BaseUpdateController(_sourceAdapter) { + constructor(uint8 _decimals, address _sourceAdapter) BaseController(_sourceAdapter) { decimals = _decimals; } diff --git a/src/adapters/makerdao/ChronicleDestinationOracleAdapter.sol b/src/adapters/makerdao/ChronicleDestinationOracleAdapter.sol index 8cb1530..623ba79 100644 --- a/src/adapters/makerdao/ChronicleDestinationOracleAdapter.sol +++ b/src/adapters/makerdao/ChronicleDestinationOracleAdapter.sol @@ -1,13 +1,13 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity 0.8.17; -import "../../controllers/BaseUpdateController.sol"; +import "../../controllers/BaseController.sol"; import "../../interfaces/chronicle/IMedian.sol"; -contract ChronicleDestinationOracleAdapter is BaseUpdateController, IMedian { +contract ChronicleDestinationOracleAdapter is BaseController, IMedian { uint8 public decimals; - constructor(uint8 _decimals, address _sourceAdapter) BaseUpdateController(_sourceAdapter) { + constructor(uint8 _decimals, address _sourceAdapter) BaseController(_sourceAdapter) { decimals = _decimals; } diff --git a/src/controllers/BaseController.sol b/src/controllers/BaseController.sol new file mode 100644 index 0000000..31049bc --- /dev/null +++ b/src/controllers/BaseController.sol @@ -0,0 +1,59 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity 0.8.17; + +import "openzeppelin-contracts/contracts/access/Ownable.sol"; +import "../OevOracle.sol"; +import "../interfaces/IBaseController.sol"; + +contract BaseController is IBaseController, OevOracle, Ownable { + constructor(address _sourceAdapter) OevOracle(_sourceAdapter) {} + + mapping(address => bool) public updaters; + + uint256 public permissionWindow = 10 minutes; + + function setUpdater(address _updater, bool allowed) public onlyOwner { + updaters[_updater] = allowed; + } + + function setPermissionWindow(uint256 _permissionWindow) public onlyOwner { + permissionWindow = _permissionWindow; + } + + function canUpdate(address caller, uint256 cachedLatestTimestamp) + public + view + override(IBaseController, OevOracle) + returns (bool) + { + return updaters[caller] || (block.timestamp - cachedLatestTimestamp) > permissionWindow; + } + + function validateUpdate(int256 rawLatestAnswer, uint256 rawLatestTimestamp) + public + view + override(IBaseController, OevOracle) + returns (bool) + { + // sample dummy check. + return rawLatestAnswer > 0 && rawLatestTimestamp > 0; + } + + function canReturnCachedValue(uint256 cachedLatestTimestamp) + public + view + override(IBaseController, OevOracle) + returns (bool) + { + return (block.timestamp - cachedLatestTimestamp < permissionWindow); + } + + function canSetSourceOracleAdapter(address caller) + public + view + override(IBaseController, OevOracle) + returns (bool) + { + return caller == owner(); + } +} diff --git a/src/controllers/BaseUpdateController.sol b/src/controllers/BaseUpdateController.sol deleted file mode 100644 index 47c81a1..0000000 --- a/src/controllers/BaseUpdateController.sol +++ /dev/null @@ -1,44 +0,0 @@ -// SPDX-License-Identifier: UNLICENSED -pragma solidity 0.8.17; - -import "openzeppelin-contracts/contracts/access/Ownable.sol"; -import "../OevOracle.sol"; - -contract BaseUpdateController is OevOracle, Ownable { - constructor(address _sourceAdapter) OevOracle(_sourceAdapter) {} - - mapping(address => bool) public updaters; - - uint256 public permissionWindow = 10 minutes; - - function setUpdater(address _updater, bool allowed) public onlyOwner { - updaters[_updater] = allowed; - } - - function setPermissionWindow(uint256 _permissionWindow) public onlyOwner { - permissionWindow = _permissionWindow; - } - - function _canUpdate(uint256 cachedLatestTimestamp) internal view override returns (bool) { - return updaters[msg.sender] || (block.timestamp - cachedLatestTimestamp) > permissionWindow; - } - - //TODO: think if we actually want this validation here. this means we have 2 forms of validation, one within the source adapter and the second here. is this needed? - function _validateUpdate(int256 rawLatestAnswer, uint256 rawLatestTimestamp) - internal - view - override - returns (bool) - { - // sample dummy check. - return rawLatestAnswer > 0 && rawLatestTimestamp > 0; - } - - function _canReturnCachedValue(uint256 cachedLatestTimestamp) internal view override returns (bool) { - return (block.timestamp - cachedLatestTimestamp < permissionWindow); - } - - function _canSetSourceOracleAdapter() internal view override returns (bool) { - return msg.sender == owner(); - } -} diff --git a/src/interfaces/IBaseController.sol b/src/interfaces/IBaseController.sol new file mode 100644 index 0000000..3dfcdf3 --- /dev/null +++ b/src/interfaces/IBaseController.sol @@ -0,0 +1,13 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity 0.8.17; + +interface IBaseController { + function canUpdate(address caller, uint256 cachedLatestTimestamp) external view returns (bool); + + //TODO: think if we actually want this validation here. this means we have 2 forms of validation, one within the source adapter and the second here. is this needed? + function validateUpdate(int256 rawLatestAnswer, uint256 rawLatestTimestamp) external view returns (bool); + + function canReturnCachedValue(uint256 cachedLatestTimestamp) external view returns (bool); + + function canSetSourceOracleAdapter(address caller) external view returns (bool); +} diff --git a/src/interfaces/IBaseDestinationOracleAdapter.sol b/src/interfaces/IBaseDestinationOracleAdapter.sol deleted file mode 100644 index 7cee736..0000000 --- a/src/interfaces/IBaseDestinationOracleAdapter.sol +++ /dev/null @@ -1,3 +0,0 @@ -// SPDX-License-Identifier: UNLICENSED -pragma solidity 0.8.17; - diff --git a/src/interfaces/IBaseIntegrationController.sol b/src/interfaces/IBaseIntegrationController.sol deleted file mode 100644 index 7cee736..0000000 --- a/src/interfaces/IBaseIntegrationController.sol +++ /dev/null @@ -1,3 +0,0 @@ -// SPDX-License-Identifier: UNLICENSED -pragma solidity 0.8.17; - diff --git a/src/interfaces/chainlink/IAggregatorV3.sol b/src/interfaces/chainlink/IAggregatorV3.sol index 1b7d529..74c07a8 100644 --- a/src/interfaces/chainlink/IAggregatorV3.sol +++ b/src/interfaces/chainlink/IAggregatorV3.sol @@ -8,6 +8,7 @@ interface IAggregatorV3 { function decimals() external view returns (uint8); + // Other chainlink functions we dont need. // function latestRoundData() // external // view diff --git a/src/interfaces/chronicle/IMedian.sol b/src/interfaces/chronicle/IMedian.sol index e265968..792c12b 100644 --- a/src/interfaces/chronicle/IMedian.sol +++ b/src/interfaces/chronicle/IMedian.sol @@ -6,12 +6,14 @@ interface IMedian { function bar() external view returns (uint256); function read() external view returns (uint256); + + function peek() external view returns (uint256, bool); + + // Other Medianer functions we dont need. // function bud(address) external view returns (uint256); // function orcl(address) external view returns (uint256); - function peek() external view returns (uint256, bool); - // function slot(uint8) external view returns (address); // function wards(address) external view returns (uint256);