Skip to main content

evm_sdk/
lib.rs

1pub mod block;
2/// This module is the EVM network abstraction layer.
3pub mod contract;
4pub mod erc;
5pub mod global;
6pub mod mempool;
7pub mod safe;
8pub mod tool;
9pub mod trade;
10pub mod types;
11pub mod onchain;
12
13use std::sync::Arc;
14
15use crate::block::BlockService;
16use crate::mempool::MempoolListener;
17use crate::mempool::MempoolService;
18use crate::trade::Trade;
19use crate::trade::TradeEventListener;
20use crate::types::EvmError;
21use ethers::providers::Middleware;
22use ethers::providers::StreamExt;
23use ethers::types::Block;
24use ethers::types::BlockNumber;
25use ethers::{
26    signers::Signer,
27    types::{Address, H256, TransactionRequest, U256},
28};
29use evm_client::EvmClient;
30use evm_client::EvmType;
31
32use ethers::types::Transaction;
33
34/// EVM Client for interacting with various EVM chains
35#[derive(Clone)]
36pub struct Evm {
37    pub client: EvmClient,
38}
39
40impl Evm {
41    /// Get block by number (height) - returns block with transaction hashes
42    pub async fn get_block_by_number(
43        &self,
44        block_number: BlockNumber,
45    ) -> Result<Option<Block<H256>>, EvmError> {
46        self.client
47            .provider
48            .get_block(block_number)
49            .await
50            .map_err(|e| EvmError::RpcError(format!("Failed to get block: {}", e)))
51    }
52
53    /// Get block by hash - returns block with transaction hashes
54    pub async fn get_block_by_hash(
55        &self,
56        block_hash: H256,
57    ) -> Result<Option<Block<H256>>, EvmError> {
58        self.client
59            .provider
60            .get_block(block_hash)
61            .await
62            .map_err(|e| EvmError::RpcError(format!("Failed to get block: {}", e)))
63    }
64
65    /// Get block with full transaction details
66    pub async fn get_block_with_txs(
67        &self,
68        block_number: BlockNumber,
69    ) -> Result<Option<Block<Transaction>>, EvmError> {
70        self.client
71            .provider
72            .get_block_with_txs(block_number)
73            .await
74            .map_err(|e| EvmError::RpcError(format!("Failed to get block with txs: {}", e)))
75    }
76
77    /// Get block with full transaction details by hash
78    pub async fn get_block_with_txs_by_hash(
79        &self,
80        block_hash: H256,
81    ) -> Result<Option<Block<Transaction>>, EvmError> {
82        let block = self.get_block_by_hash(block_hash).await?;
83        if let Some(ref block_info) = block {
84            if let Some(block_number) = block_info.number {
85                return self
86                    .get_block_with_txs(BlockNumber::Number(block_number))
87                    .await;
88            }
89        }
90        Ok(None)
91    }
92
93    /// Create a new EVM client without wallet
94    ///
95    /// # Example
96    /// ```
97    /// use evm_utils::Evm;
98    /// use evm_client::EvmType;
99    ///
100    /// async fn example() -> Result<(), Box<dyn std::error::Error>> {
101    /// let evm = Evm::new(EvmType::Ethereum).await?;
102    /// let chain_id = evm.get_chain_id().await?;
103    /// println!("Connected to chain ID: {}", chain_id);
104    /// Ok(())
105    /// }
106    /// ```
107    pub async fn new(evm_type: EvmType) -> Result<Self, EvmError> {
108        match EvmClient::from_type(evm_type).await {
109            Ok(client) => Ok(Self { client: client }),
110            Err(e) => Err(EvmError::RpcError(format!("Rpc Error:{:?}", e))),
111        }
112    }
113
114    /// Create a new EVM client with wallet
115    ///
116    /// # Example
117    /// ```
118    /// use evm_utils::Evm;
119    /// use evm_client::EvmType;
120    ///
121    /// async fn example() -> Result<(), Box<dyn std::error::Error>> {
122    /// let private_key = "your_private_key_here";
123    /// let evm = Evm::with_wallet(EvmType::Ethereum, private_key).await?;
124    /// let balance = evm.get_wallet_balance().await?;
125    /// println!("Wallet balance: {}", balance);
126    /// Ok(())
127    /// }
128    /// ```
129    pub async fn with_wallet(evm_type: EvmType, private_key: &str) -> Result<Self, EvmError> {
130        match EvmClient::from_wallet(evm_type, private_key).await {
131            Ok(client) => Ok(Self { client: client }),
132            Err(e) => Err(EvmError::RpcError(format!("Rpc Error:{:?}", e))),
133        }
134    }
135
136    /// Get chain ID
137    ///
138    /// # Example
139    /// ```
140    /// async fn example(evm: Evm) -> Result<(), Box<dyn std::error::Error>> {
141    /// let chain_id = evm.get_chain_id().await?;
142    /// println!("Chain ID: {}", chain_id);
143    /// Ok(())
144    /// }
145    /// ```
146    pub async fn get_chain_id(&self) -> Result<u64, EvmError> {
147        self.client
148            .provider
149            .get_chainid()
150            .await
151            .map_err(|e| EvmError::RpcError(format!("Failed to get chain ID: {}", e)))
152            .map(|id| id.as_u64())
153    }
154
155    /// Get block number
156    ///
157    /// # Example
158    /// ```
159    /// async fn example(evm: Evm) -> Result<(), Box<dyn std::error::Error>> {
160    /// let block_number = evm.get_block_number().await?;
161    /// println!("Current block number: {}", block_number);
162    /// Ok(())
163    /// }
164    /// ```
165    pub async fn get_block_number(&self) -> Result<u64, EvmError> {
166        self.client
167            .provider
168            .get_block_number()
169            .await
170            .map_err(|e| EvmError::RpcError(format!("Failed to get block number: {}", e)))
171            .map(|num| num.as_u64())
172    }
173
174    /// Get balance of an address
175    ///
176    /// # Example
177    /// ```
178    /// use ethers::types::Address;
179    ///
180    /// async fn example(evm: Evm) -> Result<(), Box<dyn std::error::Error>> {
181    /// let address: Address = "0x742d35Cc6634C0532925a3b8D6B5d7a4C03a3a7d".parse()?;
182    /// let balance = evm.get_balance(address).await?;
183    /// println!("Balance: {}", balance);
184    /// Ok(())
185    /// }
186    /// ```
187    pub async fn get_balance(&self, address: Address) -> Result<U256, EvmError> {
188        self.client
189            .provider
190            .get_balance(address, None)
191            .await
192            .map_err(|e| EvmError::RpcError(format!("Failed to get balance: {}", e)))
193    }
194
195    /// Get transaction count (nonce) for an address
196    ///
197    /// # Example
198    /// ```
199    /// use ethers::types::Address;
200    ///
201    /// async fn example(evm: Evm) -> Result<(), Box<dyn std::error::Error>> {
202    /// let address: Address = "0x742d35Cc6634C0532925a3b8D6B5d7a4C03a3a7d".parse()?;
203    /// let nonce = evm.get_transaction_count(address).await?;
204    /// println!("Nonce: {}", nonce);
205    /// Ok(())
206    /// }
207    /// ```
208    pub async fn get_transaction_count(&self, address: Address) -> Result<u64, EvmError> {
209        self.client
210            .provider
211            .get_transaction_count(address, None)
212            .await
213            .map_err(|e| EvmError::RpcError(format!("Failed to get transaction count: {}", e)))
214            .map(|nonce| nonce.as_u64())
215    }
216
217    /// Get gas price
218    ///
219    /// # Example
220    /// ```
221    /// async fn example(evm: Evm) -> Result<(), Box<dyn std::error::Error>> {
222    /// let gas_price = evm.get_gas_price().await?;
223    /// println!("Gas price: {}", gas_price);
224    /// Ok(())
225    /// }
226    /// ```
227    pub async fn get_gas_price(&self) -> Result<U256, EvmError> {
228        self.client
229            .provider
230            .get_gas_price()
231            .await
232            .map_err(|e| EvmError::RpcError(format!("Failed to get gas price: {}", e)))
233    }
234
235    /// Send a raw transaction
236    ///
237    /// # Example
238    /// ```
239    /// use ethers::types::{TransactionRequest, Address, U256};
240    ///
241    /// async fn example(evm: Evm) -> Result<(), Box<dyn std::error::Error>> {
242    /// let to_address: Address = "0x742d35Cc6634C0532925a3b8D6B5d7a4C03a3a7d".parse()?;
243    /// let tx = TransactionRequest::new()
244    ///     .to(to_address)
245    ///     .value(U256::from(1000000000000000u64));
246    ///     
247    /// let tx_hash = evm.send_transaction(tx).await?;
248    /// println!("Transaction sent: {:?}", tx_hash);
249    /// Ok(())
250    /// }
251    /// ```
252    pub async fn send_transaction(&self, mut tx: TransactionRequest) -> Result<H256, EvmError> {
253        if self.client.wallet.is_none() {
254            return Err(EvmError::WalletError("No wallet configured".to_string()));
255        }
256        let wallet = self.client.wallet.as_ref().unwrap();
257        tx.from = Some(wallet.address());
258        let chain_id = self.get_chain_id().await?;
259        tx.chain_id = Some(chain_id.into());
260        if tx.nonce.is_none() {
261            let nonce = self.get_transaction_count(wallet.address()).await?;
262            tx.nonce = Some(nonce.into());
263        }
264        if tx.gas_price.is_none() {
265            let gas_price = self.get_gas_price().await?;
266            tx.gas_price = Some(gas_price);
267        }
268        let pending_tx = self
269            .client
270            .provider
271            .send_transaction(tx, None)
272            .await
273            .map_err(|e| {
274                EvmError::TransactionError(format!("Failed to send transaction: {}", e))
275            })?;
276        Ok(pending_tx.tx_hash())
277    }
278
279    /// Get transaction receipt
280    ///
281    /// # Example
282    /// ```
283    /// use ethers::types::H256;
284    ///
285    /// async fn example(evm: Evm) -> Result<(), Box<dyn std::error::Error>> {
286    /// let tx_hash: H256 = "0x...".parse()?;
287    /// let receipt = evm.get_transaction_receipt(tx_hash).await?;
288    /// if let Some(receipt) = receipt {
289    ///     println!("Transaction status: {}", receipt.status);
290    /// }
291    /// Ok(())
292    /// }
293    /// ```
294    pub async fn get_transaction_receipt(
295        &self,
296        tx_hash: H256,
297    ) -> Result<Option<ethers::types::TransactionReceipt>, EvmError> {
298        self.client
299            .provider
300            .get_transaction_receipt(tx_hash)
301            .await
302            .map_err(|e| EvmError::RpcError(format!("Failed to get transaction receipt: {}", e)))
303    }
304
305    /// Get logs by filter
306    ///
307    /// # Example
308    /// ```
309    /// use ethers::types::Filter;
310    /// use ethers::types::Address;
311    ///
312    /// async fn example(evm: Evm) -> Result<(), Box<dyn std::error::Error>> {
313    /// let contract_address: Address = "0x...".parse()?;
314    /// let filter = Filter::new()
315    ///     .address(contract_address)
316    ///     .from_block(1000000)
317    ///     .to_block(1000100);
318    ///     
319    /// let logs = evm.get_logs(filter).await?;
320    /// println!("Found {} logs", logs.len());
321    /// Ok(())
322    /// }
323    /// ```
324    pub async fn get_logs(
325        &self,
326        filter: ethers::types::Filter,
327    ) -> Result<Vec<ethers::types::Log>, EvmError> {
328        self.client
329            .provider
330            .get_logs(&filter)
331            .await
332            .map_err(|e| EvmError::RpcError(format!("Failed to get logs: {}", e)))
333    }
334
335    /// Get native token balance for the wallet
336    ///
337    /// # Example
338    /// ```
339    /// async fn example(evm: Evm) -> Result<(), Box<dyn std::error::Error>> {
340    /// let balance = evm.get_wallet_balance().await?;
341    /// println!("Wallet balance: {}", balance);
342    /// Ok(())
343    /// }
344    /// ```
345    pub async fn get_wallet_balance(&self) -> Result<U256, EvmError> {
346        if let Some(wallet) = &self.client.wallet {
347            let address = wallet.address();
348            self.get_balance(address).await
349        } else {
350            Err(EvmError::WalletError("No wallet configured".to_string()))
351        }
352    }
353
354    /// Get trade service for executing trades
355    ///
356    /// # Example
357    /// ```
358    /// use std::sync::Arc;
359    ///
360    /// async fn example(evm: Evm) -> Result<(), Box<dyn std::error::Error>> {
361    /// let evm_arc = Arc::new(evm);
362    /// let trade_service = evm_arc.clone().get_trade_service();
363    /// Ok(())
364    /// }
365    /// ```
366    pub fn get_trade_service(self: Arc<Self>) -> Trade {
367        Trade::new(self.clone())
368    }
369
370    /// Get trade event listener for monitoring trade events
371    ///
372    /// # Example
373    /// ```
374    /// use std::sync::Arc;
375    ///
376    /// async fn example(evm: Evm) -> Result<(), Box<dyn std::error::Error>> {
377    /// let evm_arc = Arc::new(evm);
378    /// let trade_listener = evm_arc.clone().get_trade_listener();
379    /// Ok(())
380    /// }
381    /// ```
382    pub fn get_trade_listener(self: Arc<Self>) -> TradeEventListener {
383        TradeEventListener::new(self.clone())
384    }
385
386    /// Get mempool service for mempool interactions
387    ///
388    /// # Example
389    /// ```
390    /// use std::sync::Arc;
391    ///
392    /// async fn example(evm: Evm) -> Result<(), Box<dyn std::error::Error>> {
393    /// let evm_arc = Arc::new(evm);
394    /// let mempool_service = evm_arc.clone().get_mempool_service();
395    /// Ok(())
396    /// }
397    /// ```
398    pub fn get_mempool_service(self: Arc<Self>) -> MempoolService {
399        MempoolService::new(self.clone())
400    }
401
402    /// Get mempool listener for monitoring mempool activities
403    ///
404    /// # Example
405    /// ```
406    /// use std::sync::Arc;
407    ///
408    /// async fn example(evm: Evm) -> Result<(), Box<dyn std::error::Error>> {
409    /// let evm_arc = Arc::new(evm);
410    /// let mempool_listener = evm_arc.clone().get_mempool_listener();
411    /// Ok(())
412    /// }
413    /// ```
414    pub fn get_mempool_listener(self: Arc<Self>) -> MempoolListener {
415        MempoolListener::new(self.clone())
416    }
417
418    /// Get block service for block-related operations
419    ///
420    /// # Example
421    /// ```
422    /// use std::sync::Arc;
423    ///
424    /// async fn example(evm: Evm) -> Result<(), Box<dyn std::error::Error>> {
425    ///     let evm_arc = Arc::new(evm);
426    ///     let block_service = evm_arc.clone().get_block_service();
427    ///     
428    ///     let latest_block = block_service.get_latest_block().await?;
429    ///     if let Some(block) = latest_block {
430    ///         println!("Latest block: #{}", block.number.unwrap_or_default());
431    ///     }
432    ///     Ok(())
433    /// }
434    /// ```
435    pub fn get_block_service(self: Arc<Self>) -> BlockService {
436        BlockService::new(self.clone())
437    }
438    
439    /// Listen to the latest block (listen to newly generated blocks in real time)
440    ///
441    /// # Example
442    /// ```
443    /// let mut block_receiver = trade_service.listen_latest_blocks().await?;
444    ///
445    /// while let Some(block) = block_receiver.recv().await {
446    ///     println!("New block: #{}", block.number.unwrap_or_default());
447    /// }
448    /// ```
449    pub async fn listen_latest_blocks(
450        &self,
451    ) -> Result<tokio::sync::broadcast::Receiver<ethers::types::Block<ethers::types::H256>>, EvmError>
452    {
453        use ethers::providers::Middleware;
454        use tokio::sync::broadcast;
455        let (sender, receiver) = broadcast::channel(1024);
456        let provider = self.client.provider.clone();
457        tokio::spawn(async move {
458            if let Ok(mut stream) = provider.watch_blocks().await {
459                while let Some(block_hash) = stream.next().await {
460                    match provider.get_block(block_hash).await {
461                        Ok(Some(block)) => {
462                            if sender.send(block).is_err() {
463                                break;
464                            }
465                        }
466                        Ok(None) => {
467                            log::warn!("Block not found for hash: {:?}", block_hash);
468                        }
469                        Err(e) => {
470                            log::error!("Failed to get block: {:?}", e);
471                        }
472                    }
473                }
474            } else {
475                log::error!("Failed to create block watcher stream");
476            }
477        });
478        Ok(receiver)
479    }
480}