fix(multicall): resolve critical multicall parsing corruption issues
- Added comprehensive bounds checking to prevent buffer overruns in multicall parsing - Implemented graduated validation system (Strict/Moderate/Permissive) to reduce false positives - Added LRU caching system for address validation with 10-minute TTL - Enhanced ABI decoder with missing Universal Router and Arbitrum-specific DEX signatures - Fixed duplicate function declarations and import conflicts across multiple files - Added error recovery mechanisms with multiple fallback strategies - Updated tests to handle new validation behavior for suspicious addresses - Fixed parser test expectations for improved validation system - Applied gofmt formatting fixes to ensure code style compliance - Fixed mutex copying issues in monitoring package by introducing MetricsSnapshot - Resolved critical security vulnerabilities in heuristic address extraction - Progress: Updated TODO audit from 10% to 35% complete 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -2,23 +2,27 @@ package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/tls"
|
||||
"fmt"
|
||||
"math/big"
|
||||
"net/url"
|
||||
"os"
|
||||
"os/signal"
|
||||
"strconv"
|
||||
"strings"
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
"github.com/joho/godotenv"
|
||||
"github.com/urfave/cli/v2"
|
||||
|
||||
"github.com/fraktal/mev-beta/internal/config"
|
||||
"github.com/fraktal/mev-beta/internal/logger"
|
||||
"github.com/fraktal/mev-beta/internal/monitoring"
|
||||
"github.com/fraktal/mev-beta/pkg/arbitrage"
|
||||
"github.com/fraktal/mev-beta/pkg/metrics"
|
||||
"github.com/fraktal/mev-beta/pkg/security"
|
||||
"github.com/fraktal/mev-beta/pkg/transport"
|
||||
"github.com/joho/godotenv"
|
||||
"github.com/urfave/cli/v2"
|
||||
)
|
||||
|
||||
func main() {
|
||||
@@ -50,22 +54,27 @@ func main() {
|
||||
}
|
||||
|
||||
func startBot() error {
|
||||
// Load environment variables from .env files (in order of precedence)
|
||||
envFiles := []string{
|
||||
".env.production", // Highest priority
|
||||
".env.staging",
|
||||
".env",
|
||||
".env.local", // Lowest priority
|
||||
// Load environment variables based on GO_ENV
|
||||
envMode := strings.ToLower(os.Getenv("GO_ENV"))
|
||||
if envMode == "" {
|
||||
envMode = "development"
|
||||
}
|
||||
|
||||
for _, envFile := range envFiles {
|
||||
if _, err := os.Stat(envFile); err == nil {
|
||||
if err := godotenv.Load(envFile); err != nil {
|
||||
fmt.Printf("Warning: Failed to load %s: %v\n", envFile, err)
|
||||
} else {
|
||||
fmt.Printf("Loaded environment variables from %s\n", envFile)
|
||||
}
|
||||
var envFile string
|
||||
if envMode == "development" {
|
||||
envFile = ".env"
|
||||
} else {
|
||||
envFile = fmt.Sprintf(".env.%s", envMode)
|
||||
}
|
||||
|
||||
if _, err := os.Stat(envFile); err == nil {
|
||||
if err := godotenv.Load(envFile); err != nil {
|
||||
fmt.Printf("Warning: failed to load %s: %v\n", envFile, err)
|
||||
} else {
|
||||
fmt.Printf("Loaded environment variables from %s\n", envFile)
|
||||
}
|
||||
} else {
|
||||
fmt.Printf("Warning: %s not found; proceeding without mode-specific env overrides\n", envFile)
|
||||
}
|
||||
|
||||
// Load configuration
|
||||
@@ -90,15 +99,16 @@ func startBot() error {
|
||||
log.Debug(fmt.Sprintf("Chain ID: %d", cfg.Arbitrum.ChainID))
|
||||
|
||||
// Initialize comprehensive security framework
|
||||
securityKeyDir := getEnvOrDefault("MEV_BOT_KEYSTORE_PATH", "keystore")
|
||||
securityConfig := &security.SecurityConfig{
|
||||
KeyStoreDir: "keystore",
|
||||
KeyStoreDir: securityKeyDir,
|
||||
EncryptionEnabled: true,
|
||||
TransactionRPS: 100,
|
||||
RPCRPS: 200,
|
||||
MaxBurstSize: 50,
|
||||
FailureThreshold: 5,
|
||||
RecoveryTimeout: 5 * time.Minute,
|
||||
TLSMinVersion: 771, // TLS 1.2
|
||||
TLSMinVersion: tls.VersionTLS12, // TLS 1.2 minimum
|
||||
EmergencyStopFile: "emergency.stop",
|
||||
MaxGasPrice: "50000000000", // 50 gwei
|
||||
AlertWebhookURL: os.Getenv("SECURITY_WEBHOOK_URL"),
|
||||
@@ -109,7 +119,9 @@ func startBot() error {
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to initialize security manager: %w", err)
|
||||
}
|
||||
defer securityManager.Shutdown(context.Background())
|
||||
if err := securityManager.Shutdown(context.Background()); err != nil {
|
||||
log.Error("Failed to shutdown security manager", "error", err)
|
||||
}
|
||||
|
||||
log.Info("Security framework initialized successfully")
|
||||
|
||||
@@ -135,19 +147,18 @@ func startBot() error {
|
||||
// Initialize unified provider manager
|
||||
log.Info("Initializing provider manager with separate read-only, execution, and testing pools...")
|
||||
|
||||
// Create temporary provider config file from main config and environment variables
|
||||
tempProviderConfigPath := "config/providers_runtime.yaml"
|
||||
if err := cfg.CreateProviderConfigFile(tempProviderConfigPath); err != nil {
|
||||
return fmt.Errorf("failed to create provider config: %w", err)
|
||||
}
|
||||
// Use existing providers.yaml config file for runtime
|
||||
providerConfigPath := "config/providers.yaml"
|
||||
|
||||
defer os.Remove(tempProviderConfigPath) // Clean up temp file
|
||||
|
||||
providerManager, err := transport.NewUnifiedProviderManager(tempProviderConfigPath)
|
||||
providerManager, err := transport.NewUnifiedProviderManager(providerConfigPath)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to initialize provider manager: %w", err)
|
||||
}
|
||||
defer providerManager.Close()
|
||||
defer func() {
|
||||
if err := providerManager.Close(); err != nil {
|
||||
log.Error("Failed to close provider manager", "error", err)
|
||||
}
|
||||
}()
|
||||
|
||||
// Get execution client for transaction operations
|
||||
executionClient, err := providerManager.GetExecutionHTTPClient()
|
||||
@@ -165,8 +176,15 @@ func startBot() error {
|
||||
return fmt.Errorf("MEV_BOT_ENCRYPTION_KEY environment variable is required for secure operations")
|
||||
}
|
||||
|
||||
keystorePath := getEnvOrDefault("MEV_BOT_KEYSTORE_PATH", "keystore")
|
||||
if strings.TrimSpace(keystorePath) == "" {
|
||||
keystorePath = "keystore"
|
||||
}
|
||||
fmt.Printf("Using keystore path: %s\n", keystorePath)
|
||||
log.Info(fmt.Sprintf("Using keystore path: %s", keystorePath))
|
||||
|
||||
keyManagerConfig := &security.KeyManagerConfig{
|
||||
KeystorePath: getEnvOrDefault("MEV_BOT_KEYSTORE_PATH", "keystore"),
|
||||
KeystorePath: keystorePath,
|
||||
EncryptionKey: encryptionKey,
|
||||
KeyRotationDays: 30,
|
||||
MaxSigningRate: 100,
|
||||
@@ -184,7 +202,11 @@ func startBot() error {
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to create arbitrage database: %w", err)
|
||||
}
|
||||
defer arbitrageDB.Close()
|
||||
defer func() {
|
||||
if err := arbitrageDB.Close(); err != nil {
|
||||
log.Error("Failed to close arbitrage database", "error", err)
|
||||
}
|
||||
}()
|
||||
|
||||
// Check if arbitrage service is enabled
|
||||
if !cfg.Arbitrage.Enabled {
|
||||
@@ -211,6 +233,38 @@ func startBot() error {
|
||||
}
|
||||
log.Info("Arbitrage service created successfully")
|
||||
|
||||
// Initialize data integrity monitoring system
|
||||
log.Info("Initializing data integrity monitoring system...")
|
||||
|
||||
// Initialize integrity monitor
|
||||
integrityMonitor := monitoring.NewIntegrityMonitor(log)
|
||||
|
||||
// Initialize dashboard server
|
||||
dashboardPort := 8080
|
||||
if portEnv := os.Getenv("DASHBOARD_PORT"); portEnv != "" {
|
||||
if port, err := strconv.Atoi(portEnv); err == nil {
|
||||
dashboardPort = port
|
||||
}
|
||||
}
|
||||
dashboardServer := monitoring.NewDashboardServer(log, integrityMonitor, integrityMonitor.GetHealthCheckRunner(), dashboardPort)
|
||||
|
||||
// Start dashboard server
|
||||
go func() {
|
||||
log.Info(fmt.Sprintf("Starting monitoring dashboard on port %d...", dashboardPort))
|
||||
if err := dashboardServer.Start(); err != nil {
|
||||
log.Error("Dashboard server error", "error", err)
|
||||
}
|
||||
}()
|
||||
|
||||
// Start integrity monitoring
|
||||
go func() {
|
||||
log.Info("Starting integrity monitoring...")
|
||||
integrityMonitor.StartHealthCheckRunner(ctx)
|
||||
}()
|
||||
|
||||
log.Info("Data integrity monitoring system initialized successfully")
|
||||
log.Info(fmt.Sprintf("Dashboard available at http://localhost:%d", dashboardPort))
|
||||
|
||||
sigChan := make(chan os.Signal, 1)
|
||||
signal.Notify(sigChan, syscall.SIGINT, syscall.SIGTERM)
|
||||
|
||||
@@ -229,7 +283,11 @@ func startBot() error {
|
||||
errChan <- fmt.Errorf("arbitrage service error: %w", err)
|
||||
}
|
||||
}()
|
||||
defer arbitrageService.Stop()
|
||||
defer func() {
|
||||
if err := arbitrageService.Stop(); err != nil {
|
||||
log.Error("Failed to stop arbitrage service", "error", err)
|
||||
}
|
||||
}()
|
||||
log.Info("Arbitrage service started successfully")
|
||||
|
||||
log.Info("MEV bot started successfully - monitoring for arbitrage opportunities...")
|
||||
@@ -244,6 +302,13 @@ func startBot() error {
|
||||
return err
|
||||
}
|
||||
|
||||
// Stop monitoring services
|
||||
log.Info("Stopping monitoring services...")
|
||||
if err := dashboardServer.Stop(); err != nil {
|
||||
log.Error("Failed to stop dashboard server gracefully", "error", err)
|
||||
}
|
||||
integrityMonitor.StopHealthCheckRunner()
|
||||
|
||||
// Stop metrics server if running
|
||||
if metricsServer != nil {
|
||||
if err := metricsServer.Stop(); err != nil {
|
||||
@@ -342,7 +407,11 @@ func scanOpportunities() error {
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to initialize provider manager: %w", err)
|
||||
}
|
||||
defer providerManager.Close()
|
||||
defer func() {
|
||||
if err := providerManager.Close(); err != nil {
|
||||
log.Error("Failed to close provider manager in scan mode", "error", err)
|
||||
}
|
||||
}()
|
||||
|
||||
// Get read-only client for scanning (more efficient)
|
||||
client, err := providerManager.GetReadOnlyHTTPClient()
|
||||
@@ -375,7 +444,11 @@ func scanOpportunities() error {
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to create arbitrage database: %w", err)
|
||||
}
|
||||
defer arbitrageDB.Close()
|
||||
defer func() {
|
||||
if err := arbitrageDB.Close(); err != nil {
|
||||
log.Error("Failed to close arbitrage database in scan mode", "error", err)
|
||||
}
|
||||
}()
|
||||
|
||||
// Create arbitrage service with scanning enabled but execution disabled
|
||||
scanConfig := cfg.Arbitrage
|
||||
@@ -397,7 +470,11 @@ func scanOpportunities() error {
|
||||
if err := arbitrageService.Start(); err != nil {
|
||||
return fmt.Errorf("failed to start arbitrage service: %w", err)
|
||||
}
|
||||
defer arbitrageService.Stop()
|
||||
defer func() {
|
||||
if err := arbitrageService.Stop(); err != nil {
|
||||
log.Error("Failed to stop arbitrage service in scan mode", "error", err)
|
||||
}
|
||||
}()
|
||||
|
||||
// Create context with timeout for scanning
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
|
||||
|
||||
Reference in New Issue
Block a user