@openzeppelin/upgrades-core 1.42.2 → 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.
- package/artifacts/@openzeppelin/contracts-v5/proxy/ERC1967/ERC1967Proxy.sol/ERC1967Proxy.json +3 -3
- package/artifacts/@openzeppelin/contracts-v5/proxy/beacon/BeaconProxy.sol/BeaconProxy.json +3 -3
- package/artifacts/@openzeppelin/contracts-v5/proxy/beacon/UpgradeableBeacon.sol/UpgradeableBeacon.json +2 -2
- package/artifacts/@openzeppelin/contracts-v5/proxy/transparent/ProxyAdmin.sol/ProxyAdmin.json +2 -2
- package/artifacts/@openzeppelin/contracts-v5/proxy/transparent/TransparentUpgradeableProxy.sol/ITransparentUpgradeableProxy.json +2 -2
- package/artifacts/@openzeppelin/contracts-v5/proxy/transparent/TransparentUpgradeableProxy.sol/TransparentUpgradeableProxy.json +3 -3
- package/artifacts/build-info-v5.json +5159 -2886
- package/dist/provider.d.ts.map +1 -1
- package/dist/provider.js +1 -0
- package/dist/provider.js.map +1 -1
- package/dist/solidity-version.json +1 -1
- package/dist/storage/extract.d.ts.map +1 -1
- package/dist/storage/extract.js +14 -0
- package/dist/storage/extract.js.map +1 -1
- package/dist/storage/index.d.ts.map +1 -1
- package/dist/storage/index.js +23 -0
- 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.map +1 -1
- package/dist/storage/namespace.js +47 -1
- package/dist/storage/namespace.js.map +1 -1
- package/dist/storage-custom-layout.test.d.ts +2 -0
- package/dist/storage-custom-layout.test.d.ts.map +1 -0
- package/dist/storage-custom-layout.test.js +314 -0
- package/dist/storage-custom-layout.test.js.map +1 -0
- package/dist/utils/erc7201.d.ts +10 -0
- package/dist/utils/erc7201.d.ts.map +1 -0
- package/dist/utils/erc7201.js +24 -0
- package/dist/utils/erc7201.js.map +1 -0
- package/dist/utils/erc7201.test.d.ts +2 -0
- package/dist/utils/erc7201.test.d.ts.map +1 -0
- package/dist/utils/erc7201.test.js +11 -0
- package/dist/utils/erc7201.test.js.map +1 -0
- package/dist/utils/integer-literals.d.ts +15 -0
- package/dist/utils/integer-literals.d.ts.map +1 -0
- package/dist/utils/integer-literals.js +34 -0
- package/dist/utils/integer-literals.js.map +1 -0
- package/dist/utils/integer-literals.test.d.ts +2 -0
- package/dist/utils/integer-literals.test.d.ts.map +1 -0
- package/dist/utils/integer-literals.test.js +57 -0
- package/dist/utils/integer-literals.test.js.map +1 -0
- package/dist/utils/make-namespaced.d.ts.map +1 -1
- package/dist/utils/make-namespaced.js +4 -0
- package/dist/utils/make-namespaced.js.map +1 -1
- package/dist/utils/make-namespaced.test.js +4 -0
- package/dist/utils/make-namespaced.test.js.map +1 -1
- package/dist/utils/stabilize-layout.d.ts +1 -0
- package/dist/utils/stabilize-layout.d.ts.map +1 -1
- package/dist/utils/stabilize-layout.js +1 -0
- package/dist/utils/stabilize-layout.js.map +1 -1
- package/dist/validate/run/initializer.d.ts.map +1 -1
- package/dist/validate/run/initializer.js +42 -10
- package/dist/validate/run/initializer.js.map +1 -1
- package/dist/validate-initializers.test.js +23 -5
- package/dist/validate-initializers.test.js.map +1 -1
- package/package.json +7 -4
- package/src/provider.ts +1 -0
- package/src/solidity-version.json +1 -1
- package/src/storage/extract.ts +21 -0
- package/src/storage/index.ts +29 -0
- package/src/storage/layout.ts +1 -0
- package/src/storage/namespace.ts +67 -1
- package/src/storage-0.8.test.ts.md +4 -0
- package/src/storage-0.8.test.ts.snap +0 -0
- package/src/storage-custom-layout.test.ts +358 -0
- package/src/storage-custom-layout.test.ts.md +353 -0
- package/src/storage-custom-layout.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-layout.test.ts.md +1 -0
- package/src/storage-namespaced-layout.test.ts.snap +0 -0
- package/src/storage-namespaced.test.ts.md +2 -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/utils/erc7201.test.ts +10 -0
- package/src/utils/erc7201.ts +25 -0
- package/src/utils/integer-literals.test.ts +73 -0
- package/src/utils/integer-literals.ts +29 -0
- package/src/utils/make-namespaced.test.ts +7 -0
- package/src/utils/make-namespaced.test.ts.md +50 -0
- package/src/utils/make-namespaced.test.ts.snap +0 -0
- package/src/utils/make-namespaced.ts +5 -0
- package/src/utils/stabilize-layout.ts +1 -0
- package/src/validate/run/initializer.ts +65 -19
- package/src/validate-initializers.test.ts +28 -6
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
import type { ContractDefinition, FunctionDefinition } from 'solidity-ast';
|
|
2
|
+
import type { Node } from 'solidity-ast/node';
|
|
2
3
|
import { ASTDereferencer, findAll } from 'solidity-ast/utils';
|
|
3
4
|
import { SrcDecoder } from '../../src-decoder';
|
|
4
5
|
import { ValidationExceptionInitializer, skipCheck, tryDerefFunction } from '../run';
|
|
6
|
+
import { getAnnotationArgs, getDocumentation, hasAnnotationTag } from '../../utils/annotations';
|
|
7
|
+
import { logNote } from '../../utils/log';
|
|
5
8
|
|
|
6
9
|
/**
|
|
7
10
|
* Reports if this contract is non-abstract and any of the following are true:
|
|
@@ -20,12 +23,12 @@ export function* getInitializerExceptions(
|
|
|
20
23
|
}
|
|
21
24
|
|
|
22
25
|
const linearizedParentContracts = getLinearizedParentContracts(contractDef, deref);
|
|
23
|
-
const parentNameToInitializersMap = getParentNameToInitializersMap(linearizedParentContracts);
|
|
26
|
+
const parentNameToInitializersMap = getParentNameToInitializersMap(linearizedParentContracts, decodeSrc);
|
|
24
27
|
|
|
25
28
|
const remainingParents = getParentsNotInitializedByOtherParents(parentNameToInitializersMap);
|
|
26
29
|
|
|
27
30
|
if (remainingParents.length > 0) {
|
|
28
|
-
const contractInitializers = getPossibleInitializers(contractDef, false);
|
|
31
|
+
const contractInitializers = getPossibleInitializers(contractDef, false, decodeSrc);
|
|
29
32
|
|
|
30
33
|
// Report if there is no initializer but parents need initialization
|
|
31
34
|
if (
|
|
@@ -71,10 +74,10 @@ function getLinearizedParentContracts(contractDef: ContractDefinition, deref: AS
|
|
|
71
74
|
* Gets a map of parent contract names to their possible initializers.
|
|
72
75
|
* If a parent contract has no initializers, it is not included in the map.
|
|
73
76
|
*/
|
|
74
|
-
function getParentNameToInitializersMap(linearizedParentContracts: ContractDefinition[]) {
|
|
77
|
+
function getParentNameToInitializersMap(linearizedParentContracts: ContractDefinition[], decodeSrc: SrcDecoder) {
|
|
75
78
|
const map = new Map();
|
|
76
79
|
for (const parent of linearizedParentContracts) {
|
|
77
|
-
const initializers = getPossibleInitializers(parent, true);
|
|
80
|
+
const initializers = getPossibleInitializers(parent, true, decodeSrc);
|
|
78
81
|
if (initializers.length > 0) {
|
|
79
82
|
map.set(parent.name, initializers);
|
|
80
83
|
}
|
|
@@ -318,22 +321,65 @@ function getRecursiveFunctionIds(
|
|
|
318
321
|
}
|
|
319
322
|
|
|
320
323
|
/**
|
|
321
|
-
* Get all functions that
|
|
322
|
-
*
|
|
324
|
+
* Get all functions that are annotated as initializers or are inferred to be initializers.
|
|
325
|
+
* Logs a note if any reinitializer is found.
|
|
323
326
|
*/
|
|
324
|
-
function getPossibleInitializers(
|
|
327
|
+
function getPossibleInitializers(
|
|
328
|
+
contractDef: ContractDefinition,
|
|
329
|
+
isParentContract: boolean,
|
|
330
|
+
decodeSrc: SrcDecoder,
|
|
331
|
+
): FunctionDefinition[] {
|
|
325
332
|
const fns = [...findAll('FunctionDefinition', contractDef)];
|
|
326
|
-
return fns.filter(
|
|
327
|
-
fnDef
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
333
|
+
return fns.filter((fnDef: FunctionDefinition) => {
|
|
334
|
+
const validateAsInitializer = hasValidateAsInitializerAnnotation(fnDef, decodeSrc);
|
|
335
|
+
if (!validateAsInitializer && fnDef.modifiers.some(modifier => 'reinitializer' === modifier.modifierName.name)) {
|
|
336
|
+
logNote(`Reinitializers are not included in validations by default`, [
|
|
337
|
+
`${decodeSrc(fnDef)}: If you want to validate this function as an initializer, annotate it with '@custom:oz-upgrades-validate-as-initializer'`,
|
|
338
|
+
]);
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
return inferPossibleInitializer(fnDef, validateAsInitializer, isParentContract);
|
|
342
|
+
});
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
function hasValidateAsInitializerAnnotation(node: Node, decodeSrc: SrcDecoder): boolean {
|
|
346
|
+
const doc = getDocumentation(node);
|
|
347
|
+
const tag = 'oz-upgrades-validate-as-initializer';
|
|
348
|
+
const validateAsInitializer = hasAnnotationTag(doc, tag);
|
|
349
|
+
if (validateAsInitializer) {
|
|
350
|
+
const annotationArgs = getAnnotationArgs(doc, tag);
|
|
351
|
+
if (annotationArgs.length !== 0) {
|
|
352
|
+
throw new Error(`${decodeSrc(node)}: @custom:${tag} annotation must not have any arguments`);
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
return validateAsInitializer;
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
function hasInitializerNameOrModifier(fnDef: FunctionDefinition) {
|
|
359
|
+
return (
|
|
360
|
+
fnDef.modifiers.some(modifier => ['initializer', 'onlyInitializing'].includes(modifier.modifierName.name)) ||
|
|
361
|
+
['initialize', 'initializer'].includes(fnDef.name)
|
|
362
|
+
);
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
/**
|
|
366
|
+
* Infers whether a function could be an initializer. Does not include private functions.
|
|
367
|
+
* For parent contracts, only internal and public functions which contain statements are included.
|
|
368
|
+
*/
|
|
369
|
+
function inferPossibleInitializer(
|
|
370
|
+
fnDef: FunctionDefinition,
|
|
371
|
+
validateAsInitializer: boolean,
|
|
372
|
+
isParentContract: boolean,
|
|
373
|
+
): boolean {
|
|
374
|
+
return (
|
|
375
|
+
(validateAsInitializer || hasInitializerNameOrModifier(fnDef)) &&
|
|
376
|
+
// Skip virtual functions without a body, since that indicates an abstract function and is not itself an initializer
|
|
377
|
+
!(fnDef.virtual && !fnDef.body) &&
|
|
378
|
+
// Ignore private functions, since they cannot be called outside the contract
|
|
379
|
+
fnDef.visibility !== 'private' &&
|
|
380
|
+
// For parent contracts, only internal and public functions which contain statements need to be called
|
|
381
|
+
(isParentContract
|
|
382
|
+
? Boolean(fnDef.body?.statements?.length) && (fnDef.visibility === 'internal' || fnDef.visibility === 'public')
|
|
383
|
+
: true)
|
|
338
384
|
);
|
|
339
385
|
}
|
|
@@ -42,7 +42,7 @@ interface ExpectedErrors {
|
|
|
42
42
|
count: number;
|
|
43
43
|
}
|
|
44
44
|
|
|
45
|
-
function testRejects(name: string, kind: ValidationOptions['kind'], expectedErrors
|
|
45
|
+
function testRejects(name: string, kind: ValidationOptions['kind'], expectedErrors: ExpectedErrors) {
|
|
46
46
|
testOverride(name, kind, {}, expectedErrors);
|
|
47
47
|
}
|
|
48
48
|
|
|
@@ -98,10 +98,18 @@ testRejects('MissingInitializer_Bad', 'transparent', {
|
|
|
98
98
|
testAccepts('MissingInitializer_UnsafeAllow_Contract', 'transparent');
|
|
99
99
|
testOverride('MissingInitializer_Bad', 'transparent', { unsafeAllow: ['missing-initializer'] });
|
|
100
100
|
|
|
101
|
+
testAccepts('ValidateAsInitializer_Ok', 'transparent');
|
|
102
|
+
|
|
103
|
+
testRejects('Reinitializer_NotDetected', 'transparent', {
|
|
104
|
+
contains: ['Missing initializer'],
|
|
105
|
+
count: 1,
|
|
106
|
+
});
|
|
107
|
+
testAccepts('Reinitializer_ValidateAsInitializer_Ok', 'transparent');
|
|
108
|
+
|
|
101
109
|
testAccepts('InitializationOrder_Ok', 'transparent');
|
|
102
110
|
testAccepts('InitializationOrder_Ok_2', 'transparent');
|
|
103
111
|
|
|
104
|
-
testAccepts('InitializationOrder_WrongOrder_Bad', 'transparent'); // warn 'Expected
|
|
112
|
+
testAccepts('InitializationOrder_WrongOrder_Bad', 'transparent'); // warn 'Expected: A, B, C'
|
|
105
113
|
testAccepts('InitializationOrder_WrongOrder_UnsafeAllow_Contract', 'transparent');
|
|
106
114
|
testAccepts('InitializationOrder_WrongOrder_UnsafeAllow_Function', 'transparent');
|
|
107
115
|
testOverride('InitializationOrder_WrongOrder_Bad', 'transparent', { unsafeAllow: ['incorrect-initializer-order'] }); // skips the warning
|
|
@@ -122,7 +130,21 @@ testAccepts('InitializationOrder_Duplicate_UnsafeAllow_Contract', 'transparent')
|
|
|
122
130
|
testAccepts('InitializationOrder_Duplicate_UnsafeAllow_Function', 'transparent');
|
|
123
131
|
testAccepts('InitializationOrder_Duplicate_UnsafeAllow_Call', 'transparent');
|
|
124
132
|
testOverride('InitializationOrder_Duplicate_Bad', 'transparent', { unsafeAllow: ['duplicate-initializer-call'] });
|
|
125
|
-
testAccepts('InitializationOrder_UnsafeAllowDuplicate_But_WrongOrder', 'transparent'); // warn 'Expected
|
|
133
|
+
testAccepts('InitializationOrder_UnsafeAllowDuplicate_But_WrongOrder', 'transparent'); // warn 'Expected: A, B, C'
|
|
134
|
+
|
|
135
|
+
testAccepts('InitializationOrder_ValidateAsInitializer_Ok', 'transparent');
|
|
136
|
+
testAccepts('InitializationOrder_ValidateAsInitializer_WrongOrder', 'transparent'); // warn 'Expected: A, B, C, Parent_ValidateAsInitializer'
|
|
137
|
+
testRejects('InitializationOrder_ValidateAsInitializer_MissingCall', 'transparent', {
|
|
138
|
+
contains: ['Missing initializer calls for one or more parent contracts: `Parent_ValidateAsInitializer`'],
|
|
139
|
+
count: 1,
|
|
140
|
+
});
|
|
141
|
+
testRejects('InitializationOrder_ValidateAsInitializer_DuplicateCall', 'transparent', {
|
|
142
|
+
contains: ['Duplicate calls found to initializer `parentAssumeInit` for contract `Parent_ValidateAsInitializer`'],
|
|
143
|
+
count: 1,
|
|
144
|
+
});
|
|
145
|
+
|
|
146
|
+
testAccepts('Parent_ValidateAsInitializer_External_Ok', 'transparent');
|
|
147
|
+
testAccepts('Child_Of_ValidateAsInitializer_External_Ok', 'transparent');
|
|
126
148
|
|
|
127
149
|
testAccepts('WithRequire_Ok', 'transparent');
|
|
128
150
|
testRejects('WithRequire_Bad', 'transparent', {
|
|
@@ -178,11 +200,11 @@ testRejects('TransitiveChild_Bad_Parent', 'transparent', {
|
|
|
178
200
|
'Missing initializer calls for one or more parent contracts: `TransitiveGrandparent2`', // occurs twice: missing initializer for child, missing initializer for parent
|
|
179
201
|
],
|
|
180
202
|
count: 2,
|
|
181
|
-
}); // warn 'Expected
|
|
203
|
+
}); // warn 'Expected: TransitiveGrandparent2, TransitiveParent_Bad'
|
|
182
204
|
testRejects('TransitiveChild_Bad_Order', 'transparent', {
|
|
183
205
|
contains: ['Missing initializer calls for one or more parent contracts: `TransitiveGrandparent2`'],
|
|
184
206
|
count: 1,
|
|
185
|
-
}); // warn 'Expected
|
|
207
|
+
}); // warn 'Expected: TransitiveGrandparent2, TransitiveParent_Bad'
|
|
186
208
|
testRejects('TransitiveChild_Good_Order_Bad_Parent', 'transparent', {
|
|
187
209
|
contains: ['Missing initializer calls for one or more parent contracts: `TransitiveGrandparent2`'],
|
|
188
210
|
count: 1,
|
|
@@ -218,7 +240,7 @@ testAccepts('Recursive_Ok', 'transparent');
|
|
|
218
240
|
testAccepts('ERC20_Ok', 'uups');
|
|
219
241
|
testRejects('ERC20_Bad', 'uups', {
|
|
220
242
|
contains: [
|
|
221
|
-
'Missing initializer calls for one or more parent contracts: `ERC20Upgradeable,
|
|
243
|
+
'Missing initializer calls for one or more parent contracts: `ERC20Upgradeable, OwnableUpgradeable, ERC20PermitUpgradeable`',
|
|
222
244
|
],
|
|
223
245
|
count: 1,
|
|
224
246
|
});
|