feat: create v2-prep branch with comprehensive planning

Restructured project for V2 refactor:

**Structure Changes:**
- Moved all V1 code to orig/ folder (preserved with git mv)
- Created docs/planning/ directory
- Added orig/README_V1.md explaining V1 preservation

**Planning Documents:**
- 00_V2_MASTER_PLAN.md: Complete architecture overview
  - Executive summary of critical V1 issues
  - High-level component architecture diagrams
  - 5-phase implementation roadmap
  - Success metrics and risk mitigation

- 07_TASK_BREAKDOWN.md: Atomic task breakdown
  - 99+ hours of detailed tasks
  - Every task < 2 hours (atomic)
  - Clear dependencies and success criteria
  - Organized by implementation phase

**V2 Key Improvements:**
- Per-exchange parsers (factory pattern)
- Multi-layer strict validation
- Multi-index pool cache
- Background validation pipeline
- Comprehensive observability

**Critical Issues Addressed:**
- Zero address tokens (strict validation + cache enrichment)
- Parsing accuracy (protocol-specific parsers)
- No audit trail (background validation channel)
- Inefficient lookups (multi-index cache)
- Stats disconnection (event-driven metrics)

Next Steps:
1. Review planning documents
2. Begin Phase 1: Foundation (P1-001 through P1-010)
3. Implement parsers in Phase 2
4. Build cache system in Phase 3
5. Add validation pipeline in Phase 4
6. Migrate and test in Phase 5

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Administrator
2025-11-10 10:14:26 +01:00
parent 1773daffe7
commit 803de231ba
411 changed files with 20390 additions and 8680 deletions

310
orig/pkg/mev/competition.go Normal file
View File

@@ -0,0 +1,310 @@
package mev
import (
"context"
"math"
"math/big"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/ethclient"
"github.com/fraktal/mev-beta/internal/logger"
mathpkg "github.com/fraktal/mev-beta/pkg/math"
"github.com/fraktal/mev-beta/pkg/security"
)
// MEVOpportunity represents a potential MEV opportunity
type MEVOpportunity struct {
TxHash string
Block uint64
OpportunityType string
EstimatedProfit *big.Int
RequiredGas uint64
Competition int // Number of competing bots
Confidence float64
}
// BiddingStrategy represents the optimal bidding strategy
type BiddingStrategy struct {
PriorityFee *big.Int
BaseFee *big.Int
GasLimit uint64
SuccessProbability float64
TotalCost *big.Int
NetProfit *big.Int
}
// CompetitionAnalysis represents the result of competition analysis
type CompetitionAnalysis struct {
CompetitorCount int
AverageGasPrice *big.Int
CompetitionLevel string // "low", "medium", "high"
ThreatAssessment float64 // 0-1 scale
RecommendedStrategy *BiddingStrategy
AnalysisTime int64
}
// CompetitionAnalyzer analyzes MEV competition
type CompetitionAnalyzer struct {
client *ethclient.Client
logger *logger.Logger
decimalConverter *mathpkg.DecimalConverter
competitorData map[common.Address]*CompetitorProfile
gasHistory []GasDataPoint
profitThresholds map[string]*mathpkg.UniversalDecimal
config CompetitionConfig
}
// CompetitorProfile represents a competing MEV bot
type CompetitorProfile struct {
Address common.Address
TransactionCount int
AverageGasPrice *big.Int
SuccessRate float64
FavoredProtocols []string
CompetitionScore float64
LastSeenBlock uint64
}
// GasDataPoint represents a historical gas price data point
type GasDataPoint struct {
GasPrice *big.Int
Timestamp int64
BlockNumber uint64
Profit *big.Int
}
// CompetitionConfig holds configuration for competition analysis
type CompetitionConfig struct {
BaseGasMultiplier float64
MaxGasMultiplier float64
GasHistorySize int
CompetitorThreshold *mathpkg.UniversalDecimal
MaxOpportunitySize *mathpkg.UniversalDecimal
}
// NewCompetitionAnalyzer creates a new competition analyzer
func NewCompetitionAnalyzer(client *ethclient.Client, logger *logger.Logger) *CompetitionAnalyzer {
analyzer := &CompetitionAnalyzer{
client: client,
logger: logger,
decimalConverter: mathpkg.NewDecimalConverter(),
competitorData: make(map[common.Address]*CompetitorProfile),
gasHistory: make([]GasDataPoint, 0),
profitThresholds: make(map[string]*mathpkg.UniversalDecimal),
}
analyzer.config = CompetitionConfig{
BaseGasMultiplier: 1.2, // 20% premium
MaxGasMultiplier: 3.0, // 200% max premium
GasHistorySize: 100, // Track last 100 data points
}
// Set competitor threshold (0.005 ETH)
analyzer.config.CompetitorThreshold, _ = analyzer.decimalConverter.FromString("0.005", 18, "ETH")
// Set profit thresholds for different opportunity sizes
analyzer.profitThresholds["small"], _ = analyzer.decimalConverter.FromString("0.01", 18, "ETH") // $10
analyzer.profitThresholds["medium"], _ = analyzer.decimalConverter.FromString("0.05", 18, "ETH") // $50
analyzer.profitThresholds["large"], _ = analyzer.decimalConverter.FromString("0.25", 18, "ETH") // $250
return analyzer
}
// AnalyzeCompetition analyzes the competitive landscape for an opportunity
func (analyzer *CompetitionAnalyzer) AnalyzeCompetition(ctx context.Context, opportunity *MEVOpportunity) (*CompetitionData, error) {
analyzer.logger.Info("Analyzing competition for MEV opportunity",
"type", opportunity.OpportunityType,
"estimated_profit", opportunity.EstimatedProfit.String())
// Get current base fee
head, err := analyzer.client.HeaderByNumber(ctx, nil)
if err != nil {
return nil, err
}
baseFee := head.BaseFee
// Calculate basic gas price estimate
estimatedGasPrice := new(big.Int).Mul(baseFee, big.NewInt(12)) // 20% above base fee
estimatedGasPrice.Div(estimatedGasPrice, big.NewInt(10))
// Adjust based on competition level
competitionFactor := analyzer.calculateCompetitionFactor(opportunity)
adjustedGasPrice := new(big.Int).Mul(estimatedGasPrice, big.NewInt(int64(competitionFactor*100)))
adjustedGasPrice.Div(adjustedGasPrice, big.NewInt(100))
// Ensure minimum gas price
minGasPrice := big.NewInt(2000000000) // 2 gwei minimum
if adjustedGasPrice.Cmp(minGasPrice) < 0 {
adjustedGasPrice = minGasPrice
}
// Calculate success probability based on competition
successProbability := analyzer.estimateSuccessProbability(opportunity, competitionFactor)
// Calculate net profit after gas costs
// Calculate net profit after gas costs
requiredGasInt64, err := security.SafeUint64ToInt64(opportunity.RequiredGas)
if err != nil {
analyzer.logger.Error("Required gas exceeds int64 maximum", "requiredGas", opportunity.RequiredGas, "error", err)
// Use maximum safe value as fallback
requiredGasInt64 = math.MaxInt64
}
gasCost := new(big.Int).Mul(big.NewInt(requiredGasInt64), adjustedGasPrice)
netProfit := new(big.Int).Sub(opportunity.EstimatedProfit, gasCost)
// Create competition data
competitionData := &CompetitionData{
OpportunityType: opportunity.OpportunityType,
EstimatedProfit: opportunity.EstimatedProfit,
NetProfit: netProfit,
BaseFee: baseFee,
SuggestedGasPrice: adjustedGasPrice,
RequiredGas: opportunity.RequiredGas,
CompetitionLevel: competitionFactor,
SuccessProbability: successProbability,
TotalCost: gasCost,
Threshold: analyzer.config.CompetitorThreshold,
}
return competitionData, nil
}
// CalculateOptimalBid calculates the optimal bidding strategy
func (analyzer *CompetitionAnalyzer) CalculateOptimalBid(ctx context.Context, opportunity *MEVOpportunity, competition *CompetitionData) (*BiddingStrategy, error) {
analyzer.logger.Info("Calculating optimal bid for opportunity",
"type", opportunity.OpportunityType,
"estimated_profit", opportunity.EstimatedProfit.String())
// Start with the suggested gas price from competition analysis
baseGasPrice := competition.SuggestedGasPrice
// Calculate base strategy with safe gas conversion
requiredGasInt64, err := security.SafeUint64ToInt64(opportunity.RequiredGas)
if err != nil {
analyzer.logger.Error("Required gas exceeds int64 maximum", "requiredGas", opportunity.RequiredGas, "error", err)
// Use maximum safe value as fallback
requiredGasInt64 = math.MaxInt64
}
gasCostForBaseStrategy := new(big.Int).Mul(baseGasPrice, big.NewInt(requiredGasInt64))
strategy := &BiddingStrategy{
PriorityFee: baseGasPrice,
BaseFee: competition.BaseFee,
GasLimit: opportunity.RequiredGas,
SuccessProbability: competition.SuccessProbability,
TotalCost: gasCostForBaseStrategy,
NetProfit: competition.NetProfit,
}
// Adjust for profitability - if opportunity is very profitable, we can afford higher gas
profitRatio := new(big.Float).Quo(
new(big.Float).SetInt(opportunity.EstimatedProfit),
new(big.Float).SetInt(strategy.TotalCost),
)
profitRatioFloat, _ := profitRatio.Float64()
// If profit ratio is high, we can bid more aggressively
if profitRatioFloat > 10 { // If profit is >10x gas cost
// Increase bid by up to 50% for high-value opportunities
aggressiveMultiplier := 1.5
increasedPriority := new(big.Int).Mul(strategy.PriorityFee, big.NewInt(int64(aggressiveMultiplier*100)))
increasedPriority.Div(increasedPriority, big.NewInt(100))
// Cap at max multiplier
maxGasPrice := new(big.Int).Mul(competition.BaseFee, big.NewInt(int64(analyzer.config.MaxGasMultiplier*100)))
maxGasPrice.Div(maxGasPrice, big.NewInt(100))
if increasedPriority.Cmp(maxGasPrice) > 0 {
increasedPriority = maxGasPrice
}
// Calculate new total cost with increased priority fee using safe conversion
requiredGasInt64_safe, err := security.SafeUint64ToInt64(opportunity.RequiredGas)
if err != nil {
analyzer.logger.Error("Required gas exceeds int64 maximum for TotalCost in strategy", "requiredGas", opportunity.RequiredGas, "error", err)
// Use maximum safe value as fallback
requiredGasInt64_safe = math.MaxInt64
}
strategy.TotalCost = new(big.Int).Mul(increasedPriority, big.NewInt(requiredGasInt64_safe))
strategy.PriorityFee = increasedPriority
}
// Update net profit
strategy.NetProfit = new(big.Int).Sub(opportunity.EstimatedProfit, strategy.TotalCost)
// Ensure net profit is positive
if strategy.NetProfit.Sign() <= 0 {
analyzer.logger.Warn("Opportunity not profitable after optimal bidding",
"estimated_profit", opportunity.EstimatedProfit.String(),
"total_cost", strategy.TotalCost.String())
return nil, nil
}
return strategy, nil
}
// calculateCompetitionFactor estimates competition level for an opportunity
func (analyzer *CompetitionAnalyzer) calculateCompetitionFactor(opportunity *MEVOpportunity) float64 {
// Base competition factor
competitionFactor := 1.0
// Higher competition for more profitable opportunities
if opportunity.EstimatedProfit.Cmp(big.NewInt(100000000000000000)) > 0 { // >0.1 ETH
competitionFactor += 0.3
}
if opportunity.EstimatedProfit.Cmp(big.NewInt(500000000000000000)) > 0 { // >0.5 ETH
competitionFactor += 0.4
}
// Factor in known competitors
competitionFactor += float64(opportunity.Competition) * 0.1
// Cap at reasonable maximum
if competitionFactor > analyzer.config.MaxGasMultiplier {
competitionFactor = analyzer.config.MaxGasMultiplier
}
return competitionFactor
}
// estimateSuccessProbability estimates the success probability
func (analyzer *CompetitionAnalyzer) estimateSuccessProbability(opportunity *MEVOpportunity, competitionFactor float64) float64 {
// Base success probability is inversely related to competition
baseSuccessRate := 1.0 / competitionFactor
// Adjust based on opportunity characteristics
if opportunity.OpportunityType == "sandwich" {
// Sandwich attacks are harder to execute successfully
baseSuccessRate *= 0.7
} else if opportunity.OpportunityType == "arbitrage" {
// Arbitrage has higher success rate
baseSuccessRate *= 0.9
}
// Ensure it's between 0 and 1
if baseSuccessRate > 1.0 {
baseSuccessRate = 1.0
}
if baseSuccessRate < 0.05 {
baseSuccessRate = 0.05 // Minimum 5% chance
}
return baseSuccessRate
}
// CompetitionData holds the results of competition analysis
type CompetitionData struct {
OpportunityType string
EstimatedProfit *big.Int
NetProfit *big.Int
BaseFee *big.Int
SuggestedGasPrice *big.Int
RequiredGas uint64
CompetitionLevel float64
SuccessProbability float64
TotalCost *big.Int
Threshold *mathpkg.UniversalDecimal
}