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.
- package/README.md +316 -192
- package/dist/cli.mjs +395 -145
- 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
|
-
|
|
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(
|
|
191
|
+
return join(getChainsDir(), chainName);
|
|
188
192
|
}
|
|
189
193
|
function getMetadataPath(chainName) {
|
|
190
|
-
return join(
|
|
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(
|
|
205
|
-
|
|
206
|
-
|
|
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(
|
|
223
|
-
await writeFile(
|
|
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
|
-
|
|
284
|
-
|
|
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(
|
|
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
|
-
|
|
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
|
|
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${
|
|
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.
|
|
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 <
|
|
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>]
|
|
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
|
|
2457
|
-
$ dot account import
|
|
2458
|
-
$ dot account import
|
|
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
|
-
|
|
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 (!
|
|
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(
|
|
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
|
-
|
|
3105
|
-
|
|
3106
|
-
|
|
3107
|
-
|
|
3108
|
-
|
|
3109
|
-
|
|
3110
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
3563
|
-
|
|
3564
|
-
|
|
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
|
-
|
|
3620
|
-
|
|
3621
|
-
|
|
3622
|
-
|
|
3623
|
-
|
|
3624
|
-
|
|
3625
|
-
|
|
3626
|
-
if (added.length
|
|
3627
|
-
console.log(
|
|
3628
|
-
|
|
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([...
|
|
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 =
|
|
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
|
-
|
|
6698
|
-
|
|
6699
|
-
|
|
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(
|
|
6713
|
-
|
|
6714
|
-
|
|
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(
|
|
6731
|
-
await writeFile5(
|
|
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>
|
|
7110
|
-
console.log(" dot query.System
|
|
7111
|
-
console.log(" dot tx.System.remark 0xdead --from alice");
|
|
7112
|
-
console.log(" dot tx.
|
|
7113
|
-
console.log(" dot const.Balances.ExistentialDeposit");
|
|
7114
|
-
console.log(" dot events.Balances
|
|
7115
|
-
console.log(" dot apis.Core.version
|
|
7116
|
-
console.log(" dot polkadot.
|
|
7117
|
-
console.log(" dot
|
|
7118
|
-
console.log(" dot
|
|
7119
|
-
console.log(" dot
|
|
7120
|
-
console.log(" dot
|
|
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");
|