Files
mev-beta/tools/math-audit/regression_test.go
Krypto Kajun 850223a953 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>
2025-10-17 00:12:55 -05:00

323 lines
12 KiB
Go

package main
import (
"fmt"
"math/big"
"testing"
pkgmath "github.com/fraktal/mev-beta/pkg/math"
)
// ProfitThresholdTestCase defines a test case for profit threshold validation
type ProfitThresholdTestCase struct {
Name string
Exchange string
Reserve0 string
Reserve1 string
AmountIn string
ExpectedProfitBP float64 // Expected profit in basis points
ExpectedSpreadBP float64 // Expected spread in basis points
MinProfitThresholdBP float64 // Minimum profit threshold in basis points
Tolerance float64 // Error tolerance in basis points
}
// TestProfitThresholdRegression ensures profit calculations remain stable
func TestProfitThresholdRegression(t *testing.T) {
// Initialize decimal converter
converter := pkgmath.NewDecimalConverter()
testCases := []ProfitThresholdTestCase{
{
Name: "ETH_USDC_Small_Profit",
Exchange: "uniswap_v2",
Reserve0: "1000000000000000000000", // 1000 ETH
Reserve1: "2000000000000", // 2M USDC (6 decimals)
AmountIn: "1000000000000000000", // 1 ETH
ExpectedProfitBP: 25.0, // 0.25% profit expected
ExpectedSpreadBP: 50.0, // 0.5% spread expected
MinProfitThresholdBP: 10.0, // 0.1% minimum profit
Tolerance: 2.0, // 2bp tolerance
},
{
Name: "WBTC_ETH_Medium_Profit",
Exchange: "uniswap_v2",
Reserve0: "50000000000", // 500 WBTC (8 decimals)
Reserve1: "10000000000000000000000", // 10000 ETH
AmountIn: "100000000", // 1 WBTC
ExpectedProfitBP: 35.0, // 0.35% profit expected
ExpectedSpreadBP: 70.0, // 0.7% spread expected
MinProfitThresholdBP: 15.0, // 0.15% minimum profit
Tolerance: 3.0, // 3bp tolerance
},
{
Name: "ETH_USDC_V3_Concentrated",
Exchange: "uniswap_v3",
Reserve0: "1000000000000000000000", // 1000 ETH
Reserve1: "2000000000000", // 2M USDC
AmountIn: "500000000000000000", // 0.5 ETH
ExpectedProfitBP: 15.0, // 0.15% profit expected
ExpectedSpreadBP: 25.0, // 0.25% spread expected
MinProfitThresholdBP: 5.0, // 0.05% minimum profit
Tolerance: 1.5, // 1.5bp tolerance
},
{
Name: "USDC_USDT_Stable_Spread",
Exchange: "curve",
Reserve0: "1000000000000", // 1M USDC (6 decimals)
Reserve1: "1000000000000", // 1M USDT (6 decimals)
AmountIn: "10000000000", // 10k USDC
ExpectedProfitBP: 2.0, // 0.02% profit expected
ExpectedSpreadBP: 5.0, // 0.05% spread expected
MinProfitThresholdBP: 1.0, // 0.01% minimum profit
Tolerance: 0.5, // 0.5bp tolerance
},
{
Name: "ETH_USDC_80_20_Weighted",
Exchange: "balancer",
Reserve0: "800000000000000000000", // 800 ETH
Reserve1: "400000000000", // 400k USDC
AmountIn: "2000000000000000000", // 2 ETH
ExpectedProfitBP: 40.0, // 0.4% profit expected
ExpectedSpreadBP: 80.0, // 0.8% spread expected
MinProfitThresholdBP: 20.0, // 0.2% minimum profit
Tolerance: 5.0, // 5bp tolerance
},
}
for _, tc := range testCases {
t.Run(tc.Name, func(t *testing.T) {
// Calculate actual profit and spread
actualProfitBP, actualSpreadBP, err := calculateProfitAndSpread(converter, tc)
if err != nil {
t.Fatalf("Failed to calculate profit and spread: %v", err)
}
// Validate profit meets minimum threshold
if actualProfitBP < tc.MinProfitThresholdBP {
t.Errorf("Profit %.4f bp below minimum threshold %.4f bp",
actualProfitBP, tc.MinProfitThresholdBP)
}
// Validate profit within expected range
profitError := abs(actualProfitBP - tc.ExpectedProfitBP)
if profitError > tc.Tolerance {
t.Errorf("Profit error %.4f bp exceeds tolerance %.4f bp (expected %.4f bp, got %.4f bp)",
profitError, tc.Tolerance, tc.ExpectedProfitBP, actualProfitBP)
}
// Validate spread within expected range
spreadError := abs(actualSpreadBP - tc.ExpectedSpreadBP)
if spreadError > tc.Tolerance*2 { // Allow 2x tolerance for spread
t.Errorf("Spread error %.4f bp exceeds tolerance %.4f bp (expected %.4f bp, got %.4f bp)",
spreadError, tc.Tolerance*2, tc.ExpectedSpreadBP, actualSpreadBP)
}
t.Logf("✓ %s: Profit=%.4f bp, Spread=%.4f bp (within tolerance)",
tc.Name, actualProfitBP, actualSpreadBP)
})
}
}
// calculateProfitAndSpread calculates profit and spread for a test case
func calculateProfitAndSpread(converter *pkgmath.DecimalConverter, tc ProfitThresholdTestCase) (profitBP, spreadBP float64, err error) {
// Determine decimals based on exchange and tokens
reserve0Decimals, reserve1Decimals := getTokenDecimals(tc.Exchange, tc.Name)
// Convert amounts to UniversalDecimal
reserve0, err := converter.FromString(tc.Reserve0, reserve0Decimals, "TOKEN0")
if err != nil {
return 0, 0, fmt.Errorf("invalid reserve0: %w", err)
}
reserve1, err := converter.FromString(tc.Reserve1, reserve1Decimals, "TOKEN1")
if err != nil {
return 0, 0, fmt.Errorf("invalid reserve1: %w", err)
}
amountIn, err := converter.FromString(tc.AmountIn, reserve0Decimals, "TOKEN0")
if err != nil {
return 0, 0, fmt.Errorf("invalid amountIn: %w", err)
}
// Calculate spot price
var spotPrice *pkgmath.UniversalDecimal
switch tc.Exchange {
case "uniswap_v2":
spotPrice, err = calculateUniswapV2Price(converter, reserve0, reserve1)
case "uniswap_v3":
spotPrice, err = calculateUniswapV3EstimatedPrice(converter, reserve0, reserve1)
case "curve":
spotPrice, err = calculateCurvePrice(converter, reserve0, reserve1)
case "balancer":
spotPrice, err = calculateBalancerPrice(converter, reserve0, reserve1)
default:
return 0, 0, fmt.Errorf("unsupported exchange: %s", tc.Exchange)
}
if err != nil {
return 0, 0, fmt.Errorf("failed to calculate spot price: %w", err)
}
// Calculate amount out using AMM formula
amountOut, err := calculateAMMAmountOut(converter, tc.Exchange, reserve0, reserve1, amountIn)
if err != nil {
return 0, 0, fmt.Errorf("failed to calculate amount out: %w", err)
}
// Calculate execution price
executionPrice := calculateExecutionPrice(converter, amountIn, amountOut, reserve0Decimals, reserve1Decimals)
// Calculate profit (difference from spot price)
profitBP = calculateRelativeErrorBP(converter, spotPrice, executionPrice)
// Calculate spread (bid-ask spread approximation)
spreadBP = profitBP * 2.0 // Simple approximation: spread = 2 * price impact
return profitBP, spreadBP, nil
}
// Helper functions for price calculations
func calculateUniswapV2Price(converter *pkgmath.DecimalConverter, reserve0, reserve1 *pkgmath.UniversalDecimal) (*pkgmath.UniversalDecimal, error) {
// Price = reserve1 / reserve0 (normalized to 18 decimals)
priceInt := new(big.Int).Mul(reserve1.Value, new(big.Int).Exp(big.NewInt(10), big.NewInt(18), nil))
priceInt.Div(priceInt, reserve0.Value)
return pkgmath.NewUniversalDecimal(priceInt, 18, "PRICE")
}
func calculateUniswapV3EstimatedPrice(converter *pkgmath.DecimalConverter, reserve0, reserve1 *pkgmath.UniversalDecimal) (*pkgmath.UniversalDecimal, error) {
// For simplicity, use the same formula as V2 for testing
return calculateUniswapV2Price(converter, reserve0, reserve1)
}
func calculateCurvePrice(converter *pkgmath.DecimalConverter, reserve0, reserve1 *pkgmath.UniversalDecimal) (*pkgmath.UniversalDecimal, error) {
// For stable swaps, price is typically 1:1 with small variations
return calculateUniswapV2Price(converter, reserve0, reserve1)
}
func calculateBalancerPrice(converter *pkgmath.DecimalConverter, reserve0, reserve1 *pkgmath.UniversalDecimal) (*pkgmath.UniversalDecimal, error) {
// Weighted pool: price = (reserve1/weight1) / (reserve0/weight0)
// Assuming 80/20 weights: weight0=0.8, weight1=0.2
// price = (reserve1/0.2) / (reserve0/0.8) = (reserve1 * 0.8) / (reserve0 * 0.2) = (reserve1 * 4) / reserve0
priceInt := new(big.Int).Mul(reserve1.Value, big.NewInt(4))
priceInt.Mul(priceInt, new(big.Int).Exp(big.NewInt(10), big.NewInt(18), nil))
priceInt.Div(priceInt, reserve0.Value)
return pkgmath.NewUniversalDecimal(priceInt, 18, "PRICE")
}
func calculateAMMAmountOut(converter *pkgmath.DecimalConverter, exchange string, reserve0, reserve1, amountIn *pkgmath.UniversalDecimal) (*pkgmath.UniversalDecimal, error) {
// Simplified AMM calculation: k = x * y, amountOut = y - k / (x + amountIn)
// k = reserve0 * reserve1
k := new(big.Int).Mul(reserve0.Value, reserve1.Value)
// newReserve0 = reserve0 + amountIn
newReserve0 := new(big.Int).Add(reserve0.Value, amountIn.Value)
// newReserve1 = k / newReserve0
newReserve1 := new(big.Int).Div(k, newReserve0)
// amountOut = reserve1 - newReserve1
amountOut := new(big.Int).Sub(reserve1.Value, newReserve1)
// Apply 0.3% fee for most exchanges
fee := new(big.Int).Div(amountOut, big.NewInt(333)) // ~0.3%
amountOut.Sub(amountOut, fee)
return pkgmath.NewUniversalDecimal(amountOut, reserve1.Decimals, "TOKEN1")
}
func calculateExecutionPrice(converter *pkgmath.DecimalConverter, amountIn, amountOut *pkgmath.UniversalDecimal, decimalsIn, decimalsOut uint8) *pkgmath.UniversalDecimal {
// Execution price = amountOut / amountIn (normalized to 18 decimals)
priceInt := new(big.Int).Mul(amountOut.Value, new(big.Int).Exp(big.NewInt(10), big.NewInt(18), nil))
priceInt.Div(priceInt, amountIn.Value)
// Adjust for decimal differences
if decimalsOut != decimalsIn {
decimalDiff := int64(decimalsIn) - int64(decimalsOut)
if decimalDiff > 0 {
adjustment := new(big.Int).Exp(big.NewInt(10), big.NewInt(decimalDiff), nil)
priceInt.Mul(priceInt, adjustment)
} else {
adjustment := new(big.Int).Exp(big.NewInt(10), big.NewInt(-decimalDiff), nil)
priceInt.Div(priceInt, adjustment)
}
}
result, _ := pkgmath.NewUniversalDecimal(priceInt, 18, "EXECUTION_PRICE")
return result
}
func calculateRelativeErrorBP(converter *pkgmath.DecimalConverter, expected, actual *pkgmath.UniversalDecimal) float64 {
if expected.Value.Cmp(big.NewInt(0)) == 0 {
return 10000.0 // Max error if expected is zero
}
// Calculate relative error: |actual - expected| / expected * 10000
diff := new(big.Int).Sub(actual.Value, expected.Value)
if diff.Sign() < 0 {
diff.Neg(diff)
}
// Convert to float64 for percentage calculation
diffFloat, _ := new(big.Float).SetInt(diff).Float64()
expectedFloat, _ := new(big.Float).SetInt(expected.Value).Float64()
if expectedFloat == 0 {
return 10000.0
}
return (diffFloat / expectedFloat) * 10000.0
}
func getTokenDecimals(exchange, testName string) (uint8, uint8) {
switch {
case contains(testName, "ETH") && contains(testName, "USDC"):
return 18, 6 // ETH=18, USDC=6
case contains(testName, "WBTC") && contains(testName, "ETH"):
return 8, 18 // WBTC=8, ETH=18
case contains(testName, "USDC") && contains(testName, "USDT"):
return 6, 6 // USDC=6, USDT=6
default:
return 18, 18 // Default to 18 decimals
}
}
func contains(s, substr string) bool {
for i := 0; i <= len(s)-len(substr); i++ {
if s[i:i+len(substr)] == substr {
return true
}
}
return false
}
func abs(x float64) float64 {
if x < 0 {
return -x
}
return x
}
// BenchmarkProfitCalculation benchmarks profit calculation performance
func BenchmarkProfitCalculation(b *testing.B) {
converter := pkgmath.NewDecimalConverter()
tc := ProfitThresholdTestCase{
Name: "ETH_USDC_Benchmark",
Exchange: "uniswap_v2",
Reserve0: "1000000000000000000000",
Reserve1: "2000000000000",
AmountIn: "1000000000000000000",
ExpectedProfitBP: 25.0,
ExpectedSpreadBP: 50.0,
MinProfitThresholdBP: 10.0,
Tolerance: 2.0,
}
b.ResetTimer()
for i := 0; i < b.N; i++ {
_, _, err := calculateProfitAndSpread(converter, tc)
if err != nil {
b.Fatalf("Benchmark failed: %v", err)
}
}
}