Skip to content

Repository files navigation

go-anvil

CI codecov Go Report Card License: MIT

A Go client library for programmatic control of Anvil, Foundry's local Ethereum test node. Provides a clean interface for managing test environments, manipulating blockchain state, and controlling time and accounts during development.

Features

  • Full programmatic control over Anvil nodes
  • Builder pattern for flexible configuration
  • Chain manipulation (mining, time travel, snapshots)
  • Account management and impersonation
  • Thread-safe metrics collection
  • Fast state reset using RPC calls
  • Comprehensive test coverage

Installation

go get github.com/neverDefined/go-anvil

Prerequisites:

  • Foundry must be installed on your system
  • Go 1.25 or later

Quick Start

package main

import (
    "context"
    "log"

    "github.com/neverDefined/go-anvil"
)

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

    // Create and start an Anvil instance
    anvil, err := anvil.NewAnvil()
    if err != nil {
        log.Fatal(err)
    }

    if err := anvil.Start(); err != nil {
        log.Fatal(err)
    }
    defer anvil.Close()

    // Query the chain via the Ethereum client
    blockNumber, err := anvil.Client().BlockNumber(ctx)
    if err != nil {
        log.Fatal(err)
    }
    log.Printf("Current block: %d", blockNumber)

    // Drive Anvil's RPC with context-first methods
    if err := anvil.MineBlock(ctx); err != nil {
        log.Fatal(err)
    }
}

Configuration

Builder Pattern

Use the builder pattern for custom configuration:

anvil, err := anvil.NewAnvilBuilder().
    WithBlockTime("1").              // Block time in seconds
    WithChainID("1337").              // Custom chain ID
    WithGasLimit("12000000").         // Block gas limit
    WithPort("8545").                 // RPC port
    WithLogLevel(zerolog.InfoLevel).  // Logging level
    WithFork("https://eth-mainnet.alchemyapi.io/v2/YOUR_KEY").
    WithForkBlockNumber("15000000").  // Fork from specific block
    Build()

Available Options

  • WithBlockTime(seconds) - Set automatic block mining interval
  • WithChainID(id) - Set the chain ID
  • WithGasLimit(limit) - Set the block gas limit
  • WithGasPrice(price) - Set the gas price
  • WithPort(port) - Set the RPC port
  • WithFork(url) - Fork from a remote network
  • WithForkBlockNumber(number) - Fork from a specific block
  • WithLogLevel(level) - Set logging verbosity

Usage Examples

Every mutating RPC method takes a context.Context as its first argument. Tests can use t.Context(); production callers should use their request context or context.Background() with a deadline.

Block Mining

ctx := context.Background()

// Mine a single block
err := anvil.MineBlock(ctx)

// Mine multiple blocks
err = anvil.Mine(ctx, 5, 0)  // Mine 5 blocks with default timestamps

// Mine with specific timestamp
timestamp := uint64(time.Now().Unix())
err = anvil.Mine(ctx, 1, timestamp)

// Wait for a specific block
err = anvil.WaitForBlock(10, 5*time.Second)

Time Manipulation

// Increase time by 1 hour
err := anvil.IncreaseTime(ctx, 3600)

// Set timestamp for next block
err = anvil.SetNextBlockTimestamp(ctx, time.Now().Unix())

Account Management

// Get default test accounts
keys, addresses, err := anvil.Accounts()

// Set account balance
address := common.HexToAddress("0x...")
err = anvil.SetBalance(ctx, address, big.NewInt(1e18))  // 1 ETH

// Impersonate an account (send transactions without private key)
err = anvil.Impersonate(ctx, address)
// ... send transactions as this address
err = anvil.StopImpersonating(ctx, address)

// Set account nonce
err = anvil.SetNonce(ctx, address, 42)

State Management

// Reset to initial state (fast - uses RPC)
err := anvil.ResetState(ctx)

// Create a snapshot
snapshotID, err := anvil.Snapshot(ctx)

// Revert to snapshot
success, err := anvil.Revert(ctx, snapshotID)

Advanced Operations

// Set bytecode at address
err := anvil.SetCode(ctx, address, "0x6080604052...")

// Modify storage slot
err = anvil.SetStorageAt(ctx, address, slot, value)

// Control mining
err = anvil.SetAutomine(ctx, false)  // Disable automatic mining
err = anvil.SetIntervalMining(ctx, 5)  // Mine every 5 seconds

// Enable auto-impersonation
err = anvil.AutoImpersonate(ctx, true)

// Drop pending transaction
err = anvil.DropTransaction(ctx, txHash)

Metrics

metrics := anvil.Metrics()
fmt.Printf("Startup time: %v\n", metrics.StartupTime)
fmt.Printf("Blocks mined: %d\n", metrics.BlocksMined)
fmt.Printf("RPC calls: %d\n", metrics.RPCCalls)

Testing

The library includes comprehensive tests. Use the shared instance pattern for faster test execution:

func TestMyContract(t *testing.T) {
    // Create shared instance once
    anvil, _ := anvil.NewAnvil()
    anvil.Start()
    defer anvil.Close()
    
    t.Run("test case 1", func(t *testing.T) {
        // Reset state before each test
        anvil.ResetState(t.Context())
        // ... your test
    })
    
    t.Run("test case 2", func(t *testing.T) {
        anvil.ResetState(t.Context())
        // ... your test
    })
}

API Documentation

Full API documentation is available at pkg.go.dev.

Development

# Run tests
make test

# Run linter
make lint

# Run all checks
make check

License

MIT

About

A Go library for programmatic control of Anvil, Foundry's local Ethereum test node. Manage test environments, manipulate blockchain state, and control time/accounts during development and testing.

Topics

Resources

Contributing

Stars

Watchers

Forks

Releases

Packages

Used by

Contributors

Languages