polkadot-cli 0.8.0 → 0.9.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 +40 -1
  2. package/dist/cli.mjs +78 -29
  3. package/package.json +3 -3
package/README.md CHANGED
@@ -94,19 +94,37 @@ dot query System.Account 5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY
94
94
  # All map entries (default limit: 100)
95
95
  dot query System.Account --limit 10
96
96
 
97
- # Pipe to jq (colors disabled automatically)
97
+ # Pipe to jq stdout is clean JSON, no extra text
98
98
  dot query System.Account --limit 5 | jq '.[0].value.data.free'
99
+ dot query System.Number --output json | jq '.+1'
99
100
 
100
101
  # Query a specific chain using chain prefix
101
102
  dot query kusama.System.Account 5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY
102
103
  ```
103
104
 
105
+ #### Output formatting
106
+
107
+ Query results automatically convert on-chain types for readability:
108
+
109
+ - **BigInt** values (e.g. balances) render as decimal strings
110
+ - **Binary** fields (e.g. token `name`, `symbol`) render as text when valid UTF-8, or as `0x`-prefixed hex otherwise
111
+ - **Uint8Array** values render as `0x`-prefixed hex
112
+
113
+ ```bash
114
+ # Token metadata — symbol and name display as text, not {}
115
+ dot query assethub-paseo.Assets.Metadata 50000413
116
+ # { "deposit": "6693666000", "name": "Paseo Token", "symbol": "PAS", ... }
117
+ ```
118
+
104
119
  ### Look up constants
105
120
 
106
121
  ```bash
107
122
  dot const Balances.ExistentialDeposit
108
123
  dot const System.SS58Prefix --chain kusama
109
124
  dot const kusama.Balances.ExistentialDeposit
125
+
126
+ # Pipe to jq — stdout is clean JSON, no extra text
127
+ dot const Balances.ExistentialDeposit --output json | jq
110
128
  ```
111
129
 
112
130
  ### Inspect metadata
@@ -149,6 +167,27 @@ dot tx 0x0503008eaf04151687736326c9fea17e25fc5287613693c912909cb226aa4794f26a48
149
167
  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
150
168
  ```
151
169
 
170
+ #### Enum shorthand
171
+
172
+ Enum arguments accept a concise `Variant(value)` syntax instead of verbose JSON:
173
+
174
+ ```bash
175
+ # Instead of: '{"type":"system","value":{"type":"Authorized"}}'
176
+ dot tx Utility.dispatch_as 'system(Authorized)' $(dot tx System.remark 0xcafe --encode) --from alice
177
+
178
+ # Nested enums work too
179
+ dot tx Utility.dispatch_as 'system(Signed(5FHneW46...))' <call> --from alice
180
+
181
+ # Void variants — empty parens or just the name
182
+ dot tx ... 'Root()' ...
183
+ dot tx ... 'Root' ...
184
+
185
+ # JSON inside parens for struct values
186
+ dot tx ... 'AccountId32({"id":"0xd435..."})' ...
187
+ ```
188
+
189
+ Variant matching is case-insensitive (`system` resolves to `system`, `authorized` to `Authorized`). All existing formats (JSON objects, hex, SS58 addresses) continue to work unchanged.
190
+
152
191
  #### Encode call data
153
192
 
154
193
  Encode a call to hex without signing or submitting. Useful for preparing calls to pass to `Sudo.sudo`, multisig proposals, or governance. Works offline from cached metadata and does not require `--from`.
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.0";
8
+ var version = "0.9.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";
@@ -212,6 +212,7 @@ async function resolveAccountSigner(name) {
212
212
  }
213
213
 
214
214
  // src/core/output.ts
215
+ import { Binary } from "polkadot-api";
215
216
  var isTTY = process.stdout.isTTY ?? false;
216
217
  var RESET = isTTY ? "\x1B[0m" : "";
217
218
  var CYAN = isTTY ? "\x1B[36m" : "";
@@ -224,6 +225,10 @@ var BOLD = isTTY ? "\x1B[1m" : "";
224
225
  function replacer(_key, value) {
225
226
  if (typeof value === "bigint")
226
227
  return value.toString();
228
+ if (value instanceof Binary) {
229
+ const text = value.asText();
230
+ return text.includes("�") ? value.asHex() : text;
231
+ }
227
232
  if (value instanceof Uint8Array)
228
233
  return `0x${Buffer.from(value).toString("hex")}`;
229
234
  return value;
@@ -932,12 +937,6 @@ function registerConstCommand(cli) {
932
937
  const runtimeToken = await unsafeApi.runtimeToken;
933
938
  const result = unsafeApi.constants[palletInfo.name][constantItem.name](runtimeToken);
934
939
  const format = opts.output ?? "pretty";
935
- if (format === "json") {
936
- console.error(`chain: ${chainName}`);
937
- } else {
938
- console.log(`${DIM}chain: ${chainName}${RESET}
939
- `);
940
- }
941
940
  printResult(result, format);
942
941
  } finally {
943
942
  clientHandle.destroy();
@@ -1207,7 +1206,7 @@ function parseValue(arg) {
1207
1206
 
1208
1207
  // src/commands/tx.ts
1209
1208
  import { getViewBuilder } from "@polkadot-api/view-builder";
1210
- import { Binary } from "polkadot-api";
1209
+ import { Binary as Binary2 } from "polkadot-api";
1211
1210
 
1212
1211
  // src/core/explorers.ts
1213
1212
  var pjsAppsLink = (rpc, hash) => `https://polkadot.js.org/apps/?rpc=${encodeURIComponent(rpc)}#/explorer/query/${hash}`;
@@ -1279,8 +1278,8 @@ function normalizeValue(lookup, entry, value) {
1279
1278
  }
1280
1279
  if (innerResolved.type === "primitive" && innerResolved.value === "u8" && typeof value === "string") {
1281
1280
  if (/^0x[0-9a-fA-F]*$/.test(value))
1282
- return Binary.fromHex(value);
1283
- return Binary.fromText(value);
1281
+ return Binary2.fromHex(value);
1282
+ return Binary2.fromText(value);
1284
1283
  }
1285
1284
  if (Array.isArray(value)) {
1286
1285
  const innerEntry = resolved.value;
@@ -1335,7 +1334,20 @@ function normalizeValue(lookup, entry, value) {
1335
1334
  return value;
1336
1335
  }
1337
1336
  }
1337
+ function parseEnumShorthand(arg) {
1338
+ if (arg.startsWith("{") || arg.startsWith("[") || arg.startsWith("0x"))
1339
+ return null;
1340
+ const firstParen = arg.indexOf("(");
1341
+ if (firstParen === -1 || !arg.endsWith(")"))
1342
+ return null;
1343
+ const variant = arg.slice(0, firstParen);
1344
+ if (!/^[a-zA-Z_]\w*$/.test(variant))
1345
+ return null;
1346
+ return { variant, inner: arg.slice(firstParen + 1, -1) };
1347
+ }
1338
1348
  function parseTypedArg(meta, entry, arg) {
1349
+ if (entry.type === "lookupEntry")
1350
+ return parseTypedArg(meta, entry.value, arg);
1339
1351
  switch (entry.type) {
1340
1352
  case "primitive":
1341
1353
  return parsePrimitive(entry.value, arg);
@@ -1353,7 +1365,7 @@ function parseTypedArg(meta, entry, arg) {
1353
1365
  case "enum": {
1354
1366
  if (/^0x[0-9a-fA-F]+$/.test(arg) && meta.lookup.call != null && entry.id === meta.lookup.call) {
1355
1367
  const callCodec = meta.builder.buildDefinition(meta.lookup.call);
1356
- return callCodec.dec(Binary.fromHex(arg).asBytes());
1368
+ return callCodec.dec(Binary2.fromHex(arg).asBytes());
1357
1369
  }
1358
1370
  if (arg.startsWith("{")) {
1359
1371
  try {
@@ -1361,6 +1373,19 @@ function parseTypedArg(meta, entry, arg) {
1361
1373
  } catch {}
1362
1374
  }
1363
1375
  const variants = Object.keys(entry.value);
1376
+ const shorthand = parseEnumShorthand(arg);
1377
+ if (shorthand) {
1378
+ const matched2 = variants.find((v) => v.toLowerCase() === shorthand.variant.toLowerCase());
1379
+ if (matched2) {
1380
+ const variantDef = entry.value[matched2];
1381
+ const resolvedDef = variantDef.type === "lookupEntry" ? variantDef.value : variantDef;
1382
+ if (resolvedDef.type === "void" || shorthand.inner === "") {
1383
+ return { type: matched2 };
1384
+ }
1385
+ const innerValue = parseTypedArg(meta, variantDef, shorthand.inner);
1386
+ return normalizeValue(meta.lookup, entry, { type: matched2, value: innerValue });
1387
+ }
1388
+ }
1364
1389
  if (variants.includes("Id")) {
1365
1390
  const idVariant = entry.value.Id;
1366
1391
  const innerType = idVariant.type === "lookupEntry" ? idVariant.value : idVariant;
@@ -1382,8 +1407,8 @@ function parseTypedArg(meta, entry, arg) {
1382
1407
  const inner = entry.value;
1383
1408
  if (inner.type === "primitive" && inner.value === "u8") {
1384
1409
  if (/^0x[0-9a-fA-F]*$/.test(arg))
1385
- return Binary.fromHex(arg);
1386
- return Binary.fromText(arg);
1410
+ return Binary2.fromHex(arg);
1411
+ return Binary2.fromText(arg);
1387
1412
  }
1388
1413
  if (arg.startsWith("[")) {
1389
1414
  try {
@@ -1391,7 +1416,7 @@ function parseTypedArg(meta, entry, arg) {
1391
1416
  } catch {}
1392
1417
  }
1393
1418
  if (/^0x[0-9a-fA-F]*$/.test(arg))
1394
- return Binary.fromHex(arg);
1419
+ return Binary2.fromHex(arg);
1395
1420
  return parseValue(arg);
1396
1421
  }
1397
1422
  case "struct":
@@ -1496,12 +1521,6 @@ function registerQueryCommand(cli) {
1496
1521
  const storageApi = unsafeApi.query[palletInfo.name][storageItem.name];
1497
1522
  const parsedKeys = parseStorageKeys(meta, palletInfo.name, storageItem, keys);
1498
1523
  const format = opts.output ?? "pretty";
1499
- if (format === "json") {
1500
- console.error(`chain: ${chainName}`);
1501
- } else {
1502
- console.log(`${DIM}chain: ${chainName}${RESET}
1503
- `);
1504
- }
1505
1524
  if (storageItem.type === "map" && parsedKeys.length === 0) {
1506
1525
  const entries = await storageApi.getEntries();
1507
1526
  const limit = Number(opts.limit);
@@ -1563,7 +1582,7 @@ function parseStorageKeys(meta, palletName, storageItem, args) {
1563
1582
 
1564
1583
  // src/commands/tx.ts
1565
1584
  import { getViewBuilder as getViewBuilder2 } from "@polkadot-api/view-builder";
1566
- import { Binary as Binary2 } from "polkadot-api";
1585
+ import { Binary as Binary3 } from "polkadot-api";
1567
1586
  function registerTxCommand(cli) {
1568
1587
  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) => {
1569
1588
  if (!target) {
@@ -1628,7 +1647,7 @@ function registerTxCommand(cli) {
1628
1647
  throw new Error(`Extra arguments are not allowed when submitting a raw call hex.
1629
1648
  ` + "Usage: dot tx 0x<call_hex> --from <account>");
1630
1649
  }
1631
- const callBinary = Binary2.fromHex(target);
1650
+ const callBinary = Binary3.fromHex(target);
1632
1651
  tx = await unsafeApi.txFromCallData(callBinary);
1633
1652
  callHex = target;
1634
1653
  } else {
@@ -1649,7 +1668,7 @@ function registerTxCommand(cli) {
1649
1668
  const { codec, location } = meta.builder.buildCall(palletInfo.name, callInfo.name);
1650
1669
  const encodedArgs = codec.enc(callData);
1651
1670
  const fullCall = new Uint8Array([location[0], location[1], ...encodedArgs]);
1652
- console.log(Binary2.fromBytes(fullCall).asHex());
1671
+ console.log(Binary3.fromBytes(fullCall).asHex());
1653
1672
  return;
1654
1673
  }
1655
1674
  tx = unsafeApi.tx[palletInfo.name][callInfo.name](callData);
@@ -1832,6 +1851,10 @@ function formatEventValue(v) {
1832
1851
  return v.toString();
1833
1852
  if (v === null || v === undefined)
1834
1853
  return "null";
1854
+ if (v instanceof Binary3) {
1855
+ const text = v.asText();
1856
+ return text.includes("�") ? v.asHex() : text;
1857
+ }
1835
1858
  return JSON.stringify(v, (_k, val) => typeof val === "bigint" ? val.toString() : val);
1836
1859
  }
1837
1860
  function parseCallArgs(meta, palletName, callName, args) {
@@ -1939,8 +1962,8 @@ function normalizeValue2(lookup, entry, value) {
1939
1962
  }
1940
1963
  if (innerResolved.type === "primitive" && innerResolved.value === "u8" && typeof value === "string") {
1941
1964
  if (/^0x[0-9a-fA-F]*$/.test(value))
1942
- return Binary2.fromHex(value);
1943
- return Binary2.fromText(value);
1965
+ return Binary3.fromHex(value);
1966
+ return Binary3.fromText(value);
1944
1967
  }
1945
1968
  if (Array.isArray(value)) {
1946
1969
  const innerEntry = resolved.value;
@@ -1995,7 +2018,20 @@ function normalizeValue2(lookup, entry, value) {
1995
2018
  return value;
1996
2019
  }
1997
2020
  }
2021
+ function parseEnumShorthand2(arg) {
2022
+ if (arg.startsWith("{") || arg.startsWith("[") || arg.startsWith("0x"))
2023
+ return null;
2024
+ const firstParen = arg.indexOf("(");
2025
+ if (firstParen === -1 || !arg.endsWith(")"))
2026
+ return null;
2027
+ const variant = arg.slice(0, firstParen);
2028
+ if (!/^[a-zA-Z_]\w*$/.test(variant))
2029
+ return null;
2030
+ return { variant, inner: arg.slice(firstParen + 1, -1) };
2031
+ }
1998
2032
  function parseTypedArg2(meta, entry, arg) {
2033
+ if (entry.type === "lookupEntry")
2034
+ return parseTypedArg2(meta, entry.value, arg);
1999
2035
  switch (entry.type) {
2000
2036
  case "primitive":
2001
2037
  return parsePrimitive2(entry.value, arg);
@@ -2013,7 +2049,7 @@ function parseTypedArg2(meta, entry, arg) {
2013
2049
  case "enum": {
2014
2050
  if (/^0x[0-9a-fA-F]+$/.test(arg) && meta.lookup.call != null && entry.id === meta.lookup.call) {
2015
2051
  const callCodec = meta.builder.buildDefinition(meta.lookup.call);
2016
- return callCodec.dec(Binary2.fromHex(arg).asBytes());
2052
+ return callCodec.dec(Binary3.fromHex(arg).asBytes());
2017
2053
  }
2018
2054
  if (arg.startsWith("{")) {
2019
2055
  try {
@@ -2021,6 +2057,19 @@ function parseTypedArg2(meta, entry, arg) {
2021
2057
  } catch {}
2022
2058
  }
2023
2059
  const variants = Object.keys(entry.value);
2060
+ const shorthand = parseEnumShorthand2(arg);
2061
+ if (shorthand) {
2062
+ const matched2 = variants.find((v) => v.toLowerCase() === shorthand.variant.toLowerCase());
2063
+ if (matched2) {
2064
+ const variantDef = entry.value[matched2];
2065
+ const resolvedDef = variantDef.type === "lookupEntry" ? variantDef.value : variantDef;
2066
+ if (resolvedDef.type === "void" || shorthand.inner === "") {
2067
+ return { type: matched2 };
2068
+ }
2069
+ const innerValue = parseTypedArg2(meta, variantDef, shorthand.inner);
2070
+ return normalizeValue2(meta.lookup, entry, { type: matched2, value: innerValue });
2071
+ }
2072
+ }
2024
2073
  if (variants.includes("Id")) {
2025
2074
  const idVariant = entry.value.Id;
2026
2075
  const innerType = idVariant.type === "lookupEntry" ? idVariant.value : idVariant;
@@ -2042,8 +2091,8 @@ function parseTypedArg2(meta, entry, arg) {
2042
2091
  const inner = entry.value;
2043
2092
  if (inner.type === "primitive" && inner.value === "u8") {
2044
2093
  if (/^0x[0-9a-fA-F]*$/.test(arg))
2045
- return Binary2.fromHex(arg);
2046
- return Binary2.fromText(arg);
2094
+ return Binary3.fromHex(arg);
2095
+ return Binary3.fromText(arg);
2047
2096
  }
2048
2097
  if (arg.startsWith("[")) {
2049
2098
  try {
@@ -2051,7 +2100,7 @@ function parseTypedArg2(meta, entry, arg) {
2051
2100
  } catch {}
2052
2101
  }
2053
2102
  if (/^0x[0-9a-fA-F]*$/.test(arg))
2054
- return Binary2.fromHex(arg);
2103
+ return Binary3.fromHex(arg);
2055
2104
  return parseValue(arg);
2056
2105
  }
2057
2106
  case "struct":
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "polkadot-cli",
3
- "version": "0.8.0",
3
+ "version": "0.9.0",
4
4
  "description": "CLI tool for querying Polkadot-ecosystem on-chain state",
5
5
  "type": "module",
6
6
  "bin": {
@@ -17,8 +17,8 @@
17
17
  "typecheck": "tsc --noEmit",
18
18
  "lint": "biome check .",
19
19
  "lint:fix": "biome check --write .",
20
- "test": "bun test",
21
- "test:coverage": "bun test --coverage --coverage-reporter=lcov --coverage-dir=coverage",
20
+ "test": "bun test --concurrent",
21
+ "test:coverage": "bun test --concurrent --coverage --coverage-reporter=lcov --coverage-dir=coverage",
22
22
  "prepare": "husky",
23
23
  "changeset": "changeset",
24
24
  "version": "changeset version",