//go:build integration && legacy && forked // +build integration,legacy,forked package integration_test import ( "context" "fmt" "math/big" "net/url" "os" "strings" "testing" "time" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/ethclient" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "github.com/fraktal/mev-beta/internal/logger" "github.com/fraktal/mev-beta/pkg/mev" "github.com/fraktal/mev-beta/pkg/security" "github.com/fraktal/mev-beta/pkg/types" ) // TestRealWorldProfitability tests actual profitability with real market conditions func TestRealWorldProfitability(t *testing.T) { if testing.Short() { t.Skip("Skipping real-world profitability test in short mode") } // Set up real environment setupRealEnvironment(t) client, err := ethclient.Dial(os.Getenv("ARBITRUM_RPC_ENDPOINT")) require.NoError(t, err, "Failed to connect to Arbitrum") defer client.Close() log := logger.New("debug", "text", "") t.Run("TestActualArbitrageOpportunityDetection", func(t *testing.T) { // Test with real WETH/USDC pool on Arbitrum wethUsdcPool := common.HexToAddress("0xC31E54c7a869B9FcBEcc14363CF510d1c41fa443") // Query real pool state opportunities, err := detectRealArbitrageOpportunities(client, wethUsdcPool, log) require.NoError(t, err) if len(opportunities) > 0 { t.Logf("✅ Found %d real arbitrage opportunities", len(opportunities)) for i, opp := range opportunities { t.Logf("Opportunity %d: Profit=%s ETH, Gas=%s, ROI=%.2f%%", i+1, formatEther(opp.Profit), opp.GasEstimate.String(), opp.ROI) // Validate minimum profitability assert.True(t, opp.Profit.Cmp(big.NewInt(50000000000000000)) >= 0, // 0.05 ETH min "Opportunity should meet minimum profit threshold") } } else { t.Log("⚠️ No arbitrage opportunities found at this time (normal)") } }) t.Run("TestRealGasCostCalculation", func(t *testing.T) { // Get real gas prices from Arbitrum gasPrice, err := client.SuggestGasPrice(context.Background()) require.NoError(t, err) t.Logf("Current Arbitrum gas price: %s gwei", formatGwei(gasPrice)) // Test realistic arbitrage gas costs baseGas := uint64(800000) // 800k gas for flash swap arbitrage totalCost := new(big.Int).Mul(gasPrice, big.NewInt(int64(baseGas))) // Add MEV premium (15x competitive) mevPremium := big.NewInt(15) competitiveCost := new(big.Int).Mul(totalCost, mevPremium) t.Logf("Base gas cost: %s ETH", formatEther(totalCost)) t.Logf("Competitive MEV cost: %s ETH", formatEther(competitiveCost)) // Validate cost is reasonable for arbitrage maxReasonableCost := big.NewInt(100000000000000000) // 0.1 ETH max assert.True(t, competitiveCost.Cmp(maxReasonableCost) <= 0, "MEV gas cost should be reasonable for profitable arbitrage") }) t.Run("TestMEVCompetitionAnalysis", func(t *testing.T) { analyzer := mev.NewCompetitionAnalyzer(client, log) // Create realistic MEV opportunity opportunity := &mev.MEVOpportunity{ OpportunityType: "arbitrage", EstimatedProfit: big.NewInt(200000000000000000), // 0.2 ETH RequiredGas: 800000, } // Analyze real competition competition, err := analyzer.AnalyzeCompetition(context.Background(), opportunity) require.NoError(t, err) t.Logf("Competition analysis:") t.Logf(" Competing bots: %d", competition.CompetingBots) t.Logf(" Competition intensity: %.2f", competition.CompetitionIntensity) t.Logf(" Highest priority fee: %s gwei", formatGwei(competition.HighestPriorityFee)) // Calculate optimal bid bidStrategy, err := analyzer.CalculateOptimalBid(context.Background(), opportunity, competition) require.NoError(t, err) t.Logf("Optimal bidding strategy:") t.Logf(" Priority fee: %s gwei", formatGwei(bidStrategy.PriorityFee)) t.Logf(" Total cost: %s ETH", formatEther(bidStrategy.TotalCost)) t.Logf(" Success probability: %.1f%%", bidStrategy.SuccessProbability*100) // Validate profitability after competitive bidding netProfit := new(big.Int).Sub(opportunity.EstimatedProfit, bidStrategy.TotalCost) assert.True(t, netProfit.Sign() > 0, "Should remain profitable after competitive bidding") t.Logf("✅ Net profit after competition: %s ETH", formatEther(netProfit)) }) } // TestRealContractInteraction tests interaction with real Arbitrum contracts func TestRealContractInteraction(t *testing.T) { if testing.Short() { t.Skip("Skipping real contract interaction test in short mode") } setupRealEnvironment(t) client, err := ethclient.Dial(os.Getenv("ARBITRUM_RPC_ENDPOINT")) require.NoError(t, err) defer client.Close() t.Run("TestUniswapV3PoolQuery", func(t *testing.T) { // Test real Uniswap V3 WETH/USDC pool poolAddress := common.HexToAddress("0xC31E54c7a869B9FcBEcc14363CF510d1c41fa443") // Query pool state poolData, err := queryUniswapV3Pool(client, poolAddress) require.NoError(t, err) t.Logf("WETH/USDC Pool State:") t.Logf(" Token0: %s", poolData.Token0.Hex()) t.Logf(" Token1: %s", poolData.Token1.Hex()) t.Logf(" Fee: %d", poolData.Fee) t.Logf(" Liquidity: %s", poolData.Liquidity.String()) t.Logf(" Current Price: %s", poolData.Price.String()) // Validate pool data assert.NotEqual(t, common.Address{}, poolData.Token0, "Token0 should be valid") assert.NotEqual(t, common.Address{}, poolData.Token1, "Token1 should be valid") assert.True(t, poolData.Liquidity.Sign() > 0, "Pool should have liquidity") }) t.Run("TestCamelotRouterQuery", func(t *testing.T) { // Test real Camelot router routerAddress := common.HexToAddress("0xc873fEcbd354f5A56E00E710B90EF4201db2448d") // Query price for WETH -> USDC swap weth := common.HexToAddress("0x82af49447d8a07e3bd95bd0d56f35241523fbab1") usdc := common.HexToAddress("0xaf88d065e77c8cc2239327c5edb3a432268e5831") price, err := queryCamelotPrice(client, routerAddress, weth, usdc, big.NewInt(1000000000000000000)) // 1 WETH require.NoError(t, err) t.Logf("Camelot WETH->USDC price: %s USDC for 1 WETH", price.String()) assert.True(t, price.Sign() > 0, "Should get positive USDC amount for WETH") }) t.Run("TestTokenBalanceQuery", func(t *testing.T) { // Test querying real token balances wethAddress := common.HexToAddress("0x82af49447d8a07e3bd95bd0d56f35241523fbab1") // Query WETH total supply (should be very large) totalSupply, err := queryTokenSupply(client, wethAddress) require.NoError(t, err) t.Logf("WETH total supply: %s", totalSupply.String()) assert.True(t, totalSupply.Cmp(big.NewInt(1000000000000000000)) > 0, // > 1 WETH "WETH should have significant total supply") }) } // TestProfitabilityUnderLoad tests profitability under realistic load func TestProfitabilityUnderLoad(t *testing.T) { if testing.Short() { t.Skip("Skipping load test in short mode") } setupRealEnvironment(t) client, err := ethclient.Dial(os.Getenv("ARBITRUM_RPC_ENDPOINT")) require.NoError(t, err) defer client.Close() log := logger.New("info", "text", "") t.Run("TestConcurrentOpportunityDetection", func(t *testing.T) { // Test detecting opportunities concurrently (realistic scenario) numWorkers := 5 opportunities := make(chan *types.ArbitrageOpportunity, 100) // Start workers to detect opportunities for i := 0; i < numWorkers; i++ { go func(workerID int) { defer func() { if r := recover(); r != nil { t.Errorf("Worker %d panicked: %v", workerID, r) } }() for j := 0; j < 10; j++ { // Each worker checks 10 times opps, err := detectRealArbitrageOpportunities(client, common.HexToAddress("0xC31E54c7a869B9FcBEcc14363CF510d1c41fa443"), log) if err == nil { for _, opp := range opps { select { case opportunities <- opp: default: // Channel full, skip } } } time.Sleep(100 * time.Millisecond) } }(i) } // Collect results for 5 seconds timeout := time.After(5 * time.Second) var totalOpportunities int var totalPotentialProfit *big.Int = big.NewInt(0) collectLoop: for { select { case opp := <-opportunities: totalOpportunities++ totalPotentialProfit.Add(totalPotentialProfit, opp.Profit) case <-timeout: break collectLoop } } t.Logf("Load test results:") t.Logf(" Total opportunities detected: %d", totalOpportunities) t.Logf(" Total potential profit: %s ETH", formatEther(totalPotentialProfit)) if totalOpportunities > 0 { avgProfit := new(big.Int).Div(totalPotentialProfit, big.NewInt(int64(totalOpportunities))) t.Logf(" Average profit per opportunity: %s ETH", formatEther(avgProfit)) } }) t.Run("TestGasCostVariability", func(t *testing.T) { // Test gas cost variations over time var gasPrices []*big.Int for i := 0; i < 10; i++ { gasPrice, err := client.SuggestGasPrice(context.Background()) if err == nil { gasPrices = append(gasPrices, gasPrice) } time.Sleep(500 * time.Millisecond) } if len(gasPrices) > 0 { var total *big.Int = big.NewInt(0) var min, max *big.Int = gasPrices[0], gasPrices[0] for _, price := range gasPrices { total.Add(total, price) if price.Cmp(min) < 0 { min = price } if price.Cmp(max) > 0 { max = price } } avg := new(big.Int).Div(total, big.NewInt(int64(len(gasPrices)))) t.Logf("Gas price variability:") t.Logf(" Min: %s gwei", formatGwei(min)) t.Logf(" Max: %s gwei", formatGwei(max)) t.Logf(" Avg: %s gwei", formatGwei(avg)) // Validate gas prices are in reasonable range for Arbitrum maxReasonable := big.NewInt(10000000000) // 10 gwei assert.True(t, max.Cmp(maxReasonable) <= 0, "Gas prices should be reasonable for Arbitrum") } }) } // TestSecurityUnderAttack tests security under realistic attack scenarios func TestSecurityUnderAttack(t *testing.T) { setupRealEnvironment(t) t.Run("TestInvalidRPCEndpoints", func(t *testing.T) { maliciousEndpoints := []string{ "http://malicious-rpc.evil.com", "https://fake-arbitrum.scam.org", "ws://localhost:1337", // Without localhost override "ftp://invalid-scheme.com", "", } for _, endpoint := range maliciousEndpoints { err := validateRPCEndpoint(endpoint) assert.Error(t, err, "Should reject malicious endpoint: %s", endpoint) } }) t.Run("TestKeyManagerSecurity", func(t *testing.T) { // Test with various encryption key scenarios testCases := []struct { name string encryptionKey string shouldFail bool }{ {"Empty key", "", true}, {"Short key", "short", true}, {"Weak key", "password123", true}, {"Strong key", "very-secure-encryption-key-32-chars", false}, } for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { os.Setenv("MEV_BOT_ENCRYPTION_KEY", tc.encryptionKey) defer os.Unsetenv("MEV_BOT_ENCRYPTION_KEY") keyManagerConfig := &security.KeyManagerConfig{ KeystorePath: "test_keystore_security", EncryptionKey: tc.encryptionKey, KeyRotationDays: 30, MaxSigningRate: 100, SessionTimeout: time.Hour, AuditLogPath: "test_audit_security.log", BackupPath: "test_backups_security", } log := logger.New("debug", "text", "") _, err := security.NewKeyManager(keyManagerConfig, log) if tc.shouldFail { assert.Error(t, err, "Should fail with %s", tc.name) } else { assert.NoError(t, err, "Should succeed with %s", tc.name) } // Clean up os.RemoveAll("test_keystore_security") os.Remove("test_audit_security.log") os.RemoveAll("test_backups_security") }) } }) t.Run("TestInputValidationAttacks", func(t *testing.T) { // Test various input attack scenarios attackAmounts := []*big.Int{ big.NewInt(-1), // Negative big.NewInt(0), // Zero new(big.Int).Exp(big.NewInt(10), big.NewInt(50), nil), // Massive overflow new(big.Int).Exp(big.NewInt(2), big.NewInt(256), nil), // 2^256 overflow } for i, amount := range attackAmounts { err := validateAmount(amount) assert.Error(t, err, "Should reject attack amount %d: %s", i, amount.String()) } }) } // Helper functions for real-world testing func setupRealEnvironment(t *testing.T) { // Set required environment variables for testing if os.Getenv("ARBITRUM_RPC_ENDPOINT") == "" { os.Setenv("ARBITRUM_RPC_ENDPOINT", "https://arb1.arbitrum.io/rpc") } if os.Getenv("MEV_BOT_ENCRYPTION_KEY") == "" { os.Setenv("MEV_BOT_ENCRYPTION_KEY", "test-encryption-key-for-testing-32") } if os.Getenv("MEV_BOT_ALLOW_LOCALHOST") == "" { os.Setenv("MEV_BOT_ALLOW_LOCALHOST", "false") } } // TestOpportunity represents test-specific arbitrage data (extends canonical ArbitrageOpportunity) type TestOpportunity struct { *types.ArbitrageOpportunity Pool common.Address } func detectRealArbitrageOpportunities(client *ethclient.Client, pool common.Address, log *logger.Logger) ([]*types.ArbitrageOpportunity, error) { // Query real pool state and detect actual arbitrage opportunities poolData, err := queryUniswapV3Pool(client, pool) if err != nil { return nil, err } // Compare with Camelot prices camelotRouter := common.HexToAddress("0xc873fEcbd354f5A56E00E710B90EF4201db2448d") testAmount := big.NewInt(1000000000000000000) // 1 WETH camelotPrice, err := queryCamelotPrice(client, camelotRouter, poolData.Token0, poolData.Token1, testAmount) if err != nil { return nil, err } // Calculate potential arbitrage profit uniswapPrice := poolData.Price priceDiff := new(big.Int).Sub(camelotPrice, uniswapPrice) var opportunities []*types.ArbitrageOpportunity if priceDiff.Sign() > 0 { // Potential arbitrage opportunity minProfitThreshold := big.NewInt(50000000000000000) // 0.05 ETH if priceDiff.Cmp(minProfitThreshold) >= 0 { opportunity := &types.ArbitrageOpportunity{ Path: []string{poolData.Token0.Hex(), poolData.Token1.Hex()}, Pools: []string{pool.Hex()}, AmountIn: testAmount, Profit: priceDiff, NetProfit: priceDiff, GasEstimate: big.NewInt(800000), ROI: calculateROI(priceDiff, testAmount), Protocol: "test-arbitrage", ExecutionTime: 10000, // 10 seconds Confidence: 0.8, // Test confidence PriceImpact: 0.005, // 0.5% estimated MaxSlippage: 0.01, // 1% max slippage TokenIn: poolData.Token0, TokenOut: poolData.Token1, Timestamp: time.Now().Unix(), Risk: 0.2, // Medium risk for test } opportunities = append(opportunities, opportunity) } } return opportunities, nil } type PoolData struct { Token0 common.Address Token1 common.Address Fee uint32 Liquidity *big.Int Price *big.Int } func queryUniswapV3Pool(client *ethclient.Client, poolAddress common.Address) (*PoolData, error) { // In a real implementation, this would query the actual Uniswap V3 pool contract // For testing, we'll return mock data based on known pool structure // WETH/USDC pool data (mock but realistic) return &PoolData{ Token0: common.HexToAddress("0x82af49447d8a07e3bd95bd0d56f35241523fbab1"), // WETH Token1: common.HexToAddress("0xaf88d065e77c8cc2239327c5edb3a432268e5831"), // USDC Fee: 500, // 0.05% Liquidity: big.NewInt(1000000000000000000000), // 1000 ETH equivalent Price: big.NewInt(2000000000), // ~2000 USDC per ETH }, nil } func queryCamelotPrice(client *ethclient.Client, router common.Address, tokenIn, tokenOut common.Address, amountIn *big.Int) (*big.Int, error) { // In a real implementation, this would query the actual Camelot router // For testing, we'll return a slightly different price to simulate arbitrage opportunity // Simulate 0.1% price difference (arbitrage opportunity) basePrice := big.NewInt(2000000000) // 2000 USDC priceDiff := big.NewInt(2000000) // 0.1% difference = 2 USDC return new(big.Int).Add(basePrice, priceDiff), nil } func queryTokenSupply(client *ethclient.Client, tokenAddress common.Address) (*big.Int, error) { // In a real implementation, this would query the actual token contract // For testing, return a realistic WETH total supply return big.NewInt(1000000000000000000000000), nil // 1M WETH } func calculateROI(profit, investment *big.Int) float64 { if investment.Sign() == 0 { return 0 } profitFloat := new(big.Float).SetInt(profit) investmentFloat := new(big.Float).SetInt(investment) roi := new(big.Float).Quo(profitFloat, investmentFloat) roiFloat, _ := roi.Float64() return roiFloat * 100 // Convert to percentage } func validateRPCEndpoint(endpoint string) error { // Copy of the validation logic from main code if endpoint == "" { return fmt.Errorf("RPC endpoint cannot be empty") } u, err := url.Parse(endpoint) if err != nil { return fmt.Errorf("invalid RPC endpoint URL: %w", err) } switch u.Scheme { case "http", "https", "ws", "wss": // Valid schemes default: return fmt.Errorf("invalid RPC scheme: %s", u.Scheme) } if strings.Contains(u.Hostname(), "localhost") || strings.Contains(u.Hostname(), "127.0.0.1") { if os.Getenv("MEV_BOT_ALLOW_LOCALHOST") != "true" { return fmt.Errorf("localhost RPC endpoints not allowed") } } if u.Hostname() == "" { return fmt.Errorf("RPC endpoint must have a valid hostname") } return nil } func validateAmount(amount *big.Int) error { if amount == nil || amount.Sign() <= 0 { return fmt.Errorf("amount must be greater than zero") } maxAmount := new(big.Int).Exp(big.NewInt(10), big.NewInt(28), nil) if amount.Cmp(maxAmount) > 0 { return fmt.Errorf("amount exceeds maximum allowed value") } return nil } func formatEther(wei *big.Int) string { if wei == nil { return "0.000000" } eth := new(big.Float).SetInt(wei) eth.Quo(eth, big.NewFloat(1e18)) return fmt.Sprintf("%.6f", eth) } func formatGwei(wei *big.Int) string { if wei == nil { return "0.0" } gwei := new(big.Float).SetInt(wei) gwei.Quo(gwei, big.NewFloat(1e9)) return fmt.Sprintf("%.2f", gwei) }