Skip to main content
Glama
Seitrace

Seitrace Insights MCP Server

Official
by Seitrace
ethers_executor.ts7.89 kB
import { CallToolResult } from '@modelcontextprotocol/sdk/types.js'; import { ethers } from 'ethers'; import { ZodError } from 'zod'; import { McpToolDefinition, JsonObject } from '../../types.js'; import { McpResponse } from '../mcp_response.js'; import { getZodSchemaFromJsonSchema } from '../schema.js'; // Chain ID to RPC URL mapping for Seitrace networks const CHAIN_RPC_MAP: Record<string, string> = { 'pacific-1': 'https://evm-rpc.sei-apis.com', 'atlantic-2': 'https://evm-rpc-testnet.sei-apis.com', 'arctic-1': 'https://evm-rpc-arctic-1.sei-apis.com', }; // Multicall3 contract address (same across all EVM chains) const MULTICALL3_ADDRESS = '0xcA11bde05977b3631167028862bE2a173976CA11'; // Multicall3 ABI (using aggregate3 for better error handling) const MULTICALL3_ABI = [ { inputs: [ { components: [ { internalType: 'address', name: 'target', type: 'address' }, { internalType: 'bool', name: 'allowFailure', type: 'bool' }, { internalType: 'bytes', name: 'callData', type: 'bytes' }, ], internalType: 'struct Multicall3.Call3[]', name: 'calls', type: 'tuple[]', }, ], name: 'aggregate3', outputs: [ { components: [ { internalType: 'bool', name: 'success', type: 'bool' }, { internalType: 'bytes', name: 'returnData', type: 'bytes' }, ], internalType: 'struct Multicall3.Result[]', name: 'returnData', type: 'tuple[]', }, ], stateMutability: 'payable', type: 'function', }, ]; /** * Recursively converts BigInt values to strings for JSON serialization * @param obj The object to convert * @returns The object with BigInt values converted to strings */ function convertBigIntToString(obj: any): any { if (typeof obj === 'bigint') { return obj.toString(); } if (Array.isArray(obj)) { return obj.map(convertBigIntToString); } if (obj && typeof obj === 'object') { const converted: any = {}; for (const [key, value] of Object.entries(obj)) { converted[key] = convertBigIntToString(value); } return converted; } return obj; } /** * Executes an ethers tool for contract state queries via Multicall3 * @param toolName The name of the tool to execute * @param definition The tool definition * @param toolArgs The arguments to pass to the tool * @returns The result of the tool execution */ export const executeEthersTool = async ( toolName: string, definition: McpToolDefinition, toolArgs: JsonObject ): Promise<CallToolResult> => { try { let validatedArgs: JsonObject; try { const zodSchema = getZodSchemaFromJsonSchema(definition.inputSchema, toolName); const argsToParse = typeof toolArgs === 'object' && toolArgs !== null ? toolArgs : {}; validatedArgs = zodSchema.parse(argsToParse); } catch (error: unknown) { if (error instanceof ZodError) { const validationErrorMessage = `Invalid arguments for tool '${toolName}': ${error.errors .map((e) => `${e.path.join('.')} (${e.code}): ${e.message}`) .join(', ')}`; return McpResponse(JSON.stringify({ error: validationErrorMessage })); } else { const errorMessage = error instanceof Error ? error.message : String(error); return McpResponse( JSON.stringify({ error: `Internal error during validation setup: ${errorMessage}. Try contact dev@cavies.xyz`, }) ); } } const { abi, contract_address, payload, chain_id } = validatedArgs as { abi: any[]; contract_address: string; payload: Array<{ methodName: string; arguments?: any[] }>; chain_id: string; }; // Get RPC URL for the chain const rpcUrl = CHAIN_RPC_MAP[chain_id]; if (!rpcUrl) { return McpResponse( JSON.stringify({ error: `Unsupported chain_id: ${chain_id}. Supported chains: ${Object.keys(CHAIN_RPC_MAP).join(', ')}`, }) ); } // Create provider const provider = new ethers.JsonRpcProvider(rpcUrl); // Create contract interface from ABI const contractInterface = new ethers.Interface(abi); // Encode all function calls for aggregate3 const calls: Array<{ target: string; allowFailure: boolean; callData: string }> = []; const callDetails: Array<{ methodName: string; arguments: any[] }> = []; for (const call of payload) { const functionArgs = call.arguments || []; let encodedCall: string; try { encodedCall = contractInterface.encodeFunctionData(call.methodName, functionArgs); calls.push({ target: contract_address, allowFailure: true, // Allow individual calls to fail without breaking the batch callData: encodedCall, }); callDetails.push({ methodName: call.methodName, arguments: functionArgs, }); } catch (error) { return McpResponse( JSON.stringify({ error: `Failed to encode function call for ${call.methodName}: ${error instanceof Error ? error.message : 'Unknown error'}`, }) ); } } // Create multicall contract instance const multicall = new ethers.Contract(MULTICALL3_ADDRESS, MULTICALL3_ABI, provider); try { // Execute the multicall using aggregate3 const returnData = await multicall.aggregate3.staticCall(calls); // Get current block number separately since aggregate3 doesn't return it const blockNumber = await provider.getBlockNumber(); // Decode all return data - aggregate3 returns array of {success: bool, returnData: bytes} const results = returnData.map( (result: { success: boolean; returnData: string }, index: number) => { const callDetail = callDetails[index]; if (!result.success) { return { success: false, method: callDetail.methodName, arguments: callDetail.arguments, error: 'Call reverted', }; } try { const decodedResult = contractInterface.decodeFunctionResult( callDetail.methodName, result.returnData ); return { success: true, method: callDetail.methodName, arguments: callDetail.arguments, result: convertBigIntToString( decodedResult.length === 1 ? decodedResult[0] : decodedResult ), }; } catch (error) { return { success: false, method: callDetail.methodName, arguments: callDetail.arguments, error: error instanceof Error ? error.message : 'Unknown decode error', }; } } ); // Format the response const response = { success: true, blockNumber: blockNumber.toString(), chain_id, contract_address, calls: results, }; return McpResponse(JSON.stringify(response)); } catch (error) { const errorMessage = error instanceof Error ? error.message : 'Unknown error'; return McpResponse( JSON.stringify({ success: false, error: 'Multicall execution failed', details: errorMessage, chain_id, contract_address, calls: callDetails.map((detail) => ({ method: detail.methodName, arguments: detail.arguments, })), }) ); } } catch (error) { const errorMessage = error instanceof Error ? error.message : 'Unknown error'; return McpResponse( JSON.stringify({ success: false, error: 'Ethers executor failed', details: errorMessage, }) ); } };

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/Seitrace/seitrace-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server