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
44pub 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 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 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 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 pub async fn get_transactions_from_b_to_a(
338 &self,
339 receiver: String, sender: String, 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 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 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 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
603pub 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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#[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 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 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#[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)), 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 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"), ([0x88, 0x03, 0xdb, 0xee], "Uniswap V2"), ([0x02, 0x1b, 0x21, 0xfc], "SushiSwap"), ([0x59, 0x1c, 0x58, 0xdf], "Curve"), ([0x09, 0x5e, 0xa7, 0xb3], "1inch"), ];
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 let received = t.get_received_token_eth();
1396 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}