polkadot-cli 1.12.0 → 1.13.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/README.md +113 -45
- package/dist/cli.mjs +1084 -253
- package/package.json +8 -10
package/dist/cli.mjs
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { createRequire } from "node:module";
|
|
3
2
|
var __defProp = Object.defineProperty;
|
|
4
3
|
var __returnValue = (v) => v;
|
|
5
4
|
function __exportSetter(name, newValue) {
|
|
@@ -15,7 +14,6 @@ var __export = (target, all) => {
|
|
|
15
14
|
});
|
|
16
15
|
};
|
|
17
16
|
var __esm = (fn, res) => () => (fn && (res = fn(fn = 0)), res);
|
|
18
|
-
var __require = /* @__PURE__ */ createRequire(import.meta.url);
|
|
19
17
|
|
|
20
18
|
// src/config/types.ts
|
|
21
19
|
function primaryRpc(rpc) {
|
|
@@ -53,7 +51,9 @@ var init_types = __esm(() => {
|
|
|
53
51
|
"wss://statemint-rpc-tn.dwellir.com",
|
|
54
52
|
"wss://statemint.public.curie.radiumblock.co/ws",
|
|
55
53
|
"wss://asset-hub-polkadot.rpc.permanence.io"
|
|
56
|
-
]
|
|
54
|
+
],
|
|
55
|
+
relay: "polkadot",
|
|
56
|
+
parachainId: 1000
|
|
57
57
|
},
|
|
58
58
|
"polkadot-bridge-hub": {
|
|
59
59
|
rpc: [
|
|
@@ -65,7 +65,9 @@ var init_types = __esm(() => {
|
|
|
65
65
|
"wss://bridgehub-polkadot.api.onfinality.io/public-ws",
|
|
66
66
|
"wss://polkadot-bridge-hub-rpc-tn.dwellir.com",
|
|
67
67
|
"wss://bridgehub-polkadot.public.curie.radiumblock.co/ws"
|
|
68
|
-
]
|
|
68
|
+
],
|
|
69
|
+
relay: "polkadot",
|
|
70
|
+
parachainId: 1002
|
|
69
71
|
},
|
|
70
72
|
"polkadot-collectives": {
|
|
71
73
|
rpc: [
|
|
@@ -77,7 +79,9 @@ var init_types = __esm(() => {
|
|
|
77
79
|
"wss://collectives.api.onfinality.io/public-ws",
|
|
78
80
|
"wss://polkadot-collectives-rpc-tn.dwellir.com",
|
|
79
81
|
"wss://collectives.public.curie.radiumblock.co/ws"
|
|
80
|
-
]
|
|
82
|
+
],
|
|
83
|
+
relay: "polkadot",
|
|
84
|
+
parachainId: 1001
|
|
81
85
|
},
|
|
82
86
|
"polkadot-coretime": {
|
|
83
87
|
rpc: [
|
|
@@ -87,7 +91,9 @@ var init_types = __esm(() => {
|
|
|
87
91
|
"wss://coretime-polkadot-rpc.n.dwellir.com",
|
|
88
92
|
"wss://rpc-coretime-polkadot.luckyfriday.io",
|
|
89
93
|
"wss://coretime-polkadot.api.onfinality.io/public-ws"
|
|
90
|
-
]
|
|
94
|
+
],
|
|
95
|
+
relay: "polkadot",
|
|
96
|
+
parachainId: 1005
|
|
91
97
|
},
|
|
92
98
|
"polkadot-people": {
|
|
93
99
|
rpc: [
|
|
@@ -97,7 +103,9 @@ var init_types = __esm(() => {
|
|
|
97
103
|
"wss://people-polkadot-rpc.n.dwellir.com",
|
|
98
104
|
"wss://rpc-people-polkadot.luckyfriday.io",
|
|
99
105
|
"wss://people-polkadot.api.onfinality.io/public-ws"
|
|
100
|
-
]
|
|
106
|
+
],
|
|
107
|
+
relay: "polkadot",
|
|
108
|
+
parachainId: 1004
|
|
101
109
|
},
|
|
102
110
|
paseo: {
|
|
103
111
|
rpc: [
|
|
@@ -113,23 +121,33 @@ var init_types = __esm(() => {
|
|
|
113
121
|
"wss://asset-hub-paseo.dotters.network",
|
|
114
122
|
"wss://asset-hub-paseo-rpc.n.dwellir.com",
|
|
115
123
|
"wss://sys.turboflakes.io/asset-hub-paseo"
|
|
116
|
-
]
|
|
124
|
+
],
|
|
125
|
+
relay: "paseo",
|
|
126
|
+
parachainId: 1000
|
|
117
127
|
},
|
|
118
128
|
"paseo-bridge-hub": {
|
|
119
|
-
rpc: ["wss://bridge-hub-paseo.ibp.network", "wss://bridge-hub-paseo.dotters.network"]
|
|
129
|
+
rpc: ["wss://bridge-hub-paseo.ibp.network", "wss://bridge-hub-paseo.dotters.network"],
|
|
130
|
+
relay: "paseo",
|
|
131
|
+
parachainId: 1002
|
|
120
132
|
},
|
|
121
133
|
"paseo-collectives": {
|
|
122
|
-
rpc: ["wss://collectives-paseo.ibp.network", "wss://collectives-paseo.dotters.network"]
|
|
134
|
+
rpc: ["wss://collectives-paseo.ibp.network", "wss://collectives-paseo.dotters.network"],
|
|
135
|
+
relay: "paseo",
|
|
136
|
+
parachainId: 1001
|
|
123
137
|
},
|
|
124
138
|
"paseo-coretime": {
|
|
125
|
-
rpc: ["wss://coretime-paseo.ibp.network", "wss://coretime-paseo.dotters.network"]
|
|
139
|
+
rpc: ["wss://coretime-paseo.ibp.network", "wss://coretime-paseo.dotters.network"],
|
|
140
|
+
relay: "paseo",
|
|
141
|
+
parachainId: 1005
|
|
126
142
|
},
|
|
127
143
|
"paseo-people": {
|
|
128
144
|
rpc: [
|
|
129
145
|
"wss://people-paseo.ibp.network",
|
|
130
146
|
"wss://people-paseo.dotters.network",
|
|
131
147
|
"wss://people-paseo.rpc.amforc.com"
|
|
132
|
-
]
|
|
148
|
+
],
|
|
149
|
+
relay: "paseo",
|
|
150
|
+
parachainId: 1004
|
|
133
151
|
}
|
|
134
152
|
}
|
|
135
153
|
};
|
|
@@ -164,10 +182,16 @@ async function loadConfig() {
|
|
|
164
182
|
await ensureDir(DOT_DIR);
|
|
165
183
|
if (await fileExists(CONFIG_PATH)) {
|
|
166
184
|
const saved = JSON.parse(await readFile(CONFIG_PATH, "utf-8"));
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
chains
|
|
170
|
-
}
|
|
185
|
+
const chains = {};
|
|
186
|
+
for (const [name, defaultConfig] of Object.entries(DEFAULT_CONFIG.chains)) {
|
|
187
|
+
chains[name] = saved.chains[name] ? { ...defaultConfig, ...saved.chains[name] } : defaultConfig;
|
|
188
|
+
}
|
|
189
|
+
for (const [name, config] of Object.entries(saved.chains)) {
|
|
190
|
+
if (!(name in DEFAULT_CONFIG.chains)) {
|
|
191
|
+
chains[name] = config;
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
return { ...saved, chains };
|
|
171
195
|
}
|
|
172
196
|
await saveConfig(DEFAULT_CONFIG);
|
|
173
197
|
return DEFAULT_CONFIG;
|
|
@@ -259,6 +283,42 @@ function isWatchOnly(account) {
|
|
|
259
283
|
return account.secret === undefined;
|
|
260
284
|
}
|
|
261
285
|
|
|
286
|
+
// src/utils/fuzzy-match.ts
|
|
287
|
+
function levenshtein(a, b) {
|
|
288
|
+
const la = a.length;
|
|
289
|
+
const lb = b.length;
|
|
290
|
+
const dp = Array.from({ length: la + 1 }, () => Array(lb + 1).fill(0));
|
|
291
|
+
for (let i = 0;i <= la; i++)
|
|
292
|
+
dp[i][0] = i;
|
|
293
|
+
for (let j = 0;j <= lb; j++)
|
|
294
|
+
dp[0][j] = j;
|
|
295
|
+
for (let i = 1;i <= la; i++) {
|
|
296
|
+
for (let j = 1;j <= lb; j++) {
|
|
297
|
+
const cost = a[i - 1] === b[j - 1] ? 0 : 1;
|
|
298
|
+
dp[i][j] = Math.min(dp[i - 1][j] + 1, dp[i][j - 1] + 1, dp[i - 1][j - 1] + cost);
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
return dp[la][lb];
|
|
302
|
+
}
|
|
303
|
+
function findClosest(input, candidates, maxDistance = 3) {
|
|
304
|
+
const lower = input.toLowerCase();
|
|
305
|
+
const exact = candidates.find((c) => c.toLowerCase() === lower);
|
|
306
|
+
if (exact)
|
|
307
|
+
return [exact];
|
|
308
|
+
const scored = candidates.map((c) => ({ name: c, dist: levenshtein(lower, c.toLowerCase()) })).filter((s) => s.dist <= maxDistance).sort((a, b) => a.dist - b.dist);
|
|
309
|
+
return scored.slice(0, 3).map((s) => s.name);
|
|
310
|
+
}
|
|
311
|
+
function suggestMessage(kind, input, candidates) {
|
|
312
|
+
const suggestions = findClosest(input, candidates);
|
|
313
|
+
if (suggestions.length === 0) {
|
|
314
|
+
return `Unknown ${kind} "${input}".`;
|
|
315
|
+
}
|
|
316
|
+
if (suggestions.length === 1 && suggestions[0]?.toLowerCase() === input.toLowerCase()) {
|
|
317
|
+
return suggestions[0];
|
|
318
|
+
}
|
|
319
|
+
return `Unknown ${kind} "${input}". Did you mean: ${suggestions.join(", ")}?`;
|
|
320
|
+
}
|
|
321
|
+
|
|
262
322
|
// src/core/accounts.ts
|
|
263
323
|
import { sr25519CreateDerive } from "@polkadot-labs/hdkd";
|
|
264
324
|
import {
|
|
@@ -369,8 +429,14 @@ async function resolveAccountKeypair(name) {
|
|
|
369
429
|
const accountsFile = await loadAccounts();
|
|
370
430
|
const account = findAccount(accountsFile, name);
|
|
371
431
|
if (!account) {
|
|
372
|
-
const available = [...DEV_NAMES, ...accountsFile.accounts.map((a) => a.name)];
|
|
373
|
-
|
|
432
|
+
const available = [...DEV_NAMES, ...accountsFile.accounts.map((a) => a.name)].sort((a, b) => a.localeCompare(b));
|
|
433
|
+
const suggestions = findClosest(name, available);
|
|
434
|
+
const hint = suggestions.length > 0 ? `
|
|
435
|
+
Did you mean: ${suggestions.join(", ")}?` : "";
|
|
436
|
+
const list = available.map((a) => `
|
|
437
|
+
- ${a}`).join("");
|
|
438
|
+
throw new Error(`Unknown account "${name}".${hint}
|
|
439
|
+
Available accounts:${list}`);
|
|
374
440
|
}
|
|
375
441
|
if (account.secret === undefined) {
|
|
376
442
|
throw new Error(`Account "${name}" is watch-only (no secret). Cannot sign. Import with --secret or --env.`);
|
|
@@ -390,6 +456,7 @@ var init_accounts = __esm(() => {
|
|
|
390
456
|
});
|
|
391
457
|
|
|
392
458
|
// src/utils/binary-display.ts
|
|
459
|
+
import { Binary } from "polkadot-api";
|
|
393
460
|
function isReadableText(text) {
|
|
394
461
|
for (let i = 0;i < text.length; i++) {
|
|
395
462
|
const code = text.charCodeAt(i);
|
|
@@ -407,20 +474,17 @@ function isReadableText(text) {
|
|
|
407
474
|
return true;
|
|
408
475
|
}
|
|
409
476
|
function binaryToDisplay(value) {
|
|
410
|
-
const text =
|
|
411
|
-
return isReadableText(text) ? text :
|
|
477
|
+
const text = Binary.toText(value);
|
|
478
|
+
return isReadableText(text) ? text : Binary.toHex(value);
|
|
412
479
|
}
|
|
480
|
+
var init_binary_display = () => {};
|
|
413
481
|
|
|
414
482
|
// src/core/output.ts
|
|
415
|
-
import { Binary } from "polkadot-api";
|
|
416
483
|
function replacer(_key, value) {
|
|
417
484
|
if (typeof value === "bigint")
|
|
418
485
|
return value.toString();
|
|
419
|
-
if (value instanceof Binary) {
|
|
420
|
-
return binaryToDisplay(value);
|
|
421
|
-
}
|
|
422
486
|
if (value instanceof Uint8Array)
|
|
423
|
-
return
|
|
487
|
+
return binaryToDisplay(value);
|
|
424
488
|
return value;
|
|
425
489
|
}
|
|
426
490
|
function formatJson(data) {
|
|
@@ -442,6 +506,12 @@ function printResult(data, format = "pretty") {
|
|
|
442
506
|
console.log(formatPretty(data));
|
|
443
507
|
}
|
|
444
508
|
}
|
|
509
|
+
function isJsonOutput(opts) {
|
|
510
|
+
return opts.json === true || opts.output === "json";
|
|
511
|
+
}
|
|
512
|
+
function printJsonLine(data) {
|
|
513
|
+
console.log(JSON.stringify(data, replacer));
|
|
514
|
+
}
|
|
445
515
|
function printHeading(text) {
|
|
446
516
|
console.log(`
|
|
447
517
|
${BOLD}${text}${RESET}
|
|
@@ -500,6 +570,7 @@ function firstSentence(docs) {
|
|
|
500
570
|
}
|
|
501
571
|
var isTTY, RESET, CYAN, GREEN, RED, YELLOW, MAGENTA, DIM, BOLD, CHECK_MARK = "✓", SPINNER_FRAMES;
|
|
502
572
|
var init_output = __esm(() => {
|
|
573
|
+
init_binary_display();
|
|
503
574
|
isTTY = process.stdout.isTTY ?? false;
|
|
504
575
|
RESET = isTTY ? "\x1B[0m" : "";
|
|
505
576
|
CYAN = isTTY ? "\x1B[36m" : "";
|
|
@@ -556,37 +627,33 @@ var init_errors = __esm(() => {
|
|
|
556
627
|
|
|
557
628
|
// src/core/client.ts
|
|
558
629
|
import { createClient } from "polkadot-api";
|
|
559
|
-
import {
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
const orig = console.error;
|
|
630
|
+
import { getWsProvider } from "polkadot-api/ws";
|
|
631
|
+
function suppressProviderNoise() {
|
|
632
|
+
const origError = console.error;
|
|
633
|
+
const origWarn = console.warn;
|
|
564
634
|
console.error = (...args) => {
|
|
565
635
|
if (typeof args[0] === "string" && args[0].includes("Unable to connect"))
|
|
566
636
|
return;
|
|
567
|
-
|
|
637
|
+
origError(...args);
|
|
638
|
+
};
|
|
639
|
+
console.warn = (...args) => {
|
|
640
|
+
if (typeof args[0] === "string" && args[0].includes("ChainHead"))
|
|
641
|
+
return;
|
|
642
|
+
origWarn(...args);
|
|
568
643
|
};
|
|
569
644
|
return () => {
|
|
570
|
-
console.error =
|
|
645
|
+
console.error = origError;
|
|
646
|
+
console.warn = origWarn;
|
|
571
647
|
};
|
|
572
648
|
}
|
|
573
649
|
async function createChainClient(chainName, chainConfig, rpcOverride) {
|
|
574
|
-
const
|
|
575
|
-
const
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
} else {
|
|
580
|
-
const rpc = rpcOverride ?? chainConfig.rpc;
|
|
581
|
-
if (!rpc) {
|
|
582
|
-
restoreConsole();
|
|
583
|
-
throw new ConnectionError(`No RPC endpoint configured for chain "${chainName}". Use --rpc or configure one with: dot chain add ${chainName} --rpc <url>`);
|
|
584
|
-
}
|
|
585
|
-
provider = withPolkadotSdkCompat(getWsProvider(rpc, {
|
|
586
|
-
timeout: 1e4,
|
|
587
|
-
websocketClass: WebSocket
|
|
588
|
-
}));
|
|
650
|
+
const restoreConsole = suppressProviderNoise();
|
|
651
|
+
const rpc = rpcOverride ?? chainConfig.rpc;
|
|
652
|
+
if (!rpc) {
|
|
653
|
+
restoreConsole();
|
|
654
|
+
throw new ConnectionError(`No RPC endpoint configured for chain "${chainName}". Use --rpc or configure one with: dot chain add ${chainName} --rpc <url>`);
|
|
589
655
|
}
|
|
656
|
+
const provider = getWsProvider(rpc, { timeout: 1e4 });
|
|
590
657
|
const client = createClient(provider, {
|
|
591
658
|
getMetadata: async () => loadMetadata(chainName),
|
|
592
659
|
setMetadata: async (_codeHash, metadata) => {
|
|
@@ -596,51 +663,25 @@ async function createChainClient(chainName, chainConfig, rpcOverride) {
|
|
|
596
663
|
return {
|
|
597
664
|
client,
|
|
598
665
|
destroy: () => {
|
|
599
|
-
|
|
600
|
-
|
|
666
|
+
try {
|
|
667
|
+
client.destroy();
|
|
668
|
+
} catch {}
|
|
669
|
+
setTimeout(restoreConsole, 500);
|
|
601
670
|
}
|
|
602
671
|
};
|
|
603
672
|
}
|
|
604
|
-
async function
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
if (entry.relay) {
|
|
614
|
-
const relayEntry = KNOWN_CHAIN_SPECS[entry.relay];
|
|
615
|
-
if (!relayEntry) {
|
|
616
|
-
throw new ConnectionError(`Relay chain "${entry.relay}" not found in known chain specs.`);
|
|
617
|
-
}
|
|
618
|
-
const { chainSpec: relaySpec } = await import(relayEntry.spec);
|
|
619
|
-
const relayChain = await smoldot.addChain({ chainSpec: relaySpec, disableJsonRpc: true });
|
|
620
|
-
const chain2 = await smoldot.addChain({ chainSpec, potentialRelayChains: [relayChain] });
|
|
621
|
-
return getSmProvider(chain2);
|
|
622
|
-
}
|
|
623
|
-
const chain = await smoldot.addChain({ chainSpec });
|
|
624
|
-
return getSmProvider(chain);
|
|
625
|
-
}
|
|
626
|
-
var KNOWN_CHAIN_SPECS;
|
|
673
|
+
async function getParachainId(clientHandle) {
|
|
674
|
+
try {
|
|
675
|
+
const unsafeApi = clientHandle.client.getUnsafeApi();
|
|
676
|
+
const parachainId = await unsafeApi.query.ParachainInfo.ParachainId.getValue();
|
|
677
|
+
return typeof parachainId === "number" ? parachainId : null;
|
|
678
|
+
} catch {
|
|
679
|
+
return null;
|
|
680
|
+
}
|
|
681
|
+
}
|
|
627
682
|
var init_client = __esm(() => {
|
|
628
683
|
init_store();
|
|
629
684
|
init_errors();
|
|
630
|
-
KNOWN_CHAIN_SPECS = {
|
|
631
|
-
polkadot: { spec: "polkadot-api/chains/polkadot" },
|
|
632
|
-
kusama: { spec: "polkadot-api/chains/ksmcc3" },
|
|
633
|
-
westend: { spec: "polkadot-api/chains/westend2" },
|
|
634
|
-
paseo: { spec: "polkadot-api/chains/paseo" },
|
|
635
|
-
"polkadot-asset-hub": { spec: "polkadot-api/chains/polkadot_asset_hub", relay: "polkadot" },
|
|
636
|
-
"polkadot-bridge-hub": { spec: "polkadot-api/chains/polkadot_bridge_hub", relay: "polkadot" },
|
|
637
|
-
"polkadot-collectives": { spec: "polkadot-api/chains/polkadot_collectives", relay: "polkadot" },
|
|
638
|
-
"polkadot-coretime": { spec: "polkadot-api/chains/polkadot_coretime", relay: "polkadot" },
|
|
639
|
-
"polkadot-people": { spec: "polkadot-api/chains/polkadot_people", relay: "polkadot" },
|
|
640
|
-
"paseo-asset-hub": { spec: "polkadot-api/chains/paseo_asset_hub", relay: "paseo" },
|
|
641
|
-
"paseo-coretime": { spec: "polkadot-api/chains/paseo_coretime", relay: "paseo" },
|
|
642
|
-
"paseo-people": { spec: "polkadot-api/chains/paseo_people", relay: "paseo" }
|
|
643
|
-
};
|
|
644
685
|
});
|
|
645
686
|
|
|
646
687
|
// src/core/metadata.ts
|
|
@@ -915,42 +956,6 @@ var init_metadata = __esm(() => {
|
|
|
915
956
|
v15Arg = toHex(u32.enc(15));
|
|
916
957
|
});
|
|
917
958
|
|
|
918
|
-
// src/utils/fuzzy-match.ts
|
|
919
|
-
function levenshtein(a, b) {
|
|
920
|
-
const la = a.length;
|
|
921
|
-
const lb = b.length;
|
|
922
|
-
const dp = Array.from({ length: la + 1 }, () => Array(lb + 1).fill(0));
|
|
923
|
-
for (let i = 0;i <= la; i++)
|
|
924
|
-
dp[i][0] = i;
|
|
925
|
-
for (let j = 0;j <= lb; j++)
|
|
926
|
-
dp[0][j] = j;
|
|
927
|
-
for (let i = 1;i <= la; i++) {
|
|
928
|
-
for (let j = 1;j <= lb; j++) {
|
|
929
|
-
const cost = a[i - 1] === b[j - 1] ? 0 : 1;
|
|
930
|
-
dp[i][j] = Math.min(dp[i - 1][j] + 1, dp[i][j - 1] + 1, dp[i - 1][j - 1] + cost);
|
|
931
|
-
}
|
|
932
|
-
}
|
|
933
|
-
return dp[la][lb];
|
|
934
|
-
}
|
|
935
|
-
function findClosest(input, candidates, maxDistance = 3) {
|
|
936
|
-
const lower = input.toLowerCase();
|
|
937
|
-
const exact = candidates.find((c) => c.toLowerCase() === lower);
|
|
938
|
-
if (exact)
|
|
939
|
-
return [exact];
|
|
940
|
-
const scored = candidates.map((c) => ({ name: c, dist: levenshtein(lower, c.toLowerCase()) })).filter((s) => s.dist <= maxDistance).sort((a, b) => a.dist - b.dist);
|
|
941
|
-
return scored.slice(0, 3).map((s) => s.name);
|
|
942
|
-
}
|
|
943
|
-
function suggestMessage(kind, input, candidates) {
|
|
944
|
-
const suggestions = findClosest(input, candidates);
|
|
945
|
-
if (suggestions.length === 0) {
|
|
946
|
-
return `Unknown ${kind} "${input}".`;
|
|
947
|
-
}
|
|
948
|
-
if (suggestions.length === 1 && suggestions[0]?.toLowerCase() === input.toLowerCase()) {
|
|
949
|
-
return suggestions[0];
|
|
950
|
-
}
|
|
951
|
-
return `Unknown ${kind} "${input}". Did you mean: ${suggestions.join(", ")}?`;
|
|
952
|
-
}
|
|
953
|
-
|
|
954
959
|
// src/core/explorers.ts
|
|
955
960
|
var pjsAppsLink = (rpc, hash) => `https://polkadot.js.org/apps/?rpc=${encodeURIComponent(rpc)}#/explorer/query/${hash}`, papiLink = (rpc, hash) => `https://dev.papi.how/explorer/${hash}#networkId=custom&endpoint=${encodeURIComponent(rpc)}`;
|
|
956
961
|
|
|
@@ -976,9 +981,14 @@ async function resolveAccountAddress(input) {
|
|
|
976
981
|
return input;
|
|
977
982
|
}
|
|
978
983
|
const stored = accountsFile.accounts.map((a) => a.name);
|
|
979
|
-
const available = [...DEV_NAMES, ...stored];
|
|
980
|
-
|
|
981
|
-
|
|
984
|
+
const available = [...DEV_NAMES, ...stored].sort((a, b) => a.localeCompare(b));
|
|
985
|
+
const suggestions = findClosest(input, available);
|
|
986
|
+
const hint = suggestions.length > 0 ? `
|
|
987
|
+
Did you mean: ${suggestions.join(", ")}?` : "";
|
|
988
|
+
const list = available.map((a) => `
|
|
989
|
+
- ${a}`).join("");
|
|
990
|
+
throw new Error(`Unknown account or address "${input}".${hint}
|
|
991
|
+
Available accounts:${list}`);
|
|
982
992
|
}
|
|
983
993
|
var init_resolve_address = __esm(() => {
|
|
984
994
|
init_accounts_store();
|
|
@@ -1206,7 +1216,7 @@ async function parseTypedArg(meta, entry, arg) {
|
|
|
1206
1216
|
case "enum": {
|
|
1207
1217
|
if (/^0x[0-9a-fA-F]+$/.test(arg) && meta.lookup.call != null && entry.id === meta.lookup.call) {
|
|
1208
1218
|
const callCodec = meta.builder.buildDefinition(meta.lookup.call);
|
|
1209
|
-
return callCodec.dec(Binary2.fromHex(arg)
|
|
1219
|
+
return callCodec.dec(Binary2.fromHex(arg));
|
|
1210
1220
|
}
|
|
1211
1221
|
if (arg.startsWith("{")) {
|
|
1212
1222
|
try {
|
|
@@ -1318,6 +1328,7 @@ var init_tx = __esm(() => {
|
|
|
1318
1328
|
init_metadata();
|
|
1319
1329
|
init_output();
|
|
1320
1330
|
init_resolve_address();
|
|
1331
|
+
init_binary_display();
|
|
1321
1332
|
init_errors();
|
|
1322
1333
|
init_focused_inspect();
|
|
1323
1334
|
PAPI_BUILTIN_EXTENSIONS = new Set([
|
|
@@ -1348,6 +1359,13 @@ async function handleApis(target, args, opts) {
|
|
|
1348
1359
|
const { name: chainName2, chain: chainConfig2 } = resolveChain(config2, opts.chain);
|
|
1349
1360
|
const meta = await loadMeta(chainName2, chainConfig2, opts.rpc);
|
|
1350
1361
|
const apis = listRuntimeApis(meta);
|
|
1362
|
+
if (isJsonOutput(opts)) {
|
|
1363
|
+
console.log(formatJson({
|
|
1364
|
+
chain: chainName2,
|
|
1365
|
+
apis: apis.map((a) => ({ name: a.name, methods: a.methods.length }))
|
|
1366
|
+
}));
|
|
1367
|
+
return;
|
|
1368
|
+
}
|
|
1351
1369
|
printHeading(`Runtime APIs on ${chainName2} (${apis.length})`);
|
|
1352
1370
|
for (const api of apis) {
|
|
1353
1371
|
printItem(api.name, `${api.methods.length} methods`);
|
|
@@ -1370,7 +1388,24 @@ async function handleApis(target, args, opts) {
|
|
|
1370
1388
|
const meta = await loadMeta(chainName, chainConfig, opts.rpc);
|
|
1371
1389
|
const api = resolveRuntimeApi(meta, apiName);
|
|
1372
1390
|
if (api.methods.length === 0) {
|
|
1373
|
-
|
|
1391
|
+
if (isJsonOutput(opts)) {
|
|
1392
|
+
console.log(formatJson({ chain: chainName, api: api.name, methods: [] }));
|
|
1393
|
+
} else {
|
|
1394
|
+
console.log(`No methods in ${api.name}.`);
|
|
1395
|
+
}
|
|
1396
|
+
return;
|
|
1397
|
+
}
|
|
1398
|
+
if (isJsonOutput(opts)) {
|
|
1399
|
+
console.log(formatJson({
|
|
1400
|
+
chain: chainName,
|
|
1401
|
+
api: api.name,
|
|
1402
|
+
methods: api.methods.map((m) => ({
|
|
1403
|
+
name: m.name,
|
|
1404
|
+
args: describeRuntimeApiMethodArgs(meta, m),
|
|
1405
|
+
returns: describeType(meta.lookup, m.output),
|
|
1406
|
+
docs: firstSentence(m.docs)
|
|
1407
|
+
}))
|
|
1408
|
+
}));
|
|
1374
1409
|
return;
|
|
1375
1410
|
}
|
|
1376
1411
|
printHeading(`${api.name} Methods`);
|
|
@@ -1401,7 +1436,7 @@ async function handleApis(target, args, opts) {
|
|
|
1401
1436
|
const parsedArgs = await parseRuntimeApiArgs(meta, method, effectiveArgs);
|
|
1402
1437
|
const unsafeApi = clientHandle.client.getUnsafeApi();
|
|
1403
1438
|
const result = await unsafeApi.apis[api.name][method.name](...parsedArgs);
|
|
1404
|
-
const format = opts.output ?? "pretty";
|
|
1439
|
+
const format = isJsonOutput(opts) ? "json" : opts.output ?? "pretty";
|
|
1405
1440
|
printResult(result, format);
|
|
1406
1441
|
} finally {
|
|
1407
1442
|
clientHandle.destroy();
|
|
@@ -1441,7 +1476,8 @@ async function loadMeta(chainName, chainConfig, rpcOverride) {
|
|
|
1441
1476
|
try {
|
|
1442
1477
|
return await getOrFetchMetadata(chainName);
|
|
1443
1478
|
} catch {
|
|
1444
|
-
|
|
1479
|
+
process.stderr.write(`Fetching metadata from ${chainName}...
|
|
1480
|
+
`);
|
|
1445
1481
|
const clientHandle = await createChainClient(chainName, chainConfig, rpcOverride);
|
|
1446
1482
|
try {
|
|
1447
1483
|
return await getOrFetchMetadata(chainName, clientHandle);
|
|
@@ -1465,6 +1501,13 @@ async function handleCalls(target, opts) {
|
|
|
1465
1501
|
const meta2 = await loadMeta(chainName2, chainConfig2, opts.rpc);
|
|
1466
1502
|
const pallets = listPallets(meta2);
|
|
1467
1503
|
const withCalls = pallets.filter((p) => p.calls.length > 0);
|
|
1504
|
+
if (isJsonOutput(opts)) {
|
|
1505
|
+
console.log(formatJson({
|
|
1506
|
+
chain: chainName2,
|
|
1507
|
+
pallets: withCalls.map((p) => ({ name: p.name, calls: p.calls.length }))
|
|
1508
|
+
}));
|
|
1509
|
+
return;
|
|
1510
|
+
}
|
|
1468
1511
|
printHeading(`Pallets with calls on ${chainName2} (${withCalls.length})`);
|
|
1469
1512
|
for (const p of withCalls) {
|
|
1470
1513
|
printItem(p.name, `${p.calls.length} calls`);
|
|
@@ -1481,7 +1524,23 @@ async function handleCalls(target, opts) {
|
|
|
1481
1524
|
const pallet = resolvePallet(meta, palletName);
|
|
1482
1525
|
if (!itemName) {
|
|
1483
1526
|
if (pallet.calls.length === 0) {
|
|
1484
|
-
|
|
1527
|
+
if (isJsonOutput(opts)) {
|
|
1528
|
+
console.log(formatJson({ chain: chainName, pallet: pallet.name, calls: [] }));
|
|
1529
|
+
} else {
|
|
1530
|
+
console.log(`No calls in ${pallet.name}.`);
|
|
1531
|
+
}
|
|
1532
|
+
return;
|
|
1533
|
+
}
|
|
1534
|
+
if (isJsonOutput(opts)) {
|
|
1535
|
+
console.log(formatJson({
|
|
1536
|
+
chain: chainName,
|
|
1537
|
+
pallet: pallet.name,
|
|
1538
|
+
calls: pallet.calls.map((c) => ({
|
|
1539
|
+
name: c.name,
|
|
1540
|
+
args: describeCallArgs(meta, pallet.name, c.name),
|
|
1541
|
+
docs: firstSentence(c.docs)
|
|
1542
|
+
}))
|
|
1543
|
+
}));
|
|
1485
1544
|
return;
|
|
1486
1545
|
}
|
|
1487
1546
|
printHeading(`${pallet.name} Calls`);
|
|
@@ -1501,6 +1560,17 @@ async function handleCalls(target, opts) {
|
|
|
1501
1560
|
const names = pallet.calls.map((c) => c.name);
|
|
1502
1561
|
throw new Error(suggestMessage(`call in ${pallet.name}`, itemName, names));
|
|
1503
1562
|
}
|
|
1563
|
+
if (isJsonOutput(opts)) {
|
|
1564
|
+
console.log(formatJson({
|
|
1565
|
+
chain: chainName,
|
|
1566
|
+
pallet: pallet.name,
|
|
1567
|
+
item: callItem.name,
|
|
1568
|
+
category: "call",
|
|
1569
|
+
args: describeCallArgs(meta, pallet.name, callItem.name),
|
|
1570
|
+
docs: callItem.docs
|
|
1571
|
+
}));
|
|
1572
|
+
return;
|
|
1573
|
+
}
|
|
1504
1574
|
printHeading(`${pallet.name}.${callItem.name} (Call)`);
|
|
1505
1575
|
const args = describeCallArgs(meta, pallet.name, callItem.name);
|
|
1506
1576
|
console.log(` ${BOLD}Args:${RESET} ${args}`);
|
|
@@ -1517,6 +1587,13 @@ async function handleEvents(target, opts) {
|
|
|
1517
1587
|
const meta2 = await loadMeta(chainName2, chainConfig2, opts.rpc);
|
|
1518
1588
|
const pallets = listPallets(meta2);
|
|
1519
1589
|
const withEvents = pallets.filter((p) => p.events.length > 0);
|
|
1590
|
+
if (isJsonOutput(opts)) {
|
|
1591
|
+
console.log(formatJson({
|
|
1592
|
+
chain: chainName2,
|
|
1593
|
+
pallets: withEvents.map((p) => ({ name: p.name, events: p.events.length }))
|
|
1594
|
+
}));
|
|
1595
|
+
return;
|
|
1596
|
+
}
|
|
1520
1597
|
printHeading(`Pallets with events on ${chainName2} (${withEvents.length})`);
|
|
1521
1598
|
for (const p of withEvents) {
|
|
1522
1599
|
printItem(p.name, `${p.events.length} events`);
|
|
@@ -1533,7 +1610,23 @@ async function handleEvents(target, opts) {
|
|
|
1533
1610
|
const pallet = resolvePallet(meta, palletName);
|
|
1534
1611
|
if (!itemName) {
|
|
1535
1612
|
if (pallet.events.length === 0) {
|
|
1536
|
-
|
|
1613
|
+
if (isJsonOutput(opts)) {
|
|
1614
|
+
console.log(formatJson({ chain: chainName, pallet: pallet.name, events: [] }));
|
|
1615
|
+
} else {
|
|
1616
|
+
console.log(`No events in ${pallet.name}.`);
|
|
1617
|
+
}
|
|
1618
|
+
return;
|
|
1619
|
+
}
|
|
1620
|
+
if (isJsonOutput(opts)) {
|
|
1621
|
+
console.log(formatJson({
|
|
1622
|
+
chain: chainName,
|
|
1623
|
+
pallet: pallet.name,
|
|
1624
|
+
events: pallet.events.map((e) => ({
|
|
1625
|
+
name: e.name,
|
|
1626
|
+
fields: describeEventFields(meta, pallet.name, e.name),
|
|
1627
|
+
docs: firstSentence(e.docs)
|
|
1628
|
+
}))
|
|
1629
|
+
}));
|
|
1537
1630
|
return;
|
|
1538
1631
|
}
|
|
1539
1632
|
printHeading(`${pallet.name} Events`);
|
|
@@ -1553,6 +1646,17 @@ async function handleEvents(target, opts) {
|
|
|
1553
1646
|
const names = pallet.events.map((e) => e.name);
|
|
1554
1647
|
throw new Error(suggestMessage(`event in ${pallet.name}`, itemName, names));
|
|
1555
1648
|
}
|
|
1649
|
+
if (isJsonOutput(opts)) {
|
|
1650
|
+
console.log(formatJson({
|
|
1651
|
+
chain: chainName,
|
|
1652
|
+
pallet: pallet.name,
|
|
1653
|
+
item: eventItem.name,
|
|
1654
|
+
category: "event",
|
|
1655
|
+
fields: describeEventFields(meta, pallet.name, eventItem.name),
|
|
1656
|
+
docs: eventItem.docs
|
|
1657
|
+
}));
|
|
1658
|
+
return;
|
|
1659
|
+
}
|
|
1556
1660
|
printHeading(`${pallet.name}.${eventItem.name} (Event)`);
|
|
1557
1661
|
const fields = describeEventFields(meta, pallet.name, eventItem.name);
|
|
1558
1662
|
console.log(` ${BOLD}Fields:${RESET} ${fields}`);
|
|
@@ -1569,6 +1673,13 @@ async function handleErrors(target, opts) {
|
|
|
1569
1673
|
const meta2 = await loadMeta(chainName2, chainConfig2, opts.rpc);
|
|
1570
1674
|
const pallets = listPallets(meta2);
|
|
1571
1675
|
const withErrors = pallets.filter((p) => p.errors.length > 0);
|
|
1676
|
+
if (isJsonOutput(opts)) {
|
|
1677
|
+
console.log(formatJson({
|
|
1678
|
+
chain: chainName2,
|
|
1679
|
+
pallets: withErrors.map((p) => ({ name: p.name, errors: p.errors.length }))
|
|
1680
|
+
}));
|
|
1681
|
+
return;
|
|
1682
|
+
}
|
|
1572
1683
|
printHeading(`Pallets with errors on ${chainName2} (${withErrors.length})`);
|
|
1573
1684
|
for (const p of withErrors) {
|
|
1574
1685
|
printItem(p.name, `${p.errors.length} errors`);
|
|
@@ -1585,7 +1696,19 @@ async function handleErrors(target, opts) {
|
|
|
1585
1696
|
const pallet = resolvePallet(meta, palletName);
|
|
1586
1697
|
if (!itemName) {
|
|
1587
1698
|
if (pallet.errors.length === 0) {
|
|
1588
|
-
|
|
1699
|
+
if (isJsonOutput(opts)) {
|
|
1700
|
+
console.log(formatJson({ chain: chainName, pallet: pallet.name, errors: [] }));
|
|
1701
|
+
} else {
|
|
1702
|
+
console.log(`No errors in ${pallet.name}.`);
|
|
1703
|
+
}
|
|
1704
|
+
return;
|
|
1705
|
+
}
|
|
1706
|
+
if (isJsonOutput(opts)) {
|
|
1707
|
+
console.log(formatJson({
|
|
1708
|
+
chain: chainName,
|
|
1709
|
+
pallet: pallet.name,
|
|
1710
|
+
errors: pallet.errors.map((e) => ({ name: e.name, docs: firstSentence(e.docs) }))
|
|
1711
|
+
}));
|
|
1589
1712
|
return;
|
|
1590
1713
|
}
|
|
1591
1714
|
printHeading(`${pallet.name} Errors`);
|
|
@@ -1604,6 +1727,16 @@ async function handleErrors(target, opts) {
|
|
|
1604
1727
|
const names = pallet.errors.map((e) => e.name);
|
|
1605
1728
|
throw new Error(suggestMessage(`error in ${pallet.name}`, itemName, names));
|
|
1606
1729
|
}
|
|
1730
|
+
if (isJsonOutput(opts)) {
|
|
1731
|
+
console.log(formatJson({
|
|
1732
|
+
chain: chainName,
|
|
1733
|
+
pallet: pallet.name,
|
|
1734
|
+
item: errorItem.name,
|
|
1735
|
+
category: "error",
|
|
1736
|
+
docs: errorItem.docs
|
|
1737
|
+
}));
|
|
1738
|
+
return;
|
|
1739
|
+
}
|
|
1607
1740
|
printHeading(`${pallet.name}.${errorItem.name} (Error)`);
|
|
1608
1741
|
if (errorItem.docs.length) {
|
|
1609
1742
|
printDocs(errorItem.docs);
|
|
@@ -1617,6 +1750,13 @@ async function handleStorage(target, opts) {
|
|
|
1617
1750
|
const meta2 = await loadMeta(chainName2, chainConfig2, opts.rpc);
|
|
1618
1751
|
const pallets = listPallets(meta2);
|
|
1619
1752
|
const withStorage = pallets.filter((p) => p.storage.length > 0);
|
|
1753
|
+
if (isJsonOutput(opts)) {
|
|
1754
|
+
console.log(formatJson({
|
|
1755
|
+
chain: chainName2,
|
|
1756
|
+
pallets: withStorage.map((p) => ({ name: p.name, storage: p.storage.length }))
|
|
1757
|
+
}));
|
|
1758
|
+
return;
|
|
1759
|
+
}
|
|
1620
1760
|
printHeading(`Pallets with storage on ${chainName2} (${withStorage.length})`);
|
|
1621
1761
|
for (const p of withStorage) {
|
|
1622
1762
|
printItem(p.name, `${p.storage.length} storage`);
|
|
@@ -1633,7 +1773,23 @@ async function handleStorage(target, opts) {
|
|
|
1633
1773
|
const pallet = resolvePallet(meta, palletName);
|
|
1634
1774
|
if (!itemName) {
|
|
1635
1775
|
if (pallet.storage.length === 0) {
|
|
1636
|
-
|
|
1776
|
+
if (isJsonOutput(opts)) {
|
|
1777
|
+
console.log(formatJson({ chain: chainName, pallet: pallet.name, storage: [] }));
|
|
1778
|
+
} else {
|
|
1779
|
+
console.log(`No storage items in ${pallet.name}.`);
|
|
1780
|
+
}
|
|
1781
|
+
return;
|
|
1782
|
+
}
|
|
1783
|
+
if (isJsonOutput(opts)) {
|
|
1784
|
+
console.log(formatJson({
|
|
1785
|
+
chain: chainName,
|
|
1786
|
+
pallet: pallet.name,
|
|
1787
|
+
storage: pallet.storage.map((s) => {
|
|
1788
|
+
const valueType = describeType(meta.lookup, s.valueTypeId);
|
|
1789
|
+
const keyType = s.keyTypeId != null ? describeType(meta.lookup, s.keyTypeId) : undefined;
|
|
1790
|
+
return { name: s.name, type: s.type, valueType, keyType, docs: firstSentence(s.docs) };
|
|
1791
|
+
})
|
|
1792
|
+
}));
|
|
1637
1793
|
return;
|
|
1638
1794
|
}
|
|
1639
1795
|
printHeading(`${pallet.name} Storage`);
|
|
@@ -1660,6 +1816,21 @@ async function handleStorage(target, opts) {
|
|
|
1660
1816
|
const names = pallet.storage.map((s) => s.name);
|
|
1661
1817
|
throw new Error(suggestMessage(`storage item in ${pallet.name}`, itemName, names));
|
|
1662
1818
|
}
|
|
1819
|
+
if (isJsonOutput(opts)) {
|
|
1820
|
+
const valueType = describeType(meta.lookup, storageItem.valueTypeId);
|
|
1821
|
+
const keyType = storageItem.keyTypeId != null ? describeType(meta.lookup, storageItem.keyTypeId) : undefined;
|
|
1822
|
+
console.log(formatJson({
|
|
1823
|
+
chain: chainName,
|
|
1824
|
+
pallet: pallet.name,
|
|
1825
|
+
item: storageItem.name,
|
|
1826
|
+
category: "storage",
|
|
1827
|
+
type: storageItem.type,
|
|
1828
|
+
valueType,
|
|
1829
|
+
keyType,
|
|
1830
|
+
docs: storageItem.docs
|
|
1831
|
+
}));
|
|
1832
|
+
return;
|
|
1833
|
+
}
|
|
1663
1834
|
printHeading(`${pallet.name}.${storageItem.name} (Storage)`);
|
|
1664
1835
|
console.log(` ${BOLD}Type:${RESET} ${storageItem.type}`);
|
|
1665
1836
|
console.log(` ${BOLD}Value:${RESET} ${describeType(meta.lookup, storageItem.valueTypeId)}`);
|
|
@@ -1998,6 +2169,9 @@ async function generateCompletions(currentWord, precedingWords) {
|
|
|
1998
2169
|
if (prevWord === "--wait" || prevWord === "-w") {
|
|
1999
2170
|
return filterPrefix(["broadcast", "best-block", "best", "finalized"], currentWord);
|
|
2000
2171
|
}
|
|
2172
|
+
if (prevWord === "--relay") {
|
|
2173
|
+
return filterPrefix(knownChains, currentWord);
|
|
2174
|
+
}
|
|
2001
2175
|
if (currentWord.startsWith("--")) {
|
|
2002
2176
|
const activeCategory = detectCategory(precedingWords, knownChains);
|
|
2003
2177
|
const options = [...GLOBAL_OPTIONS];
|
|
@@ -2005,10 +2179,19 @@ async function generateCompletions(currentWord, precedingWords) {
|
|
|
2005
2179
|
options.push(...TX_OPTIONS);
|
|
2006
2180
|
if (activeCategory === "query")
|
|
2007
2181
|
options.push(...QUERY_OPTIONS);
|
|
2182
|
+
const chainIdx = precedingWords.indexOf("chain");
|
|
2183
|
+
if (chainIdx >= 0 && precedingWords[chainIdx + 1] === "add") {
|
|
2184
|
+
options.push("--relay", "--parachain-id");
|
|
2185
|
+
}
|
|
2008
2186
|
return filterPrefix(options, currentWord);
|
|
2009
2187
|
}
|
|
2010
2188
|
const firstArg = precedingWords.find((w) => !w.startsWith("-"));
|
|
2011
2189
|
if (firstArg === "chain") {
|
|
2190
|
+
const chainSubIdx = precedingWords.indexOf("chain");
|
|
2191
|
+
const subcommand = precedingWords[chainSubIdx + 1];
|
|
2192
|
+
if (subcommand === "add" && currentWord.startsWith("--")) {
|
|
2193
|
+
return filterPrefix(["--rpc", "--relay", "--parachain-id", ...GLOBAL_OPTIONS], currentWord);
|
|
2194
|
+
}
|
|
2012
2195
|
return filterPrefix(CHAIN_SUBCOMMANDS, currentWord);
|
|
2013
2196
|
}
|
|
2014
2197
|
if (firstArg === "account") {
|
|
@@ -2199,7 +2382,7 @@ var init_complete = __esm(() => {
|
|
|
2199
2382
|
"delete",
|
|
2200
2383
|
"inspect"
|
|
2201
2384
|
];
|
|
2202
|
-
GLOBAL_OPTIONS = ["--chain", "--rpc", "--
|
|
2385
|
+
GLOBAL_OPTIONS = ["--chain", "--rpc", "--output", "--help", "--version"];
|
|
2203
2386
|
TX_OPTIONS = [
|
|
2204
2387
|
"--from",
|
|
2205
2388
|
"--dry-run",
|
|
@@ -2217,7 +2400,7 @@ var init_complete = __esm(() => {
|
|
|
2217
2400
|
// src/cli.ts
|
|
2218
2401
|
import cac from "cac";
|
|
2219
2402
|
// package.json
|
|
2220
|
-
var version = "1.
|
|
2403
|
+
var version = "1.13.0";
|
|
2221
2404
|
|
|
2222
2405
|
// src/commands/account.ts
|
|
2223
2406
|
init_accounts_store();
|
|
@@ -2258,7 +2441,7 @@ function registerAccountCommands(cli) {
|
|
|
2258
2441
|
cli.command("account [action] [...names]", "Manage local accounts (create, import, list, remove)").alias("accounts").option("--secret <value>", "Secret key (mnemonic or hex seed) for import").option("--env <varName>", "Environment variable name holding the secret").option("--path <derivation>", "Derivation path (e.g. //staking, //polkadot//0/wallet)").option("--prefix <number>", "SS58 prefix for address encoding (default: 42)").action(async (action, names, opts) => {
|
|
2259
2442
|
if (!action) {
|
|
2260
2443
|
if (process.argv[2] === "accounts")
|
|
2261
|
-
return accountList();
|
|
2444
|
+
return accountList(opts);
|
|
2262
2445
|
console.log(ACCOUNT_HELP);
|
|
2263
2446
|
return;
|
|
2264
2447
|
}
|
|
@@ -2269,16 +2452,16 @@ function registerAccountCommands(cli) {
|
|
|
2269
2452
|
case "add":
|
|
2270
2453
|
if (opts.secret || opts.env)
|
|
2271
2454
|
return accountImport(names[0], opts);
|
|
2272
|
-
return accountAddWatchOnly(names[0], names[1]);
|
|
2455
|
+
return accountAddWatchOnly(names[0], names[1], opts);
|
|
2273
2456
|
case "import":
|
|
2274
2457
|
return accountImport(names[0], opts);
|
|
2275
2458
|
case "derive":
|
|
2276
2459
|
return accountDerive(names[0], names[1], opts);
|
|
2277
2460
|
case "list":
|
|
2278
|
-
return accountList();
|
|
2461
|
+
return accountList(opts);
|
|
2279
2462
|
case "delete":
|
|
2280
2463
|
case "remove":
|
|
2281
|
-
return accountRemove(names);
|
|
2464
|
+
return accountRemove(names, opts);
|
|
2282
2465
|
case "inspect":
|
|
2283
2466
|
return accountInspect(names[0], opts);
|
|
2284
2467
|
default:
|
|
@@ -2316,6 +2499,18 @@ async function accountCreate(name, opts) {
|
|
|
2316
2499
|
bandersnatch
|
|
2317
2500
|
});
|
|
2318
2501
|
await saveAccounts(accountsFile);
|
|
2502
|
+
if (isJsonOutput(opts)) {
|
|
2503
|
+
console.log(formatJson({
|
|
2504
|
+
name,
|
|
2505
|
+
address,
|
|
2506
|
+
publicKey: hexPub,
|
|
2507
|
+
mnemonic,
|
|
2508
|
+
path: path || undefined,
|
|
2509
|
+
bandersnatch
|
|
2510
|
+
}));
|
|
2511
|
+
console.error(`Save this mnemonic phrase! It is the only way to recover this account.`);
|
|
2512
|
+
return;
|
|
2513
|
+
}
|
|
2319
2514
|
printHeading("Account Created");
|
|
2320
2515
|
console.log(` ${BOLD}Name:${RESET} ${name}`);
|
|
2321
2516
|
if (path)
|
|
@@ -2364,6 +2559,11 @@ async function accountImport(name, opts) {
|
|
|
2364
2559
|
derivationPath: path
|
|
2365
2560
|
});
|
|
2366
2561
|
await saveAccounts(accountsFile);
|
|
2562
|
+
if (isJsonOutput(opts)) {
|
|
2563
|
+
const address = publicKey ? toSs58(publicKey) : undefined;
|
|
2564
|
+
console.log(formatJson({ name, address, env: opts.env, path: path || undefined }));
|
|
2565
|
+
return;
|
|
2566
|
+
}
|
|
2367
2567
|
printHeading("Account Imported");
|
|
2368
2568
|
console.log(` ${BOLD}Name:${RESET} ${name}`);
|
|
2369
2569
|
if (path)
|
|
@@ -2386,6 +2586,10 @@ async function accountImport(name, opts) {
|
|
|
2386
2586
|
derivationPath: path
|
|
2387
2587
|
});
|
|
2388
2588
|
await saveAccounts(accountsFile);
|
|
2589
|
+
if (isJsonOutput(opts)) {
|
|
2590
|
+
console.log(formatJson({ name, address, publicKey: hexPub, path: path || undefined }));
|
|
2591
|
+
return;
|
|
2592
|
+
}
|
|
2389
2593
|
printHeading("Account Imported");
|
|
2390
2594
|
console.log(` ${BOLD}Name:${RESET} ${name}`);
|
|
2391
2595
|
if (path)
|
|
@@ -2394,7 +2598,7 @@ async function accountImport(name, opts) {
|
|
|
2394
2598
|
console.log();
|
|
2395
2599
|
}
|
|
2396
2600
|
}
|
|
2397
|
-
async function accountAddWatchOnly(name, address) {
|
|
2601
|
+
async function accountAddWatchOnly(name, address, opts = {}) {
|
|
2398
2602
|
if (!name) {
|
|
2399
2603
|
console.error(`Account name is required.
|
|
2400
2604
|
`);
|
|
@@ -2431,6 +2635,10 @@ async function accountAddWatchOnly(name, address) {
|
|
|
2431
2635
|
derivationPath: ""
|
|
2432
2636
|
});
|
|
2433
2637
|
await saveAccounts(accountsFile);
|
|
2638
|
+
if (isJsonOutput(opts)) {
|
|
2639
|
+
console.log(formatJson({ name, address: toSs58(hexPub), watchOnly: true }));
|
|
2640
|
+
return;
|
|
2641
|
+
}
|
|
2434
2642
|
printHeading("Account Added (watch-only)");
|
|
2435
2643
|
console.log(` ${BOLD}Name:${RESET} ${name}`);
|
|
2436
2644
|
console.log(` ${BOLD}Address:${RESET} ${toSs58(hexPub)}`);
|
|
@@ -2480,6 +2688,11 @@ async function accountDerive(sourceName, newName, opts) {
|
|
|
2480
2688
|
derivationPath: path
|
|
2481
2689
|
});
|
|
2482
2690
|
await saveAccounts(accountsFile);
|
|
2691
|
+
if (isJsonOutput(opts)) {
|
|
2692
|
+
const address = publicKey ? toSs58(publicKey) : undefined;
|
|
2693
|
+
console.log(formatJson({ name: newName, source: sourceName, path, address, env: sourceSecret.env }));
|
|
2694
|
+
return;
|
|
2695
|
+
}
|
|
2483
2696
|
printHeading("Account Derived");
|
|
2484
2697
|
console.log(` ${BOLD}Name:${RESET} ${newName}`);
|
|
2485
2698
|
console.log(` ${BOLD}Source:${RESET} ${sourceName}`);
|
|
@@ -2502,6 +2715,10 @@ async function accountDerive(sourceName, newName, opts) {
|
|
|
2502
2715
|
derivationPath: path
|
|
2503
2716
|
});
|
|
2504
2717
|
await saveAccounts(accountsFile);
|
|
2718
|
+
if (isJsonOutput(opts)) {
|
|
2719
|
+
console.log(formatJson({ name: newName, source: sourceName, path, address, publicKey: hexPub }));
|
|
2720
|
+
return;
|
|
2721
|
+
}
|
|
2505
2722
|
printHeading("Account Derived");
|
|
2506
2723
|
console.log(` ${BOLD}Name:${RESET} ${newName}`);
|
|
2507
2724
|
console.log(` ${BOLD}Source:${RESET} ${sourceName}`);
|
|
@@ -2510,14 +2727,43 @@ async function accountDerive(sourceName, newName, opts) {
|
|
|
2510
2727
|
console.log();
|
|
2511
2728
|
}
|
|
2512
2729
|
}
|
|
2513
|
-
async function accountList() {
|
|
2730
|
+
async function accountList(opts = {}) {
|
|
2731
|
+
const accountsFile = await loadAccounts();
|
|
2732
|
+
if (isJsonOutput(opts)) {
|
|
2733
|
+
const dev = DEV_NAMES.map((name) => ({
|
|
2734
|
+
name: name.charAt(0).toUpperCase() + name.slice(1),
|
|
2735
|
+
address: getDevAddress(name)
|
|
2736
|
+
}));
|
|
2737
|
+
const stored = accountsFile.accounts.map((account) => {
|
|
2738
|
+
let address;
|
|
2739
|
+
if (isWatchOnly(account)) {
|
|
2740
|
+
address = account.publicKey ? toSs58(account.publicKey) : undefined;
|
|
2741
|
+
} else if (account.secret !== undefined && isEnvSecret(account.secret)) {
|
|
2742
|
+
let pubKey = account.publicKey;
|
|
2743
|
+
if (!pubKey) {
|
|
2744
|
+
pubKey = tryDerivePublicKey(account.secret.env, account.derivationPath) ?? "";
|
|
2745
|
+
}
|
|
2746
|
+
address = pubKey ? toSs58(pubKey) : undefined;
|
|
2747
|
+
} else {
|
|
2748
|
+
address = toSs58(account.publicKey);
|
|
2749
|
+
}
|
|
2750
|
+
return {
|
|
2751
|
+
name: account.name,
|
|
2752
|
+
address,
|
|
2753
|
+
derivationPath: account.derivationPath || undefined,
|
|
2754
|
+
watchOnly: isWatchOnly(account),
|
|
2755
|
+
env: account.secret !== undefined && isEnvSecret(account.secret) ? account.secret.env : undefined
|
|
2756
|
+
};
|
|
2757
|
+
});
|
|
2758
|
+
console.log(formatJson({ dev, stored }));
|
|
2759
|
+
return;
|
|
2760
|
+
}
|
|
2514
2761
|
printHeading("Dev Accounts");
|
|
2515
2762
|
for (const name of DEV_NAMES) {
|
|
2516
2763
|
const display = name.charAt(0).toUpperCase() + name.slice(1);
|
|
2517
2764
|
const address = getDevAddress(name);
|
|
2518
2765
|
printItem(display, address);
|
|
2519
2766
|
}
|
|
2520
|
-
const accountsFile = await loadAccounts();
|
|
2521
2767
|
if (accountsFile.accounts.length > 0) {
|
|
2522
2768
|
printHeading("Stored Accounts");
|
|
2523
2769
|
for (const account of accountsFile.accounts) {
|
|
@@ -2547,7 +2793,7 @@ async function accountList() {
|
|
|
2547
2793
|
}
|
|
2548
2794
|
console.log();
|
|
2549
2795
|
}
|
|
2550
|
-
async function accountRemove(names) {
|
|
2796
|
+
async function accountRemove(names, opts = {}) {
|
|
2551
2797
|
if (names.length === 0) {
|
|
2552
2798
|
console.error(`At least one account name is required.
|
|
2553
2799
|
`);
|
|
@@ -2582,6 +2828,10 @@ async function accountRemove(names) {
|
|
|
2582
2828
|
accountsFile.accounts.splice(idx, 1);
|
|
2583
2829
|
}
|
|
2584
2830
|
await saveAccounts(accountsFile);
|
|
2831
|
+
if (isJsonOutput(opts)) {
|
|
2832
|
+
console.log(formatJson({ removed: names }));
|
|
2833
|
+
return;
|
|
2834
|
+
}
|
|
2585
2835
|
for (const name of names) {
|
|
2586
2836
|
console.log(`Account "${name}" removed.`);
|
|
2587
2837
|
}
|
|
@@ -2637,7 +2887,7 @@ async function accountInspect(input, opts) {
|
|
|
2637
2887
|
}
|
|
2638
2888
|
}
|
|
2639
2889
|
const ss58 = toSs58(publicKeyHex, prefix);
|
|
2640
|
-
if (opts
|
|
2890
|
+
if (isJsonOutput(opts)) {
|
|
2641
2891
|
const result = { publicKey: publicKeyHex, ss58, prefix };
|
|
2642
2892
|
if (name)
|
|
2643
2893
|
result.name = name;
|
|
@@ -2680,6 +2930,13 @@ async function handleApis2(target, args, opts) {
|
|
|
2680
2930
|
const { name: chainName2, chain: chainConfig2 } = resolveChain(config2, opts.chain);
|
|
2681
2931
|
const meta = await loadMeta(chainName2, chainConfig2, opts.rpc);
|
|
2682
2932
|
const apis = listRuntimeApis(meta);
|
|
2933
|
+
if (isJsonOutput(opts)) {
|
|
2934
|
+
console.log(formatJson({
|
|
2935
|
+
chain: chainName2,
|
|
2936
|
+
apis: apis.map((a) => ({ name: a.name, methods: a.methods.length }))
|
|
2937
|
+
}));
|
|
2938
|
+
return;
|
|
2939
|
+
}
|
|
2683
2940
|
printHeading(`Runtime APIs on ${chainName2} (${apis.length})`);
|
|
2684
2941
|
for (const api of apis) {
|
|
2685
2942
|
printItem(api.name, `${api.methods.length} methods`);
|
|
@@ -2702,7 +2959,24 @@ async function handleApis2(target, args, opts) {
|
|
|
2702
2959
|
const meta = await loadMeta(chainName, chainConfig, opts.rpc);
|
|
2703
2960
|
const api = resolveRuntimeApi2(meta, apiName);
|
|
2704
2961
|
if (api.methods.length === 0) {
|
|
2705
|
-
|
|
2962
|
+
if (isJsonOutput(opts)) {
|
|
2963
|
+
console.log(formatJson({ chain: chainName, api: api.name, methods: [] }));
|
|
2964
|
+
} else {
|
|
2965
|
+
console.log(`No methods in ${api.name}.`);
|
|
2966
|
+
}
|
|
2967
|
+
return;
|
|
2968
|
+
}
|
|
2969
|
+
if (isJsonOutput(opts)) {
|
|
2970
|
+
console.log(formatJson({
|
|
2971
|
+
chain: chainName,
|
|
2972
|
+
api: api.name,
|
|
2973
|
+
methods: api.methods.map((m) => ({
|
|
2974
|
+
name: m.name,
|
|
2975
|
+
args: describeRuntimeApiMethodArgs(meta, m),
|
|
2976
|
+
returns: describeType(meta.lookup, m.output),
|
|
2977
|
+
docs: firstSentence(m.docs)
|
|
2978
|
+
}))
|
|
2979
|
+
}));
|
|
2706
2980
|
return;
|
|
2707
2981
|
}
|
|
2708
2982
|
printHeading(`${api.name} Methods`);
|
|
@@ -2733,7 +3007,7 @@ async function handleApis2(target, args, opts) {
|
|
|
2733
3007
|
const parsedArgs = await parseRuntimeApiArgs2(meta, method, effectiveArgs);
|
|
2734
3008
|
const unsafeApi = clientHandle.client.getUnsafeApi();
|
|
2735
3009
|
const result = await unsafeApi.apis[api.name][method.name](...parsedArgs);
|
|
2736
|
-
const format = opts.output ?? "pretty";
|
|
3010
|
+
const format = isJsonOutput(opts) ? "json" : opts.output ?? "pretty";
|
|
2737
3011
|
printResult(result, format);
|
|
2738
3012
|
} finally {
|
|
2739
3013
|
clientHandle.destroy();
|
|
@@ -2769,7 +3043,6 @@ init_output();
|
|
|
2769
3043
|
var CHAIN_HELP = `
|
|
2770
3044
|
${BOLD}Usage:${RESET}
|
|
2771
3045
|
$ dot chain add <name> --rpc <url> Add a chain via WebSocket RPC
|
|
2772
|
-
$ dot chain add <name> --light-client Add a chain via Smoldot light client
|
|
2773
3046
|
$ dot chain remove <name> Remove a chain
|
|
2774
3047
|
$ dot chain update [name] Re-fetch metadata (default chain if omitted)
|
|
2775
3048
|
$ dot chain update --all Re-fetch metadata for all configured chains
|
|
@@ -2779,7 +3052,8 @@ ${BOLD}Usage:${RESET}
|
|
|
2779
3052
|
${BOLD}Examples:${RESET}
|
|
2780
3053
|
$ dot chain add kusama --rpc wss://kusama-rpc.polkadot.io
|
|
2781
3054
|
$ dot chain add kusama --rpc wss://kusama-rpc.polkadot.io --rpc wss://kusama-rpc.dwellir.com
|
|
2782
|
-
$ dot chain add
|
|
3055
|
+
$ dot chain add my-para --rpc wss://rpc.example.com --relay polkadot
|
|
3056
|
+
$ dot chain add my-para --rpc wss://rpc.example.com --relay polkadot --parachain-id 2000
|
|
2783
3057
|
$ dot chain default kusama
|
|
2784
3058
|
$ dot chain list
|
|
2785
3059
|
$ dot chain update
|
|
@@ -2788,10 +3062,10 @@ ${BOLD}Examples:${RESET}
|
|
|
2788
3062
|
$ dot chain remove kusama
|
|
2789
3063
|
`.trimStart();
|
|
2790
3064
|
function registerChainCommands(cli) {
|
|
2791
|
-
cli.command("chain [action] [name]", "Manage chains (add, remove, update, list, default)").alias("chains").option("--all", "Update all configured chains").action(async (action, name, opts) => {
|
|
3065
|
+
cli.command("chain [action] [name]", "Manage chains (add, remove, update, list, default)").alias("chains").option("--all", "Update all configured chains").option("--relay <name>", "Parent relay chain for this parachain").option("--parachain-id <id>", "Parachain ID (auto-detected if omitted with --relay)").action(async (action, name, opts) => {
|
|
2792
3066
|
if (!action) {
|
|
2793
3067
|
if (process.argv[2] === "chains")
|
|
2794
|
-
return chainList();
|
|
3068
|
+
return chainList(opts);
|
|
2795
3069
|
console.log(CHAIN_HELP);
|
|
2796
3070
|
return;
|
|
2797
3071
|
}
|
|
@@ -2799,13 +3073,13 @@ function registerChainCommands(cli) {
|
|
|
2799
3073
|
case "add":
|
|
2800
3074
|
return chainAdd(name, opts);
|
|
2801
3075
|
case "remove":
|
|
2802
|
-
return chainRemove(name);
|
|
3076
|
+
return chainRemove(name, opts);
|
|
2803
3077
|
case "list":
|
|
2804
|
-
return chainList();
|
|
3078
|
+
return chainList(opts);
|
|
2805
3079
|
case "update":
|
|
2806
3080
|
return chainUpdate(name, opts);
|
|
2807
3081
|
case "default":
|
|
2808
|
-
return chainDefault(name);
|
|
3082
|
+
return chainDefault(name, opts);
|
|
2809
3083
|
default:
|
|
2810
3084
|
console.error(`Unknown action "${action}".
|
|
2811
3085
|
`);
|
|
@@ -2819,34 +3093,70 @@ async function chainAdd(name, opts) {
|
|
|
2819
3093
|
console.error(`Chain name is required.
|
|
2820
3094
|
`);
|
|
2821
3095
|
console.error("Usage: dot chain add <name> --rpc <url>");
|
|
2822
|
-
console.error(" dot chain add <name> --light-client");
|
|
2823
3096
|
process.exit(1);
|
|
2824
3097
|
}
|
|
2825
|
-
if (!opts.rpc
|
|
2826
|
-
console.error(`Must provide
|
|
3098
|
+
if (!opts.rpc) {
|
|
3099
|
+
console.error(`Must provide --rpc <url>.
|
|
2827
3100
|
`);
|
|
2828
3101
|
console.error("Usage: dot chain add <name> --rpc <url>");
|
|
2829
|
-
console.error(" dot chain add <name> --light-client");
|
|
2830
3102
|
process.exit(1);
|
|
2831
3103
|
}
|
|
2832
|
-
const
|
|
2833
|
-
|
|
2834
|
-
|
|
2835
|
-
|
|
2836
|
-
|
|
3104
|
+
const parachainIdRaw = opts.parachainId != null ? Number(opts.parachainId) : undefined;
|
|
3105
|
+
if (parachainIdRaw != null && !opts.relay) {
|
|
3106
|
+
console.error(`Cannot set --parachain-id without --relay.
|
|
3107
|
+
`);
|
|
3108
|
+
console.error("Usage: dot chain add <name> --rpc <url> --relay <relay> --parachain-id <id>");
|
|
3109
|
+
process.exit(1);
|
|
3110
|
+
}
|
|
3111
|
+
const chainConfig = { rpc: opts.rpc };
|
|
3112
|
+
process.stderr.write(`Connecting to ${name}...
|
|
3113
|
+
`);
|
|
2837
3114
|
const clientHandle = await createChainClient(name, chainConfig, opts.rpc);
|
|
2838
3115
|
try {
|
|
2839
|
-
|
|
3116
|
+
process.stderr.write(`Fetching metadata...
|
|
3117
|
+
`);
|
|
2840
3118
|
await fetchMetadataFromChain(clientHandle, name);
|
|
3119
|
+
if (opts.relay) {
|
|
3120
|
+
const config2 = await loadConfig();
|
|
3121
|
+
const relayResolved = findChainName(config2, opts.relay);
|
|
3122
|
+
if (!relayResolved) {
|
|
3123
|
+
throw new Error(`Relay chain "${opts.relay}" not found. Add it first with: dot chain add ${opts.relay} --rpc <url>`);
|
|
3124
|
+
}
|
|
3125
|
+
chainConfig.relay = relayResolved;
|
|
3126
|
+
if (parachainIdRaw != null) {
|
|
3127
|
+
chainConfig.parachainId = parachainIdRaw;
|
|
3128
|
+
} else {
|
|
3129
|
+
process.stderr.write(`Detecting parachain ID...
|
|
3130
|
+
`);
|
|
3131
|
+
const detected = await getParachainId(clientHandle);
|
|
3132
|
+
if (detected != null) {
|
|
3133
|
+
chainConfig.parachainId = detected;
|
|
3134
|
+
process.stderr.write(`Detected parachain ID: ${detected}
|
|
3135
|
+
`);
|
|
3136
|
+
} else {
|
|
3137
|
+
process.stderr.write(`Could not detect parachain ID. Use --parachain-id to set it manually.
|
|
3138
|
+
`);
|
|
3139
|
+
}
|
|
3140
|
+
}
|
|
3141
|
+
}
|
|
2841
3142
|
const config = await loadConfig();
|
|
2842
3143
|
config.chains[name] = chainConfig;
|
|
2843
3144
|
await saveConfig(config);
|
|
2844
|
-
|
|
3145
|
+
const result = { action: "added", chain: name };
|
|
3146
|
+
if (chainConfig.relay)
|
|
3147
|
+
result.relay = chainConfig.relay;
|
|
3148
|
+
if (chainConfig.parachainId != null)
|
|
3149
|
+
result.parachainId = chainConfig.parachainId;
|
|
3150
|
+
if (isJsonOutput(opts)) {
|
|
3151
|
+
console.log(formatJson(result));
|
|
3152
|
+
} else {
|
|
3153
|
+
console.log(`Chain "${name}" added successfully.`);
|
|
3154
|
+
}
|
|
2845
3155
|
} finally {
|
|
2846
3156
|
clientHandle.destroy();
|
|
2847
3157
|
}
|
|
2848
3158
|
}
|
|
2849
|
-
async function chainRemove(name) {
|
|
3159
|
+
async function chainRemove(name, opts = {}) {
|
|
2850
3160
|
if (!name) {
|
|
2851
3161
|
console.error("Usage: dot chain remove <name>");
|
|
2852
3162
|
process.exit(1);
|
|
@@ -2859,32 +3169,85 @@ async function chainRemove(name) {
|
|
|
2859
3169
|
if (BUILTIN_CHAIN_NAMES.has(resolved)) {
|
|
2860
3170
|
throw new Error(`Cannot remove the built-in "${resolved}" chain.`);
|
|
2861
3171
|
}
|
|
3172
|
+
const orphans = Object.entries(config.chains).filter(([, c]) => c.relay === resolved).map(([n]) => n);
|
|
3173
|
+
if (orphans.length > 0) {
|
|
3174
|
+
console.error(`Warning: ${orphans.length} chain(s) reference "${resolved}" as their relay: ${orphans.join(", ")}`);
|
|
3175
|
+
}
|
|
2862
3176
|
delete config.chains[resolved];
|
|
2863
3177
|
if (config.defaultChain === resolved) {
|
|
2864
3178
|
config.defaultChain = "polkadot";
|
|
2865
|
-
|
|
3179
|
+
if (!isJsonOutput(opts))
|
|
3180
|
+
console.log(`Default chain reset to "polkadot".`);
|
|
2866
3181
|
}
|
|
2867
3182
|
await saveConfig(config);
|
|
2868
3183
|
await removeChainData(resolved);
|
|
2869
|
-
|
|
3184
|
+
if (isJsonOutput(opts)) {
|
|
3185
|
+
console.log(formatJson({ action: "removed", chain: resolved }));
|
|
3186
|
+
} else {
|
|
3187
|
+
console.log(`Chain "${resolved}" removed.`);
|
|
3188
|
+
}
|
|
2870
3189
|
}
|
|
2871
|
-
async function chainList() {
|
|
3190
|
+
async function chainList(opts = {}) {
|
|
2872
3191
|
const config = await loadConfig();
|
|
3192
|
+
if (isJsonOutput(opts)) {
|
|
3193
|
+
const chains = Object.entries(config.chains).map(([name, chainConfig]) => ({
|
|
3194
|
+
name,
|
|
3195
|
+
default: name === config.defaultChain,
|
|
3196
|
+
rpc: Array.isArray(chainConfig.rpc) ? chainConfig.rpc : [chainConfig.rpc],
|
|
3197
|
+
...chainConfig.relay && { relay: chainConfig.relay },
|
|
3198
|
+
...chainConfig.parachainId != null && { parachainId: chainConfig.parachainId }
|
|
3199
|
+
}));
|
|
3200
|
+
console.log(formatJson({ chains }));
|
|
3201
|
+
return;
|
|
3202
|
+
}
|
|
2873
3203
|
printHeading("Configured Chains");
|
|
3204
|
+
const parachainsByRelay = new Map;
|
|
3205
|
+
const standalone = [];
|
|
2874
3206
|
for (const [name, chainConfig] of Object.entries(config.chains)) {
|
|
2875
|
-
|
|
2876
|
-
|
|
2877
|
-
|
|
2878
|
-
|
|
2879
|
-
} else {
|
|
2880
|
-
const rpcs = Array.isArray(chainConfig.rpc) ? chainConfig.rpc : [chainConfig.rpc];
|
|
2881
|
-
console.log(` ${CYAN}${name}${RESET}${marker} ${DIM}${rpcs[0]}${RESET}`);
|
|
2882
|
-
for (let i = 1;i < rpcs.length; i++) {
|
|
2883
|
-
console.log(` ${DIM}${rpcs[i]}${RESET}`);
|
|
2884
|
-
}
|
|
3207
|
+
if (chainConfig.relay) {
|
|
3208
|
+
const paras = parachainsByRelay.get(chainConfig.relay) ?? [];
|
|
3209
|
+
paras.push([name, chainConfig]);
|
|
3210
|
+
parachainsByRelay.set(chainConfig.relay, paras);
|
|
2885
3211
|
}
|
|
2886
3212
|
}
|
|
2887
|
-
|
|
3213
|
+
const relayNames = new Set(parachainsByRelay.keys());
|
|
3214
|
+
for (const [name, chainConfig] of Object.entries(config.chains)) {
|
|
3215
|
+
if (relayNames.has(name))
|
|
3216
|
+
continue;
|
|
3217
|
+
if (chainConfig.relay)
|
|
3218
|
+
continue;
|
|
3219
|
+
standalone.push([name, chainConfig]);
|
|
3220
|
+
}
|
|
3221
|
+
for (const relayName of relayNames) {
|
|
3222
|
+
const relayConfig = config.chains[relayName];
|
|
3223
|
+
if (relayConfig) {
|
|
3224
|
+
printChainLine(" ", relayName, relayConfig, config.defaultChain);
|
|
3225
|
+
}
|
|
3226
|
+
const paras = parachainsByRelay.get(relayName) ?? [];
|
|
3227
|
+
for (let i = 0;i < paras.length; i++) {
|
|
3228
|
+
const [name, chainConfig] = paras[i];
|
|
3229
|
+
const isLast = i === paras.length - 1;
|
|
3230
|
+
const prefix = isLast ? " └─ " : " ├─ ";
|
|
3231
|
+
const idSuffix = chainConfig.parachainId != null ? ` ${DIM}[${chainConfig.parachainId}]${RESET}` : "";
|
|
3232
|
+
printChainLine(prefix, name, chainConfig, config.defaultChain, idSuffix);
|
|
3233
|
+
}
|
|
3234
|
+
console.log();
|
|
3235
|
+
}
|
|
3236
|
+
for (const [name, chainConfig] of standalone) {
|
|
3237
|
+
printChainLine(" ", name, chainConfig, config.defaultChain);
|
|
3238
|
+
}
|
|
3239
|
+
if (standalone.length > 0)
|
|
3240
|
+
console.log();
|
|
3241
|
+
}
|
|
3242
|
+
function printChainLine(prefix, name, chainConfig, defaultChain, suffix = "") {
|
|
3243
|
+
const isDefault = name === defaultChain;
|
|
3244
|
+
const marker = isDefault ? ` ${BOLD}(default)${RESET}` : "";
|
|
3245
|
+
const rpcs = Array.isArray(chainConfig.rpc) ? chainConfig.rpc : [chainConfig.rpc];
|
|
3246
|
+
console.log(`${prefix}${CYAN}${name}${RESET}${suffix}${marker} ${DIM}${rpcs[0]}${RESET}`);
|
|
3247
|
+
const indent = prefix.replace(/[^\s]/g, " ");
|
|
3248
|
+
for (let i = 1;i < rpcs.length; i++) {
|
|
3249
|
+
console.log(`${indent} ${DIM}${rpcs[i]}${RESET}`);
|
|
3250
|
+
}
|
|
2888
3251
|
}
|
|
2889
3252
|
async function chainUpdate(name, opts) {
|
|
2890
3253
|
const config = await loadConfig();
|
|
@@ -2893,19 +3256,26 @@ async function chainUpdate(name, opts) {
|
|
|
2893
3256
|
return;
|
|
2894
3257
|
}
|
|
2895
3258
|
const { name: chainName, chain: chainConfig } = resolveChain(config, name);
|
|
2896
|
-
|
|
3259
|
+
process.stderr.write(`Connecting to ${chainName}...
|
|
3260
|
+
`);
|
|
2897
3261
|
const clientHandle = await createChainClient(chainName, chainConfig, opts.rpc);
|
|
2898
3262
|
try {
|
|
2899
|
-
|
|
3263
|
+
process.stderr.write(`Fetching metadata...
|
|
3264
|
+
`);
|
|
2900
3265
|
await fetchMetadataFromChain(clientHandle, chainName);
|
|
2901
|
-
|
|
3266
|
+
if (isJsonOutput(opts)) {
|
|
3267
|
+
console.log(formatJson({ action: "updated", chain: chainName }));
|
|
3268
|
+
} else {
|
|
3269
|
+
console.log(`Metadata for "${chainName}" updated.`);
|
|
3270
|
+
}
|
|
2902
3271
|
} finally {
|
|
2903
3272
|
clientHandle.destroy();
|
|
2904
3273
|
}
|
|
2905
3274
|
}
|
|
2906
3275
|
async function chainUpdateAll(config) {
|
|
2907
3276
|
const chainNames = Object.keys(config.chains).sort();
|
|
2908
|
-
|
|
3277
|
+
process.stderr.write(`Updating metadata for ${chainNames.length} chains...
|
|
3278
|
+
|
|
2909
3279
|
`);
|
|
2910
3280
|
const results = await Promise.allSettled(chainNames.map(async (chainName) => {
|
|
2911
3281
|
const chainConfig = config.chains[chainName];
|
|
@@ -2932,7 +3302,7 @@ ${failed} of ${chainNames.length} chains failed to update.`);
|
|
|
2932
3302
|
process.exit(1);
|
|
2933
3303
|
}
|
|
2934
3304
|
}
|
|
2935
|
-
async function chainDefault(name) {
|
|
3305
|
+
async function chainDefault(name, opts = {}) {
|
|
2936
3306
|
if (!name) {
|
|
2937
3307
|
console.error("Usage: dot chain default <name>");
|
|
2938
3308
|
process.exit(1);
|
|
@@ -2945,7 +3315,11 @@ async function chainDefault(name) {
|
|
|
2945
3315
|
}
|
|
2946
3316
|
config.defaultChain = resolved;
|
|
2947
3317
|
await saveConfig(config);
|
|
2948
|
-
|
|
3318
|
+
if (isJsonOutput(opts)) {
|
|
3319
|
+
console.log(formatJson({ action: "default", chain: resolved }));
|
|
3320
|
+
} else {
|
|
3321
|
+
console.log(`Default chain set to "${resolved}".`);
|
|
3322
|
+
}
|
|
2949
3323
|
}
|
|
2950
3324
|
|
|
2951
3325
|
// src/commands/completions.ts
|
|
@@ -3045,6 +3419,13 @@ async function handleConst(target, opts) {
|
|
|
3045
3419
|
const meta = await loadMeta(chainName2, chainConfig2, opts.rpc);
|
|
3046
3420
|
const pallets = listPallets(meta);
|
|
3047
3421
|
const withConsts = pallets.filter((p) => p.constants.length > 0);
|
|
3422
|
+
if (isJsonOutput(opts)) {
|
|
3423
|
+
console.log(formatJson({
|
|
3424
|
+
chain: chainName2,
|
|
3425
|
+
pallets: withConsts.map((p) => ({ name: p.name, constants: p.constants.length }))
|
|
3426
|
+
}));
|
|
3427
|
+
return;
|
|
3428
|
+
}
|
|
3048
3429
|
printHeading(`Pallets with constants on ${chainName2} (${withConsts.length})`);
|
|
3049
3430
|
for (const p of withConsts) {
|
|
3050
3431
|
printItem(p.name, `${p.constants.length} constants`);
|
|
@@ -3065,7 +3446,23 @@ async function handleConst(target, opts) {
|
|
|
3065
3446
|
throw new Error(suggestMessage("pallet", pallet, palletNames));
|
|
3066
3447
|
}
|
|
3067
3448
|
if (palletInfo.constants.length === 0) {
|
|
3068
|
-
|
|
3449
|
+
if (isJsonOutput(opts)) {
|
|
3450
|
+
console.log(formatJson({ chain: chainName, pallet: palletInfo.name, constants: [] }));
|
|
3451
|
+
} else {
|
|
3452
|
+
console.log(`No constants in ${palletInfo.name}.`);
|
|
3453
|
+
}
|
|
3454
|
+
return;
|
|
3455
|
+
}
|
|
3456
|
+
if (isJsonOutput(opts)) {
|
|
3457
|
+
console.log(formatJson({
|
|
3458
|
+
chain: chainName,
|
|
3459
|
+
pallet: palletInfo.name,
|
|
3460
|
+
constants: palletInfo.constants.map((c) => ({
|
|
3461
|
+
name: c.name,
|
|
3462
|
+
type: describeType(meta.lookup, c.typeId),
|
|
3463
|
+
docs: firstSentence(c.docs)
|
|
3464
|
+
}))
|
|
3465
|
+
}));
|
|
3069
3466
|
return;
|
|
3070
3467
|
}
|
|
3071
3468
|
printHeading(`${palletInfo.name} Constants`);
|
|
@@ -3094,9 +3491,9 @@ async function handleConst(target, opts) {
|
|
|
3094
3491
|
throw new Error(suggestMessage(`constant in ${palletInfo.name}`, item, constNames));
|
|
3095
3492
|
}
|
|
3096
3493
|
const unsafeApi = clientHandle.client.getUnsafeApi();
|
|
3097
|
-
const
|
|
3098
|
-
const result =
|
|
3099
|
-
const format = opts.output ?? "pretty";
|
|
3494
|
+
const staticApis = await unsafeApi.getStaticApis();
|
|
3495
|
+
const result = staticApis.constants[palletInfo.name][constantItem.name];
|
|
3496
|
+
const format = isJsonOutput(opts) ? "json" : opts.output ?? "pretty";
|
|
3100
3497
|
printResult(result, format);
|
|
3101
3498
|
} finally {
|
|
3102
3499
|
clientHandle.destroy();
|
|
@@ -3112,7 +3509,8 @@ async function loadMeta2(chainName, chainConfig, rpcOverride) {
|
|
|
3112
3509
|
try {
|
|
3113
3510
|
return await getOrFetchMetadata(chainName);
|
|
3114
3511
|
} catch {
|
|
3115
|
-
|
|
3512
|
+
process.stderr.write(`Fetching metadata from ${chainName}...
|
|
3513
|
+
`);
|
|
3116
3514
|
const clientHandle = await createChainClient(chainName, chainConfig, rpcOverride);
|
|
3117
3515
|
try {
|
|
3118
3516
|
return await getOrFetchMetadata(chainName, clientHandle);
|
|
@@ -3136,6 +3534,13 @@ async function handleCalls2(target, opts) {
|
|
|
3136
3534
|
const meta2 = await loadMeta2(chainName2, chainConfig2, opts.rpc);
|
|
3137
3535
|
const pallets = listPallets(meta2);
|
|
3138
3536
|
const withCalls = pallets.filter((p) => p.calls.length > 0);
|
|
3537
|
+
if (isJsonOutput(opts)) {
|
|
3538
|
+
console.log(formatJson({
|
|
3539
|
+
chain: chainName2,
|
|
3540
|
+
pallets: withCalls.map((p) => ({ name: p.name, calls: p.calls.length }))
|
|
3541
|
+
}));
|
|
3542
|
+
return;
|
|
3543
|
+
}
|
|
3139
3544
|
printHeading(`Pallets with calls on ${chainName2} (${withCalls.length})`);
|
|
3140
3545
|
for (const p of withCalls) {
|
|
3141
3546
|
printItem(p.name, `${p.calls.length} calls`);
|
|
@@ -3152,7 +3557,23 @@ async function handleCalls2(target, opts) {
|
|
|
3152
3557
|
const pallet = resolvePallet2(meta, palletName);
|
|
3153
3558
|
if (!itemName) {
|
|
3154
3559
|
if (pallet.calls.length === 0) {
|
|
3155
|
-
|
|
3560
|
+
if (isJsonOutput(opts)) {
|
|
3561
|
+
console.log(formatJson({ chain: chainName, pallet: pallet.name, calls: [] }));
|
|
3562
|
+
} else {
|
|
3563
|
+
console.log(`No calls in ${pallet.name}.`);
|
|
3564
|
+
}
|
|
3565
|
+
return;
|
|
3566
|
+
}
|
|
3567
|
+
if (isJsonOutput(opts)) {
|
|
3568
|
+
console.log(formatJson({
|
|
3569
|
+
chain: chainName,
|
|
3570
|
+
pallet: pallet.name,
|
|
3571
|
+
calls: pallet.calls.map((c) => ({
|
|
3572
|
+
name: c.name,
|
|
3573
|
+
args: describeCallArgs(meta, pallet.name, c.name),
|
|
3574
|
+
docs: firstSentence(c.docs)
|
|
3575
|
+
}))
|
|
3576
|
+
}));
|
|
3156
3577
|
return;
|
|
3157
3578
|
}
|
|
3158
3579
|
printHeading(`${pallet.name} Calls`);
|
|
@@ -3172,6 +3593,17 @@ async function handleCalls2(target, opts) {
|
|
|
3172
3593
|
const names = pallet.calls.map((c) => c.name);
|
|
3173
3594
|
throw new Error(suggestMessage(`call in ${pallet.name}`, itemName, names));
|
|
3174
3595
|
}
|
|
3596
|
+
if (isJsonOutput(opts)) {
|
|
3597
|
+
console.log(formatJson({
|
|
3598
|
+
chain: chainName,
|
|
3599
|
+
pallet: pallet.name,
|
|
3600
|
+
item: callItem.name,
|
|
3601
|
+
category: "call",
|
|
3602
|
+
args: describeCallArgs(meta, pallet.name, callItem.name),
|
|
3603
|
+
docs: callItem.docs
|
|
3604
|
+
}));
|
|
3605
|
+
return;
|
|
3606
|
+
}
|
|
3175
3607
|
printHeading(`${pallet.name}.${callItem.name} (Call)`);
|
|
3176
3608
|
const args = describeCallArgs(meta, pallet.name, callItem.name);
|
|
3177
3609
|
console.log(` ${BOLD}Args:${RESET} ${args}`);
|
|
@@ -3188,6 +3620,13 @@ async function handleEvents2(target, opts) {
|
|
|
3188
3620
|
const meta2 = await loadMeta2(chainName2, chainConfig2, opts.rpc);
|
|
3189
3621
|
const pallets = listPallets(meta2);
|
|
3190
3622
|
const withEvents = pallets.filter((p) => p.events.length > 0);
|
|
3623
|
+
if (isJsonOutput(opts)) {
|
|
3624
|
+
console.log(formatJson({
|
|
3625
|
+
chain: chainName2,
|
|
3626
|
+
pallets: withEvents.map((p) => ({ name: p.name, events: p.events.length }))
|
|
3627
|
+
}));
|
|
3628
|
+
return;
|
|
3629
|
+
}
|
|
3191
3630
|
printHeading(`Pallets with events on ${chainName2} (${withEvents.length})`);
|
|
3192
3631
|
for (const p of withEvents) {
|
|
3193
3632
|
printItem(p.name, `${p.events.length} events`);
|
|
@@ -3204,7 +3643,23 @@ async function handleEvents2(target, opts) {
|
|
|
3204
3643
|
const pallet = resolvePallet2(meta, palletName);
|
|
3205
3644
|
if (!itemName) {
|
|
3206
3645
|
if (pallet.events.length === 0) {
|
|
3207
|
-
|
|
3646
|
+
if (isJsonOutput(opts)) {
|
|
3647
|
+
console.log(formatJson({ chain: chainName, pallet: pallet.name, events: [] }));
|
|
3648
|
+
} else {
|
|
3649
|
+
console.log(`No events in ${pallet.name}.`);
|
|
3650
|
+
}
|
|
3651
|
+
return;
|
|
3652
|
+
}
|
|
3653
|
+
if (isJsonOutput(opts)) {
|
|
3654
|
+
console.log(formatJson({
|
|
3655
|
+
chain: chainName,
|
|
3656
|
+
pallet: pallet.name,
|
|
3657
|
+
events: pallet.events.map((e) => ({
|
|
3658
|
+
name: e.name,
|
|
3659
|
+
fields: describeEventFields(meta, pallet.name, e.name),
|
|
3660
|
+
docs: firstSentence(e.docs)
|
|
3661
|
+
}))
|
|
3662
|
+
}));
|
|
3208
3663
|
return;
|
|
3209
3664
|
}
|
|
3210
3665
|
printHeading(`${pallet.name} Events`);
|
|
@@ -3224,6 +3679,17 @@ async function handleEvents2(target, opts) {
|
|
|
3224
3679
|
const names = pallet.events.map((e) => e.name);
|
|
3225
3680
|
throw new Error(suggestMessage(`event in ${pallet.name}`, itemName, names));
|
|
3226
3681
|
}
|
|
3682
|
+
if (isJsonOutput(opts)) {
|
|
3683
|
+
console.log(formatJson({
|
|
3684
|
+
chain: chainName,
|
|
3685
|
+
pallet: pallet.name,
|
|
3686
|
+
item: eventItem.name,
|
|
3687
|
+
category: "event",
|
|
3688
|
+
fields: describeEventFields(meta, pallet.name, eventItem.name),
|
|
3689
|
+
docs: eventItem.docs
|
|
3690
|
+
}));
|
|
3691
|
+
return;
|
|
3692
|
+
}
|
|
3227
3693
|
printHeading(`${pallet.name}.${eventItem.name} (Event)`);
|
|
3228
3694
|
const fields = describeEventFields(meta, pallet.name, eventItem.name);
|
|
3229
3695
|
console.log(` ${BOLD}Fields:${RESET} ${fields}`);
|
|
@@ -3240,6 +3706,13 @@ async function handleErrors2(target, opts) {
|
|
|
3240
3706
|
const meta2 = await loadMeta2(chainName2, chainConfig2, opts.rpc);
|
|
3241
3707
|
const pallets = listPallets(meta2);
|
|
3242
3708
|
const withErrors = pallets.filter((p) => p.errors.length > 0);
|
|
3709
|
+
if (isJsonOutput(opts)) {
|
|
3710
|
+
console.log(formatJson({
|
|
3711
|
+
chain: chainName2,
|
|
3712
|
+
pallets: withErrors.map((p) => ({ name: p.name, errors: p.errors.length }))
|
|
3713
|
+
}));
|
|
3714
|
+
return;
|
|
3715
|
+
}
|
|
3243
3716
|
printHeading(`Pallets with errors on ${chainName2} (${withErrors.length})`);
|
|
3244
3717
|
for (const p of withErrors) {
|
|
3245
3718
|
printItem(p.name, `${p.errors.length} errors`);
|
|
@@ -3256,7 +3729,19 @@ async function handleErrors2(target, opts) {
|
|
|
3256
3729
|
const pallet = resolvePallet2(meta, palletName);
|
|
3257
3730
|
if (!itemName) {
|
|
3258
3731
|
if (pallet.errors.length === 0) {
|
|
3259
|
-
|
|
3732
|
+
if (isJsonOutput(opts)) {
|
|
3733
|
+
console.log(formatJson({ chain: chainName, pallet: pallet.name, errors: [] }));
|
|
3734
|
+
} else {
|
|
3735
|
+
console.log(`No errors in ${pallet.name}.`);
|
|
3736
|
+
}
|
|
3737
|
+
return;
|
|
3738
|
+
}
|
|
3739
|
+
if (isJsonOutput(opts)) {
|
|
3740
|
+
console.log(formatJson({
|
|
3741
|
+
chain: chainName,
|
|
3742
|
+
pallet: pallet.name,
|
|
3743
|
+
errors: pallet.errors.map((e) => ({ name: e.name, docs: firstSentence(e.docs) }))
|
|
3744
|
+
}));
|
|
3260
3745
|
return;
|
|
3261
3746
|
}
|
|
3262
3747
|
printHeading(`${pallet.name} Errors`);
|
|
@@ -3275,6 +3760,16 @@ async function handleErrors2(target, opts) {
|
|
|
3275
3760
|
const names = pallet.errors.map((e) => e.name);
|
|
3276
3761
|
throw new Error(suggestMessage(`error in ${pallet.name}`, itemName, names));
|
|
3277
3762
|
}
|
|
3763
|
+
if (isJsonOutput(opts)) {
|
|
3764
|
+
console.log(formatJson({
|
|
3765
|
+
chain: chainName,
|
|
3766
|
+
pallet: pallet.name,
|
|
3767
|
+
item: errorItem.name,
|
|
3768
|
+
category: "error",
|
|
3769
|
+
docs: errorItem.docs
|
|
3770
|
+
}));
|
|
3771
|
+
return;
|
|
3772
|
+
}
|
|
3278
3773
|
printHeading(`${pallet.name}.${errorItem.name} (Error)`);
|
|
3279
3774
|
if (errorItem.docs.length) {
|
|
3280
3775
|
printDocs(errorItem.docs);
|
|
@@ -3288,6 +3783,13 @@ async function handleStorage2(target, opts) {
|
|
|
3288
3783
|
const meta2 = await loadMeta2(chainName2, chainConfig2, opts.rpc);
|
|
3289
3784
|
const pallets = listPallets(meta2);
|
|
3290
3785
|
const withStorage = pallets.filter((p) => p.storage.length > 0);
|
|
3786
|
+
if (isJsonOutput(opts)) {
|
|
3787
|
+
console.log(formatJson({
|
|
3788
|
+
chain: chainName2,
|
|
3789
|
+
pallets: withStorage.map((p) => ({ name: p.name, storage: p.storage.length }))
|
|
3790
|
+
}));
|
|
3791
|
+
return;
|
|
3792
|
+
}
|
|
3291
3793
|
printHeading(`Pallets with storage on ${chainName2} (${withStorage.length})`);
|
|
3292
3794
|
for (const p of withStorage) {
|
|
3293
3795
|
printItem(p.name, `${p.storage.length} storage`);
|
|
@@ -3304,7 +3806,23 @@ async function handleStorage2(target, opts) {
|
|
|
3304
3806
|
const pallet = resolvePallet2(meta, palletName);
|
|
3305
3807
|
if (!itemName) {
|
|
3306
3808
|
if (pallet.storage.length === 0) {
|
|
3307
|
-
|
|
3809
|
+
if (isJsonOutput(opts)) {
|
|
3810
|
+
console.log(formatJson({ chain: chainName, pallet: pallet.name, storage: [] }));
|
|
3811
|
+
} else {
|
|
3812
|
+
console.log(`No storage items in ${pallet.name}.`);
|
|
3813
|
+
}
|
|
3814
|
+
return;
|
|
3815
|
+
}
|
|
3816
|
+
if (isJsonOutput(opts)) {
|
|
3817
|
+
console.log(formatJson({
|
|
3818
|
+
chain: chainName,
|
|
3819
|
+
pallet: pallet.name,
|
|
3820
|
+
storage: pallet.storage.map((s) => {
|
|
3821
|
+
const valueType = describeType(meta.lookup, s.valueTypeId);
|
|
3822
|
+
const keyType = s.keyTypeId != null ? describeType(meta.lookup, s.keyTypeId) : undefined;
|
|
3823
|
+
return { name: s.name, type: s.type, valueType, keyType, docs: firstSentence(s.docs) };
|
|
3824
|
+
})
|
|
3825
|
+
}));
|
|
3308
3826
|
return;
|
|
3309
3827
|
}
|
|
3310
3828
|
printHeading(`${pallet.name} Storage`);
|
|
@@ -3331,6 +3849,21 @@ async function handleStorage2(target, opts) {
|
|
|
3331
3849
|
const names = pallet.storage.map((s) => s.name);
|
|
3332
3850
|
throw new Error(suggestMessage(`storage item in ${pallet.name}`, itemName, names));
|
|
3333
3851
|
}
|
|
3852
|
+
if (isJsonOutput(opts)) {
|
|
3853
|
+
const valueType = describeType(meta.lookup, storageItem.valueTypeId);
|
|
3854
|
+
const keyType = storageItem.keyTypeId != null ? describeType(meta.lookup, storageItem.keyTypeId) : undefined;
|
|
3855
|
+
console.log(formatJson({
|
|
3856
|
+
chain: chainName,
|
|
3857
|
+
pallet: pallet.name,
|
|
3858
|
+
item: storageItem.name,
|
|
3859
|
+
category: "storage",
|
|
3860
|
+
type: storageItem.type,
|
|
3861
|
+
valueType,
|
|
3862
|
+
keyType,
|
|
3863
|
+
docs: storageItem.docs
|
|
3864
|
+
}));
|
|
3865
|
+
return;
|
|
3866
|
+
}
|
|
3334
3867
|
printHeading(`${pallet.name}.${storageItem.name} (Storage)`);
|
|
3335
3868
|
console.log(` ${BOLD}Type:${RESET} ${storageItem.type}`);
|
|
3336
3869
|
console.log(` ${BOLD}Value:${RESET} ${describeType(meta.lookup, storageItem.valueTypeId)}`);
|
|
@@ -3574,8 +4107,7 @@ function registerHashCommand(cli) {
|
|
|
3574
4107
|
const input = await resolveInput(data, opts);
|
|
3575
4108
|
const hash = computeHash(algorithm, input);
|
|
3576
4109
|
const hexHash = toHex2(hash);
|
|
3577
|
-
|
|
3578
|
-
if (format === "json") {
|
|
4110
|
+
if (isJsonOutput(opts)) {
|
|
3579
4111
|
printResult({
|
|
3580
4112
|
algorithm,
|
|
3581
4113
|
input: data ?? (opts.file ? `file:${opts.file}` : "stdin"),
|
|
@@ -3661,7 +4193,8 @@ function registerInspectCommand(cli) {
|
|
|
3661
4193
|
try {
|
|
3662
4194
|
meta = await getOrFetchMetadata(chainName);
|
|
3663
4195
|
} catch {
|
|
3664
|
-
|
|
4196
|
+
process.stderr.write(`Fetching metadata from ${chainName}...
|
|
4197
|
+
`);
|
|
3665
4198
|
const clientHandle = await createChainClient(chainName, chainConfig, opts.rpc);
|
|
3666
4199
|
try {
|
|
3667
4200
|
meta = await getOrFetchMetadata(chainName, clientHandle);
|
|
@@ -3671,6 +4204,20 @@ function registerInspectCommand(cli) {
|
|
|
3671
4204
|
}
|
|
3672
4205
|
if (!target) {
|
|
3673
4206
|
const pallets = listPallets(meta);
|
|
4207
|
+
if (isJsonOutput(opts)) {
|
|
4208
|
+
console.log(formatJson({
|
|
4209
|
+
chain: chainName,
|
|
4210
|
+
pallets: pallets.map((p) => ({
|
|
4211
|
+
name: p.name,
|
|
4212
|
+
storage: p.storage.length,
|
|
4213
|
+
constants: p.constants.length,
|
|
4214
|
+
calls: p.calls.length,
|
|
4215
|
+
events: p.events.length,
|
|
4216
|
+
errors: p.errors.length
|
|
4217
|
+
}))
|
|
4218
|
+
}));
|
|
4219
|
+
return;
|
|
4220
|
+
}
|
|
3674
4221
|
printHeading(`Pallets on ${chainName} (${pallets.length})`);
|
|
3675
4222
|
for (const p of pallets) {
|
|
3676
4223
|
const counts = [];
|
|
@@ -3695,6 +4242,44 @@ function registerInspectCommand(cli) {
|
|
|
3695
4242
|
if (!pallet2) {
|
|
3696
4243
|
throw new Error(suggestMessage("pallet", palletName, palletNames2));
|
|
3697
4244
|
}
|
|
4245
|
+
if (isJsonOutput(opts)) {
|
|
4246
|
+
console.log(formatJson({
|
|
4247
|
+
chain: chainName,
|
|
4248
|
+
pallet: pallet2.name,
|
|
4249
|
+
docs: pallet2.docs,
|
|
4250
|
+
storage: pallet2.storage.map((s) => {
|
|
4251
|
+
const valueType = describeType(meta.lookup, s.valueTypeId);
|
|
4252
|
+
const keyType = s.keyTypeId != null ? describeType(meta.lookup, s.keyTypeId) : undefined;
|
|
4253
|
+
return {
|
|
4254
|
+
name: s.name,
|
|
4255
|
+
type: s.type,
|
|
4256
|
+
valueType,
|
|
4257
|
+
keyType,
|
|
4258
|
+
docs: firstSentence(s.docs)
|
|
4259
|
+
};
|
|
4260
|
+
}),
|
|
4261
|
+
constants: pallet2.constants.map((c) => ({
|
|
4262
|
+
name: c.name,
|
|
4263
|
+
type: describeType(meta.lookup, c.typeId),
|
|
4264
|
+
docs: firstSentence(c.docs)
|
|
4265
|
+
})),
|
|
4266
|
+
calls: pallet2.calls.map((c) => ({
|
|
4267
|
+
name: c.name,
|
|
4268
|
+
args: describeCallArgs(meta, pallet2.name, c.name),
|
|
4269
|
+
docs: firstSentence(c.docs)
|
|
4270
|
+
})),
|
|
4271
|
+
events: pallet2.events.map((e) => ({
|
|
4272
|
+
name: e.name,
|
|
4273
|
+
fields: describeEventFields(meta, pallet2.name, e.name),
|
|
4274
|
+
docs: firstSentence(e.docs)
|
|
4275
|
+
})),
|
|
4276
|
+
errors: pallet2.errors.map((e) => ({
|
|
4277
|
+
name: e.name,
|
|
4278
|
+
docs: firstSentence(e.docs)
|
|
4279
|
+
}))
|
|
4280
|
+
}));
|
|
4281
|
+
return;
|
|
4282
|
+
}
|
|
3698
4283
|
printHeading(`${pallet2.name} Pallet`);
|
|
3699
4284
|
if (pallet2.docs.length) {
|
|
3700
4285
|
printDocs(pallet2.docs);
|
|
@@ -3773,6 +4358,79 @@ function registerInspectCommand(cli) {
|
|
|
3773
4358
|
if (!pallet) {
|
|
3774
4359
|
throw new Error(suggestMessage("pallet", palletName, palletNames));
|
|
3775
4360
|
}
|
|
4361
|
+
if (isJsonOutput(opts)) {
|
|
4362
|
+
const si = pallet.storage.find((s) => s.name.toLowerCase() === itemName.toLowerCase());
|
|
4363
|
+
if (si) {
|
|
4364
|
+
const valueType = describeType(meta.lookup, si.valueTypeId);
|
|
4365
|
+
const keyType = si.keyTypeId != null ? describeType(meta.lookup, si.keyTypeId) : undefined;
|
|
4366
|
+
console.log(formatJson({
|
|
4367
|
+
chain: chainName,
|
|
4368
|
+
pallet: pallet.name,
|
|
4369
|
+
item: si.name,
|
|
4370
|
+
category: "storage",
|
|
4371
|
+
type: si.type,
|
|
4372
|
+
valueType,
|
|
4373
|
+
keyType,
|
|
4374
|
+
docs: si.docs
|
|
4375
|
+
}));
|
|
4376
|
+
return;
|
|
4377
|
+
}
|
|
4378
|
+
const ci = pallet.constants.find((c) => c.name.toLowerCase() === itemName.toLowerCase());
|
|
4379
|
+
if (ci) {
|
|
4380
|
+
console.log(formatJson({
|
|
4381
|
+
chain: chainName,
|
|
4382
|
+
pallet: pallet.name,
|
|
4383
|
+
item: ci.name,
|
|
4384
|
+
category: "constant",
|
|
4385
|
+
type: describeType(meta.lookup, ci.typeId),
|
|
4386
|
+
docs: ci.docs
|
|
4387
|
+
}));
|
|
4388
|
+
return;
|
|
4389
|
+
}
|
|
4390
|
+
const ca = pallet.calls.find((c) => c.name.toLowerCase() === itemName.toLowerCase());
|
|
4391
|
+
if (ca) {
|
|
4392
|
+
console.log(formatJson({
|
|
4393
|
+
chain: chainName,
|
|
4394
|
+
pallet: pallet.name,
|
|
4395
|
+
item: ca.name,
|
|
4396
|
+
category: "call",
|
|
4397
|
+
args: describeCallArgs(meta, pallet.name, ca.name),
|
|
4398
|
+
docs: ca.docs
|
|
4399
|
+
}));
|
|
4400
|
+
return;
|
|
4401
|
+
}
|
|
4402
|
+
const ev = pallet.events.find((e) => e.name.toLowerCase() === itemName.toLowerCase());
|
|
4403
|
+
if (ev) {
|
|
4404
|
+
console.log(formatJson({
|
|
4405
|
+
chain: chainName,
|
|
4406
|
+
pallet: pallet.name,
|
|
4407
|
+
item: ev.name,
|
|
4408
|
+
category: "event",
|
|
4409
|
+
fields: describeEventFields(meta, pallet.name, ev.name),
|
|
4410
|
+
docs: ev.docs
|
|
4411
|
+
}));
|
|
4412
|
+
return;
|
|
4413
|
+
}
|
|
4414
|
+
const er = pallet.errors.find((e) => e.name.toLowerCase() === itemName.toLowerCase());
|
|
4415
|
+
if (er) {
|
|
4416
|
+
console.log(formatJson({
|
|
4417
|
+
chain: chainName,
|
|
4418
|
+
pallet: pallet.name,
|
|
4419
|
+
item: er.name,
|
|
4420
|
+
category: "error",
|
|
4421
|
+
docs: er.docs
|
|
4422
|
+
}));
|
|
4423
|
+
return;
|
|
4424
|
+
}
|
|
4425
|
+
const allItems2 = [
|
|
4426
|
+
...pallet.storage.map((s) => s.name),
|
|
4427
|
+
...pallet.constants.map((c) => c.name),
|
|
4428
|
+
...pallet.calls.map((c) => c.name),
|
|
4429
|
+
...pallet.events.map((e) => e.name),
|
|
4430
|
+
...pallet.errors.map((e) => e.name)
|
|
4431
|
+
];
|
|
4432
|
+
throw new Error(suggestMessage(`item in ${pallet.name}`, itemName, allItems2));
|
|
4433
|
+
}
|
|
3776
4434
|
const storageItem = pallet.storage.find((s) => s.name.toLowerCase() === itemName.toLowerCase());
|
|
3777
4435
|
if (storageItem) {
|
|
3778
4436
|
printHeading(`${pallet.name}.${storageItem.name} (Storage)`);
|
|
@@ -3906,8 +4564,7 @@ function registerParachainCommand(cli) {
|
|
|
3906
4564
|
throw new CliError(`Invalid prefix "${opts.prefix}". Must be a non-negative integer.`);
|
|
3907
4565
|
}
|
|
3908
4566
|
const types = opts.type ? [validateType(opts.type)] : SOVEREIGN_ACCOUNT_TYPES;
|
|
3909
|
-
|
|
3910
|
-
if (format === "json") {
|
|
4567
|
+
if (isJsonOutput(opts)) {
|
|
3911
4568
|
const result = { paraId, prefix };
|
|
3912
4569
|
for (const type of types) {
|
|
3913
4570
|
const accountId = deriveSovereignAccount(paraId, type);
|
|
@@ -3948,6 +4605,13 @@ async function handleQuery(target, keys, opts) {
|
|
|
3948
4605
|
const meta = await loadMeta(chainName2, chainConfig2, opts.rpc);
|
|
3949
4606
|
const pallets = listPallets(meta);
|
|
3950
4607
|
const withStorage = pallets.filter((p) => p.storage.length > 0);
|
|
4608
|
+
if (isJsonOutput(opts)) {
|
|
4609
|
+
console.log(formatJson({
|
|
4610
|
+
chain: chainName2,
|
|
4611
|
+
pallets: withStorage.map((p) => ({ name: p.name, storage: p.storage.length }))
|
|
4612
|
+
}));
|
|
4613
|
+
return;
|
|
4614
|
+
}
|
|
3951
4615
|
printHeading(`Pallets with storage on ${chainName2} (${withStorage.length})`);
|
|
3952
4616
|
for (const p of withStorage) {
|
|
3953
4617
|
printItem(p.name, `${p.storage.length} storage items`);
|
|
@@ -3962,7 +4626,23 @@ async function handleQuery(target, keys, opts) {
|
|
|
3962
4626
|
const meta = await loadMeta(chainName2, chainConfig2, opts.rpc);
|
|
3963
4627
|
const pallet2 = resolvePallet(meta, palletName(target));
|
|
3964
4628
|
if (pallet2.storage.length === 0) {
|
|
3965
|
-
|
|
4629
|
+
if (isJsonOutput(opts)) {
|
|
4630
|
+
console.log(formatJson({ chain: chainName2, pallet: pallet2.name, storage: [] }));
|
|
4631
|
+
} else {
|
|
4632
|
+
console.log(`No storage items in ${pallet2.name}.`);
|
|
4633
|
+
}
|
|
4634
|
+
return;
|
|
4635
|
+
}
|
|
4636
|
+
if (isJsonOutput(opts)) {
|
|
4637
|
+
console.log(formatJson({
|
|
4638
|
+
chain: chainName2,
|
|
4639
|
+
pallet: pallet2.name,
|
|
4640
|
+
storage: pallet2.storage.map((s) => {
|
|
4641
|
+
const valueType = describeType(meta.lookup, s.valueTypeId);
|
|
4642
|
+
const keyType = s.keyTypeId != null ? describeType(meta.lookup, s.keyTypeId) : undefined;
|
|
4643
|
+
return { name: s.name, type: s.type, valueType, keyType, docs: firstSentence(s.docs) };
|
|
4644
|
+
})
|
|
4645
|
+
}));
|
|
3966
4646
|
return;
|
|
3967
4647
|
}
|
|
3968
4648
|
printHeading(`${pallet2.name} Storage`);
|
|
@@ -4007,7 +4687,7 @@ async function handleQuery(target, keys, opts) {
|
|
|
4007
4687
|
typeof opts.parsedArgs === "object" ? JSON.stringify(opts.parsedArgs) : String(opts.parsedArgs)
|
|
4008
4688
|
];
|
|
4009
4689
|
const parsedKeys = await parseStorageKeys(meta, palletInfo.name, storageItem, effectiveKeys);
|
|
4010
|
-
const format = opts.output ?? "pretty";
|
|
4690
|
+
const format = isJsonOutput(opts) ? "json" : opts.output ?? "pretty";
|
|
4011
4691
|
const expectedLen = storageItem.type === "map" && storageItem.keyTypeId != null ? meta.builder.buildStorage(palletInfo.name, storageItem.name).len : 0;
|
|
4012
4692
|
if (storageItem.type === "map" && parsedKeys.length < expectedLen) {
|
|
4013
4693
|
if (parsedKeys.length === 0 && !opts.dump) {
|
|
@@ -4152,8 +4832,7 @@ function registerSignCommand(cli) {
|
|
|
4152
4832
|
signature: hexSignature,
|
|
4153
4833
|
enum: enumValue
|
|
4154
4834
|
};
|
|
4155
|
-
|
|
4156
|
-
if (format === "json") {
|
|
4835
|
+
if (isJsonOutput(opts)) {
|
|
4157
4836
|
printResult(result, "json");
|
|
4158
4837
|
} else {
|
|
4159
4838
|
console.log(` ${BOLD}Type:${RESET} ${result.type}`);
|
|
@@ -4172,6 +4851,7 @@ init_client();
|
|
|
4172
4851
|
init_metadata();
|
|
4173
4852
|
init_output();
|
|
4174
4853
|
init_resolve_address();
|
|
4854
|
+
init_binary_display();
|
|
4175
4855
|
init_errors();
|
|
4176
4856
|
init_focused_inspect();
|
|
4177
4857
|
import { getViewBuilder as getViewBuilder2 } from "@polkadot-api/view-builder";
|
|
@@ -4229,11 +4909,14 @@ function parseMortalityOption(raw) {
|
|
|
4229
4909
|
function parseAtOption(raw) {
|
|
4230
4910
|
if (raw === undefined)
|
|
4231
4911
|
return;
|
|
4232
|
-
if (raw === "
|
|
4233
|
-
return
|
|
4912
|
+
if (raw === "finalized")
|
|
4913
|
+
return;
|
|
4914
|
+
if (raw === "best") {
|
|
4915
|
+
throw new CliError('"best" is no longer supported for --at in papi v2. Omit --at for finalized, or pass a specific block hash.');
|
|
4916
|
+
}
|
|
4234
4917
|
if (/^0x[0-9a-fA-F]{64}$/.test(raw))
|
|
4235
4918
|
return raw;
|
|
4236
|
-
throw new CliError(`Invalid --at value "${raw}". Use
|
|
4919
|
+
throw new CliError(`Invalid --at value "${raw}". Use a 0x-prefixed 32-byte block hash, or omit for finalized.`);
|
|
4237
4920
|
}
|
|
4238
4921
|
async function handleTx(target, args, opts) {
|
|
4239
4922
|
if (!target) {
|
|
@@ -4242,6 +4925,13 @@ async function handleTx(target, args, opts) {
|
|
|
4242
4925
|
const meta = await loadMeta(chainName2, chainConfig2, opts.rpc);
|
|
4243
4926
|
const pallets = listPallets(meta);
|
|
4244
4927
|
const withCalls = pallets.filter((p) => p.calls.length > 0);
|
|
4928
|
+
if (isJsonOutput(opts)) {
|
|
4929
|
+
console.log(formatJson({
|
|
4930
|
+
chain: chainName2,
|
|
4931
|
+
pallets: withCalls.map((p) => ({ name: p.name, calls: p.calls.length }))
|
|
4932
|
+
}));
|
|
4933
|
+
return;
|
|
4934
|
+
}
|
|
4245
4935
|
printHeading(`Pallets with calls on ${chainName2} (${withCalls.length})`);
|
|
4246
4936
|
for (const p of withCalls) {
|
|
4247
4937
|
printItem(p.name, `${p.calls.length} calls`);
|
|
@@ -4256,7 +4946,23 @@ async function handleTx(target, args, opts) {
|
|
|
4256
4946
|
const meta = await loadMeta(chainName2, chainConfig2, opts.rpc);
|
|
4257
4947
|
const pallet2 = resolvePallet(meta, target);
|
|
4258
4948
|
if (pallet2.calls.length === 0) {
|
|
4259
|
-
|
|
4949
|
+
if (isJsonOutput(opts)) {
|
|
4950
|
+
console.log(formatJson({ chain: chainName2, pallet: pallet2.name, calls: [] }));
|
|
4951
|
+
} else {
|
|
4952
|
+
console.log(`No calls in ${pallet2.name}.`);
|
|
4953
|
+
}
|
|
4954
|
+
return;
|
|
4955
|
+
}
|
|
4956
|
+
if (isJsonOutput(opts)) {
|
|
4957
|
+
console.log(formatJson({
|
|
4958
|
+
chain: chainName2,
|
|
4959
|
+
pallet: pallet2.name,
|
|
4960
|
+
calls: pallet2.calls.map((c) => ({
|
|
4961
|
+
name: c.name,
|
|
4962
|
+
args: describeCallArgs(meta, pallet2.name, c.name),
|
|
4963
|
+
docs: firstSentence(c.docs)
|
|
4964
|
+
}))
|
|
4965
|
+
}));
|
|
4260
4966
|
return;
|
|
4261
4967
|
}
|
|
4262
4968
|
printHeading(`${pallet2.name} Calls`);
|
|
@@ -4271,7 +4977,7 @@ async function handleTx(target, args, opts) {
|
|
|
4271
4977
|
console.log();
|
|
4272
4978
|
return;
|
|
4273
4979
|
}
|
|
4274
|
-
if (!opts.from && !opts.encode && !opts.
|
|
4980
|
+
if (!opts.from && !opts.encode && !opts.toYaml && !opts.toJson) {
|
|
4275
4981
|
if (isRawCall) {
|
|
4276
4982
|
throw new Error("--from is required (or use --encode to output hex without signing)");
|
|
4277
4983
|
}
|
|
@@ -4284,14 +4990,14 @@ async function handleTx(target, args, opts) {
|
|
|
4284
4990
|
if (opts.encode && isRawCall) {
|
|
4285
4991
|
throw new Error("--encode cannot be used with raw call hex (already encoded)");
|
|
4286
4992
|
}
|
|
4287
|
-
if ((opts.
|
|
4288
|
-
throw new Error("--yaml/--json and --encode are mutually exclusive");
|
|
4993
|
+
if ((opts.toYaml || opts.toJson) && opts.encode) {
|
|
4994
|
+
throw new Error("--to-yaml/--to-json and --encode are mutually exclusive");
|
|
4289
4995
|
}
|
|
4290
|
-
if ((opts.
|
|
4291
|
-
throw new Error("--yaml/--json and --dry-run are mutually exclusive");
|
|
4996
|
+
if ((opts.toYaml || opts.toJson) && opts.dryRun) {
|
|
4997
|
+
throw new Error("--to-yaml/--to-json and --dry-run are mutually exclusive");
|
|
4292
4998
|
}
|
|
4293
|
-
if (opts.
|
|
4294
|
-
throw new Error("--yaml and --json are mutually exclusive");
|
|
4999
|
+
if (opts.toYaml && opts.toJson) {
|
|
5000
|
+
throw new Error("--to-yaml and --to-json are mutually exclusive");
|
|
4295
5001
|
}
|
|
4296
5002
|
const config = await loadConfig();
|
|
4297
5003
|
const effectiveChain = opts.chain;
|
|
@@ -4303,7 +5009,7 @@ async function handleTx(target, args, opts) {
|
|
|
4303
5009
|
callName = target.slice(dotIdx + 1);
|
|
4304
5010
|
}
|
|
4305
5011
|
const { name: chainName, chain: chainConfig } = resolveChain(config, effectiveChain);
|
|
4306
|
-
const decodeOnly = opts.encode || opts.
|
|
5012
|
+
const decodeOnly = opts.encode || opts.toYaml || opts.toJson;
|
|
4307
5013
|
const signer = decodeOnly ? undefined : await resolveAccountSigner(opts.from);
|
|
4308
5014
|
let clientHandle;
|
|
4309
5015
|
if (!decodeOnly) {
|
|
@@ -4352,9 +5058,9 @@ async function handleTx(target, args, opts) {
|
|
|
4352
5058
|
` + "Usage: dot tx 0x<call_hex> --from <account>");
|
|
4353
5059
|
}
|
|
4354
5060
|
callHex = target;
|
|
4355
|
-
if (opts.
|
|
5061
|
+
if (opts.toYaml || opts.toJson) {
|
|
4356
5062
|
const fileObj = decodeCallToFileFormat(meta, callHex, chainName);
|
|
4357
|
-
outputFileFormat(fileObj, !!opts.
|
|
5063
|
+
outputFileFormat(fileObj, !!opts.toYaml);
|
|
4358
5064
|
return;
|
|
4359
5065
|
}
|
|
4360
5066
|
const callBinary = Binary3.fromHex(target);
|
|
@@ -4372,26 +5078,55 @@ async function handleTx(target, args, opts) {
|
|
|
4372
5078
|
}
|
|
4373
5079
|
const effectiveArgs = opts.parsedArgs !== undefined ? fileArgsToStrings(opts.parsedArgs) : args;
|
|
4374
5080
|
const callData = await parseCallArgs(meta, palletInfo.name, callInfo.name, effectiveArgs);
|
|
4375
|
-
if (opts.encode || opts.
|
|
5081
|
+
if (opts.encode || opts.toYaml || opts.toJson) {
|
|
4376
5082
|
const { codec, location } = meta.builder.buildCall(palletInfo.name, callInfo.name);
|
|
4377
5083
|
const encodedArgs = codec.enc(callData);
|
|
4378
5084
|
const fullCall = new Uint8Array([location[0], location[1], ...encodedArgs]);
|
|
4379
|
-
const hex = Binary3.
|
|
5085
|
+
const hex = Binary3.toHex(fullCall);
|
|
4380
5086
|
if (opts.encode) {
|
|
4381
|
-
|
|
5087
|
+
if (isJsonOutput(opts)) {
|
|
5088
|
+
console.log(formatJson({ callHex: hex }));
|
|
5089
|
+
} else {
|
|
5090
|
+
console.log(hex);
|
|
5091
|
+
}
|
|
4382
5092
|
return;
|
|
4383
5093
|
}
|
|
4384
5094
|
const fileObj = decodeCallToFileFormat(meta, hex, chainName);
|
|
4385
|
-
outputFileFormat(fileObj, !!opts.
|
|
5095
|
+
outputFileFormat(fileObj, !!opts.toYaml);
|
|
4386
5096
|
return;
|
|
4387
5097
|
}
|
|
4388
5098
|
tx = unsafeApi.tx[palletInfo.name][callInfo.name](callData);
|
|
4389
5099
|
const encodedCall = await tx.getEncodedData();
|
|
4390
|
-
callHex =
|
|
5100
|
+
callHex = Binary3.toHex(encodedCall);
|
|
4391
5101
|
}
|
|
4392
5102
|
const decodedStr = decodeCall(meta, callHex);
|
|
4393
5103
|
if (opts.dryRun) {
|
|
4394
5104
|
const signerAddress = toSs58(signer.publicKey);
|
|
5105
|
+
let estimatedFees;
|
|
5106
|
+
try {
|
|
5107
|
+
estimatedFees = String(await tx.getEstimatedFees(signer?.publicKey, txOptions));
|
|
5108
|
+
} catch {
|
|
5109
|
+
estimatedFees = undefined;
|
|
5110
|
+
}
|
|
5111
|
+
if (isJsonOutput(opts)) {
|
|
5112
|
+
const result2 = {
|
|
5113
|
+
chain: chainName,
|
|
5114
|
+
from: { name: opts.from, address: signerAddress },
|
|
5115
|
+
callHex,
|
|
5116
|
+
decoded: decodedStr,
|
|
5117
|
+
estimatedFees
|
|
5118
|
+
};
|
|
5119
|
+
if (nonce !== undefined)
|
|
5120
|
+
result2.nonce = nonce;
|
|
5121
|
+
if (tip !== undefined)
|
|
5122
|
+
result2.tip = String(tip);
|
|
5123
|
+
if (mortality !== undefined)
|
|
5124
|
+
result2.mortality = mortality.mortal ? `mortal (period ${mortality.period})` : "immortal";
|
|
5125
|
+
if (at !== undefined)
|
|
5126
|
+
result2.at = at;
|
|
5127
|
+
console.log(formatJson(result2));
|
|
5128
|
+
return;
|
|
5129
|
+
}
|
|
4395
5130
|
console.log(` ${BOLD}Chain:${RESET} ${chainName}`);
|
|
4396
5131
|
console.log(` ${BOLD}From:${RESET} ${opts.from} (${signerAddress})`);
|
|
4397
5132
|
console.log(` ${BOLD}Call:${RESET} ${callHex}`);
|
|
@@ -4404,16 +5139,46 @@ async function handleTx(target, args, opts) {
|
|
|
4404
5139
|
console.log(` ${BOLD}Mortality:${RESET} ${mortality.mortal ? `mortal (period ${mortality.period})` : "immortal"}`);
|
|
4405
5140
|
if (at !== undefined)
|
|
4406
5141
|
console.log(` ${BOLD}At:${RESET} ${at}`);
|
|
4407
|
-
|
|
4408
|
-
|
|
4409
|
-
|
|
4410
|
-
} catch (err) {
|
|
5142
|
+
if (estimatedFees !== undefined) {
|
|
5143
|
+
console.log(` ${BOLD}Estimated fees:${RESET} ${estimatedFees}`);
|
|
5144
|
+
} else {
|
|
4411
5145
|
console.log(` ${BOLD}Estimated fees:${RESET} ${YELLOW}unable to estimate${RESET}`);
|
|
4412
|
-
console.log(` ${DIM}${err.message ?? err}${RESET}`);
|
|
4413
5146
|
}
|
|
4414
5147
|
return;
|
|
4415
5148
|
}
|
|
4416
5149
|
const waitLevel = parseWaitLevel(opts.wait);
|
|
5150
|
+
if (isJsonOutput(opts)) {
|
|
5151
|
+
const result2 = await watchTransactionJson(tx.signSubmitAndWatch(signer, txOptions), waitLevel);
|
|
5152
|
+
const rpcUrl2 = primaryRpc(opts.rpc ?? chainConfig.rpc);
|
|
5153
|
+
if (result2.type === "broadcasted") {
|
|
5154
|
+
printJsonLine({ event: "broadcasted", txHash: result2.txHash });
|
|
5155
|
+
return;
|
|
5156
|
+
}
|
|
5157
|
+
const blockHash = result2.block.hash;
|
|
5158
|
+
const explorer = {};
|
|
5159
|
+
if (rpcUrl2) {
|
|
5160
|
+
explorer.polkadotjs = pjsAppsLink(rpcUrl2, blockHash);
|
|
5161
|
+
explorer.papi = papiLink(rpcUrl2, blockHash);
|
|
5162
|
+
}
|
|
5163
|
+
printJsonLine({
|
|
5164
|
+
event: result2.type === "finalized" ? "finalized" : "bestBlock",
|
|
5165
|
+
blockNumber: result2.block.number,
|
|
5166
|
+
blockHash,
|
|
5167
|
+
txHash: result2.txHash,
|
|
5168
|
+
ok: result2.ok,
|
|
5169
|
+
events: result2.events?.map((e) => ({
|
|
5170
|
+
pallet: e.type,
|
|
5171
|
+
name: e.value?.type,
|
|
5172
|
+
fields: e.value?.value
|
|
5173
|
+
})),
|
|
5174
|
+
dispatchError: result2.ok ? null : formatDispatchError(result2.dispatchError),
|
|
5175
|
+
explorer
|
|
5176
|
+
});
|
|
5177
|
+
if (!result2.ok) {
|
|
5178
|
+
throw new CliError(`Transaction dispatch error: ${formatDispatchError(result2.dispatchError)}`);
|
|
5179
|
+
}
|
|
5180
|
+
return;
|
|
5181
|
+
}
|
|
4417
5182
|
const result = await watchTransaction(tx.signSubmitAndWatch(signer, txOptions), waitLevel);
|
|
4418
5183
|
console.log();
|
|
4419
5184
|
console.log(` ${BOLD}Chain:${RESET} ${chainName}`);
|
|
@@ -4508,7 +5273,7 @@ function decodeCallFallback(meta, callHex) {
|
|
|
4508
5273
|
if (callTypeId == null)
|
|
4509
5274
|
throw new Error("No RuntimeCall type ID");
|
|
4510
5275
|
const codec = meta.builder.buildDefinition(callTypeId);
|
|
4511
|
-
const decoded = codec.dec(Binary3.fromHex(callHex)
|
|
5276
|
+
const decoded = codec.dec(Binary3.fromHex(callHex));
|
|
4512
5277
|
const palletName2 = decoded.type;
|
|
4513
5278
|
const call = decoded.value;
|
|
4514
5279
|
const callName = call.type;
|
|
@@ -4524,7 +5289,7 @@ function decodeCallToFileFormat(meta, callHex, chainName) {
|
|
|
4524
5289
|
if (callTypeId == null)
|
|
4525
5290
|
throw new Error("No RuntimeCall type ID in metadata");
|
|
4526
5291
|
const codec = meta.builder.buildDefinition(callTypeId);
|
|
4527
|
-
const decoded = codec.dec(Binary3.fromHex(callHex)
|
|
5292
|
+
const decoded = codec.dec(Binary3.fromHex(callHex));
|
|
4528
5293
|
const palletName2 = decoded.type;
|
|
4529
5294
|
const call = decoded.value;
|
|
4530
5295
|
const callName = call.type;
|
|
@@ -4541,8 +5306,8 @@ function decodeCallToFileFormat(meta, callHex, chainName) {
|
|
|
4541
5306
|
function sanitizeForSerialization(value) {
|
|
4542
5307
|
if (value === undefined || value === null)
|
|
4543
5308
|
return null;
|
|
4544
|
-
if (value instanceof
|
|
4545
|
-
return
|
|
5309
|
+
if (value instanceof Uint8Array)
|
|
5310
|
+
return Binary3.toHex(value);
|
|
4546
5311
|
if (typeof value === "bigint") {
|
|
4547
5312
|
if (value >= Number.MIN_SAFE_INTEGER && value <= Number.MAX_SAFE_INTEGER) {
|
|
4548
5313
|
return Number(value);
|
|
@@ -4574,8 +5339,8 @@ function outputFileFormat(obj, asYaml) {
|
|
|
4574
5339
|
function formatRawDecoded(value) {
|
|
4575
5340
|
if (value === undefined || value === null)
|
|
4576
5341
|
return "null";
|
|
4577
|
-
if (value instanceof
|
|
4578
|
-
return
|
|
5342
|
+
if (value instanceof Uint8Array)
|
|
5343
|
+
return Binary3.toHex(value);
|
|
4579
5344
|
if (typeof value === "bigint")
|
|
4580
5345
|
return value.toString();
|
|
4581
5346
|
if (typeof value === "string")
|
|
@@ -4696,7 +5461,7 @@ function formatEventValue(v) {
|
|
|
4696
5461
|
return v.toString();
|
|
4697
5462
|
if (v === null || v === undefined)
|
|
4698
5463
|
return "null";
|
|
4699
|
-
if (v instanceof
|
|
5464
|
+
if (v instanceof Uint8Array) {
|
|
4700
5465
|
return binaryToDisplay(v);
|
|
4701
5466
|
}
|
|
4702
5467
|
return JSON.stringify(v, (_k, val) => typeof val === "bigint" ? val.toString() : val);
|
|
@@ -4970,7 +5735,7 @@ async function parseTypedArg2(meta, entry, arg) {
|
|
|
4970
5735
|
case "enum": {
|
|
4971
5736
|
if (/^0x[0-9a-fA-F]+$/.test(arg) && meta.lookup.call != null && entry.id === meta.lookup.call) {
|
|
4972
5737
|
const callCodec = meta.builder.buildDefinition(meta.lookup.call);
|
|
4973
|
-
return callCodec.dec(Binary3.fromHex(arg)
|
|
5738
|
+
return callCodec.dec(Binary3.fromHex(arg));
|
|
4974
5739
|
}
|
|
4975
5740
|
if (arg.startsWith("{")) {
|
|
4976
5741
|
try {
|
|
@@ -5197,6 +5962,49 @@ function watchTransaction(observable, level) {
|
|
|
5197
5962
|
});
|
|
5198
5963
|
});
|
|
5199
5964
|
}
|
|
5965
|
+
function watchTransactionJson(observable, level) {
|
|
5966
|
+
return new Promise((resolve, reject) => {
|
|
5967
|
+
let settled = false;
|
|
5968
|
+
const subscription = observable.subscribe({
|
|
5969
|
+
next(event) {
|
|
5970
|
+
if (settled)
|
|
5971
|
+
return;
|
|
5972
|
+
switch (event.type) {
|
|
5973
|
+
case "signed":
|
|
5974
|
+
printJsonLine({ event: "signed", txHash: event.txHash });
|
|
5975
|
+
break;
|
|
5976
|
+
case "broadcasted":
|
|
5977
|
+
printJsonLine({ event: "broadcasted", txHash: event.txHash });
|
|
5978
|
+
if (level === "broadcast") {
|
|
5979
|
+
settled = true;
|
|
5980
|
+
subscription.unsubscribe();
|
|
5981
|
+
resolve(event);
|
|
5982
|
+
}
|
|
5983
|
+
break;
|
|
5984
|
+
case "txBestBlocksState":
|
|
5985
|
+
if (event.found) {
|
|
5986
|
+
printJsonLine({ event: "bestBlock", blockNumber: event.block.number, found: true });
|
|
5987
|
+
if (level === "best-block") {
|
|
5988
|
+
settled = true;
|
|
5989
|
+
subscription.unsubscribe();
|
|
5990
|
+
resolve(event);
|
|
5991
|
+
}
|
|
5992
|
+
}
|
|
5993
|
+
break;
|
|
5994
|
+
case "finalized":
|
|
5995
|
+
settled = true;
|
|
5996
|
+
resolve(event);
|
|
5997
|
+
break;
|
|
5998
|
+
}
|
|
5999
|
+
},
|
|
6000
|
+
error(err) {
|
|
6001
|
+
if (settled)
|
|
6002
|
+
return;
|
|
6003
|
+
reject(err);
|
|
6004
|
+
}
|
|
6005
|
+
});
|
|
6006
|
+
});
|
|
6007
|
+
}
|
|
5200
6008
|
|
|
5201
6009
|
// src/commands/verifiable.ts
|
|
5202
6010
|
init_accounts_store();
|
|
@@ -5253,7 +6061,7 @@ async function deriveVerifiable(account, opts) {
|
|
|
5253
6061
|
await saveAccounts(accountsFile);
|
|
5254
6062
|
}
|
|
5255
6063
|
}
|
|
5256
|
-
if (opts
|
|
6064
|
+
if (isJsonOutput(opts)) {
|
|
5257
6065
|
const result = {
|
|
5258
6066
|
account,
|
|
5259
6067
|
memberKey: memberKeyHex
|
|
@@ -5277,8 +6085,14 @@ async function resolveMnemonic(account) {
|
|
|
5277
6085
|
const accountsFile = await loadAccounts();
|
|
5278
6086
|
const stored = findAccount(accountsFile, account);
|
|
5279
6087
|
if (!stored) {
|
|
5280
|
-
const available = [...DEV_NAMES, ...accountsFile.accounts.map((a) => a.name)];
|
|
5281
|
-
|
|
6088
|
+
const available = [...DEV_NAMES, ...accountsFile.accounts.map((a) => a.name)].sort((a, b) => a.localeCompare(b));
|
|
6089
|
+
const suggestions = findClosest(account, available);
|
|
6090
|
+
const hint = suggestions.length > 0 ? `
|
|
6091
|
+
Did you mean: ${suggestions.join(", ")}?` : "";
|
|
6092
|
+
const list = available.map((a) => `
|
|
6093
|
+
- ${a}`).join("");
|
|
6094
|
+
throw new Error(`Unknown account "${account}".${hint}
|
|
6095
|
+
Available accounts:${list}`);
|
|
5282
6096
|
}
|
|
5283
6097
|
if (isWatchOnly(stored)) {
|
|
5284
6098
|
throw new Error(`Account "${account}" is watch-only (no secret). Cannot derive Bandersnatch key.`);
|
|
@@ -5313,10 +6127,16 @@ async function loadConfig2() {
|
|
|
5313
6127
|
await ensureDir3(DOT_DIR2);
|
|
5314
6128
|
if (await fileExists3(CONFIG_PATH2)) {
|
|
5315
6129
|
const saved = JSON.parse(await readFile5(CONFIG_PATH2, "utf-8"));
|
|
5316
|
-
|
|
5317
|
-
|
|
5318
|
-
chains
|
|
5319
|
-
}
|
|
6130
|
+
const chains = {};
|
|
6131
|
+
for (const [name, defaultConfig] of Object.entries(DEFAULT_CONFIG.chains)) {
|
|
6132
|
+
chains[name] = saved.chains[name] ? { ...defaultConfig, ...saved.chains[name] } : defaultConfig;
|
|
6133
|
+
}
|
|
6134
|
+
for (const [name, config] of Object.entries(saved.chains)) {
|
|
6135
|
+
if (!(name in DEFAULT_CONFIG.chains)) {
|
|
6136
|
+
chains[name] = config;
|
|
6137
|
+
}
|
|
6138
|
+
}
|
|
6139
|
+
return { ...saved, chains };
|
|
5320
6140
|
}
|
|
5321
6141
|
await saveConfig2(DEFAULT_CONFIG);
|
|
5322
6142
|
return DEFAULT_CONFIG;
|
|
@@ -5707,8 +6527,9 @@ if (process.argv[2] === "__complete") {
|
|
|
5707
6527
|
console.log(" dot apis.Core.version Call a runtime API");
|
|
5708
6528
|
console.log(" dot polkadot.query.System.Number With chain prefix");
|
|
5709
6529
|
console.log(" dot ./transfer.yaml --from alice Run from file");
|
|
5710
|
-
console.log(" dot tx.0x1f0003... --yaml
|
|
5711
|
-
console.log(" dot tx.System.remark 0xdead --json
|
|
6530
|
+
console.log(" dot tx.0x1f0003... --to-yaml Decode hex call to YAML");
|
|
6531
|
+
console.log(" dot tx.System.remark 0xdead --to-json Encode & output as JSON file format");
|
|
6532
|
+
console.log(" dot query.System.Number --json Output as JSON");
|
|
5712
6533
|
console.log();
|
|
5713
6534
|
console.log("Commands:");
|
|
5714
6535
|
console.log(" inspect [target] Inspect chain metadata (alias: explore)");
|
|
@@ -5723,7 +6544,7 @@ if (process.argv[2] === "__complete") {
|
|
|
5723
6544
|
console.log("Global options:");
|
|
5724
6545
|
console.log(" --chain <name> Target chain (default from config)");
|
|
5725
6546
|
console.log(" --rpc <url> Override RPC endpoint");
|
|
5726
|
-
console.log(" --
|
|
6547
|
+
console.log(" --json Output as JSON");
|
|
5727
6548
|
console.log(" --output <format> Output format: pretty or json");
|
|
5728
6549
|
console.log(" --help, -h Display this message");
|
|
5729
6550
|
console.log(" --version Show version");
|
|
@@ -5732,10 +6553,10 @@ if (process.argv[2] === "__complete") {
|
|
|
5732
6553
|
const cli = cac("dot");
|
|
5733
6554
|
cli.option("--chain <name>", "Target chain (default from config)");
|
|
5734
6555
|
cli.option("--rpc <url>", "Override RPC endpoint for this call");
|
|
5735
|
-
cli.option("--light-client", "Use Smoldot light client instead of WebSocket");
|
|
5736
6556
|
cli.option("--output <format>", "Output format: pretty or json", {
|
|
5737
6557
|
default: "pretty"
|
|
5738
6558
|
});
|
|
6559
|
+
cli.option("--json", "Output as JSON (shorthand for --output json)");
|
|
5739
6560
|
registerChainCommands(cli);
|
|
5740
6561
|
registerInspectCommand(cli);
|
|
5741
6562
|
registerAccountCommands(cli);
|
|
@@ -5744,7 +6565,7 @@ if (process.argv[2] === "__complete") {
|
|
|
5744
6565
|
registerParachainCommand(cli);
|
|
5745
6566
|
registerCompletionsCommand(cli);
|
|
5746
6567
|
registerVerifiableCommands(cli);
|
|
5747
|
-
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("--yaml", "Decode call to YAML file format (for tx)").option("--json", "Decode call to JSON file format (for tx)").option("--ext <json>", "Custom signed extension values as JSON (for tx)").option("-w, --wait <level>", "Resolve at: broadcast, best-block (or best), finalized (for tx)", {
|
|
6568
|
+
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("--to-yaml", "Decode call to YAML file format (for tx)").option("--to-json", "Decode call to JSON file format (for tx)").option("--ext <json>", "Custom signed extension values as JSON (for tx)").option("-w, --wait <level>", "Resolve at: broadcast, best-block (or best), finalized (for tx)", {
|
|
5748
6569
|
default: "finalized"
|
|
5749
6570
|
}).option("--dump", "Dump all entries of a storage map (without specifying a key)").option("--var <kv>", "Template variable for file input (KEY=VALUE, repeatable)").option("--nonce <n>", "Custom nonce for manual tx sequencing (for tx)").option("--tip <amount>", "Tip to prioritize transaction (for tx)").option("--mortality <spec>", '"immortal" or period number (for tx)').option("--at <block>", 'Block hash, "best", or "finalized" to validate against (for tx)').action(async (dotpath, args, opts) => {
|
|
5750
6571
|
if (!dotpath) {
|
|
@@ -5755,7 +6576,12 @@ if (process.argv[2] === "__complete") {
|
|
|
5755
6576
|
const cliVars = collectVarFlags(process.argv);
|
|
5756
6577
|
const cmd = await loadCommandFile(dotpath, cliVars);
|
|
5757
6578
|
const effectiveChain2 = opts.chain ?? cmd.chain;
|
|
5758
|
-
const handlerOpts2 = {
|
|
6579
|
+
const handlerOpts2 = {
|
|
6580
|
+
chain: effectiveChain2,
|
|
6581
|
+
rpc: opts.rpc,
|
|
6582
|
+
output: opts.output,
|
|
6583
|
+
json: opts.json
|
|
6584
|
+
};
|
|
5759
6585
|
const target2 = `${cmd.pallet}.${cmd.item}`;
|
|
5760
6586
|
switch (cmd.category) {
|
|
5761
6587
|
case "tx":
|
|
@@ -5764,8 +6590,8 @@ if (process.argv[2] === "__complete") {
|
|
|
5764
6590
|
from: opts.from,
|
|
5765
6591
|
dryRun: opts.dryRun,
|
|
5766
6592
|
encode: opts.encode,
|
|
5767
|
-
|
|
5768
|
-
|
|
6593
|
+
toYaml: opts.toYaml,
|
|
6594
|
+
toJson: opts.toJson,
|
|
5769
6595
|
ext: opts.ext,
|
|
5770
6596
|
wait: opts.wait,
|
|
5771
6597
|
nonce: opts.nonce,
|
|
@@ -5812,7 +6638,12 @@ if (process.argv[2] === "__complete") {
|
|
|
5812
6638
|
throw new CliError2(`Chain specified both as prefix ("${parsed.chain}") and as --chain flag ("${opts.chain}"). Use one or the other.`);
|
|
5813
6639
|
}
|
|
5814
6640
|
const effectiveChain = parsed.chain ?? opts.chain;
|
|
5815
|
-
const handlerOpts = {
|
|
6641
|
+
const handlerOpts = {
|
|
6642
|
+
chain: effectiveChain,
|
|
6643
|
+
rpc: opts.rpc,
|
|
6644
|
+
output: opts.output,
|
|
6645
|
+
json: opts.json
|
|
6646
|
+
};
|
|
5816
6647
|
const target = parsed.pallet ? parsed.item ? `${parsed.pallet}.${parsed.item}` : parsed.pallet : undefined;
|
|
5817
6648
|
if (cli.options.help && parsed.pallet && parsed.item) {
|
|
5818
6649
|
await showItemHelp2(parsed.category, target, handlerOpts);
|
|
@@ -5828,8 +6659,8 @@ if (process.argv[2] === "__complete") {
|
|
|
5828
6659
|
from: opts.from,
|
|
5829
6660
|
dryRun: opts.dryRun,
|
|
5830
6661
|
encode: opts.encode,
|
|
5831
|
-
|
|
5832
|
-
|
|
6662
|
+
toYaml: opts.toYaml,
|
|
6663
|
+
toJson: opts.toJson,
|
|
5833
6664
|
ext: opts.ext,
|
|
5834
6665
|
wait: opts.wait,
|
|
5835
6666
|
nonce: opts.nonce,
|