From b2eb7210c7488564323c4831cd4411f732b0256f Mon Sep 17 00:00:00 2001 From: 0xKitsune <0xKitsune@protonmail.com> Date: Sat, 7 Jan 2023 01:19:19 -0500 Subject: [PATCH 01/12] started building out providers chapter for the book, updated the intro for the chapter as well as the Http section. Added advanced usage section. --- book/SUMMARY.md | 5 +- book/providers/advanced_provider_methods.md | 1 + book/providers/http.md | 142 +++++++++++++++++++- book/providers/providers.md | 30 +++++ book/providers/ws.md | 2 + 5 files changed, 175 insertions(+), 5 deletions(-) create mode 100644 book/providers/advanced_provider_methods.md create mode 100644 book/providers/providers.md diff --git a/book/SUMMARY.md b/book/SUMMARY.md index d3461cd5d..7e2980d09 100644 --- a/book/SUMMARY.md +++ b/book/SUMMARY.md @@ -6,14 +6,15 @@ - [Connect to an Ethereum node](./getting-started/connect_to_an_ethereum_node.md) # Reference guide -- [Providers]() +- [Providers](./providers/providers.md) - [Http](./providers/http.md) + - [WebSocket](./providers/ws.md) - [IPC](./providers/ipc.md) - [Mock](./providers/mock.md) - [Quorum](./providers/quorum.md) - [Retry](./providers/retry.md) - [RW](./providers/rw.md) - - [WebSocket](./providers/ws.md) + - [Advanced Provider Methods](./providers/advanced_provider_methods.md) - [Middleware]() - [Builder]() - [Create custom middleware]() diff --git a/book/providers/advanced_provider_methods.md b/book/providers/advanced_provider_methods.md new file mode 100644 index 000000000..0200b6c1d --- /dev/null +++ b/book/providers/advanced_provider_methods.md @@ -0,0 +1 @@ +# Advanced Provider Methods diff --git a/book/providers/http.md b/book/providers/http.md index 46e04a403..dc4dd0979 100644 --- a/book/providers/http.md +++ b/book/providers/http.md @@ -1,5 +1,141 @@ -# Http provider +# Http + +The `Http` provider establishes an Http connection with a node, allowing you to send RPC requests to the node to fetch data, simulate calls, send transactions and much more. + +## Initializing an Http Provider +Lets take a quick look at few ways to create a new `Http` provider. Since the `Http` provider implements the [`FromStr`](https://doc.rust-lang.org/std/str/trait.FromStr.html) one of the easiest ways to initialize a new provider is by using the `from_str()` method. + +```rust +use ethers::providers::{Http, Middleware, Provider}; + +#[tokio::main] +async fn main() -> eyre::Result<()> { + //Initialize a new Http provider + let rpc_url = "https://mainnet.infura.io/v3/c60b0bb42f8a4c6481ecd229eddaca27"; + let provider: Provider = Provider::::from_str(rpc_url)?; + + Ok(()) +} +``` + +The `Http` provider also supplies a way to initialize a new authorized connection. + +```rust +// Initializes a new HTTP Client with authentication +use ethers::providers::{Authorization, Http}; +use url::Url; +#[tokio::main] +async fn main() -> eyre::Result<()> { + let url = Url::parse("http://localhost:8545").unwrap(); + let provider = Http::new_with_auth(url, Authorization::basic("admin", "good_password")); + Ok(()) +} +``` + +Additionally, you can initialize a new provider with your own custom `reqwest::Client`. + +```rust +use ethers::providers::Http; +use url::Url; + +#[tokio::main] +async fn main() -> eyre::Result<()> { + let url = Url::parse("http://localhost:8545").unwrap(); + let client = reqwest::Client::builder().build().unwrap(); + let provider = Http::new_with_client(url, client); + Ok(()) +} +``` + +## Basic Usage + +Now that you have successfully established an Http connection with the node, you can use any of the methods provided by the `Middleware` trait. In the code snippet below, the provider is used to get the chain id, current block number and the content of the node's mempool. + +```rust +use ethers::providers::{Http, Middleware, Provider}; + +#[tokio::main] +async fn main() -> eyre::Result<()> { + let rpc_url = "https://mainnet.infura.io/v3/c60b0bb42f8a4c6481ecd229eddaca27"; + let provider: Provider = Provider::::from_str(rpc_url)?; + + let chain_id = provider.get_chainid().await?; + let block_number = provider.get_block_number().await?; + let tx_pool_content = provider.txpool_content().await?; + + Ok(()) +} +``` + +You can also use the provider to interact with smart contracts. The snippet below uses the provider to establish a new instance of a UniswapV2Pool and uses the `get_reserves()` method from the smart contract to fetch the current state of the pool's reserves. + +```rust +use std::{str::FromStr, sync::Arc}; + +use ethers::{ + prelude::abigen, + providers::{Http, Provider}, + types::H160, +}; + +abigen!( + IUniswapV2Pair, + r#"[function getReserves() external view returns (uint112 reserve0, uint112 reserve1, uint32 blockTimestampLast)]"# +); + +#[tokio::main] +async fn main() -> eyre::Result<()> { + let rpc_url = "https://mainnet.infura.io/v3/c60b0bb42f8a4c6481ecd229eddaca27"; + let provider: Arc> = Arc::new(Provider::::try_from(rpc_url).unwrap()); + + //Initialize a new instance of the Weth/Dai Uniswap V2 pair contract + let pair_address = H160::from_str("0xA478c2975Ab1Ea89e8196811F51A7B7Ade33eB11").unwrap(); + let uniswap_v2_pair = IUniswapV2Pair::new(pair_address, provider); + + //Use the get_reserves() function to fetch the pool reserves + let (reserve_0, reserve_1, block_timestamp_last) = + uniswap_v2_pair.get_reserves().call().await?; + + Ok(()) +} +``` + +This example is a little more complicated, so lets walk through what is going on. The `IUniswapV2Pair` is a struct that is generated from the `abigen!()` macro. The `IUniswapV2Pair::new()` function is used to create a new instance of the contract, taking in an `Address` and an `Arc` as arguments, where `M` is any type that implements the `Middleware` trait. Note that the provider is wrapped in an [`Arc`](https://doc.rust-lang.org/std/sync/struct.Arc.html) when being passed into the `new()` function. + +It is very common to wrap a provider in an `Arc` to share the provider across threads. Lets look at another example where the provider is used asynchronously across two tokio threads. In the next example, a new provider is initialized and used to asynchronously fetch the number of Ommer blocks from the most recent block, as well as the previous block. ```rust -{{#include ../../examples/providers/examples/http.rs}} -``` \ No newline at end of file +use std::sync::Arc; + +use ethers::providers::{Http, Middleware, Provider}; + +#[tokio::main] +async fn main() -> eyre::Result<()> { + let rpc_url = "https://mainnet.infura.io/v3/c60b0bb42f8a4c6481ecd229eddaca27"; + let provider: Arc> = Arc::new(Provider::::try_from(rpc_url).unwrap()); + + let current_block_number = provider.get_block_number().await?; + let prev_block_number = current_block_number - 1; + + //Clone the Arc and pass it into a new thread to get the uncle count of the current block + let provider_1 = provider.clone(); + let task_0 = + tokio::spawn(async move { provider_1.get_uncle_count(current_block_number).await }); + + //Spin up a new thread to get the uncle count of the previous block + let task_1 = tokio::spawn(async move { provider.get_uncle_count(prev_block_number).await }); + + //Wait for the tasks to finish + for task in [task_0, task_1] { + if let Ok(uncle_count) = task.await? { + println!("Success!"); + } + } + + Ok(()) +} +``` + +
+ +Before heading to the next chapter, feel free to check out the docs for the [`Http` provider](https://docs.rs/ethers/latest/ethers/providers/struct.Http.html). Keep in mind that we will cover advanced usage of providers at the end of this chapter. Now that we have the basics covered, lets move on to the next Provider, Websockets! \ No newline at end of file diff --git a/book/providers/providers.md b/book/providers/providers.md new file mode 100644 index 000000000..d18f1c548 --- /dev/null +++ b/book/providers/providers.md @@ -0,0 +1,30 @@ +# Providers + +Providers play a central role in `ethers-rs`, enabling you to establish asynchronous [Ethereum JSON-RPC](https://github.com/ethereum/wiki/wiki/JSON-RPC) compliant clients. + + your program to a node to get data, interact with smart contracts, listen to the mempool and much more. There are a few different types of default providers that are built into the library. The default providers are `Http`,`WS`,`Ipc`,`RWClient`,`Quorum`,`Mock` and `RetryClient`. In addition to all of these options, you can also create your own custom provider, which we will walk through later in this chapter. For now let take a look at what the `Provider` actually looks like. + + +```rust +#[derive(Clone, Debug)] +pub struct Provider

{ + inner: P, + ens: Option

, + interval: Option, + from: Option
, + /// Node client hasn't been checked yet= `None` + /// Unsupported node client = `Some(None)` + /// Supported node client = `Some(Some(NodeClient))` + _node_client: Arc>>, +} +``` + + + +The `Provider` struct defines a generic type `P` that can be any type that implements the [`JsonRpcClient` trait](https://docs.rs/ethers/latest/ethers/providers/trait.JsonRpcClient.html). The `inner` field stores the type that implements the `JsonRpcClient` type, allowing the Provider to make RPC calls to the node. The `ens` field is an optional value that xyz. The `interval` field is an optional value that defines the polling interval when for streams (subscribing to logs, block headers, etc.). The `from` field is an optional type that allows you to set a default "from" address when constructing transactions and making calls. Lastly, the `_node_client` field is xyz. + + +Note that all providers implement the [`Middleware` trait](https://docs.rs/ethers/latest/ethers/providers/trait.Middleware.html), which gives every provider access to [commonly used methods](https://docs.rs/ethers/latest/ethers/providers/struct.Provider.html#impl-Middleware-for-Provider%3CP%3E) to interact with the node. Later in this chapter, we will go over these methods and examples for how to use them in detail. Additionally, `Middleware` will be covered extensively in a later chapter. + +Now that you have a basis for what the `Provider` type actually is, the next few sections will walk through each implementation of the `Provider`, starting with the HTTP provider. + diff --git a/book/providers/ws.md b/book/providers/ws.md index ef6ca53a4..2e52dcc62 100644 --- a/book/providers/ws.md +++ b/book/providers/ws.md @@ -1,5 +1,7 @@ # WebSocket provider +The crate has support for WebSockets via Tokio. Please ensure that you have the “ws” and “rustls” / “openssl” features enabled if you wish to use WebSockets. + ```rust {{#include ../../examples/providers/examples/ws.rs}} ``` \ No newline at end of file From 75fadf22edcd4fe087a2f1d4384718b12622a751 Mon Sep 17 00:00:00 2001 From: 0xKitsune <0xKitsune@protonmail.com> Date: Mon, 9 Jan 2023 01:53:51 -0500 Subject: [PATCH 02/12] Updated WS and Ipc chapter, working on usage, furthering descriptions --- book/SUMMARY.md | 2 +- book/providers/advanced_provider_methods.md | 1 - book/providers/advanced_usage.md | 5 ++ book/providers/ipc.md | 23 ++++++++- book/providers/ws.md | 55 +++++++++++++++++++-- 5 files changed, 79 insertions(+), 7 deletions(-) delete mode 100644 book/providers/advanced_provider_methods.md create mode 100644 book/providers/advanced_usage.md diff --git a/book/SUMMARY.md b/book/SUMMARY.md index 7e2980d09..d3dfed73a 100644 --- a/book/SUMMARY.md +++ b/book/SUMMARY.md @@ -14,7 +14,7 @@ - [Quorum](./providers/quorum.md) - [Retry](./providers/retry.md) - [RW](./providers/rw.md) - - [Advanced Provider Methods](./providers/advanced_provider_methods.md) + - [Advanced Usage](./providers/advanced_usage.md) - [Middleware]() - [Builder]() - [Create custom middleware]() diff --git a/book/providers/advanced_provider_methods.md b/book/providers/advanced_provider_methods.md deleted file mode 100644 index 0200b6c1d..000000000 --- a/book/providers/advanced_provider_methods.md +++ /dev/null @@ -1 +0,0 @@ -# Advanced Provider Methods diff --git a/book/providers/advanced_usage.md b/book/providers/advanced_usage.md new file mode 100644 index 000000000..dfba6e7d9 --- /dev/null +++ b/book/providers/advanced_usage.md @@ -0,0 +1,5 @@ +# Advanced Usage + + +### `CallBuilder` +Todo: Mention how to use [state override set](https://geth.ethereum.org/docs/interacting-with-geth/rpc/ns-eth#3-object---state-override-set) \ No newline at end of file diff --git a/book/providers/ipc.md b/book/providers/ipc.md index ad4dc5eba..f53d9bd6e 100644 --- a/book/providers/ipc.md +++ b/book/providers/ipc.md @@ -1,5 +1,24 @@ # IPC provider +The IPC (Inter-Process Communication) transport is a way for a process to communicate with a running Ethereum client over a local Unix domain socket. If you are new to IPC, you can [follow this link to learn more](). Using the IPC transport allows the ethers library to send JSON-RPC requests to the Ethereum client and receive responses, without the need for a network connection or HTTP server. This can be useful for interacting with a local Ethereum node that is running on the same machine. Using Ipc [is faster than RPC](), however you will need to have a local node that you can connect to. + +## Initializing an Ipc Provider ```rust -{{#include ../../examples/providers/examples/ipc.rs}} -``` \ No newline at end of file +#[tokio::main] +async fn main() -> eyre::Result<()> { + + // We instantiate the provider using the path of a local Unix domain socket + // -------------------------------------------------------------------------------- + // NOTE: The IPC transport supports push notifications, but we still need to specify a polling + // interval because only subscribe RPC calls (e.g., transactions, blocks, events) support push + // notifications in Ethereum's RPC API. For other calls we must use repeated polling for many + // operations even with the IPC transport. + let provider = Provider::connect_ipc("~/.ethereum/geth.ipc") + .await? + .interval(std::time::Duration::from_millis(2000)); + + Ok(()) +} +``` +## Usage + diff --git a/book/providers/ws.md b/book/providers/ws.md index 2e52dcc62..59a8aa6f2 100644 --- a/book/providers/ws.md +++ b/book/providers/ws.md @@ -1,7 +1,56 @@ # WebSocket provider +The Ws provider allows you to send JSON-RPC requests and receive responses over WebSocket connections. The WS provider can be used with any Ethereum node that supports WebSocket connections. This allows programs interact with the network in real-time without the need for HTTP polling for things like new block headers and filter logs. Ethers-rs has support for WebSockets via Tokio. Make sure that you have the “ws” and “rustls” / “openssl” features enabled in your project's toml file if you wish to use WebSockets. -The crate has support for WebSockets via Tokio. Please ensure that you have the “ws” and “rustls” / “openssl” features enabled if you wish to use WebSockets. + +## Initializing a WS Provider +Lets look at a few ways to create a new `WS` provider. + + +```rust +#[tokio::main] +async fn main() -> eyre::Result<()> { + let ws_endpoint = ""; + let provider = Provider::::connect(ws_endpoint).await?; + Ok(()) +} +``` + +TODO: note on setting the polling interval + + +TODO: note on initializing a new ws provider with authorization like the http provider ```rust -{{#include ../../examples/providers/examples/ws.rs}} -``` \ No newline at end of file +#[tokio::main] +async fn main() -> eyre::Result<()> { + let ws_endpoint = ""; + let auth = Authorization::basic("username", "password"); + + if let Ok(_provider) = Provider::::connect_with_auth(url, auth).await { + println!("Create Ws provider with auth"); + } + + Ok(()) +} +``` + + + +TODO: snippet of creating a new ws provider with a custom WS. Initializes a new WebSocket Client, given a Stream/Sink Websocket implementer. The websocket connection must be initiated separately. + +```rust +#[tokio::main] +async fn main() -> eyre::Result<()> { + let ws_endpoint = ""; + let auth = Authorization::basic("username", "password"); + + if let Ok(_provider) = Provider::::connect_with_auth(url, auth).await { + println!("Create Ws provider with auth"); + } + + Ok(()) +} +``` + +## Usage +TODO: Examples of syncing to new blocks, filter logs. From d6771949e36dd4696298f8f3c5af31ae533297c5 Mon Sep 17 00:00:00 2001 From: 0xKitsune <0xKitsune@protonmail.com> Date: Tue, 10 Jan 2023 01:26:01 -0500 Subject: [PATCH 03/12] updated ipc section, added code snippets --- book/providers/ipc.md | 58 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 58 insertions(+) diff --git a/book/providers/ipc.md b/book/providers/ipc.md index f53d9bd6e..3b2d60aed 100644 --- a/book/providers/ipc.md +++ b/book/providers/ipc.md @@ -22,3 +22,61 @@ async fn main() -> eyre::Result<()> { ``` ## Usage +The `Ipc` provider has the same methods as the `Ws` provider, allowing it to subscribe and unsubscribe via a `NotificationStream`. + + +```rust +use ethers::providers::{Middleware, Provider, StreamExt, Ws}; + +#[tokio::main] +async fn main() -> eyre::Result<()> { + let provider = Provider::connect_ipc("~/.ethereum/geth.ipc") + .await? + .interval(std::time::Duration::from_millis(2000)); + + //Create a new stream yielding pending transactions from the mempool + let mut tx_pool_stream = provider.subscribe_pending_txs().await?; + + while let Some(tx_hash) = tx_pool_stream.next().await { + println!("Pending tx: {:?}", tx_hash); + } + + Ok(()) +} +``` + + +Note that the `Ipc` provider, like all providers, has access to the methods defined by the `Middleware` trait. With this in mind, we can use the `Ipc` provider just like the `Http` provider as well, with the only difference being that we are connected to the node via a Unix socket now! + + +```rust +use std::{str::FromStr, sync::Arc}; + +use ethers::{ + prelude::abigen, + providers::{Http, Provider}, + types::H160, +}; + +abigen!( + IUniswapV2Pair, + r#"[function getReserves() external view returns (uint112 reserve0, uint112 reserve1, uint32 blockTimestampLast)]"# +); + +#[tokio::main] +async fn main() -> eyre::Result<()> { + let provider = Provider::connect_ipc("~/.ethereum/geth.ipc") + .await? + .interval(std::time::Duration::from_millis(2000)); + + //Initialize a new instance of the Weth/Dai Uniswap V2 pair contract + let pair_address = H160::from_str("0xA478c2975Ab1Ea89e8196811F51A7B7Ade33eB11").unwrap(); + let uniswap_v2_pair = IUniswapV2Pair::new(pair_address, provider); + + //Use the get_reserves() function to fetch the pool reserves + let (reserve_0, reserve_1, block_timestamp_last) = + uniswap_v2_pair.get_reserves().call().await?; + + Ok(()) +} +``` From 592706acedd386d90f6a28c08701e33601cde2f4 Mon Sep 17 00:00:00 2001 From: 0xKitsune <0xKitsune@protonmail.com> Date: Tue, 10 Jan 2023 01:29:25 -0500 Subject: [PATCH 04/12] updating the ws section, adding code snippet for example using the subscribe_pending_tx method --- book/providers/ws.md | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/book/providers/ws.md b/book/providers/ws.md index 59a8aa6f2..3d2a11d13 100644 --- a/book/providers/ws.md +++ b/book/providers/ws.md @@ -53,4 +53,22 @@ async fn main() -> eyre::Result<()> { ``` ## Usage -TODO: Examples of syncing to new blocks, filter logs. +TODO: Examples of syncing to new blocks, filter logs. Mention that the WS client implements the `PubSubClient` trait which gives access to the subscribe and unsubscribe methods. + +```rust +use ethers::providers::{Middleware, Provider, StreamExt, Ws}; + +#[tokio::main] +async fn main() -> eyre::Result<()> { + let ws_endpoint = ""; + let provider = Provider::::connect(ws_endpoint).await?; + //Create a new stream yielding pending transactions from the mempool + let mut tx_pool_stream = provider.subscribe_pending_txs().await?; + + while let Some(tx_hash) = tx_pool_stream.next().await { + println!("Pending tx: {:?}", tx_hash); + } + + Ok(()) +} +``` \ No newline at end of file From 747f8d9d246a11e34057e03741f114e3b15f25e4 Mon Sep 17 00:00:00 2001 From: 0xKitsune <0xKitsune@protonmail.com> Date: Mon, 16 Jan 2023 12:11:47 -0500 Subject: [PATCH 05/12] Updated the provider section to include info on the ens and _node_client fields, udpated the advanced usage section to include CallBuilder and raw_call. --- book/providers/advanced_usage.md | 115 ++++++++++++++++++++++++++++++- book/providers/providers.md | 3 +- 2 files changed, 114 insertions(+), 4 deletions(-) diff --git a/book/providers/advanced_usage.md b/book/providers/advanced_usage.md index dfba6e7d9..9f1436c78 100644 --- a/book/providers/advanced_usage.md +++ b/book/providers/advanced_usage.md @@ -1,5 +1,116 @@ # Advanced Usage -### `CallBuilder` -Todo: Mention how to use [state override set](https://geth.ethereum.org/docs/interacting-with-geth/rpc/ns-eth#3-object---state-override-set) \ No newline at end of file +## `CallBuilder` + +The `CallBuilder` is an enum to help create complex calls. `CallBuilder` implements `[RawCall](https://docs.rs/ethers/latest/ethers/providers/call_raw/trait.RawCall.html)` methods for overriding parameters to the `eth_call`rpc method. + +Lets take a quick look at how to use the `CallBuilder`. + +```rust +use ethers::{ + providers::{ Http, Provider}, + types::{TransactionRequest, H160}, + utils::parse_ether, +}; +use std::sync::Arc; + +#[tokio::main] +async fn main() -> eyre::Result<()> { + let rpc_url = "https://mainnet.infura.io/v3/c60b0bb42f8a4c6481ecd229eddaca27"; + let provider: Arc> = Arc::new(Provider::::try_from(rpc_url).unwrap()); + + let from_adr: H160 = "0x6fC21092DA55B392b045eD78F4732bff3C580e2c".parse()?; + let to_adr: H160 = "0x000000000000000000000000000000000000dead".parse()?; + let val = parse_ether(1u64)?; + + let tx = TransactionRequest::default() + .from(from_adr) + .to(to_adr) + .value(val) + .into(); + + let result = provider.call_raw(&tx).await?; + + Ok(()) +} + +``` + +First, we initialize a new provider and create a transaction that sends `1 ETH` from one address to another. Then we use `provider.call_raw()`, which returns a `CallBuilder`. From here, we can use `await` to send the call to the node with exactly the same behavior as simply using `provider.call()`. We can also override the parameters sent to the node by using the methods provided by the `RawCall` trait. These methods allow you to set the block number that the call should execute on as well as give you access to the [state override set](https://geth.ethereum.org/docs/interacting-with-geth/rpc/ns-eth#3-object---state-override-set). + +Here is an example with the exact same raw call, but executed on the previous block. + +```rust +use ethers::{ + providers::{call_raw::RawCall, Http, Middleware, Provider}, + types::{BlockId, TransactionRequest, H160}, + utils::parse_ether, +}; +use std::sync::Arc; + +#[tokio::main] +async fn main() -> eyre::Result<()> { + let rpc_url = "https://mainnet.infura.io/v3/c60b0bb42f8a4c6481ecd229eddaca27"; + let provider: Arc> = Arc::new(Provider::::try_from(rpc_url).unwrap()); + + let from_adr: H160 = "0x6fC21092DA55B392b045eD78F4732bff3C580e2c".parse()?; + let to_adr: H160 = "0x000000000000000000000000000000000000dead".parse()?; + let val = parse_ether(1u64)?; + + let tx = TransactionRequest::default() + .from(from_adr) + .to(to_adr) + .value(val) + .into(); + + let previous_block_number: BlockId = (provider.get_block_number().await? - 1).into(); + let result = provider.call_raw(&tx).block(previous_block_number).await?; + + Ok(()) +} +``` + +Let's look at how to use the state override set. In short, the state override set is an optional address-to-state mapping, where each entry specifies some state to be ephemerally overridden prior to executing the call. The state override set allows you to override an account's balance, an account's nonce, the code at a given address, the entire state of an account's storage or an individual slot in an account's storage. Note that the state override set is not a default feature and is not available on every node. + + +```rust +use ethers::{ + providers::{ + call_raw::{spoof::State, RawCall}, + Http, Provider, + }, + types::{TransactionRequest, H160, U256, U64}, + utils::parse_ether, +}; +use std::sync::Arc; + +#[tokio::main] +async fn main() -> eyre::Result<()> { + let rpc_url = "https://mainnet.infura.io/v3/c60b0bb42f8a4c6481ecd229eddaca27"; + let provider: Arc> = Arc::new(Provider::::try_from(rpc_url).unwrap()); + + let from_adr: H160 = "0x6fC21092DA55B392b045eD78F4732bff3C580e2c".parse()?; + let to_adr: H160 = "0x000000000000000000000000000000000000dead".parse()?; + let val = parse_ether(1u64)?; + + let tx = TransactionRequest::default() + .from(from_adr) + .to(to_adr) + .value(val) + .into(); + + let mut state = State::default(); + + //Set the account balance to max u256 + state.account(from_adr).balance(U256::MAX); + //Set the nonce to 0 + state.account(from_adr).nonce(U64::zero()); + + let result = provider.call_raw(&tx).state(&state).await?; + + Ok(()) +} +``` + +In this example, the account balance and nonce for the `from_adr` is overridden. The state override set is a very powerful tool that you can use to simulate complicated transactions without undergoing any actual state changes. \ No newline at end of file diff --git a/book/providers/providers.md b/book/providers/providers.md index d18f1c548..c5077cb68 100644 --- a/book/providers/providers.md +++ b/book/providers/providers.md @@ -20,8 +20,7 @@ pub struct Provider

{ ``` - -The `Provider` struct defines a generic type `P` that can be any type that implements the [`JsonRpcClient` trait](https://docs.rs/ethers/latest/ethers/providers/trait.JsonRpcClient.html). The `inner` field stores the type that implements the `JsonRpcClient` type, allowing the Provider to make RPC calls to the node. The `ens` field is an optional value that xyz. The `interval` field is an optional value that defines the polling interval when for streams (subscribing to logs, block headers, etc.). The `from` field is an optional type that allows you to set a default "from" address when constructing transactions and making calls. Lastly, the `_node_client` field is xyz. +The `Provider` struct defines a generic type `P` that can be any type that implements the [`JsonRpcClient` trait](https://docs.rs/ethers/latest/ethers/providers/trait.JsonRpcClient.html). The `inner` field stores the type that implements the `JsonRpcClient` type, allowing the Provider to make RPC calls to the node. The `ens` field is an optional value that specifies the ENS address for the provider's default sender. The `interval` field is an optional value that defines the polling interval when for streams (subscribing to logs, block headers, etc.). The `from` field is an optional type that allows you to set a default "from" address when constructing transactions and making calls. Lastly, the `_node_client` field is another optional value that allows the user to specify the node they are using to access node specific API calls. Note that all providers implement the [`Middleware` trait](https://docs.rs/ethers/latest/ethers/providers/trait.Middleware.html), which gives every provider access to [commonly used methods](https://docs.rs/ethers/latest/ethers/providers/struct.Provider.html#impl-Middleware-for-Provider%3CP%3E) to interact with the node. Later in this chapter, we will go over these methods and examples for how to use them in detail. Additionally, `Middleware` will be covered extensively in a later chapter. From d29a9bc39cc9e3ffd0436feb1c0d1c9230ed2d69 Mon Sep 17 00:00:00 2001 From: 0xKitsune <0xKitsune@protonmail.com> Date: Mon, 16 Jan 2023 12:34:54 -0500 Subject: [PATCH 06/12] added examples to ipc and ws chapters, cleared todos --- book/providers/ipc.md | 2 +- book/providers/ws.md | 68 +++++++++++++++++++++++++------------------ 2 files changed, 40 insertions(+), 30 deletions(-) diff --git a/book/providers/ipc.md b/book/providers/ipc.md index 3b2d60aed..828f65532 100644 --- a/book/providers/ipc.md +++ b/book/providers/ipc.md @@ -1,5 +1,5 @@ # IPC provider -The IPC (Inter-Process Communication) transport is a way for a process to communicate with a running Ethereum client over a local Unix domain socket. If you are new to IPC, you can [follow this link to learn more](). Using the IPC transport allows the ethers library to send JSON-RPC requests to the Ethereum client and receive responses, without the need for a network connection or HTTP server. This can be useful for interacting with a local Ethereum node that is running on the same machine. Using Ipc [is faster than RPC](), however you will need to have a local node that you can connect to. +The IPC (Inter-Process Communication) transport is a way for a process to communicate with a running Ethereum client over a local Unix domain socket. If you are new to IPC, you can [follow this link to learn more](https://en.wikipedia.org/wiki/Inter-process_communication). Using the IPC transport allows the ethers library to send JSON-RPC requests to the Ethereum client and receive responses, without the need for a network connection or HTTP server. This can be useful for interacting with a local Ethereum node that is running on the same machine. Using Ipc [is faster than RPC](https://github.com/0xKitsune/geth-ipc-rpc-bench), however you will need to have a local node that you can connect to. ## Initializing an Ipc Provider diff --git a/book/providers/ws.md b/book/providers/ws.md index 3d2a11d13..a85a73c26 100644 --- a/book/providers/ws.md +++ b/book/providers/ws.md @@ -4,7 +4,7 @@ The Ws provider allows you to send JSON-RPC requests and receive responses over ## Initializing a WS Provider -Lets look at a few ways to create a new `WS` provider. +Lets look at a few ways to create a new `WS` provider. Below is the most straightforward way to initialize a new `Ws` provider. ```rust @@ -16,10 +16,8 @@ async fn main() -> eyre::Result<()> { } ``` -TODO: note on setting the polling interval +Similar to the other providers, you can also establish an authorized connection with a node via websockets. - -TODO: note on initializing a new ws provider with authorization like the http provider ```rust #[tokio::main] async fn main() -> eyre::Result<()> { @@ -34,39 +32,51 @@ async fn main() -> eyre::Result<()> { } ``` +## Usage +The `Ws` provider allows a user to send requests to the node just like the other providers. In addition to these methods, the `Ws` provider can also subscribe to new logs and events, watch transactions in the mempool and other types of data streams from the node. The default polling interval for the `Ws` provider is `7 seconds`. You can update the polling interval, by using the `provider.interval()` method. -TODO: snippet of creating a new ws provider with a custom WS. Initializes a new WebSocket Client, given a Stream/Sink Websocket implementer. The websocket connection must be initiated separately. - -```rust -#[tokio::main] -async fn main() -> eyre::Result<()> { - let ws_endpoint = ""; - let auth = Authorization::basic("username", "password"); - - if let Ok(_provider) = Provider::::connect_with_auth(url, auth).await { - println!("Create Ws provider with auth"); - } - - Ok(()) -} -``` - -## Usage -TODO: Examples of syncing to new blocks, filter logs. Mention that the WS client implements the `PubSubClient` trait which gives access to the subscribe and unsubscribe methods. +In the snippet below, a new `Ws` provider is used to watch pending transactions in the mempool as well as new block headers in two separate threads. ```rust use ethers::providers::{Middleware, Provider, StreamExt, Ws}; - +use std::{sync::Arc, time::Duration}; #[tokio::main] async fn main() -> eyre::Result<()> { let ws_endpoint = ""; - let provider = Provider::::connect(ws_endpoint).await?; - //Create a new stream yielding pending transactions from the mempool - let mut tx_pool_stream = provider.subscribe_pending_txs().await?; - - while let Some(tx_hash) = tx_pool_stream.next().await { - println!("Pending tx: {:?}", tx_hash); + let mut provider = Provider::::connect(ws_endpoint).await?; + + //Update the polling interval + provider.set_interval(Duration::new(3, 0)); + + //Clone the providers to use in separate threads + let provider = Arc::new(provider); + let provider_0 = provider.clone(); + let provider_1 = provider.clone(); + + let mut handles = vec![]; + + let pending_tx_handle = tokio::spawn(async move { + let mut tx_pool_stream = provider_0.watch_pending_transactions().await.unwrap(); + while let Some(tx_hash) = tx_pool_stream.next().await { + println!("Pending tx: {:?}", tx_hash); + } + }); + + let new_block_headers_handle = tokio::spawn(async move { + let mut new_block_headers_stream = provider_1.watch_blocks().await.unwrap(); + while let Some(block_hash) = new_block_headers_stream.next().await { + println!("New block: {:?}", block_hash); + } + }); + + //Add the JoinHandles to a vec and wait for the handles to complete + handles.push(pending_tx_handle); + handles.push(new_block_headers_handle); + for handle in handles { + if let Err(err) = handle.await { + panic!("{}", err); + } } Ok(()) From e9abb6f3c8b102419f16ac2e24f06d7deea7d7e1 Mon Sep 17 00:00:00 2001 From: 0xKitsune <0xKitsune@protonmail.com> Date: Mon, 16 Jan 2023 16:04:53 -0500 Subject: [PATCH 07/12] added note about windows ipc named pipes --- book/providers/ipc.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/book/providers/ipc.md b/book/providers/ipc.md index 828f65532..fb57f2fdf 100644 --- a/book/providers/ipc.md +++ b/book/providers/ipc.md @@ -2,6 +2,7 @@ The IPC (Inter-Process Communication) transport is a way for a process to communicate with a running Ethereum client over a local Unix domain socket. If you are new to IPC, you can [follow this link to learn more](https://en.wikipedia.org/wiki/Inter-process_communication). Using the IPC transport allows the ethers library to send JSON-RPC requests to the Ethereum client and receive responses, without the need for a network connection or HTTP server. This can be useful for interacting with a local Ethereum node that is running on the same machine. Using Ipc [is faster than RPC](https://github.com/0xKitsune/geth-ipc-rpc-bench), however you will need to have a local node that you can connect to. ## Initializing an Ipc Provider +Below is an example of how to initialize a new Ipc provider. ```rust #[tokio::main] @@ -20,6 +21,9 @@ async fn main() -> eyre::Result<()> { Ok(()) } ``` + +Note that if you are using Windows, you must use [Windows Ipc (Named pipes)](https://learn.microsoft.com/en-us/windows/win32/ipc/named-pipes). Instead of passing the provider the path to the `.ipc` file, you must pass a named pipe (`\\\pipe\`). For a local geth connection, the named pipe will look something like this: `\\.\pipe\geth` + ## Usage The `Ipc` provider has the same methods as the `Ws` provider, allowing it to subscribe and unsubscribe via a `NotificationStream`. From 0e330788db61edb3a53de28a916b8063f9a6b670 Mon Sep 17 00:00:00 2001 From: 0xKitsune <0xKitsune@protonmail.com> Date: Mon, 16 Jan 2023 20:21:31 -0500 Subject: [PATCH 08/12] added spaces to comments --- book/providers/advanced_usage.md | 4 ++-- book/providers/http.md | 10 +++++----- book/providers/ipc.md | 6 +++--- book/providers/ws.md | 6 +++--- 4 files changed, 13 insertions(+), 13 deletions(-) diff --git a/book/providers/advanced_usage.md b/book/providers/advanced_usage.md index 9f1436c78..6a64e6a03 100644 --- a/book/providers/advanced_usage.md +++ b/book/providers/advanced_usage.md @@ -102,9 +102,9 @@ async fn main() -> eyre::Result<()> { let mut state = State::default(); - //Set the account balance to max u256 + // Set the account balance to max u256 state.account(from_adr).balance(U256::MAX); - //Set the nonce to 0 + // Set the nonce to 0 state.account(from_adr).nonce(U64::zero()); let result = provider.call_raw(&tx).state(&state).await?; diff --git a/book/providers/http.md b/book/providers/http.md index dc4dd0979..0f303eaf2 100644 --- a/book/providers/http.md +++ b/book/providers/http.md @@ -88,11 +88,11 @@ async fn main() -> eyre::Result<()> { let rpc_url = "https://mainnet.infura.io/v3/c60b0bb42f8a4c6481ecd229eddaca27"; let provider: Arc> = Arc::new(Provider::::try_from(rpc_url).unwrap()); - //Initialize a new instance of the Weth/Dai Uniswap V2 pair contract + // Initialize a new instance of the Weth/Dai Uniswap V2 pair contract let pair_address = H160::from_str("0xA478c2975Ab1Ea89e8196811F51A7B7Ade33eB11").unwrap(); let uniswap_v2_pair = IUniswapV2Pair::new(pair_address, provider); - //Use the get_reserves() function to fetch the pool reserves + // Use the get_reserves() function to fetch the pool reserves let (reserve_0, reserve_1, block_timestamp_last) = uniswap_v2_pair.get_reserves().call().await?; @@ -117,15 +117,15 @@ async fn main() -> eyre::Result<()> { let current_block_number = provider.get_block_number().await?; let prev_block_number = current_block_number - 1; - //Clone the Arc and pass it into a new thread to get the uncle count of the current block + // Clone the Arc and pass it into a new thread to get the uncle count of the current block let provider_1 = provider.clone(); let task_0 = tokio::spawn(async move { provider_1.get_uncle_count(current_block_number).await }); - //Spin up a new thread to get the uncle count of the previous block + // Spin up a new thread to get the uncle count of the previous block let task_1 = tokio::spawn(async move { provider.get_uncle_count(prev_block_number).await }); - //Wait for the tasks to finish + // Wait for the tasks to finish for task in [task_0, task_1] { if let Ok(uncle_count) = task.await? { println!("Success!"); diff --git a/book/providers/ipc.md b/book/providers/ipc.md index fb57f2fdf..5f55dc433 100644 --- a/book/providers/ipc.md +++ b/book/providers/ipc.md @@ -38,7 +38,7 @@ async fn main() -> eyre::Result<()> { .await? .interval(std::time::Duration::from_millis(2000)); - //Create a new stream yielding pending transactions from the mempool + // Create a new stream yielding pending transactions from the mempool let mut tx_pool_stream = provider.subscribe_pending_txs().await?; while let Some(tx_hash) = tx_pool_stream.next().await { @@ -73,11 +73,11 @@ async fn main() -> eyre::Result<()> { .await? .interval(std::time::Duration::from_millis(2000)); - //Initialize a new instance of the Weth/Dai Uniswap V2 pair contract + // Initialize a new instance of the Weth/Dai Uniswap V2 pair contract let pair_address = H160::from_str("0xA478c2975Ab1Ea89e8196811F51A7B7Ade33eB11").unwrap(); let uniswap_v2_pair = IUniswapV2Pair::new(pair_address, provider); - //Use the get_reserves() function to fetch the pool reserves + // Use the get_reserves() function to fetch the pool reserves let (reserve_0, reserve_1, block_timestamp_last) = uniswap_v2_pair.get_reserves().call().await?; diff --git a/book/providers/ws.md b/book/providers/ws.md index a85a73c26..c624811ce 100644 --- a/book/providers/ws.md +++ b/book/providers/ws.md @@ -46,10 +46,10 @@ async fn main() -> eyre::Result<()> { let ws_endpoint = ""; let mut provider = Provider::::connect(ws_endpoint).await?; - //Update the polling interval + // Update the polling interval provider.set_interval(Duration::new(3, 0)); - //Clone the providers to use in separate threads + // Clone the providers to use in separate threads let provider = Arc::new(provider); let provider_0 = provider.clone(); let provider_1 = provider.clone(); @@ -70,7 +70,7 @@ async fn main() -> eyre::Result<()> { } }); - //Add the JoinHandles to a vec and wait for the handles to complete + // Add the JoinHandles to a vec and wait for the handles to complete handles.push(pending_tx_handle); handles.push(new_block_headers_handle); for handle in handles { From 46929bd9f3420ceb5cee7a79ea571933f87fa6b0 Mon Sep 17 00:00:00 2001 From: 0xKitsune <0xKitsune@protonmail.com> Date: Mon, 16 Jan 2023 21:13:38 -0500 Subject: [PATCH 09/12] fixed comment, removed all usage of unwrap() --- book/providers/advanced_usage.md | 6 +++--- book/providers/http.md | 16 ++++++++-------- book/providers/ipc.md | 2 +- book/providers/ws.md | 4 ++-- 4 files changed, 14 insertions(+), 14 deletions(-) diff --git a/book/providers/advanced_usage.md b/book/providers/advanced_usage.md index 6a64e6a03..d777dbcd0 100644 --- a/book/providers/advanced_usage.md +++ b/book/providers/advanced_usage.md @@ -18,7 +18,7 @@ use std::sync::Arc; #[tokio::main] async fn main() -> eyre::Result<()> { let rpc_url = "https://mainnet.infura.io/v3/c60b0bb42f8a4c6481ecd229eddaca27"; - let provider: Arc> = Arc::new(Provider::::try_from(rpc_url).unwrap()); + let provider: Arc> = Arc::new(Provider::::try_from(rpc_url)?); let from_adr: H160 = "0x6fC21092DA55B392b045eD78F4732bff3C580e2c".parse()?; let to_adr: H160 = "0x000000000000000000000000000000000000dead".parse()?; @@ -52,7 +52,7 @@ use std::sync::Arc; #[tokio::main] async fn main() -> eyre::Result<()> { let rpc_url = "https://mainnet.infura.io/v3/c60b0bb42f8a4c6481ecd229eddaca27"; - let provider: Arc> = Arc::new(Provider::::try_from(rpc_url).unwrap()); + let provider: Arc> = Arc::new(Provider::::try_from(rpc_url)?); let from_adr: H160 = "0x6fC21092DA55B392b045eD78F4732bff3C580e2c".parse()?; let to_adr: H160 = "0x000000000000000000000000000000000000dead".parse()?; @@ -88,7 +88,7 @@ use std::sync::Arc; #[tokio::main] async fn main() -> eyre::Result<()> { let rpc_url = "https://mainnet.infura.io/v3/c60b0bb42f8a4c6481ecd229eddaca27"; - let provider: Arc> = Arc::new(Provider::::try_from(rpc_url).unwrap()); + let provider: Arc> = Arc::new(Provider::::try_from(rpc_url)?); let from_adr: H160 = "0x6fC21092DA55B392b045eD78F4732bff3C580e2c".parse()?; let to_adr: H160 = "0x000000000000000000000000000000000000dead".parse()?; diff --git a/book/providers/http.md b/book/providers/http.md index 0f303eaf2..bfacbc1b2 100644 --- a/book/providers/http.md +++ b/book/providers/http.md @@ -10,9 +10,9 @@ use ethers::providers::{Http, Middleware, Provider}; #[tokio::main] async fn main() -> eyre::Result<()> { - //Initialize a new Http provider + // Initialize a new Http provider let rpc_url = "https://mainnet.infura.io/v3/c60b0bb42f8a4c6481ecd229eddaca27"; - let provider: Provider = Provider::::from_str(rpc_url)?; + let provider = Provider::try_from(rpc_url)?; Ok(()) } @@ -26,7 +26,7 @@ use ethers::providers::{Authorization, Http}; use url::Url; #[tokio::main] async fn main() -> eyre::Result<()> { - let url = Url::parse("http://localhost:8545").unwrap(); + let url = Url::parse("http://localhost:8545")?; let provider = Http::new_with_auth(url, Authorization::basic("admin", "good_password")); Ok(()) } @@ -40,8 +40,8 @@ use url::Url; #[tokio::main] async fn main() -> eyre::Result<()> { - let url = Url::parse("http://localhost:8545").unwrap(); - let client = reqwest::Client::builder().build().unwrap(); + let url = Url::parse("http://localhost:8545")?; + let client = reqwest::Client::builder().build()?; let provider = Http::new_with_client(url, client); Ok(()) } @@ -86,10 +86,10 @@ abigen!( #[tokio::main] async fn main() -> eyre::Result<()> { let rpc_url = "https://mainnet.infura.io/v3/c60b0bb42f8a4c6481ecd229eddaca27"; - let provider: Arc> = Arc::new(Provider::::try_from(rpc_url).unwrap()); + let provider: Arc> = Arc::new(Provider::::try_from(rpc_url)?); // Initialize a new instance of the Weth/Dai Uniswap V2 pair contract - let pair_address = H160::from_str("0xA478c2975Ab1Ea89e8196811F51A7B7Ade33eB11").unwrap(); + let pair_address = H160::from_str("0xA478c2975Ab1Ea89e8196811F51A7B7Ade33eB11")?; let uniswap_v2_pair = IUniswapV2Pair::new(pair_address, provider); // Use the get_reserves() function to fetch the pool reserves @@ -112,7 +112,7 @@ use ethers::providers::{Http, Middleware, Provider}; #[tokio::main] async fn main() -> eyre::Result<()> { let rpc_url = "https://mainnet.infura.io/v3/c60b0bb42f8a4c6481ecd229eddaca27"; - let provider: Arc> = Arc::new(Provider::::try_from(rpc_url).unwrap()); + let provider: Arc> = Arc::new(Provider::::try_from(rpc_url)?); let current_block_number = provider.get_block_number().await?; let prev_block_number = current_block_number - 1; diff --git a/book/providers/ipc.md b/book/providers/ipc.md index 5f55dc433..e05593b77 100644 --- a/book/providers/ipc.md +++ b/book/providers/ipc.md @@ -74,7 +74,7 @@ async fn main() -> eyre::Result<()> { .interval(std::time::Duration::from_millis(2000)); // Initialize a new instance of the Weth/Dai Uniswap V2 pair contract - let pair_address = H160::from_str("0xA478c2975Ab1Ea89e8196811F51A7B7Ade33eB11").unwrap(); + let pair_address = H160::from_str("0xA478c2975Ab1Ea89e8196811F51A7B7Ade33eB11")?; let uniswap_v2_pair = IUniswapV2Pair::new(pair_address, provider); // Use the get_reserves() function to fetch the pool reserves diff --git a/book/providers/ws.md b/book/providers/ws.md index c624811ce..261485c8b 100644 --- a/book/providers/ws.md +++ b/book/providers/ws.md @@ -57,14 +57,14 @@ async fn main() -> eyre::Result<()> { let mut handles = vec![]; let pending_tx_handle = tokio::spawn(async move { - let mut tx_pool_stream = provider_0.watch_pending_transactions().await.unwrap(); + let mut tx_pool_stream = provider_0.watch_pending_transactions().await?; while let Some(tx_hash) = tx_pool_stream.next().await { println!("Pending tx: {:?}", tx_hash); } }); let new_block_headers_handle = tokio::spawn(async move { - let mut new_block_headers_stream = provider_1.watch_blocks().await.unwrap(); + let mut new_block_headers_stream = provider_1.watch_blocks().await?; while let Some(block_hash) = new_block_headers_stream.next().await { println!("New block: {:?}", block_hash); } From dcdc022ab7c895ea6681edd28023a4b8c0a69a18 Mon Sep 17 00:00:00 2001 From: 0xKitsune <0xKitsune@protonmail.com> Date: Mon, 16 Jan 2023 21:16:43 -0500 Subject: [PATCH 10/12] updated Http provider to initialize without :: eyre::Result<()> { let rpc_url = "https://mainnet.infura.io/v3/c60b0bb42f8a4c6481ecd229eddaca27"; - let provider: Provider = Provider::::from_str(rpc_url)?; + let provider = Provider::try_from(rpc_url)?; let chain_id = provider.get_chainid().await?; let block_number = provider.get_block_number().await?; @@ -86,7 +86,7 @@ abigen!( #[tokio::main] async fn main() -> eyre::Result<()> { let rpc_url = "https://mainnet.infura.io/v3/c60b0bb42f8a4c6481ecd229eddaca27"; - let provider: Arc> = Arc::new(Provider::::try_from(rpc_url)?); + let provider = Arc::new(Provider::try_from(rpc_url)?); // Initialize a new instance of the Weth/Dai Uniswap V2 pair contract let pair_address = H160::from_str("0xA478c2975Ab1Ea89e8196811F51A7B7Ade33eB11")?; @@ -112,7 +112,7 @@ use ethers::providers::{Http, Middleware, Provider}; #[tokio::main] async fn main() -> eyre::Result<()> { let rpc_url = "https://mainnet.infura.io/v3/c60b0bb42f8a4c6481ecd229eddaca27"; - let provider: Arc> = Arc::new(Provider::::try_from(rpc_url)?); + let provider = Arc::new(Provider::try_from(rpc_url)?); let current_block_number = provider.get_block_number().await?; let prev_block_number = current_block_number - 1; From 3b32a605e2835a610c7c8894f07fad8c30cb57a8 Mon Sep 17 00:00:00 2001 From: 0xKitsune <0xKitsune@protonmail.com> Date: Mon, 16 Jan 2023 21:18:36 -0500 Subject: [PATCH 11/12] updated the Ipc provider to initialize without setting the polling interval --- book/providers/ipc.md | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/book/providers/ipc.md b/book/providers/ipc.md index e05593b77..f4abb3235 100644 --- a/book/providers/ipc.md +++ b/book/providers/ipc.md @@ -14,9 +14,7 @@ async fn main() -> eyre::Result<()> { // interval because only subscribe RPC calls (e.g., transactions, blocks, events) support push // notifications in Ethereum's RPC API. For other calls we must use repeated polling for many // operations even with the IPC transport. - let provider = Provider::connect_ipc("~/.ethereum/geth.ipc") - .await? - .interval(std::time::Duration::from_millis(2000)); + let provider = Provider::connect_ipc("~/.ethereum/geth.ipc").await?; Ok(()) } @@ -34,9 +32,7 @@ use ethers::providers::{Middleware, Provider, StreamExt, Ws}; #[tokio::main] async fn main() -> eyre::Result<()> { - let provider = Provider::connect_ipc("~/.ethereum/geth.ipc") - .await? - .interval(std::time::Duration::from_millis(2000)); + let provider = Provider::connect_ipc("~/.ethereum/geth.ipc").await?; // Create a new stream yielding pending transactions from the mempool let mut tx_pool_stream = provider.subscribe_pending_txs().await?; @@ -69,9 +65,7 @@ abigen!( #[tokio::main] async fn main() -> eyre::Result<()> { - let provider = Provider::connect_ipc("~/.ethereum/geth.ipc") - .await? - .interval(std::time::Duration::from_millis(2000)); + let provider = Provider::connect_ipc("~/.ethereum/geth.ipc").await?; // Initialize a new instance of the Weth/Dai Uniswap V2 pair contract let pair_address = H160::from_str("0xA478c2975Ab1Ea89e8196811F51A7B7Ade33eB11")?; From c0839022d0da87d1eda138343412a5ca993e7396 Mon Sep 17 00:00:00 2001 From: Georgios Konstantopoulos Date: Tue, 17 Jan 2023 11:19:01 -0800 Subject: [PATCH 12/12] Update book/providers/providers.md --- book/providers/providers.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/book/providers/providers.md b/book/providers/providers.md index c5077cb68..fa81fc04a 100644 --- a/book/providers/providers.md +++ b/book/providers/providers.md @@ -2,7 +2,7 @@ Providers play a central role in `ethers-rs`, enabling you to establish asynchronous [Ethereum JSON-RPC](https://github.com/ethereum/wiki/wiki/JSON-RPC) compliant clients. - your program to a node to get data, interact with smart contracts, listen to the mempool and much more. There are a few different types of default providers that are built into the library. The default providers are `Http`,`WS`,`Ipc`,`RWClient`,`Quorum`,`Mock` and `RetryClient`. In addition to all of these options, you can also create your own custom provider, which we will walk through later in this chapter. For now let take a look at what the `Provider` actually looks like. +Providers let your program connect to a node to get data, interact with smart contracts, listen to the mempool and much more. There are a few different types of default providers that are built into the library. The default providers are `Http`,`WS`,`Ipc`,`RWClient`,`Quorum`,`Mock` and `RetryClient`. In addition to all of these options, you can also create your own custom provider, which we will walk through later in this chapter. For now let take a look at what the `Provider` actually looks like. ```rust