Release v4.0.19

This commit is contained in:
0xfnzero
2026-06-08 00:00:32 +08:00
parent b8325b2b52
commit 7471bcba09
8 changed files with 222 additions and 16 deletions
+1 -1
View File
@@ -1,6 +1,6 @@
[package]
name = "sol-trade-sdk"
version = "4.0.18"
version = "4.0.19"
edition = "2021"
authors = [
"William <byteblock6@gmail.com>",
+25 -2
View File
@@ -259,7 +259,8 @@ Optional builder methods:
| `.wait_for_all_submits(true)` | In fast-submit mode, wait for all SWQoS lane responses and return all signatures. |
| `.simulate(true)` | Build and simulate the transaction instead of sending it. |
| `.grpc_recv_us(ts)` | Attach upstream receive timestamp for latency tracing. |
| `SimpleBuyParams::with_durable_nonce(...)` / `SimpleSellParams::with_durable_nonce(...)` | Use durable nonce instead of `recent_blockhash`. |
| `.durable_nonce(nonce_info)` | Use durable nonce and clear `recent_blockhash`. Recommended when you start from `SimpleBuyParams::new(...)` / `SimpleSellParams::new(...)`. |
| `SimpleBuyParams::with_durable_nonce(...)` / `SimpleSellParams::with_durable_nonce(...)` | Construct params directly with durable nonce instead of `recent_blockhash`. |
| `SimpleSellParams::with_tip(false)` | Disable relay tips for sells. Buys use the gas fee strategy/tip settings. |
`TradeBuyParams` and `TradeSellParams` remain available as advanced low-level APIs. See the dedicated [Trading Parameters Reference](docs/TRADING_PARAMETERS.md).
@@ -323,7 +324,29 @@ let temporal_config = SwqosConfig::Temporal(
- If no custom URL is provided (`None`), the system will use the default endpoint for the specified `SwqosRegion`
- This allows for maximum flexibility while maintaining backward compatibility
When using multiple MEV services, you need to use `Durable Nonce`. You need to use the `fetch_nonce_info` function to get the latest `nonce` value, and use it as the `durable_nonce` when trading.
When using multiple MEV services, you need to use `Durable Nonce`. Fetch the latest nonce value and attach it to the high-level buy/sell params:
```rust
use sol_trade_sdk::{fetch_nonce_info, AccountPolicy, BuyAmount, SimpleBuyParams};
let nonce_info = fetch_nonce_info(&client.infrastructure.rpc, nonce_account)
.await
.expect("nonce account must be initialized");
let buy_params = SimpleBuyParams::new(
DexType::PumpFun,
TradeTokenType::SOL,
mint_pubkey,
BuyAmount::WithMaxInput { quote_amount: buy_sol_amount },
DexParamEnum::PumpFun(pumpfun_params),
recent_blockhash, // will be cleared by `.durable_nonce(...)`
gas_fee_strategy.clone(),
)
.durable_nonce(nonce_info)
.account_policy(AccountPolicy::HotPathMinimal);
client.buy_simple(buy_params).await?;
```
#### Astralane (Binary / Plain HTTP / QUIC)
+25 -2
View File
@@ -258,7 +258,8 @@ client.buy_simple(buy_params).await?;
| `.wait_for_all_submits(true)` | fast-submit 模式下等待所有 SWQoS 通道返回,并拿到全部签名。 |
| `.simulate(true)` | 只构建并模拟交易,不真正发送。 |
| `.grpc_recv_us(ts)` | 传入上游收到事件的微秒时间戳,用于延迟追踪。 |
| `SimpleBuyParams::with_durable_nonce(...)` / `SimpleSellParams::with_durable_nonce(...)` | 使用 durable nonce不使用 `recent_blockhash`。 |
| `.durable_nonce(nonce_info)` | 使用 durable nonce并清空 `recent_blockhash`如果你从 `SimpleBuyParams::new(...)` / `SimpleSellParams::new(...)` 开始构造,推荐用这个。 |
| `SimpleBuyParams::with_durable_nonce(...)` / `SimpleSellParams::with_durable_nonce(...)` | 直接用 durable nonce 构造参数,不使用 `recent_blockhash`。 |
| `SimpleSellParams::with_tip(false)` | 关闭卖出交易 relay tip。买入的 tip 使用 gas fee strategy 控制。 |
`TradeBuyParams``TradeSellParams` 仍保留为高级低层接口。详细说明见 [交易参数参考手册](docs/TRADING_PARAMETERS_CN.md)。
@@ -322,7 +323,29 @@ let temporal_config = SwqosConfig::Temporal(
- 如果没有提供自定义 URL`None`),系统将使用指定 `SwqosRegion` 的默认端点
- 这提供了最大的灵活性,同时保持向后兼容性
当使用多个MEV服务时,需要使用`Durable Nonce`你需要使用`fetch_nonce_info`函数获取最新`nonce`值,并在交易的时候将`durable_nonce`填入交易参数。
当使用多个 MEV 服务时,需要使用 `Durable Nonce`获取最新 nonce,再挂到新的 buy/sell 参数上:
```rust
use sol_trade_sdk::{fetch_nonce_info, AccountPolicy, BuyAmount, SimpleBuyParams};
let nonce_info = fetch_nonce_info(&client.infrastructure.rpc, nonce_account)
.await
.expect("nonce account must be initialized");
let buy_params = SimpleBuyParams::new(
DexType::PumpFun,
TradeTokenType::SOL,
mint_pubkey,
BuyAmount::WithMaxInput { quote_amount: buy_sol_amount },
DexParamEnum::PumpFun(pumpfun_params),
recent_blockhash, // 会被 `.durable_nonce(...)` 清空
gas_fee_strategy.clone(),
)
.durable_nonce(nonce_info)
.account_policy(AccountPolicy::HotPathMinimal);
client.buy_simple(buy_params).await?;
```
#### AstralaneBinary / Plain / QUIC
+27 -2
View File
@@ -30,7 +30,7 @@ Use `SimpleBuyParams` and `SimpleSellParams` for new integrations. They keep the
| `address_lookup_table_account` | `Option<AddressLookupTableAccount>` | ❌ | Optional ALT to reduce transaction size. |
| `wait_tx_confirmed` | `bool` | ❌ | Whether to wait for chain confirmation before returning. Default is `false`. |
| `wait_for_all_submits` | `bool` | ❌ | Fast-submit mode only: wait for every SWQoS lane response and return all signatures. |
| `durable_nonce` | `Option<DurableNonceInfo>` | ❌ | Durable nonce info. Use `SimpleBuyParams::with_durable_nonce(...)`; do not combine with `recent_blockhash`. |
| `durable_nonce` | `Option<DurableNonceInfo>` | ❌ | Durable nonce info. Use `.durable_nonce(nonce_info)` or `SimpleBuyParams::with_durable_nonce(...)`; do not combine with `recent_blockhash`. |
| `simulate` | `bool` | ❌ | Build and simulate instead of submitting. Default is `false`. |
| `grpc_recv_us` | `Option<i64>` | ❌ | Upstream receive timestamp in microseconds for latency tracing. |
@@ -50,7 +50,7 @@ Use `SimpleBuyParams` and `SimpleSellParams` for new integrations. They keep the
| `address_lookup_table_account` | `Option<AddressLookupTableAccount>` | ❌ | Optional ALT to reduce transaction size. |
| `wait_tx_confirmed` | `bool` | ❌ | Whether to wait for chain confirmation before returning. Default is `false`. |
| `wait_for_all_submits` | `bool` | ❌ | Fast-submit mode only: wait for every SWQoS lane response and return all signatures. |
| `durable_nonce` | `Option<DurableNonceInfo>` | ❌ | Durable nonce info. Use `SimpleSellParams::with_durable_nonce(...)`; do not combine with `recent_blockhash`. |
| `durable_nonce` | `Option<DurableNonceInfo>` | ❌ | Durable nonce info. Use `.durable_nonce(nonce_info)` or `SimpleSellParams::with_durable_nonce(...)`; do not combine with `recent_blockhash`. |
| `simulate` | `bool` | ❌ | Build and simulate instead of submitting. Default is `false`. |
| `with_tip` | `bool` | ❌ | Whether sells include relay tips. Default is `true`; set with `.with_tip(false)`. |
| `grpc_recv_us` | `Option<i64>` | ❌ | Upstream receive timestamp in microseconds for latency tracing. |
@@ -74,6 +74,31 @@ Use `SimpleBuyParams` and `SimpleSellParams` for new integrations. They keep the
| `CreateMissing` | Include ATA creation where possible. | Convenience matters more than smallest transaction size. |
| `AssumePrepared` | Do not create or close token accounts; caller prepared everything. | Advanced deterministic flows. |
### Durable Nonce With Simple Params
`fetch_nonce_info` and `DurableNonceInfo` are re-exported from the crate root:
```rust
use sol_trade_sdk::{fetch_nonce_info, SimpleBuyParams};
let nonce_info = fetch_nonce_info(&client.infrastructure.rpc, nonce_account)
.await
.expect("nonce account must be initialized");
let buy_params = SimpleBuyParams::new(
dex_type,
pay_with,
mint,
amount,
extension_params,
recent_blockhash,
gas_fee_strategy,
)
.durable_nonce(nonce_info);
```
Calling `.durable_nonce(...)` clears `recent_blockhash`; nonce transactions use the nonce value as the transaction blockhash.
## TradeBuyParams
`TradeBuyParams` is the advanced low-level buy API. New integrations should prefer `SimpleBuyParams` unless they need direct control over individual ATA flags.
+27 -2
View File
@@ -30,7 +30,7 @@
| `address_lookup_table_account` | `Option<AddressLookupTableAccount>` | ❌ | 可选 ALT,用于减少交易体积。 |
| `wait_tx_confirmed` | `bool` | ❌ | 是否等链上确认后再返回。默认 `false`。 |
| `wait_for_all_submits` | `bool` | ❌ | fast-submit 模式下,是否等待所有 SWQoS 通道返回并拿到全部签名。 |
| `durable_nonce` | `Option<DurableNonceInfo>` | ❌ | durable nonce 信息。使用 `SimpleBuyParams::with_durable_nonce(...)` 设置,不要和 `recent_blockhash` 混用。 |
| `durable_nonce` | `Option<DurableNonceInfo>` | ❌ | durable nonce 信息。使用 `.durable_nonce(nonce_info)``SimpleBuyParams::with_durable_nonce(...)` 设置,不要和 `recent_blockhash` 混用。 |
| `simulate` | `bool` | ❌ | 只构建并模拟交易,不提交。默认 `false`。 |
| `grpc_recv_us` | `Option<i64>` | ❌ | 上游收到事件的微秒时间戳,用于延迟追踪。 |
@@ -50,7 +50,7 @@
| `address_lookup_table_account` | `Option<AddressLookupTableAccount>` | ❌ | 可选 ALT,用于减少交易体积。 |
| `wait_tx_confirmed` | `bool` | ❌ | 是否等链上确认后再返回。默认 `false`。 |
| `wait_for_all_submits` | `bool` | ❌ | fast-submit 模式下,是否等待所有 SWQoS 通道返回并拿到全部签名。 |
| `durable_nonce` | `Option<DurableNonceInfo>` | ❌ | durable nonce 信息。使用 `SimpleSellParams::with_durable_nonce(...)` 设置,不要和 `recent_blockhash` 混用。 |
| `durable_nonce` | `Option<DurableNonceInfo>` | ❌ | durable nonce 信息。使用 `.durable_nonce(nonce_info)``SimpleSellParams::with_durable_nonce(...)` 设置,不要和 `recent_blockhash` 混用。 |
| `simulate` | `bool` | ❌ | 只构建并模拟交易,不提交。默认 `false`。 |
| `with_tip` | `bool` | ❌ | 卖出交易是否带 relay tip。默认 `true`,可通过 `.with_tip(false)` 关闭。 |
| `grpc_recv_us` | `Option<i64>` | ❌ | 上游收到事件的微秒时间戳,用于延迟追踪。 |
@@ -74,6 +74,31 @@
| `CreateMissing` | 尽量在交易内创建缺失 ATA。 | 更重视方便,不追求最小交易体积。 |
| `AssumePrepared` | 不创建也不关闭 token account,调用方保证都已准备好。 | 高级确定性流程。 |
### Simple 参数使用 Durable Nonce
`fetch_nonce_info``DurableNonceInfo` 已从 crate root 重新导出:
```rust
use sol_trade_sdk::{fetch_nonce_info, SimpleBuyParams};
let nonce_info = fetch_nonce_info(&client.infrastructure.rpc, nonce_account)
.await
.expect("nonce account must be initialized");
let buy_params = SimpleBuyParams::new(
dex_type,
pay_with,
mint,
amount,
extension_params,
recent_blockhash,
gas_fee_strategy,
)
.durable_nonce(nonce_info);
```
调用 `.durable_nonce(...)` 会清空 `recent_blockhash`nonce 交易会使用 nonce value 作为 transaction blockhash。
## TradeBuyParams
`TradeBuyParams` 是高级低层买入 API。新接入建议优先使用 `SimpleBuyParams`,只有需要直接控制单个 ATA flag 时再使用它。
+42 -7
View File
@@ -14,11 +14,11 @@ use sol_trade_sdk::{
core::params::{DexParamEnum, PumpFunParams},
factory::DexType,
},
AccountPolicy, BuyAmount, SellAmount, SimpleBuyParams, SimpleSellParams, SolanaTrade,
TradeTokenType,
AccountPolicy, BuyAmount, DurableNonceInfo, SellAmount, SimpleBuyParams, SimpleSellParams,
SolanaTrade, TradeTokenType,
};
use solana_commitment_config::CommitmentConfig;
use solana_sdk::{pubkey::Pubkey, signature::Keypair, signer::Signer};
use solana_sdk::{hash::Hash, pubkey::Pubkey, signature::Keypair, signer::Signer};
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
@@ -83,7 +83,41 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
// client.buy_simple(buy_params).await?;
let _ = buy_params;
// Durable nonce is supported by the same high-level params. In production,
// fetch it with `sol_trade_sdk::fetch_nonce_info(...)` immediately before
// building the transaction.
let nonce_buy_params = SimpleBuyParams::new(
DexType::PumpFun,
TradeTokenType::SOL,
mint,
BuyAmount::WithMaxInput { quote_amount: 100_000 },
pumpfun_params.clone(),
recent_blockhash,
gas_fee_strategy.clone(),
)
.durable_nonce(DurableNonceInfo {
nonce_account: Some(Pubkey::new_unique()),
current_nonce: Some(Hash::new_unique()),
})
.account_policy(AccountPolicy::HotPathMinimal);
let _ = nonce_buy_params;
let sell_params = SimpleSellParams::new(
DexType::PumpFun,
TradeTokenType::SOL,
mint,
SellAmount::ExactInput(1_000_000),
pumpfun_params.clone(),
client.infrastructure.rpc.get_latest_blockhash().await?,
gas_fee_strategy.clone(),
)
.slippage_basis_points(300)
.account_policy(AccountPolicy::HotPathMinimal);
// client.sell_simple(sell_params).await?;
let _ = sell_params;
let nonce_sell_params = SimpleSellParams::new(
DexType::PumpFun,
TradeTokenType::SOL,
mint,
@@ -92,11 +126,12 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
client.infrastructure.rpc.get_latest_blockhash().await?,
gas_fee_strategy,
)
.slippage_basis_points(300)
.durable_nonce(DurableNonceInfo {
nonce_account: Some(Pubkey::new_unique()),
current_nonce: Some(Hash::new_unique()),
})
.account_policy(AccountPolicy::HotPathMinimal);
// client.sell_simple(sell_params).await?;
let _ = sell_params;
let _ = nonce_sell_params;
println!("Built simple buy/sell params for payer {}", client.payer.pubkey());
Ok(())
+74
View File
@@ -335,6 +335,16 @@ impl SimpleBuyParams {
self
}
/// Use a durable nonce instead of the recent blockhash passed to [`Self::new`].
///
/// This clears `recent_blockhash` because nonce transactions must use the
/// nonce value as their transaction blockhash.
pub fn durable_nonce(mut self, value: DurableNonceInfo) -> Self {
self.durable_nonce = Some(value);
self.recent_blockhash = None;
self
}
/// Wait for confirmation before returning.
pub fn wait_tx_confirmed(mut self, value: bool) -> Self {
self.wait_tx_confirmed = value;
@@ -444,6 +454,16 @@ impl SimpleSellParams {
self
}
/// Use a durable nonce instead of the recent blockhash passed to [`Self::new`].
///
/// This clears `recent_blockhash` because nonce transactions must use the
/// nonce value as their transaction blockhash.
pub fn durable_nonce(mut self, value: DurableNonceInfo) -> Self {
self.durable_nonce = Some(value);
self.recent_blockhash = None;
self
}
/// Wait for confirmation before returning.
pub fn wait_tx_confirmed(mut self, value: bool) -> Self {
self.wait_tx_confirmed = value;
@@ -1910,6 +1930,33 @@ mod tests {
assert!(!low.wait_tx_confirmed);
}
#[test]
fn simple_buy_builder_can_use_durable_nonce() {
let nonce_account = Pubkey::new_unique();
let nonce_hash = Hash::new_unique();
let durable_nonce = DurableNonceInfo {
nonce_account: Some(nonce_account),
current_nonce: Some(nonce_hash),
};
let simple = SimpleBuyParams::new(
DexType::PumpFun,
TradeTokenType::SOL,
Pubkey::new_unique(),
BuyAmount::ExactInput(10_000),
dummy_pumpfun_params(),
Hash::new_unique(),
GasFeeStrategy::new(),
)
.durable_nonce(durable_nonce.clone());
let low: TradeBuyParams = simple.into();
assert!(low.recent_blockhash.is_none());
assert_eq!(low.durable_nonce.as_ref().and_then(|n| n.nonce_account), Some(nonce_account));
assert_eq!(low.durable_nonce.as_ref().and_then(|n| n.current_nonce), Some(nonce_hash));
}
#[test]
fn simple_sell_auto_creates_non_sol_output_ata() {
let simple = SimpleSellParams {
@@ -1939,4 +1986,31 @@ mod tests {
assert!(!low.close_output_token_ata);
assert!(!low.close_mint_token_ata);
}
#[test]
fn simple_sell_builder_can_use_durable_nonce() {
let nonce_account = Pubkey::new_unique();
let nonce_hash = Hash::new_unique();
let durable_nonce = DurableNonceInfo {
nonce_account: Some(nonce_account),
current_nonce: Some(nonce_hash),
};
let simple = SimpleSellParams::new(
DexType::PumpFun,
TradeTokenType::SOL,
Pubkey::new_unique(),
SellAmount::ExactInput(50_000),
dummy_pumpfun_params(),
Hash::new_unique(),
GasFeeStrategy::new(),
)
.durable_nonce(durable_nonce.clone());
let low: TradeSellParams = simple.into();
assert!(low.recent_blockhash.is_none());
assert_eq!(low.durable_nonce.as_ref().and_then(|n| n.nonce_account), Some(nonce_account));
assert_eq!(low.durable_nonce.as_ref().and_then(|n| n.current_nonce), Some(nonce_hash));
}
}
+1
View File
@@ -7,6 +7,7 @@ pub mod swqos;
pub mod trading;
pub mod utils;
pub use crate::common::nonce_cache::{fetch_nonce_info, DurableNonceInfo};
// Re-export for SwqosConfig (Node1/BlockRazor transport; Astralane submission mode)
pub use crate::swqos::{AstralaneTransport, SwqosTransport};
pub use client::{