#![cfg_attr(docsrs, feature(doc_cfg))] //! # Clients for interacting with Ethereum nodes //! //! This crate provides asynchronous [Ethereum JSON-RPC](https://github.com/ethereum/wiki/wiki/JSON-RPC) //! compliant clients. //! //! For more documentation on the available calls, refer to the [`Provider`](crate::Provider) //! struct. //! //! # Examples //! //! ```no_run //! use ethers::providers::{Provider, Http, Middleware}; //! use std::convert::TryFrom; //! //! # async fn foo() -> Result<(), Box> { //! let provider = Provider::::try_from( //! "https://mainnet.infura.io/v3/c60b0bb42f8a4c6481ecd229eddaca27" //! )?; //! //! let block = provider.get_block(100u64).await?; //! println!("Got block: {}", serde_json::to_string(&block)?); //! //! let code = provider.get_code("0x89d24a6b4ccb1b6faa2625fe562bdd9a23260359", None).await?; //! println!("Got code: {}", serde_json::to_string(&code)?); //! # Ok(()) //! # } //! ``` //! //! # Websockets //! //! The crate has support for WebSockets. If none of the provided async runtime //! features are enabled, you must manually instantiate the WS connection and wrap //! it with with a [`Ws::new`](method@crate::Ws::new) call. //! //! ```ignore //! use ethers::providers::Ws; //! //! let ws = Ws::new(...); //! ``` //! //! If you have compiled the library with any of the following features, you may //! instantiate the websocket instance with the `connect` call and your URL: //! - `tokio-runtime`: Uses `tokio` as the runtime //! - `async-std-runtime`: Uses `async-std-runtime` //! //! ```no_run //! # #[cfg(any( //! # feature = "tokio-runtime", //! # feature = "tokio-tls", //! # feature = "async-std-runtime", //! # feature = "async-std-tls", //! # ))] //! # async fn foo() -> Result<(), Box> { //! # use ethers::providers::Ws; //! let ws = Ws::connect("ws://localhost:8545").await?; //! # Ok(()) //! # } //! ``` //! //! TLS support is also provided via the following feature flags: //! - `tokio-tls` //! - `async-tls` //! //! ```no_run //! # #[cfg(any( //! # feature = "tokio-runtime", //! # feature = "tokio-tls", //! # feature = "async-std-runtime", //! # feature = "async-std-tls", //! # ))] //! # async fn foo() -> Result<(), Box> { //! # use ethers::providers::Ws; //! let ws = Ws::connect("wss://localhost:8545").await?; //! # Ok(()) //! # } //! ``` //! //! # Ethereum Name Service //! //! The provider may also be used to resolve [Ethereum Name Service](https://ens.domains) (ENS) names //! to addresses (and vice versa). The default ENS address is [mainnet](https://etherscan.io/address/0x00000000000C2E074eC69A0dFb2997BA6C7d2e1e) and can be overriden by calling the [`ens`](method@crate::Provider::ens) method on the provider. //! //! ```no_run //! # use ethers::providers::{Provider, Http, Middleware}; //! # use std::convert::TryFrom; //! # async fn foo() -> Result<(), Box> { //! # let provider = Provider::::try_from( //! # "https://mainnet.infura.io/v3/c60b0bb42f8a4c6481ecd229eddaca27" //! # )?; //! // Resolve ENS name to Address //! let name = "vitalik.eth"; //! let address = provider.resolve_name(name).await?; //! //! // Lookup ENS name given Address //! let resolved_name = provider.lookup_address(address).await?; //! assert_eq!(name, resolved_name); //! # Ok(()) //! # } //! ``` mod transports; pub use transports::*; mod provider; // ENS support mod ens; mod pending_transaction; pub use pending_transaction::PendingTransaction; mod stream; pub use futures_util::StreamExt; pub use stream::{interval, FilterWatcher, DEFAULT_POLL_INTERVAL}; mod pubsub; pub use pubsub::{PubsubClient, SubscriptionStream}; use async_trait::async_trait; use serde::{de::DeserializeOwned, Serialize}; use std::{error::Error, fmt::Debug, future::Future, pin::Pin}; pub use provider::{FilterKind, Provider, ProviderError}; // Helper type alias pub(crate) type PinBoxFut<'a, T> = Pin> + Send + 'a>>; #[async_trait] /// Trait which must be implemented by data transports to be used with the Ethereum /// JSON-RPC provider. pub trait JsonRpcClient: Debug + Send + Sync { /// A JSON-RPC Error type Error: Error + Into; /// Sends a request with the provided JSON-RPC and parameters serialized as JSON async fn request(&self, method: &str, params: T) -> Result where T: Debug + Serialize + Send + Sync, R: DeserializeOwned; } use ethers_core::types::*; pub trait FromErr { fn from(src: T) -> Self; } #[async_trait] pub trait Middleware: Sync + Send + Debug { type Error: Sync + Send + Error + FromErr<::Error>; type Provider: JsonRpcClient; type Inner: Middleware; fn inner(&self) -> &Self::Inner; async fn get_block_number(&self) -> Result { self.inner().get_block_number().await.map_err(FromErr::from) } async fn send_transaction( &self, tx: TransactionRequest, block: Option, ) -> Result { self.inner() .send_transaction(tx, block) .await .map_err(FromErr::from) } async fn resolve_name(&self, ens_name: &str) -> Result { self.inner() .resolve_name(ens_name) .await .map_err(FromErr::from) } async fn lookup_address(&self, address: Address) -> Result { self.inner() .lookup_address(address) .await .map_err(FromErr::from) } async fn get_block + Send + Sync>( &self, block_hash_or_number: T, ) -> Result>, Self::Error> { self.inner() .get_block(block_hash_or_number) .await .map_err(FromErr::from) } async fn get_block_with_txs + Send + Sync>( &self, block_hash_or_number: T, ) -> Result>, Self::Error> { self.inner() .get_block_with_txs(block_hash_or_number) .await .map_err(FromErr::from) } async fn get_transaction_count + Send + Sync>( &self, from: T, block: Option, ) -> Result { self.inner() .get_transaction_count(from, block) .await .map_err(FromErr::from) } async fn estimate_gas(&self, tx: &TransactionRequest) -> Result { self.inner().estimate_gas(tx).await.map_err(FromErr::from) } async fn call( &self, tx: &TransactionRequest, block: Option, ) -> Result { self.inner().call(tx, block).await.map_err(FromErr::from) } async fn get_chainid(&self) -> Result { self.inner().get_chainid().await.map_err(FromErr::from) } async fn get_balance + Send + Sync>( &self, from: T, block: Option, ) -> Result { self.inner() .get_balance(from, block) .await .map_err(FromErr::from) } async fn get_transaction>( &self, transaction_hash: T, ) -> Result, Self::Error> { self.inner() .get_transaction(transaction_hash) .await .map_err(FromErr::from) } async fn get_transaction_receipt>( &self, transaction_hash: T, ) -> Result, Self::Error> { self.inner() .get_transaction_receipt(transaction_hash) .await .map_err(FromErr::from) } async fn get_gas_price(&self) -> Result { self.inner().get_gas_price().await.map_err(FromErr::from) } async fn get_accounts(&self) -> Result, Self::Error> { self.inner().get_accounts().await.map_err(FromErr::from) } async fn send_raw_transaction(&self, tx: &Transaction) -> Result { self.inner() .send_raw_transaction(tx) .await .map_err(FromErr::from) } async fn sign + Send + Sync>( &self, data: T, from: &Address, ) -> Result { self.inner().sign(data, from).await.map_err(FromErr::from) } ////// Contract state async fn get_logs(&self, filter: &Filter) -> Result, Self::Error> { self.inner().get_logs(filter).await.map_err(FromErr::from) } async fn new_filter(&self, filter: FilterKind<'_>) -> Result { self.inner().new_filter(filter).await.map_err(FromErr::from) } async fn uninstall_filter + Send + Sync>( &self, id: T, ) -> Result { self.inner() .uninstall_filter(id) .await .map_err(FromErr::from) } async fn watch<'a>( &'a self, filter: &Filter, ) -> Result, Self::Error> { self.inner().watch(filter).await.map_err(FromErr::from) } async fn watch_pending_transactions( &self, ) -> Result, Self::Error> { self.inner() .watch_pending_transactions() .await .map_err(FromErr::from) } async fn get_filter_changes(&self, id: T) -> Result, Self::Error> where T: Into + Send + Sync, R: DeserializeOwned + Send + Sync, { self.inner() .get_filter_changes(id) .await .map_err(FromErr::from) } async fn watch_blocks(&self) -> Result, Self::Error> { self.inner().watch_blocks().await.map_err(FromErr::from) } async fn get_code + Send + Sync>( &self, at: T, block: Option, ) -> Result { self.inner() .get_code(at, block) .await .map_err(FromErr::from) } async fn get_storage_at + Send + Sync>( &self, from: T, location: H256, block: Option, ) -> Result { self.inner() .get_storage_at(from, location, block) .await .map_err(FromErr::from) } fn pending_transaction(&self, tx_hash: TxHash) -> PendingTransaction<'_, Self::Provider> { self.inner().pending_transaction(tx_hash) } // Mempool inspection for Geth's API async fn txpool_content(&self) -> Result { self.inner().txpool_content().await.map_err(FromErr::from) } async fn txpool_inspect(&self) -> Result { self.inner().txpool_inspect().await.map_err(FromErr::from) } async fn txpool_status(&self) -> Result { self.inner().txpool_status().await.map_err(FromErr::from) } // Parity `trace` support /// Executes the given call and returns a number of possible traces for it async fn trace_call( &self, req: TransactionRequest, trace_type: Vec, block: Option, ) -> Result { self.inner() .trace_call(req, trace_type, block) .await .map_err(FromErr::from) } /// Traces a call to `eth_sendRawTransaction` without making the call, returning the traces async fn trace_raw_transaction( &self, data: Bytes, trace_type: Vec, ) -> Result { self.inner() .trace_raw_transaction(data, trace_type) .await .map_err(FromErr::from) } /// Replays a transaction, returning the traces async fn trace_replay_transaction( &self, hash: H256, trace_type: Vec, ) -> Result { self.inner() .trace_replay_transaction(hash, trace_type) .await .map_err(FromErr::from) } /// Replays all transactions in a block returning the requested traces for each transaction async fn trace_replay_block_transactions( &self, block: BlockNumber, trace_type: Vec, ) -> Result, Self::Error> { self.inner() .trace_replay_block_transactions(block, trace_type) .await .map_err(FromErr::from) } /// Returns traces created at given block async fn trace_block(&self, block: BlockNumber) -> Result, Self::Error> { self.inner().trace_block(block).await.map_err(FromErr::from) } /// Return traces matching the given filter async fn trace_filter(&self, filter: TraceFilter) -> Result, Self::Error> { self.inner() .trace_filter(filter) .await .map_err(FromErr::from) } /// Returns trace at the given position async fn trace_get + Send + Sync>( &self, hash: H256, index: Vec, ) -> Result { self.inner() .trace_get(hash, index) .await .map_err(FromErr::from) } /// Returns all traces of a given transaction async fn trace_transaction(&self, hash: H256) -> Result, Self::Error> { self.inner() .trace_transaction(hash) .await .map_err(FromErr::from) } // Parity namespace /// Returns all receipts for that block. Must be done on a parity node. async fn parity_block_receipts + Send + Sync>( &self, block: T, ) -> Result, Self::Error> { self.inner() .parity_block_receipts(block) .await .map_err(FromErr::from) } async fn subscribe( &self, params: T, ) -> Result, Self::Error> where T: Debug + Serialize + Send + Sync, R: DeserializeOwned + Send + Sync, ::Provider: PubsubClient, { self.inner().subscribe(params).await.map_err(FromErr::from) } async fn unsubscribe(&self, id: T) -> Result where T: Into + Send + Sync, ::Provider: PubsubClient, { self.inner().unsubscribe(id).await.map_err(FromErr::from) } async fn subscribe_blocks( &self, ) -> Result>, Self::Error> where ::Provider: PubsubClient, { self.inner().subscribe_blocks().await.map_err(FromErr::from) } async fn subscribe_pending_txs( &self, ) -> Result, Self::Error> where ::Provider: PubsubClient, { self.inner() .subscribe_pending_txs() .await .map_err(FromErr::from) } async fn subscribe_logs<'a>( &'a self, filter: &Filter, ) -> Result, Self::Error> where ::Provider: PubsubClient, { self.inner() .subscribe_logs(filter) .await .map_err(FromErr::from) } }