fix: make EthEvent abi attribute work for tuple inputs (#229)
* fix: try to parse the provided abi as tuple * test: validate ethevent abi attribute * docs: document ethevent abi attribute
This commit is contained in:
parent
7b10b76e20
commit
0c18f9b32c
|
@ -13,7 +13,7 @@ use syn::{
|
||||||
};
|
};
|
||||||
|
|
||||||
use abigen::{expand, ContractArgs};
|
use abigen::{expand, ContractArgs};
|
||||||
use ethers_core::abi::{AbiParser, Event, EventExt, EventParam, ParamType};
|
use ethers_core::abi::{param_type::Reader, AbiParser, Event, EventExt, EventParam, ParamType};
|
||||||
use hex::FromHex;
|
use hex::FromHex;
|
||||||
use spanned::Spanned;
|
use spanned::Spanned;
|
||||||
|
|
||||||
|
@ -79,9 +79,29 @@ pub fn abigen(input: TokenStream) -> TokenStream {
|
||||||
///
|
///
|
||||||
/// Additional arguments can be specified using the `#[ethevent(...)]` attribute:
|
/// Additional arguments can be specified using the `#[ethevent(...)]` attribute:
|
||||||
///
|
///
|
||||||
/// - `name`, `name = "..."`: Overrides the generated `EthEvent` name, default is the struct's name.
|
/// - `name`, `name = "..."`: Overrides the generated `EthEvent` name, default is the
|
||||||
/// - `signature`, `signature = "..."`: The signature as hex string to override the event's signature.
|
/// struct's name.
|
||||||
|
/// - `signature`, `signature = "..."`: The signature as hex string to override the
|
||||||
|
/// event's signature.
|
||||||
/// - `abi`, `abi = "..."`: The ABI signature for the event this event's data corresponds to.
|
/// - `abi`, `abi = "..."`: The ABI signature for the event this event's data corresponds to.
|
||||||
|
/// The `abi` should be solidity event definition or a tuple of the event's types in case the
|
||||||
|
/// event has non elementary (other `EthAbiType`) types as members
|
||||||
|
///
|
||||||
|
/// # Example
|
||||||
|
/// ```ignore
|
||||||
|
/// #[derive(Debug, EthAbiType)]
|
||||||
|
/// struct Inner {
|
||||||
|
/// inner: Address,
|
||||||
|
/// msg: String,
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// #[derive(Debug, EthEvent)]
|
||||||
|
/// #[ethevent(abi = "ValueChangedEvent((address,string),string)")]
|
||||||
|
/// struct ValueChangedEvent {
|
||||||
|
/// inner: Inner,
|
||||||
|
/// msg: String,
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
#[proc_macro_derive(EthEvent, attributes(ethevent))]
|
#[proc_macro_derive(EthEvent, attributes(ethevent))]
|
||||||
pub fn derive_abi_event(input: TokenStream) -> TokenStream {
|
pub fn derive_abi_event(input: TokenStream) -> TokenStream {
|
||||||
let input = parse_macro_input!(input as DeriveInput);
|
let input = parse_macro_input!(input as DeriveInput);
|
||||||
|
@ -97,28 +117,57 @@ pub fn derive_abi_event(input: TokenStream) -> TokenStream {
|
||||||
.unwrap_or_else(|| input.ident.to_string());
|
.unwrap_or_else(|| input.ident.to_string());
|
||||||
|
|
||||||
let (abi, hash) = if let Some((src, span)) = attributes.abi {
|
let (abi, hash) = if let Some((src, span)) = attributes.abi {
|
||||||
|
// try to parse as solidity event
|
||||||
if let Ok(mut event) = parse_event(&src) {
|
if let Ok(mut event) = parse_event(&src) {
|
||||||
event.name = event_name.clone();
|
event.name = event_name.clone();
|
||||||
(event.abi_signature(), event.signature())
|
(event.abi_signature(), event.signature())
|
||||||
} else {
|
} else {
|
||||||
match src.parse::<Source>().and_then(|s| s.get()) {
|
// try as tuple
|
||||||
Ok(abi) => {
|
if let Some(inputs) = Reader::read(
|
||||||
// try to derive the signature from the abi from the parsed abi
|
src.trim_start_matches("event ")
|
||||||
// TODO(mattsse): this will fail for events that contain other non elementary types in their abi
|
.trim_start()
|
||||||
// because the parser doesn't know how to substitute the types
|
.trim_start_matches(&event_name),
|
||||||
// this could be mitigated by getting the ABI of each non elementary type at runtime
|
)
|
||||||
// and computing the the signature as `static Lazy::...`
|
.ok()
|
||||||
match parse_event(&abi) {
|
.and_then(|param| match param {
|
||||||
Ok(mut event) => {
|
ParamType::Tuple(params) => Some(
|
||||||
event.name = event_name.clone();
|
params
|
||||||
(event.abi_signature(), event.signature())
|
.into_iter()
|
||||||
}
|
.map(|kind| EventParam {
|
||||||
Err(err) => {
|
name: "".to_string(),
|
||||||
return TokenStream::from(Error::new(span, err).to_compile_error())
|
indexed: false,
|
||||||
|
kind,
|
||||||
|
})
|
||||||
|
.collect(),
|
||||||
|
),
|
||||||
|
_ => None,
|
||||||
|
}) {
|
||||||
|
let event = Event {
|
||||||
|
name: event_name.clone(),
|
||||||
|
inputs,
|
||||||
|
anonymous: false,
|
||||||
|
};
|
||||||
|
(event.abi_signature(), event.signature())
|
||||||
|
} else {
|
||||||
|
match src.parse::<Source>().and_then(|s| s.get()) {
|
||||||
|
Ok(abi) => {
|
||||||
|
// try to derive the signature from the abi from the parsed abi
|
||||||
|
// TODO(mattsse): this will fail for events that contain other non elementary types in their abi
|
||||||
|
// because the parser doesn't know how to substitute the types
|
||||||
|
// this could be mitigated by getting the ABI of each non elementary type at runtime
|
||||||
|
// and computing the the signature as `static Lazy::...`
|
||||||
|
match parse_event(&abi) {
|
||||||
|
Ok(mut event) => {
|
||||||
|
event.name = event_name.clone();
|
||||||
|
(event.abi_signature(), event.signature())
|
||||||
|
}
|
||||||
|
Err(err) => {
|
||||||
|
return TokenStream::from(Error::new(span, err).to_compile_error())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Err(err) => return TokenStream::from(Error::new(span, err).to_compile_error()),
|
||||||
}
|
}
|
||||||
Err(err) => return TokenStream::from(Error::new(span, err).to_compile_error()),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -84,7 +84,7 @@ fn can_detokenize_nested_tuple_struct() {
|
||||||
#[test]
|
#[test]
|
||||||
fn can_derive_eth_event() {
|
fn can_derive_eth_event() {
|
||||||
#[derive(Debug, Clone, PartialEq, EthEvent)]
|
#[derive(Debug, Clone, PartialEq, EthEvent)]
|
||||||
pub struct ValueChangedEvent {
|
struct ValueChangedEvent {
|
||||||
old_author: Address,
|
old_author: Address,
|
||||||
new_author: Address,
|
new_author: Address,
|
||||||
old_value: String,
|
old_value: String,
|
||||||
|
@ -112,7 +112,7 @@ fn can_derive_eth_event() {
|
||||||
fn can_set_eth_event_name_attribute() {
|
fn can_set_eth_event_name_attribute() {
|
||||||
#[derive(Debug, PartialEq, EthEvent)]
|
#[derive(Debug, PartialEq, EthEvent)]
|
||||||
#[ethevent(name = "MyEvent")]
|
#[ethevent(name = "MyEvent")]
|
||||||
pub struct ValueChangedEvent {
|
struct ValueChangedEvent {
|
||||||
old_author: Address,
|
old_author: Address,
|
||||||
new_author: Address,
|
new_author: Address,
|
||||||
old_value: String,
|
old_value: String,
|
||||||
|
@ -165,19 +165,40 @@ fn can_detect_various_event_abi_types() {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// #[test]
|
#[test]
|
||||||
// fn can_set_eth_abi_attribute() {
|
fn can_set_eth_abi_attribute() {
|
||||||
// #[derive(Debug, Clone, PartialEq, EthAbiType)]
|
#[derive(Debug, Clone, PartialEq, EthAbiType)]
|
||||||
// struct SomeType {
|
struct SomeType {
|
||||||
// inner: Address,
|
inner: Address,
|
||||||
// msg: String,
|
msg: String,
|
||||||
// }
|
}
|
||||||
//
|
|
||||||
// #[derive(Debug, PartialEq, EthEvent)]
|
#[derive(Debug, PartialEq, EthEvent)]
|
||||||
// #[ethevent(abi = "ValueChangedEvent(address,(address,string),string)")]
|
#[ethevent(abi = "ValueChangedEvent(address,(address,string),string)")]
|
||||||
// pub struct ValueChangedEvent {
|
struct ValueChangedEvent {
|
||||||
// old_author: Address,
|
old_author: Address,
|
||||||
// inner: SomeType,
|
inner: SomeType,
|
||||||
// new_value: String,
|
new_value: String,
|
||||||
// }
|
}
|
||||||
// }
|
|
||||||
|
assert_eq!(
|
||||||
|
"ValueChangedEvent(address,(address,string),string)",
|
||||||
|
ValueChangedEvent::abi_signature()
|
||||||
|
);
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq, EthEvent)]
|
||||||
|
#[ethevent(
|
||||||
|
name = "ValueChangedEvent",
|
||||||
|
abi = "ValueChangedEvent(address,(address,string),string)"
|
||||||
|
)]
|
||||||
|
struct ValueChangedEvent2 {
|
||||||
|
old_author: Address,
|
||||||
|
inner: SomeType,
|
||||||
|
new_value: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
"ValueChangedEvent(address,(address,string),string)",
|
||||||
|
ValueChangedEvent2::abi_signature()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue