polkadot-cli 1.2.0 → 1.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 (3) hide show
  1. package/README.md +29 -0
  2. package/dist/cli.mjs +1067 -648
  3. package/package.json +1 -1
package/dist/cli.mjs CHANGED
@@ -1,141 +1,145 @@
1
1
  #!/usr/bin/env node
2
2
  import { createRequire } from "node:module";
3
+ var __defProp = Object.defineProperty;
4
+ var __returnValue = (v) => v;
5
+ function __exportSetter(name, newValue) {
6
+ this[name] = __returnValue.bind(null, newValue);
7
+ }
8
+ var __export = (target, all) => {
9
+ for (var name in all)
10
+ __defProp(target, name, {
11
+ get: all[name],
12
+ enumerable: true,
13
+ configurable: true,
14
+ set: __exportSetter.bind(all, name)
15
+ });
16
+ };
17
+ var __esm = (fn, res) => () => (fn && (res = fn(fn = 0)), res);
3
18
  var __require = /* @__PURE__ */ createRequire(import.meta.url);
4
19
 
5
- // src/cli.ts
6
- import cac from "cac";
7
- // package.json
8
- var version = "1.2.0";
9
-
10
- // src/config/accounts-store.ts
11
- import { access as access2, mkdir as mkdir2, readFile as readFile2, writeFile as writeFile2 } from "node:fs/promises";
12
- import { join as join2 } from "node:path";
13
-
14
- // src/config/store.ts
15
- import { access, mkdir, readFile, rm, writeFile } from "node:fs/promises";
16
- import { homedir } from "node:os";
17
- import { join } from "node:path";
18
-
19
20
  // src/config/types.ts
20
21
  function primaryRpc(rpc) {
21
22
  return Array.isArray(rpc) ? rpc[0] : rpc;
22
23
  }
23
- var DEFAULT_CONFIG = {
24
- defaultChain: "polkadot",
25
- chains: {
26
- polkadot: {
27
- rpc: [
28
- "wss://polkadot.ibp.network",
29
- "wss://polkadot.dotters.network",
30
- "wss://polkadot-rpc.n.dwellir.com",
31
- "wss://polkadot-rpc.publicnode.com",
32
- "wss://rpc-polkadot.luckyfriday.io",
33
- "wss://polkadot.api.onfinality.io/public-ws",
34
- "wss://rpc-polkadot.helixstreet.io",
35
- "wss://polkadot-rpc-tn.dwellir.com",
36
- "wss://polkadot.public.curie.radiumblock.co/ws",
37
- "wss://rpc-polkadot.stakeworld.io",
38
- "wss://polkadot.rpc.subquery.network/public/ws",
39
- "wss://rpc.polkadot.io"
40
- ]
41
- },
42
- "polkadot-asset-hub": {
43
- rpc: [
44
- "wss://polkadot-asset-hub-rpc.polkadot.io",
45
- "wss://asset-hub-polkadot.ibp.network",
46
- "wss://asset-hub-polkadot.dotters.network",
47
- "wss://asset-hub-polkadot-rpc.n.dwellir.com",
48
- "wss://rpc-asset-hub-polkadot.luckyfriday.io",
49
- "wss://statemint.api.onfinality.io/public-ws",
50
- "wss://statemint-rpc-tn.dwellir.com",
51
- "wss://statemint.public.curie.radiumblock.co/ws",
52
- "wss://asset-hub-polkadot.rpc.permanence.io"
53
- ]
54
- },
55
- "polkadot-bridge-hub": {
56
- rpc: [
57
- "wss://polkadot-bridge-hub-rpc.polkadot.io",
58
- "wss://bridge-hub-polkadot.ibp.network",
59
- "wss://bridge-hub-polkadot.dotters.network",
60
- "wss://bridge-hub-polkadot-rpc.n.dwellir.com",
61
- "wss://rpc-bridge-hub-polkadot.luckyfriday.io",
62
- "wss://bridgehub-polkadot.api.onfinality.io/public-ws",
63
- "wss://polkadot-bridge-hub-rpc-tn.dwellir.com",
64
- "wss://bridgehub-polkadot.public.curie.radiumblock.co/ws"
65
- ]
66
- },
67
- "polkadot-collectives": {
68
- rpc: [
69
- "wss://polkadot-collectives-rpc.polkadot.io",
70
- "wss://collectives-polkadot.ibp.network",
71
- "wss://collectives-polkadot.dotters.network",
72
- "wss://collectives-polkadot-rpc.n.dwellir.com",
73
- "wss://rpc-collectives-polkadot.luckyfriday.io",
74
- "wss://collectives.api.onfinality.io/public-ws",
75
- "wss://polkadot-collectives-rpc-tn.dwellir.com",
76
- "wss://collectives.public.curie.radiumblock.co/ws"
77
- ]
78
- },
79
- "polkadot-coretime": {
80
- rpc: [
81
- "wss://polkadot-coretime-rpc.polkadot.io",
82
- "wss://coretime-polkadot.ibp.network",
83
- "wss://coretime-polkadot.dotters.network",
84
- "wss://coretime-polkadot-rpc.n.dwellir.com",
85
- "wss://rpc-coretime-polkadot.luckyfriday.io",
86
- "wss://coretime-polkadot.api.onfinality.io/public-ws"
87
- ]
88
- },
89
- "polkadot-people": {
90
- rpc: [
91
- "wss://polkadot-people-rpc.polkadot.io",
92
- "wss://people-polkadot.ibp.network",
93
- "wss://people-polkadot.dotters.network",
94
- "wss://people-polkadot-rpc.n.dwellir.com",
95
- "wss://rpc-people-polkadot.luckyfriday.io",
96
- "wss://people-polkadot.api.onfinality.io/public-ws"
97
- ]
98
- },
99
- paseo: {
100
- rpc: [
101
- "wss://paseo.ibp.network",
102
- "wss://paseo.dotters.network",
103
- "wss://paseo-rpc.n.dwellir.com",
104
- "wss://paseo.rpc.amforc.com"
105
- ]
106
- },
107
- "paseo-asset-hub": {
108
- rpc: [
109
- "wss://asset-hub-paseo.ibp.network",
110
- "wss://asset-hub-paseo.dotters.network",
111
- "wss://asset-hub-paseo-rpc.n.dwellir.com",
112
- "wss://sys.turboflakes.io/asset-hub-paseo"
113
- ]
114
- },
115
- "paseo-bridge-hub": {
116
- rpc: ["wss://bridge-hub-paseo.ibp.network", "wss://bridge-hub-paseo.dotters.network"]
117
- },
118
- "paseo-collectives": {
119
- rpc: ["wss://collectives-paseo.ibp.network", "wss://collectives-paseo.dotters.network"]
120
- },
121
- "paseo-coretime": {
122
- rpc: ["wss://coretime-paseo.ibp.network", "wss://coretime-paseo.dotters.network"]
123
- },
124
- "paseo-people": {
125
- rpc: [
126
- "wss://people-paseo.ibp.network",
127
- "wss://people-paseo.dotters.network",
128
- "wss://people-paseo.rpc.amforc.com"
129
- ]
24
+ var DEFAULT_CONFIG, BUILTIN_CHAIN_NAMES;
25
+ var init_types = __esm(() => {
26
+ DEFAULT_CONFIG = {
27
+ defaultChain: "polkadot",
28
+ chains: {
29
+ polkadot: {
30
+ rpc: [
31
+ "wss://polkadot.ibp.network",
32
+ "wss://polkadot.dotters.network",
33
+ "wss://polkadot-rpc.n.dwellir.com",
34
+ "wss://polkadot-rpc.publicnode.com",
35
+ "wss://rpc-polkadot.luckyfriday.io",
36
+ "wss://polkadot.api.onfinality.io/public-ws",
37
+ "wss://rpc-polkadot.helixstreet.io",
38
+ "wss://polkadot-rpc-tn.dwellir.com",
39
+ "wss://polkadot.public.curie.radiumblock.co/ws",
40
+ "wss://rpc-polkadot.stakeworld.io",
41
+ "wss://polkadot.rpc.subquery.network/public/ws",
42
+ "wss://rpc.polkadot.io"
43
+ ]
44
+ },
45
+ "polkadot-asset-hub": {
46
+ rpc: [
47
+ "wss://polkadot-asset-hub-rpc.polkadot.io",
48
+ "wss://asset-hub-polkadot.ibp.network",
49
+ "wss://asset-hub-polkadot.dotters.network",
50
+ "wss://asset-hub-polkadot-rpc.n.dwellir.com",
51
+ "wss://rpc-asset-hub-polkadot.luckyfriday.io",
52
+ "wss://statemint.api.onfinality.io/public-ws",
53
+ "wss://statemint-rpc-tn.dwellir.com",
54
+ "wss://statemint.public.curie.radiumblock.co/ws",
55
+ "wss://asset-hub-polkadot.rpc.permanence.io"
56
+ ]
57
+ },
58
+ "polkadot-bridge-hub": {
59
+ rpc: [
60
+ "wss://polkadot-bridge-hub-rpc.polkadot.io",
61
+ "wss://bridge-hub-polkadot.ibp.network",
62
+ "wss://bridge-hub-polkadot.dotters.network",
63
+ "wss://bridge-hub-polkadot-rpc.n.dwellir.com",
64
+ "wss://rpc-bridge-hub-polkadot.luckyfriday.io",
65
+ "wss://bridgehub-polkadot.api.onfinality.io/public-ws",
66
+ "wss://polkadot-bridge-hub-rpc-tn.dwellir.com",
67
+ "wss://bridgehub-polkadot.public.curie.radiumblock.co/ws"
68
+ ]
69
+ },
70
+ "polkadot-collectives": {
71
+ rpc: [
72
+ "wss://polkadot-collectives-rpc.polkadot.io",
73
+ "wss://collectives-polkadot.ibp.network",
74
+ "wss://collectives-polkadot.dotters.network",
75
+ "wss://collectives-polkadot-rpc.n.dwellir.com",
76
+ "wss://rpc-collectives-polkadot.luckyfriday.io",
77
+ "wss://collectives.api.onfinality.io/public-ws",
78
+ "wss://polkadot-collectives-rpc-tn.dwellir.com",
79
+ "wss://collectives.public.curie.radiumblock.co/ws"
80
+ ]
81
+ },
82
+ "polkadot-coretime": {
83
+ rpc: [
84
+ "wss://polkadot-coretime-rpc.polkadot.io",
85
+ "wss://coretime-polkadot.ibp.network",
86
+ "wss://coretime-polkadot.dotters.network",
87
+ "wss://coretime-polkadot-rpc.n.dwellir.com",
88
+ "wss://rpc-coretime-polkadot.luckyfriday.io",
89
+ "wss://coretime-polkadot.api.onfinality.io/public-ws"
90
+ ]
91
+ },
92
+ "polkadot-people": {
93
+ rpc: [
94
+ "wss://polkadot-people-rpc.polkadot.io",
95
+ "wss://people-polkadot.ibp.network",
96
+ "wss://people-polkadot.dotters.network",
97
+ "wss://people-polkadot-rpc.n.dwellir.com",
98
+ "wss://rpc-people-polkadot.luckyfriday.io",
99
+ "wss://people-polkadot.api.onfinality.io/public-ws"
100
+ ]
101
+ },
102
+ paseo: {
103
+ rpc: [
104
+ "wss://paseo.ibp.network",
105
+ "wss://paseo.dotters.network",
106
+ "wss://paseo-rpc.n.dwellir.com",
107
+ "wss://paseo.rpc.amforc.com"
108
+ ]
109
+ },
110
+ "paseo-asset-hub": {
111
+ rpc: [
112
+ "wss://asset-hub-paseo.ibp.network",
113
+ "wss://asset-hub-paseo.dotters.network",
114
+ "wss://asset-hub-paseo-rpc.n.dwellir.com",
115
+ "wss://sys.turboflakes.io/asset-hub-paseo"
116
+ ]
117
+ },
118
+ "paseo-bridge-hub": {
119
+ rpc: ["wss://bridge-hub-paseo.ibp.network", "wss://bridge-hub-paseo.dotters.network"]
120
+ },
121
+ "paseo-collectives": {
122
+ rpc: ["wss://collectives-paseo.ibp.network", "wss://collectives-paseo.dotters.network"]
123
+ },
124
+ "paseo-coretime": {
125
+ rpc: ["wss://coretime-paseo.ibp.network", "wss://coretime-paseo.dotters.network"]
126
+ },
127
+ "paseo-people": {
128
+ rpc: [
129
+ "wss://people-paseo.ibp.network",
130
+ "wss://people-paseo.dotters.network",
131
+ "wss://people-paseo.rpc.amforc.com"
132
+ ]
133
+ }
130
134
  }
131
- }
132
- };
133
- var BUILTIN_CHAIN_NAMES = new Set(Object.keys(DEFAULT_CONFIG.chains));
135
+ };
136
+ BUILTIN_CHAIN_NAMES = new Set(Object.keys(DEFAULT_CONFIG.chains));
137
+ });
134
138
 
135
139
  // src/config/store.ts
136
- var DOT_DIR = join(homedir(), ".polkadot");
137
- var CONFIG_PATH = join(DOT_DIR, "config.json");
138
- var CHAINS_DIR = join(DOT_DIR, "chains");
140
+ import { access, mkdir, readFile, rm, writeFile } from "node:fs/promises";
141
+ import { homedir } from "node:os";
142
+ import { join } from "node:path";
139
143
  function getConfigDir() {
140
144
  return DOT_DIR;
141
145
  }
@@ -203,9 +207,17 @@ function resolveChain(config, chainFlag) {
203
207
  }
204
208
  return { name, chain: config.chains[name] };
205
209
  }
210
+ var DOT_DIR, CONFIG_PATH, CHAINS_DIR;
211
+ var init_store = __esm(() => {
212
+ init_types();
213
+ DOT_DIR = join(homedir(), ".polkadot");
214
+ CONFIG_PATH = join(DOT_DIR, "config.json");
215
+ CHAINS_DIR = join(DOT_DIR, "chains");
216
+ });
206
217
 
207
218
  // src/config/accounts-store.ts
208
- var ACCOUNTS_PATH = join2(getConfigDir(), "accounts.json");
219
+ import { access as access2, mkdir as mkdir2, readFile as readFile2, writeFile as writeFile2 } from "node:fs/promises";
220
+ import { join as join2 } from "node:path";
209
221
  async function ensureDir2(dir) {
210
222
  await mkdir2(dir, { recursive: true });
211
223
  }
@@ -233,6 +245,11 @@ async function saveAccounts(file) {
233
245
  function findAccount(file, name) {
234
246
  return file.accounts.find((a) => a.name.toLowerCase() === name.toLowerCase());
235
247
  }
248
+ var ACCOUNTS_PATH;
249
+ var init_accounts_store = __esm(() => {
250
+ init_store();
251
+ ACCOUNTS_PATH = join2(getConfigDir(), "accounts.json");
252
+ });
236
253
 
237
254
  // src/config/accounts-types.ts
238
255
  function isEnvSecret(secret) {
@@ -254,7 +271,6 @@ import {
254
271
  validateMnemonic
255
272
  } from "@polkadot-labs/hdkd-helpers";
256
273
  import { getPolkadotSigner } from "polkadot-api/signer";
257
- var DEV_NAMES = ["alice", "bob", "charlie", "dave", "eve", "ferdie"];
258
274
  function isDevAccount(name) {
259
275
  return DEV_NAMES.includes(name.toLowerCase());
260
276
  }
@@ -316,55 +332,610 @@ function toSs58(publicKey, prefix = 42) {
316
332
  }
317
333
  return ss58Address(bytes, prefix);
318
334
  }
319
- return ss58Address(publicKey, prefix);
320
- }
321
- function fromSs58(address) {
322
- const [payload] = ss58Decode(address);
323
- return payload;
324
- }
325
- function isHexPublicKey(input) {
326
- return /^0x[0-9a-fA-F]{64}$/.test(input);
335
+ return ss58Address(publicKey, prefix);
336
+ }
337
+ function fromSs58(address) {
338
+ const [payload] = ss58Decode(address);
339
+ return payload;
340
+ }
341
+ function isHexPublicKey(input) {
342
+ return /^0x[0-9a-fA-F]{64}$/.test(input);
343
+ }
344
+ function resolveSecret(secret) {
345
+ if (isEnvSecret(secret)) {
346
+ const value = process.env[secret.env];
347
+ if (!value) {
348
+ throw new Error(`Environment variable "${secret.env}" is not set. Set it before signing.`);
349
+ }
350
+ return value;
351
+ }
352
+ return secret;
353
+ }
354
+ function tryDerivePublicKey(envVarName, path = "") {
355
+ const value = process.env[envVarName];
356
+ if (!value)
357
+ return null;
358
+ try {
359
+ const { publicKey } = importAccount(value, path);
360
+ return publicKeyToHex(publicKey);
361
+ } catch {
362
+ return null;
363
+ }
364
+ }
365
+ async function resolveAccountSigner(name) {
366
+ if (isDevAccount(name)) {
367
+ const keypair2 = getDevKeypair(name);
368
+ return getPolkadotSigner(keypair2.publicKey, "Sr25519", keypair2.sign);
369
+ }
370
+ const accountsFile = await loadAccounts();
371
+ const account = findAccount(accountsFile, name);
372
+ if (!account) {
373
+ const available = [...DEV_NAMES, ...accountsFile.accounts.map((a) => a.name)];
374
+ throw new Error(`Unknown account "${name}". Available accounts: ${available.join(", ")}`);
375
+ }
376
+ if (account.secret === undefined) {
377
+ throw new Error(`Account "${name}" is watch-only (no secret). Cannot sign. Import with --secret or --env.`);
378
+ }
379
+ const secret = resolveSecret(account.secret);
380
+ const isHexSeed = /^0x[0-9a-fA-F]{64}$/.test(secret);
381
+ const keypair = isHexSeed ? deriveFromHexSeed(secret, account.derivationPath) : deriveFromMnemonic(secret, account.derivationPath);
382
+ return getPolkadotSigner(keypair.publicKey, "Sr25519", keypair.sign);
383
+ }
384
+ var DEV_NAMES;
385
+ var init_accounts = __esm(() => {
386
+ init_accounts_store();
387
+ DEV_NAMES = ["alice", "bob", "charlie", "dave", "eve", "ferdie"];
388
+ });
389
+
390
+ // src/utils/errors.ts
391
+ var CliError, ConnectionError, MetadataError;
392
+ var init_errors = __esm(() => {
393
+ CliError = class CliError extends Error {
394
+ constructor(message) {
395
+ super(message);
396
+ this.name = "CliError";
397
+ }
398
+ };
399
+ ConnectionError = class ConnectionError extends CliError {
400
+ constructor(message) {
401
+ super(message);
402
+ this.name = "ConnectionError";
403
+ }
404
+ };
405
+ MetadataError = class MetadataError extends CliError {
406
+ constructor(message) {
407
+ super(message);
408
+ this.name = "MetadataError";
409
+ }
410
+ };
411
+ });
412
+
413
+ // src/core/metadata.ts
414
+ import { getDynamicBuilder, getLookupFn } from "@polkadot-api/metadata-builders";
415
+ import { decAnyMetadata, unifyMetadata } from "@polkadot-api/substrate-bindings";
416
+ function parseMetadata(raw) {
417
+ const decoded = decAnyMetadata(raw);
418
+ const unified = unifyMetadata(decoded);
419
+ const lookup = getLookupFn(unified);
420
+ const builder = getDynamicBuilder(lookup);
421
+ return { unified, lookup, builder };
422
+ }
423
+ async function fetchMetadataFromChain(clientHandle, chainName) {
424
+ const { client } = clientHandle;
425
+ try {
426
+ const hex = await Promise.race([
427
+ client._request("state_getMetadata", []),
428
+ new Promise((_, reject) => setTimeout(() => reject(new ConnectionError(`Timed out fetching metadata for "${chainName}" after ${METADATA_TIMEOUT_MS / 1000}s. ` + "Check that the RPC endpoint is correct and reachable.")), METADATA_TIMEOUT_MS))
429
+ ]);
430
+ const bytes = hexToBytes(hex);
431
+ await saveMetadata(chainName, bytes);
432
+ return bytes;
433
+ } catch (err) {
434
+ if (err instanceof ConnectionError)
435
+ throw err;
436
+ throw new ConnectionError(`Failed to fetch metadata for "${chainName}": ${err instanceof Error ? err.message : err}. ` + "Check that the RPC endpoint is correct and reachable.");
437
+ }
438
+ }
439
+ async function getOrFetchMetadata(chainName, clientHandle) {
440
+ let raw = await loadMetadata(chainName);
441
+ if (!raw) {
442
+ if (!clientHandle) {
443
+ throw new MetadataError(`No cached metadata for chain "${chainName}". Run a command that connects to the chain first, ` + `e.g.: dot chain add ${chainName} --rpc <url>`);
444
+ }
445
+ raw = await fetchMetadataFromChain(clientHandle, chainName);
446
+ }
447
+ return parseMetadata(raw);
448
+ }
449
+ function listPallets(meta) {
450
+ return meta.unified.pallets.map((p) => ({
451
+ name: p.name,
452
+ index: p.index,
453
+ docs: p.docs ?? [],
454
+ storage: (p.storage?.items ?? []).map((s) => ({
455
+ name: s.name,
456
+ docs: s.docs ?? [],
457
+ type: s.type.tag,
458
+ keyTypeId: s.type.tag === "map" ? s.type.value.key : null,
459
+ valueTypeId: s.type.tag === "plain" ? s.type.value : s.type.value.value
460
+ })),
461
+ constants: (p.constants ?? []).map((c) => ({
462
+ name: c.name,
463
+ docs: c.docs ?? [],
464
+ typeId: c.type
465
+ })),
466
+ calls: extractEnumVariants(meta, p.calls),
467
+ events: extractEnumVariants(meta, p.events),
468
+ errors: extractEnumVariants(meta, p.errors).map(({ name, docs }) => ({ name, docs }))
469
+ }));
470
+ }
471
+ function extractEnumVariants(meta, ref) {
472
+ if (!ref)
473
+ return [];
474
+ try {
475
+ const entry = meta.lookup(ref.type);
476
+ if (entry.type !== "enum")
477
+ return [];
478
+ return Object.entries(entry.value).map(([name, variant]) => ({
479
+ name,
480
+ docs: entry.innerDocs?.[name] ?? [],
481
+ typeId: resolveVariantTypeId(variant)
482
+ }));
483
+ } catch {
484
+ return [];
485
+ }
486
+ }
487
+ function resolveVariantTypeId(variant) {
488
+ if (variant.type === "lookupEntry")
489
+ return variant.value?.id ?? null;
490
+ if (variant.type === "struct")
491
+ return null;
492
+ if (variant.type === "void" || variant.type === "empty")
493
+ return null;
494
+ return null;
495
+ }
496
+ function findPallet(meta, palletName) {
497
+ const pallets = listPallets(meta);
498
+ return pallets.find((p) => p.name.toLowerCase() === palletName.toLowerCase());
499
+ }
500
+ function getSignedExtensions(meta) {
501
+ const byVersion = meta.unified.extrinsic.signedExtensions;
502
+ const versionKeys = Object.keys(byVersion);
503
+ if (versionKeys.length === 0)
504
+ return [];
505
+ return byVersion[Number(versionKeys[0])] ?? [];
506
+ }
507
+ function getPalletNames(meta) {
508
+ return meta.unified.pallets.map((p) => p.name);
509
+ }
510
+ function describeType(lookup, typeId) {
511
+ try {
512
+ const entry = lookup(typeId);
513
+ return formatLookupEntry(entry);
514
+ } catch {
515
+ return `type(${typeId})`;
516
+ }
517
+ }
518
+ function formatLookupEntry(entry) {
519
+ switch (entry.type) {
520
+ case "primitive":
521
+ return entry.value;
522
+ case "compact":
523
+ return `Compact<${formatLookupEntry(entry.isBig ? { type: "primitive", value: "u128" } : { type: "primitive", value: "u64" })}>`;
524
+ case "AccountId32":
525
+ return "AccountId32";
526
+ case "bitSequence":
527
+ return "BitSequence";
528
+ case "sequence":
529
+ return `Vec<${formatLookupEntry(entry.value)}>`;
530
+ case "array":
531
+ return `[${formatLookupEntry(entry.value)}; ${entry.len}]`;
532
+ case "tuple":
533
+ return `(${entry.value.map(formatLookupEntry).join(", ")})`;
534
+ case "struct":
535
+ return `{ ${Object.entries(entry.value).map(([k, v]) => `${k}: ${formatLookupEntry(v)}`).join(", ")} }`;
536
+ case "option":
537
+ return `Option<${formatLookupEntry(entry.value)}>`;
538
+ case "result":
539
+ return `Result<${formatLookupEntry(entry.value.ok)}, ${formatLookupEntry(entry.value.ko)}>`;
540
+ case "enum": {
541
+ const variants = Object.keys(entry.value);
542
+ if (variants.length <= 4)
543
+ return variants.join(" | ");
544
+ return `enum(${variants.length} variants)`;
545
+ }
546
+ default:
547
+ return "unknown";
548
+ }
549
+ }
550
+ function describeCallArgs(meta, palletName, callName) {
551
+ try {
552
+ const palletMeta = meta.unified.pallets.find((p) => p.name === palletName);
553
+ if (!palletMeta?.calls)
554
+ return "";
555
+ const callsEntry = meta.lookup(palletMeta.calls.type);
556
+ if (callsEntry.type !== "enum")
557
+ return "";
558
+ const variant = callsEntry.value[callName];
559
+ if (!variant)
560
+ return "";
561
+ if (variant.type === "void")
562
+ return "()";
563
+ if (variant.type === "struct") {
564
+ const fields = Object.entries(variant.value).map(([k, v]) => `${k}: ${formatLookupEntry(v)}`).join(", ");
565
+ return `(${fields})`;
566
+ }
567
+ if (variant.type === "lookupEntry") {
568
+ const inner = variant.value;
569
+ if (inner.type === "void")
570
+ return "()";
571
+ if (inner.type === "struct") {
572
+ const fields = Object.entries(inner.value).map(([k, v]) => `${k}: ${formatLookupEntry(v)}`).join(", ");
573
+ return `(${fields})`;
574
+ }
575
+ return `(${formatLookupEntry(inner)})`;
576
+ }
577
+ if (variant.type === "tuple") {
578
+ const types = variant.value.map(formatLookupEntry).join(", ");
579
+ return `(${types})`;
580
+ }
581
+ return "";
582
+ } catch {
583
+ return "";
584
+ }
585
+ }
586
+ function describeEventFields(meta, palletName, eventName) {
587
+ try {
588
+ const palletMeta = meta.unified.pallets.find((p) => p.name === palletName);
589
+ if (!palletMeta?.events)
590
+ return "";
591
+ const eventsEntry = meta.lookup(palletMeta.events.type);
592
+ if (eventsEntry.type !== "enum")
593
+ return "";
594
+ const variant = eventsEntry.value[eventName];
595
+ if (!variant)
596
+ return "";
597
+ if (variant.type === "void")
598
+ return "()";
599
+ if (variant.type === "struct") {
600
+ const fields = Object.entries(variant.value).map(([k, v]) => `${k}: ${formatLookupEntry(v)}`).join(", ");
601
+ return `(${fields})`;
602
+ }
603
+ if (variant.type === "lookupEntry") {
604
+ const inner = variant.value;
605
+ if (inner.type === "void")
606
+ return "()";
607
+ if (inner.type === "struct") {
608
+ const fields = Object.entries(inner.value).map(([k, v]) => `${k}: ${formatLookupEntry(v)}`).join(", ");
609
+ return `(${fields})`;
610
+ }
611
+ return `(${formatLookupEntry(inner)})`;
612
+ }
613
+ if (variant.type === "tuple") {
614
+ const types = variant.value.map(formatLookupEntry).join(", ");
615
+ return `(${types})`;
616
+ }
617
+ return "";
618
+ } catch {
619
+ return "";
620
+ }
621
+ }
622
+ function hexToBytes(hex) {
623
+ const clean = hex.startsWith("0x") ? hex.slice(2) : hex;
624
+ const bytes = new Uint8Array(clean.length / 2);
625
+ for (let i = 0;i < clean.length; i += 2) {
626
+ bytes[i / 2] = parseInt(clean.substring(i, i + 2), 16);
627
+ }
628
+ return bytes;
629
+ }
630
+ var METADATA_TIMEOUT_MS = 15000;
631
+ var init_metadata = __esm(() => {
632
+ init_store();
633
+ init_errors();
634
+ });
635
+
636
+ // src/core/hash.ts
637
+ import { blake2b } from "@noble/hashes/blake2.js";
638
+ import { sha256 } from "@noble/hashes/sha2.js";
639
+ import { keccak_256 } from "@noble/hashes/sha3.js";
640
+ import { bytesToHex, hexToBytes as hexToBytes2 } from "@noble/hashes/utils.js";
641
+ function computeHash(algorithm, data) {
642
+ const algo = ALGORITHMS[algorithm];
643
+ if (!algo) {
644
+ throw new Error(`Unknown algorithm: ${algorithm}`);
645
+ }
646
+ return algo.compute(data);
647
+ }
648
+ function parseInputData(input) {
649
+ if (input.startsWith("0x")) {
650
+ const hex = input.slice(2);
651
+ if (hex.length % 2 !== 0) {
652
+ throw new Error(`Invalid hex input: odd number of characters`);
653
+ }
654
+ return hexToBytes2(hex);
655
+ }
656
+ return new TextEncoder().encode(input);
657
+ }
658
+ function toHex(bytes) {
659
+ return `0x${bytesToHex(bytes)}`;
660
+ }
661
+ function isValidAlgorithm(name) {
662
+ return name in ALGORITHMS;
663
+ }
664
+ function getAlgorithmNames() {
665
+ return Object.keys(ALGORITHMS);
666
+ }
667
+ var ALGORITHMS;
668
+ var init_hash = __esm(() => {
669
+ ALGORITHMS = {
670
+ blake2b256: {
671
+ compute: (data) => blake2b(data, { dkLen: 32 }),
672
+ outputLen: 32,
673
+ description: "BLAKE2b with 256-bit output"
674
+ },
675
+ blake2b128: {
676
+ compute: (data) => blake2b(data, { dkLen: 16 }),
677
+ outputLen: 16,
678
+ description: "BLAKE2b with 128-bit output"
679
+ },
680
+ keccak256: {
681
+ compute: (data) => keccak_256(data),
682
+ outputLen: 32,
683
+ description: "Keccak-256 (Ethereum-compatible)"
684
+ },
685
+ sha256: {
686
+ compute: (data) => sha256(data),
687
+ outputLen: 32,
688
+ description: "SHA-256"
689
+ }
690
+ };
691
+ });
692
+
693
+ // src/completions/complete.ts
694
+ var exports_complete = {};
695
+ __export(exports_complete, {
696
+ generateCompletions: () => generateCompletions
697
+ });
698
+ function matchCategory2(s) {
699
+ return CATEGORY_ALIASES2[s.toLowerCase()];
700
+ }
701
+ async function loadPallets(_config, chainName) {
702
+ const raw = await loadMetadata(chainName);
703
+ if (!raw)
704
+ return null;
705
+ const meta = parseMetadata(raw);
706
+ return listPallets(meta);
707
+ }
708
+ function filterPallets(pallets, category) {
709
+ switch (category) {
710
+ case "query":
711
+ return pallets.filter((p) => p.storage.length > 0);
712
+ case "tx":
713
+ return pallets.filter((p) => p.calls.length > 0);
714
+ case "const":
715
+ return pallets.filter((p) => p.constants.length > 0);
716
+ case "events":
717
+ return pallets.filter((p) => p.events.length > 0);
718
+ case "errors":
719
+ return pallets.filter((p) => p.errors.length > 0);
720
+ default:
721
+ return pallets;
722
+ }
723
+ }
724
+ function getItemNames(pallet, category) {
725
+ switch (category) {
726
+ case "query":
727
+ return pallet.storage.map((s) => s.name);
728
+ case "tx":
729
+ return pallet.calls.map((c) => c.name);
730
+ case "const":
731
+ return pallet.constants.map((c) => c.name);
732
+ case "events":
733
+ return pallet.events.map((e) => e.name);
734
+ case "errors":
735
+ return pallet.errors.map((e) => e.name);
736
+ default:
737
+ return [];
738
+ }
327
739
  }
328
- function resolveSecret(secret) {
329
- if (isEnvSecret(secret)) {
330
- const value = process.env[secret.env];
331
- if (!value) {
332
- throw new Error(`Environment variable "${secret.env}" is not set. Set it before signing.`);
740
+ function resolveChainFromArgs(precedingWords, _config) {
741
+ for (let i = 0;i < precedingWords.length - 1; i++) {
742
+ if (precedingWords[i] === "--chain") {
743
+ return precedingWords[i + 1];
333
744
  }
334
- return value;
335
745
  }
336
- return secret;
746
+ return;
337
747
  }
338
- function tryDerivePublicKey(envVarName, path = "") {
339
- const value = process.env[envVarName];
340
- if (!value)
341
- return null;
342
- try {
343
- const { publicKey } = importAccount(value, path);
344
- return publicKeyToHex(publicKey);
345
- } catch {
346
- return null;
347
- }
748
+ function filterPrefix(candidates, prefix) {
749
+ if (!prefix)
750
+ return candidates;
751
+ const lower = prefix.toLowerCase();
752
+ return candidates.filter((c) => c.toLowerCase().startsWith(lower));
348
753
  }
349
- async function resolveAccountSigner(name) {
350
- if (isDevAccount(name)) {
351
- const keypair2 = getDevKeypair(name);
352
- return getPolkadotSigner(keypair2.publicKey, "Sr25519", keypair2.sign);
353
- }
354
- const accountsFile = await loadAccounts();
355
- const account = findAccount(accountsFile, name);
356
- if (!account) {
357
- const available = [...DEV_NAMES, ...accountsFile.accounts.map((a) => a.name)];
358
- throw new Error(`Unknown account "${name}". Available accounts: ${available.join(", ")}`);
754
+ async function generateCompletions(currentWord, precedingWords) {
755
+ const config = await loadConfig();
756
+ const knownChains = Object.keys(config.chains);
757
+ const prevWord = precedingWords[precedingWords.length - 1];
758
+ if (prevWord === "--chain") {
759
+ return filterPrefix(knownChains, currentWord);
760
+ }
761
+ if (prevWord === "--output") {
762
+ return filterPrefix(["pretty", "json"], currentWord);
763
+ }
764
+ if (prevWord === "--from") {
765
+ const accounts = await loadAccounts();
766
+ const names = [...DEV_NAMES, ...accounts.accounts.map((a) => a.name)];
767
+ return filterPrefix(names, currentWord);
768
+ }
769
+ if (currentWord.startsWith("--")) {
770
+ const activeCategory = detectCategory(precedingWords, knownChains);
771
+ const options = [...GLOBAL_OPTIONS];
772
+ if (activeCategory === "tx")
773
+ options.push(...TX_OPTIONS);
774
+ if (activeCategory === "query")
775
+ options.push(...QUERY_OPTIONS);
776
+ return filterPrefix(options, currentWord);
777
+ }
778
+ const firstArg = precedingWords.find((w) => !w.startsWith("-"));
779
+ if (firstArg === "chain") {
780
+ return filterPrefix(CHAIN_SUBCOMMANDS, currentWord);
781
+ }
782
+ if (firstArg === "account") {
783
+ return filterPrefix(ACCOUNT_SUBCOMMANDS, currentWord);
784
+ }
785
+ if (firstArg === "hash") {
786
+ return filterPrefix(getAlgorithmNames(), currentWord);
787
+ }
788
+ return completeDotpath(currentWord, config, knownChains, precedingWords);
789
+ }
790
+ function detectCategory(words, _knownChains) {
791
+ for (const w of words) {
792
+ if (w.startsWith("-"))
793
+ continue;
794
+ const parts = w.split(".");
795
+ for (const part of parts) {
796
+ const cat = matchCategory2(part);
797
+ if (cat)
798
+ return cat;
799
+ }
800
+ }
801
+ return;
802
+ }
803
+ async function completeDotpath(currentWord, config, knownChains, precedingWords) {
804
+ const endsWithDot = currentWord.endsWith(".");
805
+ const parts = currentWord.split(".");
806
+ const completeSegments = parts.slice(0, -1);
807
+ const partial = endsWithDot ? "" : parts[parts.length - 1] ?? "";
808
+ const numComplete = completeSegments.length;
809
+ if (numComplete === 0 && !endsWithDot) {
810
+ const candidates = [...CATEGORIES.map(String), ...knownChains, ...NAMED_COMMANDS];
811
+ return filterPrefix(candidates, partial);
812
+ }
813
+ const first = completeSegments[0] ?? "";
814
+ const firstIsCategory = matchCategory2(first) !== undefined;
815
+ const firstIsChain = knownChains.some((c) => c.toLowerCase() === first.toLowerCase());
816
+ const chainFromFlag = resolveChainFromArgs(precedingWords, config);
817
+ if (firstIsCategory) {
818
+ const category = matchCategory2(first);
819
+ if (numComplete === 1 && endsWithDot) {
820
+ const chainName = chainFromFlag ?? config.defaultChain;
821
+ const pallets = await loadPallets(config, chainName);
822
+ if (!pallets)
823
+ return [];
824
+ const filtered = filterPallets(pallets, category);
825
+ const candidates = filtered.map((p) => `${first}.${p.name}`);
826
+ return filterPrefix(candidates, currentWord.slice(0, -1));
827
+ }
828
+ if (numComplete === 1 && !endsWithDot) {
829
+ const chainName = chainFromFlag ?? config.defaultChain;
830
+ const pallets = await loadPallets(config, chainName);
831
+ if (!pallets)
832
+ return [];
833
+ const filtered = filterPallets(pallets, category);
834
+ const candidates = filtered.map((p) => `${first}.${p.name}`);
835
+ return filterPrefix(candidates, currentWord);
836
+ }
837
+ if (numComplete === 2) {
838
+ const palletName2 = completeSegments[1];
839
+ const chainName = chainFromFlag ?? config.defaultChain;
840
+ const pallets = await loadPallets(config, chainName);
841
+ if (!pallets)
842
+ return [];
843
+ const pallet = pallets.find((p) => p.name.toLowerCase() === palletName2.toLowerCase());
844
+ if (!pallet)
845
+ return [];
846
+ const items = getItemNames(pallet, category);
847
+ const candidates = items.map((i) => `${first}.${palletName2}.${i}`);
848
+ return filterPrefix(candidates, endsWithDot ? currentWord.slice(0, -1) : currentWord);
849
+ }
850
+ return [];
359
851
  }
360
- if (account.secret === undefined) {
361
- throw new Error(`Account "${name}" is watch-only (no secret). Cannot sign. Import with --secret or --env.`);
852
+ if (firstIsChain) {
853
+ const chainName = first;
854
+ if (numComplete === 1 && endsWithDot) {
855
+ const candidates = CATEGORIES.map((c) => `${first}.${c}`);
856
+ return filterPrefix(candidates, currentWord.slice(0, -1));
857
+ }
858
+ if (numComplete === 1 && !endsWithDot) {
859
+ const candidates = CATEGORIES.map((c) => `${first}.${c}`);
860
+ return filterPrefix(candidates, currentWord);
861
+ }
862
+ if (numComplete === 2) {
863
+ const category = matchCategory2(completeSegments[1]);
864
+ if (!category)
865
+ return [];
866
+ const pallets = await loadPallets(config, chainName);
867
+ if (!pallets)
868
+ return [];
869
+ const filtered = filterPallets(pallets, category);
870
+ const prefix = `${first}.${completeSegments[1]}`;
871
+ const candidates = filtered.map((p) => `${prefix}.${p.name}`);
872
+ return filterPrefix(candidates, endsWithDot ? currentWord.slice(0, -1) : currentWord);
873
+ }
874
+ if (numComplete === 3) {
875
+ const category = matchCategory2(completeSegments[1]);
876
+ if (!category)
877
+ return [];
878
+ const palletName2 = completeSegments[2];
879
+ const pallets = await loadPallets(config, chainName);
880
+ if (!pallets)
881
+ return [];
882
+ const pallet = pallets.find((p) => p.name.toLowerCase() === palletName2.toLowerCase());
883
+ if (!pallet)
884
+ return [];
885
+ const items = getItemNames(pallet, category);
886
+ const prefix = `${first}.${completeSegments[1]}.${palletName2}`;
887
+ const candidates = items.map((i) => `${prefix}.${i}`);
888
+ return filterPrefix(candidates, endsWithDot ? currentWord.slice(0, -1) : currentWord);
889
+ }
890
+ return [];
362
891
  }
363
- const secret = resolveSecret(account.secret);
364
- const isHexSeed = /^0x[0-9a-fA-F]{64}$/.test(secret);
365
- const keypair = isHexSeed ? deriveFromHexSeed(secret, account.derivationPath) : deriveFromMnemonic(secret, account.derivationPath);
366
- return getPolkadotSigner(keypair.publicKey, "Sr25519", keypair.sign);
367
- }
892
+ return [];
893
+ }
894
+ var CATEGORIES, CATEGORY_ALIASES2, NAMED_COMMANDS, CHAIN_SUBCOMMANDS, ACCOUNT_SUBCOMMANDS, GLOBAL_OPTIONS, TX_OPTIONS, QUERY_OPTIONS;
895
+ var init_complete = __esm(() => {
896
+ init_accounts_store();
897
+ init_store();
898
+ init_accounts();
899
+ init_hash();
900
+ init_metadata();
901
+ CATEGORIES = ["query", "tx", "const", "events", "errors"];
902
+ CATEGORY_ALIASES2 = {
903
+ query: "query",
904
+ tx: "tx",
905
+ const: "const",
906
+ consts: "const",
907
+ constants: "const",
908
+ events: "events",
909
+ event: "events",
910
+ errors: "errors",
911
+ error: "errors"
912
+ };
913
+ NAMED_COMMANDS = ["chain", "account", "inspect", "hash", "completions"];
914
+ CHAIN_SUBCOMMANDS = ["add", "remove", "update", "list", "default"];
915
+ ACCOUNT_SUBCOMMANDS = [
916
+ "add",
917
+ "create",
918
+ "new",
919
+ "import",
920
+ "derive",
921
+ "list",
922
+ "remove",
923
+ "delete",
924
+ "inspect"
925
+ ];
926
+ GLOBAL_OPTIONS = ["--chain", "--rpc", "--light-client", "--output", "--help", "--version"];
927
+ TX_OPTIONS = ["--from", "--dry-run", "--encode", "--ext"];
928
+ QUERY_OPTIONS = ["--limit"];
929
+ });
930
+
931
+ // src/cli.ts
932
+ import cac from "cac";
933
+ // package.json
934
+ var version = "1.3.0";
935
+
936
+ // src/commands/account.ts
937
+ init_accounts_store();
938
+ init_accounts();
368
939
 
369
940
  // src/core/output.ts
370
941
  import { Binary } from "polkadot-api";
@@ -888,35 +1459,17 @@ async function accountInspect(input, opts) {
888
1459
  }
889
1460
  }
890
1461
 
1462
+ // src/commands/chain.ts
1463
+ init_store();
1464
+ init_types();
1465
+
891
1466
  // src/core/client.ts
1467
+ init_store();
1468
+ init_errors();
892
1469
  import { createClient } from "polkadot-api";
893
1470
  import { withPolkadotSdkCompat } from "polkadot-api/polkadot-sdk-compat";
894
1471
  import { getWsProvider } from "polkadot-api/ws-provider";
895
1472
  import { WebSocket } from "ws";
896
-
897
- // src/utils/errors.ts
898
- class CliError extends Error {
899
- constructor(message) {
900
- super(message);
901
- this.name = "CliError";
902
- }
903
- }
904
-
905
- class ConnectionError extends CliError {
906
- constructor(message) {
907
- super(message);
908
- this.name = "ConnectionError";
909
- }
910
- }
911
-
912
- class MetadataError extends CliError {
913
- constructor(message) {
914
- super(message);
915
- this.name = "MetadataError";
916
- }
917
- }
918
-
919
- // src/core/client.ts
920
1473
  var KNOWN_CHAIN_SPECS = {
921
1474
  polkadot: { spec: "polkadot-api/chains/polkadot" },
922
1475
  kusama: { spec: "polkadot-api/chains/ksmcc3" },
@@ -952,270 +1505,52 @@ async function createChainClient(chainName, chainConfig, rpcOverride) {
952
1505
  const rpc = rpcOverride ?? chainConfig.rpc;
953
1506
  if (!rpc) {
954
1507
  restoreConsole();
955
- throw new ConnectionError(`No RPC endpoint configured for chain "${chainName}". Use --rpc or configure one with: dot chain add ${chainName} --rpc <url>`);
956
- }
957
- provider = withPolkadotSdkCompat(getWsProvider(rpc, {
958
- timeout: 1e4,
959
- websocketClass: WebSocket
960
- }));
961
- }
962
- const client = createClient(provider, {
963
- getMetadata: async () => loadMetadata(chainName),
964
- setMetadata: async (_codeHash, metadata) => {
965
- await saveMetadata(chainName, metadata);
966
- }
967
- });
968
- return {
969
- client,
970
- destroy: () => {
971
- client.destroy();
972
- restoreConsole();
973
- }
974
- };
975
- }
976
- async function createSmoldotProvider(chainName) {
977
- const { start } = await import("polkadot-api/smoldot");
978
- const { getSmProvider } = await import("polkadot-api/sm-provider");
979
- const entry = KNOWN_CHAIN_SPECS[chainName];
980
- if (!entry) {
981
- throw new ConnectionError(`Light client is only supported for known chains: ${Object.keys(KNOWN_CHAIN_SPECS).join(", ")}. Use --rpc to connect to "${chainName}" instead.`);
982
- }
983
- const { chainSpec } = await import(entry.spec);
984
- const smoldot = start();
985
- if (entry.relay) {
986
- const relayEntry = KNOWN_CHAIN_SPECS[entry.relay];
987
- if (!relayEntry) {
988
- throw new ConnectionError(`Relay chain "${entry.relay}" not found in known chain specs.`);
989
- }
990
- const { chainSpec: relaySpec } = await import(relayEntry.spec);
991
- const relayChain = await smoldot.addChain({ chainSpec: relaySpec, disableJsonRpc: true });
992
- const chain2 = await smoldot.addChain({ chainSpec, potentialRelayChains: [relayChain] });
993
- return getSmProvider(chain2);
994
- }
995
- const chain = await smoldot.addChain({ chainSpec });
996
- return getSmProvider(chain);
997
- }
998
-
999
- // src/core/metadata.ts
1000
- import { getDynamicBuilder, getLookupFn } from "@polkadot-api/metadata-builders";
1001
- import { decAnyMetadata, unifyMetadata } from "@polkadot-api/substrate-bindings";
1002
- var METADATA_TIMEOUT_MS = 15000;
1003
- function parseMetadata(raw) {
1004
- const decoded = decAnyMetadata(raw);
1005
- const unified = unifyMetadata(decoded);
1006
- const lookup = getLookupFn(unified);
1007
- const builder = getDynamicBuilder(lookup);
1008
- return { unified, lookup, builder };
1009
- }
1010
- async function fetchMetadataFromChain(clientHandle, chainName) {
1011
- const { client } = clientHandle;
1012
- try {
1013
- const hex = await Promise.race([
1014
- client._request("state_getMetadata", []),
1015
- new Promise((_, reject) => setTimeout(() => reject(new ConnectionError(`Timed out fetching metadata for "${chainName}" after ${METADATA_TIMEOUT_MS / 1000}s. ` + "Check that the RPC endpoint is correct and reachable.")), METADATA_TIMEOUT_MS))
1016
- ]);
1017
- const bytes = hexToBytes(hex);
1018
- await saveMetadata(chainName, bytes);
1019
- return bytes;
1020
- } catch (err) {
1021
- if (err instanceof ConnectionError)
1022
- throw err;
1023
- throw new ConnectionError(`Failed to fetch metadata for "${chainName}": ${err instanceof Error ? err.message : err}. ` + "Check that the RPC endpoint is correct and reachable.");
1024
- }
1025
- }
1026
- async function getOrFetchMetadata(chainName, clientHandle) {
1027
- let raw = await loadMetadata(chainName);
1028
- if (!raw) {
1029
- if (!clientHandle) {
1030
- throw new MetadataError(`No cached metadata for chain "${chainName}". Run a command that connects to the chain first, ` + `e.g.: dot chain add ${chainName} --rpc <url>`);
1031
- }
1032
- raw = await fetchMetadataFromChain(clientHandle, chainName);
1033
- }
1034
- return parseMetadata(raw);
1035
- }
1036
- function listPallets(meta) {
1037
- return meta.unified.pallets.map((p) => ({
1038
- name: p.name,
1039
- index: p.index,
1040
- docs: p.docs ?? [],
1041
- storage: (p.storage?.items ?? []).map((s) => ({
1042
- name: s.name,
1043
- docs: s.docs ?? [],
1044
- type: s.type.tag,
1045
- keyTypeId: s.type.tag === "map" ? s.type.value.key : null,
1046
- valueTypeId: s.type.tag === "plain" ? s.type.value : s.type.value.value
1047
- })),
1048
- constants: (p.constants ?? []).map((c) => ({
1049
- name: c.name,
1050
- docs: c.docs ?? [],
1051
- typeId: c.type
1052
- })),
1053
- calls: extractEnumVariants(meta, p.calls),
1054
- events: extractEnumVariants(meta, p.events),
1055
- errors: extractEnumVariants(meta, p.errors).map(({ name, docs }) => ({ name, docs }))
1056
- }));
1057
- }
1058
- function extractEnumVariants(meta, ref) {
1059
- if (!ref)
1060
- return [];
1061
- try {
1062
- const entry = meta.lookup(ref.type);
1063
- if (entry.type !== "enum")
1064
- return [];
1065
- return Object.entries(entry.value).map(([name, variant]) => ({
1066
- name,
1067
- docs: entry.innerDocs?.[name] ?? [],
1068
- typeId: resolveVariantTypeId(variant)
1069
- }));
1070
- } catch {
1071
- return [];
1072
- }
1073
- }
1074
- function resolveVariantTypeId(variant) {
1075
- if (variant.type === "lookupEntry")
1076
- return variant.value?.id ?? null;
1077
- if (variant.type === "struct")
1078
- return null;
1079
- if (variant.type === "void" || variant.type === "empty")
1080
- return null;
1081
- return null;
1082
- }
1083
- function findPallet(meta, palletName) {
1084
- const pallets = listPallets(meta);
1085
- return pallets.find((p) => p.name.toLowerCase() === palletName.toLowerCase());
1086
- }
1087
- function getSignedExtensions(meta) {
1088
- const byVersion = meta.unified.extrinsic.signedExtensions;
1089
- const versionKeys = Object.keys(byVersion);
1090
- if (versionKeys.length === 0)
1091
- return [];
1092
- return byVersion[Number(versionKeys[0])] ?? [];
1093
- }
1094
- function getPalletNames(meta) {
1095
- return meta.unified.pallets.map((p) => p.name);
1096
- }
1097
- function describeType(lookup, typeId) {
1098
- try {
1099
- const entry = lookup(typeId);
1100
- return formatLookupEntry(entry);
1101
- } catch {
1102
- return `type(${typeId})`;
1103
- }
1104
- }
1105
- function formatLookupEntry(entry) {
1106
- switch (entry.type) {
1107
- case "primitive":
1108
- return entry.value;
1109
- case "compact":
1110
- return `Compact<${formatLookupEntry(entry.isBig ? { type: "primitive", value: "u128" } : { type: "primitive", value: "u64" })}>`;
1111
- case "AccountId32":
1112
- return "AccountId32";
1113
- case "bitSequence":
1114
- return "BitSequence";
1115
- case "sequence":
1116
- return `Vec<${formatLookupEntry(entry.value)}>`;
1117
- case "array":
1118
- return `[${formatLookupEntry(entry.value)}; ${entry.len}]`;
1119
- case "tuple":
1120
- return `(${entry.value.map(formatLookupEntry).join(", ")})`;
1121
- case "struct":
1122
- return `{ ${Object.entries(entry.value).map(([k, v]) => `${k}: ${formatLookupEntry(v)}`).join(", ")} }`;
1123
- case "option":
1124
- return `Option<${formatLookupEntry(entry.value)}>`;
1125
- case "result":
1126
- return `Result<${formatLookupEntry(entry.value.ok)}, ${formatLookupEntry(entry.value.ko)}>`;
1127
- case "enum": {
1128
- const variants = Object.keys(entry.value);
1129
- if (variants.length <= 4)
1130
- return variants.join(" | ");
1131
- return `enum(${variants.length} variants)`;
1508
+ throw new ConnectionError(`No RPC endpoint configured for chain "${chainName}". Use --rpc or configure one with: dot chain add ${chainName} --rpc <url>`);
1132
1509
  }
1133
- default:
1134
- return "unknown";
1510
+ provider = withPolkadotSdkCompat(getWsProvider(rpc, {
1511
+ timeout: 1e4,
1512
+ websocketClass: WebSocket
1513
+ }));
1135
1514
  }
1136
- }
1137
- function describeCallArgs(meta, palletName, callName) {
1138
- try {
1139
- const palletMeta = meta.unified.pallets.find((p) => p.name === palletName);
1140
- if (!palletMeta?.calls)
1141
- return "";
1142
- const callsEntry = meta.lookup(palletMeta.calls.type);
1143
- if (callsEntry.type !== "enum")
1144
- return "";
1145
- const variant = callsEntry.value[callName];
1146
- if (!variant)
1147
- return "";
1148
- if (variant.type === "void")
1149
- return "()";
1150
- if (variant.type === "struct") {
1151
- const fields = Object.entries(variant.value).map(([k, v]) => `${k}: ${formatLookupEntry(v)}`).join(", ");
1152
- return `(${fields})`;
1153
- }
1154
- if (variant.type === "lookupEntry") {
1155
- const inner = variant.value;
1156
- if (inner.type === "void")
1157
- return "()";
1158
- if (inner.type === "struct") {
1159
- const fields = Object.entries(inner.value).map(([k, v]) => `${k}: ${formatLookupEntry(v)}`).join(", ");
1160
- return `(${fields})`;
1161
- }
1162
- return `(${formatLookupEntry(inner)})`;
1515
+ const client = createClient(provider, {
1516
+ getMetadata: async () => loadMetadata(chainName),
1517
+ setMetadata: async (_codeHash, metadata) => {
1518
+ await saveMetadata(chainName, metadata);
1163
1519
  }
1164
- if (variant.type === "tuple") {
1165
- const types = variant.value.map(formatLookupEntry).join(", ");
1166
- return `(${types})`;
1520
+ });
1521
+ return {
1522
+ client,
1523
+ destroy: () => {
1524
+ client.destroy();
1525
+ restoreConsole();
1167
1526
  }
1168
- return "";
1169
- } catch {
1170
- return "";
1171
- }
1527
+ };
1172
1528
  }
1173
- function describeEventFields(meta, palletName, eventName) {
1174
- try {
1175
- const palletMeta = meta.unified.pallets.find((p) => p.name === palletName);
1176
- if (!palletMeta?.events)
1177
- return "";
1178
- const eventsEntry = meta.lookup(palletMeta.events.type);
1179
- if (eventsEntry.type !== "enum")
1180
- return "";
1181
- const variant = eventsEntry.value[eventName];
1182
- if (!variant)
1183
- return "";
1184
- if (variant.type === "void")
1185
- return "()";
1186
- if (variant.type === "struct") {
1187
- const fields = Object.entries(variant.value).map(([k, v]) => `${k}: ${formatLookupEntry(v)}`).join(", ");
1188
- return `(${fields})`;
1189
- }
1190
- if (variant.type === "lookupEntry") {
1191
- const inner = variant.value;
1192
- if (inner.type === "void")
1193
- return "()";
1194
- if (inner.type === "struct") {
1195
- const fields = Object.entries(inner.value).map(([k, v]) => `${k}: ${formatLookupEntry(v)}`).join(", ");
1196
- return `(${fields})`;
1197
- }
1198
- return `(${formatLookupEntry(inner)})`;
1199
- }
1200
- if (variant.type === "tuple") {
1201
- const types = variant.value.map(formatLookupEntry).join(", ");
1202
- return `(${types})`;
1203
- }
1204
- return "";
1205
- } catch {
1206
- return "";
1529
+ async function createSmoldotProvider(chainName) {
1530
+ const { start } = await import("polkadot-api/smoldot");
1531
+ const { getSmProvider } = await import("polkadot-api/sm-provider");
1532
+ const entry = KNOWN_CHAIN_SPECS[chainName];
1533
+ if (!entry) {
1534
+ throw new ConnectionError(`Light client is only supported for known chains: ${Object.keys(KNOWN_CHAIN_SPECS).join(", ")}. Use --rpc to connect to "${chainName}" instead.`);
1207
1535
  }
1208
- }
1209
- function hexToBytes(hex) {
1210
- const clean = hex.startsWith("0x") ? hex.slice(2) : hex;
1211
- const bytes = new Uint8Array(clean.length / 2);
1212
- for (let i = 0;i < clean.length; i += 2) {
1213
- bytes[i / 2] = parseInt(clean.substring(i, i + 2), 16);
1536
+ const { chainSpec } = await import(entry.spec);
1537
+ const smoldot = start();
1538
+ if (entry.relay) {
1539
+ const relayEntry = KNOWN_CHAIN_SPECS[entry.relay];
1540
+ if (!relayEntry) {
1541
+ throw new ConnectionError(`Relay chain "${entry.relay}" not found in known chain specs.`);
1542
+ }
1543
+ const { chainSpec: relaySpec } = await import(relayEntry.spec);
1544
+ const relayChain = await smoldot.addChain({ chainSpec: relaySpec, disableJsonRpc: true });
1545
+ const chain2 = await smoldot.addChain({ chainSpec, potentialRelayChains: [relayChain] });
1546
+ return getSmProvider(chain2);
1214
1547
  }
1215
- return bytes;
1548
+ const chain = await smoldot.addChain({ chainSpec });
1549
+ return getSmProvider(chain);
1216
1550
  }
1217
1551
 
1218
1552
  // src/commands/chain.ts
1553
+ init_metadata();
1219
1554
  var CHAIN_HELP = `
1220
1555
  ${BOLD}Usage:${RESET}
1221
1556
  $ dot chain add <name> --rpc <url> Add a chain via WebSocket RPC
@@ -1363,6 +1698,93 @@ async function chainDefault(name) {
1363
1698
  console.log(`Default chain set to "${resolved}".`);
1364
1699
  }
1365
1700
 
1701
+ // src/commands/completions.ts
1702
+ var ZSH_SCRIPT = `_dot_completions() {
1703
+ local -a completions
1704
+ local current_word="\${words[CURRENT]}"
1705
+ local preceding=("\${words[@]:1:CURRENT-2}")
1706
+
1707
+ # Build args: -- <current_word> <preceding_words...>
1708
+ local args=("__complete" "--" "\${current_word}")
1709
+ args+=("\${preceding[@]}")
1710
+
1711
+ local output
1712
+ output="$(dot "\${args[@]}" 2>/dev/null)"
1713
+ [[ -z "$output" ]] && return
1714
+
1715
+ completions=("\${(@f)output}")
1716
+
1717
+ compadd -S '' -- "\${completions[@]}"
1718
+ }
1719
+
1720
+ compdef _dot_completions dot`;
1721
+ var BASH_SCRIPT = `_dot_completions() {
1722
+ local current_word="\${COMP_WORDS[COMP_CWORD]}"
1723
+ local preceding=("\${COMP_WORDS[@]:1:COMP_CWORD-1}")
1724
+
1725
+ # Build args: -- <current_word> <preceding_words...>
1726
+ local args=("__complete" "--" "\${current_word}")
1727
+ args+=("\${preceding[@]}")
1728
+
1729
+ local IFS=$'\\n'
1730
+ local completions
1731
+ completions=($(dot "\${args[@]}" 2>/dev/null))
1732
+
1733
+ [[ \${#completions[@]} -eq 0 ]] && return
1734
+
1735
+ compopt -o nospace
1736
+ COMPREPLY=("\${completions[@]}")
1737
+ }
1738
+
1739
+ complete -F _dot_completions dot`;
1740
+ var FISH_SCRIPT = `function __dot_complete
1741
+ set -l tokens (commandline -opc)
1742
+ set -l current (commandline -ct)
1743
+
1744
+ set -l args "__complete" "--" "$current"
1745
+ for t in $tokens[2..-1]
1746
+ set -a args "$t"
1747
+ end
1748
+
1749
+ dot $args 2>/dev/null
1750
+ end
1751
+
1752
+ complete -c dot -f -a '(__dot_complete)'`;
1753
+ var SETUP_INSTRUCTIONS = {
1754
+ zsh: `# Add this to your ~/.zshrc:
1755
+ # eval "$(dot completions zsh)"
1756
+ # Then restart your shell or run: source ~/.zshrc`,
1757
+ bash: `# Add this to your ~/.bashrc:
1758
+ # eval "$(dot completions bash)"
1759
+ # Then restart your shell or run: source ~/.bashrc`,
1760
+ fish: `# Save this to ~/.config/fish/completions/dot.fish:
1761
+ # dot completions fish > ~/.config/fish/completions/dot.fish`
1762
+ };
1763
+ var SCRIPTS = {
1764
+ zsh: ZSH_SCRIPT,
1765
+ bash: BASH_SCRIPT,
1766
+ fish: FISH_SCRIPT
1767
+ };
1768
+ function registerCompletionsCommand(cli) {
1769
+ cli.command("completions <shell>", "Generate shell completion script (zsh, bash, fish)").action((shell) => {
1770
+ const script = SCRIPTS[shell];
1771
+ if (!script) {
1772
+ console.error(`Unsupported shell "${shell}". Supported: ${Object.keys(SCRIPTS).join(", ")}`);
1773
+ process.exit(1);
1774
+ }
1775
+ const instructions = SETUP_INSTRUCTIONS[shell];
1776
+ if (instructions) {
1777
+ process.stderr.write(`${instructions}
1778
+ `);
1779
+ }
1780
+ console.log(script);
1781
+ });
1782
+ }
1783
+
1784
+ // src/commands/const.ts
1785
+ init_store();
1786
+ init_metadata();
1787
+
1366
1788
  // src/utils/fuzzy-match.ts
1367
1789
  function levenshtein(a, b) {
1368
1790
  const la = a.length;
@@ -1400,6 +1822,8 @@ function suggestMessage(kind, input, candidates) {
1400
1822
  }
1401
1823
 
1402
1824
  // src/commands/focused-inspect.ts
1825
+ init_store();
1826
+ init_metadata();
1403
1827
  async function loadMeta(chainName, chainConfig, rpcOverride) {
1404
1828
  try {
1405
1829
  return await getOrFetchMetadata(chainName);
@@ -1842,6 +2266,8 @@ async function handleConst(target, opts) {
1842
2266
  }
1843
2267
 
1844
2268
  // src/commands/focused-inspect.ts
2269
+ init_store();
2270
+ init_metadata();
1845
2271
  async function loadMeta2(chainName, chainConfig, rpcOverride) {
1846
2272
  try {
1847
2273
  return await getOrFetchMetadata(chainName);
@@ -2217,61 +2643,9 @@ async function showItemHelp2(category, target, opts) {
2217
2643
  }
2218
2644
  }
2219
2645
 
2220
- // src/core/hash.ts
2221
- import { blake2b } from "@noble/hashes/blake2.js";
2222
- import { sha256 } from "@noble/hashes/sha2.js";
2223
- import { keccak_256 } from "@noble/hashes/sha3.js";
2224
- import { bytesToHex, hexToBytes as hexToBytes2 } from "@noble/hashes/utils.js";
2225
- var ALGORITHMS = {
2226
- blake2b256: {
2227
- compute: (data) => blake2b(data, { dkLen: 32 }),
2228
- outputLen: 32,
2229
- description: "BLAKE2b with 256-bit output"
2230
- },
2231
- blake2b128: {
2232
- compute: (data) => blake2b(data, { dkLen: 16 }),
2233
- outputLen: 16,
2234
- description: "BLAKE2b with 128-bit output"
2235
- },
2236
- keccak256: {
2237
- compute: (data) => keccak_256(data),
2238
- outputLen: 32,
2239
- description: "Keccak-256 (Ethereum-compatible)"
2240
- },
2241
- sha256: {
2242
- compute: (data) => sha256(data),
2243
- outputLen: 32,
2244
- description: "SHA-256"
2245
- }
2246
- };
2247
- function computeHash(algorithm, data) {
2248
- const algo = ALGORITHMS[algorithm];
2249
- if (!algo) {
2250
- throw new Error(`Unknown algorithm: ${algorithm}`);
2251
- }
2252
- return algo.compute(data);
2253
- }
2254
- function parseInputData(input) {
2255
- if (input.startsWith("0x")) {
2256
- const hex = input.slice(2);
2257
- if (hex.length % 2 !== 0) {
2258
- throw new Error(`Invalid hex input: odd number of characters`);
2259
- }
2260
- return hexToBytes2(hex);
2261
- }
2262
- return new TextEncoder().encode(input);
2263
- }
2264
- function toHex(bytes) {
2265
- return `0x${bytesToHex(bytes)}`;
2266
- }
2267
- function isValidAlgorithm(name) {
2268
- return name in ALGORITHMS;
2269
- }
2270
- function getAlgorithmNames() {
2271
- return Object.keys(ALGORITHMS);
2272
- }
2273
-
2274
2646
  // src/commands/hash.ts
2647
+ init_hash();
2648
+ init_errors();
2275
2649
  async function resolveInput(data, opts) {
2276
2650
  const sources = [data !== undefined, !!opts.file, !!opts.stdin].filter(Boolean).length;
2277
2651
  if (sources > 1) {
@@ -2348,6 +2722,10 @@ function registerHashCommand(cli) {
2348
2722
  });
2349
2723
  }
2350
2724
 
2725
+ // src/commands/inspect.ts
2726
+ init_store();
2727
+ init_metadata();
2728
+
2351
2729
  // src/utils/parse-target.ts
2352
2730
  function parseTarget(input, options) {
2353
2731
  const parts = input.split(".");
@@ -2598,6 +2976,10 @@ function registerInspectCommand(cli) {
2598
2976
  });
2599
2977
  }
2600
2978
 
2979
+ // src/commands/query.ts
2980
+ init_store();
2981
+ init_metadata();
2982
+
2601
2983
  // src/utils/parse-value.ts
2602
2984
  function parseValue(arg) {
2603
2985
  if (/^\d+$/.test(arg))
@@ -2619,6 +3001,9 @@ function parseValue(arg) {
2619
3001
  }
2620
3002
 
2621
3003
  // src/commands/tx.ts
3004
+ init_store();
3005
+ init_types();
3006
+ init_accounts();
2622
3007
  import { getViewBuilder } from "@polkadot-api/view-builder";
2623
3008
  import { Binary as Binary2 } from "polkadot-api";
2624
3009
 
@@ -2626,7 +3011,12 @@ import { Binary as Binary2 } from "polkadot-api";
2626
3011
  var pjsAppsLink = (rpc, hash) => `https://polkadot.js.org/apps/?rpc=${encodeURIComponent(rpc)}#/explorer/query/${hash}`;
2627
3012
  var papiLink = (rpc, hash) => `https://dev.papi.how/explorer/${hash}#networkId=custom&endpoint=${encodeURIComponent(rpc)}`;
2628
3013
 
3014
+ // src/commands/tx.ts
3015
+ init_metadata();
3016
+
2629
3017
  // src/core/resolve-address.ts
3018
+ init_accounts_store();
3019
+ init_accounts();
2630
3020
  async function resolveAccountAddress(input) {
2631
3021
  if (isDevAccount(input)) {
2632
3022
  return getDevAddress(input);
@@ -2654,6 +3044,7 @@ async function resolveAccountAddress(input) {
2654
3044
  }
2655
3045
 
2656
3046
  // src/commands/tx.ts
3047
+ init_errors();
2657
3048
  async function parseStructArgs(meta, fields, args, callLabel) {
2658
3049
  const fieldNames = Object.keys(fields);
2659
3050
  if (args.length !== fieldNames.length) {
@@ -3074,8 +3465,13 @@ async function parseStorageKeys(meta, palletName2, storageItem, args) {
3074
3465
  }
3075
3466
 
3076
3467
  // src/commands/tx.ts
3468
+ init_store();
3469
+ init_types();
3470
+ init_accounts();
3077
3471
  import { getViewBuilder as getViewBuilder2 } from "@polkadot-api/view-builder";
3078
3472
  import { Binary as Binary3 } from "polkadot-api";
3473
+ init_metadata();
3474
+ init_errors();
3079
3475
  async function handleTx(target, args, opts) {
3080
3476
  if (!target) {
3081
3477
  const config2 = await loadConfig();
@@ -3865,6 +4261,7 @@ function watchTransaction(observable) {
3865
4261
  }
3866
4262
 
3867
4263
  // src/config/store.ts
4264
+ init_types();
3868
4265
  import { access as access3, mkdir as mkdir3, readFile as readFile3, rm as rm2, writeFile as writeFile3 } from "node:fs/promises";
3869
4266
  import { homedir as homedir2 } from "node:os";
3870
4267
  import { join as join3 } from "node:path";
@@ -3901,6 +4298,7 @@ async function saveConfig2(config) {
3901
4298
  }
3902
4299
 
3903
4300
  // src/core/update-notifier.ts
4301
+ init_store();
3904
4302
  import { readFileSync } from "node:fs";
3905
4303
  import { mkdir as mkdir4, writeFile as writeFile4 } from "node:fs/promises";
3906
4304
  import { join as join4 } from "node:path";
@@ -4089,159 +4487,180 @@ function parseDotPath(input, knownChains = []) {
4089
4487
  }
4090
4488
 
4091
4489
  // src/cli.ts
4092
- startBackgroundCheck(version);
4093
- var cli = cac("dot");
4094
- cli.option("--chain <name>", "Target chain (default from config)");
4095
- cli.option("--rpc <url>", "Override RPC endpoint for this call");
4096
- cli.option("--light-client", "Use Smoldot light client instead of WebSocket");
4097
- cli.option("--output <format>", "Output format: pretty or json", {
4098
- default: "pretty"
4099
- });
4100
- registerChainCommands(cli);
4101
- registerInspectCommand(cli);
4102
- registerAccountCommands(cli);
4103
- registerHashCommand(cli);
4104
- cli.command("[dotpath] [...args]").option("--from <name>", "Account to sign with (for tx)").option("--dry-run", "Estimate fees without submitting (for tx)").option("--encode", "Encode call to hex without signing (for tx)").option("--ext <json>", "Custom signed extension values as JSON (for tx)").option("--limit <n>", "Max entries to return for map queries (0 = unlimited)", {
4105
- default: 100
4106
- }).action(async (dotpath, args, opts) => {
4107
- if (!dotpath) {
4108
- printHelp();
4109
- return;
4110
- }
4111
- const config = await loadConfig2();
4112
- const knownChains = Object.keys(config.chains);
4113
- let parsed;
4114
- try {
4115
- parsed = parseDotPath(dotpath, knownChains);
4116
- } catch {
4117
- throw new CliError2(`Unknown command "${dotpath}". Run "dot --help" for available commands.`);
4118
- }
4119
- if (parsed.chain && opts.chain) {
4120
- throw new CliError2(`Chain specified both as prefix ("${parsed.chain}") and as --chain flag ("${opts.chain}"). Use one or the other.`);
4121
- }
4122
- const effectiveChain = parsed.chain ?? opts.chain;
4123
- const handlerOpts = { chain: effectiveChain, rpc: opts.rpc, output: opts.output };
4124
- const target = parsed.pallet ? parsed.item ? `${parsed.pallet}.${parsed.item}` : parsed.pallet : undefined;
4125
- if (cli.options.help && parsed.pallet && parsed.item) {
4126
- await showItemHelp2(parsed.category, target, handlerOpts);
4127
- return;
4128
- }
4129
- switch (parsed.category) {
4130
- case "query":
4131
- await handleQuery(target, args, { ...handlerOpts, limit: opts.limit });
4132
- break;
4133
- case "tx":
4134
- if (parsed.pallet && /^0x[0-9a-fA-F]+$/.test(parsed.pallet)) {
4135
- await handleTx(parsed.pallet, args, {
4136
- ...handlerOpts,
4137
- from: opts.from,
4138
- dryRun: opts.dryRun,
4139
- encode: opts.encode,
4140
- ext: opts.ext
4141
- });
4142
- } else {
4143
- await handleTx(target, args, {
4144
- ...handlerOpts,
4145
- from: opts.from,
4146
- dryRun: opts.dryRun,
4147
- encode: opts.encode,
4148
- ext: opts.ext
4149
- });
4490
+ if (process.argv[2] === "__complete") {
4491
+ (async () => {
4492
+ try {
4493
+ const dashDashIndex = process.argv.indexOf("--");
4494
+ const completionArgs = dashDashIndex >= 0 ? process.argv.slice(dashDashIndex + 1) : [];
4495
+ const currentWord = completionArgs[0] ?? "";
4496
+ const precedingWords = completionArgs.slice(1);
4497
+ const { generateCompletions: generateCompletions2 } = await Promise.resolve().then(() => (init_complete(), exports_complete));
4498
+ const results = await generateCompletions2(currentWord, precedingWords);
4499
+ if (results.length > 0) {
4500
+ process.stdout.write(`${results.join(`
4501
+ `)}
4502
+ `);
4150
4503
  }
4151
- break;
4152
- case "const":
4153
- await handleConst(target, handlerOpts);
4154
- break;
4155
- case "events":
4156
- await handleEvents2(target, handlerOpts);
4157
- break;
4158
- case "errors":
4159
- await handleErrors2(target, handlerOpts);
4160
- break;
4161
- }
4162
- });
4163
- cli.option("--help, -h", "Display this message");
4164
- cli.version(version);
4165
- function printHelp() {
4166
- console.log(`dot/${version} \u2014 Polkadot CLI`);
4167
- console.log();
4168
- console.log("Usage:");
4169
- console.log(" dot <category>[.Pallet[.Item]] [args] [options]");
4170
- console.log(" dot [Chain.]<category>[.Pallet[.Item]] [args] [options]");
4171
- console.log();
4172
- console.log("Categories:");
4173
- console.log(" query Query on-chain storage");
4174
- console.log(" tx Submit an extrinsic");
4175
- console.log(" const Look up or list pallet constants");
4176
- console.log(" events List or inspect pallet events");
4177
- console.log(" errors List or inspect pallet errors");
4178
- console.log();
4179
- console.log("Examples:");
4180
- console.log(" dot query.System.Account <addr> Query a storage item");
4181
- console.log(" dot query.System List storage items in System");
4182
- console.log(" dot tx.System.remark 0xdead --from alice");
4183
- console.log(" dot const.Balances.ExistentialDeposit");
4184
- console.log(" dot events.Balances List events in Balances");
4185
- console.log(" dot polkadot.query.System.Number With chain prefix");
4186
- console.log();
4187
- console.log("Commands:");
4188
- console.log(" inspect [target] Inspect chain metadata (alias: explore)");
4189
- console.log(" chain Manage chain configurations");
4190
- console.log(" account Manage accounts");
4191
- console.log(" hash Hash utilities");
4192
- console.log();
4193
- console.log("Global options:");
4194
- console.log(" --chain <name> Target chain (default from config)");
4195
- console.log(" --rpc <url> Override RPC endpoint");
4196
- console.log(" --light-client Use Smoldot light client");
4197
- console.log(" --output <format> Output format: pretty or json");
4198
- console.log(" --help, -h Display this message");
4199
- console.log(" --version Show version");
4200
- }
4201
- async function showUpdateAndExit(code) {
4202
- await waitForPendingCheck();
4203
- const note = getUpdateNotification(version);
4204
- if (note)
4205
- process.stderr.write(`${note}
4504
+ } catch {}
4505
+ process.exit(0);
4506
+ })();
4507
+ } else {
4508
+ let printHelp = function() {
4509
+ console.log(`dot/${version} \u2014 Polkadot CLI`);
4510
+ console.log();
4511
+ console.log("Usage:");
4512
+ console.log(" dot <category>[.Pallet[.Item]] [args] [options]");
4513
+ console.log(" dot [Chain.]<category>[.Pallet[.Item]] [args] [options]");
4514
+ console.log();
4515
+ console.log("Categories:");
4516
+ console.log(" query Query on-chain storage");
4517
+ console.log(" tx Submit an extrinsic");
4518
+ console.log(" const Look up or list pallet constants");
4519
+ console.log(" events List or inspect pallet events");
4520
+ console.log(" errors List or inspect pallet errors");
4521
+ console.log();
4522
+ console.log("Examples:");
4523
+ console.log(" dot query.System.Account <addr> Query a storage item");
4524
+ console.log(" dot query.System List storage items in System");
4525
+ console.log(" dot tx.System.remark 0xdead --from alice");
4526
+ console.log(" dot const.Balances.ExistentialDeposit");
4527
+ console.log(" dot events.Balances List events in Balances");
4528
+ console.log(" dot polkadot.query.System.Number With chain prefix");
4529
+ console.log();
4530
+ console.log("Commands:");
4531
+ console.log(" inspect [target] Inspect chain metadata (alias: explore)");
4532
+ console.log(" chain Manage chain configurations");
4533
+ console.log(" account Manage accounts");
4534
+ console.log(" hash Hash utilities");
4535
+ console.log(" completions <sh> Generate shell completions (zsh, bash, fish)");
4536
+ console.log();
4537
+ console.log("Global options:");
4538
+ console.log(" --chain <name> Target chain (default from config)");
4539
+ console.log(" --rpc <url> Override RPC endpoint");
4540
+ console.log(" --light-client Use Smoldot light client");
4541
+ console.log(" --output <format> Output format: pretty or json");
4542
+ console.log(" --help, -h Display this message");
4543
+ console.log(" --version Show version");
4544
+ };
4545
+ startBackgroundCheck(version);
4546
+ const cli = cac("dot");
4547
+ cli.option("--chain <name>", "Target chain (default from config)");
4548
+ cli.option("--rpc <url>", "Override RPC endpoint for this call");
4549
+ cli.option("--light-client", "Use Smoldot light client instead of WebSocket");
4550
+ cli.option("--output <format>", "Output format: pretty or json", {
4551
+ default: "pretty"
4552
+ });
4553
+ registerChainCommands(cli);
4554
+ registerInspectCommand(cli);
4555
+ registerAccountCommands(cli);
4556
+ registerHashCommand(cli);
4557
+ registerCompletionsCommand(cli);
4558
+ cli.command("[dotpath] [...args]").option("--from <name>", "Account to sign with (for tx)").option("--dry-run", "Estimate fees without submitting (for tx)").option("--encode", "Encode call to hex without signing (for tx)").option("--ext <json>", "Custom signed extension values as JSON (for tx)").option("--limit <n>", "Max entries to return for map queries (0 = unlimited)", {
4559
+ default: 100
4560
+ }).action(async (dotpath, args, opts) => {
4561
+ if (!dotpath) {
4562
+ printHelp();
4563
+ return;
4564
+ }
4565
+ const config = await loadConfig2();
4566
+ const knownChains = Object.keys(config.chains);
4567
+ let parsed;
4568
+ try {
4569
+ parsed = parseDotPath(dotpath, knownChains);
4570
+ } catch {
4571
+ throw new CliError2(`Unknown command "${dotpath}". Run "dot --help" for available commands.`);
4572
+ }
4573
+ if (parsed.chain && opts.chain) {
4574
+ throw new CliError2(`Chain specified both as prefix ("${parsed.chain}") and as --chain flag ("${opts.chain}"). Use one or the other.`);
4575
+ }
4576
+ const effectiveChain = parsed.chain ?? opts.chain;
4577
+ const handlerOpts = { chain: effectiveChain, rpc: opts.rpc, output: opts.output };
4578
+ const target = parsed.pallet ? parsed.item ? `${parsed.pallet}.${parsed.item}` : parsed.pallet : undefined;
4579
+ if (cli.options.help && parsed.pallet && parsed.item) {
4580
+ await showItemHelp2(parsed.category, target, handlerOpts);
4581
+ return;
4582
+ }
4583
+ switch (parsed.category) {
4584
+ case "query":
4585
+ await handleQuery(target, args, { ...handlerOpts, limit: opts.limit });
4586
+ break;
4587
+ case "tx":
4588
+ if (parsed.pallet && /^0x[0-9a-fA-F]+$/.test(parsed.pallet)) {
4589
+ await handleTx(parsed.pallet, args, {
4590
+ ...handlerOpts,
4591
+ from: opts.from,
4592
+ dryRun: opts.dryRun,
4593
+ encode: opts.encode,
4594
+ ext: opts.ext
4595
+ });
4596
+ } else {
4597
+ await handleTx(target, args, {
4598
+ ...handlerOpts,
4599
+ from: opts.from,
4600
+ dryRun: opts.dryRun,
4601
+ encode: opts.encode,
4602
+ ext: opts.ext
4603
+ });
4604
+ }
4605
+ break;
4606
+ case "const":
4607
+ await handleConst(target, handlerOpts);
4608
+ break;
4609
+ case "events":
4610
+ await handleEvents2(target, handlerOpts);
4611
+ break;
4612
+ case "errors":
4613
+ await handleErrors2(target, handlerOpts);
4614
+ break;
4615
+ }
4616
+ });
4617
+ cli.option("--help, -h", "Display this message");
4618
+ cli.version(version);
4619
+ async function showUpdateAndExit(code) {
4620
+ await waitForPendingCheck();
4621
+ const note = getUpdateNotification(version);
4622
+ if (note)
4623
+ process.stderr.write(`${note}
4206
4624
  `);
4207
- process.exit(code);
4208
- }
4209
- async function handleError(err) {
4210
- if (err instanceof CliError2) {
4211
- console.error(`Error: ${err.message}`);
4212
- } else if (err instanceof Error) {
4213
- console.error(`Error: ${err.message}`);
4214
- } else {
4215
- console.error("An unexpected error occurred:", err);
4625
+ process.exit(code);
4216
4626
  }
4217
- return showUpdateAndExit(1);
4218
- }
4219
- async function main() {
4220
- try {
4221
- cli.parse(process.argv, { run: false });
4222
- if (cli.options.version) {
4223
- await showUpdateAndExit(0);
4224
- } else if (cli.options.help) {
4225
- if (cli.matchedCommand) {
4627
+ async function handleError(err) {
4628
+ if (err instanceof CliError2) {
4629
+ console.error(`Error: ${err.message}`);
4630
+ } else if (err instanceof Error) {
4631
+ console.error(`Error: ${err.message}`);
4632
+ } else {
4633
+ console.error("An unexpected error occurred:", err);
4634
+ }
4635
+ return showUpdateAndExit(1);
4636
+ }
4637
+ async function main() {
4638
+ try {
4639
+ cli.parse(process.argv, { run: false });
4640
+ if (cli.options.version) {
4641
+ await showUpdateAndExit(0);
4642
+ } else if (cli.options.help) {
4643
+ if (cli.matchedCommand) {
4644
+ const result = cli.runMatchedCommand();
4645
+ if (result && typeof result.then === "function") {
4646
+ await result.then(() => showUpdateAndExit(0), handleError);
4647
+ }
4648
+ } else {
4649
+ printHelp();
4650
+ await showUpdateAndExit(0);
4651
+ }
4652
+ } else if (!cli.matchedCommand) {
4653
+ printHelp();
4654
+ await showUpdateAndExit(0);
4655
+ } else {
4226
4656
  const result = cli.runMatchedCommand();
4227
4657
  if (result && typeof result.then === "function") {
4228
4658
  await result.then(() => showUpdateAndExit(0), handleError);
4229
4659
  }
4230
- } else {
4231
- printHelp();
4232
- await showUpdateAndExit(0);
4233
- }
4234
- } else if (!cli.matchedCommand) {
4235
- printHelp();
4236
- await showUpdateAndExit(0);
4237
- } else {
4238
- const result = cli.runMatchedCommand();
4239
- if (result && typeof result.then === "function") {
4240
- await result.then(() => showUpdateAndExit(0), handleError);
4241
4660
  }
4661
+ } catch (err) {
4662
+ await handleError(err);
4242
4663
  }
4243
- } catch (err) {
4244
- await handleError(err);
4245
4664
  }
4665
+ main();
4246
4666
  }
4247
- main();