fix: switch to new Event builder

This commit is contained in:
Matthias Seitz 2021-03-18 18:12:21 +01:00
parent cf29488aae
commit 36ac73e764
3 changed files with 52 additions and 194 deletions

View File

@ -34,14 +34,18 @@ impl Context {
/// Generate the event filter methods for the contract
pub fn event_methods(&self) -> Result<TokenStream> {
let sorted_events: BTreeMap<_, _> = self.abi.events.clone().into_iter().collect();
let data_types = sorted_events
let filter_methods = sorted_events
.values()
.flatten()
.map(|event| self.expand_filter(event))
.collect::<Vec<_>>();
let events_method = self.expand_events_method();
Ok(quote! {
#( #data_types )*
#( #filter_methods )*
#events_method
})
}
@ -106,21 +110,27 @@ impl Context {
util::ident(&format!("{}Events", self.contract_name.to_string()))
}
/// The type that the `events` function should return
///
/// The generated enum type if more than 1 events are present
/// The event name if only 1 event is present
/// `None` otherwise
fn expand_events_type(&self) -> Option<Ident> {
/// Expands the `events` function that bundles all declared events of this contract
fn expand_events_method(&self) -> TokenStream {
let sorted_events: BTreeMap<_, _> = self.abi.events.clone().into_iter().collect();
let mut iter = sorted_events.values().flatten();
let event = iter.next()?;
if iter.next().is_some() {
Some(self.expand_event_enum_name())
if let Some(event) = iter.next() {
let ty = if iter.next().is_some() {
self.expand_event_enum_name()
} else {
expand_struct_name(event)
};
quote! {
/// Returns an [`Event`](ethers_contract::builders::Event) builder for all events of this contract
pub fn events(&self) -> ethers_contract::builders::Event<M, #ty> {
self.0.event_with_filter(Default::default())
}
}
} else {
Some(expand_struct_name(event))
quote! {}
}
}
@ -208,13 +218,12 @@ impl Context {
let name = util::safe_ident(&format!("{}_filter", event.name.to_snake_case()));
// let result = util::ident(&event.name.to_pascal_case());
let result = expand_struct_name(event);
let ev_name = Literal::string(&event.name);
let doc = util::expand_doc(&format!("Gets the contract's `{}` event", event.name));
quote! {
#doc
pub fn #name(&self) -> ethers_contract::builders::Event<M, #result> {
self.0.event(#ev_name).expect("event not found (this should never happen)")
self.0.event()
}
}
}

View File

@ -1,7 +1,8 @@
use super::{
use crate::{
base::{encode_function_data, AbiError, BaseContract},
call::ContractCall,
event::Event,
event::{EthEvent, Event},
EthLogDecode,
};
use ethers_core::{
@ -179,19 +180,25 @@ impl<M: Middleware> Contract<M> {
}
}
/// Returns an [`Event`](crate::builders::Event) builder for the provided event name.
/// TODO(mattsse) keep this but remove event
pub fn event<D: Detokenize>(&self, name: &str) -> Result<Event<M, D>, Error> {
/// Returns an [`Event`](crate::builders::Event) builder for the provided event.
pub fn event<D: EthEvent>(&self) -> Event<M, D> {
self.event_with_filter(Filter::new().event(&D::abi_signature()))
}
/// Returns an [`Event`](crate::builders::Event) builder with the provided filter.
pub fn event_with_filter<D: EthLogDecode>(&self, filter: Filter) -> Event<M, D> {
Event {
provider: &self.client,
filter: filter.address(self.address),
datatype: PhantomData,
}
}
/// Returns an [`Event`](crate::builders::Event) builder with the provided name.
pub fn event_by_name<D: EthLogDecode>(&self, name: &str) -> Result<Event<M, D>, Error> {
// get the event's full name
let event = self.base_contract.abi.event(name)?;
Ok(Event {
provider: &self.client,
filter: Filter::new()
.event(&event.abi_signature())
.address(self.address),
event: &event,
datatype: PhantomData,
})
Ok(self.event_with_filter(Filter::new().event(&event.abi_signature())))
}
/// Returns a transaction builder for the provided function name. If there are

View File

@ -1,7 +1,7 @@
use crate::{base::decode_event, stream::EventStream, ContractError, EthLogDecode};
use crate::{stream::EventStream, ContractError, EthLogDecode};
use ethers_core::{
abi::{Detokenize, Event as AbiEvent, RawLog},
abi::{Detokenize, RawLog},
types::{BlockNumber, Filter, Log, TxHash, ValueOrArray, H256, U64},
};
use ethers_providers::{FilterWatcher, Middleware, PubsubClient, SubscriptionStream};
@ -31,12 +31,12 @@ pub trait EthEvent: Detokenize {
fn is_anonymous() -> bool;
/// Returns an Event builder for the ethereum event represented by this types ABI signature.
fn new<M: Middleware>(filter: Filter, provider: &M) -> Event2<M, Self>
fn new<M: Middleware>(filter: Filter, provider: &M) -> Event<M, Self>
where
Self: Sized,
{
let filter = filter.event(&Self::abi_signature());
Event2 {
Event {
filter,
provider,
datatype: PhantomData,
@ -57,7 +57,7 @@ impl<T: EthEvent> EthLogDecode for T {
/// Helper for managing the event filter before querying or streaming its logs
#[derive(Debug)]
#[must_use = "event filters do nothing unless you `query` or `stream` them"]
pub struct Event2<'a, M, D> {
pub struct Event<'a, M, D> {
/// The event filter's state
pub filter: Filter,
pub(crate) provider: &'a M,
@ -66,7 +66,7 @@ pub struct Event2<'a, M, D> {
}
// TODO: Improve these functions
impl<M, D: EthLogDecode> Event2<'_, M, D> {
impl<M, D: EthLogDecode> Event<'_, M, D> {
/// Sets the filter's `from` block
#[allow(clippy::wrong_self_convention)]
pub fn from_block<T: Into<BlockNumber>>(mut self, block: T) -> Self {
@ -114,7 +114,7 @@ impl<M, D: EthLogDecode> Event2<'_, M, D> {
}
}
impl<'a, M, D> Event2<'a, M, D>
impl<'a, M, D> Event<'a, M, D>
where
M: Middleware,
D: EthLogDecode,
@ -140,7 +140,7 @@ where
}
}
impl<'a, M, D> Event2<'a, M, D>
impl<'a, M, D> Event<'a, M, D>
where
M: Middleware,
<M as Middleware>::Provider: PubsubClient,
@ -167,7 +167,7 @@ where
}
}
impl<M, D> Event2<'_, M, D>
impl<M, D> Event<'_, M, D>
where
M: Middleware,
D: EthLogDecode,
@ -215,164 +215,6 @@ where
}
}
/// Helper for managing the event filter before querying or streaming its logs
#[derive(Debug)]
#[must_use = "event filters do nothing unless you `query` or `stream` them"]
pub struct Event<'a: 'b, 'b, M, D> {
/// The event filter's state
pub filter: Filter,
/// The ABI of the event which is being filtered
pub event: &'b AbiEvent,
pub(crate) provider: &'a M,
pub(crate) datatype: PhantomData<D>,
}
// TODO: Improve these functions
impl<M, D: Detokenize> Event<'_, '_, M, D> {
/// Sets the filter's `from` block
#[allow(clippy::wrong_self_convention)]
pub fn from_block<T: Into<BlockNumber>>(mut self, block: T) -> Self {
self.filter = self.filter.from_block(block);
self
}
/// Sets the filter's `to` block
#[allow(clippy::wrong_self_convention)]
pub fn to_block<T: Into<BlockNumber>>(mut self, block: T) -> Self {
self.filter = self.filter.to_block(block);
self
}
/// Sets the filter's `blockHash`. Setting this will override previously
/// set `from_block` and `to_block` fields.
#[allow(clippy::wrong_self_convention)]
pub fn at_block_hash<T: Into<H256>>(mut self, hash: T) -> Self {
self.filter = self.filter.at_block_hash(hash);
self
}
/// Sets the filter's 0th topic (typically the event name for non-anonymous events)
pub fn topic0<T: Into<ValueOrArray<H256>>>(mut self, topic: T) -> Self {
self.filter.topics[0] = Some(topic.into());
self
}
/// Sets the filter's 1st topic
pub fn topic1<T: Into<ValueOrArray<H256>>>(mut self, topic: T) -> Self {
self.filter.topics[1] = Some(topic.into());
self
}
/// Sets the filter's 2nd topic
pub fn topic2<T: Into<ValueOrArray<H256>>>(mut self, topic: T) -> Self {
self.filter.topics[2] = Some(topic.into());
self
}
/// Sets the filter's 3rd topic
pub fn topic3<T: Into<ValueOrArray<H256>>>(mut self, topic: T) -> Self {
self.filter.topics[3] = Some(topic.into());
self
}
}
impl<'a, 'b, M, D> Event<'a, 'b, M, D>
where
M: Middleware,
D: 'b + Detokenize + Clone,
{
/// Returns a stream for the event
pub async fn stream(
&'a self,
) -> Result<
// Wraps the FilterWatcher with a mapping to the event
EventStream<'a, FilterWatcher<'a, M::Provider, Log>, D, ContractError<M>>,
ContractError<M>,
> {
let filter = self
.provider
.watch(&self.filter)
.await
.map_err(ContractError::MiddlewareError)?;
Ok(EventStream::new(
filter.id,
filter,
Box::new(move |log| self.parse_log(log)),
))
}
}
impl<'a, 'b, M, D> Event<'a, 'b, M, D>
where
M: Middleware,
<M as Middleware>::Provider: PubsubClient,
D: 'b + Detokenize + Clone,
{
/// Returns a subscription for the event
pub async fn subscribe(
&'a self,
) -> Result<
// Wraps the SubscriptionStream with a mapping to the event
EventStream<'a, SubscriptionStream<'a, M::Provider, Log>, D, ContractError<M>>,
ContractError<M>,
> {
let filter = self
.provider
.subscribe_logs(&self.filter)
.await
.map_err(ContractError::MiddlewareError)?;
Ok(EventStream::new(
filter.id,
filter,
Box::new(move |log| self.parse_log(log)),
))
}
}
impl<M, D> Event<'_, '_, M, D>
where
M: Middleware,
D: Detokenize + Clone,
{
/// Queries the blockchain for the selected filter and returns a vector of matching
/// event logs
pub async fn query(&self) -> Result<Vec<D>, ContractError<M>> {
let logs = self
.provider
.get_logs(&self.filter)
.await
.map_err(ContractError::MiddlewareError)?;
let events = logs
.into_iter()
.map(|log| self.parse_log(log))
.collect::<Result<Vec<_>, ContractError<M>>>()?;
Ok(events)
}
/// Queries the blockchain for the selected filter and returns a vector of logs
/// along with their metadata
pub async fn query_with_meta(&self) -> Result<Vec<(D, LogMeta)>, ContractError<M>> {
let logs = self
.provider
.get_logs(&self.filter)
.await
.map_err(ContractError::MiddlewareError)?;
let events = logs
.into_iter()
.map(|log| {
let meta = LogMeta::from(&log);
let event = self.parse_log(log)?;
Ok((event, meta))
})
.collect::<Result<_, ContractError<M>>>()?;
Ok(events)
}
fn parse_log(&self, log: Log) -> Result<D, ContractError<M>> {
Ok(decode_event(self.event, log.topics, log.data)?)
}
}
/// Metadata inside a log
#[derive(Clone, Debug, PartialEq)]
pub struct LogMeta {