polkadot-cli 0.7.0 → 0.8.1
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 +29 -1
- package/dist/cli.mjs +89 -26
- package/package.json +3 -2
package/README.md
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
[](https://codecov.io/gh/peetzweg/polkadot-cli)
|
|
2
|
+
|
|
1
3
|
# polkadot-cli
|
|
2
4
|
|
|
3
5
|
A command-line tool for interacting with Polkadot-ecosystem chains. Manage chains and accounts, query storage, look up constants, inspect metadata, submit extrinsics, and compute hashes — all from your terminal.
|
|
@@ -66,6 +68,20 @@ dot account remove my-validator
|
|
|
66
68
|
|
|
67
69
|
**Known limitation:** Hex seed import (`--secret 0x...`) does not work from the command line. The CLI argument parser (`cac`) interprets `0x`-prefixed values as JavaScript numbers, which loses precision for 32-byte seeds. Use a BIP39 mnemonic instead. If you need to import a raw seed programmatically, write it directly to `~/.polkadot/accounts.json`.
|
|
68
70
|
|
|
71
|
+
### Chain prefix
|
|
72
|
+
|
|
73
|
+
Instead of the `--chain` flag, you can prefix any target with the chain name using dot notation:
|
|
74
|
+
|
|
75
|
+
```bash
|
|
76
|
+
dot query kusama.System.Account 5GrwvaEF...
|
|
77
|
+
dot const kusama.Balances.ExistentialDeposit
|
|
78
|
+
dot tx kusama.Balances.transferKeepAlive 5FHneW46... 1000000000000 --from alice
|
|
79
|
+
dot inspect kusama.System
|
|
80
|
+
dot inspect kusama.System.Account
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
The `--chain` flag and default chain still work as before. If both a chain prefix and `--chain` flag are provided, the CLI errors.
|
|
84
|
+
|
|
69
85
|
### Query storage
|
|
70
86
|
|
|
71
87
|
```bash
|
|
@@ -78,8 +94,12 @@ dot query System.Account 5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY
|
|
|
78
94
|
# All map entries (default limit: 100)
|
|
79
95
|
dot query System.Account --limit 10
|
|
80
96
|
|
|
81
|
-
# Pipe to jq
|
|
97
|
+
# Pipe to jq — stdout is clean JSON, no extra text
|
|
82
98
|
dot query System.Account --limit 5 | jq '.[0].value.data.free'
|
|
99
|
+
dot query System.Number --output json | jq '.+1'
|
|
100
|
+
|
|
101
|
+
# Query a specific chain using chain prefix
|
|
102
|
+
dot query kusama.System.Account 5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY
|
|
83
103
|
```
|
|
84
104
|
|
|
85
105
|
### Look up constants
|
|
@@ -87,6 +107,10 @@ dot query System.Account --limit 5 | jq '.[0].value.data.free'
|
|
|
87
107
|
```bash
|
|
88
108
|
dot const Balances.ExistentialDeposit
|
|
89
109
|
dot const System.SS58Prefix --chain kusama
|
|
110
|
+
dot const kusama.Balances.ExistentialDeposit
|
|
111
|
+
|
|
112
|
+
# Pipe to jq — stdout is clean JSON, no extra text
|
|
113
|
+
dot const Balances.ExistentialDeposit --output json | jq
|
|
90
114
|
```
|
|
91
115
|
|
|
92
116
|
### Inspect metadata
|
|
@@ -102,6 +126,10 @@ dot inspect System
|
|
|
102
126
|
|
|
103
127
|
# Detailed type info for a specific item
|
|
104
128
|
dot inspect System.Account
|
|
129
|
+
|
|
130
|
+
# Inspect a specific chain using chain prefix
|
|
131
|
+
dot inspect kusama.System
|
|
132
|
+
dot inspect kusama.System.Account
|
|
105
133
|
```
|
|
106
134
|
|
|
107
135
|
### Submit extrinsics
|
package/dist/cli.mjs
CHANGED
|
@@ -5,7 +5,7 @@ var __require = /* @__PURE__ */ createRequire(import.meta.url);
|
|
|
5
5
|
// src/cli.ts
|
|
6
6
|
import cac from "cac";
|
|
7
7
|
// package.json
|
|
8
|
-
var version = "0.
|
|
8
|
+
var version = "0.8.1";
|
|
9
9
|
|
|
10
10
|
// src/config/accounts-store.ts
|
|
11
11
|
import { access as access2, mkdir as mkdir2, readFile as readFile2, writeFile as writeFile2 } from "node:fs/promises";
|
|
@@ -848,28 +848,73 @@ function suggestMessage(kind, input, candidates) {
|
|
|
848
848
|
}
|
|
849
849
|
|
|
850
850
|
// src/utils/parse-target.ts
|
|
851
|
-
function parseTarget(input) {
|
|
851
|
+
function parseTarget(input, options) {
|
|
852
852
|
const parts = input.split(".");
|
|
853
|
-
if (
|
|
854
|
-
|
|
853
|
+
if (options?.allowPalletOnly) {
|
|
854
|
+
switch (parts.length) {
|
|
855
|
+
case 1:
|
|
856
|
+
if (!parts[0]) {
|
|
857
|
+
throw new Error(`Invalid target "${input}". Expected format: Pallet or Pallet.Item (e.g. System or System.Account)`);
|
|
858
|
+
}
|
|
859
|
+
return { pallet: parts[0] };
|
|
860
|
+
case 2:
|
|
861
|
+
if (!parts[0] || !parts[1]) {
|
|
862
|
+
throw new Error(`Invalid target "${input}". Expected format: Pallet.Item or Chain.Pallet (e.g. System.Account or kusama.System)`);
|
|
863
|
+
}
|
|
864
|
+
if (options.knownChains?.some((c) => c.toLowerCase() === parts[0].toLowerCase())) {
|
|
865
|
+
return { chain: parts[0], pallet: parts[1] };
|
|
866
|
+
}
|
|
867
|
+
return { pallet: parts[0], item: parts[1] };
|
|
868
|
+
case 3:
|
|
869
|
+
if (!parts[0] || !parts[1] || !parts[2]) {
|
|
870
|
+
throw new Error(`Invalid target "${input}". Expected format: Chain.Pallet.Item (e.g. kusama.System.Account)`);
|
|
871
|
+
}
|
|
872
|
+
return { chain: parts[0], pallet: parts[1], item: parts[2] };
|
|
873
|
+
default:
|
|
874
|
+
throw new Error(`Invalid target "${input}". Expected format: Pallet, Pallet.Item, or Chain.Pallet.Item`);
|
|
875
|
+
}
|
|
876
|
+
}
|
|
877
|
+
switch (parts.length) {
|
|
878
|
+
case 2:
|
|
879
|
+
if (!parts[0] || !parts[1]) {
|
|
880
|
+
throw new Error(`Invalid target "${input}". Expected format: Pallet.Item (e.g. System.Account)`);
|
|
881
|
+
}
|
|
882
|
+
return { pallet: parts[0], item: parts[1] };
|
|
883
|
+
case 3:
|
|
884
|
+
if (!parts[0] || !parts[1] || !parts[2]) {
|
|
885
|
+
throw new Error(`Invalid target "${input}". Expected format: Chain.Pallet.Item (e.g. kusama.System.Account)`);
|
|
886
|
+
}
|
|
887
|
+
return { chain: parts[0], pallet: parts[1], item: parts[2] };
|
|
888
|
+
default:
|
|
889
|
+
throw new Error(`Invalid target "${input}". Expected format: Pallet.Item (e.g. System.Account)`);
|
|
890
|
+
}
|
|
891
|
+
}
|
|
892
|
+
function resolveTargetChain(target, chainFlag) {
|
|
893
|
+
if (target.chain && chainFlag) {
|
|
894
|
+
throw new Error(`Chain specified both as prefix ("${target.chain}") and as --chain flag ("${chainFlag}"). Use one or the other.`);
|
|
855
895
|
}
|
|
856
|
-
return
|
|
896
|
+
return target.chain ?? chainFlag;
|
|
857
897
|
}
|
|
858
898
|
|
|
859
899
|
// src/commands/const.ts
|
|
860
900
|
function registerConstCommand(cli) {
|
|
861
901
|
cli.command("const [target]", "Look up a pallet constant (e.g. Balances.ExistentialDeposit)").action(async (target, opts) => {
|
|
862
902
|
if (!target) {
|
|
863
|
-
console.log("Usage: dot const <Pallet.Constant> [--chain <name>] [--output json]");
|
|
903
|
+
console.log("Usage: dot const <[Chain.]Pallet.Constant> [--chain <name>] [--output json]");
|
|
864
904
|
console.log("");
|
|
865
905
|
console.log("Examples:");
|
|
866
906
|
console.log(" $ dot const Balances.ExistentialDeposit");
|
|
867
907
|
console.log(" $ dot const System.SS58Prefix --chain kusama");
|
|
908
|
+
console.log(" $ dot const kusama.Balances.ExistentialDeposit # chain prefix");
|
|
868
909
|
return;
|
|
869
910
|
}
|
|
870
911
|
const config = await loadConfig();
|
|
871
|
-
const
|
|
872
|
-
const
|
|
912
|
+
const knownChains = Object.keys(config.chains);
|
|
913
|
+
const parsed = parseTarget(target, { knownChains });
|
|
914
|
+
const effectiveChain = resolveTargetChain(parsed, opts.chain);
|
|
915
|
+
const { name: chainName, chain: chainConfig } = resolveChain(config, effectiveChain);
|
|
916
|
+
const pallet = parsed.pallet;
|
|
917
|
+
const item = parsed.item;
|
|
873
918
|
const clientHandle = await createChainClient(chainName, chainConfig, opts.rpc);
|
|
874
919
|
try {
|
|
875
920
|
const meta = await getOrFetchMetadata(chainName, clientHandle);
|
|
@@ -886,7 +931,8 @@ function registerConstCommand(cli) {
|
|
|
886
931
|
const unsafeApi = clientHandle.client.getUnsafeApi();
|
|
887
932
|
const runtimeToken = await unsafeApi.runtimeToken;
|
|
888
933
|
const result = unsafeApi.constants[palletInfo.name][constantItem.name](runtimeToken);
|
|
889
|
-
|
|
934
|
+
const format = opts.output ?? "pretty";
|
|
935
|
+
printResult(result, format);
|
|
890
936
|
} finally {
|
|
891
937
|
clientHandle.destroy();
|
|
892
938
|
}
|
|
@@ -1028,7 +1074,17 @@ function registerHashCommand(cli) {
|
|
|
1028
1074
|
function registerInspectCommand(cli) {
|
|
1029
1075
|
cli.command("inspect [target]", "Inspect chain metadata (pallets, storage, constants)").option("--chain <name>", "Target chain").option("--rpc <url>", "Override RPC endpoint").action(async (target, opts) => {
|
|
1030
1076
|
const config = await loadConfig();
|
|
1031
|
-
const
|
|
1077
|
+
const knownChains = Object.keys(config.chains);
|
|
1078
|
+
let effectiveChain = opts.chain;
|
|
1079
|
+
let palletName;
|
|
1080
|
+
let itemName;
|
|
1081
|
+
if (target) {
|
|
1082
|
+
const parsed = parseTarget(target, { knownChains, allowPalletOnly: true });
|
|
1083
|
+
effectiveChain = resolveTargetChain(parsed, opts.chain);
|
|
1084
|
+
palletName = parsed.pallet;
|
|
1085
|
+
itemName = parsed.item;
|
|
1086
|
+
}
|
|
1087
|
+
const { name: chainName, chain: chainConfig } = resolveChain(config, effectiveChain);
|
|
1032
1088
|
let meta;
|
|
1033
1089
|
try {
|
|
1034
1090
|
meta = await getOrFetchMetadata(chainName);
|
|
@@ -1055,11 +1111,11 @@ function registerInspectCommand(cli) {
|
|
|
1055
1111
|
console.log();
|
|
1056
1112
|
return;
|
|
1057
1113
|
}
|
|
1058
|
-
if (!
|
|
1114
|
+
if (!itemName) {
|
|
1059
1115
|
const palletNames2 = getPalletNames(meta);
|
|
1060
|
-
const pallet2 = findPallet(meta,
|
|
1116
|
+
const pallet2 = findPallet(meta, palletName);
|
|
1061
1117
|
if (!pallet2) {
|
|
1062
|
-
throw new Error(suggestMessage("pallet",
|
|
1118
|
+
throw new Error(suggestMessage("pallet", palletName, palletNames2));
|
|
1063
1119
|
}
|
|
1064
1120
|
printHeading(`${pallet2.name} Pallet`);
|
|
1065
1121
|
if (pallet2.docs.length) {
|
|
@@ -1084,7 +1140,6 @@ function registerInspectCommand(cli) {
|
|
|
1084
1140
|
}
|
|
1085
1141
|
return;
|
|
1086
1142
|
}
|
|
1087
|
-
const { pallet: palletName, item: itemName } = parseTarget(target);
|
|
1088
1143
|
const palletNames = getPalletNames(meta);
|
|
1089
1144
|
const pallet = findPallet(meta, palletName);
|
|
1090
1145
|
if (!pallet) {
|
|
@@ -1399,7 +1454,7 @@ function registerQueryCommand(cli) {
|
|
|
1399
1454
|
default: DEFAULT_LIMIT
|
|
1400
1455
|
}).action(async (target, keys, opts) => {
|
|
1401
1456
|
if (!target) {
|
|
1402
|
-
console.log("Usage: dot query <Pallet.Item> [...keys] [--chain <name>] [--output json]");
|
|
1457
|
+
console.log("Usage: dot query <[Chain.]Pallet.Item> [...keys] [--chain <name>] [--output json]");
|
|
1403
1458
|
console.log("");
|
|
1404
1459
|
console.log("Examples:");
|
|
1405
1460
|
console.log(" $ dot query System.Number # plain storage value");
|
|
@@ -1408,11 +1463,16 @@ function registerQueryCommand(cli) {
|
|
|
1408
1463
|
console.log(" $ dot query System.Account --limit 10 # first 10 entries");
|
|
1409
1464
|
console.log(" $ dot query System.Account --limit 0 # all entries (no limit)");
|
|
1410
1465
|
console.log(" $ dot query Assets.Metadata 42 --chain asset-hub");
|
|
1466
|
+
console.log(" $ dot query kusama.System.Account 5Grw... # chain prefix");
|
|
1411
1467
|
return;
|
|
1412
1468
|
}
|
|
1413
1469
|
const config = await loadConfig();
|
|
1414
|
-
const
|
|
1415
|
-
const
|
|
1470
|
+
const knownChains = Object.keys(config.chains);
|
|
1471
|
+
const parsed = parseTarget(target, { knownChains });
|
|
1472
|
+
const effectiveChain = resolveTargetChain(parsed, opts.chain);
|
|
1473
|
+
const { name: chainName, chain: chainConfig } = resolveChain(config, effectiveChain);
|
|
1474
|
+
const pallet = parsed.pallet;
|
|
1475
|
+
const item = parsed.item;
|
|
1416
1476
|
const clientHandle = await createChainClient(chainName, chainConfig, opts.rpc);
|
|
1417
1477
|
try {
|
|
1418
1478
|
const meta = await getOrFetchMetadata(chainName, clientHandle);
|
|
@@ -1430,12 +1490,6 @@ function registerQueryCommand(cli) {
|
|
|
1430
1490
|
const storageApi = unsafeApi.query[palletInfo.name][storageItem.name];
|
|
1431
1491
|
const parsedKeys = parseStorageKeys(meta, palletInfo.name, storageItem, keys);
|
|
1432
1492
|
const format = opts.output ?? "pretty";
|
|
1433
|
-
if (format === "json") {
|
|
1434
|
-
console.error(`chain: ${chainName}`);
|
|
1435
|
-
} else {
|
|
1436
|
-
console.log(`${DIM}chain: ${chainName}${RESET}
|
|
1437
|
-
`);
|
|
1438
|
-
}
|
|
1439
1493
|
if (storageItem.type === "map" && parsedKeys.length === 0) {
|
|
1440
1494
|
const entries = await storageApi.getEntries();
|
|
1441
1495
|
const limit = Number(opts.limit);
|
|
@@ -1501,13 +1555,14 @@ import { Binary as Binary2 } from "polkadot-api";
|
|
|
1501
1555
|
function registerTxCommand(cli) {
|
|
1502
1556
|
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("--encode", "Encode call to hex without signing or submitting").option("--ext <json>", `Custom signed extension values as JSON, e.g. '{"ExtName":{"value":...}}'`).action(async (target, args, opts) => {
|
|
1503
1557
|
if (!target) {
|
|
1504
|
-
console.log("Usage: dot tx <Pallet.Call|0xCallHex> [...args] --from <account> [--dry-run] [--encode]");
|
|
1558
|
+
console.log("Usage: dot tx <[Chain.]Pallet.Call|0xCallHex> [...args] --from <account> [--dry-run] [--encode]");
|
|
1505
1559
|
console.log("");
|
|
1506
1560
|
console.log("Examples:");
|
|
1507
1561
|
console.log(" $ dot tx Balances.transferKeepAlive 5FHn... 1000000000000 --from alice");
|
|
1508
1562
|
console.log(" $ dot tx System.remark 0xdeadbeef --from alice --dry-run");
|
|
1509
1563
|
console.log(" $ dot tx 0x0001076465616462656566 --from alice");
|
|
1510
1564
|
console.log(" $ dot tx Assets.force_create 4 owner true 10 --encode --chain people");
|
|
1565
|
+
console.log(" $ dot tx kusama.Balances.transferKeepAlive 5FHn... 1000000000000 --from alice");
|
|
1511
1566
|
return;
|
|
1512
1567
|
}
|
|
1513
1568
|
if (!opts.from && !opts.encode) {
|
|
@@ -1521,7 +1576,14 @@ function registerTxCommand(cli) {
|
|
|
1521
1576
|
throw new Error("--encode cannot be used with raw call hex (already encoded)");
|
|
1522
1577
|
}
|
|
1523
1578
|
const config = await loadConfig();
|
|
1524
|
-
|
|
1579
|
+
let effectiveChain = opts.chain;
|
|
1580
|
+
let parsedTarget;
|
|
1581
|
+
if (!isRawCall) {
|
|
1582
|
+
const knownChains = Object.keys(config.chains);
|
|
1583
|
+
parsedTarget = parseTarget(target, { knownChains });
|
|
1584
|
+
effectiveChain = resolveTargetChain(parsedTarget, opts.chain);
|
|
1585
|
+
}
|
|
1586
|
+
const { name: chainName, chain: chainConfig } = resolveChain(config, effectiveChain);
|
|
1525
1587
|
const signer = opts.encode ? undefined : await resolveAccountSigner(opts.from);
|
|
1526
1588
|
let clientHandle;
|
|
1527
1589
|
if (!opts.encode) {
|
|
@@ -1558,7 +1620,8 @@ function registerTxCommand(cli) {
|
|
|
1558
1620
|
tx = await unsafeApi.txFromCallData(callBinary);
|
|
1559
1621
|
callHex = target;
|
|
1560
1622
|
} else {
|
|
1561
|
-
const
|
|
1623
|
+
const pallet = parsedTarget.pallet;
|
|
1624
|
+
const callName = parsedTarget.item;
|
|
1562
1625
|
const palletNames = getPalletNames(meta);
|
|
1563
1626
|
const palletInfo = findPallet(meta, pallet);
|
|
1564
1627
|
if (!palletInfo) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "polkadot-cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.8.1",
|
|
4
4
|
"description": "CLI tool for querying Polkadot-ecosystem on-chain state",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -17,7 +17,8 @@
|
|
|
17
17
|
"typecheck": "tsc --noEmit",
|
|
18
18
|
"lint": "biome check .",
|
|
19
19
|
"lint:fix": "biome check --write .",
|
|
20
|
-
"test": "bun test",
|
|
20
|
+
"test": "bun test --concurrent",
|
|
21
|
+
"test:coverage": "bun test --concurrent --coverage --coverage-reporter=lcov --coverage-dir=coverage",
|
|
21
22
|
"prepare": "husky",
|
|
22
23
|
"changeset": "changeset",
|
|
23
24
|
"version": "changeset version",
|