diff --git a/src/OevOracle.sol b/src/OevOracle.sol index 345020a..a66493c 100644 --- a/src/OevOracle.sol +++ b/src/OevOracle.sol @@ -27,6 +27,8 @@ abstract contract OevOracle is IOevOracle { cachedLatestTimestamp = _latestTimestamp; } + // TODO: Decide how to handle negative values. Since not all source oracles support negative values we may need to + // limit the support only to positive values. function rawLatestAnswer() public view override returns (int256) { if (canReturnCachedValue(cachedLatestTimestamp)) return cachedLatestAnswer; return sourceAdapter.latestAnswer(); diff --git a/src/adapters/makerdao/ChronicleDestinationOracleAdapter.sol b/src/adapters/makerdao/ChronicleDestinationOracleAdapter.sol index 623ba79..5c5bf2c 100644 --- a/src/adapters/makerdao/ChronicleDestinationOracleAdapter.sol +++ b/src/adapters/makerdao/ChronicleDestinationOracleAdapter.sol @@ -2,31 +2,28 @@ pragma solidity 0.8.17; import "../../controllers/BaseController.sol"; -import "../../interfaces/chronicle/IMedian.sol"; +import "../../interfaces/chronicle/IOSM.sol"; -contract ChronicleDestinationOracleAdapter is BaseController, IMedian { - uint8 public decimals; +contract ChronicleDestinationOracleAdapter is BaseController, IOSM { + constructor(address _sourceAdapter) BaseController(_sourceAdapter) {} - constructor(uint8 _decimals, address _sourceAdapter) BaseController(_sourceAdapter) { - decimals = _decimals; - } - - function read() public view override returns (uint256) { - // TODO: if we never have more than 18 decimals on the output oracle then we can subtract decimals and divide. - return (uint256(rawLatestAnswer()) * (10 ** decimals)) / (10 ** 18); + function read() public view override returns (bytes32) { + // MakerDAO performs decimal conversion in collateral adapter contracts, so all oracle prices are expected to have + // 18 decimals, the same as returned by the rawLatestAnswer(). + return bytes32(uint256(rawLatestAnswer())); } // TODO: might need to add toll functionality to replicate consumer authorization as in MakerDao. - function peek() public view override returns (uint256, bool) { - uint256 val = read(); - return (val, val > 0); - } - - function age() public view override returns (uint32) { - return uint32(rawLatestTimestamp()); + function peek() public view override returns (bytes32, bool) { + uint256 val = uint256(rawLatestAnswer()); + // TODO: In current design we cannot pass through invalid 0 values and fetching them from source OSM would revert. + // This might be required for MakerDAO when voiding Oracle sources. + return (bytes32(val), val > 0); } - function bar() public view override returns (uint256) { - return uint256(decimals); + // This is only implemented to satisfy the interface, but should not be consumed, especially when mixing with other + // source Oracle adapters than OSM. + function zzz() public view override returns (uint64) { + return uint64(rawLatestTimestamp()); } } diff --git a/src/adapters/makerdao/ChronicleSourceOracleAdapter.sol b/src/adapters/makerdao/ChronicleSourceOracleAdapter.sol index 5340848..1ed5a88 100644 --- a/src/adapters/makerdao/ChronicleSourceOracleAdapter.sol +++ b/src/adapters/makerdao/ChronicleSourceOracleAdapter.sol @@ -2,24 +2,25 @@ pragma solidity 0.8.17; import "../../interfaces/IBaseOracleAdapter.sol"; -import "../../interfaces/chronicle/IMedian.sol"; +import "../../interfaces/chronicle/IOSM.sol"; -contract ChainlinkSourceOracleAdapter is IBaseOracleAdapter { - IMedian public source; +contract ChronicleSourceOracleAdapter is IBaseOracleAdapter { + IOSM public source; - constructor(IMedian _source) { + // MakerDAO performs decimal conversion in collateral adapter contracts, so all oracle prices are expected to have + // 18 decimals. + uint8 public constant decimals = 18; + + constructor(IOSM _source) { source = _source; } function latestAnswer() public view override returns (int256) { - return int256((source.read() * (10 ** 18)) / decimals()); + // This will revert if the price has been voided. + return int256((uint(source.read()) * (10 ** 18)) / (10 ** decimals)); } function latestTimestamp() public view override returns (uint256) { - return source.age(); - } - - function decimals() public view override returns (uint8) { - return uint8(source.bar()); + return source.zzz(); } } diff --git a/src/interfaces/chronicle/IOSM.sol b/src/interfaces/chronicle/IOSM.sol new file mode 100644 index 0000000..8d5598b --- /dev/null +++ b/src/interfaces/chronicle/IOSM.sol @@ -0,0 +1,37 @@ +pragma solidity 0.8.17; + +interface IOSM { + + // function wards(address) external view returns (uint256); // Auth addresses + // function rely(address usr) external; // Add auth (auth) + // function deny(address usr) external; // Remove auth (auth) + + // function stopped() external view returns (uint256); // Determines if OSM can be poked. + + // function src() external view returns (address); // Address of source oracle. + + // function hop() external view returns (uint16); // Oracle delay in seconds. + function zzz() external view returns (uint64); // Time of last update (rounded down to nearest multiple of hop). + + // function bud(address _addr) external view returns (uint256); // Whitelisted contracts, set by an auth + + // function stop() external; // Stop Oracle updates (auth) + // function start() external; // Resume Oracle updates (auth) + + // function change(address src_) external; // Change source oracle (auth) + // function step(uint16 ts) external; // Change hop (auth) + + // function void() external; // Reset price feed to invalid and stop updates (auth) + + // function pass() external view returns (bool); // Check if oracle update period has passed. + // function poke() external; // Poke OSM for a new price (can be called by anyone) + + function peek() external view returns (bytes32, bool); // Return current price and if valid (whitelisted) + // function peep() external view returns (bytes32, bool); // Return the next price and if valid (whitelisted) + function read() external view returns (bytes32); // Return current price, only if valid (whitelisted) + + // function kiss(address a) external; // Add address to whitelist (auth) + // function diss(address a) external; // Remove address from whitelist (auth) + // function kiss(address[] calldata a) external; // Add addresses to whitelist (auth) + // function diss(address[] calldata a) external; // Remove addresses from whitelist (auth) +}