A high-performance Rust library for detecting and simulating arbitrage opportunities across Uniswap V2 DEX pairs on Ethereum.
This library provides a modular, production-ready framework for:
- ๐ Discovering arbitrage opportunities across DEX pairs
- โก Parallel processing of blockchain blocks using Rayon
- ๐ Smart caching with thread-safe operations
- ๐งช REVM-based execution simulation with accurate gas tracking
- ๐ Mathematical optimization using ternary search algorithms
Originally a 1,347-line monolithic example, now refactored into a well-organized library with 6 specialized modules and comprehensive documentation.
graph TB
subgraph "Core Library Modules"
PARALLEL[parallel/<br/>Block Processing]
CACHE[cache/<br/>Smart Caching]
SIMULATION[simulation/<br/>REVM Execution]
STRATEGY[strategy/<br/>Algorithms]
TYPES[types/<br/>Data Structures]
UTILS[utils/<br/>Helpers]
end
subgraph "External Dependencies"
RPC[RPC Provider<br/>Ethereum Node]
REVM_LIB[REVM<br/>EVM Simulator]
end
PARALLEL --> CACHE
PARALLEL --> SIMULATION
PARALLEL --> STRATEGY
PARALLEL --> UTILS
CACHE --> TYPES
SIMULATION --> TYPES
STRATEGY --> TYPES
UTILS --> TYPES
SIMULATION --> REVM_LIB
CACHE --> RPC
style PARALLEL fill:#ffd699,color:#000
style CACHE fill:#d4a5ff,color:#000
style SIMULATION fill:#a5ffb8,color:#000
style STRATEGY fill:#ffb3b3,color:#000
style TYPES fill:#d4d4d4,color:#000
style UTILS fill:#fff066,color:#000
๐ Full Architecture Documentation - Detailed diagrams and design patterns
You'll need access to an Ethereum archive node with full historical state. Options include:
- Local node (Erigon, Reth, Geth archive mode)
- Remote RPC provider (Alchemy, Infura, QuickNode with archive access)
- Private network node (e.g., via Tailscale)
[dependencies]
simple-arbitrage = { path = "." }
tokio = { version = "1", features = ["full"] }
anyhow = "1.0"use simple_arbitrage::parallel::{
process_block_range, ArbitrageStats, BlockProcessor,
};
use std::sync::Arc;
#[tokio::main]
async fn main() -> anyhow::Result<()> {
// Setup RPC client
let client = Arc::new(
ProviderBuilder::new()
.connect("http://localhost:8545")
.await?
.erased(),
);
// Create processor and stats
let processor = BlockProcessor::new();
let stats = ArbitrageStats::new();
// Process blocks in parallel
let results = process_block_range(
22_200_000, // start block
22_210_000, // end block
client,
processor.get_cache_clone(),
processor.config.clone(),
None, // optional progress callback
stats.clone(),
);
println!("Found {} profitable opportunities", stats.get_total());
Ok(())
}See examples/modular_arbitrage.rs for a complete example.
Orchestrates parallel arbitrage detection across multiple blocks using Rayon.
Key Features:
- Rayon-based parallel iteration
- Tokio async/sync bridging
- Progress tracking with callbacks
- Thread-safe statistics
Main Types:
BlockProcessor- Coordinates block processingArbitrageStats- Tracks profitable opportunitiesprocess_block_range()- Main entry point
Thread-safe caching layer with smart loading strategies.
Key Features:
- Arc<Mutex> for thread safety
- Full load vs reserve-only updates
- Multicall batching (1000 pairs/call)
- High-level management API
Main Types:
PairCache- Thread-safe cache wrapperCacheManager- High-level cache operationsclassify_pairs()- Smart loading strategy
EVM simulation infrastructure for accurate arbitrage execution testing.
Key Features:
- REVM-based execution
- Accurate gas tracking
- Account and storage setup
- Balance, transfer, and swap operations
Main Types:
simulate_arbitrage_execution()- Full simulationGasMeter- Gas tracking- EVM call wrappers (balance_of, swap, transfer)
Core algorithms for arbitrage detection and optimization.
Key Features:
- Mathematical inequality detection
- Ternary search optimization (O(logโ n))
- U512 overflow prevention
- Configurable convergence epsilon
Main Types:
find_arbitrage()- Detects opportunitiesfind_optimal_amount()- Ternary searchcompute_profit()- Profit calculation
Shared type definitions used across modules.
Key Features:
- PairInfo with reserve updates
- Solidity contract interfaces
- Type aliases for complex nested types
Main Types:
PairInfo- Liquidity pool informationAlloyCacheDB- REVM state type alias- Contract interfaces (IUniswapV2Pair)
Common operations for pair grouping and combinations.
Key Features:
- WETH pair grouping
- Combination generation (C(n,2))
- Comprehensive unit tests
Main Functions:
group_pairs_by_token()- Groups WETH pairsget_pair_combinations()- Generates combinations
- Parallel Processing: Rayon-based multi-threaded block processing
- Smart Caching: Full load vs reserve-only update strategies
- Multicall Batching: 1000 pairs per RPC call
- Lock-Free Stats: Atomic counters for statistics
- Overflow Prevention: U512 arithmetic in profit calculations
- Pre-Allocation: Exact capacity for vectors (C(n,2) combinations)
- Early Filtering: Minimum reserve checks (1 ETH threshold)
The library is designed for safe concurrent execution:
graph LR
subgraph "Shared State (Thread-Safe)"
CACHE[Arc<Mutex<HashMap>><br/>Pair Cache]
STATS[Arc<AtomicUsize><br/>Statistics]
CONFIG[Arc<Config><br/>Read-Only]
end
subgraph "Per-Thread (Isolated)"
STATE1[REVM State 1]
STATE2[REVM State 2]
STATEN[REVM State N]
end
T1[Thread 1] --> CACHE
T2[Thread 2] --> CACHE
TN[Thread N] --> CACHE
T1 --> STATS
T2 --> STATS
TN --> STATS
T1 --> STATE1
T2 --> STATE2
TN --> STATEN
Uses mathematical inequality to detect opportunities:
997ยฒ ร reserve0_a ร reserve1_b > 1000ยฒ ร reserve1_a ร reserve0_b
Where:
997= Uniswap fee factor (0.3% fee)1000= Base factor- Reserves arranged as: reserve1 = WETH, reserve0 = Token
Implements ternary search to find the optimal input amount:
- Initialize bounds:
[1 wei, min(100รreserve, balance)] - Divide range into thirds
- Evaluate profit at
mid1andmid2 - Discard third with lower profit
- Repeat until convergence (ฮต = 0.001 ETH)
- Return amount with maximum profit
Complexity: O(logโ(range)) iterations
Run the test suite:
# Run all tests
cargo test
# Run specific module tests
cargo test --lib cache
cargo test --lib utils
# Run with output
cargo test -- --nocapturecargo run --example modular_arbitrageThe examples/ directory contains various demonstration scripts:
modular_arbitrage.rs- Clean example using refactored library110725_simulation3.rs- Original monolithic implementation110725_simulation2.rs- Intermediate version110725_simulation.rs- Earlier version
Customize behavior via BlockProcessorConfig:
use simple_arbitrage::parallel::{BlockProcessor, BlockProcessorConfig};
use alloy::primitives::{address, U256};
let config = BlockProcessorConfig {
weth_address: address!("c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2"),
account_address: address!("18B06aaF27d44B756FCF16Ca20C1f183EB49111f"),
balance: U256::from(1_000_000_000_000_000_000_000_000u128), // 1M ETH
};
let processor = BlockProcessor::with_config(config);Monitor arbitrage opportunities across parallel workers:
let stats = ArbitrageStats::new();
// ... process blocks ...
println!("Total profitable opportunities: {}", stats.get_total());Thread-safe atomic counters ensure accurate statistics across parallel execution.
Enable detailed logging:
// Add to Cargo.toml
tracing-subscriber = "0.3"
// In your code
tracing_subscriber::fmt::init();Log levels:
debug- Skipped pairs, cache hits/misseswarn- Non-critical failureserror- Critical errors
- Architecture Diagrams - Visual overview with Mermaid diagrams
- Refactoring Summary - Details of the refactoring process
- API Docs - Generate with
cargo doc --open
- Reads recently active pair addresses from cached data
- Filters for pairs with swaps in last ~10k blocks (~1 day)
- First encounter: Full load (addresses, symbols, decimals, reserves)
- Already cached: Reserve-only update via multicall
- Thread-safe shared cache across parallel workers
- Groups pairs by non-WETH token
- Generates all combinations C(n,2) for each token
- Tests both directions (AโB and BโA)
- Filters by minimum reserves (โฅ1 ETH)
- Mathematical inequality check for arbitrage
- Ternary search finds optimal input amount
- Evaluates profit function at midpoints
- Converges to maximum profit amount
- REVM executes trades in simulated environment
- Tracks gas for all operations
- Calculates net profit after gas costs
- Returns (profit, gas_used) tuple
- Atomic counters track profitable opportunities
- Progress callbacks for monitoring
- Per-block timing and results
- Uniswap V2 Only: Currently supports only Uniswap V2 pairs
- Two-Pool Arbitrage: Limited to simple two-pool arbitrage loops
- No Flash Loans: Assumes available balance for trades
- Historical Data: Requires pre-cached pair addresses
- Gas Price: Uses simple base_fee + priority_fee model
- Multi-hop arbitrage (3+ pools)
- Flash loan integration
- Uniswap V3 support
- Cross-DEX arbitrage (Sushiswap, Curve, etc.)
- Real-time mempool monitoring
- MEV protection strategies
- Configurable gas price strategies
- Web UI for monitoring
This project is provided as-is for educational and research purposes.
Built with:
- Alloy - Ethereum types and RPC
- REVM - Rust EVM implementation
- Rayon - Data parallelism
- Tokio - Async runtime