Skip to main content

Overview

The useBalances hook fetches and manages user token balances aggregated across all supported chains. It automatically fetches balances when a predicted address is available and provides a manual refresh function.

Import

import { useBalances } from '@/lib/hooks';

Signature

const useBalances: (predictedAddress: string | null) => {
  balances: BalancesResponse | null;
  loading: boolean;
  error: string | null;
  fetchBalances: () => Promise<void>;
}

Parameters

predictedAddress
string | null
required
The user’s predicted account address (smart contract wallet address). Balances are automatically fetched when this changes from null to a valid address.

Return Values

balances
BalancesResponse | null
The aggregated balance data for all assets. Contains balanceByAggregatedAsset array and totalBalance object.
loading
boolean
Indicates if balance data is currently being fetched.
error
string | null
Error message if balance fetching fails. null when no errors.
fetchBalances
() => Promise<void>
Manually trigger a balance refresh. Useful after completing a swap or transfer.

Usage Examples

Basic Usage

import { useBalances } from '@/lib/hooks';
import { usePredictedAddress } from '@/lib/contexts/PredictedAddressContext';

function BalanceCard() {
  const { predictedAddress } = usePredictedAddress();
  const { balances, loading, error } = useBalances(predictedAddress);

  if (loading) return <div>Loading balances...</div>;
  if (error) return <div>Error: {error}</div>;
  if (!balances) return null;

  return (
    <div>
      <h2>Total Balance</h2>
      <p>${balances.totalBalance.fiatValue.toFixed(2)}</p>
      
      <h3>Assets</h3>
      {balances.balanceByAggregatedAsset.map(asset => (
        <div key={asset.aggregatedAssetId}>
          <span>{asset.symbol || asset.aggregatedAssetId}</span>
          <span>${asset.fiatValue.toFixed(2)}</span>
        </div>
      ))}
    </div>
  );
}

Display Balance for Selected Asset

import { useBalances } from '@/lib/hooks';
import { formatTokenAmount } from '@/lib/utils/token';

function AssetBalance({ selectedAssetId, predictedAddress }) {
  const { balances } = useBalances(predictedAddress);

  // Find balance for selected asset
  const selectedBalance = balances?.balanceByAggregatedAsset.find(
    b => b.aggregatedAssetId === selectedAssetId
  );

  if (!selectedBalance) return <div>No balance</div>;

  return (
    <div>
      <div>
        Balance: {formatTokenAmount(selectedBalance.balance, selectedBalance.decimals || 18)}
      </div>
      <div>
        Value: ${selectedBalance.fiatValue.toFixed(2)}
      </div>
    </div>
  );
}

Refresh Balances After Swap

import { useBalances } from '@/lib/hooks';
import { useQuotes } from '@/lib/hooks';
import { useEffect } from 'react';

function SwapForm() {
  const { predictedAddress } = usePredictedAddress();
  const { balances, fetchBalances } = useBalances(predictedAddress);
  const { status, executeQuote } = useQuotes();

  // Refresh balances when swap completes
  useEffect(() => {
    if (status?.status === 'COMPLETED') {
      fetchBalances();
    }
  }, [status, fetchBalances]);

  return (
    <div>
      <button onClick={executeQuote}>Execute Swap</button>
    </div>
  );
}

Balance List with Individual Chain Breakdown

import { useBalances } from '@/lib/hooks';
import { formatTokenAmount } from '@/lib/utils/token';

function DetailedBalances({ predictedAddress }) {
  const { balances, loading } = useBalances(predictedAddress);

  if (loading) return <div>Loading...</div>;
  if (!balances) return null;

  return (
    <div>
      {balances.balanceByAggregatedAsset.map(asset => (
        <div key={asset.aggregatedAssetId}>
          <h3>{asset.symbol}</h3>
          <p>Total: ${asset.fiatValue.toFixed(2)}</p>
          
          <h4>Chain Breakdown:</h4>
          {asset.individualAssetBalances.map((individual, idx) => (
            <div key={idx}>
              <span>{individual.assetType}</span>
              <span>
                {formatTokenAmount(individual.balance, asset.decimals || 18)}
              </span>
              <span>${individual.fiatValue.toFixed(2)}</span>
            </div>
          ))}
        </div>
      ))}
    </div>
  );
}

Check Sufficient Balance

import { useBalances } from '@/lib/hooks';
import { parseTokenAmount } from '@/lib/utils/token';

function SwapForm() {
  const { predictedAddress } = usePredictedAddress();
  const { balances } = useBalances(predictedAddress);
  const [amount, setAmount] = useState('');
  const [selectedAsset, setSelectedAsset] = useState('ob:usdc');

  const hasSufficientBalance = (amount: string) => {
    if (!balances || !amount) return false;
    
    const assetBalance = balances.balanceByAggregatedAsset.find(
      b => b.aggregatedAssetId === selectedAsset
    );
    
    if (!assetBalance) return false;
    
    const parsed = parseTokenAmount(amount, assetBalance.decimals || 18);
    return BigInt(assetBalance.balance) >= BigInt(parsed);
  };

  return (
    <div>
      <input
        type="text"
        value={amount}
        onChange={(e) => setAmount(e.target.value)}
      />
      
      {amount && !hasSufficientBalance(amount) && (
        <div>Insufficient balance</div>
      )}
    </div>
  );
}

Types

BalancesResponse

interface BalancesResponse {
  balanceByAggregatedAsset: BalanceByAssetDto[];
  totalBalance: TotalBalance;
}

BalanceByAssetDto

interface BalanceByAssetDto {
  aggregatedAssetId: string;
  balance: string;
  fiatValue: number;
  individualAssetBalances: IndividualAssetBalance[];
  symbol?: string;
  decimals?: number;
}

IndividualAssetBalance

interface IndividualAssetBalance {
  assetType: string; // CAIP-19 format (e.g., eip155:1/erc20:0x...)
  balance: string;
  fiatValue: number;
}

TotalBalance

interface TotalBalance {
  fiatValue: number;
}

Notes

  • Balances are automatically fetched when predictedAddress changes from null to a valid address
  • The hook uses the Balances API endpoint to fetch aggregated data
  • Balance amounts are returned as strings (BigInt) in the smallest unit (wei)
  • Use formatTokenAmount() utility to convert balances to human-readable format
  • Individual asset balances show the breakdown across different chains

See Also

Build docs developers (and LLMs) love