slotdiff 0.0.0-stage → 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 +26 -0
- package/LICENSE +10 -0
- package/README.md +304 -2
- 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/bytecode.d.ts +46 -0
- package/dist/bytecode.d.ts.map +1 -0
- package/dist/bytecode.js +101 -0
- package/dist/bytecode.js.map +1 -0
- package/dist/chain.d.ts +20 -0
- package/dist/chain.d.ts.map +1 -0
- package/dist/chain.js +52 -0
- package/dist/chain.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/diff.d.ts +15 -0
- package/dist/diff.d.ts.map +1 -0
- package/dist/diff.js +11 -0
- package/dist/diff.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 +23 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +32 -0
- package/dist/errors.js.map +1 -0
- package/dist/explorer.d.ts +42 -0
- package/dist/explorer.d.ts.map +1 -0
- package/dist/explorer.js +131 -0
- package/dist/explorer.js.map +1 -0
- package/dist/index.d.ts +13 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +12 -0
- package/dist/index.js.map +1 -0
- package/dist/reconstruct.d.ts +75 -0
- package/dist/reconstruct.d.ts.map +1 -0
- package/dist/reconstruct.js +169 -0
- package/dist/reconstruct.js.map +1 -0
- package/dist/record.d.ts +48 -0
- package/dist/record.d.ts.map +1 -0
- package/dist/record.js +91 -0
- package/dist/record.js.map +1 -0
- 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 +65 -0
- package/dist/resolve.d.ts.map +1 -0
- package/dist/resolve.js +90 -0
- package/dist/resolve.js.map +1 -0
- package/dist/solc.d.ts +38 -0
- package/dist/solc.d.ts.map +1 -0
- package/dist/solc.js +194 -0
- package/dist/solc.js.map +1 -0
- package/package.json +73 -4
- package/src/bin.ts +25 -0
- package/src/build-info.ts +405 -0
- package/src/bytecode.ts +141 -0
- package/src/chain.ts +75 -0
- package/src/cli.ts +423 -0
- package/src/diff.ts +31 -0
- package/src/erc7201.ts +412 -0
- package/src/errors.ts +33 -0
- package/src/explorer.ts +190 -0
- package/src/index.ts +53 -0
- package/src/reconstruct.ts +329 -0
- package/src/record.ts +127 -0
- package/src/report.ts +155 -0
- package/src/resolve.ts +153 -0
- package/src/solc.ts +268 -0
|
@@ -0,0 +1,319 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Reads a project's own build info: Foundry, Hardhat 2 and Hardhat 3.
|
|
3
|
+
*
|
|
4
|
+
* The build is chosen by content, never by modification time or file count.
|
|
5
|
+
* Foundry keeps every build-info file it ever wrote, so after a few edits
|
|
6
|
+
* several hold the target, most of them describing older sources. Only a build
|
|
7
|
+
* whose sources still match the files on disk is used.
|
|
8
|
+
*/
|
|
9
|
+
import { readFile, readdir, stat } from "node:fs/promises";
|
|
10
|
+
import { isAbsolute, join, relative, resolve } from "node:path";
|
|
11
|
+
// Foundry, then Hardhat.
|
|
12
|
+
const DIRS = ["out/build-info", "artifacts/build-info"];
|
|
13
|
+
const NO_INPUT_HINT = " Foundry writes the compiler input only with `build_info = true` in foundry.toml or " +
|
|
14
|
+
"`forge build --build-info`.";
|
|
15
|
+
/**
|
|
16
|
+
* Finds `contract` in the build info under `root` and returns what a layout
|
|
17
|
+
* or a bytecode proof needs. `contract` is `path/File.sol:Name`, with the path
|
|
18
|
+
* as written in the project (Hardhat 3's `project/` prefix is optional), or a
|
|
19
|
+
* bare `Name` when only one contract has it.
|
|
20
|
+
*/
|
|
21
|
+
export async function findBuildInfo(root, contract, options = {}) {
|
|
22
|
+
const target = parseTarget(contract);
|
|
23
|
+
if (target.path !== undefined && isAbsolute(target.path)) {
|
|
24
|
+
target.path = relative(root, target.path);
|
|
25
|
+
}
|
|
26
|
+
if (options.file !== undefined) {
|
|
27
|
+
const file = resolve(root, options.file);
|
|
28
|
+
let text;
|
|
29
|
+
try {
|
|
30
|
+
text = await readFile(file, "utf8");
|
|
31
|
+
}
|
|
32
|
+
catch (e) {
|
|
33
|
+
throw new Error(`Cannot read ${options.file} (${e.code}).`, {
|
|
34
|
+
cause: e,
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
const info = await readBuildInfo(file, text);
|
|
38
|
+
if (info === undefined)
|
|
39
|
+
throw new Error(`${options.file} holds no compiler input.${NO_INPUT_HINT}`);
|
|
40
|
+
const matches = findContract(info, target);
|
|
41
|
+
if (matches.length === 0)
|
|
42
|
+
throw new Error(`${options.file} has no contract ${contract}.`);
|
|
43
|
+
if (matches.length > 1)
|
|
44
|
+
throw ambiguousName(contract, matches);
|
|
45
|
+
return toResult({ file, info, contract: matches[0] });
|
|
46
|
+
}
|
|
47
|
+
const files = await listBuildInfoFiles(root);
|
|
48
|
+
if (files.length === 0) {
|
|
49
|
+
const isDir = await stat(root).then((st) => st.isDirectory(), () => false);
|
|
50
|
+
if (!isDir)
|
|
51
|
+
throw new Error(`The project root ${root} is not a directory.`);
|
|
52
|
+
throw new Error(`No build info found in ${DIRS.join(" or ")} under ${root}. Run from the project root ` +
|
|
53
|
+
`(or pass its path as the root), after a build.${NO_INPUT_HINT}`);
|
|
54
|
+
}
|
|
55
|
+
const holding = [];
|
|
56
|
+
let withoutInput = false;
|
|
57
|
+
for (const file of files) {
|
|
58
|
+
// Cheap text check first: build-info files can be large, and most do not hold the target.
|
|
59
|
+
const text = await readFile(file, "utf8");
|
|
60
|
+
if (target.path !== undefined && !text.includes(`${target.path}"`))
|
|
61
|
+
continue;
|
|
62
|
+
const info = await readBuildInfo(file, text);
|
|
63
|
+
if (info === undefined) {
|
|
64
|
+
withoutInput = true;
|
|
65
|
+
continue;
|
|
66
|
+
}
|
|
67
|
+
for (const name of findContract(info, target))
|
|
68
|
+
holding.push({ file, info, contract: name });
|
|
69
|
+
}
|
|
70
|
+
if (holding.length === 0) {
|
|
71
|
+
throw new Error(`No build info holds ${contract}. ` +
|
|
72
|
+
(withoutInput
|
|
73
|
+
? `Some hold no compiler input.${NO_INPUT_HINT}`
|
|
74
|
+
: "Check the name (it is case-sensitive) and give the source path as the compiler " +
|
|
75
|
+
"saw it (for a remapped import, the path under lib/), or just the contract name. " +
|
|
76
|
+
"Or build first."));
|
|
77
|
+
}
|
|
78
|
+
// A build is fresh when the target's file exists and nothing it imports has changed.
|
|
79
|
+
const fresh = [];
|
|
80
|
+
const stale = [];
|
|
81
|
+
for (const candidate of holding) {
|
|
82
|
+
const disk = await checkDisk(root, candidate);
|
|
83
|
+
if (disk === "gone")
|
|
84
|
+
continue;
|
|
85
|
+
if (disk.fresh)
|
|
86
|
+
fresh.push(candidate);
|
|
87
|
+
else
|
|
88
|
+
stale.push({ candidate, target: disk.target });
|
|
89
|
+
}
|
|
90
|
+
// A bare name is ambiguous across every build that holds it, not only the
|
|
91
|
+
// fresh ones: an incremental build holds just the files it recompiled, so the
|
|
92
|
+
// freshest build can miss a second definition. A stale definition counts only
|
|
93
|
+
// while its file still declares the name (it may have been renamed since).
|
|
94
|
+
const name = target.name.replace(/\$/g, "\\$");
|
|
95
|
+
const declares = new RegExp(`\\b(?:contract|interface|library)\\s+${name}(?![\\w$])`);
|
|
96
|
+
const present = [
|
|
97
|
+
...fresh,
|
|
98
|
+
...stale
|
|
99
|
+
.filter(({ target }) => target === undefined || declares.test(target))
|
|
100
|
+
.map(({ candidate }) => candidate),
|
|
101
|
+
];
|
|
102
|
+
const names = [...new Set(present.map((c) => c.contract))];
|
|
103
|
+
if (names.length > 1)
|
|
104
|
+
throw ambiguousName(contract, names);
|
|
105
|
+
if (fresh.length === 0) {
|
|
106
|
+
throw new Error(stale.length > 0
|
|
107
|
+
? `Every build info holding ${contract} is older than the sources on disk. Build again.`
|
|
108
|
+
: `${contract} is no longer on disk (moved or deleted). Build again.`);
|
|
109
|
+
}
|
|
110
|
+
// Several fresh builds of the same sources are interchangeable only when the
|
|
111
|
+
// compiler and its settings agree (Foundry profiles can differ in both).
|
|
112
|
+
const byBuild = new Map();
|
|
113
|
+
for (const candidate of fresh.sort((a, b) => a.file.localeCompare(b.file))) {
|
|
114
|
+
const key = buildKey(candidate.info);
|
|
115
|
+
if (!byBuild.has(key))
|
|
116
|
+
byBuild.set(key, candidate);
|
|
117
|
+
}
|
|
118
|
+
if (byBuild.size > 1) {
|
|
119
|
+
const files = [...byBuild.values()].map((c) => relative(root, c.file));
|
|
120
|
+
throw new Error(`${contract} was built with different compilers or settings in ${files.join(", ")} ` +
|
|
121
|
+
`(a project with several solc versions compiles shared files once per version). ` +
|
|
122
|
+
`Pick one with the \`file\` option (\`--build-info\` on the command line); ` +
|
|
123
|
+
`\`forge clean\` drops leftover builds.`);
|
|
124
|
+
}
|
|
125
|
+
return toResult([...byBuild.values()][0]);
|
|
126
|
+
}
|
|
127
|
+
function parseTarget(contract) {
|
|
128
|
+
const colon = contract.lastIndexOf(":");
|
|
129
|
+
const name = contract.slice(colon + 1);
|
|
130
|
+
if (!/^[A-Za-z_$][\w$]*$/.test(name)) {
|
|
131
|
+
// Not quoted: a URL passed here by mistake can carry an API key.
|
|
132
|
+
throw new Error("Expected a contract name or `path/File.sol:Name`.");
|
|
133
|
+
}
|
|
134
|
+
if (colon === -1)
|
|
135
|
+
return { name };
|
|
136
|
+
const path = contract.slice(0, colon).replace(/^\.\//, "");
|
|
137
|
+
return { path: path.replace(/^project\//, ""), name };
|
|
138
|
+
}
|
|
139
|
+
async function listBuildInfoFiles(root) {
|
|
140
|
+
const files = [];
|
|
141
|
+
for (const dir of DIRS) {
|
|
142
|
+
let entries;
|
|
143
|
+
try {
|
|
144
|
+
entries = await readdir(resolve(root, dir));
|
|
145
|
+
}
|
|
146
|
+
catch (e) {
|
|
147
|
+
if (e.code === "ENOENT")
|
|
148
|
+
continue;
|
|
149
|
+
throw e;
|
|
150
|
+
}
|
|
151
|
+
for (const entry of entries.sort()) {
|
|
152
|
+
// Hardhat 3 keeps the compiler output next to the build info, in `<id>.output.json`.
|
|
153
|
+
if (entry.endsWith(".json") && !entry.endsWith(".output.json")) {
|
|
154
|
+
files.push(join(resolve(root, dir), entry));
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
return files;
|
|
159
|
+
}
|
|
160
|
+
/**
|
|
161
|
+
* Undefined for a file with no compiler input: Foundry writes one per build
|
|
162
|
+
* (only `id` and `source_id_to_path`) unless asked for full build info.
|
|
163
|
+
*/
|
|
164
|
+
async function readBuildInfo(file, text) {
|
|
165
|
+
let info;
|
|
166
|
+
try {
|
|
167
|
+
info = JSON.parse(text);
|
|
168
|
+
}
|
|
169
|
+
catch (e) {
|
|
170
|
+
throw new Error(`${file} is not JSON: ${e.message}`, { cause: e });
|
|
171
|
+
}
|
|
172
|
+
if (info?.input === undefined && info?.source_id_to_path !== undefined)
|
|
173
|
+
return undefined;
|
|
174
|
+
if (typeof info?.solcLongVersion !== "string" ||
|
|
175
|
+
typeof info.input?.sources !== "object" ||
|
|
176
|
+
info.input.sources === null) {
|
|
177
|
+
throw new Error(`${file} is not a build-info file (no solcLongVersion or input sources).`);
|
|
178
|
+
}
|
|
179
|
+
if (info.output === undefined) {
|
|
180
|
+
const outputFile = file.replace(/\.json$/, ".output.json");
|
|
181
|
+
try {
|
|
182
|
+
info.output = JSON.parse(await readFile(outputFile, "utf8")).output;
|
|
183
|
+
}
|
|
184
|
+
catch (e) {
|
|
185
|
+
if (e.code !== "ENOENT") {
|
|
186
|
+
throw new Error(`Cannot read ${outputFile}: ${e.message}`, { cause: e });
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
return info;
|
|
191
|
+
}
|
|
192
|
+
// Fully qualified names in `info` that match the target.
|
|
193
|
+
function findContract(info, target) {
|
|
194
|
+
const sources = Object.keys(info.input.sources);
|
|
195
|
+
if (target.path !== undefined) {
|
|
196
|
+
const path = target.path;
|
|
197
|
+
const source = sources.find((s) => s === path || s === `project/${path}`);
|
|
198
|
+
if (source === undefined)
|
|
199
|
+
return [];
|
|
200
|
+
const compiled = info.output?.contracts?.[source];
|
|
201
|
+
// Without output the name cannot be checked here; solc checks it when the layout is built.
|
|
202
|
+
if (compiled !== undefined && !Object.hasOwn(compiled, target.name))
|
|
203
|
+
return [];
|
|
204
|
+
return [`${source}:${target.name}`];
|
|
205
|
+
}
|
|
206
|
+
if (info.output?.contracts === undefined)
|
|
207
|
+
return [];
|
|
208
|
+
return Object.entries(info.output.contracts)
|
|
209
|
+
.filter(([, contracts]) => Object.hasOwn(contracts, target.name))
|
|
210
|
+
.map(([source]) => `${source}:${target.name}`);
|
|
211
|
+
}
|
|
212
|
+
/**
|
|
213
|
+
* Compares the target and every source it imports, directly or not, with the
|
|
214
|
+
* disk. A changed base contract changes the target's layout; a changed
|
|
215
|
+
* unrelated file does not, and must not make a build stale: an incremental
|
|
216
|
+
* build holds only the files it recompiled, so the build that holds the target
|
|
217
|
+
* is often older than files the target never imports. `gone` when the target's
|
|
218
|
+
* file no longer exists; a dependency not found on disk (hoisted node_modules,
|
|
219
|
+
* say) is not checked. `target` is the target's text on disk, when found.
|
|
220
|
+
*/
|
|
221
|
+
async function checkDisk(root, { info, contract }) {
|
|
222
|
+
const targetSource = sourceOf(contract);
|
|
223
|
+
let target;
|
|
224
|
+
let fresh = true;
|
|
225
|
+
// The target comes first.
|
|
226
|
+
for (const source of dependencies(info, targetSource)) {
|
|
227
|
+
const onDisk = await readSource(root, info, source);
|
|
228
|
+
if (source === targetSource) {
|
|
229
|
+
if (onDisk === null)
|
|
230
|
+
return "gone";
|
|
231
|
+
target = onDisk;
|
|
232
|
+
}
|
|
233
|
+
const content = info.input.sources[source]?.content;
|
|
234
|
+
if (typeof onDisk === "string" && typeof content === "string" && onDisk !== content) {
|
|
235
|
+
fresh = false;
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
return { fresh, target };
|
|
239
|
+
}
|
|
240
|
+
/**
|
|
241
|
+
* `source` and everything it imports, from the import directives in the
|
|
242
|
+
* output's ASTs. Without them, every source in the build (the cautious answer).
|
|
243
|
+
*/
|
|
244
|
+
function dependencies(info, source) {
|
|
245
|
+
// The target first, as checkDisk expects.
|
|
246
|
+
const all = [source, ...Object.keys(info.input.sources).filter((s) => s !== source)];
|
|
247
|
+
const asts = info.output?.sources;
|
|
248
|
+
const seen = new Set([source]);
|
|
249
|
+
const queue = [source];
|
|
250
|
+
while (queue.length > 0) {
|
|
251
|
+
const nodes = asts?.[queue.pop()]?.ast?.nodes;
|
|
252
|
+
if (nodes === undefined)
|
|
253
|
+
return all;
|
|
254
|
+
for (const node of nodes) {
|
|
255
|
+
const imported = node.nodeType === "ImportDirective" ? node.absolutePath : undefined;
|
|
256
|
+
if (imported !== undefined && !seen.has(imported)) {
|
|
257
|
+
seen.add(imported);
|
|
258
|
+
queue.push(imported);
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
return [...seen];
|
|
263
|
+
}
|
|
264
|
+
/**
|
|
265
|
+
* The file on disk behind a build's source name: undefined when it cannot be
|
|
266
|
+
* located by name (Hardhat 3's versioned `npm/` paths), null when it should be
|
|
267
|
+
* there and is not.
|
|
268
|
+
*/
|
|
269
|
+
async function readSource(root, info, source) {
|
|
270
|
+
const user = Object.entries(info.userSourceNameMap ?? {}).find(([, s]) => s === source)?.[0];
|
|
271
|
+
if (user === undefined && source.startsWith("npm/"))
|
|
272
|
+
return undefined;
|
|
273
|
+
const names = user !== undefined
|
|
274
|
+
? [user]
|
|
275
|
+
: [source, ...(source.startsWith("project/") ? [source.slice("project/".length)] : [])];
|
|
276
|
+
const paths = names.flatMap((name) => [resolve(root, name), resolve(root, "node_modules", name)]);
|
|
277
|
+
return (await readFirst(paths)) ?? null;
|
|
278
|
+
}
|
|
279
|
+
async function readFirst(paths) {
|
|
280
|
+
for (const path of paths) {
|
|
281
|
+
try {
|
|
282
|
+
return await readFile(path, "utf8");
|
|
283
|
+
}
|
|
284
|
+
catch (e) {
|
|
285
|
+
const code = e.code;
|
|
286
|
+
if (code !== "ENOENT" && code !== "ENOTDIR")
|
|
287
|
+
throw e;
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
return undefined;
|
|
291
|
+
}
|
|
292
|
+
function buildKey(info) {
|
|
293
|
+
const settings = { ...info.input.settings };
|
|
294
|
+
delete settings.outputSelection;
|
|
295
|
+
return JSON.stringify([info.solcLongVersion, settings]);
|
|
296
|
+
}
|
|
297
|
+
function ambiguousName(contract, names) {
|
|
298
|
+
return new Error(`${contract} is ambiguous: ${names.join(", ")}. Use \`path/File.sol:Name\`.`);
|
|
299
|
+
}
|
|
300
|
+
function sourceOf(contract) {
|
|
301
|
+
return contract.slice(0, contract.lastIndexOf(":"));
|
|
302
|
+
}
|
|
303
|
+
function toResult({ file, info, contract }) {
|
|
304
|
+
const source = sourceOf(contract);
|
|
305
|
+
const deployed = info.output?.contracts?.[source]?.[contract.slice(source.length + 1)]?.evm?.deployedBytecode;
|
|
306
|
+
const sources = info.input.sources;
|
|
307
|
+
return {
|
|
308
|
+
file,
|
|
309
|
+
contract,
|
|
310
|
+
solcVersion: info.solcLongVersion,
|
|
311
|
+
input: {
|
|
312
|
+
...info.input,
|
|
313
|
+
sources: Object.fromEntries(dependencies(info, source).map((s) => [s, sources[s]])),
|
|
314
|
+
},
|
|
315
|
+
deployedBytecode: deployed?.object,
|
|
316
|
+
immutableReferences: deployed?.immutableReferences,
|
|
317
|
+
};
|
|
318
|
+
}
|
|
319
|
+
//# sourceMappingURL=build-info.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"build-info.js","sourceRoot":"","sources":["../src/build-info.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Bytecode comparison utilities.
|
|
3
|
+
*
|
|
4
|
+
* Solidity appends a CBOR-encoded metadata hash to the end of every compiled
|
|
5
|
+
* contract's bytecode. The last two bytes encode the length of that metadata
|
|
6
|
+
* section. Stripping it allows comparing contracts that are logically identical
|
|
7
|
+
* but were compiled in different environments (different metadata).
|
|
8
|
+
*/
|
|
9
|
+
export declare function stripBytecodeMetadata(bytecode: string): string;
|
|
10
|
+
/**
|
|
11
|
+
* solc's `evm.deployedBytecode.immutableReferences`: AST id to the byte spans
|
|
12
|
+
* (relative to the deployed bytecode) that the constructor fills in.
|
|
13
|
+
*/
|
|
14
|
+
export type ImmutableReferences = Record<string, ReadonlyArray<{
|
|
15
|
+
start: number;
|
|
16
|
+
length: number;
|
|
17
|
+
}>>;
|
|
18
|
+
/**
|
|
19
|
+
* - `exact`: byte-identical.
|
|
20
|
+
* - `immutables-only`: identical once immutable (and library-link) spans are
|
|
21
|
+
* masked. Same code, deployment-specific values. Every UUPS implementation
|
|
22
|
+
* lands here because `UUPSUpgradeable.__self` is immutable.
|
|
23
|
+
* - `metadata-only`: identical after masking and stripping the CBOR metadata,
|
|
24
|
+
* so the compiler input was not byte-identical (source hashes or settings).
|
|
25
|
+
* NOT proof of storage layout: variables no code reads, gap sizes and field
|
|
26
|
+
* names do not reach the bytecode, so different layouts can share code.
|
|
27
|
+
* - `code-only`: identical (exactly or once masked), but the build embeds no
|
|
28
|
+
* source hash (`bytecodeHash: "none"` or `appendCBOR: false`), so nothing
|
|
29
|
+
* ties the code to its source. NOT proof of layout, for the same reason.
|
|
30
|
+
* - `none`: different code.
|
|
31
|
+
*
|
|
32
|
+
* `exact` and `immutables-only` therefore always mean the source is proven too.
|
|
33
|
+
*/
|
|
34
|
+
export type DeployedBytecodeMatch = "exact" | "immutables-only" | "metadata-only" | "code-only" | "none";
|
|
35
|
+
/** The matches that prove a source is the deployed code, and so prove its layout. */
|
|
36
|
+
export type ProvingMatch = "exact" | "immutables-only";
|
|
37
|
+
export declare function isProvingMatch(match: DeployedBytecodeMatch): match is ProvingMatch;
|
|
38
|
+
/**
|
|
39
|
+
* Compares runtime code read with `eth_getCode` against compiler output.
|
|
40
|
+
*
|
|
41
|
+
* On-chain code has immutables filled in while compiler output has them
|
|
42
|
+
* zeroed, and the difference sits in the code body where metadata stripping
|
|
43
|
+
* cannot reach, so the spans are zeroed on both sides before comparing.
|
|
44
|
+
*/
|
|
45
|
+
export declare function compareDeployedBytecode(onchain: string, compiled: string, immutableReferences?: ImmutableReferences): DeployedBytecodeMatch;
|
|
46
|
+
//# sourceMappingURL=bytecode.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bytecode.d.ts","sourceRoot":"","sources":["../src/bytecode.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,wBAAgB,qBAAqB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAK9D;AA8CD;;;GAGG;AACH,MAAM,MAAM,mBAAmB,GAAG,MAAM,CAAC,MAAM,EAAE,aAAa,CAAC;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC,CAAC,CAAC;AAEnG;;;;;;;;;;;;;;;GAeG;AACH,MAAM,MAAM,qBAAqB,GAC/B,OAAO,GAAG,iBAAiB,GAAG,eAAe,GAAG,WAAW,GAAG,MAAM,CAAC;AAEvE,qFAAqF;AACrF,MAAM,MAAM,YAAY,GAAG,OAAO,GAAG,iBAAiB,CAAC;AAEvD,wBAAgB,cAAc,CAAC,KAAK,EAAE,qBAAqB,GAAG,KAAK,IAAI,YAAY,CAElF;AAKD;;;;;;GAMG;AACH,wBAAgB,uBAAuB,CACrC,OAAO,EAAE,MAAM,EACf,QAAQ,EAAE,MAAM,EAChB,mBAAmB,GAAE,mBAAwB,GAC5C,qBAAqB,CAoBvB"}
|
package/dist/bytecode.js
ADDED
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Bytecode comparison utilities.
|
|
3
|
+
*
|
|
4
|
+
* Solidity appends a CBOR-encoded metadata hash to the end of every compiled
|
|
5
|
+
* contract's bytecode. The last two bytes encode the length of that metadata
|
|
6
|
+
* section. Stripping it allows comparing contracts that are logically identical
|
|
7
|
+
* but were compiled in different environments (different metadata).
|
|
8
|
+
*/
|
|
9
|
+
export function stripBytecodeMetadata(bytecode) {
|
|
10
|
+
const buf = toBuffer(bytecode);
|
|
11
|
+
const start = cborStart(buf);
|
|
12
|
+
if (start === undefined)
|
|
13
|
+
return bytecode;
|
|
14
|
+
return "0x" + buf.subarray(0, start).toString("hex");
|
|
15
|
+
}
|
|
16
|
+
function toBuffer(bytecode) {
|
|
17
|
+
return Buffer.from(bytecode.startsWith("0x") ? bytecode.slice(2) : bytecode, "hex");
|
|
18
|
+
}
|
|
19
|
+
// Where solc's CBOR metadata starts, or undefined when the tail is not CBOR.
|
|
20
|
+
function cborStart(buf) {
|
|
21
|
+
if (buf.length < 2)
|
|
22
|
+
return undefined;
|
|
23
|
+
const metadataLength = buf.readUInt16BE(buf.length - 2);
|
|
24
|
+
if (metadataLength === 0 || metadataLength + 2 > buf.length)
|
|
25
|
+
return undefined;
|
|
26
|
+
// solc's metadata is a CBOR map (major type 5). Without that marker the
|
|
27
|
+
// tail is code (e.g. compiled with appendCBOR: false), and stripping it
|
|
28
|
+
// would hide real differences.
|
|
29
|
+
const start = buf.length - 2 - metadataLength;
|
|
30
|
+
return buf[start] >> 5 === 5 ? start : undefined;
|
|
31
|
+
}
|
|
32
|
+
// The CBOR keys solc uses for the metadata hash, each with its byte-string header.
|
|
33
|
+
const SOURCE_HASH_KEYS = [
|
|
34
|
+
Buffer.from("6469706673" + "5822", "hex"), // "ipfs", 34 bytes
|
|
35
|
+
Buffer.from("65627a7a7230" + "5820", "hex"), // "bzzr0", 32 bytes
|
|
36
|
+
Buffer.from("65627a7a7231" + "5820", "hex"), // "bzzr1", 32 bytes
|
|
37
|
+
];
|
|
38
|
+
/**
|
|
39
|
+
* Whether compiled code embeds the hash of its metadata, which covers every
|
|
40
|
+
* source file and the settings. Only then does matching code also mean
|
|
41
|
+
* matching source. `bytecodeHash: "none"` and `appendCBOR: false` drop it.
|
|
42
|
+
*/
|
|
43
|
+
function hasSourceHash(bytecode) {
|
|
44
|
+
const buf = toBuffer(bytecode);
|
|
45
|
+
const start = cborStart(buf);
|
|
46
|
+
if (start === undefined)
|
|
47
|
+
return false;
|
|
48
|
+
const cbor = buf.subarray(start, buf.length - 2);
|
|
49
|
+
return SOURCE_HASH_KEYS.some((key) => cbor.includes(key));
|
|
50
|
+
}
|
|
51
|
+
function normalize(s) {
|
|
52
|
+
return s.toLowerCase().replace(/^0x/, "");
|
|
53
|
+
}
|
|
54
|
+
export function isProvingMatch(match) {
|
|
55
|
+
return match === "exact" || match === "immutables-only";
|
|
56
|
+
}
|
|
57
|
+
// solc leaves `__$<34 hex>$__` (20 bytes) where an external library address is linked.
|
|
58
|
+
const LINK_PLACEHOLDER = /__\$[0-9a-fA-F]{34}\$__/g;
|
|
59
|
+
/**
|
|
60
|
+
* Compares runtime code read with `eth_getCode` against compiler output.
|
|
61
|
+
*
|
|
62
|
+
* On-chain code has immutables filled in while compiler output has them
|
|
63
|
+
* zeroed, and the difference sits in the code body where metadata stripping
|
|
64
|
+
* cannot reach, so the spans are zeroed on both sides before comparing.
|
|
65
|
+
*/
|
|
66
|
+
export function compareDeployedBytecode(onchain, compiled, immutableReferences = {}) {
|
|
67
|
+
const live = normalize(onchain);
|
|
68
|
+
const built = normalize(compiled);
|
|
69
|
+
if (live === "" || built === "")
|
|
70
|
+
return "none";
|
|
71
|
+
if (live === built)
|
|
72
|
+
return hasSourceHash(built) ? "exact" : "code-only";
|
|
73
|
+
const spans = Object.values(immutableReferences).flat();
|
|
74
|
+
for (const m of built.matchAll(LINK_PLACEHOLDER)) {
|
|
75
|
+
spans.push({ start: m.index / 2, length: 20 });
|
|
76
|
+
}
|
|
77
|
+
const builtHex = built.replace(LINK_PLACEHOLDER, "0".repeat(40));
|
|
78
|
+
const liveMasked = maskSpans(live, spans);
|
|
79
|
+
const builtMasked = maskSpans(builtHex, spans);
|
|
80
|
+
if (liveMasked === undefined || builtMasked === undefined)
|
|
81
|
+
return "none";
|
|
82
|
+
if (liveMasked === builtMasked)
|
|
83
|
+
return hasSourceHash(builtHex) ? "immutables-only" : "code-only";
|
|
84
|
+
if (stripBytecodeMetadata(liveMasked) === stripBytecodeMetadata(builtMasked)) {
|
|
85
|
+
return "metadata-only";
|
|
86
|
+
}
|
|
87
|
+
return "none";
|
|
88
|
+
}
|
|
89
|
+
// Returns undefined when the hex is malformed or a span falls outside the code.
|
|
90
|
+
function maskSpans(hex, spans) {
|
|
91
|
+
const buf = Buffer.from(hex, "hex");
|
|
92
|
+
if (buf.length * 2 !== hex.length)
|
|
93
|
+
return undefined;
|
|
94
|
+
for (const { start, length } of spans) {
|
|
95
|
+
if (start + length > buf.length)
|
|
96
|
+
return undefined;
|
|
97
|
+
buf.fill(0, start, start + length);
|
|
98
|
+
}
|
|
99
|
+
return buf.toString("hex");
|
|
100
|
+
}
|
|
101
|
+
//# sourceMappingURL=bytecode.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bytecode.js","sourceRoot":"","sources":["../src/bytecode.ts"],"names":[],"mappings":"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"}
|
package/dist/chain.d.ts
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/** The one JSON-RPC method used; Hardhat's network provider and ethers' JsonRpcProvider both fit. */
|
|
2
|
+
export interface EthProvider {
|
|
3
|
+
send(method: string, params: unknown[]): Promise<unknown>;
|
|
4
|
+
}
|
|
5
|
+
export interface ProxyState {
|
|
6
|
+
implementation: string;
|
|
7
|
+
/** Set for a beacon proxy; `implementation` is then the beacon's. */
|
|
8
|
+
beacon?: string;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Reads what a proxy runs right now: the ERC-1967 implementation slot, or the
|
|
12
|
+
* beacon's implementation for a beacon proxy. Undefined when neither slot is
|
|
13
|
+
* set, i.e. the address is not a proxy this tool understands.
|
|
14
|
+
*/
|
|
15
|
+
export declare function readProxy(provider: EthProvider, address: string): Promise<ProxyState | undefined>;
|
|
16
|
+
export declare function readImplementation(provider: EthProvider, proxy: string): Promise<string>;
|
|
17
|
+
export declare function readCode(provider: EthProvider, address: string): Promise<string>;
|
|
18
|
+
export declare function readChainId(provider: EthProvider): Promise<number>;
|
|
19
|
+
export declare function codeSha256(code: string): string;
|
|
20
|
+
//# sourceMappingURL=chain.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"chain.d.ts","sourceRoot":"","sources":["../src/chain.ts"],"names":[],"mappings":"AAWA,qGAAqG;AACrG,MAAM,WAAW,WAAW;IAC1B,IAAI,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;CAC3D;AAED,MAAM,WAAW,UAAU;IACzB,cAAc,EAAE,MAAM,CAAC;IACvB,qEAAqE;IACrE,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED;;;;GAIG;AACH,wBAAsB,SAAS,CAC7B,QAAQ,EAAE,WAAW,EACrB,OAAO,EAAE,MAAM,GACd,OAAO,CAAC,UAAU,GAAG,SAAS,CAAC,CAgBjC;AAED,wBAAsB,kBAAkB,CAAC,QAAQ,EAAE,WAAW,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAQ9F;AAED,wBAAsB,QAAQ,CAAC,QAAQ,EAAE,WAAW,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAMtF;AAED,wBAAsB,WAAW,CAAC,QAAQ,EAAE,WAAW,GAAG,OAAO,CAAC,MAAM,CAAC,CAExE;AAED,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAI/C"}
|
package/dist/chain.js
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { EIP1967BeaconNotFound, EIP1967ImplementationNotFound, getBeaconAddress, getImplementationAddress, getImplementationAddressFromBeacon, } from "@openzeppelin/upgrades-core";
|
|
2
|
+
import { createHash } from "node:crypto";
|
|
3
|
+
import { LayoutUnavailableError } from "./errors.js";
|
|
4
|
+
/**
|
|
5
|
+
* Reads what a proxy runs right now: the ERC-1967 implementation slot, or the
|
|
6
|
+
* beacon's implementation for a beacon proxy. Undefined when neither slot is
|
|
7
|
+
* set, i.e. the address is not a proxy this tool understands.
|
|
8
|
+
*/
|
|
9
|
+
export async function readProxy(provider, address) {
|
|
10
|
+
const oz = provider;
|
|
11
|
+
try {
|
|
12
|
+
return { implementation: (await getImplementationAddress(oz, address)).toLowerCase() };
|
|
13
|
+
}
|
|
14
|
+
catch (e) {
|
|
15
|
+
if (!(e instanceof EIP1967ImplementationNotFound))
|
|
16
|
+
throw e;
|
|
17
|
+
}
|
|
18
|
+
let beacon;
|
|
19
|
+
try {
|
|
20
|
+
beacon = (await getBeaconAddress(oz, address)).toLowerCase();
|
|
21
|
+
}
|
|
22
|
+
catch (e) {
|
|
23
|
+
if (e instanceof EIP1967BeaconNotFound)
|
|
24
|
+
return undefined;
|
|
25
|
+
throw e;
|
|
26
|
+
}
|
|
27
|
+
const implementation = (await getImplementationAddressFromBeacon(oz, beacon)).toLowerCase();
|
|
28
|
+
return { implementation, beacon };
|
|
29
|
+
}
|
|
30
|
+
export async function readImplementation(provider, proxy) {
|
|
31
|
+
const state = await readProxy(provider, proxy);
|
|
32
|
+
if (state === undefined) {
|
|
33
|
+
throw new LayoutUnavailableError(`${proxy} has no ERC-1967 implementation or beacon slot set on this chain.`);
|
|
34
|
+
}
|
|
35
|
+
return state.implementation;
|
|
36
|
+
}
|
|
37
|
+
export async function readCode(provider, address) {
|
|
38
|
+
const code = (await provider.send("eth_getCode", [address, "latest"]));
|
|
39
|
+
if (code === "0x" || code === "") {
|
|
40
|
+
throw new LayoutUnavailableError(`No code at ${address} on this chain.`);
|
|
41
|
+
}
|
|
42
|
+
return code.toLowerCase();
|
|
43
|
+
}
|
|
44
|
+
export async function readChainId(provider) {
|
|
45
|
+
return Number(BigInt((await provider.send("eth_chainId", []))));
|
|
46
|
+
}
|
|
47
|
+
export function codeSha256(code) {
|
|
48
|
+
return createHash("sha256")
|
|
49
|
+
.update(Buffer.from(code.replace(/^0x/, ""), "hex"))
|
|
50
|
+
.digest("hex");
|
|
51
|
+
}
|
|
52
|
+
//# sourceMappingURL=chain.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"chain.js","sourceRoot":"","sources":["../src/chain.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,qBAAqB,EACrB,6BAA6B,EAC7B,gBAAgB,EAChB,wBAAwB,EACxB,kCAAkC,GAEnC,MAAM,6BAA6B,CAAC;AACrC,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,sBAAsB,EAAE,MAAM,aAAa,CAAC;AAarD;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,SAAS,CAC7B,QAAqB,EACrB,OAAe;IAEf,MAAM,EAAE,GAAG,QAAuC,CAAC;IACnD,IAAI,CAAC;QACH,OAAO,EAAE,cAAc,EAAE,CAAC,MAAM,wBAAwB,CAAC,EAAE,EAAE,OAAO,CAAC,CAAC,CAAC,WAAW,EAAE,EAAE,CAAC;IACzF,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC;QACX,IAAI,CAAC,CAAC,CAAC,YAAY,6BAA6B,CAAC;YAAE,MAAM,CAAC,CAAC;IAC7D,CAAC;IACD,IAAI,MAAc,CAAC;IACnB,IAAI,CAAC;QACH,MAAM,GAAG,CAAC,MAAM,gBAAgB,CAAC,EAAE,EAAE,OAAO,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC;IAC/D,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC;QACX,IAAI,CAAC,YAAY,qBAAqB;YAAE,OAAO,SAAS,CAAC;QACzD,MAAM,CAAC,CAAC;IACV,CAAC;IACD,MAAM,cAAc,GAAG,CAAC,MAAM,kCAAkC,CAAC,EAAE,EAAE,MAAM,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC;IAC5F,OAAO,EAAE,cAAc,EAAE,MAAM,EAAE,CAAC;AACpC,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,kBAAkB,CAAC,QAAqB,EAAE,KAAa;IAC3E,MAAM,KAAK,GAAG,MAAM,SAAS,CAAC,QAAQ,EAAE,KAAK,CAAC,CAAC;IAC/C,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;QACxB,MAAM,IAAI,sBAAsB,CAC9B,GAAG,KAAK,mEAAmE,CAC5E,CAAC;IACJ,CAAC;IACD,OAAO,KAAK,CAAC,cAAc,CAAC;AAC9B,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,QAAQ,CAAC,QAAqB,EAAE,OAAe;IACnE,MAAM,IAAI,GAAG,CAAC,MAAM,QAAQ,CAAC,IAAI,CAAC,aAAa,EAAE,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC,CAAW,CAAC;IACjF,IAAI,IAAI,KAAK,IAAI,IAAI,IAAI,KAAK,EAAE,EAAE,CAAC;QACjC,MAAM,IAAI,sBAAsB,CAAC,cAAc,OAAO,iBAAiB,CAAC,CAAC;IAC3E,CAAC;IACD,OAAO,IAAI,CAAC,WAAW,EAAE,CAAC;AAC5B,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,WAAW,CAAC,QAAqB;IACrD,OAAO,MAAM,CAAC,MAAM,CAAC,CAAC,MAAM,QAAQ,CAAC,IAAI,CAAC,aAAa,EAAE,EAAE,CAAC,CAAW,CAAC,CAAC,CAAC;AAC5E,CAAC;AAED,MAAM,UAAU,UAAU,CAAC,IAAY;IACrC,OAAO,UAAU,CAAC,QAAQ,CAAC;SACxB,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,EAAE,KAAK,CAAC,CAAC;SACnD,MAAM,CAAC,KAAK,CAAC,CAAC;AACnB,CAAC"}
|
package/dist/cli.d.ts
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
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
|
+
type FetchLike = (url: string, init: RequestInit) => Promise<Response>;
|
|
11
|
+
export interface CliIo {
|
|
12
|
+
stdout: (line: string) => void;
|
|
13
|
+
stderr: (line: string) => void;
|
|
14
|
+
cwd?: string;
|
|
15
|
+
env?: Record<string, string | undefined>;
|
|
16
|
+
fetch?: FetchLike;
|
|
17
|
+
/** stdout is an interactive terminal: show the banner. */
|
|
18
|
+
tty?: boolean;
|
|
19
|
+
/** stdout takes colors (Node's rules: a terminal, `NO_COLOR`, `FORCE_COLOR`). */
|
|
20
|
+
color?: boolean;
|
|
21
|
+
}
|
|
22
|
+
/** Runs the CLI and resolves to its exit code. */
|
|
23
|
+
export declare function run(argv: string[], io: CliIo): Promise<number>;
|
|
24
|
+
export {};
|
|
25
|
+
//# sourceMappingURL=cli.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAoEH,KAAK,SAAS,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,WAAW,KAAK,OAAO,CAAC,QAAQ,CAAC,CAAC;AAEvE,MAAM,WAAW,KAAK;IACpB,MAAM,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IAC/B,MAAM,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IAC/B,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,GAAG,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAC;IACzC,KAAK,CAAC,EAAE,SAAS,CAAC;IAClB,0DAA0D;IAC1D,GAAG,CAAC,EAAE,OAAO,CAAC;IACd,iFAAiF;IACjF,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB;AAUD,kDAAkD;AAClD,wBAAsB,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,KAAK,GAAG,OAAO,CAAC,MAAM,CAAC,CAsPpE"}
|