@ensuro/core 2.0.1 → 2.1.0-beta2
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/build/contracts/AccessManager.sol/AccessManager.json +2 -2
- package/build/contracts/ERC4626AssetManager.sol/ERC4626AssetManager.json +2 -2
- package/build/contracts/EToken.sol/EToken.json +71 -7
- package/build/contracts/LPManualWhitelist.sol/LPManualWhitelist.json +193 -9
- package/build/contracts/Policy.sol/Policy.json +2 -2
- package/build/contracts/PolicyPool.sol/PolicyPool.json +2 -2
- package/build/contracts/PremiumsAccount.sol/PremiumsAccount.json +46 -2
- package/build/contracts/SignedQuoteRiskModule.sol/SignedQuoteRiskModule.json +2 -2
- package/build/contracts/TimeScaled.sol/TimeScaled.json +2 -2
- package/build/contracts/TrustfulRiskModule.sol/TrustfulRiskModule.json +2 -2
- package/build/contracts/interfaces/IEToken.sol/IEToken.json +0 -5
- package/build/contracts/interfaces/ILPWhitelist.sol/ILPWhitelist.json +29 -0
- package/build/contracts/mocks/FixedRateVault.sol/FixedRateVault.json +2 -2
- package/build/contracts/mocks/InterfaceIdCalculator.sol/InterfaceIdCalculator.json +2 -2
- package/build/contracts/mocks/PolicyPoolComponentMock.sol/PolicyPoolComponentMock.json +2 -2
- package/build/contracts/mocks/PolicyPoolMock.sol/PolicyPoolMock.json +2 -2
- package/build/contracts/mocks/PolicyPoolMock.sol/PolicyPoolMockForward.json +2 -2
- package/build/contracts/mocks/RiskModuleMock.sol/RiskModuleMock.json +2 -2
- package/contracts/EToken.sol +64 -17
- package/contracts/LPManualWhitelist.sol +97 -11
- package/contracts/PremiumsAccount.sol +90 -11
- package/contracts/RiskModule.sol +2 -2
- package/contracts/TimeScaled.sol +2 -9
- package/contracts/interfaces/IAccessManager.sol +4 -4
- package/contracts/interfaces/IEToken.sol +1 -7
- package/contracts/interfaces/ILPWhitelist.sol +14 -0
- package/js/deploy.js +21 -12
- package/js/test-utils.js +2 -2
- package/package.json +1 -1
package/contracts/EToken.sol
CHANGED
|
@@ -220,6 +220,36 @@ contract EToken is Reserve, IERC20Metadata, IEToken {
|
|
|
220
220
|
return _tsScaled.getScale(tokenInterestRate()).rayMul(principalBalance.wadToRay()).rayToWad();
|
|
221
221
|
}
|
|
222
222
|
|
|
223
|
+
// Methods following AAVE's IScaledBalanceToken, to simplify future integrations
|
|
224
|
+
|
|
225
|
+
/**
|
|
226
|
+
* @dev Returns the scaled balance of the user. The scaled balance is the sum of all the
|
|
227
|
+
* updated stored balance divided by the EToken's scale index
|
|
228
|
+
* @param user The user whose balance is calculated
|
|
229
|
+
* @return The scaled balance of the user
|
|
230
|
+
**/
|
|
231
|
+
function scaledBalanceOf(address user) external view returns (uint256) {
|
|
232
|
+
return _balances[user];
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
/**
|
|
236
|
+
* @dev Returns the scaled balance of the user and the scaled total supply.
|
|
237
|
+
* @param user The address of the user
|
|
238
|
+
* @return The scaled balance of the user
|
|
239
|
+
* @return The scaled balance and the scaled total supply
|
|
240
|
+
**/
|
|
241
|
+
function getScaledUserBalanceAndSupply(address user) external view returns (uint256, uint256) {
|
|
242
|
+
return (_balances[user], uint256(_tsScaled.amount));
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
/**
|
|
246
|
+
* @dev Returns the (un)scaled total supply of the EToken. Equals to the sum of `scaledBalanceOf(x)` of all users
|
|
247
|
+
* @return The scaled total supply
|
|
248
|
+
**/
|
|
249
|
+
function scaledTotalSupply() external view returns (uint256) {
|
|
250
|
+
return uint256(_tsScaled.amount);
|
|
251
|
+
}
|
|
252
|
+
|
|
223
253
|
/**
|
|
224
254
|
* @dev See {IERC20-transfer}.
|
|
225
255
|
*
|
|
@@ -481,10 +511,14 @@ contract EToken is Reserve, IERC20Metadata, IEToken {
|
|
|
481
511
|
uint256 totalSupply_ = this.totalSupply();
|
|
482
512
|
if (totalSupply_ == 0) _scr.tokenInterestRate = 0;
|
|
483
513
|
else {
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
514
|
+
uint256 newTokenInterestRate = uint256(_scr.interestRate).wadMul(uint256(_scr.scr)).wadDiv(
|
|
515
|
+
totalSupply_
|
|
516
|
+
);
|
|
517
|
+
_scr.tokenInterestRate = (newTokenInterestRate > type(uint64).max)
|
|
518
|
+
? type(uint64).max
|
|
519
|
+
: newTokenInterestRate.toUint64();
|
|
520
|
+
// This is not the mathematically correct value, but the max we can set. The actual value of the total supply
|
|
521
|
+
// will be adjusted when the policies expire or are resolved and the SCR is unlocked.
|
|
488
522
|
}
|
|
489
523
|
}
|
|
490
524
|
|
|
@@ -500,9 +534,8 @@ contract EToken is Reserve, IERC20Metadata, IEToken {
|
|
|
500
534
|
}
|
|
501
535
|
|
|
502
536
|
function fundsAvailableToLock() public view returns (uint256) {
|
|
503
|
-
uint256
|
|
504
|
-
if (
|
|
505
|
-
return (totalSupply_ - uint256(_scr.scr)).wadMul(maxUtilizationRate());
|
|
537
|
+
uint256 supply = this.totalSupply().wadMul(maxUtilizationRate());
|
|
538
|
+
if (supply > uint256(_scr.scr)) return supply - uint256(_scr.scr);
|
|
506
539
|
else return 0;
|
|
507
540
|
}
|
|
508
541
|
|
|
@@ -645,8 +678,15 @@ contract EToken is Reserve, IERC20Metadata, IEToken {
|
|
|
645
678
|
* The only limit for withdraws is the `totalWithdrawable()` function, that's affected by the relation between the
|
|
646
679
|
* scr and the totalSupply.
|
|
647
680
|
*/
|
|
648
|
-
|
|
681
|
+
uint256 maxWithdraw = Math.min(balanceOf(provider), totalWithdrawable());
|
|
682
|
+
if (amount == type(uint256).max) amount = maxWithdraw;
|
|
649
683
|
if (amount == 0) return 0;
|
|
684
|
+
require(amount <= maxWithdraw, "amount > max withdrawable");
|
|
685
|
+
require(
|
|
686
|
+
address(_params.whitelist) == address(0) ||
|
|
687
|
+
_params.whitelist.acceptsWithdrawal(this, provider, amount),
|
|
688
|
+
"Liquidity Provider not whitelisted"
|
|
689
|
+
);
|
|
650
690
|
_burn(provider, amount);
|
|
651
691
|
_updateTokenInterestRate();
|
|
652
692
|
_transferTo(provider, amount);
|
|
@@ -669,16 +709,23 @@ contract EToken is Reserve, IERC20Metadata, IEToken {
|
|
|
669
709
|
emit InternalBorrowerRemoved(borrower, defaultedDebt);
|
|
670
710
|
}
|
|
671
711
|
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
)
|
|
712
|
+
/**
|
|
713
|
+
* @dev Returns the maximum negative adjustment (discrete loss) the eToken can accept without breaking consistency.
|
|
714
|
+
* The limit comes from limits in the internal scale that takes scaledTotalSupply() to totalSupply()
|
|
715
|
+
*/
|
|
716
|
+
function maxNegativeAdjustment() public view returns (uint256) {
|
|
717
|
+
return totalSupply() - _tsScaled.minValue(); // Min value accepted by _tsScaled
|
|
718
|
+
}
|
|
719
|
+
|
|
720
|
+
function internalLoan(uint256 amount, address receiver)
|
|
721
|
+
external
|
|
722
|
+
override
|
|
723
|
+
onlyBorrower
|
|
724
|
+
whenNotPaused
|
|
725
|
+
returns (uint256)
|
|
726
|
+
{
|
|
677
727
|
uint256 amountAsked = amount;
|
|
678
|
-
amount = Math.min(
|
|
679
|
-
Math.min(amount, fromAvailable ? fundsAvailable() : totalSupply()),
|
|
680
|
-
_tsScaled.maxNegativeAdjustment(tokenInterestRate())
|
|
681
|
-
);
|
|
728
|
+
amount = Math.min(amount, maxNegativeAdjustment());
|
|
682
729
|
if (amount == 0) return amountAsked;
|
|
683
730
|
TimeScaled.ScaledAmount storage loan = _loans[_msgSender()];
|
|
684
731
|
loan.add(amount, internalLoanInterestRate());
|
|
@@ -14,10 +14,27 @@ import {IEToken} from "./interfaces/IEToken.sol";
|
|
|
14
14
|
*/
|
|
15
15
|
contract LPManualWhitelist is ILPWhitelist, PolicyPoolComponent {
|
|
16
16
|
bytes32 public constant LP_WHITELIST_ROLE = keccak256("LP_WHITELIST_ROLE");
|
|
17
|
+
bytes32 public constant LP_WHITELIST_ADMIN_ROLE = keccak256("LP_WHITELIST_ADMIN_ROLE");
|
|
17
18
|
|
|
18
|
-
|
|
19
|
+
/**
|
|
20
|
+
* @dev Enum with the different options for whitelisting status
|
|
21
|
+
*/
|
|
22
|
+
enum WhitelistOptions {
|
|
23
|
+
undefined,
|
|
24
|
+
whitelisted,
|
|
25
|
+
blacklisted
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
struct WhitelistStatus {
|
|
29
|
+
WhitelistOptions deposit;
|
|
30
|
+
WhitelistOptions withdraw;
|
|
31
|
+
WhitelistOptions sendTransfer;
|
|
32
|
+
WhitelistOptions receiveTransfer;
|
|
33
|
+
}
|
|
19
34
|
|
|
20
|
-
|
|
35
|
+
mapping(address => WhitelistStatus) private _wlStatus;
|
|
36
|
+
|
|
37
|
+
event LPWhitelistStatusChanged(address provider, WhitelistStatus whitelisted);
|
|
21
38
|
|
|
22
39
|
/// @custom:oz-upgrades-unsafe-allow constructor
|
|
23
40
|
// solhint-disable-next-line no-empty-blocks
|
|
@@ -26,18 +43,62 @@ contract LPManualWhitelist is ILPWhitelist, PolicyPoolComponent {
|
|
|
26
43
|
/**
|
|
27
44
|
* @dev Initializes the Whitelist contract
|
|
28
45
|
*/
|
|
29
|
-
function initialize() public initializer {
|
|
46
|
+
function initialize(WhitelistStatus calldata defaultStatus) public virtual initializer {
|
|
47
|
+
__LPManualWhitelist_init(defaultStatus);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
// solhint-disable-next-line func-name-mixedcase
|
|
51
|
+
function __LPManualWhitelist_init(WhitelistStatus calldata defaultStatus)
|
|
52
|
+
internal
|
|
53
|
+
onlyInitializing
|
|
54
|
+
{
|
|
30
55
|
__PolicyPoolComponent_init();
|
|
56
|
+
__LPManualWhitelist_init_unchained(defaultStatus);
|
|
31
57
|
}
|
|
32
58
|
|
|
33
|
-
|
|
59
|
+
// solhint-disable-next-line func-name-mixedcase
|
|
60
|
+
function __LPManualWhitelist_init_unchained(WhitelistStatus calldata defaultStatus)
|
|
61
|
+
internal
|
|
62
|
+
onlyInitializing
|
|
63
|
+
{
|
|
64
|
+
_checkDefaultStatus(defaultStatus);
|
|
65
|
+
_wlStatus[address(0)] = defaultStatus;
|
|
66
|
+
emit LPWhitelistStatusChanged(address(0), defaultStatus);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
function whitelistAddress(address provider, WhitelistStatus calldata newStatus)
|
|
34
70
|
external
|
|
35
71
|
onlyComponentRole(LP_WHITELIST_ROLE)
|
|
36
72
|
{
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
73
|
+
require(provider != address(0), "You can't change the defaults");
|
|
74
|
+
_whitelistAddress(provider, newStatus);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
function _checkDefaultStatus(WhitelistStatus calldata newStatus) internal pure {
|
|
78
|
+
require(
|
|
79
|
+
newStatus.deposit != WhitelistOptions.undefined &&
|
|
80
|
+
newStatus.withdraw != WhitelistOptions.undefined &&
|
|
81
|
+
newStatus.sendTransfer != WhitelistOptions.undefined &&
|
|
82
|
+
newStatus.receiveTransfer != WhitelistOptions.undefined,
|
|
83
|
+
"You need to define the default status for all the operations"
|
|
84
|
+
);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
function setWhitelistDefaults(WhitelistStatus calldata newStatus)
|
|
88
|
+
external
|
|
89
|
+
onlyComponentRole(LP_WHITELIST_ADMIN_ROLE)
|
|
90
|
+
{
|
|
91
|
+
_checkDefaultStatus(newStatus);
|
|
92
|
+
_whitelistAddress(address(0), newStatus);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
function getWhitelistDefaults() external view returns (WhitelistStatus memory) {
|
|
96
|
+
return _wlStatus[address(0)];
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
function _whitelistAddress(address provider, WhitelistStatus memory newStatus) internal {
|
|
100
|
+
_wlStatus[provider] = newStatus;
|
|
101
|
+
emit LPWhitelistStatusChanged(provider, newStatus);
|
|
41
102
|
}
|
|
42
103
|
|
|
43
104
|
/**
|
|
@@ -52,16 +113,41 @@ contract LPManualWhitelist is ILPWhitelist, PolicyPoolComponent {
|
|
|
52
113
|
address provider,
|
|
53
114
|
uint256
|
|
54
115
|
) external view override returns (bool) {
|
|
55
|
-
|
|
116
|
+
WhitelistOptions wl = _wlStatus[provider].deposit;
|
|
117
|
+
if (wl == WhitelistOptions.undefined) {
|
|
118
|
+
wl = _wlStatus[address(0)].deposit;
|
|
119
|
+
}
|
|
120
|
+
return wl == WhitelistOptions.whitelisted;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
function acceptsWithdrawal(
|
|
124
|
+
IEToken,
|
|
125
|
+
address provider,
|
|
126
|
+
uint256
|
|
127
|
+
) external view override returns (bool) {
|
|
128
|
+
WhitelistOptions wl = _wlStatus[provider].withdraw;
|
|
129
|
+
if (wl == WhitelistOptions.undefined) {
|
|
130
|
+
wl = _wlStatus[address(0)].withdraw;
|
|
131
|
+
}
|
|
132
|
+
return wl == WhitelistOptions.whitelisted;
|
|
56
133
|
}
|
|
57
134
|
|
|
58
135
|
function acceptsTransfer(
|
|
59
136
|
IEToken,
|
|
60
|
-
address,
|
|
137
|
+
address providerFrom,
|
|
61
138
|
address providerTo,
|
|
62
139
|
uint256
|
|
63
140
|
) external view override returns (bool) {
|
|
64
|
-
|
|
141
|
+
WhitelistOptions wl = _wlStatus[providerFrom].sendTransfer;
|
|
142
|
+
if (wl == WhitelistOptions.undefined) {
|
|
143
|
+
wl = _wlStatus[address(0)].sendTransfer;
|
|
144
|
+
}
|
|
145
|
+
if (wl != WhitelistOptions.whitelisted) return false;
|
|
146
|
+
wl = _wlStatus[providerTo].receiveTransfer;
|
|
147
|
+
if (wl == WhitelistOptions.undefined) {
|
|
148
|
+
wl = _wlStatus[address(0)].receiveTransfer;
|
|
149
|
+
}
|
|
150
|
+
return wl == WhitelistOptions.whitelisted;
|
|
65
151
|
}
|
|
66
152
|
|
|
67
153
|
/**
|
|
@@ -65,9 +65,20 @@ contract PremiumsAccount is IPremiumsAccount, Reserve {
|
|
|
65
65
|
*/
|
|
66
66
|
int256 internal _surplus;
|
|
67
67
|
|
|
68
|
+
/**
|
|
69
|
+
* @dev This struct has the parameters that can be modified by governance
|
|
70
|
+
* @member deficitRatio A value between [0, 1] that defines the percentage of active pure premiums that can be used
|
|
71
|
+
* to cover losses.
|
|
72
|
+
* @member assetManager This is the implementation contract that manages the PremiumsAccount's funds. See
|
|
73
|
+
* {IAssetManager}
|
|
74
|
+
* @member jrLoanLimit This is the maximum amount that can be borrowed from the Junior eToken (without decimals)
|
|
75
|
+
* @member srLoanLimit This is the maximum amount that can be borrowed from the Senior eToken (without decimals)
|
|
76
|
+
*/
|
|
68
77
|
struct PackedParams {
|
|
69
78
|
uint16 deficitRatio;
|
|
70
79
|
IAssetManager assetManager;
|
|
80
|
+
uint32 jrLoanLimit;
|
|
81
|
+
uint32 srLoanLimit;
|
|
71
82
|
}
|
|
72
83
|
|
|
73
84
|
PackedParams internal _params;
|
|
@@ -120,7 +131,9 @@ contract PremiumsAccount is IPremiumsAccount, Reserve {
|
|
|
120
131
|
*/
|
|
121
132
|
_params = PackedParams({
|
|
122
133
|
deficitRatio: HUNDRED_PERCENT,
|
|
123
|
-
assetManager: IAssetManager(address(0))
|
|
134
|
+
assetManager: IAssetManager(address(0)),
|
|
135
|
+
jrLoanLimit: 0,
|
|
136
|
+
srLoanLimit: 0
|
|
124
137
|
});
|
|
125
138
|
_validateParameters();
|
|
126
139
|
}
|
|
@@ -240,6 +253,16 @@ contract PremiumsAccount is IPremiumsAccount, Reserve {
|
|
|
240
253
|
return -int256(_activePurePremiums.wadMul(ratio));
|
|
241
254
|
}
|
|
242
255
|
|
|
256
|
+
function _toAmount(uint32 value) internal view returns (uint256) {
|
|
257
|
+
// 0 decimals to amount decimals
|
|
258
|
+
return uint256(value) * 10**currency().decimals();
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
function _toZeroDecimals(uint256 amount) internal view returns (uint32) {
|
|
262
|
+
// Removes the decimals from the amount
|
|
263
|
+
return (amount / 10**currency().decimals()).toUint32();
|
|
264
|
+
}
|
|
265
|
+
|
|
243
266
|
/**
|
|
244
267
|
* @dev Returns the percentage of the active pure premiums that can be used to cover losses of finalized policies.
|
|
245
268
|
*/
|
|
@@ -247,6 +270,20 @@ contract PremiumsAccount is IPremiumsAccount, Reserve {
|
|
|
247
270
|
return uint256(_params.deficitRatio) * FOUR_DECIMAL_TO_WAD; // 4 -> 18 decimals
|
|
248
271
|
}
|
|
249
272
|
|
|
273
|
+
/**
|
|
274
|
+
* @dev Returns the limit on the Junior eToken loans (infinite if _params.jrLoanLimit == 0)
|
|
275
|
+
*/
|
|
276
|
+
function jrLoanLimit() public view returns (uint256) {
|
|
277
|
+
return _params.jrLoanLimit == 0 ? type(uint256).max : _toAmount(_params.jrLoanLimit);
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
/**
|
|
281
|
+
* @dev Returns the limit on the Senior eToken loans (infinite if _params.srLoanLimit == 0)
|
|
282
|
+
*/
|
|
283
|
+
function srLoanLimit() public view returns (uint256) {
|
|
284
|
+
return _params.srLoanLimit == 0 ? type(uint256).max : _toAmount(_params.srLoanLimit);
|
|
285
|
+
}
|
|
286
|
+
|
|
250
287
|
/**
|
|
251
288
|
* @dev Changes the `deficitRatio` parameter.
|
|
252
289
|
*
|
|
@@ -262,7 +299,7 @@ contract PremiumsAccount is IPremiumsAccount, Reserve {
|
|
|
262
299
|
*/
|
|
263
300
|
function setDeficitRatio(uint256 newRatio, bool adjustment)
|
|
264
301
|
external
|
|
265
|
-
|
|
302
|
+
onlyGlobalOrComponentRole(LEVEL2_ROLE)
|
|
266
303
|
{
|
|
267
304
|
require(newRatio <= 1e18, "Validation: deficitRatio must be <= 1");
|
|
268
305
|
|
|
@@ -287,6 +324,36 @@ contract PremiumsAccount is IPremiumsAccount, Reserve {
|
|
|
287
324
|
_parameterChanged(action, newRatio, false);
|
|
288
325
|
}
|
|
289
326
|
|
|
327
|
+
/**
|
|
328
|
+
* @dev Changes the `jrLoanLimit` or `srLoanLimit` parameter.
|
|
329
|
+
*
|
|
330
|
+
* Requirements:
|
|
331
|
+
* - onlyGlobalOrComponentRole(LEVEL2_ROLE)
|
|
332
|
+
*
|
|
333
|
+
* Events:
|
|
334
|
+
* - Emits GovernanceAction with action = setDeficitRatio or setDeficitRatioWithAdjustment if an adjustment was made.
|
|
335
|
+
*
|
|
336
|
+
* @param newLimitJr The new limit to be set for the loans taken from the Junior eToken.
|
|
337
|
+
If newLimitJr == MAX_UINT, it's ignored. If == 0, means the loans are unbounded.
|
|
338
|
+
* @param newLimitSr The new limit to be set for the loans taken from the Senior eToken.
|
|
339
|
+
If newLimitSr == MAX_UINT, it's ignored. If == 0, means the loans are unbounded.
|
|
340
|
+
*/
|
|
341
|
+
function setLoanLimits(uint256 newLimitJr, uint256 newLimitSr)
|
|
342
|
+
external
|
|
343
|
+
onlyGlobalOrComponentRole(LEVEL2_ROLE)
|
|
344
|
+
{
|
|
345
|
+
if (newLimitJr != type(uint256).max) {
|
|
346
|
+
_params.jrLoanLimit = _toZeroDecimals(newLimitJr);
|
|
347
|
+
require(_toAmount(_params.jrLoanLimit) == newLimitJr, "Validation: no decimals allowed");
|
|
348
|
+
_parameterChanged(IAccessManager.GovernanceActions.setJrLoanLimit, newLimitJr, false);
|
|
349
|
+
}
|
|
350
|
+
if (newLimitSr != type(uint256).max) {
|
|
351
|
+
_params.srLoanLimit = _toZeroDecimals(newLimitSr);
|
|
352
|
+
require(_toAmount(_params.srLoanLimit) == newLimitSr, "Validation: no decimals allowed");
|
|
353
|
+
_parameterChanged(IAccessManager.GovernanceActions.setSrLoanLimit, newLimitSr, false);
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
|
|
290
357
|
/**
|
|
291
358
|
* @dev Internal function called when money in the PremiumsAccount is not enough and we need to borrow from the
|
|
292
359
|
* eTokens.
|
|
@@ -302,17 +369,22 @@ contract PremiumsAccount is IPremiumsAccount, Reserve {
|
|
|
302
369
|
bool jrEtk
|
|
303
370
|
) internal {
|
|
304
371
|
require(receiver != address(0), "PremiumsAccount: receiver cannot be the zero address");
|
|
305
|
-
uint256 left;
|
|
372
|
+
uint256 left = borrow;
|
|
306
373
|
if (jrEtk) {
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
374
|
+
if (_juniorEtk.getLoan(address(this)) + borrow <= jrLoanLimit()) {
|
|
375
|
+
left = _juniorEtk.internalLoan(borrow, receiver);
|
|
376
|
+
} else if (_juniorEtk.getLoan(address(this)) < jrLoanLimit()) {
|
|
377
|
+
// Partial loan
|
|
378
|
+
uint256 loanExcess = _juniorEtk.getLoan(address(this)) + borrow - jrLoanLimit();
|
|
379
|
+
left = loanExcess + _juniorEtk.internalLoan(borrow - loanExcess, receiver);
|
|
380
|
+
}
|
|
311
381
|
}
|
|
312
382
|
if (left > NEGLIGIBLE_AMOUNT) {
|
|
313
383
|
// Consume Senior Pool only up to SCR
|
|
314
|
-
|
|
315
|
-
|
|
384
|
+
if (_seniorEtk.getLoan(address(this)) + left < srLoanLimit()) {
|
|
385
|
+
left = _seniorEtk.internalLoan(left, receiver);
|
|
386
|
+
} // in the senior eToken doesn't make sense to handle partial loan
|
|
387
|
+
require(left <= NEGLIGIBLE_AMOUNT, "Don't know where to source the rest of the money");
|
|
316
388
|
}
|
|
317
389
|
}
|
|
318
390
|
|
|
@@ -360,9 +432,16 @@ contract PremiumsAccount is IPremiumsAccount, Reserve {
|
|
|
360
432
|
* @param amount The amount to be transferred.
|
|
361
433
|
*/
|
|
362
434
|
function receiveGrant(uint256 amount) external {
|
|
363
|
-
|
|
364
|
-
|
|
435
|
+
// I need to receive the money first (without following the Check-Effects-Interactions) pattern because I need
|
|
436
|
+
// the money to pay the eTokens
|
|
365
437
|
currency().safeTransferFrom(_msgSender(), address(this), amount);
|
|
438
|
+
uint256 purePremiumWon = amount;
|
|
439
|
+
if (address(_seniorEtk) != address(0)) purePremiumWon = _repayLoan(purePremiumWon, _seniorEtk);
|
|
440
|
+
if (address(_juniorEtk) != address(0)) purePremiumWon = _repayLoan(purePremiumWon, _juniorEtk);
|
|
441
|
+
|
|
442
|
+
// Finally store purePremiumWon
|
|
443
|
+
_storePurePremiumWon(purePremiumWon);
|
|
444
|
+
emit WonPremiumsInOut(true, amount);
|
|
366
445
|
}
|
|
367
446
|
|
|
368
447
|
/**
|
package/contracts/RiskModule.sol
CHANGED
|
@@ -185,12 +185,12 @@ abstract contract RiskModule is IRiskModule, PolicyPoolComponent {
|
|
|
185
185
|
|
|
186
186
|
// solhint-disable-next-line func-name-mixedcase
|
|
187
187
|
function _XtoAmount(uint8 decimals, uint32 value) internal view returns (uint256) {
|
|
188
|
-
// X decimals to
|
|
188
|
+
// X decimals to currency decimals (6 for USDC)
|
|
189
189
|
return uint256(value) * 10**(currency().decimals() - decimals);
|
|
190
190
|
}
|
|
191
191
|
|
|
192
192
|
function _amountToX(uint8 decimals, uint256 value) internal view returns (uint32) {
|
|
193
|
-
//
|
|
193
|
+
// currency decimals to X decimals (assuming X < currency decimals)
|
|
194
194
|
return (value / 10**(currency().decimals() - decimals)).toUint32();
|
|
195
195
|
}
|
|
196
196
|
|
package/contracts/TimeScaled.sol
CHANGED
|
@@ -125,14 +125,7 @@ library TimeScaled {
|
|
|
125
125
|
require(scaledAmount.scale >= MIN_SCALE, "Scale too small, can lead to rounding errors");
|
|
126
126
|
}
|
|
127
127
|
|
|
128
|
-
function
|
|
129
|
-
|
|
130
|
-
view
|
|
131
|
-
returns (uint256)
|
|
132
|
-
{
|
|
133
|
-
uint256 ts = getScaledAmount(scaledAmount, interestRate);
|
|
134
|
-
uint256 minTs = uint256(scaledAmount.amount).wadToRay().rayMul(MIN_SCALE).rayToWad();
|
|
135
|
-
if (ts > minTs) return ts - minTs;
|
|
136
|
-
else return 0;
|
|
128
|
+
function minValue(ScaledAmount storage scaledAmount) internal view returns (uint256) {
|
|
129
|
+
return uint256(scaledAmount.amount).wadToRay().rayMul(MIN_SCALE).rayToWad();
|
|
137
130
|
}
|
|
138
131
|
}
|
|
@@ -52,10 +52,10 @@ interface IAccessManager is IAccessControlUpgradeable {
|
|
|
52
52
|
// PremiumsAccount Governance Actions
|
|
53
53
|
setDeficitRatio,
|
|
54
54
|
setDeficitRatioWithAdjustment,
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
paFiller3,
|
|
58
|
-
paFiller4,
|
|
55
|
+
setJrLoanLimit,
|
|
56
|
+
setSrLoanLimit,
|
|
57
|
+
paFiller3, // Reserve space for future PremiumsAccount actions
|
|
58
|
+
paFiller4, // Reserve space for future PremiumsAccount actions
|
|
59
59
|
// AssetManager Governance Actions
|
|
60
60
|
setLiquidityMin,
|
|
61
61
|
setLiquidityMiddle,
|
|
@@ -152,15 +152,9 @@ interface IEToken is IERC20 {
|
|
|
152
152
|
*
|
|
153
153
|
* @param amount The amount required
|
|
154
154
|
* @param receiver The received of the funds lent. This is usually the policyholder if the loan is used for a payout.
|
|
155
|
-
* @param fromAvailable If `true`, the funds that can be lent are only the available ones, i.e., excluding the funds
|
|
156
|
-
* locked as `scr()`. If `false`, all the `totalSupply()` is available to be lent.
|
|
157
155
|
* @return Returns the amount that wasn't able to fulfil. `amount - lent`
|
|
158
156
|
*/
|
|
159
|
-
function internalLoan(
|
|
160
|
-
uint256 amount,
|
|
161
|
-
address receiver,
|
|
162
|
-
bool fromAvailable
|
|
163
|
-
) external returns (uint256);
|
|
157
|
+
function internalLoan(uint256 amount, address receiver) external returns (uint256);
|
|
164
158
|
|
|
165
159
|
/**
|
|
166
160
|
* @dev Repays a loan taken with `internalLoan`.
|
|
@@ -37,4 +37,18 @@ interface ILPWhitelist {
|
|
|
37
37
|
address providerTo,
|
|
38
38
|
uint256 amount
|
|
39
39
|
) external view returns (bool);
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* @dev Indicates whether or not a liquidity provider can withdraw an eToken.
|
|
43
|
+
*
|
|
44
|
+
* @param etoken The eToken (see {EToken}) where the provider wants to withdraw money.
|
|
45
|
+
* @param provider The address of the liquidity provider (user) that wants to withdraw
|
|
46
|
+
* @param amount The amount of the withdrawal
|
|
47
|
+
* @return true if `provider` withdraw request is accepted, false if not
|
|
48
|
+
*/
|
|
49
|
+
function acceptsWithdrawal(
|
|
50
|
+
IEToken etoken,
|
|
51
|
+
address provider,
|
|
52
|
+
uint256 amount
|
|
53
|
+
) external view returns (bool);
|
|
40
54
|
}
|
package/js/deploy.js
CHANGED
|
@@ -7,6 +7,12 @@ const _BN = ethers.BigNumber.from;
|
|
|
7
7
|
const WAD = _BN(1e10).mul(_BN(1e8)); // 1e10*1e8=1e18
|
|
8
8
|
const RAY = WAD.mul(_BN(1e9)); // 1e18*1e9=1e27
|
|
9
9
|
|
|
10
|
+
const WhitelistStatus = {
|
|
11
|
+
notdefined: 0,
|
|
12
|
+
whitelisted: 1,
|
|
13
|
+
blacklisted: 2,
|
|
14
|
+
};
|
|
15
|
+
|
|
10
16
|
/**
|
|
11
17
|
* Creates a fixed-point conversion function for the desired number of decimals
|
|
12
18
|
* @param decimals The number of decimals. Must be >= 6.
|
|
@@ -153,10 +159,8 @@ async function deployProxyContract({ saveAddr, verify, contractClass, constructo
|
|
|
153
159
|
}
|
|
154
160
|
|
|
155
161
|
function parseRole(role) {
|
|
156
|
-
if (role.startsWith("0x"))
|
|
157
|
-
|
|
158
|
-
if (role === "DEFAULT_ADMIN_ROLE")
|
|
159
|
-
return ethers.constants.HashZero;
|
|
162
|
+
if (role.startsWith("0x")) return role;
|
|
163
|
+
if (role === "DEFAULT_ADMIN_ROLE") return ethers.constants.HashZero;
|
|
160
164
|
return ethers.utils.keccak256(ethers.utils.toUtf8Bytes(role));
|
|
161
165
|
}
|
|
162
166
|
|
|
@@ -255,8 +259,7 @@ async function deployEToken(
|
|
|
255
259
|
hre
|
|
256
260
|
);
|
|
257
261
|
const policyPool = await hre.ethers.getContractAt("PolicyPool", poolAddress);
|
|
258
|
-
if (opts.addComponent)
|
|
259
|
-
await policyPool.addComponent(contract.address, 1);
|
|
262
|
+
if (opts.addComponent) await policyPool.addComponent(contract.address, 1);
|
|
260
263
|
return contract.address;
|
|
261
264
|
}
|
|
262
265
|
|
|
@@ -271,8 +274,7 @@ async function deployPremiumsAccount({ poolAddress, juniorEtk, seniorEtk, ...opt
|
|
|
271
274
|
hre
|
|
272
275
|
);
|
|
273
276
|
const policyPool = await hre.ethers.getContractAt("PolicyPool", poolAddress);
|
|
274
|
-
if (opts.addComponent)
|
|
275
|
-
await policyPool.addComponent(contract.address, 3);
|
|
277
|
+
if (opts.addComponent) await policyPool.addComponent(contract.address, 3);
|
|
276
278
|
return contract.address;
|
|
277
279
|
}
|
|
278
280
|
|
|
@@ -338,11 +340,10 @@ async function deployRiskModule(
|
|
|
338
340
|
await rm.setParam(4, ensuroCocFee);
|
|
339
341
|
}
|
|
340
342
|
if (maxDuration != 24 * 365) {
|
|
341
|
-
await rm.setParam(9,
|
|
343
|
+
await rm.setParam(9, maxDuration);
|
|
342
344
|
}
|
|
343
345
|
const policyPool = await hre.ethers.getContractAt("PolicyPool", poolAddress);
|
|
344
|
-
if (opts.addComponent)
|
|
345
|
-
await policyPool.addComponent(contract.address, 2);
|
|
346
|
+
if (opts.addComponent) await policyPool.addComponent(contract.address, 2);
|
|
346
347
|
return contract.address;
|
|
347
348
|
}
|
|
348
349
|
|
|
@@ -415,10 +416,16 @@ async function deployAaveAssetManager({ asset, aave, amClass, ...opts }, hre) {
|
|
|
415
416
|
}
|
|
416
417
|
|
|
417
418
|
async function deployWhitelist(
|
|
418
|
-
{ wlClass, poolAddress, extraConstructorArgs, extraArgs, eToken, eToken2, eToken3, ...opts },
|
|
419
|
+
{ wlClass, poolAddress, extraConstructorArgs, extraArgs, eToken, eToken2, eToken3, defaultStatus, ...opts },
|
|
419
420
|
hre
|
|
420
421
|
) {
|
|
421
422
|
extraArgs = extraArgs || [];
|
|
423
|
+
if (defaultStatus !== "") {
|
|
424
|
+
defaultStatus = defaultStatus
|
|
425
|
+
.split("")
|
|
426
|
+
.map((WB) => (WB == "W" ? WhitelistStatus.whitelisted : WhitelistStatus.blacklisted));
|
|
427
|
+
extraArgs.splice(0, 0, defaultStatus);
|
|
428
|
+
}
|
|
422
429
|
extraConstructorArgs = extraConstructorArgs || [];
|
|
423
430
|
const { contract } = await deployProxyContract(
|
|
424
431
|
{
|
|
@@ -706,6 +713,7 @@ function add_task() {
|
|
|
706
713
|
.addOptionalParam("eToken", "Set the Whitelist to a given eToken", undefined, types.address)
|
|
707
714
|
.addOptionalParam("eToken2", "Set the Whitelist to a given eToken", undefined, types.address)
|
|
708
715
|
.addOptionalParam("eToken3", "Set the Whitelist to a given eToken", undefined, types.address)
|
|
716
|
+
.addOptionalParam("defaultStatus", "Default Status Ej: 'BWWB'", "BWWB", types.str)
|
|
709
717
|
.addParam("poolAddress", "PolicyPool Address", types.address)
|
|
710
718
|
.setAction(deployWhitelist);
|
|
711
719
|
|
|
@@ -776,4 +784,5 @@ module.exports = {
|
|
|
776
784
|
deploySignedQuoteRM,
|
|
777
785
|
setAssetManager,
|
|
778
786
|
deployWhitelist,
|
|
787
|
+
WhitelistStatus,
|
|
779
788
|
};
|
package/js/test-utils.js
CHANGED
|
@@ -414,8 +414,8 @@ function makePolicyId(rm, internalId) {
|
|
|
414
414
|
|
|
415
415
|
exports.makePolicyId = makePolicyId;
|
|
416
416
|
|
|
417
|
-
async function makePolicy(pool, rm, cust, payout, premium, lossProb, expiration, internalId) {
|
|
418
|
-
let tx = await rm.connect(cust)
|
|
417
|
+
async function makePolicy(pool, rm, cust, payout, premium, lossProb, expiration, internalId, method = "newPolicy") {
|
|
418
|
+
let tx = await rm.connect(cust)[method](payout, premium, lossProb, expiration, cust.address, internalId);
|
|
419
419
|
let receipt = await tx.wait();
|
|
420
420
|
const newPolicyEvt = getTransactionEvent(pool.interface, receipt, "NewPolicy");
|
|
421
421
|
|