Compiling solana_rust_bot v0.1.0 (C:\solana_rust_bot)
warning: unused import: `warn`
 --> src\lib.rs:1:17
  |
1 | use log::{info, warn};
  |                 ^^^^
  |
  = note: `#[warn(unused_imports)]` on by default

error[E0277]: `FromBase58Error` doesn't implement `std::fmt::Display`
  --> src\lib.rs:63:83
   |
63 |             .map_err(|e| PyValueError::new_err(format!("Invalid private key: {}", e)))?;
   |                                                                                   ^ `FromBase58Error` cannot be formatted with the default formatter        
   |
   = help: the trait `std::fmt::Display` is not implemented for `FromBase58Error`
   = note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead
   = note: this error originates in the macro `$crate::__export::format_args` which comes from the expansion of the macro `format` (in Nightly builds, run with -Z macro-backtrace for more info)

error[E0599]: no method named `map_err` found for unit type `()` in the current scope
   --> src\lib.rs:252:18use log::{info, warn};
use pyo3::{exceptions::PyValueError, prelude::*};
use pyo3_asyncio::tokio::future_into_py;
use solana_client::nonblocking::rpc_client::RpcClient;
use solana_sdk::{
    commitment_config::{CommitmentConfig, CommitmentLevel},
    compute_budget::ComputeBudgetInstruction,
    instruction::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::{
    env,
    str::FromStr,
    sync::Arc,
    time::Duration,
};
use base58::FromBase58;

// Constants
const COMPUTE_UNITS: u32 = 200_000;
const PRIORITY_FEE: u64 = 1_000_000;
const CONFIRM_TIMEOUT: u64 = 30; // seconds

#[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 sell_all: bool,
    #[pyo3(get, set)]
    pub victim_data: Option<Vec<u8>>,
}

#[pyclass]
pub struct TradingCore {
    client: Arc<RpcClient>,
    keypair: Arc<Keypair>,
}

impl TradingCore {
    fn load_keypair_from_env() -> PyResult<Keypair> {
        let private_key = env::var("SOLANA_PRIVATE_KEY")
            .map_err(|_| PyValueError::new_err("SOLANA_PRIVATE_KEY not found"))?;
        
        let secret_key: Vec<u8> = private_key.from_base58()
            .map_err(|e| PyValueError::new_err(format!("Invalid private key: {}", e)))?;
        
        Keypair::from_bytes(&secret_key)
            .map_err(|e| PyValueError::new_err(format!("Keypair error: {}", e)))
    }

    async fn ensure_ata_exists(&self, mint: &Pubkey) -> PyResult<Pubkey> {
        let owner = self.keypair.pubkey();
        let ata = get_associated_token_address(&owner, mint);
        
        // Check if ATA exists
        if self.client.get_account(&ata).await.is_ok() {
            info!("ATA exists: {}", ata);
            return Ok(ata);
        }

        // Create ATA instruction
        let ix = create_associated_token_account_idempotent(
            &self.keypair.pubkey(),
            &owner,
            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.as_ref()], blockhash);

        // Send and confirm transaction
        let sig = self.client.send_transaction_with_config(
            &tx,
            solana_client::rpc_config::RpcSendTransactionConfig {
                skip_preflight: false,
                preflight_commitment: Some(CommitmentLevel::Confirmed),
                encoding: None,
                max_retries: Some(5),
                min_context_slot: None,
            },
        )
        .await
        .map_err(|e| PyValueError::new_err(format!("Send error: {}", e)))?;

        // Wait for confirmation
        let start = std::time::Instant::now();
        loop {
            let status = self.client.get_signature_status(&sig).await
                .map_err(|e| PyValueError::new_err(format!("Status error: {}", e)))?;
            
            if status.is_some() {
                info!("ATA created: {}", ata);
                return Ok(ata);
            }
            
            if start.elapsed().as_secs() > CONFIRM_TIMEOUT {
                return Err(PyValueError::new_err("ATA creation timeout"));
            }
            
            tokio::time::sleep(Duration::from_secs(1)).await;
        }
    }

    fn create_swap_instruction(
        &self,
        program_id: &Pubkey,
        accounts: &[Pubkey],
        amount: u64,
        is_buy: bool,
        source_ata: Pubkey,
        dest_ata: Pubkey,
        victim_data: Option<&[u8]>,
    ) -> Instruction {
        let mut data = vec![if is_buy { 9u8 } else { 11u8 }];
        if let Some(vdata) = victim_data {
            data.extend_from_slice(vdata);
        } else {
            data.extend_from_slice(&amount.to_le_bytes());
        }

        let mut metas = accounts.iter().map(|a| {
            solana_sdk::instruction::AccountMeta::new_readonly(*a, false)
        }).collect::<Vec<_>>();

        if is_buy {
            metas[15] = solana_sdk::instruction::AccountMeta::new(source_ata, false);
            metas[16] = solana_sdk::instruction::AccountMeta::new(dest_ata, false);
        } else {
            metas[15] = solana_sdk::instruction::AccountMeta::new(dest_ata, false);
            metas[16] = solana_sdk::instruction::AccountMeta::new(source_ata, false);
        }

        metas[17] = solana_sdk::instruction::AccountMeta::new(self.keypair.pubkey(), true);

        Instruction {
            program_id: *program_id,
            accounts: metas,
            data,
        }
    }
}

#[pymethods]
impl TradingCore {
    #[new]
    fn new(rpc_url: &str) -> PyResult<Self> {
        let keypair = Self::load_keypair_from_env()?;
        info!("Loaded keypair: {}", keypair.pubkey());
        
        Ok(Self {
            client: Arc::new(RpcClient::new_with_commitment(
                rpc_url.to_string(),
                CommitmentConfig::confirmed(),
            )),
            keypair: Arc::new(keypair),
        })
    }

    fn execute_trade_py<'py>(&self, params: &TradeParams, py: Python<'py>) -> PyResult<&'py PyAny> {
        let params = params.clone();
        let self_clone = Self {
            client: self.client.clone(),
            keypair: self.keypair.clone(),
        };
        
        future_into_py(py, async move {
            // Convert accounts
            let accounts = params.accounts.iter()
                .map(|a| Pubkey::from_str(a)
                    .map_err(|e| PyValueError::new_err(format!("Invalid account: {}", e))))
                .collect::<Result<Vec<_>, _>>()?;

            // Get token mints
            let token_a = Pubkey::from_str(&params.token_a_mint)
                .map_err(|e| PyValueError::new_err(format!("Invalid token A: {}", e)))?;
            let token_b = Pubkey::from_str(&params.token_b_mint)
                .map_err(|e| PyValueError::new_err(format!("Invalid token B: {}", e)))?;

            // Ensure ATAs exist
            let (source_mint, dest_mint) = if params.is_buy {
                (&token_b, &token_a)
            } else {
                (&token_a, &token_b)
            };
            
            let source_ata = self_clone.ensure_ata_exists(source_mint).await?;
            let dest_ata = self_clone.ensure_ata_exists(dest_mint).await?;

            // Prepare instructions
            let mut instructions = vec![
                ComputeBudgetInstruction::set_compute_unit_limit(COMPUTE_UNITS),
                ComputeBudgetInstruction::set_compute_unit_price(PRIORITY_FEE),
            ];

            let amount = if let Some(amt) = params.amount_in {
                amt
            } else if params.sell_all {
                let balance = self_clone.client.get_token_account_balance(&source_ata).await
                    .map_err(|e| PyValueError::new_err(format!("Balance error: {}", e)))?;
                balance.amount.parse::<u64>()
                    .map_err(|e| PyValueError::new_err(format!("Parse error: {}", e)))?
            } else {
                return Err(PyValueError::new_err("No amount specified"));
            };

            // Create swap instruction
            let swap_ix = self_clone.create_swap_instruction(
                &accounts[0],
                &accounts,
                amount,
                params.is_buy,
                source_ata,
                dest_ata,
                params.victim_data.as_deref(),
            );
            instructions.push(swap_ix);

            // Create and send transaction
            let blockhash = self_clone.client.get_latest_blockhash().await
                .map_err(|e| PyValueError::new_err(format!("Blockhash error: {}", e)))?;

            let msg = Message::new_with_blockhash(
                &instructions,
                Some(&self_clone.keypair.pubkey()),
                &blockhash,
            );

            let mut tx = Transaction::new_unsigned(msg);
            tx.sign(&[self_clone.keypair.as_ref()], blockhash)
                .map_err(|e| PyValueError::new_err(format!("Sign error: {:?}", e)))?;

            let sig = self_clone.client.send_transaction_with_config(
                &tx,
                solana_client::rpc_config::RpcSendTransactionConfig {
                    skip_preflight: false,
                    preflight_commitment: Some(CommitmentLevel::Confirmed),
                    encoding: None,
                    max_retries: Some(5),
                    min_context_slot: None,
                },
            )
            .await
            .map_err(|e| PyValueError::new_err(format!("Send error: {}", e)))?;

            // Confirm transaction
            self_clone.client.confirm_transaction_with_commitment(&sig, CommitmentConfig::confirmed())
                .await
                .map_err(|e| PyValueError::new_err(format!("Confirmation error: {}", e)))?;

            Ok(sig.to_string())
        })
    }

    #[pyo3(name = "get_sol_balance")]
    fn get_sol_balance_py<'py>(&self, py: Python<'py>) -> PyResult<&'py PyAny> {
        let self_clone = self.clone();
        
        future_into_py(py, async move {
            let balance = self_clone.client.get_balance(&self_clone.keypair.pubkey())
                .await
                .map_err(|e| PyValueError::new_err(format!("Failed to get SOL balance: {}", e)))?;
                
            Ok(balance as f64 / 1e9)  // Convert lamports to SOL
        })
    }

    #[pyo3(name = "get_wsol_balance")]
    fn get_wsol_balance_py<'py>(&self, py: Python<'py>) -> PyResult<&'py PyAny> {
        let self_clone = self.clone();
        
        future_into_py(py, async move {
            let wsol_account = env::var("WSOL_TOKEN_ACCOUNT")
                .map_err(|_| PyValueError::new_err("WSOL_TOKEN_ACCOUNT not found"))?;
                
            let pubkey = Pubkey::from_str(&wsol_account)
                .map_err(|e| PyValueError::new_err(format!("Invalid WSOL account: {}", e)))?;
                
            let balance = self_clone.client.get_token_account_balance(&pubkey)
                .await
                .map_err(|e| PyValueError::new_err(format!("Failed to get WSOL balance: {}", e)))?;
                
            let amount = balance.amount.parse::<u64>()
                .map_err(|e| PyValueError::new_err(format!("Invalid balance format: {}", e)))?;
                
            Ok(amount as f64 / 1e9)  // Convert lamports to SOL
        })
    }
}

#[pymodule]
fn solana_rust_bot(_py: Python<'_>, m: &PyModule) -> PyResult<()> {
    pyo3_log::init();
    m.add_class::<TradingCore>()?;
    m.add_class::<TradeParams>()?;
    Ok(())
} FIX FULL SCRIPT PLEASE
    |
251 | /             tx.sign(&[self_clone.keypair.as_ref()], blockhash)
252 | |                 .map_err(|e| PyValueError::new_err(format!("Sign error: {:?}", e)))?;
    | |                 -^^^^^^^ method not found in `()`
    | |_________________|
    |
    |
note: method `sign` modifies its receiver in-place
   --> src\lib.rs:251:16
    |
251 |             tx.sign(&[self_clone.keypair.as_ref()], blockhash)
    |                ^^^^ this call modifies `tx` in-place

error[E0521]: borrowed data escapes outside of method
   --> src\lib.rs:278:26
    |
277 |     fn get_sol_balance_py<'py>(&self, py: Python<'py>) -> PyResult<&'py PyAny> {
    |                                -----
    |                                |
    |                                `self` is a reference that is only valid in the method body
    |                                let's call the lifetime of this reference `'1`
278 |         let self_clone = self.clone();
    |                          ^^^^^^^^^^^^
    |                          |
    |                          `self` escapes the method body here
    |                          argument requires that `'1` must outlive `'static`

error[E0521]: borrowed data escapes outside of method
   --> src\lib.rs:291:26
    |
290 |     fn get_wsol_balance_py<'py>(&self, py: Python<'py>) -> PyResult<&'py PyAny> {
    |                                 -----
    |                                 |
    |                                 `self` is a reference that is only valid in the method body
    |                                 let's call the lifetime of this reference `'1`
291 |         let self_clone = self.clone();
    |                          ^^^^^^^^^^^^
    |                          |
    |                          `self` escapes the method body here
    |                          argument requires that `'1` must outlive `'static`

Some errors have detailed explanations: E0277, E0521, E0599.
For more information about an error, try `rustc --explain E0277`.
warning: `solana_rust_bot` (lib) generated 1 warning
error: could not compile `solana_rust_bot` (lib) due to 4 previous errors; 1 warning emitted
2025-02-11T18:00:49.611420Z  INFO build_wheels: maturin::build_context: close time.busy=792ms time.idle=1.00µs
💥 maturin failed
  Caused by: Failed to build a native library through cargo
  Caused by: Cargo build finished with "exit code: 101": `"cargo" "rustc" "--jobs" "16" "--message-format" "json-render-diagnostics" "--manifest-path" "C:\\solana_rust_bot\\Cargo.toml" "--release" "--lib" "--crate-type" "cdylib"`KEY_METRICS = {
    "base_supply": "SOL amount in pool",
    "quote_supply": "wSOL amount in pool",
    "volume_24h": "24-hour trading volume",
    "liquidity": "Total USD value locked",
    "price": "Current SOL/wSOL ratio",
    "last_update": "Unix timestamp of update"
}

# Byte positions in pool data
METRIC_POSITIONS = {
    "BASE_SUPPLY": [8, 16],    # SOL reserve
    "QUOTE_SUPPLY": [16, 24],  # wSOL reserve
    "VOLUME_24H": [112, 120],  # 24h volume
    "LIQUIDITY": [128, 136]    # Total liquidity
}

# Solana Trading Bot Keypair Implementation Guide

## Overview
When implementing a Solana trading bot that bridges Python and Rust components, the key to successful keypair handling lies in leveraging the native capabilities of the Rust layer rather than attempting complex keypair manipulation in Python. The solution involves a streamlined approach where configuration management happens in Python while delegating all cryptographic and keypair-specific operations to the Rust engine.

## Detailed Implementation Notes

### Configuration Structure
The trading bot relies on a config.json file that contains all necessary wallet information, including the wallet address, environment variable flags, and keypair paths. This configuration serves as the single source of truth for both Python and Rust components. The wallet configuration supports multiple authentication methods including environment variables and keypair files, allowing for flexible deployment scenarios.

### Keypair Handling
Instead of manually manipulating keypairs in Python (which led to issues with byte length validation and format conversion), we allow the Rust TradingEngine to handle all keypair-related operations. The Rust layer is specifically designed to work with Solana's cryptographic requirements and can properly handle the base58 encoding, byte length validation, and proper keypair formatting that Solana requires.

### Environment Variables
The system supports environment variable-based authentication using SOLANA_PRIVATE_KEY and SOLANA_PUBLIC_KEY. When these are set, the Rust engine automatically detects and uses them, removing the need for manual keypair file management. This is particularly useful in production environments where secure key management is critical.

### Best Practices & Lessons Learned
1. Configuration Management:
   - Keep all wallet and keypair configuration in one central config file
   - Use environment variables for sensitive data in production
   - Maintain clear separation between Python configuration management and Rust cryptographic operations

2. Error Prevention:
   - Avoid manual keypair manipulation in Python
   - Let the Rust engine handle all Solana-specific cryptographic operations
   - Use proper error handling and logging at both Python and Rust layers

3. Security Considerations:
   - Never hardcode private keys
   - Use environment variables or secure key stores in production
   - Implement proper cleanup procedures for any temporary files

### Example Implementation Workflow:
1. Configuration Setup:
```json
{
    "wallet": {
        "address": "YOUR_WALLET_ADDRESS",
        "use_env_key": true,
        "private_key": "",
        "keypair_path": "./id.json"
    }
}
```

2. Python Implementation:
```python
# Simple configuration loading
with open(config_path, 'r') as f:
    config = json.load(f)

# Direct initialization of trading engine
engine = TradingEngine(json.dumps(config))
```

### Troubleshooting Common Issues
- 32-byte length errors typically indicate manual keypair manipulation - let Rust handle it
- Base58 decoding issues are resolved by using the Rust layer's native handling
- Configuration path issues can be resolved by using absolute paths in config files

### Production Deployment Notes
When deploying to production, consider:
1. Using environment variables for key management
2. Implementing secure key rotation procedures
3. Setting up proper logging and monitoring
4. Using separate configurations for development and production

### System Architecture Implications
This solution promotes a clean separation of concerns:
- Python handles high-level business logic and trading strategies
- Rust manages low-level cryptographic operations and blockchain interactions
- Configuration serves as the clean interface between layers

### Performance Considerations
By delegating keypair operations to Rust, we achieve:
- Better performance due to Rust's native speed
- Reduced memory overhead from avoiding Python cryptographic operations
- More reliable operation through native Solana library usage

### Future Maintenance
When maintaining or upgrading the system:
1. Keep the configuration structure consistent
2. Update Rust dependencies for security patches
3. Maintain backward compatibility in configuration changes
4. Document any changes to environment variable requirements

This implementation approach significantly simplifies the system architecture while improving reliability and maintainability. By understanding and respecting the strengths of each layer (Python for high-level operations, Rust for cryptographic and blockchain interactions), we create a more robust and maintainable trading system.