@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
package/js/test-utils.js
CHANGED
|
@@ -1,12 +1,8 @@
|
|
|
1
|
-
const { expect } = require("chai");
|
|
2
1
|
const hre = require("hardhat");
|
|
3
|
-
const {
|
|
4
|
-
const {
|
|
5
|
-
const { findAll } = require("solidity-ast/utils");
|
|
6
|
-
const helpers = require("@nomicfoundation/hardhat-network-helpers");
|
|
2
|
+
const { _W, grantRole, getTransactionEvent } = require("../js/utils");
|
|
3
|
+
const { RiskModuleParameter } = require("../js/enums");
|
|
7
4
|
|
|
8
|
-
|
|
9
|
-
DAY = 3600 * 24;
|
|
5
|
+
const { AddressZero } = hre.ethers.constants;
|
|
10
6
|
|
|
11
7
|
async function initCurrency(options, initial_targets, initial_balances) {
|
|
12
8
|
const Currency = await hre.ethers.getContractFactory("TestCurrency");
|
|
@@ -25,36 +21,7 @@ async function initCurrency(options, initial_targets, initial_balances) {
|
|
|
25
21
|
return currency;
|
|
26
22
|
}
|
|
27
23
|
|
|
28
|
-
async function
|
|
29
|
-
return Promise.all(
|
|
30
|
-
sources.map(async function (source, index) {
|
|
31
|
-
await currency.connect(source).approve(spender.address, amounts[index]);
|
|
32
|
-
})
|
|
33
|
-
);
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
async function check_balances(currency, users, amounts) {
|
|
37
|
-
return Promise.all(
|
|
38
|
-
users.map(async function (user, index) {
|
|
39
|
-
expect(await currency.balanceOf(user.address)).to.equal(amounts[index]);
|
|
40
|
-
})
|
|
41
|
-
);
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
const RiskModuleParameter = {
|
|
45
|
-
moc: 0,
|
|
46
|
-
jrCollRatio: 1,
|
|
47
|
-
collRatio: 2,
|
|
48
|
-
ensuroPpFee: 3,
|
|
49
|
-
ensuroCocFee: 4,
|
|
50
|
-
jrRoc: 5,
|
|
51
|
-
srRoc: 6,
|
|
52
|
-
maxPayoutPerPolicy: 7,
|
|
53
|
-
exposureLimit: 8,
|
|
54
|
-
maxDuration: 9,
|
|
55
|
-
};
|
|
56
|
-
|
|
57
|
-
const createRiskModule = async function (
|
|
24
|
+
async function createRiskModule(
|
|
58
25
|
pool,
|
|
59
26
|
premiumsAccount,
|
|
60
27
|
contractFactory,
|
|
@@ -99,7 +66,7 @@ const createRiskModule = async function (
|
|
|
99
66
|
await rm.setParam(RiskModuleParameter.moc, moc);
|
|
100
67
|
}
|
|
101
68
|
return rm;
|
|
102
|
-
}
|
|
69
|
+
}
|
|
103
70
|
|
|
104
71
|
async function addRiskModule(
|
|
105
72
|
pool,
|
|
@@ -135,7 +102,7 @@ async function addRiskModule(
|
|
|
135
102
|
return rm;
|
|
136
103
|
}
|
|
137
104
|
|
|
138
|
-
|
|
105
|
+
async function createEToken(
|
|
139
106
|
pool,
|
|
140
107
|
{ etkName, etkSymbol, maxUtilizationRate, poolLoanInterestRate, extraArgs, extraConstructorArgs }
|
|
141
108
|
) {
|
|
@@ -160,9 +127,9 @@ const createEToken = async function (
|
|
|
160
127
|
|
|
161
128
|
await etk.deployed();
|
|
162
129
|
return etk;
|
|
163
|
-
}
|
|
130
|
+
}
|
|
164
131
|
|
|
165
|
-
|
|
132
|
+
async function addEToken(
|
|
166
133
|
pool,
|
|
167
134
|
{ etkName, etkSymbol, maxUtilizationRate, poolLoanInterestRate, extraArgs, extraConstructorArgs }
|
|
168
135
|
) {
|
|
@@ -176,42 +143,12 @@ addEToken = async function addEToken(
|
|
|
176
143
|
});
|
|
177
144
|
await pool.addComponent(etk.address, 1);
|
|
178
145
|
return etk;
|
|
179
|
-
};
|
|
180
|
-
|
|
181
|
-
async function expected_change(protocol_attribute, initial, change) {
|
|
182
|
-
change = BigNumber.from(change);
|
|
183
|
-
let actual_value = await protocol_attribute();
|
|
184
|
-
expect(actual_value.sub(initial)).to.equal(change);
|
|
185
|
-
return actual_value;
|
|
186
146
|
}
|
|
187
147
|
|
|
188
|
-
/**
|
|
189
|
-
* Finds an event in the receipt
|
|
190
|
-
* @param {Interface} interface The interface of the contract that contains the requested event
|
|
191
|
-
* @param {TransactionReceipt} receipt Transaction receipt containing the events in the logs
|
|
192
|
-
* @param {String} eventName The name of the event we are interested in
|
|
193
|
-
* @returns {LogDescription}
|
|
194
|
-
*/
|
|
195
|
-
const getTransactionEvent = function (interface, receipt, eventName) {
|
|
196
|
-
// for each log in the transaction receipt
|
|
197
|
-
for (const log of receipt.logs) {
|
|
198
|
-
let parsedLog;
|
|
199
|
-
try {
|
|
200
|
-
parsedLog = interface.parseLog(log);
|
|
201
|
-
} catch (error) {
|
|
202
|
-
continue;
|
|
203
|
-
}
|
|
204
|
-
if (parsedLog.name == eventName) {
|
|
205
|
-
return parsedLog;
|
|
206
|
-
}
|
|
207
|
-
}
|
|
208
|
-
return null; // not found
|
|
209
|
-
};
|
|
210
|
-
|
|
211
148
|
const randomAddress = "0x89cDb70Fee571251a66E34caa1673cE40f7549Dc";
|
|
212
149
|
|
|
213
150
|
/**
|
|
214
|
-
* Deploys
|
|
151
|
+
* Deploys the PolicyPool contract and AccessManager
|
|
215
152
|
*
|
|
216
153
|
* By default deployes de PolicyPool and AccessManager and grants LEVEL 1, 2, 3 permissions
|
|
217
154
|
*
|
|
@@ -224,7 +161,7 @@ const randomAddress = "0x89cDb70Fee571251a66E34caa1673cE40f7549Dc";
|
|
|
224
161
|
* - .grantRoles: default []. List of additional roles to grant
|
|
225
162
|
* - .dontGrantL123Roles: if specified, doesn't grants LEVEL1, 2 and 3 roles.
|
|
226
163
|
*/
|
|
227
|
-
async function deployPool(
|
|
164
|
+
async function deployPool(options) {
|
|
228
165
|
const PolicyPool = await hre.ethers.getContractFactory("PolicyPool");
|
|
229
166
|
const AccessManager = await hre.ethers.getContractFactory("AccessManager");
|
|
230
167
|
|
|
@@ -266,14 +203,10 @@ async function deployPool(hre, options) {
|
|
|
266
203
|
return policyPool;
|
|
267
204
|
}
|
|
268
205
|
|
|
269
|
-
async function deployPremiumsAccount(
|
|
206
|
+
async function deployPremiumsAccount(pool, options, addToPool = true) {
|
|
270
207
|
const PremiumsAccount = await hre.ethers.getContractFactory("PremiumsAccount");
|
|
271
208
|
const premiumsAccount = await hre.upgrades.deployProxy(PremiumsAccount, [], {
|
|
272
|
-
constructorArgs: [
|
|
273
|
-
pool.address,
|
|
274
|
-
options.jrEtkAddr || hre.ethers.constants.AddressZero,
|
|
275
|
-
options.srEtkAddr || hre.ethers.constants.AddressZero,
|
|
276
|
-
],
|
|
209
|
+
constructorArgs: [pool.address, options.jrEtkAddr || AddressZero, options.srEtkAddr || AddressZero],
|
|
277
210
|
kind: "uups",
|
|
278
211
|
unsafeAllow: ["delegatecall"], // This holds, because EToken is a reserve and uses delegatecall
|
|
279
212
|
});
|
|
@@ -285,112 +218,6 @@ async function deployPremiumsAccount(hre, pool, options, addToPool = true) {
|
|
|
285
218
|
return premiumsAccount;
|
|
286
219
|
}
|
|
287
220
|
|
|
288
|
-
async function _getDefaultSigner(hre) {
|
|
289
|
-
const signers = await hre.ethers.getSigners();
|
|
290
|
-
return signers[0];
|
|
291
|
-
}
|
|
292
|
-
|
|
293
|
-
async function grantRole(hre, contract, role, user) {
|
|
294
|
-
let userAddress;
|
|
295
|
-
if (user === undefined) {
|
|
296
|
-
user = await _getDefaultSigner(hre);
|
|
297
|
-
userAddress = user.address;
|
|
298
|
-
} else {
|
|
299
|
-
userAddress = user;
|
|
300
|
-
}
|
|
301
|
-
if (!(await contract.hasRole(getRole(role), userAddress))) {
|
|
302
|
-
await contract.grantRole(getRole(role), userAddress);
|
|
303
|
-
}
|
|
304
|
-
}
|
|
305
|
-
|
|
306
|
-
async function grantComponentRole(hre, accessManager, component, role, user) {
|
|
307
|
-
let userAddress;
|
|
308
|
-
if (user === undefined) {
|
|
309
|
-
user = await _getDefaultSigner(hre);
|
|
310
|
-
userAddress = user.address;
|
|
311
|
-
} else {
|
|
312
|
-
userAddress = user.address === undefined ? user : user.address;
|
|
313
|
-
}
|
|
314
|
-
const componentRole = getComponentRole(component.address, getRole(role));
|
|
315
|
-
if (!(await accessManager.hasRole(componentRole, userAddress))) {
|
|
316
|
-
await accessManager.grantComponentRole(component.address, getRole(role), userAddress);
|
|
317
|
-
}
|
|
318
|
-
}
|
|
319
|
-
|
|
320
|
-
const _E = hre.ethers.utils.parseEther;
|
|
321
|
-
|
|
322
|
-
const _BN = hre.ethers.BigNumber.from;
|
|
323
|
-
|
|
324
|
-
const WAD = _BN(10).pow(18); // 1e18
|
|
325
|
-
|
|
326
|
-
const RAY = _BN(10).pow(27); // 1e27
|
|
327
|
-
|
|
328
|
-
/**
|
|
329
|
-
* Creates a fixed-point conversion function for the desired number of decimals
|
|
330
|
-
* @param decimals The number of decimals. Must be >= 6.
|
|
331
|
-
* @returns The amount function created. The function can receive strings (recommended),
|
|
332
|
-
* floats/doubles (not recommended) and integers.
|
|
333
|
-
*
|
|
334
|
-
* Floats will be rounded to 6 decimal before scaling.
|
|
335
|
-
*/
|
|
336
|
-
function amountFunction(decimals) {
|
|
337
|
-
return function (value) {
|
|
338
|
-
if (value === undefined) return undefined;
|
|
339
|
-
|
|
340
|
-
if (typeof value === "string" || value instanceof String) {
|
|
341
|
-
return hre.ethers.utils.parseUnits(value, decimals);
|
|
342
|
-
}
|
|
343
|
-
|
|
344
|
-
if (!Number.isInteger(value)) {
|
|
345
|
-
return _BN(Math.round(value * 1e6)).mul(_BN(Math.pow(10, decimals - 6)));
|
|
346
|
-
}
|
|
347
|
-
|
|
348
|
-
return _BN(value).mul(_BN(10).pow(decimals));
|
|
349
|
-
};
|
|
350
|
-
}
|
|
351
|
-
|
|
352
|
-
const _W = amountFunction(18);
|
|
353
|
-
|
|
354
|
-
const _R = amountFunction(27);
|
|
355
|
-
|
|
356
|
-
/**
|
|
357
|
-
* Builds the component role identifier
|
|
358
|
-
*
|
|
359
|
-
* Mimics the behaviour of the PolicyPoolConfig.getComponentRole method
|
|
360
|
-
*
|
|
361
|
-
* Component roles are roles created doing XOR between the component
|
|
362
|
-
* address and the original role.
|
|
363
|
-
*
|
|
364
|
-
* Example:
|
|
365
|
-
* getComponentRole("0xc6e7DF5E7b4f2A278906862b61205850344D4e7d", "ORACLE_ADMIN_ROLE")
|
|
366
|
-
* // "0x05e01b185238b49f750d03d945e38a7f6c3be8b54de0ee42d481eb7814f0d3a8"
|
|
367
|
-
*/
|
|
368
|
-
function getComponentRole(componentAddress, role) {
|
|
369
|
-
if (!role.startsWith("0x")) role = getRole(role);
|
|
370
|
-
|
|
371
|
-
// 32 byte array
|
|
372
|
-
const bytesRole = hre.ethers.utils.arrayify(role);
|
|
373
|
-
|
|
374
|
-
// 20 byte array
|
|
375
|
-
const bytesAddress = hre.ethers.utils.arrayify(componentAddress);
|
|
376
|
-
|
|
377
|
-
// xor each byte, padding bytesAddress with zeros at the end
|
|
378
|
-
return hre.ethers.utils.hexlify(bytesRole.map((elem, idx) => elem ^ (bytesAddress[idx] || 0)));
|
|
379
|
-
}
|
|
380
|
-
|
|
381
|
-
/*
|
|
382
|
-
Builds AccessControl error message for comparison in tests
|
|
383
|
-
*/
|
|
384
|
-
function accessControlMessage(address, component, role) {
|
|
385
|
-
const roleHash = component !== null ? getComponentRole(component, role) : getRole(role);
|
|
386
|
-
|
|
387
|
-
return `AccessControl: account ${address.toLowerCase()} is missing role ${roleHash}`;
|
|
388
|
-
}
|
|
389
|
-
|
|
390
|
-
function makePolicyId(rm, internalId) {
|
|
391
|
-
return hre.ethers.BigNumber.from(rm.address).shl(96).add(internalId);
|
|
392
|
-
}
|
|
393
|
-
|
|
394
221
|
async function makePolicy(pool, rm, cust, payout, premium, lossProb, expiration, internalId, method = "newPolicy") {
|
|
395
222
|
let tx = await rm.connect(cust)[method](payout, premium, lossProb, expiration, cust.address, internalId);
|
|
396
223
|
let receipt = await tx.wait();
|
|
@@ -399,71 +226,15 @@ async function makePolicy(pool, rm, cust, payout, premium, lossProb, expiration,
|
|
|
399
226
|
return newPolicyEvt;
|
|
400
227
|
}
|
|
401
228
|
|
|
402
|
-
function getRole(role) {
|
|
403
|
-
return role === "DEFAULT_ADMIN_ROLE"
|
|
404
|
-
? "0x0000000000000000000000000000000000000000000000000000000000000000"
|
|
405
|
-
: hre.ethers.utils.keccak256(hre.ethers.utils.toUtf8Bytes(role));
|
|
406
|
-
}
|
|
407
|
-
|
|
408
|
-
async function getStorageLayout(contractSrc, contractName) {
|
|
409
|
-
const buildInfo = await hre.artifacts.getBuildInfo(`${contractSrc}:${contractName}`);
|
|
410
|
-
if (buildInfo === undefined) throw new Error(`Contract ${contractSrc}:${contractName} not in artifacts`);
|
|
411
|
-
|
|
412
|
-
const solcOutput = buildInfo.output;
|
|
413
|
-
|
|
414
|
-
const storageLayouts = {};
|
|
415
|
-
|
|
416
|
-
for (const def of findAll("ContractDefinition", solcOutput.sources[contractSrc].ast)) {
|
|
417
|
-
storageLayouts[def.name] = solcOutput.contracts[contractSrc][def.name].storageLayout;
|
|
418
|
-
}
|
|
419
|
-
|
|
420
|
-
return storageLayouts[contractName];
|
|
421
|
-
}
|
|
422
|
-
|
|
423
|
-
function makeQuoteMessage({ rmAddress, payout, premium, lossProb, expiration, policyData, validUntil }) {
|
|
424
|
-
return ethers.utils.solidityPack(
|
|
425
|
-
["address", "uint256", "uint256", "uint256", "uint40", "bytes32", "uint40"],
|
|
426
|
-
[rmAddress, payout, premium, lossProb, expiration, policyData, validUntil]
|
|
427
|
-
);
|
|
428
|
-
}
|
|
429
|
-
|
|
430
|
-
async function makeSignedQuote(signer, policyParams) {
|
|
431
|
-
const quoteMessage = makeQuoteMessage(policyParams);
|
|
432
|
-
return ethers.utils.splitSignature(await signer.signMessage(ethers.utils.arrayify(quoteMessage)));
|
|
433
|
-
}
|
|
434
|
-
|
|
435
229
|
if (process.env.ENABLE_HH_WARNINGS !== "yes") hre.upgrades.silenceWarnings();
|
|
436
230
|
|
|
437
231
|
module.exports = {
|
|
438
|
-
_BN,
|
|
439
|
-
_E,
|
|
440
|
-
_R,
|
|
441
|
-
_W,
|
|
442
|
-
accessControlMessage,
|
|
443
232
|
addEToken,
|
|
444
233
|
addRiskModule,
|
|
445
|
-
amountFunction,
|
|
446
|
-
approve_multiple,
|
|
447
|
-
check_balances,
|
|
448
234
|
createEToken,
|
|
449
235
|
createRiskModule,
|
|
450
|
-
DAY,
|
|
451
236
|
deployPool,
|
|
452
237
|
deployPremiumsAccount,
|
|
453
|
-
expected_change,
|
|
454
|
-
getComponentRole,
|
|
455
|
-
getRole,
|
|
456
|
-
getStorageLayout,
|
|
457
|
-
getTransactionEvent,
|
|
458
|
-
grantComponentRole,
|
|
459
|
-
grantRole,
|
|
460
238
|
initCurrency,
|
|
461
239
|
makePolicy,
|
|
462
|
-
makePolicyId,
|
|
463
|
-
makeQuoteMessage,
|
|
464
|
-
makeSignedQuote,
|
|
465
|
-
RAY,
|
|
466
|
-
RiskModuleParameter,
|
|
467
|
-
WAD,
|
|
468
|
-
WEEK,
|
|
469
240
|
};
|
package/js/utils.js
ADDED
|
@@ -0,0 +1,264 @@
|
|
|
1
|
+
const { findAll } = require("solidity-ast/utils");
|
|
2
|
+
const ethers = require("ethers");
|
|
3
|
+
const helpers = require("@nomicfoundation/hardhat-network-helpers");
|
|
4
|
+
|
|
5
|
+
const _E = ethers.utils.parseEther;
|
|
6
|
+
const _BN = ethers.BigNumber.from;
|
|
7
|
+
const WAD = _BN(10).pow(18); // 1e18
|
|
8
|
+
const RAY = _BN(10).pow(27); // 1e27
|
|
9
|
+
|
|
10
|
+
async function getStorageLayout(hre, contractSrc, contractName) {
|
|
11
|
+
const buildInfo = await hre.artifacts.getBuildInfo(`${contractSrc}:${contractName}`);
|
|
12
|
+
if (buildInfo === undefined) throw new Error(`Contract ${contractSrc}:${contractName} not in artifacts`);
|
|
13
|
+
|
|
14
|
+
const solcOutput = buildInfo.output;
|
|
15
|
+
|
|
16
|
+
const storageLayouts = {};
|
|
17
|
+
|
|
18
|
+
for (const def of findAll("ContractDefinition", solcOutput.sources[contractSrc].ast)) {
|
|
19
|
+
storageLayouts[def.name] = solcOutput.contracts[contractSrc][def.name].storageLayout;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
return storageLayouts[contractName];
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Creates a fixed-point conversion function for the desired number of decimals
|
|
27
|
+
* @param decimals The number of decimals. Must be >= 6.
|
|
28
|
+
* @returns The amount function created. The function can receive strings (recommended),
|
|
29
|
+
* floats/doubles (not recommended) and integers.
|
|
30
|
+
*
|
|
31
|
+
* Floats will be rounded to 6 decimal before scaling.
|
|
32
|
+
*/
|
|
33
|
+
function amountFunction(decimals) {
|
|
34
|
+
return function (value) {
|
|
35
|
+
if (value === undefined) return undefined;
|
|
36
|
+
|
|
37
|
+
if (typeof value === "string" || value instanceof String) {
|
|
38
|
+
return ethers.utils.parseUnits(value, decimals);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
if (!Number.isInteger(value)) {
|
|
42
|
+
return _BN(Math.round(value * 1e6)).mul(_BN(Math.pow(10, decimals - 6)));
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
return _BN(value).mul(_BN(10).pow(decimals));
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/** Wad function */
|
|
50
|
+
const _W = amountFunction(18);
|
|
51
|
+
|
|
52
|
+
/** Ray function */
|
|
53
|
+
const _R = amountFunction(27);
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Returns a role identifier by computing the keccak of the role name.
|
|
57
|
+
*/
|
|
58
|
+
function getRole(role) {
|
|
59
|
+
if (role.startsWith("0x")) return role;
|
|
60
|
+
return role === "DEFAULT_ADMIN_ROLE"
|
|
61
|
+
? ethers.constants.HashZero
|
|
62
|
+
: ethers.utils.keccak256(ethers.utils.toUtf8Bytes(role));
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Builds the component role identifier
|
|
67
|
+
*
|
|
68
|
+
* Mimics the behaviour of the AccessManager.getComponentRole method
|
|
69
|
+
*
|
|
70
|
+
* Component roles are roles created doing XOR between the component
|
|
71
|
+
* address and the original role.
|
|
72
|
+
*
|
|
73
|
+
* Example:
|
|
74
|
+
* getComponentRole("0xc6e7DF5E7b4f2A278906862b61205850344D4e7d", "ORACLE_ADMIN_ROLE")
|
|
75
|
+
* // "0x05e01b185238b49f750d03d945e38a7f6c3be8b54de0ee42d481eb7814f0d3a8"
|
|
76
|
+
*/
|
|
77
|
+
function getComponentRole(componentAddress, role) {
|
|
78
|
+
if (!role.startsWith("0x")) role = getRole(role);
|
|
79
|
+
|
|
80
|
+
// 32 byte array
|
|
81
|
+
const bytesRole = ethers.utils.arrayify(role);
|
|
82
|
+
|
|
83
|
+
// 20 byte array
|
|
84
|
+
const bytesAddress = ethers.utils.arrayify(componentAddress);
|
|
85
|
+
|
|
86
|
+
// xor each byte, padding bytesAddress with zeros at the end
|
|
87
|
+
// eslint-disable-next-line no-bitwise
|
|
88
|
+
return ethers.utils.hexlify(bytesRole.map((elem, idx) => elem ^ (bytesAddress[idx] || 0)));
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
async function getDefaultSigner(hre) {
|
|
92
|
+
const signers = await hre.ethers.getSigners();
|
|
93
|
+
return signers[0];
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* Grant a component role to a user.
|
|
98
|
+
*/
|
|
99
|
+
// eslint-disable-next-line no-empty-function
|
|
100
|
+
async function grantComponentRole(hre, contract, component, role, user, txOverrides = {}, log = () => {}) {
|
|
101
|
+
let userAddress;
|
|
102
|
+
if (user === undefined) {
|
|
103
|
+
user = await getDefaultSigner(hre);
|
|
104
|
+
userAddress = user.address;
|
|
105
|
+
} else {
|
|
106
|
+
userAddress = user.address === undefined ? user : user.address;
|
|
107
|
+
}
|
|
108
|
+
const roleHex = getRole(role);
|
|
109
|
+
const componentAddress = component.address || component;
|
|
110
|
+
const componentRole = await contract.getComponentRole(componentAddress, roleHex);
|
|
111
|
+
if (!(await contract.hasRole(componentRole, userAddress))) {
|
|
112
|
+
await contract.grantComponentRole(componentAddress, roleHex, userAddress, txOverrides);
|
|
113
|
+
log(`Role ${role} (${roleHex}) Component ${componentAddress} granted to ${userAddress}`);
|
|
114
|
+
} else {
|
|
115
|
+
log(`Role ${role} (${roleHex}) Component ${componentAddress} already granted to ${userAddress}`);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* Grant a role to a user
|
|
121
|
+
*/
|
|
122
|
+
// eslint-disable-next-line no-empty-function
|
|
123
|
+
async function grantRole(hre, contract, role, user, txOverrides = {}, log = () => {}) {
|
|
124
|
+
let userAddress;
|
|
125
|
+
if (user === undefined) {
|
|
126
|
+
user = await getDefaultSigner(hre);
|
|
127
|
+
userAddress = user.address;
|
|
128
|
+
} else {
|
|
129
|
+
userAddress = user.address === undefined ? user : user.address;
|
|
130
|
+
}
|
|
131
|
+
const roleHex = getRole(role);
|
|
132
|
+
if (!(await contract.hasRole(roleHex, userAddress))) {
|
|
133
|
+
await contract.grantRole(roleHex, userAddress, txOverrides);
|
|
134
|
+
log(`Role ${role} (${roleHex}) granted to ${userAddress}`);
|
|
135
|
+
} else {
|
|
136
|
+
log(`Role ${role} (${roleHex}) already granted to ${userAddress}`);
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
/**
|
|
141
|
+
* Finds an event in the receipt
|
|
142
|
+
* @param {Interface} interface The interface of the contract that contains the requested event
|
|
143
|
+
* @param {TransactionReceipt} receipt Transaction receipt containing the events in the logs
|
|
144
|
+
* @param {String} eventName The name of the event we are interested in
|
|
145
|
+
* @returns {LogDescription}
|
|
146
|
+
*/
|
|
147
|
+
function getTransactionEvent(interface, receipt, eventName) {
|
|
148
|
+
// for each log in the transaction receipt
|
|
149
|
+
for (const log of receipt.logs) {
|
|
150
|
+
let parsedLog;
|
|
151
|
+
try {
|
|
152
|
+
parsedLog = interface.parseLog(log);
|
|
153
|
+
} catch (error) {
|
|
154
|
+
continue;
|
|
155
|
+
}
|
|
156
|
+
if (parsedLog.name == eventName) {
|
|
157
|
+
return parsedLog;
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
return null; // not found
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
/**
|
|
164
|
+
* Builds AccessControl error message for comparison in tests
|
|
165
|
+
*/
|
|
166
|
+
function accessControlMessage(address, component, role) {
|
|
167
|
+
const roleHash = component !== null ? getComponentRole(component, role) : getRole(role);
|
|
168
|
+
|
|
169
|
+
return `AccessControl: account ${address.toLowerCase()} is missing role ${roleHash}`;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
/**
|
|
173
|
+
* Create a policy id by combining the riskmodule address and the internal id.
|
|
174
|
+
*
|
|
175
|
+
* Mimics the PolicyPool.newPolicy method of building the policy id.
|
|
176
|
+
*/
|
|
177
|
+
function makePolicyId(rmAddress, internalId) {
|
|
178
|
+
return _BN(rmAddress).shl(96).add(internalId);
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
/**
|
|
182
|
+
* Create a packed quote message for later signing or hashing.
|
|
183
|
+
*
|
|
184
|
+
* Mimics the behaviour of the SignedQuoteRiskModule._newSignedPolicy method.
|
|
185
|
+
*/
|
|
186
|
+
function makeQuoteMessage({ rmAddress, payout, premium, lossProb, expiration, policyData, validUntil }) {
|
|
187
|
+
return ethers.utils.solidityPack(
|
|
188
|
+
["address", "uint256", "uint256", "uint256", "uint40", "bytes32", "uint40"],
|
|
189
|
+
[rmAddress, payout, premium, lossProb, expiration, policyData, validUntil]
|
|
190
|
+
);
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
/**
|
|
194
|
+
* Create a packed quote message for later signing or hashing.
|
|
195
|
+
*
|
|
196
|
+
* Mimics the behaviour of the SignedBucketRiskModule._newSignedPolicy method.
|
|
197
|
+
*/
|
|
198
|
+
function makeBucketQuoteMessage({
|
|
199
|
+
rmAddress,
|
|
200
|
+
payout,
|
|
201
|
+
premium,
|
|
202
|
+
lossProb,
|
|
203
|
+
expiration,
|
|
204
|
+
policyData,
|
|
205
|
+
bucketId,
|
|
206
|
+
validUntil,
|
|
207
|
+
}) {
|
|
208
|
+
return ethers.utils.solidityPack(
|
|
209
|
+
["address", "uint256", "uint256", "uint256", "uint40", "bytes32", "uint256", "uint40"],
|
|
210
|
+
[rmAddress, payout, premium, lossProb, expiration, policyData, bucketId, validUntil]
|
|
211
|
+
);
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
/**
|
|
215
|
+
* Creates and signs a quote message from its policy parameters.
|
|
216
|
+
*
|
|
217
|
+
* Mimics the behaviour of policy-quote-api.
|
|
218
|
+
*/
|
|
219
|
+
async function makeSignedQuote(signer, policyParams, makeQuoteMessageFn = makeQuoteMessage) {
|
|
220
|
+
const quoteMessage = makeQuoteMessageFn(policyParams);
|
|
221
|
+
return ethers.utils.splitSignature(await signer.signMessage(ethers.utils.arrayify(quoteMessage)));
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
/**
|
|
225
|
+
* Build a default policy parameters object.
|
|
226
|
+
*/
|
|
227
|
+
async function defaultPolicyParams(
|
|
228
|
+
{ rmAddress, payout, premium, lossProb, expiration, policyData, validUntil },
|
|
229
|
+
_A = amountFunction(6)
|
|
230
|
+
) {
|
|
231
|
+
const now = await helpers.time.latest();
|
|
232
|
+
return {
|
|
233
|
+
rmAddress,
|
|
234
|
+
payout: payout || _A(1000),
|
|
235
|
+
premium: premium || ethers.constants.MaxUint256,
|
|
236
|
+
lossProb: lossProb || _W(0.1),
|
|
237
|
+
expiration: expiration || now + 3600 * 24 * 30,
|
|
238
|
+
policyData: policyData || ethers.utils.hexlify(ethers.utils.randomBytes(32)),
|
|
239
|
+
validUntil: validUntil || now + 3600 * 24 * 30,
|
|
240
|
+
};
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
module.exports = {
|
|
244
|
+
_BN,
|
|
245
|
+
_E,
|
|
246
|
+
_R,
|
|
247
|
+
_W,
|
|
248
|
+
accessControlMessage,
|
|
249
|
+
amountFunction,
|
|
250
|
+
defaultPolicyParams,
|
|
251
|
+
getComponentRole,
|
|
252
|
+
getDefaultSigner,
|
|
253
|
+
getRole,
|
|
254
|
+
getStorageLayout,
|
|
255
|
+
getTransactionEvent,
|
|
256
|
+
grantComponentRole,
|
|
257
|
+
grantRole,
|
|
258
|
+
makeBucketQuoteMessage,
|
|
259
|
+
makePolicyId,
|
|
260
|
+
makeQuoteMessage,
|
|
261
|
+
makeSignedQuote,
|
|
262
|
+
RAY,
|
|
263
|
+
WAD,
|
|
264
|
+
};
|
package/package.json
CHANGED
package/scripts/storageLayout.js
CHANGED
|
@@ -1,7 +1,5 @@
|
|
|
1
1
|
const hre = require("hardhat");
|
|
2
|
-
const {
|
|
3
|
-
const { findAll } = require("solidity-ast/utils");
|
|
4
|
-
const { getStorageLayout } = require("../test/test-utils");
|
|
2
|
+
const { getStorageLayout } = require("../js/utils");
|
|
5
3
|
|
|
6
4
|
/**
|
|
7
5
|
* Script to print a contracts storage layout as a table.
|
|
@@ -9,11 +7,9 @@ const { getStorageLayout } = require("../test/test-utils");
|
|
|
9
7
|
* Example usage: node scripts/storageLayout.js EToken
|
|
10
8
|
*/
|
|
11
9
|
|
|
12
|
-
//
|
|
13
|
-
|
|
14
10
|
async function main(contractSrc, contractName) {
|
|
15
11
|
await hre.run("compile");
|
|
16
|
-
const layout = await getStorageLayout(contractSrc, contractName);
|
|
12
|
+
const layout = await getStorageLayout(hre, contractSrc, contractName);
|
|
17
13
|
|
|
18
14
|
const summary = layout.storage.map((item) => ({
|
|
19
15
|
slot: parseInt(item.slot),
|
|
@@ -29,5 +25,6 @@ const [contractSrc, contractName] = [`contracts/${process.argv[2]}.sol`, process
|
|
|
29
25
|
|
|
30
26
|
console.log(`Storage layout for ${contractSrc}:${contractName}`);
|
|
31
27
|
main(contractSrc, contractName).then(() => {
|
|
28
|
+
// eslint-disable-next-line no-process-exit
|
|
32
29
|
process.exit(0);
|
|
33
30
|
});
|