Skip to main content

solana_recover/
lib.rs

1//! # Solana Recover
2//!
3//! A high-performance Solana wallet scanner and SOL recovery library.
4//! 
5//! This library provides functionality to:
6//! - Scan Solana wallets for empty token accounts
7//! - Calculate recoverable SOL from empty accounts
8//! - Perform automated SOL recovery operations
9//! - Handle batch processing of multiple wallets
10//! - Provide connection pooling and caching for optimal performance
11//!
12//! ## Quick Start
13//!
14//! ```rust,no_run
15//! use solana_recover::{scan_wallet};
16//!
17//! #[tokio::main]
18//! async fn main() -> Result<(), Box<dyn std::error::Error>> {
19//!     let result = scan_wallet("9WzDXwBbmkg8ZTbNMqUxvQRAyrZzDsGYdLVL9zYtAWWM", None).await?;
20//!     
21//!     println!("Found {} recoverable SOL", result.recoverable_sol);
22//!     
23//!     Ok(())
24//! }
25//! ```
26//!
27//! ## Feature Flags
28//!
29//! - `default`: Enables `scanner` and `client` features
30//! - `scanner`: Core wallet scanning functionality
31//! - `client`: HTTP client for external APIs
32//! - `api`: REST API server functionality
33//! - `full`: Enables all features
34//! - `database`: Database persistence support
35//! - `cache`: Advanced caching capabilities
36//! - `metrics`: Prometheus metrics collection
37//! - `security`: Enhanced security features
38//! - `config`: Configuration file support
39
40#![cfg_attr(docsrs, feature(doc_cfg))]
41
42// Core dependencies
43use serde::{Deserialize, Serialize};
44use std::sync::Arc;
45
46// Export core modules
47pub mod core;
48pub mod rpc;
49pub mod storage;
50
51pub mod wallet;
52pub mod utils;
53pub mod config;
54pub mod api;
55
56// NFT module (when feature is enabled)
57#[cfg(feature = "nft")]
58pub mod nft;
59
60// Re-export commonly used types
61pub use core::*;
62
63/// Re-export NFT types when feature is enabled
64#[cfg(feature = "nft")]
65pub use nft::scanner::NftScanResult;
66#[cfg(feature = "nft")]
67pub use nft::types::NftInfo;
68
69/// Unified scan result containing both SOL and NFT information
70#[derive(Debug, Clone, Serialize, Deserialize)]
71pub struct UnifiedScanResult {
72    /// SOL wallet information
73    pub sol_info: Option<WalletInfo>,
74    /// NFT scan information
75    #[cfg(feature = "nft")]
76    pub nft_info: Option<NftScanResult>,
77    /// Scan mode used
78    pub scan_mode: ScanMode,
79    /// Total scan duration in milliseconds
80    pub total_scan_time_ms: u64,
81    /// Wallet address scanned
82    pub wallet_address: String,
83}
84
85/// Scan modes for different types of scanning
86#[derive(Debug, Clone, Serialize, Deserialize)]
87pub enum ScanMode {
88    /// Scan SOL accounts only
89    SolOnly,
90    /// Scan NFT accounts only
91    NftOnly,
92    /// Scan both SOL and NFT accounts
93    Both,
94}
95
96/// Library version
97pub const VERSION: &str = env!("CARGO_PKG_VERSION");
98
99/// Default RPC endpoint for mainnet
100pub const DEFAULT_MAINNET_ENDPOINT: &str = "https://api.mainnet-beta.solana.com";
101
102/// Default RPC endpoint for devnet
103pub const DEFAULT_DEVNET_ENDPOINT: &str = "https://api.devnet.solana.com";
104
105/// Represents an empty token account
106#[derive(Debug, Clone, Serialize, Deserialize)]
107pub struct EmptyAccount {
108    /// The account address
109    pub address: String,
110    /// The mint address of token
111    pub mint: String,
112    /// The owner address
113    pub owner: String,
114    /// Balance in lamports (recoverable amount after rent exemption)
115    pub lamports: u64,
116}
117
118/// Ultra-fast unified wallet scanning with SOL and NFT support
119/// 
120/// This function provides the fastest possible wallet scanning using:
121/// - Predictive prefetching
122/// - Connection multiplexing
123/// - Smart batching
124/// - Fast path scanning for common patterns
125/// - Maximum parallelization
126/// - Unified SOL and NFT scanning
127/// 
128/// # Arguments
129/// 
130/// * `wallet_address` - The Solana wallet address to scan
131/// * `rpc_endpoint` - Optional RPC endpoint (defaults to mainnet)
132/// * `scan_mode` - Scan mode: sol, nft, or both
133/// 
134/// # Returns
135/// 
136/// Returns a `UnifiedScanResult` containing both SOL and NFT scan results.
137/// 
138/// # Example
139/// 
140/// ```rust,no_run
141/// use solana_recover::{scan_wallet_unified, ScanMode};
142/// 
143/// #[tokio::main]
144/// async fn main() -> Result<(), Box<dyn std::error::Error>> {
145///     let result = scan_wallet_unified("9WzDXwBbmkg8ZTbNMqUxvQRAyrZzDsGYdLVL9zYtAWWM", None, ScanMode::Both).await?;
146///     if let Some(sol_info) = &result.sol_info {
147///         println!("Found {} recoverable SOL", sol_info.recoverable_sol);
148///     }
149///     if let Some(nft_info) = &result.nft_info {
150///         println!("Found {} NFTs", nft_info.nfts.len());
151///     }
152///     Ok(())
153/// }
154/// ```
155#[cfg(feature = "nft")]
156pub async fn scan_wallet_unified(
157    wallet_address: &str,
158    rpc_endpoint: Option<&str>,
159    scan_mode: ScanMode,
160) -> core::Result<UnifiedScanResult> {
161    use core::ScannerFactory;
162    use core::unified_scanner::UnifiedScannerConfig;
163    use core::unified_scanner::PerformanceMode;
164    use core::types::RpcEndpoint;
165    use rpc::ConnectionPool;
166    use nft::scanner::{NftScanner, NftScannerConfig};
167    use std::sync::Arc;
168    
169    let start_time = std::time::Instant::now();
170    let endpoint = rpc_endpoint.unwrap_or(DEFAULT_MAINNET_ENDPOINT);
171    let rpc_endpoint = RpcEndpoint {
172        url: endpoint.to_string(),
173        priority: 0,
174        rate_limit_rps: 200, // Higher rate limit for ultra-fast
175        timeout_ms: 5000,     // Shorter timeout for ultra-fast
176        healthy: true,
177    };
178    
179    let connection_pool = Arc::new(ConnectionPool::new(vec![rpc_endpoint], 16));
180    
181    // Initialize results
182    let mut sol_info = None;
183    let mut nft_info = None;
184    
185    // Scan SOL accounts if requested
186    if matches!(scan_mode, ScanMode::SolOnly | ScanMode::Both) {
187        let config = UnifiedScannerConfig {
188            performance_mode: PerformanceMode::UltraFast,
189            max_concurrent_scans: 500,
190            scan_timeout: std::time::Duration::from_secs(2),
191            batch_size: 100,
192            enable_optimizations: true,
193            enable_caching: true,
194            enable_parallel_processing: true,
195        };
196        
197        let scanner = ScannerFactory::create_with_config(connection_pool.clone(), config)?;
198        let scan_result = scanner.scan_wallet(wallet_address).await?;
199        sol_info = scan_result.result;
200    }
201    
202    // Scan NFT accounts if requested
203    if matches!(scan_mode, ScanMode::NftOnly | ScanMode::Both) {
204        let nft_config = NftScannerConfig {
205            performance_mode: nft::types::PerformanceMode::UltraFast,
206            max_concurrent_scans: 50,
207            scan_timeout_seconds: 60,
208            enable_batch_processing: true,
209            ..Default::default()
210        };
211        
212        let nft_scanner = NftScanner::new(connection_pool.clone(), nft_config)?;
213        nft_info = Some(nft_scanner.scan_wallet_nfts(wallet_address).await?);
214    }
215    
216    let total_scan_time_ms = start_time.elapsed().as_millis() as u64;
217    
218    #[cfg(feature = "nft")]
219    {
220        Ok(UnifiedScanResult {
221            sol_info,
222            nft_info,
223            scan_mode,
224            total_scan_time_ms,
225            wallet_address: wallet_address.to_string(),
226        })
227    }
228    #[cfg(not(feature = "nft"))]
229    {
230        Ok(UnifiedScanResult {
231            sol_info,
232            scan_mode,
233            total_scan_time_ms,
234            wallet_address: wallet_address.to_string(),
235        })
236    }
237}
238
239/// Calculate total claimable assets for multiple wallets with unified scanning
240#[cfg(feature = "nft")]
241pub async fn calculate_total_claimable_unified(
242    targets: &str,
243    rpc_endpoint: Option<&str>,
244    dev: bool,
245    scan_mode: ScanMode,
246) -> core::Result<UnifiedTotalClaimResult> {
247    let (wallets, _is_private_key) = parse_targets_wrapper(targets)?;
248    
249    let mut total_recoverable_sol = 0.0;
250    let mut total_nfts = 0usize;
251    let mut total_nft_value = 0u64;
252    let mut wallet_results = Vec::new();
253    
254    for wallet_address in wallets {
255        let scan_result = scan_wallet_unified(&wallet_address, rpc_endpoint, scan_mode.clone()).await?;
256        
257        if let Some(sol_info) = &scan_result.sol_info {
258            total_recoverable_sol += sol_info.recoverable_sol;
259        }
260        
261        if let Some(nft_info) = &scan_result.nft_info {
262            total_nfts += nft_info.nfts.len();
263            total_nft_value += nft_info.total_estimated_value_lamports;
264        }
265        
266        if dev {
267            wallet_results.push((wallet_address, scan_result));
268        }
269    }
270    
271    Ok(UnifiedTotalClaimResult {
272        total_wallets: wallet_results.len(),
273        total_recoverable_sol,
274        total_nfts,
275        total_nft_value_lamports: total_nft_value,
276        wallet_results,
277        scan_mode,
278    })
279}
280
281/// Parse targets string into wallet addresses
282/// Wrapper function to parse targets in the same format as the CLI
283pub fn parse_targets_wrapper(targets: &str) -> core::Result<(Vec<String>, bool)> {
284    if targets.starts_with("wallet:") {
285        let addresses = targets.strip_prefix("wallet:")
286            .unwrap()
287            .split(',')
288            .map(|s| s.trim().to_string())
289            .filter(|s| !s.is_empty())
290            .collect();
291        Ok((addresses, false))
292    } else if targets.starts_with("key:") {
293        // For private keys, we would need to derive addresses
294        // This is a placeholder - in a real implementation, you'd parse the private keys
295        // and derive the corresponding wallet addresses
296        Err(core::SolanaRecoverError::InternalError("Private key parsing not implemented in unified scanner".to_string()))
297    } else {
298        // Assume it's a single wallet address
299        Ok((vec![targets.trim().to_string()], false))
300    }
301}
302
303/// Unified total claim result containing both SOL and NFT information
304#[derive(Debug, Clone, Serialize, Deserialize)]
305pub struct UnifiedTotalClaimResult {
306    /// Total wallets scanned
307    pub total_wallets: usize,
308    /// Total recoverable SOL
309    pub total_recoverable_sol: f64,
310    /// Total NFTs found
311    pub total_nfts: usize,
312    /// Total NFT value in lamports
313    pub total_nft_value_lamports: u64,
314    /// Individual wallet results (only included if dev mode is enabled)
315    pub wallet_results: Vec<(String, UnifiedScanResult)>,
316    /// Scan mode used
317    pub scan_mode: ScanMode,
318}
319/// 
320/// This function provides the fastest possible wallet scanning using:
321/// - Predictive prefetching
322/// - Connection multiplexing
323/// - Smart batching
324/// - Fast path scanning for common patterns
325/// - Maximum parallelization
326/// 
327/// # Arguments
328/// 
329/// * `wallet_address` - The Solana wallet address to scan
330/// * `rpc_endpoint` - Optional RPC endpoint (defaults to mainnet)
331/// 
332/// # Returns
333/// 
334/// Returns a `WalletInfo` containing scan results in sub-second time.
335/// 
336/// # Example
337/// 
338/// ```rust,no_run
339/// use solana_recover::scan_wallet_ultra_fast;
340/// 
341/// #[tokio::main]
342/// async fn main() -> Result<(), Box<dyn std::error::Error>> {
343///     let result = scan_wallet_ultra_fast("9WzDXwBbmkg8ZTbNMqUxvQRAyrZzDsGYdLVL9zYtAWWM", None).await?;
344///     println!("Found {} recoverable SOL in {}ms", result.recoverable_sol, result.scan_time_ms);
345///     Ok(())
346/// }
347/// ```
348pub async fn scan_wallet_ultra_fast(
349    wallet_address: &str,
350    rpc_endpoint: Option<&str>,
351) -> core::Result<WalletInfo> {
352    use core::ScannerFactory;
353    use core::unified_scanner::UnifiedScannerConfig;
354    use core::unified_scanner::PerformanceMode;
355    use core::types::RpcEndpoint;
356    use rpc::ConnectionPool;
357    use std::sync::Arc;
358    
359    let endpoint = rpc_endpoint.unwrap_or(DEFAULT_MAINNET_ENDPOINT);
360    let rpc_endpoint = RpcEndpoint {
361        url: endpoint.to_string(),
362        priority: 0,
363        rate_limit_rps: 200, // Higher rate limit for ultra-fast
364        timeout_ms: 5000,     // Shorter timeout for ultra-fast
365        healthy: true,
366    };
367    
368    let connection_pool = Arc::new(ConnectionPool::new(vec![rpc_endpoint], 16));
369    
370    // Ultra-fast configuration using new unified architecture
371    let config = UnifiedScannerConfig {
372        performance_mode: PerformanceMode::UltraFast,
373        max_concurrent_scans: 500,
374        scan_timeout: std::time::Duration::from_secs(2),
375        batch_size: 100,
376        enable_optimizations: true,
377        enable_caching: true,
378        enable_parallel_processing: true,
379    };
380    
381    let scanner = ScannerFactory::create_with_config(connection_pool, config)?;
382    let scan_result = scanner.scan_wallet(wallet_address).await?;
383    
384    scan_result.result.ok_or_else(|| 
385        SolanaRecoverError::InternalError("Scan result is empty".to_string())
386    )
387}
388
389/// Convenience function for quick wallet scanning using the unified scanner
390/// 
391/// This is the simplest way to scan a wallet for empty accounts using the new
392/// unified architecture with strategy pattern.
393/// 
394/// # Arguments
395/// 
396/// * `wallet_address` - The Solana wallet address to scan
397/// * `rpc_endpoint` - Optional RPC endpoint (defaults to mainnet)
398/// 
399/// # Returns
400/// 
401/// Returns a `WalletInfo` containing scan results.
402/// 
403/// # Example
404/// 
405/// ```rust,no_run
406/// use solana_recover::scan_wallet;
407/// 
408/// #[tokio::main]
409/// async fn main() -> Result<(), Box<dyn std::error::Error>> {
410///     let result = scan_wallet("9WzDXwBbmkg8ZTbNMqUxvQRAyrZzDsGYdLVL9zYtAWWM", None).await?;
411///     println!("Found {} recoverable SOL", result.recoverable_sol);
412///     Ok(())
413/// }
414/// ```
415pub async fn scan_wallet(
416    wallet_address: &str,
417    rpc_endpoint: Option<&str>,
418) -> core::Result<WalletInfo> {
419    use core::ScannerFactory;
420    use core::types::RpcEndpoint;
421    use rpc::ConnectionPool;
422    use std::sync::Arc;
423    
424    let endpoint = rpc_endpoint.unwrap_or(DEFAULT_MAINNET_ENDPOINT);
425    let rpc_endpoint = RpcEndpoint {
426        url: endpoint.to_string(),
427        priority: 0,
428        rate_limit_rps: 100,
429        timeout_ms: 30000,
430        healthy: true,
431    };
432    
433    let connection_pool = Arc::new(ConnectionPool::new(vec![rpc_endpoint], 8));
434    
435    // Use balanced mode for general scanning
436    let scanner = ScannerFactory::create_balanced(connection_pool)?;
437    let scan_result = scanner.scan_wallet(wallet_address).await?;
438    
439    scan_result.result.ok_or_else(|| 
440        SolanaRecoverError::InternalError("Scan result is empty".to_string())
441    )
442}
443
444/// Convenience function for SOL recovery using the core recovery manager
445/// 
446/// This is the simplest way to recover SOL from empty accounts.
447/// 
448/// # Arguments
449/// 
450/// * `request` - The recovery request containing wallet and destination info
451/// * `rpc_endpoint` - Optional RPC endpoint (defaults to mainnet)
452/// * `wallet_manager` - Optional shared wallet manager instance
453/// 
454/// # Returns
455/// 
456/// Returns a `RecoveryResult` containing recovery operation results.
457/// 
458/// # Example
459/// 
460/// ```rust,no_run
461/// use solana_recover::{recover_sol, RecoveryRequest, wallet::WalletManager};
462/// 
463/// #[tokio::main]
464/// async fn main() -> Result<(), Box<dyn std::error::Error>> {
465///     let wallet_manager = std::sync::Arc::new(WalletManager::new());
466///     let request = RecoveryRequest {
467///         // ... populate request fields
468///         id: uuid::Uuid::new_v4(),
469///         wallet_address: "9WzDXwBbmkg8ZTbNMqUxvQRAyrZzDsGYdLVL9zYtAWWM".to_string(),
470///         destination_address: "destination_address_here".to_string(),
471///         empty_accounts: vec![],
472///         max_fee_lamports: Some(10_000_000),
473///         priority_fee_lamports: None,
474///         wallet_connection_id: None,
475///         user_id: None,
476///         created_at: chrono::Utc::now(),
477///     };
478///     
479///     let result = recover_sol(&request, None, Some(wallet_manager)).await?;
480///     println!("Recovered {} SOL", result.net_sol);
481///     Ok(())
482/// }
483/// ```
484pub async fn recover_sol(
485    request: &RecoveryRequest,
486    rpc_endpoint: Option<&str>,
487    wallet_manager: Option<std::sync::Arc<wallet::WalletManager>>,
488) -> core::Result<RecoveryResult> {
489    use rpc::ConnectionPool;
490    use core::{RpcEndpoint, RecoveryManager, RecoveryConfig};
491    use wallet::WalletManager;
492    
493    let endpoint = rpc_endpoint.unwrap_or(DEFAULT_MAINNET_ENDPOINT);
494    let rpc_endpoint = RpcEndpoint {
495        url: endpoint.to_string(),
496        priority: 0,
497        rate_limit_rps: 100,
498        timeout_ms: 30000,
499        healthy: true,
500    };
501    let connection_pool = Arc::new(ConnectionPool::new(vec![rpc_endpoint], 8));
502    
503    let config = RecoveryConfig::default();
504    let fee_structure = core::FeeStructure::default(); // Can be customized
505    let wallet_manager = wallet_manager.unwrap_or_else(|| Arc::new(WalletManager::new()));
506    let recovery_manager = RecoveryManager::new(connection_pool, wallet_manager, config, fee_structure);
507    
508    recovery_manager.recover_sol(request).await
509}
510
511/// Convenience function for ultra-fast NFT scanning
512/// 
513/// This function provides the fastest possible NFT scanning using:
514/// - Ultra-fast performance mode
515/// - Maximum parallelization
516/// - Optimized caching
517/// - Minimal validation
518/// 
519/// # Arguments
520/// 
521/// * `wallet_address` - The Solana wallet address to scan for NFTs
522/// * `rpc_endpoint` - Optional RPC endpoint (defaults to mainnet)
523/// 
524/// # Returns
525/// 
526/// Returns an `NftScanResult` containing comprehensive NFT analysis.
527/// 
528/// # Example
529/// 
530/// ```rust,no_run
531/// use solana_recover::scan_wallet_nfts_ultra_fast;
532/// 
533/// #[tokio::main]
534/// async fn main() -> Result<(), Box<dyn std::error::Error>> {
535///     let result = scan_wallet_nfts_ultra_fast("9WzDXwBbmkg8ZTbNMqUxvQRAyrZzDsGYdLVL9zYtAWWM", None).await?;
536///     println!("Found {} NFTs with total value {} SOL", 
537///         result.nfts.len(), result.total_estimated_value_lamports as f64 / 1_000_000_000.0);
538///     Ok(())
539/// }
540/// ```
541#[cfg(feature = "nft")]
542pub async fn scan_wallet_nfts_ultra_fast(
543    wallet_address: &str,
544    rpc_endpoint: Option<&str>,
545) -> core::Result<NftScanResult> {
546    use nft::scanner::create_ultra_fast_nft_scanner;
547    use core::types::RpcEndpoint;
548    use rpc::ConnectionPool;
549    use std::sync::Arc;
550    
551    let endpoint = rpc_endpoint.unwrap_or(DEFAULT_MAINNET_ENDPOINT);
552    let rpc_endpoint = RpcEndpoint {
553        url: endpoint.to_string(),
554        priority: 0,
555        rate_limit_rps: 200, // Higher rate limit for ultra-fast
556        timeout_ms: 5000,     // Shorter timeout for ultra-fast
557        healthy: true,
558    };
559    
560    let connection_pool = Arc::new(ConnectionPool::new(vec![rpc_endpoint], 16));
561    let scanner = create_ultra_fast_nft_scanner(connection_pool)?;
562    
563    let scan_result = scanner.scan_wallet_nfts(wallet_address).await?;
564    
565    Ok(scan_result)
566}
567
568/// Convenience function for balanced NFT scanning
569/// 
570/// This function provides balanced NFT scanning with comprehensive analysis
571/// including metadata, valuation, security validation, and portfolio analysis.
572/// 
573/// # Arguments
574/// 
575/// * `wallet_address` - The Solana wallet address to scan for NFTs
576/// * `rpc_endpoint` - Optional RPC endpoint (defaults to mainnet)
577/// 
578/// # Returns
579/// 
580/// Returns an `NftScanResult` containing comprehensive NFT analysis.
581/// 
582/// # Example
583/// 
584/// ```rust,no_run
585/// use solana_recover::scan_wallet_nfts;
586/// 
587/// #[tokio::main]
588/// async fn main() -> Result<(), Box<dyn std::error::Error>> {
589///     let result = scan_wallet_nfts("9WzDXwBbmkg8ZTbNMqUxvQRAyrZzDsGYdLVL9zYtAWWM", None).await?;
590///     println!("Found {} NFTs with {} security issues", 
591///         result.nfts.len(), result.security_issues.len());
592///     Ok(())
593/// }
594/// ```
595#[cfg(feature = "nft")]
596pub async fn scan_wallet_nfts(
597    wallet_address: &str,
598    rpc_endpoint: Option<&str>,
599) -> core::Result<NftScanResult> {
600    use nft::scanner::create_nft_scanner;
601    use core::types::RpcEndpoint;
602    use rpc::ConnectionPool;
603    use std::sync::Arc;
604    
605    let endpoint = rpc_endpoint.unwrap_or(DEFAULT_MAINNET_ENDPOINT);
606    let rpc_endpoint = RpcEndpoint {
607        url: endpoint.to_string(),
608        priority: 0,
609        rate_limit_rps: 100,
610        timeout_ms: 30000,
611        healthy: true,
612    };
613    
614    let connection_pool = Arc::new(ConnectionPool::new(vec![rpc_endpoint], 8));
615    let scanner = create_nft_scanner(connection_pool)?;
616    
617    let scan_result = scanner.scan_wallet_nfts(wallet_address).await?;
618    
619    Ok(scan_result)
620}
621
622/// Convenience function for thorough NFT scanning
623/// 
624/// This function provides thorough NFT scanning with maximum validation
625/// and comprehensive security analysis.
626/// 
627/// # Arguments
628/// 
629/// * `wallet_address` - The Solana wallet address to scan for NFTs
630/// * `rpc_endpoint` - Optional RPC endpoint (defaults to mainnet)
631/// 
632/// # Returns
633/// 
634/// Returns an `NftScanResult` containing thorough NFT analysis.
635/// 
636/// # Example
637/// 
638/// ```rust,no_run
639/// use solana_recover::scan_wallet_nfts_thorough;
640/// 
641/// #[tokio::main]
642/// async fn main() -> Result<(), Box<dyn std::error::Error>> {
643///     let result = scan_wallet_nfts_thorough("9WzDXwBbmkg8ZTbNMqUxvQRAyrZzDsGYdLVL9zYtAWWM", None).await?;
644///     println!("Thorough scan completed with {} insights", 
645///         result.portfolio.as_ref().map(|p| p.quality_metrics.diversity_score).unwrap_or(0.0));
646///     Ok(())
647/// }
648/// ```
649#[cfg(feature = "nft")]
650pub async fn scan_wallet_nfts_thorough(
651    wallet_address: &str,
652    rpc_endpoint: Option<&str>,
653) -> core::Result<NftScanResult> {
654    use nft::scanner::create_thorough_nft_scanner;
655    use core::types::RpcEndpoint;
656    use rpc::ConnectionPool;
657    use std::sync::Arc;
658    
659    let endpoint = rpc_endpoint.unwrap_or(DEFAULT_MAINNET_ENDPOINT);
660    let rpc_endpoint = RpcEndpoint {
661        url: endpoint.to_string(),
662        priority: 0,
663        rate_limit_rps: 50, // Lower rate limit for thorough scanning
664        timeout_ms: 60000,   // Longer timeout for thorough scanning
665        healthy: true,
666    };
667    
668    let connection_pool = Arc::new(ConnectionPool::new(vec![rpc_endpoint], 4));
669    let scanner = create_thorough_nft_scanner(connection_pool)?;
670    
671    let scan_result = scanner.scan_wallet_nfts(wallet_address).await?;
672    
673    Ok(scan_result)
674}
675
676/// Convenience function for batch NFT scanning
677/// 
678/// This function scans multiple wallets in parallel with optimized performance.
679/// 
680/// # Arguments
681/// 
682/// * `wallet_addresses` - Vector of Solana wallet addresses to scan
683/// * `rpc_endpoint` - Optional RPC endpoint (defaults to mainnet)
684/// 
685/// # Returns
686/// 
687/// Returns a vector of `NftScanResult` for each wallet.
688/// 
689/// # Example
690/// 
691/// ```rust,no_run
692/// use solana_recover::scan_wallets_nfts_batch;
693/// 
694/// #[tokio::main]
695/// async fn main() -> Result<(), Box<dyn std::error::Error>> {
696///     let wallets = vec![
697///         "9WzDXwBbmkg8ZTbNMqUxvQRAyrZzDsGYdLVL9zYtAWWM".to_string(),
698///         "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v".to_string(),
699///     ];
700///     let results = scan_wallets_nfts_batch(&wallets, None).await?;
701///     for result in results {
702///         println!("Wallet {}: {} NFTs", result.wallet_address, result.nfts.len());
703///     }
704///     Ok(())
705/// }
706/// ```
707#[cfg(feature = "nft")]
708pub async fn scan_wallets_nfts_batch(
709    wallet_addresses: &[String],
710    rpc_endpoint: Option<&str>,
711) -> core::Result<Vec<NftScanResult>> {
712    use nft::scanner::create_nft_scanner;
713    use core::types::RpcEndpoint;
714    use rpc::ConnectionPool;
715    use std::sync::Arc;
716    
717    let endpoint = rpc_endpoint.unwrap_or(DEFAULT_MAINNET_ENDPOINT);
718    let rpc_endpoint = RpcEndpoint {
719        url: endpoint.to_string(),
720        priority: 0,
721        rate_limit_rps: 100,
722        timeout_ms: 30000,
723        healthy: true,
724    };
725    
726    let connection_pool = Arc::new(ConnectionPool::new(vec![rpc_endpoint], 8));
727    let scanner = create_nft_scanner(connection_pool)?;
728    
729    let scan_results = scanner.scan_wallets_batch(wallet_addresses).await?;
730    
731    Ok(scan_results)
732}
733
734/// Convenience function for NFT metadata fetching only
735/// 
736/// This function fetches NFT metadata without valuation or security analysis.
737/// 
738/// # Arguments
739/// 
740/// * `mint_address` - The NFT mint address
741/// * `rpc_endpoint` - Optional RPC endpoint (defaults to mainnet)
742/// 
743/// # Returns
744/// 
745/// Returns an `NftInfo` containing the NFT metadata.
746/// 
747/// # Example
748/// 
749/// ```rust,no_run
750/// use solana_recover::fetch_nft_metadata;
751/// 
752/// #[tokio::main]
753/// async fn main() -> Result<(), Box<dyn std::error::Error>> {
754///     let nft_info = fetch_nft_metadata("mint_address_here", None).await?;
755///     println!("NFT Name: {:?}", nft_info.name);
756///     println!("NFT Symbol: {:?}", nft_info.symbol);
757///     Ok(())
758/// }
759/// ```
760#[cfg(feature = "nft")]
761pub async fn fetch_nft_metadata(
762    mint_address: &str,
763    rpc_endpoint: Option<&str>,
764) -> core::Result<NftInfo> {
765    use nft::scanner::create_nft_scanner;
766    use nft::cache::CacheManager;
767    use nft::metadata::MetadataFetcher;
768    use nft::metadata::MetadataConfig;
769    use core::types::RpcEndpoint;
770    use rpc::ConnectionPool;
771    use std::sync::Arc;
772    
773    let endpoint = rpc_endpoint.unwrap_or(DEFAULT_MAINNET_ENDPOINT);
774    let rpc_endpoint = RpcEndpoint {
775        url: endpoint.to_string(),
776        priority: 0,
777        rate_limit_rps: 100,
778        timeout_ms: 30000,
779        healthy: true,
780    };
781    
782    let connection_pool = Arc::new(ConnectionPool::new(vec![rpc_endpoint], 8));
783    let cache_manager = Arc::new(CacheManager::new(Default::default()));
784    let metadata_config = MetadataConfig::default();
785    
786    let metadata_fetcher = Arc::new(MetadataFetcher::new(
787        connection_pool,
788        metadata_config,
789        cache_manager,
790    )?);
791    
792    let nft_info = metadata_fetcher.fetch_nft_metadata(mint_address).await?;
793    
794    Ok(nft_info)
795}
796
797#[cfg(test)]
798mod tests {
799    use super::*;
800
801    #[test]
802    fn test_version() {
803        assert!(!VERSION.is_empty());
804    }
805
806    #[test]
807    fn test_default_endpoints() {
808        assert_eq!(DEFAULT_MAINNET_ENDPOINT, "https://api.mainnet-beta.solana.com");
809        assert_eq!(DEFAULT_DEVNET_ENDPOINT, "https://api.devnet.solana.com");
810    }
811}