polkadot-cli 0.13.0 → 0.14.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 +61 -5
- package/dist/cli.mjs +450 -27
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -220,7 +220,7 @@ dot query System.Account 5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY
|
|
|
220
220
|
# All map entries (default limit: 100)
|
|
221
221
|
dot query System.Account --limit 10
|
|
222
222
|
|
|
223
|
-
# Pipe
|
|
223
|
+
# Pipe-safe — stdout is clean data, progress messages go to stderr
|
|
224
224
|
dot query System.Account --limit 5 | jq '.[0].value.data.free'
|
|
225
225
|
dot query System.Number --output json | jq '.+1'
|
|
226
226
|
|
|
@@ -249,7 +249,7 @@ dot const Balances.ExistentialDeposit
|
|
|
249
249
|
dot const System.SS58Prefix --chain kusama
|
|
250
250
|
dot const kusama.Balances.ExistentialDeposit
|
|
251
251
|
|
|
252
|
-
# Pipe
|
|
252
|
+
# Pipe-safe — stdout is clean JSON, progress messages go to stderr
|
|
253
253
|
dot const Balances.ExistentialDeposit --output json | jq
|
|
254
254
|
```
|
|
255
255
|
|
|
@@ -258,10 +258,10 @@ dot const Balances.ExistentialDeposit --output json | jq
|
|
|
258
258
|
Works offline from cached metadata after the first fetch.
|
|
259
259
|
|
|
260
260
|
```bash
|
|
261
|
-
# List all pallets (shows storage, constants, and
|
|
261
|
+
# List all pallets (shows storage, constants, calls, events, and errors counts)
|
|
262
262
|
dot inspect
|
|
263
263
|
|
|
264
|
-
# List a pallet's storage items, constants, and
|
|
264
|
+
# List a pallet's storage items, constants, calls, events, and errors
|
|
265
265
|
dot inspect System
|
|
266
266
|
|
|
267
267
|
# Detailed type info for a specific storage item or constant
|
|
@@ -270,12 +270,57 @@ dot inspect System.Account
|
|
|
270
270
|
# Call detail — shows argument signature and docs
|
|
271
271
|
dot inspect Balances.transfer_allow_death
|
|
272
272
|
|
|
273
|
+
# Event detail — shows field signature and docs
|
|
274
|
+
dot inspect Balances.Transfer
|
|
275
|
+
|
|
276
|
+
# Error detail — shows docs
|
|
277
|
+
dot inspect Balances.InsufficientBalance
|
|
278
|
+
|
|
273
279
|
# Inspect a specific chain using chain prefix
|
|
274
280
|
dot inspect kusama.System
|
|
275
281
|
dot inspect kusama.System.Account
|
|
276
282
|
```
|
|
277
283
|
|
|
278
|
-
|
|
284
|
+
The pallet listing view shows type information inline so you can understand item shapes at a glance:
|
|
285
|
+
|
|
286
|
+
- **Storage**: key/value types with `[map]` tag for map items (e.g. `Account: AccountId32 → { nonce: u32, ... } [map]`)
|
|
287
|
+
- **Constants**: the constant's type (e.g. `ExistentialDeposit: u128`)
|
|
288
|
+
- **Calls**: full argument signature (e.g. `transfer_allow_death(dest: enum(5 variants), value: Compact<u128>)`)
|
|
289
|
+
- **Events**: field signature (e.g. `Transfer(from: AccountId32, to: AccountId32, amount: u128)`)
|
|
290
|
+
- **Errors**: name and documentation (e.g. `InsufficientBalance`)
|
|
291
|
+
|
|
292
|
+
Documentation from the runtime metadata is shown on an indented line below each item. The detail view (`dot inspect Balances.transfer_allow_death`) shows the full argument signature and complete documentation text. Use call inspection to discover argument names, types, and docs before constructing `dot tx` commands.
|
|
293
|
+
|
|
294
|
+
### Focused commands
|
|
295
|
+
|
|
296
|
+
Browse specific metadata categories directly without using `dot inspect`:
|
|
297
|
+
|
|
298
|
+
```bash
|
|
299
|
+
# List all pallets
|
|
300
|
+
dot pallets
|
|
301
|
+
|
|
302
|
+
# List pallet calls with argument signatures
|
|
303
|
+
dot calls Balances
|
|
304
|
+
dot calls Balances.transfer_allow_death # call detail
|
|
305
|
+
|
|
306
|
+
# List pallet events with field signatures
|
|
307
|
+
dot events Balances
|
|
308
|
+
dot events Balances.Transfer # event detail
|
|
309
|
+
|
|
310
|
+
# List pallet errors
|
|
311
|
+
dot errors Balances
|
|
312
|
+
dot errors Balances.InsufficientBalance # error detail
|
|
313
|
+
|
|
314
|
+
# List pallet storage items with types
|
|
315
|
+
dot storage System
|
|
316
|
+
dot storage System.Account # storage detail
|
|
317
|
+
|
|
318
|
+
# List pallet constants (dual-purpose — also works as value lookup)
|
|
319
|
+
dot const Balances # list constants
|
|
320
|
+
dot const Balances.ExistentialDeposit # look up value
|
|
321
|
+
```
|
|
322
|
+
|
|
323
|
+
Each command supports `--chain <name>`, `--rpc <url>`, and chain prefix syntax. Singular and plural forms are interchangeable (e.g. `dot call` = `dot calls`, `dot event` = `dot events`).
|
|
279
324
|
|
|
280
325
|
### Submit extrinsics
|
|
281
326
|
|
|
@@ -431,6 +476,17 @@ dot hash --help # same as `dot hash` — shows algorithms and examples
|
|
|
431
476
|
| `--output json` | Raw JSON output (default: pretty) |
|
|
432
477
|
| `--limit <n>` | Max entries for map queries (0 = unlimited, default: 100) |
|
|
433
478
|
|
|
479
|
+
### Pipe-safe output
|
|
480
|
+
|
|
481
|
+
All commands follow Unix conventions: **data goes to stdout, progress goes to stderr**. This means you can safely pipe `--output json` into `jq` or other tools without progress messages ("Fetching metadata...", spinner output, "Connecting...") corrupting the data stream:
|
|
482
|
+
|
|
483
|
+
```bash
|
|
484
|
+
dot const System.SS58Prefix --output json | jq '.+1'
|
|
485
|
+
dot query System.Number --output json | jq
|
|
486
|
+
```
|
|
487
|
+
|
|
488
|
+
In an interactive terminal, both streams render together so you see progress and results normally.
|
|
489
|
+
|
|
434
490
|
## How it compares
|
|
435
491
|
|
|
436
492
|
| | polkadot-cli | @polkadot/api-cli | subxt-cli | Pop CLI |
|
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.14.0";
|
|
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";
|
|
@@ -429,7 +429,7 @@ class Spinner {
|
|
|
429
429
|
start(msg) {
|
|
430
430
|
this.stop();
|
|
431
431
|
if (!isTTY) {
|
|
432
|
-
console.
|
|
432
|
+
console.error(msg);
|
|
433
433
|
return;
|
|
434
434
|
}
|
|
435
435
|
process.stdout.write(`${SPINNER_FRAMES[0]} ${msg}`);
|
|
@@ -449,9 +449,16 @@ class Spinner {
|
|
|
449
449
|
}
|
|
450
450
|
succeed(msg) {
|
|
451
451
|
this.stop();
|
|
452
|
-
console.
|
|
452
|
+
console.error(`${GREEN}${CHECK_MARK}${RESET} ${msg}`);
|
|
453
453
|
}
|
|
454
454
|
}
|
|
455
|
+
function firstSentence(docs) {
|
|
456
|
+
const text = docs.join(" ").trim();
|
|
457
|
+
if (!text)
|
|
458
|
+
return "";
|
|
459
|
+
const match = text.match(/^.*?(?<![ei]\.g|[ei]\.[eg])(?<!\betc)[.!?](?:\s|$)/);
|
|
460
|
+
return match ? match[0].trim() : text;
|
|
461
|
+
}
|
|
455
462
|
|
|
456
463
|
// src/commands/account.ts
|
|
457
464
|
var ACCOUNT_HELP = `
|
|
@@ -977,26 +984,28 @@ function listPallets(meta) {
|
|
|
977
984
|
docs: c.docs ?? [],
|
|
978
985
|
typeId: c.type
|
|
979
986
|
})),
|
|
980
|
-
calls:
|
|
987
|
+
calls: extractEnumVariants(meta, p.calls),
|
|
988
|
+
events: extractEnumVariants(meta, p.events),
|
|
989
|
+
errors: extractEnumVariants(meta, p.errors).map(({ name, docs }) => ({ name, docs }))
|
|
981
990
|
}));
|
|
982
991
|
}
|
|
983
|
-
function
|
|
984
|
-
if (!
|
|
992
|
+
function extractEnumVariants(meta, ref) {
|
|
993
|
+
if (!ref)
|
|
985
994
|
return [];
|
|
986
995
|
try {
|
|
987
|
-
const entry = meta.lookup(
|
|
996
|
+
const entry = meta.lookup(ref.type);
|
|
988
997
|
if (entry.type !== "enum")
|
|
989
998
|
return [];
|
|
990
999
|
return Object.entries(entry.value).map(([name, variant]) => ({
|
|
991
1000
|
name,
|
|
992
|
-
docs:
|
|
993
|
-
typeId:
|
|
1001
|
+
docs: entry.innerDocs?.[name] ?? [],
|
|
1002
|
+
typeId: resolveVariantTypeId(variant)
|
|
994
1003
|
}));
|
|
995
1004
|
} catch {
|
|
996
1005
|
return [];
|
|
997
1006
|
}
|
|
998
1007
|
}
|
|
999
|
-
function
|
|
1008
|
+
function resolveVariantTypeId(variant) {
|
|
1000
1009
|
if (variant.type === "lookupEntry")
|
|
1001
1010
|
return variant.value?.id ?? null;
|
|
1002
1011
|
if (variant.type === "struct")
|
|
@@ -1095,6 +1104,42 @@ function describeCallArgs(meta, palletName, callName) {
|
|
|
1095
1104
|
return "";
|
|
1096
1105
|
}
|
|
1097
1106
|
}
|
|
1107
|
+
function describeEventFields(meta, palletName, eventName) {
|
|
1108
|
+
try {
|
|
1109
|
+
const palletMeta = meta.unified.pallets.find((p) => p.name === palletName);
|
|
1110
|
+
if (!palletMeta?.events)
|
|
1111
|
+
return "";
|
|
1112
|
+
const eventsEntry = meta.lookup(palletMeta.events.type);
|
|
1113
|
+
if (eventsEntry.type !== "enum")
|
|
1114
|
+
return "";
|
|
1115
|
+
const variant = eventsEntry.value[eventName];
|
|
1116
|
+
if (!variant)
|
|
1117
|
+
return "";
|
|
1118
|
+
if (variant.type === "void")
|
|
1119
|
+
return "()";
|
|
1120
|
+
if (variant.type === "struct") {
|
|
1121
|
+
const fields = Object.entries(variant.value).map(([k, v]) => `${k}: ${formatLookupEntry(v)}`).join(", ");
|
|
1122
|
+
return `(${fields})`;
|
|
1123
|
+
}
|
|
1124
|
+
if (variant.type === "lookupEntry") {
|
|
1125
|
+
const inner = variant.value;
|
|
1126
|
+
if (inner.type === "void")
|
|
1127
|
+
return "()";
|
|
1128
|
+
if (inner.type === "struct") {
|
|
1129
|
+
const fields = Object.entries(inner.value).map(([k, v]) => `${k}: ${formatLookupEntry(v)}`).join(", ");
|
|
1130
|
+
return `(${fields})`;
|
|
1131
|
+
}
|
|
1132
|
+
return `(${formatLookupEntry(inner)})`;
|
|
1133
|
+
}
|
|
1134
|
+
if (variant.type === "tuple") {
|
|
1135
|
+
const types = variant.value.map(formatLookupEntry).join(", ");
|
|
1136
|
+
return `(${types})`;
|
|
1137
|
+
}
|
|
1138
|
+
return "";
|
|
1139
|
+
} catch {
|
|
1140
|
+
return "";
|
|
1141
|
+
}
|
|
1142
|
+
}
|
|
1098
1143
|
function hexToBytes(hex) {
|
|
1099
1144
|
const clean = hex.startsWith("0x") ? hex.slice(2) : hex;
|
|
1100
1145
|
const bytes = new Uint8Array(clean.length / 2);
|
|
@@ -1170,10 +1215,10 @@ async function chainAdd(name, opts) {
|
|
|
1170
1215
|
rpc: opts.rpc ?? "",
|
|
1171
1216
|
...opts.lightClient ? { lightClient: true } : {}
|
|
1172
1217
|
};
|
|
1173
|
-
console.
|
|
1218
|
+
console.error(`Connecting to ${name}...`);
|
|
1174
1219
|
const clientHandle = await createChainClient(name, chainConfig, opts.rpc);
|
|
1175
1220
|
try {
|
|
1176
|
-
console.
|
|
1221
|
+
console.error("Fetching metadata...");
|
|
1177
1222
|
await fetchMetadataFromChain(clientHandle, name);
|
|
1178
1223
|
const config = await loadConfig();
|
|
1179
1224
|
config.chains[name] = chainConfig;
|
|
@@ -1226,10 +1271,10 @@ async function chainList() {
|
|
|
1226
1271
|
async function chainUpdate(name, opts) {
|
|
1227
1272
|
const config = await loadConfig();
|
|
1228
1273
|
const { name: chainName, chain: chainConfig } = resolveChain(config, name);
|
|
1229
|
-
console.
|
|
1274
|
+
console.error(`Connecting to ${chainName}...`);
|
|
1230
1275
|
const clientHandle = await createChainClient(chainName, chainConfig, opts.rpc);
|
|
1231
1276
|
try {
|
|
1232
|
-
console.
|
|
1277
|
+
console.error("Fetching metadata...");
|
|
1233
1278
|
await fetchMetadataFromChain(clientHandle, chainName);
|
|
1234
1279
|
console.log(`Metadata for "${chainName}" updated.`);
|
|
1235
1280
|
} finally {
|
|
@@ -1339,23 +1384,58 @@ function resolveTargetChain(target, chainFlag) {
|
|
|
1339
1384
|
|
|
1340
1385
|
// src/commands/const.ts
|
|
1341
1386
|
function registerConstCommand(cli) {
|
|
1342
|
-
cli.command("const [target]", "Look up
|
|
1387
|
+
cli.command("const [target]", "Look up or list pallet constants (e.g. Balances.ExistentialDeposit)").alias("consts").alias("constants").action(async (target, opts) => {
|
|
1343
1388
|
if (!target) {
|
|
1344
|
-
console.log("Usage: dot const <[Chain.]Pallet.Constant> [--chain <name>] [--output json]");
|
|
1389
|
+
console.log("Usage: dot const <[Chain.]Pallet[.Constant]> [--chain <name>] [--output json]");
|
|
1345
1390
|
console.log("");
|
|
1346
1391
|
console.log("Examples:");
|
|
1347
|
-
console.log(" $ dot const Balances
|
|
1392
|
+
console.log(" $ dot const Balances # list constants");
|
|
1393
|
+
console.log(" $ dot const Balances.ExistentialDeposit # look up value");
|
|
1348
1394
|
console.log(" $ dot const System.SS58Prefix --chain kusama");
|
|
1349
1395
|
console.log(" $ dot const kusama.Balances.ExistentialDeposit # chain prefix");
|
|
1350
1396
|
return;
|
|
1351
1397
|
}
|
|
1352
1398
|
const config = await loadConfig();
|
|
1353
1399
|
const knownChains = Object.keys(config.chains);
|
|
1354
|
-
const parsed = parseTarget(target, { knownChains });
|
|
1400
|
+
const parsed = parseTarget(target, { knownChains, allowPalletOnly: true });
|
|
1355
1401
|
const effectiveChain = resolveTargetChain(parsed, opts.chain);
|
|
1356
1402
|
const { name: chainName, chain: chainConfig } = resolveChain(config, effectiveChain);
|
|
1357
1403
|
const pallet = parsed.pallet;
|
|
1358
1404
|
const item = parsed.item;
|
|
1405
|
+
if (!item) {
|
|
1406
|
+
let meta;
|
|
1407
|
+
try {
|
|
1408
|
+
meta = await getOrFetchMetadata(chainName);
|
|
1409
|
+
} catch {
|
|
1410
|
+
console.error(`Fetching metadata from ${chainName}...`);
|
|
1411
|
+
const clientHandle2 = await createChainClient(chainName, chainConfig, opts.rpc);
|
|
1412
|
+
try {
|
|
1413
|
+
meta = await getOrFetchMetadata(chainName, clientHandle2);
|
|
1414
|
+
} finally {
|
|
1415
|
+
clientHandle2.destroy();
|
|
1416
|
+
}
|
|
1417
|
+
}
|
|
1418
|
+
const palletNames = getPalletNames(meta);
|
|
1419
|
+
const palletInfo = findPallet(meta, pallet);
|
|
1420
|
+
if (!palletInfo) {
|
|
1421
|
+
throw new Error(suggestMessage("pallet", pallet, palletNames));
|
|
1422
|
+
}
|
|
1423
|
+
if (palletInfo.constants.length === 0) {
|
|
1424
|
+
console.log(`No constants in ${palletInfo.name}.`);
|
|
1425
|
+
return;
|
|
1426
|
+
}
|
|
1427
|
+
printHeading(`${palletInfo.name} Constants`);
|
|
1428
|
+
for (const c of palletInfo.constants) {
|
|
1429
|
+
const typeStr = describeType(meta.lookup, c.typeId);
|
|
1430
|
+
console.log(` ${CYAN}${c.name}${RESET}${DIM}: ${typeStr}${RESET}`);
|
|
1431
|
+
const summary = firstSentence(c.docs);
|
|
1432
|
+
if (summary) {
|
|
1433
|
+
console.log(` ${DIM}${summary}${RESET}`);
|
|
1434
|
+
}
|
|
1435
|
+
}
|
|
1436
|
+
console.log();
|
|
1437
|
+
return;
|
|
1438
|
+
}
|
|
1359
1439
|
const clientHandle = await createChainClient(chainName, chainConfig, opts.rpc);
|
|
1360
1440
|
try {
|
|
1361
1441
|
const meta = await getOrFetchMetadata(chainName, clientHandle);
|
|
@@ -1380,6 +1460,279 @@ function registerConstCommand(cli) {
|
|
|
1380
1460
|
});
|
|
1381
1461
|
}
|
|
1382
1462
|
|
|
1463
|
+
// src/commands/focused-inspect.ts
|
|
1464
|
+
async function loadMeta(chainName, chainConfig, rpcOverride) {
|
|
1465
|
+
try {
|
|
1466
|
+
return await getOrFetchMetadata(chainName);
|
|
1467
|
+
} catch {
|
|
1468
|
+
console.error(`Fetching metadata from ${chainName}...`);
|
|
1469
|
+
const clientHandle = await createChainClient(chainName, chainConfig, rpcOverride);
|
|
1470
|
+
try {
|
|
1471
|
+
return await getOrFetchMetadata(chainName, clientHandle);
|
|
1472
|
+
} finally {
|
|
1473
|
+
clientHandle.destroy();
|
|
1474
|
+
}
|
|
1475
|
+
}
|
|
1476
|
+
}
|
|
1477
|
+
function resolvePallet(meta, palletName) {
|
|
1478
|
+
const palletNames = getPalletNames(meta);
|
|
1479
|
+
const pallet = findPallet(meta, palletName);
|
|
1480
|
+
if (!pallet) {
|
|
1481
|
+
throw new Error(suggestMessage("pallet", palletName, palletNames));
|
|
1482
|
+
}
|
|
1483
|
+
return pallet;
|
|
1484
|
+
}
|
|
1485
|
+
function registerFocusedInspectCommands(cli) {
|
|
1486
|
+
cli.command("call [target]", "List or inspect pallet calls").alias("calls").option("--chain <name>", "Target chain").option("--rpc <url>", "Override RPC endpoint").action(async (target, opts) => {
|
|
1487
|
+
if (!target) {
|
|
1488
|
+
console.log("Usage: dot calls <[Chain.]Pallet[.Call]> [--chain <name>]");
|
|
1489
|
+
console.log("");
|
|
1490
|
+
console.log("Examples:");
|
|
1491
|
+
console.log(" $ dot calls Balances");
|
|
1492
|
+
console.log(" $ dot calls Balances.transfer_allow_death");
|
|
1493
|
+
return;
|
|
1494
|
+
}
|
|
1495
|
+
const config = await loadConfig();
|
|
1496
|
+
const knownChains = Object.keys(config.chains);
|
|
1497
|
+
const parsed = parseTarget(target, { knownChains, allowPalletOnly: true });
|
|
1498
|
+
const effectiveChain = resolveTargetChain(parsed, opts.chain);
|
|
1499
|
+
const { name: chainName, chain: chainConfig } = resolveChain(config, effectiveChain);
|
|
1500
|
+
const meta = await loadMeta(chainName, chainConfig, opts.rpc);
|
|
1501
|
+
const pallet = resolvePallet(meta, parsed.pallet);
|
|
1502
|
+
if (!parsed.item) {
|
|
1503
|
+
if (pallet.calls.length === 0) {
|
|
1504
|
+
console.log(`No calls in ${pallet.name}.`);
|
|
1505
|
+
return;
|
|
1506
|
+
}
|
|
1507
|
+
printHeading(`${pallet.name} Calls`);
|
|
1508
|
+
for (const c of pallet.calls) {
|
|
1509
|
+
const args2 = describeCallArgs(meta, pallet.name, c.name);
|
|
1510
|
+
console.log(` ${CYAN}${c.name}${RESET}${DIM}${args2}${RESET}`);
|
|
1511
|
+
const summary = firstSentence(c.docs);
|
|
1512
|
+
if (summary) {
|
|
1513
|
+
console.log(` ${DIM}${summary}${RESET}`);
|
|
1514
|
+
}
|
|
1515
|
+
}
|
|
1516
|
+
console.log();
|
|
1517
|
+
return;
|
|
1518
|
+
}
|
|
1519
|
+
const callItem = pallet.calls.find((c) => c.name.toLowerCase() === parsed.item.toLowerCase());
|
|
1520
|
+
if (!callItem) {
|
|
1521
|
+
const names = pallet.calls.map((c) => c.name);
|
|
1522
|
+
throw new Error(suggestMessage(`call in ${pallet.name}`, parsed.item, names));
|
|
1523
|
+
}
|
|
1524
|
+
printHeading(`${pallet.name}.${callItem.name} (Call)`);
|
|
1525
|
+
const args = describeCallArgs(meta, pallet.name, callItem.name);
|
|
1526
|
+
console.log(` ${BOLD}Args:${RESET} ${args}`);
|
|
1527
|
+
if (callItem.docs.length) {
|
|
1528
|
+
console.log();
|
|
1529
|
+
printDocs(callItem.docs);
|
|
1530
|
+
}
|
|
1531
|
+
console.log();
|
|
1532
|
+
});
|
|
1533
|
+
cli.command("event [target]", "List or inspect pallet events").alias("events").option("--chain <name>", "Target chain").option("--rpc <url>", "Override RPC endpoint").action(async (target, opts) => {
|
|
1534
|
+
if (!target) {
|
|
1535
|
+
console.log("Usage: dot events <[Chain.]Pallet[.Event]> [--chain <name>]");
|
|
1536
|
+
console.log("");
|
|
1537
|
+
console.log("Examples:");
|
|
1538
|
+
console.log(" $ dot events Balances");
|
|
1539
|
+
console.log(" $ dot events Balances.Transfer");
|
|
1540
|
+
return;
|
|
1541
|
+
}
|
|
1542
|
+
const config = await loadConfig();
|
|
1543
|
+
const knownChains = Object.keys(config.chains);
|
|
1544
|
+
const parsed = parseTarget(target, { knownChains, allowPalletOnly: true });
|
|
1545
|
+
const effectiveChain = resolveTargetChain(parsed, opts.chain);
|
|
1546
|
+
const { name: chainName, chain: chainConfig } = resolveChain(config, effectiveChain);
|
|
1547
|
+
const meta = await loadMeta(chainName, chainConfig, opts.rpc);
|
|
1548
|
+
const pallet = resolvePallet(meta, parsed.pallet);
|
|
1549
|
+
if (!parsed.item) {
|
|
1550
|
+
if (pallet.events.length === 0) {
|
|
1551
|
+
console.log(`No events in ${pallet.name}.`);
|
|
1552
|
+
return;
|
|
1553
|
+
}
|
|
1554
|
+
printHeading(`${pallet.name} Events`);
|
|
1555
|
+
for (const e of pallet.events) {
|
|
1556
|
+
const fields2 = describeEventFields(meta, pallet.name, e.name);
|
|
1557
|
+
console.log(` ${CYAN}${e.name}${RESET}${DIM}${fields2}${RESET}`);
|
|
1558
|
+
const summary = firstSentence(e.docs);
|
|
1559
|
+
if (summary) {
|
|
1560
|
+
console.log(` ${DIM}${summary}${RESET}`);
|
|
1561
|
+
}
|
|
1562
|
+
}
|
|
1563
|
+
console.log();
|
|
1564
|
+
return;
|
|
1565
|
+
}
|
|
1566
|
+
const eventItem = pallet.events.find((e) => e.name.toLowerCase() === parsed.item.toLowerCase());
|
|
1567
|
+
if (!eventItem) {
|
|
1568
|
+
const names = pallet.events.map((e) => e.name);
|
|
1569
|
+
throw new Error(suggestMessage(`event in ${pallet.name}`, parsed.item, names));
|
|
1570
|
+
}
|
|
1571
|
+
printHeading(`${pallet.name}.${eventItem.name} (Event)`);
|
|
1572
|
+
const fields = describeEventFields(meta, pallet.name, eventItem.name);
|
|
1573
|
+
console.log(` ${BOLD}Fields:${RESET} ${fields}`);
|
|
1574
|
+
if (eventItem.docs.length) {
|
|
1575
|
+
console.log();
|
|
1576
|
+
printDocs(eventItem.docs);
|
|
1577
|
+
}
|
|
1578
|
+
console.log();
|
|
1579
|
+
});
|
|
1580
|
+
cli.command("error [target]", "List or inspect pallet errors").alias("errors").option("--chain <name>", "Target chain").option("--rpc <url>", "Override RPC endpoint").action(async (target, opts) => {
|
|
1581
|
+
if (!target) {
|
|
1582
|
+
console.log("Usage: dot errors <[Chain.]Pallet[.Error]> [--chain <name>]");
|
|
1583
|
+
console.log("");
|
|
1584
|
+
console.log("Examples:");
|
|
1585
|
+
console.log(" $ dot errors Balances");
|
|
1586
|
+
console.log(" $ dot errors Balances.InsufficientBalance");
|
|
1587
|
+
return;
|
|
1588
|
+
}
|
|
1589
|
+
const config = await loadConfig();
|
|
1590
|
+
const knownChains = Object.keys(config.chains);
|
|
1591
|
+
const parsed = parseTarget(target, { knownChains, allowPalletOnly: true });
|
|
1592
|
+
const effectiveChain = resolveTargetChain(parsed, opts.chain);
|
|
1593
|
+
const { name: chainName, chain: chainConfig } = resolveChain(config, effectiveChain);
|
|
1594
|
+
const meta = await loadMeta(chainName, chainConfig, opts.rpc);
|
|
1595
|
+
const pallet = resolvePallet(meta, parsed.pallet);
|
|
1596
|
+
if (!parsed.item) {
|
|
1597
|
+
if (pallet.errors.length === 0) {
|
|
1598
|
+
console.log(`No errors in ${pallet.name}.`);
|
|
1599
|
+
return;
|
|
1600
|
+
}
|
|
1601
|
+
printHeading(`${pallet.name} Errors`);
|
|
1602
|
+
for (const e of pallet.errors) {
|
|
1603
|
+
console.log(` ${CYAN}${e.name}${RESET}`);
|
|
1604
|
+
const summary = firstSentence(e.docs);
|
|
1605
|
+
if (summary) {
|
|
1606
|
+
console.log(` ${DIM}${summary}${RESET}`);
|
|
1607
|
+
}
|
|
1608
|
+
}
|
|
1609
|
+
console.log();
|
|
1610
|
+
return;
|
|
1611
|
+
}
|
|
1612
|
+
const errorItem = pallet.errors.find((e) => e.name.toLowerCase() === parsed.item.toLowerCase());
|
|
1613
|
+
if (!errorItem) {
|
|
1614
|
+
const names = pallet.errors.map((e) => e.name);
|
|
1615
|
+
throw new Error(suggestMessage(`error in ${pallet.name}`, parsed.item, names));
|
|
1616
|
+
}
|
|
1617
|
+
printHeading(`${pallet.name}.${errorItem.name} (Error)`);
|
|
1618
|
+
if (errorItem.docs.length) {
|
|
1619
|
+
printDocs(errorItem.docs);
|
|
1620
|
+
}
|
|
1621
|
+
console.log();
|
|
1622
|
+
});
|
|
1623
|
+
cli.command("storage [target]", "List or inspect pallet storage items").option("--chain <name>", "Target chain").option("--rpc <url>", "Override RPC endpoint").action(async (target, opts) => {
|
|
1624
|
+
if (!target) {
|
|
1625
|
+
console.log("Usage: dot storage <[Chain.]Pallet[.Item]> [--chain <name>]");
|
|
1626
|
+
console.log("");
|
|
1627
|
+
console.log("Examples:");
|
|
1628
|
+
console.log(" $ dot storage System");
|
|
1629
|
+
console.log(" $ dot storage System.Account");
|
|
1630
|
+
return;
|
|
1631
|
+
}
|
|
1632
|
+
const config = await loadConfig();
|
|
1633
|
+
const knownChains = Object.keys(config.chains);
|
|
1634
|
+
const parsed = parseTarget(target, { knownChains, allowPalletOnly: true });
|
|
1635
|
+
const effectiveChain = resolveTargetChain(parsed, opts.chain);
|
|
1636
|
+
const { name: chainName, chain: chainConfig } = resolveChain(config, effectiveChain);
|
|
1637
|
+
const meta = await loadMeta(chainName, chainConfig, opts.rpc);
|
|
1638
|
+
const pallet = resolvePallet(meta, parsed.pallet);
|
|
1639
|
+
if (!parsed.item) {
|
|
1640
|
+
if (pallet.storage.length === 0) {
|
|
1641
|
+
console.log(`No storage items in ${pallet.name}.`);
|
|
1642
|
+
return;
|
|
1643
|
+
}
|
|
1644
|
+
printHeading(`${pallet.name} Storage`);
|
|
1645
|
+
for (const s of pallet.storage) {
|
|
1646
|
+
const valueType = describeType(meta.lookup, s.valueTypeId);
|
|
1647
|
+
let typeSuffix;
|
|
1648
|
+
if (s.keyTypeId != null) {
|
|
1649
|
+
const keyType = describeType(meta.lookup, s.keyTypeId);
|
|
1650
|
+
typeSuffix = `: ${keyType} → ${valueType} [map]`;
|
|
1651
|
+
} else {
|
|
1652
|
+
typeSuffix = `: ${valueType}`;
|
|
1653
|
+
}
|
|
1654
|
+
console.log(` ${CYAN}${s.name}${RESET}${DIM}${typeSuffix}${RESET}`);
|
|
1655
|
+
const summary = firstSentence(s.docs);
|
|
1656
|
+
if (summary) {
|
|
1657
|
+
console.log(` ${DIM}${summary}${RESET}`);
|
|
1658
|
+
}
|
|
1659
|
+
}
|
|
1660
|
+
console.log();
|
|
1661
|
+
return;
|
|
1662
|
+
}
|
|
1663
|
+
const storageItem = pallet.storage.find((s) => s.name.toLowerCase() === parsed.item.toLowerCase());
|
|
1664
|
+
if (!storageItem) {
|
|
1665
|
+
const names = pallet.storage.map((s) => s.name);
|
|
1666
|
+
throw new Error(suggestMessage(`storage item in ${pallet.name}`, parsed.item, names));
|
|
1667
|
+
}
|
|
1668
|
+
printHeading(`${pallet.name}.${storageItem.name} (Storage)`);
|
|
1669
|
+
console.log(` ${BOLD}Type:${RESET} ${storageItem.type}`);
|
|
1670
|
+
console.log(` ${BOLD}Value:${RESET} ${describeType(meta.lookup, storageItem.valueTypeId)}`);
|
|
1671
|
+
if (storageItem.keyTypeId != null) {
|
|
1672
|
+
console.log(` ${BOLD}Key:${RESET} ${describeType(meta.lookup, storageItem.keyTypeId)}`);
|
|
1673
|
+
}
|
|
1674
|
+
if (storageItem.docs.length) {
|
|
1675
|
+
console.log();
|
|
1676
|
+
printDocs(storageItem.docs);
|
|
1677
|
+
}
|
|
1678
|
+
console.log();
|
|
1679
|
+
});
|
|
1680
|
+
cli.command("pallet [target]", "List all pallets or inspect a specific pallet").alias("pallets").option("--chain <name>", "Target chain").option("--rpc <url>", "Override RPC endpoint").action(async (target, opts) => {
|
|
1681
|
+
const config = await loadConfig();
|
|
1682
|
+
const knownChains = Object.keys(config.chains);
|
|
1683
|
+
let effectiveChain = opts.chain;
|
|
1684
|
+
let palletName;
|
|
1685
|
+
if (target) {
|
|
1686
|
+
const parsed = parseTarget(target, { knownChains, allowPalletOnly: true });
|
|
1687
|
+
effectiveChain = resolveTargetChain(parsed, opts.chain);
|
|
1688
|
+
palletName = parsed.pallet;
|
|
1689
|
+
}
|
|
1690
|
+
const { name: chainName, chain: chainConfig } = resolveChain(config, effectiveChain);
|
|
1691
|
+
const meta = await loadMeta(chainName, chainConfig, opts.rpc);
|
|
1692
|
+
if (!palletName) {
|
|
1693
|
+
const pallets = listPallets(meta);
|
|
1694
|
+
printHeading(`Pallets on ${chainName} (${pallets.length})`);
|
|
1695
|
+
for (const p of pallets) {
|
|
1696
|
+
const counts2 = [];
|
|
1697
|
+
if (p.storage.length)
|
|
1698
|
+
counts2.push(`${p.storage.length} storage`);
|
|
1699
|
+
if (p.constants.length)
|
|
1700
|
+
counts2.push(`${p.constants.length} constants`);
|
|
1701
|
+
if (p.calls.length)
|
|
1702
|
+
counts2.push(`${p.calls.length} calls`);
|
|
1703
|
+
if (p.events.length)
|
|
1704
|
+
counts2.push(`${p.events.length} events`);
|
|
1705
|
+
if (p.errors.length)
|
|
1706
|
+
counts2.push(`${p.errors.length} errors`);
|
|
1707
|
+
printItem(p.name, counts2.join(", "));
|
|
1708
|
+
}
|
|
1709
|
+
console.log();
|
|
1710
|
+
return;
|
|
1711
|
+
}
|
|
1712
|
+
const pallet = resolvePallet(meta, palletName);
|
|
1713
|
+
printHeading(`${pallet.name} Pallet`);
|
|
1714
|
+
if (pallet.docs.length) {
|
|
1715
|
+
printDocs(pallet.docs);
|
|
1716
|
+
console.log();
|
|
1717
|
+
}
|
|
1718
|
+
const counts = [];
|
|
1719
|
+
if (pallet.storage.length)
|
|
1720
|
+
counts.push(`${pallet.storage.length} storage`);
|
|
1721
|
+
if (pallet.constants.length)
|
|
1722
|
+
counts.push(`${pallet.constants.length} constants`);
|
|
1723
|
+
if (pallet.calls.length)
|
|
1724
|
+
counts.push(`${pallet.calls.length} calls`);
|
|
1725
|
+
if (pallet.events.length)
|
|
1726
|
+
counts.push(`${pallet.events.length} events`);
|
|
1727
|
+
if (pallet.errors.length)
|
|
1728
|
+
counts.push(`${pallet.errors.length} errors`);
|
|
1729
|
+
if (counts.length) {
|
|
1730
|
+
console.log(` ${counts.join(", ")}`);
|
|
1731
|
+
}
|
|
1732
|
+
console.log();
|
|
1733
|
+
});
|
|
1734
|
+
}
|
|
1735
|
+
|
|
1383
1736
|
// src/core/hash.ts
|
|
1384
1737
|
import { blake2b } from "@noble/hashes/blake2.js";
|
|
1385
1738
|
import { sha256 } from "@noble/hashes/sha2.js";
|
|
@@ -1513,7 +1866,7 @@ function registerHashCommand(cli) {
|
|
|
1513
1866
|
|
|
1514
1867
|
// src/commands/inspect.ts
|
|
1515
1868
|
function registerInspectCommand(cli) {
|
|
1516
|
-
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) => {
|
|
1869
|
+
cli.command("inspect [target]", "Inspect chain metadata (pallets, storage, constants, calls, events, errors)").option("--chain <name>", "Target chain").option("--rpc <url>", "Override RPC endpoint").action(async (target, opts) => {
|
|
1517
1870
|
const config = await loadConfig();
|
|
1518
1871
|
const knownChains = Object.keys(config.chains);
|
|
1519
1872
|
let effectiveChain = opts.chain;
|
|
@@ -1530,7 +1883,7 @@ function registerInspectCommand(cli) {
|
|
|
1530
1883
|
try {
|
|
1531
1884
|
meta = await getOrFetchMetadata(chainName);
|
|
1532
1885
|
} catch {
|
|
1533
|
-
console.
|
|
1886
|
+
console.error(`Fetching metadata from ${chainName}...`);
|
|
1534
1887
|
const clientHandle = await createChainClient(chainName, chainConfig, opts.rpc);
|
|
1535
1888
|
try {
|
|
1536
1889
|
meta = await getOrFetchMetadata(chainName, clientHandle);
|
|
@@ -1549,6 +1902,10 @@ function registerInspectCommand(cli) {
|
|
|
1549
1902
|
counts.push(`${p.constants.length} constants`);
|
|
1550
1903
|
if (p.calls.length)
|
|
1551
1904
|
counts.push(`${p.calls.length} calls`);
|
|
1905
|
+
if (p.events.length)
|
|
1906
|
+
counts.push(`${p.events.length} events`);
|
|
1907
|
+
if (p.errors.length)
|
|
1908
|
+
counts.push(`${p.errors.length} errors`);
|
|
1552
1909
|
printItem(p.name, counts.join(", "));
|
|
1553
1910
|
}
|
|
1554
1911
|
console.log();
|
|
@@ -1568,24 +1925,66 @@ function registerInspectCommand(cli) {
|
|
|
1568
1925
|
if (pallet2.storage.length) {
|
|
1569
1926
|
console.log(` ${BOLD}Storage Items:${RESET}`);
|
|
1570
1927
|
for (const s of pallet2.storage) {
|
|
1571
|
-
const
|
|
1572
|
-
|
|
1928
|
+
const valueType = describeType(meta.lookup, s.valueTypeId);
|
|
1929
|
+
let typeSuffix;
|
|
1930
|
+
if (s.keyTypeId != null) {
|
|
1931
|
+
const keyType = describeType(meta.lookup, s.keyTypeId);
|
|
1932
|
+
typeSuffix = `: ${keyType} → ${valueType} [map]`;
|
|
1933
|
+
} else {
|
|
1934
|
+
typeSuffix = `: ${valueType}`;
|
|
1935
|
+
}
|
|
1936
|
+
console.log(` ${CYAN}${s.name}${RESET}${DIM}${typeSuffix}${RESET}`);
|
|
1937
|
+
const summary = firstSentence(s.docs);
|
|
1938
|
+
if (summary) {
|
|
1939
|
+
console.log(` ${DIM}${summary}${RESET}`);
|
|
1940
|
+
}
|
|
1573
1941
|
}
|
|
1574
1942
|
console.log();
|
|
1575
1943
|
}
|
|
1576
1944
|
if (pallet2.constants.length) {
|
|
1577
1945
|
console.log(` ${BOLD}Constants:${RESET}`);
|
|
1578
1946
|
for (const c of pallet2.constants) {
|
|
1579
|
-
const
|
|
1580
|
-
console.log(` ${CYAN}${c.name}${RESET}${DIM}${
|
|
1947
|
+
const typeStr = describeType(meta.lookup, c.typeId);
|
|
1948
|
+
console.log(` ${CYAN}${c.name}${RESET}${DIM}: ${typeStr}${RESET}`);
|
|
1949
|
+
const summary = firstSentence(c.docs);
|
|
1950
|
+
if (summary) {
|
|
1951
|
+
console.log(` ${DIM}${summary}${RESET}`);
|
|
1952
|
+
}
|
|
1581
1953
|
}
|
|
1582
1954
|
console.log();
|
|
1583
1955
|
}
|
|
1584
1956
|
if (pallet2.calls.length) {
|
|
1585
1957
|
console.log(` ${BOLD}Calls:${RESET}`);
|
|
1586
1958
|
for (const c of pallet2.calls) {
|
|
1587
|
-
const
|
|
1588
|
-
console.log(` ${CYAN}${c.name}${RESET}${DIM}${
|
|
1959
|
+
const args = describeCallArgs(meta, pallet2.name, c.name);
|
|
1960
|
+
console.log(` ${CYAN}${c.name}${RESET}${DIM}${args}${RESET}`);
|
|
1961
|
+
const summary = firstSentence(c.docs);
|
|
1962
|
+
if (summary) {
|
|
1963
|
+
console.log(` ${DIM}${summary}${RESET}`);
|
|
1964
|
+
}
|
|
1965
|
+
}
|
|
1966
|
+
console.log();
|
|
1967
|
+
}
|
|
1968
|
+
if (pallet2.events.length) {
|
|
1969
|
+
console.log(` ${BOLD}Events:${RESET}`);
|
|
1970
|
+
for (const e of pallet2.events) {
|
|
1971
|
+
const fields = describeEventFields(meta, pallet2.name, e.name);
|
|
1972
|
+
console.log(` ${CYAN}${e.name}${RESET}${DIM}${fields}${RESET}`);
|
|
1973
|
+
const summary = firstSentence(e.docs);
|
|
1974
|
+
if (summary) {
|
|
1975
|
+
console.log(` ${DIM}${summary}${RESET}`);
|
|
1976
|
+
}
|
|
1977
|
+
}
|
|
1978
|
+
console.log();
|
|
1979
|
+
}
|
|
1980
|
+
if (pallet2.errors.length) {
|
|
1981
|
+
console.log(` ${BOLD}Errors:${RESET}`);
|
|
1982
|
+
for (const e of pallet2.errors) {
|
|
1983
|
+
console.log(` ${CYAN}${e.name}${RESET}`);
|
|
1984
|
+
const summary = firstSentence(e.docs);
|
|
1985
|
+
if (summary) {
|
|
1986
|
+
console.log(` ${DIM}${summary}${RESET}`);
|
|
1987
|
+
}
|
|
1589
1988
|
}
|
|
1590
1989
|
console.log();
|
|
1591
1990
|
}
|
|
@@ -1634,10 +2033,33 @@ function registerInspectCommand(cli) {
|
|
|
1634
2033
|
console.log();
|
|
1635
2034
|
return;
|
|
1636
2035
|
}
|
|
2036
|
+
const eventItem = pallet.events.find((e) => e.name.toLowerCase() === itemName.toLowerCase());
|
|
2037
|
+
if (eventItem) {
|
|
2038
|
+
printHeading(`${pallet.name}.${eventItem.name} (Event)`);
|
|
2039
|
+
const fields = describeEventFields(meta, pallet.name, eventItem.name);
|
|
2040
|
+
console.log(` ${BOLD}Fields:${RESET} ${fields}`);
|
|
2041
|
+
if (eventItem.docs.length) {
|
|
2042
|
+
console.log();
|
|
2043
|
+
printDocs(eventItem.docs);
|
|
2044
|
+
}
|
|
2045
|
+
console.log();
|
|
2046
|
+
return;
|
|
2047
|
+
}
|
|
2048
|
+
const errorItem = pallet.errors.find((e) => e.name.toLowerCase() === itemName.toLowerCase());
|
|
2049
|
+
if (errorItem) {
|
|
2050
|
+
printHeading(`${pallet.name}.${errorItem.name} (Error)`);
|
|
2051
|
+
if (errorItem.docs.length) {
|
|
2052
|
+
printDocs(errorItem.docs);
|
|
2053
|
+
}
|
|
2054
|
+
console.log();
|
|
2055
|
+
return;
|
|
2056
|
+
}
|
|
1637
2057
|
const allItems = [
|
|
1638
2058
|
...pallet.storage.map((s) => s.name),
|
|
1639
2059
|
...pallet.constants.map((c) => c.name),
|
|
1640
|
-
...pallet.calls.map((c) => c.name)
|
|
2060
|
+
...pallet.calls.map((c) => c.name),
|
|
2061
|
+
...pallet.events.map((e) => e.name),
|
|
2062
|
+
...pallet.errors.map((e) => e.name)
|
|
1641
2063
|
];
|
|
1642
2064
|
throw new Error(suggestMessage(`item in ${pallet.name}`, itemName, allItems));
|
|
1643
2065
|
});
|
|
@@ -2970,6 +3392,7 @@ registerChainCommands(cli);
|
|
|
2970
3392
|
registerInspectCommand(cli);
|
|
2971
3393
|
registerQueryCommand(cli);
|
|
2972
3394
|
registerConstCommand(cli);
|
|
3395
|
+
registerFocusedInspectCommands(cli);
|
|
2973
3396
|
registerAccountCommands(cli);
|
|
2974
3397
|
registerTxCommand(cli);
|
|
2975
3398
|
registerHashCommand(cli);
|