polkadot-cli 0.2.1 → 0.5.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 +64 -37
- package/dist/cli.mjs +301 -44
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# polkadot-cli
|
|
2
2
|
|
|
3
|
-
A command-line tool for interacting with Polkadot-ecosystem chains.
|
|
3
|
+
A command-line tool for interacting with Polkadot-ecosystem chains. Manage chains and accounts, query storage, look up constants, inspect metadata, and submit extrinsics — all from your terminal.
|
|
4
4
|
|
|
5
5
|
Ships with Polkadot as the default chain. Add any Substrate-based chain by pointing to its RPC endpoint.
|
|
6
6
|
|
|
@@ -14,6 +14,48 @@ This installs the `dot` command globally.
|
|
|
14
14
|
|
|
15
15
|
## Usage
|
|
16
16
|
|
|
17
|
+
### Manage chains
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
# Add a chain
|
|
21
|
+
dot chain add kusama --rpc wss://kusama-rpc.polkadot.io
|
|
22
|
+
dot chain add westend --light-client
|
|
23
|
+
|
|
24
|
+
# List configured chains
|
|
25
|
+
dot chain list
|
|
26
|
+
|
|
27
|
+
# Re-fetch metadata after a runtime upgrade
|
|
28
|
+
dot chain update # updates default chain
|
|
29
|
+
dot chain update kusama # updates a specific chain
|
|
30
|
+
|
|
31
|
+
# Set default chain
|
|
32
|
+
dot chain default kusama
|
|
33
|
+
|
|
34
|
+
# Remove a chain
|
|
35
|
+
dot chain remove westend
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
### Manage accounts
|
|
39
|
+
|
|
40
|
+
Dev accounts (Alice, Bob, Charlie, Dave, Eve, Ferdie) are always available for testnets. Create or import your own accounts for any chain.
|
|
41
|
+
|
|
42
|
+
```bash
|
|
43
|
+
# List all accounts (dev + stored)
|
|
44
|
+
dot account list
|
|
45
|
+
|
|
46
|
+
# Create a new account (generates a mnemonic)
|
|
47
|
+
dot account create my-validator
|
|
48
|
+
|
|
49
|
+
# Import from a BIP39 mnemonic
|
|
50
|
+
dot account import treasury --secret "word1 word2 ... word12"
|
|
51
|
+
|
|
52
|
+
# Import from a hex seed
|
|
53
|
+
dot account import raw-key --secret 0xabcdef...
|
|
54
|
+
|
|
55
|
+
# Remove an account
|
|
56
|
+
dot account remove my-validator
|
|
57
|
+
```
|
|
58
|
+
|
|
17
59
|
### Query storage
|
|
18
60
|
|
|
19
61
|
```bash
|
|
@@ -52,30 +94,9 @@ dot inspect System
|
|
|
52
94
|
dot inspect System.Account
|
|
53
95
|
```
|
|
54
96
|
|
|
55
|
-
### Manage accounts
|
|
56
|
-
|
|
57
|
-
Dev accounts (Alice, Bob, Charlie, Dave, Eve, Ferdie) are always available for testnets. Create or import your own accounts for any chain.
|
|
58
|
-
|
|
59
|
-
```bash
|
|
60
|
-
# List all accounts (dev + stored)
|
|
61
|
-
dot account list
|
|
62
|
-
|
|
63
|
-
# Create a new account (generates a mnemonic)
|
|
64
|
-
dot account create my-validator
|
|
65
|
-
|
|
66
|
-
# Import from a BIP39 mnemonic
|
|
67
|
-
dot account import treasury --secret "word1 word2 ... word12"
|
|
68
|
-
|
|
69
|
-
# Import from a hex seed
|
|
70
|
-
dot account import raw-key --secret 0xabcdef...
|
|
71
|
-
|
|
72
|
-
# Remove an account
|
|
73
|
-
dot account remove my-validator
|
|
74
|
-
```
|
|
75
|
-
|
|
76
97
|
### Submit extrinsics
|
|
77
98
|
|
|
78
|
-
Build, sign, and submit transactions.
|
|
99
|
+
Build, sign, and submit transactions. Pass a `Pallet.Call` with arguments, or a raw SCALE-encoded call hex (e.g. from a multisig proposal or governance). Both forms display a decoded human-readable representation of the call.
|
|
79
100
|
|
|
80
101
|
```bash
|
|
81
102
|
# Simple remark
|
|
@@ -87,29 +108,35 @@ dot tx Balances.transferKeepAlive 5FHneW46xGXgs5mUiveU4sbTyGBzmstUspZC92UhjJM694
|
|
|
87
108
|
# Estimate fees without submitting
|
|
88
109
|
dot tx Balances.transferKeepAlive 5FHneW46xGXgs5mUiveU4sbTyGBzmstUspZC92UhjJM694ty 1000000000000 --from alice --dry-run
|
|
89
110
|
|
|
111
|
+
# Submit a raw SCALE-encoded call (e.g. from a multisig proposal or another tool)
|
|
112
|
+
dot tx 0x0503008eaf04151687736326c9fea17e25fc5287613693c912909cb226aa4794f26a48 --from alice
|
|
113
|
+
|
|
90
114
|
# Batch multiple transfers with Utility.batchAll
|
|
91
115
|
dot tx Utility.batchAll '[{"type":"Balances","value":{"type":"transfer_keep_alive","value":{"dest":"5FHneW46xGXgs5mUiveU4sbTyGBzmstUspZC92UhjJM694ty","value":1000000000000}}},{"type":"Balances","value":{"type":"transfer_keep_alive","value":{"dest":"5FLSigC9HGRKVhB9FiEo4Y3koPsNmBmLJbpXg2mp1hXcS59Y","value":2000000000000}}}]' --from alice
|
|
92
116
|
```
|
|
93
117
|
|
|
94
|
-
|
|
118
|
+
Both dry-run and submission display the encoded call hex and a decoded human-readable form:
|
|
95
119
|
|
|
96
|
-
```
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
120
|
+
```
|
|
121
|
+
Call: 0x0001076465616462656566
|
|
122
|
+
Decode: System.remark(remark: 0xdeadbeef)
|
|
123
|
+
Tx: 0xabc123...
|
|
124
|
+
Block: #12345678 (0xdef...)
|
|
125
|
+
Status: ok
|
|
126
|
+
```
|
|
100
127
|
|
|
101
|
-
|
|
102
|
-
dot chain list
|
|
128
|
+
#### Custom signed extensions
|
|
103
129
|
|
|
104
|
-
|
|
105
|
-
dot chain update # updates default chain
|
|
106
|
-
dot chain update kusama # updates a specific chain
|
|
130
|
+
Chains with non-standard signed extensions (e.g. `people-preview`) are auto-handled:
|
|
107
131
|
|
|
108
|
-
|
|
109
|
-
|
|
132
|
+
- `void` → empty bytes
|
|
133
|
+
- `Option<T>` → `None`
|
|
134
|
+
- enum with `Disabled` variant → `Disabled`
|
|
110
135
|
|
|
111
|
-
|
|
112
|
-
|
|
136
|
+
For manual override, use `--ext` with a JSON object:
|
|
137
|
+
|
|
138
|
+
```bash
|
|
139
|
+
dot tx System.remark 0xdeadbeef --from alice --ext '{"MyExtension":{"value":"..."}}'
|
|
113
140
|
```
|
|
114
141
|
|
|
115
142
|
### Global options
|
package/dist/cli.mjs
CHANGED
|
@@ -1,21 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { createRequire } from "node:module";
|
|
3
|
-
var __create = Object.create;
|
|
4
|
-
var __getProtoOf = Object.getPrototypeOf;
|
|
5
|
-
var __defProp = Object.defineProperty;
|
|
6
|
-
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
7
|
-
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
-
var __toESM = (mod, isNodeMode, target) => {
|
|
9
|
-
target = mod != null ? __create(__getProtoOf(mod)) : {};
|
|
10
|
-
const to = isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target;
|
|
11
|
-
for (let key of __getOwnPropNames(mod))
|
|
12
|
-
if (!__hasOwnProp.call(to, key))
|
|
13
|
-
__defProp(to, key, {
|
|
14
|
-
get: () => mod[key],
|
|
15
|
-
enumerable: true
|
|
16
|
-
});
|
|
17
|
-
return to;
|
|
18
|
-
};
|
|
19
3
|
var __require = /* @__PURE__ */ createRequire(import.meta.url);
|
|
20
4
|
|
|
21
5
|
// src/cli.ts
|
|
@@ -275,6 +259,13 @@ function findPallet(meta, palletName) {
|
|
|
275
259
|
const pallets = listPallets(meta);
|
|
276
260
|
return pallets.find((p) => p.name.toLowerCase() === palletName.toLowerCase());
|
|
277
261
|
}
|
|
262
|
+
function getSignedExtensions(meta) {
|
|
263
|
+
const byVersion = meta.unified.extrinsic.signedExtensions;
|
|
264
|
+
const versionKeys = Object.keys(byVersion);
|
|
265
|
+
if (versionKeys.length === 0)
|
|
266
|
+
return [];
|
|
267
|
+
return byVersion[Number(versionKeys[0])] ?? [];
|
|
268
|
+
}
|
|
278
269
|
function getPalletNames(meta) {
|
|
279
270
|
return meta.unified.pallets.map((p) => p.name);
|
|
280
271
|
}
|
|
@@ -381,6 +372,38 @@ function printDocs(docs) {
|
|
|
381
372
|
console.log(` ${DIM}${text}${RESET}`);
|
|
382
373
|
}
|
|
383
374
|
}
|
|
375
|
+
var CHECK_MARK = "✓";
|
|
376
|
+
var SPINNER_FRAMES = ["⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"];
|
|
377
|
+
|
|
378
|
+
class Spinner {
|
|
379
|
+
timer = null;
|
|
380
|
+
frame = 0;
|
|
381
|
+
start(msg) {
|
|
382
|
+
this.stop();
|
|
383
|
+
if (!isTTY) {
|
|
384
|
+
console.log(msg);
|
|
385
|
+
return;
|
|
386
|
+
}
|
|
387
|
+
process.stdout.write(`${SPINNER_FRAMES[0]} ${msg}`);
|
|
388
|
+
this.timer = setInterval(() => {
|
|
389
|
+
this.frame = (this.frame + 1) % SPINNER_FRAMES.length;
|
|
390
|
+
process.stdout.write(`\r\x1B[K${SPINNER_FRAMES[this.frame]} ${msg}`);
|
|
391
|
+
}, 80);
|
|
392
|
+
}
|
|
393
|
+
stop() {
|
|
394
|
+
if (this.timer !== null) {
|
|
395
|
+
clearInterval(this.timer);
|
|
396
|
+
this.timer = null;
|
|
397
|
+
this.frame = 0;
|
|
398
|
+
if (isTTY)
|
|
399
|
+
process.stdout.write("\r\x1B[K");
|
|
400
|
+
}
|
|
401
|
+
}
|
|
402
|
+
succeed(msg) {
|
|
403
|
+
this.stop();
|
|
404
|
+
console.log(`${GREEN}${CHECK_MARK}${RESET} ${msg}`);
|
|
405
|
+
}
|
|
406
|
+
}
|
|
384
407
|
|
|
385
408
|
// src/commands/chain.ts
|
|
386
409
|
var CHAIN_HELP = `
|
|
@@ -1061,41 +1084,70 @@ async function accountRemove(name) {
|
|
|
1061
1084
|
|
|
1062
1085
|
// src/commands/tx.ts
|
|
1063
1086
|
import { Binary } from "polkadot-api";
|
|
1087
|
+
import { getViewBuilder } from "@polkadot-api/view-builder";
|
|
1088
|
+
|
|
1089
|
+
// src/core/explorers.ts
|
|
1090
|
+
var pjsAppsLink = (rpc, hash) => `https://polkadot.js.org/apps/?rpc=${encodeURIComponent(rpc)}#/explorer/query/${hash}`;
|
|
1091
|
+
var papiLink = (rpc, hash) => `https://dev.papi.how/explorer/${hash}#networkId=custom&endpoint=${encodeURIComponent(rpc)}`;
|
|
1092
|
+
|
|
1093
|
+
// src/commands/tx.ts
|
|
1064
1094
|
function registerTxCommand(cli) {
|
|
1065
|
-
cli.command("tx [target] [...args]", "Submit an extrinsic (e.g. Balances.transferKeepAlive <dest> <amount>)").option("--from <name>", "Account to sign with (required)").option("--dry-run", "Estimate fees without submitting").action(async (target, args, opts) => {
|
|
1095
|
+
cli.command("tx [target] [...args]", "Submit an extrinsic (e.g. Balances.transferKeepAlive <dest> <amount>)").option("--from <name>", "Account to sign with (required)").option("--dry-run", "Estimate fees without submitting").option("--ext <json>", `Custom signed extension values as JSON, e.g. '{"ExtName":{"value":...}}'`).action(async (target, args, opts) => {
|
|
1066
1096
|
if (!target || !opts.from) {
|
|
1067
|
-
console.log("Usage: dot tx <Pallet.Call> [...args] --from <account> [--dry-run]");
|
|
1097
|
+
console.log("Usage: dot tx <Pallet.Call|0xCallHex> [...args] --from <account> [--dry-run]");
|
|
1068
1098
|
console.log("");
|
|
1069
1099
|
console.log("Examples:");
|
|
1070
1100
|
console.log(" $ dot tx Balances.transferKeepAlive 5FHn... 1000000000000 --from alice");
|
|
1071
1101
|
console.log(" $ dot tx System.remark 0xdeadbeef --from alice --dry-run");
|
|
1102
|
+
console.log(" $ dot tx 0x0001076465616462656566 --from alice");
|
|
1072
1103
|
return;
|
|
1073
1104
|
}
|
|
1105
|
+
const isRawCall = /^0x[0-9a-fA-F]+$/.test(target);
|
|
1074
1106
|
const config = await loadConfig();
|
|
1075
1107
|
const { name: chainName, chain: chainConfig } = resolveChain(config, opts.chain);
|
|
1076
|
-
const { pallet, item: callName } = parseTarget(target);
|
|
1077
1108
|
const signer = await resolveAccountSigner(opts.from);
|
|
1078
1109
|
const clientHandle = await createChainClient(chainName, chainConfig, opts.rpc);
|
|
1079
1110
|
try {
|
|
1080
1111
|
const meta = await getOrFetchMetadata(chainName, clientHandle);
|
|
1081
|
-
const
|
|
1082
|
-
const
|
|
1083
|
-
|
|
1084
|
-
throw new Error(suggestMessage("pallet", pallet, palletNames));
|
|
1085
|
-
}
|
|
1086
|
-
const callInfo = palletInfo.calls.find((c) => c.name.toLowerCase() === callName.toLowerCase());
|
|
1087
|
-
if (!callInfo) {
|
|
1088
|
-
const callNames = palletInfo.calls.map((c) => c.name);
|
|
1089
|
-
throw new Error(suggestMessage(`call in ${palletInfo.name}`, callName, callNames));
|
|
1090
|
-
}
|
|
1091
|
-
const callData = parseCallArgs(meta, palletInfo.name, callInfo.name, args);
|
|
1112
|
+
const userExtOverrides = parseExtOption(opts.ext);
|
|
1113
|
+
const customSignedExtensions = buildCustomSignedExtensions(meta, userExtOverrides);
|
|
1114
|
+
const txOptions = Object.keys(customSignedExtensions).length > 0 ? { customSignedExtensions } : undefined;
|
|
1092
1115
|
const unsafeApi = clientHandle.client.getUnsafeApi();
|
|
1093
|
-
|
|
1116
|
+
let tx;
|
|
1117
|
+
let callHex;
|
|
1118
|
+
if (isRawCall) {
|
|
1119
|
+
if (args.length > 0) {
|
|
1120
|
+
throw new Error(`Extra arguments are not allowed when submitting a raw call hex.
|
|
1121
|
+
` + "Usage: dot tx 0x<call_hex> --from <account>");
|
|
1122
|
+
}
|
|
1123
|
+
const callBinary = Binary.fromHex(target);
|
|
1124
|
+
tx = await unsafeApi.txFromCallData(callBinary);
|
|
1125
|
+
callHex = target;
|
|
1126
|
+
} else {
|
|
1127
|
+
const { pallet, item: callName } = parseTarget(target);
|
|
1128
|
+
const palletNames = getPalletNames(meta);
|
|
1129
|
+
const palletInfo = findPallet(meta, pallet);
|
|
1130
|
+
if (!palletInfo) {
|
|
1131
|
+
throw new Error(suggestMessage("pallet", pallet, palletNames));
|
|
1132
|
+
}
|
|
1133
|
+
const callInfo = palletInfo.calls.find((c) => c.name.toLowerCase() === callName.toLowerCase());
|
|
1134
|
+
if (!callInfo) {
|
|
1135
|
+
const callNames = palletInfo.calls.map((c) => c.name);
|
|
1136
|
+
throw new Error(suggestMessage(`call in ${palletInfo.name}`, callName, callNames));
|
|
1137
|
+
}
|
|
1138
|
+
const callData = parseCallArgs(meta, palletInfo.name, callInfo.name, args);
|
|
1139
|
+
tx = unsafeApi.tx[palletInfo.name][callInfo.name](callData);
|
|
1140
|
+
const encodedCall = await tx.getEncodedData();
|
|
1141
|
+
callHex = encodedCall.asHex();
|
|
1142
|
+
}
|
|
1143
|
+
const decodedStr = decodeCall(meta, callHex);
|
|
1094
1144
|
if (opts.dryRun) {
|
|
1095
1145
|
const signerAddress = toSs58(signer.publicKey);
|
|
1096
|
-
console.log(` ${BOLD}From:${RESET}
|
|
1146
|
+
console.log(` ${BOLD}From:${RESET} ${opts.from} (${signerAddress})`);
|
|
1147
|
+
console.log(` ${BOLD}Call:${RESET} ${callHex}`);
|
|
1148
|
+
console.log(` ${BOLD}Decode:${RESET} ${decodedStr}`);
|
|
1097
1149
|
try {
|
|
1098
|
-
const fees = await tx.getEstimatedFees(signer.publicKey);
|
|
1150
|
+
const fees = await tx.getEstimatedFees(signer.publicKey, txOptions);
|
|
1099
1151
|
console.log(` ${BOLD}Estimated fees:${RESET} ${fees}`);
|
|
1100
1152
|
} catch (err) {
|
|
1101
1153
|
console.log(` ${BOLD}Estimated fees:${RESET} ${YELLOW}unable to estimate${RESET}`);
|
|
@@ -1103,18 +1155,17 @@ function registerTxCommand(cli) {
|
|
|
1103
1155
|
}
|
|
1104
1156
|
return;
|
|
1105
1157
|
}
|
|
1106
|
-
|
|
1107
|
-
const result = await tx.signAndSubmit(signer);
|
|
1158
|
+
const result = await watchTransaction(tx.signSubmitAndWatch(signer, txOptions));
|
|
1108
1159
|
console.log();
|
|
1160
|
+
console.log(` ${BOLD}Call:${RESET} ${callHex}`);
|
|
1161
|
+
console.log(` ${BOLD}Decode:${RESET} ${decodedStr}`);
|
|
1109
1162
|
console.log(` ${BOLD}Tx:${RESET} ${result.txHash}`);
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
|
|
1163
|
+
console.log(` ${BOLD}Block:${RESET} #${result.block.number} (${result.block.hash})`);
|
|
1164
|
+
if (result.ok) {
|
|
1165
|
+
console.log(` ${BOLD}Status:${RESET} ${GREEN}ok${RESET}`);
|
|
1166
|
+
} else {
|
|
1114
1167
|
console.log(` ${BOLD}Status:${RESET} ${YELLOW}dispatch error${RESET}`);
|
|
1115
1168
|
console.log(` ${BOLD}Error:${RESET} ${result.dispatchError.type}${result.dispatchError.value ? ": " + JSON.stringify(result.dispatchError.value) : ""}`);
|
|
1116
|
-
} else {
|
|
1117
|
-
console.log(` ${BOLD}Status:${RESET} ${GREEN}ok${RESET}`);
|
|
1118
1169
|
}
|
|
1119
1170
|
if (result.events && result.events.length > 0) {
|
|
1120
1171
|
console.log(` ${BOLD}Events:${RESET}`);
|
|
@@ -1129,12 +1180,108 @@ function registerTxCommand(cli) {
|
|
|
1129
1180
|
}
|
|
1130
1181
|
}
|
|
1131
1182
|
}
|
|
1183
|
+
const rpcUrl = opts.rpc ?? chainConfig.rpc;
|
|
1184
|
+
if (rpcUrl) {
|
|
1185
|
+
const blockHash = result.block.hash;
|
|
1186
|
+
console.log(` ${BOLD}Explorer:${RESET}`);
|
|
1187
|
+
console.log(` ${DIM}PolkadotJS${RESET} ${pjsAppsLink(rpcUrl, blockHash)}`);
|
|
1188
|
+
console.log(` ${DIM}PAPI${RESET} ${papiLink(rpcUrl, blockHash)}`);
|
|
1189
|
+
}
|
|
1132
1190
|
console.log();
|
|
1133
1191
|
} finally {
|
|
1134
1192
|
clientHandle.destroy();
|
|
1135
1193
|
}
|
|
1136
1194
|
});
|
|
1137
1195
|
}
|
|
1196
|
+
function decodeCall(meta, callHex) {
|
|
1197
|
+
try {
|
|
1198
|
+
const viewBuilder = getViewBuilder(meta.lookup);
|
|
1199
|
+
const decoded = viewBuilder.callDecoder(callHex);
|
|
1200
|
+
const palletName = decoded.pallet.value.name;
|
|
1201
|
+
const callName = decoded.call.value.name;
|
|
1202
|
+
const argsStr = formatDecodedArgs(decoded.args.value);
|
|
1203
|
+
return `${palletName}.${callName}${argsStr}`;
|
|
1204
|
+
} catch {
|
|
1205
|
+
return "(unable to decode)";
|
|
1206
|
+
}
|
|
1207
|
+
}
|
|
1208
|
+
function formatDecodedArgs(decoded) {
|
|
1209
|
+
return formatDecoded(decoded);
|
|
1210
|
+
}
|
|
1211
|
+
function formatDecoded(d) {
|
|
1212
|
+
switch (d.codec) {
|
|
1213
|
+
case "_void":
|
|
1214
|
+
return "";
|
|
1215
|
+
case "bool":
|
|
1216
|
+
return d.value.toString();
|
|
1217
|
+
case "str":
|
|
1218
|
+
case "char":
|
|
1219
|
+
return d.value;
|
|
1220
|
+
case "u8":
|
|
1221
|
+
case "u16":
|
|
1222
|
+
case "u32":
|
|
1223
|
+
case "i8":
|
|
1224
|
+
case "i16":
|
|
1225
|
+
case "i32":
|
|
1226
|
+
case "compactNumber":
|
|
1227
|
+
return d.value.toString();
|
|
1228
|
+
case "u64":
|
|
1229
|
+
case "u128":
|
|
1230
|
+
case "u256":
|
|
1231
|
+
case "i64":
|
|
1232
|
+
case "i128":
|
|
1233
|
+
case "i256":
|
|
1234
|
+
case "compactBn":
|
|
1235
|
+
return d.value.toString();
|
|
1236
|
+
case "bitSequence":
|
|
1237
|
+
return `0x${Buffer.from(d.value.bytes).toString("hex")}`;
|
|
1238
|
+
case "AccountId":
|
|
1239
|
+
return d.value.address;
|
|
1240
|
+
case "ethAccount":
|
|
1241
|
+
return d.value;
|
|
1242
|
+
case "Bytes":
|
|
1243
|
+
return d.value;
|
|
1244
|
+
case "BytesArray":
|
|
1245
|
+
return d.value;
|
|
1246
|
+
case "Enum": {
|
|
1247
|
+
const inner = formatDecoded(d.value.value);
|
|
1248
|
+
if (!inner)
|
|
1249
|
+
return d.value.type;
|
|
1250
|
+
return `${d.value.type}(${inner})`;
|
|
1251
|
+
}
|
|
1252
|
+
case "Struct": {
|
|
1253
|
+
const entries = Object.entries(d.value);
|
|
1254
|
+
if (entries.length === 0)
|
|
1255
|
+
return " {}";
|
|
1256
|
+
const fields = entries.map(([k, v]) => `${k}: ${formatDecoded(v)}`).join(", ");
|
|
1257
|
+
return ` { ${fields} }`;
|
|
1258
|
+
}
|
|
1259
|
+
case "Tuple": {
|
|
1260
|
+
const items = d.value.map(formatDecoded).join(", ");
|
|
1261
|
+
return `(${items})`;
|
|
1262
|
+
}
|
|
1263
|
+
case "Option": {
|
|
1264
|
+
if (d.value.codec === "_void")
|
|
1265
|
+
return "None";
|
|
1266
|
+
return formatDecoded(d.value);
|
|
1267
|
+
}
|
|
1268
|
+
case "Result": {
|
|
1269
|
+
if (d.value.success) {
|
|
1270
|
+
return `Ok(${formatDecoded(d.value.value)})`;
|
|
1271
|
+
}
|
|
1272
|
+
return `Err(${formatDecoded(d.value.value)})`;
|
|
1273
|
+
}
|
|
1274
|
+
case "Sequence":
|
|
1275
|
+
case "Array": {
|
|
1276
|
+
const items = d.value.map(formatDecoded);
|
|
1277
|
+
if (items.length === 0)
|
|
1278
|
+
return "[]";
|
|
1279
|
+
return `[${items.join(", ")}]`;
|
|
1280
|
+
}
|
|
1281
|
+
default:
|
|
1282
|
+
return String(d.value ?? "");
|
|
1283
|
+
}
|
|
1284
|
+
}
|
|
1138
1285
|
function formatEventValue(v) {
|
|
1139
1286
|
if (typeof v === "bigint")
|
|
1140
1287
|
return v.toString();
|
|
@@ -1301,6 +1448,110 @@ function parsePrimitive(prim, arg) {
|
|
|
1301
1448
|
return parseValue(arg);
|
|
1302
1449
|
}
|
|
1303
1450
|
}
|
|
1451
|
+
var PAPI_BUILTIN_EXTENSIONS = new Set([
|
|
1452
|
+
"CheckNonZeroSender",
|
|
1453
|
+
"CheckSpecVersion",
|
|
1454
|
+
"CheckTxVersion",
|
|
1455
|
+
"CheckGenesis",
|
|
1456
|
+
"CheckMortality",
|
|
1457
|
+
"CheckNonce",
|
|
1458
|
+
"CheckWeight",
|
|
1459
|
+
"ChargeTransactionPayment",
|
|
1460
|
+
"ChargeAssetTxPayment",
|
|
1461
|
+
"CheckMetadataHash",
|
|
1462
|
+
"StorageWeightReclaim",
|
|
1463
|
+
"PrevalidateAttests"
|
|
1464
|
+
]);
|
|
1465
|
+
function parseExtOption(ext) {
|
|
1466
|
+
if (!ext)
|
|
1467
|
+
return {};
|
|
1468
|
+
try {
|
|
1469
|
+
const parsed = JSON.parse(ext);
|
|
1470
|
+
if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) {
|
|
1471
|
+
throw new Error(`--ext must be a JSON object, e.g. '{"ExtName":{"value":...}}'`);
|
|
1472
|
+
}
|
|
1473
|
+
return parsed;
|
|
1474
|
+
} catch (err) {
|
|
1475
|
+
if (err.message?.startsWith("--ext"))
|
|
1476
|
+
throw err;
|
|
1477
|
+
throw new Error(`Failed to parse --ext JSON: ${err.message}
|
|
1478
|
+
` + `Expected format: '{"ExtName":{"value":...}}'`);
|
|
1479
|
+
}
|
|
1480
|
+
}
|
|
1481
|
+
var NO_DEFAULT = Symbol("no-default");
|
|
1482
|
+
function buildCustomSignedExtensions(meta, userOverrides) {
|
|
1483
|
+
const result = {};
|
|
1484
|
+
const extensions = getSignedExtensions(meta);
|
|
1485
|
+
for (const ext of extensions) {
|
|
1486
|
+
if (PAPI_BUILTIN_EXTENSIONS.has(ext.identifier))
|
|
1487
|
+
continue;
|
|
1488
|
+
if (ext.identifier in userOverrides) {
|
|
1489
|
+
result[ext.identifier] = userOverrides[ext.identifier];
|
|
1490
|
+
continue;
|
|
1491
|
+
}
|
|
1492
|
+
const valueEntry = meta.lookup(ext.type);
|
|
1493
|
+
const addEntry = meta.lookup(ext.additionalSigned);
|
|
1494
|
+
const value = autoDefaultForType(valueEntry);
|
|
1495
|
+
const add = autoDefaultForType(addEntry);
|
|
1496
|
+
if (value !== NO_DEFAULT || add !== NO_DEFAULT) {
|
|
1497
|
+
result[ext.identifier] = {
|
|
1498
|
+
...value !== NO_DEFAULT ? { value } : {},
|
|
1499
|
+
...add !== NO_DEFAULT ? { additionalSigned: add } : {}
|
|
1500
|
+
};
|
|
1501
|
+
}
|
|
1502
|
+
}
|
|
1503
|
+
return result;
|
|
1504
|
+
}
|
|
1505
|
+
function autoDefaultForType(entry) {
|
|
1506
|
+
if (entry.type === "void")
|
|
1507
|
+
return new Uint8Array([]);
|
|
1508
|
+
if (entry.type === "option")
|
|
1509
|
+
return;
|
|
1510
|
+
if (entry.type === "enum") {
|
|
1511
|
+
const variants = entry.value;
|
|
1512
|
+
if ("Disabled" in variants) {
|
|
1513
|
+
return { type: "Disabled", value: undefined };
|
|
1514
|
+
}
|
|
1515
|
+
}
|
|
1516
|
+
return NO_DEFAULT;
|
|
1517
|
+
}
|
|
1518
|
+
function watchTransaction(observable) {
|
|
1519
|
+
const spinner = new Spinner;
|
|
1520
|
+
return new Promise((resolve, reject) => {
|
|
1521
|
+
spinner.start("Signing...");
|
|
1522
|
+
observable.subscribe({
|
|
1523
|
+
next(event) {
|
|
1524
|
+
switch (event.type) {
|
|
1525
|
+
case "signed":
|
|
1526
|
+
spinner.succeed("Signed");
|
|
1527
|
+
console.log(` ${BOLD}Tx:${RESET} ${event.txHash}`);
|
|
1528
|
+
spinner.start("Broadcasting...");
|
|
1529
|
+
break;
|
|
1530
|
+
case "broadcasted":
|
|
1531
|
+
spinner.succeed("Broadcasted");
|
|
1532
|
+
spinner.start("In best block...");
|
|
1533
|
+
break;
|
|
1534
|
+
case "txBestBlocksState":
|
|
1535
|
+
if (event.found) {
|
|
1536
|
+
spinner.succeed(`In best block #${event.block.number}`);
|
|
1537
|
+
spinner.start("Finalizing...");
|
|
1538
|
+
} else {
|
|
1539
|
+
spinner.start("In best block...");
|
|
1540
|
+
}
|
|
1541
|
+
break;
|
|
1542
|
+
case "finalized":
|
|
1543
|
+
spinner.stop();
|
|
1544
|
+
resolve(event);
|
|
1545
|
+
break;
|
|
1546
|
+
}
|
|
1547
|
+
},
|
|
1548
|
+
error(err) {
|
|
1549
|
+
spinner.stop();
|
|
1550
|
+
reject(err);
|
|
1551
|
+
}
|
|
1552
|
+
});
|
|
1553
|
+
});
|
|
1554
|
+
}
|
|
1304
1555
|
|
|
1305
1556
|
// src/utils/errors.ts
|
|
1306
1557
|
class CliError2 extends Error {
|
|
@@ -1309,6 +1560,8 @@ class CliError2 extends Error {
|
|
|
1309
1560
|
this.name = "CliError";
|
|
1310
1561
|
}
|
|
1311
1562
|
}
|
|
1563
|
+
// package.json
|
|
1564
|
+
var version = "0.5.0";
|
|
1312
1565
|
|
|
1313
1566
|
// src/cli.ts
|
|
1314
1567
|
var cli = cac("dot");
|
|
@@ -1325,7 +1578,7 @@ registerConstCommand(cli);
|
|
|
1325
1578
|
registerAccountCommands(cli);
|
|
1326
1579
|
registerTxCommand(cli);
|
|
1327
1580
|
cli.help();
|
|
1328
|
-
cli.version(
|
|
1581
|
+
cli.version(version);
|
|
1329
1582
|
function handleError(err) {
|
|
1330
1583
|
if (err instanceof CliError2) {
|
|
1331
1584
|
console.error(`Error: ${err.message}`);
|
|
@@ -1336,11 +1589,15 @@ function handleError(err) {
|
|
|
1336
1589
|
}
|
|
1337
1590
|
process.exit(1);
|
|
1338
1591
|
}
|
|
1339
|
-
process.on("unhandledRejection", handleError);
|
|
1340
1592
|
try {
|
|
1341
|
-
cli.parse();
|
|
1593
|
+
cli.parse(process.argv, { run: false });
|
|
1342
1594
|
if (!cli.matchedCommandName && !cli.options.help && !cli.options.version) {
|
|
1343
1595
|
cli.outputHelp();
|
|
1596
|
+
} else {
|
|
1597
|
+
const result = cli.runMatchedCommand();
|
|
1598
|
+
if (result && typeof result.then === "function") {
|
|
1599
|
+
result.then(() => process.exit(0), handleError);
|
|
1600
|
+
}
|
|
1344
1601
|
}
|
|
1345
1602
|
} catch (err) {
|
|
1346
1603
|
handleError(err);
|