Skip to main content

evm_sdk/
trade.rs

1use crate::{Evm, EvmError, erc::erc20::ERC20Service, global::is_quote, types::Direction};
2use ethers::{
3    providers::Middleware,
4    types::{
5        Address, BlockNumber, Filter, H256, Log, Transaction, TransactionReceipt, U256,
6        ValueOrArray,
7    },
8};
9use log::error;
10use serde::{Deserialize, Serialize};
11use std::{
12    sync::{
13        Arc,
14        atomic::{AtomicU64, Ordering},
15    },
16    time::Duration,
17};
18use tokio::time::interval;
19
20#[derive(Debug, Clone, Serialize, Deserialize)]
21pub struct TransactionQuery {
22    pub address: String,
23    pub from_block: Option<u64>,
24    pub to_block: Option<u64>,
25    pub page: Option<u64>,
26    pub page_size: Option<u64>,
27}
28
29#[derive(Debug, Clone, Serialize, Deserialize)]
30pub struct TransactionWithReceipt {
31    pub transaction: Transaction,
32    pub receipt: Option<TransactionReceipt>,
33}
34
35#[derive(Debug, Clone, Serialize, Deserialize)]
36pub struct PaginatedTransactions {
37    pub transactions: Vec<TransactionWithReceipt>,
38    pub total: u64,
39    pub page: u64,
40    pub page_size: u64,
41    pub total_pages: u64,
42}
43
44/// Service for handling transaction-related operations
45pub struct Trade {
46    evm: Arc<Evm>,
47    erc20_service: ERC20Service,
48}
49
50impl Trade {
51    pub fn new(evm: Arc<Evm>) -> Self {
52        Self {
53            evm: evm.clone(),
54            erc20_service: ERC20Service::new(evm.clone()),
55        }
56    }
57
58    /// Retrieve transaction details based on transaction hash
59    ///
60    /// # Params
61    /// - `tx_hash`: tx hash
62    ///
63    /// # Returns
64    /// - `Ok(TransactionInfo)`: Transaction details
65    /// - `Err(EvmError)`: Error message when retrieving failure information
66    ///
67    /// # Example
68    /// ```
69    /// let tx_info = trade_service.get_transactions_by_tx("0x1234...").await?;
70    /// ```
71    pub async fn get_transactions_by_tx(&self, tx_hash: &str) -> Result<TransactionInfo, EvmError> {
72        let hash: H256 = tx_hash
73            .parse()
74            .map_err(|e| EvmError::RpcError(format!("Invalid transaction hash format: {}", e)))?;
75        let transaction = self
76            .evm
77            .client
78            .provider
79            .get_transaction(hash)
80            .await
81            .map_err(|e| EvmError::RpcError(format!("Failed to get transaction: {}", e)))?
82            .ok_or_else(|| EvmError::RpcError("Transaction not found".to_string()))?;
83        let receipt = self
84            .evm
85            .client
86            .provider
87            .get_transaction_receipt(hash)
88            .await
89            .map_err(|e| EvmError::RpcError(format!("Failed to get transaction receipt: {}", e)))?;
90        let mut timestamp: Option<U256> = None;
91        let mut logs = Vec::new();
92        if let Some(block_number) = transaction.block_number {
93            if let Ok(Some(block)) = self
94                .evm
95                .client
96                .provider
97                .get_block(ethers::types::BlockId::Number(
98                    ethers::types::BlockNumber::Number(block_number),
99                ))
100                .await
101            {
102                timestamp = Some(block.timestamp);
103            }
104            if let Some(ref receipt_data) = receipt {
105                logs = receipt_data.logs.clone();
106            }
107        }
108        let hash_str = format!("{:?}", hash);
109        let hash_short = if hash_str.len() > 10 {
110            format!("{}...{}", &hash_str[0..6], &hash_str[hash_str.len() - 4..])
111        } else {
112            hash_str.clone()
113        };
114        let is_contract_creation = transaction.to.is_none();
115        let contract_address = receipt.as_ref().and_then(|r| r.contract_address);
116        let status = receipt.as_ref().and_then(|r| r.status).map(|s| s.as_u64());
117        let is_success = status.map(|s| s == 1).unwrap_or(false);
118        let gas_used = receipt.as_ref().and_then(|r| r.gas_used);
119        let total_gas_cost =
120            if let (Some(gas_used_val), Some(gas_price_val)) = (gas_used, transaction.gas_price) {
121                gas_used_val.checked_mul(gas_price_val)
122            } else {
123                None
124            };
125        let max_priority_fee_per_gas = transaction.max_priority_fee_per_gas;
126        let max_fee_per_gas = transaction.max_fee_per_gas;
127        let transaction_type = transaction.transaction_type.map(|t| t.as_u64());
128        let chain_id = transaction.chain_id;
129        let mut token_decimals_cache = std::collections::HashMap::new();
130        for log in &logs {
131            let token_address = log.address;
132            match self.erc20_service.get_decimals(token_address).await {
133                Ok(decimals) => {
134                    token_decimals_cache.insert(token_address, decimals);
135                }
136                Err(e) => {
137                    token_decimals_cache.insert(token_address, 18);
138                }
139            }
140        }
141        Ok(TransactionInfo {
142            hash,
143            from: transaction.from,
144            to: transaction.to,
145            value: transaction.value,
146            gas_price: transaction.gas_price,
147            gas: transaction.gas,
148            gas_used,
149            input: transaction.input.to_vec(),
150            block_number: transaction.block_number.map(|n| n.as_u64()),
151            transaction_index: transaction.transaction_index.map(|i| i.as_u64()),
152            timestamp,
153            status,
154            is_contract_creation,
155            hash_short,
156            receipt,
157            raw_transaction: transaction,
158            contract_address,
159            transaction_type,
160            max_priority_fee_per_gas,
161            max_fee_per_gas,
162            chain_id,
163            logs,
164            is_success,
165            total_gas_cost,
166            token_decimals_cache,
167        })
168    }
169
170    /// Get transactions for a specific address with filtering and pagination
171    ///
172    /// # Example
173    /// ```
174    /// let query = TransactionQuery {
175    ///     address: "0x...".to_string(),
176    ///     from_block: Some(1000000),
177    ///     to_block: Some(1001000),
178    ///     page: Some(1),
179    ///     page_size: Some(50),
180    /// };
181    /// let result = trade_service.get_transactions_by_address(query).await?;
182    /// ```
183    pub async fn get_transactions_by_address(
184        &self,
185        query: TransactionQuery,
186    ) -> Result<PaginatedTransactions, EvmError> {
187        let address: Address = query
188            .address
189            .parse()
190            .map_err(|e| EvmError::RpcError(format!("Invalid address format: {}", e)))?;
191
192        let page = query.page.unwrap_or(1);
193        let page_size = query.page_size.unwrap_or(50);
194        let mut filter = Filter::new().address(ValueOrArray::Value(address));
195        if let Some(from_block) = query.from_block {
196            filter = filter.from_block(BlockNumber::Number(from_block.into()));
197        }
198        if let Some(to_block) = query.to_block {
199            filter = filter.to_block(BlockNumber::Number(to_block.into()));
200        }
201        let logs = self
202            .evm
203            .client
204            .provider
205            .get_logs(&filter)
206            .await
207            .map_err(|e| EvmError::RpcError(format!("Failed to get logs: {}", e)))?;
208
209        let total = logs.len() as u64;
210        let total_pages = (total as f64 / page_size as f64).ceil() as u64;
211        let start_index = ((page - 1) * page_size) as usize;
212        let end_index = std::cmp::min(start_index + page_size as usize, logs.len());
213        let mut transactions = Vec::new();
214        for log in logs
215            .into_iter()
216            .skip(start_index)
217            .take(end_index - start_index)
218        {
219            if let Some(tx_hash) = log.transaction_hash {
220                if let Ok(Some(tx)) = self.evm.client.provider.get_transaction(tx_hash).await {
221                    let receipt = self
222                        .evm
223                        .client
224                        .provider
225                        .get_transaction_receipt(tx_hash)
226                        .await
227                        .map_err(|e| EvmError::RpcError(format!("Failed to get receipt: {}", e)))?;
228                    transactions.push(TransactionWithReceipt {
229                        transaction: tx,
230                        receipt,
231                    });
232                }
233            }
234        }
235        Ok(PaginatedTransactions {
236            transactions,
237            total,
238            page,
239            page_size,
240            total_pages,
241        })
242    }
243
244    /// Get transactions involving two specific addresses
245    ///
246    /// # Example
247    /// ```
248    /// let address_a = "0x...".to_string();
249    /// let address_b = "0x...".to_string();
250    /// let transactions = trade_service.get_transactions_involving_addresses(
251    ///     address_a,
252    ///     address_b,
253    ///     Some(1000000),
254    ///     Some(1001000)
255    /// ).await?;
256    /// ```
257    pub async fn get_transactions_involving_addresses(
258        &self,
259        address_a: String,
260        address_b: String,
261        from_block: Option<u64>,
262        to_block: Option<u64>,
263    ) -> Result<Vec<TransactionWithReceipt>, EvmError> {
264        let address_a_parsed: Address = address_a
265            .parse()
266            .map_err(|e| EvmError::RpcError(format!("Invalid address_a format: {}", e)))?;
267        let address_b_parsed: Address = address_b
268            .parse()
269            .map_err(|e| EvmError::RpcError(format!("Invalid address_b format: {}", e)))?;
270
271        let mut filter = Filter::new().address(ValueOrArray::Array(vec![
272            address_a_parsed,
273            address_b_parsed,
274        ]));
275        if let Some(from_block) = from_block {
276            filter = filter.from_block(BlockNumber::Number(from_block.into()));
277        }
278        if let Some(to_block) = to_block {
279            filter = filter.to_block(BlockNumber::Number(to_block.into()));
280        }
281        let logs = self
282            .evm
283            .client
284            .provider
285            .get_logs(&filter)
286            .await
287            .map_err(|e| EvmError::RpcError(format!("Failed to get logs: {}", e)))?;
288        let mut transactions = Vec::new();
289        let mut processed_hashes = std::collections::HashSet::new();
290        for log in logs {
291            if let Some(tx_hash) = log.transaction_hash {
292                if processed_hashes.contains(&tx_hash) {
293                    continue;
294                }
295                processed_hashes.insert(tx_hash);
296                if let Ok(Some(tx)) = self.evm.client.provider.get_transaction(tx_hash).await {
297                    let involves_both = tx.from == address_a_parsed
298                        || tx.from == address_b_parsed
299                        || tx
300                            .to
301                            .map(|to| to == address_a_parsed || to == address_b_parsed)
302                            .unwrap_or(false);
303                    if involves_both {
304                        let receipt = self
305                            .evm
306                            .client
307                            .provider
308                            .get_transaction_receipt(tx_hash)
309                            .await
310                            .map_err(|e| {
311                                EvmError::RpcError(format!("Failed to get receipt: {}", e))
312                            })?;
313                        transactions.push(TransactionWithReceipt {
314                            transaction: tx,
315                            receipt,
316                        });
317                    }
318                }
319            }
320        }
321        Ok(transactions)
322    }
323
324    /// Get transactions where sender address sent to receiver address
325    ///
326    /// # Example
327    /// ```
328    /// let receiver = "0x...".to_string();
329    /// let sender = "0x...".to_string();
330    /// let transactions = trade_service.get_transactions_from_b_to_a(
331    ///     receiver,
332    ///     sender,
333    ///     Some(1000000),
334    ///     Some(1001000)
335    /// ).await?;
336    /// ```
337    pub async fn get_transactions_from_b_to_a(
338        &self,
339        receiver: String, // receiver address
340        sender: String,   // sender address
341        from_block: Option<u64>,
342        to_block: Option<u64>,
343    ) -> Result<Vec<TransactionWithReceipt>, EvmError> {
344        let receiver_parsed: Address = receiver
345            .parse()
346            .map_err(|e| EvmError::RpcError(format!("Invalid receiver address format: {}", e)))?;
347        let sender_parsed: Address = sender
348            .parse()
349            .map_err(|e| EvmError::RpcError(format!("Invalid sender address format: {}", e)))?;
350
351        let mut filter = Filter::new().address(ValueOrArray::Value(receiver_parsed));
352        if let Some(from_block) = from_block {
353            filter = filter.from_block(BlockNumber::Number(from_block.into()));
354        }
355        if let Some(to_block) = to_block {
356            filter = filter.to_block(BlockNumber::Number(to_block.into()));
357        }
358        let logs = self
359            .evm
360            .client
361            .provider
362            .get_logs(&filter)
363            .await
364            .map_err(|e| EvmError::RpcError(format!("Failed to get logs: {}", e)))?;
365        let mut transactions = Vec::new();
366        for log in logs {
367            if let Some(tx_hash) = log.transaction_hash {
368                if let Ok(Some(tx)) = self.evm.client.provider.get_transaction(tx_hash).await {
369                    if tx.from == sender_parsed
370                        && tx.to.map(|to| to == receiver_parsed).unwrap_or(false)
371                    {
372                        let receipt = self
373                            .evm
374                            .client
375                            .provider
376                            .get_transaction_receipt(tx_hash)
377                            .await
378                            .map_err(|e| {
379                                EvmError::RpcError(format!("Failed to get receipt: {}", e))
380                            })?;
381                        transactions.push(TransactionWithReceipt {
382                            transaction: tx,
383                            receipt,
384                        });
385                    }
386                }
387            }
388        }
389        Ok(transactions)
390    }
391
392    /// Get transaction statistics for an address
393    ///
394    /// # Example
395    /// ```
396    /// let stats = trade_service.get_transaction_stats(
397    ///     "0x...".to_string(),
398    ///     Some(1000000),
399    ///     Some(1001000)
400    /// ).await?;
401    /// ```
402    pub async fn get_transaction_stats(
403        &self,
404        address: String,
405        from_block: Option<u64>,
406        to_block: Option<u64>,
407    ) -> Result<TransactionStats, EvmError> {
408        let address_parsed: Address = address
409            .parse()
410            .map_err(|e| EvmError::RpcError(format!("Invalid address format: {}", e)))?;
411
412        let query = TransactionQuery {
413            address: address.clone(),
414            from_block,
415            to_block,
416            page: None,
417            page_size: None,
418        };
419        let transactions = self.get_transactions_by_address(query).await?;
420        let mut total_received = ethers::types::U256::zero();
421        let mut total_sent = ethers::types::U256::zero();
422        let mut incoming_count = 0;
423        let mut outgoing_count = 0;
424        for tx_with_receipt in transactions.transactions {
425            let tx = tx_with_receipt.transaction;
426            if tx.from == address_parsed {
427                outgoing_count += 1;
428                total_sent += tx.value;
429            } else if tx.to.map(|to| to == address_parsed).unwrap_or(false) {
430                incoming_count += 1;
431                total_received += tx.value;
432            }
433        }
434        Ok(TransactionStats {
435            address: address_parsed,
436            total_transactions: (incoming_count + outgoing_count) as u64,
437            incoming_count: incoming_count as u64,
438            outgoing_count: outgoing_count as u64,
439            total_received,
440            total_sent,
441            first_seen_block: from_block.unwrap_or(0),
442            last_seen_block: to_block.unwrap_or(0),
443        })
444    }
445
446    /// Get transaction by hash
447    ///
448    /// # Example
449    /// ```
450    /// let tx_hash = "0x...".parse().unwrap();
451    /// let transaction = trade_service.get_transaction_by_hash(tx_hash).await?;
452    /// ```
453    pub async fn get_transaction_by_hash(
454        &self,
455        tx_hash: H256,
456    ) -> Result<Option<TransactionWithReceipt>, EvmError> {
457        let tx = self
458            .evm
459            .client
460            .provider
461            .get_transaction(tx_hash)
462            .await
463            .map_err(|e| EvmError::RpcError(format!("Failed to get transaction: {}", e)))?;
464        if let Some(transaction) = tx {
465            let receipt = self
466                .evm
467                .client
468                .provider
469                .get_transaction_receipt(tx_hash)
470                .await
471                .map_err(|e| EvmError::RpcError(format!("Failed to get receipt: {}", e)))?;
472            Ok(Some(TransactionWithReceipt {
473                transaction,
474                receipt,
475            }))
476        } else {
477            Ok(None)
478        }
479    }
480
481    /// Get balance history for an address
482    ///
483    /// # Example
484    /// ```
485    /// let history = trade_service.get_balance_history(
486    ///     "0x...".to_string(),
487    ///     1000000,
488    ///     1001000,
489    ///     100
490    /// ).await?;
491    /// ```
492    pub async fn get_balance_history(
493        &self,
494        address: String,
495        from_block: u64,
496        to_block: u64,
497        interval: u64,
498    ) -> Result<Vec<BalanceSnapshot>, EvmError> {
499        let address_parsed: Address = address
500            .parse()
501            .map_err(|e| EvmError::RpcError(format!("Invalid address format: {}", e)))?;
502        let mut snapshots = Vec::new();
503        for block_number in (from_block..=to_block).step_by(interval as usize) {
504            let balance = self
505                .evm
506                .client
507                .provider
508                .get_balance(address_parsed, Some(block_number.into()))
509                .await
510                .map_err(|e| EvmError::RpcError(format!("Failed to get balance: {}", e)))?;
511            snapshots.push(BalanceSnapshot {
512                block_number,
513                balance,
514                timestamp: 0,
515            });
516        }
517        Ok(snapshots)
518    }
519}
520
521#[derive(Debug, Clone, Serialize, Deserialize)]
522pub struct TransferEvent {
523    pub from: Address,
524    pub to: Address,
525    pub value: ethers::types::U256,
526    pub transaction_hash: H256,
527    pub block_number: u64,
528    pub log_index: u64,
529}
530
531impl TransferEvent {
532    pub fn from_log(log: &Log) -> Result<Self, String> {
533        if log.topics.len() != 3 {
534            return Err(format!(
535                "Invalid Transfer event log: expected 3 topics, got {}",
536                log.topics.len()
537            ));
538        }
539        let from_bytes = log.topics[1].as_bytes();
540        if from_bytes.len() != 32 {
541            return Err(format!("Invalid from topic length: {}", from_bytes.len()));
542        }
543        let from = Address::from_slice(&from_bytes[12..]);
544        let to_bytes = log.topics[2].as_bytes();
545        if to_bytes.len() != 32 {
546            return Err(format!("Invalid to topic length: {}", to_bytes.len()));
547        }
548        let to = Address::from_slice(&to_bytes[12..]);
549        let value = if log.data.is_empty() {
550            ethers::types::U256::zero()
551        } else {
552            let mut data_bytes = [0u8; 32];
553            let data_len = log.data.len();
554            if data_len >= 32 {
555                data_bytes.copy_from_slice(&log.data[..32]);
556            } else {
557                let start = 32 - data_len;
558                data_bytes[start..].copy_from_slice(&log.data);
559            }
560            ethers::types::U256::from_big_endian(&data_bytes)
561        };
562        let transaction_hash = log
563            .transaction_hash
564            .ok_or("Missing transaction hash in log".to_string())?;
565        let block_number = log
566            .block_number
567            .ok_or("Missing block number in log".to_string())?
568            .as_u64();
569        let log_index = log
570            .log_index
571            .ok_or("Missing log index in log".to_string())?
572            .as_u64();
573        Ok(TransferEvent {
574            from,
575            to,
576            value,
577            transaction_hash,
578            block_number,
579            log_index,
580        })
581    }
582}
583
584#[derive(Debug, Clone, Serialize, Deserialize)]
585pub struct TransactionStats {
586    pub address: Address,
587    pub total_transactions: u64,
588    pub incoming_count: u64,
589    pub outgoing_count: u64,
590    pub total_received: ethers::types::U256,
591    pub total_sent: ethers::types::U256,
592    pub first_seen_block: u64,
593    pub last_seen_block: u64,
594}
595
596#[derive(Debug, Clone, Serialize, Deserialize)]
597pub struct BalanceSnapshot {
598    pub block_number: u64,
599    pub balance: ethers::types::U256,
600    pub timestamp: u64,
601}
602
603/// Event listener for transaction monitoring
604pub struct TradeEventListener {
605    evm: Arc<Evm>,
606}
607
608impl TradeEventListener {
609    pub fn new(evm: Arc<Evm>) -> Self {
610        Self { evm: evm }
611    }
612
613    /// Watch for large transactions based on value threshold
614    ///
615    /// # Example
616    /// ```
617    /// let mut receiver = event_listener.watch_large_transactions(
618    ///     U256::from(10u64.pow(18)), // 1 ETH
619    ///     3
620    /// ).await?;
621    ///
622    /// while let Some(tx) = receiver.recv().await {
623    ///     println!("Large transaction: {:?}", tx.transaction.hash);
624    /// }
625    /// ```
626    pub async fn watch_large_transactions(
627        &self,
628        min_value: ethers::types::U256,
629        poll_interval_secs: u64,
630    ) -> Result<tokio::sync::mpsc::Receiver<TransactionWithReceipt>, EvmError> {
631        let (tx, rx) = tokio::sync::mpsc::channel(100);
632        let evm = self.evm.clone();
633        let last_block = Arc::new(AtomicU64::new(0));
634        let current_block = evm
635            .client
636            .provider
637            .get_block_number()
638            .await
639            .map_err(|e| EvmError::RpcError(format!("Failed to get current block: {}", e)))?;
640        last_block.store(current_block.as_u64(), Ordering::SeqCst);
641        tokio::spawn(async move {
642            let mut poll_interval = interval(Duration::from_secs(poll_interval_secs));
643            loop {
644                poll_interval.tick().await;
645                if let Err(e) =
646                    Self::poll_large_transactions(&evm, &last_block, min_value, &tx).await
647                {
648                    tokio::time::sleep(Duration::from_secs(poll_interval_secs * 2)).await;
649                }
650            }
651        });
652        Ok(rx)
653    }
654
655    /// The core logic of polling large transactions
656    async fn poll_large_transactions(
657        evm: &Evm,
658        last_block: &AtomicU64,
659        min_value: ethers::types::U256,
660        tx: &tokio::sync::mpsc::Sender<TransactionWithReceipt>,
661    ) -> Result<(), EvmError> {
662        let current_block = evm
663            .client
664            .provider
665            .get_block_number()
666            .await
667            .map_err(|e| EvmError::RpcError(format!("Failed to get current block: {}", e)))?;
668        let current_block_num = current_block.as_u64();
669        let from_block = last_block.load(Ordering::SeqCst) + 1;
670        if from_block > current_block_num {
671            return Ok(());
672        }
673        let to_block = current_block_num;
674        for block_number in from_block..=to_block {
675            if let Ok(Some(block)) = evm.client.provider.get_block_with_txs(block_number).await {
676                for transaction in block.transactions {
677                    if transaction.value >= min_value {
678                        let receipt = evm
679                            .client
680                            .provider
681                            .get_transaction_receipt(transaction.hash)
682                            .await
683                            .map_err(|e| {
684                                EvmError::RpcError(format!("Failed to get receipt: {}", e))
685                            })?;
686                        let tx_with_receipt = TransactionWithReceipt {
687                            transaction,
688                            receipt,
689                        };
690                        if tx.send(tx_with_receipt).await.is_err() {
691                            return Ok(());
692                        }
693                    }
694                }
695            }
696        }
697        last_block.store(to_block, Ordering::SeqCst);
698        Ok(())
699    }
700
701    /// Watch for large ERC20 transfer events
702    ///
703    /// # Example
704    /// ```
705    /// let token_address = "0x...".to_string();
706    /// let mut receiver = event_listener.watch_large_transfers(
707    ///     Some(token_address),
708    ///     U256::from(1000 * 10u64.pow(18)), // 1000 tokens
709    ///     3
710    /// ).await?;
711    /// ```
712    pub async fn watch_large_transfers(
713        &self,
714        token_address: Option<String>,
715        min_value: ethers::types::U256,
716        poll_interval_secs: u64,
717    ) -> Result<tokio::sync::mpsc::Receiver<LargeTransferEvent>, EvmError> {
718        let token_address_parsed = match &token_address {
719            Some(addr_str) => {
720                let addr: Address = addr_str.parse().map_err(|e| {
721                    EvmError::RpcError(format!("Invalid token address format: {}", e))
722                })?;
723                Some(addr)
724            }
725            None => None,
726        };
727        let (tx, rx) = tokio::sync::mpsc::channel(100);
728        let evm = self.evm.clone();
729        let last_block = Arc::new(AtomicU64::new(0));
730        let current_block = evm
731            .client
732            .provider
733            .get_block_number()
734            .await
735            .map_err(|e| EvmError::RpcError(format!("Failed to get current block: {}", e)))?;
736        last_block.store(current_block.as_u64(), Ordering::SeqCst);
737        tokio::spawn(async move {
738            let mut poll_interval = interval(Duration::from_secs(poll_interval_secs));
739            loop {
740                poll_interval.tick().await;
741                if let Err(e) = Self::poll_large_transfers(
742                    &evm,
743                    &last_block,
744                    token_address_parsed,
745                    min_value,
746                    &tx,
747                )
748                .await
749                {
750                    tokio::time::sleep(Duration::from_secs(poll_interval_secs * 2)).await;
751                }
752            }
753        });
754        Ok(rx)
755    }
756
757    /// The core logic of polling large transfer events
758    async fn poll_large_transfers(
759        evm: &Evm,
760        last_block: &AtomicU64,
761        token_address: Option<Address>,
762        min_value: ethers::types::U256,
763        tx: &tokio::sync::mpsc::Sender<LargeTransferEvent>,
764    ) -> Result<(), EvmError> {
765        let current_block = evm
766            .client
767            .provider
768            .get_block_number()
769            .await
770            .map_err(|e| EvmError::RpcError(format!("Failed to get current block: {}", e)))?;
771        let current_block_num = current_block.as_u64();
772        let from_block = last_block.load(Ordering::SeqCst) + 1;
773        if from_block > current_block_num {
774            return Ok(());
775        }
776        let to_block = if current_block_num - from_block > 1000 {
777            from_block + 1000
778        } else {
779            current_block_num
780        };
781        // Build Transfer event filters
782        let mut filter = Filter::new()
783            .event("Transfer(address,address,uint256)")
784            .from_block(BlockNumber::Number(from_block.into()))
785            .to_block(BlockNumber::Number(to_block.into()));
786        // If a token address is specified, transfer events for that token will be filtered.
787        if let Some(token_addr) = token_address {
788            filter = filter.address(token_addr);
789        }
790        let logs = evm
791            .client
792            .provider
793            .get_logs(&filter)
794            .await
795            .map_err(|e| EvmError::RpcError(format!("Failed to get transfer logs: {}", e)))?;
796        for log in logs {
797            match TransferEvent::from_log(&log) {
798                Ok(transfer_event) => {
799                    if transfer_event.value >= min_value {
800                        let large_transfer = LargeTransferEvent {
801                            token_address: log.address,
802                            from: transfer_event.from,
803                            to: transfer_event.to,
804                            value: transfer_event.value,
805                            transaction_hash: transfer_event.transaction_hash,
806                            block_number: transfer_event.block_number,
807                            log_index: transfer_event.log_index,
808                        };
809                        if tx.send(large_transfer).await.is_err() {
810                            return Ok(());
811                        }
812                    }
813                }
814                Err(e) => {
815                    error!(target: "[Trade Module]", "Failed to parse transfer event: {:?}", e);
816                }
817            }
818        }
819        last_block.store(to_block, Ordering::SeqCst);
820        Ok(())
821    }
822
823    /// Watch large transfers for a specific token
824    pub async fn watch_large_token_transfers(
825        &self,
826        token_address: String,
827        min_value: ethers::types::U256,
828    ) -> Result<tokio::sync::mpsc::Receiver<LargeTransferEvent>, EvmError> {
829        self.watch_large_transfers(Some(token_address), min_value, 3)
830            .await
831    }
832
833    /// Watch large transfers for all tokens
834    pub async fn watch_all_large_transfers(
835        &self,
836        min_value: ethers::types::U256,
837    ) -> Result<tokio::sync::mpsc::Receiver<LargeTransferEvent>, EvmError> {
838        self.watch_large_transfers(None, min_value, 3).await
839    }
840
841    /// Watch all events for a specific address
842    ///
843    /// # Example
844    /// ```
845    /// let mut receiver = event_listener.watch_address_events(
846    ///     "0x...".to_string()
847    /// ).await?;
848    /// ```
849    pub async fn watch_address_events(
850        &self,
851        address: String,
852    ) -> Result<tokio::sync::mpsc::Receiver<Log>, EvmError> {
853        let address_parsed: Address = address
854            .parse()
855            .map_err(|e| EvmError::RpcError(format!("Invalid address format: {}", e)))?;
856        let (tx, rx) = tokio::sync::mpsc::channel(100);
857        let evm = self.evm.clone();
858        let last_block = Arc::new(AtomicU64::new(0));
859        let current_block = evm
860            .client
861            .provider
862            .get_block_number()
863            .await
864            .map_err(|e| EvmError::RpcError(format!("Failed to get current block: {}", e)))?;
865        last_block.store(current_block.as_u64(), Ordering::SeqCst);
866        tokio::spawn(async move {
867            let mut poll_interval = interval(Duration::from_secs(3));
868            loop {
869                poll_interval.tick().await;
870                if let Err(e) = Self::poll_events(&evm, &last_block, address_parsed, &tx).await {
871                    tokio::time::sleep(Duration::from_secs(5)).await;
872                }
873            }
874        });
875        Ok(rx)
876    }
877
878    /// The core logic of polling events
879    async fn poll_events(
880        evm: &Evm,
881        last_block: &AtomicU64,
882        address: Address,
883        tx: &tokio::sync::mpsc::Sender<Log>,
884    ) -> Result<(), EvmError> {
885        let current_block = evm
886            .client
887            .provider
888            .get_block_number()
889            .await
890            .map_err(|e| EvmError::RpcError(format!("Failed to get current block: {}", e)))?;
891        let current_block_num = current_block.as_u64();
892        let from_block = last_block.load(Ordering::SeqCst) + 1;
893        if from_block > current_block_num {
894            return Ok(());
895        }
896        let to_block = if current_block_num - from_block > 1000 {
897            from_block + 1000
898        } else {
899            current_block_num
900        };
901        let filter = Filter::new()
902            .address(address)
903            .from_block(BlockNumber::Number(from_block.into()))
904            .to_block(BlockNumber::Number(to_block.into()));
905        let logs = evm
906            .client
907            .provider
908            .get_logs(&filter)
909            .await
910            .map_err(|e| EvmError::RpcError(format!("Failed to get logs: {}", e)))?;
911        for log in logs {
912            if tx.send(log).await.is_err() {
913                return Ok(());
914            }
915        }
916        last_block.store(to_block, Ordering::SeqCst);
917        Ok(())
918    }
919
920    /// Watch transfer events for a specific address
921    pub async fn watch_transfer_events(
922        &self,
923        address: String,
924    ) -> Result<tokio::sync::mpsc::Receiver<TransferEvent>, EvmError> {
925        let address_parsed: Address = address
926            .parse()
927            .map_err(|e| EvmError::RpcError(format!("Invalid address format: {}", e)))?;
928
929        let (tx, rx) = tokio::sync::mpsc::channel(100);
930        let evm = self.evm.clone();
931        let last_block = Arc::new(AtomicU64::new(0));
932        let current_block = evm
933            .client
934            .provider
935            .get_block_number()
936            .await
937            .map_err(|e| EvmError::RpcError(format!("Failed to get current block: {}", e)))?;
938        last_block.store(current_block.as_u64(), Ordering::SeqCst);
939        tokio::spawn(async move {
940            let mut poll_interval = interval(Duration::from_secs(3));
941            loop {
942                poll_interval.tick().await;
943                if let Err(e) =
944                    Self::poll_transfer_events(&evm, &last_block, address_parsed, &tx).await
945                {
946                    error!(target: "[Trade Module]", "Error polling transfer events: {:?}", e);
947                    tokio::time::sleep(Duration::from_secs(5)).await;
948                }
949            }
950        });
951        Ok(rx)
952    }
953
954    /// The core logic of polling transfer events
955    async fn poll_transfer_events(
956        evm: &Evm,
957        last_block: &AtomicU64,
958        address: Address,
959        tx: &tokio::sync::mpsc::Sender<TransferEvent>,
960    ) -> Result<(), EvmError> {
961        let current_block = evm
962            .client
963            .provider
964            .get_block_number()
965            .await
966            .map_err(|e| EvmError::RpcError(format!("Failed to get current block: {}", e)))?;
967        let current_block_num = current_block.as_u64();
968        let from_block = last_block.load(Ordering::SeqCst) + 1;
969        if from_block > current_block_num {
970            return Ok(());
971        }
972        let to_block = if current_block_num - from_block > 1000 {
973            from_block + 1000
974        } else {
975            current_block_num
976        };
977        let filter = Filter::new()
978            .address(address)
979            .event("Transfer(address,address,uint256)")
980            .from_block(BlockNumber::Number(from_block.into()))
981            .to_block(BlockNumber::Number(to_block.into()));
982        let logs = evm
983            .client
984            .provider
985            .get_logs(&filter)
986            .await
987            .map_err(|e| EvmError::RpcError(format!("Failed to get transfer logs: {}", e)))?;
988        for log in logs {
989            match TransferEvent::from_log(&log) {
990                Ok(transfer_event) => {
991                    if tx.send(transfer_event).await.is_err() {
992                        return Ok(());
993                    }
994                }
995                Err(e) => {
996                    error!(target: "[Trade Module]", "Failed to parse transfer event: {:?}", e);
997                }
998            }
999        }
1000        last_block.store(to_block, Ordering::SeqCst);
1001        Ok(())
1002    }
1003
1004    /// Watch address events with custom configuration
1005    pub async fn watch_address_events_with_config(
1006        &self,
1007        address: String,
1008        poll_interval_secs: u64,
1009        max_blocks_per_poll: u64,
1010    ) -> Result<tokio::sync::mpsc::Receiver<Log>, EvmError> {
1011        let address_parsed: Address = address
1012            .parse()
1013            .map_err(|e| EvmError::RpcError(format!("Invalid address format: {}", e)))?;
1014        let (tx, rx) = tokio::sync::mpsc::channel(100);
1015        let evm = self.evm.clone();
1016        let last_block = Arc::new(AtomicU64::new(0));
1017        let current_block = evm
1018            .client
1019            .provider
1020            .get_block_number()
1021            .await
1022            .map_err(|e| EvmError::RpcError(format!("Failed to get current block: {}", e)))?;
1023        last_block.store(current_block.as_u64(), Ordering::SeqCst);
1024        tokio::spawn(async move {
1025            let mut poll_interval = interval(Duration::from_secs(poll_interval_secs));
1026            loop {
1027                poll_interval.tick().await;
1028                if let Err(e) = Self::poll_events_with_config(
1029                    &evm,
1030                    &last_block,
1031                    address_parsed,
1032                    &tx,
1033                    max_blocks_per_poll,
1034                )
1035                .await
1036                {
1037                    error!(target: "[Trade Module]", "Error polling events: {:?}", e);
1038                    tokio::time::sleep(Duration::from_secs(poll_interval_secs * 2)).await;
1039                }
1040            }
1041        });
1042        Ok(rx)
1043    }
1044
1045    /// Polling logic with configuration
1046    async fn poll_events_with_config(
1047        evm: &Evm,
1048        last_block: &AtomicU64,
1049        address: Address,
1050        tx: &tokio::sync::mpsc::Sender<Log>,
1051        max_blocks_per_poll: u64,
1052    ) -> Result<(), EvmError> {
1053        let current_block = evm
1054            .client
1055            .provider
1056            .get_block_number()
1057            .await
1058            .map_err(|e| EvmError::RpcError(format!("Failed to get current block: {}", e)))?;
1059        let current_block_num = current_block.as_u64();
1060        let from_block = last_block.load(Ordering::SeqCst) + 1;
1061        if from_block > current_block_num {
1062            return Ok(());
1063        }
1064        let to_block = if current_block_num - from_block > max_blocks_per_poll {
1065            from_block + max_blocks_per_poll
1066        } else {
1067            current_block_num
1068        };
1069        let filter = Filter::new()
1070            .address(address)
1071            .from_block(BlockNumber::Number(from_block.into()))
1072            .to_block(BlockNumber::Number(to_block.into()));
1073        let logs = evm
1074            .client
1075            .provider
1076            .get_logs(&filter)
1077            .await
1078            .map_err(|e| EvmError::RpcError(format!("Failed to get logs: {}", e)))?;
1079        for log in logs {
1080            if tx.send(log).await.is_err() {
1081                return Ok(());
1082            }
1083        }
1084        last_block.store(to_block, Ordering::SeqCst);
1085        Ok(())
1086    }
1087
1088    pub fn stop_event_listener(receiver: tokio::sync::mpsc::Receiver<Log>) {
1089        drop(receiver);
1090    }
1091}
1092
1093/// Large transfer event structure
1094#[derive(Debug, Clone, Serialize, Deserialize)]
1095pub struct LargeTransferEvent {
1096    pub token_address: Address,
1097    pub from: Address,
1098    pub to: Address,
1099    pub value: ethers::types::U256,
1100    pub transaction_hash: H256,
1101    pub block_number: u64,
1102    pub log_index: u64,
1103}
1104
1105impl LargeTransferEvent {
1106    /// Formatted display of large transfer information
1107    pub fn display(&self) -> String {
1108        format!(
1109            "Large Transfer: {} {} from {:?} to {:?} in tx {:?}",
1110            ethers::utils::format_units(self.value, 18).unwrap_or("N/A".to_string()),
1111            self.token_short_name(),
1112            self.from,
1113            self.to,
1114            self.transaction_hash
1115        )
1116    }
1117
1118    /// Get the token short name
1119    pub fn token_short_name(&self) -> String {
1120        format!("{:?}...", &self.token_address.to_string()[..8])
1121    }
1122
1123    pub fn to_transfer_event(&self) -> TransferEvent {
1124        TransferEvent {
1125            from: self.from,
1126            to: self.to,
1127            value: self.value,
1128            transaction_hash: self.transaction_hash,
1129            block_number: self.block_number,
1130            log_index: self.log_index,
1131        }
1132    }
1133}
1134
1135/// Large transaction monitoring configuration
1136#[derive(Debug, Clone, Serialize, Deserialize)]
1137pub struct LargeTransactionConfig {
1138    pub min_value: ethers::types::U256,
1139    pub poll_interval_secs: u64,
1140    pub include_failed: bool,
1141    pub watch_tokens: Vec<Address>,
1142}
1143
1144impl Default for LargeTransactionConfig {
1145    fn default() -> Self {
1146        Self {
1147            min_value: ethers::types::U256::from(10u64.pow(18)), // 1 ETH
1148            poll_interval_secs: 3,
1149            include_failed: false,
1150            watch_tokens: Vec::new(),
1151        }
1152    }
1153}
1154
1155#[derive(Debug, Clone, Serialize, Deserialize)]
1156pub struct TransactionInfo {
1157    pub hash: H256,
1158    pub from: Address,
1159    pub to: Option<Address>,
1160    pub value: U256,
1161    pub gas_price: Option<U256>,
1162    pub gas: U256,
1163    pub gas_used: Option<U256>,
1164    pub input: Vec<u8>,
1165    pub block_number: Option<u64>,
1166    pub transaction_index: Option<u64>,
1167    pub timestamp: Option<U256>,
1168    pub status: Option<u64>,
1169    pub is_contract_creation: bool,
1170    pub hash_short: String,
1171    pub receipt: Option<TransactionReceipt>,
1172    pub raw_transaction: Transaction,
1173    pub contract_address: Option<Address>,
1174    pub transaction_type: Option<u64>,
1175    pub max_priority_fee_per_gas: Option<U256>,
1176    pub max_fee_per_gas: Option<U256>,
1177    pub chain_id: Option<U256>,
1178    pub logs: Vec<Log>,
1179    pub is_success: bool,
1180    pub total_gas_cost: Option<U256>,
1181    pub token_decimals_cache: std::collections::HashMap<Address, u8>,
1182}
1183
1184impl TransactionInfo {
1185    pub fn get_received_token(&self) -> Option<(Address, ethers::types::U256)> {
1186        if !self.is_success {
1187            return None;
1188        }
1189        for log in &self.logs {
1190            if log.topics.len() == 3 {
1191                match TransferEvent::from_log(log) {
1192                    Ok(transfer) => {
1193                        let value = transfer.value;
1194                        if value > ethers::types::U256::from(1)
1195                            && value
1196                                < ethers::types::U256::from(10).pow(ethers::types::U256::from(30))
1197                        {
1198                            return Some((log.address, value));
1199                        }
1200                    }
1201                    Err(_) => continue,
1202                }
1203            }
1204        }
1205        None
1206    }
1207
1208    pub fn get_spent_token(&self) -> Option<(Address, ethers::types::U256)> {
1209        if !self.is_success {
1210            return None;
1211        }
1212        let mut valid_transfers = Vec::new();
1213        for log in &self.logs {
1214            if log.topics.len() == 3 {
1215                match TransferEvent::from_log(log) {
1216                    Ok(transfer) => {
1217                        let value = transfer.value;
1218                        if value > ethers::types::U256::from(1)
1219                            && value
1220                                < ethers::types::U256::from(10).pow(ethers::types::U256::from(30))
1221                        {
1222                            valid_transfers.push((log.address, value));
1223                        }
1224                    }
1225                    Err(_) => continue,
1226                }
1227            }
1228        }
1229        if valid_transfers.len() >= 2 {
1230            return Some(valid_transfers[1]);
1231        }
1232        if valid_transfers.len() == 1 {
1233            return Some(valid_transfers[0]);
1234        }
1235        None
1236    }
1237
1238    pub fn get_received_token_eth(&self) -> Option<(Address, f64)> {
1239        self.get_received_token().and_then(|(addr, amount)| {
1240            let decimals = self.get_token_decimals(&addr);
1241            let decimal_amount = amount.as_u128() as f64 / 10_u64.pow(decimals as u32) as f64;
1242            Some((addr, decimal_amount))
1243        })
1244    }
1245
1246    pub fn get_spent_token_eth(&self) -> Option<(Address, f64)> {
1247        self.get_spent_token().and_then(|(addr, amount)| {
1248            let decimals = self.get_token_decimals(&addr);
1249            let decimal_amount = amount.as_u128() as f64 / 10_u64.pow(decimals as u32) as f64;
1250            Some((addr, decimal_amount))
1251        })
1252    }
1253
1254    fn get_token_decimals(&self, token_address: &Address) -> u8 {
1255        *self.token_decimals_cache.get(token_address).unwrap_or(&18)
1256    }
1257
1258    pub fn getDirection(&self) -> Direction {
1259        if (is_quote(&format!("{:?}", &self.get_spent_token_eth().unwrap().0))) {
1260            Direction::Buy
1261        } else {
1262            Direction::Sell
1263        }
1264    }
1265
1266    /// get liquidity pool addresses
1267    pub fn get_liquidity_pool_addresses(&self) -> Vec<Address> {
1268        use crate::global::dex_events;
1269        let mut pool_addresses = Vec::new();
1270        let swap_sig = dex_events::uniswap_v2_swap();
1271        let mint_sig = dex_events::uniswap_v2_mint();
1272        let burn_sig = dex_events::uniswap_v2_burn();
1273        let sync_sig = dex_events::uniswap_v2_sync();
1274        let add_liquidity_sig = dex_events::curve_add_liquidity();
1275        let remove_liquidity_sig = dex_events::curve_remove_liquidity();
1276        for log in &self.logs {
1277            if log.topics.is_empty() {
1278                continue;
1279            }
1280            let topic0_bytes = log.topics[0].as_bytes();
1281            if topic0_bytes[..] == swap_sig[..]
1282                || topic0_bytes[..] == mint_sig[..]
1283                || topic0_bytes[..] == burn_sig[..]
1284                || topic0_bytes[..] == sync_sig[..]
1285                || topic0_bytes[..] == add_liquidity_sig[..]
1286                || topic0_bytes[..] == remove_liquidity_sig[..]
1287            {
1288                pool_addresses.push(log.address);
1289            }
1290            if log.topics.len() == 3 && log.data.len() >= 32 {
1291                if self.logs.iter().any(|other_log| {
1292                    other_log.address == log.address
1293                        && !other_log.topics.is_empty()
1294                        && other_log.topics[0].as_bytes()[..] == swap_sig[..]
1295                }) {
1296                    pool_addresses.push(log.address);
1297                }
1298            }
1299        }
1300        pool_addresses.sort();
1301        pool_addresses.dedup();
1302        pool_addresses
1303    }
1304
1305    pub fn get_dex_names(&self) -> Vec<String> {
1306        use crate::global::{dex_events, get_dex_name_by_address};
1307        let mut exchange_names = Vec::new();
1308        if let Some(to_address) = self.to {
1309            let to_str = format!("{:?}", to_address);
1310            if let Some(dex_name) = get_dex_name_by_address(&to_str) {
1311                exchange_names.push(dex_name.to_string());
1312            }
1313        }
1314        let from_str = format!("{:?}", self.from);
1315        if let Some(dex_name) = get_dex_name_by_address(&from_str) {
1316            let name = dex_name.to_string();
1317            if !exchange_names.contains(&name) {
1318                exchange_names.push(name);
1319            }
1320        }
1321        let mut dex_identified_by_events = Vec::new();
1322        for log in &self.logs {
1323            if log.topics.is_empty() {
1324                continue;
1325            }
1326            let topic0_bytes = log.topics[0].as_bytes();
1327            if let Some(dex_name) = dex_events::identify_dex_by_event(topic0_bytes) {
1328                if !dex_identified_by_events.contains(&dex_name.to_string()) {
1329                    dex_identified_by_events.push(dex_name.to_string());
1330                }
1331            }
1332            let log_addr_str = format!("{:?}", log.address);
1333            if let Some(dex_name) = get_dex_name_by_address(&log_addr_str) {
1334                let name = dex_name.to_string();
1335                if !exchange_names.contains(&name) {
1336                    exchange_names.push(name);
1337                }
1338            }
1339        }
1340        for dex_name in dex_identified_by_events {
1341            if !exchange_names.contains(&dex_name) {
1342                exchange_names.push(dex_name);
1343            }
1344        }
1345        if exchange_names.is_empty() {
1346            let pool_addresses = self.get_liquidity_pool_addresses();
1347            if !pool_addresses.is_empty() {
1348                exchange_names.push("Decentralized Exchange".to_string());
1349            }
1350        }
1351        if !self.input.is_empty() && self.input.len() >= 4 {
1352            let selector = &self.input[0..4];
1353            let dex_selectors: Vec<([u8; 4], &str)> = vec![
1354                ([0x38, 0xed, 0x17, 0x38], "Uniswap V2"), // swapExactTokensForTokens
1355                ([0x88, 0x03, 0xdb, 0xee], "Uniswap V2"), // swapTokensForExactTokens
1356                ([0x02, 0x1b, 0x21, 0xfc], "SushiSwap"),  // swapExactTokensForTokens (Sushi)
1357                ([0x59, 0x1c, 0x58, 0xdf], "Curve"),      // exchange
1358                ([0x09, 0x5e, 0xa7, 0xb3], "1inch"),      // swap
1359            ];
1360            for (func_selector, dex_name) in dex_selectors {
1361                if selector == func_selector {
1362                    if !exchange_names.contains(&dex_name.to_string()) {
1363                        exchange_names.push(dex_name.to_string());
1364                    }
1365                    break;
1366                }
1367            }
1368        }
1369        exchange_names.sort();
1370        exchange_names.dedup();
1371        exchange_names
1372    }
1373}
1374
1375#[cfg(test)]
1376mod test {
1377    use evm_client::EvmType;
1378
1379    use crate::{Evm, trade::Trade};
1380    use std::{sync::Arc, time::Duration};
1381
1382    #[tokio::test]
1383    async fn test_get_transaction_by_tx() {
1384        let evm = Evm::new(evm_client::EvmType::ETHEREUM_MAINNET)
1385            .await
1386            .unwrap();
1387        let trade = Trade::new(Arc::new(evm));
1388        let t = trade
1389            .get_transactions_by_tx(
1390                "0x2c632c004c7a2c5daedf54f53a7ab424756b383bfc477bfc802e3a1d5a930a2e",
1391            )
1392            .await
1393            .unwrap();
1394        // reality received
1395        let received = t.get_received_token_eth();
1396        // reality spent
1397        let spent = t.get_spent_token_eth();
1398        println!("Actual Received {:?}", received);
1399        println!("Actual Spent {:?}", spent);
1400        println!(
1401            "Liquidity Pool Address:{:?}",
1402            t.get_liquidity_pool_addresses()
1403        );
1404        println!("Dex Names :{:?}", t.get_dex_names());
1405    }
1406}