-
Notifications
You must be signed in to change notification settings - Fork 1
/
PriceOracleProxyETH.sol
233 lines (189 loc) · 7.82 KB
/
PriceOracleProxyETH.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
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
pragma solidity ^0.8.10;
import "./PriceOracle.sol";
import "./Interfaces/AggregatorV3Interface.sol";
import "./Interfaces/FlagsInterface.sol";
import "./Interfaces/V1PriceOracleInterface.sol";
import "../CErc20.sol";
import "../CToken.sol";
import "../EIP20Interface.sol";
import "./Interfaces/GLPOracleInterface.sol";
import "../Exponential.sol";
import "../SafeMath.sol";
contract PriceOracleProxyETH is Exponential {
using SafeMath for uint256;
/// @notice Identifier of the Sequencer offline flag on the Flags contract
address private constant FLAG_ARBITRUM_SEQ_OFFLINE =
address(bytes20(bytes32(uint256(keccak256("chainlink.flags.arbitrum-seq-offline")) - 1)));
bool public constant isPriceOracle = true;
/// @notice ChainLink aggregator base, currently support USD and ETH
enum AggregatorBase {
USD,
ETH
}
/// @notice Admin address
address public admin;
/// @notice Guardian address
address public guardian;
address public letheraddress;
//address public lGLPaddress;
address public lplvGLPaddress;
address public glpOracleAddress;
struct AggregatorInfo {
/// @notice The source address of the aggregator
AggregatorV3Interface source;
/// @notice The aggregator base
AggregatorBase base;
}
/// @notice Chainlink Aggregators
mapping(address => AggregatorInfo) public aggregators;
/// @notice The v1 price oracle
V1PriceOracleInterface public v1PriceOracle;
/// @notice The ETH-USD aggregator address
AggregatorV3Interface public ethUsdAggregator;
/// @notice The Chainlink L2 Sequencer Health Flag address
//FlagsInterface private chainlinkFlags;
/**
* @param admin_ The address of admin to set aggregators
* @param v1PriceOracle_ The v1 price oracle
*/
constructor(
address admin_,
address v1PriceOracle_,
address ethUsdAggregator_,
//address flags_,
address letheraddress_,
//address lGLPaddress_,
address lplvGLPaddress_,
address glpOracleAddress_
) public {
admin = admin_;
v1PriceOracle = V1PriceOracleInterface(v1PriceOracle_);
ethUsdAggregator = AggregatorV3Interface(ethUsdAggregator_);
//chainlinkFlags = FlagsInterface(flags_);
letheraddress = letheraddress_;
//lGLPaddress = lGLPaddress_;
lplvGLPaddress = lplvGLPaddress_;
glpOracleAddress = glpOracleAddress_;
}
/**
* @notice Get the underlying price of a listed cToken asset
* @param cToken The cToken to get the underlying price of
* @return The underlying asset price mantissa (scaled by 1e18)
*/
function getUnderlyingPrice(CToken cToken) public view returns (uint256) {
address cTokenAddress = address(cToken);
AggregatorInfo memory aggregatorInfo = aggregators[cTokenAddress];
if (cTokenAddress == letheraddress) {
uint256 price = 1e18;
return price;
}
/*else if (cTokenAddress == lGLPaddress) {
uint256 price = getGLPPrice();
price = div_(price, Exp({mantissa: getPriceFromChainlink(ethUsdAggregator)}));
return price;
}*/
else if (cTokenAddress == lplvGLPaddress) {
uint256 price = getPlvGLPPrice();
price = div_(price, Exp({mantissa: getPriceFromChainlink(ethUsdAggregator)}));
return price;
}
else if (address(aggregatorInfo.source) != address(0)) {
//bool isRaised = chainlinkFlags.getFlag(FLAG_ARBITRUM_SEQ_OFFLINE);
uint256 price = getPriceFromChainlink(aggregatorInfo.source);
//if (isRaised) {
// If flag is raised we shouldn't perform any critical operations
//revert("Chainlink feeds are not being updated");
//}
/*else*/
if (aggregatorInfo.base == AggregatorBase.USD) {
//uint8 aggregatorDecimals = uint8(AggregatorV3Interface(aggregatorInfo.source).decimals);
//uint256 exponent = 18 + aggregatorDecimals;
// Convert the price to ETH based if it's USD based.
price = div_(price, Exp({mantissa: getPriceFromChainlink(ethUsdAggregator)}));
}
uint256 underlyingDecimals = EIP20Interface(CErc20(cTokenAddress).underlying()).decimals();
return price * 10**(18 - underlyingDecimals);
return price;
}
return getPriceFromV1(cTokenAddress);
}
/*** Internal fucntions ***/
/**
* @notice Get price from ChainLink
* @param aggregator The ChainLink aggregator to get the price of
* @return The price
*/
function getPriceFromChainlink(AggregatorV3Interface aggregator) public view returns (uint256) {
(, int256 price, , , ) = aggregator.latestRoundData();
require(price > 0, "invalid price");
// Extend the decimals to 1e18.
return uint256(price) * 10**(18 - uint256(aggregator.decimals()));
}
/*function getGLPPrice() internal view returns (uint256) {
uint256 price = GLPOracleInterface(glpOracleAddress).getGLPPrice();
require(price > 0, "invalid price");
//glp oracle returns price scaled to 18 decimals, no need to extend here
return price;
}*/
function getPlvGLPPrice() public view returns (uint256) {
uint256 price = GLPOracleInterface(glpOracleAddress).getPlvGLPPrice();
require(price > 0, "invalid price");
//glp oracle returns price scaled to 18 decimals, no need to extend here
return price;
}
/**
* @notice Get price from v1 price oracle
* @param cTokenAddress The CToken address
* @return The price
*/
function getPriceFromV1(address cTokenAddress) internal view returns (uint256) {
address underlying = CErc20(cTokenAddress).underlying();
return v1PriceOracle.assetPrices(underlying);
}
/*** Admin or guardian functions ***/
event AggregatorUpdated(address cTokenAddress, address source, AggregatorBase base);
event SetGuardian(address guardian);
event SetAdmin(address admin);
/**
* @notice Set guardian for price oracle proxy
* @param _guardian The new guardian
*/
function _setGuardian(address _guardian) external {
require(msg.sender == admin, "only the admin may set new guardian");
guardian = _guardian;
emit SetGuardian(guardian);
}
/**
* @notice Set admin for price oracle proxy
* @param _admin The new admin
*/
function _setAdmin(address _admin) external {
require(msg.sender == admin, "only the admin may set new admin");
admin = _admin;
emit SetAdmin(admin);
}
/**
* @notice Set ChainLink aggregators for multiple cTokens
* @param cTokenAddresses The list of cTokens
* @param sources The list of ChainLink aggregator sources
* @param bases The list of ChainLink aggregator bases
*/
function _setAggregators(
address[] calldata cTokenAddresses,
address[] calldata sources,
AggregatorBase[] calldata bases
) external {
require(msg.sender == admin || msg.sender == guardian, "only the admin or guardian may set the aggregators");
require(cTokenAddresses.length == sources.length && cTokenAddresses.length == bases.length, "mismatched data");
for (uint256 i = 0; i < cTokenAddresses.length; i++) {
if (sources[i] != address(0)) {
require(msg.sender == admin, "guardian may only clear the aggregator");
}
aggregators[cTokenAddresses[i]] = AggregatorInfo({
source: AggregatorV3Interface(sources[i]),
base: bases[i]
});
emit AggregatorUpdated(cTokenAddresses[i], sources[i], bases[i]);
}
}
}