@alchemy/cli 0.2.1 → 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-SDUCDSCZ.js → chunk-MF6DXNO7.js} +24 -4
- package/dist/{chunk-XP5KF4W2.js → chunk-UPQTWEPP.js} +204 -16
- package/dist/{chunk-HBRTTBCY.js → chunk-VYQ5V2ZR.js} +38 -1
- package/dist/index.js +784 -177
- package/dist/{interactive-L7N4HI7K.js → interactive-BFAXB5SN.js} +44 -10
- package/dist/{onboarding-YA32OJOT.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:
|
|
@@ -277,6 +393,9 @@ Examples:
|
|
|
277
393
|
"block must be a number, hex, or 'latest'"
|
|
278
394
|
);
|
|
279
395
|
}
|
|
396
|
+
if (num < 0) {
|
|
397
|
+
throw errInvalidArgs("Block number must be non-negative.");
|
|
398
|
+
}
|
|
280
399
|
blockParam = `0x${num.toString(16)}`;
|
|
281
400
|
}
|
|
282
401
|
const client = clientFromFlags(program2);
|
|
@@ -292,7 +411,7 @@ Examples:
|
|
|
292
411
|
}
|
|
293
412
|
const pairs = [];
|
|
294
413
|
if (block.number) {
|
|
295
|
-
const formatted =
|
|
414
|
+
const formatted = formatHexWithRaw(block.number);
|
|
296
415
|
pairs.push(["Block", bold(formatted ?? String(block.number))]);
|
|
297
416
|
}
|
|
298
417
|
if (block.hash) pairs.push(["Hash", String(block.hash)]);
|
|
@@ -310,11 +429,11 @@ Examples:
|
|
|
310
429
|
pairs.push(["Gas", gasSummary]);
|
|
311
430
|
} else {
|
|
312
431
|
if (block.gasUsed) {
|
|
313
|
-
const formatted =
|
|
432
|
+
const formatted = formatHexWithRaw(block.gasUsed);
|
|
314
433
|
pairs.push(["Gas Used", formatted ?? String(block.gasUsed)]);
|
|
315
434
|
}
|
|
316
435
|
if (block.gasLimit) {
|
|
317
|
-
const formatted =
|
|
436
|
+
const formatted = formatHexWithRaw(block.gasLimit);
|
|
318
437
|
pairs.push(["Gas Limit", formatted ?? String(block.gasLimit)]);
|
|
319
438
|
}
|
|
320
439
|
}
|
|
@@ -333,8 +452,28 @@ Examples:
|
|
|
333
452
|
}
|
|
334
453
|
|
|
335
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
|
+
}
|
|
336
475
|
function registerNFTs(program2) {
|
|
337
|
-
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(
|
|
338
477
|
"after",
|
|
339
478
|
`
|
|
340
479
|
Examples:
|
|
@@ -344,15 +483,15 @@ Examples:
|
|
|
344
483
|
echo 0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045 | alchemy nfts`
|
|
345
484
|
).action(async (addressArg, opts) => {
|
|
346
485
|
try {
|
|
347
|
-
const
|
|
348
|
-
|
|
486
|
+
const addressInput = addressArg ?? await readStdinArg("address");
|
|
487
|
+
const client = clientFromFlags(program2);
|
|
488
|
+
const address = await resolveAddress(addressInput, client);
|
|
349
489
|
const params = {
|
|
350
490
|
owner: address,
|
|
351
491
|
withMetadata: "true"
|
|
352
492
|
};
|
|
353
493
|
if (opts.limit) params.pageSize = String(opts.limit);
|
|
354
494
|
if (opts.pageKey) params.pageKey = opts.pageKey;
|
|
355
|
-
const client = clientFromFlags(program2);
|
|
356
495
|
const result = await withSpinner(
|
|
357
496
|
"Fetching NFTs\u2026",
|
|
358
497
|
"NFTs fetched",
|
|
@@ -366,19 +505,41 @@ Examples:
|
|
|
366
505
|
emptyState("No NFTs found.");
|
|
367
506
|
return;
|
|
368
507
|
}
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
nft.name || `#${nft.tokenId}`,
|
|
372
|
-
nft.contract.address
|
|
373
|
-
]);
|
|
374
|
-
printTable(["Collection", "Name", "Contract"], rows);
|
|
508
|
+
let shown = result.ownedNfts.length;
|
|
509
|
+
printTable(["Collection", "Name", "Contract"], formatNFTRows(result.ownedNfts));
|
|
375
510
|
if (verbose) {
|
|
376
511
|
console.log("");
|
|
377
512
|
printJSON(result);
|
|
378
513
|
}
|
|
379
|
-
|
|
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) {
|
|
380
541
|
console.log(`
|
|
381
|
-
${dim(`More results available. Use --page-key ${
|
|
542
|
+
${dim(`More results available. Use --page-key ${pageKey} to see the next page.`)}`);
|
|
382
543
|
}
|
|
383
544
|
} catch (err) {
|
|
384
545
|
exitWithError(err);
|
|
@@ -422,8 +583,34 @@ Examples:
|
|
|
422
583
|
}
|
|
423
584
|
|
|
424
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
|
+
}
|
|
425
612
|
function registerTokens(program2) {
|
|
426
|
-
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(
|
|
427
614
|
"after",
|
|
428
615
|
`
|
|
429
616
|
Examples:
|
|
@@ -433,13 +620,13 @@ Examples:
|
|
|
433
620
|
echo 0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045 | alchemy tokens`
|
|
434
621
|
).action(async (addressArg, opts) => {
|
|
435
622
|
try {
|
|
436
|
-
const
|
|
437
|
-
|
|
623
|
+
const addressInput = addressArg ?? await readStdinArg("address");
|
|
624
|
+
const client = clientFromFlags(program2);
|
|
625
|
+
const address = await resolveAddress(addressInput, client);
|
|
438
626
|
const params = [address];
|
|
439
627
|
if (opts.pageKey) {
|
|
440
628
|
params.push("erc20", { pageKey: opts.pageKey });
|
|
441
629
|
}
|
|
442
|
-
const client = clientFromFlags(program2);
|
|
443
630
|
const result = await withSpinner(
|
|
444
631
|
"Fetching token balances\u2026",
|
|
445
632
|
"Token balances fetched",
|
|
@@ -449,36 +636,54 @@ Examples:
|
|
|
449
636
|
printJSON(result);
|
|
450
637
|
return;
|
|
451
638
|
}
|
|
452
|
-
const
|
|
453
|
-
|
|
454
|
-
);
|
|
455
|
-
if (nonZero.length === 0) {
|
|
639
|
+
const rows = formatTokenRows(result.tokenBalances);
|
|
640
|
+
if (rows.length === 0) {
|
|
456
641
|
emptyState("No token balances found.");
|
|
457
642
|
return;
|
|
458
643
|
}
|
|
459
|
-
|
|
460
|
-
let decimalBalance = dim("unparseable");
|
|
461
|
-
try {
|
|
462
|
-
decimalBalance = BigInt(tb.tokenBalance).toString();
|
|
463
|
-
} catch {
|
|
464
|
-
}
|
|
465
|
-
return [tb.contractAddress, decimalBalance, tb.tokenBalance];
|
|
466
|
-
});
|
|
644
|
+
let totalShown = rows.length;
|
|
467
645
|
printKeyValueBox([
|
|
468
646
|
["Address", address],
|
|
469
647
|
["Network", client.network],
|
|
470
|
-
["
|
|
648
|
+
["Tokens", String(totalShown)]
|
|
471
649
|
]);
|
|
472
650
|
printTable(["Contract", "Balance (base units)", "Raw (hex)"], rows);
|
|
473
651
|
console.log(`
|
|
474
|
-
${dim(
|
|
652
|
+
${dim(`${totalShown} tokens (zero balances hidden).`)}`);
|
|
475
653
|
if (verbose) {
|
|
476
654
|
console.log("");
|
|
477
655
|
printJSON(result);
|
|
478
656
|
}
|
|
479
|
-
|
|
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
|
+
}
|
|
680
|
+
console.log(`
|
|
681
|
+
${dim(`${totalShown} tokens total (zero balances hidden).`)}`);
|
|
682
|
+
pageKey = nextResult.pageKey;
|
|
683
|
+
}
|
|
684
|
+
if (pageKey && !interactive) {
|
|
480
685
|
console.log(`
|
|
481
|
-
${dim(`More results available. Use --page-key ${
|
|
686
|
+
${dim(`More results available. Use --page-key ${pageKey} to see the next page.`)}`);
|
|
482
687
|
}
|
|
483
688
|
} catch (err) {
|
|
484
689
|
exitWithError(err);
|
|
@@ -525,7 +730,7 @@ Examples:
|
|
|
525
730
|
// src/commands/network.ts
|
|
526
731
|
function registerNetwork(program2) {
|
|
527
732
|
const cmd = program2.command("network").description("Manage networks");
|
|
528
|
-
cmd.command("list").description("List
|
|
733
|
+
cmd.command("list").description("List RPC network IDs for use with --network (e.g. eth-mainnet)").option(
|
|
529
734
|
"--configured",
|
|
530
735
|
"List only configured app RPC networks (requires access key and app context)"
|
|
531
736
|
).option(
|
|
@@ -573,7 +778,7 @@ function registerNetwork(program2) {
|
|
|
573
778
|
console.log(`
|
|
574
779
|
Current: ${green(current)}`);
|
|
575
780
|
console.log(
|
|
576
|
-
` ${dim("Need Admin API chain
|
|
781
|
+
` ${dim("Need Admin API chain identifiers (e.g. ETH_MAINNET)? See: apps chains")}`
|
|
577
782
|
);
|
|
578
783
|
if (verbose) {
|
|
579
784
|
console.log("");
|
|
@@ -600,43 +805,6 @@ function registerVersion(program2) {
|
|
|
600
805
|
});
|
|
601
806
|
}
|
|
602
807
|
|
|
603
|
-
// src/commands/chains.ts
|
|
604
|
-
function registerChains(program2) {
|
|
605
|
-
const cmd = program2.command("chains").description("Manage Admin API chain enums");
|
|
606
|
-
cmd.command("list").description("List available Admin API chain enums").action(async () => {
|
|
607
|
-
try {
|
|
608
|
-
const admin = adminClientFromFlags(program2);
|
|
609
|
-
const chains = await withSpinner(
|
|
610
|
-
"Fetching chains\u2026",
|
|
611
|
-
"Chains fetched",
|
|
612
|
-
() => admin.listChains()
|
|
613
|
-
);
|
|
614
|
-
if (isJSONMode()) {
|
|
615
|
-
printJSON(chains);
|
|
616
|
-
return;
|
|
617
|
-
}
|
|
618
|
-
if (chains.length === 0) {
|
|
619
|
-
emptyState("No chain networks were returned.");
|
|
620
|
-
return;
|
|
621
|
-
}
|
|
622
|
-
const rows = chains.map((c) => [
|
|
623
|
-
c.id,
|
|
624
|
-
c.name,
|
|
625
|
-
c.isTestnet ? dim("yes") : "no",
|
|
626
|
-
c.availability === "public" ? green(c.availability) : dim(c.availability),
|
|
627
|
-
c.currency
|
|
628
|
-
]);
|
|
629
|
-
printTable(["ID", "Name", "Testnet", "Availability", "Currency"], rows);
|
|
630
|
-
if (verbose) {
|
|
631
|
-
console.log("");
|
|
632
|
-
printJSON(chains);
|
|
633
|
-
}
|
|
634
|
-
} catch (err) {
|
|
635
|
-
exitWithError(err);
|
|
636
|
-
}
|
|
637
|
-
});
|
|
638
|
-
}
|
|
639
|
-
|
|
640
808
|
// src/commands/apps.ts
|
|
641
809
|
function maskAppSecrets(app) {
|
|
642
810
|
return {
|
|
@@ -655,19 +823,14 @@ async function promptPaginationAction() {
|
|
|
655
823
|
message: "More apps available",
|
|
656
824
|
options: [
|
|
657
825
|
{ label: "Load next page", value: "next" },
|
|
658
|
-
{ label: "Load
|
|
826
|
+
{ label: "Load next 5 pages", value: "next5" },
|
|
659
827
|
{ label: "Stop here", value: "stop" }
|
|
660
828
|
],
|
|
661
829
|
initialValue: "next",
|
|
662
830
|
cancelMessage: "Stopped pagination."
|
|
663
831
|
});
|
|
664
|
-
if (action === null)
|
|
665
|
-
|
|
666
|
-
}
|
|
667
|
-
if (action === "next" || action === "all" || action === "stop") {
|
|
668
|
-
return action;
|
|
669
|
-
}
|
|
670
|
-
return "stop";
|
|
832
|
+
if (action === null) return "stop";
|
|
833
|
+
return action;
|
|
671
834
|
}
|
|
672
835
|
function matchesSearch(app, query) {
|
|
673
836
|
const q = query.toLowerCase();
|
|
@@ -760,7 +923,7 @@ function registerApps(program2) {
|
|
|
760
923
|
const interactivePagination = isInteractiveAllowed(program2) && !opts.all;
|
|
761
924
|
if (interactivePagination) {
|
|
762
925
|
let page = result;
|
|
763
|
-
let
|
|
926
|
+
let batchRemaining = 0;
|
|
764
927
|
let pagesFetched = 0;
|
|
765
928
|
let appsFetched = 0;
|
|
766
929
|
while (true) {
|
|
@@ -777,7 +940,7 @@ function registerApps(program2) {
|
|
|
777
940
|
printFetchSummary(appsFetched, pagesFetched);
|
|
778
941
|
return;
|
|
779
942
|
}
|
|
780
|
-
if (
|
|
943
|
+
if (batchRemaining <= 0) {
|
|
781
944
|
printFetchSummary(appsFetched, pagesFetched, { suffix: "so far" });
|
|
782
945
|
const action = await promptPaginationAction();
|
|
783
946
|
if (action === "stop") {
|
|
@@ -786,9 +949,11 @@ function registerApps(program2) {
|
|
|
786
949
|
printFetchSummary(appsFetched, pagesFetched);
|
|
787
950
|
return;
|
|
788
951
|
}
|
|
789
|
-
if (action === "
|
|
790
|
-
|
|
952
|
+
if (action === "next5") {
|
|
953
|
+
batchRemaining = 4;
|
|
791
954
|
}
|
|
955
|
+
} else {
|
|
956
|
+
batchRemaining -= 1;
|
|
792
957
|
}
|
|
793
958
|
page = await withSpinner(
|
|
794
959
|
"Fetching next page\u2026",
|
|
@@ -1003,6 +1168,45 @@ function registerApps(program2) {
|
|
|
1003
1168
|
exitWithError(err);
|
|
1004
1169
|
}
|
|
1005
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
|
+
});
|
|
1006
1210
|
}
|
|
1007
1211
|
|
|
1008
1212
|
// src/commands/setup.ts
|
|
@@ -1063,7 +1267,7 @@ function normalizeTraceMethod(method) {
|
|
|
1063
1267
|
return `trace_${normalized}`;
|
|
1064
1268
|
}
|
|
1065
1269
|
function registerTrace(program2) {
|
|
1066
|
-
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) => {
|
|
1067
1271
|
try {
|
|
1068
1272
|
const client = clientFromFlags(program2);
|
|
1069
1273
|
const rpcMethod = normalizeTraceMethod(method);
|
|
@@ -1085,7 +1289,7 @@ function normalizeDebugMethod(method) {
|
|
|
1085
1289
|
return `debug_${method.replace(/-/g, "_")}`;
|
|
1086
1290
|
}
|
|
1087
1291
|
function registerDebug(program2) {
|
|
1088
|
-
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) => {
|
|
1089
1293
|
try {
|
|
1090
1294
|
const client = clientFromFlags(program2);
|
|
1091
1295
|
const rpcMethod = normalizeDebugMethod(method);
|
|
@@ -1102,29 +1306,72 @@ function registerDebug(program2) {
|
|
|
1102
1306
|
}
|
|
1103
1307
|
|
|
1104
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
|
+
}
|
|
1105
1334
|
function registerTransfers(program2) {
|
|
1106
|
-
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) => {
|
|
1107
1351
|
try {
|
|
1108
1352
|
const client = clientFromFlags(program2);
|
|
1109
|
-
const address = addressArg
|
|
1110
|
-
if (
|
|
1111
|
-
if (opts.
|
|
1112
|
-
|
|
1113
|
-
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 = {
|
|
1114
1357
|
fromBlock: opts.fromBlock ?? "0x0",
|
|
1115
1358
|
toBlock: opts.toBlock ?? "latest",
|
|
1116
|
-
withMetadata: true
|
|
1359
|
+
withMetadata: true,
|
|
1360
|
+
category: opts.category ? splitCommaList(opts.category) : ["external", "internal", "erc20", "erc721", "erc1155", "specialnft"]
|
|
1117
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 };
|
|
1118
1369
|
if (address && !opts.fromAddress && !opts.toAddress) {
|
|
1119
1370
|
filter.fromAddress = address;
|
|
1120
|
-
filter.toAddress = address;
|
|
1121
1371
|
} else {
|
|
1122
1372
|
if (opts.fromAddress) filter.fromAddress = opts.fromAddress;
|
|
1123
1373
|
if (opts.toAddress) filter.toAddress = opts.toAddress;
|
|
1124
1374
|
}
|
|
1125
|
-
if (opts.category) filter.category = splitCommaList(opts.category);
|
|
1126
|
-
if (opts.maxCount) filter.maxCount = opts.maxCount.startsWith("0x") ? opts.maxCount : `0x${Number.parseInt(opts.maxCount, 10).toString(16)}`;
|
|
1127
|
-
if (opts.pageKey) filter.pageKey = opts.pageKey;
|
|
1128
1375
|
const result = await withSpinner(
|
|
1129
1376
|
"Fetching transfers\u2026",
|
|
1130
1377
|
"Transfers fetched",
|
|
@@ -1132,8 +1379,43 @@ function registerTransfers(program2) {
|
|
|
1132
1379
|
);
|
|
1133
1380
|
if (isJSONMode()) {
|
|
1134
1381
|
printJSON(result);
|
|
1135
|
-
|
|
1136
|
-
|
|
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.`)}`);
|
|
1137
1419
|
}
|
|
1138
1420
|
} catch (err) {
|
|
1139
1421
|
exitWithError(err);
|
|
@@ -1587,7 +1869,7 @@ function registerSolana(program2) {
|
|
|
1587
1869
|
const cmd = program2.command("solana").description("Solana RPC and DAS wrappers");
|
|
1588
1870
|
cmd.command("rpc <method> [params...]").description("Call a Solana JSON-RPC method").action(async (method, params) => {
|
|
1589
1871
|
try {
|
|
1590
|
-
const client = clientFromFlags(program2);
|
|
1872
|
+
const client = clientFromFlags(program2, { defaultNetwork: "solana-mainnet" });
|
|
1591
1873
|
const result = await withSpinner(
|
|
1592
1874
|
`Calling ${method}\u2026`,
|
|
1593
1875
|
`Called ${method}`,
|
|
@@ -1598,14 +1880,15 @@ function registerSolana(program2) {
|
|
|
1598
1880
|
exitWithError(err);
|
|
1599
1881
|
}
|
|
1600
1882
|
});
|
|
1601
|
-
|
|
1602
|
-
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) => {
|
|
1603
1884
|
try {
|
|
1604
|
-
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;
|
|
1605
1888
|
const result = await withSpinner(
|
|
1606
1889
|
`Calling ${method}\u2026`,
|
|
1607
1890
|
`Called ${method}`,
|
|
1608
|
-
() => client.call(method,
|
|
1891
|
+
() => client.call(method, rpcParams)
|
|
1609
1892
|
);
|
|
1610
1893
|
printSyntaxJSON(result);
|
|
1611
1894
|
} catch (err) {
|
|
@@ -1614,6 +1897,311 @@ function registerSolana(program2) {
|
|
|
1614
1897
|
});
|
|
1615
1898
|
}
|
|
1616
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
|
+
|
|
1617
2205
|
// src/commands/agent-prompt.ts
|
|
1618
2206
|
var RETRYABLE_CODES = /* @__PURE__ */ new Set([
|
|
1619
2207
|
ErrorCode.RATE_LIMITED,
|
|
@@ -1715,7 +2303,7 @@ function buildAgentPrompt(program2) {
|
|
|
1715
2303
|
envVar: "ALCHEMY_ACCESS_KEY",
|
|
1716
2304
|
flag: "--access-key <key>",
|
|
1717
2305
|
configKey: "access-key",
|
|
1718
|
-
commandFamilies: ["apps", "
|
|
2306
|
+
commandFamilies: ["apps", "network list --configured"]
|
|
1719
2307
|
},
|
|
1720
2308
|
{
|
|
1721
2309
|
method: "Webhook API key",
|
|
@@ -1847,7 +2435,7 @@ var ROOT_OPTION_GROUPS = [
|
|
|
1847
2435
|
var ROOT_COMMAND_PILLARS = [
|
|
1848
2436
|
{
|
|
1849
2437
|
label: "Node",
|
|
1850
|
-
commands: ["balance", "tx", "block", "rpc", "trace", "debug"]
|
|
2438
|
+
commands: ["balance", "tx", "block", "rpc", "trace", "debug", "gas", "logs"]
|
|
1851
2439
|
},
|
|
1852
2440
|
{
|
|
1853
2441
|
label: "Data",
|
|
@@ -1859,11 +2447,11 @@ var ROOT_COMMAND_PILLARS = [
|
|
|
1859
2447
|
},
|
|
1860
2448
|
{
|
|
1861
2449
|
label: "Chains",
|
|
1862
|
-
commands: ["network", "
|
|
2450
|
+
commands: ["network", "solana"]
|
|
1863
2451
|
},
|
|
1864
2452
|
{
|
|
1865
2453
|
label: "Admin",
|
|
1866
|
-
commands: ["apps", "config", "setup", "agent-prompt", "update-check", "version", "help"]
|
|
2454
|
+
commands: ["apps", "config", "setup", "completions", "agent-prompt", "update-check", "version", "help"]
|
|
1867
2455
|
}
|
|
1868
2456
|
];
|
|
1869
2457
|
function formatCommandSignature(sub) {
|
|
@@ -1912,10 +2500,10 @@ function resetUpdateNoticeState() {
|
|
|
1912
2500
|
}
|
|
1913
2501
|
program.name("alchemy").description(
|
|
1914
2502
|
"The Alchemy CLI lets you query blockchain data, call JSON-RPC methods, and manage your Alchemy configuration."
|
|
1915
|
-
).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(
|
|
1916
2504
|
"-n, --network <network>",
|
|
1917
2505
|
"Target network (default: eth-mainnet) (env: ALCHEMY_NETWORK)"
|
|
1918
|
-
).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).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) => {
|
|
1919
2507
|
if (err.code === "commander.help" || err.code === "commander.helpDisplayed" || err.code === "commander.version") {
|
|
1920
2508
|
process.exit(0);
|
|
1921
2509
|
}
|
|
@@ -2028,6 +2616,14 @@ ${styledLine}`;
|
|
|
2028
2616
|
}).addHelpText("beforeAll", () => isHelpInvocation ? brandedHelp() : "").addHelpText("after", () => {
|
|
2029
2617
|
if (isJSONMode()) return "";
|
|
2030
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")}`,
|
|
2031
2627
|
"",
|
|
2032
2628
|
`${hBrand("\u25C6")} ${hBold("Exit Codes")}`,
|
|
2033
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")}`,
|
|
@@ -2067,7 +2663,15 @@ ${styledLine}`;
|
|
|
2067
2663
|
}
|
|
2068
2664
|
}
|
|
2069
2665
|
resetUpdateNoticeState();
|
|
2070
|
-
}).action(async () => {
|
|
2666
|
+
}).action(async (_opts, cmd) => {
|
|
2667
|
+
const excessArgs = cmd.args;
|
|
2668
|
+
if (excessArgs.length > 0) {
|
|
2669
|
+
exitWithError(
|
|
2670
|
+
errInvalidArgs(
|
|
2671
|
+
`Unknown command '${excessArgs[0]}'. Run 'alchemy help' for available commands.`
|
|
2672
|
+
)
|
|
2673
|
+
);
|
|
2674
|
+
}
|
|
2071
2675
|
const cfg = load();
|
|
2072
2676
|
if (!isSetupComplete(cfg) && !isInteractiveAllowed(program)) {
|
|
2073
2677
|
throw errSetupRequired(getSetupStatus(cfg));
|
|
@@ -2075,7 +2679,7 @@ ${styledLine}`;
|
|
|
2075
2679
|
if (isInteractiveAllowed(program)) {
|
|
2076
2680
|
let latestForInteractiveStartup = null;
|
|
2077
2681
|
if (shouldRunOnboarding(program, cfg)) {
|
|
2078
|
-
const { runOnboarding } = await import("./onboarding-
|
|
2682
|
+
const { runOnboarding } = await import("./onboarding-MUJF5QIE.js");
|
|
2079
2683
|
const latest = getAvailableUpdateOnce();
|
|
2080
2684
|
const completed = await runOnboarding(program, latest);
|
|
2081
2685
|
updateShownDuringInteractiveStartup = Boolean(latest);
|
|
@@ -2087,7 +2691,7 @@ ${styledLine}`;
|
|
|
2087
2691
|
latestForInteractiveStartup = getAvailableUpdateOnce();
|
|
2088
2692
|
updateShownDuringInteractiveStartup = Boolean(latestForInteractiveStartup);
|
|
2089
2693
|
}
|
|
2090
|
-
const { startREPL } = await import("./interactive-
|
|
2694
|
+
const { startREPL } = await import("./interactive-BFAXB5SN.js");
|
|
2091
2695
|
program.exitOverride();
|
|
2092
2696
|
program.configureOutput({
|
|
2093
2697
|
writeErr: () => {
|
|
@@ -2101,9 +2705,12 @@ ${styledLine}`;
|
|
|
2101
2705
|
registerRPC(program);
|
|
2102
2706
|
registerBalance(program);
|
|
2103
2707
|
registerTx(program);
|
|
2708
|
+
registerReceipt(program);
|
|
2104
2709
|
registerBlock(program);
|
|
2105
2710
|
registerTrace(program);
|
|
2106
2711
|
registerDebug(program);
|
|
2712
|
+
registerGas(program);
|
|
2713
|
+
registerLogs(program);
|
|
2107
2714
|
registerTokens(program);
|
|
2108
2715
|
registerNFTs(program);
|
|
2109
2716
|
registerTransfers(program);
|
|
@@ -2115,12 +2722,12 @@ registerBundler(program);
|
|
|
2115
2722
|
registerGasManager(program);
|
|
2116
2723
|
registerWebhooks(program);
|
|
2117
2724
|
registerNetwork(program);
|
|
2118
|
-
registerChains(program);
|
|
2119
2725
|
registerApps(program);
|
|
2120
2726
|
registerSetup(program);
|
|
2121
2727
|
registerConfig(program);
|
|
2122
2728
|
registerSolana(program);
|
|
2123
2729
|
registerAgentPrompt(program);
|
|
2730
|
+
registerCompletions(program);
|
|
2124
2731
|
registerUpdateCheck(program);
|
|
2125
2732
|
registerVersion(program);
|
|
2126
2733
|
program.command("help [command...]").description("display help for command").action((commandPath) => {
|