@polkadot-api/cli 0.0.1-0a3edb2e805b29fa7d3ebb02c2084a125c4ee78b.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +1 -0
- package/metadata.scale +0 -0
- package/out.txt +42 -0
- package/package.json +39 -0
- package/src/CheckboxData.ts +38 -0
- package/src/ExtrinsicData.ts +119 -0
- package/src/_polyfills.ts +3 -0
- package/src/deferred.ts +48 -0
- package/src/descriptor-schema.ts +19 -0
- package/src/guards.ts +20 -0
- package/src/main.ts +839 -0
- package/src/metadata.ts +140 -0
- package/src/smolldot-worker.ts +42 -0
- package/src/testing.ts +32 -0
- package/tsconfig-build.json +4 -0
- package/tsconfig.json +12 -0
package/src/main.ts
ADDED
|
@@ -0,0 +1,839 @@
|
|
|
1
|
+
import "./_polyfills"
|
|
2
|
+
|
|
3
|
+
import * as fs from "node:fs/promises"
|
|
4
|
+
import {
|
|
5
|
+
CodeDeclarations,
|
|
6
|
+
LookupEntry,
|
|
7
|
+
getChecksumBuilder,
|
|
8
|
+
getLookupFn,
|
|
9
|
+
getStaticBuilder,
|
|
10
|
+
} from "@polkadot-api/substrate-codegen"
|
|
11
|
+
import { V14Lookup } from "@polkadot-api/substrate-bindings"
|
|
12
|
+
import { CheckboxData } from "./CheckboxData"
|
|
13
|
+
import * as childProcess from "node:child_process"
|
|
14
|
+
import { deferred } from "./deferred"
|
|
15
|
+
import { ExtrinsicData } from "./ExtrinsicData"
|
|
16
|
+
import { confirm, input, select } from "@inquirer/prompts"
|
|
17
|
+
import util from "util"
|
|
18
|
+
import { ReadonlyRecord } from "fp-ts/lib/ReadonlyRecord"
|
|
19
|
+
import * as writePkg from "write-pkg"
|
|
20
|
+
import { z } from "zod"
|
|
21
|
+
import descriptorSchema from "./descriptor-schema"
|
|
22
|
+
import fsExists from "fs.promises.exists"
|
|
23
|
+
import { program } from "commander"
|
|
24
|
+
import { encodeMetadata, getMetadata } from "./metadata"
|
|
25
|
+
import { WellKnownChain } from "@substrate/connect"
|
|
26
|
+
import ora from "ora"
|
|
27
|
+
import { blowupMetadata } from "./testing"
|
|
28
|
+
import asTable from "as-table"
|
|
29
|
+
import chalk from "chalk"
|
|
30
|
+
import * as Record from "fp-ts/lib/Record"
|
|
31
|
+
|
|
32
|
+
const ProgramArgs = z.object({
|
|
33
|
+
metadataFile: z.string().optional(),
|
|
34
|
+
interactive: z.boolean(),
|
|
35
|
+
})
|
|
36
|
+
|
|
37
|
+
type ProgramArgs = z.infer<typeof ProgramArgs>
|
|
38
|
+
|
|
39
|
+
program
|
|
40
|
+
.name("polkadotApi")
|
|
41
|
+
.description("polkadot-api CLI")
|
|
42
|
+
.option("-m, --metadataFile <path>", "path to scale encoded metadata file")
|
|
43
|
+
.option("-i, --interactive", "whether to run in interactive mode", false)
|
|
44
|
+
|
|
45
|
+
program.parse()
|
|
46
|
+
|
|
47
|
+
const options = ProgramArgs.parse(program.opts())
|
|
48
|
+
|
|
49
|
+
const metadataArgs = options.metadataFile
|
|
50
|
+
? {
|
|
51
|
+
source: "file" as const,
|
|
52
|
+
file: options.metadataFile,
|
|
53
|
+
}
|
|
54
|
+
: {
|
|
55
|
+
source: "chain" as const,
|
|
56
|
+
chain: await select({
|
|
57
|
+
message: "Select a chain to pull metadata from",
|
|
58
|
+
choices: [
|
|
59
|
+
{ name: "polkadot", value: WellKnownChain.polkadot },
|
|
60
|
+
{ name: "westend", value: WellKnownChain.westend2 },
|
|
61
|
+
{ name: "ksm", value: WellKnownChain.ksmcc3 },
|
|
62
|
+
{ name: "rococo", value: WellKnownChain.rococo_v2_2 },
|
|
63
|
+
],
|
|
64
|
+
}),
|
|
65
|
+
}
|
|
66
|
+
const spinner = ora(`Loading Metadata`).start()
|
|
67
|
+
const { magicNumber, metadata } = await getMetadata(metadataArgs)
|
|
68
|
+
spinner.stop()
|
|
69
|
+
|
|
70
|
+
const SELECT_DESCRIPTORS = "SELECT_DESCRIPTORS"
|
|
71
|
+
const SHOW_DESCRIPTORS = "SHOW_DESCRIPTORS"
|
|
72
|
+
const OUTPUT_CODEGEN = "OUTPUT_CODEGEN"
|
|
73
|
+
const OUTPUT_DESCRIPTORS = "OUTPUT_DESCRIPTORS"
|
|
74
|
+
const LOAD_DESCRIPTORS = "LOAD_DESCRIPTORS"
|
|
75
|
+
const SAVE_METADATA = "SAVE_METADATA"
|
|
76
|
+
const BLOWUP_METADATA = "BLOWUP_METADATA"
|
|
77
|
+
const EXIT = "EXIT"
|
|
78
|
+
|
|
79
|
+
const CONSTANTS = "CONSTANTS"
|
|
80
|
+
const STORAGE = "STORAGE"
|
|
81
|
+
const EVENTS = "EVENTS"
|
|
82
|
+
const ERRORS = "ERRORS"
|
|
83
|
+
const EXTRINSICS = "EXTRINSICS"
|
|
84
|
+
|
|
85
|
+
const data: Record<
|
|
86
|
+
string,
|
|
87
|
+
{
|
|
88
|
+
constants: CheckboxData
|
|
89
|
+
storage: CheckboxData
|
|
90
|
+
events: CheckboxData
|
|
91
|
+
errors: CheckboxData
|
|
92
|
+
extrinsics: ExtrinsicData
|
|
93
|
+
}
|
|
94
|
+
> = {}
|
|
95
|
+
const { lookup, pallets } = metadata.value
|
|
96
|
+
|
|
97
|
+
const checksumBuilder = getChecksumBuilder(metadata.value)
|
|
98
|
+
|
|
99
|
+
let exit = false
|
|
100
|
+
while (!exit) {
|
|
101
|
+
const choice = await select({
|
|
102
|
+
message: "What do you want to do?",
|
|
103
|
+
choices: [
|
|
104
|
+
{ name: "Select descriptors", value: SELECT_DESCRIPTORS },
|
|
105
|
+
{ name: "Show descriptors", value: SHOW_DESCRIPTORS },
|
|
106
|
+
{ name: "Save Metadata", value: SAVE_METADATA },
|
|
107
|
+
{ name: "Output Descriptors", value: OUTPUT_DESCRIPTORS },
|
|
108
|
+
{ name: "Load Descriptors", value: LOAD_DESCRIPTORS },
|
|
109
|
+
{ name: "Blowup Metadata", value: BLOWUP_METADATA },
|
|
110
|
+
{ name: "Output Codegen", value: OUTPUT_CODEGEN },
|
|
111
|
+
{ name: "Exit", value: EXIT },
|
|
112
|
+
],
|
|
113
|
+
})
|
|
114
|
+
|
|
115
|
+
switch (choice) {
|
|
116
|
+
case SELECT_DESCRIPTORS: {
|
|
117
|
+
const pallet = await select({
|
|
118
|
+
message: "Select a pallet",
|
|
119
|
+
choices: pallets.map((p) => ({ name: p.name, value: p })),
|
|
120
|
+
})
|
|
121
|
+
|
|
122
|
+
const events = getLookupEntry(lookup, Number(pallet.events))
|
|
123
|
+
const errors = getLookupEntry(lookup, Number(pallet.errors))
|
|
124
|
+
const extrinsics = getLookupEntry(lookup, Number(pallet.calls))
|
|
125
|
+
|
|
126
|
+
if (!data[pallet.name]) {
|
|
127
|
+
data[pallet.name] = {
|
|
128
|
+
constants: new CheckboxData(),
|
|
129
|
+
storage: new CheckboxData(),
|
|
130
|
+
events: new CheckboxData(),
|
|
131
|
+
errors: new CheckboxData(),
|
|
132
|
+
extrinsics: new ExtrinsicData(),
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
let exitDescriptorSelection = false
|
|
137
|
+
while (!exitDescriptorSelection) {
|
|
138
|
+
const descriptorType = await select({
|
|
139
|
+
message: "Select a descriptor type",
|
|
140
|
+
choices: [
|
|
141
|
+
{ name: "Constants", value: CONSTANTS },
|
|
142
|
+
{ name: "Storage", value: STORAGE },
|
|
143
|
+
{ name: "Events", value: EVENTS },
|
|
144
|
+
{ name: "Errors", value: ERRORS },
|
|
145
|
+
{ name: "Extrinsics", value: EXTRINSICS },
|
|
146
|
+
{ name: "Exit", value: EXIT },
|
|
147
|
+
],
|
|
148
|
+
})
|
|
149
|
+
switch (descriptorType) {
|
|
150
|
+
case CONSTANTS: {
|
|
151
|
+
await data[pallet.name].constants.prompt(
|
|
152
|
+
"Select Constants",
|
|
153
|
+
pallet.constants.map((c) => [
|
|
154
|
+
c.name,
|
|
155
|
+
checksumBuilder.buildConstant(pallet.name, c.name)!,
|
|
156
|
+
]),
|
|
157
|
+
)
|
|
158
|
+
break
|
|
159
|
+
}
|
|
160
|
+
case STORAGE:
|
|
161
|
+
await data[pallet.name].storage.prompt(
|
|
162
|
+
"Select Storage",
|
|
163
|
+
pallet.storage?.items.map((s) => [
|
|
164
|
+
s.name,
|
|
165
|
+
checksumBuilder.buildStorage(pallet.name, s.name)!,
|
|
166
|
+
]) ?? [],
|
|
167
|
+
)
|
|
168
|
+
break
|
|
169
|
+
case EVENTS:
|
|
170
|
+
await data[pallet.name].events.prompt(
|
|
171
|
+
"Select Events",
|
|
172
|
+
events.map((e) => [
|
|
173
|
+
e,
|
|
174
|
+
checksumBuilder.buildEvent(pallet.name, e)!,
|
|
175
|
+
]),
|
|
176
|
+
)
|
|
177
|
+
break
|
|
178
|
+
case ERRORS:
|
|
179
|
+
await data[pallet.name].errors.prompt(
|
|
180
|
+
"Select Errors",
|
|
181
|
+
errors.map((e) => [
|
|
182
|
+
e,
|
|
183
|
+
checksumBuilder.buildError(pallet.name, e)!,
|
|
184
|
+
]),
|
|
185
|
+
)
|
|
186
|
+
break
|
|
187
|
+
case EXTRINSICS: {
|
|
188
|
+
let selectExtrinsics = true
|
|
189
|
+
while (selectExtrinsics) {
|
|
190
|
+
await data[pallet.name].extrinsics.prompt(
|
|
191
|
+
extrinsics.map((e) => [
|
|
192
|
+
e,
|
|
193
|
+
checksumBuilder.buildCall(pallet.name, e)!,
|
|
194
|
+
]),
|
|
195
|
+
Object.entries(data).flatMap(([pallet, { events }]) =>
|
|
196
|
+
Array.from(Object.keys(events.data)).map(
|
|
197
|
+
(event) => [pallet, event] as [string, string],
|
|
198
|
+
),
|
|
199
|
+
),
|
|
200
|
+
Object.entries(data).flatMap(([pallet, { errors }]) =>
|
|
201
|
+
Array.from(Object.keys(errors.data)).map(
|
|
202
|
+
(errors) => [pallet, errors] as [string, string],
|
|
203
|
+
),
|
|
204
|
+
),
|
|
205
|
+
)
|
|
206
|
+
selectExtrinsics = await confirm({
|
|
207
|
+
message: "Continue?",
|
|
208
|
+
default: true,
|
|
209
|
+
})
|
|
210
|
+
}
|
|
211
|
+
break
|
|
212
|
+
}
|
|
213
|
+
case EXIT:
|
|
214
|
+
exitDescriptorSelection = true
|
|
215
|
+
break
|
|
216
|
+
default:
|
|
217
|
+
break
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
break
|
|
221
|
+
}
|
|
222
|
+
case SAVE_METADATA: {
|
|
223
|
+
const outFile = await input({
|
|
224
|
+
message: "Enter output fileName",
|
|
225
|
+
default: "metadata.scale",
|
|
226
|
+
})
|
|
227
|
+
await fs.writeFile(outFile, encodeMetadata({ magicNumber, metadata }))
|
|
228
|
+
break
|
|
229
|
+
}
|
|
230
|
+
case BLOWUP_METADATA: {
|
|
231
|
+
blowupMetadata(metadata)
|
|
232
|
+
break
|
|
233
|
+
}
|
|
234
|
+
case SHOW_DESCRIPTORS: {
|
|
235
|
+
console.log(
|
|
236
|
+
util.inspect(data, { showHidden: false, depth: null, colors: true }),
|
|
237
|
+
)
|
|
238
|
+
break
|
|
239
|
+
}
|
|
240
|
+
case OUTPUT_DESCRIPTORS: {
|
|
241
|
+
const output = JSON.stringify(data, null, 2)
|
|
242
|
+
|
|
243
|
+
const writeToPkgJSON = await confirm({
|
|
244
|
+
message: "Write to package.json?",
|
|
245
|
+
default: false,
|
|
246
|
+
})
|
|
247
|
+
|
|
248
|
+
if (writeToPkgJSON) {
|
|
249
|
+
writePkg.updatePackage(
|
|
250
|
+
JSON.parse(JSON.stringify({ polkadotApi: { descriptors: data } })),
|
|
251
|
+
)
|
|
252
|
+
} else {
|
|
253
|
+
const outFile = await input({
|
|
254
|
+
message: "Enter output fileName",
|
|
255
|
+
default: "descriptors.json",
|
|
256
|
+
})
|
|
257
|
+
|
|
258
|
+
await fs.writeFile(outFile, output)
|
|
259
|
+
}
|
|
260
|
+
break
|
|
261
|
+
}
|
|
262
|
+
case LOAD_DESCRIPTORS: {
|
|
263
|
+
const descriptors = await (async () => {
|
|
264
|
+
if (await fsExists("package.json")) {
|
|
265
|
+
const pkgJSONSchema = z.object({
|
|
266
|
+
polkadotApi: z.object({ descriptors: descriptorSchema }).optional(),
|
|
267
|
+
})
|
|
268
|
+
|
|
269
|
+
const { polkadotApi } = await pkgJSONSchema.parseAsync(
|
|
270
|
+
JSON.parse(
|
|
271
|
+
await fs.readFile("package.json", { encoding: "utf-8" }),
|
|
272
|
+
),
|
|
273
|
+
)
|
|
274
|
+
|
|
275
|
+
if (polkadotApi) {
|
|
276
|
+
return polkadotApi.descriptors
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
const inFile = await input({
|
|
281
|
+
message: "Enter descriptors fileName",
|
|
282
|
+
default: "descriptors.json",
|
|
283
|
+
})
|
|
284
|
+
|
|
285
|
+
return descriptorSchema.parseAsync(
|
|
286
|
+
JSON.parse(await fs.readFile(inFile, { encoding: "utf-8" })),
|
|
287
|
+
)
|
|
288
|
+
})()
|
|
289
|
+
|
|
290
|
+
const discrepancies: Array<{
|
|
291
|
+
pallet: string
|
|
292
|
+
type: "constant" | "storage" | "event" | "error" | "extrinsic"
|
|
293
|
+
name: string
|
|
294
|
+
oldChecksum: bigint | null
|
|
295
|
+
newChecksum: bigint | null
|
|
296
|
+
}> = []
|
|
297
|
+
|
|
298
|
+
for (const [
|
|
299
|
+
pallet,
|
|
300
|
+
{ constants, storage, events, errors, extrinsics },
|
|
301
|
+
] of Object.entries(descriptors)) {
|
|
302
|
+
for (const [constantName, checksum] of Object.entries(
|
|
303
|
+
constants ?? {},
|
|
304
|
+
)) {
|
|
305
|
+
const newChecksum = checksumBuilder.buildConstant(
|
|
306
|
+
pallet,
|
|
307
|
+
constantName,
|
|
308
|
+
)
|
|
309
|
+
if (checksum != newChecksum) {
|
|
310
|
+
discrepancies.push({
|
|
311
|
+
pallet,
|
|
312
|
+
type: "constant",
|
|
313
|
+
name: constantName,
|
|
314
|
+
oldChecksum: checksum,
|
|
315
|
+
newChecksum: newChecksum,
|
|
316
|
+
})
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
for (const [storageName, checksum] of Object.entries(storage ?? {})) {
|
|
320
|
+
const newChecksum = checksumBuilder.buildStorage(pallet, storageName)
|
|
321
|
+
if (checksum != newChecksum) {
|
|
322
|
+
discrepancies.push({
|
|
323
|
+
pallet,
|
|
324
|
+
type: "storage",
|
|
325
|
+
name: storageName,
|
|
326
|
+
oldChecksum: checksum,
|
|
327
|
+
newChecksum: newChecksum,
|
|
328
|
+
})
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
for (const [eventName, checksum] of Object.entries(events ?? {})) {
|
|
332
|
+
const newChecksum = checksumBuilder.buildEvent(pallet, eventName)
|
|
333
|
+
if (checksum != newChecksum) {
|
|
334
|
+
discrepancies.push({
|
|
335
|
+
pallet,
|
|
336
|
+
type: "event",
|
|
337
|
+
name: eventName,
|
|
338
|
+
oldChecksum: checksum,
|
|
339
|
+
newChecksum: newChecksum,
|
|
340
|
+
})
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
for (const [errorName, checksum] of Object.entries(errors ?? {})) {
|
|
344
|
+
const newChecksum = checksumBuilder.buildError(pallet, errorName)
|
|
345
|
+
if (checksum != newChecksum) {
|
|
346
|
+
discrepancies.push({
|
|
347
|
+
pallet,
|
|
348
|
+
type: "error",
|
|
349
|
+
name: errorName,
|
|
350
|
+
oldChecksum: checksum,
|
|
351
|
+
newChecksum: newChecksum,
|
|
352
|
+
})
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
for (const [callName, { checksum }] of Object.entries(
|
|
356
|
+
extrinsics ?? {},
|
|
357
|
+
)) {
|
|
358
|
+
const newChecksum = checksumBuilder.buildCall(pallet, callName)
|
|
359
|
+
if (checksum != newChecksum) {
|
|
360
|
+
discrepancies.push({
|
|
361
|
+
pallet,
|
|
362
|
+
type: "extrinsic",
|
|
363
|
+
name: callName,
|
|
364
|
+
oldChecksum: checksum,
|
|
365
|
+
newChecksum: newChecksum,
|
|
366
|
+
})
|
|
367
|
+
}
|
|
368
|
+
}
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
const mapDiscrepancy = ({
|
|
372
|
+
pallet,
|
|
373
|
+
name,
|
|
374
|
+
oldChecksum,
|
|
375
|
+
newChecksum,
|
|
376
|
+
}: (typeof discrepancies)[number]) => ({
|
|
377
|
+
Pallet: pallet,
|
|
378
|
+
Name: name,
|
|
379
|
+
"Old Checksum":
|
|
380
|
+
oldChecksum === null ? chalk.red(oldChecksum) : oldChecksum,
|
|
381
|
+
"New Checksum":
|
|
382
|
+
newChecksum === null ? chalk.red(newChecksum) : newChecksum,
|
|
383
|
+
})
|
|
384
|
+
|
|
385
|
+
console.log("-------- Constant Discrepancies --------")
|
|
386
|
+
console.log(
|
|
387
|
+
asTable(
|
|
388
|
+
discrepancies
|
|
389
|
+
.filter(({ type }) => type === "constant")
|
|
390
|
+
.map(mapDiscrepancy),
|
|
391
|
+
),
|
|
392
|
+
)
|
|
393
|
+
console.log("")
|
|
394
|
+
console.log("-------- Storage Discrepancies --------")
|
|
395
|
+
console.log(
|
|
396
|
+
asTable(
|
|
397
|
+
discrepancies
|
|
398
|
+
.filter(({ type }) => type === "storage")
|
|
399
|
+
.map(mapDiscrepancy),
|
|
400
|
+
),
|
|
401
|
+
)
|
|
402
|
+
console.log("")
|
|
403
|
+
console.log("-------- Event Discrepancies --------")
|
|
404
|
+
console.log(
|
|
405
|
+
asTable(
|
|
406
|
+
discrepancies
|
|
407
|
+
.filter(({ type }) => type === "event")
|
|
408
|
+
.map(mapDiscrepancy),
|
|
409
|
+
),
|
|
410
|
+
)
|
|
411
|
+
console.log("")
|
|
412
|
+
console.log("-------- Error Discrepancies --------")
|
|
413
|
+
console.log(
|
|
414
|
+
asTable(
|
|
415
|
+
discrepancies
|
|
416
|
+
.filter(({ type }) => type === "error")
|
|
417
|
+
.map(mapDiscrepancy),
|
|
418
|
+
),
|
|
419
|
+
)
|
|
420
|
+
console.log("")
|
|
421
|
+
console.log("-------- Extrinsic Discrepancies --------")
|
|
422
|
+
console.log(
|
|
423
|
+
asTable(
|
|
424
|
+
discrepancies
|
|
425
|
+
.filter(({ type }) => type === "extrinsic")
|
|
426
|
+
.map(mapDiscrepancy),
|
|
427
|
+
),
|
|
428
|
+
)
|
|
429
|
+
console.log("")
|
|
430
|
+
|
|
431
|
+
if (discrepancies.length > 0) {
|
|
432
|
+
const accept = await confirm({ message: "Accept changes" })
|
|
433
|
+
if (!accept) {
|
|
434
|
+
break
|
|
435
|
+
}
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
for (const discrepancy of discrepancies) {
|
|
439
|
+
switch (discrepancy.type) {
|
|
440
|
+
case "constant": {
|
|
441
|
+
const { constants } = descriptors[discrepancy.pallet]
|
|
442
|
+
if (!constants) {
|
|
443
|
+
break
|
|
444
|
+
}
|
|
445
|
+
if (discrepancy.newChecksum === null) {
|
|
446
|
+
delete constants[discrepancy.name]
|
|
447
|
+
} else {
|
|
448
|
+
constants[discrepancy.name] = discrepancy.newChecksum
|
|
449
|
+
}
|
|
450
|
+
break
|
|
451
|
+
}
|
|
452
|
+
case "storage": {
|
|
453
|
+
const { storage } = descriptors[discrepancy.pallet]
|
|
454
|
+
if (!storage) {
|
|
455
|
+
break
|
|
456
|
+
}
|
|
457
|
+
if (discrepancy.newChecksum === null) {
|
|
458
|
+
delete storage[discrepancy.name]
|
|
459
|
+
} else {
|
|
460
|
+
storage[discrepancy.name] = discrepancy.newChecksum
|
|
461
|
+
}
|
|
462
|
+
break
|
|
463
|
+
}
|
|
464
|
+
case "event": {
|
|
465
|
+
const { events } = descriptors[discrepancy.pallet]
|
|
466
|
+
if (!events) {
|
|
467
|
+
break
|
|
468
|
+
}
|
|
469
|
+
if (discrepancy.newChecksum === null) {
|
|
470
|
+
delete events[discrepancy.name]
|
|
471
|
+
} else {
|
|
472
|
+
events[discrepancy.name] = discrepancy.newChecksum
|
|
473
|
+
}
|
|
474
|
+
break
|
|
475
|
+
}
|
|
476
|
+
case "error": {
|
|
477
|
+
const { errors } = descriptors[discrepancy.pallet]
|
|
478
|
+
if (!errors) {
|
|
479
|
+
break
|
|
480
|
+
}
|
|
481
|
+
if (discrepancy.newChecksum === null) {
|
|
482
|
+
delete errors[discrepancy.name]
|
|
483
|
+
} else {
|
|
484
|
+
errors[discrepancy.name] = discrepancy.newChecksum
|
|
485
|
+
}
|
|
486
|
+
break
|
|
487
|
+
}
|
|
488
|
+
case "extrinsic": {
|
|
489
|
+
const { extrinsics } = descriptors[discrepancy.pallet]
|
|
490
|
+
if (!extrinsics) {
|
|
491
|
+
break
|
|
492
|
+
}
|
|
493
|
+
if (discrepancy.newChecksum === null) {
|
|
494
|
+
delete extrinsics[discrepancy.name]
|
|
495
|
+
} else {
|
|
496
|
+
const newEvents: Record<string, Set<string>> = extrinsics[
|
|
497
|
+
discrepancy.name
|
|
498
|
+
].events
|
|
499
|
+
for (const d of discrepancies.filter((d) => d.type === "event")) {
|
|
500
|
+
newEvents[d.pallet] = newEvents[d.pallet] ?? {}
|
|
501
|
+
if (d.newChecksum === null) {
|
|
502
|
+
newEvents[d.pallet].delete(d.name)
|
|
503
|
+
}
|
|
504
|
+
}
|
|
505
|
+
const newErrors: Record<string, Set<string>> = extrinsics[
|
|
506
|
+
discrepancy.name
|
|
507
|
+
].errors
|
|
508
|
+
for (const d of discrepancies.filter((d) => d.type === "error")) {
|
|
509
|
+
newErrors[d.pallet] = newErrors[d.pallet] ?? {}
|
|
510
|
+
if (d.newChecksum === null) {
|
|
511
|
+
newErrors[d.pallet].delete(d.name)
|
|
512
|
+
}
|
|
513
|
+
}
|
|
514
|
+
|
|
515
|
+
extrinsics[discrepancy.name] = {
|
|
516
|
+
events: newEvents,
|
|
517
|
+
errors: newErrors,
|
|
518
|
+
checksum: discrepancy.newChecksum,
|
|
519
|
+
}
|
|
520
|
+
}
|
|
521
|
+
break
|
|
522
|
+
}
|
|
523
|
+
default:
|
|
524
|
+
break
|
|
525
|
+
}
|
|
526
|
+
}
|
|
527
|
+
|
|
528
|
+
for (const pallet of Object.keys(descriptors)) {
|
|
529
|
+
const palletDescriptors = descriptors[pallet]
|
|
530
|
+
data[pallet] = data[pallet] ?? {}
|
|
531
|
+
data[pallet].constants = new CheckboxData(palletDescriptors.constants)
|
|
532
|
+
data[pallet].storage = new CheckboxData(palletDescriptors.storage)
|
|
533
|
+
data[pallet].events = new CheckboxData(palletDescriptors.events)
|
|
534
|
+
data[pallet].errors = new CheckboxData(palletDescriptors.errors)
|
|
535
|
+
data[pallet].extrinsics = new ExtrinsicData(
|
|
536
|
+
palletDescriptors.extrinsics,
|
|
537
|
+
)
|
|
538
|
+
}
|
|
539
|
+
break
|
|
540
|
+
}
|
|
541
|
+
case OUTPUT_CODEGEN: {
|
|
542
|
+
const outFile = await input({
|
|
543
|
+
message: "Enter output fileName",
|
|
544
|
+
default: "codegen.ts",
|
|
545
|
+
})
|
|
546
|
+
|
|
547
|
+
const declarations: CodeDeclarations = {
|
|
548
|
+
imports: new Set<string>(),
|
|
549
|
+
variables: new Map(),
|
|
550
|
+
}
|
|
551
|
+
|
|
552
|
+
const { buildStorage, buildEvent, buildCall, buildConstant, buildError } =
|
|
553
|
+
getStaticBuilder(metadata.value, declarations)
|
|
554
|
+
|
|
555
|
+
const constantDescriptors: [
|
|
556
|
+
pallet: string,
|
|
557
|
+
name: string,
|
|
558
|
+
checksum: bigint,
|
|
559
|
+
payload: string,
|
|
560
|
+
][] = []
|
|
561
|
+
|
|
562
|
+
const storageDescriptors: [
|
|
563
|
+
pallet: string,
|
|
564
|
+
name: string,
|
|
565
|
+
checksum: bigint,
|
|
566
|
+
key: string,
|
|
567
|
+
val: string,
|
|
568
|
+
][] = []
|
|
569
|
+
|
|
570
|
+
const eventDescriptors: Record<
|
|
571
|
+
string,
|
|
572
|
+
[pallet: string, name: string, checksum: bigint, payload: string]
|
|
573
|
+
> = {}
|
|
574
|
+
const errorDescriptors: Record<
|
|
575
|
+
string,
|
|
576
|
+
[pallet: string, name: string, checksum: bigint, payload: string]
|
|
577
|
+
> = {}
|
|
578
|
+
|
|
579
|
+
const callDescriptors: [
|
|
580
|
+
pallet: string,
|
|
581
|
+
callName: string,
|
|
582
|
+
checksum: bigint,
|
|
583
|
+
payload: string,
|
|
584
|
+
events: ReadonlyRecord<string, ReadonlySet<string>>,
|
|
585
|
+
errors: ReadonlyRecord<string, ReadonlySet<string>>,
|
|
586
|
+
][] = []
|
|
587
|
+
|
|
588
|
+
for (const [
|
|
589
|
+
pallet,
|
|
590
|
+
{ constants, storage, events, extrinsics, errors },
|
|
591
|
+
] of Object.entries(data)) {
|
|
592
|
+
for (const [constantName, checksum] of Object.entries(constants.data)) {
|
|
593
|
+
const payload = buildConstant(pallet, constantName)
|
|
594
|
+
constantDescriptors.push([pallet, constantName, checksum, payload])
|
|
595
|
+
}
|
|
596
|
+
for (const [entry, checksum] of Object.entries(storage.data)) {
|
|
597
|
+
const { key, val } = buildStorage(pallet, entry)
|
|
598
|
+
storageDescriptors.push([pallet, entry, checksum, key, val])
|
|
599
|
+
}
|
|
600
|
+
for (const [eventName, checksum] of Object.entries(events.data)) {
|
|
601
|
+
const payload = buildEvent(pallet, eventName)
|
|
602
|
+
eventDescriptors[`${pallet}${eventName}`] = [
|
|
603
|
+
pallet,
|
|
604
|
+
eventName,
|
|
605
|
+
checksum,
|
|
606
|
+
payload,
|
|
607
|
+
]
|
|
608
|
+
}
|
|
609
|
+
for (const [errorName, checksum] of Object.entries(errors.data)) {
|
|
610
|
+
const payload = buildError(pallet, errorName)
|
|
611
|
+
errorDescriptors[`${pallet}${errorName}`] = [
|
|
612
|
+
pallet,
|
|
613
|
+
errorName,
|
|
614
|
+
checksum,
|
|
615
|
+
payload,
|
|
616
|
+
]
|
|
617
|
+
}
|
|
618
|
+
for (const [callName, { events, errors }] of Object.entries(
|
|
619
|
+
extrinsics.data,
|
|
620
|
+
)) {
|
|
621
|
+
const payload = buildCall(pallet, callName)
|
|
622
|
+
const checksum = checksumBuilder.buildCall(pallet, callName)!
|
|
623
|
+
callDescriptors.push([
|
|
624
|
+
pallet,
|
|
625
|
+
callName,
|
|
626
|
+
checksum,
|
|
627
|
+
payload,
|
|
628
|
+
events,
|
|
629
|
+
errors,
|
|
630
|
+
])
|
|
631
|
+
}
|
|
632
|
+
}
|
|
633
|
+
|
|
634
|
+
const constDeclarations = [...declarations.variables.values()].map(
|
|
635
|
+
(variable) =>
|
|
636
|
+
`const ${variable.id}${
|
|
637
|
+
variable.types ? ": " + variable.types : ""
|
|
638
|
+
} = ${variable.value}\nexport type ${
|
|
639
|
+
variable.id
|
|
640
|
+
} = CodecType<typeof ${variable.id}>`,
|
|
641
|
+
)
|
|
642
|
+
declarations.imports.add("CodecType")
|
|
643
|
+
declarations.imports.add("Codec")
|
|
644
|
+
constDeclarations.unshift(
|
|
645
|
+
`import {${[...declarations.imports].join(
|
|
646
|
+
", ",
|
|
647
|
+
)}} from "@polkadot-api/substrate-bindings"`,
|
|
648
|
+
)
|
|
649
|
+
|
|
650
|
+
await fs.mkdir("codegen", { recursive: true })
|
|
651
|
+
await fs.writeFile(`codegen/${outFile}`, constDeclarations.join("\n\n"))
|
|
652
|
+
const tsc = deferred<number>()
|
|
653
|
+
const process = childProcess.spawn("tsc", [
|
|
654
|
+
`codegen/${outFile}`,
|
|
655
|
+
"--outDir",
|
|
656
|
+
"./codegen",
|
|
657
|
+
"--skipLibCheck",
|
|
658
|
+
"--emitDeclarationOnly",
|
|
659
|
+
"--declaration",
|
|
660
|
+
])
|
|
661
|
+
|
|
662
|
+
process.stdout.on("data", (data) => {
|
|
663
|
+
console.log(`stdout: ${data}`)
|
|
664
|
+
})
|
|
665
|
+
|
|
666
|
+
process.stderr.on("data", (data) => {
|
|
667
|
+
console.error(`stderr: ${data}`)
|
|
668
|
+
})
|
|
669
|
+
|
|
670
|
+
process.on("close", (code) => {
|
|
671
|
+
tsc.resolve(code ?? 1)
|
|
672
|
+
})
|
|
673
|
+
|
|
674
|
+
await tsc
|
|
675
|
+
|
|
676
|
+
await fs.rm(`codegen/${outFile}`)
|
|
677
|
+
|
|
678
|
+
let descriptorCodegen = ""
|
|
679
|
+
const descriptorTypeImports = [
|
|
680
|
+
"DescriptorCommon",
|
|
681
|
+
"ArgsWithPayloadCodec",
|
|
682
|
+
"StorageDescriptor",
|
|
683
|
+
"ConstantDescriptor",
|
|
684
|
+
"EventDescriptor",
|
|
685
|
+
"ErrorDescriptor",
|
|
686
|
+
"EventToObject",
|
|
687
|
+
"UnionizeTupleEvents",
|
|
688
|
+
"TxDescriptorArgs",
|
|
689
|
+
"TxDescriptorEvents",
|
|
690
|
+
"TxDescriptorErrors",
|
|
691
|
+
"TxFunction",
|
|
692
|
+
]
|
|
693
|
+
const descriptorImports = [
|
|
694
|
+
"createCommonDescriptor",
|
|
695
|
+
"getDescriptorCreator",
|
|
696
|
+
"getPalletCreator",
|
|
697
|
+
]
|
|
698
|
+
|
|
699
|
+
descriptorCodegen += `import {${[
|
|
700
|
+
...new Set([...declarations.imports, ...descriptorImports]),
|
|
701
|
+
].join(", ")}} from "@polkadot-api/substrate-bindings"\n`
|
|
702
|
+
descriptorCodegen += `import type {${[...descriptorTypeImports].join(
|
|
703
|
+
", ",
|
|
704
|
+
)}} from "@polkadot-api/substrate-bindings"\n`
|
|
705
|
+
descriptorCodegen += `import type {${[...declarations.variables.values()]
|
|
706
|
+
.map((v) => v.id)
|
|
707
|
+
.join(", ")}} from "./codegen"\n\n`
|
|
708
|
+
|
|
709
|
+
descriptorCodegen += `const CONST = "const"\n\n`
|
|
710
|
+
descriptorCodegen += `const EVENT = "event"\n\n`
|
|
711
|
+
descriptorCodegen += `const ERROR = "error"\n\n`
|
|
712
|
+
|
|
713
|
+
for (const pallet of Object.keys(data)) {
|
|
714
|
+
descriptorCodegen += `const ${pallet}Creator = getPalletCreator(\"${pallet}\")\n\n`
|
|
715
|
+
}
|
|
716
|
+
|
|
717
|
+
descriptorCodegen +=
|
|
718
|
+
constantDescriptors
|
|
719
|
+
.map(
|
|
720
|
+
([pallet, name, checksum, payload]) =>
|
|
721
|
+
`const ${pallet}${name}Constant = ${pallet}Creator.getPayloadDescriptor(CONST, ${checksum}n, \"${name}\", {} as unknown as ${
|
|
722
|
+
declarations.imports.has(payload)
|
|
723
|
+
? `CodecType<typeof ${payload}>`
|
|
724
|
+
: payload
|
|
725
|
+
})`,
|
|
726
|
+
)
|
|
727
|
+
|
|
728
|
+
.join("\n\n") + "\n"
|
|
729
|
+
descriptorCodegen +=
|
|
730
|
+
storageDescriptors
|
|
731
|
+
.map(([pallet, name, checksum, key, payload]) => {
|
|
732
|
+
const returnType = declarations.imports.has(payload)
|
|
733
|
+
? `CodecType<typeof ${payload}>`
|
|
734
|
+
: payload
|
|
735
|
+
const len = declarations.variables.get(key)!.directDependencies.size
|
|
736
|
+
|
|
737
|
+
return `const ${pallet}${name}Storage = ${pallet}Creator.getStorageDescriptor(
|
|
738
|
+
${checksum}n,
|
|
739
|
+
\"${name}\",
|
|
740
|
+
{len: ${len}} as ArgsWithPayloadCodec<${key}, ${returnType}>)`
|
|
741
|
+
})
|
|
742
|
+
.join("\n\n") + "\n"
|
|
743
|
+
descriptorCodegen +=
|
|
744
|
+
Object.values(eventDescriptors)
|
|
745
|
+
.map(
|
|
746
|
+
([pallet, name, checksum, payload]) =>
|
|
747
|
+
`const ${pallet}${name}Event = ${pallet}Creator.getPayloadDescriptor(EVENT, ${checksum}n, \"${name}\", {} as unknown as ${
|
|
748
|
+
declarations.imports.has(payload)
|
|
749
|
+
? `CodecType<typeof ${payload}>`
|
|
750
|
+
: payload
|
|
751
|
+
})`,
|
|
752
|
+
)
|
|
753
|
+
.join("\n\n") + "\n"
|
|
754
|
+
descriptorCodegen +=
|
|
755
|
+
Object.values(errorDescriptors)
|
|
756
|
+
.map(
|
|
757
|
+
([pallet, name, checksum, payload]) =>
|
|
758
|
+
`const ${pallet}${name}Error = ${pallet}Creator.getPayloadDescriptor(ERROR, ${checksum}n, \"${name}\", {} as unknown as ${
|
|
759
|
+
declarations.imports.has(payload)
|
|
760
|
+
? `CodecType<typeof ${payload}>`
|
|
761
|
+
: payload
|
|
762
|
+
})`,
|
|
763
|
+
)
|
|
764
|
+
.join("\n\n") + "\n"
|
|
765
|
+
|
|
766
|
+
for (const [
|
|
767
|
+
pallet,
|
|
768
|
+
name,
|
|
769
|
+
checksum,
|
|
770
|
+
payload,
|
|
771
|
+
events,
|
|
772
|
+
errors,
|
|
773
|
+
] of callDescriptors) {
|
|
774
|
+
const eventVariables = Object.entries(events).reduce(
|
|
775
|
+
(p, [pallet, palletEvents]) => [
|
|
776
|
+
...p,
|
|
777
|
+
...Array.from(palletEvents).map((e) => `${pallet}${e}Event`),
|
|
778
|
+
],
|
|
779
|
+
[] as string[],
|
|
780
|
+
)
|
|
781
|
+
const errorVariables = Object.entries(errors).reduce(
|
|
782
|
+
(p, [pallet, palletErrors]) => [
|
|
783
|
+
...p,
|
|
784
|
+
...Array.from(palletErrors).map((e) => `${pallet}${e}Error`),
|
|
785
|
+
],
|
|
786
|
+
[] as string[],
|
|
787
|
+
)
|
|
788
|
+
|
|
789
|
+
descriptorCodegen +=
|
|
790
|
+
`const ${pallet}${name}Call = ${pallet}Creator.getTxDescriptor(${checksum}n, "${name}", [${eventVariables.join(
|
|
791
|
+
",",
|
|
792
|
+
)}], [${errorVariables.join(",")}], {} as unknown as ${
|
|
793
|
+
declarations.imports.has(payload)
|
|
794
|
+
? `CodecType<typeof ${payload}>`
|
|
795
|
+
: payload
|
|
796
|
+
})` + "\n\n"
|
|
797
|
+
}
|
|
798
|
+
|
|
799
|
+
const descriptorVariablesRegexp = new RegExp(
|
|
800
|
+
/(?<=const)\s(.*(Constant|Storage|Event|Error|Call))\s(?=\=)/g,
|
|
801
|
+
)
|
|
802
|
+
|
|
803
|
+
const descriptorVariableNames =
|
|
804
|
+
descriptorCodegen
|
|
805
|
+
.match(descriptorVariablesRegexp)
|
|
806
|
+
?.map((s) => s.trim()) ?? []
|
|
807
|
+
|
|
808
|
+
descriptorCodegen +=
|
|
809
|
+
`const result: [${descriptorVariableNames
|
|
810
|
+
.map((s) => `typeof ${s}`)
|
|
811
|
+
.join(",")}] = [${descriptorVariableNames.join(",")}]` +
|
|
812
|
+
"\n\nexport default result\n\n"
|
|
813
|
+
|
|
814
|
+
await fs.writeFile(`codegen/descriptor_codegen.ts`, descriptorCodegen)
|
|
815
|
+
|
|
816
|
+
break
|
|
817
|
+
}
|
|
818
|
+
case EXIT:
|
|
819
|
+
exit = true
|
|
820
|
+
break
|
|
821
|
+
default:
|
|
822
|
+
break
|
|
823
|
+
}
|
|
824
|
+
}
|
|
825
|
+
|
|
826
|
+
function getLookupEntry(lookup: V14Lookup, idx: number) {
|
|
827
|
+
const lookupFns = getLookupFn(lookup)(idx)
|
|
828
|
+
assertLookupEntryIsEnum(lookupFns)
|
|
829
|
+
|
|
830
|
+
return Object.keys(lookupFns.value)
|
|
831
|
+
}
|
|
832
|
+
|
|
833
|
+
function assertLookupEntryIsEnum(
|
|
834
|
+
lookupEntry: LookupEntry,
|
|
835
|
+
): asserts lookupEntry is LookupEntry & { type: "enum" } {
|
|
836
|
+
if (lookupEntry.type !== "enum") {
|
|
837
|
+
throw new Error("not an enum")
|
|
838
|
+
}
|
|
839
|
+
}
|