Repository: gakonst/ethers-rs
Pull request #1643 (2022-08-30 02:43:55)

chore: bump eth-keystore
<!--
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.
-->

## Solution

<!--
Summarize the solution and provide any necessary context needed to understand
the code change.
-->

## PR Checklist

- [ ] Added Tests
- [ ] Added Documentation
- [ ] Updated the changelog



Patch:
diff --git a/Cargo.lock b/Cargo.lock
index b473d7b5..28c4352e 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -481,7 +481,7 @@ checksum = "9ae3c82e4355234767756212c570e29833699ab63e6ffd161887314cc5b43847"
 dependencies = [
  "aead",
  "cipher 0.4.3",
- "ctr 0.9.1",
+ "ctr",
  "subtle",
 ]
 
@@ -917,15 +917,6 @@ dependencies = [
  "syn",
 ]
 
-[[package]]
-name = "ctr"
-version = "0.8.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "049bb91fb4aaf0e3c7efa6cd5ef877dbbbd15b39dad06d9948de4ec8a75761ea"
-dependencies = [
- "cipher 0.3.0",
-]
-
 [[package]]
 name = "ctr"
 version = "0.9.1"
@@ -1152,12 +1143,12 @@ dependencies = [
 
 [[package]]
 name = "eth-keystore"
-version = "0.4.2"
+version = "0.5.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6f65b750ac950f2f825b36d08bef4cda4112e19a7b1a68f6e2bb499413e12440"
+checksum = "1fda3bf123be441da5260717e0661c25a2fd9cb2b2c1d20bf2e05580047158ab"
 dependencies = [
- "aes 0.7.5",
- "ctr 0.8.0",
+ "aes 0.8.1",
+ "ctr",
  "digest 0.10.3",
  "hex",
  "hmac 0.12.1",
@@ -3340,11 +3331,11 @@ checksum = "73b4b750c782965c211b42f022f59af1fbceabdd026623714f104152f1ec149f"
 
 [[package]]
 name = "salsa20"
-version = "0.9.0"
+version = "0.10.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0c0fbb5f676da676c260ba276a8f43a8dc67cf02d1438423aeb1c677a7212686"
+checksum = "97a22f5af31f73a954c10289c93e8a50cc23d971e80ee446f1f6f7137a088213"
 dependencies = [
- "cipher 0.3.0",
+ "cipher 0.4.3",
 ]
 
 [[package]]
@@ -3380,13 +3371,12 @@ checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd"
 
 [[package]]
 name = "scrypt"
-version = "0.8.1"
+version = "0.10.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e73d6d7c6311ebdbd9184ad6c4447b2f36337e327bda107d3ba9e3c374f9d325"
+checksum = "9f9e24d2b632954ded8ab2ef9fea0a0c769ea56ea98bddbafbad22caeeadf45d"
 dependencies = [
  "hmac 0.12.1",
- "password-hash 0.3.2",
- "pbkdf2 0.10.1",
+ "pbkdf2 0.11.0",
  "salsa20",
  "sha2 0.10.2",
 ]
diff --git a/ethers-contract/src/multicall/mod.rs b/ethers-contract/src/multicall/mod.rs
index de30403d..15e77c2c 100644
--- a/ethers-contract/src/multicall/mod.rs
+++ b/ethers-contract/src/multicall/mod.rs
@@ -39,8 +39,8 @@ pub static MULTICALL_SUPPORTED_CHAIN_IDS: Lazy<[U256; 47]> = Lazy::new(|| {
         U256::from(Ropsten),                  // Ropsten
         U256::from(Sepolia),                  // Sepolia
         U256::from(Optimism),                 // Optimism
+        U256::from(OptimismGoerli),           // OptimismGoerli
         U256::from(OptimismKovan),            // OptimismKovan
-        U256::from(420),                      // OptimismGoerli
         U256::from(Arbitrum),                 // Arbitrum
         U256::from(421613),                   // ArbitrumGoerli,
         U256::from(ArbitrumTestnet),          // Arbitrum Rinkeby
diff --git a/ethers-core/src/types/chain.rs b/ethers-core/src/types/chain.rs
index c082f0a6..88ff947b 100644
--- a/ethers-core/src/types/chain.rs
+++ b/ethers-core/src/types/chain.rs
@@ -46,6 +46,7 @@ pub enum Chain {
     MoonbeamDev = 1281,
     Moonriver = 1285,
     Optimism = 10,
+    OptimismGoerli = 420,
     OptimismKovan = 69,
     Arbitrum = 42161,
     ArbitrumTestnet = 421611,
@@ -104,6 +105,7 @@ impl Chain {
             Chain::Sepolia |
             Chain::Moonbase |
             Chain::MoonbeamDev |
+            Chain::OptimismGoerli |
             Chain::OptimismKovan |
             Chain::Poa |
             Chain::Sokol |
@@ -142,6 +144,10 @@ impl Chain {
             Chain::Optimism => {
                 ("https://api-optimistic.etherscan.io/api", "https://optimistic.etherscan.io")
             }
+            Chain::OptimismGoerli => (
+                "https://api-goerli-optimistic.etherscan.io/api",
+                "https://goerli-optimism.etherscan.io",
+            ),
             Chain::OptimismKovan => (
                 "https://api-kovan-optimistic.etherscan.io/api",
                 "https://kovan-optimistic.etherscan.io",
@@ -229,6 +235,7 @@ impl fmt::Display for Chain {
             Chain::MoonbeamDev => "moonbeam-dev",
             Chain::Moonriver => "moonriver",
             Chain::Optimism => "optimism",
+            Chain::OptimismGoerli => "optimism-goerli",
             Chain::OptimismKovan => "optimism-kovan",
             Chain::Fantom => "fantom",
             Chain::Dev => "dev",
@@ -300,6 +307,7 @@ impl TryFrom<u64> for Chain {
             1281 => Chain::MoonbeamDev,
             1285 => Chain::Moonriver,
             10 => Chain::Optimism,
+            420 => Chain::OptimismGoerli,
             69 => Chain::OptimismKovan,
             56 => Chain::BinanceSmartChain,
             97 => Chain::BinanceSmartChainTestnet,
@@ -354,6 +362,7 @@ impl FromStr for Chain {
             "moonbeam-dev" => Chain::MoonbeamDev,
             "moonriver" => Chain::Moonriver,
             "optimism" => Chain::Optimism,
+            "optimism-goerli" => Chain::OptimismGoerli,
             "optimism-kovan" => Chain::OptimismKovan,
             "fantom" => Chain::Fantom,
             "fantom-testnet" => Chain::FantomTestnet,
@@ -386,6 +395,7 @@ impl Chain {
         matches!(
             self,
             Chain::Optimism |
+                Chain::OptimismGoerli |
                 Chain::OptimismKovan |
                 Chain::Fantom |
                 Chain::FantomTestnet |
diff --git a/ethers-core/src/utils/anvil.rs b/ethers-core/src/utils/anvil.rs
index ac941b5b..05cfabed 100644
--- a/ethers-core/src/utils/anvil.rs
+++ b/ethers-core/src/utils/anvil.rs
@@ -1,5 +1,5 @@
 use crate::{
-    types::Address,
+    types::{Address, Chain},
     utils::{secret_key_to_address, unused_port},
 };
 use k256::{ecdsa::SigningKey, SecretKey as K256SecretKey};
@@ -21,6 +21,7 @@ pub struct AnvilInstance {
     private_keys: Vec<K256SecretKey>,
     addresses: Vec<Address>,
     port: u16,
+    chain_id: Option<u64>,
 }
 
 impl AnvilInstance {
@@ -39,6 +40,11 @@ impl AnvilInstance {
         self.port
     }
 
+    /// Returns the chain of the anvil instance
+    pub fn chain_id(&self) -> u64 {
+        self.chain_id.unwrap_or_else(|| Chain::AnvilHardhat.into())
+    }
+
     /// Returns the HTTP endpoint of this instance
     pub fn endpoint(&self) -> String {
         format!("http://localhost:{}", self.port)
@@ -82,6 +88,7 @@ pub struct Anvil {
     program: Option<PathBuf>,
     port: Option<u16>,
     block_time: Option<u64>,
+    chain_id: Option<u64>,
     mnemonic: Option<String>,
     fork: Option<String>,
     fork_block_number: Option<u64>,
@@ -139,6 +146,13 @@ impl Anvil {
         self
     }
 
+    /// Sets the chain_id the `anvil` instance will use.
+    #[must_use]
+    pub fn chain_id<T: Into<u64>>(mut self, chain_id: T) -> Self {
+        self.chain_id = Some(chain_id.into());
+        self
+    }
+
     /// Sets the mnemonic which will be used when the `anvil` instance is launched.
     #[must_use]
     pub fn mnemonic<T: Into<String>>(mut self, mnemonic: T) -> Self {
@@ -208,6 +222,10 @@ impl Anvil {
             cmd.arg("-m").arg(mnemonic);
         }
 
+        if let Some(chain_id) = self.chain_id {
+            cmd.arg("--chain-id").arg(chain_id.to_string());
+        }
+
         if let Some(block_time) = self.block_time {
             cmd.arg("-b").arg(block_time.to_string());
         }
@@ -258,7 +276,7 @@ impl Anvil {
 
         child.stdout = Some(reader.into_inner());
 
-        AnvilInstance { pid: child, private_keys, addresses, port }
+        AnvilInstance { pid: child, private_keys, addresses, port, chain_id: self.chain_id }
     }
 }
 
diff --git a/ethers-etherscan/src/lib.rs b/ethers-etherscan/src/lib.rs
index 89ec0000..5b150d5d 100644
--- a/ethers-etherscan/src/lib.rs
+++ b/ethers-etherscan/src/lib.rs
@@ -85,6 +85,7 @@ impl Client {
             Chain::Rinkeby |
             Chain::Goerli |
             Chain::Optimism |
+            Chain::OptimismGoerli |
             Chain::OptimismKovan |
             Chain::BinanceSmartChain |
             Chain::BinanceSmartChainTestnet |
diff --git a/ethers-signers/Cargo.toml b/ethers-signers/Cargo.toml
index 8e638e0d..6e8bd7e3 100644
--- a/ethers-signers/Cargo.toml
+++ b/ethers-signers/Cargo.toml
@@ -37,7 +37,7 @@ tracing = { version = "0.1.36", optional = true }
 spki = { version = "0.6.0", optional = true }
 
 [target.'cfg(not(target_arch = "wasm32"))'.dependencies]
-eth-keystore = { version = "0.4.2" }
+eth-keystore = { version = "0.5.0" }
 home = { version = "0.5.3", optional = true }
 
 [dev-dependencies]
diff --git a/examples/contract_human_readable.rs b/examples/contract_human_readable.rs
index 33ddc2d2..3148dc58 100644
--- a/examples/contract_human_readable.rs
+++ b/examples/contract_human_readable.rs
@@ -42,7 +42,7 @@ async fn main() -> Result<()> {
         Provider::<Http>::try_from(anvil.endpoint())?.interval(Duration::from_millis(10u64));
 
     // 4. instantiate the client with the wallet
-    let client = SignerMiddleware::new(provider, wallet);
+    let client = SignerMiddleware::new(provider, wallet.with_chain_id(anvil.chain_id()));
     let client = Arc::new(client);
 
     // 5. create a factory which will be used to deploy instances of the contract
diff --git a/examples/contract_with_abi.rs b/examples/contract_with_abi.rs
index 67219a78..35425777 100644
--- a/examples/contract_with_abi.rs
+++ b/examples/contract_with_abi.rs
@@ -31,7 +31,7 @@ async fn main() -> Result<()> {
         Provider::<Http>::try_from(anvil.endpoint())?.interval(Duration::from_millis(10u64));
 
     // 4. instantiate the client with the wallet
-    let client = SignerMiddleware::new(provider, wallet);
+    let client = SignerMiddleware::new(provider, wallet.with_chain_id(anvil.chain_id()));
     let client = Arc::new(client);
 
     // 5. create a factory which will be used to deploy instances of the contract
diff --git a/examples/contract_with_abi_and_bytecode.rs b/examples/contract_with_abi_and_bytecode.rs
index c1920b12..2748e252 100644
--- a/examples/contract_with_abi_and_bytecode.rs
+++ b/examples/contract_with_abi_and_bytecode.rs
@@ -22,7 +22,7 @@ async fn main() -> Result<()> {
         Provider::<Http>::try_from(anvil.endpoint())?.interval(Duration::from_millis(10u64));
 
     // 4. instantiate the client with the wallet
-    let client = Arc::new(SignerMiddleware::new(provider, wallet));
+    let client = Arc::new(SignerMiddleware::new(provider, wallet.with_chain_id(anvil.chain_id())));
 
     // 5. deploy contract
     let greeter_contract =
diff --git a/examples/local_signer.rs b/examples/local_signer.rs
index 64c570c3..764de4f5 100644
--- a/examples/local_signer.rs
+++ b/examples/local_signer.rs
@@ -13,7 +13,7 @@ async fn main() -> Result<()> {
     let provider = Provider::<Http>::try_from(anvil.endpoint())?;
 
     // connect the wallet to the provider
-    let client = SignerMiddleware::new(provider, wallet);
+    let client = SignerMiddleware::new(provider, wallet.with_chain_id(anvil.chain_id()));
 
     // craft the transaction
     let tx = TransactionRequest::new().to(wallet2.address()).value(10000);


Test patch:
diff --git a/ethers-contract/tests/it/abigen.rs b/ethers-contract/tests/it/abigen.rs
index 15658294..273498d0 100644
--- a/ethers-contract/tests/it/abigen.rs
+++ b/ethers-contract/tests/it/abigen.rs
@@ -4,7 +4,7 @@
 use ethers_contract::{abigen, Abigen, EthCall, EthEvent};
 use ethers_core::{
     abi::{AbiDecode, AbiEncode, Address, Tokenizable},
-    types::{transaction::eip2718::TypedTransaction, Eip1559TransactionRequest, U256},
+    types::{transaction::eip2718::TypedTransaction, Chain, Eip1559TransactionRequest, U256},
     utils::Anvil,
 };
 use ethers_middleware::SignerMiddleware;
@@ -608,7 +608,8 @@ async fn can_send_struct_param() {
     let server = Anvil::new().spawn();
     let wallet: LocalWallet = server.keys()[0].clone().into();
     let provider = Provider::try_from(server.endpoint()).unwrap();
-    let client = Arc::new(SignerMiddleware::new(provider, wallet.with_chain_id(1337u64)));
+    let client =
+        Arc::new(SignerMiddleware::new(provider, wallet.with_chain_id(Chain::AnvilHardhat)));
 
     let contract = StructContract::deploy(client, ()).unwrap().legacy().send().await.unwrap();
 
diff --git a/ethers-middleware/tests/signer.rs b/ethers-middleware/tests/signer.rs
index 0f1e94ff..3929e7c5 100644
--- a/ethers-middleware/tests/signer.rs
+++ b/ethers-middleware/tests/signer.rs
@@ -50,6 +50,40 @@ async fn send_eth() {
     assert!(balance_before > balance_after);
 }
 
+// hardhat compatibility test, to show hardhat rejects tx signed for other chains
+#[tokio::test]
+#[cfg(not(feature = "celo"))]
+#[ignore]
+async fn send_with_chain_id_hardhat() {
+    let wallet: LocalWallet =
+        "ac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80".parse().unwrap();
+    let provider = Provider::try_from("http://localhost:8545").unwrap();
+    let client = SignerMiddleware::new(provider, wallet);
+
+    let tx = TransactionRequest::new().to(Address::random()).value(100u64);
+    let res = client.send_transaction(tx, None).await;
+
+    let err = res.unwrap_err();
+    assert!(err
+        .to_string()
+        .contains("Trying to send an incompatible EIP-155 transaction, signed for another chain."));
+}
+
+#[tokio::test]
+#[cfg(not(feature = "celo"))]
+#[ignore]
+async fn send_with_chain_id_anvil() {
+    let wallet: LocalWallet =
+        "ac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80".parse().unwrap();
+    let provider = Provider::try_from("http://localhost:8545").unwrap();
+    let client = SignerMiddleware::new(provider, wallet);
+
+    let tx = TransactionRequest::new().to(Address::random()).value(100u64);
+    let res = client.send_transaction(tx, None).await;
+
+    let _err = res.unwrap_err();
+}
+
 #[tokio::test]
 #[cfg(not(feature = "celo"))]
 async fn pending_txs_with_confirmations_testnet() {
diff --git a/examples/ethers-wasm/tests/contract_with_abi.rs b/examples/ethers-wasm/tests/contract_with_abi.rs
index 678f54b2..5530df67 100644
--- a/examples/ethers-wasm/tests/contract_with_abi.rs
+++ b/examples/ethers-wasm/tests/contract_with_abi.rs
@@ -1,12 +1,14 @@
 #![cfg(target_arch = "wasm32")]
 
-use wasm_bindgen_test::*;
-
-use ethers::prelude::{
-    abigen, ContractFactory, Http, JsonRpcClient, LocalWallet, Provider, SignerMiddleware, Ws,
+use ethers::{
+    prelude::{
+        abigen, ContractFactory, Http, JsonRpcClient, LocalWallet, Provider, SignerMiddleware, Ws,
+    },
+    signers::Signer,
+    types::Chain,
 };
-
 use std::{convert::TryFrom, sync::Arc};
+use wasm_bindgen_test::*;
 
 wasm_bindgen_test_configure!(run_in_browser);
 
@@ -22,14 +24,14 @@ abigen!(
 async fn http_connect_and_deploy() {
     console_log!("connecting http...");
     let provider = Provider::<Http>::try_from("http://localhost:8545").unwrap();
-    deploy(provider, ethers_wasm::utils::key(0)).await;
+    deploy(provider, ethers_wasm::utils::key(0).with_chain_id(Chain::AnvilHardhat)).await;
 }
 
 #[wasm_bindgen_test]
 async fn ws_connect_and_deploy() {
     console_log!("connecting ws...");
     let provider = Provider::new(Ws::connect("ws://localhost:8545").await.unwrap());
-    deploy(provider, ethers_wasm::utils::key(1)).await;
+    deploy(provider, ethers_wasm::utils::key(1).with_chain_id(Chain::AnvilHardhat)).await;
 }
 
 async fn deploy<T: JsonRpcClient>(provider: Provider<T>, wallet: LocalWallet) {