@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.
Files changed (178) hide show
  1. package/dist/call-optional-signature.d.ts +3 -0
  2. package/dist/call-optional-signature.d.ts.map +1 -0
  3. package/dist/call-optional-signature.js +24 -0
  4. package/dist/call-optional-signature.js.map +1 -0
  5. package/dist/cli/validate/build-info-file.d.ts +4 -0
  6. package/dist/cli/validate/build-info-file.d.ts.map +1 -1
  7. package/dist/cli/validate/build-info-file.js +5 -2
  8. package/dist/cli/validate/build-info-file.js.map +1 -1
  9. package/dist/cli/validate/build-info-file.test.js +4 -1
  10. package/dist/cli/validate/build-info-file.test.js.map +1 -1
  11. package/dist/cli/validate/upgradeability-assessment.js +2 -6
  12. package/dist/cli/validate/upgradeability-assessment.js.map +1 -1
  13. package/dist/cli/validate/validations.d.ts.map +1 -1
  14. package/dist/cli/validate/validations.js +5 -4
  15. package/dist/cli/validate/validations.js.map +1 -1
  16. package/dist/impl-address.d.ts.map +1 -1
  17. package/dist/impl-address.js +9 -16
  18. package/dist/impl-address.js.map +1 -1
  19. package/dist/index.d.ts +2 -0
  20. package/dist/index.d.ts.map +1 -1
  21. package/dist/index.js +5 -1
  22. package/dist/index.js.map +1 -1
  23. package/dist/levenshtein.d.ts +6 -0
  24. package/dist/levenshtein.d.ts.map +1 -1
  25. package/dist/levenshtein.js.map +1 -1
  26. package/dist/solc-api.d.ts +14 -0
  27. package/dist/solc-api.d.ts.map +1 -1
  28. package/dist/standalone.d.ts +4 -1
  29. package/dist/standalone.d.ts.map +1 -1
  30. package/dist/standalone.js +6 -3
  31. package/dist/standalone.js.map +1 -1
  32. package/dist/standalone.test.js +17 -0
  33. package/dist/standalone.test.js.map +1 -1
  34. package/dist/storage/compare.d.ts +2 -1
  35. package/dist/storage/compare.d.ts.map +1 -1
  36. package/dist/storage/compare.js +25 -2
  37. package/dist/storage/compare.js.map +1 -1
  38. package/dist/storage/extract.d.ts +15 -3
  39. package/dist/storage/extract.d.ts.map +1 -1
  40. package/dist/storage/extract.js +48 -21
  41. package/dist/storage/extract.js.map +1 -1
  42. package/dist/storage/index.d.ts.map +1 -1
  43. package/dist/storage/index.js +15 -1
  44. package/dist/storage/index.js.map +1 -1
  45. package/dist/storage/layout.d.ts +1 -0
  46. package/dist/storage/layout.d.ts.map +1 -1
  47. package/dist/storage/layout.js.map +1 -1
  48. package/dist/storage/namespace.d.ts +34 -0
  49. package/dist/storage/namespace.d.ts.map +1 -0
  50. package/dist/storage/namespace.js +191 -0
  51. package/dist/storage/namespace.js.map +1 -0
  52. package/dist/storage/report.js +6 -0
  53. package/dist/storage/report.js.map +1 -1
  54. package/dist/storage-namespaced-conflicts-layout.test.d.ts +2 -0
  55. package/dist/storage-namespaced-conflicts-layout.test.d.ts.map +1 -0
  56. package/dist/storage-namespaced-conflicts-layout.test.js +69 -0
  57. package/dist/storage-namespaced-conflicts-layout.test.js.map +1 -0
  58. package/dist/storage-namespaced-conflicts.test.d.ts +2 -0
  59. package/dist/storage-namespaced-conflicts.test.d.ts.map +1 -0
  60. package/dist/storage-namespaced-conflicts.test.js +45 -0
  61. package/dist/storage-namespaced-conflicts.test.js.map +1 -0
  62. package/dist/storage-namespaced-layout.test.d.ts +2 -0
  63. package/dist/storage-namespaced-layout.test.d.ts.map +1 -0
  64. package/dist/storage-namespaced-layout.test.js +59 -0
  65. package/dist/storage-namespaced-layout.test.js.map +1 -0
  66. package/dist/storage-namespaced-outside-contract.test.d.ts +2 -0
  67. package/dist/storage-namespaced-outside-contract.test.d.ts.map +1 -0
  68. package/dist/storage-namespaced-outside-contract.test.js +22 -0
  69. package/dist/storage-namespaced-outside-contract.test.js.map +1 -0
  70. package/dist/storage-namespaced-solc-versions.test.d.ts +2 -0
  71. package/dist/storage-namespaced-solc-versions.test.d.ts.map +1 -0
  72. package/dist/storage-namespaced-solc-versions.test.js +42 -0
  73. package/dist/storage-namespaced-solc-versions.test.js.map +1 -0
  74. package/dist/storage-namespaced-udvt.test.d.ts +2 -0
  75. package/dist/storage-namespaced-udvt.test.d.ts.map +1 -0
  76. package/dist/storage-namespaced-udvt.test.js +130 -0
  77. package/dist/storage-namespaced-udvt.test.js.map +1 -0
  78. package/dist/storage-namespaced.test.d.ts +2 -0
  79. package/dist/storage-namespaced.test.d.ts.map +1 -0
  80. package/dist/storage-namespaced.test.js +132 -0
  81. package/dist/storage-namespaced.test.js.map +1 -0
  82. package/dist/upgrade-interface-version.d.ts +3 -0
  83. package/dist/upgrade-interface-version.d.ts.map +1 -0
  84. package/dist/upgrade-interface-version.js +25 -0
  85. package/dist/upgrade-interface-version.js.map +1 -0
  86. package/dist/upgrade-interface-version.test.d.ts +2 -0
  87. package/dist/upgrade-interface-version.test.d.ts.map +1 -0
  88. package/dist/upgrade-interface-version.test.js +32 -0
  89. package/dist/upgrade-interface-version.test.js.map +1 -0
  90. package/dist/utils/annotations.d.ts +4 -0
  91. package/dist/utils/annotations.d.ts.map +1 -1
  92. package/dist/utils/annotations.js +9 -1
  93. package/dist/utils/annotations.js.map +1 -1
  94. package/dist/utils/make-namespaced.d.ts +20 -0
  95. package/dist/utils/make-namespaced.d.ts.map +1 -0
  96. package/dist/utils/make-namespaced.js +131 -0
  97. package/dist/utils/make-namespaced.js.map +1 -0
  98. package/dist/utils/make-namespaced.test.d.ts +2 -0
  99. package/dist/utils/make-namespaced.test.d.ts.map +1 -0
  100. package/dist/utils/make-namespaced.test.js +59 -0
  101. package/dist/utils/make-namespaced.test.js.map +1 -0
  102. package/dist/utils/stabilize-layout.d.ts +11 -0
  103. package/dist/utils/stabilize-layout.d.ts.map +1 -1
  104. package/dist/utils/stabilize-layout.js +5 -0
  105. package/dist/utils/stabilize-layout.js.map +1 -1
  106. package/dist/validate/overrides.js +1 -1
  107. package/dist/validate/overrides.js.map +1 -1
  108. package/dist/validate/query.d.ts.map +1 -1
  109. package/dist/validate/query.js +7 -3
  110. package/dist/validate/query.js.map +1 -1
  111. package/dist/validate/report.js +2 -2
  112. package/dist/validate/report.js.map +1 -1
  113. package/dist/validate/run.d.ts +18 -2
  114. package/dist/validate/run.d.ts.map +1 -1
  115. package/dist/validate/run.js +104 -2
  116. package/dist/validate/run.js.map +1 -1
  117. package/dist/validate.test.js +3 -0
  118. package/dist/validate.test.js.map +1 -1
  119. package/package.json +3 -3
  120. package/src/call-optional-signature.ts +20 -0
  121. package/src/cli/cli.test.ts.md +4 -4
  122. package/src/cli/cli.test.ts.snap +0 -0
  123. package/src/cli/validate/build-info-file.test.ts +4 -1
  124. package/src/cli/validate/build-info-file.ts +12 -2
  125. package/src/cli/validate/project-report.test.ts.md +4 -4
  126. package/src/cli/validate/project-report.test.ts.snap +0 -0
  127. package/src/cli/validate/upgradeability-assessment.ts +1 -6
  128. package/src/cli/validate/validate-upgrade-safety.test.ts.md +2 -2
  129. package/src/cli/validate/validate-upgrade-safety.test.ts.snap +0 -0
  130. package/src/cli/validate/validations.test.ts.md +2 -2
  131. package/src/cli/validate/validations.test.ts.snap +0 -0
  132. package/src/cli/validate/validations.ts +6 -5
  133. package/src/impl-address.ts +9 -20
  134. package/src/index.ts +3 -0
  135. package/src/levenshtein.ts +7 -0
  136. package/src/solc-api.ts +14 -0
  137. package/src/standalone.test.ts +26 -0
  138. package/src/standalone.ts +6 -2
  139. package/src/storage/compare.ts +34 -2
  140. package/src/storage/extract.ts +68 -20
  141. package/src/storage/index.ts +22 -1
  142. package/src/storage/layout.ts +1 -0
  143. package/src/storage/namespace.ts +262 -0
  144. package/src/storage/report.ts +8 -0
  145. package/src/storage-0.8.test.ts.md +4 -0
  146. package/src/storage-0.8.test.ts.snap +0 -0
  147. package/src/storage-memory-0.5.test.ts.md +2 -0
  148. package/src/storage-memory-0.5.test.ts.snap +0 -0
  149. package/src/storage-namespaced-conflicts-layout.test.ts +96 -0
  150. package/src/storage-namespaced-conflicts-layout.test.ts.md +53 -0
  151. package/src/storage-namespaced-conflicts-layout.test.ts.snap +0 -0
  152. package/src/storage-namespaced-conflicts.test.ts +54 -0
  153. package/src/storage-namespaced-conflicts.test.ts.md +53 -0
  154. package/src/storage-namespaced-conflicts.test.ts.snap +0 -0
  155. package/src/storage-namespaced-layout.test.ts +77 -0
  156. package/src/storage-namespaced-layout.test.ts.md +67 -0
  157. package/src/storage-namespaced-layout.test.ts.snap +0 -0
  158. package/src/storage-namespaced-outside-contract.test.ts +24 -0
  159. package/src/storage-namespaced-solc-versions.test.ts +59 -0
  160. package/src/storage-namespaced-udvt.test.ts +160 -0
  161. package/src/storage-namespaced.test.ts +146 -0
  162. package/src/storage-namespaced.test.ts.md +89 -0
  163. package/src/storage-namespaced.test.ts.snap +0 -0
  164. package/src/storage.test.ts.md +2 -0
  165. package/src/storage.test.ts.snap +0 -0
  166. package/src/upgrade-interface-version.test.ts +37 -0
  167. package/src/upgrade-interface-version.ts +27 -0
  168. package/src/utils/annotations.ts +8 -0
  169. package/src/utils/make-namespaced.test.ts +74 -0
  170. package/src/utils/make-namespaced.test.ts.md +154 -0
  171. package/src/utils/make-namespaced.test.ts.snap +0 -0
  172. package/src/utils/make-namespaced.ts +154 -0
  173. package/src/utils/stabilize-layout.ts +5 -0
  174. package/src/validate/overrides.ts +1 -1
  175. package/src/validate/query.ts +9 -3
  176. package/src/validate/report.ts +3 -2
  177. package/src/validate/run.ts +109 -2
  178. package/src/validate.test.ts +3 -0
@@ -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.`
@@ -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.`
@@ -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
+ }
@@ -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
+ });