# Caching & Price Tracking Analysis - MEV Bot **Date**: October 30, 2025 **Status**: ⚠️ CRITICAL ISSUES IDENTIFIED --- ## Executive Summary Analysis of the MEV bot's caching and price tracking mechanisms reveals **3 critical issues** that are preventing effective arbitrage detection: 1. **Pool cache is NOT being persisted** to disk 2. **NO swap events are being processed** from the sequencer feed 3. **Prices are NOT being updated** from on-chain swaps --- ## 🔴 Critical Issue #1: Pool Cache Not Persisted ### Current Behavior **Discovery IS working** ✅ - Bot discovered **96 pools** across 32 pairs (up from 10) - All 20 new tokens found pools - Discovery took ~3 minutes **Cache NOT saved** ❌ - Pools stored in **memory only** - `data/pools.json` shows old data (Oct 27 23:59) - Discovered pools lost on restart ### Evidence ```bash # Pool cache file (outdated) -rw-r--r-- 1 administrator administrator 5.1K Oct 27 23:59 data/pools.json # Current pools in cache $ jq 'length' data/pools.json 10 # Should be 96! # Latest discovery logs (17:59-18:00) [INFO] ✅ Found 96 pools across 32 pairs [INFO] Discovery complete! Monitoring 96 pools ``` ### Root Cause **Missing or not-called SaveCache function:** - `poolsFile: "data/pools.json"` defined in discovery.go - No evidence of SaveCache() being called after discovery - Pools kept in memory but never persisted ### Impact - **High**: Bot loses all discoveries on restart - **High**: Must re-discover 96 pools every startup (3+ minutes) - **Medium**: Increased RPC calls and startup time --- ## 🔴 Critical Issue #2: Zero Swap Events Processed ### Current Behavior **Bot IS monitoring blocks** ✅ - Processing blocks every 3 seconds - Checking for Uniswap V3 swap events - Arbitrage service stats updating every 10s **NO swaps detected** ❌ - 0 swap events found in 100+ blocks - Every block shows: "NO SWAP EVENTS FOUND" - 0 arbitrage opportunities detected ### Evidence ```bash # Swap event count $ grep "swap event" logs/mev_bot.log | wc -l 0 # Should be hundreds/thousands # Block monitoring (17:13-17:14) [INFO] 📦 Block 395116600: NO SWAP EVENTS FOUND [INFO] 📦 Block 395116612: NO SWAP EVENTS FOUND [INFO] 📦 Block 395116624: NO SWAP EVENTS FOUND ... (continues for all blocks) # Arbitrage stats [INFO] Arbitrage Service Stats - Detected: 0, Executed: 0 ``` ### Root Cause Analysis **Possible causes:** 1. **Wrong event signature** - Uniswap V3 Swap signature mismatch 2. **Pool address filter** - Only monitoring 96 pools, swaps happening elsewhere 3. **Block processing lag** - Getting stale blocks after swaps already settled 4. **Log parsing error** - Swap logs exist but not being decoded correctly ### Expected Behavior On Arbitrum mainnet: - **~500-1000 swaps per minute** across all DEXes - **~5-10 swaps per block** on monitored pools - **Bot should detect 50+ swaps/minute** minimum ### Impact - **CRITICAL**: Cannot detect arbitrage without swap data - **CRITICAL**: No price updates = stale pricing - **HIGH**: Bot is effectively blind to market activity --- ## 🔴 Critical Issue #3: No Price Updates ### Current Behavior **Price tracking exists** ✅ - `ExchangePricer` with `priceCache` map - `Market.UpdatePriceData()` function available - Price cache initialized at startup **Prices NOT being updated** ❌ - No swap events = no price data - Pools have initial liquidity but no current prices - Cache shows 0 entries ### Evidence ```bash # Price-related logs $ grep -i "price.*update" logs/mev_bot.log (only gas price updates found, no token price updates) # Price cache stats priceCache: map[string]*PriceEntry # Empty cached_prices: 0 # Market price updates $ grep "UpdatePriceData" logs/mev_bot.log (no results) ``` ### How Pricing SHOULD Work ``` 1. Sequencer feed → New transaction 2. Decode Swap event → Extract amounts, pool 3. Calculate new price → sqrtPriceX96, tick 4. Update pool cache → Market.UpdatePriceData() 5. Compare prices → Detect arbitrage ``` ### Current Broken Flow ``` 1. Sequencer feed → New transaction ✅ 2. Check for swaps → NONE FOUND ❌ 3. No price calculation ❌ 4. No cache update ❌ 5. No arbitrage detection ❌ ``` ### Impact - **CRITICAL**: Arbitrage detection requires real-time prices - **HIGH**: Using stale/initial prices leads to false opportunities - **HIGH**: Cannot react to market movements --- ## 📊 Token Cache Analysis ### Current State ```json { "tokens_cached": 6, "expected": 20, "file": "data/tokens.json", "last_updated": "Oct 27 16:26" } ``` ### Issues 1. **Only 6 tokens cached** (should be 20) 2. **Missing new tokens**: PENDLE, RDNT, MAGIC, GRAIL, AAVE, CRV, BAL, COMP, MKR, USDC.e 3. **Stale data** - 3 days old ### Impact - **MEDIUM**: Token metadata lookups may fail for new tokens - **LOW**: Doesn't block trading, just missing metadata --- ## 🔍 Detailed Investigation ### Pool Discovery Process **What's Working:** ``` ✅ Discovery scans 190 pairs ✅ Finds pools via CREATE2 calculation ✅ Validates pools on-chain ✅ Stores pools in memory ✅ Logs discovery progress ``` **What's NOT Working:** ``` ❌ SaveCache() not called after discovery ❌ data/pools.json not updated ❌ Pools lost on restart ``` ### Swap Processing Pipeline **What's Working:** ``` ✅ Connects to Arbitrum sequencer feed ✅ Receives new blocks every 3 seconds ✅ Checks blocks for Uniswap V3 logs ✅ Monitors 96 pools ``` **What's NOT Working:** ``` ❌ No swap events detected (0 in 1000+ blocks) ❌ No logs match Uniswap V3 Swap signature ❌ Either wrong signature OR pools inactive ``` ### Price Caching System **Components:** - `ExchangePricer` - Manages cross-exchange pricing - `PriceEntry` - Cache entry with timestamp & validity - `Market.UpdatePriceData()` - Updates price per pool - `priceCache` map - In-memory price storage **Status:** - ✅ System initialized - ✅ Data structures ready - ❌ Never receives swap data - ❌ Never updates prices --- ## 🔧 Required Fixes ### Fix #1: Implement Pool Cache Persistence **Add SaveCache call after discovery:** ```go // In cmd/mev-bot/main.go after discovery complete log.Info(fmt.Sprintf("🎉 Pool discovery complete! Monitoring %d pools", totalPools)) // ADD THIS: Save discovered pools to disk if err := poolDiscovery.SaveCache(); err != nil { log.Error(fmt.Sprintf("Failed to save pool cache: %v", err)) } else { log.Info("✅ Pool cache saved to data/pools.json") } ``` **Implement SaveCache if missing:** ```go // In pkg/pools/discovery.go func (pd *PoolDiscovery) SaveCache() error { pd.mu.RLock() defer pd.mu.RUnlock() // Convert map to slice pools := make([]*Pool, 0, len(pd.pools)) for _, pool := range pd.pools { pools = append(pools, pool) } // Marshal to JSON data, err := json.MarshalIndent(pools, "", " ") if err != nil { return fmt.Errorf("failed to marshal pools: %w", err) } // Write to file if err := os.WriteFile(pd.poolsFile, data, 0644); err != nil { return fmt.Errorf("failed to write pools file: %w", err) } return nil } ``` ### Fix #2: Debug Swap Event Detection **Check event signature:** ```bash # Uniswap V3 Swap event signature keccak256("Swap(address,address,int256,int256,uint160,uint128,int24)") = 0xc42079f94a6350d7e6235f29174924f928cc2ac818eb64fed8004e115fbcca67 ``` **Add diagnostic logging:** ```go // In swap processing log.Info(fmt.Sprintf("Checking block %d for swaps", blockNumber)) log.Debug(fmt.Sprintf("Monitoring %d pools", len(monitoredPools))) for i, log := range logs { log.Debug(fmt.Sprintf("Log %d: topics=%v", i, log.Topics)) if log.Topics[0].Hex() == SwapEventSignature { log.Info("✅ SWAP FOUND!") // Process swap } } ``` **Verify pool addresses:** ```go // Check if we're monitoring the right pools for pool := range monitoredPools { log.Debug(fmt.Sprintf("Monitoring pool: %s", pool.Hex())) } ``` ### Fix #3: Implement Price Updates from Swaps **Add price update to swap handler:** ```go // After processing swap event func handleSwap(pool common.Address, sqrtPriceX96 *big.Int, tick int32) { // Calculate price from sqrtPriceX96 price := uniswap.SqrtPriceX96ToPrice(sqrtPriceX96) // Update market data if market, exists := markets[pool]; exists { market.UpdatePriceData(price, liquidity, sqrtPriceX96, tick) log.Debug(fmt.Sprintf("Updated price for pool %s: %s", pool.Hex()[:8], price.String())) } // Update price cache cacheKey := fmt.Sprintf("%s/%s", tokenIn, tokenOut) priceCache[cacheKey] = &PriceEntry{ Price: price, Timestamp: time.Now(), Validity: 5 * time.Minute, } } ``` --- ## 🎯 Verification Steps ### After Fix #1 (Pool Persistence) ```bash # 1. Start bot ./mev-bot start # 2. Wait for discovery (3 minutes) # Should see: "✅ Pool cache saved" # 3. Check file updated ls -lh data/pools.json # Should show current timestamp # 4. Verify contents jq 'length' data/pools.json # Should show 96 (not 10) # 5. Restart bot # Should load 96 pools instantly ``` ### After Fix #2 (Swap Detection) ```bash # Monitor logs for swaps tail -f logs/mev_bot.log | grep -i swap # Expected output: [INFO] ✅ SWAP FOUND on pool 0x82af... [INFO] Processing swap: 1000 USDC → 0.5 WETH [INFO] Updated price for pool 0x82af [INFO] Checking for arbitrage opportunities... ``` ### After Fix #3 (Price Updates) ```bash # Check price cache stats grep "price.*cache\|cached.*price" logs/mev_bot.log # Expected: [INFO] Price cache stats: 32 prices cached [INFO] Updated 15 prices in last minute [INFO] Oldest price age: 45 seconds ``` --- ## 📈 Expected Performance After Fixes ### Pool Management - ✅ 96 pools persisted to disk - ✅ Instant load on restart (<1 second) - ✅ Discovery runs once, cache reused ### Swap Processing - ✅ 50-100 swaps/minute detected - ✅ Real-time price updates - ✅ <100ms latency from swap to price update ### Arbitrage Detection - ✅ Compare prices across 96 pools - ✅ Detect opportunities within 1 block - ✅ 5-10+ opportunities/hour expected --- ## 🚨 Priority Order 1. **URGENT**: Fix swap event detection (Fix #2) - **Why**: Bot is blind without swap data - **Impact**: Enables all arbitrage detection 2. **HIGH**: Implement price updates (Fix #3) - **Why**: Required for arbitrage calculation - **Impact**: Real-time opportunity detection 3. **MEDIUM**: Add pool cache persistence (Fix #1) - **Why**: Improves startup time - **Impact**: UX improvement, reduced RPC load --- ## 📝 Additional Recommendations ### Monitoring Enhancements ```bash # Add metrics for debugging - swap_events_processed (counter) - price_updates_count (counter) - cache_hit_rate (gauge) - pool_count (gauge) - arbitrage_opportunities_detected (counter) ``` ### Logging Improvements ```go // Add periodic stats logging Every 60 seconds: - Pools monitored: 96 - Swap events (last min): 47 - Price updates (last min): 32 - Arbitrage opportunities: 3 - Cache size: 5.2KB ``` ### Testing Strategy 1. **Unit Tests**: Test SaveCache() function 2. **Integration Tests**: Verify swap event parsing 3. **End-to-End Tests**: Full flow from swap → arbitrage 4. **Load Tests**: Handle 1000+ swaps/minute --- ## 🎯 Success Criteria After fixes are applied, the bot should: 1. ✅ Discover 96 pools and save to disk 2. ✅ Detect 50+ swaps per minute 3. ✅ Update prices within 100ms of swap 4. ✅ Cache 20-30 active prices 5. ✅ Detect 5-10 arbitrage opportunities per hour 6. ✅ Restart in <5 seconds (load from cache) --- ## 📚 Code References - **Pool Discovery**: `pkg/pools/discovery.go` - **Price Engine**: `pkg/pricing/engine.go` - **Market Updates**: `pkg/marketmanager/types.go:UpdatePriceData()` - **Swap Processing**: `pkg/scanner/market/scanner.go` - **Main Entry**: `cmd/mev-bot/main.go:256-323` --- **Status**: ⚠️ **CRITICAL FIXES REQUIRED** **Next Action**: Implement Fix #2 (Swap Detection) as highest priority **Estimated Time**: 2-4 hours for all fixes **Expected Value**: Enable arbitrage detection capability --- *Document Version*: 1.0 *Last Updated*: October 30, 2025 18:15 UTC *Analysis Duration*: 30 minutes *Evidence Reviewed*: 10+ log files, 5 code modules, 3 cache files