@ensuro/core 2.7.0 → 2.8.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.
Files changed (79) hide show
  1. package/README.md +13 -7
  2. package/contracts/AccessManager.sol +3 -13
  3. package/contracts/EToken.sol +29 -95
  4. package/contracts/LPManualWhitelist.sol +11 -26
  5. package/contracts/LiquidityThresholdAssetManager.sol +10 -21
  6. package/contracts/Policy.sol +10 -20
  7. package/contracts/PolicyPool.sol +110 -127
  8. package/contracts/PolicyPoolComponent.sol +9 -32
  9. package/contracts/PremiumsAccount.sol +41 -47
  10. package/contracts/Reserve.sol +10 -16
  11. package/contracts/RiskModule.sol +74 -83
  12. package/contracts/SignedBucketRiskModule.sol +18 -80
  13. package/contracts/SignedQuoteRiskModule.sol +13 -44
  14. package/contracts/TieredSignedQuoteRiskModule.sol +7 -13
  15. package/contracts/TimeScaled.sol +8 -39
  16. package/contracts/TrustfulRiskModule.sol +47 -42
  17. package/contracts/interfaces/IAccessManager.sol +2 -11
  18. package/contracts/interfaces/IEToken.sol +1 -5
  19. package/contracts/interfaces/ILPWhitelist.sol +2 -10
  20. package/contracts/interfaces/IPolicyHolder.sol +2 -11
  21. package/contracts/interfaces/IPolicyPool.sol +59 -3
  22. package/contracts/interfaces/IPremiumsAccount.sol +17 -5
  23. package/contracts/migration/LPManualWhitelistV20.sol +3 -15
  24. package/contracts/migration/LPManualWhitelistV20Upgraded.sol +1 -5
  25. package/contracts/mocks/FixedRateVault.sol +1 -6
  26. package/contracts/mocks/InterfaceIdCalculator.sol +2 -0
  27. package/contracts/mocks/PolicyHolderMock.sol +3 -13
  28. package/contracts/mocks/PolicyPoolComponentMock.sol +1 -3
  29. package/contracts/mocks/PolicyPoolMock.sol +25 -25
  30. package/contracts/mocks/RiskModuleMock.sol +39 -16
  31. package/contracts/mocks/TestNFT.sol +1 -1
  32. package/js/deploy.js +44 -39
  33. package/js/test-utils.js +30 -19
  34. package/js/utils.js +62 -29
  35. package/package.json +1 -1
  36. package/scripts/utils.sh +23 -12
  37. package/build/contracts/AccessManager.sol/AccessManager.json +0 -618
  38. package/build/contracts/ERC4626AssetManager.sol/ERC4626AssetManager.json +0 -238
  39. package/build/contracts/EToken.sol/EToken.json +0 -1277
  40. package/build/contracts/LPManualWhitelist.sol/LPManualWhitelist.json +0 -647
  41. package/build/contracts/LiquidityThresholdAssetManager.sol/LiquidityThresholdAssetManager.json +0 -222
  42. package/build/contracts/Policy.sol/Policy.json +0 -10
  43. package/build/contracts/PolicyPool.sol/PolicyPool.json +0 -1416
  44. package/build/contracts/PolicyPoolComponent.sol/PolicyPoolComponent.json +0 -332
  45. package/build/contracts/PremiumsAccount.sol/PremiumsAccount.json +0 -970
  46. package/build/contracts/Reserve.sol/Reserve.json +0 -403
  47. package/build/contracts/RiskModule.sol/RiskModule.json +0 -559
  48. package/build/contracts/SignedBucketRiskModule.sol/SignedBucketRiskModule.json +0 -1262
  49. package/build/contracts/SignedQuoteRiskModule.sol/SignedQuoteRiskModule.json +0 -1110
  50. package/build/contracts/TieredSignedQuoteRiskModule.sol/TieredSignedQuoteRiskModule.json +0 -1316
  51. package/build/contracts/TimeScaled.sol/TimeScaled.json +0 -10
  52. package/build/contracts/TrustfulRiskModule.sol/TrustfulRiskModule.json +0 -984
  53. package/build/contracts/dependencies/ERC1967Proxy.sol/ERC1967Proxy.json +0 -64
  54. package/build/contracts/dependencies/IERC20Metadata.sol/IERC20Metadata.json +0 -233
  55. package/build/contracts/dependencies/WadRayMath.sol/WadRayMath.json +0 -10
  56. package/build/contracts/interfaces/IAccessManager.sol/IAccessManager.json +0 -343
  57. package/build/contracts/interfaces/IAssetManager.sol/IAssetManager.json +0 -128
  58. package/build/contracts/interfaces/IEToken.sol/IEToken.json +0 -460
  59. package/build/contracts/interfaces/ILPWhitelist.sol/ILPWhitelist.json +0 -103
  60. package/build/contracts/interfaces/IPolicyHolder.sol/IPolicyHolder.json +0 -108
  61. package/build/contracts/interfaces/IPolicyPool.sol/IPolicyPool.json +0 -501
  62. package/build/contracts/interfaces/IPolicyPoolComponent.sol/IPolicyPoolComponent.json +0 -43
  63. package/build/contracts/interfaces/IPremiumsAccount.sol/IPremiumsAccount.json +0 -315
  64. package/build/contracts/interfaces/IRiskModule.sol/IRiskModule.json +0 -165
  65. package/build/contracts/migration/LPManualWhitelistV20.sol/LPManualWhitelistV20.json +0 -481
  66. package/build/contracts/migration/LPManualWhitelistV20Upgraded.sol/LPManualWhitelistV20Upgraded.json +0 -492
  67. package/build/contracts/mocks/FixedRateVault.sol/FixedRateVault.json +0 -736
  68. package/build/contracts/mocks/ForwardProxy.sol/ForwardProxy.json +0 -43
  69. package/build/contracts/mocks/IMintableERC20.sol/IMintableERC20.json +0 -47
  70. package/build/contracts/mocks/InterfaceIdCalculator.sol/InterfaceIdCalculator.json +0 -180
  71. package/build/contracts/mocks/PolicyHolderMock.sol/PolicyHolderMock.json +0 -319
  72. package/build/contracts/mocks/PolicyPoolComponentMock.sol/PolicyPoolComponentMock.json +0 -54
  73. package/build/contracts/mocks/PolicyPoolMock.sol/PolicyPoolMock.json +0 -721
  74. package/build/contracts/mocks/PolicyPoolMock.sol/PolicyPoolMockForward.json +0 -92
  75. package/build/contracts/mocks/RiskModuleMock.sol/RiskModuleMock.json +0 -783
  76. package/build/contracts/mocks/TestCurrency.sol/TestCurrency.json +0 -343
  77. package/build/contracts/mocks/TestNFT.sol/TestNFT.json +0 -388
  78. package/contracts/dependencies/ERC1967Proxy.sol +0 -19
  79. package/contracts/dependencies/IERC20Metadata.sol +0 -19
@@ -125,25 +125,6 @@ contract PolicyPool is IPolicyPool, PausableUpgradeable, UUPSUpgradeable, ERC721
125
125
  */
126
126
  string internal _nftBaseURI;
127
127
 
128
- /**
129
- * @dev Event emitted every time a new policy is added to the pool. Contains all the data about the policy that is
130
- * later required for doing operations with the policy like resolution or expiration.
131
- *
132
- * @param riskModule The risk module that created the policy
133
- * @param policy The {Policy-PolicyData} struct with all the immutable fields of the policy.
134
- */
135
- event NewPolicy(IRiskModule indexed riskModule, Policy.PolicyData policy);
136
-
137
- /**
138
- * @dev Event emitted every time a policy is removed from the pool. If the policy expired, the `payout` is 0,
139
- * otherwise is the amount transferred to the policyholder.
140
- *
141
- * @param riskModule The risk module where that created the policy initially.
142
- * @param policyId The unique id of the policy
143
- * @param payout The payout that has been paid to the policy holder. 0 when the policy expired.
144
- */
145
- event PolicyResolved(IRiskModule indexed riskModule, uint256 indexed policyId, uint256 payout);
146
-
147
128
  /**
148
129
  * @dev Event emitted when the treasury changes
149
130
  *
@@ -159,11 +140,7 @@ contract PolicyPool is IPolicyPool, PausableUpgradeable, UUPSUpgradeable, ERC721
159
140
  * @param kind Value indicating the kind of component. See {ComponentKind}
160
141
  * @param newStatus The status of the component after the operation. See {ComponentStatus}
161
142
  */
162
- event ComponentStatusChanged(
163
- IPolicyPoolComponent indexed component,
164
- ComponentKind kind,
165
- ComponentStatus newStatus
166
- );
143
+ event ComponentStatusChanged(IPolicyPoolComponent indexed component, ComponentKind kind, ComponentStatus newStatus);
167
144
 
168
145
  /**
169
146
  * @dev Modifier that checks the caller has a given role
@@ -204,11 +181,7 @@ contract PolicyPool is IPolicyPool, PausableUpgradeable, UUPSUpgradeable, ERC721
204
181
  * @param symbol_ The symbol of the ERC721 token.
205
182
  * @param treasury_ The address of the treasury that will receive the protocol fees.
206
183
  */
207
- function initialize(
208
- string memory name_,
209
- string memory symbol_,
210
- address treasury_
211
- ) public initializer {
184
+ function initialize(string memory name_, string memory symbol_, address treasury_) public initializer {
212
185
  require(bytes(name_).length > 0, "PolicyPool: name cannot be empty");
213
186
  require(bytes(symbol_).length > 0, "PolicyPool: symbol cannot be empty");
214
187
  __UUPSUpgradeable_init();
@@ -229,12 +202,7 @@ contract PolicyPool is IPolicyPool, PausableUpgradeable, UUPSUpgradeable, ERC721
229
202
  _setTreasury(treasury_);
230
203
  }
231
204
 
232
- function _authorizeUpgrade(address newImpl)
233
- internal
234
- view
235
- override
236
- onlyRole2(GUARDIAN_ROLE, LEVEL1_ROLE)
237
- {
205
+ function _authorizeUpgrade(address newImpl) internal view override onlyRole2(GUARDIAN_ROLE, LEVEL1_ROLE) {
238
206
  IPolicyPool newPool = IPolicyPool(newImpl);
239
207
  require(newPool.access() == _access, "Can't upgrade changing the access manager");
240
208
  require(newPool.currency() == _currency, "Can't upgrade changing the currency");
@@ -310,20 +278,15 @@ contract PolicyPool is IPolicyPool, PausableUpgradeable, UUPSUpgradeable, ERC721
310
278
  * to this specific {PolicyPool} and matching the `kind` specified in the next paramter.
311
279
  * @param kind The type of component to be added.
312
280
  */
313
- function addComponent(IPolicyPoolComponent component, ComponentKind kind)
314
- external
315
- onlyRole(LEVEL1_ROLE)
316
- {
281
+ function addComponent(IPolicyPoolComponent component, ComponentKind kind) external onlyRole(LEVEL1_ROLE) {
317
282
  Component storage comp = _components[component];
318
283
  require(comp.status == ComponentStatus.inactive, "Component already in the pool");
319
284
  require(component.policyPool() == this, "Component not linked to this pool");
320
285
 
321
286
  require(
322
287
  (kind == ComponentKind.eToken && component.supportsInterface(type(IEToken).interfaceId)) ||
323
- (kind == ComponentKind.premiumsAccount &&
324
- component.supportsInterface(type(IPremiumsAccount).interfaceId)) ||
325
- (kind == ComponentKind.riskModule &&
326
- component.supportsInterface(type(IRiskModule).interfaceId)),
288
+ (kind == ComponentKind.premiumsAccount && component.supportsInterface(type(IPremiumsAccount).interfaceId)) ||
289
+ (kind == ComponentKind.riskModule && component.supportsInterface(type(IRiskModule).interfaceId)),
327
290
  "PolicyPool: Not the right kind"
328
291
  );
329
292
 
@@ -360,15 +323,9 @@ contract PolicyPool is IPolicyPool, PausableUpgradeable, UUPSUpgradeable, ERC721
360
323
  Component storage comp = _components[component];
361
324
  require(comp.status == ComponentStatus.deprecated, "Component not deprecated");
362
325
  if (comp.kind == ComponentKind.eToken) {
363
- require(
364
- IEToken(address(component)).totalSupply() == 0,
365
- "EToken has liquidity, can't be removed"
366
- );
326
+ require(IEToken(address(component)).totalSupply() == 0, "EToken has liquidity, can't be removed");
367
327
  } else if (comp.kind == ComponentKind.riskModule) {
368
- require(
369
- IRiskModule(address(component)).activeExposure() == 0,
370
- "Can't remove a module with active policies"
371
- );
328
+ require(IRiskModule(address(component)).activeExposure() == 0, "Can't remove a module with active policies");
372
329
  } else if (comp.kind == ComponentKind.premiumsAccount) {
373
330
  IPremiumsAccount pa = IPremiumsAccount(address(component));
374
331
  require(pa.purePremiums() == 0, "Can't remove a PremiumsAccount with premiums");
@@ -398,10 +355,10 @@ contract PolicyPool is IPolicyPool, PausableUpgradeable, UUPSUpgradeable, ERC721
398
355
  * @param component The address of component contract. Must be a component added before.
399
356
  * @param newStatus The new status, must be either `active`, `deprecated` or `suspended`.
400
357
  */
401
- function changeComponentStatus(IPolicyPoolComponent component, ComponentStatus newStatus)
402
- external
403
- onlyRole2(GUARDIAN_ROLE, LEVEL1_ROLE)
404
- {
358
+ function changeComponentStatus(
359
+ IPolicyPoolComponent component,
360
+ ComponentStatus newStatus
361
+ ) external onlyRole2(GUARDIAN_ROLE, LEVEL1_ROLE) {
405
362
  Component storage comp = _components[component];
406
363
  require(comp.status != ComponentStatus.inactive, "Component not found");
407
364
  require(
@@ -420,52 +377,38 @@ contract PolicyPool is IPolicyPool, PausableUpgradeable, UUPSUpgradeable, ERC721
420
377
  * @param component The address of the component
421
378
  * @return The status of the component. See {ComponentStatus}
422
379
  */
423
- function getComponentStatus(IPolicyPoolComponent component)
424
- external
425
- view
426
- returns (ComponentStatus)
427
- {
380
+ function getComponentStatus(IPolicyPoolComponent component) external view returns (ComponentStatus) {
428
381
  return _components[component].status;
429
382
  }
430
383
 
431
- function _etkStatus(IEToken eToken) internal view returns (ComponentStatus) {
432
- Component storage comp = _components[IPolicyPoolComponent(address(eToken))];
433
- require(comp.kind == ComponentKind.eToken, "Component is not an eToken");
384
+ function _componentStatus(address component, ComponentKind kind) internal view returns (ComponentStatus) {
385
+ Component storage comp = _components[IPolicyPoolComponent(component)];
386
+ require(comp.kind == kind, "Component is not of the right kind");
434
387
  return comp.status;
435
388
  }
436
389
 
437
- function _rmStatus(IRiskModule riskModule) internal view returns (ComponentStatus) {
438
- Component storage comp = _components[IPolicyPoolComponent(address(riskModule))];
439
- require(comp.kind == ComponentKind.riskModule, "Component is not a RiskModule");
440
- return comp.status;
390
+ function _requireCompActive(address component, ComponentKind kind) internal view {
391
+ require(_componentStatus(component, kind) == ComponentStatus.active, "Component not found or not active");
441
392
  }
442
393
 
443
- function _paStatus(IPremiumsAccount premiumsAccount) internal view returns (ComponentStatus) {
444
- Component storage comp = _components[IPolicyPoolComponent(address(premiumsAccount))];
445
- require(comp.kind == ComponentKind.premiumsAccount, "Component is not a PremiumsAccount");
446
- return comp.status;
394
+ function _requireCompActiveOrDeprecated(address component, ComponentKind kind) internal view {
395
+ ComponentStatus status = _componentStatus(component, kind);
396
+ require(
397
+ status == ComponentStatus.active || status == ComponentStatus.deprecated,
398
+ "Component must be active or deprecated"
399
+ );
447
400
  }
448
401
 
449
402
  function deposit(IEToken eToken, uint256 amount) external override whenNotPaused {
450
- require(_etkStatus(eToken) == ComponentStatus.active, "eToken is not active");
403
+ _requireCompActive(address(eToken), ComponentKind.eToken);
451
404
  uint256 balanceBefore = _currency.balanceOf(address(eToken));
452
405
  _currency.safeTransferFrom(_msgSender(), address(eToken), amount);
453
406
  eToken.deposit(_msgSender(), _currency.balanceOf(address(eToken)) - balanceBefore);
454
407
  }
455
408
 
456
- function withdraw(IEToken eToken, uint256 amount)
457
- external
458
- override
459
- whenNotPaused
460
- returns (uint256)
461
- {
462
- ComponentStatus etkStatus = _etkStatus(eToken);
463
- require(
464
- etkStatus == ComponentStatus.active || etkStatus == ComponentStatus.deprecated,
465
- "eToken not found or withdraws not allowed"
466
- );
467
- address provider = _msgSender();
468
- return eToken.withdraw(provider, amount);
409
+ function withdraw(IEToken eToken, uint256 amount) external override whenNotPaused returns (uint256) {
410
+ _requireCompActiveOrDeprecated(address(eToken), ComponentKind.eToken);
411
+ return eToken.withdraw(_msgSender(), amount);
469
412
  }
470
413
 
471
414
  function newPolicy(
@@ -477,14 +420,15 @@ contract PolicyPool is IPolicyPool, PausableUpgradeable, UUPSUpgradeable, ERC721
477
420
  // Checks
478
421
  IRiskModule rm = policy.riskModule;
479
422
  require(address(rm) == _msgSender(), "Only the RM can create new policies");
480
- require(_rmStatus(rm) == ComponentStatus.active, "RM module not found or not active");
423
+ _requireCompActive(address(rm), ComponentKind.riskModule);
481
424
  IPremiumsAccount pa = rm.premiumsAccount();
482
- require(_paStatus(pa) == ComponentStatus.active, "PremiumsAccount not found or not active");
425
+ _requireCompActive(address(pa), ComponentKind.premiumsAccount);
483
426
 
484
427
  // Effects
485
- policy.id = (uint256(uint160(address(rm))) << 96) + internalId;
428
+ policy.id = makePolicyId(rm, internalId);
486
429
  require(_policies[policy.id] == bytes32(0), "Policy already exists");
487
430
  _policies[policy.id] = policy.hash();
431
+ _safeMint(policyHolder, policy.id, "");
488
432
 
489
433
  // Interactions
490
434
  pa.policyCreated(policy);
@@ -501,16 +445,81 @@ contract PolicyPool is IPolicyPool, PausableUpgradeable, UUPSUpgradeable, ERC721
501
445
  * transfers. This might be considered in the future, but to avoid increasing the complexity and since so far we
502
446
  * operate on low gas-cost blockchains, we keep it as it is.
503
447
  */
504
- _safeMint(policyHolder, policy.id, "");
505
448
 
506
449
  emit NewPolicy(rm, policy);
507
450
  return policy.id;
508
451
  }
509
452
 
453
+ function replacePolicy(
454
+ Policy.PolicyData memory oldPolicy,
455
+ Policy.PolicyData memory newPolicy_,
456
+ address payer,
457
+ uint96 internalId
458
+ ) external override whenNotPaused returns (uint256) {
459
+ // Checks
460
+ _validatePolicy(oldPolicy);
461
+ IRiskModule rm = oldPolicy.riskModule;
462
+ require(address(rm) == _msgSender(), "Only the RM can create new policies");
463
+ _requireCompActive(address(rm), ComponentKind.riskModule);
464
+ IPremiumsAccount pa = rm.premiumsAccount();
465
+ _requireCompActive(address(pa), ComponentKind.premiumsAccount);
466
+ require(oldPolicy.expiration > uint40(block.timestamp), "Old policy is expired");
467
+ require(oldPolicy.start == newPolicy_.start, "Both policies must have the same starting date");
468
+ require(
469
+ oldPolicy.payout <= newPolicy_.payout &&
470
+ oldPolicy.purePremium <= newPolicy_.purePremium &&
471
+ oldPolicy.ensuroCommission <= newPolicy_.ensuroCommission &&
472
+ oldPolicy.jrCoc <= newPolicy_.jrCoc &&
473
+ oldPolicy.srCoc <= newPolicy_.srCoc &&
474
+ oldPolicy.jrScr <= newPolicy_.jrScr &&
475
+ oldPolicy.srScr <= newPolicy_.srScr &&
476
+ oldPolicy.partnerCommission <= newPolicy_.partnerCommission &&
477
+ oldPolicy.expiration <= newPolicy_.expiration &&
478
+ rm == newPolicy_.riskModule,
479
+ "New policy must be greater or equal than old policy"
480
+ );
481
+
482
+ // Effects
483
+ newPolicy_.id = makePolicyId(rm, internalId);
484
+ require(_policies[newPolicy_.id] == bytes32(0), "Policy already exists");
485
+ _policies[newPolicy_.id] = newPolicy_.hash();
486
+ address policyHolder = ownerOf(oldPolicy.id);
487
+ _safeMint(policyHolder, newPolicy_.id, "");
488
+ delete _policies[oldPolicy.id];
489
+
490
+ // Interactions
491
+ pa.policyReplaced(oldPolicy, newPolicy_);
492
+
493
+ // Distribute the premium
494
+ uint256 aux = newPolicy_.purePremium - oldPolicy.purePremium;
495
+ if (aux > 0) _currency.safeTransferFrom(payer, address(pa), aux);
496
+ aux = newPolicy_.srCoc - oldPolicy.srCoc;
497
+ if (aux > 0) _currency.safeTransferFrom(payer, address(pa.seniorEtk()), aux);
498
+ aux = newPolicy_.jrCoc - oldPolicy.jrCoc;
499
+ if (aux > 0) _currency.safeTransferFrom(payer, address(pa.juniorEtk()), aux);
500
+ aux = newPolicy_.ensuroCommission - oldPolicy.ensuroCommission;
501
+ if (aux > 0) _currency.safeTransferFrom(payer, _treasury, aux);
502
+ aux = newPolicy_.partnerCommission - oldPolicy.partnerCommission;
503
+ if (aux > 0 && payer != rm.wallet()) _currency.safeTransferFrom(payer, rm.wallet(), aux);
504
+ /**
505
+ * This code does up to 5 ERC20 transfers. This can be avoided to reduce the gas cost, by implementing delayed
506
+ * transfers. This might be considered in the future, but to avoid increasing the complexity and since so far we
507
+ * operate on low gas-cost blockchains, we keep it as it is.
508
+ */
509
+
510
+ emit NewPolicy(rm, newPolicy_);
511
+ emit PolicyReplaced(rm, oldPolicy.id, newPolicy_.id);
512
+ return newPolicy_.id;
513
+ }
514
+
510
515
  function _validatePolicy(Policy.PolicyData memory policy) internal view {
511
516
  require(policy.id != 0 && policy.hash() == _policies[policy.id], "Policy not found");
512
517
  }
513
518
 
519
+ function makePolicyId(IRiskModule rm, uint96 internalId) public pure returns (uint256) {
520
+ return (uint256(uint160(address(rm))) << 96) + internalId;
521
+ }
522
+
514
523
  function expirePolicy(Policy.PolicyData calldata policy) external override whenNotPaused {
515
524
  require(policy.expiration <= block.timestamp, "Policy not expired yet");
516
525
  return _resolvePolicy(policy, 0, true);
@@ -523,19 +532,14 @@ contract PolicyPool is IPolicyPool, PausableUpgradeable, UUPSUpgradeable, ERC721
523
532
  }
524
533
  }
525
534
 
526
- function resolvePolicy(Policy.PolicyData calldata policy, uint256 payout)
527
- external
528
- override
529
- whenNotPaused
530
- {
535
+ function resolvePolicy(Policy.PolicyData calldata policy, uint256 payout) external override whenNotPaused {
531
536
  return _resolvePolicy(policy, payout, false);
532
537
  }
533
538
 
534
- function resolvePolicyFullPayout(Policy.PolicyData calldata policy, bool customerWon)
535
- external
536
- override
537
- whenNotPaused
538
- {
539
+ function resolvePolicyFullPayout(
540
+ Policy.PolicyData calldata policy,
541
+ bool customerWon
542
+ ) external override whenNotPaused {
539
543
  return _resolvePolicy(policy, customerWon ? policy.payout : 0, false);
540
544
  }
541
545
 
@@ -558,31 +562,20 @@ contract PolicyPool is IPolicyPool, PausableUpgradeable, UUPSUpgradeable, ERC721
558
562
  * @param payout The amount to paid to the policyholder
559
563
  * @param expired True for expiration resolution (`payout` must be 0)
560
564
  */
561
- function _resolvePolicy(
562
- Policy.PolicyData memory policy,
563
- uint256 payout,
564
- bool expired
565
- ) internal {
565
+ function _resolvePolicy(Policy.PolicyData memory policy, uint256 payout, bool expired) internal {
566
566
  // Checks
567
567
  _validatePolicy(policy);
568
568
  IRiskModule rm = policy.riskModule;
569
569
  require(expired || address(rm) == _msgSender(), "Only the RM can resolve policies");
570
570
  require(payout == 0 || policy.expiration > block.timestamp, "Can't pay expired policy");
571
- ComponentStatus compStatus = _rmStatus(rm);
572
- require(
573
- compStatus == ComponentStatus.active || compStatus == ComponentStatus.deprecated,
574
- "Module must be active or deprecated to process resolutions"
575
- );
571
+ _requireCompActiveOrDeprecated(address(rm), ComponentKind.riskModule);
572
+
576
573
  require(payout <= policy.payout, "payout > policy.payout");
577
574
 
578
575
  bool customerWon = payout > 0;
579
576
 
580
577
  IPremiumsAccount pa = rm.premiumsAccount();
581
- compStatus = _paStatus(pa);
582
- require(
583
- compStatus == ComponentStatus.active || compStatus == ComponentStatus.deprecated,
584
- "PremiumsAccount must be active or deprecated to process resolutions"
585
- );
578
+ _requireCompActiveOrDeprecated(address(pa), ComponentKind.premiumsAccount);
586
579
  // Effects
587
580
  delete _policies[policy.id];
588
581
  // Interactions
@@ -612,16 +605,8 @@ contract PolicyPool is IPolicyPool, PausableUpgradeable, UUPSUpgradeable, ERC721
612
605
  if (!AddressUpgradeable.isContract(customer)) return;
613
606
  if (!ERC165Checker.supportsInterface(customer, type(IPolicyHolder).interfaceId)) return;
614
607
 
615
- bytes4 retval = IPolicyHolder(customer).onPayoutReceived(
616
- _msgSender(),
617
- address(this),
618
- policyId,
619
- payout
620
- );
621
- require(
622
- retval == IPolicyHolder.onPayoutReceived.selector,
623
- "PolicyPool: Invalid return value from IPolicyHolder"
624
- );
608
+ bytes4 retval = IPolicyHolder(customer).onPayoutReceived(_msgSender(), address(this), policyId, payout);
609
+ require(retval == IPolicyHolder.onPayoutReceived.selector, "PolicyPool: Invalid return value from IPolicyHolder");
625
610
  }
626
611
 
627
612
  /**
@@ -632,9 +617,7 @@ contract PolicyPool is IPolicyPool, PausableUpgradeable, UUPSUpgradeable, ERC721
632
617
  if (!AddressUpgradeable.isContract(customer)) return;
633
618
  if (!ERC165Checker.supportsInterface(customer, type(IPolicyHolder).interfaceId)) return;
634
619
 
635
- try IPolicyHolder(customer).onPolicyExpired(_msgSender(), address(this), policyId) returns (
636
- bytes4
637
- ) {
620
+ try IPolicyHolder(customer).onPolicyExpired(_msgSender(), address(this), policyId) returns (bytes4) {
638
621
  return;
639
622
  } catch {
640
623
  return;
@@ -24,11 +24,7 @@ import {WadRayMath} from "./dependencies/WadRayMath.sol";
24
24
  * @custom:security-contact security@ensuro.co
25
25
  * @author Ensuro
26
26
  */
27
- abstract contract PolicyPoolComponent is
28
- UUPSUpgradeable,
29
- PausableUpgradeable,
30
- IPolicyPoolComponent
31
- {
27
+ abstract contract PolicyPoolComponent is UUPSUpgradeable, PausableUpgradeable, IPolicyPoolComponent {
32
28
  using WadRayMath for uint256;
33
29
 
34
30
  bytes32 public constant GUARDIAN_ROLE = keccak256("GUARDIAN_ROLE");
@@ -80,10 +76,7 @@ abstract contract PolicyPoolComponent is
80
76
 
81
77
  /// @custom:oz-upgrades-unsafe-allow constructor
82
78
  constructor(IPolicyPool policyPool_) {
83
- require(
84
- address(policyPool_) != address(0),
85
- "PolicyPoolComponent: policyPool cannot be zero address"
86
- );
79
+ require(address(policyPool_) != address(0), "PolicyPoolComponent: policyPool cannot be zero address");
87
80
  _disableInitializers();
88
81
  _policyPool = policyPool_;
89
82
  }
@@ -94,29 +87,21 @@ abstract contract PolicyPoolComponent is
94
87
  __Pausable_init();
95
88
  }
96
89
 
97
- function _authorizeUpgrade(address newImpl)
98
- internal
99
- view
100
- override
101
- onlyGlobalOrComponentRole2(GUARDIAN_ROLE, LEVEL1_ROLE)
102
- {
90
+ function _authorizeUpgrade(
91
+ address newImpl
92
+ ) internal view override onlyGlobalOrComponentRole2(GUARDIAN_ROLE, LEVEL1_ROLE) {
103
93
  _upgradeValidations(newImpl);
104
94
  }
105
95
 
106
96
  function _upgradeValidations(address newImpl) internal view virtual {
107
- require(
108
- IPolicyPoolComponent(newImpl).policyPool() == _policyPool,
109
- "Can't upgrade changing the PolicyPool!"
110
- );
97
+ require(IPolicyPoolComponent(newImpl).policyPool() == _policyPool, "Can't upgrade changing the PolicyPool!");
111
98
  }
112
99
 
113
100
  /**
114
101
  * @dev See {IERC165-supportsInterface}.
115
102
  */
116
103
  function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
117
- return
118
- interfaceId == type(IERC165).interfaceId ||
119
- interfaceId == type(IPolicyPoolComponent).interfaceId;
104
+ return interfaceId == type(IERC165).interfaceId || interfaceId == type(IPolicyPoolComponent).interfaceId;
120
105
  }
121
106
 
122
107
  function pause() public onlyGlobalOrComponentRole(GUARDIAN_ROLE) {
@@ -139,11 +124,7 @@ abstract contract PolicyPoolComponent is
139
124
  return _policyPool.access().hasComponentRole(address(this), role, _msgSender(), true);
140
125
  }
141
126
 
142
- function _isTweakWad(
143
- uint256 oldValue,
144
- uint256 newValue,
145
- uint256 maxTweak
146
- ) internal pure returns (bool) {
127
+ function _isTweakWad(uint256 oldValue, uint256 newValue, uint256 maxTweak) internal pure returns (bool) {
147
128
  if (oldValue == newValue) return true;
148
129
  if (oldValue == 0) return maxTweak >= WadRayMath.WAD;
149
130
  if (newValue == 0) return false;
@@ -157,11 +138,7 @@ abstract contract PolicyPoolComponent is
157
138
  // solhint-disable-next-line no-empty-blocks
158
139
  function _validateParameters() internal view virtual {} // Must be reimplemented with specific validations
159
140
 
160
- function _parameterChanged(
161
- IAccessManager.GovernanceActions action,
162
- uint256 value,
163
- bool tweak
164
- ) internal {
141
+ function _parameterChanged(IAccessManager.GovernanceActions action, uint256 value, bool tweak) internal {
165
142
  _validateParameters();
166
143
  if (tweak) _registerTweak(action);
167
144
  emit GovernanceAction(action, value);
@@ -2,6 +2,7 @@
2
2
  pragma solidity ^0.8.0;
3
3
 
4
4
  import {Math} from "@openzeppelin/contracts/utils/math/Math.sol";
5
+ import {SignedMath} from "@openzeppelin/contracts/utils/math/SignedMath.sol";
5
6
  import {IERC20Metadata} from "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol";
6
7
  import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
7
8
  import {SafeCast} from "@openzeppelin/contracts/utils/math/SafeCast.sol";
@@ -113,11 +114,7 @@ contract PremiumsAccount is IPremiumsAccount, Reserve {
113
114
  * @param seniorEtk_ Address of the Senior EToken (2nd loss lender). `address(0)` if not present.
114
115
  */
115
116
  /// @custom:oz-upgrades-unsafe-allow constructor
116
- constructor(
117
- IPolicyPool policyPool_,
118
- IEToken juniorEtk_,
119
- IEToken seniorEtk_
120
- ) Reserve(policyPool_) {
117
+ constructor(IPolicyPool policyPool_, IEToken juniorEtk_, IEToken seniorEtk_) Reserve(policyPool_) {
121
118
  _juniorEtk = juniorEtk_;
122
119
  _seniorEtk = seniorEtk_;
123
120
  }
@@ -169,8 +166,7 @@ contract PremiumsAccount is IPremiumsAccount, Reserve {
169
166
  * @dev See {IERC165-supportsInterface}.
170
167
  */
171
168
  function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
172
- return
173
- super.supportsInterface(interfaceId) || interfaceId == type(IPremiumsAccount).interfaceId;
169
+ return super.supportsInterface(interfaceId) || interfaceId == type(IPremiumsAccount).interfaceId;
174
170
  }
175
171
 
176
172
  function assetManager() public view override returns (IAssetManager) {
@@ -274,12 +270,12 @@ contract PremiumsAccount is IPremiumsAccount, Reserve {
274
270
 
275
271
  function _toAmount(uint32 value) internal view returns (uint256) {
276
272
  // 0 decimals to amount decimals
277
- return uint256(value) * 10**currency().decimals();
273
+ return uint256(value) * 10 ** currency().decimals();
278
274
  }
279
275
 
280
276
  function _toZeroDecimals(uint256 amount) internal view returns (uint32) {
281
277
  // Removes the decimals from the amount
282
- return (amount / 10**currency().decimals()).toUint32();
278
+ return (amount / 10 ** currency().decimals()).toUint32();
283
279
  }
284
280
 
285
281
  /**
@@ -316,15 +312,9 @@ contract PremiumsAccount is IPremiumsAccount, Reserve {
316
312
  * `_maxDeficit()` and borrows the difference from the eTokens.
317
313
  * If false and the new ratio leaves `_surplus < -_maxDeficit()`, the operation is reverted.
318
314
  */
319
- function setDeficitRatio(uint256 newRatio, bool adjustment)
320
- external
321
- onlyGlobalOrComponentRole(LEVEL2_ROLE)
322
- {
315
+ function setDeficitRatio(uint256 newRatio, bool adjustment) external onlyGlobalOrComponentRole(LEVEL2_ROLE) {
323
316
  uint16 truncatedRatio = (newRatio / FOUR_DECIMAL_TO_WAD).toUint16();
324
- require(
325
- uint256(truncatedRatio) * FOUR_DECIMAL_TO_WAD == newRatio,
326
- "Validation: only up to 4 decimals allowed"
327
- );
317
+ require(uint256(truncatedRatio) * FOUR_DECIMAL_TO_WAD == newRatio, "Validation: only up to 4 decimals allowed");
328
318
 
329
319
  int256 maxDeficit = _maxDeficit(newRatio);
330
320
  require(adjustment || _surplus >= maxDeficit, "Validation: surplus must be >= maxDeficit");
@@ -356,10 +346,7 @@ contract PremiumsAccount is IPremiumsAccount, Reserve {
356
346
  * @param newLimitSr The new limit to be set for the loans taken from the Senior eToken.
357
347
  If newLimitSr == MAX_UINT, it's ignored. If == 0, means the loans are unbounded.
358
348
  */
359
- function setLoanLimits(uint256 newLimitJr, uint256 newLimitSr)
360
- external
361
- onlyGlobalOrComponentRole(LEVEL2_ROLE)
362
- {
349
+ function setLoanLimits(uint256 newLimitJr, uint256 newLimitSr) external onlyGlobalOrComponentRole(LEVEL2_ROLE) {
363
350
  if (newLimitJr != type(uint256).max) {
364
351
  _params.jrLoanLimit = _toZeroDecimals(newLimitJr);
365
352
  require(_toAmount(_params.jrLoanLimit) == newLimitJr, "Validation: no decimals allowed");
@@ -381,11 +368,7 @@ contract PremiumsAccount is IPremiumsAccount, Reserve {
381
368
  * in the context of a policy payout.
382
369
  * @param jrEtk If true it indicates that the loan is asked first from the junior eToken.
383
370
  */
384
- function _borrowFromEtk(
385
- uint256 borrow,
386
- address receiver,
387
- bool jrEtk
388
- ) internal {
371
+ function _borrowFromEtk(uint256 borrow, address receiver, bool jrEtk) internal {
389
372
  uint256 left = borrow;
390
373
  if (jrEtk) {
391
374
  if (_juniorEtk.getLoan(address(this)) + borrow <= jrLoanLimit()) {
@@ -471,11 +454,10 @@ contract PremiumsAccount is IPremiumsAccount, Reserve {
471
454
  * @param destination The address that will receive the transferred funds.
472
455
  * @return Returns the actual amount withdrawn.
473
456
  */
474
- function withdrawWonPremiums(uint256 amount, address destination)
475
- external
476
- onlyGlobalOrComponentRole(WITHDRAW_WON_PREMIUMS_ROLE)
477
- returns (uint256)
478
- {
457
+ function withdrawWonPremiums(
458
+ uint256 amount,
459
+ address destination
460
+ ) external onlyGlobalOrComponentRole(WITHDRAW_WON_PREMIUMS_ROLE) returns (uint256) {
479
461
  require(destination != address(0), "PremiumsAccount: destination cannot be the zero address");
480
462
  if (_surplus <= 0) {
481
463
  amount = 0;
@@ -489,17 +471,36 @@ contract PremiumsAccount is IPremiumsAccount, Reserve {
489
471
  return amount;
490
472
  }
491
473
 
492
- function policyCreated(Policy.PolicyData memory policy)
493
- external
494
- override
495
- onlyPolicyPool
496
- whenNotPaused
497
- {
474
+ function policyCreated(Policy.PolicyData memory policy) external override onlyPolicyPool whenNotPaused {
498
475
  _activePurePremiums += policy.purePremium;
499
476
  if (policy.jrScr > 0) _juniorEtk.lockScr(policy.jrScr, policy.jrInterestRate());
500
477
  if (policy.srScr > 0) _seniorEtk.lockScr(policy.srScr, policy.srInterestRate());
501
478
  }
502
479
 
480
+ function policyReplaced(
481
+ Policy.PolicyData memory oldPolicy,
482
+ Policy.PolicyData memory newPolicy
483
+ ) external override onlyPolicyPool whenNotPaused {
484
+ if (oldPolicy.srScr > 0 && newPolicy.srScr > 0) {
485
+ int256 diff = int256(oldPolicy.srInterestRate()) - int256(newPolicy.srInterestRate());
486
+ require(SignedMath.abs(diff) < 1e14, "Interest rate can't change");
487
+ }
488
+ if (oldPolicy.jrScr > 0 && newPolicy.jrScr > 0) {
489
+ int256 diff = int256(oldPolicy.jrInterestRate()) - int256(newPolicy.jrInterestRate());
490
+ require(SignedMath.abs(diff) < 1e14, "Interest rate can't change");
491
+ }
492
+ /*
493
+ * Supporting interest rate change is possible, but it would require complex computations.
494
+ * If new IR > old IR, then we must adjust positivelly to accrue the interests not accrued
495
+ * If new IR < old IR, then we must adjust negativelly to substract the interests accrued in excess
496
+ */
497
+ _activePurePremiums += newPolicy.purePremium - oldPolicy.purePremium;
498
+ if (oldPolicy.jrScr > 0) _juniorEtk.unlockScr(oldPolicy.jrScr, oldPolicy.jrInterestRate(), 0);
499
+ if (oldPolicy.srScr > 0) _seniorEtk.unlockScr(oldPolicy.srScr, oldPolicy.srInterestRate(), 0);
500
+ if (newPolicy.jrScr > 0) _juniorEtk.lockScr(newPolicy.jrScr, newPolicy.jrInterestRate());
501
+ if (newPolicy.srScr > 0) _seniorEtk.lockScr(newPolicy.srScr, newPolicy.srInterestRate());
502
+ }
503
+
503
504
  function policyResolvedWithPayout(
504
505
  address policyHolder,
505
506
  Policy.PolicyData memory policy,
@@ -550,10 +551,8 @@ contract PremiumsAccount is IPremiumsAccount, Reserve {
550
551
  returns (uint256 available)
551
552
  {
552
553
  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);
554
+ if (available != 0 && address(_seniorEtk) != address(0)) available = _repayLoan(available, _seniorEtk);
555
+ if (available != 0 && address(_juniorEtk) != address(0)) available = _repayLoan(available, _juniorEtk);
557
556
  return available;
558
557
  }
559
558
 
@@ -589,12 +588,7 @@ contract PremiumsAccount is IPremiumsAccount, Reserve {
589
588
  return fundsAvailable_ - repayAmount;
590
589
  }
591
590
 
592
- function policyExpired(Policy.PolicyData memory policy)
593
- external
594
- override
595
- onlyPolicyPool
596
- whenNotPaused
597
- {
591
+ function policyExpired(Policy.PolicyData memory policy) external override onlyPolicyPool whenNotPaused {
598
592
  _activePurePremiums -= policy.purePremium;
599
593
  _storePurePremiumWon(policy.purePremium);
600
594
  _unlockScr(policy);