1use serde::{Deserialize, Serialize};
2use yellowstone_grpc_proto::geyser::{
3 subscribe_request_filter_accounts_filter::Filter as AccountsFilterOneof,
4 subscribe_request_filter_accounts_filter_memcmp::Data as MemcmpDataOneof,
5 SubscribeRequestFilterAccountsFilter, SubscribeRequestFilterAccountsFilterMemcmp,
6};
7
8#[derive(Debug, Clone, Copy, PartialEq, Eq, Default, Serialize, Deserialize)]
10pub enum OrderMode {
11 #[default]
13 Unordered,
14 Ordered,
18 StreamingOrdered,
22 MicroBatch,
26}
27
28#[derive(Debug, Clone, Serialize, Deserialize)]
29pub struct ClientConfig {
30 pub enable_metrics: bool,
32 pub connection_timeout_ms: u64,
34 pub request_timeout_ms: u64,
36 pub enable_tls: bool,
38 pub max_retries: u32,
39 pub retry_delay_ms: u64,
40 pub max_concurrent_streams: u32,
41 pub keep_alive_interval_ms: u64,
42 pub keep_alive_timeout_ms: u64,
43 pub buffer_size: usize,
44 pub order_mode: OrderMode,
46 pub order_timeout_ms: u64,
49 pub micro_batch_us: u64,
52}
53
54impl Default for ClientConfig {
55 fn default() -> Self {
56 Self {
57 enable_metrics: false,
58 connection_timeout_ms: 8000,
59 request_timeout_ms: 15000,
60 enable_tls: true,
61 max_retries: 3,
62 retry_delay_ms: 1000,
63 max_concurrent_streams: 100,
64 keep_alive_interval_ms: 30000,
65 keep_alive_timeout_ms: 5000,
66 buffer_size: 8192,
67 order_mode: OrderMode::Unordered,
68 order_timeout_ms: 100,
69 micro_batch_us: 100, }
71 }
72}
73
74impl ClientConfig {
75 pub fn low_latency() -> Self {
76 Self {
77 enable_metrics: false,
78 connection_timeout_ms: 5000,
79 request_timeout_ms: 10000,
80 enable_tls: true,
81 max_retries: 1,
82 retry_delay_ms: 100,
83 max_concurrent_streams: 200,
84 keep_alive_interval_ms: 10000,
85 keep_alive_timeout_ms: 2000,
86 buffer_size: 16384,
87 order_mode: OrderMode::Unordered,
88 order_timeout_ms: 50,
89 micro_batch_us: 50, }
91 }
92
93 pub fn high_throughput() -> Self {
94 Self {
95 enable_metrics: true,
96 connection_timeout_ms: 10000,
97 request_timeout_ms: 30000,
98 enable_tls: true,
99 max_retries: 5,
100 retry_delay_ms: 2000,
101 max_concurrent_streams: 500,
102 keep_alive_interval_ms: 60000,
103 keep_alive_timeout_ms: 10000,
104 buffer_size: 32768,
105 order_mode: OrderMode::Unordered,
106 order_timeout_ms: 200,
107 micro_batch_us: 200, }
109 }
110}
111
112#[derive(Debug, Clone)]
113pub struct TransactionFilter {
114 pub account_include: Vec<String>,
115 pub account_exclude: Vec<String>,
116 pub account_required: Vec<String>,
117}
118
119impl TransactionFilter {
120 pub fn new() -> Self {
121 Self {
122 account_include: Vec::new(),
123 account_exclude: Vec::new(),
124 account_required: Vec::new(),
125 }
126 }
127
128 pub fn include_account(mut self, account: impl Into<String>) -> Self {
129 self.account_include.push(account.into());
130 self
131 }
132
133 pub fn exclude_account(mut self, account: impl Into<String>) -> Self {
134 self.account_exclude.push(account.into());
135 self
136 }
137
138 pub fn require_account(mut self, account: impl Into<String>) -> Self {
139 self.account_required.push(account.into());
140 self
141 }
142
143 pub fn from_program_ids(program_ids: Vec<String>) -> Self {
145 Self {
146 account_include: program_ids,
147 account_exclude: Vec::new(),
148 account_required: Vec::new(),
149 }
150 }
151}
152
153impl Default for TransactionFilter {
154 fn default() -> Self {
155 Self::new()
156 }
157}
158
159#[derive(Debug, Clone)]
160pub struct AccountFilter {
161 pub account: Vec<String>,
162 pub owner: Vec<String>,
163 pub filters: Vec<SubscribeRequestFilterAccountsFilter>,
164}
165
166impl AccountFilter {
167 pub fn new() -> Self {
168 Self { account: Vec::new(), owner: Vec::new(), filters: Vec::new() }
169 }
170
171 pub fn add_account(mut self, account: impl Into<String>) -> Self {
172 self.account.push(account.into());
173 self
174 }
175
176 pub fn add_owner(mut self, owner: impl Into<String>) -> Self {
177 self.owner.push(owner.into());
178 self
179 }
180
181 pub fn add_filter(mut self, filter: SubscribeRequestFilterAccountsFilter) -> Self {
182 self.filters.push(filter);
183 self
184 }
185
186 pub fn from_program_owners(program_ids: Vec<String>) -> Self {
188 Self { account: Vec::new(), owner: program_ids, filters: Vec::new() }
189 }
190}
191
192impl Default for AccountFilter {
193 fn default() -> Self {
194 Self::new()
195 }
196}
197
198#[inline]
201pub fn account_filter_memcmp(offset: u64, bytes: Vec<u8>) -> SubscribeRequestFilterAccountsFilter {
202 SubscribeRequestFilterAccountsFilter {
203 filter: Some(AccountsFilterOneof::Memcmp(SubscribeRequestFilterAccountsFilterMemcmp {
204 offset,
205 data: Some(MemcmpDataOneof::Bytes(bytes)),
206 })),
207 }
208}
209
210#[derive(Debug, Clone)]
211pub struct AccountFilterData {
212 pub memcmp: Option<AccountFilterMemcmp>,
213 pub datasize: Option<u64>,
214}
215
216#[derive(Debug, Clone)]
217pub struct AccountFilterMemcmp {
218 pub offset: u64,
219 pub bytes: Vec<u8>,
220}
221
222#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
223pub enum Protocol {
224 PumpFun,
225 PumpSwap,
226 Bonk,
227 RaydiumCpmm,
228 RaydiumClmm,
229 RaydiumAmmV4,
230 MeteoraDammV2,
231}
232
233#[derive(Debug, Clone, Copy, PartialEq, Eq)]
234pub enum EventType {
235 BlockMeta,
237
238 BonkTrade,
240 BonkPoolCreate,
241 BonkMigrateAmm,
242
243 PumpFunTrade, PumpFunBuy, PumpFunSell, PumpFunBuyExactSolIn, PumpFunCreate,
249 PumpFunCreateV2, PumpFunComplete,
251 PumpFunMigrate,
252 PumpFeesCreateFeeSharingConfig,
254 PumpFeesInitializeFeeConfig,
255 PumpFeesResetFeeSharingConfig,
256 PumpFeesRevokeFeeSharingAuthority,
257 PumpFeesTransferFeeSharingAuthority,
258 PumpFeesUpdateAdmin,
259 PumpFeesUpdateFeeConfig,
260 PumpFeesUpdateFeeShares,
261 PumpFeesUpsertFeeTiers,
262 PumpFunMigrateBondingCurveCreator,
264
265 PumpSwapBuy,
267 PumpSwapSell,
268 PumpSwapCreatePool,
269 PumpSwapLiquidityAdded,
270 PumpSwapLiquidityRemoved,
271 MeteoraDammV2Swap,
313 MeteoraDammV2AddLiquidity,
314 MeteoraDammV2RemoveLiquidity,
315 MeteoraDammV2CreatePosition,
317 MeteoraDammV2ClosePosition,
318 TokenAccount,
325 NonceAccount,
326 AccountPumpFunGlobal,
327
328 AccountPumpSwapGlobalConfig,
329 AccountPumpSwapPool,
330}
331
332#[derive(Debug, Clone)]
333pub struct EventTypeFilter {
334 pub include_only: Option<Vec<EventType>>,
335 pub exclude_types: Option<Vec<EventType>>,
336}
337
338impl EventTypeFilter {
339 pub fn include_only(types: Vec<EventType>) -> Self {
340 Self { include_only: Some(types), exclude_types: None }
341 }
342
343 pub fn exclude_types(types: Vec<EventType>) -> Self {
344 Self { include_only: None, exclude_types: Some(types) }
345 }
346
347 pub fn should_include(&self, event_type: EventType) -> bool {
348 if let Some(ref include_only) = self.include_only {
349 if include_only.contains(&event_type) {
351 return true;
352 }
353 if event_type == EventType::PumpFunTrade {
357 return include_only.iter().any(|t| {
358 matches!(
359 t,
360 EventType::PumpFunBuy
361 | EventType::PumpFunSell
362 | EventType::PumpFunBuyExactSolIn
363 )
364 });
365 }
366 return false;
367 }
368
369 if let Some(ref exclude_types) = self.exclude_types {
370 return !exclude_types.contains(&event_type);
371 }
372
373 true
374 }
375
376 #[inline]
377 pub fn includes_pumpfun(&self) -> bool {
378 if let Some(ref include_only) = self.include_only {
379 return include_only.iter().any(|t| {
380 matches!(
381 t,
382 EventType::PumpFunTrade
383 | EventType::PumpFunBuy
384 | EventType::PumpFunSell
385 | EventType::PumpFunBuyExactSolIn
386 | EventType::PumpFunCreate
387 | EventType::PumpFunCreateV2
388 | EventType::PumpFunComplete
389 | EventType::PumpFunMigrate
390 | EventType::PumpFeesCreateFeeSharingConfig
391 | EventType::PumpFeesInitializeFeeConfig
392 | EventType::PumpFeesResetFeeSharingConfig
393 | EventType::PumpFeesRevokeFeeSharingAuthority
394 | EventType::PumpFeesTransferFeeSharingAuthority
395 | EventType::PumpFeesUpdateAdmin
396 | EventType::PumpFeesUpdateFeeConfig
397 | EventType::PumpFeesUpdateFeeShares
398 | EventType::PumpFeesUpsertFeeTiers
399 | EventType::PumpFunMigrateBondingCurveCreator
400 | EventType::AccountPumpFunGlobal
401 )
402 });
403 }
404
405 if let Some(ref exclude_types) = self.exclude_types {
406 return !exclude_types.iter().any(|t| {
407 matches!(
408 t,
409 EventType::PumpFunTrade
410 | EventType::PumpFunBuy
411 | EventType::PumpFunSell
412 | EventType::PumpFunBuyExactSolIn
413 | EventType::PumpFunCreate
414 | EventType::PumpFunCreateV2
415 | EventType::PumpFunComplete
416 | EventType::PumpFunMigrate
417 | EventType::PumpFeesCreateFeeSharingConfig
418 | EventType::PumpFeesInitializeFeeConfig
419 | EventType::PumpFeesResetFeeSharingConfig
420 | EventType::PumpFeesRevokeFeeSharingAuthority
421 | EventType::PumpFeesTransferFeeSharingAuthority
422 | EventType::PumpFeesUpdateAdmin
423 | EventType::PumpFeesUpdateFeeConfig
424 | EventType::PumpFeesUpdateFeeShares
425 | EventType::PumpFeesUpsertFeeTiers
426 | EventType::PumpFunMigrateBondingCurveCreator
427 | EventType::AccountPumpFunGlobal
428 )
429 });
430 }
431
432 true
433 }
434
435 #[inline]
436 pub fn includes_meteora_damm_v2(&self) -> bool {
437 if let Some(ref include_only) = self.include_only {
438 return include_only.iter().any(|t| {
439 matches!(
440 t,
441 EventType::MeteoraDammV2Swap
442 | EventType::MeteoraDammV2AddLiquidity
443 | EventType::MeteoraDammV2CreatePosition
444 | EventType::MeteoraDammV2ClosePosition
445 | EventType::MeteoraDammV2RemoveLiquidity
446 )
447 });
448 }
449 if let Some(ref exclude_types) = self.exclude_types {
450 return !exclude_types.iter().any(|t| {
451 matches!(
452 t,
453 EventType::MeteoraDammV2Swap
454 | EventType::MeteoraDammV2AddLiquidity
455 | EventType::MeteoraDammV2CreatePosition
456 | EventType::MeteoraDammV2ClosePosition
457 | EventType::MeteoraDammV2RemoveLiquidity
458 )
459 });
460 }
461 true
462 }
463
464 #[inline]
465 pub fn includes_pump_fees(&self) -> bool {
466 macro_rules! any_pfees {
467 () => {
468 EventType::PumpFeesCreateFeeSharingConfig
469 | EventType::PumpFeesInitializeFeeConfig
470 | EventType::PumpFeesResetFeeSharingConfig
471 | EventType::PumpFeesRevokeFeeSharingAuthority
472 | EventType::PumpFeesTransferFeeSharingAuthority
473 | EventType::PumpFeesUpdateAdmin
474 | EventType::PumpFeesUpdateFeeConfig
475 | EventType::PumpFeesUpdateFeeShares
476 | EventType::PumpFeesUpsertFeeTiers
477 };
478 }
479 if let Some(ref include_only) = self.include_only {
480 return include_only.iter().any(|t| matches!(t, any_pfees!()));
481 }
482 if let Some(ref exclude_types) = self.exclude_types {
483 return !exclude_types.iter().any(|t| matches!(t, any_pfees!()));
484 }
485 true
486 }
487
488 #[inline]
490 pub fn includes_pumpswap(&self) -> bool {
491 if let Some(ref include_only) = self.include_only {
492 return include_only.iter().any(|t| {
493 matches!(
494 t,
495 EventType::PumpSwapBuy
496 | EventType::PumpSwapSell
497 | EventType::PumpSwapCreatePool
498 | EventType::PumpSwapLiquidityAdded
499 | EventType::PumpSwapLiquidityRemoved
500 )
501 });
502 }
503 if let Some(ref exclude_types) = self.exclude_types {
504 return !exclude_types.iter().any(|t| {
505 matches!(
506 t,
507 EventType::PumpSwapBuy
508 | EventType::PumpSwapSell
509 | EventType::PumpSwapCreatePool
510 | EventType::PumpSwapLiquidityAdded
511 | EventType::PumpSwapLiquidityRemoved
512 )
513 });
514 }
515 true
516 }
517
518 #[inline]
520 pub fn includes_raydium_launchpad(&self) -> bool {
521 if let Some(ref include_only) = self.include_only {
522 return include_only.iter().any(|t| {
523 matches!(
524 t,
525 EventType::BonkTrade | EventType::BonkPoolCreate | EventType::BonkMigrateAmm
526 )
527 });
528 }
529 if let Some(ref exclude_types) = self.exclude_types {
530 return !exclude_types.iter().any(|t| {
531 matches!(
532 t,
533 EventType::BonkTrade | EventType::BonkPoolCreate | EventType::BonkMigrateAmm
534 )
535 });
536 }
537 true
538 }
539}
540
541#[derive(Debug, Clone)]
542pub struct SlotFilter {
543 pub min_slot: Option<u64>,
544 pub max_slot: Option<u64>,
545}
546
547impl SlotFilter {
548 pub fn new() -> Self {
549 Self { min_slot: None, max_slot: None }
550 }
551
552 pub fn min_slot(mut self, slot: u64) -> Self {
553 self.min_slot = Some(slot);
554 self
555 }
556
557 pub fn max_slot(mut self, slot: u64) -> Self {
558 self.max_slot = Some(slot);
559 self
560 }
561}
562
563impl Default for SlotFilter {
564 fn default() -> Self {
565 Self::new()
566 }
567}