@openzeppelin/upgrades-core 1.27.3 → 1.29.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/cli/cli.test.js +93 -3
- package/dist/cli/cli.test.js.map +1 -1
- package/dist/cli/index.d.ts +1 -1
- package/dist/cli/index.d.ts.map +1 -1
- package/dist/cli/index.js +2 -2
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/validate/build-info-file.test.js +2 -4
- package/dist/cli/validate/build-info-file.test.js.map +1 -1
- package/dist/cli/validate/contract-report.d.ts +3 -1
- package/dist/cli/validate/contract-report.d.ts.map +1 -1
- package/dist/cli/validate/contract-report.js +7 -6
- package/dist/cli/validate/contract-report.js.map +1 -1
- package/dist/cli/validate/find-contract.d.ts +14 -0
- package/dist/cli/validate/find-contract.d.ts.map +1 -0
- package/dist/cli/validate/find-contract.js +32 -0
- package/dist/cli/validate/find-contract.js.map +1 -0
- package/dist/cli/validate/project-report.test.js +1 -2
- package/dist/cli/validate/project-report.test.js.map +1 -1
- package/dist/cli/validate/upgradeability-assessment.d.ts +1 -12
- package/dist/cli/validate/upgradeability-assessment.d.ts.map +1 -1
- package/dist/cli/validate/upgradeability-assessment.js +17 -40
- package/dist/cli/validate/upgradeability-assessment.js.map +1 -1
- package/dist/cli/validate/validate-upgrade-safety.d.ts +8 -1
- package/dist/cli/validate/validate-upgrade-safety.d.ts.map +1 -1
- package/dist/cli/validate/validate-upgrade-safety.js +20 -2
- package/dist/cli/validate/validate-upgrade-safety.js.map +1 -1
- package/dist/cli/validate/validate-upgrade-safety.test.js +4 -6
- package/dist/cli/validate/validate-upgrade-safety.test.js.map +1 -1
- package/dist/cli/validate.d.ts +2 -0
- package/dist/cli/validate.d.ts.map +1 -1
- package/dist/cli/validate.js +19 -3
- package/dist/cli/validate.js.map +1 -1
- package/dist/cli/validate.test.js.map +1 -1
- package/dist/deployment.d.ts.map +1 -1
- package/dist/deployment.js.map +1 -1
- package/dist/impl-store.test.js +2 -4
- package/dist/impl-store.test.js.map +1 -1
- package/dist/scripts/migrate-oz-cli-project.test.js +2 -4
- package/dist/scripts/migrate-oz-cli-project.test.js.map +1 -1
- package/dist/standalone.d.ts.map +1 -1
- package/dist/standalone.js.map +1 -1
- package/dist/storage/compare.d.ts.map +1 -1
- package/dist/storage/compare.js.map +1 -1
- package/dist/storage/extract.d.ts +1 -1
- package/dist/storage/extract.d.ts.map +1 -1
- package/dist/storage/extract.js.map +1 -1
- package/dist/storage/report-gap.test.js +1 -2
- package/dist/storage/report-gap.test.js.map +1 -1
- package/dist/storage/report-rename-retype.test.js +1 -2
- package/dist/storage/report-rename-retype.test.js.map +1 -1
- package/dist/storage/report-retype-from-contract.test.js +1 -2
- package/dist/storage/report-retype-from-contract.test.js.map +1 -1
- package/dist/storage/report.test.js +1 -2
- package/dist/storage/report.test.js.map +1 -1
- package/dist/storage-0.8.test.js +1 -2
- package/dist/storage-0.8.test.js.map +1 -1
- package/dist/storage-memory-0.5.test.js +1 -2
- package/dist/storage-memory-0.5.test.js.map +1 -1
- package/dist/storage.test.js +1 -2
- package/dist/storage.test.js.map +1 -1
- package/dist/utils/function.d.ts +1 -1
- package/dist/utils/function.d.ts.map +1 -1
- package/dist/utils/function.test.js +1 -2
- package/dist/utils/function.test.js.map +1 -1
- package/dist/validate/error.d.ts.map +1 -1
- package/dist/validate/error.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 +3 -1
- 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 +1 -1
- package/dist/validate/run.d.ts.map +1 -1
- package/dist/validate/run.js +1 -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 +7 -7
- package/src/cli/cli.test.ts +131 -2
- package/src/cli/cli.test.ts.md +96 -2
- package/src/cli/cli.test.ts.snap +0 -0
- package/src/cli/index.ts +1 -1
- package/src/cli/validate/build-info-file.test.ts +1 -4
- package/src/cli/validate/contract-report.ts +19 -7
- package/src/cli/validate/find-contract.ts +44 -0
- package/src/cli/validate/project-report.test.ts +1 -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 +18 -50
- package/src/cli/validate/validate-upgrade-safety.test.ts +2 -5
- 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/validate-upgrade-safety.ts +32 -2
- package/src/cli/validate/validations.test.ts.md +2 -2
- package/src/cli/validate/validations.test.ts.snap +0 -0
- package/src/cli/validate.test.ts +1 -1
- package/src/cli/validate.ts +28 -4
- package/src/deployment.ts +5 -1
- package/src/impl-store.test.ts +1 -4
- package/src/scripts/migrate-oz-cli-project.test.ts +1 -3
- package/src/standalone.ts +6 -1
- package/src/storage/compare.ts +4 -1
- package/src/storage/extract.ts +1 -2
- package/src/storage/report-gap.test.ts +1 -2
- package/src/storage/report-rename-retype.test.ts +1 -2
- package/src/storage/report-retype-from-contract.test.ts +1 -2
- package/src/storage/report.test.ts +1 -2
- package/src/storage-0.8.test.ts +1 -2
- package/src/storage-memory-0.5.test.ts +1 -2
- package/src/storage.test.ts +1 -2
- package/src/utils/function.test.ts +1 -2
- package/src/utils/function.ts +1 -1
- package/src/validate/error.ts +4 -1
- package/src/validate/overrides.ts +1 -1
- package/src/validate/query.ts +5 -1
- package/src/validate/report.ts +3 -2
- package/src/validate/run.ts +2 -3
- package/src/validate.test.ts +3 -0
- package/dist/ast-dereferencer.d.ts +0 -8
- package/dist/ast-dereferencer.d.ts.map +0 -1
- package/dist/ast-dereferencer.js +0 -29
- package/dist/ast-dereferencer.js.map +0 -1
- package/src/ast-dereferencer.ts +0 -42
|
@@ -2,28 +2,58 @@ import { ValidationOptions } from '../..';
|
|
|
2
2
|
|
|
3
3
|
import { getBuildInfoFiles } from './build-info-file';
|
|
4
4
|
import { getContractReports } from './contract-report';
|
|
5
|
+
import { findContract } from './find-contract';
|
|
5
6
|
import { ProjectReport, getProjectReport } from './project-report';
|
|
6
|
-
import { validateBuildInfoContracts } from './validations';
|
|
7
|
+
import { SourceContract, validateBuildInfoContracts } from './validations';
|
|
7
8
|
|
|
8
9
|
/**
|
|
9
10
|
* Validation options for upgrade safety checks.
|
|
10
11
|
*/
|
|
11
12
|
export type ValidateUpgradeSafetyOptions = Omit<ValidationOptions, 'kind'>;
|
|
12
13
|
|
|
14
|
+
export type SpecifiedContracts = {
|
|
15
|
+
contract: SourceContract;
|
|
16
|
+
reference?: SourceContract;
|
|
17
|
+
};
|
|
18
|
+
|
|
13
19
|
/**
|
|
14
20
|
* Validates the upgrade safety of all contracts in the build info dir's build info files.
|
|
15
21
|
* Only contracts that are detected as upgradeable will be validated.
|
|
16
22
|
*
|
|
17
23
|
* @param buildInfoDir Absolute path of build info directory, or undefined to use the default Hardhat or Foundry build-info dir.
|
|
24
|
+
* @param contract The name or fully qualified name of the contract to validate. If not specified, all upgradeable contracts in the build info directory will be validated.
|
|
25
|
+
* @param reference The name or fully qualified name of the reference contract to use for storage layout comparisons. Can only be used along with `contract`. If not specified, uses the `@custom:oz-upgrades-from` annotation in the contract that is being validated.
|
|
18
26
|
* @param opts Validation options, or undefined to use the default validation options.
|
|
19
27
|
* @returns The project report.
|
|
20
28
|
*/
|
|
21
29
|
export async function validateUpgradeSafety(
|
|
22
30
|
buildInfoDir?: string,
|
|
31
|
+
contract?: string,
|
|
32
|
+
reference?: string,
|
|
23
33
|
opts: ValidateUpgradeSafetyOptions = {},
|
|
24
34
|
): Promise<ProjectReport> {
|
|
25
35
|
const buildInfoFiles = await getBuildInfoFiles(buildInfoDir);
|
|
26
36
|
const sourceContracts = validateBuildInfoContracts(buildInfoFiles);
|
|
27
|
-
|
|
37
|
+
|
|
38
|
+
const specifiedContracts = findSpecifiedContracts(sourceContracts, contract, reference);
|
|
39
|
+
|
|
40
|
+
const contractReports = getContractReports(sourceContracts, opts, specifiedContracts);
|
|
28
41
|
return getProjectReport(contractReports);
|
|
29
42
|
}
|
|
43
|
+
|
|
44
|
+
function findSpecifiedContracts(
|
|
45
|
+
sourceContracts: SourceContract[],
|
|
46
|
+
contractName?: string,
|
|
47
|
+
referenceName?: string,
|
|
48
|
+
): SpecifiedContracts | undefined {
|
|
49
|
+
if (contractName !== undefined) {
|
|
50
|
+
return {
|
|
51
|
+
contract: findContract(contractName, undefined, sourceContracts),
|
|
52
|
+
reference: referenceName !== undefined ? findContract(referenceName, undefined, sourceContracts) : undefined,
|
|
53
|
+
};
|
|
54
|
+
} else if (referenceName !== undefined) {
|
|
55
|
+
throw new Error(`The reference option can only be specified when the contract option is also specified.`);
|
|
56
|
+
} else {
|
|
57
|
+
return undefined;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
@@ -50,8 +50,8 @@ Generated by [AVA](https://avajs.dev).
|
|
|
50
50
|
|
|
51
51
|
` ✘ contracts/test/cli/Validate.sol:UpgradesFromUUPS (upgrades from contracts/test/cli/Validate.sol:HasUpgradeTo)␊
|
|
52
52
|
␊
|
|
53
|
-
contracts/test/cli/Validate.sol:72: Implementation is missing a public \`upgradeTo(address)\` function␊
|
|
54
|
-
Inherit UUPSUpgradeable to include
|
|
53
|
+
contracts/test/cli/Validate.sol:72: Implementation is missing a public \`upgradeTo(address)\` or \`upgradeToAndCall(address,bytes)\` function␊
|
|
54
|
+
Inherit UUPSUpgradeable to include one or both of these functions in your contract␊
|
|
55
55
|
@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol␊
|
|
56
56
|
https://zpl.in/upgrades/error-008`
|
|
57
57
|
|
|
Binary file
|
package/src/cli/validate.test.ts
CHANGED
|
@@ -99,7 +99,7 @@ test('withDefaults - all', t => {
|
|
|
99
99
|
t.is(opts.unsafeSkipStorageCheck, true);
|
|
100
100
|
t.is(opts.unsafeAllowCustomTypes, true);
|
|
101
101
|
t.is(opts.unsafeAllowLinkedLibraries, true);
|
|
102
|
-
t.true(opts.unsafeAllow.every((kind: string) => errorKinds.includes(kind as typeof errorKinds[number])));
|
|
102
|
+
t.true(opts.unsafeAllow.every((kind: string) => errorKinds.includes(kind as (typeof errorKinds)[number])));
|
|
103
103
|
});
|
|
104
104
|
|
|
105
105
|
test('withDefaults - invalid unsafeAllow', t => {
|
package/src/cli/validate.ts
CHANGED
|
@@ -13,6 +13,8 @@ Arguments:
|
|
|
13
13
|
<BUILD_INFO_DIR> Optional path to the build info directory which contains JSON files with Solidity compiler input and output. Defaults to 'artifacts/build-info' for Hardhat projects or 'out/build-info' for Foundry projects. If your project uses a custom output directory, you must specify its build info directory here.
|
|
14
14
|
|
|
15
15
|
Options:
|
|
16
|
+
--contract <CONTRACT> The name or fully qualified name of the contract to validate. If not specified, all upgradeable contracts in the build info directory will be validated.
|
|
17
|
+
--reference <REFERENCE_CONTRACT> The name or fully qualified name of the reference contract to use for storage layout comparisons. Can only be used along with the --contract option. If not specified, uses the @custom:oz-upgrades-from annotation in the contract that is being validated.
|
|
16
18
|
--unsafeAllow "<VALIDATION_ERRORS>" Selectively disable one or more validation errors. Comma-separated list with one or more of the following: ${errorKinds.join(
|
|
17
19
|
', ',
|
|
18
20
|
)}
|
|
@@ -24,7 +26,12 @@ export async function main(args: string[]): Promise<void> {
|
|
|
24
26
|
|
|
25
27
|
if (!help(parsedArgs, extraArgs)) {
|
|
26
28
|
const functionArgs = getFunctionArgs(parsedArgs, extraArgs);
|
|
27
|
-
const result = await validateUpgradeSafety(
|
|
29
|
+
const result = await validateUpgradeSafety(
|
|
30
|
+
functionArgs.buildInfoDir,
|
|
31
|
+
functionArgs.contract,
|
|
32
|
+
functionArgs.reference,
|
|
33
|
+
functionArgs.opts,
|
|
34
|
+
);
|
|
28
35
|
console.log(result.explain());
|
|
29
36
|
process.exitCode = result.ok ? 0 : 1;
|
|
30
37
|
}
|
|
@@ -39,7 +46,7 @@ function parseArgs(args: string[]) {
|
|
|
39
46
|
'unsafeAllowCustomTypes',
|
|
40
47
|
'unsafeAllowLinkedLibraries',
|
|
41
48
|
],
|
|
42
|
-
string: ['unsafeAllow'],
|
|
49
|
+
string: ['unsafeAllow', 'contract', 'reference'],
|
|
43
50
|
alias: { h: 'help' },
|
|
44
51
|
});
|
|
45
52
|
const extraArgs = parsedArgs._;
|
|
@@ -59,6 +66,8 @@ function help(parsedArgs: minimist.ParsedArgs, extraArgs: string[]): boolean {
|
|
|
59
66
|
|
|
60
67
|
interface FunctionArgs {
|
|
61
68
|
buildInfoDir?: string;
|
|
69
|
+
contract?: string;
|
|
70
|
+
reference?: string;
|
|
62
71
|
opts: Required<ValidateUpgradeSafetyOptions>;
|
|
63
72
|
}
|
|
64
73
|
|
|
@@ -76,9 +85,22 @@ export function getFunctionArgs(parsedArgs: minimist.ParsedArgs, extraArgs: stri
|
|
|
76
85
|
throw new Error('The validate command takes only one argument: the build info directory.');
|
|
77
86
|
} else {
|
|
78
87
|
const buildInfoDir = extraArgs.length === 1 ? undefined : extraArgs[1];
|
|
88
|
+
const contract = getAndValidateString(parsedArgs, 'contract');
|
|
89
|
+
const reference = getAndValidateString(parsedArgs, 'reference');
|
|
90
|
+
if (reference !== undefined && contract === undefined) {
|
|
91
|
+
throw new Error('The --reference option can only be used along with the --contract option.');
|
|
92
|
+
}
|
|
79
93
|
const opts = withDefaults(parsedArgs);
|
|
80
|
-
return { buildInfoDir, opts };
|
|
94
|
+
return { buildInfoDir, contract, reference, opts };
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
function getAndValidateString(parsedArgs: minimist.ParsedArgs, option: string): string | undefined {
|
|
99
|
+
const value = parsedArgs[option];
|
|
100
|
+
if (value !== undefined && value.trim().length === 0) {
|
|
101
|
+
throw new Error(`Invalid option: --${option} cannot be empty`);
|
|
81
102
|
}
|
|
103
|
+
return value;
|
|
82
104
|
}
|
|
83
105
|
|
|
84
106
|
function validateOptions(parsedArgs: minimist.ParsedArgs) {
|
|
@@ -93,6 +115,8 @@ function validateOptions(parsedArgs: minimist.ParsedArgs) {
|
|
|
93
115
|
'unsafeAllowCustomTypes',
|
|
94
116
|
'unsafeAllowLinkedLibraries',
|
|
95
117
|
'unsafeAllow',
|
|
118
|
+
'contract',
|
|
119
|
+
'reference',
|
|
96
120
|
].includes(key),
|
|
97
121
|
);
|
|
98
122
|
if (invalidArgs.length > 0) {
|
|
@@ -101,7 +125,7 @@ function validateOptions(parsedArgs: minimist.ParsedArgs) {
|
|
|
101
125
|
}
|
|
102
126
|
|
|
103
127
|
function getUnsafeAllowKinds(unsafeAllow: string | undefined): ValidationError['kind'][] {
|
|
104
|
-
type errorKindsType = typeof errorKinds[number];
|
|
128
|
+
type errorKindsType = (typeof errorKinds)[number];
|
|
105
129
|
|
|
106
130
|
if (unsafeAllow === undefined) {
|
|
107
131
|
return [];
|
package/src/deployment.ts
CHANGED
|
@@ -257,7 +257,11 @@ export async function waitAndValidateDeployment(
|
|
|
257
257
|
}
|
|
258
258
|
|
|
259
259
|
export class TransactionMinedTimeout extends UpgradesError {
|
|
260
|
-
constructor(
|
|
260
|
+
constructor(
|
|
261
|
+
readonly deployment: Deployment & RemoteDeploymentId,
|
|
262
|
+
type?: string,
|
|
263
|
+
configurableTimeout?: boolean,
|
|
264
|
+
) {
|
|
261
265
|
super(
|
|
262
266
|
`Timed out waiting for ${type ? type + ' ' : ''}contract deployment to address ${deployment.address} with ${
|
|
263
267
|
deployment.remoteDeploymentId
|
package/src/impl-store.test.ts
CHANGED
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
import test from 'ava';
|
|
2
2
|
|
|
3
3
|
import { promises as fs } from 'fs';
|
|
4
|
-
import
|
|
5
|
-
import util from 'util';
|
|
4
|
+
import { rimraf } from 'rimraf';
|
|
6
5
|
import path from 'path';
|
|
7
6
|
import os from 'os';
|
|
8
7
|
import sinon from 'sinon';
|
|
@@ -12,8 +11,6 @@ import { getVersion } from './version';
|
|
|
12
11
|
import { stubProvider } from './stub-provider';
|
|
13
12
|
import { ImplDeployment } from './manifest';
|
|
14
13
|
|
|
15
|
-
const rimraf = util.promisify(rimrafAsync);
|
|
16
|
-
|
|
17
14
|
test.before(async () => {
|
|
18
15
|
process.chdir(await fs.mkdtemp(path.join(os.tmpdir(), 'upgrades-core-test-')));
|
|
19
16
|
});
|
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
import os from 'os';
|
|
2
2
|
import test from 'ava';
|
|
3
3
|
import path from 'path';
|
|
4
|
-
import
|
|
5
|
-
import rimrafAsync from 'rimraf';
|
|
4
|
+
import { rimraf } from 'rimraf';
|
|
6
5
|
import { promises as fs } from 'fs';
|
|
7
6
|
import { compare as compareVersions } from 'compare-versions';
|
|
8
7
|
import {
|
|
@@ -13,7 +12,6 @@ import {
|
|
|
13
12
|
migrateLegacyProject,
|
|
14
13
|
} from './migrate-oz-cli-project';
|
|
15
14
|
|
|
16
|
-
const rimraf = util.promisify(rimrafAsync);
|
|
17
15
|
const BASE_PATH = 'src/scripts';
|
|
18
16
|
const OPENZEPPELIN_FOLDER = '.openzeppelin';
|
|
19
17
|
const PROJECT_FILE = path.join(OPENZEPPELIN_FOLDER, 'project.json');
|
package/src/standalone.ts
CHANGED
|
@@ -23,7 +23,12 @@ export class UpgradeableContract {
|
|
|
23
23
|
readonly errors: ValidationError[];
|
|
24
24
|
readonly layout: StorageLayout;
|
|
25
25
|
|
|
26
|
-
constructor(
|
|
26
|
+
constructor(
|
|
27
|
+
readonly name: string,
|
|
28
|
+
solcInput: SolcInput,
|
|
29
|
+
solcOutput: SolcOutput,
|
|
30
|
+
opts: ValidationOptions = {},
|
|
31
|
+
) {
|
|
27
32
|
const decodeSrc = solcInputOutputDecoder(solcInput, solcOutput);
|
|
28
33
|
const validation = validate(solcOutput, decodeSrc);
|
|
29
34
|
this.version = getContractVersion(validation, name);
|
package/src/storage/compare.ts
CHANGED
|
@@ -103,7 +103,10 @@ export class StorageLayoutComparator {
|
|
|
103
103
|
stack = new Set<string>();
|
|
104
104
|
cache = new Map<string, TypeChange | undefined>();
|
|
105
105
|
|
|
106
|
-
constructor(
|
|
106
|
+
constructor(
|
|
107
|
+
readonly unsafeAllowCustomTypes = false,
|
|
108
|
+
readonly unsafeAllowRenames = false,
|
|
109
|
+
) {}
|
|
107
110
|
|
|
108
111
|
compareLayouts(original: StorageItem[], updated: StorageItem[]): LayoutCompatibilityReport {
|
|
109
112
|
return new LayoutCompatibilityReport(this.layoutLevenshtein(original, updated, { allowAppend: true }));
|
package/src/storage/extract.ts
CHANGED
|
@@ -6,11 +6,10 @@ import {
|
|
|
6
6
|
TypeDescriptions,
|
|
7
7
|
VariableDeclaration,
|
|
8
8
|
} from 'solidity-ast';
|
|
9
|
-
import { isNodeType, findAll } from 'solidity-ast/utils';
|
|
9
|
+
import { isNodeType, findAll, ASTDereferencer } from 'solidity-ast/utils';
|
|
10
10
|
import { StorageLayout, TypeItem } from './layout';
|
|
11
11
|
import { normalizeTypeIdentifier } from '../utils/type-id';
|
|
12
12
|
import { SrcDecoder } from '../src-decoder';
|
|
13
|
-
import { ASTDereferencer } from '../ast-dereferencer';
|
|
14
13
|
import { mapValues } from '../utils/map-values';
|
|
15
14
|
import { pick } from '../utils/pick';
|
|
16
15
|
import { execall } from '../utils/execall';
|
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
import _test, { TestFn } from 'ava';
|
|
2
2
|
import { ContractDefinition } from 'solidity-ast';
|
|
3
|
-
import { ASTDereferencer, findAll } from 'solidity-ast/utils';
|
|
3
|
+
import { ASTDereferencer, astDereferencer, findAll } from 'solidity-ast/utils';
|
|
4
4
|
import { artifacts } from 'hardhat';
|
|
5
|
-
import { astDereferencer } from '../ast-dereferencer';
|
|
6
5
|
import { extractStorageLayout } from './extract';
|
|
7
6
|
import { StorageLayoutComparator } from './compare';
|
|
8
7
|
import { StorageLayout, getDetailedLayout } from './layout';
|
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
import _test, { TestFn } from 'ava';
|
|
2
2
|
import { ContractDefinition } from 'solidity-ast';
|
|
3
|
-
import { ASTDereferencer, findAll } from 'solidity-ast/utils';
|
|
3
|
+
import { ASTDereferencer, astDereferencer, findAll } from 'solidity-ast/utils';
|
|
4
4
|
import { artifacts } from 'hardhat';
|
|
5
|
-
import { astDereferencer } from '../ast-dereferencer';
|
|
6
5
|
import { extractStorageLayout } from './extract';
|
|
7
6
|
import { StorageLayoutComparator } from './compare';
|
|
8
7
|
import { StorageLayout, getDetailedLayout } from './layout';
|
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
import _test, { TestFn } from 'ava';
|
|
2
2
|
import { ContractDefinition } from 'solidity-ast';
|
|
3
|
-
import { ASTDereferencer, findAll } from 'solidity-ast/utils';
|
|
3
|
+
import { ASTDereferencer, astDereferencer, findAll } from 'solidity-ast/utils';
|
|
4
4
|
import { artifacts } from 'hardhat';
|
|
5
|
-
import { astDereferencer } from '../ast-dereferencer';
|
|
6
5
|
import { extractStorageLayout } from './extract';
|
|
7
6
|
import { StorageLayoutComparator, stripContractSubstrings } from './compare';
|
|
8
7
|
import { StorageLayout, getDetailedLayout } from './layout';
|
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
import _test, { TestFn } from 'ava';
|
|
2
2
|
import { ContractDefinition } from 'solidity-ast';
|
|
3
|
-
import { findAll } from 'solidity-ast/utils';
|
|
3
|
+
import { findAll, astDereferencer } from 'solidity-ast/utils';
|
|
4
4
|
import { artifacts } from 'hardhat';
|
|
5
5
|
|
|
6
6
|
import { SolcOutput } from '../solc-api';
|
|
7
|
-
import { astDereferencer } from '../ast-dereferencer';
|
|
8
7
|
import { extractStorageLayout } from '../storage/extract';
|
|
9
8
|
import { StorageLayoutComparator } from './compare';
|
|
10
9
|
import { StorageLayout, getDetailedLayout } from './layout';
|
package/src/storage-0.8.test.ts
CHANGED
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
import _test, { TestFn } from 'ava';
|
|
2
|
-
import { findAll } from 'solidity-ast/utils';
|
|
2
|
+
import { findAll, astDereferencer } from 'solidity-ast/utils';
|
|
3
3
|
import { artifacts } from 'hardhat';
|
|
4
4
|
|
|
5
5
|
import { SolcOutput } from './solc-api';
|
|
6
|
-
import { astDereferencer } from './ast-dereferencer';
|
|
7
6
|
import { getStorageUpgradeErrors } from './storage';
|
|
8
7
|
import { extractStorageLayout } from './storage/extract';
|
|
9
8
|
import { BuildInfo } from 'hardhat/types';
|
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
import _test, { TestFn } from 'ava';
|
|
2
|
-
import { findAll } from 'solidity-ast/utils';
|
|
2
|
+
import { findAll, astDereferencer } from 'solidity-ast/utils';
|
|
3
3
|
import { artifacts } from 'hardhat';
|
|
4
4
|
|
|
5
5
|
import { SolcOutput } from './solc-api';
|
|
6
|
-
import { astDereferencer } from './ast-dereferencer';
|
|
7
6
|
import { getStorageUpgradeErrors } from './storage';
|
|
8
7
|
import { extractStorageLayout } from './storage/extract';
|
|
9
8
|
import { BuildInfo } from 'hardhat/types';
|
package/src/storage.test.ts
CHANGED
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
import _test, { TestFn } from 'ava';
|
|
2
2
|
import { ContractDefinition } from 'solidity-ast';
|
|
3
|
-
import { findAll } from 'solidity-ast/utils';
|
|
3
|
+
import { findAll, astDereferencer } from 'solidity-ast/utils';
|
|
4
4
|
import { artifacts } from 'hardhat';
|
|
5
5
|
|
|
6
6
|
import { SolcOutput } from './solc-api';
|
|
7
|
-
import { astDereferencer } from './ast-dereferencer';
|
|
8
7
|
import { getStorageUpgradeErrors } from './storage';
|
|
9
8
|
import { StorageLayout } from './storage/layout';
|
|
10
9
|
import { extractStorageLayout } from './storage/extract';
|
|
@@ -1,11 +1,10 @@
|
|
|
1
1
|
import test from 'ava';
|
|
2
2
|
import { artifacts } from 'hardhat';
|
|
3
3
|
import { FunctionDefinition } from 'solidity-ast';
|
|
4
|
-
import { findAll } from 'solidity-ast/utils';
|
|
4
|
+
import { findAll, astDereferencer } from 'solidity-ast/utils';
|
|
5
5
|
|
|
6
6
|
import { getFunctionSignature } from './function';
|
|
7
7
|
import { SolcOutput } from '../solc-api';
|
|
8
|
-
import { astDereferencer } from '../ast-dereferencer';
|
|
9
8
|
|
|
10
9
|
testContract('ContractFunctionSignatures');
|
|
11
10
|
testContract('LibraryFunctionSignatures');
|
package/src/utils/function.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { FunctionDefinition, TypeName, VariableDeclaration } from 'solidity-ast';
|
|
2
|
-
import { ASTDereferencer } from '
|
|
2
|
+
import { ASTDereferencer } from 'solidity-ast/utils';
|
|
3
3
|
import { assert, assertUnreachable } from './assert';
|
|
4
4
|
|
|
5
5
|
function serializeParameterType(parameter: VariableDeclaration, deref: ASTDereferencer): string {
|
package/src/validate/error.ts
CHANGED
|
@@ -3,7 +3,10 @@ import { UpgradesError } from '../error';
|
|
|
3
3
|
import { UpgradeableContractErrorReport } from './report';
|
|
4
4
|
|
|
5
5
|
export class ValidationErrors extends UpgradesError {
|
|
6
|
-
constructor(
|
|
6
|
+
constructor(
|
|
7
|
+
contractName: string,
|
|
8
|
+
readonly errors: ValidationError[],
|
|
9
|
+
) {
|
|
7
10
|
super(`Contract \`${contractName}\` is not upgrade safe`, () =>
|
|
8
11
|
new UpgradeableContractErrorReport(errors).explain(),
|
|
9
12
|
);
|
|
@@ -73,7 +73,7 @@ export const ValidationErrorUnsafeMessages: Record<ValidationError['kind'], stri
|
|
|
73
73
|
selfdestruct: [`You are using the \`unsafeAllow.selfdestruct\` flag.`],
|
|
74
74
|
'missing-public-upgradeto': [
|
|
75
75
|
`You are using the \`unsafeAllow.missing-public-upgradeto\` flag with uups proxy.`,
|
|
76
|
-
`Not having a public upgradeTo function in your implementation can break upgradeability.`,
|
|
76
|
+
`Not having a public upgradeTo or upgradeToAndCall function in your implementation can break upgradeability.`,
|
|
77
77
|
`Some implementation might check that onchain, and cause the upgrade to revert.`,
|
|
78
78
|
],
|
|
79
79
|
};
|
package/src/validate/query.ts
CHANGED
|
@@ -8,6 +8,7 @@ import { ValidationData, normalizeValidationData } from './data';
|
|
|
8
8
|
import { ProxyDeployment } from '../manifest';
|
|
9
9
|
|
|
10
10
|
const upgradeToSignature = 'upgradeTo(address)';
|
|
11
|
+
const upgradeToAndCallSignature = 'upgradeToAndCall(address,bytes)';
|
|
11
12
|
|
|
12
13
|
export function assertUpgradeSafe(data: ValidationData, version: Version, opts: ValidationOptions): void {
|
|
13
14
|
const dataV3 = normalizeValidationData(data);
|
|
@@ -147,7 +148,10 @@ export function getErrors(data: ValidationData, version: Version, opts: Validati
|
|
|
147
148
|
|
|
148
149
|
const selfAndInheritedMethods = getAllMethods(runValidation, fullContractName);
|
|
149
150
|
|
|
150
|
-
if (
|
|
151
|
+
if (
|
|
152
|
+
!selfAndInheritedMethods.includes(upgradeToSignature) &&
|
|
153
|
+
!selfAndInheritedMethods.includes(upgradeToAndCallSignature)
|
|
154
|
+
) {
|
|
151
155
|
errors.push({
|
|
152
156
|
src: c.src,
|
|
153
157
|
kind: 'missing-public-upgradeto',
|
package/src/validate/report.ts
CHANGED
|
@@ -57,9 +57,10 @@ const errorInfo: ErrorDescriptions<ValidationError> = {
|
|
|
57
57
|
hint: () => `Update your dependency and run again`,
|
|
58
58
|
},
|
|
59
59
|
'missing-public-upgradeto': {
|
|
60
|
-
msg: () =>
|
|
60
|
+
msg: () =>
|
|
61
|
+
`Implementation is missing a public \`upgradeTo(address)\` or \`upgradeToAndCall(address,bytes)\` function`,
|
|
61
62
|
hint: () =>
|
|
62
|
-
`Inherit UUPSUpgradeable to include
|
|
63
|
+
`Inherit UUPSUpgradeable to include one or both of these functions in your contract\n` +
|
|
63
64
|
` @openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol`,
|
|
64
65
|
link: 'https://zpl.in/upgrades/error-008',
|
|
65
66
|
},
|
package/src/validate/run.ts
CHANGED
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
import { Node } from 'solidity-ast/node';
|
|
2
|
-
import { isNodeType, findAll, ASTDereferencer } from 'solidity-ast/utils';
|
|
2
|
+
import { isNodeType, findAll, ASTDereferencer, astDereferencer } from 'solidity-ast/utils';
|
|
3
3
|
import type { ContractDefinition, FunctionDefinition } from 'solidity-ast';
|
|
4
4
|
|
|
5
5
|
import { SolcOutput, SolcBytecode } from '../solc-api';
|
|
6
6
|
import { SrcDecoder } from '../src-decoder';
|
|
7
|
-
import { astDereferencer } from '../ast-dereferencer';
|
|
8
7
|
import { isNullish } from '../utils/is-nullish';
|
|
9
8
|
import { getFunctionSignature } from '../utils/function';
|
|
10
9
|
import { Version, getVersion } from '../version';
|
|
@@ -48,7 +47,7 @@ export type ValidationError =
|
|
|
48
47
|
|
|
49
48
|
interface ValidationErrorBase {
|
|
50
49
|
src: string;
|
|
51
|
-
kind: typeof errorKinds[number];
|
|
50
|
+
kind: (typeof errorKinds)[number];
|
|
52
51
|
}
|
|
53
52
|
|
|
54
53
|
interface ValidationErrorWithName extends ValidationErrorBase {
|
package/src/validate.test.ts
CHANGED
|
@@ -99,7 +99,10 @@ testOverride('UsesExplicitSafeExternalLibrary', 'transparent', { unsafeAllow: ['
|
|
|
99
99
|
testValid('HasEmptyConstructor', 'uups', false);
|
|
100
100
|
testValid('HasInternalUpgradeToFunction', 'uups', false);
|
|
101
101
|
testValid('HasUpgradeToFunction', 'uups', true);
|
|
102
|
+
testValid('HasInternalUpgradeToAndCallFunction', 'uups', false);
|
|
103
|
+
testValid('HasUpgradeToAndCallFunction', 'uups', true);
|
|
102
104
|
testValid('ParentHasUpgradeToFunction', 'uups', true);
|
|
105
|
+
testValid('ParentHasUpgradeToAndCallFunction', 'uups', true);
|
|
103
106
|
testValid('ChildOfProxiable', 'uups', true);
|
|
104
107
|
|
|
105
108
|
testValid('HasNonEmptyConstructorNatspec1', 'transparent', true);
|
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
import type { NodeType, NodeTypeMap } from 'solidity-ast/node';
|
|
2
|
-
import type { SolcOutput } from './solc-api';
|
|
3
|
-
export interface ASTDereferencer {
|
|
4
|
-
<T extends NodeType>(nodeTypes: T[]): (id: number) => NodeTypeMap[T];
|
|
5
|
-
<T extends NodeType>(nodeTypes: T[], id: number): NodeTypeMap[T];
|
|
6
|
-
}
|
|
7
|
-
export declare function astDereferencer(solcOutput: SolcOutput): ASTDereferencer;
|
|
8
|
-
//# sourceMappingURL=ast-dereferencer.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"ast-dereferencer.d.ts","sourceRoot":"","sources":["../src/ast-dereferencer.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAQ,QAAQ,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAGrE,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAM7C,MAAM,WAAW,eAAe;IAC9B,CAAC,CAAC,SAAS,QAAQ,EAAE,SAAS,EAAE,CAAC,EAAE,GAAG,CAAC,EAAE,EAAE,MAAM,KAAK,WAAW,CAAC,CAAC,CAAC,CAAC;IACrE,CAAC,CAAC,SAAS,QAAQ,EAAE,SAAS,EAAE,CAAC,EAAE,EAAE,EAAE,EAAE,MAAM,GAAG,WAAW,CAAC,CAAC,CAAC,CAAC;CAClE;AAED,wBAAgB,eAAe,CAAC,UAAU,EAAE,UAAU,GAAG,eAAe,CA0BvE"}
|
package/dist/ast-dereferencer.js
DELETED
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.astDereferencer = void 0;
|
|
4
|
-
const utils_1 = require("solidity-ast/utils");
|
|
5
|
-
const curry_1 = require("./utils/curry");
|
|
6
|
-
function astDereferencer(solcOutput) {
|
|
7
|
-
const asts = Array.from(Object.values(solcOutput.sources), s => s.ast);
|
|
8
|
-
const cache = new Map();
|
|
9
|
-
function deref(nodeTypes, id) {
|
|
10
|
-
const cached = cache.get(id);
|
|
11
|
-
if (cached) {
|
|
12
|
-
if (nodeTypes.includes(cached.nodeType)) {
|
|
13
|
-
return cached;
|
|
14
|
-
}
|
|
15
|
-
}
|
|
16
|
-
for (const ast of asts) {
|
|
17
|
-
for (const node of (0, utils_1.findAll)(nodeTypes, ast)) {
|
|
18
|
-
if (node.id === id) {
|
|
19
|
-
cache.set(id, node);
|
|
20
|
-
return node;
|
|
21
|
-
}
|
|
22
|
-
}
|
|
23
|
-
}
|
|
24
|
-
throw new Error(`No node with id ${id} of type ${nodeTypes}`);
|
|
25
|
-
}
|
|
26
|
-
return (0, curry_1.curry2)(deref);
|
|
27
|
-
}
|
|
28
|
-
exports.astDereferencer = astDereferencer;
|
|
29
|
-
//# sourceMappingURL=ast-dereferencer.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"ast-dereferencer.js","sourceRoot":"","sources":["../src/ast-dereferencer.ts"],"names":[],"mappings":";;;AAAA,8CAA6C;AAG7C,yCAAuC;AAYvC,SAAgB,eAAe,CAAC,UAAsB;IACpD,MAAM,IAAI,GAAG,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,UAAU,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;IACvE,MAAM,KAAK,GAAG,IAAI,GAAG,EAAgB,CAAC;IAEtC,SAAS,KAAK,CAAqB,SAAc,EAAE,EAAU;QAC3D,MAAM,MAAM,GAAG,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QAE7B,IAAI,MAAM,EAAE;YACV,IAAK,SAAwB,CAAC,QAAQ,CAAC,MAAM,CAAC,QAAQ,CAAC,EAAE;gBACvD,OAAO,MAAwB,CAAC;aACjC;SACF;QAED,KAAK,MAAM,GAAG,IAAI,IAAI,EAAE;YACtB,KAAK,MAAM,IAAI,IAAI,IAAA,eAAO,EAAC,SAAS,EAAE,GAAG,CAAC,EAAE;gBAC1C,IAAI,IAAI,CAAC,EAAE,KAAK,EAAE,EAAE;oBAClB,KAAK,CAAC,GAAG,CAAC,EAAE,EAAE,IAAI,CAAC,CAAC;oBACpB,OAAO,IAAI,CAAC;iBACb;aACF;SACF;QAED,MAAM,IAAI,KAAK,CAAC,mBAAmB,EAAE,YAAY,SAAS,EAAE,CAAC,CAAC;IAChE,CAAC;IAED,OAAO,IAAA,cAAM,EAAC,KAAK,CAAC,CAAC;AACvB,CAAC;AA1BD,0CA0BC"}
|
package/src/ast-dereferencer.ts
DELETED
|
@@ -1,42 +0,0 @@
|
|
|
1
|
-
import { findAll } from 'solidity-ast/utils';
|
|
2
|
-
import type { Node, NodeType, NodeTypeMap } from 'solidity-ast/node';
|
|
3
|
-
|
|
4
|
-
import { curry2 } from './utils/curry';
|
|
5
|
-
import type { SolcOutput } from './solc-api';
|
|
6
|
-
|
|
7
|
-
// An ASTDereferencer is a function that looks up an AST node given its id, in all of the source files involved in a
|
|
8
|
-
// solc run. It will generally be used together with the AST property `referencedDeclaration` (found in Identifier,
|
|
9
|
-
// UserDefinedTypeName, etc.) to look up a variable definition or type definition.
|
|
10
|
-
|
|
11
|
-
export interface ASTDereferencer {
|
|
12
|
-
<T extends NodeType>(nodeTypes: T[]): (id: number) => NodeTypeMap[T];
|
|
13
|
-
<T extends NodeType>(nodeTypes: T[], id: number): NodeTypeMap[T];
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
export function astDereferencer(solcOutput: SolcOutput): ASTDereferencer {
|
|
17
|
-
const asts = Array.from(Object.values(solcOutput.sources), s => s.ast);
|
|
18
|
-
const cache = new Map<number, Node>();
|
|
19
|
-
|
|
20
|
-
function deref<T extends NodeType>(nodeTypes: T[], id: number): NodeTypeMap[T] {
|
|
21
|
-
const cached = cache.get(id);
|
|
22
|
-
|
|
23
|
-
if (cached) {
|
|
24
|
-
if ((nodeTypes as NodeType[]).includes(cached.nodeType)) {
|
|
25
|
-
return cached as NodeTypeMap[T];
|
|
26
|
-
}
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
for (const ast of asts) {
|
|
30
|
-
for (const node of findAll(nodeTypes, ast)) {
|
|
31
|
-
if (node.id === id) {
|
|
32
|
-
cache.set(id, node);
|
|
33
|
-
return node;
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
throw new Error(`No node with id ${id} of type ${nodeTypes}`);
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
return curry2(deref);
|
|
42
|
-
}
|