get_token_info
Retrieve ERC-20 token details including name, symbol, and decimals using contract address and chain ID to verify token information before transactions.
Instructions
Get the name, symbol, and decimals of any ERC-20 token by its contract address. Useful for discovering token details before transfers or approvals.
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| token | Yes | ERC-20 token contract address | |
| chain_id | Yes | Chain ID |
Implementation Reference
- src/index.ts:880-912 (registration)Tool registration for 'get_token_info' - registers the tool with MCP server, defines the schema using zod, and provides the handler function
server.tool( 'get_token_info', 'Get the name, symbol, and decimals of any ERC-20 token by its contract address. ' + 'Useful for discovering token details before transfers or approvals.', { token: z.string().regex(/^0x[a-fA-F0-9]{40}$/).describe('ERC-20 token contract address'), chain_id: z.number().int().describe('Chain ID'), }, async ({ token, chain_id }) => { if (isSolanaChain(chain_id)) { throw new Error('get_token_info is not supported on Solana. Use Solana token metadata programs to query SPL token details.'); } // Make 3 parallel eth_call requests: name(), symbol(), decimals() const [nameResult, symbolResult, decimalsResult] = await Promise.all([ api('/eth-call', 'POST', { chain_id, to: token, data: '0x06fdde03' }).catch(() => ({ result: '0x' })), api('/eth-call', 'POST', { chain_id, to: token, data: '0x95d89b41' }).catch(() => ({ result: '0x' })), api('/eth-call', 'POST', { chain_id, to: token, data: '0x313ce567' }).catch(() => ({ result: '0x' })), ]) as { result: string }[]; const name = decodeAbiString(nameResult.result); const symbol = decodeAbiString(symbolResult.result); const decimalsHex = decimalsResult.result.replace('0x', ''); const decimals = decimalsHex ? parseInt(decimalsHex, 16) : 0; return jsonResponse({ token, chain_id, name: name || 'Unknown', symbol: symbol || 'Unknown', decimals, }); }, ); - src/index.ts:888-911 (handler)Handler function for get_token_info - validates chain is not Solana, makes 3 parallel eth_call requests for name(), symbol(), decimals(), decodes results and returns token metadata
async ({ token, chain_id }) => { if (isSolanaChain(chain_id)) { throw new Error('get_token_info is not supported on Solana. Use Solana token metadata programs to query SPL token details.'); } // Make 3 parallel eth_call requests: name(), symbol(), decimals() const [nameResult, symbolResult, decimalsResult] = await Promise.all([ api('/eth-call', 'POST', { chain_id, to: token, data: '0x06fdde03' }).catch(() => ({ result: '0x' })), api('/eth-call', 'POST', { chain_id, to: token, data: '0x95d89b41' }).catch(() => ({ result: '0x' })), api('/eth-call', 'POST', { chain_id, to: token, data: '0x313ce567' }).catch(() => ({ result: '0x' })), ]) as { result: string }[]; const name = decodeAbiString(nameResult.result); const symbol = decodeAbiString(symbolResult.result); const decimalsHex = decimalsResult.result.replace('0x', ''); const decimals = decimalsHex ? parseInt(decimalsHex, 16) : 0; return jsonResponse({ token, chain_id, name: name || 'Unknown', symbol: symbol || 'Unknown', decimals, }); }, - src/index.ts:884-887 (schema)Input schema for get_token_info using zod - requires 'token' (0x-prefixed 40-char hex address) and 'chain_id' (integer)
{ token: z.string().regex(/^0x[a-fA-F0-9]{40}$/).describe('ERC-20 token contract address'), chain_id: z.number().int().describe('Chain ID'), }, - src/index.ts:856-878 (helper)Helper function decodeAbiString() - decodes ABI-encoded string return values from hex, handles malformed data gracefully, used to decode token name and symbol from eth_call results
/** * Decode an ABI-encoded string return value from hex. * Handles malformed data gracefully — returns empty string on any parsing failure. */ function decodeAbiString(hex: string): string { try { const clean = hex.replace('0x', ''); if (clean.length < 128) return ''; // offset + length minimum // First 32 bytes = offset, next 32 bytes at that offset = length const offset = parseInt(clean.slice(0, 64), 16) * 2; if (isNaN(offset) || offset + 64 > clean.length) return ''; const length = parseInt(clean.slice(offset, offset + 64), 16); if (isNaN(length) || length === 0) return ''; const dataHex = clean.slice(offset + 64, offset + 64 + length * 2); const pairs = dataHex.match(/.{2}/g); if (!pairs) return ''; // Convert hex to UTF-8 const bytes = new Uint8Array(pairs.map(b => parseInt(b, 16))); return new TextDecoder().decode(bytes); } catch { return ''; } }