Skip to content

Batch Wallet.getBalance asset fetches via Multicall3#506

Draft
its-everdred wants to merge 2 commits into
mainfrom
kevin/batch-wallet-getbalance
Draft

Batch Wallet.getBalance asset fetches via Multicall3#506
its-everdred wants to merge 2 commits into
mainfrom
kevin/batch-wallet-getbalance

Conversation

@its-everdred

@its-everdred its-everdred commented Jun 18, 2026

Copy link
Copy Markdown
Collaborator

Closes #452

Summary

Reorganizes Wallet.getBalance from a per-(chain, asset) RPC fan-out to a per-chain Multicall3 batch.

Before: each asset helper (fetchETHBalance / fetchERC20Balance) iterated across chains, costing chains × (1 + erc20s) RPCs. After: one publicClient.multicall per chain reads the wallet's native balance (via Multicall3 getEthBalance) and every ERC-20 balanceOf in a single eth_call. Total RPCs drop to chains (e.g. 5 chains × 6 assets: 30 → 5). Cross-chain parallelism is preserved via Promise.all.

The public TokenBalance[] shape is unchanged — per-chain results are transposed back into per-asset records, and the array preserves asset order.

Changes

  • New src/constants/multicall.ts: canonical MULTICALL3_ADDRESS + a minimal getEthBalance ABI fragment (viem's exported multicall3Abi only carries aggregate3).
  • src/services/tokenBalance.ts: replaced the two per-asset helpers with a single fetchBalances(chainManager, walletAddress, assets, options) that batches per chain and transposes. The per-chain Multicall3 address is resolved from the chain's own viem config with the canonical address as fallback (the "override hook" from the issue), keeping the getEthBalance target consistent with how viem routes the aggregate call.
  • Wallet.getBalance now makes one fetchBalances([ETH, ...supportedAssets], …) call.
  • MockChainManager gained a multicall mock; both affected spec files were rewritten to mock multicall / fetchBalances.

Failure handling decision

The issue left open whether a failed inner balanceOf should surface or zero. This PR uses allowFailure: true and omits the (chain, asset) entry on a per-call failure (e.g. a revert from a non-token address), mirroring how an asset with no configured address is already skipped. A transport-level failure of the whole multicall still rejects, preserving the previous loud-failure behavior for real RPC outages.

Validation

  • pnpm test (sdk): 666 passed / 10 skipped.
  • pnpm typecheck, pnpm build, pnpm lint: clean (0 errors).
  • Manual CLI: actions wallet balance run against live base-sepolia / op-sepolia RPCs with a throwaway zero-balance key — ETH/USDC_DEMO/OP_DEMO balances fetched through the new Multicall3 path.

Self-review

Self-review across correctness, performance, testing, and maintainability before marking ready. Fixes applied:

  • P1 (correctness): the first pass gated native ETH behind the per-chain address map, so native balances on supported chains absent from ETH.address (e.g. celo, superseed) silently vanished — a regression vs. the old unconditional native fan-out. balanceContract now resolves native assets to getEthBalance regardless of the address map. Added a celo regression test.
  • P2 (typescript): dropped a redundant result.result as bigint cast (viem already infers bigint; typecheck stays clean without it).
  • Testing gaps: added tests for transport-level multicall rejection (the documented loud-failure path), partial cross-chain inner-call failure, and the chain-configured Multicall3 address override branch.

Performance reviewer confirmed the efficiency goal is met (one multicall per chain, cross-chain parallelism preserved, zero-asset chains skip the RPC entirely).

@netlify

netlify Bot commented Jun 18, 2026

Copy link
Copy Markdown

Deploy Preview for actions-ui ready!

Name Link
🔨 Latest commit 8b4cd6b
🔍 Latest deploy log https://app.netlify.com/projects/actions-ui/deploys/6a3336f14a8fce0008e38220
😎 Deploy Preview https://deploy-preview-506--actions-ui.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

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.

Batch Wallet.getBalance asset fetches via Multicall3

1 participant