Skip to content

fix: send native token as value transfer in EIP-5792 batch#27

Open
dawsbot wants to merge 1 commit into
mainfrom
fix/native-token-batching
Open

fix: send native token as value transfer in EIP-5792 batch#27
dawsbot wants to merge 1 commit into
mainfrom
fix/native-token-batching

Conversation

@dawsbot

@dawsbot dawsbot commented Jul 6, 2026

Copy link
Copy Markdown
Owner

What

The batched (EIP-5792 sendCalls) path in components/contract/SendTokens.tsx encoded every selected token as an ERC-20 transfer() call — including the chain's native currency (ETH, MATIC, AVAX, …). The native token lives at a pseudo-address (0xeee…) that has no transfer() method, so that call reverts. Because the batch is atomic (forceAtomic: true), one reverting call takes every other transfer down with it.

This PR fixes the batched path to move the native token with a plain value transfer to the destination, reserving gas the same way the sequential path does.

Why

The sequential fallback path was already fixed for this exact bug in b875374 ("Send native/default token as a value transfer, not an ERC-20 transfer"), but the batched path was left behind and still constructs a doomed ERC-20 call for the native token. This closes that regression gap so both code paths handle the native token identically.

How

  • Extracts a pure, testable buildTokenCalls() helper (src/build-token-calls.ts):
    • ERC-20 tokens → encoded transfer() calls targeting the token contract.
    • Native token → { to: destination, value } value transfer, reserving gasPrice × 21000 × 2 for gas (mirrors the sequential path's reserve).
    • Native balances too small to cover the gas reserve are skipped and surfaced to the user via a toast.
  • sendBatchedTokens now builds calls via the helper and only marks the actually-sent tokens as pending.
  • Adds src/build-token-calls.test.ts: ERC-20 encoding, native value transfer, a mixed native + ERC-20 batch, and the insufficient-gas skip.

Verification

  • tsc --noEmit clean
  • eslint . clean
  • vitest run src/build-token-calls.test.ts — 4/4 passing
  • next build succeeds

Note: opened alongside chore/delete-dead-code, which removes the [drain] diagnostic console.logs in this same file. Both branch off main, so a trivial merge conflict in sendBatchedTokens is possible depending on merge order.

🤖 Generated with Claude Code

The batched (sendCalls) path encoded every selected token as an ERC-20
transfer() call, including the chain's native currency (ETH, MATIC, …),
which lives at a pseudo-address (0xeee…) with no transfer() method. That
call reverts, and because the batch is atomic, it takes every other
transfer down with it.

The sequential fallback was already fixed in b875374 to move the native
token with a plain value transfer and a gas reserve; the batched path was
left behind. This applies the equivalent fix by extracting a pure
buildTokenCalls() helper that both understands: ERC-20 tokens become
encoded transfer() calls, the native token becomes a value transfer to
the destination with a 21000×2 gas reserve, and native balances too small
to cover gas are skipped and surfaced to the user.

Adds unit tests covering ERC-20 encoding, native value transfer, a mixed
batch, and the insufficient-gas skip.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@vercel

vercel Bot commented Jul 6, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
drain Ready Ready Preview, Comment Jul 6, 2026 7:05pm

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.

1 participant