Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/dzimiks/onebalance-chain-abstracted-swap/llms.txt

Use this file to discover all available pages before exploring further.

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