@ensuro/core 2.0.0-beta1 → 2.0.0-beta11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +36 -14
- package/build/contracts/AccessManager.sol/AccessManager.json +564 -0
- package/build/contracts/ERC4626AssetManager.sol/ERC4626AssetManager.json +238 -0
- package/build/contracts/EToken.sol/EToken.json +147 -46
- package/build/contracts/LPManualWhitelist.sol/LPManualWhitelist.json +23 -4
- package/build/contracts/LiquidityThresholdAssetManager.sol/LiquidityThresholdAssetManager.json +222 -0
- package/build/contracts/Policy.sol/Policy.json +2 -2
- package/build/contracts/PolicyPool.sol/PolicyPool.json +437 -61
- package/build/contracts/PolicyPoolComponent.sol/PolicyPoolComponent.json +21 -2
- package/build/contracts/PremiumsAccount.sol/PremiumsAccount.json +142 -16
- package/build/contracts/Reserve.sol/Reserve.json +85 -8
- package/build/contracts/RiskModule.sol/RiskModule.json +21 -2
- package/build/contracts/SignedQuoteRiskModule.sol/SignedQuoteRiskModule.json +979 -0
- package/build/contracts/TimeScaled.sol/TimeScaled.json +3 -17
- package/build/contracts/TrustfulRiskModule.sol/TrustfulRiskModule.json +24 -5
- package/build/contracts/{WadRayMath.sol → dependencies/WadRayMath.sol}/WadRayMath.json +3 -3
- package/build/contracts/interfaces/{IPolicyPoolConfig.sol/IPolicyPoolConfig.json → IAccessManager.sol/IAccessManager.json} +77 -59
- package/build/contracts/interfaces/IAssetManager.sol/IAssetManager.json +128 -0
- package/build/contracts/interfaces/IEToken.sol/IEToken.json +13 -0
- package/build/contracts/interfaces/IPolicyPool.sol/IPolicyPool.json +40 -16
- package/build/contracts/interfaces/IPolicyPoolComponent.sol/IPolicyPoolComponent.json +19 -0
- package/build/contracts/interfaces/IPremiumsAccount.sol/IPremiumsAccount.json +13 -0
- package/build/contracts/mocks/FixedRateVault.sol/FixedRateVault.json +736 -0
- package/build/contracts/mocks/ForwardProxy.sol/ForwardProxy.json +2 -2
- package/build/contracts/mocks/InterfaceIdCalculator.sol/InterfaceIdCalculator.json +180 -0
- package/build/contracts/mocks/PolicyHolderMock.sol/PolicyHolderMock.json +28 -2
- package/build/contracts/mocks/PolicyPoolComponentMock.sol/PolicyPoolComponentMock.json +21 -2
- package/build/contracts/mocks/PolicyPoolMock.sol/PolicyPoolMock.json +118 -19
- package/build/contracts/mocks/PolicyPoolMock.sol/PolicyPoolMockForward.json +6 -6
- package/build/contracts/mocks/RiskModuleMock.sol/RiskModuleMock.json +783 -0
- package/build/contracts/mocks/TestCurrency.sol/TestCurrency.json +2 -2
- package/build/contracts/mocks/TestNFT.sol/TestNFT.json +2 -2
- package/contracts/AccessManager.sol +132 -0
- package/contracts/ERC4626AssetManager.sol +55 -0
- package/contracts/EToken.sol +208 -102
- package/contracts/LPManualWhitelist.sol +19 -3
- package/contracts/LiquidityThresholdAssetManager.sol +175 -0
- package/contracts/Policy.sol +5 -3
- package/contracts/PolicyPool.sol +381 -116
- package/contracts/PolicyPoolComponent.sol +61 -44
- package/contracts/PremiumsAccount.sol +324 -86
- package/contracts/Reserve.sol +199 -4
- package/contracts/RiskModule.sol +62 -31
- package/contracts/SignedQuoteRiskModule.sol +248 -0
- package/contracts/TimeScaled.sol +19 -15
- package/contracts/TrustfulRiskModule.sol +69 -2
- package/contracts/dependencies/WadRayMath.sol +126 -0
- package/contracts/interfaces/IAccessManager.sol +148 -0
- package/contracts/interfaces/IAssetManager.sol +89 -0
- package/contracts/interfaces/IEToken.sol +25 -2
- package/contracts/interfaces/ILPWhitelist.sol +17 -0
- package/contracts/interfaces/IPolicyPool.sol +21 -14
- package/contracts/interfaces/IPolicyPoolComponent.sol +5 -1
- package/contracts/interfaces/IPremiumsAccount.sol +5 -0
- package/contracts/interfaces/IRiskModule.sol +67 -4
- package/contracts/mocks/FixedRateVault.sol +85 -0
- package/contracts/mocks/InterfaceIdCalculator.sol +32 -0
- package/contracts/mocks/PolicyHolderMock.sol +21 -0
- package/contracts/mocks/PolicyPoolComponentMock.sol +10 -0
- package/contracts/mocks/PolicyPoolMock.sol +41 -15
- package/contracts/mocks/RiskModuleMock.sol +75 -0
- package/js/deploy.js +704 -0
- package/js/test-utils.js +339 -159
- package/package.json +1 -1
- package/build/contracts/FlightDelayRiskModule.sol/FlightDelayRiskModule.json +0 -890
- package/build/contracts/PolicyNFT.sol/PolicyNFT.json +0 -583
- package/build/contracts/PolicyPoolConfig.sol/PolicyPoolConfig.json +0 -691
- package/build/contracts/dependencies/ChainlinkClientUpgradeable.sol/ChainlinkClientUpgradeable.json +0 -63
- package/build/contracts/interfaces/IPolicyNFT.sol/IPolicyNFT.json +0 -321
- package/build/contracts/mocks/LinkTokenMock.sol/LinkTokenMock.json +0 -370
- package/build/contracts/mocks/TestCurrencyUUPS.sol/TestCurrencyUUPS.json +0 -353
- package/build/contracts/upgraded/IPolicyNFTv1.sol/IPolicyNFTv1.json +0 -322
- package/build/contracts/upgraded/PolicyNFTv1.sol/PolicyNFTv1.json +0 -584
- package/build/contracts/upgraded/PolicyNFTv1.sol/PolicyNFTv1_Upgrade.json +0 -615
- package/contracts/FlightDelayRiskModule.sol +0 -217
- package/contracts/PolicyNFT.sol +0 -96
- package/contracts/PolicyPoolConfig.sol +0 -204
- package/contracts/WadRayMath.sol +0 -135
- package/contracts/dependencies/ChainlinkClientUpgradeable.sol +0 -371
- package/contracts/interfaces/IPolicyNFT.sol +0 -15
- package/contracts/interfaces/IPolicyPoolConfig.sol +0 -96
- package/contracts/mocks/LinkTokenMock.sol +0 -30
- package/contracts/upgraded/IPolicyNFTv1.sol +0 -15
- package/contracts/upgraded/PolicyNFTv1.sol +0 -126
package/contracts/EToken.sol
CHANGED
|
@@ -1,13 +1,19 @@
|
|
|
1
1
|
// SPDX-License-Identifier: Apache-2.0
|
|
2
2
|
pragma solidity ^0.8.0;
|
|
3
3
|
|
|
4
|
+
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
|
|
4
5
|
import {IERC20Metadata} from "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol";
|
|
5
6
|
import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
|
|
7
|
+
import {SafeCast} from "@openzeppelin/contracts/utils/math/SafeCast.sol";
|
|
8
|
+
import {Math} from "@openzeppelin/contracts/utils/math/Math.sol";
|
|
6
9
|
import {IPolicyPool} from "./interfaces/IPolicyPool.sol";
|
|
7
10
|
import {Reserve} from "./Reserve.sol";
|
|
8
11
|
import {IEToken} from "./interfaces/IEToken.sol";
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
12
|
+
import {IAccessManager} from "./interfaces/IAccessManager.sol";
|
|
13
|
+
import {IPolicyPoolComponent} from "./interfaces/IPolicyPoolComponent.sol";
|
|
14
|
+
import {ILPWhitelist} from "./interfaces/ILPWhitelist.sol";
|
|
15
|
+
import {IAssetManager} from "./interfaces/IAssetManager.sol";
|
|
16
|
+
import {WadRayMath} from "./dependencies/WadRayMath.sol";
|
|
11
17
|
import {TimeScaled} from "./TimeScaled.sol";
|
|
12
18
|
|
|
13
19
|
/**
|
|
@@ -24,8 +30,14 @@ contract EToken is Reserve, IERC20Metadata, IEToken {
|
|
|
24
30
|
using WadRayMath for uint256;
|
|
25
31
|
using TimeScaled for TimeScaled.ScaledAmount;
|
|
26
32
|
using SafeERC20 for IERC20Metadata;
|
|
33
|
+
using SafeCast for uint256;
|
|
27
34
|
|
|
28
|
-
uint256 internal constant
|
|
35
|
+
uint256 internal constant FOUR_DECIMAL_TO_WAD = 1e14;
|
|
36
|
+
uint16 internal constant HUNDRED_PERCENT = 1e4;
|
|
37
|
+
uint16 internal constant MAX_UR_MIN = 5e3; // 50% - Minimum value for Max Utilization Rate
|
|
38
|
+
uint16 internal constant LIQ_REQ_MIN = 8e3; // 80%
|
|
39
|
+
uint16 internal constant LIQ_REQ_MAX = 13e3; // 130%
|
|
40
|
+
uint16 internal constant INT_LOAN_IR_MAX = 5e3; // 50% - Maximum value for InternalLoan interest rate
|
|
29
41
|
|
|
30
42
|
// Attributes taken from ERC20
|
|
31
43
|
mapping(address => uint256) private _balances;
|
|
@@ -52,13 +64,17 @@ contract EToken is Reserve, IERC20Metadata, IEToken {
|
|
|
52
64
|
uint16 minUtilizationRate; // Min utilization rate, to reject deposits that leave UR under this value - 4 decimals
|
|
53
65
|
uint16 maxUtilizationRate; // Max utilization rate, to reject lockScr that leave UR above this value - 4 decimals
|
|
54
66
|
uint16 internalLoanInterestRate; // Annualized interest rate charged to internal borrowers (premiums accounts) - 4dec
|
|
67
|
+
ILPWhitelist whitelist; // Whitelist for deposits and transfers
|
|
55
68
|
}
|
|
56
69
|
|
|
57
70
|
PackedParams internal _params;
|
|
58
71
|
|
|
72
|
+
IAssetManager internal _assetManager;
|
|
73
|
+
|
|
59
74
|
event InternalLoan(address indexed borrower, uint256 value, uint256 amountAsked);
|
|
60
75
|
event InternalLoanRepaid(address indexed borrower, uint256 value);
|
|
61
|
-
event
|
|
76
|
+
event InternalBorrowerAdded(address indexed borrower);
|
|
77
|
+
event InternalBorrowerRemoved(address indexed borrower, uint256 defaultedDebt);
|
|
62
78
|
|
|
63
79
|
modifier onlyBorrower() {
|
|
64
80
|
require(_loans[_msgSender()].scale != 0, "The caller must be a borrower");
|
|
@@ -82,7 +98,7 @@ contract EToken is Reserve, IERC20Metadata, IEToken {
|
|
|
82
98
|
uint256 maxUtilizationRate_,
|
|
83
99
|
uint256 internalLoanInterestRate_
|
|
84
100
|
) public initializer {
|
|
85
|
-
|
|
101
|
+
__Reserve_init();
|
|
86
102
|
__EToken_init_unchained(name_, symbol_, maxUtilizationRate_, internalLoanInterestRate_);
|
|
87
103
|
}
|
|
88
104
|
|
|
@@ -92,7 +108,9 @@ contract EToken is Reserve, IERC20Metadata, IEToken {
|
|
|
92
108
|
string memory symbol_,
|
|
93
109
|
uint256 maxUtilizationRate_,
|
|
94
110
|
uint256 internalLoanInterestRate_
|
|
95
|
-
) internal
|
|
111
|
+
) internal onlyInitializing {
|
|
112
|
+
require(bytes(name_).length > 0, "EToken: name cannot be empty");
|
|
113
|
+
require(bytes(symbol_).length > 0, "EToken: symbol cannot be empty");
|
|
96
114
|
_name = name_;
|
|
97
115
|
_symbol = symbol_;
|
|
98
116
|
_tsScaled.init();
|
|
@@ -102,28 +120,52 @@ contract EToken is Reserve, IERC20Metadata, IEToken {
|
|
|
102
120
|
tokenInterestRate: 0
|
|
103
121
|
}); */
|
|
104
122
|
_params = PackedParams({
|
|
105
|
-
maxUtilizationRate:
|
|
106
|
-
liquidityRequirement:
|
|
123
|
+
maxUtilizationRate: _wadTo4(maxUtilizationRate_),
|
|
124
|
+
liquidityRequirement: HUNDRED_PERCENT,
|
|
107
125
|
minUtilizationRate: 0,
|
|
108
|
-
internalLoanInterestRate:
|
|
126
|
+
internalLoanInterestRate: _wadTo4(internalLoanInterestRate_),
|
|
127
|
+
whitelist: ILPWhitelist(address(0))
|
|
109
128
|
});
|
|
110
129
|
|
|
111
130
|
_validateParameters();
|
|
112
131
|
}
|
|
113
132
|
|
|
133
|
+
/**
|
|
134
|
+
* @dev See {IERC165-supportsInterface}.
|
|
135
|
+
*/
|
|
136
|
+
function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
|
|
137
|
+
return
|
|
138
|
+
super.supportsInterface(interfaceId) ||
|
|
139
|
+
interfaceId == type(IERC20).interfaceId ||
|
|
140
|
+
interfaceId == type(IERC20Metadata).interfaceId ||
|
|
141
|
+
interfaceId == type(IEToken).interfaceId;
|
|
142
|
+
}
|
|
143
|
+
|
|
114
144
|
// runs validation on EToken parameters
|
|
115
145
|
function _validateParameters() internal view override {
|
|
116
146
|
require(
|
|
117
|
-
_params.liquidityRequirement >=
|
|
147
|
+
_params.liquidityRequirement >= LIQ_REQ_MIN && _params.liquidityRequirement <= LIQ_REQ_MAX,
|
|
118
148
|
"Validation: liquidityRequirement must be [0.8, 1.3]"
|
|
119
149
|
);
|
|
120
150
|
require(
|
|
121
|
-
_params.maxUtilizationRate >=
|
|
151
|
+
_params.maxUtilizationRate >= MAX_UR_MIN && _params.maxUtilizationRate <= HUNDRED_PERCENT,
|
|
122
152
|
"Validation: maxUtilizationRate must be [0.5, 1]"
|
|
123
153
|
);
|
|
124
|
-
require(_params.minUtilizationRate <= 1e4, "Validation: minUtilizationRate must be [0, 1]");
|
|
125
154
|
require(
|
|
126
|
-
_params.
|
|
155
|
+
_params.minUtilizationRate <= HUNDRED_PERCENT,
|
|
156
|
+
"Validation: minUtilizationRate must be [0, 1]"
|
|
157
|
+
);
|
|
158
|
+
/*
|
|
159
|
+
* We don't validate minUtilizationRate < maxUtilizationRate because the opposite is valid too.
|
|
160
|
+
* These limits aren't strong limits on the values the utilization rate can take, but instead they are
|
|
161
|
+
* limits on specific operations.
|
|
162
|
+
* `minUtilizationRate` is used to avoid new deposits to dilute the yields of existing LPs, but it doesn't
|
|
163
|
+
* prevent the UR from going down in other operations (`unlockScr` for example).
|
|
164
|
+
* `maxUtilizationRate` is used to prevent selling more coverage when UR is too high, only checked on `lockScr`
|
|
165
|
+
* operations, but not in withdrawals or other operations.
|
|
166
|
+
*/
|
|
167
|
+
require(
|
|
168
|
+
_params.internalLoanInterestRate <= INT_LOAN_IR_MAX,
|
|
127
169
|
"Validation: internalLoanInterestRate must be <= 50%"
|
|
128
170
|
);
|
|
129
171
|
}
|
|
@@ -234,15 +276,34 @@ contract EToken is Reserve, IERC20Metadata, IEToken {
|
|
|
234
276
|
address recipient,
|
|
235
277
|
uint256 amount
|
|
236
278
|
) public virtual override returns (bool) {
|
|
279
|
+
address spender = _msgSender();
|
|
280
|
+
_spendAllowance(sender, spender, amount);
|
|
237
281
|
_transfer(sender, recipient, amount);
|
|
238
|
-
|
|
239
|
-
uint256 currentAllowance = _allowances[sender][_msgSender()];
|
|
240
|
-
require(currentAllowance >= amount, "EToken: transfer amount exceeds allowance");
|
|
241
|
-
_approve(sender, _msgSender(), currentAllowance - amount);
|
|
242
|
-
|
|
243
282
|
return true;
|
|
244
283
|
}
|
|
245
284
|
|
|
285
|
+
/**
|
|
286
|
+
* @dev Updates `owner` s allowance for `spender` based on spent `amount`.
|
|
287
|
+
*
|
|
288
|
+
* Does not update the allowance amount in case of infinite allowance.
|
|
289
|
+
* Revert if not enough allowance is available.
|
|
290
|
+
*
|
|
291
|
+
* Might emit an {Approval} event.
|
|
292
|
+
*/
|
|
293
|
+
function _spendAllowance(
|
|
294
|
+
address owner,
|
|
295
|
+
address spender,
|
|
296
|
+
uint256 amount
|
|
297
|
+
) internal virtual {
|
|
298
|
+
uint256 currentAllowance = allowance(owner, spender);
|
|
299
|
+
if (currentAllowance != type(uint256).max) {
|
|
300
|
+
require(currentAllowance >= amount, "EToken: insufficient allowance");
|
|
301
|
+
unchecked {
|
|
302
|
+
_approve(owner, spender, currentAllowance - amount);
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
|
|
246
307
|
/**
|
|
247
308
|
* @dev Atomically increases the allowance granted to `spender` by the caller.
|
|
248
309
|
*
|
|
@@ -256,7 +317,7 @@ contract EToken is Reserve, IERC20Metadata, IEToken {
|
|
|
256
317
|
* - `spender` cannot be the zero address.
|
|
257
318
|
*/
|
|
258
319
|
function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) {
|
|
259
|
-
_approve(_msgSender(), spender,
|
|
320
|
+
_approve(_msgSender(), spender, allowance(_msgSender(), spender) + addedValue);
|
|
260
321
|
return true;
|
|
261
322
|
}
|
|
262
323
|
|
|
@@ -330,6 +391,7 @@ contract EToken is Reserve, IERC20Metadata, IEToken {
|
|
|
330
391
|
*/
|
|
331
392
|
function _mint(address account, uint256 amount) internal virtual {
|
|
332
393
|
require(account != address(0), "EToken: mint to the zero address");
|
|
394
|
+
require(amount > 0, "EToken: amount to mint should be greater than zero");
|
|
333
395
|
|
|
334
396
|
_beforeTokenTransfer(address(0), account, amount);
|
|
335
397
|
uint256 scaledAmount = _tsScaled.add(amount, tokenInterestRate());
|
|
@@ -403,12 +465,12 @@ contract EToken is Reserve, IERC20Metadata, IEToken {
|
|
|
403
465
|
address from,
|
|
404
466
|
address to,
|
|
405
467
|
uint256 amount
|
|
406
|
-
) internal virtual {
|
|
468
|
+
) internal virtual whenNotPaused {
|
|
407
469
|
require(
|
|
408
470
|
from == address(0) ||
|
|
409
471
|
to == address(0) ||
|
|
410
|
-
address(
|
|
411
|
-
|
|
472
|
+
address(_params.whitelist) == address(0) ||
|
|
473
|
+
_params.whitelist.acceptsTransfer(this, from, to, amount),
|
|
412
474
|
"Transfer not allowed - Liquidity Provider not whitelisted"
|
|
413
475
|
);
|
|
414
476
|
}
|
|
@@ -419,9 +481,10 @@ contract EToken is Reserve, IERC20Metadata, IEToken {
|
|
|
419
481
|
uint256 totalSupply_ = this.totalSupply();
|
|
420
482
|
if (totalSupply_ == 0) _scr.tokenInterestRate = 0;
|
|
421
483
|
else {
|
|
422
|
-
_scr.tokenInterestRate =
|
|
423
|
-
|
|
424
|
-
|
|
484
|
+
_scr.tokenInterestRate = uint256(_scr.interestRate)
|
|
485
|
+
.wadMul(uint256(_scr.scr))
|
|
486
|
+
.wadDiv(totalSupply_)
|
|
487
|
+
.toUint64();
|
|
425
488
|
}
|
|
426
489
|
}
|
|
427
490
|
|
|
@@ -443,6 +506,25 @@ contract EToken is Reserve, IERC20Metadata, IEToken {
|
|
|
443
506
|
else return 0;
|
|
444
507
|
}
|
|
445
508
|
|
|
509
|
+
function assetManager() public view override returns (IAssetManager) {
|
|
510
|
+
return _assetManager;
|
|
511
|
+
}
|
|
512
|
+
|
|
513
|
+
function _setAssetManager(IAssetManager newAM) internal override {
|
|
514
|
+
_assetManager = newAM;
|
|
515
|
+
}
|
|
516
|
+
|
|
517
|
+
// solhint-disable-next-line func-name-mixedcase
|
|
518
|
+
function _4toWad(uint16 value) internal pure returns (uint256) {
|
|
519
|
+
// 4 decimals to Wad (18 decimals)
|
|
520
|
+
return uint256(value) * FOUR_DECIMAL_TO_WAD;
|
|
521
|
+
}
|
|
522
|
+
|
|
523
|
+
function _wadTo4(uint256 value) internal pure returns (uint16) {
|
|
524
|
+
// Wad to 4 decimals
|
|
525
|
+
return (value / FOUR_DECIMAL_TO_WAD).toUint16();
|
|
526
|
+
}
|
|
527
|
+
|
|
446
528
|
function scr() public view virtual override returns (uint256) {
|
|
447
529
|
return uint256(_scr.scr);
|
|
448
530
|
}
|
|
@@ -456,39 +538,41 @@ contract EToken is Reserve, IERC20Metadata, IEToken {
|
|
|
456
538
|
}
|
|
457
539
|
|
|
458
540
|
function liquidityRequirement() public view returns (uint256) {
|
|
459
|
-
return
|
|
541
|
+
return _4toWad(_params.liquidityRequirement);
|
|
460
542
|
}
|
|
461
543
|
|
|
462
544
|
function maxUtilizationRate() public view returns (uint256) {
|
|
463
|
-
return
|
|
545
|
+
return _4toWad(_params.maxUtilizationRate);
|
|
464
546
|
}
|
|
465
547
|
|
|
466
548
|
function minUtilizationRate() public view returns (uint256) {
|
|
467
|
-
return
|
|
549
|
+
return _4toWad(_params.minUtilizationRate);
|
|
468
550
|
}
|
|
469
551
|
|
|
470
552
|
function utilizationRate() public view returns (uint256) {
|
|
471
553
|
return uint256(_scr.scr).wadDiv(this.totalSupply());
|
|
472
554
|
}
|
|
473
555
|
|
|
474
|
-
function lockScr(uint256 scrAmount, uint256 policyInterestRate)
|
|
556
|
+
function lockScr(uint256 scrAmount, uint256 policyInterestRate)
|
|
557
|
+
external
|
|
558
|
+
override
|
|
559
|
+
onlyBorrower
|
|
560
|
+
whenNotPaused
|
|
561
|
+
{
|
|
475
562
|
require(
|
|
476
563
|
scrAmount <= this.fundsAvailableToLock(),
|
|
477
|
-
"Not
|
|
564
|
+
"Not enough funds available to cover the SCR"
|
|
478
565
|
);
|
|
479
566
|
_tsScaled.updateScale(tokenInterestRate());
|
|
480
567
|
if (_scr.scr == 0) {
|
|
481
|
-
_scr.scr =
|
|
482
|
-
_scr.interestRate =
|
|
568
|
+
_scr.scr = scrAmount.toUint128();
|
|
569
|
+
_scr.interestRate = policyInterestRate.toUint64();
|
|
483
570
|
} else {
|
|
484
571
|
uint256 origScr = uint256(_scr.scr);
|
|
485
572
|
uint256 newScr = origScr + scrAmount;
|
|
486
|
-
_scr.interestRate =
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
)
|
|
490
|
-
);
|
|
491
|
-
_scr.scr = uint128(newScr);
|
|
573
|
+
_scr.interestRate = (uint256(_scr.interestRate).wadMul(origScr) +
|
|
574
|
+
policyInterestRate.wadMul(scrAmount)).wadDiv(newScr).toUint64();
|
|
575
|
+
_scr.scr = newScr.toUint128();
|
|
492
576
|
}
|
|
493
577
|
emit SCRLocked(policyInterestRate, scrAmount);
|
|
494
578
|
_updateTokenInterestRate();
|
|
@@ -498,7 +582,7 @@ contract EToken is Reserve, IERC20Metadata, IEToken {
|
|
|
498
582
|
uint256 scrAmount,
|
|
499
583
|
uint256 policyInterestRate,
|
|
500
584
|
int256 adjustment
|
|
501
|
-
) external override onlyBorrower {
|
|
585
|
+
) external override onlyBorrower whenNotPaused {
|
|
502
586
|
require(scrAmount <= uint256(_scr.scr), "Current SCR less than the amount you want to unlock");
|
|
503
587
|
_tsScaled.updateScale(tokenInterestRate());
|
|
504
588
|
|
|
@@ -508,17 +592,18 @@ contract EToken is Reserve, IERC20Metadata, IEToken {
|
|
|
508
592
|
} else {
|
|
509
593
|
uint256 origScr = uint256(_scr.scr);
|
|
510
594
|
uint256 newScr = origScr - scrAmount;
|
|
511
|
-
_scr.interestRate =
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
)
|
|
515
|
-
);
|
|
516
|
-
_scr.scr = uint128(newScr);
|
|
595
|
+
_scr.interestRate = (uint256(_scr.interestRate).wadMul(origScr) -
|
|
596
|
+
policyInterestRate.wadMul(scrAmount)).wadDiv(newScr).toUint64();
|
|
597
|
+
_scr.scr = newScr.toUint128();
|
|
517
598
|
}
|
|
518
599
|
emit SCRUnlocked(policyInterestRate, scrAmount);
|
|
519
600
|
_discreteChange(adjustment);
|
|
520
601
|
}
|
|
521
602
|
|
|
603
|
+
function _assetEarnings(int256 earnings) internal override {
|
|
604
|
+
_discreteChange(earnings);
|
|
605
|
+
}
|
|
606
|
+
|
|
522
607
|
function _discreteChange(int256 amount) internal {
|
|
523
608
|
_tsScaled.discreteChange(amount, tokenInterestRate());
|
|
524
609
|
_updateTokenInterestRate();
|
|
@@ -528,12 +613,11 @@ contract EToken is Reserve, IERC20Metadata, IEToken {
|
|
|
528
613
|
external
|
|
529
614
|
override
|
|
530
615
|
onlyPolicyPool
|
|
531
|
-
whenNotPaused
|
|
532
616
|
returns (uint256)
|
|
533
617
|
{
|
|
534
618
|
require(
|
|
535
|
-
address(
|
|
536
|
-
|
|
619
|
+
address(_params.whitelist) == address(0) ||
|
|
620
|
+
_params.whitelist.acceptsDeposit(this, provider, amount),
|
|
537
621
|
"Liquidity Provider not whitelisted"
|
|
538
622
|
);
|
|
539
623
|
_mint(provider, amount);
|
|
@@ -553,14 +637,15 @@ contract EToken is Reserve, IERC20Metadata, IEToken {
|
|
|
553
637
|
external
|
|
554
638
|
override
|
|
555
639
|
onlyPolicyPool
|
|
556
|
-
whenNotPaused
|
|
557
640
|
returns (uint256)
|
|
558
641
|
{
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
642
|
+
/**
|
|
643
|
+
* Here we don't check for maxUtilizationRate because that limit only affects locking more capital (`lockScr`), but
|
|
644
|
+
* doesn't affects the right of liquidity providers to withdraw their funds.
|
|
645
|
+
* The only limit for withdraws is the `totalWithdrawable()` function, that's affected by the relation between the
|
|
646
|
+
* scr and the totalSupply.
|
|
647
|
+
*/
|
|
648
|
+
amount = Math.min(amount, Math.min(balanceOf(provider), totalWithdrawable()));
|
|
564
649
|
if (amount == 0) return 0;
|
|
565
650
|
_burn(provider, amount);
|
|
566
651
|
_updateTokenInterestRate();
|
|
@@ -569,25 +654,32 @@ contract EToken is Reserve, IERC20Metadata, IEToken {
|
|
|
569
654
|
}
|
|
570
655
|
|
|
571
656
|
function addBorrower(address borrower) external override onlyPolicyPool {
|
|
657
|
+
require(borrower != address(0), "EToken: Borrower cannot be the zero address");
|
|
572
658
|
TimeScaled.ScaledAmount storage loan = _loans[borrower];
|
|
573
659
|
if (loan.scale == 0) {
|
|
574
660
|
loan.init();
|
|
575
|
-
emit
|
|
661
|
+
emit InternalBorrowerAdded(borrower);
|
|
576
662
|
}
|
|
577
663
|
}
|
|
578
664
|
|
|
665
|
+
function removeBorrower(address borrower) external override onlyPolicyPool {
|
|
666
|
+
require(borrower != address(0), "EToken: Borrower cannot be the zero address");
|
|
667
|
+
uint256 defaultedDebt = getLoan(borrower);
|
|
668
|
+
delete _loans[borrower];
|
|
669
|
+
emit InternalBorrowerRemoved(borrower, defaultedDebt);
|
|
670
|
+
}
|
|
671
|
+
|
|
579
672
|
function internalLoan(
|
|
580
673
|
uint256 amount,
|
|
581
674
|
address receiver,
|
|
582
675
|
bool fromAvailable
|
|
583
676
|
) external override onlyBorrower whenNotPaused returns (uint256) {
|
|
584
677
|
uint256 amountAsked = amount;
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
}
|
|
678
|
+
amount = Math.min(
|
|
679
|
+
Math.min(amount, fromAvailable ? fundsAvailable() : totalSupply()),
|
|
680
|
+
_tsScaled.maxNegativeAdjustment(tokenInterestRate())
|
|
681
|
+
);
|
|
682
|
+
if (amount == 0) return amountAsked;
|
|
591
683
|
TimeScaled.ScaledAmount storage loan = _loans[_msgSender()];
|
|
592
684
|
loan.add(amount, internalLoanInterestRate());
|
|
593
685
|
_discreteChange(-int256(amount));
|
|
@@ -596,77 +688,91 @@ contract EToken is Reserve, IERC20Metadata, IEToken {
|
|
|
596
688
|
return amountAsked - amount;
|
|
597
689
|
}
|
|
598
690
|
|
|
599
|
-
function repayLoan(uint256 amount, address onBehalfOf) external override {
|
|
691
|
+
function repayLoan(uint256 amount, address onBehalfOf) external override whenNotPaused {
|
|
692
|
+
require(amount > 0, "EToken: amount should be greater than zero.");
|
|
600
693
|
// Anyone can call this method, since it has to pay
|
|
601
|
-
currency().safeTransferFrom(_msgSender(), address(this), amount);
|
|
602
694
|
TimeScaled.ScaledAmount storage loan = _loans[onBehalfOf];
|
|
603
695
|
require(loan.scale != 0, "Not a registered borrower");
|
|
604
696
|
loan.sub(amount, internalLoanInterestRate());
|
|
605
697
|
_discreteChange(int256(amount));
|
|
606
698
|
emit InternalLoanRepaid(onBehalfOf, amount);
|
|
699
|
+
// Interaction at the end for security reasons
|
|
700
|
+
currency().safeTransferFrom(_msgSender(), address(this), amount);
|
|
607
701
|
}
|
|
608
702
|
|
|
609
703
|
function getLoan(address borrower) public view virtual override returns (uint256) {
|
|
610
704
|
TimeScaled.ScaledAmount storage loan = _loans[borrower];
|
|
611
|
-
if (loan.scale == 0) return 0;
|
|
612
705
|
return loan.getScaledAmount(internalLoanInterestRate());
|
|
613
706
|
}
|
|
614
707
|
|
|
615
708
|
function internalLoanInterestRate() public view returns (uint256) {
|
|
616
|
-
return
|
|
709
|
+
return _4toWad(_params.internalLoanInterestRate);
|
|
617
710
|
}
|
|
618
711
|
|
|
619
|
-
function
|
|
712
|
+
function setParam(Parameter param, uint256 newValue)
|
|
620
713
|
external
|
|
621
|
-
|
|
714
|
+
onlyGlobalOrComponentRole2(LEVEL2_ROLE, LEVEL3_ROLE)
|
|
622
715
|
{
|
|
623
716
|
bool tweak = !hasPoolRole(LEVEL2_ROLE);
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
717
|
+
if (param == Parameter.liquidityRequirement) {
|
|
718
|
+
require(
|
|
719
|
+
!tweak || _isTweakWad(liquidityRequirement(), newValue, 1e17),
|
|
720
|
+
"Tweak exceeded: liquidityRequirement tweaks only up to 10%"
|
|
721
|
+
);
|
|
722
|
+
_params.liquidityRequirement = _wadTo4(newValue);
|
|
723
|
+
} else if (param == Parameter.minUtilizationRate) {
|
|
724
|
+
require(
|
|
725
|
+
!tweak || _isTweakWad(minUtilizationRate(), newValue, 3e17),
|
|
726
|
+
"Tweak exceeded: minUtilizationRate tweaks only up to 30%"
|
|
727
|
+
);
|
|
728
|
+
_params.minUtilizationRate = _wadTo4(newValue);
|
|
729
|
+
} else if (param == Parameter.maxUtilizationRate) {
|
|
730
|
+
require(
|
|
731
|
+
!tweak || _isTweakWad(maxUtilizationRate(), newValue, 3e17),
|
|
732
|
+
"Tweak exceeded: maxUtilizationRate tweaks only up to 30%"
|
|
733
|
+
);
|
|
734
|
+
_params.maxUtilizationRate = _wadTo4(newValue);
|
|
735
|
+
} else if (param == Parameter.internalLoanInterestRate) {
|
|
736
|
+
require(
|
|
737
|
+
!tweak || _isTweakWad(internalLoanInterestRate(), newValue, 3e17),
|
|
738
|
+
"Tweak exceeded: internalLoanInterestRate tweaks only up to 30%"
|
|
739
|
+
);
|
|
740
|
+
// This call changes the interest rate without updating the current loans up to this point
|
|
741
|
+
// So, if interest rate goes from 5% to 6%, this change will be retroactive to the lastUpdate of each
|
|
742
|
+
// loan. Since it's a permissioned call, I'm ok with this. If a caller wants to reduce the impact, it can
|
|
743
|
+
// issue 1 wei repayLoan to each active loan, forcing the update of the scales
|
|
744
|
+
_params.internalLoanInterestRate = _wadTo4(newValue);
|
|
745
|
+
}
|
|
633
746
|
_parameterChanged(
|
|
634
|
-
|
|
635
|
-
|
|
747
|
+
IAccessManager.GovernanceActions(
|
|
748
|
+
uint256(IAccessManager.GovernanceActions.setLiquidityRequirement) + uint256(param)
|
|
749
|
+
),
|
|
750
|
+
newValue,
|
|
636
751
|
tweak
|
|
637
752
|
);
|
|
638
753
|
}
|
|
639
754
|
|
|
640
|
-
function
|
|
755
|
+
function setWhitelist(ILPWhitelist lpWhitelist_)
|
|
641
756
|
external
|
|
642
|
-
|
|
757
|
+
onlyGlobalOrComponentRole2(GUARDIAN_ROLE, LEVEL1_ROLE)
|
|
643
758
|
{
|
|
644
|
-
bool tweak = !hasPoolRole(LEVEL2_ROLE);
|
|
645
759
|
require(
|
|
646
|
-
|
|
647
|
-
|
|
760
|
+
address(lpWhitelist_) == address(0) ||
|
|
761
|
+
IPolicyPoolComponent(address(lpWhitelist_)).policyPool() == _policyPool,
|
|
762
|
+
"Component not linked to this PolicyPool"
|
|
648
763
|
);
|
|
649
|
-
_params.
|
|
650
|
-
|
|
764
|
+
_params.whitelist = lpWhitelist_;
|
|
765
|
+
_componentChanged(IAccessManager.GovernanceActions.setLPWhitelist, address(lpWhitelist_));
|
|
651
766
|
}
|
|
652
767
|
|
|
653
|
-
function
|
|
654
|
-
|
|
655
|
-
require(
|
|
656
|
-
!tweak || _isTweakWad(maxUtilizationRate(), newRate, 3e17),
|
|
657
|
-
"Tweak exceeded: maxUtilizationRate tweaks only up to 30%"
|
|
658
|
-
);
|
|
659
|
-
_params.maxUtilizationRate = uint16(newRate / 1e14);
|
|
660
|
-
_parameterChanged(IPolicyPoolConfig.GovernanceActions.setMaxUtilizationRate, newRate, tweak);
|
|
768
|
+
function whitelist() external view returns (ILPWhitelist) {
|
|
769
|
+
return _params.whitelist;
|
|
661
770
|
}
|
|
662
771
|
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
_params.minUtilizationRate = uint16(newRate / 1e14);
|
|
670
|
-
_parameterChanged(IPolicyPoolConfig.GovernanceActions.setMinUtilizationRate, newRate, tweak);
|
|
671
|
-
}
|
|
772
|
+
/**
|
|
773
|
+
* @dev This empty reserved space is put in place to allow future versions to add new
|
|
774
|
+
* variables without shifting down storage in the inheritance chain.
|
|
775
|
+
* See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
|
|
776
|
+
*/
|
|
777
|
+
uint256[41] private __gap;
|
|
672
778
|
}
|
|
@@ -32,10 +32,19 @@ contract LPManualWhitelist is ILPWhitelist, PolicyPoolComponent {
|
|
|
32
32
|
|
|
33
33
|
function whitelistAddress(address provider, bool whitelisted)
|
|
34
34
|
external
|
|
35
|
-
|
|
35
|
+
onlyComponentRole(LP_WHITELIST_ROLE)
|
|
36
36
|
{
|
|
37
|
-
_whitelisted[provider]
|
|
38
|
-
|
|
37
|
+
if (_whitelisted[provider] != whitelisted) {
|
|
38
|
+
_whitelisted[provider] = whitelisted;
|
|
39
|
+
emit LPWhitelisted(provider, whitelisted);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* @dev See {IERC165-supportsInterface}.
|
|
45
|
+
*/
|
|
46
|
+
function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
|
|
47
|
+
return super.supportsInterface(interfaceId) || interfaceId == type(ILPWhitelist).interfaceId;
|
|
39
48
|
}
|
|
40
49
|
|
|
41
50
|
function acceptsDeposit(
|
|
@@ -54,4 +63,11 @@ contract LPManualWhitelist is ILPWhitelist, PolicyPoolComponent {
|
|
|
54
63
|
) external view override returns (bool) {
|
|
55
64
|
return _whitelisted[providerTo];
|
|
56
65
|
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* @dev This empty reserved space is put in place to allow future versions to add new
|
|
69
|
+
* variables without shifting down storage in the inheritance chain.
|
|
70
|
+
* See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
|
|
71
|
+
*/
|
|
72
|
+
uint256[49] private __gap;
|
|
57
73
|
}
|