> ## Documentation Index
> Fetch the complete documentation index at: https://docs.dynamic.xyz/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Get Balances for All Wallets

> Use getMultichainTokenBalances to fetch token holdings across every connected wallet in a single API call.

When a user connects multiple wallets, for example an EVM and a Solana account or several EVM networks, you almost always want to display each balance side by side. The right tool for this is [`getMultichainTokenBalances`](https://docs.dynamic.xyz/docs/javascript/reference/wallets/get-multichain-token-balances): it batches **every chain, every network, and every address** into a single API call, so you avoid the N×M round-trip explosion of looping `getTokenBalances` (or `getNativeBalance`) over each wallet.

## Why getMultichainTokenBalances

`getMultichainTokenBalances` accepts a list of `balanceRequests`. Each entry says: *for this address on this chain, get the balances on these networks*. The API fans out, dedups, and returns a single grouped result.

```ts theme={"system"}
{
  balanceRequest: {
    filterSpamTokens: true,
    balanceRequests: [
      { address: '0xabc…', chain: 'EVM', networkIds: [1, 137, 56] },
      { address: 'CKEAuq…', chain: 'SOL', networkIds: [101] },
    ],
  }
}
```

Each balance row in the response carries `isNative`, `symbol`, `price`, `decimals`, `rawBalance`, etc., so a portfolio view never needs a second call for token metadata or prices. Use `filterSpamTokens: true` to drop airdrop spam server-side, and `whitelistedContracts` per request entry to pin specific tokens you care about.

## Building the request from connected wallets

Group the user's connected `walletAccounts` by chain, then collect the network IDs each address should query. `getWalletAccounts` is the source of truth: it includes both verified and unverified accounts, so filter on `walletAccount.verifiedCredentialId` if you only want verified ones. For BTC, pass a single network ID matching each address's network: `1` for mainnet, `2` for testnet, or `3` for signet.

> [tab] JavaScript
>
> ```javascript theme={"system"}
> import {
>   getWalletAccounts,
>   getMultichainTokenBalances,
> } from '@dynamic-labs-sdk/client';
>
> // Customize per-app: which networks you care about for each chain
> const NETWORKS_BY_CHAIN = {
>   EVM: [1, 137, 56, 8453], // Ethereum, Polygon, BNB, Base
>   SOL: [101],
> };
>
> // BTC takes a single network ID matching each address's network.
> // Testnet and signet share the same address format, so pick the ID
> // for the network you intend to query (2 here, or 3 for signet).
> const btcNetworkIdsFor = (address) => {
>   if (/^(tb1|[mn2])/.test(address)) return [2];
>   return [1];
> };
>
> export const getAllBalances = async () => {
>   const walletAccounts = getWalletAccounts();
>
>   // Group addresses by chain (you may have several EVM accounts)
>   const byChain = walletAccounts.flatMap((walletAccount) => {
>     let networkIds;
>     if (walletAccount.chain === 'BTC') {
>       networkIds = btcNetworkIdsFor(walletAccount.address);
>     } else {
>       networkIds = NETWORKS_BY_CHAIN[walletAccount.chain];
>     }
>     if (!networkIds) return [];
>
>     return [
>       {
>         address: walletAccount.address,
>         chain: walletAccount.chain,
>         networkIds,
>       },
>     ];
>   });
>
>   if (byChain.length === 0) return [];
>
>   const chainBalances = await getMultichainTokenBalances({
>     balanceRequest: {
>       filterSpamTokens: true,
>       balanceRequests: byChain,
>     },
>   });
>
>   return chainBalances;
> };
> ```

> [tab] React
>
> `useGetWalletAccounts` re-renders whenever accounts are added or removed, so the request rebuilds (and `useGetMultichainTokenBalances` re-fetches) automatically when the user connects or disconnects a wallet.
>
> ```tsx theme={"system"}
> import {
>   useGetMultichainTokenBalances,
>   useGetWalletAccounts,
> } from '@dynamic-labs-sdk/react-hooks';
> import { useMemo } from 'react';
>
> const NETWORKS_BY_CHAIN: Record<string, number[]> = {
>   EVM: [1, 137, 56, 8453],
>   SOL: [101],
> };
>
> export function AllWalletBalances() {
>   const { data: walletAccounts = [] } = useGetWalletAccounts();
>
>   const balanceRequest = useMemo(() => {
>     const balanceRequests = walletAccounts
>       .filter((walletAccount) => NETWORKS_BY_CHAIN[walletAccount.chain])
>       .map((walletAccount) => ({
>         address: walletAccount.address,
>         chain: walletAccount.chain,
>         networkIds: NETWORKS_BY_CHAIN[walletAccount.chain],
>       }));
>
>     // Keep the hook disabled until there is at least one account to query.
>     return balanceRequests.length === 0
>       ? undefined
>       : { filterSpamTokens: true, balanceRequests };
>   }, [walletAccounts]);
>
>   const { data: balances } = useGetMultichainTokenBalances({ balanceRequest });
>
>   return <pre>{JSON.stringify(balances ?? [], null, 2)}</pre>;
> }
> ```

## Reading the response

The response is grouped by chain → network → balance rows. Each row carries the metadata you need to render a portfolio cell without a second fetch.

```ts theme={"system"}
[
  {
    chain: 'EVM',
    walletAddress: '0x7d1afa7b718fb893db30a3abc0cfc608aacfebb0',
    networks: [
      {
        networkId: 1,
        balances: [
          {
            symbol: 'ETH',
            isNative: true,
            balance: 0.42,
            rawBalance: 4.2e17,
            decimals: 18,
            price: 3200.55,
            marketValue: 1344.23,
            logoURI: 'https://…',
          },
          {
            symbol: 'USDC',
            isNative: false,
            address: '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48',
            balance: 250.0,
            rawBalance: 2.5e8,
            decimals: 6,
            price: 1.0,
            marketValue: 250.0,
            logoURI: 'https://…',
          },
        ],
      },
    ],
  },
]
```

Common ways to slice it for the UI:

```ts theme={"system"}
// Flatten into a single list of "wallet × chain × network × token" rows
const tokenRows = chainBalances.flatMap((chainBalance) =>
  chainBalance.networks.flatMap((network) =>
    network.balances.map((tokenBalance) => ({
      walletAddress: chainBalance.walletAddress,
      chain: chainBalance.chain,
      networkId: network.networkId,
      ...tokenBalance,
    }))
  )
);

// Sum marketValue for a portfolio total
const portfolioTotalUsd = tokenRows.reduce(
  (sum, tokenRow) => sum + (tokenRow.marketValue ?? 0),
  0
);

// Group by token symbol for a "holdings" view
const balanceBySymbol = (tokenRows as { symbol: string; balance: number }[]).reduce<
  Record<string, number>
>(
  (accumulator, tokenRow) => {
    accumulator[tokenRow.symbol] =
      (accumulator[tokenRow.symbol] ?? 0) + tokenRow.balance;
    return accumulator;
  },
  {}
);
```

## Patterns

### Pin specific tokens per chain

When you only care about a stablecoin or a handful of governance tokens, pass `whitelistedContracts` per request entry. The API skips the rest, response stays small.

```ts theme={"system"}
import { getMultichainTokenBalances } from '@dynamic-labs-sdk/client';

await getMultichainTokenBalances({
  balanceRequest: {
    filterSpamTokens: true,
    balanceRequests: [
      {
        address: walletAccount.address,
        chain: 'EVM',
        networkIds: [1, 137],
        whitelistedContracts: [
          '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48', // USDC mainnet
          '0x2791bca1f2de4661ed88a30c99a7a9449aa84174', // USDC polygon
        ],
      },
    ],
  },
});
```

### Disable spam filtering for power-user views

`filterSpamTokens: false` returns the raw set, including airdrop spam. Use this on a "see all tokens" toggle, not in the default view.

### Refresh on `walletAccountsChanged`

`useGetWalletAccounts` already covers this in React. For vanilla apps, subscribe via `onEvent`:

```ts theme={"system"}
import { onEvent } from '@dynamic-labs-sdk/client';

onEvent({
  event: 'walletAccountsChanged',
  listener: () => {
    getAllBalances().then(render);
  },
});
```

## When NOT to use it

* You only need the native gas balance. Use [`getNativeBalance`](https://docs.dynamic.xyz/docs/javascript/reference/wallets/get-native-balance) for an RPC-direct read.
* You have a single wallet on a single chain (one or more networks of that chain) and prefer the simpler call shape. Use [`getTokenBalances`](https://docs.dynamic.xyz/docs/javascript/reference/wallets/get-token-balances).

## Related functions

* [Getting Multichain Token Balances](https://docs.dynamic.xyz/docs/javascript/reference/wallets/get-multichain-token-balances.md): full parameter reference
* [Getting Wallet Accounts](https://docs.dynamic.xyz/docs/javascript/reference/wallets/get-wallet-accounts.md)
* [Getting Token Balances](https://docs.dynamic.xyz/docs/javascript/reference/wallets/get-token-balances.md): token balances for a single chain (one or more networks)
* [Getting Native Balance](https://docs.dynamic.xyz/docs/javascript/reference/wallets/get-native-balance.md): native gas balance only


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.