[
  {
    "path": ".gitignore",
    "content": ".env\ntarget\n"
  },
  {
    "path": "Cargo.toml",
    "content": "[package]\nname = \"raydium-sniper-bot\"\nversion = \"0.1.0\"\nedition = \"2021\"\n"
  },
  {
    "path": "README.md",
    "content": "# Solana Raydium Sniper Bot \nThis bot fetches to new Raydium pools and buys as soon as possible. If RPC or node is good, it commonly buy tokens before token is availabel on Raydium UI, can buy tokens than the others. It's free, basic version, and I have advanced version for it. I updated codebase with Rust to boost speed and performance. Feel free to contact with me to get advanced version. [Telegram: https://t.me/DevCutup, Whatsapp: https://wa.me/13137423660]. This is just version to give vision about raydium dex and sniper bot.\n\n\n\n## Features\n### Speed and Efficiency\n- **Lightning-Quick Transactions**: Leveraging Rust's exceptional performance, our bot allows you to snipe new tokens almost instantly. Say goodbye to delays and seize opportunities as they arise!\n### Safety First\n- **Robust Security**: Rust's safety guarantees minimize bugs and vulnerabilities, ensuring your trading activities are secure. Trade with confidence and peace of mind.\n### Multiple gRPC Connections\n- **Stay Updated**: Effortlessly connect to top Solana data providers like **Helius** and **Yellowstone** through multiple gRPC connections. Get real-time updates and make informed trading decisions.\n### User-Friendly Interface\n- **Intuitive Design**: My sniper bot features a clean and accessible interface, making it easy for users of all experience levels to navigate. Start trading in no time!\n\n\n\n## Advanced Features\n- **jito-confirm**: Engage in low-latency transactions on platforms like Raydium and Pumpfun.\n- **jito-bundle**: Bundle buy/sell actions with up to **20 wallets** in Raydium/Pumpfun, enhancing your trading strategy and flexibility.\n\n\n\n---\n\n## Directory Structure\n\n```\nsrc/\n├── core/\n│   ├── token.rs        # Token definitions and handling\n│   └── tx.rs           # Transaction handling\n|   └── mod.rs          # mod file\n| \n├── engine/\n│   ├── swap.rs         # Token swap(buy/sell) functionalities in various Dexs\n│   └── monitor         # New token monitoring(and parse tx) in Dexs using geyser rpc, and normal rpc\n│       └── helius.rs               # Helius gRpc for tx listen and parse.\n│       └── yellowstone.rs          # Yellowstone gRpc for tx listen and parse.\n|   └── mod.rs          # mod file\n|\n├── dex/\n│   ├── raydium.rs      # Raydium\n|   └── mod.rs          # mod file\n│\n├── services/\n│   ├── jito.rs        # Jito service provides ultra-fast transaction confirmation\n│   ├── nozomi.rs        # Jito service provides ultra-fast transaction confirmation\n│   ├── zeroslot.rs        # Jito service provides ultra-fast transaction confirmation\n│   └── nextblock.rs        # NextBlock service provides the ultra-fast transaction confirmation in unique way\n|   └── mod.rs          # mod file\n|\n├── common/\n│   ├── logger.rs        # Logs to be clean and convenient to monitor.\n│   └── utils.rs        # Utility functions used across the project\n|   └── mod.rs          # mod file\n│\n├── lib.rs\n└── main.rs\n```\n---\n\n\n\n### Setup\n1. Environment Variables Settings\n```plaintext\nPRIVATE_KEY= # your wallet priv_key\nRPC_API_KEY= #your helius rpc api-key (Please use premium version that has Geyser Enhanced Websocket)\nSLIPPAGE=10\nJITO_BLOCK_ENGINE_URL=https://ny.mainnet.block-engine.jito.wtf\nJITO_TIP_VALUE=0.00927\nTIME_EXCEED=60 # seconds; time limit for volume non-increasing\nTOKEN_AMOUNT=0.0000001 # token amount to purchase\nTP=3 #3 times\nSL=0.5 #50 percentage\n```\n2. Add the wallet address you want to block on a new line and save the file.\n```\n3NQmnSXfGqtgxFTZ82gS7Pwt2btn3fEPb6EiX5ax5bvr\n```\n3. Run `trial/raydium-sniper.exe`.\n\n\n\n### Test Result(Same Block)\n- Detect: https://solscan.io/tx/5o7ajnZ9CRf7FBYEvydu8vapJJDWtKCvRFiTUBmbeu2FmmDhAQQy3c9YFFhpTucr2SZcrf2aUsDanEVjYgwN9kBc\n- Bought: https://solscan.io/tx/3vgim3MwJsdtahXqfW2DrzTAWpVQ8EUTed2cjzHuqxSfUpfp72mgzZhiVosWaCUHdqJTDHpQaYh5xN7rkHGmzqWv\n- Dexscreener: https://dexscreener.com/solana/A1zZXCq2DmqwVD4fLDzmgQ3ceY6LQnMBVokejqnHpump\n\n\n### Contact Information\n- Telegram: https://t.me/DevCutup\n- Whatsapp: https://wa.me/13137423660\n- Twitter: https://x.com/devcutup\n"
  },
  {
    "path": "src/common/logger.rs",
    "content": "use chrono::Local;\n\nconst LOG_LEVEL: &str = \"LOG\";\n\npub struct Logger {\n    prefix: String,\n    date_format: String,\n}\n\nimpl Logger {\n    // Constructor function to create a new Logger instance\n    pub fn new(prefix: String) -> Self {\n        Logger {\n            prefix,\n            date_format: String::from(\"%Y-%m-%d %H:%M:%S\"),\n        }\n    }\n\n    // Method to log a message with a prefix\n    pub fn log(&self, message: String) -> String {\n        let log = format!(\"{} {}\", self.prefix_with_date(), message);\n        println!(\"{}\", log);\n        log\n    }\n\n    pub fn debug(&self, message: String) -> String {\n        let log = format!(\"{} [{}] {}\", self.prefix_with_date(), \"DEBUG\", message);\n        if LogLevel::new().is_debug() {\n            println!(\"{}\", log);\n        }\n        log\n    }\n    pub fn error(&self, message: String) -> String {\n        let log = format!(\"{} [{}] {}\", self.prefix_with_date(), \"ERROR\", message);\n        println!(\"{}\", log);\n\n        log\n    }\n\n    fn prefix_with_date(&self) -> String {\n        let date = Local::now();\n        format!(\n            \"[{}] {}\",\n            date.format(self.date_format.as_str()),\n            self.prefix\n        )\n    }\n}\n\nstruct LogLevel<'a> {\n    level: &'a str,\n}\nimpl LogLevel<'_> {\n    fn new() -> Self {\n        let level = LOG_LEVEL;\n        LogLevel { level }\n    }\n    fn is_debug(&self) -> bool {\n        self.level.to_lowercase().eq(\"debug\")\n    }\n}\n"
  },
  {
    "path": "src/common/mod.rs",
    "content": "pub mod logger;\npub mod utils;\n"
  },
  {
    "path": "src/common/utils.rs",
    "content": "use anyhow::Result;\nuse solana_sdk::{commitment_config::CommitmentConfig, signature::Keypair};\nuse std::{env, sync::Arc};\n\n#[derive(Clone)]\npub struct AppState {\n    pub rpc_client: Arc<solana_client::rpc_client::RpcClient>,\n    pub rpc_nonblocking_client: Arc<solana_client::nonblocking::rpc_client::RpcClient>,\n    pub wallet: Arc<Keypair>,\n}\n\npub fn import_env_var(key: &str) -> String {\n    env::var(key).unwrap_or_else(|_| panic!(\"Environment variable {} is not set\", key))\n}\n\npub fn create_rpc_client() -> Result<Arc<solana_client::rpc_client::RpcClient>> {\n    let rpc_https = import_env_var(\"RPC_HTTPS\");\n    let rpc_client = solana_client::rpc_client::RpcClient::new_with_commitment(\n        rpc_https,\n        CommitmentConfig::processed(),\n    );\n    Ok(Arc::new(rpc_client))\n}\n\npub async fn create_nonblocking_rpc_client(\n) -> Result<Arc<solana_client::nonblocking::rpc_client::RpcClient>> {\n    let rpc_https = import_env_var(\"RPC_HTTPS\");\n    let rpc_client = solana_client::nonblocking::rpc_client::RpcClient::new_with_commitment(\n        rpc_https,\n        CommitmentConfig::processed(),\n    );\n    Ok(Arc::new(rpc_client))\n}\n\npub fn import_wallet() -> Result<Arc<Keypair>> {\n    let priv_key = import_env_var(\"PRIVATE_KEY\");\n    let wallet: Keypair = Keypair::from_base58_string(priv_key.as_str());\n\n    Ok(Arc::new(wallet))\n}\n"
  },
  {
    "path": "src/core/mod.rs",
    "content": "pub mod token;\npub mod tx;\n"
  },
  {
    "path": "src/core/token.rs",
    "content": "use solana_sdk::{pubkey::Pubkey, signature::Keypair};\nuse spl_token_2022::{\n    extension::StateWithExtensionsOwned,\n    state::{Account, Mint},\n};\nuse spl_token_client::{\n    client::{ProgramClient, ProgramRpcClient, ProgramRpcClientSendTransaction},\n    token::{Token, TokenError, TokenResult},\n};\nuse std::sync::Arc;\n\npub fn get_associated_token_address(\n    client: Arc<solana_client::nonblocking::rpc_client::RpcClient>,\n    keypair: Arc<Keypair>,\n    address: &Pubkey,\n    owner: &Pubkey,\n) -> Pubkey {\n    let token_client = Token::new(\n        Arc::new(ProgramRpcClient::new(\n            client.clone(),\n            ProgramRpcClientSendTransaction,\n        )),\n        &spl_token::ID,\n        address,\n        None,\n        Arc::new(Keypair::from_bytes(&keypair.to_bytes()).expect(\"failed to copy keypair\")),\n    );\n    token_client.get_associated_token_address(owner)\n}\n\npub async fn get_account_info(\n    client: Arc<solana_client::nonblocking::rpc_client::RpcClient>,\n    _keypair: Arc<Keypair>,\n    address: &Pubkey,\n    account: &Pubkey,\n) -> TokenResult<StateWithExtensionsOwned<Account>> {\n    let program_client = Arc::new(ProgramRpcClient::new(\n        client.clone(),\n        ProgramRpcClientSendTransaction,\n    ));\n    let account = program_client\n        .get_account(*account)\n        .await\n        .map_err(TokenError::Client)?\n        .ok_or(TokenError::AccountNotFound)\n        .inspect_err(|err| println!(\"get_account_info: {} {}: mint {}\", account, err, address))?;\n\n    if account.owner != spl_token::ID {\n        return Err(TokenError::AccountInvalidOwner);\n    }\n    let account = StateWithExtensionsOwned::<Account>::unpack(account.data)?;\n    if account.base.mint != *address {\n        return Err(TokenError::AccountInvalidMint);\n    }\n\n    Ok(account)\n}\n\npub async fn get_mint_info(\n    client: Arc<solana_client::nonblocking::rpc_client::RpcClient>,\n    _keypair: Arc<Keypair>,\n    address: &Pubkey,\n) -> TokenResult<StateWithExtensionsOwned<Mint>> {\n    let program_client = Arc::new(ProgramRpcClient::new(\n        client.clone(),\n        ProgramRpcClientSendTransaction,\n    ));\n    let account = program_client\n        .get_account(*address)\n        .await\n        .map_err(TokenError::Client)?\n        .ok_or(TokenError::AccountNotFound)\n        .inspect_err(|err| println!(\"{} {}: mint {}\", address, err, address))?;\n\n    if account.owner != spl_token::ID {\n        return Err(TokenError::AccountInvalidOwner);\n    }\n\n    let mint_result = StateWithExtensionsOwned::<Mint>::unpack(account.data).map_err(Into::into);\n    let decimals: Option<u8> = None;\n    if let (Ok(mint), Some(decimals)) = (&mint_result, decimals) {\n        if decimals != mint.base.decimals {\n            return Err(TokenError::InvalidDecimals);\n        }\n    }\n\n    mint_result\n}\n"
  },
  {
    "path": "src/core/tx.rs",
    "content": "use std::{env, sync::Arc, time::Duration};\n\nuse anyhow::Result;\nuse jito_json_rpc_client::jsonrpc_client::rpc_client::RpcClient as JitoRpcClient;\nuse solana_client::rpc_client::RpcClient;\nuse solana_sdk::{\n    instruction::Instruction,\n    signature::Keypair,\n    signer::Signer,\n    system_transaction,\n    transaction::{Transaction, VersionedTransaction},\n};\nuse spl_token::ui_amount_to_amount;\n\nuse std::str::FromStr;\nuse tokio::time::Instant;\n\nuse crate::{\n    common::logger::Logger,\n    services::jito::{self, get_tip_account, get_tip_value, wait_for_bundle_confirmation},\n};\n\n// prioritization fee = UNIT_PRICE * UNIT_LIMIT\nfn get_unit_price() -> u64 {\n    env::var(\"UNIT_PRICE\")\n        .ok()\n        .and_then(|v| u64::from_str(&v).ok())\n        .unwrap_or(1)\n}\n\nfn get_unit_limit() -> u32 {\n    env::var(\"UNIT_LIMIT\")\n        .ok()\n        .and_then(|v| u32::from_str(&v).ok())\n        .unwrap_or(300_000)\n}\n\npub async fn new_signed_and_send(\n    client: &RpcClient,\n    keypair: &Keypair,\n    mut instructions: Vec<Instruction>,\n    use_jito: bool,\n    logger: &Logger,\n) -> Result<Vec<String>> {\n    let unit_price = get_unit_price();\n    let unit_limit = get_unit_limit();\n    // If not using Jito, manually set the compute unit price and limit\n    if !use_jito {\n        let modify_compute_units =\n            solana_sdk::compute_budget::ComputeBudgetInstruction::set_compute_unit_price(\n                unit_price,\n            );\n        let add_priority_fee =\n            solana_sdk::compute_budget::ComputeBudgetInstruction::set_compute_unit_limit(\n                unit_limit,\n            );\n        instructions.insert(0, modify_compute_units);\n        instructions.insert(1, add_priority_fee);\n    }\n    // send init tx\n    let recent_blockhash = client.get_latest_blockhash()?;\n    let txn = Transaction::new_signed_with_payer(\n        &instructions,\n        Some(&keypair.pubkey()),\n        &vec![keypair],\n        recent_blockhash,\n    );\n\n    let start_time = Instant::now();\n    let mut txs = vec![];\n    if use_jito {\n        // jito\n        let tip_account = get_tip_account().await?;\n        let jito_client = Arc::new(JitoRpcClient::new(format!(\n            \"{}/api/v1/bundles\",\n            *jito::BLOCK_ENGINE_URL\n        )));\n        // jito tip, the upper limit is 0.1\n        let mut tip = get_tip_value().await?;\n        tip = tip.min(0.1);\n        let tip_lamports = ui_amount_to_amount(tip, spl_token::native_mint::DECIMALS);\n        logger.log(format!(\n            \"tip account: {}, tip(sol): {}, lamports: {}\",\n            tip_account, tip, tip_lamports\n        ));\n        // tip tx\n        let bundle: Vec<VersionedTransaction> = vec![\n            VersionedTransaction::from(txn),\n            VersionedTransaction::from(system_transaction::transfer(\n                keypair,\n                &tip_account,\n                tip_lamports,\n                recent_blockhash,\n            )),\n        ];\n        let bundle_id = jito_client.send_bundle(&bundle).await?;\n        logger.log(format!(\"bundle_id: {}\", bundle_id));\n\n        txs = wait_for_bundle_confirmation(\n            move |id: String| {\n                let client = Arc::clone(&jito_client);\n                async move {\n                    let response = client.get_bundle_statuses(&[id]).await;\n                    let statuses = response.inspect_err(|err| {\n                        logger.log(format!(\"Error fetching bundle status: {:?}\", err));\n                    })?;\n                    Ok(statuses.value)\n                }\n            },\n            bundle_id,\n            Duration::from_millis(1000),\n            Duration::from_secs(10),\n        )\n        .await?;\n    } else {\n        let sig = common::rpc::send_txn(client, &txn, true)?;\n        logger.log(format!(\"signature: {:#?}\", sig));\n        txs.push(sig.to_string());\n    }\n\n    logger.log(format!(\"tx ellapsed: {:?}\", start_time.elapsed()));\n    Ok(txs)\n}\n"
  },
  {
    "path": "src/dex/mod.rs",
    "content": "pub mod pump_fun;\npub mod raydium;\npub mod meteora;\npub mod orca;\n"
  },
  {
    "path": "src/dex/raydium.rs",
    "content": "use crate::{\n    common::{\n        logger::Logger,\n        utils::{import_env_var, SwapConfig},\n    },\n    core::{\n        token::{get_account_info, get_associated_token_address, get_mint_info},\n        tx,\n    },\n    engine::swap::{SwapDirection, SwapInType},\n};\nuse amm_cli::AmmSwapInfoResult;\nuse anyhow::{anyhow, Context, Result};\nuse bytemuck;\nuse raydium_amm::state::{AmmInfo, Loadable};\nuse reqwest::Proxy;\nuse serde::Deserialize;\nuse solana_client::rpc_filter::{Memcmp, RpcFilterType};\nuse solana_sdk::{\n    instruction::Instruction, program_pack::Pack, pubkey::Pubkey, signature::Keypair,\n    signer::Signer, system_instruction,\n};\nuse spl_associated_token_account::instruction::create_associated_token_account;\nuse spl_token::{amount_to_ui_amount, state::Account, ui_amount_to_amount};\nuse spl_token_client::token::TokenError;\nuse std::{str::FromStr, sync::Arc};\n\npub const AMM_PROGRAM: &str = \"675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8\";\n\n#[derive(Debug, Deserialize)]\npub struct PoolInfo {\n    pub success: bool,\n    pub data: PoolData,\n}\n\n#[derive(Debug, Deserialize)]\npub struct PoolData {\n    // pub count: u32,\n    pub data: Vec<Pool>,\n}\n\nimpl PoolData {\n    pub fn get_pool(&self) -> Option<Pool> {\n        self.data.first().cloned()\n    }\n}\n\n#[derive(Debug, Deserialize, Clone)]\npub struct Pool {\n    pub id: String,\n    #[serde(rename = \"programId\")]\n    pub program_id: String,\n    #[serde(rename = \"mintA\")]\n    pub mint_a: Mint,\n    #[serde(rename = \"mintB\")]\n    pub mint_b: Mint,\n    #[serde(rename = \"marketId\")]\n    pub market_id: String,\n}\n\n#[derive(Debug, Deserialize, Clone)]\npub struct Mint {\n    pub address: String,\n    pub symbol: String,\n    pub name: String,\n    pub decimals: u8,\n}\n\npub struct Raydium {\n    pub rpc_nonblocking_client: Arc<solana_client::nonblocking::rpc_client::RpcClient>,\n    pub rpc_client: Option<Arc<solana_client::rpc_client::RpcClient>>,\n    pub keypair: Arc<Keypair>,\n    pub pool_id: Option<String>,\n}\n\nimpl Raydium {\n    pub fn new(\n        rpc_nonblocking_client: Arc<solana_client::nonblocking::rpc_client::RpcClient>,\n        rpc_client: Arc<solana_client::rpc_client::RpcClient>,\n        keypair: Arc<Keypair>,\n    ) -> Self {\n        Self {\n            rpc_nonblocking_client,\n            keypair,\n            rpc_client: Some(rpc_client),\n            pool_id: None,\n        }\n    }\n\n    pub async fn swap(\n        &self,\n        swap_config: SwapConfig,\n        amm_pool_id: Pubkey,\n        pool_state: AmmInfo,\n    ) -> Result<Vec<String>> {\n        let logger = Logger::new(format!(\n            \"[SWAP IN RAYDIUM]({}) => \",\n            chrono::Utc::now().timestamp()\n        ));\n        let slippage_bps = swap_config.slippage * 100;\n        let owner = self.keypair.pubkey();\n        let program_id = spl_token::ID;\n        let native_mint = spl_token::native_mint::ID;\n        let mint = pool_state.coin_vault_mint;\n\n        let (token_in, token_out, user_input_token, swap_base_in) = match (\n            swap_config.swap_direction.clone(),\n            pool_state.coin_vault_mint == native_mint,\n        ) {\n            (SwapDirection::Buy, true) => (native_mint, mint, pool_state.coin_vault, true),\n            (SwapDirection::Buy, false) => (native_mint, mint, pool_state.pc_vault, true),\n            (SwapDirection::Sell, true) => (mint, native_mint, pool_state.pc_vault, true),\n            (SwapDirection::Sell, false) => (mint, native_mint, pool_state.coin_vault, true),\n        };\n\n        logger.log(format!(\n            \"token_in:{}, token_out:{}, user_input_token:{}, swap_base_in:{}\",\n            token_in, token_out, user_input_token, swap_base_in\n        ));\n\n        let in_ata = get_associated_token_address(\n            self.rpc_nonblocking_client.clone(),\n            self.keypair.clone(),\n            &token_in,\n            &owner,\n        );\n        let out_ata = get_associated_token_address(\n            self.rpc_nonblocking_client.clone(),\n            self.keypair.clone(),\n            &token_out,\n            &owner,\n        );\n\n        let mut create_instruction = None;\n        let mut close_instruction = None;\n\n        tx::new_signed_and_send(\n            &client,\n            &self.keypair,\n            instructions,\n            swap_config.use_jito,\n            &logger,\n        )\n        .await\n    }\n}\n\npub fn amm_swap(\n    amm_program: &Pubkey,\n    result: AmmSwapInfoResult,\n    user_owner: &Pubkey,\n    user_source: &Pubkey,\n    user_destination: &Pubkey,\n    amount_specified: u64,\n    other_amount_threshold: u64,\n    swap_base_in: bool,\n) -> Result<Instruction> {\n    let swap_instruction = if swap_base_in {\n        raydium_amm::instruction::swap_base_in(\n            amm_program,\n            &result.pool_id,\n            &result.amm_authority,\n            &result.amm_open_orders,\n            &result.amm_coin_vault,\n            &result.amm_pc_vault,\n            &result.market_program,\n            &result.market,\n            &result.market_bids,\n            &result.market_asks,\n            &result.market_event_queue,\n            &result.market_coin_vault,\n            &result.market_pc_vault,\n            &result.market_vault_signer,\n            user_source,\n            user_destination,\n            user_owner,\n            amount_specified,\n            other_amount_threshold,\n        )?\n    } else {\n        raydium_amm::instruction::swap_base_out(\n            amm_program,\n            &result.pool_id,\n            &result.amm_authority,\n            &result.amm_open_orders,\n            &result.amm_coin_vault,\n            &result.amm_pc_vault,\n            &result.market_program,\n            &result.market,\n            &result.market_bids,\n            &result.market_asks,\n            &result.market_event_queue,\n            &result.market_coin_vault,\n            &result.market_pc_vault,\n            &result.market_vault_signer,\n            user_source,\n            user_destination,\n            user_owner,\n            other_amount_threshold,\n            amount_specified,\n        )?\n    };\n\n    Ok(swap_instruction)\n}\n\npub async fn get_pool_state(\n    rpc_client: Arc<solana_client::rpc_client::RpcClient>,\n    pool_id: Option<&str>,\n    mint: Option<&str>,\n    logger: &Logger,\n) -> Result<(Pubkey, AmmInfo)> {\n    if let Some(pool_id) = pool_id {\n        logger.log(format!(\"[FIND POOL STATE BY pool_id]: {}\", pool_id));\n        let amm_pool_id = Pubkey::from_str(pool_id)?;\n        let pool_data = common::rpc::get_account(&rpc_client, &amm_pool_id)?\n            .ok_or(anyhow!(\"NotFoundPool: pool state not found\"))?;\n        let pool_state: &AmmInfo =\n            bytemuck::from_bytes(&pool_data[0..core::mem::size_of::<AmmInfo>()]);\n        Ok((amm_pool_id, *pool_state))\n    } else if let Some(mint) = mint {\n        // find pool by mint via rpc\n        if let Ok(pool_state) = get_pool_state_by_mint(rpc_client.clone(), mint, logger).await {\n            return Ok(pool_state);\n        }\n        // find pool by mint via raydium api\n        let pool_data = get_pool_info(&spl_token::native_mint::ID.to_string(), mint).await;\n        if let Ok(pool_data) = pool_data {\n            let pool = pool_data\n                .get_pool()\n                .ok_or(anyhow!(\"NotFoundPool: pool not found in raydium api\"))?;\n            let amm_pool_id = Pubkey::from_str(&pool.id)?;\n            logger.log(format!(\"[FIND POOL STATE BY raydium api]: {}\", amm_pool_id));\n            let pool_data = common::rpc::get_account(&rpc_client, &amm_pool_id)?\n                .ok_or(anyhow!(\"NotFoundPool: pool state not found\"))?;\n            let pool_state: &AmmInfo =\n                bytemuck::from_bytes(&pool_data[0..core::mem::size_of::<AmmInfo>()]);\n\n            return Ok((amm_pool_id, *pool_state));\n        }\n        Err(anyhow!(\"NotFoundPool: pool state not found\"))\n    } else {\n        Err(anyhow!(\"NotFoundPool: pool state not found\"))\n    }\n}\n\npub async fn get_pool_state_by_mint(\n    rpc_client: Arc<solana_client::rpc_client::RpcClient>,\n    mint: &str,\n    logger: &Logger,\n) -> Result<(Pubkey, AmmInfo)> {\n    logger.log(format!(\"[FIND POOL STATE BY mint]: {}\", mint));\n    let pairs = vec![\n        // pump pool\n        (\n            Some(spl_token::native_mint::ID),\n            Pubkey::from_str(mint).ok(),\n        ),\n        // general pool\n        (\n            Pubkey::from_str(mint).ok(),\n            Some(spl_token::native_mint::ID),\n        ),\n    ];\n\n    let pool_len = core::mem::size_of::<AmmInfo>() as u64;\n    let amm_program = Pubkey::from_str(AMM_PROGRAM)?;\n    // Find matching AMM pool from mint pairs by filter\n    let mut found_pools = None;\n    for (coin_mint, pc_mint) in pairs {\n        logger.log(format!(\n            \"get_pool_state_by_mint filter: coin_mint: {:?}, pc_mint: {:?}\",\n            coin_mint, pc_mint\n        ));\n        let filters = match (coin_mint, pc_mint) {\n            (None, None) => Some(vec![RpcFilterType::DataSize(pool_len)]),\n            (Some(coin_mint), None) => Some(vec![\n                RpcFilterType::Memcmp(Memcmp::new_base58_encoded(400, &coin_mint.to_bytes())),\n                RpcFilterType::DataSize(pool_len),\n            ]),\n            (None, Some(pc_mint)) => Some(vec![\n                RpcFilterType::Memcmp(Memcmp::new_base58_encoded(432, &pc_mint.to_bytes())),\n                RpcFilterType::DataSize(pool_len),\n            ]),\n            (Some(coin_mint), Some(pc_mint)) => Some(vec![\n                RpcFilterType::Memcmp(Memcmp::new_base58_encoded(400, &coin_mint.to_bytes())),\n                RpcFilterType::Memcmp(Memcmp::new_base58_encoded(432, &pc_mint.to_bytes())),\n                RpcFilterType::DataSize(pool_len),\n            ]),\n        };\n        let pools =\n            common::rpc::get_program_accounts_with_filters(&rpc_client, amm_program, filters)\n                .unwrap();\n        if !pools.is_empty() {\n            found_pools = Some(pools);\n            break;\n        }\n    }\n\n    match found_pools {\n        Some(pools) => {\n            let pool = &pools[0];\n            let pool_state = AmmInfo::load_from_bytes(&pools[0].1.data)?;\n            Ok((pool.0, *pool_state))\n        }\n        None => Err(anyhow!(\"NotFoundPool: pool state not found\")),\n    }\n}\n\n// get pool info\n// https://api-v3.raydium.io/pools/info/mint?mint1=So11111111111111111111111111111111111111112&mint2=EzM2d8JVpzfhV7km3tUsR1U1S4xwkrPnWkM4QFeTpump&poolType=standard&poolSortField=default&sortType=desc&pageSize=10&page=1\npub async fn get_pool_info(mint1: &str, mint2: &str) -> Result<PoolData> {\n    let mut client_builder = reqwest::Client::builder();\n    let http_proxy = import_env_var(\"HTTP_PROXY\");\n    let proxy = Proxy::all(http_proxy)?;\n    client_builder = client_builder.proxy(proxy);\n    let client = client_builder.build()?;\n\n    let result = client\n        .get(\"https://api-v3.raydium.io/pools/info/mint\")\n        .query(&[\n            (\"mint1\", mint1),\n            (\"mint2\", mint2),\n            (\"poolType\", \"standard\"),\n            (\"poolSortField\", \"default\"),\n            (\"sortType\", \"desc\"),\n            (\"pageSize\", \"1\"),\n            (\"page\", \"1\"),\n        ])\n        .send()\n        .await?\n        .json::<PoolInfo>()\n        .await\n        .context(\"Failed to parse pool info JSON\")?;\n    Ok(result.data)\n}\n"
  },
  {
    "path": "src/engine/mod.rs",
    "content": "pub mod monitor;\npub mod swap;\n"
  },
  {
    "path": "src/engine/monitor/mod.rs",
    "content": "pub mod helius;\npub mod yellowstone;\n"
  },
  {
    "path": "src/lib.rs",
    "content": "pub mod common;\npub mod core;\npub mod dex;\npub mod engine;\npub mod services;\n"
  },
  {
    "path": "src/main.rs",
    "content": "use dotenv::dotenv;\nuse raydium_pump_snipe_bot::{\n    common::{\n        logger::Logger,\n        utils::{\n            create_nonblocking_rpc_client, create_rpc_client, import_env_var, import_wallet,\n            AppState,\n        },\n    },\n    engine::monitor::{pumpfun_monitor, raydium_monitor},\n    services::jito,\n};\nuse solana_sdk::signer::Signer;\n\n#[tokio::main]\nasync fn main() {\n    let logger = Logger::new(\"[INIT] => \".to_string());\n\n    dotenv().ok();\n    let rpc_wss = import_env_var(\"RPC_WSS\");\n    let rpc_client = create_rpc_client().unwrap();\n    let rpc_nonblocking_client = create_nonblocking_rpc_client().await.unwrap();\n    let wallet = import_wallet().unwrap();\n    let wallet_cloned = wallet.clone();\n\n    let state = AppState {\n        rpc_client,\n        rpc_nonblocking_client,\n        wallet,\n    };\n    let slippage = import_env_var(\"SLIPPAGE\").parse::<u64>().unwrap_or(5);\n    let use_jito = true;\n    if use_jito {\n        jito::init_tip_accounts().await.unwrap();\n    }\n\n    logger.log(format!(\n        \"Successfully Set the environment variables.\\n\\t\\t\\t\\t [Web Socket RPC]: {},\\n\\t\\t\\t\\t [Wallet]: {:?},\\n\\t\\t\\t\\t [Slippage]: {}\\n\", \n        rpc_wss, wallet_cloned.pubkey(), slippage\n    ));\n    // raydium_monitor(&rpc_wss, state, slippage, use_jito).await;\n    pumpfun_monitor(&rpc_wss, state, slippage, use_jito).await;\n}\n"
  },
  {
    "path": "src/services/mod.rs",
    "content": "pub mod jito;\npub mod nextblock;\n"
  },
  {
    "path": "trial/blacklist.txt",
    "content": ""
  }
]