// Put #[pyclass] on struct definition only, not on the impl block
#[pyclass]
pub struct TradingCore {
    client: Arc<RpcClient>,
    keypair: Arc<Keypair>,
    ata_cache: Arc<RwLock<HashMap<String, Pubkey>>>,
    last_trade_time: Arc<RwLock<SystemTime>>,
    active_trade: Arc<RwLock<bool>>,
}

// Use #[pymethods] for the implementation block containing Python-exposed methods
#[pymethods]
impl TradingCore {
    #[new]
    pub fn new(rpc_url: String) -> PyResult<Self> {
        let keypair = Self::load_keypair()?;
        let client = RpcClient::new_with_commitment(rpc_url, CommitmentConfig::confirmed());

        Ok(Self {
            client: Arc::new(client),
            keypair: Arc::new(keypair),
            ata_cache: Arc::new(RwLock::new(HashMap::new())),
            last_trade_time: Arc::new(RwLock::new(SystemTime::now())),
            active_trade: Arc::new(RwLock::new(false)),
        })
    }

    // Rest of the methods...
}use base58::FromBase58;
use log::info;
use pyo3::{exceptions::PyValueError, prelude::*};
use pyo3_asyncio::tokio::future_into_py;
use solana_client::{nonblocking::rpc_client::RpcClient, rpc_config::RpcSendTransactionConfig};
use solana_sdk::{
    commitment_config::{CommitmentConfig, CommitmentLevel},
    compute_budget::ComputeBudgetInstruction,
    instruction::{AccountMeta, Instruction},
    message::Message,
    pubkey::Pubkey,
    signature::{Keypair, Signer},
    transaction::Transaction,
};
use spl_associated_token_account::{
    get_associated_token_address, instruction::create_associated_token_account_idempotent,
};
use spl_token;
use std::{
    collections::HashMap,
    env,
    str::FromStr,
    sync::Arc,
    time::{Duration, SystemTime},
};
use tokio::sync::RwLock;

// Constants
const COMPUTE_UNITS: u32 = 50_000;
const PRIORITY_FEE: u64 = 750_000;
const WSOL_MINT: &str = "So11111111111111111111111111111111111111112";
const LAMPORTS_PER_SOL: u64 = 1_000_000_000;
const MIN_TRADE_INTERVAL: Duration = Duration::from_micros(50);
const MAX_RETRIES: usize = 4;
const TOKEN_2022_PROGRAM_ID: &str = "TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb";
const ASSOCIATED_TOKEN_PROGRAM_ID: &str = "ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL";

#[pyclass]
#[derive(Clone)]
pub struct TradeParams {
    #[pyo3(get, set)]
    pub accounts: Vec<String>,
    #[pyo3(get, set)]
    pub amount_in: Option<u64>,
    #[pyo3(get, set)]
    pub is_buy: bool,
    #[pyo3(get, set)]
    pub token_a_mint: String,
    #[pyo3(get, set)]
    pub token_b_mint: String,
    #[pyo3(get, set)]
    pub victim_data: Option<Vec<u8>>,
    #[pyo3(get, set)]
    pub sell_all: bool,
    #[pyo3(get, set)]
    pub blockhash: Option<String>,
}

#[derive(Clone, Default)]
struct MarketAccounts {
    amm_authority: Pubkey,
    amm_open_orders: Pubkey,
    amm_target: Pubkey,
    market: Pubkey,
    pool_token_account: Pubkey,
    serum_market: Pubkey,
    serum_bids: Pubkey,
    serum_asks: Pubkey,
    event_queue: Pubkey,
    base_vault: Pubkey,
    quote_vault: Pubkey,
    vault_signer: Pubkey,
}

#[pyclass]
#[derive(Clone)]
pub struct TradingCore {
    client: Arc<RpcClient>,
    keypair: Arc<Keypair>,
    ata_cache: Arc<RwLock<HashMap<String, Pubkey>>>,
    last_trade_time: Arc<RwLock<SystemTime>>,
    active_trade: Arc<RwLock<bool>>,
}

impl TradingCore {
    fn load_keypair() -> PyResult<Keypair> {
        // Try Base58 private key first
        if let Ok(private_key) = env::var("SOLANA_PRIVATE_KEY") {
            if let Ok(secret_key_bytes) = private_key.from_base58() {
                if let Ok(keypair) = Keypair::from_bytes(&secret_key_bytes) {
                    info!("✅ Loaded keypair from SOLANA_PRIVATE_KEY");
                    return Ok(keypair);
                }
            }
        }

        // Fallback to JSON file
        if let Ok(keypair_path) = env::var("KEYPAIR_PATH") {
            if let Ok(file_content) = std::fs::read_to_string(keypair_path) {
                if let Ok(bytes) = serde_json::from_str::<Vec<u8>>(&file_content) {
                    if let Ok(keypair) = Keypair::from_bytes(&bytes) {
                        info!("✅ Loaded keypair from JSON file");
                        return Ok(keypair);
                    }
                }
            }
        }

        Err(PyValueError::new_err("Failed to load keypair"))
    }

    async fn check_token_program(&self, mint: &Pubkey) -> PyResult<Pubkey> {
        // Get account info to determine the program ID
        let account_info =
            self.client.get_account(mint).await.map_err(|e| {
                PyValueError::new_err(format!("Failed to get token mint info: {}", e))
            })?;

        // Return the program ID (owner of the mint account)
        Ok(account_info.owner)
    }

    // Custom function to create Token-2022 ATA
    async fn create_token2022_ata(&self, mint: &Pubkey) -> PyResult<()> {
        let token_2022_pubkey = Pubkey::from_str(TOKEN_2022_PROGRAM_ID)
            .map_err(|e| PyValueError::new_err(format!("Invalid Token-2022 ID: {}", e)))?;

        let ata_program_pubkey = Pubkey::from_str(ASSOCIATED_TOKEN_PROGRAM_ID)
            .map_err(|e| PyValueError::new_err(format!("Invalid ATA program ID: {}", e)))?;

        let system_program = solana_sdk::system_program::ID;
        let rent_sysvar = solana_sdk::sysvar::rent::ID;

        // Derive the PDA manually - fix for temporary value issue
        let wallet_pubkey = self.keypair.pubkey();
        let wallet_bytes = wallet_pubkey.as_ref();
        let mint_bytes = mint.as_ref();
        let token_prog_bytes = token_2022_pubkey.as_ref();

        let seeds = &[wallet_bytes, token_prog_bytes, mint_bytes];

        let (ata, _) = Pubkey::find_program_address(seeds, &ata_program_pubkey);

        // Create instruction for creating a Token-2022 ATA
        let ix = Instruction {
            program_id: ata_program_pubkey,
            accounts: vec![
                AccountMeta::new(self.keypair.pubkey(), true), // Funding account
                AccountMeta::new(ata, false),                  // ATA
                AccountMeta::new_readonly(self.keypair.pubkey(), false), // Wallet
                AccountMeta::new_readonly(*mint, false),       // Mint
                AccountMeta::new_readonly(system_program, false), // System Program
                AccountMeta::new_readonly(token_2022_pubkey, false), // Token 2022 Program
                AccountMeta::new_readonly(rent_sysvar, false), // Rent
            ],
            data: vec![1], // Instruction index for create_idempotent
        };

        let blockhash = self
            .client
            .get_latest_blockhash()
            .await
            .map_err(|e| PyValueError::new_err(format!("Blockhash error: {}", e)))?;

        let mut tx = Transaction::new_with_payer(&[ix], Some(&self.keypair.pubkey()));
        tx.sign(&[&*self.keypair], blockhash);

        let config = RpcSendTransactionConfig {
            skip_preflight: true,
            preflight_commitment: Some(CommitmentLevel::Confirmed),
            ..Default::default()
        };

        self.client
            .send_transaction_with_config(&tx, config)
            .await
            .map_err(|e| PyValueError::new_err(format!("Token-2022 ATA creation failed: {}", e)))?;

        Ok(())
    }

    async fn ensure_ata_exists(
        &self,
        mint: &Pubkey,
        program_id_str: Option<String>,
    ) -> PyResult<String> {
        let is_token_2022 = if let Some(program_str) = &program_id_str {
            program_str == TOKEN_2022_PROGRAM_ID
        } else {
            // Try to auto-detect the token program
            match self.check_token_program(mint).await {
                Ok(detected_program) => {
                    // Check if this is Token-2022
                    let token_2022_pubkey =
                        Pubkey::from_str(TOKEN_2022_PROGRAM_ID).map_err(|e| {
                            PyValueError::new_err(format!("Invalid Token-2022 ID: {}", e))
                        })?;

                    detected_program == token_2022_pubkey
                }
                Err(_) => false,
            }
        };

        // Get the ATA address
        let ata = get_associated_token_address(&self.keypair.pubkey(), mint);
        let ata_str = ata.to_string();

        // Fast cache check
        if let Some(cached_ata) = self.ata_cache.read().await.get(&ata_str) {
            return Ok(cached_ata.to_string());
        }

        match self.client.get_account(&ata).await {
            Ok(_) => {
                info!("✅ ATA exists: {}", ata);
            }
            Err(_) => {
                info!("🔄 Creating ATA for mint: {}", mint);

                if is_token_2022 {
                    info!("Using Token-2022 program for ATA creation");
                    self.create_token2022_ata(mint).await?;
                } else {
                    // Standard token program
                    let ix = create_associated_token_account_idempotent(
                        &self.keypair.pubkey(),
                        &self.keypair.pubkey(),
                        mint,
                        &spl_token::ID,
                    );

                    let blockhash =
                        self.client.get_latest_blockhash().await.map_err(|e| {
                            PyValueError::new_err(format!("Blockhash error: {}", e))
                        })?;

                    let mut tx = Transaction::new_with_payer(&[ix], Some(&self.keypair.pubkey()));
                    tx.sign(&[&*self.keypair], blockhash);

                    let config = RpcSendTransactionConfig {
                        skip_preflight: true,
                        preflight_commitment: Some(CommitmentLevel::Confirmed),
                        ..Default::default()
                    };

                    self.client
                        .send_transaction_with_config(&tx, config)
                        .await
                        .map_err(|e| {
                            PyValueError::new_err(format!("ATA creation failed: {}", e))
                        })?;
                }
            }
        }

        self.ata_cache.write().await.insert(ata_str.clone(), ata);
        Ok(ata_str)
    }

    fn decode_ray_log(&self, data: &[u8]) -> PyResult<(String, String, u64)> {
        if data.len() < 9 {
            return Err(PyValueError::new_err("Data too short"));
        }

        let instruction_type = data[0];
        // Accept 0x03 and 0x09 as valid instruction types (both are buys based on your testing)
        if instruction_type != 0x03 && instruction_type != 0x09 {
            return Err(PyValueError::new_err("Invalid instruction type"));
        }

        let amount = u64::from_le_bytes(data[1..9].try_into().unwrap());

        // Extract token mints using try_from instead of new
        let token_a_mint = if data.len() >= 72 {
            Pubkey::try_from(&data[40..72])
                .map_err(|e| PyValueError::new_err(format!("Invalid token A mint data: {}", e)))?
                .to_string()
        } else {
            return Err(PyValueError::new_err("Data too short for token A mint"));
        };

        let token_b_mint = if data.len() >= 104 {
            Pubkey::try_from(&data[72..104])
                .map_err(|e| PyValueError::new_err(format!("Invalid token B mint data: {}", e)))?
                .to_string()
        } else {
            WSOL_MINT.to_string()
        };

        Ok((token_a_mint, token_b_mint, amount))
    }

    fn create_swap_instruction(
        &self,
        params: &TradeParams,
        source_ata: Pubkey,
        dest_ata: Pubkey,
    ) -> PyResult<Instruction> {
        // Validate accounts
        if params.accounts.len() < 15 {
            return Err(PyValueError::new_err("Insufficient accounts provided"));
        }

        let accounts: Vec<Pubkey> = params
            .accounts
            .iter()
            .enumerate()
            .map(|(i, acc)| {
                Pubkey::from_str(acc).map_err(|e| {
                    PyValueError::new_err(format!("Invalid account at position {}: {}", i, e))
                })
            })
            .collect::<Result<Vec<_>, _>>()?;

        // Use 0x03 for all operations - direction is determined by source/dest accounts
        let mut data = vec![0x03];

        match (params.amount_in, &params.victim_data, params.sell_all) {
            // If sell_all is true, use a minimal amount for the instruction data
            (Some(amount), None, true) if !params.is_buy => {
                data.extend_from_slice(&amount.to_le_bytes()); // Amount in (minimal value)
                data.extend_from_slice(&0u64.to_le_bytes()); // Minimum amount out
            }
            // Normal case with amount_in
            (Some(amount), None, _) => {
                data.extend_from_slice(&amount.to_le_bytes()); // Amount in
                data.extend_from_slice(&0u64.to_le_bytes()); // Minimum amount out
            }
            // Use victim data if provided
            (_, Some(victim_data), _) => {
                data.extend_from_slice(victim_data);
            }
            _ => {
                return Err(PyValueError::new_err(
                    "Either amount_in or victim_data required",
                ));
            }
        }

        // Construct the accounts for the instruction based on the Raydium ABI
        let meta_accounts = vec![
            AccountMeta::new(accounts[0], false),          // Raydium program
            AccountMeta::new(accounts[1], false),          // AMM ID
            AccountMeta::new_readonly(accounts[2], false), // AMM authority
            AccountMeta::new(accounts[3], false),          // AMM open orders
            AccountMeta::new(accounts[4], false),          // AMM target orders
            AccountMeta::new(accounts[5], false),          // Pool coin token account
            AccountMeta::new(accounts[6], false),          // Pool pc token account
            AccountMeta::new_readonly(accounts[7], false), // Serum program
            AccountMeta::new(accounts[8], false),          // Serum market
            AccountMeta::new(accounts[9], false),          // Serum bids
            AccountMeta::new(accounts[10], false),         // Serum asks
            AccountMeta::new(accounts[11], false),         // Serum event queue
            AccountMeta::new(accounts[12], false),         // Serum coin vault
            AccountMeta::new(accounts[13], false),         // Serum pc vault
            AccountMeta::new_readonly(accounts[14], false), // Serum vault signer
            AccountMeta::new(source_ata, false),           // User source token account
            AccountMeta::new(dest_ata, false),             // User destination token account
            AccountMeta::new(self.keypair.pubkey(), true), // User owner
        ];

        Ok(Instruction {
            program_id: accounts[0],
            accounts: meta_accounts,
            data,
        })
    }
}

#[pyclass]
impl TradingCore {
    #[new]
    pub fn new(rpc_url: String) -> PyResult<Self> {
        let keypair = Self::load_keypair()?;
        let client = RpcClient::new_with_commitment(rpc_url, CommitmentConfig::confirmed());

        Ok(Self {
            client: Arc::new(client),
            keypair: Arc::new(keypair),
            ata_cache: Arc::new(RwLock::new(HashMap::new())),
            last_trade_time: Arc::new(RwLock::new(SystemTime::now())),
            active_trade: Arc::new(RwLock::new(false)),
        })
    }

    #[getter]
    pub fn wallet_address(&self) -> String {
        self.keypair.pubkey().to_string()
    }

    #[getter]
    pub fn public_key(&self) -> Vec<u8> {
        self.keypair.pubkey().to_bytes().to_vec()
    }

    fn check_trade_rate_limit(&self) -> PyResult<()> {
        let current_time = SystemTime::now();
        let last_time = *self.last_trade_time.blocking_read();

        if let Ok(elapsed) = current_time.duration_since(last_time) {
            if elapsed < MIN_TRADE_INTERVAL {
                return Err(PyValueError::new_err(format!(
                    "Trading too fast, need to wait {} more microseconds",
                    MIN_TRADE_INTERVAL.as_micros() - elapsed.as_micros()
                )));
            }
        }

        Ok(())
    }

    #[pyo3(text_signature = "(self, hex_data)")]
    fn process_raydium_log(&self, hex_data: &str) -> PyResult<Py<PyAny>> {
        let gil = Python::acquire_gil();
        let py = gil.python();

        // Convert hex to bytes
        let data = hex::decode(hex_data)
            .map_err(|e| PyValueError::new_err(format!("Invalid hex data: {}", e)))?;

        // Decode the log
        let (token_a, token_b, amount) = self.decode_ray_log(&data)?;

        // Create Python dict for result
        let result = PyDict::new(py);
        result.set_item("token_a", token_a)?;
        result.set_item("token_b", token_b)?;
        result.set_item("amount", amount)?;
        result.set_item("is_buy", data[0] == 0x09 || data[0] == 0x03)?;

        Ok(result.into())
    }

    #[pyo3(text_signature = "(self, token_mint, token_program=None)")]
    fn get_token_ata(
        &self,
        token_mint: &str,
        token_program: Option<String>,
    ) -> PyResult<Py<PyAny>> {
        let mint = Pubkey::from_str(token_mint)
            .map_err(|e| PyValueError::new_err(format!("Invalid token mint: {}", e)))?;

        let self_clone = self.clone();

        future_into_py(async move {
            let ata = self_clone.ensure_ata_exists(&mint, token_program).await?;
            Python::with_gil(|py| Ok(ata.into_py(py)))
        })
    }

    #[pyo3(text_signature = "(self, params)")]
    fn execute_trade(&self, params: &TradeParams) -> PyResult<Py<PyAny>> {
        // Validate parameters
        if params.token_a_mint.is_empty() || params.token_b_mint.is_empty() {
            return Err(PyValueError::new_err("Token mints cannot be empty"));
        }

        let self_clone = self.clone();
        let params_clone = params.clone();

        // Execute the trade asynchronously
        future_into_py(async move {
            // Check trade rate limit
            self_clone.check_trade_rate_limit()?;

            // Check if there's already an active trade
            if *self_clone.active_trade.read().await {
                return Err(PyValueError::new_err("Trade already in progress"));
            }

            // Set active trade flag
            *self_clone.active_trade.write().await = true;
            // Update last trade time
            *self_clone.last_trade_time.write().await = SystemTime::now();

            // Reset active trade flag when done
            let _guard = scopeguard::guard((), |_| {
                tokio::spawn(async move {
                    *self_clone.active_trade.write().await = false;
                });
            });

            let token_a = Pubkey::from_str(&params_clone.token_a_mint)
                .map_err(|e| PyValueError::new_err(format!("Invalid token A mint: {}", e)))?;

            let token_b = Pubkey::from_str(&params_clone.token_b_mint)
                .map_err(|e| PyValueError::new_err(format!("Invalid token B mint: {}", e)))?;

            // Get source and destination ATAs
            let (source_ata_str, dest_ata_str) = if params_clone.is_buy {
                (
                    self_clone.ensure_ata_exists(&token_b, None).await?,
                    self_clone.ensure_ata_exists(&token_a, None).await?,
                )
            } else {
                (
                    self_clone.ensure_ata_exists(&token_a, None).await?,
                    self_clone.ensure_ata_exists(&token_b, None).await?,
                )
            };

            // Convert to Pubkeys
            let source_ata = Pubkey::from_str(&source_ata_str)
                .map_err(|e| PyValueError::new_err(format!("Invalid source ATA: {}", e)))?;

            let dest_ata = Pubkey::from_str(&dest_ata_str)
                .map_err(|e| PyValueError::new_err(format!("Invalid destination ATA: {}", e)))?;

            // Create swap instruction
            let swap_ix =
                self_clone.create_swap_instruction(&params_clone, source_ata, dest_ata)?;

            // Create compute budget instruction to increase compute units
            let compute_ix = ComputeBudgetInstruction::set_compute_unit_limit(COMPUTE_UNITS);

            // Priority fee instruction
            let priority_ix = ComputeBudgetInstruction::set_compute_unit_price(PRIORITY_FEE);

            // Get blockhash
            let blockhash = if let Some(bh) = &params_clone.blockhash {
                bh.clone()
            } else {
                self_clone
                    .client
                    .get_latest_blockhash()
                    .await
                    .map_err(|e| PyValueError::new_err(format!("Failed to get blockhash: {}", e)))?
                    .to_string()
            };

            // Create transaction
            let message = Message::new(
                &[compute_ix, priority_ix, swap_ix],
                Some(&self_clone.keypair.pubkey()),
            );

            let blockhash_bytes = solana_sdk::hash::Hash::from_str(&blockhash)
                .map_err(|e| PyValueError::new_err(format!("Invalid blockhash: {}", e)))?;

            let mut tx = Transaction::new_unsigned(message);
            tx.sign(&[&*self_clone.keypair], blockhash_bytes);

            // Send transaction
            let config = RpcSendTransactionConfig {
                skip_preflight: true,
                preflight_commitment: Some(CommitmentLevel::Confirmed),
                ..Default::default()
            };

            let mut retry_counter = 0;
            let sig_str = loop {
                match self_clone
                    .client
                    .send_transaction_with_config(&tx, config)
                    .await
                {
                    Ok(sig) => break sig.to_string(),
                    Err(e) => {
                        retry_counter += 1;
                        if retry_counter >= MAX_RETRIES {
                            return Err(PyValueError::new_err(format!(
                                "Transaction failed after {} retries: {}",
                                MAX_RETRIES, e
                            )));
                        }
                        tokio::time::sleep(Duration::from_millis(250)).await;
                    }
                }
            };

            // Return signature
            Python::with_gil(|py| Ok(sig_str.into_py(py)))
        })
    }
}

#[pymodule]
fn libcore(_py: Python, m: &PyModule) -> PyResult<()> {
    m.add_class::<TradingCore>()?;
    m.add_class::<TradeParams>()?;
    Ok(())
}
 add it to this script and write the full script please thank you