Repository: gakonst/ethers-rs
Pull request #913 (2022-02-15 03:10:20)

chore(deps): bump eth-keystore from 0.4.0 to 0.4.1
Bumps [eth-keystore](https://github.com/roynalnaruto/eth-keystore-rs) from 0.4.0 to 0.4.1.
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a href="https://github.com/roynalnaruto/eth-keystore-rs/blob/master/CHANGELOG.md">eth-keystore's changelog</a>.</em></p>
<blockquote>
<h3>0.4.1</h3>
<ul>
<li>Add <code>geth-compat</code> feature that makes keystore creation/handling
compatible with geth <a href="https://github-redirect.dependabot.com/roynalnaruto/eth-keystore-rs/pull/12">#12</a></li>
</ul>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li>See full diff in <a href="https://github.com/roynalnaruto/eth-keystore-rs/commits">compare view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=eth-keystore&package-manager=cargo&previous-version=0.4.0&new-version=0.4.1)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually
- `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)


</details>


Patch:
diff --git a/Cargo.lock b/Cargo.lock
index 1c86f036..58d45e81 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -537,7 +537,7 @@ dependencies = [
  "hex",
  "hmac 0.11.0",
  "pbkdf2 0.8.0",
- "rand 0.8.4",
+ "rand 0.8.5",
  "sha2 0.9.9",
  "thiserror",
 ]
@@ -1063,9 +1063,9 @@ dependencies = [
 
 [[package]]
 name = "eth-keystore"
-version = "0.4.0"
+version = "0.4.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b9cdd5504a7b6b93c1176b0f4c193218221a927dd38bd1f4a1feb5ddd3ddb7f9"
+checksum = "aff9543a3535519a0d2ebbb6ae0afd58175258162e2fa4c1b57981edaad60fcb"
 dependencies = [
  "aes",
  "ctr",
@@ -1073,7 +1073,7 @@ dependencies = [
  "hex",
  "hmac 0.12.0",
  "pbkdf2 0.10.0",
- "rand 0.8.4",
+ "rand 0.8.5",
  "scrypt",
  "serde",
  "serde_json",
@@ -1141,7 +1141,7 @@ dependencies = [
  "ethers-solc",
  "eyre",
  "hex",
- "rand 0.8.4",
+ "rand 0.8.5",
  "serde",
  "serde_json",
  "tokio",
@@ -1235,7 +1235,7 @@ dependencies = [
  "once_cell",
  "proc-macro2",
  "quote",
- "rand 0.8.4",
+ "rand 0.8.5",
  "rlp",
  "rlp-derive",
  "serde",
@@ -1292,7 +1292,7 @@ dependencies = [
  "hex",
  "instant",
  "once_cell",
- "rand 0.8.4",
+ "rand 0.8.5",
  "reqwest",
  "serde",
  "serde_json",
@@ -1356,7 +1356,7 @@ dependencies = [
  "futures-util",
  "hex",
  "home",
- "rand 0.8.4",
+ "rand 0.8.5",
  "rusoto_core",
  "rusoto_kms",
  "semver",
@@ -1392,7 +1392,7 @@ dependencies = [
  "num_cpus",
  "once_cell",
  "pretty_assertions",
- "rand 0.8.4",
+ "rand 0.8.5",
  "rayon",
  "regex",
  "semver",
@@ -1469,7 +1469,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "cfcf0ed7fe52a17a03854ec54a9f76d6d84508d1c0e66bc1793301c73fc8493c"
 dependencies = [
  "byteorder",
- "rand 0.8.4",
+ "rand 0.8.5",
  "rustc-hex",
  "static_assertions",
 ]
@@ -2531,7 +2531,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "5d5285893bb5eb82e6aaf5d59ee909a06a16737a8970984dd7746ba9283498d6"
 dependencies = [
  "phf_shared 0.10.0",
- "rand 0.8.4",
+ "rand 0.8.5",
 ]
 
 [[package]]
@@ -2772,19 +2772,18 @@ dependencies = [
  "libc",
  "rand_chacha 0.2.2",
  "rand_core 0.5.1",
- "rand_hc 0.2.0",
+ "rand_hc",
 ]
 
 [[package]]
 name = "rand"
-version = "0.8.4"
+version = "0.8.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2e7573632e6454cf6b99d7aac4ccca54be06da05aca2ef7423d22d27d4d4bcd8"
+checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404"
 dependencies = [
  "libc",
  "rand_chacha 0.3.1",
  "rand_core 0.6.3",
- "rand_hc 0.3.1",
 ]
 
 [[package]]
@@ -2834,15 +2833,6 @@ dependencies = [
  "rand_core 0.5.1",
 ]
 
-[[package]]
-name = "rand_hc"
-version = "0.3.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d51e9f596de227fda2ea6c84607f5558e196eeaf43c986b724ba4fb8fdf497e7"
-dependencies = [
- "rand_core 0.6.3",
-]
-
 [[package]]
 name = "rayon"
 version = "1.5.1"
@@ -3594,7 +3584,7 @@ dependencies = [
  "indicatif",
  "itertools",
  "once_cell",
- "rand 0.8.4",
+ "rand 0.8.5",
  "reqwest",
  "semver",
  "serde",
@@ -3987,7 +3977,7 @@ dependencies = [
  "httparse",
  "log",
  "native-tls",
- "rand 0.8.4",
+ "rand 0.8.5",
  "rustls",
  "sha-1",
  "thiserror",
diff --git a/Cargo.toml b/Cargo.toml
index 48933976..dfcdecec 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -98,7 +98,7 @@ ethers-providers = { version = "^0.6.0", default-features = false, path = "./eth
 [target.'cfg(target_family = "unix")'.dev-dependencies]
 ethers-providers = { version = "^0.6.0", default-features = false, path = "./ethers-providers", features = ["ws", "ipc"] }
 eyre = "0.6.6"
-rand = "0.8.4"
+rand = "0.8.5"
 serde = { version = "1.0.124", features = ["derive"] }
 serde_json = "1.0.64"
 tokio = { version = "1.5", features = ["macros", "rt-multi-thread"] }
diff --git a/ethers-contract/src/multicall/mod.rs b/ethers-contract/src/multicall/mod.rs
index 61ca2701..3d5fe49d 100644
--- a/ethers-contract/src/multicall/mod.rs
+++ b/ethers-contract/src/multicall/mod.rs
@@ -187,14 +187,7 @@ impl<M: Middleware> Multicall<M> {
     }
 
     /// Appends a `call` to the list of calls for the Multicall instance
-    ///
-    /// # Panics
-    ///
-    /// If more than the maximum number of supported calls are added. The maximum
-    /// limits is constrained due to tokenization/detokenization support for tuples
     pub fn add_call<D: Detokenize>(&mut self, call: ContractCall<M, D>) -> &mut Self {
-        assert!(self.calls.len() < 16, "Cannot support more than {} calls", 16);
-
         match (call.tx.to(), call.tx.data()) {
             (Some(NameOrAddress::Address(target)), Some(data)) => {
                 let call = Call { target: *target, data: data.clone(), function: call.function };
@@ -284,23 +277,58 @@ impl<M: Middleware> Multicall<M> {
     /// # }
     /// ```
     ///
+    /// # Panics
+    ///
+    /// If more than the maximum number of supported calls are added. The maximum
+    /// limits is constrained due to tokenization/detokenization support for tuples
+    ///
     /// Note: this method _does not_ send a transaction from your account
     ///
     /// [`ContractError<M>`]: crate::ContractError<M>
     pub async fn call<D: Detokenize>(&self) -> Result<D, ContractError<M>> {
-        let contract_call = self.as_contract_call();
+        assert!(self.calls.len() < 16, "Cannot decode more than {} calls", 16);
+        let tokens = self.call_raw().await?;
+        let tokens = vec![Token::Tuple(tokens)];
+        let data = D::from_tokens(tokens)?;
+        Ok(data)
+    }
 
+    /// Queries the Ethereum blockchain via an `eth_call`, but via the Multicall contract and
+    /// without detokenization.
+    ///
+    /// It returns a [`ContractError<M>`] if there is any error in the RPC call.
+    ///
+    /// ```no_run
+    /// # async fn foo() -> Result<(), Box<dyn std::error::Error>> {
+    /// # use ethers_core::types::{U256, Address};
+    /// # use ethers_providers::{Provider, Http};
+    /// # use ethers_contract::Multicall;
+    /// # use std::convert::TryFrom;
+    /// #
+    /// # let client = Provider::<Http>::try_from("http://localhost:8545")?;
+    /// #
+    /// # let multicall = Multicall::new(client, None).await?;
+    /// // The consumer of the API is responsible for detokenizing the results
+    /// // as the results will be a Vec<Token>
+    /// let tokens = multicall.call_raw().await?;
+    /// # Ok(())
+    /// # }
+    /// ```
+    ///
+    /// Note: this method _does not_ send a transaction from your account
+    ///
+    /// [`ContractError<M>`]: crate::ContractError<M>
+
+    pub async fn call_raw(&self) -> Result<Vec<Token>, ContractError<M>> {
+        let contract_call = self.as_contract_call();
         // Fetch response from the Multicall contract
         let (_block_number, return_data) = contract_call.call().await?;
-
-        // Decode return data into ABI tokens
         let tokens = self
             .calls
             .iter()
             .zip(&return_data)
             .map(|(call, bytes)| {
                 let mut tokens: Vec<Token> = call.function.decode_output(bytes.as_ref())?;
-
                 Ok(match tokens.len() {
                     0 => Token::Tuple(vec![]),
                     1 => tokens.remove(0),
@@ -308,14 +336,7 @@ impl<M: Middleware> Multicall<M> {
                 })
             })
             .collect::<Result<Vec<Token>, ContractError<M>>>()?;
-
-        // Form tokens that represent tuples
-        let tokens = vec![Token::Tuple(tokens)];
-
-        // Detokenize from the tokens into the provided tuple D
-        let data = D::from_tokens(tokens)?;
-
-        Ok(data)
+        Ok(tokens)
     }
 
     /// Signs and broadcasts a batch of transactions by using the Multicall contract as proxy.
diff --git a/ethers-core/Cargo.toml b/ethers-core/Cargo.toml
index 788ffe0a..9ba2a5a8 100644
--- a/ethers-core/Cargo.toml
+++ b/ethers-core/Cargo.toml
@@ -20,7 +20,7 @@ ecdsa = { version = "0.13.4", default-features = false, features = ["std"] }
 elliptic-curve = { version = "0.11.12", default-features = false }
 generic-array = { version = "0.14.5", default-features = false }
 k256 = { version = "0.10.2", default-features = false, features = ["keccak256", "ecdsa"] }
-rand = { version = "0.8.4", default-features = false }
+rand = { version = "0.8.5", default-features = false }
 tiny-keccak = { version = "2.0.2", default-features = false }
 
 # misc
@@ -51,7 +51,7 @@ bincode = { version = "1.3.3", default-features = false }
 once_cell = { version = "1.8.0" }
 hex-literal = "0.3.4"
 futures-util = { version = "^0.3" }
-rand = "0.8.4"
+rand = "0.8.5"
 
 [features]
 celo = ["legacy"] # celo support extends the transaction format with extra fields
diff --git a/ethers-middleware/Cargo.toml b/ethers-middleware/Cargo.toml
index 283633dc..4c77dec9 100644
--- a/ethers-middleware/Cargo.toml
+++ b/ethers-middleware/Cargo.toml
@@ -39,7 +39,7 @@ tokio = { version = "1.5" }
 
 [dev-dependencies]
 hex = { version = "0.4.3", default-features = false, features = ["std"] }
-rand = { version = "0.8.4", default-features = false }
+rand = { version = "0.8.5", default-features = false }
 ethers-providers = { version = "^0.6.0", path = "../ethers-providers", default-features = false, features = ["ws", "rustls"] }
 once_cell = "1.8.0"
 ethers-solc = { version = "^0.2.0", path = "../ethers-solc", default-features = false }
diff --git a/ethers-signers/Cargo.toml b/ethers-signers/Cargo.toml
index 5c35a064..e19c32af 100644
--- a/ethers-signers/Cargo.toml
+++ b/ethers-signers/Cargo.toml
@@ -23,7 +23,7 @@ hex = { version = "0.4.3", default-features = false, features = ["std"] }
 async-trait = { version = "0.1.50", default-features = false }
 elliptic-curve = { version = "0.11.12", default-features = false }
 sha2 = { version = "0.9.8", default-features = false }
-rand = { version = "0.8.4", default-features = false }
+rand = { version = "0.8.5", default-features = false }
 yubihsm = { version = "0.40.0", features = ["secp256k1", "http", "usb"], optional = true }
 futures-util = "^0.3"
 futures-executor = "^0.3"
@@ -38,7 +38,7 @@ tracing-futures = { version = "0.2.5", optional = true }
 spki = { version = "0.5.4", optional = true }
 
 [target.'cfg(not(target_arch = "wasm32"))'.dependencies]
-eth-keystore = { version = "0.4.0" }
+eth-keystore = { version = "0.4.1" }
 home = "0.5.3"
 
 [dev-dependencies]
diff --git a/ethers-solc/Cargo.toml b/ethers-solc/Cargo.toml
index 2425d0ae..0892d28b 100644
--- a/ethers-solc/Cargo.toml
+++ b/ethers-solc/Cargo.toml
@@ -52,7 +52,7 @@ getrandom = { version = "0.2", features = ["js"] }
 criterion = { version = "0.3", features = ["async_tokio"] }
 env_logger = "*"
 tracing-subscriber = {version = "0.3", default-features = false, features = ["env-filter", "fmt"]}
-rand = "0.8.4"
+rand = "0.8.5"
 pretty_assertions = "1.1.0"
 tempfile = "3.3.0"
 tokio = { version = "1.15.0", features = ["full"] }


Test patch:
diff --git a/ethers-contract/tests/contract.rs b/ethers-contract/tests/contract.rs
index 09f82878..46e955db 100644
--- a/ethers-contract/tests/contract.rs
+++ b/ethers-contract/tests/contract.rs
@@ -9,6 +9,7 @@ mod eth_tests {
     use super::*;
     use ethers_contract::{LogMeta, Multicall};
     use ethers_core::{
+        abi::{Detokenize, Token, Tokenizable},
         types::{transaction::eip712::Eip712, Address, BlockId, Bytes, I256, U256},
         utils::{keccak256, Ganache},
     };
@@ -374,7 +375,8 @@ mod eth_tests {
         let (abi, bytecode) = compile_contract("SimpleStorage", "SimpleStorage.sol");
 
         // launch ganache
-        let ganache = Ganache::new().spawn();
+        // some tests expect 100 ether (-e === --wallet.defaultBalance in ether)
+        let ganache = Ganache::new().arg("-e").arg("100").spawn();
 
         // Instantiate the clients. We assume that clients consume the provider and the wallet
         // (which makes sense), so for multi-client tests, you must clone the provider.
@@ -425,6 +427,7 @@ mod eth_tests {
             .send()
             .await
             .unwrap();
+
         not_so_simple_contract
             .connect(client3.clone())
             .method::<_, H256>("setValue", "reset second".to_owned())
@@ -498,10 +501,42 @@ mod eth_tests {
             .eth_balance_of(addrs[4])
             .eth_balance_of(addrs[5])
             .eth_balance_of(addrs[6]);
+
         let balances: (U256, U256, U256) = multicall.call().await.unwrap();
-        assert_eq!(balances.0, U256::from(100000000000000000000u128));
-        assert_eq!(balances.1, U256::from(100000000000000000000u128));
-        assert_eq!(balances.2, U256::from(100000000000000000000u128));
+        assert_eq!(balances.0, U256::from(100_000_000_000_000_000_000u128));
+        assert_eq!(balances.1, U256::from(100_000_000_000_000_000_000u128));
+        assert_eq!(balances.2, U256::from(100_000_000_000_000_000_000u128));
+
+        // clear multicall so we can test `call_raw` w/ >16 calls
+        multicall.clear_calls();
+
+        // clear the current value
+        simple_contract
+            .connect(client2.clone())
+            .method::<_, H256>("setValue", "many".to_owned())
+            .unwrap()
+            .legacy()
+            .send()
+            .await
+            .unwrap();
+
+        // build up a list of calls greater than the 16 max restriction
+        for i in 0..=16 {
+            let call = simple_contract.method::<_, String>("getValue", ()).unwrap();
+            multicall.add_call(call);
+        }
+
+        // must use `call_raw` as `.calls` > 16
+        let tokens = multicall.call_raw().await.unwrap();
+        // if want to use, must detokenize manually
+        let results: Vec<String> = tokens
+            .iter()
+            .map(|token| {
+                // decode manually using Tokenizable method
+                String::from_token(token.to_owned()).unwrap()
+            })
+            .collect();
+        assert_eq!(results, ["many"; 17]);
     }
 
     #[tokio::test]