@ensuro/core 2.0.0-beta9 → 2.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (56) hide show
  1. package/README.md +14 -0
  2. package/build/contracts/AccessManager.sol/AccessManager.json +7 -2
  3. package/build/contracts/ERC4626AssetManager.sol/ERC4626AssetManager.json +21 -2
  4. package/build/contracts/EToken.sol/EToken.json +21 -2
  5. package/build/contracts/LPManualWhitelist.sol/LPManualWhitelist.json +21 -2
  6. package/build/contracts/LiquidityThresholdAssetManager.sol/LiquidityThresholdAssetManager.json +19 -0
  7. package/build/contracts/Policy.sol/Policy.json +2 -2
  8. package/build/contracts/PolicyPool.sol/PolicyPool.json +21 -2
  9. package/build/contracts/PolicyPoolComponent.sol/PolicyPoolComponent.json +19 -0
  10. package/build/contracts/PremiumsAccount.sol/PremiumsAccount.json +21 -2
  11. package/build/contracts/Reserve.sol/Reserve.json +19 -0
  12. package/build/contracts/RiskModule.sol/RiskModule.json +19 -0
  13. package/build/contracts/SignedQuoteRiskModule.sol/SignedQuoteRiskModule.json +1110 -0
  14. package/build/contracts/TimeScaled.sol/TimeScaled.json +2 -2
  15. package/build/contracts/TrustfulRiskModule.sol/TrustfulRiskModule.json +137 -2
  16. package/build/contracts/dependencies/WadRayMath.sol/WadRayMath.json +2 -2
  17. package/build/contracts/interfaces/IAssetManager.sol/IAssetManager.json +19 -0
  18. package/build/contracts/interfaces/IPolicyPool.sol/IPolicyPool.json +19 -0
  19. package/build/contracts/interfaces/IPolicyPoolComponent.sol/IPolicyPoolComponent.json +19 -0
  20. package/build/contracts/mocks/FixedRateVault.sol/FixedRateVault.json +2 -2
  21. package/build/contracts/mocks/ForwardProxy.sol/ForwardProxy.json +2 -2
  22. package/build/contracts/mocks/InterfaceIdCalculator.sol/InterfaceIdCalculator.json +180 -0
  23. package/build/contracts/mocks/PolicyHolderMock.sol/PolicyHolderMock.json +2 -2
  24. package/build/contracts/mocks/PolicyPoolComponentMock.sol/PolicyPoolComponentMock.json +21 -2
  25. package/build/contracts/mocks/PolicyPoolMock.sol/PolicyPoolMock.json +21 -2
  26. package/build/contracts/mocks/PolicyPoolMock.sol/PolicyPoolMockForward.json +2 -2
  27. package/build/contracts/mocks/RiskModuleMock.sol/RiskModuleMock.json +21 -2
  28. package/build/contracts/mocks/TestCurrency.sol/TestCurrency.json +2 -2
  29. package/build/contracts/mocks/TestNFT.sol/TestNFT.json +2 -2
  30. package/contracts/AccessManager.sol +30 -1
  31. package/contracts/ERC4626AssetManager.sol +3 -0
  32. package/contracts/EToken.sol +89 -19
  33. package/contracts/LPManualWhitelist.sol +18 -2
  34. package/contracts/LiquidityThresholdAssetManager.sol +17 -2
  35. package/contracts/Policy.sol +4 -2
  36. package/contracts/PolicyPool.sol +72 -13
  37. package/contracts/PolicyPoolComponent.sol +29 -3
  38. package/contracts/PremiumsAccount.sol +72 -24
  39. package/contracts/Reserve.sol +19 -3
  40. package/contracts/RiskModule.sol +46 -13
  41. package/contracts/SignedQuoteRiskModule.sol +310 -0
  42. package/contracts/TrustfulRiskModule.sol +104 -3
  43. package/contracts/interfaces/IAssetManager.sol +8 -3
  44. package/contracts/interfaces/IPolicyPool.sol +15 -4
  45. package/contracts/interfaces/IPolicyPoolComponent.sol +2 -1
  46. package/contracts/mocks/InterfaceIdCalculator.sol +32 -0
  47. package/contracts/mocks/PolicyPoolComponentMock.sol +10 -0
  48. package/contracts/mocks/PolicyPoolMock.sol +4 -0
  49. package/js/deploy.js +779 -0
  50. package/js/test-utils.js +139 -37
  51. package/package.json +4 -2
  52. package/scripts/change-pragma.sh +19 -0
  53. package/scripts/deploySmokeTest-fork.sh +53 -0
  54. package/scripts/deploySmokeTest.sh +51 -0
  55. package/scripts/storageLayout.js +33 -0
  56. package/scripts/utils.sh +65 -0
package/js/deploy.js ADDED
@@ -0,0 +1,779 @@
1
+ const upgrades_core = require("@openzeppelin/upgrades-core");
2
+ const fs = require("fs");
3
+
4
+ const ethers = require("ethers");
5
+
6
+ const _BN = ethers.BigNumber.from;
7
+ const WAD = _BN(1e10).mul(_BN(1e8)); // 1e10*1e8=1e18
8
+ const RAY = WAD.mul(_BN(1e9)); // 1e18*1e9=1e27
9
+
10
+ /**
11
+ * Creates a fixed-point conversion function for the desired number of decimals
12
+ * @param decimals The number of decimals. Must be >= 6.
13
+ * @returns The amount function created. The function can receive strings (recommended),
14
+ * floats/doubles (not recommended) and integers.
15
+ *
16
+ * Floats will be rounded to 6 decimal before scaling.
17
+ */
18
+ function amountFunction(decimals) {
19
+ return function (value) {
20
+ if (value === undefined) return undefined;
21
+
22
+ if (typeof value === "string" || value instanceof String) {
23
+ return hre.ethers.utils.parseUnits(value, decimals);
24
+ }
25
+
26
+ if (!Number.isInteger(value)) {
27
+ return _BN(Math.round(value * 1e6)).mul(_BN(Math.pow(10, decimals - 6)));
28
+ }
29
+
30
+ return _BN(value).mul(_BN(10).pow(decimals));
31
+ };
32
+ }
33
+
34
+ function amountDecimals() {
35
+ let decimals = Number.parseInt(process.env.DEPLOY_AMOUNT_DECIMALS);
36
+ console.assert(decimals >= 6);
37
+ return decimals;
38
+ }
39
+
40
+ const GWei = amountFunction(9);
41
+ const _W = amountFunction(18);
42
+ const _R = amountFunction(27);
43
+ const _A = amountFunction(amountDecimals());
44
+
45
+ /**
46
+ * Transaction overrides using env variables because hardhat-ethers ignores hardhat config
47
+ * See: https://hardhat.org/hardhat-runner/plugins/nomiclabs-hardhat-ethers#gas-transaction-parameters-in--hardhat.config--are-not-used
48
+ */
49
+ function txOverrides() {
50
+ const ret = {};
51
+ if (process.env.OVERRIDE_GAS_PRICE !== undefined) {
52
+ ret.gasPrice = GWei(parseFloat(process.env.OVERRIDE_GAS_PRICE));
53
+ }
54
+
55
+ if (process.env.OVERRIDE_GAS_LIMIT !== undefined) {
56
+ ret.gasLimit = parseInt(process.env.OVERRIDE_GAS_LIMIT);
57
+ }
58
+ return ret || undefined;
59
+ }
60
+
61
+ function saveAddress(name, address) {
62
+ if (name === undefined) {
63
+ throw "Didn't specified an address to save. If you don't want to save the address send null";
64
+ }
65
+ if (!name || name === "") return;
66
+ let addresses;
67
+ let addressesFilename;
68
+ if (process.env.ADDRESSES_FILENAME) {
69
+ addressesFilename = process.env.ADDRESSES_FILENAME;
70
+ } else {
71
+ if (process.env.NETWORK) {
72
+ addressesFilename = `.addresses-${process.env.NETWORK}.json`;
73
+ } else {
74
+ addressesFilename = ".addresses-localhost.json";
75
+ }
76
+ }
77
+ try {
78
+ addresses = JSON.parse(fs.readFileSync(addressesFilename));
79
+ } catch (err) {
80
+ console.log("Error reading .addresses.json", err);
81
+ addresses = {};
82
+ }
83
+ addresses[name] = address;
84
+ fs.writeFileSync(addressesFilename, JSON.stringify(addresses, null, 4));
85
+ }
86
+
87
+ function etherscanUrl() {
88
+ return process.env.ETHERSCAN_URL;
89
+ }
90
+
91
+ async function logContractCreated(hre, contractName, address) {
92
+ const browserUrl = etherscanUrl();
93
+ if (browserUrl) {
94
+ console.log(`${contractName} deployed to: ${browserUrl}/address/${address}`);
95
+ } else {
96
+ console.log(`${contractName} deployed to: ${address}`);
97
+ }
98
+ }
99
+
100
+ async function verifyContract(hre, contract, isProxy, constructorArguments) {
101
+ if (isProxy === undefined) isProxy = false;
102
+ if (constructorArguments === undefined) constructorArguments = [];
103
+ let address = contract.address;
104
+ if (isProxy) address = await upgrades_core.getImplementationAddress(hre.network.provider, address);
105
+ try {
106
+ await hre.run("verify:verify", {
107
+ address: address,
108
+ constructorArguments: constructorArguments,
109
+ });
110
+ if (isProxy) {
111
+ console.log(
112
+ "Contract successfully verified, you should verify the proxy at " +
113
+ `${etherscanUrl()}/proxyContractChecker?a=${contract.address}`
114
+ );
115
+ }
116
+ } catch (error) {
117
+ console.log("Error verifying contract", error);
118
+ }
119
+ }
120
+
121
+ async function deployContract({ saveAddr, verify, contractClass, constructorArgs }, hre) {
122
+ const ContractFactory = await hre.ethers.getContractFactory(contractClass);
123
+ const contract = await ContractFactory.deploy(...constructorArgs, txOverrides());
124
+ if (verify) {
125
+ // From https://ethereum.stackexchange.com/a/119622/79726
126
+ await contract.deployTransaction.wait(6);
127
+ } else {
128
+ await contract.deployed();
129
+ }
130
+ await logContractCreated(hre, contractClass, contract.address);
131
+ saveAddress(saveAddr, contract.address);
132
+ if (verify) await verifyContract(hre, contract, false, constructorArgs);
133
+ return { ContractFactory, contract };
134
+ }
135
+
136
+ async function deployProxyContract({ saveAddr, verify, contractClass, constructorArgs, initializeArgs }, hre) {
137
+ const ContractFactory = await hre.ethers.getContractFactory(contractClass);
138
+ const contract = await hre.upgrades.deployProxy(ContractFactory, initializeArgs || [], {
139
+ constructorArgs: constructorArgs,
140
+ kind: "uups",
141
+ unsafeAllow: ["delegatecall"],
142
+ });
143
+ if (verify) {
144
+ // From https://ethereum.stackexchange.com/a/119622/79726
145
+ await contract.deployTransaction.wait(6);
146
+ } else {
147
+ await contract.deployed();
148
+ }
149
+ await logContractCreated(hre, contractClass, contract.address);
150
+ saveAddress(saveAddr, contract.address);
151
+ if (verify) await verifyContract(hre, contract, true, constructorArgs);
152
+ return { ContractFactory, contract };
153
+ }
154
+
155
+ function parseRole(role) {
156
+ if (role.startsWith("0x"))
157
+ return role;
158
+ if (role === "DEFAULT_ADMIN_ROLE")
159
+ return ethers.constants.HashZero;
160
+ return ethers.utils.keccak256(ethers.utils.toUtf8Bytes(role));
161
+ }
162
+
163
+ async function grantComponentRole(hre, contract, component, role, user) {
164
+ let userAddress;
165
+ if (user === undefined) {
166
+ user = await _getDefaultSigner(hre);
167
+ userAddress = user.address;
168
+ } else {
169
+ userAddress = user;
170
+ }
171
+ const roleHex = parseRole(role);
172
+ const componentAddress = component.address || component;
173
+ const componentRole = await contract.getComponentRole(componentAddress, roleHex);
174
+ if (!(await contract.hasRole(componentRole, userAddress))) {
175
+ await contract.grantComponentRole(componentAddress, roleHex, userAddress, txOverrides());
176
+ console.log(`Role ${role} (${roleHex}) Component ${componentAddress} granted to ${userAddress}`);
177
+ } else {
178
+ console.log(`Role ${role} (${roleHex}) Component ${componentAddress} already granted to ${userAddress}`);
179
+ }
180
+ }
181
+
182
+ async function grantRole(hre, contract, role, user) {
183
+ let userAddress;
184
+ if (user === undefined) {
185
+ user = await _getDefaultSigner(hre);
186
+ userAddress = user.address;
187
+ } else {
188
+ userAddress = user;
189
+ }
190
+ const roleHex = parseRole(role);
191
+ if (!(await contract.hasRole(roleHex, userAddress))) {
192
+ await contract.grantRole(roleHex, userAddress, txOverrides());
193
+ console.log(`Role ${role} (${roleHex}) granted to ${userAddress}`);
194
+ } else {
195
+ console.log(`Role ${role} (${roleHex}) already granted to ${userAddress}`);
196
+ }
197
+ }
198
+
199
+ async function grantRoleTask({ contractAddress, role, account, component }, hre) {
200
+ const contract = await hre.ethers.getContractAt("AccessManager", contractAddress);
201
+ if (component === ethers.constants.AddressZero) {
202
+ await grantRole(hre, contract, role, account);
203
+ } else {
204
+ await grantComponentRole(hre, contract, component, role, account);
205
+ }
206
+ }
207
+
208
+ async function deployTestCurrency({ currName, currSymbol, initialSupply, ...opts }, hre) {
209
+ return (
210
+ await deployContract(
211
+ {
212
+ contractClass: "TestCurrency",
213
+ constructorArgs: [currName, currSymbol, _A(initialSupply), amountDecimals()],
214
+ ...opts,
215
+ },
216
+ hre
217
+ )
218
+ ).contract.address;
219
+ }
220
+
221
+ async function deployAccessManager(opts, hre) {
222
+ return (await deployProxyContract({ contractClass: "AccessManager", ...opts }, hre)).contract.address;
223
+ }
224
+
225
+ async function _getDefaultSigner(hre) {
226
+ const signers = await hre.ethers.getSigners();
227
+ return signers[0];
228
+ }
229
+
230
+ async function deployPolicyPool({ accessAddress, currencyAddress, nftName, nftSymbol, treasuryAddress, ...opts }, hre) {
231
+ return (
232
+ await deployProxyContract(
233
+ {
234
+ contractClass: "PolicyPool",
235
+ constructorArgs: [accessAddress, currencyAddress],
236
+ initializeArgs: [nftName, nftSymbol, treasuryAddress],
237
+ ...opts,
238
+ },
239
+ hre
240
+ )
241
+ ).contract.address;
242
+ }
243
+
244
+ async function deployEToken(
245
+ { poolAddress, etkName, etkSymbol, maxUtilizationRate, poolLoanInterestRate, ...opts },
246
+ hre
247
+ ) {
248
+ const { contract } = await deployProxyContract(
249
+ {
250
+ contractClass: "EToken",
251
+ constructorArgs: [poolAddress],
252
+ initializeArgs: [etkName, etkSymbol, _W(maxUtilizationRate), _W(poolLoanInterestRate)],
253
+ ...opts,
254
+ },
255
+ hre
256
+ );
257
+ const policyPool = await hre.ethers.getContractAt("PolicyPool", poolAddress);
258
+ if (opts.addComponent)
259
+ await policyPool.addComponent(contract.address, 1);
260
+ return contract.address;
261
+ }
262
+
263
+ async function deployPremiumsAccount({ poolAddress, juniorEtk, seniorEtk, ...opts }, hre) {
264
+ const { contract } = await deployProxyContract(
265
+ {
266
+ contractClass: "PremiumsAccount",
267
+ constructorArgs: [poolAddress, juniorEtk, seniorEtk],
268
+ initializeArgs: [],
269
+ ...opts,
270
+ },
271
+ hre
272
+ );
273
+ const policyPool = await hre.ethers.getContractAt("PolicyPool", poolAddress);
274
+ if (opts.addComponent)
275
+ await policyPool.addComponent(contract.address, 3);
276
+ return contract.address;
277
+ }
278
+
279
+ async function deployRiskModule(
280
+ {
281
+ rmClass,
282
+ rmName,
283
+ poolAddress,
284
+ paAddress,
285
+ collRatio,
286
+ jrCollRatio,
287
+ roc,
288
+ jrRoc,
289
+ ensuroPpFee,
290
+ ensuroCocFee,
291
+ maxPayoutPerPolicy,
292
+ exposureLimit,
293
+ maxDuration,
294
+ moc,
295
+ wallet,
296
+ extraArgs,
297
+ extraConstructorArgs,
298
+ ...opts
299
+ },
300
+ hre
301
+ ) {
302
+ extraArgs = extraArgs || [];
303
+ extraConstructorArgs = extraConstructorArgs || [];
304
+ const { contract } = await deployProxyContract(
305
+ {
306
+ contractClass: rmClass,
307
+ constructorArgs: [poolAddress, paAddress, ...extraConstructorArgs],
308
+ initializeArgs: [
309
+ rmName,
310
+ _W(collRatio),
311
+ _W(ensuroPpFee),
312
+ _W(roc),
313
+ _A(maxPayoutPerPolicy),
314
+ _A(exposureLimit),
315
+ wallet,
316
+ ...extraArgs,
317
+ ],
318
+ ...opts,
319
+ },
320
+ hre
321
+ );
322
+ const rm = contract;
323
+
324
+ if (moc != 1.0) {
325
+ moc = _W(moc);
326
+ await rm.setParam(0, moc);
327
+ }
328
+ if (jrCollRatio != 0.0) {
329
+ jrCollRatio = _W(jrCollRatio);
330
+ await rm.setParam(1, jrCollRatio);
331
+ }
332
+ if (jrRoc != 0.0) {
333
+ jrRoc = _W(jrRoc);
334
+ await rm.setParam(5, jrRoc);
335
+ }
336
+ if (ensuroCocFee != 0) {
337
+ ensuroCocFee = _W(ensuroCocFee);
338
+ await rm.setParam(4, ensuroCocFee);
339
+ }
340
+ if (maxDuration != 24 * 365) {
341
+ await rm.setParam(9, ensuroCocFee);
342
+ }
343
+ const policyPool = await hre.ethers.getContractAt("PolicyPool", poolAddress);
344
+ if (opts.addComponent)
345
+ await policyPool.addComponent(contract.address, 2);
346
+ return contract.address;
347
+ }
348
+
349
+ async function deployFlightDelayRM(opts, hre) {
350
+ opts.extraArgs = [opts.linkToken, [opts.oracle, opts.delayTime, _W(opts.oracleFee), opts.dataJobId, opts.sleepJobId]];
351
+ return deployRiskModule(opts, hre);
352
+ }
353
+
354
+ async function deployPriceRM(opts, hre) {
355
+ opts.extraConstructorArgs = [opts.assetOracle, opts.referenceOracle, _W(opts.slotSize)];
356
+ opts.extraArgs = [opts.oracleTolerance];
357
+ const rm = await deployRiskModule(opts, hre);
358
+ if (opts.minDuration != 3600) {
359
+ // TODO: we will need ORACLE_ADMIN_ROLE
360
+ await rm.setMinDuration(opts.minDuration);
361
+ }
362
+ }
363
+
364
+ async function deploySignedQuoteRM(opts, hre) {
365
+ opts.extraConstructorArgs = [opts.creationIsOpen];
366
+ return deployRiskModule(opts, hre);
367
+ }
368
+
369
+ async function setAssetManager({ reserve, amAddress, liquidityMin, liquidityMiddle, liquidityMax }, hre) {
370
+ const reserveContract = await hre.ethers.getContractAt("Reserve", reserve);
371
+ const tx = await reserveContract.setAssetManager(amAddress, false);
372
+ console.log(`Asset Manager ${amAddress} set to reserve ${reserve}`);
373
+ if (liquidityMin !== undefined || liquidityMiddle !== undefined || liquidityMax !== undefined) {
374
+ liquidityMin = liquidityMin === undefined ? ethers.constants.MaxUint256 : _A(liquidityMin);
375
+ liquidityMiddle = liquidityMiddle === undefined ? ethers.constants.MaxUint256 : _A(liquidityMiddle);
376
+ liquidityMax = liquidityMax === undefined ? ethers.constants.MaxUint256 : _A(liquidityMax);
377
+ const amContract = await hre.ethers.getContractAt(
378
+ "ERC4626AssetManager", // Not relevant if it's ERC4626AssetManager, only need setLiquidityThresholds
379
+ amAddress
380
+ );
381
+
382
+ // To make sure the setAssetManager was executed - wait 2 confirmations
383
+ await tx.wait(process.env.NETWORK !== "localhost" ? 2 : undefined);
384
+ await reserveContract.forwardToAssetManager(
385
+ amContract.interface.encodeFunctionData("setLiquidityThresholds", [liquidityMin, liquidityMiddle, liquidityMax])
386
+ );
387
+ console.log(`setLiquidityThresholds(${liquidityMin}, ${liquidityMiddle}, ${liquidityMax}`);
388
+ }
389
+ }
390
+
391
+ async function deployERC4626AssetManager({ asset, vault, amClass, ...opts }, hre) {
392
+ return (
393
+ await deployContract(
394
+ {
395
+ contractClass: amClass,
396
+ constructorArgs: [asset, vault],
397
+ ...opts,
398
+ },
399
+ hre
400
+ )
401
+ ).contract.address;
402
+ }
403
+
404
+ async function deployAaveAssetManager({ asset, aave, amClass, ...opts }, hre) {
405
+ return (
406
+ await deployContract(
407
+ {
408
+ contractClass: amClass,
409
+ constructorArgs: [asset, aave],
410
+ ...opts,
411
+ },
412
+ hre
413
+ )
414
+ ).contract.address;
415
+ }
416
+
417
+ async function deployWhitelist(
418
+ { wlClass, poolAddress, extraConstructorArgs, extraArgs, eToken, eToken2, eToken3, ...opts },
419
+ hre
420
+ ) {
421
+ extraArgs = extraArgs || [];
422
+ extraConstructorArgs = extraConstructorArgs || [];
423
+ const { contract } = await deployProxyContract(
424
+ {
425
+ contractClass: wlClass,
426
+ constructorArgs: [poolAddress, ...extraConstructorArgs],
427
+ initializeArgs: [...extraArgs],
428
+ ...opts,
429
+ },
430
+ hre
431
+ );
432
+ if (eToken !== undefined) {
433
+ const etk = await hre.ethers.getContractAt("EToken", eToken);
434
+ await etk.setWhitelist(contract.address);
435
+ }
436
+ if (eToken2 !== undefined) {
437
+ const etk = await hre.ethers.getContractAt("EToken", eToken2);
438
+ await etk.setWhitelist(contract.address);
439
+ }
440
+ if (eToken3 !== undefined) {
441
+ const etk = await hre.ethers.getContractAt("EToken", eToken3);
442
+ await etk.setWhitelist(contract.address);
443
+ }
444
+ return contract.address;
445
+ }
446
+
447
+ async function trustfullPolicy({ rmAddress, payout, premium, lossProb, expiration, customer }, hre) {
448
+ const rm = await hre.ethers.getContractAt("TrustfulRiskModule", rmAddress);
449
+ const policyPool = await hre.ethers.getContractAt("PolicyPool", await rm.policyPool());
450
+ const access = await hre.ethers.getContractAt("AccessManager", await policyPool.access());
451
+ const currency = await hre.ethers.getContractAt("IERC20Metadata", await policyPool.currency());
452
+ await grantComponentRole(hre, access, rm, "PRICER_ROLE");
453
+
454
+ customer = customer || (await _getDefaultSigner(hre));
455
+ premium = _A(premium);
456
+
457
+ await currency.approve(policyPool.address, premium);
458
+ lossProb = _W(lossProb);
459
+ if (expiration === undefined) {
460
+ expiration = 3600;
461
+ }
462
+ if (expiration < 1600000000) {
463
+ expiration = Math.round(new Date().getTime() / 1000) + expiration;
464
+ }
465
+ payout = _A(payout);
466
+
467
+ const tx = await rm.newPolicy(payout, premium, lossProb, expiration, customer.address, { gasLimit: 999999 });
468
+ console.log(tx);
469
+ }
470
+
471
+ async function resolvePolicy({ rmAddress, payout, fullPayout, policyId }, hre) {
472
+ const rm = await hre.ethers.getContractAt("TrustfulRiskModule", rmAddress);
473
+ const policyPool = await hre.ethers.getContractAt("PolicyPool", await rm.policyPool());
474
+ const access = await hre.ethers.getContractAt("AccessManager", await policyPool.access());
475
+ await grantComponentRole(hre, access, rm, "RESOLVER_ROLE");
476
+
477
+ let tx;
478
+
479
+ if (fullPayout === undefined) {
480
+ payout = _A(payout);
481
+ tx = await rm.resolvePolicy(policyId, payout);
482
+ } else {
483
+ tx = await rm.resolvePolicyFullPayout(policyId, fullPayout);
484
+ }
485
+ console.log(tx);
486
+ }
487
+
488
+ async function flightDelayPolicy(
489
+ { rmAddress, flight, departure, expectedArrival, tolerance, payout, premium, lossProb, customer },
490
+ hre
491
+ ) {
492
+ const rm = await hre.ethers.getContractAt("FlightDelayRiskModule", rmAddress);
493
+ const policyPool = await hre.ethers.getContractAt("PolicyPool", await rm.policyPool());
494
+ const access = await hre.ethers.getContractAt("AccessManager", await policyPool.access());
495
+ const currency = await hre.ethers.getContractAt("IERC20Metadata", await policyPool.currency());
496
+
497
+ await grantComponentRole(hre, access, rm, "PRICER_ROLE");
498
+ customer = customer || (await _getDefaultSigner(hre));
499
+ premium = _A(premium);
500
+
501
+ await currency.approve(policyPool.address, premium);
502
+ lossProb = _W(lossProb);
503
+ payout = _A(payout);
504
+
505
+ const tx = await rm.newPolicy(
506
+ flight,
507
+ departure,
508
+ expectedArrival,
509
+ tolerance,
510
+ payout,
511
+ premium,
512
+ lossProb,
513
+ customer.address,
514
+ { gasLimit: 999999 }
515
+ );
516
+ console.log(tx);
517
+ }
518
+
519
+ async function listETokens({ poolAddress }, hre) {
520
+ const policyPool = await hre.ethers.getContractAt("PolicyPool", poolAddress);
521
+ const etkCount = await policyPool.getETokenCount();
522
+
523
+ console.log(`Pool has ${etkCount} tokens`);
524
+
525
+ for (i = 0; i < etkCount; i++) {
526
+ const etk = await hre.ethers.getContractAt("EToken", await policyPool.getETokenAt(i));
527
+ const etkName = await etk.name();
528
+ console.log(`eToken at ${etk.address}: ${etkName}`);
529
+ }
530
+ }
531
+
532
+ async function deposit({ etkAddress, amount }, hre) {
533
+ const etk = await hre.ethers.getContractAt("EToken", etkAddress);
534
+ const policyPool = await hre.ethers.getContractAt("PolicyPool", await etk.policyPool());
535
+ const currency = await hre.ethers.getContractAt("IERC20Metadata", await policyPool.currency());
536
+ amount = _A(amount);
537
+ await currency.approve(policyPool.address, amount);
538
+ const tx = await policyPool.deposit(etk.address, amount, { gasLimit: 999999 });
539
+ console.log(tx);
540
+ }
541
+
542
+ function add_task() {
543
+ task("deploy", "Deploys the PolicyPool and other required contracts")
544
+ .addOptionalParam("verify", "Verify contract in Etherscan", false, types.boolean)
545
+ .addOptionalParam("currName", "Name of Test Currency", "Ensuro Test USD", types.str)
546
+ .addOptionalParam("currSymbol", "Symbol of Test Currency", "EUSD", types.str)
547
+ .addOptionalParam("initialSupply", "Initial supply in the test currency", 2000, types.int)
548
+ .addOptionalParam("nftName", "Name of Policies NFT Token", "Ensuro Policies NFT", types.str)
549
+ .addOptionalParam("nftSymbol", "Symbol of Policies NFT Token", "EPOL", types.str)
550
+ .addOptionalParam("currencyAddress", "Currency Address", undefined, types.address)
551
+ .addOptionalParam("accessAddress", "AccessManager Address", undefined, types.address)
552
+ .addParam("treasuryAddress", "Treasury Address", types.address)
553
+ .setAction(async function (taskArgs, hre) {
554
+ if (taskArgs.currencyAddress === undefined) {
555
+ taskArgs.saveAddr = "CURRENCY";
556
+ taskArgs.currencyAddress = await deployTestCurrency(taskArgs, hre);
557
+ }
558
+ if (taskArgs.accessAddress === undefined) {
559
+ taskArgs.saveAddr = "ACCESSMANAGER";
560
+ taskArgs.accessAddress = await deployAccessManager(taskArgs, hre);
561
+ }
562
+ taskArgs.saveAddr = "POOL";
563
+ let policyPoolAddress = await deployPolicyPool(taskArgs, hre);
564
+ });
565
+
566
+ task("deploy:testCurrency", "Deploys the Test Currency")
567
+ .addOptionalParam("verify", "Verify contract in Etherscan", false, types.boolean)
568
+ .addOptionalParam("saveAddr", "Save created contract address", "CURRENCY", types.str)
569
+ .addOptionalParam("currName", "Name of Test Currency", "Ensuro Test USD", types.str)
570
+ .addOptionalParam("currSymbol", "Symbol of Test Currency", "EUSD", types.str)
571
+ .addOptionalParam("initialSupply", "Initial supply in the test currency", 2000, types.int)
572
+ .setAction(deployTestCurrency);
573
+
574
+ task("deploy:accessManager", "Deploys the AccessManager")
575
+ .addOptionalParam("verify", "Verify contract in Etherscan", false, types.boolean)
576
+ .addOptionalParam("saveAddr", "Save created contract address", "ACCESSMANAGER", types.str)
577
+ .setAction(deployAccessManager);
578
+
579
+ task("deploy:pool", "Deploys the PolicyPool")
580
+ .addOptionalParam("verify", "Verify contract in Etherscan", false, types.boolean)
581
+ .addOptionalParam("saveAddr", "Save created contract address", "POOL", types.str)
582
+ .addOptionalParam("nftName", "Name of Policies NFT Token", "Ensuro Policies NFT", types.str)
583
+ .addOptionalParam("nftSymbol", "Symbol of Policies NFT Token", "EPOL", types.str)
584
+ .addOptionalParam("treasuryAddress", "Treasury Address", ethers.constants.AddressZero, types.address)
585
+ .addParam("currencyAddress", "Currency Address", types.address)
586
+ .addParam("accessAddress", "AccessManager Address", types.address)
587
+ .setAction(deployPolicyPool);
588
+
589
+ task("deploy:eToken", "Deploy an EToken and adds it to the pool")
590
+ .addOptionalParam("verify", "Verify contract in Etherscan", false, types.boolean)
591
+ .addOptionalParam("saveAddr", "Save created contract address", "ETOKEN", types.str)
592
+ .addOptionalParam("addComponent", "Adds the new component to the pool", true, types.boolean)
593
+ .addParam("poolAddress", "PolicyPool Address", types.address)
594
+ .addParam("etkName", "Name of EToken", types.str)
595
+ .addParam("etkSymbol", "Symbol of EToken", types.str)
596
+ .addOptionalParam("maxUtilizationRate", "Max Utilization Rate", 1.0, types.float)
597
+ .addOptionalParam("poolLoanInterestRate", "Interest rate when pool takes money from eToken", 0.05, types.float)
598
+ .setAction(deployEToken);
599
+
600
+ task("deploy:premiumsAccount", "Deploy a premiums account")
601
+ .addOptionalParam("verify", "Verify contract in Etherscan", false, types.boolean)
602
+ .addOptionalParam("saveAddr", "Save created contract address", "PA", types.str)
603
+ .addOptionalParam("addComponent", "Adds the new component to the pool", true, types.boolean)
604
+ .addParam("poolAddress", "PolicyPool Address", types.address)
605
+ .addParam("juniorEtk", "Junior EToken Address", types.address)
606
+ .addParam("seniorEtk", "Senior EToken Address", types.address)
607
+ .setAction(deployPremiumsAccount);
608
+
609
+ task("deploy:riskModule", "Deploys a RiskModule and adds it to the pool")
610
+ .addOptionalParam("verify", "Verify contract in Etherscan", false, types.boolean)
611
+ .addOptionalParam("saveAddr", "Save created contract address", "RM", types.str)
612
+ .addOptionalParam("addComponent", "Adds the new component to the pool", true, types.boolean)
613
+ .addParam("poolAddress", "PolicyPool Address", types.address)
614
+ .addParam("paAddress", "PremiumsAccount Address", types.address)
615
+ .addOptionalParam("rmClass", "RiskModule contract", "TrustfulRiskModule", types.str)
616
+ .addOptionalParam("rmName", "Name of the RM", "Test RM", types.str)
617
+ .addOptionalParam("collRatio", "Collateralization ratio", 1.0, types.float)
618
+ .addOptionalParam("jrCollRatio", "Junior Collateralization ratio", 0.0, types.float)
619
+ .addOptionalParam("ensuroPpFee", "Ensuro Pure Premium Fee", 0.02, types.float)
620
+ .addOptionalParam("ensuroCocFee", "Ensuro Coc Fee", 0.1, types.float)
621
+ .addOptionalParam("roc", "Interest rate paid to Senior LPs for solvency capital", 0.05, types.float)
622
+ .addOptionalParam("jrRoc", "Interest rate paid to Junior LPs for solvency capital", 0.0, types.float)
623
+ .addOptionalParam("maxPayoutPerPolicy", "Max Payout Per policy", 10000, types.float)
624
+ .addOptionalParam("exposureLimit", "Exposure (sum of payouts) limit for the RM", 1e6, types.float)
625
+ .addOptionalParam("maxDuration", "Maximum policy duration in hours", 24 * 365, types.int)
626
+ .addOptionalParam("moc", "Margin of Conservativism", 1.0, types.float)
627
+ .addParam("wallet", "RM address", types.address)
628
+ .setAction(deployRiskModule);
629
+
630
+ task("deploy:signedQuoteRiskModule", "Deploys a RiskModule and adds it to the pool")
631
+ .addOptionalParam("verify", "Verify contract in Etherscan", false, types.boolean)
632
+ .addOptionalParam("saveAddr", "Save created contract address", "RM", types.str)
633
+ .addOptionalParam("addComponent", "Adds the new component to the pool", true, types.boolean)
634
+ .addParam("poolAddress", "PolicyPool Address", types.address)
635
+ .addParam("paAddress", "PremiumsAccount Address", types.address)
636
+ .addOptionalParam("rmClass", "RiskModule contract", "SignedQuoteRiskModule", types.str)
637
+ .addOptionalParam("rmName", "Name of the RM", "Test RM", types.str)
638
+ .addOptionalParam("collRatio", "Collateralization ratio", 1.0, types.float)
639
+ .addOptionalParam("jrCollRatio", "Junior Collateralization ratio", 0.0, types.float)
640
+ .addOptionalParam("ensuroPpFee", "Ensuro Pure Premium Fee", 0.02, types.float)
641
+ .addOptionalParam("ensuroCocFee", "Ensuro Coc Fee", 0.1, types.float)
642
+ .addOptionalParam("roc", "Interest rate paid to Senior LPs for solvency capital", 0.05, types.float)
643
+ .addOptionalParam("jrRoc", "Interest rate paid to Junior LPs for solvency capital", 0.0, types.float)
644
+ .addOptionalParam("maxPayoutPerPolicy", "Max Payout Per policy", 10000, types.float)
645
+ .addOptionalParam("exposureLimit", "Exposure (sum of payouts) limit for the RM", 1e6, types.float)
646
+ .addOptionalParam("maxDuration", "Maximum policy duration in hours", 24 * 365, types.int)
647
+ .addOptionalParam("moc", "Margin of Conservativism", 1.0, types.float)
648
+ .addOptionalParam("creationIsOpen", "Indicates if anyone can create policies (with a quote)", true, types.boolean)
649
+ .addParam("wallet", "RM address", types.address)
650
+ .setAction(deploySignedQuoteRM);
651
+
652
+ task("deploy:priceRiskModule", "Deploys and injects a Price RiskModule")
653
+ .addOptionalParam("verify", "Verify contract in Etherscan", false, types.boolean)
654
+ .addOptionalParam("saveAddr", "Save created contract address", "RM", types.str)
655
+ .addOptionalParam("addComponent", "Adds the new component to the pool", true, types.boolean)
656
+ .addParam("poolAddress", "PolicyPool Address", types.address)
657
+ .addParam("paAddress", "PremiumsAccount Address", types.address)
658
+ .addOptionalParam("rmClass", "RiskModule contract", "PriceRiskModule", types.str)
659
+ .addOptionalParam("rmName", "Name of the RM", "Price Risk Module", types.str)
660
+ .addOptionalParam("collRatio", "Collateralization ratio", 1.0, types.float)
661
+ .addOptionalParam("jrCollRatio", "Junior Collateralization ratio", 0.0, types.float)
662
+ .addOptionalParam("ensuroPpFee", "Ensuro Pure Premium Fee", 0.02, types.float)
663
+ .addOptionalParam("ensuroCocFee", "Ensuro Coc Fee", 0.1, types.float)
664
+ .addOptionalParam("roc", "Interest rate paid to Senior LPs for solvency capital", 0.05, types.float)
665
+ .addOptionalParam("jrRoc", "Interest rate paid to Junior LPs for solvency capital", 0.0, types.float)
666
+ .addOptionalParam("maxPayoutPerPolicy", "Max Payout Per policy", 10000, types.float)
667
+ .addOptionalParam("exposureLimit", "Exposure (sum of payouts) limit for the RM", 1e6, types.float)
668
+ .addOptionalParam("maxDuration", "Maximum policy duration in hours", 24 * 365, types.int)
669
+ .addOptionalParam("moc", "Margin of Conservativism", 1.0, types.float)
670
+ .addParam("wallet", "RM address", types.address)
671
+ .addParam("assetOracle", "Insured asset oracle address", types.address)
672
+ .addOptionalParam("referenceOracle", "Reference currency address", ethers.constants.AddressZero, types.address)
673
+ .addOptionalParam("slotSize", "Slot size", 0.01, types.float)
674
+ .addOptionalParam("oracleTolerance", "Oracle age tolerance", 1800, types.int)
675
+ .addOptionalParam("minDuration", "Minimum time that must elapse before a policy can be triggered", 3600, types.int)
676
+ .setAction(deployPriceRM);
677
+
678
+ task("ens:setAssetManager", "Sets an asset manager to a reserve")
679
+ .addParam("reserve", "Reserve Address", types.address)
680
+ .addParam("amAddress", "Address of Asset Manager (reuse one already deployed)", types.address)
681
+ .addOptionalParam("liquidityMin", "liquidityMin", undefined, types.float)
682
+ .addOptionalParam("liquidityMiddle", "liquidityMiddle", undefined, types.float)
683
+ .addOptionalParam("liquidityMax", "liquidityMax", undefined, types.float)
684
+ .setAction(setAssetManager);
685
+
686
+ task("deploy:erc4626AssetManager", "Deploys an ERC4626 AssetManager")
687
+ .addOptionalParam("verify", "Verify contract in Etherscan", false, types.boolean)
688
+ .addOptionalParam("saveAddr", "Save created contract address", "ASSETMANAGER", types.str)
689
+ .addParam("asset", "Asset Address", types.address)
690
+ .addParam("vault", "Vault Address", types.address)
691
+ .addOptionalParam("amClass", "AssetManager contract", "ERC4626AssetManager", types.str)
692
+ .setAction(deployERC4626AssetManager);
693
+
694
+ task("deploy:aaveAssetManager", "Deploys a AaveAssetManager")
695
+ .addOptionalParam("verify", "Verify contract in Etherscan", false, types.boolean)
696
+ .addOptionalParam("saveAddr", "Save created contract address", "ASSETMANAGER", types.str)
697
+ .addParam("asset", "Asset Address", types.address)
698
+ .addParam("aave", "AAVE LendingPool Address", types.address)
699
+ .addOptionalParam("amClass", "AssetManager contract", "AAVEv3AssetManager", types.str)
700
+ .setAction(deployAaveAssetManager);
701
+
702
+ task("deploy:whitelist", "Deploys a Whitelisting contract")
703
+ .addOptionalParam("verify", "Verify contract in Etherscan", false, types.boolean)
704
+ .addOptionalParam("saveAddr", "Save created contract address", "WHITELIST", types.str)
705
+ .addOptionalParam("wlClass", "Whitelisting contract", "LPManualWhitelist", types.str)
706
+ .addOptionalParam("eToken", "Set the Whitelist to a given eToken", undefined, types.address)
707
+ .addOptionalParam("eToken2", "Set the Whitelist to a given eToken", undefined, types.address)
708
+ .addOptionalParam("eToken3", "Set the Whitelist to a given eToken", undefined, types.address)
709
+ .addParam("poolAddress", "PolicyPool Address", types.address)
710
+ .setAction(deployWhitelist);
711
+
712
+ task("ens:trustfullPolicy", "Creates a TrustfulRiskModule Policy")
713
+ .addParam("rmAddress", "RiskModule address", types.address)
714
+ .addParam("payout", "Payout for customer in case policy is triggered", undefined, types.int)
715
+ .addParam("premium", "Premium the customer pays", undefined, types.int)
716
+ .addParam("lossProb", "Probability of policy being triggered", undefined, types.float)
717
+ .addOptionalParam("expiration", "Expiration of the policy (relative or absolute)", undefined, types.int)
718
+ .addOptionalParam("customer", "Customer", undefined, types.address)
719
+ .setAction(trustfullPolicy);
720
+
721
+ task("ens:resolvePolicy", "Resolves a TrustfulRiskModule Policy")
722
+ .addParam("rmAddress", "RiskModule address", types.address)
723
+ .addParam("policyId", "Id of the policy", undefined, types.int)
724
+ .addOptionalParam("payout", "Payout for customer in case policy is triggered", undefined, types.int)
725
+ .addOptionalParam("fullPayout", "Full payout or not", undefined, types.boolean)
726
+ .setAction(resolvePolicy);
727
+
728
+ task("ens:flightDelayPolicy", "Creates a Flight Delay Policy")
729
+ .addParam("rmAddress", "RiskModule address", types.address)
730
+ .addParam("flight", "Flight Number as String (ex: NAX105)", types.str)
731
+ .addParam("departure", "Departure in epoch seconds (ex: 1631817600)", undefined, types.int)
732
+ .addParam("expectedArrival", "Expected arrival in epoch seconds (ex: 1631824800)", undefined, types.int)
733
+ .addOptionalParam(
734
+ "tolerance",
735
+ "In seconds, the tolerance margin after expectedArrival before trigger the policy",
736
+ 12 * 3600,
737
+ types.int
738
+ )
739
+ .addParam("payout", "Payout for customer in case policy is triggered", undefined, types.int)
740
+ .addParam("premium", "Premium the customer pays", undefined, types.int)
741
+ .addParam("lossProb", "Probability of policy being triggered", undefined, types.float)
742
+ .addOptionalParam("customer", "Customer", undefined, types.address)
743
+ .setAction(flightDelayPolicy);
744
+
745
+ task("ens:listETokens", "Lists eTokens")
746
+ .addParam("poolAddress", "PolicyPool Address", types.address)
747
+ .setAction(listETokens);
748
+
749
+ task("ens:deposit", "Deposits in a given eToken")
750
+ .addParam("etkAddress", "EToken address", types.address)
751
+ .addParam("amount", "Amount to Deposit", undefined, types.int)
752
+ .setAction(deposit);
753
+
754
+ task("ens:grantRole", "Grants a given role")
755
+ .addParam("contractAddress", "Contract", undefined, types.address)
756
+ .addParam("role", "Role", types.str)
757
+ .addOptionalParam("account", "Account", undefined, types.address)
758
+ .addOptionalParam(
759
+ "component",
760
+ "Address of the component if it's a component role",
761
+ ethers.constants.AddressZero,
762
+ types.address
763
+ )
764
+ .setAction(grantRoleTask);
765
+ }
766
+
767
+ module.exports = {
768
+ add_task,
769
+ saveAddress,
770
+ logContractCreated,
771
+ deployContract,
772
+ deployProxyContract,
773
+ grantRole,
774
+ grantComponentRole,
775
+ deployRiskModule,
776
+ deploySignedQuoteRM,
777
+ setAssetManager,
778
+ deployWhitelist,
779
+ };