@ensuro/core 2.5.0 → 2.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/build/contracts/SignedBucketRiskModule.sol/SignedBucketRiskModule.json +1262 -0
- package/build/contracts/SignedQuoteRiskModule.sol/SignedQuoteRiskModule.json +2 -2
- package/build/contracts/TieredSignedQuoteRiskModule.sol/TieredSignedQuoteRiskModule.json +2 -2
- package/build/contracts/TrustfulRiskModule.sol/TrustfulRiskModule.json +2 -2
- package/build/contracts/mocks/RiskModuleMock.sol/RiskModuleMock.json +2 -2
- package/contracts/RiskModule.sol +1 -1
- package/contracts/SignedBucketRiskModule.sol +451 -0
- package/js/constants.js +7 -0
- package/js/deploy.js +10 -93
- package/js/enums.js +30 -0
- package/js/test-utils.js +12 -241
- package/js/utils.js +264 -0
- package/package.json +1 -1
- package/scripts/storageLayout.js +3 -6
|
@@ -0,0 +1,451 @@
|
|
|
1
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
2
|
+
pragma solidity ^0.8.0;
|
|
3
|
+
|
|
4
|
+
import {ECDSA} from "@openzeppelin/contracts/utils/cryptography/ECDSA.sol";
|
|
5
|
+
import {IPolicyPool} from "./interfaces/IPolicyPool.sol";
|
|
6
|
+
import {IPremiumsAccount} from "./interfaces/IPremiumsAccount.sol";
|
|
7
|
+
import {RiskModule} from "./RiskModule.sol";
|
|
8
|
+
import {Policy} from "./Policy.sol";
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* @title 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). One of the components of the price it's a bucket id that groups policies within
|
|
14
|
+
a risk module, with different parameters (such as collaterallization levels or fees).
|
|
15
|
+
For the resolution (resolvePolicy), it has to be called by an authorized user
|
|
16
|
+
* @custom:security-contact security@ensuro.co
|
|
17
|
+
* @author Ensuro
|
|
18
|
+
*/
|
|
19
|
+
contract SignedBucketRiskModule is RiskModule {
|
|
20
|
+
bytes32 public constant POLICY_CREATOR_ROLE = keccak256("POLICY_CREATOR_ROLE");
|
|
21
|
+
bytes32 public constant PRICER_ROLE = keccak256("PRICER_ROLE");
|
|
22
|
+
bytes32 public constant RESOLVER_ROLE = keccak256("RESOLVER_ROLE");
|
|
23
|
+
|
|
24
|
+
/// @custom:oz-upgrades-unsafe-allow state-variable-immutable
|
|
25
|
+
bool internal immutable _creationIsOpen;
|
|
26
|
+
|
|
27
|
+
mapping(uint256 => PackedParams) internal _buckets;
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* @dev Emitted when a new risk bucket is created (or modified).
|
|
31
|
+
* @param bucketId The identifier of the group of policies.
|
|
32
|
+
* @param params The packed parameters of the new bucket.
|
|
33
|
+
*/
|
|
34
|
+
event NewBucket(uint256 indexed bucketId, Params params);
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* @dev Emitted when a risk bucket is deleted.
|
|
38
|
+
* @param bucketId The identifier of the group of policies.
|
|
39
|
+
*/
|
|
40
|
+
event BucketDeleted(uint256 indexed bucketId);
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* @dev Event emitted every time a new policy is created. It allows to link the policyData with a particular policy
|
|
44
|
+
*
|
|
45
|
+
* @param policyId The id of the policy
|
|
46
|
+
* @param policyData The value sent in `policyData` parameter that's the hash of the off-chain stored data.
|
|
47
|
+
*/
|
|
48
|
+
event NewSignedPolicy(uint256 indexed policyId, bytes32 policyData);
|
|
49
|
+
|
|
50
|
+
/// @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
|
+
}
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* @dev Initializes the RiskModule
|
|
61
|
+
* @param name_ Name of the Risk Module
|
|
62
|
+
* @param collRatio_ Collateralization ratio to compute solvency requirement as % of payout (in ray)
|
|
63
|
+
* @param ensuroPpFee_ % of pure premium that will go for Ensuro treasury (in ray)
|
|
64
|
+
* @param srRoc_ return on capital paid to Senior LPs (annualized percentage - in ray)
|
|
65
|
+
* @param maxPayoutPerPolicy_ Maximum payout per policy (in wad)
|
|
66
|
+
* @param exposureLimit_ Max exposure (sum of payouts) to be allocated to this module (in wad)
|
|
67
|
+
* @param wallet_ Address of the RiskModule provider
|
|
68
|
+
*/
|
|
69
|
+
function initialize(
|
|
70
|
+
string memory name_,
|
|
71
|
+
uint256 collRatio_,
|
|
72
|
+
uint256 ensuroPpFee_,
|
|
73
|
+
uint256 srRoc_,
|
|
74
|
+
uint256 maxPayoutPerPolicy_,
|
|
75
|
+
uint256 exposureLimit_,
|
|
76
|
+
address wallet_
|
|
77
|
+
) public initializer {
|
|
78
|
+
__RiskModule_init(
|
|
79
|
+
name_,
|
|
80
|
+
collRatio_,
|
|
81
|
+
ensuroPpFee_,
|
|
82
|
+
srRoc_,
|
|
83
|
+
maxPayoutPerPolicy_,
|
|
84
|
+
exposureLimit_,
|
|
85
|
+
wallet_
|
|
86
|
+
);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
function _checkSignature(
|
|
90
|
+
uint256 payout,
|
|
91
|
+
uint256 premium,
|
|
92
|
+
uint256 lossProb,
|
|
93
|
+
uint40 expiration,
|
|
94
|
+
bytes32 policyData,
|
|
95
|
+
uint256 bucketId,
|
|
96
|
+
bytes32 quoteSignatureR,
|
|
97
|
+
bytes32 quoteSignatureVS,
|
|
98
|
+
uint40 quoteValidUntil
|
|
99
|
+
) internal view {
|
|
100
|
+
if (!_creationIsOpen)
|
|
101
|
+
_policyPool.access().checkComponentRole(
|
|
102
|
+
address(this),
|
|
103
|
+
POLICY_CREATOR_ROLE,
|
|
104
|
+
_msgSender(),
|
|
105
|
+
false
|
|
106
|
+
);
|
|
107
|
+
require(quoteValidUntil >= block.timestamp, "Quote expired");
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* Checks the quote has been signed by an authorized user
|
|
111
|
+
* The "quote" is computed as hash of the following fields (encodePacked):
|
|
112
|
+
* - address(this): the address of this RiskModule
|
|
113
|
+
* - payout, premium, lossProb, expiration: the base parameters of the policy
|
|
114
|
+
* - policyData: a hash of the private details of the policy. The calculation should include some
|
|
115
|
+
* unique id (quoteId), so each policyData identifies a policy.
|
|
116
|
+
* - quoteValidUntil: the maximum validity of the quote
|
|
117
|
+
*/
|
|
118
|
+
bytes32 quoteHash = ECDSA.toEthSignedMessageHash(
|
|
119
|
+
abi.encodePacked(
|
|
120
|
+
address(this),
|
|
121
|
+
payout,
|
|
122
|
+
premium,
|
|
123
|
+
lossProb,
|
|
124
|
+
expiration,
|
|
125
|
+
policyData,
|
|
126
|
+
bucketId,
|
|
127
|
+
quoteValidUntil
|
|
128
|
+
)
|
|
129
|
+
);
|
|
130
|
+
address signer = ECDSA.recover(quoteHash, quoteSignatureR, quoteSignatureVS);
|
|
131
|
+
_policyPool.access().checkComponentRole(address(this), PRICER_ROLE, signer, false);
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
function _newPolicySigned(
|
|
135
|
+
uint256 payout,
|
|
136
|
+
uint256 premium,
|
|
137
|
+
uint256 lossProb,
|
|
138
|
+
uint40 expiration,
|
|
139
|
+
bytes32 policyData,
|
|
140
|
+
uint256 bucketId,
|
|
141
|
+
address payer,
|
|
142
|
+
address onBehalfOf
|
|
143
|
+
) internal returns (Policy.PolicyData memory createdPolicy) {
|
|
144
|
+
uint96 internalId = uint96(uint256(policyData) % 2**96);
|
|
145
|
+
createdPolicy = _newPolicyWithParams(
|
|
146
|
+
payout,
|
|
147
|
+
premium,
|
|
148
|
+
lossProb,
|
|
149
|
+
expiration,
|
|
150
|
+
payer,
|
|
151
|
+
onBehalfOf,
|
|
152
|
+
internalId,
|
|
153
|
+
bucketParams(bucketId)
|
|
154
|
+
);
|
|
155
|
+
emit NewSignedPolicy(createdPolicy.id, policyData);
|
|
156
|
+
return createdPolicy;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
/**
|
|
160
|
+
* @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.
|
|
161
|
+
*
|
|
162
|
+
* Requirements:
|
|
163
|
+
* - The caller approved the spending of the premium to the PolicyPool
|
|
164
|
+
* - The quote has been signed by an address with the component role PRICER_ROLE
|
|
165
|
+
*
|
|
166
|
+
* Emits:
|
|
167
|
+
* - {PolicyPool.NewPolicy}
|
|
168
|
+
* - {NewSignedPolicy}
|
|
169
|
+
*
|
|
170
|
+
* @param payout The exposure (maximum payout) of the policy
|
|
171
|
+
* @param premium The premium that will be paid by the payer
|
|
172
|
+
* @param lossProb The probability of having to pay the maximum payout (wad)
|
|
173
|
+
* @param expiration The expiration of the policy (timestamp)
|
|
174
|
+
* @param onBehalfOf The policy holder
|
|
175
|
+
* @param policyData A hash of the private details of the policy. The last 96 bits will be used as internalId
|
|
176
|
+
* @param bucketId Identifies the group to which the policy belongs (that defines the RM parameters applicable to it)
|
|
177
|
+
* @param quoteSignatureR The signature of the quote. R component (EIP-2098 signature)
|
|
178
|
+
* @param quoteSignatureVS The signature of the quote. VS component (EIP-2098 signature)
|
|
179
|
+
* @param quoteValidUntil The expiration of the quote
|
|
180
|
+
* @return createdPolicy Returns the created policy
|
|
181
|
+
*/
|
|
182
|
+
function newPolicyFull(
|
|
183
|
+
uint256 payout,
|
|
184
|
+
uint256 premium,
|
|
185
|
+
uint256 lossProb,
|
|
186
|
+
uint40 expiration,
|
|
187
|
+
address onBehalfOf,
|
|
188
|
+
bytes32 policyData,
|
|
189
|
+
uint256 bucketId,
|
|
190
|
+
bytes32 quoteSignatureR,
|
|
191
|
+
bytes32 quoteSignatureVS,
|
|
192
|
+
uint40 quoteValidUntil
|
|
193
|
+
) external whenNotPaused returns (Policy.PolicyData memory createdPolicy) {
|
|
194
|
+
_checkSignature(
|
|
195
|
+
payout,
|
|
196
|
+
premium,
|
|
197
|
+
lossProb,
|
|
198
|
+
expiration,
|
|
199
|
+
policyData,
|
|
200
|
+
bucketId,
|
|
201
|
+
quoteSignatureR,
|
|
202
|
+
quoteSignatureVS,
|
|
203
|
+
quoteValidUntil
|
|
204
|
+
);
|
|
205
|
+
return
|
|
206
|
+
_newPolicySigned(
|
|
207
|
+
payout,
|
|
208
|
+
premium,
|
|
209
|
+
lossProb,
|
|
210
|
+
expiration,
|
|
211
|
+
policyData,
|
|
212
|
+
bucketId,
|
|
213
|
+
_msgSender(),
|
|
214
|
+
onBehalfOf
|
|
215
|
+
);
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
/**
|
|
219
|
+
* @dev Creates a new Policy using a signed quote. The caller is the payer of the policy.
|
|
220
|
+
*
|
|
221
|
+
* Requirements:
|
|
222
|
+
* - The caller approved the spending of the premium to the PolicyPool
|
|
223
|
+
* - The quote has been signed by an address with the component role PRICER_ROLE
|
|
224
|
+
*
|
|
225
|
+
* Emits:
|
|
226
|
+
* - {PolicyPool.NewPolicy}
|
|
227
|
+
* - {NewSignedPolicy}
|
|
228
|
+
*
|
|
229
|
+
* @param payout The exposure (maximum payout) of the policy
|
|
230
|
+
* @param premium The premium that will be paid by the payer
|
|
231
|
+
* @param lossProb The probability of having to pay the maximum payout (wad)
|
|
232
|
+
* @param expiration The expiration of the policy (timestamp)
|
|
233
|
+
* @param onBehalfOf The policy holder
|
|
234
|
+
* @param policyData A hash of the private details of the policy. The last 96 bits will be used as internalId
|
|
235
|
+
* @param bucketId Identifies the group to which the policy belongs (that defines the RM parameters applicable to it)
|
|
236
|
+
* @param quoteSignatureR The signature of the quote. R component (EIP-2098 signature)
|
|
237
|
+
* @param quoteSignatureVS The signature of the quote. VS component (EIP-2098 signature)
|
|
238
|
+
* @param quoteValidUntil The expiration of the quote
|
|
239
|
+
* @return Returns the id of the created policy
|
|
240
|
+
*/
|
|
241
|
+
function newPolicy(
|
|
242
|
+
uint256 payout,
|
|
243
|
+
uint256 premium,
|
|
244
|
+
uint256 lossProb,
|
|
245
|
+
uint40 expiration,
|
|
246
|
+
address onBehalfOf,
|
|
247
|
+
bytes32 policyData,
|
|
248
|
+
uint256 bucketId,
|
|
249
|
+
bytes32 quoteSignatureR,
|
|
250
|
+
bytes32 quoteSignatureVS,
|
|
251
|
+
uint40 quoteValidUntil
|
|
252
|
+
) external whenNotPaused returns (uint256) {
|
|
253
|
+
_checkSignature(
|
|
254
|
+
payout,
|
|
255
|
+
premium,
|
|
256
|
+
lossProb,
|
|
257
|
+
expiration,
|
|
258
|
+
policyData,
|
|
259
|
+
bucketId,
|
|
260
|
+
quoteSignatureR,
|
|
261
|
+
quoteSignatureVS,
|
|
262
|
+
quoteValidUntil
|
|
263
|
+
);
|
|
264
|
+
return
|
|
265
|
+
_newPolicySigned(
|
|
266
|
+
payout,
|
|
267
|
+
premium,
|
|
268
|
+
lossProb,
|
|
269
|
+
expiration,
|
|
270
|
+
policyData,
|
|
271
|
+
bucketId,
|
|
272
|
+
_msgSender(),
|
|
273
|
+
onBehalfOf
|
|
274
|
+
).id;
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
/**
|
|
278
|
+
* @dev Creates a new Policy using a signed quote. The payer is the policy holder
|
|
279
|
+
*
|
|
280
|
+
* Requirements:
|
|
281
|
+
* - currency().allowance(onBehalfOf, _msgSender()) > 0
|
|
282
|
+
* - The quote has been signed by an address with the component role PRICER_ROLE
|
|
283
|
+
*
|
|
284
|
+
* Emits:
|
|
285
|
+
* - {PolicyPool.NewPolicy}
|
|
286
|
+
* - {NewSignedPolicy}
|
|
287
|
+
*
|
|
288
|
+
* @param payout The exposure (maximum payout) of the policy
|
|
289
|
+
* @param premium The premium that will be paid by the payer
|
|
290
|
+
* @param lossProb The probability of having to pay the maximum payout (wad)
|
|
291
|
+
* @param expiration The expiration of the policy (timestamp)
|
|
292
|
+
* @param onBehalfOf The policy holder
|
|
293
|
+
* @param policyData A hash of the private details of the policy. The last 96 bits will be used as internalId
|
|
294
|
+
* @param bucketId Identifies the group to which the policy belongs (that defines the RM parameters applicable to it)
|
|
295
|
+
* @param quoteSignatureR The signature of the quote. R component (EIP-2098 signature)
|
|
296
|
+
* @param quoteSignatureVS The signature of the quote. VS component (EIP-2098 signature)
|
|
297
|
+
* @param quoteValidUntil The expiration of the quote
|
|
298
|
+
* @return Returns the id of the created policy
|
|
299
|
+
*/
|
|
300
|
+
function newPolicyPaidByHolder(
|
|
301
|
+
uint256 payout,
|
|
302
|
+
uint256 premium,
|
|
303
|
+
uint256 lossProb,
|
|
304
|
+
uint40 expiration,
|
|
305
|
+
address onBehalfOf,
|
|
306
|
+
bytes32 policyData,
|
|
307
|
+
uint256 bucketId,
|
|
308
|
+
bytes32 quoteSignatureR,
|
|
309
|
+
bytes32 quoteSignatureVS,
|
|
310
|
+
uint40 quoteValidUntil
|
|
311
|
+
) external whenNotPaused returns (uint256) {
|
|
312
|
+
require(
|
|
313
|
+
onBehalfOf == _msgSender() || currency().allowance(onBehalfOf, _msgSender()) > 0,
|
|
314
|
+
"Sender is not authorized to create policies onBehalfOf"
|
|
315
|
+
);
|
|
316
|
+
/**
|
|
317
|
+
* The standard is the payer should be the _msgSender() but usually, in this type of module,
|
|
318
|
+
* the sender is an operative account managed by software, where the onBehalfOf is a more
|
|
319
|
+
* secure account (hardware wallet) that does the cash movements.
|
|
320
|
+
* This non standard behaviour allows for a more secure setup, where the sender never manages
|
|
321
|
+
* cash.
|
|
322
|
+
* We leverage the currency's allowance mechanism to allow the sender access to the payer's
|
|
323
|
+
* funds.
|
|
324
|
+
* Note that this allowance won't be spent, so anything above 0 is accepted.
|
|
325
|
+
*/
|
|
326
|
+
_checkSignature(
|
|
327
|
+
payout,
|
|
328
|
+
premium,
|
|
329
|
+
lossProb,
|
|
330
|
+
expiration,
|
|
331
|
+
policyData,
|
|
332
|
+
bucketId,
|
|
333
|
+
quoteSignatureR,
|
|
334
|
+
quoteSignatureVS,
|
|
335
|
+
quoteValidUntil
|
|
336
|
+
);
|
|
337
|
+
return
|
|
338
|
+
_newPolicySigned(
|
|
339
|
+
payout,
|
|
340
|
+
premium,
|
|
341
|
+
lossProb,
|
|
342
|
+
expiration,
|
|
343
|
+
policyData,
|
|
344
|
+
bucketId,
|
|
345
|
+
onBehalfOf,
|
|
346
|
+
onBehalfOf
|
|
347
|
+
).id;
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
function resolvePolicy(Policy.PolicyData calldata policy, uint256 payout)
|
|
351
|
+
external
|
|
352
|
+
onlyComponentRole(RESOLVER_ROLE)
|
|
353
|
+
whenNotPaused
|
|
354
|
+
{
|
|
355
|
+
_policyPool.resolvePolicy(policy, payout);
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
/**
|
|
359
|
+
* @dev Sets the parameters for a risk bucket.
|
|
360
|
+
*
|
|
361
|
+
* Requirements:
|
|
362
|
+
*
|
|
363
|
+
* - The caller must have the LEVEL1_ROLE or LEVEL2_ROLE
|
|
364
|
+
*
|
|
365
|
+
* @param bucketId Group identifier for the policies that will have these parameters
|
|
366
|
+
* @param params_ The parameters of the new bucket.
|
|
367
|
+
*/
|
|
368
|
+
function setBucketParams(uint256 bucketId, Params calldata params_)
|
|
369
|
+
external
|
|
370
|
+
onlyGlobalOrComponentRole2(LEVEL1_ROLE, LEVEL2_ROLE)
|
|
371
|
+
{
|
|
372
|
+
require(
|
|
373
|
+
bucketId != 0,
|
|
374
|
+
"SignedBucketRiskModule: bucketId can't be zero, set default RM parameters"
|
|
375
|
+
);
|
|
376
|
+
_buckets[bucketId] = PackedParams({
|
|
377
|
+
moc: _wadTo4(params_.moc),
|
|
378
|
+
jrCollRatio: _wadTo4(params_.jrCollRatio),
|
|
379
|
+
collRatio: _wadTo4(params_.collRatio),
|
|
380
|
+
ensuroPpFee: _wadTo4(params_.ensuroPpFee),
|
|
381
|
+
ensuroCocFee: _wadTo4(params_.ensuroCocFee),
|
|
382
|
+
jrRoc: _wadTo4(params_.jrRoc),
|
|
383
|
+
srRoc: _wadTo4(params_.srRoc),
|
|
384
|
+
maxPayoutPerPolicy: type(uint32).max, // unused, but needs to be > 0
|
|
385
|
+
exposureLimit: type(uint32).max, //unused, but needs to be > 0
|
|
386
|
+
maxDuration: type(uint16).max //unused
|
|
387
|
+
});
|
|
388
|
+
_validatePackedParams(_buckets[bucketId]);
|
|
389
|
+
emit NewBucket(bucketId, params_);
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
/**
|
|
393
|
+
* @dev Deletes a bucket
|
|
394
|
+
*
|
|
395
|
+
* Requirements:
|
|
396
|
+
*
|
|
397
|
+
* - The caller must have the LEVEL1_ROLE or LEVEL2_ROLE
|
|
398
|
+
*
|
|
399
|
+
* @param bucketId Group identifier for the policies that will have these parameters
|
|
400
|
+
*/
|
|
401
|
+
function deleteBucket(uint256 bucketId)
|
|
402
|
+
external
|
|
403
|
+
onlyGlobalOrComponentRole2(LEVEL1_ROLE, LEVEL2_ROLE)
|
|
404
|
+
{
|
|
405
|
+
require(
|
|
406
|
+
bucketId != 0,
|
|
407
|
+
"SignedBucketRiskModule: bucketId can't be zero, set default RM parameters"
|
|
408
|
+
);
|
|
409
|
+
delete _buckets[bucketId];
|
|
410
|
+
emit BucketDeleted(bucketId);
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
/**
|
|
414
|
+
* @dev returns the risk bucket parameters for the given bucketId
|
|
415
|
+
*
|
|
416
|
+
* @param bucketId Id of the bucket of 0 if you want the default params
|
|
417
|
+
*/
|
|
418
|
+
function bucketParams(uint256 bucketId) public view returns (Params memory params_) {
|
|
419
|
+
if (bucketId != 0) {
|
|
420
|
+
PackedParams storage bucketParams_ = _buckets[bucketId];
|
|
421
|
+
require(bucketParams_.moc != 0, "SignedBucketRiskModule: bucket not found!");
|
|
422
|
+
params_ = _unpackParams(bucketParams_);
|
|
423
|
+
} else {
|
|
424
|
+
params_ = params();
|
|
425
|
+
}
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
/**
|
|
429
|
+
* @dev Returns the minimum premium for a given bucket
|
|
430
|
+
*
|
|
431
|
+
* @param payout Maximum payout of the policy
|
|
432
|
+
* @param lossProb Probability of having a loss equal to the maximum payout
|
|
433
|
+
* @param expiration Expiration date of the policy
|
|
434
|
+
* @param bucketId Id of the bucket of 0 if you want the default params
|
|
435
|
+
*/
|
|
436
|
+
function getMinimumPremiumForBucket(
|
|
437
|
+
uint256 payout,
|
|
438
|
+
uint256 lossProb,
|
|
439
|
+
uint40 expiration,
|
|
440
|
+
uint256 bucketId
|
|
441
|
+
) public view virtual returns (uint256) {
|
|
442
|
+
return _getMinimumPremium(payout, lossProb, expiration, bucketParams(bucketId));
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
/**
|
|
446
|
+
* @dev This empty reserved space is put in place to allow future versions to add new
|
|
447
|
+
* variables without shifting down storage in the inheritance chain.
|
|
448
|
+
* See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
|
|
449
|
+
*/
|
|
450
|
+
uint256[49] private __gap;
|
|
451
|
+
}
|
package/js/constants.js
ADDED
package/js/deploy.js
CHANGED
|
@@ -3,45 +3,14 @@ const helpers = require("@nomicfoundation/hardhat-network-helpers");
|
|
|
3
3
|
const fs = require("fs");
|
|
4
4
|
const { request } = require("undici");
|
|
5
5
|
const ethers = require("ethers");
|
|
6
|
-
|
|
7
|
-
const
|
|
8
|
-
const
|
|
9
|
-
const RAY = WAD.mul(_BN(1e9)); // 1e18*1e9=1e27
|
|
10
|
-
|
|
11
|
-
const WhitelistStatus = {
|
|
12
|
-
notdefined: 0,
|
|
13
|
-
whitelisted: 1,
|
|
14
|
-
blacklisted: 2,
|
|
15
|
-
};
|
|
6
|
+
const { task, types } = require("hardhat/config");
|
|
7
|
+
const { WhitelistStatus } = require("../js/enums");
|
|
8
|
+
const { amountFunction, _W, grantRole, grantComponentRole, getDefaultSigner } = require("../js/utils");
|
|
16
9
|
|
|
17
10
|
const reservesOpts = {
|
|
18
11
|
unsafeAllow: ["delegatecall"],
|
|
19
12
|
};
|
|
20
13
|
|
|
21
|
-
/**
|
|
22
|
-
* Creates a fixed-point conversion function for the desired number of decimals
|
|
23
|
-
* @param decimals The number of decimals. Must be >= 6.
|
|
24
|
-
* @returns The amount function created. The function can receive strings (recommended),
|
|
25
|
-
* floats/doubles (not recommended) and integers.
|
|
26
|
-
*
|
|
27
|
-
* Floats will be rounded to 6 decimal before scaling.
|
|
28
|
-
*/
|
|
29
|
-
function amountFunction(decimals) {
|
|
30
|
-
return function (value) {
|
|
31
|
-
if (value === undefined) return undefined;
|
|
32
|
-
|
|
33
|
-
if (typeof value === "string" || value instanceof String) {
|
|
34
|
-
return hre.ethers.utils.parseUnits(value, decimals);
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
if (!Number.isInteger(value)) {
|
|
38
|
-
return _BN(Math.round(value * 1e6)).mul(_BN(Math.pow(10, decimals - 6)));
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
return _BN(value).mul(_BN(10).pow(decimals));
|
|
42
|
-
};
|
|
43
|
-
}
|
|
44
|
-
|
|
45
14
|
function amountDecimals() {
|
|
46
15
|
let decimals = Number.parseInt(process.env.DEPLOY_AMOUNT_DECIMALS);
|
|
47
16
|
console.assert(decimals >= 6);
|
|
@@ -49,8 +18,6 @@ function amountDecimals() {
|
|
|
49
18
|
}
|
|
50
19
|
|
|
51
20
|
const GWei = amountFunction(9);
|
|
52
|
-
const _W = amountFunction(18);
|
|
53
|
-
const _R = amountFunction(27);
|
|
54
21
|
const _A = amountFunction(amountDecimals());
|
|
55
22
|
|
|
56
23
|
/**
|
|
@@ -185,48 +152,6 @@ async function deployProxyContract(
|
|
|
185
152
|
return { ContractFactory, contract };
|
|
186
153
|
}
|
|
187
154
|
|
|
188
|
-
function parseRole(role) {
|
|
189
|
-
if (role.startsWith("0x")) return role;
|
|
190
|
-
if (role === "DEFAULT_ADMIN_ROLE") return ethers.constants.HashZero;
|
|
191
|
-
return ethers.utils.keccak256(ethers.utils.toUtf8Bytes(role));
|
|
192
|
-
}
|
|
193
|
-
|
|
194
|
-
async function grantComponentRole(hre, contract, component, role, user) {
|
|
195
|
-
let userAddress;
|
|
196
|
-
if (user === undefined) {
|
|
197
|
-
user = await _getDefaultSigner(hre);
|
|
198
|
-
userAddress = user.address;
|
|
199
|
-
} else {
|
|
200
|
-
userAddress = user;
|
|
201
|
-
}
|
|
202
|
-
const roleHex = parseRole(role);
|
|
203
|
-
const componentAddress = component.address || component;
|
|
204
|
-
const componentRole = await contract.getComponentRole(componentAddress, roleHex);
|
|
205
|
-
if (!(await contract.hasRole(componentRole, userAddress))) {
|
|
206
|
-
await contract.grantComponentRole(componentAddress, roleHex, userAddress, txOverrides());
|
|
207
|
-
console.log(`Role ${role} (${roleHex}) Component ${componentAddress} granted to ${userAddress}`);
|
|
208
|
-
} else {
|
|
209
|
-
console.log(`Role ${role} (${roleHex}) Component ${componentAddress} already granted to ${userAddress}`);
|
|
210
|
-
}
|
|
211
|
-
}
|
|
212
|
-
|
|
213
|
-
async function grantRole(hre, contract, role, user) {
|
|
214
|
-
let userAddress;
|
|
215
|
-
if (user === undefined) {
|
|
216
|
-
user = await _getDefaultSigner(hre);
|
|
217
|
-
userAddress = user.address;
|
|
218
|
-
} else {
|
|
219
|
-
userAddress = user;
|
|
220
|
-
}
|
|
221
|
-
const roleHex = parseRole(role);
|
|
222
|
-
if (!(await contract.hasRole(roleHex, userAddress))) {
|
|
223
|
-
await contract.grantRole(roleHex, userAddress, txOverrides());
|
|
224
|
-
console.log(`Role ${role} (${roleHex}) granted to ${userAddress}`);
|
|
225
|
-
} else {
|
|
226
|
-
console.log(`Role ${role} (${roleHex}) already granted to ${userAddress}`);
|
|
227
|
-
}
|
|
228
|
-
}
|
|
229
|
-
|
|
230
155
|
async function grantRoleTask({ contractAddress, role, account, component, impersonate, impersonateBalance }, hre) {
|
|
231
156
|
let contract = await hre.ethers.getContractAt("AccessManager", contractAddress);
|
|
232
157
|
if (impersonate !== undefined) {
|
|
@@ -237,9 +162,9 @@ async function grantRoleTask({ contractAddress, role, account, component, impers
|
|
|
237
162
|
contract = contract.connect(signer);
|
|
238
163
|
}
|
|
239
164
|
if (component === ethers.constants.AddressZero) {
|
|
240
|
-
await grantRole(hre, contract, role, account);
|
|
165
|
+
await grantRole(hre, contract, role, account, txOverrides(), console.log);
|
|
241
166
|
} else {
|
|
242
|
-
await grantComponentRole(hre, contract, component, role, account);
|
|
167
|
+
await grantComponentRole(hre, contract, component, role, account, txOverrides(), console.log);
|
|
243
168
|
}
|
|
244
169
|
}
|
|
245
170
|
|
|
@@ -260,11 +185,6 @@ async function deployAccessManager(opts, hre) {
|
|
|
260
185
|
return (await deployProxyContract({ contractClass: "AccessManager", ...opts }, hre)).contract.address;
|
|
261
186
|
}
|
|
262
187
|
|
|
263
|
-
async function _getDefaultSigner(hre) {
|
|
264
|
-
const signers = await hre.ethers.getSigners();
|
|
265
|
-
return signers[0];
|
|
266
|
-
}
|
|
267
|
-
|
|
268
188
|
async function deployPolicyPool({ accessAddress, currencyAddress, nftName, nftSymbol, treasuryAddress, ...opts }, hre) {
|
|
269
189
|
return (
|
|
270
190
|
await deployProxyContract(
|
|
@@ -447,7 +367,7 @@ async function deployAaveAssetManager({ asset, aave, amClass, ...opts }, hre) {
|
|
|
447
367
|
}
|
|
448
368
|
|
|
449
369
|
async function deployWhitelist(
|
|
450
|
-
{ wlClass, poolAddress, extraConstructorArgs, extraArgs, eToken, eToken2, eToken3, defaultStatus,
|
|
370
|
+
{ wlClass, poolAddress, extraConstructorArgs, extraArgs, eToken, eToken2, eToken3, defaultStatus, ...opts },
|
|
451
371
|
hre
|
|
452
372
|
) {
|
|
453
373
|
extraArgs = extraArgs || [];
|
|
@@ -490,7 +410,7 @@ async function trustfullPolicy({ rmAddress, payout, premium, lossProb, expiratio
|
|
|
490
410
|
const currency = await hre.ethers.getContractAt("IERC20Metadata", await policyPool.currency());
|
|
491
411
|
await grantComponentRole(hre, access, rm, "PRICER_ROLE");
|
|
492
412
|
|
|
493
|
-
customer = customer || (await
|
|
413
|
+
customer = customer || (await getDefaultSigner(hre));
|
|
494
414
|
premium = _A(premium);
|
|
495
415
|
|
|
496
416
|
await currency.approve(policyPool.address, premium);
|
|
@@ -534,7 +454,7 @@ async function flightDelayPolicy(
|
|
|
534
454
|
const currency = await hre.ethers.getContractAt("IERC20Metadata", await policyPool.currency());
|
|
535
455
|
|
|
536
456
|
await grantComponentRole(hre, access, rm, "PRICER_ROLE");
|
|
537
|
-
customer = customer || (await
|
|
457
|
+
customer = customer || (await getDefaultSigner(hre));
|
|
538
458
|
premium = _A(premium);
|
|
539
459
|
|
|
540
460
|
await currency.approve(policyPool.address, premium);
|
|
@@ -561,7 +481,7 @@ async function listETokens({ poolAddress }, hre) {
|
|
|
561
481
|
|
|
562
482
|
console.log(`Pool has ${etkCount} tokens`);
|
|
563
483
|
|
|
564
|
-
for (i = 0; i < etkCount; i++) {
|
|
484
|
+
for (let i = 0; i < etkCount; i++) {
|
|
565
485
|
const etk = await hre.ethers.getContractAt("EToken", await policyPool.getETokenAt(i));
|
|
566
486
|
const etkName = await etk.name();
|
|
567
487
|
console.log(`eToken at ${etk.address}: ${etkName}`);
|
|
@@ -599,7 +519,7 @@ function add_task() {
|
|
|
599
519
|
taskArgs.accessAddress = await deployAccessManager(taskArgs, hre);
|
|
600
520
|
}
|
|
601
521
|
taskArgs.saveAddr = "POOL";
|
|
602
|
-
|
|
522
|
+
await deployPolicyPool(taskArgs, hre);
|
|
603
523
|
});
|
|
604
524
|
|
|
605
525
|
task("deploy:testCurrency", "Deploys the Test Currency")
|
|
@@ -786,15 +706,12 @@ module.exports = {
|
|
|
786
706
|
logContractCreated,
|
|
787
707
|
deployContract,
|
|
788
708
|
deployProxyContract,
|
|
789
|
-
grantRole,
|
|
790
|
-
grantComponentRole,
|
|
791
709
|
deployEToken,
|
|
792
710
|
deployPremiumsAccount,
|
|
793
711
|
deployRiskModule,
|
|
794
712
|
deploySignedQuoteRM,
|
|
795
713
|
setAssetManager,
|
|
796
714
|
deployWhitelist,
|
|
797
|
-
WhitelistStatus,
|
|
798
715
|
txOverrides,
|
|
799
716
|
amountFunction,
|
|
800
717
|
_W,
|
package/js/enums.js
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
const WhitelistStatus = {
|
|
2
|
+
notdefined: 0,
|
|
3
|
+
whitelisted: 1,
|
|
4
|
+
blacklisted: 2,
|
|
5
|
+
};
|
|
6
|
+
|
|
7
|
+
const RiskModuleParameter = {
|
|
8
|
+
moc: 0,
|
|
9
|
+
jrCollRatio: 1,
|
|
10
|
+
collRatio: 2,
|
|
11
|
+
ensuroPpFee: 3,
|
|
12
|
+
ensuroCocFee: 4,
|
|
13
|
+
jrRoc: 5,
|
|
14
|
+
srRoc: 6,
|
|
15
|
+
maxPayoutPerPolicy: 7,
|
|
16
|
+
exposureLimit: 8,
|
|
17
|
+
maxDuration: 9,
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
const ComponentKind = {
|
|
21
|
+
eToken: 1,
|
|
22
|
+
riskModule: 2,
|
|
23
|
+
premiumsAccount: 3,
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
module.exports = {
|
|
27
|
+
WhitelistStatus,
|
|
28
|
+
RiskModuleParameter,
|
|
29
|
+
ComponentKind,
|
|
30
|
+
};
|