package integration import ( "math/big" "testing" "time" "github.com/ethereum/go-ethereum/common" "github.com/fraktal/mev-beta/internal/logger" "github.com/fraktal/mev-beta/pkg/arbitrum" "github.com/fraktal/mev-beta/test/mocks" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) // TestL2MessageParsingAccuracy tests the accuracy of L2 message parsing func TestL2MessageParsingAccuracy(t *testing.T) { log := logger.New("info", "text", "") parser := arbitrum.NewL2MessageParser(log) testCases := []struct { name string protocol string expectedTokens []common.Address expectedFee uint32 }{ { name: "UniswapV3_USDC_WETH", protocol: "UniswapV3", expectedTokens: []common.Address{ common.HexToAddress("0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48"), // USDC common.HexToAddress("0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2"), // WETH }, expectedFee: 3000, }, { name: "SushiSwap_USDC_WETH", protocol: "SushiSwap", expectedTokens: []common.Address{ common.HexToAddress("0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48"), // USDC common.HexToAddress("0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2"), // WETH }, expectedFee: 3000, }, { name: "Camelot_ARB_WETH", protocol: "Camelot", expectedTokens: []common.Address{ common.HexToAddress("0x912CE59144191C1204E64559FE8253a0e49E6548"), // ARB common.HexToAddress("0x82aF49447D8a07e3bd95BD0d56f35241523fBab1"), // WETH on Arbitrum }, expectedFee: 3000, }, } for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { // Create mock transaction with DEX interaction poolAddress := common.HexToAddress("0xE592427A0AEce92De3Edee1F18E0157C05861564") // Uniswap V3 Router // Create mock transaction data for swap swapData := createMockSwapData(tc.expectedTokens[0], tc.expectedTokens[1], tc.expectedFee) tx := mocks.CreateMockTransaction(poolAddress, swapData) // Parse DEX interaction interaction, err := parser.ParseDEXInteraction(tx) if tc.protocol == "UniswapV3" { // UniswapV3 should be successfully parsed require.NoError(t, err) require.NotNil(t, interaction) assert.Equal(t, tc.protocol, interaction.Protocol) // Note: Fee field not available in current DEXInteraction struct assert.Equal(t, tc.protocol, interaction.Protocol) } else { // Other protocols might not be implemented yet, so we allow nil results if interaction != nil { assert.Equal(t, tc.protocol, interaction.Protocol) } } }) } } // TestL2MessageLatency tests the latency of L2 message processing func TestL2MessageLatency(t *testing.T) { log := logger.New("info", "text", "") parser := arbitrum.NewL2MessageParser(log) const numMessages = 100 const maxLatencyMs = 10 // Maximum acceptable latency in milliseconds for i := 0; i < numMessages; i++ { // Create L2 message l2Message := mocks.CreateMockL2Message() // Measure parsing time startTime := time.Now() if l2Message.ParsedTx != nil { _, err := parser.ParseDEXInteraction(l2Message.ParsedTx) // Error is expected for mock data, just measure timing _ = err } latency := time.Since(startTime) latencyMs := latency.Nanoseconds() / 1000000 // Verify latency is acceptable assert.LessOrEqual(t, latencyMs, int64(maxLatencyMs), "L2 message processing latency too high: %dms", latencyMs) } } // TestMultiProtocolDetection tests detection of multiple DEX protocols func TestMultiProtocolDetection(t *testing.T) { log := logger.New("info", "text", "") parser := arbitrum.NewL2MessageParser(log) protocols := []string{"UniswapV3", "SushiSwap", "Camelot", "Balancer", "Curve"} for _, protocol := range protocols { t.Run(protocol, func(t *testing.T) { // Create mock transaction for each protocol poolAddress := getProtocolPoolAddress(protocol) swapData := createMockSwapDataForProtocol(protocol) tx := mocks.CreateMockTransaction(poolAddress, swapData) // Parse DEX interaction interaction, err := parser.ParseDEXInteraction(tx) // For UniswapV3, we expect successful parsing // For others, we may not have full implementation yet if protocol == "UniswapV3" { require.NoError(t, err) require.NotNil(t, interaction) assert.Equal(t, protocol, interaction.Protocol) } else { // Log the results for other protocols if err != nil { t.Logf("Protocol %s not fully implemented yet: %v", protocol, err) } else if interaction != nil { t.Logf("Protocol %s detected: %+v", protocol, interaction) } else { t.Logf("Protocol %s: no interaction detected (expected for mock data)", protocol) } } }) } } // Helper functions for test data creation func createMockSwapData(token0, token1 common.Address, fee uint32) []byte { // exactInputSingle selector: 0x414bf389 selector := []byte{0x41, 0x4b, 0xf3, 0x89} // Create a mock payload for exactInputSingle payload := make([]byte, 256) // tokenIn (address) copy(payload[12:32], token0.Bytes()) // tokenOut (address) copy(payload[44:64], token1.Bytes()) // amountIn (uint256) amountIn := new(big.Int).SetInt64(1000000000000000000) // 1 ETH amountInBytes := amountIn.Bytes() copy(payload[192-len(amountInBytes):192], amountInBytes) return append(selector, payload...) } func createMockSwapDataForProtocol(protocol string) []byte { // For testing, we'll just use the same mock data for all protocols. // In a real scenario, this would generate protocol-specific data. token0 := common.HexToAddress("0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48") // USDC token1 := common.HexToAddress("0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2") // WETH return createMockSwapData(token0, token1, 3000) } func getProtocolPoolAddress(protocol string) common.Address { // Return known pool addresses for different protocols on Arbitrum protocolPools := map[string]string{ "UniswapV3": "0x88e6A0c2dDD26FEEb64F039a2c41296FcB3f5640", "SushiSwap": "0x905dfCD5649217c42684f23958568e533C711Aa3", "Camelot": "0x84652bb2539513BAf36e225c930Fdd8eaa63CE27", "Balancer": "0x32dF62dc3aEd2cD6224193052Ce665DC18165841", "Curve": "0x7f90122BF0700F9E7e1F688fe926940E8839F353", } if addr, exists := protocolPools[protocol]; exists { return common.HexToAddress(addr) } return common.HexToAddress("0x0000000000000000000000000000000000000000") }