From 095be63b3b17b26738e32a037f79c97a76c5a575 Mon Sep 17 00:00:00 2001 From: Georgios Konstantopoulos Date: Mon, 1 Jun 2020 00:17:50 +0300 Subject: [PATCH] feat: allow querying logs with their respective tx hashes --- crates/ethers-contract/src/event.rs | 22 ++++++++++++++++++---- crates/ethers-providers/src/lib.rs | 2 +- crates/ethers-providers/src/provider.rs | 6 ++++++ crates/ethers-signers/src/client.rs | 5 +++++ crates/ethers-signers/src/lib.rs | 5 ++++- crates/ethers/examples/contract.rs | 6 +++++- crates/ethers/src/lib.rs | 2 +- 7 files changed, 40 insertions(+), 8 deletions(-) diff --git a/crates/ethers-contract/src/event.rs b/crates/ethers-contract/src/event.rs index d5bde24f..f59caaf9 100644 --- a/crates/ethers-contract/src/event.rs +++ b/crates/ethers-contract/src/event.rs @@ -7,7 +7,7 @@ use ethers_core::{ types::{BlockNumber, Filter, ValueOrArray, H256}, }; -use std::marker::PhantomData; +use std::{collections::HashMap, marker::PhantomData}; pub struct Event<'a, 'b, P, N, D> { pub filter: Filter, @@ -34,16 +34,27 @@ impl<'a, 'b, P, N, D: Detokenize> Event<'a, 'b, P, N, D> { self.filter.topics[0] = Some(topic.into()); self } + + pub fn topic1>>(mut self, topic: T) -> Self { + self.filter.topics[1] = Some(topic.into()); + self + } } // TODO: Can we get rid of the static? -impl<'a, 'b, P: JsonRpcClient, N: Network, D: Detokenize> Event<'a, 'b, P, N, D> +impl<'a, 'b, P: JsonRpcClient, N: Network, D: Detokenize + Clone> Event<'a, 'b, P, N, D> where P::Error: 'static, { /// Queries the blockchain for the selected filter and returns a vector of matching /// event logs pub async fn query(self) -> Result, ContractError

> { + Ok(self.query_with_hashes().await?.values().cloned().collect()) + } + + /// Queries the blockchain for the selected filter and returns a vector of matching + /// event logs + pub async fn query_with_hashes(self) -> Result, ContractError

> { // get the logs let logs = self .provider @@ -68,9 +79,12 @@ where .collect::>(); // convert the tokens to the requested datatype - Ok::<_, ContractError

>(D::from_tokens(tokens)?) + Ok::<_, ContractError

>(( + log.transaction_hash.expect("should have tx hash"), + D::from_tokens(tokens)?, + )) }) - .collect::, _>>()?; + .collect::, _>>()?; Ok(events) } diff --git a/crates/ethers-providers/src/lib.rs b/crates/ethers-providers/src/lib.rs index 48ea7beb..f1564853 100644 --- a/crates/ethers-providers/src/lib.rs +++ b/crates/ethers-providers/src/lib.rs @@ -1,4 +1,4 @@ -mod http; +pub mod http; mod provider; pub mod networks; diff --git a/crates/ethers-providers/src/provider.rs b/crates/ethers-providers/src/provider.rs index 139f0d6b..ca2643d5 100644 --- a/crates/ethers-providers/src/provider.rs +++ b/crates/ethers-providers/src/provider.rs @@ -123,6 +123,12 @@ impl Provider { self.0.request("eth_getBalance", Some(&[from, block])).await } + /// Returns the currently configured chain id, a value used in replay-protected + /// transaction signing as introduced by EIP-155. + pub async fn get_chainid(&self) -> Result { + self.0.request("eth_chainId", None::<()>).await + } + ////// Contract Execution // // These are relatively low-level calls. The Contracts API should usually be used instead. diff --git a/crates/ethers-signers/src/client.rs b/crates/ethers-signers/src/client.rs index aa100235..ffce3054 100644 --- a/crates/ethers-signers/src/client.rs +++ b/crates/ethers-signers/src/client.rs @@ -106,6 +106,11 @@ where pub fn provider(&self) -> &Provider { self.provider } + + /// Returns a reference to the client's signer, will panic if no signer is set + pub fn signer_unchecked(&self) -> &S { + self.signer.as_ref().expect("no signer is configured") + } } // Abuse Deref to use the Provider's methods without re-writing everything. diff --git a/crates/ethers-signers/src/lib.rs b/crates/ethers-signers/src/lib.rs index 870e86bf..8ac5d631 100644 --- a/crates/ethers-signers/src/lib.rs +++ b/crates/ethers-signers/src/lib.rs @@ -1,4 +1,3 @@ -// TODO: We might need a `SignerAsync` trait for HSM use cases? mod wallet; pub use wallet::Wallet; @@ -11,6 +10,7 @@ use std::error::Error; /// Trait for signing transactions and messages /// /// Implement this trait to support different signing modes, e.g. Ledger, hosted etc. +// TODO: We might need a `SignerAsync` trait for HSM use cases? pub trait Signer { type Error: Error; /// Signs the hash of the provided message after prefixing it @@ -31,3 +31,6 @@ pub type MainnetWallet = Wallet; /// A wallet which does not use EIP-155 and does not take the chain id into account /// when creating transactions pub type AnyWallet = Wallet; + +/// An HTTP client configured to work with ANY blockchain without replay protection +pub type HttpClient<'a> = Client<'a, ethers_providers::http::Provider, Any, Wallet>; diff --git a/crates/ethers/examples/contract.rs b/crates/ethers/examples/contract.rs index 35d96781..2e97c39e 100644 --- a/crates/ethers/examples/contract.rs +++ b/crates/ethers/examples/contract.rs @@ -53,7 +53,11 @@ async fn main() -> Result<()> { let _tx_hash = contract.set_value("hi".to_owned()).send().await?; // 11. get all events - let logs = contract.value_changed_filter().from_block(0u64).query().await?; + let logs = contract + .value_changed_filter() + .from_block(0u64) + .query() + .await?; // 12. get the new value let value = contract.get_value().call().await?; diff --git a/crates/ethers/src/lib.rs b/crates/ethers/src/lib.rs index 89b28663..5721e134 100644 --- a/crates/ethers/src/lib.rs +++ b/crates/ethers/src/lib.rs @@ -151,7 +151,7 @@ pub mod signers { /// /// let message = "Some data"; /// let key = PrivateKey::new(&mut rand::thread_rng()); -/// let address = Address::from(key); +/// let address = Address::from(&key); /// /// // Sign the message /// let signature = key.sign(message);