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:
398
orig/test/production/arbitrage_validation_test.go
Normal file
398
orig/test/production/arbitrage_validation_test.go
Normal file
@@ -0,0 +1,398 @@
|
||||
//go:build integration && legacy && forked
|
||||
// +build integration,legacy,forked
|
||||
|
||||
package production_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"log"
|
||||
"math/big"
|
||||
"os"
|
||||
"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/ethereum/go-ethereum/ethclient"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/fraktal/mev-beta/bindings/arbitrage"
|
||||
"github.com/fraktal/mev-beta/internal/config"
|
||||
arbService "github.com/fraktal/mev-beta/pkg/arbitrage"
|
||||
"github.com/fraktal/mev-beta/pkg/arbitrum"
|
||||
"github.com/fraktal/mev-beta/pkg/mev"
|
||||
"github.com/fraktal/mev-beta/pkg/monitor"
|
||||
"github.com/fraktal/mev-beta/pkg/uniswap"
|
||||
)
|
||||
|
||||
// ProductionLogger provides structured logging for production validation
|
||||
type ProductionLogger struct {
|
||||
*log.Logger
|
||||
}
|
||||
|
||||
func NewProductionLogger() *ProductionLogger {
|
||||
return &ProductionLogger{
|
||||
Logger: log.New(os.Stdout, "[PRODUCTION-TEST] ", log.LstdFlags|log.Lmicroseconds),
|
||||
}
|
||||
}
|
||||
|
||||
func (pl *ProductionLogger) LogArbitrageOpportunity(opportunity *mev.MEVOpportunity, profit *big.Int) {
|
||||
profitETH := new(big.Float).Quo(new(big.Float).SetInt(profit), new(big.Float).SetInt(big.NewInt(1e18)))
|
||||
pl.Printf("🎯 ARBITRAGE OPPORTUNITY DETECTED: Pool=%s, Type=%s, EstimatedProfit=%.6f ETH",
|
||||
opportunity.PoolAddress.Hex(), opportunity.Type, profitETH)
|
||||
}
|
||||
|
||||
func (pl *ProductionLogger) LogTradeExecution(txHash common.Hash, gasUsed uint64, actualProfit *big.Int) {
|
||||
profitETH := new(big.Float).Quo(new(big.Float).SetInt(actualProfit), new(big.Float).SetInt(big.NewInt(1e18)))
|
||||
pl.Printf("⚡ ARBITRAGE EXECUTED: TxHash=%s, GasUsed=%d, ActualProfit=%.6f ETH",
|
||||
txHash.Hex(), gasUsed, profitETH)
|
||||
}
|
||||
|
||||
func (pl *ProductionLogger) LogMarketConditions(pool1Price, pool2Price *big.Int, spread *big.Float) {
|
||||
price1ETH := new(big.Float).Quo(new(big.Float).SetInt(pool1Price), new(big.Float).SetInt(big.NewInt(1e6)))
|
||||
price2ETH := new(big.Float).Quo(new(big.Float).SetInt(pool2Price), new(big.Float).SetInt(big.NewInt(1e6)))
|
||||
pl.Printf("📊 MARKET CONDITIONS: Pool1Price=%.2f USDC, Pool2Price=%.2f USDC, Spread=%.4f%%",
|
||||
price1ETH, price2ETH, spread)
|
||||
}
|
||||
|
||||
// TestProductionArbitrageValidation proves the bot can detect and execute real arbitrages
|
||||
func TestProductionArbitrageValidation(t *testing.T) {
|
||||
logger := NewProductionLogger()
|
||||
logger.Printf("🚀 STARTING PRODUCTION ARBITRAGE VALIDATION TEST")
|
||||
|
||||
// Setup forked Arbitrum environment
|
||||
client, cleanup := setupForkedArbitrum(t)
|
||||
defer cleanup()
|
||||
|
||||
logger.Printf("✅ Connected to forked Arbitrum mainnet")
|
||||
|
||||
// Validate we can connect to real Arbitrum contracts
|
||||
ctx := context.Background()
|
||||
|
||||
// Real Arbitrum pool addresses with different fee tiers
|
||||
wethUsdcPool05 := common.HexToAddress("0xC31E54c7a869B9FcBEcc14363CF510d1c41fa443") // 0.05% fee
|
||||
wethUsdcPool30 := common.HexToAddress("0x17c14D2c404D167802b16C450d3c99F88F2c4F4d") // 0.3% fee
|
||||
|
||||
logger.Printf("📍 Target Pools: WETH/USDC 0.05%% (%s), WETH/USDC 0.30%% (%s)",
|
||||
wethUsdcPool05.Hex(), wethUsdcPool30.Hex())
|
||||
|
||||
t.Run("Real World Market Analysis", func(t *testing.T) {
|
||||
logger.Printf("🔍 ANALYZING REAL MARKET CONDITIONS...")
|
||||
|
||||
// Get current prices from both pools
|
||||
price1, err := uniswap.GetPoolPrice(client, wethUsdcPool05)
|
||||
require.NoError(t, err, "Failed to get price from 0.05% pool")
|
||||
|
||||
price2, err := uniswap.GetPoolPrice(client, wethUsdcPool30)
|
||||
require.NoError(t, err, "Failed to get price from 0.30% pool")
|
||||
|
||||
// Calculate price spread
|
||||
priceDiff := new(big.Int).Sub(price1, price2)
|
||||
if priceDiff.Sign() < 0 {
|
||||
priceDiff.Neg(priceDiff)
|
||||
}
|
||||
|
||||
spreadBasisPoints := new(big.Int).Div(
|
||||
new(big.Int).Mul(priceDiff, big.NewInt(10000)),
|
||||
price1,
|
||||
)
|
||||
|
||||
spreadPercent := new(big.Float).Quo(
|
||||
new(big.Float).SetInt(spreadBasisPoints),
|
||||
new(big.Float).SetInt(big.NewInt(100)),
|
||||
)
|
||||
|
||||
logger.LogMarketConditions(price1, price2, spreadPercent)
|
||||
|
||||
// Validate prices are reasonable (WETH/USDC should be between $1000-$10000)
|
||||
minPrice := big.NewInt(1000 * 1e6) // $1000 USDC
|
||||
maxPrice := big.NewInt(10000 * 1e6) // $10000 USDC
|
||||
|
||||
assert.True(t, price1.Cmp(minPrice) >= 0 && price1.Cmp(maxPrice) <= 0,
|
||||
"Pool 1 price should be reasonable: got %s USDC",
|
||||
new(big.Float).Quo(new(big.Float).SetInt(price1), new(big.Float).SetInt(big.NewInt(1e6))))
|
||||
|
||||
assert.True(t, price2.Cmp(minPrice) >= 0 && price2.Cmp(maxPrice) <= 0,
|
||||
"Pool 2 price should be reasonable: got %s USDC",
|
||||
new(big.Float).Quo(new(big.Float).SetInt(price2), new(big.Float).SetInt(big.NewInt(1e6))))
|
||||
|
||||
logger.Printf("✅ Market conditions validated - prices are within expected ranges")
|
||||
})
|
||||
|
||||
t.Run("Live Arbitrage Opportunity Detection", func(t *testing.T) {
|
||||
logger.Printf("🎯 TESTING LIVE ARBITRAGE OPPORTUNITY DETECTION...")
|
||||
|
||||
// Deploy our arbitrage contract to forked environment
|
||||
privateKey, err := crypto.GenerateKey()
|
||||
require.NoError(t, err)
|
||||
|
||||
auth, err := bind.NewKeyedTransactorWithChainID(privateKey, big.NewInt(42161))
|
||||
require.NoError(t, err)
|
||||
|
||||
// Set reasonable gas price for Arbitrum
|
||||
gasPrice, err := client.SuggestGasPrice(ctx)
|
||||
require.NoError(t, err)
|
||||
auth.GasPrice = gasPrice
|
||||
auth.GasLimit = uint64(5000000)
|
||||
|
||||
logger.Printf("⚙️ Deploying arbitrage contract with gas price: %s gwei",
|
||||
new(big.Float).Quo(new(big.Float).SetInt(gasPrice), new(big.Float).SetInt(big.NewInt(1e9))))
|
||||
|
||||
// Deploy ArbitrageExecutor
|
||||
contractAddr, tx, contract, err := arbitrage.DeployArbitrageExecutor(
|
||||
auth,
|
||||
client,
|
||||
common.HexToAddress("0x1F98431c8aD98523631AE4a59f267346ea31F984"), // Uniswap V3 Factory
|
||||
common.HexToAddress("0x82aF49447D8a07e3bd95BD0d56f35241523fBab1"), // WETH
|
||||
)
|
||||
require.NoError(t, err, "Failed to deploy arbitrage contract")
|
||||
|
||||
logger.Printf("📝 Contract deployment tx: %s", tx.Hash().Hex())
|
||||
|
||||
// Wait for deployment
|
||||
receipt, err := bind.WaitMined(ctx, client, tx)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, types.ReceiptStatusSuccessful, receipt.Status)
|
||||
|
||||
logger.Printf("✅ ArbitrageExecutor deployed at: %s (Gas used: %d)",
|
||||
contractAddr.Hex(), receipt.GasUsed)
|
||||
|
||||
// Test arbitrage opportunity detection
|
||||
swapAmount := big.NewInt(1000000000000000000) // 1 ETH
|
||||
|
||||
opportunity, err := contract.DetectArbitrageOpportunity(nil, wethUsdcPool05, wethUsdcPool30, swapAmount)
|
||||
require.NoError(t, err, "Failed to detect arbitrage opportunity")
|
||||
|
||||
logger.LogArbitrageOpportunity(&mev.MEVOpportunity{
|
||||
Type: mev.TypeArbitrage,
|
||||
EstimatedProfit: opportunity.EstimatedProfit,
|
||||
PoolAddress: wethUsdcPool05,
|
||||
}, opportunity.EstimatedProfit)
|
||||
|
||||
if opportunity.Profitable {
|
||||
logger.Printf("🎉 PROFITABLE ARBITRAGE DETECTED!")
|
||||
|
||||
// Calculate net profit after gas costs
|
||||
gasEstimate := big.NewInt(300000) // Estimated gas for arbitrage
|
||||
gasCost := new(big.Int).Mul(gasPrice, gasEstimate)
|
||||
netProfit := new(big.Int).Sub(opportunity.EstimatedProfit, gasCost)
|
||||
|
||||
netProfitETH := new(big.Float).Quo(new(big.Float).SetInt(netProfit), new(big.Float).SetInt(big.NewInt(1e18)))
|
||||
logger.Printf("💰 Net profit after gas: %.6f ETH", netProfitETH)
|
||||
|
||||
assert.True(t, netProfit.Sign() > 0, "Net profit should be positive after gas costs")
|
||||
} else {
|
||||
logger.Printf("ℹ️ No profitable arbitrage found in current market conditions")
|
||||
// This is acceptable - real markets may not always have arbitrage opportunities
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("MEV Competition Analysis", func(t *testing.T) {
|
||||
logger.Printf("🏁 TESTING 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: wethUsdcPool05,
|
||||
Timestamp: time.Now(),
|
||||
}
|
||||
|
||||
competition, err := analyzer.AnalyzeCompetition(ctx, opportunity)
|
||||
require.NoError(t, err, "Failed to analyze MEV competition")
|
||||
|
||||
logger.Printf("🏆 Competition Analysis: Competitors=%d, AvgPriorityFee=%s gwei, SuccessRate=%.2f%%",
|
||||
competition.CompetitorCount,
|
||||
new(big.Float).Quo(new(big.Float).SetInt(competition.AveragePriorityFee), new(big.Float).SetInt(big.NewInt(1e9))),
|
||||
competition.SuccessRate*100)
|
||||
|
||||
strategy, err := analyzer.CalculateOptimalBid(ctx, opportunity, competition)
|
||||
require.NoError(t, err, "Failed to calculate optimal bidding strategy")
|
||||
|
||||
logger.Printf("💡 Optimal Strategy: PriorityFee=%s gwei, MaxFee=%s gwei, ExpectedProfit=%.6f ETH",
|
||||
new(big.Float).Quo(new(big.Float).SetInt(strategy.PriorityFeePerGas), new(big.Float).SetInt(big.NewInt(1e9))),
|
||||
new(big.Float).Quo(new(big.Float).SetInt(strategy.MaxFeePerGas), new(big.Float).SetInt(big.NewInt(1e9))),
|
||||
new(big.Float).Quo(new(big.Float).SetInt(strategy.ExpectedProfit), new(big.Float).SetInt(big.NewInt(1e18))))
|
||||
|
||||
assert.Greater(t, strategy.ExpectedProfit.Sign(), 0, "Strategy should maintain profitability")
|
||||
})
|
||||
|
||||
t.Run("Real-Time Market Monitoring", func(t *testing.T) {
|
||||
logger.Printf("📡 TESTING REAL-TIME MARKET MONITORING...")
|
||||
|
||||
// Setup connection manager with fallback
|
||||
cfg := &config.ArbitrumConfig{
|
||||
RPCEndpoint: os.Getenv("ARBITRUM_RPC_ENDPOINT"),
|
||||
}
|
||||
|
||||
connManager := arbitrum.NewConnectionManager(cfg)
|
||||
defer connManager.Close()
|
||||
|
||||
// Test connection with automatic fallback
|
||||
healthyClient, err := connManager.GetClientWithRetry(ctx, 3)
|
||||
require.NoError(t, err, "Failed to get healthy client connection")
|
||||
defer healthyClient.Close()
|
||||
|
||||
logger.Printf("✅ Established healthy connection with fallback support")
|
||||
|
||||
// Test real-time block monitoring
|
||||
monitor := monitor.NewConcurrentMonitor(healthyClient)
|
||||
|
||||
// Monitor for 30 seconds to catch real blocks
|
||||
monitorCtx, cancel := context.WithTimeout(ctx, 30*time.Second)
|
||||
defer cancel()
|
||||
|
||||
blockChan := make(chan uint64, 10)
|
||||
eventChan := make(chan *arbService.SimpleSwapEvent, 100)
|
||||
|
||||
// Start monitoring in background
|
||||
go func() {
|
||||
err := monitor.StartMonitoring(monitorCtx, blockChan)
|
||||
if err != nil {
|
||||
logger.Printf("❌ Monitoring error: %v", err)
|
||||
}
|
||||
}()
|
||||
|
||||
// Process blocks and detect swap events
|
||||
go func() {
|
||||
for {
|
||||
select {
|
||||
case blockNum := <-blockChan:
|
||||
logger.Printf("📦 Processing block: %d", blockNum)
|
||||
|
||||
// Get block and analyze transactions
|
||||
block, err := healthyClient.BlockByNumber(monitorCtx, big.NewInt(int64(blockNum)))
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
|
||||
// Look for large swaps that could create arbitrage opportunities
|
||||
for _, tx := range block.Transactions() {
|
||||
if tx.To() != nil &&
|
||||
(tx.To().Hex() == wethUsdcPool05.Hex() || tx.To().Hex() == wethUsdcPool30.Hex()) {
|
||||
|
||||
logger.Printf("🔄 Large swap detected in target pool: TxHash=%s, Pool=%s",
|
||||
tx.Hash().Hex(), tx.To().Hex())
|
||||
|
||||
// Create mock swap event for testing
|
||||
mockEvent := &arbService.SimpleSwapEvent{
|
||||
TxHash: tx.Hash(),
|
||||
Pool: *tx.To(),
|
||||
Token0: common.HexToAddress("0x82aF49447D8a07e3bd95BD0d56f35241523fBab1"), // WETH
|
||||
Token1: common.HexToAddress("0xaf88d065e77c8cC2239327C5EDb3A432268e5831"), // USDC
|
||||
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 }(),
|
||||
}
|
||||
|
||||
eventChan <- mockEvent
|
||||
}
|
||||
}
|
||||
|
||||
case <-monitorCtx.Done():
|
||||
return
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
// Collect and analyze events
|
||||
eventCount := 0
|
||||
arbitrageCount := 0
|
||||
|
||||
for {
|
||||
select {
|
||||
case event := <-eventChan:
|
||||
eventCount++
|
||||
logger.Printf("⚡ Swap event #%d: Pool=%s, Amount0=%s ETH",
|
||||
eventCount, event.Pool.Hex(),
|
||||
new(big.Float).Quo(new(big.Float).SetInt(event.Amount0), new(big.Float).SetInt(big.NewInt(1e18))))
|
||||
|
||||
// Check if this creates arbitrage opportunity
|
||||
if event.Amount0.Cmp(big.NewInt(500000000000000000)) >= 0 { // >= 0.5 ETH
|
||||
arbitrageCount++
|
||||
logger.Printf("🎯 Large swap detected - potential arbitrage opportunity #%d", arbitrageCount)
|
||||
}
|
||||
|
||||
case <-monitorCtx.Done():
|
||||
logger.Printf("📊 MONITORING SUMMARY: ProcessedEvents=%d, PotentialArbitrages=%d",
|
||||
eventCount, arbitrageCount)
|
||||
return
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("Production Configuration Validation", func(t *testing.T) {
|
||||
logger.Printf("⚙️ VALIDATING PRODUCTION CONFIGURATION...")
|
||||
|
||||
// Test configuration loading
|
||||
cfg, err := config.Load("../../config/arbitrum_production.yaml")
|
||||
require.NoError(t, err, "Failed to load production config")
|
||||
|
||||
// Validate all critical addresses are configured
|
||||
assert.NotEmpty(t, cfg.Arbitrum.RPCEndpoint, "RPC endpoint must be configured")
|
||||
assert.NotEmpty(t, cfg.Arbitrum.FallbackEndpoints, "Fallback endpoints must be configured")
|
||||
assert.Greater(t, len(cfg.Arbitrum.FallbackEndpoints), 2, "Should have multiple fallback endpoints")
|
||||
|
||||
logger.Printf("✅ Configuration validation passed:")
|
||||
logger.Printf(" - Primary RPC: %s", cfg.Arbitrum.RPCEndpoint)
|
||||
logger.Printf(" - Fallback endpoints: %d configured", len(cfg.Arbitrum.FallbackEndpoints))
|
||||
logger.Printf(" - Rate limit: %d RPS", cfg.Arbitrum.RateLimit.RequestsPerSecond)
|
||||
|
||||
// Test environment variable override
|
||||
originalEndpoint := os.Getenv("ARBITRUM_RPC_ENDPOINT")
|
||||
testEndpoint := "wss://test-override.com"
|
||||
os.Setenv("ARBITRUM_RPC_ENDPOINT", testEndpoint)
|
||||
defer func() {
|
||||
if originalEndpoint != "" {
|
||||
os.Setenv("ARBITRUM_RPC_ENDPOINT", originalEndpoint)
|
||||
} else {
|
||||
os.Unsetenv("ARBITRUM_RPC_ENDPOINT")
|
||||
}
|
||||
}()
|
||||
|
||||
cfg.OverrideWithEnv()
|
||||
assert.Equal(t, testEndpoint, cfg.Arbitrum.RPCEndpoint, "Environment variable should override config")
|
||||
|
||||
logger.Printf("✅ Environment variable override working correctly")
|
||||
})
|
||||
|
||||
logger.Printf("🎉 PRODUCTION VALIDATION COMPLETED SUCCESSFULLY!")
|
||||
logger.Printf("📋 VALIDATION SUMMARY:")
|
||||
logger.Printf(" ✅ Real market data access verified")
|
||||
logger.Printf(" ✅ Smart contract deployment successful")
|
||||
logger.Printf(" ✅ Arbitrage detection functional")
|
||||
logger.Printf(" ✅ MEV competition analysis working")
|
||||
logger.Printf(" ✅ Real-time monitoring operational")
|
||||
logger.Printf(" ✅ Configuration system validated")
|
||||
logger.Printf(" ✅ Fallback connectivity confirmed")
|
||||
logger.Printf("")
|
||||
logger.Printf("🚀 THE MEV BOT IS PRODUCTION READY!")
|
||||
}
|
||||
|
||||
// setupForkedArbitrum sets up a forked Arbitrum environment for testing
|
||||
func setupForkedArbitrum(t *testing.T) (*ethclient.Client, func()) {
|
||||
// Use environment variable or default to a working endpoint
|
||||
rpcEndpoint := os.Getenv("ARBITRUM_RPC_ENDPOINT")
|
||||
if rpcEndpoint == "" {
|
||||
rpcEndpoint = "https://arb1.arbitrum.io/rpc" // Public endpoint for testing
|
||||
}
|
||||
|
||||
client, err := ethclient.Dial(rpcEndpoint)
|
||||
require.NoError(t, err, "Failed to connect to Arbitrum")
|
||||
|
||||
// Verify we're connected to Arbitrum mainnet
|
||||
chainID, err := client.ChainID(context.Background())
|
||||
require.NoError(t, err, "Failed to get chain ID")
|
||||
require.Equal(t, int64(42161), chainID.Int64(), "Must be connected to Arbitrum mainnet")
|
||||
|
||||
cleanup := func() {
|
||||
client.Close()
|
||||
}
|
||||
|
||||
return client, cleanup
|
||||
}
|
||||
298
orig/test/production/deployed_contracts_demo_test.go
Normal file
298
orig/test/production/deployed_contracts_demo_test.go
Normal file
@@ -0,0 +1,298 @@
|
||||
//go:build integration && legacy && forked
|
||||
// +build integration,legacy,forked
|
||||
|
||||
package production_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"log"
|
||||
"math/big"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/ethereum/go-ethereum"
|
||||
"github.com/ethereum/go-ethereum/accounts/abi"
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/ethclient"
|
||||
)
|
||||
|
||||
// ContractInfo holds contract metadata from JSON files
|
||||
type ContractInfo struct {
|
||||
ABI []interface{} `json:"abi"`
|
||||
}
|
||||
|
||||
// DeployedContractsTester validates our integration with real deployed contracts
|
||||
type DeployedContractsTester struct {
|
||||
client *ethclient.Client
|
||||
logger *log.Logger
|
||||
contracts map[string]ContractDetails
|
||||
}
|
||||
|
||||
type ContractDetails struct {
|
||||
Address common.Address
|
||||
ABI abi.ABI
|
||||
CodeSize int
|
||||
}
|
||||
|
||||
func NewDeployedContractsTester() *DeployedContractsTester {
|
||||
return &DeployedContractsTester{
|
||||
logger: log.New(os.Stdout, "[DEPLOYED-CONTRACTS] ", log.LstdFlags|log.Lmicroseconds),
|
||||
contracts: make(map[string]ContractDetails),
|
||||
}
|
||||
}
|
||||
|
||||
func main() {
|
||||
tester := NewDeployedContractsTester()
|
||||
tester.logger.Printf("🚀 TESTING INTEGRATION WITH REAL DEPLOYED MEV CONTRACTS")
|
||||
|
||||
// Connect to Arbitrum
|
||||
rpcEndpoint := os.Getenv("ARBITRUM_RPC_ENDPOINT")
|
||||
if rpcEndpoint == "" {
|
||||
rpcEndpoint = "https://arb1.arbitrum.io/rpc"
|
||||
}
|
||||
|
||||
var err error
|
||||
tester.client, err = ethclient.Dial(rpcEndpoint)
|
||||
if err != nil {
|
||||
tester.logger.Fatalf("❌ Failed to connect to Arbitrum: %v", err)
|
||||
}
|
||||
defer tester.client.Close()
|
||||
|
||||
ctx := context.Background()
|
||||
|
||||
// Verify we're on Arbitrum
|
||||
chainID, err := tester.client.ChainID(ctx)
|
||||
if err != nil {
|
||||
tester.logger.Fatalf("❌ Failed to get chain ID: %v", err)
|
||||
}
|
||||
|
||||
if chainID.Int64() != 42161 {
|
||||
tester.logger.Fatalf("❌ Not connected to Arbitrum mainnet. Got chain ID: %d", chainID.Int64())
|
||||
}
|
||||
|
||||
tester.logger.Printf("✅ Connected to Arbitrum mainnet (Chain ID: %d)", chainID.Int64())
|
||||
|
||||
// Real deployed contract addresses from Mev-Alpha
|
||||
deployedContracts := map[string]string{
|
||||
"ArbitrageExecutor": "0xec2a16d5f8ac850d08c4c7f67efd50051e7cfc0b",
|
||||
"UniswapV3FlashSwapper": "0x5801ee5c2f6069e0f11cce7c0f27c2ef88e79a95",
|
||||
"DataFetcher": "0x3c2c9c86f081b9dac1f0bf97981cfbe96436b89d",
|
||||
"UniswapV2FlashSwapper": "0xc0b8c3e9a976ec67d182d7cb0283fb4496692593",
|
||||
}
|
||||
|
||||
tester.logger.Printf("🎯 Validating %d deployed contracts...", len(deployedContracts))
|
||||
|
||||
// Test 1: Verify all contracts exist and have code
|
||||
tester.testContractExistence(ctx, deployedContracts)
|
||||
|
||||
// Test 2: Load ABIs and validate contract interfaces
|
||||
tester.loadContractABIs()
|
||||
|
||||
// Test 3: Test contract interactions
|
||||
tester.testContractInteractions(ctx)
|
||||
|
||||
// Test 4: Validate authorization setup
|
||||
tester.testContractAuthorization(ctx)
|
||||
|
||||
// Test 5: Test arbitrage opportunity detection
|
||||
tester.testArbitrageDetection(ctx)
|
||||
|
||||
tester.logger.Printf("")
|
||||
tester.logger.Printf("🎉 DEPLOYED CONTRACTS INTEGRATION VALIDATION COMPLETED!")
|
||||
tester.logger.Printf("📋 VALIDATION SUMMARY:")
|
||||
tester.logger.Printf(" ✅ All contracts deployed and verified on Arbitrum")
|
||||
tester.logger.Printf(" ✅ Contract code and interfaces validated")
|
||||
tester.logger.Printf(" ✅ Authorization setup confirmed")
|
||||
tester.logger.Printf(" ✅ Arbitrage detection functional")
|
||||
tester.logger.Printf("")
|
||||
tester.logger.Printf("🚀 MEV BOT READY FOR PRODUCTION WITH DEPLOYED CONTRACTS!")
|
||||
}
|
||||
|
||||
func (t *DeployedContractsTester) testContractExistence(ctx context.Context, contracts map[string]string) {
|
||||
t.logger.Printf("🔍 Testing contract existence and code verification...")
|
||||
|
||||
for name, addressHex := range contracts {
|
||||
address := common.HexToAddress(addressHex)
|
||||
t.logger.Printf(" Checking %s at %s...", name, address.Hex())
|
||||
|
||||
// Get contract code
|
||||
code, err := t.client.CodeAt(ctx, address, nil)
|
||||
if err != nil {
|
||||
t.logger.Fatalf("❌ Failed to get code for %s: %v", name, err)
|
||||
}
|
||||
|
||||
if len(code) == 0 {
|
||||
t.logger.Fatalf("❌ Contract %s has no code at %s", name, address.Hex())
|
||||
}
|
||||
|
||||
t.logger.Printf(" ✅ %s verified: %d bytes of contract code", name, len(code))
|
||||
|
||||
// Store contract details
|
||||
t.contracts[name] = ContractDetails{
|
||||
Address: address,
|
||||
CodeSize: len(code),
|
||||
}
|
||||
}
|
||||
|
||||
t.logger.Printf("✅ All deployed contracts verified with code")
|
||||
}
|
||||
|
||||
func (t *DeployedContractsTester) loadContractABIs() {
|
||||
t.logger.Printf("📋 Loading contract ABIs...")
|
||||
|
||||
// Try to load ABIs from the bindings directory
|
||||
abiFiles := map[string]string{
|
||||
"ArbitrageExecutor": "bindings/deployed/ArbitrageExecutor.json",
|
||||
"UniswapV3FlashSwapper": "bindings/deployed/UniswapV3FlashSwapper.json",
|
||||
"DataFetcher": "bindings/deployed/DataFetcher.json",
|
||||
}
|
||||
|
||||
for contractName, abiFile := range abiFiles {
|
||||
if contract, exists := t.contracts[contractName]; exists {
|
||||
t.logger.Printf(" Loading ABI for %s from %s...", contractName, abiFile)
|
||||
|
||||
// Read ABI file
|
||||
abiData, err := os.ReadFile(abiFile)
|
||||
if err != nil {
|
||||
t.logger.Printf(" ⚠️ Could not load ABI file for %s: %v", contractName, err)
|
||||
continue
|
||||
}
|
||||
|
||||
// Parse contract JSON
|
||||
var contractInfo ContractInfo
|
||||
if err := json.Unmarshal(abiData, &contractInfo); err != nil {
|
||||
t.logger.Printf(" ⚠️ Could not parse contract JSON for %s: %v", contractName, err)
|
||||
continue
|
||||
}
|
||||
|
||||
// Convert ABI to Go ABI
|
||||
abiJSON, _ := json.Marshal(contractInfo.ABI)
|
||||
contractABI, err := abi.JSON(strings.NewReader(string(abiJSON)))
|
||||
if err != nil {
|
||||
t.logger.Printf(" ⚠️ Could not parse ABI for %s: %v", contractName, err)
|
||||
continue
|
||||
}
|
||||
|
||||
// Update contract details
|
||||
contract.ABI = contractABI
|
||||
t.contracts[contractName] = contract
|
||||
|
||||
t.logger.Printf(" ✅ %s ABI loaded: %d methods", contractName, len(contractABI.Methods))
|
||||
}
|
||||
}
|
||||
|
||||
t.logger.Printf("✅ Contract ABIs loaded successfully")
|
||||
}
|
||||
|
||||
func (t *DeployedContractsTester) testContractInteractions(ctx context.Context) {
|
||||
t.logger.Printf("🔧 Testing basic contract interactions...")
|
||||
|
||||
// Test each contract with basic view functions
|
||||
for name, contract := range t.contracts {
|
||||
t.logger.Printf(" Testing %s interactions...", name)
|
||||
|
||||
// Try to call a common view function if it exists
|
||||
if method, exists := contract.ABI.Methods["owner"]; exists {
|
||||
t.logger.Printf(" Found 'owner' method with %d inputs", len(method.Inputs))
|
||||
|
||||
// Create call data
|
||||
callData, err := contract.ABI.Pack("owner")
|
||||
if err == nil {
|
||||
// Make the call
|
||||
result, err := t.client.CallContract(ctx, ethereum.CallMsg{
|
||||
To: &contract.Address,
|
||||
Data: callData,
|
||||
}, nil)
|
||||
|
||||
if err == nil && len(result) > 0 {
|
||||
t.logger.Printf(" ✅ owner() call successful: %d bytes returned", len(result))
|
||||
} else {
|
||||
t.logger.Printf(" ⚠️ owner() call failed or empty result")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Check for pause status if the method exists
|
||||
if method, exists := contract.ABI.Methods["paused"]; exists {
|
||||
t.logger.Printf(" Found 'paused' method with %d inputs", len(method.Inputs))
|
||||
}
|
||||
|
||||
t.logger.Printf(" ✅ %s interaction tests completed", name)
|
||||
}
|
||||
|
||||
t.logger.Printf("✅ Contract interaction tests completed")
|
||||
}
|
||||
|
||||
func (t *DeployedContractsTester) testContractAuthorization(ctx context.Context) {
|
||||
t.logger.Printf("🔐 Testing contract authorization setup...")
|
||||
|
||||
// Check if UniswapV3FlashSwapper is authorized to call ArbitrageExecutor
|
||||
arbitrageExecutor := t.contracts["ArbitrageExecutor"]
|
||||
flashSwapper := t.contracts["UniswapV3FlashSwapper"]
|
||||
|
||||
t.logger.Printf(" ArbitrageExecutor: %s", arbitrageExecutor.Address.Hex())
|
||||
t.logger.Printf(" UniswapV3FlashSwapper: %s", flashSwapper.Address.Hex())
|
||||
|
||||
// Check if authorization method exists and call it
|
||||
if method, exists := arbitrageExecutor.ABI.Methods["authorizedCallers"]; exists {
|
||||
t.logger.Printf(" Found 'authorizedCallers' method with %d inputs", len(method.Inputs))
|
||||
// Note: Would need to call this with the flash swapper address as parameter
|
||||
}
|
||||
|
||||
t.logger.Printf("✅ Authorization setup validated")
|
||||
}
|
||||
|
||||
func (t *DeployedContractsTester) testArbitrageDetection(ctx context.Context) {
|
||||
t.logger.Printf("🎯 Testing arbitrage opportunity detection with deployed contracts...")
|
||||
|
||||
// Use DataFetcher to analyze real pool data
|
||||
dataFetcher := t.contracts["DataFetcher"]
|
||||
|
||||
// Real Arbitrum pool addresses
|
||||
wethUsdcPool := common.HexToAddress("0xC31E54c7a869B9FcBEcc14363CF510d1c41fa443") // WETH/USDC 0.05%
|
||||
|
||||
t.logger.Printf(" Analyzing WETH/USDC pool: %s", wethUsdcPool.Hex())
|
||||
t.logger.Printf(" Using DataFetcher contract: %s", dataFetcher.Address.Hex())
|
||||
|
||||
// Get current block for reference
|
||||
currentBlock, err := t.client.BlockNumber(ctx)
|
||||
if err == nil {
|
||||
t.logger.Printf(" Current block: %d", currentBlock)
|
||||
}
|
||||
|
||||
// Check pool liquidity
|
||||
balance, err := t.client.BalanceAt(ctx, wethUsdcPool, nil)
|
||||
if err == nil {
|
||||
balanceETH := new(big.Float).Quo(new(big.Float).SetInt(balance), new(big.Float).SetInt(big.NewInt(1e18)))
|
||||
t.logger.Printf(" Pool ETH balance: %.6f ETH", balanceETH)
|
||||
}
|
||||
|
||||
// Simulate arbitrage opportunity calculation
|
||||
t.logger.Printf(" Simulating arbitrage opportunity detection...")
|
||||
|
||||
// Mock calculation - in production this would use the deployed DataFetcher
|
||||
profit := big.NewInt(5000000000000000) // 0.005 ETH mock profit
|
||||
gasEstimate := big.NewInt(300000)
|
||||
gasPrice := big.NewInt(1000000000) // 1 gwei for Arbitrum
|
||||
|
||||
gasCost := new(big.Int).Mul(gasEstimate, gasPrice)
|
||||
netProfit := new(big.Int).Sub(profit, gasCost)
|
||||
|
||||
profitETH := new(big.Float).Quo(new(big.Float).SetInt(netProfit), new(big.Float).SetInt(big.NewInt(1e18)))
|
||||
|
||||
t.logger.Printf(" 📊 Mock arbitrage analysis:")
|
||||
t.logger.Printf(" Estimated profit: 0.005 ETH")
|
||||
t.logger.Printf(" Gas cost: 0.0003 ETH")
|
||||
t.logger.Printf(" Net profit: %.6f ETH", profitETH)
|
||||
|
||||
if netProfit.Sign() > 0 {
|
||||
t.logger.Printf(" ✅ Profitable arbitrage opportunity detected!")
|
||||
} else {
|
||||
t.logger.Printf(" ℹ️ Current conditions not profitable (normal)")
|
||||
}
|
||||
|
||||
t.logger.Printf("✅ Arbitrage detection integration validated")
|
||||
}
|
||||
|
||||
// Additional imports are included above
|
||||
235
orig/test/production/real_arbitrage_demo_test.go
Normal file
235
orig/test/production/real_arbitrage_demo_test.go
Normal file
@@ -0,0 +1,235 @@
|
||||
//go:build integration && legacy && forked
|
||||
// +build integration,legacy,forked
|
||||
|
||||
package production_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"log"
|
||||
"math/big"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/core/types"
|
||||
"github.com/ethereum/go-ethereum/ethclient"
|
||||
)
|
||||
|
||||
// ProductionLogger provides structured logging for production validation
|
||||
type ProductionLogger struct {
|
||||
*log.Logger
|
||||
}
|
||||
|
||||
func NewProductionLogger() *ProductionLogger {
|
||||
return &ProductionLogger{
|
||||
Logger: log.New(os.Stdout, "[ARBITRAGE-DEMO] ", log.LstdFlags|log.Lmicroseconds),
|
||||
}
|
||||
}
|
||||
|
||||
func main() {
|
||||
logger := NewProductionLogger()
|
||||
logger.Printf("🚀 STARTING REAL ARBITRAGE DETECTION DEMO")
|
||||
|
||||
// Connect to Arbitrum mainnet
|
||||
rpcEndpoint := os.Getenv("ARBITRUM_RPC_ENDPOINT")
|
||||
if rpcEndpoint == "" {
|
||||
rpcEndpoint = "https://arb1.arbitrum.io/rpc"
|
||||
}
|
||||
|
||||
logger.Printf("📡 Connecting to Arbitrum: %s", rpcEndpoint)
|
||||
|
||||
client, err := ethclient.Dial(rpcEndpoint)
|
||||
if err != nil {
|
||||
logger.Fatalf("❌ Failed to connect to Arbitrum: %v", err)
|
||||
}
|
||||
defer client.Close()
|
||||
|
||||
// Verify we're on Arbitrum mainnet
|
||||
ctx := context.Background()
|
||||
chainID, err := client.ChainID(ctx)
|
||||
if err != nil {
|
||||
logger.Fatalf("❌ Failed to get chain ID: %v", err)
|
||||
}
|
||||
|
||||
if chainID.Int64() != 42161 {
|
||||
logger.Fatalf("❌ Not connected to Arbitrum mainnet. Got chain ID: %d", chainID.Int64())
|
||||
}
|
||||
|
||||
logger.Printf("✅ Connected to Arbitrum mainnet (Chain ID: %d)", chainID.Int64())
|
||||
|
||||
// Real Arbitrum WETH/USDC pools with different fee tiers
|
||||
pools := map[string]common.Address{
|
||||
"WETH/USDC 0.05%": common.HexToAddress("0xC31E54c7a869B9FcBEcc14363CF510d1c41fa443"),
|
||||
"WETH/USDC 0.30%": common.HexToAddress("0x17c14D2c404D167802b16C450d3c99F88F2c4F4d"),
|
||||
"WETH/USDT 0.05%": common.HexToAddress("0x641C00A822e8b671738d32a431a4Fb6074E5c79d"),
|
||||
}
|
||||
|
||||
logger.Printf("🎯 Analyzing real Uniswap V3 pools for arbitrage opportunities...")
|
||||
|
||||
// Get current block number
|
||||
blockNumber, err := client.BlockNumber(ctx)
|
||||
if err != nil {
|
||||
logger.Fatalf("❌ Failed to get block number: %v", err)
|
||||
}
|
||||
|
||||
logger.Printf("📦 Current block: %d", blockNumber)
|
||||
|
||||
// Analyze each pool for current liquidity and activity
|
||||
for name, poolAddress := range pools {
|
||||
logger.Printf("🔍 Analyzing %s (%s)...", name, poolAddress.Hex())
|
||||
|
||||
// Get pool contract code to verify it exists
|
||||
code, err := client.CodeAt(ctx, poolAddress, nil)
|
||||
if err != nil {
|
||||
logger.Printf("❌ Failed to get code for %s: %v", name, err)
|
||||
continue
|
||||
}
|
||||
|
||||
if len(code) == 0 {
|
||||
logger.Printf("❌ Pool %s has no code - invalid address", name)
|
||||
continue
|
||||
}
|
||||
|
||||
logger.Printf("✅ Pool %s verified - contract exists (%d bytes of code)", name, len(code))
|
||||
|
||||
// Try to get recent transactions to this pool
|
||||
// This demonstrates we can monitor real activity
|
||||
|
||||
// Check last 10 blocks for transactions to this pool
|
||||
transactionCount := 0
|
||||
for i := int64(0); i < 10 && blockNumber-uint64(i) > 0; i++ {
|
||||
block, err := client.BlockByNumber(ctx, big.NewInt(int64(blockNumber)-i))
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
|
||||
for _, tx := range block.Transactions() {
|
||||
if tx.To() != nil && tx.To().Hex() == poolAddress.Hex() {
|
||||
transactionCount++
|
||||
logger.Printf("🔄 Recent transaction to %s: %s (Block: %d)",
|
||||
name, tx.Hash().Hex(), block.NumberU64())
|
||||
break // Just show one example per block
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if transactionCount > 0 {
|
||||
logger.Printf("📈 Pool %s is ACTIVE - found %d recent transactions", name, transactionCount)
|
||||
} else {
|
||||
logger.Printf("📉 Pool %s - no recent activity in last 10 blocks", name)
|
||||
}
|
||||
}
|
||||
|
||||
// Demonstrate real-time monitoring capability
|
||||
logger.Printf("📡 Demonstrating real-time block monitoring...")
|
||||
|
||||
blockChan := make(chan *types.Header, 10)
|
||||
sub, err := client.SubscribeNewHead(ctx, blockChan)
|
||||
if err != nil {
|
||||
logger.Printf("❌ Failed to subscribe to new blocks: %v", err)
|
||||
logger.Printf("ℹ️ Using polling method instead...")
|
||||
|
||||
// Fallback to polling
|
||||
lastBlockNumber := blockNumber
|
||||
for i := 0; i < 3; i++ {
|
||||
time.Sleep(5 * time.Second)
|
||||
currentBlock, err := client.BlockNumber(ctx)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
|
||||
if currentBlock > lastBlockNumber {
|
||||
logger.Printf("📦 NEW BLOCK DETECTED: %d (polling method)", currentBlock)
|
||||
lastBlockNumber = currentBlock
|
||||
|
||||
// Get the actual block to analyze
|
||||
block, err := client.BlockByNumber(ctx, big.NewInt(int64(currentBlock)))
|
||||
if err == nil {
|
||||
logger.Printf("📊 Block %d: %d transactions, Gas Used: %d",
|
||||
currentBlock, len(block.Transactions()), block.GasUsed())
|
||||
|
||||
// Check for transactions to our target pools
|
||||
for _, tx := range block.Transactions() {
|
||||
if tx.To() != nil {
|
||||
for name, poolAddr := range pools {
|
||||
if tx.To().Hex() == poolAddr.Hex() {
|
||||
logger.Printf("⚡ POOL ACTIVITY: Transaction %s to %s",
|
||||
tx.Hash().Hex(), name)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
defer sub.Unsubscribe()
|
||||
|
||||
// Monitor for 15 seconds
|
||||
timeout := time.After(15 * time.Second)
|
||||
blocksProcessed := 0
|
||||
|
||||
for {
|
||||
select {
|
||||
case header := <-blockChan:
|
||||
blocksProcessed++
|
||||
logger.Printf("📦 NEW BLOCK: %d (Hash: %s, Gas Used: %d)",
|
||||
header.Number.Uint64(), header.Hash().Hex(), header.GasUsed)
|
||||
|
||||
if blocksProcessed >= 3 {
|
||||
logger.Printf("✅ Successfully monitored %d blocks in real-time", blocksProcessed)
|
||||
goto monitoring_complete
|
||||
}
|
||||
|
||||
case err := <-sub.Err():
|
||||
logger.Printf("❌ Subscription error: %v", err)
|
||||
goto monitoring_complete
|
||||
|
||||
case <-timeout:
|
||||
logger.Printf("⏰ Monitoring timeout - processed %d blocks", blocksProcessed)
|
||||
goto monitoring_complete
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
monitoring_complete:
|
||||
// Final demonstration: Show we can read contract state
|
||||
logger.Printf("🔍 Demonstrating contract state reading capability...")
|
||||
|
||||
// Try to read balance of WETH contract
|
||||
wethAddress := common.HexToAddress("0x82aF49447D8a07e3bd95BD0d56f35241523fBab1")
|
||||
|
||||
// Get total supply (this is a standard ERC20 call)
|
||||
// We'll simulate what a real contract call would look like
|
||||
wethCode, err := client.CodeAt(ctx, wethAddress, nil)
|
||||
if err == nil && len(wethCode) > 0 {
|
||||
logger.Printf("✅ WETH contract verified at %s (%d bytes)", wethAddress.Hex(), len(wethCode))
|
||||
|
||||
// Get current ETH balance of the WETH contract (wrapped ETH)
|
||||
balance, err := client.BalanceAt(ctx, wethAddress, nil)
|
||||
if err == nil {
|
||||
balanceETH := new(big.Float).Quo(new(big.Float).SetInt(balance), new(big.Float).SetInt(big.NewInt(1e18)))
|
||||
logger.Printf("📊 WETH Contract Balance: %.6f ETH", balanceETH)
|
||||
}
|
||||
}
|
||||
|
||||
// Summary of capabilities demonstrated
|
||||
logger.Printf("")
|
||||
logger.Printf("🎉 ARBITRAGE DETECTION DEMO COMPLETED SUCCESSFULLY!")
|
||||
logger.Printf("")
|
||||
logger.Printf("📋 CAPABILITIES DEMONSTRATED:")
|
||||
logger.Printf(" ✅ Connect to real Arbitrum mainnet")
|
||||
logger.Printf(" ✅ Verify and interact with real Uniswap V3 pools")
|
||||
logger.Printf(" ✅ Monitor real-time blockchain activity")
|
||||
logger.Printf(" ✅ Detect transactions to target pools")
|
||||
logger.Printf(" ✅ Read contract state and balances")
|
||||
logger.Printf(" ✅ Handle both WebSocket and polling connections")
|
||||
logger.Printf("")
|
||||
logger.Printf("💡 This proves our MEV bot can:")
|
||||
logger.Printf(" • Access real market data from Arbitrum")
|
||||
logger.Printf(" • Monitor live trading activity")
|
||||
logger.Printf(" • Detect arbitrage opportunities")
|
||||
logger.Printf(" • Execute trades when profitable spreads exist")
|
||||
logger.Printf("")
|
||||
logger.Printf("🚀 THE MEV BOT IS PRODUCTION READY FOR REAL ARBITRAGE!")
|
||||
}
|
||||
Reference in New Issue
Block a user