Debug and trace API wrapper for Ethereum nodes.
Provides access to the debug_* JSON-RPC namespace for transaction tracing,
call tracing, and direct storage slot reads. These methods are supported by
reth, geth, Erigon, and Nethermind — any full node with debug APIs enabled.
Not a core dependency — the library works with any RPC endpoint. This module provides enhanced debugging and inspection capabilities when available.
Tracer Types
"callTracer"(default) — returns the call tree: type, from, to, gas, value, input, output, and nested calls"prestateTracer"— returns the pre-execution state: balance, nonce, code, and storage for each touched account
Performance Note
For faster EVM simulation, pass a local node URL (e.g. http://localhost:8545)
as :rpc_url to Onchain.EVM.simulate_*/3. Local nodes eliminate network
latency and rate limits — no special integration needed.
Error Format
- Address validation:
{:error, {:invalid_address, input}} - Data validation:
{:error, {:invalid_data, input}} - Block validation:
{:error, {:invalid_block, input}} - Tx hash validation:
{:error, {:invalid_tx_hash, input}}(must be 32 bytes) - Slot validation:
{:error, {:invalid_slot, input}}(must be 0x hex) - RPC/network errors:
{:error, {:rpc_error, %{code: integer, message: string}}}
Functions
| Function | Purpose |
|---|---|
trace_transaction/2 | Full execution trace of a mined transaction |
trace_transaction!/2 | Same, raises on error |
trace_call/3 | Trace a call without mining it |
trace_call!/3 | Same, raises on error |
storage_at/3 | Read a contract storage slot directly |
storage_at!/3 | Same, raises on error |
available?/1 | Check if debug/trace APIs are supported |
API Functions
| Function | Arity | Description | Param Kinds |
|---|---|---|---|
available? | 1 | Check if debug/trace APIs are supported by the connected node. | opts: value |
storage_at! | 3 | Read a contract storage slot directly. Raises on error. | address: value, slot: value, opts: value |
storage_at | 3 | Read a contract storage slot directly (eth_getStorageAt). | address: value, slot: value, opts: value |
trace_call! | 3 | Trace a call without mining it. Raises on error. | call_params: value, block: value, opts: value |
trace_call | 3 | Trace a call without mining it (debug_traceCall). | call_params: value, block: value, opts: value |
trace_transaction! | 2 | Get a full execution trace of a mined transaction. Raises on error. | tx_hash: value, opts: value |
trace_transaction | 2 | Get a full execution trace of a mined transaction (debug_traceTransaction). | tx_hash: value, opts: value |
Summary
Types
RPC/network errors from the Ethereum node.
All possible errors from trace functions.
Validation errors from Elixir-side input checks.
Functions
Check if debug/trace APIs are supported by the connected node.
Read a contract storage slot directly (eth_getStorageAt).
Read a contract storage slot directly. Raises on error.
Trace a call without mining it (debug_traceCall).
Trace a call without mining it. Raises on error.
Get a full execution trace of a mined transaction (debug_traceTransaction).
Get a full execution trace of a mined transaction. Raises on error.
Types
@type rpc_error() :: {:rpc_error, map()}
RPC/network errors from the Ethereum node.
@type trace_error() :: validation_error() | rpc_error()
All possible errors from trace functions.
@type validation_error() :: {:invalid_address, term()} | {:invalid_data, term()} | {:invalid_block, term()} | {:invalid_tx_hash, term()} | {:invalid_tracer, term()} | {:invalid_slot, term()} | {:invalid_value, term()} | {:missing_param, atom()}
Validation errors from Elixir-side input checks.
Functions
Check if debug/trace APIs are supported by the connected node.
Parameters
opts- Options: :rpc_url, :timeout (default:[], value)
Returns
true if the node supports debug_traceCall, false otherwise (boolean)
# descripex:contract
%{
params: %{
opts: %{
default: [],
description: "Options: :rpc_url, :timeout",
kind: :value
}
},
returns: %{
type: :boolean,
description: "true if the node supports debug_traceCall, false otherwise"
}
}
@spec storage_at(String.t() | binary(), String.t(), keyword()) :: {:ok, String.t()} | {:error, {:invalid_address, term()} | {:invalid_slot, term()} | {:invalid_block, term()} | rpc_error()}
Read a contract storage slot directly (eth_getStorageAt).
Parameters
address- Contract address as 0x hex string or 20-byte binary (value)slot- Storage slot position as 0x-prefixed hex string (32 bytes) (value)opts- Options: :rpc_url, :timeout, :block (default:[], value)
Returns
32-byte hex value at the storage slot ({:ok, hex_string} | {:error, {:invalid_address, term} | {:invalid_slot, term} | {:invalid_block, term} | rpc_error()})
# descripex:contract
%{
params: %{
slot: %{
description: "Storage slot position as 0x-prefixed hex string (32 bytes)",
kind: :value
},
opts: %{
default: [],
description: "Options: :rpc_url, :timeout, :block",
kind: :value
},
address: %{
description: "Contract address as 0x hex string or 20-byte binary",
kind: :value
}
},
returns: %{
type: "{:ok, hex_string} | {:error, {:invalid_address, term} | {:invalid_slot, term} | {:invalid_block, term} | rpc_error()}",
description: "32-byte hex value at the storage slot",
example: "0x0000000000000000000000000000000000000000000000000000000000000001"
}
}
Read a contract storage slot directly. Raises on error.
Parameters
address- Contract address as 0x hex string or 20-byte binary (value)slot- Storage slot position as 0x-prefixed hex string (value)opts- Options: :rpc_url, :timeout, :block (default:[], value)
Returns
32-byte hex value at the storage slot (string)
# descripex:contract
%{
params: %{
slot: %{
description: "Storage slot position as 0x-prefixed hex string",
kind: :value
},
opts: %{
default: [],
description: "Options: :rpc_url, :timeout, :block",
kind: :value
},
address: %{
description: "Contract address as 0x hex string or 20-byte binary",
kind: :value
}
},
returns: %{
type: :string,
description: "32-byte hex value at the storage slot"
}
}
@spec trace_call(map(), non_neg_integer() | String.t(), keyword()) :: {:ok, map()} | {:error, trace_error()}
Trace a call without mining it (debug_traceCall).
Parameters
call_params- Call parameters map with :to (address), :data (hex calldata), and optional :from (address), :value (hex wei) (value)block- Block number (integer), tag ("latest", "finalized", etc.), or "0x..." hex (default:"latest", value)opts- Options: :rpc_url, :timeout, :tracer ("callTracer" or "prestateTracer", default: "callTracer") (default:[], value)
Returns
Raw trace output from the node (shape depends on tracer type) ({:ok, map} | {:error, trace_error()})
# descripex:contract
%{
params: %{
block: %{
default: "latest",
description: "Block number (integer), tag (\"latest\", \"finalized\", etc.), or \"0x...\" hex",
kind: :value
},
opts: %{
default: [],
description: "Options: :rpc_url, :timeout, :tracer (\"callTracer\" or \"prestateTracer\", default: \"callTracer\")",
kind: :value
},
call_params: %{
description: "Call parameters map with :to (address), :data (hex calldata), and optional :from (address), :value (hex wei)",
kind: :value
}
},
returns: %{
type: "{:ok, map} | {:error, trace_error()}",
description: "Raw trace output from the node (shape depends on tracer type)"
}
}
@spec trace_call!(map(), non_neg_integer() | String.t(), keyword()) :: map()
Trace a call without mining it. Raises on error.
Parameters
call_params- Call parameters map (see trace_call/3) (value)block- Block identifier (default:"latest", value)opts- Options: :rpc_url, :timeout, :tracer (default:[], value)
Returns
Raw trace output from the node (map)
# descripex:contract
%{
params: %{
block: %{default: "latest", description: "Block identifier", kind: :value},
opts: %{
default: [],
description: "Options: :rpc_url, :timeout, :tracer",
kind: :value
},
call_params: %{
description: "Call parameters map (see trace_call/3)",
kind: :value
}
},
returns: %{type: :map, description: "Raw trace output from the node"}
}
@spec trace_transaction( String.t(), keyword() ) :: {:ok, map()} | {:error, {:invalid_tx_hash, term()} | {:invalid_tracer, term()} | rpc_error()}
Get a full execution trace of a mined transaction (debug_traceTransaction).
Parameters
tx_hash- 0x-prefixed hex transaction hash (value)opts- Options: :rpc_url, :timeout, :tracer ("callTracer" or "prestateTracer", default: "callTracer") (default:[], value)
Returns
Raw trace output from the node (shape depends on tracer type) ({:ok, map} | {:error, {:invalid_tx_hash, term} | {:invalid_tracer, term} | rpc_error()})
# descripex:contract
%{
params: %{
opts: %{
default: [],
description: "Options: :rpc_url, :timeout, :tracer (\"callTracer\" or \"prestateTracer\", default: \"callTracer\")",
kind: :value
},
tx_hash: %{description: "0x-prefixed hex transaction hash", kind: :value}
},
returns: %{
type: "{:ok, map} | {:error, {:invalid_tx_hash, term} | {:invalid_tracer, term} | rpc_error()}",
description: "Raw trace output from the node (shape depends on tracer type)"
}
}
Get a full execution trace of a mined transaction. Raises on error.
Parameters
tx_hash- 0x-prefixed hex transaction hash (value)opts- Options: :rpc_url, :timeout, :tracer (default:[], value)
Returns
Raw trace output from the node (map)
# descripex:contract
%{
params: %{
opts: %{
default: [],
description: "Options: :rpc_url, :timeout, :tracer",
kind: :value
},
tx_hash: %{description: "0x-prefixed hex transaction hash", kind: :value}
},
returns: %{type: :map, description: "Raw trace output from the node"}
}