package discovery import ( "testing" "github.com/ethereum/go-ethereum/common" "github.com/stretchr/testify/assert" "coppertone.tech/fraktal/mev-bot/pkg/cache" ) // TestNewUniswapV2PoolDiscovery tests the constructor for pool discovery func TestNewUniswapV2PoolDiscovery(t *testing.T) { tests := []struct { name string client interface{} // Using interface{} since we can't easily mock ethclient poolCache cache.PoolCache wantError bool }{ { name: "nil client should error", client: nil, poolCache: cache.NewPoolCache(), wantError: true, }, { name: "nil cache should error", client: "mock", // Not nil but not a real client poolCache: nil, wantError: true, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { // We can't actually create a real client here without RPC endpoint // This test mainly validates the nil checks // Real integration tests would use actual Arbitrum RPC if tt.client == nil { _, err := NewUniswapV2PoolDiscovery(nil, tt.poolCache) if tt.wantError { assert.Error(t, err) } else { assert.NoError(t, err) } } }) } } // TestMajorTokenPairs validates that the major token pairs are correctly defined func TestMajorTokenPairs(t *testing.T) { // Verify we have the expected pairs assert.NotEmpty(t, MajorTokenPairs, "should have major token pairs defined") assert.GreaterOrEqual(t, len(MajorTokenPairs), 10, "should have at least 10 major pairs") // Verify WETH/USDC pair exists (most liquid pair) foundWETHUSDC := false for _, pair := range MajorTokenPairs { if (pair[0] == WETH && pair[1] == USDC) || (pair[0] == USDC && pair[1] == WETH) { foundWETHUSDC = true break } } assert.True(t, foundWETHUSDC, "should include WETH/USDC pair") } // TestGetTokenDecimals validates the token decimals helper func TestGetTokenDecimals(t *testing.T) { tests := []struct { name string token common.Address expected uint8 }{ { name: "WETH should be 18 decimals", token: WETH, expected: 18, }, { name: "USDC should be 6 decimals", token: USDC, expected: 6, }, { name: "USDT should be 6 decimals", token: USDT, expected: 6, }, { name: "ARB should be 18 decimals", token: ARB, expected: 18, }, { name: "WBTC should be 18 decimals (Arbitrum wrapped BTC)", token: WBTC, expected: 18, }, { name: "unknown token should default to 18", token: common.HexToAddress("0x0000000000000000000000000000000000000001"), expected: 18, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { decimals := getTokenDecimals(tt.token) assert.Equal(t, tt.expected, decimals) }) } } // TestUniswapV2FactoryAddress validates the factory address is set func TestUniswapV2FactoryAddress(t *testing.T) { // Verify factory address is not zero assert.NotEqual(t, common.Address{}, UniswapV2FactoryAddress, "factory address should not be zero") // Verify it matches the known Arbitrum UniswapV2 factory expectedFactory := common.HexToAddress("0xf1D7CC64Fb4452F05c498126312eBE29f30Fbcf9") assert.Equal(t, expectedFactory, UniswapV2FactoryAddress, "should match Arbitrum UniswapV2 factory") } // TestWellKnownTokenAddresses validates all token addresses are non-zero func TestWellKnownTokenAddresses(t *testing.T) { tokens := map[string]common.Address{ "WETH": WETH, "USDC": USDC, "USDT": USDT, "ARB": ARB, "WBTC": WBTC, "DAI": DAI, "LINK": LINK, "UNI": UNI, } for name, addr := range tokens { t.Run(name, func(t *testing.T) { assert.NotEqual(t, common.Address{}, addr, "%s address should not be zero", name) }) } } // NOTE: Integration tests that actually call Arbitrum RPC would go in a separate file // marked with build tags (e.g., // +build integration) so they don't run in CI // without proper RPC configuration. Example: // // // +build integration // // func TestDiscoverMajorPools_Integration(t *testing.T) { // // This would require ARBITRUM_RPC_URL environment variable // rpcURL := os.Getenv("ARBITRUM_RPC_URL") // if rpcURL == "" { // t.Skip("ARBITRUM_RPC_URL not set") // } // // client, err := ethclient.Dial(rpcURL) // require.NoError(t, err) // defer client.Close() // // poolCache := cache.NewPoolCache() // discovery, err := NewUniswapV2PoolDiscovery(client, poolCache) // require.NoError(t, err) // // ctx := context.Background() // count, err := discovery.DiscoverMajorPools(ctx) // assert.NoError(t, err) // assert.Greater(t, count, 0, "should discover at least one pool") // }