@ensuro/core 2.8.0 → 2.8.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.
- package/contracts/Policy.sol +58 -21
- package/contracts/PolicyPool.sol +155 -37
- package/contracts/PolicyPoolComponent.sol +5 -2
- package/contracts/RiskModule.sol +27 -30
- package/contracts/SignedBucketRiskModule.sol +32 -95
- package/contracts/SignedQuoteRiskModule.sol +3 -1
- package/contracts/interfaces/IPolicyHolder.sol +2 -2
- package/contracts/interfaces/IPolicyHolderV2.sol +29 -0
- package/contracts/mocks/PolicyHolderMock.sol +71 -10
- package/js/utils.js +9 -4
- package/package.json +1 -1
- package/contracts/TieredSignedQuoteRiskModule.sol +0 -159
package/contracts/Policy.sol
CHANGED
|
@@ -34,6 +34,51 @@ library Policy {
|
|
|
34
34
|
uint40 expiration;
|
|
35
35
|
}
|
|
36
36
|
|
|
37
|
+
struct PremiumComposition {
|
|
38
|
+
uint256 purePremium;
|
|
39
|
+
uint256 jrScr;
|
|
40
|
+
uint256 srScr;
|
|
41
|
+
uint256 jrCoc;
|
|
42
|
+
uint256 srCoc;
|
|
43
|
+
uint256 ensuroCommission;
|
|
44
|
+
uint256 partnerCommission;
|
|
45
|
+
uint256 totalPremium;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
function getMinimumPremium(
|
|
49
|
+
IRiskModule.Params memory rmParams,
|
|
50
|
+
uint256 payout,
|
|
51
|
+
uint256 lossProb,
|
|
52
|
+
uint40 expiration,
|
|
53
|
+
uint40 start
|
|
54
|
+
) internal pure returns (PremiumComposition memory minPremium) {
|
|
55
|
+
minPremium.purePremium = payout.wadMul(lossProb.wadMul(rmParams.moc));
|
|
56
|
+
minPremium.jrScr = payout.wadMul(rmParams.jrCollRatio);
|
|
57
|
+
if (minPremium.jrScr > minPremium.purePremium) {
|
|
58
|
+
minPremium.jrScr -= minPremium.purePremium;
|
|
59
|
+
} else {
|
|
60
|
+
minPremium.jrScr = 0;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
minPremium.srScr = payout.wadMul(rmParams.collRatio);
|
|
64
|
+
if (minPremium.srScr > (minPremium.purePremium + minPremium.jrScr)) {
|
|
65
|
+
minPremium.srScr -= minPremium.purePremium + minPremium.jrScr;
|
|
66
|
+
} else {
|
|
67
|
+
minPremium.srScr = 0;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
// Calculate CoCs
|
|
71
|
+
minPremium.jrCoc = minPremium.jrScr.wadMul((rmParams.jrRoc * (expiration - start)) / SECONDS_PER_YEAR);
|
|
72
|
+
minPremium.srCoc = minPremium.srScr.wadMul((rmParams.srRoc * (expiration - start)) / SECONDS_PER_YEAR);
|
|
73
|
+
uint256 totalCoc = minPremium.jrCoc + minPremium.srCoc;
|
|
74
|
+
|
|
75
|
+
minPremium.ensuroCommission =
|
|
76
|
+
minPremium.purePremium.wadMul(rmParams.ensuroPpFee) +
|
|
77
|
+
totalCoc.wadMul(rmParams.ensuroCocFee);
|
|
78
|
+
|
|
79
|
+
minPremium.totalPremium = minPremium.purePremium + minPremium.ensuroCommission + totalCoc;
|
|
80
|
+
}
|
|
81
|
+
|
|
37
82
|
function initialize(
|
|
38
83
|
IRiskModule riskModule,
|
|
39
84
|
IRiskModule.Params memory rmParams,
|
|
@@ -52,27 +97,19 @@ library Policy {
|
|
|
52
97
|
policy.lossProb = lossProb;
|
|
53
98
|
policy.start = start;
|
|
54
99
|
policy.expiration = expiration;
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
policy.
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
}
|
|
69
|
-
// Calculate CoCs
|
|
70
|
-
policy.jrCoc = policy.jrScr.wadMul((rmParams.jrRoc * (policy.expiration - policy.start)) / SECONDS_PER_YEAR);
|
|
71
|
-
policy.srCoc = policy.srScr.wadMul((rmParams.srRoc * (policy.expiration - policy.start)) / SECONDS_PER_YEAR);
|
|
72
|
-
uint256 coc = policy.jrCoc + policy.srCoc;
|
|
73
|
-
policy.ensuroCommission = policy.purePremium.wadMul(rmParams.ensuroPpFee) + coc.wadMul(rmParams.ensuroCocFee);
|
|
74
|
-
require((policy.purePremium + policy.ensuroCommission + coc) <= premium, "Premium less than minimum");
|
|
75
|
-
policy.partnerCommission = premium - policy.purePremium - coc - policy.ensuroCommission;
|
|
100
|
+
|
|
101
|
+
PremiumComposition memory minPremium = getMinimumPremium(rmParams, payout, lossProb, expiration, start);
|
|
102
|
+
|
|
103
|
+
policy.purePremium = minPremium.purePremium;
|
|
104
|
+
policy.jrScr = minPremium.jrScr;
|
|
105
|
+
policy.srScr = minPremium.srScr;
|
|
106
|
+
policy.jrCoc = minPremium.jrCoc;
|
|
107
|
+
policy.srCoc = minPremium.srCoc;
|
|
108
|
+
policy.ensuroCommission = minPremium.ensuroCommission;
|
|
109
|
+
|
|
110
|
+
require(minPremium.totalPremium <= premium, "Premium less than minimum");
|
|
111
|
+
|
|
112
|
+
policy.partnerCommission = premium - minPremium.totalPremium;
|
|
76
113
|
return policy;
|
|
77
114
|
}
|
|
78
115
|
|
package/contracts/PolicyPool.sol
CHANGED
|
@@ -11,6 +11,7 @@ import {UUPSUpgradeable} from "@openzeppelin/contracts-upgradeable/proxy/utils/U
|
|
|
11
11
|
|
|
12
12
|
import {IAccessManager} from "./interfaces/IAccessManager.sol";
|
|
13
13
|
import {IEToken} from "./interfaces/IEToken.sol";
|
|
14
|
+
import {IPolicyHolderV2} from "./interfaces/IPolicyHolderV2.sol";
|
|
14
15
|
import {IPolicyHolder} from "./interfaces/IPolicyHolder.sol";
|
|
15
16
|
import {IPolicyPool} from "./interfaces/IPolicyPool.sol";
|
|
16
17
|
import {IPolicyPoolComponent} from "./interfaces/IPolicyPoolComponent.sol";
|
|
@@ -43,6 +44,8 @@ contract PolicyPool is IPolicyPool, PausableUpgradeable, UUPSUpgradeable, ERC721
|
|
|
43
44
|
bytes32 public constant LEVEL2_ROLE = keccak256("LEVEL2_ROLE");
|
|
44
45
|
bytes32 public constant LEVEL3_ROLE = keccak256("LEVEL3_ROLE");
|
|
45
46
|
|
|
47
|
+
uint256 internal constant HOLDER_GAS_LIMIT = 150000;
|
|
48
|
+
|
|
46
49
|
/**
|
|
47
50
|
* @dev {AccessManager} that handles the access permissions for the PolicyPool and its components.
|
|
48
51
|
*/
|
|
@@ -125,6 +128,98 @@ contract PolicyPool is IPolicyPool, PausableUpgradeable, UUPSUpgradeable, ERC721
|
|
|
125
128
|
*/
|
|
126
129
|
string internal _nftBaseURI;
|
|
127
130
|
|
|
131
|
+
/**
|
|
132
|
+
* @dev Constructor error when address(0) is sent as `access()`
|
|
133
|
+
*/
|
|
134
|
+
error NoZeroAccess();
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
* @dev Constructor error when address(0) is sent as `currency()`
|
|
138
|
+
*/
|
|
139
|
+
error NoZeroCurrency();
|
|
140
|
+
|
|
141
|
+
/**
|
|
142
|
+
* @dev Constructor error (or setTreasury) when address(0) is sent as `treasury()`
|
|
143
|
+
*/
|
|
144
|
+
error NoZeroTreasury();
|
|
145
|
+
|
|
146
|
+
/**
|
|
147
|
+
* @dev Initialization error when empty name for the ERC721 is sent
|
|
148
|
+
*/
|
|
149
|
+
error NoEmptyName();
|
|
150
|
+
|
|
151
|
+
/**
|
|
152
|
+
* @dev Initialization error when empty symbol for the ERC721 is sent
|
|
153
|
+
*/
|
|
154
|
+
error NoEmptySymbol();
|
|
155
|
+
|
|
156
|
+
/**
|
|
157
|
+
* @dev Upgrade error when the new implementation contract tries to change the `access()`
|
|
158
|
+
*/
|
|
159
|
+
error UpgradeCannotChangeAccess();
|
|
160
|
+
|
|
161
|
+
/**
|
|
162
|
+
* @dev Upgrade error when the new implementation contract tries to change the `currency()`
|
|
163
|
+
*/
|
|
164
|
+
error UpgradeCannotChangeCurrency();
|
|
165
|
+
|
|
166
|
+
/**
|
|
167
|
+
* @dev Error when trying to add a component that was already added to the PolicyPool
|
|
168
|
+
*/
|
|
169
|
+
error ComponentAlreadyInThePool();
|
|
170
|
+
|
|
171
|
+
/**
|
|
172
|
+
* @dev Error when trying to add a component that isn't linked to this pool (`.policyPool() != this`)
|
|
173
|
+
*/
|
|
174
|
+
error ComponentNotLinkedToThisPool();
|
|
175
|
+
|
|
176
|
+
/**
|
|
177
|
+
* @dev Error when a component is not of the right kind, it might happen if a component declared as
|
|
178
|
+
* ComponentKind.eToken doesn't support the IEToken interface (or similar) or when in a given operation
|
|
179
|
+
* we expect a component to be a risk module and the stored kind is different.
|
|
180
|
+
*/
|
|
181
|
+
error ComponentNotTheRightKind(IPolicyPoolComponent component, ComponentKind expectedKind);
|
|
182
|
+
|
|
183
|
+
/**
|
|
184
|
+
* @dev Error when a component is expected to be deprecated for the operation (see `removeComponent`) and it isn't.
|
|
185
|
+
*/
|
|
186
|
+
error ComponentNotDeprecated();
|
|
187
|
+
|
|
188
|
+
/**
|
|
189
|
+
* @dev Error when trying to remove a component that is still in use. The "in use" definition can change from one
|
|
190
|
+
* component to the other. For eToken in use means `totalSupply() != 0`. For PremiumsAccount means
|
|
191
|
+
* `purePremiums() != 0`. For RiskModule means `activeExposure() != 0`.
|
|
192
|
+
*/
|
|
193
|
+
error ComponentInUseCannotRemove(ComponentKind kind, uint256 amount);
|
|
194
|
+
|
|
195
|
+
/**
|
|
196
|
+
* @dev Error when a component is not found in the pool (status = 0 = inactive)
|
|
197
|
+
*/
|
|
198
|
+
error ComponentNotFound();
|
|
199
|
+
|
|
200
|
+
/**
|
|
201
|
+
* @dev Error when a component is not found in the pool or is not active (status != active)
|
|
202
|
+
*/
|
|
203
|
+
error ComponentNotFoundOrNotActive();
|
|
204
|
+
|
|
205
|
+
/**
|
|
206
|
+
* @dev Error when a component is not active or deprecated. Happens on some operations like eToken withdrawals or
|
|
207
|
+
* policy resolutions that accept the component might be active or deprecated and isn't on any of those states.
|
|
208
|
+
*/
|
|
209
|
+
error ComponentMustBeActiveOrDeprecated();
|
|
210
|
+
|
|
211
|
+
/**
|
|
212
|
+
* @dev Error when a method intented to be called by riskModule (and by policy's risk module) is called by someone
|
|
213
|
+
* else.
|
|
214
|
+
*/
|
|
215
|
+
error OnlyRiskModuleAllowed();
|
|
216
|
+
|
|
217
|
+
/**
|
|
218
|
+
* @dev Error raised when IPolicyHolder doesn't return the expected selector answer when notified of policy payout,
|
|
219
|
+
* reception or replacement.
|
|
220
|
+
*/
|
|
221
|
+
error InvalidNotificationResponse(bytes4 response);
|
|
222
|
+
|
|
128
223
|
/**
|
|
129
224
|
* @dev Event emitted when the treasury changes
|
|
130
225
|
*
|
|
@@ -142,6 +237,13 @@ contract PolicyPool is IPolicyPool, PausableUpgradeable, UUPSUpgradeable, ERC721
|
|
|
142
237
|
*/
|
|
143
238
|
event ComponentStatusChanged(IPolicyPoolComponent indexed component, ComponentKind kind, ComponentStatus newStatus);
|
|
144
239
|
|
|
240
|
+
/**
|
|
241
|
+
* @dev Event emitted when a IPolicyHolder reverts on the expiration notification. The operation doesn't reverts
|
|
242
|
+
*
|
|
243
|
+
* @param policyId The id of the policy being expired
|
|
244
|
+
* @param holder The address of the contract that owns the policy
|
|
245
|
+
*/
|
|
246
|
+
event ExpirationNotificationFailed(uint256 indexed policyId, IPolicyHolder holder);
|
|
145
247
|
/**
|
|
146
248
|
* @dev Modifier that checks the caller has a given role
|
|
147
249
|
*/
|
|
@@ -167,8 +269,8 @@ contract PolicyPool is IPolicyPool, PausableUpgradeable, UUPSUpgradeable, ERC721
|
|
|
167
269
|
*/
|
|
168
270
|
/// @custom:oz-upgrades-unsafe-allow constructor
|
|
169
271
|
constructor(IAccessManager access_, IERC20Metadata currency_) {
|
|
170
|
-
|
|
171
|
-
|
|
272
|
+
if (address(access_) == address(0)) revert NoZeroAccess();
|
|
273
|
+
if (address(currency_) == address(0)) revert NoZeroCurrency();
|
|
172
274
|
_disableInitializers();
|
|
173
275
|
_access = access_;
|
|
174
276
|
_currency = currency_;
|
|
@@ -182,8 +284,8 @@ contract PolicyPool is IPolicyPool, PausableUpgradeable, UUPSUpgradeable, ERC721
|
|
|
182
284
|
* @param treasury_ The address of the treasury that will receive the protocol fees.
|
|
183
285
|
*/
|
|
184
286
|
function initialize(string memory name_, string memory symbol_, address treasury_) public initializer {
|
|
185
|
-
|
|
186
|
-
|
|
287
|
+
if (bytes(name_).length == 0) revert NoEmptyName();
|
|
288
|
+
if (bytes(symbol_).length == 0) revert NoEmptySymbol();
|
|
187
289
|
__UUPSUpgradeable_init();
|
|
188
290
|
__ERC721_init(name_, symbol_);
|
|
189
291
|
__Pausable_init();
|
|
@@ -204,8 +306,8 @@ contract PolicyPool is IPolicyPool, PausableUpgradeable, UUPSUpgradeable, ERC721
|
|
|
204
306
|
|
|
205
307
|
function _authorizeUpgrade(address newImpl) internal view override onlyRole2(GUARDIAN_ROLE, LEVEL1_ROLE) {
|
|
206
308
|
IPolicyPool newPool = IPolicyPool(newImpl);
|
|
207
|
-
|
|
208
|
-
|
|
309
|
+
if (newPool.access() != _access) revert UpgradeCannotChangeAccess();
|
|
310
|
+
if (newPool.currency() != _currency) revert UpgradeCannotChangeCurrency();
|
|
209
311
|
}
|
|
210
312
|
|
|
211
313
|
/**
|
|
@@ -238,7 +340,7 @@ contract PolicyPool is IPolicyPool, PausableUpgradeable, UUPSUpgradeable, ERC721
|
|
|
238
340
|
}
|
|
239
341
|
|
|
240
342
|
function _setTreasury(address treasury_) internal {
|
|
241
|
-
|
|
343
|
+
if (treasury_ == address(0)) revert NoZeroTreasury();
|
|
242
344
|
_treasury = treasury_;
|
|
243
345
|
emit ComponentChanged(IAccessManager.GovernanceActions.setTreasury, _treasury);
|
|
244
346
|
}
|
|
@@ -280,15 +382,14 @@ contract PolicyPool is IPolicyPool, PausableUpgradeable, UUPSUpgradeable, ERC721
|
|
|
280
382
|
*/
|
|
281
383
|
function addComponent(IPolicyPoolComponent component, ComponentKind kind) external onlyRole(LEVEL1_ROLE) {
|
|
282
384
|
Component storage comp = _components[component];
|
|
283
|
-
|
|
284
|
-
|
|
385
|
+
if (comp.status != ComponentStatus.inactive) revert ComponentAlreadyInThePool();
|
|
386
|
+
if (component.policyPool() != this) revert ComponentNotLinkedToThisPool();
|
|
285
387
|
|
|
286
|
-
|
|
287
|
-
(kind == ComponentKind.eToken && component.supportsInterface(type(IEToken).interfaceId)) ||
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
);
|
|
388
|
+
if (
|
|
389
|
+
(kind == ComponentKind.eToken && !component.supportsInterface(type(IEToken).interfaceId)) ||
|
|
390
|
+
(kind == ComponentKind.premiumsAccount && !component.supportsInterface(type(IPremiumsAccount).interfaceId)) ||
|
|
391
|
+
(kind == ComponentKind.riskModule && !component.supportsInterface(type(IRiskModule).interfaceId))
|
|
392
|
+
) revert ComponentNotTheRightKind(component, kind);
|
|
292
393
|
|
|
293
394
|
comp.status = ComponentStatus.active;
|
|
294
395
|
comp.kind = kind;
|
|
@@ -321,14 +422,16 @@ contract PolicyPool is IPolicyPool, PausableUpgradeable, UUPSUpgradeable, ERC721
|
|
|
321
422
|
*/
|
|
322
423
|
function removeComponent(IPolicyPoolComponent component) external onlyRole(LEVEL1_ROLE) {
|
|
323
424
|
Component storage comp = _components[component];
|
|
324
|
-
|
|
425
|
+
if (comp.status != ComponentStatus.deprecated) revert ComponentNotDeprecated();
|
|
325
426
|
if (comp.kind == ComponentKind.eToken) {
|
|
326
|
-
|
|
427
|
+
if (IEToken(address(component)).totalSupply() != 0)
|
|
428
|
+
revert ComponentInUseCannotRemove(comp.kind, IEToken(address(component)).totalSupply());
|
|
327
429
|
} else if (comp.kind == ComponentKind.riskModule) {
|
|
328
|
-
|
|
430
|
+
if (IRiskModule(address(component)).activeExposure() != 0)
|
|
431
|
+
revert ComponentInUseCannotRemove(comp.kind, IRiskModule(address(component)).activeExposure());
|
|
329
432
|
} else if (comp.kind == ComponentKind.premiumsAccount) {
|
|
330
433
|
IPremiumsAccount pa = IPremiumsAccount(address(component));
|
|
331
|
-
|
|
434
|
+
if (pa.purePremiums() != 0) revert ComponentInUseCannotRemove(comp.kind, pa.purePremiums());
|
|
332
435
|
IEToken etk = pa.juniorEtk();
|
|
333
436
|
if (address(etk) != address(0)) {
|
|
334
437
|
etk.removeBorrower(address(pa));
|
|
@@ -360,13 +463,13 @@ contract PolicyPool is IPolicyPool, PausableUpgradeable, UUPSUpgradeable, ERC721
|
|
|
360
463
|
ComponentStatus newStatus
|
|
361
464
|
) external onlyRole2(GUARDIAN_ROLE, LEVEL1_ROLE) {
|
|
362
465
|
Component storage comp = _components[component];
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
466
|
+
if (comp.status == ComponentStatus.inactive) revert ComponentNotFound();
|
|
467
|
+
if (newStatus == ComponentStatus.active || newStatus == ComponentStatus.deprecated) {
|
|
468
|
+
_access.checkRole(LEVEL1_ROLE, _msgSender());
|
|
469
|
+
} else {
|
|
470
|
+
// ComponentStatus.suspended requires GUARDIAN_ROLE
|
|
471
|
+
_access.checkRole(GUARDIAN_ROLE, _msgSender());
|
|
472
|
+
}
|
|
370
473
|
comp.status = newStatus;
|
|
371
474
|
emit ComponentStatusChanged(component, comp.kind, newStatus);
|
|
372
475
|
}
|
|
@@ -383,20 +486,18 @@ contract PolicyPool is IPolicyPool, PausableUpgradeable, UUPSUpgradeable, ERC721
|
|
|
383
486
|
|
|
384
487
|
function _componentStatus(address component, ComponentKind kind) internal view returns (ComponentStatus) {
|
|
385
488
|
Component storage comp = _components[IPolicyPoolComponent(component)];
|
|
386
|
-
|
|
489
|
+
if (comp.kind != kind) revert ComponentNotTheRightKind(IPolicyPoolComponent(component), kind);
|
|
387
490
|
return comp.status;
|
|
388
491
|
}
|
|
389
492
|
|
|
390
493
|
function _requireCompActive(address component, ComponentKind kind) internal view {
|
|
391
|
-
|
|
494
|
+
if (_componentStatus(component, kind) != ComponentStatus.active) revert ComponentNotFoundOrNotActive();
|
|
392
495
|
}
|
|
393
496
|
|
|
394
497
|
function _requireCompActiveOrDeprecated(address component, ComponentKind kind) internal view {
|
|
395
498
|
ComponentStatus status = _componentStatus(component, kind);
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
"Component must be active or deprecated"
|
|
399
|
-
);
|
|
499
|
+
if (status != ComponentStatus.active && status != ComponentStatus.deprecated)
|
|
500
|
+
revert ComponentMustBeActiveOrDeprecated();
|
|
400
501
|
}
|
|
401
502
|
|
|
402
503
|
function deposit(IEToken eToken, uint256 amount) external override whenNotPaused {
|
|
@@ -419,7 +520,7 @@ contract PolicyPool is IPolicyPool, PausableUpgradeable, UUPSUpgradeable, ERC721
|
|
|
419
520
|
) external override whenNotPaused returns (uint256) {
|
|
420
521
|
// Checks
|
|
421
522
|
IRiskModule rm = policy.riskModule;
|
|
422
|
-
|
|
523
|
+
if (address(rm) != _msgSender()) revert OnlyRiskModuleAllowed();
|
|
423
524
|
_requireCompActive(address(rm), ComponentKind.riskModule);
|
|
424
525
|
IPremiumsAccount pa = rm.premiumsAccount();
|
|
425
526
|
_requireCompActive(address(pa), ComponentKind.premiumsAccount);
|
|
@@ -459,7 +560,7 @@ contract PolicyPool is IPolicyPool, PausableUpgradeable, UUPSUpgradeable, ERC721
|
|
|
459
560
|
// Checks
|
|
460
561
|
_validatePolicy(oldPolicy);
|
|
461
562
|
IRiskModule rm = oldPolicy.riskModule;
|
|
462
|
-
|
|
563
|
+
if (address(rm) != _msgSender()) revert OnlyRiskModuleAllowed();
|
|
463
564
|
_requireCompActive(address(rm), ComponentKind.riskModule);
|
|
464
565
|
IPremiumsAccount pa = rm.premiumsAccount();
|
|
465
566
|
_requireCompActive(address(pa), ComponentKind.premiumsAccount);
|
|
@@ -509,6 +610,7 @@ contract PolicyPool is IPolicyPool, PausableUpgradeable, UUPSUpgradeable, ERC721
|
|
|
509
610
|
|
|
510
611
|
emit NewPolicy(rm, newPolicy_);
|
|
511
612
|
emit PolicyReplaced(rm, oldPolicy.id, newPolicy_.id);
|
|
613
|
+
_notifyReplacement(oldPolicy.id, newPolicy_.id);
|
|
512
614
|
return newPolicy_.id;
|
|
513
615
|
}
|
|
514
616
|
|
|
@@ -566,7 +668,7 @@ contract PolicyPool is IPolicyPool, PausableUpgradeable, UUPSUpgradeable, ERC721
|
|
|
566
668
|
// Checks
|
|
567
669
|
_validatePolicy(policy);
|
|
568
670
|
IRiskModule rm = policy.riskModule;
|
|
569
|
-
|
|
671
|
+
if (!expired && address(rm) != _msgSender()) revert OnlyRiskModuleAllowed();
|
|
570
672
|
require(payout == 0 || policy.expiration > block.timestamp, "Can't pay expired policy");
|
|
571
673
|
_requireCompActiveOrDeprecated(address(rm), ComponentKind.riskModule);
|
|
572
674
|
|
|
@@ -606,7 +708,7 @@ contract PolicyPool is IPolicyPool, PausableUpgradeable, UUPSUpgradeable, ERC721
|
|
|
606
708
|
if (!ERC165Checker.supportsInterface(customer, type(IPolicyHolder).interfaceId)) return;
|
|
607
709
|
|
|
608
710
|
bytes4 retval = IPolicyHolder(customer).onPayoutReceived(_msgSender(), address(this), policyId, payout);
|
|
609
|
-
|
|
711
|
+
if (retval != IPolicyHolder.onPayoutReceived.selector) revert InvalidNotificationResponse(retval);
|
|
610
712
|
}
|
|
611
713
|
|
|
612
714
|
/**
|
|
@@ -617,13 +719,29 @@ contract PolicyPool is IPolicyPool, PausableUpgradeable, UUPSUpgradeable, ERC721
|
|
|
617
719
|
if (!AddressUpgradeable.isContract(customer)) return;
|
|
618
720
|
if (!ERC165Checker.supportsInterface(customer, type(IPolicyHolder).interfaceId)) return;
|
|
619
721
|
|
|
620
|
-
try IPolicyHolder(customer).onPolicyExpired(_msgSender(), address(this), policyId) returns (
|
|
722
|
+
try IPolicyHolder(customer).onPolicyExpired{gas: HOLDER_GAS_LIMIT}(_msgSender(), address(this), policyId) returns (
|
|
723
|
+
bytes4
|
|
724
|
+
) {
|
|
621
725
|
return;
|
|
622
726
|
} catch {
|
|
727
|
+
emit ExpirationNotificationFailed(policyId, IPolicyHolder(customer));
|
|
623
728
|
return;
|
|
624
729
|
}
|
|
625
730
|
}
|
|
626
731
|
|
|
732
|
+
/**
|
|
733
|
+
* @dev Notifies the replacement with a callback if the policyholder is a contract. Never reverts.
|
|
734
|
+
*/
|
|
735
|
+
function _notifyReplacement(uint256 oldPolicyId, uint256 newPolicyId) internal {
|
|
736
|
+
address customer = ownerOf(oldPolicyId);
|
|
737
|
+
if (!AddressUpgradeable.isContract(customer)) return;
|
|
738
|
+
if (!ERC165Checker.supportsInterface(customer, type(IPolicyHolderV2).interfaceId)) return;
|
|
739
|
+
|
|
740
|
+
bytes4 retval = IPolicyHolderV2(customer).onPolicyReplaced(_msgSender(), address(this), oldPolicyId, newPolicyId);
|
|
741
|
+
// PolicyHolder can revert and cancel the policy replacement
|
|
742
|
+
if (retval != IPolicyHolderV2.onPolicyReplaced.selector) revert InvalidNotificationResponse(retval);
|
|
743
|
+
}
|
|
744
|
+
|
|
627
745
|
/**
|
|
628
746
|
* @dev Base URI for computing {tokenURI}. If set, the resulting URI for each
|
|
629
747
|
* token will be the concatenation of the `baseURI` and the `tokenId`. Empty
|
|
@@ -42,6 +42,9 @@ abstract contract PolicyPoolComponent is UUPSUpgradeable, PausableUpgradeable, I
|
|
|
42
42
|
event GovernanceAction(IAccessManager.GovernanceActions indexed action, uint256 value);
|
|
43
43
|
event ComponentChanged(IAccessManager.GovernanceActions indexed action, address value);
|
|
44
44
|
|
|
45
|
+
error NoZeroPolicyPool();
|
|
46
|
+
error UpgradeCannotChangePolicyPool();
|
|
47
|
+
|
|
45
48
|
modifier onlyPolicyPool() {
|
|
46
49
|
require(_msgSender() == address(_policyPool), "The caller must be the PolicyPool");
|
|
47
50
|
_;
|
|
@@ -76,7 +79,7 @@ abstract contract PolicyPoolComponent is UUPSUpgradeable, PausableUpgradeable, I
|
|
|
76
79
|
|
|
77
80
|
/// @custom:oz-upgrades-unsafe-allow constructor
|
|
78
81
|
constructor(IPolicyPool policyPool_) {
|
|
79
|
-
|
|
82
|
+
if (address(policyPool_) == address(0)) revert NoZeroPolicyPool();
|
|
80
83
|
_disableInitializers();
|
|
81
84
|
_policyPool = policyPool_;
|
|
82
85
|
}
|
|
@@ -94,7 +97,7 @@ abstract contract PolicyPoolComponent is UUPSUpgradeable, PausableUpgradeable, I
|
|
|
94
97
|
}
|
|
95
98
|
|
|
96
99
|
function _upgradeValidations(address newImpl) internal view virtual {
|
|
97
|
-
|
|
100
|
+
if (IPolicyPoolComponent(newImpl).policyPool() != _policyPool) revert UpgradeCannotChangePolicyPool();
|
|
98
101
|
}
|
|
99
102
|
|
|
100
103
|
/**
|
package/contracts/RiskModule.sol
CHANGED
|
@@ -56,12 +56,16 @@ abstract contract RiskModule is IRiskModule, PolicyPoolComponent {
|
|
|
56
56
|
|
|
57
57
|
address internal _wallet; // Address of the RiskModule provider
|
|
58
58
|
|
|
59
|
+
error NoZeroWallet();
|
|
60
|
+
error ExposureLimitCannotBeLessThanActiveExposure();
|
|
61
|
+
error PremiumsAccountMustBePartOfThePool();
|
|
62
|
+
error UpgradeCannotChangePremiumsAccount();
|
|
63
|
+
|
|
59
64
|
/// @custom:oz-upgrades-unsafe-allow constructor
|
|
60
65
|
constructor(IPolicyPool policyPool_, IPremiumsAccount premiumsAccount_) PolicyPoolComponent(policyPool_) {
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
);
|
|
66
|
+
if (PolicyPoolComponent(address(premiumsAccount_)).policyPool() != policyPool_) {
|
|
67
|
+
revert PremiumsAccountMustBePartOfThePool();
|
|
68
|
+
}
|
|
65
69
|
_premiumsAccount = premiumsAccount_;
|
|
66
70
|
}
|
|
67
71
|
|
|
@@ -120,7 +124,9 @@ abstract contract RiskModule is IRiskModule, PolicyPoolComponent {
|
|
|
120
124
|
function _upgradeValidations(address newImpl) internal view virtual override {
|
|
121
125
|
super._upgradeValidations(newImpl);
|
|
122
126
|
IRiskModule newRM = IRiskModule(newImpl);
|
|
123
|
-
|
|
127
|
+
if (newRM.premiumsAccount() != _premiumsAccount) {
|
|
128
|
+
revert UpgradeCannotChangePremiumsAccount();
|
|
129
|
+
}
|
|
124
130
|
}
|
|
125
131
|
|
|
126
132
|
/**
|
|
@@ -133,8 +139,12 @@ abstract contract RiskModule is IRiskModule, PolicyPoolComponent {
|
|
|
133
139
|
// runs validation on RiskModule parameters
|
|
134
140
|
function _validateParameters() internal view virtual override {
|
|
135
141
|
// _maxPayoutPerPolicy no limits
|
|
136
|
-
|
|
137
|
-
|
|
142
|
+
if (exposureLimit() < _activeExposure) {
|
|
143
|
+
revert ExposureLimitCannotBeLessThanActiveExposure();
|
|
144
|
+
}
|
|
145
|
+
if (_wallet == address(0)) {
|
|
146
|
+
revert NoZeroWallet();
|
|
147
|
+
}
|
|
138
148
|
_validatePackedParams(_params);
|
|
139
149
|
}
|
|
140
150
|
|
|
@@ -259,7 +269,9 @@ abstract contract RiskModule is IRiskModule, PolicyPoolComponent {
|
|
|
259
269
|
}
|
|
260
270
|
|
|
261
271
|
function setWallet(address wallet_) external onlyComponentRole(RM_PROVIDER_ROLE) {
|
|
262
|
-
|
|
272
|
+
if (wallet_ == address(0)) {
|
|
273
|
+
revert NoZeroWallet();
|
|
274
|
+
}
|
|
263
275
|
_wallet = wallet_;
|
|
264
276
|
_parameterChanged(IAccessManager.GovernanceActions.setWallet, uint256(uint160(wallet_)), false);
|
|
265
277
|
}
|
|
@@ -269,32 +281,17 @@ abstract contract RiskModule is IRiskModule, PolicyPoolComponent {
|
|
|
269
281
|
uint256 lossProb,
|
|
270
282
|
uint40 expiration
|
|
271
283
|
) public view virtual returns (uint256) {
|
|
272
|
-
return _getMinimumPremium(payout, lossProb, expiration, params());
|
|
284
|
+
return _getMinimumPremium(payout, lossProb, expiration, uint40(block.timestamp), params());
|
|
273
285
|
}
|
|
274
286
|
|
|
275
287
|
function _getMinimumPremium(
|
|
276
288
|
uint256 payout,
|
|
277
289
|
uint256 lossProb,
|
|
278
290
|
uint40 expiration,
|
|
291
|
+
uint40 start,
|
|
279
292
|
Params memory p
|
|
280
|
-
) internal
|
|
281
|
-
|
|
282
|
-
uint256 jrScr = payout.wadMul(p.jrCollRatio);
|
|
283
|
-
if (jrScr > purePremium) {
|
|
284
|
-
jrScr -= purePremium;
|
|
285
|
-
} else {
|
|
286
|
-
jrScr = 0;
|
|
287
|
-
}
|
|
288
|
-
uint256 srScr = payout.wadMul(p.collRatio);
|
|
289
|
-
if (srScr > (purePremium + jrScr)) {
|
|
290
|
-
srScr -= purePremium + jrScr;
|
|
291
|
-
} else {
|
|
292
|
-
srScr = 0;
|
|
293
|
-
}
|
|
294
|
-
uint256 jrCoc = jrScr.wadMul((p.jrRoc * (expiration - block.timestamp)).wadDiv(SECONDS_IN_YEAR_WAD));
|
|
295
|
-
uint256 srCoc = srScr.wadMul((p.srRoc * (expiration - block.timestamp)).wadDiv(SECONDS_IN_YEAR_WAD));
|
|
296
|
-
uint256 ensuroCommission = purePremium.wadMul(p.ensuroPpFee) + (jrCoc + srCoc).wadMul(p.ensuroCocFee);
|
|
297
|
-
return purePremium + ensuroCommission + (jrCoc + srCoc);
|
|
293
|
+
) internal pure returns (uint256) {
|
|
294
|
+
return Policy.getMinimumPremium(p, payout, lossProb, expiration, start).totalPremium;
|
|
298
295
|
}
|
|
299
296
|
|
|
300
297
|
/**
|
|
@@ -334,11 +331,11 @@ abstract contract RiskModule is IRiskModule, PolicyPoolComponent {
|
|
|
334
331
|
uint96 internalId,
|
|
335
332
|
Params memory params_
|
|
336
333
|
) internal returns (Policy.PolicyData memory policy) {
|
|
334
|
+
uint40 now_ = uint40(block.timestamp);
|
|
337
335
|
if (premium == type(uint256).max) {
|
|
338
|
-
premium = _getMinimumPremium(payout, lossProb, expiration, params_);
|
|
336
|
+
premium = _getMinimumPremium(payout, lossProb, expiration, now_, params_);
|
|
339
337
|
}
|
|
340
338
|
require(premium < payout, "Premium must be less than payout");
|
|
341
|
-
uint40 now_ = uint40(block.timestamp);
|
|
342
339
|
require(expiration > now_, "Expiration must be in the future");
|
|
343
340
|
require(((expiration - now_) / 3600) < _params.maxDuration, "Policy exceeds max duration");
|
|
344
341
|
require(onBehalfOf != address(0), "Customer can't be zero address");
|
|
@@ -381,7 +378,7 @@ abstract contract RiskModule is IRiskModule, PolicyPoolComponent {
|
|
|
381
378
|
Params memory params_
|
|
382
379
|
) internal virtual returns (Policy.PolicyData memory policy) {
|
|
383
380
|
if (premium == type(uint256).max) {
|
|
384
|
-
premium = _getMinimumPremium(payout, lossProb, expiration, params_);
|
|
381
|
+
premium = _getMinimumPremium(payout, lossProb, expiration, oldPolicy.start, params_);
|
|
385
382
|
}
|
|
386
383
|
require(premium < payout, "Premium must be less than payout");
|
|
387
384
|
require(oldPolicy.expiration > uint40(block.timestamp), "Old policy is expired");
|
|
@@ -2,15 +2,16 @@
|
|
|
2
2
|
pragma solidity ^0.8.0;
|
|
3
3
|
|
|
4
4
|
import {ECDSA} from "@openzeppelin/contracts/utils/cryptography/ECDSA.sol";
|
|
5
|
+
|
|
5
6
|
import {IPolicyPool} from "./interfaces/IPolicyPool.sol";
|
|
6
7
|
import {IPremiumsAccount} from "./interfaces/IPremiumsAccount.sol";
|
|
7
|
-
import {RiskModule} from "./RiskModule.sol";
|
|
8
8
|
import {Policy} from "./Policy.sol";
|
|
9
|
+
import {RiskModule} from "./RiskModule.sol";
|
|
9
10
|
|
|
10
11
|
/**
|
|
11
|
-
* @title
|
|
12
|
+
* @title SignedBucket Risk Module
|
|
12
13
|
* @dev Risk Module that for policy creation verifies the different components of the price have been signed by a
|
|
13
|
-
trusted account (PRICER_ROLE). One of the components of the price
|
|
14
|
+
trusted account (PRICER_ROLE). One of the components of the price is a bucket id that groups policies within
|
|
14
15
|
a risk module, with different parameters (such as collaterallization levels or fees).
|
|
15
16
|
For the resolution (resolvePolicy), it has to be called by an authorized user
|
|
16
17
|
* @custom:security-contact security@ensuro.co
|
|
@@ -18,12 +19,10 @@ import {Policy} from "./Policy.sol";
|
|
|
18
19
|
*/
|
|
19
20
|
contract SignedBucketRiskModule is RiskModule {
|
|
20
21
|
bytes32 public constant POLICY_CREATOR_ROLE = keccak256("POLICY_CREATOR_ROLE");
|
|
22
|
+
bytes32 public constant REPLACER_ROLE = keccak256("REPLACER_ROLE");
|
|
21
23
|
bytes32 public constant PRICER_ROLE = keccak256("PRICER_ROLE");
|
|
22
24
|
bytes32 public constant RESOLVER_ROLE = keccak256("RESOLVER_ROLE");
|
|
23
25
|
|
|
24
|
-
/// @custom:oz-upgrades-unsafe-allow state-variable-immutable
|
|
25
|
-
bool internal immutable _creationIsOpen;
|
|
26
|
-
|
|
27
26
|
mapping(uint256 => PackedParams) internal _buckets;
|
|
28
27
|
|
|
29
28
|
/**
|
|
@@ -47,14 +46,12 @@ contract SignedBucketRiskModule is RiskModule {
|
|
|
47
46
|
*/
|
|
48
47
|
event NewSignedPolicy(uint256 indexed policyId, bytes32 policyData);
|
|
49
48
|
|
|
49
|
+
error QuoteExpired();
|
|
50
|
+
error BucketCannotBeZero();
|
|
51
|
+
error BucketNotFound();
|
|
52
|
+
|
|
50
53
|
/// @custom:oz-upgrades-unsafe-allow constructor
|
|
51
|
-
constructor(
|
|
52
|
-
IPolicyPool policyPool_,
|
|
53
|
-
IPremiumsAccount premiumsAccount_,
|
|
54
|
-
bool creationIsOpen_
|
|
55
|
-
) RiskModule(policyPool_, premiumsAccount_) {
|
|
56
|
-
_creationIsOpen = creationIsOpen_;
|
|
57
|
-
}
|
|
54
|
+
constructor(IPolicyPool policyPool_, IPremiumsAccount premiumsAccount_) RiskModule(policyPool_, premiumsAccount_) {}
|
|
58
55
|
|
|
59
56
|
/**
|
|
60
57
|
* @dev Initializes the RiskModule
|
|
@@ -89,9 +86,7 @@ contract SignedBucketRiskModule is RiskModule {
|
|
|
89
86
|
bytes32 quoteSignatureVS,
|
|
90
87
|
uint40 quoteValidUntil
|
|
91
88
|
) internal view {
|
|
92
|
-
if (
|
|
93
|
-
_policyPool.access().checkComponentRole(address(this), POLICY_CREATOR_ROLE, _msgSender(), false);
|
|
94
|
-
require(quoteValidUntil >= block.timestamp, "Quote expired");
|
|
89
|
+
if (quoteValidUntil < block.timestamp) revert QuoteExpired();
|
|
95
90
|
|
|
96
91
|
/**
|
|
97
92
|
* Checks the quote has been signed by an authorized user
|
|
@@ -134,55 +129,6 @@ contract SignedBucketRiskModule is RiskModule {
|
|
|
134
129
|
return createdPolicy;
|
|
135
130
|
}
|
|
136
131
|
|
|
137
|
-
/**
|
|
138
|
-
* @dev Creates a new Policy using a signed quote. The caller is the payer of the policy. Returns all the struct, not just the id.
|
|
139
|
-
*
|
|
140
|
-
* Requirements:
|
|
141
|
-
* - The caller approved the spending of the premium to the PolicyPool
|
|
142
|
-
* - The quote has been signed by an address with the component role PRICER_ROLE
|
|
143
|
-
*
|
|
144
|
-
* Emits:
|
|
145
|
-
* - {PolicyPool.NewPolicy}
|
|
146
|
-
* - {NewSignedPolicy}
|
|
147
|
-
*
|
|
148
|
-
* @param payout The exposure (maximum payout) of the policy
|
|
149
|
-
* @param premium The premium that will be paid by the payer
|
|
150
|
-
* @param lossProb The probability of having to pay the maximum payout (wad)
|
|
151
|
-
* @param expiration The expiration of the policy (timestamp)
|
|
152
|
-
* @param onBehalfOf The policy holder
|
|
153
|
-
* @param policyData A hash of the private details of the policy. The last 96 bits will be used as internalId
|
|
154
|
-
* @param bucketId Identifies the group to which the policy belongs (that defines the RM parameters applicable to it)
|
|
155
|
-
* @param quoteSignatureR The signature of the quote. R component (EIP-2098 signature)
|
|
156
|
-
* @param quoteSignatureVS The signature of the quote. VS component (EIP-2098 signature)
|
|
157
|
-
* @param quoteValidUntil The expiration of the quote
|
|
158
|
-
* @return createdPolicy Returns the created policy
|
|
159
|
-
*/
|
|
160
|
-
function newPolicyFull(
|
|
161
|
-
uint256 payout,
|
|
162
|
-
uint256 premium,
|
|
163
|
-
uint256 lossProb,
|
|
164
|
-
uint40 expiration,
|
|
165
|
-
address onBehalfOf,
|
|
166
|
-
bytes32 policyData,
|
|
167
|
-
uint256 bucketId,
|
|
168
|
-
bytes32 quoteSignatureR,
|
|
169
|
-
bytes32 quoteSignatureVS,
|
|
170
|
-
uint40 quoteValidUntil
|
|
171
|
-
) external whenNotPaused returns (Policy.PolicyData memory createdPolicy) {
|
|
172
|
-
_checkSignature(
|
|
173
|
-
payout,
|
|
174
|
-
premium,
|
|
175
|
-
lossProb,
|
|
176
|
-
expiration,
|
|
177
|
-
policyData,
|
|
178
|
-
bucketId,
|
|
179
|
-
quoteSignatureR,
|
|
180
|
-
quoteSignatureVS,
|
|
181
|
-
quoteValidUntil
|
|
182
|
-
);
|
|
183
|
-
return _newPolicySigned(payout, premium, lossProb, expiration, policyData, bucketId, _msgSender(), onBehalfOf);
|
|
184
|
-
}
|
|
185
|
-
|
|
186
132
|
/**
|
|
187
133
|
* @dev Creates a new Policy using a signed quote. The caller is the payer of the policy.
|
|
188
134
|
*
|
|
@@ -217,7 +163,7 @@ contract SignedBucketRiskModule is RiskModule {
|
|
|
217
163
|
bytes32 quoteSignatureR,
|
|
218
164
|
bytes32 quoteSignatureVS,
|
|
219
165
|
uint40 quoteValidUntil
|
|
220
|
-
) external whenNotPaused returns (uint256) {
|
|
166
|
+
) external whenNotPaused onlyComponentRole(POLICY_CREATOR_ROLE) returns (uint256) {
|
|
221
167
|
_checkSignature(
|
|
222
168
|
payout,
|
|
223
169
|
premium,
|
|
@@ -233,21 +179,22 @@ contract SignedBucketRiskModule is RiskModule {
|
|
|
233
179
|
}
|
|
234
180
|
|
|
235
181
|
/**
|
|
236
|
-
* @dev
|
|
182
|
+
* @dev Replace a policy with a new one, reusing the premium and the capital locked
|
|
237
183
|
*
|
|
238
184
|
* Requirements:
|
|
239
|
-
* -
|
|
185
|
+
* - The caller approved the spending of the premium to the PolicyPool
|
|
240
186
|
* - The quote has been signed by an address with the component role PRICER_ROLE
|
|
187
|
+
* - The caller has been granted component role REPLACER_ROLE or creation is open
|
|
241
188
|
*
|
|
242
189
|
* Emits:
|
|
190
|
+
* - {PolicyPool.PolicyReplaced}
|
|
243
191
|
* - {PolicyPool.NewPolicy}
|
|
244
|
-
* - {NewSignedPolicy}
|
|
245
192
|
*
|
|
246
|
-
* @param
|
|
247
|
-
* @param
|
|
193
|
+
* @param oldPolicy The policy to be replaced
|
|
194
|
+
* @param payout The exposure (maximum payout) of the new policy
|
|
195
|
+
* @param premium The premium that will be paid by the caller
|
|
248
196
|
* @param lossProb The probability of having to pay the maximum payout (wad)
|
|
249
197
|
* @param expiration The expiration of the policy (timestamp)
|
|
250
|
-
* @param onBehalfOf The policy holder
|
|
251
198
|
* @param policyData A hash of the private details of the policy. The last 96 bits will be used as internalId
|
|
252
199
|
* @param bucketId Identifies the group to which the policy belongs (that defines the RM parameters applicable to it)
|
|
253
200
|
* @param quoteSignatureR The signature of the quote. R component (EIP-2098 signature)
|
|
@@ -255,32 +202,18 @@ contract SignedBucketRiskModule is RiskModule {
|
|
|
255
202
|
* @param quoteValidUntil The expiration of the quote
|
|
256
203
|
* @return Returns the id of the created policy
|
|
257
204
|
*/
|
|
258
|
-
function
|
|
205
|
+
function replacePolicy(
|
|
206
|
+
Policy.PolicyData calldata oldPolicy,
|
|
259
207
|
uint256 payout,
|
|
260
208
|
uint256 premium,
|
|
261
209
|
uint256 lossProb,
|
|
262
210
|
uint40 expiration,
|
|
263
|
-
address onBehalfOf,
|
|
264
211
|
bytes32 policyData,
|
|
265
212
|
uint256 bucketId,
|
|
266
213
|
bytes32 quoteSignatureR,
|
|
267
214
|
bytes32 quoteSignatureVS,
|
|
268
215
|
uint40 quoteValidUntil
|
|
269
|
-
) external whenNotPaused returns (uint256) {
|
|
270
|
-
require(
|
|
271
|
-
onBehalfOf == _msgSender() || currency().allowance(onBehalfOf, _msgSender()) > 0,
|
|
272
|
-
"Sender is not authorized to create policies onBehalfOf"
|
|
273
|
-
);
|
|
274
|
-
/**
|
|
275
|
-
* The standard is the payer should be the _msgSender() but usually, in this type of module,
|
|
276
|
-
* the sender is an operative account managed by software, where the onBehalfOf is a more
|
|
277
|
-
* secure account (hardware wallet) that does the cash movements.
|
|
278
|
-
* This non standard behaviour allows for a more secure setup, where the sender never manages
|
|
279
|
-
* cash.
|
|
280
|
-
* We leverage the currency's allowance mechanism to allow the sender access to the payer's
|
|
281
|
-
* funds.
|
|
282
|
-
* Note that this allowance won't be spent, so anything above 0 is accepted.
|
|
283
|
-
*/
|
|
216
|
+
) external whenNotPaused onlyComponentRole(REPLACER_ROLE) returns (uint256) {
|
|
284
217
|
_checkSignature(
|
|
285
218
|
payout,
|
|
286
219
|
premium,
|
|
@@ -292,7 +225,10 @@ contract SignedBucketRiskModule is RiskModule {
|
|
|
292
225
|
quoteSignatureVS,
|
|
293
226
|
quoteValidUntil
|
|
294
227
|
);
|
|
295
|
-
|
|
228
|
+
uint96 internalId = uint96(uint256(policyData) % 2 ** 96);
|
|
229
|
+
return
|
|
230
|
+
_replacePolicy(oldPolicy, payout, premium, lossProb, expiration, _msgSender(), internalId, bucketParams(bucketId))
|
|
231
|
+
.id;
|
|
296
232
|
}
|
|
297
233
|
|
|
298
234
|
function resolvePolicy(
|
|
@@ -316,7 +252,7 @@ contract SignedBucketRiskModule is RiskModule {
|
|
|
316
252
|
uint256 bucketId,
|
|
317
253
|
Params calldata params_
|
|
318
254
|
) external onlyGlobalOrComponentRole2(LEVEL1_ROLE, LEVEL2_ROLE) {
|
|
319
|
-
|
|
255
|
+
if (bucketId == 0) revert BucketCannotBeZero();
|
|
320
256
|
_buckets[bucketId] = PackedParams({
|
|
321
257
|
moc: _wadTo4(params_.moc),
|
|
322
258
|
jrCollRatio: _wadTo4(params_.jrCollRatio),
|
|
@@ -343,7 +279,8 @@ contract SignedBucketRiskModule is RiskModule {
|
|
|
343
279
|
* @param bucketId Group identifier for the policies that will have these parameters
|
|
344
280
|
*/
|
|
345
281
|
function deleteBucket(uint256 bucketId) external onlyGlobalOrComponentRole2(LEVEL1_ROLE, LEVEL2_ROLE) {
|
|
346
|
-
|
|
282
|
+
if (bucketId == 0) revert BucketCannotBeZero();
|
|
283
|
+
if (_buckets[bucketId].moc == 0) revert BucketNotFound();
|
|
347
284
|
delete _buckets[bucketId];
|
|
348
285
|
emit BucketDeleted(bucketId);
|
|
349
286
|
}
|
|
@@ -351,12 +288,12 @@ contract SignedBucketRiskModule is RiskModule {
|
|
|
351
288
|
/**
|
|
352
289
|
* @dev returns the risk bucket parameters for the given bucketId
|
|
353
290
|
*
|
|
354
|
-
* @param bucketId Id of the bucket
|
|
291
|
+
* @param bucketId Id of the bucket or 0 if you want the default params
|
|
355
292
|
*/
|
|
356
293
|
function bucketParams(uint256 bucketId) public view returns (Params memory params_) {
|
|
357
294
|
if (bucketId != 0) {
|
|
358
295
|
PackedParams storage bucketParams_ = _buckets[bucketId];
|
|
359
|
-
|
|
296
|
+
if (bucketParams_.moc == 0) revert BucketNotFound();
|
|
360
297
|
params_ = _unpackParams(bucketParams_);
|
|
361
298
|
} else {
|
|
362
299
|
params_ = params();
|
|
@@ -377,7 +314,7 @@ contract SignedBucketRiskModule is RiskModule {
|
|
|
377
314
|
uint40 expiration,
|
|
378
315
|
uint256 bucketId
|
|
379
316
|
) public view virtual returns (uint256) {
|
|
380
|
-
return _getMinimumPremium(payout, lossProb, expiration, bucketParams(bucketId));
|
|
317
|
+
return _getMinimumPremium(payout, lossProb, expiration, uint40(block.timestamp), bucketParams(bucketId));
|
|
381
318
|
}
|
|
382
319
|
|
|
383
320
|
/**
|
|
@@ -30,6 +30,8 @@ contract SignedQuoteRiskModule is RiskModule {
|
|
|
30
30
|
*/
|
|
31
31
|
event NewSignedPolicy(uint256 indexed policyId, bytes32 policyData);
|
|
32
32
|
|
|
33
|
+
error QuoteExpired();
|
|
34
|
+
|
|
33
35
|
/// @custom:oz-upgrades-unsafe-allow constructor
|
|
34
36
|
constructor(
|
|
35
37
|
IPolicyPool policyPool_,
|
|
@@ -75,7 +77,7 @@ contract SignedQuoteRiskModule is RiskModule {
|
|
|
75
77
|
) internal returns (Policy.PolicyData memory createdPolicy) {
|
|
76
78
|
if (!_creationIsOpen)
|
|
77
79
|
_policyPool.access().checkComponentRole(address(this), POLICY_CREATOR_ROLE, _msgSender(), false);
|
|
78
|
-
|
|
80
|
+
if (quoteValidUntil < block.timestamp) revert QuoteExpired();
|
|
79
81
|
|
|
80
82
|
/**
|
|
81
83
|
* Checks the quote has been signed by an authorized user
|
|
@@ -16,7 +16,7 @@ interface IPolicyHolder is IERC721Receiver {
|
|
|
16
16
|
* No mather what's the return value or even if this function reverts, this function will not revert the policy
|
|
17
17
|
* expiration.
|
|
18
18
|
*
|
|
19
|
-
* The selector can be obtained in Solidity with `
|
|
19
|
+
* The selector can be obtained in Solidity with `IPolicyHolder.onPolicyExpired.selector`.
|
|
20
20
|
*/
|
|
21
21
|
function onPolicyExpired(address operator, address from, uint256 policyId) external returns (bytes4);
|
|
22
22
|
|
|
@@ -27,7 +27,7 @@ interface IPolicyHolder is IERC721Receiver {
|
|
|
27
27
|
* If interface is not implemented by the recipient, it will be ignored and the payout will be successful.
|
|
28
28
|
* If any other value is returned or it reverts, the policy resolution / payout will be reverted.
|
|
29
29
|
*
|
|
30
|
-
* The selector can be obtained in Solidity with `
|
|
30
|
+
* The selector can be obtained in Solidity with `IPolicyHolder.onPayoutReceived.selector`.
|
|
31
31
|
*/
|
|
32
32
|
function onPayoutReceived(address operator, address from, uint256 policyId, uint256 amount) external returns (bytes4);
|
|
33
33
|
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
2
|
+
pragma solidity ^0.8.0;
|
|
3
|
+
|
|
4
|
+
import {IPolicyHolder} from "./IPolicyHolder.sol";
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* @title Policy holder interface - V2 of the interface that adds onPolicyReplaced endpoint
|
|
8
|
+
* @dev Interface for any contract that wants to be a holder of Ensuro Policies and receive notification of payouts and
|
|
9
|
+
* replacements.
|
|
10
|
+
*
|
|
11
|
+
* Implementors of this interface MUST return true on supportsInterface for both IPolicyHolder and IPolicyHolderV2.
|
|
12
|
+
*/
|
|
13
|
+
interface IPolicyHolderV2 is IPolicyHolder {
|
|
14
|
+
/**
|
|
15
|
+
* @dev Whenever a policy is replaced, this function is called
|
|
16
|
+
*
|
|
17
|
+
* It must return its Solidity selector to confirm the payout.
|
|
18
|
+
* If interface is not implemented by the recipient, it will be ignored and the replacement will be successful.
|
|
19
|
+
* If any other value is returned or it reverts, the policy replacement will be reverted.
|
|
20
|
+
*
|
|
21
|
+
* The selector can be obtained in Solidity with `IPolicyHolderV2.onPolicyReplaced.selector`.
|
|
22
|
+
*/
|
|
23
|
+
function onPolicyReplaced(
|
|
24
|
+
address operator,
|
|
25
|
+
address from,
|
|
26
|
+
uint256 oldPolicyId,
|
|
27
|
+
uint256 newPolicyId
|
|
28
|
+
) external returns (bytes4);
|
|
29
|
+
}
|
|
@@ -2,22 +2,29 @@
|
|
|
2
2
|
pragma solidity ^0.8.0;
|
|
3
3
|
|
|
4
4
|
import {IPolicyHolder} from "../interfaces/IPolicyHolder.sol";
|
|
5
|
+
import {IPolicyHolderV2} from "../interfaces/IPolicyHolderV2.sol";
|
|
5
6
|
import {IERC721Receiver} from "@openzeppelin/contracts/token/ERC721/IERC721Receiver.sol";
|
|
6
7
|
import {IERC165} from "@openzeppelin/contracts/utils/introspection/IERC165.sol";
|
|
8
|
+
import {StorageSlot} from "@openzeppelin/contracts/utils/StorageSlot.sol";
|
|
7
9
|
|
|
8
|
-
contract PolicyHolderMock is
|
|
10
|
+
contract PolicyHolderMock is IPolicyHolderV2 {
|
|
9
11
|
uint256 public policyId;
|
|
10
12
|
uint256 public payout;
|
|
11
13
|
bool public fail;
|
|
14
|
+
bool public failReplace;
|
|
12
15
|
bool public emptyRevert;
|
|
13
16
|
bool public notImplemented;
|
|
14
17
|
bool public badlyImplemented;
|
|
18
|
+
bool public badlyImplementedReplace;
|
|
15
19
|
bool public noERC165;
|
|
20
|
+
bool public noV2;
|
|
21
|
+
uint256 public spendGasCount;
|
|
16
22
|
|
|
17
23
|
enum NotificationKind {
|
|
18
24
|
PolicyReceived,
|
|
19
25
|
PayoutReceived,
|
|
20
|
-
PolicyExpired
|
|
26
|
+
PolicyExpired,
|
|
27
|
+
PolicyReplaced
|
|
21
28
|
}
|
|
22
29
|
|
|
23
30
|
event NotificationReceived(NotificationKind kind, uint256 policyId, address operator, address from);
|
|
@@ -29,12 +36,21 @@ contract PolicyHolderMock is IPolicyHolder {
|
|
|
29
36
|
emptyRevert = false;
|
|
30
37
|
noERC165 = false;
|
|
31
38
|
payout = type(uint256).max;
|
|
39
|
+
spendGasCount = 0;
|
|
32
40
|
}
|
|
33
41
|
|
|
34
42
|
function setFail(bool fail_) external {
|
|
35
43
|
fail = fail_;
|
|
36
44
|
}
|
|
37
45
|
|
|
46
|
+
function setFailReplace(bool failReplace_) external {
|
|
47
|
+
failReplace = failReplace_;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
function setSpendGasCount(uint256 spendGasCount_) external {
|
|
51
|
+
spendGasCount = spendGasCount_;
|
|
52
|
+
}
|
|
53
|
+
|
|
38
54
|
function setNotImplemented(bool notImplemented_) external {
|
|
39
55
|
notImplemented = notImplemented_;
|
|
40
56
|
}
|
|
@@ -43,6 +59,14 @@ contract PolicyHolderMock is IPolicyHolder {
|
|
|
43
59
|
badlyImplemented = badlyImplemented_;
|
|
44
60
|
}
|
|
45
61
|
|
|
62
|
+
function setBadlyImplementedReplace(bool badlyImplementedReplace_) external {
|
|
63
|
+
badlyImplementedReplace = badlyImplementedReplace_;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
function setNoV2(bool noV2_) external {
|
|
67
|
+
noV2 = noV2_;
|
|
68
|
+
}
|
|
69
|
+
|
|
46
70
|
function setNoERC165(bool noERC165_) external {
|
|
47
71
|
noERC165 = noERC165_;
|
|
48
72
|
}
|
|
@@ -51,6 +75,13 @@ contract PolicyHolderMock is IPolicyHolder {
|
|
|
51
75
|
emptyRevert = emptyRevert_;
|
|
52
76
|
}
|
|
53
77
|
|
|
78
|
+
function spendGas() internal {
|
|
79
|
+
// Spends gas doing storage writes
|
|
80
|
+
for (uint256 i = 0; i < spendGasCount; i++) {
|
|
81
|
+
StorageSlot.getUint256Slot(bytes32(100 + i)).value = i + 1;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
54
85
|
/**
|
|
55
86
|
* @dev See {IERC165-supportsInterface}.
|
|
56
87
|
*/
|
|
@@ -60,7 +91,10 @@ contract PolicyHolderMock is IPolicyHolder {
|
|
|
60
91
|
revert(0, 0)
|
|
61
92
|
}
|
|
62
93
|
if (notImplemented) return false;
|
|
63
|
-
return
|
|
94
|
+
return
|
|
95
|
+
interfaceId == type(IPolicyHolder).interfaceId ||
|
|
96
|
+
(!noV2 && interfaceId == type(IPolicyHolderV2).interfaceId) ||
|
|
97
|
+
interfaceId == type(IERC165).interfaceId;
|
|
64
98
|
}
|
|
65
99
|
|
|
66
100
|
function onERC721Received(
|
|
@@ -82,6 +116,8 @@ contract PolicyHolderMock is IPolicyHolder {
|
|
|
82
116
|
|
|
83
117
|
if (badlyImplemented) return bytes4(0x0badf00d);
|
|
84
118
|
|
|
119
|
+
spendGas();
|
|
120
|
+
|
|
85
121
|
return IERC721Receiver.onERC721Received.selector;
|
|
86
122
|
}
|
|
87
123
|
|
|
@@ -98,17 +134,13 @@ contract PolicyHolderMock is IPolicyHolder {
|
|
|
98
134
|
|
|
99
135
|
if (badlyImplemented) return bytes4(0x0badf00d);
|
|
100
136
|
|
|
137
|
+
spendGas();
|
|
138
|
+
|
|
101
139
|
return IPolicyHolder.onPolicyExpired.selector;
|
|
102
140
|
}
|
|
103
141
|
|
|
104
142
|
/**
|
|
105
|
-
* @dev
|
|
106
|
-
*
|
|
107
|
-
* It must return its Solidity selector to confirm the payout.
|
|
108
|
-
* If interface is not implemented by the recipient, it will be ignored and the payout will be successful.
|
|
109
|
-
* If any other value is returned or it reverts, the policy resolution / payout will be reverted.
|
|
110
|
-
*
|
|
111
|
-
* The selector can be obtained in Solidity with `IPolicyPool.onPayoutReceived.selector`.
|
|
143
|
+
* @dev See {IPolicyHolderV2-onPayoutReceived}.
|
|
112
144
|
*/
|
|
113
145
|
function onPayoutReceived(
|
|
114
146
|
address operator,
|
|
@@ -128,6 +160,35 @@ contract PolicyHolderMock is IPolicyHolder {
|
|
|
128
160
|
|
|
129
161
|
if (badlyImplemented) return bytes4(0x0badf00d);
|
|
130
162
|
|
|
163
|
+
spendGas();
|
|
164
|
+
|
|
131
165
|
return IPolicyHolder.onPayoutReceived.selector;
|
|
132
166
|
}
|
|
167
|
+
|
|
168
|
+
/**
|
|
169
|
+
* @dev See {IPolicyHolderV2-onPolicyReplaced}.
|
|
170
|
+
*/
|
|
171
|
+
function onPolicyReplaced(
|
|
172
|
+
address operator,
|
|
173
|
+
address from,
|
|
174
|
+
uint256 oldPolicyId,
|
|
175
|
+
uint256 newPolicyId
|
|
176
|
+
) external override returns (bytes4) {
|
|
177
|
+
if (noV2) revert("Shouldn't call this method if V2 not enabled");
|
|
178
|
+
if (failReplace)
|
|
179
|
+
if (emptyRevert)
|
|
180
|
+
assembly {
|
|
181
|
+
revert(0, 0)
|
|
182
|
+
}
|
|
183
|
+
else revert("onPolicyReplaced: They told me I have to fail");
|
|
184
|
+
policyId = oldPolicyId;
|
|
185
|
+
payout = newPolicyId;
|
|
186
|
+
emit NotificationReceived(NotificationKind.PolicyReplaced, oldPolicyId, operator, from);
|
|
187
|
+
|
|
188
|
+
if (badlyImplementedReplace) return bytes4(0x0badf00d);
|
|
189
|
+
|
|
190
|
+
spendGas();
|
|
191
|
+
|
|
192
|
+
return IPolicyHolderV2.onPolicyReplaced.selector;
|
|
193
|
+
}
|
|
133
194
|
}
|
package/js/utils.js
CHANGED
|
@@ -144,22 +144,27 @@ async function grantRole(hre, contract, role, user, txOverrides = {}, log = () =
|
|
|
144
144
|
* @param {Interface} interface The interface of the contract that contains the requested event
|
|
145
145
|
* @param {TransactionReceipt} receipt Transaction receipt containing the events in the logs
|
|
146
146
|
* @param {String} eventName The name of the event we are interested in
|
|
147
|
+
* @param {Boolean} firstOnly If false, returns all the events matching the name
|
|
148
|
+
* @param {String} contractAddress If not null, if returns only those events generated by the specified contract
|
|
147
149
|
* @returns {LogDescription}
|
|
148
150
|
*/
|
|
149
|
-
function getTransactionEvent(interface, receipt, eventName) {
|
|
151
|
+
function getTransactionEvent(interface, receipt, eventName, firstOnly = true, contractAddress = null) {
|
|
152
|
+
const ret = [];
|
|
150
153
|
// for each log in the transaction receipt
|
|
151
154
|
for (const log of receipt.logs) {
|
|
152
155
|
let parsedLog;
|
|
156
|
+
if (contractAddress !== null && contractAddress !== log.address) continue;
|
|
153
157
|
try {
|
|
154
158
|
parsedLog = interface.parseLog(log);
|
|
155
159
|
} catch (error) {
|
|
156
160
|
continue;
|
|
157
161
|
}
|
|
158
162
|
if (parsedLog?.name == eventName) {
|
|
159
|
-
return parsedLog;
|
|
163
|
+
if (firstOnly) return parsedLog;
|
|
164
|
+
ret.push(parsedLog);
|
|
160
165
|
}
|
|
161
166
|
}
|
|
162
|
-
return null
|
|
167
|
+
return firstOnly ? null : ret;
|
|
163
168
|
}
|
|
164
169
|
|
|
165
170
|
/**
|
|
@@ -246,7 +251,7 @@ async function defaultPolicyParams(
|
|
|
246
251
|
_A = amountFunction(6)
|
|
247
252
|
) {
|
|
248
253
|
const now = await helpers.time.latest();
|
|
249
|
-
const rmAddress = rm ?
|
|
254
|
+
const rmAddress = rm ? getAddress(rm) : null;
|
|
250
255
|
return {
|
|
251
256
|
rmAddress,
|
|
252
257
|
payout: payout || _A(1000),
|
package/package.json
CHANGED
|
@@ -1,159 +0,0 @@
|
|
|
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(
|
|
66
|
-
uint256 lossProb,
|
|
67
|
-
Params calldata params_
|
|
68
|
-
) external onlyGlobalOrComponentRole2(LEVEL1_ROLE, LEVEL2_ROLE) {
|
|
69
|
-
uint256 newBucket = 0;
|
|
70
|
-
if (_buckets.lossProbs[0] != 0) {
|
|
71
|
-
// solhint-disable-next-line no-empty-blocks
|
|
72
|
-
for (newBucket = 1; newBucket < MAX_BUCKETS && _buckets.lossProbs[newBucket] != 0; newBucket++) {}
|
|
73
|
-
require(newBucket < MAX_BUCKETS, "No more than 4 buckets accepted");
|
|
74
|
-
require(lossProb > uint256(_buckets.lossProbs[newBucket - 1]), "lossProb <= last lossProb - reset instead");
|
|
75
|
-
}
|
|
76
|
-
_buckets.lossProbs[newBucket] = lossProb.toUint64();
|
|
77
|
-
_bucketParams[newBucket] = PackedParams({
|
|
78
|
-
moc: _wadTo4(params_.moc),
|
|
79
|
-
jrCollRatio: _wadTo4(params_.jrCollRatio),
|
|
80
|
-
collRatio: _wadTo4(params_.collRatio),
|
|
81
|
-
ensuroPpFee: _wadTo4(params_.ensuroPpFee),
|
|
82
|
-
ensuroCocFee: _wadTo4(params_.ensuroCocFee),
|
|
83
|
-
jrRoc: _wadTo4(params_.jrRoc),
|
|
84
|
-
srRoc: _wadTo4(params_.srRoc),
|
|
85
|
-
maxPayoutPerPolicy: type(uint32).max, // unused, but needs to be > 0
|
|
86
|
-
exposureLimit: type(uint32).max, //unused, but needs to be > 0
|
|
87
|
-
maxDuration: type(uint16).max //unused
|
|
88
|
-
});
|
|
89
|
-
if (newBucket < MAX_BUCKETS - 1) {
|
|
90
|
-
_buckets.lossProbs[newBucket + 1] = 0;
|
|
91
|
-
}
|
|
92
|
-
_validatePackedParams(_bucketParams[newBucket]);
|
|
93
|
-
emit NewBucket(lossProb, params_);
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
function resetBuckets() external onlyGlobalOrComponentRole2(LEVEL1_ROLE, LEVEL2_ROLE) {
|
|
97
|
-
_buckets.lossProbs[0] = 0;
|
|
98
|
-
emit BucketsReset();
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
/**
|
|
102
|
-
* @dev returns the risk bucket parameters for the given loss probability
|
|
103
|
-
*/
|
|
104
|
-
function bucketParams(uint256 lossProb) public view returns (Params memory) {
|
|
105
|
-
for (uint256 i = 0; i < MAX_BUCKETS && _buckets.lossProbs[i] != 0; i++) {
|
|
106
|
-
if (lossProb <= _buckets.lossProbs[i]) {
|
|
107
|
-
return _unpackParams(_bucketParams[i]);
|
|
108
|
-
}
|
|
109
|
-
}
|
|
110
|
-
return this.params();
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
function _newPolicy(
|
|
114
|
-
uint256 payout,
|
|
115
|
-
uint256 premium,
|
|
116
|
-
uint256 lossProb,
|
|
117
|
-
uint40 expiration,
|
|
118
|
-
address payer,
|
|
119
|
-
address onBehalfOf,
|
|
120
|
-
uint96 internalId
|
|
121
|
-
) internal override whenNotPaused returns (Policy.PolicyData memory) {
|
|
122
|
-
return
|
|
123
|
-
_newPolicyWithParams(
|
|
124
|
-
payout,
|
|
125
|
-
premium,
|
|
126
|
-
lossProb,
|
|
127
|
-
expiration,
|
|
128
|
-
payer,
|
|
129
|
-
onBehalfOf,
|
|
130
|
-
internalId,
|
|
131
|
-
bucketParams(lossProb)
|
|
132
|
-
);
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
function getMinimumPremium(
|
|
136
|
-
uint256 payout,
|
|
137
|
-
uint256 lossProb,
|
|
138
|
-
uint40 expiration
|
|
139
|
-
) public view virtual override returns (uint256) {
|
|
140
|
-
return _getMinimumPremium(payout, lossProb, expiration, bucketParams(lossProb));
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
/**
|
|
144
|
-
* @dev returns the current risk bucket limits
|
|
145
|
-
*/
|
|
146
|
-
function buckets() external view returns (uint256[MAX_BUCKETS] memory result) {
|
|
147
|
-
for (uint256 i = 0; i < MAX_BUCKETS && _buckets.lossProbs[i] > 0; i++) {
|
|
148
|
-
result[i] = _buckets.lossProbs[i];
|
|
149
|
-
}
|
|
150
|
-
return result;
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
/**
|
|
154
|
-
* @dev This empty reserved space is put in place to allow future versions to add new
|
|
155
|
-
* variables without shifting down storage in the inheritance chain.
|
|
156
|
-
* See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
|
|
157
|
-
*/
|
|
158
|
-
uint256[45] private __gap;
|
|
159
|
-
}
|