Matrix logo

Simulate

The simulator performs eth_call dry runs with optional debug_traceCall tracing. It resolves chain profiles, dials RPC, and returns structured results with gas estimates and revert reasons.

Source file: internal/simulate/simulate.go

The simulator performs eth_call dry runs with optional debug_traceCall tracing. It is the backend for both the simulate verb and the call verb when simulate_only: true.


Design decisions

Chain resolution

The simulator resolves the target chain from three sources, in priority order:

  1. Inline rpc_url on the request (anonymous inline chain)
  2. chain_id on the request (matched against presets or custom profiles by id or numeric chain-id)
  3. Active chain from the registry

Timeout

All calls use a 30-second context timeout. This prevents hung RPC calls from blocking the daemon.

Gas estimation alongside eth_call

The simulator runs EstimateGas in parallel with CallMessage. The gas estimate is returned even when the call reverts, giving agents insight into the cost of a reverted call.

Trace support

When req.Trace is true, the simulator calls debug_traceCall with disableStorage: true to reduce trace size. The trace is returned as raw JSON (any). If tracing fails (node does not support it), the trace is silently omitted.


SimulateRequest

type SimulateRequest struct {
    ChainID string `json:"chain_id,omitempty"`
    RPCURL  string `json:"rpc_url,omitempty"`
    From    string `json:"from,omitempty"`
    To      string `json:"to"`
    Data    string `json:"data,omitempty"`
    Value   string `json:"value,omitempty"`
    Block   string `json:"block,omitempty"`
    Trace   bool   `json:"trace,omitempty"`
}

SimulateResponse

type SimulateResponse struct {
    Result      string `json:"result,omitempty"`
    GasEstimate uint64 `json:"gas_estimate,omitempty"`
    Revert      string `json:"revert,omitempty"`
    Trace       any    `json:"trace,omitempty"`
}

Error handling

CodeMeaning
SIMULATE_FAILEDeth_call returned an error (revert reason captured in data.revert)
INVALID_REQUESTMissing to field
CHAIN_NOT_FOUNDCould not resolve chain profile
CHAIN_RPC_FAILEDRPC dial error

Modifying the simulator

What to changeWhere
Change timeoutinternal/simulate/simulate.go - context.WithTimeout (30s)
Add state override supportinternal/evm/client.go - CallMessage signature
Add access list generationinternal/evm/client.go - new CreateAccessList method