Repository: gakonst/ethers-rs
Pull request #1979 (2022-12-27 20:00:22)

chore: update all rust editions to 2021
<!--
Thank you for your Pull Request. Please provide a description above and review
the requirements below.

Bug fixes and new features should include tests.

Contributors guide: https://github.com/gakonst/ethers-rs/blob/master/CONTRIBUTING.md

The contributors guide includes instructions for running rustfmt and building the
documentation.
-->

## Motivation

https://t.me/ethers_rs/23467

<!--
Explain the context and why you're making that change. What is the problem
you're trying to solve? In some cases there is not a problem and this can be
thought of as being the motivation for your change.
-->

## Solution

<!--
Summarize the solution and provide any necessary context needed to understand
the code change.
-->

## PR Checklist

-   [ ] Added Tests
-   [ ] Added Documentation
-   [ ] Updated the changelog
-   [ ] Breaking changes



Patch:
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index bcfaa4ba..16d62793 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -232,32 +232,7 @@ jobs:
             - uses: Swatinem/rust-cache@v1
               with:
                   cache-on-failure: true
-            - name: Build all examples
-              run: |
-                  export PATH=$HOME/bin:$PATH
-                  examples=$(cargo metadata --format-version 1 | \
-                    jq -c '.packages[]
-                    | select(.name == "ethers")
-                    | .targets[]
-                    | select(.kind[] | contains("example"))
-                    | with_entries(select([.key]
-                    | inside(["name", "required-features"])))'
-                  )
-                  for example in $examples; do
-                    name="$(echo "$example" | jq -r '.name')"
-                    args=(
-                      -p ethers
-                      --example "$name"
-                    )
-                    features="$(echo "$example" | jq -r 'try(."required-features" | join(","))')"
-                    if [[ ! -z "$features" ]]; then
-                      args+=(--features "$features")
-                    fi
-
-                    echo "building $name"
-                    cargo build "${args[@]}"
-                  done
-            - name: Run all examples
+            - name: Build and run all examples
               run: |
                   export PATH=$HOME/bin:$PATH
                   chmod +x ./scripts/examples.sh
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 2a623363..c5a0d996 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -275,6 +275,7 @@
 
 - `eth-keystore-rs` crate updated. Allow an optional name for the to-be-generated
   keystore file [#910](https://github.com/gakonst/ethers-rs/pull/910)
+- [1983](https://github.com/gakonst/ethers-rs/pull/1983) Added a `from_bytes` function for the `Wallet` type.
 
 ### 0.6.0
 
diff --git a/Cargo.lock b/Cargo.lock
index 0121253b..f6f73319 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -1627,6 +1627,111 @@ dependencies = [
  "wee_alloc",
 ]
 
+[[package]]
+name = "examples-anvil"
+version = "1.0.2"
+dependencies = [
+ "ethers",
+ "eyre",
+ "tokio",
+]
+
+[[package]]
+name = "examples-big-numbers"
+version = "1.0.2"
+dependencies = [
+ "ethers",
+]
+
+[[package]]
+name = "examples-contracts"
+version = "1.0.2"
+dependencies = [
+ "ethers",
+ "eyre",
+ "serde",
+ "serde_json",
+ "tokio",
+]
+
+[[package]]
+name = "examples-events"
+version = "1.0.2"
+dependencies = [
+ "ethers",
+ "eyre",
+ "serde",
+ "serde_json",
+ "tokio",
+]
+
+[[package]]
+name = "examples-middleware"
+version = "1.0.2"
+dependencies = [
+ "async-trait",
+ "ethers",
+ "eyre",
+ "serde_json",
+ "thiserror",
+ "tokio",
+]
+
+[[package]]
+name = "examples-providers"
+version = "1.0.2"
+dependencies = [
+ "ethers",
+ "eyre",
+ "serde",
+ "serde_json",
+ "tokio",
+]
+
+[[package]]
+name = "examples-queries"
+version = "1.0.2"
+dependencies = [
+ "ethers",
+ "eyre",
+ "serde",
+ "serde_json",
+ "tokio",
+]
+
+[[package]]
+name = "examples-subscriptions"
+version = "1.0.2"
+dependencies = [
+ "ethers",
+ "eyre",
+ "serde",
+ "serde_json",
+ "tokio",
+]
+
+[[package]]
+name = "examples-transactions"
+version = "1.0.2"
+dependencies = [
+ "ethers",
+ "eyre",
+ "serde",
+ "serde_json",
+ "tokio",
+]
+
+[[package]]
+name = "examples-wallets"
+version = "1.0.2"
+dependencies = [
+ "ethers",
+ "eyre",
+ "serde",
+ "serde_json",
+ "tokio",
+]
+
 [[package]]
 name = "eyre"
 version = "0.6.8"
@@ -2616,9 +2721,9 @@ checksum = "830b246a0e5f20af87141b25c173cd1b609bd7779a4617d6ec582abaf90870f3"
 
 [[package]]
 name = "once_cell"
-version = "1.16.0"
+version = "1.17.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "86f0b0d4bf799edbc74508c1e8bf170ff5f41238e5f8225603ca7caaae2b7860"
+checksum = "6f61fba1741ea2b3d6a1e3178721804bb716a68a6aeba1149b5d52e3d464ea66"
 
 [[package]]
 name = "oorandom"
diff --git a/Cargo.toml b/Cargo.toml
index f4c2adf4..45c2d1d1 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -21,7 +21,8 @@ members = [
     "ethers-middleware",
     "ethers-etherscan",
     "ethers-solc",
-    "examples/ethers-wasm",
+    # Example crates
+    "examples/*",
 ]
 
 default-members = [
@@ -128,62 +129,3 @@ bytes = "1.3.0"
 # Tell `rustc` to optimize for small code size.
 opt-level = "s"
 
-[[example]]
-name = "abigen"
-path = "examples/abigen.rs"
-required-features = ["ethers-solc"]
-
-[[example]]
-name = "contract_human_readable"
-path = "examples/contract_human_readable.rs"
-required-features = ["ethers-solc"]
-
-[[example]]
-name = "contract_with_abi"
-path = "examples/contract_with_abi.rs"
-required-features = ["ethers-solc"]
-
-[[example]]
-name = "contract_with_abi_and_bytecode"
-path = "examples/contract_with_abi_and_bytecode.rs"
-required-features = ["ethers-solc"]
-
-[[example]]
-name = "ipc"
-path = "examples/ipc.rs"
-required-features = ["ipc"]
-
-[[example]]
-name = "ledger"
-path = "examples/ledger.rs"
-required-features = ["ledger"]
-
-[[example]]
-name = "moonbeam_with_abi"
-path = "examples/moonbeam_with_abi.rs"
-required-features = ["legacy", "ethers-solc"]
-
-[[example]]
-name = "trezor"
-path = "examples/trezor.rs"
-required-features = ["trezor"]
-
-[[example]]
-name = "yubi"
-path = "examples/yubi.rs"
-required-features = ["yubi"]
-
-[[example]]
-name = "paginated_logs"
-path = "examples/paginated_logs.rs"
-required-features = ["rustls"]
-
-[[example]]
-name = "subscribe_contract_events"
-path = "examples/subscribe_contract_events.rs"
-required-features = ["rustls", "ws"]
-
-[[example]]
-name = "subscribe_contract_events_with_meta"
-path = "examples/subscribe_contract_events_with_meta.rs"
-required-features = ["rustls", "ws"]
diff --git a/README.md b/README.md
index 9d98bb16..c85e9f9e 100644
--- a/README.md
+++ b/README.md
@@ -15,7 +15,12 @@ Extensive documentation and examples are available [here](https://docs.rs/ethers
 
 Alternatively, you may clone the repository and run `cd ethers/ && cargo doc --open`
 
-You can also run any of the examples by executing: `cargo run -p ethers --example <name>`
+Examples are organized into individual crates under the `/examples` folder.
+You can run any of the examples by executing: 
+```bash
+# cargo run -p <example-crate-name> --example <name>
+cargo run -p examples-big-numbers --example math_operations
+```
 
 ## Add ethers-rs to your repository
 
diff --git a/ethers-addressbook/Cargo.toml b/ethers-addressbook/Cargo.toml
index 17907527..3e491ffc 100644
--- a/ethers-addressbook/Cargo.toml
+++ b/ethers-addressbook/Cargo.toml
@@ -11,7 +11,7 @@ repository = "https://github.com/gakonst/ethers-rs"
 keywords = ["ethereum", "web3", "celo", "ethers"]
 
 [dependencies]
-once_cell = "1.16.0"
+once_cell = "1.17.0"
 serde = { version = "1.0", features = ["derive"] }
 serde_json = "1.0"
 
diff --git a/ethers-contract/Cargo.toml b/ethers-contract/Cargo.toml
index 821fe3bf..aa9cb7ca 100644
--- a/ethers-contract/Cargo.toml
+++ b/ethers-contract/Cargo.toml
@@ -20,7 +20,7 @@ ethers-derive-eip712 = { version = "^1.0.0", path = "../ethers-core/ethers-deriv
 serde = { version = "1.0.124", default-features = false }
 serde_json = { version = "1.0.64", default-features = false }
 thiserror = { version = "1.0", default-features = false }
-once_cell = { version = "1.16.0" }
+once_cell = { version = "1.17.0" }
 pin-project = { version = "1.0.11", default-features = false }
 futures-util = { version = "^0.3" }
 hex = { version = "0.4.3", default-features = false, features = ["std"] }
diff --git a/ethers-contract/ethers-contract-abigen/Cargo.toml b/ethers-contract/ethers-contract-abigen/Cargo.toml
index f69e2f69..164d8b9e 100644
--- a/ethers-contract/ethers-contract-abigen/Cargo.toml
+++ b/ethers-contract/ethers-contract-abigen/Cargo.toml
@@ -1,11 +1,12 @@
 [package]
 name = "ethers-contract-abigen"
 version = "1.0.2"
+edition = "2021"
+rust-version = "1.64"
 authors = [
     "Nicholas Rodrigues Lordello <nlordell@gmail.com>",
     "Georgios Konstantopoulos <me@gakonst.com>",
 ]
-edition = "2018"
 license = "MIT OR Apache-2.0"
 description = "Code generation for type-safe bindings to Ethereum smart contracts"
 homepage = "https://docs.rs/ethers"
diff --git a/ethers-contract/ethers-contract-derive/Cargo.toml b/ethers-contract/ethers-contract-derive/Cargo.toml
index 1c49c995..0191d2f5 100644
--- a/ethers-contract/ethers-contract-derive/Cargo.toml
+++ b/ethers-contract/ethers-contract-derive/Cargo.toml
@@ -1,11 +1,12 @@
 [package]
 name = "ethers-contract-derive"
 version = "1.0.2"
+edition = "2021"
+rust-version = "1.64"
 authors = [
     "Nicholas Rodrigues Lordello <nlordell@gmail.com>",
     "Georgios Konstantopoulos <me@gakonst.com>",
 ]
-edition = "2018"
 license = "MIT OR Apache-2.0"
 description = "Proc macro for type-safe bindings generation to Ethereum and Celo smart contracts"
 homepage = "https://docs.rs/ethers"
diff --git a/ethers-contract/src/multicall/mod.rs b/ethers-contract/src/multicall/mod.rs
index 56dca427..0b5bc56f 100644
--- a/ethers-contract/src/multicall/mod.rs
+++ b/ethers-contract/src/multicall/mod.rs
@@ -661,7 +661,7 @@ impl<M: Middleware> Multicall<M> {
     /// #
     /// # let multicall = Multicall::new(client, None).await?;
     /// // If the all Solidity function calls `returns (uint256)`:
-    /// let result: Vec<U256> = multicall.call().await?;
+    /// let result: Vec<U256> = multicall.call_array().await?;
     /// # Ok(())
     /// # }
     /// ```
diff --git a/ethers-core/Cargo.toml b/ethers-core/Cargo.toml
index fbf0e92d..8aa21a6f 100644
--- a/ethers-core/Cargo.toml
+++ b/ethers-core/Cargo.toml
@@ -1,10 +1,10 @@
 [package]
 name = "ethers-core"
-license = "MIT OR Apache-2.0"
 version = "1.0.2"
+edition = "2021"
 rust-version = "1.64"
 authors = ["Georgios Konstantopoulos <me@gakonst.com>"]
-edition = "2018"
+license = "MIT OR Apache-2.0"
 description = "Core structures for the ethers-rs crate"
 homepage = "https://docs.rs/ethers"
 repository = "https://github.com/gakonst/ethers-rs"
@@ -31,7 +31,7 @@ serde_json = { version = "1.0.64", default-features = false, features = ["arbitr
 thiserror = { version = "1.0", default-features = false }
 bytes = { version = "1.3.0", features = ["serde"] }
 hex = { version = "0.4.3", default-features = false, features = ["std"] }
-once_cell = { version = "1.16.0", optional = true }
+once_cell = { version = "1.17.0", optional = true }
 unicode-xid = "0.2.4"
 strum = { version = "0.24", features = ["derive"] }
 
@@ -48,7 +48,7 @@ num_enum = "0.5.7"
 tempfile = { version = "3.3.0", default-features = false }
 serde_json = { version = "1.0.64", default-features = false }
 bincode = { version = "1.3.3", default-features = false }
-once_cell = { version = "1.16.0" }
+once_cell = { version = "1.17.0" }
 hex-literal = "0.3.4"
 rand = "0.8.5"
 
diff --git a/ethers-core/ethers-derive-eip712/Cargo.toml b/ethers-core/ethers-derive-eip712/Cargo.toml
index 305bfcfd..61073774 100644
--- a/ethers-core/ethers-derive-eip712/Cargo.toml
+++ b/ethers-core/ethers-derive-eip712/Cargo.toml
@@ -1,7 +1,8 @@
 [package]
 name = "ethers-derive-eip712"
 version = "1.0.2"
-edition = "2018"
+edition = "2021"
+rust-version = "1.64"
 description = "Custom derive macro for EIP-712 typed data"
 license = "MIT OR Apache-2.0"
 
@@ -11,7 +12,10 @@ proc-macro = true
 [dependencies]
 quote = "1.0.9"
 syn = "1.0.77"
-ethers-core = { version = "^1.0.0", path = "../", default-features = false, features = ["eip712", "macros"] }
+ethers-core = { version = "^1.0.0", path = "../", default-features = false, features = [
+    "eip712",
+    "macros",
+] }
 hex = "0.4.3"
 serde_json = "1.0.68"
 
diff --git a/ethers-core/src/macros/ethers_crate.rs b/ethers-core/src/macros/ethers_crate.rs
index 78bc38d8..2c33eb5c 100644
--- a/ethers-core/src/macros/ethers_crate.rs
+++ b/ethers-core/src/macros/ethers_crate.rs
@@ -63,7 +63,7 @@ pub fn determine_ethers_crates() -> (&'static str, &'static str, &'static str) {
     let needs_lock_file_cleanup = !std::path::Path::new(&lock_file).exists();
 
     let res = MetadataCommand::new()
-        .manifest_path(&format!("{manifest_dir}/Cargo.toml"))
+        .manifest_path(format!("{manifest_dir}/Cargo.toml"))
         .exec()
         .ok()
         .and_then(|metadata| {
diff --git a/ethers-etherscan/Cargo.toml b/ethers-etherscan/Cargo.toml
index abea9a1e..8de6d5ac 100644
--- a/ethers-etherscan/Cargo.toml
+++ b/ethers-etherscan/Cargo.toml
@@ -1,13 +1,13 @@
 [package]
 name = "ethers-etherscan"
 version = "1.0.2"
+edition = "2021"
 rust-version = "1.64"
 authors = [
     "Matthias Seitz <matthias.seitz@outlook.de>",
     "Georgios Konstantopoulos <me@gakonst.com>",
 ]
 license = "MIT OR Apache-2.0"
-edition = "2018"
 readme = "../README.md"
 documentation = "https://docs.rs/ethers"
 repository = "https://github.com/gakonst/ethers-rs"
diff --git a/ethers-middleware/Cargo.toml b/ethers-middleware/Cargo.toml
index 2518a21d..08c79162 100644
--- a/ethers-middleware/Cargo.toml
+++ b/ethers-middleware/Cargo.toml
@@ -1,7 +1,7 @@
 [package]
 name = "ethers-middleware"
 version = "1.0.2"
-edition = "2018"
+edition = "2021"
 rust-version = "1.64"
 authors = ["Georgios Konstantopoulos <me@gakonst.com>"]
 license = "MIT OR Apache-2.0"
@@ -47,7 +47,7 @@ ethers-providers = { version = "^1.0.0", path = "../ethers-providers", default-f
     "ws",
     "rustls",
 ] }
-once_cell = "1.16.0"
+once_cell = "1.17.0"
 ethers-solc = { version = "^1.0.0", path = "../ethers-solc" }
 serial_test = "0.10.0"
 reqwest = { version = "0.11.13", default-features = false, features = ["json", "rustls"] }
diff --git a/ethers-middleware/src/gas_oracle/mod.rs b/ethers-middleware/src/gas_oracle/mod.rs
index 9be17750..40c1bf42 100644
--- a/ethers-middleware/src/gas_oracle/mod.rs
+++ b/ethers-middleware/src/gas_oracle/mod.rs
@@ -37,7 +37,7 @@ use std::{error::Error, fmt::Debug};
 use thiserror::Error;
 
 pub(crate) const GWEI_TO_WEI: u64 = 1_000_000_000;
-pub(crate) const GWEI_TO_WEI_U256: U256 = U256([0, 0, 0, GWEI_TO_WEI]);
+pub(crate) const GWEI_TO_WEI_U256: U256 = U256([GWEI_TO_WEI, 0, 0, 0]);
 
 pub type Result<T, E = GasOracleError> = std::result::Result<T, E>;
 
@@ -153,3 +153,15 @@ pub trait GasOracle: Send + Sync + Debug {
 pub(crate) fn from_gwei_f64(gwei: f64) -> U256 {
     ethers_core::types::u256_from_f64_saturating(gwei) * GWEI_TO_WEI_U256
 }
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+
+    #[test]
+    fn test_gwei_wei_constants() {
+        let as_u256: U256 = GWEI_TO_WEI.into();
+        assert_eq!(as_u256, GWEI_TO_WEI_U256);
+        assert_eq!(GWEI_TO_WEI_U256.as_u64(), GWEI_TO_WEI);
+    }
+}
diff --git a/ethers-middleware/src/gas_oracle/polygon.rs b/ethers-middleware/src/gas_oracle/polygon.rs
index 5fd63545..f7acf85a 100644
--- a/ethers-middleware/src/gas_oracle/polygon.rs
+++ b/ethers-middleware/src/gas_oracle/polygon.rs
@@ -20,7 +20,7 @@ pub struct Polygon {
 
 /// The response from the Polygon gas station API.
 ///
-/// Gas prices are in Gwei.
+/// Gas prices are in __Gwei__.
 #[derive(Debug, Deserialize, PartialEq)]
 #[serde(rename_all = "camelCase")]
 pub struct Response {
@@ -103,3 +103,14 @@ impl Polygon {
         Ok(response)
     }
 }
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+
+    #[test]
+    fn parse_polygon_gas_station_response() {
+        let s = r#"{"safeLow":{"maxPriorityFee":2.1267086610666666,"maxFee":2.1267086760666665},"standard":{"maxPriorityFee":2.3482958369333335,"maxFee":2.3482958519333335},"fast":{"maxPriorityFee":2.793454819,"maxFee":2.793454834},"estimatedBaseFee":1.5e-8,"blockTime":2,"blockNumber":30328888}"#;
+        let _resp: Response = serde_json::from_str(s).unwrap();
+    }
+}
diff --git a/ethers-providers/Cargo.toml b/ethers-providers/Cargo.toml
index d11f4f81..e3117d68 100644
--- a/ethers-providers/Cargo.toml
+++ b/ethers-providers/Cargo.toml
@@ -1,7 +1,7 @@
 [package]
 name = "ethers-providers"
 version = "1.0.2"
-edition = "2018"
+edition = "2021"
 rust-version = "1.64"
 authors = ["Georgios Konstantopoulos <me@gakonst.com>"]
 license = "MIT OR Apache-2.0"
@@ -43,7 +43,7 @@ tracing = { version = "0.1.37", default-features = false }
 tracing-futures = { version = "0.2.5", default-features = false, features = ["std-future"] }
 
 bytes = { version = "1.3.0", default-features = false, optional = true }
-once_cell = "1.16.0"
+once_cell = "1.17.0"
 hashers = "1.0.1"
 
 [target.'cfg(not(target_arch = "wasm32"))'.dependencies]
diff --git a/ethers-providers/src/provider.rs b/ethers-providers/src/provider.rs
index cde771cc..97d5a995 100644
--- a/ethers-providers/src/provider.rs
+++ b/ethers-providers/src/provider.rs
@@ -352,8 +352,19 @@ impl<P: JsonRpcClient> Middleware for Provider<P> {
                 if inner.max_fee_per_gas.is_none() || inner.max_priority_fee_per_gas.is_none() {
                     let (max_fee_per_gas, max_priority_fee_per_gas) =
                         self.estimate_eip1559_fees(None).await?;
-                    inner.max_fee_per_gas = Some(max_fee_per_gas);
-                    inner.max_priority_fee_per_gas = Some(max_priority_fee_per_gas);
+                    // we want to avoid overriding the user if either of these
+                    // are set. In order to do this, we refuse to override the
+                    // `max_fee_per_gas` if already set.
+                    // However, we must preserve the constraint that the tip
+                    // cannot be higher than max fee, so we override user
+                    // intent if that is so. We override by
+                    //   - first: if set, set to the min(current value, MFPG)
+                    //   - second, if still unset, use the RPC estimated amount
+                    let mfpg = inner.max_fee_per_gas.get_or_insert(max_fee_per_gas);
+                    inner
+                        .max_priority_fee_per_gas
+                        .map(|tip| std::cmp::min(tip, *mfpg))
+                        .get_or_insert(max_priority_fee_per_gas);
                 };
             }
         }
diff --git a/ethers-signers/Cargo.toml b/ethers-signers/Cargo.toml
index 02c2bab1..8a25e34f 100644
--- a/ethers-signers/Cargo.toml
+++ b/ethers-signers/Cargo.toml
@@ -1,7 +1,7 @@
 [package]
 name = "ethers-signers"
 version = "1.0.2"
-edition = "2018"
+edition = "2021"
 rust-version = "1.64"
 authors = ["Georgios Konstantopoulos <me@gakonst.com>"]
 license = "MIT OR Apache-2.0"
diff --git a/ethers-signers/src/wallet/private_key.rs b/ethers-signers/src/wallet/private_key.rs
index cdddf00a..ed10949c 100644
--- a/ethers-signers/src/wallet/private_key.rs
+++ b/ethers-signers/src/wallet/private_key.rs
@@ -90,6 +90,13 @@ impl Wallet<SigningKey> {
         let address = secret_key_to_address(&signer);
         Self { signer, address, chain_id: 1 }
     }
+
+    /// Creates a new Wallet instance from a raw scalar value (big endian).
+    pub fn from_bytes(bytes: &[u8]) -> Result<Self, WalletError> {
+        let signer = SigningKey::from_bytes(bytes)?;
+        let address = secret_key_to_address(&signer);
+        Ok(Self { signer, address, chain_id: 1 })
+    }
 }
 
 impl PartialEq for Wallet<SigningKey> {
@@ -305,4 +312,17 @@ mod tests {
             Address::from_str("6813Eb9362372EEF6200f3b1dbC3f819671cBA69").expect("Decoding failed")
         );
     }
+
+    #[test]
+    fn key_from_bytes() {
+        let wallet: Wallet<SigningKey> =
+            "0000000000000000000000000000000000000000000000000000000000000001".parse().unwrap();
+
+        let key_as_bytes = wallet.signer.to_bytes();
+        let wallet_from_bytes = Wallet::from_bytes(&key_as_bytes).unwrap();
+
+        assert_eq!(wallet.address, wallet_from_bytes.address);
+        assert_eq!(wallet.chain_id, wallet_from_bytes.chain_id);
+        assert_eq!(wallet.signer, wallet_from_bytes.signer);
+    }
 }
diff --git a/ethers-solc/Cargo.toml b/ethers-solc/Cargo.toml
index 66002fd5..3555e1b4 100644
--- a/ethers-solc/Cargo.toml
+++ b/ethers-solc/Cargo.toml
@@ -1,7 +1,7 @@
 [package]
 name = "ethers-solc"
 version = "1.0.2"
-edition = "2018"
+edition = "2021"
 rust-version = "1.64"
 authors = [
     "Matthias Seitz <matthias.seitz@outlook.de>",
@@ -23,7 +23,7 @@ semver = { version = "1.0.16", features = ["serde"] }
 walkdir = "2.3.2"
 tokio = { version = "1.18", default-features = false, features = ["rt"] }
 futures-util = { version = "^0.3", optional = true }
-once_cell = "1.16.0"
+once_cell = "1.17.0"
 regex = "1.7.0"
 md-5 = "0.10.5"
 thiserror = "1.0"
diff --git a/ethers-solc/benches/compile_many.rs b/ethers-solc/benches/compile_many.rs
index b667a6b9..b0df3c7a 100644
--- a/ethers-solc/benches/compile_many.rs
+++ b/ethers-solc/benches/compile_many.rs
@@ -36,7 +36,6 @@ fn load_compiler_inputs() -> Vec<CompilerInput> {
     let mut inputs = Vec::new();
     for file in std::fs::read_dir(Path::new(&env!("CARGO_MANIFEST_DIR")).join("test-data/in"))
         .unwrap()
-        .into_iter()
         .take(5)
     {
         let file = file.unwrap();
diff --git a/ethers-solc/src/artifacts/ast/mod.rs b/ethers-solc/src/artifacts/ast/mod.rs
index 82e01a2b..be83cd00 100644
--- a/ethers-solc/src/artifacts/ast/mod.rs
+++ b/ethers-solc/src/artifacts/ast/mod.rs
@@ -1089,11 +1089,11 @@ mod tests {
                 let result: Result<SourceUnit, _> = serde_path_to_error::deserialize(deserializer);
                 match result {
                     Err(e) => {
-                        println!("... {} fail: {e}", path_str);
+                        println!("... {path_str} fail: {e}");
                         panic!();
                     }
                     Ok(_) => {
-                        println!("... {} ok", path_str);
+                        println!("... {path_str} ok");
                     }
                 }
             })
diff --git a/ethers-solc/src/compile/mod.rs b/ethers-solc/src/compile/mod.rs
index fe40cfb9..b34913fe 100644
--- a/ethers-solc/src/compile/mod.rs
+++ b/ethers-solc/src/compile/mod.rs
@@ -457,7 +457,7 @@ impl Solc {
 
         use sha2::Digest;
         let mut hasher = sha2::Sha256::new();
-        hasher.update(&content);
+        hasher.update(content);
         let checksum_calc = &hasher.finalize()[..];
 
         let checksum_found = &RELEASES.0.get_checksum(&version).expect("checksum not found");
diff --git a/ethers-solc/src/resolver/mod.rs b/ethers-solc/src/resolver/mod.rs
index eceba2e1..848713ad 100644
--- a/ethers-solc/src/resolver/mod.rs
+++ b/ethers-solc/src/resolver/mod.rs
@@ -649,7 +649,7 @@ impl Graph {
                 return Vec::new()
             }
 
-            let mut result = sets.pop().cloned().expect("not empty; qed.").clone();
+            let mut result = sets.pop().cloned().expect("not empty; qed.");
             if !sets.is_empty() {
                 result.retain(|item| sets.iter().all(|set| set.contains(item)));
             }
diff --git a/examples/README.md b/examples/README.md
new file mode 100644
index 00000000..87fbfc19
--- /dev/null
+++ b/examples/README.md
@@ -0,0 +1,81 @@
+# Examples
+- [ ] Address book
+- [ ] Anvil
+    - [ ] Boot anvil
+    - [ ] Deploy contracts
+    - [x] Fork
+    - [ ] Testing
+- [x] Big numbers
+    - [x] Comparison and equivalence
+    - [x] Conversion
+    - [x] Creating Instances
+    - [x] Math operations
+    - [x] Utilities
+- [ ] Contracts
+    - [x] Abigen
+    - [x] Compile
+    - [ ] Creating Instances
+    - [x] Deploy Anvil
+    - [x] Deploy from ABI and bytecode
+    - [x] Deploy Moonbeam
+    - [x] Events
+    - [x] Events with meta
+    - [ ] Methods
+- [ ] Events
+  - [ ] Logs and filtering
+  - [ ] Solidity topics
+- [ ] Middleware
+  - [x] Builder
+  - [x] Create custom middleware
+  - [x] Gas escalator
+  - [x] Gas oracle
+  - [x] Nonce manager
+  - [x] Policy
+  - [x] Signer
+  - [ ] Time lag
+  - [ ] Transformer
+- [ ] Providers
+  - [ ] Http
+  - [x] IPC
+  - [ ] Mock 
+  - [x] Quorum
+  - [ ] Retry
+  - [x] RW
+  - [ ] WS
+- [ ] Queries
+  - [ ] Blocks
+  - [x] Contracts
+  - [ ] Events
+  - [x] Paginated logs
+  - [x] UniswapV2 pair
+  - [ ] Transactions
+- [x] Subscriptions
+  - [x] Watch blocks
+  - [x] Subscribe events by type
+  - [x] Subscribe logs
+- [ ] Transactions
+  - [x] Call override
+  - [ ] Create raw transaction
+  - [ ] Create typed transaction
+  - [x] Decode input
+  - [ ] EIP-1559
+  - [x] ENS
+  - [ ] Estimate gas
+  - [ ] Get gas price
+  - [x] Get gas price USD
+  - [x] Remove liquidity
+  - [ ] Set gas for a transaction
+  - [ ] Send raw transaction
+  - [ ] Send typed transaction
+  - [x] Trace
+  - [ ] Transaction receipt
+  - [ ] Transaction status
+  - [x] Transfer ETH
+- [x] Wallets
+  - [x] Mnemonic
+  - [x] Ledger
+  - [x] Local
+  - [x] Permit hash
+  - [x] Sign message
+  - [x] Trezor
+  - [x] Yubi
diff --git a/examples/anvil/Cargo.toml b/examples/anvil/Cargo.toml
new file mode 100644
index 00000000..7e1fb044
--- /dev/null
+++ b/examples/anvil/Cargo.toml
@@ -0,0 +1,10 @@
+[package]
+name = "examples-anvil"
+version = "1.0.2"
+authors = ["Andrea Simeoni <andreasimeoni84@gmail.com>"]
+edition = "2021"
+
+[dev-dependencies]
+ethers = { path = "../..", version = "1.0.0" }
+eyre = "0.6"
+tokio = { version = "1.18", features = ["full"] }
diff --git a/examples/anvil/README.md b/examples/anvil/README.md
new file mode 100644
index 00000000..e69de29b
diff --git a/examples/anvil_fork.rs b/examples/anvil/examples/anvil_fork.rs
similarity index 88%
rename from examples/anvil_fork.rs
rename to examples/anvil/examples/anvil_fork.rs
index 31da8670..4fecb8e8 100644
--- a/examples/anvil_fork.rs
+++ b/examples/anvil/examples/anvil_fork.rs
@@ -1,9 +1,10 @@
 //! Spawn an [anvil](https://github.com/foundry-rs/foundry/tree/master/anvil) instance in forking mode
 
 use ethers::utils::Anvil;
+use eyre::Result;
 
 #[tokio::main]
-async fn main() -> eyre::Result<()> {
+async fn main() -> Result<()> {
     // ensure `anvil` is available in $PATH
     let anvil =
         Anvil::new().fork("https://mainnet.infura.io/v3/c60b0bb42f8a4c6481ecd229eddaca27").spawn();
diff --git a/examples/big-numbers/Cargo.toml b/examples/big-numbers/Cargo.toml
new file mode 100644
index 00000000..04505c19
--- /dev/null
+++ b/examples/big-numbers/Cargo.toml
@@ -0,0 +1,10 @@
+[package]
+name = "examples-big-numbers"
+version = "1.0.2"
+authors = ["Andrea Simeoni <andreasimeoni84@gmail.com>"]
+edition = "2021"
+
+[dev-dependencies]
+#ethers-core = { version = "^1.0.0", path = "../../ethers-core" }
+ethers = { path = "../..", version = "1.0.0" }
+
diff --git a/examples/big-numbers/README.md b/examples/big-numbers/README.md
new file mode 100644
index 00000000..7ac9428e
--- /dev/null
+++ b/examples/big-numbers/README.md
@@ -0,0 +1,7 @@
+# Big numbers
+Ethereum uses big numbers (also known as "bignums" or "arbitrary-precision integers") to represent certain values in its codebase and in blockchain transactions. This is necessary because [the EVM](https://ethereum.org/en/developers/docs/evm) operates on a 256-bit word size, which is different from the usual 32-bit or 64-bit of modern machines. This was chosen for the ease of use with 256-bit cryptography (such as Keccak-256 hashes or secp256k1 signatures).
+
+It is worth noting that Ethereum is not the only blockchain or cryptocurrency that uses big numbers. Many other blockchains and cryptocurrencies also use big numbers to represent values in their respective systems.
+
+## Utilities
+In order to create an application, it is often necessary to convert between the representation of values that is easily understood by humans (such as ether) and the machine-readable form that is used by contracts and math functions (such as wei). This is particularly important when working with Ethereum, as certain values, such as balances and gas prices, must be expressed in wei when sending transactions, even if they are displayed to the user in a different format, such as ether or gwei. To help with this conversion, ethers-rs provides two functions, `parse_units` and `format_units`, which allow you to easily convert between human-readable and machine-readable forms of values. `parse_units` can be used to convert a string representing a value in ether, such as "1.1", into a big number in wei, which can be used in contracts and math functions. `format_units` can be used to convert a big number value into a human-readable string, which is useful for displaying values to users.
diff --git a/examples/big-numbers/examples/comparison_equivalence.rs b/examples/big-numbers/examples/comparison_equivalence.rs
new file mode 100644
index 00000000..214a81e7
--- /dev/null
+++ b/examples/big-numbers/examples/comparison_equivalence.rs
@@ -0,0 +1,32 @@
+use ethers::types::U256;
+
+fn main() {
+    // a == b
+    let a = U256::from(100_u32);
+    let b = U256::from(100_u32);
+    assert!(a == b);
+
+    // a < b
+    let a = U256::from(1_u32);
+    let b = U256::from(100_u32);
+    assert!(a < b);
+
+    // a <= b
+    let a = U256::from(100_u32);
+    let b = U256::from(100_u32);
+    assert!(a <= b);
+
+    // a > b
+    let a = U256::from(100_u32);
+    let b = U256::from(1_u32);
+    assert!(a > b);
+
+    // a >= b
+    let a = U256::from(100_u32);
+    let b = U256::from(100_u32);
+    assert!(a >= b);
+
+    // a == 0
+    let a = U256::zero();
+    assert!(a.is_zero());
+}
diff --git a/examples/big-numbers/examples/conversion.rs b/examples/big-numbers/examples/conversion.rs
new file mode 100644
index 00000000..99eb6ea0
--- /dev/null
+++ b/examples/big-numbers/examples/conversion.rs
@@ -0,0 +1,23 @@
+use ethers::{types::U256, utils::format_units};
+
+fn main() {
+    let num = U256::from(42_u8);
+
+    let a: u128 = num.as_u128();
+    assert_eq!(a, 42);
+
+    let b: u64 = num.as_u64();
+    assert_eq!(b, 42);
+
+    let c: u32 = num.as_u32();
+    assert_eq!(c, 42);
+
+    let d: usize = num.as_usize();
+    assert_eq!(d, 42);
+
+    let e: String = num.to_string();
+    assert_eq!(e, "42");
+
+    let f: String = format_units(num, 4).unwrap();
+    assert_eq!(f, "0.0042");
+}
diff --git a/examples/big-numbers/examples/create_instances.rs b/examples/big-numbers/examples/create_instances.rs
new file mode 100644
index 00000000..35fea7f1
--- /dev/null
+++ b/examples/big-numbers/examples/create_instances.rs
@@ -0,0 +1,47 @@
+use ethers::{
+    types::{serde_helpers::Numeric, U256},
+    utils::{parse_units, ParseUnits},
+};
+
+fn main() {
+    // From strings
+    let a = U256::from_dec_str("42").unwrap();
+    assert_eq!(format!("{a:?}"), "42");
+
+    let amount = "42";
+    let units = 4;
+    let pu: ParseUnits = parse_units(amount, units).unwrap();
+    let b = U256::from(pu);
+    assert_eq!(format!("{b:?}"), "420000");
+
+    // From numbers
+    let c = U256::from(42_u8);
+    assert_eq!(format!("{c:?}"), "42");
+
+    let d = U256::from(42_u16);
+    assert_eq!(format!("{d:?}"), "42");
+
+    let e = U256::from(42_u32);
+    assert_eq!(format!("{e:?}"), "42");
+
+    let f = U256::from(42_u64);
+    assert_eq!(format!("{f:?}"), "42");
+
+    let g = U256::from(42_u128);
+    assert_eq!(format!("{g:?}"), "42");
+
+    let h = U256::from(0x2a);
+    assert_eq!(format!("{h:?}"), "42");
+
+    let i: U256 = 42.into();
+    assert_eq!(format!("{i:?}"), "42");
+
+    // From `Numeric`
+    let num: Numeric = Numeric::U256(U256::one());
+    let l = U256::from(num);
+    assert_eq!(format!("{l:?}"), "1");
+
+    let num: Numeric = Numeric::Num(42);
+    let m = U256::from(num);
+    assert_eq!(format!("{m:?}"), "42");
+}
diff --git a/examples/big-numbers/examples/math_operations.rs b/examples/big-numbers/examples/math_operations.rs
new file mode 100644
index 00000000..45938331
--- /dev/null
+++ b/examples/big-numbers/examples/math_operations.rs
@@ -0,0 +1,49 @@
+use ethers::{types::U256, utils::format_units};
+use std::ops::{Div, Mul};
+
+fn main() {
+    let a = U256::from(10);
+    let b = U256::from(2);
+
+    // addition
+    let sum = a + b;
+    assert_eq!(sum, U256::from(12));
+
+    // subtraction
+    let difference = a - b;
+    assert_eq!(difference, U256::from(8));
+
+    // multiplication
+    let product = a * b;
+    assert_eq!(product, U256::from(20));
+
+    // division
+    let quotient = a / b;
+    assert_eq!(quotient, U256::from(5));
+
+    // modulo
+    let remainder = a % b;
+    assert_eq!(remainder, U256::zero()); // equivalent to `U256::from(0)`
+
+    // exponentiation
+    let power = a.pow(b);
+    assert_eq!(power, U256::from(100));
+    // powers of 10 can also be expressed like this:
+    let power_of_10 = U256::exp10(2);
+    assert_eq!(power_of_10, U256::from(100));
+
+    // Multiply two 'ether' numbers:
+    // Big numbers are integers, that can represent fixed point numbers.
+    // For instance, 1 ether has 18 fixed
+    // decimal places (1.000000000000000000), and its big number
+    // representation is 10^18 = 1000000000000000000.
+    // When we multiply such numbers we are summing up their exponents.
+    // So if we multiply 10^18 * 10^18 we get 10^36, that is obviously incorrect.
+    // In order to get the correct result we need to divide by 10^18.
+    let eth1 = U256::from(10_000000000000000000_u128); // 10 ether
+    let eth2 = U256::from(20_000000000000000000_u128); // 20 ether
+    let base = U256::from(10).pow(18.into());
+    let mul = eth1.mul(eth2).div(base); // We also divide by 10^18
+    let s: String = format_units(mul, "ether").unwrap();
+    assert_eq!(s, "200.000000000000000000"); // 200
+}
diff --git a/examples/big-numbers/examples/utilities.rs b/examples/big-numbers/examples/utilities.rs
new file mode 100644
index 00000000..58493584
--- /dev/null
+++ b/examples/big-numbers/examples/utilities.rs
@@ -0,0 +1,92 @@
+use ethers::{
+    types::U256,
+    utils::{format_units, parse_units, ParseUnits},
+};
+
+fn main() {
+    parse_units_example();
+    format_units_example();
+}
+
+/// DApps business logics handles big numbers in 'wei' units (i.e. sending transactions, on-chain
+/// math, etc.). We provide convenient methods to map user inputs (usually in 'ether' or 'gwei')
+/// into 'wei' format.
+fn parse_units_example() {
+    let pu: ParseUnits = parse_units("1.0", "wei").unwrap();
+    let num = U256::from(pu);
+    assert_eq!(num, U256::one());
+
+    let pu: ParseUnits = parse_units("1.0", "kwei").unwrap();
+    let num = U256::from(pu);
+    assert_eq!(num, U256::from(1000));
+
+    let pu: ParseUnits = parse_units("1.0", "mwei").unwrap();
+    let num = U256::from(pu);
+    assert_eq!(num, U256::from(1000000));
+
+    let pu: ParseUnits = parse_units("1.0", "gwei").unwrap();
+    let num = U256::from(pu);
+    assert_eq!(num, U256::from(1000000000));
+
+    let pu: ParseUnits = parse_units("1.0", "szabo").unwrap();
+    let num = U256::from(pu);
+    assert_eq!(num, U256::from(1000000000000_u128));
+
+    let pu: ParseUnits = parse_units("1.0", "finney").unwrap();
+    let num = U256::from(pu);
+    assert_eq!(num, U256::from(1000000000000000_u128));
+
+    let pu: ParseUnits = parse_units("1.0", "ether").unwrap();
+    let num = U256::from(pu);
+    assert_eq!(num, U256::from(1000000000000000000_u128));
+
+    let pu: ParseUnits = parse_units("1.0", 18).unwrap();
+    let num = U256::from(pu);
+    assert_eq!(num, U256::from(1000000000000000000_u128));
+}
+
+/// DApps business logics handles big numbers in 'wei' units (i.e. sending transactions, on-chain
+/// math, etc.). On the other hand it is useful to convert big numbers into user readable formats
+/// when displaying on a UI. Generally dApps display numbers in 'ether' and 'gwei' units,
+/// respectively for displaying amounts and gas. The `format_units` function will format a big
+/// number into a user readable string.
+fn format_units_example() {
+    // 1 ETHER = 10^18 WEI
+    let one_ether = U256::from(1000000000000000000_u128);
+
+    let num: String = format_units(one_ether, "wei").unwrap();
+    assert_eq!(num, "1000000000000000000.0");
+
+    let num: String = format_units(one_ether, "gwei").unwrap();
+    assert_eq!(num, "1000000000.000000000");
+
+    let num: String = format_units(one_ether, "ether").unwrap();
+    assert_eq!(num, "1.000000000000000000");
+
+    // 1 GWEI = 10^9 WEI
+    let one_gwei = U256::from(1000000000_u128);
+
+    let num: String = format_units(one_gwei, 0).unwrap();
+    assert_eq!(num, "1000000000.0");
+
+    let num: String = format_units(one_gwei, "wei").unwrap();
+    assert_eq!(num, "1000000000.0");
+
+    let num: String = format_units(one_gwei, "kwei").unwrap();
+    assert_eq!(num, "1000000.000");
+
+    let num: String = format_units(one_gwei, "mwei").unwrap();
+    assert_eq!(num, "1000.000000");
+
+    let num: String = format_units(one_gwei, "gwei").unwrap();
+    assert_eq!(num, "1.000000000");
+
+    let num: String = format_units(one_gwei, "szabo").unwrap();
+    assert_eq!(num, "0.001000000000");
+
+    let num: String = format_units(one_gwei, "finney").unwrap();
+    assert_eq!(num, "0.000001000000000");
+
+    let num: String = format_units(one_gwei, "ether").unwrap();
+    assert_eq!(num, "0.000000001000000000");
+}
diff --git a/examples/contracts/Cargo.toml b/examples/contracts/Cargo.toml
new file mode 100644
index 00000000..4f0e12bd
--- /dev/null
+++ b/examples/contracts/Cargo.toml
@@ -0,0 +1,19 @@
+[package]
+name = "examples-contracts"
+version = "1.0.2"
+authors = ["Andrea Simeoni <andreasimeoni84@gmail.com>"]
+edition = "2021"
+
+[features]
+default = ["legacy"]
+legacy = []
+
+[dev-dependencies]
+ethers = { path = "../..", version = "1.0.0", features = ["abigen", "ethers-solc", "legacy", "rustls", "ws"] }
+
+eyre = "0.6"
+serde = { version = "1.0.144", features = ["derive"] }
+serde_json = "1.0.64"
+tokio = { version = "1.18", features = ["macros"] }
+
+
diff --git a/examples/contracts/README.md b/examples/contracts/README.md
new file mode 100644
index 00000000..472592f7
--- /dev/null
+++ b/examples/contracts/README.md
@@ -0,0 +1,39 @@
+# Contracts
+In this guide, we will go over some examples of using ethers-rs to work with contracts, including using abigen to generate Rust bindings for a contract, listening for contract events, calling contract methods, and instantiating contracts.
+
+## Generating Rust bindings with abigen
+To use a contract with ethers-rs, you will need to generate Rust bindings using the abigen tool. abigen is included with the ethers-rs library and can be used to generate Rust bindings for any Solidity contract.
+
+### Generate a Rust file
+This method takes a smart contract's Application Binary Interface (ABI) file and generates a Rust file to interact with it. This is useful if the smart contract is referenced in different places in a project. File generation from ABI can also be easily included as a build step of your application.
+
+Running the code below will generate a file called `token.rs` containing the bindings inside, which exports an `ERC20Token` struct, along with all its events and methods. Put into a `build.rs` file this will generate the bindings during cargo build.
+
+```rust
+Abigen::new("ERC20Token", "./abi.json")?.generate()?.write_to_file("token.rs")?;
+```
+
+### Generate inline Rust bindings
+This method takes a smart contract's solidity definition and generates inline Rust code to interact with it. This is useful for fast prototyping and for tight scoped use-cases of your contracts. Inline Rust generation uses the `abigen!` macro to expand Rust contract bindings.
+
+Running the code below will generate bindings for the `ERC20Token` struct, along with all its events and methods.
+```rust
+abigen!(
+    ERC20Token,
+    r#"[
+        function approve(address spender, uint256 amount) external returns (bool)
+        event Transfer(address indexed from, address indexed to, uint256 value)
+        event Approval(address indexed owner, address indexed spender, uint256 value)
+    ]"#,
+);
+```
+
+Another way to get the same result, is to provide the ABI contract's definition as follows.
+```rust 
+abigen!(ERC20Token, "./abi.json",);
+```
+
+## Contract instances
+## Contract methods
+## Contract events
+
diff --git a/examples/contracts/examples/abi/IERC20.json b/examples/contracts/examples/abi/IERC20.json
new file mode 100644
index 00000000..4827e872
--- /dev/null
+++ b/examples/contracts/examples/abi/IERC20.json
@@ -0,0 +1,153 @@
+[
+  {
+    "constant": true,
+    "inputs": [],
+    "name": "name",
+    "outputs": [{ "name": "", "type": "string" }],
+    "payable": false,
+    "stateMutability": "view",
+    "type": "function"
+  },
+  {
+    "constant": false,
+    "inputs": [
+      { "name": "guy", "type": "address" },
+      { "name": "wad", "type": "uint256" }
+    ],
+    "name": "approve",
+    "outputs": [{ "name": "", "type": "bool" }],
+    "payable": false,
+    "stateMutability": "nonpayable",
+    "type": "function"
+  },
+  {
+    "constant": true,
+    "inputs": [],
+    "name": "totalSupply",
+    "outputs": [{ "name": "", "type": "uint256" }],
+    "payable": false,
+    "stateMutability": "view",
+    "type": "function"
+  },
+  {
+    "constant": false,
+    "inputs": [
+      { "name": "src", "type": "address" },
+      { "name": "dst", "type": "address" },
+      { "name": "wad", "type": "uint256" }
+    ],
+    "name": "transferFrom",
+    "outputs": [{ "name": "", "type": "bool" }],
+    "payable": false,
+    "stateMutability": "nonpayable",
+    "type": "function"
+  },
+  {
+    "constant": false,
+    "inputs": [{ "name": "wad", "type": "uint256" }],
+    "name": "withdraw",
+    "outputs": [],
+    "payable": false,
+    "stateMutability": "nonpayable",
+    "type": "function"
+  },
+  {
+    "constant": true,
+    "inputs": [],
+    "name": "decimals",
+    "outputs": [{ "name": "", "type": "uint8" }],
+    "payable": false,
+    "stateMutability": "view",
+    "type": "function"
+  },
+  {
+    "constant": true,
+    "inputs": [{ "name": "", "type": "address" }],
+    "name": "balanceOf",
+    "outputs": [{ "name": "", "type": "uint256" }],
+    "payable": false,
+    "stateMutability": "view",
+    "type": "function"
+  },
+  {
+    "constant": true,
+    "inputs": [],
+    "name": "symbol",
+    "outputs": [{ "name": "", "type": "string" }],
+    "payable": false,
+    "stateMutability": "view",
+    "type": "function"
+  },
+  {
+    "constant": false,
+    "inputs": [
+      { "name": "dst", "type": "address" },
+      { "name": "wad", "type": "uint256" }
+    ],
+    "name": "transfer",
+    "outputs": [{ "name": "", "type": "bool" }],
+    "payable": false,
+    "stateMutability": "nonpayable",
+    "type": "function"
+  },
+  {
+    "constant": false,
+    "inputs": [],
+    "name": "deposit",
+    "outputs": [],
+    "payable": true,
+    "stateMutability": "payable",
+    "type": "function"
+  },
+  {
+    "constant": true,
+    "inputs": [
+      { "name": "", "type": "address" },
+      { "name": "", "type": "address" }
+    ],
+    "name": "allowance",
+    "outputs": [{ "name": "", "type": "uint256" }],
+    "payable": false,
+    "stateMutability": "view",
+    "type": "function"
+  },
+  { "payable": true, "stateMutability": "payable", "type": "fallback" },
+  {
+    "anonymous": false,
+    "inputs": [
+      { "indexed": true, "name": "src", "type": "address" },
+      { "indexed": true, "name": "guy", "type": "address" },
+      { "indexed": false, "name": "wad", "type": "uint256" }
+    ],
+    "name": "Approval",
+    "type": "event"
+  },
+  {
+    "anonymous": false,
+    "inputs": [
+      { "indexed": true, "name": "src", "type": "address" },
+      { "indexed": true, "name": "dst", "type": "address" },
+      { "indexed": false, "name": "wad", "type": "uint256" }
+    ],
+    "name": "Transfer",
+    "type": "event"
+  },
+  {
+    "anonymous": false,
+    "inputs": [
+      { "indexed": true, "name": "dst", "type": "address" },
+      { "indexed": false, "name": "wad", "type": "uint256" }
+    ],
+    "name": "Deposit",
+    "type": "event"
+  },
+  {
+    "anonymous": false,
+    "inputs": [
+      { "indexed": true, "name": "src", "type": "address" },
+      { "indexed": false, "name": "wad", "type": "uint256" }
+    ],
+    "name": "Withdrawal",
+    "type": "event"
+  }
+]
diff --git a/examples/contract_abi.json b/examples/contracts/examples/abi/contract_abi.json
similarity index 100%
rename from examples/contract_abi.json
rename to examples/contracts/examples/abi/contract_abi.json
diff --git a/examples/contracts/examples/abigen.rs b/examples/contracts/examples/abigen.rs
new file mode 100644
index 00000000..b29fa2b2
--- /dev/null
+++ b/examples/contracts/examples/abigen.rs
@@ -0,0 +1,77 @@
+use ethers::{
+    prelude::{abigen, Abigen},
+    providers::{Http, Provider},
+    types::Address,
+};
+use eyre::Result;
+use std::sync::Arc;
+
+/// Abigen is used to generate Rust code to interact with smart contracts on the blockchain.
+/// It provides a way to encode and decode data that is passed to and from smart contracts.
+/// The output of abigen is Rust code, that is bound to the contract's interface, allowing
+/// developers to call its methods to read/write on-chain state and subscribe to realtime events.
+///
+/// The abigen tool can be used in two ways, addressing different use-cases scenarios and developer
+/// taste:
+///
+/// 1. **Rust file generation:** takes a smart contract's Application Binary Interface (ABI)
+/// file and generates a Rust file to interact with it. This is useful if the smart contract is
+/// referenced in different places in a project. File generation from ABI can also be easily
+/// included as a build step of your application.
+/// 2. **Rust inline generation:** takes a smart contract's solidity definition and generates inline
+/// Rust code to interact with it. This is useful for fast prototyping and for tight scoped
+/// use-cases of your contracts.
+/// 3. **Rust inline generation from ABI:** similar to the previous point but instead of Solidity
+/// code takes in input a smart contract's Application Binary Interface (ABI) file.
+#[tokio::main]
+async fn main() -> Result<()> {
+    rust_file_generation()?;
+    rust_inline_generation().await?;
+    rust_inline_generation_from_abi();
+    Ok(())
+}
+
+fn rust_file_generation() -> Result<()> {
+    let base_dir = "./examples/contracts/examples/abi";
+    Abigen::new("IERC20", format!("{base_dir}/IERC20.json"))?
+        .generate()?
+        .write_to_file(format!("{base_dir}/ierc20.rs"))?;
+    Ok(())
+}
+
+fn rust_inline_generation_from_abi() {
+    abigen!(IERC20, "./examples/contracts/examples/abi/IERC20.json");
+}
+
+async fn rust_inline_generation() -> Result<()> {
+    // The abigen! macro expands the contract's code in the current scope
+    // so that you can interface your Rust program with the blockchain
+    // counterpart of the contract.
+    abigen!(
+        IERC20,
+        r#"[
+            function totalSupply() external view returns (uint256)
+            function balanceOf(address account) external view returns (uint256)
+            function transfer(address recipient, uint256 amount) external returns (bool)
+            function allowance(address owner, address spender) external view returns (uint256)
+            function approve(address spender, uint256 amount) external returns (bool)
+            function transferFrom( address sender, address recipient, uint256 amount) external returns (bool)
+            event Transfer(address indexed from, address indexed to, uint256 value)
+            event Approval(address indexed owner, address indexed spender, uint256 value)
+        ]"#,
+    );
+
+    const RPC_URL: &str = "https://mainnet.infura.io/v3/c60b0bb42f8a4c6481ecd229eddaca27";
+    const WETH_ADDRESS: &str = "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2";
+
+    let provider = Provider::<Http>::try_from(RPC_URL)?;
+    let client = Arc::new(provider);
+    let address: Address = WETH_ADDRESS.parse()?;
+    let contract = IERC20::new(address, client);
+
+    if let Ok(total_supply) = contract.total_supply().call().await {
+        println!("WETH total supply is {total_supply:?}");
+    }
+
+    Ok(())
+}
diff --git a/examples/abigen.rs b/examples/contracts/examples/compile.rs
similarity index 77%
rename from examples/abigen.rs
rename to examples/contracts/examples/compile.rs
index e0886687..21b7586a 100644
--- a/examples/abigen.rs
+++ b/examples/contracts/examples/compile.rs
@@ -1,11 +1,14 @@
-use ethers::{contract::Abigen, solc::Solc};
+use ethers::{prelude::Abigen, solc::Solc};
+use eyre::Result;
 
-fn main() -> eyre::Result<()> {
+fn main() -> Result<()> {
     let mut args = std::env::args();
     args.next().unwrap(); // skip program name
 
     let contract_name = args.next().unwrap_or_else(|| "SimpleStorage".to_owned());
-    let contract: String = args.next().unwrap_or_else(|| "examples/contract.sol".to_owned());
+    let contract: String = args
+        .next()
+        .unwrap_or_else(|| "examples/contracts/examples/contracts/contract.sol".to_owned());
 
     println!("Generating bindings for {contract}\n");
 
diff --git a/examples/contract.sol b/examples/contracts/examples/contracts/contract.sol
similarity index 93%
rename from examples/contract.sol
rename to examples/contracts/examples/contracts/contract.sol
index 9d04f2f4..e9910f32 100644
--- a/examples/contract.sol
+++ b/examples/contracts/examples/contracts/contract.sol
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: Unlicense
 pragma solidity >=0.4.24;
 
 contract SimpleStorage {
diff --git a/examples/contract_human_readable.rs b/examples/contracts/examples/deploy_anvil.rs
similarity index 90%
rename from examples/contract_human_readable.rs
rename to examples/contracts/examples/deploy_anvil.rs
index d0ca18c7..7ef77176 100644
--- a/examples/contract_human_readable.rs
+++ b/examples/contracts/examples/deploy_anvil.rs
@@ -1,10 +1,13 @@
 use ethers::{
-    prelude::*,
-    solc::{Project, ProjectPathsConfig},
-    utils::Anvil,
+    contract::{abigen, ContractFactory},
+    core::utils::Anvil,
+    middleware::SignerMiddleware,
+    providers::{Http, Provider},
+    signers::{LocalWallet, Signer},
+    solc::{Artifact, Project, ProjectPathsConfig},
 };
 use eyre::Result;
-use std::{convert::TryFrom, path::PathBuf, sync::Arc, time::Duration};
+use std::{path::PathBuf, sync::Arc, time::Duration};
 
 // Generate the type-safe contract bindings by providing the ABI
 // definition in human readable format
diff --git a/examples/contract_with_abi_and_bytecode.rs b/examples/contracts/examples/deploy_from_abi_and_bytecode.rs
similarity index 89%
rename from examples/contract_with_abi_and_bytecode.rs
rename to examples/contracts/examples/deploy_from_abi_and_bytecode.rs
index 2748e252..1dd91f37 100644
--- a/examples/contract_with_abi_and_bytecode.rs
+++ b/examples/contracts/examples/deploy_from_abi_and_bytecode.rs
@@ -1,4 +1,10 @@
-use ethers::{prelude::*, utils::Anvil};
+use ethers::{
+    contract::abigen,
+    core::utils::Anvil,
+    middleware::SignerMiddleware,
+    providers::{Http, Provider},
+    signers::{LocalWallet, Signer},
+};
 use eyre::Result;
 use std::{convert::TryFrom, sync::Arc, time::Duration};
 
diff --git a/examples/contract_with_abi.rs b/examples/contracts/examples/deploy_from_solidity.rs
similarity index 85%
rename from examples/contract_with_abi.rs
rename to examples/contracts/examples/deploy_from_solidity.rs
index c77d094f..fa6fb365 100644
--- a/examples/contract_with_abi.rs
+++ b/examples/contracts/examples/deploy_from_solidity.rs
@@ -1,4 +1,11 @@
-use ethers::{prelude::*, utils::Anvil};
+use ethers::{
+    contract::{abigen, ContractFactory},
+    core::utils::Anvil,
+    middleware::SignerMiddleware,
+    providers::{Http, Provider},
+    signers::{LocalWallet, Signer},
+    solc::Solc,
+};
 use eyre::Result;
 use std::{convert::TryFrom, path::Path, sync::Arc, time::Duration};
 
@@ -6,7 +13,7 @@ use std::{convert::TryFrom, path::Path, sync::Arc, time::Duration};
 // definition
 abigen!(
     SimpleContract,
-    "./examples/contract_abi.json",
+    "./examples/contracts/examples/abi/contract_abi.json",
     event_derives(serde::Deserialize, serde::Serialize)
 );
 
@@ -17,8 +24,8 @@ async fn main() -> Result<()> {
     let anvil = Anvil::new().spawn();
 
     // set the path to the contract, `CARGO_MANIFEST_DIR` points to the directory containing the
-    // manifest of `ethers`. which will be `../` relative to this file
-    let source = Path::new(&env!("CARGO_MANIFEST_DIR")).join("examples/contract.sol");
+    // manifest of `example/contracts`. which will be `../` relative to this file
+    let source = Path::new(&env!("CARGO_MANIFEST_DIR")).join("examples/contracts/contract.sol");
     let compiled = Solc::default().compile_source(source).expect("Could not compile contracts");
     let (abi, bytecode, _runtime_bytecode) =
         compiled.find("SimpleStorage").expect("could not find contract").into_parts_or_default();
diff --git a/examples/moonbeam_with_abi.rs b/examples/contracts/examples/deploy_moonbeam.rs
similarity index 95%
rename from examples/moonbeam_with_abi.rs
rename to examples/contracts/examples/deploy_moonbeam.rs
index e17500bc..a26464c8 100644
--- a/examples/moonbeam_with_abi.rs
+++ b/examples/contracts/examples/deploy_moonbeam.rs
@@ -1,8 +1,8 @@
-use ethers::prelude::*;
+use ethers::contract::abigen;
 
 abigen!(
     SimpleContract,
-    "./examples/contract_abi.json",
+    "./examples/contracts/examples/abi/contract_abi.json",
     event_derives(serde::Deserialize, serde::Serialize)
 );
 
@@ -19,7 +19,9 @@ abigen!(
 #[tokio::main]
 #[cfg(feature = "legacy")]
 async fn main() -> eyre::Result<()> {
+    use ethers::prelude::*;
     use std::{convert::TryFrom, path::Path, sync::Arc, time::Duration};
+
     const MOONBEAM_DEV_ENDPOINT: &str = "http://localhost:9933";
 
     // set the path to the contract, `CARGO_MANIFEST_DIR` points to the directory containing the
diff --git a/examples/contracts/examples/events.rs b/examples/contracts/examples/events.rs
new file mode 100644
index 00000000..4039d883
--- /dev/null
+++ b/examples/contracts/examples/events.rs
@@ -0,0 +1,68 @@
+use ethers::{
+    contract::abigen,
+    core::types::Address,
+    providers::{Provider, StreamExt, Ws},
+};
+use eyre::Result;
+use std::sync::Arc;
+
+abigen!(
+    IERC20,
+    r#"[
+        event Transfer(address indexed from, address indexed to, uint256 value)
+        event Approval(address indexed owner, address indexed spender, uint256 value)
+    ]"#,
+);
+
+const WSS_URL: &str = "wss://mainnet.infura.io/ws/v3/c60b0bb42f8a4c6481ecd229eddaca27";
+const WETH_ADDRESS: &str = "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2";
+
+#[tokio::main]
+async fn main() -> Result<()> {
+    let provider = Provider::<Ws>::connect(WSS_URL).await?;
+    let client = Arc::new(provider);
+    let address: Address = WETH_ADDRESS.parse()?;
+    let contract = IERC20::new(address, client);
+
+    listen_all_events(&contract).await?;
+    listen_specific_events(&contract).await?;
+
+    Ok(())
+}
+
+/// Given a contract instance, subscribe to all possible events.
+/// This allows to centralize the event handling logic and dispatch
+/// proper actions.
+///
+/// Note that all event bindings have been generated
+/// by abigen. Feel free to investigate the abigen expanded code to
+/// better understand types and functionalities.
+async fn listen_all_events(contract: &IERC20<Provider<Ws>>) -> Result<()> {
+    let events = contract.events().from_block(16232696);
+    let mut stream = events.stream().await?.take(1);
+
+    while let Some(Ok(evt)) = stream.next().await {
+        match evt {
+            IERC20Events::ApprovalFilter(f) => println!("{f:?}"),
+            IERC20Events::TransferFilter(f) => println!("{f:?}"),
+        }
+    }
+
+    Ok(())
+}
+
+/// Given a contract instance subscribe to a single type of event.
+///
+/// Note that all event bindings have been generated
+/// by abigen. Feel free to investigate the abigen expanded code to
+/// better understand types and functionalities.
+async fn listen_specific_events(contract: &IERC20<Provider<Ws>>) -> Result<()> {
+    let events = contract.event::<ApprovalFilter>().from_block(16232696);
+    let mut stream = events.stream().await?.take(1);
+
+    while let Some(Ok(f)) = stream.next().await {
+        println!("ApprovalFilter event: {f:?}");
+    }
+
+    Ok(())
+}
diff --git a/examples/subscribe_contract_events_with_meta.rs b/examples/contracts/examples/events_with_meta.rs
similarity index 80%
rename from examples/subscribe_contract_events_with_meta.rs
rename to examples/contracts/examples/events_with_meta.rs
index c81b4da8..ceb0c68e 100644
--- a/examples/subscribe_contract_events_with_meta.rs
+++ b/examples/contracts/examples/events_with_meta.rs
@@ -1,4 +1,8 @@
-use ethers::prelude::*;
+use ethers::{
+    contract::abigen,
+    core::types::Address,
+    providers::{Provider, StreamExt, Ws},
+};
 use eyre::Result;
 use std::sync::Arc;
 
@@ -11,9 +15,6 @@ abigen!(
     ]"#,
 );
 
-// In order to run this example you need to include Ws and TLS features
-// Run this example with
-// `cargo run -p ethers --example subscribe_contract_events_with_meta --features="ws","rustls"`
 #[tokio::main]
 async fn main() -> Result<()> {
     let client =
@@ -27,8 +28,8 @@ async fn main() -> Result<()> {
     let weth = ERC20::new(address, Arc::clone(&client));
 
     // Subscribe Transfer events
-    let events = weth.events();
-    let mut stream = events.stream().await?.with_meta();
+    let events = weth.events().from_block(16232698);
+    let mut stream = events.stream().await?.with_meta().take(1);
     while let Some(Ok((event, meta))) = stream.next().await {
         println!("src: {:?}, dst: {:?}, wad: {:?}", event.src, event.dst, event.wad);
 
diff --git a/examples/contracts/examples/instances.rs b/examples/contracts/examples/instances.rs
new file mode 100644
index 00000000..7f755fb7
--- /dev/null
+++ b/examples/contracts/examples/instances.rs
@@ -0,0 +1,2 @@
+#[tokio::main]
+async fn main() {}
diff --git a/examples/contracts/examples/methods.rs b/examples/contracts/examples/methods.rs
new file mode 100644
index 00000000..7f755fb7
--- /dev/null
+++ b/examples/contracts/examples/methods.rs
@@ -0,0 +1,2 @@
+#[tokio::main]
+async fn main() {}
diff --git a/examples/contract_with_abi_and_structs.rs b/examples/contracts/examples/methods_abi_and_structs.rs
similarity index 82%
rename from examples/contract_with_abi_and_structs.rs
rename to examples/contracts/examples/methods_abi_and_structs.rs
index b74c9ea9..87b08c52 100644
--- a/examples/contract_with_abi_and_structs.rs
+++ b/examples/contracts/examples/methods_abi_and_structs.rs
@@ -1,7 +1,17 @@
 //! Main entry point for ContractMonitor
 
-use ethers::{prelude::*, utils::Anvil};
-use std::{convert::TryFrom, sync::Arc, time::Duration};
+use std::{sync::Arc, time::Duration};
+
+use ethers::{
+    contract::abigen,
+    core::{
+        types::{Address, U256},
+        utils::Anvil,
+    },
+    middleware::SignerMiddleware,
+    providers::{Http, Provider},
+    signers::LocalWallet,
+};
 
 abigen!(VerifierContract, "ethers-contract/tests/solidity-contracts/verifier_abi.json");
 
diff --git a/examples/ethers-wasm/Cargo.toml b/examples/ethers-wasm/Cargo.toml
index 181e0f81..6ca4f575 100644
--- a/examples/ethers-wasm/Cargo.toml
+++ b/examples/ethers-wasm/Cargo.toml
@@ -1,7 +1,7 @@
 [package]
 name = "ethers-wasm"
 version = "0.1.0"
-edition = "2018"
+edition = "2021"
 rust-version = "1.64"
 authors = ["Matthias Seitz <matthias.seitz@outlook.de>"]
 license = "MIT OR Apache-2.0"
diff --git a/examples/ethers-wasm/abi/contract_abi.json b/examples/ethers-wasm/abi/contract_abi.json
new file mode 100644
index 00000000..12de10c8
--- /dev/null
+++ b/examples/ethers-wasm/abi/contract_abi.json
@@ -0,0 +1,1 @@
+[{"inputs":[{"internalType":"string","name":"value","type":"string"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"author","type":"address"},{"indexed":false,"internalType":"string","name":"oldValue","type":"string"},{"indexed":false,"internalType":"string","name":"newValue","type":"string"}],"name":"ValueChanged","type":"event"},{"inputs":[],"name":"getValue","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"value","type":"string"}],"name":"setValue","outputs":[],"stateMutability":"nonpayable","type":"function"}]
diff --git a/examples/ethers-wasm/src/lib.rs b/examples/ethers-wasm/src/lib.rs
index 2e18ad03..273836ce 100644
--- a/examples/ethers-wasm/src/lib.rs
+++ b/examples/ethers-wasm/src/lib.rs
@@ -24,7 +24,7 @@ macro_rules! log {
 
 abigen!(
     SimpleContract,
-    "./../contract_abi.json",
+    "./abi/contract_abi.json",
     event_derives(serde::Deserialize, serde::Serialize)
 );
 
diff --git a/examples/events/Cargo.toml b/examples/events/Cargo.toml
new file mode 100644
index 00000000..4330bdf7
--- /dev/null
+++ b/examples/events/Cargo.toml
@@ -0,0 +1,13 @@
+[package]
+name = "examples-events"
+version = "1.0.2"
+authors = ["Andrea Simeoni <andreasimeoni84@gmail.com>"]
+edition = "2021"
+
+[dev-dependencies]
+ethers = { path = "../..", version = "1.0.0" }
+
+eyre = "0.6"
+serde = { version = "1.0.144", features = ["derive"] }
+serde_json = "1.0.64"
+tokio = { version = "1.18", features = ["macros"] }
\ No newline at end of file
diff --git a/examples/events/README.md b/examples/events/README.md
new file mode 100644
index 00000000..e69de29b
diff --git a/examples/events/examples/placeholder.rs b/examples/events/examples/placeholder.rs
new file mode 100644
index 00000000..7f755fb7
--- /dev/null
+++ b/examples/events/examples/placeholder.rs
@@ -0,0 +1,2 @@
+#[tokio::main]
+async fn main() {}
diff --git a/examples/middleware/Cargo.toml b/examples/middleware/Cargo.toml
new file mode 100644
index 00000000..0c6eb85d
--- /dev/null
+++ b/examples/middleware/Cargo.toml
@@ -0,0 +1,15 @@
+[package]
+name = "examples-middleware"
+version = "1.0.2"
+authors = ["Andrea Simeoni <andreasimeoni84@gmail.com>"]
+edition = "2021"
+
+[dev-dependencies]
+ethers = { path = "../..", version = "1.0.0", features = ["rustls", "ws"] }
+
+async-trait = { version = "0.1.50", default-features = false }
+eyre = "0.6"
+serde_json = "1.0.61"
+thiserror = { version = "1.0", default-features = false }
+tokio = { version = "1.18", features = ["macros", "rt", "rt-multi-thread"] }
+
diff --git a/examples/middleware/README.md b/examples/middleware/README.md
new file mode 100644
index 00000000..e69de29b
diff --git a/examples/middleware/examples/builder.rs b/examples/middleware/examples/builder.rs
new file mode 100644
index 00000000..c9fb058a
--- /dev/null
+++ b/examples/middleware/examples/builder.rs
@@ -0,0 +1,62 @@
+use ethers::{
+    core::types::BlockNumber,
+    middleware::{
+        gas_escalator::{Frequency, GasEscalatorMiddleware, GeometricGasPrice},
+        gas_oracle::{GasNow, GasOracleMiddleware},
+        MiddlewareBuilder, NonceManagerMiddleware, SignerMiddleware,
+    },
+    providers::{Http, Middleware, Provider},
+    signers::{LocalWallet, Signer},
+};
+use std::convert::TryFrom;
+
+const RPC_URL: &str = "https://mainnet.infura.io/v3/c60b0bb42f8a4c6481ecd229eddaca27";
+const SIGNING_KEY: &str = "fdb33e2105f08abe41a8ee3b758726a31abdd57b7a443f470f23efce853af169";
+
+/// In ethers-rs, middleware is a way to customize the behavior of certain aspects of the library by
+/// injecting custom logic into the process of sending transactions and interacting with contracts
+/// on the Ethereum blockchain. The MiddlewareBuilder trait provides a way to define a chain of
+/// middleware that will be called at different points in this process, allowing you to customize
+/// the behavior of the Provider based on your needs.
+#[tokio::main]
+async fn main() {
+    builder_example().await;
+    builder_example_raw_wrap().await;
+}
+
+async fn builder_example() {
+    let signer = SIGNING_KEY.parse::<LocalWallet>().unwrap();
+    let address = signer.address();
+    let escalator = GeometricGasPrice::new(1.125, 60_u64, None::<u64>);
+    let gas_oracle = GasNow::new();
+
+    let provider = Provider::<Http>::try_from(RPC_URL)
+        .unwrap()
+        .wrap_into(|p| GasEscalatorMiddleware::new(p, escalator, Frequency::PerBlock))
+        .gas_oracle(gas_oracle)
+        .with_signer(signer)
+        .nonce_manager(address); // Outermost layer
+
+    match provider.get_block(BlockNumber::Latest).await {
+        Ok(Some(block)) => println!("{:?}", block.number),
+        _ => println!("Unable to get latest block"),
+    }
+}
+
+async fn builder_example_raw_wrap() {
+    let signer = SIGNING_KEY.parse::<LocalWallet>().unwrap();
+    let address = signer.address();
+    let escalator = GeometricGasPrice::new(1.125, 60_u64, None::<u64>);
+
+    let provider = Provider::<Http>::try_from(RPC_URL)
+        .unwrap()
+        .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
+
+    match provider.get_block(BlockNumber::Latest).await {
+        Ok(Some(block)) => println!("{:?}", block.number),
+        _ => println!("Unable to get latest block"),
+    }
+}
diff --git a/examples/middleware/examples/create_custom_middleware.rs b/examples/middleware/examples/create_custom_middleware.rs
new file mode 100644
index 00000000..56a4a21d
--- /dev/null
+++ b/examples/middleware/examples/create_custom_middleware.rs
@@ -0,0 +1,156 @@
+use async_trait::async_trait;
+use ethers::{
+    core::{
+        types::{transaction::eip2718::TypedTransaction, BlockId, TransactionRequest, U256},
+        utils::{parse_units, Anvil},
+    },
+    middleware::MiddlewareBuilder,
+    providers::{FromErr, Http, Middleware, PendingTransaction, Provider},
+    signers::{LocalWallet, Signer},
+};
+use thiserror::Error;
+
+/// This example demonstrates the mechanisms for creating custom middlewares in ethers-rs.
+/// The example includes explanations of the process and code snippets to illustrate the
+/// concepts. It is intended for developers who want to learn how to customize the behavior of
+/// ethers-rs providers by creating and using custom middlewares.
+///
+/// This custom middleware increases the gas value of transactions sent through an ethers-rs
+/// provider by a specified percentage and will be called for each transaction before it is sent.
+/// This can be useful if you want to ensure that transactions have a higher gas value than the
+/// estimated, in order to improve the chances of them not to run out of gas when landing on-chain.
+#[derive(Debug)]
+struct GasMiddleware<M> {
+    inner: M,
+    /// This value is used to raise the gas value before sending transactions
+    contingency: U256,
+}
+
+/// Contingency is expressed with 4 units
+/// e.g.
+/// 50% => 1 + 0.5  => 15000
+/// 20% => 1 + 0.2  => 12000
+/// 1%  => 1 + 0.01 => 10100
+const CONTINGENCY_UNITS: usize = 4;
+
+impl<M> GasMiddleware<M>
+where
+    M: Middleware,
+{
+    /// Creates an instance of GasMiddleware
+    /// `ìnner` the inner Middleware
+    /// `perc` This is an unsigned integer representing the percentage increase in the amount of gas
+    /// to be used for the transaction. The percentage is relative to the gas value specified in the
+    /// transaction. Valid contingency values are in range 1..=50. Otherwise a custom middleware
+    /// error is raised.
+    pub fn new(inner: M, perc: u32) -> Result<Self, GasMiddlewareError<M>> {
+        let contingency = match perc {
+            0 => Err(GasMiddlewareError::TooLowContingency(perc))?,
+            51.. => Err(GasMiddlewareError::TooHighContingency(perc))?,
+            1..=50 => {
+                let decimals = 2;
+                let perc = U256::from(perc) * U256::exp10(decimals); // e.g. 50 => 5000
+                let one = parse_units(1, CONTINGENCY_UNITS).unwrap();
+                let one = U256::from(one);
+                one + perc // e.g. 50% => 1 + 0.5 => 10000 + 5000 => 15000
+            }
+        };
+
+        Ok(Self { inner, contingency })
+    }
+}
+
+/// Let's implement the `Middleware` trait for our custom middleware.
+/// All trait functions are derived automatically, so we just need to
+/// override the needed functions.
+#[async_trait]
+impl<M> Middleware for GasMiddleware<M>
+where
+    M: Middleware,
+{
+    type Error = GasMiddlewareError<M>;
+    type Provider = M::Provider;
+    type Inner = M;
+
+    fn inner(&self) -> &M {
+        &self.inner
+    }
+
+    /// In this function we bump the transaction gas value by the specified percentage
+    /// This can raise a custom middleware error if a gas amount was not set for
+    /// the transaction.
+    async fn send_transaction<T: Into<TypedTransaction> + Send + Sync>(
+        &self,
+        tx: T,
+        block: Option<BlockId>,
+    ) -> Result<PendingTransaction<'_, Self::Provider>, Self::Error> {
+        let mut tx: TypedTransaction = tx.into();
+
+        let curr_gas: U256 = match tx.gas() {
+            Some(gas) => gas.to_owned(),
+            None => Err(GasMiddlewareError::NoGasSetForTransaction)?,
+        };
+
+        println!("Original transaction gas: {curr_gas:?} wei");
+        let units: U256 = U256::exp10(CONTINGENCY_UNITS);
+        let raised_gas: U256 = (curr_gas * self.contingency) / units;
+        tx.set_gas(raised_gas);
+        println!("Raised transaction gas: {raised_gas:?} wei");
+
+        // Dispatch the call to the inner layer
+        self.inner().send_transaction(tx, block).await.map_err(FromErr::from)
+    }
+}
+
+/// This example demonstrates how to handle errors in custom middlewares. It shows how to define
+/// custom error types, use them in middleware implementations, and how to propagate the errors
+/// through the middleware chain. This is intended for developers who want to create custom
+/// middlewares that can handle and propagate errors in a consistent and robust way.
+#[derive(Error, Debug)]
+pub enum GasMiddlewareError<M: Middleware> {
+    /// Thrown when the internal middleware errors
+    #[error("{0}")]
+    MiddlewareError(M::Error),
+    /// Specific errors of this GasMiddleware.
+    /// Please refer to the `thiserror` crate for
+    /// further docs.
+    #[error("{0}")]
+    TooHighContingency(u32),
+    #[error("{0}")]
+    TooLowContingency(u32),
+    #[error("Cannot raise gas! Gas value not provided for this transaction.")]
+    NoGasSetForTransaction,
+}
+
+impl<M: Middleware> FromErr<M::Error> for GasMiddlewareError<M> {
+    fn from(src: M::Error) -> Self {
+        GasMiddlewareError::MiddlewareError(src)
+    }
+}
+
+#[tokio::main]
+async fn main() -> eyre::Result<()> {
+    let anvil = Anvil::new().spawn();
+
+    let wallet: LocalWallet = anvil.keys()[0].clone().into();
+    let wallet2: LocalWallet = anvil.keys()[1].clone().into();
+    let signer = wallet.with_chain_id(anvil.chain_id());
+
+    let gas_raise_perc = 50; // 50%;
+    let provider = Provider::<Http>::try_from(anvil.endpoint())?
+        .with_signer(signer)
+        .wrap_into(|s| GasMiddleware::new(s, gas_raise_perc).unwrap());
+
+    let gas = 15000;
+    let tx = TransactionRequest::new().to(wallet2.address()).value(10000).gas(gas);
+
+    let pending_tx = provider.send_transaction(tx, None).await?;
+
+    let receipt = pending_tx.await?.ok_or_else(|| eyre::format_err!("tx dropped from mempool"))?;
+    let tx = provider.get_transaction(receipt.transaction_hash).await?;
+
+    println!("Sent tx: {}\n", serde_json::to_string(&tx)?);
+    println!("Tx receipt: {}", serde_json::to_string(&receipt)?);
+
+    Ok(())
+}
diff --git a/examples/middleware/examples/gas_escalator.rs b/examples/middleware/examples/gas_escalator.rs
new file mode 100644
index 00000000..c60d304c
--- /dev/null
+++ b/examples/middleware/examples/gas_escalator.rs
@@ -0,0 +1,59 @@
+use ethers::{
+    core::{types::TransactionRequest, utils::Anvil},
+    middleware::gas_escalator::*,
+    providers::{Http, Middleware, Provider},
+};
+use eyre::Result;
+
+/// The gas escalator middleware in ethers-rs is designed to automatically increase the gas cost of
+/// transactions if they get stuck in the mempool. This can be useful if you want to
+/// ensure that transactions are processed in a timely manner without having to manually adjust the
+/// gas cost yourself.
+#[tokio::main]
+async fn main() -> Result<()> {
+    let every_secs: u64 = 60;
+    let max_price: Option<i32> = None;
+
+    // Linearly increase gas price:
+    // Start with `initial_price`, then increase it by fixed amount `increase_by` every `every_secs`
+    // seconds until the transaction gets confirmed. There is an optional upper limit.
+    let increase_by: i32 = 100;
+    let linear_escalator = LinearGasPrice::new(increase_by, every_secs, max_price);
+    send_escalating_transaction(linear_escalator).await?;
+
+    // Geometrically increase gas price:
+    // Start with `initial_price`, then increase it every 'every_secs' seconds by a fixed
+    // coefficient. Coefficient defaults to 1.125 (12.5%), the minimum increase for Parity to
+    // replace a transaction. Coefficient can be adjusted, and there is an optional upper limit.
+    let coefficient: f64 = 1.125;
+    let geometric_escalator = GeometricGasPrice::new(coefficient, every_secs, max_price);
+    send_escalating_transaction(geometric_escalator).await?;
+
+    Ok(())
+}
+
+async fn send_escalating_transaction<E>(escalator: E) -> Result<()>
+where
+    E: GasEscalator + Clone + 'static,
+{
+    // Spawn local node
+    let anvil = Anvil::new().spawn();
+    let endpoint = anvil.endpoint();
+
+    // Connect to the node
+    let provider = Provider::<Http>::try_from(endpoint)?;
+    let provider = GasEscalatorMiddleware::new(provider, escalator, Frequency::PerBlock);
+
+    let accounts = provider.get_accounts().await?;
+    let from = accounts[0];
+    let to = accounts[1];
+    let tx = TransactionRequest::new().from(from).to(to).value(1000);
+
+    // Bumps the gas price until transaction gets mined
+    let pending_tx = provider.send_transaction(tx, None).await?;
+    let receipt = pending_tx.await?;
+
+    println!("{receipt:?}");
+
+    Ok(())
+}
diff --git a/examples/middleware/examples/gas_oracle.rs b/examples/middleware/examples/gas_oracle.rs
new file mode 100644
index 00000000..95105aeb
--- /dev/null
+++ b/examples/middleware/examples/gas_oracle.rs
@@ -0,0 +1,88 @@
+use ethers::{
+    core::types::Chain,
+    etherscan::Client,
+    middleware::gas_oracle::{
+        BlockNative, Etherscan, GasCategory, GasNow, GasOracle, Polygon, ProviderOracle,
+    },
+    providers::{Http, Provider},
+};
+
+/// In Ethereum, the "gas" of a transaction refers to the amount of computation required to execute
+/// the transaction on the blockchain. Gas is typically measured in units of "gas," and the cost of
+/// a transaction is determined by the amount of gas it consumes.
+///
+/// A "gas oracle" is a tool or service that provides information about the current price of gas on
+/// the Ethereum network. Gas oracles are often used to help determine the appropriate amount of gas
+/// to include in a transaction, in order to ensure that it will be processed in a timely manner
+/// without running out of gas.
+///
+/// Ethers-rs includes a feature called "gas oracle middleware" that allows you to customize the
+/// behavior of the library when it comes to determining the gas cost of transactions.
+#[tokio::main]
+async fn main() {
+    blocknative().await;
+    etherscan().await;
+    gas_now().await;
+    polygon().await;
+    provider_oracle().await;
+    //etherchain().await; // FIXME: Etherchain URL is broken (Http 404)
+}
+
+async fn blocknative() {
+    let api_key: Option<String> = std::env::var("BLOCK_NATIVE_API_KEY").ok();
+    let oracle = BlockNative::new(api_key).category(GasCategory::Fastest);
+    match oracle.fetch().await {
+        Ok(gas_price) => println!("[Blocknative]: Gas price is {gas_price:?}"),
+        Err(e) => panic!("[Blocknative]: Cannot estimate gas: {e:?}"),
+    }
+}
+
+async fn etherscan() {
+    let chain = Chain::Mainnet;
+    let api_key: String = std::env::var("ETHERSCAN_API_KEY_ETHEREUM").expect("Provide an API key");
+    if let Ok(client) = Client::new(chain, api_key) {
+        let oracle = Etherscan::new(client).category(GasCategory::Fast);
+        match oracle.fetch().await {
+            Ok(gas_price) => println!("[Etherscan]: Gas price is {gas_price:?}"),
+            Err(e) => panic!("[Etherscan]: Cannot estimate gas: {e:?}"),
+        }
+    }
+}
+
+async fn gas_now() {
+    let oracle = GasNow::new().category(GasCategory::Fast);
+    match oracle.fetch().await {
+        Ok(gas_price) => println!("[GasNow]: Gas price is {gas_price:?}"),
+        Err(e) => panic!("[GasNow]: Cannot estimate gas: {e:?}"),
+    }
+}
+
+async fn polygon() {
+    let chain = Chain::Polygon;
+    if let Ok(oracle) = Polygon::new(chain) {
+        match oracle.category(GasCategory::SafeLow).fetch().await {
+            Ok(gas_price) => println!("[Polygon]: Gas price is {gas_price:?}"),
+            Err(e) => panic!("[Polygon]: Cannot estimate gas: {e:?}"),
+        }
+    }
+}
+
+async fn provider_oracle() {
+    const RPC_URL: &str = "https://mainnet.infura.io/v3/c60b0bb42f8a4c6481ecd229eddaca27";
+    let provider = Provider::<Http>::try_from(RPC_URL).unwrap();
+    let oracle = ProviderOracle::new(provider);
+    match oracle.fetch().await {
+        Ok(gas_price) => println!("[Provider oracle]: Gas price is {gas_price:?}"),
+        Err(e) => panic!("[Provider oracle]: Cannot estimate gas: {e:?}"),
+    }
+}
+
+/*
+// FIXME: Etherchain URL is broken (Http 404)
+async fn etherchain() {
+    let oracle = Etherchain::new().category(GasCategory::Standard);
+    match oracle.fetch().await {
+        Ok(gas_price) => println!("[Etherchain]: Gas price is {gas_price:?}"),
+        Err(e) => panic!("[Etherchain]: Cannot estimate gas: {e:?}"),
+    }
+}*/
diff --git a/examples/middleware/examples/nonce_manager.rs b/examples/middleware/examples/nonce_manager.rs
new file mode 100644
index 00000000..e76bcc1c
--- /dev/null
+++ b/examples/middleware/examples/nonce_manager.rs
@@ -0,0 +1,46 @@
+use ethers::{
+    core::{
+        types::{BlockNumber, TransactionRequest},
+        utils::Anvil,
+    },
+    middleware::MiddlewareBuilder,
+    providers::{Http, Middleware, Provider},
+};
+use eyre::Result;
+
+/// In Ethereum, the nonce of a transaction is a number that represents the number of transactions
+/// that have been sent from a particular account. The nonce is used to ensure that transactions are
+/// processed in the order they are intended, and to prevent the same transaction from being
+/// processed multiple times.
+///
+/// The nonce manager in ethers-rs is a middleware that helps you manage the nonce
+/// of transactions by keeping track of the current nonce for a given account and automatically
+/// incrementing it as needed. This can be useful if you want to ensure that transactions are sent
+/// in the correct order, or if you want to avoid having to manually manage the nonce yourself.
+#[tokio::main]
+async fn main() -> Result<()> {
+    let anvil = Anvil::new().spawn();
+    let endpoint = anvil.endpoint();
+
+    let provider = Provider::<Http>::try_from(endpoint)?;
+    let accounts = provider.get_accounts().await?;
+    let account = accounts[0];
+    let to = accounts[1];
+    let tx = TransactionRequest::new().from(account).to(to).value(1000);
+
+    let nonce_manager = provider.nonce_manager(account);
+
+    let curr_nonce = nonce_manager
+        .get_transaction_count(account, Some(BlockNumber::Pending.into()))
+        .await?
+        .as_u64();
+
+    assert_eq!(curr_nonce, 0);
+
+    nonce_manager.send_transaction(tx, None).await?;
+    let next_nonce = nonce_manager.next().as_u64();
+
+    assert_eq!(next_nonce, 1);
+
+    Ok(())
+}
diff --git a/examples/middleware/examples/policy.rs b/examples/middleware/examples/policy.rs
new file mode 100644
index 00000000..3e2e0a4b
--- /dev/null
+++ b/examples/middleware/examples/policy.rs
@@ -0,0 +1,39 @@
+use ethers::{
+    core::{types::TransactionRequest, utils::Anvil},
+    middleware::{
+        policy::{PolicyMiddlewareError, RejectEverything},
+        MiddlewareBuilder, PolicyMiddleware,
+    },
+    providers::{Http, Middleware, Provider},
+};
+use eyre::Result;
+
+/// Policy middleware is a way to inject custom logic into the process of sending transactions and
+/// interacting with contracts on the Ethereum blockchain. It allows you to define rules or policies
+/// that should be followed when performing these actions, and to customize the behavior of the
+/// library based on these policies.
+#[tokio::main]
+async fn main() -> Result<()> {
+    let anvil = Anvil::new().spawn();
+    let endpoint = anvil.endpoint();
+
+    let provider = Provider::<Http>::try_from(endpoint)?;
+
+    let accounts = provider.get_accounts().await?;
+    let account = accounts[0];
+    let to = accounts[1];
+    let tx = TransactionRequest::new().from(account).to(to).value(1000);
+
+    let policy = RejectEverything;
+    let policy_middleware = provider.wrap_into(|p| PolicyMiddleware::new(p, policy));
+
+    match policy_middleware.send_transaction(tx, None).await {
+        Err(e) => {
+            // Given the RejectEverything policy, we expect to execute this branch
+            assert!(matches!(e, PolicyMiddlewareError::PolicyError(())))
+        }
+        _ => panic!("We don't expect this to happen!"),
+    }
+
+    Ok(())
+}
diff --git a/examples/middleware/examples/signer.rs b/examples/middleware/examples/signer.rs
new file mode 100644
index 00000000..38ad057c
--- /dev/null
+++ b/examples/middleware/examples/signer.rs
@@ -0,0 +1,40 @@
+use ethers::{
+    core::{types::TransactionRequest, utils::Anvil},
+    middleware::SignerMiddleware,
+    providers::{Http, Middleware, Provider},
+    signers::{LocalWallet, Signer},
+};
+use eyre::Result;
+use std::convert::TryFrom;
+
+/// In Ethereum, transactions must be signed with a private key before they can be broadcast to the
+/// network. Ethers-rs provides a way to customize this process by allowing
+/// you to define a signer, called to sign transactions before they are sent.
+#[tokio::main]
+async fn main() -> Result<()> {
+    let anvil = Anvil::new().spawn();
+
+    let wallet: LocalWallet = anvil.keys()[0].clone().into();
+    let wallet2: LocalWallet = anvil.keys()[1].clone().into();
+
+    // connect to the network
+    let provider = Provider::<Http>::try_from(anvil.endpoint())?;
+
+    // connect the wallet to the provider
+    let client = SignerMiddleware::new(provider, wallet.with_chain_id(anvil.chain_id()));
+
+    // craft the transaction
+    let tx = TransactionRequest::new().to(wallet2.address()).value(10000);
+
+    // send it!
+    let pending_tx = client.send_transaction(tx, None).await?;
+
+    // get the mined tx
+    let receipt = pending_tx.await?.ok_or_else(|| eyre::format_err!("tx dropped from mempool"))?;
+    let tx = client.get_transaction(receipt.transaction_hash).await?;
+
+    println!("Sent tx: {}\n", serde_json::to_string(&tx)?);
+    println!("Tx receipt: {}", serde_json::to_string(&receipt)?);
+
+    Ok(())
+}
diff --git a/examples/middleware/examples/timelag.rs b/examples/middleware/examples/timelag.rs
new file mode 100644
index 00000000..7f755fb7
--- /dev/null
+++ b/examples/middleware/examples/timelag.rs
@@ -0,0 +1,2 @@
+#[tokio::main]
+async fn main() {}
diff --git a/examples/middleware/examples/transformer.rs b/examples/middleware/examples/transformer.rs
new file mode 100644
index 00000000..7f755fb7
--- /dev/null
+++ b/examples/middleware/examples/transformer.rs
@@ -0,0 +1,2 @@
+#[tokio::main]
+async fn main() {}
diff --git a/examples/providers/Cargo.toml b/examples/providers/Cargo.toml
new file mode 100644
index 00000000..71a92210
--- /dev/null
+++ b/examples/providers/Cargo.toml
@@ -0,0 +1,17 @@
+[package]
+name = "examples-providers"
+version = "1.0.2"
+authors = ["Andrea Simeoni <andreasimeoni84@gmail.com>"]
+edition = "2021"
+
+[features]
+default = ["ipc"]
+ipc = []
+
+[dev-dependencies]
+ethers = { path = "../..", version = "1.0.0", features = ["abigen", "ipc", "rustls", "ws"] }
+
+eyre = "0.6"
+serde = { version = "1.0.144", features = ["derive"] }
+serde_json = "1.0.64"
+tokio = { version = "1.18", features = ["macros"] }
diff --git a/examples/providers/README.md b/examples/providers/README.md
new file mode 100644
index 00000000..e69de29b
diff --git a/examples/ipc.rs b/examples/providers/examples/ipc.rs
similarity index 100%
rename from examples/ipc.rs
rename to examples/providers/examples/ipc.rs
diff --git a/examples/quorum.rs b/examples/providers/examples/quorum.rs
similarity index 85%
rename from examples/quorum.rs
rename to examples/providers/examples/quorum.rs
index 95f62af1..a1d50c8c 100644
--- a/examples/quorum.rs
+++ b/examples/providers/examples/quorum.rs
@@ -1,11 +1,15 @@
 //! Example usage for the `QuorumProvider` that requests multiple backends and only returns
 //! a value if the configured `Quorum` was reached.
 
-use ethers::{prelude::*, utils::Anvil};
+use ethers::{
+    core::utils::Anvil,
+    providers::{Http, Middleware, Provider, Quorum, QuorumProvider, WeightedProvider, Ws},
+};
+use eyre::Result;
 use std::{str::FromStr, time::Duration};
 
 #[tokio::main]
-async fn main() -> eyre::Result<()> {
+async fn main() -> Result<()> {
     let anvil = Anvil::new().spawn();
 
     // create a quorum provider with some providers
diff --git a/examples/rw.rs b/examples/providers/examples/rw.rs
similarity index 76%
rename from examples/rw.rs
rename to examples/providers/examples/rw.rs
index 89733a8f..89f1f439 100644
--- a/examples/rw.rs
+++ b/examples/providers/examples/rw.rs
@@ -1,11 +1,15 @@
 //! Example usage for the `RwClient` that uses a didicated client to send transaction and nother one
 //! for read ops
 
-use ethers::{prelude::*, utils::Anvil};
+use ethers::{
+    core::utils::Anvil,
+    providers::{Http, Middleware, Provider, Ws},
+};
+use eyre::Result;
 use std::{str::FromStr, time::Duration};
 
 #[tokio::main]
-async fn main() -> eyre::Result<()> {
+async fn main() -> Result<()> {
     let anvil = Anvil::new().spawn();
 
     let http = Http::from_str(&anvil.endpoint())?;
diff --git a/examples/queries/Cargo.toml b/examples/queries/Cargo.toml
new file mode 100644
index 00000000..fa92ea52
--- /dev/null
+++ b/examples/queries/Cargo.toml
@@ -0,0 +1,13 @@
+[package]
+name = "examples-queries"
+version = "1.0.2"
+authors = ["Andrea Simeoni <andreasimeoni84@gmail.com>"]
+edition = "2021"
+
+[dev-dependencies]
+ethers = { path = "../..", version = "1.0.0", features = ["abigen", "rustls", "ws"] }
+
+eyre = "0.6"
+serde = { version = "1.0.144", features = ["derive"] }
+serde_json = "1.0.64"
+tokio = { version = "1.18", features = ["macros"] }
\ No newline at end of file
diff --git a/examples/queries/README.md b/examples/queries/README.md
new file mode 100644
index 00000000..e69de29b
diff --git a/examples/paginated_logs.rs b/examples/queries/examples/paginated_logs.rs
similarity index 84%
rename from examples/paginated_logs.rs
rename to examples/queries/examples/paginated_logs.rs
index 9f94f9e0..563b90f1 100644
--- a/examples/paginated_logs.rs
+++ b/examples/queries/examples/paginated_logs.rs
@@ -1,4 +1,10 @@
-use ethers::{abi::AbiDecode, prelude::*, providers::Middleware};
+use ethers::{
+    core::{
+        abi::AbiDecode,
+        types::{BlockNumber, Filter, U256},
+    },
+    providers::{Middleware, Provider, StreamExt, Ws},
+};
 use eyre::Result;
 use std::sync::Arc;
 
@@ -15,7 +21,7 @@ async fn main() -> Result<()> {
     let erc20_transfer_filter =
         Filter::new().from_block(last_block - 10000).event("Transfer(address,address,uint256)");
 
-    let mut stream = client.get_logs_paginated(&erc20_transfer_filter, 10);
+    let mut stream = client.get_logs_paginated(&erc20_transfer_filter, 10).take(5);
 
     while let Some(res) = stream.next().await {
         let log = res?;
diff --git a/examples/uniswapv2.rs b/examples/queries/examples/uniswapv2_pair.rs
similarity index 91%
rename from examples/uniswapv2.rs
rename to examples/queries/examples/uniswapv2_pair.rs
index 8b956112..c9d306da 100644
--- a/examples/uniswapv2.rs
+++ b/examples/queries/examples/uniswapv2_pair.rs
@@ -1,4 +1,8 @@
-use ethers::prelude::*;
+use ethers::{
+    contract::abigen,
+    core::types::Address,
+    providers::{Http, Provider},
+};
 use eyre::Result;
 use std::sync::Arc;
 
diff --git a/examples/subscribe_contract_events.rs b/examples/subscribe_contract_events.rs
deleted file mode 100644
index a6f769f9..00000000
--- a/examples/subscribe_contract_events.rs
+++ /dev/null
@@ -1,38 +0,0 @@
-use ethers::prelude::*;
-use eyre::Result;
-use std::sync::Arc;
-
-// Generate the type-safe contract bindings by providing the ABI
-// definition in human readable format
-abigen!(
-    ERC20,
-    r#"[
-        event  Transfer(address indexed src, address indexed dst, uint wad)
-    ]"#,
-);
-
-// In order to run this example you need to include Ws and TLS features
-// Run this example with
-// `cargo run -p ethers --example subscribe_contract_events --features="ws","rustls"`
-#[tokio::main]
-async fn main() -> Result<()> {
-    let client =
-        Provider::<Ws>::connect("wss://mainnet.infura.io/ws/v3/c60b0bb42f8a4c6481ecd229eddaca27")
-            .await?;
-
-    let client = Arc::new(client);
-
-    // WETH Token
-    let address = "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2".parse::<Address>()?;
-    let weth = ERC20::new(address, Arc::clone(&client));
-
-    // Subscribe Transfer events
-    let events = weth.events();
-    let mut stream = events.stream().await?;
-
-    while let Some(Ok(event)) = stream.next().await {
-        println!("src: {:?}, dst: {:?}, wad: {:?}", event.src, event.dst, event.wad);
-    }
-
-    Ok(())
-}
diff --git a/examples/subscriptions/Cargo.toml b/examples/subscriptions/Cargo.toml
new file mode 100644
index 00000000..9dd76878
--- /dev/null
+++ b/examples/subscriptions/Cargo.toml
@@ -0,0 +1,13 @@
+[package]
+name = "examples-subscriptions"
+version = "1.0.2"
+authors = ["Andrea Simeoni <andreasimeoni84@gmail.com>"]
+edition = "2021"
+
+[dev-dependencies]
+ethers = { path = "../..", version = "1.0.0", features = ["abigen", "rustls", "ws"] }
+
+eyre = "0.6"
+serde = { version = "1.0.144", features = ["derive"] }
+serde_json = "1.0.64"
+tokio = { version = "1.18", features = ["macros"] }
\ No newline at end of file
diff --git a/examples/subscriptions/README.md b/examples/subscriptions/README.md
new file mode 100644
index 00000000..e69de29b
diff --git a/examples/subscribe_events_by_type.rs b/examples/subscriptions/examples/subscribe_events_by_type.rs
similarity index 82%
rename from examples/subscribe_events_by_type.rs
rename to examples/subscriptions/examples/subscribe_events_by_type.rs
index 76e394ac..355404a3 100644
--- a/examples/subscribe_events_by_type.rs
+++ b/examples/subscriptions/examples/subscribe_events_by_type.rs
@@ -1,5 +1,10 @@
-use ethers::{contract::Contract, prelude::*};
+use ethers::{
+    contract::{abigen, Contract},
+    core::types::ValueOrArray,
+    providers::{Provider, StreamExt, Ws},
+};
 use std::{error::Error, sync::Arc};
+
 abigen!(
     AggregatorInterface,
     r#"[
@@ -14,10 +19,6 @@ const PRICE_FEED_3: &str = "0xebf67ab8cff336d3f609127e8bbf8bd6dd93cd81";
 /// Subscribe to a typed event stream without requiring a `Contract` instance.
 /// In this example we subscribe Chainlink price feeds and filter out them
 /// by address.
-/// -------------------------------------------------------------------------------
-/// In order to run this example you need to include Ws and TLS features
-/// Run this example with
-/// `cargo run -p ethers --example subscribe_events_by_type --features="ws","rustls"`
 #[tokio::main]
 async fn main() -> Result<(), Box<dyn Error>> {
     let client = get_client().await;
diff --git a/examples/subscribe_logs.rs b/examples/subscriptions/examples/subscribe_logs.rs
similarity index 82%
rename from examples/subscribe_logs.rs
rename to examples/subscriptions/examples/subscribe_logs.rs
index b8cb1891..3ee71259 100644
--- a/examples/subscribe_logs.rs
+++ b/examples/subscriptions/examples/subscribe_logs.rs
@@ -1,9 +1,13 @@
-use ethers::{abi::AbiDecode, prelude::*};
+use ethers::{
+    core::{
+        abi::AbiDecode,
+        types::{Address, BlockNumber, Filter, U256},
+    },
+    providers::{Middleware, Provider, StreamExt, Ws},
+};
 use eyre::Result;
 use std::sync::Arc;
 
-// In order to run this example you need to include Ws and TLS features
-// Run this example with `cargo run -p ethers --example subscribe_logs --features="ws","rustls"`
 #[tokio::main]
 async fn main() -> Result<()> {
     let client =
diff --git a/examples/watch_blocks.rs b/examples/subscriptions/examples/watch_blocks.rs
similarity index 58%
rename from examples/watch_blocks.rs
rename to examples/subscriptions/examples/watch_blocks.rs
index af1385da..38fb90e5 100644
--- a/examples/watch_blocks.rs
+++ b/examples/subscriptions/examples/watch_blocks.rs
@@ -1,12 +1,13 @@
-use ethers::{prelude::*, utils::Anvil};
+use ethers::providers::{Middleware, Provider, StreamExt, Ws};
+use eyre::Result;
 use std::time::Duration;
 
 #[tokio::main]
-async fn main() -> eyre::Result<()> {
-    let anvil = Anvil::new().block_time(1u64).spawn();
-    let ws = Ws::connect(anvil.ws_endpoint()).await?;
+async fn main() -> Result<()> {
+    let ws_endpoint = "wss://mainnet.infura.io/ws/v3/c60b0bb42f8a4c6481ecd229eddaca27";
+    let ws = Ws::connect(ws_endpoint).await?;
     let provider = Provider::new(ws).interval(Duration::from_millis(2000));
-    let mut stream = provider.watch_blocks().await?.take(5);
+    let mut stream = provider.watch_blocks().await?.take(1);
     while let Some(block) = stream.next().await {
         let block = provider.get_block(block).await?.unwrap();
         println!(
diff --git a/examples/transactions/Cargo.toml b/examples/transactions/Cargo.toml
new file mode 100644
index 00000000..6bdf9412
--- /dev/null
+++ b/examples/transactions/Cargo.toml
@@ -0,0 +1,13 @@
+[package]
+name = "examples-transactions"
+version = "1.0.2"
+authors = ["Andrea Simeoni <andreasimeoni84@gmail.com>"]
+edition = "2021"
+
+[dev-dependencies]
+ethers = { path = "../..", version = "1.0.0", features = ["abigen", "rustls", "ws"] }
+
+eyre = "0.6"
+serde = { version = "1.0.144", features = ["derive"] }
+serde_json = "1.0.64"
+tokio = { version = "1.18", features = ["macros"] }
\ No newline at end of file
diff --git a/examples/transactions/README.md b/examples/transactions/README.md
new file mode 100644
index 00000000..e69de29b
diff --git a/examples/call_override.rs b/examples/transactions/examples/call_override.rs
similarity index 90%
rename from examples/call_override.rs
rename to examples/transactions/examples/call_override.rs
index 2237ee1e..b80191e8 100644
--- a/examples/call_override.rs
+++ b/examples/transactions/examples/call_override.rs
@@ -1,14 +1,21 @@
 use ethers::{
-    prelude::*,
-    providers::call_raw::RawCall,
-    utils::{parse_ether, Geth},
+    contract::abigen,
+    core::{
+        types::{Address, TransactionRequest, H256},
+        utils::{parse_ether, Geth},
+    },
+    providers::{
+        call_raw::{self, RawCall},
+        Http, Provider,
+    },
 };
+use eyre::Result;
 use std::sync::Arc;
 
 abigen!(Greeter, "ethers-contract/tests/solidity-contracts/greeter.json",);
 
 #[tokio::main]
-async fn main() -> eyre::Result<()> {
+async fn main() -> Result<()> {
     let geth = Geth::new().spawn();
     let provider = Provider::<Http>::try_from(geth.endpoint()).unwrap();
     let client = Arc::new(provider);
diff --git a/examples/decode_tx_input.rs b/examples/transactions/examples/decode_input.rs
similarity index 94%
rename from examples/decode_tx_input.rs
rename to examples/transactions/examples/decode_input.rs
index f11b6f1b..0eca8c37 100644
--- a/examples/decode_tx_input.rs
+++ b/examples/transactions/examples/decode_input.rs
@@ -1,4 +1,7 @@
-use ethers::{abi::AbiDecode, prelude::*};
+use ethers::{
+    contract::abigen,
+    core::{abi::AbiDecode, types::Bytes},
+};
 use eyre::Result;
 
 // Abigen creates a SwapExactTokensForTokensCall struct that can be used to decode
diff --git a/examples/ens.rs b/examples/transactions/examples/ens.rs
similarity index 87%
rename from examples/ens.rs
rename to examples/transactions/examples/ens.rs
index 5874d5c9..0606288e 100644
--- a/examples/ens.rs
+++ b/examples/transactions/examples/ens.rs
@@ -1,6 +1,8 @@
-use ethers::{prelude::*, utils::Anvil};
+use ethers::{
+    core::{types::TransactionRequest, utils::Anvil},
+    providers::{Http, Middleware, Provider},
+};
 use eyre::Result;
-use std::convert::TryFrom;
 
 #[tokio::main]
 async fn main() -> Result<()> {
diff --git a/examples/gas_price_usd.rs b/examples/transactions/examples/gas_price_usd.rs
similarity index 92%
rename from examples/gas_price_usd.rs
rename to examples/transactions/examples/gas_price_usd.rs
index 307baf82..eef46a72 100644
--- a/examples/gas_price_usd.rs
+++ b/examples/transactions/examples/gas_price_usd.rs
@@ -1,10 +1,18 @@
-use ethers::{prelude::*, utils::format_units};
 use std::{
     error::Error,
     ops::{Div, Mul},
     sync::Arc,
 };
 
+use ethers::{
+    contract::abigen,
+    core::{
+        types::{Address, I256, U256},
+        utils::format_units,
+    },
+    providers::{Http, Middleware, Provider},
+};
+
 abigen!(
     AggregatorInterface,
     r#"[
diff --git a/examples/remove_liquidity.rs b/examples/transactions/examples/remove_liquidity.rs
similarity index 92%
rename from examples/remove_liquidity.rs
rename to examples/transactions/examples/remove_liquidity.rs
index 0d3e889d..587f6436 100644
--- a/examples/remove_liquidity.rs
+++ b/examples/transactions/examples/remove_liquidity.rs
@@ -1,6 +1,13 @@
-use ethers::prelude::*;
+use std::sync::Arc;
+
+use ethers::{
+    contract::abigen,
+    core::types::{Address, U256},
+    middleware::SignerMiddleware,
+    providers::{Http, Middleware, Provider},
+    signers::{LocalWallet, Signer},
+};
 use eyre::Result;
-use std::{convert::TryFrom, sync::Arc};
 
 abigen!(
     UniswapV2Router,
diff --git a/examples/geth_trace_transaction.rs b/examples/transactions/examples/trace.rs
similarity index 85%
rename from examples/geth_trace_transaction.rs
rename to examples/transactions/examples/trace.rs
index ef20f738..35ea370d 100644
--- a/examples/geth_trace_transaction.rs
+++ b/examples/transactions/examples/trace.rs
@@ -1,4 +1,7 @@
-use ethers::prelude::*;
+use ethers::{
+    core::types::{GethDebugTracingOptions, H256},
+    providers::{Http, Middleware, Provider},
+};
 use eyre::Result;
 use std::str::FromStr;
 
diff --git a/examples/transfer_eth.rs b/examples/transactions/examples/transfer_eth.rs
similarity index 90%
rename from examples/transfer_eth.rs
rename to examples/transactions/examples/transfer_eth.rs
index 3be81cc9..00a4e6fc 100644
--- a/examples/transfer_eth.rs
+++ b/examples/transactions/examples/transfer_eth.rs
@@ -1,4 +1,7 @@
-use ethers::{prelude::*, utils::Anvil};
+use ethers::{
+    core::{types::TransactionRequest, utils::Anvil},
+    providers::{Http, Middleware, Provider},
+};
 use eyre::Result;
 use std::convert::TryFrom;
 
diff --git a/examples/wallets/Cargo.toml b/examples/wallets/Cargo.toml
new file mode 100644
index 00000000..c3112132
--- /dev/null
+++ b/examples/wallets/Cargo.toml
@@ -0,0 +1,20 @@
+[package]
+name = "examples-wallets"
+version = "1.0.2"
+authors = ["Andrea Simeoni <andreasimeoni84@gmail.com>"]
+edition = "2021"
+
+[features]
+default = ["ledger", "trezor", "yubi"]
+ledger = []
+trezor = []
+yubi = []
+
+[dev-dependencies]
+ethers = { path = "../..", version = "1.0.0", features = ["abigen", "eip712", "ledger", "rustls", "trezor", "ws", "yubi"] }
+
+eyre = "0.6"
+serde = { version = "1.0.144", features = ["derive"] }
+serde_json = "1.0.64"
+tokio = { version = "1.18", features = ["macros"] }
+
diff --git a/examples/wallets/README.md b/examples/wallets/README.md
new file mode 100644
index 00000000..e69de29b
diff --git a/examples/ledger.rs b/examples/wallets/examples/ledger.rs
similarity index 100%
rename from examples/ledger.rs
rename to examples/wallets/examples/ledger.rs
diff --git a/examples/local_signer.rs b/examples/wallets/examples/local_signer.rs
similarity index 84%
rename from examples/local_signer.rs
rename to examples/wallets/examples/local_signer.rs
index 764de4f5..b7193076 100644
--- a/examples/local_signer.rs
+++ b/examples/wallets/examples/local_signer.rs
@@ -1,4 +1,9 @@
-use ethers::{prelude::*, utils::Anvil};
+use ethers::{
+    core::{types::TransactionRequest, utils::Anvil},
+    middleware::SignerMiddleware,
+    providers::{Http, Middleware, Provider},
+    signers::{LocalWallet, Signer},
+};
 use eyre::Result;
 use std::convert::TryFrom;
 
diff --git a/examples/mnemonic.rs b/examples/wallets/examples/mnemonic.rs
similarity index 87%
rename from examples/mnemonic.rs
rename to examples/wallets/examples/mnemonic.rs
index 2c14b69d..b04aaea9 100644
--- a/examples/mnemonic.rs
+++ b/examples/wallets/examples/mnemonic.rs
@@ -1,6 +1,10 @@
-use ethers::signers::{coins_bip39::English, MnemonicBuilder};
+use ethers::{
+    core::rand,
+    signers::{coins_bip39::English, MnemonicBuilder},
+};
+use eyre::Result;
 
-fn main() -> eyre::Result<()> {
+fn main() -> Result<()> {
     let phrase = "work man father plunge mystery proud hollow address reunion sauce theory bonus";
     let index = 0u32;
     let password = "TREZOR123";
diff --git a/examples/permit_hash.rs b/examples/wallets/examples/permit_hash.rs
similarity index 89%
rename from examples/permit_hash.rs
rename to examples/wallets/examples/permit_hash.rs
index b313b3a5..ac28588c 100644
--- a/examples/permit_hash.rs
+++ b/examples/wallets/examples/permit_hash.rs
@@ -1,7 +1,9 @@
 use ethers::{
     contract::{Eip712, EthAbiType},
-    core::types::transaction::eip712::Eip712,
-    types::{Address, U256},
+    core::{
+        types::{transaction::eip712::Eip712, Address, U256},
+        utils::hex,
+    },
 };
 
 // Generate the EIP712 permit hash to sign for a Uniswap V2 pair.
diff --git a/examples/sign.rs b/examples/wallets/examples/sign_message.rs
similarity index 91%
rename from examples/sign.rs
rename to examples/wallets/examples/sign_message.rs
index 6f6b592e..07d50d87 100644
--- a/examples/sign.rs
+++ b/examples/wallets/examples/sign_message.rs
@@ -1,9 +1,9 @@
 // use the eyre crate for easy idiomatic error handling
 use eyre::Result;
 // use the ethers_core rand for rng
-use ethers_core::rand::thread_rng;
+use ethers::core::rand::thread_rng;
 // use the ethers_signers crate to manage LocalWallet and Signer
-use ethers_signers::{LocalWallet, Signer};
+use ethers::signers::{LocalWallet, Signer};
 
 // Use the `tokio::main` macro for using async on the main function
 #[tokio::main]
diff --git a/examples/trezor.rs b/examples/wallets/examples/trezor.rs
similarity index 100%
rename from examples/trezor.rs
rename to examples/wallets/examples/trezor.rs
diff --git a/examples/yubi.rs b/examples/wallets/examples/yubi.rs
similarity index 100%
rename from examples/yubi.rs
rename to examples/wallets/examples/yubi.rs
diff --git a/scripts/examples.sh b/scripts/examples.sh
index ee50628e..90537870 100755
--- a/scripts/examples.sh
+++ b/scripts/examples.sh
@@ -1,25 +1,42 @@
-set -e
+#!/bin/bash
+
+set -e; # Fail fast
 # shellcheck shell=bash
 
 # examples that we can't run because they require some additional infra, docker or ledger for example
 ignored=(
-  "moonbeam_with_abi"
-  "ipc"
-  "ledger"
-  "paginated_logs"
-  "subscribe_logs"
-  "trezor"
-  "yubi"
-  "remove_liquidity"
+  "examples-contracts:deploy_moonbeam"
+  "examples-providers:ipc"
+  "examples-wallets:ledger"
+  "examples-wallets:trezor"
+  "examples-wallets:yubi"
+  "examples-transactions:remove_liquidity"
 )
 
-# run all examples
-for file in examples/*.rs; do
-  name="$(echo "$file" | cut -f 1 -d '.')"
-  if [[ "${ignored[*]}" =~ $(basename "$name") ]]; then
-    echo "skipping: $file"
-    continue
-  fi
-  echo "running: $file"
-  cargo r -p ethers --example "$(basename "$name")" --features "ethers-solc rustls ws"
+example_crates=$(cargo metadata --format-version 1 | 
+                 jq -c '.workspace_members' | 
+                 jq -r 'map(select(startswith("examples")) |
+                 sub("\\s.*$";"")) | .[]')
+
+for crate in $example_crates; do 
+    # Remove "examples-" prefix from crate name (e.g. examples-contracts => contracts)
+    cratedir="${crate#examples-}"
+    srcdir="examples/$cratedir/examples"
+    # Retrieve all example files in crate:
+    # Transform the absolute path into the filename (e.g. some-path/deploy_anvil.rs => deploy_anvil)
+    example_files=$(find $srcdir -type f -name '*.rs' -exec basename {} \; | sed 's/\.[^.]*$//')
+
+    for file in $example_files; do
+        # Build the example
+        echo "Building example: $crate:$file"
+        cargo build -p $crate --example $file
+
+        # Run the example
+        if [[ "${ignored[*]}" =~ $(basename "$crate:$file") ]]; then
+            echo "skipping: $crate:$file"
+            continue
+        fi
+        echo "running $crate:$file"
+        cargo run -p $crate --example $file
+    done
 done


Test patch:
diff --git a/examples/ethers-wasm/tests/contract_with_abi.rs b/examples/ethers-wasm/tests/contract_with_abi.rs
index 5530df67..df080b38 100644
--- a/examples/ethers-wasm/tests/contract_with_abi.rs
+++ b/examples/ethers-wasm/tests/contract_with_abi.rs
@@ -16,7 +16,7 @@ wasm_bindgen_test_configure!(run_in_browser);
 // definition in human readable format
 abigen!(
     SimpleContract,
-    "../contract_abi.json",
+    "./abi/contract_abi.json",
     event_derives(serde::Deserialize, serde::Serialize)
 );