fix(critical): complete execution pipeline - all blockers fixed and operational

This commit is contained in:
Krypto Kajun
2025-11-04 10:24:34 -06:00
parent 0b1c7bbc86
commit 52d555ccdf
410 changed files with 99504 additions and 28488 deletions

View File

@@ -12,28 +12,28 @@ type Config struct {
EnabledProtocols []string `yaml:"enabled_protocols" json:"enabled_protocols"`
// Profitability thresholds
MinProfitETH float64 `yaml:"min_profit_eth" json:"min_profit_eth"` // Minimum profit in ETH
MinProfitUSD float64 `yaml:"min_profit_usd" json:"min_profit_usd"` // Minimum profit in USD
MaxPriceImpact float64 `yaml:"max_price_impact" json:"max_price_impact"` // Maximum acceptable price impact (0-1)
MinConfidence float64 `yaml:"min_confidence" json:"min_confidence"` // Minimum confidence score (0-1)
MinProfitETH float64 `yaml:"min_profit_eth" json:"min_profit_eth"` // Minimum profit in ETH
MinProfitUSD float64 `yaml:"min_profit_usd" json:"min_profit_usd"` // Minimum profit in USD
MaxPriceImpact float64 `yaml:"max_price_impact" json:"max_price_impact"` // Maximum acceptable price impact (0-1)
MinConfidence float64 `yaml:"min_confidence" json:"min_confidence"` // Minimum confidence score (0-1)
// Multi-hop configuration
MaxHops int `yaml:"max_hops" json:"max_hops"` // Maximum number of hops (2-4)
EnableMultiHop bool `yaml:"enable_multi_hop" json:"enable_multi_hop"` // Enable multi-hop arbitrage
MaxHops int `yaml:"max_hops" json:"max_hops"` // Maximum number of hops (2-4)
EnableMultiHop bool `yaml:"enable_multi_hop" json:"enable_multi_hop"` // Enable multi-hop arbitrage
// Performance settings
ParallelQueries bool `yaml:"parallel_queries" json:"parallel_queries"` // Query DEXes in parallel
TimeoutSeconds int `yaml:"timeout_seconds" json:"timeout_seconds"` // Query timeout
CacheTTLSeconds int `yaml:"cache_ttl_seconds" json:"cache_ttl_seconds"` // Pool cache TTL
MaxConcurrent int `yaml:"max_concurrent" json:"max_concurrent"` // Max concurrent queries
ParallelQueries bool `yaml:"parallel_queries" json:"parallel_queries"` // Query DEXes in parallel
TimeoutSeconds int `yaml:"timeout_seconds" json:"timeout_seconds"` // Query timeout
CacheTTLSeconds int `yaml:"cache_ttl_seconds" json:"cache_ttl_seconds"` // Pool cache TTL
MaxConcurrent int `yaml:"max_concurrent" json:"max_concurrent"` // Max concurrent queries
// Gas settings
MaxGasPrice uint64 `yaml:"max_gas_price" json:"max_gas_price"` // Maximum gas price in gwei
GasBuffer float64 `yaml:"gas_buffer" json:"gas_buffer"` // Gas estimate buffer multiplier
MaxGasPrice uint64 `yaml:"max_gas_price" json:"max_gas_price"` // Maximum gas price in gwei
GasBuffer float64 `yaml:"gas_buffer" json:"gas_buffer"` // Gas estimate buffer multiplier
// Monitoring
EnableMetrics bool `yaml:"enable_metrics" json:"enable_metrics"`
MetricsInterval int `yaml:"metrics_interval" json:"metrics_interval"`
EnableMetrics bool `yaml:"enable_metrics" json:"enable_metrics"`
MetricsInterval int `yaml:"metrics_interval" json:"metrics_interval"`
}
// DefaultConfig returns default DEX configuration
@@ -42,24 +42,24 @@ func DefaultConfig() *Config {
Enabled: true,
EnabledProtocols: []string{"uniswap_v3", "sushiswap", "curve", "balancer"},
MinProfitETH: 0.0001, // $0.25 @ $2500/ETH
MinProfitUSD: 0.25, // $0.25
MaxPriceImpact: 0.05, // 5%
MinConfidence: 0.5, // 50%
MinProfitETH: 0.0001, // $0.25 @ $2500/ETH
MinProfitUSD: 0.25, // $0.25
MaxPriceImpact: 0.05, // 5%
MinConfidence: 0.5, // 50%
MaxHops: 4,
EnableMultiHop: true,
MaxHops: 4,
EnableMultiHop: true,
ParallelQueries: true,
TimeoutSeconds: 5,
CacheTTLSeconds: 30, // 30 second cache
MaxConcurrent: 10, // Max 10 concurrent queries
ParallelQueries: true,
TimeoutSeconds: 5,
CacheTTLSeconds: 30, // 30 second cache
MaxConcurrent: 10, // Max 10 concurrent queries
MaxGasPrice: 100, // 100 gwei max
GasBuffer: 1.2, // 20% gas buffer
MaxGasPrice: 100, // 100 gwei max
GasBuffer: 1.2, // 20% gas buffer
EnableMetrics: true,
MetricsInterval: 60, // 60 seconds
EnableMetrics: true,
MetricsInterval: 60, // 60 seconds
}
}
@@ -69,24 +69,24 @@ func ProductionConfig() *Config {
Enabled: true,
EnabledProtocols: []string{"uniswap_v3", "sushiswap", "curve", "balancer"},
MinProfitETH: 0.0002, // $0.50 @ $2500/ETH - higher threshold for production
MinProfitUSD: 0.50,
MaxPriceImpact: 0.03, // 3% - stricter for production
MinConfidence: 0.7, // 70% - higher confidence required
MinProfitETH: 0.0002, // $0.50 @ $2500/ETH - higher threshold for production
MinProfitUSD: 0.50,
MaxPriceImpact: 0.03, // 3% - stricter for production
MinConfidence: 0.7, // 70% - higher confidence required
MaxHops: 3, // Limit to 3 hops for lower gas
EnableMultiHop: true,
MaxHops: 3, // Limit to 3 hops for lower gas
EnableMultiHop: true,
ParallelQueries: true,
TimeoutSeconds: 3, // Faster timeout for production
CacheTTLSeconds: 15, // Shorter cache for fresher data
MaxConcurrent: 20, // More concurrent for speed
ParallelQueries: true,
TimeoutSeconds: 3, // Faster timeout for production
CacheTTLSeconds: 15, // Shorter cache for fresher data
MaxConcurrent: 20, // More concurrent for speed
MaxGasPrice: 50, // 50 gwei max for production
GasBuffer: 1.3, // 30% gas buffer for safety
MaxGasPrice: 50, // 50 gwei max for production
GasBuffer: 1.3, // 30% gas buffer for safety
EnableMetrics: true,
MetricsInterval: 30, // More frequent metrics
EnableMetrics: true,
MetricsInterval: 30, // More frequent metrics
}
}

View File

@@ -284,7 +284,7 @@ func (d *CurveDecoder) CalculatePriceImpact(amountIn *big.Int, reserves *PoolRes
ratio := new(big.Float).Quo(amountInFloat, reserveFloat)
impact := new(big.Float).Mul(ratio, ratio) // Square for stable curves
impact.Mul(impact, big.NewFloat(0.1)) // Scale down for StableSwap efficiency
impact.Mul(impact, big.NewFloat(0.1)) // Scale down for StableSwap efficiency
impactValue, _ := impact.Float64()
return impactValue, nil

View File

@@ -3,10 +3,11 @@ package dex
import (
"context"
"math/big"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/ethclient"
"math/big"
)
// DEXDecoder is the interface that all DEX protocol decoders must implement

310
pkg/dex/detector.go Normal file
View File

@@ -0,0 +1,310 @@
package dex
import (
"context"
"fmt"
"math/big"
"time"
"github.com/ethereum/go-ethereum"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/ethclient"
)
// PoolType represents the detected pool/exchange type
type PoolType string
const (
PoolTypeUnknown PoolType = "unknown"
PoolTypeUniswapV2 PoolType = "uniswap_v2"
PoolTypeUniswapV3 PoolType = "uniswap_v3"
PoolTypeUniswapV4 PoolType = "uniswap_v4"
PoolTypeSushiswap PoolType = "sushiswap"
PoolTypeBalancer PoolType = "balancer"
PoolTypeCurve PoolType = "curve"
PoolTypeAlgebraV1 PoolType = "algebra_v1"
PoolTypeAlgebraV19 PoolType = "algebra_v1.9"
PoolTypeAlgebraIntegral PoolType = "algebra_integral"
PoolTypeCamelot PoolType = "camelot"
PoolTypeKyberswap PoolType = "kyberswap"
PoolTypePancakeV3 PoolType = "pancake_v3"
)
// PoolDetector identifies pool/exchange types using unique signatures
type PoolDetector struct {
client *ethclient.Client
}
// NewPoolDetector creates a new pool detector
func NewPoolDetector(client *ethclient.Client) *PoolDetector {
return &PoolDetector{
client: client,
}
}
// PoolInfo contains detected pool information
type PoolInfo struct {
Address common.Address
Type PoolType
Token0 common.Address
Token1 common.Address
Fee *big.Int
Version string
Confidence float64
DetectedAt time.Time
Properties map[string]interface{}
}
// DetectPoolType identifies the pool type using unique method signatures
func (pd *PoolDetector) DetectPoolType(ctx context.Context, poolAddr common.Address) (*PoolInfo, error) {
// First check if contract exists
code, err := pd.client.CodeAt(ctx, poolAddr, nil)
if err != nil {
return nil, fmt.Errorf("failed to get contract code: %w", err)
}
if len(code) == 0 {
return nil, fmt.Errorf("no contract at address %s", poolAddr.Hex())
}
info := &PoolInfo{
Address: poolAddr,
Type: PoolTypeUnknown,
Properties: make(map[string]interface{}),
DetectedAt: time.Now(),
}
// Method selectors for detection
selectors := map[string][]byte{
"token0": {0x0d, 0xfe, 0x16, 0x81}, // Common to many DEXs
"token1": {0xd2, 0x1c, 0xec, 0xd4}, // Common to many DEXs
"fee": {0xdd, 0xca, 0x3f, 0x43}, // UniswapV3
"slot0": {0x38, 0x50, 0xc7, 0xbd}, // UniswapV3
"globalState": {0x13, 0xaf, 0x40, 0x35}, // Algebra
"getReserves": {0x09, 0x02, 0xf1, 0xac}, // UniswapV2
"liquidity": {0x1a, 0x68, 0x6d, 0x0f}, // UniswapV3
"factory": {0xc4, 0x5a, 0x01, 0x55}, // Common
"tickSpacing": {0xd0, 0xc9, 0x38, 0x91}, // UniswapV3
"maxLiquidityPerTick": {0x70, 0xcf, 0x75, 0x4a}, // UniswapV3
}
// Test each selector
results := make(map[string]bool)
for name, selector := range selectors {
result, err := pd.client.CallContract(ctx, ethereum.CallMsg{
To: &poolAddr,
Data: selector,
}, nil)
results[name] = err == nil && len(result) > 0
}
// Detection logic based on unique combinations
hasToken0 := results["token0"]
hasToken1 := results["token1"]
hasFee := results["fee"]
hasSlot0 := results["slot0"]
hasGlobalState := results["globalState"]
hasGetReserves := results["getReserves"]
hasLiquidity := results["liquidity"]
hasTickSpacing := results["tickSpacing"]
hasMaxLiquidityPerTick := results["maxLiquidityPerTick"]
// UniswapV3: Has slot0, fee, tickSpacing, maxLiquidityPerTick
if hasToken0 && hasToken1 && hasSlot0 && hasFee && hasTickSpacing && hasMaxLiquidityPerTick {
info.Type = PoolTypeUniswapV3
info.Version = "3"
info.Confidence = 0.95
info.Properties["has_concentrated_liquidity"] = true
// Get fee tier
if feeData, err := pd.getUint24(ctx, poolAddr, selectors["fee"]); err == nil {
info.Fee = feeData
info.Properties["fee_tier"] = feeData.Uint64()
}
} else if hasToken0 && hasToken1 && hasGlobalState && !hasSlot0 {
// Algebra-based (Camelot, QuickSwap V3): Has globalState instead of slot0
// Further distinguish between Algebra versions
if hasDirectionalFees := pd.checkDirectionalFees(ctx, poolAddr); hasDirectionalFees {
info.Type = PoolTypeAlgebraIntegral
info.Version = "integral"
info.Properties["has_directional_fees"] = true
} else {
info.Type = PoolTypeAlgebraV19
info.Version = "1.9"
}
info.Confidence = 0.90
info.Properties["has_concentrated_liquidity"] = true
} else if hasToken0 && hasToken1 && hasGetReserves && !hasSlot0 && !hasGlobalState {
// UniswapV2/Sushiswap: Has getReserves, no slot0
// Check factory to distinguish between V2 and Sushiswap
if factory := pd.getFactory(ctx, poolAddr); factory != nil {
if pd.isUniswapV2Factory(*factory) {
info.Type = PoolTypeUniswapV2
info.Version = "2"
} else if pd.isSushiswapFactory(*factory) {
info.Type = PoolTypeSushiswap
info.Version = "1"
}
} else {
info.Type = PoolTypeUniswapV2 // Default to V2 pattern
info.Version = "2"
}
info.Confidence = 0.85
info.Properties["has_constant_product"] = true
} else if hasToken0 && hasToken1 && hasSlot0 && hasFee && hasLiquidity {
// PancakeSwap V3: Similar to UniswapV3 but different factory
if factory := pd.getFactory(ctx, poolAddr); factory != nil && pd.isPancakeV3Factory(*factory) {
info.Type = PoolTypePancakeV3
info.Version = "3"
info.Confidence = 0.85
} else {
// Generic V3-like pool
info.Type = PoolTypeUniswapV3
info.Version = "3-compatible"
info.Confidence = 0.70
}
}
// Get token addresses if detected
if hasToken0 && hasToken1 {
if token0, err := pd.getAddress(ctx, poolAddr, selectors["token0"]); err == nil {
info.Token0 = *token0
}
if token1, err := pd.getAddress(ctx, poolAddr, selectors["token1"]); err == nil {
info.Token1 = *token1
}
}
// If still unknown but has basic token methods
if info.Type == PoolTypeUnknown && hasToken0 && hasToken1 {
info.Type = PoolTypeUnknown
info.Confidence = 0.30
info.Properties["has_basic_methods"] = true
}
return info, nil
}
// DetectFromTransaction detects pool type from transaction data
func (pd *PoolDetector) DetectFromTransaction(ctx context.Context, txData []byte, to common.Address) (*PoolInfo, error) {
if len(txData) < 4 {
return nil, fmt.Errorf("transaction data too short")
}
// Get method selector (first 4 bytes)
selector := txData[:4]
// Common swap selectors by protocol
swapSelectors := map[string]PoolType{
"0x128acb08": PoolTypeUniswapV3, // swap (V3)
"0x5c11d795": PoolTypeUniswapV2, // swapExactTokensForTokensSupportingFeeOnTransferTokens
"0x38ed1739": PoolTypeUniswapV2, // swapExactTokensForTokens
"0x8803dbee": PoolTypeUniswapV2, // swapTokensForExactTokens
"0x04e45aaf": PoolTypeUniswapV3, // exactInputSingle
"0x414bf389": PoolTypeUniswapV3, // exactInputSingle (SwapRouter02)
"0xac9650d8": PoolTypeUniswapV3, // multicall (V3)
"0x5ae401dc": PoolTypeUniswapV3, // multicall with deadline
}
selectorHex := fmt.Sprintf("0x%x", selector)
info := &PoolInfo{
Address: to,
Type: PoolTypeUnknown,
Properties: make(map[string]interface{}),
DetectedAt: time.Now(),
}
// Check known selectors
if poolType, found := swapSelectors[selectorHex]; found {
info.Type = poolType
info.Confidence = 0.75
info.Properties["detected_from"] = "transaction"
info.Properties["method_selector"] = selectorHex
// Try to extract pool address from calldata
if poolAddr := pd.extractPoolFromCalldata(txData); poolAddr != nil {
// Detect the actual pool (not router)
return pd.DetectPoolType(ctx, *poolAddr)
}
}
return info, nil
}
// Helper methods
func (pd *PoolDetector) getAddress(ctx context.Context, contract common.Address, selector []byte) (*common.Address, error) {
result, err := pd.client.CallContract(ctx, ethereum.CallMsg{
To: &contract,
Data: selector,
}, nil)
if err != nil || len(result) < 32 {
return nil, err
}
addr := common.BytesToAddress(result[12:32])
return &addr, nil
}
func (pd *PoolDetector) getUint24(ctx context.Context, contract common.Address, selector []byte) (*big.Int, error) {
result, err := pd.client.CallContract(ctx, ethereum.CallMsg{
To: &contract,
Data: selector,
}, nil)
if err != nil || len(result) < 32 {
return nil, err
}
return new(big.Int).SetBytes(result[:32]), nil
}
func (pd *PoolDetector) getFactory(ctx context.Context, poolAddr common.Address) *common.Address {
factorySelector := []byte{0xc4, 0x5a, 0x01, 0x55}
addr, _ := pd.getAddress(ctx, poolAddr, factorySelector)
return addr
}
func (pd *PoolDetector) checkDirectionalFees(ctx context.Context, poolAddr common.Address) bool {
// Check for directional fee methods (Algebra Integral specific)
feeZtoOSelector := []byte{0x8b, 0x94, 0xc9, 0xae} // feeZtoO()
result, err := pd.client.CallContract(ctx, ethereum.CallMsg{
To: &poolAddr,
Data: feeZtoOSelector,
}, nil)
return err == nil && len(result) > 0
}
func (pd *PoolDetector) isUniswapV2Factory(factory common.Address) bool {
// Known UniswapV2 factory addresses on Arbitrum
knownFactories := []common.Address{
common.HexToAddress("0xc35DADB65012eC5796536bD9864eD8773aBc74C4"), // Sushiswap
common.HexToAddress("0xf1D7CC64Fb4452F05c498126312eBE29f30Fbcf9"), // Shibaswap
}
for _, known := range knownFactories {
if factory == known {
return true
}
}
return false
}
func (pd *PoolDetector) isSushiswapFactory(factory common.Address) bool {
return factory == common.HexToAddress("0xc35DADB65012eC5796536bD9864eD8773aBc74C4")
}
func (pd *PoolDetector) isPancakeV3Factory(factory common.Address) bool {
// PancakeSwap V3 factory on Arbitrum
return factory == common.HexToAddress("0x0BFbCF9fa4f9C56B0F40a671Ad40E0805A091865")
}
func (pd *PoolDetector) extractPoolFromCalldata(data []byte) *common.Address {
// Try to extract pool address from common positions in calldata
// This is protocol-specific and would need expansion
if len(data) >= 68 { // 4 (selector) + 32 + 32
// Check if bytes 36-68 look like an address
possibleAddr := common.BytesToAddress(data[36:68])
if possibleAddr != (common.Address{}) {
return &possibleAddr
}
}
return nil
}

View File

@@ -273,7 +273,7 @@ func (r *Registry) InitializeArbitrumDEXes() error {
Name: "Curve",
RouterAddress: common.HexToAddress("0x0000000000000000000000000000000000000000"), // Curve uses individual pools
FactoryAddress: common.HexToAddress("0xb17b674D9c5CB2e441F8e196a2f048A81355d031"), // Curve Factory on Arbitrum
Fee: big.NewInt(4), // 0.04% typical
Fee: big.NewInt(4), // 0.04% typical
PricingModel: PricingStableSwap,
Decoder: NewCurveDecoder(r.client),
Active: true, // ACTIVATED
@@ -288,7 +288,7 @@ func (r *Registry) InitializeArbitrumDEXes() error {
Name: "Balancer",
RouterAddress: common.HexToAddress("0xBA12222222228d8Ba445958a75a0704d566BF2C8"), // Balancer Vault
FactoryAddress: common.HexToAddress("0x0000000000000000000000000000000000000000"), // Uses Vault
Fee: big.NewInt(25), // 0.25% typical
Fee: big.NewInt(25), // 0.25% typical
PricingModel: PricingWeighted,
Decoder: NewBalancerDecoder(r.client),
Active: true, // ACTIVATED

View File

@@ -74,7 +74,7 @@ type DEXInfo struct {
Name string
RouterAddress common.Address
FactoryAddress common.Address
Fee *big.Int // Default fee in basis points (e.g., 30 = 0.3%)
Fee *big.Int // Default fee in basis points (e.g., 30 = 0.3%)
PricingModel PricingModel
Decoder DEXDecoder
Active bool
@@ -82,21 +82,21 @@ type DEXInfo struct {
// PoolReserves represents pool reserves and metadata
type PoolReserves struct {
Token0 common.Address
Token1 common.Address
Reserve0 *big.Int
Reserve1 *big.Int
Fee *big.Int
Protocol DEXProtocol
PoolAddress common.Address
Token0 common.Address
Token1 common.Address
Reserve0 *big.Int
Reserve1 *big.Int
Fee *big.Int
Protocol DEXProtocol
PoolAddress common.Address
// UniswapV3 specific
SqrtPriceX96 *big.Int
Tick int32
Liquidity *big.Int
SqrtPriceX96 *big.Int
Tick int32
Liquidity *big.Int
// Curve specific
A *big.Int // Amplification coefficient
A *big.Int // Amplification coefficient
// Balancer specific
Weights []*big.Int
Weights []*big.Int
}
// SwapInfo represents decoded swap information
@@ -114,26 +114,26 @@ type SwapInfo struct {
// PriceQuote represents a price quote from a DEX
type PriceQuote struct {
DEX DEXProtocol
PoolAddress common.Address
TokenIn common.Address
TokenOut common.Address
AmountIn *big.Int
ExpectedOut *big.Int
PriceImpact float64
Fee *big.Int
GasEstimate uint64
DEX DEXProtocol
PoolAddress common.Address
TokenIn common.Address
TokenOut common.Address
AmountIn *big.Int
ExpectedOut *big.Int
PriceImpact float64
Fee *big.Int
GasEstimate uint64
}
// ArbitragePath represents a multi-DEX arbitrage path
type ArbitragePath struct {
Hops []*PathHop
TotalProfit *big.Int
ProfitETH float64
ROI float64
GasCost *big.Int
NetProfit *big.Int
Confidence float64
Hops []*PathHop
TotalProfit *big.Int
ProfitETH float64
ROI float64
GasCost *big.Int
NetProfit *big.Int
Confidence float64
}
// PathHop represents a single hop in an arbitrage path

View File

@@ -16,8 +16,8 @@ import (
// UniswapV3Decoder implements DEXDecoder for Uniswap V3
type UniswapV3Decoder struct {
*BaseDecoder
poolABI abi.ABI
routerABI abi.ABI
poolABI abi.ABI
routerABI abi.ABI
}
// UniswapV3 Pool ABI (minimal)