slotdiff 0.1.0-alpha.1 → 0.2.0-alpha.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 +16 -9
- package/README.md +196 -105
- package/dist/bin.d.ts +3 -0
- package/dist/bin.d.ts.map +1 -0
- package/dist/bin.js +22 -0
- package/dist/bin.js.map +1 -0
- package/dist/build-info.d.ts +45 -0
- package/dist/build-info.d.ts.map +1 -0
- package/dist/build-info.js +319 -0
- package/dist/build-info.js.map +1 -0
- package/dist/cli.d.ts +25 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +363 -0
- package/dist/cli.js.map +1 -0
- package/dist/erc7201.d.ts +72 -0
- package/dist/erc7201.d.ts.map +1 -0
- package/dist/erc7201.js +340 -0
- package/dist/erc7201.js.map +1 -0
- package/dist/errors.d.ts +5 -0
- package/dist/errors.d.ts.map +1 -1
- package/dist/errors.js +8 -0
- package/dist/errors.js.map +1 -1
- package/dist/explorer.js +2 -2
- package/dist/explorer.js.map +1 -1
- package/dist/index.d.ts +3 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -1
- package/dist/index.js.map +1 -1
- package/dist/reconstruct.d.ts +51 -3
- package/dist/reconstruct.d.ts.map +1 -1
- package/dist/reconstruct.js +37 -8
- package/dist/reconstruct.js.map +1 -1
- package/dist/report.d.ts +26 -0
- package/dist/report.d.ts.map +1 -0
- package/dist/report.js +109 -0
- package/dist/report.js.map +1 -0
- package/dist/resolve.d.ts +11 -0
- package/dist/resolve.d.ts.map +1 -1
- package/dist/resolve.js +11 -1
- package/dist/resolve.js.map +1 -1
- package/package.json +6 -3
- package/src/bin.ts +25 -0
- package/src/build-info.ts +405 -0
- package/src/cli.ts +423 -0
- package/src/erc7201.ts +412 -0
- package/src/errors.ts +9 -0
- package/src/explorer.ts +2 -2
- package/src/index.ts +18 -1
- package/src/reconstruct.ts +111 -10
- package/src/report.ts +155 -0
- package/src/resolve.ts +17 -2
package/dist/cli.js
ADDED
|
@@ -0,0 +1,363 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `slotdiff <old> <new>`: each side is a contract in the project's build info
|
|
3
|
+
* or an address: a proxy (read as the implementation it runs now) or an
|
|
4
|
+
* implementation.
|
|
5
|
+
*
|
|
6
|
+
* Exit codes: 0 every check ran and passed (or was skipped with --no-safety),
|
|
7
|
+
* 1 a check failed, 2 something could not be checked. Failing to check is
|
|
8
|
+
* never reported as compatible.
|
|
9
|
+
*/
|
|
10
|
+
import { readFile } from "node:fs/promises";
|
|
11
|
+
import { relative, resolve } from "node:path";
|
|
12
|
+
import { parseArgs, styleText } from "node:util";
|
|
13
|
+
import { findBuildInfo } from "./build-info.js";
|
|
14
|
+
import { readCode, readProxy } from "./chain.js";
|
|
15
|
+
import { diffLayouts } from "./diff.js";
|
|
16
|
+
import { checkNamespaces } from "./erc7201.js";
|
|
17
|
+
import { checkLines, namespaceLines, plain } from "./report.js";
|
|
18
|
+
import { errorCode, LayoutUnavailableError } from "./errors.js";
|
|
19
|
+
import { canQueryExplorer } from "./explorer.js";
|
|
20
|
+
import { rebuild } from "./resolve.js";
|
|
21
|
+
import { analyzeSource, SAFETY_ERROR_KINDS, } from "./reconstruct.js";
|
|
22
|
+
import { getSolc } from "./solc.js";
|
|
23
|
+
const USAGE = `Usage: slotdiff <old> <new> [options]
|
|
24
|
+
|
|
25
|
+
Checks that <new> can replace <old> behind a proxy: OpenZeppelin's storage layout
|
|
26
|
+
rules, that each ERC-7201 namespace stays in the slot the code really uses, and
|
|
27
|
+
OpenZeppelin's safety rules for <new> (constructors, initializers, selfdestruct...).
|
|
28
|
+
Each side is either:
|
|
29
|
+
a contract in this project's build info src/Vault.sol:Vault, or Vault when unique
|
|
30
|
+
an address a proxy (the implementation it runs now),
|
|
31
|
+
or an implementation
|
|
32
|
+
|
|
33
|
+
Options:
|
|
34
|
+
--rpc <url> JSON-RPC endpoint, required when a side is an address
|
|
35
|
+
--root <dir> Project root (default: the current directory)
|
|
36
|
+
--build-info <file> Read local sides from this build-info file, as is
|
|
37
|
+
(not compared with the sources on disk)
|
|
38
|
+
--explorer-url <url> Another Etherscan-compatible API, such as Blockscout
|
|
39
|
+
--unsafe-allow-renames Accept renames without @custom:oz-renamed-from
|
|
40
|
+
--unsafe-allow <kinds> Comma-separated safety errors to accept, e.g. constructor;
|
|
41
|
+
prefer @custom:oz-upgrades-unsafe-allow in the source
|
|
42
|
+
--no-safety Skip the safety rules
|
|
43
|
+
-h, --help Show this help
|
|
44
|
+
-v, --version Show the version
|
|
45
|
+
|
|
46
|
+
An address needs verified source: set ETHERSCAN_API_KEY once (one key covers every
|
|
47
|
+
chain), or use --explorer-url, with that explorer's key in its query if it needs one
|
|
48
|
+
(ETHERSCAN_API_KEY is sent only to Etherscan). --rpc picks the chain for each run.
|
|
49
|
+
|
|
50
|
+
Exit codes: 0 every check passed (or was skipped with --no-safety), 1 a check
|
|
51
|
+
failed, 2 something could not be checked.
|
|
52
|
+
|
|
53
|
+
A pass means these checks found no problem, not that an upgrade is safe in every
|
|
54
|
+
way. No warranty; see LICENSE.`;
|
|
55
|
+
const HELP_HINT = "Run slotdiff --help for usage.";
|
|
56
|
+
// "slot" and "diff" in block letters, split where the two words meet.
|
|
57
|
+
const BANNER = [
|
|
58
|
+
[" _ _ ", " _ _ __ __"],
|
|
59
|
+
[" ___| | ___ | |_", " __| (_)/ _|/ _|"],
|
|
60
|
+
["/ __| |/ _ \\| __", "/ _` | | |_| |_"],
|
|
61
|
+
["\\__ \\ | (_) | |", "| (_| | | _| _|"],
|
|
62
|
+
["|___/_|\\___/ \\__", "\\__,_|_|_| |_|"],
|
|
63
|
+
];
|
|
64
|
+
const ADDRESS = /^0x[0-9a-fA-F]{40}$/;
|
|
65
|
+
/** Runs the CLI and resolves to its exit code. */
|
|
66
|
+
export async function run(argv, io) {
|
|
67
|
+
let parsed;
|
|
68
|
+
try {
|
|
69
|
+
parsed = parseArgs({
|
|
70
|
+
args: argv,
|
|
71
|
+
allowPositionals: true,
|
|
72
|
+
options: {
|
|
73
|
+
rpc: { type: "string" },
|
|
74
|
+
root: { type: "string" },
|
|
75
|
+
"build-info": { type: "string" },
|
|
76
|
+
"explorer-url": { type: "string" },
|
|
77
|
+
"unsafe-allow-renames": { type: "boolean" },
|
|
78
|
+
"unsafe-allow": { type: "string" },
|
|
79
|
+
"no-safety": { type: "boolean" },
|
|
80
|
+
help: { type: "boolean", short: "h" },
|
|
81
|
+
version: { type: "boolean", short: "v" },
|
|
82
|
+
},
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
catch (e) {
|
|
86
|
+
// Node's text for an unknown option runs on about `--`; the option is enough.
|
|
87
|
+
const message = e.message;
|
|
88
|
+
const unknown = /^Unknown option '([^']+)'/.exec(message)?.[1];
|
|
89
|
+
const text = unknown !== undefined ? `Unknown option ${unknown}` : message;
|
|
90
|
+
io.stderr(`${text.replace(/\.?$/, ".")} ${HELP_HINT}`);
|
|
91
|
+
return 2;
|
|
92
|
+
}
|
|
93
|
+
const { values, positionals } = parsed;
|
|
94
|
+
const paint = io.color
|
|
95
|
+
? (format, text) => styleText(format, text, { validateStream: false })
|
|
96
|
+
: plain;
|
|
97
|
+
// Only for a person at a terminal: never in a pipe, a log or CI.
|
|
98
|
+
const banner = async () => [
|
|
99
|
+
...BANNER.map(([slot, diff]) => paint("blueBright", slot) + paint("magenta", diff)),
|
|
100
|
+
` ${paint("dim", `storage layout diff for upgradeable contracts · ${await packageVersion()}`)}`,
|
|
101
|
+
].join("\n");
|
|
102
|
+
if (values.help) {
|
|
103
|
+
io.stdout(io.tty ? `${await banner()}\n\n${USAGE}` : USAGE);
|
|
104
|
+
return 0;
|
|
105
|
+
}
|
|
106
|
+
if (values.version) {
|
|
107
|
+
io.stdout(io.tty ? await banner() : await packageVersion());
|
|
108
|
+
return 0;
|
|
109
|
+
}
|
|
110
|
+
if (positionals.length !== 2) {
|
|
111
|
+
io.stderr(`Expected <old> and <new>, got ${positionals.length} argument(s). ${HELP_HINT}`);
|
|
112
|
+
return 2;
|
|
113
|
+
}
|
|
114
|
+
if (positionals.some((p) => p.includes("://"))) {
|
|
115
|
+
// Not echoed: an RPC URL usually carries an API key.
|
|
116
|
+
io.stderr("A side looks like a URL. Pass the endpoint with --rpc <url>.");
|
|
117
|
+
return 2;
|
|
118
|
+
}
|
|
119
|
+
const short = positionals.find((p) => /^0x[0-9a-fA-F]*$/.test(p) && !ADDRESS.test(p));
|
|
120
|
+
if (short !== undefined) {
|
|
121
|
+
io.stderr(`${short} is not an address: an address is 0x and 40 hex digits.`);
|
|
122
|
+
return 2;
|
|
123
|
+
}
|
|
124
|
+
const hasAddress = positionals.some((p) => ADDRESS.test(p));
|
|
125
|
+
if (values.rpc === undefined && hasAddress) {
|
|
126
|
+
io.stderr("An address needs --rpc <url>.");
|
|
127
|
+
return 2;
|
|
128
|
+
}
|
|
129
|
+
const safety = !values["no-safety"];
|
|
130
|
+
if (!safety && values["unsafe-allow"] !== undefined) {
|
|
131
|
+
io.stderr("--unsafe-allow does nothing with --no-safety.");
|
|
132
|
+
return 2;
|
|
133
|
+
}
|
|
134
|
+
const unsafeAllow = (values["unsafe-allow"]?.split(",") ?? [])
|
|
135
|
+
.map((k) => k.trim())
|
|
136
|
+
.filter((k) => k !== "");
|
|
137
|
+
const unknownKind = unsafeAllow.find((k) => !SAFETY_ERROR_KINDS.includes(k));
|
|
138
|
+
if (unknownKind !== undefined) {
|
|
139
|
+
io.stderr(`--unsafe-allow: unknown error kind "${unknownKind}". Known: ${SAFETY_ERROR_KINDS.join(", ")}.`);
|
|
140
|
+
return 2;
|
|
141
|
+
}
|
|
142
|
+
// Neither URL is ever echoed: endpoints often carry an API key.
|
|
143
|
+
let rpcUrl;
|
|
144
|
+
try {
|
|
145
|
+
rpcUrl = values.rpc !== undefined ? httpUrl(values.rpc, "--rpc") : undefined;
|
|
146
|
+
const explorerUrl = values["explorer-url"];
|
|
147
|
+
if (explorerUrl !== undefined && hasCredentials(httpUrl(explorerUrl, "--explorer-url"))) {
|
|
148
|
+
throw new Error("--explorer-url must not include a user name or password.");
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
catch (e) {
|
|
152
|
+
io.stderr(e.message);
|
|
153
|
+
return 2;
|
|
154
|
+
}
|
|
155
|
+
const cwd = io.cwd ?? process.cwd();
|
|
156
|
+
const root = resolve(cwd, values.root ?? ".");
|
|
157
|
+
const buildInfoFile = values["build-info"] !== undefined ? resolve(cwd, values["build-info"]) : undefined;
|
|
158
|
+
const env = io.env ?? process.env;
|
|
159
|
+
// The Etherscan key goes to Etherscan only, never to another explorer's URL.
|
|
160
|
+
const explorer = values["explorer-url"] !== undefined
|
|
161
|
+
? { apiUrl: values["explorer-url"] }
|
|
162
|
+
: { apiKey: env.ETHERSCAN_API_KEY };
|
|
163
|
+
const provider = rpcUrl !== undefined ? jsonRpcProvider(rpcUrl, io.fetch ?? fetch) : undefined;
|
|
164
|
+
if (io.tty)
|
|
165
|
+
io.stdout(`${await banner()}\n`);
|
|
166
|
+
const readSide = async (spec) => {
|
|
167
|
+
if (ADDRESS.test(spec)) {
|
|
168
|
+
// A proxy stands for what it runs now; any other address is an implementation.
|
|
169
|
+
const proxy = await readProxy(provider, spec);
|
|
170
|
+
const implementation = proxy?.implementation ?? spec.toLowerCase();
|
|
171
|
+
if (!canQueryExplorer(explorer)) {
|
|
172
|
+
await readCode(provider, implementation); // a wrong address is reported as such first
|
|
173
|
+
throw new Error(`${implementation} needs an explorer key to fetch its verified source: set ` +
|
|
174
|
+
"ETHERSCAN_API_KEY (or use --explorer-url for another explorer).");
|
|
175
|
+
}
|
|
176
|
+
const { record, analysis } = await rebuild(provider, implementation, { explorer });
|
|
177
|
+
return {
|
|
178
|
+
description: [
|
|
179
|
+
proxy === undefined
|
|
180
|
+
? `${implementation} (implementation)`
|
|
181
|
+
: `${spec.toLowerCase()} → implementation ${implementation}` +
|
|
182
|
+
(proxy.beacon !== undefined ? ` (via beacon ${proxy.beacon})` : ""),
|
|
183
|
+
`${record.contract} (verified source, ${record.bytecodeMatch} match)`,
|
|
184
|
+
],
|
|
185
|
+
kind: proxy?.beacon !== undefined ? "beacon" : analysis.kind,
|
|
186
|
+
analysis,
|
|
187
|
+
};
|
|
188
|
+
}
|
|
189
|
+
const build = await findBuildInfo(root, spec, { file: buildInfoFile });
|
|
190
|
+
const solc = await getSolc(build.solcVersion);
|
|
191
|
+
const analysis = await analyzeSource(build.input, solc, build.contract);
|
|
192
|
+
return {
|
|
193
|
+
description: [
|
|
194
|
+
build.contract,
|
|
195
|
+
relative(root, build.file) +
|
|
196
|
+
(buildInfoFile !== undefined ? " (as given, not compared with the sources on disk)" : ""),
|
|
197
|
+
],
|
|
198
|
+
kind: analysis.kind,
|
|
199
|
+
analysis,
|
|
200
|
+
};
|
|
201
|
+
};
|
|
202
|
+
let old;
|
|
203
|
+
let next;
|
|
204
|
+
try {
|
|
205
|
+
old = await readSide(positionals[0]);
|
|
206
|
+
// The same side twice (e.g. a proxy against itself) is fetched and compiled once.
|
|
207
|
+
next = positionals[1] === positionals[0] ? old : await readSide(positionals[1]);
|
|
208
|
+
}
|
|
209
|
+
catch (e) {
|
|
210
|
+
io.stderr(`Could not check: ${e.message}`);
|
|
211
|
+
return 2;
|
|
212
|
+
}
|
|
213
|
+
for (const [label, side] of [
|
|
214
|
+
["old", old],
|
|
215
|
+
["new", next],
|
|
216
|
+
]) {
|
|
217
|
+
io.stdout(`${paint("bold", label)} ${side.description[0]}\n ${paint("dim", side.description[1])}`);
|
|
218
|
+
}
|
|
219
|
+
// OpenZeppelin matches namespaces by annotation; slotdiff pairs them by the
|
|
220
|
+
// slot the code uses, and OpenZeppelin then compares the structs of each pair.
|
|
221
|
+
const namespaces = checkNamespaces(old.analysis, next.analysis);
|
|
222
|
+
const grid = namespaceLines(namespaces.pairs, paint);
|
|
223
|
+
if (grid.length > 0)
|
|
224
|
+
io.stdout(`\n${grid.join("\n")}`);
|
|
225
|
+
const report = diffLayouts(namespaces.layout, next.analysis.layout, {
|
|
226
|
+
unsafeAllowRenames: values["unsafe-allow-renames"],
|
|
227
|
+
});
|
|
228
|
+
const renames = values["unsafe-allow-renames"] ? " (renames accepted)" : "";
|
|
229
|
+
const checks = [
|
|
230
|
+
report.ok
|
|
231
|
+
? { name: "Storage layout", status: "pass", summary: `compatible${renames}` }
|
|
232
|
+
: {
|
|
233
|
+
name: "Storage layout",
|
|
234
|
+
status: "fail",
|
|
235
|
+
summary: `incompatible${renames}`,
|
|
236
|
+
details: report.explain(),
|
|
237
|
+
},
|
|
238
|
+
];
|
|
239
|
+
if (namespaces.pairs.length > 0) {
|
|
240
|
+
checks.push({
|
|
241
|
+
name: "ERC-7201 slots",
|
|
242
|
+
...(namespaces.result === "fail"
|
|
243
|
+
? { status: "fail", summary: "problems found in <new> (see above)" }
|
|
244
|
+
: namespaces.result === "unread"
|
|
245
|
+
? { status: "skip", summary: "not checked: some slots could not be read (see above)" }
|
|
246
|
+
: grid.length > 0
|
|
247
|
+
? { status: "pass", summary: "compared by the slot in code (see above)" }
|
|
248
|
+
: { status: "pass", summary: "match their annotations" }),
|
|
249
|
+
});
|
|
250
|
+
}
|
|
251
|
+
// The kind comes from <old>, the proxy being upgraded: inferring it from <new>
|
|
252
|
+
// would miss a UUPS implementation that lost its upgrade function.
|
|
253
|
+
const accepted = unsafeAllow.length > 0 ? `; accepted: ${unsafeAllow.join(", ")}` : "";
|
|
254
|
+
const safetyCheck = safety ? next.analysis.safety({ kind: old.kind, unsafeAllow }) : undefined;
|
|
255
|
+
checks.push(safetyCheck === undefined
|
|
256
|
+
? { name: "Safety rules", status: "skip", summary: "skipped (--no-safety)" }
|
|
257
|
+
: safetyCheck.ok
|
|
258
|
+
? {
|
|
259
|
+
name: "Safety rules",
|
|
260
|
+
status: "pass",
|
|
261
|
+
summary: `no problems found (${old.kind} proxy${accepted})`,
|
|
262
|
+
}
|
|
263
|
+
: {
|
|
264
|
+
name: "Safety rules",
|
|
265
|
+
status: "fail",
|
|
266
|
+
summary: `problems found (${old.kind} proxy${accepted})`,
|
|
267
|
+
details: safetyCheck.explain(),
|
|
268
|
+
});
|
|
269
|
+
io.stdout(`\n${checkLines(checks, paint).join("\n")}`);
|
|
270
|
+
// One verdict, so a passing check next to a failing one is never read as safe.
|
|
271
|
+
const problems = [
|
|
272
|
+
...(report.ok ? [] : ["the storage layout is incompatible"]),
|
|
273
|
+
...(namespaces.result === "fail" ? ["an ERC-7201 namespace fails the slot check"] : []),
|
|
274
|
+
...(safetyCheck?.ok === false ? ["<new> breaks the safety rules"] : []),
|
|
275
|
+
];
|
|
276
|
+
if (problems.length > 0) {
|
|
277
|
+
io.stdout(`\n${paint(["bold", "red"], "Not safe to upgrade:")} ${problems.join(" and ")}.`);
|
|
278
|
+
return 1;
|
|
279
|
+
}
|
|
280
|
+
if (namespaces.result === "unread") {
|
|
281
|
+
io.stdout(`\n${paint(["bold", "yellow"], "Could not check:")} some ERC-7201 slots could not be read.`);
|
|
282
|
+
return 2;
|
|
283
|
+
}
|
|
284
|
+
io.stdout(safetyCheck === undefined
|
|
285
|
+
? `\n${paint("yellow", "Storage layout compatible; safety rules not checked (--no-safety).")}`
|
|
286
|
+
: `\n${paint(["bold", "green"], "Safe to upgrade.")}`);
|
|
287
|
+
return 0;
|
|
288
|
+
}
|
|
289
|
+
function httpUrl(value, flag) {
|
|
290
|
+
let url;
|
|
291
|
+
try {
|
|
292
|
+
url = new URL(value);
|
|
293
|
+
}
|
|
294
|
+
catch {
|
|
295
|
+
throw new Error(`${flag} is not a valid URL; it needs a scheme, such as https://.`);
|
|
296
|
+
}
|
|
297
|
+
if (url.protocol !== "http:" && url.protocol !== "https:") {
|
|
298
|
+
throw new Error(`${flag} must be an http or https URL.`);
|
|
299
|
+
}
|
|
300
|
+
return url;
|
|
301
|
+
}
|
|
302
|
+
function hasCredentials(url) {
|
|
303
|
+
return url.username !== "" || url.password !== "";
|
|
304
|
+
}
|
|
305
|
+
/**
|
|
306
|
+
* A minimal JSON-RPC client. Errors never include the URL: endpoints often
|
|
307
|
+
* carry an API key in the path or query. Credentials in the URL, which fetch
|
|
308
|
+
* refuses, are sent as basic auth instead.
|
|
309
|
+
*/
|
|
310
|
+
function jsonRpcProvider(url, fetchImpl) {
|
|
311
|
+
const headers = { "content-type": "application/json" };
|
|
312
|
+
if (hasCredentials(url)) {
|
|
313
|
+
const user = `${decodeURIComponent(url.username)}:${decodeURIComponent(url.password)}`;
|
|
314
|
+
headers.authorization = `Basic ${Buffer.from(user).toString("base64")}`;
|
|
315
|
+
url = new URL(url);
|
|
316
|
+
url.username = "";
|
|
317
|
+
url.password = "";
|
|
318
|
+
}
|
|
319
|
+
const endpoint = url.href;
|
|
320
|
+
let id = 0;
|
|
321
|
+
return {
|
|
322
|
+
async send(method, params) {
|
|
323
|
+
let response;
|
|
324
|
+
try {
|
|
325
|
+
response = await fetchImpl(endpoint, {
|
|
326
|
+
method: "POST",
|
|
327
|
+
headers,
|
|
328
|
+
body: JSON.stringify({ jsonrpc: "2.0", id: ++id, method, params }),
|
|
329
|
+
});
|
|
330
|
+
}
|
|
331
|
+
catch (e) {
|
|
332
|
+
throw new LayoutUnavailableError(`Cannot reach the RPC endpoint (${errorCode(e)}).`);
|
|
333
|
+
}
|
|
334
|
+
if (!response.ok) {
|
|
335
|
+
throw new LayoutUnavailableError(`The RPC endpoint answered HTTP ${response.status}.`);
|
|
336
|
+
}
|
|
337
|
+
let body;
|
|
338
|
+
try {
|
|
339
|
+
body = (await response.json());
|
|
340
|
+
}
|
|
341
|
+
catch {
|
|
342
|
+
body = {};
|
|
343
|
+
}
|
|
344
|
+
if (typeof body !== "object" || body === null || !("result" in body || "error" in body)) {
|
|
345
|
+
throw new LayoutUnavailableError(`The RPC endpoint did not answer JSON-RPC.`);
|
|
346
|
+
}
|
|
347
|
+
if (body.error !== undefined) {
|
|
348
|
+
// The server's text, without control characters (terminal escapes) and capped.
|
|
349
|
+
const message = String(body.error.message ?? "unknown error")
|
|
350
|
+
// eslint-disable-next-line no-control-regex
|
|
351
|
+
.replace(/[\u0000-\u001f\u007f-\u009f]/g, " ")
|
|
352
|
+
.slice(0, 300);
|
|
353
|
+
throw new Error(`RPC ${method} failed: ${message}`);
|
|
354
|
+
}
|
|
355
|
+
return body.result;
|
|
356
|
+
},
|
|
357
|
+
};
|
|
358
|
+
}
|
|
359
|
+
async function packageVersion() {
|
|
360
|
+
const pkg = JSON.parse(await readFile(new URL("../package.json", import.meta.url), "utf8"));
|
|
361
|
+
return pkg.version;
|
|
362
|
+
}
|
|
363
|
+
//# sourceMappingURL=cli.js.map
|
package/dist/cli.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ERC-7201 namespaces by the slot the code really uses.
|
|
3
|
+
*
|
|
4
|
+
* OpenZeppelin matches namespaces by their `@custom:storage-location
|
|
5
|
+
* erc7201:<id>` annotation and never checks the `bytes32` slot the code assigns
|
|
6
|
+
* (`assembly { $.slot := LOCATION }`). The two can disagree. A changed
|
|
7
|
+
* constant behind an unchanged annotation moves the storage while the layout
|
|
8
|
+
* check passes; a corrected annotation over an unchanged constant leaves the
|
|
9
|
+
* storage in place while the check reports a deleted namespace. Reading the
|
|
10
|
+
* slot from the AST catches the first and fixes the second.
|
|
11
|
+
*/
|
|
12
|
+
import type { SolcOutput, StorageLayout } from "@openzeppelin/upgrades-core";
|
|
13
|
+
export interface NamespaceSlot {
|
|
14
|
+
/** `erc7201:<id>`, as annotated. */
|
|
15
|
+
namespace: string;
|
|
16
|
+
/** The slot the annotation implies. */
|
|
17
|
+
expected: string;
|
|
18
|
+
/** The slot the code assigns, when it could be read and is unique. */
|
|
19
|
+
actual?: string;
|
|
20
|
+
/**
|
|
21
|
+
* `match`: the code uses the annotated slot. `mismatch`: it uses `actual`
|
|
22
|
+
* instead. `conflict`: it assigns different slots in different places.
|
|
23
|
+
* `unread`: no assignment was found, or one could not be evaluated.
|
|
24
|
+
*/
|
|
25
|
+
status: "match" | "mismatch" | "conflict" | "unread";
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* How each of `namespaces` (`erc7201:<id>` keys of `contract`'s layout,
|
|
29
|
+
* `source.sol:Name`) is assigned in `output`. Only structs declared in the
|
|
30
|
+
* contract or its bases count, as for OpenZeppelin: a sibling contract in the
|
|
31
|
+
* same build (a V1 next to its V2, a test copy) may declare the same id.
|
|
32
|
+
*/
|
|
33
|
+
export declare function namespaceSlots(output: SolcOutput, contract: string, namespaces: string[]): NamespaceSlot[];
|
|
34
|
+
export interface NamespacePair {
|
|
35
|
+
old?: NamespaceSlot;
|
|
36
|
+
next?: NamespaceSlot;
|
|
37
|
+
/**
|
|
38
|
+
* Why this pair fails the check: `<new>` assigns several slots (`conflict`),
|
|
39
|
+
* leaves the old data behind (`moved`), or keeps the data in place under an
|
|
40
|
+
* annotation that does not match (`mismatch`). `unread`: a slot could not be
|
|
41
|
+
* read, so the pair could not be checked.
|
|
42
|
+
*/
|
|
43
|
+
problem?: "conflict" | "moved" | "mismatch" | "unread";
|
|
44
|
+
}
|
|
45
|
+
export interface NamespaceCheck {
|
|
46
|
+
/**
|
|
47
|
+
* `old`'s layout with each paired namespace under its name in `<new>`, for
|
|
48
|
+
* `diffLayouts`: OpenZeppelin then compares the structs of the same storage.
|
|
49
|
+
* An unpaired namespace keeps its name, so one that is really gone is still
|
|
50
|
+
* reported as deleted.
|
|
51
|
+
*/
|
|
52
|
+
layout: StorageLayout;
|
|
53
|
+
/** Every namespace of either side, old and new paired when they are the same storage. */
|
|
54
|
+
pairs: NamespacePair[];
|
|
55
|
+
/** `fail` when any pair has a problem other than `unread`; `unread` when a slot could not be read. */
|
|
56
|
+
result: "pass" | "fail" | "unread";
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Checks ERC-7201 namespaces by the slot the code uses, not the annotation
|
|
60
|
+
* OpenZeppelin goes by. An old and a new namespace are the same storage when
|
|
61
|
+
* the code uses the same slot (under the same annotation first), failing that
|
|
62
|
+
* when they share an annotation, and failing that when the new annotation
|
|
63
|
+
* names the slot where the old data is.
|
|
64
|
+
* Pass `layout` to `diffLayouts` in place of `old.layout`.
|
|
65
|
+
*/
|
|
66
|
+
export declare function checkNamespaces(old: {
|
|
67
|
+
layout: StorageLayout;
|
|
68
|
+
namespaces: NamespaceSlot[];
|
|
69
|
+
}, next: {
|
|
70
|
+
namespaces: NamespaceSlot[];
|
|
71
|
+
}): NamespaceCheck;
|
|
72
|
+
//# sourceMappingURL=erc7201.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"erc7201.d.ts","sourceRoot":"","sources":["../src/erc7201.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,aAAa,EAAE,MAAM,6BAA6B,CAAC;AAW7E,MAAM,WAAW,aAAa;IAC5B,oCAAoC;IACpC,SAAS,EAAE,MAAM,CAAC;IAClB,uCAAuC;IACvC,QAAQ,EAAE,MAAM,CAAC;IACjB,sEAAsE;IACtE,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB;;;;OAIG;IACH,MAAM,EAAE,OAAO,GAAG,UAAU,GAAG,UAAU,GAAG,QAAQ,CAAC;CACtD;AAQD;;;;;GAKG;AACH,wBAAgB,cAAc,CAC5B,MAAM,EAAE,UAAU,EAClB,QAAQ,EAAE,MAAM,EAChB,UAAU,EAAE,MAAM,EAAE,GACnB,aAAa,EAAE,CA6FjB;AAED,MAAM,WAAW,aAAa;IAC5B,GAAG,CAAC,EAAE,aAAa,CAAC;IACpB,IAAI,CAAC,EAAE,aAAa,CAAC;IACrB;;;;;OAKG;IACH,OAAO,CAAC,EAAE,UAAU,GAAG,OAAO,GAAG,UAAU,GAAG,QAAQ,CAAC;CACxD;AAED,MAAM,WAAW,cAAc;IAC7B;;;;;OAKG;IACH,MAAM,EAAE,aAAa,CAAC;IACtB,yFAAyF;IACzF,KAAK,EAAE,aAAa,EAAE,CAAC;IACvB,sGAAsG;IACtG,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,QAAQ,CAAC;CACpC;AAED;;;;;;;GAOG;AACH,wBAAgB,eAAe,CAC7B,GAAG,EAAE;IAAE,MAAM,EAAE,aAAa,CAAC;IAAC,UAAU,EAAE,aAAa,EAAE,CAAA;CAAE,EAC3D,IAAI,EAAE;IAAE,UAAU,EAAE,aAAa,EAAE,CAAA;CAAE,GACpC,cAAc,CAmDhB"}
|