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>;