evmole

package module
v0.8.4 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Mar 14, 2026 License: MIT Imports: 9 Imported by: 0

README

EVMole Go

Go bindings for EVMole - a library that extracts information from Ethereum Virtual Machine (EVM) bytecode, including function selectors, arguments, state mutability, storage layout, and control flow graphs.

Features

  • No CGO required - Pure Go implementation using WebAssembly (wazero)
  • Cross-platform - Works on Linux, macOS, Windows (amd64, arm64)
  • Reusable analyzer - Create once, analyze many contracts efficiently

Installation

go get github.com/cdump/evmole/go

Tagged go/v* releases embed the WASM binary. If you are building the Go package from a checkout of this repository, run make wasm in go/ first.

Usage

Basic Usage
package main

import (
    "context"
    "encoding/hex"
    "fmt"
    "log"

    "github.com/cdump/evmole/go"
)

func main() {
    ctx := context.Background()

    bytecode, _ := hex.DecodeString("6080604052...") // Your contract bytecode

    info, err := evmole.ContractInfo(ctx, bytecode, evmole.Options{
        Selectors:       true,
        Arguments:       true,
        StateMutability: true,
    })
    if err != nil {
        log.Fatal(err)
    }

    for _, fn := range info.Functions {
        fmt.Printf("Selector: %s\n", fn.Selector)
        if fn.Arguments != nil {
            fmt.Printf("  Arguments: %s\n", *fn.Arguments)
        }
        if fn.StateMutability != nil {
            fmt.Printf("  State Mutability: %s\n", *fn.StateMutability)
        }
    }
}
Efficient Batch Processing

For analyzing multiple contracts, create an analyzer once and reuse it:

// Create analyzer
analyzer, err := evmole.NewAnalyzer(ctx)
if err != nil {
    log.Fatal(err)
}
defer analyzer.Close(ctx)

// Analyze multiple contracts efficiently
for _, bytecode := range contracts {
    info, err := analyzer.ContractInfo(ctx, bytecode, evmole.Options{
        Selectors: true,
    })
    if err != nil {
        log.Printf("Error: %v", err)
        continue
    }
    // Process info...
}
Storage Layout Analysis
info, err := evmole.ContractInfo(ctx, bytecode, evmole.Options{
    Storage: true,  // Note: also enables Selectors and Arguments
})

for _, record := range info.Storage {
    fmt.Printf("Slot: %s\n", record.Slot)
    fmt.Printf("  Type: %s\n", record.Type)
    fmt.Printf("  Offset: %d\n", record.Offset)
    fmt.Printf("  Reads: %v\n", record.Reads)
    fmt.Printf("  Writes: %v\n", record.Writes)
}
Control Flow Graph
info, err := evmole.ContractInfo(ctx, bytecode, evmole.Options{
    ControlFlowGraph: true,  // Note: also enables BasicBlocks
})

// Build a map from block ID to bytecode start offset
idToStart := make(map[int]int, len(info.ControlFlowGraph.Blocks))
for _, b := range info.ControlFlowGraph.Blocks {
    idToStart[b.ID] = b.Start
}

for _, block := range info.ControlFlowGraph.Blocks {
    fmt.Printf("Block %d-%d: ", block.Start, block.End)
    switch block.Type.Kind {
    case evmole.BlockKindTerminate:
        fmt.Printf("Terminate(success=%v)\n", block.Type.Terminate.Success)
    case evmole.BlockKindJump:
        fmt.Printf("Jump(to=%d)\n", idToStart[block.Type.Jump.To])
    case evmole.BlockKindJumpi:
        fmt.Printf("Jumpi(true=%d, false=%d)\n",
            idToStart[block.Type.Jumpi.TrueTo], idToStart[block.Type.Jumpi.FalseTo])
    }
}
Disassembly
info, err := evmole.ContractInfo(ctx, bytecode, evmole.Options{
    Disassemble: true,
})

for _, instr := range info.Disassembled {
    fmt.Printf("%04x: %s\n", instr.Offset, instr.Opcode)
}

API Reference

Options
Field Description
Selectors Extract function selectors (4-byte signatures)
Arguments Extract function parameter types
StateMutability Detect function state mutability (pure/view/payable/nonpayable)
Storage Extract storage layout (enables Selectors and Arguments)
Disassemble Disassemble bytecode into opcodes
BasicBlocks Extract basic blocks
ControlFlowGraph Generate control flow graph (enables BasicBlocks)
Types
Contract
type Contract struct {
    Functions        []Function
    Storage          []StorageRecord
    Disassembled     []Instruction
    BasicBlocks      []BasicBlock
    ControlFlowGraph *ControlFlowGraph
}
Function
type Function struct {
    Selector        string   // e.g., "a9059cbb"
    BytecodeOffset  int      // Entry point in bytecode
    Arguments       *string  // e.g., "uint256,address[]"
    StateMutability *string  // "pure", "view", "payable", "nonpayable"
}
StorageRecord
type StorageRecord struct {
    Slot   string   // 32-byte hex slot
    Offset int      // Byte offset within slot (0-31)
    Type   string   // e.g., "uint256", "mapping(address => uint256)"
    Reads  []string // Function selectors that read
    Writes []string // Function selectors that write
}
Block
type Block struct {
    ID    int       // Unique block identifier (CFG key)
    Start int       // Byte offset where the block's first opcode begins
    End   int       // Byte offset where the block's last opcode begins
    Type  BlockType // Control flow type
}

Jump destination fields (Jump.To, Jumpi.TrueTo, Jumpi.FalseTo, DynamicJumpi.FalseTo, DynamicJump.To) are block IDs, not bytecode offsets. Use Block.Start (looked up by ID) to get the actual bytecode offset.

Thread Safety

The Analyzer type is safe for concurrent use from multiple goroutines. Internally, it uses a mutex to serialize WASM execution (since WASM is single-threaded). For high-concurrency workloads, consider creating a pool of analyzers.

Documentation

Overview

Package evmole provides EVM bytecode analysis functionality.

EVMole extracts function selectors, arguments, state mutability, storage layout, and control flow graphs from Ethereum Virtual Machine bytecode.

Basic usage:

// Single contract analysis
info, err := evmole.ContractInfo(ctx, bytecode, evmole.Options{Selectors: true})

// Multiple contracts (efficient - compile WASM once)
analyzer, err := evmole.NewAnalyzer(ctx)
if err != nil {
	return err
}
defer analyzer.Close(ctx)

for _, bytecode := range contracts {
	info, err := analyzer.ContractInfo(ctx, bytecode, opts)
	// ...
}

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type Analyzer

type Analyzer struct {
	// contains filtered or unexported fields
}

Analyzer holds the compiled WASM module for reuse. Create once with NewAnalyzer(), use for many contracts.

func NewAnalyzer

func NewAnalyzer(ctx context.Context) (*Analyzer, error)

NewAnalyzer creates a new analyzer with AOT-compiled WASM. This takes ~50ms for compilation, so create once and reuse.

func (*Analyzer) Close

func (a *Analyzer) Close(ctx context.Context) error

Close releases all resources. Call when done with the analyzer.

func (*Analyzer) ContractInfo

func (a *Analyzer) ContractInfo(ctx context.Context, code []byte, opts Options) (*Contract, error)

ContractInfo analyzes EVM bytecode with the given options. Safe to call concurrently from multiple goroutines.

type BasicBlock

type BasicBlock struct {
	Start int
	End   int
}

BasicBlock represents a sequence of instructions with single entry and exit.

func (BasicBlock) MarshalJSON

func (b BasicBlock) MarshalJSON() ([]byte, error)

MarshalJSON implements custom marshaling for BasicBlock as [start, end] array.

func (*BasicBlock) UnmarshalJSON

func (b *BasicBlock) UnmarshalJSON(data []byte) error

UnmarshalJSON implements custom unmarshaling for BasicBlock from [start, end] array.

type Block

type Block struct {
	// ID is the unique block identifier (CFG key).
	ID int `json:"id"`
	// Start is the byte offset where the block's first opcode begins.
	Start int `json:"start"`
	// End is the byte offset where the block's last opcode begins.
	End int `json:"end"`
	// Type indicates how control flow continues after this block.
	Type BlockType `json:"-"`
}

Block is a basic block in the control flow graph.

func (Block) MarshalJSON

func (b Block) MarshalJSON() ([]byte, error)

MarshalJSON implements custom marshaling for Block with type and data fields.

func (*Block) UnmarshalJSON

func (b *Block) UnmarshalJSON(data []byte) error

UnmarshalJSON implements custom unmarshaling for Block.

type BlockKind

type BlockKind int

BlockKind represents the kind of block termination.

const (
	BlockKindTerminate BlockKind = iota
	BlockKindJump
	BlockKindJumpi
	BlockKindDynamicJump
	BlockKindDynamicJumpi
)

func (BlockKind) String

func (k BlockKind) String() string

String returns the JSON type name for the block kind.

type BlockType

type BlockType struct {
	Kind         BlockKind
	Terminate    *TerminateData
	Jump         *JumpData
	Jumpi        *JumpiData
	DynamicJump  *DynamicJumpData
	DynamicJumpi *DynamicJumpiData
}

BlockType represents the type of control flow at the end of a block.

type Contract

type Contract struct {
	// Functions is the list of contract functions with their metadata.
	Functions []Function `json:"functions,omitempty"`
	// Storage is the contract storage layout.
	Storage []StorageRecord `json:"storage,omitempty"`
	// Disassembled is the list of disassembled opcodes (offset, instruction).
	Disassembled []Instruction `json:"disassembled,omitempty"`
	// BasicBlocks are sequences of instructions that execute sequentially.
	BasicBlocks []BasicBlock `json:"basic_blocks,omitempty"`
	// ControlFlowGraph represents the program's execution paths.
	ControlFlowGraph *ControlFlowGraph `json:"control_flow_graph,omitempty"`
}

Contract contains analyzed information about a smart contract.

func ContractInfo

func ContractInfo(ctx context.Context, code []byte, opts Options) (*Contract, error)

ContractInfo is a convenience function that creates a temporary analyzer. For analyzing multiple contracts, use NewAnalyzer() instead.

type ControlFlowGraph

type ControlFlowGraph struct {
	// Blocks is the list of basic blocks in the control flow graph.
	Blocks []Block `json:"blocks"`
}

ControlFlowGraph represents the structure and flow of EVM bytecode.

type DynamicJump

type DynamicJump struct {
	// Path is the sequence of block offsets representing the path taken to reach this jump.
	Path []int `json:"path"`
	// To is the resolved destination of the jump, if known.
	To *int `json:"to,omitempty"`
}

DynamicJump represents a dynamic jump destination with the path taken to reach it.

type DynamicJumpData

type DynamicJumpData struct {
	// To is the list of possible jump destinations and paths to reach them.
	To []DynamicJump `json:"to"`
}

DynamicJumpData contains data for DynamicJump block type.

type DynamicJumpiData

type DynamicJumpiData struct {
	// TrueTo is the list of possible destinations for the true branch.
	TrueTo []DynamicJump `json:"true_to"`
	// FalseTo is the static destination for the false branch.
	FalseTo int `json:"false_to"`
}

DynamicJumpiData contains data for DynamicJumpi block type.

type Function

type Function struct {
	// Selector is the 4-byte function selector as hex string (e.g., "a9059cbb").
	Selector string `json:"selector"`
	// BytecodeOffset is the starting byte offset within EVM bytecode for the function body.
	BytecodeOffset int `json:"bytecode_offset"`
	// Arguments is the function parameter types (e.g., "uint256,address[]").
	Arguments *string `json:"arguments,omitempty"`
	// StateMutability is the function state mutability ("pure", "view", "payable", "nonpayable").
	StateMutability *string `json:"state_mutability,omitempty"`
}

Function represents a public smart contract function.

type Instruction

type Instruction struct {
	Offset int
	Opcode string
}

Instruction represents a disassembled EVM opcode.

func (Instruction) MarshalJSON

func (i Instruction) MarshalJSON() ([]byte, error)

MarshalJSON implements custom marshaling for Instruction as [offset, opcode] array.

func (*Instruction) UnmarshalJSON

func (i *Instruction) UnmarshalJSON(data []byte) error

UnmarshalJSON implements custom unmarshaling for Instruction from [offset, opcode] array.

type JumpData

type JumpData struct {
	// To is the destination of the jump.
	To int `json:"to"`
}

JumpData contains data for Jump block type.

type JumpiData

type JumpiData struct {
	// TrueTo is the destination if condition is true.
	TrueTo int `json:"true_to"`
	// FalseTo is the destination if condition is false.
	FalseTo int `json:"false_to"`
}

JumpiData contains data for Jumpi block type.

type Options

type Options struct {
	// Selectors enables extraction of function selectors.
	Selectors bool
	// Arguments enables extraction of function parameter types.
	Arguments bool
	// StateMutability enables detection of function state mutability.
	StateMutability bool
	// Storage enables extraction of storage layout.
	Storage bool
	// Disassemble enables bytecode disassembly.
	Disassemble bool
	// BasicBlocks enables extraction of basic blocks.
	BasicBlocks bool
	// ControlFlowGraph enables generation of control flow graph.
	ControlFlowGraph bool
}

Options configures which analyses to perform.

type StorageRecord

type StorageRecord struct {
	// Slot is the storage slot location as hex string (32 bytes).
	Slot string `json:"slot"`
	// Offset is the byte offset within the storage slot (0-31).
	Offset int `json:"offset"`
	// Type is the variable type descriptor.
	Type string `json:"type"`
	// Reads is the list of function selectors that read from this storage location.
	Reads []string `json:"reads"`
	// Writes is the list of function selectors that write to this storage location.
	Writes []string `json:"writes"`
}

StorageRecord represents a storage variable record in a contract's storage layout.

type TerminateData

type TerminateData struct {
	// Success indicates whether the termination was successful (true for STOP/RETURN).
	Success bool `json:"success"`
}

TerminateData contains data for Terminate block type.

Directories

Path Synopsis

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL