//go:build integration && legacy && forked // +build integration,legacy,forked package integration_test import ( "context" "math/big" "testing" "time" "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/crypto" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "github.com/fraktal/mev-beta/bindings/arbitrage" arbService "github.com/fraktal/mev-beta/pkg/arbitrage" "github.com/fraktal/mev-beta/pkg/mev" "github.com/fraktal/mev-beta/pkg/oracle" "github.com/fraktal/mev-beta/pkg/uniswap" ) func TestEndToEndProfitValidation(t *testing.T) { client, cleanup := setupForkedArbitrum(t) defer cleanup() // Deploy arbitrage contract privateKey, err := crypto.GenerateKey() require.NoError(t, err) auth, err := bind.NewKeyedTransactorWithChainID(privateKey, big.NewInt(42161)) require.NoError(t, err) contractAddr, tx, contract, err := arbitrage.DeployArbitrageExecutor( auth, client, common.HexToAddress("0x1F98431c8aD98523631AE4a59f267346ea31F984"), // Uniswap V3 Factory common.HexToAddress("0x82aF49447D8a07e3bd95BD0d56f35241523fBab1"), // WETH ) require.NoError(t, err) ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second) defer cancel() receipt, err := bind.WaitMined(ctx, client, tx) require.NoError(t, err) require.Equal(t, types.ReceiptStatusSuccessful, receipt.Status) t.Run("Real Market Arbitrage Opportunity", func(t *testing.T) { // Real Arbitrum pool addresses with different fee tiers wethUsdcPool05 := common.HexToAddress("0xC31E54c7a869B9FcBEcc14363CF510d1c41fa443") // 0.05% wethUsdcPool30 := common.HexToAddress("0x17c14D2c404D167802b16C450d3c99F88F2c4F4d") // 0.3% // Get current prices from both pools price1, err := uniswap.GetPoolPrice(client, wethUsdcPool05) require.NoError(t, err) price2, err := uniswap.GetPoolPrice(client, wethUsdcPool30) require.NoError(t, err) t.Logf("Pool 1 (0.05%%) price: %s", price1.String()) t.Logf("Pool 2 (0.30%%) price: %s", price2.String()) // Calculate price difference priceDiff := new(big.Int).Sub(price1, price2) if priceDiff.Sign() < 0 { priceDiff.Neg(priceDiff) } // Calculate percentage difference priceDiffPercent := new(big.Int).Div( new(big.Int).Mul(priceDiff, big.NewInt(10000)), price1, ) t.Logf("Price difference: %s (%s basis points)", priceDiff.String(), priceDiffPercent.String()) // Test arbitrage opportunity detection swapAmount := big.NewInt(1000000000000000000) // 1 ETH opportunity, err := contract.DetectArbitrageOpportunity(nil, wethUsdcPool05, wethUsdcPool30, swapAmount) require.NoError(t, err) if opportunity.Profitable { t.Logf("Arbitrage opportunity detected!") t.Logf("Estimated profit: %s ETH", new(big.Float).Quo( new(big.Float).SetInt(opportunity.EstimatedProfit), new(big.Float).SetInt(big.NewInt(1000000000000000000)), ).String()) // Validate minimum profit threshold minProfit := big.NewInt(10000000000000000) // 0.01 ETH minimum assert.GreaterOrEqual(t, opportunity.EstimatedProfit.Cmp(minProfit), 0, "Profit should meet minimum threshold") // Test gas cost calculation gasPrice, err := client.SuggestGasPrice(context.Background()) require.NoError(t, err) estimatedGas := big.NewInt(300000) // Estimated gas for arbitrage gasCost := new(big.Int).Mul(gasPrice, estimatedGas) netProfit := new(big.Int).Sub(opportunity.EstimatedProfit, gasCost) t.Logf("Gas cost: %s ETH", new(big.Float).Quo( new(big.Float).SetInt(gasCost), new(big.Float).SetInt(big.NewInt(1000000000000000000)), ).String()) t.Logf("Net profit: %s ETH", new(big.Float).Quo( new(big.Float).SetInt(netProfit), new(big.Float).SetInt(big.NewInt(1000000000000000000)), ).String()) assert.Greater(t, netProfit.Sign(), 0, "Net profit should be positive after gas costs") } else { t.Log("No profitable arbitrage opportunity detected in current market conditions") } }) t.Run("Simulate Large Trade Impact", func(t *testing.T) { // Simulate a large trade that creates arbitrage opportunity wethUsdcPool := common.HexToAddress("0xC31E54c7a869B9FcBEcc14363CF510d1c41fa443") // Large swap amount that should create price impact largeSwapAmount := new(big.Int) largeSwapAmount.SetString("100000000000000000000", 10) // 100 ETH // Calculate price impact priceImpact, err := contract.CalculatePriceImpact(nil, wethUsdcPool, largeSwapAmount, true) require.NoError(t, err) t.Logf("Price impact for 100 ETH swap: %s basis points", priceImpact.String()) // Price impact should be significant for large trades assert.Greater(t, priceImpact.Uint64(), uint64(100), "Large trades should have measurable price impact") // Test if this creates arbitrage opportunities if priceImpact.Uint64() > 500 { // More than 5% price impact // This should create profitable arbitrage opportunities t.Log("Large trade creates significant arbitrage opportunity") } }) t.Run("Multi-Pool Arbitrage Chain", func(t *testing.T) { // Test arbitrage opportunities across multiple pools pools := []common.Address{ common.HexToAddress("0xC31E54c7a869B9FcBEcc14363CF510d1c41fa443"), // WETH/USDC 0.05% common.HexToAddress("0x17c14D2c404D167802b16C450d3c99F88F2c4F4d"), // WETH/USDC 0.3% common.HexToAddress("0x641C00A822e8b671738d32a431a4Fb6074E5c79d"), // WETH/USDT 0.05% } swapAmount := big.NewInt(5000000000000000000) // 5 ETH totalOpportunities := 0 totalPotentialProfit := big.NewInt(0) for i := 0; i < len(pools); i++ { for j := i + 1; j < len(pools); j++ { opportunity, err := contract.DetectArbitrageOpportunity(nil, pools[i], pools[j], swapAmount) require.NoError(t, err) if opportunity.Profitable { totalOpportunities++ totalPotentialProfit.Add(totalPotentialProfit, opportunity.EstimatedProfit) t.Logf("Opportunity between pool %d and %d: %s ETH profit", i, j, new(big.Float).Quo( new(big.Float).SetInt(opportunity.EstimatedProfit), new(big.Float).SetInt(big.NewInt(1000000000000000000)), ).String()) } } } t.Logf("Total opportunities found: %d", totalOpportunities) t.Logf("Total potential profit: %s ETH", new(big.Float).Quo( new(big.Float).SetInt(totalPotentialProfit), new(big.Float).SetInt(big.NewInt(1000000000000000000)), ).String()) }) } func TestRealWorldGasOptimization(t *testing.T) { client, cleanup := setupForkedArbitrum(t) defer cleanup() t.Run("Gas Price Strategy Optimization", func(t *testing.T) { // Get current network conditions gasPrice, err := client.SuggestGasPrice(context.Background()) require.NoError(t, err) // Get latest block for base fee (EIP-1559) header, err := client.HeaderByNumber(context.Background(), nil) require.NoError(t, err) baseFee := header.BaseFee t.Logf("Current gas price: %s gwei", new(big.Int).Div(gasPrice, big.NewInt(1000000000))) t.Logf("Current base fee: %s gwei", new(big.Int).Div(baseFee, big.NewInt(1000000000))) // Test MEV competition analysis analyzer := mev.NewCompetitionAnalyzer(client) opportunity := &mev.MEVOpportunity{ Type: mev.TypeArbitrage, EstimatedProfit: big.NewInt(50000000000000000), // 0.05 ETH RequiredGasLimit: big.NewInt(300000), PoolAddress: common.HexToAddress("0xC31E54c7a869B9FcBEcc14363CF510d1c41fa443"), Timestamp: time.Now(), } ctx := context.Background() competition, err := analyzer.AnalyzeCompetition(ctx, opportunity) require.NoError(t, err) strategy, err := analyzer.CalculateOptimalBid(ctx, opportunity, competition) require.NoError(t, err) t.Logf("Recommended priority fee: %s gwei", new(big.Int).Div(strategy.PriorityFeePerGas, big.NewInt(1000000000))) t.Logf("Max fee per gas: %s gwei", new(big.Int).Div(strategy.MaxFeePerGas, big.NewInt(1000000000))) t.Logf("Expected profit after gas: %s ETH", new(big.Float).Quo( new(big.Float).SetInt(strategy.ExpectedProfit), new(big.Float).SetInt(big.NewInt(1000000000000000000)), ).String()) // Validate strategy is profitable assert.Greater(t, strategy.ExpectedProfit.Sign(), 0, "Strategy should be profitable after gas costs") assert.LessOrEqual(t, strategy.MaxFeePerGas.Cmp(new(big.Int).Mul(baseFee, big.NewInt(3))), 0, "Max fee should not exceed 3x base fee for reasonable execution") }) t.Run("Gas Limit Optimization", func(t *testing.T) { // Test different gas limits for arbitrage execution gasLimits := []*big.Int{ big.NewInt(250000), big.NewInt(300000), big.NewInt(400000), big.NewInt(500000), } profit := big.NewInt(80000000000000000) // 0.08 ETH base profit gasPrice := big.NewInt(10000000000) // 10 gwei bestGasLimit := big.NewInt(0) bestNetProfit := big.NewInt(0) for _, gasLimit := range gasLimits { gasCost := new(big.Int).Mul(gasPrice, gasLimit) netProfit := new(big.Int).Sub(profit, gasCost) t.Logf("Gas limit %s: Net profit %s ETH", gasLimit.String(), new(big.Float).Quo( new(big.Float).SetInt(netProfit), new(big.Float).SetInt(big.NewInt(1000000000000000000)), ).String()) if netProfit.Cmp(bestNetProfit) > 0 { bestNetProfit.Set(netProfit) bestGasLimit.Set(gasLimit) } } t.Logf("Optimal gas limit: %s", bestGasLimit.String()) assert.Greater(t, bestGasLimit.Uint64(), uint64(0), "Should find optimal gas limit") }) } func TestRealMarketConditions(t *testing.T) { client, cleanup := setupForkedArbitrum(t) defer cleanup() t.Run("Market Volatility Impact", func(t *testing.T) { // Test arbitrage detection under different market conditions service, err := arbService.NewArbitrageService(client) require.NoError(t, err) // Create events representing different market conditions volatileEvents := []*arbService.SimpleSwapEvent{ // Small trade - normal market { TxHash: common.HexToHash("0x1"), Pool: common.HexToAddress("0xC31E54c7a869B9FcBEcc14363CF510d1c41fa443"), Token0: common.HexToAddress("0x82aF49447D8a07e3bd95BD0d56f35241523fBab1"), Token1: common.HexToAddress("0xaf88d065e77c8cC2239327C5EDb3A432268e5831"), Amount0: big.NewInt(1000000000000000000), // 1 ETH Amount1: big.NewInt(-2000000000), // -2000 USDC SqrtPriceX96: func() *big.Int { x, _ := new(big.Int).SetString("79228162514264337593543950336", 10); return x }(), }, // Large trade - volatile market { TxHash: common.HexToHash("0x2"), Pool: common.HexToAddress("0xC31E54c7a869B9FcBEcc14363CF510d1c41fa443"), Token0: common.HexToAddress("0x82aF49447D8a07e3bd95BD0d56f35241523fBab1"), Token1: common.HexToAddress("0xaf88d065e77c8cC2239327C5EDb3A432268e5831"), Amount0: func() *big.Int { x, _ := new(big.Int).SetString("50000000000000000000", 10); return x }(), // 50 ETH Amount1: big.NewInt(-100000000000), // -100,000 USDC SqrtPriceX96: func() *big.Int { x, _ := new(big.Int).SetString("80000000000000000000000000000", 10); return x }(), }, } detectedOpportunities := 0 for i, event := range volatileEvents { err := service.ProcessSwapEvent(event) require.NoError(t, err) // Check if this event would trigger arbitrage detection if service.IsSignificantSwap(event) { detectedOpportunities++ t.Logf("Event %d triggered arbitrage detection (amount: %s ETH)", i+1, new(big.Float).Quo( new(big.Float).SetInt(event.Amount0), new(big.Float).SetInt(big.NewInt(1000000000000000000)), ).String()) } } assert.Greater(t, detectedOpportunities, 0, "Should detect opportunities in volatile market") }) t.Run("Oracle Price Validation", func(t *testing.T) { // Test oracle-based price validation for arbitrage priceOracle := oracle.NewPriceOracle(client) // WETH/USDC price from different sources wethAddress := common.HexToAddress("0x82aF49447D8a07e3bd95BD0d56f35241523fBab1") usdcAddress := common.HexToAddress("0xaf88d065e77c8cC2239327C5EDb3A432268e5831") ctx := context.Background() // Get price from Uniswap V3 uniPrice, err := priceOracle.GetUniswapV3Price(ctx, wethAddress, usdcAddress, 500) require.NoError(t, err) // Get price from alternative DEX (SushiSwap) sushiPrice, err := priceOracle.GetSushiSwapPrice(ctx, wethAddress, usdcAddress) require.NoError(t, err) t.Logf("Uniswap V3 WETH/USDC price: %s", uniPrice.String()) t.Logf("SushiSwap WETH/USDC price: %s", sushiPrice.String()) // Calculate price deviation priceDiff := new(big.Int).Sub(uniPrice, sushiPrice) if priceDiff.Sign() < 0 { priceDiff.Neg(priceDiff) } deviationPercent := new(big.Int).Div( new(big.Int).Mul(priceDiff, big.NewInt(10000)), uniPrice, ) t.Logf("Price deviation: %s basis points", deviationPercent.String()) // Significant price deviation indicates arbitrage opportunity if deviationPercent.Uint64() > 50 { // More than 0.5% t.Log("Significant price deviation detected - potential arbitrage opportunity") assert.Greater(t, deviationPercent.Uint64(), uint64(50), "Price deviation indicates opportunity") } else { t.Log("Prices are aligned - no immediate arbitrage opportunity") } }) t.Run("Liquidity Depth Analysis", func(t *testing.T) { // Test liquidity depth for arbitrage execution pools := []common.Address{ common.HexToAddress("0xC31E54c7a869B9FcBEcc14363CF510d1c41fa443"), // WETH/USDC 0.05% common.HexToAddress("0x17c14D2c404D167802b16C450d3c99F88F2c4F4d"), // WETH/USDC 0.3% } for i, pool := range pools { liquidity, err := uniswap.GetPoolLiquidity(client, pool) require.NoError(t, err) t.Logf("Pool %d liquidity: %s", i+1, liquidity.String()) // Minimum liquidity threshold for profitable arbitrage minLiquidity := new(big.Int) minLiquidity.SetString("1000000000000000000000", 10) // 1000 ETH equivalent if liquidity.Cmp(minLiquidity) >= 0 { t.Logf("Pool %d has sufficient liquidity for large arbitrage", i+1) } else { t.Logf("Pool %d has limited liquidity - small arbitrage only", i+1) } assert.Greater(t, liquidity.Uint64(), uint64(0), "Pool should have measurable liquidity") } }) } func TestProfitabilityUnderStress(t *testing.T) { client, cleanup := setupForkedArbitrum(t) defer cleanup() t.Run("High Gas Price Environment", func(t *testing.T) { // Simulate high gas price conditions (network congestion) highGasPrice := big.NewInt(50000000000) // 50 gwei opportunity := &mev.MEVOpportunity{ Type: mev.TypeArbitrage, EstimatedProfit: big.NewInt(30000000000000000), // 0.03 ETH RequiredGasLimit: big.NewInt(300000), PoolAddress: common.HexToAddress("0xC31E54c7a869B9FcBEcc14363CF510d1c41fa443"), Timestamp: time.Now(), } gasCost := new(big.Int).Mul(highGasPrice, opportunity.RequiredGasLimit) netProfit := new(big.Int).Sub(opportunity.EstimatedProfit, gasCost) t.Logf("High gas environment - Gas cost: %s ETH, Net profit: %s ETH", new(big.Float).Quo(new(big.Float).SetInt(gasCost), new(big.Float).SetInt(big.NewInt(1e18))), new(big.Float).Quo(new(big.Float).SetInt(netProfit), new(big.Float).SetInt(big.NewInt(1e18)))) if netProfit.Sign() > 0 { t.Log("Arbitrage remains profitable even with high gas prices") } else { t.Log("High gas prices make arbitrage unprofitable") } }) t.Run("MEV Competition Pressure", func(t *testing.T) { // Simulate competitive MEV environment analyzer := mev.NewCompetitionAnalyzer(client) opportunity := &mev.MEVOpportunity{ Type: mev.TypeArbitrage, EstimatedProfit: big.NewInt(100000000000000000), // 0.1 ETH RequiredGasLimit: big.NewInt(300000), PoolAddress: common.HexToAddress("0xC31E54c7a869B9FcBEcc14363CF510d1c41fa443"), Timestamp: time.Now(), } ctx := context.Background() // Simulate different competition levels competitionLevels := []string{"low", "medium", "high", "extreme"} for _, level := range competitionLevels { // Mock competition metrics based on level competition := &mev.CompetitionMetrics{ CompetitorCount: getCompetitorCount(level), AveragePriorityFee: getAveragePriorityFee(level), SuccessRate: getSuccessRate(level), RecentOpportunities: 10, } strategy, err := analyzer.CalculateOptimalBid(ctx, opportunity, competition) require.NoError(t, err) t.Logf("Competition level %s: Priority fee %s gwei, Expected profit %s ETH", level, new(big.Int).Div(strategy.PriorityFeePerGas, big.NewInt(1e9)), new(big.Float).Quo(new(big.Float).SetInt(strategy.ExpectedProfit), new(big.Float).SetInt(big.NewInt(1e18)))) // Even under extreme competition, some profit should remain if level != "extreme" { assert.Greater(t, strategy.ExpectedProfit.Sign(), 0, "Should maintain profitability under %s competition", level) } } }) } // Helper functions for stress testing func getCompetitorCount(level string) int { switch level { case "low": return 2 case "medium": return 5 case "high": return 10 case "extreme": return 20 default: return 3 } } func getAveragePriorityFee(level string) *big.Int { switch level { case "low": return big.NewInt(2000000000) // 2 gwei case "medium": return big.NewInt(5000000000) // 5 gwei case "high": return big.NewInt(10000000000) // 10 gwei case "extreme": return big.NewInt(25000000000) // 25 gwei default: return big.NewInt(3000000000) // 3 gwei } } func getSuccessRate(level string) float64 { switch level { case "low": return 0.9 case "medium": return 0.7 case "high": return 0.4 case "extreme": return 0.1 default: return 0.8 } }