@ensuro/core 2.5.0 → 2.6.0-beta1
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 +10 -237
- 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,6 @@
|
|
|
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");
|
|
7
|
-
|
|
8
|
-
WEEK = 3600 * 24 * 7;
|
|
9
|
-
DAY = 3600 * 24;
|
|
2
|
+
const { _W, grantRole, getTransactionEvent } = require("../js/utils");
|
|
3
|
+
const { RiskModuleParameter } = require("../js/enums");
|
|
10
4
|
|
|
11
5
|
async function initCurrency(options, initial_targets, initial_balances) {
|
|
12
6
|
const Currency = await hre.ethers.getContractFactory("TestCurrency");
|
|
@@ -25,36 +19,7 @@ async function initCurrency(options, initial_targets, initial_balances) {
|
|
|
25
19
|
return currency;
|
|
26
20
|
}
|
|
27
21
|
|
|
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 (
|
|
22
|
+
async function createRiskModule(
|
|
58
23
|
pool,
|
|
59
24
|
premiumsAccount,
|
|
60
25
|
contractFactory,
|
|
@@ -99,7 +64,7 @@ const createRiskModule = async function (
|
|
|
99
64
|
await rm.setParam(RiskModuleParameter.moc, moc);
|
|
100
65
|
}
|
|
101
66
|
return rm;
|
|
102
|
-
}
|
|
67
|
+
}
|
|
103
68
|
|
|
104
69
|
async function addRiskModule(
|
|
105
70
|
pool,
|
|
@@ -135,7 +100,7 @@ async function addRiskModule(
|
|
|
135
100
|
return rm;
|
|
136
101
|
}
|
|
137
102
|
|
|
138
|
-
|
|
103
|
+
async function createEToken(
|
|
139
104
|
pool,
|
|
140
105
|
{ etkName, etkSymbol, maxUtilizationRate, poolLoanInterestRate, extraArgs, extraConstructorArgs }
|
|
141
106
|
) {
|
|
@@ -160,9 +125,9 @@ const createEToken = async function (
|
|
|
160
125
|
|
|
161
126
|
await etk.deployed();
|
|
162
127
|
return etk;
|
|
163
|
-
}
|
|
128
|
+
}
|
|
164
129
|
|
|
165
|
-
|
|
130
|
+
async function addEToken(
|
|
166
131
|
pool,
|
|
167
132
|
{ etkName, etkSymbol, maxUtilizationRate, poolLoanInterestRate, extraArgs, extraConstructorArgs }
|
|
168
133
|
) {
|
|
@@ -176,42 +141,12 @@ addEToken = async function addEToken(
|
|
|
176
141
|
});
|
|
177
142
|
await pool.addComponent(etk.address, 1);
|
|
178
143
|
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
144
|
}
|
|
187
145
|
|
|
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
146
|
const randomAddress = "0x89cDb70Fee571251a66E34caa1673cE40f7549Dc";
|
|
212
147
|
|
|
213
148
|
/**
|
|
214
|
-
* Deploys
|
|
149
|
+
* Deploys the PolicyPool contract and AccessManager
|
|
215
150
|
*
|
|
216
151
|
* By default deployes de PolicyPool and AccessManager and grants LEVEL 1, 2, 3 permissions
|
|
217
152
|
*
|
|
@@ -224,7 +159,7 @@ const randomAddress = "0x89cDb70Fee571251a66E34caa1673cE40f7549Dc";
|
|
|
224
159
|
* - .grantRoles: default []. List of additional roles to grant
|
|
225
160
|
* - .dontGrantL123Roles: if specified, doesn't grants LEVEL1, 2 and 3 roles.
|
|
226
161
|
*/
|
|
227
|
-
async function deployPool(
|
|
162
|
+
async function deployPool(options) {
|
|
228
163
|
const PolicyPool = await hre.ethers.getContractFactory("PolicyPool");
|
|
229
164
|
const AccessManager = await hre.ethers.getContractFactory("AccessManager");
|
|
230
165
|
|
|
@@ -266,7 +201,7 @@ async function deployPool(hre, options) {
|
|
|
266
201
|
return policyPool;
|
|
267
202
|
}
|
|
268
203
|
|
|
269
|
-
async function deployPremiumsAccount(
|
|
204
|
+
async function deployPremiumsAccount(pool, options, addToPool = true) {
|
|
270
205
|
const PremiumsAccount = await hre.ethers.getContractFactory("PremiumsAccount");
|
|
271
206
|
const premiumsAccount = await hre.upgrades.deployProxy(PremiumsAccount, [], {
|
|
272
207
|
constructorArgs: [
|
|
@@ -285,112 +220,6 @@ async function deployPremiumsAccount(hre, pool, options, addToPool = true) {
|
|
|
285
220
|
return premiumsAccount;
|
|
286
221
|
}
|
|
287
222
|
|
|
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
223
|
async function makePolicy(pool, rm, cust, payout, premium, lossProb, expiration, internalId, method = "newPolicy") {
|
|
395
224
|
let tx = await rm.connect(cust)[method](payout, premium, lossProb, expiration, cust.address, internalId);
|
|
396
225
|
let receipt = await tx.wait();
|
|
@@ -399,71 +228,15 @@ async function makePolicy(pool, rm, cust, payout, premium, lossProb, expiration,
|
|
|
399
228
|
return newPolicyEvt;
|
|
400
229
|
}
|
|
401
230
|
|
|
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
231
|
if (process.env.ENABLE_HH_WARNINGS !== "yes") hre.upgrades.silenceWarnings();
|
|
436
232
|
|
|
437
233
|
module.exports = {
|
|
438
|
-
_BN,
|
|
439
|
-
_E,
|
|
440
|
-
_R,
|
|
441
|
-
_W,
|
|
442
|
-
accessControlMessage,
|
|
443
234
|
addEToken,
|
|
444
235
|
addRiskModule,
|
|
445
|
-
amountFunction,
|
|
446
|
-
approve_multiple,
|
|
447
|
-
check_balances,
|
|
448
236
|
createEToken,
|
|
449
237
|
createRiskModule,
|
|
450
|
-
DAY,
|
|
451
238
|
deployPool,
|
|
452
239
|
deployPremiumsAccount,
|
|
453
|
-
expected_change,
|
|
454
|
-
getComponentRole,
|
|
455
|
-
getRole,
|
|
456
|
-
getStorageLayout,
|
|
457
|
-
getTransactionEvent,
|
|
458
|
-
grantComponentRole,
|
|
459
|
-
grantRole,
|
|
460
240
|
initCurrency,
|
|
461
241
|
makePolicy,
|
|
462
|
-
makePolicyId,
|
|
463
|
-
makeQuoteMessage,
|
|
464
|
-
makeSignedQuote,
|
|
465
|
-
RAY,
|
|
466
|
-
RiskModuleParameter,
|
|
467
|
-
WAD,
|
|
468
|
-
WEEK,
|
|
469
242
|
};
|
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(contractSrc, contractName, hre) {
|
|
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(contractSrc, contractName, hre);
|
|
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
|
});
|