@alchemy/cli 0.2.2 → 0.3.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 +29 -9
- package/dist/{chunk-2WI4JODY.js → chunk-MF6DXNO7.js} +6 -3
- package/dist/{chunk-6KOJKH6N.js → chunk-UPQTWEPP.js} +153 -12
- package/dist/{chunk-NA7MQB7X.js → chunk-VYQ5V2ZR.js} +38 -1
- package/dist/index.js +772 -176
- package/dist/{interactive-EAUEVR63.js → interactive-BFAXB5SN.js} +44 -10
- package/dist/{onboarding-SJ2BRK5I.js → onboarding-MUJF5QIE.js} +2 -2
- package/package.json +2 -1
package/dist/index.js
CHANGED
|
@@ -8,19 +8,21 @@ import {
|
|
|
8
8
|
registerConfig,
|
|
9
9
|
registerWallet,
|
|
10
10
|
resolveAPIKey,
|
|
11
|
+
resolveAddress,
|
|
11
12
|
resolveAppId,
|
|
12
13
|
resolveConfiguredNetworkSlugs,
|
|
13
14
|
resolveNetwork,
|
|
14
15
|
splitCommaList,
|
|
15
16
|
validateAddress,
|
|
16
17
|
validateTxHash
|
|
17
|
-
} from "./chunk-
|
|
18
|
+
} from "./chunk-UPQTWEPP.js";
|
|
18
19
|
import {
|
|
19
20
|
getRPCNetworks,
|
|
20
21
|
getSetupStatus,
|
|
21
22
|
isSetupComplete,
|
|
23
|
+
nativeTokenSymbol,
|
|
22
24
|
shouldRunOnboarding
|
|
23
|
-
} from "./chunk-
|
|
25
|
+
} from "./chunk-VYQ5V2ZR.js";
|
|
24
26
|
import {
|
|
25
27
|
EXIT_CODES,
|
|
26
28
|
ErrorCode,
|
|
@@ -59,20 +61,21 @@ import {
|
|
|
59
61
|
printUpdateNotice,
|
|
60
62
|
promptSelect,
|
|
61
63
|
quiet,
|
|
64
|
+
red,
|
|
62
65
|
setFlags,
|
|
63
66
|
successBadge,
|
|
64
67
|
timeAgo,
|
|
65
68
|
verbose,
|
|
66
69
|
weiToEth,
|
|
67
70
|
withSpinner
|
|
68
|
-
} from "./chunk-
|
|
71
|
+
} from "./chunk-MF6DXNO7.js";
|
|
69
72
|
|
|
70
73
|
// src/index.ts
|
|
71
74
|
import { Command, Help } from "commander";
|
|
72
75
|
|
|
73
76
|
// src/commands/rpc.ts
|
|
74
77
|
function registerRPC(program2) {
|
|
75
|
-
program2.command("rpc
|
|
78
|
+
program2.command("rpc").argument("<method>", "JSON-RPC method name (e.g. eth_blockNumber)").argument("[params...]", "Method parameters as JSON values").description("Make a raw JSON-RPC call").addHelpText(
|
|
76
79
|
"after",
|
|
77
80
|
`
|
|
78
81
|
Examples:
|
|
@@ -104,36 +107,50 @@ Examples:
|
|
|
104
107
|
|
|
105
108
|
// src/commands/balance.ts
|
|
106
109
|
function registerBalance(program2) {
|
|
107
|
-
program2.command("balance
|
|
110
|
+
program2.command("balance").argument("[address]", "Wallet address (0x...) or ENS name, or pipe via stdin").alias("bal").description("Get the native token balance of an address").addHelpText(
|
|
108
111
|
"after",
|
|
109
112
|
`
|
|
110
113
|
Examples:
|
|
111
114
|
alchemy balance 0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045
|
|
112
115
|
alchemy balance 0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045 -n polygon-mainnet
|
|
113
|
-
echo 0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045 | alchemy balance
|
|
114
|
-
|
|
116
|
+
echo 0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045 | alchemy balance
|
|
117
|
+
alchemy balance 0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045 --block 15537393
|
|
118
|
+
alchemy balance vitalik.eth`
|
|
119
|
+
).option("--block <block>", "Block number, hex, or tag (default: latest)").action(async (addressArg, opts) => {
|
|
115
120
|
try {
|
|
116
|
-
const
|
|
117
|
-
validateAddress(address);
|
|
121
|
+
const addressInput = addressArg ?? await readStdinArg("address");
|
|
118
122
|
const client = clientFromFlags(program2);
|
|
123
|
+
const address = await resolveAddress(addressInput, client);
|
|
124
|
+
let blockParam = opts?.block ?? "latest";
|
|
125
|
+
if (blockParam !== "latest" && blockParam !== "earliest" && blockParam !== "pending") {
|
|
126
|
+
if (!blockParam.startsWith("0x")) {
|
|
127
|
+
const num = parseInt(blockParam, 10);
|
|
128
|
+
if (isNaN(num) || num < 0) {
|
|
129
|
+
throw errInvalidArgs("Block must be a number, hex, or tag (latest, earliest, pending).");
|
|
130
|
+
}
|
|
131
|
+
blockParam = `0x${num.toString(16)}`;
|
|
132
|
+
}
|
|
133
|
+
}
|
|
119
134
|
const result = await withSpinner(
|
|
120
135
|
"Fetching balance\u2026",
|
|
121
136
|
"Balance fetched",
|
|
122
|
-
() => client.call("eth_getBalance", [address,
|
|
137
|
+
() => client.call("eth_getBalance", [address, blockParam])
|
|
123
138
|
);
|
|
124
139
|
const wei = BigInt(result);
|
|
125
140
|
const network = resolveNetwork(program2);
|
|
141
|
+
const symbol = nativeTokenSymbol(network);
|
|
126
142
|
if (isJSONMode()) {
|
|
127
143
|
printJSON({
|
|
128
144
|
address,
|
|
129
145
|
wei: wei.toString(),
|
|
130
|
-
|
|
146
|
+
balance: weiToEth(wei),
|
|
147
|
+
symbol,
|
|
131
148
|
network
|
|
132
149
|
});
|
|
133
150
|
} else {
|
|
134
151
|
printKeyValueBox([
|
|
135
152
|
["Address", address],
|
|
136
|
-
["Balance", green(weiToEth(wei)
|
|
153
|
+
["Balance", green(`${weiToEth(wei)} ${symbol}`)],
|
|
137
154
|
["Network", network]
|
|
138
155
|
]);
|
|
139
156
|
if (verbose) {
|
|
@@ -151,9 +168,76 @@ Examples:
|
|
|
151
168
|
});
|
|
152
169
|
}
|
|
153
170
|
|
|
171
|
+
// src/lib/block-format.ts
|
|
172
|
+
function parseHexQuantity(value) {
|
|
173
|
+
if (typeof value !== "string" || !/^0x[0-9a-f]+$/i.test(value)) {
|
|
174
|
+
return void 0;
|
|
175
|
+
}
|
|
176
|
+
try {
|
|
177
|
+
return BigInt(value);
|
|
178
|
+
} catch {
|
|
179
|
+
return void 0;
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
function formatWithCommas(value) {
|
|
183
|
+
return value.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",");
|
|
184
|
+
}
|
|
185
|
+
function formatHexQuantity(value) {
|
|
186
|
+
const parsed = parseHexQuantity(value);
|
|
187
|
+
if (parsed === void 0) return void 0;
|
|
188
|
+
return formatWithCommas(parsed);
|
|
189
|
+
}
|
|
190
|
+
function formatBlockTimestamp(value) {
|
|
191
|
+
if (typeof value !== "string") return void 0;
|
|
192
|
+
const parsed = parseHexQuantity(value);
|
|
193
|
+
if (parsed === void 0) return void 0;
|
|
194
|
+
const millis = Number(parsed) * 1e3;
|
|
195
|
+
if (!Number.isFinite(millis)) return void 0;
|
|
196
|
+
const d = new Date(millis);
|
|
197
|
+
if (Number.isNaN(d.getTime())) return void 0;
|
|
198
|
+
const iso = d.toISOString().replace(".000Z", "Z");
|
|
199
|
+
return `${iso} ${dim("(" + timeAgo(value) + ")")}`;
|
|
200
|
+
}
|
|
201
|
+
function formatHexWithRaw(value) {
|
|
202
|
+
if (typeof value !== "string") return void 0;
|
|
203
|
+
const parsed = parseHexQuantity(value);
|
|
204
|
+
if (parsed === void 0) return void 0;
|
|
205
|
+
return `${formatWithCommas(parsed)} ${dim(`(${value})`)}`;
|
|
206
|
+
}
|
|
207
|
+
function formatWeiWithRaw(value, symbol = "ETH") {
|
|
208
|
+
if (typeof value !== "string") return void 0;
|
|
209
|
+
const parsed = parseHexQuantity(value);
|
|
210
|
+
if (parsed === void 0) return void 0;
|
|
211
|
+
return `${weiToEth(parsed)} ${symbol} ${dim(`(${value})`)}`;
|
|
212
|
+
}
|
|
213
|
+
function formatGwei(gwei) {
|
|
214
|
+
const fixed = gwei.toFixed(9);
|
|
215
|
+
return fixed.replace(/\.?0+$/, "") || "0";
|
|
216
|
+
}
|
|
217
|
+
function formatGweiWithRaw(value) {
|
|
218
|
+
if (typeof value !== "string") return void 0;
|
|
219
|
+
const parsed = parseHexQuantity(value);
|
|
220
|
+
if (parsed === void 0) return void 0;
|
|
221
|
+
const gwei = Number(parsed) / 1e9;
|
|
222
|
+
return `${formatGwei(gwei)} gwei ${dim(`(${value})`)}`;
|
|
223
|
+
}
|
|
224
|
+
function formatGasSummary(gasUsed, gasLimit, options) {
|
|
225
|
+
const used = parseHexQuantity(gasUsed);
|
|
226
|
+
const limit = parseHexQuantity(gasLimit);
|
|
227
|
+
if (used === void 0 || limit === void 0) return void 0;
|
|
228
|
+
const usedFormatted = formatWithCommas(used);
|
|
229
|
+
const limitFormatted = formatWithCommas(limit);
|
|
230
|
+
if (limit === 0n) return `${usedFormatted} / ${limitFormatted}`;
|
|
231
|
+
const bps = used * 10000n / limit;
|
|
232
|
+
const percent = Number(bps) / 100;
|
|
233
|
+
const percentText = `${percent.toFixed(2)}%`;
|
|
234
|
+
const percentDisplay = options?.colored ? dim(percentText) : percentText;
|
|
235
|
+
return `${usedFormatted} / ${limitFormatted} (${percentDisplay})`;
|
|
236
|
+
}
|
|
237
|
+
|
|
154
238
|
// src/commands/tx.ts
|
|
155
239
|
function registerTx(program2) {
|
|
156
|
-
program2.command("tx
|
|
240
|
+
program2.command("tx").argument("[hash]", "Transaction hash (0x...) or pipe via stdin").description("Get transaction details by hash").addHelpText(
|
|
157
241
|
"after",
|
|
158
242
|
`
|
|
159
243
|
Examples:
|
|
@@ -178,23 +262,34 @@ Examples:
|
|
|
178
262
|
printJSON({ transaction: tx, receipt });
|
|
179
263
|
return;
|
|
180
264
|
}
|
|
265
|
+
const network = resolveNetwork(program2);
|
|
266
|
+
const symbol = nativeTokenSymbol(network);
|
|
181
267
|
const pairs = [["Hash", hash]];
|
|
182
268
|
if (tx.from) pairs.push(["From", String(tx.from)]);
|
|
183
269
|
if (tx.to) pairs.push(["To", String(tx.to)]);
|
|
184
270
|
if (tx.value) {
|
|
185
|
-
const
|
|
186
|
-
pairs.push(["Value", green(
|
|
271
|
+
const formatted = formatWeiWithRaw(tx.value, symbol);
|
|
272
|
+
pairs.push(["Value", formatted ? green(formatted) : String(tx.value)]);
|
|
273
|
+
}
|
|
274
|
+
if (tx.blockNumber) {
|
|
275
|
+
const formatted = formatHexWithRaw(tx.blockNumber);
|
|
276
|
+
pairs.push(["Block", formatted ?? String(tx.blockNumber)]);
|
|
187
277
|
}
|
|
188
|
-
if (tx.blockNumber) pairs.push(["Block", String(tx.blockNumber)]);
|
|
189
278
|
if (receipt) {
|
|
190
279
|
if (receipt.status === "0x1") {
|
|
191
280
|
pairs.push(["Status", `${successBadge()} Success`]);
|
|
192
281
|
} else if (receipt.status) {
|
|
193
282
|
pairs.push(["Status", `${failBadge()} Failed`]);
|
|
194
283
|
}
|
|
195
|
-
if (receipt.gasUsed)
|
|
284
|
+
if (receipt.gasUsed) {
|
|
285
|
+
const formatted = formatHexWithRaw(receipt.gasUsed);
|
|
286
|
+
pairs.push(["Gas Used", formatted ?? String(receipt.gasUsed)]);
|
|
287
|
+
}
|
|
288
|
+
if (receipt.effectiveGasPrice) {
|
|
289
|
+
const formatted = formatGweiWithRaw(receipt.effectiveGasPrice);
|
|
290
|
+
pairs.push(["Gas Price", formatted ?? String(receipt.effectiveGasPrice)]);
|
|
291
|
+
}
|
|
196
292
|
}
|
|
197
|
-
const network = resolveNetwork(program2);
|
|
198
293
|
const explorerURL = etherscanTxURL(hash, network);
|
|
199
294
|
if (explorerURL) {
|
|
200
295
|
pairs.push(["Explorer", explorerURL]);
|
|
@@ -210,53 +305,74 @@ Examples:
|
|
|
210
305
|
});
|
|
211
306
|
}
|
|
212
307
|
|
|
213
|
-
// src/
|
|
214
|
-
function
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
}
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
308
|
+
// src/commands/receipt.ts
|
|
309
|
+
function registerReceipt(program2) {
|
|
310
|
+
program2.command("receipt").argument("[hash]", "Transaction hash (0x...) or pipe via stdin").description("Get transaction receipt (status, gas used, logs)").addHelpText(
|
|
311
|
+
"after",
|
|
312
|
+
`
|
|
313
|
+
Examples:
|
|
314
|
+
alchemy receipt 0xabc123...
|
|
315
|
+
echo 0xabc123... | alchemy receipt`
|
|
316
|
+
).action(async (hashArg) => {
|
|
317
|
+
try {
|
|
318
|
+
const hash = hashArg ?? await readStdinArg("hash");
|
|
319
|
+
validateTxHash(hash);
|
|
320
|
+
const client = clientFromFlags(program2);
|
|
321
|
+
const receipt = await withSpinner(
|
|
322
|
+
"Fetching receipt\u2026",
|
|
323
|
+
"Receipt fetched",
|
|
324
|
+
() => client.call("eth_getTransactionReceipt", [hash])
|
|
325
|
+
);
|
|
326
|
+
if (!receipt) throw errNotFound(`receipt for ${hash}`);
|
|
327
|
+
if (isJSONMode()) {
|
|
328
|
+
printJSON(receipt);
|
|
329
|
+
return;
|
|
330
|
+
}
|
|
331
|
+
const pairs = [["Hash", hash]];
|
|
332
|
+
if (receipt.status === "0x1") {
|
|
333
|
+
pairs.push(["Status", `${successBadge()} ${green("Success")}`]);
|
|
334
|
+
} else if (receipt.status) {
|
|
335
|
+
pairs.push(["Status", `${failBadge()} ${red("Failed")}`]);
|
|
336
|
+
}
|
|
337
|
+
if (receipt.from) pairs.push(["From", String(receipt.from)]);
|
|
338
|
+
if (receipt.to) pairs.push(["To", String(receipt.to)]);
|
|
339
|
+
if (receipt.contractAddress) {
|
|
340
|
+
pairs.push(["Contract Created", String(receipt.contractAddress)]);
|
|
341
|
+
}
|
|
342
|
+
if (receipt.blockNumber) {
|
|
343
|
+
const hex = String(receipt.blockNumber);
|
|
344
|
+
const decoded = formatHexQuantity(hex);
|
|
345
|
+
pairs.push(["Block", decoded ? `${decoded} ${dim(`(${hex})`)}` : hex]);
|
|
346
|
+
}
|
|
347
|
+
if (receipt.gasUsed) {
|
|
348
|
+
const hex = String(receipt.gasUsed);
|
|
349
|
+
const decoded = formatHexQuantity(hex);
|
|
350
|
+
pairs.push(["Gas Used", decoded ? `${decoded} ${dim(`(${hex})`)}` : hex]);
|
|
351
|
+
}
|
|
352
|
+
if (receipt.effectiveGasPrice) {
|
|
353
|
+
const hex = String(receipt.effectiveGasPrice);
|
|
354
|
+
const wei = BigInt(hex);
|
|
355
|
+
const gwei = Number(wei) / 1e9;
|
|
356
|
+
pairs.push(["Gas Price", `${formatGwei(gwei)} gwei ${dim(`(${hex})`)}`]);
|
|
357
|
+
}
|
|
358
|
+
if (Array.isArray(receipt.logs)) {
|
|
359
|
+
pairs.push(["Logs", `${receipt.logs.length} event${receipt.logs.length === 1 ? "" : "s"}`]);
|
|
360
|
+
}
|
|
361
|
+
const network = resolveNetwork(program2);
|
|
362
|
+
const explorerURL = etherscanTxURL(hash, network);
|
|
363
|
+
if (explorerURL) {
|
|
364
|
+
pairs.push(["Explorer", explorerURL]);
|
|
365
|
+
}
|
|
366
|
+
printKeyValueBox(pairs);
|
|
367
|
+
} catch (err) {
|
|
368
|
+
exitWithError(err);
|
|
369
|
+
}
|
|
370
|
+
});
|
|
255
371
|
}
|
|
256
372
|
|
|
257
373
|
// src/commands/block.ts
|
|
258
374
|
function registerBlock(program2) {
|
|
259
|
-
program2.command("block
|
|
375
|
+
program2.command("block").argument("<number>", "Block number, hex (0x...), or tag (latest, earliest, pending)").description("Get block details by number").addHelpText(
|
|
260
376
|
"after",
|
|
261
377
|
`
|
|
262
378
|
Examples:
|
|
@@ -295,7 +411,7 @@ Examples:
|
|
|
295
411
|
}
|
|
296
412
|
const pairs = [];
|
|
297
413
|
if (block.number) {
|
|
298
|
-
const formatted =
|
|
414
|
+
const formatted = formatHexWithRaw(block.number);
|
|
299
415
|
pairs.push(["Block", bold(formatted ?? String(block.number))]);
|
|
300
416
|
}
|
|
301
417
|
if (block.hash) pairs.push(["Hash", String(block.hash)]);
|
|
@@ -313,11 +429,11 @@ Examples:
|
|
|
313
429
|
pairs.push(["Gas", gasSummary]);
|
|
314
430
|
} else {
|
|
315
431
|
if (block.gasUsed) {
|
|
316
|
-
const formatted =
|
|
432
|
+
const formatted = formatHexWithRaw(block.gasUsed);
|
|
317
433
|
pairs.push(["Gas Used", formatted ?? String(block.gasUsed)]);
|
|
318
434
|
}
|
|
319
435
|
if (block.gasLimit) {
|
|
320
|
-
const formatted =
|
|
436
|
+
const formatted = formatHexWithRaw(block.gasLimit);
|
|
321
437
|
pairs.push(["Gas Limit", formatted ?? String(block.gasLimit)]);
|
|
322
438
|
}
|
|
323
439
|
}
|
|
@@ -336,8 +452,28 @@ Examples:
|
|
|
336
452
|
}
|
|
337
453
|
|
|
338
454
|
// src/commands/nfts.ts
|
|
455
|
+
async function promptNFTPagination(shown, total) {
|
|
456
|
+
const action = await promptSelect({
|
|
457
|
+
message: `Showing ${shown} of ${total} NFTs`,
|
|
458
|
+
options: [
|
|
459
|
+
{ label: "Load next page", value: "next" },
|
|
460
|
+
{ label: "Stop here", value: "stop" }
|
|
461
|
+
],
|
|
462
|
+
initialValue: "next",
|
|
463
|
+
cancelMessage: "Stopped pagination."
|
|
464
|
+
});
|
|
465
|
+
if (action === null) return "stop";
|
|
466
|
+
return action;
|
|
467
|
+
}
|
|
468
|
+
function formatNFTRows(nfts) {
|
|
469
|
+
return nfts.map((nft) => [
|
|
470
|
+
nft.contract.name || dim("unnamed"),
|
|
471
|
+
nft.name || `#${nft.tokenId}`,
|
|
472
|
+
nft.contract.address
|
|
473
|
+
]);
|
|
474
|
+
}
|
|
339
475
|
function registerNFTs(program2) {
|
|
340
|
-
const cmd = program2.command("nfts").description("NFT API wrappers").argument("[address]", "Wallet address (default action: list owned NFTs)").option("--limit <n>", "Maximum number of NFTs to return", parseInt).option("--page-key <key>", "Pagination key from a previous response").addHelpText(
|
|
476
|
+
const cmd = program2.command("nfts").description("NFT API wrappers").argument("[address]", "Wallet address or ENS name (default action: list owned NFTs)").option("--limit <n>", "Maximum number of NFTs to return per page", parseInt).option("--page-key <key>", "Pagination key from a previous response").addHelpText(
|
|
341
477
|
"after",
|
|
342
478
|
`
|
|
343
479
|
Examples:
|
|
@@ -347,15 +483,15 @@ Examples:
|
|
|
347
483
|
echo 0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045 | alchemy nfts`
|
|
348
484
|
).action(async (addressArg, opts) => {
|
|
349
485
|
try {
|
|
350
|
-
const
|
|
351
|
-
|
|
486
|
+
const addressInput = addressArg ?? await readStdinArg("address");
|
|
487
|
+
const client = clientFromFlags(program2);
|
|
488
|
+
const address = await resolveAddress(addressInput, client);
|
|
352
489
|
const params = {
|
|
353
490
|
owner: address,
|
|
354
491
|
withMetadata: "true"
|
|
355
492
|
};
|
|
356
493
|
if (opts.limit) params.pageSize = String(opts.limit);
|
|
357
494
|
if (opts.pageKey) params.pageKey = opts.pageKey;
|
|
358
|
-
const client = clientFromFlags(program2);
|
|
359
495
|
const result = await withSpinner(
|
|
360
496
|
"Fetching NFTs\u2026",
|
|
361
497
|
"NFTs fetched",
|
|
@@ -369,19 +505,41 @@ Examples:
|
|
|
369
505
|
emptyState("No NFTs found.");
|
|
370
506
|
return;
|
|
371
507
|
}
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
nft.name || `#${nft.tokenId}`,
|
|
375
|
-
nft.contract.address
|
|
376
|
-
]);
|
|
377
|
-
printTable(["Collection", "Name", "Contract"], rows);
|
|
508
|
+
let shown = result.ownedNfts.length;
|
|
509
|
+
printTable(["Collection", "Name", "Contract"], formatNFTRows(result.ownedNfts));
|
|
378
510
|
if (verbose) {
|
|
379
511
|
console.log("");
|
|
380
512
|
printJSON(result);
|
|
381
513
|
}
|
|
382
|
-
|
|
514
|
+
const interactive = isInteractiveAllowed(program2);
|
|
515
|
+
let pageKey = result.pageKey;
|
|
516
|
+
while (pageKey && interactive) {
|
|
517
|
+
const action = await promptNFTPagination(shown, result.totalCount);
|
|
518
|
+
if (action === "stop") {
|
|
519
|
+
console.log(`
|
|
520
|
+
${dim(`Next page key: ${pageKey}`)}`);
|
|
521
|
+
break;
|
|
522
|
+
}
|
|
523
|
+
const nextParams = {
|
|
524
|
+
owner: address,
|
|
525
|
+
withMetadata: "true",
|
|
526
|
+
pageKey
|
|
527
|
+
};
|
|
528
|
+
if (opts.limit) nextParams.pageSize = String(opts.limit);
|
|
529
|
+
const nextResult = await withSpinner(
|
|
530
|
+
"Fetching next page\u2026",
|
|
531
|
+
"Page fetched",
|
|
532
|
+
() => client.callEnhanced("getNFTsForOwner", nextParams)
|
|
533
|
+
);
|
|
534
|
+
if (nextResult.ownedNfts.length > 0) {
|
|
535
|
+
printTable(["Collection", "Name", "Contract"], formatNFTRows(nextResult.ownedNfts));
|
|
536
|
+
shown += nextResult.ownedNfts.length;
|
|
537
|
+
}
|
|
538
|
+
pageKey = nextResult.pageKey;
|
|
539
|
+
}
|
|
540
|
+
if (pageKey && !interactive) {
|
|
383
541
|
console.log(`
|
|
384
|
-
${dim(`More results available. Use --page-key ${
|
|
542
|
+
${dim(`More results available. Use --page-key ${pageKey} to see the next page.`)}`);
|
|
385
543
|
}
|
|
386
544
|
} catch (err) {
|
|
387
545
|
exitWithError(err);
|
|
@@ -425,8 +583,34 @@ Examples:
|
|
|
425
583
|
}
|
|
426
584
|
|
|
427
585
|
// src/commands/tokens.ts
|
|
586
|
+
async function promptTokensPagination() {
|
|
587
|
+
const action = await promptSelect({
|
|
588
|
+
message: "More token balances available",
|
|
589
|
+
options: [
|
|
590
|
+
{ label: "Load next page", value: "next" },
|
|
591
|
+
{ label: "Stop here", value: "stop" }
|
|
592
|
+
],
|
|
593
|
+
initialValue: "next",
|
|
594
|
+
cancelMessage: "Stopped pagination."
|
|
595
|
+
});
|
|
596
|
+
if (action === null) return "stop";
|
|
597
|
+
return action;
|
|
598
|
+
}
|
|
599
|
+
function formatTokenRows(balances) {
|
|
600
|
+
const nonZero = balances.filter(
|
|
601
|
+
(tb) => tb.tokenBalance !== "0x0" && tb.tokenBalance !== "0x0000000000000000000000000000000000000000000000000000000000000000"
|
|
602
|
+
);
|
|
603
|
+
return nonZero.map((tb) => {
|
|
604
|
+
let decimalBalance = dim("unparseable");
|
|
605
|
+
try {
|
|
606
|
+
decimalBalance = BigInt(tb.tokenBalance).toString();
|
|
607
|
+
} catch {
|
|
608
|
+
}
|
|
609
|
+
return [tb.contractAddress, decimalBalance, tb.tokenBalance];
|
|
610
|
+
});
|
|
611
|
+
}
|
|
428
612
|
function registerTokens(program2) {
|
|
429
|
-
const cmd = program2.command("tokens").description("Token API wrappers").argument("[address]", "Wallet address (default action: list balances)").option("--page-key <key>", "Pagination key from a previous response").addHelpText(
|
|
613
|
+
const cmd = program2.command("tokens").description("Token API wrappers").argument("[address]", "Wallet address or ENS name (default action: list balances)").option("--page-key <key>", "Pagination key from a previous response").addHelpText(
|
|
430
614
|
"after",
|
|
431
615
|
`
|
|
432
616
|
Examples:
|
|
@@ -436,13 +620,13 @@ Examples:
|
|
|
436
620
|
echo 0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045 | alchemy tokens`
|
|
437
621
|
).action(async (addressArg, opts) => {
|
|
438
622
|
try {
|
|
439
|
-
const
|
|
440
|
-
|
|
623
|
+
const addressInput = addressArg ?? await readStdinArg("address");
|
|
624
|
+
const client = clientFromFlags(program2);
|
|
625
|
+
const address = await resolveAddress(addressInput, client);
|
|
441
626
|
const params = [address];
|
|
442
627
|
if (opts.pageKey) {
|
|
443
628
|
params.push("erc20", { pageKey: opts.pageKey });
|
|
444
629
|
}
|
|
445
|
-
const client = clientFromFlags(program2);
|
|
446
630
|
const result = await withSpinner(
|
|
447
631
|
"Fetching token balances\u2026",
|
|
448
632
|
"Token balances fetched",
|
|
@@ -452,36 +636,54 @@ Examples:
|
|
|
452
636
|
printJSON(result);
|
|
453
637
|
return;
|
|
454
638
|
}
|
|
455
|
-
const
|
|
456
|
-
|
|
457
|
-
);
|
|
458
|
-
if (nonZero.length === 0) {
|
|
639
|
+
const rows = formatTokenRows(result.tokenBalances);
|
|
640
|
+
if (rows.length === 0) {
|
|
459
641
|
emptyState("No token balances found.");
|
|
460
642
|
return;
|
|
461
643
|
}
|
|
462
|
-
|
|
463
|
-
let decimalBalance = dim("unparseable");
|
|
464
|
-
try {
|
|
465
|
-
decimalBalance = BigInt(tb.tokenBalance).toString();
|
|
466
|
-
} catch {
|
|
467
|
-
}
|
|
468
|
-
return [tb.contractAddress, decimalBalance, tb.tokenBalance];
|
|
469
|
-
});
|
|
644
|
+
let totalShown = rows.length;
|
|
470
645
|
printKeyValueBox([
|
|
471
646
|
["Address", address],
|
|
472
647
|
["Network", client.network],
|
|
473
|
-
["
|
|
648
|
+
["Tokens", String(totalShown)]
|
|
474
649
|
]);
|
|
475
650
|
printTable(["Contract", "Balance (base units)", "Raw (hex)"], rows);
|
|
476
651
|
console.log(`
|
|
477
|
-
${dim(
|
|
652
|
+
${dim(`${totalShown} tokens (zero balances hidden).`)}`);
|
|
478
653
|
if (verbose) {
|
|
479
654
|
console.log("");
|
|
480
655
|
printJSON(result);
|
|
481
656
|
}
|
|
482
|
-
|
|
657
|
+
const interactive = isInteractiveAllowed(program2);
|
|
658
|
+
let pageKey = result.pageKey;
|
|
659
|
+
while (pageKey && interactive) {
|
|
660
|
+
const action = await promptTokensPagination();
|
|
661
|
+
if (action === "stop") {
|
|
662
|
+
console.log(`
|
|
663
|
+
${dim(`Next page key: ${pageKey}`)}`);
|
|
664
|
+
break;
|
|
665
|
+
}
|
|
666
|
+
const nextResult = await withSpinner(
|
|
667
|
+
"Fetching next page\u2026",
|
|
668
|
+
"Page fetched",
|
|
669
|
+
() => client.call("alchemy_getTokenBalances", [address, "erc20", { pageKey }])
|
|
670
|
+
);
|
|
671
|
+
if (isJSONMode()) {
|
|
672
|
+
printJSON(nextResult);
|
|
673
|
+
return;
|
|
674
|
+
}
|
|
675
|
+
const nextRows = formatTokenRows(nextResult.tokenBalances);
|
|
676
|
+
totalShown += nextRows.length;
|
|
677
|
+
if (nextRows.length > 0) {
|
|
678
|
+
printTable(["Contract", "Balance (base units)", "Raw (hex)"], nextRows);
|
|
679
|
+
}
|
|
483
680
|
console.log(`
|
|
484
|
-
${dim(
|
|
681
|
+
${dim(`${totalShown} tokens total (zero balances hidden).`)}`);
|
|
682
|
+
pageKey = nextResult.pageKey;
|
|
683
|
+
}
|
|
684
|
+
if (pageKey && !interactive) {
|
|
685
|
+
console.log(`
|
|
686
|
+
${dim(`More results available. Use --page-key ${pageKey} to see the next page.`)}`);
|
|
485
687
|
}
|
|
486
688
|
} catch (err) {
|
|
487
689
|
exitWithError(err);
|
|
@@ -528,7 +730,7 @@ Examples:
|
|
|
528
730
|
// src/commands/network.ts
|
|
529
731
|
function registerNetwork(program2) {
|
|
530
732
|
const cmd = program2.command("network").description("Manage networks");
|
|
531
|
-
cmd.command("list").description("List
|
|
733
|
+
cmd.command("list").description("List RPC network IDs for use with --network (e.g. eth-mainnet)").option(
|
|
532
734
|
"--configured",
|
|
533
735
|
"List only configured app RPC networks (requires access key and app context)"
|
|
534
736
|
).option(
|
|
@@ -576,7 +778,7 @@ function registerNetwork(program2) {
|
|
|
576
778
|
console.log(`
|
|
577
779
|
Current: ${green(current)}`);
|
|
578
780
|
console.log(
|
|
579
|
-
` ${dim("Need Admin API chain
|
|
781
|
+
` ${dim("Need Admin API chain identifiers (e.g. ETH_MAINNET)? See: apps chains")}`
|
|
580
782
|
);
|
|
581
783
|
if (verbose) {
|
|
582
784
|
console.log("");
|
|
@@ -603,43 +805,6 @@ function registerVersion(program2) {
|
|
|
603
805
|
});
|
|
604
806
|
}
|
|
605
807
|
|
|
606
|
-
// src/commands/chains.ts
|
|
607
|
-
function registerChains(program2) {
|
|
608
|
-
const cmd = program2.command("chains").description("Manage Admin API chain enums");
|
|
609
|
-
cmd.command("list").description("List available Admin API chain enums").action(async () => {
|
|
610
|
-
try {
|
|
611
|
-
const admin = adminClientFromFlags(program2);
|
|
612
|
-
const chains = await withSpinner(
|
|
613
|
-
"Fetching chains\u2026",
|
|
614
|
-
"Chains fetched",
|
|
615
|
-
() => admin.listChains()
|
|
616
|
-
);
|
|
617
|
-
if (isJSONMode()) {
|
|
618
|
-
printJSON(chains);
|
|
619
|
-
return;
|
|
620
|
-
}
|
|
621
|
-
if (chains.length === 0) {
|
|
622
|
-
emptyState("No chain networks were returned.");
|
|
623
|
-
return;
|
|
624
|
-
}
|
|
625
|
-
const rows = chains.map((c) => [
|
|
626
|
-
c.id,
|
|
627
|
-
c.name,
|
|
628
|
-
c.isTestnet ? dim("yes") : "no",
|
|
629
|
-
c.availability === "public" ? green(c.availability) : dim(c.availability),
|
|
630
|
-
c.currency
|
|
631
|
-
]);
|
|
632
|
-
printTable(["ID", "Name", "Testnet", "Availability", "Currency"], rows);
|
|
633
|
-
if (verbose) {
|
|
634
|
-
console.log("");
|
|
635
|
-
printJSON(chains);
|
|
636
|
-
}
|
|
637
|
-
} catch (err) {
|
|
638
|
-
exitWithError(err);
|
|
639
|
-
}
|
|
640
|
-
});
|
|
641
|
-
}
|
|
642
|
-
|
|
643
808
|
// src/commands/apps.ts
|
|
644
809
|
function maskAppSecrets(app) {
|
|
645
810
|
return {
|
|
@@ -658,19 +823,14 @@ async function promptPaginationAction() {
|
|
|
658
823
|
message: "More apps available",
|
|
659
824
|
options: [
|
|
660
825
|
{ label: "Load next page", value: "next" },
|
|
661
|
-
{ label: "Load
|
|
826
|
+
{ label: "Load next 5 pages", value: "next5" },
|
|
662
827
|
{ label: "Stop here", value: "stop" }
|
|
663
828
|
],
|
|
664
829
|
initialValue: "next",
|
|
665
830
|
cancelMessage: "Stopped pagination."
|
|
666
831
|
});
|
|
667
|
-
if (action === null)
|
|
668
|
-
|
|
669
|
-
}
|
|
670
|
-
if (action === "next" || action === "all" || action === "stop") {
|
|
671
|
-
return action;
|
|
672
|
-
}
|
|
673
|
-
return "stop";
|
|
832
|
+
if (action === null) return "stop";
|
|
833
|
+
return action;
|
|
674
834
|
}
|
|
675
835
|
function matchesSearch(app, query) {
|
|
676
836
|
const q = query.toLowerCase();
|
|
@@ -763,7 +923,7 @@ function registerApps(program2) {
|
|
|
763
923
|
const interactivePagination = isInteractiveAllowed(program2) && !opts.all;
|
|
764
924
|
if (interactivePagination) {
|
|
765
925
|
let page = result;
|
|
766
|
-
let
|
|
926
|
+
let batchRemaining = 0;
|
|
767
927
|
let pagesFetched = 0;
|
|
768
928
|
let appsFetched = 0;
|
|
769
929
|
while (true) {
|
|
@@ -780,7 +940,7 @@ function registerApps(program2) {
|
|
|
780
940
|
printFetchSummary(appsFetched, pagesFetched);
|
|
781
941
|
return;
|
|
782
942
|
}
|
|
783
|
-
if (
|
|
943
|
+
if (batchRemaining <= 0) {
|
|
784
944
|
printFetchSummary(appsFetched, pagesFetched, { suffix: "so far" });
|
|
785
945
|
const action = await promptPaginationAction();
|
|
786
946
|
if (action === "stop") {
|
|
@@ -789,9 +949,11 @@ function registerApps(program2) {
|
|
|
789
949
|
printFetchSummary(appsFetched, pagesFetched);
|
|
790
950
|
return;
|
|
791
951
|
}
|
|
792
|
-
if (action === "
|
|
793
|
-
|
|
952
|
+
if (action === "next5") {
|
|
953
|
+
batchRemaining = 4;
|
|
794
954
|
}
|
|
955
|
+
} else {
|
|
956
|
+
batchRemaining -= 1;
|
|
795
957
|
}
|
|
796
958
|
page = await withSpinner(
|
|
797
959
|
"Fetching next page\u2026",
|
|
@@ -1006,6 +1168,45 @@ function registerApps(program2) {
|
|
|
1006
1168
|
exitWithError(err);
|
|
1007
1169
|
}
|
|
1008
1170
|
});
|
|
1171
|
+
cmd.command("chains").description("List Admin API chain identifiers for app configuration (e.g. ETH_MAINNET)").action(async () => {
|
|
1172
|
+
try {
|
|
1173
|
+
const admin = adminClientFromFlags(program2);
|
|
1174
|
+
const chains = await withSpinner(
|
|
1175
|
+
"Fetching chains\u2026",
|
|
1176
|
+
"Chains fetched",
|
|
1177
|
+
() => admin.listChains()
|
|
1178
|
+
);
|
|
1179
|
+
if (isJSONMode()) {
|
|
1180
|
+
printJSON(chains);
|
|
1181
|
+
return;
|
|
1182
|
+
}
|
|
1183
|
+
if (chains.length === 0) {
|
|
1184
|
+
emptyState("No chain networks were returned.");
|
|
1185
|
+
return;
|
|
1186
|
+
}
|
|
1187
|
+
const formatChainId = (value) => {
|
|
1188
|
+
if (!value) return dim("\u2014");
|
|
1189
|
+
const num = parseInt(value, 10);
|
|
1190
|
+
if (isNaN(num)) return value;
|
|
1191
|
+
return `${num} (0x${num.toString(16)})`;
|
|
1192
|
+
};
|
|
1193
|
+
const rows = chains.map((c) => [
|
|
1194
|
+
c.id,
|
|
1195
|
+
c.name,
|
|
1196
|
+
formatChainId(c.networkChainId),
|
|
1197
|
+
c.isTestnet ? dim("yes") : "no",
|
|
1198
|
+
c.availability === "public" ? green(c.availability) : dim(c.availability),
|
|
1199
|
+
c.currency
|
|
1200
|
+
]);
|
|
1201
|
+
printTable(["ID", "Name", "Chain ID", "Testnet", "Availability", "Currency"], rows);
|
|
1202
|
+
if (verbose) {
|
|
1203
|
+
console.log("");
|
|
1204
|
+
printJSON(chains);
|
|
1205
|
+
}
|
|
1206
|
+
} catch (err) {
|
|
1207
|
+
exitWithError(err);
|
|
1208
|
+
}
|
|
1209
|
+
});
|
|
1009
1210
|
}
|
|
1010
1211
|
|
|
1011
1212
|
// src/commands/setup.ts
|
|
@@ -1066,7 +1267,7 @@ function normalizeTraceMethod(method) {
|
|
|
1066
1267
|
return `trace_${normalized}`;
|
|
1067
1268
|
}
|
|
1068
1269
|
function registerTrace(program2) {
|
|
1069
|
-
program2.command("trace
|
|
1270
|
+
program2.command("trace").argument("<method>", "Trace method name (e.g. trace_transaction)").argument("[params...]", "Method parameters as JSON values").description("Call a trace_* method").action(async (method, params) => {
|
|
1070
1271
|
try {
|
|
1071
1272
|
const client = clientFromFlags(program2);
|
|
1072
1273
|
const rpcMethod = normalizeTraceMethod(method);
|
|
@@ -1088,7 +1289,7 @@ function normalizeDebugMethod(method) {
|
|
|
1088
1289
|
return `debug_${method.replace(/-/g, "_")}`;
|
|
1089
1290
|
}
|
|
1090
1291
|
function registerDebug(program2) {
|
|
1091
|
-
program2.command("debug
|
|
1292
|
+
program2.command("debug").argument("<method>", "Debug method name (e.g. debug_traceTransaction)").argument("[params...]", "Method parameters as JSON values").description("Call a debug_* method").action(async (method, params) => {
|
|
1092
1293
|
try {
|
|
1093
1294
|
const client = clientFromFlags(program2);
|
|
1094
1295
|
const rpcMethod = normalizeDebugMethod(method);
|
|
@@ -1105,29 +1306,72 @@ function registerDebug(program2) {
|
|
|
1105
1306
|
}
|
|
1106
1307
|
|
|
1107
1308
|
// src/commands/transfers.ts
|
|
1309
|
+
async function promptTransfersPagination(shown) {
|
|
1310
|
+
const action = await promptSelect({
|
|
1311
|
+
message: `${shown} transfers loaded \u2014 more available`,
|
|
1312
|
+
options: [
|
|
1313
|
+
{ label: "Load next page", value: "next" },
|
|
1314
|
+
{ label: "Stop here", value: "stop" }
|
|
1315
|
+
],
|
|
1316
|
+
initialValue: "next",
|
|
1317
|
+
cancelMessage: "Stopped pagination."
|
|
1318
|
+
});
|
|
1319
|
+
if (action === null) return "stop";
|
|
1320
|
+
return action;
|
|
1321
|
+
}
|
|
1322
|
+
var TABLE_HEADERS = ["Block", "From", "To", "Value", "Asset", "Category"];
|
|
1323
|
+
function formatTransferRows(transfers) {
|
|
1324
|
+
return transfers.map((t) => {
|
|
1325
|
+
const block = t.blockNum ? String(parseInt(t.blockNum, 16)) : dim("\u2014");
|
|
1326
|
+
const from = t.from ? `${t.from.slice(0, 8)}\u2026${t.from.slice(-4)}` : dim("\u2014");
|
|
1327
|
+
const to = t.to ? `${t.to.slice(0, 8)}\u2026${t.to.slice(-4)}` : dim("contract creation");
|
|
1328
|
+
const value = t.value !== null && t.value !== void 0 ? String(t.value) : dim("\u2014");
|
|
1329
|
+
const asset = t.asset ?? dim("\u2014");
|
|
1330
|
+
const category = t.category;
|
|
1331
|
+
return [block, from, to, value, asset, category];
|
|
1332
|
+
});
|
|
1333
|
+
}
|
|
1108
1334
|
function registerTransfers(program2) {
|
|
1109
|
-
program2.command("transfers
|
|
1335
|
+
program2.command("transfers").argument("[address]", "Wallet address or ENS name \u2014 queries outgoing transfers (use --to-address for incoming)").description("Get transfer history (alchemy_getAssetTransfers)").option("--from-address <address>", "Filter sender address").option("--to-address <address>", "Filter recipient address").option("--from-block <block>", "Start block (default: 0x0)").option("--to-block <block>", "End block (default: latest)").option("--category <list>", "Comma-separated categories (erc20,erc721,erc1155,external,internal,specialnft)").option("--max-count <hexOrDecimal>", "Max records to return per page").option("--page-key <key>", "Pagination key").addHelpText(
|
|
1336
|
+
"after",
|
|
1337
|
+
`
|
|
1338
|
+
Examples:
|
|
1339
|
+
# Outgoing transfers from an address
|
|
1340
|
+
alchemy transfers 0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045
|
|
1341
|
+
|
|
1342
|
+
# Incoming transfers to an address
|
|
1343
|
+
alchemy transfers --to-address 0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045
|
|
1344
|
+
|
|
1345
|
+
# Outgoing ERC-20 transfers only
|
|
1346
|
+
alchemy transfers --from-address 0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045 --category erc20
|
|
1347
|
+
|
|
1348
|
+
# Transfers within a block range
|
|
1349
|
+
alchemy transfers 0xd8dA... --from-block 0x100000 --to-block latest`
|
|
1350
|
+
).action(async (addressArg, opts) => {
|
|
1110
1351
|
try {
|
|
1111
1352
|
const client = clientFromFlags(program2);
|
|
1112
|
-
const address = addressArg
|
|
1113
|
-
if (
|
|
1114
|
-
if (opts.
|
|
1115
|
-
|
|
1116
|
-
const filter = {
|
|
1353
|
+
const address = addressArg ? await resolveAddress(addressArg, client) : void 0;
|
|
1354
|
+
if (opts.fromAddress) opts.fromAddress = await resolveAddress(opts.fromAddress, client);
|
|
1355
|
+
if (opts.toAddress) opts.toAddress = await resolveAddress(opts.toAddress, client);
|
|
1356
|
+
const baseFilter = {
|
|
1117
1357
|
fromBlock: opts.fromBlock ?? "0x0",
|
|
1118
1358
|
toBlock: opts.toBlock ?? "latest",
|
|
1119
|
-
withMetadata: true
|
|
1359
|
+
withMetadata: true,
|
|
1360
|
+
category: opts.category ? splitCommaList(opts.category) : ["external", "internal", "erc20", "erc721", "erc1155", "specialnft"]
|
|
1120
1361
|
};
|
|
1362
|
+
if (opts.maxCount) {
|
|
1363
|
+
baseFilter.maxCount = opts.maxCount.startsWith("0x") ? opts.maxCount : `0x${Number.parseInt(opts.maxCount, 10).toString(16)}`;
|
|
1364
|
+
} else if (!isJSONMode()) {
|
|
1365
|
+
baseFilter.maxCount = "0x19";
|
|
1366
|
+
}
|
|
1367
|
+
if (opts.pageKey) baseFilter.pageKey = opts.pageKey;
|
|
1368
|
+
const filter = { ...baseFilter };
|
|
1121
1369
|
if (address && !opts.fromAddress && !opts.toAddress) {
|
|
1122
1370
|
filter.fromAddress = address;
|
|
1123
|
-
filter.toAddress = address;
|
|
1124
1371
|
} else {
|
|
1125
1372
|
if (opts.fromAddress) filter.fromAddress = opts.fromAddress;
|
|
1126
1373
|
if (opts.toAddress) filter.toAddress = opts.toAddress;
|
|
1127
1374
|
}
|
|
1128
|
-
if (opts.category) filter.category = splitCommaList(opts.category);
|
|
1129
|
-
if (opts.maxCount) filter.maxCount = opts.maxCount.startsWith("0x") ? opts.maxCount : `0x${Number.parseInt(opts.maxCount, 10).toString(16)}`;
|
|
1130
|
-
if (opts.pageKey) filter.pageKey = opts.pageKey;
|
|
1131
1375
|
const result = await withSpinner(
|
|
1132
1376
|
"Fetching transfers\u2026",
|
|
1133
1377
|
"Transfers fetched",
|
|
@@ -1135,8 +1379,43 @@ function registerTransfers(program2) {
|
|
|
1135
1379
|
);
|
|
1136
1380
|
if (isJSONMode()) {
|
|
1137
1381
|
printJSON(result);
|
|
1138
|
-
|
|
1139
|
-
|
|
1382
|
+
return;
|
|
1383
|
+
}
|
|
1384
|
+
let totalShown = result.transfers.length;
|
|
1385
|
+
if (totalShown === 0) {
|
|
1386
|
+
console.log(dim("No transfers found."));
|
|
1387
|
+
return;
|
|
1388
|
+
}
|
|
1389
|
+
console.log(`${totalShown} transfer${totalShown === 1 ? "" : "s"}
|
|
1390
|
+
`);
|
|
1391
|
+
printTable(TABLE_HEADERS, formatTransferRows(result.transfers));
|
|
1392
|
+
const interactive = isInteractiveAllowed(program2);
|
|
1393
|
+
let pageKey = result.pageKey;
|
|
1394
|
+
while (pageKey && interactive) {
|
|
1395
|
+
const action = await promptTransfersPagination(totalShown);
|
|
1396
|
+
if (action === "stop") {
|
|
1397
|
+
console.log(`
|
|
1398
|
+
${dim(`Next page key: ${pageKey}`)}`);
|
|
1399
|
+
break;
|
|
1400
|
+
}
|
|
1401
|
+
filter.pageKey = pageKey;
|
|
1402
|
+
const nextResult = await withSpinner(
|
|
1403
|
+
"Fetching next page\u2026",
|
|
1404
|
+
"Page fetched",
|
|
1405
|
+
() => client.call("alchemy_getAssetTransfers", [filter])
|
|
1406
|
+
);
|
|
1407
|
+
if (nextResult.transfers.length > 0) {
|
|
1408
|
+
totalShown += nextResult.transfers.length;
|
|
1409
|
+
console.log(`
|
|
1410
|
+
${totalShown} transfers total
|
|
1411
|
+
`);
|
|
1412
|
+
printTable(TABLE_HEADERS, formatTransferRows(nextResult.transfers));
|
|
1413
|
+
}
|
|
1414
|
+
pageKey = nextResult.pageKey;
|
|
1415
|
+
}
|
|
1416
|
+
if (pageKey && !interactive) {
|
|
1417
|
+
console.log(`
|
|
1418
|
+
${dim(`More results available. Use --page-key ${pageKey} to see the next page.`)}`);
|
|
1140
1419
|
}
|
|
1141
1420
|
} catch (err) {
|
|
1142
1421
|
exitWithError(err);
|
|
@@ -1590,7 +1869,7 @@ function registerSolana(program2) {
|
|
|
1590
1869
|
const cmd = program2.command("solana").description("Solana RPC and DAS wrappers");
|
|
1591
1870
|
cmd.command("rpc <method> [params...]").description("Call a Solana JSON-RPC method").action(async (method, params) => {
|
|
1592
1871
|
try {
|
|
1593
|
-
const client = clientFromFlags(program2);
|
|
1872
|
+
const client = clientFromFlags(program2, { defaultNetwork: "solana-mainnet" });
|
|
1594
1873
|
const result = await withSpinner(
|
|
1595
1874
|
`Calling ${method}\u2026`,
|
|
1596
1875
|
`Called ${method}`,
|
|
@@ -1601,14 +1880,15 @@ function registerSolana(program2) {
|
|
|
1601
1880
|
exitWithError(err);
|
|
1602
1881
|
}
|
|
1603
1882
|
});
|
|
1604
|
-
|
|
1605
|
-
das.command("<method> [params...]").description("Call DAS method (e.g. getAssetsByOwner)").action(async (method, params) => {
|
|
1883
|
+
cmd.command("das <method> [params...]").description("Call a Solana DAS method (e.g. getAssetsByOwner)").action(async (method, params) => {
|
|
1606
1884
|
try {
|
|
1607
|
-
const client = clientFromFlags(program2);
|
|
1885
|
+
const client = clientFromFlags(program2, { defaultNetwork: "solana-mainnet" });
|
|
1886
|
+
const parsed = parseCLIParams(params);
|
|
1887
|
+
const rpcParams = parsed.length === 1 && typeof parsed[0] === "object" && parsed[0] !== null && !Array.isArray(parsed[0]) ? parsed[0] : parsed;
|
|
1608
1888
|
const result = await withSpinner(
|
|
1609
1889
|
`Calling ${method}\u2026`,
|
|
1610
1890
|
`Called ${method}`,
|
|
1611
|
-
() => client.call(method,
|
|
1891
|
+
() => client.call(method, rpcParams)
|
|
1612
1892
|
);
|
|
1613
1893
|
printSyntaxJSON(result);
|
|
1614
1894
|
} catch (err) {
|
|
@@ -1617,6 +1897,311 @@ function registerSolana(program2) {
|
|
|
1617
1897
|
});
|
|
1618
1898
|
}
|
|
1619
1899
|
|
|
1900
|
+
// src/commands/gas.ts
|
|
1901
|
+
function registerGas(program2) {
|
|
1902
|
+
program2.command("gas").description("Get current gas prices (base fee + priority fee)").addHelpText(
|
|
1903
|
+
"after",
|
|
1904
|
+
`
|
|
1905
|
+
Examples:
|
|
1906
|
+
alchemy gas
|
|
1907
|
+
alchemy gas -n polygon-mainnet
|
|
1908
|
+
alchemy gas --json`
|
|
1909
|
+
).action(async () => {
|
|
1910
|
+
try {
|
|
1911
|
+
const client = clientFromFlags(program2);
|
|
1912
|
+
const [gasPrice, maxPriorityFee] = await withSpinner(
|
|
1913
|
+
"Fetching gas prices\u2026",
|
|
1914
|
+
"Gas prices fetched",
|
|
1915
|
+
async () => {
|
|
1916
|
+
const [gp, mpf] = await Promise.all([
|
|
1917
|
+
client.call("eth_gasPrice", []),
|
|
1918
|
+
client.call("eth_maxPriorityFeePerGas", []).catch(() => null)
|
|
1919
|
+
]);
|
|
1920
|
+
return [gp, mpf];
|
|
1921
|
+
}
|
|
1922
|
+
);
|
|
1923
|
+
const network = resolveNetwork(program2);
|
|
1924
|
+
const gasPriceWei = BigInt(gasPrice);
|
|
1925
|
+
const gasPriceGwei = Number(gasPriceWei) / 1e9;
|
|
1926
|
+
let priorityFeeGwei = null;
|
|
1927
|
+
let priorityFeeWei = null;
|
|
1928
|
+
if (maxPriorityFee) {
|
|
1929
|
+
priorityFeeWei = BigInt(maxPriorityFee);
|
|
1930
|
+
priorityFeeGwei = Number(priorityFeeWei) / 1e9;
|
|
1931
|
+
}
|
|
1932
|
+
if (isJSONMode()) {
|
|
1933
|
+
const json = {
|
|
1934
|
+
gasPrice,
|
|
1935
|
+
gasPriceGwei: formatGwei(gasPriceGwei),
|
|
1936
|
+
network
|
|
1937
|
+
};
|
|
1938
|
+
if (maxPriorityFee) {
|
|
1939
|
+
json.maxPriorityFeePerGas = maxPriorityFee;
|
|
1940
|
+
json.maxPriorityFeePerGasGwei = formatGwei(priorityFeeGwei);
|
|
1941
|
+
}
|
|
1942
|
+
printJSON(json);
|
|
1943
|
+
} else {
|
|
1944
|
+
const pairs = [];
|
|
1945
|
+
const gasPriceFormatted = formatGweiWithRaw(gasPrice);
|
|
1946
|
+
pairs.push(["Gas Price", gasPriceFormatted ?? `${formatGwei(gasPriceGwei)} gwei`]);
|
|
1947
|
+
if (maxPriorityFee && priorityFeeGwei !== null) {
|
|
1948
|
+
const priorityFormatted = formatGweiWithRaw(maxPriorityFee);
|
|
1949
|
+
pairs.push(["Priority Fee", priorityFormatted ?? `${formatGwei(priorityFeeGwei)} gwei`]);
|
|
1950
|
+
}
|
|
1951
|
+
pairs.push(["Network", network]);
|
|
1952
|
+
printKeyValueBox(pairs);
|
|
1953
|
+
if (verbose) {
|
|
1954
|
+
console.log("");
|
|
1955
|
+
const verboseData = {
|
|
1956
|
+
rpcMethod: "eth_gasPrice",
|
|
1957
|
+
rpcResult: gasPrice
|
|
1958
|
+
};
|
|
1959
|
+
if (maxPriorityFee) {
|
|
1960
|
+
verboseData.rpcMethod2 = "eth_maxPriorityFeePerGas";
|
|
1961
|
+
verboseData.rpcResult2 = maxPriorityFee;
|
|
1962
|
+
}
|
|
1963
|
+
printJSON(verboseData);
|
|
1964
|
+
}
|
|
1965
|
+
}
|
|
1966
|
+
} catch (err) {
|
|
1967
|
+
exitWithError(err);
|
|
1968
|
+
}
|
|
1969
|
+
});
|
|
1970
|
+
}
|
|
1971
|
+
|
|
1972
|
+
// src/commands/logs.ts
|
|
1973
|
+
var PAGE_SIZE = 25;
|
|
1974
|
+
var LARGE_PAGE_SIZE = 100;
|
|
1975
|
+
function normalizeBlockParam(value) {
|
|
1976
|
+
if (value === "latest" || value === "earliest" || value === "pending") {
|
|
1977
|
+
return value;
|
|
1978
|
+
}
|
|
1979
|
+
if (value.startsWith("0x")) return value;
|
|
1980
|
+
const num = parseInt(value, 10);
|
|
1981
|
+
if (isNaN(num) || num < 0) {
|
|
1982
|
+
throw errInvalidArgs("Block must be a number, hex, or tag (latest, earliest, pending).");
|
|
1983
|
+
}
|
|
1984
|
+
return `0x${num.toString(16)}`;
|
|
1985
|
+
}
|
|
1986
|
+
function formatLogRows(logs) {
|
|
1987
|
+
return logs.map((log) => {
|
|
1988
|
+
const block = formatHexQuantity(log.blockNumber) ?? log.blockNumber;
|
|
1989
|
+
const idx = formatHexQuantity(log.logIndex) ?? log.logIndex;
|
|
1990
|
+
const topic0 = log.topics[0] ? `${log.topics[0].slice(0, 10)}\u2026` : dim("none");
|
|
1991
|
+
const addr = log.address;
|
|
1992
|
+
const txHash = `${log.transactionHash.slice(0, 10)}\u2026`;
|
|
1993
|
+
return [block, idx, addr, topic0, txHash];
|
|
1994
|
+
});
|
|
1995
|
+
}
|
|
1996
|
+
var TABLE_HEADERS2 = ["Block", "Index", "Address", "Topic0", "Tx Hash"];
|
|
1997
|
+
async function promptPaginationAction2(shown, total) {
|
|
1998
|
+
const remaining = total - shown;
|
|
1999
|
+
const options = [
|
|
2000
|
+
{ label: `Show next ${Math.min(PAGE_SIZE, remaining)}`, value: "next" }
|
|
2001
|
+
];
|
|
2002
|
+
if (remaining > PAGE_SIZE) {
|
|
2003
|
+
options.push({ label: `Show next ${Math.min(LARGE_PAGE_SIZE, remaining)}`, value: "next-large" });
|
|
2004
|
+
}
|
|
2005
|
+
options.push({ label: "Stop here", value: "stop" });
|
|
2006
|
+
const action = await promptSelect({
|
|
2007
|
+
message: `Showing ${shown} of ${total} logs (${remaining} remaining)`,
|
|
2008
|
+
options,
|
|
2009
|
+
initialValue: "next",
|
|
2010
|
+
cancelMessage: "Stopped pagination."
|
|
2011
|
+
});
|
|
2012
|
+
if (action === null) return "stop";
|
|
2013
|
+
return action;
|
|
2014
|
+
}
|
|
2015
|
+
function registerLogs(program2) {
|
|
2016
|
+
program2.command("logs").description("Query event logs (eth_getLogs)").addHelpText(
|
|
2017
|
+
"after",
|
|
2018
|
+
`
|
|
2019
|
+
Examples:
|
|
2020
|
+
alchemy logs --from-block 18000000 --to-block 18000010
|
|
2021
|
+
alchemy logs --address 0xdAC17F958D2ee523a2206206994597C13D831ec7 --from-block 18000000 --to-block 18000010
|
|
2022
|
+
alchemy logs --address 0xdAC17F958D2ee523a2206206994597C13D831ec7 --topic 0xddf252ad...
|
|
2023
|
+
alchemy logs --from-block latest --json`
|
|
2024
|
+
).option("--address <address>", "Contract address to filter logs").option("--topic <topic...>", "Event topic(s) to filter (topic0, topic1, ...)").option("--from-block <block>", "Start block (number, hex, or tag)", "latest").option("--to-block <block>", "End block (number, hex, or tag)", "latest").action(async (opts) => {
|
|
2025
|
+
try {
|
|
2026
|
+
const filter = {
|
|
2027
|
+
fromBlock: normalizeBlockParam(opts.fromBlock),
|
|
2028
|
+
toBlock: normalizeBlockParam(opts.toBlock)
|
|
2029
|
+
};
|
|
2030
|
+
if (opts.address) {
|
|
2031
|
+
filter.address = opts.address;
|
|
2032
|
+
}
|
|
2033
|
+
if (opts.topic && opts.topic.length > 0) {
|
|
2034
|
+
filter.topics = opts.topic;
|
|
2035
|
+
}
|
|
2036
|
+
const client = clientFromFlags(program2);
|
|
2037
|
+
const logs = await withSpinner(
|
|
2038
|
+
"Fetching logs\u2026",
|
|
2039
|
+
"Logs fetched",
|
|
2040
|
+
() => client.call("eth_getLogs", [filter])
|
|
2041
|
+
);
|
|
2042
|
+
const network = resolveNetwork(program2);
|
|
2043
|
+
if (isJSONMode()) {
|
|
2044
|
+
printJSON({ logs, count: logs.length, network });
|
|
2045
|
+
return;
|
|
2046
|
+
}
|
|
2047
|
+
if (logs.length === 0) {
|
|
2048
|
+
console.log(dim("No logs found for the given filter."));
|
|
2049
|
+
return;
|
|
2050
|
+
}
|
|
2051
|
+
const total = logs.length;
|
|
2052
|
+
const interactive = isInteractiveAllowed(program2);
|
|
2053
|
+
if (!interactive) {
|
|
2054
|
+
console.log(`Found ${total} log${total === 1 ? "" : "s"} on ${network}
|
|
2055
|
+
`);
|
|
2056
|
+
printTable(TABLE_HEADERS2, formatLogRows(logs));
|
|
2057
|
+
} else {
|
|
2058
|
+
let offset = 0;
|
|
2059
|
+
const firstPage = logs.slice(0, PAGE_SIZE);
|
|
2060
|
+
console.log(`Found ${total} log${total === 1 ? "" : "s"} on ${network}
|
|
2061
|
+
`);
|
|
2062
|
+
printTable(TABLE_HEADERS2, formatLogRows(firstPage));
|
|
2063
|
+
offset = firstPage.length;
|
|
2064
|
+
while (offset < total) {
|
|
2065
|
+
const action = await promptPaginationAction2(offset, total);
|
|
2066
|
+
if (action === "stop") break;
|
|
2067
|
+
const size = action === "next-large" ? LARGE_PAGE_SIZE : PAGE_SIZE;
|
|
2068
|
+
const page = logs.slice(offset, offset + size);
|
|
2069
|
+
console.log("");
|
|
2070
|
+
printTable(TABLE_HEADERS2, formatLogRows(page));
|
|
2071
|
+
offset += page.length;
|
|
2072
|
+
}
|
|
2073
|
+
}
|
|
2074
|
+
if (total >= 1e4) {
|
|
2075
|
+
console.log("");
|
|
2076
|
+
console.log(dim("\u26A0 RPC result limit reached (10,000). Narrow your block range for complete results."));
|
|
2077
|
+
}
|
|
2078
|
+
} catch (err) {
|
|
2079
|
+
exitWithError(err);
|
|
2080
|
+
}
|
|
2081
|
+
});
|
|
2082
|
+
}
|
|
2083
|
+
|
|
2084
|
+
// src/commands/completions.ts
|
|
2085
|
+
function getDescription(cmd) {
|
|
2086
|
+
try {
|
|
2087
|
+
return typeof cmd.description === "function" ? cmd.description() : String(cmd.description || "");
|
|
2088
|
+
} catch {
|
|
2089
|
+
return "";
|
|
2090
|
+
}
|
|
2091
|
+
}
|
|
2092
|
+
function collectCommands(cmd, prefix = []) {
|
|
2093
|
+
const results = [];
|
|
2094
|
+
for (const sub of cmd.commands) {
|
|
2095
|
+
const path = [...prefix, sub.name()];
|
|
2096
|
+
results.push({ path, description: getDescription(sub) });
|
|
2097
|
+
results.push(...collectCommands(sub, path));
|
|
2098
|
+
}
|
|
2099
|
+
return results;
|
|
2100
|
+
}
|
|
2101
|
+
function generateBash(program2) {
|
|
2102
|
+
const commands = collectCommands(program2);
|
|
2103
|
+
const topLevel = program2.commands.map((c) => c.name()).join(" ");
|
|
2104
|
+
const cases = commands.filter((c) => c.path.length === 1).map((c) => {
|
|
2105
|
+
const subs = commands.filter((s) => s.path.length === 2 && s.path[0] === c.path[0]).map((s) => s.path[1]);
|
|
2106
|
+
if (subs.length === 0) return "";
|
|
2107
|
+
return ` ${c.path[0]}) COMPREPLY=($(compgen -W "${subs.join(" ")}" -- "$cur")) ;;`;
|
|
2108
|
+
}).filter(Boolean).join("\n");
|
|
2109
|
+
return `# bash completion for alchemy CLI
|
|
2110
|
+
# Add to ~/.bashrc: eval "$(alchemy completions bash)"
|
|
2111
|
+
_alchemy_completions() {
|
|
2112
|
+
local cur prev
|
|
2113
|
+
cur="\${COMP_WORDS[COMP_CWORD]}"
|
|
2114
|
+
prev="\${COMP_WORDS[COMP_CWORD-1]}"
|
|
2115
|
+
|
|
2116
|
+
if [[ \${COMP_CWORD} -eq 1 ]]; then
|
|
2117
|
+
COMPREPLY=($(compgen -W "${topLevel}" -- "$cur"))
|
|
2118
|
+
return
|
|
2119
|
+
fi
|
|
2120
|
+
|
|
2121
|
+
case "$prev" in
|
|
2122
|
+
${cases}
|
|
2123
|
+
-n|--network) COMPREPLY=() ;;
|
|
2124
|
+
*) COMPREPLY=() ;;
|
|
2125
|
+
esac
|
|
2126
|
+
}
|
|
2127
|
+
complete -F _alchemy_completions alchemy
|
|
2128
|
+
`;
|
|
2129
|
+
}
|
|
2130
|
+
function generateZsh(program2) {
|
|
2131
|
+
const commands = collectCommands(program2);
|
|
2132
|
+
const topLevel = program2.commands.map((c) => `'${c.name()}:${getDescription(c).replace(/'/g, "'\\''")}'`).join("\n ");
|
|
2133
|
+
const subcommandCases = commands.filter((c) => c.path.length === 1).map((c) => {
|
|
2134
|
+
const subs = commands.filter((s) => s.path.length === 2 && s.path[0] === c.path[0]).map((s) => `'${s.path[1]}:${s.description.replace(/'/g, "'\\''")}'`);
|
|
2135
|
+
if (subs.length === 0) return "";
|
|
2136
|
+
return ` ${c.path[0]})
|
|
2137
|
+
_values 'subcommand' \\
|
|
2138
|
+
${subs.join(" \\\n ")}
|
|
2139
|
+
;;`;
|
|
2140
|
+
}).filter(Boolean).join("\n");
|
|
2141
|
+
return `#compdef alchemy
|
|
2142
|
+
# zsh completion for alchemy CLI
|
|
2143
|
+
# Add to ~/.zshrc: eval "$(alchemy completions zsh)"
|
|
2144
|
+
_alchemy() {
|
|
2145
|
+
local -a commands
|
|
2146
|
+
if (( CURRENT == 2 )); then
|
|
2147
|
+
commands=(
|
|
2148
|
+
${topLevel}
|
|
2149
|
+
)
|
|
2150
|
+
_describe 'command' commands
|
|
2151
|
+
return
|
|
2152
|
+
fi
|
|
2153
|
+
|
|
2154
|
+
case "$words[2]" in
|
|
2155
|
+
${subcommandCases}
|
|
2156
|
+
esac
|
|
2157
|
+
}
|
|
2158
|
+
_alchemy "$@"
|
|
2159
|
+
compdef _alchemy alchemy
|
|
2160
|
+
`;
|
|
2161
|
+
}
|
|
2162
|
+
function generateFish(program2) {
|
|
2163
|
+
const commands = collectCommands(program2);
|
|
2164
|
+
const lines = commands.map((c) => {
|
|
2165
|
+
const desc = c.description.replace(/\\/g, "\\\\").replace(/'/g, "\\'");
|
|
2166
|
+
if (c.path.length === 1) {
|
|
2167
|
+
return `complete -c alchemy -n '__fish_use_subcommand' -a '${c.path[0]}' -d '${desc}'`;
|
|
2168
|
+
}
|
|
2169
|
+
if (c.path.length === 2) {
|
|
2170
|
+
return `complete -c alchemy -n '__fish_seen_subcommand_from ${c.path[0]}' -a '${c.path[1]}' -d '${desc}'`;
|
|
2171
|
+
}
|
|
2172
|
+
return "";
|
|
2173
|
+
}).filter(Boolean);
|
|
2174
|
+
return `# fish completion for alchemy CLI
|
|
2175
|
+
# Add to ~/.config/fish/completions/alchemy.fish
|
|
2176
|
+
${lines.join("\n")}
|
|
2177
|
+
`;
|
|
2178
|
+
}
|
|
2179
|
+
function registerCompletions(program2) {
|
|
2180
|
+
program2.command("completions").argument("<shell>", "Shell type: bash, zsh, or fish").description("Generate shell completion scripts").addHelpText(
|
|
2181
|
+
"after",
|
|
2182
|
+
`
|
|
2183
|
+
Examples:
|
|
2184
|
+
alchemy completions bash >> ~/.bashrc
|
|
2185
|
+
eval "$(alchemy completions zsh)"
|
|
2186
|
+
alchemy completions fish > ~/.config/fish/completions/alchemy.fish`
|
|
2187
|
+
).action((shell) => {
|
|
2188
|
+
switch (shell.toLowerCase()) {
|
|
2189
|
+
case "bash":
|
|
2190
|
+
process.stdout.write(generateBash(program2));
|
|
2191
|
+
break;
|
|
2192
|
+
case "zsh":
|
|
2193
|
+
process.stdout.write(generateZsh(program2));
|
|
2194
|
+
break;
|
|
2195
|
+
case "fish":
|
|
2196
|
+
process.stdout.write(generateFish(program2));
|
|
2197
|
+
break;
|
|
2198
|
+
default:
|
|
2199
|
+
console.error(`Unknown shell: ${shell}. Supported: bash, zsh, fish`);
|
|
2200
|
+
process.exit(2);
|
|
2201
|
+
}
|
|
2202
|
+
});
|
|
2203
|
+
}
|
|
2204
|
+
|
|
1620
2205
|
// src/commands/agent-prompt.ts
|
|
1621
2206
|
var RETRYABLE_CODES = /* @__PURE__ */ new Set([
|
|
1622
2207
|
ErrorCode.RATE_LIMITED,
|
|
@@ -1718,7 +2303,7 @@ function buildAgentPrompt(program2) {
|
|
|
1718
2303
|
envVar: "ALCHEMY_ACCESS_KEY",
|
|
1719
2304
|
flag: "--access-key <key>",
|
|
1720
2305
|
configKey: "access-key",
|
|
1721
|
-
commandFamilies: ["apps", "
|
|
2306
|
+
commandFamilies: ["apps", "network list --configured"]
|
|
1722
2307
|
},
|
|
1723
2308
|
{
|
|
1724
2309
|
method: "Webhook API key",
|
|
@@ -1850,7 +2435,7 @@ var ROOT_OPTION_GROUPS = [
|
|
|
1850
2435
|
var ROOT_COMMAND_PILLARS = [
|
|
1851
2436
|
{
|
|
1852
2437
|
label: "Node",
|
|
1853
|
-
commands: ["balance", "tx", "block", "rpc", "trace", "debug"]
|
|
2438
|
+
commands: ["balance", "tx", "block", "rpc", "trace", "debug", "gas", "logs"]
|
|
1854
2439
|
},
|
|
1855
2440
|
{
|
|
1856
2441
|
label: "Data",
|
|
@@ -1862,11 +2447,11 @@ var ROOT_COMMAND_PILLARS = [
|
|
|
1862
2447
|
},
|
|
1863
2448
|
{
|
|
1864
2449
|
label: "Chains",
|
|
1865
|
-
commands: ["network", "
|
|
2450
|
+
commands: ["network", "solana"]
|
|
1866
2451
|
},
|
|
1867
2452
|
{
|
|
1868
2453
|
label: "Admin",
|
|
1869
|
-
commands: ["apps", "config", "setup", "agent-prompt", "update-check", "version", "help"]
|
|
2454
|
+
commands: ["apps", "config", "setup", "completions", "agent-prompt", "update-check", "version", "help"]
|
|
1870
2455
|
}
|
|
1871
2456
|
];
|
|
1872
2457
|
function formatCommandSignature(sub) {
|
|
@@ -1915,10 +2500,10 @@ function resetUpdateNoticeState() {
|
|
|
1915
2500
|
}
|
|
1916
2501
|
program.name("alchemy").description(
|
|
1917
2502
|
"The Alchemy CLI lets you query blockchain data, call JSON-RPC methods, and manage your Alchemy configuration."
|
|
1918
|
-
).version("0.
|
|
2503
|
+
).version("0.3.0", "-v, --version", "display CLI version").option("--api-key <key>", "Alchemy API key (env: ALCHEMY_API_KEY)").option("--access-key <key>", "Alchemy access key (env: ALCHEMY_ACCESS_KEY)").option(
|
|
1919
2504
|
"-n, --network <network>",
|
|
1920
2505
|
"Target network (default: eth-mainnet) (env: ALCHEMY_NETWORK)"
|
|
1921
|
-
).option("--x402", "Use x402 wallet-based gateway auth").option("--wallet-key-file <path>", "Path to wallet private key file for x402").option("--json", "Force JSON output").option("-q, --quiet", "Suppress non-essential output").option("--verbose", "Enable verbose output").option("--no-color", "Disable color output").option("--reveal", "Show secrets in plain text (TTY only)").option("--timeout <ms>", "Request timeout in milliseconds", parseInt).option("--debug", "Enable debug diagnostics").option("--no-interactive", "Disable REPL and prompt-driven interactions").addHelpCommand(false).allowExcessArguments(true).exitOverride((err) => {
|
|
2506
|
+
).option("--x402", "Use x402 wallet-based gateway auth").option("--wallet-key-file <path>", "Path to wallet private key file for x402").option("--json", "Force JSON output (auto-enabled when piped)").option("-q, --quiet", "Suppress non-essential output").option("--verbose", "Enable verbose output").option("--no-color", "Disable color output").option("--reveal", "Show secrets in plain text (TTY only)").option("--timeout <ms>", "Request timeout in milliseconds", parseInt).option("--debug", "Enable debug diagnostics").option("--no-interactive", "Disable REPL and prompt-driven interactions").addHelpCommand(false).allowExcessArguments(true).exitOverride((err) => {
|
|
1922
2507
|
if (err.code === "commander.help" || err.code === "commander.helpDisplayed" || err.code === "commander.version") {
|
|
1923
2508
|
process.exit(0);
|
|
1924
2509
|
}
|
|
@@ -2031,6 +2616,14 @@ ${styledLine}`;
|
|
|
2031
2616
|
}).addHelpText("beforeAll", () => isHelpInvocation ? brandedHelp() : "").addHelpText("after", () => {
|
|
2032
2617
|
if (isJSONMode()) return "";
|
|
2033
2618
|
return [
|
|
2619
|
+
"",
|
|
2620
|
+
`${hBrand("\u25C6")} ${hBold("Quick Start")}`,
|
|
2621
|
+
` ${hDim("\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500")}`,
|
|
2622
|
+
` ${hBrand("alchemy")} ${hDim("Interactive mode with guided setup")}`,
|
|
2623
|
+
` ${hBrand("alchemy balance")} ${hDim("<address>")} ${hDim("Get native token balance")}`,
|
|
2624
|
+
` ${hBrand("alchemy block latest")} ${hDim("Latest block summary")}`,
|
|
2625
|
+
` ${hBrand("alchemy rpc eth_chainId")} ${hDim("Raw JSON-RPC call")}`,
|
|
2626
|
+
` ${hBrand("alchemy config list")} ${hDim("View current configuration")}`,
|
|
2034
2627
|
"",
|
|
2035
2628
|
`${hBrand("\u25C6")} ${hBold("Exit Codes")}`,
|
|
2036
2629
|
` ${hDim("\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500")}`,
|
|
@@ -2086,7 +2679,7 @@ ${styledLine}`;
|
|
|
2086
2679
|
if (isInteractiveAllowed(program)) {
|
|
2087
2680
|
let latestForInteractiveStartup = null;
|
|
2088
2681
|
if (shouldRunOnboarding(program, cfg)) {
|
|
2089
|
-
const { runOnboarding } = await import("./onboarding-
|
|
2682
|
+
const { runOnboarding } = await import("./onboarding-MUJF5QIE.js");
|
|
2090
2683
|
const latest = getAvailableUpdateOnce();
|
|
2091
2684
|
const completed = await runOnboarding(program, latest);
|
|
2092
2685
|
updateShownDuringInteractiveStartup = Boolean(latest);
|
|
@@ -2098,7 +2691,7 @@ ${styledLine}`;
|
|
|
2098
2691
|
latestForInteractiveStartup = getAvailableUpdateOnce();
|
|
2099
2692
|
updateShownDuringInteractiveStartup = Boolean(latestForInteractiveStartup);
|
|
2100
2693
|
}
|
|
2101
|
-
const { startREPL } = await import("./interactive-
|
|
2694
|
+
const { startREPL } = await import("./interactive-BFAXB5SN.js");
|
|
2102
2695
|
program.exitOverride();
|
|
2103
2696
|
program.configureOutput({
|
|
2104
2697
|
writeErr: () => {
|
|
@@ -2112,9 +2705,12 @@ ${styledLine}`;
|
|
|
2112
2705
|
registerRPC(program);
|
|
2113
2706
|
registerBalance(program);
|
|
2114
2707
|
registerTx(program);
|
|
2708
|
+
registerReceipt(program);
|
|
2115
2709
|
registerBlock(program);
|
|
2116
2710
|
registerTrace(program);
|
|
2117
2711
|
registerDebug(program);
|
|
2712
|
+
registerGas(program);
|
|
2713
|
+
registerLogs(program);
|
|
2118
2714
|
registerTokens(program);
|
|
2119
2715
|
registerNFTs(program);
|
|
2120
2716
|
registerTransfers(program);
|
|
@@ -2126,12 +2722,12 @@ registerBundler(program);
|
|
|
2126
2722
|
registerGasManager(program);
|
|
2127
2723
|
registerWebhooks(program);
|
|
2128
2724
|
registerNetwork(program);
|
|
2129
|
-
registerChains(program);
|
|
2130
2725
|
registerApps(program);
|
|
2131
2726
|
registerSetup(program);
|
|
2132
2727
|
registerConfig(program);
|
|
2133
2728
|
registerSolana(program);
|
|
2134
2729
|
registerAgentPrompt(program);
|
|
2730
|
+
registerCompletions(program);
|
|
2135
2731
|
registerUpdateCheck(program);
|
|
2136
2732
|
registerVersion(program);
|
|
2137
2733
|
program.command("help [command...]").description("display help for command").action((commandPath) => {
|