Merge pull request #67 from HelvetiCrypt/feat/shared-infrastructure
Add shared_infrastructure example and update documentation
This commit is contained in:
@@ -17,6 +17,7 @@ readme = "README.md"
|
|||||||
[workspace]
|
[workspace]
|
||||||
members = [
|
members = [
|
||||||
"examples/trading_client",
|
"examples/trading_client",
|
||||||
|
"examples/shared_infrastructure",
|
||||||
"examples/middleware_system",
|
"examples/middleware_system",
|
||||||
"examples/pumpfun_copy_trading",
|
"examples/pumpfun_copy_trading",
|
||||||
"examples/pumpfun_sniper_trading",
|
"examples/pumpfun_sniper_trading",
|
||||||
|
|||||||
@@ -71,6 +71,7 @@
|
|||||||
8. **Concurrent Trading**: Send transactions using multiple MEV services simultaneously; the fastest succeeds while others fail
|
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
|
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
|
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
|
## 📦 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).
|
You can refer to [Example: Create TradingClient Instance](examples/trading_client/src/main.rs).
|
||||||
|
|
||||||
|
**Method 1: Simple (single wallet)**
|
||||||
```rust
|
```rust
|
||||||
// Wallet
|
// Wallet
|
||||||
let payer = Keypair::from_base58_string("use_your_payer_keypair_here");
|
let payer = Keypair::from_base58_string("use_your_payer_keypair_here");
|
||||||
@@ -116,27 +118,29 @@ let swqos_configs: Vec<SwqosConfig> = vec![
|
|||||||
SwqosConfig::Default(rpc_url.clone()),
|
SwqosConfig::Default(rpc_url.clone()),
|
||||||
SwqosConfig::Jito("your uuid".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::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
|
// Create TradeConfig instance
|
||||||
let trade_config = TradeConfig::new(rpc_url, swqos_configs, commitment);
|
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
|
// Create TradingClient
|
||||||
let client = TradingClient::new(Arc::new(payer), trade_config).await;
|
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
|
#### 2. Configure Gas Fee Strategy
|
||||||
|
|
||||||
For detailed information about Gas Fee Strategy, see the [Gas Fee Strategy Reference](docs/GAS_FEE_STRATEGY.md).
|
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 |
|
| 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) |
|
| 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 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) |
|
| 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) |
|
| 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) |
|
||||||
|
|||||||
@@ -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"] }
|
||||||
@@ -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<dyn std::error::Error>> {
|
||||||
|
// 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<SwqosConfig> = 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(())
|
||||||
|
}
|
||||||
@@ -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::{
|
use sol_trade_sdk::{
|
||||||
common::{AnyResult, TradeConfig},
|
common::{AnyResult, InfrastructureConfig, TradeConfig},
|
||||||
swqos::{SwqosConfig, SwqosRegion},
|
swqos::{SwqosConfig, SwqosRegion},
|
||||||
SolanaTrade,
|
TradingClient, TradingInfrastructure,
|
||||||
};
|
};
|
||||||
use solana_commitment_config::CommitmentConfig;
|
use solana_commitment_config::CommitmentConfig;
|
||||||
use solana_sdk::signature::Keypair;
|
use solana_sdk::signature::Keypair;
|
||||||
@@ -9,32 +18,75 @@ use std::sync::Arc;
|
|||||||
|
|
||||||
#[tokio::main]
|
#[tokio::main]
|
||||||
async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||||
let _ = create_solana_trade_client().await?;
|
// Method 1: Simple - TradingClient::new() (recommended for single wallet)
|
||||||
println!("Successfully created SolanaTrade client!");
|
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(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Create SolanaTrade client
|
/// Method 1: Create TradingClient using TradeConfig (simple, self-contained)
|
||||||
/// Initializes a new SolanaTrade client with configuration
|
///
|
||||||
async fn create_solana_trade_client() -> AnyResult<SolanaTrade> {
|
/// Use this when you have a single wallet or don't need to share infrastructure.
|
||||||
println!("Creating SolanaTrade client...");
|
async fn create_trading_client_simple() -> AnyResult<TradingClient> {
|
||||||
let payer = Keypair::from_base58_string("use_your_payer_keypair_here");
|
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 rpc_url = "https://mainnet.helius-rpc.com/?api-key=xxxxxx".to_string();
|
||||||
println!("rpc_url: {}", rpc_url);
|
|
||||||
let commitment = CommitmentConfig::processed();
|
let commitment = CommitmentConfig::processed();
|
||||||
|
|
||||||
let swqos_configs: Vec<SwqosConfig> = vec![
|
let swqos_configs: Vec<SwqosConfig> = vec![
|
||||||
SwqosConfig::Default(rpc_url.clone()),
|
SwqosConfig::Default(rpc_url.clone()),
|
||||||
SwqosConfig::Jito("your uuid".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::Bloxroute("your_api_token".to_string(), SwqosRegion::Frankfurt, None),
|
||||||
SwqosConfig::ZeroSlot("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::Temporal("your_api_token".to_string(), SwqosRegion::Frankfurt, None),
|
||||||
SwqosConfig::FlashBlock("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::Node1("your_api_token".to_string(), SwqosRegion::Frankfurt, None),
|
||||||
SwqosConfig::BlockRazor("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::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;
|
// Optional: Customize WSOL ATA and Seed optimization settings
|
||||||
println!("SolanaTrade client created successfully!");
|
let trade_config = TradeConfig::new(rpc_url, swqos_configs, commitment)
|
||||||
Ok(solana_trade_client)
|
.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<TradingClient> {
|
||||||
|
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<SwqosConfig> = 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)
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user