> ## Documentation Index
> Fetch the complete documentation index at: https://seilabs-docs-evm-cookbook.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# JavaScript Tracers

> Create custom debugging logic with JavaScript tracers for advanced EVM transaction analysis on Sei. Learn performance optimization, memory management, and advanced debugging patterns.

JavaScript tracers let you create custom debugging logic to analyze EVM transactions on Sei. You can use them for more complex analysis than the built-in tracers support.

## Interface overview

Every JavaScript tracer has this structure:

```javascript theme={null}
{
  "tracer": `{
    // Initialize variables
    data: [],

    // Called for each opcode execution
    step: function(log, db) {
      // Your analysis logic here
    },

    // Called when execution fails (optional)
    fault: function(log, db) {
      return {};
    },

    // Called at the end to return results
    result: function(ctx, db) {
      return {
        // Your analysis results
      };
    }
  }`
}
```

## Core methods

### step(log, db)

This method runs for each EVM opcode that executes. Put your main analysis logic here.

**Parameters:**

* `log`: The current execution context, with methods such as `getPC()`, `op.toString()`, and `getCost()`
* `db`: The database interface to query state

**Gas cost**: Varies by tracer complexity

### result(ctx, db)

This method runs at the end of execution and returns your analysis results.

**Parameters:**

* `ctx`: The execution context, with `gasUsed` and transaction information
* `db`: The database interface for final queries

## Advanced tracer examples

### State change tracker

Track every state change in detail:

```javascript theme={null}
{
  "tracer": `{
    stateChanges: {},

    step: function(log, db) {
      if (log.op.toString() == "SSTORE") {
        var key = log.stack.peek(0).toString(16);
        var value = log.stack.peek(1).toString(16);
        var address = log.contract.getAddress().toString();

        if (!this.stateChanges[address]) {
          this.stateChanges[address] = {};
        }

        this.stateChanges[address][key] = {
          oldValue: db.getState(address, key),
          newValue: value,
          pc: log.getPC()
        };
      }
    },

    result: function(ctx, db) {
      return {
        modifiedAccounts: Object.keys(this.stateChanges).length,
        stateChanges: this.stateChanges
      };
    }
  }`
}
```

### DeFi transaction analysis

Analyze complex DeFi transactions with multiple contract interactions:

```javascript theme={null}
{
  "tracer": `{
    transfers: [],

    step: function(log, db) {
      // Track ERC20 Transfer events (LOG3 with Transfer signature)
      if (log.op.toString() == "LOG3") {
        var topic0 = log.stack.peek(2).toString(16);
        // ERC20 Transfer event signature
        if (topic0 == "ddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef") {
          this.transfers.push({
            from: log.stack.peek(3).toString(16),
            to: log.stack.peek(4).toString(16),
            value: log.memory.slice(log.stack.peek(0), log.stack.peek(1)),
            contract: log.contract.getAddress().toString()
          });
        }
      }
    },

    result: function(ctx, db) {
      return {
        totalTransfers: this.transfers.length,
        transfers: this.transfers,
        gasEfficiency: this.transfers.length > 0 ? ctx.gasUsed / this.transfers.length : 0
      };
    }
  }`
}
```

### Security analysis tracer

Detect suspicious patterns and potential vulnerabilities:

```javascript theme={null}
{
  "tracer": `{
    suspiciousOps: [],
    externalCalls: 0,
    selfDestructs: 0,

    step: function(log, db) {
      var op = log.op.toString();

      // Track external calls
      if (op == "CALL" || op == "DELEGATECALL" || op == "STATICCALL") {
        this.externalCalls++;

        // Flag suspicious delegate calls
        if (op == "DELEGATECALL") {
          this.suspiciousOps.push({
            type: "DELEGATECALL",
            target: log.stack.peek(1).toString(16),
            pc: log.getPC()
          });
        }
      }

      // Track self-destructs
      if (op == "SELFDESTRUCT") {
        this.selfDestructs++;
        this.suspiciousOps.push({
          type: "SELFDESTRUCT",
          beneficiary: log.stack.peek(0).toString(16),
          pc: log.getPC()
        });
      }
    },

    result: function(ctx, db) {
      return {
        riskScore: this.suspiciousOps.length * 10 + this.selfDestructs * 50,
        externalCalls: this.externalCalls,
        suspiciousOperations: this.suspiciousOps,
        recommendations: this.suspiciousOps.length > 0 ?
          ["Review delegate calls", "Verify contract security"] :
          ["Transaction appears safe"]
      };
    }
  }`
}
```

### Gas optimization tracer

Identify expensive operations for gas optimization:

```javascript theme={null}
{
  "tracer": `{
    expensive: [],
    threshold: 1000, // Gas cost threshold

    step: function(log, db) {
      var cost = log.getCost();
      if (cost > this.threshold) {
        this.expensive.push({
          pc: log.getPC(),
          op: log.op.toString(),
          cost: cost,
          gas: log.getGas()
        });
      }
    },

    result: function(ctx, db) {
      // Sort by cost descending
      this.expensive.sort((a, b) => b.cost - a.cost);

      return {
        expensiveOperations: this.expensive.slice(0, 20),
        totalExpensiveCost: this.expensive.reduce((sum, op) => sum + op.cost, 0),
        optimizationPotential: this.expensive.length > 0
      };
    }
  }`
}
```

## Performance optimization

<Warning>Optimize your tracer code, and use timeouts in production. JavaScript tracers can slow down tracing significantly.</Warning>

### Memory-efficient patterns

```javascript theme={null}
// ✅ Efficient - Use summary data
{
  "tracer": `{
    summary: {
      totalGas: 0,
      operationCounts: {},
      maxStackDepth: 0
    },

    step: function(log, db) {
      // Update counters instead of storing arrays
      this.summary.totalGas += log.getCost();

      var op = log.op.toString();
      this.summary.operationCounts[op] = (this.summary.operationCounts[op] || 0) + 1;

      var stackDepth = log.stack.length();
      if (stackDepth > this.summary.maxStackDepth) {
        this.summary.maxStackDepth = stackDepth;
      }
    },

    result: function(ctx, db) {
      return this.summary;
    }
  }`
}
```

### Selective operation tracking

```javascript theme={null}
{
  "tracer": `{
    data: [],
    counter: 0,
    maxEntries: 1000, // Limit data collection

    step: function(log, db) {
      // Only track specific operations
      var op = log.op.toString();
      if ((op == "SSTORE" || op == "SLOAD") && this.counter < this.maxEntries) {
        this.data.push([
          log.getPC(),
          op,
          log.getCost()
        ]);
        this.counter++;
      }
    },

    result: function(ctx, db) {
      return {
        operations: this.data,
        truncated: this.counter >= this.maxEntries
      };
    }
  }`
}
```

## Configuration options

### Basic configuration

```json theme={null}
{
  "tracer": "your-javascript-tracer",
  "tracerConfig": {
    "timeout": "30s",
    "enableMemory": false,
    "enableStack": false,
    "enableStorage": false,
    "enableReturnData": true
  }
}
```

### Production settings

```json theme={null}
{
  "tracerConfig": {
    "timeout": "60s", // Longer timeout for complex traces
    "enableMemory": false, // Disable to save memory
    "enableStack": false, // Disable to save memory
    "enableStorage": true, // Enable only if needed
    "enableReturnData": true // Usually safe to enable
  }
}
```

## Practical integration examples

### Smart contract debugger

```solidity theme={null}
contract TransactionAnalyzer {
    struct TraceResult {
        uint256 gasUsed;
        uint256 operationCount;
        bool hasErrors;
    }

    event TransactionTraced(
        bytes32 indexed txHash,
        uint256 gasUsed,
        uint256 operationCount
    );

    function analyzeTransaction(
        bytes32 txHash,
        string memory tracerCode
    ) external {
        // Off-chain: Use the tracer to analyze the transaction
        // On-chain: Process and store the results

        // This would typically be called by an oracle or off-chain service
        // that performs the tracing and submits results
    }
}
```

### DeFi analytics dashboard

```javascript theme={null}
// Off-chain analytics service
class DeFiAnalytics {
  async analyzeSwap(txHash) {
    const swapTracer = `{
            swaps: [],
            
            step: function(log, db) {
                if (log.op.toString() == "LOG3") {
                    // Detect swap events
                    var topic0 = log.stack.peek(2).toString(16);
                    if (topic0 == "swap_event_signature") {
                        this.swaps.push({
                            contract: log.contract.getAddress().toString(),
                            // ... extract swap data
                        });
                    }
                }
            },
            
            result: function(ctx, db) {
                return { swaps: this.swaps };
            }
        }`;

    const result = await this.traceTransaction(txHash, swapTracer);
    return this.processSwapData(result);
  }
}
```

## Best practices

1. **Start simple**: Begin with basic tracers before you add complexity.
2. **Limit data collection**: Collect only the information that you need.
3. **Use efficient data structures**: Prefer counters to arrays when possible.
4. **Set appropriate timeouts**: Balance thoroughness with performance.
5. **Test incrementally**: Validate tracers on simple transactions first.
6. **Handle errors gracefully**: Include error handling in your tracers.

## Common use cases

### Gas profiling

```javascript theme={null}
const gasProfiler = `{
  profile: {},
  
  step: function(log, db) {
    var op = log.op.toString();
    var cost = log.getCost();
    
    if (!this.profile[op]) {
      this.profile[op] = { count: 0, totalCost: 0 };
    }
    
    this.profile[op].count++;
    this.profile[op].totalCost += cost;
  },
  
  result: function(ctx, db) {
    // Calculate averages
    for (var op in this.profile) {
      this.profile[op].avgCost = this.profile[op].totalCost / this.profile[op].count;
    }
    return this.profile;
  }
}`;
```

### Event extraction

```javascript theme={null}
const eventExtractor = `{
  events: [],
  
  step: function(log, db) {
    var op = log.op.toString();
    if (op.startsWith("LOG")) {
      this.events.push({
        address: log.contract.getAddress().toString(),
        topics: this.extractTopics(log),
        data: this.extractData(log)
      });
    }
  },
  
  extractTopics: function(log) {
    // Implementation depends on log structure
    return [];
  },
  
  result: function(ctx, db) {
    return { events: this.events };
  }
}`;
```

<Info>If you have issues with JavaScript tracers, see the [Troubleshooting guide](/evm/tracing/troubleshooting) for common solutions and debugging tips.</Info>


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.