removed the fucking vendor files
This commit is contained in:
@@ -3,18 +3,20 @@ package main
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"math/big"
|
||||
"net/url"
|
||||
"os"
|
||||
"os/signal"
|
||||
"strings"
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
"github.com/ethereum/go-ethereum/ethclient"
|
||||
"github.com/fraktal/mev-beta/internal/config"
|
||||
"github.com/fraktal/mev-beta/internal/logger"
|
||||
"github.com/fraktal/mev-beta/internal/ratelimit"
|
||||
"github.com/fraktal/mev-beta/pkg/market"
|
||||
"github.com/fraktal/mev-beta/pkg/arbitrage"
|
||||
"github.com/fraktal/mev-beta/pkg/metrics"
|
||||
"github.com/fraktal/mev-beta/pkg/monitor"
|
||||
"github.com/fraktal/mev-beta/pkg/scanner"
|
||||
"github.com/fraktal/mev-beta/pkg/security"
|
||||
"github.com/urfave/cli/v2"
|
||||
)
|
||||
|
||||
@@ -52,6 +54,10 @@ func startBot() error {
|
||||
if _, err := os.Stat("config/local.yaml"); err == nil {
|
||||
configFile = "config/local.yaml"
|
||||
}
|
||||
if _, err := os.Stat("config/arbitrum_production.yaml"); err == nil {
|
||||
configFile = "config/arbitrum_production.yaml"
|
||||
}
|
||||
|
||||
cfg, err := config.Load(configFile)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to load config: %w", err)
|
||||
@@ -59,12 +65,11 @@ func startBot() error {
|
||||
|
||||
// Initialize logger
|
||||
log := logger.New(cfg.Log.Level, cfg.Log.Format, cfg.Log.File)
|
||||
log.Info(fmt.Sprintf("Starting MEV bot with Arbitrage Service - Config: %s", configFile))
|
||||
log.Debug(fmt.Sprintf("RPC Endpoint: %s", cfg.Arbitrum.RPCEndpoint))
|
||||
log.Debug(fmt.Sprintf("WS Endpoint: %s", cfg.Arbitrum.WSEndpoint))
|
||||
log.Debug(fmt.Sprintf("Chain ID: %d", cfg.Arbitrum.ChainID))
|
||||
|
||||
log.Info("Starting MEV bot with L2 message processing...")
|
||||
|
||||
// Initialize metrics collector
|
||||
metricsCollector := metrics.NewMetricsCollector(log)
|
||||
|
||||
@@ -81,88 +86,150 @@ func startBot() error {
|
||||
log.Error("Metrics server error: ", err)
|
||||
}
|
||||
}()
|
||||
log.Info(fmt.Sprintf("Metrics server started on port %s", metricsPort))
|
||||
}
|
||||
|
||||
// Create rate limiter manager
|
||||
rateLimiter := ratelimit.NewLimiterManager(&cfg.Arbitrum)
|
||||
// Validate and create Ethereum client
|
||||
if err := validateRPCEndpoint(cfg.Arbitrum.RPCEndpoint); err != nil {
|
||||
return fmt.Errorf("invalid RPC endpoint: %w", err)
|
||||
}
|
||||
|
||||
// Create market manager
|
||||
marketMgr := market.NewMarketManager(&cfg.Uniswap, log)
|
||||
client, err := ethclient.Dial(cfg.Arbitrum.RPCEndpoint)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to connect to Ethereum client: %w", err)
|
||||
}
|
||||
defer client.Close()
|
||||
|
||||
// Create market scanner
|
||||
scanner := scanner.NewMarketScanner(&cfg.Bot, log)
|
||||
// Create key manager for secure transaction signing
|
||||
encryptionKey := os.Getenv("MEV_BOT_ENCRYPTION_KEY")
|
||||
if encryptionKey == "" {
|
||||
return fmt.Errorf("MEV_BOT_ENCRYPTION_KEY environment variable is required for secure operations")
|
||||
}
|
||||
|
||||
// Create Arbitrum monitor with concurrency support
|
||||
monitor, err := monitor.NewArbitrumMonitor(
|
||||
&cfg.Arbitrum,
|
||||
&cfg.Bot,
|
||||
keyManagerConfig := &security.KeyManagerConfig{
|
||||
KeystorePath: getEnvOrDefault("MEV_BOT_KEYSTORE_PATH", "keystore"),
|
||||
EncryptionKey: encryptionKey,
|
||||
KeyRotationDays: 30,
|
||||
MaxSigningRate: 100,
|
||||
SessionTimeout: time.Hour,
|
||||
AuditLogPath: getEnvOrDefault("MEV_BOT_AUDIT_LOG", "logs/audit.log"),
|
||||
BackupPath: getEnvOrDefault("MEV_BOT_BACKUP_PATH", "backups"),
|
||||
}
|
||||
keyManager, err := security.NewKeyManager(keyManagerConfig, log)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to create key manager: %w", err)
|
||||
}
|
||||
|
||||
// Create arbitrage database
|
||||
arbitrageDB, err := arbitrage.NewSQLiteDatabase(cfg.Database.File, log)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to create arbitrage database: %w", err)
|
||||
}
|
||||
defer arbitrageDB.Close()
|
||||
|
||||
// Check if arbitrage service is enabled
|
||||
if !cfg.Arbitrage.Enabled {
|
||||
log.Info("Arbitrage service is disabled in configuration")
|
||||
return fmt.Errorf("arbitrage service disabled - enable in config to run")
|
||||
}
|
||||
|
||||
// Create arbitrage service
|
||||
log.Info("Creating arbitrage service...")
|
||||
arbitrageService, err := arbitrage.NewSimpleArbitrageService(
|
||||
client,
|
||||
log,
|
||||
rateLimiter,
|
||||
marketMgr,
|
||||
scanner,
|
||||
&cfg.Arbitrage,
|
||||
keyManager,
|
||||
arbitrageDB,
|
||||
)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to create Arbitrum monitor: %w", err)
|
||||
return fmt.Errorf("failed to create arbitrage service: %w", err)
|
||||
}
|
||||
log.Info("Arbitrage service created successfully")
|
||||
|
||||
// Set up context with cancellation
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
// Start the arbitrage service
|
||||
log.Info("Starting arbitrage service...")
|
||||
if err := arbitrageService.Start(); err != nil {
|
||||
return fmt.Errorf("failed to start arbitrage service: %w", err)
|
||||
}
|
||||
defer arbitrageService.Stop()
|
||||
log.Info("Arbitrage service started successfully")
|
||||
|
||||
// Set up signal handling for graceful shutdown
|
||||
log.Info("MEV bot started successfully - monitoring for arbitrage opportunities...")
|
||||
|
||||
// Setup graceful shutdown
|
||||
sigChan := make(chan os.Signal, 1)
|
||||
signal.Notify(sigChan, syscall.SIGINT, syscall.SIGTERM)
|
||||
|
||||
// Start monitoring in a goroutine
|
||||
monitorDone := make(chan error, 1)
|
||||
go func() {
|
||||
monitorDone <- monitor.Start(ctx)
|
||||
}()
|
||||
// Wait for shutdown signal
|
||||
<-sigChan
|
||||
log.Info("Shutdown signal received, stopping MEV bot...")
|
||||
|
||||
log.Info("MEV bot started. Press Ctrl+C to stop.")
|
||||
|
||||
// Wait for signal or monitor completion
|
||||
select {
|
||||
case <-sigChan:
|
||||
log.Info("Received shutdown signal...")
|
||||
case err := <-monitorDone:
|
||||
if err != nil {
|
||||
log.Error("Monitor error: ", err)
|
||||
}
|
||||
log.Info("Monitor stopped...")
|
||||
// Stop metrics server if running
|
||||
if metricsServer != nil {
|
||||
metricsServer.Stop()
|
||||
}
|
||||
|
||||
// Cancel context to stop monitor
|
||||
cancel()
|
||||
// Get final stats
|
||||
stats := arbitrageService.GetStats()
|
||||
log.Info(fmt.Sprintf("Final Statistics - Opportunities: %d, Executions: %d, Successful: %d, Total Profit: %s ETH",
|
||||
stats.TotalOpportunitiesDetected,
|
||||
stats.TotalOpportunitiesExecuted,
|
||||
stats.TotalSuccessfulExecutions,
|
||||
formatEther(stats.TotalProfitRealized)))
|
||||
|
||||
// Create shutdown timeout context (5 seconds)
|
||||
shutdownCtx, shutdownCancel := context.WithTimeout(context.Background(), 5*time.Second)
|
||||
defer shutdownCancel()
|
||||
log.Info("MEV bot stopped gracefully")
|
||||
return nil
|
||||
}
|
||||
|
||||
// Shutdown components with timeout
|
||||
shutdownDone := make(chan struct{})
|
||||
go func() {
|
||||
defer close(shutdownDone)
|
||||
// formatEther formats wei amount to ether string
|
||||
func formatEther(wei *big.Int) string {
|
||||
if wei == nil {
|
||||
return "0.000000"
|
||||
}
|
||||
eth := new(big.Float).SetInt(wei)
|
||||
eth.Quo(eth, big.NewFloat(1e18))
|
||||
return fmt.Sprintf("%.6f", eth)
|
||||
}
|
||||
|
||||
// Stop the monitor
|
||||
monitor.Stop()
|
||||
// getEnvOrDefault returns environment variable value or default if not set
|
||||
func getEnvOrDefault(key, defaultValue string) string {
|
||||
if value := os.Getenv(key); value != "" {
|
||||
return value
|
||||
}
|
||||
return defaultValue
|
||||
}
|
||||
|
||||
// Stop the scanner
|
||||
scanner.Stop()
|
||||
// validateRPCEndpoint validates RPC endpoint URL for security
|
||||
func validateRPCEndpoint(endpoint string) error {
|
||||
if endpoint == "" {
|
||||
return fmt.Errorf("RPC endpoint cannot be empty")
|
||||
}
|
||||
|
||||
// Stop metrics server if running
|
||||
if metricsServer != nil {
|
||||
metricsServer.Stop()
|
||||
u, err := url.Parse(endpoint)
|
||||
if err != nil {
|
||||
return fmt.Errorf("invalid RPC endpoint URL: %w", err)
|
||||
}
|
||||
|
||||
// Check for valid schemes
|
||||
switch u.Scheme {
|
||||
case "http", "https", "ws", "wss":
|
||||
// Valid schemes
|
||||
default:
|
||||
return fmt.Errorf("invalid RPC scheme: %s (must be http, https, ws, or wss)", u.Scheme)
|
||||
}
|
||||
|
||||
// Check for localhost/private networks in production
|
||||
if strings.Contains(u.Hostname(), "localhost") || strings.Contains(u.Hostname(), "127.0.0.1") {
|
||||
// Allow localhost only if explicitly enabled
|
||||
if os.Getenv("MEV_BOT_ALLOW_LOCALHOST") != "true" {
|
||||
return fmt.Errorf("localhost RPC endpoints not allowed in production (set MEV_BOT_ALLOW_LOCALHOST=true to override)")
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
// Wait for shutdown or timeout
|
||||
select {
|
||||
case <-shutdownDone:
|
||||
log.Info("MEV bot stopped gracefully.")
|
||||
case <-shutdownCtx.Done():
|
||||
log.Error("Shutdown timeout exceeded, forcing exit...")
|
||||
os.Exit(1)
|
||||
// Validate hostname is not empty
|
||||
if u.Hostname() == "" {
|
||||
return fmt.Errorf("RPC endpoint must have a valid hostname")
|
||||
}
|
||||
|
||||
return nil
|
||||
@@ -170,6 +237,105 @@ func startBot() error {
|
||||
|
||||
func scanOpportunities() error {
|
||||
fmt.Println("Scanning for arbitrage opportunities...")
|
||||
// TODO: Implement scanning logic
|
||||
|
||||
// Load configuration
|
||||
configFile := "config/config.yaml"
|
||||
if _, err := os.Stat("config/local.yaml"); err == nil {
|
||||
configFile = "config/local.yaml"
|
||||
}
|
||||
if _, err := os.Stat("config/arbitrum_production.yaml"); err == nil {
|
||||
configFile = "config/arbitrum_production.yaml"
|
||||
}
|
||||
|
||||
cfg, err := config.Load(configFile)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to load config: %w", err)
|
||||
}
|
||||
|
||||
// Initialize logger
|
||||
log := logger.New(cfg.Log.Level, cfg.Log.Format, cfg.Log.File)
|
||||
log.Info("Starting one-time arbitrage opportunity scan...")
|
||||
|
||||
// Validate and create Ethereum client
|
||||
if err := validateRPCEndpoint(cfg.Arbitrum.RPCEndpoint); err != nil {
|
||||
return fmt.Errorf("invalid RPC endpoint: %w", err)
|
||||
}
|
||||
|
||||
client, err := ethclient.Dial(cfg.Arbitrum.RPCEndpoint)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to connect to Ethereum client: %w", err)
|
||||
}
|
||||
defer client.Close()
|
||||
|
||||
// Create key manager (not used for scanning but needed for service)
|
||||
encryptionKey := os.Getenv("MEV_BOT_ENCRYPTION_KEY")
|
||||
if encryptionKey == "" {
|
||||
return fmt.Errorf("MEV_BOT_ENCRYPTION_KEY environment variable is required")
|
||||
}
|
||||
|
||||
keyManagerConfig := &security.KeyManagerConfig{
|
||||
KeystorePath: getEnvOrDefault("MEV_BOT_KEYSTORE_PATH", "keystore"),
|
||||
EncryptionKey: encryptionKey,
|
||||
KeyRotationDays: 30,
|
||||
MaxSigningRate: 100,
|
||||
SessionTimeout: time.Hour,
|
||||
AuditLogPath: getEnvOrDefault("MEV_BOT_AUDIT_LOG", "logs/audit.log"),
|
||||
BackupPath: getEnvOrDefault("MEV_BOT_BACKUP_PATH", "backups"),
|
||||
}
|
||||
keyManager, err := security.NewKeyManager(keyManagerConfig, log)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to create key manager: %w", err)
|
||||
}
|
||||
|
||||
// Create arbitrage database
|
||||
arbitrageDB, err := arbitrage.NewSQLiteDatabase(cfg.Database.File, log)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to create arbitrage database: %w", err)
|
||||
}
|
||||
defer arbitrageDB.Close()
|
||||
|
||||
// Create arbitrage service with scanning enabled but execution disabled
|
||||
scanConfig := cfg.Arbitrage
|
||||
scanConfig.MaxConcurrentExecutions = 0 // Disable execution for scan mode
|
||||
|
||||
arbitrageService, err := arbitrage.NewSimpleArbitrageService(
|
||||
client,
|
||||
log,
|
||||
&scanConfig,
|
||||
keyManager,
|
||||
arbitrageDB,
|
||||
)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to create arbitrage service: %w", err)
|
||||
}
|
||||
|
||||
// Start the service in scan mode
|
||||
if err := arbitrageService.Start(); err != nil {
|
||||
return fmt.Errorf("failed to start arbitrage service: %w", err)
|
||||
}
|
||||
defer arbitrageService.Stop()
|
||||
|
||||
// Create context with timeout for scanning
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
|
||||
defer cancel()
|
||||
|
||||
log.Info("Scanning for 30 seconds...")
|
||||
|
||||
// Wait for scan duration
|
||||
<-ctx.Done()
|
||||
|
||||
// Get and display results
|
||||
stats := arbitrageService.GetStats()
|
||||
log.Info(fmt.Sprintf("Scan Results - Opportunities Detected: %d", stats.TotalOpportunitiesDetected))
|
||||
|
||||
// Get recent opportunities from database
|
||||
history, err := arbitrageDB.GetExecutionHistory(ctx, 10)
|
||||
if err == nil && len(history) > 0 {
|
||||
log.Info(fmt.Sprintf("Found %d recent opportunities in database", len(history)))
|
||||
}
|
||||
|
||||
fmt.Printf("Scan completed. Found %d arbitrage opportunities.\n", stats.TotalOpportunitiesDetected)
|
||||
fmt.Println("Check the database and logs for detailed results.")
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user