Conversation
Add swap quote and execute commands so the CLI can request quotes, handle permit flows, and submit same-chain token swaps with test coverage. Made-with: Cursor
Avoid sending the default slippage value to wallet quote requests so swap quotes and executions use the API default unless the user explicitly overrides it. Made-with: Cursor
Avoid reporting a slippage value the CLI did not send and label swap quote output as a minimum receive amount so the output matches the underlying quote semantics. Made-with: Cursor
src/commands/swap.ts
Outdated
| .description("Get a swap quote without executing") | ||
| .requiredOption("--from <address>", "Token address to swap from (use 0xEeee...EEeE for the native token)") | ||
| .requiredOption("--to <address>", "Token address to swap to") | ||
| .requiredOption("--amount <number>", "Amount to swap (human-readable)") |
There was a problem hiding this comment.
nit: what do we mean by human-readable here?
There was a problem hiding this comment.
yeah this is ambiguous - I updated it.
was basically saying to pass the value in decimal form (human readable) and not in base units like wei
src/commands/swap.ts
Outdated
| .command("quote") | ||
| .description("Get a swap quote without executing") | ||
| .requiredOption("--from <address>", "Token address to swap from (use 0xEeee...EEeE for the native token)") | ||
| .requiredOption("--to <address>", "Token address to swap to") |
There was a problem hiding this comment.
nit: I know it's in the description, but just to add additional guardrail for agents - can we do --to/from <token_address>
| const type = quote.type ?? "unknown"; | ||
|
|
||
| if (quote.quote?.minimumToAmount !== undefined) { | ||
| return { type, minimumOutput: BigInt(quote.quote.minimumToAmount) }; |
There was a problem hiding this comment.
quote is typed any here, which bypasses the RequestQuoteV0Result type that's already imported. If the SDK response shape changes this would silently hide bugs. Consider using the actual SDK type:
function extractQuoteData(quote: RequestQuoteV0Result): { type: string; minimumOutput?: bigint }
src/commands/swap.ts
Outdated
| ...(paymaster ? { capabilities: { paymaster } } : {}), | ||
| }; | ||
|
|
||
| return request as Parameters<ReturnType<ReturnType<typeof buildWalletClient>["client"]["extend"]>["requestQuoteV0"]>[0]; |
There was a problem hiding this comment.
This as Parameters<...>[0] cast is brittle — if the SDK signature changes, this will silently pass the wrong shape at runtime. Consider typing the request object directly against the SDK's expected input type, or at minimum adding a comment explaining why the cast is necessary.
| printKeyValueBox(pairs); | ||
| } | ||
| } | ||
|
|
There was a problem hiding this comment.
quote is declared with let but never reassigned — can be const.
More broadly, the preparedQuote flow is a bit hard to follow with two conditional branches and a post-check for the permit type. Consider extracting the paymaster-permit handling into a small helper to reduce nesting in performSwapExecute.
|
|
||
| // ── Quote implementation ──────────────────────────────────────────── | ||
|
|
||
| async function performSwapQuote(program: Command, opts: SwapOpts) { |
There was a problem hiding this comment.
If the token address is invalid or the RPC call to fetch decimals fails (e.g. non-ERC20 address), the error will bubble up with a potentially cryptic message. Worth confirming that fetchTokenDecimals provides a user-friendly error in this context, or wrapping with a clearer message like "Failed to resolve token info for
| } | ||
|
|
||
| function formatTokenAmount(rawAmount: bigint, decimals: number): string { | ||
| const str = rawAmount.toString().padStart(decimals + 1, "0"); |
There was a problem hiding this comment.
nit: formatTokenAmount works correctly when decimals is 0, but the behavior is subtle (the padStart / slice logic). A brief comment or a unit test for that edge case would help future maintainers.
Type the swap quote helpers against the SDK surface so response and request shape changes fail fast, and clarify swap inputs and token metadata failures for operators. Made-with: Cursor
Summary
alchemy swap quoteandalchemy swap executefor same-chain token swapsTest plan
pnpm test tests/commands/swap.test.tspnpm lint