get_token_balance
Retrieve the ERC20 token balance for a specific wallet address on any EVM-compatible network using token and owner addresses. Supports ENS names and multiple blockchains.
Instructions
Get the balance of an ERC20 token for an address
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| network | No | Network name (e.g., 'ethereum', 'optimism', 'arbitrum', 'base', etc.) or chain ID. Supports all EVM-compatible networks. Defaults to Ethereum mainnet. | |
| ownerAddress | Yes | The wallet address or ENS name to check the balance for (e.g., '0x1234...' or 'vitalik.eth') | |
| tokenAddress | Yes | The contract address or ENS name of the ERC20 token (e.g., '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48' for USDC or 'uniswap.eth') |
Implementation Reference
- src/core/services/balance.ts:98-136 (handler)Core implementation of ERC20 token balance fetching using viem contract reads for balanceOf, symbol, and decimals. Resolves ENS names and handles formatting.export async function getERC20Balance( tokenAddressOrEns: string, ownerAddressOrEns: string, network = 'ethereum' ): Promise<{ raw: bigint; formatted: string; token: { symbol: string; decimals: number; } }> { // Resolve ENS names to addresses if needed const tokenAddress = await resolveAddress(tokenAddressOrEns, network); const ownerAddress = await resolveAddress(ownerAddressOrEns, network); const publicClient = getPublicClient(network); const contract = getContract({ address: tokenAddress, abi: erc20Abi, client: publicClient, }); const [balance, symbol, decimals] = await Promise.all([ contract.read.balanceOf([ownerAddress]), contract.read.symbol(), contract.read.decimals() ]); return { raw: balance, formatted: formatUnits(balance, decimals), token: { symbol, decimals } }; }
- src/core/tools.ts:370-429 (registration)Registers the MCP tool 'get_token_balance' with input schema (zod), handler wrapper that calls services.getERC20Balance and formats MCP response.'get_token_balance', 'Get the balance of an ERC20 token for an address', { tokenAddress: z .string() .describe( "The contract address or ENS name of the ERC20 token (e.g., '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48' for USDC or 'uniswap.eth')" ), ownerAddress: z .string() .describe( "The wallet address or ENS name to check the balance for (e.g., '0x1234...' or 'vitalik.eth')" ), network: z .string() .optional() .describe( "Network name (e.g., 'ethereum', 'optimism', 'arbitrum', 'base', etc.) or chain ID. Supports all EVM-compatible networks. Defaults to Ethereum mainnet." ) }, async ({ tokenAddress, ownerAddress, network = 'ethereum' }) => { try { const balance = await services.getERC20Balance( tokenAddress, ownerAddress, network ); return { content: [ { type: 'text', text: JSON.stringify( { tokenAddress, owner: ownerAddress, network, raw: balance.raw.toString(), formatted: balance.formatted, symbol: balance.token.symbol, decimals: balance.token.decimals }, null, 2 ) } ] }; } catch (error) { return { content: [ { type: 'text', text: `Error fetching token balance: ${error instanceof Error ? error.message : String(error)}` } ], isError: true }; } }
- src/core/services/balance.ts:13-35 (schema)ERC20 ABI used for reading token symbol, decimals, and balanceOf in getERC20Balance.const erc20Abi = [ { inputs: [], name: 'symbol', outputs: [{ type: 'string' }], stateMutability: 'view', type: 'function' }, { inputs: [], name: 'decimals', outputs: [{ type: 'uint8' }], stateMutability: 'view', type: 'function' }, { inputs: [{ type: 'address', name: 'account' }], name: 'balanceOf', outputs: [{ type: 'uint256' }], stateMutability: 'view', type: 'function' } ] as const;
- src/core/services/balance.ts:1-11 (helper)Imports and dependencies for balance service, including viem utilities and ENS resolution.import { formatEther, formatUnits, type Address, type Abi, getContract } from 'viem'; import { getPublicClient } from './clients.js'; import { readContract } from './contracts.js'; import { resolveAddress } from './ens.js';