feat: generate EthLogDecode implementations

This commit is contained in:
Matthias Seitz 2021-03-18 12:54:39 +01:00
parent c4d87d11b8
commit 855fd2deb2
3 changed files with 52 additions and 10 deletions

View File

@ -63,7 +63,7 @@ impl Context {
#(#variants(#variants)),* #(#variants(#variants)),*
} }
impl ethers_core::abi::Tokenizable for #enum_name { impl ethers::abi::Tokenizable for #enum_name {
fn from_token(token: ethers::abi::Token) -> Result<Self, ethers::abi::InvalidOutputType> where fn from_token(token: ethers::abi::Token) -> Result<Self, ethers::abi::InvalidOutputType> where
Self: Sized { Self: Sized {
@ -83,7 +83,21 @@ impl Context {
} }
} }
} }
impl ethers_core::abi::TokenizableItem for #enum_name { } impl ethers::abi::TokenizableItem for #enum_name { }
impl ethers::contract::EthLogDecode for #enum_name {
fn decode_log(log: &ethers::abi::RawLog) -> Result<Self, ethers::abi::Error>
where
Self: Sized,
{
#(
if let Ok(decoded) = #variants::decode_log(log) {
return Ok(#enum_name::#variants(decoded))
}
)*
Err(ethers::abi::Error::InvalidData)
}
}
} }
} }
@ -92,6 +106,24 @@ 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
///
/// 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 mut iter = sorted_events.values().flatten();
let event = iter.next()?;
if iter.next().is_some() {
Some(self.expand_event_enum_name())
} else {
Some(expand_struct_name(event))
}
}
/// Expands an event property type. /// Expands an event property type.
/// ///
/// Note that this is slightly different than an expanding a Solidity type as /// Note that this is slightly different than an expanding a Solidity type as
@ -258,17 +290,16 @@ impl Context {
} }
/// Expands an ABI event into an identifier for its event data type. /// Expands an ABI event into an identifier for its event data type.
fn expand_struct_name(event: &Event) -> TokenStream { fn expand_struct_name(event: &Event) -> Ident {
// TODO: get rid of `Filter` suffix? // TODO: get rid of `Filter` suffix?
let name = format!("{}Filter", event.name.to_pascal_case()); let name = format!("{}Filter", event.name.to_pascal_case());
let event_name = util::ident(&name); util::ident(&name)
quote! { #event_name }
} }
/// Expands an event data structure from its name-type parameter pairs. Returns /// Expands an event data structure from its name-type parameter pairs. Returns
/// a tuple with the type definition (i.e. the struct declaration) and /// a tuple with the type definition (i.e. the struct declaration) and
/// construction (i.e. code for creating an instance of the event data). /// construction (i.e. code for creating an instance of the event data).
fn expand_data_struct(name: &TokenStream, params: &[(TokenStream, TokenStream)]) -> TokenStream { fn expand_data_struct(name: &Ident, params: &[(TokenStream, TokenStream)]) -> TokenStream {
let fields = params let fields = params
.iter() .iter()
.map(|(name, ty)| quote! { pub #name: #ty }) .map(|(name, ty)| quote! { pub #name: #ty })
@ -279,7 +310,7 @@ fn expand_data_struct(name: &TokenStream, params: &[(TokenStream, TokenStream)])
/// Expands an event data named tuple from its name-type parameter pairs. /// Expands an event data named tuple from its name-type parameter pairs.
/// Returns a tuple with the type definition and construction. /// Returns a tuple with the type definition and construction.
fn expand_data_tuple(name: &TokenStream, params: &[(TokenStream, TokenStream)]) -> TokenStream { fn expand_data_tuple(name: &Ident, params: &[(TokenStream, TokenStream)]) -> TokenStream {
let fields = params let fields = params
.iter() .iter()
.map(|(_, ty)| quote! { pub #ty }) .map(|(_, ty)| quote! { pub #ty })
@ -406,7 +437,7 @@ mod tests {
let cx = test_context(); let cx = test_context();
let params = cx.expand_params(&event).unwrap(); let params = cx.expand_params(&event).unwrap();
let name = expand_struct_name(&event); let name = expand_struct_name(&event);
let definition = expand_data_tuple(&name, &params); let definition = expand_data_tuple(name, &params);
assert_quote!(definition, { assert_quote!(definition, {
struct FooFilter(pub bool, pub Address); struct FooFilter(pub bool, pub Address);

View File

@ -1,4 +1,4 @@
use crate::{base::decode_event, stream::EventStream, ContractError}; use crate::{base::decode_event, stream::EventStream, ContractError, EthLogDecode};
use ethers_core::{ use ethers_core::{
abi::{Detokenize, Event as AbiEvent, RawLog}, abi::{Detokenize, Event as AbiEvent, RawLog},
@ -29,7 +29,16 @@ pub trait EthEvent: Detokenize {
/// Returns true if this is an anonymous event /// Returns true if this is an anonymous event
fn is_anonymous() -> bool; fn is_anonymous() -> bool;
}
// Convenience implementation
impl<T: EthEvent> EthLogDecode for T {
fn decode_log(log: &RawLog) -> Result<Self, ethers_core::abi::Error>
where
Self: Sized,
{
T::decode_log(log)
}
} }
/// Helper for managing the event filter before querying or streaming its logs /// Helper for managing the event filter before querying or streaming its logs

View File

@ -5,7 +5,9 @@ use ethers_core::abi::RawLog;
/// A trait for types (events) that can be decoded from a `RawLog` /// A trait for types (events) that can be decoded from a `RawLog`
pub trait EthLogDecode { pub trait EthLogDecode {
/// decode from a `RawLog` /// decode from a `RawLog`
fn decode_log(log: &RawLog) -> Result<Self, Error> where Self: Sized; fn decode_log(log: &RawLog) -> Result<Self, Error>
where
Self: Sized;
} }
/// Decodes a series of logs into a vector /// Decodes a series of logs into a vector