Files
mev-beta/docs/MATH_FIX_EXAMPLES_20251101.md

365 lines
11 KiB
Markdown

# Mathematical Fixes - Code Examples
## Issue #1: Profit Margin Cap at 100%
### BEFORE (WRONG):
```go
// profit_calc.go: Lines 199-210
if profitMarginFloat > 1.0 { // 100% profit margin is unrealistic
opportunity.ProfitMargin = 0.0
opportunity.IsExecutable = false
opportunity.RejectReason = "unrealistic profit margin"
opportunity.Confidence = 0.0
} else {
opportunity.ProfitMargin = profitMarginFloat
}
```
**Problem**: This rejects ALL opportunities with >100% profit margin, which is mathematically possible in arbitrage.
### AFTER (CORRECT):
```go
// Remove the arbitrary 100% cap
// Only reject if profit is negative or margin is NaN
if math.IsNaN(profitMarginFloat) {
opportunity.ProfitMargin = 0.0
opportunity.IsExecutable = false
opportunity.RejectReason = "invalid profit margin calculation"
opportunity.Confidence = 0.0
} else if profitMarginFloat < 0 {
opportunity.ProfitMargin = 0.0
opportunity.IsExecutable = false
opportunity.RejectReason = "negative profit margin"
opportunity.Confidence = 0.0
} else {
opportunity.ProfitMargin = profitMarginFloat
// Confidence increases with margin
if profitMarginFloat > 0.5 { // 50% margin
opportunity.Confidence += 0.2
}
}
```
---
## Issue #2: Slippage Calculation Formula
### BEFORE (WRONG):
```go
// slippage_protection.go: Lines 59-67
estimatedSlippage := tradeSizeFloat / 2.0
// Apply curve adjustment for larger trades (non-linear slippage)
if tradeSizeFloat > 0.1 { // > 10% of pool
// Quadratic increase for large trades
estimatedSlippage = estimatedSlippage * (1 + tradeSizeFloat)
}
```
**Problems**:
1. Formula is not based on actual AMM mechanics
2. The "curve adjustment" is arbitrary
3. Doesn't account for fees
### AFTER (CORRECT):
```go
// Implement proper Uniswap V2 constant product formula
// For swap: amountOut = (amountIn * 997 * reserveOut) / (reserveIn * 1000 + amountIn * 997)
// Price impact = 1 - (amountOut / (amountIn * spotPrice))
func (sp *SlippageProtector) CalculateAccurateSlippage(
amountIn *big.Float,
reserveIn *big.Float,
reserveOut *big.Float,
fee uint32, // In basis points, e.g., 3000 for 0.3%
) float64 {
if amountIn.Sign() <= 0 || reserveIn.Sign() <= 0 || reserveOut.Sign() <= 0 {
return 0
}
// Apply fee: amountInWithFee = amountIn * (10000 - fee) / 10000
feeMultiplier := new(big.Float).SetInt64(int64(10000 - fee))
tenThousand := new(big.Float).SetInt64(10000)
feeFactor := new(big.Float).Quo(feeMultiplier, tenThousand)
amountInWithFee := new(big.Float).Mul(amountIn, feeFactor)
// Numerator = amountInWithFee * reserveOut
numerator := new(big.Float).Mul(amountInWithFee, reserveOut)
// Denominator = reserveIn * 10000 + amountInWithFee
reserveInTenK := new(big.Float).Mul(reserveIn, tenThousand)
denominator := new(big.Float).Add(reserveInTenK, amountInWithFee)
// amountOut = numerator / denominator
amountOut := new(big.Float).Quo(numerator, denominator)
// Spot price = reserveOut / reserveIn
spotPrice := new(big.Float).Quo(reserveOut, reserveIn)
// Expected output = amountIn * spotPrice
expectedOut := new(big.Float).Mul(amountIn, spotPrice)
// Slippage = (expectedOut - amountOut) / expectedOut
if expectedOut.Sign() <= 0 {
return 0
}
diff := new(big.Float).Sub(expectedOut, amountOut)
slippageRatio := new(big.Float).Quo(diff, expectedOut)
slippage, _ := slippageRatio.Float64()
if slippage < 0 {
return 0
}
if slippage > 1.0 {
return 1.0
}
return slippage
}
```
---
## Issue #3: Float to Int Conversion for Profit Comparison
### BEFORE (WRONG):
```go
// profit_calc.go: Lines 214-216
if netProfit.Sign() > 0 {
netProfitWei, _ := netProfit.Int(nil) // Truncates decimal places!
if netProfitWei.Cmp(spc.minProfitThreshold) >= 0 {
// Execute opportunity
}
}
```
**Problem**:
- Converts `big.Float` to `big.Int`, truncating all decimal places
- 0.00005 ETH becomes 0 when converted to Int
- Valid opportunities are incorrectly rejected
### AFTER (CORRECT):
```go
// profit_calc.go: Keep netProfit as big.Float
if netProfit.Sign() > 0 {
minThresholdFloat := new(big.Float).SetInt(spc.minProfitThreshold)
minThresholdFloat.Quo(minThresholdFloat, new(big.Float).SetInt64(1e18)) // Convert wei to ETH
if netProfit.Cmp(minThresholdFloat) >= 0 {
// Execute opportunity
}
}
// Or better yet, use UniversalDecimal throughout:
netProfitDecimal := &math.UniversalDecimal{
Value: netProfit.Int(nil), // Only convert when absolutely necessary
Decimals: 18,
Symbol: "ETH",
}
if netProfitDecimal.Cmp(spc.minProfitThresholdDecimal) >= 0 {
// Execute opportunity
}
```
---
## Issue #4: Price Impact Missing Fee Adjustment
### BEFORE (WRONG):
```go
// exchange_math.go: Lines 128-146
amountOut, err := u.CalculateAmountOut(amountIn, reserveIn, reserveOut, 3000)
if err != nil {
return 0, err
}
// WRONG: Using raw amountIn instead of amountInWithFee
newReserveIn := new(big.Int).Add(reserveIn, amountIn) // ← BUG HERE
newReserveOut := new(big.Int).Sub(reserveOut, amountOut)
priceAfter := new(big.Float).Quo(new(big.Float).SetInt(newReserveOut), new(big.Float).SetInt(newReserveIn))
```
**Problem**: Uses raw `amountIn` instead of the fee-adjusted amount, underestimating price impact
### AFTER (CORRECT):
```go
// exchange_math.go: Lines 128-146
amountOut, err := u.CalculateAmountOut(amountIn, reserveIn, reserveOut, 3000)
if err != nil {
return 0, err
}
// Apply fee BEFORE calculating new reserves
if fee == 0 {
fee = 3000
}
feeFactor := big.NewInt(int64(10000 - fee))
amountInWithFee := new(big.Int).Mul(amountIn, feeFactor)
amountInWithFee.Div(amountInWithFee, big.NewInt(10000))
// Use fee-adjusted amount in reserve calculation
newReserveIn := new(big.Int).Add(reserveIn, amountInWithFee) // ← FIXED
newReserveOut := new(big.Int).Sub(reserveOut, amountOut)
priceAfter := new(big.Float).Quo(new(big.Float).SetInt(newReserveOut), new(big.Float).SetInt(newReserveIn))
```
---
## Issue #5: Division by Zero Protection
### BEFORE (WRONG):
```go
// slippage_protection.go: Line 56
tradeSizeRatio := new(big.Float).Quo(tradeAmount, poolLiquidity)
```
**Problem**: No check if `poolLiquidity` is zero
### AFTER (CORRECT):
```go
// Add proper validation
if poolLiquidity == nil || poolLiquidity.Sign() <= 0 {
return &SlippageAnalysis{
IsAcceptable: false,
RiskLevel: "Extreme",
Recommendation: "Invalid pool liquidity for slippage calculation",
}
}
tradeSizeRatio := new(big.Float).Quo(tradeAmount, poolLiquidity)
```
---
## Issue #6: Arbitrary Gas Cost Buffer
### BEFORE (WRONG):
```go
// profit_calc.go: Lines 271-273
// Add 20% buffer for MEV competition
buffer := new(big.Int).Div(gasCostWei, big.NewInt(5)) // 20%
gasCostWei.Add(gasCostWei, buffer)
```
**Problem**: 20% is arbitrary, not based on actual network conditions
### AFTER (CORRECT):
```go
// Dynamic gas adjustment based on network state
func (spc *ProfitCalculator) calculateGasCostWithNetworkAdjustment() *big.Float {
gasLimitInt64, _ := security.SafeUint64ToInt64(spc.gasLimit)
gasLimit := big.NewInt(gasLimitInt64)
currentGasPrice := spc.GetCurrentGasPrice()
gasCostWei := new(big.Int).Mul(currentGasPrice, gasLimit)
// Dynamic buffer based on gas price volatility
gasPrice := spc.GetCurrentGasPrice()
// Get recent gas price trend (this would need implementation)
recentAvgGasPrice := spc.GetRecentAverageGasPrice() // Needs implementation
if gasPrice == nil || recentAvgGasPrice == nil || recentAvgGasPrice.Sign() == 0 {
// Default conservative estimate
buffer := new(big.Int).Div(gasCostWei, big.NewInt(5)) // 20%
gasCostWei.Add(gasCostWei, buffer)
} else {
// Calculate buffer as percentage of price change
priceDiff := new(big.Int).Sub(gasPrice, recentAvgGasPrice)
if priceDiff.Sign() > 0 {
// Gas price is above average - add 10-30% buffer
bufferPercent := calculateBufferPercent(priceDiff, recentAvgGasPrice)
buffer := new(big.Int).Mul(gasCostWei, big.NewInt(int64(bufferPercent)))
buffer.Div(buffer, big.NewInt(100))
gasCostWei.Add(gasCostWei, buffer)
} else {
// Gas price is below average - use minimal buffer
buffer := new(big.Int).Div(gasCostWei, big.NewInt(20)) // 5%
gasCostWei.Add(gasCostWei, buffer)
}
}
// Convert to big.Float for easier calculation
gasCostFloat := new(big.Float).SetInt(gasCostWei)
etherDenominator := new(big.Float).SetInt(big.NewInt(1e18))
return new(big.Float).Quo(gasCostFloat, etherDenominator)
}
```
---
## Issue #7: Proper Rounding for Amount Calculations
### BEFORE (WRONG):
```go
// exchange_math.go: Lines 107-109
// amountIn = numerator / denominator + 1 (round up)
amountIn := new(big.Int).Div(numerator, denominator)
amountIn.Add(amountIn, big.NewInt(1)) // Always adds 1
```
**Problem**: Always adds 1, even when exact division occurs
### AFTER (CORRECT):
```go
// Implement proper banker's rounding (round-half-to-even)
amountIn := new(big.Int).Div(numerator, denominator)
// Check if there's a remainder
remainder := new(big.Int).Mod(numerator, denominator)
if remainder.Sign() > 0 {
// There's a remainder, round up
amountIn.Add(amountIn, big.NewInt(1))
}
// Alternative: Always round up for safety
amountIn := new(big.Int).Add(numerator, new(big.Int).Sub(denominator, big.NewInt(1)))
amountIn.Div(amountIn, denominator)
```
---
## Testing the Fixes
Add these test cases:
```go
func TestProfitMarginWithHighReturns(t *testing.T) {
// Should allow 200% profit margin
profitMargin := 2.0 // 200%
// Should NOT be rejected
if profitMargin > 1.0 {
t.Fatal("Valid 200% profit margin incorrectly rejected")
}
}
func TestSlippageCalculation(t *testing.T) {
// Test against known Uniswap V2 swap
amountIn, _ := new(big.Float).SetString("1000000000000000000") // 1 ETH
reserveIn, _ := new(big.Float).SetString("10000000000000000000") // 10 ETH
reserveOut, _ := new(big.Float).SetString("100000000000000000000") // 100 tokens
slippage := CalculateAccurateSlippage(amountIn, reserveIn, reserveOut, 3000)
// Expected: ~8.26% slippage for this swap
if slippage < 0.08 || slippage > 0.09 {
t.Errorf("Slippage calculation incorrect: got %f, expected ~0.0826", slippage)
}
}
func TestProfitThresholdComparison(t *testing.T) {
// Should accept profits > 0 wei, even very small ones
netProfit := big.NewFloat(0.00000001) // 0.00000001 ETH (10 wei)
minThreshold := big.NewFloat(0.00000000) // 0 wei
if netProfit.Cmp(minThreshold) <= 0 {
t.Fatal("Valid small profit incorrectly rejected")
}
}
```