Skip to main content

Building a trace viewer

This guide walks through the pieces you need to turn ethdebug/format data and an execution trace into a working trace viewer. For the conceptual reference on how trace data maps to the format, see Tracing execution; to see a finished viewer in action, try the Trace playground.

The key components for trace integration:

1. Trace source

Get transaction traces from:

  • JSON-RPC debug_traceTransaction
  • Local simulation (Ganache, Anvil, Hardhat)
  • Historical archive nodes

2. Program loader

Load compiled program data containing:

  • Instruction list with contexts
  • Source materials
  • Type definitions

3. Pointer resolver

Use @ethdebug/pointers to resolve variable locations:

import { dereference } from "@ethdebug/pointers";

// For each variable in scope
const cursor = await dereference(variable.pointer, { state: machineState });
const view = await cursor.view(machineState);
const value = await view.read(view.regions[0]);

4. Type decoder

Interpret raw bytes according to type:

function decodeValue(bytes: Data, type: Type): string {
switch (type.kind) {
case "uint":
return bytes.asUint().toString();
case "bool":
return bytes.asUint() !== 0n ? "true" : "false";
case "address":
return "0x" + bytes.toHex().slice(-40);
// ... other types
}
}

Learn more