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>
447 lines
10 KiB
Markdown
447 lines
10 KiB
Markdown
# 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
|
|
|
|
```bash
|
|
# 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
|
|
|
|
```bash
|
|
# 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
|
|
|
|
```bash
|
|
# 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:**
|
|
```bash
|
|
# Prometheus metrics
|
|
open http://localhost:9090
|
|
|
|
# Query example: mev_bot_opportunities_found
|
|
```
|
|
|
|
**View Grafana Dashboard:**
|
|
```bash
|
|
# Grafana UI
|
|
open http://localhost:3000
|
|
# Login: admin / admin
|
|
```
|
|
|
|
**View Bot Logs:**
|
|
```bash
|
|
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:**
|
|
```bash
|
|
# 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:**
|
|
```bash
|
|
# Maximum position size (10 ETH)
|
|
MAX_POSITION_SIZE=10000000000000000000
|
|
|
|
# Maximum daily volume (100 ETH)
|
|
MAX_DAILY_VOLUME=100000000000000000000
|
|
```
|
|
|
|
**Performance Tuning:**
|
|
```bash
|
|
# 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`:
|
|
|
|
```yaml
|
|
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
|
|
|
|
```bash
|
|
# 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
|
|
|
|
```bash
|
|
# 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
|
|
|
|
```bash
|
|
# 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
|
|
|
|
```bash
|
|
# 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
|
|
|
|
```bash
|
|
# 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
|
|
|
|
```bash
|
|
# 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
|
|
|
|
```bash
|
|
# 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
|
|
|
|
```bash
|
|
# 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
|
|
|
|
```bash
|
|
# 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
|
|
|
|
```bash
|
|
# 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
|
|
|
|
```bash
|
|
# 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
|
|
|
|
```bash
|
|
# 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
|
|
|
|
```bash
|
|
# 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
|
|
|
|
```bash
|
|
# Set specific block in .env
|
|
FORK_BLOCK_NUMBER=180000000
|
|
|
|
# Restart Anvil
|
|
docker-compose restart anvil
|
|
```
|
|
|
|
### Impersonate Accounts
|
|
|
|
```bash
|
|
# Use Anvil's account impersonation to test edge cases
|
|
docker-compose exec anvil cast rpc anvil_impersonateAccount <ADDRESS>
|
|
```
|
|
|
|
### Manipulate State
|
|
|
|
```bash
|
|
# 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
|
|
|
|
```bash
|
|
# 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
|
|
|
|
```bash
|
|
# 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
|
|
|
|
```bash
|
|
# 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
|
|
|
|
- **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:
|
|
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`
|