@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/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
+ }