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)),*
}
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
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()))
}
/// 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.
///
/// 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.
fn expand_struct_name(event: &Event) -> TokenStream {
fn expand_struct_name(event: &Event) -> Ident {
// TODO: get rid of `Filter` suffix?
let name = format!("{}Filter", event.name.to_pascal_case());
let event_name = util::ident(&name);
quote! { #event_name }
util::ident(&name)
}
/// Expands an event data structure from its name-type parameter pairs. Returns
/// a tuple with the type definition (i.e. the struct declaration) and
/// 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
.iter()
.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.
/// 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
.iter()
.map(|(_, ty)| quote! { pub #ty })
@ -406,7 +437,7 @@ mod tests {
let cx = test_context();
let params = cx.expand_params(&event).unwrap();
let name = expand_struct_name(&event);
let definition = expand_data_tuple(&name, &params);
let definition = expand_data_tuple(name, &params);
assert_quote!(definition, {
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::{
abi::{Detokenize, Event as AbiEvent, RawLog},
@ -29,7 +29,16 @@ pub trait EthEvent: Detokenize {
/// Returns true if this is an anonymous event
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

View File

@ -5,7 +5,9 @@ use ethers_core::abi::RawLog;
/// A trait for types (events) that can be decoded from a `RawLog`
pub trait EthLogDecode {
/// 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