@ensuro/core 1.2.7 → 2.0.0-beta1
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 +44 -17
- package/build/contracts/EToken.sol/EToken.json +122 -177
- package/build/contracts/FlightDelayRiskModule.sol/FlightDelayRiskModule.json +101 -323
- package/build/contracts/LPManualWhitelist.sol/LPManualWhitelist.json +15 -2
- package/build/contracts/Policy.sol/Policy.json +2 -2
- package/build/contracts/PolicyNFT.sol/PolicyNFT.json +16 -3
- package/build/contracts/PolicyPool.sol/PolicyPool.json +105 -351
- package/build/contracts/PolicyPoolComponent.sol/PolicyPoolComponent.json +13 -0
- package/build/contracts/PolicyPoolConfig.sol/PolicyPoolConfig.json +77 -72
- package/build/contracts/PremiumsAccount.sol/PremiumsAccount.json +761 -0
- package/build/contracts/{BaseAssetManager.sol/BaseAssetManager.json → Reserve.sol/Reserve.json} +15 -202
- package/build/contracts/RiskModule.sol/RiskModule.json +83 -310
- package/build/contracts/TimeScaled.sol/TimeScaled.json +24 -0
- package/build/contracts/TrustfulRiskModule.sol/TrustfulRiskModule.json +131 -333
- package/build/contracts/dependencies/ChainlinkClientUpgradeable.sol/ChainlinkClientUpgradeable.json +15 -2
- package/build/contracts/dependencies/ERC1967Proxy.sol/ERC1967Proxy.json +64 -0
- package/build/{interfaces/IExchange.sol/IExchange.json → contracts/dependencies/IERC20Metadata.sol/IERC20Metadata.json} +83 -79
- package/build/{interfaces → contracts/interfaces}/IEToken.sol/IEToken.json +32 -97
- package/build/{interfaces → contracts/interfaces}/ILPWhitelist.sol/ILPWhitelist.json +1 -1
- package/build/{interfaces → contracts/interfaces}/IPolicyHolder.sol/IPolicyHolder.json +1 -1
- package/build/{interfaces → contracts/interfaces}/IPolicyNFT.sol/IPolicyNFT.json +1 -1
- package/build/{interfaces → contracts/interfaces}/IPolicyPool.sol/IPolicyPool.json +121 -108
- package/build/{interfaces → contracts/interfaces}/IPolicyPoolComponent.sol/IPolicyPoolComponent.json +1 -1
- package/build/{interfaces → contracts/interfaces}/IPolicyPoolConfig.sol/IPolicyPoolConfig.json +20 -36
- package/build/contracts/interfaces/IPremiumsAccount.sol/IPremiumsAccount.json +302 -0
- package/build/{interfaces → contracts/interfaces}/IRiskModule.sol/IRiskModule.json +58 -34
- package/build/contracts/mocks/ForwardProxy.sol/ForwardProxy.json +43 -0
- package/build/{interfaces/IInsolvencyHook.sol/IInsolvencyHook.json → contracts/mocks/IMintableERC20.sol/IMintableERC20.json} +13 -8
- package/build/contracts/mocks/LinkTokenMock.sol/LinkTokenMock.json +370 -0
- package/build/contracts/mocks/PolicyHolderMock.sol/PolicyHolderMock.json +202 -0
- package/build/contracts/mocks/PolicyPoolComponentMock.sol/PolicyPoolComponentMock.json +35 -0
- package/build/contracts/mocks/PolicyPoolMock.sol/PolicyPoolMock.json +603 -0
- package/build/contracts/mocks/PolicyPoolMock.sol/PolicyPoolMockForward.json +92 -0
- package/build/contracts/mocks/TestCurrency.sol/TestCurrency.json +343 -0
- package/build/contracts/mocks/TestCurrencyUUPS.sol/TestCurrencyUUPS.json +353 -0
- package/build/contracts/mocks/TestNFT.sol/TestNFT.json +388 -0
- package/build/contracts/upgraded/PolicyNFTv1.sol/PolicyNFTv1.json +16 -3
- package/build/contracts/upgraded/PolicyNFTv1.sol/PolicyNFTv1_Upgrade.json +16 -3
- package/contracts/EToken.sol +188 -269
- package/contracts/FlightDelayRiskModule.sol +30 -21
- package/contracts/LPManualWhitelist.sol +3 -3
- package/contracts/Policy.sol +48 -44
- package/contracts/PolicyNFT.sol +2 -2
- package/contracts/PolicyPool.sol +114 -467
- package/contracts/PolicyPoolComponent.sol +8 -3
- package/contracts/PolicyPoolConfig.sol +30 -73
- package/contracts/PremiumsAccount.sol +274 -0
- package/contracts/Reserve.sol +34 -0
- package/contracts/RiskModule.sol +216 -164
- package/contracts/TimeScaled.sol +134 -0
- package/contracts/TrustfulRiskModule.sol +23 -21
- package/contracts/dependencies/ERC1967Proxy.sol +19 -0
- package/contracts/dependencies/IERC20Metadata.sol +19 -0
- package/contracts/interfaces/IEToken.sol +172 -0
- package/{interfaces → contracts/interfaces}/ILPWhitelist.sol +0 -0
- package/{interfaces → contracts/interfaces}/IPolicyHolder.sol +0 -0
- package/{interfaces → contracts/interfaces}/IPolicyNFT.sol +0 -0
- package/contracts/interfaces/IPolicyPool.sol +138 -0
- package/{interfaces → contracts/interfaces}/IPolicyPoolComponent.sol +0 -0
- package/{interfaces → contracts/interfaces}/IPolicyPoolConfig.sol +29 -20
- package/contracts/interfaces/IPremiumsAccount.sol +71 -0
- package/contracts/interfaces/IRiskModule.sol +60 -0
- package/contracts/mocks/ForwardProxy.sol +66 -0
- package/contracts/mocks/IMintableERC20.sol +13 -0
- package/contracts/mocks/LinkTokenMock.sol +30 -0
- package/contracts/mocks/PolicyHolderMock.sol +68 -0
- package/contracts/mocks/PolicyPoolComponentMock.sol +17 -0
- package/contracts/mocks/PolicyPoolMock.sol +122 -0
- package/contracts/mocks/TestCurrency.sol +35 -0
- package/contracts/mocks/TestNFT.sol +23 -0
- package/contracts/upgraded/PolicyNFTv1.sol +1 -1
- package/js/test-utils.js +278 -0
- package/package.json +2 -2
- package/build/contracts/AaveAssetManager.sol/AaveAssetManager.json +0 -742
- package/build/contracts/DataTypes.sol/DataTypes.json +0 -10
- package/build/contracts/Exchange.sol/Exchange.json +0 -591
- package/build/contracts/extras/IPriceRiskModule.sol/IPriceRiskModule.json +0 -253
- package/build/contracts/extras/PriceRiskModule.sol/PriceRiskModule.json +0 -1055
- package/build/interfaces/IAssetManager.sol/IAssetManager.json +0 -31
- package/build/interfaces/IExchange.sol/IPriceOracle.json +0 -30
- package/contracts/AaveAssetManager.sol +0 -298
- package/contracts/BaseAssetManager.sol +0 -301
- package/contracts/DataTypes.sol +0 -287
- package/contracts/Exchange.sol +0 -189
- package/contracts/extras/IPriceRiskModule.sol +0 -41
- package/contracts/extras/PriceRiskModule.sol +0 -243
- package/interfaces/IAssetManager.sol +0 -23
- package/interfaces/IEToken.sol +0 -48
- package/interfaces/IExchange.sol +0 -59
- package/interfaces/IInsolvencyHook.sol +0 -27
- package/interfaces/IPolicyPool.sol +0 -44
- package/interfaces/IRiskModule.sol +0 -29
package/contracts/EToken.sol
CHANGED
|
@@ -2,139 +2,130 @@
|
|
|
2
2
|
pragma solidity ^0.8.0;
|
|
3
3
|
|
|
4
4
|
import {IERC20Metadata} from "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol";
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
5
|
+
import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
|
|
6
|
+
import {IPolicyPool} from "./interfaces/IPolicyPool.sol";
|
|
7
|
+
import {Reserve} from "./Reserve.sol";
|
|
8
|
+
import {IEToken} from "./interfaces/IEToken.sol";
|
|
9
|
+
import {IPolicyPoolConfig} from "./interfaces/IPolicyPoolConfig.sol";
|
|
10
10
|
import {WadRayMath} from "./WadRayMath.sol";
|
|
11
|
+
import {TimeScaled} from "./TimeScaled.sol";
|
|
11
12
|
|
|
12
13
|
/**
|
|
13
14
|
* @title Ensuro ERC20 EToken - interest-bearing token
|
|
14
15
|
* @dev Implementation of the interest/earnings bearing token for the Ensuro protocol.
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
* Every operation that changes the utilization rate (_scr/totalSupply) or the
|
|
18
|
-
* first the
|
|
16
|
+
* `_tsScaled.scale` scales the balances stored in _balances. _tsScaled (totalSupply scaled) grows
|
|
17
|
+
* continuoulsly at tokenInterestRate().
|
|
18
|
+
* Every operation that changes the utilization rate (_scr.scr/totalSupply) or the _scr.interestRate, updates
|
|
19
|
+
* first the _tsScaled.scale accumulating the interest accrued since _tsScaled.lastUpdate.
|
|
19
20
|
* @custom:security-contact security@ensuro.co
|
|
20
21
|
* @author Ensuro
|
|
21
22
|
*/
|
|
22
|
-
contract EToken is
|
|
23
|
-
uint256 public constant MIN_SCALE = 1e17; // 0.0000000001 == 1e-10 in ray
|
|
24
|
-
|
|
23
|
+
contract EToken is Reserve, IERC20Metadata, IEToken {
|
|
25
24
|
using WadRayMath for uint256;
|
|
25
|
+
using TimeScaled for TimeScaled.ScaledAmount;
|
|
26
|
+
using SafeERC20 for IERC20Metadata;
|
|
26
27
|
|
|
27
28
|
uint256 internal constant SECONDS_PER_YEAR = 365 days;
|
|
28
29
|
|
|
29
30
|
// Attributes taken from ERC20
|
|
30
31
|
mapping(address => uint256) private _balances;
|
|
31
32
|
mapping(address => mapping(address => uint256)) private _allowances;
|
|
32
|
-
uint256 private _totalSupply; // non-scaled totalSupply
|
|
33
33
|
|
|
34
34
|
string private _name;
|
|
35
35
|
string private _symbol;
|
|
36
36
|
|
|
37
|
-
|
|
38
|
-
uint256 internal _scaleFactor; // in Ray
|
|
39
|
-
uint40 internal _lastScaleUpdate;
|
|
37
|
+
TimeScaled.ScaledAmount internal _tsScaled; // Total Supply scaled
|
|
40
38
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
39
|
+
struct Scr {
|
|
40
|
+
uint128 scr; // in Wad - Capital locked as Solvency Capital Requirement of backed up policies
|
|
41
|
+
uint64 interestRate; // in Wad - Interest rate received in exchange of solvency capital
|
|
42
|
+
uint64 tokenInterestRate; // in Wad - Overall interest rate of the token
|
|
43
|
+
}
|
|
46
44
|
|
|
47
|
-
|
|
48
|
-
uint256 internal _poolLoanInterestRate; // in Ray
|
|
49
|
-
uint256 internal _poolLoanScale; // in Ray
|
|
50
|
-
uint40 internal _poolLoanLastUpdate;
|
|
45
|
+
Scr internal _scr;
|
|
51
46
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
mapping(address => bool) internal _acceptExceptions;
|
|
47
|
+
// Mapping that keeps track of allowed borrowers (PremiumsAccount) and their current debt
|
|
48
|
+
mapping(address => TimeScaled.ScaledAmount) internal _loans;
|
|
55
49
|
|
|
56
|
-
|
|
57
|
-
|
|
50
|
+
struct PackedParams {
|
|
51
|
+
uint16 liquidityRequirement; // Liquidity requirement to lock more/less than SCR - 4 decimals
|
|
52
|
+
uint16 minUtilizationRate; // Min utilization rate, to reject deposits that leave UR under this value - 4 decimals
|
|
53
|
+
uint16 maxUtilizationRate; // Max utilization rate, to reject lockScr that leave UR above this value - 4 decimals
|
|
54
|
+
uint16 internalLoanInterestRate; // Annualized interest rate charged to internal borrowers (premiums accounts) - 4dec
|
|
55
|
+
}
|
|
58
56
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
57
|
+
PackedParams internal _params;
|
|
58
|
+
|
|
59
|
+
event InternalLoan(address indexed borrower, uint256 value, uint256 amountAsked);
|
|
60
|
+
event InternalLoanRepaid(address indexed borrower, uint256 value);
|
|
61
|
+
event PoolBorrowerAdded(address borrower);
|
|
62
|
+
|
|
63
|
+
modifier onlyBorrower() {
|
|
64
|
+
require(_loans[_msgSender()].scale != 0, "The caller must be a borrower");
|
|
64
65
|
_;
|
|
65
66
|
}
|
|
66
67
|
|
|
67
68
|
/// @custom:oz-upgrades-unsafe-allow constructor
|
|
68
69
|
// solhint-disable-next-line no-empty-blocks
|
|
69
|
-
constructor(IPolicyPool policyPool_)
|
|
70
|
+
constructor(IPolicyPool policyPool_) Reserve(policyPool_) {}
|
|
70
71
|
|
|
71
72
|
/**
|
|
72
73
|
* @dev Initializes the eToken
|
|
73
|
-
* @param expirationPeriod_ Maximum expirationPeriod (from block.timestamp) of policies to be accepted
|
|
74
|
-
* @param liquidityRequirement_ Liquidity requirement to allow withdrawal (in Ray - default=1 Ray)
|
|
75
74
|
* @param maxUtilizationRate_ Max utilization rate (scr/totalSupply) (in Ray - default=1 Ray)
|
|
76
|
-
* @param
|
|
75
|
+
* @param internalLoanInterestRate_ Rate of loans givencrto the policy pool (in Ray)
|
|
77
76
|
* @param name_ Name of the eToken
|
|
78
77
|
* @param symbol_ Symbol of the eToken
|
|
79
78
|
*/
|
|
80
79
|
function initialize(
|
|
81
80
|
string memory name_,
|
|
82
81
|
string memory symbol_,
|
|
83
|
-
uint40 expirationPeriod_,
|
|
84
|
-
uint256 liquidityRequirement_,
|
|
85
82
|
uint256 maxUtilizationRate_,
|
|
86
|
-
uint256
|
|
83
|
+
uint256 internalLoanInterestRate_
|
|
87
84
|
) public initializer {
|
|
88
85
|
__PolicyPoolComponent_init();
|
|
89
|
-
__EToken_init_unchained(
|
|
90
|
-
name_,
|
|
91
|
-
symbol_,
|
|
92
|
-
expirationPeriod_,
|
|
93
|
-
liquidityRequirement_,
|
|
94
|
-
maxUtilizationRate_,
|
|
95
|
-
poolLoanInterestRate_
|
|
96
|
-
);
|
|
86
|
+
__EToken_init_unchained(name_, symbol_, maxUtilizationRate_, internalLoanInterestRate_);
|
|
97
87
|
}
|
|
98
88
|
|
|
99
89
|
// solhint-disable-next-line func-name-mixedcase
|
|
100
90
|
function __EToken_init_unchained(
|
|
101
91
|
string memory name_,
|
|
102
92
|
string memory symbol_,
|
|
103
|
-
uint40 expirationPeriod_,
|
|
104
|
-
uint256 liquidityRequirement_,
|
|
105
93
|
uint256 maxUtilizationRate_,
|
|
106
|
-
uint256
|
|
94
|
+
uint256 internalLoanInterestRate_
|
|
107
95
|
) internal initializer {
|
|
108
96
|
_name = name_;
|
|
109
97
|
_symbol = symbol_;
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
_poolLoanLastUpdate = uint40(block.timestamp);
|
|
98
|
+
_tsScaled.init();
|
|
99
|
+
/* _scr = Scr({
|
|
100
|
+
scr: 0,
|
|
101
|
+
interestRate: 0,
|
|
102
|
+
tokenInterestRate: 0
|
|
103
|
+
}); */
|
|
104
|
+
_params = PackedParams({
|
|
105
|
+
maxUtilizationRate: uint16(maxUtilizationRate_ / 1e14),
|
|
106
|
+
liquidityRequirement: 1e4,
|
|
107
|
+
minUtilizationRate: 0,
|
|
108
|
+
internalLoanInterestRate: uint16(internalLoanInterestRate_ / 1e14)
|
|
109
|
+
});
|
|
110
|
+
|
|
124
111
|
_validateParameters();
|
|
125
112
|
}
|
|
126
113
|
|
|
127
114
|
// runs validation on EToken parameters
|
|
128
115
|
function _validateParameters() internal view override {
|
|
129
116
|
require(
|
|
130
|
-
|
|
117
|
+
_params.liquidityRequirement >= 8e3 && _params.liquidityRequirement <= 13e3,
|
|
131
118
|
"Validation: liquidityRequirement must be [0.8, 1.3]"
|
|
132
119
|
);
|
|
133
120
|
require(
|
|
134
|
-
|
|
121
|
+
_params.maxUtilizationRate >= 5e3 && _params.maxUtilizationRate <= 1e4,
|
|
135
122
|
"Validation: maxUtilizationRate must be [0.5, 1]"
|
|
136
123
|
);
|
|
137
|
-
require(
|
|
124
|
+
require(_params.minUtilizationRate <= 1e4, "Validation: minUtilizationRate must be [0, 1]");
|
|
125
|
+
require(
|
|
126
|
+
_params.internalLoanInterestRate <= 5e3,
|
|
127
|
+
"Validation: internalLoanInterestRate must be <= 50%"
|
|
128
|
+
);
|
|
138
129
|
}
|
|
139
130
|
|
|
140
131
|
/*** BEGIN ERC20 methods - mainly copied from OpenZeppelin but changes in events and scaledAmount */
|
|
@@ -175,7 +166,7 @@ contract EToken is PolicyPoolComponent, IERC20Metadata, IEToken {
|
|
|
175
166
|
* @dev See {IERC20-totalSupply}.
|
|
176
167
|
*/
|
|
177
168
|
function totalSupply() public view virtual override returns (uint256) {
|
|
178
|
-
return
|
|
169
|
+
return _tsScaled.getScaledAmount(tokenInterestRate());
|
|
179
170
|
}
|
|
180
171
|
|
|
181
172
|
/**
|
|
@@ -184,7 +175,7 @@ contract EToken is PolicyPoolComponent, IERC20Metadata, IEToken {
|
|
|
184
175
|
function balanceOf(address account) public view virtual override returns (uint256) {
|
|
185
176
|
uint256 principalBalance = _balances[account];
|
|
186
177
|
if (principalBalance == 0) return 0;
|
|
187
|
-
return
|
|
178
|
+
return _tsScaled.getScale(tokenInterestRate()).rayMul(principalBalance.wadToRay()).rayToWad();
|
|
188
179
|
}
|
|
189
180
|
|
|
190
181
|
/**
|
|
@@ -295,10 +286,6 @@ contract EToken is PolicyPoolComponent, IERC20Metadata, IEToken {
|
|
|
295
286
|
return true;
|
|
296
287
|
}
|
|
297
288
|
|
|
298
|
-
function _scaleAmount(uint256 amount) internal view returns (uint256) {
|
|
299
|
-
return amount.wadToRay().rayDiv(_calculateCurrentScale()).rayToWad();
|
|
300
|
-
}
|
|
301
|
-
|
|
302
289
|
/**
|
|
303
290
|
* @dev Moves tokens `amount` from `sender` to `recipient`.
|
|
304
291
|
*
|
|
@@ -322,7 +309,7 @@ contract EToken is PolicyPoolComponent, IERC20Metadata, IEToken {
|
|
|
322
309
|
require(recipient != address(0), "EToken: transfer to the zero address");
|
|
323
310
|
|
|
324
311
|
_beforeTokenTransfer(sender, recipient, amount);
|
|
325
|
-
uint256 scaledAmount =
|
|
312
|
+
uint256 scaledAmount = _tsScaled.scaleAmountNow(tokenInterestRate(), amount);
|
|
326
313
|
|
|
327
314
|
uint256 senderBalance = _balances[sender];
|
|
328
315
|
require(senderBalance >= scaledAmount, "EToken: transfer amount exceeds balance");
|
|
@@ -345,9 +332,7 @@ contract EToken is PolicyPoolComponent, IERC20Metadata, IEToken {
|
|
|
345
332
|
require(account != address(0), "EToken: mint to the zero address");
|
|
346
333
|
|
|
347
334
|
_beforeTokenTransfer(address(0), account, amount);
|
|
348
|
-
uint256 scaledAmount =
|
|
349
|
-
|
|
350
|
-
_totalSupply += scaledAmount;
|
|
335
|
+
uint256 scaledAmount = _tsScaled.add(amount, tokenInterestRate());
|
|
351
336
|
_balances[account] += scaledAmount;
|
|
352
337
|
emit Transfer(address(0), account, amount);
|
|
353
338
|
}
|
|
@@ -367,11 +352,10 @@ contract EToken is PolicyPoolComponent, IERC20Metadata, IEToken {
|
|
|
367
352
|
require(account != address(0), "EToken: burn from the zero address");
|
|
368
353
|
_beforeTokenTransfer(account, address(0), amount);
|
|
369
354
|
|
|
370
|
-
uint256 scaledAmount =
|
|
355
|
+
uint256 scaledAmount = _tsScaled.sub(amount, tokenInterestRate());
|
|
371
356
|
uint256 accountBalance = _balances[account];
|
|
372
357
|
require(accountBalance >= scaledAmount, "EToken: burn amount exceeds balance");
|
|
373
358
|
_balances[account] = accountBalance - scaledAmount;
|
|
374
|
-
_totalSupply -= scaledAmount;
|
|
375
359
|
|
|
376
360
|
emit Transfer(account, address(0), amount);
|
|
377
361
|
}
|
|
@@ -431,127 +415,115 @@ contract EToken is PolicyPoolComponent, IERC20Metadata, IEToken {
|
|
|
431
415
|
|
|
432
416
|
/*** END ERC20 methods - mainly copied from OpenZeppelin but changes in events and scaledAmount */
|
|
433
417
|
|
|
434
|
-
function _updateCurrentScale() internal {
|
|
435
|
-
if (uint40(block.timestamp) == _lastScaleUpdate) return;
|
|
436
|
-
_scaleFactor = _calculateCurrentScale();
|
|
437
|
-
require(_scaleFactor >= MIN_SCALE, "Scale too small, can lead to rounding errors");
|
|
438
|
-
_lastScaleUpdate = uint40(block.timestamp);
|
|
439
|
-
}
|
|
440
|
-
|
|
441
418
|
function _updateTokenInterestRate() internal {
|
|
442
|
-
uint256 totalSupply_ = this.totalSupply()
|
|
443
|
-
if (totalSupply_ == 0)
|
|
444
|
-
else
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
function _calculateCurrentScale() internal view returns (uint256) {
|
|
448
|
-
if (uint40(block.timestamp) <= _lastScaleUpdate) return _scaleFactor;
|
|
449
|
-
uint256 timeDifference = block.timestamp - _lastScaleUpdate;
|
|
450
|
-
return
|
|
451
|
-
_scaleFactor.rayMul(
|
|
452
|
-
((_tokenInterestRate * timeDifference) / SECONDS_PER_YEAR) + WadRayMath.ray()
|
|
419
|
+
uint256 totalSupply_ = this.totalSupply();
|
|
420
|
+
if (totalSupply_ == 0) _scr.tokenInterestRate = 0;
|
|
421
|
+
else {
|
|
422
|
+
_scr.tokenInterestRate = uint64(
|
|
423
|
+
uint256(_scr.interestRate).wadMul(uint256(_scr.scr)).wadDiv(totalSupply_)
|
|
453
424
|
);
|
|
425
|
+
}
|
|
454
426
|
}
|
|
455
427
|
|
|
456
428
|
function getCurrentScale(bool updated) public view returns (uint256) {
|
|
457
|
-
if (updated) return
|
|
458
|
-
else return
|
|
429
|
+
if (updated) return _tsScaled.getScale(tokenInterestRate());
|
|
430
|
+
else return uint256(_tsScaled.scale);
|
|
459
431
|
}
|
|
460
432
|
|
|
461
|
-
function
|
|
433
|
+
function fundsAvailable() public view returns (uint256) {
|
|
462
434
|
uint256 totalSupply_ = this.totalSupply();
|
|
463
|
-
if (totalSupply_ > _scr) return totalSupply_ - _scr;
|
|
435
|
+
if (totalSupply_ > uint256(_scr.scr)) return totalSupply_ - uint256(_scr.scr);
|
|
464
436
|
else return 0;
|
|
465
437
|
}
|
|
466
438
|
|
|
467
|
-
function
|
|
439
|
+
function fundsAvailableToLock() public view returns (uint256) {
|
|
468
440
|
uint256 totalSupply_ = this.totalSupply();
|
|
469
|
-
if (totalSupply_ >
|
|
441
|
+
if (totalSupply_ > uint256(_scr.scr))
|
|
442
|
+
return (totalSupply_ - uint256(_scr.scr)).wadMul(maxUtilizationRate());
|
|
470
443
|
else return 0;
|
|
471
444
|
}
|
|
472
445
|
|
|
473
446
|
function scr() public view virtual override returns (uint256) {
|
|
474
|
-
return _scr;
|
|
447
|
+
return uint256(_scr.scr);
|
|
475
448
|
}
|
|
476
449
|
|
|
477
450
|
function scrInterestRate() public view override returns (uint256) {
|
|
478
|
-
return
|
|
451
|
+
return uint256(_scr.interestRate);
|
|
479
452
|
}
|
|
480
453
|
|
|
481
454
|
function tokenInterestRate() public view override returns (uint256) {
|
|
482
|
-
return
|
|
455
|
+
return uint256(_scr.tokenInterestRate);
|
|
483
456
|
}
|
|
484
457
|
|
|
485
458
|
function liquidityRequirement() public view returns (uint256) {
|
|
486
|
-
return
|
|
459
|
+
return uint256(_params.liquidityRequirement) * 1e14; // 4 -> 18 decimals
|
|
487
460
|
}
|
|
488
461
|
|
|
489
462
|
function maxUtilizationRate() public view returns (uint256) {
|
|
490
|
-
return
|
|
463
|
+
return uint256(_params.maxUtilizationRate) * 1e14; // 4 -> 18 decimals
|
|
491
464
|
}
|
|
492
465
|
|
|
493
|
-
function
|
|
494
|
-
return
|
|
466
|
+
function minUtilizationRate() public view returns (uint256) {
|
|
467
|
+
return uint256(_params.minUtilizationRate) * 1e14; // 4 -> 18 decimals
|
|
495
468
|
}
|
|
496
469
|
|
|
497
470
|
function utilizationRate() public view returns (uint256) {
|
|
498
|
-
return _scr.wadDiv(this.totalSupply())
|
|
471
|
+
return uint256(_scr.scr).wadDiv(this.totalSupply());
|
|
499
472
|
}
|
|
500
473
|
|
|
501
|
-
function lockScr(uint256
|
|
502
|
-
require(
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
474
|
+
function lockScr(uint256 scrAmount, uint256 policyInterestRate) external override onlyBorrower {
|
|
475
|
+
require(
|
|
476
|
+
scrAmount <= this.fundsAvailableToLock(),
|
|
477
|
+
"Not enought funds available to cover the SCR"
|
|
478
|
+
);
|
|
479
|
+
_tsScaled.updateScale(tokenInterestRate());
|
|
480
|
+
if (_scr.scr == 0) {
|
|
481
|
+
_scr.scr = uint128(scrAmount);
|
|
482
|
+
_scr.interestRate = uint64(policyInterestRate);
|
|
507
483
|
} else {
|
|
508
|
-
uint256 origScr = _scr.
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
484
|
+
uint256 origScr = uint256(_scr.scr);
|
|
485
|
+
uint256 newScr = origScr + scrAmount;
|
|
486
|
+
_scr.interestRate = uint64(
|
|
487
|
+
(uint256(_scr.interestRate).wadMul(origScr) + policyInterestRate.wadMul(scrAmount)).wadDiv(
|
|
488
|
+
newScr
|
|
489
|
+
)
|
|
490
|
+
);
|
|
491
|
+
_scr.scr = uint128(newScr);
|
|
512
492
|
}
|
|
513
493
|
emit SCRLocked(policyInterestRate, scrAmount);
|
|
514
494
|
_updateTokenInterestRate();
|
|
515
495
|
}
|
|
516
496
|
|
|
517
|
-
function unlockScr(
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
{
|
|
522
|
-
require(scrAmount <= _scr, "Current SCR less than the amount you want to unlock");
|
|
523
|
-
|
|
497
|
+
function unlockScr(
|
|
498
|
+
uint256 scrAmount,
|
|
499
|
+
uint256 policyInterestRate,
|
|
500
|
+
int256 adjustment
|
|
501
|
+
) external override onlyBorrower {
|
|
502
|
+
require(scrAmount <= uint256(_scr.scr), "Current SCR less than the amount you want to unlock");
|
|
503
|
+
_tsScaled.updateScale(tokenInterestRate());
|
|
524
504
|
|
|
525
|
-
if (_scr == scrAmount) {
|
|
526
|
-
_scr = 0;
|
|
527
|
-
|
|
505
|
+
if (uint256(_scr.scr) == scrAmount) {
|
|
506
|
+
_scr.scr = 0;
|
|
507
|
+
_scr.interestRate = 0;
|
|
528
508
|
} else {
|
|
529
|
-
uint256 origScr = _scr.
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
509
|
+
uint256 origScr = uint256(_scr.scr);
|
|
510
|
+
uint256 newScr = origScr - scrAmount;
|
|
511
|
+
_scr.interestRate = uint64(
|
|
512
|
+
(uint256(_scr.interestRate).wadMul(origScr) - policyInterestRate.wadMul(scrAmount)).wadDiv(
|
|
513
|
+
newScr
|
|
514
|
+
)
|
|
515
|
+
);
|
|
516
|
+
_scr.scr = uint128(newScr);
|
|
533
517
|
}
|
|
534
518
|
emit SCRUnlocked(policyInterestRate, scrAmount);
|
|
535
|
-
|
|
519
|
+
_discreteChange(adjustment);
|
|
536
520
|
}
|
|
537
521
|
|
|
538
|
-
function _discreteChange(
|
|
539
|
-
|
|
540
|
-
_scaleFactor = newTotalSupply.wadToRay().rayDiv(_totalSupply.wadToRay());
|
|
541
|
-
require(_scaleFactor >= MIN_SCALE, "Scale too small, can lead to rounding errors");
|
|
522
|
+
function _discreteChange(int256 amount) internal {
|
|
523
|
+
_tsScaled.discreteChange(amount, tokenInterestRate());
|
|
542
524
|
_updateTokenInterestRate();
|
|
543
525
|
}
|
|
544
526
|
|
|
545
|
-
function discreteEarning(uint256 amount, bool positive) external override onlyPolicyPool {
|
|
546
|
-
_updateCurrentScale();
|
|
547
|
-
_discreteChange(amount, positive);
|
|
548
|
-
}
|
|
549
|
-
|
|
550
|
-
function assetEarnings(uint256 amount, bool positive) external override onlyAssetManager {
|
|
551
|
-
_updateCurrentScale();
|
|
552
|
-
_discreteChange(amount, positive);
|
|
553
|
-
}
|
|
554
|
-
|
|
555
527
|
function deposit(address provider, uint256 amount)
|
|
556
528
|
external
|
|
557
529
|
override
|
|
@@ -564,14 +536,14 @@ contract EToken is PolicyPoolComponent, IERC20Metadata, IEToken {
|
|
|
564
536
|
policyPool().config().lpWhitelist().acceptsDeposit(this, provider, amount),
|
|
565
537
|
"Liquidity Provider not whitelisted"
|
|
566
538
|
);
|
|
567
|
-
_updateCurrentScale();
|
|
568
539
|
_mint(provider, amount);
|
|
569
540
|
_updateTokenInterestRate();
|
|
541
|
+
require(utilizationRate() >= minUtilizationRate(), "Deposit rejected - Utilization Rate < min");
|
|
570
542
|
return balanceOf(provider);
|
|
571
543
|
}
|
|
572
544
|
|
|
573
545
|
function totalWithdrawable() public view virtual override returns (uint256) {
|
|
574
|
-
uint256 locked = _scr.
|
|
546
|
+
uint256 locked = uint256(_scr.scr).wadMul(liquidityRequirement());
|
|
575
547
|
uint256 totalSupply_ = totalSupply();
|
|
576
548
|
if (totalSupply_ >= locked) return totalSupply_ - locked;
|
|
577
549
|
else return 0;
|
|
@@ -584,7 +556,6 @@ contract EToken is PolicyPoolComponent, IERC20Metadata, IEToken {
|
|
|
584
556
|
whenNotPaused
|
|
585
557
|
returns (uint256)
|
|
586
558
|
{
|
|
587
|
-
_updateCurrentScale();
|
|
588
559
|
uint256 balance = balanceOf(provider);
|
|
589
560
|
if (balance == 0) return 0;
|
|
590
561
|
if (amount > balance) amount = balance;
|
|
@@ -593,116 +564,77 @@ contract EToken is PolicyPoolComponent, IERC20Metadata, IEToken {
|
|
|
593
564
|
if (amount == 0) return 0;
|
|
594
565
|
_burn(provider, amount);
|
|
595
566
|
_updateTokenInterestRate();
|
|
567
|
+
_transferTo(provider, amount);
|
|
596
568
|
return amount;
|
|
597
569
|
}
|
|
598
570
|
|
|
599
|
-
function
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
returns (bool)
|
|
605
|
-
{
|
|
606
|
-
if (paused()) return false;
|
|
607
|
-
if (_acceptAllRMs == _acceptExceptions[riskModule]) {
|
|
608
|
-
// all accepted except this one or all rejected and this one is not an exception
|
|
609
|
-
return false;
|
|
571
|
+
function addBorrower(address borrower) external override onlyPolicyPool {
|
|
572
|
+
TimeScaled.ScaledAmount storage loan = _loans[borrower];
|
|
573
|
+
if (loan.scale == 0) {
|
|
574
|
+
loan.init();
|
|
575
|
+
emit PoolBorrowerAdded(borrower);
|
|
610
576
|
}
|
|
611
|
-
return policyExpiration < (uint40(block.timestamp) + _expirationPeriod);
|
|
612
|
-
}
|
|
613
|
-
|
|
614
|
-
function _updatePoolLoanScale() internal {
|
|
615
|
-
if (uint40(block.timestamp) == _poolLoanLastUpdate) return;
|
|
616
|
-
_poolLoanScale = _getPoolLoanScale();
|
|
617
|
-
_poolLoanLastUpdate = uint40(block.timestamp);
|
|
618
577
|
}
|
|
619
578
|
|
|
620
|
-
function
|
|
621
|
-
uint256
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
returns (uint256)
|
|
632
|
-
{
|
|
633
|
-
if (fromOcean && amount > ocean()) amount = ocean();
|
|
634
|
-
if (!fromOcean && amount > totalSupply()) amount = totalSupply();
|
|
635
|
-
if (amount > _maxNegativeAdjustment()) {
|
|
636
|
-
amount = _maxNegativeAdjustment();
|
|
637
|
-
if (amount == 0) return amount;
|
|
579
|
+
function internalLoan(
|
|
580
|
+
uint256 amount,
|
|
581
|
+
address receiver,
|
|
582
|
+
bool fromAvailable
|
|
583
|
+
) external override onlyBorrower whenNotPaused returns (uint256) {
|
|
584
|
+
uint256 amountAsked = amount;
|
|
585
|
+
if (fromAvailable && amount > fundsAvailable()) amount = fundsAvailable();
|
|
586
|
+
if (!fromAvailable && amount > totalSupply()) amount = totalSupply();
|
|
587
|
+
if (amount > _tsScaled.maxNegativeAdjustment(tokenInterestRate())) {
|
|
588
|
+
amount = _tsScaled.maxNegativeAdjustment(tokenInterestRate());
|
|
589
|
+
if (amount == 0) return amountAsked;
|
|
638
590
|
}
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
_poolLoan += amount.wadToRay().rayDiv(_poolLoanScale).rayToWad();
|
|
646
|
-
}
|
|
647
|
-
_updateCurrentScale(); // shouldn't do anything because lendToPool is after unlock_scr but doing anyway
|
|
648
|
-
_discreteChange(amount, false);
|
|
649
|
-
emit PoolLoan(amount);
|
|
650
|
-
if (!fromOcean && _scr > totalSupply()) {
|
|
651
|
-
// Notify insolvency_hook - Insuficient solvency
|
|
652
|
-
IInsolvencyHook hook = _policyPool.config().insolvencyHook();
|
|
653
|
-
if (address(hook) != address(0)) {
|
|
654
|
-
hook.insolventEToken(this, _scr - totalSupply());
|
|
655
|
-
}
|
|
656
|
-
}
|
|
657
|
-
return amount;
|
|
591
|
+
TimeScaled.ScaledAmount storage loan = _loans[_msgSender()];
|
|
592
|
+
loan.add(amount, internalLoanInterestRate());
|
|
593
|
+
_discreteChange(-int256(amount));
|
|
594
|
+
_transferTo(receiver, amount);
|
|
595
|
+
emit InternalLoan(_msgSender(), amount, amountAsked);
|
|
596
|
+
return amountAsked - amount;
|
|
658
597
|
}
|
|
659
598
|
|
|
660
|
-
function
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
599
|
+
function repayLoan(uint256 amount, address onBehalfOf) external override {
|
|
600
|
+
// Anyone can call this method, since it has to pay
|
|
601
|
+
currency().safeTransferFrom(_msgSender(), address(this), amount);
|
|
602
|
+
TimeScaled.ScaledAmount storage loan = _loans[onBehalfOf];
|
|
603
|
+
require(loan.scale != 0, "Not a registered borrower");
|
|
604
|
+
loan.sub(amount, internalLoanInterestRate());
|
|
605
|
+
_discreteChange(int256(amount));
|
|
606
|
+
emit InternalLoanRepaid(onBehalfOf, amount);
|
|
666
607
|
}
|
|
667
608
|
|
|
668
|
-
function
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
return
|
|
672
|
-
_poolLoanScale.rayMul(
|
|
673
|
-
((_poolLoanInterestRate * timeDifference) / SECONDS_PER_YEAR) + WadRayMath.ray()
|
|
674
|
-
);
|
|
609
|
+
function getLoan(address borrower) public view virtual override returns (uint256) {
|
|
610
|
+
TimeScaled.ScaledAmount storage loan = _loans[borrower];
|
|
611
|
+
if (loan.scale == 0) return 0;
|
|
612
|
+
return loan.getScaledAmount(internalLoanInterestRate());
|
|
675
613
|
}
|
|
676
614
|
|
|
677
|
-
function
|
|
678
|
-
|
|
679
|
-
return _poolLoan.wadToRay().rayMul(_getPoolLoanScale()).rayToWad();
|
|
615
|
+
function internalLoanInterestRate() public view returns (uint256) {
|
|
616
|
+
return uint256(_params.internalLoanInterestRate) * 1e14; // to wad 4 -> 18 digits
|
|
680
617
|
}
|
|
681
618
|
|
|
682
|
-
function
|
|
683
|
-
return _poolLoanInterestRate;
|
|
684
|
-
}
|
|
685
|
-
|
|
686
|
-
function acceptAllRMs() public view returns (bool) {
|
|
687
|
-
return _acceptAllRMs;
|
|
688
|
-
}
|
|
689
|
-
|
|
690
|
-
function isAcceptException(address riskModule) public view returns (bool) {
|
|
691
|
-
return _acceptExceptions[riskModule];
|
|
692
|
-
}
|
|
693
|
-
|
|
694
|
-
function setPoolLoanInterestRate(uint256 newRate)
|
|
619
|
+
function setInternalLoanInterestRate(uint256 newRate)
|
|
695
620
|
external
|
|
696
621
|
onlyPoolRole2(LEVEL2_ROLE, LEVEL3_ROLE)
|
|
697
622
|
{
|
|
698
623
|
bool tweak = !hasPoolRole(LEVEL2_ROLE);
|
|
699
624
|
require(
|
|
700
|
-
!tweak ||
|
|
701
|
-
"Tweak exceeded:
|
|
625
|
+
!tweak || _isTweakWad(internalLoanInterestRate(), newRate, 3e17),
|
|
626
|
+
"Tweak exceeded: internalLoanInterestRate tweaks only up to 30%"
|
|
627
|
+
);
|
|
628
|
+
// This call changes the interest rate without updating the current loans up to this point
|
|
629
|
+
// So, if interest rate goes from 5% to 6%, this change will be retroactive to the lastUpdate of each
|
|
630
|
+
// loan. Since it's a permissioned call, I'm ok with this. If a caller wants to reduce the impact, it can
|
|
631
|
+
// issue 1 wei repayLoan to each active loan, forcing the update of the scales
|
|
632
|
+
_params.internalLoanInterestRate = uint16(newRate / 1e14);
|
|
633
|
+
_parameterChanged(
|
|
634
|
+
IPolicyPoolConfig.GovernanceActions.setInternalLoanInterestRate,
|
|
635
|
+
newRate,
|
|
636
|
+
tweak
|
|
702
637
|
);
|
|
703
|
-
_updatePoolLoanScale();
|
|
704
|
-
_poolLoanInterestRate = newRate;
|
|
705
|
-
_parameterChanged(IPolicyPoolConfig.GovernanceActions.setPoolLoanInterestRate, newRate, tweak);
|
|
706
638
|
}
|
|
707
639
|
|
|
708
640
|
function setLiquidityRequirement(uint256 newRate)
|
|
@@ -711,43 +643,30 @@ contract EToken is PolicyPoolComponent, IERC20Metadata, IEToken {
|
|
|
711
643
|
{
|
|
712
644
|
bool tweak = !hasPoolRole(LEVEL2_ROLE);
|
|
713
645
|
require(
|
|
714
|
-
!tweak ||
|
|
646
|
+
!tweak || _isTweakWad(liquidityRequirement(), newRate, 1e17),
|
|
715
647
|
"Tweak exceeded: liquidityRequirement tweaks only up to 10%"
|
|
716
648
|
);
|
|
717
|
-
|
|
649
|
+
_params.liquidityRequirement = uint16(newRate / 1e14);
|
|
718
650
|
_parameterChanged(IPolicyPoolConfig.GovernanceActions.setLiquidityRequirement, newRate, tweak);
|
|
719
651
|
}
|
|
720
652
|
|
|
721
653
|
function setMaxUtilizationRate(uint256 newRate) external onlyPoolRole2(LEVEL2_ROLE, LEVEL3_ROLE) {
|
|
722
654
|
bool tweak = !hasPoolRole(LEVEL2_ROLE);
|
|
723
655
|
require(
|
|
724
|
-
!tweak ||
|
|
656
|
+
!tweak || _isTweakWad(maxUtilizationRate(), newRate, 3e17),
|
|
725
657
|
"Tweak exceeded: maxUtilizationRate tweaks only up to 30%"
|
|
726
658
|
);
|
|
727
|
-
|
|
659
|
+
_params.maxUtilizationRate = uint16(newRate / 1e14);
|
|
728
660
|
_parameterChanged(IPolicyPoolConfig.GovernanceActions.setMaxUtilizationRate, newRate, tweak);
|
|
729
661
|
}
|
|
730
662
|
|
|
731
|
-
function
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
false
|
|
663
|
+
function setMinUtilizationRate(uint256 newRate) external onlyPoolRole2(LEVEL2_ROLE, LEVEL3_ROLE) {
|
|
664
|
+
bool tweak = !hasPoolRole(LEVEL2_ROLE);
|
|
665
|
+
require(
|
|
666
|
+
!tweak || _isTweakWad(minUtilizationRate(), newRate, 3e17),
|
|
667
|
+
"Tweak exceeded: minUtilizationRate tweaks only up to 30%"
|
|
737
668
|
);
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
function setAcceptException(address riskModule, bool isException)
|
|
741
|
-
external
|
|
742
|
-
onlyPoolRole(LEVEL2_ROLE)
|
|
743
|
-
{
|
|
744
|
-
_acceptExceptions[riskModule] = isException;
|
|
745
|
-
uint256 value = uint160(riskModule);
|
|
746
|
-
if (!isException) value |= (1 << 255); // if changed to NOT exception activate first bit
|
|
747
|
-
_parameterChanged(IPolicyPoolConfig.GovernanceActions.setAcceptException, value, false);
|
|
748
|
-
}
|
|
749
|
-
|
|
750
|
-
function getInvestable() public view virtual override returns (uint256) {
|
|
751
|
-
return _scr + ocean() + getPoolLoan();
|
|
669
|
+
_params.minUtilizationRate = uint16(newRate / 1e14);
|
|
670
|
+
_parameterChanged(IPolicyPoolConfig.GovernanceActions.setMinUtilizationRate, newRate, tweak);
|
|
752
671
|
}
|
|
753
672
|
}
|