package parser import ( "context" "fmt" "time" logpkg "github.com/fraktal/mev-beta/internal/logger" pkgtypes "github.com/fraktal/mev-beta/pkg/types" ) // OpportunityDispatcher represents the arbitrage service entry point that can // accept opportunities discovered by the transaction analyzer. type OpportunityDispatcher interface { SubmitBridgeOpportunity(ctx context.Context, bridgeOpportunity interface{}) error } // Executor routes arbitrage opportunities discovered in the Arbitrum parser to // the core arbitrage service. type Executor struct { logger *logpkg.Logger dispatcher OpportunityDispatcher metrics *ExecutorMetrics serviceName string } // ExecutorMetrics captures lightweight counters about dispatched opportunities. type ExecutorMetrics struct { OpportunitiesForwarded int64 OpportunitiesRejected int64 LastDispatchTime time.Time } // NewExecutor creates a new parser executor that forwards opportunities to the // provided dispatcher (typically the arbitrage service). func NewExecutor(dispatcher OpportunityDispatcher, log *logpkg.Logger) *Executor { if log == nil { log = logpkg.New("info", "text", "") } return &Executor{ logger: log, dispatcher: dispatcher, metrics: &ExecutorMetrics{ OpportunitiesForwarded: 0, OpportunitiesRejected: 0, }, serviceName: "arbitrum-parser", } } // ExecuteArbitrage forwards the opportunity to the arbitrage service. func (e *Executor) ExecuteArbitrage(ctx context.Context, arbOp *pkgtypes.ArbitrageOpportunity) error { if arbOp == nil { e.metrics.OpportunitiesRejected++ return fmt.Errorf("arbitrage opportunity cannot be nil") } if e.dispatcher == nil { e.metrics.OpportunitiesRejected++ return fmt.Errorf("no dispatcher configured for executor") } if ctx == nil { ctx = context.Background() } e.logger.Info("Forwarding arbitrage opportunity detected by parser", "id", arbOp.ID, "path_length", len(arbOp.Path), "pools", len(arbOp.Pools), "profit", arbOp.NetProfit, ) if err := e.dispatcher.SubmitBridgeOpportunity(ctx, arbOp); err != nil { e.metrics.OpportunitiesRejected++ e.logger.Error("Failed to forward arbitrage opportunity", "id", arbOp.ID, "error", err, ) return err } e.metrics.OpportunitiesForwarded++ e.metrics.LastDispatchTime = time.Now() return nil } // Metrics returns a snapshot of executor metrics. func (e *Executor) Metrics() ExecutorMetrics { return *e.metrics }