@alchemy/cli 0.3.1 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/auth-7E33EMAI.js +13 -0
- package/dist/auth-E26YCAJV.js +23 -0
- package/dist/chunk-44OGGLN4.js +681 -0
- package/dist/chunk-56ZVYB4G.js +536 -0
- package/dist/{chunk-QDDJ3OYO.js → chunk-5X6YRTPU.js} +15 -5
- package/dist/chunk-DUQFOLLZ.js +118 -0
- package/dist/chunk-IGD4NIK7.js +300 -0
- package/dist/chunk-LYUW7O6X.js +231 -0
- package/dist/chunk-T2XSNZE3.js +1398 -0
- package/dist/index.js +417 -204
- package/dist/{interactive-CLPT5QDZ.js → interactive-K7XOS6U6.js} +12 -7
- package/dist/{onboarding-XNAWN5BR.js → onboarding-F5PZMFZU.js} +57 -15
- package/package.json +1 -1
- package/dist/chunk-6XTLILDF.js +0 -1246
- package/dist/chunk-J6RZM4CJ.js +0 -1333
package/dist/index.js
CHANGED
|
@@ -1,37 +1,66 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
if(process.argv.includes("--no-color"))process.env.NO_COLOR="1";
|
|
3
3
|
import {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
4
|
+
registerAuth
|
|
5
|
+
} from "./chunk-LYUW7O6X.js";
|
|
6
|
+
import "./chunk-IGD4NIK7.js";
|
|
7
|
+
import {
|
|
7
8
|
readStdinArg,
|
|
9
|
+
readStdinLines,
|
|
8
10
|
registerConfig,
|
|
9
11
|
registerWallet,
|
|
10
|
-
resolveAPIKey,
|
|
11
12
|
resolveAddress,
|
|
12
|
-
resolveAppId,
|
|
13
|
-
resolveConfiguredNetworkSlugs,
|
|
14
|
-
resolveNetwork,
|
|
15
13
|
splitCommaList,
|
|
16
14
|
validateAddress,
|
|
17
15
|
validateTxHash
|
|
18
|
-
} from "./chunk-
|
|
16
|
+
} from "./chunk-44OGGLN4.js";
|
|
19
17
|
import {
|
|
20
18
|
getRPCNetworks,
|
|
21
19
|
getSetupStatus,
|
|
22
20
|
isSetupComplete,
|
|
23
21
|
nativeTokenSymbol,
|
|
24
22
|
shouldRunOnboarding
|
|
25
|
-
} from "./chunk-
|
|
23
|
+
} from "./chunk-5X6YRTPU.js";
|
|
26
24
|
import {
|
|
27
|
-
|
|
28
|
-
|
|
25
|
+
getAvailableUpdate,
|
|
26
|
+
getUpdateStatus,
|
|
27
|
+
printUpdateNotice
|
|
28
|
+
} from "./chunk-DUQFOLLZ.js";
|
|
29
|
+
import {
|
|
30
|
+
adminClientFromFlags,
|
|
29
31
|
bold,
|
|
30
32
|
brand,
|
|
31
33
|
brandedHelp,
|
|
32
|
-
|
|
34
|
+
clientFromFlags,
|
|
33
35
|
dim,
|
|
34
36
|
emptyState,
|
|
37
|
+
etherscanTxURL,
|
|
38
|
+
failBadge,
|
|
39
|
+
green,
|
|
40
|
+
isInteractiveAllowed,
|
|
41
|
+
load,
|
|
42
|
+
maskIf,
|
|
43
|
+
printKeyValueBox,
|
|
44
|
+
printSyntaxJSON,
|
|
45
|
+
printTable,
|
|
46
|
+
promptConfirm,
|
|
47
|
+
promptSelect,
|
|
48
|
+
red,
|
|
49
|
+
resolveAPIKey,
|
|
50
|
+
resolveAppId,
|
|
51
|
+
resolveNetwork,
|
|
52
|
+
resolveX402Client,
|
|
53
|
+
save,
|
|
54
|
+
successBadge,
|
|
55
|
+
timeAgo,
|
|
56
|
+
weiToEth,
|
|
57
|
+
withSpinner
|
|
58
|
+
} from "./chunk-T2XSNZE3.js";
|
|
59
|
+
import {
|
|
60
|
+
EXIT_CODES,
|
|
61
|
+
ErrorCode,
|
|
62
|
+
debug,
|
|
63
|
+
errAppRequired,
|
|
35
64
|
errAuthRequired,
|
|
36
65
|
errInvalidAPIKey,
|
|
37
66
|
errInvalidArgs,
|
|
@@ -40,37 +69,20 @@ import {
|
|
|
40
69
|
errRateLimited,
|
|
41
70
|
errSetupRequired,
|
|
42
71
|
esc,
|
|
43
|
-
etherscanTxURL,
|
|
44
72
|
exitWithError,
|
|
45
|
-
|
|
73
|
+
fetchWithTimeout,
|
|
46
74
|
formatCommanderError,
|
|
47
|
-
|
|
48
|
-
getUpdateStatus,
|
|
49
|
-
green,
|
|
75
|
+
getBaseDomain,
|
|
50
76
|
identity,
|
|
51
|
-
isInteractiveAllowed,
|
|
52
77
|
isJSONMode,
|
|
53
|
-
load,
|
|
54
|
-
maskIf,
|
|
55
78
|
noColor,
|
|
56
79
|
printHuman,
|
|
57
80
|
printJSON,
|
|
58
|
-
printKeyValueBox,
|
|
59
|
-
printSyntaxJSON,
|
|
60
|
-
printTable,
|
|
61
|
-
printUpdateNotice,
|
|
62
|
-
promptConfirm,
|
|
63
|
-
promptSelect,
|
|
64
81
|
quiet,
|
|
65
|
-
red,
|
|
66
82
|
setFlags,
|
|
67
83
|
setNoColor,
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
verbose,
|
|
71
|
-
weiToEth,
|
|
72
|
-
withSpinner
|
|
73
|
-
} from "./chunk-6XTLILDF.js";
|
|
84
|
+
verbose
|
|
85
|
+
} from "./chunk-56ZVYB4G.js";
|
|
74
86
|
|
|
75
87
|
// src/index.ts
|
|
76
88
|
import { Command, Help } from "commander";
|
|
@@ -108,6 +120,54 @@ Examples:
|
|
|
108
120
|
}
|
|
109
121
|
|
|
110
122
|
// src/commands/balance.ts
|
|
123
|
+
async function fetchBalance(program2, addressInput, blockParam) {
|
|
124
|
+
const client = clientFromFlags(program2);
|
|
125
|
+
const address = await resolveAddress(addressInput, client);
|
|
126
|
+
const result = await withSpinner(
|
|
127
|
+
"Fetching balance\u2026",
|
|
128
|
+
"Balance fetched",
|
|
129
|
+
() => client.call("eth_getBalance", [address, blockParam])
|
|
130
|
+
);
|
|
131
|
+
const wei = BigInt(result);
|
|
132
|
+
const network = resolveNetwork(program2);
|
|
133
|
+
const symbol = nativeTokenSymbol(network);
|
|
134
|
+
if (isJSONMode()) {
|
|
135
|
+
printJSON({
|
|
136
|
+
address,
|
|
137
|
+
wei: wei.toString(),
|
|
138
|
+
balance: weiToEth(wei),
|
|
139
|
+
symbol,
|
|
140
|
+
network
|
|
141
|
+
});
|
|
142
|
+
} else {
|
|
143
|
+
printKeyValueBox([
|
|
144
|
+
["Address", address],
|
|
145
|
+
["Balance", green(`${weiToEth(wei)} ${symbol}`)],
|
|
146
|
+
["Network", network]
|
|
147
|
+
]);
|
|
148
|
+
if (verbose) {
|
|
149
|
+
console.log("");
|
|
150
|
+
printJSON({
|
|
151
|
+
rpcMethod: "eth_getBalance",
|
|
152
|
+
rpcParams: [address, blockParam],
|
|
153
|
+
rpcResult: result
|
|
154
|
+
});
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
function resolveBlockParam(block) {
|
|
159
|
+
let blockParam = block ?? "latest";
|
|
160
|
+
if (blockParam !== "latest" && blockParam !== "earliest" && blockParam !== "pending") {
|
|
161
|
+
if (!blockParam.startsWith("0x")) {
|
|
162
|
+
const num = parseInt(blockParam, 10);
|
|
163
|
+
if (isNaN(num) || num < 0) {
|
|
164
|
+
throw errInvalidArgs("Block must be a number, hex, or tag (latest, earliest, pending).");
|
|
165
|
+
}
|
|
166
|
+
blockParam = `0x${num.toString(16)}`;
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
return blockParam;
|
|
170
|
+
}
|
|
111
171
|
function registerBalance(program2) {
|
|
112
172
|
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(
|
|
113
173
|
"after",
|
|
@@ -117,51 +177,21 @@ Examples:
|
|
|
117
177
|
alchemy balance 0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045 -n polygon-mainnet
|
|
118
178
|
echo 0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045 | alchemy balance
|
|
119
179
|
alchemy balance 0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045 --block 15537393
|
|
120
|
-
alchemy balance vitalik.eth
|
|
180
|
+
alchemy balance vitalik.eth
|
|
181
|
+
cat addresses.txt | alchemy balance`
|
|
121
182
|
).option("--block <block>", "Block number, hex, or tag (default: latest)").action(async (addressArg, opts) => {
|
|
122
183
|
try {
|
|
123
|
-
const
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
if (blockParam !== "latest" && blockParam !== "earliest" && blockParam !== "pending") {
|
|
128
|
-
if (!blockParam.startsWith("0x")) {
|
|
129
|
-
const num = parseInt(blockParam, 10);
|
|
130
|
-
if (isNaN(num) || num < 0) {
|
|
131
|
-
throw errInvalidArgs("Block must be a number, hex, or tag (latest, earliest, pending).");
|
|
132
|
-
}
|
|
133
|
-
blockParam = `0x${num.toString(16)}`;
|
|
134
|
-
}
|
|
184
|
+
const blockParam = resolveBlockParam(opts?.block);
|
|
185
|
+
if (addressArg) {
|
|
186
|
+
await fetchBalance(program2, addressArg, blockParam);
|
|
187
|
+
return;
|
|
135
188
|
}
|
|
136
|
-
const
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
const network = resolveNetwork(program2);
|
|
143
|
-
const symbol = nativeTokenSymbol(network);
|
|
144
|
-
if (isJSONMode()) {
|
|
145
|
-
printJSON({
|
|
146
|
-
address,
|
|
147
|
-
wei: wei.toString(),
|
|
148
|
-
balance: weiToEth(wei),
|
|
149
|
-
symbol,
|
|
150
|
-
network
|
|
151
|
-
});
|
|
152
|
-
} else {
|
|
153
|
-
printKeyValueBox([
|
|
154
|
-
["Address", address],
|
|
155
|
-
["Balance", green(`${weiToEth(wei)} ${symbol}`)],
|
|
156
|
-
["Network", network]
|
|
157
|
-
]);
|
|
158
|
-
if (verbose) {
|
|
159
|
-
console.log("");
|
|
160
|
-
printJSON({
|
|
161
|
-
rpcMethod: "eth_getBalance",
|
|
162
|
-
rpcParams: [address, "latest"],
|
|
163
|
-
rpcResult: result
|
|
164
|
-
});
|
|
189
|
+
const lines = await readStdinLines("address");
|
|
190
|
+
for (const line of lines) {
|
|
191
|
+
try {
|
|
192
|
+
await fetchBalance(program2, line, blockParam);
|
|
193
|
+
} catch (err) {
|
|
194
|
+
exitWithError(err);
|
|
165
195
|
}
|
|
166
196
|
}
|
|
167
197
|
} catch (err) {
|
|
@@ -239,29 +269,28 @@ function formatGasSummary(gasUsed, gasLimit, options) {
|
|
|
239
269
|
|
|
240
270
|
// src/commands/tx.ts
|
|
241
271
|
function registerTx(program2) {
|
|
242
|
-
program2.command("tx").argument("[hash]", "Transaction hash (0x...) or pipe via stdin").description("Get transaction details by hash").addHelpText(
|
|
272
|
+
program2.command("tx").argument("[hash]", "Transaction hash (0x...) or pipe via stdin").description("Get transaction details by hash (use 'receipt' for receipt data)").addHelpText(
|
|
243
273
|
"after",
|
|
244
274
|
`
|
|
245
275
|
Examples:
|
|
246
276
|
alchemy tx 0xabc123...
|
|
247
|
-
echo 0xabc123... | alchemy tx
|
|
277
|
+
echo 0xabc123... | alchemy tx
|
|
278
|
+
|
|
279
|
+
Tip: use 'alchemy receipt <hash>' to get the transaction receipt (status, gas used, logs).`
|
|
248
280
|
).action(async (hashArg) => {
|
|
249
281
|
try {
|
|
250
282
|
const hash = hashArg ?? await readStdinArg("hash");
|
|
251
283
|
validateTxHash(hash);
|
|
252
284
|
const client = clientFromFlags(program2);
|
|
253
|
-
const
|
|
285
|
+
const tx = await withSpinner("Fetching transaction\u2026", "Transaction fetched", async () => {
|
|
254
286
|
const t = await client.call("eth_getTransactionByHash", [
|
|
255
287
|
hash
|
|
256
288
|
]);
|
|
257
289
|
if (!t) throw errNotFound(`transaction ${hash}`);
|
|
258
|
-
|
|
259
|
-
hash
|
|
260
|
-
]);
|
|
261
|
-
return [t, r];
|
|
290
|
+
return t;
|
|
262
291
|
});
|
|
263
292
|
if (isJSONMode()) {
|
|
264
|
-
printJSON(
|
|
293
|
+
printJSON(tx);
|
|
265
294
|
return;
|
|
266
295
|
}
|
|
267
296
|
const network = resolveNetwork(program2);
|
|
@@ -277,20 +306,13 @@ Examples:
|
|
|
277
306
|
const formatted = formatHexWithRaw(tx.blockNumber);
|
|
278
307
|
pairs.push(["Block", formatted ?? String(tx.blockNumber)]);
|
|
279
308
|
}
|
|
280
|
-
if (
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
const formatted = formatHexWithRaw(receipt.gasUsed);
|
|
288
|
-
pairs.push(["Gas Used", formatted ?? String(receipt.gasUsed)]);
|
|
289
|
-
}
|
|
290
|
-
if (receipt.effectiveGasPrice) {
|
|
291
|
-
const formatted = formatGweiWithRaw(receipt.effectiveGasPrice);
|
|
292
|
-
pairs.push(["Gas Price", formatted ?? String(receipt.effectiveGasPrice)]);
|
|
293
|
-
}
|
|
309
|
+
if (tx.nonce) {
|
|
310
|
+
const formatted = formatHexWithRaw(tx.nonce);
|
|
311
|
+
pairs.push(["Nonce", formatted ?? String(tx.nonce)]);
|
|
312
|
+
}
|
|
313
|
+
if (tx.gasPrice) {
|
|
314
|
+
const formatted = formatGweiWithRaw(tx.gasPrice);
|
|
315
|
+
pairs.push(["Gas Price", formatted ?? String(tx.gasPrice)]);
|
|
294
316
|
}
|
|
295
317
|
const explorerURL = etherscanTxURL(hash, network);
|
|
296
318
|
if (explorerURL) {
|
|
@@ -299,7 +321,7 @@ Examples:
|
|
|
299
321
|
printKeyValueBox(pairs);
|
|
300
322
|
if (verbose) {
|
|
301
323
|
console.log("");
|
|
302
|
-
printJSON(
|
|
324
|
+
printJSON(tx);
|
|
303
325
|
}
|
|
304
326
|
} catch (err) {
|
|
305
327
|
exitWithError(err);
|
|
@@ -314,7 +336,9 @@ function registerReceipt(program2) {
|
|
|
314
336
|
`
|
|
315
337
|
Examples:
|
|
316
338
|
alchemy receipt 0xabc123...
|
|
317
|
-
echo 0xabc123... | alchemy receipt
|
|
339
|
+
echo 0xabc123... | alchemy receipt
|
|
340
|
+
|
|
341
|
+
Tip: use 'alchemy tx <hash>' for transaction details (value, block, nonce). Receipt provides execution results (status, gas used, logs).`
|
|
318
342
|
).action(async (hashArg) => {
|
|
319
343
|
try {
|
|
320
344
|
const hash = hashArg ?? await readStdinArg("hash");
|
|
@@ -598,11 +622,13 @@ async function promptTokensPagination() {
|
|
|
598
622
|
if (action === null) return "stop";
|
|
599
623
|
return action;
|
|
600
624
|
}
|
|
601
|
-
function
|
|
602
|
-
|
|
625
|
+
function filterNonZero(balances) {
|
|
626
|
+
return balances.filter(
|
|
603
627
|
(tb) => tb.tokenBalance !== "0x0" && tb.tokenBalance !== "0x0000000000000000000000000000000000000000000000000000000000000000"
|
|
604
628
|
);
|
|
605
|
-
|
|
629
|
+
}
|
|
630
|
+
function formatTokenRows(balances) {
|
|
631
|
+
return filterNonZero(balances).map((tb) => {
|
|
606
632
|
let decimalBalance = dim("unparseable");
|
|
607
633
|
try {
|
|
608
634
|
decimalBalance = BigInt(tb.tokenBalance).toString();
|
|
@@ -611,15 +637,72 @@ function formatTokenRows(balances) {
|
|
|
611
637
|
return [tb.contractAddress, decimalBalance, tb.tokenBalance];
|
|
612
638
|
});
|
|
613
639
|
}
|
|
640
|
+
function formatWithDecimals(rawBalance, decimals) {
|
|
641
|
+
if (decimals === null || decimals === 0) {
|
|
642
|
+
try {
|
|
643
|
+
return BigInt(rawBalance).toString();
|
|
644
|
+
} catch {
|
|
645
|
+
return rawBalance;
|
|
646
|
+
}
|
|
647
|
+
}
|
|
648
|
+
try {
|
|
649
|
+
const raw = BigInt(rawBalance);
|
|
650
|
+
const divisor = 10n ** BigInt(decimals);
|
|
651
|
+
const whole = raw / divisor;
|
|
652
|
+
const remainder = raw % divisor;
|
|
653
|
+
if (remainder === 0n) return whole.toString();
|
|
654
|
+
const fracStr = remainder.toString().padStart(decimals, "0").replace(/0+$/, "");
|
|
655
|
+
return `${whole}.${fracStr}`;
|
|
656
|
+
} catch {
|
|
657
|
+
return rawBalance;
|
|
658
|
+
}
|
|
659
|
+
}
|
|
660
|
+
async function resolveMetadata(client, balances) {
|
|
661
|
+
const nonZero = filterNonZero(balances);
|
|
662
|
+
const results = await Promise.all(
|
|
663
|
+
nonZero.map(async (tb) => {
|
|
664
|
+
try {
|
|
665
|
+
const meta = await client.call("alchemy_getTokenMetadata", [tb.contractAddress]);
|
|
666
|
+
return [tb.contractAddress, meta];
|
|
667
|
+
} catch {
|
|
668
|
+
return [tb.contractAddress, { name: null, symbol: null, decimals: null, logo: null }];
|
|
669
|
+
}
|
|
670
|
+
})
|
|
671
|
+
);
|
|
672
|
+
return new Map(results);
|
|
673
|
+
}
|
|
674
|
+
function formatResolvedRows(balances, metadata) {
|
|
675
|
+
return filterNonZero(balances).map((tb) => {
|
|
676
|
+
const meta = metadata.get(tb.contractAddress);
|
|
677
|
+
const symbol = meta?.symbol ?? "???";
|
|
678
|
+
const formatted = formatWithDecimals(tb.tokenBalance, meta?.decimals ?? null);
|
|
679
|
+
return [tb.contractAddress, symbol, `${formatted} ${symbol}`];
|
|
680
|
+
});
|
|
681
|
+
}
|
|
682
|
+
function formatResolvedJSON(balances, metadata) {
|
|
683
|
+
return filterNonZero(balances).map((tb) => {
|
|
684
|
+
const meta = metadata.get(tb.contractAddress);
|
|
685
|
+
return {
|
|
686
|
+
contractAddress: tb.contractAddress,
|
|
687
|
+
tokenBalance: tb.tokenBalance,
|
|
688
|
+
...meta?.symbol && { symbol: meta.symbol },
|
|
689
|
+
...meta?.name && { name: meta.name },
|
|
690
|
+
...meta?.decimals !== null && meta?.decimals !== void 0 && { decimals: meta.decimals },
|
|
691
|
+
...meta?.decimals !== null && meta?.decimals !== void 0 && {
|
|
692
|
+
formattedBalance: formatWithDecimals(tb.tokenBalance, meta.decimals)
|
|
693
|
+
}
|
|
694
|
+
};
|
|
695
|
+
});
|
|
696
|
+
}
|
|
614
697
|
function registerTokens(program2) {
|
|
615
|
-
const cmd = program2.command("tokens").description("Token API wrappers")
|
|
698
|
+
const cmd = program2.command("tokens").description("Token API wrappers");
|
|
699
|
+
cmd.command("balances").argument("[address]", "Wallet address or ENS name, or pipe via stdin").description("Get ERC-20 token balances for an address").option("--page-key <key>", "Pagination key from a previous response").option("--metadata", "Fetch token metadata (symbol, decimals) and show formatted balances").addHelpText(
|
|
616
700
|
"after",
|
|
617
701
|
`
|
|
618
702
|
Examples:
|
|
619
|
-
alchemy tokens 0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045
|
|
620
|
-
alchemy tokens metadata
|
|
621
|
-
|
|
622
|
-
echo 0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045 | alchemy tokens`
|
|
703
|
+
alchemy tokens balances 0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045
|
|
704
|
+
alchemy tokens balances 0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045 --metadata
|
|
705
|
+
echo 0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045 | alchemy tokens balances`
|
|
623
706
|
).action(async (addressArg, opts) => {
|
|
624
707
|
try {
|
|
625
708
|
const addressInput = addressArg ?? await readStdinArg("address");
|
|
@@ -634,24 +717,50 @@ Examples:
|
|
|
634
717
|
"Token balances fetched",
|
|
635
718
|
() => client.call("alchemy_getTokenBalances", params)
|
|
636
719
|
);
|
|
637
|
-
|
|
638
|
-
|
|
720
|
+
const nonZero = filterNonZero(result.tokenBalances);
|
|
721
|
+
if (nonZero.length === 0) {
|
|
722
|
+
if (isJSONMode()) {
|
|
723
|
+
printJSON(result);
|
|
724
|
+
} else {
|
|
725
|
+
emptyState("No token balances found.");
|
|
726
|
+
}
|
|
639
727
|
return;
|
|
640
728
|
}
|
|
641
|
-
const
|
|
642
|
-
|
|
643
|
-
|
|
729
|
+
const metadata = opts.metadata ? await withSpinner(
|
|
730
|
+
`Resolving metadata for ${nonZero.length} tokens\u2026`,
|
|
731
|
+
"Metadata resolved",
|
|
732
|
+
() => resolveMetadata(client, result.tokenBalances)
|
|
733
|
+
) : null;
|
|
734
|
+
if (isJSONMode()) {
|
|
735
|
+
if (metadata) {
|
|
736
|
+
printJSON({
|
|
737
|
+
address: result.address,
|
|
738
|
+
tokenBalances: formatResolvedJSON(result.tokenBalances, metadata),
|
|
739
|
+
...result.pageKey && { pageKey: result.pageKey }
|
|
740
|
+
});
|
|
741
|
+
} else {
|
|
742
|
+
printJSON(result);
|
|
743
|
+
}
|
|
644
744
|
return;
|
|
645
745
|
}
|
|
646
|
-
let totalShown =
|
|
746
|
+
let totalShown = nonZero.length;
|
|
647
747
|
printKeyValueBox([
|
|
648
748
|
["Address", address],
|
|
649
749
|
["Network", client.network],
|
|
650
750
|
["Tokens", String(totalShown)]
|
|
651
751
|
]);
|
|
652
|
-
|
|
752
|
+
if (metadata) {
|
|
753
|
+
const rows = formatResolvedRows(result.tokenBalances, metadata);
|
|
754
|
+
printTable(["Contract", "Symbol", "Balance"], rows);
|
|
755
|
+
} else {
|
|
756
|
+
const rows = formatTokenRows(result.tokenBalances);
|
|
757
|
+
printTable(["Contract", "Balance (base units)", "Raw (hex)"], rows);
|
|
758
|
+
}
|
|
653
759
|
console.log(`
|
|
654
760
|
${dim(`${totalShown} tokens (zero balances hidden).`)}`);
|
|
761
|
+
if (!metadata) {
|
|
762
|
+
console.log(` ${dim("Tip: use --metadata to fetch token symbols, decimals, and show formatted balances.")}`);
|
|
763
|
+
}
|
|
655
764
|
if (verbose) {
|
|
656
765
|
console.log("");
|
|
657
766
|
printJSON(result);
|
|
@@ -674,10 +783,21 @@ Examples:
|
|
|
674
783
|
printJSON(nextResult);
|
|
675
784
|
return;
|
|
676
785
|
}
|
|
677
|
-
const
|
|
678
|
-
totalShown +=
|
|
679
|
-
if (
|
|
680
|
-
|
|
786
|
+
const nextNonZero = filterNonZero(nextResult.tokenBalances);
|
|
787
|
+
totalShown += nextNonZero.length;
|
|
788
|
+
if (nextNonZero.length > 0) {
|
|
789
|
+
if (metadata) {
|
|
790
|
+
const nextMeta = await withSpinner(
|
|
791
|
+
`Resolving metadata for ${nextNonZero.length} tokens\u2026`,
|
|
792
|
+
"Metadata resolved",
|
|
793
|
+
() => resolveMetadata(client, nextResult.tokenBalances)
|
|
794
|
+
);
|
|
795
|
+
const rows = formatResolvedRows(nextResult.tokenBalances, nextMeta);
|
|
796
|
+
printTable(["Contract", "Symbol", "Balance"], rows);
|
|
797
|
+
} else {
|
|
798
|
+
const rows = formatTokenRows(nextResult.tokenBalances);
|
|
799
|
+
printTable(["Contract", "Balance (base units)", "Raw (hex)"], rows);
|
|
800
|
+
}
|
|
681
801
|
}
|
|
682
802
|
console.log(`
|
|
683
803
|
${dim(`${totalShown} tokens total (zero balances hidden).`)}`);
|
|
@@ -691,7 +811,12 @@ Examples:
|
|
|
691
811
|
exitWithError(err);
|
|
692
812
|
}
|
|
693
813
|
});
|
|
694
|
-
cmd.command("metadata <contract>").description("Get ERC-20 token metadata").
|
|
814
|
+
cmd.command("metadata <contract>").description("Get ERC-20 token metadata (name, symbol, decimals, logo)").addHelpText(
|
|
815
|
+
"after",
|
|
816
|
+
`
|
|
817
|
+
Examples:
|
|
818
|
+
alchemy tokens metadata 0xA0b86991c6218b36c1d19d4a2e9eb0ce3606eB48`
|
|
819
|
+
).action(async (contract) => {
|
|
695
820
|
try {
|
|
696
821
|
validateAddress(contract);
|
|
697
822
|
const client = clientFromFlags(program2);
|
|
@@ -715,11 +840,11 @@ Examples:
|
|
|
715
840
|
const result = await withSpinner(
|
|
716
841
|
"Fetching token allowance\u2026",
|
|
717
842
|
"Token allowance fetched",
|
|
718
|
-
() => client.call("alchemy_getTokenAllowance", [
|
|
719
|
-
opts.owner,
|
|
720
|
-
opts.spender,
|
|
721
|
-
opts.contract
|
|
722
|
-
])
|
|
843
|
+
() => client.call("alchemy_getTokenAllowance", [{
|
|
844
|
+
owner: opts.owner,
|
|
845
|
+
spender: opts.spender,
|
|
846
|
+
contract: opts.contract
|
|
847
|
+
}])
|
|
723
848
|
);
|
|
724
849
|
if (isJSONMode()) printJSON(result);
|
|
725
850
|
else printSyntaxJSON(result);
|
|
@@ -732,34 +857,22 @@ Examples:
|
|
|
732
857
|
// src/commands/network.ts
|
|
733
858
|
function registerNetwork(program2) {
|
|
734
859
|
const cmd = program2.command("network").description("Manage networks");
|
|
735
|
-
cmd.command("list").description("List RPC network IDs for use with --network (e.g. eth-mainnet)").option(
|
|
736
|
-
"--configured",
|
|
737
|
-
"List only configured app RPC networks (requires access key and app context)"
|
|
738
|
-
).option(
|
|
739
|
-
"--app-id <id>",
|
|
740
|
-
"App ID for configured network lookups (overrides saved app)"
|
|
741
|
-
).action(async (opts) => {
|
|
860
|
+
cmd.command("list").description("List RPC network IDs for use with --network (e.g. eth-mainnet)").option("--mainnet-only", "Show only mainnet networks").option("--testnet-only", "Show only testnet networks").option("--search <term>", "Filter networks by name or ID").action(async (opts) => {
|
|
742
861
|
try {
|
|
743
|
-
|
|
862
|
+
let display = getRPCNetworks();
|
|
744
863
|
const current = resolveNetwork(program2);
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
() =>
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
864
|
+
if (opts.mainnetOnly) {
|
|
865
|
+
display = display.filter((n) => !n.isTestnet);
|
|
866
|
+
} else if (opts.testnetOnly) {
|
|
867
|
+
display = display.filter((n) => n.isTestnet);
|
|
868
|
+
}
|
|
869
|
+
if (opts.search) {
|
|
870
|
+
const term = opts.search.toLowerCase();
|
|
871
|
+
display = display.filter(
|
|
872
|
+
(n) => n.id.toLowerCase().includes(term) || n.name.toLowerCase().includes(term) || n.family.toLowerCase().includes(term)
|
|
873
|
+
);
|
|
874
|
+
}
|
|
753
875
|
if (isJSONMode()) {
|
|
754
|
-
if (configured) {
|
|
755
|
-
printJSON({
|
|
756
|
-
mode: "configured",
|
|
757
|
-
appId,
|
|
758
|
-
configuredNetworkIds: configured,
|
|
759
|
-
networks: display
|
|
760
|
-
});
|
|
761
|
-
return;
|
|
762
|
-
}
|
|
763
876
|
printJSON(display);
|
|
764
877
|
return;
|
|
765
878
|
}
|
|
@@ -771,23 +884,18 @@ function registerNetwork(program2) {
|
|
|
771
884
|
return [idCell, nameCell, network.family, testnetCell];
|
|
772
885
|
});
|
|
773
886
|
printTable(["Network ID", "Name", "Family", "Testnet"], rows);
|
|
774
|
-
if (configured) {
|
|
775
|
-
console.log(
|
|
776
|
-
`
|
|
777
|
-
${dim(`Configured networks for app ${appId}: ${display.length}`)}`
|
|
778
|
-
);
|
|
779
|
-
}
|
|
780
887
|
console.log(`
|
|
781
888
|
Current: ${green(current)}`);
|
|
782
889
|
console.log(
|
|
783
890
|
` ${dim("Need Admin API chain identifiers (e.g. ETH_MAINNET)? See: apps chains")}`
|
|
784
891
|
);
|
|
892
|
+
console.log(
|
|
893
|
+
` ${dim("Need configured networks for an app? See: apps networks")}`
|
|
894
|
+
);
|
|
785
895
|
if (verbose) {
|
|
786
896
|
console.log("");
|
|
787
897
|
printJSON({
|
|
788
|
-
mode:
|
|
789
|
-
appId: appId ?? null,
|
|
790
|
-
configuredNetworkIds: configured ?? null,
|
|
898
|
+
mode: "all",
|
|
791
899
|
networks: display,
|
|
792
900
|
currentNetwork: current
|
|
793
901
|
});
|
|
@@ -1182,6 +1290,95 @@ function registerApps(program2) {
|
|
|
1182
1290
|
exitWithError(err);
|
|
1183
1291
|
}
|
|
1184
1292
|
});
|
|
1293
|
+
cmd.command("configured-networks").description("List RPC network slugs configured for an app").option("--app-id <id>", "App ID (overrides saved app)").action(async (opts) => {
|
|
1294
|
+
try {
|
|
1295
|
+
const admin = adminClientFromFlags(program2);
|
|
1296
|
+
const appId = opts.appId || resolveAppId(program2);
|
|
1297
|
+
if (!appId) throw errAppRequired();
|
|
1298
|
+
const app = await withSpinner(
|
|
1299
|
+
"Fetching app\u2026",
|
|
1300
|
+
"App fetched",
|
|
1301
|
+
() => admin.getApp(appId)
|
|
1302
|
+
);
|
|
1303
|
+
const slugs = app.chainNetworks.map((n) => {
|
|
1304
|
+
const match = n.rpcUrl?.match(/^https:\/\/([^.]+)\.g\.alchemy\.com(?:\/|$)/);
|
|
1305
|
+
return match ? match[1] : null;
|
|
1306
|
+
}).filter((s) => Boolean(s));
|
|
1307
|
+
const uniqueSlugs = Array.from(new Set(slugs)).sort();
|
|
1308
|
+
if (isJSONMode()) {
|
|
1309
|
+
printJSON({ appId: app.id, appName: app.name, networks: uniqueSlugs });
|
|
1310
|
+
return;
|
|
1311
|
+
}
|
|
1312
|
+
if (uniqueSlugs.length === 0) {
|
|
1313
|
+
emptyState(`No RPC networks configured for ${app.name}.`);
|
|
1314
|
+
return;
|
|
1315
|
+
}
|
|
1316
|
+
const rows = uniqueSlugs.map((slug) => [slug]);
|
|
1317
|
+
printTable(["Network ID"], rows);
|
|
1318
|
+
console.log(`
|
|
1319
|
+
${dim(`${uniqueSlugs.length} networks configured for ${app.name} (${app.id})`)}`);
|
|
1320
|
+
} catch (err) {
|
|
1321
|
+
exitWithError(err);
|
|
1322
|
+
}
|
|
1323
|
+
});
|
|
1324
|
+
cmd.command("select [id]").description("Select an app to use as the default").action(async (id) => {
|
|
1325
|
+
try {
|
|
1326
|
+
const admin = adminClientFromFlags(program2);
|
|
1327
|
+
let selected;
|
|
1328
|
+
if (id) {
|
|
1329
|
+
selected = await withSpinner(
|
|
1330
|
+
"Fetching app\u2026",
|
|
1331
|
+
"App fetched",
|
|
1332
|
+
() => admin.getApp(id)
|
|
1333
|
+
);
|
|
1334
|
+
} else {
|
|
1335
|
+
const result = await withSpinner(
|
|
1336
|
+
"Fetching apps\u2026",
|
|
1337
|
+
"Apps fetched",
|
|
1338
|
+
() => admin.listAllApps()
|
|
1339
|
+
);
|
|
1340
|
+
if (result.apps.length === 0) {
|
|
1341
|
+
emptyState("No apps found.");
|
|
1342
|
+
return;
|
|
1343
|
+
}
|
|
1344
|
+
if (isJSONMode()) {
|
|
1345
|
+
printJSON({ apps: result.apps.map(maskAppSecrets) });
|
|
1346
|
+
return;
|
|
1347
|
+
}
|
|
1348
|
+
const appId = await promptSelect({
|
|
1349
|
+
message: "Select an app",
|
|
1350
|
+
options: result.apps.map((app) => ({
|
|
1351
|
+
value: app.id,
|
|
1352
|
+
label: app.name,
|
|
1353
|
+
hint: `${app.chainNetworks.length} networks`
|
|
1354
|
+
})),
|
|
1355
|
+
cancelMessage: "Cancelled app selection."
|
|
1356
|
+
});
|
|
1357
|
+
if (!appId) return;
|
|
1358
|
+
const found = result.apps.find((a) => a.id === appId);
|
|
1359
|
+
if (!found) return;
|
|
1360
|
+
selected = found;
|
|
1361
|
+
}
|
|
1362
|
+
const cfg = load();
|
|
1363
|
+
save({
|
|
1364
|
+
...cfg,
|
|
1365
|
+
app: {
|
|
1366
|
+
id: selected.id,
|
|
1367
|
+
name: selected.name,
|
|
1368
|
+
apiKey: selected.apiKey,
|
|
1369
|
+
webhookApiKey: selected.webhookApiKey
|
|
1370
|
+
}
|
|
1371
|
+
});
|
|
1372
|
+
if (isJSONMode()) {
|
|
1373
|
+
printJSON(maskAppSecrets(selected));
|
|
1374
|
+
return;
|
|
1375
|
+
}
|
|
1376
|
+
console.log(` ${green("\u2713")} Selected app: ${selected.name}`);
|
|
1377
|
+
console.log(` ${dim("Saved to config")}`);
|
|
1378
|
+
} catch (err) {
|
|
1379
|
+
exitWithError(err);
|
|
1380
|
+
}
|
|
1381
|
+
});
|
|
1185
1382
|
cmd.command("chains").description("List Admin API chain identifiers for app configuration (e.g. ETH_MAINNET)").action(async () => {
|
|
1186
1383
|
try {
|
|
1187
1384
|
const admin = adminClientFromFlags(program2);
|
|
@@ -1471,13 +1668,13 @@ async function requestJSON(url, options) {
|
|
|
1471
1668
|
}
|
|
1472
1669
|
async function callApiData(apiKey, path, options = {}) {
|
|
1473
1670
|
if (!apiKey) throw errAuthRequired();
|
|
1474
|
-
const base = new URL(`https://api.g
|
|
1671
|
+
const base = new URL(`https://api.g.${getBaseDomain()}/data/v1/${apiKey}/`);
|
|
1475
1672
|
const url = withQuery(new URL(path.replace(/^\//, ""), base), options.query);
|
|
1476
1673
|
return requestJSON(url, { ...options, path });
|
|
1477
1674
|
}
|
|
1478
1675
|
async function callApiPrices(apiKey, path, options = {}) {
|
|
1479
1676
|
if (!apiKey) throw errAuthRequired();
|
|
1480
|
-
const base = new URL(`https://api.g
|
|
1677
|
+
const base = new URL(`https://api.g.${getBaseDomain()}/prices/v1/${apiKey}/`);
|
|
1481
1678
|
const url = withQuery(new URL(path.replace(/^\//, ""), base), options.query);
|
|
1482
1679
|
return requestJSON(url, { ...options, path });
|
|
1483
1680
|
}
|
|
@@ -1487,7 +1684,7 @@ async function callNotify(token, path, options = {}) {
|
|
|
1487
1684
|
"Webhook API key required. Set ALCHEMY_WEBHOOK_API_KEY (or ALCHEMY_NOTIFY_AUTH_TOKEN) or pass --webhook-api-key."
|
|
1488
1685
|
);
|
|
1489
1686
|
}
|
|
1490
|
-
const base = new URL(
|
|
1687
|
+
const base = new URL(`https://dashboard.${getBaseDomain()}/api/`);
|
|
1491
1688
|
const url = withQuery(new URL(path.replace(/^\//, ""), base), options.query);
|
|
1492
1689
|
return requestJSON(url, {
|
|
1493
1690
|
...options,
|
|
@@ -1504,14 +1701,14 @@ function registerPrices(program2) {
|
|
|
1504
1701
|
const cmd = program2.command("prices").description("Prices API wrappers");
|
|
1505
1702
|
cmd.command("symbol <symbols>").description("Get spot prices by symbol (comma-separated)").action(async (symbols) => {
|
|
1506
1703
|
try {
|
|
1507
|
-
const apiKey = resolveAPIKey(program2);
|
|
1508
1704
|
const values = splitCommaList(symbols);
|
|
1509
1705
|
const query = new URLSearchParams();
|
|
1510
1706
|
for (const symbol of values) query.append("symbols", symbol);
|
|
1707
|
+
const x402 = resolveX402Client(program2);
|
|
1511
1708
|
const result = await withSpinner(
|
|
1512
1709
|
"Fetching prices\u2026",
|
|
1513
1710
|
"Prices fetched",
|
|
1514
|
-
() => callApiPrices(
|
|
1711
|
+
() => x402 ? x402.callRest(`prices/v1/tokens/by-symbol?${query.toString()}`) : callApiPrices(resolveAPIKey(program2), `/tokens/by-symbol?${query.toString()}`)
|
|
1515
1712
|
);
|
|
1516
1713
|
if (isJSONMode()) printJSON(result);
|
|
1517
1714
|
else printSyntaxJSON(result);
|
|
@@ -1521,12 +1718,12 @@ function registerPrices(program2) {
|
|
|
1521
1718
|
});
|
|
1522
1719
|
cmd.command("address").description("Get spot prices by token addresses").requiredOption("--addresses <json>", "JSON array of {network,address}").action(async (opts) => {
|
|
1523
1720
|
try {
|
|
1524
|
-
const apiKey = resolveAPIKey(program2);
|
|
1525
1721
|
const body = { addresses: JSON.parse(opts.addresses) };
|
|
1722
|
+
const x402 = resolveX402Client(program2);
|
|
1526
1723
|
const result = await withSpinner(
|
|
1527
1724
|
"Fetching prices\u2026",
|
|
1528
1725
|
"Prices fetched",
|
|
1529
|
-
() => callApiPrices(
|
|
1726
|
+
() => x402 ? x402.callRest("prices/v1/tokens/by-address", { method: "POST", body }) : callApiPrices(resolveAPIKey(program2), "/tokens/by-address", { method: "POST", body })
|
|
1530
1727
|
);
|
|
1531
1728
|
if (isJSONMode()) printJSON(result);
|
|
1532
1729
|
else printSyntaxJSON(result);
|
|
@@ -1534,14 +1731,20 @@ function registerPrices(program2) {
|
|
|
1534
1731
|
exitWithError(err);
|
|
1535
1732
|
}
|
|
1536
1733
|
});
|
|
1537
|
-
cmd.command("historical").description("Get historical prices").requiredOption("--body <json>", "JSON request payload").
|
|
1734
|
+
cmd.command("historical").description("Get historical prices").requiredOption("--body <json>", "JSON request payload").addHelpText(
|
|
1735
|
+
"after",
|
|
1736
|
+
`
|
|
1737
|
+
Examples:
|
|
1738
|
+
alchemy prices historical --body '{"symbol":"ETH","startTime":"2024-01-01T00:00:00Z","endTime":"2024-01-02T00:00:00Z","interval":"1h"}'
|
|
1739
|
+
alchemy prices historical --body '{"address":"0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48","network":"eth-mainnet","startTime":"2024-06-01","endTime":"2024-06-07","interval":"1d"}'`
|
|
1740
|
+
).action(async (opts) => {
|
|
1538
1741
|
try {
|
|
1539
|
-
const apiKey = resolveAPIKey(program2);
|
|
1540
1742
|
const payload = JSON.parse(opts.body);
|
|
1743
|
+
const x402 = resolveX402Client(program2);
|
|
1541
1744
|
const result = await withSpinner(
|
|
1542
1745
|
"Fetching historical prices\u2026",
|
|
1543
1746
|
"Historical prices fetched",
|
|
1544
|
-
() => callApiPrices(
|
|
1747
|
+
() => x402 ? x402.callRest("prices/v1/tokens/historical", { method: "POST", body: payload }) : callApiPrices(resolveAPIKey(program2), "/tokens/historical", { method: "POST", body: payload })
|
|
1545
1748
|
);
|
|
1546
1749
|
if (isJSONMode()) printJSON(result);
|
|
1547
1750
|
else printSyntaxJSON(result);
|
|
@@ -1552,20 +1755,20 @@ function registerPrices(program2) {
|
|
|
1552
1755
|
}
|
|
1553
1756
|
|
|
1554
1757
|
// src/commands/portfolio.ts
|
|
1555
|
-
async function runDataCall(
|
|
1758
|
+
async function runDataCall(program2, title, path, body) {
|
|
1759
|
+
const x402 = resolveX402Client(program2);
|
|
1556
1760
|
return withSpinner(
|
|
1557
1761
|
`Fetching ${title}\u2026`,
|
|
1558
1762
|
`${title} fetched`,
|
|
1559
|
-
() => callApiData(
|
|
1763
|
+
() => x402 ? x402.callRest(`data/v1${path}`, { method: "POST", body }) : callApiData(resolveAPIKey(program2), path, { method: "POST", body })
|
|
1560
1764
|
);
|
|
1561
1765
|
}
|
|
1562
1766
|
function registerPortfolio(program2) {
|
|
1563
1767
|
const cmd = program2.command("portfolio").description("Portfolio API wrappers");
|
|
1564
1768
|
cmd.command("tokens").description("Get token portfolio by address/network pairs").requiredOption("--body <json>", "JSON body for /assets/tokens/by-address").action(async (opts) => {
|
|
1565
1769
|
try {
|
|
1566
|
-
const apiKey = resolveAPIKey(program2);
|
|
1567
1770
|
const result = await runDataCall(
|
|
1568
|
-
|
|
1771
|
+
program2,
|
|
1569
1772
|
"token portfolio",
|
|
1570
1773
|
"/assets/tokens/by-address",
|
|
1571
1774
|
JSON.parse(opts.body)
|
|
@@ -1578,9 +1781,8 @@ function registerPortfolio(program2) {
|
|
|
1578
1781
|
});
|
|
1579
1782
|
cmd.command("token-balances").description("Get token balances by address/network pairs").requiredOption("--body <json>", "JSON body for /assets/tokens/balances/by-address").action(async (opts) => {
|
|
1580
1783
|
try {
|
|
1581
|
-
const apiKey = resolveAPIKey(program2);
|
|
1582
1784
|
const result = await runDataCall(
|
|
1583
|
-
|
|
1785
|
+
program2,
|
|
1584
1786
|
"token balances",
|
|
1585
1787
|
"/assets/tokens/balances/by-address",
|
|
1586
1788
|
JSON.parse(opts.body)
|
|
@@ -1593,9 +1795,8 @@ function registerPortfolio(program2) {
|
|
|
1593
1795
|
});
|
|
1594
1796
|
cmd.command("nfts").description("Get NFT portfolio by address/network pairs").requiredOption("--body <json>", "JSON body for /assets/nfts/by-address").action(async (opts) => {
|
|
1595
1797
|
try {
|
|
1596
|
-
const apiKey = resolveAPIKey(program2);
|
|
1597
1798
|
const result = await runDataCall(
|
|
1598
|
-
|
|
1799
|
+
program2,
|
|
1599
1800
|
"NFT portfolio",
|
|
1600
1801
|
"/assets/nfts/by-address",
|
|
1601
1802
|
JSON.parse(opts.body)
|
|
@@ -1608,9 +1809,8 @@ function registerPortfolio(program2) {
|
|
|
1608
1809
|
});
|
|
1609
1810
|
cmd.command("nft-contracts").description("Get NFT contracts by address/network pairs").requiredOption("--body <json>", "JSON body for /assets/nfts/contracts/by-address").action(async (opts) => {
|
|
1610
1811
|
try {
|
|
1611
|
-
const apiKey = resolveAPIKey(program2);
|
|
1612
1812
|
const result = await runDataCall(
|
|
1613
|
-
|
|
1813
|
+
program2,
|
|
1614
1814
|
"NFT contracts",
|
|
1615
1815
|
"/assets/nfts/contracts/by-address",
|
|
1616
1816
|
JSON.parse(opts.body)
|
|
@@ -1621,21 +1821,6 @@ function registerPortfolio(program2) {
|
|
|
1621
1821
|
exitWithError(err);
|
|
1622
1822
|
}
|
|
1623
1823
|
});
|
|
1624
|
-
cmd.command("transactions").description("Get transaction history by address/network pairs").requiredOption("--body <json>", "JSON body for /transactions/history/by-address").action(async (opts) => {
|
|
1625
|
-
try {
|
|
1626
|
-
const apiKey = resolveAPIKey(program2);
|
|
1627
|
-
const result = await runDataCall(
|
|
1628
|
-
apiKey,
|
|
1629
|
-
"transaction history",
|
|
1630
|
-
"/transactions/history/by-address",
|
|
1631
|
-
JSON.parse(opts.body)
|
|
1632
|
-
);
|
|
1633
|
-
if (isJSONMode()) printJSON(result);
|
|
1634
|
-
else printSyntaxJSON(result);
|
|
1635
|
-
} catch (err) {
|
|
1636
|
-
exitWithError(err);
|
|
1637
|
-
}
|
|
1638
|
-
});
|
|
1639
1824
|
}
|
|
1640
1825
|
|
|
1641
1826
|
// src/commands/simulate.ts
|
|
@@ -1714,15 +1899,24 @@ function registerWebhooks(program2) {
|
|
|
1714
1899
|
exitWithError(err);
|
|
1715
1900
|
}
|
|
1716
1901
|
});
|
|
1717
|
-
cmd.command("create").description("Create webhook").requiredOption("--body <json>", "Create webhook JSON payload").action(async (opts) => {
|
|
1902
|
+
cmd.command("create").description("Create webhook").requiredOption("--body <json>", "Create webhook JSON payload").option("--dry-run", "Preview without executing").action(async (opts) => {
|
|
1718
1903
|
try {
|
|
1904
|
+
const payload = parseRequiredJSON(opts.body, "--body");
|
|
1905
|
+
if (opts.dryRun) {
|
|
1906
|
+
if (isJSONMode()) printJSON({ dryRun: true, action: "create-webhook", payload });
|
|
1907
|
+
else {
|
|
1908
|
+
console.log(` ${dim("Dry run:")} Would create webhook`);
|
|
1909
|
+
printSyntaxJSON(payload);
|
|
1910
|
+
}
|
|
1911
|
+
return;
|
|
1912
|
+
}
|
|
1719
1913
|
const token = resolveWebhookApiKey(cmd.opts());
|
|
1720
1914
|
const result = await withSpinner(
|
|
1721
1915
|
"Creating webhook\u2026",
|
|
1722
1916
|
"Webhook created",
|
|
1723
1917
|
() => callNotify(token, "/create-webhook", {
|
|
1724
1918
|
method: "POST",
|
|
1725
|
-
body:
|
|
1919
|
+
body: payload
|
|
1726
1920
|
})
|
|
1727
1921
|
);
|
|
1728
1922
|
if (isJSONMode()) printJSON(result);
|
|
@@ -1731,15 +1925,24 @@ function registerWebhooks(program2) {
|
|
|
1731
1925
|
exitWithError(err);
|
|
1732
1926
|
}
|
|
1733
1927
|
});
|
|
1734
|
-
cmd.command("update").description("Update webhook").requiredOption("--body <json>", "Update webhook JSON payload").action(async (opts) => {
|
|
1928
|
+
cmd.command("update").description("Update webhook").requiredOption("--body <json>", "Update webhook JSON payload").option("--dry-run", "Preview without executing").action(async (opts) => {
|
|
1735
1929
|
try {
|
|
1930
|
+
const payload = parseRequiredJSON(opts.body, "--body");
|
|
1931
|
+
if (opts.dryRun) {
|
|
1932
|
+
if (isJSONMode()) printJSON({ dryRun: true, action: "update-webhook", payload });
|
|
1933
|
+
else {
|
|
1934
|
+
console.log(` ${dim("Dry run:")} Would update webhook`);
|
|
1935
|
+
printSyntaxJSON(payload);
|
|
1936
|
+
}
|
|
1937
|
+
return;
|
|
1938
|
+
}
|
|
1736
1939
|
const token = resolveWebhookApiKey(cmd.opts());
|
|
1737
1940
|
const result = await withSpinner(
|
|
1738
1941
|
"Updating webhook\u2026",
|
|
1739
1942
|
"Webhook updated",
|
|
1740
1943
|
() => callNotify(token, "/update-webhook", {
|
|
1741
1944
|
method: "PUT",
|
|
1742
|
-
body:
|
|
1945
|
+
body: payload
|
|
1743
1946
|
})
|
|
1744
1947
|
);
|
|
1745
1948
|
if (isJSONMode()) printJSON(result);
|
|
@@ -1748,8 +1951,13 @@ function registerWebhooks(program2) {
|
|
|
1748
1951
|
exitWithError(err);
|
|
1749
1952
|
}
|
|
1750
1953
|
});
|
|
1751
|
-
cmd.command("delete <webhookId>").description("Delete webhook").option("-y, --yes", "Skip confirmation prompt").action(async (webhookId, opts) => {
|
|
1954
|
+
cmd.command("delete <webhookId>").description("Delete webhook").option("--dry-run", "Preview without executing").option("-y, --yes", "Skip confirmation prompt").action(async (webhookId, opts) => {
|
|
1752
1955
|
try {
|
|
1956
|
+
if (opts.dryRun) {
|
|
1957
|
+
if (isJSONMode()) printJSON({ dryRun: true, action: "delete-webhook", payload: { webhookId } });
|
|
1958
|
+
else console.log(` ${dim("Dry run:")} Would delete webhook ${webhookId}`);
|
|
1959
|
+
return;
|
|
1960
|
+
}
|
|
1753
1961
|
if (!opts.yes && isInteractiveAllowed(program2)) {
|
|
1754
1962
|
const proceed = await promptConfirm({
|
|
1755
1963
|
message: `Delete webhook ${webhookId}?`,
|
|
@@ -2413,8 +2621,12 @@ function formatAsSystemPrompt(payload) {
|
|
|
2413
2621
|
return lines.join("\n");
|
|
2414
2622
|
}
|
|
2415
2623
|
function registerAgentPrompt(program2) {
|
|
2416
|
-
program2.command("agent-prompt").description("Emit complete agent/automation usage instructions").action(() => {
|
|
2624
|
+
program2.command("agent-prompt").description("Emit complete agent/automation usage instructions").option("--commands <list>", "Filter to specific commands in JSON output (requires --json). Comma-separated (e.g. balance,tokens,gas)").action((opts) => {
|
|
2417
2625
|
const payload = buildAgentPrompt(program2);
|
|
2626
|
+
if (opts.commands) {
|
|
2627
|
+
const filter = new Set(opts.commands.split(",").map((s) => s.trim().toLowerCase()));
|
|
2628
|
+
payload.commands = payload.commands.filter((cmd) => filter.has(cmd.name.toLowerCase()));
|
|
2629
|
+
}
|
|
2418
2630
|
printHuman(formatAsSystemPrompt(payload), payload);
|
|
2419
2631
|
});
|
|
2420
2632
|
}
|
|
@@ -2477,7 +2689,7 @@ var ROOT_COMMAND_PILLARS = [
|
|
|
2477
2689
|
},
|
|
2478
2690
|
{
|
|
2479
2691
|
label: "Admin",
|
|
2480
|
-
commands: ["apps", "config", "setup", "completions", "agent-prompt", "update-check", "version", "help"]
|
|
2692
|
+
commands: ["apps", "auth", "config", "setup", "completions", "agent-prompt", "update-check", "version", "help"]
|
|
2481
2693
|
}
|
|
2482
2694
|
];
|
|
2483
2695
|
function formatCommandSignature(sub) {
|
|
@@ -2526,10 +2738,10 @@ function resetUpdateNoticeState() {
|
|
|
2526
2738
|
}
|
|
2527
2739
|
program.name("alchemy").description(
|
|
2528
2740
|
"The Alchemy CLI lets you query blockchain data, call JSON-RPC methods, and manage your Alchemy configuration."
|
|
2529
|
-
).version("0.
|
|
2741
|
+
).version("0.5.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(
|
|
2530
2742
|
"-n, --network <network>",
|
|
2531
2743
|
"Target network (default: eth-mainnet) (env: ALCHEMY_NETWORK)"
|
|
2532
|
-
).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
|
|
2744
|
+
).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").option("--timeout <ms>", "Request timeout in milliseconds (default: none)", parseInt).option("--debug", "Enable debug diagnostics").option("--no-interactive", "Disable REPL and prompt-driven interactions").addHelpCommand(false).allowExcessArguments(true).exitOverride((err) => {
|
|
2533
2745
|
if (err.code === "commander.help" || err.code === "commander.helpDisplayed" || err.code === "commander.version") {
|
|
2534
2746
|
process.exit(0);
|
|
2535
2747
|
}
|
|
@@ -2706,7 +2918,7 @@ ${styledLine}`;
|
|
|
2706
2918
|
if (isInteractiveAllowed(program)) {
|
|
2707
2919
|
let latestForInteractiveStartup = null;
|
|
2708
2920
|
if (shouldRunOnboarding(program, cfg)) {
|
|
2709
|
-
const { runOnboarding } = await import("./onboarding-
|
|
2921
|
+
const { runOnboarding } = await import("./onboarding-F5PZMFZU.js");
|
|
2710
2922
|
const latest = getAvailableUpdateOnce();
|
|
2711
2923
|
const completed = await runOnboarding(program, latest);
|
|
2712
2924
|
updateShownDuringInteractiveStartup = Boolean(latest);
|
|
@@ -2718,7 +2930,7 @@ ${styledLine}`;
|
|
|
2718
2930
|
latestForInteractiveStartup = getAvailableUpdateOnce();
|
|
2719
2931
|
updateShownDuringInteractiveStartup = Boolean(latestForInteractiveStartup);
|
|
2720
2932
|
}
|
|
2721
|
-
const { startREPL } = await import("./interactive-
|
|
2933
|
+
const { startREPL } = await import("./interactive-K7XOS6U6.js");
|
|
2722
2934
|
program.exitOverride();
|
|
2723
2935
|
program.configureOutput({
|
|
2724
2936
|
writeErr: () => {
|
|
@@ -2750,6 +2962,7 @@ registerGasManager(program);
|
|
|
2750
2962
|
registerWebhooks(program);
|
|
2751
2963
|
registerNetwork(program);
|
|
2752
2964
|
registerApps(program);
|
|
2965
|
+
registerAuth(program);
|
|
2753
2966
|
registerSetup(program);
|
|
2754
2967
|
registerConfig(program);
|
|
2755
2968
|
registerSolana(program);
|