polkadot-cli 1.17.0 → 1.19.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 +276 -40
- package/dist/cli.mjs +1472 -115
- package/package.json +3 -2
package/dist/cli.mjs
CHANGED
|
@@ -22,6 +22,12 @@ function isLikelyStaleMetadataError(err) {
|
|
|
22
22
|
return false;
|
|
23
23
|
return STALE_METADATA_PATTERNS.some((re) => re.test(msg));
|
|
24
24
|
}
|
|
25
|
+
function isBlockUnavailableError(err) {
|
|
26
|
+
const msg = err instanceof Error ? err.message : typeof err === "string" ? err : "";
|
|
27
|
+
if (!msg)
|
|
28
|
+
return false;
|
|
29
|
+
return BLOCK_UNAVAILABLE_PATTERNS.some((re) => re.test(msg));
|
|
30
|
+
}
|
|
25
31
|
function formatRuntimeError(err) {
|
|
26
32
|
const msg = err instanceof Error ? err.message : String(err);
|
|
27
33
|
if (/wasm trap|wasm `?unreachable`? instruction|Execution aborted due to trap/i.test(msg)) {
|
|
@@ -40,7 +46,7 @@ function formatRuntimeError(err) {
|
|
|
40
46
|
}
|
|
41
47
|
return msg;
|
|
42
48
|
}
|
|
43
|
-
var CliError, ConnectionError, MetadataError, STALE_METADATA_PATTERNS;
|
|
49
|
+
var CliError, ConnectionError, MetadataError, STALE_METADATA_PATTERNS, BLOCK_UNAVAILABLE_PATTERNS;
|
|
44
50
|
var init_errors = __esm(() => {
|
|
45
51
|
CliError = class CliError extends Error {
|
|
46
52
|
constructor(message) {
|
|
@@ -69,6 +75,11 @@ var init_errors = __esm(() => {
|
|
|
69
75
|
/Lookup failed/i,
|
|
70
76
|
/metadata.*mismatch/i
|
|
71
77
|
];
|
|
78
|
+
BLOCK_UNAVAILABLE_PATTERNS = [
|
|
79
|
+
/is not pinned/i,
|
|
80
|
+
/Invalid BlockHash/i,
|
|
81
|
+
/UnknownBlock.*Header was not found/i
|
|
82
|
+
];
|
|
72
83
|
});
|
|
73
84
|
|
|
74
85
|
// src/utils/runtime-fingerprint.ts
|
|
@@ -240,6 +251,9 @@ function getMetadataPath(chainName) {
|
|
|
240
251
|
function getMetadataFingerprintPath(chainName) {
|
|
241
252
|
return join(getChainDir(chainName), "metadata.fingerprint.json");
|
|
242
253
|
}
|
|
254
|
+
function getRpcMethodsPath(chainName) {
|
|
255
|
+
return join(getChainDir(chainName), "rpc-methods.json");
|
|
256
|
+
}
|
|
243
257
|
function getConfigPath() {
|
|
244
258
|
return join(getConfigDir(), "config.json");
|
|
245
259
|
}
|
|
@@ -305,6 +319,31 @@ async function loadMetadataFingerprint(chainName) {
|
|
|
305
319
|
return null;
|
|
306
320
|
}
|
|
307
321
|
}
|
|
322
|
+
async function loadRpcMethods(chainName) {
|
|
323
|
+
const path = getRpcMethodsPath(chainName);
|
|
324
|
+
if (!await fileExists(path))
|
|
325
|
+
return null;
|
|
326
|
+
try {
|
|
327
|
+
const parsed = JSON.parse(await readFile(path, "utf-8"));
|
|
328
|
+
if (parsed && Array.isArray(parsed.methods) && typeof parsed.version === "number" && typeof parsed.fetchedAt === "string") {
|
|
329
|
+
return parsed;
|
|
330
|
+
}
|
|
331
|
+
return null;
|
|
332
|
+
} catch {
|
|
333
|
+
return null;
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
async function saveRpcMethods(chainName, methods, version2) {
|
|
337
|
+
const dir = getChainDir(chainName);
|
|
338
|
+
await ensureDir(dir);
|
|
339
|
+
const cache = {
|
|
340
|
+
methods,
|
|
341
|
+
version: version2,
|
|
342
|
+
fetchedAt: new Date().toISOString()
|
|
343
|
+
};
|
|
344
|
+
await writeFile(getRpcMethodsPath(chainName), `${JSON.stringify(cache, null, 2)}
|
|
345
|
+
`);
|
|
346
|
+
}
|
|
308
347
|
async function removeChainData(chainName) {
|
|
309
348
|
const dir = getChainDir(chainName);
|
|
310
349
|
await rm(dir, { recursive: true, force: true });
|
|
@@ -375,6 +414,15 @@ function isEnvSecret(secret) {
|
|
|
375
414
|
function isWatchOnly(account) {
|
|
376
415
|
return account.secret === undefined;
|
|
377
416
|
}
|
|
417
|
+
function classifyAccount(account) {
|
|
418
|
+
if (account.source?.kind === "pallet")
|
|
419
|
+
return "pallet";
|
|
420
|
+
if (account.source?.kind === "parachain")
|
|
421
|
+
return "parachain";
|
|
422
|
+
if (account.secret !== undefined)
|
|
423
|
+
return "signer";
|
|
424
|
+
return "watch-only";
|
|
425
|
+
}
|
|
378
426
|
|
|
379
427
|
// src/utils/fuzzy-match.ts
|
|
380
428
|
function levenshtein(a, b) {
|
|
@@ -1216,7 +1264,7 @@ async function fetchMetadataFromChain(clientHandle, chainName) {
|
|
|
1216
1264
|
let bytes;
|
|
1217
1265
|
try {
|
|
1218
1266
|
const hex = await withTimeout(client._request("state_call", ["Metadata_metadata_at_version", v15Arg]), chainName);
|
|
1219
|
-
const raw =
|
|
1267
|
+
const raw = hexToBytes2(hex);
|
|
1220
1268
|
const decoded = optionalOpaqueBytes.dec(raw);
|
|
1221
1269
|
if (decoded !== undefined) {
|
|
1222
1270
|
bytes = new Uint8Array(decoded);
|
|
@@ -1225,7 +1273,7 @@ async function fetchMetadataFromChain(clientHandle, chainName) {
|
|
|
1225
1273
|
if (!bytes) {
|
|
1226
1274
|
try {
|
|
1227
1275
|
const hex = await withTimeout(client._request("state_getMetadata", []), chainName);
|
|
1228
|
-
bytes =
|
|
1276
|
+
bytes = hexToBytes2(hex);
|
|
1229
1277
|
} catch (err) {
|
|
1230
1278
|
if (err instanceof ConnectionError)
|
|
1231
1279
|
throw err;
|
|
@@ -1274,6 +1322,24 @@ async function withStalenessSuggestion(chainName, clientHandle, task) {
|
|
|
1274
1322
|
` + ` Run: dot chain update ${chainName}`);
|
|
1275
1323
|
}
|
|
1276
1324
|
}
|
|
1325
|
+
async function withBlockAvailabilityHint(atRaw, task) {
|
|
1326
|
+
try {
|
|
1327
|
+
return await task();
|
|
1328
|
+
} catch (err) {
|
|
1329
|
+
if (!isBlockUnavailableError(err))
|
|
1330
|
+
throw err;
|
|
1331
|
+
const original = err instanceof Error ? err.message : String(err);
|
|
1332
|
+
const isExplicitHash = atRaw && atRaw !== "best" && atRaw !== "finalized";
|
|
1333
|
+
const target = isExplicitHash ? atRaw : "the requested block";
|
|
1334
|
+
const exampleAt = isExplicitHash ? atRaw : "<hash>";
|
|
1335
|
+
throw new CliError(`${original}
|
|
1336
|
+
|
|
1337
|
+
` + `⚠ ${target} is not available on the current RPC endpoint.
|
|
1338
|
+
` + ` Public nodes serve only recent (pinned) blocks via chainHead_v1_*.
|
|
1339
|
+
` + ` For deep historical reads, point --rpc at an archive endpoint, e.g.:
|
|
1340
|
+
` + ` dot ... --at ${exampleAt} --rpc wss://<archive-endpoint>`);
|
|
1341
|
+
}
|
|
1342
|
+
}
|
|
1277
1343
|
async function getOrFetchMetadata(chainName, clientHandle) {
|
|
1278
1344
|
let raw = await loadMetadata(chainName);
|
|
1279
1345
|
if (!raw) {
|
|
@@ -1403,7 +1469,7 @@ function describeCallArgs(meta, palletName, callName) {
|
|
|
1403
1469
|
function describeEventFields(meta, palletName, eventName) {
|
|
1404
1470
|
return compactArgsString(getEventFields(meta, palletName, eventName));
|
|
1405
1471
|
}
|
|
1406
|
-
function
|
|
1472
|
+
function hexToBytes2(hex) {
|
|
1407
1473
|
const clean = hex.startsWith("0x") ? hex.slice(2) : hex;
|
|
1408
1474
|
const bytes = new Uint8Array(clean.length / 2);
|
|
1409
1475
|
for (let i = 0;i < clean.length; i += 2) {
|
|
@@ -1498,6 +1564,15 @@ import { compact as scaleCompact } from "@polkadot-api/substrate-bindings";
|
|
|
1498
1564
|
import { getViewBuilder } from "@polkadot-api/view-builder";
|
|
1499
1565
|
import { Binary as Binary2 } from "polkadot-api";
|
|
1500
1566
|
import { stringify as stringifyYaml } from "yaml";
|
|
1567
|
+
function parseAtForRead(raw) {
|
|
1568
|
+
if (raw === undefined)
|
|
1569
|
+
return;
|
|
1570
|
+
if (raw === "best" || raw === "finalized")
|
|
1571
|
+
return raw;
|
|
1572
|
+
if (/^0x[0-9a-fA-F]{64}$/.test(raw))
|
|
1573
|
+
return raw;
|
|
1574
|
+
throw new CliError(`Invalid --at value "${raw}". Use "best", "finalized", or a 0x-prefixed 32-byte block hash.`);
|
|
1575
|
+
}
|
|
1501
1576
|
async function parseStructArgs(meta, fields, args, callLabel) {
|
|
1502
1577
|
const fieldNames = Object.keys(fields);
|
|
1503
1578
|
if (args.length !== fieldNames.length) {
|
|
@@ -1906,8 +1981,10 @@ async function handleApis(target, args, opts) {
|
|
|
1906
1981
|
typeof opts.parsedArgs === "object" ? JSON.stringify(opts.parsedArgs) : String(opts.parsedArgs)
|
|
1907
1982
|
];
|
|
1908
1983
|
const parsedArgs = await parseRuntimeApiArgs(meta, method, effectiveArgs);
|
|
1984
|
+
const atArg = parseAtForRead(opts.at);
|
|
1985
|
+
const pullOpts = atArg !== undefined ? [{ at: atArg }] : [];
|
|
1909
1986
|
const unsafeApi = clientHandle.client.getUnsafeApi();
|
|
1910
|
-
const result = await unsafeApi.apis[api.name][method.name](...parsedArgs);
|
|
1987
|
+
const result = await withBlockAvailabilityHint(opts.at, () => unsafeApi.apis[api.name][method.name](...parsedArgs, ...pullOpts));
|
|
1911
1988
|
const format = isJsonOutput(opts) ? "json" : opts.output ?? "pretty";
|
|
1912
1989
|
printResult(result, format);
|
|
1913
1990
|
} finally {
|
|
@@ -2559,11 +2636,569 @@ var init_focused_inspect = __esm(() => {
|
|
|
2559
2636
|
init_pretty_type();
|
|
2560
2637
|
});
|
|
2561
2638
|
|
|
2639
|
+
// src/data/rpc-registry.ts
|
|
2640
|
+
function inferFamily(method) {
|
|
2641
|
+
const prefix = method.split("_")[0];
|
|
2642
|
+
switch (prefix) {
|
|
2643
|
+
case "system":
|
|
2644
|
+
case "chain":
|
|
2645
|
+
case "state":
|
|
2646
|
+
case "author":
|
|
2647
|
+
case "payment":
|
|
2648
|
+
case "babe":
|
|
2649
|
+
case "grandpa":
|
|
2650
|
+
case "beefy":
|
|
2651
|
+
case "mmr":
|
|
2652
|
+
case "offchain":
|
|
2653
|
+
case "dev":
|
|
2654
|
+
return prefix;
|
|
2655
|
+
case "rpc":
|
|
2656
|
+
return "spec";
|
|
2657
|
+
case "chainHead":
|
|
2658
|
+
return "chainHead";
|
|
2659
|
+
case "chainSpec":
|
|
2660
|
+
return "chainSpec";
|
|
2661
|
+
case "transaction":
|
|
2662
|
+
return "transaction";
|
|
2663
|
+
case "archive":
|
|
2664
|
+
return "archive";
|
|
2665
|
+
default:
|
|
2666
|
+
return "other";
|
|
2667
|
+
}
|
|
2668
|
+
}
|
|
2669
|
+
var RPC_REGISTRY;
|
|
2670
|
+
var init_rpc_registry = __esm(() => {
|
|
2671
|
+
RPC_REGISTRY = {
|
|
2672
|
+
system_health: {
|
|
2673
|
+
description: "Node sync state (peers, isSyncing, shouldHavePeers).",
|
|
2674
|
+
family: "system",
|
|
2675
|
+
args: []
|
|
2676
|
+
},
|
|
2677
|
+
system_syncState: {
|
|
2678
|
+
description: "Block-level sync progress (startingBlock, currentBlock, highestBlock).",
|
|
2679
|
+
family: "system",
|
|
2680
|
+
args: []
|
|
2681
|
+
},
|
|
2682
|
+
system_version: {
|
|
2683
|
+
description: "Node software version string.",
|
|
2684
|
+
family: "system",
|
|
2685
|
+
args: []
|
|
2686
|
+
},
|
|
2687
|
+
system_name: {
|
|
2688
|
+
description: "Node implementation name.",
|
|
2689
|
+
family: "system",
|
|
2690
|
+
args: []
|
|
2691
|
+
},
|
|
2692
|
+
system_chain: {
|
|
2693
|
+
description: "Chain name as reported by the node.",
|
|
2694
|
+
family: "system",
|
|
2695
|
+
args: []
|
|
2696
|
+
},
|
|
2697
|
+
system_chainType: {
|
|
2698
|
+
description: "Chain type (Live, Development, Local).",
|
|
2699
|
+
family: "system",
|
|
2700
|
+
args: []
|
|
2701
|
+
},
|
|
2702
|
+
system_properties: {
|
|
2703
|
+
description: "Chain properties (ss58Format, tokenDecimals, tokenSymbol).",
|
|
2704
|
+
family: "system",
|
|
2705
|
+
args: []
|
|
2706
|
+
},
|
|
2707
|
+
system_peers: {
|
|
2708
|
+
description: "Connected peer details (peerId, roles, bestHash, bestNumber).",
|
|
2709
|
+
family: "system",
|
|
2710
|
+
args: []
|
|
2711
|
+
},
|
|
2712
|
+
system_localPeerId: {
|
|
2713
|
+
description: "Base58 PeerId of this node.",
|
|
2714
|
+
family: "system",
|
|
2715
|
+
args: []
|
|
2716
|
+
},
|
|
2717
|
+
system_localListenAddresses: {
|
|
2718
|
+
description: "Multiaddrs this node listens on.",
|
|
2719
|
+
family: "system",
|
|
2720
|
+
args: []
|
|
2721
|
+
},
|
|
2722
|
+
system_nodeRoles: {
|
|
2723
|
+
description: "Role(s) of the node (Authority, Full, Light, …).",
|
|
2724
|
+
family: "system",
|
|
2725
|
+
args: []
|
|
2726
|
+
},
|
|
2727
|
+
system_addLogFilter: {
|
|
2728
|
+
description: "Add a tracing/log filter directive at runtime.",
|
|
2729
|
+
family: "system",
|
|
2730
|
+
args: [{ name: "directives", type: "string" }],
|
|
2731
|
+
dangerous: true
|
|
2732
|
+
},
|
|
2733
|
+
system_resetLogFilter: {
|
|
2734
|
+
description: "Reset log filter to the default set at startup.",
|
|
2735
|
+
family: "system",
|
|
2736
|
+
args: [],
|
|
2737
|
+
dangerous: true
|
|
2738
|
+
},
|
|
2739
|
+
system_accountNextIndex: {
|
|
2740
|
+
description: "Next nonce for an account, including pending mempool extrinsics.",
|
|
2741
|
+
family: "system",
|
|
2742
|
+
args: [{ name: "address", type: "AccountId" }]
|
|
2743
|
+
},
|
|
2744
|
+
system_dryRun: {
|
|
2745
|
+
description: "Dry-run an extrinsic, returning its ApplyExtrinsicResult.",
|
|
2746
|
+
family: "system",
|
|
2747
|
+
args: [
|
|
2748
|
+
{ name: "extrinsic", type: "hex" },
|
|
2749
|
+
{ name: "at", type: "H256", optional: true }
|
|
2750
|
+
]
|
|
2751
|
+
},
|
|
2752
|
+
chain_getBlock: {
|
|
2753
|
+
description: "Full block (header + extrinsics) by hash.",
|
|
2754
|
+
family: "chain",
|
|
2755
|
+
args: [{ name: "blockHash", type: "H256", optional: true, description: "latest if omitted" }]
|
|
2756
|
+
},
|
|
2757
|
+
chain_getBlockHash: {
|
|
2758
|
+
description: "Block hash by number, or latest if omitted.",
|
|
2759
|
+
family: "chain",
|
|
2760
|
+
args: [{ name: "blockNumber", type: "u32", optional: true }]
|
|
2761
|
+
},
|
|
2762
|
+
chain_getFinalizedHead: {
|
|
2763
|
+
description: "Hash of the latest finalized head.",
|
|
2764
|
+
family: "chain",
|
|
2765
|
+
args: []
|
|
2766
|
+
},
|
|
2767
|
+
chain_getHeader: {
|
|
2768
|
+
description: "Block header by hash, or latest if omitted.",
|
|
2769
|
+
family: "chain",
|
|
2770
|
+
args: [{ name: "blockHash", type: "H256", optional: true }]
|
|
2771
|
+
},
|
|
2772
|
+
chain_subscribeAllHeads: {
|
|
2773
|
+
description: "Subscribe to all imported headers.",
|
|
2774
|
+
family: "chain",
|
|
2775
|
+
args: [],
|
|
2776
|
+
subscription: true
|
|
2777
|
+
},
|
|
2778
|
+
chain_subscribeFinalizedHeads: {
|
|
2779
|
+
description: "Subscribe to finalized-head changes.",
|
|
2780
|
+
family: "chain",
|
|
2781
|
+
args: [],
|
|
2782
|
+
subscription: true
|
|
2783
|
+
},
|
|
2784
|
+
chain_subscribeNewHeads: {
|
|
2785
|
+
description: "Subscribe to best-block-head changes.",
|
|
2786
|
+
family: "chain",
|
|
2787
|
+
args: [],
|
|
2788
|
+
subscription: true
|
|
2789
|
+
},
|
|
2790
|
+
state_call: {
|
|
2791
|
+
description: "Invoke a runtime API method by name with raw SCALE-encoded arguments.",
|
|
2792
|
+
family: "state",
|
|
2793
|
+
args: [
|
|
2794
|
+
{ name: "method", type: "string", description: "e.g. Core_version" },
|
|
2795
|
+
{ name: "data", type: "hex", description: "SCALE-encoded args (0x for none)" },
|
|
2796
|
+
{ name: "at", type: "H256", optional: true }
|
|
2797
|
+
]
|
|
2798
|
+
},
|
|
2799
|
+
state_getMetadata: {
|
|
2800
|
+
description: "Raw SCALE-encoded runtime metadata at a block.",
|
|
2801
|
+
family: "state",
|
|
2802
|
+
args: [{ name: "at", type: "H256", optional: true }]
|
|
2803
|
+
},
|
|
2804
|
+
state_getRuntimeVersion: {
|
|
2805
|
+
description: "Runtime version at a block.",
|
|
2806
|
+
family: "state",
|
|
2807
|
+
args: [{ name: "at", type: "H256", optional: true }]
|
|
2808
|
+
},
|
|
2809
|
+
state_getStorage: {
|
|
2810
|
+
description: "Raw SCALE-encoded storage value at a key.",
|
|
2811
|
+
family: "state",
|
|
2812
|
+
args: [
|
|
2813
|
+
{ name: "key", type: "StorageKey" },
|
|
2814
|
+
{ name: "at", type: "H256", optional: true }
|
|
2815
|
+
]
|
|
2816
|
+
},
|
|
2817
|
+
state_getStorageHash: {
|
|
2818
|
+
description: "Blake2 hash of the value at a storage key.",
|
|
2819
|
+
family: "state",
|
|
2820
|
+
args: [
|
|
2821
|
+
{ name: "key", type: "StorageKey" },
|
|
2822
|
+
{ name: "at", type: "H256", optional: true }
|
|
2823
|
+
]
|
|
2824
|
+
},
|
|
2825
|
+
state_getStorageSize: {
|
|
2826
|
+
description: "Byte length of the value at a storage key.",
|
|
2827
|
+
family: "state",
|
|
2828
|
+
args: [
|
|
2829
|
+
{ name: "key", type: "StorageKey" },
|
|
2830
|
+
{ name: "at", type: "H256", optional: true }
|
|
2831
|
+
]
|
|
2832
|
+
},
|
|
2833
|
+
state_getKeysPaged: {
|
|
2834
|
+
description: "Paginated key iteration under a prefix.",
|
|
2835
|
+
family: "state",
|
|
2836
|
+
args: [
|
|
2837
|
+
{ name: "prefix", type: "StorageKey" },
|
|
2838
|
+
{ name: "count", type: "u32" },
|
|
2839
|
+
{ name: "startKey", type: "StorageKey", optional: true },
|
|
2840
|
+
{ name: "at", type: "H256", optional: true }
|
|
2841
|
+
]
|
|
2842
|
+
},
|
|
2843
|
+
state_queryStorageAt: {
|
|
2844
|
+
description: "Read multiple keys at a single block.",
|
|
2845
|
+
family: "state",
|
|
2846
|
+
args: [
|
|
2847
|
+
{ name: "keys", type: "StorageKey[]" },
|
|
2848
|
+
{ name: "at", type: "H256", optional: true }
|
|
2849
|
+
]
|
|
2850
|
+
},
|
|
2851
|
+
state_traceBlock: {
|
|
2852
|
+
description: "Per-block storage access trace (heavy: archival/debug nodes only).",
|
|
2853
|
+
family: "state",
|
|
2854
|
+
args: [
|
|
2855
|
+
{ name: "blockHash", type: "H256" },
|
|
2856
|
+
{ name: "targets", type: "string", optional: true },
|
|
2857
|
+
{ name: "storageKeys", type: "string", optional: true },
|
|
2858
|
+
{ name: "methods", type: "string", optional: true }
|
|
2859
|
+
]
|
|
2860
|
+
},
|
|
2861
|
+
state_subscribeRuntimeVersion: {
|
|
2862
|
+
description: "Subscribe to runtime upgrades.",
|
|
2863
|
+
family: "state",
|
|
2864
|
+
args: [],
|
|
2865
|
+
subscription: true
|
|
2866
|
+
},
|
|
2867
|
+
state_subscribeStorage: {
|
|
2868
|
+
description: "Subscribe to changes for a set of keys.",
|
|
2869
|
+
family: "state",
|
|
2870
|
+
args: [{ name: "keys", type: "StorageKey[]" }],
|
|
2871
|
+
subscription: true
|
|
2872
|
+
},
|
|
2873
|
+
author_pendingExtrinsics: {
|
|
2874
|
+
description: "Mempool snapshot — encoded extrinsics waiting to be included.",
|
|
2875
|
+
family: "author",
|
|
2876
|
+
args: []
|
|
2877
|
+
},
|
|
2878
|
+
author_submitExtrinsic: {
|
|
2879
|
+
description: "Submit a signed extrinsic to the mempool. Returns the tx hash.",
|
|
2880
|
+
family: "author",
|
|
2881
|
+
args: [{ name: "extrinsic", type: "hex" }],
|
|
2882
|
+
dangerous: true
|
|
2883
|
+
},
|
|
2884
|
+
author_removeExtrinsic: {
|
|
2885
|
+
description: "Remove specific extrinsics from the mempool by hash.",
|
|
2886
|
+
family: "author",
|
|
2887
|
+
args: [{ name: "bytesOrHash", type: "ExtrinsicOrHash[]" }],
|
|
2888
|
+
dangerous: true
|
|
2889
|
+
},
|
|
2890
|
+
author_hasKey: {
|
|
2891
|
+
description: "Whether the keystore has the public key for a given key type.",
|
|
2892
|
+
family: "author",
|
|
2893
|
+
args: [
|
|
2894
|
+
{ name: "publicKey", type: "hex" },
|
|
2895
|
+
{ name: "keyType", type: "string", description: "e.g. babe, gran, imon" }
|
|
2896
|
+
]
|
|
2897
|
+
},
|
|
2898
|
+
author_hasSessionKeys: {
|
|
2899
|
+
description: "Whether the keystore has all keys for a session-keys blob.",
|
|
2900
|
+
family: "author",
|
|
2901
|
+
args: [{ name: "sessionKeys", type: "hex" }]
|
|
2902
|
+
},
|
|
2903
|
+
author_rotateKeys: {
|
|
2904
|
+
description: "Generate a new set of session keys and return the public-keys blob.",
|
|
2905
|
+
family: "author",
|
|
2906
|
+
args: [],
|
|
2907
|
+
dangerous: true
|
|
2908
|
+
},
|
|
2909
|
+
author_insertKey: {
|
|
2910
|
+
description: "Insert a key into the node keystore.",
|
|
2911
|
+
family: "author",
|
|
2912
|
+
args: [
|
|
2913
|
+
{ name: "keyType", type: "string" },
|
|
2914
|
+
{ name: "suri", type: "string" },
|
|
2915
|
+
{ name: "publicKey", type: "hex" }
|
|
2916
|
+
],
|
|
2917
|
+
dangerous: true
|
|
2918
|
+
},
|
|
2919
|
+
author_submitAndWatchExtrinsic: {
|
|
2920
|
+
description: "Submit an extrinsic and subscribe to its status updates.",
|
|
2921
|
+
family: "author",
|
|
2922
|
+
args: [{ name: "extrinsic", type: "hex" }],
|
|
2923
|
+
dangerous: true,
|
|
2924
|
+
subscription: true
|
|
2925
|
+
},
|
|
2926
|
+
payment_queryInfo: {
|
|
2927
|
+
description: "Pre-submission fee estimate (weight, partialFee, class).",
|
|
2928
|
+
family: "payment",
|
|
2929
|
+
args: [
|
|
2930
|
+
{ name: "extrinsic", type: "hex" },
|
|
2931
|
+
{ name: "at", type: "H256", optional: true }
|
|
2932
|
+
]
|
|
2933
|
+
},
|
|
2934
|
+
payment_queryFeeDetails: {
|
|
2935
|
+
description: "Fee breakdown (baseFee, lenFee, adjustedWeightFee, tip).",
|
|
2936
|
+
family: "payment",
|
|
2937
|
+
args: [
|
|
2938
|
+
{ name: "extrinsic", type: "hex" },
|
|
2939
|
+
{ name: "at", type: "H256", optional: true }
|
|
2940
|
+
]
|
|
2941
|
+
},
|
|
2942
|
+
babe_epochAuthorship: {
|
|
2943
|
+
description: "Slots this node is allowed to author in the current epoch.",
|
|
2944
|
+
family: "babe",
|
|
2945
|
+
args: []
|
|
2946
|
+
},
|
|
2947
|
+
grandpa_proveFinality: {
|
|
2948
|
+
description: "Finality proof up to a block (for light clients).",
|
|
2949
|
+
family: "grandpa",
|
|
2950
|
+
args: [{ name: "blockNumber", type: "u32" }]
|
|
2951
|
+
},
|
|
2952
|
+
grandpa_roundState: {
|
|
2953
|
+
description: "GRANDPA round state (best round, total weight, voters).",
|
|
2954
|
+
family: "grandpa",
|
|
2955
|
+
args: []
|
|
2956
|
+
},
|
|
2957
|
+
grandpa_subscribeJustifications: {
|
|
2958
|
+
description: "Subscribe to GRANDPA justifications.",
|
|
2959
|
+
family: "grandpa",
|
|
2960
|
+
args: [],
|
|
2961
|
+
subscription: true
|
|
2962
|
+
},
|
|
2963
|
+
beefy_getFinalizedHead: {
|
|
2964
|
+
description: "Latest BEEFY-finalized block hash.",
|
|
2965
|
+
family: "beefy",
|
|
2966
|
+
args: []
|
|
2967
|
+
},
|
|
2968
|
+
beefy_subscribeJustifications: {
|
|
2969
|
+
description: "Subscribe to BEEFY signed commitments.",
|
|
2970
|
+
family: "beefy",
|
|
2971
|
+
args: [],
|
|
2972
|
+
subscription: true
|
|
2973
|
+
},
|
|
2974
|
+
mmr_root: {
|
|
2975
|
+
description: "MMR root at a block.",
|
|
2976
|
+
family: "mmr",
|
|
2977
|
+
args: [{ name: "at", type: "H256", optional: true }]
|
|
2978
|
+
},
|
|
2979
|
+
mmr_generateProof: {
|
|
2980
|
+
description: "Generate an MMR proof for given leaf indices.",
|
|
2981
|
+
family: "mmr",
|
|
2982
|
+
args: [
|
|
2983
|
+
{ name: "blockNumbers", type: "u32[]" },
|
|
2984
|
+
{ name: "bestKnownBlockNumber", type: "u32", optional: true },
|
|
2985
|
+
{ name: "at", type: "H256", optional: true }
|
|
2986
|
+
]
|
|
2987
|
+
},
|
|
2988
|
+
mmr_verifyProof: {
|
|
2989
|
+
description: "Verify an MMR proof.",
|
|
2990
|
+
family: "mmr",
|
|
2991
|
+
args: [{ name: "proof", type: "MmrLeavesProof" }]
|
|
2992
|
+
},
|
|
2993
|
+
offchain_localStorageGet: {
|
|
2994
|
+
description: "Read from offchain-worker local storage (PERSISTENT or LOCAL kind).",
|
|
2995
|
+
family: "offchain",
|
|
2996
|
+
args: [
|
|
2997
|
+
{ name: "kind", type: "string", description: "PERSISTENT or LOCAL" },
|
|
2998
|
+
{ name: "key", type: "hex" }
|
|
2999
|
+
]
|
|
3000
|
+
},
|
|
3001
|
+
offchain_localStorageSet: {
|
|
3002
|
+
description: "Write to offchain-worker local storage.",
|
|
3003
|
+
family: "offchain",
|
|
3004
|
+
args: [
|
|
3005
|
+
{ name: "kind", type: "string" },
|
|
3006
|
+
{ name: "key", type: "hex" },
|
|
3007
|
+
{ name: "value", type: "hex" }
|
|
3008
|
+
],
|
|
3009
|
+
dangerous: true
|
|
3010
|
+
},
|
|
3011
|
+
dev_newBlock: {
|
|
3012
|
+
description: "Manually trigger block production (manual-seal dev nodes).",
|
|
3013
|
+
family: "dev",
|
|
3014
|
+
args: [
|
|
3015
|
+
{
|
|
3016
|
+
name: "params",
|
|
3017
|
+
type: "json",
|
|
3018
|
+
optional: true,
|
|
3019
|
+
description: "{ create_empty?: bool, finalize?: bool }"
|
|
3020
|
+
}
|
|
3021
|
+
],
|
|
3022
|
+
dangerous: true
|
|
3023
|
+
},
|
|
3024
|
+
dev_setHead: {
|
|
3025
|
+
description: "Set the chain head to a specific block (manual-seal dev nodes).",
|
|
3026
|
+
family: "dev",
|
|
3027
|
+
args: [{ name: "blockHash", type: "H256" }],
|
|
3028
|
+
dangerous: true
|
|
3029
|
+
},
|
|
3030
|
+
rpc_methods: {
|
|
3031
|
+
description: "List of JSON-RPC methods this node exposes.",
|
|
3032
|
+
family: "spec",
|
|
3033
|
+
args: []
|
|
3034
|
+
},
|
|
3035
|
+
chainSpec_v1_chainName: {
|
|
3036
|
+
description: "Chain name from the chain spec (no SCALE).",
|
|
3037
|
+
family: "chainSpec",
|
|
3038
|
+
args: []
|
|
3039
|
+
},
|
|
3040
|
+
chainSpec_v1_genesisHash: {
|
|
3041
|
+
description: "Genesis block hash.",
|
|
3042
|
+
family: "chainSpec",
|
|
3043
|
+
args: []
|
|
3044
|
+
},
|
|
3045
|
+
chainSpec_v1_properties: {
|
|
3046
|
+
description: "Chain properties from the chain spec.",
|
|
3047
|
+
family: "chainSpec",
|
|
3048
|
+
args: []
|
|
3049
|
+
},
|
|
3050
|
+
archive_v1_finalizedHeight: {
|
|
3051
|
+
description: "Latest finalized block number this archive node has.",
|
|
3052
|
+
family: "archive",
|
|
3053
|
+
args: []
|
|
3054
|
+
},
|
|
3055
|
+
archive_v1_genesisHash: {
|
|
3056
|
+
description: "Genesis block hash from the archive node.",
|
|
3057
|
+
family: "archive",
|
|
3058
|
+
args: []
|
|
3059
|
+
},
|
|
3060
|
+
archive_v1_hashByHeight: {
|
|
3061
|
+
description: "Block hashes at a height (canonical + forks).",
|
|
3062
|
+
family: "archive",
|
|
3063
|
+
args: [{ name: "height", type: "u32" }]
|
|
3064
|
+
},
|
|
3065
|
+
archive_v1_header: {
|
|
3066
|
+
description: "Header for an archived block.",
|
|
3067
|
+
family: "archive",
|
|
3068
|
+
args: [{ name: "blockHash", type: "H256" }]
|
|
3069
|
+
},
|
|
3070
|
+
archive_v1_body: {
|
|
3071
|
+
description: "Block body (extrinsics) for an archived block.",
|
|
3072
|
+
family: "archive",
|
|
3073
|
+
args: [{ name: "blockHash", type: "H256" }]
|
|
3074
|
+
},
|
|
3075
|
+
archive_v1_call: {
|
|
3076
|
+
description: "Invoke a runtime API at an archived block.",
|
|
3077
|
+
family: "archive",
|
|
3078
|
+
args: [
|
|
3079
|
+
{ name: "blockHash", type: "H256" },
|
|
3080
|
+
{ name: "function", type: "string" },
|
|
3081
|
+
{ name: "callParameters", type: "hex" }
|
|
3082
|
+
]
|
|
3083
|
+
},
|
|
3084
|
+
archive_v1_storage: {
|
|
3085
|
+
description: "Read storage at an archived block.",
|
|
3086
|
+
family: "archive",
|
|
3087
|
+
args: [
|
|
3088
|
+
{ name: "blockHash", type: "H256" },
|
|
3089
|
+
{ name: "items", type: "StorageItemInput[]" },
|
|
3090
|
+
{ name: "childTrie", type: "string", optional: true }
|
|
3091
|
+
],
|
|
3092
|
+
subscription: true
|
|
3093
|
+
},
|
|
3094
|
+
chainHead_v1_follow: {
|
|
3095
|
+
description: "Pin chainHead and stream block events. Requires a follow session.",
|
|
3096
|
+
family: "chainHead",
|
|
3097
|
+
args: [{ name: "withRuntime", type: "bool" }],
|
|
3098
|
+
subscription: true
|
|
3099
|
+
},
|
|
3100
|
+
transaction_v1_broadcast: {
|
|
3101
|
+
description: "Broadcast a signed extrinsic and watch its status.",
|
|
3102
|
+
family: "transaction",
|
|
3103
|
+
args: [{ name: "extrinsic", type: "hex" }],
|
|
3104
|
+
dangerous: true,
|
|
3105
|
+
subscription: true
|
|
3106
|
+
}
|
|
3107
|
+
};
|
|
3108
|
+
});
|
|
3109
|
+
|
|
3110
|
+
// src/core/xxh64.ts
|
|
3111
|
+
function rotl(v, r) {
|
|
3112
|
+
return (v << r | v >> 64n - r) & MASK;
|
|
3113
|
+
}
|
|
3114
|
+
function round(acc, val) {
|
|
3115
|
+
acc = acc + val * P2 & MASK;
|
|
3116
|
+
acc = rotl(acc, 31n);
|
|
3117
|
+
return acc * P1 & MASK;
|
|
3118
|
+
}
|
|
3119
|
+
function mergeRound(h, val) {
|
|
3120
|
+
const k = round(0n, val);
|
|
3121
|
+
return (h ^ k) * P1 + P4 & MASK;
|
|
3122
|
+
}
|
|
3123
|
+
function readU64LE(data, p) {
|
|
3124
|
+
return BigInt(data[p]) | BigInt(data[p + 1]) << 8n | BigInt(data[p + 2]) << 16n | BigInt(data[p + 3]) << 24n | BigInt(data[p + 4]) << 32n | BigInt(data[p + 5]) << 40n | BigInt(data[p + 6]) << 48n | BigInt(data[p + 7]) << 56n;
|
|
3125
|
+
}
|
|
3126
|
+
function readU32LE(data, p) {
|
|
3127
|
+
return BigInt(data[p]) | BigInt(data[p + 1]) << 8n | BigInt(data[p + 2]) << 16n | BigInt(data[p + 3]) << 24n;
|
|
3128
|
+
}
|
|
3129
|
+
function xxh64(input, seed = 0n) {
|
|
3130
|
+
const len = input.length;
|
|
3131
|
+
let p = 0;
|
|
3132
|
+
let h;
|
|
3133
|
+
if (len >= 32) {
|
|
3134
|
+
let v1 = seed + P1 + P2 & MASK;
|
|
3135
|
+
let v2 = seed + P2 & MASK;
|
|
3136
|
+
let v3 = seed & MASK;
|
|
3137
|
+
let v4 = seed - P1 & MASK;
|
|
3138
|
+
while (p <= len - 32) {
|
|
3139
|
+
v1 = round(v1, readU64LE(input, p));
|
|
3140
|
+
p += 8;
|
|
3141
|
+
v2 = round(v2, readU64LE(input, p));
|
|
3142
|
+
p += 8;
|
|
3143
|
+
v3 = round(v3, readU64LE(input, p));
|
|
3144
|
+
p += 8;
|
|
3145
|
+
v4 = round(v4, readU64LE(input, p));
|
|
3146
|
+
p += 8;
|
|
3147
|
+
}
|
|
3148
|
+
h = rotl(v1, 1n) + rotl(v2, 7n) + rotl(v3, 12n) + rotl(v4, 18n) & MASK;
|
|
3149
|
+
h = mergeRound(h, v1);
|
|
3150
|
+
h = mergeRound(h, v2);
|
|
3151
|
+
h = mergeRound(h, v3);
|
|
3152
|
+
h = mergeRound(h, v4);
|
|
3153
|
+
} else {
|
|
3154
|
+
h = seed + P5 & MASK;
|
|
3155
|
+
}
|
|
3156
|
+
h = h + BigInt(len) & MASK;
|
|
3157
|
+
while (p + 8 <= len) {
|
|
3158
|
+
const k = round(0n, readU64LE(input, p));
|
|
3159
|
+
h = rotl(h ^ k, 27n) * P1 + P4 & MASK;
|
|
3160
|
+
p += 8;
|
|
3161
|
+
}
|
|
3162
|
+
if (p + 4 <= len) {
|
|
3163
|
+
const k = readU32LE(input, p) * P1 & MASK;
|
|
3164
|
+
h = rotl(h ^ k, 23n) * P2 + P3 & MASK;
|
|
3165
|
+
p += 4;
|
|
3166
|
+
}
|
|
3167
|
+
while (p < len) {
|
|
3168
|
+
const k = BigInt(input[p]) * P5 & MASK;
|
|
3169
|
+
h = rotl(h ^ k, 11n) * P1 & MASK;
|
|
3170
|
+
p++;
|
|
3171
|
+
}
|
|
3172
|
+
h ^= h >> 33n;
|
|
3173
|
+
h = h * P2 & MASK;
|
|
3174
|
+
h ^= h >> 29n;
|
|
3175
|
+
h = h * P3 & MASK;
|
|
3176
|
+
h ^= h >> 32n;
|
|
3177
|
+
return h;
|
|
3178
|
+
}
|
|
3179
|
+
function u64ToLEBytes(v, out, offset) {
|
|
3180
|
+
for (let i = 0;i < 8; i++) {
|
|
3181
|
+
out[offset + i] = Number(v >> BigInt(i * 8) & 0xffn);
|
|
3182
|
+
}
|
|
3183
|
+
}
|
|
3184
|
+
function twox(input, bits) {
|
|
3185
|
+
const lanes = bits / 64;
|
|
3186
|
+
const out = new Uint8Array(bits / 8);
|
|
3187
|
+
for (let i = 0;i < lanes; i++) {
|
|
3188
|
+
u64ToLEBytes(xxh64(input, BigInt(i)), out, i * 8);
|
|
3189
|
+
}
|
|
3190
|
+
return out;
|
|
3191
|
+
}
|
|
3192
|
+
var MASK, P1 = 11400714785074694791n, P2 = 14029467366897019727n, P3 = 1609587929392839161n, P4 = 9650029242287828579n, P5 = 2870177450012600261n;
|
|
3193
|
+
var init_xxh64 = __esm(() => {
|
|
3194
|
+
MASK = (1n << 64n) - 1n;
|
|
3195
|
+
});
|
|
3196
|
+
|
|
2562
3197
|
// src/core/hash.ts
|
|
2563
3198
|
import { blake2b as blake2b2 } from "@noble/hashes/blake2.js";
|
|
2564
3199
|
import { sha256 } from "@noble/hashes/sha2.js";
|
|
2565
|
-
import { keccak_256 } from "@noble/hashes/sha3.js";
|
|
2566
|
-
import { bytesToHex as
|
|
3200
|
+
import { keccak_256 as keccak_2562 } from "@noble/hashes/sha3.js";
|
|
3201
|
+
import { bytesToHex as bytesToHex3, hexToBytes as hexToBytes3 } from "@noble/hashes/utils.js";
|
|
2567
3202
|
function computeHash(algorithm, data) {
|
|
2568
3203
|
const algo = ALGORITHMS[algorithm];
|
|
2569
3204
|
if (!algo) {
|
|
@@ -2577,12 +3212,12 @@ function parseInputData(input) {
|
|
|
2577
3212
|
if (hex.length % 2 !== 0) {
|
|
2578
3213
|
throw new Error(`Invalid hex input: odd number of characters`);
|
|
2579
3214
|
}
|
|
2580
|
-
return
|
|
3215
|
+
return hexToBytes3(hex);
|
|
2581
3216
|
}
|
|
2582
3217
|
return new TextEncoder().encode(input);
|
|
2583
3218
|
}
|
|
2584
3219
|
function toHex2(bytes) {
|
|
2585
|
-
return `0x${
|
|
3220
|
+
return `0x${bytesToHex3(bytes)}`;
|
|
2586
3221
|
}
|
|
2587
3222
|
function isValidAlgorithm(name) {
|
|
2588
3223
|
return name in ALGORITHMS;
|
|
@@ -2592,6 +3227,7 @@ function getAlgorithmNames() {
|
|
|
2592
3227
|
}
|
|
2593
3228
|
var ALGORITHMS;
|
|
2594
3229
|
var init_hash = __esm(() => {
|
|
3230
|
+
init_xxh64();
|
|
2595
3231
|
ALGORITHMS = {
|
|
2596
3232
|
blake2b256: {
|
|
2597
3233
|
compute: (data) => blake2b2(data, { dkLen: 32 }),
|
|
@@ -2604,7 +3240,7 @@ var init_hash = __esm(() => {
|
|
|
2604
3240
|
description: "BLAKE2b with 128-bit output"
|
|
2605
3241
|
},
|
|
2606
3242
|
keccak256: {
|
|
2607
|
-
compute: (data) =>
|
|
3243
|
+
compute: (data) => keccak_2562(data),
|
|
2608
3244
|
outputLen: 32,
|
|
2609
3245
|
description: "Keccak-256 (Ethereum-compatible)"
|
|
2610
3246
|
},
|
|
@@ -2612,6 +3248,21 @@ var init_hash = __esm(() => {
|
|
|
2612
3248
|
compute: (data) => sha256(data),
|
|
2613
3249
|
outputLen: 32,
|
|
2614
3250
|
description: "SHA-256"
|
|
3251
|
+
},
|
|
3252
|
+
twox64: {
|
|
3253
|
+
compute: (data) => twox(data, 64),
|
|
3254
|
+
outputLen: 8,
|
|
3255
|
+
description: "XXH64 with seed 0 (Substrate twox64)"
|
|
3256
|
+
},
|
|
3257
|
+
twox128: {
|
|
3258
|
+
compute: (data) => twox(data, 128),
|
|
3259
|
+
outputLen: 16,
|
|
3260
|
+
description: "XXH64 with seeds 0,1 (Substrate twox128, pallet/storage prefix)"
|
|
3261
|
+
},
|
|
3262
|
+
twox256: {
|
|
3263
|
+
compute: (data) => twox(data, 256),
|
|
3264
|
+
outputLen: 32,
|
|
3265
|
+
description: "XXH64 with seeds 0,1,2,3 (Substrate twox256)"
|
|
2615
3266
|
}
|
|
2616
3267
|
};
|
|
2617
3268
|
});
|
|
@@ -2742,11 +3393,8 @@ async function generateCompletions(currentWord, precedingWords) {
|
|
|
2742
3393
|
if (firstArg === "hash") {
|
|
2743
3394
|
return filterPrefix(getAlgorithmNames(), currentWord);
|
|
2744
3395
|
}
|
|
2745
|
-
if (firstArg === "parachain") {
|
|
2746
|
-
|
|
2747
|
-
return filterPrefix(["child", "sibling"], currentWord);
|
|
2748
|
-
}
|
|
2749
|
-
return [];
|
|
3396
|
+
if (firstArg === "account" && prevWord === "--parachain-type") {
|
|
3397
|
+
return filterPrefix(["child", "sibling"], currentWord);
|
|
2750
3398
|
}
|
|
2751
3399
|
return completeDotpath(currentWord, config, knownChains, precedingWords);
|
|
2752
3400
|
}
|
|
@@ -2789,6 +3437,9 @@ async function completeDotpath(currentWord, config, knownChains, precedingWords)
|
|
|
2789
3437
|
if (category === "extensions") {
|
|
2790
3438
|
return completeExtensionsCategory(first, numComplete, endsWithDot, currentWord, config, chainFromFlag);
|
|
2791
3439
|
}
|
|
3440
|
+
if (category === "rpc") {
|
|
3441
|
+
return completeRpcCategory(first, numComplete, endsWithDot, currentWord, chainFromFlag);
|
|
3442
|
+
}
|
|
2792
3443
|
if (numComplete === 1 && endsWithDot) {
|
|
2793
3444
|
const chainName = chainFromFlag;
|
|
2794
3445
|
if (!chainName)
|
|
@@ -2848,6 +3499,9 @@ async function completeDotpath(currentWord, config, knownChains, precedingWords)
|
|
|
2848
3499
|
if (category === "extensions") {
|
|
2849
3500
|
return completeExtensionsCategory(`${first}.${completeSegments[1]}`, numComplete - 1, endsWithDot, currentWord, config, chainName);
|
|
2850
3501
|
}
|
|
3502
|
+
if (category === "rpc") {
|
|
3503
|
+
return completeRpcCategory(`${first}.${completeSegments[1]}`, numComplete - 1, endsWithDot, currentWord, chainName);
|
|
3504
|
+
}
|
|
2851
3505
|
const pallets = await loadPallets(config, chainName);
|
|
2852
3506
|
if (!pallets)
|
|
2853
3507
|
return [];
|
|
@@ -2921,6 +3575,24 @@ async function completeExtensionsCategory(prefix, numComplete, endsWithDot, curr
|
|
|
2921
3575
|
}
|
|
2922
3576
|
return [];
|
|
2923
3577
|
}
|
|
3578
|
+
async function completeRpcCategory(prefix, numComplete, endsWithDot, currentWord, chainNameOverride) {
|
|
3579
|
+
let names;
|
|
3580
|
+
if (chainNameOverride) {
|
|
3581
|
+
const cached = await loadRpcMethods(chainNameOverride);
|
|
3582
|
+
names = cached?.methods ?? Object.keys(RPC_REGISTRY);
|
|
3583
|
+
} else {
|
|
3584
|
+
names = Object.keys(RPC_REGISTRY);
|
|
3585
|
+
}
|
|
3586
|
+
if (numComplete === 1 && endsWithDot) {
|
|
3587
|
+
const candidates = names.map((n) => `${prefix}.${n}`);
|
|
3588
|
+
return filterPrefix(candidates, currentWord.slice(0, -1));
|
|
3589
|
+
}
|
|
3590
|
+
if (numComplete === 1 && !endsWithDot) {
|
|
3591
|
+
const candidates = names.map((n) => `${prefix}.${n}`);
|
|
3592
|
+
return filterPrefix(candidates, currentWord);
|
|
3593
|
+
}
|
|
3594
|
+
return [];
|
|
3595
|
+
}
|
|
2924
3596
|
var CATEGORIES2, CATEGORY_ALIASES2, NAMED_COMMANDS, CHAIN_SUBCOMMANDS, ACCOUNT_SUBCOMMANDS, GLOBAL_OPTIONS, TX_OPTIONS, QUERY_OPTIONS;
|
|
2925
3597
|
var init_complete = __esm(() => {
|
|
2926
3598
|
init_accounts_store();
|
|
@@ -2928,7 +3600,17 @@ var init_complete = __esm(() => {
|
|
|
2928
3600
|
init_accounts();
|
|
2929
3601
|
init_hash();
|
|
2930
3602
|
init_metadata();
|
|
2931
|
-
|
|
3603
|
+
init_rpc_registry();
|
|
3604
|
+
CATEGORIES2 = [
|
|
3605
|
+
"query",
|
|
3606
|
+
"tx",
|
|
3607
|
+
"const",
|
|
3608
|
+
"events",
|
|
3609
|
+
"errors",
|
|
3610
|
+
"apis",
|
|
3611
|
+
"extensions",
|
|
3612
|
+
"rpc"
|
|
3613
|
+
];
|
|
2932
3614
|
CATEGORY_ALIASES2 = {
|
|
2933
3615
|
query: "query",
|
|
2934
3616
|
tx: "tx",
|
|
@@ -2943,9 +3625,10 @@ var init_complete = __esm(() => {
|
|
|
2943
3625
|
api: "apis",
|
|
2944
3626
|
extensions: "extensions",
|
|
2945
3627
|
extension: "extensions",
|
|
2946
|
-
ext: "extensions"
|
|
3628
|
+
ext: "extensions",
|
|
3629
|
+
rpc: "rpc"
|
|
2947
3630
|
};
|
|
2948
|
-
NAMED_COMMANDS = ["chain", "account", "inspect", "hash", "sign", "
|
|
3631
|
+
NAMED_COMMANDS = ["chain", "account", "inspect", "hash", "sign", "completions"];
|
|
2949
3632
|
CHAIN_SUBCOMMANDS = ["add", "info", "list", "remove", "update"];
|
|
2950
3633
|
ACCOUNT_SUBCOMMANDS = [
|
|
2951
3634
|
"add",
|
|
@@ -2977,23 +3660,154 @@ var init_complete = __esm(() => {
|
|
|
2977
3660
|
// src/cli.ts
|
|
2978
3661
|
import cac from "cac";
|
|
2979
3662
|
// package.json
|
|
2980
|
-
var version = "1.
|
|
3663
|
+
var version = "1.19.0";
|
|
2981
3664
|
|
|
2982
3665
|
// src/commands/account.ts
|
|
2983
3666
|
init_accounts_store();
|
|
2984
3667
|
init_accounts();
|
|
2985
|
-
init_output();
|
|
2986
3668
|
import { readFile as readFile3, writeFile as writeFile3 } from "node:fs/promises";
|
|
3669
|
+
import { hexToBytes as nobleHexToBytes } from "@noble/hashes/utils.js";
|
|
3670
|
+
|
|
3671
|
+
// src/core/h160.ts
|
|
3672
|
+
import { keccak_256 } from "@noble/hashes/sha3.js";
|
|
3673
|
+
import { bytesToHex as bytesToHex2, hexToBytes } from "@noble/hashes/utils.js";
|
|
3674
|
+
var ETH_DERIVED_SUFFIX_BYTE = 238;
|
|
3675
|
+
var H160_LEN = 20;
|
|
3676
|
+
var ACCOUNT_ID_LEN = 32;
|
|
3677
|
+
function hasEthDerivedSuffix(accountId) {
|
|
3678
|
+
if (accountId.length !== ACCOUNT_ID_LEN)
|
|
3679
|
+
return false;
|
|
3680
|
+
for (let i = H160_LEN;i < ACCOUNT_ID_LEN; i++) {
|
|
3681
|
+
if (accountId[i] !== ETH_DERIVED_SUFFIX_BYTE)
|
|
3682
|
+
return false;
|
|
3683
|
+
}
|
|
3684
|
+
return true;
|
|
3685
|
+
}
|
|
3686
|
+
function accountIdToH160(accountId) {
|
|
3687
|
+
if (accountId.length !== ACCOUNT_ID_LEN) {
|
|
3688
|
+
throw new Error(`accountIdToH160 expects 32 bytes, got ${accountId.length}`);
|
|
3689
|
+
}
|
|
3690
|
+
if (hasEthDerivedSuffix(accountId)) {
|
|
3691
|
+
return accountId.slice(0, H160_LEN);
|
|
3692
|
+
}
|
|
3693
|
+
return keccak_256(accountId).slice(ACCOUNT_ID_LEN - H160_LEN);
|
|
3694
|
+
}
|
|
3695
|
+
function h160ToFallbackAccountId(h160) {
|
|
3696
|
+
if (h160.length !== H160_LEN) {
|
|
3697
|
+
throw new Error(`h160ToFallbackAccountId expects 20 bytes, got ${h160.length}`);
|
|
3698
|
+
}
|
|
3699
|
+
const out = new Uint8Array(ACCOUNT_ID_LEN);
|
|
3700
|
+
out.set(h160, 0);
|
|
3701
|
+
out.fill(ETH_DERIVED_SUFFIX_BYTE, H160_LEN);
|
|
3702
|
+
return out;
|
|
3703
|
+
}
|
|
3704
|
+
function toEip55(h160) {
|
|
3705
|
+
if (h160.length !== H160_LEN) {
|
|
3706
|
+
throw new Error(`toEip55 expects 20 bytes, got ${h160.length}`);
|
|
3707
|
+
}
|
|
3708
|
+
const lowerHex = bytesToHex2(h160);
|
|
3709
|
+
const hashBytes = keccak_256(new TextEncoder().encode(lowerHex));
|
|
3710
|
+
let out = "0x";
|
|
3711
|
+
for (let i = 0;i < lowerHex.length; i++) {
|
|
3712
|
+
const c = lowerHex[i];
|
|
3713
|
+
const nibble = i % 2 === 0 ? hashBytes[i >> 1] >> 4 : hashBytes[i >> 1] & 15;
|
|
3714
|
+
out += nibble >= 8 ? c.toUpperCase() : c;
|
|
3715
|
+
}
|
|
3716
|
+
return out;
|
|
3717
|
+
}
|
|
3718
|
+
function isH160Hex(input) {
|
|
3719
|
+
return /^0x[0-9a-fA-F]{40}$/.test(input);
|
|
3720
|
+
}
|
|
3721
|
+
function h160FromHex(input) {
|
|
3722
|
+
if (!isH160Hex(input)) {
|
|
3723
|
+
throw new Error(`Not a valid 0x-prefixed 20-byte hex string: ${input}`);
|
|
3724
|
+
}
|
|
3725
|
+
return hexToBytes(input.slice(2));
|
|
3726
|
+
}
|
|
3727
|
+
|
|
3728
|
+
// src/commands/account.ts
|
|
3729
|
+
init_output();
|
|
3730
|
+
|
|
3731
|
+
// src/core/pallet.ts
|
|
3732
|
+
init_errors();
|
|
3733
|
+
var MODL_PREFIX = new Uint8Array([109, 111, 100, 108]);
|
|
3734
|
+
var PALLET_ID_BYTES = 8;
|
|
3735
|
+
function derivePalletAccount(palletId) {
|
|
3736
|
+
if (palletId.length !== PALLET_ID_BYTES) {
|
|
3737
|
+
throw new CliError(`PalletId must be exactly ${PALLET_ID_BYTES} bytes (got ${palletId.length}).`);
|
|
3738
|
+
}
|
|
3739
|
+
const result = new Uint8Array(32);
|
|
3740
|
+
result.set(MODL_PREFIX, 0);
|
|
3741
|
+
result.set(palletId, 4);
|
|
3742
|
+
return result;
|
|
3743
|
+
}
|
|
3744
|
+
function parsePalletId(input) {
|
|
3745
|
+
if (input.startsWith("0x") || input.startsWith("0X")) {
|
|
3746
|
+
const hex = input.slice(2);
|
|
3747
|
+
if (hex.length !== PALLET_ID_BYTES * 2) {
|
|
3748
|
+
throw new CliError(`Invalid PalletId hex "${input}". Must be 0x followed by exactly ${PALLET_ID_BYTES * 2} hex characters.`);
|
|
3749
|
+
}
|
|
3750
|
+
if (!/^[0-9a-fA-F]+$/.test(hex)) {
|
|
3751
|
+
throw new CliError(`Invalid PalletId hex "${input}". Contains non-hex characters.`);
|
|
3752
|
+
}
|
|
3753
|
+
const bytes2 = new Uint8Array(PALLET_ID_BYTES);
|
|
3754
|
+
for (let i = 0;i < PALLET_ID_BYTES; i++) {
|
|
3755
|
+
bytes2[i] = parseInt(hex.slice(i * 2, i * 2 + 2), 16);
|
|
3756
|
+
}
|
|
3757
|
+
return bytes2;
|
|
3758
|
+
}
|
|
3759
|
+
if (input.length !== PALLET_ID_BYTES) {
|
|
3760
|
+
throw new CliError(`Invalid PalletId "${input}". Must be ${PALLET_ID_BYTES} ASCII characters or 0x-prefixed hex.`);
|
|
3761
|
+
}
|
|
3762
|
+
const bytes = new Uint8Array(PALLET_ID_BYTES);
|
|
3763
|
+
for (let i = 0;i < PALLET_ID_BYTES; i++) {
|
|
3764
|
+
const code = input.charCodeAt(i);
|
|
3765
|
+
if (code > 127) {
|
|
3766
|
+
throw new CliError(`Invalid PalletId "${input}". ASCII form must contain only ASCII bytes.`);
|
|
3767
|
+
}
|
|
3768
|
+
bytes[i] = code;
|
|
3769
|
+
}
|
|
3770
|
+
return bytes;
|
|
3771
|
+
}
|
|
3772
|
+
function formatPalletId(palletId) {
|
|
3773
|
+
const allPrintable = palletId.every((b) => b >= 32 && b <= 126);
|
|
3774
|
+
if (allPrintable) {
|
|
3775
|
+
return Array.from(palletId, (b) => String.fromCharCode(b)).join("");
|
|
3776
|
+
}
|
|
3777
|
+
return `0x${Array.from(palletId, (b) => b.toString(16).padStart(2, "0")).join("")}`;
|
|
3778
|
+
}
|
|
3779
|
+
|
|
3780
|
+
// src/core/parachain.ts
|
|
3781
|
+
var SOVEREIGN_ACCOUNT_TYPES = ["child", "sibling"];
|
|
3782
|
+
var PREFIXES = {
|
|
3783
|
+
child: new Uint8Array([112, 97, 114, 97]),
|
|
3784
|
+
sibling: new Uint8Array([115, 105, 98, 108])
|
|
3785
|
+
};
|
|
3786
|
+
function deriveSovereignAccount(paraId, type) {
|
|
3787
|
+
const result = new Uint8Array(32);
|
|
3788
|
+
result.set(PREFIXES[type], 0);
|
|
3789
|
+
new DataView(result.buffer).setUint32(4, paraId, true);
|
|
3790
|
+
return result;
|
|
3791
|
+
}
|
|
3792
|
+
function isValidParaId(value) {
|
|
3793
|
+
return Number.isInteger(value) && value >= 0 && value <= 4294967295;
|
|
3794
|
+
}
|
|
3795
|
+
|
|
3796
|
+
// src/commands/account.ts
|
|
2987
3797
|
var ACCOUNT_HELP = `
|
|
2988
3798
|
${BOLD}Usage:${RESET}
|
|
2989
3799
|
$ dot account add <name> <ss58|hex> Add a watch-only address (no secret)
|
|
2990
3800
|
$ dot account add <name> --secret <s> [--path <derivation>] Import from BIP39 mnemonic
|
|
2991
3801
|
$ dot account add <name> --env <VAR> [--path <derivation>] Import account backed by env variable
|
|
3802
|
+
$ dot account add <name> --parachain <id> --parachain-type <t> Derive a parachain sovereign (t = child|sibling)
|
|
3803
|
+
$ dot account add <name> --pallet-id <8 chars or 0x hex> Derive a pallet sovereign (e.g. py/trsry)
|
|
2992
3804
|
$ dot account create|new <name> [--path <derivation>] Create a new account
|
|
2993
3805
|
$ dot account import <file> Batch-import accounts from a file
|
|
2994
3806
|
$ dot account export [names...] Export accounts to stdout
|
|
2995
3807
|
$ dot account derive <source> <new-name> --path <derivation> Derive a child account
|
|
2996
3808
|
$ dot account inspect <input> [--prefix <N>] [--show-secret] Inspect an account/address/key
|
|
3809
|
+
$ dot account inspect --pallet-id <id> [--prefix <N>] Derive a pallet sovereign (no save — script-friendly)
|
|
3810
|
+
$ dot account inspect --parachain <id> --parachain-type <t> Derive a parachain sovereign (no save — script-friendly)
|
|
2997
3811
|
$ dot account list List all accounts
|
|
2998
3812
|
$ dot account remove|delete <name> [name2] ... Remove stored account(s)
|
|
2999
3813
|
|
|
@@ -3001,6 +3815,10 @@ ${BOLD}Examples:${RESET}
|
|
|
3001
3815
|
$ dot account add treasury 5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY
|
|
3002
3816
|
$ dot account add treasury --secret "word1 word2 ... word12"
|
|
3003
3817
|
$ dot account add ci-signer --env MY_SECRET --path //ci
|
|
3818
|
+
$ dot account add Treasury --pallet-id py/trsry
|
|
3819
|
+
$ dot account add Bounties --pallet-id 0x70792f626f756e74
|
|
3820
|
+
$ dot account add People --parachain 1004 --parachain-type child
|
|
3821
|
+
$ dot account add People-Sibling --parachain 1004 --parachain-type sibling
|
|
3004
3822
|
$ dot account create my-validator
|
|
3005
3823
|
$ dot account create my-staking --path //staking
|
|
3006
3824
|
$ dot account create multi --path //polkadot//0/wallet
|
|
@@ -3016,6 +3834,8 @@ ${BOLD}Examples:${RESET}
|
|
|
3016
3834
|
$ dot account inspect dave --show-secret
|
|
3017
3835
|
$ dot account inspect 5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY
|
|
3018
3836
|
$ dot account inspect 0xd435...a27d --prefix 0
|
|
3837
|
+
$ dot account inspect --pallet-id py/trsry --prefix 0
|
|
3838
|
+
$ dot account inspect --parachain 1004 --parachain-type child
|
|
3019
3839
|
$ dot account list
|
|
3020
3840
|
$ dot account remove my-validator stale-key
|
|
3021
3841
|
|
|
@@ -3024,7 +3844,7 @@ ${YELLOW}Note: Secrets are stored unencrypted in ~/.polkadot/accounts.json.
|
|
|
3024
3844
|
Hex seed import (0x...) is not supported via CLI.${RESET}
|
|
3025
3845
|
`.trimStart();
|
|
3026
3846
|
function registerAccountCommands(cli) {
|
|
3027
|
-
cli.command("account [action] [...names]", "Manage local accounts (create, import, list, remove, export)").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)").option("--file <path>", "Input/output file for batch import/export").option("--overwrite", "Overwrite existing accounts on batch import").option("--dry-run", "Preview batch import without applying changes").option("--include-secrets", "Include secrets in export (redacted by default)").option("--watch-only", "Export only watch-only accounts").option("--show-secret", "Reveal the 64-byte sr25519 expanded private key (inspect only)").action(async (action, names, opts) => {
|
|
3847
|
+
cli.command("account [action] [...names]", "Manage local accounts (create, import, list, remove, export)").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("--parachain <id>", "Derive a parachain sovereign account (requires --parachain-type)").option("--parachain-type <type>", "Parachain sovereign type: child or sibling").option("--pallet-id <id>", "Derive a pallet sovereign account from an 8-byte PalletId").option("--prefix <number>", "SS58 prefix for address encoding (default: 42)").option("--file <path>", "Input/output file for batch import/export").option("--overwrite", "Overwrite existing accounts on batch import").option("--dry-run", "Preview batch import without applying changes").option("--include-secrets", "Include secrets in export (redacted by default)").option("--watch-only", "Export only watch-only accounts").option("--show-secret", "Reveal the 64-byte sr25519 expanded private key (inspect only)").action(async (action, names, opts) => {
|
|
3028
3848
|
if (!action) {
|
|
3029
3849
|
if (process.argv[2] === "accounts")
|
|
3030
3850
|
return accountList(opts);
|
|
@@ -3036,8 +3856,13 @@ function registerAccountCommands(cli) {
|
|
|
3036
3856
|
case "create":
|
|
3037
3857
|
return accountCreate(names[0], opts);
|
|
3038
3858
|
case "add":
|
|
3039
|
-
if (opts.secret || opts.env)
|
|
3859
|
+
if (opts.secret || opts.env) {
|
|
3860
|
+
const hasDerivation = opts.parachain != null || opts.palletId != null || process.argv.includes("--parachain") || process.argv.includes("--pallet-id") || process.argv.some((a) => a.startsWith("--parachain=") || a.startsWith("--pallet-id="));
|
|
3861
|
+
if (hasDerivation) {
|
|
3862
|
+
throw new Error("Derivation flags (--parachain, --pallet-id) cannot be combined with --secret or --env. A derived sovereign account has no secret.");
|
|
3863
|
+
}
|
|
3040
3864
|
return accountImport(names[0], opts);
|
|
3865
|
+
}
|
|
3041
3866
|
return accountAddWatchOnly(names[0], names[1], opts);
|
|
3042
3867
|
case "import":
|
|
3043
3868
|
return accountBatchImport(names[0], opts);
|
|
@@ -3193,10 +4018,16 @@ async function accountAddWatchOnly(name, address, opts = {}) {
|
|
|
3193
4018
|
console.error("Usage: dot account add <name> <ss58-address|0x-public-key>");
|
|
3194
4019
|
process.exit(1);
|
|
3195
4020
|
}
|
|
3196
|
-
|
|
4021
|
+
const sovereignSource = resolveSovereignSource(opts);
|
|
4022
|
+
if (sovereignSource && address) {
|
|
4023
|
+
throw new Error("Cannot combine a positional address with --parachain or --pallet-id. Pass either an address OR a derivation flag, not both.");
|
|
4024
|
+
}
|
|
4025
|
+
if (!sovereignSource && !address) {
|
|
3197
4026
|
console.error(`Address is required.
|
|
3198
4027
|
`);
|
|
3199
4028
|
console.error("Usage: dot account add <name> <ss58-address|0x-public-key>");
|
|
4029
|
+
console.error(" dot account add <name> --parachain <id> --parachain-type <child|sibling>");
|
|
4030
|
+
console.error(" dot account add <name> --pallet-id <8 chars or 0x hex>");
|
|
3200
4031
|
process.exit(1);
|
|
3201
4032
|
}
|
|
3202
4033
|
if (isDevAccount(name)) {
|
|
@@ -3207,7 +4038,10 @@ async function accountAddWatchOnly(name, address, opts = {}) {
|
|
|
3207
4038
|
throw new Error(`Account "${name}" already exists.`);
|
|
3208
4039
|
}
|
|
3209
4040
|
let hexPub;
|
|
3210
|
-
if (
|
|
4041
|
+
if (sovereignSource) {
|
|
4042
|
+
const accountId = sovereignSource.kind === "parachain" ? deriveSovereignAccount(sovereignSource.paraId, sovereignSource.type) : derivePalletAccount(sovereignSource.palletId);
|
|
4043
|
+
hexPub = publicKeyToHex(accountId);
|
|
4044
|
+
} else if (isHexPublicKey(address)) {
|
|
3211
4045
|
hexPub = address;
|
|
3212
4046
|
} else {
|
|
3213
4047
|
try {
|
|
@@ -3217,21 +4051,99 @@ async function accountAddWatchOnly(name, address, opts = {}) {
|
|
|
3217
4051
|
throw new Error(`Invalid address "${address}". Expected an SS58 address or 0x-prefixed 32-byte hex public key.`);
|
|
3218
4052
|
}
|
|
3219
4053
|
}
|
|
4054
|
+
let persistedSource;
|
|
4055
|
+
if (sovereignSource?.kind === "pallet") {
|
|
4056
|
+
persistedSource = {
|
|
4057
|
+
kind: "pallet",
|
|
4058
|
+
palletId: `0x${Array.from(sovereignSource.palletId, (b) => b.toString(16).padStart(2, "0")).join("")}`
|
|
4059
|
+
};
|
|
4060
|
+
} else if (sovereignSource?.kind === "parachain") {
|
|
4061
|
+
persistedSource = {
|
|
4062
|
+
kind: "parachain",
|
|
4063
|
+
paraId: sovereignSource.paraId,
|
|
4064
|
+
type: sovereignSource.type
|
|
4065
|
+
};
|
|
4066
|
+
}
|
|
3220
4067
|
accountsFile.accounts.push({
|
|
3221
4068
|
name,
|
|
3222
4069
|
publicKey: hexPub,
|
|
3223
|
-
derivationPath: ""
|
|
4070
|
+
derivationPath: "",
|
|
4071
|
+
...persistedSource ? { source: persistedSource } : {}
|
|
3224
4072
|
});
|
|
3225
4073
|
await saveAccounts(accountsFile);
|
|
3226
4074
|
if (isJsonOutput(opts)) {
|
|
3227
|
-
|
|
4075
|
+
const payload = {
|
|
4076
|
+
name,
|
|
4077
|
+
address: toSs58(hexPub),
|
|
4078
|
+
watchOnly: true
|
|
4079
|
+
};
|
|
4080
|
+
if (sovereignSource?.kind === "parachain") {
|
|
4081
|
+
payload.derivation = {
|
|
4082
|
+
kind: "parachain",
|
|
4083
|
+
paraId: sovereignSource.paraId,
|
|
4084
|
+
type: sovereignSource.type
|
|
4085
|
+
};
|
|
4086
|
+
} else if (sovereignSource?.kind === "pallet") {
|
|
4087
|
+
payload.derivation = {
|
|
4088
|
+
kind: "pallet",
|
|
4089
|
+
palletId: formatPalletId(sovereignSource.palletId),
|
|
4090
|
+
palletIdHex: `0x${Array.from(sovereignSource.palletId, (b) => b.toString(16).padStart(2, "0")).join("")}`
|
|
4091
|
+
};
|
|
4092
|
+
}
|
|
4093
|
+
console.log(formatJson(payload));
|
|
3228
4094
|
return;
|
|
3229
4095
|
}
|
|
3230
4096
|
printHeading("Account Added (watch-only)");
|
|
3231
4097
|
console.log(` ${BOLD}Name:${RESET} ${name}`);
|
|
3232
4098
|
console.log(` ${BOLD}Address:${RESET} ${toSs58(hexPub)}`);
|
|
4099
|
+
if (sovereignSource?.kind === "parachain") {
|
|
4100
|
+
console.log(` ${BOLD}Source:${RESET} parachain ${sovereignSource.paraId} (${sovereignSource.type} sovereign)`);
|
|
4101
|
+
} else if (sovereignSource?.kind === "pallet") {
|
|
4102
|
+
const display = formatPalletId(sovereignSource.palletId);
|
|
4103
|
+
const hex = `0x${Array.from(sovereignSource.palletId, (b) => b.toString(16).padStart(2, "0")).join("")}`;
|
|
4104
|
+
console.log(` ${BOLD}Source:${RESET} pallet ${display} (${hex})`);
|
|
4105
|
+
}
|
|
3233
4106
|
console.log();
|
|
3234
4107
|
}
|
|
4108
|
+
function rawArgValue(flag) {
|
|
4109
|
+
const argv = process.argv;
|
|
4110
|
+
for (let i = 0;i < argv.length; i++) {
|
|
4111
|
+
if (argv[i] === flag && i + 1 < argv.length)
|
|
4112
|
+
return argv[i + 1];
|
|
4113
|
+
const prefix = `${flag}=`;
|
|
4114
|
+
if (argv[i]?.startsWith(prefix))
|
|
4115
|
+
return argv[i].slice(prefix.length);
|
|
4116
|
+
}
|
|
4117
|
+
return;
|
|
4118
|
+
}
|
|
4119
|
+
function resolveSovereignSource(opts) {
|
|
4120
|
+
const rawPalletId = rawArgValue("--pallet-id") ?? opts.palletId;
|
|
4121
|
+
const rawParachain = rawArgValue("--parachain") ?? opts.parachain;
|
|
4122
|
+
if (rawParachain != null && rawPalletId != null) {
|
|
4123
|
+
throw new Error("--parachain and --pallet-id are mutually exclusive. Pass only one derivation flag.");
|
|
4124
|
+
}
|
|
4125
|
+
if (rawParachain != null) {
|
|
4126
|
+
const paraId = Number(rawParachain);
|
|
4127
|
+
if (!isValidParaId(paraId)) {
|
|
4128
|
+
throw new Error(`Invalid parachain ID "${rawParachain}". Must be a non-negative integer (0 to 4294967295).`);
|
|
4129
|
+
}
|
|
4130
|
+
if (!opts.parachainType) {
|
|
4131
|
+
throw new Error("--parachain-type is required when --parachain is given. Use --parachain-type child or --parachain-type sibling.");
|
|
4132
|
+
}
|
|
4133
|
+
const type = opts.parachainType.toLowerCase();
|
|
4134
|
+
if (type !== "child" && type !== "sibling") {
|
|
4135
|
+
throw new Error(`Unknown parachain account type "${opts.parachainType}". Valid types: child, sibling.`);
|
|
4136
|
+
}
|
|
4137
|
+
return { kind: "parachain", paraId, type };
|
|
4138
|
+
}
|
|
4139
|
+
if (rawPalletId != null) {
|
|
4140
|
+
return { kind: "pallet", palletId: parsePalletId(String(rawPalletId)) };
|
|
4141
|
+
}
|
|
4142
|
+
if (opts.parachainType != null) {
|
|
4143
|
+
throw new Error("--parachain-type requires --parachain.");
|
|
4144
|
+
}
|
|
4145
|
+
return;
|
|
4146
|
+
}
|
|
3235
4147
|
async function accountDerive(sourceName, newName, opts) {
|
|
3236
4148
|
if (!sourceName) {
|
|
3237
4149
|
console.error(`Source account name is required.
|
|
@@ -3315,69 +4227,134 @@ async function accountDerive(sourceName, newName, opts) {
|
|
|
3315
4227
|
console.log();
|
|
3316
4228
|
}
|
|
3317
4229
|
}
|
|
4230
|
+
function resolveAddress(account) {
|
|
4231
|
+
if (isWatchOnly(account)) {
|
|
4232
|
+
return account.publicKey ? toSs58(account.publicKey) : "n/a";
|
|
4233
|
+
}
|
|
4234
|
+
if (account.secret !== undefined && isEnvSecret(account.secret)) {
|
|
4235
|
+
const pubKey = account.publicKey || tryDerivePublicKey(account.secret.env, account.derivationPath) || "";
|
|
4236
|
+
return pubKey ? toSs58(pubKey) : "n/a";
|
|
4237
|
+
}
|
|
4238
|
+
return toSs58(account.publicKey);
|
|
4239
|
+
}
|
|
4240
|
+
function buildAttributes(account) {
|
|
4241
|
+
const attrs = [];
|
|
4242
|
+
if (account.derivationPath)
|
|
4243
|
+
attrs.push({ label: "path", value: account.derivationPath });
|
|
4244
|
+
if (account.secret !== undefined && isEnvSecret(account.secret)) {
|
|
4245
|
+
attrs.push({ label: "env", value: `$${account.secret.env}` });
|
|
4246
|
+
}
|
|
4247
|
+
if (account.source) {
|
|
4248
|
+
if (account.source.kind === "pallet") {
|
|
4249
|
+
const bytes = parsePalletId(account.source.palletId);
|
|
4250
|
+
attrs.push({
|
|
4251
|
+
label: "pallet-id",
|
|
4252
|
+
value: `${formatPalletId(bytes)} (${account.source.palletId})`
|
|
4253
|
+
});
|
|
4254
|
+
} else {
|
|
4255
|
+
attrs.push({ label: "parachain", value: String(account.source.paraId) });
|
|
4256
|
+
attrs.push({ label: "parachain-type", value: account.source.type });
|
|
4257
|
+
}
|
|
4258
|
+
}
|
|
4259
|
+
return attrs;
|
|
4260
|
+
}
|
|
4261
|
+
function buildRow(account) {
|
|
4262
|
+
return {
|
|
4263
|
+
account,
|
|
4264
|
+
kind: classifyAccount(account),
|
|
4265
|
+
address: resolveAddress(account),
|
|
4266
|
+
attributes: buildAttributes(account)
|
|
4267
|
+
};
|
|
4268
|
+
}
|
|
4269
|
+
var SECTION_ORDER = [
|
|
4270
|
+
{ kind: "signer", title: "Signers" },
|
|
4271
|
+
{ kind: "watch-only", title: "Watch-only" },
|
|
4272
|
+
{ kind: "pallet", title: "Pallet Sovereigns" },
|
|
4273
|
+
{ kind: "parachain", title: "Parachain Sovereigns" }
|
|
4274
|
+
];
|
|
4275
|
+
function printAccountSection(title, rows) {
|
|
4276
|
+
if (rows.length === 0)
|
|
4277
|
+
return;
|
|
4278
|
+
const nameWidth = Math.max(...rows.map((r) => r.name.length));
|
|
4279
|
+
printHeading(title);
|
|
4280
|
+
for (const row of rows) {
|
|
4281
|
+
const namePad = row.name.padEnd(nameWidth);
|
|
4282
|
+
console.log(` ${CYAN}${namePad}${RESET} ${row.address}`);
|
|
4283
|
+
if (row.attributes.length === 0)
|
|
4284
|
+
continue;
|
|
4285
|
+
const labelWidth = Math.max(...row.attributes.map((a) => a.label.length)) + 1;
|
|
4286
|
+
for (let i = 0;i < row.attributes.length; i++) {
|
|
4287
|
+
const isLast = i === row.attributes.length - 1;
|
|
4288
|
+
const connector = isLast ? "└─" : "├─";
|
|
4289
|
+
const labelText = `${row.attributes[i].label}:`.padEnd(labelWidth + 1);
|
|
4290
|
+
console.log(` ${DIM}${connector}${RESET} ${DIM}${labelText}${RESET}${row.attributes[i].value}`);
|
|
4291
|
+
}
|
|
4292
|
+
}
|
|
4293
|
+
}
|
|
3318
4294
|
async function accountList(opts = {}) {
|
|
3319
4295
|
const accountsFile = await loadAccounts();
|
|
3320
4296
|
if (isJsonOutput(opts)) {
|
|
3321
4297
|
const dev = DEV_NAMES.map((name) => ({
|
|
3322
4298
|
name: name.charAt(0).toUpperCase() + name.slice(1),
|
|
3323
|
-
address: getDevAddress(name)
|
|
4299
|
+
address: getDevAddress(name),
|
|
4300
|
+
kind: "dev"
|
|
3324
4301
|
}));
|
|
3325
4302
|
const stored = accountsFile.accounts.map((account) => {
|
|
3326
|
-
|
|
3327
|
-
|
|
3328
|
-
address = account.publicKey ? toSs58(account.publicKey) : undefined;
|
|
3329
|
-
} else if (account.secret !== undefined && isEnvSecret(account.secret)) {
|
|
3330
|
-
let pubKey = account.publicKey;
|
|
3331
|
-
if (!pubKey) {
|
|
3332
|
-
pubKey = tryDerivePublicKey(account.secret.env, account.derivationPath) ?? "";
|
|
3333
|
-
}
|
|
3334
|
-
address = pubKey ? toSs58(pubKey) : undefined;
|
|
3335
|
-
} else {
|
|
3336
|
-
address = toSs58(account.publicKey);
|
|
3337
|
-
}
|
|
3338
|
-
return {
|
|
4303
|
+
const kind = classifyAccount(account);
|
|
4304
|
+
const entry = {
|
|
3339
4305
|
name: account.name,
|
|
3340
|
-
address,
|
|
3341
|
-
|
|
3342
|
-
watchOnly: isWatchOnly(account)
|
|
3343
|
-
env: account.secret !== undefined && isEnvSecret(account.secret) ? account.secret.env : undefined
|
|
4306
|
+
address: resolveAddress(account),
|
|
4307
|
+
kind,
|
|
4308
|
+
watchOnly: isWatchOnly(account)
|
|
3344
4309
|
};
|
|
4310
|
+
if (account.derivationPath)
|
|
4311
|
+
entry.derivationPath = account.derivationPath;
|
|
4312
|
+
if (account.secret !== undefined && isEnvSecret(account.secret)) {
|
|
4313
|
+
entry.env = account.secret.env;
|
|
4314
|
+
}
|
|
4315
|
+
if (account.source) {
|
|
4316
|
+
if (account.source.kind === "pallet") {
|
|
4317
|
+
const bytes = parsePalletId(account.source.palletId);
|
|
4318
|
+
entry.source = {
|
|
4319
|
+
kind: "pallet",
|
|
4320
|
+
palletId: formatPalletId(bytes),
|
|
4321
|
+
palletIdHex: account.source.palletId
|
|
4322
|
+
};
|
|
4323
|
+
} else {
|
|
4324
|
+
entry.source = account.source;
|
|
4325
|
+
}
|
|
4326
|
+
}
|
|
4327
|
+
return entry;
|
|
3345
4328
|
});
|
|
3346
4329
|
console.log(formatJson({ dev, stored }));
|
|
3347
4330
|
return;
|
|
3348
4331
|
}
|
|
3349
|
-
|
|
3350
|
-
|
|
3351
|
-
|
|
3352
|
-
|
|
3353
|
-
|
|
4332
|
+
const devRows = DEV_NAMES.map((name) => ({
|
|
4333
|
+
name: name.charAt(0).toUpperCase() + name.slice(1),
|
|
4334
|
+
address: getDevAddress(name),
|
|
4335
|
+
attributes: []
|
|
4336
|
+
}));
|
|
4337
|
+
printAccountSection("Dev Accounts", devRows);
|
|
4338
|
+
const buckets = new Map;
|
|
4339
|
+
for (const account of accountsFile.accounts) {
|
|
4340
|
+
const row = buildRow(account);
|
|
4341
|
+
const arr = buckets.get(row.kind) ?? [];
|
|
4342
|
+
arr.push(row);
|
|
4343
|
+
buckets.set(row.kind, arr);
|
|
4344
|
+
}
|
|
4345
|
+
for (const { kind, title } of SECTION_ORDER) {
|
|
4346
|
+
const rows = buckets.get(kind);
|
|
4347
|
+
if (!rows || rows.length === 0)
|
|
4348
|
+
continue;
|
|
4349
|
+
printAccountSection(title, rows.map((r) => ({
|
|
4350
|
+
name: r.account.name,
|
|
4351
|
+
address: r.address,
|
|
4352
|
+
attributes: r.attributes
|
|
4353
|
+
})));
|
|
3354
4354
|
}
|
|
3355
|
-
if (accountsFile.accounts.length
|
|
3356
|
-
printHeading("Stored Accounts");
|
|
3357
|
-
for (const account of accountsFile.accounts) {
|
|
3358
|
-
let displayName = account.name;
|
|
3359
|
-
if (account.derivationPath) {
|
|
3360
|
-
displayName += ` (${account.derivationPath})`;
|
|
3361
|
-
}
|
|
3362
|
-
let address;
|
|
3363
|
-
if (isWatchOnly(account)) {
|
|
3364
|
-
displayName += " (watch-only)";
|
|
3365
|
-
address = account.publicKey ? toSs58(account.publicKey) : "n/a";
|
|
3366
|
-
} else if (account.secret !== undefined && isEnvSecret(account.secret)) {
|
|
3367
|
-
displayName += ` (env: ${account.secret.env})`;
|
|
3368
|
-
let pubKey = account.publicKey;
|
|
3369
|
-
if (!pubKey) {
|
|
3370
|
-
pubKey = tryDerivePublicKey(account.secret.env, account.derivationPath) ?? "";
|
|
3371
|
-
}
|
|
3372
|
-
address = pubKey ? toSs58(pubKey) : "n/a";
|
|
3373
|
-
} else {
|
|
3374
|
-
address = toSs58(account.publicKey);
|
|
3375
|
-
}
|
|
3376
|
-
printItem(displayName, address);
|
|
3377
|
-
}
|
|
3378
|
-
} else {
|
|
4355
|
+
if (accountsFile.accounts.length === 0) {
|
|
3379
4356
|
printHeading("Stored Accounts");
|
|
3380
|
-
console.log(
|
|
4357
|
+
console.log(` ${DIM}(none)${RESET}`);
|
|
3381
4358
|
}
|
|
3382
4359
|
console.log();
|
|
3383
4360
|
}
|
|
@@ -3425,10 +4402,20 @@ async function accountRemove(names, opts = {}) {
|
|
|
3425
4402
|
}
|
|
3426
4403
|
}
|
|
3427
4404
|
async function accountInspect(input, opts) {
|
|
3428
|
-
|
|
4405
|
+
const sovereignSource = resolveSovereignSource({
|
|
4406
|
+
parachain: opts.parachain,
|
|
4407
|
+
parachainType: opts.parachainType,
|
|
4408
|
+
palletId: opts.palletId
|
|
4409
|
+
});
|
|
4410
|
+
if (sovereignSource && input) {
|
|
4411
|
+
throw new Error("Cannot combine a positional input with --parachain or --pallet-id. Pass either an existing-account input OR a derivation flag, not both.");
|
|
4412
|
+
}
|
|
4413
|
+
if (!sovereignSource && !input) {
|
|
3429
4414
|
console.error(`Input is required.
|
|
3430
4415
|
`);
|
|
3431
4416
|
console.error("Usage: dot account inspect <name|ss58-address|0x-public-key> [--prefix <N>]");
|
|
4417
|
+
console.error(" dot account inspect --pallet-id <id> [--prefix <N>]");
|
|
4418
|
+
console.error(" dot account inspect --parachain <id> --parachain-type <child|sibling> [--prefix <N>]");
|
|
3432
4419
|
process.exit(1);
|
|
3433
4420
|
}
|
|
3434
4421
|
const prefix = opts.prefix != null ? Number(opts.prefix) : 42;
|
|
@@ -3440,11 +4427,33 @@ async function accountInspect(input, opts) {
|
|
|
3440
4427
|
let publicKeyHex;
|
|
3441
4428
|
let bandersnatch;
|
|
3442
4429
|
let hasSecret = false;
|
|
3443
|
-
|
|
4430
|
+
let storedAccount;
|
|
4431
|
+
let isDev = false;
|
|
4432
|
+
let isH160Fallback = false;
|
|
4433
|
+
let virtualSource;
|
|
4434
|
+
if (sovereignSource) {
|
|
4435
|
+
if (sovereignSource.kind === "pallet") {
|
|
4436
|
+
const accountId = derivePalletAccount(sovereignSource.palletId);
|
|
4437
|
+
publicKeyHex = publicKeyToHex(accountId);
|
|
4438
|
+
virtualSource = {
|
|
4439
|
+
kind: "pallet",
|
|
4440
|
+
palletIdHex: `0x${Array.from(sovereignSource.palletId, (b) => b.toString(16).padStart(2, "0")).join("")}`
|
|
4441
|
+
};
|
|
4442
|
+
} else {
|
|
4443
|
+
const accountId = deriveSovereignAccount(sovereignSource.paraId, sovereignSource.type);
|
|
4444
|
+
publicKeyHex = publicKeyToHex(accountId);
|
|
4445
|
+
virtualSource = {
|
|
4446
|
+
kind: "parachain",
|
|
4447
|
+
paraId: sovereignSource.paraId,
|
|
4448
|
+
type: sovereignSource.type
|
|
4449
|
+
};
|
|
4450
|
+
}
|
|
4451
|
+
} else if (isDevAccount(input)) {
|
|
3444
4452
|
name = input.charAt(0).toUpperCase() + input.slice(1).toLowerCase();
|
|
3445
4453
|
const devAddr = getDevAddress(input);
|
|
3446
4454
|
publicKeyHex = publicKeyToHex(fromSs58(devAddr));
|
|
3447
4455
|
hasSecret = true;
|
|
4456
|
+
isDev = true;
|
|
3448
4457
|
} else {
|
|
3449
4458
|
const accountsFile = await loadAccounts();
|
|
3450
4459
|
const account = findAccount(accountsFile, input);
|
|
@@ -3452,6 +4461,7 @@ async function accountInspect(input, opts) {
|
|
|
3452
4461
|
name = account.name;
|
|
3453
4462
|
bandersnatch = account.bandersnatch;
|
|
3454
4463
|
hasSecret = account.secret !== undefined;
|
|
4464
|
+
storedAccount = account;
|
|
3455
4465
|
if (account.publicKey) {
|
|
3456
4466
|
publicKeyHex = account.publicKey;
|
|
3457
4467
|
} else if (account.secret !== undefined && isEnvSecret(account.secret)) {
|
|
@@ -3467,17 +4477,22 @@ async function accountInspect(input, opts) {
|
|
|
3467
4477
|
}
|
|
3468
4478
|
} else if (isHexPublicKey(input)) {
|
|
3469
4479
|
publicKeyHex = input;
|
|
4480
|
+
} else if (isH160Hex(input)) {
|
|
4481
|
+
const fallback = h160ToFallbackAccountId(h160FromHex(input));
|
|
4482
|
+
publicKeyHex = publicKeyToHex(fallback);
|
|
4483
|
+
isH160Fallback = true;
|
|
3470
4484
|
} else {
|
|
3471
4485
|
try {
|
|
3472
4486
|
const decoded = fromSs58(input);
|
|
3473
4487
|
publicKeyHex = publicKeyToHex(decoded);
|
|
3474
4488
|
} catch {
|
|
3475
|
-
console.error(`Cannot identify "${input}" as an account name, SS58 address,
|
|
4489
|
+
console.error(`Cannot identify "${input}" as an account name, SS58 address, hex public key, or H160.`);
|
|
3476
4490
|
process.exit(1);
|
|
3477
4491
|
}
|
|
3478
4492
|
}
|
|
3479
4493
|
}
|
|
3480
4494
|
const ss58 = toSs58(publicKeyHex, prefix);
|
|
4495
|
+
const h160Hex = toEip55(accountIdToH160(nobleHexToBytes(publicKeyHex.slice(2))));
|
|
3481
4496
|
let privateKeyHex;
|
|
3482
4497
|
if (opts.showSecret) {
|
|
3483
4498
|
if (!name) {
|
|
@@ -3495,10 +4510,81 @@ async function accountInspect(input, opts) {
|
|
|
3495
4510
|
process.exit(1);
|
|
3496
4511
|
}
|
|
3497
4512
|
}
|
|
4513
|
+
let kindLabel;
|
|
4514
|
+
let sourceLine;
|
|
4515
|
+
let derivationLine;
|
|
4516
|
+
let envLine;
|
|
4517
|
+
if (virtualSource?.kind === "pallet") {
|
|
4518
|
+
kindLabel = "pallet sovereign";
|
|
4519
|
+
const bytes = parsePalletId(virtualSource.palletIdHex);
|
|
4520
|
+
sourceLine = `PalletId ${formatPalletId(bytes)} (${virtualSource.palletIdHex})`;
|
|
4521
|
+
} else if (virtualSource?.kind === "parachain") {
|
|
4522
|
+
kindLabel = `parachain sovereign (${virtualSource.type})`;
|
|
4523
|
+
sourceLine = `parachain ${virtualSource.paraId}`;
|
|
4524
|
+
} else if (isDev) {
|
|
4525
|
+
kindLabel = "dev";
|
|
4526
|
+
} else if (isH160Fallback) {
|
|
4527
|
+
kindLabel = "revive H160 fallback";
|
|
4528
|
+
} else if (storedAccount) {
|
|
4529
|
+
const k = classifyAccount(storedAccount);
|
|
4530
|
+
if (k === "pallet" && storedAccount.source?.kind === "pallet") {
|
|
4531
|
+
kindLabel = "pallet sovereign";
|
|
4532
|
+
const bytes = parsePalletId(storedAccount.source.palletId);
|
|
4533
|
+
sourceLine = `PalletId ${formatPalletId(bytes)} (${storedAccount.source.palletId})`;
|
|
4534
|
+
} else if (k === "parachain" && storedAccount.source?.kind === "parachain") {
|
|
4535
|
+
kindLabel = `parachain sovereign (${storedAccount.source.type})`;
|
|
4536
|
+
sourceLine = `parachain ${storedAccount.source.paraId}`;
|
|
4537
|
+
} else if (k === "signer") {
|
|
4538
|
+
kindLabel = "signer";
|
|
4539
|
+
} else {
|
|
4540
|
+
kindLabel = "watch-only";
|
|
4541
|
+
}
|
|
4542
|
+
if (storedAccount.derivationPath)
|
|
4543
|
+
derivationLine = storedAccount.derivationPath;
|
|
4544
|
+
if (storedAccount.secret !== undefined && isEnvSecret(storedAccount.secret)) {
|
|
4545
|
+
envLine = `$${storedAccount.secret.env}`;
|
|
4546
|
+
}
|
|
4547
|
+
}
|
|
3498
4548
|
if (isJsonOutput(opts)) {
|
|
3499
|
-
const result = {
|
|
4549
|
+
const result = {
|
|
4550
|
+
publicKey: publicKeyHex,
|
|
4551
|
+
ss58,
|
|
4552
|
+
h160: h160Hex,
|
|
4553
|
+
prefix
|
|
4554
|
+
};
|
|
3500
4555
|
if (name)
|
|
3501
4556
|
result.name = name;
|
|
4557
|
+
if (kindLabel)
|
|
4558
|
+
result.kind = kindLabel;
|
|
4559
|
+
if (virtualSource?.kind === "pallet") {
|
|
4560
|
+
const bytes = parsePalletId(virtualSource.palletIdHex);
|
|
4561
|
+
result.source = {
|
|
4562
|
+
kind: "pallet",
|
|
4563
|
+
palletId: formatPalletId(bytes),
|
|
4564
|
+
palletIdHex: virtualSource.palletIdHex
|
|
4565
|
+
};
|
|
4566
|
+
} else if (virtualSource?.kind === "parachain") {
|
|
4567
|
+
result.source = {
|
|
4568
|
+
kind: "parachain",
|
|
4569
|
+
paraId: virtualSource.paraId,
|
|
4570
|
+
type: virtualSource.type
|
|
4571
|
+
};
|
|
4572
|
+
} else if (storedAccount?.source) {
|
|
4573
|
+
if (storedAccount.source.kind === "pallet") {
|
|
4574
|
+
const bytes = parsePalletId(storedAccount.source.palletId);
|
|
4575
|
+
result.source = {
|
|
4576
|
+
kind: "pallet",
|
|
4577
|
+
palletId: formatPalletId(bytes),
|
|
4578
|
+
palletIdHex: storedAccount.source.palletId
|
|
4579
|
+
};
|
|
4580
|
+
} else {
|
|
4581
|
+
result.source = storedAccount.source;
|
|
4582
|
+
}
|
|
4583
|
+
}
|
|
4584
|
+
if (derivationLine)
|
|
4585
|
+
result.derivationPath = derivationLine;
|
|
4586
|
+
if (envLine)
|
|
4587
|
+
result.env = envLine.replace(/^\$/, "");
|
|
3502
4588
|
if (bandersnatch && Object.keys(bandersnatch).length > 0)
|
|
3503
4589
|
result.bandersnatch = bandersnatch;
|
|
3504
4590
|
if (privateKeyHex)
|
|
@@ -3508,8 +4594,17 @@ async function accountInspect(input, opts) {
|
|
|
3508
4594
|
printHeading("Account Info");
|
|
3509
4595
|
if (name)
|
|
3510
4596
|
console.log(` ${BOLD}Name:${RESET} ${name}`);
|
|
4597
|
+
if (kindLabel)
|
|
4598
|
+
console.log(` ${BOLD}Kind:${RESET} ${kindLabel}`);
|
|
3511
4599
|
console.log(` ${BOLD}Public Key:${RESET} ${publicKeyHex}`);
|
|
3512
4600
|
console.log(` ${BOLD}SS58:${RESET} ${ss58}`);
|
|
4601
|
+
console.log(` ${BOLD}H160:${RESET} ${h160Hex}`);
|
|
4602
|
+
if (sourceLine)
|
|
4603
|
+
console.log(` ${BOLD}Source:${RESET} ${sourceLine}`);
|
|
4604
|
+
if (derivationLine)
|
|
4605
|
+
console.log(` ${BOLD}Derivation:${RESET} ${derivationLine}`);
|
|
4606
|
+
if (envLine)
|
|
4607
|
+
console.log(` ${BOLD}Env:${RESET} ${envLine}`);
|
|
3513
4608
|
if (bandersnatch && Object.keys(bandersnatch).length > 0) {
|
|
3514
4609
|
const entries = Object.entries(bandersnatch);
|
|
3515
4610
|
for (let i = 0;i < entries.length; i++) {
|
|
@@ -3777,8 +4872,10 @@ async function handleApis2(target, args, opts) {
|
|
|
3777
4872
|
typeof opts.parsedArgs === "object" ? JSON.stringify(opts.parsedArgs) : String(opts.parsedArgs)
|
|
3778
4873
|
];
|
|
3779
4874
|
const parsedArgs = await parseRuntimeApiArgs2(meta, method, effectiveArgs);
|
|
4875
|
+
const atArg = parseAtForRead(opts.at);
|
|
4876
|
+
const pullOpts = atArg !== undefined ? [{ at: atArg }] : [];
|
|
3780
4877
|
const unsafeApi = clientHandle.client.getUnsafeApi();
|
|
3781
|
-
const result = await unsafeApi.apis[api.name][method.name](...parsedArgs);
|
|
4878
|
+
const result = await withBlockAvailabilityHint(opts.at, () => unsafeApi.apis[api.name][method.name](...parsedArgs, ...pullOpts));
|
|
3782
4879
|
const format = isJsonOutput(opts) ? "json" : opts.output ?? "pretty";
|
|
3783
4880
|
printResult(result, format);
|
|
3784
4881
|
} finally {
|
|
@@ -3813,6 +4910,53 @@ init_client();
|
|
|
3813
4910
|
init_metadata();
|
|
3814
4911
|
init_output();
|
|
3815
4912
|
import { readFile as readFile4, writeFile as writeFile4 } from "node:fs/promises";
|
|
4913
|
+
|
|
4914
|
+
// src/core/rpc.ts
|
|
4915
|
+
init_errors();
|
|
4916
|
+
import { createClient as createSubstrateClient } from "@polkadot-api/substrate-client";
|
|
4917
|
+
import { getWsProvider as getWsProvider2 } from "polkadot-api/ws";
|
|
4918
|
+
function suppressProviderNoise2() {
|
|
4919
|
+
const origError = console.error;
|
|
4920
|
+
console.error = (...args) => {
|
|
4921
|
+
if (typeof args[0] === "string" && args[0].includes("Unable to connect"))
|
|
4922
|
+
return;
|
|
4923
|
+
origError(...args);
|
|
4924
|
+
};
|
|
4925
|
+
return () => {
|
|
4926
|
+
console.error = origError;
|
|
4927
|
+
};
|
|
4928
|
+
}
|
|
4929
|
+
async function rpcRequest(rpcUrl, method, params, timeoutMs = 30000) {
|
|
4930
|
+
const restoreConsole = suppressProviderNoise2();
|
|
4931
|
+
const provider = getWsProvider2(rpcUrl, { timeout: 1e4 });
|
|
4932
|
+
const client = createSubstrateClient(provider);
|
|
4933
|
+
const controller = new AbortController;
|
|
4934
|
+
const timer = setTimeout(() => controller.abort(), timeoutMs);
|
|
4935
|
+
try {
|
|
4936
|
+
return await client.request(method, params, controller.signal);
|
|
4937
|
+
} catch (err) {
|
|
4938
|
+
if (err instanceof Error && /Unable to connect/i.test(err.message)) {
|
|
4939
|
+
throw new ConnectionError(`Could not reach RPC ${Array.isArray(rpcUrl) ? rpcUrl.join(", ") : rpcUrl}: ${err.message}`);
|
|
4940
|
+
}
|
|
4941
|
+
throw err;
|
|
4942
|
+
} finally {
|
|
4943
|
+
clearTimeout(timer);
|
|
4944
|
+
try {
|
|
4945
|
+
client.destroy();
|
|
4946
|
+
} catch {}
|
|
4947
|
+
setTimeout(restoreConsole, 100);
|
|
4948
|
+
}
|
|
4949
|
+
}
|
|
4950
|
+
async function fetchRpcMethods(rpcUrl) {
|
|
4951
|
+
const result = await rpcRequest(rpcUrl, "rpc_methods", []);
|
|
4952
|
+
if (!result || !Array.isArray(result.methods)) {
|
|
4953
|
+
throw new ConnectionError("Node returned an unexpected response for rpc_methods (no methods array).");
|
|
4954
|
+
}
|
|
4955
|
+
return { methods: result.methods, version: result.version ?? 1 };
|
|
4956
|
+
}
|
|
4957
|
+
|
|
4958
|
+
// src/commands/chain.ts
|
|
4959
|
+
init_rpc_registry();
|
|
3816
4960
|
var CHAIN_HELP = `
|
|
3817
4961
|
${BOLD}Usage:${RESET}
|
|
3818
4962
|
$ dot chain add <name> --rpc <url> Add a chain via WebSocket RPC
|
|
@@ -3881,6 +5025,18 @@ function registerChainCommands(cli) {
|
|
|
3881
5025
|
}
|
|
3882
5026
|
});
|
|
3883
5027
|
}
|
|
5028
|
+
async function refreshRpcMethods(chainName, rpcUrl, silent = false) {
|
|
5029
|
+
try {
|
|
5030
|
+
const { methods, version: version2 } = await fetchRpcMethods(rpcUrl);
|
|
5031
|
+
await saveRpcMethods(chainName, methods, version2);
|
|
5032
|
+
} catch (err) {
|
|
5033
|
+
if (!silent) {
|
|
5034
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
5035
|
+
process.stderr.write(`${YELLOW}Warning:${RESET} could not fetch rpc_methods — ${msg}
|
|
5036
|
+
`);
|
|
5037
|
+
}
|
|
5038
|
+
}
|
|
5039
|
+
}
|
|
3884
5040
|
async function chainAdd(name, opts) {
|
|
3885
5041
|
if (!name) {
|
|
3886
5042
|
console.error(`Chain name is required.
|
|
@@ -3909,6 +5065,7 @@ async function chainAdd(name, opts) {
|
|
|
3909
5065
|
process.stderr.write(`Fetching metadata...
|
|
3910
5066
|
`);
|
|
3911
5067
|
await fetchMetadataFromChain(clientHandle, name);
|
|
5068
|
+
await refreshRpcMethods(name, opts.rpc);
|
|
3912
5069
|
if (opts.relay) {
|
|
3913
5070
|
const config2 = await loadConfig();
|
|
3914
5071
|
const relayResolved = findChainName(config2, opts.relay);
|
|
@@ -4049,6 +5206,12 @@ async function chainInfo(name, opts = {}) {
|
|
|
4049
5206
|
const rpcs = Array.isArray(chain.rpc) ? chain.rpc : [chain.rpc];
|
|
4050
5207
|
const parachains = Object.entries(config.chains).filter(([, c]) => c.relay === resolved).map(([n, c]) => ({ name: n, parachainId: c.parachainId }));
|
|
4051
5208
|
const fingerprint = await loadMetadataFingerprint(resolved);
|
|
5209
|
+
const rpcCache = await loadRpcMethods(resolved);
|
|
5210
|
+
const rpcSummary = rpcCache ? {
|
|
5211
|
+
count: rpcCache.methods.length,
|
|
5212
|
+
fetchedAt: rpcCache.fetchedAt,
|
|
5213
|
+
byFamily: countByFamily(rpcCache.methods)
|
|
5214
|
+
} : null;
|
|
4052
5215
|
if (isJsonOutput(opts)) {
|
|
4053
5216
|
console.log(formatJson({
|
|
4054
5217
|
name: resolved,
|
|
@@ -4060,7 +5223,8 @@ async function chainInfo(name, opts = {}) {
|
|
|
4060
5223
|
specName: fingerprint.specName,
|
|
4061
5224
|
specVersion: fingerprint.specVersion,
|
|
4062
5225
|
fetchedAt: fingerprint.fetchedAt
|
|
4063
|
-
} : null
|
|
5226
|
+
} : null,
|
|
5227
|
+
rpcMethods: rpcSummary
|
|
4064
5228
|
}));
|
|
4065
5229
|
return;
|
|
4066
5230
|
}
|
|
@@ -4088,6 +5252,22 @@ async function chainInfo(name, opts = {}) {
|
|
|
4088
5252
|
} else {
|
|
4089
5253
|
console.log(` ${DIM}not cached — run \`dot chain update ${resolved}\`${RESET}`);
|
|
4090
5254
|
}
|
|
5255
|
+
console.log(` ${CYAN}rpc methods:${RESET}`);
|
|
5256
|
+
if (rpcSummary) {
|
|
5257
|
+
const families = Object.entries(rpcSummary.byFamily).map(([f, n]) => `${f}: ${n}`).join(", ");
|
|
5258
|
+
console.log(` ${rpcSummary.count} ${DIM}(${families})${RESET}`);
|
|
5259
|
+
console.log(` ${DIM}cached ${rpcSummary.fetchedAt}${RESET}`);
|
|
5260
|
+
} else {
|
|
5261
|
+
console.log(` ${DIM}not cached — run \`dot chain update ${resolved}\`${RESET}`);
|
|
5262
|
+
}
|
|
5263
|
+
}
|
|
5264
|
+
function countByFamily(methods) {
|
|
5265
|
+
const counts = {};
|
|
5266
|
+
for (const m of methods) {
|
|
5267
|
+
const family = RPC_REGISTRY[m]?.family ?? inferFamily(m);
|
|
5268
|
+
counts[family] = (counts[family] ?? 0) + 1;
|
|
5269
|
+
}
|
|
5270
|
+
return counts;
|
|
4091
5271
|
}
|
|
4092
5272
|
async function chainUpdate(name, opts) {
|
|
4093
5273
|
const config = await loadConfig();
|
|
@@ -4107,6 +5287,7 @@ async function chainUpdate(name, opts) {
|
|
|
4107
5287
|
process.stderr.write(`Fetching metadata...
|
|
4108
5288
|
`);
|
|
4109
5289
|
await fetchMetadataFromChain(clientHandle, chainName);
|
|
5290
|
+
await refreshRpcMethods(chainName, opts.rpc ?? chainConfig.rpc);
|
|
4110
5291
|
if (isJsonOutput(opts)) {
|
|
4111
5292
|
console.log(formatJson({ action: "updated", chain: chainName }));
|
|
4112
5293
|
} else {
|
|
@@ -4136,6 +5317,7 @@ async function updateChainsMetadata(config, chainNames) {
|
|
|
4136
5317
|
const clientHandle = await createChainClient(chainName, chainConfig);
|
|
4137
5318
|
try {
|
|
4138
5319
|
await fetchMetadataFromChain(clientHandle, chainName);
|
|
5320
|
+
await refreshRpcMethods(chainName, chainConfig.rpc, true);
|
|
4139
5321
|
} finally {
|
|
4140
5322
|
clientHandle.destroy();
|
|
4141
5323
|
}
|
|
@@ -5687,24 +6869,6 @@ function registerMetadataCommand(cli) {
|
|
|
5687
6869
|
// src/commands/parachain.ts
|
|
5688
6870
|
init_accounts();
|
|
5689
6871
|
init_output();
|
|
5690
|
-
|
|
5691
|
-
// src/core/parachain.ts
|
|
5692
|
-
var SOVEREIGN_ACCOUNT_TYPES = ["child", "sibling"];
|
|
5693
|
-
var PREFIXES = {
|
|
5694
|
-
child: new Uint8Array([112, 97, 114, 97]),
|
|
5695
|
-
sibling: new Uint8Array([115, 105, 98, 108])
|
|
5696
|
-
};
|
|
5697
|
-
function deriveSovereignAccount(paraId, type) {
|
|
5698
|
-
const result = new Uint8Array(32);
|
|
5699
|
-
result.set(PREFIXES[type], 0);
|
|
5700
|
-
new DataView(result.buffer).setUint32(4, paraId, true);
|
|
5701
|
-
return result;
|
|
5702
|
-
}
|
|
5703
|
-
function isValidParaId(value) {
|
|
5704
|
-
return Number.isInteger(value) && value >= 0 && value <= 4294967295;
|
|
5705
|
-
}
|
|
5706
|
-
|
|
5707
|
-
// src/commands/parachain.ts
|
|
5708
6872
|
init_errors();
|
|
5709
6873
|
function printParachainHelp() {
|
|
5710
6874
|
console.log(`${BOLD}Usage:${RESET} dot parachain <paraId> [options]
|
|
@@ -5734,6 +6898,7 @@ function validateType(type) {
|
|
|
5734
6898
|
}
|
|
5735
6899
|
function registerParachainCommand(cli) {
|
|
5736
6900
|
cli.command("parachain [paraId]", "Derive parachain sovereign accounts").option("--type <type>", "Account type: child, sibling (default: both)").option("--prefix <number>", "SS58 prefix for address encoding (default: 42)").action(async (paraIdStr, opts) => {
|
|
6901
|
+
console.error("Warning: `dot parachain` is deprecated; use `dot account inspect --parachain <id> --parachain-type <child|sibling>` instead. Will be removed in a future release.");
|
|
5737
6902
|
if (!paraIdStr) {
|
|
5738
6903
|
printParachainHelp();
|
|
5739
6904
|
return;
|
|
@@ -5880,6 +7045,8 @@ async function handleQuery(target, keys, opts) {
|
|
|
5880
7045
|
typeof opts.parsedArgs === "object" ? JSON.stringify(opts.parsedArgs) : String(opts.parsedArgs)
|
|
5881
7046
|
];
|
|
5882
7047
|
const parsedKeys = await parseStorageKeys(meta, palletInfo.name, storageItem, effectiveKeys);
|
|
7048
|
+
const atArg = parseAtForRead(opts.at);
|
|
7049
|
+
const pullOpts = atArg !== undefined ? [{ at: atArg }] : [];
|
|
5883
7050
|
const format = isJsonOutput(opts) ? "json" : opts.output ?? "pretty";
|
|
5884
7051
|
const expectedLen = storageItem.type === "map" && storageItem.keyTypeId != null ? meta.builder.buildStorage(palletInfo.name, storageItem.name).len : 0;
|
|
5885
7052
|
if (storageItem.type === "map" && parsedKeys.length < expectedLen) {
|
|
@@ -5889,7 +7056,7 @@ async function handleQuery(target, keys, opts) {
|
|
|
5889
7056
|
console.log(`${DIM}Hint: use --dump to fetch all entries${RESET}`);
|
|
5890
7057
|
return;
|
|
5891
7058
|
}
|
|
5892
|
-
const entries = await withStalenessSuggestion(chainName, clientHandle, () => storageApi.getEntries(...parsedKeys));
|
|
7059
|
+
const entries = await withStalenessSuggestion(chainName, clientHandle, () => withBlockAvailabilityHint(opts.at, () => storageApi.getEntries(...parsedKeys, ...pullOpts)));
|
|
5893
7060
|
const rows = entries.map((e) => ({
|
|
5894
7061
|
keys: e.keyArgs,
|
|
5895
7062
|
value: e.value
|
|
@@ -5898,7 +7065,7 @@ async function handleQuery(target, keys, opts) {
|
|
|
5898
7065
|
await writeStdout(`${text}
|
|
5899
7066
|
`);
|
|
5900
7067
|
} else {
|
|
5901
|
-
const result = await withStalenessSuggestion(chainName, clientHandle, () => storageApi.getValue(...parsedKeys));
|
|
7068
|
+
const result = await withStalenessSuggestion(chainName, clientHandle, () => withBlockAvailabilityHint(opts.at, () => storageApi.getValue(...parsedKeys, ...pullOpts)));
|
|
5902
7069
|
const text = format === "json" ? formatJson(result) : formatPretty(result);
|
|
5903
7070
|
await writeStdout(`${text}
|
|
5904
7071
|
`);
|
|
@@ -5947,6 +7114,168 @@ async function parseStorageKeys(meta, palletName2, storageItem, args) {
|
|
|
5947
7114
|
return Promise.all(args.map((arg) => parseTypedArg(meta, keyEntry, arg)));
|
|
5948
7115
|
}
|
|
5949
7116
|
|
|
7117
|
+
// src/commands/rpc.ts
|
|
7118
|
+
init_store();
|
|
7119
|
+
init_output();
|
|
7120
|
+
init_rpc_registry();
|
|
7121
|
+
init_errors();
|
|
7122
|
+
var FAMILY_ORDER = [
|
|
7123
|
+
"system",
|
|
7124
|
+
"chain",
|
|
7125
|
+
"state",
|
|
7126
|
+
"author",
|
|
7127
|
+
"payment",
|
|
7128
|
+
"babe",
|
|
7129
|
+
"grandpa",
|
|
7130
|
+
"beefy",
|
|
7131
|
+
"mmr",
|
|
7132
|
+
"offchain",
|
|
7133
|
+
"dev",
|
|
7134
|
+
"spec",
|
|
7135
|
+
"chainHead",
|
|
7136
|
+
"chainSpec",
|
|
7137
|
+
"transaction",
|
|
7138
|
+
"archive",
|
|
7139
|
+
"other"
|
|
7140
|
+
];
|
|
7141
|
+
async function getMethodList(chainName, rpcUrl, refresh) {
|
|
7142
|
+
if (!refresh) {
|
|
7143
|
+
const cached = await loadRpcMethods(chainName);
|
|
7144
|
+
if (cached) {
|
|
7145
|
+
return { methods: cached.methods, version: cached.version, fromCache: true };
|
|
7146
|
+
}
|
|
7147
|
+
}
|
|
7148
|
+
const fresh = await fetchRpcMethods(rpcUrl);
|
|
7149
|
+
await saveRpcMethods(chainName, fresh.methods, fresh.version);
|
|
7150
|
+
return { methods: fresh.methods, version: fresh.version, fromCache: false };
|
|
7151
|
+
}
|
|
7152
|
+
function groupByFamily(methods) {
|
|
7153
|
+
const groups = new Map;
|
|
7154
|
+
for (const m of methods) {
|
|
7155
|
+
const family = RPC_REGISTRY[m]?.family ?? inferFamily(m);
|
|
7156
|
+
const list = groups.get(family) ?? [];
|
|
7157
|
+
list.push(m);
|
|
7158
|
+
groups.set(family, list);
|
|
7159
|
+
}
|
|
7160
|
+
for (const list of groups.values())
|
|
7161
|
+
list.sort();
|
|
7162
|
+
return groups;
|
|
7163
|
+
}
|
|
7164
|
+
function formatArgs(info) {
|
|
7165
|
+
if (info.args.length === 0)
|
|
7166
|
+
return "(no args)";
|
|
7167
|
+
return info.args.map((a) => `<${a.name}: ${a.type}${a.optional ? "?" : ""}>`).join(" ");
|
|
7168
|
+
}
|
|
7169
|
+
function printMethodHelp(method, info) {
|
|
7170
|
+
console.log();
|
|
7171
|
+
console.log(`${BOLD}${method}${RESET}`);
|
|
7172
|
+
if (info) {
|
|
7173
|
+
if (info.dangerous) {
|
|
7174
|
+
console.log(` ${YELLOW}⚠️ WRITE / state-changing${RESET}`);
|
|
7175
|
+
}
|
|
7176
|
+
if (info.subscription) {
|
|
7177
|
+
console.log(` ${DIM}subscription — not callable as a one-shot${RESET}`);
|
|
7178
|
+
}
|
|
7179
|
+
console.log(` ${info.description}`);
|
|
7180
|
+
console.log();
|
|
7181
|
+
console.log(` ${DIM}Family:${RESET} ${info.family}`);
|
|
7182
|
+
console.log(` ${DIM}Args:${RESET} ${formatArgs(info)}`);
|
|
7183
|
+
if (info.args.some((a) => a.description)) {
|
|
7184
|
+
console.log();
|
|
7185
|
+
for (const a of info.args) {
|
|
7186
|
+
if (a.description) {
|
|
7187
|
+
console.log(` ${CYAN}${a.name}${RESET} ${DIM}${a.description}${RESET}`);
|
|
7188
|
+
}
|
|
7189
|
+
}
|
|
7190
|
+
}
|
|
7191
|
+
} else {
|
|
7192
|
+
console.log(` ${DIM}No curated metadata. Args are passed through as raw JSON-RPC params.${RESET}`);
|
|
7193
|
+
console.log(` ${DIM}Family:${RESET} ${inferFamily(method)} (inferred)`);
|
|
7194
|
+
}
|
|
7195
|
+
console.log();
|
|
7196
|
+
}
|
|
7197
|
+
async function listMethods(chainName, rpcUrl, opts) {
|
|
7198
|
+
const { methods, version: version2, fromCache } = await getMethodList(chainName, rpcUrl, opts.refresh ?? false);
|
|
7199
|
+
if (isJsonOutput(opts)) {
|
|
7200
|
+
console.log(formatJson({
|
|
7201
|
+
chain: chainName,
|
|
7202
|
+
version: version2,
|
|
7203
|
+
fromCache,
|
|
7204
|
+
methods: methods.map((m) => {
|
|
7205
|
+
const info = RPC_REGISTRY[m];
|
|
7206
|
+
return {
|
|
7207
|
+
method: m,
|
|
7208
|
+
family: info?.family ?? inferFamily(m),
|
|
7209
|
+
description: info?.description,
|
|
7210
|
+
dangerous: info?.dangerous ?? false,
|
|
7211
|
+
subscription: info?.subscription ?? false
|
|
7212
|
+
};
|
|
7213
|
+
})
|
|
7214
|
+
}));
|
|
7215
|
+
return;
|
|
7216
|
+
}
|
|
7217
|
+
printHeading(`RPC methods on ${chainName} (${methods.length})`);
|
|
7218
|
+
const groups = groupByFamily(methods);
|
|
7219
|
+
for (const family of FAMILY_ORDER) {
|
|
7220
|
+
const list = groups.get(family);
|
|
7221
|
+
if (!list || list.length === 0)
|
|
7222
|
+
continue;
|
|
7223
|
+
console.log(`${BOLD}${family}${RESET} ${DIM}(${list.length})${RESET}`);
|
|
7224
|
+
for (const m of list) {
|
|
7225
|
+
const info = RPC_REGISTRY[m];
|
|
7226
|
+
const tags = [];
|
|
7227
|
+
if (info?.dangerous)
|
|
7228
|
+
tags.push(`${YELLOW}⚠ write${RESET}`);
|
|
7229
|
+
if (info?.subscription)
|
|
7230
|
+
tags.push(`${DIM}sub${RESET}`);
|
|
7231
|
+
const suffix = tags.length > 0 ? ` ${tags.join(" ")}` : "";
|
|
7232
|
+
const desc = info?.description ? ` ${DIM}${info.description}${RESET}` : "";
|
|
7233
|
+
console.log(` ${CYAN}${m}${RESET}${suffix}${desc}`);
|
|
7234
|
+
}
|
|
7235
|
+
console.log();
|
|
7236
|
+
}
|
|
7237
|
+
if (!fromCache) {
|
|
7238
|
+
console.log(`${DIM}(fetched from node — cached for next run)${RESET}`);
|
|
7239
|
+
}
|
|
7240
|
+
}
|
|
7241
|
+
async function handleRpc(method, args, opts) {
|
|
7242
|
+
const config = await loadConfig();
|
|
7243
|
+
const { name: chainName, chain: chainConfig } = resolveChain(config, opts.chain);
|
|
7244
|
+
const rpcUrl = opts.rpc ?? chainConfig.rpc;
|
|
7245
|
+
if (!rpcUrl) {
|
|
7246
|
+
throw new CliError(`No RPC endpoint for chain "${chainName}". Pass --rpc or run \`dot chain add ${chainName} --rpc <url>\`.`);
|
|
7247
|
+
}
|
|
7248
|
+
if (!method) {
|
|
7249
|
+
await listMethods(chainName, rpcUrl, opts);
|
|
7250
|
+
return;
|
|
7251
|
+
}
|
|
7252
|
+
const info = RPC_REGISTRY[method];
|
|
7253
|
+
if (opts.help) {
|
|
7254
|
+
printMethodHelp(method, info);
|
|
7255
|
+
return;
|
|
7256
|
+
}
|
|
7257
|
+
const { methods: knownMethods } = await getMethodList(chainName, rpcUrl, opts.refresh ?? false);
|
|
7258
|
+
if (!knownMethods.includes(method)) {
|
|
7259
|
+
const hint = suggestMessage("method", method, knownMethods);
|
|
7260
|
+
throw new CliError(`Method "${method}" is not exposed by the node for "${chainName}".${hint ? ` ${hint}` : ""} ` + `Run \`dot ${chainName}.rpc --refresh\` if the node has been upgraded.`);
|
|
7261
|
+
}
|
|
7262
|
+
if (info?.subscription) {
|
|
7263
|
+
throw new CliError(`"${method}" is a subscription method (requires a follow session) and is not callable as a one-shot. ` + `Use a long-running client for streaming RPC.`);
|
|
7264
|
+
}
|
|
7265
|
+
if (!info && /(_subscribe|_unsubscribe)/.test(method)) {
|
|
7266
|
+
throw new CliError(`"${method}" looks like a subscription/unsubscription method and isn't supported as a one-shot. ` + `Pass --help to see what we know about it.`);
|
|
7267
|
+
}
|
|
7268
|
+
if (info) {
|
|
7269
|
+
const required = info.args.filter((a) => !a.optional).length;
|
|
7270
|
+
if (args.length < required) {
|
|
7271
|
+
throw new CliError(`"${method}" expects at least ${required} argument(s) (${formatArgs(info)}); got ${args.length}.`);
|
|
7272
|
+
}
|
|
7273
|
+
}
|
|
7274
|
+
const params = args.map(parseValue);
|
|
7275
|
+
const result = await rpcRequest(rpcUrl, method, params);
|
|
7276
|
+
printResult(result, isJsonOutput(opts) ? "json" : opts.output);
|
|
7277
|
+
}
|
|
7278
|
+
|
|
5950
7279
|
// src/commands/sign.ts
|
|
5951
7280
|
init_accounts();
|
|
5952
7281
|
init_hash();
|
|
@@ -6360,7 +7689,7 @@ async function handleTx(target, args, opts) {
|
|
|
6360
7689
|
let estimatedFees;
|
|
6361
7690
|
let estimationError;
|
|
6362
7691
|
try {
|
|
6363
|
-
estimatedFees = String(await withStalenessSuggestion(chainName, clientHandle, () => tx.getEstimatedFees(signer?.publicKey, txOptions)));
|
|
7692
|
+
estimatedFees = String(await withStalenessSuggestion(chainName, clientHandle, () => withBlockAvailabilityHint(opts.at, () => tx.getEstimatedFees(signer?.publicKey, txOptions))));
|
|
6364
7693
|
} catch (err) {
|
|
6365
7694
|
estimationError = err instanceof Error ? err.message : String(err);
|
|
6366
7695
|
}
|
|
@@ -6430,7 +7759,7 @@ async function handleTx(target, args, opts) {
|
|
|
6430
7759
|
}
|
|
6431
7760
|
const observable = clientHandle.client.submitAndWatch(generalTx, at);
|
|
6432
7761
|
if (isJsonOutput(opts)) {
|
|
6433
|
-
const result3 = await withStalenessSuggestion(chainName, clientHandle, () => watchTransactionJson(observable, waitLevel, { unsigned: true }));
|
|
7762
|
+
const result3 = await withStalenessSuggestion(chainName, clientHandle, () => withBlockAvailabilityHint(opts.at, () => watchTransactionJson(observable, waitLevel, { unsigned: true })));
|
|
6434
7763
|
const rpcUrl3 = primaryRpc(opts.rpc ?? chainConfig.rpc);
|
|
6435
7764
|
if (result3.type === "broadcasted") {
|
|
6436
7765
|
printJsonLine({ event: "broadcasted", txHash: result3.txHash });
|
|
@@ -6462,7 +7791,7 @@ async function handleTx(target, args, opts) {
|
|
|
6462
7791
|
}
|
|
6463
7792
|
return;
|
|
6464
7793
|
}
|
|
6465
|
-
const result2 = await withStalenessSuggestion(chainName, clientHandle, () => watchTransaction(observable, waitLevel, { unsigned: true }));
|
|
7794
|
+
const result2 = await withStalenessSuggestion(chainName, clientHandle, () => withBlockAvailabilityHint(opts.at, () => watchTransaction(observable, waitLevel, { unsigned: true })));
|
|
6466
7795
|
console.log();
|
|
6467
7796
|
console.log(` ${BOLD}Chain:${RESET} ${chainName}`);
|
|
6468
7797
|
console.log(` ${BOLD}Type:${RESET} unsigned (bare)`);
|
|
@@ -6511,7 +7840,7 @@ async function handleTx(target, args, opts) {
|
|
|
6511
7840
|
return;
|
|
6512
7841
|
}
|
|
6513
7842
|
if (isJsonOutput(opts)) {
|
|
6514
|
-
const result2 = await withStalenessSuggestion(chainName, clientHandle, () => watchTransactionJson(tx.signSubmitAndWatch(signer, txOptions), waitLevel));
|
|
7843
|
+
const result2 = await withStalenessSuggestion(chainName, clientHandle, () => withBlockAvailabilityHint(opts.at, () => watchTransactionJson(tx.signSubmitAndWatch(signer, txOptions), waitLevel)));
|
|
6515
7844
|
const rpcUrl2 = primaryRpc(opts.rpc ?? chainConfig.rpc);
|
|
6516
7845
|
if (result2.type === "broadcasted") {
|
|
6517
7846
|
printJsonLine({ event: "broadcasted", txHash: result2.txHash });
|
|
@@ -6542,7 +7871,7 @@ async function handleTx(target, args, opts) {
|
|
|
6542
7871
|
}
|
|
6543
7872
|
return;
|
|
6544
7873
|
}
|
|
6545
|
-
const result = await withStalenessSuggestion(chainName, clientHandle, () => watchTransaction(tx.signSubmitAndWatch(signer, txOptions), waitLevel));
|
|
7874
|
+
const result = await withStalenessSuggestion(chainName, clientHandle, () => withBlockAvailabilityHint(opts.at, () => watchTransaction(tx.signSubmitAndWatch(signer, txOptions), waitLevel)));
|
|
6546
7875
|
console.log();
|
|
6547
7876
|
console.log(` ${BOLD}Chain:${RESET} ${chainName}`);
|
|
6548
7877
|
console.log(` ${BOLD}Call:${RESET} ${callHex}`);
|
|
@@ -7946,7 +9275,8 @@ var CATEGORY_ALIASES = {
|
|
|
7946
9275
|
api: "apis",
|
|
7947
9276
|
extensions: "extensions",
|
|
7948
9277
|
extension: "extensions",
|
|
7949
|
-
ext: "extensions"
|
|
9278
|
+
ext: "extensions",
|
|
9279
|
+
rpc: "rpc"
|
|
7950
9280
|
};
|
|
7951
9281
|
function matchCategory(segment) {
|
|
7952
9282
|
return CATEGORY_ALIASES[segment.toLowerCase()];
|
|
@@ -7961,7 +9291,7 @@ function parseDotPath(input, knownChains = []) {
|
|
|
7961
9291
|
const cat = matchCategory(parts[0]);
|
|
7962
9292
|
if (cat)
|
|
7963
9293
|
return { category: cat };
|
|
7964
|
-
throw new Error(`Unknown command "${parts[0]}". Expected a category (query, tx, const, events, errors, apis, extensions) or a named command.`);
|
|
9294
|
+
throw new Error(`Unknown command "${parts[0]}". Expected a category (query, tx, const, events, errors, apis, extensions, rpc) or a named command.`);
|
|
7965
9295
|
}
|
|
7966
9296
|
case 2: {
|
|
7967
9297
|
const cat = matchCategory(parts[0]);
|
|
@@ -8016,7 +9346,15 @@ if (process.argv[2] === "__complete") {
|
|
|
8016
9346
|
process.exit(0);
|
|
8017
9347
|
})();
|
|
8018
9348
|
} else {
|
|
8019
|
-
let
|
|
9349
|
+
let readAtFromArgv = function(argv) {
|
|
9350
|
+
for (let i = 0;i < argv.length; i++) {
|
|
9351
|
+
if (argv[i] === "--at" && i + 1 < argv.length)
|
|
9352
|
+
return argv[i + 1];
|
|
9353
|
+
if (argv[i].startsWith("--at="))
|
|
9354
|
+
return argv[i].slice(5);
|
|
9355
|
+
}
|
|
9356
|
+
return;
|
|
9357
|
+
}, collectVarFlags = function(argv) {
|
|
8020
9358
|
const vars = [];
|
|
8021
9359
|
for (let i = 0;i < argv.length; i++) {
|
|
8022
9360
|
if (argv[i] === "--var" && i + 1 < argv.length) {
|
|
@@ -8043,6 +9381,7 @@ if (process.argv[2] === "__complete") {
|
|
|
8043
9381
|
console.log(" errors List or inspect pallet errors");
|
|
8044
9382
|
console.log(" apis Browse and call runtime APIs");
|
|
8045
9383
|
console.log(" extensions List transaction extensions on a chain");
|
|
9384
|
+
console.log(" rpc Call raw JSON-RPC methods on a node");
|
|
8046
9385
|
console.log();
|
|
8047
9386
|
console.log("Examples:");
|
|
8048
9387
|
console.log(" dot polkadot.query.System.Account <addr> Query a storage item");
|
|
@@ -8055,6 +9394,8 @@ if (process.argv[2] === "__complete") {
|
|
|
8055
9394
|
console.log(" dot metadata polkadot Dump runtime metadata as JSON");
|
|
8056
9395
|
console.log(" dot polkadot.extensions List transaction extensions");
|
|
8057
9396
|
console.log(" dot polkadot.extensions.CheckMortality Inspect one extension");
|
|
9397
|
+
console.log(" dot polkadot.rpc List RPC methods on the node");
|
|
9398
|
+
console.log(" dot polkadot.rpc.system_health Call a JSON-RPC method");
|
|
8058
9399
|
console.log(" dot query.System.Number --chain polkadot --chain flag form");
|
|
8059
9400
|
console.log(" dot ./transfer.yaml --from alice Run from file (chain in YAML)");
|
|
8060
9401
|
console.log(" dot tx.0x1f0003... --to-yaml --chain polkadot Decode hex call to YAML");
|
|
@@ -8068,7 +9409,7 @@ if (process.argv[2] === "__complete") {
|
|
|
8068
9409
|
console.log(" account Manage accounts");
|
|
8069
9410
|
console.log(" hash Hash utilities");
|
|
8070
9411
|
console.log(" sign Sign a message with an account keypair");
|
|
8071
|
-
console.log(" parachain Derive parachain sovereign accounts");
|
|
9412
|
+
console.log(" parachain Derive parachain sovereign accounts (deprecated \u2014 use `account inspect --parachain`)");
|
|
8072
9413
|
console.log(" verifiable Derive Bandersnatch member key from mnemonic");
|
|
8073
9414
|
console.log(" completions <sh> Generate shell completions (zsh, bash, fish)");
|
|
8074
9415
|
console.log();
|
|
@@ -8099,11 +9440,12 @@ if (process.argv[2] === "__complete") {
|
|
|
8099
9440
|
registerVerifiableCommands(cli);
|
|
8100
9441
|
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("--asset <json>", "Pay fees in an alternative asset (XCM location JSON, for tx)").option("-w, --wait <level>", "Resolve at: broadcast, best-block (or best), finalized (for tx)", {
|
|
8101
9442
|
default: "finalized"
|
|
8102
|
-
}).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 (
|
|
9443
|
+
}).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 read/validate against (tx, query, apis)').option("--unsigned", "Submit as unsigned/bare transaction (no signer required, for tx)").option("--refresh", "Refresh the cached RPC method list from the node (for rpc)").action(async (dotpath, args, opts) => {
|
|
8103
9444
|
if (!dotpath) {
|
|
8104
9445
|
printHelp();
|
|
8105
9446
|
return;
|
|
8106
9447
|
}
|
|
9448
|
+
const atRaw = readAtFromArgv(process.argv);
|
|
8107
9449
|
if (isFilePath(dotpath)) {
|
|
8108
9450
|
const cliVars = collectVarFlags(process.argv);
|
|
8109
9451
|
const cmd = await loadCommandFile(dotpath, cliVars);
|
|
@@ -8131,7 +9473,7 @@ if (process.argv[2] === "__complete") {
|
|
|
8131
9473
|
nonce: opts.nonce,
|
|
8132
9474
|
tip: opts.tip,
|
|
8133
9475
|
mortality: opts.mortality,
|
|
8134
|
-
at:
|
|
9476
|
+
at: atRaw,
|
|
8135
9477
|
parsedArgs: cmd.args
|
|
8136
9478
|
});
|
|
8137
9479
|
break;
|
|
@@ -8139,6 +9481,7 @@ if (process.argv[2] === "__complete") {
|
|
|
8139
9481
|
await handleQuery(target2, args, {
|
|
8140
9482
|
...handlerOpts2,
|
|
8141
9483
|
dump: opts.dump,
|
|
9484
|
+
at: atRaw,
|
|
8142
9485
|
parsedArgs: cmd.args
|
|
8143
9486
|
});
|
|
8144
9487
|
break;
|
|
@@ -8148,6 +9491,7 @@ if (process.argv[2] === "__complete") {
|
|
|
8148
9491
|
case "apis":
|
|
8149
9492
|
await handleApis2(target2, args, {
|
|
8150
9493
|
...handlerOpts2,
|
|
9494
|
+
at: atRaw,
|
|
8151
9495
|
parsedArgs: cmd.args
|
|
8152
9496
|
});
|
|
8153
9497
|
break;
|
|
@@ -8162,9 +9506,10 @@ if (process.argv[2] === "__complete") {
|
|
|
8162
9506
|
} catch {
|
|
8163
9507
|
throw new CliError2(`Unknown command "${dotpath}". Run "dot --help" for available commands.`);
|
|
8164
9508
|
}
|
|
9509
|
+
const isFlatCategory = parsed.category === "rpc" || parsed.category === "extensions";
|
|
8165
9510
|
if (!parsed.pallet && args.length > 0) {
|
|
8166
9511
|
parsed.pallet = args.shift();
|
|
8167
|
-
if (!parsed.item && args.length > 0) {
|
|
9512
|
+
if (!isFlatCategory && !parsed.item && args.length > 0) {
|
|
8168
9513
|
parsed.item = args.shift();
|
|
8169
9514
|
}
|
|
8170
9515
|
}
|
|
@@ -8185,7 +9530,7 @@ if (process.argv[2] === "__complete") {
|
|
|
8185
9530
|
}
|
|
8186
9531
|
switch (parsed.category) {
|
|
8187
9532
|
case "query":
|
|
8188
|
-
await handleQuery(target, args, { ...handlerOpts, dump: opts.dump });
|
|
9533
|
+
await handleQuery(target, args, { ...handlerOpts, dump: opts.dump, at: atRaw });
|
|
8189
9534
|
break;
|
|
8190
9535
|
case "tx": {
|
|
8191
9536
|
const txOpts = {
|
|
@@ -8202,7 +9547,7 @@ if (process.argv[2] === "__complete") {
|
|
|
8202
9547
|
nonce: opts.nonce,
|
|
8203
9548
|
tip: opts.tip,
|
|
8204
9549
|
mortality: opts.mortality,
|
|
8205
|
-
at:
|
|
9550
|
+
at: atRaw
|
|
8206
9551
|
};
|
|
8207
9552
|
if (parsed.pallet && /^0x[0-9a-fA-F]+$/.test(parsed.pallet)) {
|
|
8208
9553
|
await handleTx(parsed.pallet, args, txOpts);
|
|
@@ -8221,7 +9566,7 @@ if (process.argv[2] === "__complete") {
|
|
|
8221
9566
|
await handleErrors2(target, handlerOpts);
|
|
8222
9567
|
break;
|
|
8223
9568
|
case "apis":
|
|
8224
|
-
await handleApis2(target, args, handlerOpts);
|
|
9569
|
+
await handleApis2(target, args, { ...handlerOpts, at: atRaw });
|
|
8225
9570
|
break;
|
|
8226
9571
|
case "extensions": {
|
|
8227
9572
|
if (parsed.item) {
|
|
@@ -8231,6 +9576,18 @@ if (process.argv[2] === "__complete") {
|
|
|
8231
9576
|
await handleExtensions(parsed.pallet, handlerOpts);
|
|
8232
9577
|
break;
|
|
8233
9578
|
}
|
|
9579
|
+
case "rpc": {
|
|
9580
|
+
if (parsed.item) {
|
|
9581
|
+
const suggestion = parsed.chain ? `dot ${parsed.chain}.rpc.${parsed.pallet}` : opts.chain ? `dot rpc.${parsed.pallet} --chain ${opts.chain}` : `dot rpc.${parsed.pallet} --chain <chain>`;
|
|
9582
|
+
throw new CliError2(`RPC methods have no sub-items. Try "${suggestion}".`);
|
|
9583
|
+
}
|
|
9584
|
+
await handleRpc(parsed.pallet, args, {
|
|
9585
|
+
...handlerOpts,
|
|
9586
|
+
help: cli.options.help,
|
|
9587
|
+
refresh: opts.refresh
|
|
9588
|
+
});
|
|
9589
|
+
break;
|
|
9590
|
+
}
|
|
8234
9591
|
}
|
|
8235
9592
|
});
|
|
8236
9593
|
cli.option("--help, -h", "Display this message");
|