transfer_tokens
Transfer ERC-20 tokens without paying gas fees using paymaster sponsorship, with automatic fallback to standard gas payments when sponsorship is unavailable.
Instructions
Transfer ERC-20 tokens gaslessly via paymaster. Falls back to normal gas if no paymaster. Requires DEPLOYER_PRIVATE_KEY (transfers FROM the deployer wallet).
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| token_address | Yes | Token contract address | |
| to | Yes | Recipient address | |
| amount | Yes | Amount in human units (e.g. '1000' for 1000 tokens) |
Implementation Reference
- src/index.ts:376-438 (handler)The complete implementation of the 'transfer_tokens' tool handler, including input validation schema, transaction estimation, and execution logic.
server.tool( "transfer_tokens", "Transfer ERC-20 tokens gaslessly via paymaster. Falls back to normal gas if no paymaster. Requires DEPLOYER_PRIVATE_KEY (transfers FROM the deployer wallet).", { token_address: z.string().describe("Token contract address"), to: z.string().describe("Recipient address"), amount: z.string().describe("Amount in human units (e.g. '1000' for 1000 tokens)"), }, async ({ token_address, to, amount }) => { try { const signer = getSigner(); const provider = getProvider(); const token = new ethers.Contract(token_address, TOKEN_ABI, signer); // Get decimals const decimals = await token.decimals(); const amountWei = ethers.parseUnits(amount, decimals); // Check balance const signerAddress = await signer.getAddress(); const balance = await token.balanceOf(signerAddress); if (balance < amountWei) { return mcpError( `Insufficient balance. Have: ${ethers.formatUnits(balance, decimals)}, Need: ${amount}` ); } // Estimate gas for savings calc const gasEstimate = await token.transfer.estimateGas(to, amountWei); const feeData = await provider.getFeeData(); const gasPrice = feeData.gasPrice || 0n; const estimatedCostWei = gasEstimate * gasPrice; // Encode the transfer call const txData = token.interface.encodeFunctionData("transfer", [to, amountWei]); const txRequest: ethers.TransactionRequest = { to: token_address, data: txData, }; const { receipt, usedPaymaster } = await sendTransaction(signer, txRequest); const actualGasCostWei = receipt.gasUsed * receipt.gasPrice; return mcpResult({ success: true, token_address, from: signerAddress, to, amount, decimals: Number(decimals), gasless: usedPaymaster, gas_used: receipt.gasUsed.toString(), gas_cost_eth: usedPaymaster ? "0 (sponsored)" : ethers.formatEther(actualGasCostWei), gas_saved_eth: usedPaymaster ? ethers.formatEther(estimatedCostWei) : "0", tx_hash: receipt.hash, block_number: receipt.blockNumber, explorer: `https://basescan.org/tx/${receipt.hash}`, }); } catch (err: unknown) { const message = err instanceof Error ? err.message : String(err); return mcpError(`Transfer failed: ${message}`); } }