polkadot-cli 1.8.1 → 1.10.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 +56 -1
- package/dist/cli.mjs +142 -35
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
[](https://www.npmjs.com/package/polkadot-cli)
|
|
1
2
|
[](https://codecov.io/gh/peetzweg/polkadot-cli)
|
|
2
3
|
|
|
3
4
|
# polkadot-cli
|
|
@@ -309,12 +310,32 @@ dot query System.Number --output json | jq '.+1'
|
|
|
309
310
|
dot query kusama.System.Account 5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY
|
|
310
311
|
```
|
|
311
312
|
|
|
313
|
+
#### Partial key queries
|
|
314
|
+
|
|
315
|
+
For storage maps with multiple keys (NMaps), you can provide fewer keys than
|
|
316
|
+
expected to retrieve all entries matching that prefix. This uses the chain's
|
|
317
|
+
prefix-based iteration and does not require `--dump`.
|
|
318
|
+
|
|
319
|
+
```bash
|
|
320
|
+
# Full key — returns a single value
|
|
321
|
+
dot query Staking.ErasStakers 100 5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY
|
|
322
|
+
|
|
323
|
+
# Partial key — returns all entries matching the first key
|
|
324
|
+
dot query Staking.ErasStakers 100
|
|
325
|
+
|
|
326
|
+
# No keys — requires --dump (safety net for large maps)
|
|
327
|
+
dot query Staking.ErasStakers --dump --limit 10
|
|
328
|
+
```
|
|
329
|
+
|
|
330
|
+
The `--limit` option applies to partial key results just like it does for
|
|
331
|
+
`--dump` (default: 100, use `--limit 0` for unlimited).
|
|
332
|
+
|
|
312
333
|
#### Output formatting
|
|
313
334
|
|
|
314
335
|
Query results automatically convert on-chain types for readability:
|
|
315
336
|
|
|
316
337
|
- **BigInt** values (e.g. balances) render as decimal strings
|
|
317
|
-
- **Binary** fields (e.g. token `name`, `symbol`) render as text when
|
|
338
|
+
- **Binary** fields (e.g. token `name`, `symbol`) render as text when the value contains only printable characters, or as `0x`-prefixed hex otherwise (values containing control characters, Private Use Area code points, or invalid UTF-8 sequences always fall back to hex)
|
|
318
339
|
- **Uint8Array** values render as `0x`-prefixed hex
|
|
319
340
|
|
|
320
341
|
```bash
|
|
@@ -596,6 +617,40 @@ For manual override, use `--ext` with a JSON object:
|
|
|
596
617
|
dot tx System.remark 0xdeadbeef --from alice --ext '{"MyExtension":{"value":"..."}}'
|
|
597
618
|
```
|
|
598
619
|
|
|
620
|
+
#### Transaction options
|
|
621
|
+
|
|
622
|
+
Override low-level transaction parameters. Useful for rapid-fire submission (custom nonce), priority fees (tip), or controlling transaction lifetime (mortality).
|
|
623
|
+
|
|
624
|
+
| Flag | Value | Description |
|
|
625
|
+
|------|-------|-------------|
|
|
626
|
+
| `--nonce <n>` | non-negative integer | Override the auto-detected nonce |
|
|
627
|
+
| `--tip <amount>` | non-negative integer (planck) | Priority tip for the transaction pool |
|
|
628
|
+
| `--mortality <spec>` | `immortal` or period (min 4) | Transaction mortality window |
|
|
629
|
+
| `--at <block>` | `best`, `finalized`, or 0x-prefixed block hash | Block state to validate against |
|
|
630
|
+
|
|
631
|
+
```bash
|
|
632
|
+
# Fire-and-forget: submit two txs in rapid succession with manual nonces
|
|
633
|
+
dot tx System.remark 0xdead --from alice --nonce 0 --wait broadcast
|
|
634
|
+
dot tx System.remark 0xbeef --from alice --nonce 1 --wait broadcast
|
|
635
|
+
|
|
636
|
+
# Add a priority tip (in planck)
|
|
637
|
+
dot tx Balances.transferKeepAlive 5FHneW46... 1000000000000 --from alice --tip 1000000
|
|
638
|
+
|
|
639
|
+
# Submit an immortal transaction (no expiry)
|
|
640
|
+
dot tx System.remark 0xdead --from alice --mortality immortal
|
|
641
|
+
|
|
642
|
+
# Set a custom mortality period (rounds up to nearest power of two)
|
|
643
|
+
dot tx System.remark 0xdead --from alice --mortality 128
|
|
644
|
+
|
|
645
|
+
# Validate against the best (not finalized) block
|
|
646
|
+
dot tx System.remark 0xdead --from alice --at best
|
|
647
|
+
|
|
648
|
+
# Combine: rapid-fire with tip and broadcast-only
|
|
649
|
+
dot tx System.remark 0xdead --from alice --nonce 5 --tip 500000 --wait broadcast
|
|
650
|
+
```
|
|
651
|
+
|
|
652
|
+
When set, nonce / tip / mortality / at are shown in both `--dry-run` and submission output. These flags are silently ignored with `--encode`, `--yaml`, and `--json` (which return before signing).
|
|
653
|
+
|
|
599
654
|
### File-based commands
|
|
600
655
|
|
|
601
656
|
Run any `dot` command from a YAML or JSON file. Especially useful for complex calls like XCM messages that are hard to construct inline.
|
package/dist/cli.mjs
CHANGED
|
@@ -387,14 +387,35 @@ var init_accounts = __esm(() => {
|
|
|
387
387
|
DEV_NAMES = ["alice", "bob", "charlie", "dave", "eve", "ferdie"];
|
|
388
388
|
});
|
|
389
389
|
|
|
390
|
+
// src/utils/binary-display.ts
|
|
391
|
+
function isReadableText(text) {
|
|
392
|
+
for (let i = 0;i < text.length; i++) {
|
|
393
|
+
const code = text.charCodeAt(i);
|
|
394
|
+
if (code <= 31 && code !== 9 && code !== 10 && code !== 13)
|
|
395
|
+
return false;
|
|
396
|
+
if (code === 127)
|
|
397
|
+
return false;
|
|
398
|
+
if (code >= 128 && code <= 159)
|
|
399
|
+
return false;
|
|
400
|
+
if (code === 65533)
|
|
401
|
+
return false;
|
|
402
|
+
if (code >= 57344 && code <= 63743)
|
|
403
|
+
return false;
|
|
404
|
+
}
|
|
405
|
+
return true;
|
|
406
|
+
}
|
|
407
|
+
function binaryToDisplay(value) {
|
|
408
|
+
const text = value.asText();
|
|
409
|
+
return isReadableText(text) ? text : value.asHex();
|
|
410
|
+
}
|
|
411
|
+
|
|
390
412
|
// src/core/output.ts
|
|
391
413
|
import { Binary } from "polkadot-api";
|
|
392
414
|
function replacer(_key, value) {
|
|
393
415
|
if (typeof value === "bigint")
|
|
394
416
|
return value.toString();
|
|
395
417
|
if (value instanceof Binary) {
|
|
396
|
-
|
|
397
|
-
return text.includes("�") ? value.asHex() : text;
|
|
418
|
+
return binaryToDisplay(value);
|
|
398
419
|
}
|
|
399
420
|
if (value instanceof Uint8Array)
|
|
400
421
|
return `0x${Buffer.from(value).toString("hex")}`;
|
|
@@ -2151,14 +2172,24 @@ var init_complete = __esm(() => {
|
|
|
2151
2172
|
"inspect"
|
|
2152
2173
|
];
|
|
2153
2174
|
GLOBAL_OPTIONS = ["--chain", "--rpc", "--light-client", "--output", "--help", "--version"];
|
|
2154
|
-
TX_OPTIONS = [
|
|
2175
|
+
TX_OPTIONS = [
|
|
2176
|
+
"--from",
|
|
2177
|
+
"--dry-run",
|
|
2178
|
+
"--encode",
|
|
2179
|
+
"--ext",
|
|
2180
|
+
"--wait",
|
|
2181
|
+
"--nonce",
|
|
2182
|
+
"--tip",
|
|
2183
|
+
"--mortality",
|
|
2184
|
+
"--at"
|
|
2185
|
+
];
|
|
2155
2186
|
QUERY_OPTIONS = ["--limit"];
|
|
2156
2187
|
});
|
|
2157
2188
|
|
|
2158
2189
|
// src/cli.ts
|
|
2159
2190
|
import cac from "cac";
|
|
2160
2191
|
// package.json
|
|
2161
|
-
var version = "1.
|
|
2192
|
+
var version = "1.10.0";
|
|
2162
2193
|
|
|
2163
2194
|
// src/commands/account.ts
|
|
2164
2195
|
init_accounts_store();
|
|
@@ -3927,14 +3958,15 @@ async function handleQuery(target, keys, opts) {
|
|
|
3927
3958
|
];
|
|
3928
3959
|
const parsedKeys = await parseStorageKeys(meta, palletInfo.name, storageItem, effectiveKeys);
|
|
3929
3960
|
const format = opts.output ?? "pretty";
|
|
3930
|
-
|
|
3931
|
-
|
|
3961
|
+
const expectedLen = storageItem.type === "map" && storageItem.keyTypeId != null ? meta.builder.buildStorage(palletInfo.name, storageItem.name).len : 0;
|
|
3962
|
+
if (storageItem.type === "map" && parsedKeys.length < expectedLen) {
|
|
3963
|
+
if (parsedKeys.length === 0 && !opts.dump) {
|
|
3932
3964
|
clientHandle.destroy();
|
|
3933
3965
|
await showItemHelp("query", target, { chain: opts.chain, rpc: opts.rpc });
|
|
3934
3966
|
console.log(`${DIM}Hint: use --dump to fetch all entries${RESET}`);
|
|
3935
3967
|
return;
|
|
3936
3968
|
}
|
|
3937
|
-
const entries = await storageApi.getEntries();
|
|
3969
|
+
const entries = await storageApi.getEntries(...parsedKeys);
|
|
3938
3970
|
const limit = Number(opts.limit);
|
|
3939
3971
|
const truncated = limit > 0 && entries.length > limit;
|
|
3940
3972
|
const display = truncated ? entries.slice(0, limit) : entries;
|
|
@@ -3978,18 +4010,18 @@ async function parseStorageKeys(meta, palletName2, storageItem, args) {
|
|
|
3978
4010
|
throw new Error(`${palletName2}.${storageItem.name} key expects ${typeDesc}
|
|
3979
4011
|
` + ` Pass 1 argument. Got ${args.length}.`);
|
|
3980
4012
|
}
|
|
3981
|
-
if (args.length
|
|
4013
|
+
if (args.length > len) {
|
|
3982
4014
|
let typeDesc;
|
|
3983
4015
|
if (keyEntry.type === "tuple") {
|
|
3984
4016
|
typeDesc = keyEntry.value.map((e) => describeType(meta.lookup, e.id)).join(", ");
|
|
3985
4017
|
} else {
|
|
3986
4018
|
typeDesc = describeType(meta.lookup, storageItem.keyTypeId);
|
|
3987
4019
|
}
|
|
3988
|
-
throw new Error(`${palletName2}.${storageItem.name} expects ${len} key arg(s): (${typeDesc}). Got ${args.length}.`);
|
|
4020
|
+
throw new Error(`${palletName2}.${storageItem.name} expects at most ${len} key arg(s): (${typeDesc}). Got ${args.length}.`);
|
|
3989
4021
|
}
|
|
3990
4022
|
if (keyEntry.type === "tuple") {
|
|
3991
4023
|
const entries = keyEntry.value;
|
|
3992
|
-
return Promise.all(entries.map((entry, i) => parseTypedArg(meta, entry, args[i])));
|
|
4024
|
+
return Promise.all(entries.slice(0, args.length).map((entry, i) => parseTypedArg(meta, entry, args[i])));
|
|
3993
4025
|
}
|
|
3994
4026
|
return Promise.all(args.map((arg) => parseTypedArg(meta, keyEntry, arg)));
|
|
3995
4027
|
}
|
|
@@ -4021,6 +4053,50 @@ function parseWaitLevel(raw) {
|
|
|
4021
4053
|
throw new CliError(`Invalid --wait value "${raw}". Valid: broadcast, best-block, best, finalized`);
|
|
4022
4054
|
}
|
|
4023
4055
|
}
|
|
4056
|
+
function parseNonceOption(raw) {
|
|
4057
|
+
if (raw === undefined)
|
|
4058
|
+
return;
|
|
4059
|
+
const n = Number(raw);
|
|
4060
|
+
if (!Number.isInteger(n) || n < 0) {
|
|
4061
|
+
throw new CliError(`Invalid --nonce value "${raw}". Must be a non-negative integer.`);
|
|
4062
|
+
}
|
|
4063
|
+
return n;
|
|
4064
|
+
}
|
|
4065
|
+
function parseTipOption(raw) {
|
|
4066
|
+
if (raw === undefined)
|
|
4067
|
+
return;
|
|
4068
|
+
try {
|
|
4069
|
+
const t = BigInt(raw);
|
|
4070
|
+
if (t < 0n) {
|
|
4071
|
+
throw new CliError(`Invalid --tip value "${raw}". Must be a non-negative integer.`);
|
|
4072
|
+
}
|
|
4073
|
+
return t;
|
|
4074
|
+
} catch (err) {
|
|
4075
|
+
if (err instanceof CliError)
|
|
4076
|
+
throw err;
|
|
4077
|
+
throw new CliError(`Invalid --tip value "${raw}". Must be a non-negative integer.`);
|
|
4078
|
+
}
|
|
4079
|
+
}
|
|
4080
|
+
function parseMortalityOption(raw) {
|
|
4081
|
+
if (raw === undefined)
|
|
4082
|
+
return;
|
|
4083
|
+
if (raw === "immortal")
|
|
4084
|
+
return { mortal: false };
|
|
4085
|
+
const n = Number(raw);
|
|
4086
|
+
if (!Number.isInteger(n) || n < 4) {
|
|
4087
|
+
throw new CliError(`Invalid --mortality value "${raw}". Use "immortal" or a period number (minimum 4).`);
|
|
4088
|
+
}
|
|
4089
|
+
return { mortal: true, period: n };
|
|
4090
|
+
}
|
|
4091
|
+
function parseAtOption(raw) {
|
|
4092
|
+
if (raw === undefined)
|
|
4093
|
+
return;
|
|
4094
|
+
if (raw === "best" || raw === "finalized")
|
|
4095
|
+
return raw;
|
|
4096
|
+
if (/^0x[0-9a-fA-F]{64}$/.test(raw))
|
|
4097
|
+
return raw;
|
|
4098
|
+
throw new CliError(`Invalid --at value "${raw}". Use "best", "finalized", or a 0x-prefixed 32-byte block hash.`);
|
|
4099
|
+
}
|
|
4024
4100
|
async function handleTx(target, args, opts) {
|
|
4025
4101
|
if (!target) {
|
|
4026
4102
|
const config2 = await loadConfig();
|
|
@@ -4109,10 +4185,25 @@ async function handleTx(target, args, opts) {
|
|
|
4109
4185
|
}
|
|
4110
4186
|
let unsafeApi;
|
|
4111
4187
|
let txOptions;
|
|
4188
|
+
const nonce = parseNonceOption(opts.nonce);
|
|
4189
|
+
const tip = parseTipOption(opts.tip);
|
|
4190
|
+
const mortality = parseMortalityOption(opts.mortality);
|
|
4191
|
+
const at = parseAtOption(opts.at);
|
|
4112
4192
|
if (!decodeOnly) {
|
|
4113
4193
|
const userExtOverrides = parseExtOption(opts.ext);
|
|
4114
4194
|
const customSignedExtensions = buildCustomSignedExtensions(meta, userExtOverrides);
|
|
4115
|
-
|
|
4195
|
+
const built = {};
|
|
4196
|
+
if (Object.keys(customSignedExtensions).length > 0)
|
|
4197
|
+
built.customSignedExtensions = customSignedExtensions;
|
|
4198
|
+
if (nonce !== undefined)
|
|
4199
|
+
built.nonce = nonce;
|
|
4200
|
+
if (tip !== undefined)
|
|
4201
|
+
built.tip = tip;
|
|
4202
|
+
if (mortality !== undefined)
|
|
4203
|
+
built.mortality = mortality;
|
|
4204
|
+
if (at !== undefined)
|
|
4205
|
+
built.at = at;
|
|
4206
|
+
txOptions = Object.keys(built).length > 0 ? built : undefined;
|
|
4116
4207
|
unsafeApi = clientHandle?.client.getUnsafeApi();
|
|
4117
4208
|
}
|
|
4118
4209
|
let tx;
|
|
@@ -4167,6 +4258,14 @@ async function handleTx(target, args, opts) {
|
|
|
4167
4258
|
console.log(` ${BOLD}From:${RESET} ${opts.from} (${signerAddress})`);
|
|
4168
4259
|
console.log(` ${BOLD}Call:${RESET} ${callHex}`);
|
|
4169
4260
|
console.log(` ${BOLD}Decode:${RESET} ${decodedStr}`);
|
|
4261
|
+
if (nonce !== undefined)
|
|
4262
|
+
console.log(` ${BOLD}Nonce:${RESET} ${nonce}`);
|
|
4263
|
+
if (tip !== undefined)
|
|
4264
|
+
console.log(` ${BOLD}Tip:${RESET} ${tip}`);
|
|
4265
|
+
if (mortality !== undefined)
|
|
4266
|
+
console.log(` ${BOLD}Mortality:${RESET} ${mortality.mortal ? `mortal (period ${mortality.period})` : "immortal"}`);
|
|
4267
|
+
if (at !== undefined)
|
|
4268
|
+
console.log(` ${BOLD}At:${RESET} ${at}`);
|
|
4170
4269
|
try {
|
|
4171
4270
|
const fees = await tx.getEstimatedFees(signer?.publicKey, txOptions);
|
|
4172
4271
|
console.log(` ${BOLD}Estimated fees:${RESET} ${fees}`);
|
|
@@ -4182,6 +4281,14 @@ async function handleTx(target, args, opts) {
|
|
|
4182
4281
|
console.log(` ${BOLD}Chain:${RESET} ${chainName}`);
|
|
4183
4282
|
console.log(` ${BOLD}Call:${RESET} ${callHex}`);
|
|
4184
4283
|
console.log(` ${BOLD}Decode:${RESET} ${decodedStr}`);
|
|
4284
|
+
if (nonce !== undefined)
|
|
4285
|
+
console.log(` ${BOLD}Nonce:${RESET} ${nonce}`);
|
|
4286
|
+
if (tip !== undefined)
|
|
4287
|
+
console.log(` ${BOLD}Tip:${RESET} ${tip}`);
|
|
4288
|
+
if (mortality !== undefined)
|
|
4289
|
+
console.log(` ${BOLD}Mortality:${RESET} ${mortality.mortal ? `mortal (period ${mortality.period})` : "immortal"}`);
|
|
4290
|
+
if (at !== undefined)
|
|
4291
|
+
console.log(` ${BOLD}At:${RESET} ${at}`);
|
|
4185
4292
|
console.log(` ${BOLD}Tx:${RESET} ${result.txHash}`);
|
|
4186
4293
|
if (result.type === "broadcasted") {
|
|
4187
4294
|
console.log(` ${BOLD}Status:${RESET} ${GREEN}broadcasted${RESET}`);
|
|
@@ -4452,8 +4559,7 @@ function formatEventValue(v) {
|
|
|
4452
4559
|
if (v === null || v === undefined)
|
|
4453
4560
|
return "null";
|
|
4454
4561
|
if (v instanceof Binary3) {
|
|
4455
|
-
|
|
4456
|
-
return text.includes("�") ? v.asHex() : text;
|
|
4562
|
+
return binaryToDisplay(v);
|
|
4457
4563
|
}
|
|
4458
4564
|
return JSON.stringify(v, (_k, val) => typeof val === "bigint" ? val.toString() : val);
|
|
4459
4565
|
}
|
|
@@ -5400,7 +5506,7 @@ if (process.argv[2] === "__complete") {
|
|
|
5400
5506
|
default: "finalized"
|
|
5401
5507
|
}).option("--limit <n>", "Max entries to return for map queries (0 = unlimited)", {
|
|
5402
5508
|
default: 100
|
|
5403
|
-
}).option("--dump", "Dump all entries of a storage map (without specifying a key)").option("--var <kv>", "Template variable for file input (KEY=VALUE, repeatable)").action(async (dotpath, args, opts) => {
|
|
5509
|
+
}).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)').action(async (dotpath, args, opts) => {
|
|
5404
5510
|
if (!dotpath) {
|
|
5405
5511
|
printHelp();
|
|
5406
5512
|
return;
|
|
@@ -5422,6 +5528,10 @@ if (process.argv[2] === "__complete") {
|
|
|
5422
5528
|
json: opts.json,
|
|
5423
5529
|
ext: opts.ext,
|
|
5424
5530
|
wait: opts.wait,
|
|
5531
|
+
nonce: opts.nonce,
|
|
5532
|
+
tip: opts.tip,
|
|
5533
|
+
mortality: opts.mortality,
|
|
5534
|
+
at: opts.at,
|
|
5425
5535
|
parsedArgs: cmd.args
|
|
5426
5536
|
});
|
|
5427
5537
|
break;
|
|
@@ -5473,31 +5583,28 @@ if (process.argv[2] === "__complete") {
|
|
|
5473
5583
|
case "query":
|
|
5474
5584
|
await handleQuery(target, args, { ...handlerOpts, limit: opts.limit, dump: opts.dump });
|
|
5475
5585
|
break;
|
|
5476
|
-
case "tx":
|
|
5586
|
+
case "tx": {
|
|
5587
|
+
const txOpts = {
|
|
5588
|
+
...handlerOpts,
|
|
5589
|
+
from: opts.from,
|
|
5590
|
+
dryRun: opts.dryRun,
|
|
5591
|
+
encode: opts.encode,
|
|
5592
|
+
yaml: opts.yaml,
|
|
5593
|
+
json: opts.json,
|
|
5594
|
+
ext: opts.ext,
|
|
5595
|
+
wait: opts.wait,
|
|
5596
|
+
nonce: opts.nonce,
|
|
5597
|
+
tip: opts.tip,
|
|
5598
|
+
mortality: opts.mortality,
|
|
5599
|
+
at: opts.at
|
|
5600
|
+
};
|
|
5477
5601
|
if (parsed.pallet && /^0x[0-9a-fA-F]+$/.test(parsed.pallet)) {
|
|
5478
|
-
await handleTx(parsed.pallet, args,
|
|
5479
|
-
...handlerOpts,
|
|
5480
|
-
from: opts.from,
|
|
5481
|
-
dryRun: opts.dryRun,
|
|
5482
|
-
encode: opts.encode,
|
|
5483
|
-
yaml: opts.yaml,
|
|
5484
|
-
json: opts.json,
|
|
5485
|
-
ext: opts.ext,
|
|
5486
|
-
wait: opts.wait
|
|
5487
|
-
});
|
|
5602
|
+
await handleTx(parsed.pallet, args, txOpts);
|
|
5488
5603
|
} else {
|
|
5489
|
-
await handleTx(target, args,
|
|
5490
|
-
...handlerOpts,
|
|
5491
|
-
from: opts.from,
|
|
5492
|
-
dryRun: opts.dryRun,
|
|
5493
|
-
encode: opts.encode,
|
|
5494
|
-
yaml: opts.yaml,
|
|
5495
|
-
json: opts.json,
|
|
5496
|
-
ext: opts.ext,
|
|
5497
|
-
wait: opts.wait
|
|
5498
|
-
});
|
|
5604
|
+
await handleTx(target, args, txOpts);
|
|
5499
5605
|
}
|
|
5500
5606
|
break;
|
|
5607
|
+
}
|
|
5501
5608
|
case "const":
|
|
5502
5609
|
await handleConst(target, handlerOpts);
|
|
5503
5610
|
break;
|