@ensuro/core 2.2.1 → 2.4.0

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.
Files changed (29) hide show
  1. package/build/contracts/AccessManager.sol/AccessManager.json +2 -2
  2. package/build/contracts/ERC4626AssetManager.sol/ERC4626AssetManager.json +2 -2
  3. package/build/contracts/EToken.sol/EToken.json +2 -2
  4. package/build/contracts/LPManualWhitelist.sol/LPManualWhitelist.json +2 -2
  5. package/build/contracts/Policy.sol/Policy.json +2 -2
  6. package/build/contracts/PolicyPool.sol/PolicyPool.json +2 -2
  7. package/build/contracts/PremiumsAccount.sol/PremiumsAccount.json +41 -2
  8. package/build/contracts/SignedQuoteRiskModule.sol/SignedQuoteRiskModule.json +2 -2
  9. package/build/contracts/TieredSignedQuoteRiskModule.sol/TieredSignedQuoteRiskModule.json +1316 -0
  10. package/build/contracts/TimeScaled.sol/TimeScaled.json +2 -2
  11. package/build/contracts/TrustfulRiskModule.sol/TrustfulRiskModule.json +2 -2
  12. package/build/contracts/migration/LPManualWhitelistV20Upgraded.sol/LPManualWhitelistV20Upgraded.json +2 -2
  13. package/build/contracts/mocks/FixedRateVault.sol/FixedRateVault.json +6 -6
  14. package/build/contracts/mocks/InterfaceIdCalculator.sol/InterfaceIdCalculator.json +2 -2
  15. package/build/contracts/mocks/PolicyPoolComponentMock.sol/PolicyPoolComponentMock.json +2 -2
  16. package/build/contracts/mocks/PolicyPoolMock.sol/PolicyPoolMock.json +2 -2
  17. package/build/contracts/mocks/PolicyPoolMock.sol/PolicyPoolMockForward.json +2 -2
  18. package/build/contracts/mocks/RiskModuleMock.sol/RiskModuleMock.json +2 -2
  19. package/build/contracts/mocks/TestCurrency.sol/TestCurrency.json +2 -2
  20. package/build/contracts/mocks/TestNFT.sol/TestNFT.json +2 -2
  21. package/contracts/PolicyPool.sol +3 -2
  22. package/contracts/PremiumsAccount.sol +61 -56
  23. package/contracts/RiskModule.sol +5 -38
  24. package/contracts/SignedQuoteRiskModule.sol +3 -3
  25. package/contracts/TieredSignedQuoteRiskModule.sol +165 -0
  26. package/contracts/TrustfulRiskModule.sol +7 -2
  27. package/js/deploy.js +31 -7
  28. package/js/test-utils.js +41 -29
  29. package/package.json +1 -1
@@ -35,6 +35,7 @@ contract PremiumsAccount is IPremiumsAccount, Reserve {
35
35
  using SafeCast for uint256;
36
36
 
37
37
  bytes32 public constant WITHDRAW_WON_PREMIUMS_ROLE = keccak256("WITHDRAW_WON_PREMIUMS_ROLE");
38
+ bytes32 public constant REPAY_LOANS_ROLE = keccak256("REPAY_LOANS_ROLE");
38
39
  uint256 internal constant FOUR_DECIMAL_TO_WAD = 1e14;
39
40
  uint16 internal constant HUNDRED_PERCENT = 1e4;
40
41
 
@@ -92,6 +93,19 @@ contract PremiumsAccount is IPremiumsAccount, Reserve {
92
93
  */
93
94
  event WonPremiumsInOut(bool moneyIn, uint256 value);
94
95
 
96
+ /**
97
+ * @dev Modifier to make a function callable only by a certain global or component role.
98
+ * In addition to checking the sender's role, `address(0)` 's role is also
99
+ * considered. Granting a role to `address(0)` (at global or component level) is equivalent
100
+ * to enabling this role for everyone.
101
+ */
102
+ modifier onlyGlobalOrComponentOrOpenRole(bytes32 role) {
103
+ if (!_policyPool.access().hasComponentRole(address(this), role, address(0), true)) {
104
+ _policyPool.access().checkComponentRole(address(this), role, _msgSender(), true);
105
+ }
106
+ _;
107
+ }
108
+
95
109
  /**
96
110
  * @dev Constructor of the contract, sets the immutable fields.
97
111
  *
@@ -176,13 +190,10 @@ contract PremiumsAccount is IPremiumsAccount, Reserve {
176
190
  * loans to cover asset losses.
177
191
  */
178
192
  function _assetEarnings(int256 earningsOrLosses) internal override {
179
- if (earningsOrLosses > 0) {
180
- uint256 earnings = uint256(earningsOrLosses);
181
- if (address(_seniorEtk) != address(0)) earnings = _repayLoan(earnings, _seniorEtk);
182
- if (address(_juniorEtk) != address(0)) earnings = _repayLoan(earnings, _juniorEtk);
183
- _storePurePremiumWon(earnings);
193
+ if (earningsOrLosses >= 0) {
194
+ _storePurePremiumWon(uint256(earningsOrLosses));
184
195
  } else {
185
- require(_payFromPremiums(uint256(-earningsOrLosses)) == 0, "Losses can't exceed maxDeficit");
196
+ require(_payFromPremiums(-earningsOrLosses) == 0, "Losses can't exceed maxDeficit");
186
197
  }
187
198
  }
188
199
 
@@ -230,6 +241,14 @@ contract PremiumsAccount is IPremiumsAccount, Reserve {
230
241
  return _surplus;
231
242
  }
232
243
 
244
+ /**
245
+ * @dev Returns the amount of funds available to cover losses or repay eToken loans.
246
+ */
247
+ function fundsAvailable() public view returns (uint256) {
248
+ // This is guaranteed to be positive because _maxDeficit is negative and always gte _surplus in absolute value
249
+ return uint256(_surplus - _maxDeficit(deficitRatio()));
250
+ }
251
+
233
252
  function seniorEtk() external view override returns (IEToken) {
234
253
  return _seniorEtk;
235
254
  }
@@ -301,8 +320,6 @@ contract PremiumsAccount is IPremiumsAccount, Reserve {
301
320
  external
302
321
  onlyGlobalOrComponentRole(LEVEL2_ROLE)
303
322
  {
304
- require(newRatio <= 1e18, "Validation: deficitRatio must be <= 1");
305
-
306
323
  uint16 truncatedRatio = (newRatio / FOUR_DECIMAL_TO_WAD).toUint16();
307
324
  require(
308
325
  uint256(truncatedRatio) * FOUR_DECIMAL_TO_WAD == newRatio,
@@ -311,6 +328,8 @@ contract PremiumsAccount is IPremiumsAccount, Reserve {
311
328
 
312
329
  int256 maxDeficit = _maxDeficit(newRatio);
313
330
  require(adjustment || _surplus >= maxDeficit, "Validation: surplus must be >= maxDeficit");
331
+ _params.deficitRatio = truncatedRatio;
332
+ _validateParameters();
314
333
 
315
334
  IAccessManager.GovernanceActions action = IAccessManager.GovernanceActions.setDeficitRatio;
316
335
  if (_surplus < maxDeficit) {
@@ -320,7 +339,6 @@ contract PremiumsAccount is IPremiumsAccount, Reserve {
320
339
  _borrowFromEtk(borrow, address(this), address(_juniorEtk) != address(0));
321
340
  action = IAccessManager.GovernanceActions.setDeficitRatioWithAdjustment;
322
341
  }
323
- _params.deficitRatio = truncatedRatio;
324
342
  _parameterChanged(action, newRatio, false);
325
343
  }
326
344
 
@@ -368,7 +386,6 @@ contract PremiumsAccount is IPremiumsAccount, Reserve {
368
386
  address receiver,
369
387
  bool jrEtk
370
388
  ) internal {
371
- require(receiver != address(0), "PremiumsAccount: receiver cannot be the zero address");
372
389
  uint256 left = borrow;
373
390
  if (jrEtk) {
374
391
  if (_juniorEtk.getLoan(address(this)) + borrow <= jrLoanLimit()) {
@@ -395,8 +412,8 @@ contract PremiumsAccount is IPremiumsAccount, Reserve {
395
412
  * @param toPay The amount to pay.
396
413
  * @return The amount that couldn't be paid from the premiums account.
397
414
  */
398
- function _payFromPremiums(uint256 toPay) internal returns (uint256) {
399
- int256 newSurplus = _surplus - int256(toPay);
415
+ function _payFromPremiums(int256 toPay) internal returns (uint256) {
416
+ int256 newSurplus = _surplus - toPay;
400
417
  int256 maxDeficit = _maxDeficit(deficitRatio());
401
418
  if (newSurplus >= maxDeficit) {
402
419
  _surplus = newSurplus;
@@ -413,7 +430,6 @@ contract PremiumsAccount is IPremiumsAccount, Reserve {
413
430
  * @param purePremiumWon The amount earned
414
431
  */
415
432
  function _storePurePremiumWon(uint256 purePremiumWon) internal {
416
- if (purePremiumWon == 0) return;
417
433
  _surplus += int256(purePremiumWon);
418
434
  }
419
435
 
@@ -432,15 +448,8 @@ contract PremiumsAccount is IPremiumsAccount, Reserve {
432
448
  * @param amount The amount to be transferred.
433
449
  */
434
450
  function receiveGrant(uint256 amount) external {
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
451
+ _storePurePremiumWon(amount);
437
452
  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
453
  emit WonPremiumsInOut(true, amount);
445
454
  }
446
455
 
@@ -497,23 +506,14 @@ contract PremiumsAccount is IPremiumsAccount, Reserve {
497
506
  uint256 payout
498
507
  ) external override onlyPolicyPool whenNotPaused {
499
508
  _activePurePremiums -= policy.purePremium;
500
- if (policy.purePremium >= payout) {
501
- uint256 purePremiumWon = policy.purePremium - payout;
502
- if (address(_seniorEtk) != address(0))
503
- purePremiumWon = _repayLoan(purePremiumWon, _seniorEtk);
504
- if (address(_juniorEtk) != address(0))
505
- purePremiumWon = _repayLoan(purePremiumWon, _juniorEtk);
506
- _storePurePremiumWon(purePremiumWon);
509
+ uint256 borrowFromScr = _payFromPremiums(int256(payout) - int256(policy.purePremium));
510
+ if (borrowFromScr != 0) {
507
511
  _unlockScr(policy);
508
- _transferTo(policyHolder, payout);
512
+ _borrowFromEtk(borrowFromScr, policyHolder, policy.jrScr > 0);
509
513
  } else {
510
- uint256 borrowFromScr = _payFromPremiums(payout - policy.purePremium);
511
514
  _unlockScr(policy);
512
- if (borrowFromScr > 0) {
513
- _borrowFromEtk(borrowFromScr, policyHolder, policy.jrScr > 0);
514
- }
515
- _transferTo(policyHolder, payout - borrowFromScr);
516
515
  }
516
+ _transferTo(policyHolder, payout - borrowFromScr);
517
517
  }
518
518
 
519
519
  /**
@@ -538,18 +538,37 @@ contract PremiumsAccount is IPremiumsAccount, Reserve {
538
538
  }
539
539
  }
540
540
 
541
+ /**
542
+ * @dev Function that repays the loan(s) if fundsAvailable
543
+ *
544
+ * @return available The funds still available after repayment
545
+ */
546
+ function repayLoans()
547
+ external
548
+ onlyGlobalOrComponentOrOpenRole(REPAY_LOANS_ROLE)
549
+ whenNotPaused
550
+ returns (uint256 available)
551
+ {
552
+ available = fundsAvailable();
553
+ if (available != 0 && address(_seniorEtk) != address(0))
554
+ available = _repayLoan(available, _seniorEtk);
555
+ if (available != 0 && address(_juniorEtk) != address(0))
556
+ available = _repayLoan(available, _juniorEtk);
557
+ return available;
558
+ }
559
+
541
560
  /**
542
561
  * @dev Internal function that repays a loan taken (if any outstanding) from the an eToken
543
562
  *
544
- * @param purePremiumWon The amount earned and available for loan repayment.
563
+ * @param fundsAvailable_ The amount of funds available for the repayment
545
564
  * @param etk The eToken with the potential debt
546
565
  * @return The excess amount of the purePremiumWon that wasn't used for the loan repayment.
547
566
  */
548
- function _repayLoan(uint256 purePremiumWon, IEToken etk) internal returns (uint256) {
549
- if (purePremiumWon < NEGLIGIBLE_AMOUNT) return purePremiumWon;
567
+ function _repayLoan(uint256 fundsAvailable_, IEToken etk) internal returns (uint256) {
550
568
  uint256 borrowedFromEtk = etk.getLoan(address(this));
551
- if (borrowedFromEtk == 0) return purePremiumWon;
552
- uint256 repayAmount = Math.min(purePremiumWon, borrowedFromEtk);
569
+ if (borrowedFromEtk == 0) return fundsAvailable_;
570
+ uint256 repayAmount = Math.min(fundsAvailable_, borrowedFromEtk);
571
+ _surplus -= int256(repayAmount);
553
572
 
554
573
  // If not enough liquidity, it deinvests from the asset manager
555
574
  if (currency().balanceOf(address(this)) < repayAmount) {
@@ -567,7 +586,7 @@ contract PremiumsAccount is IPremiumsAccount, Reserve {
567
586
  currency().approve(address(etk), borrowedFromEtk);
568
587
  }
569
588
  etk.repayLoan(repayAmount, address(this));
570
- return purePremiumWon - repayAmount;
589
+ return fundsAvailable_ - repayAmount;
571
590
  }
572
591
 
573
592
  function policyExpired(Policy.PolicyData memory policy)
@@ -576,22 +595,8 @@ contract PremiumsAccount is IPremiumsAccount, Reserve {
576
595
  onlyPolicyPool
577
596
  whenNotPaused
578
597
  {
579
- uint256 purePremiumWon = policy.purePremium;
580
- _activePurePremiums -= purePremiumWon;
581
-
582
- // If negative _activePurePremiums, repay this first (shouldn't happen)
583
- int256 maxDeficit = _maxDeficit(deficitRatio());
584
- if (_surplus < maxDeficit) {
585
- // Covers the excess of deficit first
586
- purePremiumWon -= uint256(-_surplus + maxDeficit);
587
- _surplus = maxDeficit;
588
- }
589
-
590
- if (address(_seniorEtk) != address(0)) purePremiumWon = _repayLoan(purePremiumWon, _seniorEtk);
591
- if (address(_juniorEtk) != address(0)) purePremiumWon = _repayLoan(purePremiumWon, _juniorEtk);
592
-
593
- // Finally store purePremiumWon
594
- _storePurePremiumWon(purePremiumWon);
598
+ _activePurePremiums -= policy.purePremium;
599
+ _storePurePremiumWon(policy.purePremium);
595
600
  _unlockScr(policy);
596
601
  }
597
602
 
@@ -26,8 +26,8 @@ abstract contract RiskModule is IRiskModule, PolicyPoolComponent {
26
26
 
27
27
  uint256 internal constant FOUR_DECIMAL_TO_WAD = 1e14;
28
28
  uint16 internal constant HUNDRED_PERCENT = 1e4;
29
- uint16 internal constant MIN_MOC = 5e3;
30
- uint16 internal constant MAX_MOC = 4e4;
29
+ uint16 internal constant MIN_MOC = 5e3; // 50%
30
+ uint16 internal constant MAX_MOC = 4e4; // 400%
31
31
 
32
32
  // For parameters that can be changed by the risk module provider
33
33
  bytes32 public constant RM_PROVIDER_ROLE = keccak256("RM_PROVIDER_ROLE");
@@ -339,7 +339,8 @@ abstract contract RiskModule is IRiskModule, PolicyPoolComponent {
339
339
  }
340
340
 
341
341
  /**
342
- * @dev Called from child contracts to create policies (after they validated the pricing)
342
+ * @dev Called from child contracts to create policies (after they validated the pricing).
343
+ * whenNotPaused validation must be done in the external method.
343
344
  *
344
345
  * @param payout The exposure (maximum payout) of the policy
345
346
  * @param premium The premium that will be paid by the policyHolder
@@ -357,7 +358,7 @@ abstract contract RiskModule is IRiskModule, PolicyPoolComponent {
357
358
  address payer,
358
359
  address onBehalfOf,
359
360
  uint96 internalId
360
- ) internal whenNotPaused returns (Policy.PolicyData memory) {
361
+ ) internal virtual returns (Policy.PolicyData memory) {
361
362
  return
362
363
  _newPolicyWithParams(
363
364
  payout,
@@ -371,40 +372,6 @@ abstract contract RiskModule is IRiskModule, PolicyPoolComponent {
371
372
  );
372
373
  }
373
374
 
374
- /**
375
- * @dev Called from child contracts to create policies (after they validated the pricing), receives custom params
376
- *
377
- * @param payout The exposure (maximum payout) of the policy
378
- * @param premium The premium that will be paid by the policyHolder
379
- * @param lossProb The probability of having to pay the maximum payout (wad)
380
- * @param payer The account that pays for the premium
381
- * @param expiration The expiration of the policy (timestamp)
382
- * @param onBehalfOf The policy holder
383
- * @param internalId An id that's unique within this module and it will be used to identify the policy
384
- */
385
- function _newPolicyCustomParams(
386
- uint256 payout,
387
- uint256 premium,
388
- uint256 lossProb,
389
- uint40 expiration,
390
- address payer,
391
- address onBehalfOf,
392
- uint96 internalId,
393
- Params memory params_
394
- ) internal whenNotPaused returns (Policy.PolicyData memory) {
395
- return
396
- _newPolicyWithParams(
397
- payout,
398
- premium,
399
- lossProb,
400
- expiration,
401
- payer,
402
- onBehalfOf,
403
- internalId,
404
- params_
405
- );
406
- }
407
-
408
375
  /**
409
376
  * @dev Internal method without whenNotPaused, MUST be called from other function that has this modifier
410
377
  */
@@ -159,7 +159,7 @@ contract SignedQuoteRiskModule is RiskModule {
159
159
  bytes32 quoteSignatureR,
160
160
  bytes32 quoteSignatureVS,
161
161
  uint40 quoteValidUntil
162
- ) external returns (Policy.PolicyData memory createdPolicy) {
162
+ ) external whenNotPaused returns (Policy.PolicyData memory createdPolicy) {
163
163
  return
164
164
  _newPolicySigned(
165
165
  payout,
@@ -207,7 +207,7 @@ contract SignedQuoteRiskModule is RiskModule {
207
207
  bytes32 quoteSignatureR,
208
208
  bytes32 quoteSignatureVS,
209
209
  uint40 quoteValidUntil
210
- ) external returns (uint256) {
210
+ ) external whenNotPaused returns (uint256) {
211
211
  return
212
212
  _newPolicySigned(
213
213
  payout,
@@ -255,7 +255,7 @@ contract SignedQuoteRiskModule is RiskModule {
255
255
  bytes32 quoteSignatureR,
256
256
  bytes32 quoteSignatureVS,
257
257
  uint40 quoteValidUntil
258
- ) external returns (uint256) {
258
+ ) external whenNotPaused returns (uint256) {
259
259
  require(
260
260
  onBehalfOf == _msgSender() || currency().allowance(onBehalfOf, _msgSender()) > 0,
261
261
  "Sender is not authorized to create policies onBehalfOf"
@@ -0,0 +1,165 @@
1
+ // SPDX-License-Identifier: Apache-2.0
2
+ pragma solidity ^0.8.0;
3
+
4
+ import {SafeCast} from "@openzeppelin/contracts/utils/math/SafeCast.sol";
5
+ import {IPolicyPool} from "./interfaces/IPolicyPool.sol";
6
+ import {IPremiumsAccount} from "./interfaces/IPremiumsAccount.sol";
7
+ import {SignedQuoteRiskModule} from "./SignedQuoteRiskModule.sol";
8
+ import {Policy} from "./Policy.sol";
9
+
10
+ /**
11
+ * @title Tiered SignedQuote Risk Module
12
+ * @dev Risk Module that for policy creation verifies the different components of the price have been signed by a
13
+ * trusted account (PRICER_ROLE). For the resolution (resolvePolicy), it has to be called by an authorized user.
14
+ *
15
+ * It allows different collaterallization levels for different policy types, by defining tiers or buckets of loss
16
+ * probability.
17
+ *
18
+ * Each bucket's loss probability represents the upper bound of the bucket (inclusive). The global parameters of
19
+ * the contract represent the 100% bucket.
20
+ *
21
+ * @custom:security-contact security@ensuro.co
22
+ * @author Ensuro
23
+ */
24
+ contract TieredSignedQuoteRiskModule is SignedQuoteRiskModule {
25
+ using SafeCast for uint256;
26
+
27
+ uint8 public constant MAX_BUCKETS = 4;
28
+
29
+ struct PackedBuckets {
30
+ uint64[MAX_BUCKETS] lossProbs;
31
+ }
32
+
33
+ PackedBuckets internal _buckets;
34
+ PackedParams[MAX_BUCKETS] internal _bucketParams;
35
+
36
+ /**
37
+ * @dev Emitted when a new risk bucket is created.
38
+ * @param lossProb The loss probability of the new bucket.
39
+ * @param params The packed parameters of the new bucket.
40
+ */
41
+ event NewBucket(uint256 lossProb, Params params);
42
+
43
+ /**
44
+ * @dev Emitted when the risks buckets are reset and only the default one remains
45
+ */
46
+ event BucketsReset();
47
+
48
+ /// @custom:oz-upgrades-unsafe-allow constructor
49
+ constructor(
50
+ IPolicyPool policyPool_,
51
+ IPremiumsAccount premiumsAccount_,
52
+ bool creationIsOpen_
53
+ ) SignedQuoteRiskModule(policyPool_, premiumsAccount_, creationIsOpen_) {} // solhint-disable-line no-empty-blocks
54
+
55
+ /**
56
+ * @dev Adds a new risk bucket with the given loss probability and parameters after the last one.
57
+ *
58
+ * Requirements:
59
+ *
60
+ * - The caller must have the LEVEL1_ROLE or LEVEL2_ROLE
61
+ *
62
+ * @param lossProb The loss probability of the new bucket.
63
+ * @param params_ The parameters of the new bucket.
64
+ */
65
+ function pushBucket(uint256 lossProb, Params calldata params_)
66
+ external
67
+ onlyGlobalOrComponentRole2(LEVEL1_ROLE, LEVEL2_ROLE)
68
+ {
69
+ uint256 newBucket = 0;
70
+ if (_buckets.lossProbs[0] != 0) {
71
+ for (
72
+ newBucket = 1;
73
+ newBucket < MAX_BUCKETS && _buckets.lossProbs[newBucket] != 0;
74
+ newBucket++
75
+ ) {} // solhint-disable-line no-empty-blocks
76
+ require(newBucket < MAX_BUCKETS, "No more than 4 buckets accepted");
77
+ require(
78
+ lossProb > uint256(_buckets.lossProbs[newBucket - 1]),
79
+ "lossProb <= last lossProb - reset instead"
80
+ );
81
+ }
82
+ _buckets.lossProbs[newBucket] = lossProb.toUint64();
83
+ _bucketParams[newBucket] = PackedParams({
84
+ moc: _wadTo4(params_.moc),
85
+ jrCollRatio: _wadTo4(params_.jrCollRatio),
86
+ collRatio: _wadTo4(params_.collRatio),
87
+ ensuroPpFee: _wadTo4(params_.ensuroPpFee),
88
+ ensuroCocFee: _wadTo4(params_.ensuroCocFee),
89
+ jrRoc: _wadTo4(params_.jrRoc),
90
+ srRoc: _wadTo4(params_.srRoc),
91
+ maxPayoutPerPolicy: type(uint32).max, // unused, but needs to be > 0
92
+ exposureLimit: type(uint32).max, //unused, but needs to be > 0
93
+ maxDuration: type(uint16).max //unused
94
+ });
95
+ if (newBucket < MAX_BUCKETS - 1) {
96
+ _buckets.lossProbs[newBucket + 1] = 0;
97
+ }
98
+ _validatePackedParams(_bucketParams[newBucket]);
99
+ emit NewBucket(lossProb, params_);
100
+ }
101
+
102
+ function resetBuckets() external onlyGlobalOrComponentRole2(LEVEL1_ROLE, LEVEL2_ROLE) {
103
+ _buckets.lossProbs[0] = 0;
104
+ emit BucketsReset();
105
+ }
106
+
107
+ /**
108
+ * @dev returns the risk bucket parameters for the given loss probability
109
+ */
110
+ function bucketParams(uint256 lossProb) public view returns (Params memory) {
111
+ for (uint256 i = 0; i < MAX_BUCKETS && _buckets.lossProbs[i] != 0; i++) {
112
+ if (lossProb <= _buckets.lossProbs[i]) {
113
+ return _unpackParams(_bucketParams[i]);
114
+ }
115
+ }
116
+ return this.params();
117
+ }
118
+
119
+ function _newPolicy(
120
+ uint256 payout,
121
+ uint256 premium,
122
+ uint256 lossProb,
123
+ uint40 expiration,
124
+ address payer,
125
+ address onBehalfOf,
126
+ uint96 internalId
127
+ ) internal override whenNotPaused returns (Policy.PolicyData memory) {
128
+ return
129
+ _newPolicyWithParams(
130
+ payout,
131
+ premium,
132
+ lossProb,
133
+ expiration,
134
+ payer,
135
+ onBehalfOf,
136
+ internalId,
137
+ bucketParams(lossProb)
138
+ );
139
+ }
140
+
141
+ function getMinimumPremium(
142
+ uint256 payout,
143
+ uint256 lossProb,
144
+ uint40 expiration
145
+ ) public view virtual override returns (uint256) {
146
+ return _getMinimumPremium(payout, lossProb, expiration, bucketParams(lossProb));
147
+ }
148
+
149
+ /**
150
+ * @dev returns the current risk bucket limits
151
+ */
152
+ function buckets() external view returns (uint256[MAX_BUCKETS] memory result) {
153
+ for (uint256 i = 0; i < MAX_BUCKETS && _buckets.lossProbs[i] > 0; i++) {
154
+ result[i] = _buckets.lossProbs[i];
155
+ }
156
+ return result;
157
+ }
158
+
159
+ /**
160
+ * @dev This empty reserved space is put in place to allow future versions to add new
161
+ * variables without shifting down storage in the inheritance chain.
162
+ * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
163
+ */
164
+ uint256[45] private __gap;
165
+ }
@@ -78,7 +78,7 @@ contract TrustfulRiskModule is RiskModule {
78
78
  uint40 expiration,
79
79
  address onBehalfOf,
80
80
  uint96 internalId
81
- ) external onlyComponentRole(PRICER_ROLE) returns (uint256) {
81
+ ) external whenNotPaused onlyComponentRole(PRICER_ROLE) returns (uint256) {
82
82
  return
83
83
  _newPolicy(
84
84
  payout,
@@ -115,7 +115,12 @@ contract TrustfulRiskModule is RiskModule {
115
115
  uint40 expiration,
116
116
  address onBehalfOf,
117
117
  uint96 internalId
118
- ) external onlyComponentRole(PRICER_ROLE) returns (Policy.PolicyData memory createdPolicy) {
118
+ )
119
+ external
120
+ whenNotPaused
121
+ onlyComponentRole(PRICER_ROLE)
122
+ returns (Policy.PolicyData memory createdPolicy)
123
+ {
119
124
  return
120
125
  _newPolicy(
121
126
  payout,
package/js/deploy.js CHANGED
@@ -1,7 +1,7 @@
1
1
  const upgrades_core = require("@openzeppelin/upgrades-core");
2
2
  const helpers = require("@nomicfoundation/hardhat-network-helpers");
3
3
  const fs = require("fs");
4
-
4
+ const { request } = require("undici");
5
5
  const ethers = require("ethers");
6
6
 
7
7
  const _BN = ethers.BigNumber.from;
@@ -14,6 +14,10 @@ const WhitelistStatus = {
14
14
  blacklisted: 2,
15
15
  };
16
16
 
17
+ const reservesOpts = {
18
+ unsafeAllow: ["delegatecall"],
19
+ };
20
+
17
21
  /**
18
22
  * Creates a fixed-point conversion function for the desired number of decimals
19
23
  * @param decimals The number of decimals. Must be >= 6.
@@ -115,10 +119,28 @@ async function verifyContract(hre, contract, isProxy, constructorArguments) {
115
119
  constructorArguments: constructorArguments,
116
120
  });
117
121
  if (isProxy) {
118
- console.log(
119
- "Contract successfully verified, you should verify the proxy at " +
120
- `${etherscanUrl()}/proxyContractChecker?a=${contract.address}`
121
- );
122
+ // the following should work but it fails with the current @openzeppelin/hardhat-upgrades version (1.20.0)
123
+ // await hre.run("verify:verify", {
124
+ // address: contract.address,
125
+ // });
126
+
127
+ // so we use the following workaround
128
+ const endpoints = await hre.run("verify:get-etherscan-endpoint");
129
+ const params = new URLSearchParams({
130
+ module: "contract",
131
+ action: "verifyproxycontract",
132
+ apiKey: hre.config.etherscan.apiKey,
133
+ address: contract.address,
134
+ });
135
+ const response = await request(endpoints.urls.apiURL, {
136
+ method: "POST",
137
+ headers: { "Content-Type": "application/x-www-form-urlencoded" },
138
+ body: params.toString(),
139
+ });
140
+ if (response.statusCode != 200)
141
+ throw new Error(`Etherscan replied with ${response.statusCode}: ${await response.body.text()}`);
142
+ const body = await response.body.json();
143
+ if (body.status != 1) throw new Error(`Etherscan replied with ${body}`);
122
144
  }
123
145
  } catch (error) {
124
146
  console.log("Error verifying contract", error);
@@ -141,7 +163,7 @@ async function deployContract({ saveAddr, verify, contractClass, constructorArgs
141
163
  }
142
164
 
143
165
  async function deployProxyContract(
144
- { saveAddr, verify, contractClass, constructorArgs, initializeArgs, initializer },
166
+ { saveAddr, verify, contractClass, constructorArgs, initializeArgs, initializer, deployProxyArgs },
145
167
  hre
146
168
  ) {
147
169
  const ContractFactory = await hre.ethers.getContractFactory(contractClass);
@@ -149,7 +171,7 @@ async function deployProxyContract(
149
171
  constructorArgs: constructorArgs,
150
172
  kind: "uups",
151
173
  initializer: initializer,
152
- unsafeAllow: ["delegatecall"],
174
+ ...deployProxyArgs,
153
175
  });
154
176
  if (verify) {
155
177
  // From https://ethereum.stackexchange.com/a/119622/79726
@@ -266,6 +288,7 @@ async function deployEToken(
266
288
  contractClass: "EToken",
267
289
  constructorArgs: [poolAddress],
268
290
  initializeArgs: [etkName, etkSymbol, _W(maxUtilizationRate), _W(poolLoanInterestRate)],
291
+ deployProxyArgs: reservesOpts,
269
292
  ...opts,
270
293
  },
271
294
  hre
@@ -284,6 +307,7 @@ async function deployPremiumsAccount({ poolAddress, juniorEtk, seniorEtk, runAs,
284
307
  contractClass: "PremiumsAccount",
285
308
  constructorArgs: [poolAddress, juniorEtk, seniorEtk],
286
309
  initializeArgs: [],
310
+ deployProxyArgs: reservesOpts,
287
311
  ...opts,
288
312
  },
289
313
  hre