if self.sol_balance < wrap_amount + (self.min_sol_balance / 2):  # Reduced min balance requirement
            logger.error(f"Insufficient SOL: {self.sol_balance}, need {wrap_amount + (self.min_sol_balance / 2)}")
            return False
            
        try:
            logger.info(f"Wrapping {wrap_amount} SOL to WSOL")
            
            if not self.simulation_mode:
                # Execute wrap - this actually executes the SOL wrap
                signature = self.trader.wrap_sol(wrap_amount)
                self.last_wrap_time = time.time()
                
                # Wait for confirmation
                confirmed = self.trader.confirm_transaction(signature, 15)
                
                if confirmed:
                    # Update balances
                    self.sol_balance = self.trader.get_sol_balance()
                    self.wsol_balance = self.trader.get_token_balance(CONFIG["WSOL_ADDRESS"])
                    logger.info(f"Wrapped SOL successfully: SOL={self.sol_balance:.4f}, WSOL={self.wsol_balance:.4f}")
                    return True
                else:
                    logger.error(f"Wrap confirmation failed")
                    return False
            else:
                # Simulation mode
                logger.info(f"SIMULATION: Would wrap {wrap_amount} SOL to WSOL")
                self.last_wrap_time = time.time()
                
                # Simulate the wrap by adjusting balances
                self.sol_balance -= wrap_amount
                self.wsol_balance += wrap_amount
                return True
                
        except Exception as e:
            logger.error(f"Error wrapping SOL: {e}")
            return False
    
    async def unwrap_wsol(self):
        """Unwrap WSOL back to native SOL"""
        try:
            logger.info(f"Unwrapping {self.wsol_balance} WSOL to SOL")
            
            if not self.simulation_mode:
                # Execute unwrap - this actually executes the WSOL unwrap
                signature = self.trader.unwrap_sol()
                
                # Wait for confirmation
                confirmed = self.trader.confirm_transaction(signature, 15)
                
                if confirmed:
                    # Update balances
                    self.sol_balance = self.trader.get_sol_balance()
                    self.wsol_balance = self.trader.get_token_balance(CONFIG["WSOL_ADDRESS"])
                    logger.info(f"Unwrapped WSOL successfully: SOL={self.sol_balance:.4f}, WSOL={self.wsol_balance:.4f}")
                    return True
                else:
                    logger.error(f"Unwrap confirmation failed")
                    return False
            else:
                # Simulation mode
                logger.info(f"SIMULATION: Would unwrap {self.wsol_balance} WSOL to SOL")
                
                # Simulate the unwrap by adjusting balances
                self.sol_balance += self.wsol_balance
                self.wsol_balance = 0
                return True
                
        except Exception as e:
            logger.error(f"Error unwrapping WSOL: {e}")
            return False
            
    async def monitor_balances(self):
        """Monitor and manage SOL/WSOL balances"""
        check_interval = 60  # Check every minute
        
        while self.running:
            try:
                # Skip if active opportunity
                if self.active_opportunity:
                    await asyncio.sleep(check_interval)
                    continue
                
                # Get current balances
                current_time = time.time()
                if current_time - self.last_balance_update > 60:
                    try:
                        self.sol_balance = self.trader.get_sol_balance()
                        self.wsol_balance = self.trader.get_token_balance(CONFIG["WSOL_ADDRESS"])
                        self.last_balance_update = current_time
                    except Exception as e:
                        logger.error(f"Error updating balances: {e}")
                        # Continue despite errors - will try again next interval
                
                # Check if we need to wrap SOL or unwrap WSOL
                total_balance = self.sol_balance + self.wsol_balance
                wsol_ratio = self.wsol_balance / total_balance if total_balance > 0 else 0
                target_ratio = 0.75  # Target 75% in WSOL, 25% in SOL
                
                # If SOL balance is too low, unwrap WSOL
                if self.sol_balance < self.min_sol_balance and self.wsol_balance > self.min_sol_balance * 2:
                    logger.info(f"SOL balance too low ({self.sol_balance:.4f}), unwrapping WSOL")
                    await self.unwrap_wsol()
                
                # If WSOL ratio is too low, wrap SOL
                elif wsol_ratio < target_ratio * 0.8 and self.sol_balance > self.min_sol_balance * 1.5:
                    wrap_amount = (total_balance * target_ratio - self.wsol_balance) * 1.1
                    if wrap_amount > 0.01:  # Reduced min wrap amount
                        logger.info(f"WSOL ratio too low ({wsol_ratio:.2f}), wrapping {wrap_amount:.4f} SOL")
                        await self.ensure_wsol(wrap_amount)
                
            except Exception as e:
                logger.error(f"Error in balance monitoring: {e}")
                
            await asyncio.sleep(check_interval)
    
    async def safe_shutdown(self):
        """Clean shutdown with completion of active trades"""
        logger.info("Initiating safe shutdown...")
        
        # Complete active opportunity if any
        if self.active_opportunity and self.active_opportunity.status == "frontrun":
            logger.info(f"Completing active opportunity before shutdown")
            await self.execute_emergency_sell(self.active_opportunity)
        
        # Unwrap excess WSOL if not in simulation mode
        if not self.simulation_mode and self.wsol_balance > self.min_wsol_balance * 2:
            await self.unwrap_wsol()
            
        logger.info("Shutdown complete")
        
    def print_stats(self):
        """Print detailed trading statistics"""
        duration = time.time() - self.stats.start_time
        hours = duration // 3600
        minutes = (duration % 3600) // 60
        seconds = duration % 60
        
        logger.info("=" * 50)
        logger.info("MEV Trading Statistics:")
        logger.info(f"Runtime: {int(hours)}h {int(minutes)}m {int(seconds)}s")
        logger.info(f"Transactions seen: {self.stats.transactions_seen}")
        logger.info(f"Raydium swaps found: {self.stats.raydium_swaps_found}")
        logger.info(f"Viable opportunities: {self.stats.viable_opportunities}")
        logger.info(f"Trades attempted: {self.stats.trades_attempted}")
        logger.info(f"Trades completed: {self.stats.trades_completed}")
        logger.info(f"Failed front-runs: {self.stats.failed_front_runs}")
        logger.info(f"Failed back-runs: {self.stats.failed_back_runs}")
        logger.info(f"Total profit: {self.stats.total_profit:.6f} SOL")
        logger.info(f"Total loss: {self.stats.total_loss:.6f} SOL")
        logger.info(f"Net profit: {self.stats.total_profit - self.stats.total_loss:.6f} SOL")
        
        # Token validation stats
        logger.info(f"Invalid tokens rejected: {self.stats.invalid_tokens_count}")
        logger.info(f"AccountNotFound errors: {self.stats.account_not_found_count}")
        
        # WebSocket stats
        logger.info(f"WebSocket connections: {self.stats.ws_connections}")
        logger.info(f"WebSocket messages received: {self.stats.ws_messages_received}")
        logger.info(f"WebSocket errors: {self.stats.ws_errors}")
        logger.info(f"WebSocket reconnects: {self.stats.ws_reconnects}")
        
        logger.info("=" * 50)

async def main():
    """Main entry point"""
    try:
        # Initialize and run the MEV trader
        trader = RaydiumMEVTrader()
        async with trader:
            await trader.run()
    except KeyboardInterrupt:
        logger.info("Keyboard interrupt received, shutting down gracefully...")
    except Exception as e:
        logger.critical(f"Critical error: {e}")
        logger.critical(traceback.format_exc())

if __name__ == "__main__":
    if sys.platform == 'win32':
        asyncio.set_event_loop_policy(asyncio.WindowsSelectorEventLoopPolicy())
    asyncio.run(main())                self.stats.ws_reconnects += 1
                # Rotate endpoints on disconnection
                self.rpc_manager.rotate_endpoints()
                
            except (asyncio.TimeoutError, websockets.exceptions.WebSocketException) as e:
                self.stats.ws_errors += 1
                retry_count += 1
                logger.error(f"WebSocket error (retry {retry_count}/{max_retries}): {e}")
                
                # Rotate endpoints on connection failure
                self.rpc_manager.rotate_endpoints()
                
                # Wait before retry with exponential backoff
                await asyncio.sleep(backoff)
                backoff = min(30, backoff * 1.5)
                
            except Exception as e:
                self.stats.ws_errors += 1
                retry_count += 1
                logger.error(f"Unexpected error: {e}")
                logger.error(traceback.format_exc())
                
                # Wait before retry with exponential backoff
                await asyncio.sleep(backoff)
                backoff = min(30, backoff * 1.5)
                
        # If we've exhausted all retries
        if retry_count >= max_retries:
            logger.critical("Exceeded maximum retry attempts for WebSocket connection")
            self.running = False

    async def process_logs_notification(self, data):
        """Process Raydium program logs for MEV opportunities"""
        try:
            # Skip if shutting down or already have active opportunity
            if not self.running or self.active_opportunity:
                return
                
            # Extract logs and signature
            params = data.get("params", {})
            result = params.get("result", {})
            value = result.get("value", {})
            
            logs = value.get("logs", [])
            tx_signature = value.get("signature", "unknown")
            
            # Skip if no logs or already processed
            if not logs or tx_signature in self.processed_txs or tx_signature in self.processing_txs:
                return
                
            # Mark as processing
            self.processing_txs.add(tx_signature)
            
            self.stats.transactions_seen += 1
            self.processed_txs.add(tx_signature)
            
            # Limit processed_txs size
            if len(self.processed_txs) > 5000:
                self.processed_txs = set(list(self.processed_txs)[-2500:])
            
            # Check for ray_log entries
            ray_log_found = False
            token_mint = None
            accounts = {}
            amount_sol = 0.0
            is_buy = False
            
            for log in logs:
                if "ray_log:" in log:
                    ray_log_found = True
                    ray_data = self.token_extractor.decode_ray_log(log)
                    
                    if ray_data and ray_data["instruction_type"] == 3:  # Look for 0x03 instructions
                        self.stats.raydium_swaps_found += 1
                        
                        # Check amount to see if it's a viable opportunity
                        amount_sol = ray_data["amount"]
                        is_buy = ray_data["is_buy"]
                        
                        if (is_buy and 
                            self.min_victim_size <= amount_sol <= self.max_victim_size):
                            
                            # Extract token mint (parallelized)
                            token_mint = await asyncio.get_event_loop().run_in_executor(
                                self.thread_pool,
                                lambda: self.token_extractor.extract_token_mint(logs)
                            )
                            
                            if token_mint:
                                # Extract accounts for swap
                                accounts = self.token_extractor.extract_accounts(logs)
                                accounts["token_mint"] = token_mint
                                
                                logger.info(f"Found potential MEV: {tx_signature[:8]}, "
                                          f"Buy {amount_sol:.4f} SOL, "
                                          f"Token: {token_mint[:8]}")
                                          
                                self.stats.viable_opportunities += 1
                                          
                                # Process opportunity
                                await self.process_opportunity(token_mint, amount_sol, tx_signature, accounts)
                        
                        else:
                            # Log if it's a Raydium swap but not a viable opportunity
                            token_info = "Unknown"
                            if ray_data["pubkeys"] and len(ray_data["pubkeys"]) > 3:
                                possible_token = ray_data["pubkeys"][3]
                                if self.token_extractor.is_valid_pubkey(possible_token):
                                    token_info = possible_token[:8]
                                    
                            logger.debug(f"Raydium swap (not viable): {tx_signature[:8]}, "
                                    f"Buy: {is_buy}, Amount: {amount_sol:.4f} SOL, "
                                    f"Token: {token_info}")
            
            if not ray_log_found:
                logger.debug(f"Transaction without ray_log: {tx_signature[:8]}")
            
            # Remove from processing list
            if tx_signature in self.processing_txs:
                self.processing_txs.remove(tx_signature)
                
        except Exception as e:
            logger.error(f"Error processing logs: {e}")
            logger.error(traceback.format_exc())
            # Make sure to remove from processing list
            if tx_signature in self.processing_txs:
                self.processing_txs.remove(tx_signature)
    
    async def process_opportunity(self, token_mint, amount_sol, tx_signature, accounts):
        """Process an MEV opportunity"""
        try:
            # Skip if already have active opportunity or shutting down
            if self.active_opportunity or not self.running:
                return
                
            # Quick validation using cached results
            if token_mint in self.invalid_tokens:
                logger.debug(f"Skipping known invalid token: {token_mint[:8]}")
                return
                
            # Check valid tokens cache
            if token_mint in self.valid_tokens:
                is_valid = True
                logger.info(f"Using cached valid token: {token_mint[:8]}")
                self.stats.cached_tokens_used += 1
            else:
                # Verify token exists first (cheap check)
                token_exists = await self.token_validator.verify_token_exists(token_mint)
                if not token_exists:
                    logger.info(f"Token {token_mint[:8]} does not exist or is not a mint")
                    self.invalid_tokens.add(token_mint)
                    self.stats.invalid_tokens_count += 1
                    self.stats.account_not_found_count += 1
                    return
                
                # Validate token security features
                security = await self.token_validator.validate_token_security(token_mint)
                is_valid = security.valid
                
                # Update cache based on result
                if is_valid:
                    self.valid_tokens.add(token_mint)
                    logger.info(f"Validated new token: {token_mint[:8]}")
                else:
                    self.invalid_tokens.add(token_mint)
                    self.stats.invalid_tokens_count += 1
                    logger.info(f"Invalid token rejected: {token_mint[:8]}: " +
                              f"mint_revoked={security.mint_authority_revoked}, " +
                              f"lp_locked={security.lp_locked}, " +
                              f"exit_liquidity={security.exit_liquidity_sol:.2f} SOL")
                    return
            
            # Calculate front-run amount based on victim size
            # Dynamic calculation based on victim size with square root scaling
            front_amount = min(self.front_run_amount, self.sol_balance * 0.2)  # Never use more than 20% of balance
            if amount_sol > 10.0:
                # Scale up for larger victims, limited to 2x base amount
                front_amount = min(
                    self.front_run_amount * (amount_sol / 10.0) ** 0.5,
                    self.front_run_amount * 2,
                    self.sol_balance * 0.2  # Still capped at 20% of balance
                )
            
            # Create opportunity object
            opportunity = TradeOpportunity(
                token_mint=token_mint,
                amount_sol=amount_sol,
                tx_signature=tx_signature,
                accounts=accounts,
                front_amount=front_amount,
                start_time=time.time(),
                start_sol_balance=self.sol_balance,
                start_wsol_balance=self.wsol_balance
            )
            
            # Check if we have enough balance with reduced requirements
            async with self.balance_lock:
                total_balance = self.sol_balance + self.wsol_balance
                min_required = front_amount + self.min_sol_balance
                
                if total_balance < min_required:
                    logger.warning(f"Insufficient balance: {total_balance:.4f} SOL, need {min_required:.4f} SOL")
                    return
                    
                # Make sure we have enough WSOL - with reduced buffer
                wsol_ok = await self.ensure_wsol(front_amount * 1.2)  # Reduced from 1.5 to 1.2
                
                if not wsol_ok:
                    logger.error(f"Failed to ensure WSOL for {token_mint[:8]}")
                    return
                    
                # Update WSOL balance after wrapping
                self.wsol_balance = self.trader.get_token_balance(CONFIG["WSOL_ADDRESS"])
            
            # Check profitability estimation
            profit_estimate = self.estimate_profit(front_amount, amount_sol)
            if not profit_estimate["is_profitable"]:
                logger.info(f"Skipping unprofitable opportunity: {token_mint[:8]}, " +
                           f"estimated profit: {profit_estimate['net_profit']:.6f} SOL")
                return
                
            # Set as active opportunity
            self.active_opportunity = opportunity
            self.stats.trades_attempted += 1
            
            logger.info(f"Executing front-run for victim tx {tx_signature[:8]} with {front_amount:.4f} SOL -> {token_mint[:8]}")
            
            # ======= TRADE EXECUTION - THIS IS THE CRITICAL PART =======
            # Execute front-run using the Rust trader module
            if not self.simulation_mode:
                front_tx_signature = self.execute_swap(
                    token_mint=token_mint,
                    amount_sol=front_amount,
                    accounts=accounts,
                    is_buy=True
                )
                
                if front_tx_signature:
                    logger.info(f"Front-run successful: {front_tx_signature[:8]}")
                    opportunity.front_tx = front_tx_signature
                    opportunity.status = "frontrun"
                    
                    # Get token balance and decimals for accurate back-run
                    opportunity.token_balance = self.trader.get_token_balance(token_mint)
                    opportunity.token_decimals = self.trader.get_token_decimals(token_mint)
                    
                    logger.info(f"Received {opportunity.token_balance} tokens (decimals: {opportunity.token_decimals})")
                    
                    # Now wait for victim confirmation via WebSocket balance updates
                else:
                    logger.error(f"Front-run failed: null tx")
                    self.stats.failed_front_runs += 1
                    self.active_opportunity = None
            else:
                # Simulation mode - pretend the front-run worked
                logger.info(f"SIMULATION: Front-run would be executed for {front_amount:.4f} SOL -> {token_mint[:8]}")
                
                # Simulate a successful front-run
                opportunity.front_tx = "simulated_" + tx_signature
                opportunity.status = "frontrun"
                opportunity.token_balance = 1000.0  # Pretend we got 1000 tokens
                opportunity.token_decimals = 9      # Standard decimals
                logger.info("SIMULATION: Front-run 'successful' - waiting for victim transaction")
                
        except Exception as e:
            logger.error(f"Error processing opportunity: {e}")
            logger.error(traceback.format_exc())
            self.active_opportunity = None
            
    async def check_active_opportunity(self):
        """Check and update active opportunity status"""
        if not self.active_opportunity:
            return
            
        # Handle timeout for victim confirmation
        victim_timeout = CONFIG["VICTIM_CONFIRM_TIMEOUT"]
        if (self.active_opportunity.status == "frontrun" and 
            not self.active_opportunity.victim_confirmed and
            time.time() - self.active_opportunity.start_time > victim_timeout):
            
            logger.warning(f"Victim tx confirmation timeout for {self.active_opportunity.token_mint[:8]}")
            self.stats.victim_missed_count += 1
            
            # Execute emergency sell
            await self.execute_emergency_sell(self.active_opportunity)
            return
            
        # If victim confirmed, execute back-run
        if (self.active_opportunity.status == "frontrun" and 
            self.active_opportunity.victim_confirmed and
            not hasattr(self.active_opportunity, "back_run_started")):
            
            # Mark back_run as started to prevent double execution
            self.active_opportunity.back_run_started = True
            
            # Add a small delay to ensure victim transaction is fully processed
            await asyncio.sleep(CONFIG["MIN_TRADE_INTERVAL"])
            
            # Execute back-run
            await self.execute_back_run(self.active_opportunity)
    
    async def update_wallet_balance(self):
        """Update wallet balance after transaction"""
        async with self.balance_lock:
            prev_sol = self.sol_balance
            prev_wsol = self.wsol_balance
            
            try:
                self.sol_balance = self.trader.get_sol_balance()
                self.wsol_balance = self.trader.get_token_balance(CONFIG["WSOL_ADDRESS"])
                self.last_balance_update = time.time()
                
                total_before = prev_sol + prev_wsol
                total_after = self.sol_balance + self.wsol_balance
                
                # Only log if there's a significant change
                if abs(total_after - total_before) > 0.0001:
                    logger.info(f"Updated wallet balance: SOL={self.sol_balance:.4f}, WSOL={self.wsol_balance:.4f}, " +
                               f"Change: {total_after - total_before:.6f} SOL")
            except Exception as e:
                logger.error(f"Error updating wallet balance: {e}")
                return
            
            # Check for victim confirmation if we have active opportunity
            if (self.active_opportunity and 
                self.active_opportunity.status == "frontrun" and 
                not self.active_opportunity.victim_confirmed):
                
                # Calculate balance change
                total_before = prev_sol + prev_wsol
                total_after = self.sol_balance + self.wsol_balance
                significant_change = abs(total_after - total_before) > 0.0001
                
                # Mark victim as confirmed if we see a balance change
                if significant_change:
                    self.active_opportunity.victim_confirmed = True
                    self.stats.victim_confirmed_count += 1
                    
                    logger.info(f"Victim transaction confirmed for {self.active_opportunity.token_mint[:8]} " +
                              f"(balance change: {total_after - total_before:.6f} SOL)")
    
    def execute_swap(self, token_mint, amount_sol, accounts, is_buy):
        """Execute a swap transaction with correct instruction format"""
        try:
            # Fill in any missing accounts with defaults based on token_mint
            required_keys = [
                "token_program_id", "amm_id", "amm_authority", "amm_open_orders", 
                "amm_target_orders", "pool_coin_token_account", "pool_pc_token_account", 
                "serum_program_id", "serum_market", "serum_bids", "serum_asks",
                "serum_event_queue", "serum_coin_vault", "serum_pc_vault",
                "serum_vault_signer", "token_mint"
            ]
            
            # Add token_mint if not already in accounts
            if "token_mint" not in accounts:
                accounts["token_mint"] = token_mint
                
            # Add program IDs if not already in accounts
            if "token_program_id" not in accounts:
                accounts["token_program_id"] = CONFIG["TOKEN_PROGRAM_ID"]
            if "serum_program_id" not in accounts:
                accounts["serum_program_id"] = CONFIG["SERUM_PROGRAM_ID"]
                
            # Verify all accounts are present and valid
            missing_keys = [key for key in required_keys if key not in accounts]
            if missing_keys:
                logger.error(f"Missing required accounts: {missing_keys}")
                # Try to fill in with defaults
                for key in missing_keys:
                    if key == "token_program_id":
                        accounts[key] = CONFIG["TOKEN_PROGRAM_ID"]
                    elif key == "serum_program_id":
                        accounts[key] = CONFIG["SERUM_PROGRAM_ID"]
                    else:
                        # For other missing accounts, we can't proceed safely
                        logger.error(f"Cannot fill missing account: {key}")
                        return None
            
            # Execute proper swap with the trader
            slippage = self.slippage_percent  # Already in percent
            priority_multiplier = 1
            
            # Use the Rust trader to execute the swap
            tx_signature = self.trader.execute_raydium_swap(
                accounts,               # All required accounts
                amount_sol,             # Amount in SOL
                slippage,               # Slippage percentage
                priority_multiplier     # Priority multiplier
            )
            
            # Log the transaction
            if tx_signature:
                logger.info(f"TRADE EXECUTED: {'Buy' if is_buy else 'Sell'} {amount_sol:.4f} SOL of {token_mint[:8]} with tx: {tx_signature}")
            else:
                logger.error(f"TRADE FAILED: {'Buy' if is_buy else 'Sell'} {amount_sol:.4f} SOL of {token_mint[:8]}")
                
            return tx_signature
        
        except Exception as e:
            logger.error(f"Error executing swap: {e}")
            logger.error(traceback.format_exc())
            return None
            
    async def execute_back_run(self, opportunity):
        """Execute back-run after victim tx confirmation"""
        try:
            token_mint = opportunity.token_mint
            
            # Get token balance with verification
            if opportunity.token_balance <= 0:
                opportunity.token_balance = self.trader.get_token_balance(token_mint)
            
            if opportunity.token_balance <= 0:
                logger.warning(f"No tokens to sell for back-run: {token_mint[:8]}")
                self.active_opportunity = None
                return
                
            logger.info(f"Back-running with {opportunity.token_balance} tokens of {token_mint[:8]}")
            
            # Get token decimals if not already known
            if opportunity.token_decimals == 9:  # Default value
                opportunity.token_decimals = self.trader.get_token_decimals(token_mint)
            
            # Add optimal timing delay based on victim size
            victim_size = opportunity.amount_sol
            optimal_delay = min(0.2 + (victim_size / 100.0), 0.8)
            await asyncio.sleep(optimal_delay)
            
            # Execute back-run (sell 100% of tokens)
            if not self.simulation_mode:
                back_tx_signature = self.execute_token_sell(
                    token_mint=token_mint,
                    token_amount=opportunity.token_balance,
                    token_decimals=opportunity.token_decimals,
                    accounts=opportunity.accounts
                )
                
                if back_tx_signature:
                    logger.info(f"Back-run successful: {back_tx_signature[:8]}")
                    opportunity.back_tx = back_tx_signature
                    
                    # Get updated balances
                    async with self.balance_lock:
                        self.sol_balance = self.trader.get_sol_balance()
                        self.wsol_balance = self.trader.get_token_balance(CONFIG["WSOL_ADDRESS"])
                        self.last_balance_update = time.time()
                        
                        # Calculate profit/loss
                        total_end = self.sol_balance + self.wsol_balance
                        total_start = opportunity.start_sol_balance + opportunity.start_wsol_balance
                        
                        # Calculate transaction costs
                        tx_cost = 0.000005 * 2  # Base fee for two transactions
                        compute_cost = (CONFIG["COMPUTE_LIMIT"] / 1000000) * (CONFIG["PRIORITY_FEE"] / LAMPORTS_PER_SOL) * 2
                        total_cost = tx_cost + compute_cost
                        
                        raw_profit = total_end - total_start
                        net_profit = raw_profit - total_cost
                        
                        opportunity.profit = net_profit
                        opportunity.end_sol_balance = self.sol_balance
                        opportunity.end_wsol_balance = self.wsol_balance
                        opportunity.status = "complete"
                        
                        self.stats.trades_completed += 1
                        
                        if net_profit >= 0:
                            self.stats.total_profit += net_profit
                            roi_percent = (net_profit / opportunity.front_amount) * 100
                            logger.info(f"Trade profit: +{net_profit:.6f} SOL (ROI: {roi_percent:.2f}%)")
                        else:
                            self.stats.total_loss += abs(net_profit)
                            logger.info(f"Trade loss: {net_profit:.6f} SOL")
                else:
                    logger.error(f"Back-run failed: null tx")
                    self.stats.failed_back_runs += 1
                    await self.execute_emergency_sell(opportunity)
                    return
            else:
                # Simulation mode
                logger.info(f"SIMULATION: Back-run would be executed to sell {opportunity.token_balance} tokens")
                
                # Simulate a successful back-run with a small profit
                opportunity.back_tx = "simulated_back_" + opportunity.tx_signature
                opportunity.status = "complete"
                opportunity.profit = self.min_profit * 1.5  # Pretend we made a small profit
                
                self.stats.trades_completed += 1
                self.stats.total_profit += opportunity.profit
                logger.info(f"SIMULATION: Trade profit: +{opportunity.profit:.6f} SOL")
            
            # Clear active opportunity
            self.active_opportunity = None
                
        except Exception as e:
            logger.error(f"Error in back-run: {e}")
            logger.error(traceback.format_exc())
            await self.execute_emergency_sell(opportunity)
    
    def execute_token_sell(self, token_mint, token_amount, token_decimals, accounts):
        """Sell tokens with proper instruction format"""
        try:
            # Calculate token amount in smallest units
            token_units = int(token_amount * (10 ** token_decimals))
            
            # Make sure we have all the required accounts
            required_keys = [
                "token_program_id", "amm_id", "amm_authority", "amm_open_orders", 
                "amm_target_orders", "pool_coin_token_account", "pool_pc_token_account", 
                "serum_program_id", "serum_market", "token_mint"
            ]
            
            # Add token_mint if not already in accounts
            if "token_mint" not in accounts:
                accounts["token_mint"] = token_mint
                
            # Add program IDs if not already in accounts
            if "token_program_id" not in accounts:
                accounts["token_program_id"] = CONFIG["TOKEN_PROGRAM_ID"]
            if "serum_program_id" not in accounts:
                accounts["serum_program_id"] = CONFIG["SERUM_PROGRAM_ID"]
                
            # Verify all accounts are present
            missing_keys = [key for key in required_keys if key not in accounts]
            if missing_keys:
                logger.error(f"Missing required accounts for sell: {missing_keys}")
                return None
            
            # Use the Rust trader to execute the sell
            tx_signature = self.trader.sell_token_for_sol(
                token_mint,                        # Token mint address
                token_amount,                      # Amount of tokens to sell
                token_decimals,                    # Token decimals
                accounts["amm_id"],                # AMM ID
                accounts["amm_authority"],         # AMM Authority
                accounts["amm_open_orders"],       # AMM Open Orders
                accounts["amm_target_orders"],     # AMM Target Orders
                accounts["pool_coin_token_account"], # Pool Coin Token Account
                accounts["pool_pc_token_account"],   # Pool PC Token Account
                self.slippage_percent,             # Slippage percentage
                2                                  # Priority multiplier (2x for back-run)
            )
            
            if tx_signature:
                logger.info(f"TOKEN SELL EXECUTED: {token_amount} tokens of {token_mint[:8]} with tx: {tx_signature}")
            else:
                logger.error(f"TOKEN SELL FAILED: {token_amount} tokens of {token_mint[:8]}")
                
            return tx_signature
        
        except Exception as e:
            logger.error(f"Error selling tokens: {e}")
            logger.error(traceback.format_exc())
            return None
    
    async def execute_emergency_sell(self, opportunity):
        """Emergency sell to recover funds"""
        try:
            token_mint = opportunity.token_mint
            
            # Get current token balance
            token_balance = self.trader.get_token_balance(token_mint)
            
            if token_balance <= 0:
                logger.warning(f"No tokens to sell: {token_mint[:8]}")
                self.active_opportunity = None
                return
                
            logger.info(f"Emergency selling {token_balance} tokens of {token_mint[:8]}")
            
            # Get token decimals if not already known
            if opportunity.token_decimals == 9:  # Default value
                opportunity.token_decimals = self.trader.get_token_decimals(token_mint)
            
            # Execute sell with higher slippage
            if not self.simulation_mode:
                for attempt in range(3):
                    multiplier = 1.0 + (attempt * 0.5)  # Increase slippage with each attempt
                    
                    tx_signature = self.execute_token_sell(
                        token_mint=token_mint,
                        token_amount=token_balance,
                        token_decimals=opportunity.token_decimals,
                        accounts=opportunity.accounts
                    )
                    
                    if tx_signature:
                        logger.info(f"Emergency sell successful on attempt {attempt+1}: {tx_signature[:8]}")
                        
                        # Get updated balances
                        async with self.balance_lock:
                            self.sol_balance = self.trader.get_sol_balance()
                            self.wsol_balance = self.trader.get_token_balance(CONFIG["WSOL_ADDRESS"])
                            self.last_balance_update = time.time()
                            
                            # Calculate profit/loss
                            total_end = self.sol_balance + self.wsol_balance
                            profit = total_end - (opportunity.start_sol_balance + opportunity.start_wsol_balance)
                            
                            opportunity.profit = profit
                            opportunity.end_sol_balance = self.sol_balance
                            opportunity.end_wsol_balance = self.wsol_balance
                            
                            if profit >= 0:
                                self.stats.total_profit += profit
                                logger.info(f"Emergency sell profit: +{profit:.6f} SOL")
                            else:
                                self.stats.total_loss += abs(profit)
                                logger.info(f"Emergency sell loss: {profit:.6f} SOL")
                        
                        break
                    else:
                        logger.error(f"Emergency sell attempt {attempt+1} failed")
                        await asyncio.sleep(0.5 * (attempt + 1))
            else:
                # Simulation mode
                logger.info(f"SIMULATION: Emergency sell would be executed for {token_balance} tokens")
                # Simulate a small loss
                opportunity.profit = -0.005
                self.stats.total_loss += abs(opportunity.profit)
                logger.info(f"SIMULATION: Emergency sell loss: {opportunity.profit:.6f} SOL")
            
            # Clear active opportunity
            self.active_opportunity = None
                
        except Exception as e:
            logger.error(f"Error in emergency sell: {e}")
            logger.error(traceback.format_exc())
            self.active_opportunity = None
    
    def estimate_profit(self, front_amount, victim_amount):
        """Estimate profit with enhanced calculation"""
        # Raydium fee
        raydium_fee = 0.0025  # 0.25%
        
        # Calculate token flow
        tokens_received = front_amount * (1.0 - raydium_fee)
        
        # Calculate price impact based on victim size
        # Larger victims cause more price impact
        price_impact_percent = min(0.05 * (victim_amount / 5.0) ** 0.5, 0.20)
        
        # Calculate expected SOL from back-run
        back_amount = tokens_received * (1.0 + price_impact_percent) * (1.0 - raydium_fee)
        
        # Calculate total fees
        priority_fee = (CONFIG["PRIORITY_FEE"] / LAMPORTS_PER_SOL) * (CONFIG["COMPUTE_LIMIT"] / 1000000) * 2
        total_fees = priority_fee + (0.000005 * 2)  # Base fee for two transactions
        
        # Calculate profit after fees
        raw_profit = back_amount - front_amount
        net_profit = raw_profit - total_fees
        
        # Apply safety margin
        adjusted_profit = net_profit * 0.95
        
        return {
            "raw_profit": raw_profit,
            "net_profit": net_profit,
            "adjusted_profit": adjusted_profit,
            "total_fees": total_fees,
            "price_impact": price_impact_percent,
            "is_profitable": adjusted_profit > self.min_profit
        }
    
    async def ensure_wsol(self, amount_needed):
        """Ensure sufficient WSOL for trading with reduced requirements"""
        # Already have enough
        if self.wsol_balance >= amount_needed:
            return True
            
        # Don't wrap too frequently
        if time.time() - self.last_wrap_time < self.wsol_wrap_interval:
            return False
            
        # Calculate amount to wrap (reduced buffer)
        wrap_amount = max(
            0.01,  # Minimum wrap amount reduced to 0.01
            (amount_needed - self.wsol_balance) * 1.1  # Buffer reduced from 1.5 to 1.1
        )
        
        # Ensure we have enough SOL - reduced min balance to improve success rate
        if self.sol_                                "filters": [
                                    {"dataSize": 680},  # Raydium V4 pool size
                                    {"memcmp": {"offset": 72, "bytes": token_mint}}
                                ]
                            }
                        ]
                    },
                    headers=self.rpc_manager.get_headers()
                ) as response:
                    data = await response.json()
                    
                    # Check for rate limiting
                    if "error" in data and "429" in str(data.get("error")):
                        self.rpc_manager.handle_rate_limit(rpc_url)
                        return await self.get_token_pool(token_mint)
                    
                    if "result" in data and len(data["result"]) > 0:
                        return data["result"][0]["pubkey"]
            
            return None
        except Exception as e:
            logger.error(f"Error finding pool for token {token_mint[:8]}: {e}")
            return None
    
    async def get_pool_data(self, pool_address):
        """Get the raw binary data for a pool"""
        try:
            rpc_url = self.rpc_manager.get_current_rpc()
            
            async with aiohttp.ClientSession() as session:
                async with session.post(
                    rpc_url,
                    json={
                        "jsonrpc": "2.0",
                        "id": 1,
                        "method": "getAccountInfo",
                        "params": [
                            pool_address,
                            {"encoding": "base64"}
                        ]
                    },
                    headers=self.rpc_manager.get_headers()
                ) as response:
                    data = await response.json()
                    
                    # Check for rate limiting
                    if "error" in data and "429" in str(data.get("error")):
                        self.rpc_manager.handle_rate_limit(rpc_url)
                        return await self.get_pool_data(pool_address)
                    
                    if "result" in data and data["result"] and "value" in data["result"]:
                        value = data["result"]["value"]
                        if "data" in value and len(value["data"]) > 0:
                            return base64.b64decode(value["data"][0])
            
            return None
        except Exception as e:
            logger.error(f"Error getting pool data for {pool_address}: {e}")
            return None
    
    def analyze_pool_security(self, data):
        """Analyze pool security features with multiple validation approaches"""
        results = {
            "exit_liquidity": 0.0,
            "lp_locked": False
        }
        
        # Try all security profiles
        for profile in self.security_profiles:
            try:
                # Check liquidity
                if len(data) >= profile["liquidity"][1]:
                    liquidity_bytes = data[profile["liquidity"][0]:profile["liquidity"][1]]
                    liquidity_raw = int.from_bytes(liquidity_bytes, "little")
                    # Convert to SOL amount using scaling factor
                    liquidity_value = liquidity_raw / 1e6
                    
                    # Update if we found a valid liquidity value
                    if liquidity_value > 0 and liquidity_value < 1e9:  # Sanity check
                        results["exit_liquidity"] = liquidity_value
                
                # Check LP lock
                if len(data) >= profile["lp_lock"] + 8:
                    lp_raw_value = int.from_bytes(data[profile["lp_lock"]:profile["lp_lock"]+8], "little")
                    results["lp_locked"] = lp_raw_value > 0
                
                # If we found valid data, exit loop
                if results["exit_liquidity"] > 0:
                    break
                    
            except Exception:
                continue
        
        # Additional LP lock verification methods
        # Try alternative offsets if we didn't find LP lock
        if not results["lp_locked"] and len(data) > 100:
            alt_lock_offsets = [64, 70, 76, 84, 92, 96, 104]
            for offset in alt_lock_offsets:
                if len(data) >= offset + 8:
                    try:
                        lp_raw_value = int.from_bytes(data[offset:offset+8], "little")
                        if lp_raw_value > 0 and lp_raw_value < 1e12:  # Sanity check
                            results["lp_locked"] = True
                            break
                    except Exception:
                        continue
                
        return results

class SolanaTransactionMonitor:
    """Monitor Solana transactions for confirmation"""
    
    def __init__(self, rpc_manager):
        self.rpc_manager = rpc_manager
        self.confirmed_txs = set()  # Cache of confirmed transactions
        
    async def check_transaction_confirmed(self, tx_signature: str, max_attempts=3) -> bool:
        """
        Check if a transaction has been confirmed
        Returns True if confirmed, False otherwise
        """
        # Fast path for already confirmed transactions
        if tx_signature in self.confirmed_txs:
            return True
            
        # Try multiple RPC endpoints in case of failure
        for attempt in range(max_attempts):
            try:
                # Get current RPC endpoint with rate limiting
                rpc_url = self.rpc_manager.get_current_rpc()
                
                # Build RPC request
                headers = self.rpc_manager.get_headers()
                payload = {
                    "jsonrpc": "2.0",
                    "id": 1,
                    "method": "getSignatureStatuses",
                    "params": [[tx_signature], {"searchTransactionHistory": True}]
                }
                
                # Make request
                async with aiohttp.ClientSession() as session:
                    async with session.post(rpc_url, json=payload, headers=headers) as response:
                        data = await response.json()
                        
                        # Check for rate limiting
                        if "error" in data and "429" in str(data.get("error")):
                            self.rpc_manager.handle_rate_limit(rpc_url)
                            # Try again with different RPC if not last attempt
                            if attempt < max_attempts - 1:
                                continue
                            return False
                        
                        # Check if transaction is confirmed
                        if "result" in data and data["result"]["value"] and len(data["result"]["value"]) > 0:
                            status = data["result"]["value"][0]
                            if status is not None and status.get("confirmationStatus") in ["confirmed", "finalized"]:
                                # Cache this confirmed transaction
                                self.confirmed_txs.add(tx_signature)
                                return True
                                
                        # If we got a valid response but tx is not confirmed, break early
                        break
                
            except Exception as e:
                logger.error(f"Error checking transaction confirmation (attempt {attempt+1}): {e}")
                # Only rotate endpoints if it's a connection error
                if "connection" in str(e).lower():
                    self.rpc_manager.rotate_endpoints()
                # Continue to next attempt
                
        return False

class EnhancedMempoolAnalyzer(AbstractAsyncContextManager):
    """Enhanced mempool analyzer with proper async context manager"""
    
    def __init__(self, trader, rpc_manager):
        self.trader = trader
        self.rpc_manager = rpc_manager
        self.is_running = False
        self.recent_txs = deque(maxlen=1000)  # Store recent transactions
        
    async def __aenter__(self):
        await self.initialize()
        return self
        
    async def __aexit__(self, exc_type, exc_val, exc_tb):
        await self.cleanup()
        
    async def initialize(self):
        """Initialize the mempool analyzer"""
        self.is_running = True
        logger.info("Mempool analyzer initialized")
        return self
        
    async def analyze_transaction(self, tx_data):
        """Analyze transaction for MEV opportunities"""
        if not tx_data or "params" not in tx_data:
            return None
            
        try:
            # Extract transaction signature
            signature = tx_data["params"]["result"]["value"].get("signature", "")
            
            # Skip if already processed
            if signature in self.recent_txs:
                return None
                
            # Add to processed list
            self.recent_txs.append(signature)
            
            # Extract logs
            logs = tx_data["params"]["result"]["value"].get("logs", [])
            if not logs:
                return None
                
            # Look for Raydium program
            raydium_program = CONFIG["RAYDIUM_PROGRAM_ID"]
            if not any(raydium_program in log for log in logs):
                return None
                
            # Look for ray_log entries
            ray_log_found = False
            for log in logs:
                if "ray_log:" in log:
                    ray_log_found = True
                    break
                    
            if not ray_log_found:
                return None
                
            # Return the transaction data for further processing
            return {
                "signature": signature,
                "logs": logs,
                "timestamp": time.time()
            }
            
        except Exception as e:
            logger.error(f"Error in transaction analysis: {e}")
            return None
        
    async def cleanup(self):
        """Cleanup resources"""
        self.is_running = False
        logger.info("Mempool analyzer stopped")

class RaydiumMonitor(AbstractAsyncContextManager):
    """Raydium price monitor with proper async context manager"""
    
    def __init__(self, trader, rpc_manager):
        self.trader = trader
        self.rpc_manager = rpc_manager
        self.is_running = False
        self.pool_prices = {}
        self.last_update = {}
        
    async def __aenter__(self):
        await self.start_monitoring()
        return self
        
    async def __aexit__(self, exc_type, exc_val, exc_tb):
        await self.cleanup()
        
    async def start_monitoring(self):
        """Start price monitoring"""
        self.is_running = True
        logger.info("Raydium price monitoring started")
        return self
        
    async def get_pool_price(self, pool_address, force_update=False):
        """Get current price from a pool with caching"""
        # Check cache first
        if not force_update and pool_address in self.pool_prices:
            last_update = self.last_update.get(pool_address, 0)
            if time.time() - last_update < 60:  # Cache for 60 seconds
                return self.pool_prices[pool_address]
        
        try:
            rpc_url = self.rpc_manager.get_current_rpc()
            
            # Get pool account data
            async with aiohttp.ClientSession() as session:
                async with session.post(
                    rpc_url,
                    json={
                        "jsonrpc": "2.0",
                        "id": 1,
                        "method": "getAccountInfo",
                        "params": [
                            pool_address,
                            {"encoding": "base64"}
                        ]
                    },
                    headers=self.rpc_manager.get_headers()
                ) as response:
                    data = await response.json()
                    
                    # Check for rate limiting
                    if "error" in data and "429" in str(data.get("error")):
                        self.rpc_manager.handle_rate_limit(rpc_url)
                        return await self.get_pool_price(pool_address, force_update)
                    
                    if "result" in data and data["result"] and "value" in data["result"]:
                        value = data["result"]["value"]
                        if "data" in value and len(value["data"]) > 0:
                            # Parse pool data to extract price
                            raw_data = base64.b64decode(value["data"][0])
                            
                            # Try to extract price from multiple possible locations
                            price = self.extract_price_from_pool_data(raw_data)
                            
                            if price > 0:
                                # Update cache
                                self.pool_prices[pool_address] = price
                                self.last_update[pool_address] = time.time()
                                return price
            
            # If we have a cached value, return it even if update failed
            if pool_address in self.pool_prices:
                return self.pool_prices[pool_address]
                
            return 0.0
            
        except Exception as e:
            logger.error(f"Error getting pool price for {pool_address}: {e}")
            
            # Return cached value if available
            if pool_address in self.pool_prices:
                return self.pool_prices[pool_address]
                
            return 0.0
    
    def extract_price_from_pool_data(self, data):
        """Extract price from pool binary data with multiple approaches"""
        # Common price offset locations in Raydium pools
        price_offsets = [
            (200, 208),  # Common price location 1
            (208, 216),  # Common price location 2
            (216, 224),  # Common price location 3
            (224, 232),  # Common price location 4
        ]
        
        for start, end in price_offsets:
            if len(data) >= end:
                try:
                    price_bytes = data[start:end]
                    price_raw = int.from_bytes(price_bytes, "little")
                    
                    # Normalize price based on typical scales
                    price = price_raw / 1e9
                    
                    # Sanity check - price should be reasonable
                    if 1e-10 < price < 1e10:
                        return price
                except Exception:
                    continue
        
        # Fallback to reserves method
        try:
            if len(data) >= 300:
                # Try to extract token reserves
                pc_reserve_offset = (128, 136)
                coin_reserve_offset = (136, 144)
                
                if len(data) >= coin_reserve_offset[1]:
                    pc_reserve = int.from_bytes(data[pc_reserve_offset[0]:pc_reserve_offset[1]], "little")
                    coin_reserve = int.from_bytes(data[coin_reserve_offset[0]:coin_reserve_offset[1]], "little")
                    
                    if pc_reserve > 0 and coin_reserve > 0:
                        # Calculate price as ratio of reserves
                        price = pc_reserve / coin_reserve
                        
                        # Normalize by typical decimal factors
                        price = price / 1e3
                        
                        # Sanity check
                        if 1e-10 < price < 1e10:
                            return price
        except Exception:
            pass
            
        return 0.0
        
    async def cleanup(self):
        """Cleanup resources"""
        self.is_running = False
        logger.info("Raydium price monitoring stopped")

class RaydiumMEVTrader(AbstractAsyncContextManager):
    """High-performance MEV trader for Raydium with GPU acceleration"""
    
    def __init__(self):
        # Create RPC manager for endpoint handling
        self.rpc_manager = RPCManager()
        
        # Create thread pool for parallel processing
        self.thread_pool = ThreadPoolExecutor(
            max_workers=CONFIG["THREADS"]
        )
        
        # Initialize trader with keypair
        self.trader = SolanaTrader(
            rpc_url=self.rpc_manager.get_current_rpc(),
            ws_url=self.rpc_manager.get_current_ws(),
            keypair_path=CONFIG["SOLANA_KEYPAIR"],
            compute_limit=CONFIG["COMPUTE_LIMIT"]
        )
        
        # Initialize wallet info
        self.wallet_address = self.trader.get_address()
        
        # Initialize components
        self.token_extractor = RaydiumDataExtractor(
            tensor_size=CONFIG["TENSOR_SIZE"]
        )
        
        # Initialize exit stack for context management
        self.exit_stack = AsyncExitStack()
        
        # State tracking
        self.running = False
        self.active_opportunity = None
        self.processed_txs = set()
        self.processing_txs = set()  # Track transactions being processed to avoid duplicates
        self.valid_tokens = set()
        self.invalid_tokens = set()
        self.last_balance_update = 0
        self.sol_balance = 0
        self.wsol_balance = 0
        self.wsol_account = CONFIG.get("WSOL_TOKEN_ACCOUNT", "")
        self.stats = TradingStats()
        self.balance_lock = asyncio.Lock()
        
        # MEV Config
        self.front_run_amount = CONFIG["FRONT_RUN_AMOUNT"]
        self.min_victim_size = CONFIG["MIN_VICTIM_SIZE"]
        self.max_victim_size = CONFIG["MAX_VICTIM_SIZE"]
        self.min_sol_balance = CONFIG["MIN_SOL_BALANCE"]
        self.min_wsol_balance = CONFIG["MIN_WSOL_BALANCE"]
        self.slippage_percent = CONFIG["SLIPPAGE"]  # In percent (e.g. 20.0 = 20%)
        self.min_profit = CONFIG["MIN_PROFIT"]
        self.wsol_wrap_interval = 30  # Seconds between WSOL wraps
        self.last_wrap_time = 0
        self.simulation_mode = CONFIG["SIMULATION_MODE"]
        
        logger.info(f"Initialized RaydiumMEVTrader with wallet: {self.wallet_address}")
        logger.info(f"Simulation mode: {self.simulation_mode}")
        
        if HAS_TORCH and torch.cuda.is_available():
            gpu_name = torch.cuda.get_device_name()
            gpu_memory = torch.cuda.get_device_properties(0).total_memory / (1024**3)
            logger.info(f"GPU Acceleration enabled: {gpu_name} with {gpu_memory:.1f}GB memory")
            
    async def __aenter__(self):
        await self.initialize()
        return self
        
    async def __aexit__(self, exc_type, exc_val, exc_tb):
        await self.cleanup()
        
    async def initialize(self):
        """Initialize all components"""
        try:
            # Initialize token validator
            self.token_validator = GPUAcceleratedTokenValidator(
                self.trader, 
                self.rpc_manager
            )
            await self.exit_stack.enter_async_context(self.token_validator)
            
            # Initialize advanced components
            self.mempool_analyzer = EnhancedMempoolAnalyzer(self.trader, self.rpc_manager)
            await self.exit_stack.enter_async_context(self.mempool_analyzer)
            
            self.price_monitor = RaydiumMonitor(self.trader, self.rpc_manager)
            await self.exit_stack.enter_async_context(self.price_monitor)
            
            self.tx_monitor = SolanaTransactionMonitor(self.rpc_manager)
            
            # Initial balance check and WSOL account creation
            try:
                # Verify WSOL account exists or create it
                await self.ensure_wsol_account_exists()
                
                # Get initial balances with retry logic
                for attempt in range(3):
                    try:
                        self.sol_balance = self.trader.get_sol_balance()
                        self.wsol_balance = self.trader.get_token_balance(CONFIG["WSOL_ADDRESS"])
                        self.last_balance_update = time.time()
                        
                        self.stats.initial_sol_balance = self.sol_balance
                        self.stats.initial_wsol_balance = self.wsol_balance
                        
                        total_balance = self.sol_balance + self.wsol_balance
                        logger.info(f"Initial wallet balance: {total_balance:.4f} SOL")
                        break
                    except Exception as e:
                        if "429" in str(e):
                            # Handle rate limiting
                            self.rpc_manager.handle_rate_limit(self.rpc_manager.get_current_rpc())
                            # Update trader with new RPC
                            if attempt < 2:  # Don't update on last attempt
                                self.trader = SolanaTrader(
                                    rpc_url=self.rpc_manager.get_current_rpc(),
                                    ws_url=self.rpc_manager.get_current_ws(),
                                    keypair_path=CONFIG["SOLANA_KEYPAIR"],
                                    compute_limit=CONFIG["COMPUTE_LIMIT"]
                                )
                                await asyncio.sleep(0.5)
                        else:
                            logger.error(f"Error getting initial balance: {e}")
                            break
            except Exception as e:
                logger.error(f"Error setting up initial account state: {e}")
            
            # Set running flag
            self.running = True
            logger.info("MEV trader initialization complete")
            return self
        except Exception as e:
            logger.error(f"MEV trader initialization failed: {e}")
            await self.cleanup()
            raise
            
    async def run(self):
        """Run the MEV trader"""
        self.running = True
        
        # Setup signal handlers
        for sig in (signal.SIGINT, signal.SIGTERM):
            signal.signal(sig, self._handle_exit)
            
        logger.info("Starting Raydium MEV Trader...")
        
        # Start tasks
        tasks = [
            asyncio.create_task(self.monitor_mempool()),
            asyncio.create_task(self.monitor_balances())
        ]
        
        # Keep the bot running
        while self.running:
            await asyncio.sleep(0.1)
            await self.check_active_opportunity()
        
        # Safe shutdown
        await self.safe_shutdown()
        self.print_stats()
        
        # Cancel tasks
        for task in tasks:
            task.cancel()
            
        try:
            await asyncio.gather(*tasks, return_exceptions=True)
        except asyncio.CancelledError:
            logger.info("Tasks cancelled successfully")
            
    async def cleanup(self):
        """Clean up resources"""
        self.running = False
        await self.exit_stack.aclose()
        logger.info("Trading system resources cleaned up")
    
    def _handle_exit(self, sig, frame):
        """Handle exit signals gracefully"""
        if not self.running:
            return
            
        logger.info("Shutdown signal received, cleaning up...")
        self.running = False
    
    async def ensure_wsol_account_exists(self):
        """Ensure WSOL token account exists, creating it if needed"""
        wsol_address = CONFIG["WSOL_ADDRESS"]
        
        # Check if WSOL account is provided in env
        if not self.wsol_account:
            try:
                # Get the default WSOL token account from trader
                self.wsol_account = self.trader.get_associated_token_address(
                    self.wallet_address, wsol_address
                )
                logger.info(f"Using calculated WSOL account: {self.wsol_account}")
            except Exception as e:
                logger.error(f"Error getting WSOL account: {e}")
                return
        
        # Check if the account already exists
        wsol_balance = -1
        try:
            wsol_balance = self.trader.get_token_balance(wsol_address)
        except Exception:
            logger.info("WSOL account does not exist, creating it...")
            
        # If balance check failed, create the WSOL account
        if wsol_balance < 0:
            try:
                # Create the token account
                result = self.trader.create_token_account_if_needed(wsol_address)
                if result:
                    logger.info(f"Successfully created WSOL account: {self.wsol_account}")
                    # Wrap a small amount to initialize the account
                    if self.sol_balance > 0.01:
                        logger.info("Wrapping 0.01 SOL to initialize WSOL account")
                        wrap_result = self.trader.wrap_sol(0.01)
                        if wrap_result:
                            logger.info("Successfully initialized WSOL account")
                            self.last_wrap_time = time.time()
            except Exception as e:
                logger.error(f"Error creating WSOL account: {e}")
    
    async def monitor_mempool(self):
        """Monitor Raydium program logs for MEV opportunities"""
        logger.info(f"Starting mempool monitoring via WebSocket to {self.rpc_manager.get_current_ws()}")
        
        retry_count = 0
        backoff = 1.0
        max_retries = 5
        
        while self.running and retry_count < max_retries:
            try:
                # Setup WebSocket connection
                headers = self.rpc_manager.get_headers()
                
                # Create a custom SSL context that doesn't verify
                ssl_context = ssl.create_default_context()
                ssl_context.check_hostname = False
                ssl_context.verify_mode = ssl.CERT_NONE
                
                ws_url = self.rpc_manager.get_current_ws()
                
                # Connect to WebSocket
                async with websockets.connect(
                    ws_url,
                    extra_headers=headers,
                    ping_interval=30,
                    ping_timeout=20,
                    close_timeout=10,
                    max_size=10 * 1024 * 1024,
                    ssl=ssl_context
                ) as ws:
                    self.stats.ws_connections += 1
                    logger.info(f"Connected to WebSocket: {ws_url}")
                    
                    # Reset retry count on successful connection
                    retry_count = 0
                    backoff = 1.0
                    
                    # Subscribe to Raydium program logs
                    await ws.send(json.dumps({
                        "jsonrpc": "2.0", 
                        "id": 1,
                        "method": "logsSubscribe",
                        "params": [
                            {"mentions": [CONFIG["RAYDIUM_PROGRAM_ID"]]},
                            {"commitment": "processed"}  # Use processed for fastest notification
                        ]
                    }))
                    
                    # Wait for logs subscription confirmation
                    logs_response = await ws.recv()
                    self.stats.ws_messages_received += 1
                    logs_data = json.loads(logs_response)
                    
                    if "result" not in logs_data:
                        error_msg = logs_data.get("error", {}).get("message", "Unknown error")
                        logger.error(f"Failed to subscribe to logs: {error_msg}")
                        
                        # Check for rate limiting
                        if "429" in str(error_msg) or "too many requests" in str(error_msg).lower():
                            self.rpc_manager.handle_rate_limit(ws_url)
                            
                        await asyncio.sleep(backoff)
                        backoff = min(30, backoff * 1.5)
                        retry_count += 1
                        continue
                    
                    logs_subscription_id = logs_data["result"]
                    logger.info(f"Successfully subscribed to Raydium logs (ID: {logs_subscription_id})")
                    
                    # Subscribe to account updates for balance tracking (optional)
                    await ws.send(json.dumps({
                        "jsonrpc": "2.0", 
                        "id": 2,
                        "method": "accountSubscribe",
                        "params": [
                            self.wallet_address,
                            {"commitment": "confirmed", "encoding": "jsonParsed"}
                        ]
                    }))
                    
                    # Wait for account subscription confirmation
                    account_response = await ws.recv()
                    self.stats.ws_messages_received += 1
                    account_data = json.loads(account_response)
                    
                    if "result" in account_data:
                        account_subscription_id = account_data["result"]
                        logger.info(f"Successfully subscribed to wallet account (ID: {account_subscription_id})")
                    else:
                        logger.warning(f"Failed to subscribe to wallet account: {account_data}")
                    
                    # Set up timing variables
                    last_ping_time = time.time()
                    last_heartbeat = time.time()
                    
                    # Process WebSocket messages
                    while self.running:
                        try:
                            # Set shorter timeout to allow for periodic checks
                            message = await asyncio.wait_for(ws.recv(), timeout=5)
                            self.stats.ws_messages_received += 1
                            
                            # Reset heartbeat timer on each message
                            last_heartbeat = time.time()
                            
                            data = json.loads(message)
                            
                            # Handle log notifications (Raydium transactions)
                            if ("method" in data and data["method"] == "logsNotification" and 
                                  "params" in data and "subscription" in data["params"] and 
                                  data["params"]["subscription"] == logs_subscription_id):
                                await self.process_logs_notification(data)
                                
                            # Handle account notifications (balance updates)
                            elif ("method" in data and data["method"] == "accountNotification" and 
                                  "params" in data and "subscription" in data["params"]):
                                await self.update_wallet_balance()
                            
                        except asyncio.TimeoutError:
                            # Check if heartbeat needed
                            current_time = time.time()
                            time_since_last_message = current_time - last_heartbeat
                            
                            # If no messages for twice the heartbeat interval, send ping
                            if time_since_last_message > 20:
                                logger.info(f"No messages for {time_since_last_message:.1f}s, sending heartbeat ping")
                                try:
                                    pong = await ws.ping()
                                    await pong  # Wait for pong response
                                    last_heartbeat = current_time
                                except Exception as e:
                                    logger.warning(f"Heartbeat ping failed: {e}")
                                    # Connection likely dead, break to reconnect
                                    break
                            
                            # Regular checks on timeout
                            await self.check_active_opportunity()
                            
                            # Send regular ping if needed
                            if current_time - last_ping_time > 30:
                                try:
                                    await ws.ping()
                                    last_ping_time = current_time
                                except Exception as e:
                                    logger.warning(f"Regular ping failed: {e}")
                                
                        except websockets.exceptions.ConnectionClosed as e:
                            self.stats.ws_errors += 1
                            logger.warning(f"WebSocket connection closed ({e.code}): {e.reason}, reconnecting...")
                            break
                            
                        except json.JSONDecodeError:
                            self.stats.ws_errors += 1
                            logger.warning("Received invalid JSON, ignoring message")
                            continue
                            
                        except Exception as e:
                            self.stats.ws_errors += 1
                            logger.error(f"Error processing message: {e}")
                            logger.error(traceback.format_exc())
                            
                # Connection closed, now reconnect
                logger.info("WebSocket connection ended, reconnecting...")
                self#!/usr/bin/env python3
"""
Quantum Raydium MEV Trader - Production Implementation
------------------------------------------------------
High-performance MEV trader for Raydium with GPU acceleration,
microsecond-level latency, comprehensive security verification,
and automated trading execution.
"""

import asyncio
import base58
import base64
import json
import logging
import os
import signal
import sys
import time
import traceback
from concurrent.futures import ThreadPoolExecutor
from dataclasses import dataclass, field
from datetime import datetime
from pathlib import Path
from typing import Dict, List, Optional, Set, Tuple, Any, Deque
import re
import ssl
import aiohttp
import websockets
from dotenv import load_dotenv
from contextlib import AsyncExitStack, AbstractAsyncContextManager
from collections import deque

# Import GPU acceleration
try:
    import torch
    import numpy as np
    HAS_TORCH = True
except ImportError:
    HAS_TORCH = False
    logging.warning("PyTorch not installed. Running without GPU acceleration.")

# Import Rust trading core - this is the critical component that executes trades
try:
    from solana_rust_bot import SolanaTrader
except ImportError:
    logging.critical("Failed to import SolanaTrader. Make sure solana_rust_bot is properly installed.")
    sys.exit(1)

# Fix for Windows event loop
if sys.platform == 'win32':
    asyncio.set_event_loop_policy(asyncio.WindowsSelectorEventLoopPolicy())

# Configure logging
os.makedirs("logs", exist_ok=True)
timestamp = datetime.now().strftime('%Y%m%d_%H%M%S')
logging.basicConfig(
    level=logging.INFO,
    format="%(asctime)s | %(levelname)s | %(message)s",
    handlers=[
        logging.FileHandler(f"logs/solana_mev_{timestamp}.log"),
        logging.StreamHandler()
    ]
)
logger = logging.getLogger(__name__)

# Constants
LAMPORTS_PER_SOL = 1_000_000_000

# Load environment variables
def load_env_config():
    """Load configuration from .env file or environment variables"""
    config = {}
    
    # Try to load from .env file
    load_dotenv()
    
    # Define all expected config keys with defaults
    config_keys = {
        # RPC and API settings
        "RPC_URL": "https://winny-rychu7-fast-mainnet.helius-rpc.com",
        "WS_URL": "wss://winny-rychu7-fast-mainnet.helius-rpc.com",
        "API_KEY": "",
        
        # Wallet settings
        "SOLANA_KEYPAIR": "keypair.bin",
        "SOLANA_PUBLIC_KEY": "",
        "WSOL_TOKEN_ACCOUNT": "",
        
        # Program IDs
        "RAYDIUM_PROGRAM_ID": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8",
        "SERUM_PROGRAM_ID": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin",
        "TOKEN_PROGRAM_ID": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA",
        "SYSTEM_PROGRAM_ID": "11111111111111111111111111111111",
        "ASSOCIATED_TOKEN_PROGRAM_ID": "ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL",
        "WSOL_ADDRESS": "So11111111111111111111111111111111111111112",
        
        # Transaction settings
        "COMPUTE_LIMIT": "50000",
        "PRIORITY_FEE": "750000",
        "SKIP_PREFLIGHT": "true",
        "MAX_RETRIES": "5",
        "SLIPPAGE": "20.0",
        
        # MEV settings
        "FRONT_RUN_AMOUNT": "0.05",
        "MIN_VICTIM_SIZE": "5.0",
        "MAX_VICTIM_SIZE": "320.0",
        "MIN_PROFIT": "0.001",
        "MIN_TRADE_INTERVAL": "0.2",
        "MAX_ACTIVE_MEVS": "1",
        "VICTIM_CONFIRM_TIMEOUT": "15",
        
        # Balance safety
        "MIN_SOL_BALANCE": "0.03",
        "MIN_WSOL_BALANCE": "0.02",
        
        # Performance settings
        "GPU_MEMORY_FRACTION": "0.95",
        "TENSOR_SIZE": "176",
        "WARMUP_CYCLES": "2500",
        "STREAM_PRIORITY": "-3",
        "USE_AMP": "true",
        "ALLOW_TF32": "true",
        "CUDA_TENSOR_CORES": "true",
        "COMPUTE_STREAMS": "1",
        "BATCH_SIZE": "512",
        "THREADS": "48",
        
        # System settings
        "LOG_LEVEL": "INFO",
        "SIMULATION_MODE": "true",
        
        # RPC Settings for rate limiting
        "RPC_REQUEST_DELAY": "0.05",
        "MAX_REQUESTS_PER_SECOND": "10",
        "RPC_COOLDOWN_TIME": "2.0",
        "RPC_ROTATION_THRESHOLD": "3"
    }
    
    # Fill config with environment variables or defaults
    for key, default in config_keys.items():
        value = os.getenv(key, default)
        
        # Convert to appropriate type
        if value.lower() in ["true", "yes", "1"]:
            config[key] = True
        elif value.lower() in ["false", "no", "0"]:
            config[key] = False
        elif value.replace(".", "", 1).isdigit():
            if "." in value:
                config[key] = float(value)
            else:
                config[key] = int(value)
        else:
            config[key] = value
            
    logger.info(f"Loaded configuration with {len(config)} settings")
    return config

# Load configuration
CONFIG = load_env_config()

@dataclass
class TokenSecurity:
    mint_authority_revoked: bool = False
    lp_locked: bool = False
    has_exit_liquidity: bool = False
    exit_liquidity_sol: float = 0.0
    pool_address: str = ""
    token_mint: str = ""
    valid: bool = False
    exists: bool = False  # Added field to track if token account exists
    
@dataclass
class TradingStats:
    transactions_seen: int = 0
    raydium_swaps_found: int = 0
    viable_opportunities: int = 0
    trades_attempted: int = 0
    trades_completed: int = 0
    failed_front_runs: int = 0
    failed_back_runs: int = 0
    total_profit: float = 0.0
    total_loss: float = 0.0
    start_time: float = field(default_factory=time.time)
    token_profits: Dict[str, float] = field(default_factory=dict)
    victim_confirmed_count: int = 0
    victim_missed_count: int = 0
    initial_sol_balance: float = 0.0
    initial_wsol_balance: float = 0.0
    rpc_calls: int = 0
    cached_tokens_used: int = 0
    ws_connections: int = 0
    ws_messages_received: int = 0
    ws_errors: int = 0
    ws_reconnects: int = 0
    invalid_tokens_count: int = 0
    account_not_found_count: int = 0
    
@dataclass
class TradeOpportunity:
    token_mint: str
    amount_sol: float
    tx_signature: str
    accounts: Dict[str, str]
    front_amount: float
    start_time: float = field(default_factory=time.time)
    front_tx: Optional[str] = None
    back_tx: Optional[str] = None
    status: str = "pending"
    profit: float = 0.0
    victim_confirmed: bool = False
    token_balance: float = 0.0
    token_decimals: int = 9
    start_sol_balance: float = 0.0
    start_wsol_balance: float = 0.0
    end_sol_balance: float = 0.0
    end_wsol_balance: float = 0.0

class RPCManager:
    """Manages RPC endpoints with failover and rate-limiting"""
    
    def __init__(self):
        # Load RPC endpoints
        self.primary_rpc = CONFIG["RPC_URL"]
        self.primary_ws = CONFIG["WS_URL"]
        
        # Backup RPC endpoints
        self.rpc_endpoints = deque([
            self.primary_rpc,
            "https://api.mainnet-beta.solana.com",
            "https://solana-api.projectserum.com",
            "https://rpc.ankr.com/solana"
        ])
        
        # Backup WebSocket endpoints
        self.ws_endpoints = deque([
            self.primary_ws,
            "wss://api.mainnet-beta.solana.com",
            "wss://solana-api.projectserum.com"
        ])
        
        # Rate limiting
        self.rate_limit_counts = {endpoint: 0 for endpoint in self.rpc_endpoints}
        self.last_request_time = 0.0
        self.request_times = deque(maxlen=CONFIG["MAX_REQUESTS_PER_SECOND"])
        self.in_cooldown = False
        self.cooldown_until = 0.0
        
        # Current endpoints
        self.current_rpc = self.primary_rpc
        self.current_ws = self.primary_ws
        
        # API key for Helius
        self.api_key = CONFIG["API_KEY"]
        
        logger.info(f"RPC Manager initialized with primary endpoint: {self.primary_rpc}")
    
    def get_current_rpc(self):
        """Get current RPC endpoint with rate limiting protection"""
        if self.in_cooldown and time.time() < self.cooldown_until:
            time.sleep(0.05)  # Small sleep to avoid busy waiting
            
        now = time.time()
        elapsed = now - self.last_request_time
        
        # Enforce minimum delay between requests
        if elapsed < CONFIG["RPC_REQUEST_DELAY"]:
            time.sleep(CONFIG["RPC_REQUEST_DELAY"] - elapsed)
        
        # Track request time
        self.request_times.append(time.time())
        self.last_request_time = time.time()
        
        # Check rate limiting
        if len(self.request_times) >= CONFIG["MAX_REQUESTS_PER_SECOND"]:
            window = time.time() - self.request_times[0]
            if window < 1.0:
                sleep_time = 1.0 - window
                time.sleep(sleep_time)
        
        return self.current_rpc
    
    def get_current_ws(self):
        """Get current WebSocket endpoint"""
        return self.current_ws
    
    def handle_rate_limit(self, endpoint):
        """Handle rate limit response from endpoint"""
        self.rate_limit_counts[endpoint] += 1
        
        # Enter cooldown
        self.in_cooldown = True
        self.cooldown_until = time.time() + CONFIG["RPC_COOLDOWN_TIME"]
        
        # If we've hit threshold, rotate endpoints
        if self.rate_limit_counts[endpoint] >= CONFIG["RPC_ROTATION_THRESHOLD"]:
            self.rotate_endpoints()
            
        return self.current_rpc
    
    def rotate_endpoints(self):
        """Rotate to next endpoint"""
        # Rotate RPC endpoints
        self.rpc_endpoints.rotate(1)
        self.current_rpc = self.rpc_endpoints[0]
        
        # Rotate WebSocket endpoints
        self.ws_endpoints.rotate(1)
        self.current_ws = self.ws_endpoints[0]
        
        # Reset rate limiting
        self.rate_limit_counts[self.current_rpc] = 0
        self.request_times.clear()
        self.in_cooldown = False
        
        logger.info(f"Rotated to new endpoints - RPC: {self.current_rpc}, WS: {self.current_ws}")
    
    def get_headers(self):
        """Get headers with API key if available"""
        headers = {
            "Content-Type": "application/json",
        }
        if self.api_key:
            headers["api-key"] = self.api_key
        return headers

class RaydiumDataExtractor:
    """Extract and validate token data from Raydium pools and transaction logs"""

    def __init__(self, tensor_size=176):
        self.tensor_size = tensor_size
        
        # Initialize GPU acceleration if available
        if HAS_TORCH and torch.cuda.is_available():
            self.device = torch.device('cuda')
            # Setup CUDA for maximum performance
            torch.backends.cuda.matmul.allow_tf32 = CONFIG["ALLOW_TF32"]
            torch.backends.cudnn.benchmark = True
            torch.backends.cudnn.deterministic = False
            # Create stream for parallel processing
            self.stream = torch.cuda.Stream(priority=CONFIG["STREAM_PRIORITY"])
            self.warmup_gpu()
            logger.info(f"GPU acceleration enabled: {torch.cuda.get_device_name()}")
        else:
            self.device = None
            logger.info("Running without GPU acceleration")
            
        # Program IDs to exclude when identifying token mints
        self.program_ids = {
            CONFIG["RAYDIUM_PROGRAM_ID"],
            CONFIG["TOKEN_PROGRAM_ID"],
            CONFIG["SERUM_PROGRAM_ID"],
            CONFIG["SYSTEM_PROGRAM_ID"],
            CONFIG["WSOL_ADDRESS"],
            CONFIG["ASSOCIATED_TOKEN_PROGRAM_ID"],
        }
        
    def warmup_gpu(self):
        """Warm up GPU to ensure consistent performance"""
        if not HAS_TORCH or not torch.cuda.is_available():
            return
            
        # Create tensors for warmup
        with torch.cuda.stream(self.stream):
            warmup_tensor = torch.randn(self.tensor_size, device=self.device)
            for _ in range(CONFIG["WARMUP_CYCLES"]):  # Warm up cycles from your benchmarks
                result = torch.matmul(warmup_tensor, warmup_tensor)
                
        # Synchronize to ensure warmup is complete
        torch.cuda.synchronize()
        logger.info("GPU warmup completed")
        
    def decode_ray_log(self, log_str):
        """Decode Raydium ray_log with optimized parsing"""
        if "ray_log:" not in log_str:
            return None
            
        try:
            ray_log_part = log_str.split("ray_log:")[1].strip()
            
            # Multi-strategy decoding with validation
            raw_data = None
            decode_attempts = [
                lambda x: base64.b64decode(x),  # Standard
                lambda x: base64.b64decode(x + "=" * (4 - len(x) % 4) % 4),  # Add padding
                lambda x: base64.b64decode(x.replace("-", "+").replace("_", "/")),  # URL-safe
                lambda x: base64.b64decode(x.replace("-", "+").replace("_", "/") + "=" * (4 - len(x.replace("-", "+").replace("_", "/")) % 4) % 4)  # URL-safe with padding
            ]
            
            # Try all decoding strategies
            for decode_func in decode_attempts:
                try:
                    raw_data = decode_func(ray_log_part)
                    if raw_data and len(raw_data) >= 9:
                        break
                except Exception:
                    continue
                    
            if not raw_data or len(raw_data) < 9:
                return None
            
            # First byte is instruction type
            instruction_type = raw_data[0]
            
            # Next 8 bytes are the amount in little-endian
            amount_bytes = raw_data[1:9]
            amount = int.from_bytes(amount_bytes, byteorder="little") / LAMPORTS_PER_SOL
            
            # Based on instruction type, determine if buy or sell
            is_buy = instruction_type in [3, 9]  # 3 & 9 are buy instructions
            is_sell = instruction_type == 11  # 11 is sell instruction
            
            # Extract pubkeys if available
            pubkeys = []
            if len(raw_data) > 9:
                account_data = raw_data[9:]
                
                for i in range(0, len(account_data) - 31, 32):
                    try:
                        pubkey_bytes = account_data[i:i+32]
                        # Skip zero or all-one pubkeys
                        if all(b == 0 for b in pubkey_bytes) or all(b == 255 for b in pubkey_bytes):
                            continue
                            
                        pubkey = base58.b58encode(pubkey_bytes).decode('utf-8')
                        if self.is_valid_pubkey(pubkey):
                            pubkeys.append(pubkey)
                    except Exception:
                        continue
            
            return {
                "instruction_type": instruction_type,
                "amount": amount,
                "is_buy": is_buy,
                "is_sell": is_sell,
                "pubkeys": pubkeys,
                "raw_data": raw_data
            }
            
        except Exception as e:
            logger.error(f"Error decoding ray_log: {e}")
            return None
            
    def is_valid_pubkey(self, address):
        """Validate a Solana address format"""
        if not address or len(address) < 32 or len(address) > 44:
            return False
            
        try:
            # Check for concatenated addresses (e.g. 11111111... + another address)
            if address.startswith("11111111") and len(address) > 8:
                return False
                
            # Make sure we decode to 32 bytes exactly
            decoded = base58.b58decode(address)
            return len(decoded) == 32
        except Exception:
            return False
    
    def extract_token_mint(self, logs):
        """Extract token mint from logs with multi-pass approach and better validation"""
        # Method 1: Extract from Transfer logs targeting Mint Authority
        token_program_id = CONFIG["TOKEN_PROGRAM_ID"]
        token_candidates = []
        
        for log in logs:
            if token_program_id in log and "Instruction: Transfer" in log:
                # Look for the next few logs for pubkeys
                token_index = logs.index(log)
                for i in range(token_index, min(token_index + 5, len(logs))):
                    address_pattern = r'\b[1-9A-HJ-NP-Za-km-z]{32,44}\b'
                    matches = re.findall(address_pattern, logs[i])
                    for match in matches:
                        if match not in self.program_ids and self.is_valid_pubkey(match):
                            token_candidates.append(match)
        
        # Method 2: Extract from ray_log pubkeys
        for log in logs:
            if "ray_log:" in log:
                ray_data = self.decode_ray_log(log)
                if ray_data and ray_data["pubkeys"]:
                    for pubkey in ray_data["pubkeys"]:
                        # Skip known program IDs
                        if pubkey not in self.program_ids and self.is_valid_pubkey(pubkey):
                            token_candidates.append(pubkey)
        
        # Method 3: Extract from MintTo or related token instructions
        for log in logs:
            if token_program_id in log and "Program data:" in log and "MintTo" in log:
                address_pattern = r'\b[1-9A-HJ-NP-Za-km-z]{32,44}\b'
                matches = re.findall(address_pattern, log)
                for match in matches:
                    if match not in self.program_ids and self.is_valid_pubkey(match):
                        token_candidates.append(match)
        
        # Count occurrences and pick the most likely token mint
        if token_candidates:
            # Filter out common program IDs and system accounts
            filtered_candidates = [c for c in token_candidates if not c.startswith("1111")]
            
            if filtered_candidates:
                # Count occurrences and pick the most frequent
                token_counts = {}
                for token in filtered_candidates:
                    token_counts[token] = token_counts.get(token, 0) + 1
                
                # Sort by frequency and return the most common
                sorted_tokens = sorted(token_counts.items(), key=lambda x: x[1], reverse=True)
                return sorted_tokens[0][0]
        
        return None
        
    def extract_accounts(self, logs):
        """Extract account information from logs"""
        accounts = {
            "token_program_id": CONFIG["TOKEN_PROGRAM_ID"],
            "serum_program_id": CONFIG["SERUM_PROGRAM_ID"],
            "raydium_program_id": CONFIG["RAYDIUM_PROGRAM_ID"],
            "system_program_id": CONFIG["SYSTEM_PROGRAM_ID"]
        }
        
        # Account field mapping from logs
        account_fields = {
            "amm id": "amm_id",
            "authority": "amm_authority",
            "open orders": "amm_open_orders",
            "target orders": "amm_target_orders",
            "pool coin": "pool_coin_token_account",
            "pool pc": "pool_pc_token_account",
            "serum market": "serum_market",
            "serum bids": "serum_bids",
            "serum asks": "serum_asks",
            "event queue": "serum_event_queue",
            "coin vault": "serum_coin_vault",
            "pc vault": "serum_pc_vault",
            "vault signer": "serum_vault_signer"
        }
        
        # Extract accounts from logs
        for log in logs:
            if ":" not in log:
                continue
                
            # Check for account patterns
            for pattern, field_name in account_fields.items():
                if pattern in log.lower():
                    parts = log.split(":")
                    if len(parts) < 2:
                        continue
                        
                    # Extract pubkey after pattern
                    address_part = parts[1].strip()
                    address_pattern = r'\b[1-9A-HJ-NP-Za-km-z]{32,44}\b'
                    matches = re.findall(address_pattern, address_part)
                    
                    for match in matches:
                        if self.is_valid_pubkey(match):
                            accounts[field_name] = match
                            break
        
        # Extract AMM ID from ray_log as fallback
        if "amm_id" not in accounts:
            for log in logs:
                if "ray_log:" in log:
                    ray_data = self.decode_ray_log(log)
                    if ray_data and ray_data["pubkeys"] and len(ray_data["pubkeys"]) >= 5:
                        accounts["amm_id"] = ray_data["pubkeys"][0]
                        break
        
        return accounts

class GPUAcceleratedTokenValidator(AbstractAsyncContextManager):
    """Token validator with GPU acceleration and enhanced security checks"""
    
    def __init__(self, trader, rpc_manager):
        self.trader = trader
        self.rpc_manager = rpc_manager
        self.security_cache = {}
        
        # Security profile for checking binary layout
        self.security_profiles = [
            {"mint_authority": 72, "lp_lock": 88, "liquidity": (128, 136)},
            {"mint_authority": 70, "lp_lock": 80, "liquidity": (128, 136)},
            {"mint_authority": 64, "lp_lock": 100, "liquidity": (128, 136)},
        ]
        
        # Minimum exit liquidity in SOL
        self.min_exit_liquidity = float(CONFIG.get("MIN_EXIT_LIQUIDITY_SOL", 10.0))
        self.security_cache_seconds = int(CONFIG.get("SECURITY_CACHE_SECONDS", 600))
    
    async def __aenter__(self):
        return self
        
    async def __aexit__(self, exc_type, exc_val, exc_tb):
        pass
        
    async def verify_token_exists(self, token_mint):
        """Verify a token mint address exists before validation"""
        try:
            rpc_url = self.rpc_manager.get_current_rpc()
            
            async with aiohttp.ClientSession() as session:
                async with session.post(
                    rpc_url,
                    json={
                        "jsonrpc": "2.0",
                        "id": 1,
                        "method": "getAccountInfo",
                        "params": [
                            token_mint,
                            {"encoding": "jsonParsed"}
                        ]
                    },
                    headers=self.rpc_manager.get_headers()
                ) as response:
                    data = await response.json()
                    
                    if "result" in data and data["result"] and data["result"]["value"]:
                        # Check if it's actually a token mint by looking for mint info
                        account_data = data["result"]["value"]
                        if "data" in account_data and "parsed" in account_data["data"]:
                            parsed = account_data["data"]["parsed"]
                            if "type" in parsed and parsed["type"] == "mint":
                                return True
                    
                    # Check for rate limiting
                    if "error" in data and "429" in str(data.get("error")):
                        self.rpc_manager.handle_rate_limit(rpc_url)
                        return await self.verify_token_exists(token_mint)
            
            return False
        except Exception as e:
            logger.error(f"Error verifying token {token_mint[:8]} exists: {e}")
            return False
            
    async def validate_token_security(self, token_mint):
        """Validate token security features comprehensively with existence check"""
        # Create security result
        security = TokenSecurity(token_mint=token_mint)
        
        # Skip WSOL - always safe
        if token_mint == CONFIG["WSOL_ADDRESS"]:
            return TokenSecurity(
                mint_authority_revoked=True,
                lp_locked=True,
                has_exit_liquidity=True,
                exit_liquidity_sol=1000000.0,
                pool_address="NATIVE_SOL",
                token_mint=token_mint,
                valid=True,
                exists=True
            )
        
        # Check cache
        if token_mint in self.security_cache:
            last_check, security = self.security_cache[token_mint]
            if time.time() - last_check < self.security_cache_seconds:
                return security
        
        try:
            # 1. First verify the token actually exists and is a mint
            token_exists = await self.verify_token_exists(token_mint)
            if not token_exists:
                logger.info(f"Token {token_mint[:8]} validation failed: token does not exist or is not a mint")
                security.exists = False
                self.security_cache[token_mint] = (time.time(), security)
                return security
                
            security.exists = True
            
            # 2. Check mint authority
            security.mint_authority_revoked = self.trader.verify_token_safety(token_mint)
            if not security.mint_authority_revoked:
                logger.info(f"Token {token_mint[:8]} validation failed: mint authority not revoked")
                self.security_cache[token_mint] = (time.time(), security)
                return security
            
            # 3. Get pool address and check liquidity with RPC
            pool_address = await self.get_token_pool(token_mint)
            if not pool_address:
                logger.info(f"Token {token_mint[:8]} validation failed: no pool found")
                self.security_cache[token_mint] = (time.time(), security)
                return security
                
            security.pool_address = pool_address
            
            # 4. Get pool data and validate security
            pool_data = await self.get_pool_data(pool_address)
            if not pool_data:
                logger.info(f"Token {token_mint[:8]} validation failed: failed to get pool data")
                self.security_cache[token_mint] = (time.time(), security)
                return security
                
            # 5. Analyze pool binary data
            security_result = self.analyze_pool_security(pool_data)
            security.lp_locked = security_result.get("lp_locked", False)
            security.exit_liquidity_sol = security_result.get("exit_liquidity", 0.0)
            security.has_exit_liquidity = security.exit_liquidity_sol >= self.min_exit_liquidity
            
            # 6. Final validity check
            security.valid = (
                security.mint_authority_revoked and 
                security.lp_locked and 
                security.has_exit_liquidity
            )
            
            # Cache result
            self.security_cache[token_mint] = (time.time(), security)
            
            # Log result
            logger.info(
                f"Token {token_mint[:8]} validation: " +
                f"mint_revoked={security.mint_authority_revoked}, " +
                f"lp_locked={security.lp_locked}, " +
                f"exit_liquidity={security.exit_liquidity_sol:.2f} SOL, " +
                f"valid={security.valid}"
            )
            
            return security
        except Exception as e:
            logger.error(f"Error validating token {token_mint[:8]}: {e}")
            security.exists = False
            self.security_cache[token_mint] = (time.time(), security)
            return security
    
    async def get_token_pool(self, token_mint):
        """Get the pool address for a token"""
        try:
            rpc_url = self.rpc_manager.get_current_rpc()
            
            # Use RPC to find the pool containing this token
            async with aiohttp.ClientSession() as session:
                async with session.post(
                    rpc_url,
                    json={
                        "jsonrpc": "2.0",
                        "id": 1,
                        "method": "getProgramAccounts",
                        "params": [
                            CONFIG["RAYDIUM_PROGRAM_ID"],
                            {
                                "encoding": "base64", will u fix tis script i messed up u see where i didnt do it properly