please write script without spacing and bracket issues use std::collections::HashMap;
use std::sync::{Arc, Mutex};
use std::time::{Duration, Instant, SystemTime, UNIX_EPOCH};
use std::str::FromStr;

use anyhow::{anyhow, Result};
use config::Config;
use log::{info, warn, error};
use solana_client::rpc_client::RpcClient;
use solana_sdk::commitment::Commitment;
use solana_sdk::hash::Hash;
use solana_sdk::pubkey::Pubkey;
use solana_sdk::signer::keypair::Keypair;
use solana_sdk::signer::Signer;
use solana_sdk::transaction::Transaction;
use tokio::time::interval;
use tokio_tungstenite::tungstenite::Message;
use tokio_tungstenite::connect_async;
use url::Url;

const WSOL_MINT: &str = "So11111111111111111111111111111111111111112";
const MAX_TOKEN_AGE: Duration = Duration::from_secs(3600); // 1 hour
const MAX_ACTIVE_TRADES: usize = 10;
const MAX_BUY_ATTEMPTS: u32 = 3;
#[derive(Clone)]
struct Trade {
    token_address: String,
    amount: u64,
    buy_price: f64,
    take_profit_price: f64,
    stop_loss_price: f64,
    timestamp: u64,
}

struct PriceCache {
    prices: HashMap<String, (f64, Instant)>,
    ttl: Duration,
}

impl PriceCache {
    fn new(ttl: u64) -> Self {
        Self {
            prices: HashMap::new(),
            ttl: Duration::from_secs(ttl),
        }
    }

    fn get(&self, token_address: &str) -> Option<f64> {
        self.prices
            .get(token_address)
            .and_then(|(price, timestamp)| {
                if timestamp.elapsed() < self.ttl {
                    Some(*price)
                } else {
                    None
                }
            })
    }

    fn set(&mut self, token_address: String, price: f64) {
        self.prices.insert(token_address, (price, Instant::now()));
    }
}
struct Bot {
    config: Config,
    rpc_client: RpcClient,
    keypair: Keypair,
    price_cache: Arc<Mutex<PriceCache>>,
    active_trades: Arc<Mutex<HashMap<String, Trade>>>,
    last_blockhash: Arc<Mutex<(Hash, Instant)>>,
    metadata_limiter: Arc<Mutex<()>>,
    swap_limiter: Arc<Mutex<()>>,
}

impl Bot {
    async fn new(config_path: &str) -> Result<Self> {
        let config = Config::builder()
        .add_source(config::File::with_name(config_path))
        .build()?;
        let rpc_url = config.get_string("rpc_url")?;
        let rpc_client = RpcClient::new(rpc_url);
        let keypair_64 = config.get_string("keypair_64")?;
        let keypair = bs58::decode(keypair_64).into_vec().map_err(|e| anyhow!("Failed to decode keypair: {}", e))?;
        let keypair = Keypair::from_bytes(&keypair).map_err(|e| anyhow!("Failed to create keypair: {}", e))?;
        let price_cache = Arc::new(Mutex::new(PriceCache::new(60)));
        let active_trades = Arc::new(Mutex::new(HashMap::new()));
        let last_blockhash = Arc::new(Mutex::new((Hash::default(), Instant::now())));
        let metadata_limiter = Arc::new(Mutex::new(()));
        let swap_limiter = Arc::new(Mutex::new(()));
        Ok(Self {
            config,
            rpc_client,
            keypair,
            price_cache,
            active_trades,
            last_blockhash,
            metadata_limiter,
            swap_limiter,
        })
    }

    async fn run(&self) -> Result<()> {
        let (mut write, mut read) = connect_async(&self.config.get_string("helius_websocket_url")?).await?;
        write.send(Message::Text(serde_json::json!({
            "jsonrpc": "2.0",
            "id": 1,
            "method": "subscribePoolCreations",
            "params": []
        }).to_string())).await?;
        info!("Connected to Helius WebSocket");

        loop {
            tokio::select! {
                Some(msg) = read.next() => {
                    match msg {
                        Ok(Message::Text(text)) => {
                            if let Err(e) = self.handle_event(&text).await {
                                error!("Error handling event: {}", e);
                            }
                        }
                        Err(e) => {
                            error!("WebSocket error: {}", e);
                            break;
                        }
                        _ => {}
                    }
                }
                _ = interval(Duration::from_secs(10)).tick() => {
                    if let Err(e) = self.check_active_trades().await {
                        error!("Error checking active trades: {}", e);
                    }
                }
            }
        }
        Ok(())
    }

    async fn handle_event(&self, text: &str) -> Result<()> {
        let event: serde_json::Value = serde_json::from_str(text)?;
        if let Some(params) = event.get("params") {
            let token_address = params
                .get("tokenAddress")
                .and_then(|v| v.as_str())
                .ok_or_else(|| anyhow!("Token address not found in event"))?;

            let creation_time = SystemTime::now()
                .duration_since(UNIX_EPOCH)
                .expect("Time went backwards")
                .as_secs();

            info!("Token {} created at {}", token_address, creation_time);

            if self.is_valid_pool(token_address, creation_time).await? {
                self.attempt_buy(token_address).await?;
            } else {
                info!("Token {} failed validation checks. Skipping.", token_address);
            }
        }

    Ok(())
    }
    async fn is_valid_pool(&self, token_address: &str, creation_time: u64) -> Result<bool> {
        let _guard = self.metadata_limiter.lock().await;

        let url = format!(
            "https://api.helius-rpc.com/v0/tokens/?api-key={}",
            self.config.get_string("helius_api_key")?
        );

        let response = reqwest::Client::new()
            .post(url)
            .json(&serde_json::json!({
                "mintAccounts": [token_address],
                "includeOffChain": true,
                "includeOnChain": true
            }))
            .send()
            .await?
            .json::<Vec<serde_json::Value>>()
            .await?;

        if let Some(token_data) = response.first() {
            let mint_authority = token_data["onChainMetadata"]["mintAuthority"].as_str().unwrap_or("").is_empty();
            let burnt = token_data["burnt"].as_bool().unwrap_or(false);
            let is_raydium_pool = token_data["legacyMetadata"]["dex"].as_str().map_or(false, |dex| dex == "raydium");
            let is_spl_token = token_data["tokenStandard"].as_str().map_or(false, |standard| standard == "SPL");

            let current_time = SystemTime::now()
                .duration_since(UNIX_EPOCH)
                .expect("Time went backwards")
                .as_secs();

            let token_age = current_time - creation_time;

            let liquidity = token_data["marketData"]["liquidity"].as_f64().unwrap_or(0.0);

            let is_valid = mint_authority
                && !burnt
                && is_raydium_pool
                && is_spl_token
                && token_age <= MAX_TOKEN_AGE.as_secs()
                && liquidity >= self.config.get_f64("min_liquidity")?
                && liquidity <= self.config.get_f64("max_liquidity")?;

            info!(
                "Token {} validation: Mint Authority empty: {}, Not burnt: {}, Raydium pool: {}, SPL token: {}, Age: {}s, Liquidity: {} SOL",
                token_address,
                mint_authority,
                !burnt,
                is_raydium_pool,
                is_spl_token,
                token_age,
                liquidity
            );

            Ok(is_valid)
        } else {
            Err(anyhow!("Failed to get asset information for token {}", token_address))
        }
    }

    async fn attempt_buy(&self, token_address: &str) -> Result<()> {
        let active_trades_count = self.active_trades.lock().await.len();
        if active_trades_count >= MAX_ACTIVE_TRADES {
            info!("Maximum active trades reached. Skipping buy for {}", token_address);
            return Ok(());
        }

        let snipe_amount = self.config.get_f64("snipe_amount")?;
        let snipe_amount_sol = snipe_amount * 1e9 as f64;

        for attempt in 1..=MAX_BUY_ATTEMPTS {
            info!("Buy attempt {} for token {}", attempt, token_address);

            let current_price = self.get_token_price(token_address).await?;
            info!("Current price for {}: {}", token_address, current_price);

            match self.execute_buy(token_address, snipe_amount_sol as u64).await {
                Ok(_) => return Ok(()),
                Err(e) => warn!("Buy attempt {} failed: {}", attempt, e),
            }
        }

        error!("All buy attempts failed for token: {}", token_address);
        Err(anyhow!("Failed to buy token after {} attempts", MAX_BUY_ATTEMPTS))
    }

    async fn execute_buy(&self, token_address: &str, amount: u64) -> Result<()> {
        let _guard = self.swap_limiter.lock().await;

        let jupiter_url = "https://quote-api.jup.ag/v6/quote";
        let params = serde_json::json!({
            "inputMint": WSOL_MINT,
            "outputMint": token_address,
            "amount": amount.to_string(),
            "slippageBps": (self.config.get_f64("max_slippage")? * 100.0) as u64,
        });

        let quote_response = reqwest::Client::new()
            .post(jupiter_url)
            .query(&params)
            .send()
            .await?
            .json::<serde_json::Value>()
            .await?;

        let swap_url = "https://quote-api.jup.ag/v6/swap";
        let swap_params = serde_json::json!({
            "quoteResponse": quote_response,
            "userPublicKey": self.keypair.pubkey().to_string(),
            "wrapUnwrapSOL": true,
            "priorityFee": self.config.get_f64("priority_fee")?
        });

        let swap_response = reqwest::Client::new()
            .post(swap_url)
            .json(&swap_params)
            .send()
            .await?
            .json::<serde_json::Value>()
            .await?;

        let transaction_data = base64::decode(swap_response["swapTransaction"].as_str().unwrap())?;
        let transaction = Transaction::from_bytes(&transaction_data)?;

        let recent_blockhash = self.get_recent_blockhash().await?;
        let mut final_transaction = Transaction::new_unsigned(transaction.message().clone());
        final_transaction.sign(&[&self.keypair], recent_blockhash);

        let signature = self.rpc_client.send_and_confirm_transaction_with_spinner(&final_transaction)?;
        info!("Buy executed successfully. Signature: {}", signature);

        let current_price = self.get_token_price(token_address).await?;
        let take_profit_price = current_price * (1.0 + self.config.get_f64("profit_target_percent")? / 100.0);
        let stop_loss_price = current_price * (1.0 - self.config.get_f64("stop_loss_percent")? / 100.0);

        let trade = Trade {
            token_address: token_address.to_string(),
            amount,
            buy_price: current_price,
            take_profit_price,
            stop_loss_price,
            timestamp: SystemTime::now()
                .duration_since(UNIX_EPOCH)
                .expect("Time went backwards")
                .as_secs(),
        };

        self.active_trades.lock().await.insert(token_address.to_string(), trade);

        info!(
            "Added trade to active trades. Take profit: {}, Stop loss: {}",
            take_profit_price, stop_loss_price
        );

        Ok(())
    }

    async fn check_active_trades(&self) -> Result<()> {
        let mut trades_to_remove = Vec::new();
        let current_time = SystemTime::now()
            .duration_since(UNIX_EPOCH)
            .expect("Time went backwards")
            .as_secs();

        {
            let active_trades = self.active_trades.lock().await;
            for (token_address, trade) in active_trades.iter() {
                if current_time - trade.timestamp > MAX_TOKEN_AGE.as_secs() {
                    trades_to_remove.push(token_address.clone());
                    continue;
                }

                let current_price = self.get_token_price(token_address).await?;

                if current_price >= trade.take_profit_price || current_price <= trade.stop_loss_price {
                    info!("Executing sell for token {}. Current price: {}", token_address, current_price);
                    if let Err(e) = self.execute_sell(token_address).await {
                        error!("Failed to sell token {}: {}", token_address, e);
                    }
                }
            }
        }

        if !trades_to_remove.is_empty() {
            let mut active_trades = self.active_trades.lock().await;
            for token_address in trades_to_remove {
                active_trades.remove(&token_address);
                info!("Removed old trade for token {}", token_address);
            }
        }

        Ok(())
    }

    async fn execute_sell(&self, token_address: &str) -> Result<()> {
        let _guard = self.swap_limiter.lock().await;

        let amount = {
            let active_trades = self.active_trades.lock().await;
            active_trades.get(token_address)
                .map(|trade| trade.amount)
                .ok_or_else(|| anyhow
    
    async fn execute_sell(&self, token_address: &str) -> Result<()> {
        let _guard = self.swap_limiter.lock().await;
                
        let amount = {
                let active_trades = self.active_trades.lock().await;
            active_trades.get(token_address)
                .map(|trade| trade.amount)
                .ok_or_else(|| anyhow!("Trade not found for token {}", token_address))?
        };
                
        let jupiter_url = "https://quote-api.jup.ag/v6/quote";
        let params = serde_json::json!({
            "inputMint": token_address,
            "outputMint": WSOL_MINT,
            "amount": amount.to_string(),
            "slippageBps": (self.config.get_f64("max_slippage")? * 100.0) as u64,
        });
                
        let quote_response = reqwest::Client::new()
            .post(jupiter_url)
            .query(&params)
            .send()
            .await?
            .json::<serde_json::Value>()
            .await?;
                
        let swap_url = "https://quote-api.jup.ag/v6/swap";
        let swap_params = serde_json::json!({
            "quoteResponse": quote_response,
            "userPublicKey": self.keypair.pubkey().to_string(),
            "wrapUnwrapSOL": true,
            "priorityFee": self.config.get_f64("priority_fee")?
        });
                
        let swap_response = reqwest::Client::new()
            .post(swap_url)
            .json(&swap_params)
            .send()
            .await?
            .json::<serde_json::Value>()
            .await?;
                
        let transaction_data = base64::decode(swap_response["swapTransaction"].as_str().unwrap())?;
        let transaction = Transaction::from_bytes(&transaction_data)?;
                
        let recent_blockhash = self.get_recent_blockhash().await?;
        let mut final_transaction = Transaction::new_unsigned(transaction.message().clone());
        final_transaction.sign(&[&self.keypair], recent_blockhash);
                
        let signature = self.rpc_client.send_and_confirm_transaction_with_spinner(&final_transaction)?;
        info!("Sell executed successfully. Signature: {}", signature);
                
        // Ensure the trade is completely sold
        loop {
            match self.get_token_balance(token_address).await {
                Ok(balance) => {
                    if balance == 0 {
                        info!("Token {} completely sold", token_address);
                        break;
                    }
                    info!("Remaining balance for {}: {}. Waiting for complete sell...", token_address, balance);
                }
                Err(e) => {
                    error!("Failed to get balance for {}: {}", token_address, e);
                    break;
                }
            }
                
            tokio::time::sleep(Duration::from_secs(1)).await;
        }
                
        // Remove the trade from active trades
        let mut active_trades = self.active_trades.lock().await;
        active_trades.remove(token_address);
                
        Ok(())
    }
                
    async fn get_token_price(&self, token_address: &str) -> Result<f64> {
        let cache = self.price_cache.lock().await;
        if let Some(price) = cache.get(token_address) {
            return Ok(price);
        }
        drop(cache);
                
        let _guard = self.metadata_limiter.lock().await;
                
        let url = format!(
            "https://api.helius-rpc.com/v0/tokens/?api-key={}",
            self.config.get_string("helius_api_key")?
        );
                
        let response = reqwest::Client::new()
            .post(url)
            .json(&serde_json::json!({
                "mintAccounts": [token_address],
                "includeOffChain": true,
                "includeOnChain": true
            }))
            .send()
            .await?
            .json::<serde_json::Value>()
            .await?;
                
        if let Some(token_data) = response.first() {
            if let Some(price) = token_data["price"].as_f64() {
                let mut cache = self.price_cache.lock().await;
                cache.set(token_address.to_string(), price);
                Ok(price)
                } else {
                Err(anyhow!("No price found for token {}", token_address))
            }
        }   else {
                 Err(anyhow!("No data found for token {}", token_address))
        }
    }
        }
    }
}
                
    async fn get_token_balance(&self, token_address: &str) -> Result<u64> {
        let token_pubkey = Pubkey::from_str(token_address)?;
        let token_accounts = self.rpc_client.get_token_accounts_by_owner(
            &self.keypair.pubkey(),
            solana_client::rpc_request::TokenAccountsFilter::Mint(token_pubkey)
        )?;
                
        if let Some(account) = token_accounts.first() {
            let balance = self.rpc_client.get_token_account_balance(&Pubkey::from_str(&account.pubkey)?)?;
            Ok(balance.amount.parse()?)
        } else {
            Ok(0) // If no token account, assume balance is 0
        }
    }
                
    async fn update_blockhash(&self) -> Result<()> {
        let new_blockhash = self.rpc_client.get_latest_blockhash()?;
        let mut last_blockhash = self.last_blockhash.lock().await;
        *last_blockhash = (new_blockhash, Instant::now());
        Ok(())
    }
                
    async fn get_recent_blockhash(&self) -> Result<Hash> {
        let last_blockhash = self.last_blockhash.lock().await;
        if last_blockhash.1.elapsed() > Duration::from_secs(60) {
            drop(last_blockhash);
            self.update_blockhash().await?;
            Ok(self.last_blockhash.lock().await.0)
        } else {
            Ok(last_blockhash.0)
        }
    }
}
                
#[tokio::main]
async fn main() -> Result<()> {
    env_logger::init_from_env(env_logger::Env::default().default_filter_or("info"));
    let bot = Bot::new("config.toml").await?;
    bot.run().await?;
    Ok(())
}