@alchemy/cli 0.7.2 → 0.7.3
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-F2IXC6CM.js +16 -0
- package/dist/{auth-TA3SL4BL.js → auth-GD7BJOMK.js} +2 -2
- package/dist/{chunk-KLPWJFWP.js → chunk-2BALTY22.js} +2 -19
- package/dist/{chunk-DGKUBK7G.js → chunk-5IL2PMZ6.js} +1 -1
- package/dist/{chunk-RE5HSYJJ.js → chunk-64A5W4M2.js} +1 -1
- package/dist/{chunk-INVT5BV6.js → chunk-C5HNQOLB.js} +1 -1
- package/dist/{chunk-MB6REYQL.js → chunk-FD6YLNTB.js} +3 -3
- package/dist/{chunk-BAZ4NGOD.js → chunk-JUCUKTP3.js} +1 -1
- package/dist/{chunk-5LCA2B6S.js → chunk-K6V3R7SH.js} +514 -509
- package/dist/chunk-R4W44A6E.js +134 -0
- package/dist/{chunk-LQXLZLCY.js → chunk-XSN4XA5Z.js} +6 -6
- package/dist/{errors-J6HNGXVA.js → errors-E2P6WHTX.js} +1 -1
- package/dist/index.js +391 -81
- package/dist/{interactive-JNTFVCUJ.js → interactive-BNIJYEOV.js} +13 -10
- package/dist/{onboarding-WN3IMTGS.js → onboarding-TTUVIXM4.js} +6 -6
- package/dist/{resolve-ZCR3YCHJ.js → resolve-WXT5ZCUK.js} +3 -3
- package/package.json +18 -24
- package/scripts/postinstall.cjs +2 -0
- package/dist/auth-7QNYRHIK.js +0 -16
- package/dist/chunk-EZ2ZD7YO.js +0 -64
package/dist/index.js
CHANGED
|
@@ -2,18 +2,20 @@
|
|
|
2
2
|
if(process.argv.includes("--no-color"))process.env.NO_COLOR="1";
|
|
3
3
|
import {
|
|
4
4
|
registerAuth
|
|
5
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-XSN4XA5Z.js";
|
|
6
6
|
import {
|
|
7
7
|
openBrowser
|
|
8
|
-
} from "./chunk-
|
|
8
|
+
} from "./chunk-C5HNQOLB.js";
|
|
9
9
|
import {
|
|
10
|
+
SETUP_CAPABILITY_LABELS,
|
|
11
|
+
SETUP_CAPABILITY_ORDER,
|
|
10
12
|
getSetupStatus,
|
|
11
13
|
isSetupComplete,
|
|
12
14
|
shouldRunOnboarding
|
|
13
|
-
} from "./chunk-
|
|
15
|
+
} from "./chunk-R4W44A6E.js";
|
|
14
16
|
import {
|
|
15
17
|
isInteractiveAllowed
|
|
16
|
-
} from "./chunk-
|
|
18
|
+
} from "./chunk-64A5W4M2.js";
|
|
17
19
|
import {
|
|
18
20
|
adminClientFromFlags,
|
|
19
21
|
clearSession,
|
|
@@ -41,12 +43,12 @@ import {
|
|
|
41
43
|
resolveX402Client,
|
|
42
44
|
saveSession,
|
|
43
45
|
updateSession
|
|
44
|
-
} from "./chunk-
|
|
46
|
+
} from "./chunk-K6V3R7SH.js";
|
|
45
47
|
import {
|
|
46
48
|
getAvailableUpdate,
|
|
47
49
|
getUpdateStatus,
|
|
48
50
|
printUpdateNotice
|
|
49
|
-
} from "./chunk-
|
|
51
|
+
} from "./chunk-FD6YLNTB.js";
|
|
50
52
|
import {
|
|
51
53
|
bold,
|
|
52
54
|
brand,
|
|
@@ -70,7 +72,7 @@ import {
|
|
|
70
72
|
weiToEth,
|
|
71
73
|
withSpinner,
|
|
72
74
|
yellow
|
|
73
|
-
} from "./chunk-
|
|
75
|
+
} from "./chunk-5IL2PMZ6.js";
|
|
74
76
|
import {
|
|
75
77
|
KEY_MAP,
|
|
76
78
|
configDir,
|
|
@@ -81,7 +83,7 @@ import {
|
|
|
81
83
|
save,
|
|
82
84
|
toMap,
|
|
83
85
|
validKeys
|
|
84
|
-
} from "./chunk-
|
|
86
|
+
} from "./chunk-JUCUKTP3.js";
|
|
85
87
|
import {
|
|
86
88
|
CLIError,
|
|
87
89
|
EXIT_CODES,
|
|
@@ -117,7 +119,7 @@ import {
|
|
|
117
119
|
setFlags,
|
|
118
120
|
setNoColor,
|
|
119
121
|
verbose
|
|
120
|
-
} from "./chunk-
|
|
122
|
+
} from "./chunk-2BALTY22.js";
|
|
121
123
|
|
|
122
124
|
// src/index.ts
|
|
123
125
|
import { Command, Help } from "commander";
|
|
@@ -624,7 +626,7 @@ function registerConfig(program2) {
|
|
|
624
626
|
printJSON(toMap(cfg));
|
|
625
627
|
return;
|
|
626
628
|
}
|
|
627
|
-
const { resolveAuthToken: resolveAuthToken2 } = await import("./resolve-
|
|
629
|
+
const { resolveAuthToken: resolveAuthToken2 } = await import("./resolve-WXT5ZCUK.js");
|
|
628
630
|
const validToken = resolveAuthToken2(cfg);
|
|
629
631
|
const authStatus = cfg.auth_token ? validToken ? `${green("\u2713")} authenticated${cfg.auth_token_expires_at ? ` ${dim(`(expires ${cfg.auth_token_expires_at})`)}` : ""}` : `${yellow("\u25C6")} expired${cfg.auth_token_expires_at ? ` ${dim(`(${cfg.auth_token_expires_at})`)}` : ""}` : dim("(not set) \u2014 run 'alchemy auth' to log in");
|
|
630
632
|
const pairs = [
|
|
@@ -738,6 +740,15 @@ function registerConfig(program2) {
|
|
|
738
740
|
console.log(` ${dim(`- ${command}`)}`);
|
|
739
741
|
}
|
|
740
742
|
}
|
|
743
|
+
console.log("");
|
|
744
|
+
console.log(` ${dim("Capabilities:")}`);
|
|
745
|
+
printKeyValue(
|
|
746
|
+
SETUP_CAPABILITY_ORDER.map((capability) => {
|
|
747
|
+
const capabilityStatus = status.capabilities[capability];
|
|
748
|
+
const value = capabilityStatus.complete ? `ready (${capabilityStatus.satisfiedBy})` : `missing ${capabilityStatus.missing.join(", ")}`;
|
|
749
|
+
return [SETUP_CAPABILITY_LABELS[capability], value];
|
|
750
|
+
})
|
|
751
|
+
);
|
|
741
752
|
});
|
|
742
753
|
}
|
|
743
754
|
|
|
@@ -2682,6 +2693,8 @@ function registerWallets(program2) {
|
|
|
2682
2693
|
}
|
|
2683
2694
|
|
|
2684
2695
|
// src/lib/rest.ts
|
|
2696
|
+
var DATA_API_BASE_URL_ENV = "ALCHEMY_DATA_API_BASE_URL";
|
|
2697
|
+
var PRICES_API_BASE_URL_ENV = "ALCHEMY_PRICES_API_BASE_URL";
|
|
2685
2698
|
function withQuery(url, query) {
|
|
2686
2699
|
if (!query) return url;
|
|
2687
2700
|
for (const [key, value] of Object.entries(query)) {
|
|
@@ -2715,13 +2728,15 @@ async function requestJSON(url, options) {
|
|
|
2715
2728
|
}
|
|
2716
2729
|
async function callApiData(apiKey, path, options = {}) {
|
|
2717
2730
|
if (!apiKey) throw errAuthRequired();
|
|
2718
|
-
const
|
|
2731
|
+
const override = parseBaseURLOverride(DATA_API_BASE_URL_ENV);
|
|
2732
|
+
const base2 = override ? new URL(`/data/v1/${apiKey}/`, override) : new URL(`https://api.g.${getBaseDomain()}/data/v1/${apiKey}/`);
|
|
2719
2733
|
const url = withQuery(new URL(path.replace(/^\//, ""), base2), options.query);
|
|
2720
2734
|
return requestJSON(url, { ...options, path });
|
|
2721
2735
|
}
|
|
2722
2736
|
async function callApiPrices(apiKey, path, options = {}) {
|
|
2723
2737
|
if (!apiKey) throw errAuthRequired();
|
|
2724
|
-
const
|
|
2738
|
+
const override = parseBaseURLOverride(PRICES_API_BASE_URL_ENV);
|
|
2739
|
+
const base2 = override ? new URL(`/prices/v1/${apiKey}/`, override) : new URL(`https://api.g.${getBaseDomain()}/prices/v1/${apiKey}/`);
|
|
2725
2740
|
const url = withQuery(new URL(path.replace(/^\//, ""), base2), options.query);
|
|
2726
2741
|
return requestJSON(url, { ...options, path });
|
|
2727
2742
|
}
|
|
@@ -3632,7 +3647,7 @@ async function performSolanaSend(program2, toArg, amountArg, tokenAddress, opts
|
|
|
3632
3647
|
}
|
|
3633
3648
|
|
|
3634
3649
|
// src/lib/smart-wallet.ts
|
|
3635
|
-
import { createSmartWalletClient
|
|
3650
|
+
import { createSmartWalletClient } from "@alchemy/wallet-apis";
|
|
3636
3651
|
import { privateKeyToAccount as privateKeyToAccount2 } from "viem/accounts";
|
|
3637
3652
|
|
|
3638
3653
|
// src/lib/chains.ts
|
|
@@ -3971,6 +3986,17 @@ function createDelegatedAccount(args) {
|
|
|
3971
3986
|
});
|
|
3972
3987
|
}
|
|
3973
3988
|
|
|
3989
|
+
// src/lib/wallet-transport.ts
|
|
3990
|
+
import { alchemyWalletTransport } from "@alchemy/wallet-apis";
|
|
3991
|
+
var WALLET_RPC_BASE_URL_ENV = "ALCHEMY_WALLET_RPC_BASE_URL";
|
|
3992
|
+
function createAlchemyWalletTransport(apiKey) {
|
|
3993
|
+
const override = parseBaseURLOverride(WALLET_RPC_BASE_URL_ENV);
|
|
3994
|
+
return alchemyWalletTransport({
|
|
3995
|
+
apiKey,
|
|
3996
|
+
...override ? { url: override.toString() } : {}
|
|
3997
|
+
});
|
|
3998
|
+
}
|
|
3999
|
+
|
|
3974
4000
|
// src/lib/smart-wallet.ts
|
|
3975
4001
|
function normalizeKey(key) {
|
|
3976
4002
|
const trimmed = key.trim();
|
|
@@ -4069,7 +4095,7 @@ function buildWalletClient(program2, options = {}) {
|
|
|
4069
4095
|
}
|
|
4070
4096
|
const paymaster = gasSponsored && gasPolicyId ? { policyId: gasPolicyId } : void 0;
|
|
4071
4097
|
const client = createSmartWalletClient({
|
|
4072
|
-
transport:
|
|
4098
|
+
transport: createAlchemyWalletTransport(apiKey),
|
|
4073
4099
|
chain,
|
|
4074
4100
|
signer: signerConfig.signer,
|
|
4075
4101
|
paymaster
|
|
@@ -4640,6 +4666,7 @@ var ERROR_RECOVERY = {
|
|
|
4640
4666
|
RATE_LIMITED: "Wait and retry; consider upgrading your Alchemy plan",
|
|
4641
4667
|
PAYMENT_REQUIRED: "Fund your x402 wallet or switch to API key auth",
|
|
4642
4668
|
SETUP_REQUIRED: "Run preflight: alchemy --json --no-interactive config status, then follow nextCommands",
|
|
4669
|
+
QUOTE_FAILED: "Quote unavailable; check data.cause for the specific reason (INSUFFICIENT_BALANCE, INSUFFICIENT_LIQUIDITY, UNSUPPORTED_ROUTE, QUOTE_REVERTED, QUOTE_FAILED) and follow the hint",
|
|
4643
4670
|
INTERNAL_ERROR: "Unexpected error; retry or report a bug"
|
|
4644
4671
|
};
|
|
4645
4672
|
function buildCommandSchema(cmd) {
|
|
@@ -4694,11 +4721,13 @@ function buildAgentPrompt(program2) {
|
|
|
4694
4721
|
"For general capability and usage questions, prefer npx -y @alchemy/cli@latest --json --no-interactive agent-prompt so stale local installs or PATH shims do not hide new commands",
|
|
4695
4722
|
"Use the user's installed alchemy binary only when executing commands against their local config or diagnosing their installed version",
|
|
4696
4723
|
"If installed alchemy help contradicts latest npm help, compare alchemy --json --no-interactive version with npx -y @alchemy/cli@latest --json --no-interactive version and check command -v alchemy",
|
|
4697
|
-
"Run alchemy --json --no-interactive update-check when you need to detect available CLI upgrades"
|
|
4724
|
+
"Run alchemy --json --no-interactive update-check when you need to detect available CLI upgrades",
|
|
4725
|
+
"For state-changing EVM commands, prefer preview flags such as --dry-run when available before asking the user to execute",
|
|
4726
|
+
"For large data reads, use output-size controls such as --limit or --summary when available"
|
|
4698
4727
|
],
|
|
4699
4728
|
preflight: {
|
|
4700
4729
|
command: "alchemy --json --no-interactive config status",
|
|
4701
|
-
description: "Check auth readiness before first command.
|
|
4730
|
+
description: "Check auth readiness before first command. Use capabilities.rpc_data/admin_api/notify_webhooks/wallet_signing/x402 to scope setup to the intended command family."
|
|
4702
4731
|
},
|
|
4703
4732
|
runtimeDiscovery: {
|
|
4704
4733
|
installed: {
|
|
@@ -4810,9 +4839,11 @@ function buildAgentPrompt(program2) {
|
|
|
4810
4839
|
"ALCHEMY_ACCESS_KEY=ak_xxx alchemy --json --no-interactive app list",
|
|
4811
4840
|
"alchemy --json --no-interactive evm rpc eth_blockNumber --api-key $ALCHEMY_API_KEY",
|
|
4812
4841
|
"alchemy --json --no-interactive evm network list",
|
|
4813
|
-
"alchemy --json --no-interactive evm send 0xRecipient 0.001 -n eth-sepolia",
|
|
4842
|
+
"alchemy --json --no-interactive evm send 0xRecipient 0.001 --dry-run -n eth-sepolia",
|
|
4814
4843
|
`alchemy --json --no-interactive evm contract read 0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48 "balanceOf(address)(uint256)" --args '["0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045"]' -n eth-mainnet`,
|
|
4815
|
-
"alchemy --json --no-interactive evm swap quote --from 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE --to 0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48 --amount 1.0 -n eth-mainnet",
|
|
4844
|
+
"alchemy --json --no-interactive evm swap quote --from 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE --to 0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48 --amount 1.0 --from-address 0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045 -n eth-mainnet",
|
|
4845
|
+
"alchemy --json --no-interactive evm logs --from-block latest --limit 25",
|
|
4846
|
+
"alchemy --json --no-interactive evm block latest --summary",
|
|
4816
4847
|
"alchemy --json --no-interactive evm status 0xCallId -n eth-mainnet"
|
|
4817
4848
|
],
|
|
4818
4849
|
docs: "https://www.alchemy.com/docs"
|
|
@@ -5154,15 +5185,26 @@ async function performApprove(program2, spenderArg, opts) {
|
|
|
5154
5185
|
}
|
|
5155
5186
|
|
|
5156
5187
|
// src/commands/block.ts
|
|
5188
|
+
function summarizeBlock(block) {
|
|
5189
|
+
return {
|
|
5190
|
+
number: block.number ?? null,
|
|
5191
|
+
hash: block.hash ?? null,
|
|
5192
|
+
timestamp: block.timestamp ?? null,
|
|
5193
|
+
transactionCount: Array.isArray(block.transactions) ? block.transactions.length : null,
|
|
5194
|
+
miner: block.miner ?? null,
|
|
5195
|
+
gasUsed: block.gasUsed ?? null,
|
|
5196
|
+
gasLimit: block.gasLimit ?? null
|
|
5197
|
+
};
|
|
5198
|
+
}
|
|
5157
5199
|
function registerBlock(program2) {
|
|
5158
|
-
program2.command("block").argument("<number>", "Block number, hex (0x...), or tag (latest, earliest, pending)").description("Get block details by number").addHelpText(
|
|
5200
|
+
program2.command("block").argument("<number>", "Block number, hex (0x...), or tag (latest, earliest, pending)").description("Get block details by number").option("--summary", "Return compact block summary in JSON mode").addHelpText(
|
|
5159
5201
|
"after",
|
|
5160
5202
|
`
|
|
5161
5203
|
Examples:
|
|
5162
5204
|
alchemy evm block latest
|
|
5163
5205
|
alchemy evm block 17000000
|
|
5164
5206
|
alchemy evm block 0x1`
|
|
5165
|
-
).action(async (blockId) => {
|
|
5207
|
+
).action(async (blockId, opts) => {
|
|
5166
5208
|
try {
|
|
5167
5209
|
let blockParam;
|
|
5168
5210
|
if (["latest", "earliest", "pending"].includes(blockId)) {
|
|
@@ -5189,7 +5231,7 @@ Examples:
|
|
|
5189
5231
|
);
|
|
5190
5232
|
if (!block) throw errNotFound(`block ${blockId}`);
|
|
5191
5233
|
if (isJSONMode()) {
|
|
5192
|
-
printJSON(block);
|
|
5234
|
+
printJSON(opts.summary ? summarizeBlock(block) : block);
|
|
5193
5235
|
return;
|
|
5194
5236
|
}
|
|
5195
5237
|
const pairs = [];
|
|
@@ -6237,60 +6279,74 @@ async function runDataCall(program2, title, path, body) {
|
|
|
6237
6279
|
() => x402 ? x402.callRest(`data/v1${path}`, { method: "POST", body }) : callApiData(resolveAPIKey(program2), path, { method: "POST", body })
|
|
6238
6280
|
);
|
|
6239
6281
|
}
|
|
6282
|
+
function limitPayload(value, limit) {
|
|
6283
|
+
if (limit === void 0) return value;
|
|
6284
|
+
if (Array.isArray(value)) {
|
|
6285
|
+
return value.slice(0, limit);
|
|
6286
|
+
}
|
|
6287
|
+
if (value && typeof value === "object") {
|
|
6288
|
+
return Object.fromEntries(
|
|
6289
|
+
Object.entries(value).map(([key, nested]) => [
|
|
6290
|
+
key,
|
|
6291
|
+
Array.isArray(nested) ? nested.slice(0, limit) : nested
|
|
6292
|
+
])
|
|
6293
|
+
);
|
|
6294
|
+
}
|
|
6295
|
+
return value;
|
|
6296
|
+
}
|
|
6297
|
+
async function runPortfolioCommand(program2, title, path, opts) {
|
|
6298
|
+
const limit = parseOptionalInt(opts.limit, "--limit");
|
|
6299
|
+
const result = await runDataCall(program2, title, path, JSON.parse(opts.body));
|
|
6300
|
+
const output = limitPayload(result, limit);
|
|
6301
|
+
if (isJSONMode()) printJSON(output);
|
|
6302
|
+
else printSyntaxJSON(output);
|
|
6303
|
+
}
|
|
6240
6304
|
function registerPortfolio(program2) {
|
|
6241
6305
|
const cmd = program2.command("portfolio").description("Portfolio API wrappers");
|
|
6242
|
-
cmd.command("tokens").description("Get token portfolio by address/network pairs").requiredOption("--body <json>", "JSON body for /assets/tokens/by-address").action(async (opts) => {
|
|
6306
|
+
cmd.command("tokens").description("Get token portfolio by address/network pairs").requiredOption("--body <json>", "JSON body for /assets/tokens/by-address").option("--limit <n>", "Limit arrays in output").action(async (opts) => {
|
|
6243
6307
|
try {
|
|
6244
|
-
|
|
6308
|
+
await runPortfolioCommand(
|
|
6245
6309
|
program2,
|
|
6246
6310
|
"token portfolio",
|
|
6247
6311
|
"/assets/tokens/by-address",
|
|
6248
|
-
|
|
6312
|
+
opts
|
|
6249
6313
|
);
|
|
6250
|
-
if (isJSONMode()) printJSON(result);
|
|
6251
|
-
else printSyntaxJSON(result);
|
|
6252
6314
|
} catch (err) {
|
|
6253
6315
|
exitWithError(err);
|
|
6254
6316
|
}
|
|
6255
6317
|
});
|
|
6256
|
-
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) => {
|
|
6318
|
+
cmd.command("token-balances").description("Get token balances by address/network pairs").requiredOption("--body <json>", "JSON body for /assets/tokens/balances/by-address").option("--limit <n>", "Limit arrays in output").action(async (opts) => {
|
|
6257
6319
|
try {
|
|
6258
|
-
|
|
6320
|
+
await runPortfolioCommand(
|
|
6259
6321
|
program2,
|
|
6260
6322
|
"token balances",
|
|
6261
6323
|
"/assets/tokens/balances/by-address",
|
|
6262
|
-
|
|
6324
|
+
opts
|
|
6263
6325
|
);
|
|
6264
|
-
if (isJSONMode()) printJSON(result);
|
|
6265
|
-
else printSyntaxJSON(result);
|
|
6266
6326
|
} catch (err) {
|
|
6267
6327
|
exitWithError(err);
|
|
6268
6328
|
}
|
|
6269
6329
|
});
|
|
6270
|
-
cmd.command("nfts").description("Get NFT portfolio by address/network pairs").requiredOption("--body <json>", "JSON body for /assets/nfts/by-address").action(async (opts) => {
|
|
6330
|
+
cmd.command("nfts").description("Get NFT portfolio by address/network pairs").requiredOption("--body <json>", "JSON body for /assets/nfts/by-address").option("--limit <n>", "Limit arrays in output").action(async (opts) => {
|
|
6271
6331
|
try {
|
|
6272
|
-
|
|
6332
|
+
await runPortfolioCommand(
|
|
6273
6333
|
program2,
|
|
6274
6334
|
"NFT portfolio",
|
|
6275
6335
|
"/assets/nfts/by-address",
|
|
6276
|
-
|
|
6336
|
+
opts
|
|
6277
6337
|
);
|
|
6278
|
-
if (isJSONMode()) printJSON(result);
|
|
6279
|
-
else printSyntaxJSON(result);
|
|
6280
6338
|
} catch (err) {
|
|
6281
6339
|
exitWithError(err);
|
|
6282
6340
|
}
|
|
6283
6341
|
});
|
|
6284
|
-
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) => {
|
|
6342
|
+
cmd.command("nft-contracts").description("Get NFT contracts by address/network pairs").requiredOption("--body <json>", "JSON body for /assets/nfts/contracts/by-address").option("--limit <n>", "Limit arrays in output").action(async (opts) => {
|
|
6285
6343
|
try {
|
|
6286
|
-
|
|
6344
|
+
await runPortfolioCommand(
|
|
6287
6345
|
program2,
|
|
6288
6346
|
"NFT contracts",
|
|
6289
6347
|
"/assets/nfts/contracts/by-address",
|
|
6290
|
-
|
|
6348
|
+
opts
|
|
6291
6349
|
);
|
|
6292
|
-
if (isJSONMode()) printJSON(result);
|
|
6293
|
-
else printSyntaxJSON(result);
|
|
6294
6350
|
} catch (err) {
|
|
6295
6351
|
exitWithError(err);
|
|
6296
6352
|
}
|
|
@@ -6454,8 +6510,9 @@ Examples:
|
|
|
6454
6510
|
alchemy evm logs --address 0xdAC17F958D2ee523a2206206994597C13D831ec7 --from-block 18000000 --to-block 18000010
|
|
6455
6511
|
alchemy evm logs --address 0xdAC17F958D2ee523a2206206994597C13D831ec7 --topic 0xddf252ad...
|
|
6456
6512
|
alchemy evm logs --from-block latest --json`
|
|
6457
|
-
).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) => {
|
|
6513
|
+
).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").option("--limit <n>", "Limit returned logs in output").action(async (opts) => {
|
|
6458
6514
|
try {
|
|
6515
|
+
const outputLimit = parseOptionalInt(opts.limit, "--limit");
|
|
6459
6516
|
const filter = {
|
|
6460
6517
|
fromBlock: normalizeBlockParam(opts.fromBlock),
|
|
6461
6518
|
toBlock: normalizeBlockParam(opts.toBlock)
|
|
@@ -6473,20 +6530,41 @@ Examples:
|
|
|
6473
6530
|
() => client.call("eth_getLogs", [filter])
|
|
6474
6531
|
);
|
|
6475
6532
|
const network = resolveNetwork(program2);
|
|
6533
|
+
const displayedLogs = outputLimit === void 0 ? logs : logs.slice(0, outputLimit);
|
|
6476
6534
|
if (isJSONMode()) {
|
|
6477
|
-
printJSON({
|
|
6535
|
+
printJSON({
|
|
6536
|
+
logs: displayedLogs,
|
|
6537
|
+
count: displayedLogs.length,
|
|
6538
|
+
network,
|
|
6539
|
+
...outputLimit !== void 0 ? {
|
|
6540
|
+
totalCount: logs.length,
|
|
6541
|
+
truncated: displayedLogs.length < logs.length
|
|
6542
|
+
} : {}
|
|
6543
|
+
});
|
|
6478
6544
|
return;
|
|
6479
6545
|
}
|
|
6480
6546
|
if (logs.length === 0) {
|
|
6481
6547
|
console.log(dim("No logs found for the given filter."));
|
|
6482
6548
|
return;
|
|
6483
6549
|
}
|
|
6550
|
+
if (displayedLogs.length === 0) {
|
|
6551
|
+
console.log(dim(`Found ${logs.length} log${logs.length === 1 ? "" : "s"}; --limit 0 hides output.`));
|
|
6552
|
+
return;
|
|
6553
|
+
}
|
|
6484
6554
|
const total = logs.length;
|
|
6485
6555
|
const interactive = isInteractiveAllowed(program2);
|
|
6556
|
+
const limitSummary = displayedLogs.length < total ? `Showing ${displayedLogs.length} of ${total} logs on ${network}
|
|
6557
|
+
` : `Found ${total} log${total === 1 ? "" : "s"} on ${network}
|
|
6558
|
+
`;
|
|
6559
|
+
if (outputLimit !== void 0) {
|
|
6560
|
+
console.log(limitSummary);
|
|
6561
|
+
printTable(TABLE_HEADERS2, formatLogRows(displayedLogs));
|
|
6562
|
+
return;
|
|
6563
|
+
}
|
|
6486
6564
|
if (!interactive) {
|
|
6487
6565
|
console.log(`Found ${total} log${total === 1 ? "" : "s"} on ${network}
|
|
6488
6566
|
`);
|
|
6489
|
-
printTable(TABLE_HEADERS2, formatLogRows(
|
|
6567
|
+
printTable(TABLE_HEADERS2, formatLogRows(displayedLogs));
|
|
6490
6568
|
} else {
|
|
6491
6569
|
let offset = 0;
|
|
6492
6570
|
const firstPage = logs.slice(0, PAGE_SIZE);
|
|
@@ -6616,8 +6694,15 @@ Examples:
|
|
|
6616
6694
|
// src/commands/send-evm.ts
|
|
6617
6695
|
import { encodeFunctionData as encodeFunctionData3, erc20Abi as erc20Abi2 } from "viem";
|
|
6618
6696
|
var NATIVE_EVM_DECIMALS = 18;
|
|
6697
|
+
function formatCallPreview(call) {
|
|
6698
|
+
return {
|
|
6699
|
+
to: call.to,
|
|
6700
|
+
...call.value !== void 0 ? { value: call.value.toString() } : {},
|
|
6701
|
+
...call.data ? { data: call.data } : {}
|
|
6702
|
+
};
|
|
6703
|
+
}
|
|
6619
6704
|
function registerEvmSend(program2) {
|
|
6620
|
-
const sendCmd = program2.command("send").description("Send native tokens or ERC-20 tokens to an address").argument("<to>", "Recipient address (0x... or ENS name)").argument("<amount>", "Amount to send (human-readable, e.g. 1.5)").option("--token <address>", "ERC-20 token contract address (omit for native token)");
|
|
6705
|
+
const sendCmd = program2.command("send").description("Send native tokens or ERC-20 tokens to an address").argument("<to>", "Recipient address (0x... or ENS name)").argument("<amount>", "Amount to send (human-readable, e.g. 1.5)").option("--token <address>", "ERC-20 token contract address (omit for native token)").option("--dry-run", "Preview transaction without signing or sending");
|
|
6621
6706
|
addSignerOption(sendCmd);
|
|
6622
6707
|
sendCmd.option("--gas-sponsored", "Enable gas sponsorship (env: ALCHEMY_EVM_GAS_SPONSORED)").option("--gas-policy-id <id>", "Gas policy ID for sponsorship (env: ALCHEMY_EVM_GAS_POLICY_ID)").addHelpText(
|
|
6623
6708
|
"after",
|
|
@@ -6626,16 +6711,18 @@ Examples:
|
|
|
6626
6711
|
alchemy evm send 0xAbC...123 1.5 Send 1.5 ETH
|
|
6627
6712
|
alchemy evm send vitalik.eth 0.1 -n base-mainnet Send 0.1 ETH on Base
|
|
6628
6713
|
alchemy evm send 0xAbC...123 100 --token 0xA0b8...USDC Send 100 USDC
|
|
6714
|
+
alchemy evm send 0xAbC...123 1.5 --dry-run Preview without signing or sending
|
|
6629
6715
|
alchemy evm send 0xAbC...123 1 --gas-sponsored --gas-policy-id <id>
|
|
6630
6716
|
alchemy evm send 0xAbC...123 1.5 --signer local Force the local wallet`
|
|
6631
6717
|
).action(async (toArg, amountArg, _opts, cmd) => {
|
|
6632
6718
|
try {
|
|
6633
6719
|
const opts = cmd.opts();
|
|
6634
6720
|
await performEvmSend(cmd, toArg, amountArg, opts.token, {
|
|
6635
|
-
signer: parseSignerOpt(opts.signer)
|
|
6721
|
+
signer: parseSignerOpt(opts.signer),
|
|
6722
|
+
dryRun: opts.dryRun
|
|
6636
6723
|
});
|
|
6637
6724
|
} catch (err) {
|
|
6638
|
-
const { exitWithError: exitWithError2 } = await import("./errors-
|
|
6725
|
+
const { exitWithError: exitWithError2 } = await import("./errors-E2P6WHTX.js");
|
|
6639
6726
|
exitWithError2(err);
|
|
6640
6727
|
}
|
|
6641
6728
|
});
|
|
@@ -6666,6 +6753,37 @@ async function performEvmSend(program2, toArg, amountArg, tokenAddress, opts = {
|
|
|
6666
6753
|
args: [to, wei]
|
|
6667
6754
|
})
|
|
6668
6755
|
}] : [{ to, value: wei }];
|
|
6756
|
+
if (opts.dryRun) {
|
|
6757
|
+
const previewCalls = calls.map(formatCallPreview);
|
|
6758
|
+
if (isJSONMode()) {
|
|
6759
|
+
printJSON({
|
|
6760
|
+
dryRun: true,
|
|
6761
|
+
action: "evm-send",
|
|
6762
|
+
from,
|
|
6763
|
+
to,
|
|
6764
|
+
amount: amountArg,
|
|
6765
|
+
token: tokenAddress ?? symbol,
|
|
6766
|
+
tokenAddress: tokenAddress ?? null,
|
|
6767
|
+
network,
|
|
6768
|
+
sponsored: !!paymaster,
|
|
6769
|
+
calls: previewCalls
|
|
6770
|
+
});
|
|
6771
|
+
} else {
|
|
6772
|
+
const pairs = [
|
|
6773
|
+
["Dry Run", "yes"],
|
|
6774
|
+
["From", from],
|
|
6775
|
+
["To", to],
|
|
6776
|
+
["Amount", green(`${amountArg} ${symbol}`)],
|
|
6777
|
+
["Network", network],
|
|
6778
|
+
["Calls", String(previewCalls.length)]
|
|
6779
|
+
];
|
|
6780
|
+
if (paymaster) {
|
|
6781
|
+
pairs.push(["Gas", green("Sponsored")]);
|
|
6782
|
+
}
|
|
6783
|
+
printKeyValue(pairs);
|
|
6784
|
+
}
|
|
6785
|
+
return;
|
|
6786
|
+
}
|
|
6669
6787
|
const { id } = await withSpinner(
|
|
6670
6788
|
"Sending transaction\u2026",
|
|
6671
6789
|
"Transaction submitted",
|
|
@@ -6770,6 +6888,105 @@ function registerSimulate(program2) {
|
|
|
6770
6888
|
import {
|
|
6771
6889
|
swapActions
|
|
6772
6890
|
} from "@alchemy/wallet-apis/experimental";
|
|
6891
|
+
|
|
6892
|
+
// src/lib/wallet-quote-client.ts
|
|
6893
|
+
import { createClient } from "viem";
|
|
6894
|
+
import { parseAccount } from "viem/accounts";
|
|
6895
|
+
function buildWalletQuoteClient(program2, address2) {
|
|
6896
|
+
const apiKey = resolveAPIKey(program2);
|
|
6897
|
+
if (!apiKey) throw errAuthRequired();
|
|
6898
|
+
const cfg = load();
|
|
6899
|
+
const network = resolveNetwork(program2, cfg);
|
|
6900
|
+
const chain = networkToChain(network);
|
|
6901
|
+
const client = createClient({
|
|
6902
|
+
account: parseAccount(address2),
|
|
6903
|
+
transport: createAlchemyWalletTransport(apiKey),
|
|
6904
|
+
chain,
|
|
6905
|
+
name: "alchemyQuoteClient"
|
|
6906
|
+
});
|
|
6907
|
+
if (typeof client.extend !== "function") {
|
|
6908
|
+
throw new Error("Quote client missing extend(); @alchemy/wallet-apis or viem may have changed.");
|
|
6909
|
+
}
|
|
6910
|
+
return {
|
|
6911
|
+
client,
|
|
6912
|
+
network,
|
|
6913
|
+
chain,
|
|
6914
|
+
address: address2,
|
|
6915
|
+
paymaster: void 0
|
|
6916
|
+
};
|
|
6917
|
+
}
|
|
6918
|
+
|
|
6919
|
+
// src/lib/quote-errors.ts
|
|
6920
|
+
function errorText(err) {
|
|
6921
|
+
if (err instanceof CLIError) {
|
|
6922
|
+
return [err.message, err.details].filter(Boolean).join(" ");
|
|
6923
|
+
}
|
|
6924
|
+
if (err instanceof Error) {
|
|
6925
|
+
return err.message;
|
|
6926
|
+
}
|
|
6927
|
+
return String(err);
|
|
6928
|
+
}
|
|
6929
|
+
function classifyQuoteFailure(text) {
|
|
6930
|
+
const lower = text.toLowerCase();
|
|
6931
|
+
if (/liquidity|no route|route not found|cannot find route|unable to find route|no quote/.test(lower)) {
|
|
6932
|
+
return "INSUFFICIENT_LIQUIDITY";
|
|
6933
|
+
}
|
|
6934
|
+
if (/insufficient (funds|balance)|exceeds balance|not enough (funds|balance)|balance too low/.test(lower)) {
|
|
6935
|
+
return "INSUFFICIENT_BALANCE";
|
|
6936
|
+
}
|
|
6937
|
+
if (/unsupported|not supported|unsupported route|unsupported token|unsupported chain|unsupported network/.test(lower)) {
|
|
6938
|
+
return "UNSUPPORTED_ROUTE";
|
|
6939
|
+
}
|
|
6940
|
+
if (/execution reverted|revert|call exception|internal json-rpc|rpc error|-32603/.test(lower)) {
|
|
6941
|
+
return "QUOTE_REVERTED";
|
|
6942
|
+
}
|
|
6943
|
+
return "QUOTE_FAILED";
|
|
6944
|
+
}
|
|
6945
|
+
function quoteMessage(flow, cause) {
|
|
6946
|
+
const label = flow === "swap" ? "Swap" : "Bridge";
|
|
6947
|
+
switch (cause) {
|
|
6948
|
+
case "INSUFFICIENT_BALANCE":
|
|
6949
|
+
return `${label} quote unavailable: insufficient balance for the requested amount.`;
|
|
6950
|
+
case "INSUFFICIENT_LIQUIDITY":
|
|
6951
|
+
return `${label} quote unavailable: no route or insufficient liquidity for this trade.`;
|
|
6952
|
+
case "UNSUPPORTED_ROUTE":
|
|
6953
|
+
return `${label} quote unavailable: unsupported token, chain, or route.`;
|
|
6954
|
+
case "QUOTE_REVERTED":
|
|
6955
|
+
return `${label} quote unavailable: quote simulation reverted.`;
|
|
6956
|
+
case "QUOTE_FAILED":
|
|
6957
|
+
return `${label} quote unavailable.`;
|
|
6958
|
+
}
|
|
6959
|
+
}
|
|
6960
|
+
function quoteHint(flow, cause) {
|
|
6961
|
+
switch (cause) {
|
|
6962
|
+
case "INSUFFICIENT_BALANCE":
|
|
6963
|
+
return "Lower --amount or quote from an address that holds enough source token.";
|
|
6964
|
+
case "INSUFFICIENT_LIQUIDITY":
|
|
6965
|
+
return flow === "swap" ? "Try a smaller --amount, different tokens, or a different mainnet." : "Try a smaller --amount, different tokens, or a different destination network.";
|
|
6966
|
+
case "UNSUPPORTED_ROUTE":
|
|
6967
|
+
return flow === "swap" ? "Check token addresses and use an EVM mainnet supported by swap." : "Check token addresses and source/destination EVM mainnets.";
|
|
6968
|
+
case "QUOTE_REVERTED":
|
|
6969
|
+
return "Try a smaller --amount or different route. Use --json for typed error details.";
|
|
6970
|
+
case "QUOTE_FAILED":
|
|
6971
|
+
return "Retry later or try a different amount, token, or network.";
|
|
6972
|
+
}
|
|
6973
|
+
}
|
|
6974
|
+
function normalizeQuoteError(err, flow) {
|
|
6975
|
+
if (err instanceof CLIError && err.code !== ErrorCode.RPC_ERROR && err.code !== ErrorCode.INTERNAL_ERROR) {
|
|
6976
|
+
return err;
|
|
6977
|
+
}
|
|
6978
|
+
const detail = errorText(err);
|
|
6979
|
+
const cause = classifyQuoteFailure(detail);
|
|
6980
|
+
return new CLIError(
|
|
6981
|
+
ErrorCode.QUOTE_FAILED,
|
|
6982
|
+
quoteMessage(flow, cause),
|
|
6983
|
+
quoteHint(flow, cause),
|
|
6984
|
+
detail || void 0,
|
|
6985
|
+
{ cause }
|
|
6986
|
+
);
|
|
6987
|
+
}
|
|
6988
|
+
|
|
6989
|
+
// src/commands/swap.ts
|
|
6773
6990
|
var NATIVE_TOKEN_ADDRESS2 = "0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE";
|
|
6774
6991
|
var NATIVE_DECIMALS = 18;
|
|
6775
6992
|
function isNativeToken2(address2) {
|
|
@@ -6792,11 +7009,12 @@ async function resolveTokenInfo(network, program2, tokenAddress) {
|
|
|
6792
7009
|
throw errInvalidArgs(`Failed to resolve token info for ${tokenAddress}.${detail}`);
|
|
6793
7010
|
}
|
|
6794
7011
|
}
|
|
6795
|
-
function createQuoteRequest(fromToken, toToken, fromAmount, slippagePercent, paymaster) {
|
|
7012
|
+
function createQuoteRequest(fromToken, toToken, fromAmount, slippagePercent, paymaster, account) {
|
|
6796
7013
|
const request2 = {
|
|
6797
7014
|
fromToken,
|
|
6798
7015
|
toToken,
|
|
6799
7016
|
fromAmount,
|
|
7017
|
+
...account ? { account } : {},
|
|
6800
7018
|
...slippagePercent !== void 0 ? { slippage: slippagePercentToBasisPoints(slippagePercent) } : {},
|
|
6801
7019
|
...paymaster ? { capabilities: { paymaster } } : {}
|
|
6802
7020
|
};
|
|
@@ -6843,7 +7061,7 @@ async function prepareQuoteForExecution(client, quote) {
|
|
|
6843
7061
|
}
|
|
6844
7062
|
function registerSwap(program2) {
|
|
6845
7063
|
const cmd = program2.command("swap").description("Swap tokens on the same chain");
|
|
6846
|
-
const quoteCmd = cmd.command("quote").description("Get a swap quote without executing").requiredOption("--from <token_address>", "Token address to swap from (use 0xEeee...EEeE for the native token)").requiredOption("--to <token_address>", "Token address to swap to (use 0xEeee...EEeE for the native token)").requiredOption("--amount <number>", "Amount to swap in decimal token units (for example, 1.5)").option("--slippage <percent>", "Max slippage percentage (omit to use the API default)");
|
|
7064
|
+
const quoteCmd = cmd.command("quote").description("Get a swap quote without executing").requiredOption("--from <token_address>", "Token address to swap from (use 0xEeee...EEeE for the native token)").requiredOption("--to <token_address>", "Token address to swap to (use 0xEeee...EEeE for the native token)").requiredOption("--amount <number>", "Amount to swap in decimal token units (for example, 1.5)").option("--from-address <address>", "Wallet/account address to quote from without changing signer selection").option("--slippage <percent>", "Max slippage percentage (omit to use the API default)");
|
|
6847
7065
|
addSignerOption(quoteCmd);
|
|
6848
7066
|
quoteCmd.addHelpText(
|
|
6849
7067
|
"after",
|
|
@@ -6880,8 +7098,9 @@ async function performSwapQuote(program2, opts) {
|
|
|
6880
7098
|
validateSwapNetwork(resolveNetwork(program2));
|
|
6881
7099
|
validateAddress(opts.from);
|
|
6882
7100
|
validateAddress(opts.to);
|
|
7101
|
+
if (opts.fromAddress) validateAddress(opts.fromAddress);
|
|
6883
7102
|
const signer = parseSignerOpt(opts.signer);
|
|
6884
|
-
const { client, network, paymaster } = buildWalletClient(program2, { signer });
|
|
7103
|
+
const { client, network, address: fromAddress, paymaster } = opts.fromAddress ? buildWalletQuoteClient(program2, opts.fromAddress) : buildWalletClient(program2, { signer });
|
|
6885
7104
|
const swapClient = client.extend(swapActions);
|
|
6886
7105
|
const fromInfo = await resolveTokenInfo(network, program2, opts.from);
|
|
6887
7106
|
const rawAmount = parseAmount(opts.amount, fromInfo.decimals);
|
|
@@ -6889,17 +7108,23 @@ async function performSwapQuote(program2, opts) {
|
|
|
6889
7108
|
if (slippage !== void 0 && (isNaN(slippage) || slippage < 0 || slippage > 100)) {
|
|
6890
7109
|
throw errInvalidArgs("Slippage must be a number between 0 and 100.");
|
|
6891
7110
|
}
|
|
6892
|
-
|
|
6893
|
-
|
|
6894
|
-
|
|
6895
|
-
|
|
6896
|
-
|
|
7111
|
+
let quote;
|
|
7112
|
+
try {
|
|
7113
|
+
quote = await withSpinner(
|
|
7114
|
+
"Fetching quote\u2026",
|
|
7115
|
+
"Quote received",
|
|
7116
|
+
() => swapClient.requestQuoteV0(createQuoteRequest(opts.from, opts.to, rawAmount, slippage, paymaster, fromAddress))
|
|
7117
|
+
);
|
|
7118
|
+
} catch (err) {
|
|
7119
|
+
throw normalizeQuoteError(err, "swap");
|
|
7120
|
+
}
|
|
6897
7121
|
const toInfo = await resolveTokenInfo(network, program2, opts.to);
|
|
6898
7122
|
const quoteData = extractQuoteData(quote);
|
|
6899
7123
|
if (isJSONMode()) {
|
|
6900
7124
|
printJSON({
|
|
6901
7125
|
fromToken: opts.from,
|
|
6902
7126
|
toToken: opts.to,
|
|
7127
|
+
fromAddress,
|
|
6903
7128
|
fromAmount: opts.amount,
|
|
6904
7129
|
fromSymbol: fromInfo.symbol,
|
|
6905
7130
|
toSymbol: toInfo.symbol,
|
|
@@ -6918,6 +7143,7 @@ async function performSwapQuote(program2, opts) {
|
|
|
6918
7143
|
pairs.push(["To", `${toInfo.symbol}`]);
|
|
6919
7144
|
}
|
|
6920
7145
|
pairs.push(
|
|
7146
|
+
["Wallet", fromAddress],
|
|
6921
7147
|
["Slippage", slippage === void 0 ? "API default" : `${slippage}%`],
|
|
6922
7148
|
["Network", network]
|
|
6923
7149
|
);
|
|
@@ -6937,11 +7163,16 @@ async function performSwapExecute(program2, opts) {
|
|
|
6937
7163
|
if (slippage !== void 0 && (isNaN(slippage) || slippage < 0 || slippage > 100)) {
|
|
6938
7164
|
throw errInvalidArgs("Slippage must be a number between 0 and 100.");
|
|
6939
7165
|
}
|
|
6940
|
-
|
|
6941
|
-
|
|
6942
|
-
|
|
6943
|
-
|
|
6944
|
-
|
|
7166
|
+
let quote;
|
|
7167
|
+
try {
|
|
7168
|
+
quote = await withSpinner(
|
|
7169
|
+
"Fetching quote\u2026",
|
|
7170
|
+
"Quote received",
|
|
7171
|
+
() => swapClient.requestQuoteV0(createQuoteRequest(opts.from, opts.to, rawAmount, slippage, paymaster, from))
|
|
7172
|
+
);
|
|
7173
|
+
} catch (err) {
|
|
7174
|
+
throw normalizeQuoteError(err, "swap");
|
|
7175
|
+
}
|
|
6945
7176
|
const preparedQuote = await prepareQuoteForExecution(client, quote);
|
|
6946
7177
|
const { id } = await withSpinner(
|
|
6947
7178
|
"Sending swap transaction\u2026",
|
|
@@ -7143,12 +7374,13 @@ async function resolveTokenInfo2(network, program2, tokenAddress) {
|
|
|
7143
7374
|
throw errInvalidArgs(`Failed to resolve token info for ${tokenAddress}.${detail}`);
|
|
7144
7375
|
}
|
|
7145
7376
|
}
|
|
7146
|
-
function createBridgeQuoteRequest(fromToken, toToken, fromAmount, toChainId, slippagePercent, paymaster) {
|
|
7377
|
+
function createBridgeQuoteRequest(fromToken, toToken, fromAmount, toChainId, slippagePercent, paymaster, account) {
|
|
7147
7378
|
const request2 = {
|
|
7148
7379
|
fromToken,
|
|
7149
7380
|
toToken,
|
|
7150
7381
|
fromAmount,
|
|
7151
7382
|
toChainId,
|
|
7383
|
+
...account ? { account } : {},
|
|
7152
7384
|
...slippagePercent !== void 0 ? { slippage: slippagePercentToBasisPoints2(slippagePercent) } : {},
|
|
7153
7385
|
...paymaster ? { capabilities: { paymaster } } : {}
|
|
7154
7386
|
};
|
|
@@ -7214,7 +7446,7 @@ function extractQuoteData2(quote) {
|
|
|
7214
7446
|
}
|
|
7215
7447
|
function registerBridge(program2) {
|
|
7216
7448
|
const cmd = program2.command("bridge").description("Bridge tokens from the source -n/--network to a destination --to-network");
|
|
7217
|
-
const quoteCmd = cmd.command("quote").description("Get a bridge quote without executing").requiredOption("--from <token_address>", `Source token address (use ${NATIVE_TOKEN_ADDRESS3} for the native token)`).requiredOption("--to <token_address>", `Destination token address (use ${NATIVE_TOKEN_ADDRESS3} for the native token)`).requiredOption("--amount <number>", "Amount to bridge in decimal token units (for example, 1.5)").requiredOption("--to-network <network>", "Destination network (e.g. base-mainnet)").option("--slippage <percent>", "Max slippage percentage (omit to use the API default)");
|
|
7449
|
+
const quoteCmd = cmd.command("quote").description("Get a bridge quote without executing").requiredOption("--from <token_address>", `Source token address (use ${NATIVE_TOKEN_ADDRESS3} for the native token)`).requiredOption("--to <token_address>", `Destination token address (use ${NATIVE_TOKEN_ADDRESS3} for the native token)`).requiredOption("--amount <number>", "Amount to bridge in decimal token units (for example, 1.5)").requiredOption("--to-network <network>", "Destination network (e.g. base-mainnet)").option("--from-address <address>", "Wallet/account address to quote from without changing signer selection").option("--slippage <percent>", "Max slippage percentage (omit to use the API default)");
|
|
7218
7450
|
addSignerOption(quoteCmd);
|
|
7219
7451
|
quoteCmd.addHelpText(
|
|
7220
7452
|
"after",
|
|
@@ -7256,8 +7488,9 @@ async function performBridgeQuote(program2, opts) {
|
|
|
7256
7488
|
validateAddress(opts.from);
|
|
7257
7489
|
const toChainId = bridgeDestinationChainId(opts.toNetwork);
|
|
7258
7490
|
validateAddress(opts.to);
|
|
7491
|
+
if (opts.fromAddress) validateAddress(opts.fromAddress);
|
|
7259
7492
|
const signer = parseSignerOpt(opts.signer);
|
|
7260
|
-
const { client, network, paymaster } = buildWalletClient(program2, { signer });
|
|
7493
|
+
const { client, network, address: fromAddress, paymaster } = opts.fromAddress ? buildWalletQuoteClient(program2, opts.fromAddress) : buildWalletClient(program2, { signer });
|
|
7261
7494
|
validateBridgeNetworks(network, opts.toNetwork);
|
|
7262
7495
|
const swapClient = client.extend(swapActions2);
|
|
7263
7496
|
const fromInfo = await resolveTokenInfo2(network, program2, opts.from);
|
|
@@ -7266,17 +7499,23 @@ async function performBridgeQuote(program2, opts) {
|
|
|
7266
7499
|
if (slippage !== void 0 && (isNaN(slippage) || slippage < 0 || slippage > 100)) {
|
|
7267
7500
|
throw errInvalidArgs("Slippage must be a number between 0 and 100.");
|
|
7268
7501
|
}
|
|
7269
|
-
|
|
7270
|
-
|
|
7271
|
-
|
|
7272
|
-
|
|
7273
|
-
|
|
7502
|
+
let quote;
|
|
7503
|
+
try {
|
|
7504
|
+
quote = await withSpinner(
|
|
7505
|
+
"Fetching bridge quote\u2026",
|
|
7506
|
+
"Quote received",
|
|
7507
|
+
() => swapClient.requestQuoteV0(createBridgeQuoteRequest(opts.from, opts.to, rawAmount, toChainId, slippage, paymaster, fromAddress))
|
|
7508
|
+
);
|
|
7509
|
+
} catch (err) {
|
|
7510
|
+
throw normalizeQuoteError(err, "bridge");
|
|
7511
|
+
}
|
|
7274
7512
|
const toInfo = await resolveTokenInfo2(opts.toNetwork, program2, opts.to);
|
|
7275
7513
|
const quoteData = extractQuoteData2(quote);
|
|
7276
7514
|
if (isJSONMode()) {
|
|
7277
7515
|
printJSON({
|
|
7278
7516
|
fromToken: opts.from,
|
|
7279
7517
|
toToken: opts.to,
|
|
7518
|
+
fromAddress,
|
|
7280
7519
|
fromAmount: opts.amount,
|
|
7281
7520
|
fromSymbol: fromInfo.symbol,
|
|
7282
7521
|
toSymbol: toInfo.symbol,
|
|
@@ -7296,6 +7535,7 @@ async function performBridgeQuote(program2, opts) {
|
|
|
7296
7535
|
pairs.push(["To", toInfo.symbol]);
|
|
7297
7536
|
}
|
|
7298
7537
|
pairs.push(
|
|
7538
|
+
["Wallet", fromAddress],
|
|
7299
7539
|
["Slippage", slippage === void 0 ? "API default" : `${slippage}%`],
|
|
7300
7540
|
["From Network", network],
|
|
7301
7541
|
["To Network", opts.toNetwork]
|
|
@@ -7317,11 +7557,16 @@ async function performBridgeExecute(program2, opts) {
|
|
|
7317
7557
|
if (slippage !== void 0 && (isNaN(slippage) || slippage < 0 || slippage > 100)) {
|
|
7318
7558
|
throw errInvalidArgs("Slippage must be a number between 0 and 100.");
|
|
7319
7559
|
}
|
|
7320
|
-
|
|
7321
|
-
|
|
7322
|
-
|
|
7323
|
-
|
|
7324
|
-
|
|
7560
|
+
let quote;
|
|
7561
|
+
try {
|
|
7562
|
+
quote = await withSpinner(
|
|
7563
|
+
"Fetching bridge quote\u2026",
|
|
7564
|
+
"Quote received",
|
|
7565
|
+
() => swapClient.requestQuoteV0(createBridgeQuoteRequest(opts.from, opts.to, rawAmount, toChainId, slippage, paymaster, from))
|
|
7566
|
+
);
|
|
7567
|
+
} catch (err) {
|
|
7568
|
+
throw normalizeQuoteError(err, "bridge");
|
|
7569
|
+
}
|
|
7325
7570
|
const preparedQuote = await prepareQuoteForExecution2(client, quote);
|
|
7326
7571
|
const { id } = await withSpinner(
|
|
7327
7572
|
"Sending bridge transaction\u2026",
|
|
@@ -7866,13 +8111,62 @@ function registerInstall(program2) {
|
|
|
7866
8111
|
}
|
|
7867
8112
|
|
|
7868
8113
|
// src/commands/doctor.ts
|
|
8114
|
+
var DOCTOR_SETUP_CAPABILITY_ORDER = SETUP_CAPABILITY_ORDER.filter(
|
|
8115
|
+
(capability) => capability !== "x402"
|
|
8116
|
+
);
|
|
8117
|
+
function removeX402SetupMissing(missing) {
|
|
8118
|
+
return missing.map(
|
|
8119
|
+
(item) => item.replace(" OR SIWx wallet", "").replace(" or x402 wallet", "")
|
|
8120
|
+
);
|
|
8121
|
+
}
|
|
8122
|
+
function removeX402NextCommands(commands) {
|
|
8123
|
+
return commands.filter((command) => !/x402|siwx/i.test(command));
|
|
8124
|
+
}
|
|
8125
|
+
function sanitizeCapabilityStatus(status) {
|
|
8126
|
+
if (status.satisfiedBy !== "x402_wallet") {
|
|
8127
|
+
return {
|
|
8128
|
+
...status,
|
|
8129
|
+
missing: removeX402SetupMissing(status.missing),
|
|
8130
|
+
nextCommands: removeX402NextCommands(status.nextCommands)
|
|
8131
|
+
};
|
|
8132
|
+
}
|
|
8133
|
+
return {
|
|
8134
|
+
complete: false,
|
|
8135
|
+
satisfiedBy: null,
|
|
8136
|
+
missing: ["api-key"],
|
|
8137
|
+
nextCommands: ["alchemy config set app", "alchemy config set api-key <key>"]
|
|
8138
|
+
};
|
|
8139
|
+
}
|
|
8140
|
+
function doctorSetupStatus(setup) {
|
|
8141
|
+
const { x402: _x402, ...capabilities } = setup.capabilities;
|
|
8142
|
+
const sanitizedCapabilities = Object.fromEntries(
|
|
8143
|
+
Object.entries(capabilities).map(([capability, status]) => [
|
|
8144
|
+
capability,
|
|
8145
|
+
sanitizeCapabilityStatus(status)
|
|
8146
|
+
])
|
|
8147
|
+
);
|
|
8148
|
+
const x402OnlySetup = setup.satisfiedBy === "x402_wallet";
|
|
8149
|
+
return {
|
|
8150
|
+
...setup,
|
|
8151
|
+
complete: x402OnlySetup ? false : setup.complete,
|
|
8152
|
+
satisfiedBy: x402OnlySetup ? null : setup.satisfiedBy,
|
|
8153
|
+
missing: x402OnlySetup ? ["Provide one auth path: alchemy auth OR api-key OR ALCHEMY_ACCESS_KEY+app"] : removeX402SetupMissing(setup.missing),
|
|
8154
|
+
nextCommands: x402OnlySetup ? [
|
|
8155
|
+
"alchemy auth",
|
|
8156
|
+
"alchemy config set app",
|
|
8157
|
+
"alchemy config set access-key <key> && alchemy config set app <app-id>"
|
|
8158
|
+
] : removeX402NextCommands(setup.nextCommands),
|
|
8159
|
+
capabilities: sanitizedCapabilities
|
|
8160
|
+
};
|
|
8161
|
+
}
|
|
7869
8162
|
function registerDoctor(program2) {
|
|
7870
8163
|
program2.command("doctor").description("Run readiness checks and print suggested fixes").action(() => {
|
|
7871
|
-
const setup = getSetupStatus(load());
|
|
8164
|
+
const setup = doctorSetupStatus(getSetupStatus(load()));
|
|
7872
8165
|
const payload = {
|
|
7873
8166
|
ok: setup.complete,
|
|
7874
8167
|
checks: {
|
|
7875
|
-
setup
|
|
8168
|
+
setup,
|
|
8169
|
+
capabilities: setup.capabilities
|
|
7876
8170
|
}
|
|
7877
8171
|
};
|
|
7878
8172
|
if (isJSONMode()) {
|
|
@@ -7891,6 +8185,15 @@ function registerDoctor(program2) {
|
|
|
7891
8185
|
console.log(` ${command}`);
|
|
7892
8186
|
}
|
|
7893
8187
|
}
|
|
8188
|
+
console.log("");
|
|
8189
|
+
console.log(` ${dim("Capabilities:")}`);
|
|
8190
|
+
printKeyValue(
|
|
8191
|
+
DOCTOR_SETUP_CAPABILITY_ORDER.map((capability) => {
|
|
8192
|
+
const status = setup.capabilities[capability];
|
|
8193
|
+
const value = status.complete ? green(`ready${status.satisfiedBy ? ` (${status.satisfiedBy})` : ""}`) : dim(`missing ${status.missing.join(", ")}`);
|
|
8194
|
+
return [SETUP_CAPABILITY_LABELS[capability], value];
|
|
8195
|
+
})
|
|
8196
|
+
);
|
|
7894
8197
|
});
|
|
7895
8198
|
}
|
|
7896
8199
|
|
|
@@ -7987,9 +8290,15 @@ function resetUpdateNoticeState() {
|
|
|
7987
8290
|
cachedAvailableUpdate = void 0;
|
|
7988
8291
|
updateShownDuringInteractiveStartup = false;
|
|
7989
8292
|
}
|
|
8293
|
+
async function flushProcessOutput() {
|
|
8294
|
+
await Promise.all([
|
|
8295
|
+
new Promise((resolve) => process.stdout.write("", () => resolve())),
|
|
8296
|
+
new Promise((resolve) => process.stderr.write("", () => resolve()))
|
|
8297
|
+
]);
|
|
8298
|
+
}
|
|
7990
8299
|
program.name("alchemy").description(
|
|
7991
8300
|
"The Alchemy CLI lets you query blockchain data, call JSON-RPC methods, and manage your Alchemy configuration."
|
|
7992
|
-
).version("0.7.
|
|
8301
|
+
).version("0.7.3", "-v, --version", "display CLI version").option("--api-key <key>", "Alchemy API key (env: ALCHEMY_API_KEY)").option(
|
|
7993
8302
|
"-n, --network <network>",
|
|
7994
8303
|
"Target network (default: eth-mainnet) (env: ALCHEMY_NETWORK)"
|
|
7995
8304
|
).option("--x402", "Use x402 wallet-based gateway auth").option(
|
|
@@ -8176,17 +8485,17 @@ ${styledLine}`;
|
|
|
8176
8485
|
"wallet"
|
|
8177
8486
|
];
|
|
8178
8487
|
if (!skipAppPrompt.includes(cmdName) && isInteractiveAllowed(program) && !opts.apiKey && !process.env.ALCHEMY_API_KEY) {
|
|
8179
|
-
const { resolveAuthToken: resolveAuthToken2 } = await import("./resolve-
|
|
8488
|
+
const { resolveAuthToken: resolveAuthToken2 } = await import("./resolve-WXT5ZCUK.js");
|
|
8180
8489
|
const authToken = resolveAuthToken2(cfg);
|
|
8181
8490
|
const hasApiKey = Boolean(cfg.api_key?.trim() || cfg.app?.apiKey);
|
|
8182
8491
|
if (authToken && !hasApiKey) {
|
|
8183
|
-
const { selectAppAfterAuth } = await import("./auth-
|
|
8492
|
+
const { selectAppAfterAuth } = await import("./auth-F2IXC6CM.js");
|
|
8184
8493
|
console.log("");
|
|
8185
8494
|
console.log(` No app selected. Please select an app to continue.`);
|
|
8186
8495
|
await selectAppAfterAuth(authToken);
|
|
8187
8496
|
}
|
|
8188
8497
|
}
|
|
8189
|
-
}).hook("postAction", () => {
|
|
8498
|
+
}).hook("postAction", async () => {
|
|
8190
8499
|
if (!isJSONMode() && !quiet) {
|
|
8191
8500
|
console.log("");
|
|
8192
8501
|
if (!updateShownDuringInteractiveStartup) {
|
|
@@ -8196,6 +8505,7 @@ ${styledLine}`;
|
|
|
8196
8505
|
}
|
|
8197
8506
|
resetUpdateNoticeState();
|
|
8198
8507
|
if (!isReplMode()) {
|
|
8508
|
+
await flushProcessOutput();
|
|
8199
8509
|
process.exit(0);
|
|
8200
8510
|
}
|
|
8201
8511
|
}).action(async (_opts, cmd) => {
|
|
@@ -8214,7 +8524,7 @@ ${styledLine}`;
|
|
|
8214
8524
|
if (isInteractiveAllowed(program)) {
|
|
8215
8525
|
let latestForInteractiveStartup = null;
|
|
8216
8526
|
if (shouldRunOnboarding(program, cfg)) {
|
|
8217
|
-
const { runOnboarding } = await import("./onboarding-
|
|
8527
|
+
const { runOnboarding } = await import("./onboarding-TTUVIXM4.js");
|
|
8218
8528
|
const latest = getAvailableUpdateOnce();
|
|
8219
8529
|
const completed = await runOnboarding(program, latest);
|
|
8220
8530
|
updateShownDuringInteractiveStartup = Boolean(latest);
|
|
@@ -8228,7 +8538,7 @@ ${styledLine}`;
|
|
|
8228
8538
|
latestForInteractiveStartup
|
|
8229
8539
|
);
|
|
8230
8540
|
}
|
|
8231
|
-
const { startREPL } = await import("./interactive-
|
|
8541
|
+
const { startREPL } = await import("./interactive-BNIJYEOV.js");
|
|
8232
8542
|
program.exitOverride();
|
|
8233
8543
|
program.configureOutput({
|
|
8234
8544
|
writeErr: () => {
|