slotdiff 0.2.0-alpha.1 → 0.3.1
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/CHANGELOG.md +41 -0
- package/README.md +55 -38
- package/dist/build-info.d.ts.map +1 -1
- package/dist/build-info.js +9 -3
- package/dist/build-info.js.map +1 -1
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +59 -33
- package/dist/cli.js.map +1 -1
- package/dist/erc7201.d.ts +27 -11
- package/dist/erc7201.d.ts.map +1 -1
- package/dist/erc7201.js +182 -13
- package/dist/erc7201.js.map +1 -1
- package/dist/errors.d.ts +14 -0
- package/dist/errors.d.ts.map +1 -1
- package/dist/errors.js +20 -0
- package/dist/errors.js.map +1 -1
- package/dist/explorer.d.ts.map +1 -1
- package/dist/explorer.js +28 -9
- package/dist/explorer.js.map +1 -1
- package/dist/index.d.ts +4 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -2
- package/dist/index.js.map +1 -1
- package/dist/reconstruct.d.ts +30 -15
- package/dist/reconstruct.d.ts.map +1 -1
- package/dist/reconstruct.js +140 -32
- package/dist/reconstruct.js.map +1 -1
- package/dist/record.d.ts +13 -0
- package/dist/record.d.ts.map +1 -1
- package/dist/record.js +8 -0
- package/dist/record.js.map +1 -1
- package/dist/report.d.ts +4 -1
- package/dist/report.d.ts.map +1 -1
- package/dist/report.js +37 -8
- package/dist/report.js.map +1 -1
- package/dist/resolve.d.ts +6 -1
- package/dist/resolve.d.ts.map +1 -1
- package/dist/resolve.js +6 -1
- package/dist/resolve.js.map +1 -1
- package/dist/solc.js +20 -4
- package/dist/solc.js.map +1 -1
- package/dist/upgrade.d.ts +48 -0
- package/dist/upgrade.d.ts.map +1 -0
- package/dist/upgrade.js +36 -0
- package/dist/upgrade.js.map +1 -0
- package/package.json +5 -5
- package/src/build-info.ts +9 -3
- package/src/cli.ts +69 -33
- package/src/erc7201.ts +217 -26
- package/src/errors.ts +22 -0
- package/src/explorer.ts +39 -10
- package/src/index.ts +11 -3
- package/src/reconstruct.ts +206 -57
- package/src/record.ts +18 -0
- package/src/report.ts +44 -13
- package/src/resolve.ts +12 -2
- package/src/solc.ts +20 -4
- package/src/upgrade.ts +91 -0
package/dist/resolve.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"resolve.d.ts","sourceRoot":"","sources":["../src/resolve.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,6BAA6B,CAAC;AACjE,OAAO,EAGL,KAAK,qBAAqB,EAC1B,KAAK,mBAAmB,EACzB,MAAM,eAAe,CAAC;AACvB,OAAO,EAAgD,KAAK,WAAW,EAAE,MAAM,YAAY,CAAC;AAE5F,OAAO,EAAyC,KAAK,cAAc,EAAE,MAAM,eAAe,CAAC;AAC3F,OAAO,EAAqB,KAAK,mBAAmB,EAAE,MAAM,kBAAkB,CAAC;AAC/
|
|
1
|
+
{"version":3,"file":"resolve.d.ts","sourceRoot":"","sources":["../src/resolve.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,6BAA6B,CAAC;AACjE,OAAO,EAGL,KAAK,qBAAqB,EAC1B,KAAK,mBAAmB,EACzB,MAAM,eAAe,CAAC;AACvB,OAAO,EAAgD,KAAK,WAAW,EAAE,MAAM,YAAY,CAAC;AAE5F,OAAO,EAAyC,KAAK,cAAc,EAAE,MAAM,eAAe,CAAC;AAC3F,OAAO,EAAqB,KAAK,SAAS,EAAE,KAAK,mBAAmB,EAAE,MAAM,kBAAkB,CAAC;AAC/F,OAAO,EAAe,KAAK,YAAY,EAAE,MAAM,aAAa,CAAC;AAC7D,OAAO,EAAW,KAAK,WAAW,EAAE,MAAM,WAAW,CAAC;AAEtD,MAAM,WAAW,cAAc;IAC7B,QAAQ,EAAE,cAAc,CAAC;IACzB,IAAI,CAAC,EAAE,WAAW,CAAC;CACpB;AAED;;;;GAIG;AACH,wBAAsB,aAAa,CACjC,QAAQ,EAAE,WAAW,EACrB,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,cAAc,GACtB,OAAO,CAAC,YAAY,CAAC,CAEvB;AAED;;;;;GAKG;AACH,wBAAsB,OAAO,CAC3B,QAAQ,EAAE,WAAW,EACrB,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,cAAc,GACtB,OAAO,CAAC;IAAE,MAAM,EAAE,YAAY,CAAC;IAAC,QAAQ,EAAE,mBAAmB,CAAA;CAAE,CAAC,CA4BlE;AAED,MAAM,WAAW,WAAW;IAC1B,6CAA6C;IAC7C,cAAc,EAAE,MAAM,CAAC;IACvB,8BAA8B;IAC9B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,yFAAyF;IACzF,IAAI,EAAE,SAAS,CAAC;IAChB,MAAM,EAAE,YAAY,CAAC;CACtB;AAED,+FAA+F;AAC/F,wBAAsB,kBAAkB,CACtC,QAAQ,EAAE,WAAW,EACrB,KAAK,EAAE,MAAM,EACb,OAAO,EAAE,cAAc,GACtB,OAAO,CAAC,WAAW,CAAC,CAUtB;AAED,MAAM,WAAW,UAAU;IACzB,mDAAmD;IACnD,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,aAAa,CAAC;IACtB,gBAAgB,EAAE,MAAM,CAAC;IACzB,mBAAmB,CAAC,EAAE,mBAAmB,CAAC;IAC1C,6EAA6E;IAC7E,IAAI,CAAC,EAAE,YAAY,CAAC,MAAM,CAAC,CAAC;IAC5B,UAAU,CAAC,EAAE,YAAY,CAAC,YAAY,CAAC,CAAC;CACzC;AAED,MAAM,WAAW,gBAAgB;IAC/B,aAAa,EAAE,qBAAqB,CAAC;IACrC,gFAAgF;IAChF,MAAM,CAAC,EAAE,YAAY,CAAC;CACvB;AAED;;;;GAIG;AACH,wBAAsB,eAAe,CACnC,QAAQ,EAAE,WAAW,EACrB,OAAO,EAAE,MAAM,EACf,KAAK,EAAE,UAAU,GAChB,OAAO,CAAC,gBAAgB,CAAC,CA0B3B"}
|
package/dist/resolve.js
CHANGED
|
@@ -49,6 +49,8 @@ export async function rebuild(provider, address, options) {
|
|
|
49
49
|
source: "explorer",
|
|
50
50
|
recordedAt: new Date().toISOString(),
|
|
51
51
|
layout: rebuilt.layout,
|
|
52
|
+
kind: rebuilt.kind,
|
|
53
|
+
namespaces: rebuilt.namespaces,
|
|
52
54
|
};
|
|
53
55
|
return { record, analysis: rebuilt };
|
|
54
56
|
}
|
|
@@ -59,7 +61,8 @@ export async function resolveProxyLayout(provider, proxy, options) {
|
|
|
59
61
|
throw new LayoutUnavailableError(`${proxy} has no ERC-1967 implementation or beacon slot set on this chain.`);
|
|
60
62
|
}
|
|
61
63
|
const record = await resolveLayout(provider, state.implementation, options);
|
|
62
|
-
|
|
64
|
+
// A rebuilt record always has its kind.
|
|
65
|
+
return { ...state, kind: state.beacon !== undefined ? "beacon" : record.kind, record };
|
|
63
66
|
}
|
|
64
67
|
/**
|
|
65
68
|
* Makes a record from a local build of the code at `address`, but only after
|
|
@@ -83,6 +86,8 @@ export async function proveLocalBuild(provider, address, build) {
|
|
|
83
86
|
source: "local-compile",
|
|
84
87
|
recordedAt: new Date().toISOString(),
|
|
85
88
|
layout: build.layout,
|
|
89
|
+
...(build.kind !== undefined ? { kind: build.kind } : {}),
|
|
90
|
+
...(build.namespaces !== undefined ? { namespaces: build.namespaces } : {}),
|
|
86
91
|
};
|
|
87
92
|
// A record this returns must load back through parseRecord, so check it now.
|
|
88
93
|
return { bytecodeMatch, record: parseRecord(JSON.parse(JSON.stringify(record)), lower) };
|
package/dist/resolve.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"resolve.js","sourceRoot":"","sources":["../src/resolve.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAGH,OAAO,EACL,uBAAuB,EACvB,cAAc,GAGf,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,QAAQ,EAAE,SAAS,EAAoB,MAAM,YAAY,CAAC;AAC5F,OAAO,EAAE,sBAAsB,EAAE,MAAM,aAAa,CAAC;AACrD,OAAO,EAAE,gBAAgB,EAAE,mBAAmB,EAAuB,MAAM,eAAe,CAAC;AAC3F,OAAO,EAAE,iBAAiB,
|
|
1
|
+
{"version":3,"file":"resolve.js","sourceRoot":"","sources":["../src/resolve.ts"],"names":[],"mappings":"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"}
|
package/dist/solc.js
CHANGED
|
@@ -13,9 +13,9 @@
|
|
|
13
13
|
*/
|
|
14
14
|
import { spawn } from "node:child_process";
|
|
15
15
|
import { createHash, randomUUID } from "node:crypto";
|
|
16
|
-
import { access, chmod, mkdir, readdir, rename, writeFile } from "node:fs/promises";
|
|
16
|
+
import { access, chmod, mkdir, mkdtemp, readdir, rename, rm, writeFile } from "node:fs/promises";
|
|
17
17
|
import { constants } from "node:fs";
|
|
18
|
-
import { homedir } from "node:os";
|
|
18
|
+
import { homedir, tmpdir } from "node:os";
|
|
19
19
|
import { join } from "node:path";
|
|
20
20
|
import { LayoutIntegrityError, LayoutUnavailableError } from "./errors.js";
|
|
21
21
|
const BINARIES_URL = "https://binaries.soliditylang.org";
|
|
@@ -108,6 +108,10 @@ async function findBuild(platform, version, fetchImpl) {
|
|
|
108
108
|
if (build === undefined) {
|
|
109
109
|
throw new LayoutUnavailableError(`solc ${version} has no native ${platform} build.`);
|
|
110
110
|
}
|
|
111
|
+
// Both become paths: a release is matched by prefix, so its long version comes from the list.
|
|
112
|
+
if (!SOLC_VERSION.test(build.longVersion) || !/^[\w.+-]+$/.test(build.path)) {
|
|
113
|
+
throw new LayoutUnavailableError(`The solc build list has a malformed entry for ${version}.`);
|
|
114
|
+
}
|
|
111
115
|
// Old Windows releases (up to 0.7.1) ship as zip archives, not executables.
|
|
112
116
|
if (build.path.endsWith(".zip")) {
|
|
113
117
|
throw new LayoutUnavailableError(`solc ${build.longVersion} for ${platform} ships as a zip archive; pass a compiler via solc.resolvePath.`);
|
|
@@ -130,9 +134,21 @@ async function download(platform, build, dest, fetchImpl) {
|
|
|
130
134
|
await chmod(tmp, 0o755);
|
|
131
135
|
await rename(tmp, dest);
|
|
132
136
|
}
|
|
133
|
-
|
|
137
|
+
// solc reads imports it is not given from its working directory, so it runs in
|
|
138
|
+
// an empty one: verified source could otherwise import, and quote in an error,
|
|
139
|
+
// any file under the caller's (an .env, say).
|
|
140
|
+
async function runSolc(path, input) {
|
|
141
|
+
const cwd = await mkdtemp(join(tmpdir(), "slotdiff-solc-"));
|
|
142
|
+
try {
|
|
143
|
+
return await runSolcIn(cwd, path, input);
|
|
144
|
+
}
|
|
145
|
+
finally {
|
|
146
|
+
await rm(cwd, { recursive: true, force: true });
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
function runSolcIn(cwd, path, input) {
|
|
134
150
|
return new Promise((resolve, reject) => {
|
|
135
|
-
const child = spawn(path, ["--standard-json"], { stdio: ["pipe", "pipe", "pipe"] });
|
|
151
|
+
const child = spawn(path, ["--standard-json"], { cwd, stdio: ["pipe", "pipe", "pipe"] });
|
|
136
152
|
const out = [];
|
|
137
153
|
const err = [];
|
|
138
154
|
child.stdout.on("data", (d) => out.push(d));
|
package/dist/solc.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"solc.js","sourceRoot":"","sources":["../src/solc.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,EAAE,KAAK,EAAE,MAAM,oBAAoB,CAAC;AAC3C,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACrD,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,KAAK,EAAE,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;
|
|
1
|
+
{"version":3,"file":"solc.js","sourceRoot":"","sources":["../src/solc.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The whole upgrade check in one call, as the CLI runs it: the storage layout,
|
|
3
|
+
* the ERC-7201 slots and OpenZeppelin's safety rules, with one verdict.
|
|
4
|
+
*/
|
|
5
|
+
import type { StorageLayout } from "@openzeppelin/upgrades-core";
|
|
6
|
+
import { type DiffOptions, type LayoutReport } from "./diff.js";
|
|
7
|
+
import { type NamespaceCheck, type NamespaceSlot } from "./erc7201.js";
|
|
8
|
+
import type { ProxyKind, SafetyErrorKind, SafetyReport, SourceAnalysis } from "./reconstruct.js";
|
|
9
|
+
export interface UpgradeOptions extends DiffOptions {
|
|
10
|
+
/** Error kinds to accept anyway (OZ's `unsafeAllow`). Prefer NatSpec exceptions in the source. */
|
|
11
|
+
unsafeAllow?: SafetyErrorKind[];
|
|
12
|
+
/** Skip the safety rules; the layout and slots are still checked. */
|
|
13
|
+
skipSafety?: boolean;
|
|
14
|
+
}
|
|
15
|
+
/** A layout with the slot of each namespace, such as a `LayoutRecord` or a `SourceAnalysis`. */
|
|
16
|
+
export interface UpgradeSide {
|
|
17
|
+
layout: StorageLayout;
|
|
18
|
+
/** Without them, the namespaces are unchecked. */
|
|
19
|
+
namespaces?: NamespaceSlot[];
|
|
20
|
+
}
|
|
21
|
+
export interface UpgradeCheck {
|
|
22
|
+
/** OpenZeppelin's comparison, with each namespace paired by the slot in code. */
|
|
23
|
+
layout: LayoutReport;
|
|
24
|
+
namespaces: NamespaceCheck;
|
|
25
|
+
/** Absent with `skipSafety`: then `pass` covers the layout and slots only. */
|
|
26
|
+
safety?: SafetyReport;
|
|
27
|
+
/**
|
|
28
|
+
* `fail`: a check failed. `unchecked`: none failed, but an ERC-7201 slot
|
|
29
|
+
* could not be read (`unread` in `namespaces`). `pass`: every check that ran passed.
|
|
30
|
+
*/
|
|
31
|
+
result: "pass" | "fail" | "unchecked";
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Whether `next` can replace `old` behind a proxy. `old.kind` is the kind of
|
|
35
|
+
* the proxy being upgraded (`beacon` when a beacon serves it): taking it from
|
|
36
|
+
* `next` would let a UUPS implementation that lost its upgrade function pass.
|
|
37
|
+
* `old` may be a `SourceAnalysis`, or a `LayoutRecord` with its `kind` given.
|
|
38
|
+
* With `skipSafety`, `next` may be a record too, and `old.kind` is not needed.
|
|
39
|
+
*/
|
|
40
|
+
export declare function checkUpgrade(old: UpgradeSide & {
|
|
41
|
+
kind: ProxyKind;
|
|
42
|
+
}, next: SourceAnalysis, options?: UpgradeOptions): UpgradeCheck;
|
|
43
|
+
export declare function checkUpgrade(old: UpgradeSide & {
|
|
44
|
+
kind?: ProxyKind;
|
|
45
|
+
}, next: UpgradeSide, options: UpgradeOptions & {
|
|
46
|
+
skipSafety: true;
|
|
47
|
+
}): UpgradeCheck;
|
|
48
|
+
//# sourceMappingURL=upgrade.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"upgrade.d.ts","sourceRoot":"","sources":["../src/upgrade.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,6BAA6B,CAAC;AACjE,OAAO,EAAe,KAAK,WAAW,EAAE,KAAK,YAAY,EAAE,MAAM,WAAW,CAAC;AAC7E,OAAO,EAAmB,KAAK,cAAc,EAAE,KAAK,aAAa,EAAE,MAAM,cAAc,CAAC;AACxF,OAAO,KAAK,EAAE,SAAS,EAAE,eAAe,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAEjG,MAAM,WAAW,cAAe,SAAQ,WAAW;IACjD,kGAAkG;IAClG,WAAW,CAAC,EAAE,eAAe,EAAE,CAAC;IAChC,qEAAqE;IACrE,UAAU,CAAC,EAAE,OAAO,CAAC;CACtB;AAED,gGAAgG;AAChG,MAAM,WAAW,WAAW;IAC1B,MAAM,EAAE,aAAa,CAAC;IACtB,kDAAkD;IAClD,UAAU,CAAC,EAAE,aAAa,EAAE,CAAC;CAC9B;AAED,MAAM,WAAW,YAAY;IAC3B,iFAAiF;IACjF,MAAM,EAAE,YAAY,CAAC;IACrB,UAAU,EAAE,cAAc,CAAC;IAC3B,8EAA8E;IAC9E,MAAM,CAAC,EAAE,YAAY,CAAC;IACtB;;;OAGG;IACH,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,WAAW,CAAC;CACvC;AAID;;;;;;GAMG;AACH,wBAAgB,YAAY,CAC1B,GAAG,EAAE,WAAW,GAAG;IAAE,IAAI,EAAE,SAAS,CAAA;CAAE,EACtC,IAAI,EAAE,cAAc,EACpB,OAAO,CAAC,EAAE,cAAc,GACvB,YAAY,CAAC;AAChB,wBAAgB,YAAY,CAC1B,GAAG,EAAE,WAAW,GAAG;IAAE,IAAI,CAAC,EAAE,SAAS,CAAA;CAAE,EACvC,IAAI,EAAE,WAAW,EACjB,OAAO,EAAE,cAAc,GAAG;IAAE,UAAU,EAAE,IAAI,CAAA;CAAE,GAC7C,YAAY,CAAC"}
|
package/dist/upgrade.js
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The whole upgrade check in one call, as the CLI runs it: the storage layout,
|
|
3
|
+
* the ERC-7201 slots and OpenZeppelin's safety rules, with one verdict.
|
|
4
|
+
*/
|
|
5
|
+
import { diffLayouts } from "./diff.js";
|
|
6
|
+
import { checkNamespaces } from "./erc7201.js";
|
|
7
|
+
const PROXY_KINDS = ["uups", "transparent", "beacon"];
|
|
8
|
+
export function checkUpgrade(old, next, options = {}) {
|
|
9
|
+
if (!options.skipSafety) {
|
|
10
|
+
// Checked here for JavaScript callers: OpenZeppelin treats an unknown kind as uups.
|
|
11
|
+
if (!PROXY_KINDS.includes(old.kind)) {
|
|
12
|
+
throw new Error(`checkUpgrade needs the kind of the proxy being upgraded (${PROXY_KINDS.join(", ")}), ` +
|
|
13
|
+
`got ${JSON.stringify(old.kind)}.`);
|
|
14
|
+
}
|
|
15
|
+
if (typeof next.safety !== "function") {
|
|
16
|
+
throw new Error("checkUpgrade needs an analysis of next (analyzeSource), or skipSafety.");
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
// OpenZeppelin matches namespaces by annotation; pairing them by slot first
|
|
20
|
+
// makes it compare the structs of the same storage.
|
|
21
|
+
const namespaces = checkNamespaces(old, next);
|
|
22
|
+
const layout = diffLayouts(namespaces.layout, next.layout, {
|
|
23
|
+
unsafeAllowRenames: options.unsafeAllowRenames,
|
|
24
|
+
});
|
|
25
|
+
const safety = options.skipSafety
|
|
26
|
+
? undefined
|
|
27
|
+
: next.safety({ kind: old.kind, unsafeAllow: options.unsafeAllow });
|
|
28
|
+
// A failure outranks an unread slot, so a known problem is never reported as merely unchecked.
|
|
29
|
+
const result = !layout.ok || namespaces.result === "fail" || safety?.ok === false
|
|
30
|
+
? "fail"
|
|
31
|
+
: namespaces.result === "unchecked"
|
|
32
|
+
? "unchecked"
|
|
33
|
+
: "pass";
|
|
34
|
+
return { layout, namespaces, ...(safety !== undefined ? { safety } : {}), result };
|
|
35
|
+
}
|
|
36
|
+
//# sourceMappingURL=upgrade.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"upgrade.js","sourceRoot":"","sources":["../src/upgrade.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,EAAE,WAAW,EAAuC,MAAM,WAAW,CAAC;AAC7E,OAAO,EAAE,eAAe,EAA2C,MAAM,cAAc,CAAC;AA8BxF,MAAM,WAAW,GAAsB,CAAC,MAAM,EAAE,aAAa,EAAE,QAAQ,CAAC,CAAC;AAmBzE,MAAM,UAAU,YAAY,CAC1B,GAAuC,EACvC,IAAyD,EACzD,UAA0B,EAAE;IAE5B,IAAI,CAAC,OAAO,CAAC,UAAU,EAAE,CAAC;QACxB,oFAAoF;QACpF,IAAI,CAAC,WAAW,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAc,CAAC,EAAE,CAAC;YAC9C,MAAM,IAAI,KAAK,CACb,4DAA4D,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK;gBACrF,OAAO,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CACrC,CAAC;QACJ,CAAC;QACD,IAAI,OAAO,IAAI,CAAC,MAAM,KAAK,UAAU,EAAE,CAAC;YACtC,MAAM,IAAI,KAAK,CAAC,wEAAwE,CAAC,CAAC;QAC5F,CAAC;IACH,CAAC;IACD,4EAA4E;IAC5E,oDAAoD;IACpD,MAAM,UAAU,GAAG,eAAe,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;IAC9C,MAAM,MAAM,GAAG,WAAW,CAAC,UAAU,CAAC,MAAM,EAAE,IAAI,CAAC,MAAM,EAAE;QACzD,kBAAkB,EAAE,OAAO,CAAC,kBAAkB;KAC/C,CAAC,CAAC;IACH,MAAM,MAAM,GAAG,OAAO,CAAC,UAAU;QAC/B,CAAC,CAAC,SAAS;QACX,CAAC,CAAC,IAAI,CAAC,MAAO,CAAC,EAAE,IAAI,EAAE,GAAG,CAAC,IAAK,EAAE,WAAW,EAAE,OAAO,CAAC,WAAW,EAAE,CAAC,CAAC;IACxE,+FAA+F;IAC/F,MAAM,MAAM,GACV,CAAC,MAAM,CAAC,EAAE,IAAI,UAAU,CAAC,MAAM,KAAK,MAAM,IAAI,MAAM,EAAE,EAAE,KAAK,KAAK;QAChE,CAAC,CAAC,MAAM;QACR,CAAC,CAAC,UAAU,CAAC,MAAM,KAAK,WAAW;YACjC,CAAC,CAAC,WAAW;YACb,CAAC,CAAC,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,GAAG,CAAC,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC;AACrF,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "slotdiff",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.1",
|
|
4
4
|
"description": "Storage layout diff for upgradeable Solidity contracts: compare a local build or a live deployment against another",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "Rohit Solia (https://github.com/rokso)",
|
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
"main": "./dist/index.js",
|
|
17
17
|
"types": "./dist/index.d.ts",
|
|
18
18
|
"bin": {
|
|
19
|
-
"slotdiff": "
|
|
19
|
+
"slotdiff": "dist/bin.js"
|
|
20
20
|
},
|
|
21
21
|
"exports": {
|
|
22
22
|
".": {
|
|
@@ -53,10 +53,10 @@
|
|
|
53
53
|
"eslint": "^10.2.0",
|
|
54
54
|
"eslint-config-prettier": "^10.1.8",
|
|
55
55
|
"globals": "^17.5.0",
|
|
56
|
-
"prettier": "^3.
|
|
57
|
-
"typescript": "^
|
|
56
|
+
"prettier": "^3.9.10",
|
|
57
|
+
"typescript": "^6.0.3",
|
|
58
58
|
"typescript-eslint": "^8.58.2",
|
|
59
|
-
"vitest": "^
|
|
59
|
+
"vitest": "^5.0.3"
|
|
60
60
|
},
|
|
61
61
|
"engines": {
|
|
62
62
|
"node": ">=22.13.0"
|
package/src/build-info.ts
CHANGED
|
@@ -172,9 +172,15 @@ export async function findBuildInfo(
|
|
|
172
172
|
|
|
173
173
|
if (fresh.length === 0) {
|
|
174
174
|
throw new Error(
|
|
175
|
-
stale.length
|
|
176
|
-
?
|
|
177
|
-
:
|
|
175
|
+
stale.length === 0
|
|
176
|
+
? `${contract} is no longer on disk (moved or deleted). Build again.`
|
|
177
|
+
: withoutInput
|
|
178
|
+
? // Forge then skips the unchanged files, so building again keeps the input out.
|
|
179
|
+
`Every build info holding ${contract} with its compiler input is older than the ` +
|
|
180
|
+
"sources on disk; newer build info holds no compiler input (built without " +
|
|
181
|
+
"`--build-info`). Run `forge build --build-info --force`, or set " +
|
|
182
|
+
"`build_info = true` in foundry.toml so every build keeps it."
|
|
183
|
+
: `Every build info holding ${contract} is older than the sources on disk. Build again.`,
|
|
178
184
|
);
|
|
179
185
|
}
|
|
180
186
|
|
package/src/cli.ts
CHANGED
|
@@ -13,10 +13,15 @@ import { relative, resolve } from "node:path";
|
|
|
13
13
|
import { parseArgs, styleText } from "node:util";
|
|
14
14
|
import { findBuildInfo } from "./build-info.js";
|
|
15
15
|
import { readCode, readProxy, type EthProvider } from "./chain.js";
|
|
16
|
-
import {
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
16
|
+
import {
|
|
17
|
+
checkLines,
|
|
18
|
+
namespaceLines,
|
|
19
|
+
plain,
|
|
20
|
+
unassignedCount,
|
|
21
|
+
type Check,
|
|
22
|
+
type Paint,
|
|
23
|
+
} from "./report.js";
|
|
24
|
+
import { errorCode, LayoutUnavailableError, printable } from "./errors.js";
|
|
20
25
|
import { canQueryExplorer } from "./explorer.js";
|
|
21
26
|
import { rebuild } from "./resolve.js";
|
|
22
27
|
import {
|
|
@@ -27,6 +32,7 @@ import {
|
|
|
27
32
|
type SourceAnalysis,
|
|
28
33
|
} from "./reconstruct.js";
|
|
29
34
|
import { getSolc } from "./solc.js";
|
|
35
|
+
import { checkUpgrade } from "./upgrade.js";
|
|
30
36
|
|
|
31
37
|
const USAGE = `Usage: slotdiff <old> <new> [options]
|
|
32
38
|
|
|
@@ -36,7 +42,7 @@ OpenZeppelin's safety rules for <new> (constructors, initializers, selfdestruct.
|
|
|
36
42
|
Each side is either:
|
|
37
43
|
a contract in this project's build info src/Vault.sol:Vault, or Vault when unique
|
|
38
44
|
an address a proxy (the implementation it runs now),
|
|
39
|
-
or an implementation
|
|
45
|
+
or for <new>, an implementation
|
|
40
46
|
|
|
41
47
|
Options:
|
|
42
48
|
--rpc <url> JSON-RPC endpoint, required when a side is an address
|
|
@@ -48,6 +54,8 @@ Options:
|
|
|
48
54
|
--unsafe-allow <kinds> Comma-separated safety errors to accept, e.g. constructor;
|
|
49
55
|
prefer @custom:oz-upgrades-unsafe-allow in the source
|
|
50
56
|
--no-safety Skip the safety rules
|
|
57
|
+
--old-implementation <old> is an implementation address, not a proxy; also
|
|
58
|
+
for a proxy slotdiff cannot read (pass its implementation)
|
|
51
59
|
-h, --help Show this help
|
|
52
60
|
-v, --version Show the version
|
|
53
61
|
|
|
@@ -111,6 +119,7 @@ export async function run(argv: string[], io: CliIo): Promise<number> {
|
|
|
111
119
|
"unsafe-allow-renames": { type: "boolean" },
|
|
112
120
|
"unsafe-allow": { type: "string" },
|
|
113
121
|
"no-safety": { type: "boolean" },
|
|
122
|
+
"old-implementation": { type: "boolean" },
|
|
114
123
|
help: { type: "boolean", short: "h" },
|
|
115
124
|
version: { type: "boolean", short: "v" },
|
|
116
125
|
},
|
|
@@ -161,6 +170,12 @@ export async function run(argv: string[], io: CliIo): Promise<number> {
|
|
|
161
170
|
return 2;
|
|
162
171
|
}
|
|
163
172
|
|
|
173
|
+
const oldImplementation = values["old-implementation"] === true;
|
|
174
|
+
if (oldImplementation && !ADDRESS.test(positionals[0])) {
|
|
175
|
+
io.stderr("--old-implementation needs <old> to be an address.");
|
|
176
|
+
return 2;
|
|
177
|
+
}
|
|
178
|
+
|
|
164
179
|
const safety = !values["no-safety"];
|
|
165
180
|
if (!safety && values["unsafe-allow"] !== undefined) {
|
|
166
181
|
io.stderr("--unsafe-allow does nothing with --no-safety.");
|
|
@@ -206,10 +221,23 @@ export async function run(argv: string[], io: CliIo): Promise<number> {
|
|
|
206
221
|
|
|
207
222
|
if (io.tty) io.stdout(`${await banner()}\n`);
|
|
208
223
|
|
|
209
|
-
const readSide = async (spec: string): Promise<Side> => {
|
|
224
|
+
const readSide = async (spec: string, side: "old" | "new"): Promise<Side> => {
|
|
210
225
|
if (ADDRESS.test(spec)) {
|
|
211
|
-
// A proxy stands for what it runs now
|
|
226
|
+
// A proxy stands for what it runs now. <new> may be an implementation, but
|
|
227
|
+
// <old> only when said so: a proxy of a kind slotdiff cannot read (a
|
|
228
|
+
// diamond, a custom slot) would otherwise be compared as its own code.
|
|
212
229
|
const proxy = await readProxy(provider!, spec);
|
|
230
|
+
if (side === "old" && (proxy === undefined) !== oldImplementation) {
|
|
231
|
+
// An address with no code is reported as such.
|
|
232
|
+
if (proxy === undefined) await readCode(provider!, spec);
|
|
233
|
+
throw new Error(
|
|
234
|
+
proxy === undefined
|
|
235
|
+
? `${spec.toLowerCase()} is not a proxy slotdiff can read (no ERC-1967 implementation ` +
|
|
236
|
+
"or beacon slot is set). If it is an implementation, or a proxy of another kind " +
|
|
237
|
+
"given by its implementation's address, pass --old-implementation."
|
|
238
|
+
: `${spec.toLowerCase()} is a proxy, not an implementation: drop --old-implementation.`,
|
|
239
|
+
);
|
|
240
|
+
}
|
|
213
241
|
const implementation = proxy?.implementation ?? spec.toLowerCase();
|
|
214
242
|
if (!canQueryExplorer(explorer)) {
|
|
215
243
|
await readCode(provider!, implementation); // a wrong address is reported as such first
|
|
@@ -248,11 +276,12 @@ export async function run(argv: string[], io: CliIo): Promise<number> {
|
|
|
248
276
|
let old: Side;
|
|
249
277
|
let next: Side;
|
|
250
278
|
try {
|
|
251
|
-
old = await readSide(positionals[0]);
|
|
279
|
+
old = await readSide(positionals[0], "old");
|
|
252
280
|
// The same side twice (e.g. a proxy against itself) is fetched and compiled once.
|
|
253
|
-
next = positionals[1] === positionals[0] ? old : await readSide(positionals[1]);
|
|
281
|
+
next = positionals[1] === positionals[0] ? old : await readSide(positionals[1], "new");
|
|
254
282
|
} catch (e) {
|
|
255
|
-
|
|
283
|
+
// Messages can quote an explorer or verified source.
|
|
284
|
+
io.stderr(`Could not check: ${printable((e as Error).message)}`);
|
|
256
285
|
return 2;
|
|
257
286
|
}
|
|
258
287
|
|
|
@@ -265,15 +294,17 @@ export async function run(argv: string[], io: CliIo): Promise<number> {
|
|
|
265
294
|
);
|
|
266
295
|
}
|
|
267
296
|
|
|
268
|
-
//
|
|
269
|
-
//
|
|
270
|
-
const
|
|
297
|
+
// The kind comes from <old>, the proxy being upgraded: inferring it from <new>
|
|
298
|
+
// would miss a UUPS implementation that lost its upgrade function.
|
|
299
|
+
const upgrade = checkUpgrade({ ...old.analysis, kind: old.kind }, next.analysis, {
|
|
300
|
+
unsafeAllowRenames: values["unsafe-allow-renames"],
|
|
301
|
+
unsafeAllow,
|
|
302
|
+
skipSafety: !safety,
|
|
303
|
+
});
|
|
304
|
+
const { layout: report, namespaces, safety: safetyCheck } = upgrade;
|
|
271
305
|
const grid = namespaceLines(namespaces.pairs, paint);
|
|
272
306
|
if (grid.length > 0) io.stdout(`\n${grid.join("\n")}`);
|
|
273
307
|
|
|
274
|
-
const report = diffLayouts(namespaces.layout, next.analysis.layout, {
|
|
275
|
-
unsafeAllowRenames: values["unsafe-allow-renames"],
|
|
276
|
-
});
|
|
277
308
|
const renames = values["unsafe-allow-renames"] ? " (renames accepted)" : "";
|
|
278
309
|
const checks: Check[] = [
|
|
279
310
|
report.ok
|
|
@@ -291,18 +322,19 @@ export async function run(argv: string[], io: CliIo): Promise<number> {
|
|
|
291
322
|
name: "ERC-7201 slots",
|
|
292
323
|
...(namespaces.result === "fail"
|
|
293
324
|
? { status: "fail", summary: "problems found in <new> (see above)" }
|
|
294
|
-
: namespaces.result === "
|
|
325
|
+
: namespaces.result === "unchecked"
|
|
295
326
|
? { status: "skip", summary: "not checked: some slots could not be read (see above)" }
|
|
296
|
-
:
|
|
297
|
-
|
|
298
|
-
|
|
327
|
+
: {
|
|
328
|
+
status: "pass",
|
|
329
|
+
summary:
|
|
330
|
+
(grid.length > 0
|
|
331
|
+
? "compared by the slot in code (see above)"
|
|
332
|
+
: "match their annotations") + unassigned(unassignedCount(namespaces.pairs)),
|
|
333
|
+
}),
|
|
299
334
|
});
|
|
300
335
|
}
|
|
301
336
|
|
|
302
|
-
// The kind comes from <old>, the proxy being upgraded: inferring it from <new>
|
|
303
|
-
// would miss a UUPS implementation that lost its upgrade function.
|
|
304
337
|
const accepted = unsafeAllow.length > 0 ? `; accepted: ${unsafeAllow.join(", ")}` : "";
|
|
305
|
-
const safetyCheck = safety ? next.analysis.safety({ kind: old.kind, unsafeAllow }) : undefined;
|
|
306
338
|
checks.push(
|
|
307
339
|
safetyCheck === undefined
|
|
308
340
|
? { name: "Safety rules", status: "skip", summary: "skipped (--no-safety)" }
|
|
@@ -322,16 +354,16 @@ export async function run(argv: string[], io: CliIo): Promise<number> {
|
|
|
322
354
|
io.stdout(`\n${checkLines(checks, paint).join("\n")}`);
|
|
323
355
|
|
|
324
356
|
// One verdict, so a passing check next to a failing one is never read as safe.
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
357
|
+
if (upgrade.result === "fail") {
|
|
358
|
+
const problems = [
|
|
359
|
+
...(report.ok ? [] : ["the storage layout is incompatible"]),
|
|
360
|
+
...(namespaces.result === "fail" ? ["an ERC-7201 namespace fails the slot check"] : []),
|
|
361
|
+
...(safetyCheck?.ok === false ? ["<new> breaks the safety rules"] : []),
|
|
362
|
+
];
|
|
331
363
|
io.stdout(`\n${paint(["bold", "red"], "Not safe to upgrade:")} ${problems.join(" and ")}.`);
|
|
332
364
|
return 1;
|
|
333
365
|
}
|
|
334
|
-
if (
|
|
366
|
+
if (upgrade.result === "unchecked") {
|
|
335
367
|
io.stdout(
|
|
336
368
|
`\n${paint(["bold", "yellow"], "Could not check:")} some ERC-7201 slots could not be read.`,
|
|
337
369
|
);
|
|
@@ -345,6 +377,11 @@ export async function run(argv: string[], io: CliIo): Promise<number> {
|
|
|
345
377
|
return 0;
|
|
346
378
|
}
|
|
347
379
|
|
|
380
|
+
function unassigned(count: number): string {
|
|
381
|
+
if (count === 0) return "";
|
|
382
|
+
return `; ${count} not assigned in code, compared by annotation`;
|
|
383
|
+
}
|
|
384
|
+
|
|
348
385
|
function httpUrl(value: string, flag: string): URL {
|
|
349
386
|
let url: URL;
|
|
350
387
|
try {
|
|
@@ -404,9 +441,8 @@ function jsonRpcProvider(url: URL, fetchImpl: FetchLike): EthProvider {
|
|
|
404
441
|
}
|
|
405
442
|
if (body.error !== undefined) {
|
|
406
443
|
// The server's text, without control characters (terminal escapes) and capped.
|
|
407
|
-
const message = String(body.error.message ?? "unknown error")
|
|
408
|
-
|
|
409
|
-
.replace(/[\u0000-\u001f\u007f-\u009f]/g, " ")
|
|
444
|
+
const message = printable(String(body.error.message ?? "unknown error"))
|
|
445
|
+
.replace(/\s/g, " ")
|
|
410
446
|
.slice(0, 300);
|
|
411
447
|
throw new Error(`RPC ${method} failed: ${message}`);
|
|
412
448
|
}
|