@openzeppelin/upgrades-core 1.31.2 → 1.32.0-alpha.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 +76 -0
- package/artifacts/@openzeppelin/contracts-v5/proxy/beacon/BeaconProxy.sol/BeaconProxy.json +87 -0
- package/artifacts/@openzeppelin/contracts-v5/proxy/beacon/UpgradeableBeacon.sol/UpgradeableBeacon.json +151 -0
- package/artifacts/@openzeppelin/contracts-v5/proxy/transparent/ProxyAdmin.sol/ProxyAdmin.json +132 -0
- package/artifacts/@openzeppelin/contracts-v5/proxy/transparent/TransparentUpgradeableProxy.sol/ITransparentUpgradeableProxy.json +74 -0
- package/artifacts/@openzeppelin/contracts-v5/proxy/transparent/TransparentUpgradeableProxy.sol/TransparentUpgradeableProxy.json +116 -0
- package/artifacts/build-info-v5.json +13993 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -1
- package/dist/index.js.map +1 -1
- package/dist/scripts/migratable-manifest.test.json +175 -0
- package/dist/scripts/project-file.test.json +25 -0
- package/dist/solidity-version.json +1 -0
- package/dist/standalone.test.js +9 -8
- package/dist/standalone.test.js.map +1 -1
- package/dist/usage-error.d.ts +3 -0
- package/dist/usage-error.d.ts.map +1 -1
- package/dist/usage-error.js +7 -1
- package/dist/usage-error.js.map +1 -1
- package/dist/utils/make-namespaced.d.ts +3 -4
- package/dist/utils/make-namespaced.d.ts.map +1 -1
- package/dist/utils/make-namespaced.js +85 -42
- package/dist/utils/make-namespaced.js.map +1 -1
- package/dist/utils/make-namespaced.test.js +9 -8
- package/dist/utils/make-namespaced.test.js.map +1 -1
- package/package.json +20 -13
- package/src/index.ts +1 -0
- package/src/solidity-version.json +1 -0
- package/src/standalone.test.ts +41 -7
- package/src/usage-error.ts +9 -0
- package/src/utils/make-namespaced.test.ts +11 -9
- package/src/utils/make-namespaced.test.ts.md +97 -32
- package/src/utils/make-namespaced.test.ts.snap +0 -0
- package/src/utils/make-namespaced.ts +91 -44
- package/artifacts/@openzeppelin/contracts/proxy/ERC1967/ERC1967Proxy.sol/ERC1967Proxy.dbg.json +0 -4
- package/artifacts/@openzeppelin/contracts/proxy/beacon/BeaconProxy.sol/BeaconProxy.dbg.json +0 -4
- package/artifacts/@openzeppelin/contracts/proxy/beacon/UpgradeableBeacon.sol/UpgradeableBeacon.dbg.json +0 -4
|
@@ -8,7 +8,7 @@ const hardhat_1 = require("hardhat");
|
|
|
8
8
|
const task_names_1 = require("hardhat/builtin-tasks/task-names");
|
|
9
9
|
const make_namespaced_1 = require("./make-namespaced");
|
|
10
10
|
(0, ava_1.default)('make namespaced input', async (t) => {
|
|
11
|
-
const origBuildInfo = await hardhat_1.artifacts.getBuildInfo('contracts/test/
|
|
11
|
+
const origBuildInfo = await hardhat_1.artifacts.getBuildInfo('contracts/test/NamespacedToModifyImported.sol:Example');
|
|
12
12
|
await testMakeNamespaced(origBuildInfo, t, '0.8.20');
|
|
13
13
|
});
|
|
14
14
|
(0, ava_1.default)('make namespaced input - solc 0.7', async (t) => {
|
|
@@ -23,20 +23,21 @@ async function testMakeNamespaced(origBuildInfo, t, solcVersion) {
|
|
|
23
23
|
// Inefficient, but we want to test that we don't actually modify the original input object
|
|
24
24
|
const origInput = JSON.parse(JSON.stringify(origBuildInfo.input));
|
|
25
25
|
const modifiedInput = (0, make_namespaced_1.makeNamespacedInput)(origBuildInfo.input, origBuildInfo.output);
|
|
26
|
-
normalizeStateVariableNames(modifiedInput);
|
|
27
|
-
t.snapshot(modifiedInput);
|
|
28
|
-
t.deepEqual(origBuildInfo.input, origInput);
|
|
29
|
-
t.notDeepEqual(modifiedInput, origInput);
|
|
30
26
|
// Run hardhat compile on the modified input and make sure it has no errors
|
|
31
27
|
const modifiedOutput = await hardhatCompile(modifiedInput, solcVersion);
|
|
32
28
|
t.is(modifiedOutput.errors, undefined);
|
|
29
|
+
normalizeIdentifiers(modifiedInput);
|
|
30
|
+
t.snapshot(modifiedInput);
|
|
31
|
+
t.deepEqual(origBuildInfo.input, origInput);
|
|
32
|
+
t.notDeepEqual(modifiedInput, origInput);
|
|
33
33
|
}
|
|
34
|
-
function
|
|
34
|
+
function normalizeIdentifiers(input) {
|
|
35
35
|
for (const source of Object.values(input.sources)) {
|
|
36
36
|
if (source.content !== undefined) {
|
|
37
37
|
source.content = source.content
|
|
38
|
-
.replace(/\$MainStorage_\d{1,6}
|
|
39
|
-
.replace(/\$SecondaryStorage_\d{1,6}/g, '$SecondaryStorage_random')
|
|
38
|
+
.replace(/\$MainStorage_\d{1,6}/g, '$MainStorage_random')
|
|
39
|
+
.replace(/\$SecondaryStorage_\d{1,6}/g, '$SecondaryStorage_random')
|
|
40
|
+
.replace(/\$astId_\d+_\d{1,6}/g, '$astId_id_random');
|
|
40
41
|
}
|
|
41
42
|
}
|
|
42
43
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"make-namespaced.test.js","sourceRoot":"","sources":["../../src/utils/make-namespaced.test.ts"],"names":[],"mappings":";;;;;AAAA,8CAA6C;AAC7C,qCAAyC;AACzC,iEAI0C;AAE1C,uDAAwD;AAKxD,IAAA,aAAI,EAAC,uBAAuB,EAAE,KAAK,EAAC,CAAC,EAAC,EAAE;IACtC,MAAM,aAAa,GAAG,MAAM,mBAAS,CAAC,YAAY,CAAC
|
|
1
|
+
{"version":3,"file":"make-namespaced.test.js","sourceRoot":"","sources":["../../src/utils/make-namespaced.test.ts"],"names":[],"mappings":";;;;;AAAA,8CAA6C;AAC7C,qCAAyC;AACzC,iEAI0C;AAE1C,uDAAwD;AAKxD,IAAA,aAAI,EAAC,uBAAuB,EAAE,KAAK,EAAC,CAAC,EAAC,EAAE;IACtC,MAAM,aAAa,GAAG,MAAM,mBAAS,CAAC,YAAY,CAAC,uDAAuD,CAAC,CAAC;IAC5G,MAAM,kBAAkB,CAAC,aAAa,EAAE,CAAC,EAAE,QAAQ,CAAC,CAAC;AACvD,CAAC,CAAC,CAAC;AAEH,IAAA,aAAI,EAAC,kCAAkC,EAAE,KAAK,EAAC,CAAC,EAAC,EAAE;IACjD,6JAA6J;IAC7J,MAAM,aAAa,GAAG,MAAM,mBAAS,CAAC,YAAY,CAAC,qDAAqD,CAAC,CAAC;IAC1G,MAAM,kBAAkB,CAAC,aAAa,EAAE,CAAC,EAAE,OAAO,CAAC,CAAC;AACtD,CAAC,CAAC,CAAC;AAEH,KAAK,UAAU,kBAAkB,CAC/B,aAAoC,EACpC,CAA4B,EAC5B,WAAmB;IAEnB,IAAI,aAAa,KAAK,SAAS,EAAE;QAC/B,MAAM,IAAI,KAAK,CAAC,sBAAsB,CAAC,CAAC;KACzC;IAED,2FAA2F;IAC3F,MAAM,SAAS,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC,CAAC;IAElE,MAAM,aAAa,GAAG,IAAA,qCAAmB,EAAC,aAAa,CAAC,KAAK,EAAE,aAAa,CAAC,MAAM,CAAC,CAAC;IAErF,2EAA2E;IAC3E,MAAM,cAAc,GAAG,MAAM,cAAc,CAAC,aAAa,EAAE,WAAW,CAAC,CAAC;IACxE,CAAC,CAAC,EAAE,CAAC,cAAc,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;IAEvC,oBAAoB,CAAC,aAAa,CAAC,CAAC;IACpC,CAAC,CAAC,QAAQ,CAAC,aAAa,CAAC,CAAC;IAE1B,CAAC,CAAC,SAAS,CAAC,aAAa,CAAC,KAAK,EAAE,SAAS,CAAC,CAAC;IAC5C,CAAC,CAAC,YAAY,CAAC,aAAa,EAAE,SAAS,CAAC,CAAC;AAC3C,CAAC;AAED,SAAS,oBAAoB,CAAC,KAAgB;IAC5C,KAAK,MAAM,MAAM,IAAI,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,EAAE;QACjD,IAAI,MAAM,CAAC,OAAO,KAAK,SAAS,EAAE;YAChC,MAAM,CAAC,OAAO,GAAG,MAAM,CAAC,OAAO;iBAC5B,OAAO,CAAC,wBAAwB,EAAE,qBAAqB,CAAC;iBACxD,OAAO,CAAC,6BAA6B,EAAE,0BAA0B,CAAC;iBAClE,OAAO,CAAC,sBAAsB,EAAE,kBAAkB,CAAC,CAAC;SACxD;KACF;AACH,CAAC;AAED,KAAK,UAAU,cAAc,CAAC,KAAgB,EAAE,WAAmB;IACjE,MAAM,SAAS,GAAc,MAAM,IAAA,aAAG,EAAC,iDAAoC,EAAE;QAC3E,KAAK,EAAE,IAAI;QACX,WAAW;KACZ,CAAC,CAAC;IAEH,IAAI,SAAS,CAAC,QAAQ,EAAE;QACtB,OAAO,MAAM,IAAA,aAAG,EAAC,6CAAgC,EAAE;YACjD,KAAK;YACL,UAAU,EAAE,SAAS,CAAC,YAAY;SACnC,CAAC,CAAC;KACJ;SAAM;QACL,OAAO,MAAM,IAAA,aAAG,EAAC,2CAA8B,EAAE;YAC/C,KAAK;YACL,QAAQ,EAAE,SAAS,CAAC,YAAY;SACjC,CAAC,CAAC;KACJ;AACH,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@openzeppelin/upgrades-core",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.32.0-alpha.0",
|
|
4
4
|
"description": "",
|
|
5
5
|
"repository": "https://github.com/OpenZeppelin/openzeppelin-upgrades/tree/master/packages/core",
|
|
6
6
|
"license": "MIT",
|
|
@@ -13,22 +13,29 @@
|
|
|
13
13
|
"/artifacts/contracts/proxy/AdminUpgradeabilityProxy.sol/AdminUpgradeabilityProxy.json",
|
|
14
14
|
"/artifacts/contracts/proxy/ProxyAdmin.sol/ProxyAdmin.json",
|
|
15
15
|
"/contracts/Initializable.sol",
|
|
16
|
-
"/artifacts/@openzeppelin/contracts/proxy/beacon/BeaconProxy.sol",
|
|
17
|
-
"/artifacts/@openzeppelin/contracts/proxy/beacon/UpgradeableBeacon.sol",
|
|
18
|
-
"/artifacts/@openzeppelin/contracts/proxy/ERC1967/ERC1967Proxy.sol",
|
|
16
|
+
"/artifacts/@openzeppelin/contracts/proxy/beacon/BeaconProxy.sol/BeaconProxy.json",
|
|
17
|
+
"/artifacts/@openzeppelin/contracts/proxy/beacon/UpgradeableBeacon.sol/UpgradeableBeacon.json",
|
|
18
|
+
"/artifacts/@openzeppelin/contracts/proxy/ERC1967/ERC1967Proxy.sol/ERC1967Proxy.json",
|
|
19
19
|
"/artifacts/@openzeppelin/contracts/proxy/transparent/ProxyAdmin.sol/ProxyAdmin.json",
|
|
20
20
|
"/artifacts/@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol/TransparentUpgradeableProxy.json",
|
|
21
21
|
"/artifacts/@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol/ITransparentUpgradeableProxy.json",
|
|
22
|
-
"/artifacts/build-info.json"
|
|
22
|
+
"/artifacts/build-info.json",
|
|
23
|
+
"/artifacts/@openzeppelin/contracts-v5/proxy/beacon/BeaconProxy.sol/BeaconProxy.json",
|
|
24
|
+
"/artifacts/@openzeppelin/contracts-v5/proxy/beacon/UpgradeableBeacon.sol/UpgradeableBeacon.json",
|
|
25
|
+
"/artifacts/@openzeppelin/contracts-v5/proxy/ERC1967/ERC1967Proxy.sol/ERC1967Proxy.json",
|
|
26
|
+
"/artifacts/@openzeppelin/contracts-v5/proxy/transparent/ProxyAdmin.sol/ProxyAdmin.json",
|
|
27
|
+
"/artifacts/@openzeppelin/contracts-v5/proxy/transparent/TransparentUpgradeableProxy.sol/TransparentUpgradeableProxy.json",
|
|
28
|
+
"/artifacts/@openzeppelin/contracts-v5/proxy/transparent/TransparentUpgradeableProxy.sol/ITransparentUpgradeableProxy.json",
|
|
29
|
+
"/artifacts/build-info-v5.json"
|
|
23
30
|
],
|
|
24
31
|
"scripts": {
|
|
25
32
|
"clean": "hardhat clean && rimraf dist *.tsbuildinfo",
|
|
26
33
|
"compile": "tsc -b && yarn compile:contracts",
|
|
27
|
-
"compile:contracts": "hardhat compile
|
|
28
|
-
"
|
|
29
|
-
"
|
|
30
|
-
"test": "tsc -b && hardhat compile --force &&
|
|
31
|
-
"test:watch": "hardhat compile --force && fgbg 'ava --watch' 'tsc -b --watch' --",
|
|
34
|
+
"compile:contracts": "hardhat compile",
|
|
35
|
+
"copyfiles": "node scripts/copy-build-info-v5.js && bash scripts/copy-legacy-artifacts.sh",
|
|
36
|
+
"prepare": "yarn clean && yarn compile && yarn copyfiles",
|
|
37
|
+
"test": "tsc -b && hardhat compile --force && yarn copyfiles && ava",
|
|
38
|
+
"test:watch": "hardhat compile --force && yarn copyfiles && fgbg 'ava --watch' 'tsc -b --watch' --",
|
|
32
39
|
"version": "node ../../scripts/bump-changelog.js",
|
|
33
40
|
"cli": "node ./dist/cli/cli.js"
|
|
34
41
|
},
|
|
@@ -38,8 +45,8 @@
|
|
|
38
45
|
"devDependencies": {
|
|
39
46
|
"@ava/typescript": "^4.0.0",
|
|
40
47
|
"@nomicfoundation/hardhat-ethers": "^3.0.5",
|
|
41
|
-
"@openzeppelin/contracts": "
|
|
42
|
-
"@openzeppelin/
|
|
48
|
+
"@openzeppelin/contracts": "5.0.0",
|
|
49
|
+
"@openzeppelin/upgrades-core-legacy": "npm:@openzeppelin/upgrades-core@1.31.3",
|
|
43
50
|
"@types/cbor": "^5.0.0",
|
|
44
51
|
"@types/debug": "^4.1.5",
|
|
45
52
|
"@types/mocha": "^7.0.2",
|
|
@@ -64,5 +71,5 @@
|
|
|
64
71
|
"proper-lockfile": "^4.1.1",
|
|
65
72
|
"solidity-ast": "^0.4.51"
|
|
66
73
|
},
|
|
67
|
-
"gitHead": "
|
|
74
|
+
"gitHead": "7fd74e339fe760d23aea5cc0bbf6bac525323ab4"
|
|
68
75
|
}
|
package/src/index.ts
CHANGED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"0.8.20"
|
package/src/standalone.test.ts
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import _test, { TestFn } from 'ava';
|
|
2
2
|
import { artifacts } from 'hardhat';
|
|
3
3
|
|
|
4
|
+
import SOLIDITY_VERSION from './solidity-version.json';
|
|
5
|
+
|
|
4
6
|
import { SolcInput, SolcOutput } from './solc-api';
|
|
5
7
|
import { UpgradeableContract } from './standalone';
|
|
6
8
|
|
|
@@ -21,7 +23,7 @@ test.before(async t => {
|
|
|
21
23
|
});
|
|
22
24
|
|
|
23
25
|
test('reports unsafe operation', t => {
|
|
24
|
-
const impl = new UpgradeableContract('StandaloneV1', t.context.solcInput, t.context.solcOutput);
|
|
26
|
+
const impl = new UpgradeableContract('StandaloneV1', t.context.solcInput, t.context.solcOutput, {}, SOLIDITY_VERSION);
|
|
25
27
|
const report = impl.getErrorReport();
|
|
26
28
|
t.false(report.ok);
|
|
27
29
|
t.true(report.errors[0].kind === 'delegatecall');
|
|
@@ -32,6 +34,8 @@ test('reports unsafe operation - fully qualified name', t => {
|
|
|
32
34
|
'contracts/test/Standalone.sol:StandaloneV1',
|
|
33
35
|
t.context.solcInput,
|
|
34
36
|
t.context.solcOutput,
|
|
37
|
+
{},
|
|
38
|
+
SOLIDITY_VERSION,
|
|
35
39
|
);
|
|
36
40
|
const report = impl.getErrorReport();
|
|
37
41
|
t.false(report.ok);
|
|
@@ -39,25 +43,55 @@ test('reports unsafe operation - fully qualified name', t => {
|
|
|
39
43
|
});
|
|
40
44
|
|
|
41
45
|
test('reports storage upgrade errors', t => {
|
|
42
|
-
const v1 = new UpgradeableContract('StandaloneV1', t.context.solcInput, t.context.solcOutput);
|
|
46
|
+
const v1 = new UpgradeableContract('StandaloneV1', t.context.solcInput, t.context.solcOutput, {}, SOLIDITY_VERSION);
|
|
43
47
|
|
|
44
|
-
const v2Good = new UpgradeableContract(
|
|
48
|
+
const v2Good = new UpgradeableContract(
|
|
49
|
+
'StandaloneV2Good',
|
|
50
|
+
t.context.solcInput,
|
|
51
|
+
t.context.solcOutput,
|
|
52
|
+
{},
|
|
53
|
+
SOLIDITY_VERSION,
|
|
54
|
+
);
|
|
45
55
|
const goodReport = v1.getStorageUpgradeReport(v2Good);
|
|
46
56
|
t.true(goodReport.ok);
|
|
47
57
|
|
|
48
|
-
const v2Bad = new UpgradeableContract(
|
|
58
|
+
const v2Bad = new UpgradeableContract(
|
|
59
|
+
'StandaloneV2Bad',
|
|
60
|
+
t.context.solcInput,
|
|
61
|
+
t.context.solcOutput,
|
|
62
|
+
{},
|
|
63
|
+
SOLIDITY_VERSION,
|
|
64
|
+
);
|
|
49
65
|
const badReport = v1.getStorageUpgradeReport(v2Bad);
|
|
50
66
|
t.false(badReport.ok);
|
|
51
67
|
});
|
|
52
68
|
|
|
53
69
|
test('dont report renamed version update', t => {
|
|
54
|
-
const v1 = new UpgradeableContract(
|
|
70
|
+
const v1 = new UpgradeableContract(
|
|
71
|
+
'StandaloneRenameV1',
|
|
72
|
+
t.context.solcInput,
|
|
73
|
+
t.context.solcOutput,
|
|
74
|
+
{},
|
|
75
|
+
SOLIDITY_VERSION,
|
|
76
|
+
);
|
|
55
77
|
|
|
56
|
-
const v2 = new UpgradeableContract(
|
|
78
|
+
const v2 = new UpgradeableContract(
|
|
79
|
+
'StandaloneRenameV2',
|
|
80
|
+
t.context.solcInput,
|
|
81
|
+
t.context.solcOutput,
|
|
82
|
+
{},
|
|
83
|
+
SOLIDITY_VERSION,
|
|
84
|
+
);
|
|
57
85
|
const goodReport = v1.getStorageUpgradeReport(v2);
|
|
58
86
|
t.true(goodReport.ok);
|
|
59
87
|
|
|
60
|
-
const v3 = new UpgradeableContract(
|
|
88
|
+
const v3 = new UpgradeableContract(
|
|
89
|
+
'StandaloneRenameV3',
|
|
90
|
+
t.context.solcInput,
|
|
91
|
+
t.context.solcOutput,
|
|
92
|
+
{},
|
|
93
|
+
SOLIDITY_VERSION,
|
|
94
|
+
);
|
|
61
95
|
const goodReport2 = v2.getStorageUpgradeReport(v3);
|
|
62
96
|
t.true(goodReport2.ok);
|
|
63
97
|
});
|
package/src/usage-error.ts
CHANGED
|
@@ -95,6 +95,15 @@ export class PrepareUpgradeRequiresKindError extends UpgradesError {
|
|
|
95
95
|
}
|
|
96
96
|
}
|
|
97
97
|
|
|
98
|
+
export class InitialOwnerUnsupportedKindError extends UpgradesError {
|
|
99
|
+
constructor(kind: string) {
|
|
100
|
+
super(
|
|
101
|
+
`The \`initialOwner\` option is not supported for this kind of proxy ('${kind}')`,
|
|
102
|
+
() => `Set the initial owner as part of your contract's initializer arguments instead.`,
|
|
103
|
+
);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
98
107
|
export async function assertNotProxy(provider: EthereumProvider, address: string) {
|
|
99
108
|
if (await isTransparentOrUUPSProxy(provider, address)) {
|
|
100
109
|
throw new UpgradesError(
|
|
@@ -12,7 +12,7 @@ import { SolcInput, SolcOutput } from '../solc-api';
|
|
|
12
12
|
import { BuildInfo } from 'hardhat/types';
|
|
13
13
|
|
|
14
14
|
test('make namespaced input', async t => {
|
|
15
|
-
const origBuildInfo = await artifacts.getBuildInfo('contracts/test/
|
|
15
|
+
const origBuildInfo = await artifacts.getBuildInfo('contracts/test/NamespacedToModifyImported.sol:Example');
|
|
16
16
|
await testMakeNamespaced(origBuildInfo, t, '0.8.20');
|
|
17
17
|
});
|
|
18
18
|
|
|
@@ -35,23 +35,25 @@ async function testMakeNamespaced(
|
|
|
35
35
|
const origInput = JSON.parse(JSON.stringify(origBuildInfo.input));
|
|
36
36
|
|
|
37
37
|
const modifiedInput = makeNamespacedInput(origBuildInfo.input, origBuildInfo.output);
|
|
38
|
-
normalizeStateVariableNames(modifiedInput);
|
|
39
|
-
t.snapshot(modifiedInput);
|
|
40
|
-
|
|
41
|
-
t.deepEqual(origBuildInfo.input, origInput);
|
|
42
|
-
t.notDeepEqual(modifiedInput, origInput);
|
|
43
38
|
|
|
44
39
|
// Run hardhat compile on the modified input and make sure it has no errors
|
|
45
40
|
const modifiedOutput = await hardhatCompile(modifiedInput, solcVersion);
|
|
46
41
|
t.is(modifiedOutput.errors, undefined);
|
|
42
|
+
|
|
43
|
+
normalizeIdentifiers(modifiedInput);
|
|
44
|
+
t.snapshot(modifiedInput);
|
|
45
|
+
|
|
46
|
+
t.deepEqual(origBuildInfo.input, origInput);
|
|
47
|
+
t.notDeepEqual(modifiedInput, origInput);
|
|
47
48
|
}
|
|
48
49
|
|
|
49
|
-
function
|
|
50
|
+
function normalizeIdentifiers(input: SolcInput): void {
|
|
50
51
|
for (const source of Object.values(input.sources)) {
|
|
51
52
|
if (source.content !== undefined) {
|
|
52
53
|
source.content = source.content
|
|
53
|
-
.replace(/\$MainStorage_\d{1,6}
|
|
54
|
-
.replace(/\$SecondaryStorage_\d{1,6}/g, '$SecondaryStorage_random')
|
|
54
|
+
.replace(/\$MainStorage_\d{1,6}/g, '$MainStorage_random')
|
|
55
|
+
.replace(/\$SecondaryStorage_\d{1,6}/g, '$SecondaryStorage_random')
|
|
56
|
+
.replace(/\$astId_\d+_\d{1,6}/g, '$astId_id_random');
|
|
55
57
|
}
|
|
56
58
|
}
|
|
57
59
|
}
|
|
@@ -45,27 +45,27 @@ Generated by [AVA](https://avajs.dev).
|
|
|
45
45
|
uint256 b;␊
|
|
46
46
|
} SecondaryStorage $SecondaryStorage_random;␊
|
|
47
47
|
␊
|
|
48
|
-
␊
|
|
49
|
-
␊
|
|
48
|
+
/// @notice some natspec␊
|
|
49
|
+
enum $astId_id_random { dummy }␊
|
|
50
50
|
␊
|
|
51
|
-
␊
|
|
52
|
-
␊
|
|
51
|
+
/// @param a docs␊
|
|
52
|
+
enum $astId_id_random { dummy }␊
|
|
53
53
|
␊
|
|
54
|
-
␊
|
|
55
|
-
␊
|
|
54
|
+
/// @param a docs␊
|
|
55
|
+
enum $astId_id_random { dummy }␊
|
|
56
56
|
struct MyStruct { uint b; }␊
|
|
57
57
|
␊
|
|
58
58
|
// keccak256(abi.encode(uint256(keccak256("example.main")) - 1)) & ~bytes32(uint256(0xff));␊
|
|
59
|
-
␊
|
|
59
|
+
enum $astId_id_random { dummy }␊
|
|
60
60
|
␊
|
|
61
|
-
␊
|
|
61
|
+
enum $astId_id_random { dummy }␊
|
|
62
62
|
␊
|
|
63
|
-
␊
|
|
63
|
+
enum $astId_id_random { dummy }␊
|
|
64
64
|
␊
|
|
65
65
|
/// @notice standlone natspec␊
|
|
66
66
|
␊
|
|
67
|
-
␊
|
|
68
|
-
␊
|
|
67
|
+
/// @notice natspec for var␊
|
|
68
|
+
enum $astId_id_random { dummy }␊
|
|
69
69
|
␊
|
|
70
70
|
// standalone doc␊
|
|
71
71
|
␊
|
|
@@ -73,49 +73,114 @@ Generated by [AVA](https://avajs.dev).
|
|
|
73
73
|
* standlone doc block␊
|
|
74
74
|
*/␊
|
|
75
75
|
␊
|
|
76
|
-
|
|
77
|
-
|
|
76
|
+
/**␊
|
|
77
|
+
* doc block without natspec␊
|
|
78
|
+
*/␊
|
|
79
|
+
enum $astId_id_random { dummy }␊
|
|
80
|
+
␊
|
|
81
|
+
/**␊
|
|
82
|
+
* doc block with natspec␊
|
|
83
|
+
*␊
|
|
84
|
+
* @notice some natspec␊
|
|
85
|
+
*/␊
|
|
86
|
+
enum $astId_id_random { dummy }␊
|
|
78
87
|
␊
|
|
79
|
-
|
|
80
|
-
|
|
88
|
+
/**␊
|
|
89
|
+
* @dev a custom error inside a contract␊
|
|
90
|
+
*/␊
|
|
91
|
+
enum $astId_id_random { dummy }␊
|
|
81
92
|
}␊
|
|
82
93
|
␊
|
|
83
94
|
contract HasFunction {␊
|
|
84
|
-
␊
|
|
85
|
-
␊
|
|
95
|
+
enum $astId_id_random { dummy }␊
|
|
96
|
+
enum $astId_id_random { dummy }␊
|
|
86
97
|
}␊
|
|
87
98
|
␊
|
|
88
99
|
contract UsingFunction is HasFunction {␊
|
|
89
|
-
␊
|
|
100
|
+
enum $astId_id_random { dummy }␊
|
|
90
101
|
}␊
|
|
91
102
|
␊
|
|
92
|
-
|
|
103
|
+
enum FreeFunctionUsingSelector { dummy }␊
|
|
93
104
|
␊
|
|
94
|
-
|
|
105
|
+
enum CONSTANT_USING_SELECTOR { dummy }␊
|
|
95
106
|
␊
|
|
96
107
|
library Lib {␊
|
|
97
|
-
␊
|
|
108
|
+
enum $astId_id_random { dummy }␊
|
|
98
109
|
␊
|
|
99
|
-
␊
|
|
110
|
+
enum $astId_id_random { dummy }␊
|
|
100
111
|
}␊
|
|
101
112
|
␊
|
|
102
113
|
contract Consumer {␊
|
|
103
|
-
␊
|
|
114
|
+
enum $astId_id_random { dummy }␊
|
|
115
|
+
␊
|
|
116
|
+
enum $astId_id_random { dummy }␊
|
|
104
117
|
␊
|
|
105
|
-
␊
|
|
118
|
+
enum $astId_id_random { dummy }␊
|
|
106
119
|
␊
|
|
107
|
-
␊
|
|
120
|
+
enum $astId_id_random { dummy }␊
|
|
108
121
|
}␊
|
|
109
122
|
␊
|
|
110
|
-
|
|
123
|
+
enum plusTwo { dummy }␊
|
|
124
|
+
␊
|
|
125
|
+
/**␊
|
|
126
|
+
* @notice originally orphaned natspec␊
|
|
127
|
+
*/␊
|
|
128
|
+
␊
|
|
129
|
+
/**␊
|
|
130
|
+
* @dev plusThree␊
|
|
131
|
+
* @param x x␊
|
|
132
|
+
*/␊
|
|
133
|
+
enum plusThree { dummy }␊
|
|
134
|
+
␊
|
|
135
|
+
/// @notice originally orphaned natspec 2␊
|
|
111
136
|
␊
|
|
137
|
+
/**␊
|
|
138
|
+
* @dev plusThree overloaded␊
|
|
139
|
+
* @param x x␊
|
|
140
|
+
* @param y y␊
|
|
141
|
+
*/␊
|
|
142
|
+
enum $astId_id_random { dummy }␊
|
|
112
143
|
␊
|
|
144
|
+
enum originallyNoDocumentation { dummy }␊
|
|
145
|
+
␊
|
|
146
|
+
/**␊
|
|
147
|
+
* @param foo foo␊
|
|
148
|
+
*/␊
|
|
149
|
+
enum $astId_id_random { dummy }␊
|
|
113
150
|
␊
|
|
114
151
|
contract UsingForDirectives {␊
|
|
115
|
-
␊
|
|
152
|
+
enum $astId_id_random { dummy }␊
|
|
153
|
+
␊
|
|
154
|
+
enum $astId_id_random { dummy }␊
|
|
155
|
+
}␊
|
|
156
|
+
␊
|
|
157
|
+
/**␊
|
|
158
|
+
* @title a␊
|
|
159
|
+
* @author a␊
|
|
160
|
+
* @inheritdoc Example␊
|
|
161
|
+
* @dev a␊
|
|
162
|
+
* @custom:a a␊
|
|
163
|
+
* @notice a␊
|
|
164
|
+
* @param a a␊
|
|
165
|
+
* @return a a␊
|
|
166
|
+
*/␊
|
|
167
|
+
enum FreeEnum { MyEnum }␊
|
|
168
|
+
␊
|
|
169
|
+
/**␊
|
|
170
|
+
* @dev a custom error outside a contract␊
|
|
171
|
+
* @param example example parameter␊
|
|
172
|
+
*/␊
|
|
173
|
+
enum CustomErrorOutsideContract { dummy }␊
|
|
174
|
+
`,
|
|
175
|
+
},
|
|
176
|
+
'contracts/test/NamespacedToModifyImported.sol': {
|
|
177
|
+
content: `// SPDX-License-Identifier: MIT␊
|
|
178
|
+
pragma solidity ^0.8.20;␊
|
|
116
179
|
␊
|
|
117
|
-
|
|
118
|
-
|
|
180
|
+
import {CONSTANT_USING_SELECTOR, plusTwo, plusThree, CustomErrorOutsideContract} from "./NamespacedToModify.sol";␊
|
|
181
|
+
␊
|
|
182
|
+
contract Example {}␊
|
|
183
|
+
`,
|
|
119
184
|
},
|
|
120
185
|
},
|
|
121
186
|
}
|
|
@@ -148,12 +213,12 @@ Generated by [AVA](https://avajs.dev).
|
|
|
148
213
|
pragma solidity 0.7.6;␊
|
|
149
214
|
␊
|
|
150
215
|
contract HasFunction {␊
|
|
151
|
-
␊
|
|
152
|
-
␊
|
|
216
|
+
enum $astId_id_random { dummy }␊
|
|
217
|
+
enum $astId_id_random { dummy }␊
|
|
153
218
|
}␊
|
|
154
219
|
␊
|
|
155
220
|
contract UsingFunction is HasFunction {␊
|
|
156
|
-
␊
|
|
221
|
+
enum $astId_id_random { dummy }␊
|
|
157
222
|
}␊
|
|
158
223
|
`,
|
|
159
224
|
},
|
|
Binary file
|
|
@@ -17,10 +17,9 @@ const OUTPUT_SELECTION = {
|
|
|
17
17
|
*
|
|
18
18
|
* This makes the following modifications to the input:
|
|
19
19
|
* - Adds a state variable for each namespaced struct definition
|
|
20
|
-
* -
|
|
21
|
-
* -
|
|
22
|
-
* -
|
|
23
|
-
* - Converts all free functions and constants (at file level) to dummy variables (do not delete them since they might be imported by other files)
|
|
20
|
+
* - For each contract, for all node types that are not needed for storage layout or may reference deleted functions and constructors, converts them to dummy enums with random id
|
|
21
|
+
* - Converts all using for directives (at file level and in contracts) to dummy enums with random id (do not delete them to avoid orphaning possible NatSpec documentation)
|
|
22
|
+
* - Converts all custom errors, free functions and constants (at file level) to dummy enums with the same name (do not delete them since they might be imported by other files)
|
|
24
23
|
*
|
|
25
24
|
* Also sets the outputSelection to only include storageLayout and ast, since the other outputs are not needed.
|
|
26
25
|
*
|
|
@@ -41,55 +40,95 @@ export function makeNamespacedInput(input: SolcInput, output: SolcOutput): SolcI
|
|
|
41
40
|
|
|
42
41
|
const orig = Buffer.from(source.content, 'utf8');
|
|
43
42
|
|
|
43
|
+
const replacedIdentifiers = new Set<string>();
|
|
44
44
|
const modifications: Modification[] = [];
|
|
45
45
|
|
|
46
46
|
for (const node of output.sources[sourcePath].ast.nodes) {
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
47
|
+
switch (node.nodeType) {
|
|
48
|
+
case 'ContractDefinition': {
|
|
49
|
+
const contractDef = node;
|
|
50
|
+
|
|
51
|
+
// Remove any calls to parent constructors from the inheritance list
|
|
52
|
+
const inherits = contractDef.baseContracts;
|
|
53
|
+
for (const inherit of inherits) {
|
|
54
|
+
if (Array.isArray(inherit.arguments)) {
|
|
55
|
+
assert(inherit.baseName.name !== undefined);
|
|
56
|
+
modifications.push(makeReplace(inherit, orig, inherit.baseName.name));
|
|
57
|
+
}
|
|
56
58
|
}
|
|
57
|
-
}
|
|
58
59
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
60
|
+
const contractNodes = contractDef.nodes;
|
|
61
|
+
for (const contractNode of contractNodes) {
|
|
62
|
+
switch (contractNode.nodeType) {
|
|
63
|
+
case 'ErrorDefinition':
|
|
64
|
+
case 'EventDefinition':
|
|
65
|
+
case 'FunctionDefinition':
|
|
66
|
+
case 'ModifierDefinition':
|
|
67
|
+
case 'UsingForDirective':
|
|
68
|
+
case 'VariableDeclaration': {
|
|
69
|
+
// Replace with an enum based on astId (the original name is not needed, since nothing should reference it)
|
|
70
|
+
modifications.push(makeReplace(contractNode, orig, toDummyEnumWithAstId(contractNode.id)));
|
|
71
|
+
break;
|
|
72
|
+
}
|
|
73
|
+
case 'StructDefinition': {
|
|
74
|
+
const storageLocation = getStorageLocationAnnotation(contractNode);
|
|
75
|
+
if (storageLocation !== undefined) {
|
|
76
|
+
const structName = contractNode.name;
|
|
77
|
+
const variableName = `$${structName}_${(Math.random() * 1e6).toFixed(0)}`;
|
|
78
|
+
const insertText = ` ${structName} ${variableName};`;
|
|
79
|
+
|
|
80
|
+
modifications.push(makeInsertAfter(contractNode, insertText));
|
|
81
|
+
}
|
|
82
|
+
break;
|
|
83
|
+
}
|
|
84
|
+
case 'EnumDefinition':
|
|
85
|
+
case 'UserDefinedValueTypeDefinition':
|
|
86
|
+
default: {
|
|
87
|
+
// - EnumDefinition may be used in structures with storage locations
|
|
88
|
+
// - UserDefinedValueTypeDefinition may be used in structures with storage locations
|
|
89
|
+
// - default: in case unexpected ast nodes show up
|
|
90
|
+
break;
|
|
91
|
+
}
|
|
80
92
|
}
|
|
81
93
|
}
|
|
94
|
+
break;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
// - UsingForDirective isn't needed, but it might have NatSpec documentation which is not included in the AST.
|
|
98
|
+
// We convert it to a dummy enum to avoid orphaning any possible documentation.
|
|
99
|
+
// - ErrorDefinition, FunctionDefinition, and VariableDeclaration might be imported by other files, so they cannot be deleted.
|
|
100
|
+
// However, we need to remove their values to avoid referencing other deleted nodes.
|
|
101
|
+
// We do this by converting them to dummy enums, but avoiding duplicate names.
|
|
102
|
+
case 'UsingForDirective':
|
|
103
|
+
case 'ErrorDefinition':
|
|
104
|
+
case 'FunctionDefinition':
|
|
105
|
+
case 'VariableDeclaration': {
|
|
106
|
+
// If an identifier with the same name was not previously written, replace with a dummy enum using its name.
|
|
107
|
+
// Otherwise replace with an enum based on astId to avoid duplicate names, which can happen if there was overloading.
|
|
108
|
+
// This does not need to check all identifiers from the original contract, since the original compilation
|
|
109
|
+
// should have failed if there were conflicts in the first place.
|
|
110
|
+
if ('name' in node && !replacedIdentifiers.has(node.name)) {
|
|
111
|
+
modifications.push(makeReplace(node, orig, toDummyEnumWithName(node.name)));
|
|
112
|
+
replacedIdentifiers.add(node.name);
|
|
113
|
+
} else {
|
|
114
|
+
modifications.push(makeReplace(node, orig, toDummyEnumWithAstId(node.id)));
|
|
115
|
+
}
|
|
116
|
+
break;
|
|
82
117
|
}
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
118
|
+
case 'EnumDefinition':
|
|
119
|
+
case 'ImportDirective':
|
|
120
|
+
case 'PragmaDirective':
|
|
121
|
+
case 'StructDefinition':
|
|
122
|
+
case 'UserDefinedValueTypeDefinition':
|
|
123
|
+
default: {
|
|
124
|
+
// - EnumDefinition may be used in structures with storage locations
|
|
125
|
+
// - ImportDirective may import types used in structures with storage locations
|
|
126
|
+
// - PragmaDirective is necessary for compilation
|
|
127
|
+
// - StructDefinition may be used in structures with storage locations
|
|
128
|
+
// - UserDefinedValueTypeDefinition may be used in structures with storage locations
|
|
129
|
+
// - default: in case unexpected ast nodes show up (file-level events since 0.8.22)
|
|
130
|
+
break;
|
|
86
131
|
}
|
|
87
|
-
// Replace with a dummy variable of arbitrary type
|
|
88
|
-
const name = node.name;
|
|
89
|
-
const insertText = `uint256 constant ${name} = 0;`;
|
|
90
|
-
modifications.push(makeReplace(node, orig, insertText));
|
|
91
|
-
} else if (isNodeType('UsingForDirective', node)) {
|
|
92
|
-
modifications.push(makeDelete(node, orig));
|
|
93
132
|
}
|
|
94
133
|
}
|
|
95
134
|
|
|
@@ -105,6 +144,14 @@ interface Modification {
|
|
|
105
144
|
text?: string;
|
|
106
145
|
}
|
|
107
146
|
|
|
147
|
+
function toDummyEnumWithName(name: string) {
|
|
148
|
+
return `enum ${name} { dummy }`;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
function toDummyEnumWithAstId(astId: number) {
|
|
152
|
+
return `enum $astId_${astId}_${(Math.random() * 1e6).toFixed(0)} { dummy }`;
|
|
153
|
+
}
|
|
154
|
+
|
|
108
155
|
function getPositions(node: Node) {
|
|
109
156
|
const [start, length] = node.src.split(':').map(Number);
|
|
110
157
|
const end = start + length;
|