feat: add global MEV protection and refactor TradeConfig to builder pattern

- Add `mev_protection: bool` to `TradeConfig` and `InfrastructureConfig` (default: false)
  - Astralane QUIC: switches to port 9000 (MEV-protected endpoint) when enabled
  - BlockRazor HTTP: uses `mode=sandwichMitigation` query param when enabled
  - BlockRazor gRPC: uses `mode=sandwichMitigation` when enabled
- Add `SWQOS_ENDPOINTS_ASTRALANE_QUIC_MEV` constants (port 9000) to `constants/swqos.rs`
- Fix `astralane_quic.rs` IP candidates to use the actual port from the address (supports both 7000 and 9000)
- Refactor `TradeConfig` to builder pattern via `TradeConfig::builder()`
  - Introduce `TradeConfigBuilder` with all optional fields and clear defaults
  - `TradeConfig::new()` kept as a shortcut (calls `builder().build()`) for backward compatibility
  - Remove old `with_wsol_ata_config` / `with_check_min_tip` / `with_swqos_cores_from_end` / `with_mev_protection` chain methods
- Update all 16 examples to use `TradeConfig::builder()` with commented-out options so users can discover all available settings at a glance
- Update README.md and README_CN.md code snippets to use builder pattern

🤖 Generated with [Qoder][https://qoder.com]
This commit is contained in:
0xfnzero
2026-04-08 02:13:37 +08:00
parent 35bfa93516
commit 971ef41fad
44 changed files with 6783 additions and 74 deletions
+115 -22
View File
@@ -11,6 +11,10 @@ pub struct InfrastructureConfig {
pub commitment: CommitmentConfig,
/// When true, SWQOS sender threads use the *last* N cores instead of the first N. Reduces contention with main thread / default tokio workers that often use low-numbered cores. Default false.
pub swqos_cores_from_end: bool,
/// Global MEV protection flag. When true, SWQOS providers that support MEV protection
/// (Astralane QUIC port 9000, BlockRazor revert_protection) will use their MEV-protected
/// endpoints/modes. Default false.
pub mev_protection: bool,
}
impl InfrastructureConfig {
@@ -24,6 +28,7 @@ impl InfrastructureConfig {
swqos_configs,
commitment,
swqos_cores_from_end: false,
mev_protection: false,
}
}
@@ -34,6 +39,7 @@ impl InfrastructureConfig {
swqos_configs: config.swqos_configs.clone(),
commitment: config.commitment.clone(),
swqos_cores_from_end: config.swqos_cores_from_end,
mev_protection: config.mev_protection,
}
}
@@ -53,6 +59,7 @@ impl Hash for InfrastructureConfig {
self.swqos_configs.hash(state);
format!("{:?}", self.commitment).hash(state);
self.swqos_cores_from_end.hash(state);
self.mev_protection.hash(state);
}
}
@@ -62,6 +69,7 @@ impl PartialEq for InfrastructureConfig {
&& self.swqos_configs == other.swqos_configs
&& self.commitment == other.commitment
&& self.swqos_cores_from_end == other.swqos_cores_from_end
&& self.mev_protection == other.mev_protection
}
}
@@ -83,52 +91,137 @@ pub struct TradeConfig {
pub check_min_tip: bool,
/// When true, SWQOS uses the *last* N cores (instead of the first N). Use when main thread / tokio use low-numbered cores to reduce CPU contention. Default false.
pub swqos_cores_from_end: bool,
/// Global MEV protection flag. When true, SWQOS providers that support MEV protection
/// (Astralane QUIC port 9000, BlockRazor sandwichMitigation mode) will use their
/// MEV-protected endpoints/modes. Default false (no MEV protection, lower latency).
pub mev_protection: bool,
}
impl TradeConfig {
/// Create a new TradeConfig using the builder pattern.
///
/// # Available builder methods
/// - `.create_wsol_ata_on_startup(bool)` — check & create WSOL ATA on init (default: true)
/// - `.use_seed_optimize(bool)` — seed optimization for ATA ops (default: true)
/// - `.log_enabled(bool)` — SDK timing/SWQOS logs (default: true)
/// - `.check_min_tip(bool)` — filter SWQOS below min tip (default: false)
/// - `.swqos_cores_from_end(bool)` — bind SWQOS to last N cores (default: false)
/// - `.mev_protection(bool)` — MEV protection for Astralane/BlockRazor (default: false)
///
/// # Example
/// ```rust
/// let config = TradeConfig::builder(rpc_url, swqos_configs, commitment)
/// .mev_protection(true)
/// .check_min_tip(true)
/// .log_enabled(false)
/// .build();
/// ```
pub fn builder(
rpc_url: String,
swqos_configs: Vec<SwqosConfig>,
commitment: CommitmentConfig,
) -> TradeConfigBuilder {
TradeConfigBuilder::new(rpc_url, swqos_configs, commitment)
}
/// Shortcut: create a TradeConfig with all defaults. Equivalent to `builder(...).build()`.
pub fn new(
rpc_url: String,
swqos_configs: Vec<SwqosConfig>,
commitment: CommitmentConfig,
) -> Self {
if crate::common::sdk_log::sdk_log_enabled() {
println!("🔧 TradeConfig create_wsol_ata_on_startup default: true");
println!("🔧 TradeConfig use_seed_optimize default: true");
}
Self::builder(rpc_url, swqos_configs, commitment).build()
}
}
/// Builder for [`TradeConfig`]. Created via [`TradeConfig::builder`].
///
/// All fields are optional and pre-filled with sensible defaults.
/// Call `.build()` to produce the final [`TradeConfig`].
#[derive(Debug, Clone)]
pub struct TradeConfigBuilder {
rpc_url: String,
swqos_configs: Vec<SwqosConfig>,
commitment: CommitmentConfig,
create_wsol_ata_on_startup: bool,
use_seed_optimize: bool,
log_enabled: bool,
check_min_tip: bool,
swqos_cores_from_end: bool,
mev_protection: bool,
}
impl TradeConfigBuilder {
fn new(rpc_url: String, swqos_configs: Vec<SwqosConfig>, commitment: CommitmentConfig) -> Self {
Self {
rpc_url,
swqos_configs,
commitment,
create_wsol_ata_on_startup: true, // default: check and create on startup
use_seed_optimize: true, // default: use seed optimization
log_enabled: true, // default: enable all SDK logs
check_min_tip: false, // default: skip min tip check to reduce latency
create_wsol_ata_on_startup: true,
use_seed_optimize: true,
log_enabled: true,
check_min_tip: false,
swqos_cores_from_end: false,
mev_protection: false,
}
}
/// Create a TradeConfig with custom WSOL ATA settings
pub fn with_wsol_ata_config(
mut self,
create_wsol_ata_on_startup: bool,
use_seed_optimize: bool,
) -> Self {
self.create_wsol_ata_on_startup = create_wsol_ata_on_startup;
self.use_seed_optimize = use_seed_optimize;
/// Check and create WSOL ATA on SDK initialization. Default: `true`.
pub fn create_wsol_ata_on_startup(mut self, v: bool) -> Self {
self.create_wsol_ata_on_startup = v;
self
}
/// Set whether to check minimum tip per SWQOS (filter out configs below min). Default false for lower latency.
pub fn with_check_min_tip(mut self, check_min_tip: bool) -> Self {
self.check_min_tip = check_min_tip;
/// Enable seed optimization for all ATA operations. Default: `true`.
pub fn use_seed_optimize(mut self, v: bool) -> Self {
self.use_seed_optimize = v;
self
}
/// Use the *last* N cores for SWQOS (instead of the first N). Call this when the main thread or tokio workers use low-numbered cores to avoid binding SWQOS to busy cores. Default false.
pub fn with_swqos_cores_from_end(mut self, from_end: bool) -> Self {
self.swqos_cores_from_end = from_end;
/// Enable SDK logs (timing, SWQOS submit/confirm, WSOL, blacklist, etc.). Default: `true`.
pub fn log_enabled(mut self, v: bool) -> Self {
self.log_enabled = v;
self
}
/// Filter out SWQOS providers whose tip is below their minimum requirement.
/// Adds a small check on the hot path; disable for lowest latency. Default: `false`.
pub fn check_min_tip(mut self, v: bool) -> Self {
self.check_min_tip = v;
self
}
/// Bind SWQOS sender threads to the *last* N CPU cores instead of the first N.
/// Useful when main thread / tokio workers occupy low-numbered cores. Default: `false`.
pub fn swqos_cores_from_end(mut self, v: bool) -> Self {
self.swqos_cores_from_end = v;
self
}
/// Enable global MEV protection. When `true`:
/// - **Astralane QUIC** uses port `9000` (MEV-protected endpoint)
/// - **BlockRazor** uses `mode=sandwichMitigation` (skips blacklisted Leader slots)
///
/// May reduce landing speed. Default: `false`.
pub fn mev_protection(mut self, v: bool) -> Self {
self.mev_protection = v;
self
}
/// Consume the builder and produce a [`TradeConfig`].
pub fn build(self) -> TradeConfig {
TradeConfig {
rpc_url: self.rpc_url,
swqos_configs: self.swqos_configs,
commitment: self.commitment,
create_wsol_ata_on_startup: self.create_wsol_ata_on_startup,
use_seed_optimize: self.use_seed_optimize,
log_enabled: self.log_enabled,
check_min_tip: self.check_min_tip,
swqos_cores_from_end: self.swqos_cores_from_end,
mev_protection: self.mev_protection,
}
}
}
pub type SolanaRpcClient = solana_client::nonblocking::rpc_client::RpcClient;