fix: switch to new Event builder
This commit is contained in:
parent
cf29488aae
commit
36ac73e764
|
@ -34,14 +34,18 @@ impl Context {
|
||||||
/// Generate the event filter methods for the contract
|
/// Generate the event filter methods for the contract
|
||||||
pub fn event_methods(&self) -> Result<TokenStream> {
|
pub fn event_methods(&self) -> Result<TokenStream> {
|
||||||
let sorted_events: BTreeMap<_, _> = self.abi.events.clone().into_iter().collect();
|
let sorted_events: BTreeMap<_, _> = self.abi.events.clone().into_iter().collect();
|
||||||
let data_types = sorted_events
|
let filter_methods = sorted_events
|
||||||
.values()
|
.values()
|
||||||
.flatten()
|
.flatten()
|
||||||
.map(|event| self.expand_filter(event))
|
.map(|event| self.expand_filter(event))
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
|
let events_method = self.expand_events_method();
|
||||||
|
|
||||||
Ok(quote! {
|
Ok(quote! {
|
||||||
#( #data_types )*
|
#( #filter_methods )*
|
||||||
|
|
||||||
|
#events_method
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -106,21 +110,27 @@ impl Context {
|
||||||
util::ident(&format!("{}Events", self.contract_name.to_string()))
|
util::ident(&format!("{}Events", self.contract_name.to_string()))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The type that the `events` function should return
|
/// Expands the `events` function that bundles all declared events of this contract
|
||||||
///
|
fn expand_events_method(&self) -> TokenStream {
|
||||||
/// 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> {
|
|
||||||
let sorted_events: BTreeMap<_, _> = self.abi.events.clone().into_iter().collect();
|
let sorted_events: BTreeMap<_, _> = self.abi.events.clone().into_iter().collect();
|
||||||
|
|
||||||
let mut iter = sorted_events.values().flatten();
|
let mut iter = sorted_events.values().flatten();
|
||||||
let event = iter.next()?;
|
|
||||||
|
|
||||||
if iter.next().is_some() {
|
if let Some(event) = iter.next() {
|
||||||
Some(self.expand_event_enum_name())
|
let ty = if iter.next().is_some() {
|
||||||
|
self.expand_event_enum_name()
|
||||||
} else {
|
} else {
|
||||||
Some(expand_struct_name(event))
|
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 {
|
||||||
|
quote! {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -208,13 +218,12 @@ impl Context {
|
||||||
let name = util::safe_ident(&format!("{}_filter", event.name.to_snake_case()));
|
let name = util::safe_ident(&format!("{}_filter", event.name.to_snake_case()));
|
||||||
// let result = util::ident(&event.name.to_pascal_case());
|
// let result = util::ident(&event.name.to_pascal_case());
|
||||||
let result = expand_struct_name(event);
|
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));
|
let doc = util::expand_doc(&format!("Gets the contract's `{}` event", event.name));
|
||||||
quote! {
|
quote! {
|
||||||
#doc
|
#doc
|
||||||
pub fn #name(&self) -> ethers_contract::builders::Event<M, #result> {
|
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()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
use super::{
|
use crate::{
|
||||||
base::{encode_function_data, AbiError, BaseContract},
|
base::{encode_function_data, AbiError, BaseContract},
|
||||||
call::ContractCall,
|
call::ContractCall,
|
||||||
event::Event,
|
event::{EthEvent, Event},
|
||||||
|
EthLogDecode,
|
||||||
};
|
};
|
||||||
|
|
||||||
use ethers_core::{
|
use ethers_core::{
|
||||||
|
@ -179,19 +180,25 @@ impl<M: Middleware> Contract<M> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns an [`Event`](crate::builders::Event) builder for the provided event name.
|
/// Returns an [`Event`](crate::builders::Event) builder for the provided event.
|
||||||
/// TODO(mattsse) keep this but remove event
|
pub fn event<D: EthEvent>(&self) -> Event<M, D> {
|
||||||
pub fn event<D: Detokenize>(&self, name: &str) -> Result<Event<M, D>, Error> {
|
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
|
// get the event's full name
|
||||||
let event = self.base_contract.abi.event(name)?;
|
let event = self.base_contract.abi.event(name)?;
|
||||||
Ok(Event {
|
Ok(self.event_with_filter(Filter::new().event(&event.abi_signature())))
|
||||||
provider: &self.client,
|
|
||||||
filter: Filter::new()
|
|
||||||
.event(&event.abi_signature())
|
|
||||||
.address(self.address),
|
|
||||||
event: &event,
|
|
||||||
datatype: PhantomData,
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns a transaction builder for the provided function name. If there are
|
/// Returns a transaction builder for the provided function name. If there are
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
use crate::{base::decode_event, stream::EventStream, ContractError, EthLogDecode};
|
use crate::{stream::EventStream, ContractError, EthLogDecode};
|
||||||
|
|
||||||
use ethers_core::{
|
use ethers_core::{
|
||||||
abi::{Detokenize, Event as AbiEvent, RawLog},
|
abi::{Detokenize, RawLog},
|
||||||
types::{BlockNumber, Filter, Log, TxHash, ValueOrArray, H256, U64},
|
types::{BlockNumber, Filter, Log, TxHash, ValueOrArray, H256, U64},
|
||||||
};
|
};
|
||||||
use ethers_providers::{FilterWatcher, Middleware, PubsubClient, SubscriptionStream};
|
use ethers_providers::{FilterWatcher, Middleware, PubsubClient, SubscriptionStream};
|
||||||
|
@ -31,12 +31,12 @@ pub trait EthEvent: Detokenize {
|
||||||
fn is_anonymous() -> bool;
|
fn is_anonymous() -> bool;
|
||||||
|
|
||||||
/// Returns an Event builder for the ethereum event represented by this types ABI signature.
|
/// 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
|
where
|
||||||
Self: Sized,
|
Self: Sized,
|
||||||
{
|
{
|
||||||
let filter = filter.event(&Self::abi_signature());
|
let filter = filter.event(&Self::abi_signature());
|
||||||
Event2 {
|
Event {
|
||||||
filter,
|
filter,
|
||||||
provider,
|
provider,
|
||||||
datatype: PhantomData,
|
datatype: PhantomData,
|
||||||
|
@ -57,7 +57,7 @@ impl<T: EthEvent> EthLogDecode for T {
|
||||||
/// Helper for managing the event filter before querying or streaming its logs
|
/// Helper for managing the event filter before querying or streaming its logs
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
#[must_use = "event filters do nothing unless you `query` or `stream` them"]
|
#[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
|
/// The event filter's state
|
||||||
pub filter: Filter,
|
pub filter: Filter,
|
||||||
pub(crate) provider: &'a M,
|
pub(crate) provider: &'a M,
|
||||||
|
@ -66,7 +66,7 @@ pub struct Event2<'a, M, D> {
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Improve these functions
|
// TODO: Improve these functions
|
||||||
impl<M, D: EthLogDecode> Event2<'_, M, D> {
|
impl<M, D: EthLogDecode> Event<'_, M, D> {
|
||||||
/// Sets the filter's `from` block
|
/// Sets the filter's `from` block
|
||||||
#[allow(clippy::wrong_self_convention)]
|
#[allow(clippy::wrong_self_convention)]
|
||||||
pub fn from_block<T: Into<BlockNumber>>(mut self, block: T) -> Self {
|
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
|
where
|
||||||
M: Middleware,
|
M: Middleware,
|
||||||
D: EthLogDecode,
|
D: EthLogDecode,
|
||||||
|
@ -140,7 +140,7 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, M, D> Event2<'a, M, D>
|
impl<'a, M, D> Event<'a, M, D>
|
||||||
where
|
where
|
||||||
M: Middleware,
|
M: Middleware,
|
||||||
<M as Middleware>::Provider: PubsubClient,
|
<M as Middleware>::Provider: PubsubClient,
|
||||||
|
@ -167,7 +167,7 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<M, D> Event2<'_, M, D>
|
impl<M, D> Event<'_, M, D>
|
||||||
where
|
where
|
||||||
M: Middleware,
|
M: Middleware,
|
||||||
D: EthLogDecode,
|
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
|
/// Metadata inside a log
|
||||||
#[derive(Clone, Debug, PartialEq)]
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
pub struct LogMeta {
|
pub struct LogMeta {
|
||||||
|
|
Loading…
Reference in New Issue