polkadot-cli 1.17.0 → 1.18.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/README.md +196 -38
  2. package/dist/cli.mjs +1214 -89
  3. package/package.json +2 -1
package/dist/cli.mjs CHANGED
@@ -240,6 +240,9 @@ function getMetadataPath(chainName) {
240
240
  function getMetadataFingerprintPath(chainName) {
241
241
  return join(getChainDir(chainName), "metadata.fingerprint.json");
242
242
  }
243
+ function getRpcMethodsPath(chainName) {
244
+ return join(getChainDir(chainName), "rpc-methods.json");
245
+ }
243
246
  function getConfigPath() {
244
247
  return join(getConfigDir(), "config.json");
245
248
  }
@@ -305,6 +308,31 @@ async function loadMetadataFingerprint(chainName) {
305
308
  return null;
306
309
  }
307
310
  }
311
+ async function loadRpcMethods(chainName) {
312
+ const path = getRpcMethodsPath(chainName);
313
+ if (!await fileExists(path))
314
+ return null;
315
+ try {
316
+ const parsed = JSON.parse(await readFile(path, "utf-8"));
317
+ if (parsed && Array.isArray(parsed.methods) && typeof parsed.version === "number" && typeof parsed.fetchedAt === "string") {
318
+ return parsed;
319
+ }
320
+ return null;
321
+ } catch {
322
+ return null;
323
+ }
324
+ }
325
+ async function saveRpcMethods(chainName, methods, version2) {
326
+ const dir = getChainDir(chainName);
327
+ await ensureDir(dir);
328
+ const cache = {
329
+ methods,
330
+ version: version2,
331
+ fetchedAt: new Date().toISOString()
332
+ };
333
+ await writeFile(getRpcMethodsPath(chainName), `${JSON.stringify(cache, null, 2)}
334
+ `);
335
+ }
308
336
  async function removeChainData(chainName) {
309
337
  const dir = getChainDir(chainName);
310
338
  await rm(dir, { recursive: true, force: true });
@@ -375,6 +403,15 @@ function isEnvSecret(secret) {
375
403
  function isWatchOnly(account) {
376
404
  return account.secret === undefined;
377
405
  }
406
+ function classifyAccount(account) {
407
+ if (account.source?.kind === "pallet")
408
+ return "pallet";
409
+ if (account.source?.kind === "parachain")
410
+ return "parachain";
411
+ if (account.secret !== undefined)
412
+ return "signer";
413
+ return "watch-only";
414
+ }
378
415
 
379
416
  // src/utils/fuzzy-match.ts
380
417
  function levenshtein(a, b) {
@@ -2559,6 +2596,477 @@ var init_focused_inspect = __esm(() => {
2559
2596
  init_pretty_type();
2560
2597
  });
2561
2598
 
2599
+ // src/data/rpc-registry.ts
2600
+ function inferFamily(method) {
2601
+ const prefix = method.split("_")[0];
2602
+ switch (prefix) {
2603
+ case "system":
2604
+ case "chain":
2605
+ case "state":
2606
+ case "author":
2607
+ case "payment":
2608
+ case "babe":
2609
+ case "grandpa":
2610
+ case "beefy":
2611
+ case "mmr":
2612
+ case "offchain":
2613
+ case "dev":
2614
+ return prefix;
2615
+ case "rpc":
2616
+ return "spec";
2617
+ case "chainHead":
2618
+ return "chainHead";
2619
+ case "chainSpec":
2620
+ return "chainSpec";
2621
+ case "transaction":
2622
+ return "transaction";
2623
+ case "archive":
2624
+ return "archive";
2625
+ default:
2626
+ return "other";
2627
+ }
2628
+ }
2629
+ var RPC_REGISTRY;
2630
+ var init_rpc_registry = __esm(() => {
2631
+ RPC_REGISTRY = {
2632
+ system_health: {
2633
+ description: "Node sync state (peers, isSyncing, shouldHavePeers).",
2634
+ family: "system",
2635
+ args: []
2636
+ },
2637
+ system_syncState: {
2638
+ description: "Block-level sync progress (startingBlock, currentBlock, highestBlock).",
2639
+ family: "system",
2640
+ args: []
2641
+ },
2642
+ system_version: {
2643
+ description: "Node software version string.",
2644
+ family: "system",
2645
+ args: []
2646
+ },
2647
+ system_name: {
2648
+ description: "Node implementation name.",
2649
+ family: "system",
2650
+ args: []
2651
+ },
2652
+ system_chain: {
2653
+ description: "Chain name as reported by the node.",
2654
+ family: "system",
2655
+ args: []
2656
+ },
2657
+ system_chainType: {
2658
+ description: "Chain type (Live, Development, Local).",
2659
+ family: "system",
2660
+ args: []
2661
+ },
2662
+ system_properties: {
2663
+ description: "Chain properties (ss58Format, tokenDecimals, tokenSymbol).",
2664
+ family: "system",
2665
+ args: []
2666
+ },
2667
+ system_peers: {
2668
+ description: "Connected peer details (peerId, roles, bestHash, bestNumber).",
2669
+ family: "system",
2670
+ args: []
2671
+ },
2672
+ system_localPeerId: {
2673
+ description: "Base58 PeerId of this node.",
2674
+ family: "system",
2675
+ args: []
2676
+ },
2677
+ system_localListenAddresses: {
2678
+ description: "Multiaddrs this node listens on.",
2679
+ family: "system",
2680
+ args: []
2681
+ },
2682
+ system_nodeRoles: {
2683
+ description: "Role(s) of the node (Authority, Full, Light, …).",
2684
+ family: "system",
2685
+ args: []
2686
+ },
2687
+ system_addLogFilter: {
2688
+ description: "Add a tracing/log filter directive at runtime.",
2689
+ family: "system",
2690
+ args: [{ name: "directives", type: "string" }],
2691
+ dangerous: true
2692
+ },
2693
+ system_resetLogFilter: {
2694
+ description: "Reset log filter to the default set at startup.",
2695
+ family: "system",
2696
+ args: [],
2697
+ dangerous: true
2698
+ },
2699
+ system_accountNextIndex: {
2700
+ description: "Next nonce for an account, including pending mempool extrinsics.",
2701
+ family: "system",
2702
+ args: [{ name: "address", type: "AccountId" }]
2703
+ },
2704
+ system_dryRun: {
2705
+ description: "Dry-run an extrinsic, returning its ApplyExtrinsicResult.",
2706
+ family: "system",
2707
+ args: [
2708
+ { name: "extrinsic", type: "hex" },
2709
+ { name: "at", type: "H256", optional: true }
2710
+ ]
2711
+ },
2712
+ chain_getBlock: {
2713
+ description: "Full block (header + extrinsics) by hash.",
2714
+ family: "chain",
2715
+ args: [{ name: "blockHash", type: "H256", optional: true, description: "latest if omitted" }]
2716
+ },
2717
+ chain_getBlockHash: {
2718
+ description: "Block hash by number, or latest if omitted.",
2719
+ family: "chain",
2720
+ args: [{ name: "blockNumber", type: "u32", optional: true }]
2721
+ },
2722
+ chain_getFinalizedHead: {
2723
+ description: "Hash of the latest finalized head.",
2724
+ family: "chain",
2725
+ args: []
2726
+ },
2727
+ chain_getHeader: {
2728
+ description: "Block header by hash, or latest if omitted.",
2729
+ family: "chain",
2730
+ args: [{ name: "blockHash", type: "H256", optional: true }]
2731
+ },
2732
+ chain_subscribeAllHeads: {
2733
+ description: "Subscribe to all imported headers.",
2734
+ family: "chain",
2735
+ args: [],
2736
+ subscription: true
2737
+ },
2738
+ chain_subscribeFinalizedHeads: {
2739
+ description: "Subscribe to finalized-head changes.",
2740
+ family: "chain",
2741
+ args: [],
2742
+ subscription: true
2743
+ },
2744
+ chain_subscribeNewHeads: {
2745
+ description: "Subscribe to best-block-head changes.",
2746
+ family: "chain",
2747
+ args: [],
2748
+ subscription: true
2749
+ },
2750
+ state_call: {
2751
+ description: "Invoke a runtime API method by name with raw SCALE-encoded arguments.",
2752
+ family: "state",
2753
+ args: [
2754
+ { name: "method", type: "string", description: "e.g. Core_version" },
2755
+ { name: "data", type: "hex", description: "SCALE-encoded args (0x for none)" },
2756
+ { name: "at", type: "H256", optional: true }
2757
+ ]
2758
+ },
2759
+ state_getMetadata: {
2760
+ description: "Raw SCALE-encoded runtime metadata at a block.",
2761
+ family: "state",
2762
+ args: [{ name: "at", type: "H256", optional: true }]
2763
+ },
2764
+ state_getRuntimeVersion: {
2765
+ description: "Runtime version at a block.",
2766
+ family: "state",
2767
+ args: [{ name: "at", type: "H256", optional: true }]
2768
+ },
2769
+ state_getStorage: {
2770
+ description: "Raw SCALE-encoded storage value at a key.",
2771
+ family: "state",
2772
+ args: [
2773
+ { name: "key", type: "StorageKey" },
2774
+ { name: "at", type: "H256", optional: true }
2775
+ ]
2776
+ },
2777
+ state_getStorageHash: {
2778
+ description: "Blake2 hash of the value at a storage key.",
2779
+ family: "state",
2780
+ args: [
2781
+ { name: "key", type: "StorageKey" },
2782
+ { name: "at", type: "H256", optional: true }
2783
+ ]
2784
+ },
2785
+ state_getStorageSize: {
2786
+ description: "Byte length of the value at a storage key.",
2787
+ family: "state",
2788
+ args: [
2789
+ { name: "key", type: "StorageKey" },
2790
+ { name: "at", type: "H256", optional: true }
2791
+ ]
2792
+ },
2793
+ state_getKeysPaged: {
2794
+ description: "Paginated key iteration under a prefix.",
2795
+ family: "state",
2796
+ args: [
2797
+ { name: "prefix", type: "StorageKey" },
2798
+ { name: "count", type: "u32" },
2799
+ { name: "startKey", type: "StorageKey", optional: true },
2800
+ { name: "at", type: "H256", optional: true }
2801
+ ]
2802
+ },
2803
+ state_queryStorageAt: {
2804
+ description: "Read multiple keys at a single block.",
2805
+ family: "state",
2806
+ args: [
2807
+ { name: "keys", type: "StorageKey[]" },
2808
+ { name: "at", type: "H256", optional: true }
2809
+ ]
2810
+ },
2811
+ state_traceBlock: {
2812
+ description: "Per-block storage access trace (heavy: archival/debug nodes only).",
2813
+ family: "state",
2814
+ args: [
2815
+ { name: "blockHash", type: "H256" },
2816
+ { name: "targets", type: "string", optional: true },
2817
+ { name: "storageKeys", type: "string", optional: true },
2818
+ { name: "methods", type: "string", optional: true }
2819
+ ]
2820
+ },
2821
+ state_subscribeRuntimeVersion: {
2822
+ description: "Subscribe to runtime upgrades.",
2823
+ family: "state",
2824
+ args: [],
2825
+ subscription: true
2826
+ },
2827
+ state_subscribeStorage: {
2828
+ description: "Subscribe to changes for a set of keys.",
2829
+ family: "state",
2830
+ args: [{ name: "keys", type: "StorageKey[]" }],
2831
+ subscription: true
2832
+ },
2833
+ author_pendingExtrinsics: {
2834
+ description: "Mempool snapshot — encoded extrinsics waiting to be included.",
2835
+ family: "author",
2836
+ args: []
2837
+ },
2838
+ author_submitExtrinsic: {
2839
+ description: "Submit a signed extrinsic to the mempool. Returns the tx hash.",
2840
+ family: "author",
2841
+ args: [{ name: "extrinsic", type: "hex" }],
2842
+ dangerous: true
2843
+ },
2844
+ author_removeExtrinsic: {
2845
+ description: "Remove specific extrinsics from the mempool by hash.",
2846
+ family: "author",
2847
+ args: [{ name: "bytesOrHash", type: "ExtrinsicOrHash[]" }],
2848
+ dangerous: true
2849
+ },
2850
+ author_hasKey: {
2851
+ description: "Whether the keystore has the public key for a given key type.",
2852
+ family: "author",
2853
+ args: [
2854
+ { name: "publicKey", type: "hex" },
2855
+ { name: "keyType", type: "string", description: "e.g. babe, gran, imon" }
2856
+ ]
2857
+ },
2858
+ author_hasSessionKeys: {
2859
+ description: "Whether the keystore has all keys for a session-keys blob.",
2860
+ family: "author",
2861
+ args: [{ name: "sessionKeys", type: "hex" }]
2862
+ },
2863
+ author_rotateKeys: {
2864
+ description: "Generate a new set of session keys and return the public-keys blob.",
2865
+ family: "author",
2866
+ args: [],
2867
+ dangerous: true
2868
+ },
2869
+ author_insertKey: {
2870
+ description: "Insert a key into the node keystore.",
2871
+ family: "author",
2872
+ args: [
2873
+ { name: "keyType", type: "string" },
2874
+ { name: "suri", type: "string" },
2875
+ { name: "publicKey", type: "hex" }
2876
+ ],
2877
+ dangerous: true
2878
+ },
2879
+ author_submitAndWatchExtrinsic: {
2880
+ description: "Submit an extrinsic and subscribe to its status updates.",
2881
+ family: "author",
2882
+ args: [{ name: "extrinsic", type: "hex" }],
2883
+ dangerous: true,
2884
+ subscription: true
2885
+ },
2886
+ payment_queryInfo: {
2887
+ description: "Pre-submission fee estimate (weight, partialFee, class).",
2888
+ family: "payment",
2889
+ args: [
2890
+ { name: "extrinsic", type: "hex" },
2891
+ { name: "at", type: "H256", optional: true }
2892
+ ]
2893
+ },
2894
+ payment_queryFeeDetails: {
2895
+ description: "Fee breakdown (baseFee, lenFee, adjustedWeightFee, tip).",
2896
+ family: "payment",
2897
+ args: [
2898
+ { name: "extrinsic", type: "hex" },
2899
+ { name: "at", type: "H256", optional: true }
2900
+ ]
2901
+ },
2902
+ babe_epochAuthorship: {
2903
+ description: "Slots this node is allowed to author in the current epoch.",
2904
+ family: "babe",
2905
+ args: []
2906
+ },
2907
+ grandpa_proveFinality: {
2908
+ description: "Finality proof up to a block (for light clients).",
2909
+ family: "grandpa",
2910
+ args: [{ name: "blockNumber", type: "u32" }]
2911
+ },
2912
+ grandpa_roundState: {
2913
+ description: "GRANDPA round state (best round, total weight, voters).",
2914
+ family: "grandpa",
2915
+ args: []
2916
+ },
2917
+ grandpa_subscribeJustifications: {
2918
+ description: "Subscribe to GRANDPA justifications.",
2919
+ family: "grandpa",
2920
+ args: [],
2921
+ subscription: true
2922
+ },
2923
+ beefy_getFinalizedHead: {
2924
+ description: "Latest BEEFY-finalized block hash.",
2925
+ family: "beefy",
2926
+ args: []
2927
+ },
2928
+ beefy_subscribeJustifications: {
2929
+ description: "Subscribe to BEEFY signed commitments.",
2930
+ family: "beefy",
2931
+ args: [],
2932
+ subscription: true
2933
+ },
2934
+ mmr_root: {
2935
+ description: "MMR root at a block.",
2936
+ family: "mmr",
2937
+ args: [{ name: "at", type: "H256", optional: true }]
2938
+ },
2939
+ mmr_generateProof: {
2940
+ description: "Generate an MMR proof for given leaf indices.",
2941
+ family: "mmr",
2942
+ args: [
2943
+ { name: "blockNumbers", type: "u32[]" },
2944
+ { name: "bestKnownBlockNumber", type: "u32", optional: true },
2945
+ { name: "at", type: "H256", optional: true }
2946
+ ]
2947
+ },
2948
+ mmr_verifyProof: {
2949
+ description: "Verify an MMR proof.",
2950
+ family: "mmr",
2951
+ args: [{ name: "proof", type: "MmrLeavesProof" }]
2952
+ },
2953
+ offchain_localStorageGet: {
2954
+ description: "Read from offchain-worker local storage (PERSISTENT or LOCAL kind).",
2955
+ family: "offchain",
2956
+ args: [
2957
+ { name: "kind", type: "string", description: "PERSISTENT or LOCAL" },
2958
+ { name: "key", type: "hex" }
2959
+ ]
2960
+ },
2961
+ offchain_localStorageSet: {
2962
+ description: "Write to offchain-worker local storage.",
2963
+ family: "offchain",
2964
+ args: [
2965
+ { name: "kind", type: "string" },
2966
+ { name: "key", type: "hex" },
2967
+ { name: "value", type: "hex" }
2968
+ ],
2969
+ dangerous: true
2970
+ },
2971
+ dev_newBlock: {
2972
+ description: "Manually trigger block production (manual-seal dev nodes).",
2973
+ family: "dev",
2974
+ args: [
2975
+ {
2976
+ name: "params",
2977
+ type: "json",
2978
+ optional: true,
2979
+ description: "{ create_empty?: bool, finalize?: bool }"
2980
+ }
2981
+ ],
2982
+ dangerous: true
2983
+ },
2984
+ dev_setHead: {
2985
+ description: "Set the chain head to a specific block (manual-seal dev nodes).",
2986
+ family: "dev",
2987
+ args: [{ name: "blockHash", type: "H256" }],
2988
+ dangerous: true
2989
+ },
2990
+ rpc_methods: {
2991
+ description: "List of JSON-RPC methods this node exposes.",
2992
+ family: "spec",
2993
+ args: []
2994
+ },
2995
+ chainSpec_v1_chainName: {
2996
+ description: "Chain name from the chain spec (no SCALE).",
2997
+ family: "chainSpec",
2998
+ args: []
2999
+ },
3000
+ chainSpec_v1_genesisHash: {
3001
+ description: "Genesis block hash.",
3002
+ family: "chainSpec",
3003
+ args: []
3004
+ },
3005
+ chainSpec_v1_properties: {
3006
+ description: "Chain properties from the chain spec.",
3007
+ family: "chainSpec",
3008
+ args: []
3009
+ },
3010
+ archive_v1_finalizedHeight: {
3011
+ description: "Latest finalized block number this archive node has.",
3012
+ family: "archive",
3013
+ args: []
3014
+ },
3015
+ archive_v1_genesisHash: {
3016
+ description: "Genesis block hash from the archive node.",
3017
+ family: "archive",
3018
+ args: []
3019
+ },
3020
+ archive_v1_hashByHeight: {
3021
+ description: "Block hashes at a height (canonical + forks).",
3022
+ family: "archive",
3023
+ args: [{ name: "height", type: "u32" }]
3024
+ },
3025
+ archive_v1_header: {
3026
+ description: "Header for an archived block.",
3027
+ family: "archive",
3028
+ args: [{ name: "blockHash", type: "H256" }]
3029
+ },
3030
+ archive_v1_body: {
3031
+ description: "Block body (extrinsics) for an archived block.",
3032
+ family: "archive",
3033
+ args: [{ name: "blockHash", type: "H256" }]
3034
+ },
3035
+ archive_v1_call: {
3036
+ description: "Invoke a runtime API at an archived block.",
3037
+ family: "archive",
3038
+ args: [
3039
+ { name: "blockHash", type: "H256" },
3040
+ { name: "function", type: "string" },
3041
+ { name: "callParameters", type: "hex" }
3042
+ ]
3043
+ },
3044
+ archive_v1_storage: {
3045
+ description: "Read storage at an archived block.",
3046
+ family: "archive",
3047
+ args: [
3048
+ { name: "blockHash", type: "H256" },
3049
+ { name: "items", type: "StorageItemInput[]" },
3050
+ { name: "childTrie", type: "string", optional: true }
3051
+ ],
3052
+ subscription: true
3053
+ },
3054
+ chainHead_v1_follow: {
3055
+ description: "Pin chainHead and stream block events. Requires a follow session.",
3056
+ family: "chainHead",
3057
+ args: [{ name: "withRuntime", type: "bool" }],
3058
+ subscription: true
3059
+ },
3060
+ transaction_v1_broadcast: {
3061
+ description: "Broadcast a signed extrinsic and watch its status.",
3062
+ family: "transaction",
3063
+ args: [{ name: "extrinsic", type: "hex" }],
3064
+ dangerous: true,
3065
+ subscription: true
3066
+ }
3067
+ };
3068
+ });
3069
+
2562
3070
  // src/core/hash.ts
2563
3071
  import { blake2b as blake2b2 } from "@noble/hashes/blake2.js";
2564
3072
  import { sha256 } from "@noble/hashes/sha2.js";
@@ -2742,11 +3250,8 @@ async function generateCompletions(currentWord, precedingWords) {
2742
3250
  if (firstArg === "hash") {
2743
3251
  return filterPrefix(getAlgorithmNames(), currentWord);
2744
3252
  }
2745
- if (firstArg === "parachain") {
2746
- if (prevWord === "--type") {
2747
- return filterPrefix(["child", "sibling"], currentWord);
2748
- }
2749
- return [];
3253
+ if (firstArg === "account" && prevWord === "--parachain-type") {
3254
+ return filterPrefix(["child", "sibling"], currentWord);
2750
3255
  }
2751
3256
  return completeDotpath(currentWord, config, knownChains, precedingWords);
2752
3257
  }
@@ -2789,6 +3294,9 @@ async function completeDotpath(currentWord, config, knownChains, precedingWords)
2789
3294
  if (category === "extensions") {
2790
3295
  return completeExtensionsCategory(first, numComplete, endsWithDot, currentWord, config, chainFromFlag);
2791
3296
  }
3297
+ if (category === "rpc") {
3298
+ return completeRpcCategory(first, numComplete, endsWithDot, currentWord, chainFromFlag);
3299
+ }
2792
3300
  if (numComplete === 1 && endsWithDot) {
2793
3301
  const chainName = chainFromFlag;
2794
3302
  if (!chainName)
@@ -2848,6 +3356,9 @@ async function completeDotpath(currentWord, config, knownChains, precedingWords)
2848
3356
  if (category === "extensions") {
2849
3357
  return completeExtensionsCategory(`${first}.${completeSegments[1]}`, numComplete - 1, endsWithDot, currentWord, config, chainName);
2850
3358
  }
3359
+ if (category === "rpc") {
3360
+ return completeRpcCategory(`${first}.${completeSegments[1]}`, numComplete - 1, endsWithDot, currentWord, chainName);
3361
+ }
2851
3362
  const pallets = await loadPallets(config, chainName);
2852
3363
  if (!pallets)
2853
3364
  return [];
@@ -2921,6 +3432,24 @@ async function completeExtensionsCategory(prefix, numComplete, endsWithDot, curr
2921
3432
  }
2922
3433
  return [];
2923
3434
  }
3435
+ async function completeRpcCategory(prefix, numComplete, endsWithDot, currentWord, chainNameOverride) {
3436
+ let names;
3437
+ if (chainNameOverride) {
3438
+ const cached = await loadRpcMethods(chainNameOverride);
3439
+ names = cached?.methods ?? Object.keys(RPC_REGISTRY);
3440
+ } else {
3441
+ names = Object.keys(RPC_REGISTRY);
3442
+ }
3443
+ if (numComplete === 1 && endsWithDot) {
3444
+ const candidates = names.map((n) => `${prefix}.${n}`);
3445
+ return filterPrefix(candidates, currentWord.slice(0, -1));
3446
+ }
3447
+ if (numComplete === 1 && !endsWithDot) {
3448
+ const candidates = names.map((n) => `${prefix}.${n}`);
3449
+ return filterPrefix(candidates, currentWord);
3450
+ }
3451
+ return [];
3452
+ }
2924
3453
  var CATEGORIES2, CATEGORY_ALIASES2, NAMED_COMMANDS, CHAIN_SUBCOMMANDS, ACCOUNT_SUBCOMMANDS, GLOBAL_OPTIONS, TX_OPTIONS, QUERY_OPTIONS;
2925
3454
  var init_complete = __esm(() => {
2926
3455
  init_accounts_store();
@@ -2928,7 +3457,17 @@ var init_complete = __esm(() => {
2928
3457
  init_accounts();
2929
3458
  init_hash();
2930
3459
  init_metadata();
2931
- CATEGORIES2 = ["query", "tx", "const", "events", "errors", "apis", "extensions"];
3460
+ init_rpc_registry();
3461
+ CATEGORIES2 = [
3462
+ "query",
3463
+ "tx",
3464
+ "const",
3465
+ "events",
3466
+ "errors",
3467
+ "apis",
3468
+ "extensions",
3469
+ "rpc"
3470
+ ];
2932
3471
  CATEGORY_ALIASES2 = {
2933
3472
  query: "query",
2934
3473
  tx: "tx",
@@ -2943,9 +3482,10 @@ var init_complete = __esm(() => {
2943
3482
  api: "apis",
2944
3483
  extensions: "extensions",
2945
3484
  extension: "extensions",
2946
- ext: "extensions"
3485
+ ext: "extensions",
3486
+ rpc: "rpc"
2947
3487
  };
2948
- NAMED_COMMANDS = ["chain", "account", "inspect", "hash", "sign", "parachain", "completions"];
3488
+ NAMED_COMMANDS = ["chain", "account", "inspect", "hash", "sign", "completions"];
2949
3489
  CHAIN_SUBCOMMANDS = ["add", "info", "list", "remove", "update"];
2950
3490
  ACCOUNT_SUBCOMMANDS = [
2951
3491
  "add",
@@ -2977,23 +3517,94 @@ var init_complete = __esm(() => {
2977
3517
  // src/cli.ts
2978
3518
  import cac from "cac";
2979
3519
  // package.json
2980
- var version = "1.17.0";
3520
+ var version = "1.18.0";
2981
3521
 
2982
3522
  // src/commands/account.ts
2983
3523
  init_accounts_store();
2984
3524
  init_accounts();
2985
3525
  init_output();
2986
3526
  import { readFile as readFile3, writeFile as writeFile3 } from "node:fs/promises";
3527
+
3528
+ // src/core/pallet.ts
3529
+ init_errors();
3530
+ var MODL_PREFIX = new Uint8Array([109, 111, 100, 108]);
3531
+ var PALLET_ID_BYTES = 8;
3532
+ function derivePalletAccount(palletId) {
3533
+ if (palletId.length !== PALLET_ID_BYTES) {
3534
+ throw new CliError(`PalletId must be exactly ${PALLET_ID_BYTES} bytes (got ${palletId.length}).`);
3535
+ }
3536
+ const result = new Uint8Array(32);
3537
+ result.set(MODL_PREFIX, 0);
3538
+ result.set(palletId, 4);
3539
+ return result;
3540
+ }
3541
+ function parsePalletId(input) {
3542
+ if (input.startsWith("0x") || input.startsWith("0X")) {
3543
+ const hex = input.slice(2);
3544
+ if (hex.length !== PALLET_ID_BYTES * 2) {
3545
+ throw new CliError(`Invalid PalletId hex "${input}". Must be 0x followed by exactly ${PALLET_ID_BYTES * 2} hex characters.`);
3546
+ }
3547
+ if (!/^[0-9a-fA-F]+$/.test(hex)) {
3548
+ throw new CliError(`Invalid PalletId hex "${input}". Contains non-hex characters.`);
3549
+ }
3550
+ const bytes2 = new Uint8Array(PALLET_ID_BYTES);
3551
+ for (let i = 0;i < PALLET_ID_BYTES; i++) {
3552
+ bytes2[i] = parseInt(hex.slice(i * 2, i * 2 + 2), 16);
3553
+ }
3554
+ return bytes2;
3555
+ }
3556
+ if (input.length !== PALLET_ID_BYTES) {
3557
+ throw new CliError(`Invalid PalletId "${input}". Must be ${PALLET_ID_BYTES} ASCII characters or 0x-prefixed hex.`);
3558
+ }
3559
+ const bytes = new Uint8Array(PALLET_ID_BYTES);
3560
+ for (let i = 0;i < PALLET_ID_BYTES; i++) {
3561
+ const code = input.charCodeAt(i);
3562
+ if (code > 127) {
3563
+ throw new CliError(`Invalid PalletId "${input}". ASCII form must contain only ASCII bytes.`);
3564
+ }
3565
+ bytes[i] = code;
3566
+ }
3567
+ return bytes;
3568
+ }
3569
+ function formatPalletId(palletId) {
3570
+ const allPrintable = palletId.every((b) => b >= 32 && b <= 126);
3571
+ if (allPrintable) {
3572
+ return Array.from(palletId, (b) => String.fromCharCode(b)).join("");
3573
+ }
3574
+ return `0x${Array.from(palletId, (b) => b.toString(16).padStart(2, "0")).join("")}`;
3575
+ }
3576
+
3577
+ // src/core/parachain.ts
3578
+ var SOVEREIGN_ACCOUNT_TYPES = ["child", "sibling"];
3579
+ var PREFIXES = {
3580
+ child: new Uint8Array([112, 97, 114, 97]),
3581
+ sibling: new Uint8Array([115, 105, 98, 108])
3582
+ };
3583
+ function deriveSovereignAccount(paraId, type) {
3584
+ const result = new Uint8Array(32);
3585
+ result.set(PREFIXES[type], 0);
3586
+ new DataView(result.buffer).setUint32(4, paraId, true);
3587
+ return result;
3588
+ }
3589
+ function isValidParaId(value) {
3590
+ return Number.isInteger(value) && value >= 0 && value <= 4294967295;
3591
+ }
3592
+
3593
+ // src/commands/account.ts
2987
3594
  var ACCOUNT_HELP = `
2988
3595
  ${BOLD}Usage:${RESET}
2989
3596
  $ dot account add <name> <ss58|hex> Add a watch-only address (no secret)
2990
3597
  $ dot account add <name> --secret <s> [--path <derivation>] Import from BIP39 mnemonic
2991
3598
  $ dot account add <name> --env <VAR> [--path <derivation>] Import account backed by env variable
3599
+ $ dot account add <name> --parachain <id> --parachain-type <t> Derive a parachain sovereign (t = child|sibling)
3600
+ $ dot account add <name> --pallet-id <8 chars or 0x hex> Derive a pallet sovereign (e.g. py/trsry)
2992
3601
  $ dot account create|new <name> [--path <derivation>] Create a new account
2993
3602
  $ dot account import <file> Batch-import accounts from a file
2994
3603
  $ dot account export [names...] Export accounts to stdout
2995
3604
  $ dot account derive <source> <new-name> --path <derivation> Derive a child account
2996
3605
  $ dot account inspect <input> [--prefix <N>] [--show-secret] Inspect an account/address/key
3606
+ $ dot account inspect --pallet-id <id> [--prefix <N>] Derive a pallet sovereign (no save — script-friendly)
3607
+ $ dot account inspect --parachain <id> --parachain-type <t> Derive a parachain sovereign (no save — script-friendly)
2997
3608
  $ dot account list List all accounts
2998
3609
  $ dot account remove|delete <name> [name2] ... Remove stored account(s)
2999
3610
 
@@ -3001,6 +3612,10 @@ ${BOLD}Examples:${RESET}
3001
3612
  $ dot account add treasury 5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY
3002
3613
  $ dot account add treasury --secret "word1 word2 ... word12"
3003
3614
  $ dot account add ci-signer --env MY_SECRET --path //ci
3615
+ $ dot account add Treasury --pallet-id py/trsry
3616
+ $ dot account add Bounties --pallet-id 0x70792f626f756e74
3617
+ $ dot account add People --parachain 1004 --parachain-type child
3618
+ $ dot account add People-Sibling --parachain 1004 --parachain-type sibling
3004
3619
  $ dot account create my-validator
3005
3620
  $ dot account create my-staking --path //staking
3006
3621
  $ dot account create multi --path //polkadot//0/wallet
@@ -3016,6 +3631,8 @@ ${BOLD}Examples:${RESET}
3016
3631
  $ dot account inspect dave --show-secret
3017
3632
  $ dot account inspect 5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY
3018
3633
  $ dot account inspect 0xd435...a27d --prefix 0
3634
+ $ dot account inspect --pallet-id py/trsry --prefix 0
3635
+ $ dot account inspect --parachain 1004 --parachain-type child
3019
3636
  $ dot account list
3020
3637
  $ dot account remove my-validator stale-key
3021
3638
 
@@ -3024,7 +3641,7 @@ ${YELLOW}Note: Secrets are stored unencrypted in ~/.polkadot/accounts.json.
3024
3641
  Hex seed import (0x...) is not supported via CLI.${RESET}
3025
3642
  `.trimStart();
3026
3643
  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) => {
3644
+ 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
3645
  if (!action) {
3029
3646
  if (process.argv[2] === "accounts")
3030
3647
  return accountList(opts);
@@ -3036,8 +3653,13 @@ function registerAccountCommands(cli) {
3036
3653
  case "create":
3037
3654
  return accountCreate(names[0], opts);
3038
3655
  case "add":
3039
- if (opts.secret || opts.env)
3656
+ if (opts.secret || opts.env) {
3657
+ 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="));
3658
+ if (hasDerivation) {
3659
+ throw new Error("Derivation flags (--parachain, --pallet-id) cannot be combined with --secret or --env. A derived sovereign account has no secret.");
3660
+ }
3040
3661
  return accountImport(names[0], opts);
3662
+ }
3041
3663
  return accountAddWatchOnly(names[0], names[1], opts);
3042
3664
  case "import":
3043
3665
  return accountBatchImport(names[0], opts);
@@ -3193,10 +3815,16 @@ async function accountAddWatchOnly(name, address, opts = {}) {
3193
3815
  console.error("Usage: dot account add <name> <ss58-address|0x-public-key>");
3194
3816
  process.exit(1);
3195
3817
  }
3196
- if (!address) {
3818
+ const sovereignSource = resolveSovereignSource(opts);
3819
+ if (sovereignSource && address) {
3820
+ throw new Error("Cannot combine a positional address with --parachain or --pallet-id. Pass either an address OR a derivation flag, not both.");
3821
+ }
3822
+ if (!sovereignSource && !address) {
3197
3823
  console.error(`Address is required.
3198
3824
  `);
3199
3825
  console.error("Usage: dot account add <name> <ss58-address|0x-public-key>");
3826
+ console.error(" dot account add <name> --parachain <id> --parachain-type <child|sibling>");
3827
+ console.error(" dot account add <name> --pallet-id <8 chars or 0x hex>");
3200
3828
  process.exit(1);
3201
3829
  }
3202
3830
  if (isDevAccount(name)) {
@@ -3207,7 +3835,10 @@ async function accountAddWatchOnly(name, address, opts = {}) {
3207
3835
  throw new Error(`Account "${name}" already exists.`);
3208
3836
  }
3209
3837
  let hexPub;
3210
- if (isHexPublicKey(address)) {
3838
+ if (sovereignSource) {
3839
+ const accountId = sovereignSource.kind === "parachain" ? deriveSovereignAccount(sovereignSource.paraId, sovereignSource.type) : derivePalletAccount(sovereignSource.palletId);
3840
+ hexPub = publicKeyToHex(accountId);
3841
+ } else if (isHexPublicKey(address)) {
3211
3842
  hexPub = address;
3212
3843
  } else {
3213
3844
  try {
@@ -3217,21 +3848,99 @@ async function accountAddWatchOnly(name, address, opts = {}) {
3217
3848
  throw new Error(`Invalid address "${address}". Expected an SS58 address or 0x-prefixed 32-byte hex public key.`);
3218
3849
  }
3219
3850
  }
3851
+ let persistedSource;
3852
+ if (sovereignSource?.kind === "pallet") {
3853
+ persistedSource = {
3854
+ kind: "pallet",
3855
+ palletId: `0x${Array.from(sovereignSource.palletId, (b) => b.toString(16).padStart(2, "0")).join("")}`
3856
+ };
3857
+ } else if (sovereignSource?.kind === "parachain") {
3858
+ persistedSource = {
3859
+ kind: "parachain",
3860
+ paraId: sovereignSource.paraId,
3861
+ type: sovereignSource.type
3862
+ };
3863
+ }
3220
3864
  accountsFile.accounts.push({
3221
3865
  name,
3222
3866
  publicKey: hexPub,
3223
- derivationPath: ""
3867
+ derivationPath: "",
3868
+ ...persistedSource ? { source: persistedSource } : {}
3224
3869
  });
3225
3870
  await saveAccounts(accountsFile);
3226
3871
  if (isJsonOutput(opts)) {
3227
- console.log(formatJson({ name, address: toSs58(hexPub), watchOnly: true }));
3872
+ const payload = {
3873
+ name,
3874
+ address: toSs58(hexPub),
3875
+ watchOnly: true
3876
+ };
3877
+ if (sovereignSource?.kind === "parachain") {
3878
+ payload.derivation = {
3879
+ kind: "parachain",
3880
+ paraId: sovereignSource.paraId,
3881
+ type: sovereignSource.type
3882
+ };
3883
+ } else if (sovereignSource?.kind === "pallet") {
3884
+ payload.derivation = {
3885
+ kind: "pallet",
3886
+ palletId: formatPalletId(sovereignSource.palletId),
3887
+ palletIdHex: `0x${Array.from(sovereignSource.palletId, (b) => b.toString(16).padStart(2, "0")).join("")}`
3888
+ };
3889
+ }
3890
+ console.log(formatJson(payload));
3228
3891
  return;
3229
3892
  }
3230
3893
  printHeading("Account Added (watch-only)");
3231
3894
  console.log(` ${BOLD}Name:${RESET} ${name}`);
3232
3895
  console.log(` ${BOLD}Address:${RESET} ${toSs58(hexPub)}`);
3896
+ if (sovereignSource?.kind === "parachain") {
3897
+ console.log(` ${BOLD}Source:${RESET} parachain ${sovereignSource.paraId} (${sovereignSource.type} sovereign)`);
3898
+ } else if (sovereignSource?.kind === "pallet") {
3899
+ const display = formatPalletId(sovereignSource.palletId);
3900
+ const hex = `0x${Array.from(sovereignSource.palletId, (b) => b.toString(16).padStart(2, "0")).join("")}`;
3901
+ console.log(` ${BOLD}Source:${RESET} pallet ${display} (${hex})`);
3902
+ }
3233
3903
  console.log();
3234
3904
  }
3905
+ function rawArgValue(flag) {
3906
+ const argv = process.argv;
3907
+ for (let i = 0;i < argv.length; i++) {
3908
+ if (argv[i] === flag && i + 1 < argv.length)
3909
+ return argv[i + 1];
3910
+ const prefix = `${flag}=`;
3911
+ if (argv[i]?.startsWith(prefix))
3912
+ return argv[i].slice(prefix.length);
3913
+ }
3914
+ return;
3915
+ }
3916
+ function resolveSovereignSource(opts) {
3917
+ const rawPalletId = rawArgValue("--pallet-id") ?? opts.palletId;
3918
+ const rawParachain = rawArgValue("--parachain") ?? opts.parachain;
3919
+ if (rawParachain != null && rawPalletId != null) {
3920
+ throw new Error("--parachain and --pallet-id are mutually exclusive. Pass only one derivation flag.");
3921
+ }
3922
+ if (rawParachain != null) {
3923
+ const paraId = Number(rawParachain);
3924
+ if (!isValidParaId(paraId)) {
3925
+ throw new Error(`Invalid parachain ID "${rawParachain}". Must be a non-negative integer (0 to 4294967295).`);
3926
+ }
3927
+ if (!opts.parachainType) {
3928
+ throw new Error("--parachain-type is required when --parachain is given. Use --parachain-type child or --parachain-type sibling.");
3929
+ }
3930
+ const type = opts.parachainType.toLowerCase();
3931
+ if (type !== "child" && type !== "sibling") {
3932
+ throw new Error(`Unknown parachain account type "${opts.parachainType}". Valid types: child, sibling.`);
3933
+ }
3934
+ return { kind: "parachain", paraId, type };
3935
+ }
3936
+ if (rawPalletId != null) {
3937
+ return { kind: "pallet", palletId: parsePalletId(String(rawPalletId)) };
3938
+ }
3939
+ if (opts.parachainType != null) {
3940
+ throw new Error("--parachain-type requires --parachain.");
3941
+ }
3942
+ return;
3943
+ }
3235
3944
  async function accountDerive(sourceName, newName, opts) {
3236
3945
  if (!sourceName) {
3237
3946
  console.error(`Source account name is required.
@@ -3315,69 +4024,134 @@ async function accountDerive(sourceName, newName, opts) {
3315
4024
  console.log();
3316
4025
  }
3317
4026
  }
4027
+ function resolveAddress(account) {
4028
+ if (isWatchOnly(account)) {
4029
+ return account.publicKey ? toSs58(account.publicKey) : "n/a";
4030
+ }
4031
+ if (account.secret !== undefined && isEnvSecret(account.secret)) {
4032
+ const pubKey = account.publicKey || tryDerivePublicKey(account.secret.env, account.derivationPath) || "";
4033
+ return pubKey ? toSs58(pubKey) : "n/a";
4034
+ }
4035
+ return toSs58(account.publicKey);
4036
+ }
4037
+ function buildAttributes(account) {
4038
+ const attrs = [];
4039
+ if (account.derivationPath)
4040
+ attrs.push({ label: "path", value: account.derivationPath });
4041
+ if (account.secret !== undefined && isEnvSecret(account.secret)) {
4042
+ attrs.push({ label: "env", value: `$${account.secret.env}` });
4043
+ }
4044
+ if (account.source) {
4045
+ if (account.source.kind === "pallet") {
4046
+ const bytes = parsePalletId(account.source.palletId);
4047
+ attrs.push({
4048
+ label: "pallet-id",
4049
+ value: `${formatPalletId(bytes)} (${account.source.palletId})`
4050
+ });
4051
+ } else {
4052
+ attrs.push({ label: "parachain", value: String(account.source.paraId) });
4053
+ attrs.push({ label: "parachain-type", value: account.source.type });
4054
+ }
4055
+ }
4056
+ return attrs;
4057
+ }
4058
+ function buildRow(account) {
4059
+ return {
4060
+ account,
4061
+ kind: classifyAccount(account),
4062
+ address: resolveAddress(account),
4063
+ attributes: buildAttributes(account)
4064
+ };
4065
+ }
4066
+ var SECTION_ORDER = [
4067
+ { kind: "signer", title: "Signers" },
4068
+ { kind: "watch-only", title: "Watch-only" },
4069
+ { kind: "pallet", title: "Pallet Sovereigns" },
4070
+ { kind: "parachain", title: "Parachain Sovereigns" }
4071
+ ];
4072
+ function printAccountSection(title, rows) {
4073
+ if (rows.length === 0)
4074
+ return;
4075
+ const nameWidth = Math.max(...rows.map((r) => r.name.length));
4076
+ printHeading(title);
4077
+ for (const row of rows) {
4078
+ const namePad = row.name.padEnd(nameWidth);
4079
+ console.log(` ${CYAN}${namePad}${RESET} ${row.address}`);
4080
+ if (row.attributes.length === 0)
4081
+ continue;
4082
+ const labelWidth = Math.max(...row.attributes.map((a) => a.label.length)) + 1;
4083
+ for (let i = 0;i < row.attributes.length; i++) {
4084
+ const isLast = i === row.attributes.length - 1;
4085
+ const connector = isLast ? "└─" : "├─";
4086
+ const labelText = `${row.attributes[i].label}:`.padEnd(labelWidth + 1);
4087
+ console.log(` ${DIM}${connector}${RESET} ${DIM}${labelText}${RESET}${row.attributes[i].value}`);
4088
+ }
4089
+ }
4090
+ }
3318
4091
  async function accountList(opts = {}) {
3319
4092
  const accountsFile = await loadAccounts();
3320
4093
  if (isJsonOutput(opts)) {
3321
4094
  const dev = DEV_NAMES.map((name) => ({
3322
4095
  name: name.charAt(0).toUpperCase() + name.slice(1),
3323
- address: getDevAddress(name)
4096
+ address: getDevAddress(name),
4097
+ kind: "dev"
3324
4098
  }));
3325
4099
  const stored = accountsFile.accounts.map((account) => {
3326
- let address;
3327
- if (isWatchOnly(account)) {
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 {
4100
+ const kind = classifyAccount(account);
4101
+ const entry = {
3339
4102
  name: account.name,
3340
- address,
3341
- derivationPath: account.derivationPath || undefined,
3342
- watchOnly: isWatchOnly(account),
3343
- env: account.secret !== undefined && isEnvSecret(account.secret) ? account.secret.env : undefined
4103
+ address: resolveAddress(account),
4104
+ kind,
4105
+ watchOnly: isWatchOnly(account)
3344
4106
  };
4107
+ if (account.derivationPath)
4108
+ entry.derivationPath = account.derivationPath;
4109
+ if (account.secret !== undefined && isEnvSecret(account.secret)) {
4110
+ entry.env = account.secret.env;
4111
+ }
4112
+ if (account.source) {
4113
+ if (account.source.kind === "pallet") {
4114
+ const bytes = parsePalletId(account.source.palletId);
4115
+ entry.source = {
4116
+ kind: "pallet",
4117
+ palletId: formatPalletId(bytes),
4118
+ palletIdHex: account.source.palletId
4119
+ };
4120
+ } else {
4121
+ entry.source = account.source;
4122
+ }
4123
+ }
4124
+ return entry;
3345
4125
  });
3346
4126
  console.log(formatJson({ dev, stored }));
3347
4127
  return;
3348
4128
  }
3349
- printHeading("Dev Accounts");
3350
- for (const name of DEV_NAMES) {
3351
- const display = name.charAt(0).toUpperCase() + name.slice(1);
3352
- const address = getDevAddress(name);
3353
- printItem(display, address);
4129
+ const devRows = DEV_NAMES.map((name) => ({
4130
+ name: name.charAt(0).toUpperCase() + name.slice(1),
4131
+ address: getDevAddress(name),
4132
+ attributes: []
4133
+ }));
4134
+ printAccountSection("Dev Accounts", devRows);
4135
+ const buckets = new Map;
4136
+ for (const account of accountsFile.accounts) {
4137
+ const row = buildRow(account);
4138
+ const arr = buckets.get(row.kind) ?? [];
4139
+ arr.push(row);
4140
+ buckets.set(row.kind, arr);
4141
+ }
4142
+ for (const { kind, title } of SECTION_ORDER) {
4143
+ const rows = buckets.get(kind);
4144
+ if (!rows || rows.length === 0)
4145
+ continue;
4146
+ printAccountSection(title, rows.map((r) => ({
4147
+ name: r.account.name,
4148
+ address: r.address,
4149
+ attributes: r.attributes
4150
+ })));
3354
4151
  }
3355
- if (accountsFile.accounts.length > 0) {
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 {
4152
+ if (accountsFile.accounts.length === 0) {
3379
4153
  printHeading("Stored Accounts");
3380
- console.log(" (none)");
4154
+ console.log(` ${DIM}(none)${RESET}`);
3381
4155
  }
3382
4156
  console.log();
3383
4157
  }
@@ -3425,10 +4199,20 @@ async function accountRemove(names, opts = {}) {
3425
4199
  }
3426
4200
  }
3427
4201
  async function accountInspect(input, opts) {
3428
- if (!input) {
4202
+ const sovereignSource = resolveSovereignSource({
4203
+ parachain: opts.parachain,
4204
+ parachainType: opts.parachainType,
4205
+ palletId: opts.palletId
4206
+ });
4207
+ if (sovereignSource && input) {
4208
+ 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.");
4209
+ }
4210
+ if (!sovereignSource && !input) {
3429
4211
  console.error(`Input is required.
3430
4212
  `);
3431
4213
  console.error("Usage: dot account inspect <name|ss58-address|0x-public-key> [--prefix <N>]");
4214
+ console.error(" dot account inspect --pallet-id <id> [--prefix <N>]");
4215
+ console.error(" dot account inspect --parachain <id> --parachain-type <child|sibling> [--prefix <N>]");
3432
4216
  process.exit(1);
3433
4217
  }
3434
4218
  const prefix = opts.prefix != null ? Number(opts.prefix) : 42;
@@ -3440,11 +4224,32 @@ async function accountInspect(input, opts) {
3440
4224
  let publicKeyHex;
3441
4225
  let bandersnatch;
3442
4226
  let hasSecret = false;
3443
- if (isDevAccount(input)) {
4227
+ let storedAccount;
4228
+ let isDev = false;
4229
+ let virtualSource;
4230
+ if (sovereignSource) {
4231
+ if (sovereignSource.kind === "pallet") {
4232
+ const accountId = derivePalletAccount(sovereignSource.palletId);
4233
+ publicKeyHex = publicKeyToHex(accountId);
4234
+ virtualSource = {
4235
+ kind: "pallet",
4236
+ palletIdHex: `0x${Array.from(sovereignSource.palletId, (b) => b.toString(16).padStart(2, "0")).join("")}`
4237
+ };
4238
+ } else {
4239
+ const accountId = deriveSovereignAccount(sovereignSource.paraId, sovereignSource.type);
4240
+ publicKeyHex = publicKeyToHex(accountId);
4241
+ virtualSource = {
4242
+ kind: "parachain",
4243
+ paraId: sovereignSource.paraId,
4244
+ type: sovereignSource.type
4245
+ };
4246
+ }
4247
+ } else if (isDevAccount(input)) {
3444
4248
  name = input.charAt(0).toUpperCase() + input.slice(1).toLowerCase();
3445
4249
  const devAddr = getDevAddress(input);
3446
4250
  publicKeyHex = publicKeyToHex(fromSs58(devAddr));
3447
4251
  hasSecret = true;
4252
+ isDev = true;
3448
4253
  } else {
3449
4254
  const accountsFile = await loadAccounts();
3450
4255
  const account = findAccount(accountsFile, input);
@@ -3452,6 +4257,7 @@ async function accountInspect(input, opts) {
3452
4257
  name = account.name;
3453
4258
  bandersnatch = account.bandersnatch;
3454
4259
  hasSecret = account.secret !== undefined;
4260
+ storedAccount = account;
3455
4261
  if (account.publicKey) {
3456
4262
  publicKeyHex = account.publicKey;
3457
4263
  } else if (account.secret !== undefined && isEnvSecret(account.secret)) {
@@ -3495,10 +4301,74 @@ async function accountInspect(input, opts) {
3495
4301
  process.exit(1);
3496
4302
  }
3497
4303
  }
4304
+ let kindLabel;
4305
+ let sourceLine;
4306
+ let derivationLine;
4307
+ let envLine;
4308
+ if (virtualSource?.kind === "pallet") {
4309
+ kindLabel = "pallet sovereign";
4310
+ const bytes = parsePalletId(virtualSource.palletIdHex);
4311
+ sourceLine = `PalletId ${formatPalletId(bytes)} (${virtualSource.palletIdHex})`;
4312
+ } else if (virtualSource?.kind === "parachain") {
4313
+ kindLabel = `parachain sovereign (${virtualSource.type})`;
4314
+ sourceLine = `parachain ${virtualSource.paraId}`;
4315
+ } else if (isDev) {
4316
+ kindLabel = "dev";
4317
+ } else if (storedAccount) {
4318
+ const k = classifyAccount(storedAccount);
4319
+ if (k === "pallet" && storedAccount.source?.kind === "pallet") {
4320
+ kindLabel = "pallet sovereign";
4321
+ const bytes = parsePalletId(storedAccount.source.palletId);
4322
+ sourceLine = `PalletId ${formatPalletId(bytes)} (${storedAccount.source.palletId})`;
4323
+ } else if (k === "parachain" && storedAccount.source?.kind === "parachain") {
4324
+ kindLabel = `parachain sovereign (${storedAccount.source.type})`;
4325
+ sourceLine = `parachain ${storedAccount.source.paraId}`;
4326
+ } else if (k === "signer") {
4327
+ kindLabel = "signer";
4328
+ } else {
4329
+ kindLabel = "watch-only";
4330
+ }
4331
+ if (storedAccount.derivationPath)
4332
+ derivationLine = storedAccount.derivationPath;
4333
+ if (storedAccount.secret !== undefined && isEnvSecret(storedAccount.secret)) {
4334
+ envLine = `$${storedAccount.secret.env}`;
4335
+ }
4336
+ }
3498
4337
  if (isJsonOutput(opts)) {
3499
4338
  const result = { publicKey: publicKeyHex, ss58, prefix };
3500
4339
  if (name)
3501
4340
  result.name = name;
4341
+ if (kindLabel)
4342
+ result.kind = kindLabel;
4343
+ if (virtualSource?.kind === "pallet") {
4344
+ const bytes = parsePalletId(virtualSource.palletIdHex);
4345
+ result.source = {
4346
+ kind: "pallet",
4347
+ palletId: formatPalletId(bytes),
4348
+ palletIdHex: virtualSource.palletIdHex
4349
+ };
4350
+ } else if (virtualSource?.kind === "parachain") {
4351
+ result.source = {
4352
+ kind: "parachain",
4353
+ paraId: virtualSource.paraId,
4354
+ type: virtualSource.type
4355
+ };
4356
+ } else if (storedAccount?.source) {
4357
+ if (storedAccount.source.kind === "pallet") {
4358
+ const bytes = parsePalletId(storedAccount.source.palletId);
4359
+ result.source = {
4360
+ kind: "pallet",
4361
+ palletId: formatPalletId(bytes),
4362
+ palletIdHex: storedAccount.source.palletId
4363
+ };
4364
+ } else {
4365
+ result.source = storedAccount.source;
4366
+ }
4367
+ }
4368
+ if (derivationLine)
4369
+ result.derivationPath = derivationLine;
4370
+ if (envLine)
4371
+ result.env = envLine.replace(/^\$/, "");
3502
4372
  if (bandersnatch && Object.keys(bandersnatch).length > 0)
3503
4373
  result.bandersnatch = bandersnatch;
3504
4374
  if (privateKeyHex)
@@ -3508,8 +4378,16 @@ async function accountInspect(input, opts) {
3508
4378
  printHeading("Account Info");
3509
4379
  if (name)
3510
4380
  console.log(` ${BOLD}Name:${RESET} ${name}`);
4381
+ if (kindLabel)
4382
+ console.log(` ${BOLD}Kind:${RESET} ${kindLabel}`);
3511
4383
  console.log(` ${BOLD}Public Key:${RESET} ${publicKeyHex}`);
3512
4384
  console.log(` ${BOLD}SS58:${RESET} ${ss58}`);
4385
+ if (sourceLine)
4386
+ console.log(` ${BOLD}Source:${RESET} ${sourceLine}`);
4387
+ if (derivationLine)
4388
+ console.log(` ${BOLD}Derivation:${RESET} ${derivationLine}`);
4389
+ if (envLine)
4390
+ console.log(` ${BOLD}Env:${RESET} ${envLine}`);
3513
4391
  if (bandersnatch && Object.keys(bandersnatch).length > 0) {
3514
4392
  const entries = Object.entries(bandersnatch);
3515
4393
  for (let i = 0;i < entries.length; i++) {
@@ -3813,6 +4691,53 @@ init_client();
3813
4691
  init_metadata();
3814
4692
  init_output();
3815
4693
  import { readFile as readFile4, writeFile as writeFile4 } from "node:fs/promises";
4694
+
4695
+ // src/core/rpc.ts
4696
+ init_errors();
4697
+ import { createClient as createSubstrateClient } from "@polkadot-api/substrate-client";
4698
+ import { getWsProvider as getWsProvider2 } from "polkadot-api/ws";
4699
+ function suppressProviderNoise2() {
4700
+ const origError = console.error;
4701
+ console.error = (...args) => {
4702
+ if (typeof args[0] === "string" && args[0].includes("Unable to connect"))
4703
+ return;
4704
+ origError(...args);
4705
+ };
4706
+ return () => {
4707
+ console.error = origError;
4708
+ };
4709
+ }
4710
+ async function rpcRequest(rpcUrl, method, params, timeoutMs = 30000) {
4711
+ const restoreConsole = suppressProviderNoise2();
4712
+ const provider = getWsProvider2(rpcUrl, { timeout: 1e4 });
4713
+ const client = createSubstrateClient(provider);
4714
+ const controller = new AbortController;
4715
+ const timer = setTimeout(() => controller.abort(), timeoutMs);
4716
+ try {
4717
+ return await client.request(method, params, controller.signal);
4718
+ } catch (err) {
4719
+ if (err instanceof Error && /Unable to connect/i.test(err.message)) {
4720
+ throw new ConnectionError(`Could not reach RPC ${Array.isArray(rpcUrl) ? rpcUrl.join(", ") : rpcUrl}: ${err.message}`);
4721
+ }
4722
+ throw err;
4723
+ } finally {
4724
+ clearTimeout(timer);
4725
+ try {
4726
+ client.destroy();
4727
+ } catch {}
4728
+ setTimeout(restoreConsole, 100);
4729
+ }
4730
+ }
4731
+ async function fetchRpcMethods(rpcUrl) {
4732
+ const result = await rpcRequest(rpcUrl, "rpc_methods", []);
4733
+ if (!result || !Array.isArray(result.methods)) {
4734
+ throw new ConnectionError("Node returned an unexpected response for rpc_methods (no methods array).");
4735
+ }
4736
+ return { methods: result.methods, version: result.version ?? 1 };
4737
+ }
4738
+
4739
+ // src/commands/chain.ts
4740
+ init_rpc_registry();
3816
4741
  var CHAIN_HELP = `
3817
4742
  ${BOLD}Usage:${RESET}
3818
4743
  $ dot chain add <name> --rpc <url> Add a chain via WebSocket RPC
@@ -3881,6 +4806,18 @@ function registerChainCommands(cli) {
3881
4806
  }
3882
4807
  });
3883
4808
  }
4809
+ async function refreshRpcMethods(chainName, rpcUrl, silent = false) {
4810
+ try {
4811
+ const { methods, version: version2 } = await fetchRpcMethods(rpcUrl);
4812
+ await saveRpcMethods(chainName, methods, version2);
4813
+ } catch (err) {
4814
+ if (!silent) {
4815
+ const msg = err instanceof Error ? err.message : String(err);
4816
+ process.stderr.write(`${YELLOW}Warning:${RESET} could not fetch rpc_methods — ${msg}
4817
+ `);
4818
+ }
4819
+ }
4820
+ }
3884
4821
  async function chainAdd(name, opts) {
3885
4822
  if (!name) {
3886
4823
  console.error(`Chain name is required.
@@ -3909,6 +4846,7 @@ async function chainAdd(name, opts) {
3909
4846
  process.stderr.write(`Fetching metadata...
3910
4847
  `);
3911
4848
  await fetchMetadataFromChain(clientHandle, name);
4849
+ await refreshRpcMethods(name, opts.rpc);
3912
4850
  if (opts.relay) {
3913
4851
  const config2 = await loadConfig();
3914
4852
  const relayResolved = findChainName(config2, opts.relay);
@@ -4049,6 +4987,12 @@ async function chainInfo(name, opts = {}) {
4049
4987
  const rpcs = Array.isArray(chain.rpc) ? chain.rpc : [chain.rpc];
4050
4988
  const parachains = Object.entries(config.chains).filter(([, c]) => c.relay === resolved).map(([n, c]) => ({ name: n, parachainId: c.parachainId }));
4051
4989
  const fingerprint = await loadMetadataFingerprint(resolved);
4990
+ const rpcCache = await loadRpcMethods(resolved);
4991
+ const rpcSummary = rpcCache ? {
4992
+ count: rpcCache.methods.length,
4993
+ fetchedAt: rpcCache.fetchedAt,
4994
+ byFamily: countByFamily(rpcCache.methods)
4995
+ } : null;
4052
4996
  if (isJsonOutput(opts)) {
4053
4997
  console.log(formatJson({
4054
4998
  name: resolved,
@@ -4060,7 +5004,8 @@ async function chainInfo(name, opts = {}) {
4060
5004
  specName: fingerprint.specName,
4061
5005
  specVersion: fingerprint.specVersion,
4062
5006
  fetchedAt: fingerprint.fetchedAt
4063
- } : null
5007
+ } : null,
5008
+ rpcMethods: rpcSummary
4064
5009
  }));
4065
5010
  return;
4066
5011
  }
@@ -4088,6 +5033,22 @@ async function chainInfo(name, opts = {}) {
4088
5033
  } else {
4089
5034
  console.log(` ${DIM}not cached — run \`dot chain update ${resolved}\`${RESET}`);
4090
5035
  }
5036
+ console.log(` ${CYAN}rpc methods:${RESET}`);
5037
+ if (rpcSummary) {
5038
+ const families = Object.entries(rpcSummary.byFamily).map(([f, n]) => `${f}: ${n}`).join(", ");
5039
+ console.log(` ${rpcSummary.count} ${DIM}(${families})${RESET}`);
5040
+ console.log(` ${DIM}cached ${rpcSummary.fetchedAt}${RESET}`);
5041
+ } else {
5042
+ console.log(` ${DIM}not cached — run \`dot chain update ${resolved}\`${RESET}`);
5043
+ }
5044
+ }
5045
+ function countByFamily(methods) {
5046
+ const counts = {};
5047
+ for (const m of methods) {
5048
+ const family = RPC_REGISTRY[m]?.family ?? inferFamily(m);
5049
+ counts[family] = (counts[family] ?? 0) + 1;
5050
+ }
5051
+ return counts;
4091
5052
  }
4092
5053
  async function chainUpdate(name, opts) {
4093
5054
  const config = await loadConfig();
@@ -4107,6 +5068,7 @@ async function chainUpdate(name, opts) {
4107
5068
  process.stderr.write(`Fetching metadata...
4108
5069
  `);
4109
5070
  await fetchMetadataFromChain(clientHandle, chainName);
5071
+ await refreshRpcMethods(chainName, opts.rpc ?? chainConfig.rpc);
4110
5072
  if (isJsonOutput(opts)) {
4111
5073
  console.log(formatJson({ action: "updated", chain: chainName }));
4112
5074
  } else {
@@ -4136,6 +5098,7 @@ async function updateChainsMetadata(config, chainNames) {
4136
5098
  const clientHandle = await createChainClient(chainName, chainConfig);
4137
5099
  try {
4138
5100
  await fetchMetadataFromChain(clientHandle, chainName);
5101
+ await refreshRpcMethods(chainName, chainConfig.rpc, true);
4139
5102
  } finally {
4140
5103
  clientHandle.destroy();
4141
5104
  }
@@ -5687,24 +6650,6 @@ function registerMetadataCommand(cli) {
5687
6650
  // src/commands/parachain.ts
5688
6651
  init_accounts();
5689
6652
  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
6653
  init_errors();
5709
6654
  function printParachainHelp() {
5710
6655
  console.log(`${BOLD}Usage:${RESET} dot parachain <paraId> [options]
@@ -5734,6 +6679,7 @@ function validateType(type) {
5734
6679
  }
5735
6680
  function registerParachainCommand(cli) {
5736
6681
  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) => {
6682
+ 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
6683
  if (!paraIdStr) {
5738
6684
  printParachainHelp();
5739
6685
  return;
@@ -5947,6 +6893,168 @@ async function parseStorageKeys(meta, palletName2, storageItem, args) {
5947
6893
  return Promise.all(args.map((arg) => parseTypedArg(meta, keyEntry, arg)));
5948
6894
  }
5949
6895
 
6896
+ // src/commands/rpc.ts
6897
+ init_store();
6898
+ init_output();
6899
+ init_rpc_registry();
6900
+ init_errors();
6901
+ var FAMILY_ORDER = [
6902
+ "system",
6903
+ "chain",
6904
+ "state",
6905
+ "author",
6906
+ "payment",
6907
+ "babe",
6908
+ "grandpa",
6909
+ "beefy",
6910
+ "mmr",
6911
+ "offchain",
6912
+ "dev",
6913
+ "spec",
6914
+ "chainHead",
6915
+ "chainSpec",
6916
+ "transaction",
6917
+ "archive",
6918
+ "other"
6919
+ ];
6920
+ async function getMethodList(chainName, rpcUrl, refresh) {
6921
+ if (!refresh) {
6922
+ const cached = await loadRpcMethods(chainName);
6923
+ if (cached) {
6924
+ return { methods: cached.methods, version: cached.version, fromCache: true };
6925
+ }
6926
+ }
6927
+ const fresh = await fetchRpcMethods(rpcUrl);
6928
+ await saveRpcMethods(chainName, fresh.methods, fresh.version);
6929
+ return { methods: fresh.methods, version: fresh.version, fromCache: false };
6930
+ }
6931
+ function groupByFamily(methods) {
6932
+ const groups = new Map;
6933
+ for (const m of methods) {
6934
+ const family = RPC_REGISTRY[m]?.family ?? inferFamily(m);
6935
+ const list = groups.get(family) ?? [];
6936
+ list.push(m);
6937
+ groups.set(family, list);
6938
+ }
6939
+ for (const list of groups.values())
6940
+ list.sort();
6941
+ return groups;
6942
+ }
6943
+ function formatArgs(info) {
6944
+ if (info.args.length === 0)
6945
+ return "(no args)";
6946
+ return info.args.map((a) => `<${a.name}: ${a.type}${a.optional ? "?" : ""}>`).join(" ");
6947
+ }
6948
+ function printMethodHelp(method, info) {
6949
+ console.log();
6950
+ console.log(`${BOLD}${method}${RESET}`);
6951
+ if (info) {
6952
+ if (info.dangerous) {
6953
+ console.log(` ${YELLOW}⚠️ WRITE / state-changing${RESET}`);
6954
+ }
6955
+ if (info.subscription) {
6956
+ console.log(` ${DIM}subscription — not callable as a one-shot${RESET}`);
6957
+ }
6958
+ console.log(` ${info.description}`);
6959
+ console.log();
6960
+ console.log(` ${DIM}Family:${RESET} ${info.family}`);
6961
+ console.log(` ${DIM}Args:${RESET} ${formatArgs(info)}`);
6962
+ if (info.args.some((a) => a.description)) {
6963
+ console.log();
6964
+ for (const a of info.args) {
6965
+ if (a.description) {
6966
+ console.log(` ${CYAN}${a.name}${RESET} ${DIM}${a.description}${RESET}`);
6967
+ }
6968
+ }
6969
+ }
6970
+ } else {
6971
+ console.log(` ${DIM}No curated metadata. Args are passed through as raw JSON-RPC params.${RESET}`);
6972
+ console.log(` ${DIM}Family:${RESET} ${inferFamily(method)} (inferred)`);
6973
+ }
6974
+ console.log();
6975
+ }
6976
+ async function listMethods(chainName, rpcUrl, opts) {
6977
+ const { methods, version: version2, fromCache } = await getMethodList(chainName, rpcUrl, opts.refresh ?? false);
6978
+ if (isJsonOutput(opts)) {
6979
+ console.log(formatJson({
6980
+ chain: chainName,
6981
+ version: version2,
6982
+ fromCache,
6983
+ methods: methods.map((m) => {
6984
+ const info = RPC_REGISTRY[m];
6985
+ return {
6986
+ method: m,
6987
+ family: info?.family ?? inferFamily(m),
6988
+ description: info?.description,
6989
+ dangerous: info?.dangerous ?? false,
6990
+ subscription: info?.subscription ?? false
6991
+ };
6992
+ })
6993
+ }));
6994
+ return;
6995
+ }
6996
+ printHeading(`RPC methods on ${chainName} (${methods.length})`);
6997
+ const groups = groupByFamily(methods);
6998
+ for (const family of FAMILY_ORDER) {
6999
+ const list = groups.get(family);
7000
+ if (!list || list.length === 0)
7001
+ continue;
7002
+ console.log(`${BOLD}${family}${RESET} ${DIM}(${list.length})${RESET}`);
7003
+ for (const m of list) {
7004
+ const info = RPC_REGISTRY[m];
7005
+ const tags = [];
7006
+ if (info?.dangerous)
7007
+ tags.push(`${YELLOW}⚠ write${RESET}`);
7008
+ if (info?.subscription)
7009
+ tags.push(`${DIM}sub${RESET}`);
7010
+ const suffix = tags.length > 0 ? ` ${tags.join(" ")}` : "";
7011
+ const desc = info?.description ? ` ${DIM}${info.description}${RESET}` : "";
7012
+ console.log(` ${CYAN}${m}${RESET}${suffix}${desc}`);
7013
+ }
7014
+ console.log();
7015
+ }
7016
+ if (!fromCache) {
7017
+ console.log(`${DIM}(fetched from node — cached for next run)${RESET}`);
7018
+ }
7019
+ }
7020
+ async function handleRpc(method, args, opts) {
7021
+ const config = await loadConfig();
7022
+ const { name: chainName, chain: chainConfig } = resolveChain(config, opts.chain);
7023
+ const rpcUrl = opts.rpc ?? chainConfig.rpc;
7024
+ if (!rpcUrl) {
7025
+ throw new CliError(`No RPC endpoint for chain "${chainName}". Pass --rpc or run \`dot chain add ${chainName} --rpc <url>\`.`);
7026
+ }
7027
+ if (!method) {
7028
+ await listMethods(chainName, rpcUrl, opts);
7029
+ return;
7030
+ }
7031
+ const info = RPC_REGISTRY[method];
7032
+ if (opts.help) {
7033
+ printMethodHelp(method, info);
7034
+ return;
7035
+ }
7036
+ const { methods: knownMethods } = await getMethodList(chainName, rpcUrl, opts.refresh ?? false);
7037
+ if (!knownMethods.includes(method)) {
7038
+ const hint = suggestMessage("method", method, knownMethods);
7039
+ 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.`);
7040
+ }
7041
+ if (info?.subscription) {
7042
+ 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.`);
7043
+ }
7044
+ if (!info && /(_subscribe|_unsubscribe)/.test(method)) {
7045
+ 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.`);
7046
+ }
7047
+ if (info) {
7048
+ const required = info.args.filter((a) => !a.optional).length;
7049
+ if (args.length < required) {
7050
+ throw new CliError(`"${method}" expects at least ${required} argument(s) (${formatArgs(info)}); got ${args.length}.`);
7051
+ }
7052
+ }
7053
+ const params = args.map(parseValue);
7054
+ const result = await rpcRequest(rpcUrl, method, params);
7055
+ printResult(result, isJsonOutput(opts) ? "json" : opts.output);
7056
+ }
7057
+
5950
7058
  // src/commands/sign.ts
5951
7059
  init_accounts();
5952
7060
  init_hash();
@@ -7946,7 +9054,8 @@ var CATEGORY_ALIASES = {
7946
9054
  api: "apis",
7947
9055
  extensions: "extensions",
7948
9056
  extension: "extensions",
7949
- ext: "extensions"
9057
+ ext: "extensions",
9058
+ rpc: "rpc"
7950
9059
  };
7951
9060
  function matchCategory(segment) {
7952
9061
  return CATEGORY_ALIASES[segment.toLowerCase()];
@@ -7961,7 +9070,7 @@ function parseDotPath(input, knownChains = []) {
7961
9070
  const cat = matchCategory(parts[0]);
7962
9071
  if (cat)
7963
9072
  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.`);
9073
+ throw new Error(`Unknown command "${parts[0]}". Expected a category (query, tx, const, events, errors, apis, extensions, rpc) or a named command.`);
7965
9074
  }
7966
9075
  case 2: {
7967
9076
  const cat = matchCategory(parts[0]);
@@ -8043,6 +9152,7 @@ if (process.argv[2] === "__complete") {
8043
9152
  console.log(" errors List or inspect pallet errors");
8044
9153
  console.log(" apis Browse and call runtime APIs");
8045
9154
  console.log(" extensions List transaction extensions on a chain");
9155
+ console.log(" rpc Call raw JSON-RPC methods on a node");
8046
9156
  console.log();
8047
9157
  console.log("Examples:");
8048
9158
  console.log(" dot polkadot.query.System.Account <addr> Query a storage item");
@@ -8055,6 +9165,8 @@ if (process.argv[2] === "__complete") {
8055
9165
  console.log(" dot metadata polkadot Dump runtime metadata as JSON");
8056
9166
  console.log(" dot polkadot.extensions List transaction extensions");
8057
9167
  console.log(" dot polkadot.extensions.CheckMortality Inspect one extension");
9168
+ console.log(" dot polkadot.rpc List RPC methods on the node");
9169
+ console.log(" dot polkadot.rpc.system_health Call a JSON-RPC method");
8058
9170
  console.log(" dot query.System.Number --chain polkadot --chain flag form");
8059
9171
  console.log(" dot ./transfer.yaml --from alice Run from file (chain in YAML)");
8060
9172
  console.log(" dot tx.0x1f0003... --to-yaml --chain polkadot Decode hex call to YAML");
@@ -8068,7 +9180,7 @@ if (process.argv[2] === "__complete") {
8068
9180
  console.log(" account Manage accounts");
8069
9181
  console.log(" hash Hash utilities");
8070
9182
  console.log(" sign Sign a message with an account keypair");
8071
- console.log(" parachain Derive parachain sovereign accounts");
9183
+ console.log(" parachain Derive parachain sovereign accounts (deprecated \u2014 use `account inspect --parachain`)");
8072
9184
  console.log(" verifiable Derive Bandersnatch member key from mnemonic");
8073
9185
  console.log(" completions <sh> Generate shell completions (zsh, bash, fish)");
8074
9186
  console.log();
@@ -8099,7 +9211,7 @@ if (process.argv[2] === "__complete") {
8099
9211
  registerVerifiableCommands(cli);
8100
9212
  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
9213
  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 (for tx)').option("--unsigned", "Submit as unsigned/bare transaction (no signer required, for tx)").action(async (dotpath, args, opts) => {
9214
+ }).option("--dump", "Dump all entries of a storage map (without specifying a key)").option("--var <kv>", "Template variable for file input (KEY=VALUE, repeatable)").option("--nonce <n>", "Custom nonce for manual tx sequencing (for tx)").option("--tip <amount>", "Tip to prioritize transaction (for tx)").option("--mortality <spec>", '"immortal" or period number (for tx)').option("--at <block>", 'Block hash, "best", or "finalized" to validate against (for tx)').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
9215
  if (!dotpath) {
8104
9216
  printHelp();
8105
9217
  return;
@@ -8162,9 +9274,10 @@ if (process.argv[2] === "__complete") {
8162
9274
  } catch {
8163
9275
  throw new CliError2(`Unknown command "${dotpath}". Run "dot --help" for available commands.`);
8164
9276
  }
9277
+ const isFlatCategory = parsed.category === "rpc" || parsed.category === "extensions";
8165
9278
  if (!parsed.pallet && args.length > 0) {
8166
9279
  parsed.pallet = args.shift();
8167
- if (!parsed.item && args.length > 0) {
9280
+ if (!isFlatCategory && !parsed.item && args.length > 0) {
8168
9281
  parsed.item = args.shift();
8169
9282
  }
8170
9283
  }
@@ -8231,6 +9344,18 @@ if (process.argv[2] === "__complete") {
8231
9344
  await handleExtensions(parsed.pallet, handlerOpts);
8232
9345
  break;
8233
9346
  }
9347
+ case "rpc": {
9348
+ if (parsed.item) {
9349
+ 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>`;
9350
+ throw new CliError2(`RPC methods have no sub-items. Try "${suggestion}".`);
9351
+ }
9352
+ await handleRpc(parsed.pallet, args, {
9353
+ ...handlerOpts,
9354
+ help: cli.options.help,
9355
+ refresh: opts.refresh
9356
+ });
9357
+ break;
9358
+ }
8234
9359
  }
8235
9360
  });
8236
9361
  cli.option("--help, -h", "Display this message");