slotdiff 0.1.0-alpha.1 → 0.3.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.
Files changed (65) hide show
  1. package/CHANGELOG.md +50 -9
  2. package/README.md +219 -111
  3. package/dist/bin.d.ts +3 -0
  4. package/dist/bin.d.ts.map +1 -0
  5. package/dist/bin.js +22 -0
  6. package/dist/bin.js.map +1 -0
  7. package/dist/build-info.d.ts +45 -0
  8. package/dist/build-info.d.ts.map +1 -0
  9. package/dist/build-info.js +319 -0
  10. package/dist/build-info.js.map +1 -0
  11. package/dist/cli.d.ts +25 -0
  12. package/dist/cli.d.ts.map +1 -0
  13. package/dist/cli.js +389 -0
  14. package/dist/cli.js.map +1 -0
  15. package/dist/erc7201.d.ts +88 -0
  16. package/dist/erc7201.d.ts.map +1 -0
  17. package/dist/erc7201.js +509 -0
  18. package/dist/erc7201.js.map +1 -0
  19. package/dist/errors.d.ts +19 -0
  20. package/dist/errors.d.ts.map +1 -1
  21. package/dist/errors.js +28 -0
  22. package/dist/errors.js.map +1 -1
  23. package/dist/explorer.d.ts.map +1 -1
  24. package/dist/explorer.js +29 -10
  25. package/dist/explorer.js.map +1 -1
  26. package/dist/index.d.ts +6 -3
  27. package/dist/index.d.ts.map +1 -1
  28. package/dist/index.js +5 -2
  29. package/dist/index.js.map +1 -1
  30. package/dist/reconstruct.d.ts +70 -7
  31. package/dist/reconstruct.d.ts.map +1 -1
  32. package/dist/reconstruct.js +157 -20
  33. package/dist/reconstruct.js.map +1 -1
  34. package/dist/record.d.ts +13 -0
  35. package/dist/record.d.ts.map +1 -1
  36. package/dist/record.js +8 -0
  37. package/dist/record.js.map +1 -1
  38. package/dist/report.d.ts +29 -0
  39. package/dist/report.d.ts.map +1 -0
  40. package/dist/report.js +138 -0
  41. package/dist/report.js.map +1 -0
  42. package/dist/resolve.d.ts +16 -0
  43. package/dist/resolve.d.ts.map +1 -1
  44. package/dist/resolve.js +17 -2
  45. package/dist/resolve.js.map +1 -1
  46. package/dist/solc.js +20 -4
  47. package/dist/solc.js.map +1 -1
  48. package/dist/upgrade.d.ts +48 -0
  49. package/dist/upgrade.d.ts.map +1 -0
  50. package/dist/upgrade.js +36 -0
  51. package/dist/upgrade.js.map +1 -0
  52. package/package.json +9 -6
  53. package/src/bin.ts +25 -0
  54. package/src/build-info.ts +405 -0
  55. package/src/cli.ts +459 -0
  56. package/src/erc7201.ts +603 -0
  57. package/src/errors.ts +31 -0
  58. package/src/explorer.ts +40 -11
  59. package/src/index.ts +28 -3
  60. package/src/reconstruct.ts +279 -29
  61. package/src/record.ts +18 -0
  62. package/src/report.ts +186 -0
  63. package/src/resolve.ts +28 -3
  64. package/src/solc.ts +20 -4
  65. package/src/upgrade.ts +91 -0
package/dist/cli.js ADDED
@@ -0,0 +1,389 @@
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 { checkLines, namespaceLines, plain, unassignedCount, } from "./report.js";
16
+ import { errorCode, LayoutUnavailableError, printable } from "./errors.js";
17
+ import { canQueryExplorer } from "./explorer.js";
18
+ import { rebuild } from "./resolve.js";
19
+ import { analyzeSource, SAFETY_ERROR_KINDS, } from "./reconstruct.js";
20
+ import { getSolc } from "./solc.js";
21
+ import { checkUpgrade } from "./upgrade.js";
22
+ const USAGE = `Usage: slotdiff <old> <new> [options]
23
+
24
+ Checks that <new> can replace <old> behind a proxy: OpenZeppelin's storage layout
25
+ rules, that each ERC-7201 namespace stays in the slot the code really uses, and
26
+ OpenZeppelin's safety rules for <new> (constructors, initializers, selfdestruct...).
27
+ Each side is either:
28
+ a contract in this project's build info src/Vault.sol:Vault, or Vault when unique
29
+ an address a proxy (the implementation it runs now),
30
+ or for <new>, an implementation
31
+
32
+ Options:
33
+ --rpc <url> JSON-RPC endpoint, required when a side is an address
34
+ --root <dir> Project root (default: the current directory)
35
+ --build-info <file> Read local sides from this build-info file, as is
36
+ (not compared with the sources on disk)
37
+ --explorer-url <url> Another Etherscan-compatible API, such as Blockscout
38
+ --unsafe-allow-renames Accept renames without @custom:oz-renamed-from
39
+ --unsafe-allow <kinds> Comma-separated safety errors to accept, e.g. constructor;
40
+ prefer @custom:oz-upgrades-unsafe-allow in the source
41
+ --no-safety Skip the safety rules
42
+ --old-implementation <old> is an implementation address, not a proxy; also
43
+ for a proxy slotdiff cannot read (pass its implementation)
44
+ -h, --help Show this help
45
+ -v, --version Show the version
46
+
47
+ An address needs verified source: set ETHERSCAN_API_KEY once (one key covers every
48
+ chain), or use --explorer-url, with that explorer's key in its query if it needs one
49
+ (ETHERSCAN_API_KEY is sent only to Etherscan). --rpc picks the chain for each run.
50
+
51
+ Exit codes: 0 every check passed (or was skipped with --no-safety), 1 a check
52
+ failed, 2 something could not be checked.
53
+
54
+ A pass means these checks found no problem, not that an upgrade is safe in every
55
+ way. No warranty; see LICENSE.`;
56
+ const HELP_HINT = "Run slotdiff --help for usage.";
57
+ // "slot" and "diff" in block letters, split where the two words meet.
58
+ const BANNER = [
59
+ [" _ _ ", " _ _ __ __"],
60
+ [" ___| | ___ | |_", " __| (_)/ _|/ _|"],
61
+ ["/ __| |/ _ \\| __", "/ _` | | |_| |_"],
62
+ ["\\__ \\ | (_) | |", "| (_| | | _| _|"],
63
+ ["|___/_|\\___/ \\__", "\\__,_|_|_| |_|"],
64
+ ];
65
+ const ADDRESS = /^0x[0-9a-fA-F]{40}$/;
66
+ /** Runs the CLI and resolves to its exit code. */
67
+ export async function run(argv, io) {
68
+ let parsed;
69
+ try {
70
+ parsed = parseArgs({
71
+ args: argv,
72
+ allowPositionals: true,
73
+ options: {
74
+ rpc: { type: "string" },
75
+ root: { type: "string" },
76
+ "build-info": { type: "string" },
77
+ "explorer-url": { type: "string" },
78
+ "unsafe-allow-renames": { type: "boolean" },
79
+ "unsafe-allow": { type: "string" },
80
+ "no-safety": { type: "boolean" },
81
+ "old-implementation": { type: "boolean" },
82
+ help: { type: "boolean", short: "h" },
83
+ version: { type: "boolean", short: "v" },
84
+ },
85
+ });
86
+ }
87
+ catch (e) {
88
+ // Node's text for an unknown option runs on about `--`; the option is enough.
89
+ const message = e.message;
90
+ const unknown = /^Unknown option '([^']+)'/.exec(message)?.[1];
91
+ const text = unknown !== undefined ? `Unknown option ${unknown}` : message;
92
+ io.stderr(`${text.replace(/\.?$/, ".")} ${HELP_HINT}`);
93
+ return 2;
94
+ }
95
+ const { values, positionals } = parsed;
96
+ const paint = io.color
97
+ ? (format, text) => styleText(format, text, { validateStream: false })
98
+ : plain;
99
+ // Only for a person at a terminal: never in a pipe, a log or CI.
100
+ const banner = async () => [
101
+ ...BANNER.map(([slot, diff]) => paint("blueBright", slot) + paint("magenta", diff)),
102
+ ` ${paint("dim", `storage layout diff for upgradeable contracts · ${await packageVersion()}`)}`,
103
+ ].join("\n");
104
+ if (values.help) {
105
+ io.stdout(io.tty ? `${await banner()}\n\n${USAGE}` : USAGE);
106
+ return 0;
107
+ }
108
+ if (values.version) {
109
+ io.stdout(io.tty ? await banner() : await packageVersion());
110
+ return 0;
111
+ }
112
+ if (positionals.length !== 2) {
113
+ io.stderr(`Expected <old> and <new>, got ${positionals.length} argument(s). ${HELP_HINT}`);
114
+ return 2;
115
+ }
116
+ if (positionals.some((p) => p.includes("://"))) {
117
+ // Not echoed: an RPC URL usually carries an API key.
118
+ io.stderr("A side looks like a URL. Pass the endpoint with --rpc <url>.");
119
+ return 2;
120
+ }
121
+ const short = positionals.find((p) => /^0x[0-9a-fA-F]*$/.test(p) && !ADDRESS.test(p));
122
+ if (short !== undefined) {
123
+ io.stderr(`${short} is not an address: an address is 0x and 40 hex digits.`);
124
+ return 2;
125
+ }
126
+ const hasAddress = positionals.some((p) => ADDRESS.test(p));
127
+ if (values.rpc === undefined && hasAddress) {
128
+ io.stderr("An address needs --rpc <url>.");
129
+ return 2;
130
+ }
131
+ const oldImplementation = values["old-implementation"] === true;
132
+ if (oldImplementation && !ADDRESS.test(positionals[0])) {
133
+ io.stderr("--old-implementation needs <old> to be an address.");
134
+ return 2;
135
+ }
136
+ const safety = !values["no-safety"];
137
+ if (!safety && values["unsafe-allow"] !== undefined) {
138
+ io.stderr("--unsafe-allow does nothing with --no-safety.");
139
+ return 2;
140
+ }
141
+ const unsafeAllow = (values["unsafe-allow"]?.split(",") ?? [])
142
+ .map((k) => k.trim())
143
+ .filter((k) => k !== "");
144
+ const unknownKind = unsafeAllow.find((k) => !SAFETY_ERROR_KINDS.includes(k));
145
+ if (unknownKind !== undefined) {
146
+ io.stderr(`--unsafe-allow: unknown error kind "${unknownKind}". Known: ${SAFETY_ERROR_KINDS.join(", ")}.`);
147
+ return 2;
148
+ }
149
+ // Neither URL is ever echoed: endpoints often carry an API key.
150
+ let rpcUrl;
151
+ try {
152
+ rpcUrl = values.rpc !== undefined ? httpUrl(values.rpc, "--rpc") : undefined;
153
+ const explorerUrl = values["explorer-url"];
154
+ if (explorerUrl !== undefined && hasCredentials(httpUrl(explorerUrl, "--explorer-url"))) {
155
+ throw new Error("--explorer-url must not include a user name or password.");
156
+ }
157
+ }
158
+ catch (e) {
159
+ io.stderr(e.message);
160
+ return 2;
161
+ }
162
+ const cwd = io.cwd ?? process.cwd();
163
+ const root = resolve(cwd, values.root ?? ".");
164
+ const buildInfoFile = values["build-info"] !== undefined ? resolve(cwd, values["build-info"]) : undefined;
165
+ const env = io.env ?? process.env;
166
+ // The Etherscan key goes to Etherscan only, never to another explorer's URL.
167
+ const explorer = values["explorer-url"] !== undefined
168
+ ? { apiUrl: values["explorer-url"] }
169
+ : { apiKey: env.ETHERSCAN_API_KEY };
170
+ const provider = rpcUrl !== undefined ? jsonRpcProvider(rpcUrl, io.fetch ?? fetch) : undefined;
171
+ if (io.tty)
172
+ io.stdout(`${await banner()}\n`);
173
+ const readSide = async (spec, side) => {
174
+ if (ADDRESS.test(spec)) {
175
+ // A proxy stands for what it runs now. <new> may be an implementation, but
176
+ // <old> only when said so: a proxy of a kind slotdiff cannot read (a
177
+ // diamond, a custom slot) would otherwise be compared as its own code.
178
+ const proxy = await readProxy(provider, spec);
179
+ if (side === "old" && (proxy === undefined) !== oldImplementation) {
180
+ // An address with no code is reported as such.
181
+ if (proxy === undefined)
182
+ await readCode(provider, spec);
183
+ throw new Error(proxy === undefined
184
+ ? `${spec.toLowerCase()} is not a proxy slotdiff can read (no ERC-1967 implementation ` +
185
+ "or beacon slot is set). If it is an implementation, or a proxy of another kind " +
186
+ "given by its implementation's address, pass --old-implementation."
187
+ : `${spec.toLowerCase()} is a proxy, not an implementation: drop --old-implementation.`);
188
+ }
189
+ const implementation = proxy?.implementation ?? spec.toLowerCase();
190
+ if (!canQueryExplorer(explorer)) {
191
+ await readCode(provider, implementation); // a wrong address is reported as such first
192
+ throw new Error(`${implementation} needs an explorer key to fetch its verified source: set ` +
193
+ "ETHERSCAN_API_KEY (or use --explorer-url for another explorer).");
194
+ }
195
+ const { record, analysis } = await rebuild(provider, implementation, { explorer });
196
+ return {
197
+ description: [
198
+ proxy === undefined
199
+ ? `${implementation} (implementation)`
200
+ : `${spec.toLowerCase()} → implementation ${implementation}` +
201
+ (proxy.beacon !== undefined ? ` (via beacon ${proxy.beacon})` : ""),
202
+ `${record.contract} (verified source, ${record.bytecodeMatch} match)`,
203
+ ],
204
+ kind: proxy?.beacon !== undefined ? "beacon" : analysis.kind,
205
+ analysis,
206
+ };
207
+ }
208
+ const build = await findBuildInfo(root, spec, { file: buildInfoFile });
209
+ const solc = await getSolc(build.solcVersion);
210
+ const analysis = await analyzeSource(build.input, solc, build.contract);
211
+ return {
212
+ description: [
213
+ build.contract,
214
+ relative(root, build.file) +
215
+ (buildInfoFile !== undefined ? " (as given, not compared with the sources on disk)" : ""),
216
+ ],
217
+ kind: analysis.kind,
218
+ analysis,
219
+ };
220
+ };
221
+ let old;
222
+ let next;
223
+ try {
224
+ old = await readSide(positionals[0], "old");
225
+ // The same side twice (e.g. a proxy against itself) is fetched and compiled once.
226
+ next = positionals[1] === positionals[0] ? old : await readSide(positionals[1], "new");
227
+ }
228
+ catch (e) {
229
+ // Messages can quote an explorer or verified source.
230
+ io.stderr(`Could not check: ${printable(e.message)}`);
231
+ return 2;
232
+ }
233
+ for (const [label, side] of [
234
+ ["old", old],
235
+ ["new", next],
236
+ ]) {
237
+ io.stdout(`${paint("bold", label)} ${side.description[0]}\n ${paint("dim", side.description[1])}`);
238
+ }
239
+ // The kind comes from <old>, the proxy being upgraded: inferring it from <new>
240
+ // would miss a UUPS implementation that lost its upgrade function.
241
+ const upgrade = checkUpgrade({ ...old.analysis, kind: old.kind }, next.analysis, {
242
+ unsafeAllowRenames: values["unsafe-allow-renames"],
243
+ unsafeAllow,
244
+ skipSafety: !safety,
245
+ });
246
+ const { layout: report, namespaces, safety: safetyCheck } = upgrade;
247
+ const grid = namespaceLines(namespaces.pairs, paint);
248
+ if (grid.length > 0)
249
+ io.stdout(`\n${grid.join("\n")}`);
250
+ const renames = values["unsafe-allow-renames"] ? " (renames accepted)" : "";
251
+ const checks = [
252
+ report.ok
253
+ ? { name: "Storage layout", status: "pass", summary: `compatible${renames}` }
254
+ : {
255
+ name: "Storage layout",
256
+ status: "fail",
257
+ summary: `incompatible${renames}`,
258
+ details: report.explain(),
259
+ },
260
+ ];
261
+ if (namespaces.pairs.length > 0) {
262
+ checks.push({
263
+ name: "ERC-7201 slots",
264
+ ...(namespaces.result === "fail"
265
+ ? { status: "fail", summary: "problems found in <new> (see above)" }
266
+ : namespaces.result === "unchecked"
267
+ ? { status: "skip", summary: "not checked: some slots could not be read (see above)" }
268
+ : {
269
+ status: "pass",
270
+ summary: (grid.length > 0
271
+ ? "compared by the slot in code (see above)"
272
+ : "match their annotations") + unassigned(unassignedCount(namespaces.pairs)),
273
+ }),
274
+ });
275
+ }
276
+ const accepted = unsafeAllow.length > 0 ? `; accepted: ${unsafeAllow.join(", ")}` : "";
277
+ checks.push(safetyCheck === undefined
278
+ ? { name: "Safety rules", status: "skip", summary: "skipped (--no-safety)" }
279
+ : safetyCheck.ok
280
+ ? {
281
+ name: "Safety rules",
282
+ status: "pass",
283
+ summary: `no problems found (${old.kind} proxy${accepted})`,
284
+ }
285
+ : {
286
+ name: "Safety rules",
287
+ status: "fail",
288
+ summary: `problems found (${old.kind} proxy${accepted})`,
289
+ details: safetyCheck.explain(),
290
+ });
291
+ io.stdout(`\n${checkLines(checks, paint).join("\n")}`);
292
+ // One verdict, so a passing check next to a failing one is never read as safe.
293
+ if (upgrade.result === "fail") {
294
+ const problems = [
295
+ ...(report.ok ? [] : ["the storage layout is incompatible"]),
296
+ ...(namespaces.result === "fail" ? ["an ERC-7201 namespace fails the slot check"] : []),
297
+ ...(safetyCheck?.ok === false ? ["<new> breaks the safety rules"] : []),
298
+ ];
299
+ io.stdout(`\n${paint(["bold", "red"], "Not safe to upgrade:")} ${problems.join(" and ")}.`);
300
+ return 1;
301
+ }
302
+ if (upgrade.result === "unchecked") {
303
+ io.stdout(`\n${paint(["bold", "yellow"], "Could not check:")} some ERC-7201 slots could not be read.`);
304
+ return 2;
305
+ }
306
+ io.stdout(safetyCheck === undefined
307
+ ? `\n${paint("yellow", "Storage layout compatible; safety rules not checked (--no-safety).")}`
308
+ : `\n${paint(["bold", "green"], "Safe to upgrade.")}`);
309
+ return 0;
310
+ }
311
+ function unassigned(count) {
312
+ if (count === 0)
313
+ return "";
314
+ return `; ${count} not assigned in code, compared by annotation`;
315
+ }
316
+ function httpUrl(value, flag) {
317
+ let url;
318
+ try {
319
+ url = new URL(value);
320
+ }
321
+ catch {
322
+ throw new Error(`${flag} is not a valid URL; it needs a scheme, such as https://.`);
323
+ }
324
+ if (url.protocol !== "http:" && url.protocol !== "https:") {
325
+ throw new Error(`${flag} must be an http or https URL.`);
326
+ }
327
+ return url;
328
+ }
329
+ function hasCredentials(url) {
330
+ return url.username !== "" || url.password !== "";
331
+ }
332
+ /**
333
+ * A minimal JSON-RPC client. Errors never include the URL: endpoints often
334
+ * carry an API key in the path or query. Credentials in the URL, which fetch
335
+ * refuses, are sent as basic auth instead.
336
+ */
337
+ function jsonRpcProvider(url, fetchImpl) {
338
+ const headers = { "content-type": "application/json" };
339
+ if (hasCredentials(url)) {
340
+ const user = `${decodeURIComponent(url.username)}:${decodeURIComponent(url.password)}`;
341
+ headers.authorization = `Basic ${Buffer.from(user).toString("base64")}`;
342
+ url = new URL(url);
343
+ url.username = "";
344
+ url.password = "";
345
+ }
346
+ const endpoint = url.href;
347
+ let id = 0;
348
+ return {
349
+ async send(method, params) {
350
+ let response;
351
+ try {
352
+ response = await fetchImpl(endpoint, {
353
+ method: "POST",
354
+ headers,
355
+ body: JSON.stringify({ jsonrpc: "2.0", id: ++id, method, params }),
356
+ });
357
+ }
358
+ catch (e) {
359
+ throw new LayoutUnavailableError(`Cannot reach the RPC endpoint (${errorCode(e)}).`);
360
+ }
361
+ if (!response.ok) {
362
+ throw new LayoutUnavailableError(`The RPC endpoint answered HTTP ${response.status}.`);
363
+ }
364
+ let body;
365
+ try {
366
+ body = (await response.json());
367
+ }
368
+ catch {
369
+ body = {};
370
+ }
371
+ if (typeof body !== "object" || body === null || !("result" in body || "error" in body)) {
372
+ throw new LayoutUnavailableError(`The RPC endpoint did not answer JSON-RPC.`);
373
+ }
374
+ if (body.error !== undefined) {
375
+ // The server's text, without control characters (terminal escapes) and capped.
376
+ const message = printable(String(body.error.message ?? "unknown error"))
377
+ .replace(/\s/g, " ")
378
+ .slice(0, 300);
379
+ throw new Error(`RPC ${method} failed: ${message}`);
380
+ }
381
+ return body.result;
382
+ },
383
+ };
384
+ }
385
+ async function packageVersion() {
386
+ const pkg = JSON.parse(await readFile(new URL("../package.json", import.meta.url), "utf8"));
387
+ return pkg.version;
388
+ }
389
+ //# sourceMappingURL=cli.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAC5C,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAC9C,OAAO,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AACjD,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAChD,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAoB,MAAM,YAAY,CAAC;AACnE,OAAO,EACL,UAAU,EACV,cAAc,EACd,KAAK,EACL,eAAe,GAGhB,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,SAAS,EAAE,sBAAsB,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAC3E,OAAO,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AACjD,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AACvC,OAAO,EACL,aAAa,EACb,kBAAkB,GAInB,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAE5C,MAAM,KAAK,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;+BAiCiB,CAAC;AAEhC,MAAM,SAAS,GAAG,gCAAgC,CAAC;AAEnD,sEAAsE;AACtE,MAAM,MAAM,GAA4B;IACtC,CAAC,kBAAkB,EAAE,iBAAiB,CAAC;IACvC,CAAC,kBAAkB,EAAE,kBAAkB,CAAC;IACxC,CAAC,mBAAmB,EAAE,iBAAiB,CAAC;IACxC,CAAC,mBAAmB,EAAE,mBAAmB,CAAC;IAC1C,CAAC,oBAAoB,EAAE,iBAAiB,CAAC;CAC1C,CAAC;AAEF,MAAM,OAAO,GAAG,qBAAqB,CAAC;AAwBtC,kDAAkD;AAClD,MAAM,CAAC,KAAK,UAAU,GAAG,CAAC,IAAc,EAAE,EAAS;IACjD,IAAI,MAAM,CAAC;IACX,IAAI,CAAC;QACH,MAAM,GAAG,SAAS,CAAC;YACjB,IAAI,EAAE,IAAI;YACV,gBAAgB,EAAE,IAAI;YACtB,OAAO,EAAE;gBACP,GAAG,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;gBACvB,IAAI,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;gBACxB,YAAY,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;gBAChC,cAAc,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;gBAClC,sBAAsB,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE;gBAC3C,cAAc,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;gBAClC,WAAW,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE;gBAChC,oBAAoB,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE;gBACzC,IAAI,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,KAAK,EAAE,GAAG,EAAE;gBACrC,OAAO,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,KAAK,EAAE,GAAG,EAAE;aACzC;SACF,CAAC,CAAC;IACL,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC;QACX,8EAA8E;QAC9E,MAAM,OAAO,GAAI,CAAW,CAAC,OAAO,CAAC;QACrC,MAAM,OAAO,GAAG,2BAA2B,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;QAC/D,MAAM,IAAI,GAAG,OAAO,KAAK,SAAS,CAAC,CAAC,CAAC,kBAAkB,OAAO,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC;QAC3E,EAAE,CAAC,MAAM,CAAC,GAAG,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,GAAG,CAAC,IAAI,SAAS,EAAE,CAAC,CAAC;QACvD,OAAO,CAAC,CAAC;IACX,CAAC;IACD,MAAM,EAAE,MAAM,EAAE,WAAW,EAAE,GAAG,MAAM,CAAC;IACvC,MAAM,KAAK,GAAU,EAAE,CAAC,KAAK;QAC3B,CAAC,CAAC,CAAC,MAAM,EAAE,IAAI,EAAE,EAAE,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,EAAE,cAAc,EAAE,KAAK,EAAE,CAAC;QACtE,CAAC,CAAC,KAAK,CAAC;IACV,iEAAiE;IACjE,MAAM,MAAM,GAAG,KAAK,IAAI,EAAE,CACxB;QACE,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,EAAE,IAAI,CAAC,EAAE,EAAE,CAAC,KAAK,CAAC,YAAY,EAAE,IAAI,CAAC,GAAG,KAAK,CAAC,SAAS,EAAE,IAAI,CAAC,CAAC;QACnF,IAAI,KAAK,CAAC,KAAK,EAAE,mDAAmD,MAAM,cAAc,EAAE,EAAE,CAAC,EAAE;KAChG,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACf,IAAI,MAAM,CAAC,IAAI,EAAE,CAAC;QAChB,EAAE,CAAC,MAAM,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,MAAM,MAAM,EAAE,OAAO,KAAK,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC;QAC5D,OAAO,CAAC,CAAC;IACX,CAAC;IACD,IAAI,MAAM,CAAC,OAAO,EAAE,CAAC;QACnB,EAAE,CAAC,MAAM,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,MAAM,MAAM,EAAE,CAAC,CAAC,CAAC,MAAM,cAAc,EAAE,CAAC,CAAC;QAC5D,OAAO,CAAC,CAAC;IACX,CAAC;IACD,IAAI,WAAW,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC7B,EAAE,CAAC,MAAM,CAAC,iCAAiC,WAAW,CAAC,MAAM,iBAAiB,SAAS,EAAE,CAAC,CAAC;QAC3F,OAAO,CAAC,CAAC;IACX,CAAC;IACD,IAAI,WAAW,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC;QAC/C,qDAAqD;QACrD,EAAE,CAAC,MAAM,CAAC,8DAA8D,CAAC,CAAC;QAC1E,OAAO,CAAC,CAAC;IACX,CAAC;IACD,MAAM,KAAK,GAAG,WAAW,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,kBAAkB,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;IACtF,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;QACxB,EAAE,CAAC,MAAM,CAAC,GAAG,KAAK,yDAAyD,CAAC,CAAC;QAC7E,OAAO,CAAC,CAAC;IACX,CAAC;IACD,MAAM,UAAU,GAAG,WAAW,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;IAC5D,IAAI,MAAM,CAAC,GAAG,KAAK,SAAS,IAAI,UAAU,EAAE,CAAC;QAC3C,EAAE,CAAC,MAAM,CAAC,+BAA+B,CAAC,CAAC;QAC3C,OAAO,CAAC,CAAC;IACX,CAAC;IAED,MAAM,iBAAiB,GAAG,MAAM,CAAC,oBAAoB,CAAC,KAAK,IAAI,CAAC;IAChE,IAAI,iBAAiB,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;QACvD,EAAE,CAAC,MAAM,CAAC,oDAAoD,CAAC,CAAC;QAChE,OAAO,CAAC,CAAC;IACX,CAAC;IAED,MAAM,MAAM,GAAG,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC;IACpC,IAAI,CAAC,MAAM,IAAI,MAAM,CAAC,cAAc,CAAC,KAAK,SAAS,EAAE,CAAC;QACpD,EAAE,CAAC,MAAM,CAAC,+CAA+C,CAAC,CAAC;QAC3D,OAAO,CAAC,CAAC;IACX,CAAC;IACD,MAAM,WAAW,GAAG,CAAC,MAAM,CAAC,cAAc,CAAC,EAAE,KAAK,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC;SAC3D,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;SACpB,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,KAAK,EAAE,CAAsB,CAAC;IAChD,MAAM,WAAW,GAAG,WAAW,CAAC,IAAI,CAClC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAE,kBAAwC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAC9D,CAAC;IACF,IAAI,WAAW,KAAK,SAAS,EAAE,CAAC;QAC9B,EAAE,CAAC,MAAM,CACP,uCAAuC,WAAW,aAAa,kBAAkB,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAChG,CAAC;QACF,OAAO,CAAC,CAAC;IACX,CAAC;IAED,gEAAgE;IAChE,IAAI,MAAuB,CAAC;IAC5B,IAAI,CAAC;QACH,MAAM,GAAG,MAAM,CAAC,GAAG,KAAK,SAAS,CAAC,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;QAC7E,MAAM,WAAW,GAAG,MAAM,CAAC,cAAc,CAAC,CAAC;QAC3C,IAAI,WAAW,KAAK,SAAS,IAAI,cAAc,CAAC,OAAO,CAAC,WAAW,EAAE,gBAAgB,CAAC,CAAC,EAAE,CAAC;YACxF,MAAM,IAAI,KAAK,CAAC,0DAA0D,CAAC,CAAC;QAC9E,CAAC;IACH,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC;QACX,EAAE,CAAC,MAAM,CAAE,CAAW,CAAC,OAAO,CAAC,CAAC;QAChC,OAAO,CAAC,CAAC;IACX,CAAC;IAED,MAAM,GAAG,GAAG,EAAE,CAAC,GAAG,IAAI,OAAO,CAAC,GAAG,EAAE,CAAC;IACpC,MAAM,IAAI,GAAG,OAAO,CAAC,GAAG,EAAE,MAAM,CAAC,IAAI,IAAI,GAAG,CAAC,CAAC;IAC9C,MAAM,aAAa,GACjB,MAAM,CAAC,YAAY,CAAC,KAAK,SAAS,CAAC,CAAC,CAAC,OAAO,CAAC,GAAG,EAAE,MAAM,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;IACtF,MAAM,GAAG,GAAG,EAAE,CAAC,GAAG,IAAI,OAAO,CAAC,GAAG,CAAC;IAClC,6EAA6E;IAC7E,MAAM,QAAQ,GACZ,MAAM,CAAC,cAAc,CAAC,KAAK,SAAS;QAClC,CAAC,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,cAAc,CAAC,EAAE;QACpC,CAAC,CAAC,EAAE,MAAM,EAAE,GAAG,CAAC,iBAAiB,EAAE,CAAC;IACxC,MAAM,QAAQ,GAAG,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,eAAe,CAAC,MAAM,EAAE,EAAE,CAAC,KAAK,IAAI,KAAK,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;IAE/F,IAAI,EAAE,CAAC,GAAG;QAAE,EAAE,CAAC,MAAM,CAAC,GAAG,MAAM,MAAM,EAAE,IAAI,CAAC,CAAC;IAE7C,MAAM,QAAQ,GAAG,KAAK,EAAE,IAAY,EAAE,IAAmB,EAAiB,EAAE;QAC1E,IAAI,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;YACvB,2EAA2E;YAC3E,qEAAqE;YACrE,uEAAuE;YACvE,MAAM,KAAK,GAAG,MAAM,SAAS,CAAC,QAAS,EAAE,IAAI,CAAC,CAAC;YAC/C,IAAI,IAAI,KAAK,KAAK,IAAI,CAAC,KAAK,KAAK,SAAS,CAAC,KAAK,iBAAiB,EAAE,CAAC;gBAClE,+CAA+C;gBAC/C,IAAI,KAAK,KAAK,SAAS;oBAAE,MAAM,QAAQ,CAAC,QAAS,EAAE,IAAI,CAAC,CAAC;gBACzD,MAAM,IAAI,KAAK,CACb,KAAK,KAAK,SAAS;oBACjB,CAAC,CAAC,GAAG,IAAI,CAAC,WAAW,EAAE,gEAAgE;wBACnF,iFAAiF;wBACjF,mEAAmE;oBACvE,CAAC,CAAC,GAAG,IAAI,CAAC,WAAW,EAAE,gEAAgE,CAC1F,CAAC;YACJ,CAAC;YACD,MAAM,cAAc,GAAG,KAAK,EAAE,cAAc,IAAI,IAAI,CAAC,WAAW,EAAE,CAAC;YACnE,IAAI,CAAC,gBAAgB,CAAC,QAAQ,CAAC,EAAE,CAAC;gBAChC,MAAM,QAAQ,CAAC,QAAS,EAAE,cAAc,CAAC,CAAC,CAAC,4CAA4C;gBACvF,MAAM,IAAI,KAAK,CACb,GAAG,cAAc,2DAA2D;oBAC1E,iEAAiE,CACpE,CAAC;YACJ,CAAC;YACD,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,GAAG,MAAM,OAAO,CAAC,QAAS,EAAE,cAAc,EAAE,EAAE,QAAQ,EAAE,CAAC,CAAC;YACpF,OAAO;gBACL,WAAW,EAAE;oBACX,KAAK,KAAK,SAAS;wBACjB,CAAC,CAAC,GAAG,cAAc,mBAAmB;wBACtC,CAAC,CAAC,GAAG,IAAI,CAAC,WAAW,EAAE,qBAAqB,cAAc,EAAE;4BAC1D,CAAC,KAAK,CAAC,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,gBAAgB,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC;oBACvE,GAAG,MAAM,CAAC,QAAQ,sBAAsB,MAAM,CAAC,aAAa,SAAS;iBACtE;gBACD,IAAI,EAAE,KAAK,EAAE,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,IAAI;gBAC5D,QAAQ;aACT,CAAC;QACJ,CAAC;QACD,MAAM,KAAK,GAAG,MAAM,aAAa,CAAC,IAAI,EAAE,IAAI,EAAE,EAAE,IAAI,EAAE,aAAa,EAAE,CAAC,CAAC;QACvE,MAAM,IAAI,GAAG,MAAM,OAAO,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC;QAC9C,MAAM,QAAQ,GAAG,MAAM,aAAa,CAAC,KAAK,CAAC,KAAK,EAAE,IAAI,EAAE,KAAK,CAAC,QAAQ,CAAC,CAAC;QACxE,OAAO;YACL,WAAW,EAAE;gBACX,KAAK,CAAC,QAAQ;gBACd,QAAQ,CAAC,IAAI,EAAE,KAAK,CAAC,IAAI,CAAC;oBACxB,CAAC,aAAa,KAAK,SAAS,CAAC,CAAC,CAAC,oDAAoD,CAAC,CAAC,CAAC,EAAE,CAAC;aAC5F;YACD,IAAI,EAAE,QAAQ,CAAC,IAAI;YACnB,QAAQ;SACT,CAAC;IACJ,CAAC,CAAC;IAEF,IAAI,GAAS,CAAC;IACd,IAAI,IAAU,CAAC;IACf,IAAI,CAAC;QACH,GAAG,GAAG,MAAM,QAAQ,CAAC,WAAW,CAAC,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC;QAC5C,kFAAkF;QAClF,IAAI,GAAG,WAAW,CAAC,CAAC,CAAC,KAAK,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,MAAM,QAAQ,CAAC,WAAW,CAAC,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC;IACzF,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC;QACX,qDAAqD;QACrD,EAAE,CAAC,MAAM,CAAC,oBAAoB,SAAS,CAAE,CAAW,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;QACjE,OAAO,CAAC,CAAC;IACX,CAAC;IAED,KAAK,MAAM,CAAC,KAAK,EAAE,IAAI,CAAC,IAAI;QAC1B,CAAC,KAAK,EAAE,GAAG,CAAC;QACZ,CAAC,KAAK,EAAE,IAAI,CAAC;KACL,EAAE,CAAC;QACX,EAAE,CAAC,MAAM,CACP,GAAG,KAAK,CAAC,MAAM,EAAE,KAAK,CAAC,KAAK,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC,UAAU,KAAK,CAAC,KAAK,EAAE,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,EAAE,CAC7F,CAAC;IACJ,CAAC;IAED,+EAA+E;IAC/E,mEAAmE;IACnE,MAAM,OAAO,GAAG,YAAY,CAAC,EAAE,GAAG,GAAG,CAAC,QAAQ,EAAE,IAAI,EAAE,GAAG,CAAC,IAAI,EAAE,EAAE,IAAI,CAAC,QAAQ,EAAE;QAC/E,kBAAkB,EAAE,MAAM,CAAC,sBAAsB,CAAC;QAClD,WAAW;QACX,UAAU,EAAE,CAAC,MAAM;KACpB,CAAC,CAAC;IACH,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,WAAW,EAAE,GAAG,OAAO,CAAC;IACpE,MAAM,IAAI,GAAG,cAAc,CAAC,UAAU,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC;IACrD,IAAI,IAAI,CAAC,MAAM,GAAG,CAAC;QAAE,EAAE,CAAC,MAAM,CAAC,KAAK,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IAEvD,MAAM,OAAO,GAAG,MAAM,CAAC,sBAAsB,CAAC,CAAC,CAAC,CAAC,qBAAqB,CAAC,CAAC,CAAC,EAAE,CAAC;IAC5E,MAAM,MAAM,GAAY;QACtB,MAAM,CAAC,EAAE;YACP,CAAC,CAAC,EAAE,IAAI,EAAE,gBAAgB,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,aAAa,OAAO,EAAE,EAAE;YAC7E,CAAC,CAAC;gBACE,IAAI,EAAE,gBAAgB;gBACtB,MAAM,EAAE,MAAM;gBACd,OAAO,EAAE,eAAe,OAAO,EAAE;gBACjC,OAAO,EAAE,MAAM,CAAC,OAAO,EAAE;aAC1B;KACN,CAAC;IAEF,IAAI,UAAU,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAChC,MAAM,CAAC,IAAI,CAAC;YACV,IAAI,EAAE,gBAAgB;YACtB,GAAG,CAAC,UAAU,CAAC,MAAM,KAAK,MAAM;gBAC9B,CAAC,CAAC,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,qCAAqC,EAAE;gBACpE,CAAC,CAAC,UAAU,CAAC,MAAM,KAAK,WAAW;oBACjC,CAAC,CAAC,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,uDAAuD,EAAE;oBACtF,CAAC,CAAC;wBACE,MAAM,EAAE,MAAM;wBACd,OAAO,EACL,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC;4BACd,CAAC,CAAC,0CAA0C;4BAC5C,CAAC,CAAC,yBAAyB,CAAC,GAAG,UAAU,CAAC,eAAe,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC;qBACjF,CAAC;SACT,CAAC,CAAC;IACL,CAAC;IAED,MAAM,QAAQ,GAAG,WAAW,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,eAAe,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;IACvF,MAAM,CAAC,IAAI,CACT,WAAW,KAAK,SAAS;QACvB,CAAC,CAAC,EAAE,IAAI,EAAE,cAAc,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,uBAAuB,EAAE;QAC5E,CAAC,CAAC,WAAW,CAAC,EAAE;YACd,CAAC,CAAC;gBACE,IAAI,EAAE,cAAc;gBACpB,MAAM,EAAE,MAAM;gBACd,OAAO,EAAE,sBAAsB,GAAG,CAAC,IAAI,SAAS,QAAQ,GAAG;aAC5D;YACH,CAAC,CAAC;gBACE,IAAI,EAAE,cAAc;gBACpB,MAAM,EAAE,MAAM;gBACd,OAAO,EAAE,mBAAmB,GAAG,CAAC,IAAI,SAAS,QAAQ,GAAG;gBACxD,OAAO,EAAE,WAAW,CAAC,OAAO,EAAE;aAC/B,CACR,CAAC;IACF,EAAE,CAAC,MAAM,CAAC,KAAK,UAAU,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IAEvD,+EAA+E;IAC/E,IAAI,OAAO,CAAC,MAAM,KAAK,MAAM,EAAE,CAAC;QAC9B,MAAM,QAAQ,GAAG;YACf,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,oCAAoC,CAAC,CAAC;YAC5D,GAAG,CAAC,UAAU,CAAC,MAAM,KAAK,MAAM,CAAC,CAAC,CAAC,CAAC,4CAA4C,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;YACvF,GAAG,CAAC,WAAW,EAAE,EAAE,KAAK,KAAK,CAAC,CAAC,CAAC,CAAC,+BAA+B,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;SACxE,CAAC;QACF,EAAE,CAAC,MAAM,CAAC,KAAK,KAAK,CAAC,CAAC,MAAM,EAAE,KAAK,CAAC,EAAE,sBAAsB,CAAC,IAAI,QAAQ,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;QAC5F,OAAO,CAAC,CAAC;IACX,CAAC;IACD,IAAI,OAAO,CAAC,MAAM,KAAK,WAAW,EAAE,CAAC;QACnC,EAAE,CAAC,MAAM,CACP,KAAK,KAAK,CAAC,CAAC,MAAM,EAAE,QAAQ,CAAC,EAAE,kBAAkB,CAAC,yCAAyC,CAC5F,CAAC;QACF,OAAO,CAAC,CAAC;IACX,CAAC;IACD,EAAE,CAAC,MAAM,CACP,WAAW,KAAK,SAAS;QACvB,CAAC,CAAC,KAAK,KAAK,CAAC,QAAQ,EAAE,oEAAoE,CAAC,EAAE;QAC9F,CAAC,CAAC,KAAK,KAAK,CAAC,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,kBAAkB,CAAC,EAAE,CACxD,CAAC;IACF,OAAO,CAAC,CAAC;AACX,CAAC;AAED,SAAS,UAAU,CAAC,KAAa;IAC/B,IAAI,KAAK,KAAK,CAAC;QAAE,OAAO,EAAE,CAAC;IAC3B,OAAO,KAAK,KAAK,+CAA+C,CAAC;AACnE,CAAC;AAED,SAAS,OAAO,CAAC,KAAa,EAAE,IAAY;IAC1C,IAAI,GAAQ,CAAC;IACb,IAAI,CAAC;QACH,GAAG,GAAG,IAAI,GAAG,CAAC,KAAK,CAAC,CAAC;IACvB,CAAC;IAAC,MAAM,CAAC;QACP,MAAM,IAAI,KAAK,CAAC,GAAG,IAAI,2DAA2D,CAAC,CAAC;IACtF,CAAC;IACD,IAAI,GAAG,CAAC,QAAQ,KAAK,OAAO,IAAI,GAAG,CAAC,QAAQ,KAAK,QAAQ,EAAE,CAAC;QAC1D,MAAM,IAAI,KAAK,CAAC,GAAG,IAAI,gCAAgC,CAAC,CAAC;IAC3D,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC;AAED,SAAS,cAAc,CAAC,GAAQ;IAC9B,OAAO,GAAG,CAAC,QAAQ,KAAK,EAAE,IAAI,GAAG,CAAC,QAAQ,KAAK,EAAE,CAAC;AACpD,CAAC;AAED;;;;GAIG;AACH,SAAS,eAAe,CAAC,GAAQ,EAAE,SAAoB;IACrD,MAAM,OAAO,GAA2B,EAAE,cAAc,EAAE,kBAAkB,EAAE,CAAC;IAC/E,IAAI,cAAc,CAAC,GAAG,CAAC,EAAE,CAAC;QACxB,MAAM,IAAI,GAAG,GAAG,kBAAkB,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI,kBAAkB,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC;QACvF,OAAO,CAAC,aAAa,GAAG,SAAS,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC,EAAE,CAAC;QACxE,GAAG,GAAG,IAAI,GAAG,CAAC,GAAG,CAAC,CAAC;QACnB,GAAG,CAAC,QAAQ,GAAG,EAAE,CAAC;QAClB,GAAG,CAAC,QAAQ,GAAG,EAAE,CAAC;IACpB,CAAC;IACD,MAAM,QAAQ,GAAG,GAAG,CAAC,IAAI,CAAC;IAC1B,IAAI,EAAE,GAAG,CAAC,CAAC;IACX,OAAO;QACL,KAAK,CAAC,IAAI,CAAC,MAAM,EAAE,MAAM;YACvB,IAAI,QAAkB,CAAC;YACvB,IAAI,CAAC;gBACH,QAAQ,GAAG,MAAM,SAAS,CAAC,QAAQ,EAAE;oBACnC,MAAM,EAAE,MAAM;oBACd,OAAO;oBACP,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,OAAO,EAAE,KAAK,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC;iBACnE,CAAC,CAAC;YACL,CAAC;YAAC,OAAO,CAAC,EAAE,CAAC;gBACX,MAAM,IAAI,sBAAsB,CAAC,kCAAkC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;YACvF,CAAC;YACD,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;gBACjB,MAAM,IAAI,sBAAsB,CAAC,kCAAkC,QAAQ,CAAC,MAAM,GAAG,CAAC,CAAC;YACzF,CAAC;YACD,IAAI,IAAwD,CAAC;YAC7D,IAAI,CAAC;gBACH,IAAI,GAAG,CAAC,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAgB,CAAC;YAChD,CAAC;YAAC,MAAM,CAAC;gBACP,IAAI,GAAG,EAAE,CAAC;YACZ,CAAC;YACD,IAAI,OAAO,IAAI,KAAK,QAAQ,IAAI,IAAI,KAAK,IAAI,IAAI,CAAC,CAAC,QAAQ,IAAI,IAAI,IAAI,OAAO,IAAI,IAAI,CAAC,EAAE,CAAC;gBACxF,MAAM,IAAI,sBAAsB,CAAC,2CAA2C,CAAC,CAAC;YAChF,CAAC;YACD,IAAI,IAAI,CAAC,KAAK,KAAK,SAAS,EAAE,CAAC;gBAC7B,+EAA+E;gBAC/E,MAAM,OAAO,GAAG,SAAS,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,OAAO,IAAI,eAAe,CAAC,CAAC;qBACrE,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC;qBACnB,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;gBACjB,MAAM,IAAI,KAAK,CAAC,OAAO,MAAM,YAAY,OAAO,EAAE,CAAC,CAAC;YACtD,CAAC;YACD,OAAO,IAAI,CAAC,MAAM,CAAC;QACrB,CAAC;KACF,CAAC;AACJ,CAAC;AAED,KAAK,UAAU,cAAc;IAC3B,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,QAAQ,CAAC,IAAI,GAAG,CAAC,iBAAiB,EAAE,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,MAAM,CAAC,CAEzF,CAAC;IACF,OAAO,GAAG,CAAC,OAAO,CAAC;AACrB,CAAC"}
@@ -0,0 +1,88 @@
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
+ * `unused`: no code assigns its slot (a namespace kept reserved).
24
+ * `unread`: an assignment could not be evaluated.
25
+ */
26
+ status: "match" | "mismatch" | "conflict" | "unused" | "unread";
27
+ }
28
+ /**
29
+ * How each of `namespaces` (`erc7201:<id>` keys of `contract`'s layout,
30
+ * `source.sol:Name`) is assigned in `output`. Only structs declared in the
31
+ * contract or its bases count, as for OpenZeppelin: a sibling contract in the
32
+ * same build (a V1 next to its V2, a test copy) may declare the same id.
33
+ */
34
+ export declare function namespaceSlots(output: SolcOutput, contract: string, namespaces: string[]): NamespaceSlot[];
35
+ export interface NamespacePair {
36
+ old?: NamespaceSlot;
37
+ next?: NamespaceSlot;
38
+ /**
39
+ * Why this pair fails the check: `<new>` assigns several slots (`conflict`),
40
+ * leaves the old data behind (`moved`), keeps the data in place under an
41
+ * annotation that does not match (`mismatch`), or stops assigning a namespace
42
+ * whose deployed annotation does not match its data (`dropped`). `unread`: a
43
+ * slot could not be read, so the pair could not be checked.
44
+ */
45
+ problem?: "conflict" | "moved" | "mismatch" | "dropped" | "unread";
46
+ }
47
+ export interface NamespaceCheck {
48
+ /**
49
+ * `old`'s layout with each paired namespace under its name in `<new>`, for
50
+ * `diffLayouts`: OpenZeppelin then compares the structs of the same storage.
51
+ * An unpaired namespace keeps its name, so one that is really gone is still
52
+ * reported as deleted.
53
+ */
54
+ layout: StorageLayout;
55
+ /** Every namespace of either side, old and new paired when they are the same storage. */
56
+ pairs: NamespacePair[];
57
+ /**
58
+ * `fail` when any pair has a problem other than `unread`; `unchecked` when a
59
+ * slot could not be read (a pair's problem is `unread`), as in `UpgradeCheck`.
60
+ */
61
+ result: "pass" | "fail" | "unchecked";
62
+ /** The CLI's namespace grid, with what each problem means; empty when nothing is worth showing. */
63
+ explain(color?: boolean): string;
64
+ }
65
+ /**
66
+ * Checks ERC-7201 namespaces by the slot the code uses, not the annotation
67
+ * OpenZeppelin goes by. An old and a new namespace are the same storage when
68
+ * the code uses the same slot (under the same annotation first), failing that
69
+ * when they share an annotation, and failing that when the new annotation
70
+ * names the slot where the old data is. A namespace of either layout missing
71
+ * from that side's `namespaces` (or all of them, when it is absent) is unread.
72
+ * Pass `layout` to `diffLayouts` in place of `old.layout`.
73
+ */
74
+ export declare function checkNamespaces(old: {
75
+ layout: StorageLayout;
76
+ namespaces?: NamespaceSlot[];
77
+ }, next: {
78
+ layout: StorageLayout;
79
+ namespaces?: NamespaceSlot[];
80
+ }): NamespaceCheck;
81
+ /**
82
+ * Why `namespaces` cannot be the slots of `layout`'s namespaces, or undefined
83
+ * when they can (or are absent). A slot for a namespace the layout lacks, or a
84
+ * second one for the same namespace, could take another's place when
85
+ * namespaces are paired, so either is refused. Internal, shared with records.
86
+ */
87
+ export declare function slotsMisfit(layout: StorageLayout, namespaces: unknown): string | undefined;
88
+ //# 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;AAc7E,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;;;;;OAKG;IACH,MAAM,EAAE,OAAO,GAAG,UAAU,GAAG,UAAU,GAAG,QAAQ,GAAG,QAAQ,CAAC;CACjE;AAQD;;;;;GAKG;AACH,wBAAgB,cAAc,CAC5B,MAAM,EAAE,UAAU,EAClB,QAAQ,EAAE,MAAM,EAChB,UAAU,EAAE,MAAM,EAAE,GACnB,aAAa,EAAE,CAoJjB;AAED,MAAM,WAAW,aAAa;IAC5B,GAAG,CAAC,EAAE,aAAa,CAAC;IACpB,IAAI,CAAC,EAAE,aAAa,CAAC;IACrB;;;;;;OAMG;IACH,OAAO,CAAC,EAAE,UAAU,GAAG,OAAO,GAAG,UAAU,GAAG,SAAS,GAAG,QAAQ,CAAC;CACpE;AAED,MAAM,WAAW,cAAc;IAC7B;;;;;OAKG;IACH,MAAM,EAAE,aAAa,CAAC;IACtB,yFAAyF;IACzF,KAAK,EAAE,aAAa,EAAE,CAAC;IACvB;;;OAGG;IACH,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,WAAW,CAAC;IACtC,mGAAmG;IACnG,OAAO,CAAC,KAAK,CAAC,EAAE,OAAO,GAAG,MAAM,CAAC;CAClC;AAED;;;;;;;;GAQG;AACH,wBAAgB,eAAe,CAC7B,GAAG,EAAE;IAAE,MAAM,EAAE,aAAa,CAAC;IAAC,UAAU,CAAC,EAAE,aAAa,EAAE,CAAA;CAAE,EAC5D,IAAI,EAAE;IAAE,MAAM,EAAE,aAAa,CAAC;IAAC,UAAU,CAAC,EAAE,aAAa,EAAE,CAAA;CAAE,GAC5D,cAAc,CAyDhB;AAoCD;;;;;GAKG;AACH,wBAAgB,WAAW,CAAC,MAAM,EAAE,aAAa,EAAE,UAAU,EAAE,OAAO,GAAG,MAAM,GAAG,SAAS,CAc1F"}