Skip to main content

sol_trade_sdk/common/
types.rs

1use crate::common::GasFeeStrategyType;
2use crate::swqos::{SwqosConfig, SwqosType};
3use solana_commitment_config::CommitmentConfig;
4use std::hash::{Hash, Hasher};
5
6/// Infrastructure-only configuration (wallet-independent)
7/// Can be shared across multiple wallets using the same RPC/SWQOS setup
8#[derive(Debug, Clone)]
9pub struct InfrastructureConfig {
10    pub rpc_url: String,
11    pub swqos_configs: Vec<SwqosConfig>,
12    pub commitment: CommitmentConfig,
13    /// 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.
14    pub swqos_cores_from_end: bool,
15    /// Global MEV protection flag. When true, SWQOS providers that support MEV protection
16    /// (Astralane QUIC `:9000` or HTTP `mev-protect=true`, BlockRazor) use MEV-protected
17    /// endpoints/modes. Default false.
18    pub mev_protection: bool,
19}
20
21impl InfrastructureConfig {
22    pub fn new(
23        rpc_url: String,
24        swqos_configs: Vec<SwqosConfig>,
25        commitment: CommitmentConfig,
26    ) -> Self {
27        Self {
28            rpc_url,
29            swqos_configs,
30            commitment,
31            swqos_cores_from_end: false,
32            mev_protection: false,
33        }
34    }
35
36    /// Create from TradeConfig (extract infrastructure-only settings)
37    pub fn from_trade_config(config: &TradeConfig) -> Self {
38        Self {
39            rpc_url: config.rpc_url.clone(),
40            swqos_configs: config.swqos_configs.clone(),
41            commitment: config.commitment.clone(),
42            swqos_cores_from_end: config.swqos_cores_from_end,
43            mev_protection: config.mev_protection,
44        }
45    }
46
47    /// Generate a cache key for this infrastructure configuration
48    pub fn cache_key(&self) -> String {
49        use std::collections::hash_map::DefaultHasher;
50        let mut hasher = DefaultHasher::new();
51        self.hash(&mut hasher);
52        format!("{:x}", hasher.finish())
53    }
54}
55
56// Manual Hash implementation since CommitmentConfig doesn't implement Hash
57impl Hash for InfrastructureConfig {
58    fn hash<H: Hasher>(&self, state: &mut H) {
59        self.rpc_url.hash(state);
60        self.swqos_configs.hash(state);
61        format!("{:?}", self.commitment).hash(state);
62        self.swqos_cores_from_end.hash(state);
63        self.mev_protection.hash(state);
64    }
65}
66
67impl PartialEq for InfrastructureConfig {
68    fn eq(&self, other: &Self) -> bool {
69        self.rpc_url == other.rpc_url
70            && self.swqos_configs == other.swqos_configs
71            && self.commitment == other.commitment
72            && self.swqos_cores_from_end == other.swqos_cores_from_end
73            && self.mev_protection == other.mev_protection
74    }
75}
76
77impl Eq for InfrastructureConfig {}
78
79#[derive(Debug, Clone, Copy, PartialEq, Eq)]
80pub struct SwqosSubmitTiming {
81    pub swqos_type: SwqosType,
82    pub strategy_type: GasFeeStrategyType,
83    pub submit_done_us: i64,
84}
85
86#[derive(Debug, Clone)]
87pub struct TradeConfig {
88    pub rpc_url: String,
89    pub swqos_configs: Vec<SwqosConfig>,
90    pub commitment: CommitmentConfig,
91    /// Whether to create WSOL ATA on startup (default: true)
92    /// If true, SDK will check WSOL ATA on initialization and create if not exists
93    pub create_wsol_ata_on_startup: bool,
94    /// Whether to use seed optimization for all ATA operations (default: true)
95    pub use_seed_optimize: bool,
96    /// Whether to output all SDK logs (timing, SWQOS submit/confirm, WSOL, blacklist, etc.). Default true.
97    pub log_enabled: bool,
98    /// Whether to check minimum tip per SWQOS provider (filter out configs below min). Default false to save latency.
99    pub check_min_tip: bool,
100    /// 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.
101    pub swqos_cores_from_end: bool,
102    /// Global MEV protection flag. When true, SWQOS providers that support MEV protection
103    /// (Astralane QUIC `:9000` or Plain/Binary HTTP `mev-protect=true`, BlockRazor sandwichMitigation)
104    /// use their MEV-protected endpoints/modes. Default false (no MEV protection, lower latency).
105    pub mev_protection: bool,
106}
107
108impl TradeConfig {
109    /// Create a new TradeConfig using the builder pattern.
110    ///
111    /// # Available builder methods
112    /// - `.create_wsol_ata_on_startup(bool)` — check & create WSOL ATA on init (default: true)
113    /// - `.use_seed_optimize(bool)`           — seed optimization for ATA ops (default: true)
114    /// - `.log_enabled(bool)`                 — SDK timing/SWQOS logs (default: true)
115    /// - `.check_min_tip(bool)`               — filter SWQOS below min tip (default: false)
116    /// - `.swqos_cores_from_end(bool)`        — bind SWQOS to last N cores (default: false)
117    /// - `.mev_protection(bool)`              — MEV protection for Astralane/BlockRazor (default: false)
118    ///
119    /// # Example
120    /// ```rust,ignore
121    /// let config = TradeConfig::builder(rpc_url, swqos_configs, commitment)
122    ///     .mev_protection(true)
123    ///     .check_min_tip(true)
124    ///     .log_enabled(false)
125    ///     .build();
126    /// ```
127    pub fn builder(
128        rpc_url: String,
129        swqos_configs: Vec<SwqosConfig>,
130        commitment: CommitmentConfig,
131    ) -> TradeConfigBuilder {
132        TradeConfigBuilder::new(rpc_url, swqos_configs, commitment)
133    }
134
135    /// Shortcut: create a TradeConfig with all defaults. Equivalent to `builder(...).build()`.
136    pub fn new(
137        rpc_url: String,
138        swqos_configs: Vec<SwqosConfig>,
139        commitment: CommitmentConfig,
140    ) -> Self {
141        Self::builder(rpc_url, swqos_configs, commitment).build()
142    }
143}
144
145/// Builder for [`TradeConfig`]. Created via [`TradeConfig::builder`].
146///
147/// All fields are optional and pre-filled with sensible defaults.
148/// Call `.build()` to produce the final [`TradeConfig`].
149#[derive(Debug, Clone)]
150pub struct TradeConfigBuilder {
151    rpc_url: String,
152    swqos_configs: Vec<SwqosConfig>,
153    commitment: CommitmentConfig,
154    create_wsol_ata_on_startup: bool,
155    use_seed_optimize: bool,
156    log_enabled: bool,
157    check_min_tip: bool,
158    swqos_cores_from_end: bool,
159    mev_protection: bool,
160}
161
162impl TradeConfigBuilder {
163    fn new(rpc_url: String, swqos_configs: Vec<SwqosConfig>, commitment: CommitmentConfig) -> Self {
164        Self {
165            rpc_url,
166            swqos_configs,
167            commitment,
168            create_wsol_ata_on_startup: true,
169            use_seed_optimize: true,
170            log_enabled: true,
171            check_min_tip: false,
172            swqos_cores_from_end: false,
173            mev_protection: false,
174        }
175    }
176
177    /// Check and create WSOL ATA on SDK initialization. Default: `true`.
178    pub fn create_wsol_ata_on_startup(mut self, v: bool) -> Self {
179        self.create_wsol_ata_on_startup = v;
180        self
181    }
182
183    /// Enable seed optimization for all ATA operations. Default: `true`.
184    pub fn use_seed_optimize(mut self, v: bool) -> Self {
185        self.use_seed_optimize = v;
186        self
187    }
188
189    /// Enable SDK logs (timing, SWQOS submit/confirm, WSOL, blacklist, etc.). Default: `true`.
190    pub fn log_enabled(mut self, v: bool) -> Self {
191        self.log_enabled = v;
192        self
193    }
194
195    /// Filter out SWQOS providers whose tip is below their minimum requirement.
196    /// Adds a small check on the hot path; disable for lowest latency. Default: `false`.
197    pub fn check_min_tip(mut self, v: bool) -> Self {
198        self.check_min_tip = v;
199        self
200    }
201
202    /// Bind SWQOS sender threads to the *last* N CPU cores instead of the first N.
203    /// Useful when main thread / tokio workers occupy low-numbered cores. Default: `false`.
204    pub fn swqos_cores_from_end(mut self, v: bool) -> Self {
205        self.swqos_cores_from_end = v;
206        self
207    }
208
209    /// Enable global MEV protection. When `true`:
210    /// - **Astralane QUIC** uses port `9000`; **Astralane HTTP** adds `mev-protect=true`
211    /// - **BlockRazor** uses `mode=sandwichMitigation` (skips blacklisted Leader slots)
212    ///
213    /// May reduce landing speed. Default: `false`.
214    pub fn mev_protection(mut self, v: bool) -> Self {
215        self.mev_protection = v;
216        self
217    }
218
219    /// Consume the builder and produce a [`TradeConfig`].
220    pub fn build(self) -> TradeConfig {
221        TradeConfig {
222            rpc_url: self.rpc_url,
223            swqos_configs: self.swqos_configs,
224            commitment: self.commitment,
225            create_wsol_ata_on_startup: self.create_wsol_ata_on_startup,
226            use_seed_optimize: self.use_seed_optimize,
227            log_enabled: self.log_enabled,
228            check_min_tip: self.check_min_tip,
229            swqos_cores_from_end: self.swqos_cores_from_end,
230            mev_protection: self.mev_protection,
231        }
232    }
233}
234
235pub type SolanaRpcClient = solana_client::nonblocking::rpc_client::RpcClient;
236pub type AnyResult<T> = anyhow::Result<T>;