1use crate::Evm;
3use crate::types::EvmError;
4use ethers::providers::Middleware;
5use ethers::types::Bytes;
6use ethers::types::{Address, U256};
7use ethers::types::{Filter, Transaction, TxHash};
8use sha3::{Digest, Keccak256};
9use std::collections::{HashMap, HashSet};
10use std::sync::Arc;
11use tokio::sync::RwLock;
12use tokio::time::{Duration, sleep};
13
14#[derive(Debug, Clone)]
16pub struct MempoolTransaction {
17 pub hash: TxHash,
18 pub from: Address,
19 pub to: Option<Address>,
20 pub value: U256,
21 pub transaction_type: Option<u64>,
22 pub gas_price: Option<U256>, pub max_fee_per_gas: Option<U256>, pub max_priority_fee_per_gas: Option<U256>, pub gas: U256,
26 pub input: Bytes,
27 pub nonce: U256,
28 pub transaction: Transaction,
29 pub first_seen: u64,
30 pub last_seen: u64,
31 pub is_mev: bool,
32 pub bundle_hash: Option<TxHash>,
33 pub frontrunning_protection: bool,
34}
35
36#[derive(Debug, Clone)]
38pub struct MempoolConfig {
39 pub poll_interval: Duration,
40 pub max_transactions: usize,
41 pub track_pending: bool,
42 pub enable_mev_detection: bool,
43 pub max_reorg_depth: u64,
44 pub simulate_transactions: bool,
45 pub track_bundles: bool,
46}
47
48impl Default for MempoolConfig {
49 fn default() -> Self {
50 Self {
51 poll_interval: Duration::from_secs(2),
52 max_transactions: 10000,
53 track_pending: true,
54 enable_mev_detection: false,
55 max_reorg_depth: 5,
56 simulate_transactions: false,
57 track_bundles: false,
58 }
59 }
60}
61
62#[derive(Clone)]
64pub struct MempoolListener {
65 evm: Arc<Evm>,
66 config: MempoolConfig,
67 state: Arc<RwLock<MempoolState>>,
68}
69
70#[derive(Debug)]
72struct MempoolState {
73 transactions: HashMap<TxHash, MempoolTransaction>,
74 pending_hashes: HashSet<TxHash>,
75 last_block_number: u64,
76 is_running: bool,
77 transaction_bundles: HashMap<TxHash, Vec<TxHash>>,
80}
81
82impl MempoolListener {
83 pub fn new(evm: Arc<Evm>) -> Self {
85 Self::with_config(evm, MempoolConfig::default())
86 }
87
88 pub fn with_config(evm: Arc<Evm>, config: MempoolConfig) -> Self {
90 Self {
91 evm,
92 config,
93 state: Arc::new(RwLock::new(MempoolState {
94 transactions: HashMap::new(),
95 pending_hashes: HashSet::new(),
96 last_block_number: 0,
97 is_running: false,
98 transaction_bundles: HashMap::new(),
99 })),
100 }
101 }
102
103 pub async fn start(&self) -> Result<(), EvmError> {
112 let mut state = self.state.write().await;
113 if state.is_running {
114 return Err(EvmError::MempoolError(
115 "Mempool listener is already running".to_string(),
116 ));
117 }
118 state.is_running = true;
119 drop(state);
120
121 let listener = self.clone();
122 tokio::spawn(async move {
123 listener.run().await;
124 });
125
126 Ok(())
127 }
128
129 pub async fn stop(&self) {
131 let mut state = self.state.write().await;
132 state.is_running = false;
133 }
134
135 async fn run(&self) {
137 while self.is_running().await {
138 if let Err(e) = self.poll_mempool().await {
139 eprintln!("Error polling mempool: {}", e);
140 }
141 sleep(self.config.poll_interval).await;
142 }
143 }
144
145 async fn is_running(&self) -> bool {
147 self.state.read().await.is_running
148 }
149
150 async fn poll_mempool(&self) -> Result<(), EvmError> {
152 let current_block = self.evm.get_block_number().await?;
153 {
154 let mut state = self.state.write().await;
155 state.last_block_number = current_block;
156 }
157 let pending_txs = self.get_pending_transactions().await?;
158 self.update_mempool_state(pending_txs, current_block).await;
159 self.clean_confirmed_transactions().await?;
160 Ok(())
161 }
162
163 async fn get_pending_transactions(&self) -> Result<Vec<Transaction>, EvmError> {
192 let block = tokio::time::timeout(
194 Duration::from_secs(30),
195 self.evm
196 .client
197 .provider
198 .get_block(ethers::types::BlockId::Number(
199 ethers::types::BlockNumber::Pending,
200 )),
201 )
202 .await
203 .map_err(|_| EvmError::RpcError("Timeout getting pending block".to_string()))?
204 .map_err(|e| EvmError::RpcError(format!("Failed to get pending block: {}", e)))?;
205 let mut pending_txs = Vec::new();
206 if let Some(block) = block {
207 let mut handles = Vec::new();
209 for tx_hash in block.transactions {
210 let provider = self.evm.client.provider.clone();
211 let handle = tokio::spawn(async move {
212 for attempt in 0..3 {
214 match provider.get_transaction(tx_hash).await {
215 Ok(Some(tx)) if tx.block_number.is_none() => return Some(tx),
216 Ok(Some(_)) => return None, Ok(None) => return None, Err(_) if attempt < 2 => {
219 tokio::time::sleep(Duration::from_millis(100 * (attempt + 1)))
220 .await;
221 continue;
222 }
223 Err(e) => {
224 eprintln!(
225 "Failed to get transaction {} after {} attempts: {}",
226 tx_hash,
227 attempt + 1,
228 e
229 );
230 return None;
231 }
232 }
233 }
234 None
235 });
236 handles.push(handle);
237 }
238 for handle in handles {
240 match handle.await {
241 Ok(Some(tx)) => pending_txs.push(tx),
242 Ok(None) => {} Err(e) => eprintln!("Task failed: {}", e),
244 }
245 }
246 }
247 Ok(pending_txs)
248 }
249
250 async fn update_mempool_state(&self, transactions: Vec<Transaction>, current_block: u64) {
252 let mut state = self.state.write().await;
253 let new_transactions: Vec<Transaction> = transactions
255 .into_iter()
256 .filter(|tx| !state.transactions.contains_key(&tx.hash))
257 .collect();
258 let bundles = if self.config.track_bundles {
260 Self::detect_transaction_bundles(&new_transactions)
261 } else {
262 HashMap::new()
263 };
264 for (bundle_hash, tx_hashes) in bundles {
266 state
267 .transaction_bundles
268 .insert(bundle_hash, tx_hashes.clone());
269 }
270 for tx in new_transactions {
272 if state.transactions.len() < self.config.max_transactions {
273 let is_mev = self.config.enable_mev_detection && Self::detect_mev_transaction(&tx);
274 let frontrunning_protection = Self::has_frontrunning_protection(&tx);
275 let bundle_hash =
277 Self::find_bundle_for_transaction(&tx, &state.transaction_bundles);
278 let mempool_tx = MempoolTransaction {
279 hash: tx.hash,
280 from: tx.from,
281 to: tx.to,
282 value: tx.value,
283 transaction_type: tx.transaction_type.map(|v| v.as_u64()),
284 gas_price: tx.gas_price,
285 max_fee_per_gas: tx.max_fee_per_gas,
286 max_priority_fee_per_gas: tx.max_priority_fee_per_gas,
287 gas: tx.gas,
288 input: tx.input.clone(),
289 nonce: tx.nonce,
290 transaction: tx.clone(),
291 first_seen: current_block,
292 last_seen: current_block,
293 is_mev,
294 bundle_hash,
295 frontrunning_protection,
296 };
297 state.transactions.insert(tx.hash, mempool_tx);
298 state.pending_hashes.insert(tx.hash);
299 }
300 }
301 }
302
303 async fn clean_confirmed_transactions(&self) -> Result<(), EvmError> {
305 let current_block = self.evm.get_block_number().await?;
306 let mut state = self.state.write().await;
307 let mut to_remove = Vec::new();
308 for (tx_hash, mempool_tx) in state.transactions.iter() {
309 if current_block.saturating_sub(mempool_tx.last_seen) > self.config.max_reorg_depth {
310 if let Ok(Some(receipt)) = self.evm.get_transaction_receipt(*tx_hash).await {
311 if receipt.block_number.is_some() {
312 to_remove.push(*tx_hash);
313 }
314 }
315 }
316 }
317 for tx_hash in to_remove {
318 state.transactions.remove(&tx_hash);
319 state.pending_hashes.remove(&tx_hash);
320 state.transaction_bundles.retain(|_, tx_hashes| {
321 tx_hashes.retain(|h| h != &tx_hash);
322 !tx_hashes.is_empty()
323 });
324 }
325 Ok(())
326 }
327
328 pub async fn get_pending_transactions_list(&self) -> Vec<MempoolTransaction> {
338 let state = self.state.read().await;
339 state.transactions.values().cloned().collect()
340 }
341
342 pub async fn get_transactions_by_sender(&self, address: Address) -> Vec<MempoolTransaction> {
350 let state = self.state.read().await;
351 state
352 .transactions
353 .values()
354 .filter(|tx| tx.from == address)
355 .cloned()
356 .collect()
357 }
358
359 pub async fn get_transactions_by_receiver(&self, address: Address) -> Vec<MempoolTransaction> {
367 let state = self.state.read().await;
368 state
369 .transactions
370 .values()
371 .filter(|tx| tx.to == Some(address))
372 .cloned()
373 .collect()
374 }
375
376 pub async fn get_high_gas_transactions(&self, threshold: U256) -> Vec<MempoolTransaction> {
384 let state = self.state.read().await;
385 state
386 .transactions
387 .values()
388 .filter(|tx| tx.gas_price >= Some(threshold))
389 .cloned()
390 .collect()
391 }
392
393 pub async fn get_large_value_transactions(&self, threshold: U256) -> Vec<MempoolTransaction> {
401 let state = self.state.read().await;
402 state
403 .transactions
404 .values()
405 .filter(|tx| tx.value >= threshold)
406 .cloned()
407 .collect()
408 }
409
410 pub async fn get_stats(&self) -> MempoolStats {
419 let state = self.state.read().await;
420 let total_txs = state.transactions.len();
421 let total_value = state
422 .transactions
423 .values()
424 .fold(U256::zero(), |acc, tx| acc + tx.value);
425 let total_gas_limit = state
426 .transactions
427 .values()
428 .fold(U256::zero(), |acc, tx| acc + tx.gas);
429 let (gas_sum, count) =
431 state
432 .transactions
433 .values()
434 .fold((U256::zero(), 0), |(sum, count), tx| {
435 let effective_gas_price = tx
436 .max_fee_per_gas
437 .unwrap_or_else(|| tx.gas_price.unwrap_or_default());
438 (sum + effective_gas_price, count + 1)
439 });
440 let avg_gas_price = if count > 0 {
441 gas_sum / U256::from(count)
442 } else {
443 U256::zero()
444 };
445 MempoolStats {
446 total_transactions: total_txs,
447 total_value,
448 total_gas: total_gas_limit,
449 average_gas_price: avg_gas_price,
450 last_block_number: state.last_block_number,
451 eip1559_transactions: state
453 .transactions
454 .values()
455 .filter(|tx| tx.transaction_type == Some(2))
456 .count(),
457 mev_transactions: state.transactions.values().filter(|tx| tx.is_mev).count(),
458 protected_transactions: state
459 .transactions
460 .values()
461 .filter(|tx| tx.frontrunning_protection)
462 .count(),
463 }
464 }
465
466 pub async fn contains_transaction(&self, tx_hash: TxHash) -> bool {
476 let state = self.state.read().await;
477 state.transactions.contains_key(&tx_hash)
478 }
479
480 pub async fn get_transaction_details(&self, tx_hash: TxHash) -> Option<MempoolTransaction> {
490 let state = self.state.read().await;
491 state.transactions.get(&tx_hash).cloned()
492 }
493
494 fn detect_mev_transaction(tx: &Transaction) -> bool {
495 let input_str = hex::encode(&tx.input);
496 input_str.contains("0x6a761202")
497 || tx.value.is_zero() && !tx.input.is_empty()
498 || tx.gas_price.unwrap_or_default() > U256::from(100_000_000_000u64)
499 }
500
501 fn has_frontrunning_protection(tx: &Transaction) -> bool {
502 tx.max_priority_fee_per_gas.is_some() && tx.input.len() > 1000
504 }
505
506 pub async fn get_eip1559_transactions(&self) -> Vec<MempoolTransaction> {
508 let state = self.state.read().await;
509 state
510 .transactions
511 .values()
512 .filter(|tx| tx.transaction_type == Some(2))
513 .cloned()
514 .collect()
515 }
516
517 pub async fn get_mev_transactions(&self) -> Vec<MempoolTransaction> {
519 let state = self.state.read().await;
520 state
521 .transactions
522 .values()
523 .filter(|tx| tx.is_mev)
524 .cloned()
525 .collect()
526 }
527
528 fn detect_transaction_bundles(transactions: &[Transaction]) -> HashMap<TxHash, Vec<TxHash>> {
529 let mut bundles = HashMap::new();
530 let mut by_sender: HashMap<Address, Vec<&Transaction>> = HashMap::new();
531 for tx in transactions {
532 by_sender.entry(tx.from).or_default().push(tx);
533 }
534 for (sender, txs) in by_sender {
535 let mut sorted_txs = txs;
536 sorted_txs.sort_by_key(|tx| tx.nonce);
537 let mut current_bundle = Vec::new();
538 for window in sorted_txs.windows(2) {
539 if let [prev, current] = window {
540 if current.nonce == prev.nonce + U256::one() {
541 if current_bundle.is_empty() {
542 current_bundle.push(prev.hash);
543 }
544 current_bundle.push(current.hash);
545 } else if !current_bundle.is_empty() {
546 if current_bundle.len() > 1 {
547 let bundle_hash = Self::calculate_bundle_hash(¤t_bundle);
548 bundles.insert(bundle_hash, current_bundle.clone());
549 }
550 current_bundle.clear();
551 }
552 }
553 }
554 if current_bundle.len() > 1 {
555 let bundle_hash = Self::calculate_bundle_hash(¤t_bundle);
556 bundles.insert(bundle_hash, current_bundle);
557 }
558 }
559 let mut by_contract: HashMap<Address, Vec<&Transaction>> = HashMap::new();
560 for tx in transactions {
561 if let Some(to) = tx.to {
562 by_contract.entry(to).or_default().push(tx);
563 }
564 }
565 for (contract, txs) in by_contract {
566 if txs.len() > 1 {
567 let mut by_selector: HashMap<Vec<u8>, Vec<TxHash>> = HashMap::new();
568 for tx in txs {
569 if tx.input.len() >= 4 {
570 let selector = tx.input.0[..4].to_vec();
571 by_selector.entry(selector).or_default().push(tx.hash);
572 }
573 }
574 for (_, tx_hashes) in by_selector {
575 if tx_hashes.len() > 1 {
576 let bundle_hash = Self::calculate_bundle_hash(&tx_hashes);
577 bundles.insert(bundle_hash, tx_hashes);
578 }
579 }
580 }
581 }
582 bundles
583 }
584
585 fn calculate_bundle_hash(tx_hashes: &[TxHash]) -> TxHash {
586 let mut hasher = Keccak256::new();
587 for tx_hash in tx_hashes {
588 hasher.update(tx_hash.as_bytes());
589 }
590 let result = hasher.finalize();
591 TxHash::from_slice(&result[..32])
592 }
593
594 fn find_bundle_for_transaction(
595 tx: &Transaction,
596 bundles: &HashMap<TxHash, Vec<TxHash>>,
597 ) -> Option<TxHash> {
598 for (bundle_hash, tx_hashes) in bundles {
599 if tx_hashes.contains(&tx.hash) {
600 return Some(*bundle_hash);
601 }
602 }
603 None
604 }
605
606 pub async fn get_bundle_transactions(&self, bundle_hash: TxHash) -> Vec<MempoolTransaction> {
607 let state = self.state.read().await;
608 if let Some(tx_hashes) = state.transaction_bundles.get(&bundle_hash) {
609 tx_hashes
610 .iter()
611 .filter_map(|tx_hash| state.transactions.get(tx_hash))
612 .cloned()
613 .collect()
614 } else {
615 Vec::new()
616 }
617 }
618
619 pub async fn get_all_bundles(&self) -> HashMap<TxHash, Vec<TxHash>> {
620 let state = self.state.read().await;
621 state.transaction_bundles.clone()
622 }
623}
624
625#[derive(Debug, Clone)]
627pub struct MempoolStats {
628 pub total_transactions: usize,
629 pub total_value: U256,
630 pub total_gas: U256,
631 pub average_gas_price: U256,
632 pub last_block_number: u64,
633 pub eip1559_transactions: usize,
634 pub mev_transactions: usize,
635 pub protected_transactions: usize,
636}
637
638#[derive(Clone)]
640pub struct MempoolService {
641 evm: Arc<Evm>,
642}
643
644impl MempoolService {
645 pub fn new(evm: Arc<Evm>) -> Self {
647 Self { evm: evm }
648 }
649
650 pub fn create_listener(&self) -> MempoolListener {
658 MempoolListener::new(self.evm.clone())
659 }
660
661 pub fn create_listener_with_config(&self, config: MempoolConfig) -> MempoolListener {
673 MempoolListener::with_config(self.evm.clone(), config)
674 }
675
676 pub async fn get_pending_transaction_count(&self) -> Result<usize, EvmError> {
684 let filter = Filter::new().from_block(ethers::types::BlockNumber::Latest);
685 let logs = self.evm.get_logs(filter).await?;
686 Ok(logs.len())
687 }
688
689 pub async fn get_suggested_gas_price(&self) -> Result<U256, EvmError> {
697 self.evm.get_gas_price().await
698 }
699}