Skip to main content

Type Definition

Object representing Solidity source map that maps bytecode positions to source code locations.
export type SourceMapEntry = {
  readonly start: number;          // Byte offset in source
  readonly length: number;         // Length in source
  readonly fileIndex: number;      // Source file index
  readonly jump: "i" | "o" | "-"; // Jump type
  readonly modifierDepth?: number; // Modifier depth
};

export type SourceMap = {
  readonly raw: string;            // Raw semicolon-separated string
  readonly entries: readonly SourceMapEntry[];
};

Quick Reference

import * as SourceMap from '@tevm/voltaire/SourceMap';

// Parse source map
const map = SourceMap.from("0:50:0:-;51:100:0:-;151:25:0:o");

// Access entries
for (const entry of map.entries) {
  console.log(`${entry.start}:${entry.length} in file ${entry.fileIndex}`);
}

API Methods

Constructors

Access

Conversion

Usage Patterns

Debugging Contract Execution

import * as SourceMap from '@tevm/voltaire/SourceMap';
import * as Bytecode from '@tevm/voltaire/Bytecode';

// Get source map from compilation output
const sourceMap = SourceMap.from(compiledOutput.sourceMap);

// Trace execution
const instructions = Bytecode.parseInstructions(bytecode);
for (const [i, instr] of instructions.entries()) {
  const entry = SourceMap.getEntryAt(sourceMap, i);
  if (entry) {
    console.log(`PC ${i}: opcode ${instr.opcode}`);
    console.log(`  Source: offset ${entry.start}, length ${entry.length}`);
    console.log(`  File: ${entry.fileIndex}`);
    console.log(`  Jump: ${entry.jump}`);
  }
}

Error Location Mapping

import * as SourceMap from '@tevm/voltaire/SourceMap';

// Map revert at PC to source location
function getSourceLocation(pc: number, sourceMap: SourceMap.SourceMap) {
  const entry = SourceMap.getEntryAt(sourceMap, pc);
  if (!entry) return null;

  return {
    file: sourceFiles[entry.fileIndex],
    start: entry.start,
    end: entry.start + entry.length,
    code: sourceFiles[entry.fileIndex]?.slice(entry.start, entry.start + entry.length),
  };
}

// Use in error handling
try {
  // Execute contract call
} catch (error) {
  if (error.data?.revertPc) {
    const location = getSourceLocation(error.data.revertPc, sourceMap);
    console.log(`Reverted at: ${location?.file}:${location?.start}`);
    console.log(`Code: ${location?.code}`);
  }
}

Coverage Analysis

import * as SourceMap from '@tevm/voltaire/SourceMap';

// Track executed PCs
const executedPcs = new Set<number>();

// During execution
function recordExecution(pc: number) {
  executedPcs.add(pc);
}

// Calculate coverage
function calculateCoverage(sourceMap: SourceMap.SourceMap) {
  const coveredLines = new Set<string>();

  for (const pc of executedPcs) {
    const entry = SourceMap.getEntryAt(sourceMap, pc);
    if (entry) {
      const key = `${entry.fileIndex}:${entry.start}`;
      coveredLines.add(key);
    }
  }

  const totalEntries = sourceMap.entries.length;
  const coverage = (coveredLines.size / totalEntries) * 100;
  console.log(`Coverage: ${coverage.toFixed(2)}%`);
}

Source Map Format

Solidity source maps use semicolon-separated entries:
s:l:f:j:m;s:l:f:j:m;...
Where:
  • s: Start byte offset in source
  • l: Length in bytes
  • f: File index (0-based)
  • j: Jump type (i = into, o = out, - = regular)
  • m: Modifier depth (optional)

Compression

Empty fields inherit from previous entry:
0:50:0:-;::1:i;
Second entry inherits start (0) and length (50), changes file to 1 and jump to i.

Jump Types

  • -: Regular instruction (no jump)
  • i: Jump into function/modifier (JUMP)
  • o: Jump out of function/modifier (return)

Specification