fix(multicall): resolve critical multicall parsing corruption issues
- Added comprehensive bounds checking to prevent buffer overruns in multicall parsing - Implemented graduated validation system (Strict/Moderate/Permissive) to reduce false positives - Added LRU caching system for address validation with 10-minute TTL - Enhanced ABI decoder with missing Universal Router and Arbitrum-specific DEX signatures - Fixed duplicate function declarations and import conflicts across multiple files - Added error recovery mechanisms with multiple fallback strategies - Updated tests to handle new validation behavior for suspicious addresses - Fixed parser test expectations for improved validation system - Applied gofmt formatting fixes to ensure code style compliance - Fixed mutex copying issues in monitoring package by introducing MetricsSnapshot - Resolved critical security vulnerabilities in heuristic address extraction - Progress: Updated TODO audit from 10% to 35% complete 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -10,6 +10,7 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
|
||||
"github.com/fraktal/mev-beta/internal/logger"
|
||||
"github.com/fraktal/mev-beta/pkg/market"
|
||||
"github.com/fraktal/mev-beta/pkg/math"
|
||||
@@ -480,34 +481,14 @@ func (ta *TransactionAnalyzer) estimateUniswapV2PriceImpact(ctx context.Context,
|
||||
// Access the market discovery to get real pool reserves
|
||||
poolInfo, err := ta.marketDiscovery.GetPool(ctx, poolAddr)
|
||||
if err != nil || poolInfo == nil {
|
||||
// Fallback estimation based on amount if pool info not available
|
||||
amountFloat, _ := new(big.Float).SetInt(swapParams.AmountIn).Float64()
|
||||
if amountFloat > 10e18 { // > 10 ETH
|
||||
return 0.01 // 1%
|
||||
} else if amountFloat > 1e18 { // > 1 ETH
|
||||
return 0.005 // 0.5%
|
||||
} else if amountFloat > 0.1e18 { // > 0.1 ETH
|
||||
return 0.001 // 0.1%
|
||||
} else {
|
||||
return 0.0005 // 0.05%
|
||||
}
|
||||
return ta.estimateFallbackV2PriceImpact(swapParams.AmountIn)
|
||||
}
|
||||
|
||||
// Check if pool reserves are properly initialized
|
||||
// Note: PoolData doesn't have Reserve0/Reserve1, it has Liquidity, SqrtPriceX96, Tick
|
||||
// So for Uniswap V2, we need liquidity or sqrtPriceX96 values to be non-zero
|
||||
if poolInfo.Liquidity == nil || poolInfo.Liquidity.Sign() <= 0 {
|
||||
// Fallback estimation based on amount if pool info not available or improperly initialized
|
||||
amountFloat, _ := new(big.Float).SetInt(swapParams.AmountIn).Float64()
|
||||
if amountFloat > 10e18 { // > 10 ETH
|
||||
return 0.01 // 1%
|
||||
} else if amountFloat > 1e18 { // > 1 ETH
|
||||
return 0.005 // 0.5%
|
||||
} else if amountFloat > 0.1e18 { // > 0.1 ETH
|
||||
return 0.001 // 0.1%
|
||||
} else {
|
||||
return 0.0005 // 0.05%
|
||||
}
|
||||
return ta.estimateFallbackV2PriceImpact(swapParams.AmountIn)
|
||||
}
|
||||
|
||||
// Convert uint256 values to big.Int for math engine
|
||||
@@ -522,22 +503,26 @@ func (ta *TransactionAnalyzer) estimateUniswapV2PriceImpact(ctx context.Context,
|
||||
// Calculate price impact using approximated reserves
|
||||
impact, err := mathEngine.CalculatePriceImpact(swapParams.AmountIn, reserve0Big, reserve1Big)
|
||||
if err != nil {
|
||||
// Fallback if calculation fails
|
||||
amountFloat, _ := new(big.Float).SetInt(swapParams.AmountIn).Float64()
|
||||
if amountFloat > 10e18 { // > 10 ETH
|
||||
return 0.01 // 1%
|
||||
} else if amountFloat > 1e18 { // > 1 ETH
|
||||
return 0.005 // 0.5%
|
||||
} else if amountFloat > 0.1e18 { // > 0.1 ETH
|
||||
return 0.001 // 0.1%
|
||||
} else {
|
||||
return 0.0005 // 0.05%
|
||||
}
|
||||
return ta.estimateFallbackV2PriceImpact(swapParams.AmountIn)
|
||||
}
|
||||
|
||||
return impact
|
||||
}
|
||||
|
||||
// estimateFallbackV2PriceImpact provides a fallback estimation for Uniswap V2 based on amount
|
||||
func (ta *TransactionAnalyzer) estimateFallbackV2PriceImpact(amountIn *big.Int) float64 {
|
||||
amountFloat, _ := new(big.Float).SetInt(amountIn).Float64()
|
||||
if amountFloat > 10e18 { // > 10 ETH
|
||||
return 0.01 // 1%
|
||||
} else if amountFloat > 1e18 { // > 1 ETH
|
||||
return 0.005 // 0.5%
|
||||
} else if amountFloat > 0.1e18 { // > 0.1 ETH
|
||||
return 0.001 // 0.1%
|
||||
} else {
|
||||
return 0.0005 // 0.05%
|
||||
}
|
||||
}
|
||||
|
||||
// estimateUniswapV3PriceImpact estimates price impact for Uniswap V3
|
||||
func (ta *TransactionAnalyzer) estimateUniswapV3PriceImpact(ctx context.Context, swapParams *SwapParams, mathEngine math.ExchangeMath) float64 {
|
||||
// Get actual pool data from market discovery
|
||||
@@ -546,32 +531,12 @@ func (ta *TransactionAnalyzer) estimateUniswapV3PriceImpact(ctx context.Context,
|
||||
// Access the market discovery to get real pool data
|
||||
poolInfo, err := ta.marketDiscovery.GetPool(ctx, poolAddr)
|
||||
if err != nil || poolInfo == nil || poolInfo.SqrtPriceX96 == nil || poolInfo.Liquidity == nil {
|
||||
// Fallback estimation based on amount if pool info not available
|
||||
amountFloat, _ := new(big.Float).SetInt(swapParams.AmountIn).Float64()
|
||||
if amountFloat > 10e18 { // > 10 ETH
|
||||
return 0.005 // 0.5%
|
||||
} else if amountFloat > 1e18 { // > 1 ETH
|
||||
return 0.002 // 0.2%
|
||||
} else if amountFloat > 0.1e18 { // > 0.1 ETH
|
||||
return 0.0005 // 0.05%
|
||||
} else {
|
||||
return 0.0002 // 0.02%
|
||||
}
|
||||
return ta.estimateFallbackPriceImpact(swapParams.AmountIn)
|
||||
}
|
||||
|
||||
// Check if pool data is properly initialized
|
||||
if poolInfo.SqrtPriceX96 == nil || poolInfo.Liquidity == nil {
|
||||
// Fallback estimation based on amount if pool info not available or improperly initialized
|
||||
amountFloat, _ := new(big.Float).SetInt(swapParams.AmountIn).Float64()
|
||||
if amountFloat > 10e18 { // > 10 ETH
|
||||
return 0.005 // 0.5%
|
||||
} else if amountFloat > 1e18 { // > 1 ETH
|
||||
return 0.002 // 0.2%
|
||||
} else if amountFloat > 0.1e18 { // > 0.1 ETH
|
||||
return 0.0005 // 0.05%
|
||||
} else {
|
||||
return 0.0002 // 0.02%
|
||||
}
|
||||
return ta.estimateFallbackPriceImpact(swapParams.AmountIn)
|
||||
}
|
||||
|
||||
// Convert uint256 values to big.Int for math engine
|
||||
@@ -581,22 +546,26 @@ func (ta *TransactionAnalyzer) estimateUniswapV3PriceImpact(ctx context.Context,
|
||||
// Calculate price impact using V3-specific math with converted values
|
||||
impact, err := mathEngine.CalculatePriceImpact(swapParams.AmountIn, sqrtPriceX96Big, liquidityBig)
|
||||
if err != nil {
|
||||
// Fallback if calculation fails
|
||||
amountFloat, _ := new(big.Float).SetInt(swapParams.AmountIn).Float64()
|
||||
if amountFloat > 10e18 { // > 10 ETH
|
||||
return 0.005 // 0.5%
|
||||
} else if amountFloat > 1e18 { // > 1 ETH
|
||||
return 0.002 // 0.2%
|
||||
} else if amountFloat > 0.1e18 { // > 0.1 ETH
|
||||
return 0.0005 // 0.05%
|
||||
} else {
|
||||
return 0.0002 // 0.02%
|
||||
}
|
||||
return ta.estimateFallbackPriceImpact(swapParams.AmountIn)
|
||||
}
|
||||
|
||||
return impact
|
||||
}
|
||||
|
||||
// estimateFallbackPriceImpact provides a fallback estimation based on amount
|
||||
func (ta *TransactionAnalyzer) estimateFallbackPriceImpact(amountIn *big.Int) float64 {
|
||||
amountFloat, _ := new(big.Float).SetInt(amountIn).Float64()
|
||||
if amountFloat > 10e18 { // > 10 ETH
|
||||
return 0.005 // 0.5%
|
||||
} else if amountFloat > 1e18 { // > 1 ETH
|
||||
return 0.002 // 0.2%
|
||||
} else if amountFloat > 0.1e18 { // > 0.1 ETH
|
||||
return 0.0005 // 0.05%
|
||||
} else {
|
||||
return 0.0002 // 0.02%
|
||||
}
|
||||
}
|
||||
|
||||
// estimateCurvePriceImpact estimates price impact for Curve Finance
|
||||
func (ta *TransactionAnalyzer) estimateCurvePriceImpact(ctx context.Context, swapParams *SwapParams, mathEngine math.ExchangeMath) float64 {
|
||||
// Get actual pool data from market discovery
|
||||
@@ -858,6 +827,10 @@ func (ta *TransactionAnalyzer) findArbitrageOpportunity(ctx context.Context, swa
|
||||
arbOp.Profit = profit
|
||||
arbOp.NetProfit = netProfit
|
||||
arbOp.GasEstimate = gasCost
|
||||
arbOp.EstimatedProfit = profit
|
||||
arbOp.RequiredAmount = amountIn
|
||||
arbOp.DetectedAt = time.Now()
|
||||
arbOp.ExpiresAt = time.Now().Add(5 * time.Minute)
|
||||
|
||||
// Handle empty token addresses to prevent slice bounds panic
|
||||
tokenInDisplay := "unknown"
|
||||
@@ -918,8 +891,6 @@ func (ta *TransactionAnalyzer) findArbitrageOpportunity(ctx context.Context, swa
|
||||
}()
|
||||
|
||||
return arbOp
|
||||
|
||||
return arbOp
|
||||
}
|
||||
|
||||
func (ta *TransactionAnalyzer) findSandwichOpportunity(ctx context.Context, swapData *SwapData, tx *RawL2Transaction) *SandwichOpportunity {
|
||||
|
||||
Reference in New Issue
Block a user