refactor: Refactor SDK core architecture and trading parameter system

- Refactor SolanaTrade main class structure with improved modular design
- Refactor trading parameter system: BuyParams/SellParams -> InternalBuyParams/InternalSellParams
- Remove deprecated PriorityFee and related utility functions
- Add SwqosSettings to replace legacy SwqosConfig
- Add comprehensive technical documentation:
  • Address Lookup Table usage guide (EN/CN)
  • Nonce Cache mechanism documentation (EN/CN)
  • Trading Parameters documentation (EN/CN)
- Refactor all example code to adapt to new API interfaces
- Optimize public API design and code comments
- Clean up redundant utility functions and type definitions

Impact: 43 files changed, 2013 insertions(+), 1735 deletions(-)
This commit is contained in:
ysq
2025-09-17 00:10:33 +08:00
parent 943c2627f3
commit c5ff7c1cbb
43 changed files with 2010 additions and 1732 deletions
+1 -1
View File
@@ -1,6 +1,6 @@
[package]
name = "sol-trade-sdk"
version = "0.6.15"
version = "1.0.0"
edition = "2021"
authors = [
"William <byteblock6@gmail.com>",
+88 -152
View File
@@ -44,15 +44,14 @@
- [✨ Features](#-features)
- [📦 Installation](#-installation)
- [🛠️ Usage Examples](#-usage-examples)
- [📋 Important Parameter Description](#-important-parameter-description)
- [📋 Example Usage](#-example-usage)
- [⚡ Trading Parameters](#-trading-parameters)
- [📊 Usage Examples Summary Table](#-usage-examples-summary-table)
- [⚙️ SWQOS Service Configuration](#-swqos-service-configuration)
- [🔧 Middleware System](#-middleware-system)
- [⚡ Custom Priority Fee Configuration](#-custom-priority-fee-configuration)
- [🏪 Supported Trading Platforms](#-supported-trading-platforms)
- [🔍 Address Lookup Tables](#-address-lookup-tables)
- [🔍 Nonce Cache](#-nonce-cache)
- [🛡️ MEV Protection Services](#-mev-protection-services)
- [💰 Price Calculation Utilities](#-price-calculation-utilities)
- [🧮 Amount Calculation Utilities](#-amount-calculation-utilities)
- [📁 Project Structure](#-project-structure)
- [📄 License](#-license)
- [💬 Contact](#-contact)
@@ -67,13 +66,11 @@
3. **Bonk Trading**: Support for Bonk trading operations
4. **Raydium CPMM Trading**: Support for Raydium CPMM (Concentrated Pool Market Maker) trading operations
5. **Raydium AMM V4 Trading**: Support for Raydium AMM V4 (Automated Market Maker) trading operations
6. **Event Subscription**: Subscribe to PumpFun, PumpSwap, Bonk, Raydium CPMM, and Raydium AMM V4 program trading events
7. **Yellowstone gRPC**: Subscribe to program events using Yellowstone gRPC
8. **ShredStream Support**: Subscribe to program events using ShredStream
9. **Multiple MEV Protection**: Support for Jito, Nextblock, ZeroSlot, Temporal, Bloxroute, FlashBlock, BlockRazor, Node1, Astralane and other services
10. **Concurrent Trading**: Send transactions using multiple MEV services simultaneously; the fastest succeeds while others fail
11. **Unified Trading Interface**: Use unified trading protocol enums for trading operations
12. **Middleware System**: Support for custom instruction middleware to modify, add, or remove instructions before transaction execution
6. **Event Subscription**: SDK integrates solana-streamer SDK, supports subscribing to PumpFun, PumpSwap, Bonk, Raydium CPMM, and Raydium AMM V4 program trading events, the description of this SDK can be found in [solana-streamer SDK](https://github.com/0xfnzero/solana-streamer).
7. **Multiple MEV Protection**: Support for Jito, Nextblock, ZeroSlot, Temporal, Bloxroute, FlashBlock, BlockRazor, Node1, Astralane and other services
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
## 📦 Installation
@@ -90,74 +87,78 @@ Add the dependency to your `Cargo.toml`:
```toml
# Add to your Cargo.toml
sol-trade-sdk = { path = "./sol-trade-sdk", version = "0.6.15" }
sol-trade-sdk = { path = "./sol-trade-sdk", version = "1.0.0" }
```
### Use crates.io
```toml
# Add to your Cargo.toml
sol-trade-sdk = "0.6.15"
sol-trade-sdk = "1.0.0"
```
## 🛠️ Usage Examples
### 📋 Important Parameter Description
### 📋 Example Usage
#### 🌱 open_seed_optimize Parameter
#### 1. Create SolanaTrade Instance
`open_seed_optimize` is used to specify whether to use seed optimization to reduce transaction CU consumption.
You can refer to [Example: Create SolanaTrade Instance](examples/trading_client/src/main.rs).
- **Purpose**: When `open_seed_optimize: true`, the SDK uses createAccountWithSeed optimization to create token ata accounts during transactions.
- **Note**: Transactions created with `open_seed_optimize` enabled must be sold through this SDK. Using official methods to sell may fail.
- **Note**: After enabling `open_seed_optimize`, you need to use the `get_associated_token_address_with_program_id_fast_use_seed` method to get the token ata address.
```rust
// Wallet
let payer = Keypair::from_base58_string("use_your_payer_keypair_here");
// RPC URL
let rpc_url = "https://mainnet.helius-rpc.com/?api-key=xxxxxx".to_string();
let commitment = CommitmentConfig::processed();
// Transaction CU and fee settings
let cu_limit = DEFAULT_CU_LIMIT;
let cu_price = DEFAULT_CU_PRICE;
let buy_tip_fee = DEFAULT_BUY_TIP_FEE;
let sell_tip_fee = DEFAULT_SELL_TIP_FEE;
// SWQOS service configuration
let swqos_settings: Vec<SwqosSettings> = vec![
SwqosSettings::new(SwqosConfig::Default(rpc_url.clone()), cu_limit, cu_price, 0.0, 0.0),
// First parameter is UUID, pass empty string if no UUID
SwqosSettings::new(SwqosConfig::Jito("your uuid".to_string(), SwqosRegion::Frankfurt, None), cu_limit, cu_price, buy_tip_fee, sell_tip_fee),
// ....other service configurations...
];
// Create SolanaTrade instance
let client =
SolanaTrade::new(Arc::new(payer), rpc_url, commitment, swqos_settings).await;
```
#### 💰 create_wsol_ata and close_wsol_ata、 create_mint_ata Parameters
#### 2. Build Trading Parameters
In PumpSwap, Bonk, and Raydium trading, the `create_wsol_ata` and `close_wsol_ata``create_mint_ata` parameters provide fine-grained control over wSOL (Wrapped SOL) account management:
For detailed information about all trading parameters, see the [Trading Parameters Reference](docs/TRADING_PARAMETERS.md).
- **create_wsol_ata**:
- When `create_wsol_ata: true`, the SDK automatically creates and wraps SOL to wSOL before trading
- When buying: automatically wraps SOL to wSOL for trading
```rust
let buy_params = sol_trade_sdk::TradeBuyParams {
dex_type: DexType::PumpSwap,
mint: mint_pubkey,
sol_amount: buy_sol_amount,
slippage_basis_points: slippage_basis_points,
recent_blockhash: recent_blockhash,
extension_params: Box::new(params.clone()),
custom_cu_limit: None,
lookup_table_key: None,
wait_transaction_confirmed: true,
create_wsol_ata: true,
close_wsol_ata: true,
create_mint_ata: true,
open_seed_optimize: false,
};
```
- **close_wsol_ata**:
- When `close_wsol_ata: true`, the SDK automatically closes the wSOL account and unwraps to SOL after trading
- When selling: automatically unwraps the received wSOL to SOL and reclaims rent
#### 3. Execute Trading
- **create_mint_ata**:
- When `create_mint_ata: true`, the SDK automatically creates the token ata account before trading
```rust
client.buy(buy_params).await?;
```
- **Benefits of Separate Parameters**:
- Allows independent control of wSOL account creation and closure
- Useful for batch operations where you want to create once and close after multiple transactions
- Provides flexibility for advanced trading strategies
### ⚡ Trading Parameters
#### 🔍 lookup_table_key Parameter
The `lookup_table_key` parameter is an optional `Pubkey` that specifies an address lookup table for transaction optimization. You need to use `AddressLookupTableCache` to manage the cached address lookup table before using it.
- **Purpose**: Address lookup tables can reduce transaction size and improve execution speed by storing frequently used addresses
- **Usage**:
- Can be overridden per transaction in `buy()` and `sell()` methods
- If not provided, defaults to `None`
- **Benefits**:
- Reduces transaction size by referencing addresses from lookup tables
- Improves transaction success rate and speed
- Particularly useful for complex transactions with many account references
#### ⚡ priority_fee Parameter
The `priority_fee` parameter is an optional `PriorityFee` that allows you to override the default priority fee settings for individual transactions:
- **Purpose**: Provides fine-grained control over transaction priority fees on a per-transaction basis
- **Usage**:
- Can be passed to `buy()` and `sell()` methods to override the global priority fee settings
- If not provided, defaults to `None` and uses the priority fee settings from `TradeConfig`
- When provided, the `buy_tip_fees` array will be automatically padded to match the number of SWQOS clients
- **Benefits**:
- Allows dynamic adjustment of priority fees based on market conditions
- Enables different fee strategies for different types of transactions
- Provides flexibility for high-frequency trading scenarios
For comprehensive information about all trading parameters including `TradeBuyParams` and `TradeSellParams`, see the dedicated [Trading Parameters Reference](docs/TRADING_PARAMETERS.md).
#### About ShredStream
@@ -166,22 +167,22 @@ Please ensure that the parameters your trading logic depends on are available in
### 📊 Usage Examples Summary Table
| Feature Type | Package Name | Description | Run Command | Source Code |
|-------------|--------------|-------------|-------------|-------------|
| Event Subscription | `event_subscription` | Monitor token trading events | `cargo run --package event_subscription` | [examples/event_subscription](https://github.com/0xfnzero/sol-trade-sdk/tree/main/examples/event_subscription/src/main.rs) |
| Trading Client | `trading_client` | Create and configure SolanaTrade instance | `cargo run --package trading_client` | [examples/trading_client](https://github.com/0xfnzero/sol-trade-sdk/tree/main/examples/trading_client/src/main.rs) |
| PumpFun Sniping | `pumpfun_sniper_trading` | 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 Copy Trading | `pumpfun_copy_trading` | 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 | `pumpswap_trading` | 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) |
| Raydium CPMM | `raydium_cpmm_trading` | Raydium CPMM trading operations | `cargo run --package raydium_cpmm_trading` | [examples/raydium_cpmm_trading](https://github.com/0xfnzero/sol-trade-sdk/tree/main/examples/raydium_cpmm_trading/src/main.rs) |
| Raydium AMM V4 | `raydium_amm_v4_trading` | Raydium AMM V4 trading operations | `cargo run --package raydium_amm_v4_trading` | [examples/raydium_amm_v4_trading](https://github.com/0xfnzero/sol-trade-sdk/tree/main/examples/raydium_amm_v4_trading/src/main.rs) |
| Bonk Sniping | `bonk_sniper_trading` | Bonk token sniping trading | `cargo run --package bonk_sniper_trading` | [examples/bonk_sniper_trading](https://github.com/0xfnzero/sol-trade-sdk/tree/main/examples/bonk_sniper_trading/src/main.rs) |
| Bonk Copy Trading | `bonk_copy_trading` | Bonk token copy trading | `cargo run --package bonk_copy_trading` | [examples/bonk_copy_trading](https://github.com/0xfnzero/sol-trade-sdk/tree/main/examples/bonk_copy_trading/src/main.rs) |
| Middleware System | `middleware_system` | Custom instruction middleware example | `cargo run --package middleware_system` | [examples/middleware_system](https://github.com/0xfnzero/sol-trade-sdk/tree/main/examples/middleware_system/src/main.rs) |
| Address Lookup | `address_lookup` | Address lookup table example | `cargo run --package address_lookup` | [examples/address_lookup](https://github.com/0xfnzero/sol-trade-sdk/tree/main/examples/address_lookup/src/main.rs) |
| Nonce | `nonce_cache` | Nonce example | `cargo run --package nonce_cache` | [examples/nonce_cache](https://github.com/0xfnzero/sol-trade-sdk/tree/main/examples/nonce_cache/src/main.rs) |
| WSOL Wrapper | `wsol_wrapper` | Wrap/unwrap SOL to/from WSOL example | `cargo run --package wsol_wrapper` | [examples/wsol_wrapper](https://github.com/0xfnzero/sol-trade-sdk/tree/main/examples/wsol_wrapper/src/main.rs) |
| Seed Trading | `seed_trading` | Seed trading example | `cargo run --package seed_trading` | [examples/seed_trading](https://github.com/0xfnzero/sol-trade-sdk/tree/main/examples/seed_trading/src/main.rs) |
| Description | Run Command | Source Code |
|-------------|-------------|-------------|
| Monitor token trading events | `cargo run --package event_subscription` | [examples/event_subscription](https://github.com/0xfnzero/sol-trade-sdk/tree/main/examples/event_subscription/src/main.rs) |
| Create and configure SolanaTrade instance | `cargo run --package trading_client` | [examples/trading_client](https://github.com/0xfnzero/sol-trade-sdk/tree/main/examples/trading_client/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) |
| Raydium CPMM trading operations | `cargo run --package raydium_cpmm_trading` | [examples/raydium_cpmm_trading](https://github.com/0xfnzero/sol-trade-sdk/tree/main/examples/raydium_cpmm_trading/src/main.rs) |
| Raydium AMM V4 trading operations | `cargo run --package raydium_amm_v4_trading` | [examples/raydium_amm_v4_trading](https://github.com/0xfnzero/sol-trade-sdk/tree/main/examples/raydium_amm_v4_trading/src/main.rs) |
| Bonk token sniping trading | `cargo run --package bonk_sniper_trading` | [examples/bonk_sniper_trading](https://github.com/0xfnzero/sol-trade-sdk/tree/main/examples/bonk_sniper_trading/src/main.rs) |
| Bonk token copy trading | `cargo run --package bonk_copy_trading` | [examples/bonk_copy_trading](https://github.com/0xfnzero/sol-trade-sdk/tree/main/examples/bonk_copy_trading/src/main.rs) |
| Custom instruction middleware example | `cargo run --package middleware_system` | [examples/middleware_system](https://github.com/0xfnzero/sol-trade-sdk/tree/main/examples/middleware_system/src/main.rs) |
| Address lookup table example | `cargo run --package address_lookup` | [examples/address_lookup](https://github.com/0xfnzero/sol-trade-sdk/tree/main/examples/address_lookup/src/main.rs) |
| Nonce example | `cargo run --package nonce_cache` | [examples/nonce_cache](https://github.com/0xfnzero/sol-trade-sdk/tree/main/examples/nonce_cache/src/main.rs) |
| Wrap/unwrap SOL to/from WSOL example | `cargo run --package wsol_wrapper` | [examples/wsol_wrapper](https://github.com/0xfnzero/sol-trade-sdk/tree/main/examples/wsol_wrapper/src/main.rs) |
| Seed trading example | `cargo run --package seed_trading` | [examples/seed_trading](https://github.com/0xfnzero/sol-trade-sdk/tree/main/examples/seed_trading/src/main.rs) |
### ⚙️ SWQOS Service Configuration
@@ -230,41 +231,18 @@ let middleware_manager = MiddlewareManager::new()
.add_middleware(Box::new(ThirdMiddleware)); // Executes last
```
### ⚡ Custom Priority Fee Configuration
### 🔍 Address Lookup Tables
```rust
use sol_trade_sdk::common::PriorityFee;
Address Lookup Tables (ALT) allow you to optimize transaction size and reduce fees by storing frequently used addresses in a compact table format. For detailed information, see the [Address Lookup Tables Guide](docs/ADDRESS_LOOKUP_TABLE.md).
// Custom priority fee configuration
let priority_fee = PriorityFee {
tip_unit_limit: 190000,
tip_unit_price: 1000000,
rpc_unit_limit: 500000,
rpc_unit_price: 500000,
buy_tip_fee: 0.001,
buy_tip_fees: vec![0.001, 0.002],
sell_tip_fee: 0.0001,
};
### 🔍 Nonce Cache
// Use custom priority fee in TradeConfig
let trade_config = TradeConfig {
rpc_url: rpc_url.clone(),
commitment: CommitmentConfig::confirmed(),
priority_fee, // Use custom priority fee
swqos_configs,
};
```
## 🏪 Supported Trading Platforms
- **PumpFun**: Primary meme coin trading platform
- **PumpSwap**: PumpFun's swap protocol
- **Bonk**: Token launch platform (letsbonk.fun)
- **Raydium CPMM**: Raydium's Concentrated Pool Market Maker protocol
- **Raydium AMM V4**: Raydium's Automated Market Maker V4 protocol
Use Nonce Cache to implement transaction replay protection and optimize transaction processing. For detailed information, see the [Nonce Cache Guide](docs/NONCE_CACHE.md).
## 🛡️ MEV Protection Services
You can apply for a key through the official website: [Community Website](https://fnzero.dev/swqos)
- **Jito**: High-performance block space
- **NextBlock**: Fast transaction execution
- **ZeroSlot**: Zero-latency transactions
@@ -275,28 +253,6 @@ let trade_config = TradeConfig {
- **Node1**: High-speed transaction execution with API key authentication - [Official Documentation](https://node1.me/docs.html)
- **Astralane**: Blockchain network acceleration
## 💰 Price Calculation Utilities
The SDK includes price calculation utilities for all supported protocols in `src/utils/price/`.
## 🧮 Amount Calculation Utilities
The SDK provides trading amount calculation functionality for various protocols, located in `src/utils/calc/`:
- **Common Calculation Functions**: Provides general fee calculation and division utilities
- **Protocol-Specific Calculations**: Specialized calculation logic for each protocol
- **PumpFun**: Token buy/sell amount calculations based on bonding curves
- **PumpSwap**: Amount calculations for multiple trading pairs
- **Raydium AMM V4**: Amount and fee calculations for automated market maker pools
- **Raydium CPMM**: Amount calculations for constant product market makers
- **Bonk**: Specialized calculation logic for Bonk tokens
Key features include:
- Calculate output amounts based on input amounts
- Fee calculation and distribution
- Slippage protection calculations
- Liquidity pool state calculations
## 📁 Project Structure
```
@@ -304,38 +260,18 @@ src/
├── common/ # Common functionality and tools
├── constants/ # Constant definitions
├── instruction/ # Instruction building
│ └── utils/ # Instruction utilities
├── protos/ # gRPC protocol definitions
├── swqos/ # MEV service clients
├── trading/ # Unified trading engine
│ ├── common/ # Common trading tools
│ ├── core/ # Core trading engine
│ ├── middleware/ # Middleware system
│ │ ├── builtin.rs # Built-in middleware implementations
│ │ ├── traits.rs # Middleware trait definitions
│ │ └── mod.rs # Middleware module
│ ├── bonk/ # Bonk trading implementation
│ ├── pumpfun/ # PumpFun trading implementation
│ ├── pumpswap/ # PumpSwap trading implementation
│ ├── raydium_cpmm/ # Raydium CPMM trading implementation
│ ├── raydium_amm_v4/ # Raydium AMM V4 trading implementation
│ └── factory.rs # Trading factory
├── utils/ # Utility functions
│ ├── price/ # Price calculation utilities
│ ├── common.rs # Common price functions
│ │ ├── bonk.rs # Bonk price calculations
│ │ ├── pumpfun.rs # PumpFun price calculations
│ │ ├── pumpswap.rs # PumpSwap price calculations
│ │ ├── raydium_cpmm.rs # Raydium CPMM price calculations
│ │ ├── raydium_clmm.rs # Raydium CLMM price calculations
│ │ └── raydium_amm_v4.rs # Raydium AMM V4 price calculations
│ └── calc/ # Amount calculation utilities
│ ├── common.rs # Common calculation functions
│ ├── bonk.rs # Bonk amount calculations
│ ├── pumpfun.rs # PumpFun amount calculations
│ ├── pumpswap.rs # PumpSwap amount calculations
│ ├── raydium_cpmm.rs # Raydium CPMM amount calculations
│ └── raydium_amm_v4.rs # Raydium AMM V4 amount calculations
├── lib.rs # Main library file
└── main.rs # Example program
│ ├── calc/ # Amount calculation utilities
└── price/ # Price calculation utilities
└── lib.rs # Main library file
```
## 📄 License
+92 -155
View File
@@ -35,7 +35,8 @@
<a href="https://github.com/0xfnzero/sol-trade-sdk/blob/main/README_CN.md">中文</a> |
<a href="https://github.com/0xfnzero/sol-trade-sdk/blob/main/README.md">English</a> |
<a href="https://fnzero.dev/">Website</a> |
<a href="https://t.me/fnzero_group">Telegram</a>
<a href="https://t.me/fnzero_group">Telegram</a> |
<a href="https://discord.gg/vuazbGkqQE">Discord</a>
</p>
## 📋 目录
@@ -43,15 +44,14 @@
- [✨ 项目特性](#-项目特性)
- [📦 安装](#-安装)
- [🛠️ 使用示例](#-使用示例)
- [📋 重要说明](#-重要说明)
- [📋 使用示例](#-使用示例)
- [⚡ 交易参数](#-交易参数)
- [📊 使用示例汇总表格](#-使用示例汇总表格)
- [⚙️ SWQOS 服务配置说明](#-swqos-服务配置说明)
- [🔧 中间件系统说明](#-中间件系统说明)
- [⚡ 自定义优先费用配置](#-自定义优先费用配置)
- [🏪 支持的交易平台](#-支持的交易平台)
- [🔍 地址查找表](#-地址查找表)
- [🔍 Nonce 缓存](#-nonce-缓存)
- [🛡️ MEV 保护服务](#-mev-保护服务)
- [💰 价格计算工具](#-价格计算工具)
- [🧮 数量计算工具](#-数量计算工具)
- [📁 项目结构](#-项目结构)
- [📄 许可证](#-许可证)
- [💬 联系方式](#-联系方式)
@@ -66,13 +66,11 @@
3. **Bonk 交易**: 支持 Bonk 的交易操作
4. **Raydium CPMM 交易**: 支持 Raydium CPMM (Concentrated Pool Market Maker) 的交易操作
5. **Raydium AMM V4 交易**: 支持 Raydium AMM V4 (Automated Market Maker) 的交易操作
6. **事件订阅**: 订阅 PumpFun、PumpSwap、Bonk、Raydium CPMM 和 Raydium AMM V4 程序的交易事件
7. **Yellowstone gRPC**: 使用 Yellowstone gRPC 订阅程序事件
8. **ShredStream 支持**: 使用 ShredStream 订阅程序事件
9. **多种 MEV 保护**: 支持 Jito、Nextblock、ZeroSlot、Temporal、Bloxroute、FlashBlock、BlockRazor、Node1、Astralane 等服务
10. **并发交易**: 同时使用多个 MEV 服务发送交易,最快的成功,其他失败
11. **统一交易接口**: 使用统一的交易协议枚举进行交易操作
12. **中间件系统**: 支持自定义指令中间件,可在交易执行前对指令进行修改、添加或移除
6. **事件订阅**: SDK 集成了 solana-streamer SDK,支持引用该 SDK 订阅 PumpFun、PumpSwap、Bonk、Raydium CPMM 和 Raydium AMM V4 程序的交易事件,该 SDK 的说明可以查阅:[solana-streamer SDK](https://github.com/0xfnzero/solana-streamer)。
7. **多种 MEV 保护**: 支持 Jito、Nextblock、ZeroSlot、Temporal、Bloxroute、FlashBlock、BlockRazor、Node1、Astralane 等服务
8. **并发交易**: 同时使用多个 MEV 服务发送交易,最快的成功,其他失败
9. **统一交易接口**: 使用统一的交易协议枚举进行交易操作
10. **中间件系统**: 支持自定义指令中间件,可在交易执行前对指令进行修改、添加或移除
## 📦 安装
@@ -89,74 +87,78 @@ git clone https://github.com/0xfnzero/sol-trade-sdk
```toml
# 添加到您的 Cargo.toml
sol-trade-sdk = { path = "./sol-trade-sdk", version = "0.6.15" }
sol-trade-sdk = { path = "./sol-trade-sdk", version = "1.0.0" }
```
### 使用 crates.io
```toml
# 添加到您的 Cargo.toml
sol-trade-sdk = "0.6.15"
sol-trade-sdk = "1.0.0"
```
## 🛠️ 使用示例
### 📋 重要说明
### 📋 使用示例
#### 🌱 open_seed_optimize 参数
#### 1. 创建 SolanaTrade 实例
`open_seed_optimize` ,用于指定是否使用 seed 优化交易 CU 消耗
可以参考 [示例:创建 SolanaTrade 实例](examples/trading_client/src/main.rs)
- **用途**:当 `open_seed_optimize: true` 时,SDK 会在交易时使用 createAccountWithSeed 优化来创建代币 ata 账户。
- **注意**:开启 `open_seed_optimize` 后创建的交易,需要通过该 SDK 卖出,使用官网提供的方法卖出可能会失败。
- **注意**:开启 `open_seed_optimize` 后,获取代币 ata 地址需要通过 `get_associated_token_address_with_program_id_fast_use_seed` 方法获取。
```rust
// 钱包
let payer = Keypair::from_base58_string("use_your_payer_keypair_here");
// RPC 地址
let rpc_url = "https://mainnet.helius-rpc.com/?api-key=xxxxxx".to_string();
let commitment = CommitmentConfig::processed();
// 交易CU和手续费设置
let cu_limit = DEFAULT_CU_LIMIT;
let cu_price = DEFAULT_CU_PRICE;
let buy_tip_fee = DEFAULT_BUY_TIP_FEE;
let sell_tip_fee = DEFAULT_SELL_TIP_FEE;
// SWQOS 服务配置
let swqos_settings: Vec<SwqosSettings> = vec![
SwqosSettings::new(SwqosConfig::Default(rpc_url.clone()), cu_limit, cu_price, 0.0, 0.0),
// First parameter is UUID, pass empty string if no UUID
SwqosSettings::new(SwqosConfig::Jito("your uuid".to_string(), SwqosRegion::Frankfurt, None), cu_limit, cu_price, buy_tip_fee, sell_tip_fee),
// ....其他服务配置...
];
// 创建 SolanaTrade 实例
let client =
SolanaTrade::new(Arc::new(payer), rpc_url, commitment, swqos_settings).await;
```
#### 💰 create_wsol_ata 和 close_wsol_ata、 create_mint_ata 参数
#### 2. 构建交易参数
在 PumpSwap、Bonk、Raydium 交易中,`create_wsol_ata``close_wsol_ata``create_mint_ata` 参数提供对 wSOL(Wrapped SOL)账户管理的精细控制:
有关所有交易参数的详细信息,请参阅 [交易参数参考手册](docs/TRADING_PARAMETERS_CN.md)。
- **create_wsol_ata**
-`create_wsol_ata: true` 时,SDK 会在交易前自动创建并将 SOL 包装为 wSOL
- 买入时:自动将 SOL 包装为 wSOL 进行交易
```rust
let buy_params = sol_trade_sdk::TradeBuyParams {
dex_type: DexType::PumpSwap,
mint: mint_pubkey,
sol_amount: buy_sol_amount,
slippage_basis_points: slippage_basis_points,
recent_blockhash: recent_blockhash,
extension_params: Box::new(params.clone()),
custom_cu_limit: None,
lookup_table_key: None,
wait_transaction_confirmed: true,
create_wsol_ata: true,
close_wsol_ata: true,
create_mint_ata: true,
open_seed_optimize: false,
};
```
- **close_wsol_ata**
-`close_wsol_ata: true` 时,SDK 会在交易后自动关闭 wSOL 账户并解包装为 SOL
- 卖出时:自动将获得的 wSOL 解包装为 SOL 并回收租金
#### 3. 执行交易
- **create_mint_ata**
-`create_mint_ata: true` 时,SDK 会在交易时创建代币ata账户
```rust
client.buy(buy_params).await?;
```
- **分离参数的优势**
- 允许独立控制 wSOL 账户的创建和关闭
- 适用于批量操作,可以创建一次,在多次交易后再关闭
- 为高级交易策略提供灵活性
### ⚡ 交易参数
#### 🔍 lookup_table_key 参数
`lookup_table_key` 参数是一个可选的 `Pubkey`,用于指定地址查找表以优化交易。在使用前你需要通过`AddressLookupTableCache`来管理缓存地址查找表。
- **用途**:地址查找表可以通过存储常用地址来减少交易大小并提高执行速度
- **使用方法**
- 可以在 `buy()``sell()` 方法中按交易覆盖
- 如果不提供,默认为 `None`
- **优势**
- 通过从查找表引用地址来减少交易大小
- 提高交易成功率和速度
- 特别适用于具有许多账户引用的复杂交易
#### ⚡ priority_fee 参数
`priority_fee` 参数是一个可选的 `PriorityFee`,允许您为单个交易覆盖默认的优先级费用设置:
- **用途**:为每个交易提供对交易优先级费用的细粒度控制
- **使用方法**
- 可以传递给 `buy()``sell()` 方法来覆盖全局优先级费用设置
- 如果不提供,默认为 `None` 并使用 `TradeConfig` 中的优先级费用设置
- 当提供时,`buy_tip_fees` 数组将自动填充以匹配 SWQOS 客户端的数量
- **优势**
- 允许根据市场条件动态调整优先级费用
- 为不同类型的交易启用不同的费用策略
- 为高频交易场景提供灵活性
有关所有交易参数(包括 `TradeBuyParams``TradeSellParams`)的详细信息,请参阅专门的 [交易参数参考手册](docs/TRADING_PARAMETERS_CN.md)。
#### 关于shredstream
@@ -165,22 +167,22 @@ sol-trade-sdk = "0.6.15"
### 📊 使用示例汇总表格
| 功能类型 | 示例包名 | 描述 | 运行命令 | 源码路径 |
|---------|---------|------|---------|----------|
| 事件订阅 | `event_subscription` | 监听代币交易事件 | `cargo run --package event_subscription` | [examples/event_subscription](https://github.com/0xfnzero/sol-trade-sdk/tree/main/examples/event_subscription/src/main.rs) |
| 交易客户端 | `trading_client` | 创建和配置 SolanaTrade 实例 | `cargo run --package trading_client` | [examples/trading_client](https://github.com/0xfnzero/sol-trade-sdk/tree/main/examples/trading_client/src/main.rs) |
| PumpFun 狙击 | `pumpfun_sniper_trading` | PumpFun 代币狙击交易 | `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 跟单 | `pumpfun_copy_trading` | PumpFun 代币跟单交易 | `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 | `pumpswap_trading` | PumpSwap 交易操作 | `cargo run --package pumpswap_trading` | [examples/pumpswap_trading](https://github.com/0xfnzero/sol-trade-sdk/tree/main/examples/pumpswap_trading/src/main.rs) |
| Raydium CPMM | `raydium_cpmm_trading` | Raydium CPMM 交易操作 | `cargo run --package raydium_cpmm_trading` | [examples/raydium_cpmm_trading](https://github.com/0xfnzero/sol-trade-sdk/tree/main/examples/raydium_cpmm_trading/src/main.rs) |
| Raydium AMM V4 | `raydium_amm_v4_trading` | Raydium AMM V4 交易操作 | `cargo run --package raydium_amm_v4_trading` | [examples/raydium_amm_v4_trading](https://github.com/0xfnzero/sol-trade-sdk/tree/main/examples/raydium_amm_v4_trading/src/main.rs) |
| Bonk 狙击 | `bonk_sniper_trading` | Bonk 代币狙击交易 | `cargo run --package bonk_sniper_trading` | [examples/bonk_sniper_trading](https://github.com/0xfnzero/sol-trade-sdk/tree/main/examples/bonk_sniper_trading/src/main.rs) |
| Bonk 跟单 | `bonk_copy_trading` | Bonk 代币跟单交易 | `cargo run --package bonk_copy_trading` | [examples/bonk_copy_trading](https://github.com/0xfnzero/sol-trade-sdk/tree/main/examples/bonk_copy_trading/src/main.rs) |
| 中间件系统 | `middleware_system` | 自定义指令中间件示例 | `cargo run --package middleware_system` | [examples/middleware_system](https://github.com/0xfnzero/sol-trade-sdk/tree/main/examples/middleware_system/src/main.rs) |
| 地址查找表 | `address_lookup` | 地址查找表示例 | `cargo run --package address_lookup` | [examples/address_lookup](https://github.com/0xfnzero/sol-trade-sdk/tree/main/examples/address_lookup/src/main.rs) |
| Nonce | `nonce_cache` | Nonce示例 | `cargo run --package nonce_cache` | [examples/nonce_cache](https://github.com/0xfnzero/sol-trade-sdk/tree/main/examples/nonce_cache/src/main.rs) |
| WSOL 包装器 | `wsol_wrapper` | SOL与WSOL相互转换示例 | `cargo run --package wsol_wrapper` | [examples/wsol_wrapper](https://github.com/0xfnzero/sol-trade-sdk/tree/main/examples/wsol_wrapper/src/main.rs) |
| Seed 优化 | `seed_trading` | Seed 优化交易示例 | `cargo run --package seed_trading` | [examples/seed_trading](https://github.com/0xfnzero/sol-trade-sdk/tree/main/examples/seed_trading/src/main.rs) |
| 描述 | 运行命令 | 源码路径 |
|------|---------|----------|
| 监听代币交易事件 | `cargo run --package event_subscription` | [examples/event_subscription](https://github.com/0xfnzero/sol-trade-sdk/tree/main/examples/event_subscription/src/main.rs) |
| 创建和配置 SolanaTrade 实例 | `cargo run --package trading_client` | [examples/trading_client](https://github.com/0xfnzero/sol-trade-sdk/tree/main/examples/trading_client/src/main.rs) |
| PumpFun 代币狙击交易 | `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 代币跟单交易 | `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 交易操作 | `cargo run --package pumpswap_trading` | [examples/pumpswap_trading](https://github.com/0xfnzero/sol-trade-sdk/tree/main/examples/pumpswap_trading/src/main.rs) |
| Raydium CPMM 交易操作 | `cargo run --package raydium_cpmm_trading` | [examples/raydium_cpmm_trading](https://github.com/0xfnzero/sol-trade-sdk/tree/main/examples/raydium_cpmm_trading/src/main.rs) |
| Raydium AMM V4 交易操作 | `cargo run --package raydium_amm_v4_trading` | [examples/raydium_amm_v4_trading](https://github.com/0xfnzero/sol-trade-sdk/tree/main/examples/raydium_amm_v4_trading/src/main.rs) |
| Bonk 代币狙击交易 | `cargo run --package bonk_sniper_trading` | [examples/bonk_sniper_trading](https://github.com/0xfnzero/sol-trade-sdk/tree/main/examples/bonk_sniper_trading/src/main.rs) |
| Bonk 代币跟单交易 | `cargo run --package bonk_copy_trading` | [examples/bonk_copy_trading](https://github.com/0xfnzero/sol-trade-sdk/tree/main/examples/bonk_copy_trading/src/main.rs) |
| 自定义指令中间件示例 | `cargo run --package middleware_system` | [examples/middleware_system](https://github.com/0xfnzero/sol-trade-sdk/tree/main/examples/middleware_system/src/main.rs) |
| 地址查找表示例 | `cargo run --package address_lookup` | [examples/address_lookup](https://github.com/0xfnzero/sol-trade-sdk/tree/main/examples/address_lookup/src/main.rs) |
| Nonce示例 | `cargo run --package nonce_cache` | [examples/nonce_cache](https://github.com/0xfnzero/sol-trade-sdk/tree/main/examples/nonce_cache/src/main.rs) |
| SOL与WSOL相互转换示例 | `cargo run --package wsol_wrapper` | [examples/wsol_wrapper](https://github.com/0xfnzero/sol-trade-sdk/tree/main/examples/wsol_wrapper/src/main.rs) |
| Seed 优化交易示例 | `cargo run --package seed_trading` | [examples/seed_trading](https://github.com/0xfnzero/sol-trade-sdk/tree/main/examples/seed_trading/src/main.rs) |
### ⚙️ SWQOS 服务配置说明
@@ -229,41 +231,18 @@ let middleware_manager = MiddlewareManager::new()
.add_middleware(Box::new(ThirdMiddleware)); // 最后执行
```
### ⚡ 自定义优先费用配置
### 🔍 地址查找表
```rust
use sol_trade_sdk::common::PriorityFee;
地址查找表 (ALT) 允许您通过将经常使用的地址存储在紧凑的表格格式中来优化交易大小并降低费用。详细信息请参阅 [地址查找表指南](docs/ADDRESS_LOOKUP_TABLE_CN.md)。
// 自定义优先费用配置
let priority_fee = PriorityFee {
tip_unit_limit: 190000,
tip_unit_price: 1000000,
rpc_unit_limit: 500000,
rpc_unit_price: 500000,
buy_tip_fee: 0.001,
buy_tip_fees: vec![0.001, 0.002],
sell_tip_fee: 0.0001,
};
### 🔍 Nonce 缓存
// 在TradeConfig中使用自定义优先费用
let trade_config = TradeConfig {
rpc_url: rpc_url.clone(),
commitment: CommitmentConfig::confirmed(),
priority_fee, // 使用自定义优先费用
swqos_configs,
};
```
## 🏪 支持的交易平台
- **PumpFun**: 主要的 meme 币交易平台
- **PumpSwap**: PumpFun 的交换协议
- **Bonk**: 代币发行平台(letsbonk.fun
- **Raydium CPMM**: Raydium 的集中流动性做市商协议
- **Raydium AMM V4**: Raydium 的自动做市商 V4 协议
使用 Nonce 缓存来实现交易重放保护和优化交易处理。详细信息请参阅 [Nonce 缓存指南](docs/NONCE_CACHE_CN.md)。
## 🛡️ MEV 保护服务
可以通过官网申请密钥:[社区官网](https://fnzero.dev/swqos)
- **Jito**: 高性能区块空间
- **NextBlock**: 快速交易执行
- **ZeroSlot**: 零延迟交易
@@ -274,29 +253,6 @@ let trade_config = TradeConfig {
- **Node1**: 高速交易执行,支持 API 密钥认证 - [官方文档](https://node1.me/docs.html)
- **Astralane**: 高速交易执行,支持 API 密钥认证
## 💰 价格计算工具
SDK 包含所有支持协议的价格计算工具,位于 `src/utils/price/` 目录。
## 🧮 数量计算工具
SDK 提供各种协议的交易数量计算功能,位于 `src/utils/calc/` 目录:
- **通用计算函数**: 提供通用的手续费计算和除法运算工具
- **协议特定计算**: 针对每个协议的特定计算逻辑
- **PumpFun**: 基于联合曲线的代币购买/销售数量计算
- **PumpSwap**: 支持多种交易对的数量计算
- **Raydium AMM V4**: 自动做市商池的数量和手续费计算
- **Raydium CPMM**: 恒定乘积做市商的数量计算
- **Bonk**: 专门的 Bonk 代币计算逻辑
主要功能包括:
- 根据输入金额计算输出数量
- 手续费计算和分配
- 滑点保护计算
- 流动性池状态计算
## 📁 项目结构
```
@@ -304,38 +260,18 @@ src/
├── common/ # 通用功能和工具
├── constants/ # 常量定义
├── instruction/ # 指令构建
├── swqos/ # MEV服务客户端
│ └── utils/ # 指令工具函数
├── protos/ # gRPC 协议定义
├── swqos/ # MEV 服务客户端
├── trading/ # 统一交易引擎
│ ├── common/ # 通用交易工具
│ ├── core/ # 核心交易引擎
│ ├── middleware/ # 中间件系统
│ │ ├── builtin.rs # 内置中间件实现
│ │ ├── traits.rs # 中间件 trait 定义
│ │ └── mod.rs # 中间件模块
│ ├── bonk/ # Bonk交易实现
│ ├── pumpfun/ # PumpFun交易实现
│ ├── pumpswap/ # PumpSwap交易实现
│ ├── raydium_cpmm/ # Raydium CPMM交易实现
│ ├── raydium_amm_v4/ # Raydium AMM V4交易实现
│ └── factory.rs # 交易工厂
├── utils/ # 工具函数
│ ├── price/ # 价格计算工具
│ ├── common.rs # 通用价格函数
│ │ ├── bonk.rs # Bonk 价格计算
│ │ ├── pumpfun.rs # PumpFun 价格计算
│ │ ├── pumpswap.rs # PumpSwap 价格计算
│ │ ├── raydium_cpmm.rs # Raydium CPMM 价格计算
│ │ ├── raydium_clmm.rs # Raydium CLMM 价格计算
│ │ └── raydium_amm_v4.rs # Raydium AMM V4 价格计算
│ └── calc/ # 数量计算工具
│ ├── common.rs # 通用计算函数
│ ├── bonk.rs # Bonk 数量计算
│ ├── pumpfun.rs # PumpFun 数量计算
│ ├── pumpswap.rs # PumpSwap 数量计算
│ ├── raydium_cpmm.rs # Raydium CPMM 数量计算
│ └── raydium_amm_v4.rs # Raydium AMM V4 数量计算
├── lib.rs # 主库文件
└── main.rs # 示例程序
│ ├── calc/ # 数量计算工具
└── price/ # 价格计算工具
└── lib.rs # 主库文件
```
## 📄 许可证
@@ -347,6 +283,7 @@ MIT 许可证
- 官方网站: https://fnzero.dev/
- 项目仓库: https://github.com/0xfnzero/sol-trade-sdk
- Telegram 群组: https://t.me/fnzero_group
- Discord: https://discord.gg/vuazbGkqQE
## ⚠️ 重要注意事项
+94
View File
@@ -0,0 +1,94 @@
# Address Lookup Table Guide
This guide explains how to use Address Lookup Tables (ALT) in Sol Trade SDK to optimize transaction size and reduce fees.
## 📋 What are Address Lookup Tables?
Address Lookup Tables are a Solana feature that allows you to store frequently used addresses in a compact table format. Instead of including full 32-byte addresses in transactions, you can reference addresses by their index in the lookup table, significantly reducing transaction size and cost.
## 🚀 Core Benefits
- **Transaction Size Optimization**: Reduce transaction size by using address indices instead of full addresses
- **Cost Reduction**: Lower transaction fees due to reduced transaction size
- **Performance Improvement**: Faster transaction processing and validation
- **Network Efficiency**: Reduced bandwidth usage and block space consumption
## 🛠️ Implementation
### 1. Setting up Address Lookup Table Cache
The SDK provides a global cache to manage address lookup tables:
```rust
use sol_trade_sdk::common::address_lookup_cache::AddressLookupTableCache;
use solana_sdk::pubkey::Pubkey;
use std::str::FromStr;
/// Setup lookup table cache
async fn setup_lookup_table_cache(
client: Arc<SolanaRpcClient>,
lookup_table_address: Pubkey,
) -> AnyResult<()> {
AddressLookupTableCache::get_instance()
.set_address_lookup_table(client, &lookup_table_address)
.await
.map_err(|e| anyhow::anyhow!("Failed to set address lookup table: {}", e))?;
Ok(())
}
```
### 2. Using Lookup Tables in Trade Parameters
Include lookup tables in your trade parameters:
```rust
// Initialize lookup table
let lookup_table_key = Pubkey::from_str("your_lookup_table_address_here").unwrap();
setup_lookup_table_cache(client.rpc.clone(), lookup_table_key).await?;
// Include lookup table in trade parameters
let buy_params = sol_trade_sdk::TradeBuyParams {
dex_type: DexType::PumpFun,
mint: mint_pubkey,
sol_amount: buy_sol_amount,
slippage_basis_points: Some(100),
recent_blockhash: recent_blockhash,
extension_params: Box::new(PumpFunParams::from_trade(&trade_info, None)),
lookup_table_key: Some(lookup_table_key), // Include lookup table
wait_transaction_confirmed: true,
create_wsol_ata: false,
close_wsol_ata: false,
create_mint_ata: true,
open_seed_optimize: false,
custom_cu_limit: None,
};
// Execute transaction
client.buy(buy_params).await?;
```
## 📊 Performance Comparison
| Aspect | Without ALT | With ALT | Improvement |
|--------|-------------|----------|-------------|
| **Transaction Size** | ~1,232 bytes | ~800 bytes | 35% reduction |
| **Address Storage** | 32 bytes per address | 1 byte per address | 97% reduction |
| **Transaction Fees** | Higher | Lower | Up to 30% savings |
| **Block Space Usage** | More | Less | Improved network efficiency |
## ⚠️ Important Notes
1. **Lookup Table Address**: Must provide a valid address lookup table address
2. **Cache Management**: SDK automatically manages lookup table cache
3. **RPC Compatibility**: Ensure your RPC provider supports lookup tables
4. **Network Specific**: Lookup tables are network-specific (mainnet/devnet/testnet)
5. **Testing**: Always test on devnet before using on mainnet
## 🔗 Related Documentation
- [Trading Parameters Reference](TRADING_PARAMETERS.md)
- [Example: Address Lookup Table](../examples/address_lookup/)
## 📚 External Resources
- [Solana Address Lookup Tables Documentation](https://docs.solana.com/developing/lookup-tables)
+94
View File
@@ -0,0 +1,94 @@
# 地址查找表指南
本指南介绍如何在 Sol Trade SDK 中使用地址查找表 (ALT) 来优化交易大小并降低费用。
## 📋 什么是地址查找表?
地址查找表是 Solana 的一项功能,允许您将经常使用的地址以紧凑的表格格式存储。您可以通过查找表中的索引来引用地址,而不是在交易中包含完整的 32 字节地址,从而显著减少交易大小和成本。
## 🚀 核心优势
- **交易大小优化**: 使用地址索引而非完整地址来减少交易大小
- **成本降低**: 由于交易大小减小而降低交易费用
- **性能提升**: 更快的交易处理和验证速度
- **网络效率**: 减少带宽使用和区块空间消耗
## 🛠️ 实现方法
### 1. 设置地址查找表缓存
SDK 提供了一个全局缓存来管理地址查找表:
```rust
use sol_trade_sdk::common::address_lookup_cache::AddressLookupTableCache;
use solana_sdk::pubkey::Pubkey;
use std::str::FromStr;
/// 设置查找表缓存
async fn setup_lookup_table_cache(
client: Arc<SolanaRpcClient>,
lookup_table_address: Pubkey,
) -> AnyResult<()> {
AddressLookupTableCache::get_instance()
.set_address_lookup_table(client, &lookup_table_address)
.await
.map_err(|e| anyhow::anyhow!("Failed to set address lookup table: {}", e))?;
Ok(())
}
```
### 2. 在交易参数中使用查找表
在您的交易参数中包含查找表:
```rust
// 初始化查找表
let lookup_table_key = Pubkey::from_str("your_lookup_table_address_here").unwrap();
setup_lookup_table_cache(client.rpc.clone(), lookup_table_key).await?;
// 在交易参数中包含查找表
let buy_params = sol_trade_sdk::TradeBuyParams {
dex_type: DexType::PumpFun,
mint: mint_pubkey,
sol_amount: buy_sol_amount,
slippage_basis_points: Some(100),
recent_blockhash: recent_blockhash,
extension_params: Box::new(PumpFunParams::from_trade(&trade_info, None)),
lookup_table_key: Some(lookup_table_key), // 包含查找表
wait_transaction_confirmed: true,
create_wsol_ata: false,
close_wsol_ata: false,
create_mint_ata: true,
open_seed_optimize: false,
custom_cu_limit: None,
};
// 执行交易
client.buy(buy_params).await?;
```
## 📊 性能对比
| 方面 | 不使用 ALT | 使用 ALT | 改进幅度 |
|------|-----------|----------|----------|
| **交易大小** | ~1,232 字节 | ~800 字节 | 减少 35% |
| **地址存储** | 每个地址 32 字节 | 每个地址 1 字节 | 减少 97% |
| **交易费用** | 更高 | 更低 | 节省高达 30% |
| **区块空间使用** | 更多 | 更少 | 提高网络效率 |
## ⚠️ 重要注意事项
1. **查找表地址**: 必须提供有效的地址查找表地址
2. **缓存管理**: SDK 自动管理查找表缓存
3. **RPC 兼容性**: 确保您的 RPC 提供商支持查找表
4. **网络**: 查找表是特定于网络的(主网/开发网/测试网)
5. **测试**: 在主网使用前请务必在开发网测试
## 🔗 相关文档
- [交易参数参考手册](TRADING_PARAMETERS_CN.md)
- [示例:地址查找表](../examples/address_lookup/)
## 📚 外部资源
- [Solana 地址查找表文档](https://docs.solana.com/developing/lookup-tables)
+84
View File
@@ -0,0 +1,84 @@
# Nonce Cache Guide
This guide explains how to use Nonce Cache in Sol Trade SDK to implement transaction replay protection and optimize transaction processing.
## 📋 What is Nonce Cache?
Nonce Cache is a global singleton cache system for managing durable nonce accounts in the Solana network. Durable nonce is a Solana feature that allows you to create transactions that remain valid for extended periods, not limited by the 150-block constraint of recent block hashes.
## 🚀 Core Benefits
- **Transaction Replay Protection**: Prevents the same transaction from being executed multiple times
- **Extended Time Window**: Transactions can remain valid for longer periods
- **Network Performance Optimization**: Reduces dependency on recent block hashes
- **Transaction Determinism**: Provides consistent transaction processing experience
- **Offline Transaction Support**: Supports offline processing of pre-signed transactions
## 🛠️ Implementation
### Prerequisites:
You need to create a nonce account for your payer account first.
Reference: https://solana.com/developers/guides/advanced/introduction-to-durable-nonces
### 1. Initialize Nonce Cache
First, set up the nonce account and initialize the cache:
```rust
use sol_trade_sdk::common::nonce_cache::NonceCache;
// Set nonce account
let nonce_account_str = "your_nonce_account_address_here";
NonceCache::get_instance().init(Some(nonce_account_str.to_string()));
```
### 2. Fetch Nonce Information
Get the latest nonce information from RPC:
```rust
// Fetch and update nonce information
NonceCache::get_instance().fetch_nonce_info_use_rpc(&client.rpc).await?;
// Get current nonce value
let nonce_info = NonceCache::get_instance().get_nonce_info();
let current_nonce = nonce_info.current_nonce;
println!("Current nonce: {}", current_nonce);
```
### 3. Use Nonce in Transactions
Pass the nonce as the recent_blockhash parameter to transactions:
```rust
let buy_params = sol_trade_sdk::TradeBuyParams {
dex_type: DexType::PumpFun,
mint: mint_pubkey,
sol_amount: buy_sol_amount,
slippage_basis_points: Some(100),
recent_blockhash: current_nonce, // Use nonce as blockhash
extension_params: Box::new(PumpFunParams::from_trade(&trade_info, None)),
lookup_table_key: None,
wait_transaction_confirmed: true,
create_wsol_ata: false,
close_wsol_ata: false,
create_mint_ata: true,
open_seed_optimize: false,
custom_cu_limit: None,
};
// Execute transaction
client.buy(buy_params).await?;
```
## 🔄 Nonce Lifecycle
1. **Initialize**: Set nonce account address
2. **Fetch**: Get the latest nonce value from RPC
4. **Use**: Use as blockhash in transactions
6. **Refresh**: Re-fetch new nonce value before next use
## 🔗 Related Documentation
- [Example: Nonce Cache](../examples/nonce_cache/)
+84
View File
@@ -0,0 +1,84 @@
# Nonce 缓存指南
本指南介绍如何在 Sol Trade SDK 中使用 Nonce 缓存来实现交易重放保护和优化交易处理。
## 📋 什么是 Nonce 缓存?
Nonce 缓存是一个全局单例模式的缓存系统,用于管理 Solana 网络中的 durable nonce 账户。Durable nonce 是 Solana 的一项功能,允许您创建在较长时间内有效的交易,而不受最近区块哈希的 150 个区块限制。
## 🚀 核心优势
- **交易重放保护**: 防止相同交易被重复执行
- **时间窗口扩展**: 交易可在更长时间内保持有效
- **网络性能优化**: 减少对最新区块哈希的依赖
- **交易确定性**: 提供一致的交易处理体验
- **离线交易支持**: 支持预签名交易的离线处理
## 🛠️ 实现方法
### 前提:
需要先创建你 payer 账号使用的 nonce 账户。
参考资料: https://solana.com/zh/developers/guides/advanced/introduction-to-durable-nonces
### 1. 初始化 Nonce 缓存
首先需要设置 nonce 账户并初始化缓存:
```rust
use sol_trade_sdk::common::nonce_cache::NonceCache;
// 设置 nonce 账户
let nonce_account_str = "your_nonce_account_address_here";
NonceCache::get_instance().init(Some(nonce_account_str.to_string()));
```
### 2. 获取 Nonce 信息
从 RPC 获取最新的 nonce 信息:
```rust
// 获取并更新 nonce 信息
NonceCache::get_instance().fetch_nonce_info_use_rpc(&client.rpc).await?;
// 获取当前 nonce 值
let nonce_info = NonceCache::get_instance().get_nonce_info();
let current_nonce = nonce_info.current_nonce;
println!("Current nonce: {}", current_nonce);
```
### 3. 在交易中使用 Nonce
将 nonce 作为 recent_blockhash 参数传递给交易:
```rust
let buy_params = sol_trade_sdk::TradeBuyParams {
dex_type: DexType::PumpFun,
mint: mint_pubkey,
sol_amount: buy_sol_amount,
slippage_basis_points: Some(100),
recent_blockhash: current_nonce, // 使用 nonce 作为 blockhash
extension_params: Box::new(PumpFunParams::from_trade(&trade_info, None)),
lookup_table_key: None,
wait_transaction_confirmed: true,
create_wsol_ata: false,
close_wsol_ata: false,
create_mint_ata: true,
open_seed_optimize: false,
custom_cu_limit: None,
};
// 执行交易
client.buy(buy_params).await?;
```
## 🔄 Nonce 生命周期
1. **初始化**: 设置 nonce 账户地址
2. **获取**: 从 RPC 获取最新 nonce 值
4. **使用**: 在交易中作为 blockhash 使用
6. **刷新**: 下次使用前重新获取新的 nonce 值
## 🔗 相关文档
- [示例:Nonce 缓存](../examples/nonce_cache/)
+142
View File
@@ -0,0 +1,142 @@
# 📋 Trading Parameters Reference
This document provides a comprehensive reference for all trading parameters used in the Sol Trade SDK.
## 📋 Table of Contents
- [TradeBuyParams](#tradebuyparams)
- [TradeSellParams](#tradesellparams)
- [Parameter Categories](#parameter-categories)
- [Important Notes](#important-notes)
## TradeBuyParams
The `TradeBuyParams` struct contains all parameters required for executing buy orders across different DEX protocols.
### Basic Trading Parameters
| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| `dex_type` | `DexType` | ✅ | The trading protocol to use (PumpFun, PumpSwap, Bonk, RaydiumCpmm, RaydiumAmmV4) |
| `mint` | `Pubkey` | ✅ | The public key of the token mint to purchase |
| `sol_amount` | `u64` | ✅ | Amount of SOL to spend (in lamports) |
| `slippage_basis_points` | `Option<u64>` | ❌ | Slippage tolerance in basis points (e.g., 100 = 1%, 500 = 5%) |
| `recent_blockhash` | `Hash` | ✅ | Recent blockhash for transaction validity |
| `extension_params` | `Box<dyn ProtocolParams>` | ✅ | Protocol-specific parameters (PumpFunParams, PumpSwapParams, etc.) |
### Advanced Configuration Parameters
| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| `custom_cu_limit` | `Option<u32>` | ❌ | Custom compute unit limit for the transaction |
| `lookup_table_key` | `Option<Pubkey>` | ❌ | Address lookup table key for transaction optimization |
| `wait_transaction_confirmed` | `bool` | ✅ | Whether to wait for transaction confirmation |
| `create_wsol_ata` | `bool` | ✅ | Whether to create wSOL Associated Token Account |
| `close_wsol_ata` | `bool` | ✅ | Whether to close wSOL ATA after transaction |
| `create_mint_ata` | `bool` | ✅ | Whether to create token mint ATA |
| `open_seed_optimize` | `bool` | ✅ | Whether to use seed optimization for reduced CU consumption |
## TradeSellParams
The `TradeSellParams` struct contains all parameters required for executing sell orders across different DEX protocols.
### Basic Trading Parameters
| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| `dex_type` | `DexType` | ✅ | The trading protocol to use (PumpFun, PumpSwap, Bonk, RaydiumCpmm, RaydiumAmmV4) |
| `mint` | `Pubkey` | ✅ | The public key of the token mint to sell |
| `token_amount` | `u64` | ✅ | Amount of tokens to sell (in smallest token units) |
| `slippage_basis_points` | `Option<u64>` | ❌ | Slippage tolerance in basis points (e.g., 100 = 1%, 500 = 5%) |
| `recent_blockhash` | `Hash` | ✅ | Recent blockhash for transaction validity |
| `with_tip` | `bool` | ✅ | Whether to include tip in the transaction |
| `extension_params` | `Box<dyn ProtocolParams>` | ✅ | Protocol-specific parameters (PumpFunParams, PumpSwapParams, etc.) |
### Advanced Configuration Parameters
| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| `custom_cu_limit` | `Option<u32>` | ❌ | Custom compute unit limit for the transaction |
| `lookup_table_key` | `Option<Pubkey>` | ❌ | Address lookup table key for transaction optimization |
| `wait_transaction_confirmed` | `bool` | ✅ | Whether to wait for transaction confirmation |
| `create_wsol_ata` | `bool` | ✅ | Whether to create wSOL Associated Token Account |
| `close_wsol_ata` | `bool` | ✅ | Whether to close wSOL ATA after transaction |
| `open_seed_optimize` | `bool` | ✅ | Whether to use seed optimization for reduced CU consumption |
## Parameter Categories
### 🎯 Core Trading Parameters
These parameters are essential for defining the basic trading operation:
- **dex_type**: Determines which protocol to use for trading
- **mint**: Specifies the token to trade
- **sol_amount** (buy) / **token_amount** (sell): Defines the trade size
- **recent_blockhash**: Ensures transaction validity
### ⚙️ Transaction Control Parameters
These parameters control how the transaction is processed:
- **slippage_basis_points**: Controls acceptable price slippage
- **custom_cu_limit**: Override default compute unit limits
- **wait_transaction_confirmed**: Controls whether to wait for confirmation
### 🔧 Account Management Parameters
These parameters control automatic account creation and management:
- **create_wsol_ata**: Automatically wrap SOL to wSOL when needed
- **close_wsol_ata**: Automatically unwrap wSOL to SOL after trading
- **create_mint_ata**: Automatically create token accounts
### 🚀 Optimization Parameters
These parameters enable advanced optimizations:
- **lookup_table_key**: Use address lookup tables for reduced transaction size
- **open_seed_optimize**: Use seed-based account creation for lower CU consumption
## Important Notes
### 🌱 Seed Optimization
When `open_seed_optimize: true`:
- ⚠️ **Warning**: Tokens purchased with seed optimization must be sold through this SDK
- ⚠️ **Warning**: Official platform selling methods may fail
- 📝 **Note**: Use `get_associated_token_address_with_program_id_fast_use_seed` to get ATA addresses
### 💰 wSOL Account Management
The `create_wsol_ata` and `close_wsol_ata` parameters provide granular control:
- **Independent Control**: Create and close operations can be controlled separately
- **Batch Operations**: Create once, trade multiple times, then close
- **Rent Optimization**: Automatic rent reclamation when closing accounts
### 🔍 Address Lookup Tables
Before using `lookup_table_key`:
- Initialize `AddressLookupTableCache` to manage cached lookup tables
- Lookup tables reduce transaction size and improve success rates
- Particularly beneficial for complex transactions with many account references
### 📊 Slippage Configuration
Recommended slippage settings:
- **Conservative**: 100-300 basis points (1-3%)
- **Moderate**: 300-500 basis points (3-5%)
- **Aggressive**: 500-1000 basis points (5-10%)
### 🎯 Protocol-Specific Parameters
Each DEX protocol requires specific `extension_params`:
- **PumpFun**: `PumpFunParams`
- **PumpSwap**: `PumpSwapParams`
- **Bonk**: `BonkParams`
- **Raydium CPMM**: `RaydiumCpmmParams`
- **Raydium AMM V4**: `RaydiumAmmV4Params`
Refer to the respective protocol documentation for detailed parameter specifications.
+142
View File
@@ -0,0 +1,142 @@
# 📋 交易参数参考手册
本文档提供 Sol Trade SDK 中所有交易参数的完整参考说明。
## 📋 目录
- [TradeBuyParams](#tradebuyparams)
- [TradeSellParams](#tradesellparams)
- [参数分类](#参数分类)
- [重要说明](#重要说明)
## TradeBuyParams
`TradeBuyParams` 结构体包含在不同 DEX 协议上执行买入订单所需的所有参数。
### 基础交易参数
| 参数 | 类型 | 必需 | 描述 |
|------|------|------|------|
| `dex_type` | `DexType` | ✅ | 要使用的交易协议 (PumpFun, PumpSwap, Bonk, RaydiumCpmm, RaydiumAmmV4) |
| `mint` | `Pubkey` | ✅ | 要购买的代币 mint 公钥 |
| `sol_amount` | `u64` | ✅ | 要花费的 SOL 数量(以 lamports 为单位) |
| `slippage_basis_points` | `Option<u64>` | ❌ | 滑点容忍度(基点单位,例如 100 = 1%, 500 = 5% |
| `recent_blockhash` | `Hash` | ✅ | 用于交易有效性的最新区块哈希 |
| `extension_params` | `Box<dyn ProtocolParams>` | ✅ | 协议特定参数 (PumpFunParams, PumpSwapParams 等) |
### 高级配置参数
| 参数 | 类型 | 必需 | 描述 |
|------|------|------|------|
| `custom_cu_limit` | `Option<u32>` | ❌ | 交易的自定义计算单元限制 |
| `lookup_table_key` | `Option<Pubkey>` | ❌ | 用于交易优化的地址查找表键 |
| `wait_transaction_confirmed` | `bool` | ✅ | 是否等待交易确认 |
| `create_wsol_ata` | `bool` | ✅ | 是否创建 wSOL 关联代币账户 |
| `close_wsol_ata` | `bool` | ✅ | 交易后是否关闭 wSOL ATA |
| `create_mint_ata` | `bool` | ✅ | 是否创建代币 mint ATA |
| `open_seed_optimize` | `bool` | ✅ | 是否使用 seed 优化以减少 CU 消耗 |
## TradeSellParams
`TradeSellParams` 结构体包含在不同 DEX 协议上执行卖出订单所需的所有参数。
### 基础交易参数
| 参数 | 类型 | 必需 | 描述 |
|------|------|------|------|
| `dex_type` | `DexType` | ✅ | 要使用的交易协议 (PumpFun, PumpSwap, Bonk, RaydiumCpmm, RaydiumAmmV4) |
| `mint` | `Pubkey` | ✅ | 要出售的代币 mint 公钥 |
| `token_amount` | `u64` | ✅ | 要出售的代币数量(最小代币单位) |
| `slippage_basis_points` | `Option<u64>` | ❌ | 滑点容忍度(基点单位,例如 100 = 1%, 500 = 5% |
| `recent_blockhash` | `Hash` | ✅ | 用于交易有效性的最新区块哈希 |
| `with_tip` | `bool` | ✅ | 交易中是否包含小费 |
| `extension_params` | `Box<dyn ProtocolParams>` | ✅ | 协议特定参数 (PumpFunParams, PumpSwapParams 等) |
### 高级配置参数
| 参数 | 类型 | 必需 | 描述 |
|------|------|------|------|
| `custom_cu_limit` | `Option<u32>` | ❌ | 交易的自定义计算单元限制 |
| `lookup_table_key` | `Option<Pubkey>` | ❌ | 用于交易优化的地址查找表键 |
| `wait_transaction_confirmed` | `bool` | ✅ | 是否等待交易确认 |
| `create_wsol_ata` | `bool` | ✅ | 是否创建 wSOL 关联代币账户 |
| `close_wsol_ata` | `bool` | ✅ | 交易后是否关闭 wSOL ATA |
| `open_seed_optimize` | `bool` | ✅ | 是否使用 seed 优化以减少 CU 消耗 |
## 参数分类
### 🎯 核心交易参数
这些参数对于定义基本交易操作至关重要:
- **dex_type**: 确定用于交易的协议
- **mint**: 指定要交易的代币
- **sol_amount** (买入) / **token_amount** (卖出): 定义交易规模
- **recent_blockhash**: 确保交易有效性
### ⚙️ 交易控制参数
这些参数控制交易的处理方式:
- **slippage_basis_points**: 控制可接受的价格滑点
- **custom_cu_limit**: 覆盖默认的计算单元限制
- **wait_transaction_confirmed**: 控制是否等待确认
### 🔧 账户管理参数
这些参数控制自动账户创建和管理:
- **create_wsol_ata**: 需要时自动将 SOL 包装为 wSOL
- **close_wsol_ata**: 交易后自动将 wSOL 解包装为 SOL
- **create_mint_ata**: 自动创建代币账户
### 🚀 优化参数
这些参数启用高级优化:
- **lookup_table_key**: 使用地址查找表减少交易大小
- **open_seed_optimize**: 使用基于 seed 的账户创建以降低 CU 消耗
## 重要说明
### 🌱 Seed 优化
`open_seed_optimize: true` 时:
- ⚠️ **警告**: 使用 seed 优化购买的代币必须通过此 SDK 出售
- ⚠️ **警告**: 官方平台的出售方法可能会失败
- 📝 **注意**: 使用 `get_associated_token_address_with_program_id_fast_use_seed` 获取 ATA 地址
### 💰 wSOL 账户管理
`create_wsol_ata``close_wsol_ata` 参数提供精细控制:
- **独立控制**: 创建和关闭操作可以分别控制
- **批量操作**: 创建一次,多次交易,然后关闭
- **租金优化**: 关闭账户时自动回收租金
### 🔍 地址查找表
使用 `lookup_table_key` 之前:
- 初始化 `AddressLookupTableCache` 来管理缓存的查找表
- 查找表减少交易大小并提高成功率
- 对于有许多账户引用的复杂交易特别有益
### 📊 滑点配置
推荐的滑点设置:
- **保守**: 100-300 基点 (1-3%)
- **中等**: 300-500 基点 (3-5%)
- **激进**: 500-1000 基点 (5-10%)
### 🎯 协议特定参数
每个 DEX 协议需要特定的 `extension_params`
- **PumpFun**: `PumpFunParams`
- **PumpSwap**: `PumpSwapParams`
- **Bonk**: `BonkParams`
- **Raydium CPMM**: `RaydiumCpmmParams`
- **Raydium AMM V4**: `RaydiumAmmV4Params`
请参阅相应的协议文档了解详细的参数规格。
+35 -42
View File
@@ -19,15 +19,17 @@ use sol_trade_sdk::{
solana_streamer_sdk::streaming::event_parser::common::EventType,
};
use sol_trade_sdk::{
common::SolanaRpcClient,
solana_streamer_sdk::streaming::event_parser::common::filter::EventTypeFilter,
};
use sol_trade_sdk::{
common::{AnyResult, PriorityFee, TradeConfig},
common::AnyResult,
constants::trade::trade::{DEFAULT_CU_LIMIT, DEFAULT_CU_PRICE},
swqos::settings::SwqosSettings,
swqos::SwqosConfig,
trading::{core::params::PumpFunParams, factory::DexType},
SolanaTrade,
};
use sol_trade_sdk::{
common::SolanaRpcClient,
solana_streamer_sdk::streaming::event_parser::common::filter::EventTypeFilter,
};
use solana_sdk::pubkey::Pubkey;
use solana_sdk::{commitment_config::CommitmentConfig, signature::Keypair};
@@ -117,28 +119,20 @@ async fn setup_lookup_table_cache(
/// Create SolanaTrade client
/// Initializes a new SolanaTrade client with configuration
async fn create_solana_trade_client() -> AnyResult<SolanaTrade> {
println!("Creating SolanaTrade client...");
println!("🚀 Initializing SolanaTrade client...");
let payer = Keypair::from_base58_string("use_your_payer_keypair_here");
let rpc_url = "https://api.mainnet-beta.solana.com".to_string();
let swqos_configs = vec![SwqosConfig::Default(rpc_url.clone())];
let mut priority_fee = PriorityFee::default();
// Configure according to your needs
priority_fee.rpc_unit_limit = 100000;
let trade_config = TradeConfig {
rpc_url,
commitment: CommitmentConfig::confirmed(),
priority_fee: priority_fee,
swqos_configs,
};
let solana_trade_client = SolanaTrade::new(Arc::new(payer), trade_config).await;
println!("SolanaTrade client created successfully!");
Ok(solana_trade_client)
let commitment = CommitmentConfig::confirmed();
let swqos_settings: Vec<SwqosSettings> = vec![SwqosSettings::new(
SwqosConfig::Default(rpc_url.clone()),
DEFAULT_CU_LIMIT,
DEFAULT_CU_PRICE,
0.0,
0.0,
)];
let solana_trade = SolanaTrade::new(Arc::new(payer), rpc_url, commitment, swqos_settings).await;
println!("✅ SolanaTrade client initialized successfully!");
Ok(solana_trade)
}
/// PumpFun sniper trade
@@ -158,23 +152,22 @@ async fn pumpfun_copy_trade_with_grpc(trade_info: PumpFunTradeEvent) -> AnyResul
// Buy tokens
println!("Buying tokens from PumpFun...");
let buy_sol_amount = 100_000;
client
.buy(
DexType::PumpFun,
mint_pubkey,
buy_sol_amount,
slippage_basis_points,
recent_blockhash,
None,
Box::new(PumpFunParams::from_trade(&trade_info, None)),
Some(lookup_table_key), // you still need to update the AddressLookupTableCache
true,
false,
false,
true,
false,
)
.await?;
let buy_params = sol_trade_sdk::TradeBuyParams {
dex_type: DexType::PumpFun,
mint: mint_pubkey,
sol_amount: buy_sol_amount,
slippage_basis_points: slippage_basis_points,
recent_blockhash: recent_blockhash,
extension_params: Box::new(PumpFunParams::from_trade(&trade_info, None)),
lookup_table_key: Some(lookup_table_key), // you still need to update the AddressLookupTableCache
wait_transaction_confirmed: true,
create_wsol_ata: false,
close_wsol_ata: false,
create_mint_ata: true,
open_seed_optimize: false,
custom_cu_limit: None,
};
client.buy(buy_params).await?;
// Exit program
std::process::exit(0);
+47 -55
View File
@@ -14,7 +14,9 @@ use sol_trade_sdk::solana_streamer_sdk::streaming::yellowstone_grpc::{
};
use sol_trade_sdk::solana_streamer_sdk::streaming::YellowstoneGrpc;
use sol_trade_sdk::{
common::{AnyResult, PriorityFee, TradeConfig},
common::AnyResult,
constants::trade::trade::{DEFAULT_CU_LIMIT, DEFAULT_CU_PRICE},
swqos::settings::SwqosSettings,
swqos::SwqosConfig,
trading::{core::params::BonkParams, factory::DexType},
SolanaTrade,
@@ -103,28 +105,20 @@ fn create_event_callback() -> impl Fn(Box<dyn UnifiedEvent>) {
/// Create SolanaTrade client
/// Initializes a new SolanaTrade client with configuration
async fn create_solana_trade_client() -> AnyResult<SolanaTrade> {
println!("Creating SolanaTrade client...");
println!("🚀 Initializing SolanaTrade client...");
let payer = Keypair::from_base58_string("use_your_payer_keypair_here");
let rpc_url = "https://api.mainnet-beta.solana.com".to_string();
let swqos_configs = vec![SwqosConfig::Default(rpc_url.clone())];
let mut priority_fee = PriorityFee::default();
// Configure according to your needs
priority_fee.rpc_unit_limit = 150000;
let trade_config = TradeConfig {
rpc_url,
commitment: CommitmentConfig::confirmed(),
priority_fee: priority_fee,
swqos_configs,
};
let solana_trade_client = SolanaTrade::new(Arc::new(payer), trade_config).await;
println!("SolanaTrade client created successfully!");
Ok(solana_trade_client)
let commitment = CommitmentConfig::confirmed();
let swqos_settings: Vec<SwqosSettings> = vec![SwqosSettings::new(
SwqosConfig::Default(rpc_url.clone()),
DEFAULT_CU_LIMIT,
DEFAULT_CU_PRICE,
0.0,
0.0,
)];
let solana_trade = SolanaTrade::new(Arc::new(payer), rpc_url, commitment, swqos_settings).await;
println!("✅ SolanaTrade client initialized successfully!");
Ok(solana_trade)
}
/// Bonk sniper trade
@@ -140,23 +134,22 @@ async fn bonk_copy_trade_with_grpc(trade_info: BonkTradeEvent) -> AnyResult<()>
// Buy tokens
println!("Buying tokens from Bonk...");
let buy_sol_amount = 100_000;
client
.buy(
DexType::Bonk,
mint_pubkey,
buy_sol_amount,
slippage_basis_points,
recent_blockhash,
None,
Box::new(BonkParams::from_trade(trade_info.clone())),
None,
true,
true,
true,
true,
false,
)
.await?;
let buy_params = sol_trade_sdk::TradeBuyParams {
dex_type: DexType::Bonk,
mint: mint_pubkey,
sol_amount: buy_sol_amount,
slippage_basis_points: slippage_basis_points,
recent_blockhash: recent_blockhash,
extension_params: Box::new(BonkParams::from_trade(trade_info.clone())),
lookup_table_key: None,
wait_transaction_confirmed: true,
create_wsol_ata: true,
close_wsol_ata: true,
create_mint_ata: true,
open_seed_optimize: false,
custom_cu_limit: None,
};
client.buy(buy_params).await?;
// Sell tokens
println!("Selling tokens from Bonk...");
@@ -169,23 +162,22 @@ async fn bonk_copy_trade_with_grpc(trade_info: BonkTradeEvent) -> AnyResult<()>
let amount_token = balance.amount.parse::<u64>().unwrap();
println!("Selling {} tokens", amount_token);
client
.sell(
DexType::Bonk,
mint_pubkey,
amount_token,
slippage_basis_points,
recent_blockhash,
None,
false,
Box::new(BonkParams::from_trade(trade_info.clone())),
None,
true,
true,
true,
false,
)
.await?;
let sell_params = sol_trade_sdk::TradeSellParams {
dex_type: DexType::Bonk,
mint: mint_pubkey,
token_amount: amount_token,
slippage_basis_points: slippage_basis_points,
recent_blockhash: recent_blockhash,
extension_params: Box::new(BonkParams::from_trade(trade_info.clone())),
lookup_table_key: None,
wait_transaction_confirmed: true,
create_wsol_ata: true,
close_wsol_ata: true,
open_seed_optimize: false,
with_tip: false,
custom_cu_limit: None,
};
client.sell(sell_params).await?;
// Exit program
std::process::exit(0);
+52 -61
View File
@@ -2,10 +2,11 @@ use sol_trade_sdk::solana_streamer_sdk::streaming::event_parser::common::filter:
use sol_trade_sdk::solana_streamer_sdk::streaming::event_parser::common::EventType;
use sol_trade_sdk::solana_streamer_sdk::streaming::event_parser::protocols::bonk::BonkTradeEvent;
use sol_trade_sdk::solana_streamer_sdk::streaming::event_parser::{Protocol, UnifiedEvent};
use sol_trade_sdk::solana_streamer_sdk::streaming::grpc::ClientConfig;
use sol_trade_sdk::solana_streamer_sdk::{match_event, streaming::ShredStreamGrpc};
use sol_trade_sdk::{
common::{AnyResult, PriorityFee, TradeConfig},
common::AnyResult,
constants::trade::trade::{DEFAULT_CU_LIMIT, DEFAULT_CU_PRICE},
swqos::settings::SwqosSettings,
swqos::SwqosConfig,
trading::{core::params::BonkParams, factory::DexType},
SolanaTrade,
@@ -72,28 +73,20 @@ fn create_event_callback() -> impl Fn(Box<dyn UnifiedEvent>) {
/// Create SolanaTrade client
/// Initializes a new SolanaTrade client with configuration
async fn create_solana_trade_client() -> AnyResult<SolanaTrade> {
println!("Creating SolanaTrade client...");
println!("🚀 Initializing SolanaTrade client...");
let payer = Keypair::from_base58_string("use_your_payer_keypair_here");
let rpc_url = "https://api.mainnet-beta.solana.com".to_string();
let swqos_configs = vec![SwqosConfig::Default(rpc_url.clone())];
let mut priority_fee = PriorityFee::default();
// Set RPC unit limit based on your requirements
priority_fee.rpc_unit_limit = 150000;
let trade_config = TradeConfig {
rpc_url,
commitment: CommitmentConfig::confirmed(),
priority_fee: priority_fee,
swqos_configs,
};
let solana_trade_client = SolanaTrade::new(Arc::new(payer), trade_config).await;
println!("SolanaTrade client created successfully!");
Ok(solana_trade_client)
let commitment = CommitmentConfig::confirmed();
let swqos_settings: Vec<SwqosSettings> = vec![SwqosSettings::new(
SwqosConfig::Default(rpc_url.clone()),
DEFAULT_CU_LIMIT,
DEFAULT_CU_PRICE,
0.0,
0.0,
)];
let solana_trade = SolanaTrade::new(Arc::new(payer), rpc_url, commitment, swqos_settings).await;
println!("✅ SolanaTrade client initialized successfully!");
Ok(solana_trade)
}
/// Execute Bonk sniper trading strategy based on received token creation event
@@ -109,23 +102,22 @@ async fn bonk_sniper_trade_with_shreds(trade_info: BonkTradeEvent) -> AnyResult<
// Buy tokens
println!("Buying tokens from Bonk...");
let buy_sol_amount = 100_000;
client
.buy(
DexType::Bonk,
mint_pubkey,
buy_sol_amount,
slippage_basis_points,
recent_blockhash,
None,
Box::new(BonkParams::from_dev_trade(trade_info.clone())),
None,
true,
true,
true,
true,
false,
)
.await?;
let buy_params = sol_trade_sdk::TradeBuyParams {
dex_type: DexType::Bonk,
mint: mint_pubkey,
sol_amount: buy_sol_amount,
slippage_basis_points: slippage_basis_points,
recent_blockhash: recent_blockhash,
extension_params: Box::new(BonkParams::from_dev_trade(trade_info.clone())),
lookup_table_key: None,
wait_transaction_confirmed: true,
create_wsol_ata: true,
close_wsol_ata: true,
create_mint_ata: true,
open_seed_optimize: false,
custom_cu_limit: None,
};
client.buy(buy_params).await?;
// Sell tokens
println!("Selling tokens from Bonk...");
@@ -138,28 +130,27 @@ async fn bonk_sniper_trade_with_shreds(trade_info: BonkTradeEvent) -> AnyResult<
let amount_token = balance.amount.parse::<u64>().unwrap();
println!("Selling {} tokens", amount_token);
client
.sell(
DexType::Bonk,
mint_pubkey,
amount_token,
slippage_basis_points,
recent_blockhash,
None,
false,
Box::new(BonkParams::immediate_sell(
trade_info.base_token_program,
trade_info.platform_config,
trade_info.platform_associated_account,
trade_info.creator_associated_account,
)),
None,
true,
true,
true,
false,
)
.await?;
let sell_params = sol_trade_sdk::TradeSellParams {
dex_type: DexType::Bonk,
mint: mint_pubkey,
token_amount: amount_token,
slippage_basis_points: slippage_basis_points,
recent_blockhash: recent_blockhash,
extension_params: Box::new(BonkParams::immediate_sell(
trade_info.base_token_program,
trade_info.platform_config,
trade_info.platform_associated_account,
trade_info.creator_associated_account,
)),
lookup_table_key: None,
wait_transaction_confirmed: true,
create_wsol_ata: true,
close_wsol_ata: true,
open_seed_optimize: false,
with_tip: false,
custom_cu_limit: None,
};
client.sell(sell_params).await?;
// Exit program after completing the trade
std::process::exit(0);
+179 -199
View File
@@ -1,17 +1,15 @@
use clap::Parser;
use sol_trade_sdk::{
common::{
fast_fn::get_associated_token_address_with_program_id_fast_use_seed, AnyResult,
PriorityFee, TradeConfig,
},
swqos::SwqosConfig,
common::{fast_fn::get_associated_token_address_with_program_id_fast_use_seed, AnyResult},
constants::trade::trade::{DEFAULT_CU_LIMIT, DEFAULT_CU_PRICE},
swqos::{settings::SwqosSettings, SwqosConfig},
trading::{
core::params::{
BonkParams, PumpFunParams, PumpSwapParams, RaydiumAmmV4Params, RaydiumCpmmParams,
},
factory::DexType,
},
SolanaTrade,
SolanaTrade, TradeBuyParams, TradeSellParams,
};
use solana_sdk::{
commitment_config::CommitmentConfig, native_token::sol_str_to_lamports, pubkey::Pubkey,
@@ -604,24 +602,22 @@ async fn handle_buy_pumpfun(
let recent_blockhash = client.rpc.get_latest_blockhash().await?;
let sol_lamports = sol_str_to_lamports(sol_amount.to_string().as_str()).unwrap();
match client
.buy(
DexType::PumpFun,
mint_pubkey,
sol_lamports,
slippage,
recent_blockhash,
None,
Box::new(param),
None,
true,
false,
false,
create_mint_ata,
use_seed,
)
.await
{
let buy_params = TradeBuyParams {
dex_type: DexType::PumpFun,
mint: mint_pubkey,
sol_amount: sol_lamports,
slippage_basis_points: slippage,
recent_blockhash: recent_blockhash,
extension_params: Box::new(param),
lookup_table_key: None,
wait_transaction_confirmed: true,
create_wsol_ata: false,
close_wsol_ata: false,
create_mint_ata: create_mint_ata,
open_seed_optimize: use_seed,
custom_cu_limit: None,
};
match client.buy(buy_params).await {
Ok(signature) => {
println!(" ✅ Successfully bought tokens from PumpFun!");
println!(" ✅ Transaction Signature: {}", signature);
@@ -654,24 +650,22 @@ async fn handle_buy_pumpswap(
let recent_blockhash = client.rpc.get_latest_blockhash().await?;
let sol_lamports = sol_str_to_lamports(sol_amount.to_string().as_str()).unwrap();
match client
.buy(
DexType::PumpSwap,
mint_pubkey,
sol_lamports,
slippage,
recent_blockhash,
None,
Box::new(param),
None,
true,
true,
false,
create_mint_ata,
use_seed,
)
.await
{
let buy_params = TradeBuyParams {
dex_type: DexType::PumpSwap,
mint: mint_pubkey,
sol_amount: sol_lamports,
slippage_basis_points: slippage,
recent_blockhash: recent_blockhash,
extension_params: Box::new(param),
lookup_table_key: None,
wait_transaction_confirmed: true,
create_wsol_ata: true,
close_wsol_ata: false,
create_mint_ata: create_mint_ata,
open_seed_optimize: use_seed,
custom_cu_limit: None,
};
match client.buy(buy_params).await {
Ok(signature) => {
println!(" ✅ Successfully bought tokens from PumpSwap!");
println!(" ✅ Transaction Signature: {}", signature);
@@ -703,24 +697,22 @@ async fn handle_buy_bonk(
let recent_blockhash = client.rpc.get_latest_blockhash().await?;
let sol_lamports = sol_str_to_lamports(sol_amount.to_string().as_str()).unwrap();
match client
.buy(
DexType::Bonk,
mint_pubkey,
sol_lamports,
slippage,
recent_blockhash,
None,
Box::new(param),
None,
true,
true,
false,
create_mint_ata,
use_seed,
)
.await
{
let buy_params = TradeBuyParams {
dex_type: DexType::Bonk,
mint: mint_pubkey,
sol_amount: sol_lamports,
slippage_basis_points: slippage,
recent_blockhash: recent_blockhash,
extension_params: Box::new(param),
lookup_table_key: None,
wait_transaction_confirmed: true,
create_wsol_ata: true,
close_wsol_ata: false,
create_mint_ata: create_mint_ata,
open_seed_optimize: use_seed,
custom_cu_limit: None,
};
match client.buy(buy_params).await {
Ok(signature) => {
println!(" ✅ Successfully bought tokens from Bonk!");
println!(" ✅ Transaction Signature: {}", signature);
@@ -756,24 +748,22 @@ async fn handle_buy_raydium_v4(
let recent_blockhash = client.rpc.get_latest_blockhash().await?;
let sol_lamports = sol_str_to_lamports(sol_amount.to_string().as_str()).unwrap();
match client
.buy(
DexType::RaydiumAmmV4,
mint_pubkey,
sol_lamports,
slippage,
recent_blockhash,
None,
Box::new(param),
None,
true,
true,
false,
create_mint_ata,
use_seed,
)
.await
{
let buy_params = TradeBuyParams {
dex_type: DexType::RaydiumAmmV4,
mint: mint_pubkey,
sol_amount: sol_lamports,
slippage_basis_points: slippage,
recent_blockhash: recent_blockhash,
extension_params: Box::new(param),
lookup_table_key: None,
wait_transaction_confirmed: true,
create_wsol_ata: true,
close_wsol_ata: false,
create_mint_ata: create_mint_ata,
open_seed_optimize: use_seed,
custom_cu_limit: None,
};
match client.buy(buy_params).await {
Ok(signature) => {
println!(" ✅ Successfully bought tokens from Raydium V4!");
println!(" ✅ Transaction Signature: {}", signature);
@@ -809,24 +799,22 @@ async fn handle_buy_raydium_cpmm(
let recent_blockhash = client.rpc.get_latest_blockhash().await?;
let sol_lamports = sol_str_to_lamports(sol_amount.to_string().as_str()).unwrap();
match client
.buy(
DexType::RaydiumCpmm,
mint_pubkey,
sol_lamports,
slippage,
recent_blockhash,
None,
Box::new(param),
None,
true,
true,
false,
create_mint_ata,
use_seed,
)
.await
{
let buy_params = TradeBuyParams {
dex_type: DexType::RaydiumCpmm,
mint: mint_pubkey,
sol_amount: sol_lamports,
slippage_basis_points: slippage,
recent_blockhash: recent_blockhash,
extension_params: Box::new(param),
lookup_table_key: None,
wait_transaction_confirmed: true,
create_wsol_ata: true,
close_wsol_ata: false,
create_mint_ata: create_mint_ata,
open_seed_optimize: use_seed,
custom_cu_limit: None,
};
match client.buy(buy_params).await {
Ok(signature) => {
println!(" ✅ Successfully bought tokens from Raydium CPMM!");
println!(" ✅ Transaction Signature: {}", signature);
@@ -972,24 +960,23 @@ async fn handle_sell_pumpfun(
let param = PumpFunParams::from_mint_by_rpc(&client.rpc, &mint_pubkey).await?;
let recent_blockhash = client.rpc.get_latest_blockhash().await?;
match client
.sell(
DexType::PumpFun,
mint_pubkey,
amount as u64,
slippage,
recent_blockhash,
None,
false,
Box::new(param),
None,
true,
true,
false,
use_seed,
)
.await
{
let sell_params = TradeSellParams {
dex_type: DexType::PumpFun,
mint: mint_pubkey,
token_amount: amount as u64,
slippage_basis_points: slippage,
recent_blockhash: recent_blockhash,
with_tip: false,
extension_params: Box::new(param),
custom_cu_limit: None,
lookup_table_key: None,
wait_transaction_confirmed: true,
create_wsol_ata: true,
close_wsol_ata: false,
open_seed_optimize: use_seed,
};
match client.sell(sell_params).await {
Ok(signature) => {
println!(" ✅ Successfully sold tokens from PumpFun!");
println!(" ✅ Transaction Signature: {}", signature);
@@ -1024,24 +1011,22 @@ async fn handle_sell_pumpswap(
let param = PumpSwapParams::from_mint_by_rpc(&client.rpc, &mint_pubkey).await?;
let recent_blockhash = client.rpc.get_latest_blockhash().await?;
match client
.sell(
DexType::PumpSwap,
mint_pubkey,
amount as u64,
slippage,
recent_blockhash,
None,
false,
Box::new(param),
None,
true,
true,
false,
use_seed,
)
.await
{
let sell_params = TradeSellParams {
dex_type: DexType::PumpSwap,
mint: mint_pubkey,
token_amount: amount as u64,
slippage_basis_points: slippage,
recent_blockhash: recent_blockhash,
with_tip: false,
extension_params: Box::new(param),
custom_cu_limit: None,
lookup_table_key: None,
wait_transaction_confirmed: true,
create_wsol_ata: true,
close_wsol_ata: false,
open_seed_optimize: use_seed,
};
match client.sell(sell_params).await {
Ok(signature) => {
println!(" ✅ Successfully sold tokens from PumpSwap!");
println!(" ✅ Transaction Signature: {}", signature);
@@ -1076,24 +1061,22 @@ async fn handle_sell_bonk(
let param = BonkParams::from_mint_by_rpc(&client.rpc, &mint_pubkey).await?;
let recent_blockhash = client.rpc.get_latest_blockhash().await?;
match client
.sell(
DexType::Bonk,
mint_pubkey,
amount as u64,
slippage,
recent_blockhash,
None,
false,
Box::new(param),
None,
true,
true,
false,
use_seed,
)
.await
{
let sell_params = TradeSellParams {
dex_type: DexType::Bonk,
mint: mint_pubkey,
token_amount: amount as u64,
slippage_basis_points: slippage,
recent_blockhash: recent_blockhash,
with_tip: false,
extension_params: Box::new(param),
custom_cu_limit: None,
lookup_table_key: None,
wait_transaction_confirmed: true,
create_wsol_ata: true,
close_wsol_ata: false,
open_seed_optimize: use_seed,
};
match client.sell(sell_params).await {
Ok(signature) => {
println!(" ✅ Successfully sold tokens from Bonk!");
println!(" ✅ Transaction Signature: {}", signature);
@@ -1131,24 +1114,22 @@ async fn handle_sell_raydium_v4(
let param = RaydiumAmmV4Params::from_amm_address_by_rpc(&client.rpc, amm_pubkey).await?;
let recent_blockhash = client.rpc.get_latest_blockhash().await?;
match client
.sell(
DexType::RaydiumAmmV4,
mint_pubkey,
amount as u64,
slippage,
recent_blockhash,
None,
false,
Box::new(param),
None,
true,
true,
false,
use_seed,
)
.await
{
let sell_params = TradeSellParams {
dex_type: DexType::RaydiumAmmV4,
mint: mint_pubkey,
token_amount: amount as u64,
slippage_basis_points: slippage,
recent_blockhash: recent_blockhash,
with_tip: false,
extension_params: Box::new(param),
custom_cu_limit: None,
lookup_table_key: None,
wait_transaction_confirmed: true,
create_wsol_ata: true,
close_wsol_ata: false,
open_seed_optimize: use_seed,
};
match client.sell(sell_params).await {
Ok(signature) => {
println!(" ✅ Successfully sold tokens from Raydium V4!");
println!(" ✅ Transaction Signature: {}", signature);
@@ -1186,24 +1167,22 @@ async fn handle_sell_raydium_cpmm(
let param = RaydiumCpmmParams::from_pool_address_by_rpc(&client.rpc, &pool_pubkey).await?;
let recent_blockhash = client.rpc.get_latest_blockhash().await?;
match client
.sell(
DexType::RaydiumCpmm,
mint_pubkey,
amount as u64,
slippage,
recent_blockhash,
None,
false,
Box::new(param),
None,
true,
true,
false,
use_seed,
)
.await
{
let sell_params = TradeSellParams {
dex_type: DexType::RaydiumCpmm,
mint: mint_pubkey,
token_amount: amount as u64,
slippage_basis_points: slippage,
recent_blockhash: recent_blockhash,
with_tip: false,
extension_params: Box::new(param),
custom_cu_limit: None,
lookup_table_key: None,
wait_transaction_confirmed: true,
create_wsol_ata: true,
close_wsol_ata: false,
open_seed_optimize: use_seed,
};
match client.sell(sell_params).await {
Ok(signature) => {
println!(" ✅ Successfully sold tokens from Raydium CPMM!");
println!(" ✅ Transaction Signature: {}", signature);
@@ -1308,20 +1287,21 @@ async fn handle_wallet() -> Result<(), Box<dyn std::error::Error>> {
async fn initialize_real_client() -> AnyResult<SolanaTrade> {
// You need to update this with a real RPC URL
let swqos_configs = vec![SwqosConfig::Default(RPC_URL.to_string())];
let swqos_settings: Vec<SwqosSettings> = vec![SwqosSettings::new(
SwqosConfig::Default(RPC_URL.to_string()),
DEFAULT_CU_LIMIT,
DEFAULT_CU_PRICE,
0.0,
0.0,
)];
let mut priority_fee = PriorityFee::default();
priority_fee.rpc_unit_limit = 200000;
let trade_config = TradeConfig {
rpc_url: RPC_URL.to_string(),
commitment: CommitmentConfig::confirmed(),
priority_fee,
swqos_configs,
};
let client =
SolanaTrade::new(Arc::new(Keypair::try_from(&PAYER.to_bytes()[..]).unwrap()), trade_config)
.await;
let client = SolanaTrade::new(
Arc::new(Keypair::try_from(&PAYER.to_bytes()[..]).unwrap()),
RPC_URL.to_string(),
CommitmentConfig::confirmed(),
swqos_settings,
)
.await;
Ok(client)
}
+35 -36
View File
@@ -1,6 +1,8 @@
use anyhow::Result;
use sol_trade_sdk::{
common::{AnyResult, PriorityFee, TradeConfig},
common::AnyResult,
constants::trade::trade::{DEFAULT_CU_LIMIT, DEFAULT_CU_PRICE},
swqos::settings::SwqosSettings,
swqos::{SwqosConfig, SwqosRegion},
trading::{
core::params::PumpSwapParams, factory::DexType, middleware::builtin::LoggingMiddleware,
@@ -59,25 +61,20 @@ impl InstructionMiddleware for CustomMiddleware {
/// Create SolanaTrade client
/// Initializes a new SolanaTrade client with configuration
async fn create_solana_trade_client() -> AnyResult<SolanaTrade> {
println!("Creating SolanaTrade client...");
// In real transactions, use your own private key to initialize the payer
let payer = Keypair::new();
println!("🚀 Initializing SolanaTrade client...");
let payer = Keypair::from_base58_string("use_your_payer_keypair_here");
let rpc_url = "https://api.mainnet-beta.solana.com".to_string();
let swqos_configs = vec![SwqosConfig::Default(rpc_url.clone())];
let trade_config = TradeConfig {
rpc_url,
commitment: CommitmentConfig::confirmed(),
priority_fee: PriorityFee::default(),
swqos_configs,
};
let solana_trade_client = SolanaTrade::new(Arc::new(payer), trade_config).await;
println!("SolanaTrade client created successfully!");
Ok(solana_trade_client)
let commitment = CommitmentConfig::confirmed();
let swqos_settings: Vec<SwqosSettings> = vec![SwqosSettings::new(
SwqosConfig::Default(rpc_url.clone()),
DEFAULT_CU_LIMIT,
DEFAULT_CU_PRICE,
0.0,
0.0,
)];
let solana_trade = SolanaTrade::new(Arc::new(payer), rpc_url, commitment, swqos_settings).await;
println!("✅ SolanaTrade client initialized successfully!");
Ok(solana_trade)
}
async fn test_middleware() -> AnyResult<()> {
@@ -91,23 +88,25 @@ async fn test_middleware() -> AnyResult<()> {
let slippage_basis_points = Some(100);
let recent_blockhash = client.rpc.get_latest_blockhash().await?;
let pool_address = Pubkey::from_str("539m4mVWt6iduB6W8rDGPMarzNCMesuqY5eUTiiYHAgR")?;
client
.buy(
DexType::PumpSwap,
mint_pubkey,
buy_sol_cost,
slippage_basis_points,
recent_blockhash,
None,
Box::new(PumpSwapParams::from_pool_address_by_rpc(&client.rpc, &pool_address).await?),
None,
true,
true,
true,
true,
false,
)
.await?;
let buy_params = sol_trade_sdk::TradeBuyParams {
dex_type: DexType::PumpSwap,
mint: mint_pubkey,
sol_amount: buy_sol_cost,
slippage_basis_points: slippage_basis_points,
recent_blockhash: recent_blockhash,
extension_params: Box::new(
PumpSwapParams::from_pool_address_by_rpc(&client.rpc, &pool_address).await?,
),
custom_cu_limit: None,
lookup_table_key: None,
wait_transaction_confirmed: true,
create_wsol_ata: true,
close_wsol_ata: true,
create_mint_ata: true,
open_seed_optimize: false,
};
client.buy(buy_params).await?;
println!("tip: This transaction will not succeed because we're using a test account. You can modify the code to initialize the payer with your own private key");
Ok(())
}
+31 -38
View File
@@ -17,7 +17,9 @@ use sol_trade_sdk::{
solana_streamer_sdk::streaming::event_parser::protocols::pumpfun::parser::PUMPFUN_PROGRAM_ID,
};
use sol_trade_sdk::{
common::{AnyResult, PriorityFee, TradeConfig},
common::AnyResult,
constants::trade::trade::{DEFAULT_CU_LIMIT, DEFAULT_CU_PRICE},
swqos::settings::SwqosSettings,
swqos::SwqosConfig,
trading::{core::params::PumpFunParams, factory::DexType},
SolanaTrade,
@@ -98,28 +100,20 @@ fn create_event_callback() -> impl Fn(Box<dyn UnifiedEvent>) {
/// Create SolanaTrade client
/// Initializes a new SolanaTrade client with configuration
async fn create_solana_trade_client() -> AnyResult<SolanaTrade> {
println!("Creating SolanaTrade client...");
println!("🚀 Initializing SolanaTrade client...");
let payer = Keypair::from_base58_string("use_your_payer_keypair_here");
let rpc_url = "https://api.mainnet-beta.solana.com".to_string();
let swqos_configs = vec![SwqosConfig::Default(rpc_url.clone())];
let mut priority_fee = PriorityFee::default();
// Configure according to your needs
priority_fee.rpc_unit_limit = 100000;
let trade_config = TradeConfig {
rpc_url,
commitment: CommitmentConfig::confirmed(),
priority_fee: priority_fee,
swqos_configs,
};
let solana_trade_client = SolanaTrade::new(Arc::new(payer), trade_config).await;
println!("SolanaTrade client created successfully!");
Ok(solana_trade_client)
let commitment = CommitmentConfig::confirmed();
let swqos_settings: Vec<SwqosSettings> = vec![SwqosSettings::new(
SwqosConfig::Default(rpc_url.clone()),
DEFAULT_CU_LIMIT,
DEFAULT_CU_PRICE,
0.0,
0.0,
)];
let solana_trade = SolanaTrade::new(Arc::new(payer), rpc_url, commitment, swqos_settings).await;
println!("✅ SolanaTrade client initialized successfully!");
Ok(solana_trade)
}
/// PumpFun sniper trade
@@ -141,23 +135,22 @@ async fn pumpfun_copy_trade_with_grpc(trade_info: PumpFunTradeEvent) -> AnyResul
// Buy tokens
println!("Buying tokens from PumpFun...");
let buy_sol_amount = 100_000;
client
.buy(
DexType::PumpFun,
mint_pubkey,
buy_sol_amount,
slippage_basis_points,
last_nonce,
None,
Box::new(PumpFunParams::from_trade(&trade_info, None)),
None,
true,
false,
false,
true,
false,
)
.await?;
let buy_params = sol_trade_sdk::TradeBuyParams {
dex_type: DexType::PumpFun,
mint: mint_pubkey,
sol_amount: buy_sol_amount,
slippage_basis_points: slippage_basis_points,
recent_blockhash: last_nonce,
extension_params: Box::new(PumpFunParams::from_trade(&trade_info, None)),
custom_cu_limit: None,
lookup_table_key: None,
wait_transaction_confirmed: true,
create_wsol_ata: false,
close_wsol_ata: false,
create_mint_ata: true,
open_seed_optimize: false,
};
client.buy(buy_params).await?;
// Exit program
std::process::exit(0);
+47 -55
View File
@@ -14,7 +14,9 @@ use sol_trade_sdk::solana_streamer_sdk::streaming::yellowstone_grpc::{
};
use sol_trade_sdk::solana_streamer_sdk::streaming::YellowstoneGrpc;
use sol_trade_sdk::{
common::{AnyResult, PriorityFee, TradeConfig},
common::AnyResult,
constants::trade::trade::{DEFAULT_CU_LIMIT, DEFAULT_CU_PRICE},
swqos::settings::SwqosSettings,
swqos::SwqosConfig,
trading::{core::params::PumpFunParams, factory::DexType},
SolanaTrade,
@@ -97,28 +99,20 @@ fn create_event_callback() -> impl Fn(Box<dyn UnifiedEvent>) {
/// Create SolanaTrade client
/// Initializes a new SolanaTrade client with configuration
async fn create_solana_trade_client() -> AnyResult<SolanaTrade> {
println!("Creating SolanaTrade client...");
println!("🚀 Initializing SolanaTrade client...");
let payer = Keypair::from_base58_string("use_your_payer_keypair_here");
let rpc_url = "https://api.mainnet-beta.solana.com".to_string();
let swqos_configs = vec![SwqosConfig::Default(rpc_url.clone())];
let mut priority_fee = PriorityFee::default();
// Configure according to your needs
priority_fee.rpc_unit_limit = 100000;
let trade_config = TradeConfig {
rpc_url,
commitment: CommitmentConfig::confirmed(),
priority_fee: priority_fee,
swqos_configs,
};
let solana_trade_client = SolanaTrade::new(Arc::new(payer), trade_config).await;
println!("SolanaTrade client created successfully!");
Ok(solana_trade_client)
let commitment = CommitmentConfig::confirmed();
let swqos_settings: Vec<SwqosSettings> = vec![SwqosSettings::new(
SwqosConfig::Default(rpc_url.clone()),
DEFAULT_CU_LIMIT,
DEFAULT_CU_PRICE,
0.0,
0.0,
)];
let solana_trade = SolanaTrade::new(Arc::new(payer), rpc_url, commitment, swqos_settings).await;
println!("✅ SolanaTrade client initialized successfully!");
Ok(solana_trade)
}
/// PumpFun sniper trade
@@ -134,23 +128,22 @@ async fn pumpfun_copy_trade_with_grpc(trade_info: PumpFunTradeEvent) -> AnyResul
// Buy tokens
println!("Buying tokens from PumpFun...");
let buy_sol_amount = 100_000;
client
.buy(
DexType::PumpFun,
mint_pubkey,
buy_sol_amount,
slippage_basis_points,
recent_blockhash,
None,
Box::new(PumpFunParams::from_trade(&trade_info, None)),
None,
true,
false,
false,
true,
false,
)
.await?;
let buy_params = sol_trade_sdk::TradeBuyParams {
dex_type: DexType::PumpFun,
mint: mint_pubkey,
sol_amount: buy_sol_amount,
slippage_basis_points: slippage_basis_points,
recent_blockhash: recent_blockhash,
extension_params: Box::new(PumpFunParams::from_trade(&trade_info, None)),
custom_cu_limit: None,
lookup_table_key: None,
wait_transaction_confirmed: true,
create_wsol_ata: false,
close_wsol_ata: false,
create_mint_ata: true,
open_seed_optimize: false,
};
client.buy(buy_params).await?;
// Sell tokens
println!("Selling tokens from PumpFun...");
@@ -163,23 +156,22 @@ async fn pumpfun_copy_trade_with_grpc(trade_info: PumpFunTradeEvent) -> AnyResul
let amount_token = balance.amount.parse::<u64>().unwrap();
println!("Selling {} tokens", amount_token);
client
.sell(
DexType::PumpFun,
mint_pubkey,
amount_token,
slippage_basis_points,
recent_blockhash,
None,
false,
Box::new(PumpFunParams::from_trade(&trade_info, Some(true))),
None,
true,
false,
false,
false,
)
.await?;
let sell_params = sol_trade_sdk::TradeSellParams {
dex_type: DexType::PumpFun,
mint: mint_pubkey,
token_amount: amount_token,
slippage_basis_points: slippage_basis_points,
recent_blockhash: recent_blockhash,
with_tip: false,
extension_params: Box::new(PumpFunParams::from_trade(&trade_info, Some(true))),
custom_cu_limit: None,
lookup_table_key: None,
wait_transaction_confirmed: true,
create_wsol_ata: false,
close_wsol_ata: false,
open_seed_optimize: false,
};
client.sell(sell_params).await?;
// PumpFunParams can also be set as PumpFunParams::immediate_sell(creator_vault, close_token_account_when_sell)
// creator_vault can be obtained from the trade event
+47 -55
View File
@@ -4,7 +4,9 @@ use sol_trade_sdk::solana_streamer_sdk::streaming::event_parser::protocols::pump
use sol_trade_sdk::solana_streamer_sdk::streaming::event_parser::{Protocol, UnifiedEvent};
use sol_trade_sdk::solana_streamer_sdk::{match_event, streaming::ShredStreamGrpc};
use sol_trade_sdk::{
common::{AnyResult, PriorityFee, TradeConfig},
common::AnyResult,
constants::trade::trade::{DEFAULT_CU_LIMIT, DEFAULT_CU_PRICE},
swqos::settings::SwqosSettings,
swqos::SwqosConfig,
trading::{core::params::PumpFunParams, factory::DexType},
SolanaTrade,
@@ -65,28 +67,20 @@ fn create_event_callback() -> impl Fn(Box<dyn UnifiedEvent>) {
/// Create SolanaTrade client
/// Initializes a new SolanaTrade client with configuration
async fn create_solana_trade_client() -> AnyResult<SolanaTrade> {
println!("Creating SolanaTrade client...");
println!("🚀 Initializing SolanaTrade client...");
let payer = Keypair::from_base58_string("use_your_payer_keypair_here");
let rpc_url = "https://api.mainnet-beta.solana.com".to_string();
let swqos_configs = vec![SwqosConfig::Default(rpc_url.clone())];
let mut priority_fee = PriorityFee::default();
// Set RPC unit limit based on your requirements
priority_fee.rpc_unit_limit = 100000;
let trade_config = TradeConfig {
rpc_url,
commitment: CommitmentConfig::confirmed(),
priority_fee: priority_fee,
swqos_configs,
};
let solana_trade_client = SolanaTrade::new(Arc::new(payer), trade_config).await;
println!("SolanaTrade client created successfully!");
Ok(solana_trade_client)
let commitment = CommitmentConfig::confirmed();
let swqos_settings: Vec<SwqosSettings> = vec![SwqosSettings::new(
SwqosConfig::Default(rpc_url.clone()),
DEFAULT_CU_LIMIT,
DEFAULT_CU_PRICE,
0.0,
0.0,
)];
let solana_trade = SolanaTrade::new(Arc::new(payer), rpc_url, commitment, swqos_settings).await;
println!("✅ SolanaTrade client initialized successfully!");
Ok(solana_trade)
}
/// Execute PumpFun sniper trading strategy based on received token creation event
@@ -102,23 +96,22 @@ async fn pumpfun_sniper_trade_with_shreds(trade_info: PumpFunTradeEvent) -> AnyR
// Buy tokens
println!("Buying tokens from PumpFun...");
let buy_sol_amount = 100_000;
client
.buy(
DexType::PumpFun,
mint_pubkey,
buy_sol_amount,
slippage_basis_points,
recent_blockhash,
None,
Box::new(PumpFunParams::from_dev_trade(&trade_info, None)),
None,
true,
true,
true,
true,
false,
)
.await?;
let buy_params = sol_trade_sdk::TradeBuyParams {
dex_type: DexType::PumpFun,
mint: mint_pubkey,
sol_amount: buy_sol_amount,
slippage_basis_points: slippage_basis_points,
recent_blockhash: recent_blockhash,
extension_params: Box::new(PumpFunParams::from_dev_trade(&trade_info, None)),
custom_cu_limit: None,
lookup_table_key: None,
wait_transaction_confirmed: true,
create_wsol_ata: true,
close_wsol_ata: true,
create_mint_ata: true,
open_seed_optimize: false,
};
client.buy(buy_params).await?;
// Sell tokens
println!("Selling tokens from PumpFun...");
@@ -131,23 +124,22 @@ async fn pumpfun_sniper_trade_with_shreds(trade_info: PumpFunTradeEvent) -> AnyR
let amount_token = balance.amount.parse::<u64>().unwrap();
println!("Selling {} tokens", amount_token);
client
.sell(
DexType::PumpFun,
mint_pubkey,
amount_token,
slippage_basis_points,
recent_blockhash,
None,
false,
Box::new(PumpFunParams::immediate_sell(trade_info.creator_vault, true)),
None,
true,
true,
true,
false,
)
.await?;
let sell_params = sol_trade_sdk::TradeSellParams {
dex_type: DexType::PumpFun,
mint: mint_pubkey,
token_amount: amount_token,
slippage_basis_points: slippage_basis_points,
recent_blockhash: recent_blockhash,
with_tip: false,
extension_params: Box::new(PumpFunParams::immediate_sell(trade_info.creator_vault, true)),
custom_cu_limit: None,
lookup_table_key: None,
wait_transaction_confirmed: true,
create_wsol_ata: true,
close_wsol_ata: true,
open_seed_optimize: false,
};
client.sell(sell_params).await?;
// PumpFunParams can also be set as PumpFunParams::immediate_sell(creator_vault, close_token_account_when_sell)
// creator_vault can be obtained from the trade event
+52 -57
View File
@@ -1,5 +1,7 @@
use sol_trade_sdk::{
common::{AnyResult, PriorityFee, TradeConfig},
common::AnyResult,
constants::trade::trade::{DEFAULT_CU_LIMIT, DEFAULT_CU_PRICE},
swqos::settings::SwqosSettings,
swqos::SwqosConfig,
trading::{core::params::PumpSwapParams, factory::DexType},
SolanaTrade,
@@ -22,23 +24,24 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
// Buy tokens
println!("Buying tokens from PumpSwap...");
let buy_sol_amount = 100_000;
client
.buy(
DexType::PumpSwap,
mint_pubkey,
buy_sol_amount,
slippage_basis_points,
recent_blockhash,
None,
Box::new(PumpSwapParams::from_pool_address_by_rpc(&client.rpc, &pool).await?),
None,
true,
true,
true,
true,
false,
)
.await?;
let buy_params = sol_trade_sdk::TradeBuyParams {
dex_type: DexType::PumpSwap,
mint: mint_pubkey,
sol_amount: buy_sol_amount,
slippage_basis_points: slippage_basis_points,
recent_blockhash: recent_blockhash,
extension_params: Box::new(
PumpSwapParams::from_pool_address_by_rpc(&client.rpc, &pool).await?,
),
custom_cu_limit: None,
lookup_table_key: None,
wait_transaction_confirmed: true,
create_wsol_ata: true,
close_wsol_ata: true,
create_mint_ata: true,
open_seed_optimize: false,
};
client.buy(buy_params).await?;
// Sell tokens
println!("Selling tokens from PumpSwap...");
@@ -49,23 +52,24 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
let account = get_associated_token_address_with_program_id(&payer, &mint_pubkey, &program_id);
let balance = rpc.get_token_account_balance(&account).await?;
let amount_token = balance.amount.parse::<u64>().unwrap();
client
.sell(
DexType::PumpSwap,
mint_pubkey,
amount_token,
slippage_basis_points,
recent_blockhash,
None,
false,
Box::new(PumpSwapParams::from_pool_address_by_rpc(&client.rpc, &pool).await?),
None,
true,
true,
true,
false,
)
.await?;
let sell_params = sol_trade_sdk::TradeSellParams {
dex_type: DexType::PumpSwap,
mint: mint_pubkey,
token_amount: amount_token,
slippage_basis_points: slippage_basis_points,
recent_blockhash: recent_blockhash,
with_tip: false,
extension_params: Box::new(
PumpSwapParams::from_pool_address_by_rpc(&client.rpc, &pool).await?,
),
custom_cu_limit: None,
lookup_table_key: None,
wait_transaction_confirmed: true,
create_wsol_ata: true,
close_wsol_ata: true,
open_seed_optimize: false,
};
client.sell(sell_params).await?;
tokio::signal::ctrl_c().await?;
Ok(())
@@ -74,27 +78,18 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
/// Create SolanaTrade client
/// Initializes a new SolanaTrade client with configuration
async fn create_solana_trade_client() -> AnyResult<SolanaTrade> {
println!("Creating SolanaTrade client...");
let payer = Keypair::from_base58_string("use_your_own_keypair");
println!("🚀 Initializing SolanaTrade client...");
let payer = Keypair::from_base58_string("use_your_payer_keypair_here");
let rpc_url = "https://api.mainnet-beta.solana.com".to_string();
let swqos_configs = vec![SwqosConfig::Default(rpc_url.clone())];
let mut priority_fee = PriorityFee::default();
priority_fee.buy_tip_fees = vec![0.001];
// Configure according to your needs
priority_fee.rpc_unit_limit = 150000;
let trade_config = TradeConfig {
rpc_url,
commitment: CommitmentConfig::confirmed(),
priority_fee: priority_fee,
swqos_configs,
};
let solana_trade_client = SolanaTrade::new(Arc::new(payer), trade_config).await;
println!("SolanaTrade client created successfully!");
Ok(solana_trade_client)
let commitment = CommitmentConfig::confirmed();
let swqos_settings: Vec<SwqosSettings> = vec![SwqosSettings::new(
SwqosConfig::Default(rpc_url.clone()),
DEFAULT_CU_LIMIT,
DEFAULT_CU_PRICE,
0.0,
0.0,
)];
let solana_trade = SolanaTrade::new(Arc::new(payer), rpc_url, commitment, swqos_settings).await;
println!("✅ SolanaTrade client initialized successfully!");
Ok(solana_trade)
}
+50 -56
View File
@@ -6,7 +6,6 @@ use std::sync::{
use sol_trade_sdk::solana_streamer_sdk::streaming::event_parser::{
common::EventType, protocols::pumpswap::PumpSwapSellEvent,
};
use sol_trade_sdk::solana_streamer_sdk::streaming::event_parser::{Protocol, UnifiedEvent};
use sol_trade_sdk::solana_streamer_sdk::streaming::yellowstone_grpc::{
AccountFilter, TransactionFilter,
};
@@ -15,7 +14,8 @@ use sol_trade_sdk::solana_streamer_sdk::{
match_event, streaming::event_parser::protocols::pumpswap::parser::PUMPSWAP_PROGRAM_ID,
};
use sol_trade_sdk::{
common::{AnyResult, PriorityFee, TradeConfig},
common::AnyResult,
constants::trade::trade::{DEFAULT_CU_LIMIT, DEFAULT_CU_PRICE},
swqos::SwqosConfig,
trading::{core::params::PumpSwapParams, factory::DexType},
SolanaTrade,
@@ -26,6 +26,10 @@ use sol_trade_sdk::{
common::filter::EventTypeFilter, protocols::pumpswap::PumpSwapBuyEvent,
},
};
use sol_trade_sdk::{
solana_streamer_sdk::streaming::event_parser::{Protocol, UnifiedEvent},
swqos::settings::SwqosSettings,
};
use solana_sdk::{commitment_config::CommitmentConfig, signature::Keypair};
use solana_sdk::{pubkey::Pubkey, signer::Signer};
use spl_associated_token_account::get_associated_token_address_with_program_id;
@@ -120,28 +124,20 @@ fn create_event_callback() -> impl Fn(Box<dyn UnifiedEvent>) {
/// Create SolanaTrade client
/// Initializes a new SolanaTrade client with configuration
async fn create_solana_trade_client() -> AnyResult<SolanaTrade> {
println!("Creating SolanaTrade client...");
println!("🚀 Initializing SolanaTrade client...");
let payer = Keypair::from_base58_string("use_your_payer_keypair_here");
let rpc_url = "https://api.mainnet-beta.solana.com".to_string();
let swqos_configs = vec![SwqosConfig::Default(rpc_url.clone())];
let mut priority_fee = PriorityFee::default();
// Configure according to your needs
priority_fee.rpc_unit_limit = 150000;
let trade_config = TradeConfig {
rpc_url,
commitment: CommitmentConfig::confirmed(),
priority_fee: priority_fee,
swqos_configs,
};
let solana_trade_client = SolanaTrade::new(Arc::new(payer), trade_config).await;
println!("SolanaTrade client created successfully!");
Ok(solana_trade_client)
let commitment = CommitmentConfig::confirmed();
let swqos_settings: Vec<SwqosSettings> = vec![SwqosSettings::new(
SwqosConfig::Default(rpc_url.clone()),
DEFAULT_CU_LIMIT,
DEFAULT_CU_PRICE,
0.0,
0.0,
)];
let solana_trade = SolanaTrade::new(Arc::new(payer), rpc_url, commitment, swqos_settings).await;
println!("✅ SolanaTrade client initialized successfully!");
Ok(solana_trade)
}
async fn pumpswap_trade_with_grpc_buy_event(trade_info: PumpSwapBuyEvent) -> AnyResult<()> {
@@ -176,23 +172,22 @@ async fn pumpswap_trade_with_grpc(mint_pubkey: Pubkey, params: PumpSwapParams) -
// Buy tokens
println!("Buying tokens from PumpSwap...");
let buy_sol_amount = 100_000;
client
.buy(
DexType::PumpSwap,
mint_pubkey,
buy_sol_amount,
slippage_basis_points,
recent_blockhash,
None,
Box::new(params.clone()),
None,
true,
true,
true,
true,
false,
)
.await?;
let buy_params = sol_trade_sdk::TradeBuyParams {
dex_type: DexType::PumpSwap,
mint: mint_pubkey,
sol_amount: buy_sol_amount,
slippage_basis_points: slippage_basis_points,
recent_blockhash: recent_blockhash,
extension_params: Box::new(params.clone()),
custom_cu_limit: None,
lookup_table_key: None,
wait_transaction_confirmed: true,
create_wsol_ata: true,
close_wsol_ata: true,
create_mint_ata: true,
open_seed_optimize: false,
};
client.buy(buy_params).await?;
// Sell tokens
println!("Selling tokens from PumpSwap...");
@@ -207,23 +202,22 @@ async fn pumpswap_trade_with_grpc(mint_pubkey: Pubkey, params: PumpSwapParams) -
let account = get_associated_token_address_with_program_id(&payer, &mint_pubkey, &program_id);
let balance = rpc.get_token_account_balance(&account).await?;
let amount_token = balance.amount.parse::<u64>().unwrap();
client
.sell(
DexType::PumpSwap,
mint_pubkey,
amount_token,
slippage_basis_points,
recent_blockhash,
None,
false,
Box::new(params.clone()),
None,
true,
true,
true,
false,
)
.await?;
let sell_params = sol_trade_sdk::TradeSellParams {
dex_type: DexType::PumpSwap,
mint: mint_pubkey,
token_amount: amount_token,
slippage_basis_points: slippage_basis_points,
recent_blockhash: recent_blockhash,
with_tip: false,
extension_params: Box::new(params.clone()),
custom_cu_limit: None,
lookup_table_key: None,
wait_transaction_confirmed: true,
create_wsol_ata: true,
close_wsol_ata: true,
open_seed_optimize: false,
};
client.sell(sell_params).await?;
// Exit program
std::process::exit(0);
+47 -56
View File
@@ -7,13 +7,14 @@ use sol_trade_sdk::{instruction::utils::raydium_amm_v4::{accounts, fetch_amm_inf
use sol_trade_sdk::solana_streamer_sdk::streaming::event_parser::common::filter::EventTypeFilter;
use sol_trade_sdk::solana_streamer_sdk::streaming::event_parser::common::EventType;
use sol_trade_sdk::solana_streamer_sdk::streaming::event_parser::protocols::raydium_amm_v4::parser::RAYDIUM_AMM_V4_PROGRAM_ID;
use sol_trade_sdk::solana_streamer_sdk::streaming::event_parser::{Protocol, UnifiedEvent};
use sol_trade_sdk::{solana_streamer_sdk::streaming::event_parser::{Protocol, UnifiedEvent}, swqos::settings::SwqosSettings};
use sol_trade_sdk::solana_streamer_sdk::streaming::yellowstone_grpc::{
AccountFilter, TransactionFilter,
};
use sol_trade_sdk::solana_streamer_sdk::streaming::YellowstoneGrpc;
use sol_trade_sdk::{
common::{AnyResult, PriorityFee, TradeConfig},
common::AnyResult,
constants::trade::trade::{DEFAULT_CU_LIMIT, DEFAULT_CU_PRICE},
swqos::SwqosConfig,
trading::{core::params::RaydiumAmmV4Params, factory::DexType},
SolanaTrade,
@@ -97,28 +98,20 @@ fn create_event_callback() -> impl Fn(Box<dyn UnifiedEvent>) {
/// Create SolanaTrade client
/// Initializes a new SolanaTrade client with configuration
async fn create_solana_trade_client() -> AnyResult<SolanaTrade> {
println!("Creating SolanaTrade client...");
println!("🚀 Initializing SolanaTrade client...");
let payer = Keypair::from_base58_string("use_your_payer_keypair_here");
let rpc_url = "https://api.mainnet-beta.solana.com".to_string();
let swqos_configs = vec![SwqosConfig::Default(rpc_url.clone())];
let mut priority_fee = PriorityFee::default();
// Configure according to your needs
priority_fee.rpc_unit_limit = 150000;
let trade_config = TradeConfig {
rpc_url,
commitment: CommitmentConfig::confirmed(),
priority_fee: priority_fee,
swqos_configs,
};
let solana_trade_client = SolanaTrade::new(Arc::new(payer), trade_config).await;
println!("SolanaTrade client created successfully!");
Ok(solana_trade_client)
let commitment = CommitmentConfig::confirmed();
let swqos_settings: Vec<SwqosSettings> = vec![SwqosSettings::new(
SwqosConfig::Default(rpc_url.clone()),
DEFAULT_CU_LIMIT,
DEFAULT_CU_PRICE,
0.0,
0.0,
)];
let solana_trade = SolanaTrade::new(Arc::new(payer), rpc_url, commitment, swqos_settings).await;
println!("✅ SolanaTrade client initialized successfully!");
Ok(solana_trade)
}
/// Raydium_amm_v4 sniper trade
@@ -147,23 +140,22 @@ async fn raydium_amm_v4_copy_trade_with_grpc(trade_info: RaydiumAmmV4SwapEvent)
// Buy tokens
println!("Buying tokens from Raydium_amm_v4...");
let buy_sol_amount = 100_000;
client
.buy(
DexType::RaydiumAmmV4,
mint_pubkey,
buy_sol_amount,
slippage_basis_points,
recent_blockhash,
None,
Box::new(params),
None,
true,
true,
true,
true,
false,
)
.await?;
let buy_params = sol_trade_sdk::TradeBuyParams {
dex_type: DexType::RaydiumAmmV4,
mint: mint_pubkey,
sol_amount: buy_sol_amount,
slippage_basis_points: slippage_basis_points,
recent_blockhash: recent_blockhash,
extension_params: Box::new(params),
custom_cu_limit: None,
lookup_table_key: None,
wait_transaction_confirmed: true,
create_wsol_ata: true,
close_wsol_ata: true,
create_mint_ata: true,
open_seed_optimize: false,
};
client.buy(buy_params).await?;
// Sell tokens
println!("Selling tokens from Raydium_amm_v4...");
@@ -177,23 +169,22 @@ async fn raydium_amm_v4_copy_trade_with_grpc(trade_info: RaydiumAmmV4SwapEvent)
println!("Selling {} tokens", amount_token);
let params = RaydiumAmmV4Params::from_amm_address_by_rpc(&client.rpc, trade_info.amm).await?;
client
.sell(
DexType::RaydiumAmmV4,
mint_pubkey,
amount_token,
slippage_basis_points,
recent_blockhash,
None,
false,
Box::new(params),
None,
true,
true,
true,
false,
)
.await?;
let sell_params = sol_trade_sdk::TradeSellParams {
dex_type: DexType::RaydiumAmmV4,
mint: mint_pubkey,
token_amount: amount_token,
slippage_basis_points: slippage_basis_points,
recent_blockhash: recent_blockhash,
with_tip: false,
extension_params: Box::new(params),
custom_cu_limit: None,
lookup_table_key: None,
wait_transaction_confirmed: true,
create_wsol_ata: true,
close_wsol_ata: true,
open_seed_optimize: false,
};
client.sell(sell_params).await?;
// Exit program
std::process::exit(0);
+48 -58
View File
@@ -3,7 +3,6 @@ use std::sync::{
Arc,
};
use sol_trade_sdk::solana_streamer_sdk::streaming::event_parser::{Protocol, UnifiedEvent};
use sol_trade_sdk::solana_streamer_sdk::streaming::yellowstone_grpc::{
AccountFilter, TransactionFilter,
};
@@ -11,10 +10,11 @@ use sol_trade_sdk::solana_streamer_sdk::streaming::YellowstoneGrpc;
use sol_trade_sdk::solana_streamer_sdk::{
match_event, streaming::event_parser::protocols::raydium_cpmm::RaydiumCpmmSwapEvent,
};
use sol_trade_sdk::{common::AnyResult, swqos::SwqosConfig, SolanaTrade};
use sol_trade_sdk::{
common::{AnyResult, PriorityFee, TradeConfig},
swqos::SwqosConfig,
SolanaTrade,
constants::trade::trade::{DEFAULT_CU_LIMIT, DEFAULT_CU_PRICE},
solana_streamer_sdk::streaming::event_parser::{Protocol, UnifiedEvent},
swqos::settings::SwqosSettings,
};
use sol_trade_sdk::{
instruction::utils::raydium_cpmm::accounts,
@@ -107,28 +107,20 @@ fn create_event_callback() -> impl Fn(Box<dyn UnifiedEvent>) {
/// Create SolanaTrade client
/// Initializes a new SolanaTrade client with configuration
async fn create_solana_trade_client() -> AnyResult<SolanaTrade> {
println!("Creating SolanaTrade client...");
println!("🚀 Initializing SolanaTrade client...");
let payer = Keypair::from_base58_string("use_your_payer_keypair_here");
let rpc_url = "https://api.mainnet-beta.solana.com".to_string();
let swqos_configs = vec![SwqosConfig::Default(rpc_url.clone())];
let mut priority_fee = PriorityFee::default();
// Configure according to your needs
priority_fee.rpc_unit_limit = 150000;
let trade_config = TradeConfig {
rpc_url,
commitment: CommitmentConfig::confirmed(),
priority_fee: priority_fee,
swqos_configs,
};
let solana_trade_client = SolanaTrade::new(Arc::new(payer), trade_config).await;
println!("SolanaTrade client created successfully!");
Ok(solana_trade_client)
let commitment = CommitmentConfig::confirmed();
let swqos_settings: Vec<SwqosSettings> = vec![SwqosSettings::new(
SwqosConfig::Default(rpc_url.clone()),
DEFAULT_CU_LIMIT,
DEFAULT_CU_PRICE,
0.0,
0.0,
)];
let solana_trade = SolanaTrade::new(Arc::new(payer), rpc_url, commitment, swqos_settings).await;
println!("✅ SolanaTrade client initialized successfully!");
Ok(solana_trade)
}
/// Raydium_cpmm sniper trade
@@ -151,23 +143,22 @@ async fn raydium_cpmm_copy_trade_with_grpc(trade_info: RaydiumCpmmSwapEvent) ->
// Buy tokens
println!("Buying tokens from Raydium_cpmm...");
let buy_sol_amount = 100_000;
client
.buy(
DexType::RaydiumCpmm,
mint_pubkey,
buy_sol_amount,
slippage_basis_points,
recent_blockhash,
None,
Box::new(buy_params),
None,
true,
true,
true,
true,
false,
)
.await?;
let buy_params = sol_trade_sdk::TradeBuyParams {
dex_type: DexType::RaydiumCpmm,
mint: mint_pubkey,
sol_amount: buy_sol_amount,
slippage_basis_points: slippage_basis_points,
recent_blockhash: recent_blockhash,
extension_params: Box::new(buy_params),
custom_cu_limit: None,
lookup_table_key: None,
wait_transaction_confirmed: true,
create_wsol_ata: true,
close_wsol_ata: true,
create_mint_ata: true,
open_seed_optimize: false,
};
client.buy(buy_params).await?;
// Sell tokens
println!("Selling tokens from Raydium_cpmm...");
@@ -183,23 +174,22 @@ async fn raydium_cpmm_copy_trade_with_grpc(trade_info: RaydiumCpmmSwapEvent) ->
RaydiumCpmmParams::from_pool_address_by_rpc(&client.rpc, &trade_info.pool_state).await?;
println!("Selling {} tokens", amount_token);
client
.sell(
DexType::RaydiumCpmm,
mint_pubkey,
amount_token,
slippage_basis_points,
recent_blockhash,
None,
false,
Box::new(sell_params),
None,
true,
true,
true,
false,
)
.await?;
let sell_params = sol_trade_sdk::TradeSellParams {
dex_type: DexType::RaydiumCpmm,
mint: mint_pubkey,
token_amount: amount_token,
slippage_basis_points: slippage_basis_points,
recent_blockhash: recent_blockhash,
with_tip: false,
extension_params: Box::new(sell_params),
custom_cu_limit: None,
lookup_table_key: None,
wait_transaction_confirmed: true,
create_wsol_ata: true,
close_wsol_ata: true,
open_seed_optimize: false,
};
client.sell(sell_params).await?;
// Exit program
std::process::exit(0);
+52 -61
View File
@@ -1,9 +1,7 @@
use sol_trade_sdk::{
common::{
fast_fn::get_associated_token_address_with_program_id_fast_use_seed, AnyResult,
PriorityFee, TradeConfig,
},
swqos::SwqosConfig,
common::{fast_fn::get_associated_token_address_with_program_id_fast_use_seed, AnyResult},
constants::trade::trade::{DEFAULT_CU_LIMIT, DEFAULT_CU_PRICE},
swqos::{settings::SwqosSettings, SwqosConfig},
trading::{core::params::PumpSwapParams, factory::DexType},
SolanaTrade,
};
@@ -24,23 +22,24 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
// Buy tokens
println!("Buying tokens from PumpSwap...");
let buy_sol_amount = 100_000;
client
.buy(
DexType::PumpSwap,
mint_pubkey,
buy_sol_amount,
slippage_basis_points,
recent_blockhash,
None,
Box::new(PumpSwapParams::from_pool_address_by_rpc(&client.rpc, &pool).await?),
None,
true,
true,
true,
true,
true, // ❗️❗️❗️❗️ open seed optimize
)
.await?;
let buy_params = sol_trade_sdk::TradeBuyParams {
dex_type: DexType::PumpSwap,
mint: mint_pubkey,
sol_amount: buy_sol_amount,
slippage_basis_points: slippage_basis_points,
recent_blockhash: recent_blockhash,
extension_params: Box::new(
PumpSwapParams::from_pool_address_by_rpc(&client.rpc, &pool).await?,
),
custom_cu_limit: None,
lookup_table_key: None,
wait_transaction_confirmed: true,
create_wsol_ata: true,
close_wsol_ata: true,
create_mint_ata: true,
open_seed_optimize: true, // ❗️❗️❗️❗️ open seed optimize
};
client.buy(buy_params).await?;
tokio::time::sleep(std::time::Duration::from_secs(4)).await;
@@ -59,23 +58,24 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
);
let balance = rpc.get_token_account_balance(&account).await?;
let amount_token = balance.amount.parse::<u64>().unwrap();
client
.sell(
DexType::PumpSwap,
mint_pubkey,
amount_token,
slippage_basis_points,
recent_blockhash,
None,
false,
Box::new(PumpSwapParams::from_pool_address_by_rpc(&client.rpc, &pool).await?),
None,
true,
true,
true,
true, // ❗️❗️❗️❗️ open seed optimize
)
.await?;
let sell_params = sol_trade_sdk::TradeSellParams {
dex_type: DexType::PumpSwap,
mint: mint_pubkey,
token_amount: amount_token,
slippage_basis_points: slippage_basis_points,
recent_blockhash: recent_blockhash,
with_tip: false,
extension_params: Box::new(
PumpSwapParams::from_pool_address_by_rpc(&client.rpc, &pool).await?,
),
custom_cu_limit: None,
lookup_table_key: None,
wait_transaction_confirmed: true,
create_wsol_ata: true,
close_wsol_ata: true,
open_seed_optimize: true, // ❗️❗️❗️❗️ open seed optimize
};
client.sell(sell_params).await?;
tokio::signal::ctrl_c().await?;
Ok(())
@@ -84,27 +84,18 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
/// Create SolanaTrade client
/// Initializes a new SolanaTrade client with configuration
async fn create_solana_trade_client() -> AnyResult<SolanaTrade> {
println!("Creating SolanaTrade client...");
let payer = Keypair::from_base58_string("use_your_own_keypair");
println!("🚀 Initializing SolanaTrade client...");
let payer = Keypair::from_base58_string("use_your_payer_keypair_here");
let rpc_url = "https://api.mainnet-beta.solana.com".to_string();
let swqos_configs = vec![SwqosConfig::Default(rpc_url.clone())];
let mut priority_fee = PriorityFee::default();
priority_fee.buy_tip_fees = vec![0.001];
// Configure according to your needs
priority_fee.rpc_unit_limit = 150000;
let trade_config = TradeConfig {
rpc_url,
commitment: CommitmentConfig::confirmed(),
priority_fee: priority_fee,
swqos_configs,
};
let solana_trade_client = SolanaTrade::new(Arc::new(payer), trade_config).await;
println!("SolanaTrade client created successfully!");
Ok(solana_trade_client)
let commitment = CommitmentConfig::confirmed();
let swqos_settings: Vec<SwqosSettings> = vec![SwqosSettings::new(
SwqosConfig::Default(rpc_url.clone()),
DEFAULT_CU_LIMIT,
DEFAULT_CU_PRICE,
0.0,
0.0,
)];
let solana_trade = SolanaTrade::new(Arc::new(payer), rpc_url, commitment, swqos_settings).await;
println!("✅ SolanaTrade client initialized successfully!");
Ok(solana_trade)
}
+27 -39
View File
@@ -1,6 +1,9 @@
use sol_trade_sdk::{
common::{AnyResult, PriorityFee, TradeConfig},
swqos::{SwqosConfig, SwqosRegion},
common::AnyResult,
constants::trade::trade::{
DEFAULT_BUY_TIP_FEE, DEFAULT_CU_LIMIT, DEFAULT_CU_PRICE, DEFAULT_SELL_TIP_FEE,
},
swqos::{settings::SwqosSettings, SwqosConfig, SwqosRegion},
SolanaTrade,
};
use solana_sdk::{commitment_config::CommitmentConfig, signature::Keypair};
@@ -8,53 +11,38 @@ use std::sync::Arc;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let _ = test_create_solana_trade_client().await?;
let _ = create_solana_trade_client().await?;
println!("Successfully created SolanaTrade client!");
Ok(())
}
/// Create SolanaTrade client
/// Initializes a new SolanaTrade client with configuration
async fn test_create_solana_trade_client() -> AnyResult<SolanaTrade> {
async fn create_solana_trade_client() -> AnyResult<SolanaTrade> {
println!("Creating SolanaTrade client...");
let payer = Keypair::new();
let rpc_url = "https://mainnet.helius-rpc.com/?api-key=xxxxxx".to_string();
println!("rpc_url: {}", rpc_url);
let swqos_configs = create_swqos_configs(&rpc_url);
let trade_config = create_trade_config(rpc_url, swqos_configs);
let solana_trade_client = SolanaTrade::new(Arc::new(payer), trade_config).await;
let commitment = CommitmentConfig::processed();
let cu_limit = DEFAULT_CU_LIMIT;
let cu_price = DEFAULT_CU_PRICE;
let buy_tip_fee = DEFAULT_BUY_TIP_FEE;
let sell_tip_fee = DEFAULT_SELL_TIP_FEE;
let swqos_settings: Vec<SwqosSettings> = vec![
SwqosSettings::new(SwqosConfig::Default(rpc_url.clone()), cu_limit, cu_price, 0.0, 0.0),
// First parameter is UUID, pass empty string if no UUID
SwqosSettings::new(SwqosConfig::Jito("your uuid".to_string(), SwqosRegion::Frankfurt, None), cu_limit, cu_price, buy_tip_fee, sell_tip_fee),
SwqosSettings::new(SwqosConfig::NextBlock("your api_token".to_string(), SwqosRegion::Frankfurt, None), cu_limit, cu_price, buy_tip_fee, sell_tip_fee),
SwqosSettings::new(SwqosConfig::Bloxroute("your api_token".to_string(), SwqosRegion::Frankfurt, None), cu_limit, cu_price, buy_tip_fee, sell_tip_fee),
SwqosSettings::new(SwqosConfig::ZeroSlot("your api_token".to_string(), SwqosRegion::Frankfurt, None), cu_limit, cu_price, buy_tip_fee, sell_tip_fee),
SwqosSettings::new(SwqosConfig::Temporal("your api_token".to_string(), SwqosRegion::Frankfurt, None), cu_limit, cu_price, buy_tip_fee, sell_tip_fee),
SwqosSettings::new(SwqosConfig::FlashBlock("your api_token".to_string(), SwqosRegion::Frankfurt, None), cu_limit, cu_price, buy_tip_fee, sell_tip_fee),
SwqosSettings::new(SwqosConfig::Node1("your api_token".to_string(), SwqosRegion::Frankfurt, None), cu_limit, cu_price, buy_tip_fee, sell_tip_fee),
SwqosSettings::new(SwqosConfig::BlockRazor("your api_token".to_string(), SwqosRegion::Frankfurt, None), cu_limit, cu_price, buy_tip_fee, sell_tip_fee),
SwqosSettings::new(SwqosConfig::Astralane("your api_token".to_string(), SwqosRegion::Frankfurt, None), cu_limit, cu_price, buy_tip_fee, sell_tip_fee),
];
let solana_trade_client =
SolanaTrade::new(Arc::new(payer), rpc_url, commitment, swqos_settings).await;
println!("SolanaTrade client created successfully!");
Ok(solana_trade_client)
}
fn create_swqos_configs(rpc_url: &str) -> Vec<SwqosConfig> {
vec![
// First parameter is UUID, pass empty string if no UUID
SwqosConfig::Jito("your uuid".to_string(), SwqosRegion::Frankfurt, None),
SwqosConfig::NextBlock("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),
// Add tg official customer https://t.me/FlashBlock_Official to get free FlashBlock key
SwqosConfig::FlashBlock("your api_token".to_string(), SwqosRegion::Frankfurt, None),
// Add tg official customer https://t.me/node1_me to get free Node1 key
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::Default(rpc_url.to_string()),
]
}
fn create_trade_config(rpc_url: String, swqos_configs: Vec<SwqosConfig>) -> TradeConfig {
TradeConfig {
rpc_url,
commitment: CommitmentConfig::confirmed(),
priority_fee: PriorityFee::default(),
swqos_configs,
}
}
+11 -8
View File
@@ -1,5 +1,6 @@
use sol_trade_sdk::{
common::{PriorityFee, TradeConfig},
constants::trade::trade::{DEFAULT_CU_LIMIT, DEFAULT_CU_PRICE},
swqos::{settings::SwqosSettings, SwqosConfig},
SolanaTrade,
};
use solana_sdk::{commitment_config::CommitmentConfig, signature::Keypair};
@@ -57,13 +58,15 @@ async fn create_solana_trade_client() -> Result<SolanaTrade, Box<dyn std::error:
println!("🚀 Initializing SolanaTrade client...");
let payer = Keypair::from_base58_string("use_your_payer_keypair_here");
let rpc_url = "https://api.mainnet-beta.solana.com".to_string();
let trade_config = TradeConfig {
rpc_url,
commitment: CommitmentConfig::confirmed(),
priority_fee: PriorityFee::default(),
swqos_configs: vec![],
};
let solana_trade = SolanaTrade::new(Arc::new(payer), trade_config).await;
let commitment = CommitmentConfig::confirmed();
let swqos_settings: Vec<SwqosSettings> = vec![SwqosSettings::new(
SwqosConfig::Default(rpc_url.clone()),
DEFAULT_CU_LIMIT,
DEFAULT_CU_PRICE,
0.0,
0.0,
)];
let solana_trade = SolanaTrade::new(Arc::new(payer), rpc_url, commitment, swqos_settings).await;
println!("✅ SolanaTrade client initialized successfully!");
Ok(solana_trade)
}
+3 -17
View File
@@ -15,8 +15,6 @@ pub struct NonceInfo {
pub nonce_account: Option<Pubkey>,
/// Current nonce value
pub current_nonce: Hash,
/// Next available time (Unix timestamp in seconds)
pub next_buy_time: i64,
/// Whether it has been used
pub used: bool,
}
@@ -39,7 +37,6 @@ impl NonceCache {
nonce_info: Mutex::new(NonceInfo {
nonce_account: None,
current_nonce: Hash::default(),
next_buy_time: 0,
used: false,
}),
})
@@ -50,7 +47,7 @@ impl NonceCache {
/// Initialize nonce information
pub fn init(&self, nonce_account_str: Option<String>) {
let nonce_account = nonce_account_str.and_then(|s| Pubkey::from_str(&s).ok());
self.update_nonce_info_partial(nonce_account, None, None, Some(false));
self.update_nonce_info_partial(nonce_account, None, Some(false));
}
/// Get a copy of NonceInfo
@@ -59,7 +56,6 @@ impl NonceCache {
NonceInfo {
nonce_account: nonce_info.nonce_account,
current_nonce: nonce_info.current_nonce,
next_buy_time: nonce_info.next_buy_time,
used: nonce_info.used,
}
}
@@ -69,7 +65,6 @@ impl NonceCache {
&self,
nonce_account: Option<Pubkey>,
current_nonce: Option<Hash>,
next_buy_time: Option<i64>,
used: Option<bool>,
) {
let mut current = self.nonce_info.lock();
@@ -83,10 +78,6 @@ impl NonceCache {
current.current_nonce = nonce;
}
if let Some(time) = next_buy_time {
current.next_buy_time = time;
}
if let Some(u) = used {
current.used = u;
}
@@ -94,7 +85,7 @@ impl NonceCache {
/// Mark nonce as used
pub fn mark_used(&self) {
self.update_nonce_info_partial(None, None, None, Some(true));
self.update_nonce_info_partial(None, None, Some(true));
}
/// Fetch nonce information using RPC
@@ -109,12 +100,7 @@ impl NonceCache {
let blockhash = data.durable_nonce.as_hash();
let old_nonce_info = self.get_nonce_info();
if old_nonce_info.current_nonce != *blockhash {
self.update_nonce_info_partial(
None,
Some(*blockhash),
None,
Some(false),
);
self.update_nonce_info_partial(None, Some(*blockhash), Some(false));
}
}
}
-78
View File
@@ -1,80 +1,2 @@
use std::sync::Arc;
use crate::{
constants::trade::trade::{
DEFAULT_BUY_TIP_FEE, DEFAULT_RPC_UNIT_LIMIT, DEFAULT_RPC_UNIT_PRICE, DEFAULT_SELL_TIP_FEE,
DEFAULT_TIP_UNIT_LIMIT, DEFAULT_TIP_UNIT_PRICE,
},
swqos::{SwqosClient, SwqosConfig},
};
use serde::Deserialize;
use solana_client::rpc_client::RpcClient;
use solana_sdk::{commitment_config::CommitmentConfig, signature::Keypair};
#[derive(Debug, Clone)]
pub struct TradeConfig {
pub rpc_url: String,
pub swqos_configs: Vec<SwqosConfig>,
pub priority_fee: PriorityFee,
pub commitment: CommitmentConfig,
}
impl TradeConfig {
pub fn new(
rpc_url: String,
swqos_configs: Vec<SwqosConfig>,
priority_fee: PriorityFee,
commitment: CommitmentConfig,
) -> Self {
Self { rpc_url, swqos_configs, priority_fee, commitment }
}
}
#[derive(Debug, Deserialize, Clone, PartialEq)]
pub struct PriorityFee {
pub tip_unit_limit: u32,
pub tip_unit_price: u64,
pub rpc_unit_limit: u32,
pub rpc_unit_price: u64,
// Matches the order of swqos
pub buy_tip_fees: Vec<f64>,
// Matches the order of swqos
pub sell_tip_fees: Vec<f64>,
}
impl Default for PriorityFee {
fn default() -> Self {
Self {
tip_unit_limit: DEFAULT_TIP_UNIT_LIMIT,
tip_unit_price: DEFAULT_TIP_UNIT_PRICE,
rpc_unit_limit: DEFAULT_RPC_UNIT_LIMIT,
rpc_unit_price: DEFAULT_RPC_UNIT_PRICE,
// Matches the order of swqos
buy_tip_fees: vec![DEFAULT_BUY_TIP_FEE],
// Matches the order of swqos
sell_tip_fees: vec![DEFAULT_SELL_TIP_FEE],
}
}
}
pub type SolanaRpcClient = solana_client::nonblocking::rpc_client::RpcClient;
pub struct MethodArgs {
pub payer: Arc<Keypair>,
pub rpc: Arc<RpcClient>,
pub nonblocking_rpc: Arc<SolanaRpcClient>,
pub jito_client: Arc<SwqosClient>,
}
impl MethodArgs {
pub fn new(
payer: Arc<Keypair>,
rpc: Arc<RpcClient>,
nonblocking_rpc: Arc<SolanaRpcClient>,
jito_client: Arc<SwqosClient>,
) -> Self {
Self { payer, rpc, nonblocking_rpc, jito_client }
}
}
pub type AnyResult<T> = anyhow::Result<T>;
+3 -5
View File
@@ -1,9 +1,7 @@
pub mod trade {
pub const DEFAULT_CU_LIMIT: u32 = 150000;
pub const DEFAULT_CU_PRICE: u64 = 500000;
pub const DEFAULT_SLIPPAGE: u64 = 1000; // 10%
pub const DEFAULT_TIP_UNIT_LIMIT: u32 = 78000;
pub const DEFAULT_TIP_UNIT_PRICE: u64 = 500000;
pub const DEFAULT_BUY_TIP_FEE: f64 = 0.0006;
pub const DEFAULT_SELL_TIP_FEE: f64 = 0.0001;
pub const DEFAULT_RPC_UNIT_LIMIT: u32 = 78000;
pub const DEFAULT_RPC_UNIT_PRICE: u64 = 500000;
pub const DEFAULT_SELL_TIP_FEE: f64 = 0.0001;
}
+3 -3
View File
@@ -7,7 +7,7 @@ use crate::{
trading::{
common::utils::get_token_balance,
core::{
params::{BonkParams, BuyParams, SellParams},
params::{BonkParams, InternalBuyParams, InternalSellParams},
traits::InstructionBuilder,
},
},
@@ -27,7 +27,7 @@ pub struct BonkInstructionBuilder;
#[async_trait::async_trait]
impl InstructionBuilder for BonkInstructionBuilder {
async fn build_buy_instructions(&self, params: &BuyParams) -> Result<Vec<Instruction>> {
async fn build_buy_instructions(&self, params: &InternalBuyParams) -> Result<Vec<Instruction>> {
// ========================================
// Parameter validation and basic data preparation
// ========================================
@@ -144,7 +144,7 @@ impl InstructionBuilder for BonkInstructionBuilder {
Ok(instructions)
}
async fn build_sell_instructions(&self, params: &SellParams) -> Result<Vec<Instruction>> {
async fn build_sell_instructions(&self, params: &InternalSellParams) -> Result<Vec<Instruction>> {
// ========================================
// Parameter validation and basic data preparation
// ========================================
+3 -3
View File
@@ -1,7 +1,7 @@
use crate::{
constants::trade::trade::DEFAULT_SLIPPAGE,
trading::core::{
params::{BuyParams, PumpFunParams, SellParams},
params::{InternalBuyParams, PumpFunParams, InternalSellParams},
traits::InstructionBuilder,
},
};
@@ -25,7 +25,7 @@ pub struct PumpFunInstructionBuilder;
#[async_trait::async_trait]
impl InstructionBuilder for PumpFunInstructionBuilder {
async fn build_buy_instructions(&self, params: &BuyParams) -> Result<Vec<Instruction>> {
async fn build_buy_instructions(&self, params: &InternalBuyParams) -> Result<Vec<Instruction>> {
// ========================================
// Parameter validation and basic data preparation
// ========================================
@@ -138,7 +138,7 @@ impl InstructionBuilder for PumpFunInstructionBuilder {
Ok(instructions)
}
async fn build_sell_instructions(&self, params: &SellParams) -> Result<Vec<Instruction>> {
async fn build_sell_instructions(&self, params: &InternalSellParams) -> Result<Vec<Instruction>> {
// ========================================
// Parameter validation and basic data preparation
// ========================================
+3 -3
View File
@@ -7,7 +7,7 @@ use crate::{
trading::{
common::wsol_manager,
core::{
params::{BuyParams, PumpSwapParams, SellParams},
params::{InternalBuyParams, PumpSwapParams, InternalSellParams},
traits::InstructionBuilder,
},
},
@@ -25,7 +25,7 @@ pub struct PumpSwapInstructionBuilder;
#[async_trait::async_trait]
impl InstructionBuilder for PumpSwapInstructionBuilder {
async fn build_buy_instructions(&self, params: &BuyParams) -> Result<Vec<Instruction>> {
async fn build_buy_instructions(&self, params: &InternalBuyParams) -> Result<Vec<Instruction>> {
// ========================================
// Parameter validation and basic data preparation
// ========================================
@@ -197,7 +197,7 @@ impl InstructionBuilder for PumpSwapInstructionBuilder {
Ok(instructions)
}
async fn build_sell_instructions(&self, params: &SellParams) -> Result<Vec<Instruction>> {
async fn build_sell_instructions(&self, params: &InternalSellParams) -> Result<Vec<Instruction>> {
// ========================================
// Parameter validation and basic data preparation
// ========================================
+3 -3
View File
@@ -2,7 +2,7 @@ use crate::{
constants::trade::trade::DEFAULT_SLIPPAGE,
instruction::utils::raydium_amm_v4::{accounts, SWAP_BASE_IN_DISCRIMINATOR},
trading::core::{
params::{BuyParams, RaydiumAmmV4Params, SellParams},
params::{InternalBuyParams, RaydiumAmmV4Params, InternalSellParams},
traits::InstructionBuilder,
},
utils::calc::raydium_amm_v4::compute_swap_amount,
@@ -18,7 +18,7 @@ pub struct RaydiumAmmV4InstructionBuilder;
#[async_trait::async_trait]
impl InstructionBuilder for RaydiumAmmV4InstructionBuilder {
async fn build_buy_instructions(&self, params: &BuyParams) -> Result<Vec<Instruction>> {
async fn build_buy_instructions(&self, params: &InternalBuyParams) -> Result<Vec<Instruction>> {
// ========================================
// Parameter validation and basic data preparation
// ========================================
@@ -122,7 +122,7 @@ impl InstructionBuilder for RaydiumAmmV4InstructionBuilder {
Ok(instructions)
}
async fn build_sell_instructions(&self, params: &SellParams) -> Result<Vec<Instruction>> {
async fn build_sell_instructions(&self, params: &InternalSellParams) -> Result<Vec<Instruction>> {
// ========================================
// Parameter validation and basic data preparation
// ========================================
+3 -3
View File
@@ -6,7 +6,7 @@ use crate::{
SWAP_BASE_IN_DISCRIMINATOR,
},
trading::core::{
params::{BuyParams, RaydiumCpmmParams, SellParams},
params::{InternalBuyParams, RaydiumCpmmParams, InternalSellParams},
traits::InstructionBuilder,
},
utils::calc::raydium_cpmm::compute_swap_amount,
@@ -23,7 +23,7 @@ pub struct RaydiumCpmmInstructionBuilder;
#[async_trait::async_trait]
impl InstructionBuilder for RaydiumCpmmInstructionBuilder {
async fn build_buy_instructions(&self, params: &BuyParams) -> Result<Vec<Instruction>> {
async fn build_buy_instructions(&self, params: &InternalBuyParams) -> Result<Vec<Instruction>> {
// ========================================
// Parameter validation and basic data preparation
// ========================================
@@ -153,7 +153,7 @@ impl InstructionBuilder for RaydiumCpmmInstructionBuilder {
Ok(instructions)
}
async fn build_sell_instructions(&self, params: &SellParams) -> Result<Vec<Instruction>> {
async fn build_sell_instructions(&self, params: &InternalSellParams) -> Result<Vec<Instruction>> {
// ========================================
// Parameter validation and basic data preparation
// ========================================
+223 -191
View File
@@ -5,11 +5,8 @@ pub mod protos;
pub mod swqos;
pub mod trading;
pub mod utils;
use solana_sdk::signer::Signer;
pub use solana_streamer_sdk;
use crate::constants::trade::trade::DEFAULT_SLIPPAGE;
use crate::swqos::SwqosConfig;
use crate::swqos::settings::SwqosSettings;
use crate::trading::core::params::BonkParams;
use crate::trading::core::params::PumpFunParams;
use crate::trading::core::params::PumpSwapParams;
@@ -17,24 +14,33 @@ use crate::trading::core::params::RaydiumAmmV4Params;
use crate::trading::core::params::RaydiumCpmmParams;
use crate::trading::core::traits::ProtocolParams;
use crate::trading::factory::DexType;
use crate::trading::BuyParams;
use crate::trading::InternalBuyParams;
use crate::trading::InternalSellParams;
use crate::trading::MiddlewareManager;
use crate::trading::SellParams;
use crate::trading::TradeFactory;
use common::{PriorityFee, SolanaRpcClient, TradeConfig};
use common::SolanaRpcClient;
use parking_lot::Mutex;
use rustls::crypto::{ring::default_provider, CryptoProvider};
use solana_sdk::commitment_config::CommitmentConfig;
use solana_sdk::hash::Hash;
use solana_sdk::signer::Signer;
use solana_sdk::{pubkey::Pubkey, signature::Keypair, signature::Signature};
pub use solana_streamer_sdk;
use std::sync::Arc;
use swqos::SwqosClient;
/// Main trading client for Solana DeFi protocols
///
/// `SolanaTrade` provides a unified interface for trading across multiple Solana DEXs
/// including PumpFun, PumpSwap, Bonk, Raydium AMM V4, and Raydium CPMM.
/// It manages RPC connections, transaction signing, and SWQOS (Solana Web Quality of Service) settings.
pub struct SolanaTrade {
/// The keypair used for signing all transactions
pub payer: Arc<Keypair>,
/// RPC client for blockchain interactions
pub rpc: Arc<SolanaRpcClient>,
pub rpc_client: Vec<Arc<SwqosClient>>,
pub swqos_clients: Vec<Arc<SwqosClient>>,
pub priority_fee: Arc<PriorityFee>,
/// SWQOS settings for transaction priority and routing
pub swqos_settings: Vec<Arc<SwqosSettings>>,
/// Optional middleware manager for custom transaction processing
pub middleware_manager: Option<Arc<MiddlewareManager>>,
}
@@ -45,17 +51,105 @@ impl Clone for SolanaTrade {
Self {
payer: self.payer.clone(),
rpc: self.rpc.clone(),
rpc_client: self.rpc_client.clone(),
swqos_clients: self.swqos_clients.clone(),
priority_fee: self.priority_fee.clone(),
swqos_settings: self.swqos_settings.clone(),
middleware_manager: self.middleware_manager.clone(),
}
}
}
/// Parameters for executing buy orders across different DEX protocols
///
/// Contains all necessary configuration for purchasing tokens, including
/// protocol-specific settings, account management options, and transaction preferences.
#[derive(Clone)]
pub struct TradeBuyParams {
// Trading configuration
/// The DEX protocol to use for the trade
pub dex_type: DexType,
/// Public key of the token to purchase
pub mint: Pubkey,
/// Amount of SOL to spend (in lamports)
pub sol_amount: u64,
/// Optional slippage tolerance in basis points (e.g., 100 = 1%)
pub slippage_basis_points: Option<u64>,
/// Recent blockhash for transaction validity
pub recent_blockhash: Hash,
/// Protocol-specific parameters (PumpFun, Raydium, etc.)
pub extension_params: Box<dyn ProtocolParams>,
// Extended configuration
/// Optional custom compute unit limit for the transaction
pub custom_cu_limit: Option<u32>,
/// Optional address lookup table for transaction size optimization
pub lookup_table_key: Option<Pubkey>,
/// Whether to wait for transaction confirmation before returning
pub wait_transaction_confirmed: bool,
/// Whether to create wrapped SOL associated token account
pub create_wsol_ata: bool,
/// Whether to close wrapped SOL associated token account after trade
pub close_wsol_ata: bool,
/// Whether to create token mint associated token account
pub create_mint_ata: bool,
/// Whether to enable seed-based optimization for account creation
pub open_seed_optimize: bool,
}
/// Parameters for executing sell orders across different DEX protocols
///
/// Contains all necessary configuration for selling tokens, including
/// protocol-specific settings, tip preferences, account management options, and transaction preferences.
#[derive(Clone)]
pub struct TradeSellParams {
// Trading configuration
/// The DEX protocol to use for the trade
pub dex_type: DexType,
/// Public key of the token to sell
pub mint: Pubkey,
/// Amount of tokens to sell (in smallest token units)
pub token_amount: u64,
/// Optional slippage tolerance in basis points (e.g., 100 = 1%)
pub slippage_basis_points: Option<u64>,
/// Recent blockhash for transaction validity
pub recent_blockhash: Hash,
/// Whether to include tip for transaction priority
pub with_tip: bool,
/// Protocol-specific parameters (PumpFun, Raydium, etc.)
pub extension_params: Box<dyn ProtocolParams>,
// Extended configuration
/// Optional custom compute unit limit for the transaction
pub custom_cu_limit: Option<u32>,
/// Optional address lookup table for transaction size optimization
pub lookup_table_key: Option<Pubkey>,
/// Whether to wait for transaction confirmation before returning
pub wait_transaction_confirmed: bool,
/// Whether to create wrapped SOL associated token account
pub create_wsol_ata: bool,
/// Whether to close wrapped SOL associated token account after trade
pub close_wsol_ata: bool,
/// Whether to enable seed-based optimization for account creation
pub open_seed_optimize: bool,
}
impl SolanaTrade {
/// Creates a new SolanaTrade instance with the specified configuration
///
/// This function initializes the trading system with RPC connection, SWQOS settings,
/// and sets up necessary components for trading operations.
///
/// # Arguments
/// * `payer` - The keypair used for signing transactions
/// * `rpc_url` - Solana RPC endpoint URL
/// * `commitment` - Transaction commitment level for RPC calls
/// * `swqos_settings` - List of SWQOS (Solana Web Quality of Service) configurations
///
/// # Returns
/// Returns a configured `SolanaTrade` instance ready for trading operations
#[inline]
pub async fn new(payer: Arc<Keypair>, trade_config: TradeConfig) -> Self {
pub async fn new(
payer: Arc<Keypair>,
rpc_url: String,
commitment: CommitmentConfig,
mut swqos_settings: Vec<SwqosSettings>,
) -> Self {
crate::common::fast_fn::fast_init(&payer.try_pubkey().unwrap());
if CryptoProvider::get_default().is_none() {
@@ -64,34 +158,22 @@ impl SolanaTrade {
.map_err(|e| anyhow::anyhow!("Failed to install crypto provider: {:?}", e));
}
let rpc_url = trade_config.rpc_url.clone();
let swqos_configs = trade_config.swqos_configs.clone();
let priority_fee = Arc::new(trade_config.priority_fee.clone());
let commitment = trade_config.commitment.clone();
let mut swqos_clients: Vec<Arc<SwqosClient>> = vec![];
let rpc_url = rpc_url.clone();
let commitment = commitment.clone();
for swqos in swqos_configs {
let swqos_client =
SwqosConfig::get_swqos_client(rpc_url.clone(), commitment.clone(), swqos.clone());
swqos_clients.push(swqos_client);
for swqos in &mut swqos_settings {
swqos.setup_swqos_client(rpc_url.clone(), commitment.clone());
}
let rpc = Arc::new(SolanaRpcClient::new_with_commitment(rpc_url.clone(), commitment));
let rpc =
Arc::new(SolanaRpcClient::new_with_commitment(rpc_url.clone(), commitment.clone()));
common::seed::update_rents(&rpc).await.unwrap();
common::seed::start_rent_updater(rpc.clone());
let rpc_client = SwqosConfig::get_swqos_client(
rpc_url.clone(),
commitment,
SwqosConfig::Default(rpc_url),
);
let instance = Self {
payer,
rpc,
rpc_client: vec![rpc_client],
swqos_clients,
priority_fee,
swqos_settings: swqos_settings.into_iter().map(|s| Arc::new(s)).collect(),
middleware_manager: None,
};
@@ -101,22 +183,47 @@ impl SolanaTrade {
instance
}
/// Adds a middleware manager to the SolanaTrade instance
///
/// Middleware managers can be used to implement custom logic that runs before or after trading operations,
/// such as logging, monitoring, or custom validation.
///
/// # Arguments
/// * `middleware_manager` - The middleware manager to attach
///
/// # Returns
/// Returns the modified SolanaTrade instance with middleware manager attached
pub fn with_middleware_manager(mut self, middleware_manager: MiddlewareManager) -> Self {
self.middleware_manager = Some(Arc::new(middleware_manager));
self
}
/// Get the RPC client instance
/// Gets the RPC client instance for direct Solana blockchain interactions
///
/// This provides access to the underlying Solana RPC client that can be used
/// for custom blockchain operations outside of the trading framework.
///
/// # Returns
/// Returns a reference to the Arc-wrapped SolanaRpcClient instance
pub fn get_rpc(&self) -> &Arc<SolanaRpcClient> {
&self.rpc
}
/// Get the current instance
/// Gets the current globally shared SolanaTrade instance
///
/// This provides access to the singleton instance that was created with `new()`.
/// Useful for accessing the trading instance from different parts of the application.
///
/// # Returns
/// Returns the Arc-wrapped SolanaTrade instance
///
/// # Panics
/// Panics if no instance has been initialized yet. Make sure to call `new()` first.
pub fn get_instance() -> Arc<Self> {
let instance = INSTANCE.lock();
instance
.as_ref()
.expect("PumpFun instance not initialized. Please call new() first.")
.expect("SolanaTrade instance not initialized. Please call new() first.")
.clone()
}
@@ -124,80 +231,53 @@ impl SolanaTrade {
///
/// # Arguments
///
/// * `dex_type` - The trading protocol to use (PumpFun, PumpSwap, or Bonk)
/// * `mint` - The public key of the token mint to buy
/// * `sol_amount` - Amount of SOL to spend on the purchase (in lamports)
/// * `slippage_basis_points` - Optional slippage tolerance in basis points (e.g., 100 = 1%)
/// * `recent_blockhash` - Recent blockhash for transaction validity
/// * `custom_priority_fee` - Optional custom priority fee for priority processing
/// * `extension_params` - Optional protocol-specific parameters (uses defaults if None)
/// * `lookup_table_key` - Optional address lookup table key for transaction optimization
/// * `wait_transaction_confirmed` - Whether to wait for the transaction to be confirmed
/// * `create_wsol_ata` - Whether to create wSOL ATA account
/// * `close_wsol_ata` - Whether to close wSOL ATA account
/// * `open_seed_optimize` - Whether to open seed optimize
/// * `params` - Buy trade parameters containing all necessary trading configuration
///
/// # Returns
///
/// Returns `Ok(())` if the buy order is successfully executed, or an error if the transaction fails.
/// Returns `Ok(Signature)` with the transaction signature if the buy order is successfully executed,
/// or an error if the transaction fails.
///
/// # Errors
///
/// This function will return an error if:
/// - Invalid protocol parameters are provided
/// - Invalid protocol parameters are provided for the specified DEX type
/// - The transaction fails to execute
/// - Network or RPC errors occur
/// - Insufficient SOL balance for the purchase
pub async fn buy(
&self,
dex_type: DexType,
mint: Pubkey,
sol_amount: u64,
slippage_basis_points: Option<u64>,
recent_blockhash: Hash,
custom_priority_fee: Option<PriorityFee>,
extension_params: Box<dyn ProtocolParams>,
lookup_table_key: Option<Pubkey>,
wait_transaction_confirmed: bool,
create_wsol_ata: bool,
close_wsol_ata: bool,
create_mint_ata: bool,
open_seed_optimize: bool,
) -> Result<Signature, anyhow::Error> {
if slippage_basis_points.is_none() {
/// - Required accounts cannot be created or accessed
pub async fn buy(&self, params: TradeBuyParams) -> Result<Signature, anyhow::Error> {
if params.slippage_basis_points.is_none() {
println!(
"slippage_basis_points is none, use default slippage basis points: {}",
DEFAULT_SLIPPAGE
);
}
let executor = TradeFactory::create_executor(dex_type.clone());
let protocol_params = extension_params;
let executor = TradeFactory::create_executor(params.dex_type.clone());
let protocol_params = params.extension_params;
let mut buy_params = BuyParams {
let buy_params = InternalBuyParams {
rpc: Some(self.rpc.clone()),
payer: self.payer.clone(),
mint: mint,
sol_amount: sol_amount,
slippage_basis_points: slippage_basis_points,
priority_fee: self.priority_fee.clone(),
lookup_table_key,
recent_blockhash,
mint: params.mint,
sol_amount: params.sol_amount,
slippage_basis_points: params.slippage_basis_points,
lookup_table_key: params.lookup_table_key,
recent_blockhash: params.recent_blockhash,
data_size_limit: 256 * 1024,
wait_transaction_confirmed: wait_transaction_confirmed,
wait_transaction_confirmed: params.wait_transaction_confirmed,
protocol_params: protocol_params.clone(),
open_seed_optimize,
create_wsol_ata,
close_wsol_ata,
create_mint_ata,
swqos_clients: self.swqos_clients.clone(),
open_seed_optimize: params.open_seed_optimize,
create_wsol_ata: params.create_wsol_ata,
close_wsol_ata: params.close_wsol_ata,
create_mint_ata: params.create_mint_ata,
swqos_settings: self.swqos_settings.clone(),
middleware_manager: self.middleware_manager.clone(),
custom_cu_limit: params.custom_cu_limit,
};
if custom_priority_fee.is_some() {
buy_params.priority_fee = Arc::new(custom_priority_fee.unwrap());
}
// Validate protocol params
let is_valid_params = match dex_type {
let is_valid_params = match params.dex_type {
DexType::PumpFun => protocol_params.as_any().downcast_ref::<PumpFunParams>().is_some(),
DexType::PumpSwap => {
protocol_params.as_any().downcast_ref::<PumpSwapParams>().is_some()
@@ -222,86 +302,53 @@ impl SolanaTrade {
///
/// # Arguments
///
/// * `dex_type` - The trading protocol to use (PumpFun, PumpSwap, or Bonk)
/// * `mint` - The public key of the token mint to sell
/// * `token_amount` - Amount of tokens to sell (in smallest token units)
/// * `slippage_basis_points` - Optional slippage tolerance in basis points (e.g., 100 = 1%)
/// * `recent_blockhash` - Recent blockhash for transaction validity
/// * `custom_priority_fee` - Optional custom priority fee for priority processing
/// * `with_tip` - Optional boolean to indicate if the transaction should be sent with tip
/// * `extension_params` - Optional protocol-specific parameters (uses defaults if None)
/// * `lookup_table_key` - Optional address lookup table key for transaction optimization
/// * `wait_transaction_confirmed` - Whether to wait for the transaction to be confirmed
/// * `create_wsol_ata` - Whether to create wSOL ATA account
/// * `close_wsol_ata` - Whether to close wSOL ATA account
/// * `open_seed_optimize` - Whether to open seed optimize
/// * `params` - Sell trade parameters containing all necessary trading configuration
///
/// # Returns
///
/// Returns `Ok(())` if the sell order is successfully executed, or an error if the transaction fails.
/// Returns `Ok(Signature)` with the transaction signature if the sell order is successfully executed,
/// or an error if the transaction fails.
///
/// # Errors
///
/// This function will return an error if:
/// - Invalid protocol parameters are provided
/// - Invalid protocol parameters are provided for the specified DEX type
/// - The transaction fails to execute
/// - Network or RPC errors occur
/// - Insufficient token balance for the sale
/// - Token account doesn't exist or is not properly initialized
pub async fn sell(
&self,
dex_type: DexType,
mint: Pubkey,
token_amount: u64,
slippage_basis_points: Option<u64>,
recent_blockhash: Hash,
custom_priority_fee: Option<PriorityFee>,
with_tip: bool,
extension_params: Box<dyn ProtocolParams>,
lookup_table_key: Option<Pubkey>,
wait_transaction_confirmed: bool,
create_wsol_ata: bool,
close_wsol_ata: bool,
open_seed_optimize: bool,
) -> Result<Signature, anyhow::Error> {
if slippage_basis_points.is_none() {
/// - Required accounts cannot be created or accessed
pub async fn sell(&self, params: TradeSellParams) -> Result<Signature, anyhow::Error> {
if params.slippage_basis_points.is_none() {
println!(
"slippage_basis_points is none, use default slippage basis points: {}",
DEFAULT_SLIPPAGE
);
}
let executor = TradeFactory::create_executor(dex_type.clone());
let protocol_params = extension_params;
let executor = TradeFactory::create_executor(params.dex_type.clone());
let protocol_params = params.extension_params;
let mut sell_params = SellParams {
let sell_params = InternalSellParams {
rpc: Some(self.rpc.clone()),
payer: self.payer.clone(),
mint: mint,
token_amount: Some(token_amount),
slippage_basis_points: slippage_basis_points,
priority_fee: self.priority_fee.clone(),
lookup_table_key,
recent_blockhash,
wait_transaction_confirmed: wait_transaction_confirmed,
mint: params.mint,
token_amount: Some(params.token_amount),
slippage_basis_points: params.slippage_basis_points,
lookup_table_key: params.lookup_table_key,
recent_blockhash: params.recent_blockhash,
wait_transaction_confirmed: params.wait_transaction_confirmed,
protocol_params: protocol_params.clone(),
with_tip: with_tip,
open_seed_optimize,
swqos_clients: if !with_tip {
self.rpc_client.clone()
} else {
self.swqos_clients.clone()
},
with_tip: params.with_tip,
open_seed_optimize: params.open_seed_optimize,
swqos_settings: self.swqos_settings.clone(),
middleware_manager: self.middleware_manager.clone(),
create_wsol_ata,
close_wsol_ata,
create_wsol_ata: params.create_wsol_ata,
close_wsol_ata: params.close_wsol_ata,
custom_cu_limit: params.custom_cu_limit,
};
if custom_priority_fee.is_some() {
sell_params.priority_fee = Arc::new(custom_priority_fee.unwrap());
}
// Validate protocol params
let is_valid_params = match dex_type {
let is_valid_params = match params.dex_type {
DexType::PumpFun => protocol_params.as_any().downcast_ref::<PumpFunParams>().is_some(),
DexType::PumpSwap => {
protocol_params.as_any().downcast_ref::<PumpSwapParams>().is_some()
@@ -330,82 +377,59 @@ impl SolanaTrade {
///
/// # Arguments
///
/// * `dex_type` - The trading protocol to use (PumpFun, PumpSwap, or Bonk)
/// * `mint` - The public key of the token mint to sell
/// * `params` - Sell trade parameters (will be modified with calculated token amount)
/// * `amount_token` - Total amount of tokens available (in smallest token units)
/// * `percent` - Percentage of tokens to sell (1-100, where 100 = 100%)
/// * `slippage_basis_points` - Optional slippage tolerance in basis points (e.g., 100 = 1%)
/// * `recent_blockhash` - Recent blockhash for transaction validity
/// * `custom_priority_fee` - Optional custom priority fee for priority processing
/// * `with_tip` - Whether to use tip for priority processing
/// * `extension_params` - Optional protocol-specific parameters (uses defaults if None)
/// * `lookup_table_key` - Optional lookup table key for address lookup optimization
/// * `wait_transaction_confirmed` - Whether to wait for the transaction to be confirmed
///
/// # Returns
///
/// Returns `Ok(())` if the sell order is successfully executed, or an error if the transaction fails.
/// Returns `Ok(Signature)` with the transaction signature if the sell order is successfully executed,
/// or an error if the transaction fails.
///
/// # Errors
///
/// This function will return an error if:
/// - `percent` is 0 or greater than 100
/// - Invalid protocol parameters are provided
/// - Invalid protocol parameters are provided for the specified DEX type
/// - The transaction fails to execute
/// - Network or RPC errors occur
/// - Insufficient token balance for the calculated sale amount
/// - Token account doesn't exist or is not properly initialized
/// - Required accounts cannot be created or accessed
pub async fn sell_by_percent(
&self,
dex_type: DexType,
mint: Pubkey,
mut params: TradeSellParams,
amount_token: u64,
percent: u64,
slippage_basis_points: Option<u64>,
recent_blockhash: Hash,
custom_priority_fee: Option<PriorityFee>,
with_tip: bool,
extension_params: Box<dyn ProtocolParams>,
lookup_table_key: Option<Pubkey>,
wait_transaction_confirmed: bool,
create_wsol_ata: bool,
close_wsol_ata: bool,
open_seed_optimize: bool,
) -> Result<Signature, anyhow::Error> {
if percent == 0 || percent > 100 {
return Err(anyhow::anyhow!("Percentage must be between 1 and 100"));
}
let amount = amount_token * percent / 100;
self.sell(
dex_type,
mint,
amount,
slippage_basis_points,
recent_blockhash,
custom_priority_fee,
with_tip,
extension_params,
lookup_table_key,
wait_transaction_confirmed,
create_wsol_ata,
close_wsol_ata,
open_seed_optimize,
)
.await
params.token_amount = amount;
self.sell(params).await
}
/// Wraps SOL into wSOL (Wrapped SOL)
/// Wraps native SOL into wSOL (Wrapped SOL) for use in SPL token operations
///
/// This function creates a wSOL associated token account (if it doesn't exist),
/// transfers the specified amount of SOL to that account, and then syncs the native
/// token balance to make SOL usable as an SPL token.
/// token balance to make SOL usable as an SPL token in trading operations.
///
/// # Arguments
/// - `amount`: The amount of SOL to wrap (in lamports)
/// * `amount` - The amount of SOL to wrap (in lamports)
///
/// # Returns
/// - `Ok(String)`: Transaction signature
/// - `Err(anyhow::Error)`: If the transaction fails
/// * `Ok(String)` - Transaction signature if successful
/// * `Err(anyhow::Error)` - If the transaction fails to execute
///
/// # Errors
///
/// This function will return an error if:
/// - Insufficient SOL balance for the wrap operation
/// - wSOL associated token account creation fails
/// - Transaction fails to execute or confirm
/// - Network or RPC errors occur
pub async fn wrap_sol_to_wsol(&self, amount: u64) -> Result<String, anyhow::Error> {
use crate::trading::common::wsol_manager::handle_wsol;
use solana_sdk::transaction::Transaction;
@@ -417,15 +441,23 @@ impl SolanaTrade {
let signature = self.rpc.send_and_confirm_transaction(&transaction).await?;
Ok(signature.to_string())
}
/// Closes the wSOL account and unwraps SOL back to native SOL
/// Closes the wSOL associated token account and unwraps remaining balance to native SOL
///
/// This function closes the wSOL associated token account, which automatically
/// transfers any remaining wSOL balance back to the account owner as native SOL.
/// This is useful for cleaning up wSOL accounts and recovering wrapped SOL.
/// This is useful for cleaning up wSOL accounts and recovering wrapped SOL after trading operations.
///
/// # Returns
/// - `Ok(String)`: Transaction signature
/// - `Err(anyhow::Error)`: If the transaction fails
/// * `Ok(String)` - Transaction signature if successful
/// * `Err(anyhow::Error)` - If the transaction fails to execute
///
/// # Errors
///
/// This function will return an error if:
/// - wSOL associated token account doesn't exist
/// - Account closure fails due to insufficient permissions
/// - Transaction fails to execute or confirm
/// - Network or RPC errors occur
pub async fn close_wsol(&self) -> Result<String, anyhow::Error> {
use crate::trading::common::wsol_manager::close_wsol;
use solana_sdk::transaction::Transaction;
+10
View File
@@ -9,6 +9,7 @@ pub mod node1;
pub mod flashblock;
pub mod blockrazor;
pub mod astralane;
pub mod settings;
use std::sync::Arc;
@@ -107,14 +108,23 @@ pub enum SwqosRegion {
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub enum SwqosConfig {
Default(String),
/// Jito(uuid, region, custom_url)
Jito(String, SwqosRegion, Option<String>),
/// NextBlock(api_token, region, custom_url)
NextBlock(String, SwqosRegion, Option<String>),
/// Bloxroute(api_token, region, custom_url)
Bloxroute(String, SwqosRegion, Option<String>),
/// Temporal(api_token, region, custom_url)
Temporal(String, SwqosRegion, Option<String>),
/// ZeroSlot(api_token, region, custom_url)
ZeroSlot(String, SwqosRegion, Option<String>),
/// Node1(api_token, region, custom_url)
Node1(String, SwqosRegion, Option<String>),
/// FlashBlock(api_token, region, custom_url)
FlashBlock(String, SwqosRegion, Option<String>),
/// BlockRazor(api_token, region, custom_url)
BlockRazor(String, SwqosRegion, Option<String>),
/// Astralane(api_token, region, custom_url)
Astralane(String, SwqosRegion, Option<String>),
}
+47
View File
@@ -0,0 +1,47 @@
use crate::swqos::{SwqosClient, SwqosConfig};
use solana_sdk::commitment_config::CommitmentConfig;
use std::sync::Arc;
pub struct SwqosSettings {
pub swqos_config: SwqosConfig,
pub swqos_client: Option<Arc<SwqosClient>>,
pub unit_limit: u32,
pub unit_price: u64,
pub buy_tip_fee: f64,
pub sell_tip_fee: f64,
}
impl SwqosSettings {
/// Create a new SwqosSettings
/// swqos_config: SwqosConfig,
/// unit_limit: u32,
/// unit_price: u64,
/// buy_tip_fee: f64,
/// sell_tip_fee: f64,
pub fn new(
swqos_config: SwqosConfig,
unit_limit: u32,
unit_price: u64,
buy_tip_fee: f64,
sell_tip_fee: f64,
) -> Self {
Self { swqos_config, swqos_client: None, unit_limit, unit_price, buy_tip_fee, sell_tip_fee }
}
pub fn setup_swqos_client(&mut self, rpc_url: String, commitment: CommitmentConfig) {
let swqos_client =
SwqosConfig::get_swqos_client(rpc_url, commitment, self.swqos_config.clone());
self.swqos_client = Some(swqos_client);
}
pub fn clone(&self) -> Self {
Self {
swqos_config: self.swqos_config.clone(),
swqos_client: self.swqos_client.clone(),
unit_limit: self.unit_limit,
unit_price: self.unit_price,
buy_tip_fee: self.buy_tip_fee,
sell_tip_fee: self.sell_tip_fee,
}
}
}
+8 -10
View File
@@ -1,4 +1,3 @@
use crate::common::PriorityFee;
use dashmap::DashMap;
use once_cell::sync::Lazy;
use smallvec::SmallVec;
@@ -20,19 +19,18 @@ static COMPUTE_BUDGET_CACHE: Lazy<DashMap<ComputeBudgetCacheKey, SmallVec<[Instr
#[inline(always)]
pub fn compute_budget_instructions(
priority_fee: &PriorityFee,
unit_price: u64,
unit_limit: u32,
data_size_limit: u32,
is_rpc: bool,
is_buy: bool,
) -> SmallVec<[Instruction; 3]> {
let (unit_price, unit_limit) = if is_rpc {
(priority_fee.rpc_unit_price, priority_fee.rpc_unit_limit)
} else {
(priority_fee.tip_unit_price, priority_fee.tip_unit_limit)
};
// Create cache key
let cache_key = ComputeBudgetCacheKey { data_size_limit, unit_price, unit_limit, is_buy };
let cache_key = ComputeBudgetCacheKey {
data_size_limit,
unit_price: unit_price,
unit_limit: unit_limit,
is_buy,
};
// Try to get from cache first
if let Some(cached_insts) = COMPUTE_BUDGET_CACHE.get(&cache_key) {
+7 -8
View File
@@ -16,12 +16,13 @@ use super::{
compute_budget_manager::compute_budget_instructions,
nonce_manager::{add_nonce_instruction, get_transaction_blockhash},
};
use crate::{common::PriorityFee, trading::MiddlewareManager};
use crate::trading::MiddlewareManager;
/// Build standard RPC transaction
pub async fn build_transaction(
payer: Arc<Keypair>,
priority_fee: &PriorityFee,
unit_limit: u32,
unit_price: u64,
business_instructions: Vec<Instruction>,
lookup_table_key: Option<Pubkey>,
recent_blockhash: Hash,
@@ -36,10 +37,8 @@ pub async fn build_transaction(
let mut instructions = Vec::with_capacity(business_instructions.len() + 5);
// Add nonce instruction
if is_buy {
if let Err(e) = add_nonce_instruction(&mut instructions, payer.as_ref()) {
return Err(e);
}
if let Err(e) = add_nonce_instruction(&mut instructions, payer.as_ref()) {
return Err(e);
}
// Add tip transfer instruction
@@ -53,9 +52,9 @@ pub async fn build_transaction(
// Add compute budget instructions
instructions.extend(compute_budget_instructions(
priority_fee,
unit_price,
unit_limit,
data_size_limit,
!with_tip,
is_buy,
));
+3 -3
View File
@@ -5,7 +5,7 @@ use std::{sync::Arc, time::Instant};
use crate::trading::core::parallel::{buy_parallel_execute, sell_parallel_execute};
use super::{
params::{BuyParams, SellParams},
params::{InternalBuyParams, InternalSellParams},
traits::{InstructionBuilder, TradeExecutor},
};
@@ -26,7 +26,7 @@ impl GenericTradeExecutor {
#[async_trait::async_trait]
impl TradeExecutor for GenericTradeExecutor {
async fn buy_with_tip(&self, params: BuyParams) -> Result<Signature> {
async fn buy_with_tip(&self, params: InternalBuyParams) -> Result<Signature> {
let start = Instant::now();
// Build instructions directly from params to avoid unnecessary cloning
@@ -47,7 +47,7 @@ impl TradeExecutor for GenericTradeExecutor {
buy_parallel_execute(params, final_instructions, self.protocol_name).await
}
async fn sell_with_tip(&self, params: SellParams) -> Result<Signature> {
async fn sell_with_tip(&self, params: InternalSellParams) -> Result<Signature> {
let start = Instant::now();
// Build instructions directly from params to avoid unnecessary cloning
+92 -98
View File
@@ -8,21 +8,21 @@ use tokio::sync::mpsc;
use tokio::task::JoinHandle;
use crate::{
common::PriorityFee,
swqos::{SwqosClient, SwqosType, TradeType},
trading::{common::build_transaction, BuyParams, MiddlewareManager, SellParams},
swqos::{settings::SwqosSettings, SwqosType, TradeType},
trading::{
common::build_transaction, InternalBuyParams, InternalSellParams, MiddlewareManager,
},
};
pub async fn buy_parallel_execute(
params: BuyParams,
params: InternalBuyParams,
instructions: Vec<Instruction>,
protocol_name: &'static str,
) -> Result<Signature> {
parallel_execute(
params.swqos_clients,
params.swqos_settings,
params.payer,
instructions,
params.priority_fee,
params.lookup_table_key,
params.recent_blockhash,
params.data_size_limit,
@@ -36,15 +36,14 @@ pub async fn buy_parallel_execute(
}
pub async fn sell_parallel_execute(
params: SellParams,
params: InternalSellParams,
instructions: Vec<Instruction>,
protocol_name: &'static str,
) -> Result<Signature> {
parallel_execute(
params.swqos_clients,
params.swqos_settings,
params.payer,
instructions,
params.priority_fee,
params.lookup_table_key,
params.recent_blockhash,
0,
@@ -59,10 +58,9 @@ pub async fn sell_parallel_execute(
/// Generic function for parallel transaction execution
async fn parallel_execute(
swqos_clients: Vec<Arc<SwqosClient>>,
swqos_settings: Vec<Arc<SwqosSettings>>,
payer: Arc<Keypair>,
instructions: Vec<Instruction>,
priority_fee: Arc<PriorityFee>,
lookup_table_key: Option<Pubkey>,
recent_blockhash: Hash,
data_size_limit: u32,
@@ -72,113 +70,109 @@ async fn parallel_execute(
wait_transaction_confirmed: bool,
with_tip: bool,
) -> Result<Signature> {
if swqos_settings.is_empty() {
return Err(anyhow!("swqos_settings is empty"));
}
if !with_tip
&& swqos_settings
.iter()
.find(|swqos| {
matches!(swqos.swqos_client.as_ref().unwrap().get_swqos_type(), SwqosType::Default)
})
.is_none()
{
return Err(anyhow!("No Rpc Default Swqos configured"));
}
let cores = core_affinity::get_core_ids().unwrap();
let mut handles: Vec<JoinHandle<Result<Signature>>> = Vec::with_capacity(swqos_clients.len());
if is_buy && with_tip && priority_fee.buy_tip_fees.is_empty() {
return Err(anyhow!("buy_tip_fees is empty"));
}
if !is_buy && with_tip && priority_fee.sell_tip_fees.is_empty() {
return Err(anyhow!("sell_tip_fees is empty"));
}
let mut handles: Vec<JoinHandle<Result<Signature>>> = Vec::with_capacity(swqos_settings.len());
let instructions = Arc::new(instructions);
for i in 0..swqos_clients.len() {
let swqos_client = swqos_clients[i].clone();
if !with_tip && !matches!(swqos_client.get_swqos_type(), SwqosType::Default) {
continue;
}
let payer = payer.clone();
let instructions = instructions.clone();
let priority_fee = priority_fee.clone();
let core_id = cores[i % cores.len()];
for i in 0..swqos_settings.len() {
if let Some(swqos_client) = swqos_settings[i].swqos_client.as_ref() {
if !with_tip && !matches!(swqos_client.get_swqos_type(), SwqosType::Default) {
continue;
}
let payer = payer.clone();
let instructions = instructions.clone();
let core_id = cores[i % cores.len()];
let middleware_manager = middleware_manager.clone();
let middleware_manager = middleware_manager.clone();
let swqos_client = swqos_client.clone();
let buy_tip_fee = swqos_settings[i].buy_tip_fee;
let sell_tip_fee = swqos_settings[i].sell_tip_fee;
let unit_limit = swqos_settings[i].unit_limit;
let unit_price = swqos_settings[i].unit_price;
let handle = tokio::spawn(async move {
core_affinity::set_for_current(core_id);
let handle = tokio::spawn(async move {
core_affinity::set_for_current(core_id);
let swqos_type = swqos_client.get_swqos_type();
let mut start = Instant::now();
let swqos_type = swqos_client.get_swqos_type();
let mut start = Instant::now();
let tip_account_str = swqos_client.get_tip_account()?;
let tip_account = Arc::new(Pubkey::from_str(&tip_account_str).unwrap_or_default());
let tip_account_str = swqos_client.get_tip_account()?;
let tip_account = Arc::new(Pubkey::from_str(&tip_account_str).unwrap_or_default());
let tip_amount = if with_tip {
if is_buy {
if priority_fee.buy_tip_fees.len() > i {
priority_fee.buy_tip_fees[i]
let tip_amount = if with_tip {
if is_buy {
buy_tip_fee
} else {
println!(
"❗️❗️❗️[{:?}] - Using buy_tip_fees[0]: {:?}",
swqos_type, priority_fee.buy_tip_fees[0]
);
priority_fee.buy_tip_fees[0]
sell_tip_fee
}
} else {
if priority_fee.sell_tip_fees.len() > i {
priority_fee.sell_tip_fees[i]
} else {
println!(
"❗️❗️❗️[{:?}] - Using sell_tip_fees[0]: {:?}",
swqos_type, priority_fee.sell_tip_fees[0]
);
priority_fee.sell_tip_fees[0]
}
}
} else {
0.0
};
0.0
};
let transaction = build_transaction(
payer,
&priority_fee,
instructions.as_ref().clone(),
lookup_table_key,
recent_blockhash,
data_size_limit,
middleware_manager,
protocol_name,
is_buy,
swqos_type != SwqosType::Default,
&tip_account,
tip_amount,
)
.await?;
println!(
"[{:?}] - Building transaction instructions: {:?}",
swqos_type,
start.elapsed()
);
start = Instant::now();
swqos_client
.send_transaction(
if is_buy { TradeType::Buy } else { TradeType::Sell },
&transaction,
let transaction = build_transaction(
payer,
unit_limit,
unit_price,
instructions.as_ref().clone(),
lookup_table_key,
recent_blockhash,
data_size_limit,
middleware_manager,
protocol_name,
is_buy,
swqos_type != SwqosType::Default,
&tip_account,
tip_amount,
)
.await?;
println!(
"[{:?}] - Submitting transaction instructions: {:?}",
swqos_type,
start.elapsed()
);
println!(
"[{:?}] - Building transaction instructions: {:?}",
swqos_type,
start.elapsed()
);
transaction
.signatures
.first()
.ok_or_else(|| anyhow!("Transaction has no signatures"))
.cloned()
});
start = Instant::now();
handles.push(handle);
swqos_client
.send_transaction(
if is_buy { TradeType::Buy } else { TradeType::Sell },
&transaction,
)
.await?;
println!(
"[{:?}] - Submitting transaction instructions: {:?}",
swqos_type,
start.elapsed()
);
transaction
.signatures
.first()
.ok_or_else(|| anyhow!("Transaction has no signatures"))
.cloned()
});
handles.push(handle);
}
}
// Return as soon as any one succeeds
let (tx, mut rx) = mpsc::channel(swqos_clients.len());
let (tx, mut rx) = mpsc::channel(handles.len());
// Start monitoring tasks
for handle in handles {
+12 -12
View File
@@ -1,9 +1,9 @@
use super::traits::ProtocolParams;
use crate::common::bonding_curve::BondingCurveAccount;
use crate::common::{PriorityFee, SolanaRpcClient};
use crate::common::SolanaRpcClient;
use crate::solana_streamer_sdk::streaming::event_parser::common::EventType;
use crate::solana_streamer_sdk::streaming::event_parser::protocols::bonk::BonkTradeEvent;
use crate::swqos::SwqosClient;
use crate::swqos::settings::SwqosSettings;
use crate::trading::common::get_multi_token_balances;
use crate::trading::MiddlewareManager;
use solana_hash::Hash;
@@ -18,56 +18,56 @@ use spl_associated_token_account::get_associated_token_address;
use std::sync::Arc;
/// Buy parameters
#[derive(Clone)]
pub struct BuyParams {
pub struct InternalBuyParams {
pub rpc: Option<Arc<SolanaRpcClient>>,
pub payer: Arc<Keypair>,
pub mint: Pubkey,
pub sol_amount: u64,
pub slippage_basis_points: Option<u64>,
pub priority_fee: Arc<PriorityFee>,
pub lookup_table_key: Option<Pubkey>,
pub recent_blockhash: Hash,
pub data_size_limit: u32,
pub wait_transaction_confirmed: bool,
pub protocol_params: Box<dyn ProtocolParams>,
pub open_seed_optimize: bool,
pub swqos_clients: Vec<Arc<SwqosClient>>,
pub swqos_settings: Vec<Arc<SwqosSettings>>,
pub middleware_manager: Option<Arc<MiddlewareManager>>,
pub create_wsol_ata: bool,
pub close_wsol_ata: bool,
pub create_mint_ata: bool,
pub custom_cu_limit: Option<u32>,
}
/// Sell parameters
#[derive(Clone)]
pub struct SellParams {
pub struct InternalSellParams {
pub rpc: Option<Arc<SolanaRpcClient>>,
pub payer: Arc<Keypair>,
pub mint: Pubkey,
pub token_amount: Option<u64>,
pub slippage_basis_points: Option<u64>,
pub priority_fee: Arc<PriorityFee>,
pub lookup_table_key: Option<Pubkey>,
pub recent_blockhash: Hash,
pub wait_transaction_confirmed: bool,
pub with_tip: bool,
pub protocol_params: Box<dyn ProtocolParams>,
pub open_seed_optimize: bool,
pub swqos_clients: Vec<Arc<SwqosClient>>,
pub swqos_settings: Vec<Arc<SwqosSettings>>,
pub middleware_manager: Option<Arc<MiddlewareManager>>,
pub create_wsol_ata: bool,
pub close_wsol_ata: bool,
pub custom_cu_limit: Option<u32>,
}
impl std::fmt::Debug for BuyParams {
impl std::fmt::Debug for InternalBuyParams {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "BuyParams: {:?}", self)
write!(f, "InternalBuyParams: {:?}", self)
}
}
impl std::fmt::Debug for SellParams {
impl std::fmt::Debug for InternalSellParams {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "SellParams: {:?}", self)
write!(f, "InternalSellParams: {:?}", self)
}
}
+5 -5
View File
@@ -1,4 +1,4 @@
use super::params::{BuyParams, SellParams};
use super::params::{InternalBuyParams, InternalSellParams};
use anyhow::Result;
use solana_sdk::{instruction::Instruction, signature::Signature};
@@ -6,9 +6,9 @@ use solana_sdk::{instruction::Instruction, signature::Signature};
#[async_trait::async_trait]
pub trait TradeExecutor: Send + Sync {
/// 使用MEV服务执行买入交易
async fn buy_with_tip(&self, params: BuyParams) -> Result<Signature>;
async fn buy_with_tip(&self, params: InternalBuyParams) -> Result<Signature>;
/// 使用MEV服务执行卖出交易
async fn sell_with_tip(&self, params: SellParams) -> Result<Signature>;
async fn sell_with_tip(&self, params: InternalSellParams) -> Result<Signature>;
/// 获取协议名称
fn protocol_name(&self) -> &'static str;
}
@@ -17,10 +17,10 @@ pub trait TradeExecutor: Send + Sync {
#[async_trait::async_trait]
pub trait InstructionBuilder: Send + Sync {
/// 构建买入指令
async fn build_buy_instructions(&self, params: &BuyParams) -> Result<Vec<Instruction>>;
async fn build_buy_instructions(&self, params: &InternalBuyParams) -> Result<Vec<Instruction>>;
/// 构建卖出指令
async fn build_sell_instructions(&self, params: &SellParams) -> Result<Vec<Instruction>>;
async fn build_sell_instructions(&self, params: &InternalSellParams) -> Result<Vec<Instruction>>;
}
/// 协议特定参数trait - 允许每个协议定义自己的参数
+1 -1
View File
@@ -3,7 +3,7 @@ pub mod core;
pub mod factory;
pub mod middleware;
pub use core::params::{BuyParams, SellParams};
pub use core::params::{InternalBuyParams, InternalSellParams};
pub use core::traits::{InstructionBuilder, TradeExecutor};
pub use factory::TradeFactory;
pub use middleware::{InstructionMiddleware, MiddlewareManager};
-105
View File
@@ -1,7 +1,5 @@
pub mod calc;
pub mod price;
use crate::solana_streamer_sdk::streaming::event_parser::protocols::pumpfun::PumpFunTradeEvent;
use crate::trading;
use crate::SolanaTrade;
use solana_sdk::pubkey::Pubkey;
@@ -57,107 +55,4 @@ impl SolanaTrade {
pub async fn close_token_account(&self, mint: &Pubkey) -> Result<(), anyhow::Error> {
trading::common::utils::close_token_account(&self.rpc, self.payer.as_ref(), mint).await
}
// -------------------------------- PumpFun --------------------------------
#[deprecated(since = "0.6.7", note = "This function is deprecated and will be removed in a future version")]
#[inline]
pub fn get_pumpfun_token_buy_price(&self, amount: u64, trade_info: &PumpFunTradeEvent) -> u64 {
crate::instruction::utils::pumpfun::get_buy_price(amount, trade_info)
}
#[deprecated(since = "0.6.7", note = "This function is deprecated and will be removed in a future version")]
#[inline]
pub async fn get_pumpfun_token_current_price(
&self,
mint: &Pubkey,
) -> Result<f64, anyhow::Error> {
let (bonding_curve, _) =
crate::instruction::utils::pumpfun::fetch_bonding_curve_account(&self.rpc, mint)
.await?;
let virtual_sol_reserves = bonding_curve.virtual_sol_reserves;
let virtual_token_reserves = bonding_curve.virtual_token_reserves;
Ok(price::pumpfun::price_token_in_sol(virtual_sol_reserves, virtual_token_reserves))
}
#[deprecated(since = "0.6.7", note = "This function is deprecated and will be removed in a future version")]
#[inline]
pub async fn get_pumpfun_token_real_sol_reserves(
&self,
mint: &Pubkey,
) -> Result<u64, anyhow::Error> {
let (bonding_curve, _) =
crate::instruction::utils::pumpfun::fetch_bonding_curve_account(&self.rpc, mint)
.await?;
let actual_sol_reserves = bonding_curve.real_sol_reserves;
Ok(actual_sol_reserves)
}
#[deprecated(since = "0.6.7", note = "This function is deprecated and will be removed in a future version")]
#[inline]
pub async fn get_pumpfun_token_creator(&self, mint: &Pubkey) -> Result<Pubkey, anyhow::Error> {
let (bonding_curve, _) =
crate::instruction::utils::pumpfun::fetch_bonding_curve_account(&self.rpc, mint)
.await?;
let creator = bonding_curve.creator;
Ok(creator)
}
// -------------------------------- PumpSwap --------------------------------
#[deprecated(since = "0.6.7", note = "This function is deprecated and will be removed in a future version")]
#[inline]
pub async fn get_pumpswap_token_current_price(
&self,
pool_address: &Pubkey,
) -> Result<f64, anyhow::Error> {
let pool = crate::instruction::utils::pumpswap::fetch_pool(&self.rpc, pool_address).await?;
let (base_amount, quote_amount) =
crate::instruction::utils::pumpswap::get_token_balances(&pool, &self.rpc).await?;
// Calculate price using constant product formula (x * y = k)
// Price = quote_amount / base_amount
if base_amount == 0 {
return Err(anyhow::anyhow!("Base amount is zero, cannot calculate price"));
}
let price = quote_amount as f64 / base_amount as f64;
Ok(price)
}
#[deprecated(since = "0.6.7", note = "This function is deprecated and will be removed in a future version")]
#[inline]
pub async fn get_pumpswap_token_real_sol_reserves(
&self,
pool_address: &Pubkey,
) -> Result<u64, anyhow::Error> {
let pool = crate::instruction::utils::pumpswap::fetch_pool(&self.rpc, pool_address).await?;
let (_, quote_amount) =
crate::instruction::utils::pumpswap::get_token_balances(&pool, &self.rpc).await?;
Ok(quote_amount)
}
#[deprecated(since = "0.6.7", note = "This function is deprecated and will be removed in a future version")]
#[inline]
pub async fn get_pumpswap_payer_token_balance(
&self,
pool_address: &Pubkey,
) -> Result<u64, anyhow::Error> {
let pool = crate::instruction::utils::pumpswap::fetch_pool(&self.rpc, pool_address).await?;
let (base_amount, _) =
crate::instruction::utils::pumpswap::get_token_balances(&pool, &self.rpc).await?;
Ok(base_amount)
}
}