-
Notifications
You must be signed in to change notification settings - Fork 6
/
Copy pathOracleReader.sol
94 lines (77 loc) · 2.8 KB
/
OracleReader.sol
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.26;
import {OracleFeeds} from "./OracleFeeds.sol";
import {AggregatorV3Interface} from "@chainlink/contracts/src/v0.8/shared/interfaces/AggregatorV3Interface.sol";
/**
* @title OracleReader
* @dev Contract for reading price data from Chainlink oracles
*/
contract OracleReader {
address public oracleFeeds;
uint256[49] private __gap;
// @note: address(0) is a special address that represents USD (IRL asset)
address public constant USD = address(0);
// @note: special address that represents ETH (Chainlink asset)
address public constant ETH = address(0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE);
/**
* @dev Error thrown when no valid price is found
*/
error NoPriceFound();
/**
* @dev Error thrown when no valid feed is found
*/
error NoFeedFound();
/**
* @dev Error thrown when the price is stale
*/
error StalePrice();
/**
* @dev Error thrown when oracle feeds are aready initialized
*/
error AlreadyInitialized();
/**
* @dev Initializes the contract with the OracleFeeds address
* @param _oracleFeeds Address of the OracleFeeds contract
*/
function __OracleReader_init(address _oracleFeeds) internal {
require(oracleFeeds == address(0), AlreadyInitialized());
oracleFeeds = _oracleFeeds;
}
/**
* @dev Retrieves the latest price from the oracle
* @return price from the oracle
* @dev Reverts if the price data is older than chainlink's heartbeat
*/
function getOraclePrice(address quote, address base) public view returns(uint256) {
bool isInverted = false;
address feed = OracleFeeds(oracleFeeds).priceFeeds(quote, base);
if (feed == address(0)) {
feed = OracleFeeds(oracleFeeds).priceFeeds(base, quote);
if (feed == address(0)) {
revert NoFeedFound();
}
// Invert the price
isInverted = true;
}
(,int256 answer,,uint256 updatedTimestamp,) = AggregatorV3Interface(feed).latestRoundData();
if (updatedTimestamp + OracleFeeds(oracleFeeds).feedHeartbeats(feed) < block.timestamp) {
revert StalePrice();
}
uint256 decimals = uint256(AggregatorV3Interface(feed).decimals());
return isInverted ? (10 ** decimals * 10 ** decimals) / uint256(answer) : uint256(answer);
}
/**
* @dev Retrieves the number of decimals used in the oracle's price data
* @return decimals Number of decimals used in the price data
*/
function getOracleDecimals(address quote, address base) public view returns(uint8 decimals) {
address feed = OracleFeeds(oracleFeeds).priceFeeds(quote, base);
if (feed == address(0)) {
feed = OracleFeeds(oracleFeeds).priceFeeds(base, quote);
if (feed == address(0)) {
revert NoFeedFound();
}
}
return AggregatorV3Interface(feed).decimals();
}
}