Repository: gakonst/ethers-rs
Pull request #2338 (2023-04-10 08:24:24)

feat: add Base Goerli chain
<!--
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

<!--
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.
-->

https://github.com/foundry-rs/foundry/issues/4716

## Solution

<!--
Summarize the solution and provide any necessary context needed to understand
the code change.
-->

Add Base Goerli as a chain.

## PR Checklist

-   [ ] Added Tests
-   [ ] Added Documentation
-   [ ] Breaking changes



Patch:
diff --git a/Cargo.lock b/Cargo.lock
index 035e97df..efc09397 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -725,9 +725,9 @@ dependencies = [
 
 [[package]]
 name = "crossbeam-channel"
-version = "0.5.7"
+version = "0.5.8"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cf2b3e8478797446514c91ef04bafcb59faba183e621ad488df88983cc14128c"
+checksum = "a33c2bf77f2df06183c3aa30d1e96c0695a313d4f9c453cc3762a6db39f99200"
 dependencies = [
  "cfg-if",
  "crossbeam-utils",
@@ -907,9 +907,9 @@ dependencies = [
 
 [[package]]
 name = "der"
-version = "0.7.2"
+version = "0.7.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "19c5cb402c5c958281c7c0702edea7b780d03b86b606497ca3a10fcd3fc393ac"
+checksum = "82b10af9f9f9f2134a42d3f8aa74658660f2e0234b0eb81bd171df8aa32779ed"
 dependencies = [
  "const-oid",
  "zeroize",
@@ -994,9 +994,9 @@ checksum = "0bd4b30a6560bbd9b4620f4de34c3f14f60848e58a9b7216801afcb4c7b31c3c"
 
 [[package]]
 name = "ecdsa"
-version = "0.16.4"
+version = "0.16.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "106401dadc137d05cb0d4ab4d42be089746aefdfe8992df4d0edcf351c16ddca"
+checksum = "a48e5d537b8a30c0b023116d981b16334be1485af7ca68db3a2b7024cbc957fd"
 dependencies = [
  "der",
  "digest 0.10.6",
@@ -1037,9 +1037,9 @@ checksum = "7fcaabb2fef8c910e7f4c7ce9f67a1283a1715879a7c230ca9d6d1ae31f16d91"
 
 [[package]]
 name = "elliptic-curve"
-version = "0.13.3"
+version = "0.13.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "22cdacd4d6ed3f9b98680b679c0e52a823b8a2c7a97358d508fe247f2180c282"
+checksum = "75c71eaa367f2e5d556414a8eea812bc62985c879748d6403edabd9cb03f16e7"
 dependencies = [
  "base16ct",
  "crypto-bigint",
@@ -1111,13 +1111,13 @@ dependencies = [
 
 [[package]]
 name = "errno"
-version = "0.3.0"
+version = "0.3.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "50d6a0976c999d473fe89ad888d5a284e55366d9dc9038b1ba2aa15128c4afa0"
+checksum = "4bcfec3a70f97c962c307b2d2c56e358cf1d00b558d74262b5f929ee8cc7e73a"
 dependencies = [
  "errno-dragonfly",
  "libc",
- "windows-sys 0.45.0",
+ "windows-sys 0.48.0",
 ]
 
 [[package]]
@@ -1862,9 +1862,9 @@ dependencies = [
 
 [[package]]
 name = "getrandom"
-version = "0.2.8"
+version = "0.2.9"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c05aeb6a22b8f62540c194aac980f2115af067bfe15a0734d7277a768d396b31"
+checksum = "c85e1d9ab2eadba7e5040d4e09cbd6d072b76a557ad64e797c2cb9d4da21d7e4"
 dependencies = [
  "cfg-if",
  "js-sys",
@@ -2254,14 +2254,14 @@ checksum = "12b6ee2129af8d4fb011108c73d99a1b83a85977f23b82460c0ae2e25bb4b57f"
 
 [[package]]
 name = "is-terminal"
-version = "0.4.6"
+version = "0.4.7"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "256017f749ab3117e93acb91063009e1f1bb56d03965b14c2c8df4eb02c524d8"
+checksum = "adcf93614601c8129ddf72e2d5633df827ba6551541c6d8c59520a371475be1f"
 dependencies = [
  "hermit-abi 0.3.1",
  "io-lifetimes",
  "rustix",
- "windows-sys 0.45.0",
+ "windows-sys 0.48.0",
 ]
 
 [[package]]
@@ -2299,9 +2299,9 @@ dependencies = [
 
 [[package]]
 name = "k256"
-version = "0.13.0"
+version = "0.13.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "955890845095ccf31ef83ad41a05aabb4d8cc23dc3cac5a9f5c89cf26dd0da75"
+checksum = "cadb76004ed8e97623117f3df85b17aaa6626ab0b0831e6573f104df16cd1bcc"
 dependencies = [
  "cfg-if",
  "ecdsa",
@@ -2651,9 +2651,9 @@ dependencies = [
 
 [[package]]
 name = "openssl"
-version = "0.10.49"
+version = "0.10.50"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4d2f106ab837a24e03672c59b1239669a0596406ff657c3c0835b6b7f0f35a33"
+checksum = "7e30d8bc91859781f0a943411186324d580f2bbeb71b452fe91ae344806af3f1"
 dependencies = [
  "bitflags 1.3.2",
  "cfg-if",
@@ -2683,9 +2683,9 @@ checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf"
 
 [[package]]
 name = "openssl-sys"
-version = "0.9.84"
+version = "0.9.85"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3a20eace9dc2d82904039cb76dcf50fb1a0bba071cfd1629720b5d6f1ddba0fa"
+checksum = "0d3d193fb1488ad46ffe3aaabc912cc931d02ee8518fe2959aea8ef52718b0c0"
 dependencies = [
  "cc",
  "libc",
@@ -3037,9 +3037,9 @@ dependencies = [
 
 [[package]]
 name = "primeorder"
-version = "0.13.0"
+version = "0.13.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7613fdcc0831c10060fa69833ea8fa2caa94b6456f51e25356a885b530a2e3d0"
+checksum = "cf8d3875361e28f7753baefef104386e7aa47642c93023356d97fdef4003bfb5"
 dependencies = [
  "elliptic-curve",
 ]
@@ -3443,16 +3443,16 @@ dependencies = [
 
 [[package]]
 name = "rustix"
-version = "0.37.7"
+version = "0.37.11"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2aae838e49b3d63e9274e1c01833cc8139d3fec468c3b84688c628f44b1ae11d"
+checksum = "85597d61f83914ddeba6a47b3b8ffe7365107221c2e557ed94426489fefb5f77"
 dependencies = [
  "bitflags 1.3.2",
  "errno",
  "io-lifetimes",
  "libc",
  "linux-raw-sys",
- "windows-sys 0.45.0",
+ "windows-sys 0.48.0",
 ]
 
 [[package]]
@@ -3593,9 +3593,9 @@ dependencies = [
 
 [[package]]
 name = "sec1"
-version = "0.7.1"
+version = "0.7.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "48518a2b5775ba8ca5b46596aae011caa431e6ce7e4a67ead66d92f08884220e"
+checksum = "f0aec48e813d6b90b15f0b8948af3c63483992dee44c03e9930b3eebdabe046e"
 dependencies = [
  "base16ct",
  "der",
@@ -4509,9 +4509,9 @@ dependencies = [
 
 [[package]]
 name = "uuid"
-version = "1.3.0"
+version = "1.3.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1674845326ee10d37ca60470760d4288a6f80f304007d92e5c53bab78c9cfd79"
+checksum = "5b55a3fef2a1e3b3a00ce878640918820d3c51081576ac657d23af9fc7928fdb"
 dependencies = [
  "serde",
 ]
@@ -4956,7 +4956,7 @@ dependencies = [
  "subtle",
  "thiserror",
  "time",
- "uuid 1.3.0",
+ "uuid 1.3.1",
  "zeroize",
 ]
 
diff --git a/ethers-contract/ethers-contract-derive/src/eip712.rs b/ethers-contract/ethers-contract-derive/src/eip712.rs
index ece0524e..50f3451a 100644
--- a/ethers-contract/ethers-contract-derive/src/eip712.rs
+++ b/ethers-contract/ethers-contract-derive/src/eip712.rs
@@ -138,8 +138,12 @@ fn parse_fields(input: &DeriveInput) -> Result<Vec<(String, ParamType)>> {
 
     let mut fields = Vec::with_capacity(named_fields.named.len());
     for f in named_fields.named.iter() {
-        let field_name = f.ident.as_ref().unwrap().to_string().to_camel_case();
-        let field_type =
+        // strip the raw identifier prefix
+        let name = f.ident.as_ref().unwrap().to_string();
+        let s = name.strip_prefix("r#").unwrap_or(&name);
+        let name = s.to_camel_case();
+
+        let ty =
             match f.attrs.iter().find(|a| a.path().segments.iter().any(|s| s.ident == "eip712")) {
                 // Found nested Eip712 Struct
                 // TODO: Implement custom
@@ -150,7 +154,7 @@ fn parse_fields(input: &DeriveInput) -> Result<Vec<(String, ParamType)>> {
                 None => crate::utils::find_parameter_type(&f.ty)?,
             };
 
-        fields.push((field_name, field_type));
+        fields.push((name, ty));
     }
 
     Ok(fields)
diff --git a/ethers-core/src/types/chain.rs b/ethers-core/src/types/chain.rs
index 60138ae8..16a814fd 100644
--- a/ethers-core/src/types/chain.rs
+++ b/ethers-core/src/types/chain.rs
@@ -87,6 +87,8 @@ pub enum Chain {
     Poa = 99,
     Sokol = 77,
 
+    ScrollAlphaTestnet = 534353,
+
     #[strum(to_string = "xdai", serialize = "gnosis", serialize = "gnosis-chain")]
     #[serde(alias = "xdai", alias = "gnosis", alias = "gnosis_chain")]
     XDai = 100,
@@ -140,6 +142,8 @@ pub enum Chain {
     CantoTestnet = 740,
 
     Boba = 288,
+
+    BaseGoerli = 84531,
 }
 
 // === impl Chain ===
@@ -268,11 +272,11 @@ impl Chain {
             Dev | AnvilHardhat => 200,
             Celo | CeloAlfajores | CeloBaklava => 5_000,
             FilecoinHyperspaceTestnet | FilecoinMainnet => 30_000,
-
+            ScrollAlphaTestnet => 3_000,
             // Explicitly exhaustive. See NB above.
             Morden | Ropsten | Rinkeby | Goerli | Kovan | XDai | Chiado | Sepolia | Moonbase |
             MoonbeamDev | Optimism | OptimismGoerli | OptimismKovan | Poa | Sokol | Rsk |
-            EmeraldTestnet | Boba => return None,
+            EmeraldTestnet | Boba | BaseGoerli => return None,
         };
 
         Some(Duration::from_millis(ms))
@@ -311,7 +315,8 @@ impl Chain {
             Celo |
             CeloAlfajores |
             CeloBaklava |
-            Boba => true,
+            Boba |
+            BaseGoerli => true,
 
             // Known EIP-1559 chains
             Mainnet |
@@ -327,7 +332,8 @@ impl Chain {
             // Unknown / not applicable, default to false for backwards compatibility
             Dev | AnvilHardhat | Morden | Ropsten | Rinkeby | Cronos | CronosTestnet | Kovan |
             Sokol | Poa | XDai | Moonbeam | MoonbeamDev | Moonriver | Moonbase | Evmos |
-            EvmosTestnet | Chiado | Aurora | AuroraTestnet | Canto | CantoTestnet => false,
+            EvmosTestnet | Chiado | Aurora | AuroraTestnet | Canto | CantoTestnet |
+            ScrollAlphaTestnet => false,
         }
     }
 
@@ -412,6 +418,10 @@ impl Chain {
                 ("https://blockscout.com/xdai/mainnet/api", "https://blockscout.com/xdai/mainnet")
             }
 
+            ScrollAlphaTestnet => {
+                ("https://blockscout.scroll.io/api", "https://blockscout.scroll.io/")
+            }
+
             Chiado => {
                 ("https://blockscout.chiadochain.net/api", "https://blockscout.chiadochain.net")
             }
@@ -460,6 +470,8 @@ impl Chain {
 
             Boba => ("https://api.bobascan.com/api", "https://bobascan.com"),
 
+            BaseGoerli => ("https://api-goerli.basescan.org/api", "https://goerli.basescan.org"),
+
             AnvilHardhat | Dev | Morden | MoonbeamDev | FilecoinMainnet => {
                 // this is explicitly exhaustive so we don't forget to add new urls when adding a
                 // new chain
@@ -505,7 +517,8 @@ impl Chain {
             AuroraTestnet |
             Celo |
             CeloAlfajores |
-            CeloBaklava => "ETHERSCAN_API_KEY",
+            CeloBaklava |
+            BaseGoerli => "ETHERSCAN_API_KEY",
 
             Avalanche | AvalancheFuji => "SNOWTRACE_API_KEY",
 
@@ -521,6 +534,7 @@ impl Chain {
 
             // Explicitly exhaustive. See NB above.
             XDai |
+            ScrollAlphaTestnet |
             Chiado |
             Sepolia |
             Rsk |
diff --git a/ethers-etherscan/src/account.rs b/ethers-etherscan/src/account.rs
index 8a51813c..5a77ed7e 100644
--- a/ethers-etherscan/src/account.rs
+++ b/ethers-etherscan/src/account.rs
@@ -392,11 +392,11 @@ impl Display for Sort {
 /// Common optional arguments for the transaction or event list API endpoints
 #[derive(Clone, Copy, Debug)]
 pub struct TxListParams {
-    start_block: u64,
-    end_block: u64,
-    page: u64,
-    offset: u64,
-    sort: Sort,
+    pub start_block: u64,
+    pub end_block: u64,
+    pub page: u64,
+    pub offset: u64,
+    pub sort: Sort,
 }
 
 impl TxListParams {
@@ -480,17 +480,13 @@ impl Display for BlockType {
 impl Client {
     /// Returns the Ether balance of a given address.
     ///
-    /// ```no_run
-    /// # use ethers_etherscan::Client;
-    /// # use ethers_core::types::Chain;
+    /// # Examples
     ///
-    /// # #[tokio::main]
-    /// # async fn main() {
-    ///     let client = Client::new(Chain::Mainnet, "API_KEY").unwrap();
-    ///     let balance = client
-    ///         .get_ether_balance_single(&"0x58eB28A67731c570Ef827C365c89B5751F9E6b0a".parse().unwrap(),
-    ///         None).await.unwrap();
-    /// # }
+    /// ```no_run
+    /// # async fn foo(client: ethers_etherscan::Client) -> Result<(), Box<dyn std::error::Error>> {
+    /// let address = "0x58eB28A67731c570Ef827C365c89B5751F9E6b0a".parse()?;
+    /// let balance = client.get_ether_balance_single(&address, None).await?;
+    /// # Ok(()) }
     /// ```
     pub async fn get_ether_balance_single(
         &self,
@@ -515,21 +511,22 @@ impl Client {
 
     /// Returns the balance of the accounts from a list of addresses.
     ///
-    /// ```no_run
-    /// # use ethers_etherscan::Client;
-    /// # use ethers_core::types::Chain;
+    /// # Examples
     ///
-    /// # #[tokio::main]
-    /// # async fn main() {
-    ///     let client = Client::new(Chain::Mainnet, "API_KEY").unwrap();
-    ///     let balances = client
-    ///         .get_ether_balance_multi(&vec![&"0x58eB28A67731c570Ef827C365c89B5751F9E6b0a".parse().unwrap()],
-    ///         None).await.unwrap();
-    /// # }
+    /// ```no_run
+    /// # use ethers_core::types::Address;
+    /// # async fn foo(client: ethers_etherscan::Client) -> Result<(), Box<dyn std::error::Error>> {
+    /// let addresses = [
+    ///     "0x3E3c00494d0b306a0739E480DBB5DB91FFb5d4CB".parse::<Address>()?,
+    ///     "0x7e9996ef050a9Fa7A01248e63271F69086aaFc9D".parse::<Address>()?,
+    /// ];
+    /// let balances = client.get_ether_balance_multi(&addresses, None).await?;
+    /// assert_eq!(addresses.len(), balances.len());
+    /// # Ok(()) }
     /// ```
     pub async fn get_ether_balance_multi(
         &self,
-        addresses: &[&Address],
+        addresses: &[Address],
         tag: Option<Tag>,
     ) -> Result<Vec<AccountBalance>> {
         let tag_str = tag.unwrap_or_default().to_string();
@@ -550,17 +547,13 @@ impl Client {
 
     /// Returns the list of transactions performed by an address, with optional pagination.
     ///
-    /// ```no_run
-    /// # use ethers_etherscan::Client;
-    /// # use ethers_core::types::Chain;
+    /// # Examples
     ///
-    /// # #[tokio::main]
-    /// # async fn main() {
-    ///     let client = Client::new(Chain::Mainnet, "API_KEY").unwrap();
-    ///     let txs = client
-    ///         .get_transactions(&"0x58eB28A67731c570Ef827C365c89B5751F9E6b0a".parse().unwrap(),
-    ///         None).await.unwrap();
-    /// # }
+    /// ```no_run
+    /// # async fn foo(client: ethers_etherscan::Client) -> Result<(), Box<dyn std::error::Error>> {
+    /// let address = "0x1f162cf730564efD2Bb96eb27486A2801d76AFB6".parse()?;
+    /// let transactions = client.get_transactions(&address, None).await?;
+    /// # Ok(()) }
     /// ```
     pub async fn get_transactions(
         &self,
@@ -578,18 +571,16 @@ impl Client {
     /// Returns the list of internal transactions performed by an address or within a transaction,
     /// with optional pagination.
     ///
+    /// # Examples
+    ///
     /// ```no_run
-    /// # use ethers_etherscan::{Client, account::InternalTxQueryOption};
-    /// # use ethers_core::types::Chain;
+    /// use ethers_etherscan::account::InternalTxQueryOption;
     ///
-    /// # #[tokio::main]
-    /// # async fn main() {
-    ///     let client = Client::new(Chain::Mainnet, "API_KEY").unwrap();
-    ///     let txs = client
-    ///         .get_internal_transactions(
-    ///             InternalTxQueryOption::ByAddress(
-    ///                 "0x2c1ba59d6f58433fb1eaee7d20b26ed83bda51a3".parse().unwrap()), None).await.unwrap();
-    /// # }
+    /// # async fn foo(client: ethers_etherscan::Client) -> Result<(), Box<dyn std::error::Error>> {
+    /// let address = "0x2c1ba59d6f58433fb1eaee7d20b26ed83bda51a3".parse()?;
+    /// let query = InternalTxQueryOption::ByAddress(address);
+    /// let internal_transactions = client.get_internal_transactions(query, None).await?;
+    /// # Ok(()) }
     /// ```
     pub async fn get_internal_transactions(
         &self,
@@ -615,18 +606,16 @@ impl Client {
     /// Returns the list of ERC-20 tokens transferred by an address, with optional filtering by
     /// token contract.
     ///
+    /// # Examples
+    ///
     /// ```no_run
-    /// # use ethers_etherscan::{Client, account::TokenQueryOption};
-    /// # use ethers_core::types::Chain;
+    /// use ethers_etherscan::account::TokenQueryOption;
     ///
-    /// # #[tokio::main]
-    /// # async fn main() {
-    ///     let client = Client::new(Chain::Mainnet, "API_KEY").unwrap();
-    ///     let txs = client
-    ///         .get_erc20_token_transfer_events(
-    ///             TokenQueryOption::ByAddress(
-    ///                 "0x4e83362442b8d1bec281594cea3050c8eb01311c".parse().unwrap()), None).await.unwrap();
-    /// # }
+    /// # async fn foo(client: ethers_etherscan::Client) -> Result<(), Box<dyn std::error::Error>> {
+    /// let address = "0x4e83362442b8d1bec281594cea3050c8eb01311c".parse()?;
+    /// let query = TokenQueryOption::ByAddress(address);
+    /// let events = client.get_erc20_token_transfer_events(query, None).await?;
+    /// # Ok(()) }
     /// ```
     pub async fn get_erc20_token_transfer_events(
         &self,
@@ -643,20 +632,16 @@ impl Client {
     /// Returns the list of ERC-721 ( NFT ) tokens transferred by an address, with optional
     /// filtering by token contract.
     ///
+    /// # Examples
+    ///
     /// ```no_run
-    /// # use ethers_etherscan::{Client, account::TokenQueryOption};
-    /// # use ethers_core::types::Chain;
+    /// use ethers_etherscan::account::TokenQueryOption;
     ///
-    /// # #[tokio::main]
-    /// # async fn main() {
-    ///     let client = Client::new(Chain::Mainnet, "API_KEY").unwrap();
-    ///     let txs = client
-    ///         .get_erc721_token_transfer_events(
-    ///             TokenQueryOption::ByAddressAndContract(
-    ///                 "0x6975be450864c02b4613023c2152ee0743572325".parse().unwrap(),
-    ///                 "0x06012c8cf97bead5deae237070f9587f8e7a266d".parse().unwrap(),
-    ///          ), None).await.unwrap();
-    /// # }
+    /// # async fn foo(client: ethers_etherscan::Client) -> Result<(), Box<dyn std::error::Error>> {
+    /// let contract = "0x06012c8cf97bead5deae237070f9587f8e7a266d".parse()?;
+    /// let query = TokenQueryOption::ByContract(contract);
+    /// let events = client.get_erc721_token_transfer_events(query, None).await?;
+    /// # Ok(()) }
     /// ```
     pub async fn get_erc721_token_transfer_events(
         &self,
@@ -673,20 +658,17 @@ impl Client {
     /// Returns the list of ERC-1155 ( NFT ) tokens transferred by an address, with optional
     /// filtering by token contract.
     ///
+    /// # Examples
+    ///
     /// ```no_run
-    /// # use ethers_etherscan::{Client, account::TokenQueryOption};
-    /// # use ethers_core::types::Chain;
+    /// use ethers_etherscan::account::TokenQueryOption;
     ///
-    /// # #[tokio::main]
-    /// # async fn main() {
-    ///     let client = Client::new(Chain::Mainnet, "API_KEY").unwrap();
-    ///     let txs = client
-    ///         .get_erc1155_token_transfer_events(
-    ///             TokenQueryOption::ByAddressAndContract(
-    ///                 "0x216CD350a4044e7016f14936663e2880Dd2A39d7".parse().unwrap(),
-    ///                 "0x495f947276749ce646f68ac8c248420045cb7b5e".parse().unwrap(),
-    ///          ), None).await.unwrap();
-    /// # }
+    /// # async fn foo(client: ethers_etherscan::Client) -> Result<(), Box<dyn std::error::Error>> {
+    /// let address = "0x216CD350a4044e7016f14936663e2880Dd2A39d7".parse()?;
+    /// let contract = "0x495f947276749ce646f68ac8c248420045cb7b5e".parse()?;
+    /// let query = TokenQueryOption::ByAddressAndContract(address, contract);
+    /// let events = client.get_erc1155_token_transfer_events(query, None).await?;
+    /// # Ok(()) }
     /// ```
     pub async fn get_erc1155_token_transfer_events(
         &self,
@@ -702,17 +684,13 @@ impl Client {
 
     /// Returns the list of blocks mined by an address.
     ///
-    /// ```no_run
-    /// # use ethers_etherscan::Client;
-    /// # use ethers_core::types::Chain;
+    /// # Examples
     ///
-    /// # #[tokio::main]
-    /// # async fn main() {
-    ///     let client = Client::new(Chain::Mainnet, "API_KEY").unwrap();
-    ///     let blocks = client
-    ///         .get_mined_blocks(&"0x9dd134d14d1e65f84b706d6f205cd5b1cd03a46b".parse().unwrap(), None, None)
-    ///         .await.unwrap();
-    /// # }
+    /// ```no_run
+    /// # async fn foo(client: ethers_etherscan::Client) -> Result<(), Box<dyn std::error::Error>> {
+    /// let address = "0x9dd134d14d1e65f84b706d6f205cd5b1cd03a46b".parse()?;
+    /// let blocks = client.get_mined_blocks(&address, None, None).await?;
+    /// # Ok(()) }
     /// ```
     pub async fn get_mined_blocks(
         &self,
diff --git a/ethers-etherscan/src/contract.rs b/ethers-etherscan/src/contract.rs
index edbfdb38..2942afa6 100644
--- a/ethers-etherscan/src/contract.rs
+++ b/ethers-etherscan/src/contract.rs
@@ -312,16 +312,10 @@ impl Client {
     /// # Example
     ///
     /// ```no_run
-    /// # use ethers_etherscan::Client;
-    /// # use ethers_core::types::Chain;
-    ///
-    /// # #[tokio::main]
-    /// # async fn main() {
-    ///     let client = Client::new(Chain::Mainnet, "API_KEY").unwrap();
-    ///     let abi = client
-    ///         .contract_abi("0xBB9bc244D798123fDe783fCc1C72d3Bb8C189413".parse().unwrap())
-    ///         .await.unwrap();
-    /// # }
+    /// # async fn foo(client: ethers_etherscan::Client) -> Result<(), Box<dyn std::error::Error>> {
+    /// let address = "0xBB9bc244D798123fDe783fCc1C72d3Bb8C189413".parse()?;
+    /// let abi = client.contract_abi(address).await?;
+    /// # Ok(()) }
     /// ```
     pub async fn contract_abi(&self, address: Address) -> Result<Abi> {
         // apply caching
@@ -361,15 +355,11 @@ impl Client {
     /// # Example
     ///
     /// ```no_run
-    /// # use ethers_etherscan::Client;
-    /// # use ethers_core::types::Chain;
-    /// # async fn foo() -> Result<(), Box<dyn std::error::Error>> {
-    /// let client = Client::new(Chain::Mainnet, "<your_api_key>")?;
+    /// # async fn foo(client: ethers_etherscan::Client) -> Result<(), Box<dyn std::error::Error>> {
     /// let address = "0xBB9bc244D798123fDe783fCc1C72d3Bb8C189413".parse()?;
     /// let metadata = client.contract_source_code(address).await?;
     /// assert_eq!(metadata.items[0].contract_name, "DAO");
-    /// # Ok(())
-    /// # }
+    /// # Ok(()) }
     /// ```
     pub async fn contract_source_code(&self, address: Address) -> Result<ContractMetadata> {
         // apply caching
diff --git a/ethers-etherscan/src/gas.rs b/ethers-etherscan/src/gas.rs
index e8eacdd4..2428a2e4 100644
--- a/ethers-etherscan/src/gas.rs
+++ b/ethers-etherscan/src/gas.rs
@@ -1,27 +1,57 @@
 use crate::{Client, EtherscanError, Response, Result};
-use ethers_core::types::U256;
+use ethers_core::{types::U256, utils::parse_units};
 use serde::{de, Deserialize, Deserializer};
 use std::{collections::HashMap, str::FromStr};
 
+const WEI_PER_GWEI: u64 = 1_000_000_000;
+
 #[derive(Deserialize, Clone, Debug)]
 #[serde(rename_all = "PascalCase")]
 pub struct GasOracle {
-    #[serde(deserialize_with = "deserialize_number_from_string")]
-    pub safe_gas_price: f64,
-    #[serde(deserialize_with = "deserialize_number_from_string")]
-    pub propose_gas_price: f64,
-    #[serde(deserialize_with = "deserialize_number_from_string")]
-    pub fast_gas_price: f64,
+    /// Safe Gas Price in wei
+    #[serde(deserialize_with = "deser_gwei_amount")]
+    pub safe_gas_price: U256,
+    /// Propose Gas Price in wei
+    #[serde(deserialize_with = "deser_gwei_amount")]
+    pub propose_gas_price: U256,
+    /// Fast Gas Price in wei
+    #[serde(deserialize_with = "deser_gwei_amount")]
+    pub fast_gas_price: U256,
+    /// Last Block
     #[serde(deserialize_with = "deserialize_number_from_string")]
     pub last_block: u64,
-    #[serde(deserialize_with = "deserialize_number_from_string")]
+    /// Suggested Base Fee in wei
+    #[serde(deserialize_with = "deser_gwei_amount")]
     #[serde(rename = "suggestBaseFee")]
-    pub suggested_base_fee: f64,
+    pub suggested_base_fee: U256,
+    /// Gas Used Ratio
     #[serde(deserialize_with = "deserialize_f64_vec")]
     #[serde(rename = "gasUsedRatio")]
     pub gas_used_ratio: Vec<f64>,
 }
 
+// This function is used to deserialize a string or number into a U256 with an
+// amount of gwei. If the contents is a number, deserialize it. If the contents
+// is a string, attempt to deser as first a decimal f64 then a decimal U256.
+fn deser_gwei_amount<'de, D>(deserializer: D) -> Result<U256, D::Error>
+where
+    D: Deserializer<'de>,
+{
+    #[derive(Deserialize)]
+    #[serde(untagged)]
+    enum StringOrInt {
+        Number(u64),
+        String(String),
+    }
+
+    match StringOrInt::deserialize(deserializer)? {
+        StringOrInt::Number(i) => Ok(U256::from(i) * WEI_PER_GWEI),
+        StringOrInt::String(s) => {
+            parse_units(s, "gwei").map(Into::into).map_err(serde::de::Error::custom)
+        }
+    }
+}
+
 fn deserialize_number_from_string<'de, T, D>(deserializer: D) -> Result<T, D::Error>
 where
     D: Deserializer<'de>,
@@ -105,5 +135,42 @@ mod tests {
         }"#;
         let gas_oracle: Response<GasOracle> = serde_json::from_str(v).unwrap();
         assert_eq!(gas_oracle.message, "OK");
+        assert_eq!(
+            gas_oracle.result.propose_gas_price,
+            parse_units("141.9", "gwei").unwrap().into()
+        );
+
+        let v = r#"{
+            "status":"1",
+            "message":"OK",
+            "result":{
+               "LastBlock":"13053741",
+               "SafeGasPrice":"20",
+               "ProposeGasPrice":"22",
+               "FastGasPrice":"24",
+               "suggestBaseFee":"19.230609716",
+               "gasUsedRatio":"0.370119078777807,0.8954731,0.550911766666667,0.212457033333333,0.552463633333333"
+            }
+        }"#;
+        let gas_oracle: Response<GasOracle> = serde_json::from_str(v).unwrap();
+        assert_eq!(gas_oracle.message, "OK");
+        assert_eq!(gas_oracle.result.propose_gas_price, parse_units(22, "gwei").unwrap().into());
+
+        // remove quotes around integers
+        let v = r#"{
+            "status":"1",
+            "message":"OK",
+            "result":{
+               "LastBlock":13053741,
+               "SafeGasPrice":20,
+               "ProposeGasPrice":22,
+               "FastGasPrice":24,
+               "suggestBaseFee":"19.230609716",
+               "gasUsedRatio":"0.370119078777807,0.8954731,0.550911766666667,0.212457033333333,0.552463633333333"
+            }
+        }"#;
+        let gas_oracle: Response<GasOracle> = serde_json::from_str(v).unwrap();
+        assert_eq!(gas_oracle.message, "OK");
+        assert_eq!(gas_oracle.result.propose_gas_price, parse_units(22, "gwei").unwrap().into());
     }
 }
diff --git a/ethers-middleware/src/gas_oracle/etherscan.rs b/ethers-middleware/src/gas_oracle/etherscan.rs
index 39645eb9..4a66b488 100644
--- a/ethers-middleware/src/gas_oracle/etherscan.rs
+++ b/ethers-middleware/src/gas_oracle/etherscan.rs
@@ -44,8 +44,6 @@ impl GasOracle for Etherscan {
             GasCategory::Fast => result.fast_gas_price,
             _ => unreachable!(),
         };
-        // returned gas prices are f64 value in gwei
-        let gas_price = super::from_gwei_f64(gas_price);
         Ok(gas_price)
     }
 
diff --git a/ethers-providers/src/ext/dev_rpc.rs b/ethers-providers/src/ext/dev_rpc.rs
index 6e72b485..b5b7c392 100644
--- a/ethers-providers/src/ext/dev_rpc.rs
+++ b/ethers-providers/src/ext/dev_rpc.rs
@@ -2,21 +2,19 @@
 //!
 //! # Example
 //!
-//!```
+//! ```no_run
 //! use ethers_providers::{Provider, Http, Middleware, DevRpcMiddleware};
 //! use ethers_core::types::TransactionRequest;
 //! use ethers_core::utils::Anvil;
-//! use std::convert::TryFrom;
 //!
-//! # #[tokio::main(flavor = "current_thread")]
-//! # async fn main() -> Result<(), Box<dyn std::error::Error>> {
+//! # async fn foo() -> Result<(), Box<dyn std::error::Error>> {
 //! let anvil = Anvil::new().spawn();
-//! let provider = Provider::<Http>::try_from(anvil.endpoint()).unwrap();
+//! let provider = Provider::<Http>::try_from(anvil.endpoint())?;
 //! let client = DevRpcMiddleware::new(provider);
 //!
 //! // snapshot the initial state
-//! let block0 = client.get_block_number().await.unwrap();
-//! let snap_id = client.snapshot().await.unwrap();
+//! let block0 = client.get_block_number().await?;
+//! let snap_id = client.snapshot().await?;
 //!
 //! // send a transaction
 //! let accounts = client.get_accounts().await?;
@@ -29,12 +27,12 @@
 //! assert_eq!(balance_after, balance_before + 1000);
 //!
 //! // revert to snapshot
-//! client.revert_to_snapshot(snap_id).await.unwrap();
+//! client.revert_to_snapshot(snap_id).await?;
 //! let balance_after_revert = client.get_balance(to, None).await?;
 //! assert_eq!(balance_after_revert, balance_before);
-//! # Ok(())
-//! # }
+//! # Ok(()) }
 //! ```
+
 use crate::{Middleware, MiddlewareError, ProviderError};
 use async_trait::async_trait;
 use ethers_core::types::U256;
diff --git a/ethers-providers/src/middleware.rs b/ethers-providers/src/middleware.rs
index 8fce071f..2970bccf 100644
--- a/ethers-providers/src/middleware.rs
+++ b/ethers-providers/src/middleware.rs
@@ -225,6 +225,7 @@ pub trait Middleware: Sync + Send + Debug {
     }
 
     /// Returns the ENS name the `address` resolves to (or None if not configured).
+    ///
     /// # Panics
     ///
     /// If the bytes returned from the ENS registrar/resolver cannot be interpreted as
@@ -236,16 +237,14 @@ pub trait Middleware: Sync + Send + Debug {
     /// Returns the avatar HTTP link of the avatar that the `ens_name` resolves to (or None
     /// if not configured)
     ///
-    /// # Example
+    /// # Examples
+    ///
     /// ```no_run
-    /// # use ethers_providers::{Provider, Http as HttpProvider, Middleware};
-    /// # use std::convert::TryFrom;
-    /// # #[tokio::main(flavor = "current_thread")]
-    /// # async fn main() {
-    /// # let provider = Provider::<HttpProvider>::try_from("https://eth.llamarpc.com").unwrap();
-    /// let avatar = provider.resolve_avatar("parishilton.eth").await.unwrap();
+    /// # use ethers_providers::{Provider, Http, Middleware};
+    /// # async fn foo(provider: Provider<Http>) -> Result<(), Box<dyn std::error::Error>> {
+    /// let avatar = provider.resolve_avatar("parishilton.eth").await?;
     /// assert_eq!(avatar.to_string(), "https://i.imgur.com/YW3Hzph.jpg");
-    /// # }
+    /// # Ok(()) }
     /// ```
     ///
     /// # Panics
@@ -260,15 +259,16 @@ pub trait Middleware: Sync + Send + Debug {
     ///
     /// # Example
     /// ```no_run
-    /// # use ethers_providers::{Provider, Http as HttpProvider, Middleware};
-    /// # use std::{str::FromStr, convert::TryFrom};
-    /// # #[tokio::main(flavor = "current_thread")]
-    /// # async fn main() {
-    /// # let provider = Provider::<HttpProvider>::try_from("https://eth.llamarpc.com").unwrap();
-    /// let token = ethers_providers::erc::ERCNFT::from_str("erc721:0xc92ceddfb8dd984a89fb494c376f9a48b999aafc/9018").unwrap();
-    /// let token_image = provider.resolve_nft(token).await.unwrap();
-    /// assert_eq!(token_image.to_string(), "https://creature.mypinata.cloud/ipfs/QmNwj3aUzXfG4twV3no7hJRYxLLAWNPk6RrfQaqJ6nVJFa/9018.jpg");
-    /// # }
+    /// # use ethers_providers::{Provider, Http, Middleware};
+    /// use ethers_providers::erc::ERCNFT;
+    /// # async fn foo(provider: Provider<Http>) -> Result<(), Box<dyn std::error::Error>> {
+    /// let token = "erc721:0xc92ceddfb8dd984a89fb494c376f9a48b999aafc/9018".parse()?;
+    /// let token_image = provider.resolve_nft(token).await?;
+    /// assert_eq!(
+    ///     token_image.to_string(),
+    ///     "https://creature.mypinata.cloud/ipfs/QmNwj3aUzXfG4twV3no7hJRYxLLAWNPk6RrfQaqJ6nVJFa/9018.jpg"
+    /// );
+    /// # Ok(()) }
     /// ```
     ///
     /// # Panics
diff --git a/ethers-providers/src/rpc/provider.rs b/ethers-providers/src/rpc/provider.rs
index efe6a833..5478ae13 100644
--- a/ethers-providers/src/rpc/provider.rs
+++ b/ethers-providers/src/rpc/provider.rs
@@ -211,16 +211,14 @@ impl<P: JsonRpcClient> Provider<P> {
     /// [`call_raw::spoof`]: crate::call_raw::spoof
     ///
     /// # Example
+    ///
     /// ```no_run
     /// # use ethers_core::{
     /// #     types::{Address, TransactionRequest, H256},
     /// #     utils::{parse_ether, Geth},
     /// # };
     /// # use ethers_providers::{Provider, Http, Middleware, call_raw::{RawCall, spoof}};
-    /// # use std::convert::TryFrom;
-    /// #
-    /// # #[tokio::main(flavor = "current_thread")]
-    /// # async fn main() -> Result<(), Box<dyn std::error::Error>> {
+    /// # async fn foo() -> Result<(), Box<dyn std::error::Error>> {
     /// let geth = Geth::new().spawn();
     /// let provider = Provider::<Http>::try_from(geth.endpoint()).unwrap();
     ///
@@ -234,8 +232,7 @@ impl<P: JsonRpcClient> Provider<P> {
     /// // override the sender's balance for the call
     /// let mut state = spoof::balance(adr1, pay_amt * 2);
     /// provider.call_raw(&tx).state(&state).await?;
-    /// # Ok(())
-    /// # }
+    /// # Ok(()) }
     /// ```
     pub fn call_raw<'a>(&'a self, tx: &'a TypedTransaction) -> CallBuilder<'a, P> {
         CallBuilder::new(self, tx)
diff --git a/ethers-providers/src/rpc/pubsub.rs b/ethers-providers/src/rpc/pubsub.rs
index 690606d6..a1157950 100644
--- a/ethers-providers/src/rpc/pubsub.rs
+++ b/ethers-providers/src/rpc/pubsub.rs
@@ -94,16 +94,18 @@ where
             return Poll::Ready(next_element)
         }
 
-        let this = self.project();
-        match futures_util::ready!(this.rx.poll_next(ctx)) {
-            Some(item) => match serde_json::from_str(item.get()) {
-                Ok(res) => Poll::Ready(Some(res)),
-                Err(err) => {
-                    error!("failed to deserialize item {:?}", err);
-                    Poll::Pending
-                }
-            },
-            None => Poll::Ready(None),
+        let mut this = self.project();
+        loop {
+            return match futures_util::ready!(this.rx.as_mut().poll_next(ctx)) {
+                Some(item) => match serde_json::from_str(item.get()) {
+                    Ok(res) => Poll::Ready(Some(res)),
+                    Err(err) => {
+                        error!("failed to deserialize item {:?}", err);
+                        continue
+                    }
+                },
+                None => Poll::Ready(None),
+            }
         }
     }
 }
diff --git a/ethers-providers/src/toolbox/call_raw.rs b/ethers-providers/src/toolbox/call_raw.rs
index a3f0b771..0a959503 100644
--- a/ethers-providers/src/toolbox/call_raw.rs
+++ b/ethers-providers/src/toolbox/call_raw.rs
@@ -329,21 +329,19 @@ pub mod spoof {
     /// Returns an empty state override set.
     ///
     /// # Example
+    ///
     /// ```no_run
     /// # use ethers_core::{
     /// #     types::{Address, TransactionRequest, H256},
     /// #     utils::{parse_ether, Geth},
     /// # };
     /// # use ethers_providers::{Provider, Http, Middleware, call_raw::{spoof, RawCall}};
-    /// # use std::convert::TryFrom;
-    /// #
-    /// # #[tokio::main(flavor = "current_thread")]
-    /// # async fn main() -> Result<(), Box<dyn std::error::Error>> {
+    /// # async fn foo() -> Result<(), Box<dyn std::error::Error>> {
     /// let geth = Geth::new().spawn();
     /// let provider = Provider::<Http>::try_from(geth.endpoint()).unwrap();
     ///
-    /// let adr1: Address = "0x6fC21092DA55B392b045eD78F4732bff3C580e2c".parse().unwrap();
-    /// let adr2: Address = "0x295a70b2de5e3953354a6a8344e616ed314d7251".parse().unwrap();
+    /// let adr1: Address = "0x6fC21092DA55B392b045eD78F4732bff3C580e2c".parse()?;
+    /// let adr2: Address = "0x295a70b2de5e3953354a6a8344e616ed314d7251".parse()?;
     /// let key = H256::from_low_u64_be(1);
     /// let val = H256::from_low_u64_be(17);
     ///
@@ -356,7 +354,7 @@ pub mod spoof {
     /// // override the nonce at `adr1`
     /// state.account(adr1).nonce(2.into());
     ///
-    /// provider.call_raw(&tx).state(&state).await.unwrap();
+    /// provider.call_raw(&tx).state(&state).await?;
     /// # Ok(())
     /// # }
     /// ```
@@ -373,10 +371,7 @@ pub mod spoof {
     /// #     utils::{parse_ether, Geth},
     /// # };
     /// # use ethers_providers::{Provider, Http, Middleware, call_raw::{RawCall, spoof}};
-    /// # use std::convert::TryFrom;
-    /// #
-    /// # #[tokio::main(flavor = "current_thread")]
-    /// # async fn main() -> Result<(), Box<dyn std::error::Error>> {
+    /// # async fn foo() -> Result<(), Box<dyn std::error::Error>> {
     /// let geth = Geth::new().spawn();
     /// let provider = Provider::<Http>::try_from(geth.endpoint()).unwrap();
     ///
@@ -408,10 +403,7 @@ pub mod spoof {
     /// #     utils::{parse_ether, Geth},
     /// # };
     /// # use ethers_providers::{Provider, Http, Middleware, call_raw::{RawCall, spoof}};
-    /// # use std::convert::TryFrom;
-    /// #
-    /// # #[tokio::main(flavor = "current_thread")]
-    /// # async fn main() -> Result<(), Box<dyn std::error::Error>> {
+    /// # async fn foo() -> Result<(), Box<dyn std::error::Error>> {
     /// let geth = Geth::new().spawn();
     /// let provider = Provider::<Http>::try_from(geth.endpoint()).unwrap();
     ///
@@ -441,10 +433,7 @@ pub mod spoof {
     /// #     utils::{parse_ether, Geth},
     /// # };
     /// # use ethers_providers::{Provider, Http, Middleware, call_raw::{RawCall, spoof}};
-    /// # use std::convert::TryFrom;
-    /// #
-    /// # #[tokio::main(flavor = "current_thread")]
-    /// # async fn main() -> Result<(), Box<dyn std::error::Error>> {
+    /// # async fn foo() -> Result<(), Box<dyn std::error::Error>> {
     /// let geth = Geth::new().spawn();
     /// let provider = Provider::<Http>::try_from(geth.endpoint()).unwrap();
     ///
@@ -469,16 +458,14 @@ pub mod spoof {
     /// and key.
     ///
     /// # Example
+    ///
     /// ```no_run
     /// # use ethers_core::{
     /// #     types::{Address, TransactionRequest, H256},
     /// #     utils::{parse_ether, Geth},
     /// # };
     /// # use ethers_providers::{Provider, Http, Middleware, call_raw::{RawCall, spoof}};
-    /// # use std::convert::TryFrom;
-    /// #
-    /// # #[tokio::main(flavor = "current_thread")]
-    /// # async fn main() -> Result<(), Box<dyn std::error::Error>> {
+    /// # async fn foo() -> Result<(), Box<dyn std::error::Error>> {
     /// let geth = Geth::new().spawn();
     /// let provider = Provider::<Http>::try_from(geth.endpoint()).unwrap();
     ///
diff --git a/ethers-providers/src/toolbox/pending_transaction.rs b/ethers-providers/src/toolbox/pending_transaction.rs
index d9deabc3..cbe2e0a0 100644
--- a/ethers-providers/src/toolbox/pending_transaction.rs
+++ b/ethers-providers/src/toolbox/pending_transaction.rs
@@ -24,32 +24,15 @@ use std::{
 ///
 /// # Example
 ///
-///```
-/// # use ethers_providers::{Provider, Http};
-/// # use ethers_core::utils::Anvil;
-/// # use std::convert::TryFrom;
-/// use ethers_providers::Middleware;
+/// ```ignore
 /// use ethers_core::types::TransactionRequest;
 ///
-/// # #[tokio::main(flavor = "current_thread")]
-/// # async fn main() -> Result<(), Box<dyn std::error::Error>> {
-/// # let anvil = Anvil::new().spawn();
-/// # let client = Provider::<Http>::try_from(anvil.endpoint()).unwrap();
-/// # let accounts = client.get_accounts().await?;
-/// # let from = accounts[0];
-/// # let to = accounts[1];
-/// # let balance_before = client.get_balance(to, None).await?;
 /// let tx = TransactionRequest::new().to(to).value(1000).from(from);
 /// let receipt = client
 ///     .send_transaction(tx, None)
 ///     .await?                           // PendingTransaction<_>
 ///     .log_msg("Pending transfer hash") // print pending tx hash with message
 ///     .await?;                          // Result<Option<TransactionReceipt>, _>
-/// # let _ = receipt;
-/// # let balance_after = client.get_balance(to, None).await?;
-/// # assert_eq!(balance_after, balance_before + 1000);
-/// # Ok(())
-/// # }
 /// ```
 #[pin_project]
 pub struct PendingTransaction<'a, P> {


Test patch:
diff --git a/ethers-contract/tests/it/eip712.rs b/ethers-contract/tests/it/eip712.rs
index 82ded36a..d89d9b26 100644
--- a/ethers-contract/tests/it/eip712.rs
+++ b/ethers-contract/tests/it/eip712.rs
@@ -11,7 +11,7 @@ use ethers_core::{
 };
 
 #[test]
-fn test_derive_eip712() {
+fn derive_eip712() {
     #[derive(Debug, Clone, Eip712, EthAbiType)]
     #[eip712(
         name = "Radicle",
@@ -43,7 +43,7 @@ fn test_derive_eip712() {
 }
 
 #[test]
-fn test_struct_hash() {
+fn struct_hash() {
     #[derive(Debug, Clone, Eip712, EthAbiType)]
     #[eip712(
         name = "Radicle",
@@ -80,7 +80,7 @@ fn test_struct_hash() {
 }
 
 #[test]
-fn test_derive_eip712_nested() {
+fn derive_eip712_nested() {
     #[derive(Debug, Clone, Eip712, EthAbiType)]
     #[eip712(
         name = "MyDomain",
@@ -126,7 +126,7 @@ fn test_derive_eip712_nested() {
 }
 
 #[test]
-fn test_uniswap_v2_permit_hash() {
+fn uniswap_v2_permit_hash() {
     // See examples/permit_hash.rs for comparison
     // the following produces the same permit_hash as in the example
 
@@ -162,7 +162,7 @@ fn test_uniswap_v2_permit_hash() {
 }
 
 #[test]
-fn test_domain_hash_constants() {
+fn domain_hash_constants() {
     assert_eq!(
         EIP712_DOMAIN_TYPE_HASH,
         keccak256(
@@ -174,3 +174,21 @@ fn test_domain_hash_constants() {
         keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract,bytes32 salt)")
     );
 }
+
+// https://t.me/ethers_rs/26844
+#[test]
+fn raw_ident_fields() {
+    #[derive(Debug, Clone, Eip712, EthAbiType)]
+    #[eip712(name = "replica", version = "1", chain_id = 6666)]
+    pub struct Message {
+        pub title: String,
+        pub href: String,
+        pub r#type: String,
+        pub timestamp: U256,
+    }
+
+    assert_eq!(
+        Message::type_hash().unwrap(),
+        keccak256("Message(string title,string href,string type,uint256 timestamp)")
+    );
+}
diff --git a/ethers-etherscan/tests/it/account.rs b/ethers-etherscan/tests/it/account.rs
index 035ba365..db581ee9 100644
--- a/ethers-etherscan/tests/it/account.rs
+++ b/ethers-etherscan/tests/it/account.rs
@@ -23,7 +23,7 @@ async fn get_ether_balance_multi_success() {
     run_with_client(Chain::Mainnet, |client| async move {
         let balances = client
             .get_ether_balance_multi(
-                &[&"0x58eB28A67731c570Ef827C365c89B5751F9E6b0a".parse().unwrap()],
+                &["0x58eB28A67731c570Ef827C365c89B5751F9E6b0a".parse().unwrap()],
                 None,
             )
             .await;
diff --git a/ethers-etherscan/tests/it/gas.rs b/ethers-etherscan/tests/it/gas.rs
index 7c8e548e..1a69ba99 100644
--- a/ethers-etherscan/tests/it/gas.rs
+++ b/ethers-etherscan/tests/it/gas.rs
@@ -1,5 +1,5 @@
 use crate::*;
-use ethers_core::types::Chain;
+use ethers_core::types::{Chain, U256};
 use serial_test::serial;
 
 #[tokio::test]
@@ -34,11 +34,11 @@ async fn gas_oracle_success() {
 
         let oracle = result.unwrap();
 
-        assert!(oracle.safe_gas_price > 0f64);
-        assert!(oracle.propose_gas_price > 0f64);
-        assert!(oracle.fast_gas_price > 0f64);
+        assert!(oracle.safe_gas_price > U256::zero());
+        assert!(oracle.propose_gas_price > U256::zero());
+        assert!(oracle.fast_gas_price > U256::zero());
         assert!(oracle.last_block > 0);
-        assert!(oracle.suggested_base_fee > 0.0);
+        assert!(oracle.suggested_base_fee > U256::zero());
         assert!(!oracle.gas_used_ratio.is_empty());
     })
     .await