Skip to content

feat: multichain balance detection page with on-demand ERC20 lookup #246

@AugustoL

Description

@AugustoL

Summary

Add a multichain balance page where users input a wallet address and instantly see its native token balances across all supported EVM networks (and BTC). ERC20 token balances on each network are available on demand — the user explicitly requests them per network by clicking a button, keeping initial load fast and RPC usage minimal.

Motivation

Users managing multi-chain portfolios currently have to navigate to each network individually and check balances one by one. A single consolidated view of native balances across all chains eliminates that friction. The on-demand ERC20 lookup respects the user's intent: native balances are lightweight and always useful, while ERC20 discovery is expensive (requires token list + multiple RPC calls) and only needed for specific networks.

Target users: All users, power users, developers testing multi-chain deployments.

Proposed Solution

User Flow

  1. User navigates to /multichain (or /wallet — TBD).
  2. An address input field is shown (pre-filled if an ENS or address is in context).
  3. On submit, native token balances are fetched in parallel across all supported networks using each network's configured RPC.
  4. Results appear in a per-network card/row layout showing:
    • Network name + logo
    • Native token balance + symbol (e.g. 1.42 ETH, 0.003 BTC)
    • USD equivalent (if price feed is available)
    • A "Load ERC20 tokens" button
  5. When the user clicks "Load ERC20 tokens" on a network row, ERC20 balances are fetched for that network only and displayed inline below the native balance row, as a collapsible token list.
  6. Already-expanded networks remain expanded if the user re-searches a different address.

Native Balance Fetching

  • Use eth_getBalance via each network's RPCClient in parallel.
  • For BTC: use a public, configurable read-only API (e.g. mempool.space or blockstream.info) — display only, no private key handling.
  • Failed networks (RPC unreachable / timeout) show an error state per row, not a full page error.
  • Localhost (chain ID 31337) is included if the dev server is reachable.

ERC20 Balance Fetching (On-Demand, Per Network)

  • Triggered only when the user clicks "Load ERC20 tokens" for a specific network.
  • Strategy: query a token list (e.g. Uniswap default list or a configurable source) to get known ERC20 addresses for that chain, then batch balanceOf calls using eth_call (or multicall if available).
  • Show only tokens with non-zero balance.
  • Each token row shows: token logo (if available), symbol, name, balance, and USD equivalent.
  • A loading spinner is shown per network while ERC20s are being fetched.
  • The "Load ERC20 tokens" button becomes a "Refresh" button after the first load.

Address Input

  • Accepts both raw 0x... addresses and ENS names (resolved on the currently selected primary network).
  • Shareable URL: address embedded in query param (e.g. /multichain?address=0x...) so users can bookmark or share their balance view.
  • "Check my wallet" shortcut if a wallet is connected via the existing wallet integration.

Layout

┌─────────────────────────────────────────────────────┐
│  Address: [  0x1234...abcd          ] [Check]        │
└─────────────────────────────────────────────────────┘

┌─ Ethereum ──────────────────── 1.42 ETH  ~$4,210 ──┐
│  [Load ERC20 tokens]                                 │
└──────────────────────────────────────────────────────┘

┌─ Base ──────────────────────── 0.08 ETH  ~$188  ───┐
│  ▼ ERC20 Tokens                    [Refresh]        │
│    USDC    1,200.00    ~$1,200                       │
│    AERO      42.50     ~$18                          │
└──────────────────────────────────────────────────────┘

┌─ Arbitrum ──────────────────── 0.00 ETH  ~$0   ───┐
│  [Load ERC20 tokens]                                │
└─────────────────────────────────────────────────────┘

┌─ Bitcoin ───────────────────── 0.003 BTC ~$180  ───┐
│  (BTC — ERC20 not applicable)                       │
└─────────────────────────────────────────────────────┘

Performance and UX Details

  • Native balances are fetched in parallel on page load; no network blocks another.
  • Each network row renders immediately as its result arrives (streaming-style, not wait-for-all).
  • Networks with zero native balance are shown collapsed / dimmed by default, with a toggle to show all.
  • Results are cached for 30 seconds (consistent with existing cache strategy) to avoid redundant calls if the user navigates away and back.

Alternatives Considered

  • Fetching ERC20 balances automatically on load: Too expensive — requires a token list fetch + dozens of balanceOf calls per network. Would cause slow loads and high RPC usage, especially with many networks.
  • Relying on a portfolio API (Zerion, DeBank, etc.): Introduces external dependency, potential privacy concerns, and requires API keys. Contradicts the trustless/standalone design.
  • Merging into the existing address page: The address page is network-scoped. A multichain view needs to be a standalone page that queries multiple networks simultaneously.

Additional Context

  • Supported networks to include: Ethereum, Arbitrum, Optimism, Base, BSC, Polygon, Sepolia, Localhost (31337), Bitcoin (native balance only via public API).
  • Network list should mirror ALL_NETWORKS from src/config/networks.ts so adding a new network automatically includes it.
  • Token lists: consider using tokenlists.org or the Uniswap default list per chain, configurable via Settings.
  • Price feeds (USD equivalent): optional, sourced from existing price feed integrations if available; gracefully omitted if unavailable.
  • BTC support is read-only and display-only — no transaction functionality, consistent with the explorer's EVM focus.

Acceptance Criteria

  • A new multichain balance page is accessible via the main navigation
  • Address input accepts 0x addresses and ENS names; address is reflected in the URL query param
  • Native token balances are fetched in parallel across all supported EVM networks on submit
  • Each network row renders as soon as its result arrives (no blocking wait for all networks)
  • BTC native balance is displayed via a configurable read-only public API
  • Networks with failed RPC calls show a per-row error state, not a full page error
  • A "Load ERC20 tokens" button is shown per EVM network and triggers ERC20 fetching only on click
  • ERC20 results show only non-zero balances with symbol, name, and amount
  • Already-loaded ERC20 sections remain expanded on re-search
  • Zero-native-balance networks are collapsed/dimmed by default with a "Show all" toggle
  • Results are cached for 30 seconds consistent with existing cache strategy
  • "Check my wallet" shortcut available if a wallet is connected
  • All UI strings use the i18n system; translations added for en and es
  • TypeScript type checking passes with no errors
  • Formatting and linting pass (npm run format:fix, npm run lint:fix)

Metadata

Metadata

Assignees

Labels

enhancementNew feature or request

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions