@ensuro/core 2.8.0 → 2.8.2

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 (52) hide show
  1. package/build/contracts/AccessManager.sol/AccessManager.json +618 -0
  2. package/build/contracts/ERC4626AssetManager.sol/ERC4626AssetManager.json +238 -0
  3. package/build/contracts/EToken.sol/EToken.json +1287 -0
  4. package/build/contracts/LPManualWhitelist.sol/LPManualWhitelist.json +657 -0
  5. package/build/contracts/LiquidityThresholdAssetManager.sol/LiquidityThresholdAssetManager.json +222 -0
  6. package/build/contracts/Policy.sol/Policy.json +10 -0
  7. package/build/contracts/PolicyPool.sol/PolicyPool.json +1775 -0
  8. package/build/contracts/PolicyPoolComponent.sol/PolicyPoolComponent.json +342 -0
  9. package/build/contracts/PremiumsAccount.sol/PremiumsAccount.json +1142 -0
  10. package/build/contracts/Reserve.sol/Reserve.json +413 -0
  11. package/build/contracts/RiskModule.sol/RiskModule.json +589 -0
  12. package/build/contracts/SignedBucketRiskModule.sol/SignedBucketRiskModule.json +1251 -0
  13. package/build/contracts/SignedQuoteRiskModule.sol/SignedQuoteRiskModule.json +1145 -0
  14. package/build/contracts/TimeScaled.sol/TimeScaled.json +10 -0
  15. package/build/contracts/TrustfulRiskModule.sol/TrustfulRiskModule.json +1143 -0
  16. package/build/contracts/dependencies/WadRayMath.sol/WadRayMath.json +10 -0
  17. package/build/contracts/interfaces/IAccessManager.sol/IAccessManager.json +343 -0
  18. package/build/contracts/interfaces/IAssetManager.sol/IAssetManager.json +128 -0
  19. package/build/contracts/interfaces/IEToken.sol/IEToken.json +460 -0
  20. package/build/contracts/interfaces/ILPWhitelist.sol/ILPWhitelist.json +103 -0
  21. package/build/contracts/interfaces/IPolicyHolder.sol/IPolicyHolder.json +108 -0
  22. package/build/contracts/interfaces/IPolicyHolderV2.sol/IPolicyHolderV2.json +142 -0
  23. package/build/contracts/interfaces/IPolicyPool.sol/IPolicyPool.json +820 -0
  24. package/build/contracts/interfaces/IPolicyPoolComponent.sol/IPolicyPoolComponent.json +43 -0
  25. package/build/contracts/interfaces/IPremiumsAccount.sol/IPremiumsAccount.json +477 -0
  26. package/build/contracts/interfaces/IRiskModule.sol/IRiskModule.json +165 -0
  27. package/build/contracts/migration/LPManualWhitelistV20.sol/LPManualWhitelistV20.json +491 -0
  28. package/build/contracts/migration/LPManualWhitelistV20Upgraded.sol/LPManualWhitelistV20Upgraded.json +502 -0
  29. package/build/contracts/mocks/FixedRateVault.sol/FixedRateVault.json +736 -0
  30. package/build/contracts/mocks/ForwardProxy.sol/ForwardProxy.json +43 -0
  31. package/build/contracts/mocks/IMintableERC20.sol/IMintableERC20.json +47 -0
  32. package/build/contracts/mocks/InterfaceIdCalculator.sol/InterfaceIdCalculator.json +193 -0
  33. package/build/contracts/mocks/PolicyHolderMock.sol/PolicyHolderMock.json +457 -0
  34. package/build/contracts/mocks/PolicyPoolComponentMock.sol/PolicyPoolComponentMock.json +54 -0
  35. package/build/contracts/mocks/PolicyPoolMock.sol/PolicyPoolMock.json +929 -0
  36. package/build/contracts/mocks/PolicyPoolMock.sol/PolicyPoolMockForward.json +92 -0
  37. package/build/contracts/mocks/RiskModuleMock.sol/RiskModuleMock.json +1316 -0
  38. package/build/contracts/mocks/TestCurrency.sol/TestCurrency.json +343 -0
  39. package/build/contracts/mocks/TestNFT.sol/TestNFT.json +388 -0
  40. package/contracts/Policy.sol +58 -21
  41. package/contracts/PolicyPool.sol +155 -37
  42. package/contracts/PolicyPoolComponent.sol +5 -2
  43. package/contracts/RiskModule.sol +27 -30
  44. package/contracts/SignedBucketRiskModule.sol +32 -95
  45. package/contracts/SignedQuoteRiskModule.sol +3 -1
  46. package/contracts/interfaces/IPolicyHolder.sol +2 -2
  47. package/contracts/interfaces/IPolicyHolderV2.sol +29 -0
  48. package/contracts/mocks/PolicyHolderMock.sol +71 -10
  49. package/js/deploy.js +6 -25
  50. package/js/utils.js +9 -4
  51. package/package.json +3 -5
  52. package/contracts/TieredSignedQuoteRiskModule.sol +0 -159
@@ -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 SignedQuote Risk Module
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 it's a bucket id that groups policies within
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 (!_creationIsOpen)
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 Creates a new Policy using a signed quote. The payer is the policy holder
182
+ * @dev Replace a policy with a new one, reusing the premium and the capital locked
237
183
  *
238
184
  * Requirements:
239
- * - currency().allowance(onBehalfOf, _msgSender()) > 0
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 payout The exposure (maximum payout) of the policy
247
- * @param premium The premium that will be paid by the payer
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 newPolicyPaidByHolder(
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
- return _newPolicySigned(payout, premium, lossProb, expiration, policyData, bucketId, onBehalfOf, onBehalfOf).id;
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
- require(bucketId != 0, "SignedBucketRiskModule: bucketId can't be zero, set default RM parameters");
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
- require(bucketId != 0, "SignedBucketRiskModule: bucketId can't be zero, set default RM parameters");
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 of 0 if you want the default params
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
- require(bucketParams_.moc != 0, "SignedBucketRiskModule: bucket not found!");
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
- require(quoteValidUntil >= block.timestamp, "Quote expired");
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 `IPolicyPool.onPolicyExpired.selector`.
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 `IPolicyPool.onPayoutReceived.selector`.
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 IPolicyHolder {
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 interfaceId == type(IPolicyHolder).interfaceId || interfaceId == type(IERC165).interfaceId;
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 Whenever an Policy is resolved with payout > 0, this function is called
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/deploy.js CHANGED
@@ -1,4 +1,3 @@
1
- const upgrades_core = require("@openzeppelin/upgrades-core");
2
1
  const helpers = require("@nomicfoundation/hardhat-network-helpers");
3
2
  const fs = require("fs");
4
3
  const ethers = require("ethers");
@@ -75,16 +74,12 @@ async function logContractCreated(hre, contractName, address) {
75
74
  }
76
75
 
77
76
  async function verifyContract(hre, contract, isProxy, constructorArguments) {
78
- if (isProxy === undefined) isProxy = false;
79
- if (constructorArguments === undefined) constructorArguments = [];
80
- const contractAddr = await ethers.resolveAddress(contract);
81
- const address = isProxy
82
- ? await upgrades_core.getImplementationAddress(hre.network.provider, contractAddr)
83
- : contractAddr;
77
+ constructorArguments = constructorArguments || [];
78
+ const address = await ethers.resolveAddress(contract);
84
79
  try {
85
80
  await hre.run("verify:verify", {
86
- address: address,
87
- constructorArguments: constructorArguments,
81
+ address,
82
+ constructorArguments,
88
83
  });
89
84
  } catch (error) {
90
85
  console.log("Error verifying contract implementation: ", error);
@@ -95,18 +90,6 @@ async function verifyContract(hre, contract, isProxy, constructorArguments) {
95
90
  .join(" ")}`
96
91
  );
97
92
  }
98
- try {
99
- if (isProxy) {
100
- await hre.run("verify:verify", {
101
- address: contractAddr,
102
- constructorArguments: constructorArguments,
103
- });
104
- }
105
- } catch (error) {
106
- console.log("Error verifying contract proxy: ", error);
107
- const endpoints = await hre.run("verify:get-etherscan-endpoint");
108
- console.log(`You should do it manually at ${endpoints.urls.browserURL}/proxyContractChecker?a=${contractAddr}`);
109
- }
110
93
  }
111
94
 
112
95
  async function deployContract({ saveAddr, verify, contractClass, constructorArgs }, hre) {
@@ -114,8 +97,7 @@ async function deployContract({ saveAddr, verify, contractClass, constructorArgs
114
97
  const contract = await ContractFactory.deploy(...constructorArgs, txOverrides());
115
98
  const contractAddr = await ethers.resolveAddress(contract);
116
99
  if (verify) {
117
- // From https://ethereum.stackexchange.com/a/119622/79726
118
- await contract.deployTransaction.wait(6);
100
+ await contract.deploymentTransaction().wait(6);
119
101
  } else {
120
102
  await contract.waitForDeployment();
121
103
  }
@@ -138,8 +120,7 @@ async function deployProxyContract(
138
120
  });
139
121
  const contractAddr = await ethers.resolveAddress(contract);
140
122
  if (verify) {
141
- // From https://ethereum.stackexchange.com/a/119622/79726
142
- await contract.deployTransaction.wait(6);
123
+ await contract.deploymentTransaction().wait(6);
143
124
  } else {
144
125
  await contract.waitForDeployment();
145
126
  }
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; // not found
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 ? await ethers.resolveAddress(rm) : 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,14 +1,12 @@
1
1
  {
2
2
  "name": "@ensuro/core",
3
3
  "description": "Ensuro - Decentralized insurance protocol",
4
- "version": "2.8.0",
4
+ "version": "2.8.2",
5
5
  "files": [
6
6
  "**/*.sol",
7
- "/build/contracts/*.json",
8
- "/build/interfaces/*.json",
7
+ "/build",
9
8
  "/js/*.js",
10
- "/scripts/*.sh",
11
- "/scripts/*.js"
9
+ "/scripts"
12
10
  ],
13
11
  "repository": {
14
12
  "type": "git",