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>
This commit is contained in:
105
scripts/create-test-swap.sh
Executable file
105
scripts/create-test-swap.sh
Executable file
@@ -0,0 +1,105 @@
|
||||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
# MEV Bot V2 - Create Test Swap Script
|
||||
# This script creates a test swap on the Anvil fork for the bot to detect
|
||||
|
||||
# Colors for output
|
||||
GREEN='\033[0;32m'
|
||||
YELLOW='\033[1;33m'
|
||||
RED='\033[0;31m'
|
||||
NC='\033[0m' # No Color
|
||||
|
||||
echo "🔄 Creating test swap on Anvil fork..."
|
||||
|
||||
# Load environment variables
|
||||
if [ ! -f .env ]; then
|
||||
echo -e "${RED}❌ Error: .env file not found${NC}"
|
||||
exit 1
|
||||
fi
|
||||
source .env
|
||||
|
||||
# Token addresses on Arbitrum
|
||||
WETH="0x82aF49447D8a07e3bd95BD0d56f35241523fBab1"
|
||||
USDC="0xFF970a61A04b1cA14834A43f5dE4533eBDDB5CC8"
|
||||
|
||||
# SushiSwap Router on Arbitrum
|
||||
SUSHISWAP_ROUTER="0x1b02dA8Cb0d097eB8D57A175b88c7D8b47997506"
|
||||
|
||||
# Amount to swap (0.1 ETH)
|
||||
AMOUNT="100000000000000000"
|
||||
|
||||
echo -e "${YELLOW}Token In: WETH ($WETH)${NC}"
|
||||
echo -e "${YELLOW}Token Out: USDC ($USDC)${NC}"
|
||||
echo -e "${YELLOW}Amount: 0.1 ETH${NC}"
|
||||
|
||||
# Step 1: Wrap ETH to WETH
|
||||
echo ""
|
||||
echo "📦 Step 1: Wrapping ETH to WETH..."
|
||||
docker-compose exec -T anvil cast send $WETH \
|
||||
"deposit()" \
|
||||
--value 0.1ether \
|
||||
--private-key $PRIVATE_KEY \
|
||||
--rpc-url http://localhost:8545
|
||||
|
||||
WETH_BALANCE=$(docker-compose exec -T anvil cast call $WETH \
|
||||
"balanceOf(address)(uint256)" \
|
||||
$(docker-compose exec -T anvil cast wallet address $PRIVATE_KEY) \
|
||||
--rpc-url http://localhost:8545)
|
||||
echo -e "${GREEN}✅ WETH Balance: $WETH_BALANCE${NC}"
|
||||
|
||||
# Step 2: Approve router to spend WETH
|
||||
echo ""
|
||||
echo "✅ Step 2: Approving SushiSwap router..."
|
||||
docker-compose exec -T anvil cast send $WETH \
|
||||
"approve(address,uint256)" \
|
||||
$SUSHISWAP_ROUTER \
|
||||
"0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff" \
|
||||
--private-key $PRIVATE_KEY \
|
||||
--rpc-url http://localhost:8545
|
||||
|
||||
echo -e "${GREEN}✅ Approval confirmed${NC}"
|
||||
|
||||
# Step 3: Execute swap
|
||||
echo ""
|
||||
echo "🔄 Step 3: Executing swap on SushiSwap..."
|
||||
echo -e "${YELLOW}This swap should be detected by the MEV bot!${NC}"
|
||||
|
||||
# Build swap calldata
|
||||
# swapExactTokensForTokens(uint256 amountIn, uint256 amountOutMin, address[] path, address to, uint256 deadline)
|
||||
DEADLINE=$(($(date +%s) + 3600))
|
||||
TO=$(docker-compose exec -T anvil cast wallet address $PRIVATE_KEY)
|
||||
|
||||
docker-compose exec -T anvil cast send $SUSHISWAP_ROUTER \
|
||||
"swapExactTokensForTokens(uint256,uint256,address[],address,uint256)" \
|
||||
$AMOUNT \
|
||||
"0" \
|
||||
"[$WETH,$USDC]" \
|
||||
$TO \
|
||||
$DEADLINE \
|
||||
--private-key $PRIVATE_KEY \
|
||||
--rpc-url http://localhost:8545
|
||||
|
||||
echo ""
|
||||
echo -e "${GREEN}✅ Test swap executed!${NC}"
|
||||
|
||||
# Check balances
|
||||
echo ""
|
||||
echo "📊 Final balances:"
|
||||
WETH_BALANCE=$(docker-compose exec -T anvil cast call $WETH \
|
||||
"balanceOf(address)(uint256)" \
|
||||
$TO \
|
||||
--rpc-url http://localhost:8545)
|
||||
echo -e " WETH: $WETH_BALANCE"
|
||||
|
||||
USDC_BALANCE=$(docker-compose exec -T anvil cast call $USDC \
|
||||
"balanceOf(address)(uint256)" \
|
||||
$TO \
|
||||
--rpc-url http://localhost:8545)
|
||||
echo -e " USDC: $USDC_BALANCE"
|
||||
|
||||
echo ""
|
||||
echo -e "${GREEN}✨ Test swap complete!${NC}"
|
||||
echo ""
|
||||
echo "Check the MEV bot logs to see if it detected the opportunity:"
|
||||
echo " docker-compose logs -f mev-bot"
|
||||
86
scripts/setup-local-fork.sh
Executable file
86
scripts/setup-local-fork.sh
Executable file
@@ -0,0 +1,86 @@
|
||||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
# MEV Bot V2 - Local Fork Setup Script
|
||||
# This script sets up the Anvil fork with test liquidity and scenarios
|
||||
|
||||
echo "🚀 Setting up MEV Bot V2 local testing environment..."
|
||||
|
||||
# Colors for output
|
||||
GREEN='\033[0;32m'
|
||||
YELLOW='\033[1;33m'
|
||||
RED='\033[0;31m'
|
||||
NC='\033[0m' # No Color
|
||||
|
||||
# Check if .env exists
|
||||
if [ ! -f .env ]; then
|
||||
echo -e "${YELLOW}⚠️ No .env file found. Copying from .env.example...${NC}"
|
||||
cp .env.example .env
|
||||
echo -e "${RED}⚠️ IMPORTANT: Edit .env and set your PRIVATE_KEY before continuing!${NC}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Load environment variables
|
||||
source .env
|
||||
|
||||
# Check if private key is set
|
||||
if [ "$PRIVATE_KEY" == "0000000000000000000000000000000000000000000000000000000000000000" ]; then
|
||||
echo -e "${RED}❌ Error: PRIVATE_KEY not set in .env file${NC}"
|
||||
echo -e "${YELLOW}Please set a test private key in .env${NC}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo -e "${GREEN}✅ Configuration loaded${NC}"
|
||||
|
||||
# Start Anvil fork
|
||||
echo "🔧 Starting Anvil fork of Arbitrum..."
|
||||
docker-compose up -d anvil
|
||||
|
||||
# Wait for Anvil to be ready
|
||||
echo "⏳ Waiting for Anvil to be ready..."
|
||||
max_attempts=30
|
||||
attempt=0
|
||||
while [ $attempt -lt $max_attempts ]; do
|
||||
if docker-compose exec -T anvil cast block-number --rpc-url http://localhost:8545 &>/dev/null; then
|
||||
echo -e "${GREEN}✅ Anvil is ready${NC}"
|
||||
break
|
||||
fi
|
||||
attempt=$((attempt + 1))
|
||||
sleep 2
|
||||
done
|
||||
|
||||
if [ $attempt -eq $max_attempts ]; then
|
||||
echo -e "${RED}❌ Anvil failed to start${NC}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Get current block number
|
||||
BLOCK_NUMBER=$(docker-compose exec -T anvil cast block-number --rpc-url http://localhost:8545)
|
||||
echo -e "${GREEN}📦 Forked at block: $BLOCK_NUMBER${NC}"
|
||||
|
||||
# Get wallet address from private key
|
||||
WALLET_ADDRESS=$(docker-compose exec -T anvil cast wallet address $PRIVATE_KEY)
|
||||
echo -e "${GREEN}💼 Wallet address: $WALLET_ADDRESS${NC}"
|
||||
|
||||
# Fund the wallet with test ETH
|
||||
echo "💰 Funding wallet with 100 test ETH..."
|
||||
docker-compose exec -T anvil cast send --value 100ether --private-key 0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80 $WALLET_ADDRESS --rpc-url http://localhost:8545
|
||||
|
||||
# Get wallet balance
|
||||
BALANCE=$(docker-compose exec -T anvil cast balance $WALLET_ADDRESS --rpc-url http://localhost:8545)
|
||||
echo -e "${GREEN}💵 Wallet balance: $(echo "scale=4; $BALANCE / 1000000000000000000" | bc) ETH${NC}"
|
||||
|
||||
echo ""
|
||||
echo -e "${GREEN}✨ Local fork setup complete!${NC}"
|
||||
echo ""
|
||||
echo "Next steps:"
|
||||
echo " 1. Start the full stack: docker-compose up -d"
|
||||
echo " 2. View logs: docker-compose logs -f mev-bot"
|
||||
echo " 3. View metrics: http://localhost:9090"
|
||||
echo " 4. View Grafana: http://localhost:3000 (admin/admin)"
|
||||
echo ""
|
||||
echo "Testing commands:"
|
||||
echo " - Check Anvil: docker-compose exec anvil cast block-number --rpc-url http://localhost:8545"
|
||||
echo " - Get balance: docker-compose exec anvil cast balance $WALLET_ADDRESS --rpc-url http://localhost:8545"
|
||||
echo " - Create test swap: ./scripts/create-test-swap.sh"
|
||||
echo ""
|
||||
Reference in New Issue
Block a user