diff --git a/Cargo.toml b/Cargo.toml index 665d688..bd8c5ec 100755 --- a/Cargo.toml +++ b/Cargo.toml @@ -17,6 +17,7 @@ readme = "README.md" [workspace] members = [ "examples/trading_client", + "examples/shared_infrastructure", "examples/middleware_system", "examples/pumpfun_copy_trading", "examples/pumpfun_sniper_trading", diff --git a/README.md b/README.md index 8d93d4c..8b18c72 100644 --- a/README.md +++ b/README.md @@ -71,6 +71,7 @@ 8. **Concurrent Trading**: Send transactions using multiple MEV services simultaneously; the fastest succeeds while others fail 9. **Unified Trading Interface**: Use unified trading protocol enums for trading operations 10. **Middleware System**: Support for custom instruction middleware to modify, add, or remove instructions before transaction execution +11. **Shared Infrastructure**: Share expensive RPC and SWQOS clients across multiple wallets for reduced resource usage ## 📦 Installation @@ -105,6 +106,7 @@ sol-trade-sdk = "3.3.6" You can refer to [Example: Create TradingClient Instance](examples/trading_client/src/main.rs). +**Method 1: Simple (single wallet)** ```rust // Wallet let payer = Keypair::from_base58_string("use_your_payer_keypair_here"); @@ -116,27 +118,29 @@ let swqos_configs: Vec = vec![ SwqosConfig::Default(rpc_url.clone()), SwqosConfig::Jito("your uuid".to_string(), SwqosRegion::Frankfurt, None), SwqosConfig::Bloxroute("your api_token".to_string(), SwqosRegion::Frankfurt, None), - SwqosConfig::ZeroSlot("your api_token".to_string(), SwqosRegion::Frankfurt, None), - SwqosConfig::Temporal("your api_token".to_string(), SwqosRegion::Frankfurt, None), - SwqosConfig::FlashBlock("your api_token".to_string(), SwqosRegion::Frankfurt, None), - SwqosConfig::Node1("your api_token".to_string(), SwqosRegion::Frankfurt, None), - SwqosConfig::BlockRazor("your api_token".to_string(), SwqosRegion::Frankfurt, None), - SwqosConfig::Astralane("your api_token".to_string(), SwqosRegion::Frankfurt, None), ]; // Create TradeConfig instance let trade_config = TradeConfig::new(rpc_url, swqos_configs, commitment); -// Optional: Customize WSOL ATA and Seed optimization settings -// let trade_config = TradeConfig::new(rpc_url, swqos_configs, commitment) -// .with_wsol_ata_config( -// true, // create_wsol_ata_on_startup: Check and create WSOL ATA on startup (default: true) -// true // use_seed_optimize: Enable seed optimization globally for all ATA operations (default: true) -// ); - // Create TradingClient let client = TradingClient::new(Arc::new(payer), trade_config).await; ``` +**Method 2: Shared infrastructure (multiple wallets)** + +For multi-wallet scenarios, create the infrastructure once and share it across wallets. +See [Example: Shared Infrastructure](examples/shared_infrastructure/src/main.rs). + +```rust +// Create infrastructure once (expensive) +let infra_config = InfrastructureConfig::new(rpc_url, swqos_configs, commitment); +let infrastructure = Arc::new(TradingInfrastructure::new(infra_config).await); + +// Create multiple clients sharing the same infrastructure (fast) +let client1 = TradingClient::from_infrastructure(Arc::new(payer1), infrastructure.clone(), true); +let client2 = TradingClient::from_infrastructure(Arc::new(payer2), infrastructure.clone(), true); +``` + #### 2. Configure Gas Fee Strategy For detailed information about Gas Fee Strategy, see the [Gas Fee Strategy Reference](docs/GAS_FEE_STRATEGY.md). @@ -197,6 +201,7 @@ Please ensure that the parameters your trading logic depends on are available in | Description | Run Command | Source Code | |-------------|-------------|-------------| | Create and configure TradingClient instance | `cargo run --package trading_client` | [examples/trading_client](https://github.com/0xfnzero/sol-trade-sdk/tree/main/examples/trading_client/src/main.rs) | +| Share infrastructure across multiple wallets | `cargo run --package shared_infrastructure` | [examples/shared_infrastructure](https://github.com/0xfnzero/sol-trade-sdk/tree/main/examples/shared_infrastructure/src/main.rs) | | PumpFun token sniping trading | `cargo run --package pumpfun_sniper_trading` | [examples/pumpfun_sniper_trading](https://github.com/0xfnzero/sol-trade-sdk/tree/main/examples/pumpfun_sniper_trading/src/main.rs) | | PumpFun token copy trading | `cargo run --package pumpfun_copy_trading` | [examples/pumpfun_copy_trading](https://github.com/0xfnzero/sol-trade-sdk/tree/main/examples/pumpfun_copy_trading/src/main.rs) | | PumpSwap trading operations | `cargo run --package pumpswap_trading` | [examples/pumpswap_trading](https://github.com/0xfnzero/sol-trade-sdk/tree/main/examples/pumpswap_trading/src/main.rs) | diff --git a/examples/shared_infrastructure/Cargo.toml b/examples/shared_infrastructure/Cargo.toml new file mode 100644 index 0000000..867beac --- /dev/null +++ b/examples/shared_infrastructure/Cargo.toml @@ -0,0 +1,10 @@ +[package] +name = "shared_infrastructure" +version = "0.1.0" +edition = "2021" + +[dependencies] +sol-trade-sdk = { path = "../.." } +solana-sdk = "3.0.0" +solana-commitment-config = { version = "3.0.0", features = ["serde"] } +tokio = { version = "1", features = ["full"] } diff --git a/examples/shared_infrastructure/src/main.rs b/examples/shared_infrastructure/src/main.rs new file mode 100644 index 0000000..3368f5b --- /dev/null +++ b/examples/shared_infrastructure/src/main.rs @@ -0,0 +1,72 @@ +//! Shared Infrastructure Example +//! +//! This example demonstrates how to share expensive infrastructure (RPC client, SWQOS clients) +//! across multiple wallets, significantly reducing resource usage and initialization time. +//! +//! Use this pattern when: +//! - Running a trading service with multiple wallets +//! - All wallets use the same RPC endpoint and SWQOS configuration +//! - You want to minimize memory usage and connection overhead +//! +//! Benefits: +//! - First wallet: Full async initialization (~200-500ms) +//! - Additional wallets: Fast sync initialization (~1-2ms) +//! - Shared RPC connection pool and SWQOS clients + +use sol_trade_sdk::{ + common::InfrastructureConfig, + swqos::{SwqosConfig, SwqosRegion}, + TradingClient, TradingInfrastructure, +}; +use solana_commitment_config::CommitmentConfig; +use solana_sdk::signature::Keypair; +use std::sync::Arc; + +#[tokio::main] +async fn main() -> Result<(), Box> { + // Configuration (same for all wallets) + let rpc_url = "https://mainnet.helius-rpc.com/?api-key=xxxxxx".to_string(); + let commitment = CommitmentConfig::processed(); + let swqos_configs: Vec = vec![ + SwqosConfig::Default(rpc_url.clone()), + SwqosConfig::Jito("your_uuid".to_string(), SwqosRegion::Frankfurt, None), + SwqosConfig::Bloxroute("your_api_token".to_string(), SwqosRegion::Frankfurt, None), + ]; + + // Step 1: Create shared infrastructure (expensive, do once) + println!("Creating shared infrastructure..."); + let infra_config = InfrastructureConfig::new(rpc_url, swqos_configs, commitment); + let infrastructure = Arc::new(TradingInfrastructure::new(infra_config).await); + println!("Infrastructure created with {} SWQOS clients", infrastructure.swqos_clients.len()); + + // Step 2: Create multiple TradingClients sharing the same infrastructure (fast) + let wallet_keys = vec![ + "wallet1_base58_private_key_here", + "wallet2_base58_private_key_here", + "wallet3_base58_private_key_here", + ]; + + let mut clients = Vec::new(); + for (i, key) in wallet_keys.iter().enumerate() { + println!("Creating client for wallet {}...", i + 1); + let payer = Arc::new(Keypair::from_base58_string(key)); + + // Fast: reuses existing infrastructure + let client = TradingClient::from_infrastructure( + payer, + infrastructure.clone(), + true, // use_seed_optimize + ); + clients.push(client); + println!(" Client {} created (shares infrastructure)", i + 1); + } + + println!("\nCreated {} clients sharing 1 infrastructure instance", clients.len()); + println!(" - 1 RPC client (shared)"); + println!(" - {} SWQOS clients (shared)", infrastructure.swqos_clients.len()); + + // All clients can now trade concurrently using shared resources + // Example: clients[0].buy(buy_params).await?; + + Ok(()) +} diff --git a/examples/trading_client/src/main.rs b/examples/trading_client/src/main.rs index 8939846..4105a2a 100644 --- a/examples/trading_client/src/main.rs +++ b/examples/trading_client/src/main.rs @@ -1,7 +1,16 @@ +//! TradingClient Creation Example +//! +//! This example demonstrates two ways to create a TradingClient: +//! +//! 1. Simple method: `TradingClient::new()` - creates client with its own infrastructure +//! 2. Shared method: `TradingClient::from_infrastructure()` - reuses existing infrastructure +//! +//! For multi-wallet scenarios, see the `shared_infrastructure` example. + use sol_trade_sdk::{ - common::{AnyResult, TradeConfig}, + common::{AnyResult, InfrastructureConfig, TradeConfig}, swqos::{SwqosConfig, SwqosRegion}, - SolanaTrade, + TradingClient, TradingInfrastructure, }; use solana_commitment_config::CommitmentConfig; use solana_sdk::signature::Keypair; @@ -9,32 +18,75 @@ use std::sync::Arc; #[tokio::main] async fn main() -> Result<(), Box> { - let _ = create_solana_trade_client().await?; - println!("Successfully created SolanaTrade client!"); + // Method 1: Simple - TradingClient::new() (recommended for single wallet) + let client = create_trading_client_simple().await?; + println!("Method 1: Created TradingClient with new()"); + println!(" Wallet: {}", client.get_payer_pubkey()); + + // Method 2: From infrastructure (recommended for multiple wallets) + let client2 = create_trading_client_from_infrastructure().await?; + println!("\nMethod 2: Created TradingClient with from_infrastructure()"); + println!(" Wallet: {}", client2.get_payer_pubkey()); + Ok(()) } -/// Create SolanaTrade client -/// Initializes a new SolanaTrade client with configuration -async fn create_solana_trade_client() -> AnyResult { - println!("Creating SolanaTrade client..."); +/// Method 1: Create TradingClient using TradeConfig (simple, self-contained) +/// +/// Use this when you have a single wallet or don't need to share infrastructure. +async fn create_trading_client_simple() -> AnyResult { let payer = Keypair::from_base58_string("use_your_payer_keypair_here"); let rpc_url = "https://mainnet.helius-rpc.com/?api-key=xxxxxx".to_string(); - println!("rpc_url: {}", rpc_url); let commitment = CommitmentConfig::processed(); + let swqos_configs: Vec = vec![ SwqosConfig::Default(rpc_url.clone()), - SwqosConfig::Jito("your uuid".to_string(), SwqosRegion::Frankfurt, None), - SwqosConfig::Bloxroute("your api_token".to_string(), SwqosRegion::Frankfurt, None), - SwqosConfig::ZeroSlot("your api_token".to_string(), SwqosRegion::Frankfurt, None), - SwqosConfig::Temporal("your api_token".to_string(), SwqosRegion::Frankfurt, None), - SwqosConfig::FlashBlock("your api_token".to_string(), SwqosRegion::Frankfurt, None), - SwqosConfig::Node1("your api_token".to_string(), SwqosRegion::Frankfurt, None), - SwqosConfig::BlockRazor("your api_token".to_string(), SwqosRegion::Frankfurt, None), - SwqosConfig::Astralane("your api_token".to_string(), SwqosRegion::Frankfurt, None), + SwqosConfig::Jito("your_uuid".to_string(), SwqosRegion::Frankfurt, None), + SwqosConfig::Bloxroute("your_api_token".to_string(), SwqosRegion::Frankfurt, None), + SwqosConfig::ZeroSlot("your_api_token".to_string(), SwqosRegion::Frankfurt, None), + SwqosConfig::Temporal("your_api_token".to_string(), SwqosRegion::Frankfurt, None), + SwqosConfig::FlashBlock("your_api_token".to_string(), SwqosRegion::Frankfurt, None), + SwqosConfig::Node1("your_api_token".to_string(), SwqosRegion::Frankfurt, None), + SwqosConfig::BlockRazor("your_api_token".to_string(), SwqosRegion::Frankfurt, None), + SwqosConfig::Astralane("your_api_token".to_string(), SwqosRegion::Frankfurt, None), ]; - let trade_config = TradeConfig::new(rpc_url, swqos_configs, commitment); - let solana_trade_client = SolanaTrade::new(Arc::new(payer), trade_config).await; - println!("SolanaTrade client created successfully!"); - Ok(solana_trade_client) + + // Optional: Customize WSOL ATA and Seed optimization settings + let trade_config = TradeConfig::new(rpc_url, swqos_configs, commitment) + .with_wsol_ata_config( + true, // create_wsol_ata_on_startup: Check and create WSOL ATA on startup + true, // use_seed_optimize: Enable seed optimization for all ATA operations + ); + + // Creates new infrastructure internally + let client = TradingClient::new(Arc::new(payer), trade_config).await; + Ok(client) +} + +/// Method 2: Create TradingClient from shared infrastructure +/// +/// Use this when you have multiple wallets sharing the same configuration. +/// The infrastructure (RPC client, SWQOS clients) is created once and shared. +async fn create_trading_client_from_infrastructure() -> AnyResult { + let payer = Keypair::from_base58_string("use_your_payer_keypair_here"); + let rpc_url = "https://mainnet.helius-rpc.com/?api-key=xxxxxx".to_string(); + let commitment = CommitmentConfig::processed(); + + let swqos_configs: Vec = vec![ + SwqosConfig::Default(rpc_url.clone()), + SwqosConfig::Jito("your_uuid".to_string(), SwqosRegion::Frankfurt, None), + ]; + + // Create infrastructure separately (can be shared across multiple wallets) + let infra_config = InfrastructureConfig::new(rpc_url, swqos_configs, commitment); + let infrastructure = Arc::new(TradingInfrastructure::new(infra_config).await); + + // Create client from existing infrastructure (fast, no async needed) + let client = TradingClient::from_infrastructure( + Arc::new(payer), + infrastructure, + true, // use_seed_optimize + ); + + Ok(client) }