polkadot-cli 0.4.0 → 0.5.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 +64 -37
  2. package/dist/cli.mjs +96 -27
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # polkadot-cli
2
2
 
3
- A command-line tool for interacting with Polkadot-ecosystem chains. Query storage, look up constants, inspect metadata, manage accounts, and submit extrinsics — all from your terminal.
3
+ A command-line tool for interacting with Polkadot-ecosystem chains. Manage chains and accounts, query storage, look up constants, inspect metadata, and submit extrinsics — all from your terminal.
4
4
 
5
5
  Ships with Polkadot as the default chain. Add any Substrate-based chain by pointing to its RPC endpoint.
6
6
 
@@ -14,6 +14,48 @@ This installs the `dot` command globally.
14
14
 
15
15
  ## Usage
16
16
 
17
+ ### Manage chains
18
+
19
+ ```bash
20
+ # Add a chain
21
+ dot chain add kusama --rpc wss://kusama-rpc.polkadot.io
22
+ dot chain add westend --light-client
23
+
24
+ # List configured chains
25
+ dot chain list
26
+
27
+ # Re-fetch metadata after a runtime upgrade
28
+ dot chain update # updates default chain
29
+ dot chain update kusama # updates a specific chain
30
+
31
+ # Set default chain
32
+ dot chain default kusama
33
+
34
+ # Remove a chain
35
+ dot chain remove westend
36
+ ```
37
+
38
+ ### Manage accounts
39
+
40
+ Dev accounts (Alice, Bob, Charlie, Dave, Eve, Ferdie) are always available for testnets. Create or import your own accounts for any chain.
41
+
42
+ ```bash
43
+ # List all accounts (dev + stored)
44
+ dot account list
45
+
46
+ # Create a new account (generates a mnemonic)
47
+ dot account create my-validator
48
+
49
+ # Import from a BIP39 mnemonic
50
+ dot account import treasury --secret "word1 word2 ... word12"
51
+
52
+ # Import from a hex seed
53
+ dot account import raw-key --secret 0xabcdef...
54
+
55
+ # Remove an account
56
+ dot account remove my-validator
57
+ ```
58
+
17
59
  ### Query storage
18
60
 
19
61
  ```bash
@@ -52,30 +94,9 @@ dot inspect System
52
94
  dot inspect System.Account
53
95
  ```
54
96
 
55
- ### Manage accounts
56
-
57
- Dev accounts (Alice, Bob, Charlie, Dave, Eve, Ferdie) are always available for testnets. Create or import your own accounts for any chain.
58
-
59
- ```bash
60
- # List all accounts (dev + stored)
61
- dot account list
62
-
63
- # Create a new account (generates a mnemonic)
64
- dot account create my-validator
65
-
66
- # Import from a BIP39 mnemonic
67
- dot account import treasury --secret "word1 word2 ... word12"
68
-
69
- # Import from a hex seed
70
- dot account import raw-key --secret 0xabcdef...
71
-
72
- # Remove an account
73
- dot account remove my-validator
74
- ```
75
-
76
97
  ### Submit extrinsics
77
98
 
78
- Build, sign, and submit transactions. Arguments are parsed from metadata the CLI knows the expected types for each call.
99
+ Build, sign, and submit transactions. Pass a `Pallet.Call` with arguments, or a raw SCALE-encoded call hex (e.g. from a multisig proposal or governance). Both forms display a decoded human-readable representation of the call.
79
100
 
80
101
  ```bash
81
102
  # Simple remark
@@ -87,29 +108,35 @@ dot tx Balances.transferKeepAlive 5FHneW46xGXgs5mUiveU4sbTyGBzmstUspZC92UhjJM694
87
108
  # Estimate fees without submitting
88
109
  dot tx Balances.transferKeepAlive 5FHneW46xGXgs5mUiveU4sbTyGBzmstUspZC92UhjJM694ty 1000000000000 --from alice --dry-run
89
110
 
111
+ # Submit a raw SCALE-encoded call (e.g. from a multisig proposal or another tool)
112
+ dot tx 0x0503008eaf04151687736326c9fea17e25fc5287613693c912909cb226aa4794f26a48 --from alice
113
+
90
114
  # Batch multiple transfers with Utility.batchAll
91
115
  dot tx Utility.batchAll '[{"type":"Balances","value":{"type":"transfer_keep_alive","value":{"dest":"5FHneW46xGXgs5mUiveU4sbTyGBzmstUspZC92UhjJM694ty","value":1000000000000}}},{"type":"Balances","value":{"type":"transfer_keep_alive","value":{"dest":"5FLSigC9HGRKVhB9FiEo4Y3koPsNmBmLJbpXg2mp1hXcS59Y","value":2000000000000}}}]' --from alice
92
116
  ```
93
117
 
94
- ### Manage chains
118
+ Both dry-run and submission display the encoded call hex and a decoded human-readable form:
95
119
 
96
- ```bash
97
- # Add a chain
98
- dot chain add kusama --rpc wss://kusama-rpc.polkadot.io
99
- dot chain add westend --light-client
120
+ ```
121
+ Call: 0x0001076465616462656566
122
+ Decode: System.remark(remark: 0xdeadbeef)
123
+ Tx: 0xabc123...
124
+ Block: #12345678 (0xdef...)
125
+ Status: ok
126
+ ```
100
127
 
101
- # List configured chains
102
- dot chain list
128
+ #### Custom signed extensions
103
129
 
104
- # Re-fetch metadata after a runtime upgrade
105
- dot chain update # updates default chain
106
- dot chain update kusama # updates a specific chain
130
+ Chains with non-standard signed extensions (e.g. `people-preview`) are auto-handled:
107
131
 
108
- # Set default chain
109
- dot chain default kusama
132
+ - `void` empty bytes
133
+ - `Option<T>` `None`
134
+ - enum with `Disabled` variant → `Disabled`
110
135
 
111
- # Remove a chain
112
- dot chain remove westend
136
+ For manual override, use `--ext` with a JSON object:
137
+
138
+ ```bash
139
+ dot tx System.remark 0xdeadbeef --from alice --ext '{"MyExtension":{"value":"..."}}'
113
140
  ```
114
141
 
115
142
  ### Global options
package/dist/cli.mjs CHANGED
@@ -1,21 +1,5 @@
1
1
  #!/usr/bin/env node
2
2
  import { createRequire } from "node:module";
3
- var __create = Object.create;
4
- var __getProtoOf = Object.getPrototypeOf;
5
- var __defProp = Object.defineProperty;
6
- var __getOwnPropNames = Object.getOwnPropertyNames;
7
- var __hasOwnProp = Object.prototype.hasOwnProperty;
8
- var __toESM = (mod, isNodeMode, target) => {
9
- target = mod != null ? __create(__getProtoOf(mod)) : {};
10
- const to = isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target;
11
- for (let key of __getOwnPropNames(mod))
12
- if (!__hasOwnProp.call(to, key))
13
- __defProp(to, key, {
14
- get: () => mod[key],
15
- enumerable: true
16
- });
17
- return to;
18
- };
19
3
  var __require = /* @__PURE__ */ createRequire(import.meta.url);
20
4
 
21
5
  // src/cli.ts
@@ -388,6 +372,38 @@ function printDocs(docs) {
388
372
  console.log(` ${DIM}${text}${RESET}`);
389
373
  }
390
374
  }
375
+ var CHECK_MARK = "✓";
376
+ var SPINNER_FRAMES = ["⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"];
377
+
378
+ class Spinner {
379
+ timer = null;
380
+ frame = 0;
381
+ start(msg) {
382
+ this.stop();
383
+ if (!isTTY) {
384
+ console.log(msg);
385
+ return;
386
+ }
387
+ process.stdout.write(`${SPINNER_FRAMES[0]} ${msg}`);
388
+ this.timer = setInterval(() => {
389
+ this.frame = (this.frame + 1) % SPINNER_FRAMES.length;
390
+ process.stdout.write(`\r\x1B[K${SPINNER_FRAMES[this.frame]} ${msg}`);
391
+ }, 80);
392
+ }
393
+ stop() {
394
+ if (this.timer !== null) {
395
+ clearInterval(this.timer);
396
+ this.timer = null;
397
+ this.frame = 0;
398
+ if (isTTY)
399
+ process.stdout.write("\r\x1B[K");
400
+ }
401
+ }
402
+ succeed(msg) {
403
+ this.stop();
404
+ console.log(`${GREEN}${CHECK_MARK}${RESET} ${msg}`);
405
+ }
406
+ }
391
407
 
392
408
  // src/commands/chain.ts
393
409
  var CHAIN_HELP = `
@@ -1069,6 +1085,12 @@ async function accountRemove(name) {
1069
1085
  // src/commands/tx.ts
1070
1086
  import { Binary } from "polkadot-api";
1071
1087
  import { getViewBuilder } from "@polkadot-api/view-builder";
1088
+
1089
+ // src/core/explorers.ts
1090
+ var pjsAppsLink = (rpc, hash) => `https://polkadot.js.org/apps/?rpc=${encodeURIComponent(rpc)}#/explorer/query/${hash}`;
1091
+ var papiLink = (rpc, hash) => `https://dev.papi.how/explorer/${hash}#networkId=custom&endpoint=${encodeURIComponent(rpc)}`;
1092
+
1093
+ // src/commands/tx.ts
1072
1094
  function registerTxCommand(cli) {
1073
1095
  cli.command("tx [target] [...args]", "Submit an extrinsic (e.g. Balances.transferKeepAlive <dest> <amount>)").option("--from <name>", "Account to sign with (required)").option("--dry-run", "Estimate fees without submitting").option("--ext <json>", `Custom signed extension values as JSON, e.g. '{"ExtName":{"value":...}}'`).action(async (target, args, opts) => {
1074
1096
  if (!target || !opts.from) {
@@ -1133,20 +1155,17 @@ function registerTxCommand(cli) {
1133
1155
  }
1134
1156
  return;
1135
1157
  }
1136
- console.log("Signing and submitting...");
1137
- const result = await tx.signAndSubmit(signer, txOptions);
1158
+ const result = await watchTransaction(tx.signSubmitAndWatch(signer, txOptions));
1138
1159
  console.log();
1139
1160
  console.log(` ${BOLD}Call:${RESET} ${callHex}`);
1140
1161
  console.log(` ${BOLD}Decode:${RESET} ${decodedStr}`);
1141
1162
  console.log(` ${BOLD}Tx:${RESET} ${result.txHash}`);
1142
- if (result.block) {
1143
- console.log(` ${BOLD}Block:${RESET} #${result.block.number} (${result.block.hash})`);
1144
- }
1145
- if (result.dispatchError) {
1163
+ console.log(` ${BOLD}Block:${RESET} #${result.block.number} (${result.block.hash})`);
1164
+ if (result.ok) {
1165
+ console.log(` ${BOLD}Status:${RESET} ${GREEN}ok${RESET}`);
1166
+ } else {
1146
1167
  console.log(` ${BOLD}Status:${RESET} ${YELLOW}dispatch error${RESET}`);
1147
1168
  console.log(` ${BOLD}Error:${RESET} ${result.dispatchError.type}${result.dispatchError.value ? ": " + JSON.stringify(result.dispatchError.value) : ""}`);
1148
- } else {
1149
- console.log(` ${BOLD}Status:${RESET} ${GREEN}ok${RESET}`);
1150
1169
  }
1151
1170
  if (result.events && result.events.length > 0) {
1152
1171
  console.log(` ${BOLD}Events:${RESET}`);
@@ -1161,6 +1180,13 @@ function registerTxCommand(cli) {
1161
1180
  }
1162
1181
  }
1163
1182
  }
1183
+ const rpcUrl = opts.rpc ?? chainConfig.rpc;
1184
+ if (rpcUrl) {
1185
+ const blockHash = result.block.hash;
1186
+ console.log(` ${BOLD}Explorer:${RESET}`);
1187
+ console.log(` ${DIM}PolkadotJS${RESET} ${pjsAppsLink(rpcUrl, blockHash)}`);
1188
+ console.log(` ${DIM}PAPI${RESET} ${papiLink(rpcUrl, blockHash)}`);
1189
+ }
1164
1190
  console.log();
1165
1191
  } finally {
1166
1192
  clientHandle.destroy();
@@ -1489,6 +1515,43 @@ function autoDefaultForType(entry) {
1489
1515
  }
1490
1516
  return NO_DEFAULT;
1491
1517
  }
1518
+ function watchTransaction(observable) {
1519
+ const spinner = new Spinner;
1520
+ return new Promise((resolve, reject) => {
1521
+ spinner.start("Signing...");
1522
+ observable.subscribe({
1523
+ next(event) {
1524
+ switch (event.type) {
1525
+ case "signed":
1526
+ spinner.succeed("Signed");
1527
+ console.log(` ${BOLD}Tx:${RESET} ${event.txHash}`);
1528
+ spinner.start("Broadcasting...");
1529
+ break;
1530
+ case "broadcasted":
1531
+ spinner.succeed("Broadcasted");
1532
+ spinner.start("In best block...");
1533
+ break;
1534
+ case "txBestBlocksState":
1535
+ if (event.found) {
1536
+ spinner.succeed(`In best block #${event.block.number}`);
1537
+ spinner.start("Finalizing...");
1538
+ } else {
1539
+ spinner.start("In best block...");
1540
+ }
1541
+ break;
1542
+ case "finalized":
1543
+ spinner.stop();
1544
+ resolve(event);
1545
+ break;
1546
+ }
1547
+ },
1548
+ error(err) {
1549
+ spinner.stop();
1550
+ reject(err);
1551
+ }
1552
+ });
1553
+ });
1554
+ }
1492
1555
 
1493
1556
  // src/utils/errors.ts
1494
1557
  class CliError2 extends Error {
@@ -1497,6 +1560,8 @@ class CliError2 extends Error {
1497
1560
  this.name = "CliError";
1498
1561
  }
1499
1562
  }
1563
+ // package.json
1564
+ var version = "0.5.0";
1500
1565
 
1501
1566
  // src/cli.ts
1502
1567
  var cli = cac("dot");
@@ -1513,7 +1578,7 @@ registerConstCommand(cli);
1513
1578
  registerAccountCommands(cli);
1514
1579
  registerTxCommand(cli);
1515
1580
  cli.help();
1516
- cli.version("0.3.0");
1581
+ cli.version(version);
1517
1582
  function handleError(err) {
1518
1583
  if (err instanceof CliError2) {
1519
1584
  console.error(`Error: ${err.message}`);
@@ -1524,11 +1589,15 @@ function handleError(err) {
1524
1589
  }
1525
1590
  process.exit(1);
1526
1591
  }
1527
- process.on("unhandledRejection", handleError);
1528
1592
  try {
1529
- cli.parse();
1593
+ cli.parse(process.argv, { run: false });
1530
1594
  if (!cli.matchedCommandName && !cli.options.help && !cli.options.version) {
1531
1595
  cli.outputHelp();
1596
+ } else {
1597
+ const result = cli.runMatchedCommand();
1598
+ if (result && typeof result.then === "function") {
1599
+ result.then(() => process.exit(0), handleError);
1600
+ }
1532
1601
  }
1533
1602
  } catch (err) {
1534
1603
  handleError(err);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "polkadot-cli",
3
- "version": "0.4.0",
3
+ "version": "0.5.0",
4
4
  "description": "CLI tool for querying Polkadot-ecosystem on-chain state",
5
5
  "type": "module",
6
6
  "bin": {