@ensuro/core 2.0.0-beta9 → 2.0.1

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 (56) hide show
  1. package/README.md +14 -0
  2. package/build/contracts/AccessManager.sol/AccessManager.json +7 -2
  3. package/build/contracts/ERC4626AssetManager.sol/ERC4626AssetManager.json +21 -2
  4. package/build/contracts/EToken.sol/EToken.json +21 -2
  5. package/build/contracts/LPManualWhitelist.sol/LPManualWhitelist.json +21 -2
  6. package/build/contracts/LiquidityThresholdAssetManager.sol/LiquidityThresholdAssetManager.json +19 -0
  7. package/build/contracts/Policy.sol/Policy.json +2 -2
  8. package/build/contracts/PolicyPool.sol/PolicyPool.json +21 -2
  9. package/build/contracts/PolicyPoolComponent.sol/PolicyPoolComponent.json +19 -0
  10. package/build/contracts/PremiumsAccount.sol/PremiumsAccount.json +21 -2
  11. package/build/contracts/Reserve.sol/Reserve.json +19 -0
  12. package/build/contracts/RiskModule.sol/RiskModule.json +19 -0
  13. package/build/contracts/SignedQuoteRiskModule.sol/SignedQuoteRiskModule.json +1110 -0
  14. package/build/contracts/TimeScaled.sol/TimeScaled.json +2 -2
  15. package/build/contracts/TrustfulRiskModule.sol/TrustfulRiskModule.json +137 -2
  16. package/build/contracts/dependencies/WadRayMath.sol/WadRayMath.json +2 -2
  17. package/build/contracts/interfaces/IAssetManager.sol/IAssetManager.json +19 -0
  18. package/build/contracts/interfaces/IPolicyPool.sol/IPolicyPool.json +19 -0
  19. package/build/contracts/interfaces/IPolicyPoolComponent.sol/IPolicyPoolComponent.json +19 -0
  20. package/build/contracts/mocks/FixedRateVault.sol/FixedRateVault.json +2 -2
  21. package/build/contracts/mocks/ForwardProxy.sol/ForwardProxy.json +2 -2
  22. package/build/contracts/mocks/InterfaceIdCalculator.sol/InterfaceIdCalculator.json +180 -0
  23. package/build/contracts/mocks/PolicyHolderMock.sol/PolicyHolderMock.json +2 -2
  24. package/build/contracts/mocks/PolicyPoolComponentMock.sol/PolicyPoolComponentMock.json +21 -2
  25. package/build/contracts/mocks/PolicyPoolMock.sol/PolicyPoolMock.json +21 -2
  26. package/build/contracts/mocks/PolicyPoolMock.sol/PolicyPoolMockForward.json +2 -2
  27. package/build/contracts/mocks/RiskModuleMock.sol/RiskModuleMock.json +21 -2
  28. package/build/contracts/mocks/TestCurrency.sol/TestCurrency.json +2 -2
  29. package/build/contracts/mocks/TestNFT.sol/TestNFT.json +2 -2
  30. package/contracts/AccessManager.sol +30 -1
  31. package/contracts/ERC4626AssetManager.sol +3 -0
  32. package/contracts/EToken.sol +89 -19
  33. package/contracts/LPManualWhitelist.sol +18 -2
  34. package/contracts/LiquidityThresholdAssetManager.sol +17 -2
  35. package/contracts/Policy.sol +4 -2
  36. package/contracts/PolicyPool.sol +72 -13
  37. package/contracts/PolicyPoolComponent.sol +29 -3
  38. package/contracts/PremiumsAccount.sol +72 -24
  39. package/contracts/Reserve.sol +19 -3
  40. package/contracts/RiskModule.sol +46 -13
  41. package/contracts/SignedQuoteRiskModule.sol +310 -0
  42. package/contracts/TrustfulRiskModule.sol +104 -3
  43. package/contracts/interfaces/IAssetManager.sol +8 -3
  44. package/contracts/interfaces/IPolicyPool.sol +15 -4
  45. package/contracts/interfaces/IPolicyPoolComponent.sol +2 -1
  46. package/contracts/mocks/InterfaceIdCalculator.sol +32 -0
  47. package/contracts/mocks/PolicyPoolComponentMock.sol +10 -0
  48. package/contracts/mocks/PolicyPoolMock.sol +4 -0
  49. package/js/deploy.js +779 -0
  50. package/js/test-utils.js +139 -37
  51. package/package.json +4 -2
  52. package/scripts/change-pragma.sh +19 -0
  53. package/scripts/deploySmokeTest-fork.sh +53 -0
  54. package/scripts/deploySmokeTest.sh +51 -0
  55. package/scripts/storageLayout.js +33 -0
  56. package/scripts/utils.sh +65 -0
@@ -3,6 +3,7 @@ pragma solidity ^0.8.0;
3
3
 
4
4
  import {UUPSUpgradeable} from "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol";
5
5
  import {IERC20Metadata} from "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol";
6
+ import {IERC165} from "@openzeppelin/contracts/utils/introspection/IERC165.sol";
6
7
  import {IPolicyPool} from "./interfaces/IPolicyPool.sol";
7
8
  import {IPolicyPoolComponent} from "./interfaces/IPolicyPoolComponent.sol";
8
9
  import {IAccessManager} from "./interfaces/IAccessManager.sol";
@@ -14,8 +15,8 @@ import {WadRayMath} from "./dependencies/WadRayMath.sol";
14
15
  * @dev This is the base class of all the components of the protocol that are linked to the PolicyPool and created
15
16
  * after it.
16
17
  * Holds the reference to _policyPool as immutable, also provides access to common admin roles:
17
- * - LEVEL1_ROLE: High impact changes like upgrades or other critical operations
18
- * - LEVEL2_ROLE: Mid-impact changes like adding new risk modules or changing some parameters
18
+ * - LEVEL1_ROLE: High impact changes like upgrades, adding or removing components or other critical operations
19
+ * - LEVEL2_ROLE: Mid-impact changes like changing some parameters
19
20
  * - LEVEL3_ROLE: Low-impact changes like changing some parameters up to given percentage (tweaks)
20
21
  * - GUARDIAN_ROLE: For emergency operations oriented to protect the protocol in case of attacks or hacking.
21
22
  *
@@ -79,11 +80,16 @@ abstract contract PolicyPoolComponent is
79
80
 
80
81
  /// @custom:oz-upgrades-unsafe-allow constructor
81
82
  constructor(IPolicyPool policyPool_) {
83
+ require(
84
+ address(policyPool_) != address(0),
85
+ "PolicyPoolComponent: policyPool cannot be zero address"
86
+ );
87
+ _disableInitializers();
82
88
  _policyPool = policyPool_;
83
89
  }
84
90
 
85
91
  // solhint-disable-next-line func-name-mixedcase
86
- function __PolicyPoolComponent_init() internal initializer {
92
+ function __PolicyPoolComponent_init() internal onlyInitializing {
87
93
  __UUPSUpgradeable_init();
88
94
  __Pausable_init();
89
95
  }
@@ -94,12 +100,25 @@ abstract contract PolicyPoolComponent is
94
100
  override
95
101
  onlyGlobalOrComponentRole2(GUARDIAN_ROLE, LEVEL1_ROLE)
96
102
  {
103
+ _upgradeValidations(newImpl);
104
+ }
105
+
106
+ function _upgradeValidations(address newImpl) internal view virtual {
97
107
  require(
98
108
  IPolicyPoolComponent(newImpl).policyPool() == _policyPool,
99
109
  "Can't upgrade changing the PolicyPool!"
100
110
  );
101
111
  }
102
112
 
113
+ /**
114
+ * @dev See {IERC165-supportsInterface}.
115
+ */
116
+ function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
117
+ return
118
+ interfaceId == type(IERC165).interfaceId ||
119
+ interfaceId == type(IPolicyPoolComponent).interfaceId;
120
+ }
121
+
103
122
  function pause() public onlyGlobalOrComponentRole(GUARDIAN_ROLE) {
104
123
  _pause();
105
124
  }
@@ -171,4 +190,11 @@ abstract contract PolicyPoolComponent is
171
190
  }
172
191
  }
173
192
  }
193
+
194
+ /**
195
+ * @dev This empty reserved space is put in place to allow future versions to add new
196
+ * variables without shifting down storage in the inheritance chain.
197
+ * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
198
+ */
199
+ uint256[49] private __gap;
174
200
  }
@@ -22,7 +22,7 @@ import {IAssetManager} from "./interfaces/IAssetManager.sol";
22
22
  * (_activePurePremiums) and the surplus or deficit generated by the finalized policies (pure premiums collected -
23
23
  * losses).
24
24
  *
25
- * Collaborates with a junior {EToken} and a senior {EToken} that act as lenders when the premiums aren't enought to
25
+ * Collaborates with a junior {EToken} and a senior {EToken} that act as lenders when the premiums aren't enough to
26
26
  * cover the losses.
27
27
  *
28
28
  * @custom:security-contact security@ensuro.co
@@ -35,6 +35,8 @@ 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
+ uint256 internal constant FOUR_DECIMAL_TO_WAD = 1e14;
39
+ uint16 internal constant HUNDRED_PERCENT = 1e4;
38
40
 
39
41
  /**
40
42
  * @dev The Junior eToken is the first {EToken} to which the PremiumsAccount will go for credit when it runs out of
@@ -106,29 +108,44 @@ contract PremiumsAccount is IPremiumsAccount, Reserve {
106
108
  * @dev Initializes the PremiumsAccount (to be called by subclasses)
107
109
  */
108
110
  // solhint-disable-next-line func-name-mixedcase
109
- function __PremiumsAccount_init() internal initializer {
110
- __PolicyPoolComponent_init();
111
+ function __PremiumsAccount_init() internal onlyInitializing {
112
+ __Reserve_init();
111
113
  __PremiumsAccount_init_unchained();
112
114
  }
113
115
 
114
- /**
115
- * @dev In the initialization, besides settings the parameters, we approve the spending of funds by the eTokens
116
- * so we don't need to do it on every repayment operation
117
- */
118
116
  // solhint-disable-next-line func-name-mixedcase
119
- function __PremiumsAccount_init_unchained() internal initializer {
117
+ function __PremiumsAccount_init_unchained() internal onlyInitializing {
120
118
  /*
121
119
  _activePurePremiums = 0;
122
120
  */
123
- if (address(_juniorEtk) != address(0))
124
- currency().approve(address(_juniorEtk), type(uint256).max);
125
- if (address(_seniorEtk) != address(0))
126
- currency().approve(address(_seniorEtk), type(uint256).max);
127
-
128
- _params = PackedParams({deficitRatio: 1e4, assetManager: IAssetManager(address(0))});
121
+ _params = PackedParams({
122
+ deficitRatio: HUNDRED_PERCENT,
123
+ assetManager: IAssetManager(address(0))
124
+ });
129
125
  _validateParameters();
130
126
  }
131
127
 
128
+ function _upgradeValidations(address newImpl) internal view virtual override {
129
+ super._upgradeValidations(newImpl);
130
+ IPremiumsAccount newPA = IPremiumsAccount(newImpl);
131
+ require(
132
+ newPA.juniorEtk() == _juniorEtk || address(_juniorEtk) == address(0),
133
+ "Can't upgrade changing the Junior ETK unless to non-zero"
134
+ );
135
+ require(
136
+ newPA.seniorEtk() == _seniorEtk || address(_seniorEtk) == address(0),
137
+ "Can't upgrade changing the Senior ETK unless to non-zero"
138
+ );
139
+ }
140
+
141
+ /**
142
+ * @dev See {IERC165-supportsInterface}.
143
+ */
144
+ function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
145
+ return
146
+ super.supportsInterface(interfaceId) || interfaceId == type(IPremiumsAccount).interfaceId;
147
+ }
148
+
132
149
  function assetManager() public view override returns (IAssetManager) {
133
150
  return _params.assetManager;
134
151
  }
@@ -141,7 +158,7 @@ contract PremiumsAccount is IPremiumsAccount, Reserve {
141
158
  * @dev This is called by the {Reserve} base class to record the earnings generated by the asset management.
142
159
  *
143
160
  * @param earningsOrLosses Indicates the amount earned since last time earnings where recorded.
144
- * - If positive, repays the lons and accumulates the rest in the surplus.
161
+ * - If positive, repays the loans and accumulates the rest in the surplus.
145
162
  * - If negative (losses) substracts it from surplus. It never can exceed _maxDeficit and doesn't takes
146
163
  * loans to cover asset losses.
147
164
  */
@@ -158,7 +175,7 @@ contract PremiumsAccount is IPremiumsAccount, Reserve {
158
175
 
159
176
  function _validateParameters() internal view override {
160
177
  require(
161
- _params.deficitRatio <= 1e4 && _params.deficitRatio >= 0,
178
+ _params.deficitRatio <= HUNDRED_PERCENT && _params.deficitRatio >= 0,
162
179
  "Validation: deficitRatio must be <= 1"
163
180
  );
164
181
  }
@@ -227,16 +244,19 @@ contract PremiumsAccount is IPremiumsAccount, Reserve {
227
244
  * @dev Returns the percentage of the active pure premiums that can be used to cover losses of finalized policies.
228
245
  */
229
246
  function deficitRatio() public view returns (uint256) {
230
- return uint256(_params.deficitRatio) * 1e14; // 4 -> 18 decimals
247
+ return uint256(_params.deficitRatio) * FOUR_DECIMAL_TO_WAD; // 4 -> 18 decimals
231
248
  }
232
249
 
233
250
  /**
234
251
  * @dev Changes the `deficitRatio` parameter.
235
252
  *
253
+ * Requirements:
254
+ * - onlyGlobalOrComponentRole(LEVEL2_ROLE)
255
+ *
236
256
  * Events:
237
257
  * - Emits GovernanceAction with action = setDeficitRatio or setDeficitRatioWithAdjustment if an adjustment was made.
238
258
  *
239
- * @param adjustment If true and the new ratio leaves `_surplus < -_maxDeficit()`, if adjusts the _surplus to the new
259
+ * @param adjustment If true and the new ratio leaves `_surplus < -_maxDeficit()`, it adjusts the _surplus to the new
240
260
  * `_maxDeficit()` and borrows the difference from the eTokens.
241
261
  * If false and the new ratio leaves `_surplus < -_maxDeficit()`, the operation is reverted.
242
262
  */
@@ -244,9 +264,17 @@ contract PremiumsAccount is IPremiumsAccount, Reserve {
244
264
  external
245
265
  onlyComponentRole(LEVEL2_ROLE)
246
266
  {
247
- require(newRatio <= 1e18 && newRatio >= 0, "Validation: deficitRatio must be <= 1");
267
+ require(newRatio <= 1e18, "Validation: deficitRatio must be <= 1");
268
+
269
+ uint16 truncatedRatio = (newRatio / FOUR_DECIMAL_TO_WAD).toUint16();
270
+ require(
271
+ uint256(truncatedRatio) * FOUR_DECIMAL_TO_WAD == newRatio,
272
+ "Validation: only up to 4 decimals allowed"
273
+ );
274
+
248
275
  int256 maxDeficit = _maxDeficit(newRatio);
249
276
  require(adjustment || _surplus >= maxDeficit, "Validation: surplus must be >= maxDeficit");
277
+
250
278
  IAccessManager.GovernanceActions action = IAccessManager.GovernanceActions.setDeficitRatio;
251
279
  if (_surplus < maxDeficit) {
252
280
  // Do the adjustment
@@ -255,12 +283,12 @@ contract PremiumsAccount is IPremiumsAccount, Reserve {
255
283
  _borrowFromEtk(borrow, address(this), address(_juniorEtk) != address(0));
256
284
  action = IAccessManager.GovernanceActions.setDeficitRatioWithAdjustment;
257
285
  }
258
- _params.deficitRatio = (newRatio / 1e14).toUint16();
286
+ _params.deficitRatio = truncatedRatio;
259
287
  _parameterChanged(action, newRatio, false);
260
288
  }
261
289
 
262
290
  /**
263
- * @dev Internal function called when money in the PremiumsAccount is not enought and we need to borrow from the
291
+ * @dev Internal function called when money in the PremiumsAccount is not enough and we need to borrow from the
264
292
  * eTokens.
265
293
  *
266
294
  * @param borrow The amount to borrow.
@@ -273,6 +301,7 @@ contract PremiumsAccount is IPremiumsAccount, Reserve {
273
301
  address receiver,
274
302
  bool jrEtk
275
303
  ) internal {
304
+ require(receiver != address(0), "PremiumsAccount: receiver cannot be the zero address");
276
305
  uint256 left;
277
306
  if (jrEtk) {
278
307
  // Consume Junior Pool until exhausted
@@ -331,9 +360,9 @@ contract PremiumsAccount is IPremiumsAccount, Reserve {
331
360
  * @param amount The amount to be transferred.
332
361
  */
333
362
  function receiveGrant(uint256 amount) external {
334
- currency().safeTransferFrom(_msgSender(), address(this), amount);
335
363
  _storePurePremiumWon(amount);
336
364
  emit WonPremiumsInOut(true, amount);
365
+ currency().safeTransferFrom(_msgSender(), address(this), amount);
337
366
  }
338
367
 
339
368
  /**
@@ -345,7 +374,7 @@ contract PremiumsAccount is IPremiumsAccount, Reserve {
345
374
  *
346
375
  * Requirements:
347
376
  * - onlyGlobalOrComponentRole(WITHDRAW_WON_PREMIUMS_ROLE)
348
- * - _wonPurePremiums > 0
377
+ * - _surplus > 0
349
378
  *
350
379
  * Events:
351
380
  * - Emits {WonPremiumsInOut} with moneyIn = false
@@ -359,6 +388,7 @@ contract PremiumsAccount is IPremiumsAccount, Reserve {
359
388
  onlyGlobalOrComponentRole(WITHDRAW_WON_PREMIUMS_ROLE)
360
389
  returns (uint256)
361
390
  {
391
+ require(destination != address(0), "PremiumsAccount: destination cannot be the zero address");
362
392
  if (_surplus <= 0) {
363
393
  amount = 0;
364
394
  } else {
@@ -442,10 +472,21 @@ contract PremiumsAccount is IPremiumsAccount, Reserve {
442
472
  if (borrowedFromEtk == 0) return purePremiumWon;
443
473
  uint256 repayAmount = Math.min(purePremiumWon, borrowedFromEtk);
444
474
 
445
- // If not enought liquidity, it deinvests from the asset manager
475
+ // If not enough liquidity, it deinvests from the asset manager
446
476
  if (currency().balanceOf(address(this)) < repayAmount) {
477
+ /**
478
+ * I send `repayAmount` because the IAssetManager expects the full amount that's needed, not the missing one.
479
+ * It uses the value of the full amount to optimize the deinvestment leaving more liquidity if possible to avoid
480
+ * future deinvestment. It will only fail if it can't refill `repayAmount - currency().balanceOf(address(this))`
481
+ */
447
482
  _refillWallet(repayAmount);
448
483
  }
484
+ // Checks the allowance before repayment
485
+ if (currency().allowance(address(this), address(etk)) < repayAmount) {
486
+ // If I have to approve, I approve for all the pending debt (not just repayAmount), this way I avoid some
487
+ // future approvals.
488
+ currency().approve(address(etk), borrowedFromEtk);
489
+ }
449
490
  etk.repayLoan(repayAmount, address(this));
450
491
  return purePremiumWon - repayAmount;
451
492
  }
@@ -474,4 +515,11 @@ contract PremiumsAccount is IPremiumsAccount, Reserve {
474
515
  _storePurePremiumWon(purePremiumWon);
475
516
  _unlockScr(policy);
476
517
  }
518
+
519
+ /**
520
+ * @dev This empty reserved space is put in place to allow future versions to add new
521
+ * variables without shifting down storage in the inheritance chain.
522
+ * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
523
+ */
524
+ uint256[47] private __gap;
477
525
  }
@@ -39,6 +39,14 @@ abstract contract Reserve is PolicyPoolComponent {
39
39
  NEGLIGIBLE_AMOUNT = 10**(policyPool_.currency().decimals() / 2);
40
40
  }
41
41
 
42
+ /**
43
+ * @dev Initializes the Reserve (to be called by subclasses)
44
+ */
45
+ // solhint-disable-next-line func-name-mixedcase
46
+ function __Reserve_init() internal onlyInitializing {
47
+ __PolicyPoolComponent_init();
48
+ }
49
+
42
50
  /**
43
51
  * @dev Refills the reserve's balance, deinvesting from the asset manager to be able to make a payment
44
52
  *
@@ -62,12 +70,13 @@ abstract contract Reserve is PolicyPoolComponent {
62
70
 
63
71
  /**
64
72
  * @dev Internal function that transfers money to a destination. It might need to call `_refillWallet` to deinvest
65
- * some money to have enought liquidity for the payment.
73
+ * some money to have enough liquidity for the payment.
66
74
  *
67
75
  * @param destination The destination of the transfer.
68
76
  * @param amount The amount to be transferred.
69
77
  */
70
78
  function _transferTo(address destination, uint256 amount) internal {
79
+ require(destination != address(0), "Reserve: transfer to the zero address");
71
80
  if (amount == 0) return;
72
81
  uint256 balance = currency().balanceOf(address(this));
73
82
  if (balance < amount) {
@@ -126,8 +135,8 @@ abstract contract Reserve is PolicyPoolComponent {
126
135
  onlyGlobalOrComponentRole2(GUARDIAN_ROLE, LEVEL1_ROLE)
127
136
  {
128
137
  require(
129
- address(newAM) == address(0) || address(newAM).isContract(),
130
- "The assetManager is not a contract!"
138
+ address(newAM) == address(0) || newAM.supportsInterface(type(IAssetManager).interfaceId),
139
+ "Reserve: asset manager doesn't implements the required interface"
131
140
  );
132
141
  address am = address(assetManager());
133
142
  IAccessManager.GovernanceActions action = IAccessManager.GovernanceActions.setAssetManager;
@@ -210,4 +219,11 @@ abstract contract Reserve is PolicyPoolComponent {
210
219
  {
211
220
  return address(assetManager()).functionDelegateCall(functionCall);
212
221
  }
222
+
223
+ /**
224
+ * @dev This empty reserved space is put in place to allow future versions to add new
225
+ * variables without shifting down storage in the inheritance chain.
226
+ * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
227
+ */
228
+ uint256[50] private __gap;
213
229
  }
@@ -22,6 +22,12 @@ abstract contract RiskModule is IRiskModule, PolicyPoolComponent {
22
22
  using SafeCast for uint256;
23
23
 
24
24
  uint256 internal constant SECONDS_IN_YEAR_WAD = 31536000e18; /* 365 * 24 * 3600 * 10e18 */
25
+ uint16 internal constant HOURS_PER_YEAR = 8760; /* 24 * 365 */
26
+
27
+ uint256 internal constant FOUR_DECIMAL_TO_WAD = 1e14;
28
+ uint16 internal constant HUNDRED_PERCENT = 1e4;
29
+ uint16 internal constant MIN_MOC = 5e3;
30
+ uint16 internal constant MAX_MOC = 4e4;
25
31
 
26
32
  // For parameters that can be changed by the risk module provider
27
33
  bytes32 public constant RM_PROVIDER_ROLE = keccak256("RM_PROVIDER_ROLE");
@@ -80,7 +86,7 @@ abstract contract RiskModule is IRiskModule, PolicyPoolComponent {
80
86
  uint256 maxPayoutPerPolicy_,
81
87
  uint256 exposureLimit_,
82
88
  address wallet_
83
- ) internal initializer {
89
+ ) internal onlyInitializing {
84
90
  __PolicyPoolComponent_init();
85
91
  __RiskModule_init_unchained(
86
92
  name_,
@@ -102,10 +108,10 @@ abstract contract RiskModule is IRiskModule, PolicyPoolComponent {
102
108
  uint256 maxPayoutPerPolicy_,
103
109
  uint256 exposureLimit_,
104
110
  address wallet_
105
- ) internal initializer {
111
+ ) internal onlyInitializing {
106
112
  _name = name_;
107
113
  _params = PackedParams({
108
- moc: 1e4,
114
+ moc: HUNDRED_PERCENT,
109
115
  jrCollRatio: 0,
110
116
  collRatio: _wadTo4(collRatio_),
111
117
  ensuroPpFee: _wadTo4(ensuroPpFee_),
@@ -114,23 +120,42 @@ abstract contract RiskModule is IRiskModule, PolicyPoolComponent {
114
120
  srRoc: _wadTo4(srRoc_),
115
121
  maxPayoutPerPolicy: _amountToX(2, maxPayoutPerPolicy_),
116
122
  exposureLimit: _amountToX(0, exposureLimit_),
117
- maxDuration: 24 * 365 // default = 1 year
123
+ maxDuration: HOURS_PER_YEAR
118
124
  });
119
125
  _activeExposure = 0;
120
126
  _wallet = wallet_;
121
127
  _validateParameters();
122
128
  }
123
129
 
130
+ function _upgradeValidations(address newImpl) internal view virtual override {
131
+ super._upgradeValidations(newImpl);
132
+ IRiskModule newRM = IRiskModule(newImpl);
133
+ require(
134
+ newRM.premiumsAccount() == _premiumsAccount,
135
+ "Can't upgrade changing the PremiumsAccount"
136
+ );
137
+ }
138
+
139
+ /**
140
+ * @dev See {IERC165-supportsInterface}.
141
+ */
142
+ function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
143
+ return super.supportsInterface(interfaceId) || interfaceId == type(IRiskModule).interfaceId;
144
+ }
145
+
124
146
  // runs validation on RiskModule parameters
125
147
  function _validateParameters() internal view override {
126
- require(_params.jrCollRatio <= 1e4, "Validation: jrCollRatio must be <=1");
127
- require(_params.collRatio <= 1e4 && _params.collRatio > 0, "Validation: collRatio must be <=1");
148
+ require(_params.jrCollRatio <= HUNDRED_PERCENT, "Validation: jrCollRatio must be <=1");
149
+ require(
150
+ _params.collRatio <= HUNDRED_PERCENT && _params.collRatio > 0,
151
+ "Validation: collRatio must be <=1"
152
+ );
128
153
  require(_params.collRatio >= _params.jrCollRatio, "Validation: collRatio >= jrCollRatio");
129
- require(_params.moc <= 4e4 && _params.moc >= 5e3, "Validation: moc must be [0.5, 4]");
130
- require(_params.ensuroPpFee <= 1e4, "Validation: ensuroPpFee must be <= 1");
131
- require(_params.ensuroCocFee <= 1e4, "Validation: ensuroCocFee must be <= 1");
132
- require(_params.srRoc <= 1e4, "Validation: srRoc must be <= 1 (100%)");
133
- require(_params.jrRoc <= 1e4, "Validation: jrRoc must be <= 1 (100%)");
154
+ require(_params.moc <= MAX_MOC && _params.moc >= MIN_MOC, "Validation: moc must be [0.5, 4]");
155
+ require(_params.ensuroPpFee <= HUNDRED_PERCENT, "Validation: ensuroPpFee must be <= 1");
156
+ require(_params.ensuroCocFee <= HUNDRED_PERCENT, "Validation: ensuroCocFee must be <= 1");
157
+ require(_params.srRoc <= HUNDRED_PERCENT, "Validation: srRoc must be <= 1 (100%)");
158
+ require(_params.jrRoc <= HUNDRED_PERCENT, "Validation: jrRoc must be <= 1 (100%)");
134
159
  // _maxPayoutPerPolicy no limits
135
160
  require(
136
161
  exposureLimit() >= _activeExposure,
@@ -150,12 +175,12 @@ abstract contract RiskModule is IRiskModule, PolicyPoolComponent {
150
175
  // solhint-disable-next-line func-name-mixedcase
151
176
  function _4toWad(uint16 value) internal pure returns (uint256) {
152
177
  // 4 decimals to Wad (18 decimals)
153
- return uint256(value) * 1e14;
178
+ return uint256(value) * FOUR_DECIMAL_TO_WAD;
154
179
  }
155
180
 
156
181
  function _wadTo4(uint256 value) internal pure returns (uint16) {
157
182
  // Wad to 4 decimals
158
- return (value / 1e14).toUint16();
183
+ return (value / FOUR_DECIMAL_TO_WAD).toUint16();
159
184
  }
160
185
 
161
186
  // solhint-disable-next-line func-name-mixedcase
@@ -262,6 +287,7 @@ abstract contract RiskModule is IRiskModule, PolicyPoolComponent {
262
287
  }
263
288
 
264
289
  function setWallet(address wallet_) external onlyComponentRole(RM_PROVIDER_ROLE) {
290
+ require(wallet_ != address(0), "RiskModule: wallet cannot be the zero address");
265
291
  _wallet = wallet_;
266
292
  _parameterChanged(IAccessManager.GovernanceActions.setWallet, uint256(uint160(wallet_)), false);
267
293
  }
@@ -358,4 +384,11 @@ abstract contract RiskModule is IRiskModule, PolicyPoolComponent {
358
384
  function premiumsAccount() external view override returns (IPremiumsAccount) {
359
385
  return _premiumsAccount;
360
386
  }
387
+
388
+ /**
389
+ * @dev This empty reserved space is put in place to allow future versions to add new
390
+ * variables without shifting down storage in the inheritance chain.
391
+ * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
392
+ */
393
+ uint256[46] private __gap;
361
394
  }