refactor: move all remaining files to orig/ directory
Completed clean root directory structure: - Root now contains only: .git, .env, docs/, orig/ - Moved all remaining files and directories to orig/: - Config files (.claude, .dockerignore, .drone.yml, etc.) - All .env variants (except active .env) - Git config (.gitconfig, .github, .gitignore, etc.) - Tool configs (.golangci.yml, .revive.toml, etc.) - Documentation (*.md files, @prompts) - Build files (Dockerfiles, Makefile, go.mod, go.sum) - Docker compose files - All source directories (scripts, tests, tools, etc.) - Runtime directories (logs, monitoring, reports) - Dependency files (node_modules, lib, cache) - Special files (--delete) - Removed empty runtime directories (bin/, data/) V2 structure is now clean: - docs/planning/ - V2 planning documents - orig/ - Complete V1 codebase preserved - .env - Active environment config (not in git) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
290
orig/tests/integration/arbitrage_test.go
Normal file
290
orig/tests/integration/arbitrage_test.go
Normal file
@@ -0,0 +1,290 @@
|
||||
//go:build integration
|
||||
// +build integration
|
||||
|
||||
package integration
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"math/big"
|
||||
"os"
|
||||
"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/config"
|
||||
"github.com/fraktal/mev-beta/internal/logger"
|
||||
"github.com/fraktal/mev-beta/pkg/arbitrage"
|
||||
"github.com/fraktal/mev-beta/pkg/security"
|
||||
)
|
||||
|
||||
// Test configuration for forked environment
|
||||
const (
|
||||
TestRPCEndpoint = "http://localhost:8545"
|
||||
TestChainID = 31337
|
||||
testEncryptionKey = "integration_key_32_chars_minimum_length"
|
||||
)
|
||||
|
||||
// Arbitrum One token addresses for testing
|
||||
var (
|
||||
WETH = common.HexToAddress("0x82aF49447D8A07e3bd95BD0d56f35241523fBab1")
|
||||
USDC = common.HexToAddress("0xA0b86a33E6417aB7d461a67E4d3F14F6b49d3e8B") // USDC.e
|
||||
USDT = common.HexToAddress("0xFd086bC7CD5C481DCC9C85ebE478A1C0b69FCbb9")
|
||||
)
|
||||
|
||||
func TestMain(m *testing.M) {
|
||||
// Check if we're in test mode
|
||||
if os.Getenv("TEST_MODE") != "true" {
|
||||
fmt.Println("Skipping integration tests - set TEST_MODE=true to run")
|
||||
os.Exit(0)
|
||||
}
|
||||
|
||||
// Run tests
|
||||
code := m.Run()
|
||||
os.Exit(code)
|
||||
}
|
||||
|
||||
func setupTestEnvironment(t *testing.T) (*arbitrage.ArbitrageService, func()) {
|
||||
t.Helper()
|
||||
|
||||
ctx := context.Background()
|
||||
|
||||
// Create test logger
|
||||
log := logger.New("debug", "text", "")
|
||||
|
||||
// Create test configuration
|
||||
cfg := &config.ArbitrageConfig{
|
||||
Enabled: true,
|
||||
ArbitrageContractAddress: "0x0000000000000000000000000000000000000001", // Placeholder
|
||||
FlashSwapContractAddress: "0x0000000000000000000000000000000000000002", // Placeholder
|
||||
MinProfitWei: 1000000000000000, // 0.001 ETH
|
||||
MinROIPercent: 1.0, // 1%
|
||||
MinSignificantSwapSize: 1000000000000000000, // 1 ETH
|
||||
SlippageTolerance: 0.005, // 0.5%
|
||||
MinScanAmountWei: 100000000000000000, // 0.1 ETH
|
||||
MaxScanAmountWei: 9000000000000000000, // 9 ETH (fits int64)
|
||||
MaxGasPriceWei: 100000000000, // 100 gwei
|
||||
MaxConcurrentExecutions: 1, // Single execution for testing
|
||||
MaxOpportunitiesPerEvent: 3,
|
||||
OpportunityTTL: 30 * time.Second,
|
||||
MaxPathAge: 60 * time.Second,
|
||||
StatsUpdateInterval: 10 * time.Second,
|
||||
}
|
||||
|
||||
// Create Ethereum client
|
||||
client, err := ethclient.Dial(TestRPCEndpoint)
|
||||
if err != nil {
|
||||
t.Skipf("skipping integration test; unable to connect to %s: %v", TestRPCEndpoint, err)
|
||||
}
|
||||
|
||||
// Create key manager
|
||||
keyManagerConfig := &security.KeyManagerConfig{
|
||||
KeystorePath: "test_keystore",
|
||||
EncryptionKey: testEncryptionKey,
|
||||
KeyRotationDays: 30,
|
||||
MaxSigningRate: 100,
|
||||
SessionTimeout: time.Hour,
|
||||
}
|
||||
keyManager, err := security.NewKeyManager(keyManagerConfig, log)
|
||||
require.NoError(t, err, "Failed to create key manager")
|
||||
|
||||
// Create test database
|
||||
database, err := arbitrage.NewSQLiteDatabase(":memory:", log)
|
||||
require.NoError(t, err, "Failed to create test database")
|
||||
|
||||
// Create arbitrage service
|
||||
service, err := arbitrage.NewArbitrageService(
|
||||
ctx,
|
||||
client,
|
||||
log,
|
||||
cfg,
|
||||
keyManager,
|
||||
database,
|
||||
)
|
||||
require.NoError(t, err, "Failed to create arbitrage service")
|
||||
|
||||
// Start the service
|
||||
err = service.Start()
|
||||
require.NoError(t, err, "Failed to start arbitrage service")
|
||||
|
||||
// Cleanup function
|
||||
cleanup := func() {
|
||||
service.Stop()
|
||||
database.Close()
|
||||
client.Close()
|
||||
os.RemoveAll("test_keystore")
|
||||
}
|
||||
|
||||
return service, cleanup
|
||||
}
|
||||
|
||||
func TestArbitrageServiceIntegration(t *testing.T) {
|
||||
service, cleanup := setupTestEnvironment(t)
|
||||
defer cleanup()
|
||||
|
||||
t.Run("ServiceHealthCheck", func(t *testing.T) {
|
||||
assert.True(t, service.IsRunning(), "Service should be running")
|
||||
|
||||
stats := service.GetStats()
|
||||
assert.NotNil(t, stats, "Stats should not be nil")
|
||||
assert.Equal(t, int64(0), stats.TotalOpportunitiesDetected, "Initial opportunities should be zero")
|
||||
})
|
||||
|
||||
t.Run("TokenValidation", func(t *testing.T) {
|
||||
// Test that we can validate token addresses
|
||||
tokens := []common.Address{WETH, USDC, USDT}
|
||||
|
||||
for _, token := range tokens {
|
||||
assert.False(t, token.String() == "0x0000000000000000000000000000000000000000",
|
||||
"Token address should not be zero: %s", token.String())
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func TestSwapEventProcessing(t *testing.T) {
|
||||
service, cleanup := setupTestEnvironment(t)
|
||||
defer cleanup()
|
||||
|
||||
t.Run("ProcessLargeSwapEvent", func(t *testing.T) {
|
||||
// Create a simulated large swap event
|
||||
swapEvent := &arbitrage.SimpleSwapEvent{
|
||||
TxHash: common.HexToHash("0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef"),
|
||||
PoolAddress: common.HexToAddress("0xC6962004f452bE9203591991D15f6b388e09E8D0"), // Example pool
|
||||
Token0: WETH,
|
||||
Token1: USDC,
|
||||
Amount0: mustBigInt(t, "-5000000000000000000"), // -5 ETH
|
||||
Amount1: mustBigInt(t, "12500000000"), // +12500 USDC
|
||||
SqrtPriceX96: mustBigInt(t, "1000000000000000000000"), // Example price
|
||||
Liquidity: mustBigInt(t, "50000000000000000000000"), // Example liquidity
|
||||
Tick: int32(-85000), // Example tick
|
||||
BlockNumber: 12345678,
|
||||
LogIndex: 1,
|
||||
Timestamp: time.Now(),
|
||||
}
|
||||
|
||||
// Process the swap event
|
||||
err := service.ProcessSwapEvent(swapEvent)
|
||||
assert.NoError(t, err, "Should process swap event without error")
|
||||
|
||||
// Allow time for processing
|
||||
time.Sleep(1 * time.Second)
|
||||
|
||||
// Check that the event was processed
|
||||
stats := service.GetStats()
|
||||
t.Logf("Opportunities detected: %d", stats.TotalOpportunitiesDetected)
|
||||
})
|
||||
}
|
||||
|
||||
func TestPoolDataRetrieval(t *testing.T) {
|
||||
_, cleanup := setupTestEnvironment(t)
|
||||
defer cleanup()
|
||||
|
||||
t.Run("SaveAndRetrievePoolData", func(t *testing.T) {
|
||||
// Create test pool data
|
||||
poolData := &arbitrage.SimplePoolData{
|
||||
Address: common.HexToAddress("0xC6962004f452bE9203591991D15f6b388e09E8D0"),
|
||||
Token0: WETH,
|
||||
Token1: USDC,
|
||||
Fee: 500, // 0.05%
|
||||
Liquidity: mustBigInt(t, "50000000000000000000000"),
|
||||
SqrtPriceX96: mustBigInt(t, "1000000000000000000000"),
|
||||
Tick: -85000,
|
||||
BlockNumber: 12345678,
|
||||
TxHash: common.HexToHash("0xabcdef"),
|
||||
LogIndex: 1,
|
||||
LastUpdated: time.Now(),
|
||||
}
|
||||
|
||||
// This test would require database access through the service
|
||||
// For now, we verify the structure is correct
|
||||
assert.Equal(t, WETH, poolData.Token0, "Token0 should be WETH")
|
||||
assert.Equal(t, USDC, poolData.Token1, "Token1 should be USDC")
|
||||
assert.Equal(t, int64(500), poolData.Fee, "Fee should be 500 (0.05%)")
|
||||
})
|
||||
}
|
||||
|
||||
func TestRealTimeArbitrageDetection(t *testing.T) {
|
||||
if testing.Short() {
|
||||
t.Skip("Skipping real-time test in short mode")
|
||||
}
|
||||
|
||||
service, cleanup := setupTestEnvironment(t)
|
||||
defer cleanup()
|
||||
|
||||
t.Run("ContinuousMonitoring", func(t *testing.T) {
|
||||
// Run service for a short period to test real-time processing
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
|
||||
defer cancel()
|
||||
|
||||
initialStats := service.GetStats()
|
||||
|
||||
// Simulate periodic swap events
|
||||
ticker := time.NewTicker(5 * time.Second)
|
||||
defer ticker.Stop()
|
||||
|
||||
go func() {
|
||||
eventCount := 0
|
||||
for {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return
|
||||
case <-ticker.C:
|
||||
eventCount++
|
||||
|
||||
// Create varied swap events
|
||||
swapEvent := &arbitrage.SimpleSwapEvent{
|
||||
TxHash: common.HexToHash(fmt.Sprintf("0x%064d", eventCount)),
|
||||
PoolAddress: common.HexToAddress("0xC6962004f452bE9203591991D15f6b388e09E8D0"),
|
||||
Token0: WETH,
|
||||
Token1: USDC,
|
||||
Amount0: scaleBigInt(t, "-1000000000000000000", eventCount),
|
||||
Amount1: scaleBigInt(t, "2500000000", eventCount),
|
||||
SqrtPriceX96: mustBigInt(t, "1000000000000000000000"),
|
||||
Liquidity: mustBigInt(t, "50000000000000000000000"),
|
||||
Tick: int32(-85000 + eventCount*100),
|
||||
BlockNumber: 12345678 + uint64(eventCount),
|
||||
LogIndex: uint(eventCount),
|
||||
Timestamp: time.Now(),
|
||||
}
|
||||
|
||||
service.ProcessSwapEvent(swapEvent)
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
// Wait for test duration
|
||||
<-ctx.Done()
|
||||
|
||||
// Check final stats
|
||||
finalStats := service.GetStats()
|
||||
t.Logf("Initial opportunities: %d", initialStats.TotalOpportunitiesDetected)
|
||||
t.Logf("Final opportunities: %d", finalStats.TotalOpportunitiesDetected)
|
||||
|
||||
// We expect some processing activity
|
||||
assert.True(t, finalStats.TotalOpportunitiesDetected >= initialStats.TotalOpportunitiesDetected,
|
||||
"Should have processed some opportunities")
|
||||
})
|
||||
}
|
||||
|
||||
func mustBigInt(t testing.TB, value string) *big.Int {
|
||||
t.Helper()
|
||||
bi, ok := new(big.Int).SetString(value, 10)
|
||||
if !ok {
|
||||
t.Fatalf("invalid big.Int value: %s", value)
|
||||
}
|
||||
return bi
|
||||
}
|
||||
|
||||
func scaleBigInt(t testing.TB, base string, multiplier int) *big.Int {
|
||||
t.Helper()
|
||||
if multiplier == 0 {
|
||||
return big.NewInt(0)
|
||||
}
|
||||
bi := mustBigInt(t, base)
|
||||
factor := big.NewInt(int64(multiplier))
|
||||
return bi.Mul(bi, factor)
|
||||
}
|
||||
286
orig/tests/integration/basic_integration_test.go
Normal file
286
orig/tests/integration/basic_integration_test.go
Normal file
@@ -0,0 +1,286 @@
|
||||
//go:build integration && legacy && forked
|
||||
// +build integration,legacy,forked
|
||||
|
||||
// Package integration provides integration tests for the MEV bot using a forked Arbitrum environment
|
||||
package integration
|
||||
|
||||
import (
|
||||
"context"
|
||||
"math/big"
|
||||
"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/config"
|
||||
"github.com/fraktal/mev-beta/internal/logger"
|
||||
"github.com/fraktal/mev-beta/pkg/contracts"
|
||||
"github.com/fraktal/mev-beta/pkg/database"
|
||||
"github.com/fraktal/mev-beta/pkg/pools"
|
||||
"github.com/fraktal/mev-beta/pkg/security"
|
||||
)
|
||||
|
||||
// TestContractExecutorInitialization tests that the contract executor can be initialized
|
||||
func TestContractExecutorInitialization(t *testing.T) {
|
||||
// Skip this test in short mode
|
||||
if testing.Short() {
|
||||
t.Skip("skipping contract executor test in short mode")
|
||||
}
|
||||
|
||||
// Create test logger
|
||||
log := logger.New("debug", "text", "")
|
||||
|
||||
// Create test configuration
|
||||
cfg := &config.Config{
|
||||
Arbitrum: config.ArbitrumConfig{
|
||||
RPCEndpoint: "http://localhost:8545", // Anvil default port
|
||||
ChainID: 31337, // Anvil default chain ID
|
||||
RateLimit: config.RateLimitConfig{
|
||||
RequestsPerSecond: 10,
|
||||
MaxConcurrent: 5,
|
||||
Burst: 20,
|
||||
},
|
||||
},
|
||||
Bot: config.BotConfig{
|
||||
Enabled: true,
|
||||
PollingInterval: 1,
|
||||
MinProfitThreshold: 0.01, // Lower threshold for testing
|
||||
GasPriceMultiplier: 1.2,
|
||||
MaxWorkers: 2,
|
||||
ChannelBufferSize: 10,
|
||||
RPCTimeout: 30,
|
||||
},
|
||||
Ethereum: config.EthereumConfig{
|
||||
PrivateKey: "", // Will be set by environment or test setup
|
||||
AccountAddress: "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266", // Default Anvil account
|
||||
GasPriceMultiplier: 1.2,
|
||||
},
|
||||
Contracts: config.ContractsConfig{
|
||||
ArbitrageExecutor: "0x0000000000000000000000000000000000000000", // Placeholder
|
||||
FlashSwapper: "0x0000000000000000000000000000000000000000", // Placeholder
|
||||
AuthorizedCallers: []string{
|
||||
"0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266", // Default Anvil account
|
||||
},
|
||||
AuthorizedDEXes: []string{
|
||||
"0x1F98431c8aD98523631AE4a59f267346ea31F984", // Uniswap V3 Factory
|
||||
"0xf1D7CC64Fb4452F05c498126312eBE29f30Fbcf9", // Uniswap V2 Factory
|
||||
"0xc35DADB65012eC5796536bD9864eD8773aBc74C4", // SushiSwap Factory
|
||||
},
|
||||
},
|
||||
Database: config.DatabaseConfig{
|
||||
File: ":memory:",
|
||||
MaxOpenConnections: 10,
|
||||
MaxIdleConnections: 5,
|
||||
},
|
||||
Uniswap: config.UniswapConfig{
|
||||
FactoryAddress: "0x1F98431c8aD98523631AE4a59f267346ea31F984",
|
||||
PositionManagerAddress: "0xC36442b4a4522E871399CD717aBDD847Ab11FE88",
|
||||
FeeTiers: []int64{500, 3000, 10000},
|
||||
Cache: config.CacheConfig{
|
||||
Enabled: true,
|
||||
Expiration: 300,
|
||||
MaxSize: 10000,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
// Connect to the forked environment
|
||||
client, err := ethclient.Dial(cfg.Arbitrum.RPCEndpoint)
|
||||
if err != nil {
|
||||
t.Skipf("Skipping test: failed to connect to forked Arbitrum at %s", cfg.Arbitrum.RPCEndpoint)
|
||||
}
|
||||
defer client.Close()
|
||||
|
||||
// Verify connection by getting chain ID
|
||||
chainID, err := client.ChainID(context.Background())
|
||||
require.NoError(t, err, "failed to get chain ID")
|
||||
log.Info("Connected to forked Arbitrum chain ID:", chainID.String())
|
||||
|
||||
// Test contract executor creation (this might fail in testing but we can verify the setup)
|
||||
// Create a mock key manager for testing
|
||||
keyManager, err := security.NewKeyManager(&security.KeyManagerConfig{
|
||||
KeystorePath: "/tmp/test_keys",
|
||||
EncryptionKey: "test_encryption_key",
|
||||
}, log)
|
||||
require.NoError(t, err)
|
||||
|
||||
contractExecutor, err := contracts.NewContractExecutor(cfg, log, keyManager)
|
||||
if err != nil {
|
||||
// This is expected in testing since we don't have real contracts deployed
|
||||
log.Warn("Contract executor creation failed (expected in testing):", err)
|
||||
} else {
|
||||
defer contractExecutor.Close()
|
||||
assert.NotNil(t, contractExecutor)
|
||||
log.Info("Contract executor created successfully")
|
||||
}
|
||||
|
||||
log.Info("Contract executor initialization test completed")
|
||||
}
|
||||
|
||||
// TestCREATE2Calculator tests the CREATE2 pool address calculation
|
||||
func TestCREATE2Calculator(t *testing.T) {
|
||||
// Create test logger
|
||||
log := logger.New("debug", "text", "")
|
||||
|
||||
// Create CREATE2 calculator
|
||||
calculator := pools.NewCREATE2Calculator(log)
|
||||
|
||||
// Test calculating pool addresses for known token pairs
|
||||
testCases := []struct {
|
||||
name string
|
||||
factoryName string
|
||||
token0 string
|
||||
token1 string
|
||||
fee uint32
|
||||
expectedLen int
|
||||
}{
|
||||
{
|
||||
name: "Uniswap V3 USDC/WETH",
|
||||
factoryName: "uniswap_v3",
|
||||
token0: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48", // USDC
|
||||
token1: "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2", // WETH
|
||||
fee: 3000,
|
||||
expectedLen: 20, // Address should be 20 bytes
|
||||
},
|
||||
{
|
||||
name: "Uniswap V2 USDC/WETH",
|
||||
factoryName: "uniswap_v2",
|
||||
token0: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48", // USDC
|
||||
token1: "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2", // WETH
|
||||
fee: 0, // V2 doesn't use fee in pool calculation
|
||||
expectedLen: 20,
|
||||
},
|
||||
{
|
||||
name: "SushiSwap USDC/WETH",
|
||||
factoryName: "sushiswap",
|
||||
token0: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48", // USDC
|
||||
token1: "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2", // WETH
|
||||
fee: 0, // SushiSwap V2 doesn't use fee in pool calculation
|
||||
expectedLen: 20,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
// Convert hex addresses to common.Address
|
||||
token0 := common.HexToAddress(tc.token0)
|
||||
token1 := common.HexToAddress(tc.token1)
|
||||
|
||||
// Calculate pool address
|
||||
poolAddr, err := calculator.CalculatePoolAddress(tc.factoryName, token0, token1, tc.fee)
|
||||
require.NoError(t, err, "failed to calculate pool address")
|
||||
|
||||
// Verify the pool address
|
||||
assert.Equal(t, tc.expectedLen, len(poolAddr.Bytes()), "pool address should be 20 bytes")
|
||||
assert.NotEqual(t, common.Address{}, poolAddr, "pool address should not be zero")
|
||||
|
||||
log.Info("Calculated pool address:", poolAddr.Hex(), "for", tc.name)
|
||||
})
|
||||
}
|
||||
|
||||
// Test finding pools for token pairs
|
||||
usdc := common.HexToAddress("0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48")
|
||||
weth := common.HexToAddress("0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2")
|
||||
|
||||
pools, err := calculator.FindPoolsForTokenPair(usdc, weth)
|
||||
require.NoError(t, err, "failed to find pools for token pair")
|
||||
|
||||
log.Info("Found", len(pools), "potential pools for USDC/WETH pair")
|
||||
|
||||
// Verify we found some pools
|
||||
assert.True(t, len(pools) > 0, "should find at least one pool for USDC/WETH")
|
||||
|
||||
// Verify each pool has valid data
|
||||
for _, pool := range pools {
|
||||
assert.NotEqual(t, "", pool.Factory, "factory should not be empty")
|
||||
assert.NotEqual(t, common.Address{}, pool.Token0, "token0 should not be zero")
|
||||
assert.NotEqual(t, common.Address{}, pool.Token1, "token1 should not be zero")
|
||||
assert.NotEqual(t, common.Address{}, pool.PoolAddr, "pool address should not be zero")
|
||||
assert.True(t, pool.Fee >= 0, "fee should be non-negative")
|
||||
}
|
||||
|
||||
log.Info("CREATE2 calculator test completed successfully")
|
||||
}
|
||||
|
||||
// TestDatabaseIntegration tests database integration
|
||||
func TestDatabaseIntegration(t *testing.T) {
|
||||
// Create test logger
|
||||
log := logger.New("debug", "text", "")
|
||||
|
||||
// Create test configuration
|
||||
cfg := &config.DatabaseConfig{
|
||||
File: ":memory:", // In-memory database for testing
|
||||
MaxOpenConnections: 10,
|
||||
MaxIdleConnections: 5,
|
||||
}
|
||||
|
||||
// Create database
|
||||
db, err := database.NewDatabase(cfg, log)
|
||||
require.NoError(t, err, "failed to create database")
|
||||
defer db.Close()
|
||||
|
||||
// Test inserting swap event
|
||||
swapEvent := &database.SwapEvent{
|
||||
Timestamp: time.Now(),
|
||||
BlockNumber: 12345678,
|
||||
TxHash: common.HexToHash("0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef"),
|
||||
PoolAddress: common.HexToAddress("0x88e6A0c2dDD26FEEb64F039a2c41296FcB3f5640"),
|
||||
Token0: common.HexToAddress("0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48"), // USDC
|
||||
Token1: common.HexToAddress("0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2"), // WETH
|
||||
Amount0In: big.NewInt(1000000000), // 1000 USDC
|
||||
Amount1In: big.NewInt(0),
|
||||
Amount0Out: big.NewInt(0),
|
||||
Amount1Out: big.NewInt(500000000000000000), // 0.5 WETH
|
||||
Sender: common.HexToAddress("0x1234567890abcdef1234567890abcdef12345678"),
|
||||
Recipient: common.HexToAddress("0x8765432109fedcba8765432109fedcba87654321"),
|
||||
Protocol: "uniswap_v3",
|
||||
}
|
||||
|
||||
err = db.InsertSwapEvent(swapEvent)
|
||||
assert.NoError(t, err, "failed to insert swap event")
|
||||
|
||||
// Test retrieving recent swap events
|
||||
swaps, err := db.GetRecentSwapEvents(10)
|
||||
assert.NoError(t, err, "failed to get recent swap events")
|
||||
assert.Len(t, swaps, 1, "expected 1 swap event")
|
||||
|
||||
// Verify the retrieved swap event
|
||||
if len(swaps) > 0 {
|
||||
assert.Equal(t, swapEvent.PoolAddress, swaps[0].PoolAddress, "pool address mismatch")
|
||||
assert.Equal(t, swapEvent.Token0, swaps[0].Token0, "token0 mismatch")
|
||||
assert.Equal(t, swapEvent.Token1, swaps[0].Token1, "token1 mismatch")
|
||||
assert.Equal(t, swapEvent.Protocol, swaps[0].Protocol, "protocol mismatch")
|
||||
assert.Equal(t, swapEvent.Amount0In, swaps[0].Amount0In, "amount0 in mismatch")
|
||||
assert.Equal(t, swapEvent.Amount1Out, swaps[0].Amount1Out, "amount1 out mismatch")
|
||||
}
|
||||
|
||||
// Test inserting pool data
|
||||
poolData := &database.PoolData{
|
||||
Address: common.HexToAddress("0x88e6A0c2dDD26FEEb64F039a2c41296FcB3f5640"),
|
||||
Token0: common.HexToAddress("0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48"), // USDC
|
||||
Token1: common.HexToAddress("0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2"), // WETH
|
||||
Fee: 3000, // 0.3%
|
||||
Liquidity: big.NewInt(1000000000000000000), // 1 ETH equivalent
|
||||
SqrtPriceX96: big.NewInt(2505414483750470000), // Realistic price
|
||||
Tick: 200000, // Corresponding tick
|
||||
LastUpdated: time.Now(),
|
||||
Protocol: "uniswap_v3",
|
||||
}
|
||||
|
||||
err = db.InsertPoolData(poolData)
|
||||
assert.NoError(t, err, "failed to insert pool data")
|
||||
|
||||
// Test retrieving pool data
|
||||
retrievedPool, err := db.GetPoolData(poolData.Address)
|
||||
assert.NoError(t, err, "failed to get pool data")
|
||||
assert.Equal(t, poolData.Address, retrievedPool.Address, "pool address mismatch")
|
||||
assert.Equal(t, poolData.Token0, retrievedPool.Token0, "token0 mismatch")
|
||||
assert.Equal(t, poolData.Token1, retrievedPool.Token1, "token1 mismatch")
|
||||
assert.Equal(t, poolData.Fee, retrievedPool.Fee, "fee mismatch")
|
||||
assert.Equal(t, poolData.Protocol, retrievedPool.Protocol, "protocol mismatch")
|
||||
|
||||
log.Info("Database integration test completed successfully")
|
||||
}
|
||||
335
orig/tests/integration/fork_test.go
Normal file
335
orig/tests/integration/fork_test.go
Normal file
@@ -0,0 +1,335 @@
|
||||
package integration
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/ethereum/go-ethereum/accounts/abi/bind"
|
||||
"github.com/ethereum/go-ethereum/crypto"
|
||||
"github.com/ethereum/go-ethereum/ethclient"
|
||||
"github.com/stretchr/testify/require"
|
||||
// NOTE: The following imports will be needed once the commented test code is uncommented:
|
||||
// "math/big"
|
||||
// "github.com/ethereum/go-ethereum/common"
|
||||
// "github.com/yourusername/mev-beta/bindings/contracts"
|
||||
// "github.com/yourusername/mev-beta/bindings/interfaces"
|
||||
)
|
||||
|
||||
const (
|
||||
// Arbitrum Mainnet RPC for forking
|
||||
ArbitrumRPC = "https://arb1.arbitrum.io/rpc"
|
||||
|
||||
// Known Arbitrum addresses
|
||||
WETH_ADDRESS = "0x82aF49447D8a07e3bd95BD0d56f35241523fBab1"
|
||||
USDC_ADDRESS = "0xaf88d065e77c8cC2239327C5EDb3A432268e5831"
|
||||
|
||||
UNISWAP_V3_FACTORY = "0x1F98431c8aD98523631AE4a59f267346ea31F984"
|
||||
WETH_USDC_POOL_500_FEE = "0xC6962004f452bE9203591991D15f6b388e09E8D0"
|
||||
)
|
||||
|
||||
// TestForkContractDeployment tests deploying contracts to an Arbitrum fork
|
||||
func TestForkContractDeployment(t *testing.T) {
|
||||
// Skip if not running integration tests
|
||||
if testing.Short() {
|
||||
t.Skip("Skipping integration test in short mode")
|
||||
}
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Minute)
|
||||
defer cancel()
|
||||
|
||||
// Connect to Arbitrum fork
|
||||
client, err := ethclient.DialContext(ctx, ArbitrumRPC)
|
||||
require.NoError(t, err, "Failed to connect to Arbitrum RPC")
|
||||
defer client.Close()
|
||||
|
||||
chainID, err := client.ChainID(ctx)
|
||||
require.NoError(t, err, "Failed to get chain ID")
|
||||
t.Logf("Connected to chain ID: %s", chainID.String())
|
||||
|
||||
// Create test account with private key
|
||||
privateKey, err := crypto.GenerateKey()
|
||||
require.NoError(t, err, "Failed to generate private key")
|
||||
|
||||
auth, err := bind.NewKeyedTransactorWithChainID(privateKey, chainID)
|
||||
require.NoError(t, err, "Failed to create transactor")
|
||||
|
||||
// Set gas limits
|
||||
auth.GasLimit = 5000000
|
||||
|
||||
t.Logf("Test account: %s", auth.From.Hex())
|
||||
|
||||
// Note: Actual deployment would happen here using generated bindings
|
||||
// Example (uncomment after binding generation):
|
||||
/*
|
||||
// Deploy UniswapV3FlashSwapper
|
||||
flashSwapperAddr, tx, flashSwapper, err := contracts.DeployUniswapV3FlashSwapper(
|
||||
auth,
|
||||
client,
|
||||
common.HexToAddress(UNISWAP_V3_FACTORY),
|
||||
)
|
||||
require.NoError(t, err, "Failed to deploy UniswapV3FlashSwapper")
|
||||
|
||||
t.Logf("UniswapV3FlashSwapper deployed at: %s", flashSwapperAddr.Hex())
|
||||
t.Logf("Deployment tx: %s", tx.Hash().Hex())
|
||||
|
||||
// Wait for deployment
|
||||
receipt, err := bind.WaitMined(ctx, client, tx)
|
||||
require.NoError(t, err, "Failed to wait for deployment")
|
||||
require.Equal(t, uint64(1), receipt.Status, "Deployment failed")
|
||||
|
||||
// Deploy ArbitrageExecutor
|
||||
arbExecutorAddr, tx, arbExecutor, err := contracts.DeployArbitrageExecutor(
|
||||
auth,
|
||||
client,
|
||||
flashSwapperAddr,
|
||||
)
|
||||
require.NoError(t, err, "Failed to deploy ArbitrageExecutor")
|
||||
|
||||
t.Logf("ArbitrageExecutor deployed at: %s", arbExecutorAddr.Hex())
|
||||
|
||||
receipt, err = bind.WaitMined(ctx, client, tx)
|
||||
require.NoError(t, err, "Failed to wait for deployment")
|
||||
require.Equal(t, uint64(1), receipt.Status, "Deployment failed")
|
||||
*/
|
||||
|
||||
t.Log("Contract deployment test structure ready")
|
||||
}
|
||||
|
||||
// TestForkFlashSwapFeeCalculation tests flash swap fee calculation on fork
|
||||
func TestForkFlashSwapFeeCalculation(t *testing.T) {
|
||||
if testing.Short() {
|
||||
t.Skip("Skipping integration test in short mode")
|
||||
}
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 2*time.Minute)
|
||||
defer cancel()
|
||||
|
||||
client, err := ethclient.DialContext(ctx, ArbitrumRPC)
|
||||
require.NoError(t, err, "Failed to connect to Arbitrum RPC")
|
||||
defer client.Close()
|
||||
|
||||
// Note: After binding generation, this would use the actual contract binding
|
||||
/*
|
||||
flashSwapper, err := contracts.NewUniswapV3FlashSwapper(
|
||||
common.HexToAddress("YOUR_DEPLOYED_ADDRESS"),
|
||||
client,
|
||||
)
|
||||
require.NoError(t, err, "Failed to create flash swapper binding")
|
||||
|
||||
// Test fee calculation for 0.05% pool
|
||||
amount0 := big.NewInt(100_000_000) // 100 USDC (6 decimals)
|
||||
amount1 := big.NewInt(0)
|
||||
|
||||
fee0, fee1, err := flashSwapper.CalculateFlashSwapFee(
|
||||
&bind.CallOpts{Context: ctx},
|
||||
common.HexToAddress(WETH_USDC_POOL_500_FEE),
|
||||
amount0,
|
||||
amount1,
|
||||
)
|
||||
require.NoError(t, err, "Failed to calculate flash swap fee")
|
||||
|
||||
t.Logf("Borrow amount: %s USDC", amount0.String())
|
||||
t.Logf("Flash loan fee: %s", fee0.String())
|
||||
|
||||
// For 0.05% fee tier on 100 USDC: fee = 100 * 0.0005 = 0.05 USDC = 50000 (6 decimals)
|
||||
expectedFee := big.NewInt(50000)
|
||||
require.Equal(t, expectedFee.String(), fee0.String(), "Fee calculation incorrect")
|
||||
*/
|
||||
|
||||
t.Log("Flash swap fee calculation test structure ready")
|
||||
}
|
||||
|
||||
// TestForkArbitrageCalculation tests arbitrage profit calculation
|
||||
func TestForkArbitrageCalculation(t *testing.T) {
|
||||
if testing.Short() {
|
||||
t.Skip("Skipping integration test in short mode")
|
||||
}
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 2*time.Minute)
|
||||
defer cancel()
|
||||
|
||||
client, err := ethclient.DialContext(ctx, ArbitrumRPC)
|
||||
require.NoError(t, err, "Failed to connect to Arbitrum RPC")
|
||||
defer client.Close()
|
||||
|
||||
// Note: After binding generation
|
||||
/*
|
||||
arbExecutor, err := contracts.NewArbitrageExecutor(
|
||||
common.HexToAddress("YOUR_DEPLOYED_ADDRESS"),
|
||||
client,
|
||||
)
|
||||
require.NoError(t, err, "Failed to create arbitrage executor binding")
|
||||
|
||||
// Create test arbitrage params
|
||||
params := contracts.IArbitrageArbitrageParams{
|
||||
Tokens: []common.Address{
|
||||
common.HexToAddress(WETH_ADDRESS),
|
||||
common.HexToAddress(USDC_ADDRESS),
|
||||
common.HexToAddress(WETH_ADDRESS),
|
||||
},
|
||||
Pools: []common.Address{
|
||||
common.HexToAddress("POOL_1"),
|
||||
common.HexToAddress("POOL_2"),
|
||||
},
|
||||
Amounts: []*big.Int{
|
||||
big.NewInt(1000000000000000000), // 1 WETH
|
||||
big.NewInt(2000000000), // 2000 USDC
|
||||
},
|
||||
SwapData: [][]byte{
|
||||
[]byte("swap_data_1"),
|
||||
[]byte("swap_data_2"),
|
||||
},
|
||||
MinProfit: big.NewInt(1000000000000000), // 0.001 WETH minimum profit
|
||||
}
|
||||
|
||||
expectedProfit, err := arbExecutor.CalculateArbitrageProfit(
|
||||
&bind.CallOpts{Context: ctx},
|
||||
params,
|
||||
)
|
||||
require.NoError(t, err, "Failed to calculate arbitrage profit")
|
||||
|
||||
t.Logf("Expected arbitrage profit: %s", expectedProfit.String())
|
||||
require.True(t, expectedProfit.Cmp(big.NewInt(0)) >= 0, "Expected profit should be non-negative")
|
||||
*/
|
||||
|
||||
t.Log("Arbitrage calculation test structure ready")
|
||||
}
|
||||
|
||||
// TestForkEndToEndArbitrage tests the complete arbitrage flow
|
||||
func TestForkEndToEndArbitrage(t *testing.T) {
|
||||
if testing.Short() {
|
||||
t.Skip("Skipping integration test in short mode")
|
||||
}
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Minute)
|
||||
defer cancel()
|
||||
|
||||
t.Log("=== End-to-End Arbitrage Test ===")
|
||||
|
||||
// 1. Connect to fork
|
||||
client, err := ethclient.DialContext(ctx, ArbitrumRPC)
|
||||
require.NoError(t, err, "Failed to connect to Arbitrum RPC")
|
||||
defer client.Close()
|
||||
|
||||
chainID, err := client.ChainID(ctx)
|
||||
require.NoError(t, err)
|
||||
t.Logf("Connected to chain ID: %s", chainID.String())
|
||||
|
||||
// 2. Setup test account
|
||||
privateKey, err := crypto.GenerateKey()
|
||||
require.NoError(t, err)
|
||||
|
||||
auth, err := bind.NewKeyedTransactorWithChainID(privateKey, chainID)
|
||||
require.NoError(t, err)
|
||||
auth.GasLimit = 5000000
|
||||
|
||||
t.Logf("Test account: %s", auth.From.Hex())
|
||||
|
||||
// 3. Deploy contracts (placeholder)
|
||||
t.Log("Step 1: Deploy contracts")
|
||||
// Actual deployment with bindings goes here
|
||||
|
||||
// 4. Configure contracts
|
||||
t.Log("Step 2: Configure contracts")
|
||||
// Set authorized callers, DEXes, pools, etc.
|
||||
|
||||
// 5. Fund contracts with test tokens
|
||||
t.Log("Step 3: Fund contracts with test tokens")
|
||||
// Transfer WETH, USDC to test account and contracts
|
||||
|
||||
// 6. Execute test arbitrage
|
||||
t.Log("Step 4: Execute arbitrage")
|
||||
/*
|
||||
// Build arbitrage params
|
||||
params := contracts.IArbitrageArbitrageParams{
|
||||
Tokens: []common.Address{
|
||||
common.HexToAddress(WETH_ADDRESS),
|
||||
common.HexToAddress(USDC_ADDRESS),
|
||||
common.HexToAddress(WETH_ADDRESS),
|
||||
},
|
||||
Pools: []common.Address{
|
||||
common.HexToAddress(WETH_USDC_POOL_500_FEE),
|
||||
common.HexToAddress("SECOND_POOL"),
|
||||
},
|
||||
Amounts: []*big.Int{
|
||||
big.NewInt(1000000000000000000), // 1 WETH
|
||||
big.NewInt(2000000000), // 2000 USDC
|
||||
},
|
||||
SwapData: [][]byte{
|
||||
buildSwapData(),
|
||||
buildSwapData(),
|
||||
},
|
||||
MinProfit: big.NewInt(1000000000000000), // 0.001 WETH
|
||||
}
|
||||
|
||||
// Execute arbitrage
|
||||
tx, err := arbExecutor.ExecuteArbitrage(auth, params)
|
||||
require.NoError(t, err, "Failed to execute arbitrage")
|
||||
|
||||
t.Logf("Arbitrage tx: %s", tx.Hash().Hex())
|
||||
|
||||
// Wait for confirmation
|
||||
receipt, err := bind.WaitMined(ctx, client, tx)
|
||||
require.NoError(t, err, "Failed to wait for tx")
|
||||
require.Equal(t, uint64(1), receipt.Status, "Arbitrage transaction failed")
|
||||
|
||||
// Check events
|
||||
t.Log("Step 5: Verify arbitrage events")
|
||||
// Parse ArbitrageExecuted event
|
||||
*/
|
||||
|
||||
// 7. Verify profit
|
||||
t.Log("Step 5: Verify profit")
|
||||
// Check final balances
|
||||
|
||||
t.Log("=== End-to-End Test Complete ===")
|
||||
}
|
||||
|
||||
// TestForkDataFetcher tests the DataFetcher contract
|
||||
func TestForkDataFetcher(t *testing.T) {
|
||||
if testing.Short() {
|
||||
t.Skip("Skipping integration test in short mode")
|
||||
}
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 2*time.Minute)
|
||||
defer cancel()
|
||||
|
||||
client, err := ethclient.DialContext(ctx, ArbitrumRPC)
|
||||
require.NoError(t, err)
|
||||
defer client.Close()
|
||||
|
||||
/*
|
||||
dataFetcher, err := contracts.NewDataFetcher(
|
||||
common.HexToAddress("YOUR_DEPLOYED_ADDRESS"),
|
||||
client,
|
||||
)
|
||||
require.NoError(t, err)
|
||||
|
||||
// Build batch request
|
||||
req := contracts.DataFetcherBatchRequest{
|
||||
V2Pools: []common.Address{},
|
||||
V3Pools: []common.Address{
|
||||
common.HexToAddress(WETH_USDC_POOL_500_FEE),
|
||||
},
|
||||
}
|
||||
|
||||
// Fetch batch data
|
||||
response, err := dataFetcher.BatchFetchAllData(
|
||||
&bind.CallOpts{Context: ctx},
|
||||
req,
|
||||
)
|
||||
require.NoError(t, err, "Failed to fetch batch data")
|
||||
|
||||
t.Logf("Fetched %d V3 pool data entries", len(response.V3PoolData))
|
||||
|
||||
for i, poolData := range response.V3PoolData {
|
||||
t.Logf("Pool %d:", i)
|
||||
t.Logf(" Token0: %s", poolData.Token0.Hex())
|
||||
t.Logf(" Token1: %s", poolData.Token1.Hex())
|
||||
t.Logf(" Liquidity: %s", poolData.Liquidity.String())
|
||||
}
|
||||
*/
|
||||
|
||||
t.Log("DataFetcher test structure ready")
|
||||
}
|
||||
412
orig/tests/integration/full_pipeline_test.go
Normal file
412
orig/tests/integration/full_pipeline_test.go
Normal file
@@ -0,0 +1,412 @@
|
||||
//go:build integration && legacy && forked
|
||||
// +build integration,legacy,forked
|
||||
|
||||
// Package integration provides integration tests for the MEV bot using a forked Arbitrum environment
|
||||
package integration
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"math/big"
|
||||
"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/config"
|
||||
"github.com/fraktal/mev-beta/internal/logger"
|
||||
"github.com/fraktal/mev-beta/internal/ratelimit"
|
||||
"github.com/fraktal/mev-beta/pkg/contracts"
|
||||
"github.com/fraktal/mev-beta/pkg/database"
|
||||
"github.com/fraktal/mev-beta/pkg/market"
|
||||
"github.com/fraktal/mev-beta/pkg/monitor"
|
||||
"github.com/fraktal/mev-beta/pkg/orchestrator"
|
||||
"github.com/fraktal/mev-beta/pkg/pools"
|
||||
"github.com/fraktal/mev-beta/pkg/scanner"
|
||||
)
|
||||
|
||||
// TestFullArbitragePipeline tests the complete arbitrage detection and execution pipeline
|
||||
// using a forked Arbitrum environment
|
||||
func TestFullArbitragePipeline(t *testing.T) {
|
||||
// Skip this test in short mode
|
||||
if testing.Short() {
|
||||
t.Skip("skipping integration test in short mode")
|
||||
}
|
||||
|
||||
// Create test logger
|
||||
log := logger.New("debug", "text", "")
|
||||
|
||||
// Create test configuration
|
||||
cfg := createTestConfig()
|
||||
|
||||
// Connect to the forked environment
|
||||
client, err := ethclient.Dial(cfg.Arbitrum.RPCEndpoint)
|
||||
require.NoError(t, err, "failed to connect to forked Arbitrum")
|
||||
defer client.Close()
|
||||
|
||||
// Verify connection by getting chain ID
|
||||
chainID, err := client.ChainID(context.Background())
|
||||
require.NoError(t, err, "failed to get chain ID")
|
||||
log.Info(fmt.Sprintf("Connected to forked Arbitrum chain ID: %s", chainID.String()))
|
||||
|
||||
// Create rate limiter
|
||||
rateLimiter := ratelimit.NewLimiterManager(&cfg.Arbitrum)
|
||||
|
||||
// Create market manager
|
||||
marketMgr := market.NewMarketManager(&cfg.Uniswap, log)
|
||||
|
||||
// Create database (in-memory for testing)
|
||||
dbCfg := &config.DatabaseConfig{
|
||||
File: ":memory:",
|
||||
MaxOpenConnections: 10,
|
||||
MaxIdleConnections: 5,
|
||||
}
|
||||
db, err := database.NewDatabase(dbCfg, log)
|
||||
require.NoError(t, err, "failed to create database")
|
||||
defer db.Close()
|
||||
|
||||
// Create contract executor
|
||||
contractExecutor, err := contracts.NewContractExecutor(cfg, log)
|
||||
require.NoError(t, err, "failed to create contract executor")
|
||||
defer contractExecutor.Close()
|
||||
|
||||
// Create market scanner
|
||||
scanner := scanner.NewMarketScanner(&cfg.Bot, log, contractExecutor, db)
|
||||
|
||||
// Create MEV coordinator
|
||||
coordinator := orchestrator.NewMEVCoordinator(cfg, log, marketMgr, scanner, db)
|
||||
|
||||
// Create Arbitrum monitor
|
||||
monitor, err := monitor.NewArbitrumMonitor(
|
||||
&cfg.Arbitrum,
|
||||
&cfg.Bot,
|
||||
log,
|
||||
rateLimiter,
|
||||
marketMgr,
|
||||
scanner,
|
||||
coordinator,
|
||||
)
|
||||
require.NoError(t, err, "failed to create Arbitrum monitor")
|
||||
|
||||
// Test the full pipeline
|
||||
t.Run("TestArbitrageDetection", func(t *testing.T) {
|
||||
testArbitrageDetection(t, client, monitor, scanner, marketMgr, log)
|
||||
})
|
||||
|
||||
t.Run("TestPoolDiscovery", func(t *testing.T) {
|
||||
testPoolDiscovery(t, client, marketMgr, log)
|
||||
})
|
||||
|
||||
t.Run("TestArbitrageExecution", func(t *testing.T) {
|
||||
testArbitrageExecution(t, client, contractExecutor, log)
|
||||
})
|
||||
|
||||
// Cleanup
|
||||
monitor.Stop()
|
||||
scanner.Stop()
|
||||
coordinator.Stop()
|
||||
}
|
||||
|
||||
// createTestConfig creates a test configuration for the integration tests
|
||||
func createTestConfig() *config.Config {
|
||||
return &config.Config{
|
||||
Arbitrum: config.ArbitrumConfig{
|
||||
RPCEndpoint: "http://localhost:8545", // Anvil default port
|
||||
WSEndpoint: "",
|
||||
ChainID: 31337, // Anvil default chain ID
|
||||
RateLimit: config.RateLimitConfig{
|
||||
RequestsPerSecond: 10,
|
||||
MaxConcurrent: 5,
|
||||
Burst: 20,
|
||||
},
|
||||
FallbackEndpoints: []config.EndpointConfig{},
|
||||
},
|
||||
Bot: config.BotConfig{
|
||||
Enabled: true,
|
||||
PollingInterval: 1,
|
||||
MinProfitThreshold: 0.01, // Lower threshold for testing
|
||||
GasPriceMultiplier: 1.2,
|
||||
MaxWorkers: 2,
|
||||
ChannelBufferSize: 10,
|
||||
RPCTimeout: 30,
|
||||
},
|
||||
Uniswap: config.UniswapConfig{
|
||||
FactoryAddress: "0x1F98431c8aD98523631AE4a59f267346ea31F984",
|
||||
PositionManagerAddress: "0xC36442b4a4522E871399CD717aBDD847Ab11FE88",
|
||||
FeeTiers: []int64{500, 3000, 10000},
|
||||
Cache: config.CacheConfig{
|
||||
Enabled: true,
|
||||
Expiration: 300,
|
||||
MaxSize: 10000,
|
||||
},
|
||||
},
|
||||
Log: config.LogConfig{
|
||||
Level: "debug",
|
||||
Format: "text",
|
||||
File: "",
|
||||
},
|
||||
Database: config.DatabaseConfig{
|
||||
File: ":memory:",
|
||||
MaxOpenConnections: 10,
|
||||
MaxIdleConnections: 5,
|
||||
},
|
||||
Ethereum: config.EthereumConfig{
|
||||
PrivateKey: "", // Will be set by environment or test setup
|
||||
AccountAddress: "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266", // Default Anvil account
|
||||
GasPriceMultiplier: 1.2,
|
||||
},
|
||||
Contracts: config.ContractsConfig{
|
||||
ArbitrageExecutor: "0x...", // Will be deployed during test setup
|
||||
FlashSwapper: "0x...", // Will be deployed during test setup
|
||||
AuthorizedCallers: []string{
|
||||
"0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266", // Default Anvil account
|
||||
},
|
||||
AuthorizedDEXes: []string{
|
||||
"0x1F98431c8aD98523631AE4a59f267346ea31F984", // Uniswap V3 Factory
|
||||
"0xf1D7CC64Fb4452F05c498126312eBE29f30Fbcf9", // Uniswap V2 Factory
|
||||
"0xc35DADB65012eC5796536bD9864eD8773aBc74C4", // SushiSwap Factory
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// testArbitrageDetection tests arbitrage opportunity detection
|
||||
func testArbitrageDetection(t *testing.T, client *ethclient.Client, monitor *monitor.ArbitrumMonitor, scanner *scanner.MarketScanner, marketMgr *market.MarketManager, log *logger.Logger) {
|
||||
log.Info("Testing arbitrage detection...")
|
||||
|
||||
// Create context with timeout
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
|
||||
defer cancel()
|
||||
|
||||
// Start monitoring in a goroutine
|
||||
monitorDone := make(chan error, 1)
|
||||
go func() {
|
||||
monitorDone <- monitor.Start(ctx)
|
||||
}()
|
||||
|
||||
// Let the monitor run for a bit to detect events
|
||||
time.Sleep(5 * time.Second)
|
||||
|
||||
// Check if any arbitrage opportunities were detected
|
||||
// In a real test, we would simulate price movements to create opportunities
|
||||
|
||||
log.Info("Arbitrage detection test completed")
|
||||
}
|
||||
|
||||
// testPoolDiscovery tests pool discovery functionality
|
||||
func testPoolDiscovery(t *testing.T, client *ethclient.Client, marketMgr *market.MarketManager, log *logger.Logger) {
|
||||
log.Info("Testing pool discovery...")
|
||||
|
||||
// Test discovering pools for common token pairs
|
||||
knownPairs := []struct {
|
||||
token0 common.Address
|
||||
token1 common.Address
|
||||
}{
|
||||
{
|
||||
token0: common.HexToAddress("0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48"), // USDC
|
||||
token1: common.HexToAddress("0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2"), // WETH
|
||||
},
|
||||
{
|
||||
token0: common.HexToAddress("0xFF970A61A04b1cA14834A43f5dE4533eBDDB5CC8"), // USDT
|
||||
token1: common.HexToAddress("0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2"), // WETH
|
||||
},
|
||||
}
|
||||
|
||||
// Create CREATE2 calculator for pool discovery
|
||||
calculator := pools.NewCREATE2Calculator(log)
|
||||
|
||||
// Test pool discovery for each pair
|
||||
for _, pair := range knownPairs {
|
||||
log.Info(fmt.Sprintf("Discovering pools for %s-%s", pair.token0.Hex(), pair.token1.Hex()))
|
||||
|
||||
// Use CREATE2 calculator to find potential pools
|
||||
pools, err := calculator.FindPoolsForTokenPair(pair.token0, pair.token1)
|
||||
if err != nil {
|
||||
log.Warn(fmt.Sprintf("Failed to discover pools for %s-%s: %v", pair.token0.Hex(), pair.token1.Hex(), err))
|
||||
continue
|
||||
}
|
||||
|
||||
log.Info(fmt.Sprintf("Found %d potential pools for %s-%s", len(pools), pair.token0.Hex(), pair.token1.Hex()))
|
||||
|
||||
// Validate each pool
|
||||
for _, pool := range pools {
|
||||
log.Debug(fmt.Sprintf("Validating pool: %s (factory: %s)", pool.PoolAddr.Hex(), pool.Factory))
|
||||
|
||||
// In a real implementation, we would validate that the pool actually exists
|
||||
// and has liquidity. For now, we just log the discovery.
|
||||
}
|
||||
}
|
||||
|
||||
log.Info("Pool discovery test completed")
|
||||
}
|
||||
|
||||
// testArbitrageExecution tests arbitrage execution functionality
|
||||
func testArbitrageExecution(t *testing.T, client *ethclient.Client, contractExecutor *contracts.ContractExecutor, log *logger.Logger) {
|
||||
log.Info("Testing arbitrage execution...")
|
||||
|
||||
// Create a mock arbitrage opportunity for testing
|
||||
mockOpportunity := scanner.ArbitrageOpportunity{
|
||||
Path: []string{
|
||||
"0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48", // USDC
|
||||
"0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2", // WETH
|
||||
},
|
||||
Pools: []string{
|
||||
"0x88e6A0c2dDD26FEEb64F039a2c41296FcB3f5640", // Known USDC/WETH pool
|
||||
},
|
||||
Profit: big.NewInt(1000000000000000000), // 1 ETH profit estimate
|
||||
GasEstimate: big.NewInt(300000), // Estimated gas cost
|
||||
ROI: 5.0, // 5% ROI
|
||||
Protocol: "UniswapV3",
|
||||
}
|
||||
|
||||
// Test execution (this will fail in testing but we can verify the setup)
|
||||
log.Info("Setting up arbitrage execution test...")
|
||||
|
||||
// In a real test, we would:
|
||||
// 1. Deploy the contracts to the forked environment
|
||||
// 2. Fund the test account with tokens
|
||||
// 3. Create actual arbitrage opportunities by manipulating pool states
|
||||
// 4. Execute the arbitrage and verify profits
|
||||
|
||||
log.Info("Arbitrage execution test setup completed")
|
||||
}
|
||||
|
||||
// TestContractBindings tests that all contract bindings are working correctly
|
||||
func TestContractBindings(t *testing.T) {
|
||||
// Skip this test in short mode
|
||||
if testing.Short() {
|
||||
t.Skip("skipping contract binding test in short mode")
|
||||
}
|
||||
|
||||
log := logger.New("debug", "text", "")
|
||||
cfg := createTestConfig()
|
||||
|
||||
// Connect to the forked environment
|
||||
client, err := ethclient.Dial(cfg.Arbitrum.RPCEndpoint)
|
||||
require.NoError(t, err, "failed to connect to forked Arbitrum")
|
||||
defer client.Close()
|
||||
|
||||
// Test contract executor creation
|
||||
contractExecutor, err := contracts.NewContractExecutor(cfg, log)
|
||||
require.NoError(t, err, "failed to create contract executor")
|
||||
defer contractExecutor.Close()
|
||||
|
||||
// Verify contract executor was created successfully
|
||||
assert.NotNil(t, contractExecutor)
|
||||
assert.NotNil(t, contractExecutor.Client())
|
||||
|
||||
log.Info("Contract bindings test completed successfully")
|
||||
}
|
||||
|
||||
// TestDatabaseIntegration tests database integration with the scanner
|
||||
func TestDatabaseIntegration(t *testing.T) {
|
||||
// Skip this test in short mode
|
||||
if testing.Short() {
|
||||
t.Skip("skipping database integration test in short mode")
|
||||
}
|
||||
|
||||
log := logger.New("debug", "text", "")
|
||||
|
||||
// Create in-memory database for testing
|
||||
dbCfg := &config.DatabaseConfig{
|
||||
File: ":memory:",
|
||||
MaxOpenConnections: 10,
|
||||
MaxIdleConnections: 5,
|
||||
}
|
||||
db, err := database.NewDatabase(dbCfg, log)
|
||||
require.NoError(t, err, "failed to create database")
|
||||
defer db.Close()
|
||||
|
||||
// Test inserting swap event
|
||||
swapEvent := &database.SwapEvent{
|
||||
Timestamp: time.Now(),
|
||||
BlockNumber: 12345678,
|
||||
TxHash: common.HexToHash("0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef"),
|
||||
PoolAddress: common.HexToAddress("0x88e6A0c2dDD26FEEb64F039a2c41296FcB3f5640"),
|
||||
Token0: common.HexToAddress("0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48"), // USDC
|
||||
Token1: common.HexToAddress("0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2"), // WETH
|
||||
Amount0In: big.NewInt(1000000000), // 1000 USDC
|
||||
Amount1In: big.NewInt(0),
|
||||
Amount0Out: big.NewInt(0),
|
||||
Amount1Out: big.NewInt(500000000000000000), // 0.5 WETH
|
||||
Sender: common.HexToAddress("0x1234567890abcdef1234567890abcdef12345678"),
|
||||
Recipient: common.HexToAddress("0x8765432109fedcba8765432109fedcba87654321"),
|
||||
Protocol: "uniswap_v3",
|
||||
}
|
||||
|
||||
err = db.InsertSwapEvent(swapEvent)
|
||||
assert.NoError(t, err, "failed to insert swap event")
|
||||
|
||||
// Test inserting liquidity event
|
||||
liquidityEvent := &database.LiquidityEvent{
|
||||
Timestamp: time.Now(),
|
||||
BlockNumber: 12345679,
|
||||
TxHash: common.HexToHash("0xabcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890"),
|
||||
PoolAddress: common.HexToAddress("0x88e6A0c2dDD26FEEb64F039a2c41296FcB3f5640"),
|
||||
Token0: common.HexToAddress("0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48"), // USDC
|
||||
Token1: common.HexToAddress("0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2"), // WETH
|
||||
Liquidity: big.NewInt(1000000000000000000), // 1 ETH equivalent
|
||||
Amount0: big.NewInt(2000000000), // 2000 USDC
|
||||
Amount1: big.NewInt(1000000000000000000), // 1 WETH
|
||||
Sender: common.HexToAddress("0x1234567890abcdef1234567890abcdef12345678"),
|
||||
Recipient: common.HexToAddress("0x8765432109fedcba8765432109fedcba87654321"),
|
||||
EventType: "add",
|
||||
Protocol: "uniswap_v3",
|
||||
}
|
||||
|
||||
err = db.InsertLiquidityEvent(liquidityEvent)
|
||||
assert.NoError(t, err, "failed to insert liquidity event")
|
||||
|
||||
// Test inserting pool data
|
||||
poolData := &database.PoolData{
|
||||
Address: common.HexToAddress("0x88e6A0c2dDD26FEEb64F039a2c41296FcB3f5640"),
|
||||
Token0: common.HexToAddress("0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48"), // USDC
|
||||
Token1: common.HexToAddress("0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2"), // WETH
|
||||
Fee: 3000, // 0.3%
|
||||
Liquidity: big.NewInt(1000000000000000000), // 1 ETH equivalent
|
||||
SqrtPriceX96: big.NewInt(2505414483750470000), // Realistic price
|
||||
Tick: 200000, // Corresponding tick
|
||||
LastUpdated: time.Now(),
|
||||
Protocol: "uniswap_v3",
|
||||
}
|
||||
|
||||
err = db.InsertPoolData(poolData)
|
||||
assert.NoError(t, err, "failed to insert pool data")
|
||||
|
||||
// Test retrieving recent swap events
|
||||
swaps, err := db.GetRecentSwapEvents(10)
|
||||
assert.NoError(t, err, "failed to get recent swap events")
|
||||
assert.Len(t, swaps, 1, "expected 1 swap event")
|
||||
if len(swaps) > 0 {
|
||||
assert.Equal(t, swapEvent.PoolAddress, swaps[0].PoolAddress, "pool address mismatch")
|
||||
assert.Equal(t, swapEvent.Token0, swaps[0].Token0, "token0 mismatch")
|
||||
assert.Equal(t, swapEvent.Token1, swaps[0].Token1, "token1 mismatch")
|
||||
assert.Equal(t, swapEvent.Protocol, swaps[0].Protocol, "protocol mismatch")
|
||||
}
|
||||
|
||||
// Test retrieving recent liquidity events
|
||||
liquidityEvents, err := db.GetRecentLiquidityEvents(10)
|
||||
assert.NoError(t, err, "failed to get recent liquidity events")
|
||||
assert.Len(t, liquidityEvents, 1, "expected 1 liquidity event")
|
||||
if len(liquidityEvents) > 0 {
|
||||
assert.Equal(t, liquidityEvent.PoolAddress, liquidityEvents[0].PoolAddress, "pool address mismatch")
|
||||
assert.Equal(t, liquidityEvent.Token0, liquidityEvents[0].Token0, "token0 mismatch")
|
||||
assert.Equal(t, liquidityEvent.Token1, liquidityEvents[0].Token1, "token1 mismatch")
|
||||
assert.Equal(t, liquidityEvent.EventType, liquidityEvents[0].EventType, "event type mismatch")
|
||||
assert.Equal(t, liquidityEvent.Protocol, liquidityEvents[0].Protocol, "protocol mismatch")
|
||||
}
|
||||
|
||||
// Test retrieving pool data
|
||||
retrievedPool, err := db.GetPoolData(poolData.Address)
|
||||
assert.NoError(t, err, "failed to get pool data")
|
||||
assert.Equal(t, poolData.Address, retrievedPool.Address, "pool address mismatch")
|
||||
assert.Equal(t, poolData.Token0, retrievedPool.Token0, "token0 mismatch")
|
||||
assert.Equal(t, poolData.Token1, retrievedPool.Token1, "token1 mismatch")
|
||||
assert.Equal(t, poolData.Fee, retrievedPool.Fee, "fee mismatch")
|
||||
assert.Equal(t, poolData.Protocol, retrievedPool.Protocol, "protocol mismatch")
|
||||
|
||||
log.Info("Database integration test completed successfully")
|
||||
}
|
||||
180
orig/tests/integration/pool_discovery_test.go
Normal file
180
orig/tests/integration/pool_discovery_test.go
Normal file
@@ -0,0 +1,180 @@
|
||||
//go:build integration && legacy && forked
|
||||
// +build integration,legacy,forked
|
||||
|
||||
// Package integration provides integration tests for the MEV bot using a forked Arbitrum environment
|
||||
package integration
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/fraktal/mev-beta/internal/logger"
|
||||
"github.com/fraktal/mev-beta/pkg/pools"
|
||||
)
|
||||
|
||||
// TestPoolDiscovery tests that the pool discovery mechanism works correctly
|
||||
func TestPoolDiscovery(t *testing.T) {
|
||||
// Skip this test in short mode
|
||||
if testing.Short() {
|
||||
t.Skip("skipping pool discovery test in short mode")
|
||||
}
|
||||
|
||||
// Create test logger
|
||||
log := logger.New("debug", "text", "")
|
||||
|
||||
// Create CREATE2 calculator
|
||||
calculator := pools.NewCREATE2Calculator(log)
|
||||
|
||||
// Test discovering pools for common token pairs on Arbitrum
|
||||
testCases := []struct {
|
||||
name string
|
||||
token0 string
|
||||
token1 string
|
||||
expected int
|
||||
}{
|
||||
{
|
||||
name: "USDC/WETH",
|
||||
token0: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48", // USDC
|
||||
token1: "0x82aF49447D8a07e3bd95BD0d56f35241523fBab1", // WETH
|
||||
expected: 3, // Uniswap V3, SushiSwap, Camelot V3
|
||||
},
|
||||
{
|
||||
name: "USDT/WETH",
|
||||
token0: "0xFd086bC7CD5C481DCC9C85ebE478A1C0b69FCbb9", // USDT
|
||||
token1: "0x82aF49447D8a07e3bd95BD0d56f35241523fBab1", // WETH
|
||||
expected: 3, // Uniswap V3, SushiSwap, Camelot V3
|
||||
},
|
||||
{
|
||||
name: "ARB/WETH",
|
||||
token0: "0x912CE59144191C1204E64559FE8253a0e49E6548", // ARB
|
||||
token1: "0x82aF49447D8a07e3bd95BD0d56f35241523fBab1", // WETH
|
||||
expected: 3, // Uniswap V3, SushiSwap, Camelot V3
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
// Convert hex addresses to common.Address
|
||||
token0 := common.HexToAddress(tc.token0)
|
||||
token1 := common.HexToAddress(tc.token1)
|
||||
|
||||
// Discover pools for this token pair
|
||||
pools, err := calculator.FindPoolsForTokenPair(token0, token1)
|
||||
require.NoError(t, err, "failed to discover pools for token pair")
|
||||
|
||||
// Verify we found the expected number of pools
|
||||
assert.GreaterOrEqual(t, len(pools), tc.expected, "should find at least %d pools for %s", tc.expected, tc.name)
|
||||
|
||||
// Verify each pool has valid data
|
||||
for i, pool := range pools {
|
||||
assert.NotEqual(t, "", pool.Factory, "pool %d should have a factory name", i)
|
||||
assert.NotEqual(t, common.Address{}, pool.Token0, "pool %d should have token0", i)
|
||||
assert.NotEqual(t, common.Address{}, pool.Token1, "pool %d should have token1", i)
|
||||
assert.NotEqual(t, common.Address{}, pool.PoolAddr, "pool %d should have a pool address", i)
|
||||
assert.True(t, pool.Fee >= 0, "pool %d should have a non-negative fee", i)
|
||||
|
||||
log.Info("Discovered pool:", pool.Factory, pool.PoolAddr.Hex())
|
||||
}
|
||||
|
||||
log.Info("Found", len(pools), "pools for", tc.name)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// TestFactoryConfigurations tests that all factory configurations are properly loaded
|
||||
func TestFactoryConfigurations(t *testing.T) {
|
||||
// Create test logger
|
||||
log := logger.New("debug", "text", "")
|
||||
|
||||
// Create CREATE2 calculator
|
||||
calculator := pools.NewCREATE2Calculator(log)
|
||||
|
||||
// Get list of all factories
|
||||
factories := calculator.ListFactories()
|
||||
assert.Greater(t, len(factories), 0, "should have at least one factory configured")
|
||||
|
||||
// Verify each factory has valid configuration
|
||||
for _, factoryName := range factories {
|
||||
t.Run(factoryName, func(t *testing.T) {
|
||||
config, err := calculator.GetFactoryConfig(factoryName)
|
||||
assert.NoError(t, err, "should be able to get config for factory %s", factoryName)
|
||||
assert.NotNil(t, config, "config should not be nil for factory %s", factoryName)
|
||||
assert.NotEqual(t, common.Address{}, config.Address, "factory %s should have a valid address", factoryName)
|
||||
assert.NotEqual(t, common.Hash{}, config.InitCodeHash, "factory %s should have a valid init code hash", factoryName)
|
||||
assert.Greater(t, len(config.FeeStructure.DefaultFees), 0, "factory %s should have default fees", factoryName)
|
||||
})
|
||||
}
|
||||
|
||||
log.Info("Verified", len(factories), "factories")
|
||||
}
|
||||
|
||||
// TestPoolAddressCalculation tests that pool addresses are calculated correctly
|
||||
func TestPoolAddressCalculation(t *testing.T) {
|
||||
// Create test logger
|
||||
log := logger.New("debug", "text", "")
|
||||
|
||||
// Create CREATE2 calculator
|
||||
calculator := pools.NewCREATE2Calculator(log)
|
||||
|
||||
// Test known pool addresses on Arbitrum
|
||||
testCases := []struct {
|
||||
name string
|
||||
factory string
|
||||
token0 string
|
||||
token1 string
|
||||
fee uint32
|
||||
expectedAddr string
|
||||
}{
|
||||
{
|
||||
name: "Uniswap V3 USDC/WETH 0.05%",
|
||||
factory: "uniswap_v3",
|
||||
token0: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48", // USDC
|
||||
token1: "0x82aF49447D8a07e3bd95BD0d56f35241523fBab1", // WETH
|
||||
fee: 500, // 0.05%
|
||||
expectedAddr: "0xC6962004f452bE9203591991D15f6b388e09E8D0",
|
||||
},
|
||||
{
|
||||
name: "Uniswap V3 USDC/WETH 0.3%",
|
||||
factory: "uniswap_v3",
|
||||
token0: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48", // USDC
|
||||
token1: "0x82aF49447D8a07e3bd95BD0d56f35241523fBab1", // WETH
|
||||
fee: 3000, // 0.3%
|
||||
expectedAddr: "0x88e6A0c2dDD26FEEb64F039a2c41296FcB3f5640",
|
||||
},
|
||||
{
|
||||
name: "Uniswap V3 USDC/WETH 1%",
|
||||
factory: "uniswap_v3",
|
||||
token0: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48", // USDC
|
||||
token1: "0x82aF49447D8a07e3bd95BD0d56f35241523fBab1", // WETH
|
||||
fee: 10000, // 1%
|
||||
expectedAddr: "0x7f90122BF0700F9E7e1F688fe926940E8839F353",
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
// Convert hex addresses to common.Address
|
||||
token0 := common.HexToAddress(tc.token0)
|
||||
token1 := common.HexToAddress(tc.token1)
|
||||
expectedAddr := common.HexToAddress(tc.expectedAddr)
|
||||
|
||||
// Calculate pool address
|
||||
calculatedAddr, err := calculator.CalculatePoolAddress(tc.factory, token0, token1, tc.fee)
|
||||
require.NoError(t, err, "should be able to calculate pool address")
|
||||
|
||||
// Verify the calculated address matches expected (this may fail for placeholder addresses)
|
||||
if tc.expectedAddr != "0x0000000000000000000000000000000000000000" {
|
||||
// For now, just log the addresses for verification
|
||||
log.Info("Calculated pool address:", calculatedAddr.Hex())
|
||||
log.Info("Expected pool address: ", expectedAddr.Hex())
|
||||
log.Info("Match:", calculatedAddr == expectedAddr)
|
||||
} else {
|
||||
// Just verify the address is not zero
|
||||
assert.NotEqual(t, common.Address{}, calculatedAddr, "calculated address should not be zero")
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user