Skip to content

Retrieve Balance

Retrieve the balance and format for display. MiniPay is a stablecoin wallet. Retrieving the balance of one of our supported stablecoins is done by reading the token's smart contract.

Supported tokens for Mini Apps

Mini Apps should use USDT, USDC, and USDm only. Do not display or use the CELO token in your Mini App; the system automatically handles fees using the appropriate stablecoin.

  • Dynamic adaptation: Ideally, adapt to the user's preferred stablecoin (e.g. the one with the highest balance). See the Multiple Token Balances example below.
  • Graceful degradation: If your app cannot support multiple stablecoins, provide a clear, simple explanation to the user rather than a broken interface.

The token address table below includes other tokens for reference; for Mini Apps, use the USDT, USDC, and USDm rows for your network.

typescript
import { useConnection, useReadContracts } from "wagmi";
import { erc20Abi, formatUnits, type Hex } from "viem";

const Example = () => {
  const { address } = useConnection();
  const token = "0xcebA9300f2b948710d2653dD7B07f33A8B32118C"; // USDC on Celo mainnet

  const { data: balanceResult } = useReadContracts({
    allowFailure: false,
    contracts: [
      {
        address: token,
        abi: erc20Abi,
        functionName: "balanceOf",
        args: [address as Hex],
      },
      {
        address: token,
        abi: erc20Abi,
        functionName: "decimals",
      },
      {
        address: token,
        abi: erc20Abi,
        functionName: "symbol",
      },
    ],
    query: {
      enabled: !!address,
    },
  });

  const [balance, decimals, symbol] = balanceResult || [];

  const stringBalance = balance && decimals && formatUnits(balance, decimals); // 0.05

  const userLocale = navigator.language || "en-US"; // Fallback to 'en-US' if not available

  // Decimal formatter based on user's locale
  const decimalFormatter = new Intl.NumberFormat(userLocale, {
    style: "decimal",
    minimumFractionDigits: 0,
    maximumFractionDigits: 2,
  });

  const formattedBalance = decimalFormatter.format(+stringBalance); // 0.05 or 0,05

  return `${formattedBalance} ${symbol}`; // 0.05 USDC
};
 Mainnet

 Name                  Symbol Token Address                              Adapter                                    Decimals Uses Adapter?
 ───────────────────── ────── ────────────────────────────────────────── ────────────────────────────────────────── ──────── ─────────────
 Tether USD            USD₮   0x48065fbBE25f71C9282ddf5e1cD6D6A887483D5e 0x0E2A3e05bc9A16F5292A6170456A710cb89C6f72 6        true
 PUSO                  PUSO   0x105d4A9306D2E55a71d2Eb95B81553AE1dC20d7B -                                          18       false
 USDC                  USDC   0xcebA9300f2b948710d2653dD7B07f33A8B32118C 0x2F25deB3848C207fc8E0c34035B3Ba7fC157602B 6        true
 Mento Kenyan Shilling KESm   0x456a3D042C0DbD3db53D5489e98dFb038553B0d0 -                                          18       false
 ECO CFA               eXOF   0x73F93dcc49cB8A239e2032663e9475dd5ef29A08 -                                          18       false
 Mento Dollar          USDm   0x765DE816845861e75A25fCA122bb6898B8B1282a -                                          18       false
 Mento Colombian Peso  COPm   0x8A567e2aE79CA692Bd748aB832081C45de4041eA -                                          18       false
 Mento Euro            EURm   0xD8763CBa276a3738E6DE85b4b3bF5FDed6D6cA73 -                                          18       false
 Mento Brazilian Real  REALm  0xe8537a3d056DA446677B9E9d6c5dB704EaAb4787 -                                          18       false
 Mento Ghanian Cedi    GHSm   0xfAeA5F3404bbA20D3cc2f8C4B0A888F55a3c7313 -                                          18       false

 Celo Sepolia Testnet

  Name                 Symbol   Token Address                              Adapter                                    Decimals Uses Adapter?
 ───────────────────── ──────── ────────────────────────────────────────── ────────────────────────────────────────── ──────── ─────────────
 Mento Euro            EURm     0x10c892A6EC43a53E45D0B916B4b7D383B1b78C0F -                                          18       false
 Mento Kenyan Shilling KESm     0x1E0433C1769271ECcF4CFF9FDdD515eefE6CdF92 -                                          18       false
 USDC                  USDC     0x2F25deB3848C207fc8E0c34035B3Ba7fC157602B 0x4822e58de6f5e485eF90df51C41CE01721331dC0 6        true
 Mento Dollar          USDm     0x874069Fa1Eb16D44d622F2e0Ca25eeA172369bC1 -                                          18       false
 ECO CFA               eXOF     0xB0FA15e002516d0301884059c0aaC0F0C72b019D -                                          18       false
 TetherToken           USD₮     0xC4f86E9B4A588D501c1c3e25628dFd50Bc8D615e -                                          18       false
 Mento Brazilian Real  REALm    0xE4D517785D091D3c54818832dB6094bcc2744545 -                                          18       false

Explanation

  • useAccount: This hook retrieves the current account information, including the address.
  • useReadContracts: This hook reads the function of one or multiple smart contracts.
  • formatUnits: Converts the balance from its raw format to a human-readable string.
  • Intl.NumberFormat: Formats the balance as a currency string based on the user's locale.

Loading States

Handle loading states while fetching the balance:

tsx
const {
  data: balanceResult,
  isLoading,
  error,
} = useReadContracts({
  allowFailure: false,
  contracts: [
    {
      address: token,
      abi: erc20Abi,
      functionName: "balanceOf",
      args: [account?.address as Hex],
    },
    {
      address: token,
      abi: erc20Abi,
      functionName: "decimals",
    },
    {
      address: token,
      abi: erc20Abi,
      functionName: "symbol",
    },
  ],
  query: {
    enabled: !!account?.address, // Only fetch when address is available
  },
});

if (isLoading) {
  return <div>Loading balance...</div>;
}

if (error) {
  return <div>Error loading balance: {error.message}</div>;
}

Multiple Token Balances

Fetch balances for multiple tokens efficiently:

tsx
import { useAccount, useReadContracts } from "wagmi";
import { erc20Abi, formatUnits, Hex } from "viem";

const TOKENS = {
  USDC: "0xcebA9300f2b948710d2653dD7B07f33A8B32118C",
  USDm: "0x765DE816845861e75A25fCA122bb6898B8B1282a",
  USDT: "0x48065fbBE25f71C9282ddf5e1cD6D6A887483D5e",
};

function MultiTokenBalance() {
  const account = useAccount();

  // Create contracts for all tokens
  const contracts = Object.entries(TOKENS).flatMap(([symbol, address]) => [
    {
      address: address as Hex,
      abi: erc20Abi,
      functionName: "balanceOf" as const,
      args: [account?.address as Hex],
    },
    {
      address: address as Hex,
      abi: erc20Abi,
      functionName: "decimals" as const,
    },
  ]);

  const { data: results, isLoading } = useReadContracts({
    allowFailure: false,
    contracts,
    query: {
      enabled: !!account?.address,
    },
  });

  if (isLoading) return <div>Loading...</div>;

  // Process results: each token has 2 results (balance, decimals)
  const balances = Object.keys(TOKENS).map((symbol, index) => {
    const resultIndex = index * 2;
    const [balance, decimals] =
      results?.slice(resultIndex, resultIndex + 2) || [];
    const formatted =
      balance && decimals ? formatUnits(balance, decimals) : "0";

    return { symbol, balance: formatted };
  });

  return (
    <div>
      {balances.map(({ symbol, balance }) => (
        <div key={symbol}>
          {symbol}: {balance}
        </div>
      ))}
    </div>
  );
}

Error Handling

Handle errors gracefully:

tsx
const {
  data: balanceResult,
  error,
  isLoading,
} = useReadContracts({
  allowFailure: true, // Allow individual contract calls to fail
  contracts: [
    // ... contracts
  ],
});

if (error) {
  return (
    <div className="error">
      <p>Failed to load balance</p>
      <p>{error.message}</p>
      <p>Make sure you're connected to MiniPay and on the correct network.</p>
    </div>
  );
}

Notes

  • Ensure wagmi is correctly configured. Follow our Quick Start guide to know how.
  • Ensure that the account address is correctly retrieved and passed to the contract calls.
  • Ensure the token constant is correctly set to the stablecoin you want the balance of. Check the Token addresses tab to get the list of stablecoin addresses on Celo and Celo Sepolia (testnet).
  • Use enabled in the query options to prevent unnecessary calls when the address is not available.
  • Consider using allowFailure: true if you want to handle individual contract call failures gracefully.

For more information, refer to the Wagmi documentation.