read.wallet.balances
Read-onlyIdempotent
Check wallet balances for native ETH and ERC20 tokens on supported chains to verify token availability before executing transactions.
Instructions
Get native ETH and ERC20 token balances for a wallet address. Reads directly from chain via RPC multicall. Use before write.account.add_liquidity or write.account.deposit to verify the wallet has sufficient tokens. Returns both raw balance (smallest unit/wei) and formatted (human-readable) per token.
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| wallet_address | Yes | Wallet address to check balances for | |
| token_addresses | Yes | ERC20 token contract addresses to check | |
| chain_id | No | Chain ID: 8453 (Base) or 130 (Unichain) |
Output Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| native | Yes | ||
| tokens | Yes |
Implementation Reference
- src/tools/read/wallet.ts:42-108 (handler)Handler implementation for the "read.wallet.balances" tool, which uses viem to get native ETH balance and ERC20 token balances via multicall.
async ({ wallet_address, token_addresses, chain_id }) => { try { const validChainId = validateChainId(chain_id); const wallet = validateAddress(wallet_address, "wallet_address"); const client = getPublicClient(validChainId, chains); // Build multicall: for each token get balanceOf, decimals, symbol const calls = token_addresses.flatMap((addr) => [ { address: addr as `0x${string}`, abi: erc20Abi, functionName: "balanceOf" as const, args: [wallet], }, { address: addr as `0x${string}`, abi: erc20Abi, functionName: "decimals" as const }, { address: addr as `0x${string}`, abi: erc20Abi, functionName: "symbol" as const }, ]); const [nativeBalance, ...multicallResults] = await Promise.all([ client.getBalance({ address: wallet }), ...(calls.length > 0 ? [client.multicall({ contracts: calls, allowFailure: true })] : []), ]); const results = (multicallResults[0] ?? []) as { status: string; result?: unknown }[]; const tokens = token_addresses.map((addr, i) => { const balRes = results[i * 3]; const decRes = results[i * 3 + 1]; const symRes = results[i * 3 + 2]; const balance = balRes?.status === "success" ? String(balRes.result) : "0"; const decimals = decRes?.status === "success" ? Number(decRes.result) : 18; const symbol = symRes?.status === "success" ? String(symRes.result) : "???"; return { address: addr, symbol, decimals, balance, formatted: formatUnits(BigInt(balance), decimals), }; }); const result = { native: { symbol: "ETH", balance: String(nativeBalance), formatted: formatUnits(nativeBalance, 18), }, tokens, }; return { content: [{ type: "text" as const, text: JSON.stringify(result, null, 2) }], structuredContent: result, }; } catch (err) { return { content: [ { type: "text" as const, text: `Error: ${err instanceof Error ? err.message : String(err)}`, }, ], isError: true, }; } }, - src/tools/read/wallet.ts:23-41 (registration)Registration of the "read.wallet.balances" tool with its description, input schema, and annotations.
server.registerTool( "read.wallet.balances", { annotations: { title: "Get Wallet Balances", readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: true, }, description: "Get native ETH and ERC20 token balances for a wallet address. Reads directly from chain via RPC multicall. Use before write.account.add_liquidity or write.account.deposit to verify the wallet has sufficient tokens. Returns both raw balance (smallest unit/wei) and formatted (human-readable) per token.", inputSchema: { wallet_address: z.string().describe("Wallet address to check balances for"), token_addresses: z.array(z.string()).describe("ERC20 token contract addresses to check"), chain_id: z.number().default(8453).describe("Chain ID: 8453 (Base) or 130 (Unichain)"), }, outputSchema: WalletBalancesOutput, },