@alchemy/cli 0.7.1 → 0.7.2-alpha.26
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-JGON2JU6.js → auth-GD7BJOMK.js} +2 -2
- package/dist/{chunk-QEDAULQ2.js → chunk-2BALTY22.js} +6 -19
- package/dist/{chunk-5IFXLC2S.js → chunk-5IL2PMZ6.js} +1 -1
- package/dist/{chunk-HYCRHNPX.js → chunk-64A5W4M2.js} +1 -1
- package/dist/{chunk-HSKKIATB.js → chunk-C5HNQOLB.js} +1 -1
- package/dist/{chunk-7WD3YLRK.js → chunk-JUCUKTP3.js} +1 -1
- package/dist/{chunk-TOEVZMIP.js → chunk-K6V3R7SH.js} +514 -509
- package/dist/chunk-R4W44A6E.js +134 -0
- package/dist/{chunk-SYP6KKP6.js → chunk-XSN4XA5Z.js} +6 -6
- package/dist/{chunk-RS3DSL3X.js → chunk-YQZLLSGS.js} +3 -3
- package/dist/{errors-3CNFGAXT.js → errors-E2P6WHTX.js} +3 -1
- package/dist/index.js +395 -81
- package/dist/{interactive-N33RCX33.js → interactive-3L4IXWXJ.js} +13 -10
- package/dist/{onboarding-S6HKWOEA.js → onboarding-6FSQLTHP.js} +6 -6
- package/dist/{resolve-R4JZZCCF.js → resolve-WXT5ZCUK.js} +3 -3
- package/package.json +18 -24
- package/scripts/postinstall.cjs +2 -0
- package/dist/auth-BNT5Z5GZ.js +0 -16
- package/dist/chunk-V4IK4CJN.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-YQZLLSGS.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,
|
|
@@ -108,6 +110,7 @@ import {
|
|
|
108
110
|
identity,
|
|
109
111
|
isJSONMode,
|
|
110
112
|
isLocalhost,
|
|
113
|
+
isReplMode,
|
|
111
114
|
noColor,
|
|
112
115
|
parseBaseURLOverride,
|
|
113
116
|
printHuman,
|
|
@@ -116,7 +119,7 @@ import {
|
|
|
116
119
|
setFlags,
|
|
117
120
|
setNoColor,
|
|
118
121
|
verbose
|
|
119
|
-
} from "./chunk-
|
|
122
|
+
} from "./chunk-2BALTY22.js";
|
|
120
123
|
|
|
121
124
|
// src/index.ts
|
|
122
125
|
import { Command, Help } from "commander";
|
|
@@ -623,7 +626,7 @@ function registerConfig(program2) {
|
|
|
623
626
|
printJSON(toMap(cfg));
|
|
624
627
|
return;
|
|
625
628
|
}
|
|
626
|
-
const { resolveAuthToken: resolveAuthToken2 } = await import("./resolve-
|
|
629
|
+
const { resolveAuthToken: resolveAuthToken2 } = await import("./resolve-WXT5ZCUK.js");
|
|
627
630
|
const validToken = resolveAuthToken2(cfg);
|
|
628
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");
|
|
629
632
|
const pairs = [
|
|
@@ -737,6 +740,15 @@ function registerConfig(program2) {
|
|
|
737
740
|
console.log(` ${dim(`- ${command}`)}`);
|
|
738
741
|
}
|
|
739
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
|
+
);
|
|
740
752
|
});
|
|
741
753
|
}
|
|
742
754
|
|
|
@@ -2681,6 +2693,8 @@ function registerWallets(program2) {
|
|
|
2681
2693
|
}
|
|
2682
2694
|
|
|
2683
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";
|
|
2684
2698
|
function withQuery(url, query) {
|
|
2685
2699
|
if (!query) return url;
|
|
2686
2700
|
for (const [key, value] of Object.entries(query)) {
|
|
@@ -2714,13 +2728,15 @@ async function requestJSON(url, options) {
|
|
|
2714
2728
|
}
|
|
2715
2729
|
async function callApiData(apiKey, path, options = {}) {
|
|
2716
2730
|
if (!apiKey) throw errAuthRequired();
|
|
2717
|
-
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}/`);
|
|
2718
2733
|
const url = withQuery(new URL(path.replace(/^\//, ""), base2), options.query);
|
|
2719
2734
|
return requestJSON(url, { ...options, path });
|
|
2720
2735
|
}
|
|
2721
2736
|
async function callApiPrices(apiKey, path, options = {}) {
|
|
2722
2737
|
if (!apiKey) throw errAuthRequired();
|
|
2723
|
-
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}/`);
|
|
2724
2740
|
const url = withQuery(new URL(path.replace(/^\//, ""), base2), options.query);
|
|
2725
2741
|
return requestJSON(url, { ...options, path });
|
|
2726
2742
|
}
|
|
@@ -3631,7 +3647,7 @@ async function performSolanaSend(program2, toArg, amountArg, tokenAddress, opts
|
|
|
3631
3647
|
}
|
|
3632
3648
|
|
|
3633
3649
|
// src/lib/smart-wallet.ts
|
|
3634
|
-
import { createSmartWalletClient
|
|
3650
|
+
import { createSmartWalletClient } from "@alchemy/wallet-apis";
|
|
3635
3651
|
import { privateKeyToAccount as privateKeyToAccount2 } from "viem/accounts";
|
|
3636
3652
|
|
|
3637
3653
|
// src/lib/chains.ts
|
|
@@ -3970,6 +3986,17 @@ function createDelegatedAccount(args) {
|
|
|
3970
3986
|
});
|
|
3971
3987
|
}
|
|
3972
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
|
+
|
|
3973
4000
|
// src/lib/smart-wallet.ts
|
|
3974
4001
|
function normalizeKey(key) {
|
|
3975
4002
|
const trimmed = key.trim();
|
|
@@ -4068,7 +4095,7 @@ function buildWalletClient(program2, options = {}) {
|
|
|
4068
4095
|
}
|
|
4069
4096
|
const paymaster = gasSponsored && gasPolicyId ? { policyId: gasPolicyId } : void 0;
|
|
4070
4097
|
const client = createSmartWalletClient({
|
|
4071
|
-
transport:
|
|
4098
|
+
transport: createAlchemyWalletTransport(apiKey),
|
|
4072
4099
|
chain,
|
|
4073
4100
|
signer: signerConfig.signer,
|
|
4074
4101
|
paymaster
|
|
@@ -4639,6 +4666,7 @@ var ERROR_RECOVERY = {
|
|
|
4639
4666
|
RATE_LIMITED: "Wait and retry; consider upgrading your Alchemy plan",
|
|
4640
4667
|
PAYMENT_REQUIRED: "Fund your x402 wallet or switch to API key auth",
|
|
4641
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",
|
|
4642
4670
|
INTERNAL_ERROR: "Unexpected error; retry or report a bug"
|
|
4643
4671
|
};
|
|
4644
4672
|
function buildCommandSchema(cmd) {
|
|
@@ -4693,11 +4721,13 @@ function buildAgentPrompt(program2) {
|
|
|
4693
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",
|
|
4694
4722
|
"Use the user's installed alchemy binary only when executing commands against their local config or diagnosing their installed version",
|
|
4695
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",
|
|
4696
|
-
"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"
|
|
4697
4727
|
],
|
|
4698
4728
|
preflight: {
|
|
4699
4729
|
command: "alchemy --json --no-interactive config status",
|
|
4700
|
-
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."
|
|
4701
4731
|
},
|
|
4702
4732
|
runtimeDiscovery: {
|
|
4703
4733
|
installed: {
|
|
@@ -4809,9 +4839,11 @@ function buildAgentPrompt(program2) {
|
|
|
4809
4839
|
"ALCHEMY_ACCESS_KEY=ak_xxx alchemy --json --no-interactive app list",
|
|
4810
4840
|
"alchemy --json --no-interactive evm rpc eth_blockNumber --api-key $ALCHEMY_API_KEY",
|
|
4811
4841
|
"alchemy --json --no-interactive evm network list",
|
|
4812
|
-
"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",
|
|
4813
4843
|
`alchemy --json --no-interactive evm contract read 0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48 "balanceOf(address)(uint256)" --args '["0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045"]' -n eth-mainnet`,
|
|
4814
|
-
"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",
|
|
4815
4847
|
"alchemy --json --no-interactive evm status 0xCallId -n eth-mainnet"
|
|
4816
4848
|
],
|
|
4817
4849
|
docs: "https://www.alchemy.com/docs"
|
|
@@ -5153,15 +5185,26 @@ async function performApprove(program2, spenderArg, opts) {
|
|
|
5153
5185
|
}
|
|
5154
5186
|
|
|
5155
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
|
+
}
|
|
5156
5199
|
function registerBlock(program2) {
|
|
5157
|
-
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(
|
|
5158
5201
|
"after",
|
|
5159
5202
|
`
|
|
5160
5203
|
Examples:
|
|
5161
5204
|
alchemy evm block latest
|
|
5162
5205
|
alchemy evm block 17000000
|
|
5163
5206
|
alchemy evm block 0x1`
|
|
5164
|
-
).action(async (blockId) => {
|
|
5207
|
+
).action(async (blockId, opts) => {
|
|
5165
5208
|
try {
|
|
5166
5209
|
let blockParam;
|
|
5167
5210
|
if (["latest", "earliest", "pending"].includes(blockId)) {
|
|
@@ -5188,7 +5231,7 @@ Examples:
|
|
|
5188
5231
|
);
|
|
5189
5232
|
if (!block) throw errNotFound(`block ${blockId}`);
|
|
5190
5233
|
if (isJSONMode()) {
|
|
5191
|
-
printJSON(block);
|
|
5234
|
+
printJSON(opts.summary ? summarizeBlock(block) : block);
|
|
5192
5235
|
return;
|
|
5193
5236
|
}
|
|
5194
5237
|
const pairs = [];
|
|
@@ -6236,60 +6279,74 @@ async function runDataCall(program2, title, path, body) {
|
|
|
6236
6279
|
() => x402 ? x402.callRest(`data/v1${path}`, { method: "POST", body }) : callApiData(resolveAPIKey(program2), path, { method: "POST", body })
|
|
6237
6280
|
);
|
|
6238
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
|
+
}
|
|
6239
6304
|
function registerPortfolio(program2) {
|
|
6240
6305
|
const cmd = program2.command("portfolio").description("Portfolio API wrappers");
|
|
6241
|
-
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) => {
|
|
6242
6307
|
try {
|
|
6243
|
-
|
|
6308
|
+
await runPortfolioCommand(
|
|
6244
6309
|
program2,
|
|
6245
6310
|
"token portfolio",
|
|
6246
6311
|
"/assets/tokens/by-address",
|
|
6247
|
-
|
|
6312
|
+
opts
|
|
6248
6313
|
);
|
|
6249
|
-
if (isJSONMode()) printJSON(result);
|
|
6250
|
-
else printSyntaxJSON(result);
|
|
6251
6314
|
} catch (err) {
|
|
6252
6315
|
exitWithError(err);
|
|
6253
6316
|
}
|
|
6254
6317
|
});
|
|
6255
|
-
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) => {
|
|
6256
6319
|
try {
|
|
6257
|
-
|
|
6320
|
+
await runPortfolioCommand(
|
|
6258
6321
|
program2,
|
|
6259
6322
|
"token balances",
|
|
6260
6323
|
"/assets/tokens/balances/by-address",
|
|
6261
|
-
|
|
6324
|
+
opts
|
|
6262
6325
|
);
|
|
6263
|
-
if (isJSONMode()) printJSON(result);
|
|
6264
|
-
else printSyntaxJSON(result);
|
|
6265
6326
|
} catch (err) {
|
|
6266
6327
|
exitWithError(err);
|
|
6267
6328
|
}
|
|
6268
6329
|
});
|
|
6269
|
-
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) => {
|
|
6270
6331
|
try {
|
|
6271
|
-
|
|
6332
|
+
await runPortfolioCommand(
|
|
6272
6333
|
program2,
|
|
6273
6334
|
"NFT portfolio",
|
|
6274
6335
|
"/assets/nfts/by-address",
|
|
6275
|
-
|
|
6336
|
+
opts
|
|
6276
6337
|
);
|
|
6277
|
-
if (isJSONMode()) printJSON(result);
|
|
6278
|
-
else printSyntaxJSON(result);
|
|
6279
6338
|
} catch (err) {
|
|
6280
6339
|
exitWithError(err);
|
|
6281
6340
|
}
|
|
6282
6341
|
});
|
|
6283
|
-
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) => {
|
|
6284
6343
|
try {
|
|
6285
|
-
|
|
6344
|
+
await runPortfolioCommand(
|
|
6286
6345
|
program2,
|
|
6287
6346
|
"NFT contracts",
|
|
6288
6347
|
"/assets/nfts/contracts/by-address",
|
|
6289
|
-
|
|
6348
|
+
opts
|
|
6290
6349
|
);
|
|
6291
|
-
if (isJSONMode()) printJSON(result);
|
|
6292
|
-
else printSyntaxJSON(result);
|
|
6293
6350
|
} catch (err) {
|
|
6294
6351
|
exitWithError(err);
|
|
6295
6352
|
}
|
|
@@ -6453,8 +6510,9 @@ Examples:
|
|
|
6453
6510
|
alchemy evm logs --address 0xdAC17F958D2ee523a2206206994597C13D831ec7 --from-block 18000000 --to-block 18000010
|
|
6454
6511
|
alchemy evm logs --address 0xdAC17F958D2ee523a2206206994597C13D831ec7 --topic 0xddf252ad...
|
|
6455
6512
|
alchemy evm logs --from-block latest --json`
|
|
6456
|
-
).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) => {
|
|
6457
6514
|
try {
|
|
6515
|
+
const outputLimit = parseOptionalInt(opts.limit, "--limit");
|
|
6458
6516
|
const filter = {
|
|
6459
6517
|
fromBlock: normalizeBlockParam(opts.fromBlock),
|
|
6460
6518
|
toBlock: normalizeBlockParam(opts.toBlock)
|
|
@@ -6472,20 +6530,41 @@ Examples:
|
|
|
6472
6530
|
() => client.call("eth_getLogs", [filter])
|
|
6473
6531
|
);
|
|
6474
6532
|
const network = resolveNetwork(program2);
|
|
6533
|
+
const displayedLogs = outputLimit === void 0 ? logs : logs.slice(0, outputLimit);
|
|
6475
6534
|
if (isJSONMode()) {
|
|
6476
|
-
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
|
+
});
|
|
6477
6544
|
return;
|
|
6478
6545
|
}
|
|
6479
6546
|
if (logs.length === 0) {
|
|
6480
6547
|
console.log(dim("No logs found for the given filter."));
|
|
6481
6548
|
return;
|
|
6482
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
|
+
}
|
|
6483
6554
|
const total = logs.length;
|
|
6484
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
|
+
}
|
|
6485
6564
|
if (!interactive) {
|
|
6486
6565
|
console.log(`Found ${total} log${total === 1 ? "" : "s"} on ${network}
|
|
6487
6566
|
`);
|
|
6488
|
-
printTable(TABLE_HEADERS2, formatLogRows(
|
|
6567
|
+
printTable(TABLE_HEADERS2, formatLogRows(displayedLogs));
|
|
6489
6568
|
} else {
|
|
6490
6569
|
let offset = 0;
|
|
6491
6570
|
const firstPage = logs.slice(0, PAGE_SIZE);
|
|
@@ -6615,8 +6694,15 @@ Examples:
|
|
|
6615
6694
|
// src/commands/send-evm.ts
|
|
6616
6695
|
import { encodeFunctionData as encodeFunctionData3, erc20Abi as erc20Abi2 } from "viem";
|
|
6617
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
|
+
}
|
|
6618
6704
|
function registerEvmSend(program2) {
|
|
6619
|
-
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");
|
|
6620
6706
|
addSignerOption(sendCmd);
|
|
6621
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(
|
|
6622
6708
|
"after",
|
|
@@ -6625,16 +6711,18 @@ Examples:
|
|
|
6625
6711
|
alchemy evm send 0xAbC...123 1.5 Send 1.5 ETH
|
|
6626
6712
|
alchemy evm send vitalik.eth 0.1 -n base-mainnet Send 0.1 ETH on Base
|
|
6627
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
|
|
6628
6715
|
alchemy evm send 0xAbC...123 1 --gas-sponsored --gas-policy-id <id>
|
|
6629
6716
|
alchemy evm send 0xAbC...123 1.5 --signer local Force the local wallet`
|
|
6630
6717
|
).action(async (toArg, amountArg, _opts, cmd) => {
|
|
6631
6718
|
try {
|
|
6632
6719
|
const opts = cmd.opts();
|
|
6633
6720
|
await performEvmSend(cmd, toArg, amountArg, opts.token, {
|
|
6634
|
-
signer: parseSignerOpt(opts.signer)
|
|
6721
|
+
signer: parseSignerOpt(opts.signer),
|
|
6722
|
+
dryRun: opts.dryRun
|
|
6635
6723
|
});
|
|
6636
6724
|
} catch (err) {
|
|
6637
|
-
const { exitWithError: exitWithError2 } = await import("./errors-
|
|
6725
|
+
const { exitWithError: exitWithError2 } = await import("./errors-E2P6WHTX.js");
|
|
6638
6726
|
exitWithError2(err);
|
|
6639
6727
|
}
|
|
6640
6728
|
});
|
|
@@ -6665,6 +6753,37 @@ async function performEvmSend(program2, toArg, amountArg, tokenAddress, opts = {
|
|
|
6665
6753
|
args: [to, wei]
|
|
6666
6754
|
})
|
|
6667
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
|
+
}
|
|
6668
6787
|
const { id } = await withSpinner(
|
|
6669
6788
|
"Sending transaction\u2026",
|
|
6670
6789
|
"Transaction submitted",
|
|
@@ -6769,6 +6888,105 @@ function registerSimulate(program2) {
|
|
|
6769
6888
|
import {
|
|
6770
6889
|
swapActions
|
|
6771
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
|
|
6772
6990
|
var NATIVE_TOKEN_ADDRESS2 = "0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE";
|
|
6773
6991
|
var NATIVE_DECIMALS = 18;
|
|
6774
6992
|
function isNativeToken2(address2) {
|
|
@@ -6791,11 +7009,12 @@ async function resolveTokenInfo(network, program2, tokenAddress) {
|
|
|
6791
7009
|
throw errInvalidArgs(`Failed to resolve token info for ${tokenAddress}.${detail}`);
|
|
6792
7010
|
}
|
|
6793
7011
|
}
|
|
6794
|
-
function createQuoteRequest(fromToken, toToken, fromAmount, slippagePercent, paymaster) {
|
|
7012
|
+
function createQuoteRequest(fromToken, toToken, fromAmount, slippagePercent, paymaster, account) {
|
|
6795
7013
|
const request2 = {
|
|
6796
7014
|
fromToken,
|
|
6797
7015
|
toToken,
|
|
6798
7016
|
fromAmount,
|
|
7017
|
+
...account ? { account } : {},
|
|
6799
7018
|
...slippagePercent !== void 0 ? { slippage: slippagePercentToBasisPoints(slippagePercent) } : {},
|
|
6800
7019
|
...paymaster ? { capabilities: { paymaster } } : {}
|
|
6801
7020
|
};
|
|
@@ -6842,7 +7061,7 @@ async function prepareQuoteForExecution(client, quote) {
|
|
|
6842
7061
|
}
|
|
6843
7062
|
function registerSwap(program2) {
|
|
6844
7063
|
const cmd = program2.command("swap").description("Swap tokens on the same chain");
|
|
6845
|
-
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)");
|
|
6846
7065
|
addSignerOption(quoteCmd);
|
|
6847
7066
|
quoteCmd.addHelpText(
|
|
6848
7067
|
"after",
|
|
@@ -6879,8 +7098,9 @@ async function performSwapQuote(program2, opts) {
|
|
|
6879
7098
|
validateSwapNetwork(resolveNetwork(program2));
|
|
6880
7099
|
validateAddress(opts.from);
|
|
6881
7100
|
validateAddress(opts.to);
|
|
7101
|
+
if (opts.fromAddress) validateAddress(opts.fromAddress);
|
|
6882
7102
|
const signer = parseSignerOpt(opts.signer);
|
|
6883
|
-
const { client, network, paymaster } = buildWalletClient(program2, { signer });
|
|
7103
|
+
const { client, network, address: fromAddress, paymaster } = opts.fromAddress ? buildWalletQuoteClient(program2, opts.fromAddress) : buildWalletClient(program2, { signer });
|
|
6884
7104
|
const swapClient = client.extend(swapActions);
|
|
6885
7105
|
const fromInfo = await resolveTokenInfo(network, program2, opts.from);
|
|
6886
7106
|
const rawAmount = parseAmount(opts.amount, fromInfo.decimals);
|
|
@@ -6888,17 +7108,23 @@ async function performSwapQuote(program2, opts) {
|
|
|
6888
7108
|
if (slippage !== void 0 && (isNaN(slippage) || slippage < 0 || slippage > 100)) {
|
|
6889
7109
|
throw errInvalidArgs("Slippage must be a number between 0 and 100.");
|
|
6890
7110
|
}
|
|
6891
|
-
|
|
6892
|
-
|
|
6893
|
-
|
|
6894
|
-
|
|
6895
|
-
|
|
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
|
+
}
|
|
6896
7121
|
const toInfo = await resolveTokenInfo(network, program2, opts.to);
|
|
6897
7122
|
const quoteData = extractQuoteData(quote);
|
|
6898
7123
|
if (isJSONMode()) {
|
|
6899
7124
|
printJSON({
|
|
6900
7125
|
fromToken: opts.from,
|
|
6901
7126
|
toToken: opts.to,
|
|
7127
|
+
fromAddress,
|
|
6902
7128
|
fromAmount: opts.amount,
|
|
6903
7129
|
fromSymbol: fromInfo.symbol,
|
|
6904
7130
|
toSymbol: toInfo.symbol,
|
|
@@ -6917,6 +7143,7 @@ async function performSwapQuote(program2, opts) {
|
|
|
6917
7143
|
pairs.push(["To", `${toInfo.symbol}`]);
|
|
6918
7144
|
}
|
|
6919
7145
|
pairs.push(
|
|
7146
|
+
["Wallet", fromAddress],
|
|
6920
7147
|
["Slippage", slippage === void 0 ? "API default" : `${slippage}%`],
|
|
6921
7148
|
["Network", network]
|
|
6922
7149
|
);
|
|
@@ -6936,11 +7163,16 @@ async function performSwapExecute(program2, opts) {
|
|
|
6936
7163
|
if (slippage !== void 0 && (isNaN(slippage) || slippage < 0 || slippage > 100)) {
|
|
6937
7164
|
throw errInvalidArgs("Slippage must be a number between 0 and 100.");
|
|
6938
7165
|
}
|
|
6939
|
-
|
|
6940
|
-
|
|
6941
|
-
|
|
6942
|
-
|
|
6943
|
-
|
|
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
|
+
}
|
|
6944
7176
|
const preparedQuote = await prepareQuoteForExecution(client, quote);
|
|
6945
7177
|
const { id } = await withSpinner(
|
|
6946
7178
|
"Sending swap transaction\u2026",
|
|
@@ -7142,12 +7374,13 @@ async function resolveTokenInfo2(network, program2, tokenAddress) {
|
|
|
7142
7374
|
throw errInvalidArgs(`Failed to resolve token info for ${tokenAddress}.${detail}`);
|
|
7143
7375
|
}
|
|
7144
7376
|
}
|
|
7145
|
-
function createBridgeQuoteRequest(fromToken, toToken, fromAmount, toChainId, slippagePercent, paymaster) {
|
|
7377
|
+
function createBridgeQuoteRequest(fromToken, toToken, fromAmount, toChainId, slippagePercent, paymaster, account) {
|
|
7146
7378
|
const request2 = {
|
|
7147
7379
|
fromToken,
|
|
7148
7380
|
toToken,
|
|
7149
7381
|
fromAmount,
|
|
7150
7382
|
toChainId,
|
|
7383
|
+
...account ? { account } : {},
|
|
7151
7384
|
...slippagePercent !== void 0 ? { slippage: slippagePercentToBasisPoints2(slippagePercent) } : {},
|
|
7152
7385
|
...paymaster ? { capabilities: { paymaster } } : {}
|
|
7153
7386
|
};
|
|
@@ -7213,7 +7446,7 @@ function extractQuoteData2(quote) {
|
|
|
7213
7446
|
}
|
|
7214
7447
|
function registerBridge(program2) {
|
|
7215
7448
|
const cmd = program2.command("bridge").description("Bridge tokens from the source -n/--network to a destination --to-network");
|
|
7216
|
-
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)");
|
|
7217
7450
|
addSignerOption(quoteCmd);
|
|
7218
7451
|
quoteCmd.addHelpText(
|
|
7219
7452
|
"after",
|
|
@@ -7255,8 +7488,9 @@ async function performBridgeQuote(program2, opts) {
|
|
|
7255
7488
|
validateAddress(opts.from);
|
|
7256
7489
|
const toChainId = bridgeDestinationChainId(opts.toNetwork);
|
|
7257
7490
|
validateAddress(opts.to);
|
|
7491
|
+
if (opts.fromAddress) validateAddress(opts.fromAddress);
|
|
7258
7492
|
const signer = parseSignerOpt(opts.signer);
|
|
7259
|
-
const { client, network, paymaster } = buildWalletClient(program2, { signer });
|
|
7493
|
+
const { client, network, address: fromAddress, paymaster } = opts.fromAddress ? buildWalletQuoteClient(program2, opts.fromAddress) : buildWalletClient(program2, { signer });
|
|
7260
7494
|
validateBridgeNetworks(network, opts.toNetwork);
|
|
7261
7495
|
const swapClient = client.extend(swapActions2);
|
|
7262
7496
|
const fromInfo = await resolveTokenInfo2(network, program2, opts.from);
|
|
@@ -7265,17 +7499,23 @@ async function performBridgeQuote(program2, opts) {
|
|
|
7265
7499
|
if (slippage !== void 0 && (isNaN(slippage) || slippage < 0 || slippage > 100)) {
|
|
7266
7500
|
throw errInvalidArgs("Slippage must be a number between 0 and 100.");
|
|
7267
7501
|
}
|
|
7268
|
-
|
|
7269
|
-
|
|
7270
|
-
|
|
7271
|
-
|
|
7272
|
-
|
|
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
|
+
}
|
|
7273
7512
|
const toInfo = await resolveTokenInfo2(opts.toNetwork, program2, opts.to);
|
|
7274
7513
|
const quoteData = extractQuoteData2(quote);
|
|
7275
7514
|
if (isJSONMode()) {
|
|
7276
7515
|
printJSON({
|
|
7277
7516
|
fromToken: opts.from,
|
|
7278
7517
|
toToken: opts.to,
|
|
7518
|
+
fromAddress,
|
|
7279
7519
|
fromAmount: opts.amount,
|
|
7280
7520
|
fromSymbol: fromInfo.symbol,
|
|
7281
7521
|
toSymbol: toInfo.symbol,
|
|
@@ -7295,6 +7535,7 @@ async function performBridgeQuote(program2, opts) {
|
|
|
7295
7535
|
pairs.push(["To", toInfo.symbol]);
|
|
7296
7536
|
}
|
|
7297
7537
|
pairs.push(
|
|
7538
|
+
["Wallet", fromAddress],
|
|
7298
7539
|
["Slippage", slippage === void 0 ? "API default" : `${slippage}%`],
|
|
7299
7540
|
["From Network", network],
|
|
7300
7541
|
["To Network", opts.toNetwork]
|
|
@@ -7316,11 +7557,16 @@ async function performBridgeExecute(program2, opts) {
|
|
|
7316
7557
|
if (slippage !== void 0 && (isNaN(slippage) || slippage < 0 || slippage > 100)) {
|
|
7317
7558
|
throw errInvalidArgs("Slippage must be a number between 0 and 100.");
|
|
7318
7559
|
}
|
|
7319
|
-
|
|
7320
|
-
|
|
7321
|
-
|
|
7322
|
-
|
|
7323
|
-
|
|
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
|
+
}
|
|
7324
7570
|
const preparedQuote = await prepareQuoteForExecution2(client, quote);
|
|
7325
7571
|
const { id } = await withSpinner(
|
|
7326
7572
|
"Sending bridge transaction\u2026",
|
|
@@ -7865,13 +8111,62 @@ function registerInstall(program2) {
|
|
|
7865
8111
|
}
|
|
7866
8112
|
|
|
7867
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
|
+
}
|
|
7868
8162
|
function registerDoctor(program2) {
|
|
7869
8163
|
program2.command("doctor").description("Run readiness checks and print suggested fixes").action(() => {
|
|
7870
|
-
const setup = getSetupStatus(load());
|
|
8164
|
+
const setup = doctorSetupStatus(getSetupStatus(load()));
|
|
7871
8165
|
const payload = {
|
|
7872
8166
|
ok: setup.complete,
|
|
7873
8167
|
checks: {
|
|
7874
|
-
setup
|
|
8168
|
+
setup,
|
|
8169
|
+
capabilities: setup.capabilities
|
|
7875
8170
|
}
|
|
7876
8171
|
};
|
|
7877
8172
|
if (isJSONMode()) {
|
|
@@ -7890,6 +8185,15 @@ function registerDoctor(program2) {
|
|
|
7890
8185
|
console.log(` ${command}`);
|
|
7891
8186
|
}
|
|
7892
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
|
+
);
|
|
7893
8197
|
});
|
|
7894
8198
|
}
|
|
7895
8199
|
|
|
@@ -7986,9 +8290,15 @@ function resetUpdateNoticeState() {
|
|
|
7986
8290
|
cachedAvailableUpdate = void 0;
|
|
7987
8291
|
updateShownDuringInteractiveStartup = false;
|
|
7988
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
|
+
}
|
|
7989
8299
|
program.name("alchemy").description(
|
|
7990
8300
|
"The Alchemy CLI lets you query blockchain data, call JSON-RPC methods, and manage your Alchemy configuration."
|
|
7991
|
-
).version("0.7.
|
|
8301
|
+
).version("0.7.2-alpha.26", "-v, --version", "display CLI version").option("--api-key <key>", "Alchemy API key (env: ALCHEMY_API_KEY)").option(
|
|
7992
8302
|
"-n, --network <network>",
|
|
7993
8303
|
"Target network (default: eth-mainnet) (env: ALCHEMY_NETWORK)"
|
|
7994
8304
|
).option("--x402", "Use x402 wallet-based gateway auth").option(
|
|
@@ -8175,17 +8485,17 @@ ${styledLine}`;
|
|
|
8175
8485
|
"wallet"
|
|
8176
8486
|
];
|
|
8177
8487
|
if (!skipAppPrompt.includes(cmdName) && isInteractiveAllowed(program) && !opts.apiKey && !process.env.ALCHEMY_API_KEY) {
|
|
8178
|
-
const { resolveAuthToken: resolveAuthToken2 } = await import("./resolve-
|
|
8488
|
+
const { resolveAuthToken: resolveAuthToken2 } = await import("./resolve-WXT5ZCUK.js");
|
|
8179
8489
|
const authToken = resolveAuthToken2(cfg);
|
|
8180
8490
|
const hasApiKey = Boolean(cfg.api_key?.trim() || cfg.app?.apiKey);
|
|
8181
8491
|
if (authToken && !hasApiKey) {
|
|
8182
|
-
const { selectAppAfterAuth } = await import("./auth-
|
|
8492
|
+
const { selectAppAfterAuth } = await import("./auth-F2IXC6CM.js");
|
|
8183
8493
|
console.log("");
|
|
8184
8494
|
console.log(` No app selected. Please select an app to continue.`);
|
|
8185
8495
|
await selectAppAfterAuth(authToken);
|
|
8186
8496
|
}
|
|
8187
8497
|
}
|
|
8188
|
-
}).hook("postAction", () => {
|
|
8498
|
+
}).hook("postAction", async () => {
|
|
8189
8499
|
if (!isJSONMode() && !quiet) {
|
|
8190
8500
|
console.log("");
|
|
8191
8501
|
if (!updateShownDuringInteractiveStartup) {
|
|
@@ -8194,6 +8504,10 @@ ${styledLine}`;
|
|
|
8194
8504
|
}
|
|
8195
8505
|
}
|
|
8196
8506
|
resetUpdateNoticeState();
|
|
8507
|
+
if (!isReplMode()) {
|
|
8508
|
+
await flushProcessOutput();
|
|
8509
|
+
process.exit(0);
|
|
8510
|
+
}
|
|
8197
8511
|
}).action(async (_opts, cmd) => {
|
|
8198
8512
|
const excessArgs = cmd.args;
|
|
8199
8513
|
if (excessArgs.length > 0) {
|
|
@@ -8210,7 +8524,7 @@ ${styledLine}`;
|
|
|
8210
8524
|
if (isInteractiveAllowed(program)) {
|
|
8211
8525
|
let latestForInteractiveStartup = null;
|
|
8212
8526
|
if (shouldRunOnboarding(program, cfg)) {
|
|
8213
|
-
const { runOnboarding } = await import("./onboarding-
|
|
8527
|
+
const { runOnboarding } = await import("./onboarding-6FSQLTHP.js");
|
|
8214
8528
|
const latest = getAvailableUpdateOnce();
|
|
8215
8529
|
const completed = await runOnboarding(program, latest);
|
|
8216
8530
|
updateShownDuringInteractiveStartup = Boolean(latest);
|
|
@@ -8224,7 +8538,7 @@ ${styledLine}`;
|
|
|
8224
8538
|
latestForInteractiveStartup
|
|
8225
8539
|
);
|
|
8226
8540
|
}
|
|
8227
|
-
const { startREPL } = await import("./interactive-
|
|
8541
|
+
const { startREPL } = await import("./interactive-3L4IXWXJ.js");
|
|
8228
8542
|
program.exitOverride();
|
|
8229
8543
|
program.configureOutput({
|
|
8230
8544
|
writeErr: () => {
|