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:
605
orig/pkg/arbitrum/mev_strategies.go
Normal file
605
orig/pkg/arbitrum/mev_strategies.go
Normal file
@@ -0,0 +1,605 @@
|
||||
package arbitrum
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"math/big"
|
||||
"sort"
|
||||
"time"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
|
||||
"github.com/fraktal/mev-beta/internal/logger"
|
||||
"github.com/fraktal/mev-beta/pkg/types"
|
||||
)
|
||||
|
||||
// MEVStrategyEngine implements profitable MEV strategies
|
||||
type MEVStrategyEngine struct {
|
||||
logger *logger.Logger
|
||||
protocolRegistry *ArbitrumProtocolRegistry
|
||||
profitCalculator *RealTimeProfitCalculator
|
||||
riskManager *RiskManager
|
||||
|
||||
// Strategy configuration
|
||||
minProfitUSD float64 // Minimum profit in USD
|
||||
maxGasPrice *big.Int // Maximum gas price willing to pay
|
||||
maxSlippage float64 // Maximum slippage tolerance
|
||||
|
||||
// Performance tracking
|
||||
successfulTrades uint64
|
||||
totalProfit *big.Int
|
||||
totalGasCost *big.Int
|
||||
}
|
||||
|
||||
// RealTimeProfitCalculator provides real-time profit calculations
|
||||
type RealTimeProfitCalculator struct {
|
||||
// Token prices (token address -> price in USD)
|
||||
tokenPrices map[common.Address]*TokenPrice
|
||||
|
||||
// Gas pricing
|
||||
currentGasPrice *big.Int
|
||||
|
||||
// Exchange rates and fees
|
||||
exchangeFees map[string]float64 // protocol -> fee percentage
|
||||
|
||||
// Liquidity data
|
||||
poolLiquidity map[common.Address]*PoolLiquidity
|
||||
}
|
||||
|
||||
// RiskManager manages risk parameters for MEV strategies
|
||||
type RiskManager struct {
|
||||
maxPositionSize *big.Int // Maximum position size in wei
|
||||
maxDailyLoss *big.Int // Maximum daily loss
|
||||
maxConcurrentTxs int // Maximum concurrent transactions
|
||||
|
||||
// Current risk metrics
|
||||
dailyLoss *big.Int
|
||||
activeTxs int
|
||||
lastResetTime time.Time
|
||||
}
|
||||
|
||||
// TokenPrice represents real-time token pricing data
|
||||
type TokenPrice struct {
|
||||
Address common.Address
|
||||
PriceUSD float64
|
||||
LastUpdated time.Time
|
||||
Confidence float64 // Price confidence 0-1
|
||||
Volume24h float64
|
||||
Volatility float64
|
||||
}
|
||||
|
||||
// PoolLiquidity represents pool liquidity information
|
||||
type PoolLiquidity struct {
|
||||
Pool common.Address
|
||||
Token0 common.Address
|
||||
Token1 common.Address
|
||||
Reserve0 *big.Int
|
||||
Reserve1 *big.Int
|
||||
TotalLiquidity *big.Int
|
||||
Fee float64
|
||||
LastUpdated time.Time
|
||||
}
|
||||
|
||||
// ProfitableStrategy represents a profitable MEV strategy
|
||||
type ProfitableStrategy struct {
|
||||
Type string // "arbitrage", "sandwich", "liquidation"
|
||||
Priority int // Higher = more urgent
|
||||
ExpectedProfit *big.Int // Expected profit in wei
|
||||
GasCost *big.Int // Estimated gas cost
|
||||
NetProfit *big.Int // Net profit after gas
|
||||
ProfitMarginPct float64 // Profit margin percentage
|
||||
RiskScore float64 // Risk score 0-1 (higher = riskier)
|
||||
Confidence float64 // Confidence in profit estimate 0-1
|
||||
ExecutionTime time.Duration // Estimated execution time
|
||||
Parameters map[string]interface{} // Strategy-specific parameters
|
||||
}
|
||||
|
||||
// ArbitrageParams holds arbitrage-specific parameters
|
||||
type ArbitrageParams struct {
|
||||
TokenIn common.Address `json:"token_in"`
|
||||
TokenOut common.Address `json:"token_out"`
|
||||
AmountIn *big.Int `json:"amount_in"`
|
||||
Path []common.Address `json:"path"`
|
||||
Exchanges []string `json:"exchanges"`
|
||||
PriceDiff float64 `json:"price_diff"`
|
||||
Slippage float64 `json:"slippage"`
|
||||
}
|
||||
|
||||
// SandwichParams holds sandwich attack parameters
|
||||
type SandwichParams struct {
|
||||
TargetTx string `json:"target_tx"`
|
||||
TokenIn common.Address `json:"token_in"`
|
||||
TokenOut common.Address `json:"token_out"`
|
||||
FrontrunAmount *big.Int `json:"frontrun_amount"`
|
||||
BackrunAmount *big.Int `json:"backrun_amount"`
|
||||
Pool common.Address `json:"pool"`
|
||||
MaxSlippage float64 `json:"max_slippage"`
|
||||
}
|
||||
|
||||
// LiquidationParams holds liquidation-specific parameters
|
||||
type LiquidationParams struct {
|
||||
Protocol string `json:"protocol"`
|
||||
Borrower common.Address `json:"borrower"`
|
||||
CollateralToken common.Address `json:"collateral_token"`
|
||||
DebtToken common.Address `json:"debt_token"`
|
||||
MaxLiquidation *big.Int `json:"max_liquidation"`
|
||||
HealthFactor float64 `json:"health_factor"`
|
||||
LiquidationBonus float64 `json:"liquidation_bonus"`
|
||||
}
|
||||
|
||||
// NewMEVStrategyEngine creates a new MEV strategy engine
|
||||
func NewMEVStrategyEngine(logger *logger.Logger, protocolRegistry *ArbitrumProtocolRegistry) *MEVStrategyEngine {
|
||||
return &MEVStrategyEngine{
|
||||
logger: logger,
|
||||
protocolRegistry: protocolRegistry,
|
||||
minProfitUSD: 50.0, // $50 minimum profit
|
||||
maxGasPrice: big.NewInt(20000000000), // 20 gwei max
|
||||
maxSlippage: 0.005, // 0.5% max slippage
|
||||
totalProfit: big.NewInt(0),
|
||||
totalGasCost: big.NewInt(0),
|
||||
profitCalculator: NewRealTimeProfitCalculator(),
|
||||
riskManager: NewRiskManager(),
|
||||
}
|
||||
}
|
||||
|
||||
// NewRealTimeProfitCalculator creates a new profit calculator
|
||||
func NewRealTimeProfitCalculator() *RealTimeProfitCalculator {
|
||||
return &RealTimeProfitCalculator{
|
||||
tokenPrices: make(map[common.Address]*TokenPrice),
|
||||
exchangeFees: make(map[string]float64),
|
||||
poolLiquidity: make(map[common.Address]*PoolLiquidity),
|
||||
currentGasPrice: big.NewInt(5000000000), // 5 gwei default
|
||||
}
|
||||
}
|
||||
|
||||
// NewRiskManager creates a new risk manager
|
||||
func NewRiskManager() *RiskManager {
|
||||
return &RiskManager{
|
||||
maxPositionSize: big.NewInt(1000000000000000000), // 1 ETH max position
|
||||
maxDailyLoss: big.NewInt(100000000000000000), // 0.1 ETH max daily loss
|
||||
maxConcurrentTxs: 5,
|
||||
dailyLoss: big.NewInt(0),
|
||||
activeTxs: 0,
|
||||
lastResetTime: time.Now(),
|
||||
}
|
||||
}
|
||||
|
||||
// AnalyzeArbitrageOpportunity analyzes potential arbitrage opportunities
|
||||
func (engine *MEVStrategyEngine) AnalyzeArbitrageOpportunity(ctx context.Context, swapEvent interface{}) (interface{}, error) {
|
||||
// Type assert the swapEvent to *SwapEvent
|
||||
swap, ok := swapEvent.(*SwapEvent)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("invalid swap event type")
|
||||
}
|
||||
|
||||
// Parse token addresses
|
||||
tokenIn := common.HexToAddress(swap.TokenIn)
|
||||
tokenOut := common.HexToAddress(swap.TokenOut)
|
||||
|
||||
// Get current prices across exchanges
|
||||
prices, err := engine.profitCalculator.GetCrossExchangePrices(ctx, tokenIn, tokenOut)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to get cross-exchange prices: %w", err)
|
||||
}
|
||||
|
||||
// Find best arbitrage path
|
||||
bestArb := engine.findBestArbitragePath(prices, tokenIn, tokenOut)
|
||||
if bestArb == nil {
|
||||
return nil, nil // No profitable arbitrage
|
||||
}
|
||||
|
||||
// Calculate gas costs
|
||||
gasCost := engine.calculateArbitrageGasCost(bestArb)
|
||||
|
||||
// Calculate net profit
|
||||
netProfit := new(big.Int).Sub(bestArb.Profit, gasCost)
|
||||
|
||||
// Convert to USD for minimum profit check
|
||||
profitUSD := engine.profitCalculator.WeiToUSD(netProfit, common.HexToAddress("0x82af49447d8a07e3bd95bd0d56f35241523fbab1")) // WETH
|
||||
|
||||
if profitUSD < engine.minProfitUSD {
|
||||
return nil, nil // Below minimum profit threshold
|
||||
}
|
||||
|
||||
// Check risk parameters
|
||||
riskScore := engine.riskManager.CalculateRiskScore(bestArb)
|
||||
if riskScore > 0.7 { // Risk too high
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
return &ProfitableStrategy{
|
||||
Type: "arbitrage",
|
||||
Priority: engine.calculatePriority(profitUSD, riskScore),
|
||||
ExpectedProfit: bestArb.Profit,
|
||||
GasCost: gasCost,
|
||||
NetProfit: netProfit,
|
||||
ProfitMarginPct: (float64(netProfit.Uint64()) / float64(bestArb.AmountIn.Uint64())) * 100,
|
||||
RiskScore: riskScore,
|
||||
Confidence: bestArb.Confidence,
|
||||
ExecutionTime: time.Duration(15) * time.Second, // Estimated execution time
|
||||
Parameters: map[string]interface{}{
|
||||
"arbitrage": &ArbitrageParams{
|
||||
TokenIn: tokenIn,
|
||||
TokenOut: tokenOut,
|
||||
AmountIn: bestArb.AmountIn,
|
||||
Path: []common.Address{bestArb.TokenIn, bestArb.TokenOut},
|
||||
Exchanges: bestArb.Pools, // Use pools as exchanges
|
||||
PriceDiff: engine.calculatePriceDifference(prices),
|
||||
Slippage: engine.maxSlippage,
|
||||
},
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
|
||||
// AnalyzeSandwichOpportunity analyzes potential sandwich attack opportunities
|
||||
func (engine *MEVStrategyEngine) AnalyzeSandwichOpportunity(ctx context.Context, targetTx *SwapEvent) (*ProfitableStrategy, error) {
|
||||
// Only analyze large transactions that can be sandwiched profitably
|
||||
amountIn, ok := new(big.Int).SetString(targetTx.AmountIn, 10)
|
||||
if !ok || amountIn.Cmp(big.NewInt(100000000000000000)) < 0 { // < 0.1 ETH
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// Check if transaction has sufficient slippage tolerance
|
||||
if targetTx.PriceImpact < 0.01 { // < 1% price impact
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
tokenIn := common.HexToAddress(targetTx.TokenIn)
|
||||
tokenOut := common.HexToAddress(targetTx.TokenOut)
|
||||
|
||||
// Calculate optimal sandwich amounts
|
||||
frontrunAmount, backrunAmount := engine.calculateOptimalSandwichAmounts(amountIn, targetTx.PriceImpact)
|
||||
|
||||
// Estimate profit from price manipulation
|
||||
expectedProfit := engine.calculateSandwichProfit(frontrunAmount, backrunAmount, targetTx.PriceImpact)
|
||||
|
||||
// Calculate gas costs (frontrun + backrun + priority fees)
|
||||
gasCost := engine.calculateSandwichGasCost()
|
||||
|
||||
// Calculate net profit
|
||||
netProfit := new(big.Int).Sub(expectedProfit, gasCost)
|
||||
|
||||
// Convert to USD
|
||||
profitUSD := engine.profitCalculator.WeiToUSD(netProfit, tokenOut)
|
||||
|
||||
if profitUSD < engine.minProfitUSD {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// Calculate risk (sandwich attacks are inherently risky)
|
||||
riskScore := 0.6 + (targetTx.PriceImpact * 0.3) // Base risk + impact risk
|
||||
|
||||
return &ProfitableStrategy{
|
||||
Type: "sandwich",
|
||||
Priority: engine.calculatePriority(profitUSD, riskScore),
|
||||
ExpectedProfit: expectedProfit,
|
||||
GasCost: gasCost,
|
||||
NetProfit: netProfit,
|
||||
ProfitMarginPct: (float64(netProfit.Uint64()) / float64(amountIn.Uint64())) * 100,
|
||||
RiskScore: riskScore,
|
||||
Confidence: 0.7, // Moderate confidence due to MEV competition
|
||||
ExecutionTime: time.Duration(3) * time.Second, // Fast execution required
|
||||
Parameters: map[string]interface{}{
|
||||
"sandwich": &SandwichParams{
|
||||
TargetTx: targetTx.TxHash,
|
||||
TokenIn: tokenIn,
|
||||
TokenOut: tokenOut,
|
||||
FrontrunAmount: frontrunAmount,
|
||||
BackrunAmount: backrunAmount,
|
||||
Pool: common.HexToAddress(targetTx.Pool),
|
||||
MaxSlippage: engine.maxSlippage,
|
||||
},
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
|
||||
// AnalyzeLiquidationOpportunity analyzes potential liquidation opportunities
|
||||
func (engine *MEVStrategyEngine) AnalyzeLiquidationOpportunity(ctx context.Context, liquidationEvent *LiquidationEvent) (*ProfitableStrategy, error) {
|
||||
// Only analyze under-collateralized positions
|
||||
if liquidationEvent.HealthFactor >= 1.0 {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// Calculate liquidation profitability
|
||||
collateralAmount, ok := new(big.Int).SetString(liquidationEvent.CollateralAmount, 10)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("invalid collateral amount")
|
||||
}
|
||||
|
||||
debtAmount, ok := new(big.Int).SetString(liquidationEvent.DebtAmount, 10)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("invalid debt amount")
|
||||
}
|
||||
|
||||
// Calculate liquidation bonus (usually 5-15%)
|
||||
bonusAmount, ok := new(big.Int).SetString(liquidationEvent.Bonus, 10)
|
||||
if !ok {
|
||||
bonusAmount = new(big.Int).Div(collateralAmount, big.NewInt(20)) // 5% default
|
||||
}
|
||||
|
||||
// Estimate gas costs for liquidation
|
||||
gasCost := engine.calculateLiquidationGasCost(liquidationEvent.Protocol)
|
||||
|
||||
// Calculate net profit (bonus - gas costs)
|
||||
netProfit := new(big.Int).Sub(bonusAmount, gasCost)
|
||||
|
||||
// Convert to USD
|
||||
collateralToken := common.HexToAddress(liquidationEvent.CollateralToken)
|
||||
profitUSD := engine.profitCalculator.WeiToUSD(netProfit, collateralToken)
|
||||
|
||||
if profitUSD < engine.minProfitUSD {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// Calculate risk score (liquidations are generally lower risk)
|
||||
riskScore := 0.3 + (1.0-liquidationEvent.HealthFactor)*0.2
|
||||
|
||||
return &ProfitableStrategy{
|
||||
Type: "liquidation",
|
||||
Priority: engine.calculatePriority(profitUSD, riskScore),
|
||||
ExpectedProfit: bonusAmount,
|
||||
GasCost: gasCost,
|
||||
NetProfit: netProfit,
|
||||
ProfitMarginPct: (float64(netProfit.Uint64()) / float64(debtAmount.Uint64())) * 100,
|
||||
RiskScore: riskScore,
|
||||
Confidence: 0.9, // High confidence for liquidations
|
||||
ExecutionTime: time.Duration(10) * time.Second,
|
||||
Parameters: map[string]interface{}{
|
||||
"liquidation": &LiquidationParams{
|
||||
Protocol: liquidationEvent.Protocol,
|
||||
Borrower: common.HexToAddress(liquidationEvent.Borrower),
|
||||
CollateralToken: collateralToken,
|
||||
DebtToken: common.HexToAddress(liquidationEvent.DebtToken),
|
||||
MaxLiquidation: collateralAmount,
|
||||
HealthFactor: liquidationEvent.HealthFactor,
|
||||
LiquidationBonus: float64(bonusAmount.Uint64()) / float64(collateralAmount.Uint64()),
|
||||
},
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
|
||||
// GetCrossExchangePrices gets prices across different exchanges
|
||||
func (calc *RealTimeProfitCalculator) GetCrossExchangePrices(ctx context.Context, tokenIn, tokenOut common.Address) (map[string]float64, error) {
|
||||
prices := make(map[string]float64)
|
||||
|
||||
// Get prices from major exchanges
|
||||
exchanges := []string{"uniswap_v3", "uniswap_v2", "sushiswap", "camelot_v3", "balancer_v2"}
|
||||
|
||||
for _, exchange := range exchanges {
|
||||
price, err := calc.getTokenPairPrice(ctx, exchange, tokenIn, tokenOut)
|
||||
if err != nil {
|
||||
continue // Skip if price unavailable
|
||||
}
|
||||
prices[exchange] = price
|
||||
}
|
||||
|
||||
return prices, nil
|
||||
}
|
||||
|
||||
// Helper methods for calculations
|
||||
func (engine *MEVStrategyEngine) findBestArbitragePath(prices map[string]float64, tokenIn, tokenOut common.Address) *types.ArbitrageOpportunity {
|
||||
if len(prices) < 2 {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Find highest and lowest prices
|
||||
var minPrice, maxPrice float64
|
||||
var minExchange, maxExchange string
|
||||
first := true
|
||||
|
||||
for exchange, price := range prices {
|
||||
if first {
|
||||
minPrice = price
|
||||
maxPrice = price
|
||||
minExchange = exchange
|
||||
maxExchange = exchange
|
||||
first = false
|
||||
continue
|
||||
}
|
||||
|
||||
if price < minPrice {
|
||||
minPrice = price
|
||||
minExchange = exchange
|
||||
}
|
||||
if price > maxPrice {
|
||||
maxPrice = price
|
||||
maxExchange = exchange
|
||||
}
|
||||
}
|
||||
|
||||
// Calculate potential profit
|
||||
priceDiff := (maxPrice - minPrice) / minPrice
|
||||
if priceDiff < 0.005 { // Minimum 0.5% price difference
|
||||
return nil
|
||||
}
|
||||
|
||||
// Estimate amounts and profit
|
||||
amountIn := big.NewInt(100000000000000000) // 0.1 ETH test amount
|
||||
expectedProfit := new(big.Int).Mul(amountIn, big.NewInt(int64(priceDiff*1000)))
|
||||
expectedProfit = new(big.Int).Div(expectedProfit, big.NewInt(1000))
|
||||
|
||||
return &types.ArbitrageOpportunity{
|
||||
Path: []string{tokenIn.Hex(), tokenOut.Hex()},
|
||||
Pools: []string{minExchange + "-pool", maxExchange + "-pool"},
|
||||
AmountIn: amountIn,
|
||||
Profit: expectedProfit,
|
||||
NetProfit: expectedProfit, // Simplified - gas will be calculated later
|
||||
GasEstimate: big.NewInt(200000), // Estimate
|
||||
ROI: 0.0, // Will be calculated when gas is known
|
||||
Protocol: "multi-exchange",
|
||||
ExecutionTime: 4000, // 4 seconds
|
||||
Confidence: 0.8,
|
||||
PriceImpact: 0.005, // 0.5% estimated
|
||||
MaxSlippage: 0.02, // 2% max slippage
|
||||
TokenIn: tokenIn,
|
||||
TokenOut: tokenOut,
|
||||
Timestamp: time.Now().Unix(),
|
||||
Risk: 0.3, // Medium risk for cross-exchange arbitrage
|
||||
}
|
||||
}
|
||||
|
||||
func (engine *MEVStrategyEngine) calculateOptimalSandwichAmounts(targetAmount *big.Int, priceImpact float64) (*big.Int, *big.Int) {
|
||||
// Optimal frontrun is typically 10-30% of target transaction
|
||||
frontrunPct := 0.15 + (priceImpact * 0.15) // Scale with price impact
|
||||
frontrunAmount := new(big.Int).Mul(targetAmount, big.NewInt(int64(frontrunPct*100)))
|
||||
frontrunAmount = new(big.Int).Div(frontrunAmount, big.NewInt(100))
|
||||
|
||||
// Backrun amount should be similar to frontrun
|
||||
backrunAmount := new(big.Int).Set(frontrunAmount)
|
||||
|
||||
return frontrunAmount, backrunAmount
|
||||
}
|
||||
|
||||
func (engine *MEVStrategyEngine) calculateSandwichProfit(frontrunAmount, backrunAmount *big.Int, priceImpact float64) *big.Int {
|
||||
// Simplified calculation: profit = frontrun_amount * (price_impact - fees)
|
||||
profitPct := priceImpact - 0.006 // Subtract 0.6% for fees and slippage
|
||||
if profitPct <= 0 {
|
||||
return big.NewInt(0)
|
||||
}
|
||||
|
||||
profit := new(big.Int).Mul(frontrunAmount, big.NewInt(int64(profitPct*1000)))
|
||||
profit = new(big.Int).Div(profit, big.NewInt(1000))
|
||||
|
||||
return profit
|
||||
}
|
||||
|
||||
// Gas cost calculation methods
|
||||
func (engine *MEVStrategyEngine) calculateArbitrageGasCost(arb *types.ArbitrageOpportunity) *big.Int {
|
||||
// Estimate gas usage: swap + transfer operations
|
||||
gasUsage := big.NewInt(300000) // ~300k gas for complex arbitrage
|
||||
return new(big.Int).Mul(gasUsage, engine.maxGasPrice)
|
||||
}
|
||||
|
||||
func (engine *MEVStrategyEngine) calculateSandwichGasCost() *big.Int {
|
||||
// Frontrun + backrun + priority fees
|
||||
gasUsage := big.NewInt(400000) // ~400k gas total
|
||||
priorityFee := big.NewInt(10000000000) // 10 gwei priority
|
||||
totalGasPrice := new(big.Int).Add(engine.maxGasPrice, priorityFee)
|
||||
return new(big.Int).Mul(gasUsage, totalGasPrice)
|
||||
}
|
||||
|
||||
func (engine *MEVStrategyEngine) calculateLiquidationGasCost(protocol string) *big.Int {
|
||||
// Different protocols have different gas costs
|
||||
gasUsage := big.NewInt(200000) // ~200k gas for liquidation
|
||||
if protocol == "gmx" {
|
||||
gasUsage = big.NewInt(350000) // GMX is more expensive
|
||||
}
|
||||
return new(big.Int).Mul(gasUsage, engine.maxGasPrice)
|
||||
}
|
||||
|
||||
// Utility methods
|
||||
func (engine *MEVStrategyEngine) calculatePriority(profitUSD, riskScore float64) int {
|
||||
// Higher profit and lower risk = higher priority
|
||||
priority := int((profitUSD / 10.0) * (1.0 - riskScore) * 100)
|
||||
if priority > 1000 {
|
||||
priority = 1000 // Cap at 1000
|
||||
}
|
||||
return priority
|
||||
}
|
||||
|
||||
func (engine *MEVStrategyEngine) calculatePriceDifference(prices map[string]float64) float64 {
|
||||
if len(prices) < 2 {
|
||||
return 0
|
||||
}
|
||||
|
||||
var min, max float64
|
||||
first := true
|
||||
for _, price := range prices {
|
||||
if first {
|
||||
min = price
|
||||
max = price
|
||||
first = false
|
||||
continue
|
||||
}
|
||||
if price < min {
|
||||
min = price
|
||||
}
|
||||
if price > max {
|
||||
max = price
|
||||
}
|
||||
}
|
||||
|
||||
return (max - min) / min
|
||||
}
|
||||
|
||||
// WeiToUSD converts wei amount to USD using token price
|
||||
func (calc *RealTimeProfitCalculator) WeiToUSD(amount *big.Int, token common.Address) float64 {
|
||||
price, exists := calc.tokenPrices[token]
|
||||
if !exists {
|
||||
return 0
|
||||
}
|
||||
|
||||
// Convert wei to token units (assume 18 decimals)
|
||||
tokenAmount := new(big.Float).SetInt(amount)
|
||||
tokenAmount.Quo(tokenAmount, big.NewFloat(1e18))
|
||||
|
||||
tokenAmountFloat, _ := tokenAmount.Float64()
|
||||
return tokenAmountFloat * price.PriceUSD
|
||||
}
|
||||
|
||||
func (calc *RealTimeProfitCalculator) getTokenPairPrice(ctx context.Context, exchange string, tokenIn, tokenOut common.Address) (float64, error) {
|
||||
// This would connect to actual DEX contracts or price oracles
|
||||
// For now, we'll return an error to indicate this needs implementation
|
||||
return 0, fmt.Errorf("getTokenPairPrice not implemented - needs connection to actual DEX contracts or price oracles")
|
||||
}
|
||||
|
||||
// CalculateRiskScore calculates risk score for a strategy
|
||||
func (rm *RiskManager) CalculateRiskScore(arb *types.ArbitrageOpportunity) float64 {
|
||||
// Base risk factors
|
||||
baseRisk := 0.1
|
||||
|
||||
// Size risk - larger positions are riskier
|
||||
sizeRisk := float64(arb.AmountIn.Uint64()) / 1e18 * 0.1 // 0.1 per ETH
|
||||
|
||||
// Confidence risk
|
||||
confidenceRisk := (1.0 - arb.Confidence) * 0.3
|
||||
|
||||
// Path complexity risk
|
||||
pathRisk := float64(len(arb.Path)-2) * 0.05 // Additional risk for each hop
|
||||
|
||||
totalRisk := baseRisk + sizeRisk + confidenceRisk + pathRisk
|
||||
|
||||
// Cap at 1.0
|
||||
if totalRisk > 1.0 {
|
||||
totalRisk = 1.0
|
||||
}
|
||||
|
||||
return totalRisk
|
||||
}
|
||||
|
||||
// GetTopStrategies returns the most profitable strategies sorted by priority
|
||||
func (engine *MEVStrategyEngine) GetTopStrategies(strategies []*ProfitableStrategy, limit int) []*ProfitableStrategy {
|
||||
// Sort by priority (highest first)
|
||||
sort.Slice(strategies, func(i, j int) bool {
|
||||
return strategies[i].Priority > strategies[j].Priority
|
||||
})
|
||||
|
||||
// Apply limit
|
||||
if len(strategies) > limit {
|
||||
strategies = strategies[:limit]
|
||||
}
|
||||
|
||||
return strategies
|
||||
}
|
||||
|
||||
// UpdatePerformanceMetrics updates strategy performance tracking
|
||||
func (engine *MEVStrategyEngine) UpdatePerformanceMetrics(strategy *ProfitableStrategy, actualProfit *big.Int, gasCost *big.Int) {
|
||||
if actualProfit.Sign() > 0 {
|
||||
engine.successfulTrades++
|
||||
engine.totalProfit.Add(engine.totalProfit, actualProfit)
|
||||
}
|
||||
engine.totalGasCost.Add(engine.totalGasCost, gasCost)
|
||||
}
|
||||
|
||||
// GetPerformanceStats returns performance statistics
|
||||
func (engine *MEVStrategyEngine) GetPerformanceStats() map[string]interface{} {
|
||||
netProfit := new(big.Int).Sub(engine.totalProfit, engine.totalGasCost)
|
||||
|
||||
return map[string]interface{}{
|
||||
"successful_trades": engine.successfulTrades,
|
||||
"total_profit_wei": engine.totalProfit.String(),
|
||||
"total_gas_cost": engine.totalGasCost.String(),
|
||||
"net_profit_wei": netProfit.String(),
|
||||
"profit_ratio": float64(engine.totalProfit.Uint64()) / float64(engine.totalGasCost.Uint64()),
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user