feat: multiple addresses on Filter (#375)
* feat: support multiple addresses in filters To support filtering of 1..n addresses we had to add the ValueOrArray enum to the log types and refactor some ethers-contract code Fixes: #240 Signed-off-by: Sebastian Martinez <sebastinez@me.com> * chore: fmt * fix: use legacy tx in unit test due to Ganache Co-authored-by: Sebastian Martinez <sebastinez@me.com>
This commit is contained in:
parent
99e9a687ca
commit
60ff4660df
|
@ -7,7 +7,7 @@ use crate::{
|
||||||
|
|
||||||
use ethers_core::{
|
use ethers_core::{
|
||||||
abi::{Abi, Detokenize, Error, EventExt, Function, Tokenize},
|
abi::{Abi, Detokenize, Error, EventExt, Function, Tokenize},
|
||||||
types::{Address, Filter, NameOrAddress, Selector},
|
types::{Address, Filter, NameOrAddress, Selector, ValueOrArray},
|
||||||
};
|
};
|
||||||
|
|
||||||
#[cfg(not(feature = "legacy"))]
|
#[cfg(not(feature = "legacy"))]
|
||||||
|
@ -178,7 +178,7 @@ impl<M: Middleware> Contract<M> {
|
||||||
pub fn event_with_filter<D: EthLogDecode>(&self, filter: Filter) -> Event<M, D> {
|
pub fn event_with_filter<D: EthLogDecode>(&self, filter: Filter) -> Event<M, D> {
|
||||||
Event {
|
Event {
|
||||||
provider: &self.client,
|
provider: &self.client,
|
||||||
filter: filter.address(self.address),
|
filter: filter.address(ValueOrArray::Value(self.address)),
|
||||||
datatype: PhantomData,
|
datatype: PhantomData,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,7 @@
|
||||||
use ethers::{contract::ContractFactory, types::H256};
|
use ethers::{
|
||||||
|
contract::ContractFactory,
|
||||||
|
types::{Filter, ValueOrArray, H256},
|
||||||
|
};
|
||||||
|
|
||||||
mod common;
|
mod common;
|
||||||
pub use common::*;
|
pub use common::*;
|
||||||
|
@ -338,6 +341,43 @@ mod eth_tests {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn watch_subscription_events_multiple_addresses() {
|
||||||
|
let (abi, bytecode) = compile_contract("SimpleStorage", "SimpleStorage.sol");
|
||||||
|
let ganache = Ganache::new().spawn();
|
||||||
|
let client = connect(&ganache, 0);
|
||||||
|
let contract_1 = deploy(client.clone(), abi.clone(), bytecode.clone()).await;
|
||||||
|
let contract_2 = deploy(client.clone(), abi.clone(), bytecode).await;
|
||||||
|
|
||||||
|
let ws = Provider::connect(ganache.ws_endpoint()).await.unwrap();
|
||||||
|
let filter = Filter::new().address(ValueOrArray::Array(vec![
|
||||||
|
contract_1.address(),
|
||||||
|
contract_2.address(),
|
||||||
|
]));
|
||||||
|
let mut stream = ws.subscribe_logs(&filter).await.unwrap();
|
||||||
|
|
||||||
|
// and we make a few calls
|
||||||
|
let call = contract_1
|
||||||
|
.method::<_, H256>("setValue", "1".to_string())
|
||||||
|
.unwrap()
|
||||||
|
.legacy();
|
||||||
|
let pending_tx = call.send().await.unwrap();
|
||||||
|
let _receipt = pending_tx.await.unwrap();
|
||||||
|
|
||||||
|
let call = contract_2
|
||||||
|
.method::<_, H256>("setValue", "2".to_string())
|
||||||
|
.unwrap()
|
||||||
|
.legacy();
|
||||||
|
let pending_tx = call.send().await.unwrap();
|
||||||
|
let _receipt = pending_tx.await.unwrap();
|
||||||
|
|
||||||
|
// unwrap the option of the stream, then unwrap the decoding result
|
||||||
|
let log_1 = stream.next().await.unwrap();
|
||||||
|
let log_2 = stream.next().await.unwrap();
|
||||||
|
assert_eq!(log_1.address, contract_1.address());
|
||||||
|
assert_eq!(log_2.address, contract_2.address());
|
||||||
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn signer_on_node() {
|
async fn signer_on_node() {
|
||||||
let (abi, bytecode) = compile_contract("SimpleStorage", "SimpleStorage.sol");
|
let (abi, bytecode) = compile_contract("SimpleStorage", "SimpleStorage.sol");
|
||||||
|
|
|
@ -181,9 +181,7 @@ pub struct Filter {
|
||||||
pub block_option: FilterBlockOption,
|
pub block_option: FilterBlockOption,
|
||||||
|
|
||||||
/// Address
|
/// Address
|
||||||
// TODO: The spec says that this can also be an array, do we really want to
|
address: Option<ValueOrArray<Address>>,
|
||||||
// monitor for the same event for multiple contracts?
|
|
||||||
address: Option<Address>,
|
|
||||||
|
|
||||||
/// Topics
|
/// Topics
|
||||||
// TODO: We could improve the low level API here by using ethabi's RawTopicFilter
|
// TODO: We could improve the low level API here by using ethabi's RawTopicFilter
|
||||||
|
@ -331,7 +329,7 @@ impl Filter {
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn address<T: Into<Address>>(mut self, address: T) -> Self {
|
pub fn address<T: Into<ValueOrArray<Address>>>(mut self, address: T) -> Self {
|
||||||
self.address = Some(address.into());
|
self.address = Some(address.into());
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
@ -449,7 +447,7 @@ mod tests {
|
||||||
let ser = serialize(&filter);
|
let ser = serialize(&filter);
|
||||||
assert_eq!(ser, json!({ "topics": [] }));
|
assert_eq!(ser, json!({ "topics": [] }));
|
||||||
|
|
||||||
let filter = filter.address(addr);
|
let filter = filter.address(ValueOrArray::Value(addr));
|
||||||
|
|
||||||
let ser = serialize(&filter);
|
let ser = serialize(&filter);
|
||||||
assert_eq!(ser, json!({"address" : addr, "topics": []}));
|
assert_eq!(ser, json!({"address" : addr, "topics": []}));
|
||||||
|
|
Loading…
Reference in New Issue