fix: event decoding for events with zero or one parameters (#300)

* fix: support events with zero or one paramaters

* test: test against events with zero and one parameter
This commit is contained in:
Matthias Seitz 2021-05-28 09:44:42 +02:00 committed by GitHub
parent ac6d4d70a6
commit b5a2ee9a3d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 95 additions and 10 deletions

View File

@ -785,15 +785,40 @@ fn derive_tokenizeable_impl(input: &DeriveInput) -> proc_macro2::TokenStream {
}
};
quote! {
impl<#generic_params> ethers_core::abi::Tokenizable for #name<#generic_args>
where
#generic_predicates
#tokenize_predicates
{
// there might be the case that the event has only 1 params, which is not a tuple
let (from_token_impl, into_token_impl) = match params_len {
0 => (
quote! {
Ok(#init_struct_impl)
},
// can't encode an empty struct
// TODO: panic instead?
quote! {
ethers_core::abi::Token::Tuple(vec![])
},
),
1 => {
// This is a hacky solution in order to keep the same tokenstream as for tuples
let from_token = quote! {
let mut iter = Some(token).into_iter();
Ok(#init_struct_impl)
};
fn from_token(token: ethers_core::abi::Token) -> Result<Self, ethers_core::abi::InvalidOutputType> where
Self: Sized {
// This is a hack to get rid of the trailing comma introduced in the macro that concatenates all the fields
if let Ok(into_token) = into_token_impl
.to_string()
.as_str()
.trim_end_matches(',')
.parse()
{
(from_token, into_token)
} else {
return Error::new(input.span(), "Failed to derive Tokenizeable implementation")
.to_compile_error();
}
}
_ => {
let from_token = quote! {
if let ethers_core::abi::Token::Tuple(tokens) = token {
if tokens.len() != #params_len {
return Err(ethers_core::abi::InvalidOutputType(format!(
@ -813,14 +838,33 @@ fn derive_tokenizeable_impl(input: &DeriveInput) -> proc_macro2::TokenStream {
token
)))
}
}
};
fn into_token(self) -> ethers_core::abi::Token {
let into_token = quote! {
ethers_core::abi::Token::Tuple(
vec![
#into_token_impl
]
)
};
(from_token, into_token)
}
};
quote! {
impl<#generic_params> ethers_core::abi::Tokenizable for #name<#generic_args>
where
#generic_predicates
#tokenize_predicates
{
fn from_token(token: ethers_core::abi::Token) -> Result<Self, ethers_core::abi::InvalidOutputType> where
Self: Sized {
#from_token_impl
}
fn into_token(self) -> ethers_core::abi::Token {
#into_token_impl
}
}

View File

@ -268,3 +268,44 @@ fn can_decode_event_with_no_topics() {
assert_eq!(event.seize_tokens, 5250648u64.into());
assert_eq!(event.repay_amount, 653800000000000000u64.into());
}
#[test]
fn can_decode_event_single_param() {
#[derive(Debug, PartialEq, EthEvent)]
pub struct OneParam {
#[ethevent(indexed)]
param1: U256,
}
let log = RawLog {
topics: vec![
"bd9bb67345a2fcc8ef3b0857e7e2901f5a0dcfc7fe5e3c10dc984f02842fb7ba"
.parse()
.unwrap(),
"000000000000000000000000000000000000000000000000000000000000007b"
.parse()
.unwrap(),
],
data: vec![],
};
let event = <OneParam as EthLogDecode>::decode_log(&log).unwrap();
assert_eq!(event.param1, 123u64.into());
}
#[test]
fn can_decode_event_with_no_params() {
#[derive(Debug, PartialEq, EthEvent)]
pub struct NoParam {}
let log = RawLog {
topics: vec![
"59a6f900daaeb7581ff830f3a97097fa6372db29b0b50c6d1818ede9d1daaa0c"
.parse()
.unwrap(),
],
data: vec![],
};
let _ = <NoParam as EthLogDecode>::decode_log(&log).unwrap();
}