ethers-rs/ethers-middleware
DaniPopes da743fc8b2
ci/test: improve CI jobs and tests (#2189)
* ci: move to scripts directory

* nits

* ci: improve main CI jobs

* fix: install script

* fix

* fix: use curl for windows installation

* fix: wasm typo

* tests: move to single binary

* chore: clippy

* chore: clippy

* chore: clippy

* fix: test command

* fix: quote tests

* update script

* fix: action exclude

* fix: dev deps

* fix: only run wasm in own job

* ci: add aarch64 targets

* test: rm useless test

* ci: update security audit

* ci: add deny CI

* chore: rm unused audit.toml

* chore: update geth.rs

* ci: remove unusable targets

* fix: install script path

* fix: wasm

* improve script

* fix: failing ci

* fix: contract tests

* ci: improve install script

* update middleware tests

* move integration etherscan tests to tests/ dir

* fix: eip2930 access_list field name

* add pendingtransaction must_use

* add random anvil comment

* ci: add miri job

* ci: simplify

* fixci

* Revert "add pendingtransaction must_use"

This reverts commit 770b21b4a3.

* fix: macos script

* fix: use curl in script

* unused ci

* update script

* fix wasm

* rm_miri

* fix: signer test

* fix: wasm ci

* fix: ipc test

* fix: live celo tests

* fix: abi online source test

* fix: windows paths in test

* chore: update serial_test

* ci: run live tests separately

* fix: provider tests

* fix: unused var

* fix: feature

* fix merge

* fix: etherscan key tests

* ci: rm duplicate audit

* fix: split etherscan test ci

* fix: etherscan test

* fix: generate multiple unused ports

* fix: source test

* fix: udeps

* rm unused
2023-02-28 17:26:27 -07:00
..
contracts ci/test: improve CI jobs and tests (#2189) 2023-02-28 17:26:27 -07:00
src ci/test: improve CI jobs and tests (#2189) 2023-02-28 17:26:27 -07:00
tests/it ci/test: improve CI jobs and tests (#2189) 2023-02-28 17:26:27 -07:00
Cargo.toml ci/test: improve CI jobs and tests (#2189) 2023-02-28 17:26:27 -07:00
README.md docs: fix broken links, update documentation (#2203) 2023-02-27 13:03:17 -07:00

README.md

ethers-middleware

Your ethers application interacts with the blockchain through a Provider abstraction. Provider is a special type of 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 being the first element in the stack. This process continues having new middlewares being pushed on top of a layered data structure.

For more information, please refer to the book.

Available Middleware

  • Signer: Signs transactions locally, with a private key or a hardware wallet.
  • Nonce Manager: Manages nonces locally. Allows to sign multiple consecutive transactions without waiting for them to hit the mempool.
  • Gas Escalator: Bumps transactions gas price in the background to avoid getting them stuck in the memory pool. A GasEscalatorMiddleware supports different escalation strategies (see GasEscalator) and bump frequencies (see Frequency).
  • Gas Oracle: Allows getting your gas price estimates from places other than eth_gasPrice, including REST based gas stations (i.e. Etherscan, ETH Gas Station etc.).
  • Transformer: Allows intercepting and transforming a transaction to be broadcasted via a proxy wallet, e.g. DSProxy.

Examples

Each Middleware implements the trait MiddlewareBuilder. This trait helps a developer to compose a custom Middleware stack.

The following example shows how to build a composed Middleware starting from a Provider:

# use ethers_providers::{Middleware, Provider, Http};
# use ethers_signers::{LocalWallet, Signer};
# use ethers_middleware::{gas_oracle::GasNow, MiddlewareBuilder};
let key = "fdb33e2105f08abe41a8ee3b758726a31abdd57b7a443f470f23efce853af169";
let signer = key.parse::<LocalWallet>()?;
let address = signer.address();
let gas_oracle = GasNow::new();

let provider = Provider::<Http>::try_from("http://localhost:8545")?
    .gas_oracle(gas_oracle)
    .with_signer(signer)
    .nonce_manager(address); // Outermost layer
# Ok::<_, Box<dyn std::error::Error>>(())

The wrap_into function can be used to wrap Middleware layers explicitly. This is useful when pushing Middlewares not directly handled by the builder interface.

# use ethers_providers::{Middleware, Provider, Http};
# use std::convert::TryFrom;
# use ethers_signers::{LocalWallet, Signer};
# use ethers_middleware::{*,gas_escalator::*,gas_oracle::*};
let key = "fdb33e2105f08abe41a8ee3b758726a31abdd57b7a443f470f23efce853af169";
let signer = key.parse::<LocalWallet>()?;
let address = signer.address();
let escalator = GeometricGasPrice::new(1.125, 60_u64, None::<u64>);

let provider = Provider::<Http>::try_from("http://localhost:8545")?
    .wrap_into(|p| GasEscalatorMiddleware::new(p, escalator, Frequency::PerBlock))
    .wrap_into(|p| SignerMiddleware::new(p, signer))
    .wrap_into(|p| GasOracleMiddleware::new(p, GasNow::new()))
    .wrap_into(|p| NonceManagerMiddleware::new(p, address)); // Outermost layer
# Ok::<_, Box<dyn std::error::Error>>(())

A Middleware stack can be also constructed manually. This is achieved by explicitly wrapping layers.

# use ethers_providers::{Provider, Http};
# use ethers_signers::{LocalWallet, Signer};
# use ethers_middleware::{
#     gas_escalator::{GasEscalatorMiddleware, GeometricGasPrice, Frequency},
#     gas_oracle::{GasOracleMiddleware, GasCategory, GasNow},
#     signer::SignerMiddleware,
#     nonce_manager::NonceManagerMiddleware,
# };
// Start the stack
let provider = Provider::<Http>::try_from("http://localhost:8545")?;

// Escalate gas prices
let escalator = GeometricGasPrice::new(1.125, 60u64, None::<u64>);
let provider = GasEscalatorMiddleware::new(provider, escalator, Frequency::PerBlock);

// Sign transactions with a private key
let key = "fdb33e2105f08abe41a8ee3b758726a31abdd57b7a443f470f23efce853af169";
let signer = key.parse::<LocalWallet>()?;
let address = signer.address();
let provider = SignerMiddleware::new(provider, signer);

// Use GasNow as the gas oracle
let gas_oracle = GasNow::new();
let provider = GasOracleMiddleware::new(provider, gas_oracle);

// Manage nonces locally
let provider = NonceManagerMiddleware::new(provider, address);
# Ok::<_, Box<dyn std::error::Error>>(())