#!/usr/bin/env python3
"""
Solana Raydium MEV Trading Bot
------------------------------
High-performance front-running and arbitrage bot for Solana's Raydium DEX.
Production-ready implementation with proper error handling and fixed token destinations.

© 2025 - All-in-one implementation
"""
import asyncio
import sys
import os
import time
import signal
import json
import base64
import uuid
import traceback
import argparse
import platform
import logging
import numpy as np
from pathlib import Path
from datetime import datetime
from typing import Dict, Any, Optional, List, Tuple, Union, Set

# Create necessary directories
os.makedirs("logs", exist_ok=True)
os.makedirs("models", exist_ok=True)
os.makedirs("data", exist_ok=True)

# Configure system settings for Windows
if platform.system() == "Windows":
    asyncio.set_event_loop_policy(asyncio.WindowsSelectorEventLoopPolicy())
    
    # Attempt to fix encoding issues on Windows
    try:
        # Set console to UTF-8 mode (Windows)
        os.system("chcp 65001 > NUL")
    except:
        pass

###########################################
# SECTION 1: LOGGING SYSTEM
###########################################

# Check if we're on Windows and if colorama is available
_USE_COLORS = True
try:
    # Windows requires the colorama library for ANSI colors
    if platform.system() == "Windows":
        import colorama
        colorama.init(autoreset=True)
except ImportError:
    # If colorama isn't available on Windows, disable colors
    if platform.system() == "Windows":
        _USE_COLORS = False

# Color definitions
class Colors:
    # Basic colors
    BLACK = "\033[30m" if _USE_COLORS else ""
    RED = "\033[31m" if _USE_COLORS else ""
    GREEN = "\033[32m" if _USE_COLORS else "" 
    YELLOW = "\033[33m" if _USE_COLORS else ""
    BLUE = "\033[34m" if _USE_COLORS else ""
    MAGENTA = "\033[35m" if _USE_COLORS else ""
    CYAN = "\033[36m" if _USE_COLORS else ""
    WHITE = "\033[37m" if _USE_COLORS else ""
    
    # Bright variants
    BRIGHT_RED = "\033[91m" if _USE_COLORS else ""
    BRIGHT_GREEN = "\033[92m" if _USE_COLORS else ""
    BRIGHT_YELLOW = "\033[93m" if _USE_COLORS else ""
    BRIGHT_BLUE = "\033[94m" if _USE_COLORS else ""
    BRIGHT_MAGENTA = "\033[95m" if _USE_COLORS else ""
    BRIGHT_CYAN = "\033[96m" if _USE_COLORS else ""
    BRIGHT_WHITE = "\033[97m" if _USE_COLORS else ""
    
    # Background colors
    BG_RED = "\033[41m" if _USE_COLORS else ""
    BG_GREEN = "\033[42m" if _USE_COLORS else ""
    BG_YELLOW = "\033[43m" if _USE_COLORS else ""
    BG_BLUE = "\033[44m" if _USE_COLORS else ""
    BG_MAGENTA = "\033[45m" if _USE_COLORS else ""
    BG_CYAN = "\033[46m" if _USE_COLORS else ""
    BG_WHITE = "\033[47m" if _USE_COLORS else ""
    
    # Styles
    BOLD = "\033[1m" if _USE_COLORS else ""
    UNDERLINE = "\033[4m" if _USE_COLORS else ""
    ITALIC = "\033[3m" if _USE_COLORS else ""
    
    # Reset
    RESET = "\033[0m" if _USE_COLORS else ""
    
    # Special trading log colors
    SUCCESS = BRIGHT_GREEN
    PROFIT = BRIGHT_GREEN
    LOSS = BRIGHT_RED
    WARNING = BRIGHT_YELLOW
    ERROR = BRIGHT_RED
    CRITICAL = BG_RED + BRIGHT_WHITE
    TRADE = BRIGHT_CYAN
    INFO = BRIGHT_WHITE
    DEBUG = BRIGHT_BLUE

# Custom log levels
TRACE = 5       # Very detailed debugging
NETWORK = 15    # Network operations
SUCCESS = 25    # Successful operations
TRADE = 26      # Trade-related info
PROFIT = 27     # Profit reports
RATE_LIMIT = 28 # Rate limit warnings
RPC = 29        # RPC-related events

# Register custom log levels with logging
logging.addLevelName(TRACE, "TRACE")
logging.addLevelName(NETWORK, "NETWORK")
logging.addLevelName(SUCCESS, "SUCCESS")
logging.addLevelName(TRADE, "TRADE")
logging.addLevelName(PROFIT, "PROFIT")
logging.addLevelName(RATE_LIMIT, "RATE_LIMIT")
logging.addLevelName(RPC, "RPC")

class ColoredFormatter(logging.Formatter):
    """Custom formatter with colored output based on log level with fixed Unicode handling"""
    
    # Map log levels to colors
    COLORS = {
        TRACE: Colors.BRIGHT_BLUE,
        logging.DEBUG: Colors.BLUE,
        NETWORK: Colors.CYAN,
        logging.INFO: Colors.BRIGHT_WHITE,
        SUCCESS: Colors.BRIGHT_GREEN,
        TRADE: Colors.BRIGHT_CYAN,
        PROFIT: Colors.SUCCESS,
        RATE_LIMIT: Colors.BRIGHT_YELLOW,
        RPC: Colors.MAGENTA,
        logging.WARNING: Colors.WARNING,
        logging.ERROR: Colors.ERROR,
        logging.CRITICAL: Colors.CRITICAL
    }
    
    # Map log levels to safe ASCII prefixes (no Unicode)
    PREFIXES = {
        TRACE: "[TRACE]",
        logging.DEBUG: "[DEBUG]",
        NETWORK: "[NETWORK]",
        logging.INFO: "[INFO]",
        SUCCESS: "[SUCCESS]",
        TRADE: "[TRADE]",
        PROFIT: "[PROFIT]",
        RATE_LIMIT: "[RATE]",
        RPC: "[RPC]",
        logging.WARNING: "[WARN]",
        logging.ERROR: "[ERROR]",
        logging.CRITICAL: "[CRITICAL]"
    }
    
    def __init__(self, fmt=None, datefmt=None, style='%', use_colors=True):
        super().__init__(fmt, datefmt, style)
        self.use_colors = use_colors and _USE_COLORS
    
    def format(self, record):
        # Save original format
        orig_format = self._style._fmt
        
        # Add color based on level if enabled
        if self.use_colors:
            color = self.COLORS.get(record.levelno, Colors.WHITE)
            prefix = self.PREFIXES.get(record.levelno, "")
            
            # Modify the format to include color
            self._style._fmt = f"{color}{prefix} {orig_format}{Colors.RESET}"
        
        # Fix Unicode issues in message
        if hasattr(record, 'msg'):
            # Replace problematic arrows with ASCII alternative
            if isinstance(record.msg, str):
                record.msg = record.msg.replace('→', '->').replace('←', '<-')
                
                # Replace other potential problematic Unicode characters
                record.msg = record.msg.replace('✅', '[OK]')
                record.msg = record.msg.replace('❌', '[X]')
                record.msg = record.msg.replace('⚠️', '[!]')
                record.msg = record.msg.replace('ℹ️', '[i]')
                record.msg = record.msg.replace('🔍', '[+]')
                record.msg = record.msg.replace('🚀', '[*]')
                record.msg = record.msg.replace('💰', '[$]')
        
        # Format the record
        result = super().format(record)
        
        # Restore original format
        self._style._fmt = orig_format
        
        return result

class SolanaLogger:
    """Enhanced logger for Solana trading operations with colored output and Unicode fixes"""
    
    def __init__(self, name="solana_trading", level=logging.INFO):
        """Initialize logger with console and file handlers
        
        Args:
            name: Logger name
            level: Default logging level
        """
        self.logger = logging.getLogger(name)
        self.logger.setLevel(level)
        self.logger.propagate = False
        
        # Clear any existing handlers
        if self.logger.handlers:
            self.logger.handlers.clear()
        
        # Create log directory if it doesn't exist
        log_dir = Path("logs")
        if not log_dir.exists():
            log_dir.mkdir(parents=True, exist_ok=True)
        
        # Generate timestamp for log file
        timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
        log_file = log_dir / f"{name}_{timestamp}.log"
        
        # Console handler with colors
        console_handler = logging.StreamHandler(sys.stdout)
        console_handler.setLevel(level)
        
        console_format = ColoredFormatter(
            fmt='%(asctime)s | %(message)s',
            datefmt='%H:%M:%S'
        )
        console_handler.setFormatter(console_format)
        
        # File handler with more detailed info but no colors
        file_handler = logging.FileHandler(log_file, encoding='utf-8')
        file_handler.setLevel(min(level, logging.DEBUG))  # Always log debug+ to file
        
        file_format = logging.Formatter(
            fmt='%(asctime)s | %(levelname)-10s | %(filename)s:%(lineno)d | %(message)s',
            datefmt='%Y-%m-%d %H:%M:%S'
        )
        file_handler.setFormatter(file_format)
        
        # Add handlers to logger
        self.logger.addHandler(console_handler)
        self.logger.addHandler(file_handler)
        
        # Store handlers for separate message handling
        self.console_handler = console_handler
        self.file_handler = file_handler
        
        # Save log path for reference
        self.log_file = log_file
        
        # Log the startup
        self.info(f"Solana Trading Logger initialized: {name}")
        self.info(f"Log file: {log_file}")

    # Standard logging methods
    def trace(self, message, *args, **kwargs):
        """Log trace message (very detailed debug info)"""
        self.logger.log(TRACE, message, *args, **kwargs)
    
    def debug(self, message, *args, **kwargs):
        """Log debug message"""
        self.logger.debug(message, *args, **kwargs)
    
    def network(self, message, *args, **kwargs):
        """Log network message"""
        self.logger.log(NETWORK, message, *args, **kwargs)
    
    def info(self, message, *args, **kwargs):
        """Log info message"""
        self.logger.info(message, *args, **kwargs)
    
    def success(self, message, *args, **kwargs):
        """Log success message"""
        self.logger.log(SUCCESS, message, *args, **kwargs)
    
    def warning(self, message, *args, **kwargs):
        """Log warning message"""
        self.logger.warning(message, *args, **kwargs)
    
    def error(self, message, *args, **kwargs):
        """Log error message"""
        self.logger.error(message, *args, **kwargs)
    
    def critical(self, message, *args, **kwargs):
        """Log critical message"""
        self.logger.critical(message, *args, **kwargs)
    
    # Trading-specific log methods
    def trade(self, message, *args, **kwargs):
        """Log trade execution message"""
        self.logger.log(TRADE, message, *args, **kwargs)
    
    def profit(self, amount: float, token="SOL", **kwargs):
        """Log profit with amount
        
        Args:
            amount: Profit amount (positive or negative)
            token: Token symbol (default: SOL)
        """
        if amount > 0:
            self.logger.log(PROFIT, f"Profit: +{amount:.6f} {token}", **kwargs)
        else:
            # Use error color for losses
            self.logger.log(PROFIT, f"Loss: {amount:.6f} {token}", **kwargs)
    
    def rate_limit(self, message, *args, **kwargs):
        """Log rate limit warning"""
        self.logger.log(RATE_LIMIT, message, *args, **kwargs)
        
    def rpc(self, message, *args, **kwargs):
        """Log RPC related message"""
        self.logger.log(RPC, message, *args, **kwargs)
    
    # Special methods for trades with ASCII indicators (no Unicode)
    def trade_start(self, trade_type, amount, token="SOL"):
        """Log the start of a trade with ASCII indicator"""
        self.trade(f">> Starting {trade_type} trade: {amount:.6f} {token}")
    
    def trade_complete(self, trade_type, amount, token="SOL", tx_hash=None):
        """Log successful trade completion with ASCII indicator"""
        msg = f"[OK] Completed {trade_type} trade: {amount:.6f} {token}"
        if tx_hash:
            msg += f" | TX: {tx_hash}"
        self.trade(msg)
    
    def trade_failed(self, trade_type, reason=None, tx_hash=None):
        """Log failed trade with ASCII indicator"""
        msg = f"[X] Failed {trade_type} trade"
        if reason:
            msg += f": {reason}"
        if tx_hash:
            msg += f" | TX: {tx_hash}"
        self.error(msg)
    
    # Utility methods
    def log_exception(self, exc_info=True, level=logging.ERROR, stack_info=False):
        """Log the current exception with traceback
        
        Args:
            exc_info: Whether to include exception info
            level: Logging level
            stack_info: Whether to include stack info
        """
        self.logger.log(level, "Exception occurred", exc_info=exc_info, stack_info=stack_info)
    
    def section(self, title, char="=", width=60):
        """Create a section header in the log
        
        Args:
            title: Section title
            char: Character to use for the divider
            width: Width of the divider
        """
        divider = char * width
        spacing = char * 3
        self.info(f"\n{divider}\n{spacing} {title} {spacing}\n{divider}")
    
    def change_level(self, level):
        """Change the logging level
        
        Args:
            level: New logging level
        """
        self.logger.setLevel(level)
        self.console_handler.setLevel(level)
        self.info(f"Logging level changed to {logging.getLevelName(level)}")

# Create the default logger instance
logger = SolanaLogger(
    name="raydium_bot",
    level=getattr(logging, os.environ.get("LOG_LEVEL", "INFO"))
)

###########################################
# SECTION 2: CONSTANTS & CONFIGURATION
###########################################

# Try to import the Rust module if available
try:
    import solana_rust_bot
    RUST_AVAILABLE = True
    logger.info("Rust trading core available")
except ImportError:
    RUST_AVAILABLE = False
    logger.warning("solana_rust_bot module not available. Running in simulation mode only.")

# Try to import required libraries
try:
    import aiohttp
    AIOHTTP_AVAILABLE = True
except ImportError:
    AIOHTTP_AVAILABLE = False
    logger.warning("aiohttp not available. Installing...")
    try:
        import subprocess
        subprocess.check_call([sys.executable, "-m", "pip", "install", "aiohttp"])
        import aiohttp
        AIOHTTP_AVAILABLE = True
        logger.info("aiohttp installed successfully")
    except:
        logger.error("Failed to install aiohttp")
        AIOHTTP_AVAILABLE = False

try:
    import websockets
    WEBSOCKETS_AVAILABLE = True
except ImportError:
    WEBSOCKETS_AVAILABLE = False
    logger.warning("websockets not available. Installing...")
    try:
        import subprocess
        subprocess.check_call([sys.executable, "-m", "pip", "install", "websockets"])
        import websockets
        WEBSOCKETS_AVAILABLE = True
        logger.info("websockets installed successfully")
    except:
        logger.error("Failed to install websockets")
        WEBSOCKETS_AVAILABLE = False

try:
    import base58
    BASE58_AVAILABLE = True
except ImportError:
    BASE58_AVAILABLE = False
    logger.warning("base58 not available. Installing...")
    try:
        import subprocess
        subprocess.check_call([sys.executable, "-m", "pip", "install", "base58"])
        import base58
        BASE58_AVAILABLE = True
        logger.info("base58 installed successfully")
    except:
        logger.error("Failed to install base58")
        BASE58_AVAILABLE = False

# Try to import PyTorch for GPU acceleration
try:
    import torch
    TORCH_AVAILABLE = True
    logger.info(f"PyTorch {torch.__version__} available, CUDA: {torch.cuda.is_available()}")
    if torch.cuda.is_available():
        GPU_DEVICE = torch.device("cuda")
        logger.info(f"Using GPU: {torch.cuda.get_device_name(0)}")
    else:
        GPU_DEVICE = torch.device("cpu")
        logger.info("No CUDA device available, using CPU")
except ImportError:
    TORCH_AVAILABLE = False
    GPU_DEVICE = None
    logger.warning("PyTorch not available. Performance optimizations disabled.")

# Load configuration from environment variables or use defaults
# RPC Settings
RPC_URL = os.environ.get("RPC_URL", "https://winny-rychu7-fast-mainnet.helius-rpc.com")
WS_URL = os.environ.get("WS_URL", "wss://winny-rychu7-fast-mainnet.helius-rpc.com")
API_KEY = os.environ.get("API_KEY", "86ab5634-df30-4a5b-bcfb-3f53d7095ca2")

# Program IDs
RAYDIUM_PROGRAM_ID = os.environ.get("RAYDIUM_PROGRAM_ID", "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8")
SERUM_PROGRAM_ID = os.environ.get("SERUM_PROGRAM_ID", "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin")
TOKEN_PROGRAM_ID = os.environ.get("TOKEN_PROGRAM_ID", "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA")
SYSTEM_PROGRAM_ID = os.environ.get("SYSTEM_PROGRAM_ID", "11111111111111111111111111111111")
ASSOCIATED_TOKEN_PROGRAM_ID = os.environ.get("ASSOCIATED_TOKEN_PROGRAM_ID", "ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL")

# Token addresses
WSOL_MINT = os.environ.get("SOL_MINT", "So11111111111111111111111111111111111111112")
TOKEN_MINT = os.environ.get("TOKEN_MINT", "DezXAZ8z7PnrnRJjz3wXBoRgixCa6xjnB7YaB1pPB263")  # BONK

# Market accounts
AMM_ID = os.environ.get("AMM_ID", "58oQChx4yWmvKdwLLZzBi4ChoCc2fqCUWBkwMihLYQo2")
MARKET_AMM_AUTHORITY = os.environ.get("MARKET_AMM_AUTHORITY", "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1")
MARKET_AMM_OPEN_ORDERS = os.environ.get("MARKET_AMM_OPEN_ORDERS", "HRk9CMrpq7Jn9sh7mzxE8CChHG8dneX9p475QKz4Fsfc")
MARKET_AMM_TARGET = os.environ.get("MARKET_AMM_TARGET", "DZnkkTmCiFWfYTfT41X3Rd1kDgozqzxWaHqsw6W4x2oe")
MARKET_POOL_TOKEN_ACCOUNT = os.environ.get("MARKET_POOL_TOKEN_ACCOUNT", "G5rZ4Qfv5SxruHQJpf8mYdVR8zaBEmr5rQQzYE3ga8Sw")
MARKET_POOL_PC_TOKEN_ACCOUNT = os.environ.get("MARKET_POOL_PC_TOKEN_ACCOUNT", "6DfxGFP8TQnAqkVFEGX3pd5xFhGNkrLhwVR9MYrjpt6h")

# Transaction parameters
COMPUTE_UNITS = int(os.environ.get("COMPUTE_LIMIT", "50000"))
PRIORITY_FEE = int(os.environ.get("PRIORITY_FEE", "750000"))
SLIPPAGE_BPS = int(os.environ.get("SLIPPAGE_BPS", "1000"))
MAX_TRADE_INTERVAL = float(os.environ.get("MIN_TRADE_INTERVAL", "0.2"))
EXECUTION_MIN_INTERVAL = float(os.environ.get("EXECUTION_MIN_INTERVAL", "0.1"))
MAX_ACTIVE_MEVS = int(os.environ.get("MAX_ACTIVE_MEVS", "1"))
MAX_RETRY_COUNT = int(os.environ.get("MAX_RETRIES", "3"))

# Trading parameters
FRONT_RUN_AMOUNT = float(os.environ.get("FRONT_RUN_AMOUNT", "0.35"))
MIN_VICTIM_SIZE = float(os.environ.get("SANDWICH_MIN_VICTIM_SIZE", "5.0"))
MAX_VICTIM_SIZE = float(os.environ.get("SANDWICH_MAX_VICTIM_SIZE", "320.0"))
MIN_PROFIT = float(os.environ.get("MIN_PROFIT", "0.002"))
MIN_SOL_BALANCE = float(os.environ.get("MIN_SOL_BALANCE", "0.03"))
MIN_WSOL_BALANCE = float(os.environ.get("MIN_WSOL_BALANCE", "0.02"))
WSOL_TARGET_RATIO = float(os.environ.get("WSOL_TARGET_RATIO", "0.95"))

# Wallet configuration - try loading from main root dir
KEYPAIR_PATH = os.environ.get("KEYPAIR_PATH", "./keypair.bin")
SOLANA_PRIVATE_KEY = os.environ.get("SOLANA_PRIVATE_KEY", "")
SOLANA_PUBLIC_KEY = os.environ.get("SOLANA_PUBLIC_KEY", "")

# Known tokens for trading
KNOWN_TOKENS = {
    "BONK": "DezXAZ8z7PnrnRJjz3wXBoRgixCa6xjnB7YaB1pPB263",
    "SAMO": "7xKXtg2CW87d97TXJSDpbD5jBkheTqA83TZRuJosgAsU",
    "DUST": "DUSTawucrTsGU8hcqRdHDCbuYhCPADMLM2VcCb8VnFnQ"
}

# Known WSOL account
WSOL_TOKEN_ACCOUNT = os.environ.get("WSOL_TOKEN_ACCOUNT", "5TwPK71xyhpkxNQ3WzxvSrpVpj16eDETwmMQJX74BGRX")

# Blacklisted token patterns to avoid
BLACKLISTED_TOKEN_PREFIXES = {
    "1111111",  # System program
    "TokenkegQ",  # Token program
    "ATokenGP",  # Associated token program
    "SysvarR",  # Sysvar
    "Compute",  # Compute budget
}

# AMM instruction discriminators
# These are binary offsets for parsing Raydium AMM instructions from memcmp subscription
RAYDIUM_SWAP_INSTRUCTION_DISCRIMINATOR = bytes.fromhex("0100000000000000")  # Swap instruction, first byte 0x01
RAYDIUM_ROUTE_INSTRUCTION_DISCRIMINATOR = bytes.fromhex("0300000000000000")  # Route instruction, first byte 0x03
RAYDIUM_MARKET_DISCRIMINATOR = bytes.fromhex("0900000000000000")  # Market instruction, first byte 0x09

###########################################
# SECTION 3: UTILITY CLASSES
###########################################

class TradingStats:
    """Class to track trading statistics"""
    
    def __init__(self):
        self.start_time = time.time()
        self.opportunities = 0
        self.filtered_by_size = 0
        self.filtered_by_safety = 0
        self.viable = 0
        self.attempted = 0
        self.completed = 0
        self.profit = 0.0
        self.execution_times = []
        self.start_balance = 0.0
        self.current_balance = 0.0
        self.last_balance_check = 0
        self.wsol_balance = 0.0
        self.token_balances = {}
        self.rpc_calls = 0
        self.rpc_errors = 0
        self.atas_created = set()
        self.last_heartbeat = 0
        self.trades_by_token = {}
        self.profit_by_token = {}
        self.success_rate = 0.0
        
    def update_success_rate(self):
        """Update success rate calculation"""
        if self.attempted > 0:
            self.success_rate = (self.completed / self.attempted) * 100
        else:
            self.success_rate = 0.0
            
    def add_trade(self, token_mint: str, profit: float, success: bool):
        """Add trade to statistics"""
        # Track by token
        if token_mint not in self.trades_by_token:
            self.trades_by_token[token_mint] = {
                "total": 0,
                "successful": 0,
                "profit": 0.0
            }
            
        self.trades_by_token[token_mint]["total"] += 1
        
        if success:
            self.trades_by_token[token_mint]["successful"] += 1
            self.trades_by_token[token_mint]["profit"] += profit
            
        # Update profit by token
        if token_mint not in self.profit_by_token:
            self.profit_by_token[token_mint] = 0.0
            
        self.profit_by_token[token_mint] += profit
        
        # Update overall stats
        self.attempted += 1
        if success:
            self.completed += 1
            self.profit += profit
            
        self.update_success_rate()
        
    def get_runtime_str(self):
        """Get formatted runtime string"""
        runtime = time.time() - self.start_time
        hours = int(runtime // 3600)
        minutes = int((runtime % 3600) // 60)
        seconds = int(runtime % 60)
        return f"{hours:02d}:{minutes:02d}:{seconds:02d}"
        
    def get_runtime_hours(self):
        """Get runtime in hours"""
        return (time.time() - self.start_time) / 3600
        
    def get_profit_per_hour(self):
        """Calculate profit per hour"""
        runtime_hours = self.get_runtime_hours()
        if runtime_hours > 0:
            return self.profit / runtime_hours
        return 0
        
    def get_roi_percent(self):
        """Calculate ROI percentage"""
        if self.start_balance > 0:
            return ((self.current_balance - self.start_balance) / self.start_balance) * 100
        return 0
        
    def print_stats(self):
        """Print current trading statistics"""
        logger.section("SOLANA TRADING STATISTICS")
        
        logger.info(f"Runtime: {self.get_runtime_str()} ({self.get_runtime_hours():.2f} hours)")
        logger.info(f"Opportunities Found: {self.opportunities}")
        logger.info(f"Viable Opportunities: {self.viable}")
        logger.info(f"Attempted Trades: {self.attempted}")
        logger.info(f"Completed Trades: {self.completed}")
        logger.info(f"Success Rate: {self.success_rate:.1f}%")
        
        avg_execution_time = 0
        if self.execution_times:
            avg_execution_time = sum(self.execution_times) / len(self.execution_times)
        logger.info(f"Avg Execution Time: {avg_execution_time:.2f}ms")
        
        logger.info("")
        logger.info("FILTERING STATS:")
        logger.info(f"Size Filtered: {self.filtered_by_size}")
        logger.info(f"Safety Filtered: {self.filtered_by_safety}")
        
        logger.info("")
        logger.info("PROFIT METRICS:")
        logger.info(f"Total Profit: {self.profit:.6f} SOL")
        logger.info(f"Profit per Hour: {self.get_profit_per_hour():.6f} SOL/hr")
        logger.info(f"Starting Balance: {self.start_balance:.6f} SOL")
        logger.info(f"Current Balance: {self.current_balance:.6f} SOL")
        logger.info(f"WSOL Balance: {self.wsol_balance:.6f} SOL")
        logger.info(f"ROI: {self.get_roi_percent():.2f}%")
        
        # Show token-specific profits if any
        if self.profit_by_token:
            logger.info("")
            logger.info("TOKEN PROFITS:")
            for token, profit in self.profit_by_token.items():
                # Get token symbol if available
                token_symbol = next((symbol for symbol, address in KNOWN_TOKENS.items() 
                                    if address == token), token[:8])
                logger.info(f"{token_symbol}: {profit:.6f} SOL")
        
        logger.info("")
        logger.info("RPC METRICS:")
        logger.info(f"RPC Calls: {self.rpc_calls}")
        logger.info(f"RPC Errors: {self.rpc_errors}")
        logger.info(f"ATAs Created: {len(self.atas_created)}")
        logger.info(f"Current Time: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}")
        logger.section("END STATISTICS", char="-")

class GlobalState:
    """Global state tracking for the trading bot"""
    
    def __init__(self):
        self.is_running = False
        self.trades_in_progress = 0
        self.last_wsol_wrap_time = 0
        self.last_balance_check = 0
        self.last_trade_time = 0
        self.last_restart_time = 0
        self.restart_attempts = 0
        self.initialized = False
        self.lock = asyncio.Lock()
        self.session_id = uuid.uuid4().hex
        self.cooldown_until = 0
        self.in_cooldown = False
        self.max_concurrency = MAX_ACTIVE_MEVS
        self.trade_semaphore = asyncio.Semaphore(MAX_ACTIVE_MEVS)
        self.last_execution = 0
        self.valid_token_mints = set(KNOWN_TOKENS.values())
        self.blacklisted_token_mints = set()
        self.wsol_balance = 0.0
        self.native_sol_balance = 0.0
        self.token_accounts = {}  # Map of token_mint -> token_account
        self.balance_subscription_id = None
        self.recent_blockhash = None
        self.blockhash_time = 0
        
    def can_execute_trade(self):
        """Check if we can execute a trade based on timing and concurrency"""
        # Check cooldown
        if self.in_cooldown and time.time() < self.cooldown_until:
            return False
            
        # Check minimum interval between trades
        if time.time() - self.last_trade_time < MAX_TRADE_INTERVAL:
            return False
            
        # Check if we've hit max concurrency
        if self.trades_in_progress >= self.max_concurrency:
            return False
            
        return True
        
    def can_execute_transaction(self):
        """Check if we can execute a transaction based on timing"""
        # Enforce minimum interval between execution steps
        if time.time() - self.last_execution < EXECUTION_MIN_INTERVAL:
            return False
        return True
        
    def start_trade(self):
        """Mark a trade as starting"""
        self.trades_in_progress += 1
        self.last_trade_time = time.time()
        
    def finish_trade(self):
        """Mark a trade as finished"""
        if self.trades_in_progress > 0:
            self.trades_in_progress -= 1
            
    def start_execution(self):
        """Mark an execution step"""
        self.last_execution = time.time()
        
    def set_cooldown(self, seconds):
        """Set a cooldown period"""
        self.in_cooldown = True
        self.cooldown_until = time.time() + seconds
        
    def clear_cooldown(self):
        """Clear cooldown state"""
        self.in_cooldown = False
        self.cooldown_until = 0
        
    def update_token_account(self, token_mint, token_account):
        """Update token account mapping"""
        self.token_accounts[token_mint] = token_account
        
    def get_token_account(self, token_mint):
        """Get token account for mint"""
        return self.token_accounts.get(token_mint)
        
    def update_blockhash(self, blockhash):
        """Update recent blockhash"""
        self.recent_blockhash = blockhash
        self.blockhash_time = time.time()
        
    def is_blockhash_fresh(self):
        """Check if blockhash is fresh (less than 50 seconds old)"""
        return self.recent_blockhash is not None and time.time() - self.blockhash_time < 50

class WSOLWrapper:
    """Utility class for wrapping and unwrapping SOL/WSOL"""
    
    def __init__(self, rpc_url=None, private_key=None, keypair_path=None):
        """
        Initialize the WSOL wrapper
        
        Args:
            rpc_url: Solana RPC URL (default: from environment)
            private_key: Base58 encoded private key (optional)
            keypair_path: Path to keypair file (optional)
        """
        self.rpc_url = rpc_url or RPC_URL
        self.private_key = private_key or SOLANA_PRIVATE_KEY
        self.keypair_path = keypair_path or KEYPAIR_PATH
        self.public_key = None
        self.rust_client = None
        self.http_client = None
        self.ws_url = WS_URL
        self.api_key = API_KEY
        
    async def initialize(self):
        """Initialize the wrapper"""
        try:
            if RUST_AVAILABLE:
                # Initialize through Rust module
                config = solana_rust_bot.TradingConfig(
                    rpc_url=self.rpc_url,
                    ws_url=self.ws_url,
                    api_key=self.api_key,
                    sol_mint=WSOL_MINT
                )
                
                if self.private_key:
                    self.rust_client = solana_rust_bot.RaydiumTradingCore(
                        rpc_url=self.rpc_url,
                        private_key=self.private_key,
                        config=config
                    )
                else:
                    self.rust_client = solana_rust_bot.RaydiumTradingCore(
                        rpc_url=self.rpc_url,
                        keypair_path=self.keypair_path,
                        config=config
                    )
                
                # Get public key
                self.public_key = self.rust_client.get_public_key()
                logger.info(f"Initialized WSOL wrapper with public key: {self.public_key}")
                return True
            else:
                # Initialize HTTP client for API access
                if AIOHTTP_AVAILABLE:
                    self.http_client = aiohttp.ClientSession()
                    logger.info("Initialized WSOL wrapper with HTTP client (limited functionality)")
                    return True
                else:
                    logger.error("Neither Rust module nor aiohttp available")
                    return False
        except Exception as e:
            logger.error(f"Error initializing WSOL wrapper: {e}")
            logger.error(traceback.format_exc())
            return False
    
    async def get_balances(self):
        """Get SOL and WSOL balances"""
        try:
            if RUST_AVAILABLE and self.rust_client:
                balances = await self.rust_client.get_balances()
                # Unpack balances
                sol_balance = balances[0]
                token_balances = balances[1]
                wsol_balance = token_balances.get(WSOL_MINT, 0)
                
                return sol_balance, wsol_balance
            else:
                # Not implemented for HTTP client yet
                logger.warning("Balance check not available without Rust module")
                return 0, 0
        except Exception as e:
            logger.error(f"Error getting balances: {e}")
            return 0, 0
    
    async def ensure_wsol_ata(self):
        """Ensure the WSOL associated token account exists"""
        try:
            if RUST_AVAILABLE and self.rust_client:
                ata = await self.rust_client.ensure_ata(WSOL_MINT)
                logger.info(f"WSOL ATA: {ata}")
                return ata
            else:
                logger.warning("ATA creation not available without Rust module")
                return None
        except Exception as e:
            logger.error(f"Error ensuring WSOL ATA: {e}")
            return None
    
    async def wrap_sol(self, amount_sol, priority_fee=None):
        """
        Wrap SOL to WSOL
        
        Args:
            amount_sol: Amount of SOL to wrap
            priority_fee: Priority fee in lamports (default: from environment)
            
        Returns:
            Transaction signature or None if failed
        """
        try:
            priority_fee = priority_fee or PRIORITY_FEE
            
            logger.info(f"Wrapping {amount_sol:.6f} SOL with priority fee: {priority_fee}")
            
            if RUST_AVAILABLE and self.rust_client:
                # Ensure ATA exists
                wsol_account = await self.ensure_wsol_ata()
                
                # Create swap parameters
                swap_params = solana_rust_bot.SwapParams(
                    token_mint=WSOL_MINT,
                    amount_in=amount_sol,
                    is_buy=True,  # SOL -> WSOL is "buy"
                    slippage_bps=SLIPPAGE_BPS,
                    compute_limit=COMPUTE_UNITS,
                    priority_fee=priority_fee
                )
                
                # Execute swap
                result = await self.rust_client.execute_swap(swap_params)
                
                if result.success:
                    logger.info(f"Wrapped {amount_sol:.6f} SOL to WSOL: {result.signature}")
                    return result.signature
                else:
                    logger.error(f"Failed to wrap SOL: {result.error}")
                    return None
            else:
                # Simulate wrapping for testing
                logger.info(f"SIMULATED wrapping {amount_sol:.6f} SOL to WSOL")
                await asyncio.sleep(0.5)
                signature = f"sim_wrap_{int(time.time())}_{uuid.uuid4().hex[:8]}"
                logger.info(f"SIMULATED wrap complete: {signature}")
                return signature
        except Exception as e:
            logger.error(f"Error wrapping SOL: {e}")
            logger.error(traceback.format_exc())
            return None
    
    async def unwrap_sol(self, amount_wsol=0, priority_fee=None):
        """
        Unwrap WSOL to SOL
        
        Args:
            amount_wsol: Amount of WSOL to unwrap (0 = all)
            priority_fee: Priority fee in lamports (default: from environment)
            
        Returns:
            Transaction signature or None if failed
        """
        try:
            priority_fee = priority_fee or PRIORITY_FEE
            
            # If amount is 0, get all available WSOL
            if amount_wsol <= 0:
                _, wsol_balance = await self.get_balances()
                amount_wsol = wsol_balance
                
                if amount_wsol <= 0:
                    logger.warning("No WSOL to unwrap")
                    return None
            
            logger.info(f"Unwrapping {amount_wsol:.6f} WSOL with priority fee: {priority_fee}")
            
            if RUST_AVAILABLE and self.rust_client:
                # Create swap parameters
                swap_params = solana_rust_bot.SwapParams(
                    token_mint=WSOL_MINT,
                    amount_in=amount_wsol,
                    is_buy=False,  # WSOL -> SOL is "sell"
                    slippage_bps=SLIPPAGE_BPS,
                    compute_limit=COMPUTE_UNITS,
                    priority_fee=priority_fee
                )
                
                # Execute swap
                result = await self.rust_client.execute_swap(swap_params)
                
                if result.success:
                    logger.info(f"Unwrapped {amount_wsol:.6f} WSOL to SOL: {result.signature}")
                    return result.signature
                else:
                    logger.error(f"Failed to unwrap WSOL: {result.error}")
                    return None
            else:
                # Simulate unwrapping for testing
                logger.info(f"SIMULATED unwrapping {amount_wsol:.6f} WSOL to SOL")
                await asyncio.sleep(0.5)
                signature = f"sim_unwrap_{int(time.time())}_{uuid.uuid4().hex[:16]}"
                logger.info(f"SIMULATED unwrap complete: {signature}")
                return signature
        except Exception as e:
            logger.error(f"Error unwrapping WSOL: {e}")
            logger.error(traceback.format_exc())
            return None
    
    async def close(self):
        """Close connections and clean up"""
        if self.http_client:
            await self.http_client.close()
            self.http_client = None

async def create_wsol_wrapper(rpc_url=None, private_key=None, keypair_path=None):
    """
    Factory function to create and initialize a WSOL wrapper
    
    Args:
        rpc_url: Solana RPC URL (default: from environment)
        private_key: Base58 encoded private key (optional)
        keypair_path: Path to keypair file (optional)
        
    Returns:
        Initialized WSOLWrapper instance
    """
    wrapper = WSOLWrapper(rpc_url, private_key, keypair_path)
    await wrapper.initialize()
    return wrapper


###########################################
# SECTION 4: TRADING CORE
###########################################

class TradingCore:
    """Enhanced trading core with better state management"""
    
    def __init__(self):
        self.state = GlobalState()
        self.stats = TradingStats()
        self.rust_core = None
        
        # Semaphores for concurrency control
        self.balance_lock = asyncio.Lock()
        self.wsol_lock = asyncio.Lock()
        
        # HTTP & WebSocket sessions
        self.http_session = None
        self.ws_connections = {}
        
        # Configure from environment
        self.min_sol_balance = MIN_SOL_BALANCE
        self.min_wsol_balance = MIN_WSOL_BALANCE
        self.front_run_amount = FRONT_RUN_AMOUNT
        self.min_victim_size = MIN_VICTIM_SIZE
        self.max_victim_size = MAX_VICTIM_SIZE
        self.min_profit = MIN_PROFIT
        self.slippage_bps = SLIPPAGE_BPS
        self.compute_units = COMPUTE_UNITS
        self.priority_fee = PRIORITY_FEE
        
        # Load config from environment
        self.load_config()
        
        # GPU acceleration if available
        self.use_gpu = TORCH_AVAILABLE and torch.cuda.is_available()
        if self.use_gpu:
            logger.info("GPU acceleration enabled for data processing")
        
    def load_config(self):
        """Load configuration from environment variables"""
        logger.info("Loading trading configuration from environment")
        
        # RPC Configuration
        self.rpc_url = RPC_URL
        self.ws_url = WS_URL
        self.api_key = API_KEY
        
        # Keypair configuration
        self.private_key = SOLANA_PRIVATE_KEY
        self.public_key = SOLANA_PUBLIC_KEY
        self.keypair_path = KEYPAIR_PATH
        
        # Program IDs
        self.raydium_program_id = RAYDIUM_PROGRAM_ID
        self.token_program_id = TOKEN_PROGRAM_ID
        self.system_program_id = SYSTEM_PROGRAM_ID
        self.associated_token_program_id = ASSOCIATED_TOKEN_PROGRAM_ID
        
        # Market configuration
        self.amm_id = AMM_ID
        self.market_amm_authority = MARKET_AMM_AUTHORITY
        self.market_amm_open_orders = MARKET_AMM_OPEN_ORDERS
        self.market_amm_target = MARKET_AMM_TARGET
        self.market_pool_token_account = MARKET_POOL_TOKEN_ACCOUNT
        self.market_pool_pc_token_account = MARKET_POOL_PC_TOKEN_ACCOUNT
        
        # Token configuration
        self.default_token_mint = TOKEN_MINT
        
        # RPC rate limiting
        self.rpc_rate_limit = int(os.environ.get("RPC_RATE_LIMIT", "5"))
        
        logger.info(f"Configuration loaded: {self.rpc_url}")
    
    async def initialize_http(self):
        """Initialize HTTP session"""
        if AIOHTTP_AVAILABLE:
            self.http_session = aiohttp.ClientSession(headers={"Content-Type": "application/json"})
            if self.api_key:
                self.http_session.headers.update({"Authorization": f"Bearer {self.api_key}"})
            return True
        return False
        
    async def initialize_rust_core(self):
        """Initialize the Rust trading core"""
        if not RUST_AVAILABLE:
            logger.warning("Rust trading core not available, running in simulation mode")
            return False
            
        try:
            logger.info("Initializing Rust trading core")
            
            # Create trading config
            config = solana_rust_bot.TradingConfig(
                rpc_url=self.rpc_url,
                ws_url=self.ws_url,
                api_key=self.api_key,
                sol_mint=WSOL_MINT,
                rpc_rate_limit=self.rpc_rate_limit,
                compute_limit=self.compute_units,
                priority_fee=self.priority_fee,
                skip_preflight=True,
                token_mint=self.default_token_mint,
                amm_id=self.amm_id,
                amm_program=self.raydium_program_id,
                market_amm_authority=self.market_amm_authority,
                market_amm_open_orders=self.market_amm_open_orders,
                market_amm_target=self.market_amm_target,
                market_pool_token_account=self.market_pool_token_account,
                market_pool_pc_token_account=self.market_pool_pc_token_account,
                raydium_program_id=self.raydium_program_id,
                token_program_id=self.token_program_id,
                system_program_id=self.system_program_id,
                associated_token_program_id=self.associated_token_program_id
            )
            
            # Add token pair settings
            for token_name, token_mint in KNOWN_TOKENS.items():
                if token_mint == self.default_token_mint and self.amm_id:
                    # Use the market params if available
                    token_pair = solana_rust_bot.TokenPairSetting(
                        token_mint=token_mint,
                        amm_id=self.amm_id,
                        amm_authority=self.market_amm_authority,
                        amm_open_orders=self.market_amm_open_orders,
                        amm_target=self.market_amm_target,
                        pool_token_account=self.market_pool_token_account,
                        pool_pc_account=self.market_pool_pc_token_account,
                        min_liquidity_pct=95.0,
                        min_exit_liquidity_sol=5.0,
                        auth_revoked=True,
                        buyer_seller_ratio=1.0,
                        min_volume_5m=10.0,
                        enabled=True
                    )
                    config.add_token_pair_setting(token_pair)
                    logger.info(f"Added token pair setting for {token_name} ({token_mint}) with AMM config")
                elif token_name == "BONK":
                    # Hardcoded values for BONK if we don't have custom values
                    token_pair = solana_rust_bot.TokenPairSetting(
                        token_mint=token_mint,
                        amm_id="58oQChx4yWmvKdwLLZzBi4ChoCc2fqCUWBkwMihLYQo2",
                        amm_authority="5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1",
                        amm_open_orders="HRk9CMrpq7Jn9sh7mzxE8CChHG8dneX9p475QKz4Fsfc",
                        amm_target="DZnkkTmCiFWfYTfT41X3Rd1kDgozqzxWaHqsw6W4x2oe",
                        pool_token_account="G5rZ4Qfv5SxruHQJpf8mYdVR8zaBEmr5rQQzYE3ga8Sw",
                        pool_pc_account="6DfxGFP8TQnAqkVFEGX3pd5xFhGNkrLhwVR9MYrjpt6h",
                        min_liquidity_pct=95.0,
                        min_exit_liquidity_sol=5.0,
                        auth_revoked=True,
                        buyer_seller_ratio=1.0,
                        min_volume_5m=10.0,
                        enabled=True
                    )
                    config.add_token_pair_setting(token_pair)
                    logger.info(f"Added token pair setting for {token_name} ({token_mint}) with default AMM config")
            
            # Create trading core instance
            # If private key is in base58 format, use it directly
            if self.private_key:
                self.rust_core = solana_rust_bot.RaydiumTradingCore(
                    rpc_url=self.rpc_url,
                    private_key=self.private_key,
                    config=config
                )
                logger.info("Created trading core with private key")
            else:
                # Use keypair file path
                self.rust_core = solana_rust_bot.RaydiumTradingCore(
                    rpc_url=self.rpc_url,
                    keypair_path=self.keypair_path,
                    config=config
                )
                logger.info(f"Created trading core with keypair file: {self.keypair_path}")
                
            # Get initial balances
            logger.info("Getting initial balances")
            balances = await self.get_balances(force_update=True)
            
            # Setup WebSocket balance monitoring to avoid excessive RPC calls
            await self.setup_balance_monitoring()
            
            # Get recent blockhash for quick transactions
            await self.refresh_blockhash()
            
            return True
            
        except Exception as e:
            logger.error(f"Error initializing Rust trading core: {e}")
            logger.error(traceback.format_exc())
            return False
    
    async def setup_balance_monitoring(self):
        """Setup WebSocket subscription for balance monitoring"""
        if not WEBSOCKETS_AVAILABLE or not self.rust_core:
            logger.warning("WebSocket or Rust core not available, balance monitoring disabled")
            return False
            
        try:
            logger.info("Setting up WebSocket balance monitoring")
            
            # Get public key
            public_key = self.rust_core.get_public_key()
            
            # Create WebSocket connection in a separate task
            asyncio.create_task(self.subscribe_to_balance_updates(public_key))
            
            return True
        except Exception as e:
            logger.error(f"Error setting up balance monitoring: {e}")
            logger.error(traceback.format_exc())
            return False
    
    async def subscribe_to_balance_updates(self, public_key):
        """Subscribe to account balance updates via WebSocket"""
        if not WEBSOCKETS_AVAILABLE:
            return
            
        headers = {}
        if self.api_key:
            headers["Authorization"] = f"Bearer {self.api_key}"
        
        try:
            logger.info("Connecting to balance WebSocket...")
            async with websockets.connect(
                self.ws_url,
                extra_headers=headers,
                ping_interval=30,
                ping_timeout=10,
                close_timeout=15
            ) as ws:
                # Store connection
                self.ws_connections["balance"] = ws
                
                # Subscribe to balance updates
                subscription_message = {
                    "jsonrpc": "2.0",
                    "id": 1,
                    "method": "accountSubscribe",
                    "params": [
                        public_key,
                        {
                            "encoding": "jsonParsed",
                            "commitment": "confirmed"
                        }
                    ]
                }
                
                await ws.send(json.dumps(subscription_message))
                response = await ws.recv()
                response_data = json.loads(response)
                
                if "result" in response_data:
                    self.state.balance_subscription_id = response_data["result"]
                    logger.info(f"Subscribed to balance updates: {self.state.balance_subscription_id}")
                    
                    # Also subscribe to token accounts
                    await self.subscribe_to_token_accounts(ws, public_key)
                
                # Process messages
                while True:
                    try:
                        message = await ws.recv()
                        await self.process_balance_message(message)
                    except websockets.exceptions.ConnectionClosed:
                        logger.warning("Balance WebSocket connection closed")
                        break
                    except Exception as e:
                        logger.error(f"Error processing balance message: {e}")
        except Exception as e:
            logger.error(f"Error in balance WebSocket: {e}")
        finally:
            # Remove connection
            if "balance" in self.ws_connections:
                del self.ws_connections["balance"]
                
            # Reconnect after delay
            await asyncio.sleep(5)
            logger.info("Reconnecting balance WebSocket...")
            asyncio.create_task(self.subscribe_to_balance_updates(public_key))
    
    async def subscribe_to_token_accounts(self, ws, owner_pubkey):
        """Subscribe to token account updates"""
        try:
            # Get all token accounts first
            for token_name, token_mint in KNOWN_TOKENS.items():
                # Ensure ATA exists
                token_account = await self.ensure_ata(token_mint)
                
                if token_account:
                    # Store token account
                    self.state.update_token_account(token_mint, token_account)
                    
                    # Subscribe to account
                    subscription_message = {
                        "jsonrpc": "2.0",
                        "id": 2,
                        "method": "accountSubscribe",
                        "params": [
                            token_account,
                            {
                                "encoding": "jsonParsed",
                                "commitment": "confirmed"
                            }
                        ]
                    }
                    
                    await ws.send(json.dumps(subscription_message))
                    response = await ws.recv()
                    response_data = json.loads(response)
                    
                    if "result" in response_data:
                        logger.info(f"Subscribed to {token_name} account updates: {response_data['result']}")
                    
            # Also subscribe to WSOL account
            wsol_account = self.state.get_token_account(WSOL_MINT)
            if wsol_account:
                subscription_message = {
                    "jsonrpc": "2.0",
                    "id": 3,
                    "method": "accountSubscribe",
                    "params": [
                        wsol_account,
                        {
                            "encoding": "jsonParsed",
                            "commitment": "confirmed"
                        }
                    ]
                }
                
                await ws.send(json.dumps(subscription_message))
                response = await ws.recv()
                response_data = json.loads(response)
                
                if "result" in response_data:
                    logger.info(f"Subscribed to WSOL account updates: {response_data['result']}")
        except Exception as e:
            logger.error(f"Error subscribing to token accounts: {e}")
    
    async def process_balance_message(self, message):
        """Process balance update message"""
        try:
            data = json.loads(message)
            
            if "method" in data and data["method"] == "accountNotification":
                params = data.get("params", {})
                result = params.get("result", {})
                value = result.get("value", {})
                
                # Check if this is a SOL balance update
                if "lamports" in value:
                    lamports = value["lamports"]
                    sol_balance = lamports / 1_000_000_000  # Convert to SOL
                    
                    # Update state
                    self.state.native_sol_balance = sol_balance
                    self.stats.current_balance = sol_balance
                    self.stats.last_balance_check = time.time()
                    
                    # Debug log
                    logger.trace(f"SOL balance updated: {sol_balance:.6f} SOL")
                
                # Check if this is a token account update
                if "data" in value and "parsed" in value["data"]:
                    parsed = value["data"]["parsed"]
                    
                    if "info" in parsed and "tokenAmount" in parsed["info"]:
                        owner = parsed["info"].get("owner")
                        mint = parsed["info"].get("mint")
                        
                        # Only process our own accounts
                        if owner == self.public_key and mint:
                            token_amount = parsed["info"]["tokenAmount"]
                            amount = float(token_amount["uiAmount"] or 0)
                            
                            # Update token balance
                            if mint in self.stats.token_balances:
                                self.stats.token_balances[mint] = amount
                            else:
                                self.stats.token_balances[mint] = amount
                            
                            # Specifically update WSOL balance
                            if mint == WSOL_MINT:
                                self.state.wsol_balance = amount
                                self.stats.wsol_balance = amount
                                logger.trace(f"WSOL balance updated: {amount:.6f} WSOL")
                            else:
                                # Get token symbol if available
                                token_symbol = next((symbol for symbol, address in KNOWN_TOKENS.items() 
                                                   if address == mint), mint[:8])
                                logger.trace(f"{token_symbol} balance updated: {amount:.6f}")
        except json.JSONDecodeError:
            logger.error("Invalid JSON in balance message")
        except Exception as e:
            logger.error(f"Error processing balance message: {e}")
            
    async def refresh_blockhash(self):
        try:
            if self.http_session:
                payload = {
                    "jsonrpc": "2.0",
                    "id": 1,
                    "method": "getLatestBlockhash",
                    "params": [{"commitment": "processed"}]
                }
                async with self.http_session.post(self.rpc_url, json=payload) as response:
                    if response.status == 200:
                        data = await response.json()
                        if "result" in data and "value" in data["result"]:
                            blockhash = data["result"]["value"]["blockhash"]
                            self.state.update_blockhash(blockhash)
                            logger.debug(f"Updated blockhash: {blockhash}")
                            return blockhash
            return None
        except Exception as e:
            logger.error(f"Error getting blockhash: {e}")
            return None
        
    async def get_balances(self, force_update=False):
        """Get SOL and token balances"""
        async with self.balance_lock:
            try:
                current_time = time.time()
                
                # Check cache first unless force update
                if not force_update and current_time - self.stats.last_balance_check < 10:
                    # If we have state from websocket, use it
                    if self.state.native_sol_balance > 0:
                        return self.state.native_sol_balance, self.stats.token_balances
                    # Otherwise use cached values
                    return self.stats.current_balance, self.stats.token_balances
                
                # Get balances from rust core
                if RUST_AVAILABLE and self.rust_core:
                    self.stats.rpc_calls += 1
                    balances = await self.rust_core.get_balances()
                    
                    # Unpack balances
                    sol_balance = balances[0]
                    token_balances = balances[1]
                    
                    # Update stats
                    self.stats.current_balance = sol_balance
                    self.stats.token_balances = token_balances
                    self.stats.last_balance_check = current_time
                    
                    # Also update state for WebSocket comparison
                    self.state.native_sol_balance = sol_balance
                    
                    # Update WSOL balance
                    if WSOL_MINT in token_balances:
                        self.stats.wsol_balance = token_balances[WSOL_MINT]
                        self.state.wsol_balance = token_balances[WSOL_MINT]
                    else:
                        self.stats.wsol_balance = 0.0
                        self.state.wsol_balance = 0.0
                    
                    # If this is the first update, set start balance
                    if self.stats.start_balance == 0.0:
                        self.stats.start_balance = sol_balance
                    
                    # Log balances if forced update
                    if force_update:
                        logger.info(f"SOL Balance: {sol_balance:.6f} SOL")
                        
                        for token_mint, balance in token_balances.items():
                            token_name = "WSOL" if token_mint == WSOL_MINT else next(
                                (name for name, mint in KNOWN_TOKENS.items() if mint == token_mint), 
                                token_mint[:8]
                            )
                            logger.info(f"{token_name} Balance: {balance:.6f}")
                        
                        # Calculate profit
                        profit = sol_balance - self.stats.start_balance
                        logger.info(f"Current profit: {profit:.6f} SOL")
                    
                    # Return balances
                    return sol_balance, token_balances
                else:
                    # Get SOL balance from HTTP API
                    if self.http_session and self.public_key:
                        self.stats.rpc_calls += 1
                        payload = {
                            "jsonrpc": "2.0",
                            "id": 1,
                            "method": "getBalance",
                            "params": [self.public_key]
                        }
                        async with self.http_session.post(self.rpc_url, json=payload) as response:
                            if response.status == 200:
                                data = await response.json()
                                if "result" in data and "value" in data["result"]:
                                    sol_balance = data["result"]["value"] / 1_000_000_000  # Convert to SOL
                                    self.stats.current_balance = sol_balance
                                    self.state.native_sol_balance = sol_balance
                                    
                                    # Set start balance if first update
                                    if self.stats.start_balance == 0.0:
                                        self.stats.start_balance = sol_balance
                                    
                                    # Log balance
                                    if force_update:
                                        logger.info(f"SOL Balance: {sol_balance:.6f} SOL")
                                    
                                    # Create token balances dict with WSOL
                                    token_balances = {WSOL_MINT: 0.35}  # Placeholder
                                    self.stats.token_balances = token_balances
                                    self.stats.wsol_balance = 0.35
                                    self.state.wsol_balance = 0.35
                                    self.stats.last_balance_check = current_time
                                    
                                    return sol_balance, token_balances
                                else:
                                    # Return cached values
                                    return self.stats.current_balance, self.stats.token_balances
                            else:
                                # Return cached values
                                return self.stats.current_balance, self.stats.token_balances
                    else:
                        # Simulate balances if HTTP not available
                        sol_balance = 0.124277
                        token_balances = {WSOL_MINT: 0.35}
                        
                        # Update stats
                        self.stats.current_balance = sol_balance
                        self.stats.token_balances = token_balances
                        self.stats.last_balance_check = current_time
                        self.stats.wsol_balance = token_balances.get(WSOL_MINT, 0.0)
                        
                        # Set start balance if first update
                        if self.stats.start_balance == 0.0:
                            self.stats.start_balance = sol_balance
                        
                        # Log simulated balances
                        if force_update:
                            logger.info(f"SIMULATED SOL Balance: {sol_balance:.6f} SOL")
                            logger.info(f"SIMULATED WSOL Balance: {token_balances.get(WSOL_MINT, 0.0):.6f}")
                        
                        return sol_balance, token_balances
            except Exception as e:
                logger.error(f"Error getting balances: {e}")
                logger.error(traceback.format_exc())
                self.stats.rpc_errors += 1
                return self.stats.current_balance, self.stats.token_balances
                
    async def ensure_ata(self, token_mint):
        """Ensure associated token account exists for a token mint with verification"""
        try:
            # Check state cache first
            cached_account = self.state.get_token_account(token_mint)
            if cached_account:
                logger.debug(f"Using cached token account for {token_mint}: {cached_account}")
                return cached_account
            
            # Skip if already created
            if token_mint in self.stats.atas_created:
                logger.debug(f"ATA for {token_mint} was previously created")
                
                # Verify it still exists and is valid if we have Rust core
                if RUST_AVAILABLE and self.rust_core:
                    # Get token account
                    token_account = await self.rust_core.get_token_account(token_mint)
                    
                    if token_account:
                        logger.debug(f"Verified ATA exists: {token_account}")
                        # Update state cache
                        self.state.update_token_account(token_mint, token_account)
                        return token_account
                    else:
                        logger.warning(f"ATA for {token_mint} was marked as created but could not be found!")
                        # Remove from created list so we'll recreate it
                        self.stats.atas_created.remove(token_mint)
            
            if RUST_AVAILABLE and self.rust_core:
                # Create ATA using rust core
                token_name = next((name for name, mint in KNOWN_TOKENS.items() if mint == token_mint), token_mint[:8])
                logger.info(f"Creating ATA for {token_name} ({token_mint})...")
                
                # Use high priority fee for ATA creation
                high_priority = self.priority_fee * 2
                
                # Create ATA with extended options
                if hasattr(self.rust_core, "create_ata_with_options"):
                    # Use enhanced method with options
                    token_account = await self.rust_core.create_ata_with_options(
                        token_mint=token_mint,
                        priority_fee=high_priority,
                        compute_limit=200000
                    )
                else:
                    # Use standard method
                    token_account = await self.rust_core.ensure_ata(token_mint)
                
                if token_account:
                    logger.success(f"Created ATA for {token_name}: {token_account}")
                    self.stats.atas_created.add(token_mint)
                    
                    # Update state cache
                    self.state.update_token_account(token_mint, token_account)
                    
                    # Verify token account exists
                    verification = await self.verify_token_account(token_mint, token_account)
                    if verification:
                        logger.success(f"ATA verified for {token_name}")
                    else:
                        logger.warning(f"ATA verification failed for {token_name}")
                    
                    return token_account
                else:
                    logger.error(f"Failed to create ATA for {token_name}")
                    return None
            else:
                # Simulate ATA creation
                logger.info(f"SIMULATED creating ATA for {token_mint}")
                await asyncio.sleep(0.5)
                self.stats.atas_created.add(token_mint)
                ata_hash = uuid.uuid4().hex[:32]
                logger.info(f"SIMULATED created ATA for {token_mint}: {ata_hash}")
                
                # Update state cache
                self.state.update_token_account(token_mint, ata_hash)
                return ata_hash
        except Exception as e:
            logger.error(f"Error ensuring ATA: {e}")
            logger.error(traceback.format_exc())
            return None
    
    async def verify_token_account(self, token_mint, token_account):
        """Skip verification since Rust handles this"""
        logger.info(f"Using token account: {token_account} for {token_mint}")
        return True
            
    async def initialize_wsol(self):
        """Initialize WSOL account and wrap some SOL if needed"""
        async with self.wsol_lock:
            try:
                # Get current balances
                sol_balance, token_balances = await self.get_balances(force_update=True)
                wsol_balance = token_balances.get(WSOL_MINT, 0)
                
                # Check if we already have enough WSOL
                if wsol_balance >= self.min_wsol_balance:
                    logger.info(f"WSOL already initialized with {wsol_balance:.6f} WSOL")
                    return True
                
                # Check if we have enough SOL to wrap
                if sol_balance <= self.min_sol_balance + 0.01:
                    logger.error(f"Not enough SOL to wrap: {sol_balance:.6f} SOL")
                    return False
                
                # Create WSOL ATA if needed
                wsol_account = await self.ensure_ata(WSOL_MINT)
                if not wsol_account:
                    logger.error("Failed to ensure WSOL ATA")
                    return False
                
                # Calculate amount to wrap
                wsol_target_ratio = WSOL_TARGET_RATIO
                target_wsol = sol_balance * wsol_target_ratio
                needed_wsol = max(0, target_wsol - wsol_balance)
                
                # Limit the amount to wrap
                wrap_amount = min(
                    needed_wsol,
                    sol_balance * 0.8,  # Don't wrap more than 80% of SOL
                    self.front_run_amount * 3  # Enough for several trades
                )
                
                # Only wrap if significant
                if wrap_amount < 0.01:
                    logger.warning(f"Wrap amount too small: {wrap_amount:.6f} SOL")
                    return wsol_balance > 0
                
                logger.info(f"Wrapping {wrap_amount:.6f} SOL to WSOL")
                
                if RUST_AVAILABLE and self.rust_core:
                    # Create a swap instruction to wrap SOL -> WSOL
                    swap_params = solana_rust_bot.SwapParams(
                        token_mint=WSOL_MINT,
                        amount_in=wrap_amount,
                        is_buy=True,
                        slippage_bps=self.slippage_bps,
                        compute_limit=self.compute_units,
                        priority_fee=self.priority_fee,
                        destination=wsol_account  # Explicitly set destination
                    )
                    
                    # Execute the swap
                    result = await self.rust_core.execute_swap(swap_params)
                    
                    if result.success:
                        logger.info(f"Wrapped {wrap_amount:.6f} SOL to WSOL: {result.signature}")
                        
                        # Update balances
                        await self.get_balances(force_update=True)
                        return True
                    else:
                        logger.error(f"Failed to wrap SOL to WSOL: {result.error}")
                        return False
                else:
                    # Use WSOL wrapper
                    wrapper = await create_wsol_wrapper(self.rpc_url, self.private_key, self.keypair_path)
                    tx_hash = await wrapper.wrap_sol(wrap_amount, self.priority_fee)
                    
                    if tx_hash:
                        logger.info(f"Wrapped {wrap_amount:.6f} SOL to WSOL: {tx_hash}")
                        
                        # Update simulated balances
                        self.stats.current_balance -= wrap_amount
                        if WSOL_MINT not in self.stats.token_balances:
                            self.stats.token_balances[WSOL_MINT] = 0
                        self.stats.token_balances[WSOL_MINT] += wrap_amount
                        self.stats.wsol_balance = self.stats.token_balances[WSOL_MINT]
                        
                        return True
                    else:
                        logger.error("Failed to wrap SOL to WSOL")
                        return False
            except Exception as e:
                logger.error(f"Error initializing WSOL: {e}")
                logger.error(traceback.format_exc())
                return False
    
    async def execute_trade(self, trade_info):
        """Execute a sandwich trade (front-run and back-run) with proper token destination"""
        if not self.state.can_execute_trade():
            logger.info("Cannot execute trade due to timing or concurrency constraints")
            return False
            
        # Start timing
        start_time = time.time()
        
        # Update state and stats
        self.state.start_trade()
        self.stats.attempted += 1
        
        try:
            # Get balance before trade
            sol_before, token_balances_before = await self.get_balances(force_update=True)
            
            # Get trade parameters
            token_mint = trade_info["token_mint"]
            
            # Find token symbol if available
            token_symbol = next((symbol for symbol, address in KNOWN_TOKENS.items() 
                              if address == token_mint), token_mint[:8])
            
            # Log trading intention
            logger.section(f"EXECUTING TRADE: {token_symbol}", char="-")
            logger.info(f"Token mint: {token_mint}")
            logger.info(f"Victim trade size: {trade_info.get('amount', 0):.4f} SOL")
            
            # Ensure ATA exists for token
            token_account = await self.ensure_ata(token_mint)
            if not token_account:
                logger.error(f"Failed to ensure ATA for {token_symbol}, aborting trade")
                self.state.finish_trade()
                return False
            
            # Verify token account is valid
            logger.info(f"Using token account for {token_symbol}: {token_account}")
            
            # Make sure blockhash is fresh
            blockhash = await self.refresh_blockhash()
            logger.debug(f"Using blockhash: {blockhash}")
            
            # Execute front-run (buy)
            logger.trade(f"Starting front-run trade: {self.front_run_amount:.6f} SOL -> {token_symbol}")
            
            # Mark execution timestamp
            self.state.start_execution()
            
            if RUST_AVAILABLE and self.rust_core:
                # Create swap parameters for buying with explicit destination
                swap_params = solana_rust_bot.SwapParams(
                    token_mint=token_mint,
                    amount_in=self.front_run_amount,
                    is_buy=True,
                    slippage_bps=self.slippage_bps,
                    compute_limit=self.compute_units,
                    priority_fee=self.priority_fee,
                    destination=token_account,  # Explicitly set destination
                    recent_blockhash=blockhash  # Use cached blockhash for quick execution
                )
                
                # Execute the swap
                result = await self.rust_core.execute_swap(swap_params)
                
                if not result.success:
                    logger.error(f"Front-run failed: {result.error}")
                    self.state.finish_trade()
                    return False
                    
                front_tx = result.signature
            else:
                # Simulate front-run
                await asyncio.sleep(0.5)
                front_tx = f"sim_{int(time.time())}_{uuid.uuid4().hex[:16]}"
            
            logger.success(f"Front-run completed: {front_tx}")
            
            # Check token account after front-run if possible
            if self.state.wsol_balance <= 0.03:
                logger.warning("WSOL balance too low after front-run, trades might fail!")
            
            # Wait for victim transaction
            victim_wait_time = float(os.environ.get("VICTIM_WAIT_TIME", "0.5"))
            logger.info(f"Waiting {victim_wait_time}s for victim transaction...")
            await asyncio.sleep(victim_wait_time)
            
            # Execute back-run (sell)
            logger.trade(f"Starting back-run trade: {token_symbol} -> WSOL (all tokens)")
            
            # Mark execution timestamp
            self.state.start_execution()
            
            if RUST_AVAILABLE and self.rust_core:
                # Create swap parameters for selling
                swap_params = solana_rust_bot.SwapParams(
                    token_mint=token_mint,
                    amount_in=0,  # 0 means sell all
                    is_buy=False,
                    slippage_bps=self.slippage_bps,
                    compute_limit=self.compute_units,
                    priority_fee=self.priority_fee,
                    recent_blockhash=blockhash  # Use cached blockhash for quick execution
                )
                
                # Execute the swap
                result = await self.rust_core.execute_swap(swap_params)
                
                if not result.success:
                    logger.error(f"Back-run failed: {result.error}")
                    self.state.finish_trade()
                    return False
                    
                back_tx = result.signature
            else:
                # Simulate back-run
                await asyncio.sleep(0.5)
                back_tx = f"sim_{int(time.time())}_{uuid.uuid4().hex[:16]}"
            
            logger.success(f"Back-run completed: {back_tx}")
            
            # Wait for transactions to settle
            await asyncio.sleep(0.5)
            
            # Get balance after trade
            sol_after, token_balances_after = await self.get_balances(force_update=True)
            profit_amount = sol_after - sol_before
            
            # Double check token balance after trade
            token_after = token_balances_after.get(token_mint, 0)
            if token_after > 0.0001:  # Small amount might remain due to dust
                logger.warning(f"Token sale may not have completed! {token_after:.8f} {token_symbol} remaining")
            
            # Record execution time
            execution_time = (time.time() - start_time) * 1000  # milliseconds
            self.stats.execution_times.append(execution_time)
            
            # Update statistics
            self.stats.add_trade(token_mint, profit_amount, True)
            
            # Log profit
            logger.profit(profit_amount)
            
            # Results summary
            logger.section(f"Trade #{self.stats.completed} Results", char="-")
            logger.info(f"Token: {token_symbol} ({token_mint})")
            logger.info(f"Victim Size: {trade_info.get('amount', 0):.4f} SOL")
            logger.info(f"Front TX: {front_tx}")
            logger.info(f"Back TX: {back_tx}")
            logger.info(f"Profit: {profit_amount:.6f} SOL")
            logger.info(f"Execution Time: {execution_time:.2f}ms")
            logger.info(f"Total Profit: {self.stats.profit:.6f} SOL")
            logger.info(f"Balance: {self.stats.current_balance:.6f} SOL")
            
            # Periodic stats update
            if self.stats.completed % 5 == 0:
                self.stats.print_stats()
            
            # Add cooldown
            cooldown_time = int(os.environ.get("TRADE_COOLDOWN", "3000"))
            self.state.set_cooldown(cooldown_time / 1000)
            
            # Finish trade
            self.state.finish_trade()
            return True
        except Exception as e:
            logger.error(f"Error executing trade: {e}")
            logger.error(traceback.format_exc())
            self.state.finish_trade()
            return False
    
    async def validate_trade(self, trade_info):
        """Validate if a trade meets our criteria"""
        try:
            # Extract data
            amount = trade_info.get("amount", 0)
            token_mint = trade_info.get("token_mint", "")
            
            # Check trade size
            if amount < self.min_victim_size:
                logger.debug(f"Trade amount too small: {amount:.4f} SOL < {self.min_victim_size:.1f} SOL")
                self.stats.filtered_by_size += 1
                return False
                
            if amount > self.max_victim_size:
                logger.debug(f"Trade amount too large: {amount:.4f} SOL > {self.max_victim_size:.1f} SOL")
                self.stats.filtered_by_size += 1
                return False
            
            # Validate token mint
            if token_mint in self.state.blacklisted_token_mints:
                logger.debug(f"Token mint {token_mint} is blacklisted")
                self.stats.filtered_by_safety += 1
                return False
                
            # Only trade known tokens
            if token_mint not in self.state.valid_token_mints:
                logger.debug(f"Token mint {token_mint} is not in our validated list")
                self.stats.filtered_by_safety += 1
                return False
            
            # Check if we have enough combined SOL + WSOL
            # First check cached WebSocket balance if available
            if self.state.native_sol_balance > 0 and self.state.wsol_balance > 0:
                sol_balance = self.state.native_sol_balance
                wsol_balance = self.state.wsol_balance
            else:
                # Fall back to RPC call
                sol_balance, token_balances = await self.get_balances()
                wsol_balance = token_balances.get(WSOL_MINT, 0)
            
            total_balance = sol_balance + wsol_balance
            
            if total_balance < self.front_run_amount + self.min_sol_balance:
                logger.warning(f"Insufficient combined balance: SOL {sol_balance:.6f} + WSOL {wsol_balance:.6f} = {total_balance:.6f}")
                return False
            
            # Check if we need to unwrap some WSOL to SOL
            if sol_balance < self.min_sol_balance and wsol_balance > 0:
                logger.info(f"Main wallet SOL balance too low ({sol_balance:.6f} SOL). Need to unwrap some WSOL first.")
                return False
            
            # Trade passed validation
            return True
        except Exception as e:
            logger.error(f"Error validating trade: {e}")
            logger.error(traceback.format_exc())
            return False
    
    async def process_trade_opportunity(self, trade_info):
        """Process and execute a trade opportunity if profitable"""
        # Use semaphore to limit concurrent trades
        async with self.state.trade_semaphore:
            # Skip if we can't trade right now
            if not self.state.can_execute_trade():
                logger.debug("Skipping opportunity: Trading constraints active")
                return
            
            try:
                # Update counters
                self.stats.opportunities += 1
                
                # Make sure WSOL is initialized
                if self.stats.wsol_balance < self.min_wsol_balance:
                    logger.info("Initializing WSOL before trade...")
                    if not await self.initialize_wsol():
                        logger.error("Failed to initialize WSOL, skipping trade")
                        return
                
                # Validate the trade
                if not await self.validate_trade(trade_info):
                    logger.debug(f"Trade validation failed for {trade_info.get('token_mint', 'unknown')}")
                    return
                
                # Mark as viable opportunity
                self.stats.viable += 1
                
                # Execute the trade
                success = await self.execute_trade(trade_info)
                
                if success:
                    logger.success("Trade executed successfully")
                else:
                    logger.error("Trade execution failed")
                
            except Exception as e:
                logger.error(f"Error processing trade opportunity: {e}")
                logger.error(traceback.format_exc())

    async def fix_token_destination(self):
        """Fix token destination issues by ensuring proper ATAs"""
        logger.section("FIXING TOKEN DESTINATION", char="=")
        
        try:
            if not RUST_AVAILABLE or not self.rust_core:
                logger.error("Rust core not available, cannot fix token destination")
                return False
            
            # Get wallet public key
            public_key = self.rust_core.get_public_key()
            logger.info(f"Wallet address: {public_key}")
            
            # Reset ATA tracking to force recreation
            self.stats.atas_created = set()
            
            # Create ATAs for all known tokens
            for token_name, token_mint in KNOWN_TOKENS.items():
                logger.info(f"Creating ATA for {token_name} ({token_mint})...")
                
                # Create ATA with higher priority fee to ensure it gets processed
                high_priority = self.priority_fee * 2
                
                # Create ATA instruction with options if available
                if hasattr(self.rust_core, "create_ata_with_options"):
                    token_account = await self.rust_core.create_ata_with_options(
                        token_mint=token_mint,
                        owner=public_key,
                        priority_fee=high_priority,
                        compute_limit=200000  # Higher compute limit for ATA creation
                    )
                else:
                    # Use standard method
                    token_account = await self.rust_core.ensure_ata(token_mint)
                
                if token_account:
                    logger.success(f"Created ATA for {token_name}: {token_account}")
                    self.stats.atas_created.add(token_mint)
                    
                    # Update state mapping
                    self.state.update_token_account(token_mint, token_account)
                    
                    # Verify token account
                    verified = await self.verify_token_account(token_mint, token_account)
                    if verified:
                        logger.success(f"Token account verified for {token_name}")
                    else:
                        logger.warning(f"Token account verification failed for {token_name}")
                else:
                    logger.error(f"Failed to create ATA for {token_name}")
            
            # Modify execute_trade function to always verify token destination
            orig_execute_trade = self.execute_trade
            
            async def new_execute_trade(trade_info):
                # Ensure token account exists and is correctly owned
                token_mint = trade_info["token_mint"]
                token_symbol = next((symbol for symbol, address in KNOWN_TOKENS.items() 
                                   if address == token_mint), token_mint[:8])
                
                logger.info(f"Verifying token account for {token_symbol} ({token_mint})...")
                
                # Force ATA creation with higher priority
                token_account = await self.ensure_ata(token_mint)
                if not token_account:
                    logger.error(f"Failed to ensure ATA for {token_symbol}")
                    return False
                
                logger.info(f"Using token account: {token_account}")
                
                # Add token account to trade info
                trade_info["token_account"] = token_account
                
                # Execute original trade function with verified account
                return await orig_execute_trade(trade_info)
            
            # Replace the execute_trade method
            self.execute_trade = new_execute_trade
            
            # Modify the rust_core.execute_swap method to always use explicit destination
            if hasattr(self.rust_core, "execute_swap"):
                orig_execute_swap = self.rust_core.execute_swap
                
                async def new_execute_swap(swap_params):
                    # If buying tokens, make sure destination is explicitly set
                    if swap_params.is_buy and not hasattr(swap_params, "destination"):
                        # Get ATA for token
                        token_account = await self.ensure_ata(swap_params.token_mint)
                        if token_account:
                            swap_params.destination = token_account
                            logger.info(f"Setting explicit destination for swap: {token_account}")
                    
                    # Always use fresh blockhash for better transaction success
                    if not hasattr(swap_params, "recent_blockhash") or not swap_params.recent_blockhash:
                        blockhash = await self.refresh_blockhash()
                        if blockhash:
                            swap_params.recent_blockhash = blockhash
                    
                    return await orig_execute_swap(swap_params)
                
                # Replace the method if possible
                try:
                    self.rust_core.execute_swap = new_execute_swap
                except:
                    logger.warning("Could not patch rust_core.execute_swap method")
            
            logger.success("Token destination fix applied successfully!")
            return True
        except Exception as e:
            logger.error(f"Error fixing token destination: {e}")
            logger.error(traceback.format_exc())
            return False


###########################################
# SECTION 5: RAYDIUM MONITOR
###########################################

class RaydiumMonitor:
    """
    Monitor Raydium DEX transactions via WebSocket
    and identify profitable trading opportunities
    """
    
    def __init__(self, trading_core: TradingCore):
        """
        Initialize Raydium monitor
        
        Args:
            trading_core: Trading core instance
        """
        self.trading_core = trading_core
        self.ws_url = WS_URL
        self.api_key = API_KEY
        self.is_running = False
        self.ws = None
        self.subscription_id = None
        self.reconnect_delay = 1.0
        self.last_message_time = 0
        self.subscription_attempts = 0
        self.last_heartbeat = 0
        self.transaction_count = 0
        self.start_time = time.time()
        
        # Transaction processing stats
        self.processed_txs = set()
        self.blacklisted_txs = set()
        self.known_logs = set()
        self.transaction_types = {}  # instruction_type -> count
        
        # GPU acceleration if available
        self.use_gpu = TORCH_AVAILABLE and torch.cuda.is_available()
        if self.use_gpu:
            logger.info("GPU acceleration enabled for WebSocket data processing")
            # Create tensors for instruction pattern matching
            self.swap_pattern = torch.tensor([int(b) for b in RAYDIUM_SWAP_INSTRUCTION_DISCRIMINATOR], 
                                           device=GPU_DEVICE)
            self.route_pattern = torch.tensor([int(b) for b in RAYDIUM_ROUTE_INSTRUCTION_DISCRIMINATOR], 
                                            device=GPU_DEVICE)
            self.market_pattern = torch.tensor([int(b) for b in RAYDIUM_MARKET_DISCRIMINATOR], 
                                             device=GPU_DEVICE)
        else:
            # NumPy for CPU processing
            self.swap_pattern = np.array([int(b) for b in RAYDIUM_SWAP_INSTRUCTION_DISCRIMINATOR])
            self.route_pattern = np.array([int(b) for b in RAYDIUM_ROUTE_INSTRUCTION_DISCRIMINATOR])
            self.market_pattern = np.array([int(b) for b in RAYDIUM_MARKET_DISCRIMINATOR])
        
    async def connect(self):
        """
        Connect to WebSocket and subscribe to Raydium logs
        """
        if not WEBSOCKETS_AVAILABLE:
            logger.error("Cannot connect: websockets module not available")
            return
            
        # Reset subscription attempts on new connection
        self.subscription_attempts = 0
        
        headers = {}
        if self.api_key:
            headers["Authorization"] = f"Bearer {self.api_key}"
        
        try:
            logger.info(f"Connecting to WebSocket: {self.ws_url}")
            
            async with websockets.connect(
                self.ws_url,
                extra_headers=headers,
                ping_interval=30,
                ping_timeout=10,
                close_timeout=15
            ) as ws:
                self.ws = ws
                self.last_message_time = time.time()
                
                # Reset reconnect delay on successful connection
                self.reconnect_delay = 1.0
                
                # Subscribe to logs
                await self.subscribe_to_raydium_logs()
                
                # Process messages while running
                while self.is_running:
                    try:
                        # Set timeout to detect stalled connections
                        message = await asyncio.wait_for(ws.recv(), timeout=60)
                        self.last_message_time = time.time()
                        await self.process_message(message)
                    except asyncio.TimeoutError:
                        # No message received for a while, check connection
                        elapsed = time.time() - self.last_message_time
                        logger.warning(f"No messages received for {elapsed:.1f}s, checking connection...")
                        
                        try:
                            # Send ping to check connection
                            pong_waiter = await ws.ping()
                            await asyncio.wait_for(pong_waiter, timeout=10)
                            logger.info("Connection is alive (ping successful)")
                            self.last_message_time = time.time()
                        except (asyncio.TimeoutError, websockets.exceptions.ConnectionClosed):
                            logger.error("Connection is stale (ping failed), reconnecting...")
                            break
                    except websockets.exceptions.ConnectionClosed as e:
                        logger.error(f"WebSocket connection closed: {e}")
                        break
                    except Exception as e:
                        logger.error(f"Error processing WebSocket message: {e}")
                        logger.error(traceback.format_exc())
                        continue
                        
        except websockets.exceptions.ConnectionClosed as e:
            logger.error(f"WebSocket connection closed: {e}")
        except Exception as e:
            logger.error(f"WebSocket connection error: {e}")
            logger.error(traceback.format_exc())
        
        # Clean up and prepare for reconnection
        self.ws = None
        
        # Only try to reconnect if still running
        if self.is_running:
            await self.handle_reconnection()
    
    async def handle_reconnection(self):
        """
        Handle reconnection with exponential backoff
        """
        if not self.is_running:
            return
            
        logger.info(f"Reconnecting in {self.reconnect_delay:.1f} seconds...")
        await asyncio.sleep(self.reconnect_delay)
        
        # Implement exponential backoff with maximum delay
        self.reconnect_delay = min(self.reconnect_delay * 1.5, 30.0)
        
        # Try to reconnect
        asyncio.create_task(self.connect())
    
    async def subscribe_to_raydium_logs(self):
        """
        Subscribe to Raydium program logs with memcmp filters for better data
        """
        if not self.ws:
            logger.error("Cannot subscribe, WebSocket not connected")
            return False
        
        # Increment attempt counter
        self.subscription_attempts += 1
    
        if self.subscription_attempts > 5:
            logger.error(f"Failed to subscribe after {self.subscription_attempts} attempts")
            self.is_running = False
            return False
        
        try:
            # Subscribe to logs for the Raydium program with memcmp filters for specific instructions
            subscription_message = {
                "jsonrpc": "2.0",
                "id": 1,
                "method": "programSubscribe",
                "params": [
                    RAYDIUM_PROGRAM_ID,
                    {
                        "encoding": "base64",
                        "commitment": "processed",
                        "filters": [
                            {
                                "memcmp": {
                                    "offset": 0,
                                    "bytes": base58.b58encode(RAYDIUM_SWAP_INSTRUCTION_DISCRIMINATOR).decode('utf-8')
                                }
                            }
                        ]
                    }
                ]
            }
        
            await self.ws.send(json.dumps(subscription_message))
            response = await asyncio.wait_for(self.ws.recv(), timeout=10.0)
            response_data = json.loads(response)
        
            if "result" in response_data:
                subscription_id = response_data["result"]
                self.subscription_id = subscription_id
                logger.info(f"Subscribed to Raydium swaps successfully: ID {subscription_id}")
            
                # Also subscribe to route instructions
                route_subscription_message = {
                    "jsonrpc": "2.0",
                    "id": 2,
                    "method": "programSubscribe",
                    "params": [
                        RAYDIUM_PROGRAM_ID,
                        {
                            "encoding": "base64",
                            "commitment": "processed",
                            "filters": [
                                {
                                    "memcmp": {
                                        "offset": 0,
                                        "bytes": base58.b58encode(RAYDIUM_ROUTE_INSTRUCTION_DISCRIMINATOR).decode('utf-8')
                                    }
                                }
                            ]
                        }
                    }
                }
            
                await self.ws.send(json.dumps(route_subscription_message))
                route_response = await asyncio.wait_for(self.ws.recv(), timeout=10.0)
                route_data = json.loads(route_response)
            
                if "result" in route_data:
                    logger.info(f"Subscribed to Raydium routes successfully: ID {route_data['result']}")
            
                return True
            else:
               error_msg = response_data.get("error", {}).get("message", "Unknown error")
                logger.error(f"Failed to subscribe to program: {error_msg}")
                return False
        except asyncio.TimeoutError:
            logger.error("Timeout while subscribing to program")
            return False
        except Exception as e:
            logger.error(f"Error subscribing to program: {e}")
            logger.error(traceback.format_exc())
            return False
    
    async def start(self):
        """
        Start monitoring Raydium transactions
        """
        logger.info("Starting Raydium transaction monitor")
        self.is_running = True
        self.start_time = time.time()
        
        # Connect to WebSocket
        await self.connect()
    
    async def stop(self):
        """
        Stop monitoring Raydium transactions
        """
        logger.info("Stopping Raydium transaction monitor")
        self.is_running = False
        
        # Close WebSocket connection if open
        if self.ws:
            await self.ws.close()
            self.ws = None
    
    async def process_message(self, message):
        """
        Process WebSocket message
        
        Args:
            message: WebSocket message
        """
        try:
            # Parse JSON
            data = json.loads(message)
            
            # Heartbeat logs periodically to show we're still receiving messages
            current_time = time.time()
            if current_time - self.last_heartbeat > 60:  # Log every minute
                self.last_heartbeat = current_time
                runtime = current_time - self.start_time
                tx_per_min = (self.transaction_count / runtime) * 60 if runtime > 0 else 0
                logger.info(f"WebSocket active: processed {self.transaction_count} transactions ({tx_per_min:.1f}/min)")
            
            # Handle subscription confirmation
            if "id" in data and (data.get("id") == 1 or data.get("id") == 2) and "result" in data:
                logger.info(f"Subscription confirmed: {data['result']}")
                return
            
            # Process program notifications
            if "method" in data and data["method"] == "programNotification":
                params = data.get("params", {})
                result = params.get("result", {})
                value = result.get("value", {})
                
                # Extract transaction signature if available
                signature = value.get("signature", "unknown")
                
                # Skip if we've already processed this transaction
                if signature in self.processed_txs or signature in self.blacklisted_txs:
                    return
                
                # Mark as processed
                self.processed_txs.add(signature)
                
                # Process the binary data directly
                await self.process_program_data(value, signature)
            
        except json.JSONDecodeError:
            logger.error("Invalid JSON in WebSocket message")
        except Exception as e:
            logger.error(f"Error processing WebSocket message: {e}")
            logger.error(traceback.format_exc())
    
    async def process_program_data(self, value, signature):
        """
        Process Raydium program data from subscription
        
        Args:
            value: Program notification value
            signature: Transaction signature
        """
        try:
            # Skip if already processing a trade
            if self.trading_core.state.trades_in_progress >= self.trading_core.state.max_concurrency:
                return
            
            # Get the account data
            data = value.get("data", [])
            if not data or len(data) < 2:
                return
            
            # Decode the data (first part is base64 encoded)
            try:
                raw_data = base64.b64decode(data[0])
            except:
                logger.error("Failed to decode base64 data")
                return
            
            # Need at least 9 bytes for swap instruction
            if len(raw_data) < 9:
                return
            
            # Process the raw data to extract trade info
            trade_info = self.extract_trade_info(raw_data, signature)
            
            if trade_info:
                # Update transaction count
                self.transaction_count += 1
                
                # Process the trade asynchronously
                asyncio.create_task(self.trading_core.process_trade_opportunity(trade_info))
        except Exception as e:
            logger.error(f"Error processing program data: {e}")
            logger.error(traceback.format_exc())
    
    def extract_trade_info(self, raw_data, signature):
        """
        Extract trade information from raw binary data using GPU acceleration if available
        
        Args:
            raw_data: Raw binary data
            signature: Transaction signature
            
        Returns:
            Dict with trade info or None if not relevant
        """
        try:
            # Check if instruction pattern matches any known patterns using GPU or CPU
            instruction_type = None
            instruction_offset = 0
            
            if self.use_gpu:
                # Convert raw data to tensor
                data_tensor = torch.tensor([int(b) for b in raw_data[:8]], device=GPU_DEVICE)
                
                # Check for matches
                if torch.all(data_tensor == self.swap_pattern):
                    instruction_type = 0x01
                elif torch.all(data_tensor == self.route_pattern):
                    instruction_type = 0x03
                elif torch.all(data_tensor == self.market_pattern):
                    instruction_type = 0x09
            else:
                # Use NumPy on CPU
                data_array = np.array([int(b) for b in raw_data[:8]])
                
                # Check for matches
                if np.array_equal(data_array, self.swap_pattern):
                    instruction_type = 0x01
                elif np.array_equal(data_array, self.route_pattern):
                    instruction_type = 0x03
                elif np.array_equal(data_array, self.market_pattern):
                    instruction_type = 0x09
            
            # If not one of our target instructions, skip
            if instruction_type not in [0x01, 0x03, 0x09]:
                return None
            
            # Track instruction types
            if instruction_type not in self.transaction_types:
                self.transaction_types[instruction_type] = 0
            self.transaction_types[instruction_type] += 1
            
            # Extract amount from the binary data (next 8 bytes after discriminator)
            amount_bytes = raw_data[8:16]
            amount = int.from_bytes(amount_bytes, byteorder="little") / 1e9
            
            # Extract token mint from AMM ID or trade_info
            token_mint = TOKEN_MINT  # Default to BONK
            
            # Look for token mint in data if present
            # This is a simplified approach - actual extraction would depend on Raydium's instruction format
            if len(raw_data) >= 64:  # Minimum size for a swap with token mint
                # For AMM swaps, the token mint could be at different offsets depending on the instruction
                possible_token_offsets = [24, 32, 56]
                
                for offset in possible_token_offsets:
                    if offset + 32 <= len(raw_data):
                        potential_token = raw_data[offset:offset+32].hex()
                        # Check if this looks like a token address
                        if any(mint.lower() == potential_token.lower() for mint in KNOWN_TOKENS.values()):
                            token_mint = potential_token
                            break
            
            # Create trade info
            trade_info = {
                "instruction_type": instruction_type,
                "amount": amount,
                "is_buy": True,  # Front-running a buy
                "token_mint": token_mint,
                "timestamp": time.time(),
                "signature": signature,
                "raw_data": raw_data.hex()  # Store as hex for logging
            }
            
            # Get token symbol if available
            token_symbol = next((symbol for symbol, address in KNOWN_TOKENS.items() 
                               if address == token_mint), token_mint[:8])
            
            # Log opportunity
            logger.info(f"Found trade opportunity: {amount:.4f} SOL for {token_symbol} (type: 0x{instruction_type:02x})")
            
            return trade_info
        except Exception as e:
            logger.error(f"Error extracting trade info: {e}")
            logger.error(traceback.format_exc())
            return None


###########################################
# SECTION 6: MAIN APPLICATION LOGIC
###########################################

class SolanaRaydiumTradingBot:
    """Main trading bot class"""
    
    def __init__(self, simulation_mode=False):
        """Initialize the trading bot"""
        self.simulation_mode = simulation_mode
        logger.info(f"Initializing Solana Trading Bot in {'simulation' if simulation_mode else 'live'} mode")
        
        # State tracking
        self.is_running = False
        self.restart_attempts = 0
        
        # Core components
        self.trading_core = TradingCore()
        self.monitor = None
        
        # Task tracking
        self.tasks = []
        
        # Set up signal handling for graceful shutdown
        try:
            signal.signal(signal.SIGINT, self.handle_shutdown)
            signal.signal(signal.SIGTERM, self.handle_shutdown)
        except (ValueError, AttributeError):
            # Signal handling might not work in some environments
            logger.warning("Could not set up signal handlers")
        
        # HTTP session for cleanup
        self.sessions_to_close = []
    
    def handle_shutdown(self, signum, frame):
        """Handle graceful shutdown on signal"""
        logger.info("Shutdown signal received, stopping trading bot...")
        self.is_running = False
        
        # Cancel background tasks
        for task in self.tasks:
            if not task.done():
                task.cancel()
                
        # Stop the monitor if it exists
        if self.monitor:
            asyncio.create_task(self.monitor.stop())
    
    async def initialize(self):
        """Initialize the bot components"""
        try:
            logger.info("Initializing trading bot components")
            
            # Initialize HTTP session
            await self.trading_core.initialize_http()
            
            # Initialize trading core
            if RUST_AVAILABLE and not self.simulation_mode:
                success = await self.trading_core.initialize_rust_core()
                if not success:
                    logger.error("Failed to initialize Rust trading core")
                    if self.simulation_mode:
                        logger.info("Continuing in simulation mode")
                    else:
                        return False
            
            # Initialize monitor
            self.monitor = RaydiumMonitor(self.trading_core)
            
            # Initialize WSOL if needed
            if not self.simulation_mode or RUST_AVAILABLE:
                await self.trading_core.initialize_wsol()
            
            # Get initial balances
            await self.trading_core.get_balances(force_update=True)
            
            # Fix token destinations to ensure proper trading
            await self.trading_core.fix_token_destination()
            
            logger.info("Trading bot initialized successfully")
            return True
        except Exception as e:
            logger.error(f"Error initializing trading bot: {e}")
            logger.error(traceback.format_exc())
            return False
    
    async def start_monitor(self):
        """Start the Raydium transaction monitor"""
        if not self.monitor:
            logger.error("Monitor not initialized")
            return False
            
        try:
            await self.monitor.start()
            return True
        except Exception as e:
            logger.error(f"Error starting monitor: {e}")
            logger.error(traceback.format_exc())
            return False
    
    async def check_health(self):
        """Periodically check system health and log status"""
        while self.is_running:
            try:
                # Get current balances
                sol_balance, token_balances = await self.trading_core.get_balances()
                
                # Log heartbeat
                runtime = time.time() - self.trading_core.stats.start_time
                hours = runtime / 3600
                
                profit = sol_balance - self.trading_core.stats.start_balance
                
                logger.info(f"Bot running - SOL: {sol_balance:.6f}, "
                           f"WSOL: {self.trading_core.stats.wsol_balance:.6f}, "
                           f"Profit: {profit:.6f}, "
                           f"Runtime: {int(hours)}h {int((hours % 1) * 60)}m")
                
                # Check for auto restart if needed
                if not self.monitor.is_running and self.is_running:
                    logger.warning("Monitor not running, attempting to restart")
                    self.restart_attempts += 1
                    
                    if self.restart_attempts <= 3:
                        logger.info(f"Restart attempt {self.restart_attempts}/3")
                        await asyncio.sleep(1.0)
                        asyncio.create_task(self.start_monitor())
                    else:
                        logger.error(f"Exceeded maximum restart attempts (3)")
                        self.is_running = False
                        break
                        
                # Reset restart attempts if monitor is running
                if self.monitor.is_running:
                    self.restart_attempts = 0
            except Exception as e:
                logger.error(f"Error in health check: {e}")
            
            # Wait before next check
            await asyncio.sleep(60)  # Check every minute
    
    async def close_sessions(self):
        """Close all open aiohttp sessions"""
        for session in self.sessions_to_close:
            try:
                if session and not session.closed:
                    await session.close()
            except:
                pass
    
    async def run(self):
        """Run the trading bot"""
        welcome_message = """
╔══════════════════════════════════════════════════════════════╗
║                                                              ║
║  Solana Raydium DEX Trading Bot                              ║
║  ───────────────────────────────                            ║
║                                                              ║
║  Monitoring Raydium transactions...                          ║
║                                                              ║
╚══════════════════════════════════════════════════════════════╝
"""
        print(welcome_message)
        
        # Mark as running
        self.is_running = True
        
        try:
            # Initialize components
            if not await self.initialize():
                logger.error("Failed to initialize trading bot")
                return
            
            # Keep track of sessions to close
            if self.trading_core.http_session:
                self.sessions_to_close.append(self.trading_core.http_session)
            
            # Start transaction monitor
            monitor_task = asyncio.create_task(self.start_monitor())
            self.tasks.append(monitor_task)
            
            # Start health check
            health_task = asyncio.create_task(self.check_health())
            self.tasks.append(health_task)
            
            # Wait until shutdown signal
            while self.is_running:
                await asyncio.sleep(0.1)
                
        except asyncio.CancelledError:
            logger.info("Bot execution cancelled")
        except Exception as e:
            logger.error(f"Error in main execution loop: {e}")
            logger.error(traceback.format_exc())
        finally:
            # Stop components
            logger.info("Stopping bot components...")
            
            # Stop monitor
            if self.monitor:
                await self.monitor.stop()
            
            # Cancel tasks
            for task in self.tasks:
                if not task.done():
                    task.cancel()
            
            # Print final stats
            self.trading_core.stats.print_stats()
            
            # Close sessions
            await self.close_sessions()
            
            logger.info("Trading bot stopped")
    
    def start(self):
        """Start the trading bot in the current event loop"""
        if self.is_running:
            logger.warning("Trading bot is already running")
            return
        
        try:
            # Run in asyncio event loop
            asyncio.run(self.run())
        except Exception as e:
            logger.critical(f"Failed to start trading bot: {e}")
            logger.critical(traceback.format_exc())

###########################################
# SECTION 7: UTILITY FUNCTIONS
###########################################

def print_environment_info():
    """Print information about the environment"""
    print("=" * 60)
    print("Solana Raydium MEV Trading Bot Environment")
    print("=" * 60)
    print(f"Python version: {platform.python_version()}")
    print(f"System: {platform.system()} {platform.release()}")
    
    # Check for NumPy
    try:
        import numpy as np
        print(f"NumPy version: {np.__version__}")
    except ImportError:
        print("NumPy: Not available")
    
    # Check for PyTorch
    try:
        import torch
        print(f"PyTorch version: {torch.__version__}")
        print(f"CUDA available: {torch.cuda.is_available()}")
        if torch.cuda.is_available():
            print(f"CUDA version: {torch.version.cuda}")
            print(f"GPU device: {torch.cuda.get_device_name(0)}")
    except ImportError:
        print("PyTorch: Not available")
    
    print("=" * 60)

def set_process_priority():
    """Set process priority for better performance"""
    try:
        if platform.system() == "Windows":
            # Set high priority on Windows
            try:
                import psutil
                process = psutil.Process(os.getpid())
                process.nice(psutil.HIGH_PRIORITY_CLASS)
                logger.info("Process priority set to HIGH_PRIORITY_CLASS")
            except ImportError:
                logger.warning("psutil not available, can't set process priority")
        elif platform.system() == "Linux":
            # Set high priority on Linux
            os.nice(-10)  # -20 is highest, 19 is lowest
            logger.info("Process priority set to nice -10")
        else:
            logger.info(f"Process priority not adjusted for {platform.system()}")
    except Exception as e:
        logger.warning(f"Failed to set process priority: {e}")

def parse_arguments():
    """Parse command line arguments"""
    parser = argparse.ArgumentParser(description="Solana Raydium DEX Trading Bot")
    parser.add_argument("--simulation", action="store_true", help="Run in simulation mode")
    parser.add_argument("--debug", action="store_true", help="Enable debug logging")
    parser.add_argument("--unwrap", action="store_true", help="Unwrap all WSOL and exit")
    parser.add_argument("--balance", action="store_true", help="Show balance and exit")
    parser.add_argument("--fix-tokens", action="store_true", help="Fix token destination issues")
    return parser.parse_args()

async def unwrap_all_wsol():
    """Unwrap all WSOL to SOL and exit"""
    logger.info("Unwrapping all WSOL to SOL and exiting")
    
    try:
        # Create WSOL wrapper
        wrapper = await create_wsol_wrapper()
        
        # Check WSOL balance
        sol_balance, wsol_balance = await wrapper.get_balances()
        
        logger.info(f"Current balances - SOL: {sol_balance:.6f}, WSOL: {wsol_balance:.6f}")
        
        if wsol_balance <= 0:
            logger.info("No WSOL to unwrap")
            return 0
        
        # Unwrap all WSOL
        tx_hash = await wrapper.unwrap_sol()
        
        if tx_hash:
            logger.success(f"Successfully unwrapped {wsol_balance:.6f} WSOL to SOL: {tx_hash}")
            
            # Check new balance
            sol_balance, wsol_balance = await wrapper.get_balances()
            logger.info(f"New balances - SOL: {sol_balance:.6f}, WSOL: {wsol_balance:.6f}")
            
            # Close wrapper
            await wrapper.close()
            return 0
        else:
            logger.error("Failed to unwrap WSOL")
            return 1
    except Exception as e:
        logger.error(f"Error unwrapping WSOL: {e}")
        logger.error(traceback.format_exc())
        return 1

async def show_balances():
    """Show balances and exit"""
    logger.info("Checking balances and exiting")
    
    try:
        # Create trading core
        trading_core = TradingCore()
        
        if RUST_AVAILABLE:
            # Initialize with Rust core
            success = await trading_core.initialize_rust_core()
            if not success:
                logger.error("Failed to initialize trading core")
                return 1
        
        # Get balances
        sol_balance, token_balances = await trading_core.get_balances(force_update=True)
        
        # Display balances
        logger.info(f"SOL Balance: {sol_balance:.6f} SOL")
        
        for token_mint, balance in token_balances.items():
            if token_mint == WSOL_MINT:
                logger.info(f"WSOL Balance: {balance:.6f} WSOL")
            else:
                # Try to find token name
                token_name = next((name for name, mint in KNOWN_TOKENS.items() if mint == token_mint), token_mint[:8])
                logger.info(f"{token_name} Balance: {balance:.6f}")
        
        # Calculate total balance
        total_balance = sol_balance + token_balances.get(WSOL_MINT, 0)
        logger.info(f"Total Balance (SOL + WSOL): {total_balance:.6f} SOL")
        
        return 0
    except Exception as e:
        logger.error(f"Error checking balances: {e}")
        logger.error(traceback.format_exc())
        return 1

async def fix_token_destination():
    """Fix token destination issues and exit"""
    logger.info("Fixing token destination issues and exiting")
    
    try:
        # Create trading core
        trading_core = TradingCore()
        
        if RUST_AVAILABLE:
            # Initialize with Rust core
            success = await trading_core.initialize_rust_core()
            if not success:
                logger.error("Failed to initialize trading core")
                return 1
                
            # Apply fix
            success = await trading_core.fix_token_destination()
            if success:
                logger.success("Token destination issues fixed successfully")
                return 0
            else:
                logger.error("Failed to fix token destination issues")
                return 1
        else:
            logger.error("Rust core not available, cannot fix token destination issues")
            return 1
    except Exception as e:
        logger.error(f"Error fixing token destination: {e}")
        logger.error(traceback.format_exc())
        return 1

async def run_special_command(args):
    """Run special commands based on arguments"""
    if args.unwrap:
        return await unwrap_all_wsol()
        
    if args.balance:
        return await show_balances()
        
    if args.fix_tokens:
        return await fix_token_destination()
        
    return None  # No special command executed

###########################################
# SECTION 8: MAIN FUNCTION
###########################################

def main():
    """Main entry point"""
    # Parse arguments
    args = parse_arguments()
    
    # Configure log level
    if args.debug:
        # Configure logger to debug level
        logger.change_level(logging.DEBUG)
    
    try:
        # Print environment info
        print_environment_info()
        
        # Set process priority
        set_process_priority()
        
        # Check if special commands should be executed
        special_result = asyncio.run(run_special_command(args))
        if special_result is not None:
            return special_result
        
        # Create and start trading bot
        bot = SolanaRaydiumTradingBot(simulation_mode=args.simulation)
        bot.start()
        
        return 0
    except KeyboardInterrupt:
        logger.info("Bot terminated by user")
        return 0
    except Exception as e:
        logger.critical(f"Unhandled exception: {e}")
        logger.critical(traceback.format_exc())
        return 1

if __name__ == "__main__":
    # Set appropriate event loop policy for Windows
    if platform.system() == "Windows":
        asyncio.set_event_loop_policy(asyncio.WindowsSelectorEventLoopPolicy())
    
    # Run main function
    exit_code = main()
    sys.exit(exit_code) fix the order of the code and fix it rewrite all of the code back in proper format