@alchemy/cli 0.3.0 → 0.4.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/{chunk-UPQTWEPP.js → chunk-PIWNNNMZ.js} +17 -23
- package/dist/{chunk-MF6DXNO7.js → chunk-TH75DFAY.js} +11 -6
- package/dist/{chunk-VYQ5V2ZR.js → chunk-Z3LXQFIY.js} +1 -1
- package/dist/index.js +324 -151
- package/dist/{interactive-BFAXB5SN.js → interactive-NASSNJHQ.js} +2 -2
- package/dist/{onboarding-MUJF5QIE.js → onboarding-WQ2TWDM3.js} +2 -2
- package/package.json +1 -1
|
@@ -10,7 +10,6 @@ import {
|
|
|
10
10
|
errAccessDenied,
|
|
11
11
|
errAccessKeyRequired,
|
|
12
12
|
errAdminAPI,
|
|
13
|
-
errAppRequired,
|
|
14
13
|
errAuthRequired,
|
|
15
14
|
errInvalidAPIKey,
|
|
16
15
|
errInvalidAccessKey,
|
|
@@ -43,7 +42,7 @@ import {
|
|
|
43
42
|
verbose,
|
|
44
43
|
withSpinner,
|
|
45
44
|
yellow
|
|
46
|
-
} from "./chunk-
|
|
45
|
+
} from "./chunk-TH75DFAY.js";
|
|
47
46
|
|
|
48
47
|
// src/lib/client-utils.ts
|
|
49
48
|
function isLocalhost(hostname) {
|
|
@@ -383,6 +382,21 @@ async function readStdinArg(name) {
|
|
|
383
382
|
}
|
|
384
383
|
return data;
|
|
385
384
|
}
|
|
385
|
+
async function readStdinLines(name) {
|
|
386
|
+
if (process.stdin.isTTY) {
|
|
387
|
+
throw errInvalidArgs(`Missing <${name}>. Provide it as an argument or pipe via stdin.`);
|
|
388
|
+
}
|
|
389
|
+
process.stdin.setEncoding("utf-8");
|
|
390
|
+
let input = "";
|
|
391
|
+
for await (const chunk of process.stdin) {
|
|
392
|
+
input += chunk;
|
|
393
|
+
}
|
|
394
|
+
const lines = input.split("\n").map((line) => line.trim()).filter((line) => line.length > 0);
|
|
395
|
+
if (lines.length === 0) {
|
|
396
|
+
throw errInvalidArgs(`No <${name}> received on stdin.`);
|
|
397
|
+
}
|
|
398
|
+
return lines;
|
|
399
|
+
}
|
|
386
400
|
function validateAddress(address) {
|
|
387
401
|
if (!ADDRESS_RE.test(address)) {
|
|
388
402
|
throw errInvalidArgs(
|
|
@@ -1201,26 +1215,6 @@ function clientFromFlags(program, opts) {
|
|
|
1201
1215
|
if (!apiKey) throw errAuthRequired();
|
|
1202
1216
|
return new Client(apiKey, network);
|
|
1203
1217
|
}
|
|
1204
|
-
function appNetworkToSlug(rpcUrl) {
|
|
1205
|
-
let parsed;
|
|
1206
|
-
try {
|
|
1207
|
-
parsed = new URL(rpcUrl);
|
|
1208
|
-
} catch {
|
|
1209
|
-
return null;
|
|
1210
|
-
}
|
|
1211
|
-
const suffix = ".g.alchemy.com";
|
|
1212
|
-
if (!parsed.hostname.endsWith(suffix)) return null;
|
|
1213
|
-
const slug = parsed.hostname.slice(0, -suffix.length);
|
|
1214
|
-
return slug || null;
|
|
1215
|
-
}
|
|
1216
|
-
async function resolveConfiguredNetworkSlugs(program, appIdOverride) {
|
|
1217
|
-
const appId = appIdOverride || resolveAppId(program);
|
|
1218
|
-
if (!appId) throw errAppRequired();
|
|
1219
|
-
const admin = adminClientFromFlags(program);
|
|
1220
|
-
const app = await admin.getApp(appId);
|
|
1221
|
-
const slugs = app.chainNetworks.map((network) => appNetworkToSlug(network.rpcUrl)).filter((slug) => Boolean(slug));
|
|
1222
|
-
return Array.from(new Set(slugs)).sort((a, b) => a.localeCompare(b));
|
|
1223
|
-
}
|
|
1224
1218
|
|
|
1225
1219
|
// src/commands/wallet.ts
|
|
1226
1220
|
var WALLET_KEYS_DIR = "wallet-keys";
|
|
@@ -1316,6 +1310,7 @@ export {
|
|
|
1316
1310
|
AdminClient,
|
|
1317
1311
|
splitCommaList,
|
|
1318
1312
|
readStdinArg,
|
|
1313
|
+
readStdinLines,
|
|
1319
1314
|
validateAddress,
|
|
1320
1315
|
resolveAddress,
|
|
1321
1316
|
validateTxHash,
|
|
@@ -1326,7 +1321,6 @@ export {
|
|
|
1326
1321
|
resolveAppId,
|
|
1327
1322
|
adminClientFromFlags,
|
|
1328
1323
|
clientFromFlags,
|
|
1329
|
-
resolveConfiguredNetworkSlugs,
|
|
1330
1324
|
generateAndPersistWallet,
|
|
1331
1325
|
importAndPersistWallet,
|
|
1332
1326
|
registerWallet
|
|
@@ -4,10 +4,13 @@ if(process.argv.includes("--no-color"))process.env.NO_COLOR="1";
|
|
|
4
4
|
// src/lib/colors.ts
|
|
5
5
|
var forceColor = "FORCE_COLOR" in process.env && process.env.FORCE_COLOR !== "0";
|
|
6
6
|
var noColor = !forceColor && ("NO_COLOR" in process.env || process.env.TERM === "dumb");
|
|
7
|
+
function setNoColor(value) {
|
|
8
|
+
noColor = value;
|
|
9
|
+
}
|
|
7
10
|
var identity = (s) => s;
|
|
8
|
-
var esc = (code) => noColor ?
|
|
9
|
-
var rgb = (r, g, b) => noColor ?
|
|
10
|
-
var bgRgb = (r, g, b) => noColor ?
|
|
11
|
+
var esc = (code) => (s) => noColor ? s : `\x1B[${code}m${s}\x1B[0m`;
|
|
12
|
+
var rgb = (r, g, b) => (s) => noColor ? s : `\x1B[38;2;${r};${g};${b}m${s}\x1B[39m`;
|
|
13
|
+
var bgRgb = (r, g, b) => (s) => noColor ? s : `\x1B[48;2;${r};${g};${b}m${s}\x1B[49m`;
|
|
11
14
|
|
|
12
15
|
// src/lib/redact.ts
|
|
13
16
|
var SENSITIVE_ERROR_CODES = /* @__PURE__ */ new Set([
|
|
@@ -195,7 +198,7 @@ function setFlags(opts) {
|
|
|
195
198
|
timeout = opts.timeout;
|
|
196
199
|
}
|
|
197
200
|
function isRevealMode() {
|
|
198
|
-
return reveal
|
|
201
|
+
return reveal;
|
|
199
202
|
}
|
|
200
203
|
function isJSONMode() {
|
|
201
204
|
if (forceJSON) return true;
|
|
@@ -475,7 +478,8 @@ function getHome() {
|
|
|
475
478
|
}
|
|
476
479
|
function configPath() {
|
|
477
480
|
if (process.env.ALCHEMY_CONFIG) return process.env.ALCHEMY_CONFIG;
|
|
478
|
-
|
|
481
|
+
const configHome = process.env.XDG_CONFIG_HOME || join(getHome(), ".config");
|
|
482
|
+
return join(configHome, "alchemy", "config.json");
|
|
479
483
|
}
|
|
480
484
|
function configDir() {
|
|
481
485
|
return dirname(configPath());
|
|
@@ -1110,7 +1114,7 @@ function semverLT(a, b) {
|
|
|
1110
1114
|
return false;
|
|
1111
1115
|
}
|
|
1112
1116
|
function currentVersion() {
|
|
1113
|
-
return true ? "0.
|
|
1117
|
+
return true ? "0.4.0" : "0.0.0";
|
|
1114
1118
|
}
|
|
1115
1119
|
function toUpdateStatus(latestVersion, checkedAt) {
|
|
1116
1120
|
const current = currentVersion();
|
|
@@ -1169,6 +1173,7 @@ ${getUpdateNoticeLines(latest).join("\n")}
|
|
|
1169
1173
|
|
|
1170
1174
|
export {
|
|
1171
1175
|
noColor,
|
|
1176
|
+
setNoColor,
|
|
1172
1177
|
identity,
|
|
1173
1178
|
esc,
|
|
1174
1179
|
rgb,
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
if(process.argv.includes("--no-color"))process.env.NO_COLOR="1";
|
|
3
3
|
import {
|
|
4
4
|
isInteractiveAllowed
|
|
5
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-TH75DFAY.js";
|
|
6
6
|
|
|
7
7
|
// src/lib/networks.ts
|
|
8
8
|
var TESTNET_TOKEN_RE = /(testnet|sepolia|holesky|hoodi|devnet|minato|amoy|fuji|saigon|cardona|aeneid|curtis|chiado|cassiopeia|blaze|ropsten|signet|mocha|fam|bepolia)$/i;
|
package/dist/index.js
CHANGED
|
@@ -5,24 +5,24 @@ import {
|
|
|
5
5
|
clientFromFlags,
|
|
6
6
|
fetchWithTimeout,
|
|
7
7
|
readStdinArg,
|
|
8
|
+
readStdinLines,
|
|
8
9
|
registerConfig,
|
|
9
10
|
registerWallet,
|
|
10
11
|
resolveAPIKey,
|
|
11
12
|
resolveAddress,
|
|
12
13
|
resolveAppId,
|
|
13
|
-
resolveConfiguredNetworkSlugs,
|
|
14
14
|
resolveNetwork,
|
|
15
15
|
splitCommaList,
|
|
16
16
|
validateAddress,
|
|
17
17
|
validateTxHash
|
|
18
|
-
} from "./chunk-
|
|
18
|
+
} from "./chunk-PIWNNNMZ.js";
|
|
19
19
|
import {
|
|
20
20
|
getRPCNetworks,
|
|
21
21
|
getSetupStatus,
|
|
22
22
|
isSetupComplete,
|
|
23
23
|
nativeTokenSymbol,
|
|
24
24
|
shouldRunOnboarding
|
|
25
|
-
} from "./chunk-
|
|
25
|
+
} from "./chunk-Z3LXQFIY.js";
|
|
26
26
|
import {
|
|
27
27
|
EXIT_CODES,
|
|
28
28
|
ErrorCode,
|
|
@@ -32,6 +32,7 @@ import {
|
|
|
32
32
|
debug,
|
|
33
33
|
dim,
|
|
34
34
|
emptyState,
|
|
35
|
+
errAppRequired,
|
|
35
36
|
errAuthRequired,
|
|
36
37
|
errInvalidAPIKey,
|
|
37
38
|
errInvalidArgs,
|
|
@@ -59,16 +60,18 @@ import {
|
|
|
59
60
|
printSyntaxJSON,
|
|
60
61
|
printTable,
|
|
61
62
|
printUpdateNotice,
|
|
63
|
+
promptConfirm,
|
|
62
64
|
promptSelect,
|
|
63
65
|
quiet,
|
|
64
66
|
red,
|
|
65
67
|
setFlags,
|
|
68
|
+
setNoColor,
|
|
66
69
|
successBadge,
|
|
67
70
|
timeAgo,
|
|
68
71
|
verbose,
|
|
69
72
|
weiToEth,
|
|
70
73
|
withSpinner
|
|
71
|
-
} from "./chunk-
|
|
74
|
+
} from "./chunk-TH75DFAY.js";
|
|
72
75
|
|
|
73
76
|
// src/index.ts
|
|
74
77
|
import { Command, Help } from "commander";
|
|
@@ -106,6 +109,54 @@ Examples:
|
|
|
106
109
|
}
|
|
107
110
|
|
|
108
111
|
// src/commands/balance.ts
|
|
112
|
+
async function fetchBalance(program2, addressInput, blockParam) {
|
|
113
|
+
const client = clientFromFlags(program2);
|
|
114
|
+
const address = await resolveAddress(addressInput, client);
|
|
115
|
+
const result = await withSpinner(
|
|
116
|
+
"Fetching balance\u2026",
|
|
117
|
+
"Balance fetched",
|
|
118
|
+
() => client.call("eth_getBalance", [address, blockParam])
|
|
119
|
+
);
|
|
120
|
+
const wei = BigInt(result);
|
|
121
|
+
const network = resolveNetwork(program2);
|
|
122
|
+
const symbol = nativeTokenSymbol(network);
|
|
123
|
+
if (isJSONMode()) {
|
|
124
|
+
printJSON({
|
|
125
|
+
address,
|
|
126
|
+
wei: wei.toString(),
|
|
127
|
+
balance: weiToEth(wei),
|
|
128
|
+
symbol,
|
|
129
|
+
network
|
|
130
|
+
});
|
|
131
|
+
} else {
|
|
132
|
+
printKeyValueBox([
|
|
133
|
+
["Address", address],
|
|
134
|
+
["Balance", green(`${weiToEth(wei)} ${symbol}`)],
|
|
135
|
+
["Network", network]
|
|
136
|
+
]);
|
|
137
|
+
if (verbose) {
|
|
138
|
+
console.log("");
|
|
139
|
+
printJSON({
|
|
140
|
+
rpcMethod: "eth_getBalance",
|
|
141
|
+
rpcParams: [address, blockParam],
|
|
142
|
+
rpcResult: result
|
|
143
|
+
});
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
function resolveBlockParam(block) {
|
|
148
|
+
let blockParam = block ?? "latest";
|
|
149
|
+
if (blockParam !== "latest" && blockParam !== "earliest" && blockParam !== "pending") {
|
|
150
|
+
if (!blockParam.startsWith("0x")) {
|
|
151
|
+
const num = parseInt(blockParam, 10);
|
|
152
|
+
if (isNaN(num) || num < 0) {
|
|
153
|
+
throw errInvalidArgs("Block must be a number, hex, or tag (latest, earliest, pending).");
|
|
154
|
+
}
|
|
155
|
+
blockParam = `0x${num.toString(16)}`;
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
return blockParam;
|
|
159
|
+
}
|
|
109
160
|
function registerBalance(program2) {
|
|
110
161
|
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(
|
|
111
162
|
"after",
|
|
@@ -115,51 +166,21 @@ Examples:
|
|
|
115
166
|
alchemy balance 0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045 -n polygon-mainnet
|
|
116
167
|
echo 0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045 | alchemy balance
|
|
117
168
|
alchemy balance 0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045 --block 15537393
|
|
118
|
-
alchemy balance vitalik.eth
|
|
169
|
+
alchemy balance vitalik.eth
|
|
170
|
+
cat addresses.txt | alchemy balance`
|
|
119
171
|
).option("--block <block>", "Block number, hex, or tag (default: latest)").action(async (addressArg, opts) => {
|
|
120
172
|
try {
|
|
121
|
-
const
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
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
|
-
}
|
|
173
|
+
const blockParam = resolveBlockParam(opts?.block);
|
|
174
|
+
if (addressArg) {
|
|
175
|
+
await fetchBalance(program2, addressArg, blockParam);
|
|
176
|
+
return;
|
|
133
177
|
}
|
|
134
|
-
const
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
const network = resolveNetwork(program2);
|
|
141
|
-
const symbol = nativeTokenSymbol(network);
|
|
142
|
-
if (isJSONMode()) {
|
|
143
|
-
printJSON({
|
|
144
|
-
address,
|
|
145
|
-
wei: wei.toString(),
|
|
146
|
-
balance: weiToEth(wei),
|
|
147
|
-
symbol,
|
|
148
|
-
network
|
|
149
|
-
});
|
|
150
|
-
} else {
|
|
151
|
-
printKeyValueBox([
|
|
152
|
-
["Address", address],
|
|
153
|
-
["Balance", green(`${weiToEth(wei)} ${symbol}`)],
|
|
154
|
-
["Network", network]
|
|
155
|
-
]);
|
|
156
|
-
if (verbose) {
|
|
157
|
-
console.log("");
|
|
158
|
-
printJSON({
|
|
159
|
-
rpcMethod: "eth_getBalance",
|
|
160
|
-
rpcParams: [address, "latest"],
|
|
161
|
-
rpcResult: result
|
|
162
|
-
});
|
|
178
|
+
const lines = await readStdinLines("address");
|
|
179
|
+
for (const line of lines) {
|
|
180
|
+
try {
|
|
181
|
+
await fetchBalance(program2, line, blockParam);
|
|
182
|
+
} catch (err) {
|
|
183
|
+
exitWithError(err);
|
|
163
184
|
}
|
|
164
185
|
}
|
|
165
186
|
} catch (err) {
|
|
@@ -237,29 +258,28 @@ function formatGasSummary(gasUsed, gasLimit, options) {
|
|
|
237
258
|
|
|
238
259
|
// src/commands/tx.ts
|
|
239
260
|
function registerTx(program2) {
|
|
240
|
-
program2.command("tx").argument("[hash]", "Transaction hash (0x...) or pipe via stdin").description("Get transaction details by hash").addHelpText(
|
|
261
|
+
program2.command("tx").argument("[hash]", "Transaction hash (0x...) or pipe via stdin").description("Get transaction details by hash (use 'receipt' for receipt data)").addHelpText(
|
|
241
262
|
"after",
|
|
242
263
|
`
|
|
243
264
|
Examples:
|
|
244
265
|
alchemy tx 0xabc123...
|
|
245
|
-
echo 0xabc123... | alchemy tx
|
|
266
|
+
echo 0xabc123... | alchemy tx
|
|
267
|
+
|
|
268
|
+
Tip: use 'alchemy receipt <hash>' to get the transaction receipt (status, gas used, logs).`
|
|
246
269
|
).action(async (hashArg) => {
|
|
247
270
|
try {
|
|
248
271
|
const hash = hashArg ?? await readStdinArg("hash");
|
|
249
272
|
validateTxHash(hash);
|
|
250
273
|
const client = clientFromFlags(program2);
|
|
251
|
-
const
|
|
274
|
+
const tx = await withSpinner("Fetching transaction\u2026", "Transaction fetched", async () => {
|
|
252
275
|
const t = await client.call("eth_getTransactionByHash", [
|
|
253
276
|
hash
|
|
254
277
|
]);
|
|
255
278
|
if (!t) throw errNotFound(`transaction ${hash}`);
|
|
256
|
-
|
|
257
|
-
hash
|
|
258
|
-
]);
|
|
259
|
-
return [t, r];
|
|
279
|
+
return t;
|
|
260
280
|
});
|
|
261
281
|
if (isJSONMode()) {
|
|
262
|
-
printJSON(
|
|
282
|
+
printJSON(tx);
|
|
263
283
|
return;
|
|
264
284
|
}
|
|
265
285
|
const network = resolveNetwork(program2);
|
|
@@ -275,20 +295,13 @@ Examples:
|
|
|
275
295
|
const formatted = formatHexWithRaw(tx.blockNumber);
|
|
276
296
|
pairs.push(["Block", formatted ?? String(tx.blockNumber)]);
|
|
277
297
|
}
|
|
278
|
-
if (
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
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
|
-
}
|
|
298
|
+
if (tx.nonce) {
|
|
299
|
+
const formatted = formatHexWithRaw(tx.nonce);
|
|
300
|
+
pairs.push(["Nonce", formatted ?? String(tx.nonce)]);
|
|
301
|
+
}
|
|
302
|
+
if (tx.gasPrice) {
|
|
303
|
+
const formatted = formatGweiWithRaw(tx.gasPrice);
|
|
304
|
+
pairs.push(["Gas Price", formatted ?? String(tx.gasPrice)]);
|
|
292
305
|
}
|
|
293
306
|
const explorerURL = etherscanTxURL(hash, network);
|
|
294
307
|
if (explorerURL) {
|
|
@@ -297,7 +310,7 @@ Examples:
|
|
|
297
310
|
printKeyValueBox(pairs);
|
|
298
311
|
if (verbose) {
|
|
299
312
|
console.log("");
|
|
300
|
-
printJSON(
|
|
313
|
+
printJSON(tx);
|
|
301
314
|
}
|
|
302
315
|
} catch (err) {
|
|
303
316
|
exitWithError(err);
|
|
@@ -312,7 +325,9 @@ function registerReceipt(program2) {
|
|
|
312
325
|
`
|
|
313
326
|
Examples:
|
|
314
327
|
alchemy receipt 0xabc123...
|
|
315
|
-
echo 0xabc123... | alchemy receipt
|
|
328
|
+
echo 0xabc123... | alchemy receipt
|
|
329
|
+
|
|
330
|
+
Tip: use 'alchemy tx <hash>' for transaction details (value, block, nonce). Receipt provides execution results (status, gas used, logs).`
|
|
316
331
|
).action(async (hashArg) => {
|
|
317
332
|
try {
|
|
318
333
|
const hash = hashArg ?? await readStdinArg("hash");
|
|
@@ -596,11 +611,13 @@ async function promptTokensPagination() {
|
|
|
596
611
|
if (action === null) return "stop";
|
|
597
612
|
return action;
|
|
598
613
|
}
|
|
599
|
-
function
|
|
600
|
-
|
|
614
|
+
function filterNonZero(balances) {
|
|
615
|
+
return balances.filter(
|
|
601
616
|
(tb) => tb.tokenBalance !== "0x0" && tb.tokenBalance !== "0x0000000000000000000000000000000000000000000000000000000000000000"
|
|
602
617
|
);
|
|
603
|
-
|
|
618
|
+
}
|
|
619
|
+
function formatTokenRows(balances) {
|
|
620
|
+
return filterNonZero(balances).map((tb) => {
|
|
604
621
|
let decimalBalance = dim("unparseable");
|
|
605
622
|
try {
|
|
606
623
|
decimalBalance = BigInt(tb.tokenBalance).toString();
|
|
@@ -609,15 +626,72 @@ function formatTokenRows(balances) {
|
|
|
609
626
|
return [tb.contractAddress, decimalBalance, tb.tokenBalance];
|
|
610
627
|
});
|
|
611
628
|
}
|
|
629
|
+
function formatWithDecimals(rawBalance, decimals) {
|
|
630
|
+
if (decimals === null || decimals === 0) {
|
|
631
|
+
try {
|
|
632
|
+
return BigInt(rawBalance).toString();
|
|
633
|
+
} catch {
|
|
634
|
+
return rawBalance;
|
|
635
|
+
}
|
|
636
|
+
}
|
|
637
|
+
try {
|
|
638
|
+
const raw = BigInt(rawBalance);
|
|
639
|
+
const divisor = 10n ** BigInt(decimals);
|
|
640
|
+
const whole = raw / divisor;
|
|
641
|
+
const remainder = raw % divisor;
|
|
642
|
+
if (remainder === 0n) return whole.toString();
|
|
643
|
+
const fracStr = remainder.toString().padStart(decimals, "0").replace(/0+$/, "");
|
|
644
|
+
return `${whole}.${fracStr}`;
|
|
645
|
+
} catch {
|
|
646
|
+
return rawBalance;
|
|
647
|
+
}
|
|
648
|
+
}
|
|
649
|
+
async function resolveMetadata(client, balances) {
|
|
650
|
+
const nonZero = filterNonZero(balances);
|
|
651
|
+
const results = await Promise.all(
|
|
652
|
+
nonZero.map(async (tb) => {
|
|
653
|
+
try {
|
|
654
|
+
const meta = await client.call("alchemy_getTokenMetadata", [tb.contractAddress]);
|
|
655
|
+
return [tb.contractAddress, meta];
|
|
656
|
+
} catch {
|
|
657
|
+
return [tb.contractAddress, { name: null, symbol: null, decimals: null, logo: null }];
|
|
658
|
+
}
|
|
659
|
+
})
|
|
660
|
+
);
|
|
661
|
+
return new Map(results);
|
|
662
|
+
}
|
|
663
|
+
function formatResolvedRows(balances, metadata) {
|
|
664
|
+
return filterNonZero(balances).map((tb) => {
|
|
665
|
+
const meta = metadata.get(tb.contractAddress);
|
|
666
|
+
const symbol = meta?.symbol ?? "???";
|
|
667
|
+
const formatted = formatWithDecimals(tb.tokenBalance, meta?.decimals ?? null);
|
|
668
|
+
return [tb.contractAddress, symbol, `${formatted} ${symbol}`];
|
|
669
|
+
});
|
|
670
|
+
}
|
|
671
|
+
function formatResolvedJSON(balances, metadata) {
|
|
672
|
+
return filterNonZero(balances).map((tb) => {
|
|
673
|
+
const meta = metadata.get(tb.contractAddress);
|
|
674
|
+
return {
|
|
675
|
+
contractAddress: tb.contractAddress,
|
|
676
|
+
tokenBalance: tb.tokenBalance,
|
|
677
|
+
...meta?.symbol && { symbol: meta.symbol },
|
|
678
|
+
...meta?.name && { name: meta.name },
|
|
679
|
+
...meta?.decimals !== null && meta?.decimals !== void 0 && { decimals: meta.decimals },
|
|
680
|
+
...meta?.decimals !== null && meta?.decimals !== void 0 && {
|
|
681
|
+
formattedBalance: formatWithDecimals(tb.tokenBalance, meta.decimals)
|
|
682
|
+
}
|
|
683
|
+
};
|
|
684
|
+
});
|
|
685
|
+
}
|
|
612
686
|
function registerTokens(program2) {
|
|
613
|
-
const cmd = program2.command("tokens").description("Token API wrappers")
|
|
687
|
+
const cmd = program2.command("tokens").description("Token API wrappers");
|
|
688
|
+
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(
|
|
614
689
|
"after",
|
|
615
690
|
`
|
|
616
691
|
Examples:
|
|
617
|
-
alchemy tokens 0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045
|
|
618
|
-
alchemy tokens metadata
|
|
619
|
-
|
|
620
|
-
echo 0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045 | alchemy tokens`
|
|
692
|
+
alchemy tokens balances 0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045
|
|
693
|
+
alchemy tokens balances 0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045 --metadata
|
|
694
|
+
echo 0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045 | alchemy tokens balances`
|
|
621
695
|
).action(async (addressArg, opts) => {
|
|
622
696
|
try {
|
|
623
697
|
const addressInput = addressArg ?? await readStdinArg("address");
|
|
@@ -632,24 +706,50 @@ Examples:
|
|
|
632
706
|
"Token balances fetched",
|
|
633
707
|
() => client.call("alchemy_getTokenBalances", params)
|
|
634
708
|
);
|
|
635
|
-
|
|
636
|
-
|
|
709
|
+
const nonZero = filterNonZero(result.tokenBalances);
|
|
710
|
+
if (nonZero.length === 0) {
|
|
711
|
+
if (isJSONMode()) {
|
|
712
|
+
printJSON(result);
|
|
713
|
+
} else {
|
|
714
|
+
emptyState("No token balances found.");
|
|
715
|
+
}
|
|
637
716
|
return;
|
|
638
717
|
}
|
|
639
|
-
const
|
|
640
|
-
|
|
641
|
-
|
|
718
|
+
const metadata = opts.metadata ? await withSpinner(
|
|
719
|
+
`Resolving metadata for ${nonZero.length} tokens\u2026`,
|
|
720
|
+
"Metadata resolved",
|
|
721
|
+
() => resolveMetadata(client, result.tokenBalances)
|
|
722
|
+
) : null;
|
|
723
|
+
if (isJSONMode()) {
|
|
724
|
+
if (metadata) {
|
|
725
|
+
printJSON({
|
|
726
|
+
address: result.address,
|
|
727
|
+
tokenBalances: formatResolvedJSON(result.tokenBalances, metadata),
|
|
728
|
+
...result.pageKey && { pageKey: result.pageKey }
|
|
729
|
+
});
|
|
730
|
+
} else {
|
|
731
|
+
printJSON(result);
|
|
732
|
+
}
|
|
642
733
|
return;
|
|
643
734
|
}
|
|
644
|
-
let totalShown =
|
|
735
|
+
let totalShown = nonZero.length;
|
|
645
736
|
printKeyValueBox([
|
|
646
737
|
["Address", address],
|
|
647
738
|
["Network", client.network],
|
|
648
739
|
["Tokens", String(totalShown)]
|
|
649
740
|
]);
|
|
650
|
-
|
|
741
|
+
if (metadata) {
|
|
742
|
+
const rows = formatResolvedRows(result.tokenBalances, metadata);
|
|
743
|
+
printTable(["Contract", "Symbol", "Balance"], rows);
|
|
744
|
+
} else {
|
|
745
|
+
const rows = formatTokenRows(result.tokenBalances);
|
|
746
|
+
printTable(["Contract", "Balance (base units)", "Raw (hex)"], rows);
|
|
747
|
+
}
|
|
651
748
|
console.log(`
|
|
652
749
|
${dim(`${totalShown} tokens (zero balances hidden).`)}`);
|
|
750
|
+
if (!metadata) {
|
|
751
|
+
console.log(` ${dim("Tip: use --metadata to fetch token symbols, decimals, and show formatted balances.")}`);
|
|
752
|
+
}
|
|
653
753
|
if (verbose) {
|
|
654
754
|
console.log("");
|
|
655
755
|
printJSON(result);
|
|
@@ -672,10 +772,21 @@ Examples:
|
|
|
672
772
|
printJSON(nextResult);
|
|
673
773
|
return;
|
|
674
774
|
}
|
|
675
|
-
const
|
|
676
|
-
totalShown +=
|
|
677
|
-
if (
|
|
678
|
-
|
|
775
|
+
const nextNonZero = filterNonZero(nextResult.tokenBalances);
|
|
776
|
+
totalShown += nextNonZero.length;
|
|
777
|
+
if (nextNonZero.length > 0) {
|
|
778
|
+
if (metadata) {
|
|
779
|
+
const nextMeta = await withSpinner(
|
|
780
|
+
`Resolving metadata for ${nextNonZero.length} tokens\u2026`,
|
|
781
|
+
"Metadata resolved",
|
|
782
|
+
() => resolveMetadata(client, nextResult.tokenBalances)
|
|
783
|
+
);
|
|
784
|
+
const rows = formatResolvedRows(nextResult.tokenBalances, nextMeta);
|
|
785
|
+
printTable(["Contract", "Symbol", "Balance"], rows);
|
|
786
|
+
} else {
|
|
787
|
+
const rows = formatTokenRows(nextResult.tokenBalances);
|
|
788
|
+
printTable(["Contract", "Balance (base units)", "Raw (hex)"], rows);
|
|
789
|
+
}
|
|
679
790
|
}
|
|
680
791
|
console.log(`
|
|
681
792
|
${dim(`${totalShown} tokens total (zero balances hidden).`)}`);
|
|
@@ -689,7 +800,12 @@ Examples:
|
|
|
689
800
|
exitWithError(err);
|
|
690
801
|
}
|
|
691
802
|
});
|
|
692
|
-
cmd.command("metadata <contract>").description("Get ERC-20 token metadata").
|
|
803
|
+
cmd.command("metadata <contract>").description("Get ERC-20 token metadata (name, symbol, decimals, logo)").addHelpText(
|
|
804
|
+
"after",
|
|
805
|
+
`
|
|
806
|
+
Examples:
|
|
807
|
+
alchemy tokens metadata 0xA0b86991c6218b36c1d19d4a2e9eb0ce3606eB48`
|
|
808
|
+
).action(async (contract) => {
|
|
693
809
|
try {
|
|
694
810
|
validateAddress(contract);
|
|
695
811
|
const client = clientFromFlags(program2);
|
|
@@ -730,34 +846,22 @@ Examples:
|
|
|
730
846
|
// src/commands/network.ts
|
|
731
847
|
function registerNetwork(program2) {
|
|
732
848
|
const cmd = program2.command("network").description("Manage networks");
|
|
733
|
-
cmd.command("list").description("List RPC network IDs for use with --network (e.g. eth-mainnet)").option(
|
|
734
|
-
"--configured",
|
|
735
|
-
"List only configured app RPC networks (requires access key and app context)"
|
|
736
|
-
).option(
|
|
737
|
-
"--app-id <id>",
|
|
738
|
-
"App ID for configured network lookups (overrides saved app)"
|
|
739
|
-
).action(async (opts) => {
|
|
849
|
+
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) => {
|
|
740
850
|
try {
|
|
741
|
-
|
|
851
|
+
let display = getRPCNetworks();
|
|
742
852
|
const current = resolveNetwork(program2);
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
() =>
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
853
|
+
if (opts.mainnetOnly) {
|
|
854
|
+
display = display.filter((n) => !n.isTestnet);
|
|
855
|
+
} else if (opts.testnetOnly) {
|
|
856
|
+
display = display.filter((n) => n.isTestnet);
|
|
857
|
+
}
|
|
858
|
+
if (opts.search) {
|
|
859
|
+
const term = opts.search.toLowerCase();
|
|
860
|
+
display = display.filter(
|
|
861
|
+
(n) => n.id.toLowerCase().includes(term) || n.name.toLowerCase().includes(term) || n.family.toLowerCase().includes(term)
|
|
862
|
+
);
|
|
863
|
+
}
|
|
751
864
|
if (isJSONMode()) {
|
|
752
|
-
if (configured) {
|
|
753
|
-
printJSON({
|
|
754
|
-
mode: "configured",
|
|
755
|
-
appId,
|
|
756
|
-
configuredNetworkIds: configured,
|
|
757
|
-
networks: display
|
|
758
|
-
});
|
|
759
|
-
return;
|
|
760
|
-
}
|
|
761
865
|
printJSON(display);
|
|
762
866
|
return;
|
|
763
867
|
}
|
|
@@ -769,23 +873,18 @@ function registerNetwork(program2) {
|
|
|
769
873
|
return [idCell, nameCell, network.family, testnetCell];
|
|
770
874
|
});
|
|
771
875
|
printTable(["Network ID", "Name", "Family", "Testnet"], rows);
|
|
772
|
-
if (configured) {
|
|
773
|
-
console.log(
|
|
774
|
-
`
|
|
775
|
-
${dim(`Configured networks for app ${appId}: ${display.length}`)}`
|
|
776
|
-
);
|
|
777
|
-
}
|
|
778
876
|
console.log(`
|
|
779
877
|
Current: ${green(current)}`);
|
|
780
878
|
console.log(
|
|
781
879
|
` ${dim("Need Admin API chain identifiers (e.g. ETH_MAINNET)? See: apps chains")}`
|
|
782
880
|
);
|
|
881
|
+
console.log(
|
|
882
|
+
` ${dim("Need configured networks for an app? See: apps networks")}`
|
|
883
|
+
);
|
|
783
884
|
if (verbose) {
|
|
784
885
|
console.log("");
|
|
785
886
|
printJSON({
|
|
786
|
-
mode:
|
|
787
|
-
appId: appId ?? null,
|
|
788
|
-
configuredNetworkIds: configured ?? null,
|
|
887
|
+
mode: "all",
|
|
789
888
|
networks: display,
|
|
790
889
|
currentNetwork: current
|
|
791
890
|
});
|
|
@@ -1037,9 +1136,21 @@ function registerApps(program2) {
|
|
|
1037
1136
|
exitWithError(err);
|
|
1038
1137
|
}
|
|
1039
1138
|
});
|
|
1040
|
-
cmd.command("delete <id>").description("Delete an app").option("--dry-run", "Preview without executing").action(async (id, opts) => {
|
|
1139
|
+
cmd.command("delete <id>").description("Delete an app").option("--dry-run", "Preview without executing").option("-y, --yes", "Skip confirmation prompt").action(async (id, opts) => {
|
|
1041
1140
|
try {
|
|
1042
1141
|
if (handleDryRun(opts, "delete", { id }, `Would delete app ${id}`)) return;
|
|
1142
|
+
if (!opts.yes && isInteractiveAllowed(program2)) {
|
|
1143
|
+
const proceed = await promptConfirm({
|
|
1144
|
+
message: `Delete app ${id}?`,
|
|
1145
|
+
initialValue: false,
|
|
1146
|
+
cancelMessage: "Cancelled app deletion."
|
|
1147
|
+
});
|
|
1148
|
+
if (proceed === null) return;
|
|
1149
|
+
if (!proceed) {
|
|
1150
|
+
console.log(` ${dim("Skipped app deletion.")}`);
|
|
1151
|
+
return;
|
|
1152
|
+
}
|
|
1153
|
+
}
|
|
1043
1154
|
const admin = adminClientFromFlags(program2);
|
|
1044
1155
|
await withSpinner(
|
|
1045
1156
|
"Deleting app\u2026",
|
|
@@ -1168,6 +1279,37 @@ function registerApps(program2) {
|
|
|
1168
1279
|
exitWithError(err);
|
|
1169
1280
|
}
|
|
1170
1281
|
});
|
|
1282
|
+
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) => {
|
|
1283
|
+
try {
|
|
1284
|
+
const admin = adminClientFromFlags(program2);
|
|
1285
|
+
const appId = opts.appId || resolveAppId(program2);
|
|
1286
|
+
if (!appId) throw errAppRequired();
|
|
1287
|
+
const app = await withSpinner(
|
|
1288
|
+
"Fetching app\u2026",
|
|
1289
|
+
"App fetched",
|
|
1290
|
+
() => admin.getApp(appId)
|
|
1291
|
+
);
|
|
1292
|
+
const slugs = app.chainNetworks.map((n) => {
|
|
1293
|
+
const match = n.rpcUrl?.match(/^https:\/\/([^.]+)\.g\.alchemy\.com(?:\/|$)/);
|
|
1294
|
+
return match ? match[1] : null;
|
|
1295
|
+
}).filter((s) => Boolean(s));
|
|
1296
|
+
const uniqueSlugs = Array.from(new Set(slugs)).sort();
|
|
1297
|
+
if (isJSONMode()) {
|
|
1298
|
+
printJSON({ appId: app.id, appName: app.name, networks: uniqueSlugs });
|
|
1299
|
+
return;
|
|
1300
|
+
}
|
|
1301
|
+
if (uniqueSlugs.length === 0) {
|
|
1302
|
+
emptyState(`No RPC networks configured for ${app.name}.`);
|
|
1303
|
+
return;
|
|
1304
|
+
}
|
|
1305
|
+
const rows = uniqueSlugs.map((slug) => [slug]);
|
|
1306
|
+
printTable(["Network ID"], rows);
|
|
1307
|
+
console.log(`
|
|
1308
|
+
${dim(`${uniqueSlugs.length} networks configured for ${app.name} (${app.id})`)}`);
|
|
1309
|
+
} catch (err) {
|
|
1310
|
+
exitWithError(err);
|
|
1311
|
+
}
|
|
1312
|
+
});
|
|
1171
1313
|
cmd.command("chains").description("List Admin API chain identifiers for app configuration (e.g. ETH_MAINNET)").action(async () => {
|
|
1172
1314
|
try {
|
|
1173
1315
|
const admin = adminClientFromFlags(program2);
|
|
@@ -1520,7 +1662,13 @@ function registerPrices(program2) {
|
|
|
1520
1662
|
exitWithError(err);
|
|
1521
1663
|
}
|
|
1522
1664
|
});
|
|
1523
|
-
cmd.command("historical").description("Get historical prices").requiredOption("--body <json>", "JSON request payload").
|
|
1665
|
+
cmd.command("historical").description("Get historical prices").requiredOption("--body <json>", "JSON request payload").addHelpText(
|
|
1666
|
+
"after",
|
|
1667
|
+
`
|
|
1668
|
+
Examples:
|
|
1669
|
+
alchemy prices historical --body '{"symbol":"ETH","startTime":"2024-01-01T00:00:00Z","endTime":"2024-01-02T00:00:00Z","interval":"1h"}'
|
|
1670
|
+
alchemy prices historical --body '{"address":"0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48","network":"eth-mainnet","startTime":"2024-06-01","endTime":"2024-06-07","interval":"1d"}'`
|
|
1671
|
+
).action(async (opts) => {
|
|
1524
1672
|
try {
|
|
1525
1673
|
const apiKey = resolveAPIKey(program2);
|
|
1526
1674
|
const payload = JSON.parse(opts.body);
|
|
@@ -1607,21 +1755,6 @@ function registerPortfolio(program2) {
|
|
|
1607
1755
|
exitWithError(err);
|
|
1608
1756
|
}
|
|
1609
1757
|
});
|
|
1610
|
-
cmd.command("transactions").description("Get transaction history by address/network pairs").requiredOption("--body <json>", "JSON body for /transactions/history/by-address").action(async (opts) => {
|
|
1611
|
-
try {
|
|
1612
|
-
const apiKey = resolveAPIKey(program2);
|
|
1613
|
-
const result = await runDataCall(
|
|
1614
|
-
apiKey,
|
|
1615
|
-
"transaction history",
|
|
1616
|
-
"/transactions/history/by-address",
|
|
1617
|
-
JSON.parse(opts.body)
|
|
1618
|
-
);
|
|
1619
|
-
if (isJSONMode()) printJSON(result);
|
|
1620
|
-
else printSyntaxJSON(result);
|
|
1621
|
-
} catch (err) {
|
|
1622
|
-
exitWithError(err);
|
|
1623
|
-
}
|
|
1624
|
-
});
|
|
1625
1758
|
}
|
|
1626
1759
|
|
|
1627
1760
|
// src/commands/simulate.ts
|
|
@@ -1700,15 +1833,24 @@ function registerWebhooks(program2) {
|
|
|
1700
1833
|
exitWithError(err);
|
|
1701
1834
|
}
|
|
1702
1835
|
});
|
|
1703
|
-
cmd.command("create").description("Create webhook").requiredOption("--body <json>", "Create webhook JSON payload").action(async (opts) => {
|
|
1836
|
+
cmd.command("create").description("Create webhook").requiredOption("--body <json>", "Create webhook JSON payload").option("--dry-run", "Preview without executing").action(async (opts) => {
|
|
1704
1837
|
try {
|
|
1838
|
+
const payload = parseRequiredJSON(opts.body, "--body");
|
|
1839
|
+
if (opts.dryRun) {
|
|
1840
|
+
if (isJSONMode()) printJSON({ dryRun: true, action: "create-webhook", payload });
|
|
1841
|
+
else {
|
|
1842
|
+
console.log(` ${dim("Dry run:")} Would create webhook`);
|
|
1843
|
+
printSyntaxJSON(payload);
|
|
1844
|
+
}
|
|
1845
|
+
return;
|
|
1846
|
+
}
|
|
1705
1847
|
const token = resolveWebhookApiKey(cmd.opts());
|
|
1706
1848
|
const result = await withSpinner(
|
|
1707
1849
|
"Creating webhook\u2026",
|
|
1708
1850
|
"Webhook created",
|
|
1709
1851
|
() => callNotify(token, "/create-webhook", {
|
|
1710
1852
|
method: "POST",
|
|
1711
|
-
body:
|
|
1853
|
+
body: payload
|
|
1712
1854
|
})
|
|
1713
1855
|
);
|
|
1714
1856
|
if (isJSONMode()) printJSON(result);
|
|
@@ -1717,15 +1859,24 @@ function registerWebhooks(program2) {
|
|
|
1717
1859
|
exitWithError(err);
|
|
1718
1860
|
}
|
|
1719
1861
|
});
|
|
1720
|
-
cmd.command("update").description("Update webhook").requiredOption("--body <json>", "Update webhook JSON payload").action(async (opts) => {
|
|
1862
|
+
cmd.command("update").description("Update webhook").requiredOption("--body <json>", "Update webhook JSON payload").option("--dry-run", "Preview without executing").action(async (opts) => {
|
|
1721
1863
|
try {
|
|
1864
|
+
const payload = parseRequiredJSON(opts.body, "--body");
|
|
1865
|
+
if (opts.dryRun) {
|
|
1866
|
+
if (isJSONMode()) printJSON({ dryRun: true, action: "update-webhook", payload });
|
|
1867
|
+
else {
|
|
1868
|
+
console.log(` ${dim("Dry run:")} Would update webhook`);
|
|
1869
|
+
printSyntaxJSON(payload);
|
|
1870
|
+
}
|
|
1871
|
+
return;
|
|
1872
|
+
}
|
|
1722
1873
|
const token = resolveWebhookApiKey(cmd.opts());
|
|
1723
1874
|
const result = await withSpinner(
|
|
1724
1875
|
"Updating webhook\u2026",
|
|
1725
1876
|
"Webhook updated",
|
|
1726
1877
|
() => callNotify(token, "/update-webhook", {
|
|
1727
1878
|
method: "PUT",
|
|
1728
|
-
body:
|
|
1879
|
+
body: payload
|
|
1729
1880
|
})
|
|
1730
1881
|
);
|
|
1731
1882
|
if (isJSONMode()) printJSON(result);
|
|
@@ -1734,8 +1885,25 @@ function registerWebhooks(program2) {
|
|
|
1734
1885
|
exitWithError(err);
|
|
1735
1886
|
}
|
|
1736
1887
|
});
|
|
1737
|
-
cmd.command("delete <webhookId>").description("Delete webhook").action(async (webhookId) => {
|
|
1888
|
+
cmd.command("delete <webhookId>").description("Delete webhook").option("--dry-run", "Preview without executing").option("-y, --yes", "Skip confirmation prompt").action(async (webhookId, opts) => {
|
|
1738
1889
|
try {
|
|
1890
|
+
if (opts.dryRun) {
|
|
1891
|
+
if (isJSONMode()) printJSON({ dryRun: true, action: "delete-webhook", payload: { webhookId } });
|
|
1892
|
+
else console.log(` ${dim("Dry run:")} Would delete webhook ${webhookId}`);
|
|
1893
|
+
return;
|
|
1894
|
+
}
|
|
1895
|
+
if (!opts.yes && isInteractiveAllowed(program2)) {
|
|
1896
|
+
const proceed = await promptConfirm({
|
|
1897
|
+
message: `Delete webhook ${webhookId}?`,
|
|
1898
|
+
initialValue: false,
|
|
1899
|
+
cancelMessage: "Cancelled webhook deletion."
|
|
1900
|
+
});
|
|
1901
|
+
if (proceed === null) return;
|
|
1902
|
+
if (!proceed) {
|
|
1903
|
+
console.log(` ${dim("Skipped webhook deletion.")}`);
|
|
1904
|
+
return;
|
|
1905
|
+
}
|
|
1906
|
+
}
|
|
1739
1907
|
const token = resolveWebhookApiKey(cmd.opts());
|
|
1740
1908
|
const result = await withSpinner(
|
|
1741
1909
|
"Deleting webhook\u2026",
|
|
@@ -2387,8 +2555,12 @@ function formatAsSystemPrompt(payload) {
|
|
|
2387
2555
|
return lines.join("\n");
|
|
2388
2556
|
}
|
|
2389
2557
|
function registerAgentPrompt(program2) {
|
|
2390
|
-
program2.command("agent-prompt").description("Emit complete agent/automation usage instructions").action(() => {
|
|
2558
|
+
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) => {
|
|
2391
2559
|
const payload = buildAgentPrompt(program2);
|
|
2560
|
+
if (opts.commands) {
|
|
2561
|
+
const filter = new Set(opts.commands.split(",").map((s) => s.trim().toLowerCase()));
|
|
2562
|
+
payload.commands = payload.commands.filter((cmd) => filter.has(cmd.name.toLowerCase()));
|
|
2563
|
+
}
|
|
2392
2564
|
printHuman(formatAsSystemPrompt(payload), payload);
|
|
2393
2565
|
});
|
|
2394
2566
|
}
|
|
@@ -2500,10 +2672,10 @@ function resetUpdateNoticeState() {
|
|
|
2500
2672
|
}
|
|
2501
2673
|
program.name("alchemy").description(
|
|
2502
2674
|
"The Alchemy CLI lets you query blockchain data, call JSON-RPC methods, and manage your Alchemy configuration."
|
|
2503
|
-
).version("0.
|
|
2675
|
+
).version("0.4.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(
|
|
2504
2676
|
"-n, --network <network>",
|
|
2505
2677
|
"Target network (default: eth-mainnet) (env: ALCHEMY_NETWORK)"
|
|
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
|
|
2678
|
+
).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) => {
|
|
2507
2679
|
if (err.code === "commander.help" || err.code === "commander.helpDisplayed" || err.code === "commander.version") {
|
|
2508
2680
|
process.exit(0);
|
|
2509
2681
|
}
|
|
@@ -2645,6 +2817,7 @@ ${styledLine}`;
|
|
|
2645
2817
|
].join("\n");
|
|
2646
2818
|
}).hook("preAction", () => {
|
|
2647
2819
|
const opts = program.opts();
|
|
2820
|
+
if (opts.color === false) setNoColor(true);
|
|
2648
2821
|
const cfg = load();
|
|
2649
2822
|
setFlags({
|
|
2650
2823
|
json: opts.json,
|
|
@@ -2679,7 +2852,7 @@ ${styledLine}`;
|
|
|
2679
2852
|
if (isInteractiveAllowed(program)) {
|
|
2680
2853
|
let latestForInteractiveStartup = null;
|
|
2681
2854
|
if (shouldRunOnboarding(program, cfg)) {
|
|
2682
|
-
const { runOnboarding } = await import("./onboarding-
|
|
2855
|
+
const { runOnboarding } = await import("./onboarding-WQ2TWDM3.js");
|
|
2683
2856
|
const latest = getAvailableUpdateOnce();
|
|
2684
2857
|
const completed = await runOnboarding(program, latest);
|
|
2685
2858
|
updateShownDuringInteractiveStartup = Boolean(latest);
|
|
@@ -2691,7 +2864,7 @@ ${styledLine}`;
|
|
|
2691
2864
|
latestForInteractiveStartup = getAvailableUpdateOnce();
|
|
2692
2865
|
updateShownDuringInteractiveStartup = Boolean(latestForInteractiveStartup);
|
|
2693
2866
|
}
|
|
2694
|
-
const { startREPL } = await import("./interactive-
|
|
2867
|
+
const { startREPL } = await import("./interactive-NASSNJHQ.js");
|
|
2695
2868
|
program.exitOverride();
|
|
2696
2869
|
program.configureOutput({
|
|
2697
2870
|
writeErr: () => {
|
|
@@ -3,7 +3,7 @@ if(process.argv.includes("--no-color"))process.env.NO_COLOR="1";
|
|
|
3
3
|
import {
|
|
4
4
|
getRPCNetworkIds,
|
|
5
5
|
getSetupMethod
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-Z3LXQFIY.js";
|
|
7
7
|
import {
|
|
8
8
|
bgRgb,
|
|
9
9
|
bold,
|
|
@@ -19,7 +19,7 @@ import {
|
|
|
19
19
|
rgb,
|
|
20
20
|
setBrandedHelpSuppressed,
|
|
21
21
|
setReplMode
|
|
22
|
-
} from "./chunk-
|
|
22
|
+
} from "./chunk-TH75DFAY.js";
|
|
23
23
|
|
|
24
24
|
// src/commands/interactive.ts
|
|
25
25
|
import * as readline from "readline";
|
|
@@ -5,7 +5,7 @@ import {
|
|
|
5
5
|
generateAndPersistWallet,
|
|
6
6
|
importAndPersistWallet,
|
|
7
7
|
selectOrCreateApp
|
|
8
|
-
} from "./chunk-
|
|
8
|
+
} from "./chunk-PIWNNNMZ.js";
|
|
9
9
|
import {
|
|
10
10
|
bold,
|
|
11
11
|
brand,
|
|
@@ -19,7 +19,7 @@ import {
|
|
|
19
19
|
promptSelect,
|
|
20
20
|
promptText,
|
|
21
21
|
save
|
|
22
|
-
} from "./chunk-
|
|
22
|
+
} from "./chunk-TH75DFAY.js";
|
|
23
23
|
|
|
24
24
|
// src/commands/onboarding.ts
|
|
25
25
|
function printNextSteps(method) {
|