// CURRENT CODE (PROBLEMATIC):

// In SolanaTrader::new method:
// Clean RPC URL by removing trailing slash if present
let rpc_url = if rpc_url.ends_with('/') {
    rpc_url.trim_end_matches('/').to_string()
} else {
    rpc_url
};

// Create RPC client with processed commitment and authentication
let rpc_client = {
    // Set timeout and commitment
    let commitment_config = CommitmentConfig::processed();
    let timeout = Duration::from_millis(500);
    
    // Create client with timeout and commitment
    let client = RpcClient::new_with_timeout_and_commitment(
        rpc_url.clone(),  // <-- PROBLEM: Not adding API key as query parameter
        timeout,
        commitment_config,
    );
    
    Arc::new(client)
};

// FIXED CODE:

// In SolanaTrader::new method:
// For RPC, always remove trailing slash
let rpc_url = rpc_url.trim_end_matches('/').to_string();

// For WebSocket, always keep trailing slash
let ws_url = if !ws_url.ends_with('/') {
    format!("{}/", ws_url)
} else {
    ws_url
};

// Create RPC client with API key in query parameter
let rpc_client = {
    // Add API key as query parameter for RPC
    let rpc_url_with_auth = if let Some(key) = &api_key {
        format!("{}?api-key={}", rpc_url, key)
    } else {
        rpc_url.clone()
    };
    
    // Set timeout and commitment
    let commitment_config = CommitmentConfig::processed();
    let timeout = Duration::from_secs(30);  // Increased timeout for reliability
    
    // Create client with timeout and commitment
    let client = RpcClient::new_with_timeout_and_commitment(
        rpc_url_with_auth,  // <-- FIXED: Using URL with API key
        timeout,
        commitment_config,
    );
    
    Arc::new(client)
};

// For WebSocket connections:
// Instead of adding API key to URL, use header-based authentication
// Example for any WebSocket connection code:
let mut request = Request::builder()
    .uri(ws_url)  // Use ws_url WITH trailing slash
    .header("User-Agent", "solana-cli 1.18.23")
    .header("Content-Type", "application/json")
    .header("Solana-Client", "SolanaLabs")
    .header("api-key", api_key)  // <-- FIXED: API key in header, not URL
    .body(())?;use base64;
use log::{debug, error, info};
use pyo3::exceptions::{PyFileNotFoundError, PyRuntimeError, PyValueError};
use pyo3::prelude::*;
use pyo3::types::PyDict;
use solana_client::rpc_client::RpcClient;
use solana_client::rpc_config::RpcSendTransactionConfig;
use solana_sdk::commitment_config::{CommitmentConfig, CommitmentLevel};
use solana_sdk::compute_budget::ComputeBudgetInstruction;
use solana_sdk::hash::Hash;
use solana_sdk::instruction::{AccountMeta, Instruction};
use solana_sdk::program_pack::Pack;
use solana_sdk::pubkey::Pubkey;
use solana_sdk::signature::{read_keypair_file, Keypair, Signature, Signer};
use solana_sdk::transaction::Transaction;
use solana_transaction_status::UiTransactionEncoding;
use spl_associated_token_account::{
    get_associated_token_address, instruction::create_associated_token_account_idempotent,
};
use spl_token;
use std::env;
use std::path::Path;
use std::str::FromStr;
use std::sync::Arc;
use std::time::{Duration, Instant};
// Fast blockhash caching using RwLock instead of Mutex
use parking_lot::RwLock;
// Concurrent map for caching
use dashmap::DashMap;
// Optional async support
use once_cell::sync::OnceCell;
use tokio::runtime::Runtime;
// Add header support for authentication
use reqwest::header::{HeaderMap, HeaderValue, AUTHORIZATION, CONTENT_TYPE};

// Fast RwLock-based blockhash cache
struct FastBlockhashCache {
    blockhash: RwLock<Hash>,
    last_update: RwLock<Instant>,
    update_interval: Duration,
    rpc_client: Arc<RpcClient>,
}

impl FastBlockhashCache {
    fn new(rpc_client: Arc<RpcClient>, update_interval_seconds: u64) -> Self {
        // More robust initial blockhash retrieval with retry logic
        let mut attempts = 0;
        let max_attempts = 5;
        let mut blockhash = None;
        
        while attempts < max_attempts {
            match rpc_client.get_latest_blockhash() {
                Ok(hash) => {
                    blockhash = Some(hash);
                    info!("Successfully retrieved initial blockhash");
                    break;
                }
                Err(e) => {
                    error!("Error getting initial blockhash (attempt {}/{}): {}", 
                            attempts + 1, max_attempts, e);
                    attempts += 1;
                    if attempts < max_attempts {
                        std::thread::sleep(Duration::from_millis(500));
                    }
                }
            }
        }
        
        // If all attempts failed, use a default blockhash (will be updated later)
        let blockhash = blockhash.unwrap_or_else(|| {
            error!("Warning: Using placeholder blockhash, will update shortly");
            Hash::default()
        });

        Self {
            blockhash: RwLock::new(blockhash),
            last_update: RwLock::new(Instant::now()),
            update_interval: Duration::from_secs(update_interval_seconds),
            rpc_client,
        }
    }

    fn get_blockhash(&self) -> Hash {
        // Check if we need to update using a read lock first
        let should_update = {
            let last_update = self.last_update.read();
            last_update.elapsed() >= self.update_interval
        };

        // If update is needed, get a new blockhash
        if should_update {
            // Simply do it synchronously for now to avoid threading issues
            match self.rpc_client.get_latest_blockhash() {
                Ok(new_hash) => {
                    *self.blockhash.write() = new_hash;
                    *self.last_update.write() = Instant::now();
                }
                Err(e) => {
                    error!("Failed to update blockhash: {}", e);
                }
            }
        }

        // Return current blockhash
        *self.blockhash.read()
    }

    fn force_update(&self) -> Hash {
        match self.rpc_client.get_latest_blockhash() {
            Ok(new_hash) => {
                *self.blockhash.write() = new_hash;
                *self.last_update.write() = Instant::now();
                new_hash
            }
            Err(e) => {
                error!("Failed to force update blockhash: {}", e);
                *self.blockhash.read() // Return current one
            }
        }
    }
}

// Optimized API response cache
struct JupiterCache {
    routes: DashMap<String, (serde_json::Value, Instant)>,
    ttl: Duration,
}

impl JupiterCache {
    fn new(ttl_seconds: u64) -> Self {
        Self {
            routes: DashMap::new(),
            ttl: Duration::from_secs(ttl_seconds),
        }
    }

    fn get(&self, key: &str) -> Option<serde_json::Value> {
        if let Some(entry) = self.routes.get(key) {
            if entry.1.elapsed() < self.ttl {
                return Some(entry.0.clone());
            }
        }
        None
    }

    fn set(&self, key: String, value: serde_json::Value) {
        self.routes.insert(key, (value, Instant::now()));
    }

    fn clear_expired(&self) {
        let now = Instant::now();
        let expired_keys: Vec<String> = self
            .routes
            .iter()
            .filter(|r| now.duration_since(r.value().1) >= self.ttl)
            .map(|r| r.key().clone())
            .collect();

        for key in expired_keys {
            self.routes.remove(&key);
        }
    }
}

// Token decimals cache using DashMap
static TOKEN_DECIMALS_CACHE: once_cell::sync::Lazy<DashMap<String, u8>> =
    once_cell::sync::Lazy::new(|| DashMap::new());

// Fast blockhash cache
static BLOCKHASH_CACHE: once_cell::sync::Lazy<OnceCell<Arc<FastBlockhashCache>>> =
    once_cell::sync::Lazy::new(|| OnceCell::new());

// Jupiter API cache
static JUPITER_CACHE: once_cell::sync::Lazy<OnceCell<Arc<JupiterCache>>> =
    once_cell::sync::Lazy::new(|| OnceCell::new());

// Core constants
const LAMPORTS_PER_SOL: u64 = 1_000_000_000;
const WSOL_ADDRESS: &str = "So11111111111111111111111111111111111111112";
const TOKEN_PROGRAM_ID: &str = "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA";
const RAYDIUM_PROGRAM_ID: &str = "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8";
const SERUM_PROGRAM_ID: &str = "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin";

// Jupiter API constants - Updated for v6
const JUPITER_QUOTE_API: &str = "https://quote-api.jup.ag/v6/quote";
const JUPITER_SWAP_API: &str = "https://quote-api.jup.ag/v6/swap-instructions";

// Transaction and trading constants
const RAYDIUM_SWAP_INSTRUCTION: u8 = 9;
const DEFAULT_COMPUTE_LIMIT: u32 = 200_000;
const DEFAULT_PRIORITY_FEE: u64 = 1_000_000; // 0.001 SOL
const DEFAULT_SLIPPAGE: f64 = 0.01; // 1%
const DEFAULT_MAX_RETRIES: usize = 3;

// Balance safety thresholds
const DEFAULT_MIN_SOL_BALANCE: f64 = 0.03;
const DEFAULT_MIN_WSOL_BALANCE: f64 = 0.02;

// Simplified error handling
struct PyError(String);

impl From<PyError> for PyErr {
    fn from(err: PyError) -> PyErr {
        PyRuntimeError::new_err(err.0)
    }
}

// Initialize tokio runtime for async operations if needed
fn get_tokio_runtime() -> &'static Runtime {
    static RUNTIME: OnceCell<Runtime> = OnceCell::new();
    RUNTIME.get_or_init(|| Runtime::new().expect("Failed to create tokio runtime"))
}

/// Represents dynamic Raydium swap accounts
#[derive(Debug, Clone)]
struct RaydiumSwapAccounts {
    amm_id: String,
    amm_authority: String,
    amm_open_orders: String,
    amm_target_orders: String,
    pool_coin_token_account: String,
    pool_pc_token_account: String,
    serum_program_id: String,
    serum_market: String,
    serum_bids: String,
    serum_asks: String,
    serum_event_queue: String,
    serum_coin_vault: String,
    serum_pc_vault: String,
    serum_vault_signer: String,
    token_mint: String,
    token_program_id: String,
}

/// Main Solana trading class
#[pyclass]
struct SolanaTrader {
    keypair: Arc<Keypair>,
    rpc_client: Arc<RpcClient>,
    rpc_url: String,
    ws_url: String,
    compute_limit: u32,
    priority_fee: u64,
    skip_preflight: bool,
    max_retries: usize,
    min_sol_balance: f64,
    min_wsol_balance: f64,
    wsol_address: String,
    token_program_id: String,
    system_program_id: String,
    raydium_program_id: String,
    serum_program_id: String,
    keypair_path: String,
    http_client: reqwest::blocking::Client,
    api_key: Option<String>, // Add API key field for authentication
}

#[pymethods]
impl SolanaTrader {
    /// Initialize the SolanaTrader with configuration
    #[new]
    fn new(
        rpc_url: String,
        ws_url: String,
        keypair_path: String,
        compute_limit: Option<u32>,
        api_key: Option<String>, // Add API key parameter
    ) -> PyResult<Self> {
        // Clean RPC URL by removing trailing slash if present
        let rpc_url = if rpc_url.ends_with('/') {
            rpc_url.trim_end_matches('/').to_string()
        } else {
            rpc_url
        };

        // Tokio runtime initialization
        let _ = get_tokio_runtime();

        // Load environment variables if .env file exists
        let _ = dotenv::dotenv();

        // Get API key from parameter or environment variable
        let api_key = api_key.or_else(|| env::var("HELIUS_API_KEY").ok());
        if let Some(key) = &api_key {
            info!("Using API key for authentication");
        }

        // Keypair loading with robust error handling
        let keypair = if Path::new(&keypair_path).exists() {
            // First, try to read as JSON
            match read_keypair_file(&keypair_path) {
                Ok(kp) => kp,
                Err(_) => {
                    // If JSON fails, try to read as binary
                    match std::fs::read(&keypair_path) {
                        Ok(bytes) => {
                            if bytes.len() == 64 {
                                match Keypair::from_bytes(&bytes) {
                                    Ok(kp) => kp,
                                    Err(e) => {
                                        return Err(PyValueError::new_err(format!(
                                            "Invalid binary keypair: {}",
                                            e
                                        )))
                                    }
                                }
                            } else {
                                // Try base58 decoding
                                match bs58::decode(std::str::from_utf8(&bytes).unwrap_or(""))
                                    .into_vec()
                                    .map(|secret_key| Keypair::from_bytes(&secret_key))
                                {
                                    Ok(Ok(kp)) => kp,
                                    _ => {
                                        return Err(PyValueError::new_err(
                                            "Could not parse keypair file in any format",
                                        ))
                                    }
                                }
                            }
                        }
                        Err(e) => {
                            return Err(PyRuntimeError::new_err(format!(
                                "Failed to read keypair file: {}",
                                e
                            )))
                        }
                    }
                }
            }
        } else {
            return Err(PyFileNotFoundError::new_err(format!(
                "Keypair file not found: {}",
                keypair_path
            )));
        };

        // Create RPC client with processed commitment and authentication
        // Fix: Use available methods in solana 1.18.x
        let rpc_client = {
            // Set timeout and commitment
            let commitment_config = CommitmentConfig::processed();
            let timeout = Duration::from_millis(500);
            
            // Create client with timeout and commitment
            // For Solana 1.18.x, we need to use the correct available constructors
            let client = RpcClient::new_with_timeout_and_commitment(
                rpc_url.clone(),
                timeout,
                commitment_config,
            );
            
            Arc::new(client)
        };

        // Read environment variables with fallbacks
        let compute = compute_limit.unwrap_or_else(|| {
            env::var("COMPUTE_LIMIT")
                .map(|v| v.parse::<u32>().unwrap_or(DEFAULT_COMPUTE_LIMIT))
                .unwrap_or(DEFAULT_COMPUTE_LIMIT)
        });

        let priority_fee = env::var("PRIORITY_FEE")
            .map(|v| v.parse::<u64>().unwrap_or(DEFAULT_PRIORITY_FEE))
            .unwrap_or(DEFAULT_PRIORITY_FEE);

        let skip_preflight = env::var("SKIP_PREFLIGHT")
            .map(|v| v.parse::<bool>().unwrap_or(true))
            .unwrap_or(true);

        let max_retries = env::var("MAX_RETRIES")
            .map(|v| v.parse::<usize>().unwrap_or(DEFAULT_MAX_RETRIES))
            .unwrap_or(DEFAULT_MAX_RETRIES);

        let min_sol_balance = env::var("MIN_SOL_BALANCE")
            .map(|v| v.parse::<f64>().unwrap_or(DEFAULT_MIN_SOL_BALANCE))
            .unwrap_or(DEFAULT_MIN_SOL_BALANCE);

        let min_wsol_balance = env::var("MIN_WSOL_BALANCE")
            .map(|v| v.parse::<f64>().unwrap_or(DEFAULT_MIN_WSOL_BALANCE))
            .unwrap_or(DEFAULT_MIN_WSOL_BALANCE);

        // Create optimized HTTP client with authentication
        let http_client = {
            let builder = reqwest::blocking::Client::builder()
                .timeout(Duration::from_millis(500))
                .connect_timeout(Duration::from_millis(300))
                .pool_max_idle_per_host(32);
            
            // Create default headers
            let mut headers = HeaderMap::new();
            
            // Add Solana CLI User-Agent header
            if let Ok(value) = HeaderValue::from_str("solana-cli 1.18.23 (src:aeb3a2e1; feat:4215500110, client:SolanaLabs)") {
                headers.insert(reqwest::header::USER_AGENT, value);
                headers.insert(CONTENT_TYPE, HeaderValue::from_static("application/json"));
            }
            
            // Add authentication headers if API key is provided
            if let Some(key) = &api_key {
                let auth_value = format!("Bearer {}", key);
                if let Ok(value) = HeaderValue::from_str(&auth_value) {
                    headers.insert(AUTHORIZATION, value);
                }
            }
            
            // Build the client with headers
            builder.default_headers(headers).build()
        }.unwrap_or_else(|_| reqwest::blocking::Client::new());

        // Initialize fast blockhash cache if not already initialized
        BLOCKHASH_CACHE.get_or_init(|| {
            let cache = FastBlockhashCache::new(
                rpc_client.clone(),
                2, // Update every 2 seconds
            );
            Arc::new(cache)
        });

        // Initialize Jupiter cache if not already initialized
        JUPITER_CACHE.get_or_init(|| {
            let cache = JupiterCache::new(10); // 10 second TTL
            Arc::new(cache)
        });

        // Start a periodic cache cleanup thread
        {
            let jupiter_cache = JUPITER_CACHE.get().unwrap().clone();
            std::thread::spawn(move || loop {
                std::thread::sleep(Duration::from_secs(60));
                jupiter_cache.clear_expired();
                debug!("Cleared expired Jupiter cache entries");
            });
        }

        info!(
            "Initialized trader with compute_limit: {}, priority_fee: {}",
            compute, priority_fee
        );

        Ok(Self {
            keypair: Arc::new(keypair),
            rpc_client,
            rpc_url,
            ws_url,
            compute_limit: compute,
            priority_fee,
            skip_preflight,
            max_retries,
            min_sol_balance,
            min_wsol_balance,
            wsol_address: WSOL_ADDRESS.to_string(),
            token_program_id: TOKEN_PROGRAM_ID.to_string(),
            system_program_id: "11111111111111111111111111111111".to_string(),
            raydium_program_id: RAYDIUM_PROGRAM_ID.to_string(),
            serum_program_id: SERUM_PROGRAM_ID.to_string(),
            keypair_path,
            http_client,
            api_key,
        })
    }

    /// Execute token swap using Jupiter (Solana's DEX aggregator) - Optimized implementation
    fn execute_jupiter_swap(
        &self,
        py: Python<'_>,
        input_mint: String,
        output_mint: String,
        amount_sol: f64,
        slippage_percent: Option<f64>,
        priority_multiplier: Option<u64>,
    ) -> PyResult<String> {
        // Convert amount to lamports
        let amount_lamports = (amount_sol * LAMPORTS_PER_SOL as f64).round() as u64;

        // Dynamic slippage calculation
        let slippage = match slippage_percent {
            Some(val) => val / 100.0,
            None => DEFAULT_SLIPPAGE,
        };
        let slippage_bps = (slippage * 10000.0) as u32;

        // Priority fee calculation
        let priority_multiplier_value = priority_multiplier.unwrap_or(1);
        let priority_fee_value = self.priority_fee * priority_multiplier_value;

        // Ensure token accounts exist for both input and output before releasing the GIL
        if input_mint != WSOL_ADDRESS {
            self.create_token_account_if_needed(py, input_mint.clone())?;
        }
        if output_mint != WSOL_ADDRESS {
            self.create_token_account_if_needed(py, output_mint.clone())?;
        }

        // Now we can safely release the GIL for network operations
        py.allow_threads(|| {
            // Step 1: Try to get from cache first
            let cache_key = format!(
                "{}:{}:{}:{}",
                input_mint, output_mint, amount_lamports, slippage_bps
            );
            let jupiter_cache = JUPITER_CACHE.get().unwrap();

            let quote_response = match jupiter_cache.get(&cache_key) {
                Some(cached) => {
                    debug!("Jupiter quote cache hit: {}", cache_key);
                    cached
                }
                None => {
                    // Step 1: Get a quote from Jupiter API
                    let quote_url = format!(
                        "{}?inputMint={}&outputMint={}&amount={}&slippageBps={}",
                        JUPITER_QUOTE_API, input_mint, output_mint, amount_lamports, slippage_bps
                    );

                    info!("Getting Jupiter quote: {}", quote_url);

                    // Implement retry logic
                    let mut retries = 0;
                    let max_retries = 3;

                    loop {
                        // Add authentication headers if needed
                        let mut request = self.http_client.get(&quote_url);
                        if let Some(key) = &self.api_key {
                            request = request.header(AUTHORIZATION, format!("Bearer {}", key));
                        }

                        match request.send() {
                            Ok(response) => {
                                if response.status().is_success() {
                                    match response.json::<serde_json::Value>() {
                                        Ok(quote_data) => {
                                            // Check for API errors
                                            if quote_data.get("error").is_some() {
                                                let error_msg = quote_data["error"]
                                                    .as_str()
                                                    .unwrap_or("Unknown error");
                                                error!("Jupiter quote error: {}", error_msg);
                                                return Err(PyError(format!(
                                                    "Jupiter quote error: {}",
                                                    error_msg
                                                ))
                                                .into());
                                            }

                                            // Cache the result
                                            jupiter_cache
                                                .set(cache_key.clone(), quote_data.clone());

                                            // Return quote
                                            break quote_data;
                                        }
                                        Err(e) => {
                                            error!("Failed to parse Jupiter quote response: {}", e);
                                            return Err(PyError(format!(
                                                "Failed to parse Jupiter quote: {}",
                                                e
                                            ))
                                            .into());
                                        }
                                    }
                                } else {
                                    let status = response.status();
                                    error!("Jupiter API error: HTTP {}", status);

                                    // For server errors, retry with linear backoff
                                    if status.is_server_error() && retries < max_retries {
                                        retries += 1;
                                        let wait_time = 50 * retries; // Linear backoff
                                        std::thread::sleep(Duration::from_millis(wait_time));
                                        continue;
                                    }

                                    return Err(PyError(format!(
                                        "Jupiter API error: HTTP {}",
                                        status
                                    ))
                                    .into());
                                }
                            }
                            Err(e) => {
                                error!("Jupiter API request failed: {}", e);

                                // Network errors are retried linearly
                                if retries < max_retries {
                                    retries += 1;
                                    let wait_time = 50 * retries; // Linear backoff
                                    std::thread::sleep(Duration::from_millis(wait_time));
                                    continue;
                                }

                                return Err(
                                    PyError(format!("Jupiter API request failed: {}", e)).into()
                                );
                            }
                        }
                    }
                }
            };

            let max_accounts = env::var("MAX_ACCOUNTS")
                .map(|v| v.parse::<u32>().unwrap_or(8))
                .unwrap_or(8);

            // Step 2: Use the swap-instructions endpoint
            let instr_payload = serde_json::json!({
                "quoteResponse": quote_response,
                "userPublicKey": self.keypair.pubkey().to_string(),
                "computeUnitPriceMicroLamports": priority_fee_value,
                "wrapUnwrapSOL": true,
                "onlyDirectRoutes": true,
                "maxHops": 1,
                "maxAccounts": max_accounts
            });

            info!("Getting Jupiter swap instructions");

            // Implement retry logic for instructions
            let mut retries = 0;
            let max_retries = 3;

            let instr_response = loop {
                // Add authentication headers if needed
                let mut request = self.http_client.post(JUPITER_SWAP_API).json(&instr_payload);
                if let Some(key) = &self.api_key {
                    request = request.header(AUTHORIZATION, format!("Bearer {}", key));
                }

                match request.send() {
                    Ok(response) => {
                        if response.status().is_success() {
                            match response.json::<serde_json::Value>() {
                                Ok(instr_data) => {
                                    // Check for API errors
                                    if instr_data.get("error").is_some() {
                                        let error_msg =
                                            instr_data["error"].as_str().unwrap_or("Unknown error");
                                        error!("Jupiter instructions error: {}", error_msg);
                                        return Err(PyError(format!(
                                            "Jupiter instructions error: {}",
                                            error_msg
                                        ))
                                        .into());
                                    }

                                    break instr_data;
                                }
                                Err(e) => {
                                    error!("Failed to parse Jupiter instructions response: {}", e);
                                    return Err(PyError(format!(
                                        "Failed to parse Jupiter instructions response: {}",
                                        e
                                    ))
                                    .into());
                                }
                            }
                        } else {
                            let status = response.status();
                            error!("Jupiter API error: HTTP {}", status);

                            // For server errors, retry with linear backoff
                            if status.is_server_error() && retries < max_retries {
                                retries += 1;
                                let wait_time = 50 * retries; // Linear backoff
                                std::thread::sleep(Duration::from_millis(wait_time));
                                continue;
                            }

                            return Err(
                                PyError(format!("Jupiter API error: HTTP {}", status)).into()
                            );
                        }
                    }
                    Err(e) => {
                        error!("Jupiter API request failed: {}", e);

                        // Network errors are retried linearly
                        if retries < max_retries {
                            retries += 1;
                            let wait_time = 50 * retries; // Linear backoff
                            std::thread::sleep(Duration::from_millis(wait_time));
                            continue;
                        }

                        return Err(PyError(format!("Jupiter API request failed: {}", e)).into());
                    }
                }
            };

            // Step 3: Create essential instructions to keep transaction size small
            let mut essential_instructions = Vec::new();

            // Add compute budget instructions
            essential_instructions.push(ComputeBudgetInstruction::set_compute_unit_limit(
                self.compute_limit,
            ));
            essential_instructions.push(ComputeBudgetInstruction::set_compute_unit_price(
                priority_fee_value,
            ));

            // Parse setupInstructions if they exist
            if let Some(setup_instructions) = instr_response
                .get("setupInstructions")
                .and_then(|v| v.as_array())
            {
                for instr in setup_instructions {
                    let program_id_str = instr["programId"].as_str().ok_or_else(|| {
                        error!("Program ID not found in setup instruction");
                        PyError("Program ID not found in setup instruction".to_string())
                    })?;
                    let program_id = Pubkey::from_str(program_id_str).map_err(|e| {
                        error!("Invalid program ID: {}", e);
                        PyError(format!("Invalid program ID: {}", e))
                    })?;

                    let accounts_arr = instr["accounts"].as_array().ok_or_else(|| {
                        error!("Accounts not found in setup instruction");
                        PyError("Accounts not found in setup instruction".to_string())
                    })?;

                    let mut accounts = Vec::new();

                    for account in accounts_arr {
                        let pubkey_str = account["pubkey"].as_str().ok_or_else(|| {
                            error!("Pubkey not found in account");
                            PyError("Pubkey not found in account".to_string())
                        })?;
                        let pubkey = Pubkey::from_str(pubkey_str).map_err(|e| {
                            error!("Invalid pubkey: {}", e);
                            PyError(format!("Invalid pubkey: {}", e))
                        })?;

                        let is_signer = account["isSigner"].as_bool().unwrap_or(false);
                        let is_writable = account["isWritable"].as_bool().unwrap_or(false);

                        let account_meta = if is_writable {
                            if is_signer {
                                AccountMeta::new(pubkey, true)
                            } else {
                                AccountMeta::new(pubkey, false)
                            }
                        } else {
                            if is_signer {
                                AccountMeta::new_readonly(pubkey, true)
                            } else {
                                AccountMeta::new_readonly(pubkey, false)
                            }
                        };

                        accounts.push(account_meta);
                    }

                    let data_str = instr["data"].as_str().ok_or_else(|| {
                        error!("Data not found in setup instruction");
                        PyError("Data not found in setup instruction".to_string())
                    })?;

                    let data = base64::decode(data_str).map_err(|e| {
                        error!("Failed to decode setup instruction data: {}", e);
                        PyError(format!("Failed to decode setup instruction data: {}", e))
                    })?;

                    let instruction = Instruction {
                        program_id,
                        accounts,
                        data,
                    };

                    essential_instructions.push(instruction);
                }
            }

            // Add swapInstruction if it exists (this is critical)
            if let Some(swap_instr) = instr_response.get("swapInstruction") {
                let program_id_str = swap_instr["programId"].as_str().ok_or_else(|| {
                    error!("Program ID not found in swap instruction");
                    PyError("Program ID not found in swap instruction".to_string())
                })?;
                let program_id = Pubkey::from_str(program_id_str).map_err(|e| {
                    error!("Invalid program ID: {}", e);
                    PyError(format!("Invalid program ID: {}", e))
                })?;

                let accounts_arr = swap_instr["accounts"].as_array().ok_or_else(|| {
                    error!("Accounts not found in swap instruction");
                    PyError("Accounts not found in swap instruction".to_string())
                })?;

                let mut accounts = Vec::new();

                for account in accounts_arr {
                    let pubkey_str = account["pubkey"].as_str().ok_or_else(|| {
                        error!("Pubkey not found in account");
                        PyError("Pubkey not found in account".to_string())
                    })?;
                    let pubkey = Pubkey::from_str(pubkey_str).map_err(|e| {
                        error!("Invalid pubkey: {}", e);
                        PyError(format!("Invalid pubkey: {}", e))
                    })?;

                    let is_signer = account["isSigner"].as_bool().unwrap_or(false);
                    let is_writable = account["isWritable"].as_bool().unwrap_or(false);

                    let account_meta = if is_writable {
                        if is_signer {
                            AccountMeta::new(pubkey, true)
                        } else {
                            AccountMeta::new(pubkey, false)
                        }
                    } else {
                        if is_signer {
                            AccountMeta::new_readonly(pubkey, true)
                        } else {
                            AccountMeta::new_readonly(pubkey, false)
                        }
                    };

                    accounts.push(account_meta);
                }

                let data_str = swap_instr["data"].as_str().ok_or_else(|| {
                    error!("Data not found in swap instruction");
                    PyError("Data not found in swap instruction".to_string())
                })?;

                let data = base64::decode(data_str).map_err(|e| {
                    error!("Failed to decode swap instruction data: {}", e);
                    PyError(format!("Failed to decode swap instruction data: {}", e))
                })?;

                let instruction = Instruction {
                    program_id,
                    accounts,
                    data,
                };

                essential_instructions.push(instruction);
            } else {
                error!("No swap instruction found in response");
                return Err(
                    PyError("Jupiter swap instruction not found in response".to_string()).into(),
                );
            }

            // Add cleanupInstruction if it exists
            if let Some(cleanup_instr) = instr_response.get("cleanupInstruction") {
                let program_id_str = cleanup_instr["programId"].as_str().ok_or_else(|| {
                    error!("Program ID not found in cleanup instruction");
                    PyError("Program ID not found in cleanup instruction".to_string())
                })?;
                let program_id = Pubkey::from_str(program_id_str).map_err(|e| {
                    error!("Invalid program ID: {}", e);
                    PyError(format!("Invalid program ID: {}", e))
                })?;

                let accounts_arr = cleanup_instr["accounts"].as_array().ok_or_else(|| {
                    error!("Accounts not found in cleanup instruction");
                    PyError("Accounts not found in cleanup instruction".to_string())
                })?;

                let mut accounts = Vec::new();

                for account in accounts_arr {
                    let pubkey_str = account["pubkey"].as_str().ok_or_else(|| {
                        error!("Pubkey not found in account");
                        PyError("Pubkey not found in account".to_string())
                    })?;
                    let pubkey = Pubkey::from_str(pubkey_str).map_err(|e| {
                        error!("Invalid pubkey: {}", e);
                        PyError(format!("Invalid pubkey: {}", e))
                    })?;

                    let is_signer = account["isSigner"].as_bool().unwrap_or(false);
                    let is_writable = account["isWritable"].as_bool().unwrap_or(false);

                    let account_meta = if is_writable {
                        if is_signer {
                            AccountMeta::new(pubkey, true)
                        } else {
                            AccountMeta::new(pubkey, false)
                        }
                    } else {
                        if is_signer {
                            AccountMeta::new_readonly(pubkey, true)
                        } else {
                            AccountMeta::new_readonly(pubkey, false)
                        }
                    };

                    accounts.push(account_meta);
                }

                let data_str = cleanup_instr["data"].as_str().ok_or_else(|| {
                    error!("Data not found in cleanup instruction");
                    PyError("Data not found in cleanup instruction".to_string())
                })?;

                let data = base64::decode(data_str).map_err(|e| {
                    error!("Failed to decode cleanup instruction data: {}", e);
                    PyError(format!("Failed to decode cleanup instruction data: {}", e))
                })?;

                let instruction = Instruction {
                    program_id,
                    accounts,
                    data,
                };

                essential_instructions.push(instruction);
            }

            // Check if we have any instructions beyond compute budget
            if essential_instructions.len() <= 2 {
                error!("No Jupiter instructions found in response");
                return Err(
                    PyError("Jupiter instructions not found in response".to_string()).into(),
                );
            }

            // Step 4: Get recent blockhash from optimized cache
            let blockhash_cache = BLOCKHASH_CACHE.get().unwrap();
            let blockhash = blockhash_cache.get_blockhash();
            debug!("Using cached blockhash: {}", blockhash);

            // Step 5: Create and sign transaction with essential instructions
            let mut transaction = Transaction::new_signed_with_payer(
                &essential_instructions,
                Some(&self.keypair.pubkey()),
                &[&self.keypair],
                blockhash,
            );

            // Step 6: Send transaction with optimized retry logic
            let send_config = RpcSendTransactionConfig {
                skip_preflight: self.skip_preflight,
                preflight_commitment: Some(CommitmentLevel::Processed),
                encoding: Some(UiTransactionEncoding::Base64),
                max_retries: Some(self.max_retries),
                ..Default::default()
            };

            // Track if we need to retry with new blockhash
            let mut retry_count = 0;
            let max_retries = 2; // Specific to blockhash errors

            while retry_count <= max_retries {
                match self
                    .rpc_client
                    .send_transaction_with_config(&transaction, send_config.clone())
                {
                    Ok(signature) => {
                        info!(
                            "Jupiter swap executed: {} SOL from {} to {} with signature {}",
                            amount_sol, input_mint, output_mint, signature
                        );
                        return Ok(signature.to_string());
                    }
                    Err(e) => {
                        let error_str = e.to_string();

                        // If it's a blockhash error, try with fresh blockhash
                        if error_str.contains("blockhash") && retry_count < max_retries {
                            error!(
                                "Blockhash error, retrying with fresh blockhash: {}",
                                error_str
                            );

                            // Force refresh the blockhash
                            let new_blockhash = blockhash_cache.force_update();

                            // Create new transaction with fresh blockhash
                            let new_transaction = Transaction::new_signed_with_payer(
                                &essential_instructions,
                                Some(&self.keypair.pubkey()),
                                &[&self.keypair],
                                new_blockhash,
                            );

                            // Update transaction for next retry
                            transaction = new_transaction;

                            retry_count += 1;
                            continue;
                        }

                        error!("Failed to send transaction: {}", e);
                        return Err(PyError(format!("Failed to send transaction: {}", e)).into());
                    }
                }
            }

            Err(PyError("Max retries exceeded".to_string()).into())
        })
    }

    /// Sell tokens for SOL via Jupiter - Optimized version
    fn sell_token_for_sol_via_jupiter(
        &self,
        py: Python<'_>,
        token_mint: String,
        amount_tokens: f64,
        slippage_percent: Option<f64>,
        priority_multiplier: Option<u64>,
    ) -> PyResult<String> {
        // Get token decimals first while holding the GIL
        let token_decimals = self.get_token_decimals(py, token_mint.clone())?;

        // Convert amount to token units
        let amount_in = (amount_tokens * 10f64.powi(token_decimals as i32)) as u64;

        // Dynamic slippage calculation
        let slippage = match slippage_percent {
            Some(val) => val / 100.0,
            None => DEFAULT_SLIPPAGE,
        };
        let slippage_bps = (slippage * 10000.0) as u32;

        // Priority fee calculation
        let priority_multiplier_value = priority_multiplier.unwrap_or(1);
        let priority_fee_value = self.priority_fee * priority_multiplier_value;

        // SOL mint address
        let sol_mint = WSOL_ADDRESS.to_string();

        let max_accounts = env::var("MAX_ACCOUNTS")
            .map(|v| v.parse::<u32>().unwrap_or(8))
            .unwrap_or(8);

        // Now release the GIL for network operations
        py.allow_threads(|| {
            // Step 1: Check if we have this in cache
            let cache_key = format!("{}:{}:{}:{}", token_mint, sol_mint, amount_in, slippage_bps);
            let jupiter_cache = JUPITER_CACHE.get().unwrap();

            let quote_response = match jupiter_cache.get(&cache_key) {
                Some(cached) => {
                    debug!("Jupiter quote cache hit: {}", cache_key);
                    cached
                }
                None => {
                    // Step 1: Get a quote from Jupiter API
                    let quote_url = format!(
                        "{}?inputMint={}&outputMint={}&amount={}&slippageBps={}",
                        JUPITER_QUOTE_API, token_mint, sol_mint, amount_in, slippage_bps
                    );

                    info!("Getting Jupiter quote for token sell: {}", quote_url);

                    // Implement retry logic
                    let mut retries = 0;
                    let max_retries = 3;

                    loop {
                        // Add authentication headers if needed
                        let mut request = self.http_client.get(&quote_url);
                        if let Some(key) = &self.api_key {
                            request = request.header(AUTHORIZATION, format!("Bearer {}", key));
                        }

                        match request.send() {
                            Ok(response) => {
                                if response.status().is_success() {
                                    match response.json::<serde_json::Value>() {
                                        Ok(quote_data) => {
                                            // Check for API errors
                                            if quote_data.get("error").is_some() {
                                                let error_msg = quote_data["error"]
                                                    .as_str()
                                                    .unwrap_or("Unknown error");
                                                error!("Jupiter quote error: {}", error_msg);
                                                return Err(PyError(format!(
                                                    "Jupiter quote error: {}",
                                                    error_msg
                                                ))
                                                .into());
                                            }

                                            // Cache the result
                                            jupiter_cache
                                                .set(cache_key.clone(), quote_data.clone());

                                            // Return quote
                                            break quote_data;
                                        }
                                        Err(e) => {
                                            error!("Failed to parse Jupiter quote response: {}", e);
                                            return Err(PyError(format!(
                                                "Failed to parse Jupiter quote: {}",
                                                e
                                            ))
                                            .into());
                                        }
                                    }
                                } else {
                                    let status = response.status();
                                    error!("Jupiter API error: HTTP {}", status);

                                    // For server errors, retry with linear backoff
                                    if status.is_server_error() && retries < max_retries {
                                        retries += 1;
                                        let wait_time = 50 * retries; // Linear backoff
                                        std::thread::sleep(Duration::from_millis(wait_time));
                                        continue;
                                    }

                                    return Err(PyError(format!(
                                        "Jupiter API error: HTTP {}",
                                        status
                                    ))
                                    .into());
                                }
                            }
                            Err(e) => {
                                error!("Jupiter API request failed: {}", e);

                                // Network errors are retried linearly
                                if retries < max_retries {
                                    retries += 1;
                                    let wait_time = 50 * retries; // Linear backoff
                                    std::thread::sleep(Duration::from_millis(wait_time));
                                    continue;
                                }

                                return Err(
                                    PyError(format!("Jupiter API request failed: {}", e)).into()
                                );
                            }
                        }
                    }
                }
            };

            // Step 2: Use the swap-instructions endpoint
            let instr_payload = serde_json::json!({
                "quoteResponse": quote_response,
                "userPublicKey": self.keypair.pubkey().to_string(),
                "computeUnitPriceMicroLamports": priority_fee_value,
                "wrapUnwrapSOL": true,
                // Since it's a token sale, we want fast execution
                "onlyDirectRoutes": true,
                "maxHops": 1,
                "maxAccounts": max_accounts
            });

            info!("Getting Jupiter swap instructions for sell");

            // Implement retry logic for instructions
            let mut retries = 0;
            let max_retries = 3;

            let instr_response = loop {
                // Add authentication headers if needed
                let mut request = self.http_client.post(JUPITER_SWAP_API).json(&instr_payload);
                if let Some(key) = &self.api_key {
                    request = request.header(AUTHORIZATION, format!("Bearer {}", key));
                }

                match request.send() {
                    Ok(response) => {
                        if response.status().is_success() {
                            match response.json::<serde_json::Value>() {
                                Ok(instr_data) => {
                                    // Check for API errors
                                    if instr_data.get("error").is_some() {
                                        let error_msg =
                                            instr_data["error"].as_str().unwrap_or("Unknown error");
                                        error!("Jupiter instructions error: {}", error_msg);
                                        return Err(PyError(format!(
                                            "Jupiter instructions error: {}",
                                            error_msg
                                        ))
                                        .into());
                                    }

                                    break instr_data;
                                }
                                Err(e) => {
                                    error!("Failed to parse Jupiter instructions response: {}", e);
                                    return Err(PyError(format!(
                                        "Failed to parse Jupiter instructions response: {}",
                                        e
                                    ))
                                    .into());
                                }
                            }
                        } else {
                            let status = response.status();
                            error!("Jupiter API error: HTTP {}", status);

                            // For server errors, retry with linear backoff
                            if status.is_server_error() && retries < max_retries {
                                retries += 1;
                                let wait_time = 50 * retries; // Linear backoff
                                std::thread::sleep(Duration::from_millis(wait_time));
                                continue;
                            }

                            return Err(
                                PyError(format!("Jupiter API error: HTTP {}", status)).into()
                            );
                        }
                    }
                    Err(e) => {
                        error!("Jupiter API request failed: {}", e);

                        // Network errors are retried linearly
                        if retries < max_retries {
                            retries += 1;
                            let wait_time = 50 * retries; // Linear backoff
                            std::thread::sleep(Duration::from_millis(wait_time));
                            continue;
                        }

                        return Err(PyError(format!("Jupiter API request failed: {}", e)).into());
                    }
                }
            };

            // Step 3: Create essential instructions to keep transaction size small
            let mut essential_instructions = Vec::new();

            // Add compute budget instructions
            essential_instructions.push(ComputeBudgetInstruction::set_compute_unit_limit(
                self.compute_limit,
            ));
            essential_instructions.push(ComputeBudgetInstruction::set_compute_unit_price(
                priority_fee_value,
            ));

            // Parse setupInstructions if they exist
            if let Some(setup_instructions) = instr_response
                .get("setupInstructions")
                .and_then(|v| v.as_array())
            {
                for instr in setup_instructions {
                    let program_id_str = instr["programId"].as_str().ok_or_else(|| {
                        error!("Program ID not found in setup instruction");
                        PyError("Program ID not found in setup instruction".to_string())
                    })?;
                    let program_id = Pubkey::from_str(program_id_str).map_err(|e| {
                        error!("Invalid program ID: {}", e);
                        PyError(format!("Invalid program ID: {}", e))
                    })?;

                    let accounts_arr = instr["accounts"].as_array().ok_or_else(|| {
                        error!("Accounts not found in setup instruction");
                        PyError("Accounts not found in setup instruction".to_string())
                    })?;

                    let mut accounts = Vec::new();

                    for account in accounts_arr {
                        let pubkey_str = account["pubkey"].as_str().ok_or_else(|| {
                            error!("Pubkey not found in account");
                            PyError("Pubkey not found in account".to_string())
                        })?;
                        let pubkey = Pubkey::from_str(pubkey_str).map_err(|e| {
                            error!("Invalid pubkey: {}", e);
                            PyError(format!("Invalid pubkey: {}", e))
                        })?;

                        let is_signer = account["isSigner"].as_bool().unwrap_or(false);
                        let is_writable = account["isWritable"].as_bool().unwrap_or(false);

                        let account_meta = if is_writable {
                            if is_signer {
                                AccountMeta::new(pubkey, true)
                            } else {
                                AccountMeta::new(pubkey, false)
                            }
                        } else {
                            if is_signer {
                                AccountMeta::new_readonly(pubkey, true)
                            } else {
                                AccountMeta::new_readonly(pubkey, false)
                            }
                        };

                        accounts.push(account_meta);
                    }

                    let data_str = instr["data"].as_str().ok_or_else(|| {
                        error!("Data not found in setup instruction");
                        PyError("Data not found in setup instruction".to_string())
                    })?;

                    let data = base64::decode(data_str).map_err(|e| {
                        error!("Failed to decode setup instruction data: {}", e);
                        PyError(format!("Failed to decode setup instruction data: {}", e))
                    })?;

                    let instruction = Instruction {
                        program_id,
                        accounts,
                        data,
                    };

                    essential_instructions.push(instruction);
                }
            }

            // Add swapInstruction if it exists (this is critical)
            if let Some(swap_instr) = instr_response.get("swapInstruction") {
                let program_id_str = swap_instr["programId"].as_str().ok_or_else(|| {
                    error!("Program ID not found in swap instruction");
                    PyError("Program ID not found in swap instruction".to_string())
                })?;
                let program_id = Pubkey::from_str(program_id_str).map_err(|e| {
                    error!("Invalid program ID: {}", e);
                    PyError(format!("Invalid program ID: {}", e))
                })?;

                let accounts_arr = swap_instr["accounts"].as_array().ok_or_else(|| {
                    error!("Accounts not found in swap instruction");
                    PyError("Accounts not found in swap instruction".to_string())
                })?;

                let mut accounts = Vec::new();

                for account in accounts_arr {
                    let pubkey_str = account["pubkey"].as_str().ok_or_else(|| {
                        error!("Pubkey not found in account");
                        PyError("Pubkey not found in account".to_string())
                    })?;
                    let pubkey = Pubkey::from_str(pubkey_str).map_err(|e| {
                        error!("Invalid pubkey: {}", e);
                        PyError(format!("Invalid pubkey: {}", e))
                    })?;

                    let is_signer = account["isSigner"].as_bool().unwrap_or(false);
                    let is_writable = account["isWritable"].as_bool().unwrap_or(false);

                    let account_meta = if is_writable {
                        if is_signer {
                            AccountMeta::new(pubkey, true)
                        } else {
                            AccountMeta::new(pubkey, false)
                        }
                    } else {
                        if is_signer {
                            AccountMeta::new_readonly(pubkey, true)
                        } else {
                            AccountMeta::new_readonly(pubkey, false)
                        }
                    };

                    accounts.push(account_meta);
                }

                let data_str = swap_instr["data"].as_str().ok_or_else(|| {
                    error!("Data not found in swap instruction");
                    PyError("Data not found in swap instruction".to_string())
                })?;

                let data = base64::decode(data_str).map_err(|e| {
                    error!("Failed to decode swap instruction data: {}", e);
                    PyError(format!("Failed to decode swap instruction data: {}", e))
                })?;

                let instruction = Instruction {
                    program_id,
                    accounts,
                    data,
                };

                essential_instructions.push(instruction);
            } else {
                error!("No swap instruction found in response");
                return Err(
                    PyError("Jupiter swap instruction not found in response".to_string()).into(),
                );
            }

            // Add cleanupInstruction if it exists
            if let Some(cleanup_instr) = instr_response.get("cleanupInstruction") {
                let program_id_str = cleanup_instr["programId"].as_str().ok_or_else(|| {
                    error!("Program ID not found in cleanup instruction");
                    PyError("Program ID not found in cleanup instruction".to_string())
                })?;
                let program_id = Pubkey::from_str(program_id_str).map_err(|e| {
                    error!("Invalid program ID: {}", e);
                    PyError(format!("Invalid program ID: {}", e))
                })?;

                let accounts_arr = cleanup_instr["accounts"].as_array().ok_or_else(|| {
                    error!("Accounts not found in cleanup instruction");
                    PyError("Accounts not found in cleanup instruction".to_string())
                })?;

                let mut accounts = Vec::new();

                for account in accounts_arr {
                    let pubkey_str = account["pubkey"].as_str().ok_or_else(|| {
                        error!("Pubkey not found in account");
                        PyError("Pubkey not found in account".to_string())
                    })?;
                    let pubkey = Pubkey::from_str(pubkey_str).map_err(|e| {
                        error!("Invalid pubkey: {}", e);
                        PyError(format!("Invalid pubkey: {}", e))
                    })?;

                    let is_signer = account["isSigner"].as_bool().unwrap_or(false);
                    let is_writable = account["isWritable"].as_bool().unwrap_or(false);

                    let account_meta = if is_writable {
                        if is_signer {
                            AccountMeta::new(pubkey, true)
                        } else {
                            AccountMeta::new(pubkey, false)
                        }
                    } else {
                        if is_signer {
                            AccountMeta::new_readonly(pubkey, true)
                        } else {
                            AccountMeta::new_readonly(pubkey, false)
                        }
                    };

                    accounts.push(account_meta);
                }

                let data_str = cleanup_instr["data"].as_str().ok_or_else(|| {
                    error!("Data not found in cleanup instruction");
                    PyError("Data not found in cleanup instruction".to_string())
                })?;

                let data = base64::decode(data_str).map_err(|e| {
                    error!("Failed to decode cleanup instruction data: {}", e);
                    PyError(format!("Failed to decode cleanup instruction data: {}", e))
                })?;

                let instruction = Instruction {
                    program_id,
                    accounts,
                    data,
                };

                essential_instructions.push(instruction);
            }

            // Check if we have any instructions beyond compute budget
            if essential_instructions.len() <= 2 {
                error!("No Jupiter instructions found in response");
                return Err(
                    PyError("Jupiter instructions not found in response".to_string()).into(),
                );
            }

            // Step 4: Get recent blockhash from optimized cache
            let blockhash_cache = BLOCKHASH_CACHE.get().unwrap();
            let blockhash = blockhash_cache.get_blockhash();
            debug!("Using cached blockhash: {}", blockhash);

            // Step 5: Create and sign transaction with essential instructions
            let mut transaction = Transaction::new_signed_with_payer(
                &essential_instructions,
                Some(&self.keypair.pubkey()),
                &[&self.keypair],
                blockhash,
            );

            // Step 6: Send transaction with optimized retry logic
            let send_config = RpcSendTransactionConfig {
                skip_preflight: self.skip_preflight,
                preflight_commitment: Some(CommitmentLevel::Processed),
                encoding: Some(UiTransactionEncoding::Base64),
                max_retries: Some(self.max_retries),
                ..Default::default()
            };

            // Track if we need to retry with new blockhash
            let mut retry_count = 0;
            let max_retries = 2; // Specific to blockhash errors

            while retry_count <= max_retries {
                match self
                    .rpc_client
                    .send_transaction_with_config(&transaction, send_config.clone())
                {
                    Ok(signature) => {
                        info!(
                            "Jupiter token sell executed: {} tokens to SOL with signature {}",
                            amount_tokens, signature
                        );
                        return Ok(signature.to_string());
                    }
                    Err(e) => {
                        let error_str = e.to_string();

                        // If it's a blockhash error, try with fresh blockhash
                        if error_str.contains("blockhash") && retry_count < max_retries {
                            error!(
                                "Blockhash error, retrying with fresh blockhash: {}",
                                error_str
                            );

                            // Force refresh the blockhash
                            let new_blockhash = blockhash_cache.force_update();

                            // Create new transaction with fresh blockhash
                            let new_transaction = Transaction::new_signed_with_payer(
                                &essential_instructions,
                                Some(&self.keypair.pubkey()),
                                &[&self.keypair],
                                new_blockhash,
                            );

                            // Update transaction for next retry
                            transaction = new_transaction;

                            retry_count += 1;
                            continue;
                        }

                        error!("Failed to send transaction: {}", e);
                        return Err(PyError(format!("Failed to send transaction: {}", e)).into());
                    }
                }
            }

            Err(PyError("Max retries exceeded".to_string()).into())
        })
    }

    /// Get token decimals with caching for speed
    fn get_token_decimals(&self, py: Python<'_>, token_mint: String) -> PyResult<u8> {
        // Check cache first
        if let Some(decimals) = TOKEN_DECIMALS_CACHE.get(&token_mint) {
            return Ok(*decimals);
        }

        // Not in cache, get from chain with GIL released
        py.allow_threads(|| {
            // Get token mint pubkey
            let token_mint_pubkey = Pubkey::from_str(&token_mint)
                .map_err(|e| PyErr::new::<PyValueError, _>(format!("Invalid pubkey: {}", e)))?;

            // Get mint data
            let mint_data = self
                .rpc_client
                .get_account_data(&token_mint_pubkey)
                .map_err(|e| {
                    PyErr::new::<PyRuntimeError, _>(format!("Failed to get account data: {}", e))
                })?;

            // Unpack mint data
            let mint_info = spl_token::state::Mint::unpack(&mint_data).map_err(|e| {
                PyErr::new::<PyRuntimeError, _>(format!("Failed to unpack mint data: {}", e))
            })?;

            // Cache the result
            TOKEN_DECIMALS_CACHE.insert(token_mint, mint_info.decimals);

            Ok(mint_info.decimals)
        })
    }

    /// Create token account if it doesn't exist - with improved error handling
    fn create_token_account_if_needed(&self, py: Python<'_>, token_mint: String) -> PyResult<bool> {
        // Get token mint pubkey
        let token_mint_pubkey = match Pubkey::from_str(&token_mint) {
            Ok(pubkey) => pubkey,
            Err(e) => return Err(PyValueError::new_err(format!("Invalid pubkey: {}", e))),
        };

        // Get associated token account
        let token_account =
            get_associated_token_address(&self.keypair.pubkey(), &token_mint_pubkey);

        // Check if account exists - do this with the GIL held
        let account_exists = self.rpc_client.get_account_data(&token_account).is_ok();
        if account_exists {
            return Ok(false);
        }

        // Create token account instruction
        let create_ata_ix = create_associated_token_account_idempotent(
            &self.keypair.pubkey(),
            &self.keypair.pubkey(),
            &token_mint_pubkey,
            &Pubkey::from_str(&self.token_program_id)
                .map_err(|e| PyValueError::new_err(format!("Invalid token program ID: {}", e)))?,
        );

        // Now we can release the GIL for the network operation
        py.allow_threads(|| {
            // Get blockhash from cache
            let blockhash_cache = BLOCKHASH_CACHE.get().unwrap();
            let blockhash = blockhash_cache.get_blockhash();

            // Create transaction
            let transaction = Transaction::new_signed_with_payer(
                &[create_ata_ix],
                Some(&self.keypair.pubkey()),
                &[&self.keypair],
                blockhash,
            );

            // Send transaction
            match self.rpc_client.send_and_confirm_transaction(&transaction) {
                Ok(signature) => {
                    info!("Created token account for {}: {}", token_mint, signature);
                    Ok(true)
                }
                Err(e) => {
                    // Check if the error is because the account already exists
                    if e.to_string().contains("already in use") {
                        debug!("Token account for {} already exists", token_mint);
                        return Ok(true);
                    }

                    error!("Failed to create token account for {}: {}", token_mint, e);
                    return Err(PyRuntimeError::new_err(format!(
                        "Failed to create token account: {}",
                        e
                    )));
                }
            }
        })
    }

    /// Get SOL balance with optimized caching
    fn get_sol_balance(&self, py: Python<'_>) -> PyResult<f64> {
        py.allow_threads(
            || match self.rpc_client.get_balance(&self.keypair.pubkey()) {
                Ok(balance) => Ok(balance as f64 / LAMPORTS_PER_SOL as f64),
                Err(e) => {
                    error!("Failed to get SOL balance: {}", e);
                    Err(PyRuntimeError::new_err(format!(
                        "Failed to get SOL balance: {}",
                        e
                    )))
                }
            },
        )
    }

    /// Get token balance with optimized error handling
    fn get_token_balance(&self, py: Python<'_>, token_mint: String) -> PyResult<f64> {
        py.allow_threads(|| {
            // Get token mint pubkey
            let token_mint_pubkey = Pubkey::from_str(&token_mint)
                .map_err(|e| PyValueError::new_err(format!("Invalid pubkey: {}", e)))?;

            // Get associated token account
            let token_account =
                get_associated_token_address(&self.keypair.pubkey(), &token_mint_pubkey);

            // Check if account exists
            match self.rpc_client.get_account_data(&token_account) {
                Ok(data) => {
                    // Account exists, unpack data
                    let account_info = spl_token::state::Account::unpack(&data).map_err(|e| {
                        PyRuntimeError::new_err(format!("Failed to unpack token account: {}", e))
                    })?;

                    // Get token mint data for decimals - check cache first
                    let decimals = if let Some(decimals) = TOKEN_DECIMALS_CACHE.get(&token_mint) {
                        *decimals
                    } else {
                        // Get from chain if not in cache
                        let mint_data = self
                            .rpc_client
                            .get_account_data(&token_mint_pubkey)
                            .map_err(|e| {
                                PyRuntimeError::new_err(format!("Failed to get mint data: {}", e))
                            })?;

                        let mint_info =
                            spl_token::state::Mint::unpack(&mint_data).map_err(|e| {
                                PyRuntimeError::new_err(format!(
                                    "Failed to unpack mint data: {}",
                                    e
                                ))
                            })?;

                        // Cache the result
                        TOKEN_DECIMALS_CACHE.insert(token_mint.clone(), mint_info.decimals);

                        mint_info.decimals
                    };

                    // Calculate balance with proper decimals
                    let balance = account_info.amount as f64 / 10f64.powi(decimals as i32);

                    Ok(balance)
                }
                Err(_) => {
                    // Account doesn't exist, balance is 0
                    Ok(0.0)
                }
            }
        })
    }

    /// Get wallet's public address
    fn get_address(&self) -> PyResult<String> {
        Ok(self.keypair.pubkey().to_string())
    }

    /// Get cached blockhash with optimized approach
    fn get_cached_blockhash(&self, py: Python<'_>) -> PyResult<String> {
        py.allow_threads(|| {
            let blockhash_cache = BLOCKHASH_CACHE.get().unwrap();
            let blockhash = blockhash_cache.get_blockhash();
            Ok(blockhash.to_string())
        })
    }

    /// Force update the blockhash cache
    fn force_update_blockhash(&self, py: Python<'_>) -> PyResult<String> {
        py.allow_threads(|| {
            let blockhash_cache = BLOCKHASH_CACHE.get().unwrap();
            let blockhash = blockhash_cache.force_update();
            Ok(blockhash.to_string())
        })
    }

    /// Confirm transaction with optimized retry logic
    fn confirm_transaction(
        &self,
        py: Python<'_>,
        signature_str: String,
        timeout: u64,
    ) -> PyResult<bool> {
        py.allow_threads(|| {
            // Parse the signature string - using simplified error handling
            let signature = Signature::from_str(&signature_str)
                .map_err(|e| PyValueError::new_err(format!("Invalid signature: {}", e)))?;

            let start_time = Instant::now();
            let timeout_duration = Duration::from_secs(timeout);

            while start_time.elapsed() < timeout_duration {
                match self.rpc_client.get_signature_status(&signature) {
                    Ok(Some(Ok(_))) => return Ok(true),
                    Ok(Some(Err(e))) => {
                        error!("Transaction failed: {:?}", e);
                        return Err(PyRuntimeError::new_err(format!(
                            "Transaction failed: {:?}",
                            e
                        )));
                    }
                    Ok(None) => {
                        // Sleep shorter time for faster responses
                        std::thread::sleep(Duration::from_millis(50));
                    }
                    Err(e) => {
                        error!("Status check failed: {}", e);
                        // Sleep a bit before retrying
                        std::thread::sleep(Duration::from_millis(500));
                    }
                }
            }

            error!("Transaction confirmation timed out");
            Err(PyRuntimeError::new_err(
                "Transaction confirmation timed out".to_string(),
            ))
        })
    }
}

/// Python module initialization
#[pymodule]
fn solana_rust_bot(_py: Python, m: &PyModule) -> PyResult<()> {
    // Initialize logging
    pyo3_log::init();

    // Register classes
    m.add_class::<SolanaTrader>()?;

    // Add constants
    m.add("LAMPORTS_PER_SOL", LAMPORTS_PER_SOL)?;
    m.add("DEFAULT_COMPUTE_LIMIT", DEFAULT_COMPUTE_LIMIT)?;
    m.add("DEFAULT_PRIORITY_FEE", DEFAULT_PRIORITY_FEE)?;
    m.add("DEFAULT_MAX_RETRIES", DEFAULT_MAX_RETRIES)?;
    m.add("DEFAULT_MIN_SOL_BALANCE", DEFAULT_MIN_SOL_BALANCE)?;
    m.add("DEFAULT_MIN_WSOL_BALANCE", DEFAULT_MIN_WSOL_BALANCE)?;
    m.add("WSOL_ADDRESS", WSOL_ADDRESS)?;

    Ok(())
}