package market import ( "fmt" "time" "github.com/ethereum/go-ethereum/common" "github.com/fraktal/mev-beta/internal/logger" ) // NewMarketDiscovery creates a new market discovery instance func NewMarketDiscovery(client interface{}, loggerInstance *logger.Logger, configPath string) (*MarketDiscovery, error) { // Load configuration config, err := LoadMarketConfig(configPath) if err != nil { return nil, fmt.Errorf("failed to load config: %w", err) } // Initialize math calculator // mathCalc := exchangeMath.NewMathCalculator() md := &MarketDiscovery{ client: client, logger: loggerInstance, config: config, // mathCalc: mathCalc, pools: make(map[common.Address]*PoolInfoDetailed), tokens: make(map[common.Address]*TokenInfo), factories: make(map[common.Address]*FactoryInfo), routers: make(map[common.Address]*RouterInfo), } // Initialize logging if err := md.initializeLogging(); err != nil { return nil, fmt.Errorf("failed to initialize logging: %w", err) } // Load initial configuration if err := md.loadInitialMarkets(); err != nil { return nil, fmt.Errorf("failed to load initial markets: %w", err) } loggerInstance.Info("Market discovery initialized with comprehensive pool detection") return md, nil } // loadInitialMarkets loads initial tokens, factories, and priority pools func (md *MarketDiscovery) loadInitialMarkets() error { md.mu.Lock() defer md.mu.Unlock() // Load tokens for _, token := range md.config.Tokens { tokenAddr := common.HexToAddress(token.Address) md.tokens[tokenAddr] = &TokenInfo{ Address: tokenAddr, Symbol: token.Symbol, Decimals: uint8(token.Decimals), Priority: token.Priority, } } // Load factories for _, factory := range md.config.Factories { factoryAddr := common.HexToAddress(factory.Address) md.factories[factoryAddr] = &FactoryInfo{ Address: factoryAddr, Type: factory.Type, InitCodeHash: common.HexToHash(factory.InitCodeHash), FeeTiers: factory.FeeTiers, Priority: factory.Priority, } } // Load routers for _, router := range md.config.Routers { routerAddr := common.HexToAddress(router.Address) factoryAddr := common.Address{} if router.Factory != "" { for _, f := range md.config.Factories { if f.Type == router.Factory { factoryAddr = common.HexToAddress(f.Address) break } } } md.routers[routerAddr] = &RouterInfo{ Address: routerAddr, Factory: factoryAddr, Type: router.Type, Priority: router.Priority, } } // Load priority pools for _, poolConfig := range md.config.PriorityPools { poolAddr := common.HexToAddress(poolConfig.Pool) token0 := common.HexToAddress(poolConfig.Token0) token1 := common.HexToAddress(poolConfig.Token1) // Find factory var factoryAddr common.Address var factoryType string for _, f := range md.config.Factories { if f.Type == poolConfig.Factory { factoryAddr = common.HexToAddress(f.Address) factoryType = f.Type break } } pool := &PoolInfoDetailed{ Address: poolAddr, Factory: factoryAddr, FactoryType: factoryType, Token0: token0, Token1: token1, Fee: poolConfig.Fee, Priority: poolConfig.Priority, Active: true, LastUpdated: time.Now(), } md.pools[poolAddr] = pool } loggerMsg := fmt.Sprintf("Loaded initial markets: %d tokens, %d factories, %d routers, %d priority pools", len(md.tokens), len(md.factories), len(md.routers), len(md.pools)) md.logger.Info(loggerMsg) return nil } // Helper methods func abs(x float64) float64 { if x < 0 { return -x } return x } // GetStatistics returns market discovery statistics func (md *MarketDiscovery) GetStatistics() map[string]interface{} { md.mu.RLock() defer md.mu.RUnlock() return map[string]interface{}{ "pools_tracked": len(md.pools), "tokens_tracked": len(md.tokens), "factories_tracked": len(md.factories), "pools_discovered": md.poolsDiscovered, "arbitrage_opportunities": md.arbitrageOpps, "last_scan_time": md.lastScanTime, "total_scan_time": md.totalScanTime.String(), } } // Close closes all log files and resources func (md *MarketDiscovery) Close() error { var errors []error // if md.marketScanLogger != nil { // if err := md.marketScanLogger.(*os.File).Close(); err != nil { // errors = append(errors, err) // } // } // if md.arbLogger != nil { // if err := md.arbLogger.(*os.File).Close(); err != nil { // errors = append(errors, err) // } // } if len(errors) > 0 { return fmt.Errorf("errors closing resources: %v", errors) } return nil }