polkadot-cli 1.20.0 → 1.22.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 +157 -31
- package/dist/cli.mjs +874 -256
- package/package.json +6 -7
package/dist/cli.mjs
CHANGED
|
@@ -73,7 +73,9 @@ var init_errors = __esm(() => {
|
|
|
73
73
|
/codec/i,
|
|
74
74
|
/decod(e|ing)/i,
|
|
75
75
|
/Lookup failed/i,
|
|
76
|
-
/metadata.*mismatch/i
|
|
76
|
+
/metadata.*mismatch/i,
|
|
77
|
+
/BadProof/,
|
|
78
|
+
/AncientBirthBlock/
|
|
77
79
|
];
|
|
78
80
|
BLOCK_UNAVAILABLE_PATTERNS = [
|
|
79
81
|
/is not pinned/i,
|
|
@@ -231,31 +233,84 @@ var init_types = __esm(() => {
|
|
|
231
233
|
BUILTIN_CHAIN_NAMES = new Set(Object.keys(DEFAULT_CONFIG.chains));
|
|
232
234
|
});
|
|
233
235
|
|
|
236
|
+
// src/config/workspace.ts
|
|
237
|
+
import { realpathSync, statSync } from "node:fs";
|
|
238
|
+
import { homedir } from "node:os";
|
|
239
|
+
import { dirname, join, resolve } from "node:path";
|
|
240
|
+
function isDirectory(path) {
|
|
241
|
+
try {
|
|
242
|
+
return statSync(path).isDirectory();
|
|
243
|
+
} catch {
|
|
244
|
+
return false;
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
function canonicalPath(path) {
|
|
248
|
+
try {
|
|
249
|
+
return realpathSync(path);
|
|
250
|
+
} catch {
|
|
251
|
+
return resolve(path);
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
function findWorkspace(startDir, home = homedir()) {
|
|
255
|
+
const homePath = canonicalPath(home);
|
|
256
|
+
let dir = canonicalPath(startDir);
|
|
257
|
+
while (dir !== homePath) {
|
|
258
|
+
const candidate = join(dir, WORKSPACE_DIR_NAME);
|
|
259
|
+
if (isDirectory(candidate))
|
|
260
|
+
return candidate;
|
|
261
|
+
const parent = dirname(dir);
|
|
262
|
+
if (parent === dir)
|
|
263
|
+
return null;
|
|
264
|
+
dir = parent;
|
|
265
|
+
}
|
|
266
|
+
return null;
|
|
267
|
+
}
|
|
268
|
+
var WORKSPACE_DIR_NAME = ".polkadot";
|
|
269
|
+
var init_workspace = () => {};
|
|
270
|
+
|
|
234
271
|
// src/config/store.ts
|
|
235
272
|
import { access, mkdir, readFile, rm, writeFile } from "node:fs/promises";
|
|
236
|
-
import { homedir } from "node:os";
|
|
237
|
-
import { join } from "node:path";
|
|
238
|
-
function
|
|
273
|
+
import { homedir as homedir2 } from "node:os";
|
|
274
|
+
import { join as join2 } from "node:path";
|
|
275
|
+
function resolveConfigDir(cwd = process.cwd()) {
|
|
239
276
|
const override = process.env.DOT_HOME;
|
|
240
|
-
|
|
277
|
+
if (override && override.length > 0)
|
|
278
|
+
return { path: override, source: "env" };
|
|
279
|
+
const workspace = findWorkspace(cwd);
|
|
280
|
+
if (workspace)
|
|
281
|
+
return { path: workspace, source: "workspace" };
|
|
282
|
+
return { path: join2(homedir2(), ".polkadot"), source: "global" };
|
|
283
|
+
}
|
|
284
|
+
function describeConfigDir(resolved = resolveConfigDir()) {
|
|
285
|
+
switch (resolved.source) {
|
|
286
|
+
case "env":
|
|
287
|
+
return `DOT_HOME ${resolved.path}`;
|
|
288
|
+
case "workspace":
|
|
289
|
+
return `workspace ${resolved.path}`;
|
|
290
|
+
case "global":
|
|
291
|
+
return `global config ${resolved.path}`;
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
function getConfigDir() {
|
|
295
|
+
return resolveConfigDir().path;
|
|
241
296
|
}
|
|
242
297
|
function getChainsDir() {
|
|
243
|
-
return
|
|
298
|
+
return join2(getConfigDir(), "chains");
|
|
244
299
|
}
|
|
245
300
|
function getChainDir(chainName) {
|
|
246
|
-
return
|
|
301
|
+
return join2(getChainsDir(), chainName);
|
|
247
302
|
}
|
|
248
303
|
function getMetadataPath(chainName) {
|
|
249
|
-
return
|
|
304
|
+
return join2(getChainDir(chainName), "metadata.bin");
|
|
250
305
|
}
|
|
251
306
|
function getMetadataFingerprintPath(chainName) {
|
|
252
|
-
return
|
|
307
|
+
return join2(getChainDir(chainName), "metadata.fingerprint.json");
|
|
253
308
|
}
|
|
254
309
|
function getRpcMethodsPath(chainName) {
|
|
255
|
-
return
|
|
310
|
+
return join2(getChainDir(chainName), "rpc-methods.json");
|
|
256
311
|
}
|
|
257
312
|
function getConfigPath() {
|
|
258
|
-
return
|
|
313
|
+
return join2(getConfigDir(), "config.json");
|
|
259
314
|
}
|
|
260
315
|
async function ensureDir(dir) {
|
|
261
316
|
await mkdir(dir, { recursive: true });
|
|
@@ -360,20 +415,21 @@ function resolveChain(config, chainFlag) {
|
|
|
360
415
|
}
|
|
361
416
|
const name = findChainName(config, chainFlag);
|
|
362
417
|
if (!name) {
|
|
363
|
-
throw new CliError(`Unknown chain "${chainFlag}". Available chains: ${available}`);
|
|
418
|
+
throw new CliError(`Unknown chain "${chainFlag}" in ${describeConfigDir()}. Available chains: ${available}`);
|
|
364
419
|
}
|
|
365
420
|
return { name, chain: config.chains[name] };
|
|
366
421
|
}
|
|
367
422
|
var init_store = __esm(() => {
|
|
368
423
|
init_errors();
|
|
369
424
|
init_types();
|
|
425
|
+
init_workspace();
|
|
370
426
|
});
|
|
371
427
|
|
|
372
428
|
// src/config/accounts-store.ts
|
|
373
429
|
import { access as access2, mkdir as mkdir2, readFile as readFile2, writeFile as writeFile2 } from "node:fs/promises";
|
|
374
|
-
import { join as
|
|
430
|
+
import { join as join3 } from "node:path";
|
|
375
431
|
function getAccountsPath() {
|
|
376
|
-
return
|
|
432
|
+
return join3(getConfigDir(), "accounts.json");
|
|
377
433
|
}
|
|
378
434
|
async function ensureDir2(dir) {
|
|
379
435
|
await mkdir2(dir, { recursive: true });
|
|
@@ -645,6 +701,16 @@ function tryDerivePublicKey(envVarName, path = "") {
|
|
|
645
701
|
return null;
|
|
646
702
|
}
|
|
647
703
|
}
|
|
704
|
+
function unknownAccountError(name, accountsFile) {
|
|
705
|
+
const available = [...DEV_NAMES, ...accountsFile.accounts.map((a) => a.name)].sort((a, b) => a.localeCompare(b));
|
|
706
|
+
const suggestions = findClosest(name, available);
|
|
707
|
+
const hint = suggestions.length > 0 ? `
|
|
708
|
+
Did you mean: ${suggestions.join(", ")}?` : "";
|
|
709
|
+
const list = available.map((a) => `
|
|
710
|
+
- ${a}`).join("");
|
|
711
|
+
return new Error(`Unknown account "${name}" in ${describeConfigDir()}.${hint}
|
|
712
|
+
Available accounts:${list}`);
|
|
713
|
+
}
|
|
648
714
|
async function resolveAccountKeypair(name) {
|
|
649
715
|
if (isDevAccount(name)) {
|
|
650
716
|
return getDevKeypair(name);
|
|
@@ -652,14 +718,7 @@ async function resolveAccountKeypair(name) {
|
|
|
652
718
|
const accountsFile = await loadAccounts();
|
|
653
719
|
const account = findAccount(accountsFile, name);
|
|
654
720
|
if (!account) {
|
|
655
|
-
|
|
656
|
-
const suggestions = findClosest(name, available);
|
|
657
|
-
const hint = suggestions.length > 0 ? `
|
|
658
|
-
Did you mean: ${suggestions.join(", ")}?` : "";
|
|
659
|
-
const list = available.map((a) => `
|
|
660
|
-
- ${a}`).join("");
|
|
661
|
-
throw new Error(`Unknown account "${name}".${hint}
|
|
662
|
-
Available accounts:${list}`);
|
|
721
|
+
throw unknownAccountError(name, accountsFile);
|
|
663
722
|
}
|
|
664
723
|
if (account.secret === undefined) {
|
|
665
724
|
throw new Error(`Account "${name}" is watch-only (no secret). Cannot sign. Import with --secret or --env.`);
|
|
@@ -678,14 +737,7 @@ async function resolveAccountExpandedSecret(name) {
|
|
|
678
737
|
const accountsFile = await loadAccounts();
|
|
679
738
|
const account = findAccount(accountsFile, name);
|
|
680
739
|
if (!account) {
|
|
681
|
-
|
|
682
|
-
const suggestions = findClosest(name, available);
|
|
683
|
-
const hint = suggestions.length > 0 ? `
|
|
684
|
-
Did you mean: ${suggestions.join(", ")}?` : "";
|
|
685
|
-
const list = available.map((a) => `
|
|
686
|
-
- ${a}`).join("");
|
|
687
|
-
throw new Error(`Unknown account "${name}".${hint}
|
|
688
|
-
Available accounts:${list}`);
|
|
740
|
+
throw unknownAccountError(name, accountsFile);
|
|
689
741
|
}
|
|
690
742
|
if (account.secret === undefined) {
|
|
691
743
|
throw new Error(`Account "${name}" is watch-only (no secret). Cannot derive private key. Import with --secret or --env.`);
|
|
@@ -698,6 +750,7 @@ function bytesToHex(bytes) {
|
|
|
698
750
|
var DEV_NAMES, EXPANDED_SECRET_RE, HEX_SEED_RE, DERIVATION_RE;
|
|
699
751
|
var init_accounts = __esm(() => {
|
|
700
752
|
init_accounts_store();
|
|
753
|
+
init_store();
|
|
701
754
|
DEV_NAMES = ["alice", "bob", "charlie", "dave", "eve", "ferdie"];
|
|
702
755
|
EXPANDED_SECRET_RE = /^0x[0-9a-fA-F]{128}$/;
|
|
703
756
|
HEX_SEED_RE = /^0x[0-9a-fA-F]{64}$/;
|
|
@@ -759,8 +812,8 @@ function isJsonOutput(opts) {
|
|
|
759
812
|
return opts.json === true || opts.output === "json";
|
|
760
813
|
}
|
|
761
814
|
function writeStdout(text) {
|
|
762
|
-
return new Promise((
|
|
763
|
-
process.stdout.write(text, () =>
|
|
815
|
+
return new Promise((resolve2) => {
|
|
816
|
+
process.stdout.write(text, () => resolve2());
|
|
764
817
|
});
|
|
765
818
|
}
|
|
766
819
|
function printJsonLine(data) {
|
|
@@ -864,24 +917,155 @@ var init_output = __esm(() => {
|
|
|
864
917
|
SPINNER_FRAMES = ["⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"];
|
|
865
918
|
});
|
|
866
919
|
|
|
867
|
-
// src/
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
920
|
+
// src/platform/cli.ts
|
|
921
|
+
function withHelp(command, printHelp) {
|
|
922
|
+
command[HELP_PRINTER] = printHelp ?? (() => command.outputHelp());
|
|
923
|
+
return command;
|
|
924
|
+
}
|
|
925
|
+
function readRawOptionValue(name, argv = process.argv) {
|
|
926
|
+
const flag = `--${name}`;
|
|
927
|
+
const prefix = `${flag}=`;
|
|
928
|
+
let value;
|
|
929
|
+
for (let i = 0;i < argv.length; i++) {
|
|
930
|
+
const arg = argv[i];
|
|
931
|
+
if (arg === "--")
|
|
932
|
+
break;
|
|
933
|
+
if (arg === flag && i + 1 < argv.length)
|
|
934
|
+
value = argv[i + 1];
|
|
935
|
+
else if (arg.startsWith(prefix))
|
|
936
|
+
value = arg.slice(prefix.length);
|
|
937
|
+
}
|
|
938
|
+
return value;
|
|
939
|
+
}
|
|
940
|
+
var HELP_PRINTER;
|
|
941
|
+
var init_cli = __esm(() => {
|
|
942
|
+
HELP_PRINTER = Symbol.for("polkadot-cli.helpPrinter");
|
|
943
|
+
});
|
|
944
|
+
|
|
945
|
+
// src/features/verifiable/lib.ts
|
|
946
|
+
var exports_lib = {};
|
|
947
|
+
__export(exports_lib, {
|
|
948
|
+
verifyRingProof: () => verifyRingProof,
|
|
949
|
+
verifyBandersnatchSig: () => verifyBandersnatchSig,
|
|
950
|
+
ringRoot: () => ringRoot,
|
|
951
|
+
ringProve: () => ringProve,
|
|
952
|
+
resolveEntropyKey: () => resolveEntropyKey,
|
|
953
|
+
isRingExponent: () => isRingExponent,
|
|
954
|
+
encodeMembers: () => encodeMembers,
|
|
955
|
+
encodeContext: () => encodeContext,
|
|
956
|
+
deriveMemberKey: () => deriveMemberKey,
|
|
957
|
+
deriveMemberEntropy: () => deriveMemberEntropy,
|
|
958
|
+
deriveBandersnatchMember: () => deriveBandersnatchMember,
|
|
959
|
+
deriveAlias: () => deriveAlias,
|
|
960
|
+
compactEncode: () => compactEncode,
|
|
961
|
+
bandersnatchSign: () => bandersnatchSign,
|
|
962
|
+
DEFAULT_RING_EXPONENT: () => DEFAULT_RING_EXPONENT
|
|
871
963
|
});
|
|
872
964
|
import { blake2b } from "@noble/hashes/blake2.js";
|
|
965
|
+
import { hexToBytes as hexToBytes3 } from "@noble/hashes/utils.js";
|
|
966
|
+
import { compact } from "@polkadot-api/substrate-bindings";
|
|
873
967
|
import { mnemonicToEntropy as mnemonicToEntropy2 } from "@polkadot-labs/hdkd-helpers";
|
|
874
|
-
import {
|
|
875
|
-
|
|
968
|
+
import {
|
|
969
|
+
alias_in_context,
|
|
970
|
+
member_from_entropy,
|
|
971
|
+
members_root,
|
|
972
|
+
one_shot,
|
|
973
|
+
sign as sign2,
|
|
974
|
+
validate,
|
|
975
|
+
validate_with_commitment,
|
|
976
|
+
verify_signature
|
|
977
|
+
} from "verifiablejs/nodejs";
|
|
978
|
+
function isRingExponent(n) {
|
|
979
|
+
return RING_EXPONENTS.includes(n);
|
|
980
|
+
}
|
|
981
|
+
function textOrHexBytes(value, label) {
|
|
982
|
+
if (value.startsWith("0x")) {
|
|
983
|
+
const hex = value.slice(2);
|
|
984
|
+
if (hex.length % 2 !== 0) {
|
|
985
|
+
throw new Error(`Invalid hex ${label}: odd number of characters`);
|
|
986
|
+
}
|
|
987
|
+
return hexToBytes3(hex);
|
|
988
|
+
}
|
|
989
|
+
return new TextEncoder().encode(value);
|
|
990
|
+
}
|
|
991
|
+
function resolveEntropyKey(value) {
|
|
992
|
+
if (value === undefined || value === "")
|
|
993
|
+
return;
|
|
994
|
+
return textOrHexBytes(value, "entropy-key");
|
|
995
|
+
}
|
|
996
|
+
function deriveMemberEntropy(mnemonic, entropyKey) {
|
|
876
997
|
const entropy = mnemonicToEntropy2(mnemonic);
|
|
877
998
|
const opts = { dkLen: 32 };
|
|
878
|
-
if (
|
|
879
|
-
opts.key =
|
|
999
|
+
if (entropyKey !== undefined && entropyKey.length > 0) {
|
|
1000
|
+
opts.key = entropyKey;
|
|
1001
|
+
}
|
|
1002
|
+
return blake2b(entropy, opts);
|
|
1003
|
+
}
|
|
1004
|
+
function deriveMemberKey(entropy) {
|
|
1005
|
+
return member_from_entropy(entropy);
|
|
1006
|
+
}
|
|
1007
|
+
function deriveBandersnatchMember(mnemonic, entropyKey) {
|
|
1008
|
+
return deriveMemberKey(deriveMemberEntropy(mnemonic, resolveEntropyKey(entropyKey)));
|
|
1009
|
+
}
|
|
1010
|
+
function deriveAlias(entropy, context) {
|
|
1011
|
+
return alias_in_context(entropy, context);
|
|
1012
|
+
}
|
|
1013
|
+
function bandersnatchSign(entropy, message) {
|
|
1014
|
+
return sign2(entropy, message);
|
|
1015
|
+
}
|
|
1016
|
+
function verifyBandersnatchSig(signature, message, member) {
|
|
1017
|
+
return verify_signature(signature, message, member);
|
|
1018
|
+
}
|
|
1019
|
+
function ringProve(ringExp, entropy, members, context, message) {
|
|
1020
|
+
const result = one_shot(ringExp, entropy, members, context, message);
|
|
1021
|
+
return { proof: result.proof, alias: result.alias };
|
|
1022
|
+
}
|
|
1023
|
+
function verifyRingProof(ringExp, proof, source, context, message) {
|
|
1024
|
+
if (source.commitment !== undefined) {
|
|
1025
|
+
return validate_with_commitment(ringExp, proof, source.commitment, context, message);
|
|
1026
|
+
}
|
|
1027
|
+
if (source.members !== undefined) {
|
|
1028
|
+
return validate(ringExp, proof, source.members, context, message);
|
|
1029
|
+
}
|
|
1030
|
+
throw new Error("verifyRingProof requires either `members` or `commitment`");
|
|
1031
|
+
}
|
|
1032
|
+
function ringRoot(ringExp, members) {
|
|
1033
|
+
return members_root(ringExp, members);
|
|
1034
|
+
}
|
|
1035
|
+
function compactEncode(n) {
|
|
1036
|
+
if (!Number.isInteger(n) || n < 0)
|
|
1037
|
+
throw new Error("compactEncode: non-negative integer required");
|
|
1038
|
+
return compact.enc(n);
|
|
1039
|
+
}
|
|
1040
|
+
function encodeMembers(members) {
|
|
1041
|
+
for (const m of members) {
|
|
1042
|
+
if (m.length !== 32) {
|
|
1043
|
+
throw new Error(`member key must be 32 bytes (got ${m.length})`);
|
|
1044
|
+
}
|
|
1045
|
+
}
|
|
1046
|
+
const prefix = compactEncode(members.length);
|
|
1047
|
+
const out = new Uint8Array(prefix.length + members.length * 32);
|
|
1048
|
+
out.set(prefix, 0);
|
|
1049
|
+
let offset = prefix.length;
|
|
1050
|
+
for (const m of members) {
|
|
1051
|
+
out.set(m, offset);
|
|
1052
|
+
offset += 32;
|
|
1053
|
+
}
|
|
1054
|
+
return out;
|
|
1055
|
+
}
|
|
1056
|
+
function encodeContext(input) {
|
|
1057
|
+
const bytes = textOrHexBytes(input, "context");
|
|
1058
|
+
if (bytes.length > 32) {
|
|
1059
|
+
throw new Error(`Context must be at most 32 bytes (got ${bytes.length})`);
|
|
880
1060
|
}
|
|
881
|
-
const
|
|
882
|
-
|
|
1061
|
+
const out = new Uint8Array(32);
|
|
1062
|
+
out.set(bytes, 0);
|
|
1063
|
+
return out;
|
|
883
1064
|
}
|
|
884
|
-
var
|
|
1065
|
+
var RING_EXPONENTS, DEFAULT_RING_EXPONENT = 9;
|
|
1066
|
+
var init_lib = __esm(() => {
|
|
1067
|
+
RING_EXPONENTS = [9, 10, 14];
|
|
1068
|
+
});
|
|
885
1069
|
|
|
886
1070
|
// src/core/client.ts
|
|
887
1071
|
import { createClient } from "polkadot-api";
|
|
@@ -1007,9 +1191,9 @@ function compactEntry(entry, color) {
|
|
|
1007
1191
|
}
|
|
1008
1192
|
}
|
|
1009
1193
|
function expandEntry(entry, indent, width, color, prefix = 0) {
|
|
1010
|
-
const
|
|
1011
|
-
if (visualWidth(
|
|
1012
|
-
return
|
|
1194
|
+
const compact2 = compactEntry(entry, color);
|
|
1195
|
+
if (visualWidth(compact2) + indent + prefix <= width)
|
|
1196
|
+
return compact2;
|
|
1013
1197
|
switch (entry.type) {
|
|
1014
1198
|
case "struct":
|
|
1015
1199
|
return expandStruct(entry.value, indent, width, color);
|
|
@@ -1043,7 +1227,7 @@ ${closePadding}>`;
|
|
|
1043
1227
|
case "lookupEntry":
|
|
1044
1228
|
return expandEntry(entry.value, indent, width, color);
|
|
1045
1229
|
default:
|
|
1046
|
-
return
|
|
1230
|
+
return compact2;
|
|
1047
1231
|
}
|
|
1048
1232
|
}
|
|
1049
1233
|
function expandStruct(fields, indent, width, color) {
|
|
@@ -1102,9 +1286,9 @@ ${closePadding}${close}`;
|
|
|
1102
1286
|
}
|
|
1103
1287
|
function prettyType(entry, opts = {}) {
|
|
1104
1288
|
const { indent, prefix, width, color } = resolveOpts(opts);
|
|
1105
|
-
const
|
|
1106
|
-
if (visualWidth(
|
|
1107
|
-
return
|
|
1289
|
+
const compact2 = compactEntry(entry, color);
|
|
1290
|
+
if (visualWidth(compact2) + indent + prefix <= width)
|
|
1291
|
+
return compact2;
|
|
1108
1292
|
return expandEntry(entry, indent, width, color);
|
|
1109
1293
|
}
|
|
1110
1294
|
function prettyTypeById(lookup, typeId, opts = {}) {
|
|
@@ -1208,15 +1392,15 @@ function renderArgsFromFields(fields, opts) {
|
|
|
1208
1392
|
case "void":
|
|
1209
1393
|
return "()";
|
|
1210
1394
|
case "named": {
|
|
1211
|
-
const
|
|
1212
|
-
if (visualWidth(
|
|
1213
|
-
return
|
|
1395
|
+
const compact2 = `(${fields.fields.map(([k, v]) => `${paint(color, CYAN2, k)}: ${compactEntry(v, color)}`).join(", ")})`;
|
|
1396
|
+
if (visualWidth(compact2) + lead <= width)
|
|
1397
|
+
return compact2;
|
|
1214
1398
|
return renderFieldList(fields.fields, "(", ")", indent, width, color);
|
|
1215
1399
|
}
|
|
1216
1400
|
case "positional": {
|
|
1217
|
-
const
|
|
1218
|
-
if (visualWidth(
|
|
1219
|
-
return
|
|
1401
|
+
const compact2 = `(${fields.types.map((t) => compactEntry(t, color)).join(", ")})`;
|
|
1402
|
+
if (visualWidth(compact2) + lead <= width)
|
|
1403
|
+
return compact2;
|
|
1220
1404
|
const innerIndent = indent + 2;
|
|
1221
1405
|
const padding = " ".repeat(innerIndent);
|
|
1222
1406
|
const closePadding = " ".repeat(indent);
|
|
@@ -1227,9 +1411,9 @@ ${lines.join(`,
|
|
|
1227
1411
|
${closePadding})`;
|
|
1228
1412
|
}
|
|
1229
1413
|
case "single": {
|
|
1230
|
-
const
|
|
1231
|
-
if (visualWidth(
|
|
1232
|
-
return
|
|
1414
|
+
const compact2 = `(${compactEntry(fields.type, color)})`;
|
|
1415
|
+
if (visualWidth(compact2) + lead <= width)
|
|
1416
|
+
return compact2;
|
|
1233
1417
|
const inner = expandEntry(fields.type, indent + 2, width, color);
|
|
1234
1418
|
return `(
|
|
1235
1419
|
${" ".repeat(indent + 2)}${inner},
|
|
@@ -1300,7 +1484,7 @@ async function fetchMetadataFromChain(clientHandle, chainName) {
|
|
|
1300
1484
|
let bytes;
|
|
1301
1485
|
try {
|
|
1302
1486
|
const hex = await withTimeout(client._request("state_call", ["Metadata_metadata_at_version", v15Arg]), chainName);
|
|
1303
|
-
const raw =
|
|
1487
|
+
const raw = hexToBytes4(hex);
|
|
1304
1488
|
const decoded = optionalOpaqueBytes.dec(raw);
|
|
1305
1489
|
if (decoded !== undefined) {
|
|
1306
1490
|
bytes = new Uint8Array(decoded);
|
|
@@ -1309,7 +1493,7 @@ async function fetchMetadataFromChain(clientHandle, chainName) {
|
|
|
1309
1493
|
if (!bytes) {
|
|
1310
1494
|
try {
|
|
1311
1495
|
const hex = await withTimeout(client._request("state_getMetadata", []), chainName);
|
|
1312
|
-
bytes =
|
|
1496
|
+
bytes = hexToBytes4(hex);
|
|
1313
1497
|
} catch (err) {
|
|
1314
1498
|
if (err instanceof ConnectionError)
|
|
1315
1499
|
throw err;
|
|
@@ -1505,7 +1689,7 @@ function describeCallArgs(meta, palletName, callName) {
|
|
|
1505
1689
|
function describeEventFields(meta, palletName, eventName) {
|
|
1506
1690
|
return compactArgsString(getEventFields(meta, palletName, eventName));
|
|
1507
1691
|
}
|
|
1508
|
-
function
|
|
1692
|
+
function hexToBytes4(hex) {
|
|
1509
1693
|
const clean = hex.startsWith("0x") ? hex.slice(2) : hex;
|
|
1510
1694
|
const bytes = new Uint8Array(clean.length / 2);
|
|
1511
1695
|
for (let i = 0;i < clean.length; i += 2) {
|
|
@@ -3234,7 +3418,7 @@ var init_xxh64 = __esm(() => {
|
|
|
3234
3418
|
import { blake2b as blake2b2 } from "@noble/hashes/blake2.js";
|
|
3235
3419
|
import { sha256 } from "@noble/hashes/sha2.js";
|
|
3236
3420
|
import { keccak_256 as keccak_2562 } from "@noble/hashes/sha3.js";
|
|
3237
|
-
import { bytesToHex as bytesToHex3, hexToBytes as
|
|
3421
|
+
import { bytesToHex as bytesToHex3, hexToBytes as hexToBytes5 } from "@noble/hashes/utils.js";
|
|
3238
3422
|
function computeHash(algorithm, data) {
|
|
3239
3423
|
const algo = ALGORITHMS[algorithm];
|
|
3240
3424
|
if (!algo) {
|
|
@@ -3248,7 +3432,7 @@ function parseInputData(input) {
|
|
|
3248
3432
|
if (hex.length % 2 !== 0) {
|
|
3249
3433
|
throw new Error(`Invalid hex input: odd number of characters`);
|
|
3250
3434
|
}
|
|
3251
|
-
return
|
|
3435
|
+
return hexToBytes5(hex);
|
|
3252
3436
|
}
|
|
3253
3437
|
return new TextEncoder().encode(input);
|
|
3254
3438
|
}
|
|
@@ -3303,6 +3487,333 @@ var init_hash = __esm(() => {
|
|
|
3303
3487
|
};
|
|
3304
3488
|
});
|
|
3305
3489
|
|
|
3490
|
+
// src/core/input.ts
|
|
3491
|
+
import { readFile as readFile5 } from "node:fs/promises";
|
|
3492
|
+
async function resolveDataInput(inline, opts, messages) {
|
|
3493
|
+
const sources = [inline !== undefined, !!opts.file, !!opts.stdin].filter(Boolean).length;
|
|
3494
|
+
if (sources > 1) {
|
|
3495
|
+
throw new CliError(messages?.conflict ?? "Provide only one of: inline data, --file, or --stdin");
|
|
3496
|
+
}
|
|
3497
|
+
if (sources === 0) {
|
|
3498
|
+
throw new CliError(messages?.missing ?? "No input provided. Pass data as argument, or use --file or --stdin");
|
|
3499
|
+
}
|
|
3500
|
+
if (opts.file) {
|
|
3501
|
+
const buf = await readFile5(opts.file);
|
|
3502
|
+
return new Uint8Array(buf);
|
|
3503
|
+
}
|
|
3504
|
+
if (opts.stdin) {
|
|
3505
|
+
const chunks = [];
|
|
3506
|
+
for await (const chunk of process.stdin) {
|
|
3507
|
+
chunks.push(chunk);
|
|
3508
|
+
}
|
|
3509
|
+
return new Uint8Array(Buffer.concat(chunks));
|
|
3510
|
+
}
|
|
3511
|
+
return parseInputData(inline);
|
|
3512
|
+
}
|
|
3513
|
+
var init_input = __esm(() => {
|
|
3514
|
+
init_errors();
|
|
3515
|
+
init_hash();
|
|
3516
|
+
});
|
|
3517
|
+
|
|
3518
|
+
// src/platform/index.ts
|
|
3519
|
+
var init_platform = __esm(() => {
|
|
3520
|
+
init_accounts_store();
|
|
3521
|
+
init_accounts();
|
|
3522
|
+
init_hash();
|
|
3523
|
+
init_input();
|
|
3524
|
+
init_output();
|
|
3525
|
+
init_errors();
|
|
3526
|
+
init_cli();
|
|
3527
|
+
});
|
|
3528
|
+
|
|
3529
|
+
// src/features/verifiable/commands.ts
|
|
3530
|
+
var exports_commands = {};
|
|
3531
|
+
__export(exports_commands, {
|
|
3532
|
+
runVerifiable: () => runVerifiable
|
|
3533
|
+
});
|
|
3534
|
+
import { readFile as readFile8 } from "node:fs/promises";
|
|
3535
|
+
import { DEV_PHRASE as DEV_PHRASE2 } from "@polkadot-labs/hdkd-helpers";
|
|
3536
|
+
async function runVerifiable(action, rest, opts) {
|
|
3537
|
+
switch (action) {
|
|
3538
|
+
case "member":
|
|
3539
|
+
return deriveMember(rest[0], opts);
|
|
3540
|
+
case "alias":
|
|
3541
|
+
return deriveAliasCmd(rest[0], opts);
|
|
3542
|
+
case "sign":
|
|
3543
|
+
return signCmd(rest[0], opts);
|
|
3544
|
+
case "prove":
|
|
3545
|
+
return proveCmd(rest[0], opts);
|
|
3546
|
+
case "verify":
|
|
3547
|
+
return verifyCmd(opts);
|
|
3548
|
+
case "verify-sig":
|
|
3549
|
+
return verifySigCmd(opts);
|
|
3550
|
+
case "members":
|
|
3551
|
+
return membersCmd(rest, opts);
|
|
3552
|
+
default:
|
|
3553
|
+
return deriveMember(action, opts);
|
|
3554
|
+
}
|
|
3555
|
+
}
|
|
3556
|
+
function mnemonicFromStored(stored, account, accountsFile) {
|
|
3557
|
+
if (!stored) {
|
|
3558
|
+
const available = [...DEV_NAMES, ...accountsFile.accounts.map((a) => a.name)].sort((a, b) => a.localeCompare(b));
|
|
3559
|
+
const suggestions = findClosest(account, available);
|
|
3560
|
+
const hint = suggestions.length > 0 ? `
|
|
3561
|
+
Did you mean: ${suggestions.join(", ")}?` : "";
|
|
3562
|
+
const list = available.map((a) => `
|
|
3563
|
+
- ${a}`).join("");
|
|
3564
|
+
throw new Error(`Unknown account "${account}".${hint}
|
|
3565
|
+
Available accounts:${list}`);
|
|
3566
|
+
}
|
|
3567
|
+
if (isWatchOnly(stored)) {
|
|
3568
|
+
throw new Error(`Account "${account}" is watch-only (no secret). Cannot derive Bandersnatch key.`);
|
|
3569
|
+
}
|
|
3570
|
+
const secret = resolveSecret(stored.secret);
|
|
3571
|
+
if (isHexPublicKey(`0x${secret.replace(/^0x/, "")}`)) {
|
|
3572
|
+
throw new Error(`Account "${account}" uses a hex seed. Bandersnatch derivation requires a BIP39 mnemonic.`);
|
|
3573
|
+
}
|
|
3574
|
+
return secret;
|
|
3575
|
+
}
|
|
3576
|
+
async function resolveMnemonic(account) {
|
|
3577
|
+
if (isDevAccount(account)) {
|
|
3578
|
+
return DEV_PHRASE2;
|
|
3579
|
+
}
|
|
3580
|
+
const accountsFile = await loadAccounts();
|
|
3581
|
+
return mnemonicFromStored(findAccount(accountsFile, account), account, accountsFile);
|
|
3582
|
+
}
|
|
3583
|
+
async function resolveEntropy(account, entropyKey) {
|
|
3584
|
+
const mnemonic = await resolveMnemonic(account);
|
|
3585
|
+
return deriveMemberEntropy(mnemonic, resolveEntropyKey(entropyKey));
|
|
3586
|
+
}
|
|
3587
|
+
function requireAccount(account, action) {
|
|
3588
|
+
if (!account) {
|
|
3589
|
+
throw new CliError(`dot verifiable ${action} requires an account. See "dot verifiable".`);
|
|
3590
|
+
}
|
|
3591
|
+
return account;
|
|
3592
|
+
}
|
|
3593
|
+
function resolveMessage(opts) {
|
|
3594
|
+
return resolveDataInput(opts.message, opts, {
|
|
3595
|
+
conflict: "Provide only one of: --message, --file, or --stdin",
|
|
3596
|
+
missing: "No message provided. Use --message, --file, or --stdin"
|
|
3597
|
+
});
|
|
3598
|
+
}
|
|
3599
|
+
async function resolveBytesArg(value, name, allowFile = false) {
|
|
3600
|
+
if (value.startsWith("0x")) {
|
|
3601
|
+
return parseInputData(value);
|
|
3602
|
+
}
|
|
3603
|
+
if (allowFile) {
|
|
3604
|
+
const buf = await readFile8(value);
|
|
3605
|
+
const text = buf.toString("utf8").trim();
|
|
3606
|
+
return text.startsWith("0x") ? parseInputData(text) : new Uint8Array(buf);
|
|
3607
|
+
}
|
|
3608
|
+
throw new CliError(`${name} must be 0x-prefixed hex`);
|
|
3609
|
+
}
|
|
3610
|
+
function resolveRingExponent(opts) {
|
|
3611
|
+
if (opts.ringExponent === undefined)
|
|
3612
|
+
return DEFAULT_RING_EXPONENT;
|
|
3613
|
+
const n = Number(opts.ringExponent);
|
|
3614
|
+
if (!isRingExponent(n)) {
|
|
3615
|
+
throw new CliError(`Invalid --ring-exponent "${opts.ringExponent}". Supported: 9, 10, 14.`);
|
|
3616
|
+
}
|
|
3617
|
+
return n;
|
|
3618
|
+
}
|
|
3619
|
+
function requireOption(value, flag, action) {
|
|
3620
|
+
if (value === undefined) {
|
|
3621
|
+
throw new CliError(`dot verifiable ${action} requires ${flag}.`);
|
|
3622
|
+
}
|
|
3623
|
+
return value;
|
|
3624
|
+
}
|
|
3625
|
+
async function deriveMember(accountArg, opts) {
|
|
3626
|
+
const account = requireAccount(accountArg, "member");
|
|
3627
|
+
const usedDeprecatedContext = opts.entropyKey === undefined && opts.context !== undefined;
|
|
3628
|
+
if (usedDeprecatedContext) {
|
|
3629
|
+
if (opts.context.startsWith("0x")) {
|
|
3630
|
+
throw new CliError(`"--context" on "dot verifiable" now means the 32-byte ring context, and hex ` + `entropy keys changed meaning in this release. Pass "--entropy-key ${opts.context}" explicitly.`);
|
|
3631
|
+
}
|
|
3632
|
+
process.stderr.write(`Warning: "--context" on "dot verifiable" now refers to the 32-byte ring context. ` + `For member-key derivation use "--entropy-key". Treating "--context ${opts.context}" ` + `as the entropy key for now.
|
|
3633
|
+
`);
|
|
3634
|
+
}
|
|
3635
|
+
const entropyKeyStr = opts.entropyKey ?? opts.context;
|
|
3636
|
+
let mnemonic;
|
|
3637
|
+
let accountsFile;
|
|
3638
|
+
let stored;
|
|
3639
|
+
if (isDevAccount(account)) {
|
|
3640
|
+
mnemonic = DEV_PHRASE2;
|
|
3641
|
+
} else {
|
|
3642
|
+
accountsFile = await loadAccounts();
|
|
3643
|
+
stored = findAccount(accountsFile, account);
|
|
3644
|
+
mnemonic = mnemonicFromStored(stored, account, accountsFile);
|
|
3645
|
+
}
|
|
3646
|
+
const memberKeyHex = publicKeyToHex(deriveBandersnatchMember(mnemonic, entropyKeyStr));
|
|
3647
|
+
if (stored && accountsFile) {
|
|
3648
|
+
if (!stored.bandersnatch)
|
|
3649
|
+
stored.bandersnatch = {};
|
|
3650
|
+
const entryKey = entropyKeyStr ?? "";
|
|
3651
|
+
if (stored.bandersnatch[entryKey] !== memberKeyHex) {
|
|
3652
|
+
stored.bandersnatch[entryKey] = memberKeyHex;
|
|
3653
|
+
await saveAccounts(accountsFile);
|
|
3654
|
+
}
|
|
3655
|
+
}
|
|
3656
|
+
const fieldKey = usedDeprecatedContext ? "context" : "entropyKey";
|
|
3657
|
+
if (isJsonOutput(opts)) {
|
|
3658
|
+
const result = { account, memberKey: memberKeyHex };
|
|
3659
|
+
if (entropyKeyStr)
|
|
3660
|
+
result[fieldKey] = entropyKeyStr;
|
|
3661
|
+
console.log(formatJson(result));
|
|
3662
|
+
} else {
|
|
3663
|
+
printHeading("Bandersnatch Member Key");
|
|
3664
|
+
console.log(` ${BOLD}Account:${RESET} ${account}`);
|
|
3665
|
+
if (entropyKeyStr) {
|
|
3666
|
+
const line = usedDeprecatedContext ? ` ${BOLD}Context:${RESET} ${entropyKeyStr}` : ` ${BOLD}Entropy Key:${RESET} ${entropyKeyStr}`;
|
|
3667
|
+
console.log(line);
|
|
3668
|
+
}
|
|
3669
|
+
console.log(` ${BOLD}Member Key:${RESET} ${memberKeyHex}`);
|
|
3670
|
+
console.log();
|
|
3671
|
+
}
|
|
3672
|
+
}
|
|
3673
|
+
async function deriveAliasCmd(accountArg, opts) {
|
|
3674
|
+
const account = requireAccount(accountArg, "alias");
|
|
3675
|
+
const contextStr = requireOption(opts.context, "--context", "alias");
|
|
3676
|
+
const entropy = await resolveEntropy(account, opts.entropyKey);
|
|
3677
|
+
const context = encodeContext(contextStr);
|
|
3678
|
+
const aliasHex = toHex2(deriveAlias(entropy, context));
|
|
3679
|
+
if (isJsonOutput(opts)) {
|
|
3680
|
+
console.log(formatJson({ account, context: contextStr, alias: aliasHex }));
|
|
3681
|
+
} else {
|
|
3682
|
+
printHeading("Verifiable Alias");
|
|
3683
|
+
console.log(` ${BOLD}Account:${RESET} ${account}`);
|
|
3684
|
+
console.log(` ${BOLD}Context:${RESET} ${contextStr}`);
|
|
3685
|
+
console.log(` ${BOLD}Alias:${RESET} ${aliasHex}`);
|
|
3686
|
+
console.log();
|
|
3687
|
+
}
|
|
3688
|
+
}
|
|
3689
|
+
async function signCmd(accountArg, opts) {
|
|
3690
|
+
const account = requireAccount(accountArg, "sign");
|
|
3691
|
+
const message = await resolveMessage(opts);
|
|
3692
|
+
const entropy = await resolveEntropy(account, opts.entropyKey);
|
|
3693
|
+
const signature = bandersnatchSign(entropy, message);
|
|
3694
|
+
const member = deriveMemberKey(entropy);
|
|
3695
|
+
const sigHex = toHex2(signature);
|
|
3696
|
+
const result = {
|
|
3697
|
+
type: "Bandersnatch",
|
|
3698
|
+
account,
|
|
3699
|
+
message: toHex2(message),
|
|
3700
|
+
signature: sigHex,
|
|
3701
|
+
member: toHex2(member),
|
|
3702
|
+
enum: `Bandersnatch(${sigHex})`
|
|
3703
|
+
};
|
|
3704
|
+
if (isJsonOutput(opts)) {
|
|
3705
|
+
console.log(formatJson(result));
|
|
3706
|
+
} else {
|
|
3707
|
+
console.log(` ${BOLD}Type:${RESET} ${result.type}`);
|
|
3708
|
+
console.log(` ${BOLD}Message:${RESET} ${result.message}`);
|
|
3709
|
+
console.log(` ${BOLD}Signature:${RESET} ${result.signature}`);
|
|
3710
|
+
console.log(` ${BOLD}Member:${RESET} ${result.member}`);
|
|
3711
|
+
console.log(` ${BOLD}Enum:${RESET} ${result.enum}`);
|
|
3712
|
+
}
|
|
3713
|
+
}
|
|
3714
|
+
async function proveCmd(accountArg, opts) {
|
|
3715
|
+
const account = requireAccount(accountArg, "prove");
|
|
3716
|
+
const contextStr = requireOption(opts.context, "--context", "prove");
|
|
3717
|
+
const membersArg = requireOption(opts.members, "--members", "prove");
|
|
3718
|
+
const message = await resolveMessage(opts);
|
|
3719
|
+
const ringExponent = resolveRingExponent(opts);
|
|
3720
|
+
const entropy = await resolveEntropy(account, opts.entropyKey);
|
|
3721
|
+
const context = encodeContext(contextStr);
|
|
3722
|
+
const members = await resolveBytesArg(membersArg, "--members", true);
|
|
3723
|
+
const { proof, alias } = ringProve(ringExponent, entropy, members, context, message);
|
|
3724
|
+
const result = {
|
|
3725
|
+
account,
|
|
3726
|
+
context: contextStr,
|
|
3727
|
+
ringExponent,
|
|
3728
|
+
alias: toHex2(alias),
|
|
3729
|
+
proof: toHex2(proof)
|
|
3730
|
+
};
|
|
3731
|
+
if (isJsonOutput(opts)) {
|
|
3732
|
+
console.log(formatJson(result));
|
|
3733
|
+
} else {
|
|
3734
|
+
printHeading("Ring-VRF Proof");
|
|
3735
|
+
console.log(` ${BOLD}Account:${RESET} ${account}`);
|
|
3736
|
+
console.log(` ${BOLD}Context:${RESET} ${contextStr}`);
|
|
3737
|
+
console.log(` ${BOLD}Ring exponent:${RESET} ${ringExponent}`);
|
|
3738
|
+
console.log(` ${BOLD}Alias:${RESET} ${result.alias}`);
|
|
3739
|
+
console.log(` ${BOLD}Proof:${RESET} ${result.proof}`);
|
|
3740
|
+
console.log();
|
|
3741
|
+
}
|
|
3742
|
+
}
|
|
3743
|
+
async function verifyCmd(opts) {
|
|
3744
|
+
const proofArg = requireOption(opts.proof, "--proof", "verify");
|
|
3745
|
+
const contextStr = requireOption(opts.context, "--context", "verify");
|
|
3746
|
+
if (!opts.members && !opts.root) {
|
|
3747
|
+
throw new CliError("dot verifiable verify requires --members or --root.");
|
|
3748
|
+
}
|
|
3749
|
+
if (opts.members && opts.root) {
|
|
3750
|
+
throw new CliError("Provide either --members or --root, not both.");
|
|
3751
|
+
}
|
|
3752
|
+
const message = await resolveMessage(opts);
|
|
3753
|
+
const ringExponent = resolveRingExponent(opts);
|
|
3754
|
+
const proof = await resolveBytesArg(proofArg, "--proof", true);
|
|
3755
|
+
const context = encodeContext(contextStr);
|
|
3756
|
+
const source = opts.root ? { commitment: await resolveBytesArg(opts.root, "--root", true) } : { members: await resolveBytesArg(opts.members, "--members", true) };
|
|
3757
|
+
let aliasHex;
|
|
3758
|
+
try {
|
|
3759
|
+
aliasHex = toHex2(verifyRingProof(ringExponent, proof, source, context, message));
|
|
3760
|
+
} catch (err) {
|
|
3761
|
+
const exponentHint = opts.ringExponent === undefined ? ` (assumed ring exponent ${ringExponent} — pass --ring-exponent if the ring uses 10 or 14)` : "";
|
|
3762
|
+
throw new CliError(`Ring-VRF proof is invalid: ${err instanceof Error ? err.message : String(err)}${exponentHint}`);
|
|
3763
|
+
}
|
|
3764
|
+
if (isJsonOutput(opts)) {
|
|
3765
|
+
console.log(formatJson({ valid: true, alias: aliasHex, ringExponent }));
|
|
3766
|
+
} else {
|
|
3767
|
+
printHeading("Ring-VRF Verification");
|
|
3768
|
+
console.log(` ${BOLD}Valid:${RESET} yes`);
|
|
3769
|
+
console.log(` ${BOLD}Alias:${RESET} ${aliasHex}`);
|
|
3770
|
+
console.log();
|
|
3771
|
+
}
|
|
3772
|
+
}
|
|
3773
|
+
async function verifySigCmd(opts) {
|
|
3774
|
+
const sigArg = requireOption(opts.signature, "--signature", "verify-sig");
|
|
3775
|
+
const memberArg = requireOption(opts.member, "--member", "verify-sig");
|
|
3776
|
+
const message = await resolveMessage(opts);
|
|
3777
|
+
const signature = await resolveBytesArg(sigArg, "--signature", true);
|
|
3778
|
+
const member = await resolveBytesArg(memberArg, "--member");
|
|
3779
|
+
const valid = verifyBandersnatchSig(signature, message, member);
|
|
3780
|
+
if (!valid) {
|
|
3781
|
+
throw new CliError("Bandersnatch signature is invalid.");
|
|
3782
|
+
}
|
|
3783
|
+
if (isJsonOutput(opts)) {
|
|
3784
|
+
console.log(formatJson({ valid: true }));
|
|
3785
|
+
} else {
|
|
3786
|
+
printHeading("Bandersnatch Signature Verification");
|
|
3787
|
+
console.log(` ${BOLD}Valid:${RESET} yes`);
|
|
3788
|
+
console.log();
|
|
3789
|
+
}
|
|
3790
|
+
}
|
|
3791
|
+
async function membersCmd(rest, opts) {
|
|
3792
|
+
if (rest.length === 0) {
|
|
3793
|
+
throw new CliError("dot verifiable members requires one or more 0x-hex member keys.");
|
|
3794
|
+
}
|
|
3795
|
+
const memberBytes = rest.map((k) => {
|
|
3796
|
+
const bytes = parseInputData(k);
|
|
3797
|
+
if (bytes.length !== 32) {
|
|
3798
|
+
throw new CliError(`member key must be 32 bytes (got ${bytes.length}): ${k}`);
|
|
3799
|
+
}
|
|
3800
|
+
return bytes;
|
|
3801
|
+
});
|
|
3802
|
+
const encoded = toHex2(encodeMembers(memberBytes));
|
|
3803
|
+
if (isJsonOutput(opts)) {
|
|
3804
|
+
console.log(formatJson({ count: rest.length, members: encoded }));
|
|
3805
|
+
} else {
|
|
3806
|
+
printHeading("Encoded Members");
|
|
3807
|
+
console.log(` ${BOLD}Count:${RESET} ${rest.length}`);
|
|
3808
|
+
console.log(` ${BOLD}Members:${RESET} ${encoded}`);
|
|
3809
|
+
console.log();
|
|
3810
|
+
}
|
|
3811
|
+
}
|
|
3812
|
+
var init_commands = __esm(() => {
|
|
3813
|
+
init_platform();
|
|
3814
|
+
init_lib();
|
|
3815
|
+
});
|
|
3816
|
+
|
|
3306
3817
|
// src/completions/complete.ts
|
|
3307
3818
|
var exports_complete = {};
|
|
3308
3819
|
__export(exports_complete, {
|
|
@@ -3664,7 +4175,16 @@ var init_complete = __esm(() => {
|
|
|
3664
4175
|
ext: "extensions",
|
|
3665
4176
|
rpc: "rpc"
|
|
3666
4177
|
};
|
|
3667
|
-
NAMED_COMMANDS = [
|
|
4178
|
+
NAMED_COMMANDS = [
|
|
4179
|
+
"chain",
|
|
4180
|
+
"account",
|
|
4181
|
+
"inspect",
|
|
4182
|
+
"hash",
|
|
4183
|
+
"sign",
|
|
4184
|
+
"completions",
|
|
4185
|
+
"init",
|
|
4186
|
+
"which"
|
|
4187
|
+
];
|
|
3668
4188
|
CHAIN_SUBCOMMANDS = ["add", "info", "list", "remove", "update"];
|
|
3669
4189
|
ACCOUNT_SUBCOMMANDS = [
|
|
3670
4190
|
"add",
|
|
@@ -3696,7 +4216,7 @@ var init_complete = __esm(() => {
|
|
|
3696
4216
|
// src/cli.ts
|
|
3697
4217
|
import cac from "cac";
|
|
3698
4218
|
// package.json
|
|
3699
|
-
var version = "1.
|
|
4219
|
+
var version = "1.22.0";
|
|
3700
4220
|
|
|
3701
4221
|
// src/commands/account.ts
|
|
3702
4222
|
init_accounts_store();
|
|
@@ -3830,6 +4350,7 @@ function isValidParaId(value) {
|
|
|
3830
4350
|
}
|
|
3831
4351
|
|
|
3832
4352
|
// src/commands/account.ts
|
|
4353
|
+
init_cli();
|
|
3833
4354
|
var ACCOUNT_HELP = `
|
|
3834
4355
|
${BOLD}Usage:${RESET}
|
|
3835
4356
|
$ dot account add <name> <ss58|hex> Add a watch-only address (no secret)
|
|
@@ -3846,7 +4367,7 @@ ${BOLD}Usage:${RESET}
|
|
|
3846
4367
|
$ dot account inspect --pallet-id <id> [--prefix <N>] Derive a pallet sovereign (no save — script-friendly)
|
|
3847
4368
|
$ dot account inspect --parachain <id> --parachain-type <t> Derive a parachain sovereign (no save — script-friendly)
|
|
3848
4369
|
$ dot account list List all accounts
|
|
3849
|
-
$ dot account remove|delete <name> [name2] ...
|
|
4370
|
+
$ dot account remove|delete|rm <name> [name2] ... Remove stored account(s)
|
|
3850
4371
|
|
|
3851
4372
|
${BOLD}Examples:${RESET}
|
|
3852
4373
|
$ dot account add treasury 5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY
|
|
@@ -3884,7 +4405,7 @@ ${YELLOW}Note: Secrets are stored unencrypted in ~/.polkadot/accounts.json.
|
|
|
3884
4405
|
Raw private keys cannot be HD-derived, so --path is rejected for them.${RESET}
|
|
3885
4406
|
`.trimStart();
|
|
3886
4407
|
function registerAccountCommands(cli) {
|
|
3887
|
-
cli.command("account [action] [...names]", "Manage local accounts (create, import, list, remove, export)").alias("accounts").option("--secret <value>", "Secret for import: BIP39 mnemonic, 0x 32-byte hex seed, or 0x 64-byte raw private key").option("--env <varName>", "Environment variable name holding the secret").option("--path <derivation>", "Derivation path (e.g. //staking, //polkadot//0/wallet)").option("--parachain <id>", "Derive a parachain sovereign account (requires --parachain-type)").option("--parachain-type <type>", "Parachain sovereign type: child or sibling").option("--pallet-id <id>", "Derive a pallet sovereign account from an 8-byte PalletId").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) => {
|
|
4408
|
+
const command = cli.command("account [action] [...names]", "Manage local accounts (create, import, list, remove, export)").alias("accounts").option("--secret <value>", "Secret for import: BIP39 mnemonic, 0x 32-byte hex seed, or 0x 64-byte raw private key").option("--env <varName>", "Environment variable name holding the secret").option("--path <derivation>", "Derivation path (e.g. //staking, //polkadot//0/wallet)").option("--parachain <id>", "Derive a parachain sovereign account (requires --parachain-type)").option("--parachain-type <type>", "Parachain sovereign type: child or sibling").option("--pallet-id <id>", "Derive a pallet sovereign account from an 8-byte PalletId").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) => {
|
|
3888
4409
|
if (!action) {
|
|
3889
4410
|
if (process.argv[2] === "accounts")
|
|
3890
4411
|
return accountList(opts);
|
|
@@ -3917,6 +4438,7 @@ function registerAccountCommands(cli) {
|
|
|
3917
4438
|
return accountList(opts);
|
|
3918
4439
|
case "delete":
|
|
3919
4440
|
case "remove":
|
|
4441
|
+
case "rm":
|
|
3920
4442
|
return accountRemove(names, opts);
|
|
3921
4443
|
case "inspect":
|
|
3922
4444
|
return accountInspect(names[0], opts);
|
|
@@ -3924,6 +4446,7 @@ function registerAccountCommands(cli) {
|
|
|
3924
4446
|
return accountInspect(action, opts);
|
|
3925
4447
|
}
|
|
3926
4448
|
});
|
|
4449
|
+
withHelp(command, () => console.log(ACCOUNT_HELP));
|
|
3927
4450
|
}
|
|
3928
4451
|
async function accountCreate(name, opts) {
|
|
3929
4452
|
if (!name) {
|
|
@@ -3943,7 +4466,7 @@ async function accountCreate(name, opts) {
|
|
|
3943
4466
|
const { mnemonic, publicKey } = createNewAccount(path);
|
|
3944
4467
|
const hexPub = publicKeyToHex(publicKey);
|
|
3945
4468
|
const address = toSs58(publicKey);
|
|
3946
|
-
const { deriveBandersnatchMember: deriveBandersnatchMember2 } = await Promise.resolve().then(() => (
|
|
4469
|
+
const { deriveBandersnatchMember: deriveBandersnatchMember2 } = await Promise.resolve().then(() => (init_lib(), exports_lib));
|
|
3947
4470
|
const bandersnatch = {};
|
|
3948
4471
|
bandersnatch[""] = publicKeyToHex(deriveBandersnatchMember2(mnemonic));
|
|
3949
4472
|
bandersnatch.candidate = publicKeyToHex(deriveBandersnatchMember2(mnemonic, "candidate"));
|
|
@@ -5017,6 +5540,7 @@ async function fetchRpcMethods(rpcUrl) {
|
|
|
5017
5540
|
|
|
5018
5541
|
// src/commands/chain.ts
|
|
5019
5542
|
init_rpc_registry();
|
|
5543
|
+
init_cli();
|
|
5020
5544
|
var CHAIN_HELP = `
|
|
5021
5545
|
${BOLD}Usage:${RESET}
|
|
5022
5546
|
$ dot chain add <name> --rpc <url> Add a chain via WebSocket RPC
|
|
@@ -5050,7 +5574,7 @@ ${BOLD}Examples:${RESET}
|
|
|
5050
5574
|
$ dot chain import my-chains.json --no-metadata
|
|
5051
5575
|
`.trimStart();
|
|
5052
5576
|
function registerChainCommands(cli) {
|
|
5053
|
-
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").option("-v, --verbose", "Show RPC endpoints in `chains` list output").action(async (action, names, opts) => {
|
|
5577
|
+
const command = 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").option("-v, --verbose", "Show RPC endpoints in `chains` list output").action(async (action, names, opts) => {
|
|
5054
5578
|
if (!action) {
|
|
5055
5579
|
if (process.argv[2] === "chains")
|
|
5056
5580
|
return chainList(opts);
|
|
@@ -5084,6 +5608,7 @@ function registerChainCommands(cli) {
|
|
|
5084
5608
|
}
|
|
5085
5609
|
}
|
|
5086
5610
|
});
|
|
5611
|
+
withHelp(command, () => console.log(CHAIN_HELP));
|
|
5087
5612
|
}
|
|
5088
5613
|
async function refreshRpcMethods(chainName, rpcUrl, silent = false) {
|
|
5089
5614
|
try {
|
|
@@ -5525,6 +6050,7 @@ async function chainImport(filePath, opts) {
|
|
|
5525
6050
|
}
|
|
5526
6051
|
|
|
5527
6052
|
// src/commands/completions.ts
|
|
6053
|
+
init_cli();
|
|
5528
6054
|
var ZSH_SCRIPT = `_dot_completions() {
|
|
5529
6055
|
emulate -L zsh
|
|
5530
6056
|
local -a completions
|
|
@@ -5593,19 +6119,20 @@ var SCRIPTS = {
|
|
|
5593
6119
|
fish: FISH_SCRIPT
|
|
5594
6120
|
};
|
|
5595
6121
|
function registerCompletionsCommand(cli) {
|
|
5596
|
-
cli.command("completions <shell>", "Generate shell completion script (zsh, bash, fish)").action((shell) => {
|
|
6122
|
+
const command = cli.command("completions <shell>", "Generate shell completion script (zsh, bash, fish)").action((shell) => {
|
|
5597
6123
|
const script = SCRIPTS[shell];
|
|
5598
6124
|
if (!script) {
|
|
5599
6125
|
console.error(`Unsupported shell "${shell}". Supported: ${Object.keys(SCRIPTS).join(", ")}`);
|
|
5600
6126
|
process.exit(1);
|
|
5601
6127
|
}
|
|
5602
6128
|
const instructions = SETUP_INSTRUCTIONS[shell];
|
|
5603
|
-
if (instructions) {
|
|
6129
|
+
if (instructions && process.stdout.isTTY) {
|
|
5604
6130
|
process.stderr.write(`${instructions}
|
|
5605
6131
|
`);
|
|
5606
6132
|
}
|
|
5607
6133
|
console.log(script);
|
|
5608
6134
|
});
|
|
6135
|
+
withHelp(command);
|
|
5609
6136
|
}
|
|
5610
6137
|
|
|
5611
6138
|
// src/commands/const.ts
|
|
@@ -6381,30 +6908,10 @@ async function handleExtensions(target, opts) {
|
|
|
6381
6908
|
|
|
6382
6909
|
// src/commands/hash.ts
|
|
6383
6910
|
init_hash();
|
|
6911
|
+
init_input();
|
|
6384
6912
|
init_output();
|
|
6913
|
+
init_cli();
|
|
6385
6914
|
init_errors();
|
|
6386
|
-
import { readFile as readFile5 } from "node:fs/promises";
|
|
6387
|
-
async function resolveInput(data, opts) {
|
|
6388
|
-
const sources = [data !== undefined, !!opts.file, !!opts.stdin].filter(Boolean).length;
|
|
6389
|
-
if (sources > 1) {
|
|
6390
|
-
throw new CliError("Provide only one of: inline data, --file, or --stdin");
|
|
6391
|
-
}
|
|
6392
|
-
if (sources === 0) {
|
|
6393
|
-
throw new CliError("No input provided. Pass data as argument, or use --file or --stdin");
|
|
6394
|
-
}
|
|
6395
|
-
if (opts.file) {
|
|
6396
|
-
const buf = await readFile5(opts.file);
|
|
6397
|
-
return new Uint8Array(buf);
|
|
6398
|
-
}
|
|
6399
|
-
if (opts.stdin) {
|
|
6400
|
-
const chunks = [];
|
|
6401
|
-
for await (const chunk of process.stdin) {
|
|
6402
|
-
chunks.push(chunk);
|
|
6403
|
-
}
|
|
6404
|
-
return new Uint8Array(Buffer.concat(chunks));
|
|
6405
|
-
}
|
|
6406
|
-
return parseInputData(data);
|
|
6407
|
-
}
|
|
6408
6915
|
function printAlgorithmHelp() {
|
|
6409
6916
|
console.log(`${BOLD}Usage:${RESET} dot hash <algorithm> <data> [options]
|
|
6410
6917
|
`);
|
|
@@ -6425,7 +6932,7 @@ ${BOLD}Examples:${RESET}`);
|
|
|
6425
6932
|
console.log(` ${DIM}$ echo -n "hello" | dot hash sha256 --stdin${RESET}`);
|
|
6426
6933
|
}
|
|
6427
6934
|
function registerHashCommand(cli) {
|
|
6428
|
-
cli.command("hash [algorithm] [data]", "Compute cryptographic hashes").option("--file <path>", "Hash file contents (raw bytes)").option("--stdin", "Read data from stdin").action(async (algorithm, data, opts) => {
|
|
6935
|
+
const command = cli.command("hash [algorithm] [data]", "Compute cryptographic hashes").option("--file <path>", "Hash file contents (raw bytes)").option("--stdin", "Read data from stdin").action(async (algorithm, data, opts) => {
|
|
6429
6936
|
if (!algorithm) {
|
|
6430
6937
|
printAlgorithmHelp();
|
|
6431
6938
|
return;
|
|
@@ -6433,7 +6940,7 @@ function registerHashCommand(cli) {
|
|
|
6433
6940
|
if (!isValidAlgorithm(algorithm)) {
|
|
6434
6941
|
throw new CliError(suggestMessage("algorithm", algorithm, getAlgorithmNames()));
|
|
6435
6942
|
}
|
|
6436
|
-
const input = await
|
|
6943
|
+
const input = await resolveDataInput(data, opts);
|
|
6437
6944
|
const hash = computeHash(algorithm, input);
|
|
6438
6945
|
const hexHash = toHex2(hash);
|
|
6439
6946
|
if (isJsonOutput(opts)) {
|
|
@@ -6446,6 +6953,7 @@ function registerHashCommand(cli) {
|
|
|
6446
6953
|
console.log(hexHash);
|
|
6447
6954
|
}
|
|
6448
6955
|
});
|
|
6956
|
+
withHelp(command, printAlgorithmHelp);
|
|
6449
6957
|
}
|
|
6450
6958
|
|
|
6451
6959
|
// src/commands/inspect.ts
|
|
@@ -6454,6 +6962,7 @@ init_client();
|
|
|
6454
6962
|
init_metadata();
|
|
6455
6963
|
init_output();
|
|
6456
6964
|
init_pretty_type();
|
|
6965
|
+
init_cli();
|
|
6457
6966
|
|
|
6458
6967
|
// src/utils/parse-target.ts
|
|
6459
6968
|
function parseTarget(input, options) {
|
|
@@ -6506,7 +7015,7 @@ function resolveTargetChain(target, chainFlag) {
|
|
|
6506
7015
|
|
|
6507
7016
|
// src/commands/inspect.ts
|
|
6508
7017
|
function registerInspectCommand(cli) {
|
|
6509
|
-
cli.command("inspect [target]", "Inspect chain metadata (pallets, storage, constants, calls, events, errors)").alias("explore").option("--chain <name>", "Target chain").option("--rpc <url>", "Override RPC endpoint").action(async (target, opts) => {
|
|
7018
|
+
const command = cli.command("inspect [target]", "Inspect chain metadata (pallets, storage, constants, calls, events, errors)").alias("explore").option("--chain <name>", "Target chain").option("--rpc <url>", "Override RPC endpoint").action(async (target, opts) => {
|
|
6510
7019
|
const config = await loadConfig();
|
|
6511
7020
|
const knownChains = Object.keys(config.chains);
|
|
6512
7021
|
let effectiveChain = opts.chain;
|
|
@@ -6874,6 +7383,7 @@ function registerInspectCommand(cli) {
|
|
|
6874
7383
|
];
|
|
6875
7384
|
throw new Error(suggestMessage(`item in ${pallet.name}`, itemName, allItems));
|
|
6876
7385
|
});
|
|
7386
|
+
withHelp(command);
|
|
6877
7387
|
}
|
|
6878
7388
|
|
|
6879
7389
|
// src/commands/metadata.ts
|
|
@@ -6881,6 +7391,7 @@ init_store();
|
|
|
6881
7391
|
init_client();
|
|
6882
7392
|
init_metadata();
|
|
6883
7393
|
init_output();
|
|
7394
|
+
init_cli();
|
|
6884
7395
|
init_errors();
|
|
6885
7396
|
function buildMetadataPayload(chainName, meta, fingerprint) {
|
|
6886
7397
|
return {
|
|
@@ -6923,12 +7434,14 @@ async function handleMetadata(chain, opts) {
|
|
|
6923
7434
|
`);
|
|
6924
7435
|
}
|
|
6925
7436
|
function registerMetadataCommand(cli) {
|
|
6926
|
-
cli.command("metadata <chain>", "Fetch chain metadata (decoded JSON; --raw for SCALE hex)").option("--raw", "Print SCALE-encoded metadata bytes as hex instead of decoded JSON").option("--cached", "Use cached metadata instead of fetching fresh from the chain").option("--rpc <url>", "Override RPC endpoint(s)").action((chain, opts) => handleMetadata(chain, opts));
|
|
7437
|
+
const command = cli.command("metadata <chain>", "Fetch chain metadata (decoded JSON; --raw for SCALE hex)").option("--raw", "Print SCALE-encoded metadata bytes as hex instead of decoded JSON").option("--cached", "Use cached metadata instead of fetching fresh from the chain").option("--rpc <url>", "Override RPC endpoint(s)").action((chain, opts) => handleMetadata(chain, opts));
|
|
7438
|
+
withHelp(command);
|
|
6927
7439
|
}
|
|
6928
7440
|
|
|
6929
7441
|
// src/commands/parachain.ts
|
|
6930
7442
|
init_accounts();
|
|
6931
7443
|
init_output();
|
|
7444
|
+
init_cli();
|
|
6932
7445
|
init_errors();
|
|
6933
7446
|
function printParachainHelp() {
|
|
6934
7447
|
console.log(`${BOLD}Usage:${RESET} dot parachain <paraId> [options]
|
|
@@ -6957,7 +7470,7 @@ function validateType(type) {
|
|
|
6957
7470
|
throw new CliError(`Unknown account type "${type}". Valid types: child, sibling.`);
|
|
6958
7471
|
}
|
|
6959
7472
|
function registerParachainCommand(cli) {
|
|
6960
|
-
cli.command("parachain [paraId]", "Derive parachain sovereign accounts").option("--type <type>", "Account type: child, sibling (default: both)").option("--prefix <number>", "SS58 prefix for address encoding (default: 42)").action(async (paraIdStr, opts) => {
|
|
7473
|
+
const command = cli.command("parachain [paraId]", "Derive parachain sovereign accounts").option("--type <type>", "Account type: child, sibling (default: both)").option("--prefix <number>", "SS58 prefix for address encoding (default: 42)").action(async (paraIdStr, opts) => {
|
|
6961
7474
|
console.error("Warning: `dot parachain` is deprecated; use `dot account inspect --parachain <id> --parachain-type <child|sibling>` instead. Will be removed in a future release.");
|
|
6962
7475
|
if (!paraIdStr) {
|
|
6963
7476
|
printParachainHelp();
|
|
@@ -6997,6 +7510,7 @@ function registerParachainCommand(cli) {
|
|
|
6997
7510
|
}
|
|
6998
7511
|
}
|
|
6999
7512
|
});
|
|
7513
|
+
withHelp(command, printParachainHelp);
|
|
7000
7514
|
}
|
|
7001
7515
|
|
|
7002
7516
|
// src/commands/query.ts
|
|
@@ -7339,9 +7853,10 @@ async function handleRpc(method, args, opts) {
|
|
|
7339
7853
|
// src/commands/sign.ts
|
|
7340
7854
|
init_accounts();
|
|
7341
7855
|
init_hash();
|
|
7856
|
+
init_input();
|
|
7342
7857
|
init_output();
|
|
7858
|
+
init_cli();
|
|
7343
7859
|
init_errors();
|
|
7344
|
-
import { readFile as readFile6 } from "node:fs/promises";
|
|
7345
7860
|
var SUPPORTED_TYPES = ["sr25519"];
|
|
7346
7861
|
function isSupportedType(type) {
|
|
7347
7862
|
return SUPPORTED_TYPES.includes(type.toLowerCase());
|
|
@@ -7352,27 +7867,6 @@ function variantName(type) {
|
|
|
7352
7867
|
return "Sr25519";
|
|
7353
7868
|
}
|
|
7354
7869
|
}
|
|
7355
|
-
async function resolveInput2(data, opts) {
|
|
7356
|
-
const sources = [data !== undefined, !!opts.file, !!opts.stdin].filter(Boolean).length;
|
|
7357
|
-
if (sources > 1) {
|
|
7358
|
-
throw new CliError("Provide only one of: inline data, --file, or --stdin");
|
|
7359
|
-
}
|
|
7360
|
-
if (sources === 0) {
|
|
7361
|
-
throw new CliError("No input provided. Pass data as argument, or use --file or --stdin");
|
|
7362
|
-
}
|
|
7363
|
-
if (opts.file) {
|
|
7364
|
-
const buf = await readFile6(opts.file);
|
|
7365
|
-
return new Uint8Array(buf);
|
|
7366
|
-
}
|
|
7367
|
-
if (opts.stdin) {
|
|
7368
|
-
const chunks = [];
|
|
7369
|
-
for await (const chunk of process.stdin) {
|
|
7370
|
-
chunks.push(chunk);
|
|
7371
|
-
}
|
|
7372
|
-
return new Uint8Array(Buffer.concat(chunks));
|
|
7373
|
-
}
|
|
7374
|
-
return parseInputData(data);
|
|
7375
|
-
}
|
|
7376
7870
|
function printSignHelp() {
|
|
7377
7871
|
console.log(`${BOLD}Usage:${RESET} dot sign <message> --from <account> [options]
|
|
7378
7872
|
`);
|
|
@@ -7394,7 +7888,7 @@ ${BOLD}Examples:${RESET}`);
|
|
|
7394
7888
|
console.log(` ${DIM}$ dot sign "hello" --from alice --output json${RESET}`);
|
|
7395
7889
|
}
|
|
7396
7890
|
function registerSignCommand(cli) {
|
|
7397
|
-
cli.command("sign [message]", "Sign a message with an account keypair").option("--from <name>", "Account to sign with").option("--type <algo>", "Signature type (default: sr25519)").option("--file <path>", "Sign file contents (raw bytes)").option("--stdin", "Read data from stdin").action(async (message, opts) => {
|
|
7891
|
+
const command = cli.command("sign [message]", "Sign a message with an account keypair").option("--from <name>", "Account to sign with").option("--type <algo>", "Signature type (default: sr25519)").option("--file <path>", "Sign file contents (raw bytes)").option("--stdin", "Read data from stdin").action(async (message, opts) => {
|
|
7398
7892
|
if (!message && !opts.file && !opts.stdin) {
|
|
7399
7893
|
printSignHelp();
|
|
7400
7894
|
return;
|
|
@@ -7406,7 +7900,7 @@ function registerSignCommand(cli) {
|
|
|
7406
7900
|
if (!isSupportedType(type)) {
|
|
7407
7901
|
throw new CliError(`Unsupported signature type "${opts.type}". Supported: ${SUPPORTED_TYPES.join(", ")}`);
|
|
7408
7902
|
}
|
|
7409
|
-
const input = await
|
|
7903
|
+
const input = await resolveDataInput(message, opts);
|
|
7410
7904
|
const keypair = await resolveAccountKeypair(opts.from);
|
|
7411
7905
|
const signature = keypair.sign(input);
|
|
7412
7906
|
const hexMessage = toHex2(input);
|
|
@@ -7428,6 +7922,7 @@ function registerSignCommand(cli) {
|
|
|
7428
7922
|
console.log(` ${BOLD}Enum:${RESET} ${result.enum}`);
|
|
7429
7923
|
}
|
|
7430
7924
|
});
|
|
7925
|
+
withHelp(command, printSignHelp);
|
|
7431
7926
|
}
|
|
7432
7927
|
|
|
7433
7928
|
// src/commands/tx.ts
|
|
@@ -8778,7 +9273,7 @@ function buildGeneralTx(meta, callData, userExtOverrides) {
|
|
|
8778
9273
|
}
|
|
8779
9274
|
function watchTransaction(observable, level, options) {
|
|
8780
9275
|
const spinner = new Spinner;
|
|
8781
|
-
return new Promise((
|
|
9276
|
+
return new Promise((resolve2, reject) => {
|
|
8782
9277
|
let settled = false;
|
|
8783
9278
|
spinner.start(options?.unsigned ? "Submitting..." : "Signing...");
|
|
8784
9279
|
const subscription = observable.subscribe({
|
|
@@ -8798,7 +9293,7 @@ function watchTransaction(observable, level, options) {
|
|
|
8798
9293
|
spinner.succeed("Broadcasted");
|
|
8799
9294
|
settled = true;
|
|
8800
9295
|
subscription.unsubscribe();
|
|
8801
|
-
|
|
9296
|
+
resolve2(event);
|
|
8802
9297
|
} else {
|
|
8803
9298
|
spinner.succeed("Broadcasted");
|
|
8804
9299
|
spinner.start("In best block...");
|
|
@@ -8810,7 +9305,7 @@ function watchTransaction(observable, level, options) {
|
|
|
8810
9305
|
spinner.succeed(`In best block #${event.block.number}`);
|
|
8811
9306
|
settled = true;
|
|
8812
9307
|
subscription.unsubscribe();
|
|
8813
|
-
|
|
9308
|
+
resolve2(event);
|
|
8814
9309
|
} else {
|
|
8815
9310
|
spinner.succeed(`In best block #${event.block.number}`);
|
|
8816
9311
|
spinner.start("Finalizing...");
|
|
@@ -8822,7 +9317,7 @@ function watchTransaction(observable, level, options) {
|
|
|
8822
9317
|
case "finalized":
|
|
8823
9318
|
spinner.succeed(`Finalized in block #${event.block.number}`);
|
|
8824
9319
|
settled = true;
|
|
8825
|
-
|
|
9320
|
+
resolve2(event);
|
|
8826
9321
|
break;
|
|
8827
9322
|
}
|
|
8828
9323
|
},
|
|
@@ -8836,7 +9331,7 @@ function watchTransaction(observable, level, options) {
|
|
|
8836
9331
|
});
|
|
8837
9332
|
}
|
|
8838
9333
|
function watchTransactionJson(observable, level, options) {
|
|
8839
|
-
return new Promise((
|
|
9334
|
+
return new Promise((resolve2, reject) => {
|
|
8840
9335
|
let settled = false;
|
|
8841
9336
|
const subscription = observable.subscribe({
|
|
8842
9337
|
next(event) {
|
|
@@ -8853,7 +9348,7 @@ function watchTransactionJson(observable, level, options) {
|
|
|
8853
9348
|
if (level === "broadcast") {
|
|
8854
9349
|
settled = true;
|
|
8855
9350
|
subscription.unsubscribe();
|
|
8856
|
-
|
|
9351
|
+
resolve2(event);
|
|
8857
9352
|
}
|
|
8858
9353
|
break;
|
|
8859
9354
|
case "txBestBlocksState":
|
|
@@ -8862,13 +9357,13 @@ function watchTransactionJson(observable, level, options) {
|
|
|
8862
9357
|
if (level === "best-block") {
|
|
8863
9358
|
settled = true;
|
|
8864
9359
|
subscription.unsubscribe();
|
|
8865
|
-
|
|
9360
|
+
resolve2(event);
|
|
8866
9361
|
}
|
|
8867
9362
|
}
|
|
8868
9363
|
break;
|
|
8869
9364
|
case "finalized":
|
|
8870
9365
|
settled = true;
|
|
8871
|
-
|
|
9366
|
+
resolve2(event);
|
|
8872
9367
|
break;
|
|
8873
9368
|
}
|
|
8874
9369
|
},
|
|
@@ -8881,119 +9376,94 @@ function watchTransactionJson(observable, level, options) {
|
|
|
8881
9376
|
});
|
|
8882
9377
|
}
|
|
8883
9378
|
|
|
8884
|
-
// src/commands/
|
|
8885
|
-
|
|
8886
|
-
|
|
8887
|
-
init_bandersnatch();
|
|
9379
|
+
// src/commands/workspace.ts
|
|
9380
|
+
init_store();
|
|
9381
|
+
init_workspace();
|
|
8888
9382
|
init_output();
|
|
8889
|
-
|
|
8890
|
-
|
|
8891
|
-
|
|
8892
|
-
|
|
8893
|
-
|
|
8894
|
-
|
|
8895
|
-
|
|
8896
|
-
|
|
8897
|
-
${
|
|
8898
|
-
--context <value> Blake2b context for keyed derivation (e.g. "candidate")
|
|
8899
|
-
|
|
8900
|
-
${BOLD}Examples:${RESET}
|
|
8901
|
-
$ dot verifiable alice Unkeyed derivation (lite person)
|
|
8902
|
-
$ dot verifiable alice --context candidate Keyed with "candidate" (full person)
|
|
8903
|
-
$ dot verifiable my-account --context candidate
|
|
8904
|
-
|
|
8905
|
-
${BOLD}How it works:${RESET}
|
|
8906
|
-
|
|
8907
|
-
Mnemonic (12/24 words)
|
|
8908
|
-
│ mnemonicToEntropy() (raw BIP39 entropy, NOT miniSecret)
|
|
8909
|
-
▼
|
|
8910
|
-
blake2b256(entropy, context?) keyed or unkeyed
|
|
8911
|
-
▼
|
|
8912
|
-
member_from_entropy() verifiablejs WASM (Bandersnatch curve)
|
|
8913
|
-
▼
|
|
8914
|
-
32-byte member key for on-chain member set registration
|
|
8915
|
-
`.trimStart();
|
|
8916
|
-
function registerVerifiableCommands(cli) {
|
|
8917
|
-
cli.command("verifiable [account]", "Derive Bandersnatch member key from account mnemonic").option("--context <value>", "Blake2b context for keyed derivation (e.g. candidate)").action(async (account, opts) => {
|
|
8918
|
-
if (!account) {
|
|
8919
|
-
console.log(VERIFIABLE_HELP);
|
|
8920
|
-
return;
|
|
8921
|
-
}
|
|
8922
|
-
return deriveVerifiable(account, opts);
|
|
8923
|
-
});
|
|
8924
|
-
}
|
|
8925
|
-
async function deriveVerifiable(account, opts) {
|
|
8926
|
-
const mnemonic = await resolveMnemonic(account);
|
|
8927
|
-
const memberKey = deriveBandersnatchMember(mnemonic, opts.context);
|
|
8928
|
-
const memberKeyHex = publicKeyToHex(memberKey);
|
|
8929
|
-
if (!isDevAccount(account)) {
|
|
8930
|
-
const accountsFile = await loadAccounts();
|
|
8931
|
-
const stored = findAccount(accountsFile, account);
|
|
8932
|
-
if (stored) {
|
|
8933
|
-
if (!stored.bandersnatch)
|
|
8934
|
-
stored.bandersnatch = {};
|
|
8935
|
-
stored.bandersnatch[opts.context ?? ""] = memberKeyHex;
|
|
8936
|
-
await saveAccounts(accountsFile);
|
|
8937
|
-
}
|
|
9383
|
+
init_cli();
|
|
9384
|
+
init_errors();
|
|
9385
|
+
import { mkdir as mkdir3, stat } from "node:fs/promises";
|
|
9386
|
+
import { homedir as homedir3 } from "node:os";
|
|
9387
|
+
import { join as join4 } from "node:path";
|
|
9388
|
+
async function initWorkspace(cwd, home = homedir3()) {
|
|
9389
|
+
const dir = canonicalPath(cwd);
|
|
9390
|
+
if (dir === canonicalPath(home)) {
|
|
9391
|
+
throw new CliError(`Cannot initialize a workspace in your home directory — ${join4(dir, WORKSPACE_DIR_NAME)} is the global config root.`);
|
|
8938
9392
|
}
|
|
8939
|
-
|
|
8940
|
-
|
|
8941
|
-
|
|
8942
|
-
|
|
8943
|
-
};
|
|
8944
|
-
if (opts.context)
|
|
8945
|
-
result.context = opts.context;
|
|
8946
|
-
console.log(formatJson(result));
|
|
8947
|
-
} else {
|
|
8948
|
-
printHeading("Bandersnatch Member Key");
|
|
8949
|
-
console.log(` ${BOLD}Account:${RESET} ${account}`);
|
|
8950
|
-
if (opts.context)
|
|
8951
|
-
console.log(` ${BOLD}Context:${RESET} ${opts.context}`);
|
|
8952
|
-
console.log(` ${BOLD}Member Key:${RESET} ${memberKeyHex}`);
|
|
8953
|
-
console.log();
|
|
9393
|
+
const workspacePath = join4(dir, WORKSPACE_DIR_NAME);
|
|
9394
|
+
const exists = await stat(workspacePath).then(() => true).catch(() => false);
|
|
9395
|
+
if (exists) {
|
|
9396
|
+
throw new CliError(`A workspace already exists at ${workspacePath}.`);
|
|
8954
9397
|
}
|
|
8955
|
-
|
|
8956
|
-
|
|
8957
|
-
if (
|
|
8958
|
-
|
|
9398
|
+
const warnings = [];
|
|
9399
|
+
const parentWorkspace = findWorkspace(dir, home);
|
|
9400
|
+
if (parentWorkspace) {
|
|
9401
|
+
warnings.push(`This workspace shadows ${parentWorkspace} for commands run below ${dir}.`);
|
|
8959
9402
|
}
|
|
8960
|
-
const
|
|
8961
|
-
|
|
8962
|
-
|
|
8963
|
-
const available = [...DEV_NAMES, ...accountsFile.accounts.map((a) => a.name)].sort((a, b) => a.localeCompare(b));
|
|
8964
|
-
const suggestions = findClosest(account, available);
|
|
8965
|
-
const hint = suggestions.length > 0 ? `
|
|
8966
|
-
Did you mean: ${suggestions.join(", ")}?` : "";
|
|
8967
|
-
const list = available.map((a) => `
|
|
8968
|
-
- ${a}`).join("");
|
|
8969
|
-
throw new Error(`Unknown account "${account}".${hint}
|
|
8970
|
-
Available accounts:${list}`);
|
|
9403
|
+
const dotHome = process.env.DOT_HOME;
|
|
9404
|
+
if (dotHome && dotHome.length > 0) {
|
|
9405
|
+
warnings.push(`DOT_HOME is set (${dotHome}) and takes precedence — this workspace will not be picked up until you unset it.`);
|
|
8971
9406
|
}
|
|
8972
|
-
|
|
8973
|
-
|
|
9407
|
+
await mkdir3(workspacePath, { recursive: true });
|
|
9408
|
+
return { workspacePath, warnings };
|
|
9409
|
+
}
|
|
9410
|
+
var SOURCE_LABELS = {
|
|
9411
|
+
env: "DOT_HOME environment variable",
|
|
9412
|
+
workspace: "local workspace (discovered from current directory)",
|
|
9413
|
+
global: "global config"
|
|
9414
|
+
};
|
|
9415
|
+
async function handleInit(cwd = process.cwd()) {
|
|
9416
|
+
const result = await initWorkspace(cwd);
|
|
9417
|
+
for (const warning of result.warnings) {
|
|
9418
|
+
process.stderr.write(`Warning: ${warning}
|
|
9419
|
+
`);
|
|
8974
9420
|
}
|
|
8975
|
-
|
|
8976
|
-
|
|
8977
|
-
|
|
9421
|
+
await writeStdout(`Initialized empty dot workspace at ${result.workspacePath}
|
|
9422
|
+
` + `Check which workspace is active with: dot which
|
|
9423
|
+
`);
|
|
9424
|
+
}
|
|
9425
|
+
async function handleWhich(opts, cwd = process.cwd()) {
|
|
9426
|
+
const resolved = resolveConfigDir(cwd);
|
|
9427
|
+
if (isJsonOutput(opts)) {
|
|
9428
|
+
await writeStdout(`${JSON.stringify({ path: resolved.path, source: resolved.source })}
|
|
9429
|
+
`);
|
|
9430
|
+
return;
|
|
8978
9431
|
}
|
|
8979
|
-
|
|
9432
|
+
await writeStdout(`${resolved.path}
|
|
9433
|
+
Source: ${SOURCE_LABELS[resolved.source]}
|
|
9434
|
+
`);
|
|
9435
|
+
}
|
|
9436
|
+
function registerWorkspaceCommands(cli) {
|
|
9437
|
+
const initCommand = cli.command("init", "Initialize a local .polkadot workspace in the current directory").action(() => handleInit());
|
|
9438
|
+
withHelp(initCommand);
|
|
9439
|
+
const whichCommand = cli.command("which", "Show the active config root (workspace, DOT_HOME, or global)").action((opts) => handleWhich(opts));
|
|
9440
|
+
withHelp(whichCommand);
|
|
8980
9441
|
}
|
|
8981
9442
|
|
|
8982
9443
|
// src/config/store.ts
|
|
8983
9444
|
init_errors();
|
|
8984
9445
|
init_types();
|
|
8985
|
-
|
|
8986
|
-
import {
|
|
8987
|
-
import {
|
|
8988
|
-
|
|
9446
|
+
init_workspace();
|
|
9447
|
+
import { access as access3, mkdir as mkdir4, readFile as readFile6, rm as rm2, writeFile as writeFile5 } from "node:fs/promises";
|
|
9448
|
+
import { homedir as homedir4 } from "node:os";
|
|
9449
|
+
import { join as join5 } from "node:path";
|
|
9450
|
+
function resolveConfigDir2(cwd = process.cwd()) {
|
|
8989
9451
|
const override = process.env.DOT_HOME;
|
|
8990
|
-
|
|
9452
|
+
if (override && override.length > 0)
|
|
9453
|
+
return { path: override, source: "env" };
|
|
9454
|
+
const workspace = findWorkspace(cwd);
|
|
9455
|
+
if (workspace)
|
|
9456
|
+
return { path: workspace, source: "workspace" };
|
|
9457
|
+
return { path: join5(homedir4(), ".polkadot"), source: "global" };
|
|
9458
|
+
}
|
|
9459
|
+
function getConfigDir2() {
|
|
9460
|
+
return resolveConfigDir2().path;
|
|
8991
9461
|
}
|
|
8992
9462
|
function getConfigPath2() {
|
|
8993
|
-
return
|
|
9463
|
+
return join5(getConfigDir2(), "config.json");
|
|
8994
9464
|
}
|
|
8995
9465
|
async function ensureDir3(dir) {
|
|
8996
|
-
await
|
|
9466
|
+
await mkdir4(dir, { recursive: true });
|
|
8997
9467
|
}
|
|
8998
9468
|
async function fileExists3(path) {
|
|
8999
9469
|
try {
|
|
@@ -9007,7 +9477,7 @@ async function loadConfig2() {
|
|
|
9007
9477
|
await ensureDir3(getConfigDir2());
|
|
9008
9478
|
const configPath = getConfigPath2();
|
|
9009
9479
|
if (await fileExists3(configPath)) {
|
|
9010
|
-
const saved = JSON.parse(await
|
|
9480
|
+
const saved = JSON.parse(await readFile6(configPath, "utf-8"));
|
|
9011
9481
|
const chains = {};
|
|
9012
9482
|
for (const [name, defaultConfig] of Object.entries(DEFAULT_CONFIG.chains)) {
|
|
9013
9483
|
chains[name] = saved.chains[name] ? { ...defaultConfig, ...saved.chains[name] } : defaultConfig;
|
|
@@ -9028,9 +9498,33 @@ async function saveConfig2(config) {
|
|
|
9028
9498
|
`);
|
|
9029
9499
|
}
|
|
9030
9500
|
|
|
9501
|
+
// src/core/dry-run.ts
|
|
9502
|
+
init_output();
|
|
9503
|
+
function isGlobalDryRun() {
|
|
9504
|
+
const raw = process.env.DOT_DRY_RUN?.trim().toLowerCase();
|
|
9505
|
+
if (raw === undefined || raw === "")
|
|
9506
|
+
return false;
|
|
9507
|
+
return raw === "1" || raw === "true" || raw === "yes" || raw === "on";
|
|
9508
|
+
}
|
|
9509
|
+
function resolveDryRun(explicitFlag, decodeOnly = false) {
|
|
9510
|
+
if (explicitFlag !== undefined)
|
|
9511
|
+
return explicitFlag;
|
|
9512
|
+
if (decodeOnly)
|
|
9513
|
+
return false;
|
|
9514
|
+
return isGlobalDryRun();
|
|
9515
|
+
}
|
|
9516
|
+
var hintPrinted = false;
|
|
9517
|
+
function printGlobalDryRunHint() {
|
|
9518
|
+
if (hintPrinted)
|
|
9519
|
+
return;
|
|
9520
|
+
hintPrinted = true;
|
|
9521
|
+
process.stderr.write(`${YELLOW}${BOLD}⚠ DOT_DRY_RUN is set${RESET}${YELLOW} — extrinsics will be simulated, not submitted.${RESET}
|
|
9522
|
+
`);
|
|
9523
|
+
}
|
|
9524
|
+
|
|
9031
9525
|
// src/core/file-loader.ts
|
|
9032
9526
|
init_errors();
|
|
9033
|
-
import { access as access4, readFile as
|
|
9527
|
+
import { access as access4, readFile as readFile7 } from "node:fs/promises";
|
|
9034
9528
|
import { parse as parseYaml } from "yaml";
|
|
9035
9529
|
var CATEGORIES = ["tx", "query", "const", "apis"];
|
|
9036
9530
|
var FILE_EXTENSIONS = [".json", ".yaml", ".yml"];
|
|
@@ -9095,7 +9589,7 @@ async function loadCommandFile(filePath, cliVars) {
|
|
|
9095
9589
|
} catch {
|
|
9096
9590
|
throw new CliError(`File not found: ${filePath}`);
|
|
9097
9591
|
}
|
|
9098
|
-
const rawText = await
|
|
9592
|
+
const rawText = await readFile7(filePath, "utf-8");
|
|
9099
9593
|
if (!rawText.trim()) {
|
|
9100
9594
|
throw new CliError(`File is empty: ${filePath}`);
|
|
9101
9595
|
}
|
|
@@ -9167,8 +9661,8 @@ async function loadCommandFile(filePath, cliVars) {
|
|
|
9167
9661
|
// src/core/update-notifier.ts
|
|
9168
9662
|
init_store();
|
|
9169
9663
|
import { readFileSync } from "node:fs";
|
|
9170
|
-
import { mkdir as
|
|
9171
|
-
import { join as
|
|
9664
|
+
import { mkdir as mkdir5, writeFile as writeFile6 } from "node:fs/promises";
|
|
9665
|
+
import { join as join6 } from "node:path";
|
|
9172
9666
|
var CACHE_FILE = "update-check.json";
|
|
9173
9667
|
var STALE_MS = 24 * 60 * 60 * 1000;
|
|
9174
9668
|
var FETCH_TIMEOUT_MS = 5000;
|
|
@@ -9224,7 +9718,7 @@ function buildNotificationBox(current, latest) {
|
|
|
9224
9718
|
`);
|
|
9225
9719
|
}
|
|
9226
9720
|
function getCachePath() {
|
|
9227
|
-
return
|
|
9721
|
+
return join6(getConfigDir(), CACHE_FILE);
|
|
9228
9722
|
}
|
|
9229
9723
|
function readCache() {
|
|
9230
9724
|
try {
|
|
@@ -9236,7 +9730,7 @@ function readCache() {
|
|
|
9236
9730
|
}
|
|
9237
9731
|
async function writeCache(cache) {
|
|
9238
9732
|
try {
|
|
9239
|
-
await
|
|
9733
|
+
await mkdir5(getConfigDir(), { recursive: true });
|
|
9240
9734
|
await writeFile6(getCachePath(), `${JSON.stringify(cache)}
|
|
9241
9735
|
`);
|
|
9242
9736
|
} catch {}
|
|
@@ -9264,7 +9758,7 @@ function startBackgroundCheck(currentVersion) {
|
|
|
9264
9758
|
async function waitForPendingCheck() {
|
|
9265
9759
|
if (!pendingCheck)
|
|
9266
9760
|
return;
|
|
9267
|
-
const timeout = new Promise((
|
|
9761
|
+
const timeout = new Promise((resolve2) => setTimeout(resolve2, EXIT_WAIT_TIMEOUT_MS));
|
|
9268
9762
|
await Promise.race([pendingCheck.catch(() => {}), timeout]);
|
|
9269
9763
|
pendingCheck = null;
|
|
9270
9764
|
}
|
|
@@ -9284,6 +9778,127 @@ function getUpdateNotification(currentVersion) {
|
|
|
9284
9778
|
return null;
|
|
9285
9779
|
}
|
|
9286
9780
|
|
|
9781
|
+
// src/features/verifiable/register.ts
|
|
9782
|
+
init_platform();
|
|
9783
|
+
var VERIFIABLE_HELP = `
|
|
9784
|
+
${BOLD}Usage:${RESET}
|
|
9785
|
+
$ dot verifiable [account] [--entropy-key <key>] Derive the member key (default action)
|
|
9786
|
+
$ dot verifiable <action> [account] [options]
|
|
9787
|
+
|
|
9788
|
+
${BOLD}Actions:${RESET}
|
|
9789
|
+
member <account> Derive the Bandersnatch member key (default if omitted)
|
|
9790
|
+
alias <account> Derive the alias for a 32-byte ring context
|
|
9791
|
+
sign <account> Standalone Bandersnatch signature (64 bytes)
|
|
9792
|
+
prove <account> Ring-VRF proof (one_shot) over a members set
|
|
9793
|
+
verify Locally verify a ring-VRF proof against members/root
|
|
9794
|
+
verify-sig Verify a standalone Bandersnatch signature
|
|
9795
|
+
members <key…> SCALE-encode member keys as Vec<[u8;32]>
|
|
9796
|
+
|
|
9797
|
+
verify / verify-sig exit non-zero on failure (the verdict is the exit code);
|
|
9798
|
+
on success they print the recovered alias / {"valid":true}.
|
|
9799
|
+
|
|
9800
|
+
${BOLD}Key concepts (do not conflate these):${RESET}
|
|
9801
|
+
--entropy-key <text|0xhex>
|
|
9802
|
+
Key mixed into the keyed-blake2b that turns your mnemonic into the
|
|
9803
|
+
Bandersnatch member entropy. Omit for a ${BOLD}lite${RESET} person (unkeyed);
|
|
9804
|
+
use "candidate" for a ${BOLD}full${RESET} person. Must match the key used when the
|
|
9805
|
+
member was recognised on-chain, or you derive a different (unrecognised)
|
|
9806
|
+
member key. It is NOT a derivation path and NOT the ring --context.
|
|
9807
|
+
--context <text|0xhex>
|
|
9808
|
+
The 32-byte ring/proof namespace (e.g. "dotns"), zero-padded right to 32
|
|
9809
|
+
bytes like Solidity bytes32(). Determines the alias. Used by alias/prove/verify.
|
|
9810
|
+
|
|
9811
|
+
${BOLD}Options:${RESET}
|
|
9812
|
+
--entropy-key <key> Entropy-derivation key (see above)
|
|
9813
|
+
--context <value> 32-byte ring context (alias/prove/verify)
|
|
9814
|
+
--message <data> Message to sign / bind / verify (text or 0x hex)
|
|
9815
|
+
--file <path> Read the message from a file (raw bytes)
|
|
9816
|
+
--stdin Read the message from stdin
|
|
9817
|
+
--members <hex|file> SCALE-encoded Vec<[u8;32]> ring (prove/verify)
|
|
9818
|
+
--root <hex> 768-byte ring root / commitment (verify)
|
|
9819
|
+
--proof <hex> Ring-VRF proof bytes (verify)
|
|
9820
|
+
--signature <hex> Bandersnatch signature (verify-sig)
|
|
9821
|
+
--member <hex> 32-byte member public key (verify-sig)
|
|
9822
|
+
--ring-exponent <n> Ring exponent: 9 (default), 10, or 14
|
|
9823
|
+
--output json Output as JSON
|
|
9824
|
+
|
|
9825
|
+
${BOLD}Examples:${RESET}
|
|
9826
|
+
$ dot verifiable alice Lite member key
|
|
9827
|
+
$ dot verifiable alice --entropy-key candidate Full member key
|
|
9828
|
+
$ dot verifiable alias alice --entropy-key candidate --context dotns
|
|
9829
|
+
$ dot verifiable sign alice --message "hello" --entropy-key candidate
|
|
9830
|
+
$ dot verifiable prove alice --entropy-key candidate --context dotns \\
|
|
9831
|
+
--message 0x… --members 0x…
|
|
9832
|
+
$ dot verifiable verify --proof 0x… --context dotns --message 0x… --members 0x…
|
|
9833
|
+
$ dot verifiable members 0x… 0x…
|
|
9834
|
+
|
|
9835
|
+
${BOLD}Derivation flow:${RESET}
|
|
9836
|
+
|
|
9837
|
+
Mnemonic ─BIP39─▶ entropy ─keyed blake2b─▶ member entropy ─▶ member key / secret
|
|
9838
|
+
(key = --entropy-key) │
|
|
9839
|
+
ring proof: one_shot(…, --context, --message)
|
|
9840
|
+
`.trimStart();
|
|
9841
|
+
var RAW_STRING_FLAGS = [
|
|
9842
|
+
["entropy-key", "entropyKey"],
|
|
9843
|
+
["context", "context"],
|
|
9844
|
+
["message", "message"],
|
|
9845
|
+
["members", "members"],
|
|
9846
|
+
["root", "root"],
|
|
9847
|
+
["proof", "proof"],
|
|
9848
|
+
["signature", "signature"],
|
|
9849
|
+
["member", "member"]
|
|
9850
|
+
];
|
|
9851
|
+
function registerVerifiableCommands(cli) {
|
|
9852
|
+
const command = cli.command("verifiable [action] [...rest]", "Bandersnatch member keys, ring-VRF proofs, signing and verification").option("--entropy-key <key>", "Entropy-derivation key (omit = lite, 'candidate' = full)").option("--context <value>", "32-byte ring/proof context (alias/prove/verify)").option("--message <data>", "Message to sign/bind/verify (text or 0x hex)").option("--file <path>", "Read message from a file (raw bytes)").option("--stdin", "Read message from stdin").option("--members <hex|file>", "SCALE-encoded Vec<[u8;32]> ring (prove/verify)").option("--root <hex>", "768-byte ring root/commitment (verify)").option("--proof <hex>", "Ring-VRF proof bytes (verify)").option("--signature <hex>", "Bandersnatch signature (verify-sig)").option("--member <hex>", "32-byte member public key (verify-sig)").option("--ring-exponent <n>", "Ring exponent: 9 (default), 10, or 14").action(async (action, rest, opts) => {
|
|
9853
|
+
if (!action) {
|
|
9854
|
+
console.log(VERIFIABLE_HELP);
|
|
9855
|
+
return;
|
|
9856
|
+
}
|
|
9857
|
+
for (const [flag, key] of RAW_STRING_FLAGS) {
|
|
9858
|
+
const raw = readRawOptionValue(flag);
|
|
9859
|
+
if (raw !== undefined)
|
|
9860
|
+
opts[key] = raw;
|
|
9861
|
+
}
|
|
9862
|
+
const { runVerifiable: runVerifiable2 } = await Promise.resolve().then(() => (init_commands(), exports_commands));
|
|
9863
|
+
return runVerifiable2(action, rest, opts);
|
|
9864
|
+
});
|
|
9865
|
+
withHelp(command, () => console.log(VERIFIABLE_HELP));
|
|
9866
|
+
}
|
|
9867
|
+
|
|
9868
|
+
// src/platform/cli.ts
|
|
9869
|
+
var HELP_PRINTER2 = Symbol.for("polkadot-cli.helpPrinter");
|
|
9870
|
+
function printMatchedCommandHelp(cli) {
|
|
9871
|
+
const matched = cli.matchedCommand;
|
|
9872
|
+
const printer = matched?.[HELP_PRINTER2];
|
|
9873
|
+
if (!printer)
|
|
9874
|
+
return false;
|
|
9875
|
+
printer();
|
|
9876
|
+
return true;
|
|
9877
|
+
}
|
|
9878
|
+
function registerGlobalOptions(cli) {
|
|
9879
|
+
cli.option("--chain <name>", "Target chain (required)");
|
|
9880
|
+
cli.option("--rpc <url>", "Override RPC endpoint for this call");
|
|
9881
|
+
cli.option("--output <format>", "Output format: pretty or json", {
|
|
9882
|
+
default: "pretty"
|
|
9883
|
+
});
|
|
9884
|
+
cli.option("--json", "Output as JSON (shorthand for --output json)");
|
|
9885
|
+
}
|
|
9886
|
+
function readRawOptionValue2(name, argv = process.argv) {
|
|
9887
|
+
const flag = `--${name}`;
|
|
9888
|
+
const prefix = `${flag}=`;
|
|
9889
|
+
let value;
|
|
9890
|
+
for (let i = 0;i < argv.length; i++) {
|
|
9891
|
+
const arg = argv[i];
|
|
9892
|
+
if (arg === "--")
|
|
9893
|
+
break;
|
|
9894
|
+
if (arg === flag && i + 1 < argv.length)
|
|
9895
|
+
value = argv[i + 1];
|
|
9896
|
+
else if (arg.startsWith(prefix))
|
|
9897
|
+
value = arg.slice(prefix.length);
|
|
9898
|
+
}
|
|
9899
|
+
return value;
|
|
9900
|
+
}
|
|
9901
|
+
|
|
9287
9902
|
// src/utils/errors.ts
|
|
9288
9903
|
class CliError2 extends Error {
|
|
9289
9904
|
constructor(message) {
|
|
@@ -9406,15 +10021,7 @@ if (process.argv[2] === "__complete") {
|
|
|
9406
10021
|
process.exit(0);
|
|
9407
10022
|
})();
|
|
9408
10023
|
} else {
|
|
9409
|
-
let
|
|
9410
|
-
for (let i = 0;i < argv.length; i++) {
|
|
9411
|
-
if (argv[i] === "--at" && i + 1 < argv.length)
|
|
9412
|
-
return argv[i + 1];
|
|
9413
|
-
if (argv[i].startsWith("--at="))
|
|
9414
|
-
return argv[i].slice(5);
|
|
9415
|
-
}
|
|
9416
|
-
return;
|
|
9417
|
-
}, collectVarFlags = function(argv) {
|
|
10024
|
+
let collectVarFlags = function(argv) {
|
|
9418
10025
|
const vars = [];
|
|
9419
10026
|
for (let i = 0;i < argv.length; i++) {
|
|
9420
10027
|
if (argv[i] === "--var" && i + 1 < argv.length) {
|
|
@@ -9470,8 +10077,10 @@ if (process.argv[2] === "__complete") {
|
|
|
9470
10077
|
console.log(" hash Hash utilities");
|
|
9471
10078
|
console.log(" sign Sign a message with an account keypair");
|
|
9472
10079
|
console.log(" parachain Derive parachain sovereign accounts (deprecated \u2014 use `account inspect --parachain`)");
|
|
9473
|
-
console.log(" verifiable
|
|
10080
|
+
console.log(" verifiable Bandersnatch member keys, ring-VRF proofs, sign/verify");
|
|
9474
10081
|
console.log(" completions <sh> Generate shell completions (zsh, bash, fish)");
|
|
10082
|
+
console.log(" init Initialize a local .polkadot workspace in this directory");
|
|
10083
|
+
console.log(" which Show the active config root (workspace, DOT_HOME, or global)");
|
|
9475
10084
|
console.log();
|
|
9476
10085
|
console.log("Global options:");
|
|
9477
10086
|
console.log(" --chain <name> Target chain (required)");
|
|
@@ -9483,12 +10092,7 @@ if (process.argv[2] === "__complete") {
|
|
|
9483
10092
|
};
|
|
9484
10093
|
startBackgroundCheck(version);
|
|
9485
10094
|
const cli = cac("dot");
|
|
9486
|
-
cli
|
|
9487
|
-
cli.option("--rpc <url>", "Override RPC endpoint for this call");
|
|
9488
|
-
cli.option("--output <format>", "Output format: pretty or json", {
|
|
9489
|
-
default: "pretty"
|
|
9490
|
-
});
|
|
9491
|
-
cli.option("--json", "Output as JSON (shorthand for --output json)");
|
|
10095
|
+
registerGlobalOptions(cli);
|
|
9492
10096
|
registerChainCommands(cli);
|
|
9493
10097
|
registerInspectCommand(cli);
|
|
9494
10098
|
registerMetadataCommand(cli);
|
|
@@ -9498,6 +10102,7 @@ if (process.argv[2] === "__complete") {
|
|
|
9498
10102
|
registerParachainCommand(cli);
|
|
9499
10103
|
registerCompletionsCommand(cli);
|
|
9500
10104
|
registerVerifiableCommands(cli);
|
|
10105
|
+
registerWorkspaceCommands(cli);
|
|
9501
10106
|
cli.command("[dotpath] [...args]").option("--from <name>", "Account to sign with (for tx)").option("--dry-run", "Estimate fees without submitting (for tx)").option("--encode", "Encode call to hex without signing (for tx)").option("--to-yaml", "Decode call to YAML file format (for tx)").option("--to-json", "Decode call to JSON file format (for tx)").option("--ext <json>", "Custom signed extension values as JSON (for tx)").option("--asset <json>", "Pay fees in an alternative asset (XCM location JSON, for tx)").option("-w, --wait <level>", "Resolve at: broadcast, best-block (or best), finalized (for tx)", {
|
|
9502
10107
|
default: "finalized"
|
|
9503
10108
|
}).option("--dump", "Dump all entries of a storage map (without specifying a key)").option("--var <kv>", "Template variable for file input (KEY=VALUE, repeatable)").option("--nonce <n>", "Custom nonce for manual tx sequencing (for tx)").option("--tip <amount>", "Tip to prioritize transaction (for tx)").option("--mortality <spec>", '"immortal" or period number (for tx)').option("--at <block>", 'Block hash, "best", or "finalized" to read/validate against (tx, query, apis)').option("--unsigned", "Submit as unsigned/bare transaction (no signer required, for tx)").option("--refresh", "Refresh the cached RPC method list from the node (for rpc)").action(async (dotpath, args, opts) => {
|
|
@@ -9505,7 +10110,7 @@ if (process.argv[2] === "__complete") {
|
|
|
9505
10110
|
printHelp();
|
|
9506
10111
|
return;
|
|
9507
10112
|
}
|
|
9508
|
-
const atRaw =
|
|
10113
|
+
const atRaw = readRawOptionValue2("at");
|
|
9509
10114
|
if (isFilePath(dotpath)) {
|
|
9510
10115
|
const cliVars = collectVarFlags(process.argv);
|
|
9511
10116
|
const cmd = await loadCommandFile(dotpath, cliVars);
|
|
@@ -9518,12 +10123,17 @@ if (process.argv[2] === "__complete") {
|
|
|
9518
10123
|
};
|
|
9519
10124
|
const target2 = `${cmd.pallet}.${cmd.item}`;
|
|
9520
10125
|
switch (cmd.category) {
|
|
9521
|
-
case "tx":
|
|
10126
|
+
case "tx": {
|
|
10127
|
+
const fileDecodeOnly = Boolean(opts.encode || opts.toYaml || opts.toJson);
|
|
10128
|
+
const fileDryRun = resolveDryRun(opts.dryRun, fileDecodeOnly);
|
|
10129
|
+
if (fileDryRun && isGlobalDryRun() && opts.dryRun === undefined) {
|
|
10130
|
+
printGlobalDryRunHint();
|
|
10131
|
+
}
|
|
9522
10132
|
await handleTx(target2, args, {
|
|
9523
10133
|
...handlerOpts2,
|
|
9524
10134
|
from: opts.from,
|
|
9525
10135
|
unsigned: opts.unsigned ?? cmd.unsigned,
|
|
9526
|
-
dryRun:
|
|
10136
|
+
dryRun: fileDryRun,
|
|
9527
10137
|
encode: opts.encode,
|
|
9528
10138
|
toYaml: opts.toYaml,
|
|
9529
10139
|
toJson: opts.toJson,
|
|
@@ -9537,6 +10147,7 @@ if (process.argv[2] === "__complete") {
|
|
|
9537
10147
|
parsedArgs: cmd.args
|
|
9538
10148
|
});
|
|
9539
10149
|
break;
|
|
10150
|
+
}
|
|
9540
10151
|
case "query":
|
|
9541
10152
|
await handleQuery(target2, args, {
|
|
9542
10153
|
...handlerOpts2,
|
|
@@ -9593,11 +10204,16 @@ if (process.argv[2] === "__complete") {
|
|
|
9593
10204
|
await handleQuery(target, args, { ...handlerOpts, dump: opts.dump, at: atRaw });
|
|
9594
10205
|
break;
|
|
9595
10206
|
case "tx": {
|
|
10207
|
+
const decodeOnly = Boolean(opts.encode || opts.toYaml || opts.toJson);
|
|
10208
|
+
const dryRun = resolveDryRun(opts.dryRun, decodeOnly);
|
|
10209
|
+
if (dryRun && isGlobalDryRun() && opts.dryRun === undefined) {
|
|
10210
|
+
printGlobalDryRunHint();
|
|
10211
|
+
}
|
|
9596
10212
|
const txOpts = {
|
|
9597
10213
|
...handlerOpts,
|
|
9598
10214
|
from: opts.from,
|
|
9599
10215
|
unsigned: opts.unsigned,
|
|
9600
|
-
dryRun
|
|
10216
|
+
dryRun,
|
|
9601
10217
|
encode: opts.encode,
|
|
9602
10218
|
toYaml: opts.toYaml,
|
|
9603
10219
|
toJson: opts.toJson,
|
|
@@ -9682,7 +10298,9 @@ if (process.argv[2] === "__complete") {
|
|
|
9682
10298
|
if (cli.options.version) {
|
|
9683
10299
|
await showUpdateAndExit(0);
|
|
9684
10300
|
} else if (cli.options.help) {
|
|
9685
|
-
if (cli
|
|
10301
|
+
if (printMatchedCommandHelp(cli)) {
|
|
10302
|
+
await showUpdateAndExit(0);
|
|
10303
|
+
} else if (cli.matchedCommand) {
|
|
9686
10304
|
const result = cli.runMatchedCommand();
|
|
9687
10305
|
if (result && typeof result.then === "function") {
|
|
9688
10306
|
await result.then(() => showUpdateAndExit(0), handleError);
|