#!/bin/bash # Automated script to: # 1. Monitor live Arbitrum mainnet for swaps # 2. Replay those swaps on Anvil fork # 3. Let MEV Bot detect arbitrage opportunities set -e CAST="/home/administrator/.foundry/bin/cast" ARBITRUM_MAINNET_RPC="https://arb1.arbitrum.io/rpc" ANVIL_RPC="http://localhost:8545" TEST_ACCOUNT="0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266" TEST_PRIVATE_KEY="0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80" SWAPS_LOG="detected_swaps.jsonl" REPLAY_LOG="replayed_swaps.log" # Known swap event signatures UNISWAP_V2_SWAP="0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822" UNISWAP_V3_SWAP="0xc42079f94a6350d7e6235f29174924f928cc2ac818eb64fed8004e115fbcca67" echo "=========================================" echo " MEV Bot V2 - Automatic Swap Tester" echo "=========================================" echo "" echo "Monitoring: Arbitrum Mainnet" echo "Testing on: Anvil Fork (localhost:8545)" echo "Bot Wallet: $TEST_ACCOUNT" echo "" echo "This script will:" echo "1. Monitor recent Arbitrum mainnet blocks" echo "2. Detect swap transactions" echo "3. Replay them on Anvil fork" echo "4. Let MEV Bot detect arbitrage" echo "" echo "Press Ctrl+C to stop" echo "" echo "=========================================" # Initialize logs > "$SWAPS_LOG" > "$REPLAY_LOG" SWAPS_PROCESSED=0 BLOCKS_SCANNED=0 while true; do # Get latest mainnet block MAINNET_BLOCK=$($CAST block-number --rpc-url "$ARBITRUM_MAINNET_RPC" 2>/dev/null || echo "0") if [ "$MAINNET_BLOCK" == "0" ]; then echo "[ERROR] Failed to get mainnet block number, retrying..." sleep 5 continue fi # Get current Anvil block ANVIL_BLOCK=$($CAST block-number --rpc-url "$ANVIL_RPC" 2>/dev/null || echo "0") echo "[$(date +%H:%M:%S)] Mainnet: $MAINNET_BLOCK | Anvil: $ANVIL_BLOCK | Processed: $SWAPS_PROCESSED swaps" # Scan blocks (start from 5 blocks back to ensure finality) SCAN_BLOCK=$((MAINNET_BLOCK - 5)) BLOCK_DATA=$($CAST block $SCAN_BLOCK --json --rpc-url "$ARBITRUM_MAINNET_RPC" 2>/dev/null || echo "{}") # Extract transaction hashes TX_HASHES=$(echo "$BLOCK_DATA" | jq -r '.transactions[]?' 2>/dev/null || echo "") for TX_HASH in $TX_HASHES; do if [ -z "$TX_HASH" ]; then continue fi # Check if already processed if grep -q "$TX_HASH" "$SWAPS_LOG" 2>/dev/null; then continue fi # Get transaction receipt RECEIPT=$($CAST receipt "$TX_HASH" --json --rpc-url "$ARBITRUM_MAINNET_RPC" 2>/dev/null || echo "{}") # Check if this transaction has swap events SWAP_LOGS=$(echo "$RECEIPT" | jq -r ".logs[]? | select(.topics[0]? == \"$UNISWAP_V2_SWAP\" or .topics[0]? == \"$UNISWAP_V3_SWAP\")" 2>/dev/null || echo "") if [ ! -z "$SWAP_LOGS" ]; then # Get pool address POOL_ADDRESS=$(echo "$SWAP_LOGS" | jq -r '.address' | head -1) # Get full transaction TX_DATA=$($CAST tx "$TX_HASH" --json --rpc-url "$ARBITRUM_MAINNET_RPC" 2>/dev/null || echo "{}") TO=$(echo "$TX_DATA" | jq -r '.to // empty') FROM=$(echo "$TX_DATA" | jq -r '.from // empty') VALUE_HEX=$(echo "$TX_DATA" | jq -r '.value // "0x0"') INPUT=$(echo "$TX_DATA" | jq -r '.input // "0x"') GAS_PRICE=$(echo "$TX_DATA" | jq -r '.gasPrice // "0x0"') # Convert VALUE from hex to decimal for Cast (handles 0x0, null, empty) if [ "$VALUE_HEX" == "null" ] || [ -z "$VALUE_HEX" ] || [ "$VALUE_HEX" == "0x0" ] || [ "$VALUE_HEX" == "0x00" ]; then VALUE="0" else # Convert hex to decimal using Cast VALUE=$($CAST --to-base "$VALUE_HEX" 10 2>/dev/null || echo "0") fi if [ -z "$TO" ] || [ "$TO" == "null" ]; then continue # Skip contract creation fi echo "[SWAP DETECTED] Block: $SCAN_BLOCK | TX: ${TX_HASH:0:10}... | Pool: ${POOL_ADDRESS:0:10}..." # Log the swap jq -n \ --arg tx "$TX_HASH" \ --arg block "$SCAN_BLOCK" \ --arg pool "$POOL_ADDRESS" \ --arg to "$TO" \ --arg from "$FROM" \ --arg value "$VALUE_HEX" \ --arg input "$INPUT" \ '{tx: $tx, block: $block, pool: $pool, to: $to, from: $from, value: $value, input: $input}' \ >> "$SWAPS_LOG" # Replay on Anvil fork echo "[REPLAYING] Sending swap to Anvil..." # Impersonate the original sender $CAST rpc anvil_impersonateAccount "$FROM" --rpc-url "$ANVIL_RPC" 2>/dev/null || true # Set balance for gas $CAST rpc anvil_setBalance "$FROM" "0x56BC75E2D63100000" --rpc-url "$ANVIL_RPC" 2>/dev/null || true # 100 ETH # Send the transaction REPLAY_TX=$($CAST send "$TO" \ --from "$FROM" \ --value "$VALUE" \ --gas-limit 500000 \ --rpc-url "$ANVIL_RPC" \ "$INPUT" 2>&1 || echo "FAILED") if echo "$REPLAY_TX" | grep -q "blockHash"; then REPLAY_TX_HASH=$(echo "$REPLAY_TX" | jq -r '.transactionHash // empty' 2>/dev/null || echo "unknown") echo "[SUCCESS] Replayed as: ${REPLAY_TX_HASH:0:10}..." echo "[$(date)] $TX_HASH -> $REPLAY_TX_HASH" >> "$REPLAY_LOG" # Stop impersonating $CAST rpc anvil_stopImpersonatingAccount "$FROM" --rpc-url "$ANVIL_RPC" 2>/dev/null || true SWAPS_PROCESSED=$((SWAPS_PROCESSED + 1)) echo "" echo "=== Swap #$SWAPS_PROCESSED Replayed ===" echo "Original TX: $TX_HASH" echo "Pool: $POOL_ADDRESS" echo "Replayed TX: $REPLAY_TX_HASH" echo "====================================" echo "" # Pause to let the bot process sleep 2 else echo "[FAILED] Could not replay: $REPLAY_TX" $CAST rpc anvil_stopImpersonatingAccount "$FROM" --rpc-url "$ANVIL_RPC" 2>/dev/null || true fi fi done BLOCKS_SCANNED=$((BLOCKS_SCANNED + 1)) # Check every 3 seconds sleep 3 done