Docs: Middleware library (#1912)
* Updated the middleware README heading * fix docs CI * Added heading description for the main middlewares * Restructure README examples * Fix docs CI * Fix MiddlewareBuilder function docs * Typos inside the middleware README Co-authored-by: Andrea Simeoni <>
This commit is contained in:
parent
913f15dc84
commit
e5aa4518d7
|
@ -1,23 +1,71 @@
|
||||||
Ethers uses a middleware-based architecture. You start the middleware stack with
|
Your ethers application interacts with the blockchain through a [`Provider`](ethers_providers::Provider) abstraction. [`Provider`](ethers_providers::Provider) is a special type of [`Middleware`](ethers_providers::Middleware) that can be composed with others to obtain a layered architecture. This approach promotes "Open Closed Principle", "Single Responsibility" and composable patterns. The building process happens in a wrapping fashion, and starts from a [`Provider`](ethers_providers::Provider) being the first element in the stack. This process continues having new middlewares being pushed on top of a layered data structure.
|
||||||
a [`Provider`](ethers_providers::Provider), and wrap it with additional
|
|
||||||
middleware functionalities that you need.
|
|
||||||
|
|
||||||
## Available Middleware
|
## Available Middleware
|
||||||
|
|
||||||
- [`Signer`](./signer/struct.SignerMiddleware.html): Signs transactions locally,
|
- [`Signer`](./signer/struct.SignerMiddleware.html): Signs transactions locally, with a private key or a hardware wallet.
|
||||||
with a private key or a hardware wallet
|
- [`Nonce Manager`](./nonce_manager/struct.NonceManagerMiddleware.html): Manages nonces locally. Allows to sign multiple consecutive transactions without waiting for them to hit the mempool.
|
||||||
- [`Nonce Manager`](./nonce_manager/struct.NonceManagerMiddleware.html): Manages
|
- [`Gas Escalator`](./gas_escalator/struct.GasEscalatorMiddleware.html): Bumps transactions gas price in the background to avoid getting them stuck in the memory pool. A [`GasEscalatorMiddleware`](crate::gas_escalator::GasEscalatorMiddleware) supports different escalation strategies (see [GasEscalator](crate::gas_escalator::GasEscalator)) and bump frequencies (see [Frequency](crate::gas_escalator::Frequency)).
|
||||||
nonces locally, allowing the rapid broadcast of transactions without having to
|
|
||||||
wait for them to be submitted
|
|
||||||
- [`Gas Escalator`](./gas_escalator/struct.GasEscalatorMiddleware.html): Bumps
|
|
||||||
transaction gas prices in the background
|
|
||||||
- [`Gas Oracle`](./gas_oracle/struct.GasOracleMiddleware.html): Allows getting
|
- [`Gas Oracle`](./gas_oracle/struct.GasOracleMiddleware.html): Allows getting
|
||||||
your gas price estimates from places other than `eth_gasPrice`.
|
your gas price estimates from places other than `eth_gasPrice`, including REST based gas stations (i.e. Etherscan, ETH Gas Station etc.).
|
||||||
- [`Transformer`](./transformer/trait.Transformer.html): Allows intercepting and
|
- [`Transformer`](./transformer/trait.Transformer.html): Allows intercepting and
|
||||||
transforming a transaction to be broadcasted via a proxy wallet, e.g.
|
transforming a transaction to be broadcasted via a proxy wallet, e.g.
|
||||||
[`DSProxy`](./transformer/struct.DsProxy.html).
|
[`DSProxy`](./transformer/struct.DsProxy.html).
|
||||||
|
|
||||||
## Example of a middleware stack
|
## Stacking middlewares using a builder
|
||||||
|
|
||||||
|
Each [`Middleware`](ethers_providers::Middleware) implements the trait [MiddlewareBuilder](crate::MiddlewareBuilder). This trait helps a developer to compose a custom [`Middleware`](ethers_providers::Middleware) stack.
|
||||||
|
|
||||||
|
The following example shows how to build a composed [`Middleware`](ethers_providers::Middleware) starting from a [`Provider`](ethers_providers::Provider):
|
||||||
|
|
||||||
|
```rust
|
||||||
|
use ethers_providers::{Middleware, Provider, Http};
|
||||||
|
use std::sync::Arc;
|
||||||
|
use std::convert::TryFrom;
|
||||||
|
use ethers_signers::{LocalWallet, Signer};
|
||||||
|
use ethers_middleware::{*,gas_oracle::*};
|
||||||
|
|
||||||
|
fn builder_example() {
|
||||||
|
let key = "fdb33e2105f08abe41a8ee3b758726a31abdd57b7a443f470f23efce853af169";
|
||||||
|
let signer = key.parse::<LocalWallet>().unwrap();
|
||||||
|
let address = signer.address();
|
||||||
|
let gas_oracle = EthGasStation::new(None);
|
||||||
|
|
||||||
|
let provider = Provider::<Http>::try_from("http://localhost:8545")
|
||||||
|
.unwrap()
|
||||||
|
.gas_oracle(gas_oracle)
|
||||||
|
.with_signer(signer)
|
||||||
|
.nonce_manager(address); // Outermost layer
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
The [wrap_into](crate::MiddlewareBuilder::wrap_into) function can be used to wrap [`Middleware`](ethers_providers::Middleware) layers explicitly. This is useful when pushing [`Middleware`](ethers_providers::Middleware)s not directly handled by the builder interface.
|
||||||
|
|
||||||
|
```rust
|
||||||
|
use ethers_providers::{Middleware, Provider, Http};
|
||||||
|
use std::sync::Arc;
|
||||||
|
use std::convert::TryFrom;
|
||||||
|
use ethers_signers::{LocalWallet, Signer};
|
||||||
|
use ethers_middleware::{*,gas_escalator::*,gas_oracle::*};
|
||||||
|
|
||||||
|
fn builder_example_wrap_into() {
|
||||||
|
let key = "fdb33e2105f08abe41a8ee3b758726a31abdd57b7a443f470f23efce853af169";
|
||||||
|
let signer = key.parse::<LocalWallet>().unwrap();
|
||||||
|
let address = signer.address();
|
||||||
|
let escalator = GeometricGasPrice::new(1.125, 60_u64, None::<u64>);
|
||||||
|
|
||||||
|
let provider = Provider::<Http>::try_from("http://localhost:8545")
|
||||||
|
.unwrap()
|
||||||
|
.wrap_into(|p| GasEscalatorMiddleware::new(p, escalator, Frequency::PerBlock))
|
||||||
|
.wrap_into(|p| SignerMiddleware::new(p, signer))
|
||||||
|
.wrap_into(|p| GasOracleMiddleware::new(p, EthGasStation::new(None)))
|
||||||
|
.wrap_into(|p| NonceManagerMiddleware::new(p, address)); // Outermost layer
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
## Stacking middlewares manually
|
||||||
|
A [`Middleware`](ethers_providers::Middleware) stack can be also constructed manually. This is achieved by explicitly wrapping layers.
|
||||||
|
|
||||||
```rust no_run
|
```rust no_run
|
||||||
use ethers_providers::{Provider, Http};
|
use ethers_providers::{Provider, Http};
|
||||||
|
@ -36,8 +84,7 @@ let provider = Provider::<Http>::try_from("http://localhost:8545").unwrap();
|
||||||
|
|
||||||
// Escalate gas prices
|
// Escalate gas prices
|
||||||
let escalator = GeometricGasPrice::new(1.125, 60u64, None::<u64>);
|
let escalator = GeometricGasPrice::new(1.125, 60u64, None::<u64>);
|
||||||
let provider =
|
let provider = GasEscalatorMiddleware::new(provider, escalator, Frequency::PerBlock);
|
||||||
GasEscalatorMiddleware::new(provider, escalator, Frequency::PerBlock);
|
|
||||||
|
|
||||||
// Sign transactions with a private key
|
// Sign transactions with a private key
|
||||||
let signer = LocalWallet::new(&mut rand::thread_rng());
|
let signer = LocalWallet::new(&mut rand::thread_rng());
|
||||||
|
@ -53,43 +100,3 @@ let provider = NonceManagerMiddleware::new(provider, address);
|
||||||
|
|
||||||
// ... do something with the provider
|
// ... do something with the provider
|
||||||
```
|
```
|
||||||
## Example of a middleware stack using a builder
|
|
||||||
|
|
||||||
Each [`Middleware`](ethers_providers::Middleware) implements the trait [MiddlewareBuilder](crate::MiddlewareBuilder) to help composition of a [`Middleware`](ethers_providers::Middleware) stack. As usual the composition acts in a wrapping fashion. Adding a new layer results in wrapping its predecessor.
|
|
||||||
Builder can be used as follows:
|
|
||||||
```rust
|
|
||||||
use ethers_providers::{Middleware, Provider, Http};
|
|
||||||
use std::sync::Arc;
|
|
||||||
use std::convert::TryFrom;
|
|
||||||
use ethers_signers::{LocalWallet, Signer};
|
|
||||||
use ethers_middleware::{*,gas_escalator::*,gas_oracle::*};
|
|
||||||
|
|
||||||
fn builder_example() {
|
|
||||||
let key = "fdb33e2105f08abe41a8ee3b758726a31abdd57b7a443f470f23efce853af169";
|
|
||||||
let signer = key.parse::<LocalWallet>().unwrap();
|
|
||||||
let address = signer.address();
|
|
||||||
let escalator = GeometricGasPrice::new(1.125, 60_u64, None::<u64>);
|
|
||||||
let gas_oracle = EthGasStation::new(None);
|
|
||||||
|
|
||||||
let provider = Provider::<Http>::try_from("http://localhost:8545")
|
|
||||||
.unwrap()
|
|
||||||
.wrap_into(|p| GasEscalatorMiddleware::new(p, escalator, Frequency::PerBlock))
|
|
||||||
.gas_oracle(gas_oracle)
|
|
||||||
.with_signer(signer)
|
|
||||||
.nonce_manager(address); // Outermost layer
|
|
||||||
}
|
|
||||||
|
|
||||||
fn builder_example_raw_wrap() {
|
|
||||||
let key = "fdb33e2105f08abe41a8ee3b758726a31abdd57b7a443f470f23efce853af169";
|
|
||||||
let signer = key.parse::<LocalWallet>().unwrap();
|
|
||||||
let address = signer.address();
|
|
||||||
let escalator = GeometricGasPrice::new(1.125, 60_u64, None::<u64>);
|
|
||||||
|
|
||||||
let provider = Provider::<Http>::try_from("http://localhost:8545")
|
|
||||||
.unwrap()
|
|
||||||
.wrap_into(|p| GasEscalatorMiddleware::new(p, escalator, Frequency::PerBlock))
|
|
||||||
.wrap_into(|p| SignerMiddleware::new(p, signer))
|
|
||||||
.wrap_into(|p| GasOracleMiddleware::new(p, EthGasStation::new(None)))
|
|
||||||
.wrap_into(|p| NonceManagerMiddleware::new(p, address)); // Outermost layer
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
|
@ -50,8 +50,8 @@ use ethers_signers::Signer;
|
||||||
pub trait MiddlewareBuilder: Middleware + Sized + 'static {
|
pub trait MiddlewareBuilder: Middleware + Sized + 'static {
|
||||||
/// Wraps `self` inside a new [`Middleware`](ethers_providers::Middleware).
|
/// Wraps `self` inside a new [`Middleware`](ethers_providers::Middleware).
|
||||||
///
|
///
|
||||||
/// `f` Consumes `self`, must be used to return a new
|
/// `f` Consumes `self`. Must be used to return a new
|
||||||
/// [`Middleware`](ethers_providers::Middleware) around `self`.
|
/// [`Middleware`](ethers_providers::Middleware) wrapping `self`.
|
||||||
fn wrap_into<F, T>(self, f: F) -> T
|
fn wrap_into<F, T>(self, f: F) -> T
|
||||||
where
|
where
|
||||||
F: FnOnce(Self) -> T,
|
F: FnOnce(Self) -> T,
|
||||||
|
@ -62,7 +62,7 @@ pub trait MiddlewareBuilder: Middleware + Sized + 'static {
|
||||||
|
|
||||||
/// Wraps `self` inside a [`SignerMiddleware`](crate::SignerMiddleware).
|
/// Wraps `self` inside a [`SignerMiddleware`](crate::SignerMiddleware).
|
||||||
///
|
///
|
||||||
/// [`Signer`] ethers_signers::Signer
|
/// [`Signer`](ethers_signers::Signer)
|
||||||
fn with_signer<S>(self, s: S) -> SignerMiddleware<Self, S>
|
fn with_signer<S>(self, s: S) -> SignerMiddleware<Self, S>
|
||||||
where
|
where
|
||||||
S: Signer,
|
S: Signer,
|
||||||
|
@ -72,14 +72,14 @@ pub trait MiddlewareBuilder: Middleware + Sized + 'static {
|
||||||
|
|
||||||
/// Wraps `self` inside a [`NonceManagerMiddleware`](crate::NonceManagerMiddleware).
|
/// Wraps `self` inside a [`NonceManagerMiddleware`](crate::NonceManagerMiddleware).
|
||||||
///
|
///
|
||||||
/// [`Address`] ethers_core::types::Address
|
/// [`Address`](ethers_core::types::Address)
|
||||||
fn nonce_manager(self, address: Address) -> NonceManagerMiddleware<Self> {
|
fn nonce_manager(self, address: Address) -> NonceManagerMiddleware<Self> {
|
||||||
NonceManagerMiddleware::new(self, address)
|
NonceManagerMiddleware::new(self, address)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Wraps `self` inside a [`GasOracleMiddleware`](crate::gas_oracle::GasOracleMiddleware).
|
/// Wraps `self` inside a [`GasOracleMiddleware`](crate::gas_oracle::GasOracleMiddleware).
|
||||||
///
|
///
|
||||||
/// [`Address`] ethers_core::types::Address
|
/// [`GasOracle`](crate::gas_oracle::GasOracle)
|
||||||
fn gas_oracle<G>(self, gas_oracle: G) -> GasOracleMiddleware<Self, G>
|
fn gas_oracle<G>(self, gas_oracle: G) -> GasOracleMiddleware<Self, G>
|
||||||
where
|
where
|
||||||
G: GasOracle,
|
G: GasOracle,
|
||||||
|
|
Loading…
Reference in New Issue