@sodax/sdk and @sodax/dapp-kit 2.2.0.
One token
sodax.spoke.getWalletBalance reads one token for one address. It works the same on every chain type: native coins, EVM ERC-20s, Solana SPL tokens and the rest.
bigint in the token’s smallest unit. Divide by 10 ** token.decimals to display it.
Many tokens on one network
sodax.spoke.getWalletBalances reads a list of tokens in one call. The SDK batches the reads where the chain allows it (EVM multicall3, ICON aggregated calls, the Injective portfolio), so a full token list costs one or two round trips, not one per token.
token.address. Look tokens up by address, not by symbol: two tokens can share a symbol.
Several networks
Each call reads one network. To show a portfolio across networks, run one call per network the user has connected, in parallel:null here, so one broken RPC does not hide the other networks. Promise.all still waits for every call, so the slowest network sets when the portfolio appears; to show each network as it arrives, render each one from its own promise (or one useBalances per network in React).
In React: useBalances
useBalances from @sodax/dapp-kit wraps getWalletBalances in a React Query hook. It only needs a SodaxProvider, not a wallet SDK, and it refreshes every 5 seconds.
chainKey and address are set and tokens is not empty, so you can mount it before the user picks a network. Pass queryOptions to change the refresh interval or other React Query settings.
useBalances is the SDK-backed successor to useXBalances, which reads through the wallet SDK’s xService. Prefer useBalances when your app already has a SodaxProvider.
How failures are reported
- One token fails: it is logged through the SDK logger and reported as
0n. The other balances still come back. A failed read and an empty wallet look the same, on purpose: showing too little blocks a spend, it never allows one. - The whole batch fails: the
Resultisok: false(the hook’serroris set). This happens for an invalid chain key, a shared request every token depends on, or a batch where no token could be read at all, so a dead RPC never shows as an empty wallet.
Things to know
- The chain comes from
srcChainKey. Every read usestoken.addresson that chain and ignores the token’s ownchainKey. A foreign token is not reliably0n: EVM networks share the native-token address, so another network’s native token reads as this network’s native balance. In a batch, a token that cannot be read reports0n; withgetWalletBalancethe same failure is anok: falseresult. Keep the chain key and the token list in step, for example withgetSupportedSwapTokensByChainId(chainKey). - Stellar XLM returns the spendable amount: the total minus the minimum reserve and selling liabilities.
- Bitcoin Runes return
0n; their amounts are not exposed by the UTXO endpoint. - Hedera native HBAR is returned in HBAR’s 8 decimals, not the 18-decimal weibars that
eth_getBalancereports. See the Hedera wallets guide.