// src/lib.rs - Solana Trading Bot for Python with PyO3
// High-performance trading core with CUDA acceleration support

use log::debug;
use pyo3::exceptions::PyValueError;
use pyo3::prelude::*;
use pyo3_log;

// Use bs58 for base58 encoding/decoding
use bs58;
use serde::{Deserialize, Serialize};

use solana_client::nonblocking::rpc_client::RpcClient;
use solana_client::rpc_config::RpcSendTransactionConfig;
use solana_sdk::{
    commitment_config::CommitmentLevel,
    compute_budget::ComputeBudgetInstruction,
    instruction::{AccountMeta, Instruction},
    program_pack::Pack, // Added Pack trait for token account unpacking
    pubkey::Pubkey,
    signature::{Keypair, Signer},
    transaction::Transaction,
};
use spl_associated_token_account::{
    get_associated_token_address, instruction::create_associated_token_account_idempotent,
};

use dashmap::DashMap;
use std::collections::HashMap;
use std::env;
use std::fs;
use std::str::FromStr;
use std::sync::atomic::{AtomicBool, AtomicU64, Ordering};
use std::sync::{Arc, RwLock};
use std::time::{SystemTime, UNIX_EPOCH};
use tokio::sync::Mutex as TokioMutex;

// Constants
const COMPUTE_UNITS: u32 = 50_000;
const PRIORITY_FEE: u64 = 950_000; // Increased for higher priority
const LAMPORTS_PER_SOL: u64 = 1_000_000_000;
const DEFAULT_RPC_RATE_LIMIT: u64 = 5; // 5 RPC calls per second
const MAX_RETRY_COUNT: u8 = 3;
const RAYDIUM_SWAP_INSTRUCTION: u8 = 6; // Important: Raydium swap instruction code

// Rate limiter for RPC calls
struct RateLimiter {
    call_count: AtomicU64,
    last_reset: AtomicU64,
    limit_per_second: Arc<AtomicU64>,
}

impl RateLimiter {
    fn new(limit_per_second: u64) -> Self {
        Self {
            call_count: AtomicU64::new(0),
            last_reset: AtomicU64::new(
                SystemTime::now()
                    .duration_since(UNIX_EPOCH)
                    .unwrap()
                    .as_secs(),
            ),
            limit_per_second: Arc::new(AtomicU64::new(limit_per_second)),
        }
    }

    fn check_and_increment(&self) -> bool {
        let now = SystemTime::now()
            .duration_since(UNIX_EPOCH)
            .unwrap()
            .as_secs();
        let last_reset = self.last_reset.load(Ordering::Relaxed);

        if now > last_reset {
            // Reset counter if we're in a new second
            self.call_count.store(0, Ordering::Relaxed);
            self.last_reset.store(now, Ordering::Relaxed);
        }

        let count = self.call_count.fetch_add(1, Ordering::Relaxed);
        let limit = self.limit_per_second.load(Ordering::Relaxed);

        count < limit
    }

    fn set_limit(&self, limit: u64) {
        self.limit_per_second.store(limit, Ordering::Relaxed);
    }
}

// Define TokenPairSetting
#[pyclass]
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct TokenPairSetting {
    #[pyo3(get, set)]
    pub token_mint: String,
    #[pyo3(get, set)]
    pub amm_id: String,
    #[pyo3(get, set)]
    pub amm_authority: String,
    #[pyo3(get, set)]
    pub amm_open_orders: String,
    #[pyo3(get, set)]
    pub amm_target: String,
    #[pyo3(get, set)]
    pub pool_token_account: String,
    #[pyo3(get, set)]
    pub pool_pc_account: String,
    #[pyo3(get, set)]
    pub min_liquidity_pct: f64,
    #[pyo3(get, set)]
    pub min_exit_liquidity_sol: f64,
    #[pyo3(get, set)]
    pub auth_revoked: bool,
    #[pyo3(get, set)]
    pub buyer_seller_ratio: f64,
    #[pyo3(get, set)]
    pub min_volume_5m: f64,
    #[pyo3(get, set)]
    pub enabled: bool,
}

#[pymethods]
impl TokenPairSetting {
    #[new]
    fn new(
        token_mint: String,
        amm_id: String,
        amm_authority: String,
        amm_open_orders: String,
        amm_target: String,
        pool_token_account: String,
        pool_pc_account: String,
        min_liquidity_pct: Option<f64>,
        min_exit_liquidity_sol: Option<f64>,
        auth_revoked: Option<bool>,
        buyer_seller_ratio: Option<f64>,
        min_volume_5m: Option<f64>,
        enabled: Option<bool>,
    ) -> Self {
        Self {
            token_mint,
            amm_id,
            amm_authority,
            amm_open_orders,
            amm_target,
            pool_token_account,
            pool_pc_account,
            min_liquidity_pct: min_liquidity_pct.unwrap_or(95.0),
            min_exit_liquidity_sol: min_exit_liquidity_sol.unwrap_or(5.0),
            auth_revoked: auth_revoked.unwrap_or(true),
            buyer_seller_ratio: buyer_seller_ratio.unwrap_or(1.0),
            min_volume_5m: min_volume_5m.unwrap_or(10.0),
            enabled: enabled.unwrap_or(true),
        }
    }
}

// Dynamic configuration structure
#[pyclass]
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct TradingConfig {
    #[pyo3(get, set)]
    pub rpc_url: String,
    #[pyo3(get, set)]
    pub ws_url: String,
    #[pyo3(get, set)]
    pub api_key: String,

    #[pyo3(get, set)]
    pub sol_mint: String,
    #[pyo3(get, set)]
    pub rpc_rate_limit: u64,

    #[pyo3(get, set)]
    pub token_mint: Option<String>,
    #[pyo3(get, set)]
    pub amm_program: Option<String>,

    #[pyo3(get, set)]
    pub compute_limit: u32,
    #[pyo3(get, set)]
    pub priority_fee: u64,
    #[pyo3(get, set)]
    pub skip_preflight: bool,
    #[pyo3(get, set)]
    pub max_retries: u8,

    #[pyo3(get, set)]
    pub front_run_amount: f64,
    #[pyo3(get, set)]
    pub min_victim_size: f64,
    #[pyo3(get, set)]
    pub max_victim_size: f64,
    #[pyo3(get, set)]
    pub min_profit: f64,
    #[pyo3(get, set)]
    pub slippage_bps: u16,

    #[pyo3(get, set)]
    pub min_sol_balance: f64,
    #[pyo3(get, set)]
    pub min_wsol_balance: f64,

    #[pyo3(get, set)]
    pub amm_id: Option<String>,
    #[pyo3(get, set)]
    pub market_amm_authority: Option<String>,
    #[pyo3(get, set)]
    pub market_amm_open_orders: Option<String>,
    #[pyo3(get, set)]
    pub market_amm_target: Option<String>,
    #[pyo3(get, set)]
    pub market_pool_token_account: Option<String>,
    #[pyo3(get, set)]
    pub market_pool_pc_token_account: Option<String>,

    #[pyo3(get, set)]
    pub raydium_program_id: String,
    #[pyo3(get, set)]
    pub token_program_id: String,
    #[pyo3(get, set)]
    pub system_program_id: String,
    #[pyo3(get, set)]
    pub associated_token_program_id: String,

    #[pyo3(get)]
    pub token_pair_settings: HashMap<String, TokenPairSetting>,
}

#[pymethods]
impl TradingConfig {
    #[new]
    fn new(
        rpc_url: Option<String>,
        ws_url: Option<String>,
        api_key: Option<String>,
        sol_mint: Option<String>,
        rpc_rate_limit: Option<u64>,
        compute_limit: Option<u32>,
        priority_fee: Option<u64>,
        skip_preflight: Option<bool>,
        max_retries: Option<u8>,
        front_run_amount: Option<f64>,
        min_victim_size: Option<f64>,
        max_victim_size: Option<f64>,
        min_profit: Option<f64>,
        slippage_bps: Option<u16>,
        min_sol_balance: Option<f64>,
        min_wsol_balance: Option<f64>,
        raydium_program_id: Option<String>,
        token_program_id: Option<String>,
        system_program_id: Option<String>,
        associated_token_program_id: Option<String>,
        token_mint: Option<String>,
        amm_program: Option<String>,
        amm_id: Option<String>,
        market_amm_authority: Option<String>,
        market_amm_open_orders: Option<String>,
        market_amm_target: Option<String>,
        market_pool_token_account: Option<String>,
        market_pool_pc_token_account: Option<String>,
    ) -> Self {
        // Use a closure to avoid .clone()
        let get_or_default = |key| env::var(key).unwrap_or_else(|_| "".to_string());

        // Fixed SOL_MINT handling with proper fallback
        let sol_mint_value = sol_mint.unwrap_or_else(|| {
            let env_val = get_or_default("SOL_MINT");
            if env_val.is_empty() {
                "So11111111111111111111111111111111111111112".to_string()
            } else {
                env_val
            }
        });

        // Clone amm_program before it's moved
        let amm_program_clone = amm_program.clone();

        // Default to the Raydium V4 program ID if not specified
        let default_raydium_program = "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8".to_string();
        let default_token_program = "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA".to_string();
        let default_system_program = "11111111111111111111111111111111".to_string();
        let default_associated_token_program =
            "ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL".to_string();

        // Fix: Handle raydium_program_id properly
        let raydium_program_value = raydium_program_id.unwrap_or_else(|| {
            if let Some(amm) = amm_program_clone {
                amm
            } else {
                let env_val = get_or_default("RAYDIUM_PROGRAM_ID");
                if env_val.is_empty() {
                    default_raydium_program
                } else {
                    env_val
                }
            }
        });

        // Fix: Handle token_program_id properly
        let token_program_value = token_program_id.unwrap_or_else(|| {
            let env_val = get_or_default("TOKEN_PROGRAM_ID");
            if env_val.is_empty() {
                default_token_program
            } else {
                env_val
            }
        });

        // Fix: Handle system_program_id properly
        let system_program_value = system_program_id.unwrap_or_else(|| {
            let env_val = get_or_default("SYSTEM_PROGRAM_ID");
            if env_val.is_empty() {
                default_system_program
            } else {
                env_val
            }
        });

        // Fix: Handle associated_token_program_id properly
        let associated_token_program_value = associated_token_program_id.unwrap_or_else(|| {
            let env_val = get_or_default("ASSOCIATED_TOKEN_PROGRAM_ID");
            if env_val.is_empty() {
                default_associated_token_program
            } else {
                env_val
            }
        });

        Self {
            rpc_url: rpc_url.unwrap_or_else(|| {
                env::var("RPC_URL")
                    .unwrap_or_else(|_| "https://api.mainnet-beta.solana.com".to_string())
            }),
            ws_url: ws_url.unwrap_or_else(|| {
                env::var("WS_URL")
                    .unwrap_or_else(|_| "wss://api.mainnet-beta.solana.com".to_string())
            }),
            api_key: api_key.unwrap_or_else(|| get_or_default("API_KEY")),
            sol_mint: sol_mint_value,
            rpc_rate_limit: rpc_rate_limit.unwrap_or_else(|| {
                env::var("RPC_RATE_LIMIT")
                    .map(|v| v.parse().unwrap_or(DEFAULT_RPC_RATE_LIMIT))
                    .unwrap_or(DEFAULT_RPC_RATE_LIMIT)
            }),
            // Store additional fields
            token_mint,
            amm_program,
            compute_limit: compute_limit.unwrap_or_else(|| {
                env::var("COMPUTE_LIMIT")
                    .map(|v| v.parse().unwrap_or(COMPUTE_UNITS))
                    .unwrap_or(COMPUTE_UNITS)
            }),
            priority_fee: priority_fee.unwrap_or_else(|| {
                env::var("PRIORITY_FEE")
                    .map(|v| v.parse().unwrap_or(PRIORITY_FEE))
                    .unwrap_or(PRIORITY_FEE)
            }),
            skip_preflight: skip_preflight.unwrap_or_else(|| {
                env::var("SKIP_PREFLIGHT")
                    .map(|v| v.parse().unwrap_or(true))
                    .unwrap_or(true)
            }),
            max_retries: max_retries.unwrap_or_else(|| {
                env::var("MAX_RETRIES")
                    .map(|v| v.parse().unwrap_or(MAX_RETRY_COUNT))
                    .unwrap_or(MAX_RETRY_COUNT)
            }),
            front_run_amount: front_run_amount.unwrap_or_else(|| {
                env::var("FRONT_RUN_AMOUNT")
                    .map(|v| v.parse().unwrap_or(0.35))
                    .unwrap_or(0.35)
            }),
            min_victim_size: min_victim_size.unwrap_or_else(|| {
                env::var("MIN_VICTIM_SIZE")
                    .map(|v| v.parse().unwrap_or(5.0))
                    .unwrap_or(5.0)
            }),
            max_victim_size: max_victim_size.unwrap_or_else(|| {
                env::var("MAX_VICTIM_SIZE")
                    .map(|v| v.parse().unwrap_or(320.0))
                    .unwrap_or(320.0)
            }),
            min_profit: min_profit.unwrap_or_else(|| {
                env::var("MIN_PROFIT")
                    .map(|v| v.parse().unwrap_or(0.002))
                    .unwrap_or(0.002)
            }),
            slippage_bps: slippage_bps.unwrap_or_else(|| {
                env::var("SLIPPAGE_BPS")
                    .map(|v| v.parse().unwrap_or(1000))
                    .unwrap_or(1000)
            }),
            min_sol_balance: min_sol_balance.unwrap_or_else(|| {
                env::var("MIN_SOL_BALANCE")
                    .map(|v| v.parse().unwrap_or(0.03))
                    .unwrap_or(0.03)
            }),
            min_wsol_balance: min_wsol_balance.unwrap_or_else(|| {
                env::var("MIN_WSOL_BALANCE")
                    .map(|v| v.parse().unwrap_or(0.02))
                    .unwrap_or(0.02)
            }),
            // Store additional market parameters
            amm_id,
            market_amm_authority,
            market_amm_open_orders,
            market_amm_target,
            market_pool_token_account,
            market_pool_pc_token_account,
            raydium_program_id: raydium_program_value,
            token_program_id: token_program_value,
            system_program_id: system_program_value,
            associated_token_program_id: associated_token_program_value,
            token_pair_settings: HashMap::new(),
        }
    }

    // Add a token pair setting
    fn add_token_pair_setting(&mut self, token_pair: TokenPairSetting) -> PyResult<()> {
        self.token_pair_settings
            .insert(token_pair.token_mint.clone(), token_pair);
        Ok(())
    }

    // Remove a token pair setting
    fn remove_token_pair_setting(&mut self, token_mint: &str) -> PyResult<bool> {
        Ok(self.token_pair_settings.remove(token_mint).is_some())
    }

    // Get a token pair setting
    fn get_token_pair_setting(&self, token_mint: &str) -> PyResult<Option<TokenPairSetting>> {
        Ok(self.token_pair_settings.get(token_mint).cloned())
    }

    // Get all active token mints
    fn get_active_token_mints(&self) -> PyResult<Vec<String>> {
        Ok(self
            .token_pair_settings
            .iter()
            .filter(|(_, v)| v.enabled)
            .map(|(k, _)| k.clone())
            .collect())
    }

    // Save config to file
    fn save_to_file(&self, path: &str) -> PyResult<()> {
        let json = serde_json::to_string_pretty(&self)
            .map_err(|e| PyValueError::new_err(format!("Failed to serialize config: {}", e)))?;

        fs::write(path, json)
            .map_err(|e| PyValueError::new_err(format!("Failed to write config file: {}", e)))?;

        Ok(())
    }

    // Load config from file
    #[staticmethod]
    fn load_from_file(path: &str) -> PyResult<Self> {
        let json = fs::read_to_string(path)
            .map_err(|e| PyValueError::new_err(format!("Failed to read config file: {}", e)))?;

        let config: Self = serde_json::from_str(&json)
            .map_err(|e| PyValueError::new_err(format!("Failed to parse config file: {}", e)))?;

        Ok(config)
    }

    // Load from environment variables
    #[staticmethod]
    fn from_env() -> PyResult<Self> {
        Ok(Self::new(
            None, None, None, None, None, None, None, None, None, None, None, None, None, None,
            None, None, None, None, None, None, None, None, None, None, None, None, None, None,
        ))
    }
}

// Structure to hold swap parameters
#[pyclass]
#[derive(Clone)]
pub struct SwapParams {
    #[pyo3(get, set)]
    pub token_mint: String,
    #[pyo3(get, set)]
    pub amount_in: f64,
    #[pyo3(get, set)]
    pub is_buy: bool,
    #[pyo3(get, set)]
    pub slippage_bps: u16,
    #[pyo3(get, set)]
    pub compute_limit: u32,
    #[pyo3(get, set)]
    pub priority_fee: u64,
}

#[pymethods]
impl SwapParams {
    #[new]
    fn new(
        token_mint: String,
        amount_in: f64,
        is_buy: bool,
        slippage_bps: Option<u16>,
        compute_limit: Option<u32>,
        priority_fee: Option<u64>,
    ) -> Self {
        Self {
            token_mint,
            amount_in,
            is_buy,
            slippage_bps: slippage_bps.unwrap_or(1000),
            compute_limit: compute_limit.unwrap_or(COMPUTE_UNITS),
            priority_fee: priority_fee.unwrap_or(PRIORITY_FEE),
        }
    }
}

// Structure for transaction status tracking
#[pyclass]
#[derive(Clone)]
pub struct TransactionStatus {
    #[pyo3(get)]
    pub signature: String,
    #[pyo3(get)]
    pub success: bool,
    #[pyo3(get)]
    pub error: Option<String>,
    #[pyo3(get)]
    pub timestamp: u64,
    #[pyo3(get)]
    pub simulation_only: bool,
    #[pyo3(get)]
    pub logs: Option<Vec<String>>,
}

#[pymethods]
impl TransactionStatus {
    #[new]
    fn new(
        signature: String,
        success: bool,
        error: Option<String>,
        timestamp: Option<u64>,
        simulation_only: Option<bool>,
        logs: Option<Vec<String>>,
    ) -> Self {
        Self {
            signature,
            success,
            error,
            timestamp: timestamp.unwrap_or_else(|| {
                SystemTime::now()
                    .duration_since(UNIX_EPOCH)
                    .unwrap()
                    .as_secs()
            }),
            simulation_only: simulation_only.unwrap_or(false),
            logs,
        }
    }
}

// Cache for token metadata
type TokenMetadataCache = Arc<DashMap<String, TokenMetadata>>;

// Simple token metadata for caching
#[derive(Clone, Debug)]
struct TokenMetadata {
    decimals: u8,
    verified: bool,
    last_updated: u64,
}

// Main trading core class
#[pyclass]
pub struct RaydiumTradingCore {
    client: Arc<RpcClient>,
    keypair: Arc<Keypair>,
    config: Arc<RwLock<TradingConfig>>,
    balances: Arc<RwLock<(f64, HashMap<String, f64>)>>, // (SOL, token balances by mint)
    rate_limiter: Arc<RateLimiter>,
    pending_transaction: Arc<AtomicBool>, // Flag to indicate pending transaction
    last_trade_time: Arc<AtomicU64>,      // Store the last trade time
    public_key: String,
    token_cache: TokenMetadataCache,
    transaction_lock: Arc<TokioMutex<bool>>,
}

#[pymethods]
impl RaydiumTradingCore {
    #[new]
    fn new(
        rpc_url: Option<String>,
        private_key: Option<String>,
        keypair_path: Option<String>,
        config: Option<TradingConfig>,
    ) -> PyResult<Self> {
        let config_obj = config.unwrap_or_else(|| {
            TradingConfig::new(
                rpc_url.clone(),
                None,
                None,
                None,
                None,
                None,
                None,
                None,
                None,
                None,
                None,
                None,
                None,
                None,
                None,
                None,
                None,
                None,
                None,
                None,
                None,
                None,
                None,
                None,
                None,
                None,
                None,
                None,
            )
        });

        let client = Arc::new(RpcClient::new_with_commitment(
            rpc_url.unwrap_or_else(|| config_obj.rpc_url.clone()),
            solana_sdk::commitment_config::CommitmentConfig::confirmed(),
        ));

        // Load keypair from either a provided string or file
        let keypair = if let Some(pk) = private_key {
            let bytes = bs58::decode(pk)
                .into_vec()
                .map_err(|e| PyValueError::new_err(format!("Invalid private key: {:?}", e)))?;

            Keypair::from_bytes(&bytes)
                .map_err(|e| PyValueError::new_err(format!("Invalid keypair: {}", e)))?
        } else if let Some(path) = keypair_path {
            if !std::path::Path::new(&path).exists() {
                return Err(PyValueError::new_err(format!(
                    "Keypair file not found: {}",
                    path
                )));
            }

            let bytes = fs::read(&path).map_err(|e| {
                PyValueError::new_err(format!("Failed to read keypair file: {}", e))
            })?;

            Keypair::from_bytes(&bytes)
                .map_err(|e| PyValueError::new_err(format!("Invalid keypair: {}", e)))?
        } else {
            let private_key = env::var("SOLANA_PRIVATE_KEY").map_err(|_| {
                PyValueError::new_err("SOLANA_PRIVATE_KEY not found in environment")
            })?;

            let secret_key_bytes = bs58::decode(&private_key).into_vec().map_err(|e| {
                PyValueError::new_err(format!("Invalid private key encoding: {:?}", e))
            })?;

            Keypair::from_bytes(&secret_key_bytes)
                .map_err(|e| PyValueError::new_err(format!("Invalid keypair: {}", e)))?
        };

        let rate_limiter = Arc::new(RateLimiter::new(config_obj.rpc_rate_limit));
        let public_key = keypair.pubkey().to_string();
        let token_cache = Arc::new(DashMap::new());
        let transaction_lock = Arc::new(TokioMutex::new(false));

        Ok(Self {
            client,
            keypair: Arc::new(keypair),
            config: Arc::new(RwLock::new(config_obj)),
            balances: Arc::new(RwLock::new((0.0, HashMap::new()))),
            rate_limiter,
            pending_transaction: Arc::new(AtomicBool::new(false)),
            last_trade_time: Arc::new(AtomicU64::new(0)),
            public_key,
            token_cache,
            transaction_lock,
        })
    }

    // Get the public key for logging/display
    fn get_public_key(&self) -> String {
        self.public_key.clone()
    }

    // Execute custom swap with raw instruction data
    fn execute_custom_swap<'py>(
        &self,
        py: Python<'py>,
        token_mint: String,
        instruction_data: Vec<u8>,
    ) -> PyResult<&'py PyAny> {
        let client = self.client.clone();
        let keypair = self.keypair.clone();
        let config_arc = self.config.clone();
        let pending_transaction = self.pending_transaction.clone();
        let transaction_lock = self.transaction_lock.clone();

        // Debug logging for instruction data
        debug!("Custom swap instruction data: {:?}", instruction_data);

        if instruction_data.len() < 9 {
            return Err(PyValueError::new_err(format!(
                "Instruction data too short: {} bytes, need at least 9",
                instruction_data.len()
            )));
        }

        // Debug - verify instruction type and amount
        debug!("Instruction type: 0x{:02x}", instruction_data[0]);
        let amount_bytes = &instruction_data[1..9];

        // Convert amount_bytes to a u64 (little-endian)
        let mut amount_array = [0u8; 8];
        amount_array.copy_from_slice(amount_bytes);
        let amount_lamports = u64::from_le_bytes(amount_array);
        debug!("Amount (lamports): {}", amount_lamports);
        debug!("Amount (SOL): {}", amount_lamports as f64 / 1_000_000_000.0);

        // Ensure the instruction type is correct for AMM swap
        if instruction_data[0] != RAYDIUM_SWAP_INSTRUCTION {
            debug!(
                "Instruction type is not 0x{:02x}. Received: 0x{:02x}",
                RAYDIUM_SWAP_INSTRUCTION, instruction_data[0]
            );
            debug!("Creating correct instruction data");

            // Don't return an error here, instead, fix the instruction data
            let mut fixed_data = vec![RAYDIUM_SWAP_INSTRUCTION];
            fixed_data.extend_from_slice(amount_bytes);
            debug!("Fixed instruction data: {:?}", fixed_data);

            // Continue with fixed data
            let result = self.execute_custom_swap(py, token_mint, fixed_data);
            return result;
        }

        // Ensure we're not already processing a transaction
        if pending_transaction.load(Ordering::Relaxed) {
            return Err(PyValueError::new_err(
                "A transaction is already in progress",
            ));
        }

        pyo3_asyncio::tokio::future_into_py(py, async move {
            // Use a mutex for transaction processing
            let _lock = transaction_lock.lock().await;

            // Set pending transaction flag
            pending_transaction.store(true, Ordering::Relaxed);

            // Get config
            let config = match config_arc.read() {
                Ok(config) => config.clone(),
                Err(_) => {
                    pending_transaction.store(false, Ordering::Relaxed);
                    return Err(PyValueError::new_err("Failed to read config"));
                }
            };

            // Get token pair settings
            let token_pair = match config.token_pair_settings.get(&token_mint) {
                Some(settings) => settings.clone(),
                None => {
                    // CHANGED: Instead of returning an error, dynamically create token pair settings
                    debug!(
                        "No token pair settings found for {}. Creating dynamically.",
                        token_mint
                    );

                    // Create a SOL mint reference
                    let sol_mint = "So11111111111111111111111111111111111111112";

                    // Create a default token pair setting for this token
                    // This assumes we're trading on the main Raydium V4 program
                    let default_pair = TokenPairSetting {
                        token_mint: token_mint.clone(),
                        amm_id: "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8".to_string(),
                        amm_authority: "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1".to_string(),
                        amm_open_orders: "FrR9FBcDuPyMrAtUNWD3MazLyMBvJ3GjWTVLWgYtGjpG".to_string(), // Placeholder
                        amm_target: "3uahGNzFuzSAo6QpucjfyzJkGCiZbmLEShKDXRMcEjjF".to_string(), // Placeholder
                        pool_token_account: "83v8iPyZihDEjDDv9zxcm9P67MkrNfFXQocfaGmh8BSm"
                            .to_string(), // Placeholder
                        pool_pc_account: "8xKCx3SGwWR6BUr9mZFm3xwZUHFAVxeRUHPTpjYMJp6q".to_string(), // Placeholder
                        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,
                    };

                    // In a production system, we would query on-chain data here
                    // to find the correct AMM and pool accounts
                    // For now, we'll just use placeholders

                    // Log a warning about using placeholder data
                    debug!(
                        "CAUTION: Using placeholder pool accounts for {}. Transaction may fail.",
                        token_mint
                    );

                    default_pair
                }
            };

            // Parse Pubkeys
            let token_mint_pubkey = match Pubkey::from_str(&token_mint) {
                Ok(pubkey) => pubkey,
                Err(e) => {
                    pending_transaction.store(false, Ordering::Relaxed);
                    return Err(PyValueError::new_err(format!("Invalid token mint: {}", e)));
                }
            };

            // Create accounts for the swap
            let wallet_pubkey = keypair.pubkey();

            // Get user's WSOL account
            let wsol_mint = Pubkey::from_str(&config.sol_mint).unwrap();
            let user_wsol_account = get_associated_token_address(&wallet_pubkey, &wsol_mint);

            // Get user's token account
            let user_token_account =
                get_associated_token_address(&wallet_pubkey, &token_mint_pubkey);

            // Parse other account pubkeys
            let raydium_program = Pubkey::from_str(&config.raydium_program_id).unwrap();
            let amm_authority = Pubkey::from_str(&token_pair.amm_authority).unwrap();
            let amm_open_orders = Pubkey::from_str(&token_pair.amm_open_orders).unwrap();
            let amm_target = Pubkey::from_str(&token_pair.amm_target).unwrap();
            let pool_coin = Pubkey::from_str(&token_pair.pool_token_account).unwrap();
            let pool_pc = Pubkey::from_str(&token_pair.pool_pc_account).unwrap();
            let token_program =
                Pubkey::from_str(&config.token_program_id).unwrap_or_else(|_| spl_token::id());

            // Debug logging
            debug!("Preparing AMM swap with accounts:");
            debug!("Program ID: {}", raydium_program);
            debug!("AMM Authority: {}", amm_authority);
            debug!("AMM Open Orders: {}", amm_open_orders);
            debug!("AMM Target: {}", amm_target);
            debug!("Pool Token Account: {}", pool_coin);
            debug!("Pool PC Account: {}", pool_pc);
            debug!("Token Mint: {}", token_mint_pubkey);
            debug!("User WSOL Account: {}", user_wsol_account);
            debug!("User Token Account: {}", user_token_account);
            debug!("Wallet: {}", wallet_pubkey);

            // Create swap instruction - IMPORTANT: Use exact instruction data
            let swap_ix = Instruction {
                program_id: raydium_program,
                accounts: vec![
                    AccountMeta::new_readonly(raydium_program, false),
                    AccountMeta::new_readonly(amm_authority, false),
                    AccountMeta::new(amm_open_orders, false),
                    AccountMeta::new(amm_target, false),
                    AccountMeta::new(pool_coin, false),
                    AccountMeta::new(pool_pc, false),
                    AccountMeta::new_readonly(token_mint_pubkey, false),
                    AccountMeta::new(user_wsol_account, false),
                    AccountMeta::new(wallet_pubkey, true),
                    AccountMeta::new_readonly(token_program, false),
                ],
                data: instruction_data.clone(),
            };

            // Add compute budget instructions
            let compute_limit_ix =
                ComputeBudgetInstruction::set_compute_unit_limit(config.compute_limit);
            let priority_fee_ix =
                ComputeBudgetInstruction::set_compute_unit_price(config.priority_fee);

            // Create ATA instruction if needed
            let mut instructions = vec![compute_limit_ix, priority_fee_ix];

            // Check if WSOL ATA exists
            let wsol_account_exists = match client.get_account(&user_wsol_account).await {
                Ok(_) => true,
                Err(_) => false,
            };

            // Create WSOL ATA if needed
            if !wsol_account_exists {
                debug!("Creating WSOL ATA account");
                let ata_ix = create_associated_token_account_idempotent(
                    &wallet_pubkey,
                    &wallet_pubkey,
                    &wsol_mint,
                    &token_program,
                );
                instructions.push(ata_ix);
            }

            // IMPORTANT NEW PART: Check if token ATA exists
            let token_account_exists = match client.get_account(&user_token_account).await {
                Ok(_) => true,
                Err(_) => false,
            };

            // Create token ATA if needed - this ensures we can receive tokens
            if !token_account_exists {
                debug!("Creating token ATA account for {}", token_mint);
                let ata_ix = create_associated_token_account_idempotent(
                    &wallet_pubkey,
                    &wallet_pubkey,
                    &token_mint_pubkey,
                    &token_program,
                );
                instructions.push(ata_ix);
            }

            // Add the swap instruction
            instructions.push(swap_ix);

            // Create transaction
            let mut transaction = Transaction::new_with_payer(&instructions, Some(&wallet_pubkey));

            // Get recent blockhash
            let blockhash = match client.get_latest_blockhash().await {
                Ok(blockhash) => blockhash,
                Err(e) => {
                    pending_transaction.store(false, Ordering::Relaxed);
                    return Err(PyValueError::new_err(format!(
                        "Failed to get recent blockhash: {}",
                        e
                    )));
                }
            };

            // Sign transaction
            transaction.sign(&[&*keypair], blockhash);

            // Send transaction
            debug!(
                "Sending transaction with instruction data: {:?}",
                instruction_data
            );
            let send_options = RpcSendTransactionConfig {
                skip_preflight: config.skip_preflight,
                preflight_commitment: Some(CommitmentLevel::Confirmed),
                encoding: None,
                max_retries: Some(config.max_retries.into()),
                min_context_slot: None,
            };

            // Attempt to send transaction
            let result = client
                .send_transaction_with_config(&transaction, send_options)
                .await;

            // Reset pending transaction flag
            pending_transaction.store(false, Ordering::Relaxed);

            match result {
                Ok(signature) => {
                    debug!("Transaction successful: {}", signature);
                    let status = TransactionStatus::new(
                        signature.to_string(),
                        true,
                        None,
                        Some(
                            SystemTime::now()
                                .duration_since(UNIX_EPOCH)
                                .unwrap()
                                .as_secs(),
                        ),
                        Some(false),
                        None,
                    );
                    Ok(status)
                }
                Err(e) => {
                    debug!("Transaction failed: {}", e);
                    let error_msg = e.to_string();

                    // Check if this is a common Raydium error and provide more info
                    if error_msg.contains("0x6") {
                        debug!("This appears to be a Raydium swap instruction error. Check the following:");
                        debug!("1. Make sure the token mint address is correct");
                        debug!("2. Make sure the AMM ID is correct");
                        debug!("3. Check if there's enough liquidity in the pool");
                    }

                    let status = TransactionStatus::new(
                        "failed".to_string(),
                        false,
                        Some(error_msg),
                        Some(
                            SystemTime::now()
                                .duration_since(UNIX_EPOCH)
                                .unwrap()
                                .as_secs(),
                        ),
                        Some(false),
                        None,
                    );
                    Ok(status)
                }
            }
        })
    }

    // Function to execute a swap on Raydium
    fn execute_swap<'py>(&self, py: Python<'py>, params: SwapParams) -> PyResult<&'py PyAny> {
        let client = self.client.clone();
        let keypair = self.keypair.clone();
        let config_arc = self.config.clone();
        let _rate_limiter = self.rate_limiter.clone();
        let pending_transaction = self.pending_transaction.clone();
        let transaction_lock = self.transaction_lock.clone();

        // Check if a transaction is already pending
        if pending_transaction.load(Ordering::Relaxed) {
            return Err(PyValueError::new_err(
                "A transaction is already in progress",
            ));
        }

        let params_clone = params.clone();

        pyo3_asyncio::tokio::future_into_py(py, async move {
            // Use a mutex for transaction processing
            let _lock = transaction_lock.lock().await;

            // Set pending transaction flag
            pending_transaction.store(true, Ordering::Relaxed);

            // Get config values
            let config = match config_arc.read() {
                Ok(config) => config.clone(),
                Err(_) => {
                    pending_transaction.store(false, Ordering::Relaxed);
                    return Err(PyValueError::new_err("Failed to read config"));
                }
            };

            // Retrieve token pair settings
            let token_pair = match config.token_pair_settings.get(&params_clone.token_mint) {
                Some(settings) => settings.clone(),
                None => {
                    if Some(params_clone.token_mint.clone()) == config.token_mint {
                        // Handle synthetic token pair logic
                        let all_present = config.amm_id.is_some()
                            && config.market_amm_authority.is_some()
                            && config.market_amm_open_orders.is_some()
                            && config.market_amm_target.is_some()
                            && config.market_pool_token_account.is_some()
                            && config.market_pool_pc_token_account.is_some();

                        if all_present {
                            // Return synthetic settings
                            TokenPairSetting {
                                token_mint: params_clone.token_mint.clone(),
                                amm_id: config.amm_id.clone().unwrap(),
                                amm_authority: config
                                    .market_amm_authority
                                    .as_ref()
                                    .unwrap()
                                    .clone(),
                                amm_open_orders: config
                                    .market_amm_open_orders
                                    .as_ref()
                                    .unwrap()
                                    .clone(),
                                amm_target: config.market_amm_target.as_ref().unwrap().clone(),
                                pool_token_account: config
                                    .market_pool_token_account
                                    .as_ref()
                                    .unwrap()
                                    .clone(),
                                pool_pc_account: config
                                    .market_pool_pc_token_account
                                    .as_ref()
                                    .unwrap()
                                    .clone(),
                                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,
                            }
                        } else {
                            // Create default settings with placeholders like in execute_custom_swap
                            debug!(
                                "No token pair settings found for {}. Creating dynamically.",
                                params_clone.token_mint
                            );

                            // Create a default token pair setting for this token
                            TokenPairSetting {
                                token_mint: params_clone.token_mint.clone(),
                                amm_id: "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8".to_string(),
                                amm_authority: "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1"
                                    .to_string(),
                                amm_open_orders: "FrR9FBcDuPyMrAtUNWD3MazLyMBvJ3GjWTVLWgYtGjpG"
                                    .to_string(), // Placeholder
                                amm_target: "3uahGNzFuzSAo6QpucjfyzJkGCiZbmLEShKDXRMcEjjF"
                                    .to_string(), // Placeholder
                                pool_token_account: "83v8iPyZihDEjDDv9zxcm9P67MkrNfFXQocfaGmh8BSm"
                                    .to_string(), // Placeholder
                                pool_pc_account: "8xKCx3SGwWR6BUr9mZFm3xwZUHFAVxeRUHPTpjYMJp6q"
                                    .to_string(), // Placeholder
                                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,
                            }
                        }
                    } else {
                        // Create default settings with placeholders like in execute_custom_swap
                        debug!(
                            "No token pair settings found for {}. Creating dynamically.",
                            params_clone.token_mint
                        );

                        // Create a default token pair setting for this token
                        TokenPairSetting {
                            token_mint: params_clone.token_mint.clone(),
                            amm_id: "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8".to_string(),
                            amm_authority: "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1"
                                .to_string(),
                            amm_open_orders: "FrR9FBcDuPyMrAtUNWD3MazLyMBvJ3GjWTVLWgYtGjpG"
                                .to_string(), // Placeholder
                            amm_target: "3uahGNzFuzSAo6QpucjfyzJkGCiZbmLEShKDXRMcEjjF".to_string(), // Placeholder
                            pool_token_account: "83v8iPyZihDEjDDv9zxcm9P67MkrNfFXQocfaGmh8BSm"
                                .to_string(), // Placeholder
                            pool_pc_account: "8xKCx3SGwWR6BUr9mZFm3xwZUHFAVxeRUHPTpjYMJp6q"
                                .to_string(), // Placeholder
                            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,
                        }
                    }
                }
            };

            // Generate, sign, and send a transaction to perform the swap
            let _token_mint_pubkey = match Pubkey::from_str(&params_clone.token_mint) {
                Ok(pubkey) => pubkey,
                Err(e) => {
                    pending_transaction.store(false, Ordering::Relaxed);
                    return Err(PyValueError::new_err(format!("Invalid token mint: {}", e)));
                }
            };

            // Create proper instruction data with correct byte ordering
            let amount_lamports = (params_clone.amount_in * LAMPORTS_PER_SOL as f64) as u64;
            let mut instruction_data = Vec::with_capacity(9);
            instruction_data.push(RAYDIUM_SWAP_INSTRUCTION); // Fixed to 6
            instruction_data.extend_from_slice(&amount_lamports.to_le_bytes()); // Amount in little-endian

            debug!("Created swap instruction with data: {:?}", instruction_data);

            // Create and send transaction with the proper instruction data
            let result = execute_swap_internal(
                &client,
                &keypair,
                &token_pair,
                &instruction_data,
                params_clone.is_buy,
            )
            .await;

            // Reset pending transaction flag
            pending_transaction.store(false, Ordering::Relaxed);

            match result {
                Ok(signature) => {
                    let status = TransactionStatus::new(
                        signature,
                        true,
                        None,
                        Some(
                            SystemTime::now()
                                .duration_since(UNIX_EPOCH)
                                .unwrap()
                                .as_secs(),
                        ),
                        Some(false),
                        None,
                    );
                    Ok(status)
                }
                Err(e) => {
                    let status = TransactionStatus::new(
                        "failed".to_string(),
                        false,
                        Some(e.to_string()),
                        Some(
                            SystemTime::now()
                                .duration_since(UNIX_EPOCH)
                                .unwrap()
                                .as_secs(),
                        ),
                        Some(false),
                        None,
                    );
                    Ok(status)
                }
            }
        })
    }

    // Get balances for SOL and SPL tokens
    fn get_balances<'py>(&self, py: Python<'py>) -> PyResult<&'py PyAny> {
        let client = self.client.clone();
        let keypair = self.keypair.clone();
        let config_arc = self.config.clone();
        let balances_arc = self.balances.clone();

        pyo3_asyncio::tokio::future_into_py(py, async move {
            let pubkey = keypair.pubkey();

            // Get SOL balance
            let sol_balance = client
                .get_balance(&pubkey)
                .await
                .map_err(|e| PyValueError::new_err(format!("Failed to get SOL balance: {}", e)))?;

            let sol_balance_f64 = sol_balance as f64 / LAMPORTS_PER_SOL as f64;

            // Get config
            let config = match config_arc.read() {
                Ok(config) => config.clone(),
                Err(_) => return Err(PyValueError::new_err("Failed to read config")),
            };

            // Get token balances
            let mut token_balances = HashMap::new();

            // Add WSOL balance
            let wsol_token_account =
                get_associated_token_address(&pubkey, &Pubkey::from_str(&config.sol_mint).unwrap());

            // Check if token account exists
            let wsol_account = client.get_account(&wsol_token_account).await;

            if let Ok(account) = wsol_account {
                // Parse token account data
                if let Ok(token_account) =
                    spl_token::state::Account::unpack_from_slice(&account.data)
                {
                    let wsol_balance = token_account.amount as f64 / LAMPORTS_PER_SOL as f64;
                    token_balances.insert(config.sol_mint.clone(), wsol_balance);
                }
            } else {
                // Account doesn't exist, balance is 0
                token_balances.insert(config.sol_mint.clone(), 0.0);
            }

            // Get token balances for all active tokens
            for token_mint in config.get_active_token_mints()? {
                if token_mint == config.sol_mint {
                    continue; // Already added WSOL above
                }

                let token_account = get_associated_token_address(
                    &pubkey,
                    &Pubkey::from_str(&token_mint)
                        .map_err(|e| PyValueError::new_err(format!("Invalid token mint: {}", e)))?,
                );

                // Check if token account exists
                let account = client.get_account(&token_account).await;

                if let Ok(account) = account {
                    // Parse token account data
                    if let Ok(token_account) =
                        spl_token::state::Account::unpack_from_slice(&account.data)
                    {
                        // We would need token decimals to convert properly, but using 9 as default
                        let token_balance = token_account.amount as f64 / LAMPORTS_PER_SOL as f64;
                        token_balances.insert(token_mint, token_balance);
                    }
                } else {
                    // Account doesn't exist, balance is 0
                    token_balances.insert(token_mint, 0.0);
                }
            }

            // Update cached balances
            if let Ok(mut balances) = balances_arc.write() {
                *balances = (sol_balance_f64, token_balances.clone());
            }

            Ok((sol_balance_f64, token_balances))
        })
    }

    // Create or get associated token account for a token mint
    fn ensure_ata<'py>(&self, py: Python<'py>, token_mint: String) -> PyResult<&'py PyAny> {
        let client = self.client.clone();
        let keypair = self.keypair.clone();

        pyo3_asyncio::tokio::future_into_py(py, async move {
            let pubkey = keypair.pubkey();

            // Parse token mint
            let token_mint_pubkey = Pubkey::from_str(&token_mint)
                .map_err(|e| PyValueError::new_err(format!("Invalid token mint: {}", e)))?;

            // Get associated token account address
            let ata = get_associated_token_address(&pubkey, &token_mint_pubkey);

            // Check if account exists
            let account = client.get_account(&ata).await;

            if account.is_err() {
                // Create ATA instruction
                let ix = create_associated_token_account_idempotent(
                    &pubkey,            // Payer
                    &pubkey,            // Owner
                    &token_mint_pubkey, // Mint
                    &spl_token::id(),   // Token program
                );

                // Create transaction
                let mut transaction = Transaction::new_with_payer(&[ix], Some(&pubkey));

                // Get recent blockhash
                let blockhash = client.get_latest_blockhash().await.map_err(|e| {
                    PyValueError::new_err(format!("Failed to get blockhash: {}", e))
                })?;

                // Sign transaction
                transaction.sign(&[&*keypair], blockhash);

                // Send transaction
                let signature = client
                    .send_transaction(&transaction)
                    .await
                    .map_err(|e| PyValueError::new_err(format!("Failed to create ATA: {}", e)))?;

                debug!("Created ATA for {}: {}", token_mint, signature);
            }

            Ok(ata.to_string())
        })
    }

    // Update ML signal (placeholder)
    fn update_ml_signal(&self, key: String, value: f64) -> PyResult<()> {
        // This is a placeholder for ML signal update functionality
        debug!("Updated ML signal: {} = {}", key, value);
        Ok(())
    }

    // Helper to create instruction data with correct format
    fn create_amm_instruction_data(&self, amount_sol: f64) -> PyResult<Vec<u8>> {
        // Convert SOL to lamports
        let amount_lamports = (amount_sol * LAMPORTS_PER_SOL as f64) as u64;

        // Create instruction data with correct byte ordering
        let mut instruction_data = Vec::with_capacity(9);
        instruction_data.push(RAYDIUM_SWAP_INSTRUCTION); // Fixed to 6 (constant)

        // Set amount bytes in little-endian format (least significant byte first)
        instruction_data.extend_from_slice(&amount_lamports.to_le_bytes());

        Ok(instruction_data)
    }

    // Simulate transaction before sending
    fn simulate_swap<'py>(
        &self,
        py: Python<'py>,
        token_mint: String,
        amount_sol: f64,
    ) -> PyResult<&'py PyAny> {
        let client = self.client.clone();
        let keypair = self.keypair.clone();
        let config_arc = self.config.clone();

        pyo3_asyncio::tokio::future_into_py(py, async move {
            // Get config
            let config = match config_arc.read() {
                Ok(config) => config.clone(),
                Err(_) => return Err(PyValueError::new_err("Failed to read config")),
            };

            // Create instruction data
            let amount_lamports = (amount_sol * LAMPORTS_PER_SOL as f64) as u64;
            let mut instruction_data = Vec::with_capacity(9);
            instruction_data.push(RAYDIUM_SWAP_INSTRUCTION); // 6 for swap
            instruction_data.extend_from_slice(&amount_lamports.to_le_bytes());

            // Get token pair settings (similar to execute_custom_swap)
            let token_pair = match config.token_pair_settings.get(&token_mint) {
                Some(settings) => settings.clone(),
                None => {
                    // Create default settings like in execute_custom_swap
                    debug!(
                        "No token pair settings found for {}. Creating dynamically for simulation.",
                        token_mint
                    );

                    TokenPairSetting {
                        token_mint: token_mint.clone(),
                        amm_id: "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8".to_string(),
                        amm_authority: "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1".to_string(),
                        amm_open_orders: "FrR9FBcDuPyMrAtUNWD3MazLyMBvJ3GjWTVLWgYtGjpG".to_string(), // Placeholder
                        amm_target: "3uahGNzFuzSAo6QpucjfyzJkGCiZbmLEShKDXRMcEjjF".to_string(), // Placeholder
                        pool_token_account: "83v8iPyZihDEjDDv9zxcm9P67MkrNfFXQocfaGmh8BSm"
                            .to_string(), // Placeholder
                        pool_pc_account: "8xKCx3SGwWR6BUr9mZFm3xwZUHFAVxeRUHPTpjYMJp6q".to_string(), // Placeholder
                        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,
                    }
                }
            };

            // Build transaction similar to execute_custom_swap
            let wallet_pubkey = keypair.pubkey();
            let token_mint_pubkey = match Pubkey::from_str(&token_mint) {
                Ok(pubkey) => pubkey,
                Err(e) => return Err(PyValueError::new_err(format!("Invalid token mint: {}", e))),
            };
            let wsol_mint = Pubkey::from_str(&config.sol_mint).unwrap();
            let user_wsol_account = get_associated_token_address(&wallet_pubkey, &wsol_mint);

            // Parse other account pubkeys
            let raydium_program = Pubkey::from_str(&config.raydium_program_id).unwrap();
            let amm_authority = Pubkey::from_str(&token_pair.amm_authority).unwrap();
            let amm_open_orders = Pubkey::from_str(&token_pair.amm_open_orders).unwrap();
            let amm_target = Pubkey::from_str(&token_pair.amm_target).unwrap();
            let pool_coin = Pubkey::from_str(&token_pair.pool_token_account).unwrap();
            let pool_pc = Pubkey::from_str(&token_pair.pool_pc_account).unwrap();
            let token_program =
                Pubkey::from_str(&config.token_program_id).unwrap_or_else(|_| spl_token::id());

            // Create swap instruction
            let swap_ix = Instruction {
                program_id: raydium_program,
                accounts: vec![
                    AccountMeta::new_readonly(raydium_program, false),
                    AccountMeta::new_readonly(amm_authority, false),
                    AccountMeta::new(amm_open_orders, false),
                    AccountMeta::new(amm_target, false),
                    AccountMeta::new(pool_coin, false),
                    AccountMeta::new(pool_pc, false),
                    AccountMeta::new_readonly(token_mint_pubkey, false),
                    AccountMeta::new(user_wsol_account, false),
                    AccountMeta::new(wallet_pubkey, true),
                    AccountMeta::new_readonly(token_program, false),
                ],
                data: instruction_data,
            };

            // Add compute budget instructions
            let compute_limit_ix =
                ComputeBudgetInstruction::set_compute_unit_limit(config.compute_limit);
            let priority_fee_ix =
                ComputeBudgetInstruction::set_compute_unit_price(config.priority_fee);

            // Create transaction
            let mut instructions = vec![compute_limit_ix, priority_fee_ix, swap_ix];

            // Create ATA instruction if needed
            let wsol_account_exists = match client.get_account(&user_wsol_account).await {
                Ok(_) => true,
                Err(_) => false,
            };

            if !wsol_account_exists {
                let ata_ix = create_associated_token_account_idempotent(
                    &wallet_pubkey,
                    &wallet_pubkey,
                    &wsol_mint,
                    &token_program,
                );
                instructions.insert(2, ata_ix); // Insert before swap instruction
            }

            // Also check if token ATA needs to be created
            let user_token_account =
                get_associated_token_address(&wallet_pubkey, &token_mint_pubkey);
            let token_account_exists = match client.get_account(&user_token_account).await {
                Ok(_) => true,
                Err(_) => false,
            };

            if !token_account_exists {
                let ata_ix = create_associated_token_account_idempotent(
                    &wallet_pubkey,
                    &wallet_pubkey,
                    &token_mint_pubkey,
                    &token_program,
                );
                instructions.insert(2, ata_ix); // Insert before swap instruction
            }

            // Create transaction
            let mut transaction = Transaction::new_with_payer(&instructions, Some(&wallet_pubkey));

            // Get recent blockhash
            let blockhash = match client.get_latest_blockhash().await {
                Ok(blockhash) => blockhash,
                Err(e) => {
                    return Err(PyValueError::new_err(format!(
                        "Failed to get blockhash: {}",
                        e
                    )))
                }
            };
            transaction.sign(&[&*keypair], blockhash);

            // Simulate transaction
            let sim_result = match client.simulate_transaction(&transaction).await {
                Ok(result) => result,
                Err(e) => return Err(PyValueError::new_err(format!("Simulation failed: {}", e))),
            };

            // Create and return status object
            let logs = if let Some(logs) = sim_result.value.logs {
                logs
            } else {
                vec![]
            };

            let status = TransactionStatus::new(
                "simulation".to_string(),
                sim_result.value.err.is_none(),
                sim_result.value.err.map(|e| format!("{:?}", e)),
                Some(
                    SystemTime::now()
                        .duration_since(UNIX_EPOCH)
                        .unwrap()
                        .as_secs(),
                ),
                Some(true),
                Some(logs),
            );

            Ok(status)
        })
    }
}

// Function to create and send a Raydium swap transaction
async fn execute_swap_internal(
    client: &RpcClient,
    keypair: &Arc<Keypair>,
    token_pair: &TokenPairSetting,
    instruction_data: &Vec<u8>,
    _is_buy: bool,
) -> Result<String, PyErr> {
    // Parse needed pubkeys
    let wallet_pubkey = keypair.pubkey();
    let token_mint = Pubkey::from_str(&token_pair.token_mint)
        .map_err(|e| PyValueError::new_err(format!("Invalid token mint: {}", e)))?;
    let wsol_mint = Pubkey::from_str("So11111111111111111111111111111111111111112").unwrap();
    let raydium_program = Pubkey::from_str("675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8").unwrap();
    let token_program = spl_token::id();

    // Get token account for this wallet
    let token_account = get_associated_token_address(&wallet_pubkey, &token_mint);
    let wsol_account = get_associated_token_address(&wallet_pubkey, &wsol_mint);

    // Create ATA instruction if needed
    let mut instructions = Vec::new();

    // Add compute budget instructions
    let compute_limit_ix = ComputeBudgetInstruction::set_compute_unit_limit(50000);
    let priority_fee_ix = ComputeBudgetInstruction::set_compute_unit_price(950000); // Increased priority
    instructions.push(compute_limit_ix);
    instructions.push(priority_fee_ix);

    // Check if token account exists
    let token_account_exists = match client.get_account(&token_account).await {
        Ok(_) => true,
        Err(_) => false,
    };

    // Check if WSOL account exists
    let wsol_account_exists = match client.get_account(&wsol_account).await {
        Ok(_) => true,
        Err(_) => false,
    };

    // Create token account if needed
    if !token_account_exists {
        debug!("Creating token account for {}", token_mint);
        let ix = create_associated_token_account_idempotent(
            &wallet_pubkey,
            &wallet_pubkey,
            &token_mint,
            &token_program,
        );
        instructions.push(ix);
    }

    // Create WSOL account if needed
    if !wsol_account_exists {
        debug!("Creating WSOL account");
        let ix = create_associated_token_account_idempotent(
            &wallet_pubkey,
            &wallet_pubkey,
            &wsol_mint,
            &token_program,
        );
        instructions.push(ix);
    }

    // Parse AMM account pubkeys
    let amm_authority = Pubkey::from_str(&token_pair.amm_authority)
        .map_err(|e| PyValueError::new_err(format!("Invalid AMM authority: {}", e)))?;
    let amm_open_orders = Pubkey::from_str(&token_pair.amm_open_orders)
        .map_err(|e| PyValueError::new_err(format!("Invalid AMM open orders: {}", e)))?;
    let amm_target = Pubkey::from_str(&token_pair.amm_target)
        .map_err(|e| PyValueError::new_err(format!("Invalid AMM target: {}", e)))?;
    let pool_token_account = Pubkey::from_str(&token_pair.pool_token_account)
        .map_err(|e| PyValueError::new_err(format!("Invalid pool token account: {}", e)))?;
    let pool_pc_account = Pubkey::from_str(&token_pair.pool_pc_account)
        .map_err(|e| PyValueError::new_err(format!("Invalid pool PC account: {}", e)))?;

    // Debug log the instruction data
    debug!("Swap instruction data: {:?}", instruction_data);

    // Create swap instruction
    let swap_accounts = vec![
        AccountMeta::new_readonly(raydium_program, false),
        AccountMeta::new_readonly(amm_authority, false),
        AccountMeta::new(amm_open_orders, false),
        AccountMeta::new(amm_target, false),
        AccountMeta::new(pool_token_account, false),
        AccountMeta::new(pool_pc_account, false),
        AccountMeta::new(token_mint, false),
        AccountMeta::new(wsol_account, false),
        AccountMeta::new(wallet_pubkey, true),
        AccountMeta::new_readonly(token_program, false),
    ];

    let swap_ix = Instruction {
        program_id: raydium_program,
        accounts: swap_accounts,
        data: instruction_data.clone(),
    };

    instructions.push(swap_ix);

    // Create transaction
    let mut transaction = Transaction::new_with_payer(&instructions, Some(&wallet_pubkey));

    // Get recent blockhash
    let blockhash = client
        .get_latest_blockhash()
        .await
        .map_err(|e| PyValueError::new_err(format!("Failed to get recent blockhash: {}", e)))?;

    // Sign transaction
    transaction.sign(&[&*keypair], blockhash);

    // Send transaction with options
    let send_options = RpcSendTransactionConfig {
        skip_preflight: true,
        preflight_commitment: Some(CommitmentLevel::Confirmed),
        encoding: None,
        max_retries: Some(3),
        min_context_slot: None,
    };

    let signature = client
        .send_transaction_with_config(&transaction, send_options)
        .await
        .map_err(|e| PyValueError::new_err(format!("Failed to send transaction: {}", e)))?;

    Ok(signature.to_string())
}

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

    m.add_class::<TradingConfig>()?;
    m.add_class::<TokenPairSetting>()?;
    m.add_class::<SwapParams>()?;
    m.add_class::<TransactionStatus>()?;
    m.add_class::<RaydiumTradingCore>()?;

    Ok(())
}
 vs // src/lib.rs - Solana Trading Bot for Python with PyO3
// High-performance trading core with CUDA acceleration support

use log::debug;
use pyo3::exceptions::PyValueError;
use pyo3::prelude::*;
use pyo3_log;

// Use bs58 for base58 encoding/decoding
use bs58;
use serde::{Deserialize, Serialize};

use solana_client::nonblocking::rpc_client::RpcClient;
use solana_client::rpc_config::RpcSendTransactionConfig;
use solana_sdk::{
    commitment_config::CommitmentLevel,
    compute_budget::ComputeBudgetInstruction,
    instruction::{AccountMeta, Instruction},
    program_pack::Pack, // Added Pack trait for token account unpacking
    pubkey::Pubkey,
    signature::{Keypair, Signer},
    transaction::Transaction,
};
use spl_associated_token_account::{
    get_associated_token_address, instruction::create_associated_token_account_idempotent,
};

use dashmap::DashMap;
use std::collections::HashMap;
use std::env;
use std::fs;
use std::str::FromStr;
use std::sync::atomic::{AtomicBool, AtomicU64, Ordering};
use std::sync::{Arc, RwLock};
use std::time::{Duration, SystemTime, UNIX_EPOCH};
use tokio::sync::Mutex as TokioMutex;
use tokio::time::sleep;

// Constants
const COMPUTE_UNITS: u32 = 50_000;
const PRIORITY_FEE: u64 = 950_000; // Increased for higher priority
const LAMPORTS_PER_SOL: u64 = 1_000_000_000;
const DEFAULT_RPC_RATE_LIMIT: u64 = 4; // Reduced from 5 to 4 for safer operation
const MAX_RETRY_COUNT: u8 = 3;
const RAYDIUM_SWAP_INSTRUCTION: u8 = 6; // Important: Raydium swap instruction code
const INITIAL_BACKOFF_MS: u64 = 100; // Initial backoff of 100ms
const MAX_BACKOFF_MS: u64 = 1000; // Max backoff of 1000ms (1 second)

// Rate limiter for RPC calls with improved backoff strategy
struct RateLimiter {
    call_count: AtomicU64,
    last_reset: AtomicU64,
    limit_per_second: Arc<AtomicU64>,
    last_backoff: AtomicU64, // Track the last backoff time
}

impl RateLimiter {
    fn new(limit_per_second: u64) -> Self {
        Self {
            call_count: AtomicU64::new(0),
            last_reset: AtomicU64::new(
                SystemTime::now()
                    .duration_since(UNIX_EPOCH)
                    .unwrap()
                    .as_secs(),
            ),
            limit_per_second: Arc::new(AtomicU64::new(limit_per_second)),
            last_backoff: AtomicU64::new(0),
        }
    }

    // Improved check_and_increment with proper backoff
    async fn check_and_increment(&self) -> bool {
        let now = SystemTime::now()
            .duration_since(UNIX_EPOCH)
            .unwrap()
            .as_secs();
        let last_reset = self.last_reset.load(Ordering::Relaxed);

        if now > last_reset {
            // Reset counter if we're in a new second
            self.call_count.store(0, Ordering::Relaxed);
            self.last_reset.store(now, Ordering::Relaxed);
        }

        let count = self.call_count.fetch_add(1, Ordering::Relaxed);
        let limit = self.limit_per_second.load(Ordering::Relaxed);

        if count < limit {
            return true;
        } else {
            // We've hit the rate limit, implement backoff
            // Calculate backoff duration with exponential increase based on consecutive failures
            let consecutive_backoffs = now - self.last_backoff.load(Ordering::Relaxed);
            let backoff_ms = if consecutive_backoffs <= 1 {
                INITIAL_BACKOFF_MS
            } else {
                std::cmp::min(INITIAL_BACKOFF_MS * consecutive_backoffs, MAX_BACKOFF_MS)
            };
            
            // Update last backoff time
            self.last_backoff.store(now, Ordering::Relaxed);
            
            // Log the backoff
            debug!("Rate limit reached, backing off for {}ms", backoff_ms);
            
            // Sleep for the calculated backoff period
            sleep(Duration::from_millis(backoff_ms)).await;
            
            // Return false to indicate the call wasn't allowed
            false
        }
    }

    // Wait until we can make a call, with retries
    async fn acquire(&self) -> Result<(), PyErr> {
        for attempt in 0..10 { // Try up to 10 times
            if self.check_and_increment().await {
                return Ok(());
            }
            
            // If we couldn't get permission, wait and retry
            let backoff_ms = INITIAL_BACKOFF_MS * (1 << attempt); // Exponential backoff
            debug!("Rate limit wait - attempt {}, sleeping for {}ms", attempt + 1, backoff_ms);
            sleep(Duration::from_millis(backoff_ms)).await;
        }
        
        // If we couldn't get permission after all attempts, return an error
        Err(PyValueError::new_err("Failed to acquire rate limit permission after multiple attempts"))
    }

    fn set_limit(&self, limit: u64) {
        self.limit_per_second.store(limit, Ordering::Relaxed);
    }
}

// Define TokenPairSetting
#[pyclass]
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct TokenPairSetting {
    #[pyo3(get, set)]
    pub token_mint: String,
    #[pyo3(get, set)]
    pub amm_id: String,
    #[pyo3(get, set)]
    pub amm_authority: String,
    #[pyo3(get, set)]
    pub amm_open_orders: String,
    #[pyo3(get, set)]
    pub amm_target: String,
    #[pyo3(get, set)]
    pub pool_token_account: String,
    #[pyo3(get, set)]
    pub pool_pc_account: String,
    #[pyo3(get, set)]
    pub min_liquidity_pct: f64,
    #[pyo3(get, set)]
    pub min_exit_liquidity_sol: f64,
    #[pyo3(get, set)]
    pub auth_revoked: bool,
    #[pyo3(get, set)]
    pub buyer_seller_ratio: f64,
    #[pyo3(get, set)]
    pub min_volume_5m: f64,
    #[pyo3(get, set)]
    pub enabled: bool,
}

#[pymethods]
impl TokenPairSetting {
    #[new]
    fn new(
        token_mint: String,
        amm_id: String,
        amm_authority: String,
        amm_open_orders: String,
        amm_target: String,
        pool_token_account: String,
        pool_pc_account: String,
        min_liquidity_pct: Option<f64>,
        min_exit_liquidity_sol: Option<f64>,
        auth_revoked: Option<bool>,
        buyer_seller_ratio: Option<f64>,
        min_volume_5m: Option<f64>,
        enabled: Option<bool>,
    ) -> Self {
        Self {
            token_mint,
            amm_id,
            amm_authority,
            amm_open_orders,
            amm_target,
            pool_token_account,
            pool_pc_account,
            min_liquidity_pct: min_liquidity_pct.unwrap_or(95.0),
            min_exit_liquidity_sol: min_exit_liquidity_sol.unwrap_or(5.0),
            auth_revoked: auth_revoked.unwrap_or(true),
            buyer_seller_ratio: buyer_seller_ratio.unwrap_or(1.0),
            min_volume_5m: min_volume_5m.unwrap_or(10.0),
            enabled: enabled.unwrap_or(true),
        }
    }
}

// Dynamic configuration structure
#[pyclass]
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct TradingConfig {
    #[pyo3(get, set)]
    pub rpc_url: String,
    #[pyo3(get, set)]
    pub ws_url: String,
    #[pyo3(get, set)]
    pub api_key: String,

    #[pyo3(get, set)]
    pub sol_mint: String,
    #[pyo3(get, set)]
    pub rpc_rate_limit: u64,

    #[pyo3(get, set)]
    pub token_mint: Option<String>,
    #[pyo3(get, set)]
    pub amm_program: Option<String>,

    #[pyo3(get, set)]
    pub compute_limit: u32,
    #[pyo3(get, set)]
    pub priority_fee: u64,
    #[pyo3(get, set)]
    pub skip_preflight: bool,
    #[pyo3(get, set)]
    pub max_retries: u8,

    #[pyo3(get, set)]
    pub front_run_amount: f64,
    #[pyo3(get, set)]
    pub min_victim_size: f64,
    #[pyo3(get, set)]
    pub max_victim_size: f64,
    #[pyo3(get, set)]
    pub min_profit: f64,
    #[pyo3(get, set)]
    pub slippage_bps: u16,

    #[pyo3(get, set)]
    pub min_sol_balance: f64,
    #[pyo3(get, set)]
    pub min_wsol_balance: f64,

    #[pyo3(get, set)]
    pub amm_id: Option<String>,
    #[pyo3(get, set)]
    pub market_amm_authority: Option<String>,
    #[pyo3(get, set)]
    pub market_amm_open_orders: Option<String>,
    #[pyo3(get, set)]
    pub market_amm_target: Option<String>,
    #[pyo3(get, set)]
    pub market_pool_token_account: Option<String>,
    #[pyo3(get, set)]
    pub market_pool_pc_token_account: Option<String>,

    #[pyo3(get, set)]
    pub raydium_program_id: String,
    #[pyo3(get, set)]
    pub token_program_id: String,
    #[pyo3(get, set)]
    pub system_program_id: String,
    #[pyo3(get, set)]
    pub associated_token_program_id: String,

    #[pyo3(get)]
    pub token_pair_settings: HashMap<String, TokenPairSetting>,
}

#[pymethods]
impl TradingConfig {
    #[new]
    fn new(
        rpc_url: Option<String>,
        ws_url: Option<String>,
        api_key: Option<String>,
        sol_mint: Option<String>,
        rpc_rate_limit: Option<u64>,
        compute_limit: Option<u32>,
        priority_fee: Option<u64>,
        skip_preflight: Option<bool>,
        max_retries: Option<u8>,
        front_run_amount: Option<f64>,
        min_victim_size: Option<f64>,
        max_victim_size: Option<f64>,
        min_profit: Option<f64>,
        slippage_bps: Option<u16>,
        min_sol_balance: Option<f64>,
        min_wsol_balance: Option<f64>,
        raydium_program_id: Option<String>,
        token_program_id: Option<String>,
        system_program_id: Option<String>,
        associated_token_program_id: Option<String>,
        token_mint: Option<String>,
        amm_program: Option<String>,
        amm_id: Option<String>,
        market_amm_authority: Option<String>,
        market_amm_open_orders: Option<String>,
        market_amm_target: Option<String>,
        market_pool_token_account: Option<String>,
        market_pool_pc_token_account: Option<String>,
    ) -> Self {
        // Use a closure to avoid .clone()
        let get_or_default = |key| env::var(key).unwrap_or_else(|_| "".to_string());

        // Fixed SOL_MINT handling with proper fallback
        let sol_mint_value = sol_mint.unwrap_or_else(|| {
            let env_val = get_or_default("SOL_MINT");
            if env_val.is_empty() {
                "So11111111111111111111111111111111111111112".to_string()
            } else {
                env_val
            }
        });

        // Clone amm_program before it's moved
        let amm_program_clone = amm_program.clone();

        // Default to the Raydium V4 program ID if not specified
        let default_raydium_program = "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8".to_string();
        let default_token_program = "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA".to_string();
        let default_system_program = "11111111111111111111111111111111".to_string();
        let default_associated_token_program =
            "ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL".to_string();

        // Fix: Handle raydium_program_id properly
        let raydium_program_value = raydium_program_id.unwrap_or_else(|| {
            if let Some(amm) = amm_program_clone {
                amm
            } else {
                let env_val = get_or_default("RAYDIUM_PROGRAM_ID");
                if env_val.is_empty() {
                    default_raydium_program
                } else {
                    env_val
                }
            }
        });

        // Fix: Handle token_program_id properly
        let token_program_value = token_program_id.unwrap_or_else(|| {
            let env_val = get_or_default("TOKEN_PROGRAM_ID");
            if env_val.is_empty() {
                default_token_program
            } else {
                env_val
            }
        });

        // Fix: Handle system_program_id properly
        let system_program_value = system_program_id.unwrap_or_else(|| {
            let env_val = get_or_default("SYSTEM_PROGRAM_ID");
            if env_val.is_empty() {
                default_system_program
            } else {
                env_val
            }
        });

        // Fix: Handle associated_token_program_id properly
        let associated_token_program_value = associated_token_program_id.unwrap_or_else(|| {
            let env_val = get_or_default("ASSOCIATED_TOKEN_PROGRAM_ID");
            if env_val.is_empty() {
                default_associated_token_program
            } else {
                env_val
            }
        });

        Self {
            rpc_url: rpc_url.unwrap_or_else(|| {
                env::var("RPC_URL")
                    .unwrap_or_else(|_| "https://api.mainnet-beta.solana.com".to_string())
            }),
            ws_url: ws_url.unwrap_or_else(|| {
                env::var("WS_URL")
                    .unwrap_or_else(|_| "wss://api.mainnet-beta.solana.com".to_string())
            }),
            api_key: api_key.unwrap_or_else(|| get_or_default("API_KEY")),
            sol_mint: sol_mint_value,
            rpc_rate_limit: rpc_rate_limit.unwrap_or_else(|| {
                env::var("RPC_RATE_LIMIT")
                    .map(|v| v.parse().unwrap_or(DEFAULT_RPC_RATE_LIMIT))
                    .unwrap_or(DEFAULT_RPC_RATE_LIMIT)
            }),
            // Store additional fields
            token_mint,
            amm_program,
            compute_limit: compute_limit.unwrap_or_else(|| {
                env::var("COMPUTE_LIMIT")
                    .map(|v| v.parse().unwrap_or(COMPUTE_UNITS))
                    .unwrap_or(COMPUTE_UNITS)
            }),
            priority_fee: priority_fee.unwrap_or_else(|| {
                env::var("PRIORITY_FEE")
                    .map(|v| v.parse().unwrap_or(PRIORITY_FEE))
                    .unwrap_or(PRIORITY_FEE)
            }),
            skip_preflight: skip_preflight.unwrap_or_else(|| {
                env::var("SKIP_PREFLIGHT")
                    .map(|v| v.parse().unwrap_or(true))
                    .unwrap_or(true)
            }),
            max_retries: max_retries.unwrap_or_else(|| {
                env::var("MAX_RETRIES")
                    .map(|v| v.parse().unwrap_or(MAX_RETRY_COUNT))
                    .unwrap_or(MAX_RETRY_COUNT)
            }),
            front_run_amount: front_run_amount.unwrap_or_else(|| {
                env::var("FRONT_RUN_AMOUNT")
                    .map(|v| v.parse().unwrap_or(0.35))
                    .unwrap_or(0.35)
            }),
            min_victim_size: min_victim_size.unwrap_or_else(|| {
                env::var("MIN_VICTIM_SIZE")
                    .map(|v| v.parse().unwrap_or(5.0))
                    .unwrap_or(5.0)
            }),
            max_victim_size: max_victim_size.unwrap_or_else(|| {
                env::var("MAX_VICTIM_SIZE")
                    .map(|v| v.parse().unwrap_or(320.0))
                    .unwrap_or(320.0)
            }),
            min_profit: min_profit.unwrap_or_else(|| {
                env::var("MIN_PROFIT")
                    .map(|v| v.parse().unwrap_or(0.002))
                    .unwrap_or(0.002)
            }),
            slippage_bps: slippage_bps.unwrap_or_else(|| {
                env::var("SLIPPAGE_BPS")
                    .map(|v| v.parse().unwrap_or(1000))
                    .unwrap_or(1000)
            }),
            min_sol_balance: min_sol_balance.unwrap_or_else(|| {
                env::var("MIN_SOL_BALANCE")
                    .map(|v| v.parse().unwrap_or(0.03))
                    .unwrap_or(0.03)
            }),
            min_wsol_balance: min_wsol_balance.unwrap_or_else(|| {
                env::var("MIN_WSOL_BALANCE")
                    .map(|v| v.parse().unwrap_or(0.02))
                    .unwrap_or(0.02)
            }),
            // Store additional market parameters
            amm_id,
            market_amm_authority,
            market_amm_open_orders,
            market_amm_target,
            market_pool_token_account,
            market_pool_pc_token_account,
            raydium_program_id: raydium_program_value,
            token_program_id: token_program_value,
            system_program_id: system_program_value,
            associated_token_program_id: associated_token_program_value,
            token_pair_settings: HashMap::new(),
        }
    }

    // Add a token pair setting
    fn add_token_pair_setting(&mut self, token_pair: TokenPairSetting) -> PyResult<()> {
        self.token_pair_settings
            .insert(token_pair.token_mint.clone(), token_pair);
        Ok(())
    }

    // Remove a token pair setting
    fn remove_token_pair_setting(&mut self, token_mint: &str) -> PyResult<bool> {
        Ok(self.token_pair_settings.remove(token_mint).is_some())
    }

    // Get a token pair setting
    fn get_token_pair_setting(&self, token_mint: &str) -> PyResult<Option<TokenPairSetting>> {
        Ok(self.token_pair_settings.get(token_mint).cloned())
    }

    // Get all active token mints
    fn get_active_token_mints(&self) -> PyResult<Vec<String>> {
        Ok(self
            .token_pair_settings
            .iter()
            .filter(|(_, v)| v.enabled)
            .map(|(k, _)| k.clone())
            .collect())
    }

    // Save config to file
    fn save_to_file(&self, path: &str) -> PyResult<()> {
        let json = serde_json::to_string_pretty(&self)
            .map_err(|e| PyValueError::new_err(format!("Failed to serialize config: {}", e)))?;

        fs::write(path, json)
            .map_err(|e| PyValueError::new_err(format!("Failed to write config file: {}", e)))?;

        Ok(())
    }

    // Load config from file
    #[staticmethod]
    fn load_from_file(path: &str) -> PyResult<Self> {
        let json = fs::read_to_string(path)
            .map_err(|e| PyValueError::new_err(format!("Failed to read config file: {}", e)))?;

        let config: Self = serde_json::from_str(&json)
            .map_err(|e| PyValueError::new_err(format!("Failed to parse config file: {}", e)))?;

        Ok(config)
    }

    // Load from environment variables
    #[staticmethod]
    fn from_env() -> PyResult<Self> {
        Ok(Self::new(
            None, None, None, None, None, None, None, None, None, None, None, None, None, None,
            None, None, None, None, None, None, None, None, None, None, None, None, None, None,
        ))
    }
}

// Structure to hold swap parameters
#[pyclass]
#[derive(Clone)]
pub struct SwapParams {
    #[pyo3(get, set)]
    pub token_mint: String,
    #[pyo3(get, set)]
    pub amount_in: f64,
    #[pyo3(get, set)]
    pub is_buy: bool,
    #[pyo3(get, set)]
    pub slippage_bps: u16,
    #[pyo3(get, set)]
    pub compute_limit: u32,
    #[pyo3(get, set)]
    pub priority_fee: u64,
}

#[pymethods]
impl SwapParams {
    #[new]
    fn new(
        token_mint: String,
        amount_in: f64,
        is_buy: bool,
        slippage_bps: Option<u16>,
        compute_limit: Option<u32>,
        priority_fee: Option<u64>,
    ) -> Self {
        Self {
            token_mint,
            amount_in,
            is_buy,
            slippage_bps: slippage_bps.unwrap_or(1000),
            compute_limit: compute_limit.unwrap_or(COMPUTE_UNITS),
            priority_fee: priority_fee.unwrap_or(PRIORITY_FEE),
        }
    }
}

// Structure for transaction status tracking
#[pyclass]
#[derive(Clone)]
pub struct TransactionStatus {
    #[pyo3(get)]
    pub signature: String,
    #[pyo3(get)]
    pub success: bool,
    #[pyo3(get)]
    pub error: Option<String>,
    #[pyo3(get)]
    pub timestamp: u64,
    #[pyo3(get)]
    pub simulation_only: bool,
    #[pyo3(get)]
    pub logs: Option<Vec<String>>,
}

#[pymethods]
impl TransactionStatus {
    #[new]
    fn new(
        signature: String,
        success: bool,
        error: Option<String>,
        timestamp: Option<u64>,
        simulation_only: Option<bool>,
        logs: Option<Vec<String>>,
    ) -> Self {
        Self {
            signature,
            success,
            error,
            timestamp: timestamp.unwrap_or_else(|| {
                SystemTime::now()
                    .duration_since(UNIX_EPOCH)
                    .unwrap()
                    .as_secs()
            }),
            simulation_only: simulation_only.unwrap_or(false),
            logs,
        }
    }
}

// Cache for token metadata
type TokenMetadataCache = Arc<DashMap<String, TokenMetadata>>;

// Simple token metadata for caching
#[derive(Clone, Debug)]
struct TokenMetadata {
    decimals: u8,
    verified: bool,
    last_updated: u64,
}

// Main trading core class
#[pyclass]
pub struct RaydiumTradingCore {
    client: Arc<RpcClient>,
    keypair: Arc<Keypair>,
    config: Arc<RwLock<TradingConfig>>,
    balances: Arc<RwLock<(f64, HashMap<String, f64>)>>, // (SOL, token balances by mint)
    rate_limiter: Arc<RateLimiter>,
    pending_transaction: Arc<AtomicBool>, // Flag to indicate pending transaction
    last_trade_time: Arc<AtomicU64>,      // Store the last trade time
    public_key: String,
    token_cache: TokenMetadataCache,
    transaction_lock: Arc<TokioMutex<bool>>,
    // New semaphore to limit parallel transactions
    transaction_semaphore: Arc<TokioMutex<u8>>,
}

#[pymethods]
impl RaydiumTradingCore {
    #[new]
    fn new(
        rpc_url: Option<String>,
        private_key: Option<String>,
        keypair_path: Option<String>,
        config: Option<TradingConfig>,
    ) -> PyResult<Self> {
        let config_obj = config.unwrap_or_else(|| {
            TradingConfig::new(
                rpc_url.clone(),
                None,
                None,
                None,
                None,
                None,
                None,
                None,
                None,
                None,
                None,
                None,
                None,
                None,
                None,
                None,
                None,
                None,
                None,
                None,
                None,
                None,
                None,
                None,
                None,
                None,
                None,
                None,
            )
        });

        let client = Arc::new(RpcClient::new_with_commitment(
            rpc_url.unwrap_or_else(|| config_obj.rpc_url.clone()),
            solana_sdk::commitment_config::CommitmentConfig::confirmed(),
        ));

        // Load keypair from either a provided string or file
        let keypair = if let Some(pk) = private_key {
            let bytes = bs58::decode(pk)
                .into_vec()
                .map_err(|e| PyValueError::new_err(format!("Invalid private key: {:?}", e)))?;

            Keypair::from_bytes(&bytes)
                .map_err(|e| PyValueError::new_err(format!("Invalid keypair: {}", e)))?
        } else if let Some(path) = keypair_path {
            if !std::path::Path::new(&path).exists() {
                return Err(PyValueError::new_err(format!(
                    "Keypair file not found: {}",
                    path
                )));
            }

            let bytes = fs::read(&path).map_err(|e| {
                PyValueError::new_err(format!("Failed to read keypair file: {}", e))
            })?;

            Keypair::from_bytes(&bytes)
                .map_err(|e| PyValueError::new_err(format!("Invalid keypair: {}", e)))?
        } else {
            let private_key = env::var("SOLANA_PRIVATE_KEY").map_err(|_| {
                PyValueError::new_err("SOLANA_PRIVATE_KEY not found in environment")
            })?;

            let secret_key_bytes = bs58::decode(&private_key).into_vec().map_err(|e| {
                PyValueError::new_err(format!("Invalid private key encoding: {:?}", e))
            })?;

            Keypair::from_bytes(&secret_key_bytes)
                .map_err(|e| PyValueError::new_err(format!("Invalid keypair: {}", e)))?
        };

        // Use the proper rate limit from config
        let rate_limiter = Arc::new(RateLimiter::new(config_obj.rpc_rate_limit));
        let public_key = keypair.pubkey().to_string();
        let token_cache = Arc::new(DashMap::new());
        let transaction_lock = Arc::new(TokioMutex::new(false));
        let transaction_semaphore = Arc::new(TokioMutex::new(0));

        debug!("Initialized RaydiumTradingCore with rate limit: {}", config_obj.rpc_rate_limit);

        Ok(Self {
            client,
            keypair: Arc::new(keypair),
            config: Arc::new(RwLock::new(config_obj)),
            balances: Arc::new(RwLock::new((0.0, HashMap::new()))),
            rate_limiter,
            pending_transaction: Arc::new(AtomicBool::new(false)),
            last_trade_time: Arc::new(AtomicU64::new(0)),
            public_key,
            token_cache,
            transaction_lock,
            transaction_semaphore,
        })
    }

    // Get the public key for logging/display
    fn get_public_key(&self) -> String {
        self.public_key.clone()
    }

    // Execute custom swap with raw instruction data
    fn execute_custom_swap<'py>(
        &self,
        py: Python<'py>,
        token_mint: String,
        instruction_data: Vec<u8>,
    ) -> PyResult<&'py PyAny> {
        let client = self.client.clone();
        let keypair = self.keypair.clone();
        let config_arc = self.config.clone();
        let pending_transaction = self.pending_transaction.clone();
        let transaction_lock = self.transaction_lock.clone();
        let transaction_semaphore = self.transaction_semaphore.clone();
        let rate_limiter = self.rate_limiter.clone();

        // Debug logging for instruction data
        debug!("Custom swap instruction data: {:?}", instruction_data);

        if instruction_data.len() < 9 {
            return Err(PyValueError::new_err(format!(
                "Instruction data too short: {} bytes, need at least 9",
                instruction_data.len()
            )));
        }

        // Debug - verify instruction type and amount
        debug!("Instruction type: 0x{:02x}", instruction_data[0]);
        let amount_bytes = &instruction_data[1..9];

        // Convert amount_bytes to a u64 (little-endian)
        let mut amount_array = [0u8; 8];
        amount_array.copy_from_slice(amount_bytes);
        let amount_lamports = u64::from_le_bytes(amount_array);
        debug!("Amount (lamports): {}", amount_lamports);
        debug!("Amount (SOL): {}", amount_lamports as f64 / 1_000_000_000.0);

        // Ensure the instruction type is correct for AMM swap
        if instruction_data[0] != RAYDIUM_SWAP_INSTRUCTION {
            debug!(
                "Instruction type is not 0x{:02x}. Received: 0x{:02x}",
                RAYDIUM_SWAP_INSTRUCTION, instruction_data[0]
            );
            debug!("Creating correct instruction data");

            // Don't return an error here, instead, fix the instruction data
            let mut fixed_data = vec![RAYDIUM_SWAP_INSTRUCTION];
            fixed_data.extend_from_slice(amount_bytes);
            debug!("Fixed instruction data: {:?}", fixed_data);

            // Continue with fixed data
            let result = self.execute_custom_swap(py, token_mint, fixed_data);
            return result;
        }

        // Ensure we're not already processing a transaction
        if pending_transaction.load(Ordering::Relaxed) {
            return Err(PyValueError::new_err(
                "A transaction is already in progress",
            ));
        }

        pyo3_asyncio::tokio::future_into_py(py, async move {
            // Acquire rate limiter before any RPC operations
            if let Err(e) = rate_limiter.acquire().await {
                debug!("Rate limiter error: {}", e);
                return Err(e);
            }

            // Use a mutex for transaction processing
            let _lock = transaction_lock.lock().await;

            // Use semaphore to limit parallel transactions
            let mut count = transaction_semaphore.lock().await;
            if *count >= 2 { // Limit to 2 concurrent transactions
                return Err(PyValueError::new_err("Too many concurrent transactions"));
            }
            *count += 1;

            // Set pending transaction flag
            pending_transaction.store(true, Ordering::Relaxed);

            // Make sure we release resources regardless of outcome
            let result = execute_custom_swap_internal(
                &client, 
                &keypair, 
                &config_arc, 
                &rate_limiter, 
                &token_mint, 
                &instruction_data
            ).await;

            // Reset pending transaction flag and semaphore count
            pending_transaction.store(false, Ordering::Relaxed);
            *count -= 1;

            result
        })
    }

    // Function to execute a swap on Raydium
    fn execute_swap<'py>(&self, py: Python<'py>, params: SwapParams) -> PyResult<&'py PyAny> {
        let client = self.client.clone();
        let keypair = self.keypair.clone();
        let config_arc = self.config.clone();
        let rate_limiter = self.rate_limiter.clone();
        let pending_transaction = self.pending_transaction.clone();
        let transaction_lock = self.transaction_lock.clone();
        let transaction_semaphore = self.transaction_semaphore.clone();

        // Check if a transaction is already pending
        if pending_transaction.load(Ordering::Relaxed) {
            return Err(PyValueError::new_err(
                "A transaction is already in progress",
            ));
        }

        let params_clone = params.clone();

        pyo3_asyncio::tokio::future_into_py(py, async move {
            // Acquire rate limiter before any RPC operations
            if let Err(e) = rate_limiter.acquire().await {
                debug!("Rate limiter error: {}", e);
                return Err(e);
            }

            // Use a mutex for transaction processing
            let _lock = transaction_lock.lock().await;

            // Use semaphore to limit parallel transactions
            let mut count = transaction_semaphore.lock().await;
            if *count >= 2 { // Limit to 2 concurrent transactions
                return Err(PyValueError::new_err("Too many concurrent transactions"));
            }
            *count += 1;

            // Set pending transaction flag
            pending_transaction.store(true, Ordering::Relaxed);

            // Get config values
            let config = match config_arc.read() {
                Ok(config) => config.clone(),
                Err(_) => {
                    pending_transaction.store(false, Ordering::Relaxed);
                    *count -= 1;
                    return Err(PyValueError::new_err("Failed to read config"));
                }
            };

            // Rest of the swap code...
            let result = execute_swap_with_params(
                &client,
                &keypair,
                &rate_limiter,
                &config,
                &params_clone
            ).await;

            // Reset pending transaction flag and semaphore count
            pending_transaction.store(false, Ordering::Relaxed);
            *count -= 1;

            result
        })
    }

    // Get balances for SOL and SPL tokens
    fn get_balances<'py>(&self, py: Python<'py>) -> PyResult<&'py PyAny> {
        let client = self.client.clone();
        let keypair = self.keypair.clone();
        let config_arc = self.config.clone();
        let balances_arc = self.balances.clone();
        let rate_limiter = self.rate_limiter.clone();

        pyo3_asyncio::tokio::future_into_py(py, async move {
            // Acquire rate limiter before any RPC operations
            if let Err(e) = rate_limiter.acquire().await {
                debug!("Rate limiter error: {}", e);
                return Err(e);
            }

            let pubkey = keypair.pubkey();

            // Get SOL balance
            let sol_balance = client
                .get_balance(&pubkey)
                .await
                .map_err(|e| PyValueError::new_err(format!("Failed to get SOL balance: {}", e)))?;

            let sol_balance_f64 = sol_balance as f64 / LAMPORTS_PER_SOL as f64;

            // Get config
            let config = match config_arc.read() {
                Ok(config) => config.clone(),
                Err(_) => return Err(PyValueError::new_err("Failed to read config")),
            };

            // Get token balances
            let mut token_balances = HashMap::new();

            // Acquire rate limiter again before next RPC call
            if let Err(e) = rate_limiter.acquire().await {
                debug!("Rate limiter error: {}", e);
                return Err(e);
            }

            // Add WSOL balance
            let wsol_mint = Pubkey::from_str(&config.sol_mint).unwrap();
            let user_wsol_account = get_associated_token_address(&pubkey, &wsol_mint);

            // Check if token account exists
            let wsol_account = client.get_account(&user_wsol_account).await;

            if let Ok(account) = wsol_account {
                // Parse token account data
                if let Ok(token_account) =
                    spl_token::state::Account::unpack_from_slice(&account.data)
                {
                    let wsol_balance = token_account.amount as f64 / LAMPORTS_PER_SOL as f64;
                    token_balances.insert(config.sol_mint.clone(), wsol_balance);
                }
            } else {
                // Account doesn't exist, balance is 0
                token_balances.insert(config.sol_mint.clone(), 0.0);
            }

            // Get token balances for all active tokens - with proper rate limiting
            for token_mint in config.get_active_token_mints()? {
                if token_mint == config.sol_mint {
                    continue; // Already added WSOL above
                }

                // Acquire rate limiter before each token balance check
                if let Err(e) = rate_limiter.acquire().await {
                    debug!("Rate limiter error during token balance check: {}", e);
                    return Err(e);
                }

                let token_account = get_associated_token_address(
                    &pubkey,
                    &Pubkey::from_str(&token_mint)
                        .map_err(|e| PyValueError::new_err(format!("Invalid token mint: {}", e)))?,
                );

                // Check if token account exists
                let account = client.get_account(&token_account).await;

                if let Ok(account) = account {
                    // Parse token account data
                    if let Ok(token_account) =
                        spl_token::state::Account::unpack_from_slice(&account.data)
                    {
                        // We would need token decimals to convert properly, but using 9 as default
                        let token_balance = token_account.amount as f64 / LAMPORTS_PER_SOL as f64;
                        token_balances.insert(token_mint, token_balance);
                    }
                } else {
                    // Account doesn't exist, balance is 0
                    token_balances.insert(token_mint, 0.0);
                }
            }

            // Update cached balances
            if let Ok(mut balances) = balances_arc.write() {
                *balances = (sol_balance_f64, token_balances.clone());
            }

            Ok((sol_balance_f64, token_balances))
        })
    }

    // Create or get associated token account for a token mint
    fn ensure_ata<'py>(&self, py: Python<'py>, token_mint: String) -> PyResult<&'py PyAny> {
        let client = self.client.clone();
        let keypair = self.keypair.clone();
        let rate_limiter = self.rate_limiter.clone();

        pyo3_asyncio::tokio::future_into_py(py, async move {
            // Acquire rate limiter before any RPC operations
            if let Err(e) = rate_limiter.acquire().await {
                debug!("Rate limiter error: {}", e);
                return Err(e);
            }

            let pubkey = keypair.pubkey();

            // Parse token mint
            let token_mint_pubkey = Pubkey::from_str(&token_mint)
                .map_err(|e| PyValueError::new_err(format!("Invalid token mint: {}", e)))?;

            // Get associated token account address
            let ata = get_associated_token_address(&pubkey, &token_mint_pubkey);

            // Check if account exists
            let account = client.get_account(&ata).await;

            if account.is_err() {
                // Acquire rate limiter before next RPC operation
                if let Err(e) = rate_limiter.acquire().await {
                    debug!("Rate limiter error: {}", e);
                    return Err(e);
                }

                // Create ATA instruction
                let ix = create_associated_token_account_idempotent(
                    &pubkey,            // Payer
                    &pubkey,            // Owner
                    &token_mint_pubkey, // Mint
                    &spl_token::id(),   // Token program
                );

                // Create transaction
                let mut transaction = Transaction::new_with_payer(&[ix], Some(&pubkey));

                // Get recent blockhash
                let blockhash = client.get_latest_blockhash().await.map_err(|e| {
                    PyValueError::new_err(format!("Failed to get blockhash: {}", e))
                })?;

                // Sign transaction
                transaction.sign(&[&*keypair], blockhash);

                // Send transaction
                let signature = client
                    .send_transaction(&transaction)
                    .await
                    .map_err(|e| PyValueError::new_err(format!("Failed to create ATA: {}", e)))?;

                debug!("Created ATA for {}: {}", token_mint, signature);
            }

            Ok(ata.to_string())
        })
    }

    // Update ML signal (placeholder)
    fn update_ml_signal(&self, key: String, value: f64) -> PyResult<()> {
        // This is a placeholder for ML signal update functionality
        debug!("Updated ML signal: {} = {}", key, value);
        Ok(())
    }

    // Helper to create instruction data with correct format
    fn create_amm_instruction_data(&self, amount_sol: f64) -> PyResult<Vec<u8>> {
        // Convert SOL to lamports
        let amount_lamports = (amount_sol * LAMPORTS_PER_SOL as f64) as u64;

        // Create instruction data with correct byte ordering
        let mut instruction_data = Vec::with_capacity(9);
        instruction_data.push(RAYDIUM_SWAP_INSTRUCTION); // Fixed to 6 (constant)

        // Set amount bytes in little-endian format (least significant byte first)
        instruction_data.extend_from_slice(&amount_lamports.to_le_bytes());

        Ok(instruction_data)
    }

    // Simulate transaction before sending
    fn simulate_swap<'py>(
        &self,
        py: Python<'py>,
        token_mint: String,
        amount_sol: f64,
    ) -> PyResult<&'py PyAny> {
        let client = self.client.clone();
        let keypair = self.keypair.clone();
        let config_arc = self.config.clone();
        let rate_limiter = self.rate_limiter.clone();

        pyo3_asyncio::tokio::future_into_py(py, async move {
            // Acquire rate limiter before any RPC operations
            if let Err(e) = rate_limiter.acquire().await {
                debug!("Rate limiter error: {}", e);
                return Err(e);
            }

            // Get config
            let config = match config_arc.read() {
                Ok(config) => config.clone(),
                Err(_) => return Err(PyValueError::new_err("Failed to read config")),
            };

            // Create instruction data
            let amount_lamports = (amount_sol * LAMPORTS_PER_SOL as f64) as u64;
            let mut instruction_data = Vec::with_capacity(9);
            instruction_data.push(RAYDIUM_SWAP_INSTRUCTION); // 6 for swap
            instruction_data.extend_from_slice(&amount_lamports.to_le_bytes());

            // Get token pair settings (similar to execute_custom_swap)
            let token_pair = match config.token_pair_settings.get(&token_mint) {
                Some(settings) => settings.clone(),
                None => {
                    // Create default settings like in execute_custom_swap
                    debug!(
                        "No token pair settings found for {}. Creating dynamically for simulation.",
                        token_mint
                    );

                    TokenPairSetting {
                        token_mint: token_mint.clone(),
                        amm_id: "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8".to_string(),
                        amm_authority: "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1".to_string(),
                        amm_open_orders: "FrR9FBcDuPyMrAtUNWD3MazLyMBvJ3GjWTVLWgYtGjpG".to_string(), // Placeholder
                        amm_target: "3uahGNzFuzSAo6QpucjfyzJkGCiZbmLEShKDXRMcEjjF".to_string(), // Placeholder
                        pool_token_account: "83v8iPyZihDEjDDv9zxcm9P67MkrNfFXQocfaGmh8BSm"
                            .to_string(), // Placeholder
                        pool_pc_account: "8xKCx3SGwWR6BUr9mZFm3xwZUHFAVxeRUHPTpjYMJp6q".to_string(), // Placeholder
                        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,
                    }
                }
            };

            // Build transaction similar to execute_custom_swap
            let wallet_pubkey = keypair.pubkey();
            let token_mint_pubkey = match Pubkey::from_str(&token_mint) {
                Ok(pubkey) => pubkey,
                Err(e) => return Err(PyValueError::new_err(format!("Invalid token mint: {}", e))),
            };
            let wsol_mint = Pubkey::from_str(&config.sol_mint).unwrap();
            let user_wsol_account = get_associated_token_address(&wallet_pubkey, &wsol_mint);

            // Parse other account pubkeys
            let raydium_program = Pubkey::from_str(&config.raydium_program_id).unwrap();
            let amm_authority = Pubkey::from_str(&token_pair.amm_authority).unwrap();
            let amm_open_orders = Pubkey::from_str(&token_pair.amm_open_orders).unwrap();
            let amm_target = Pubkey::from_str(&token_pair.amm_target).unwrap();
            let pool_coin = Pubkey::from_str(&token_pair.pool_token_account).unwrap();
            let pool_pc = Pubkey::from_str(&token_pair.pool_pc_account).unwrap();
            let token_program =
                Pubkey::from_str(&config.token_program_id).unwrap_or_else(|_| spl_token::id());

            // Create swap instruction
            let swap_ix = Instruction {
                program_id: raydium_program,
                accounts: vec![
                    AccountMeta::new_readonly(raydium_program, false),
                    AccountMeta::new_readonly(amm_authority, false),
                    AccountMeta::new(amm_open_orders, false),
                    AccountMeta::new(amm_target, false),
                    AccountMeta::new(pool_coin, false),
                    AccountMeta::new(pool_pc, false),
                    AccountMeta::new_readonly(token_mint_pubkey, false),
                    AccountMeta::new(user_wsol_account, false),
                    AccountMeta::new(wallet_pubkey, true),
                    AccountMeta::new_readonly(token_program, false),
                ],
                data: instruction_data,
            };

            // Add compute budget instructions
            let compute_limit_ix =
                ComputeBudgetInstruction::set_compute_unit_limit(config.compute_limit);
            let priority_fee_ix =
                ComputeBudgetInstruction::set_compute_unit_price(config.priority_fee);

            // Create transaction
            let mut instructions = vec![compute_limit_ix, priority_fee_ix, swap_ix];

            // Acquire rate limiter before checking WSOL account
            if let Err(e) = rate_limiter.acquire().await {
                debug!("Rate limiter error: {}", e);
                return Err(e);
            }

            // Create ATA instruction if needed
            let wsol_account_exists = match client.get_account(&user_wsol_account).await {
                Ok(_) => true,
                Err(_) => false,
            };

            if !wsol_account_exists {
                let ata_ix = create_associated_token_account_idempotent(
                    &wallet_pubkey,
                    &wallet_pubkey,
                    &wsol_mint,
                    &token_program,
                );
                instructions.insert(2, ata_ix); // Insert before swap instruction
            }

            // Acquire rate limiter before checking token account
            if let Err(e) = rate_limiter.acquire().await {
                debug!("Rate limiter error: {}", e);
                return Err(e);
            }

            // Also check if token ATA needs to be created
            let user_token_account =
                get_associated_token_address(&wallet_pubkey, &token_mint_pubkey);
            let token_account_exists = match client.get_account(&user_token_account).await {
                Ok(_) => true,
                Err(_) => false,
            };

            if !token_account_exists {
                let ata_ix = create_associated_token_account_idempotent(
                    &wallet_pubkey,
                    &wallet_pubkey,
                    &token_mint_pubkey,
                    &token_program,
                );
                instructions.insert(2, ata_ix); // Insert before swap instruction
            }

            // Create transaction
            let mut transaction = Transaction::new_with_payer(&instructions, Some(&wallet_pubkey));

            // Acquire rate limiter before getting blockhash
            if let Err(e) = rate_limiter.acquire().await {
                debug!("Rate limiter error: {}", e);
                return Err(e);
            }

            // Get recent blockhash
            let blockhash = match client.get_latest_blockhash().await {
                Ok(blockhash) => blockhash,
                Err(e) => {
                    return Err(PyValueError::new_err(format!(
                        "Failed to get blockhash: {}",
                        e
                    )))
                }
            };
            transaction.sign(&[&*keypair], blockhash);

            // Acquire rate limiter before simulation
            if let Err(e) = rate_limiter.acquire().await {
                debug!("Rate limiter error: {}", e);
                return Err(e);
            }

            // Simulate transaction
            let sim_result = match client.simulate_transaction(&transaction).await {
                Ok(result) => result,
                Err(e) => return Err(PyValueError::new_err(format!("Simulation failed: {}", e))),
            };

            // Create and return status object
            let logs = if let Some(logs) = sim_result.value.logs {
                logs
            } else {
                vec![]
            };

            let status = TransactionStatus::new(
                "simulation".to_string(),
                sim_result.value.err.is_none(),
                sim_result.value.err.map(|e| format!("{:?}", e)),
                Some(
                    SystemTime::now()
                        .duration_since(UNIX_EPOCH)
                        .unwrap()
                        .as_secs(),
                ),
                Some(true),
                Some(logs),
            );

            Ok(status)
        })
    }
}

// Internal function to execute custom swap with rate limiting
async fn execute_custom_swap_internal(
    client: &RpcClient,
    keypair: &Arc<Keypair>,
    config_arc: &Arc<RwLock<TradingConfig>>,
    rate_limiter: &Arc<RateLimiter>,
    token_mint: &str,
    instruction_data: &Vec<u8>
) -> Result<TransactionStatus, PyErr> {
    // Get config values
    let config = match config_arc.read() {
        Ok(config) => config.clone(),
        Err(_) => {
            return Err(PyValueError::new_err("Failed to read config"));
        }
    };

    // Retrieve token pair settings
    let token_pair = match config.token_pair_settings.get(token_mint) {
        Some(settings) => settings.clone(),
        None => {
            // CHANGED: Instead of returning an error, dynamically create token pair settings
            debug!(
                "No token pair settings found for {}. Creating dynamically.",
                token_mint
            );

            // Create a SOL mint reference
            let sol_mint = "So11111111111111111111111111111111111111112";

            // Create a default token pair setting for this token
            // This assumes we're trading on the main Raydium V4 program
            let default_pair = TokenPairSetting {
                token_mint: token_mint.to_string(),
                amm_id: "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8".to_string(),
                amm_authority: "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1".to_string(),
                amm_open_orders: "FrR9FBcDuPyMrAtUNWD3MazLyMBvJ3GjWTVLWgYtGjpG".to_string(), // Placeholder
                amm_target: "3uahGNzFuzSAo6QpucjfyzJkGCiZbmLEShKDXRMcEjjF".to_string(), // Placeholder
                pool_token_account: "83v8iPyZihDEjDDv9zxcm9P67MkrNfFXQocfaGmh8BSm"
                    .to_string(), // Placeholder
                pool_pc_account: "8xKCx3SGwWR6BUr9mZFm3xwZUHFAVxeRUHPTpjYMJp6q".to_string(), // Placeholder
                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,
            };

            debug!(
                "CAUTION: Using placeholder pool accounts for {}. Transaction may fail.",
                token_mint
            );

            default_pair
        }
    };

    // Parse Pubkeys
    let token_mint_pubkey = match Pubkey::from_str(token_mint) {
        Ok(pubkey) => pubkey,
        Err(e) => {
            return Err(PyValueError::new_err(format!("Invalid token mint: {}", e)));
        }
    };

    // Create accounts for the swap
    let wallet_pubkey = keypair.pubkey();

    // Get user's WSOL account
    let wsol_mint = Pubkey::from_str(&config.sol_mint).unwrap();
    let user_wsol_account = get_associated_token_address(&wallet_pubkey, &wsol_mint);

    // Get user's token account
    let user_token_account =
        get_associated_token_address(&wallet_pubkey, &token_mint_pubkey);

    // Parse other account pubkeys
    let raydium_program = Pubkey::from_str(&config.raydium_program_id).unwrap();
    let amm_authority = Pubkey::from_str(&token_pair.amm_authority).unwrap();
    let amm_open_orders = Pubkey::from_str(&token_pair.amm_open_orders).unwrap();
    let amm_target = Pubkey::from_str(&token_pair.amm_target).unwrap();
    let pool_coin = Pubkey::from_str(&token_pair.pool_token_account).unwrap();
    let pool_pc = Pubkey::from_str(&token_pair.pool_pc_account).unwrap();
    let token_program =
        Pubkey::from_str(&config.token_program_id).unwrap_or_else(|_| spl_token::id());

    // Debug logging
    debug!("Preparing AMM swap with accounts:");
    debug!("Program ID: {}", raydium_program);
    debug!("AMM Authority: {}", amm_authority);
    debug!("AMM Open Orders: {}", amm_open_orders);
    debug!("AMM Target: {}", amm_target);
    debug!("Pool Token Account: {}", pool_coin);
    debug!("Pool PC Account: {}", pool_pc);
    debug!("Token Mint: {}", token_mint_pubkey);
    debug!("User WSOL Account: {}", user_wsol_account);
    debug!("User Token Account: {}", user_token_account);
    debug!("Wallet: {}", wallet_pubkey);

    // Create swap instruction - IMPORTANT: Use exact instruction data
    let swap_ix = Instruction {
        program_id: raydium_program,
        accounts: vec![
            AccountMeta::new_readonly(raydium_program, false),
            AccountMeta::new_readonly(amm_authority, false),
            AccountMeta::new(amm_open_orders, false),
            AccountMeta::new(amm_target, false),
            AccountMeta::new(pool_coin, false),
            AccountMeta::new(pool_pc, false),
            AccountMeta::new_readonly(token_mint_pubkey, false),
            AccountMeta::new(user_wsol_account, false),
            AccountMeta::new(wallet_pubkey, true),
            AccountMeta::new_readonly(token_program, false),
        ],
        data: instruction_data.clone(),
    };

    // Add compute budget instructions
    let compute_limit_ix =
        ComputeBudgetInstruction::set_compute_unit_limit(config.compute_limit);
    let priority_fee_ix =
        ComputeBudgetInstruction::set_compute_unit_price(config.priority_fee);

    // Create ATA instruction if needed
    let mut instructions = vec![compute_limit_ix, priority_fee_ix];

    // Check if we're at the rate limit before next RPC call
    if let Err(e) = rate_limiter.acquire().await {
        return Err(e);
    }

    // Check if WSOL ATA exists
    let wsol_account_exists = match client.get_account(&user_wsol_account).await {
        Ok(_) => true,
        Err(_) => false,
    };

    // Create WSOL ATA if needed
    if !wsol_account_exists {
        debug!("Creating WSOL ATA account");
        let ata_ix = create_associated_token_account_idempotent(
            &wallet_pubkey,
            &wallet_pubkey,
            &wsol_mint,
            &token_program,
        );
        instructions.push(ata_ix);
    }

    // Check if we're at the rate limit before next RPC call
    if let Err(e) = rate_limiter.acquire().await {
        return Err(e);
    }

    // IMPORTANT NEW PART: Check if token ATA exists
    let token_account_exists = match client.get_account(&user_token_account).await {
        Ok(_) => true,
        Err(_) => false,
    };

    // Create token ATA if needed - this ensures we can receive tokens
    if !token_account_exists {
        debug!("Creating token ATA account for {}", token_mint);
        let ata_ix = create_associated_token_account_idempotent(
            &wallet_pubkey,
            &wallet_pubkey,
            &token_mint_pubkey,
            &token_program,
        );
        instructions.push(ata_ix);
    }

    // Add the swap instruction
    instructions.push(swap_ix);

    // Create transaction
    let mut transaction = Transaction::new_with_payer(&instructions, Some(&wallet_pubkey));

    // Check if we're at the rate limit before getting blockhash
    if let Err(e) = rate_limiter.acquire().await {
        return Err(e);
    }

    // Get recent blockhash
    let blockhash = match client.get_latest_blockhash().await {
        Ok(blockhash) => blockhash,
        Err(e) => {
            return Err(PyValueError::new_err(format!(
                "Failed to get recent blockhash: {}",
                e
            )));
        }
    };

    // Sign transaction
    transaction.sign(&[&*keypair], blockhash);

    // Send transaction
    debug!(
        "Sending transaction with instruction data: {:?}",
        instruction_data
    );
    let send_options = RpcSendTransactionConfig {
        skip_preflight: config.skip_preflight,
        preflight_commitment: Some(CommitmentLevel::Confirmed),
        encoding: None,
        max_retries: Some(config.max_retries.into()),
        min_context_slot: None,
    };

    // Check if we're at the rate limit before sending transaction
    if let Err(e) = rate_limiter.acquire().await {
        return Err(e);
    }

    // Attempt to send transaction
    let result = client
        .send_transaction_with_config(&transaction, send_options)
        .await;

    match result {
        Ok(signature) => {
            debug!("Transaction successful: {}", signature);
            let status = TransactionStatus::new(
                signature.to_string(),
                true,
                None,
                Some(
                    SystemTime::now()
                        .duration_since(UNIX_EPOCH)
                        .unwrap()
                        .as_secs(),
                ),
                Some(false),
                None,
            );
            Ok(status)
        }
        Err(e) => {
            debug!("Transaction failed: {}", e);
            let error_msg = e.to_string();

            // Check if this is a common Raydium error and provide more info
            if error_msg.contains("0x6") || error_msg.contains("429") {
                debug!("This appears to be a rate limit or Raydium swap instruction error.");
                debug!("Waiting before retrying...");
                
                // Implement a retry with backoff for rate limit errors
                if error_msg.contains("429") {
                    sleep(Duration::from_millis(500)).await;
                    
                    // Try one more time after backing off
                    if let Err(e) = rate_limiter.acquire().await {
                        return Err(e);
                    }
                    
                    // Get a new blockhash
                    let new_blockhash = match client.get_latest_blockhash().await {
                        Ok(blockhash) => blockhash,
                        Err(e) => {
                            return Err(PyValueError::new_err(format!(
                                "Failed to get blockhash for retry: {}",
                                e
                            )));
                        }
                    };
                    
                    // Re-sign transaction with new blockhash
                    transaction.sign(&[&*keypair], new_blockhash);
                    
                    // Try one more time to send the transaction
                    match client.send_transaction_with_config(&transaction, send_options).await {
                        Ok(signature) => {
                            debug!("Retry transaction successful: {}", signature);
                            let status = TransactionStatus::new(
                                signature.to_string(),
                                true,
                                None,
                                Some(
                                    SystemTime::now()
                                        .duration_since(UNIX_EPOCH)
                                        .unwrap()
                                        .as_secs(),
                                ),
                                Some(false),
                                None,
                            );
                            return Ok(status);
                        }
                        Err(retry_e) => {
                            debug!("Retry transaction failed: {}", retry_e);
                            let status = TransactionStatus::new(
                                "failed".to_string(),
                                false,
                                Some(format!("Initial error: {}. Retry error: {}", error_msg, retry_e)),
                                Some(
                                    SystemTime::now()
                                        .duration_since(UNIX_EPOCH)
                                        .unwrap()
                                        .as_secs(),
                                ),
                                Some(false),
                                None,
                            );
                            return Ok(status);
                        }
                    }
                }
            }

            let status = TransactionStatus::new(
                "failed".to_string(),
                false,
                Some(error_msg),
                Some(
                    SystemTime::now()
                        .duration_since(UNIX_EPOCH)
                        .unwrap()
                        .as_secs(),
                ),
                Some(false),
                None,
            );
            Ok(status)
        }
    }
}

// Function to execute a swap using SwapParams
async fn execute_swap_with_params(
    client: &RpcClient,
    keypair: &Arc<Keypair>,
    rate_limiter: &Arc<RateLimiter>,
    config: &TradingConfig,
    params: &SwapParams
) -> Result<TransactionStatus, PyErr> {
    // Retrieve token pair settings
    let token_pair = match config.token_pair_settings.get(&params.token_mint) {
        Some(settings) => settings.clone(),
        None => {
            if Some(params.token_mint.clone()) == config.token_mint {
                // Handle synthetic token pair logic
                let all_present = config.amm_id.is_some()
                    && config.market_amm_authority.is_some()
                    && config.market_amm_open_orders.is_some()
                    && config.market_amm_target.is_some()
                    && config.market_pool_token_account.is_some()
                    && config.market_pool_pc_token_account.is_some();

                if all_present {
                    // Return synthetic settings
                    TokenPairSetting {
                        token_mint: params.token_mint.clone(),
                        amm_id: config.amm_id.clone().unwrap(),
                        amm_authority: config
                            .market_amm_authority
                            .as_ref()
                            .unwrap()
                            .clone(),
                        amm_open_orders: config
                            .market_amm_open_orders
                            .as_ref()
                            .unwrap()
                            .clone(),
                        amm_target: config.market_amm_target.as_ref().unwrap().clone(),
                        pool_token_account: config
                            .market_pool_token_account
                            .as_ref()
                            .unwrap()
                            .clone(),
                        pool_pc_account: config
                            .market_pool_pc_token_account
                            .as_ref()
                            .unwrap()
                            .clone(),
                        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,
                    }
                } else {
                    // Create default settings with placeholders
                    debug!(
                        "No token pair settings found for {}. Creating dynamically.",
                        params.token_mint
                    );

                    // Create a default token pair setting for this token
                    TokenPairSetting {
                        token_mint: params.token_mint.clone(),
                        amm_id: "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8".to_string(),
                        amm_authority: "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1"
                            .to_string(),
                        amm_open_orders: "FrR9FBcDuPyMrAtUNWD3MazLyMBvJ3GjWTVLWgYtGjpG"
                            .to_string(), // Placeholder
                        amm_target: "3uahGNzFuzSAo6QpucjfyzJkGCiZbmLEShKDXRMcEjjF"
                            .to_string(), // Placeholder
                        pool_token_account: "83v8iPyZihDEjDDv9zxcm9P67MkrNfFXQocfaGmh8BSm"
                            .to_string(), // Placeholder
                        pool_pc_account: "8xKCx3SGwWR6BUr9mZFm3xwZUHFAVxeRUHPTpjYMJp6q"
                            .to_string(), // Placeholder
                        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,
                    }
                }
            } else {
                // Create default settings with placeholders
                debug!(
                    "No token pair settings found for {}. Creating dynamically.",
                    params.token_mint
                );

                // Create a default token pair setting for this token
                TokenPairSetting {
                    token_mint: params.token_mint.clone(),
                    amm_id: "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8".to_string(),
                    amm_authority: "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1"
                        .to_string(),
                    amm_open_orders: "FrR9FBcDuPyMrAtUNWD3MazLyMBvJ3GjWTVLWgYtGjpG"
                        .to_string(), // Placeholder
                    amm_target: "3uahGNzFuzSAo6QpucjfyzJkGCiZbmLEShKDXRMcEjjF".to_string(), // Placeholder
                    pool_token_account: "83v8iPyZihDEjDDv9zxcm9P67MkrNfFXQocfaGmh8BSm"
                        .to_string(), // Placeholder
                    pool_pc_account: "8xKCx3SGwWR6BUr9mZFm3xwZUHFAVxeRUHPTpjYMJp6q"
                        .to_string(), // Placeholder
                    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,
                }
            }
        }
    };

    // Generate, sign, and send a transaction to perform the swap
    let _token_mint_pubkey = match Pubkey::from_str(&params.token_mint) {
        Ok(pubkey) => pubkey,
        Err(e) => {
            return Err(PyValueError::new_err(format!("Invalid token mint: {}", e)));
        }
    };

    // Create proper instruction data with correct byte ordering
    let amount_lamports = (params.amount_in * LAMPORTS_PER_SOL as f64) as u64;
    let mut instruction_data = Vec::with_capacity(9);
    instruction_data.push(RAYDIUM_SWAP_INSTRUCTION); // Fixed to 6
    instruction_data.extend_from_slice(&amount_lamports.to_le_bytes()); // Amount in little-endian

    debug!("Created swap instruction with data: {:?}", instruction_data);

    // Create and send transaction with the proper instruction data
    execute_swap_internal(client, keypair, rate_limiter, &token_pair, &instruction_data, params.is_buy).await
}

// Function to create and send a Raydium swap transaction with rate limiting
async fn execute_swap_internal(
    client: &RpcClient,
    keypair: &Arc<Keypair>,
    rate_limiter: &Arc<RateLimiter>,
    token_pair: &TokenPairSetting,
    instruction_data: &Vec<u8>,
    _is_buy: bool,
) -> Result<String, PyErr> {
    // Parse needed pubkeys
    let wallet_pubkey = keypair.pubkey();
    let token_mint = Pubkey::from_str(&token_pair.token_mint)
        .map_err(|e| PyValueError::new_err(format!("Invalid token mint: {}", e)))?;
    let wsol_mint = Pubkey::from_str("So11111111111111111111111111111111111111112").unwrap();
    let raydium_program = Pubkey::from_str("675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8").unwrap();
    let token_program = spl_token::id();

    // Get token account for this wallet
    let token_account = get_associated_token_address(&wallet_pubkey, &token_mint);
    let wsol_account = get_associated_token_address(&wallet_pubkey, &wsol_mint);

    // Create ATA instruction if needed
    let mut instructions = Vec::new();

    // Add compute budget instructions
    let compute_limit_ix = ComputeBudgetInstruction::set_compute_unit_limit(50000);
    let priority_fee_ix = ComputeBudgetInstruction::set_compute_unit_price(950000); // Increased priority
    instructions.push(compute_limit_ix);
    instructions.push(priority_fee_ix);

    // Acquire rate limiter before checking token account
    if let Err(e) = rate_limiter.acquire().await {
        return Err(e);
    }

    // Check if token account exists
    let token_account_exists = match client.get_account(&token_account).await {
        Ok(_) => true,
        Err(_) => false,
    };

    // Acquire rate limiter before checking WSOL account
    if let Err(e) = rate_limiter.acquire().await {
        return Err(e);
    }

    // Check if WSOL account exists
    let wsol_account_exists = match client.get_account(&wsol_account).await {
        Ok(_) => true,
        Err(_) => false,
    };

    // Create token account if needed
    if !token_account_exists {
        debug!("Creating token account for {}", token_mint);
        let ix = create_associated_token_account_idempotent(
            &wallet_pubkey,
            &wallet_pubkey,
            &token_mint,
            &token_program,
        );
        instructions.push(ix);
    }

    // Create WSOL account if needed
    if !wsol_account_exists {
        debug!("Creating WSOL account");
        let ix = create_associated_token_account_idempotent(
            &wallet_pubkey,
            &wallet_pubkey,
            &wsol_mint,
            &token_program,
        );
        instructions.push(ix);
    }

    // Parse AMM account pubkeys
    let amm_authority = Pubkey::from_str(&token_pair.amm_authority)
        .map_err(|e| PyValueError::new_err(format!("Invalid AMM authority: {}", e)))?;
    let amm_open_orders = Pubkey::from_str(&token_pair.amm_open_orders)
        .map_err(|e| PyValueError::new_err(format!("Invalid AMM open orders: {}", e)))?;
    let amm_target = Pubkey::from_str(&token_pair.amm_target)
        .map_err(|e| PyValueError::new_err(format!("Invalid AMM target: {}", e)))?;
    let pool_token_account = Pubkey::from_str(&token_pair.pool_token_account)
        .map_err(|e| PyValueError::new_err(format!("Invalid pool token account: {}", e)))?;
    let pool_pc_account = Pubkey::from_str(&token_pair.pool_pc_account)
        .map_err(|e| PyValueError::new_err(format!("Invalid pool PC account: {}", e)))?;

    // Debug log the instruction data
    debug!("Swap instruction data: {:?}", instruction_data);

    // Create swap instruction
    let swap_accounts = vec![
        AccountMeta::new_readonly(raydium_program, false),
        AccountMeta::new_readonly(amm_authority, false),
        AccountMeta::new(amm_open_orders, false),
        AccountMeta::new(amm_target, false),
        AccountMeta::new(pool_token_account, false),
        AccountMeta::new(pool_pc_account, false),
        AccountMeta::new(token_mint, false),
        AccountMeta::new(wsol_account, false),
        AccountMeta::new(wallet_pubkey, true),
        AccountMeta::new_readonly(token_program, false),
    ];

    let swap_ix = Instruction {
        program_id: raydium_program,
        accounts: swap_accounts,
        data: instruction_data.clone(),
    };

    instructions.push(swap_ix);

    // Create transaction
    let mut transaction = Transaction::new_with_payer(&instructions, Some(&wallet_pubkey));

    // Acquire rate limiter before getting blockhash
    if let Err(e) = rate_limiter.acquire().await {
        return Err(e);
    }

    // Get recent blockhash
    let blockhash = client
        .get_latest_blockhash()
        .await
        .map_err(|e| PyValueError::new_err(format!("Failed to get recent blockhash: {}", e)))?;

    // Sign transaction
    transaction.sign(&[&*keypair], blockhash);

    // Send transaction with options
    let send_options = RpcSendTransactionConfig {
        skip_preflight: true,
        preflight_commitment: Some(CommitmentLevel::Confirmed),
        encoding: None,
        max_retries: Some(3),
        min_context_slot: None,
    };

    // Acquire rate limiter before sending transaction
    if let Err(e) = rate_limiter.acquire().await {
        return Err(e);
    }

    let signature = client
        .send_transaction_with_config(&transaction, send_options)
        .await
        .map_err(|e| PyValueError::new_err(format!("Failed to send transaction: {}", e)))?;

    Ok(signature.to_string())
}

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

    m.add_class::<TradingConfig>()?;
    m.add_class::<TokenPairSetting>()?;
    m.add_class::<SwapParams>()?;
    m.add_class::<TransactionStatus>()?;
    m.add_class::<RaydiumTradingCore>()?;

    Ok(())
} whats the difference