transfer_erc20
Send ERC20 tokens to a recipient address on EVM networks using a configured wallet. Specify token contract, recipient, amount, and network.
Instructions
Transfer ERC20 tokens to an address. Uses the configured wallet.
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| tokenAddress | Yes | The ERC20 token contract address | |
| to | Yes | Recipient address or ENS name | |
| amount | Yes | Amount to send (in token units, accounting for decimals) | |
| network | No | Network name or chain ID. Defaults to Ethereum mainnet. |
Implementation Reference
- src/core/tools.ts:648-726 (registration)MCP tool registration for 'transfer_erc20', including Zod input schema, description, and async handler function that formats private key, calls services.transferERC20, and formats success/error response.server.tool( 'transfer_erc20', 'Transfer ERC20 tokens to another address', { privateKey: z .string() .describe( 'Private key of the sending account (this is used for signing and is never stored)' ), tokenAddress: z .string() .describe('The address of the ERC20 token contract'), toAddress: z.string().describe('The recipient address'), amount: z .string() .describe( "The amount of tokens to send (in token units, e.g., '10' for 10 tokens)" ), 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 ({ privateKey, tokenAddress, toAddress, amount, network = 'ethereum' }) => { try { // Get the formattedKey with 0x prefix const formattedKey = privateKey.startsWith('0x') ? (privateKey as `0x${string}`) : (`0x${privateKey}` as `0x${string}`); const result = await services.transferERC20( tokenAddress as Address, toAddress as Address, amount, formattedKey, network ); return { content: [ { type: 'text', text: JSON.stringify( { success: true, txHash: result.txHash, network, tokenAddress, recipient: toAddress, amount: result.amount.formatted, symbol: result.token.symbol }, null, 2 ) } ] }; } catch (error) { return { content: [ { type: 'text', text: `Error transferring ERC20 tokens: ${error instanceof Error ? error.message : String(error)}` } ], isError: true }; } } );
- src/core/services/transfer.ts:160-229 (handler)Core implementation of transferERC20 function: resolves ENS names, fetches token decimals and symbol, parses amount, creates wallet client, sends transfer transaction via viem, returns tx hash and token details.export async function transferERC20( tokenAddressOrEns: string, toAddressOrEns: string, amount: string, privateKey: string | `0x${string}`, network: string = 'ethereum' ): Promise<{ txHash: Hash; amount: { raw: bigint; formatted: string; }; token: { symbol: string; decimals: number; }; }> { // Resolve ENS names to addresses if needed const tokenAddress = (await resolveAddress( tokenAddressOrEns, network )) as Address; const toAddress = (await resolveAddress(toAddressOrEns, network)) as Address; // Ensure the private key has 0x prefix const formattedKey = typeof privateKey === 'string' && !privateKey.startsWith('0x') ? (`0x${privateKey}` as `0x${string}`) : (privateKey as `0x${string}`); // Get token details const publicClient = getPublicClient(network); const contract = getContract({ address: tokenAddress, abi: erc20TransferAbi, client: publicClient }); // Get token decimals and symbol const decimals = await contract.read.decimals(); const symbol = await contract.read.symbol(); // Parse the amount with the correct number of decimals const rawAmount = parseUnits(amount, decimals); // Create wallet client for sending the transaction const walletClient = getWalletClient(formattedKey, network); // Send the transaction const hash = await walletClient.writeContract({ address: tokenAddress, abi: erc20TransferAbi, functionName: 'transfer', args: [toAddress, rawAmount], account: walletClient.account!, chain: walletClient.chain }); return { txHash: hash, amount: { raw: rawAmount, formatted: amount }, token: { symbol, decimals } }; }
- src/core/services/transfer.ts:17-52 (helper)ERC20 ABI constants used by transferERC20 for contract interactions (transfer, approve, decimals, symbol).const erc20TransferAbi = [ { inputs: [ { type: 'address', name: 'to' }, { type: 'uint256', name: 'amount' } ], name: 'transfer', outputs: [{ type: 'bool' }], stateMutability: 'nonpayable', type: 'function' }, { inputs: [ { type: 'address', name: 'spender' }, { type: 'uint256', name: 'amount' } ], name: 'approve', outputs: [{ type: 'bool' }], stateMutability: 'nonpayable', type: 'function' }, { inputs: [], name: 'decimals', outputs: [{ type: 'uint8' }], stateMutability: 'view', type: 'function' }, { inputs: [], name: 'symbol', outputs: [{ type: 'string' }], stateMutability: 'view', type: 'function' } ] as const;
- src/server/server.ts:18-18 (registration)Top-level registration call to registerEVMTools(server), which includes the transfer_erc20 tool.registerEVMTools(server);