Skip to content

feat: add safe ERC-20 approve command#58

Merged
blakecduncan merged 2 commits intoreleasefrom
blake/approve-command
Apr 10, 2026
Merged

feat: add safe ERC-20 approve command#58
blakecduncan merged 2 commits intoreleasefrom
blake/approve-command

Conversation

@blakecduncan
Copy link
Copy Markdown

@blakecduncan blakecduncan commented Apr 10, 2026

Summary

  • add alchemy approve for ERC-20 allowance updates with explicit --amount, --unlimited, and --revoke modes
  • show current and requested allowances, require confirmation for unlimited approvals, and support --reset-first for tokens that require zeroing an existing allowance before updating it
  • wire the command into the CLI and add focused unit plus Sepolia live coverage for the approve flow

Test plan

  • pnpm lint
  • pnpm vitest run tests/commands/approve.test.ts
  • pnpm test:live -- tests/live/approve.live.test.ts

Made with Cursor

Add an approve command that makes ERC-20 allowance updates explicit and safer for developers, with current-allowance readback, unlimited confirmation, and overwrite protection for tokens that require zeroing first.

Made-with: Cursor
@blakecduncan blakecduncan requested a review from a team as a code owner April 10, 2026 14:52
import { withSpinner, printKeyValueBox, green, dim } from "../lib/ui.js";
import { parseAmount, fetchTokenDecimals } from "./send/shared.js";

const NATIVE_TOKEN_ADDRESS = "0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE" as Address;
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is this just a placeholder for now?

Copy link
Copy Markdown
Author

@blakecduncan blakecduncan Apr 10, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

good question - we will keep this for the native token check below. This is the standard address used across defi to indicate the native token on a chain

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Btw - what is "NATIVE" here? Is it ETH? Should we have a "native" token per network mapping? I think there were some discussion in another thread regarding this

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oops - left this comment after you left yours - is that the case for solana as well?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@lohnim I think the approve command will be EVM only as this is specific to the erc20 allowance/approval flow (which isn't a solana concept).

I'm not as familiar with solana but I think we will probably want a different command for token permissions in that ecosystem

Comment on lines +65 to +66
function formatTokenAmount(rawAmount: bigint, decimals: number): string {
const str = rawAmount.toString().padStart(decimals + 1, "0");
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: Are we using this sort of formatting elsewhere? Better to add to some sort of formatting file?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah that's a good call - I can move this to a shared file

program
.command("approve")
.description("Approve an ERC-20 token allowance for a spender")
.argument("<token_address>", "ERC-20 token contract address")
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What's the framework behind keeping this as argument vs other as options? From what the description reads - it feels more like we're approving the spender to an amount. So I wonder if it should be something like
alchemy approve {spender} --token_address {} --amount

Might be missing something here though! But feel like it should read like english like I approve this person, I want to swap this token, etc.

Copy link
Copy Markdown
Author

@blakecduncan blakecduncan Apr 10, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, I think that’s a fair question. I think the current framework will feel pretty natural to people/agents familiar with the ERC-20 approval flow.

The token contract is the primary resource the command operates on, so I used that as the positional argument, with the spender as a required named parameter. this maps directly to the erc-20 approve(spender, amount) call on the token contract. which I think maps pretty well with this alchemy approve 0xUSDC --spender 0xRouter --amount 100

import { withSpinner, printKeyValueBox, green, dim } from "../lib/ui.js";
import { parseAmount, fetchTokenDecimals } from "./send/shared.js";

const NATIVE_TOKEN_ADDRESS = "0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE" as Address;
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Btw - what is "NATIVE" here? Is it ETH? Should we have a "native" token per network mapping? I think there were some discussion in another thread regarding this

Make the approve CLI read more naturally by taking the spender as the positional argument, and extract shared token amount formatting so approve and swap use the same display logic.

Made-with: Cursor
@blakecduncan blakecduncan merged commit f2780c7 into release Apr 10, 2026
4 checks passed
@blakecduncan blakecduncan deleted the blake/approve-command branch April 10, 2026 19:23
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants