diff --git a/ethers-contract/src/event.rs b/ethers-contract/src/event.rs index 4e88d608..e013b461 100644 --- a/ethers-contract/src/event.rs +++ b/ethers-contract/src/event.rs @@ -2,7 +2,7 @@ use crate::{stream::EventStream, ContractError, EthLogDecode}; use ethers_core::{ abi::{Detokenize, RawLog}, - types::{BlockNumber, Filter, Log, TxHash, ValueOrArray, H256, U64}, + types::{Address, BlockNumber, Filter, Log, TxHash, ValueOrArray, H256, U256, U64}, }; use ethers_providers::{FilterWatcher, Middleware, PubsubClient, SubscriptionStream}; use std::borrow::Cow; @@ -218,18 +218,34 @@ where /// Metadata inside a log #[derive(Clone, Debug, PartialEq)] pub struct LogMeta { + /// Address from which this log originated + pub address: Address, + /// The block in which the log was emitted pub block_number: U64, + /// The block hash in which the log was emitted + pub block_hash: H256, + /// The transaction hash in which the log was emitted pub transaction_hash: TxHash, + + /// Transactions index position log was created from + pub transaction_index: U64, + + /// Log index position in the block + pub log_index: U256, } impl From<&Log> for LogMeta { fn from(src: &Log) -> Self { LogMeta { + address: src.address, block_number: src.block_number.expect("should have a block number"), + block_hash: src.block_hash.expect("should have a block hash"), transaction_hash: src.transaction_hash.expect("should have a tx hash"), + transaction_index: src.transaction_index.expect("should have a tx index"), + log_index: src.log_index.expect("should have a log index"), } } } diff --git a/ethers-contract/src/lib.rs b/ethers-contract/src/lib.rs index 6a9df387..3d82029c 100644 --- a/ethers-contract/src/lib.rs +++ b/ethers-contract/src/lib.rs @@ -26,7 +26,7 @@ mod factory; pub use factory::ContractFactory; mod event; -pub use event::EthEvent; +pub use event::{EthEvent, LogMeta}; mod log; pub use log::{decode_logs, EthLogDecode}; diff --git a/ethers-contract/tests/contract.rs b/ethers-contract/tests/contract.rs index 0657f982..f9c89c7b 100644 --- a/ethers-contract/tests/contract.rs +++ b/ethers-contract/tests/contract.rs @@ -10,7 +10,7 @@ pub use common::*; mod eth_tests { use super::*; use ethers::{ - contract::Multicall, + contract::{LogMeta, Multicall}, providers::{Http, Middleware, PendingTransaction, Provider, StreamExt}, types::{Address, U256}, utils::Ganache, @@ -132,6 +132,37 @@ mod eth_tests { assert_eq!(logs.len(), 1); } + #[tokio::test] + async fn get_events_with_meta() { + let (abi, bytecode) = compile_contract("SimpleStorage", "SimpleStorage.sol"); + let ganache = Ganache::new().spawn(); + let client = connect(&ganache, 0); + let contract = deploy(client.clone(), abi, bytecode).await; + + // and we can fetch the events + let logs: Vec<(ValueChanged, LogMeta)> = contract + .event() + .from_block(0u64) + .topic1(client.address()) // Corresponds to the first indexed parameter + .query_with_meta() + .await + .unwrap(); + + assert_eq!(logs.len(), 1); + let (log, meta) = &logs[0]; + assert_eq!(log.new_value, "initial value"); + + assert_eq!(meta.address, contract.address()); + assert_eq!(meta.log_index, 0.into()); + assert_eq!(meta.block_number, 1.into()); + let block = client.get_block(1).await.unwrap().unwrap(); + assert_eq!(meta.block_hash, block.hash.unwrap()); + assert_eq!(block.transactions.len(), 1); + let tx = block.transactions[0]; + assert_eq!(meta.transaction_hash, tx); + assert_eq!(meta.transaction_index, 0.into()); + } + #[tokio::test] async fn call_past_state() { let (abi, bytecode) = compile_contract("SimpleStorage", "SimpleStorage.sol"); diff --git a/ethers-core/src/types/mod.rs b/ethers-core/src/types/mod.rs index 116dfb00..402dd22b 100644 --- a/ethers-core/src/types/mod.rs +++ b/ethers-core/src/types/mod.rs @@ -29,7 +29,7 @@ pub use block::{Block, BlockId, BlockNumber}; pub use block::Randomness; mod log; -pub use log::{Filter, Log, ValueOrArray}; +pub use log::{Filter, FilterBlockOption, Log, ValueOrArray}; mod ens; pub use ens::NameOrAddress;