/
Whitelist.sol
375 lines (319 loc) · 11.7 KB
/
Whitelist.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
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
// SPDX-License-Identifier: MIT
pragma solidity 0.6.11;
import "./Ownable.sol";
import "../Interfaces/IBaseOracle.sol";
import "../Interfaces/IWhitelist.sol";
import "../Interfaces/IPriceFeed.sol";
import "../Interfaces/IPriceCurve.sol";
import "../Interfaces/IActivePool.sol";
import "../Interfaces/IDefaultPool.sol";
import "../Interfaces/IStabilityPool.sol";
import "../Interfaces/ICollSurplusPool.sol";
import "../Interfaces/IERC20.sol";
import "./LiquityMath.sol";
import "./CheckContract.sol";
/**
* Whitelist is the contract that keeps track of all the assets that the system takes as collateral.
* It has onlyOwner functions to add or deprecate collaterals from the whitelist, change the price
* curve, price feed, safety ratio, etc.
*/
contract Whitelist is Ownable, IWhitelist, IBaseOracle, CheckContract {
using SafeMath for uint256;
struct CollateralParams {
// Safety ratio
uint256 ratio; // 10**18 * the ratio. i.e. ratio = .95 * 10**18 for 95%. More risky collateral has a lower ratio
address oracle;
uint256 decimals;
bool active;
address priceCurve;
uint256 index;
bool isWrapped;
}
IActivePool activePool;
IDefaultPool defaultPool;
IStabilityPool stabilityPool;
ICollSurplusPool collSurplusPool;
address borrowerOperationsAddress;
mapping(address => CollateralParams) public collateralParams;
mapping(address => bool) public validRouter;
// list of all collateral types in collateralParams (active and deprecated)
// Addresses for easy access
address[] public validCollateral; // index maps to token address.
event CollateralAdded(address _collateral);
event CollateralDeprecated(address _collateral);
event CollateralUndeprecated(address _collateral);
event CollateralRemoved(address _collateral);
event OracleChanged(address _collateral);
event PriceCurveChanged(address _collateral);
event RatioChanged(address _collateral);
// Require that the collateral exists in the whitelist. If it is not the 0th index, and the
// index is still 0 then it does not exist in the mapping.
modifier exists(address _collateral) {
if (validCollateral.length != 0 && validCollateral[0] != _collateral) {
require(collateralParams[_collateral].index != 0, "collateral does not exists");
}
_;
}
// ----------Only Owner Setter Functions----------
function setAddresses(
address _activePoolAddress,
address _defaultPoolAddress,
address _stabilityPoolAddress,
address _collSurplusPoolAddress,
address _borrowerOperationsAddress
) external override onlyOwner {
checkContract(_activePoolAddress);
checkContract(_defaultPoolAddress);
checkContract(_stabilityPoolAddress);
checkContract(_collSurplusPoolAddress);
checkContract(_borrowerOperationsAddress);
activePool = IActivePool(_activePoolAddress);
defaultPool = IDefaultPool(_defaultPoolAddress);
stabilityPool = IStabilityPool(_stabilityPoolAddress);
collSurplusPool = ICollSurplusPool(_collSurplusPoolAddress);
borrowerOperationsAddress = _borrowerOperationsAddress;
}
function addCollateral(
address _collateral,
uint256 _minRatio,
address _oracle,
uint256 _decimals,
address _priceCurve,
bool _isWrapped
) external onlyOwner {
checkContract(_collateral);
checkContract(_oracle);
checkContract(_priceCurve);
// If collateral list is not 0, and if the 0th index is not equal to this collateral,
// then if index is 0 that means it is not set yet.
if (validCollateral.length != 0 && validCollateral[0] != _collateral) {
require(collateralParams[_collateral].index == 0, "collateral already exists");
}
validCollateral.push(_collateral);
collateralParams[_collateral] = CollateralParams(
_minRatio,
_oracle,
_decimals,
true,
_priceCurve,
validCollateral.length - 1,
_isWrapped
);
activePool.addCollateralType(_collateral);
defaultPool.addCollateralType(_collateral);
stabilityPool.addCollateralType(_collateral);
collSurplusPool.addCollateralType(_collateral);
// throw event
emit CollateralAdded(_collateral);
}
/**
* Deprecate collateral by not allowing any more collateral to be added of this type.
* Still can interact with it via validCollateral and CollateralParams
*/
function deprecateCollateral(address _collateral) external exists(_collateral) onlyOwner {
checkContract(_collateral);
require(collateralParams[_collateral].active, "collateral already deprecated");
collateralParams[_collateral].active = false;
// throw event
emit CollateralDeprecated(_collateral);
}
/**
* Undeprecate collateral by allowing more collateral to be added of this type.
* Still can interact with it via validCollateral and CollateralParams
*/
function undeprecateCollateral(address _collateral) external exists(_collateral) onlyOwner {
checkContract(_collateral);
require(!collateralParams[_collateral].active, "collateral is already active");
collateralParams[_collateral].active = true;
// throw event
emit CollateralUndeprecated(_collateral);
}
/**
* Function to change oracles
*/
function changeOracle(address _collateral, address _oracle)
external
exists(_collateral)
onlyOwner
{
checkContract(_collateral);
checkContract(_oracle);
collateralParams[_collateral].oracle = _oracle;
// throw event
emit OracleChanged(_collateral);
}
/**
* Function to change price curve
*/
function changePriceCurve(address _collateral, address _priceCurve)
external
exists(_collateral)
onlyOwner
{
checkContract(_collateral);
checkContract(_priceCurve);
uint lastFeePercent;
uint lastFeeTime;
(lastFeePercent, lastFeeTime) = IPriceCurve(collateralParams[_collateral].priceCurve).getFeeCapAndTime();
IPriceCurve(_priceCurve).setFeeCapAndTime(lastFeePercent, lastFeeTime);
collateralParams[_collateral].priceCurve = _priceCurve;
// throw event
emit PriceCurveChanged(_collateral);
}
/**
* Function to change Safety ratio.
*/
function changeRatio(address _collateral, uint256 _ratio)
external
exists(_collateral)
onlyOwner
{
checkContract(_collateral);
require(_ratio < 1100000000000000000, "ratio must be less than 1.10 => greater than 1.1 would mean taking out more YUSD than collateral VC");
collateralParams[_collateral].ratio = _ratio;
// throw event
emit RatioChanged(_collateral);
}
// -----------Routers--------------
function addValidRouter(address _router) external onlyOwner {
validRouter[_router] = true;
}
function removeValidRouter(address _router) external onlyOwner {
validRouter[_router] = false;
}
// ---------- View Functions -----------
function isValidRouter(address _router) external override view returns (bool) {
return validRouter[_router];
}
function isWrapped(address _collateral) external view override returns (bool) {
return collateralParams[_collateral].isWrapped;
}
function getValidCollateral() external view override returns (address[] memory) {
return validCollateral;
}
function getRatio(address _collateral)
public
view
override
exists(_collateral)
returns (uint256)
{
return collateralParams[_collateral].ratio;
}
function getOracle(address _collateral)
external
view
override
exists(_collateral)
returns (address)
{
return collateralParams[_collateral].oracle;
}
function getPriceCurve(address _collateral)
external
view
override
exists(_collateral)
returns (address)
{
return collateralParams[_collateral].priceCurve;
}
function getIsActive(address _collateral)
external
view
override
exists(_collateral)
returns (bool)
{
return collateralParams[_collateral].active;
}
function getDecimals(address _collateral)
external
view
override
exists(_collateral)
returns (uint256)
{
return collateralParams[_collateral].decimals;
}
function getIndex(address _collateral)
public
view
override
exists(_collateral)
returns (uint256)
{
return (collateralParams[_collateral].index);
}
// Returned as fee percentage * 10**18. View function for external callers.
function getFee(
address _collateral,
uint256 _collateralVCInput,
uint256 _collateralVCBalancePost,
uint256 _totalVCBalancePre,
uint256 _totalVCBalancePost
) external view override exists(_collateral) returns (uint256 fee) {
IPriceCurve priceCurve = IPriceCurve(collateralParams[_collateral].priceCurve);
return priceCurve.getFee(_collateralVCInput, _collateralVCBalancePost, _totalVCBalancePre, _totalVCBalancePost);
}
// Returned as fee percentage * 10**18. Non view function for just borrower operations to call.
function getFeeAndUpdate(
address _collateral,
uint256 _collateralVCInput,
uint256 _collateralVCBalancePost,
uint256 _totalVCBalancePre,
uint256 _totalVCBalancePost
) external override exists(_collateral) returns (uint256 fee) {
require(
msg.sender == borrowerOperationsAddress,
"only borrower operations can call this function"
);
IPriceCurve priceCurve = IPriceCurve(collateralParams[_collateral].priceCurve);
return
priceCurve.getFeeAndUpdate(
_collateralVCInput,
_collateralVCBalancePost,
_totalVCBalancePre,
_totalVCBalancePost
);
}
// should return 10**18 times the price in USD of 1 of the given _collateral
function getPrice(address _collateral)
public
view
override
exists(_collateral)
returns (uint256)
{
IPriceFeed collateral_priceFeed = IPriceFeed(collateralParams[_collateral].oracle);
uint256 price = collateral_priceFeed.fetchPrice_v();
return price;
}
// Gets the value of that collateral type, of that amount, in USD terms.
function getValueUSD(address _collateral, uint256 _amount)
external
view
override
exists(_collateral)
returns (uint256)
{
uint256 decimals = collateralParams[_collateral].decimals;
uint256 price = getPrice(_collateral);
return price.mul(_amount).div(10**decimals);
}
// Gets the value of that collateral type, of that amount, in VC terms.
function getValueVC(address _collateral, uint256 _amount)
public
view
override
exists(_collateral)
returns (uint256)
{
uint256 price = getPrice(_collateral);
uint256 decimals = collateralParams[_collateral].decimals;
uint256 ratio = collateralParams[_collateral].ratio;
// div by 10**18 for price adjustment
// and divide by 10 ** decimals for decimal adjustment
return (price.mul(_amount).mul(ratio).div(10**(18 + decimals)));
}
}