Crates.io | revm-trace |
lib.rs | revm-trace |
version | 1.0.0 |
source | src |
created_at | 2024-11-24 04:21:34.641751 |
updated_at | 2024-11-29 08:23:02.038288 |
description | A Rust library for tracing EVM transactions, including call traces, asset transfers, and error analysis using REVM |
homepage | |
repository | https://github.com/Rollp0x/revm-trace |
max_upload_size | |
id | 1458958 |
size | 205,553 |
A Rust library for simulating EVM-compatible blockchain transactions and tracking asset transfers, logs, and events using REVM. This library provides a safe and efficient way to simulate transactions and analyze their effects without actually submitting them to the blockchain.
Add this to your Cargo.toml
:
revm-trace = "1.0.0"
use revm_trace::{
trace_tx_assets,
create_evm_instance_with_tracer,
};
async fn example() -> anyhow::Result<()> {
// Create EVM instance with transaction tracer
let inspector = TransactionTracer::default();
let mut evm = create_evm_instance_with_tracer(
"https://rpc.ankr.com/eth", // Can be any EVM-compatible chain RPC
Some(1) // Chain ID: 1 for Ethereum mainnet
)?;
// Simulate transaction and track transfers
let result = trace_tx_assets(
&mut evm,
from_address,
to_address,
value,
call_data,
"ETH" // Native token symbol
).await;
// Process results
for transfer in result.asset_transfers() {
if transfer.is_native_token() {
println!("Native token transfer: {} -> {}: {}",
transfer.from,
transfer.to,
transfer.value
);
} else {
let token_info = result.token_info.get(&transfer.token)
.expect("Token info should exist");
println!("Token transfer: {} {} -> {}: {}",
token_info.symbol,
transfer.from,
transfer.to,
transfer.value
);
}
}
// Process logs
for log in result.logs {
println!("Log from {}: {:?}", log.address, log);
}
Ok(())
}
// Example of tracking a Uniswap-like DEX swap on any EVM chain
let router = address!("7a250d5630B4cF539739dF2C5dAcb4c659F2488D");
let result = trace_tx_assets(
&mut evm,
user_address,
router,
native_token_amount,
swap_data,
"BNB" // Use appropriate native token symbol
).await;
// Process transfers and logs
for transfer in result.asset_transfers() {
println!("Transfer: {:?}", transfer);
}
for log in result.logs {
if log.topics()[0] == SWAP_EVENT_SIGNATURE {
println!("Swap event: {:?}", log);
}
}
When simulating multiple transactions using the same EVM instance, you need to reset the inspector state between simulations:
use revm_trace::{
trace_tx_assets,
create_evm_instance_with_tracer,
GetTransactionTracer,
Reset,
};
async fn simulate_multiple_txs() -> anyhow::Result<()> {
let mut evm = create_evm_instance_with_tracer(
"https://rpc.ankr.com/eth",
Some(1)
)?;
// First simulation
let result1 = trace_tx_assets(&mut evm, from, to1, value1, data1, "ETH").await;
// Reset inspector state before next simulation
evm.reset_inspector();
// Second simulation with clean state
let result2 = trace_tx_assets(&mut evm, from, to2, value2, data2, "ETH").await;
Ok(())
}
You can customize the block environment for simulation:
use revm_trace::{
trace_tx_assets,
create_evm_instance_with_tracer,
BlockEnvConfig,
};
async fn simulate_at_specific_block() -> anyhow::Result<()> {
let mut evm = create_evm_instance_with_tracer(
"https://rpc.ankr.com/eth",
Some(1)
)?;
// Set specific block number and timestamp
evm.set_block_number(17_000_000)
.set_block_timestamp(1677777777);
// Or set both at once
evm.set_block_env(17_000_000, 1677777777);
let result = trace_tx_assets(&mut evm, from, to, value, data, "ETH").await;
Ok(())
}
The core Evm
instance from REVM is not thread-safe, and consequently, our tracing functionality cannot be used across threads. This means you cannot share an Evm
instance between threads or use it in parallel operations.
// This will NOT work - do not share Evm across threads
let mut evm = create_evm_instance_with_tracer("https://rpc...", Some(1))?;
let handles: Vec<> = transactions
.into_par_iter() // ❌ Parallel processing will fail
.map(|tx| {
trace_tx_assets(&mut evm, tx.from, tx.to, tx.value, tx.data, "ETH")
})
.collect();
// Create separate EVM instances for each thread
let handles: Vec<> = transactions
.into_iter() // ✅ Sequential processing
.map(|tx| {
let mut evm = create_evm_instance_with_tracer("https://rpc...", Some(1))?;
trace_tx_assets(&mut evm, tx.from, tx.to, tx.value, tx.data, "ETH")
})
.collect();
// Alternative: If you need parallel processing
use rayon::prelude::;
let results: Vec<> = transactions
.par_iter()
.map(|tx| {
let mut evm = create_evm_instance_with_tracer("https://rpc...", Some(1))?;
trace_tx_assets(&mut evm, tx.from, tx.to, tx.value, tx.data, "ETH")
})
.collect();
Create new EVM instances for parallel operations
Consider connection pool limits of your RPC provider
Balance between parallelism and RPC rate limits
The library automatically handles proxy contracts by resolving their implementations:
When accessing historical blockchain state, capabilities depend on the node type:
The actual accessible block range varies by provider and node configuration.
Contributions are welcome! Please feel free to submit a Pull Request.
This project is licensed under either of
at your option.