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)
|
||||
}
|
||||
Reference in New Issue
Block a user