@openzeppelin/upgrades-core 1.28.0 → 1.30.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/dist/call-optional-signature.d.ts +3 -0
- package/dist/call-optional-signature.d.ts.map +1 -0
- package/dist/call-optional-signature.js +24 -0
- package/dist/call-optional-signature.js.map +1 -0
- package/dist/cli/validate/build-info-file.d.ts +4 -0
- package/dist/cli/validate/build-info-file.d.ts.map +1 -1
- package/dist/cli/validate/build-info-file.js +5 -2
- package/dist/cli/validate/build-info-file.js.map +1 -1
- package/dist/cli/validate/build-info-file.test.js +4 -1
- package/dist/cli/validate/build-info-file.test.js.map +1 -1
- package/dist/cli/validate/upgradeability-assessment.js +2 -6
- package/dist/cli/validate/upgradeability-assessment.js.map +1 -1
- package/dist/cli/validate/validations.d.ts.map +1 -1
- package/dist/cli/validate/validations.js +5 -4
- package/dist/cli/validate/validations.js.map +1 -1
- package/dist/impl-address.d.ts.map +1 -1
- package/dist/impl-address.js +9 -16
- package/dist/impl-address.js.map +1 -1
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +5 -1
- package/dist/index.js.map +1 -1
- package/dist/levenshtein.d.ts +6 -0
- package/dist/levenshtein.d.ts.map +1 -1
- package/dist/levenshtein.js.map +1 -1
- package/dist/solc-api.d.ts +14 -0
- package/dist/solc-api.d.ts.map +1 -1
- package/dist/standalone.d.ts +4 -1
- package/dist/standalone.d.ts.map +1 -1
- package/dist/standalone.js +6 -3
- package/dist/standalone.js.map +1 -1
- package/dist/standalone.test.js +17 -0
- package/dist/standalone.test.js.map +1 -1
- package/dist/storage/compare.d.ts +2 -1
- package/dist/storage/compare.d.ts.map +1 -1
- package/dist/storage/compare.js +25 -2
- package/dist/storage/compare.js.map +1 -1
- package/dist/storage/extract.d.ts +15 -3
- package/dist/storage/extract.d.ts.map +1 -1
- package/dist/storage/extract.js +48 -21
- package/dist/storage/extract.js.map +1 -1
- package/dist/storage/index.d.ts.map +1 -1
- package/dist/storage/index.js +15 -1
- package/dist/storage/index.js.map +1 -1
- package/dist/storage/layout.d.ts +1 -0
- package/dist/storage/layout.d.ts.map +1 -1
- package/dist/storage/layout.js.map +1 -1
- package/dist/storage/namespace.d.ts +34 -0
- package/dist/storage/namespace.d.ts.map +1 -0
- package/dist/storage/namespace.js +191 -0
- package/dist/storage/namespace.js.map +1 -0
- package/dist/storage/report.js +6 -0
- package/dist/storage/report.js.map +1 -1
- package/dist/storage-namespaced-conflicts-layout.test.d.ts +2 -0
- package/dist/storage-namespaced-conflicts-layout.test.d.ts.map +1 -0
- package/dist/storage-namespaced-conflicts-layout.test.js +69 -0
- package/dist/storage-namespaced-conflicts-layout.test.js.map +1 -0
- package/dist/storage-namespaced-conflicts.test.d.ts +2 -0
- package/dist/storage-namespaced-conflicts.test.d.ts.map +1 -0
- package/dist/storage-namespaced-conflicts.test.js +45 -0
- package/dist/storage-namespaced-conflicts.test.js.map +1 -0
- package/dist/storage-namespaced-layout.test.d.ts +2 -0
- package/dist/storage-namespaced-layout.test.d.ts.map +1 -0
- package/dist/storage-namespaced-layout.test.js +59 -0
- package/dist/storage-namespaced-layout.test.js.map +1 -0
- package/dist/storage-namespaced-outside-contract.test.d.ts +2 -0
- package/dist/storage-namespaced-outside-contract.test.d.ts.map +1 -0
- package/dist/storage-namespaced-outside-contract.test.js +22 -0
- package/dist/storage-namespaced-outside-contract.test.js.map +1 -0
- package/dist/storage-namespaced-solc-versions.test.d.ts +2 -0
- package/dist/storage-namespaced-solc-versions.test.d.ts.map +1 -0
- package/dist/storage-namespaced-solc-versions.test.js +42 -0
- package/dist/storage-namespaced-solc-versions.test.js.map +1 -0
- package/dist/storage-namespaced-udvt.test.d.ts +2 -0
- package/dist/storage-namespaced-udvt.test.d.ts.map +1 -0
- package/dist/storage-namespaced-udvt.test.js +130 -0
- package/dist/storage-namespaced-udvt.test.js.map +1 -0
- package/dist/storage-namespaced.test.d.ts +2 -0
- package/dist/storage-namespaced.test.d.ts.map +1 -0
- package/dist/storage-namespaced.test.js +132 -0
- package/dist/storage-namespaced.test.js.map +1 -0
- package/dist/upgrade-interface-version.d.ts +3 -0
- package/dist/upgrade-interface-version.d.ts.map +1 -0
- package/dist/upgrade-interface-version.js +25 -0
- package/dist/upgrade-interface-version.js.map +1 -0
- package/dist/upgrade-interface-version.test.d.ts +2 -0
- package/dist/upgrade-interface-version.test.d.ts.map +1 -0
- package/dist/upgrade-interface-version.test.js +32 -0
- package/dist/upgrade-interface-version.test.js.map +1 -0
- package/dist/utils/annotations.d.ts +4 -0
- package/dist/utils/annotations.d.ts.map +1 -1
- package/dist/utils/annotations.js +9 -1
- package/dist/utils/annotations.js.map +1 -1
- package/dist/utils/make-namespaced.d.ts +20 -0
- package/dist/utils/make-namespaced.d.ts.map +1 -0
- package/dist/utils/make-namespaced.js +131 -0
- package/dist/utils/make-namespaced.js.map +1 -0
- package/dist/utils/make-namespaced.test.d.ts +2 -0
- package/dist/utils/make-namespaced.test.d.ts.map +1 -0
- package/dist/utils/make-namespaced.test.js +59 -0
- package/dist/utils/make-namespaced.test.js.map +1 -0
- package/dist/utils/stabilize-layout.d.ts +11 -0
- package/dist/utils/stabilize-layout.d.ts.map +1 -1
- package/dist/utils/stabilize-layout.js +5 -0
- package/dist/utils/stabilize-layout.js.map +1 -1
- package/dist/validate/overrides.js +1 -1
- package/dist/validate/overrides.js.map +1 -1
- package/dist/validate/query.d.ts.map +1 -1
- package/dist/validate/query.js +7 -3
- package/dist/validate/query.js.map +1 -1
- package/dist/validate/report.js +2 -2
- package/dist/validate/report.js.map +1 -1
- package/dist/validate/run.d.ts +18 -2
- package/dist/validate/run.d.ts.map +1 -1
- package/dist/validate/run.js +104 -2
- package/dist/validate/run.js.map +1 -1
- package/dist/validate.test.js +3 -0
- package/dist/validate.test.js.map +1 -1
- package/package.json +3 -3
- package/src/call-optional-signature.ts +20 -0
- package/src/cli/cli.test.ts.md +4 -4
- package/src/cli/cli.test.ts.snap +0 -0
- package/src/cli/validate/build-info-file.test.ts +4 -1
- package/src/cli/validate/build-info-file.ts +12 -2
- package/src/cli/validate/project-report.test.ts.md +4 -4
- package/src/cli/validate/project-report.test.ts.snap +0 -0
- package/src/cli/validate/upgradeability-assessment.ts +1 -6
- package/src/cli/validate/validate-upgrade-safety.test.ts.md +2 -2
- package/src/cli/validate/validate-upgrade-safety.test.ts.snap +0 -0
- package/src/cli/validate/validations.test.ts.md +2 -2
- package/src/cli/validate/validations.test.ts.snap +0 -0
- package/src/cli/validate/validations.ts +6 -5
- package/src/impl-address.ts +9 -20
- package/src/index.ts +3 -0
- package/src/levenshtein.ts +7 -0
- package/src/solc-api.ts +14 -0
- package/src/standalone.test.ts +26 -0
- package/src/standalone.ts +6 -2
- package/src/storage/compare.ts +34 -2
- package/src/storage/extract.ts +68 -20
- package/src/storage/index.ts +22 -1
- package/src/storage/layout.ts +1 -0
- package/src/storage/namespace.ts +262 -0
- package/src/storage/report.ts +8 -0
- package/src/storage-0.8.test.ts.md +4 -0
- package/src/storage-0.8.test.ts.snap +0 -0
- package/src/storage-memory-0.5.test.ts.md +2 -0
- package/src/storage-memory-0.5.test.ts.snap +0 -0
- package/src/storage-namespaced-conflicts-layout.test.ts +96 -0
- package/src/storage-namespaced-conflicts-layout.test.ts.md +53 -0
- package/src/storage-namespaced-conflicts-layout.test.ts.snap +0 -0
- package/src/storage-namespaced-conflicts.test.ts +54 -0
- package/src/storage-namespaced-conflicts.test.ts.md +53 -0
- package/src/storage-namespaced-conflicts.test.ts.snap +0 -0
- package/src/storage-namespaced-layout.test.ts +77 -0
- package/src/storage-namespaced-layout.test.ts.md +67 -0
- package/src/storage-namespaced-layout.test.ts.snap +0 -0
- package/src/storage-namespaced-outside-contract.test.ts +24 -0
- package/src/storage-namespaced-solc-versions.test.ts +59 -0
- package/src/storage-namespaced-udvt.test.ts +160 -0
- package/src/storage-namespaced.test.ts +146 -0
- package/src/storage-namespaced.test.ts.md +89 -0
- package/src/storage-namespaced.test.ts.snap +0 -0
- package/src/storage.test.ts.md +2 -0
- package/src/storage.test.ts.snap +0 -0
- package/src/upgrade-interface-version.test.ts +37 -0
- package/src/upgrade-interface-version.ts +27 -0
- package/src/utils/annotations.ts +8 -0
- package/src/utils/make-namespaced.test.ts +74 -0
- package/src/utils/make-namespaced.test.ts.md +154 -0
- package/src/utils/make-namespaced.test.ts.snap +0 -0
- package/src/utils/make-namespaced.ts +154 -0
- package/src/utils/stabilize-layout.ts +5 -0
- package/src/validate/overrides.ts +1 -1
- package/src/validate/query.ts +9 -3
- package/src/validate/report.ts +3 -2
- package/src/validate/run.ts +109 -2
- package/src/validate.test.ts +3 -0
package/src/storage/report.ts
CHANGED
|
@@ -154,6 +154,11 @@ function explainStorageOperation(op: StorageOperation<StorageField>, ctx: Storag
|
|
|
154
154
|
hints.push('Keep the variable even if unused');
|
|
155
155
|
break;
|
|
156
156
|
}
|
|
157
|
+
|
|
158
|
+
case 'delete-namespace': {
|
|
159
|
+
hints.push(`Keep the struct with annotation '@custom:storage-location ${op.namespace}' even if unused`);
|
|
160
|
+
break;
|
|
161
|
+
}
|
|
157
162
|
}
|
|
158
163
|
|
|
159
164
|
return printWithHints({ title, hints });
|
|
@@ -299,6 +304,9 @@ function explainBasicOperation<T>(op: BasicOperation<T>, getName: (t: T) => stri
|
|
|
299
304
|
|
|
300
305
|
case 'append':
|
|
301
306
|
return `Added \`${getName(op.updated)}\``;
|
|
307
|
+
|
|
308
|
+
case 'delete-namespace':
|
|
309
|
+
return `Deleted namespace \`${op.namespace}\``;
|
|
302
310
|
}
|
|
303
311
|
}
|
|
304
312
|
|
|
@@ -9,6 +9,7 @@ Generated by [AVA](https://avajs.dev).
|
|
|
9
9
|
> Snapshot 1
|
|
10
10
|
|
|
11
11
|
{
|
|
12
|
+
namespaces: [],
|
|
12
13
|
storage: [
|
|
13
14
|
{
|
|
14
15
|
contract: 'Storage088',
|
|
@@ -46,6 +47,7 @@ Generated by [AVA](https://avajs.dev).
|
|
|
46
47
|
> Snapshot 1
|
|
47
48
|
|
|
48
49
|
{
|
|
50
|
+
namespaces: [],
|
|
49
51
|
storage: [
|
|
50
52
|
{
|
|
51
53
|
contract: 'Storage089',
|
|
@@ -83,6 +85,7 @@ Generated by [AVA](https://avajs.dev).
|
|
|
83
85
|
> Snapshot 1
|
|
84
86
|
|
|
85
87
|
{
|
|
88
|
+
namespaces: [],
|
|
86
89
|
storage: [
|
|
87
90
|
{
|
|
88
91
|
contract: 'Storage089',
|
|
@@ -117,6 +120,7 @@ Generated by [AVA](https://avajs.dev).
|
|
|
117
120
|
> Snapshot 1
|
|
118
121
|
|
|
119
122
|
{
|
|
123
|
+
namespaces: [],
|
|
120
124
|
storage: [
|
|
121
125
|
{
|
|
122
126
|
contract: 'StorageRenamedRetyped',
|
|
Binary file
|
|
@@ -9,6 +9,7 @@ Generated by [AVA](https://avajs.dev).
|
|
|
9
9
|
> Snapshot 1
|
|
10
10
|
|
|
11
11
|
{
|
|
12
|
+
namespaces: [],
|
|
12
13
|
storage: [
|
|
13
14
|
{
|
|
14
15
|
contract: 'Memory05',
|
|
@@ -94,6 +95,7 @@ Generated by [AVA](https://avajs.dev).
|
|
|
94
95
|
> Snapshot 1
|
|
95
96
|
|
|
96
97
|
{
|
|
98
|
+
namespaces: [],
|
|
97
99
|
storage: [
|
|
98
100
|
{
|
|
99
101
|
contract: 'Memory08',
|
|
Binary file
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import _test, { TestFn } from 'ava';
|
|
2
|
+
import { ContractDefinition } from 'solidity-ast';
|
|
3
|
+
import { findAll, astDereferencer } from 'solidity-ast/utils';
|
|
4
|
+
import { artifacts } from 'hardhat';
|
|
5
|
+
|
|
6
|
+
import { SolcOutput } from './solc-api';
|
|
7
|
+
import { StorageLayout } from './storage/layout';
|
|
8
|
+
import { extractStorageLayout } from './storage/extract';
|
|
9
|
+
import { solcInputOutputDecoder } from './src-decoder';
|
|
10
|
+
|
|
11
|
+
interface Context {
|
|
12
|
+
extractStorageLayout: (contract: string) => ReturnType<typeof extractStorageLayout>;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
const test = _test as TestFn<Context>;
|
|
16
|
+
|
|
17
|
+
test.before(async t => {
|
|
18
|
+
const origBuildInfo = await artifacts.getBuildInfo('contracts/test/NamespacedConflicts.sol:DuplicateNamespace');
|
|
19
|
+
const namespacedBuildInfo = await artifacts.getBuildInfo(
|
|
20
|
+
'contracts/test/NamespacedConflictsLayout.sol:DuplicateNamespace',
|
|
21
|
+
);
|
|
22
|
+
|
|
23
|
+
if (origBuildInfo === undefined || namespacedBuildInfo === undefined) {
|
|
24
|
+
throw new Error('Build info not found');
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
const origSolcOutput: SolcOutput = origBuildInfo.output;
|
|
28
|
+
const origContracts: Record<string, ContractDefinition> = {};
|
|
29
|
+
const origStorageLayouts: Record<string, StorageLayout> = {};
|
|
30
|
+
|
|
31
|
+
const namespacedSolcOutput: SolcOutput = namespacedBuildInfo.output;
|
|
32
|
+
const namespacedContracts: Record<string, ContractDefinition> = {};
|
|
33
|
+
const namespacedStorageLayouts: Record<string, StorageLayout> = {};
|
|
34
|
+
|
|
35
|
+
const origContractDefs = [];
|
|
36
|
+
for (const def of findAll(
|
|
37
|
+
'ContractDefinition',
|
|
38
|
+
origSolcOutput.sources['contracts/test/NamespacedConflicts.sol'].ast,
|
|
39
|
+
)) {
|
|
40
|
+
origContractDefs.push(def);
|
|
41
|
+
}
|
|
42
|
+
const namespacedContractDefs = [];
|
|
43
|
+
for (const def of findAll(
|
|
44
|
+
'ContractDefinition',
|
|
45
|
+
namespacedSolcOutput.sources['contracts/test/NamespacedConflictsLayout.sol'].ast,
|
|
46
|
+
)) {
|
|
47
|
+
namespacedContractDefs.push(def);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
for (let i = 0; i < origContractDefs.length; i++) {
|
|
51
|
+
const origContractDef = origContractDefs[i];
|
|
52
|
+
const namespacedContractDef = namespacedContractDefs[i];
|
|
53
|
+
|
|
54
|
+
origContracts[origContractDef.name] = origContractDef;
|
|
55
|
+
namespacedContracts[namespacedContractDef.name] = namespacedContractDef;
|
|
56
|
+
|
|
57
|
+
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
58
|
+
origStorageLayouts[origContractDef.name] =
|
|
59
|
+
origSolcOutput.contracts['contracts/test/NamespacedConflicts.sol'][origContractDef.name].storageLayout!;
|
|
60
|
+
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
61
|
+
namespacedStorageLayouts[namespacedContractDef.name] =
|
|
62
|
+
namespacedSolcOutput.contracts['contracts/test/NamespacedConflictsLayout.sol'][
|
|
63
|
+
namespacedContractDef.name
|
|
64
|
+
].storageLayout!;
|
|
65
|
+
}
|
|
66
|
+
const origDeref = astDereferencer(origSolcOutput);
|
|
67
|
+
const namespacedDeref = astDereferencer(namespacedSolcOutput);
|
|
68
|
+
|
|
69
|
+
const decodeSrc = solcInputOutputDecoder(origBuildInfo.input, origSolcOutput);
|
|
70
|
+
t.context.extractStorageLayout = name =>
|
|
71
|
+
extractStorageLayout(origContracts[name], decodeSrc, origDeref, origStorageLayouts[name], {
|
|
72
|
+
deref: namespacedDeref,
|
|
73
|
+
contractDef: namespacedContracts[name],
|
|
74
|
+
storageLayout: namespacedStorageLayouts[name],
|
|
75
|
+
});
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
test('duplicate namespace', t => {
|
|
79
|
+
const error = t.throws(() => t.context.extractStorageLayout('DuplicateNamespace'));
|
|
80
|
+
t.snapshot(error?.message);
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
test('inherits duplicate', t => {
|
|
84
|
+
const error = t.throws(() => t.context.extractStorageLayout('InheritsDuplicate'));
|
|
85
|
+
t.snapshot(error?.message);
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
test('conflicts with parent', t => {
|
|
89
|
+
const error = t.throws(() => t.context.extractStorageLayout('ConflictsWithParent'));
|
|
90
|
+
t.snapshot(error?.message);
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
test('conflicts in both parents', t => {
|
|
94
|
+
const error = t.throws(() => t.context.extractStorageLayout('ConflictsInBothParents'));
|
|
95
|
+
t.snapshot(error?.message);
|
|
96
|
+
});
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
# Snapshot report for `src/storage-namespaced-conflicts-layout.test.ts`
|
|
2
|
+
|
|
3
|
+
The actual snapshot is saved in `storage-namespaced-conflicts-layout.test.ts.snap`.
|
|
4
|
+
|
|
5
|
+
Generated by [AVA](https://avajs.dev).
|
|
6
|
+
|
|
7
|
+
## duplicate namespace
|
|
8
|
+
|
|
9
|
+
> Snapshot 1
|
|
10
|
+
|
|
11
|
+
`Namespace erc7201:conflicting is defined multiple times for contract DuplicateNamespace␊
|
|
12
|
+
␊
|
|
13
|
+
The namespace erc7201:conflicting was found in structs at the following locations:␊
|
|
14
|
+
- contracts/test/NamespacedConflicts.sol:10␊
|
|
15
|
+
- contracts/test/NamespacedConflicts.sol:15␊
|
|
16
|
+
␊
|
|
17
|
+
Use a unique namespace id for each struct annotated with '@custom:storage-location erc7201:<NAMESPACE_ID>' in your contract and its inherited contracts.`
|
|
18
|
+
|
|
19
|
+
## inherits duplicate
|
|
20
|
+
|
|
21
|
+
> Snapshot 1
|
|
22
|
+
|
|
23
|
+
`Namespace erc7201:conflicting is defined multiple times for contract InheritsDuplicate␊
|
|
24
|
+
␊
|
|
25
|
+
The namespace erc7201:conflicting was found in structs at the following locations:␊
|
|
26
|
+
- contracts/test/NamespacedConflicts.sol:10␊
|
|
27
|
+
- contracts/test/NamespacedConflicts.sol:15␊
|
|
28
|
+
␊
|
|
29
|
+
Use a unique namespace id for each struct annotated with '@custom:storage-location erc7201:<NAMESPACE_ID>' in your contract and its inherited contracts.`
|
|
30
|
+
|
|
31
|
+
## conflicts with parent
|
|
32
|
+
|
|
33
|
+
> Snapshot 1
|
|
34
|
+
|
|
35
|
+
`Namespace erc7201:conflicting is defined multiple times for contract ConflictsWithParent␊
|
|
36
|
+
␊
|
|
37
|
+
The namespace erc7201:conflicting was found in structs at the following locations:␊
|
|
38
|
+
- contracts/test/NamespacedConflicts.sol:45␊
|
|
39
|
+
- contracts/test/NamespacedConflicts.sol:30␊
|
|
40
|
+
␊
|
|
41
|
+
Use a unique namespace id for each struct annotated with '@custom:storage-location erc7201:<NAMESPACE_ID>' in your contract and its inherited contracts.`
|
|
42
|
+
|
|
43
|
+
## conflicts in both parents
|
|
44
|
+
|
|
45
|
+
> Snapshot 1
|
|
46
|
+
|
|
47
|
+
`Namespace erc7201:conflicting is defined multiple times for contract ConflictsInBothParents␊
|
|
48
|
+
␊
|
|
49
|
+
The namespace erc7201:conflicting was found in structs at the following locations:␊
|
|
50
|
+
- contracts/test/NamespacedConflicts.sol:45␊
|
|
51
|
+
- contracts/test/NamespacedConflicts.sol:30␊
|
|
52
|
+
␊
|
|
53
|
+
Use a unique namespace id for each struct annotated with '@custom:storage-location erc7201:<NAMESPACE_ID>' in your contract and its inherited contracts.`
|
|
Binary file
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import _test, { TestFn } from 'ava';
|
|
2
|
+
import { ContractDefinition } from 'solidity-ast';
|
|
3
|
+
import { findAll, astDereferencer } from 'solidity-ast/utils';
|
|
4
|
+
import { artifacts } from 'hardhat';
|
|
5
|
+
|
|
6
|
+
import { SolcOutput } from './solc-api';
|
|
7
|
+
import { StorageLayout } from './storage/layout';
|
|
8
|
+
import { extractStorageLayout } from './storage/extract';
|
|
9
|
+
import { solcInputOutputDecoder } from './src-decoder';
|
|
10
|
+
|
|
11
|
+
interface Context {
|
|
12
|
+
extractStorageLayout: (contract: string) => ReturnType<typeof extractStorageLayout>;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
const test = _test as TestFn<Context>;
|
|
16
|
+
|
|
17
|
+
test.before(async t => {
|
|
18
|
+
const buildInfo = await artifacts.getBuildInfo('contracts/test/NamespacedConflicts.sol:DuplicateNamespace');
|
|
19
|
+
if (buildInfo === undefined) {
|
|
20
|
+
throw new Error('Build info not found');
|
|
21
|
+
}
|
|
22
|
+
const solcOutput: SolcOutput = buildInfo.output;
|
|
23
|
+
const contracts: Record<string, ContractDefinition> = {};
|
|
24
|
+
const storageLayouts: Record<string, StorageLayout> = {};
|
|
25
|
+
for (const def of findAll('ContractDefinition', solcOutput.sources['contracts/test/NamespacedConflicts.sol'].ast)) {
|
|
26
|
+
contracts[def.name] = def;
|
|
27
|
+
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
28
|
+
storageLayouts[def.name] = solcOutput.contracts['contracts/test/NamespacedConflicts.sol'][def.name].storageLayout!;
|
|
29
|
+
}
|
|
30
|
+
const deref = astDereferencer(solcOutput);
|
|
31
|
+
const decodeSrc = solcInputOutputDecoder(buildInfo.input, solcOutput);
|
|
32
|
+
t.context.extractStorageLayout = name =>
|
|
33
|
+
extractStorageLayout(contracts[name], decodeSrc, deref, storageLayouts[name]);
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
test('duplicate namespace', t => {
|
|
37
|
+
const error = t.throws(() => t.context.extractStorageLayout('DuplicateNamespace'));
|
|
38
|
+
t.snapshot(error?.message);
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
test('inherits duplicate', t => {
|
|
42
|
+
const error = t.throws(() => t.context.extractStorageLayout('InheritsDuplicate'));
|
|
43
|
+
t.snapshot(error?.message);
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
test('conflicts with parent', t => {
|
|
47
|
+
const error = t.throws(() => t.context.extractStorageLayout('ConflictsWithParent'));
|
|
48
|
+
t.snapshot(error?.message);
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
test('conflicts in both parents', t => {
|
|
52
|
+
const error = t.throws(() => t.context.extractStorageLayout('ConflictsInBothParents'));
|
|
53
|
+
t.snapshot(error?.message);
|
|
54
|
+
});
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
# Snapshot report for `src/storage-namespaced-conflicts.test.ts`
|
|
2
|
+
|
|
3
|
+
The actual snapshot is saved in `storage-namespaced-conflicts.test.ts.snap`.
|
|
4
|
+
|
|
5
|
+
Generated by [AVA](https://avajs.dev).
|
|
6
|
+
|
|
7
|
+
## duplicate namespace
|
|
8
|
+
|
|
9
|
+
> Snapshot 1
|
|
10
|
+
|
|
11
|
+
`Namespace erc7201:conflicting is defined multiple times for contract DuplicateNamespace␊
|
|
12
|
+
␊
|
|
13
|
+
The namespace erc7201:conflicting was found in structs at the following locations:␊
|
|
14
|
+
- contracts/test/NamespacedConflicts.sol:10␊
|
|
15
|
+
- contracts/test/NamespacedConflicts.sol:15␊
|
|
16
|
+
␊
|
|
17
|
+
Use a unique namespace id for each struct annotated with '@custom:storage-location erc7201:<NAMESPACE_ID>' in your contract and its inherited contracts.`
|
|
18
|
+
|
|
19
|
+
## inherits duplicate
|
|
20
|
+
|
|
21
|
+
> Snapshot 1
|
|
22
|
+
|
|
23
|
+
`Namespace erc7201:conflicting is defined multiple times for contract InheritsDuplicate␊
|
|
24
|
+
␊
|
|
25
|
+
The namespace erc7201:conflicting was found in structs at the following locations:␊
|
|
26
|
+
- contracts/test/NamespacedConflicts.sol:10␊
|
|
27
|
+
- contracts/test/NamespacedConflicts.sol:15␊
|
|
28
|
+
␊
|
|
29
|
+
Use a unique namespace id for each struct annotated with '@custom:storage-location erc7201:<NAMESPACE_ID>' in your contract and its inherited contracts.`
|
|
30
|
+
|
|
31
|
+
## conflicts with parent
|
|
32
|
+
|
|
33
|
+
> Snapshot 1
|
|
34
|
+
|
|
35
|
+
`Namespace erc7201:conflicting is defined multiple times for contract ConflictsWithParent␊
|
|
36
|
+
␊
|
|
37
|
+
The namespace erc7201:conflicting was found in structs at the following locations:␊
|
|
38
|
+
- contracts/test/NamespacedConflicts.sol:45␊
|
|
39
|
+
- contracts/test/NamespacedConflicts.sol:30␊
|
|
40
|
+
␊
|
|
41
|
+
Use a unique namespace id for each struct annotated with '@custom:storage-location erc7201:<NAMESPACE_ID>' in your contract and its inherited contracts.`
|
|
42
|
+
|
|
43
|
+
## conflicts in both parents
|
|
44
|
+
|
|
45
|
+
> Snapshot 1
|
|
46
|
+
|
|
47
|
+
`Namespace erc7201:conflicting is defined multiple times for contract ConflictsInBothParents␊
|
|
48
|
+
␊
|
|
49
|
+
The namespace erc7201:conflicting was found in structs at the following locations:␊
|
|
50
|
+
- contracts/test/NamespacedConflicts.sol:45␊
|
|
51
|
+
- contracts/test/NamespacedConflicts.sol:30␊
|
|
52
|
+
␊
|
|
53
|
+
Use a unique namespace id for each struct annotated with '@custom:storage-location erc7201:<NAMESPACE_ID>' in your contract and its inherited contracts.`
|
|
Binary file
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import _test, { TestFn } from 'ava';
|
|
2
|
+
import { ContractDefinition } from 'solidity-ast';
|
|
3
|
+
import { findAll, astDereferencer } from 'solidity-ast/utils';
|
|
4
|
+
import { artifacts } from 'hardhat';
|
|
5
|
+
|
|
6
|
+
import { SolcOutput } from './solc-api';
|
|
7
|
+
import { StorageLayout } from './storage/layout';
|
|
8
|
+
import { extractStorageLayout } from './storage/extract';
|
|
9
|
+
import { stabilizeStorageLayout } from './utils/stabilize-layout';
|
|
10
|
+
import { solcInputOutputDecoder } from './src-decoder';
|
|
11
|
+
|
|
12
|
+
interface Context {
|
|
13
|
+
extractStorageLayout: (contract: string) => ReturnType<typeof extractStorageLayout>;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
const test = _test as TestFn<Context>;
|
|
17
|
+
|
|
18
|
+
test.before(async t => {
|
|
19
|
+
// Tests extracting the storage layout (to include slot and offset) using Namespaced.sol's Example as the original contract,
|
|
20
|
+
// and NamespacedLayout.sol's Example as the modified contract with the storage layout.
|
|
21
|
+
const origBuildInfo = await artifacts.getBuildInfo('contracts/test/Namespaced.sol:Example');
|
|
22
|
+
const namespacedBuildInfo = await artifacts.getBuildInfo('contracts/test/NamespacedLayout.sol:Example');
|
|
23
|
+
|
|
24
|
+
if (origBuildInfo === undefined || namespacedBuildInfo === undefined) {
|
|
25
|
+
throw new Error('Build info not found');
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
const origSolcOutput: SolcOutput = origBuildInfo.output;
|
|
29
|
+
const origContracts: Record<string, ContractDefinition> = {};
|
|
30
|
+
const origStorageLayouts: Record<string, StorageLayout> = {};
|
|
31
|
+
|
|
32
|
+
const namespacedSolcOutput: SolcOutput = namespacedBuildInfo.output;
|
|
33
|
+
const namespacedContracts: Record<string, ContractDefinition> = {};
|
|
34
|
+
const namespacedStorageLayouts: Record<string, StorageLayout> = {};
|
|
35
|
+
|
|
36
|
+
const origContractDefs = [];
|
|
37
|
+
for (const def of findAll('ContractDefinition', origSolcOutput.sources['contracts/test/Namespaced.sol'].ast)) {
|
|
38
|
+
origContractDefs.push(def);
|
|
39
|
+
}
|
|
40
|
+
const namespacedContractDefs = [];
|
|
41
|
+
for (const def of findAll(
|
|
42
|
+
'ContractDefinition',
|
|
43
|
+
namespacedSolcOutput.sources['contracts/test/NamespacedLayout.sol'].ast,
|
|
44
|
+
)) {
|
|
45
|
+
namespacedContractDefs.push(def);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// Expects the first contract in Namespaced.sol and NamespacedLayout.sol to be 'Example'
|
|
49
|
+
const origContractDef = origContractDefs[0];
|
|
50
|
+
const namespacedContractDef = namespacedContractDefs[0];
|
|
51
|
+
|
|
52
|
+
origContracts[origContractDef.name] = origContractDef;
|
|
53
|
+
namespacedContracts[namespacedContractDef.name] = namespacedContractDef;
|
|
54
|
+
|
|
55
|
+
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
56
|
+
origStorageLayouts[origContractDef.name] =
|
|
57
|
+
origSolcOutput.contracts['contracts/test/Namespaced.sol'][origContractDef.name].storageLayout!;
|
|
58
|
+
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
59
|
+
namespacedStorageLayouts[namespacedContractDef.name] =
|
|
60
|
+
namespacedSolcOutput.contracts['contracts/test/NamespacedLayout.sol'][namespacedContractDef.name].storageLayout!;
|
|
61
|
+
|
|
62
|
+
const origDeref = astDereferencer(origSolcOutput);
|
|
63
|
+
const namespacedDeref = astDereferencer(namespacedSolcOutput);
|
|
64
|
+
|
|
65
|
+
const decodeSrc = solcInputOutputDecoder(origBuildInfo.input, origSolcOutput);
|
|
66
|
+
t.context.extractStorageLayout = name =>
|
|
67
|
+
extractStorageLayout(origContracts[name], decodeSrc, origDeref, origStorageLayouts[name], {
|
|
68
|
+
deref: namespacedDeref,
|
|
69
|
+
contractDef: namespacedContracts[name],
|
|
70
|
+
storageLayout: namespacedStorageLayouts[name],
|
|
71
|
+
});
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
test('layout', t => {
|
|
75
|
+
const layout = t.context.extractStorageLayout('Example');
|
|
76
|
+
t.snapshot(stabilizeStorageLayout(layout));
|
|
77
|
+
});
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
# Snapshot report for `src/storage-namespaced-layout.test.ts`
|
|
2
|
+
|
|
3
|
+
The actual snapshot is saved in `storage-namespaced-layout.test.ts.snap`.
|
|
4
|
+
|
|
5
|
+
Generated by [AVA](https://avajs.dev).
|
|
6
|
+
|
|
7
|
+
## layout
|
|
8
|
+
|
|
9
|
+
> Snapshot 1
|
|
10
|
+
|
|
11
|
+
{
|
|
12
|
+
namespaces: [
|
|
13
|
+
[
|
|
14
|
+
'erc7201:example.main',
|
|
15
|
+
[
|
|
16
|
+
{
|
|
17
|
+
contract: 'Example',
|
|
18
|
+
label: 'x',
|
|
19
|
+
offset: 0,
|
|
20
|
+
slot: '0',
|
|
21
|
+
src: 'contracts/test/Namespaced.sol:7',
|
|
22
|
+
type: 't_uint256',
|
|
23
|
+
},
|
|
24
|
+
{
|
|
25
|
+
contract: 'Example',
|
|
26
|
+
label: 'y',
|
|
27
|
+
offset: 0,
|
|
28
|
+
slot: '1',
|
|
29
|
+
src: 'contracts/test/Namespaced.sol:8',
|
|
30
|
+
type: 't_uint256',
|
|
31
|
+
},
|
|
32
|
+
],
|
|
33
|
+
],
|
|
34
|
+
],
|
|
35
|
+
storage: [],
|
|
36
|
+
types: [
|
|
37
|
+
[
|
|
38
|
+
't_struct(MainStorage)storage',
|
|
39
|
+
{
|
|
40
|
+
label: 'struct Example.MainStorage',
|
|
41
|
+
members: [
|
|
42
|
+
{
|
|
43
|
+
label: 'x',
|
|
44
|
+
offset: 0,
|
|
45
|
+
slot: '0',
|
|
46
|
+
type: 't_uint256',
|
|
47
|
+
},
|
|
48
|
+
{
|
|
49
|
+
label: 'y',
|
|
50
|
+
offset: 0,
|
|
51
|
+
slot: '1',
|
|
52
|
+
type: 't_uint256',
|
|
53
|
+
},
|
|
54
|
+
],
|
|
55
|
+
numberOfBytes: '64',
|
|
56
|
+
},
|
|
57
|
+
],
|
|
58
|
+
[
|
|
59
|
+
't_uint256',
|
|
60
|
+
{
|
|
61
|
+
label: 'uint256',
|
|
62
|
+
members: undefined,
|
|
63
|
+
numberOfBytes: '32',
|
|
64
|
+
},
|
|
65
|
+
],
|
|
66
|
+
],
|
|
67
|
+
}
|
|
Binary file
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import test from 'ava';
|
|
2
|
+
import { artifacts } from 'hardhat';
|
|
3
|
+
|
|
4
|
+
import { validate } from './validate';
|
|
5
|
+
import { solcInputOutputDecoder } from './src-decoder';
|
|
6
|
+
|
|
7
|
+
test('namespace outside contract', async t => {
|
|
8
|
+
const contract = 'contracts/test/NamespacedOutsideContract.sol:Example';
|
|
9
|
+
|
|
10
|
+
const buildInfo = await artifacts.getBuildInfo(contract);
|
|
11
|
+
if (buildInfo === undefined) {
|
|
12
|
+
throw new Error(`Build info not found for contract ${contract}`);
|
|
13
|
+
}
|
|
14
|
+
const solcOutput = buildInfo.output;
|
|
15
|
+
const solcInput = buildInfo.input;
|
|
16
|
+
const decodeSrc = solcInputOutputDecoder(solcInput, solcOutput);
|
|
17
|
+
const error = t.throws(() => validate(solcOutput, decodeSrc));
|
|
18
|
+
t.assert(
|
|
19
|
+
error?.message.includes(
|
|
20
|
+
'contracts/test/NamespacedOutsideContract.sol:7: Namespace struct MainStorage is defined outside of a contract',
|
|
21
|
+
),
|
|
22
|
+
error?.message,
|
|
23
|
+
);
|
|
24
|
+
});
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import _test, { TestFn } from 'ava';
|
|
2
|
+
import { artifacts } from 'hardhat';
|
|
3
|
+
|
|
4
|
+
import { validate } from './validate';
|
|
5
|
+
import { solcInputOutputDecoder } from './src-decoder';
|
|
6
|
+
|
|
7
|
+
interface Context {
|
|
8
|
+
validate: (solcVersion?: string) => ReturnType<typeof validate>;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
const test = _test as TestFn<Context>;
|
|
12
|
+
|
|
13
|
+
test.before(async t => {
|
|
14
|
+
const contract = 'contracts/test/Namespaced.sol:Example';
|
|
15
|
+
|
|
16
|
+
const buildInfo = await artifacts.getBuildInfo(contract);
|
|
17
|
+
if (buildInfo === undefined) {
|
|
18
|
+
throw new Error(`Build info not found for contract ${contract}`);
|
|
19
|
+
}
|
|
20
|
+
const solcOutput = buildInfo.output;
|
|
21
|
+
const solcInput = buildInfo.input;
|
|
22
|
+
const decodeSrc = solcInputOutputDecoder(solcInput, solcOutput);
|
|
23
|
+
|
|
24
|
+
t.context.validate = solcVersion => validate(solcOutput, decodeSrc, solcVersion, solcInput);
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
test('namespace with older solc version', async t => {
|
|
28
|
+
const { validate } = t.context;
|
|
29
|
+
const error = t.throws(() => validate('0.8.19'));
|
|
30
|
+
t.assert(
|
|
31
|
+
error?.message.includes(
|
|
32
|
+
`contracts/test/Namespaced.sol: Namespace annotations require Solidity version >= 0.8.20, but 0.8.19 was used`,
|
|
33
|
+
),
|
|
34
|
+
error?.message,
|
|
35
|
+
);
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
test('namespace with correct solc version', async t => {
|
|
39
|
+
const { validate } = t.context;
|
|
40
|
+
validate('0.8.20');
|
|
41
|
+
t.pass();
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
test('namespace with newer solc version', async t => {
|
|
45
|
+
const { validate } = t.context;
|
|
46
|
+
validate('0.8.21');
|
|
47
|
+
t.pass();
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
test('namespace with no solc version', async t => {
|
|
51
|
+
const { validate } = t.context;
|
|
52
|
+
const error = t.throws(() => validate(undefined));
|
|
53
|
+
t.assert(
|
|
54
|
+
error?.message.includes(
|
|
55
|
+
`contracts/test/Namespaced.sol: Namespace annotations require Solidity version >= 0.8.20, but no solcVersion parameter was provided`,
|
|
56
|
+
),
|
|
57
|
+
error?.message,
|
|
58
|
+
);
|
|
59
|
+
});
|