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.
- package/README.md +64 -37
- package/dist/cli.mjs +96 -27
- 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.
|
|
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.
|
|
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
|
-
|
|
118
|
+
Both dry-run and submission display the encoded call hex and a decoded human-readable form:
|
|
95
119
|
|
|
96
|
-
```
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
120
|
+
```
|
|
121
|
+
Call: 0x0001076465616462656566
|
|
122
|
+
Decode: System.remark(remark: 0xdeadbeef)
|
|
123
|
+
Tx: 0xabc123...
|
|
124
|
+
Block: #12345678 (0xdef...)
|
|
125
|
+
Status: ok
|
|
126
|
+
```
|
|
100
127
|
|
|
101
|
-
|
|
102
|
-
dot chain list
|
|
128
|
+
#### Custom signed extensions
|
|
103
129
|
|
|
104
|
-
|
|
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
|
-
|
|
109
|
-
|
|
132
|
+
- `void` → empty bytes
|
|
133
|
+
- `Option<T>` → `None`
|
|
134
|
+
- enum with `Disabled` variant → `Disabled`
|
|
110
135
|
|
|
111
|
-
|
|
112
|
-
|
|
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
|
-
|
|
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
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
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(
|
|
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);
|