transfer_erc20
Transfer ERC20 tokens between addresses using a private key for signing. Specify token, recipient, and amount; defaults to BSC mainnet. Supports various networks.
Instructions
Transfer ERC20 tokens to an address
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| amount | Yes | Amount of tokens to send as a string (e.g., '100' for 100 tokens). This will be adjusted for the token's decimals. | |
| network | No | Network name (e.g. 'bsc', 'opbnb', 'ethereum', 'base', etc.) or chain ID. Supports others main popular networks. Defaults to BSC mainnet. | bsc |
| privateKey | No | Private key of the sender account in hex format (with or without 0x prefix). SECURITY: This is used only for transaction signing and is not stored. | 0x5a2b7e4d9c8f1a3e6b0d2c5f4e3d2a1b0c9f8e7d6a5b4c3d2e1f0a9b8c7d6e5f4 |
| toAddress | Yes | The recipient address or ENS name that will receive the tokens (e.g., '0x1234...' or 'vitalik.eth') | |
| tokenAddress | Yes | The contract address or ENS name of the ERC20 token to transfer (e.g., '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48' for USDC or 'uniswap.eth') |
Implementation Reference
- src/evm/services/transfer.ts:59-128 (handler)The core handler function `transferERC20` that executes the ERC20 token transfer: resolves addresses, fetches token decimals/symbol, parses amount, and sends the `transfer` transaction using viem wallet client.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: ERC20_ABI, client: publicClient }) // Get token decimals and symbol const decimals = (await contract.read.decimals()) as number const symbol = (await contract.read.symbol()) as string // 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: ERC20_ABI, functionName: "transfer", args: [toAddress, rawAmount], account: walletClient.account!, chain: walletClient.chain }) return { txHash: hash, amount: { raw: rawAmount, formatted: amount }, token: { symbol, decimals } } }
- src/evm/modules/wallet/tools.ts:124-169 (registration)Registers the MCP tool named 'transfer_erc20' using `server.tool()`, including input schema validation with Zod and the handler that calls the `services.transferERC20` implementation.server.tool( "transfer_erc20", "Transfer ERC20 tokens to an address", { privateKey: privateKeyParam, tokenAddress: z .string() .describe( "The contract address or ENS name of the ERC20 token to transfer (e.g., '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48' for USDC or 'uniswap.eth')" ), toAddress: z .string() .describe( "The recipient address or ENS name that will receive the tokens (e.g., '0x1234...' or 'vitalik.eth')" ), amount: z .string() .describe( "Amount of tokens to send as a string (e.g., '100' for 100 tokens). This will be adjusted for the token's decimals." ), network: defaultNetworkParam }, async ({ privateKey, tokenAddress, toAddress, amount, network }) => { try { const result = await services.transferERC20( tokenAddress, toAddress, amount, privateKey, network ) return mcpToolRes.success({ success: true, txHash: result.txHash, tokenAddress, toAddress, amount: result.amount.formatted, symbol: result.token.symbol, network }) } catch (error) { return mcpToolRes.error(error, "transferring tokens") } } )