#ethereum #defi #blockchain

revm-trace

A Rust library for tracing EVM transactions, including call traces, asset transfers, and error analysis using REVM

10 releases (stable)

new 2.0.5 Mar 31, 2025
2.0.4 Mar 2, 2025
2.0.3 Feb 13, 2025
2.0.2 Dec 25, 2024
0.1.2 Nov 26, 2024

#999 in Magic Beans

Download history 134/week @ 2024-12-11 60/week @ 2024-12-18 155/week @ 2024-12-25 7/week @ 2025-01-08 3/week @ 2025-02-05 139/week @ 2025-02-12 3/week @ 2025-02-19 165/week @ 2025-02-26 16/week @ 2025-03-05 94/week @ 2025-03-26

127 downloads per month

MIT/Apache

96KB
1K SLoC

REVM Transaction Simulator and Analyzer

A Rust library that combines powerful transaction simulation with comprehensive analysis capabilities for EVM-based blockchains. Built on REVM, this tool enables you to:

  • Simulate complex transactions and their interactions before actual execution
  • Analyze potential outcomes, asset transfers, and state changes
  • Detect possible errors and their root causes
  • Preview all transaction effects in a safe, isolated environment

Perfect for:

  • DeFi developers testing complex interactions
  • Wallet developers validating transaction safety
  • Protocol teams analyzing contract behaviors
  • Security researchers investigating transaction patterns

Key Features

  • Flexible Inspector System

    • Built on REVM's inspector framework
    • Custom TxInspector for transaction analysis
    • Support for custom inspector implementations
    • Comprehensive asset transfer tracking
  • Complete Call Hierarchy Analysis

    • Full depth call stack tracking
    • Detailed call context information
    • Internal transaction tracing
    • Precise error location in call stack
    • Step-by-step execution tracing
  • Enhanced Error Handling

    • Detailed error messages and traces
    • Error location in call stack
    • Revert reason decoding
    • Custom error parsing
    • Contract-specific error context
  • Batch Transaction Processing

    • Process multiple transactions
    • Stateful/stateless execution modes
    • Automatic state management
    • Detailed execution results
  • Asset Analysis

    • Native token transfers
    • ERC20 token transfers
    • Transfer event parsing
    • Balance change tracking
    • Complete transaction logs

Features

  • async - Enable async support
  • ws - WebSocket provider support
  • http - HTTP provider support (default)

TLS Implementation Options

By default, this library uses the system's native TLS implementation (typically OpenSSL). However, you can switch to a pure Rust TLS implementation:

  • rustls-tls: Uses rustls instead of native-tls (OpenSSL)
# In your Cargo.toml
[dependencies]
revm-trace = { version = "2.0.5", default-features = false, features = ["rustls-tls"] }

To run examples with rustls-tls:

cargo run --example test_rustls --no-default-features --features rustls-tls

This is particularly useful for:

  • Cross-compilation scenarios
  • Environments where OpenSSL is not available
  • Alpine Linux-based Docker containers
  • WASM targets

Installation

Add this to your Cargo.toml:

revm-trace = "2.0.5"

Quick Start

use revm_trace::{
    TransactionProcessor,
    evm::create_evm_with_inspector,
    types::{BlockEnv, SimulationTx, SimulationBatch},
    inspectors::TxInspector,
};
use alloy::primitives::{address, U256, TxKind};


#[tokio::main]
async fn main() -> anyhow::Result<()> {
    // Initialize EVM with transaction inspector
    let mut evm = create_evm_with_inspector(
        "https://eth-mainnet.g.alchemy.com/v2/your-api-key",
        TxInspector::new(),
    ).await?;

    // Create simulation transaction
    let tx = SimulationTx {
        caller: address!("C255fC198eEdAC7AF8aF0f6e0ca781794B094A61"),
        transact_to: TxKind::Call(address!("d878229c9c3575F224784DE610911B5607a3ad15")),
        value: U256::from(120000000000000000u64), // 0.12 ETH
        data: vec![].into(),
    };

    // Create batch with single transaction
    let batch = SimulationBatch {
        block_env: BlockEnv {
            number: 21784863,
            timestamp: 1700000000,
        },
        transactions: vec![tx],
        is_stateful: false,
    };

    // Execute transaction batch
    let results = evm.process_transactions(batch)
        .into_iter()
        .map(|v| v.unwrap())
        .collect::<Vec<_>>();

    // Process results
    for (execution_result, inspector_output) in results {
        match execution_result.is_success() {
            true => {
                println!("Transaction succeeded!");
                for transfer in inspector_output.asset_transfers {
                    println!(
                        "Transfer: {} from {} to {}",
                        transfer.value, transfer.from, transfer.to.unwrap()
                    );
                }
            }
            false => {
                println!("Transaction failed!");
                if let Some(error_trace) = inspector_output.error_trace_address {
                    println!("Error occurred at call depth: {}", error_trace.len());
                }
            }
        }
    }

    Ok(())
}

More Examples

For more detailed examples and use cases, please check:

  • Example Directory: Contains standalone examples demonstrating specific features

    • DeFi interaction simulations
    • Token transfer analysis
    • Complex contract interactions
    • Proxy contract handling
  • Integration Tests: Comprehensive test cases showing various usage scenarios

    • Transaction batching
    • Error handling
    • State tracking
    • Event analysis

These examples cover common use cases and demonstrate best practices for using the library.

For a quick overview, here are some key examples:

  1. Simulating DeFi Swaps
  2. Analyzing Token Transfers
  3. Handling Complex Contract Interactions
  4. Working with Proxy Contracts

Important Notes

Safe Simulation Environment

All simulations run in an isolated environment:

  • No actual blockchain state is modified
  • No real transactions are submitted
  • No gas fees are spent
  • Perfect for testing and validation

Thread Safety and Concurrency

The EVM instance is not thread-safe and cannot be shared between threads. Here's how to handle concurrent operations:

❌ What NOT to do
// DON'T share a single EVM instance across threads
let mut evm = create_evm_with_inspector("https://rpc...", TxInspector::new()).await?;
let results: Vec<_> = transactions
  .par_iter() // ❌ This will fail - EVM instance is not thread-safe
  .map(|tx| {
    evm.process_transactions(SimulationBatch {
      block_env: block_env.clone(),
      transactions: vec![tx.clone()],
      is_stateful: true,
    }) // Sharing EVM across threads
  })
  .collect();
✅ Correct Usage
  1. Sequential Processing
// Process transactions sequentially with a single EVM instance
let mut evm = create_evm_with_inspector("https://rpc...", TxInspector::new()).await?;
let results: Vec<_> = transactions
  .iter()
  .map(|tx| {
    evm.process_transactions(SimulationBatch {
        block_env: block_env.clone(),
        transactions: vec![tx.clone()],
        is_stateful: true,
      })
    })
  .collect();
  1. Parallel Processing with Multiple Instances
use rayon::prelude::*;
// Create new EVM instance for each thread
let results: Vec<Result<_, _>> = transactions
  .par_iter()
  .map(|tx| async {
    // Each thread gets its own EVM instance
    let mut evm = create_evm_with_inspector("https://rpc...", TxInspector::new()).await?;
    evm.process_transactions(SimulationBatch {
      block_env: block_env.clone(),
      transactions: vec![tx.clone()],
      is_stateful: true,
    })
  })
  .collect();

Performance Considerations

  • RPC Limitations:

    • Each EVM instance maintains its own RPC connection
    • Consider your RPC provider's connection and rate limits
    • Too many parallel instances might exceed provider limits
  • Resource Usage:

    • Each EVM instance requires its own memory
    • Balance parallelism with resource constraints
    • Monitor system memory usage when scaling
  • Optimal Approach:

    • For small batches: Use sequential processing

    • For large batches: Use parallel processing with connection pooling

    • Consider implementing a worker pool pattern for better resource management

Working with Proxy Contracts

The library automatically handles proxy contracts by resolving their implementations:

  • EIP-1967 proxies
  • EIP-1967 beacon proxies
  • OpenZeppelin transparent proxies
  • EIP-1822 (UUPS) proxies

Features in Detail

Asset Transfer Tracking

  • Native token transfers (including internal transfers)
  • ERC20 token transfers
  • Transaction logs and events
  • Chronological ordering of transfers
  • Complete token information collection

Transaction Simulation

  • Full EVM context simulation
  • Custom environment configuration
  • Detailed execution results
  • Error handling and revert messages

Historical State Access

Simulations can be run against different historical states:

  • Recent blocks: Available on all nodes
  • Historical blocks: Requires archive node access
  • Future blocks: Uses latest state as base

Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

License

This project is licensed under either of

at your option.

Acknowledgments

Built with REVM and Alloy

Dependencies

~41–56MB
~1M SLoC