Complete local testing setup with Anvil fork of Arbitrum mainnet: Infrastructure: - Docker Compose orchestration (Anvil, MEV Bot, Prometheus, Grafana) - Anvil fork configuration with 1-second blocks - Multi-stage Dockerfile for optimized builds - Health checks and auto-restart policies Configuration: - Comprehensive .env.example with all parameters - Prometheus metrics collection setup - Grafana datasource provisioning - .gitignore to prevent committing secrets Testing Scripts: - setup-local-fork.sh: Initialize fork and fund test wallet - create-test-swap.sh: Generate test swaps for bot detection - Both scripts include validation and helpful output Integration Components: - pkg/sequencer/reader.go: WebSocket reader for pending transactions - Worker pool pattern (10 workers) - <50ms processing target - Front-running capability - Auto-reconnection with exponential backoff - pkg/pools/discovery.go: Pool discovery service - UniswapV2-style pools (SushiSwap, Camelot) - UniswapV3 pools (multiple fee tiers) - Factory contract queries - Liquidity filtering Documentation: - TESTING.md: Complete testing guide - Quick start instructions - Testing scenarios - Monitoring and debugging - Performance benchmarks - Troubleshooting guide This enables safe local testing without deploying to public testnet, using real Arbitrum mainnet state forked locally with Anvil. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
10 KiB
10 KiB
MEV Bot V2 - Local Fork Testing Guide
This guide explains how to test the MEV Bot V2 using a local Arbitrum fork with Anvil.
Overview
Instead of deploying to a public testnet, we use Foundry's Anvil to create a local fork of Arbitrum mainnet. This allows us to:
- ✅ Test with real mainnet state (pools, liquidity, etc.)
- ✅ Execute transactions instantly (no waiting for block confirmations)
- ✅ Use unlimited test funds
- ✅ Reset and replay scenarios easily
- ✅ Debug without spending real gas
- ✅ Test front-running scenarios safely
Prerequisites
- Docker & Docker Compose installed
- Foundry (for cast commands) -
curl -L https://foundry.paradigm.xyz | bash && foundryup - Test wallet with private key (NEVER use real funds)
Quick Start
1. Initial Setup
# Copy environment file
cp .env.example .env
# Edit .env and set your test private key
nano .env # Set PRIVATE_KEY to a test wallet key
# Set up the local fork
./scripts/setup-local-fork.sh
This script will:
- Start Anvil fork of Arbitrum
- Fund your test wallet with 100 ETH
- Verify connection and balances
2. Start the Full Stack
# Start all services (Anvil, MEV Bot, Prometheus, Grafana)
docker-compose up -d
# View MEV bot logs
docker-compose logs -f mev-bot
# View Anvil logs
docker-compose logs -f anvil
3. Create Test Swaps
# Create a test swap for the bot to detect
./scripts/create-test-swap.sh
This will:
- Wrap ETH to WETH
- Approve SushiSwap router
- Execute a 0.1 ETH → USDC swap
- The MEV bot should detect this as a potential front-run opportunity
4. Monitor Activity
View Metrics:
# Prometheus metrics
open http://localhost:9090
# Query example: mev_bot_opportunities_found
View Grafana Dashboard:
# Grafana UI
open http://localhost:3000
# Login: admin / admin
View Bot Logs:
docker-compose logs -f mev-bot | grep -i "opportunity\|profit\|execution"
Architecture
┌─────────────────┐
│ Anvil Fork │ ← Forked Arbitrum mainnet state
│ (Port 8545) │
└────────┬────────┘
│
├─────────► Pool Discovery (queries real pools)
│
├─────────► Sequencer Reader (monitors pending txs)
│
└─────────► Executor (sends front-run txs)
│
▼
┌──────────────────┐
│ MEV Bot V2 │
└──────────────────┘
│
▼
┌──────────────────┐
│ Prometheus │ ← Metrics
│ (Port 9090) │
└──────────────────┘
│
▼
┌──────────────────┐
│ Grafana │ ← Visualization
│ (Port 3000) │
└──────────────────┘
Configuration
Environment Variables
Edit .env to configure the bot:
Critical Settings:
# Your test wallet private key
PRIVATE_KEY=your_test_key_here
# Minimum profit to execute (0.01 ETH)
MIN_PROFIT=10000000000000000
# Enable front-running
ENABLE_FRONT_RUNNING=true
# Enable simulation before execution
ENABLE_SIMULATION=true
Risk Parameters:
# Maximum position size (10 ETH)
MAX_POSITION_SIZE=10000000000000000000
# Maximum daily volume (100 ETH)
MAX_DAILY_VOLUME=100000000000000000000
Performance Tuning:
# Worker threads
WORKER_COUNT=10
# Buffer size
BUFFER_SIZE=1000
# Log level
LOG_LEVEL=debug
Anvil Configuration
You can customize the fork in docker-compose.yml:
anvil:
command: >
anvil
--fork-url ${ARBITRUM_RPC_URL}
--fork-block-number ${FORK_BLOCK_NUMBER:-latest} # Specific block or latest
--chain-id 42161
--accounts 10 # Test accounts
--balance 10000 # ETH per account
--block-time 1 # 1 second blocks
Testing Scenarios
Scenario 1: Simple Arbitrage Detection
# 1. Start the bot
docker-compose up -d mev-bot
# 2. Create imbalance by swapping on one DEX
./scripts/create-test-swap.sh
# 3. Check if bot detected opportunity
docker-compose logs mev-bot | grep "opportunity"
Scenario 2: Front-Running Test
# 1. Enable front-running in .env
ENABLE_FRONT_RUNNING=true
# 2. Restart bot
docker-compose restart mev-bot
# 3. Create a large swap
./scripts/create-test-swap.sh
# 4. Check if bot front-ran the transaction
docker-compose logs mev-bot | grep "front-running"
Scenario 3: Multi-Hop Arbitrage
# Create price imbalance across multiple pools
# Swap WETH → USDC on SushiSwap
# Swap USDC → WBTC on Uniswap V3
# Swap WBTC → WETH on Camelot
# Bot should detect triangular arbitrage opportunity
docker-compose logs mev-bot | grep "triangular"
Scenario 4: Stress Test
# Generate many swaps quickly
for i in {1..100}; do
./scripts/create-test-swap.sh &
done
# Monitor processing latency
docker-compose logs mev-bot | grep "latency"
Monitoring & Debugging
Check Pool Discovery
# View discovered pools
docker-compose logs mev-bot | grep "discovered pool"
# Check total pools cached
docker-compose logs mev-bot | grep "pools_cached"
Check Sequencer Connection
# Verify WebSocket connection
docker-compose logs mev-bot | grep "connected to sequencer"
# Check transaction processing
docker-compose logs mev-bot | grep "tx_processed"
Check Opportunity Detection
# View detected opportunities
docker-compose logs mev-bot | grep "opportunities_found"
# View execution attempts
docker-compose logs mev-bot | grep "executions_attempted"
Check Performance Metrics
# Prometheus queries
curl http://localhost:9090/api/v1/query?query=mev_bot_parse_latency_seconds
curl http://localhost:9090/api/v1/query?query=mev_bot_detect_latency_seconds
curl http://localhost:9090/api/v1/query?query=mev_bot_execute_latency_seconds
Debug Mode
# Enable debug logging
echo "LOG_LEVEL=debug" >> .env
# Restart with debug logs
docker-compose restart mev-bot
# View detailed logs
docker-compose logs -f mev-bot
Common Issues
Issue: Anvil not starting
# Check if port 8545 is already in use
lsof -i :8545
# Kill existing process or change port in docker-compose.yml
Issue: Bot not discovering pools
# Check RPC connectivity
docker-compose exec anvil cast block-number --rpc-url http://localhost:8545
# Check pool discovery logs
docker-compose logs mev-bot | grep "pool discovery"
# Verify token addresses are correct for Arbitrum
Issue: No opportunities detected
# 1. Verify pools were discovered
docker-compose logs mev-bot | grep "pools_cached"
# 2. Check minimum thresholds
# Lower MIN_PROFIT in .env for testing
# 3. Create larger price imbalances
# Increase swap amounts in create-test-swap.sh
Issue: Transactions reverting
# Enable simulation to catch errors before execution
ENABLE_SIMULATION=true
# Check revert reasons
docker-compose logs mev-bot | grep "revert"
# Verify wallet has sufficient balance
docker-compose exec anvil cast balance <YOUR_ADDRESS> --rpc-url http://localhost:8545
Advanced Testing
Forking from Specific Block
# Set specific block in .env
FORK_BLOCK_NUMBER=180000000
# Restart Anvil
docker-compose restart anvil
Impersonate Accounts
# Use Anvil's account impersonation to test edge cases
docker-compose exec anvil cast rpc anvil_impersonateAccount <ADDRESS>
Manipulate State
# Set arbitrary balances
docker-compose exec anvil cast rpc anvil_setBalance <ADDRESS> <AMOUNT>
# Mine blocks
docker-compose exec anvil cast rpc anvil_mine 100
# Set next block timestamp
docker-compose exec anvil cast rpc evm_setNextBlockTimestamp <TIMESTAMP>
Reset Fork
# Reset to original fork state
docker-compose exec anvil cast rpc anvil_reset
# Re-run pool discovery
docker-compose restart mev-bot
Performance Benchmarks
Target metrics for production readiness:
- ✅ Parse Latency: < 5ms per transaction
- ✅ Detect Latency: < 10ms per opportunity scan
- ✅ Execute Latency: < 30ms decision time
- ✅ Total Latency: < 50ms end-to-end
- ✅ Throughput: > 100 tx/second processing
- ✅ Memory: < 500MB steady state
- ✅ CPU: < 50% on 4 cores
Benchmarking Commands
# Measure parse latency
docker-compose logs mev-bot | grep "avg_parse_latency"
# Measure detection latency
docker-compose logs mev-bot | grep "avg_detect_latency"
# Measure execution latency
docker-compose logs mev-bot | grep "avg_execute_latency"
# Check memory usage
docker stats mev-bot-v2
# Load test with many concurrent swaps
./scripts/load-test.sh
Cleanup
# Stop all services
docker-compose down
# Remove volumes (clears metrics data)
docker-compose down -v
# Clean up logs
rm -rf logs/*
Next Steps
Once local testing is successful:
- Optimize Parameters: Tune MIN_PROFIT, MAX_SLIPPAGE, etc.
- Deploy Flashloan Contract: Deploy executor contract to Arbitrum testnet
- Testnet Testing: Test on Arbitrum Goerli with real test ETH
- Mainnet Deployment: Deploy with conservative parameters and monitoring
Resources
- Anvil Docs: https://book.getfoundry.sh/anvil/
- Arbitrum Docs: https://docs.arbitrum.io/
- Prometheus Docs: https://prometheus.io/docs/
- Grafana Docs: https://grafana.com/docs/
Support
For issues or questions:
- Check logs:
docker-compose logs mev-bot - Review configuration:
.env - Check Anvil status:
docker-compose logs anvil - Verify metrics:
http://localhost:9090