sendTransactionWithOptions
Send Ethereum transactions with customizable parameters like gas limits, fees, and data payloads. Simulate transactions before broadcasting to verify outcomes.
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| to | Yes | The Ethereum address to send to | |
| value | Yes | The amount to send in ether | |
| data | No | Optional. The hex data to include in the transaction | |
| gasLimit | No | Optional. The gas limit for the transaction | |
| maxFeePerGas | No | Optional. The maximum fee per gas (in gwei) | |
| maxPriorityFeePerGas | No | Optional. The maximum priority fee per gas (in gwei) | |
| nonce | No | Optional. The nonce to use for the transaction | |
| mockMode | No | Optional. If true, just simulates the transaction without sending it. Default is false. | |
| provider | No | Optional. Either a network name or custom RPC URL. Use getAllNetworks to see available networks and their details, or getNetwork to get info about a specific network. You can use any network name returned by these tools as a provider value. | |
| chainId | No | Optional. The chain ID to use. If provided with a named network and they don't match, the RPC's chain ID will be used. |
Implementation Reference
- src/tools/core.ts:954-1083 (handler)The complete MCP tool registration for 'sendTransactionWithOptions', including Zod input schema and the handler function that implements mock transaction simulation using ethersService.getWallet and ethers.parseEther/etc. Actual sending is disabled outside mockMode.server.tool( "sendTransactionWithOptions", { to: z.string().describe( "The Ethereum address to send to" ), value: z.string().describe( "The amount to send in ether" ), data: z.string().optional().describe( "Optional. The hex data to include in the transaction" ), gasLimit: z.string().optional().describe( "Optional. The gas limit for the transaction" ), maxFeePerGas: z.string().optional().describe( "Optional. The maximum fee per gas (in gwei)" ), maxPriorityFeePerGas: z.string().optional().describe( "Optional. The maximum priority fee per gas (in gwei)" ), nonce: z.number().optional().describe( "Optional. The nonce to use for the transaction" ), mockMode: z.boolean().optional().default(false).describe( "Optional. If true, just simulates the transaction without sending it. Default is false." ), provider: z.string().optional().describe(PROVIDER_DESCRIPTION), chainId: z.number().optional().describe( "Optional. The chain ID to use. If provided with a named network and they don't match, the RPC's chain ID will be used." ) }, async ({ to, value, data, gasLimit, maxFeePerGas, maxPriorityFeePerGas, nonce, mockMode = false, provider, chainId }) => { try { // First check if a wallet exists const wallet = await ethersService.getWallet(provider); if (!wallet) { return { isError: true, content: [{ type: "text", text: "No wallet available to send transaction. Please create or load a wallet first." }] }; } // Helper function to handle BigInt serialization const serializeData = (obj: any): any => { if (obj === null || obj === undefined) return null; if (typeof obj === 'bigint') return obj.toString(); if (typeof obj !== 'object') return obj; if (Array.isArray(obj)) { return obj.map(item => serializeData(item)); } const result: Record<string, any> = {}; for (const [key, value] of Object.entries(obj)) { result[key] = serializeData(value); } return result; }; // Create transaction object with options const tx: any = { to, value: ethers.parseEther(value), data: data || "0x" }; // Add optional parameters if provided if (gasLimit) tx.gasLimit = gasLimit; if (maxFeePerGas) tx.maxFeePerGas = ethers.parseUnits(maxFeePerGas, "gwei"); if (maxPriorityFeePerGas) tx.maxPriorityFeePerGas = ethers.parseUnits(maxPriorityFeePerGas, "gwei"); if (nonce !== undefined) tx.nonce = nonce; if (mockMode) { // Simulate the transaction without actually sending it const ethProvider = await ethersService.getProvider(provider, chainId); const fromAddress = wallet.address; const networkInfo = await ethProvider.getNetwork(); // Get nonce for the wallet if not provided if (nonce === undefined) { tx.nonce = await ethProvider.getTransactionCount(fromAddress); } // Create a properly serialized mock transaction result const mockTxResult = serializeData({ hash: `0x${Math.random().toString(16).substring(2).padStart(64, '0')}`, from: fromAddress, to: tx.to, value: tx.value, nonce: tx.nonce, gasLimit: tx.gasLimit, maxFeePerGas: tx.maxFeePerGas, maxPriorityFeePerGas: tx.maxPriorityFeePerGas, data: tx.data, chainId: networkInfo.chainId, type: 2, // EIP-1559 mockTransaction: true }); return { content: [{ type: "text", text: `MOCK TRANSACTION WITH OPTIONS (not sent): \n${JSON.stringify(mockTxResult, null, 2)}` }] }; } // If not in mock mode, we should reject since we don't want to actually send transactions from tests return { isError: true, content: [{ type: "text", text: "Non-mock transactions are not supported in this implementation. Set mockMode: true to simulate transactions." }] }; } catch (error) { return { isError: true, content: [{ type: "text", text: `Error sending transaction with options: ${error instanceof Error ? error.message : String(error)}` }] }; } } );
- src/tools/core.ts:956-985 (schema)Zod schema for validating inputs to the sendTransactionWithOptions tool.{ to: z.string().describe( "The Ethereum address to send to" ), value: z.string().describe( "The amount to send in ether" ), data: z.string().optional().describe( "Optional. The hex data to include in the transaction" ), gasLimit: z.string().optional().describe( "Optional. The gas limit for the transaction" ), maxFeePerGas: z.string().optional().describe( "Optional. The maximum fee per gas (in gwei)" ), maxPriorityFeePerGas: z.string().optional().describe( "Optional. The maximum priority fee per gas (in gwei)" ), nonce: z.number().optional().describe( "Optional. The nonce to use for the transaction" ), mockMode: z.boolean().optional().default(false).describe( "Optional. If true, just simulates the transaction without sending it. Default is false." ), provider: z.string().optional().describe(PROVIDER_DESCRIPTION), chainId: z.number().optional().describe( "Optional. The chain ID to use. If provided with a named network and they don't match, the RPC's chain ID will be used." ) },
- src/tools/core.ts:954-1083 (registration)Registration of the sendTransactionWithOptions tool using McpServer.tool method.server.tool( "sendTransactionWithOptions", { to: z.string().describe( "The Ethereum address to send to" ), value: z.string().describe( "The amount to send in ether" ), data: z.string().optional().describe( "Optional. The hex data to include in the transaction" ), gasLimit: z.string().optional().describe( "Optional. The gas limit for the transaction" ), maxFeePerGas: z.string().optional().describe( "Optional. The maximum fee per gas (in gwei)" ), maxPriorityFeePerGas: z.string().optional().describe( "Optional. The maximum priority fee per gas (in gwei)" ), nonce: z.number().optional().describe( "Optional. The nonce to use for the transaction" ), mockMode: z.boolean().optional().default(false).describe( "Optional. If true, just simulates the transaction without sending it. Default is false." ), provider: z.string().optional().describe(PROVIDER_DESCRIPTION), chainId: z.number().optional().describe( "Optional. The chain ID to use. If provided with a named network and they don't match, the RPC's chain ID will be used." ) }, async ({ to, value, data, gasLimit, maxFeePerGas, maxPriorityFeePerGas, nonce, mockMode = false, provider, chainId }) => { try { // First check if a wallet exists const wallet = await ethersService.getWallet(provider); if (!wallet) { return { isError: true, content: [{ type: "text", text: "No wallet available to send transaction. Please create or load a wallet first." }] }; } // Helper function to handle BigInt serialization const serializeData = (obj: any): any => { if (obj === null || obj === undefined) return null; if (typeof obj === 'bigint') return obj.toString(); if (typeof obj !== 'object') return obj; if (Array.isArray(obj)) { return obj.map(item => serializeData(item)); } const result: Record<string, any> = {}; for (const [key, value] of Object.entries(obj)) { result[key] = serializeData(value); } return result; }; // Create transaction object with options const tx: any = { to, value: ethers.parseEther(value), data: data || "0x" }; // Add optional parameters if provided if (gasLimit) tx.gasLimit = gasLimit; if (maxFeePerGas) tx.maxFeePerGas = ethers.parseUnits(maxFeePerGas, "gwei"); if (maxPriorityFeePerGas) tx.maxPriorityFeePerGas = ethers.parseUnits(maxPriorityFeePerGas, "gwei"); if (nonce !== undefined) tx.nonce = nonce; if (mockMode) { // Simulate the transaction without actually sending it const ethProvider = await ethersService.getProvider(provider, chainId); const fromAddress = wallet.address; const networkInfo = await ethProvider.getNetwork(); // Get nonce for the wallet if not provided if (nonce === undefined) { tx.nonce = await ethProvider.getTransactionCount(fromAddress); } // Create a properly serialized mock transaction result const mockTxResult = serializeData({ hash: `0x${Math.random().toString(16).substring(2).padStart(64, '0')}`, from: fromAddress, to: tx.to, value: tx.value, nonce: tx.nonce, gasLimit: tx.gasLimit, maxFeePerGas: tx.maxFeePerGas, maxPriorityFeePerGas: tx.maxPriorityFeePerGas, data: tx.data, chainId: networkInfo.chainId, type: 2, // EIP-1559 mockTransaction: true }); return { content: [{ type: "text", text: `MOCK TRANSACTION WITH OPTIONS (not sent): \n${JSON.stringify(mockTxResult, null, 2)}` }] }; } // If not in mock mode, we should reject since we don't want to actually send transactions from tests return { isError: true, content: [{ type: "text", text: "Non-mock transactions are not supported in this implementation. Set mockMode: true to simulate transactions." }] }; } catch (error) { return { isError: true, content: [{ type: "text", text: `Error sending transaction with options: ${error instanceof Error ? error.message : String(error)}` }] }; } } );