Completed clean root directory structure: - Root now contains only: .git, .env, docs/, orig/ - Moved all remaining files and directories to orig/: - Config files (.claude, .dockerignore, .drone.yml, etc.) - All .env variants (except active .env) - Git config (.gitconfig, .github, .gitignore, etc.) - Tool configs (.golangci.yml, .revive.toml, etc.) - Documentation (*.md files, @prompts) - Build files (Dockerfiles, Makefile, go.mod, go.sum) - Docker compose files - All source directories (scripts, tests, tools, etc.) - Runtime directories (logs, monitoring, reports) - Dependency files (node_modules, lib, cache) - Special files (--delete) - Removed empty runtime directories (bin/, data/) V2 structure is now clean: - docs/planning/ - V2 planning documents - orig/ - Complete V1 codebase preserved - .env - Active environment config (not in git) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
397 lines
18 KiB
Bash
Executable File
397 lines
18 KiB
Bash
Executable File
#!/bin/bash
|
|
# Enhanced Live MEV Bot Activity Monitor
|
|
# Comprehensive monitoring with error tracking, health metrics, and statistics
|
|
|
|
# Color codes
|
|
GREEN='\033[0;32m'
|
|
RED='\033[0;31m'
|
|
YELLOW='\033[1;33m'
|
|
BLUE='\033[0;34m'
|
|
CYAN='\033[0;36m'
|
|
PURPLE='\033[0;35m'
|
|
BOLD='\033[1m'
|
|
NC='\033[0m'
|
|
|
|
# Configuration
|
|
LOG_FILE="${1:-logs/mev_bot.log}"
|
|
UPDATE_INTERVAL=10 # Stats update interval in opportunities
|
|
ALERT_ERROR_THRESHOLD=50 # Alert when errors exceed this
|
|
|
|
# Check if log file exists
|
|
if [[ ! -f "$LOG_FILE" ]]; then
|
|
echo -e "${RED}Error: Log file not found: $LOG_FILE${NC}"
|
|
echo "Usage: $0 [log-file]"
|
|
echo "Example: $0 logs/mev_bot.log"
|
|
exit 1
|
|
fi
|
|
|
|
# Initialize counters
|
|
declare -A STATS=(
|
|
# Opportunities
|
|
["opportunities_total"]=0
|
|
["opportunities_executable"]=0
|
|
["opportunities_rejected"]=0
|
|
|
|
# Executions
|
|
["executions_attempted"]=0
|
|
["executions_successful"]=0
|
|
["executions_failed"]=0
|
|
["flash_loans_initiated"]=0
|
|
["transactions_submitted"]=0
|
|
|
|
# Errors
|
|
["errors_total"]=0
|
|
["errors_parsing"]=0
|
|
["errors_rpc"]=0
|
|
["errors_validation"]=0
|
|
["errors_zero_address"]=0
|
|
["errors_timeout"]=0
|
|
["errors_connection"]=0
|
|
["errors_rate_limit"]=0
|
|
|
|
# Processing
|
|
["blocks_processed"]=0
|
|
["transactions_analyzed"]=0
|
|
["swap_events_detected"]=0
|
|
["dex_transactions"]=0
|
|
|
|
# Performance
|
|
["gas_estimations"]=0
|
|
["pool_queries"]=0
|
|
["price_checks"]=0
|
|
)
|
|
|
|
# Track recent activity for rate calculations
|
|
declare -a RECENT_OPPORTUNITIES=()
|
|
declare -a RECENT_ERRORS=()
|
|
START_TIME=$(date +%s)
|
|
LAST_ACTIVITY=$(date +%s)
|
|
|
|
# Function to calculate rates
|
|
calculate_rate() {
|
|
local count=$1
|
|
local elapsed=$(($(date +%s) - START_TIME))
|
|
if [[ $elapsed -gt 0 ]]; then
|
|
echo "scale=2; $count / $elapsed * 60" | bc -l
|
|
else
|
|
echo "0"
|
|
fi
|
|
}
|
|
|
|
# Function to calculate percentage
|
|
calculate_percentage() {
|
|
local part=$1
|
|
local total=$2
|
|
if [[ $total -gt 0 ]]; then
|
|
echo "scale=1; $part * 100 / $total" | bc -l
|
|
else
|
|
echo "0"
|
|
fi
|
|
}
|
|
|
|
# Function to get health status
|
|
get_health_status() {
|
|
local error_rate=$(calculate_percentage ${STATS["errors_total"]} $((${STATS["opportunities_total"]} + ${STATS["errors_total"]})))
|
|
local error_rate_int=${error_rate%.*}
|
|
|
|
if [[ $error_rate_int -lt 5 ]]; then
|
|
echo -e "${GREEN}EXCELLENT${NC}"
|
|
elif [[ $error_rate_int -lt 15 ]]; then
|
|
echo -e "${YELLOW}GOOD${NC}"
|
|
elif [[ $error_rate_int -lt 30 ]]; then
|
|
echo -e "${YELLOW}DEGRADED${NC}"
|
|
else
|
|
echo -e "${RED}CRITICAL${NC}"
|
|
fi
|
|
}
|
|
|
|
# Function to display header
|
|
display_header() {
|
|
clear
|
|
echo -e "${BOLD}${PURPLE}════════════════════════════════════════════════════════════════════════${NC}"
|
|
echo -e "${BOLD}${PURPLE} 🤖 MEV Bot Enhanced Live Activity Monitor${NC}"
|
|
echo -e "${BOLD}${PURPLE}════════════════════════════════════════════════════════════════════════${NC}"
|
|
echo ""
|
|
echo -e "${CYAN}📊 Log File:${NC} $LOG_FILE"
|
|
echo -e "${CYAN}💼 Bot Wallet:${NC} 0x40091653f652a259747D86d7Cbe3e2848082a051"
|
|
echo -e "${CYAN}🌐 Network:${NC} Arbitrum One"
|
|
echo -e "${CYAN}⏱️ Started:${NC} $(date)"
|
|
echo ""
|
|
echo -e "${BOLD}Monitoring:${NC}"
|
|
echo -e " ${GREEN}✅${NC} Opportunities (executable & rejected)"
|
|
echo -e " ${BLUE}⚡${NC} Executions (flash loans, transactions, confirmations)"
|
|
echo -e " ${RED}❌${NC} Errors (parsing, RPC, validation, timeouts)"
|
|
echo -e " ${CYAN}📈${NC} Performance (blocks, transactions, events)"
|
|
echo -e " ${PURPLE}💊${NC} Health (success rate, error rate, uptime)"
|
|
echo ""
|
|
echo -e "${YELLOW}Press Ctrl+C to stop${NC}"
|
|
echo -e "${PURPLE}════════════════════════════════════════════════════════════════════════${NC}"
|
|
echo ""
|
|
}
|
|
|
|
# Function to display comprehensive stats
|
|
display_stats() {
|
|
local elapsed=$(($(date +%s) - START_TIME))
|
|
local hours=$((elapsed / 3600))
|
|
local minutes=$(((elapsed % 3600) / 60))
|
|
local seconds=$((elapsed % 60))
|
|
|
|
local opp_rate=$(calculate_rate ${STATS["opportunities_total"]})
|
|
local exec_rate=$(calculate_rate ${STATS["executions_attempted"]})
|
|
local error_rate_pct=$(calculate_percentage ${STATS["errors_total"]} $((${STATS["opportunities_total"]} + ${STATS["errors_total"]})))
|
|
local executable_pct=$(calculate_percentage ${STATS["opportunities_executable"]} ${STATS["opportunities_total"]})
|
|
local success_pct=$(calculate_percentage ${STATS["executions_successful"]} ${STATS["executions_attempted"]})
|
|
|
|
echo -e "${BOLD}${CYAN}╔════════════════════════════════════════════════════════════════════════╗${NC}"
|
|
echo -e "${BOLD}${CYAN}║ 📊 LIVE STATISTICS ║${NC}"
|
|
echo -e "${BOLD}${CYAN}╠════════════════════════════════════════════════════════════════════════╣${NC}"
|
|
|
|
# Opportunities section
|
|
echo -e "${CYAN}║${NC} ${BOLD}🎯 OPPORTUNITIES${NC} ${CYAN}║${NC}"
|
|
echo -e "${CYAN}║${NC} Total: ${GREEN}${STATS["opportunities_total"]}${NC} (${opp_rate}/min) ${CYAN}║${NC}"
|
|
echo -e "${CYAN}║${NC} Executable: ${GREEN}${STATS["opportunities_executable"]}${NC} (${executable_pct}%) ${CYAN}║${NC}"
|
|
echo -e "${CYAN}║${NC} Rejected: ${YELLOW}${STATS["opportunities_rejected"]}${NC} ${CYAN}║${NC}"
|
|
echo -e "${CYAN}╠════════════════════════════════════════════════════════════════════════╣${NC}"
|
|
|
|
# Executions section
|
|
echo -e "${CYAN}║${NC} ${BOLD}⚡ EXECUTIONS${NC} ${CYAN}║${NC}"
|
|
echo -e "${CYAN}║${NC} Attempted: ${BLUE}${STATS["executions_attempted"]}${NC} (${exec_rate}/min) ${CYAN}║${NC}"
|
|
echo -e "${CYAN}║${NC} Successful: ${GREEN}${STATS["executions_successful"]}${NC} (${success_pct}%) ${CYAN}║${NC}"
|
|
echo -e "${CYAN}║${NC} Failed: ${RED}${STATS["executions_failed"]}${NC} ${CYAN}║${NC}"
|
|
echo -e "${CYAN}║${NC} Flash Loans: ${PURPLE}${STATS["flash_loans_initiated"]}${NC} ${CYAN}║${NC}"
|
|
echo -e "${CYAN}║${NC} Tx Submitted:${BLUE}${STATS["transactions_submitted"]}${NC} ${CYAN}║${NC}"
|
|
echo -e "${CYAN}╠════════════════════════════════════════════════════════════════════════╣${NC}"
|
|
|
|
# Errors section
|
|
local error_color=$RED
|
|
if [[ ${STATS["errors_total"]} -lt 10 ]]; then
|
|
error_color=$GREEN
|
|
elif [[ ${STATS["errors_total"]} -lt 50 ]]; then
|
|
error_color=$YELLOW
|
|
fi
|
|
|
|
echo -e "${CYAN}║${NC} ${BOLD}❌ ERRORS${NC} ${CYAN}║${NC}"
|
|
echo -e "${CYAN}║${NC} Total: ${error_color}${STATS["errors_total"]}${NC} (${error_rate_pct}% error rate) ${CYAN}║${NC}"
|
|
echo -e "${CYAN}║${NC} Parsing: ${RED}${STATS["errors_parsing"]}${NC} ${CYAN}║${NC}"
|
|
echo -e "${CYAN}║${NC} RPC: ${RED}${STATS["errors_rpc"]}${NC} ${CYAN}║${NC}"
|
|
echo -e "${CYAN}║${NC} Validation: ${RED}${STATS["errors_validation"]}${NC} ${CYAN}║${NC}"
|
|
echo -e "${CYAN}║${NC} Zero Addr: ${RED}${STATS["errors_zero_address"]}${NC} ${CYAN}║${NC}"
|
|
echo -e "${CYAN}║${NC} Timeout: ${RED}${STATS["errors_timeout"]}${NC} ${CYAN}║${NC}"
|
|
echo -e "${CYAN}║${NC} Connection: ${RED}${STATS["errors_connection"]}${NC} ${CYAN}║${NC}"
|
|
echo -e "${CYAN}║${NC} Rate Limit: ${RED}${STATS["errors_rate_limit"]}${NC} ${CYAN}║${NC}"
|
|
echo -e "${CYAN}╠════════════════════════════════════════════════════════════════════════╣${NC}"
|
|
|
|
# Processing section
|
|
echo -e "${CYAN}║${NC} ${BOLD}📈 PROCESSING${NC} ${CYAN}║${NC}"
|
|
echo -e "${CYAN}║${NC} Blocks: ${BLUE}${STATS["blocks_processed"]}${NC} ${CYAN}║${NC}"
|
|
echo -e "${CYAN}║${NC} Transactions:${BLUE}${STATS["transactions_analyzed"]}${NC} ${CYAN}║${NC}"
|
|
echo -e "${CYAN}║${NC} Swap Events: ${CYAN}${STATS["swap_events_detected"]}${NC} ${CYAN}║${NC}"
|
|
echo -e "${CYAN}║${NC} DEX Txs: ${CYAN}${STATS["dex_transactions"]}${NC} ${CYAN}║${NC}"
|
|
echo -e "${CYAN}╠════════════════════════════════════════════════════════════════════════╣${NC}"
|
|
|
|
# Health section
|
|
local health_status=$(get_health_status)
|
|
echo -e "${CYAN}║${NC} ${BOLD}💊 HEALTH${NC} ${CYAN}║${NC}"
|
|
echo -e "${CYAN}║${NC} Status: $health_status ${CYAN}║${NC}"
|
|
echo -e "${CYAN}║${NC} Uptime: ${GREEN}${hours}h ${minutes}m ${seconds}s${NC} ${CYAN}║${NC}"
|
|
echo -e "${CYAN}║${NC} Success Rate:${GREEN}${success_pct}%${NC} ${CYAN}║${NC}"
|
|
echo -e "${CYAN}║${NC} Error Rate: ${error_color}${error_rate_pct}%${NC} ${CYAN}║${NC}"
|
|
echo -e "${CYAN}╚════════════════════════════════════════════════════════════════════════╝${NC}"
|
|
echo ""
|
|
}
|
|
|
|
# Function to handle opportunity detection
|
|
handle_opportunity() {
|
|
local line="$1"
|
|
local timestamp=$(echo "$line" | awk '{print $1, $2}')
|
|
|
|
((STATS["opportunities_total"]++))
|
|
RECENT_OPPORTUNITIES+=("$(date +%s)")
|
|
|
|
if echo "$line" | grep -q "isExecutable:true"; then
|
|
((STATS["opportunities_executable"]++))
|
|
echo -e "${GREEN}[$(date +'%H:%M:%S')] ✅ EXECUTABLE OPPORTUNITY #${STATS["opportunities_executable"]}${NC}"
|
|
|
|
# Extract profit
|
|
if echo "$line" | grep -oP 'netProfitETH:[0-9.]+' &>/dev/null; then
|
|
PROFIT=$(echo "$line" | grep -oP 'netProfitETH:[0-9.]+' | cut -d: -f2)
|
|
echo -e "${GREEN} 💰 Net Profit: $PROFIT ETH${NC}"
|
|
fi
|
|
|
|
# Extract path
|
|
if echo "$line" | grep -oP 'tokenIn:\w+' &>/dev/null; then
|
|
TOKEN_IN=$(echo "$line" | grep -oP 'tokenIn:\w+' | cut -d: -f2)
|
|
TOKEN_OUT=$(echo "$line" | grep -oP 'tokenOut:\w+' | cut -d: -f2)
|
|
echo -e "${CYAN} 🔄 Path: $TOKEN_IN → $TOKEN_OUT${NC}"
|
|
fi
|
|
|
|
# Extract DEX info
|
|
if echo "$line" | grep -oP 'dex:\w+' &>/dev/null; then
|
|
DEX=$(echo "$line" | grep -oP 'dex:\w+' | cut -d: -f2)
|
|
echo -e "${BLUE} 🏦 DEX: $DEX${NC}"
|
|
fi
|
|
else
|
|
((STATS["opportunities_rejected"]++))
|
|
echo -e "${YELLOW}[$(date +'%H:%M:%S')] 🎯 Opportunity #${STATS["opportunities_total"]} (rejected)${NC}"
|
|
|
|
# Extract reject reason
|
|
if echo "$line" | grep -oP 'rejectReason:[^]]+' &>/dev/null; then
|
|
REASON=$(echo "$line" | grep -oP 'rejectReason:[^]]+' | cut -d: -f2 | head -c 70)
|
|
echo -e "${RED} ❌ Reason: $REASON${NC}"
|
|
fi
|
|
fi
|
|
}
|
|
|
|
# Function to handle execution events
|
|
handle_execution() {
|
|
local line="$1"
|
|
|
|
if echo "$line" | grep -q "Flash loan initiated"; then
|
|
((STATS["flash_loans_initiated"]++))
|
|
((STATS["executions_attempted"]++))
|
|
echo -e "${PURPLE}[$(date +'%H:%M:%S')] ⚡ FLASH LOAN INITIATED #${STATS["flash_loans_initiated"]}${NC}"
|
|
|
|
elif echo "$line" | grep -q "Transaction submitted"; then
|
|
((STATS["transactions_submitted"]++))
|
|
TXHASH=$(echo "$line" | grep -oP '0x[a-fA-F0-9]{64}' | head -1)
|
|
echo -e "${GREEN}[$(date +'%H:%M:%S')] 🚀 TRANSACTION SUBMITTED${NC}"
|
|
echo -e "${GREEN} 📝 TxHash: $TXHASH${NC}"
|
|
echo -e "${GREEN} 🔗 Arbiscan: https://arbiscan.io/tx/$TXHASH${NC}"
|
|
|
|
elif echo "$line" | grep -q "Trade confirmed\|execution successful"; then
|
|
((STATS["executions_successful"]++))
|
|
echo -e "${GREEN}[$(date +'%H:%M:%S')] ✅ TRADE CONFIRMED!${NC}"
|
|
|
|
if echo "$line" | grep -oP 'Profit:.*ETH' &>/dev/null; then
|
|
PROFIT=$(echo "$line" | grep -oP 'Profit:.*ETH')
|
|
echo -e "${GREEN} 💰 $PROFIT${NC}"
|
|
fi
|
|
|
|
elif echo "$line" | grep -q "execution failed\|Trade failed"; then
|
|
((STATS["executions_failed"]++))
|
|
echo -e "${RED}[$(date +'%H:%M:%S')] ❌ EXECUTION FAILED${NC}"
|
|
|
|
if echo "$line" | grep -oP 'error:.*' &>/dev/null; then
|
|
ERROR=$(echo "$line" | grep -oP 'error:.*' | head -c 70)
|
|
echo -e "${RED} ⚠️ $ERROR${NC}"
|
|
fi
|
|
|
|
elif echo "$line" | grep -q "Executing arbitrage"; then
|
|
((STATS["executions_attempted"]++))
|
|
echo -e "${BLUE}[$(date +'%H:%M:%S')] ⚡ EXECUTING ARBITRAGE #${STATS["executions_attempted"]}${NC}"
|
|
fi
|
|
}
|
|
|
|
# Function to handle errors
|
|
handle_error() {
|
|
local line="$1"
|
|
|
|
((STATS["errors_total"]++))
|
|
RECENT_ERRORS+=("$(date +%s)")
|
|
|
|
local error_type="GENERAL"
|
|
|
|
if echo "$line" | grep -qi "parsing.*failed\|PARSING FAILED\|failed to parse"; then
|
|
((STATS["errors_parsing"]++))
|
|
error_type="PARSING"
|
|
elif echo "$line" | grep -qi "rpc.*error\|rpc.*failed\|connection refused"; then
|
|
((STATS["errors_rpc"]++))
|
|
error_type="RPC"
|
|
elif echo "$line" | grep -qi "validation.*failed\|invalid.*input"; then
|
|
((STATS["errors_validation"]++))
|
|
error_type="VALIDATION"
|
|
elif echo "$line" | grep -qi "0x0000000000000000000000000000000000000000\|zero.*address"; then
|
|
((STATS["errors_zero_address"]++))
|
|
error_type="ZERO_ADDRESS"
|
|
elif echo "$line" | grep -qi "timeout\|deadline exceeded"; then
|
|
((STATS["errors_timeout"]++))
|
|
error_type="TIMEOUT"
|
|
elif echo "$line" | grep -qi "connection.*failed\|connection.*lost\|context.*canceled"; then
|
|
((STATS["errors_connection"]++))
|
|
error_type="CONNECTION"
|
|
elif echo "$line" | grep -qi "rate.*limit\|too many requests\|429"; then
|
|
((STATS["errors_rate_limit"]++))
|
|
error_type="RATE_LIMIT"
|
|
fi
|
|
|
|
echo -e "${RED}[$(date +'%H:%M:%S')] ❌ ERROR ($error_type) #${STATS["errors_total"]}${NC}"
|
|
|
|
# Extract error message
|
|
local error_msg=$(echo "$line" | grep -oP 'error[=:].*' | head -c 100)
|
|
if [[ -n "$error_msg" ]]; then
|
|
echo -e "${RED} ⚠️ $error_msg${NC}"
|
|
fi
|
|
|
|
# Alert on high error count
|
|
if [[ ${STATS["errors_total"]} -gt $ALERT_ERROR_THRESHOLD ]] && [[ $((${STATS["errors_total"]} % 10)) -eq 0 ]]; then
|
|
echo -e "${RED}${BOLD} 🚨 ALERT: Error count exceeds threshold ($ALERT_ERROR_THRESHOLD)${NC}"
|
|
fi
|
|
}
|
|
|
|
# Function to handle processing events
|
|
handle_processing() {
|
|
local line="$1"
|
|
|
|
if echo "$line" | grep -qi "Block.*Processing.*transactions\|Processing block"; then
|
|
((STATS["blocks_processed"]++))
|
|
|
|
# Extract block number
|
|
if echo "$line" | grep -oP 'block[=: ]+\d+' &>/dev/null; then
|
|
BLOCK=$(echo "$line" | grep -oP '\d+' | head -1)
|
|
echo -e "${BLUE}[$(date +'%H:%M:%S')] 📦 Block #$BLOCK processed${NC}"
|
|
fi
|
|
|
|
elif echo "$line" | grep -qi "DEX transactions\|Found.*DEX"; then
|
|
((STATS["dex_transactions"]++))
|
|
|
|
elif echo "$line" | grep -qi "swap.*event\|Swap detected"; then
|
|
((STATS["swap_events_detected"]++))
|
|
|
|
elif echo "$line" | grep -qi "Analyzing transaction"; then
|
|
((STATS["transactions_analyzed"]++))
|
|
fi
|
|
}
|
|
|
|
# Main monitoring loop
|
|
main() {
|
|
display_header
|
|
|
|
local line_count=0
|
|
local last_stats_update=0
|
|
|
|
tail -f "$LOG_FILE" | while IFS= read -r line; do
|
|
((line_count++))
|
|
LAST_ACTIVITY=$(date +%s)
|
|
|
|
# Handle different event types
|
|
if echo "$line" | grep -qi "OPPORTUNITY DETECTED"; then
|
|
handle_opportunity "$line"
|
|
echo ""
|
|
|
|
elif echo "$line" | grep -qi "ERROR\|WARN\|failed"; then
|
|
handle_error "$line"
|
|
echo ""
|
|
|
|
elif echo "$line" | grep -qi "Flash loan\|Transaction submitted\|Trade confirmed\|execution\|Executing arbitrage"; then
|
|
handle_execution "$line"
|
|
echo ""
|
|
|
|
elif echo "$line" | grep -qi "Block\|Processing\|DEX\|swap.*event"; then
|
|
handle_processing "$line"
|
|
fi
|
|
|
|
# Update stats display periodically (only when count actually changes)
|
|
local current_count=${STATS["opportunities_total"]}
|
|
if [[ $((current_count % UPDATE_INTERVAL)) -eq 0 ]] && [[ $current_count -gt 0 ]] && [[ $current_count -ne $last_stats_update ]]; then
|
|
last_stats_update=$current_count
|
|
display_stats
|
|
fi
|
|
done
|
|
}
|
|
|
|
# Trap Ctrl+C for clean exit
|
|
trap 'echo -e "\n${YELLOW}Monitoring stopped.${NC}"; display_stats; exit 0' SIGINT SIGTERM
|
|
|
|
# Run main monitoring
|
|
main
|