Repository: gakonst/ethers-rs
Pull request #2435 (2023-05-27 03:13:14)

ethers::utils::format_ether should show decimal places
<!--
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
Well, I've just spent 30 minutes trying to understand why I see 0 ETH as the output of my code. Turns out, it was a problem in prase_ether function. Noticed an issue #2356 
<!--
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
Use `parse_units(value, "ether").unwrap();`
We can safely unwrap here, since `parse_units` returns Err only when units >= 77.
<!--
Summarize the solution and provide any necessary context needed to understand
the code change.
-->

## PR Checklist

-   [ x ] Added Tests
-   [ x ] Added Documentation
-   [ x ] Breaking changes


Patch:
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 905e4dda..8f215a01 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -17,40 +17,32 @@ env:
 
 jobs:
     test:
-        name: test ${{ matrix.os }} (${{ matrix.flags.name }})
+        name: test ${{ matrix.flags.name }} (${{ matrix.os }})
         runs-on: ${{ matrix.os }}
         strategy:
             fail-fast: false
             matrix:
-                os: ["ubuntu-latest", "macos-latest"]
+                os: ["ubuntu-latest", "macos-latest", "windows-latest"]
                 flags:
                     - name: no default features
-                      flags: --workspace --no-default-features
+                      flags: --no-default-features
                     - name: default features
-                      flags: --workspace
+                      flags: ""
                     - name: all features
-                      flags: --workspace --all-features
+                      flags: --all-features
                 include:
-                    # not workspace because compiling examples fails for no reason in CI
-                    - os: windows-latest
+                    - os: ubuntu-latest
                       flags:
-                          name: no default features
-                          flags: --no-default-features
-                    - os: windows-latest
+                          name: celo feature
+                          flags:
+                              -p ethers-core -p ethers-providers -p ethers-contract --features celo
+                    - os: ubuntu-latest
                       flags:
-                          name: default features
-                          flags: ""
-                    - os: windows-latest
-                      flags:
-                          name: all features
-                          flags: --all-features
+                          name: optimism feature
+                          flags: -p ethers-core --features optimism
         steps:
             - uses: actions/checkout@v3
             - uses: dtolnay/rust-toolchain@stable
-              with:
-                  toolchain:
-                      ${{ matrix.os == 'windows-latest' && 'stable-x86_64-pc-windows-gnu' ||
-                      'stable' }}
             - name: Install Anvil
               uses: foundry-rs/foundry-toolchain@v1
               with:
@@ -68,7 +60,7 @@ jobs:
                   cargo nextest run \
                   ${{ matrix.flags.flags }} \
                   -E "!(deps(ethers-etherscan) & kind(test))" \
-                  --retries 3
+                  --retries 2
 
     etherscan-tests:
         name: etherscan tests
@@ -82,7 +74,7 @@ jobs:
             - uses: actions/checkout@v3
             - uses: dtolnay/rust-toolchain@stable
             - uses: Swatinem/rust-cache@v2
-            # Don't use cargo-nextest since all the tests have to be ran sequentially
+            # Don't use cargo-nextest since all the tests have to be run sequentially
             - name: live tests
               run: cargo test -p ethers-etherscan --test it
 
@@ -98,30 +90,26 @@ jobs:
     #         - name: live tests
     #           run: cargo test -p ethers-tests --all-features
 
-    # TODO: [#2191](https://github.com/gakonst/ethers-rs/issues/2191)
-    # feature-checks:
-    #     name: feature checks
-    #     runs-on: ubuntu-latest
-    #     steps:
-    #         - uses: actions/checkout@v3
-    #         - uses: dtolnay/rust-toolchain@nightly
-    #         - uses: taiki-e/install-action@cargo-hack
-    #         - uses: Swatinem/rust-cache@v2
-    #         - name: cargo hack
-    #           run:
-    #               cargo hack check --all --feature-powerset --depth 2 -Z avoid-dev-deps --keep-going
+    feature-checks:
+        name: feature checks
+        runs-on: ubuntu-latest
+        steps:
+            - uses: actions/checkout@v3
+            - uses: dtolnay/rust-toolchain@stable
+            - uses: taiki-e/install-action@cargo-hack
+            - uses: Swatinem/rust-cache@v2
+            - name: cargo hack
+              run: cargo hack check --feature-powerset --depth 1 --no-dev-deps
 
     clippy:
         name: clippy
         runs-on: ubuntu-latest
         steps:
             - uses: actions/checkout@v3
-            - uses: dtolnay/rust-toolchain@nightly
-              with:
-                  components: clippy
+            - uses: dtolnay/rust-toolchain@clippy
             - uses: Swatinem/rust-cache@v2
             - name: clippy
-              run: cargo clippy --workspace --tests --all-features
+              run: cargo clippy --workspace --all-features --all-targets
               env:
                   RUSTFLAGS: "-D warnings"
 
@@ -137,7 +125,6 @@ jobs:
             - name: doc
               run: cargo doc --workspace --all-features --no-deps --document-private-items
               env:
-                  RUSTFLAGS: "--cfg docsrs"
                   RUSTDOCFLAGS: "--cfg docsrs -D warnings"
 
     fmt:
diff --git a/Cargo.toml b/Cargo.toml
index bdc9c43d..3f6d2a52 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -22,7 +22,6 @@ exclude = [
 # https://docs.rs/about/metadata
 [workspace.metadata.docs.rs]
 all-features = true
-rustc-args = ["--cfg", "docsrs"]
 rustdoc-args = ["--cfg", "docsrs"]
 
 # https://github.com/integer32llc/rust-playground/blob/c6165a36923db5d99313e6056b5b610a2ede5bb0/top-crates/src/lib.rs#L175-L184
@@ -34,6 +33,8 @@ members = [
     "ethers",
     "ethers-addressbook",
     "ethers-contract",
+    "ethers-contract/ethers-contract-abigen",
+    "ethers-contract/ethers-contract-derive",
     "ethers-core",
     "ethers-etherscan",
     "ethers-middleware",
@@ -50,6 +51,8 @@ default-members = [
     "ethers",
     "ethers-addressbook",
     "ethers-contract",
+    "ethers-contract/ethers-contract-abigen",
+    "ethers-contract/ethers-contract-derive",
     "ethers-core",
     "ethers-etherscan",
     "ethers-middleware",
diff --git a/ethers-addressbook/Cargo.toml b/ethers-addressbook/Cargo.toml
index fc9c4ca0..8744b4b0 100644
--- a/ethers-addressbook/Cargo.toml
+++ b/ethers-addressbook/Cargo.toml
@@ -17,7 +17,6 @@ exclude.workspace = true
 
 [package.metadata.docs.rs]
 all-features = true
-rustc-args = ["--cfg", "docsrs"]
 rustdoc-args = ["--cfg", "docsrs"]
 
 [package.metadata.playground]
diff --git a/ethers-contract/Cargo.toml b/ethers-contract/Cargo.toml
index 072ab237..9c1e71be 100644
--- a/ethers-contract/Cargo.toml
+++ b/ethers-contract/Cargo.toml
@@ -17,7 +17,6 @@ exclude.workspace = true
 
 [package.metadata.docs.rs]
 all-features = true
-rustc-args = ["--cfg", "docsrs"]
 rustdoc-args = ["--cfg", "docsrs"]
 
 [package.metadata.playground]
diff --git a/ethers-contract/ethers-contract-abigen/Cargo.toml b/ethers-contract/ethers-contract-abigen/Cargo.toml
index e2b9b69b..ca050fd7 100644
--- a/ethers-contract/ethers-contract-abigen/Cargo.toml
+++ b/ethers-contract/ethers-contract-abigen/Cargo.toml
@@ -19,7 +19,6 @@ keywords.workspace = true
 
 [package.metadata.docs.rs]
 all-features = true
-rustc-args = ["--cfg", "docsrs"]
 rustdoc-args = ["--cfg", "docsrs"]
 
 [package.metadata.playground]
diff --git a/ethers-core/Cargo.toml b/ethers-core/Cargo.toml
index 7c91836c..bc878507 100644
--- a/ethers-core/Cargo.toml
+++ b/ethers-core/Cargo.toml
@@ -17,7 +17,6 @@ exclude.workspace = true
 
 [package.metadata.docs.rs]
 all-features = true
-rustc-args = ["--cfg", "docsrs"]
 rustdoc-args = ["--cfg", "docsrs"]
 
 [package.metadata.playground]
diff --git a/ethers-core/src/types/trace/geth.rs b/ethers-core/src/types/trace/geth.rs
index 1aa89dac..8ea58e11 100644
--- a/ethers-core/src/types/trace/geth.rs
+++ b/ethers-core/src/types/trace/geth.rs
@@ -310,9 +310,9 @@ pub mod spoof {
 
     /// Returns an empty state override set.
     ///
-    /// # Example
+    /// # Examples
     ///
-    /// ```no_run
+    /// ```ignore
     /// # use ethers_core::{
     /// #     types::{Address, TransactionRequest, H256, spoof},
     /// #     utils::{parse_ether, Geth},
@@ -346,8 +346,9 @@ pub mod spoof {
 
     /// Returns a state override set with a single element setting the balance of the address.
     ///
-    /// # Example
-    /// ```no_run
+    /// # Examples
+    ///
+    /// ```ignore
     /// # use ethers_core::{
     /// #     types::{Address, TransactionRequest, H256},
     /// #     utils::{parse_ether, Geth},
@@ -378,8 +379,9 @@ pub mod spoof {
 
     /// Returns a state override set with a single element setting the nonce of the address.
     ///
-    /// # Example
-    /// ```no_run
+    /// # Examples
+    ///
+    /// ```ignore
     /// # use ethers_core::{
     /// #     types::{Address, TransactionRequest, H256},
     /// #     utils::{parse_ether, Geth},
@@ -408,8 +410,9 @@ pub mod spoof {
 
     /// Returns a state override set with a single element setting the code at the address.
     ///
-    /// # Example
-    /// ```no_run
+    /// # Examples
+    ///
+    /// ```ignore
     /// # use ethers_core::{
     /// #     types::{Address, TransactionRequest, H256},
     /// #     utils::{parse_ether, Geth},
@@ -439,9 +442,9 @@ pub mod spoof {
     /// Returns a state override set with a single element setting the storage at the given address
     /// and key.
     ///
-    /// # Example
+    /// # Examples
     ///
-    /// ```no_run
+    /// ```ignore
     /// # use ethers_core::{
     /// #     types::{Address, TransactionRequest, H256},
     /// #     utils::{parse_ether, Geth},
diff --git a/ethers-core/src/types/transaction/response.rs b/ethers-core/src/types/transaction/response.rs
index 595bcdf4..656a5611 100644
--- a/ethers-core/src/types/transaction/response.rs
+++ b/ethers-core/src/types/transaction/response.rs
@@ -132,7 +132,7 @@ pub struct Transaction {
     pub chain_id: Option<U256>,
 
     /// Captures unknown fields such as additional fields used by L2s
-    #[cfg(not(feature = "celo"))]
+    #[cfg(not(any(feature = "celo", feature = "optimism")))]
     #[serde(flatten)]
     pub other: crate::types::OtherFields,
 }
diff --git a/ethers-core/src/utils/mod.rs b/ethers-core/src/utils/mod.rs
index faa9052e..3e4a5588 100644
--- a/ethers-core/src/utils/mod.rs
+++ b/ethers-core/src/utils/mod.rs
@@ -141,8 +141,15 @@ construct_format_units_from! {
 /// in ether (instead of wei)
 ///
 /// Divides the input by 1e18
-pub fn format_ether<T: Into<U256>>(amount: T) -> U256 {
-    amount.into() / WEI_IN_ETHER
+/// ```
+/// use ethers_core::{types::U256, utils::format_ether};
+///
+/// let eth = format_ether(1395633240123456000_u128).unwrap();
+/// assert_eq!(eth.parse::<f64>().unwrap(), 1.395633240123456);
+/// ```
+pub fn format_ether<T: Into<ParseUnits>>(amount: T) -> String {
+    // format_units returns Err only if units >= 77. Hense, we can safely unwrap here
+    format_units(amount, "ether").unwrap()
 }
 
 /// Divides the provided amount with 10^{units} provided.
@@ -615,6 +622,64 @@ mod tests {
         assert_eq!(WEI_IN_ETHER.as_u64(), 1e18 as u64);
     }
 
+    #[test]
+    fn test_format_ether_unsigned() {
+        let eth = format_ether(WEI_IN_ETHER);
+        assert_eq!(eth.parse::<f64>().unwrap() as u64, 1);
+
+        let eth = format_ether(1395633240123456000_u128);
+        assert_eq!(eth.parse::<f64>().unwrap(), 1.395633240123456);
+
+        let eth = format_ether(U256::from_dec_str("1395633240123456000").unwrap());
+        assert_eq!(eth.parse::<f64>().unwrap(), 1.395633240123456);
+
+        let eth = format_ether(U256::from_dec_str("1395633240123456789").unwrap());
+        assert_eq!(eth, "1.395633240123456789");
+
+        let eth = format_ether(U256::from_dec_str("1005633240123456789").unwrap());
+        assert_eq!(eth, "1.005633240123456789");
+
+        let eth = format_ether(u16::MAX);
+        assert_eq!(eth, "0.000000000000065535");
+
+        // Note: This covers usize on 32 bit systems.
+        let eth = format_ether(u32::MAX);
+        assert_eq!(eth, "0.000000004294967295");
+
+        // Note: This covers usize on 64 bit systems.
+        let eth = format_ether(u64::MAX);
+        assert_eq!(eth, "18.446744073709551615");
+    }
+
+    #[test]
+    fn test_format_ether_signed() {
+        let eth = format_ether(I256::from_dec_str("-1395633240123456000").unwrap());
+        assert_eq!(eth.parse::<f64>().unwrap(), -1.395633240123456);
+
+        let eth = format_ether(I256::from_dec_str("-1395633240123456789").unwrap());
+        assert_eq!(eth, "-1.395633240123456789");
+
+        let eth = format_ether(I256::from_dec_str("1005633240123456789").unwrap());
+        assert_eq!(eth, "1.005633240123456789");
+
+        let eth = format_ether(i8::MIN);
+        assert_eq!(eth, "-0.000000000000000128");
+
+        let eth = format_ether(i8::MAX);
+        assert_eq!(eth, "0.000000000000000127");
+
+        let eth = format_ether(i16::MIN);
+        assert_eq!(eth, "-0.000000000000032768");
+
+        // Note: This covers isize on 32 bit systems.
+        let eth = format_ether(i32::MIN);
+        assert_eq!(eth, "-0.000000002147483648");
+
+        // Note: This covers isize on 64 bit systems.
+        let eth = format_ether(i64::MIN);
+        assert_eq!(eth, "-9.223372036854775808");
+    }
+
     #[test]
     fn test_format_units_unsigned() {
         let gwei_in_ether = format_units(WEI_IN_ETHER, 9).unwrap();
diff --git a/ethers-etherscan/Cargo.toml b/ethers-etherscan/Cargo.toml
index ee38d124..345c8b02 100644
--- a/ethers-etherscan/Cargo.toml
+++ b/ethers-etherscan/Cargo.toml
@@ -20,7 +20,6 @@ exclude.workspace = true
 
 [package.metadata.docs.rs]
 all-features = true
-rustc-args = ["--cfg", "docsrs"]
 rustdoc-args = ["--cfg", "docsrs"]
 
 [package.metadata.playground]
diff --git a/ethers-middleware/Cargo.toml b/ethers-middleware/Cargo.toml
index b72432ef..d2bde216 100644
--- a/ethers-middleware/Cargo.toml
+++ b/ethers-middleware/Cargo.toml
@@ -17,7 +17,6 @@ exclude.workspace = true
 
 [package.metadata.docs.rs]
 all-features = true
-rustc-args = ["--cfg", "docsrs"]
 rustdoc-args = ["--cfg", "docsrs"]
 
 [package.metadata.playground]
diff --git a/ethers-providers/Cargo.toml b/ethers-providers/Cargo.toml
index 97712fd4..7ec45f24 100644
--- a/ethers-providers/Cargo.toml
+++ b/ethers-providers/Cargo.toml
@@ -17,7 +17,6 @@ exclude.workspace = true
 
 [package.metadata.docs.rs]
 all-features = true
-rustc-args = ["--cfg", "docsrs"]
 rustdoc-args = ["--cfg", "docsrs"]
 
 [package.metadata.playground]
diff --git a/ethers-providers/src/ext/admin.rs b/ethers-providers/src/ext/admin.rs
index f4abed3f..a48ae89f 100644
--- a/ethers-providers/src/ext/admin.rs
+++ b/ethers-providers/src/ext/admin.rs
@@ -128,13 +128,15 @@ pub enum EthPeerInfo {
 #[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Eq)]
 pub struct EthInfo {
     /// The negotiated eth version.
+    #[serde(default)]
     pub version: u64,
 
     /// The total difficulty of the peer's blockchain.
-    #[serde(deserialize_with = "deserialize_stringified_numeric")]
+    #[serde(default, deserialize_with = "deserialize_stringified_numeric")]
     pub difficulty: U256,
 
     /// The hash of the peer's best known block.
+    #[serde(default)]
     pub head: H256,
 }
 
@@ -168,7 +170,7 @@ pub struct SnapInfo {
 #[derive(Clone, Debug, Deserialize, Serialize)]
 pub struct PeerInfo {
     /// The peer's ENR.
-    #[serde(skip_serializing_if = "Option::is_none")]
+    #[serde(default, skip_serializing_if = "Option::is_none")]
     pub enr: Option<Enr<SigningKey>>,
 
     /// The peer's enode URL.
diff --git a/ethers-signers/Cargo.toml b/ethers-signers/Cargo.toml
index c6c03e5c..69a1f7f9 100644
--- a/ethers-signers/Cargo.toml
+++ b/ethers-signers/Cargo.toml
@@ -17,7 +17,6 @@ exclude.workspace = true
 
 [package.metadata.docs.rs]
 all-features = true
-rustc-args = ["--cfg", "docsrs"]
 rustdoc-args = ["--cfg", "docsrs"]
 
 [package.metadata.playground]
diff --git a/ethers-solc/Cargo.toml b/ethers-solc/Cargo.toml
index 0706ffca..020b2079 100644
--- a/ethers-solc/Cargo.toml
+++ b/ethers-solc/Cargo.toml
@@ -20,7 +20,6 @@ exclude.workspace = true
 
 [package.metadata.docs.rs]
 all-features = true
-rustc-args = ["--cfg", "docsrs"]
 rustdoc-args = ["--cfg", "docsrs"]
 
 [package.metadata.playground]
@@ -67,7 +66,7 @@ svm-builds = { package = "svm-rs-builds", version = "0.1", optional = true }
 tokio = { workspace = true, features = ["rt-multi-thread"] }
 
 [dev-dependencies]
-criterion.workspace = true
+criterion = { workspace = true, features = ["async_tokio"] }
 env_logger = "0.10.0"
 tracing-subscriber = { workspace = true, features = ["env-filter", "fmt"] }
 rand.workspace = true
@@ -99,14 +98,7 @@ default = ["rustls"]
 
 full = ["async", "svm-solc"]
 
-async = [
-    "tokio/process",
-    "tokio/io-util",
-    "tokio/fs",
-    "tokio/time",
-    "futures-util",
-    "criterion/async_tokio",
-]
+async = ["tokio/process", "tokio/io-util", "tokio/fs", "tokio/time", "futures-util"]
 svm-solc = ["svm", "svm-builds", "sha2"]
 
 # Utilities for creating and testing project workspaces
diff --git a/ethers/Cargo.toml b/ethers/Cargo.toml
index 1f152f21..12417eea 100644
--- a/ethers/Cargo.toml
+++ b/ethers/Cargo.toml
@@ -17,7 +17,6 @@ exclude.workspace = true
 
 [package.metadata.docs.rs]
 all-features = true
-rustc-args = ["--cfg", "docsrs"]
 rustdoc-args = ["--cfg", "docsrs"]
 
 [package.metadata.playground]
diff --git a/ethers/src/lib.rs b/ethers/src/lib.rs
index 182a0173..71594236 100644
--- a/ethers/src/lib.rs
+++ b/ethers/src/lib.rs
@@ -107,7 +107,7 @@ pub use ethers_core::{abi, types, utils};
 
 /// Easy imports of frequently used type definitions and traits.
 #[doc(hidden)]
-#[allow(ambiguous_glob_reexports)]
+#[allow(unknown_lints, ambiguous_glob_reexports)]
 pub mod prelude {
     pub use super::addressbook::contract;
 
diff --git a/examples/contracts/Cargo.toml b/examples/contracts/Cargo.toml
index 4246eb7e..15ac75f1 100644
--- a/examples/contracts/Cargo.toml
+++ b/examples/contracts/Cargo.toml
@@ -8,10 +8,6 @@ license.workspace = true
 rust-version.workspace = true
 edition.workspace = true
 
-[features]
-default = ["legacy"]
-legacy = ["ethers/legacy"]
-
 [dev-dependencies]
 ethers = { workspace = true, features = ["abigen", "rustls", "ws", "ethers-solc"] }
 
diff --git a/examples/contracts/examples/deploy_moonbeam.rs b/examples/contracts/examples/deploy_moonbeam.rs
index a26464c8..c3d0da30 100644
--- a/examples/contracts/examples/deploy_moonbeam.rs
+++ b/examples/contracts/examples/deploy_moonbeam.rs
@@ -14,10 +14,7 @@ abigen!(
 /// ```bash
 ///  docker run --rm --name moonbeam_development -p 9944:9944 -p 9933:9933 purestake/moonbeam:v0.14.2 --dev --ws-external --rpc-external
 /// ```
-///
-/// Also requires the `legacy` feature to send Legacy transaction instead of an EIP-1559
 #[tokio::main]
-#[cfg(feature = "legacy")]
 async fn main() -> eyre::Result<()> {
     use ethers::prelude::*;
     use std::{convert::TryFrom, path::Path, sync::Arc, time::Duration};
@@ -71,6 +68,3 @@ async fn main() -> eyre::Result<()> {
 
     Ok(())
 }
-
-#[cfg(not(feature = "legacy"))]
-fn main() {}
diff --git a/examples/transactions/examples/transfer_erc20.rs b/examples/transactions/examples/transfer_erc20.rs
index 0c38f353..1084e9aa 100644
--- a/examples/transactions/examples/transfer_erc20.rs
+++ b/examples/transactions/examples/transfer_erc20.rs
@@ -17,7 +17,7 @@ async fn main() -> Result<()> {
     let anvil = Anvil::new().spawn();
     // Use the first wallet autogenerated by the Anvil node to send the transaction.
     let from_wallet: LocalWallet = anvil.keys()[0].clone().into();
-    let to_address = anvil.addresses()[2].clone();
+    let to_address = anvil.addresses()[2];
 
     // Deploy an ERC20 token contract on the freshly started local Anvil node that doesn't have any
     // tokens deployed on it. This will also allocate tokens to the `from_wallet` address.
diff --git a/examples/wallets/Cargo.toml b/examples/wallets/Cargo.toml
index 7667e840..2ba21ddf 100644
--- a/examples/wallets/Cargo.toml
+++ b/examples/wallets/Cargo.toml
@@ -8,14 +8,8 @@ license.workspace = true
 rust-version.workspace = true
 edition.workspace = true
 
-[features]
-default = ["ledger", "trezor", "yubi"]
-ledger = ["ethers/ledger"]
-trezor = ["ethers/trezor"]
-yubi = ["ethers/yubi"]
-
 [dev-dependencies]
-ethers = { workspace = true, features = ["abigen", "ws", "rustls"] }
+ethers = { workspace = true, features = ["abigen", "ws", "rustls", "ledger", "trezor", "yubi"] }
 
 tokio = { workspace = true, features = ["macros", "rt-multi-thread"] }
 
diff --git a/examples/wallets/examples/ledger.rs b/examples/wallets/examples/ledger.rs
index f4205792..e77a04f0 100644
--- a/examples/wallets/examples/ledger.rs
+++ b/examples/wallets/examples/ledger.rs
@@ -1,5 +1,4 @@
 #[tokio::main]
-#[cfg(feature = "ledger")]
 async fn main() -> Result<(), Box<dyn std::error::Error>> {
     use ethers::{prelude::*, utils::parse_ether};
 
@@ -21,6 +20,3 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
     let _receipt = pending_tx.confirmations(3).await?;
     Ok(())
 }
-
-#[cfg(not(feature = "ledger"))]
-fn main() {}
diff --git a/examples/wallets/examples/trezor.rs b/examples/wallets/examples/trezor.rs
index ab881a3c..adc08438 100644
--- a/examples/wallets/examples/trezor.rs
+++ b/examples/wallets/examples/trezor.rs
@@ -1,5 +1,4 @@
 #[tokio::main]
-#[cfg(feature = "trezor")]
 async fn main() -> Result<(), Box<dyn std::error::Error>> {
     use ethers::{prelude::*, utils::parse_ether};
 
@@ -24,6 +23,3 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
     let _receipt = pending_tx.confirmations(3).await?;
     Ok(())
 }
-
-#[cfg(not(feature = "trezor"))]
-fn main() {}
diff --git a/examples/wallets/examples/yubi.rs b/examples/wallets/examples/yubi.rs
index 4cc8ddac..9398a963 100644
--- a/examples/wallets/examples/yubi.rs
+++ b/examples/wallets/examples/yubi.rs
@@ -1,5 +1,4 @@
 #[tokio::main]
-#[cfg(feature = "yubi")]
 async fn main() -> Result<(), Box<dyn std::error::Error>> {
     use ethers::{prelude::*, utils::parse_ether};
     use yubihsm::{Connector, Credentials, UsbConfig};
@@ -24,6 +23,3 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
     let _receipt = pending_tx.confirmations(3).await?;
     Ok(())
 }
-
-#[cfg(not(feature = "yubi"))]
-fn main() {}


Test patch:
diff --git a/ethers-middleware/tests/it/stack.rs b/ethers-middleware/tests/it/stack.rs
index 464bceaa..3792aaea 100644
--- a/ethers-middleware/tests/it/stack.rs
+++ b/ethers-middleware/tests/it/stack.rs
@@ -81,7 +81,7 @@ async fn can_stack_middlewares() {
     for _ in 0..10 {
         let pending = provider.send_transaction(tx.clone(), None).await.unwrap();
         let hash = *pending;
-        let gas_price = provider.get_transaction(hash).await.unwrap().unwrap().gas_price;
+        let _ = provider.get_transaction(hash).await.unwrap().unwrap();
         pending_txs.push(pending);
     }