Skip to content

molaco/simple-arbitrage

Folders and files

NameName
Last commit message
Last commit date

Latest commit

ย 

History

50 Commits
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 

Repository files navigation

Simple Arbitrage

A high-performance Rust library for detecting and simulating arbitrage opportunities across Uniswap V2 DEX pairs on Ethereum.

๐ŸŒŸ Overview

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.

๐Ÿ“Š Architecture

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
Loading

๐Ÿ“– Full Architecture Documentation - Detailed diagrams and design patterns

๐Ÿš€ Quick Start

Prerequisites

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)

โš ๏ธ Important: Update the RPC URL in examples to point to your node. The default URL in examples is a private Tailscale endpoint and won't work for you.

Installation

[dependencies]
simple-arbitrage = { path = "." }
tokio = { version = "1", features = ["full"] }
anyhow = "1.0"

Basic Usage

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.

๐Ÿ“ฆ Module Overview

๐Ÿ”„ parallel - Concurrent Block Processing

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 processing
  • ArbitrageStats - Tracks profitable opportunities
  • process_block_range() - Main entry point

๐Ÿ’พ cache - Intelligent Pair Caching

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 wrapper
  • CacheManager - High-level cache operations
  • classify_pairs() - Smart loading strategy

๐Ÿงช simulation - REVM Execution Engine

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 simulation
  • GasMeter - Gas tracking
  • EVM call wrappers (balance_of, swap, transfer)

๐Ÿ“ strategy - Mathematical Algorithms

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 opportunities
  • find_optimal_amount() - Ternary search
  • compute_profit() - Profit calculation

๐Ÿ“‹ types - Core Data Structures

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 information
  • AlloyCacheDB - REVM state type alias
  • Contract interfaces (IUniswapV2Pair)

๐Ÿ› ๏ธ utils - Helper Utilities

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 pairs
  • get_pair_combinations() - Generates combinations

โšก Performance Features

  • 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)

๐Ÿ” Thread Safety

The library is designed for safe concurrent execution:

graph LR
    subgraph "Shared State (Thread-Safe)"
        CACHE[Arc&lt;Mutex&lt;HashMap&gt;&gt;<br/>Pair Cache]
        STATS[Arc&lt;AtomicUsize&gt;<br/>Statistics]
        CONFIG[Arc&lt;Config&gt;<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
Loading

๐Ÿงฎ Algorithm Overview

Arbitrage Detection

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

Optimal Amount Finding

Implements ternary search to find the optimal input amount:

  1. Initialize bounds: [1 wei, min(100ร—reserve, balance)]
  2. Divide range into thirds
  3. Evaluate profit at mid1 and mid2
  4. Discard third with lower profit
  5. Repeat until convergence (ฮต = 0.001 ETH)
  6. Return amount with maximum profit

Complexity: O(logโ‚ƒ(range)) iterations

๐Ÿงช Testing

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 -- --nocapture

๐Ÿ“– Examples

Run the Modular Example

cargo run --example modular_arbitrage

Other Examples

The examples/ directory contains various demonstration scripts:

  • modular_arbitrage.rs - Clean example using refactored library
  • 110725_simulation3.rs - Original monolithic implementation
  • 110725_simulation2.rs - Intermediate version
  • 110725_simulation.rs - Earlier version

๐Ÿ”ง Configuration

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);

๐Ÿ“Š Statistics Tracking

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.

๐Ÿ› Debugging

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/misses
  • warn - Non-critical failures
  • error - Critical errors

๐Ÿ“ Documentation

๐Ÿ” How It Works

1. Pair Discovery

  • Reads recently active pair addresses from cached data
  • Filters for pairs with swaps in last ~10k blocks (~1 day)

2. Smart Caching

  • First encounter: Full load (addresses, symbols, decimals, reserves)
  • Already cached: Reserve-only update via multicall
  • Thread-safe shared cache across parallel workers

3. Arbitrage Detection

  • 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

4. Optimization

  • Ternary search finds optimal input amount
  • Evaluates profit function at midpoints
  • Converges to maximum profit amount

5. Simulation

  • REVM executes trades in simulated environment
  • Tracks gas for all operations
  • Calculates net profit after gas costs
  • Returns (profit, gas_used) tuple

6. Statistics

  • Atomic counters track profitable opportunities
  • Progress callbacks for monitoring
  • Per-block timing and results

๐Ÿšง Limitations

  • 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

๐Ÿ”ฎ Future Enhancements

  • 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

๐Ÿ“„ License

This project is provided as-is for educational and research purposes.

๐Ÿ™ Acknowledgments

Built with:

  • Alloy - Ethereum types and RPC
  • REVM - Rust EVM implementation
  • Rayon - Data parallelism
  • Tokio - Async runtime

โš ๏ธ Disclaimer: This software is for educational purposes only. Using it for actual trading involves significant financial risk. Always test thoroughly and understand the code before deploying with real funds.

About

Using revm and alloy-rs to build eth arbitrage bot and perform simulations with reth archive node

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages