Files
mev-beta/TESTING.md
Administrator 65c1005d91 feat(testing): add Anvil fork local testing infrastructure
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>
2025-11-10 18:52:56 +01:00

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

  1. Docker & Docker Compose installed
  2. Foundry (for cast commands) - curl -L https://foundry.paradigm.xyz | bash && foundryup
  3. 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:

  1. Optimize Parameters: Tune MIN_PROFIT, MAX_SLIPPAGE, etc.
  2. Deploy Flashloan Contract: Deploy executor contract to Arbitrum testnet
  3. Testnet Testing: Test on Arbitrum Goerli with real test ETH
  4. Mainnet Deployment: Deploy with conservative parameters and monitoring

Resources

Support

For issues or questions:

  1. Check logs: docker-compose logs mev-bot
  2. Review configuration: .env
  3. Check Anvil status: docker-compose logs anvil
  4. Verify metrics: http://localhost:9090