-
Notifications
You must be signed in to change notification settings - Fork 0
/
OracleRef.sol
171 lines (145 loc) · 5.61 KB
/
OracleRef.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
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
// SPDX-License-Identifier: GPL-3.0-or-later
pragma solidity ^0.8.4;
import "./IOracleRef.sol";
import "./CoreRef.sol";
import "@openzeppelin/contracts/utils/math/SafeCast.sol";
import "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol";
/// @title Reference to an Oracle
/// @author Fei Protocol
/// @notice defines some utilities around interacting with the referenced oracle
abstract contract OracleRef is IOracleRef, CoreRef {
using Decimal for Decimal.D256;
using SafeCast for int256;
/// @notice the oracle reference by the contract
IOracle public override oracle;
/// @notice the backup oracle reference by the contract
IOracle public override backupOracle;
/// @notice number of decimals to scale oracle price by, i.e. multiplying by 10^(decimalsNormalizer)
int256 public override decimalsNormalizer;
bool public override doInvert;
/// @notice OracleRef constructor
/// @param _core Fei Core to reference
/// @param _oracle oracle to reference
/// @param _backupOracle backup oracle to reference
/// @param _decimalsNormalizer number of decimals to normalize the oracle feed if necessary
/// @param _doInvert invert the oracle price if this flag is on
constructor(
address _core,
address _oracle,
address _backupOracle,
int256 _decimalsNormalizer,
bool _doInvert
) CoreRef(_core) {
_setOracle(_oracle);
if (_backupOracle != address(0) && _backupOracle != _oracle) {
_setBackupOracle(_backupOracle);
}
_setDoInvert(_doInvert);
_setDecimalsNormalizer(_decimalsNormalizer);
}
/// @notice sets the referenced oracle
/// @param newOracle the new oracle to reference
function setOracle(address newOracle) external override onlyGovernor {
_setOracle(newOracle);
}
/// @notice sets the flag for whether to invert or not
/// @param newDoInvert the new flag for whether to invert
function setDoInvert(bool newDoInvert) external override onlyGovernor {
_setDoInvert(newDoInvert);
}
/// @notice sets the new decimalsNormalizer
/// @param newDecimalsNormalizer the new decimalsNormalizer
function setDecimalsNormalizer(int256 newDecimalsNormalizer)
external
override
onlyGovernor
{
_setDecimalsNormalizer(newDecimalsNormalizer);
}
/// @notice sets the referenced backup oracle
/// @param newBackupOracle the new backup oracle to reference
function setBackupOracle(address newBackupOracle)
external
override
onlyGovernorOrAdmin
{
_setBackupOracle(newBackupOracle);
}
/// @notice invert a peg price
/// @param price the peg price to invert
/// @return the inverted peg as a Decimal
/// @dev the inverted peg would be X per FEI
function invert(Decimal.D256 memory price)
public
pure
override
returns (Decimal.D256 memory)
{
return Decimal.one().div(price);
}
/// @notice updates the referenced oracle
function updateOracle() public override {
oracle.update();
}
/// @notice the peg price of the referenced oracle
/// @return the peg as a Decimal
/// @dev the peg is defined as FEI per X with X being ETH, dollars, etc
function readOracle() public view override returns (Decimal.D256 memory) {
(Decimal.D256 memory _peg, bool valid) = oracle.read();
if (!valid && address(backupOracle) != address(0)) {
(_peg, valid) = backupOracle.read();
}
require(valid, "OracleRef: oracle invalid");
// Invert the oracle price if necessary
if (doInvert) {
_peg = invert(_peg);
}
// Scale the oracle price by token decimals delta if necessary
uint256 scalingFactor;
if (decimalsNormalizer < 0) {
scalingFactor = 10**(-1 * decimalsNormalizer).toUint256();
_peg = _peg.div(scalingFactor);
} else {
scalingFactor = 10**decimalsNormalizer.toUint256();
_peg = _peg.mul(scalingFactor);
}
return _peg;
}
function _setOracle(address newOracle) internal {
require(newOracle != address(0), "OracleRef: zero address");
address oldOracle = address(oracle);
oracle = IOracle(newOracle);
emit OracleUpdate(oldOracle, newOracle);
}
// Supports zero address if no backup
function _setBackupOracle(address newBackupOracle) internal {
address oldBackupOracle = address(backupOracle);
backupOracle = IOracle(newBackupOracle);
emit BackupOracleUpdate(oldBackupOracle, newBackupOracle);
}
function _setDoInvert(bool newDoInvert) internal {
bool oldDoInvert = doInvert;
doInvert = newDoInvert;
if (oldDoInvert != newDoInvert) {
_setDecimalsNormalizer(-1 * decimalsNormalizer);
}
emit InvertUpdate(oldDoInvert, newDoInvert);
}
function _setDecimalsNormalizer(int256 newDecimalsNormalizer) internal {
int256 oldDecimalsNormalizer = decimalsNormalizer;
decimalsNormalizer = newDecimalsNormalizer;
emit DecimalsNormalizerUpdate(
oldDecimalsNormalizer,
newDecimalsNormalizer
);
}
function _setDecimalsNormalizerFromToken(address token) internal {
int256 feiDecimals = 18;
int256 _decimalsNormalizer = feiDecimals -
int256(uint256(IERC20Metadata(token).decimals()));
if (doInvert) {
_decimalsNormalizer = -1 * _decimalsNormalizer;
}
_setDecimalsNormalizer(_decimalsNormalizer);
}
}