web3icons

Designing for many chains

How to show balances across many chains, use chain logos and badges, decide when to group or split the same asset, and signal when a bridge is needed.

5 min read

A person with 500 USDC might hold it as 200 on Ethereum, 250 on Arbitrum One and 50 on Base. To them, that's 500 dollars of one stablecoin. To the blockchain, it's three balances in three different contracts on three networks, and only the 50 on Base can be used in a Base app without bridging first.

Multichain interfaces have to serve both views: the person's sense of "what I own" and the chain's reality of "what's usable here". This guide covers grouping the same asset across chains, showing chain identity with logos and badges, and making bridging visible at the moment it matters.

Same asset, different tokens

Before deciding how to display anything, decide which tokens count as "the same asset". It's less obvious than it looks.

Situation Same asset? Why
ETH on Ethereum and ETH on Arbitrum One Usually treated as yes Both are the network's gas token, bridged one to one
USDC issued natively on two chains Usually yes Same issuer, redeemable the same way
Native USDC and a bridged version on one chain No Different contracts, different risks, may trade at different prices
Wrapped and unwrapped versions (ETH and WETH) Depends on context Same value, different use: one pays gas, one is an ERC-20
Two unrelated tokens sharing a ticker No Only the ticker matches

Write these decisions down as data, not as logic scattered through components. A simple mapping from each chain-and-address pair to an asset ID you control works well:

type Holding = {
  chainId: number
  address: string
  assetId: string
  amount: bigint
  decimals: number
  usdValue?: number
}

// Only native deployments map to 'usdc'; a bridged version gets its own assetId
const assetIds: Record<string, string> = {
  '1:0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48': 'usdc',
  '8453:0x833589fcd6edb6e08f4c7c32d4f71b54bda02913': 'usdc',
}

The addresses above are native USDC on Ethereum and on Base. Verify any address you hard-code against the issuer's documentation and a trusted token list before shipping, since this mapping directly controls what people see as "the same money".

Group in portfolios, separate in actions

The two views map to two kinds of screen.

Portfolio views group. On a balances page, show one row per asset with the total across chains, and let people expand it to see the per-chain breakdown. The collapsed row answers "how much USDC do I have?" The expanded rows answer "where is it?"

USDC                                500.00   ≈ $500.00
  ├ Arbitrum One                    250.00
  ├ Ethereum                        200.00
  └ Base                             50.00

Sort the breakdown by amount, and show the chain logo and name on each sub-row.

Action views separate. On a send, swap or deposit screen, the person is acting on one network. Show only the balance on that network, labeled with it: "Balance on Base: 50 USDC". If you show the 500 total there, people will try to send 400 and hit an insufficient balance error they can't understand.

Chain logos and badges

Chain identity needs to be visible wherever it affects what the person can do. The main tools are:

  • Network indicators in the header and on action screens: the chain logo with its name, such as Base or Arbitrum One.
  • Chain badges on token icons, a small chain logo on the corner of the token icon, wherever tokens from different chains appear in one list. See network badges on token icons for sizes and the cutout ring.
  • Chain filters above lists: a row of chain logos with names, plus "All networks".

Pair logos with names. Several networks have similar marks, testnets often reuse their mainnet's logo, and many people know a chain's name but not its icon. You can browse chain marks in the network category. Chain logos in network switchers covers sizes and pairing in more detail.

Keep the order of chains consistent across filters, breakdowns and switchers. Ordering by the person's own balances is helpful in portfolio views; a fixed order is easier to learn in switchers.

Reduce the noise

A wallet active on many chains accumulates small balances everywhere: a little gas token left on each network, dust from old swaps, spam tokens. Without care, the portfolio becomes a long list of near-zero rows.

  • Hide chains with no balance from breakdowns.
  • Group small balances under a collapsible "Small balances" row with its total, and let people set the threshold.
  • Hide unrecognized tokens by default, as with any spam handling.
  • Show network totals in the chain filter ("Base · $1,240") so people can see where their money is without scrolling.

Signal when bridging is needed

The most useful moment for multichain awareness is when the person is about to fail. If they want to deposit 300 USDC into a Base app and hold only 50 on Base, but 250 on Arbitrum One, tell them on the spot:

You have 50 USDC on Base. You also have 250 USDC on Arbitrum One. Move funds to Base to deposit more.

Follow it with a button that starts a bridge, inside your app or through a provider you trust. Before the person confirms, show the bridge's expected time and fee, and what they'll receive on the other side, including whether it's the native token or a bridged version.

Be honest about timing. Some routes complete in seconds or minutes, others take much longer, depending on the bridge and the direction of transfer. Show the estimate the bridge provides and keep the in-flight transfer visible until it arrives, with links to the transaction on both chains.

Gas on each chain

Each chain charges fees in its gas token, held on that same chain. Someone with USDC on a new network and none of that network's gas token can't move it. Check for this before they start, and phrase it per network: "You need a small amount of ETH on Base to pay network fees." Some apps sponsor fees or offer to swap a little of the token for gas; if you don't, at least explain the problem before the transaction fails.

Network switching itself, for wallets that are on the wrong chain when an action starts, is covered in network switching without confusion.

More in Web3 UX

All guides