Skip to main content
Glama

simulate_transaction

Simulate blockchain transactions to preview policy tier, estimated fees, balance changes, and warnings before execution. Test transfers, token operations, contract calls, approvals, or batches without side effects.

Instructions

Simulate a transaction without executing it. Returns policy tier, estimated fees, balance changes, and warnings. No side effects.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
toYesDestination address
amountYesAmount in smallest units (wei for EVM, lamports for Solana). Example: "1000000000000000000" = 1 ETH
typeNoTransaction type. Default: TRANSFER
tokenNoRequired for TOKEN_TRANSFER
calldataNoHex-encoded calldata (EVM)
abiNoABI fragment (EVM)
valueNoNative token value in smallest units (wei for EVM). Example: "1000000000000000000" = 1 ETH
programIdNoSolana program ID
instructionDataNoBase64-encoded instruction data (Solana)
accountsNoSolana accounts
spenderNoSpender address (APPROVE type)
instructionsNoBatch instructions array
networkNoTarget network (e.g., "polygon-mainnet" or CAIP-2 "eip155:137").
wallet_idNoWallet ID for multi-wallet sessions
gas_conditionNoGas price condition (included for request compatibility, ignored by simulation)

Implementation Reference

  • The handler function within the `simulate_transaction` MCP tool, which prepares the transaction data and calls the /v1/transactions/simulate API endpoint.
    async (args) => {
      const body: Record<string, unknown> = { to: args.to, amount: args.amount };
      if (args.type) body.type = args.type;
      if (args.token) body.token = args.token;
      if (args.calldata !== undefined) body.calldata = args.calldata;
      if (args.abi !== undefined) body.abi = args.abi;
      if (args.value !== undefined) body.value = args.value;
      if (args.programId !== undefined) body.programId = args.programId;
      if (args.instructionData !== undefined) body.instructionData = args.instructionData;
      if (args.accounts !== undefined) body.accounts = args.accounts;
      if (args.spender !== undefined) body.spender = args.spender;
      if (args.instructions !== undefined) body.instructions = args.instructions;
      if (args.network !== undefined) body.network = args.network;
      if (args.wallet_id) body.walletId = args.wallet_id;
      if (args.gas_condition) {
        body.gasCondition = {
          maxGasPrice: args.gas_condition.max_gas_price,
          maxPriorityFee: args.gas_condition.max_priority_fee,
          timeout: args.gas_condition.timeout,
        };
      }
      const result = await apiClient.post('/v1/transactions/simulate', body);
      return toToolResult(result);
    },
  • The `registerSimulateTransaction` function registers the 'simulate_transaction' tool with the MCP server.
    export function registerSimulateTransaction(server: McpServer, apiClient: ApiClient, walletContext?: WalletContext): void {
      server.tool(
        'simulate_transaction',
        withWalletPrefix('Simulate a transaction without executing it. Returns policy tier, estimated fees, balance changes, and warnings. No side effects.', walletContext?.walletName),
        {
          to: z.string().describe('Destination address'),
          amount: z.string().describe('Amount in smallest units (wei for EVM, lamports for Solana). Example: "1000000000000000000" = 1 ETH'),
          type: z.enum(['TRANSFER', 'TOKEN_TRANSFER', 'CONTRACT_CALL', 'APPROVE', 'BATCH']).optional()
            .describe('Transaction type. Default: TRANSFER'),
          token: z.object({
            address: z.string().describe('Token mint/contract address'),
            decimals: z.number().describe('Token decimals'),
            symbol: z.string().describe('Token symbol'),
            assetId: z.string().optional().describe('CAIP-19 asset identifier'),
          }).optional().describe('Required for TOKEN_TRANSFER'),
          // CONTRACT_CALL fields
          calldata: z.string().optional().describe('Hex-encoded calldata (EVM)'),
          abi: z.array(z.record(z.unknown())).optional().describe('ABI fragment (EVM)'),
          value: z.string().optional().describe('Native token value in smallest units (wei for EVM). Example: "1000000000000000000" = 1 ETH'),
          programId: z.string().optional().describe('Solana program ID'),
          instructionData: z.string().optional().describe('Base64-encoded instruction data (Solana)'),
          accounts: z.array(z.object({
            pubkey: z.string(),
            isSigner: z.boolean(),
            isWritable: z.boolean(),
          })).optional().describe('Solana accounts'),
          // APPROVE fields
          spender: z.string().optional().describe('Spender address (APPROVE type)'),
          // BATCH fields
          instructions: z.array(z.record(z.unknown())).optional().describe('Batch instructions array'),
          // Common fields
          network: z.string().optional().describe('Target network (e.g., "polygon-mainnet" or CAIP-2 "eip155:137").'),
          wallet_id: z.string().optional().describe('Wallet ID for multi-wallet sessions'),
          gas_condition: z.object({
            max_gas_price: z.string().optional(),
            max_priority_fee: z.string().optional(),
            timeout: z.number().optional(),
          }).optional().describe('Gas price condition (included for request compatibility, ignored by simulation)'),
        },
        async (args) => {
          const body: Record<string, unknown> = { to: args.to, amount: args.amount };
          if (args.type) body.type = args.type;
          if (args.token) body.token = args.token;
          if (args.calldata !== undefined) body.calldata = args.calldata;
          if (args.abi !== undefined) body.abi = args.abi;
          if (args.value !== undefined) body.value = args.value;
          if (args.programId !== undefined) body.programId = args.programId;
          if (args.instructionData !== undefined) body.instructionData = args.instructionData;
          if (args.accounts !== undefined) body.accounts = args.accounts;
          if (args.spender !== undefined) body.spender = args.spender;
          if (args.instructions !== undefined) body.instructions = args.instructions;
          if (args.network !== undefined) body.network = args.network;
          if (args.wallet_id) body.walletId = args.wallet_id;
          if (args.gas_condition) {
            body.gasCondition = {
              maxGasPrice: args.gas_condition.max_gas_price,
              maxPriorityFee: args.gas_condition.max_priority_fee,
              timeout: args.gas_condition.timeout,
            };
          }
          const result = await apiClient.post('/v1/transactions/simulate', body);
          return toToolResult(result);
        },
      );
    }
  • Zod schema definition for the input arguments of the `simulate_transaction` MCP tool.
    {
      to: z.string().describe('Destination address'),
      amount: z.string().describe('Amount in smallest units (wei for EVM, lamports for Solana). Example: "1000000000000000000" = 1 ETH'),
      type: z.enum(['TRANSFER', 'TOKEN_TRANSFER', 'CONTRACT_CALL', 'APPROVE', 'BATCH']).optional()
        .describe('Transaction type. Default: TRANSFER'),
      token: z.object({
        address: z.string().describe('Token mint/contract address'),
        decimals: z.number().describe('Token decimals'),
        symbol: z.string().describe('Token symbol'),
        assetId: z.string().optional().describe('CAIP-19 asset identifier'),
      }).optional().describe('Required for TOKEN_TRANSFER'),
      // CONTRACT_CALL fields
      calldata: z.string().optional().describe('Hex-encoded calldata (EVM)'),
      abi: z.array(z.record(z.unknown())).optional().describe('ABI fragment (EVM)'),
      value: z.string().optional().describe('Native token value in smallest units (wei for EVM). Example: "1000000000000000000" = 1 ETH'),
      programId: z.string().optional().describe('Solana program ID'),
      instructionData: z.string().optional().describe('Base64-encoded instruction data (Solana)'),
      accounts: z.array(z.object({
        pubkey: z.string(),
        isSigner: z.boolean(),
        isWritable: z.boolean(),
      })).optional().describe('Solana accounts'),
      // APPROVE fields
      spender: z.string().optional().describe('Spender address (APPROVE type)'),
      // BATCH fields
      instructions: z.array(z.record(z.unknown())).optional().describe('Batch instructions array'),
      // Common fields
      network: z.string().optional().describe('Target network (e.g., "polygon-mainnet" or CAIP-2 "eip155:137").'),
      wallet_id: z.string().optional().describe('Wallet ID for multi-wallet sessions'),
      gas_condition: z.object({
        max_gas_price: z.string().optional(),
        max_priority_fee: z.string().optional(),
        timeout: z.number().optional(),
      }).optional().describe('Gas price condition (included for request compatibility, ignored by simulation)'),
    },
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Strong disclosure given zero annotations: explicitly lists return values (policy tier, fees, balance changes, warnings) and safety profile ('No side effects'). Missing minor details like authentication requirements or simulation depth (current vs. pending state).

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Three sentences with zero waste: first defines operation, second promises specific outputs, third confirms safety. Perfectly front-loaded with essential distinctions.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness3/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Adequate for the complexity given rich schema coverage, and it compensates for missing output schema by describing return values. However, for a 15-parameter multi-chain tool, it omits domain context (e.g., EVM vs Solana support) and prerequisite conditions that would improve agent success.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

With 100% schema description coverage including EVM/Solana context and nested object details, the schema carries the full load. Description adds no parameter semantics beyond what the schema provides, warranting baseline score 3.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States specific verb (simulate) + resource (transaction) + critical scope distinction ('without executing it'), clearly differentiating from execution siblings like send_token, send_batch, and sign_transaction.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Provides implicit but clear guidance via 'without executing it' and 'No side effects', signaling this is safe for preview/validation purposes versus state-changing alternatives. Lacks explicit 'use this when...' phrasing or named alternative references that would earn a 5.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Install Server

Other Tools

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/minhoyoo-iotrust/WAIaaS'

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