polkadot-cli 1.14.1 → 1.15.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 +316 -192
  2. package/dist/cli.mjs +395 -145
  3. package/package.json +2 -1
package/dist/cli.mjs CHANGED
@@ -181,13 +181,20 @@ import { access, mkdir, readFile, rm, writeFile } from "node:fs/promises";
181
181
  import { homedir } from "node:os";
182
182
  import { join } from "node:path";
183
183
  function getConfigDir() {
184
- return DOT_DIR;
184
+ const override = process.env.DOT_HOME;
185
+ return override && override.length > 0 ? override : join(homedir(), ".polkadot");
186
+ }
187
+ function getChainsDir() {
188
+ return join(getConfigDir(), "chains");
185
189
  }
186
190
  function getChainDir(chainName) {
187
- return join(CHAINS_DIR, chainName);
191
+ return join(getChainsDir(), chainName);
188
192
  }
189
193
  function getMetadataPath(chainName) {
190
- return join(CHAINS_DIR, chainName, "metadata.bin");
194
+ return join(getChainDir(chainName), "metadata.bin");
195
+ }
196
+ function getConfigPath() {
197
+ return join(getConfigDir(), "config.json");
191
198
  }
192
199
  async function ensureDir(dir) {
193
200
  await mkdir(dir, { recursive: true });
@@ -201,9 +208,10 @@ async function fileExists(path) {
201
208
  }
202
209
  }
203
210
  async function loadConfig() {
204
- await ensureDir(DOT_DIR);
205
- if (await fileExists(CONFIG_PATH)) {
206
- const saved = JSON.parse(await readFile(CONFIG_PATH, "utf-8"));
211
+ await ensureDir(getConfigDir());
212
+ const configPath = getConfigPath();
213
+ if (await fileExists(configPath)) {
214
+ const saved = JSON.parse(await readFile(configPath, "utf-8"));
207
215
  const chains = {};
208
216
  for (const [name, defaultConfig] of Object.entries(DEFAULT_CONFIG.chains)) {
209
217
  chains[name] = saved.chains[name] ? { ...defaultConfig, ...saved.chains[name] } : defaultConfig;
@@ -219,8 +227,8 @@ async function loadConfig() {
219
227
  return DEFAULT_CONFIG;
220
228
  }
221
229
  async function saveConfig(config) {
222
- await ensureDir(DOT_DIR);
223
- await writeFile(CONFIG_PATH, `${JSON.stringify(config, null, 2)}
230
+ await ensureDir(getConfigDir());
231
+ await writeFile(getConfigPath(), `${JSON.stringify(config, null, 2)}
224
232
  `);
225
233
  }
226
234
  async function loadMetadata(chainName) {
@@ -255,18 +263,17 @@ function resolveChain(config, chainFlag) {
255
263
  }
256
264
  return { name, chain: config.chains[name] };
257
265
  }
258
- var DOT_DIR, CONFIG_PATH, CHAINS_DIR;
259
266
  var init_store = __esm(() => {
260
267
  init_errors();
261
268
  init_types();
262
- DOT_DIR = join(homedir(), ".polkadot");
263
- CONFIG_PATH = join(DOT_DIR, "config.json");
264
- CHAINS_DIR = join(DOT_DIR, "chains");
265
269
  });
266
270
 
267
271
  // src/config/accounts-store.ts
268
272
  import { access as access2, mkdir as mkdir2, readFile as readFile2, writeFile as writeFile2 } from "node:fs/promises";
269
273
  import { join as join2 } from "node:path";
274
+ function getAccountsPath() {
275
+ return join2(getConfigDir(), "accounts.json");
276
+ }
270
277
  async function ensureDir2(dir) {
271
278
  await mkdir2(dir, { recursive: true });
272
279
  }
@@ -280,24 +287,23 @@ async function fileExists2(path) {
280
287
  }
281
288
  async function loadAccounts() {
282
289
  await ensureDir2(getConfigDir());
283
- if (await fileExists2(ACCOUNTS_PATH)) {
284
- const data = await readFile2(ACCOUNTS_PATH, "utf-8");
290
+ const path = getAccountsPath();
291
+ if (await fileExists2(path)) {
292
+ const data = await readFile2(path, "utf-8");
285
293
  return JSON.parse(data);
286
294
  }
287
295
  return { accounts: [] };
288
296
  }
289
297
  async function saveAccounts(file) {
290
298
  await ensureDir2(getConfigDir());
291
- await writeFile2(ACCOUNTS_PATH, `${JSON.stringify(file, null, 2)}
299
+ await writeFile2(getAccountsPath(), `${JSON.stringify(file, null, 2)}
292
300
  `);
293
301
  }
294
302
  function findAccount(file, name) {
295
303
  return file.accounts.find((a) => a.name.toLowerCase() === name.toLowerCase());
296
304
  }
297
- var ACCOUNTS_PATH;
298
305
  var init_accounts_store = __esm(() => {
299
306
  init_store();
300
- ACCOUNTS_PATH = join2(getConfigDir(), "accounts.json");
301
307
  });
302
308
 
303
309
  // src/config/accounts-types.ts
@@ -355,6 +361,7 @@ import {
355
361
  ss58Decode,
356
362
  validateMnemonic
357
363
  } from "@polkadot-labs/hdkd-helpers";
364
+ import { HDKD, secretFromSeed } from "@scure/sr25519";
358
365
  import { getPolkadotSigner } from "polkadot-api/signer";
359
366
  function isDevAccount(name) {
360
367
  return DEV_NAMES.includes(name.toLowerCase());
@@ -381,6 +388,50 @@ function getDevKeypair(name) {
381
388
  const path = devDerivationPath(name);
382
389
  return deriveFromMnemonic(DEV_PHRASE, path);
383
390
  }
391
+ function parseDerivations(path) {
392
+ const out = [];
393
+ for (const [, type, code] of path.matchAll(DERIVATION_RE)) {
394
+ out.push([type === "//" ? "hard" : "soft", code]);
395
+ }
396
+ return out;
397
+ }
398
+ function createChainCode(code) {
399
+ const chainCode = new Uint8Array(32);
400
+ const asNumber = +code;
401
+ if (Number.isNaN(asNumber)) {
402
+ const bytes = new TextEncoder().encode(code);
403
+ if (bytes.length >= 32) {
404
+ throw new Error(`Derivation component "${code}" is too long (max 31 bytes)`);
405
+ }
406
+ chainCode[0] = bytes.length << 2;
407
+ chainCode.set(bytes, 1);
408
+ } else {
409
+ const n = asNumber >>> 0;
410
+ chainCode[0] = n & 255;
411
+ chainCode[1] = n >>> 8 & 255;
412
+ chainCode[2] = n >>> 16 & 255;
413
+ chainCode[3] = n >>> 24 & 255;
414
+ }
415
+ return chainCode;
416
+ }
417
+ function deriveExpandedSecret(miniSecret, path) {
418
+ return parseDerivations(path).reduce((sk, [type, code]) => type === "hard" ? HDKD.secretHard(sk, createChainCode(code)) : HDKD.secretSoft(sk, createChainCode(code)), secretFromSeed(miniSecret));
419
+ }
420
+ function miniSecretFromSecret(secret) {
421
+ const isHexSeed = /^0x[0-9a-fA-F]{64}$/.test(secret);
422
+ if (isHexSeed) {
423
+ const clean = secret.slice(2);
424
+ const bytes = new Uint8Array(32);
425
+ for (let i = 0;i < clean.length; i += 2) {
426
+ bytes[i / 2] = parseInt(clean.substring(i, i + 2), 16);
427
+ }
428
+ return bytes;
429
+ }
430
+ if (!validateMnemonic(secret)) {
431
+ throw new Error("Invalid secret. Expected a 0x-prefixed 32-byte hex seed or a valid BIP39 mnemonic.");
432
+ }
433
+ return entropyToMiniSecret(mnemonicToEntropy(secret));
434
+ }
384
435
  function getDevAddress(name, prefix = 42) {
385
436
  const keypair = getDevKeypair(name);
386
437
  return ss58Address(keypair.publicKey, prefix);
@@ -474,10 +525,37 @@ async function resolveAccountSigner(name) {
474
525
  const keypair = await resolveAccountKeypair(name);
475
526
  return getPolkadotSigner(keypair.publicKey, "Sr25519", keypair.sign);
476
527
  }
477
- var DEV_NAMES;
528
+ async function resolveAccountExpandedSecret(name) {
529
+ if (isDevAccount(name)) {
530
+ const miniSecret2 = entropyToMiniSecret(mnemonicToEntropy(DEV_PHRASE));
531
+ return deriveExpandedSecret(miniSecret2, devDerivationPath(name));
532
+ }
533
+ const accountsFile = await loadAccounts();
534
+ const account = findAccount(accountsFile, name);
535
+ if (!account) {
536
+ const available = [...DEV_NAMES, ...accountsFile.accounts.map((a) => a.name)].sort((a, b) => a.localeCompare(b));
537
+ const suggestions = findClosest(name, available);
538
+ const hint = suggestions.length > 0 ? `
539
+ Did you mean: ${suggestions.join(", ")}?` : "";
540
+ const list = available.map((a) => `
541
+ - ${a}`).join("");
542
+ throw new Error(`Unknown account "${name}".${hint}
543
+ Available accounts:${list}`);
544
+ }
545
+ if (account.secret === undefined) {
546
+ throw new Error(`Account "${name}" is watch-only (no secret). Cannot derive private key. Import with --secret or --env.`);
547
+ }
548
+ const miniSecret = miniSecretFromSecret(resolveSecret(account.secret));
549
+ return deriveExpandedSecret(miniSecret, account.derivationPath);
550
+ }
551
+ function bytesToHex(bytes) {
552
+ return "0x" + Array.from(bytes).map((b) => b.toString(16).padStart(2, "0")).join("");
553
+ }
554
+ var DEV_NAMES, DERIVATION_RE;
478
555
  var init_accounts = __esm(() => {
479
556
  init_accounts_store();
480
557
  DEV_NAMES = ["alice", "bob", "charlie", "dave", "eve", "ferdie"];
558
+ DERIVATION_RE = /(\/{1,2})([^/]+)/g;
481
559
  });
482
560
 
483
561
  // src/utils/binary-display.ts
@@ -556,6 +634,33 @@ function printDocs(docs) {
556
634
  console.log(` ${DIM}${text}${RESET}`);
557
635
  }
558
636
  }
637
+ function printImportResults(params) {
638
+ const { added, overwritten, skipped, dryRun, noun } = params;
639
+ for (const name of added) {
640
+ console.log(` ${GREEN}${CHECK_MARK}${RESET} ${name}`);
641
+ }
642
+ for (const name of overwritten) {
643
+ console.log(` ${YELLOW}⟳${RESET} ${name}${DIM} (overwritten)${RESET}`);
644
+ }
645
+ for (const name of skipped) {
646
+ console.log(` ${DIM}- ${name} (skipped)${RESET}`);
647
+ }
648
+ if (added.length === 0 && overwritten.length === 0 && skipped.length === 0) {
649
+ const prefix = dryRun ? "(dry run) " : "";
650
+ console.log(`${prefix}No ${noun}s imported.`);
651
+ return;
652
+ }
653
+ const parts = [];
654
+ if (added.length > 0)
655
+ parts.push(`${added.length} added`);
656
+ if (overwritten.length > 0)
657
+ parts.push(`${overwritten.length} overwritten`);
658
+ if (skipped.length > 0)
659
+ parts.push(`${skipped.length} skipped`);
660
+ const suffix = dryRun ? " (dry run)" : "";
661
+ console.log();
662
+ console.log(`${parts.join(", ")}${suffix}`);
663
+ }
559
664
 
560
665
  class Spinner {
561
666
  timer = null;
@@ -802,6 +907,22 @@ function getSignedExtensions(meta) {
802
907
  return [];
803
908
  return byVersion[Number(versionKeys[0])] ?? [];
804
909
  }
910
+ function getSignedExtensionNames(meta) {
911
+ return getSignedExtensions(meta).map((e) => e.identifier).sort((a, b) => a.localeCompare(b));
912
+ }
913
+ function findSignedExtension(meta, identifier) {
914
+ return getSignedExtensions(meta).find((e) => e.identifier.toLowerCase() === identifier.toLowerCase());
915
+ }
916
+ function describeSignedExtension(meta, info) {
917
+ return {
918
+ identifier: info.identifier,
919
+ valueType: describeType(meta.lookup, info.type),
920
+ additionalSignedType: describeType(meta.lookup, info.additionalSigned),
921
+ valueTypeId: info.type,
922
+ additionalSignedTypeId: info.additionalSigned,
923
+ isBuiltin: PAPI_BUILTIN_EXTENSIONS.has(info.identifier)
924
+ };
925
+ }
805
926
  function getPalletNames(meta) {
806
927
  return meta.unified.pallets.map((p) => p.name).sort((a, b) => a.localeCompare(b));
807
928
  }
@@ -950,12 +1071,26 @@ function hexToBytes(hex) {
950
1071
  }
951
1072
  return bytes;
952
1073
  }
953
- var METADATA_TIMEOUT_MS = 15000, optionalOpaqueBytes, v15Arg;
1074
+ var METADATA_TIMEOUT_MS = 15000, optionalOpaqueBytes, v15Arg, PAPI_BUILTIN_EXTENSIONS;
954
1075
  var init_metadata = __esm(() => {
955
1076
  init_store();
956
1077
  init_errors();
957
1078
  optionalOpaqueBytes = Option(Bytes());
958
1079
  v15Arg = toHex(u32.enc(15));
1080
+ PAPI_BUILTIN_EXTENSIONS = new Set([
1081
+ "CheckNonZeroSender",
1082
+ "CheckSpecVersion",
1083
+ "CheckTxVersion",
1084
+ "CheckGenesis",
1085
+ "CheckMortality",
1086
+ "CheckNonce",
1087
+ "CheckWeight",
1088
+ "ChargeTransactionPayment",
1089
+ "ChargeAssetTxPayment",
1090
+ "CheckMetadataHash",
1091
+ "StorageWeightReclaim",
1092
+ "PrevalidateAttests"
1093
+ ]);
959
1094
  });
960
1095
 
961
1096
  // src/core/explorers.ts
@@ -1325,7 +1460,7 @@ function parsePrimitive(prim, arg) {
1325
1460
  return parseValue(arg);
1326
1461
  }
1327
1462
  }
1328
- var PAPI_BUILTIN_EXTENSIONS, NO_DEFAULT;
1463
+ var NO_DEFAULT;
1329
1464
  var init_tx = __esm(() => {
1330
1465
  init_store();
1331
1466
  init_types();
@@ -1337,20 +1472,6 @@ var init_tx = __esm(() => {
1337
1472
  init_binary_display();
1338
1473
  init_errors();
1339
1474
  init_focused_inspect();
1340
- PAPI_BUILTIN_EXTENSIONS = new Set([
1341
- "CheckNonZeroSender",
1342
- "CheckSpecVersion",
1343
- "CheckTxVersion",
1344
- "CheckGenesis",
1345
- "CheckMortality",
1346
- "CheckNonce",
1347
- "CheckWeight",
1348
- "ChargeTransactionPayment",
1349
- "ChargeAssetTxPayment",
1350
- "CheckMetadataHash",
1351
- "StorageWeightReclaim",
1352
- "PrevalidateAttests"
1353
- ]);
1354
1475
  NO_DEFAULT = Symbol("no-default");
1355
1476
  });
1356
1477
 
@@ -1894,7 +2015,8 @@ async function showItemHelp(category, target, opts) {
1894
2015
  }
1895
2016
  console.log();
1896
2017
  console.log(`${BOLD}Usage:${RESET}`);
1897
- console.log(` dot apis.${api.name}.${method.name}`);
2018
+ console.log(` dot ${chainName}.apis.${api.name}.${method.name}`);
2019
+ console.log(` dot apis.${api.name}.${method.name} --chain ${chainName}`);
1898
2020
  console.log();
1899
2021
  return;
1900
2022
  }
@@ -1936,8 +2058,9 @@ async function showItemHelp(category, target, opts) {
1936
2058
  }
1937
2059
  console.log();
1938
2060
  console.log(`${BOLD}Usage:${RESET}`);
1939
- console.log(` dot tx.${pallet.name}.${callItem.name} --from <account>`);
1940
- console.log(` dot tx.${pallet.name}.${callItem.name} --encode`);
2061
+ console.log(` dot tx.${pallet.name}.${callItem.name} --from <account> --chain ${chainName}`);
2062
+ console.log(` dot tx.${pallet.name}.${callItem.name} --encode --chain ${chainName}`);
2063
+ console.log(` dot ${chainName}.tx.${pallet.name}.${callItem.name} --from <account>`);
1941
2064
  console.log();
1942
2065
  console.log(`${BOLD}Options:${RESET}`);
1943
2066
  console.log(` --from <name> Account to sign with`);
@@ -1966,11 +2089,11 @@ async function showItemHelp(category, target, opts) {
1966
2089
  console.log();
1967
2090
  if (storageItem.keyTypeId != null) {
1968
2091
  console.log(`${BOLD}Usage:${RESET}`);
1969
- console.log(` dot query.${pallet.name}.${storageItem.name} <key>`);
1970
- console.log(` dot query.${pallet.name}.${storageItem.name} --dump # all entries`);
2092
+ console.log(` dot ${chainName}.query.${pallet.name}.${storageItem.name} <key>`);
2093
+ console.log(` dot ${chainName}.query.${pallet.name}.${storageItem.name} --dump # all entries`);
1971
2094
  } else {
1972
2095
  console.log(`${BOLD}Usage:${RESET}`);
1973
- console.log(` dot query.${pallet.name}.${storageItem.name}`);
2096
+ console.log(` dot ${chainName}.query.${pallet.name}.${storageItem.name}`);
1974
2097
  }
1975
2098
  console.log();
1976
2099
  console.log(`${BOLD}Options:${RESET}`);
@@ -1992,7 +2115,7 @@ async function showItemHelp(category, target, opts) {
1992
2115
  }
1993
2116
  console.log();
1994
2117
  console.log(`${BOLD}Usage:${RESET}`);
1995
- console.log(` dot const.${pallet.name}.${constItem.name}`);
2118
+ console.log(` dot ${chainName}.const.${pallet.name}.${constItem.name}`);
1996
2119
  console.log();
1997
2120
  return;
1998
2121
  }
@@ -2011,7 +2134,7 @@ async function showItemHelp(category, target, opts) {
2011
2134
  }
2012
2135
  console.log();
2013
2136
  console.log(`${BOLD}Usage:${RESET}`);
2014
- console.log(` dot events.${pallet.name}.${eventItem.name}`);
2137
+ console.log(` dot ${chainName}.events.${pallet.name}.${eventItem.name}`);
2015
2138
  console.log();
2016
2139
  return;
2017
2140
  }
@@ -2027,7 +2150,7 @@ async function showItemHelp(category, target, opts) {
2027
2150
  }
2028
2151
  console.log();
2029
2152
  console.log(`${BOLD}Usage:${RESET}`);
2030
- console.log(` dot errors.${pallet.name}.${errorItem.name}`);
2153
+ console.log(` dot ${chainName}.errors.${pallet.name}.${errorItem.name}`);
2031
2154
  console.log();
2032
2155
  return;
2033
2156
  }
@@ -2044,7 +2167,7 @@ var init_focused_inspect = __esm(() => {
2044
2167
  import { blake2b as blake2b2 } from "@noble/hashes/blake2.js";
2045
2168
  import { sha256 } from "@noble/hashes/sha2.js";
2046
2169
  import { keccak_256 } from "@noble/hashes/sha3.js";
2047
- import { bytesToHex, hexToBytes as hexToBytes2 } from "@noble/hashes/utils.js";
2170
+ import { bytesToHex as bytesToHex2, hexToBytes as hexToBytes2 } from "@noble/hashes/utils.js";
2048
2171
  function computeHash(algorithm, data) {
2049
2172
  const algo = ALGORITHMS[algorithm];
2050
2173
  if (!algo) {
@@ -2063,7 +2186,7 @@ function parseInputData(input) {
2063
2186
  return new TextEncoder().encode(input);
2064
2187
  }
2065
2188
  function toHex2(bytes) {
2066
- return `0x${bytesToHex(bytes)}`;
2189
+ return `0x${bytesToHex2(bytes)}`;
2067
2190
  }
2068
2191
  function isValidAlgorithm(name) {
2069
2192
  return name in ALGORITHMS;
@@ -2122,6 +2245,12 @@ async function loadRuntimeApiNames(_config, chainName) {
2122
2245
  methodNames: a.methods.map((m) => m.name)
2123
2246
  }));
2124
2247
  }
2248
+ async function loadExtensionIdentifiers(_config, chainName) {
2249
+ const raw = await loadMetadata(chainName);
2250
+ if (!raw)
2251
+ return null;
2252
+ return getSignedExtensionNames(parseMetadata(raw));
2253
+ }
2125
2254
  function filterPallets(pallets, category) {
2126
2255
  switch (category) {
2127
2256
  case "query":
@@ -2261,6 +2390,9 @@ async function completeDotpath(currentWord, config, knownChains, precedingWords)
2261
2390
  if (category === "apis") {
2262
2391
  return completeApisCategory(first, numComplete, endsWithDot, completeSegments, currentWord, config, chainFromFlag);
2263
2392
  }
2393
+ if (category === "extensions") {
2394
+ return completeExtensionsCategory(first, numComplete, endsWithDot, currentWord, config, chainFromFlag);
2395
+ }
2264
2396
  if (numComplete === 1 && endsWithDot) {
2265
2397
  const chainName = chainFromFlag;
2266
2398
  if (!chainName)
@@ -2317,6 +2449,9 @@ async function completeDotpath(currentWord, config, knownChains, precedingWords)
2317
2449
  if (category === "apis") {
2318
2450
  return completeApisCategory(`${first}.${completeSegments[1]}`, numComplete - 1, endsWithDot, completeSegments.slice(1), currentWord, config, chainName);
2319
2451
  }
2452
+ if (category === "extensions") {
2453
+ return completeExtensionsCategory(`${first}.${completeSegments[1]}`, numComplete - 1, endsWithDot, currentWord, config, chainName);
2454
+ }
2320
2455
  const pallets = await loadPallets(config, chainName);
2321
2456
  if (!pallets)
2322
2457
  return [];
@@ -2373,6 +2508,23 @@ async function completeApisCategory(prefix, numComplete, endsWithDot, segments,
2373
2508
  }
2374
2509
  return [];
2375
2510
  }
2511
+ async function completeExtensionsCategory(prefix, numComplete, endsWithDot, currentWord, config, chainNameOverride) {
2512
+ const chainName = chainNameOverride;
2513
+ if (!chainName)
2514
+ return [];
2515
+ const names = await loadExtensionIdentifiers(config, chainName);
2516
+ if (!names)
2517
+ return [];
2518
+ if (numComplete === 1 && endsWithDot) {
2519
+ const candidates = names.map((n) => `${prefix}.${n}`);
2520
+ return filterPrefix(candidates, currentWord.slice(0, -1));
2521
+ }
2522
+ if (numComplete === 1 && !endsWithDot) {
2523
+ const candidates = names.map((n) => `${prefix}.${n}`);
2524
+ return filterPrefix(candidates, currentWord);
2525
+ }
2526
+ return [];
2527
+ }
2376
2528
  var CATEGORIES2, CATEGORY_ALIASES2, NAMED_COMMANDS, CHAIN_SUBCOMMANDS, ACCOUNT_SUBCOMMANDS, GLOBAL_OPTIONS, TX_OPTIONS, QUERY_OPTIONS;
2377
2529
  var init_complete = __esm(() => {
2378
2530
  init_accounts_store();
@@ -2380,7 +2532,7 @@ var init_complete = __esm(() => {
2380
2532
  init_accounts();
2381
2533
  init_hash();
2382
2534
  init_metadata();
2383
- CATEGORIES2 = ["query", "tx", "const", "events", "errors", "apis"];
2535
+ CATEGORIES2 = ["query", "tx", "const", "events", "errors", "apis", "extensions"];
2384
2536
  CATEGORY_ALIASES2 = {
2385
2537
  query: "query",
2386
2538
  tx: "tx",
@@ -2392,7 +2544,10 @@ var init_complete = __esm(() => {
2392
2544
  errors: "errors",
2393
2545
  error: "errors",
2394
2546
  apis: "apis",
2395
- api: "apis"
2547
+ api: "apis",
2548
+ extensions: "extensions",
2549
+ extension: "extensions",
2550
+ ext: "extensions"
2396
2551
  };
2397
2552
  NAMED_COMMANDS = ["chain", "account", "inspect", "hash", "sign", "parachain", "completions"];
2398
2553
  CHAIN_SUBCOMMANDS = ["add", "remove", "update", "list"];
@@ -2426,7 +2581,7 @@ var init_complete = __esm(() => {
2426
2581
  // src/cli.ts
2427
2582
  import cac from "cac";
2428
2583
  // package.json
2429
- var version = "1.14.1";
2584
+ var version = "1.15.0";
2430
2585
 
2431
2586
  // src/commands/account.ts
2432
2587
  init_accounts_store();
@@ -2439,31 +2594,30 @@ ${BOLD}Usage:${RESET}
2439
2594
  $ dot account add <name> --secret <s> [--path <derivation>] Import from BIP39 mnemonic
2440
2595
  $ dot account add <name> --env <VAR> [--path <derivation>] Import account backed by env variable
2441
2596
  $ dot account create|new <name> [--path <derivation>] Create a new account
2442
- $ dot account import <name> --secret <s> [--path <derivation>] Import from BIP39 mnemonic
2443
- $ dot account import <name> --env <VAR> [--path <derivation>] Import account backed by env variable
2444
- $ dot account import --file <path> Batch-import accounts from a file
2597
+ $ dot account import <file> Batch-import accounts from a file
2445
2598
  $ dot account export [names...] Export accounts to stdout
2446
2599
  $ dot account derive <source> <new-name> --path <derivation> Derive a child account
2447
- $ dot account inspect <input> [--prefix <N>] Inspect an account/address/key
2600
+ $ dot account inspect <input> [--prefix <N>] [--show-secret] Inspect an account/address/key
2448
2601
  $ dot account list List all accounts
2449
2602
  $ dot account remove|delete <name> [name2] ... Remove stored account(s)
2450
2603
 
2451
2604
  ${BOLD}Examples:${RESET}
2452
2605
  $ dot account add treasury 5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY
2606
+ $ dot account add treasury --secret "word1 word2 ... word12"
2607
+ $ dot account add ci-signer --env MY_SECRET --path //ci
2453
2608
  $ dot account create my-validator
2454
2609
  $ dot account create my-staking --path //staking
2455
2610
  $ dot account create multi --path //polkadot//0/wallet
2456
- $ dot account import treasury --secret "word1 word2 ... word12"
2457
- $ dot account import ci-signer --env MY_SECRET --path //ci
2458
- $ dot account import --file team-accounts.json
2459
- $ dot account import --file accounts.json --dry-run
2460
- $ dot account import --file accounts.json --overwrite
2611
+ $ dot account import team-accounts.json
2612
+ $ dot account import accounts.json --dry-run
2613
+ $ dot account import accounts.json --overwrite
2461
2614
  $ dot account export
2462
2615
  $ dot account export treasury my-validator
2463
2616
  $ dot account export --include-secrets --file backup.json
2464
2617
  $ dot account export --watch-only
2465
2618
  $ dot account derive treasury treasury-staking --path //staking
2466
2619
  $ dot account inspect alice
2620
+ $ dot account inspect dave --show-secret
2467
2621
  $ dot account inspect 5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY
2468
2622
  $ dot account inspect 0xd435...a27d --prefix 0
2469
2623
  $ dot account list
@@ -2474,7 +2628,7 @@ ${YELLOW}Note: Secrets are stored unencrypted in ~/.polkadot/accounts.json.
2474
2628
  Hex seed import (0x...) is not supported via CLI.${RESET}
2475
2629
  `.trimStart();
2476
2630
  function registerAccountCommands(cli) {
2477
- cli.command("account [action] [...names]", "Manage local accounts (create, import, list, remove, export)").alias("accounts").option("--secret <value>", "Secret key (mnemonic or hex seed) for import").option("--env <varName>", "Environment variable name holding the secret").option("--path <derivation>", "Derivation path (e.g. //staking, //polkadot//0/wallet)").option("--prefix <number>", "SS58 prefix for address encoding (default: 42)").option("--file <path>", "Input/output file for batch import/export").option("--overwrite", "Overwrite existing accounts on batch import").option("--dry-run", "Preview batch import without applying changes").option("--include-secrets", "Include secrets in export (redacted by default)").option("--watch-only", "Export only watch-only accounts").action(async (action, names, opts) => {
2631
+ cli.command("account [action] [...names]", "Manage local accounts (create, import, list, remove, export)").alias("accounts").option("--secret <value>", "Secret key (mnemonic or hex seed) for import").option("--env <varName>", "Environment variable name holding the secret").option("--path <derivation>", "Derivation path (e.g. //staking, //polkadot//0/wallet)").option("--prefix <number>", "SS58 prefix for address encoding (default: 42)").option("--file <path>", "Input/output file for batch import/export").option("--overwrite", "Overwrite existing accounts on batch import").option("--dry-run", "Preview batch import without applying changes").option("--include-secrets", "Include secrets in export (redacted by default)").option("--watch-only", "Export only watch-only accounts").option("--show-secret", "Reveal the 64-byte sr25519 expanded private key (inspect only)").action(async (action, names, opts) => {
2478
2632
  if (!action) {
2479
2633
  if (process.argv[2] === "accounts")
2480
2634
  return accountList(opts);
@@ -2490,9 +2644,7 @@ function registerAccountCommands(cli) {
2490
2644
  return accountImport(names[0], opts);
2491
2645
  return accountAddWatchOnly(names[0], names[1], opts);
2492
2646
  case "import":
2493
- if (opts.file)
2494
- return accountBatchImport(opts);
2495
- return accountImport(names[0], opts);
2647
+ return accountBatchImport(names[0], opts);
2496
2648
  case "export":
2497
2649
  return accountExport(names, opts);
2498
2650
  case "derive":
@@ -2891,16 +3043,19 @@ async function accountInspect(input, opts) {
2891
3043
  let name;
2892
3044
  let publicKeyHex;
2893
3045
  let bandersnatch;
3046
+ let hasSecret = false;
2894
3047
  if (isDevAccount(input)) {
2895
3048
  name = input.charAt(0).toUpperCase() + input.slice(1).toLowerCase();
2896
3049
  const devAddr = getDevAddress(input);
2897
3050
  publicKeyHex = publicKeyToHex(fromSs58(devAddr));
3051
+ hasSecret = true;
2898
3052
  } else {
2899
3053
  const accountsFile = await loadAccounts();
2900
3054
  const account = findAccount(accountsFile, input);
2901
3055
  if (account) {
2902
3056
  name = account.name;
2903
3057
  bandersnatch = account.bandersnatch;
3058
+ hasSecret = account.secret !== undefined;
2904
3059
  if (account.publicKey) {
2905
3060
  publicKeyHex = account.publicKey;
2906
3061
  } else if (account.secret !== undefined && isEnvSecret(account.secret)) {
@@ -2927,12 +3082,31 @@ async function accountInspect(input, opts) {
2927
3082
  }
2928
3083
  }
2929
3084
  const ss58 = toSs58(publicKeyHex, prefix);
3085
+ let privateKeyHex;
3086
+ if (opts.showSecret) {
3087
+ if (!name) {
3088
+ console.error("--show-secret requires an account name; raw addresses and hex keys have no secret to reveal.");
3089
+ process.exit(1);
3090
+ }
3091
+ if (!hasSecret) {
3092
+ console.error(`Account "${name}" is watch-only (no secret). Cannot reveal private key.`);
3093
+ process.exit(1);
3094
+ }
3095
+ try {
3096
+ privateKeyHex = bytesToHex(await resolveAccountExpandedSecret(input));
3097
+ } catch (err) {
3098
+ console.error(err.message);
3099
+ process.exit(1);
3100
+ }
3101
+ }
2930
3102
  if (isJsonOutput(opts)) {
2931
3103
  const result = { publicKey: publicKeyHex, ss58, prefix };
2932
3104
  if (name)
2933
3105
  result.name = name;
2934
3106
  if (bandersnatch && Object.keys(bandersnatch).length > 0)
2935
3107
  result.bandersnatch = bandersnatch;
3108
+ if (privateKeyHex)
3109
+ result.privateKey = privateKeyHex;
2936
3110
  console.log(formatJson(result));
2937
3111
  } else {
2938
3112
  printHeading("Account Info");
@@ -2953,6 +3127,10 @@ async function accountInspect(input, opts) {
2953
3127
  }
2954
3128
  }
2955
3129
  console.log(` ${BOLD}Prefix:${RESET} ${prefix}`);
3130
+ if (privateKeyHex) {
3131
+ console.log(` ${BOLD}Private Key:${RESET} ${privateKeyHex}`);
3132
+ console.log(` ${YELLOW}(sr25519 expanded, 64 bytes — never share)${RESET}`);
3133
+ }
2956
3134
  console.log();
2957
3135
  }
2958
3136
  }
@@ -3017,12 +3195,17 @@ async function accountExport(names, opts) {
3017
3195
  process.stdout.write(json);
3018
3196
  }
3019
3197
  }
3020
- async function accountBatchImport(opts) {
3198
+ async function accountBatchImport(filePath, opts) {
3199
+ const inputPath = filePath ?? opts.file;
3021
3200
  let raw;
3022
- if (!opts.file || opts.file === "-") {
3201
+ if (!inputPath || inputPath === "-") {
3202
+ if (process.stdin.isTTY) {
3203
+ console.log(ACCOUNT_HELP);
3204
+ return;
3205
+ }
3023
3206
  raw = await readStdin();
3024
3207
  } else {
3025
- raw = await readFile3(opts.file, "utf-8");
3208
+ raw = await readFile3(inputPath, "utf-8");
3026
3209
  }
3027
3210
  let importData;
3028
3211
  try {
@@ -3101,16 +3284,13 @@ async function accountBatchImport(opts) {
3101
3284
  }));
3102
3285
  return;
3103
3286
  }
3104
- const prefix = opts.dryRun ? "(dry run) " : "";
3105
- if (added.length > 0)
3106
- console.log(`${prefix}Added: ${added.join(", ")}`);
3107
- if (overwritten.length > 0)
3108
- console.log(`${prefix}Overwritten: ${overwritten.join(", ")}`);
3109
- if (skipped.length > 0)
3110
- console.log(`${prefix}Skipped: ${skipped.join(", ")}`);
3111
- if (added.length === 0 && overwritten.length === 0) {
3112
- console.log(`${prefix}No accounts imported.`);
3113
- }
3287
+ printImportResults({
3288
+ added,
3289
+ overwritten,
3290
+ skipped,
3291
+ dryRun: opts.dryRun ?? false,
3292
+ noun: "account"
3293
+ });
3114
3294
  }
3115
3295
 
3116
3296
  // src/commands/apis.ts
@@ -3262,9 +3442,10 @@ ${BOLD}Examples:${RESET}
3262
3442
  $ dot chain import my-chains.json
3263
3443
  $ dot chain import my-chains.json --dry-run
3264
3444
  $ dot chain import my-chains.json --overwrite
3445
+ $ dot chain import my-chains.json --no-metadata
3265
3446
  `.trimStart();
3266
3447
  function registerChainCommands(cli) {
3267
- cli.command("chain [action] [...names]", "Manage chains (add, remove, update, list, export, import)").alias("chains").option("--all", "Update/export all configured chains").option("--relay <name>", "Parent relay chain for this parachain").option("--parachain-id <id>", "Parachain ID (auto-detected if omitted with --relay)").option("--file <path>", "Output/input file for export/import").option("--overwrite", "Overwrite existing chains on import").option("--dry-run", "Preview import without applying changes").action(async (action, names, opts) => {
3448
+ cli.command("chain [action] [...names]", "Manage chains (add, remove, update, list, export, import)").alias("chains").option("--all", "Update/export all configured chains").option("--relay <name>", "Parent relay chain for this parachain").option("--parachain-id <id>", "Parachain ID (auto-detected if omitted with --relay)").option("--file <path>", "Output/input file for export/import").option("--overwrite", "Overwrite existing chains on import").option("--dry-run", "Preview import without applying changes").option("--no-metadata", "Skip automatic metadata fetch after import").action(async (action, names, opts) => {
3268
3449
  if (!action) {
3269
3450
  if (process.argv[2] === "chains")
3270
3451
  return chainList(opts);
@@ -3474,7 +3655,17 @@ async function chainUpdate(name, opts) {
3474
3655
  }
3475
3656
  async function chainUpdateAll(config) {
3476
3657
  const chainNames = Object.keys(config.chains).sort();
3477
- process.stderr.write(`Updating metadata for ${chainNames.length} chains...
3658
+ const failed = await updateChainsMetadata(config, chainNames);
3659
+ if (failed > 0) {
3660
+ console.error(`
3661
+ ${failed} of ${chainNames.length} chains failed to update.`);
3662
+ process.exit(1);
3663
+ }
3664
+ }
3665
+ async function updateChainsMetadata(config, chainNames) {
3666
+ if (chainNames.length === 0)
3667
+ return 0;
3668
+ process.stderr.write(`Updating metadata for ${chainNames.length} chain(s)...
3478
3669
 
3479
3670
  `);
3480
3671
  const results = await Promise.allSettled(chainNames.map(async (chainName) => {
@@ -3495,12 +3686,7 @@ async function chainUpdateAll(config) {
3495
3686
  console.log(` ${RED}✗${RESET} ${name}${DIM} — ${result.reason?.message ?? "unknown error"}${RESET}`);
3496
3687
  }
3497
3688
  }
3498
- const failed = results.filter((r) => r.status === "rejected").length;
3499
- if (failed > 0) {
3500
- console.error(`
3501
- ${failed} of ${chainNames.length} chains failed to update.`);
3502
- process.exit(1);
3503
- }
3689
+ return results.filter((r) => r.status === "rejected").length;
3504
3690
  }
3505
3691
  function isBuiltinModified(name, config) {
3506
3692
  const defaultRpc = DEFAULT_CONFIG.chains[name]?.rpc;
@@ -3559,10 +3745,14 @@ async function chainExport(names, opts) {
3559
3745
  async function chainImport(filePath, opts) {
3560
3746
  const inputPath = filePath ?? opts.file;
3561
3747
  let raw;
3562
- if (inputPath && inputPath !== "-") {
3563
- raw = await readFile4(inputPath, "utf-8");
3564
- } else {
3748
+ if (!inputPath || inputPath === "-") {
3749
+ if (process.stdin.isTTY) {
3750
+ console.log(CHAIN_HELP);
3751
+ return;
3752
+ }
3565
3753
  raw = await readStdin2();
3754
+ } else {
3755
+ raw = await readFile4(inputPath, "utf-8");
3566
3756
  }
3567
3757
  let importData;
3568
3758
  try {
@@ -3616,18 +3806,16 @@ async function chainImport(filePath, opts) {
3616
3806
  }));
3617
3807
  return;
3618
3808
  }
3619
- const prefix = opts.dryRun ? "(dry run) " : "";
3620
- if (added.length > 0)
3621
- console.log(`${prefix}Added: ${added.join(", ")}`);
3622
- if (overwritten.length > 0)
3623
- console.log(`${prefix}Overwritten: ${overwritten.join(", ")}`);
3624
- if (skipped.length > 0)
3625
- console.log(`${prefix}Skipped: ${skipped.join(", ")}`);
3626
- if (added.length === 0 && overwritten.length === 0) {
3627
- console.log(`${prefix}No chains imported.`);
3628
- } else if (!opts.dryRun) {
3629
- console.error(`
3630
- Run "dot chain update --all" to fetch metadata for imported chains.`);
3809
+ printImportResults({
3810
+ added,
3811
+ overwritten,
3812
+ skipped,
3813
+ dryRun: opts.dryRun ?? false,
3814
+ noun: "chain"
3815
+ });
3816
+ if (!opts.dryRun && opts.metadata !== false && (added.length > 0 || overwritten.length > 0)) {
3817
+ console.log();
3818
+ await updateChainsMetadata(config, [...added, ...overwritten]);
3631
3819
  }
3632
3820
  }
3633
3821
 
@@ -4230,7 +4418,8 @@ async function showItemHelp2(category, target, opts) {
4230
4418
  }
4231
4419
  console.log();
4232
4420
  console.log(`${BOLD}Usage:${RESET}`);
4233
- console.log(` dot apis.${api.name}.${method.name}`);
4421
+ console.log(` dot ${chainName}.apis.${api.name}.${method.name}`);
4422
+ console.log(` dot apis.${api.name}.${method.name} --chain ${chainName}`);
4234
4423
  console.log();
4235
4424
  return;
4236
4425
  }
@@ -4272,8 +4461,9 @@ async function showItemHelp2(category, target, opts) {
4272
4461
  }
4273
4462
  console.log();
4274
4463
  console.log(`${BOLD}Usage:${RESET}`);
4275
- console.log(` dot tx.${pallet.name}.${callItem.name} --from <account>`);
4276
- console.log(` dot tx.${pallet.name}.${callItem.name} --encode`);
4464
+ console.log(` dot tx.${pallet.name}.${callItem.name} --from <account> --chain ${chainName}`);
4465
+ console.log(` dot tx.${pallet.name}.${callItem.name} --encode --chain ${chainName}`);
4466
+ console.log(` dot ${chainName}.tx.${pallet.name}.${callItem.name} --from <account>`);
4277
4467
  console.log();
4278
4468
  console.log(`${BOLD}Options:${RESET}`);
4279
4469
  console.log(` --from <name> Account to sign with`);
@@ -4302,11 +4492,11 @@ async function showItemHelp2(category, target, opts) {
4302
4492
  console.log();
4303
4493
  if (storageItem.keyTypeId != null) {
4304
4494
  console.log(`${BOLD}Usage:${RESET}`);
4305
- console.log(` dot query.${pallet.name}.${storageItem.name} <key>`);
4306
- console.log(` dot query.${pallet.name}.${storageItem.name} --dump # all entries`);
4495
+ console.log(` dot ${chainName}.query.${pallet.name}.${storageItem.name} <key>`);
4496
+ console.log(` dot ${chainName}.query.${pallet.name}.${storageItem.name} --dump # all entries`);
4307
4497
  } else {
4308
4498
  console.log(`${BOLD}Usage:${RESET}`);
4309
- console.log(` dot query.${pallet.name}.${storageItem.name}`);
4499
+ console.log(` dot ${chainName}.query.${pallet.name}.${storageItem.name}`);
4310
4500
  }
4311
4501
  console.log();
4312
4502
  console.log(`${BOLD}Options:${RESET}`);
@@ -4328,7 +4518,7 @@ async function showItemHelp2(category, target, opts) {
4328
4518
  }
4329
4519
  console.log();
4330
4520
  console.log(`${BOLD}Usage:${RESET}`);
4331
- console.log(` dot const.${pallet.name}.${constItem.name}`);
4521
+ console.log(` dot ${chainName}.const.${pallet.name}.${constItem.name}`);
4332
4522
  console.log();
4333
4523
  return;
4334
4524
  }
@@ -4347,7 +4537,7 @@ async function showItemHelp2(category, target, opts) {
4347
4537
  }
4348
4538
  console.log();
4349
4539
  console.log(`${BOLD}Usage:${RESET}`);
4350
- console.log(` dot events.${pallet.name}.${eventItem.name}`);
4540
+ console.log(` dot ${chainName}.events.${pallet.name}.${eventItem.name}`);
4351
4541
  console.log();
4352
4542
  return;
4353
4543
  }
@@ -4363,12 +4553,67 @@ async function showItemHelp2(category, target, opts) {
4363
4553
  }
4364
4554
  console.log();
4365
4555
  console.log(`${BOLD}Usage:${RESET}`);
4366
- console.log(` dot errors.${pallet.name}.${errorItem.name}`);
4556
+ console.log(` dot ${chainName}.errors.${pallet.name}.${errorItem.name}`);
4367
4557
  console.log();
4368
4558
  return;
4369
4559
  }
4370
4560
  }
4371
4561
  }
4562
+ async function handleExtensions(target, opts) {
4563
+ const config = await loadConfig();
4564
+ const { name: chainName, chain: chainConfig } = resolveChain(config, opts.chain);
4565
+ const meta = await loadMeta2(chainName, chainConfig, opts.rpc);
4566
+ if (!target) {
4567
+ const extensions = getSignedExtensions(meta).map((e) => describeSignedExtension(meta, e)).sort((a, b) => a.identifier.localeCompare(b.identifier));
4568
+ if (isJsonOutput(opts)) {
4569
+ console.log(formatJson({
4570
+ chain: chainName,
4571
+ extensions: extensions.map((e) => ({
4572
+ identifier: e.identifier,
4573
+ valueType: e.valueType,
4574
+ additionalSignedType: e.additionalSignedType,
4575
+ isBuiltin: e.isBuiltin
4576
+ }))
4577
+ }));
4578
+ return;
4579
+ }
4580
+ printHeading(`Transaction extensions on ${chainName} (${extensions.length})`);
4581
+ for (const e of extensions) {
4582
+ const tag = e.isBuiltin ? `${DIM}[builtin]${RESET}` : `${CYAN}[custom]${RESET}`;
4583
+ printItem(e.identifier, `${e.valueType} ${tag}`);
4584
+ }
4585
+ console.log();
4586
+ return;
4587
+ }
4588
+ const info = findSignedExtension(meta, target);
4589
+ if (!info) {
4590
+ const names = getSignedExtensionNames(meta);
4591
+ throw new Error(suggestMessage("transaction extension", target, names));
4592
+ }
4593
+ const described = describeSignedExtension(meta, info);
4594
+ if (isJsonOutput(opts)) {
4595
+ console.log(formatJson({
4596
+ chain: chainName,
4597
+ identifier: described.identifier,
4598
+ valueType: described.valueType,
4599
+ additionalSignedType: described.additionalSignedType,
4600
+ valueTypeId: described.valueTypeId,
4601
+ additionalSignedTypeId: described.additionalSignedTypeId,
4602
+ isBuiltin: described.isBuiltin
4603
+ }));
4604
+ return;
4605
+ }
4606
+ printHeading(`${described.identifier} (Transaction Extension)`);
4607
+ console.log(` ${BOLD}Value type:${RESET} ${described.valueType}`);
4608
+ console.log(` ${BOLD}AdditionalSigned:${RESET} ${described.additionalSignedType}`);
4609
+ console.log(` ${BOLD}Handled by:${RESET} ${described.isBuiltin ? "polkadot-api (builtin)" : "user (custom — provide via --ext)"}`);
4610
+ if (!described.isBuiltin) {
4611
+ console.log();
4612
+ console.log(`${BOLD}Usage:${RESET}`);
4613
+ console.log(` dot ${chainName}.tx.<Pallet>.<Call> --from <acc> --ext '{"${described.identifier}":{"value":<v>}}'`);
4614
+ }
4615
+ console.log();
4616
+ }
4372
4617
 
4373
4618
  // src/commands/hash.ts
4374
4619
  init_hash();
@@ -5395,7 +5640,7 @@ async function handleTx(target, args, opts) {
5395
5640
  const at = parseAtOption(opts.at);
5396
5641
  if (!decodeOnly || opts.unsigned) {
5397
5642
  const userExtOverrides = parseExtOption(opts.ext);
5398
- const skipBuiltins = asset !== undefined ? new Set([...PAPI_BUILTIN_EXTENSIONS2].filter((e) => e !== "ChargeAssetTxPayment")) : PAPI_BUILTIN_EXTENSIONS2;
5643
+ const skipBuiltins = asset !== undefined ? new Set([...PAPI_BUILTIN_EXTENSIONS].filter((e) => e !== "ChargeAssetTxPayment")) : PAPI_BUILTIN_EXTENSIONS;
5399
5644
  if (asset !== undefined) {
5400
5645
  userExtOverrides.ChargeAssetTxPayment ??= {
5401
5646
  value: { tip: tip ?? 0n, asset_id: asset }
@@ -5421,7 +5666,7 @@ async function handleTx(target, args, opts) {
5421
5666
  if (isRawCall) {
5422
5667
  if (args.length > 0) {
5423
5668
  throw new Error(`Extra arguments are not allowed when submitting a raw call hex.
5424
- ` + "Usage: dot tx 0x<call_hex> --from <account>");
5669
+ ` + "Usage: dot tx 0x<call_hex> --from <account> --chain <chain>");
5425
5670
  }
5426
5671
  callHex = target;
5427
5672
  if (opts.toYaml || opts.toJson) {
@@ -6326,20 +6571,6 @@ function parsePrimitive2(prim, arg) {
6326
6571
  return parseValue(arg);
6327
6572
  }
6328
6573
  }
6329
- var PAPI_BUILTIN_EXTENSIONS2 = new Set([
6330
- "CheckNonZeroSender",
6331
- "CheckSpecVersion",
6332
- "CheckTxVersion",
6333
- "CheckGenesis",
6334
- "CheckMortality",
6335
- "CheckNonce",
6336
- "CheckWeight",
6337
- "ChargeTransactionPayment",
6338
- "ChargeAssetTxPayment",
6339
- "CheckMetadataHash",
6340
- "StorageWeightReclaim",
6341
- "PrevalidateAttests"
6342
- ]);
6343
6574
  function parseExtOption(ext) {
6344
6575
  if (!ext)
6345
6576
  return {};
@@ -6357,7 +6588,7 @@ function parseExtOption(ext) {
6357
6588
  }
6358
6589
  }
6359
6590
  var NO_DEFAULT2 = Symbol("no-default");
6360
- function buildCustomSignedExtensions(meta, userOverrides, builtins = PAPI_BUILTIN_EXTENSIONS2) {
6591
+ function buildCustomSignedExtensions(meta, userOverrides, builtins = PAPI_BUILTIN_EXTENSIONS) {
6361
6592
  const result = {};
6362
6593
  const extensions = getSignedExtensions(meta);
6363
6594
  for (const ext of extensions) {
@@ -6694,9 +6925,13 @@ init_types();
6694
6925
  import { access as access3, mkdir as mkdir3, readFile as readFile7, rm as rm2, writeFile as writeFile5 } from "node:fs/promises";
6695
6926
  import { homedir as homedir2 } from "node:os";
6696
6927
  import { join as join3 } from "node:path";
6697
- var DOT_DIR2 = join3(homedir2(), ".polkadot");
6698
- var CONFIG_PATH2 = join3(DOT_DIR2, "config.json");
6699
- var CHAINS_DIR2 = join3(DOT_DIR2, "chains");
6928
+ function getConfigDir2() {
6929
+ const override = process.env.DOT_HOME;
6930
+ return override && override.length > 0 ? override : join3(homedir2(), ".polkadot");
6931
+ }
6932
+ function getConfigPath2() {
6933
+ return join3(getConfigDir2(), "config.json");
6934
+ }
6700
6935
  async function ensureDir3(dir) {
6701
6936
  await mkdir3(dir, { recursive: true });
6702
6937
  }
@@ -6709,9 +6944,10 @@ async function fileExists3(path) {
6709
6944
  }
6710
6945
  }
6711
6946
  async function loadConfig2() {
6712
- await ensureDir3(DOT_DIR2);
6713
- if (await fileExists3(CONFIG_PATH2)) {
6714
- const saved = JSON.parse(await readFile7(CONFIG_PATH2, "utf-8"));
6947
+ await ensureDir3(getConfigDir2());
6948
+ const configPath = getConfigPath2();
6949
+ if (await fileExists3(configPath)) {
6950
+ const saved = JSON.parse(await readFile7(configPath, "utf-8"));
6715
6951
  const chains = {};
6716
6952
  for (const [name, defaultConfig] of Object.entries(DEFAULT_CONFIG.chains)) {
6717
6953
  chains[name] = saved.chains[name] ? { ...defaultConfig, ...saved.chains[name] } : defaultConfig;
@@ -6727,8 +6963,8 @@ async function loadConfig2() {
6727
6963
  return DEFAULT_CONFIG;
6728
6964
  }
6729
6965
  async function saveConfig2(config) {
6730
- await ensureDir3(DOT_DIR2);
6731
- await writeFile5(CONFIG_PATH2, `${JSON.stringify(config, null, 2)}
6966
+ await ensureDir3(getConfigDir2());
6967
+ await writeFile5(getConfigPath2(), `${JSON.stringify(config, null, 2)}
6732
6968
  `);
6733
6969
  }
6734
6970
 
@@ -7008,7 +7244,10 @@ var CATEGORY_ALIASES = {
7008
7244
  errors: "errors",
7009
7245
  error: "errors",
7010
7246
  apis: "apis",
7011
- api: "apis"
7247
+ api: "apis",
7248
+ extensions: "extensions",
7249
+ extension: "extensions",
7250
+ ext: "extensions"
7012
7251
  };
7013
7252
  function matchCategory(segment) {
7014
7253
  return CATEGORY_ALIASES[segment.toLowerCase()];
@@ -7023,7 +7262,7 @@ function parseDotPath(input, knownChains = []) {
7023
7262
  const cat = matchCategory(parts[0]);
7024
7263
  if (cat)
7025
7264
  return { category: cat };
7026
- throw new Error(`Unknown command "${parts[0]}". Expected a category (query, tx, const, events, errors, apis) or a named command.`);
7265
+ throw new Error(`Unknown command "${parts[0]}". Expected a category (query, tx, const, events, errors, apis, extensions) or a named command.`);
7027
7266
  }
7028
7267
  case 2: {
7029
7268
  const cat = matchCategory(parts[0]);
@@ -7104,20 +7343,23 @@ if (process.argv[2] === "__complete") {
7104
7343
  console.log(" events List or inspect pallet events");
7105
7344
  console.log(" errors List or inspect pallet errors");
7106
7345
  console.log(" apis Browse and call runtime APIs");
7346
+ console.log(" extensions List transaction extensions on a chain");
7107
7347
  console.log();
7108
7348
  console.log("Examples:");
7109
- console.log(" dot query.System.Account <addr> Query a storage item");
7110
- console.log(" dot query.System List storage items in System");
7111
- console.log(" dot tx.System.remark 0xdead --from alice");
7112
- console.log(" dot tx.System.remark 0xdead --unsigned Submit unsigned/bare tx");
7113
- console.log(" dot const.Balances.ExistentialDeposit");
7114
- console.log(" dot events.Balances List events in Balances");
7115
- console.log(" dot apis.Core.version Call a runtime API");
7116
- console.log(" dot polkadot.query.System.Number With chain prefix");
7117
- console.log(" dot ./transfer.yaml --from alice Run from file");
7118
- console.log(" dot tx.0x1f0003... --to-yaml Decode hex call to YAML");
7119
- console.log(" dot tx.System.remark 0xdead --to-json Encode & output as JSON file format");
7120
- console.log(" dot query.System.Number --json Output as JSON");
7349
+ console.log(" dot polkadot.query.System.Account <addr> Query a storage item");
7350
+ console.log(" dot polkadot.query.System List storage items in System");
7351
+ console.log(" dot tx.System.remark 0xdead --from alice --chain polkadot");
7352
+ console.log(" dot tx.People.create_people_collection --unsigned --chain polkadot-people");
7353
+ console.log(" dot polkadot.const.Balances.ExistentialDeposit");
7354
+ console.log(" dot polkadot.events.Balances List events in Balances");
7355
+ console.log(" dot polkadot.apis.Core.version Call a runtime API");
7356
+ console.log(" dot polkadot.extensions List transaction extensions");
7357
+ console.log(" dot polkadot.extensions.CheckMortality Inspect one extension");
7358
+ console.log(" dot query.System.Number --chain polkadot --chain flag form");
7359
+ console.log(" dot ./transfer.yaml --from alice Run from file (chain in YAML)");
7360
+ console.log(" dot tx.0x1f0003... --to-yaml --chain polkadot Decode hex call to YAML");
7361
+ console.log(" dot tx.System.remark 0xdead --to-json --chain polkadot Output as JSON file format");
7362
+ console.log(" dot polkadot.query.System.Number --json JSON output");
7121
7363
  console.log();
7122
7364
  console.log("Commands:");
7123
7365
  console.log(" inspect [target] Inspect chain metadata (alias: explore)");
@@ -7279,6 +7521,14 @@ if (process.argv[2] === "__complete") {
7279
7521
  case "apis":
7280
7522
  await handleApis2(target, args, handlerOpts);
7281
7523
  break;
7524
+ case "extensions": {
7525
+ if (parsed.item) {
7526
+ const suggestion = parsed.chain ? `dot ${parsed.chain}.extensions.${parsed.pallet}` : opts.chain ? `dot extensions.${parsed.pallet} --chain ${opts.chain}` : `dot extensions.${parsed.pallet} --chain <chain>`;
7527
+ throw new CliError2(`Transaction extensions have no sub-items. Try "${suggestion}".`);
7528
+ }
7529
+ await handleExtensions(parsed.pallet, handlerOpts);
7530
+ break;
7531
+ }
7282
7532
  }
7283
7533
  });
7284
7534
  cli.option("--help, -h", "Display this message");