Files
sol-trade-sdk/README_CN.md
T
ysq 90ea46ea3f feat: This update includes the following changes:
1. Upgrade version from 0.4.7 to 0.5.0
2. Rename compute unit parameters from unit_limit/unit_price to tip_unit_limit/tip_unit_price
3. Remove creator parameter from API to simplify trading interface
4. Optimize PumpFun and PumpSwap protocol parameter structures with creator_vault support
5. Remove unnecessary constants and functions like TOTAL_SUPPLY and BONDING_CURVE_SUPPLY
6. Improve code formatting and documentation
2025-08-23 20:37:03 +08:00

1045 lines
34 KiB
Markdown
Executable File
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Sol Trade SDK
[中文](https://github.com/0xfnzero/sol-trade-sdk/blob/main/README_CN.md) | [English](https://github.com/0xfnzero/sol-trade-sdk/blob/main/README.md) | [Telegram](https://t.me/fnzero_group)
一个全面的 Rust SDK,用于与 Solana DEX 交易程序进行无缝交互。此 SDK 提供强大的工具和接口集,将 PumpFun、PumpSwap 和 Bonk 功能集成到您的应用程序中。
## 项目特性
1. **PumpFun 交易**: 支持`购买``卖出`功能
2. **PumpSwap 交易**: 支持 PumpSwap 池的交易操作
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、Node1 等服务
10. **并发交易**: 同时使用多个 MEV 服务发送交易,最快的成功,其他失败
11. **统一交易接口**: 使用统一的交易协议枚举进行交易操作
12. **中间件系统**: 支持自定义指令中间件,可在交易执行前对指令进行修改、添加或移除
## 安装
### 直接克隆
将此项目克隆到您的项目目录:
```bash
cd your_project_root_directory
git clone https://github.com/0xfnzero/sol-trade-sdk
```
在您的`Cargo.toml`中添加依赖:
```toml
# 添加到您的 Cargo.toml
sol-trade-sdk = { path = "./sol-trade-sdk", version = "0.5.0" }
```
### 使用 crates.io
```toml
# 添加到您的 Cargo.toml
sol-trade-sdk = "0.5.0"
```
## 使用示例
### 重要参数说明
#### auto_handle_wsol 参数
在 PumpSwap、Bonk、Raydium CPMM 交易中,`auto_handle_wsol` 参数用于自动处理 wSOLWrapped SOL):
- **作用机制**
-`auto_handle_wsol: true` 时,SDK 会自动处理 SOL 与 wSOL 之间的转换
- 买入时:自动将 SOL 包装为 wSOL 进行交易
- 卖出时:自动将获得的 wSOL 解包装为 SOL
- 默认值为 `true`
#### lookup_table_key 参数
`lookup_table_key` 参数是一个可选的 `Pubkey`,用于指定地址查找表以优化交易:
- **用途**:地址查找表可以通过存储常用地址来减少交易大小并提高执行速度
- **使用方法**
- 可以在 `TradeConfig` 中全局设置,用于所有交易
- 可以在 `buy()``sell()` 方法中按交易覆盖
- 如果不提供,默认为 `None`
- **优势**
- 通过从查找表引用地址来减少交易大小
- 提高交易成功率和速度
- 特别适用于具有许多账户引用的复杂交易
### 1. 事件订阅 - 监听代币交易
#### 1.1 使用 Yellowstone gRPC 订阅事件
```rust
use sol_trade_sdk::solana_streamer_sdk::{
streaming::{
event_parser::{
protocols::{
bonk::{BonkPoolCreateEvent, BonkTradeEvent},
pumpfun::{PumpFunCreateTokenEvent, PumpFunTradeEvent},
pumpswap::{
PumpSwapBuyEvent, PumpSwapCreatePoolEvent, PumpSwapDepositEvent,
PumpSwapSellEvent, PumpSwapWithdrawEvent,
},
raydium_cpmm::RaydiumCpmmSwapEvent,
},
Protocol, UnifiedEvent,
},
yellowstone_grpc::{AccountFilter, TransactionFilter},
YellowstoneGrpc,
},
match_event,
};
use solana_streamer_sdk::streaming::event_parser::protocols::{
bonk::parser::BONK_PROGRAM_ID,
pumpfun::parser::PUMPFUN_PROGRAM_ID,
pumpswap::parser::PUMPSWAP_PROGRAM_ID,
raydium_amm_v4::parser::RAYDIUM_AMM_V4_PROGRAM_ID,
raydium_clmm::parser::RAYDIUM_CLMM_PROGRAM_ID,
raydium_cpmm::parser::RAYDIUM_CPMM_PROGRAM_ID
};
async fn test_grpc() -> Result<(), Box<dyn std::error::Error>> {
// 使用 GRPC 客户端订阅事件
println!("正在订阅 GRPC 事件...");
let grpc = YellowstoneGrpc::new(
"https://solana-yellowstone-grpc.publicnode.com:443".to_string(),
None,
)?;
// 定义回调函数处理事件
let callback = |event: Box<dyn UnifiedEvent>| {
match_event!(event, {
BonkPoolCreateEvent => |e: BonkPoolCreateEvent| {
println!("BonkPoolCreateEvent: {:?}", e.base_mint_param.symbol);
},
BonkTradeEvent => |e: BonkTradeEvent| {
println!("BonkTradeEvent: {:?}", e);
},
PumpFunTradeEvent => |e: PumpFunTradeEvent| {
println!("PumpFunTradeEvent: {:?}", e);
},
PumpFunCreateTokenEvent => |e: PumpFunCreateTokenEvent| {
println!("PumpFunCreateTokenEvent: {:?}", e);
},
PumpSwapBuyEvent => |e: PumpSwapBuyEvent| {
println!("Buy event: {:?}", e);
},
PumpSwapSellEvent => |e: PumpSwapSellEvent| {
println!("Sell event: {:?}", e);
},
PumpSwapCreatePoolEvent => |e: PumpSwapCreatePoolEvent| {
println!("CreatePool event: {:?}", e);
},
PumpSwapDepositEvent => |e: PumpSwapDepositEvent| {
println!("Deposit event: {:?}", e);
},
PumpSwapWithdrawEvent => |e: PumpSwapWithdrawEvent| {
println!("Withdraw event: {:?}", e);
},
RaydiumCpmmSwapEvent => |e: RaydiumCpmmSwapEvent| {
println!("Raydium CPMM Swap event: {:?}", e);
},
// .....
// 更多的事件和说明请参考 https://github.com/0xfnzero/solana-streamer
});
};
// 订阅多个协议的事件
println!("开始监听事件,按 Ctrl+C 停止...");
let protocols = vec![Protocol::PumpFun, Protocol::PumpSwap, Protocol::Bonk, Protocol::RaydiumCpmm];
// 过滤账户
let account_include = vec![
PUMPFUN_PROGRAM_ID.to_string(), // 监听 pumpfun 程序 ID
PUMPSWAP_PROGRAM_ID.to_string(), // 监听 pumpswap 程序 ID
BONK_PROGRAM_ID.to_string(), // 监听 bonk 程序 ID
RAYDIUM_CPMM_PROGRAM_ID.to_string(), // 监听 raydium_cpmm 程序 ID
RAYDIUM_CLMM_PROGRAM_ID.to_string(), // 监听 raydium_clmm 程序 ID
RAYDIUM_AMM_V4_PROGRAM_ID.to_string(), // 监听 raydium_amm_v4 程序 ID
"xxxxxxxx".to_string(), // 监听特定账户
];
let account_exclude = vec![];
let account_required = vec![];
// 监听交易数据
let transaction_filter = TransactionFilter {
account_include: account_include.clone(),
account_exclude,
account_required,
};
// 监听属于owner程序的账号数据 -> 账号事件监听
let account_filter = AccountFilter {
account: vec![],
owner: account_include.clone()
};
grpc.subscribe_events_immediate(
protocols,
None,
transaction_filter,
account_filter,
None,
None,
callback,
)
.await?;
Ok(())
}
```
#### 1.2 使用 ShredStream 订阅事件
```rust
use sol_trade_sdk::solana_streamer_sdk::streaming::ShredStreamGrpc;
async fn test_shreds() -> Result<(), Box<dyn std::error::Error>> {
// 使用 ShredStream 客户端订阅事件
println!("正在订阅 ShredStream 事件...");
let shred_stream = ShredStreamGrpc::new("http://127.0.0.1:10800".to_string()).await?;
// 定义回调函数处理事件(与上面相同)
let callback = |event: Box<dyn UnifiedEvent>| {
match_event!(event, {
BonkPoolCreateEvent => |e: BonkPoolCreateEvent| {
println!("BonkPoolCreateEvent: {:?}", e.base_mint_param.symbol);
},
BonkTradeEvent => |e: BonkTradeEvent| {
println!("BonkTradeEvent: {:?}", e);
},
PumpFunTradeEvent => |e: PumpFunTradeEvent| {
println!("PumpFunTradeEvent: {:?}", e);
},
PumpFunCreateTokenEvent => |e: PumpFunCreateTokenEvent| {
println!("PumpFunCreateTokenEvent: {:?}", e);
},
PumpSwapBuyEvent => |e: PumpSwapBuyEvent| {
println!("Buy event: {:?}", e);
},
PumpSwapSellEvent => |e: PumpSwapSellEvent| {
println!("Sell event: {:?}", e);
},
PumpSwapCreatePoolEvent => |e: PumpSwapCreatePoolEvent| {
println!("CreatePool event: {:?}", e);
},
PumpSwapDepositEvent => |e: PumpSwapDepositEvent| {
println!("Deposit event: {:?}", e);
},
PumpSwapWithdrawEvent => |e: PumpSwapWithdrawEvent| {
println!("Withdraw event: {:?}", e);
},
RaydiumCpmmSwapEvent => |e: RaydiumCpmmSwapEvent| {
println!("Raydium CPMM Swap event: {:?}", e);
},
// .....
// 更多的事件和说明请参考 https://github.com/0xfnzero/solana-streamer
});
};
// 订阅事件
println!("开始监听事件,按 Ctrl+C 停止...");
let protocols = vec![Protocol::PumpFun, Protocol::PumpSwap, Protocol::Bonk, Protocol::RaydiumCpmm];
shred_stream
.shredstream_subscribe(protocols, None, None, callback)
.await?;
Ok(())
}
```
### 2. 初始化 SolanaTrade 实例
#### 2.1 SWQOS 服务配置说明
在配置 SWQOS 服务时,需要注意不同服务的参数要求:
- **Jito**: 第一个参数是 UUID,如果没有 UUID 则传空字符串 `""`
- **NextBlock**: 第一个参数是 API Token
- **Bloxroute**: 第一个参数是 API Token
- **ZeroSlot**: 第一个参数是 API Token
- **Temporal**: 第一个参数是 API Token
- **FlashBlock**: 第一个参数是 API Token, 添加tg官方客服https://t.me/FlashBlock_Official 获取免费key立即加速你的交易!官方文档: https://doc.flashblock.trade/
- **Node1**: 第一个参数是 API Token, 添加tg官方客服https://t.me/node1_me 获取免费key立即加速你的交易!官方文档: https://node1.me/docs.html
```rust
use std::{str::FromStr, sync::Arc};
use sol_trade_sdk::{
common::{AnyResult, PriorityFee, TradeConfig},
swqos::{SwqosConfig, SwqosRegion},
SolanaTrade
};
use solana_sdk::{commitment_config::CommitmentConfig, pubkey::Pubkey, signature::Keypair};
/// 创建 SolanaTrade 客户端的示例
async fn test_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();
// 配置各种 SWQOS 服务
let swqos_configs = vec![
// 第一个参数是 uuid,如果没有 uuid 则传空字符串
SwqosConfig::Jito("your uuid".to_string(), SwqosRegion::Frankfurt),
SwqosConfig::NextBlock("your api_token".to_string(), SwqosRegion::Frankfurt),
SwqosConfig::Bloxroute("your api_token".to_string(), SwqosRegion::Frankfurt),
SwqosConfig::ZeroSlot("your api_token".to_string(), SwqosRegion::Frankfurt),
SwqosConfig::Temporal("your api_token".to_string(), SwqosRegion::Frankfurt),
// 添加tg官方客服 https://t.me/FlashBlock_Official 获取免费 FlashBlock key
SwqosConfig::FlashBlock("your api_token".to_string(), SwqosRegion::Frankfurt),
// 添加tg官方客服 https://t.me/node1_me 获取免费 Node1 key
SwqosConfig::Node1("your api_token".to_string(), SwqosRegion::Frankfurt),
SwqosConfig::Default(rpc_url.clone()),
];
// 定义交易配置
let trade_config = TradeConfig {
rpc_url: rpc_url.clone(),
commitment: CommitmentConfig::confirmed(),
priority_fee: PriorityFee::default(),
swqos_configs,
lookup_table_key: None,
};
let solana_trade_client = SolanaTrade::new(Arc::new(payer), trade_config).await;
println!("SolanaTrade client created successfully!");
Ok(solana_trade_client)
}
```
### 3. PumpFun 交易操作
```rust
use sol_trade_sdk::{
common::{bonding_curve::BondingCurveAccount, AnyResult},
constants::pumpfun::global_constants::TOKEN_TOTAL_SUPPLY,
trading::{core::params::PumpFunParams, factory::DexType},
};
use sol_trade_sdk::solana_streamer_sdk::streaming::event_parser::protocols::pumpfun::PumpFunTradeEvent;
// pumpfun 狙击者交易
async fn test_pumpfun_sniper_trade_with_shreds(trade_info: PumpFunTradeEvent) -> AnyResult<()> {
println!("Testing PumpFun trading...");
// 如果不是开发者购买,则返回
if !trade_info.is_dev_create_token_trade {
return Ok(());
}
let trade_client = test_create_solana_trade_client().await?;
let mint_pubkey = trade_info.mint;
let creator = trade_info.creator;
let dev_sol_amount = trade_info.max_sol_cost;
let dev_token_amount = trade_info.token_amount;
let slippage_basis_points = Some(100);
let recent_blockhash = trade_client.rpc.get_latest_blockhash().await?;
println!("Buying tokens from PumpFun...");
// 我本次交易所花的的sol金额
let buy_sol_amount = 100_000;
trade_client.buy(
DexType::PumpFun,
mint_pubkey,
Some(creator),
buy_sol_amount,
slippage_basis_points,
recent_blockhash,
None,
Box::new(PumpFunParams::from_dev_trade(
&mint_pubkey,
dev_token_amount,
dev_sol_amount,
creator,
None,
)),
None,
)
.await?;
Ok(())
}
// pumpfun 跟单交易
async fn test_pumpfun_copy_trade_with_grpc(trade_info: PumpFunTradeEvent) -> AnyResult<()> {
println!("Testing PumpFun trading...");
let trade_client = test_create_solana_trade_client().await?;
let mint_pubkey = trade_info.mint;
let creator = trade_info.creator;
let slippage_basis_points = Some(100);
let recent_blockhash = trade_client.rpc.get_latest_blockhash().await?;
println!("Buying tokens from PumpFun...");
// 我本次交易所花的的sol金额
let buy_sol_amount = 100_000;
trade_client.buy(
DexType::PumpFun,
mint_pubkey,
Some(creator),
buy_sol_amount,
slippage_basis_points,
recent_blockhash,
None,
Box::new(PumpFunParams::from_trade(&trade_info, None)),
None,
)
.await?;
Ok(())
}
// pumpfun 卖出token
async fn test_pumpfun_sell(trade_info: PumpFunTradeEvent) -> AnyResult<()> {
let trade_client = test_create_solana_trade_client().await?;
let mint_pubkey = trade_info.mint;
let creator = trade_info.creator;
let slippage_basis_points = Some(100);
let recent_blockhash = trade_client.rpc.get_latest_blockhash().await?;
let amount_token = 100_000_000;
trade_client.sell(
DexType::PumpFun,
mint_pubkey,
Some(creator),
amount_token,
slippage_basis_points,
recent_blockhash,
None,
false,
Box::new(PumpFunParams::from_trade(&trade_info, None)),
None,
)
.await?;
Ok(())
}
```
### 4. PumpSwap 交易操作
```rust
use sol_trade_sdk::{
common::AnyResult,
trading::{core::params::PumpSwapParams, factory::DexType},
};
use solana_sdk::{pubkey::Pubkey, str::FromStr};
async fn test_pumpswap() -> AnyResult<()> {
println!("Testing PumpSwap trading...");
let client = test_create_solana_trade_client().await?;
let creator = Pubkey::from_str("11111111111111111111111111111111")?;
let mint_pubkey = Pubkey::from_str("2zMMhcVQEXDtdE6vsFS7S7D5oUodfJHE8vd1gnBouauv")?;
let buy_sol_cost = 100_000;
let slippage_basis_points = Some(100);
let recent_blockhash = client.rpc.get_latest_blockhash().await?;
let pool_address = Pubkey::from_str("xxxxxxx")?;
let base_mint = Pubkey::from_str("2zMMhcVQEXDtdE6vsFS7S7D5oUodfJHE8vd1gnBouauv")?;
let quote_mint = Pubkey::from_str("So11111111111111111111111111111111111111112")?;
let pool_base_token_reserves = 0; // 输入正确的值
let pool_quote_token_reserves = 0; // 输入正确的值
// 买入代币
println!("Buying tokens from PumpSwap...");
client.buy(
DexType::PumpSwap,
mint_pubkey,
Some(creator),
buy_sol_cost,
slippage_basis_points,
recent_blockhash,
None,
// 通过 RPC 调用,会增加延迟。可以通过使用 from_buy_trade 或手动初始化 PumpSwapParams 来优化
Box::new(PumpSwapParams::from_pool_address_by_rpc(&client.rpc, &pool_address).await?),
None,
).await?;
// 卖出代币
println!("Selling tokens from PumpSwap...");
let amount_token = 0;
client.sell(
DexType::PumpSwap,
mint_pubkey,
Some(creator),
amount_token,
slippage_basis_points,
recent_blockhash,
None,
false,
// 通过 RPC 调用,会增加延迟。可以通过使用 from_sell_trade 或手动初始化 PumpSwapParams 来优化
Box::new(PumpSwapParams::from_pool_address_by_rpc(&client.rpc, &pool_address).await?),
None,
).await?;
Ok(())
}
```
### 5. Raydium CPMM 交易操作
```rust
use sol_trade_sdk::{
trading::{
core::params::RaydiumCpmmParams,
factory::DexType,
raydium_cpmm::common::{get_buy_token_amount, get_sell_sol_amount}
},
};
use solana_sdk::{pubkey::Pubkey, str::FromStr};
use spl_token; // 用于标准 SPL Token
// use spl_token_2022; // 用于 Token 2022 标准(如果需要)
async fn test_raydium_cpmm() -> Result<(), Box<dyn std::error::Error>> {
println!("Testing Raydium CPMM trading...");
let trade_client = test_create_solana_trade_client().await?;
let mint_pubkey = Pubkey::from_str("xxxxxxxx")?; // 代币地址
let buy_sol_cost = 100_000; // 0.0001 SOL(以lamports为单位)
let slippage_basis_points = Some(100); // 1% 滑点
let recent_blockhash = trade_client.rpc.get_latest_blockhash().await?;
let pool_state = Pubkey::from_str("xxxxxxx")?; // 池状态地址
// 计算买入时预期获得的代币数量
let buy_amount_out = get_buy_token_amount(&trade_client.rpc, &pool_state, buy_sol_cost).await?;
println!("Buying tokens from Raydium CPMM...");
trade_client.buy(
DexType::RaydiumCpmm,
mint_pubkey,
None,
buy_sol_cost,
slippage_basis_points,
recent_blockhash,
None,
// 通过 RPC 调用,会增加延迟,或手动初始化 RaydiumCpmmParams
Box::new(
RaydiumCpmmParams::from_pool_address_by_rpc(&trade_client.rpc, &pool_state).await?,
),
None,
).await?;
println!("Selling tokens from Raydium CPMM...");
let amount_token = 100_000_000; // 卖出代币数量
let sell_sol_amount = get_sell_sol_amount(&trade_client.rpc, &pool_state, amount_token).await?;
trade_client.sell(
DexType::RaydiumCpmm,
mint_pubkey,
None,
amount_token,
slippage_basis_points,
recent_blockhash,
None,
false,
// 通过 RPC 调用,会增加延迟,或手动初始化 RaydiumCpmmParams
Box::new(
RaydiumCpmmParams::from_pool_address_by_rpc(&trade_client.rpc, &pool_state).await?,
),
None,
).await?;
Ok(())
}
```
### 6. Raydium AMM V4 交易操作
```rust
use sol_trade_sdk::trading::core::params::RaydiumAmmV4Params;
async fn test_raydium_amm_v4() -> Result<(), Box<dyn std::error::Error>> {
println!("Testing Raydium AMM V4 trading...");
let trade_client = test_create_solana_trade_client().await?;
let mint_pubkey = Pubkey::from_str("xxxxxxx")?; // 代币地址
let buy_sol_cost = 100_000; // 0.0001 SOL(以lamports为单位)
let slippage_basis_points = Some(100); // 1% 滑点
let recent_blockhash = trade_client.rpc.get_latest_blockhash().await?;
let amm_address = Pubkey::from_str("xxxxxx")?; // AMM 池地址
println!("Buying tokens from Raydium AMM V4...");
trade_client.buy(
DexType::RaydiumAmmV4,
mint_pubkey,
None,
buy_sol_cost,
slippage_basis_points,
recent_blockhash,
None,
// 通过 RPC 调用,会增加延迟,或使用 from_amm_info_and_reserves 或手动初始化 RaydiumAmmV4Params
Box::new(
RaydiumAmmV4Params::from_amm_address_by_rpc(&trade_client.rpc, amm_address).await?,
),
None,
).await?;
println!("Selling tokens from Raydium AMM V4...");
let amount_token = 100_000_000; // 卖出代币数量
trade_client.sell(
DexType::RaydiumAmmV4,
mint_pubkey,
None,
amount_token,
slippage_basis_points,
recent_blockhash,
None,
false,
// 通过 RPC 调用,会增加延迟,或使用 from_amm_info_and_reserves 或手动初始化 RaydiumAmmV4Params
Box::new(
RaydiumAmmV4Params::from_amm_address_by_rpc(&trade_client.rpc, amm_address).await?,
),
None,
).await?;
Ok(())
}
```
### 7. Bonk 交易操作
```rust
use sol_trade_sdk::{
common::AnyResult,
trading::{core::params::BonkParams, factory::DexType},
};
use sol_trade_sdk::solana_streamer_sdk::streaming::event_parser::protocols::bonk::BonkTradeEvent;
use solana_sdk::{pubkey::Pubkey, str::FromStr};
// bonk 狙击者交易
async fn test_bonk_sniper_trade_with_shreds(trade_info: BonkTradeEvent) -> AnyResult<()> {
println!("Testing Bonk trading...");
if !trade_info.is_dev_create_token_trade {
return Ok(());
}
let trade_client = test_create_solana_trade_client().await?;
let mint_pubkey = Pubkey::from_str("xxxxxxx")?;
let buy_sol_cost = 100_000;
let slippage_basis_points = Some(100);
let recent_blockhash = trade_client.rpc.get_latest_blockhash().await?;
println!("Buying tokens from letsbonk.fun...");
// 使用开发者交易信息构建 BonkParams,可以节约交易时间
trade_client.buy(
DexType::Bonk,
mint_pubkey,
None,
buy_sol_cost,
slippage_basis_points,
recent_blockhash,
None,
Box::new(BonkParams::from_dev_trade(trade_info.clone())),
None,
).await?;
println!("Selling tokens from letsbonk.fun...");
let amount_token = 0;
trade_client.sell(
DexType::Bonk,
mint_pubkey,
None,
amount_token,
slippage_basis_points,
recent_blockhash,
None,
false,
Box::new(BonkParams::from_dev_trade(trade_info)),
None,
).await?;
Ok(())
}
// bonk 跟单交易
async fn test_bonk_copy_trade_with_grpc(trade_info: BonkTradeEvent) -> AnyResult<()> {
println!("Testing Bonk trading...");
let trade_client = test_create_solana_trade_client().await?;
let mint_pubkey = Pubkey::from_str("xxxxxxx")?;
let buy_sol_cost = 100_000;
let slippage_basis_points = Some(100);
let recent_blockhash = trade_client.rpc.get_latest_blockhash().await?;
println!("Buying tokens from letsbonk.fun...");
// 使用交易事件信息构建 BonkParams,可以节约交易时间
trade_client.buy(
DexType::Bonk,
mint_pubkey,
None,
buy_sol_cost,
slippage_basis_points,
recent_blockhash,
None,
Box::new(BonkParams::from_trade(trade_info.clone())),
None,
).await?;
println!("Selling tokens from letsbonk.fun...");
let amount_token = 0;
trade_client.sell(
DexType::Bonk,
mint_pubkey,
None,
amount_token,
slippage_basis_points,
recent_blockhash,
None,
false,
Box::new(BonkParams::from_trade(trade_info)),
None,
).await?;
Ok(())
}
// bonk 普通交易
async fn test_bonk() -> Result<(), Box<dyn std::error::Error>> {
println!("Testing Bonk trading...");
let trade_client = test_create_solana_trade_client().await?;
let mint_pubkey = Pubkey::from_str("xxxxxxx")?;
let buy_sol_amount = 100_000;
let slippage_basis_points = Some(100); // 1%
let recent_blockhash = trade_client.rpc.get_latest_blockhash().await?;
println!("Buying tokens from letsbonk.fun...");
trade_client.buy(
DexType::Bonk,
mint_pubkey,
None,
buy_sol_amount,
slippage_basis_points,
recent_blockhash,
None,
// 通过 RPC 调用,会增加延迟。可以通过使用 from_trade 或手动初始化 BonkParams 来优化
Box::new(BonkParams::from_mint_by_rpc(&trade_client.rpc, &mint_pubkey).await?),
None,
)
.await?;
println!("Selling tokens from letsbonk.fun...");
let amount_token = 100_000;
trade_client.sell(
DexType::Bonk,
mint_pubkey,
None,
amount_token,
slippage_basis_points,
recent_blockhash,
None,
false,
// 通过 RPC 调用,会增加延迟。可以通过使用 from_trade 或手动初始化 BonkParams 来优化
Box::new(BonkParams::from_mint_by_rpc(&trade_client.rpc, &mint_pubkey).await?),
None,
)
.await?;
Ok(())
}
```
### 8. 中间件系统
SDK 提供了强大的中间件系统,允许您在交易执行前对指令进行修改、添加或移除。这为您提供了极大的灵活性来自定义交易行为。
#### 8.1 使用内置的日志中间件
```rust
use sol_trade_sdk::{
trading::{
factory::DexType,
middleware::builtin::LoggingMiddleware,
MiddlewareManager,
},
};
async fn test_middleware() -> AnyResult<()> {
let mut client = test_create_solana_trade_client().await?;
// SDK 内置的示例中间件,打印指令信息
// 您可以参考 LoggingMiddleware 来实现 InstructionMiddleware trait 来实现自己的中间件
let middleware_manager = MiddlewareManager::new()
.add_middleware(Box::new(LoggingMiddleware));
client = client.with_middleware_manager(middleware_manager);
let creator = Pubkey::from_str("11111111111111111111111111111111")?;
let mint_pubkey = Pubkey::from_str("xxxxx")?;
let buy_sol_cost = 100_000;
let slippage_basis_points = Some(100);
let recent_blockhash = client.rpc.get_latest_blockhash().await?;
let pool_address = Pubkey::from_str("xxxx")?;
// 购买代币
println!("Buying tokens from PumpSwap...");
client
.buy(
DexType::PumpSwap,
mint_pubkey,
Some(creator),
buy_sol_cost,
slippage_basis_points,
recent_blockhash,
None,
Box::new(PumpSwapParams::from_pool_address_by_rpc(&client.rpc, &pool_address).await?),
None,
)
.await?;
Ok(())
}
```
#### 8.2 创建自定义中间件
您可以通过实现 `InstructionMiddleware` trait 来创建自定义中间件:
```rust
use sol_trade_sdk::trading::middleware::traits::InstructionMiddleware;
use anyhow::Result;
use solana_sdk::instruction::Instruction;
/// 自定义中间件示例 - 添加额外指令
#[derive(Clone)]
pub struct CustomMiddleware;
impl InstructionMiddleware for CustomMiddleware {
fn name(&self) -> &'static str {
"CustomMiddleware"
}
fn process_protocol_instructions(
&self,
protocol_instructions: Vec<Instruction>,
protocol_name: String,
is_buy: bool,
) -> Result<Vec<Instruction>> {
println!("自定义中间件处理中,协议: {}", protocol_name);
// 在这里您可以:
// 1. 修改现有指令
// 2. 添加新指令
// 3. 移除特定指令
// 示例:在指令开始前添加一个自定义指令
// let custom_instruction = create_your_custom_instruction();
// instructions.insert(0, custom_instruction);
Ok(protocol_instructions)
}
fn process_full_instructions(
&self,
full_instructions: Vec<Instruction>,
protocol_name: String,
is_buy: bool,
) -> Result<Vec<Instruction>> {
println!("自定义中间件处理中,指令数量: {}", full_instructions.len());
Ok(full_instructions)
}
fn clone_box(&self) -> Box<dyn InstructionMiddleware> {
Box::new(self.clone())
}
}
// 使用自定义中间件
async fn test_custom_middleware() -> AnyResult<()> {
let mut client = test_create_solana_trade_client().await?;
let middleware_manager = MiddlewareManager::new()
.add_middleware(Box::new(LoggingMiddleware)) // 日志中间件
.add_middleware(Box::new(CustomMiddleware));
client = client.with_middleware_manager(middleware_manager);
// 现在所有交易都会通过您的中间件处理
// ...
Ok(())
}
```
#### 8.3 中间件执行顺序
中间件按照添加顺序依次执行:
```rust
let middleware_manager = MiddlewareManager::new()
.add_middleware(Box::new(FirstMiddleware)) // 第一个执行
.add_middleware(Box::new(SecondMiddleware)) // 第二个执行
.add_middleware(Box::new(ThirdMiddleware)); // 最后执行
```
### 9. 自定义优先费用配置
```rust
use sol_trade_sdk::common::PriorityFee;
// 自定义优先费用配置
let priority_fee = PriorityFee {
unit_limit: 190000,
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,
};
// 在TradeConfig中使用自定义优先费用
let trade_config = TradeConfig {
rpc_url: rpc_url.clone(),
commitment: CommitmentConfig::confirmed(),
priority_fee, // 使用自定义优先费用
swqos_configs,
lookup_table_key: None,
};
```
## 支持的交易平台
- **PumpFun**: 主要的 meme 币交易平台
- **PumpSwap**: PumpFun 的交换协议
- **Bonk**: 代币发行平台(letsbonk.fun
- **Raydium CPMM**: Raydium 的集中流动性做市商协议
- **Raydium AMM V4**: Raydium 的自动做市商 V4 协议
## MEV 保护服务
- **Jito**: 高性能区块空间
- **NextBlock**: 快速交易执行
- **ZeroSlot**: 零延迟交易
- **Temporal**: 时间敏感交易
- **Bloxroute**: 区块链网络加速
- **FlashBlock**: 高速交易执行,支持 API 密钥认证 - [官方文档](https://doc.flashblock.trade/)
- **Node1**: 高速交易执行,支持 API 密钥认证 - [官方文档](https://node1.me/docs.html)
## 新架构特性
### 统一交易接口
- **TradingProtocol 枚举**: 使用统一的协议枚举(PumpFun、PumpSwap、Bonk、RaydiumCpmm、RaydiumAmmV4
- **统一的 buy/sell 方法**: 所有协议都使用相同的交易方法签名
- **协议特定参数**: 每个协议都有自己的参数结构(PumpFunParams、RaydiumCpmmParams、RaydiumAmmV4Params 等)
### 事件解析系统
- **统一事件接口**: 所有协议事件都实现 UnifiedEvent 特征
- **协议特定事件**: 每个协议都有自己的事件类型
- **事件工厂**: 自动识别和解析不同协议的事件
### 交易引擎
- **统一交易接口**: 所有交易操作都使用相同的方法
- **协议抽象**: 支持多个协议的交易操作
- **并发执行**: 支持同时向多个 MEV 服务发送交易
## 价格计算工具
SDK 包含所有支持协议的价格计算工具,位于 `src/utils/price/` 目录。
## 数量计算工具
SDK 提供各种协议的交易数量计算功能,位于 `src/utils/calc/` 目录:
- **通用计算函数**: 提供通用的手续费计算和除法运算工具
- **协议特定计算**: 针对每个协议的特定计算逻辑
- **PumpFun**: 基于联合曲线的代币购买/销售数量计算
- **PumpSwap**: 支持多种交易对的数量计算
- **Raydium AMM V4**: 自动做市商池的数量和手续费计算
- **Raydium CPMM**: 恒定乘积做市商的数量计算
- **Bonk**: 专门的 Bonk 代币计算逻辑
主要功能包括:
- 根据输入金额计算输出数量
- 手续费计算和分配
- 滑点保护计算
- 流动性池状态计算
## 项目结构
```
src/
├── common/ # 通用功能和工具
├── constants/ # 常量定义
├── instruction/ # 指令构建
├── 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 # 示例程序
```
## 许可证
MIT 许可证
## 联系方式
- 项目仓库: https://github.com/0xfnzero/sol-trade-sdk
- Telegram 群组: https://t.me/fnzero_group
## 重要注意事项
1. 在主网使用前请充分测试
2. 正确设置私钥和 API 令牌
3. 注意滑点设置避免交易失败
4. 监控余额和交易费用
5. 遵循相关法律法规
## 语言版本
- [English](README.md)
- [中文](README_CN.md)