@openzeppelin/upgrades-core 1.43.0 → 1.44.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 (80) hide show
  1. package/artifacts/@openzeppelin/contracts-v5/proxy/ERC1967/ERC1967Proxy.sol/ERC1967Proxy.json +3 -3
  2. package/artifacts/@openzeppelin/contracts-v5/proxy/beacon/BeaconProxy.sol/BeaconProxy.json +3 -3
  3. package/artifacts/@openzeppelin/contracts-v5/proxy/beacon/UpgradeableBeacon.sol/UpgradeableBeacon.json +2 -2
  4. package/artifacts/@openzeppelin/contracts-v5/proxy/transparent/ProxyAdmin.sol/ProxyAdmin.json +2 -2
  5. package/artifacts/@openzeppelin/contracts-v5/proxy/transparent/TransparentUpgradeableProxy.sol/ITransparentUpgradeableProxy.json +2 -2
  6. package/artifacts/@openzeppelin/contracts-v5/proxy/transparent/TransparentUpgradeableProxy.sol/TransparentUpgradeableProxy.json +3 -3
  7. package/artifacts/build-info-v5.json +5159 -2886
  8. package/dist/solidity-version.json +1 -1
  9. package/dist/storage/extract.d.ts.map +1 -1
  10. package/dist/storage/extract.js +14 -0
  11. package/dist/storage/extract.js.map +1 -1
  12. package/dist/storage/index.d.ts.map +1 -1
  13. package/dist/storage/index.js +23 -0
  14. package/dist/storage/index.js.map +1 -1
  15. package/dist/storage/layout.d.ts +1 -0
  16. package/dist/storage/layout.d.ts.map +1 -1
  17. package/dist/storage/layout.js.map +1 -1
  18. package/dist/storage/namespace.d.ts.map +1 -1
  19. package/dist/storage/namespace.js +47 -1
  20. package/dist/storage/namespace.js.map +1 -1
  21. package/dist/storage-custom-layout.test.d.ts +2 -0
  22. package/dist/storage-custom-layout.test.d.ts.map +1 -0
  23. package/dist/storage-custom-layout.test.js +314 -0
  24. package/dist/storage-custom-layout.test.js.map +1 -0
  25. package/dist/utils/erc7201.d.ts +10 -0
  26. package/dist/utils/erc7201.d.ts.map +1 -0
  27. package/dist/utils/erc7201.js +24 -0
  28. package/dist/utils/erc7201.js.map +1 -0
  29. package/dist/utils/erc7201.test.d.ts +2 -0
  30. package/dist/utils/erc7201.test.d.ts.map +1 -0
  31. package/dist/utils/erc7201.test.js +11 -0
  32. package/dist/utils/erc7201.test.js.map +1 -0
  33. package/dist/utils/integer-literals.d.ts +15 -0
  34. package/dist/utils/integer-literals.d.ts.map +1 -0
  35. package/dist/utils/integer-literals.js +34 -0
  36. package/dist/utils/integer-literals.js.map +1 -0
  37. package/dist/utils/integer-literals.test.d.ts +2 -0
  38. package/dist/utils/integer-literals.test.d.ts.map +1 -0
  39. package/dist/utils/integer-literals.test.js +57 -0
  40. package/dist/utils/integer-literals.test.js.map +1 -0
  41. package/dist/utils/make-namespaced.d.ts.map +1 -1
  42. package/dist/utils/make-namespaced.js +4 -0
  43. package/dist/utils/make-namespaced.js.map +1 -1
  44. package/dist/utils/make-namespaced.test.js +4 -0
  45. package/dist/utils/make-namespaced.test.js.map +1 -1
  46. package/dist/utils/stabilize-layout.d.ts +1 -0
  47. package/dist/utils/stabilize-layout.d.ts.map +1 -1
  48. package/dist/utils/stabilize-layout.js +1 -0
  49. package/dist/utils/stabilize-layout.js.map +1 -1
  50. package/dist/validate-initializers.test.js +1 -1
  51. package/dist/validate-initializers.test.js.map +1 -1
  52. package/package.json +7 -4
  53. package/src/solidity-version.json +1 -1
  54. package/src/storage/extract.ts +21 -0
  55. package/src/storage/index.ts +29 -0
  56. package/src/storage/layout.ts +1 -0
  57. package/src/storage/namespace.ts +67 -1
  58. package/src/storage-0.8.test.ts.md +4 -0
  59. package/src/storage-0.8.test.ts.snap +0 -0
  60. package/src/storage-custom-layout.test.ts +358 -0
  61. package/src/storage-custom-layout.test.ts.md +353 -0
  62. package/src/storage-custom-layout.test.ts.snap +0 -0
  63. package/src/storage-memory-0.5.test.ts.md +2 -0
  64. package/src/storage-memory-0.5.test.ts.snap +0 -0
  65. package/src/storage-namespaced-layout.test.ts.md +1 -0
  66. package/src/storage-namespaced-layout.test.ts.snap +0 -0
  67. package/src/storage-namespaced.test.ts.md +2 -0
  68. package/src/storage-namespaced.test.ts.snap +0 -0
  69. package/src/storage.test.ts.md +2 -0
  70. package/src/storage.test.ts.snap +0 -0
  71. package/src/utils/erc7201.test.ts +10 -0
  72. package/src/utils/erc7201.ts +25 -0
  73. package/src/utils/integer-literals.test.ts +73 -0
  74. package/src/utils/integer-literals.ts +29 -0
  75. package/src/utils/make-namespaced.test.ts +7 -0
  76. package/src/utils/make-namespaced.test.ts.md +50 -0
  77. package/src/utils/make-namespaced.test.ts.snap +0 -0
  78. package/src/utils/make-namespaced.ts +5 -0
  79. package/src/utils/stabilize-layout.ts +1 -0
  80. package/src/validate-initializers.test.ts +1 -1
@@ -0,0 +1,353 @@
1
+ # Snapshot report for `src/storage-custom-layout.test.ts`
2
+
3
+ The actual snapshot is saved in `storage-custom-layout.test.ts.snap`.
4
+
5
+ Generated by [AVA](https://avajs.dev).
6
+
7
+ ## CustomLayout
8
+
9
+ > Snapshot 1
10
+
11
+ {
12
+ baseSlot: '0x1',
13
+ namespaces: [],
14
+ storage: [
15
+ {
16
+ contract: 'Base',
17
+ label: 'x',
18
+ offset: 0,
19
+ renamedFrom: undefined,
20
+ retypedFrom: undefined,
21
+ slot: '1',
22
+ src: 'file.sol:1',
23
+ type: 't_uint256',
24
+ },
25
+ {
26
+ contract: 'CustomLayout',
27
+ label: 'y',
28
+ offset: 0,
29
+ renamedFrom: undefined,
30
+ retypedFrom: undefined,
31
+ slot: '2',
32
+ src: 'file.sol:1',
33
+ type: 't_uint256',
34
+ },
35
+ ],
36
+ types: [
37
+ [
38
+ 't_uint256',
39
+ {
40
+ label: 'uint256',
41
+ members: undefined,
42
+ numberOfBytes: '32',
43
+ },
44
+ ],
45
+ ],
46
+ }
47
+
48
+ ## CustomLayout - fallback
49
+
50
+ > Snapshot 1
51
+
52
+ {
53
+ baseSlot: '0x1',
54
+ namespaces: [],
55
+ storage: [
56
+ {
57
+ contract: 'CustomLayout',
58
+ label: 'y',
59
+ renamedFrom: undefined,
60
+ retypedFrom: undefined,
61
+ src: 'file.sol:1',
62
+ type: 't_uint256',
63
+ },
64
+ ],
65
+ types: [
66
+ [
67
+ 't_uint256',
68
+ {
69
+ label: 'uint256',
70
+ members: undefined,
71
+ },
72
+ ],
73
+ ],
74
+ }
75
+
76
+ ## CustomLayout changed root - fallback - bad
77
+
78
+ > Snapshot 1
79
+
80
+ `Base slot for custom storage layout changed from 0x0000000000000000000000000000000000000000000000000000000000000001 to 0x0000000000000000000000000000000000000000000000000000000000000002␊
81
+ ␊
82
+ Do not change the base slot during upgrades when using custom storage layout.␊
83
+ ␊
84
+ If you need to change the base slot, ensure you also do the following:␊
85
+ 1. Adjust all storage variables to continue using their original slots.␊
86
+ 2. Configure your Solidity compiler options to include storage layouts according to https://docs.openzeppelin.com/upgrades-plugins/api-core#compile_contracts_with_storage_layouts␊
87
+ 3. Recompile both the original and updated contracts.␊
88
+ 4. Run the storage layout check again.`
89
+
90
+ ## CustomLayout changed root decimal - fallback - bad
91
+
92
+ > Snapshot 1
93
+
94
+ `Base slot for custom storage layout changed from 0x0000000000000000000000000000000000000000000000000000000000000001 to 0x0000000000000000000000000000000000000000000000000000000000000002␊
95
+ ␊
96
+ Do not change the base slot during upgrades when using custom storage layout.␊
97
+ ␊
98
+ If you need to change the base slot, ensure you also do the following:␊
99
+ 1. Adjust all storage variables to continue using their original slots.␊
100
+ 2. Configure your Solidity compiler options to include storage layouts according to https://docs.openzeppelin.com/upgrades-plugins/api-core#compile_contracts_with_storage_layouts␊
101
+ 3. Recompile both the original and updated contracts.␊
102
+ 4. Run the storage layout check again.`
103
+
104
+ ## CustomLayout changed root scientific notation - fallback - bad
105
+
106
+ > Snapshot 1
107
+
108
+ `Base slot for custom storage layout changed from 0x0000000000000000000000000000000000000000000000000000000000000001 to 0x00000000000000000000000000000000000000000000000000000004a817c800␊
109
+ ␊
110
+ Do not change the base slot during upgrades when using custom storage layout.␊
111
+ ␊
112
+ If you need to change the base slot, ensure you also do the following:␊
113
+ 1. Adjust all storage variables to continue using their original slots.␊
114
+ 2. Configure your Solidity compiler options to include storage layouts according to https://docs.openzeppelin.com/upgrades-plugins/api-core#compile_contracts_with_storage_layouts␊
115
+ 3. Recompile both the original and updated contracts.␊
116
+ 4. Run the storage layout check again.`
117
+
118
+ ## CustomLayout changed to default - fallback - bad
119
+
120
+ > Snapshot 1
121
+
122
+ `Base slot for custom storage layout changed from 0x0000000000000000000000000000000000000000000000000000000000000001 to 0x0000000000000000000000000000000000000000000000000000000000000000␊
123
+ ␊
124
+ Do not change the base slot during upgrades when using custom storage layout.␊
125
+ ␊
126
+ If you need to change the base slot, ensure you also do the following:␊
127
+ 1. Adjust all storage variables to continue using their original slots.␊
128
+ 2. Configure your Solidity compiler options to include storage layouts according to https://docs.openzeppelin.com/upgrades-plugins/api-core#compile_contracts_with_storage_layouts␊
129
+ 3. Recompile both the original and updated contracts.␊
130
+ 4. Run the storage layout check again.`
131
+
132
+ ## CustomLayout changed root - fallback - bad (no layout info)
133
+
134
+ > Snapshot 1
135
+
136
+ `Base slot for custom storage layout changed from 0x0000000000000000000000000000000000000000000000000000000000000001 to 0x0000000000000000000000000000000000000000000000000000000000000000␊
137
+ ␊
138
+ Do not change the base slot during upgrades when using custom storage layout.␊
139
+ ␊
140
+ If you need to change the base slot, ensure you also do the following:␊
141
+ 1. Adjust all storage variables to continue using their original slots.␊
142
+ 2. Configure your Solidity compiler options to include storage layouts according to https://docs.openzeppelin.com/upgrades-plugins/api-core#compile_contracts_with_storage_layouts␊
143
+ 3. Recompile both the original and updated contracts.␊
144
+ 4. Run the storage layout check again.`
145
+
146
+ ## CustomLayout changed to default - fallback - bad (no layout info)
147
+
148
+ > Snapshot 1
149
+
150
+ `Base slot for custom storage layout changed from 0x0000000000000000000000000000000000000000000000000000000000000001 to 0x0000000000000000000000000000000000000000000000000000000000000000␊
151
+ ␊
152
+ Do not change the base slot during upgrades when using custom storage layout.␊
153
+ ␊
154
+ If you need to change the base slot, ensure you also do the following:␊
155
+ 1. Adjust all storage variables to continue using their original slots.␊
156
+ 2. Configure your Solidity compiler options to include storage layouts according to https://docs.openzeppelin.com/upgrades-plugins/api-core#compile_contracts_with_storage_layouts␊
157
+ 3. Recompile both the original and updated contracts.␊
158
+ 4. Run the storage layout check again.`
159
+
160
+ ## CustomLayout unsupported node type
161
+
162
+ > Snapshot 1
163
+
164
+ `file.sol:1: Custom storage layout expression with node type BinaryOperation is not currently supported␊
165
+ ␊
166
+ Please report this at https://zpl.in/upgrades/report and include the \`layout at\` expression from your contract.`
167
+
168
+ ## Namespaced - custom layout clash
169
+
170
+ > Snapshot 1
171
+
172
+ `Custom layout for contract Namespaced_Custom_Layout_Clash clashes with the storage location for namespace erc7201:example.main␊
173
+ ␊
174
+ The namespace erc7201:example.main is defined in a struct at the following location:␊
175
+ - file.sol:1␊
176
+ ␊
177
+ Specify a different custom layout for the contract or use a different namespace for the struct.`
178
+
179
+ ## Namespaced - custom layout clash decimal
180
+
181
+ > Snapshot 1
182
+
183
+ `Custom layout for contract Namespaced_Custom_Layout_Clash_Decimal clashes with the storage location for namespace erc7201:example.main␊
184
+ ␊
185
+ The namespace erc7201:example.main is defined in a struct at the following location:␊
186
+ - file.sol:1␊
187
+ ␊
188
+ Specify a different custom layout for the contract or use a different namespace for the struct.`
189
+
190
+ ## Namespaced - custom layout clash extra colon
191
+
192
+ > Snapshot 1
193
+
194
+ `Custom layout for contract Namespaced_Custom_Layout_Clash_Extra_Colon clashes with the storage location for namespace erc7201:example:main␊
195
+ ␊
196
+ The namespace erc7201:example:main is defined in a struct at the following location:␊
197
+ - file.sol:1␊
198
+ ␊
199
+ Specify a different custom layout for the contract or use a different namespace for the struct.`
200
+
201
+ ## CustomLayout no namespace formula - ok
202
+
203
+ > Snapshot 1
204
+
205
+ {
206
+ baseSlot: '0x183a6125c38840424c4a85fa12bab2ab606c4b6d0e7cc73c0c06ba5300eab500',
207
+ namespaces: [
208
+ [
209
+ 'example.main',
210
+ [
211
+ {
212
+ contract: 'CustomLayout_No_Namespace_Formula',
213
+ label: 'x',
214
+ src: 'file.sol:1',
215
+ type: 't_uint256',
216
+ },
217
+ {
218
+ contract: 'CustomLayout_No_Namespace_Formula',
219
+ label: 'y',
220
+ src: 'file.sol:1',
221
+ type: 't_uint256',
222
+ },
223
+ ],
224
+ ],
225
+ ],
226
+ storage: [
227
+ {
228
+ contract: 'CustomLayout_No_Namespace_Formula',
229
+ label: 'a',
230
+ offset: 0,
231
+ renamedFrom: undefined,
232
+ retypedFrom: undefined,
233
+ slot: '10958655983261152271848436692291137275443024275653522991983264966744321209600',
234
+ src: 'file.sol:1',
235
+ type: 't_uint256',
236
+ },
237
+ ],
238
+ types: [
239
+ [
240
+ 't_uint256',
241
+ {
242
+ label: 'uint256',
243
+ members: undefined,
244
+ numberOfBytes: '32',
245
+ },
246
+ ],
247
+ ],
248
+ }
249
+
250
+ ## CustomLayout unknown namespace formula - ok
251
+
252
+ > Snapshot 1
253
+
254
+ {
255
+ baseSlot: '0x183a6125c38840424c4a85fa12bab2ab606c4b6d0e7cc73c0c06ba5300eab500',
256
+ namespaces: [
257
+ [
258
+ 'erc0000:example.main',
259
+ [
260
+ {
261
+ contract: 'CustomLayout_Unknown_Namespace_Formula',
262
+ label: 'x',
263
+ src: 'file.sol:1',
264
+ type: 't_uint256',
265
+ },
266
+ {
267
+ contract: 'CustomLayout_Unknown_Namespace_Formula',
268
+ label: 'y',
269
+ src: 'file.sol:1',
270
+ type: 't_uint256',
271
+ },
272
+ ],
273
+ ],
274
+ ],
275
+ storage: [
276
+ {
277
+ contract: 'CustomLayout_Unknown_Namespace_Formula',
278
+ label: 'a',
279
+ offset: 0,
280
+ renamedFrom: undefined,
281
+ retypedFrom: undefined,
282
+ slot: '10958655983261152271848436692291137275443024275653522991983264966744321209600',
283
+ src: 'file.sol:1',
284
+ type: 't_uint256',
285
+ },
286
+ ],
287
+ types: [
288
+ [
289
+ 't_uint256',
290
+ {
291
+ label: 'uint256',
292
+ members: undefined,
293
+ numberOfBytes: '32',
294
+ },
295
+ ],
296
+ ],
297
+ }
298
+
299
+ ## CustomLayout multiple namespaces
300
+
301
+ > Snapshot 1
302
+
303
+ {
304
+ baseSlot: '0x1',
305
+ namespaces: [
306
+ [
307
+ 'erc7201:example.b',
308
+ [
309
+ {
310
+ contract: 'NamespaceB',
311
+ label: 'x',
312
+ src: 'file.sol:1',
313
+ type: 't_uint256',
314
+ },
315
+ ],
316
+ ],
317
+ [
318
+ 'erc7201:example.a',
319
+ [
320
+ {
321
+ contract: 'NamespaceA',
322
+ label: 'x',
323
+ src: 'file.sol:1',
324
+ type: 't_uint256',
325
+ },
326
+ ],
327
+ ],
328
+ ],
329
+ storage: [],
330
+ types: [
331
+ [
332
+ 't_uint256',
333
+ {
334
+ label: 'uint256',
335
+ members: undefined,
336
+ },
337
+ ],
338
+ ],
339
+ }
340
+
341
+ ## Gap - changed root - fallback - bad (no layout info)
342
+
343
+ > Snapshot 1
344
+
345
+ `Base slot for custom storage layout changed from 0x0000000000000000000000000000000000000000000000000000000000000000 to 0x0000000000000000000000000000000000000000000000000000000000000019␊
346
+ ␊
347
+ Do not change the base slot during upgrades when using custom storage layout.␊
348
+ ␊
349
+ If you need to change the base slot, ensure you also do the following:␊
350
+ 1. Adjust all storage variables to continue using their original slots.␊
351
+ 2. Configure your Solidity compiler options to include storage layouts according to https://docs.openzeppelin.com/upgrades-plugins/api-core#compile_contracts_with_storage_layouts␊
352
+ 3. Recompile both the original and updated contracts.␊
353
+ 4. Run the storage layout check again.`
@@ -9,6 +9,7 @@ Generated by [AVA](https://avajs.dev).
9
9
  > Snapshot 1
10
10
 
11
11
  {
12
+ baseSlot: undefined,
12
13
  namespaces: [],
13
14
  storage: [
14
15
  {
@@ -95,6 +96,7 @@ Generated by [AVA](https://avajs.dev).
95
96
  > Snapshot 1
96
97
 
97
98
  {
99
+ baseSlot: undefined,
98
100
  namespaces: [],
99
101
  storage: [
100
102
  {
Binary file
@@ -9,6 +9,7 @@ Generated by [AVA](https://avajs.dev).
9
9
  > Snapshot 1
10
10
 
11
11
  {
12
+ baseSlot: undefined,
12
13
  namespaces: [
13
14
  [
14
15
  'erc7201:example.main',
@@ -9,6 +9,7 @@ Generated by [AVA](https://avajs.dev).
9
9
  > Snapshot 1
10
10
 
11
11
  {
12
+ baseSlot: undefined,
12
13
  namespaces: [
13
14
  [
14
15
  'erc7201:example.main',
@@ -45,6 +46,7 @@ Generated by [AVA](https://avajs.dev).
45
46
  > Snapshot 1
46
47
 
47
48
  {
49
+ baseSlot: undefined,
48
50
  namespaces: [
49
51
  [
50
52
  'erc7201:one',
Binary file
@@ -9,6 +9,7 @@ Generated by [AVA](https://avajs.dev).
9
9
  > Snapshot 1
10
10
 
11
11
  {
12
+ baseSlot: undefined,
12
13
  namespaces: [],
13
14
  storage: [
14
15
  {
@@ -93,6 +94,7 @@ Generated by [AVA](https://avajs.dev).
93
94
  > Snapshot 1
94
95
 
95
96
  {
97
+ baseSlot: undefined,
96
98
  namespaces: [],
97
99
  storage: [
98
100
  {
Binary file
@@ -0,0 +1,10 @@
1
+ import test from 'ava';
2
+
3
+ import { calculateERC7201StorageLocation } from './erc7201';
4
+
5
+ test('calculateERC7201StorageLocation', t => {
6
+ t.is(
7
+ calculateERC7201StorageLocation('example.main'),
8
+ '0x183a6125c38840424c4a85fa12bab2ab606c4b6d0e7cc73c0c06ba5300eab500',
9
+ );
10
+ });
@@ -0,0 +1,25 @@
1
+ import { keccak256 } from 'ethereumjs-util';
2
+
3
+ export const ERC7201_FORMULA_PREFIX = 'erc7201:';
4
+
5
+ /**
6
+ * Returns the ERC-7201 storage location hash for a given namespace id using formula:
7
+ * keccak256(abi.encode(uint256(keccak256(bytes(id))) - 1)) & ~bytes32(uint256(0xff))
8
+ *
9
+ * @param id The namespace id, not including the 'erc7201:' prefix
10
+ * @returns The ERC-7201 storage location hash as a hex string
11
+ */
12
+ export function calculateERC7201StorageLocation(id: string): string {
13
+ const firstHash = keccak256(Buffer.from(id));
14
+ const minusOne = BigInt(`0x${firstHash.toString('hex')}`) - 1n;
15
+ const minusOneBuffer = Buffer.from(minusOne.toString(16), 'hex');
16
+
17
+ const secondHash = keccak256(minusOneBuffer);
18
+
19
+ const mask = BigInt('0xff');
20
+ const masked = BigInt(`0x${secondHash.toString('hex')}`) & ~mask;
21
+
22
+ const padded = masked.toString(16).padStart(64, '0');
23
+
24
+ return `0x${padded}`;
25
+ }
@@ -0,0 +1,73 @@
1
+ import test from 'ava';
2
+
3
+ import { normalizeUint256Literal } from './integer-literals';
4
+
5
+ const ZEROES = '0x0000000000000000000000000000000000000000000000000000000000000000';
6
+
7
+ test('falsy', t => {
8
+ t.is(normalizeUint256Literal(undefined), ZEROES);
9
+ t.is(normalizeUint256Literal(null), ZEROES);
10
+ t.is(normalizeUint256Literal(''), ZEROES);
11
+ });
12
+
13
+ test('hex', t => {
14
+ t.is(normalizeUint256Literal('0x12e3'), '0x00000000000000000000000000000000000000000000000000000000000012e3');
15
+ });
16
+
17
+ test('hex - leading zeroes', t => {
18
+ t.is(normalizeUint256Literal('0x0012e3'), '0x00000000000000000000000000000000000000000000000000000000000012e3');
19
+ });
20
+
21
+ test('hex - capital', t => {
22
+ t.is(normalizeUint256Literal('0x12E3'), '0x00000000000000000000000000000000000000000000000000000000000012e3');
23
+ });
24
+
25
+ test('decimal', t => {
26
+ t.is(normalizeUint256Literal('1234'), '0x00000000000000000000000000000000000000000000000000000000000004d2');
27
+ });
28
+
29
+ test('zeroes', t => {
30
+ t.is(normalizeUint256Literal('0'), ZEROES);
31
+ t.is(normalizeUint256Literal('0x000'), ZEROES);
32
+ t.is(normalizeUint256Literal(ZEROES), ZEROES);
33
+ t.is(normalizeUint256Literal('-0'), ZEROES);
34
+ });
35
+
36
+ test('underscores', t => {
37
+ t.is(normalizeUint256Literal('1_23_4'), '0x00000000000000000000000000000000000000000000000000000000000004d2');
38
+ });
39
+
40
+ test('scientific notation', t => {
41
+ t.is(normalizeUint256Literal('20e10'), '0x0000000000000000000000000000000000000000000000000000002e90edd000');
42
+ });
43
+
44
+ test('scientific notation - capital', t => {
45
+ t.is(normalizeUint256Literal('20E10'), '0x0000000000000000000000000000000000000000000000000000002e90edd000');
46
+ });
47
+
48
+ test('scientific notation - fractional base', t => {
49
+ t.is(normalizeUint256Literal('2.5e3'), '0x00000000000000000000000000000000000000000000000000000000000009c4');
50
+ });
51
+
52
+ test('scientific notation - negative exponent', t => {
53
+ t.is(normalizeUint256Literal('250000e-2'), '0x00000000000000000000000000000000000000000000000000000000000009c4');
54
+ });
55
+
56
+ test('scientific notation - invalid integer literal', t => {
57
+ const error = t.throws(() => normalizeUint256Literal('2e-3'));
58
+ t.is(error?.message, 'Invalid integer literal: 2e-3');
59
+ });
60
+
61
+ test('full hex', t => {
62
+ t.is(
63
+ normalizeUint256Literal('0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff'),
64
+ '0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff',
65
+ );
66
+ });
67
+
68
+ test('full hex with leading and trailing zeroes', t => {
69
+ t.is(
70
+ normalizeUint256Literal('0x00ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00'),
71
+ '0x00ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00',
72
+ );
73
+ });
@@ -0,0 +1,29 @@
1
+ import BigNumber from 'bignumber.js';
2
+
3
+ /**
4
+ * Converts a Solidity unsigned integer literal according to https://docs.soliditylang.org/en/latest/types.html#rational-literals
5
+ * to a 64-byte padded hex string.
6
+ *
7
+ * Accepts decimal, hexadecimal, and scientific notation formats.
8
+ *
9
+ * If the input is null or undefined, returns '0x0000000000000000000000000000000000000000000000000000000000000000'.
10
+ *
11
+ * Assumes the input is a valid uint256-compatible literal for Solidity, and only performs minimal validation.
12
+ *
13
+ * @param literal Integer literal to convert
14
+ * @returns Hex string with 0x prefix, padded to 64 bytes with leading zeroes
15
+ */
16
+ export function normalizeUint256Literal(literal: string | null | undefined): string {
17
+ if (!literal) {
18
+ return '0x0000000000000000000000000000000000000000000000000000000000000000';
19
+ }
20
+ const lowercaseNoUnderscores = literal.replace(/_/g, '').toLowerCase();
21
+
22
+ const parsed = new BigNumber(lowercaseNoUnderscores);
23
+ if (!parsed.isInteger()) {
24
+ throw new Error(`Invalid integer literal: ${literal}`);
25
+ }
26
+ const calculatedValueAsHex = parsed.toString(16);
27
+ const padded = calculatedValueAsHex.padStart(64, '0');
28
+ return `0x${padded}`;
29
+ }
@@ -27,6 +27,13 @@ test('make namespaced input - solc 0.7', async t => {
27
27
  await testMakeNamespaced(origBuildInfo, t, '0.7.6');
28
28
  });
29
29
 
30
+ test('make namespaced input - custom layout', async t => {
31
+ const origBuildInfo = await artifacts.getBuildInfo(
32
+ 'contracts/test/NamespacedToModifyCustomLayout.sol:ExampleCustomLayout',
33
+ );
34
+ await testMakeNamespaced(origBuildInfo, t, '0.8.29');
35
+ });
36
+
30
37
  async function testMakeNamespaced(
31
38
  origBuildInfo: BuildInfo | undefined,
32
39
  t: ExecutionContext<unknown>,
@@ -688,3 +688,53 @@ Generated by [AVA](https://avajs.dev).
688
688
  },
689
689
  },
690
690
  }
691
+
692
+ ## make namespaced input - custom layout
693
+
694
+ > Snapshot 1
695
+
696
+ {
697
+ language: 'Solidity',
698
+ settings: {
699
+ evmVersion: 'paris',
700
+ optimizer: {
701
+ enabled: true,
702
+ runs: 200,
703
+ },
704
+ outputSelection: {
705
+ '*': {
706
+ '': [
707
+ 'ast',
708
+ ],
709
+ '*': [
710
+ 'storageLayout',
711
+ ],
712
+ },
713
+ },
714
+ },
715
+ sources: {
716
+ 'contracts/test/NamespacedToModifyCustomLayout.sol': {
717
+ content: `// SPDX-License-Identifier: MIT␊
718
+ pragma solidity ^0.8.29;␊
719
+ ␊
720
+ abstract contract Base {␊
721
+ }␊
722
+ ␊
723
+ abstract contract ExampleCustomLayout is Base {␊
724
+ /// @custom:storage-location erc7201:example.main␊
725
+ struct MainStorage {␊
726
+ uint256 x;␊
727
+ uint256 z;␊
728
+ } MainStorage $MainStorage_random;␊
729
+ }␊
730
+ ␊
731
+ abstract contract ExampleCustomLayout_DifferentSpecifierOrder is Base {␊
732
+ /// @custom:storage-location erc7201:example.main␊
733
+ struct MainStorage {␊
734
+ uint256 x;␊
735
+ uint256 z;␊
736
+ } MainStorage $MainStorage_random;␊
737
+ }`,
738
+ },
739
+ },
740
+ }
@@ -63,6 +63,11 @@ export function makeNamespacedInput(input: SolcInput, output: SolcOutput, _solcV
63
63
  modifications.push(makeInsertBefore(contractDef, 'abstract '));
64
64
  }
65
65
 
66
+ // Remove custom layout annotation
67
+ if (contractDef.storageLayout !== undefined) {
68
+ modifications.push(makeDelete(contractDef.storageLayout, orig));
69
+ }
70
+
66
71
  // Remove any calls to parent constructors from the inheritance list
67
72
  const inherits = contractDef.baseContracts;
68
73
  for (const inherit of inherits) {
@@ -18,5 +18,6 @@ export function stabilizeStorageLayout(layout: StorageLayout) {
18
18
  return [ns, items.map(item => ({ ...item, type: stabilizeTypeIdentifier(item.type) }))];
19
19
  })
20
20
  : undefined,
21
+ baseSlot: layout.baseSlot,
21
22
  };
22
23
  }
@@ -240,7 +240,7 @@ testAccepts('Recursive_Ok', 'transparent');
240
240
  testAccepts('ERC20_Ok', 'uups');
241
241
  testRejects('ERC20_Bad', 'uups', {
242
242
  contains: [
243
- 'Missing initializer calls for one or more parent contracts: `ERC20Upgradeable, ERC20PausableUpgradeable, OwnableUpgradeable, ERC20PermitUpgradeable`',
243
+ 'Missing initializer calls for one or more parent contracts: `ERC20Upgradeable, OwnableUpgradeable, ERC20PermitUpgradeable`',
244
244
  ],
245
245
  count: 1,
246
246
  });