Are you an LLM? Read llms.txt for a summary of the docs, or llms-full.txt for the full context.
Skip to content

SDK

balances

Read a wallet's on-chain balances. This is a plain read: no signer, no userOp, no relay. It works for any address (a Wallet you created or a bare 0x… address), including counterfactual wallets that haven't been deployed yet.

// `client` and `wallet` from earlier
const { native } = await client.balances({ wallet });
console.log(native); // bigint — native token balance in wei

Pass a bare address if that's all you have:

const { native } = await client.balances({
  wallet: "0xabc…" as `0x${string}`,
});

Target a specific chain when the client is configured with more than one:

import { createClient, BNB, ETHEREUM } from "@altananetwork/sdk";
 
const client = createClient({ chains: [BNB, ETHEREUM] });
 
// BNB Smart Chain (the default — first chain)
const bnb = await client.balances({ wallet });
// Ethereum
const ethereum = await client.balances({ wallet, chainId: 1 });

ERC-20 tokens

Pass tokens to read ERC-20 balances in the same call. All per-token reads are batched into a single multicall:

const res = await client.balances({
  wallet,
  tokens: ["0x55d398326f99059ff775485246999027b3197955"], // USDT (BSC)
});
 
for (const t of res.tokens!) {
  if (!t.ok) continue;            // token whose reads reverted (bad address, non-ERC-20)
  console.log(t.display, t.symbol); // "12.5 USDT" — ready to render
  console.log(t.raw);               // bigint — the on-chain amount, use for transfers
}

BEP-677 scaled UI amounts

Tokens implementing BEP-677 (IScaledUIAmount, detected via ERC-165 id 0xa60bf13d) carry a display multiplier: wallets must show raw × uiMultiplier / 1e18 while raw balances and allowances stay unchanged on-chain. balances handles this automatically — display (and scaled.scaledRaw) carry the multiplier; raw never does.

const [t] = (await client.balances({ wallet, tokens: [scaledToken] })).tokens!;
if (t.ok && t.scaled) {
  t.display;               // "1500" — already scaled (raw 1000, ×1.5)
  t.scaled.uiMultiplier;   // 1500000000000000000n (1e18 fixed-point)
  t.scaled.scaledRaw;      // 1500000000000000000000n — the bigint behind display
  t.scaled.pending;        // set iff a multiplier change is scheduled but not yet effective
}

Scheduled multiplier changes (newUIMultiplier() / effectiveAt(), ERC-165 id 0x4bd27648) are compared against the block timestamp of the same multicall: a change still in the future is surfaced under scaled.pending without being applied early; a change already effective is applied even if the token's uiMultiplier() lazily reports the old value.

Parameters

client.balances(opts: ClientBalancesOptions): Promise<BalancesResult>;
 
type ClientBalancesOptions = {
  wallet: Wallet | Address;       // a Wallet object or a bare 0x… address
  tokens?: readonly Address[];    // ERC-20s to include; BEP-677 display scaling is automatic
  chainId?: number;               // defaults to the client's default chain
};
 
type BalancesResult = {
  native: bigint;                 // native token balance in wei (BNB on BNB Smart Chain, ETH on Ethereum)
  tokens?: TokenBalance[];        // present iff `tokens` was passed; input order preserved
};
 
type TokenBalance =
  | {
      address: Address;
      ok: true;
      raw: bigint;                // on-chain balanceOf — what transfers/allowances use
      decimals: number;
      symbol: string;             // "" if symbol() is missing/undecodable
      display: string;            // human string, BEP-677 multiplier already applied
      scaled?: {                  // present iff the token implements IScaledUIAmount
        uiMultiplier: bigint;     // active multiplier, 1e18 fixed-point
        scaledRaw: bigint;        // raw * uiMultiplier / 1e18, truncated
        pending?: { newUIMultiplier: bigint; effectiveAt: bigint };
      };
    }
  | { address: Address; ok: false; error: string };

Notes

  • Raw vs display. raw is always the unscaled on-chain amount — build transfers and allowance checks on it. display is what to show users; for BEP-677 tokens the two intentionally differ.
  • Truncation. Scaling uses the spec's integer formula raw × uiMultiplier / 1e18, truncating toward zero. Round-trips are not lossless.
  • Non-ERC-165 tokens are fine. Tokens without supportsInterface (e.g. USDT) simply come back unscaled; the failed detection call is expected and handled.
  • A bad token doesn't throw. An address whose balanceOf/decimals reads revert yields { ok: false, error } and leaves the other entries intact.
  • No funds required. It's a read against the chain's public RPC, so it doesn't cost gas and doesn't need the wallet to be funded or deployed.
  • Units are wei. Use viem's formatEther for native; token entries already provide display.