refactor: use fully qualified syntax during abigen

This commit is contained in:
Matthias Seitz 2021-03-18 16:58:13 +01:00
parent 855fd2deb2
commit cf29488aae
8 changed files with 239 additions and 65 deletions

View File

@ -79,15 +79,14 @@ impl Context {
#[allow(clippy::too_many_arguments)] #[allow(clippy::too_many_arguments)]
mod #name_mod { mod #name_mod {
#imports #imports
#struct_decl #struct_decl
impl<'a, M: Middleware> #name<M> { impl<'a, M: ethers_providers::Middleware> #name<M> {
/// Creates a new contract instance with the specified `ethers` /// Creates a new contract instance with the specified `ethers`
/// client at the given `Address`. The contract derefs to a `ethers::Contract` /// client at the given `Address`. The contract derefs to a `ethers::Contract`
/// object /// object
pub fn new<T: Into<Address>>(address: T, client: Arc<M>) -> Self { pub fn new<T: Into<ethers_core::types::Address>>(address: T, client: ::std::sync::Arc<M>) -> Self {
let contract = Contract::new(address.into(), #abi_name.clone(), client); let contract = ethers_contract::Contract::new(address.into(), #abi_name.clone(), client);
Self(contract) Self(contract)
} }

View File

@ -31,12 +31,12 @@ pub(crate) fn struct_declaration(cx: &Context, abi_name: &proc_macro2::Ident) ->
let abi_parse = if !cx.human_readable { let abi_parse = if !cx.human_readable {
quote! { quote! {
pub static #abi_name: Lazy<Abi> = Lazy::new(|| serde_json::from_str(#abi) pub static #abi_name: ethers_contract::Lazy<ethers_core::abi::Abi> = ethers_contract::Lazy::new(|| serde_json::from_str(#abi)
.expect("invalid abi")); .expect("invalid abi"));
} }
} else { } else {
quote! { quote! {
pub static #abi_name: Lazy<Abi> = Lazy::new(|| ethers::core::abi::parse_abi_str(#abi) pub static #abi_name: ethers_contract::Lazy<ethers_core::abi::Abi> = ethers_contract::Lazy::new(|| ethers::core::abi::parse_abi_str(#abi)
.expect("invalid abi")); .expect("invalid abi"));
} }
}; };
@ -47,17 +47,17 @@ pub(crate) fn struct_declaration(cx: &Context, abi_name: &proc_macro2::Ident) ->
// Struct declaration // Struct declaration
#[derive(Clone)] #[derive(Clone)]
pub struct #name<M>(Contract<M>); pub struct #name<M>(ethers_contract::Contract<M>);
// Deref to the inner contract in order to access more specific functions functions // Deref to the inner contract in order to access more specific functions functions
impl<M> std::ops::Deref for #name<M> { impl<M> std::ops::Deref for #name<M> {
type Target = Contract<M>; type Target = ethers_contract::Contract<M>;
fn deref(&self) -> &Self::Target { &self.0 } fn deref(&self) -> &Self::Target { &self.0 }
} }
impl<M: Middleware> std::fmt::Debug for #name<M> { impl<M: ethers_providers::Middleware> std::fmt::Debug for #name<M> {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
f.debug_tuple(stringify!(#name)) f.debug_tuple(stringify!(#name))
.field(&self.address()) .field(&self.address())

View File

@ -63,19 +63,19 @@ impl Context {
#(#variants(#variants)),* #(#variants(#variants)),*
} }
impl ethers::abi::Tokenizable for #enum_name { impl ethers_core::abi::Tokenizable for #enum_name {
fn from_token(token: ethers::abi::Token) -> Result<Self, ethers::abi::InvalidOutputType> where fn from_token(token: ethers_core::abi::Token) -> Result<Self, ethers_core::abi::InvalidOutputType> where
Self: Sized { Self: Sized {
#( #(
if let Ok(decoded) = #variants::from_token(token.clone()) { if let Ok(decoded) = #variants::from_token(token.clone()) {
return Ok(#enum_name::#variants(decoded)) return Ok(#enum_name::#variants(decoded))
} }
)* )*
Err(ethers::abi::InvalidOutputType("Failed to decode all event variants".to_string())) Err(ethers_core::abi::InvalidOutputType("Failed to decode all event variants".to_string()))
} }
fn into_token(self) -> ethers::abi::Token { fn into_token(self) -> ethers_core::abi::Token {
match self { match self {
#( #(
#enum_name::#variants(element) => element.into_token() #enum_name::#variants(element) => element.into_token()
@ -83,10 +83,10 @@ impl Context {
} }
} }
} }
impl ethers::abi::TokenizableItem for #enum_name { } impl ethers_core::abi::TokenizableItem for #enum_name { }
impl ethers::contract::EthLogDecode for #enum_name { impl ethers_contract::EthLogDecode for #enum_name {
fn decode_log(log: &ethers::abi::RawLog) -> Result<Self, ethers::abi::Error> fn decode_log(log: &ethers_core::abi::RawLog) -> Result<Self, ethers_core::abi::Error>
where where
Self: Sized, Self: Sized,
{ {
@ -95,7 +95,7 @@ impl Context {
return Ok(#enum_name::#variants(decoded)) return Ok(#enum_name::#variants(decoded))
} }
)* )*
Err(ethers::abi::Error::InvalidData) Err(ethers_core::abi::Error::InvalidData)
} }
} }
} }
@ -146,7 +146,7 @@ impl Context {
return Ok(quote! {::std::vec::Vec<#ty>}); return Ok(quote! {::std::vec::Vec<#ty>});
} }
} }
quote! { H256 } quote! { ethers_core::types::H256 }
} }
(ParamType::FixedArray(ty, size), true) => { (ParamType::FixedArray(ty, size), true) => {
if let ParamType::Tuple(..) = **ty { if let ParamType::Tuple(..) = **ty {
@ -162,7 +162,7 @@ impl Context {
return Ok(quote! {[#ty; #size]}); return Ok(quote! {[#ty; #size]});
} }
} }
quote! { H256 } quote! { ethers_core::types::H256 }
} }
(ParamType::Tuple(..), true) => { (ParamType::Tuple(..), true) => {
// represents an struct // represents an struct
@ -175,11 +175,11 @@ impl Context {
{ {
quote! {#ty} quote! {#ty}
} else { } else {
quote! { H256 } quote! { ethers_core::types::H256 }
} }
} }
(ParamType::Bytes, true) | (ParamType::String, true) => { (ParamType::Bytes, true) | (ParamType::String, true) => {
quote! { H256 } quote! { ethers_core::types::H256 }
} }
(kind, _) => types::expand(kind)?, (kind, _) => types::expand(kind)?,
}) })
@ -213,7 +213,7 @@ impl Context {
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) -> 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(#ev_name).expect("event not found (this should never happen)")
} }
} }
@ -239,7 +239,7 @@ impl Context {
let event_abi_name = &event.name; let event_abi_name = &event.name;
Ok(quote! { Ok(quote! {
#[derive(Clone, Debug, Default, Eq, PartialEq, ethers::contract::EthEvent, #derives)] #[derive(Clone, Debug, Default, Eq, PartialEq, ethers_contract::EthEvent, #derives)]
#[ethevent( name = #event_abi_name, abi = #abi_signature )] #[ethevent( name = #event_abi_name, abi = #abi_signature )]
pub #data_type_definition pub #data_type_definition
}) })
@ -335,7 +335,7 @@ fn expand_hash(hash: Hash) -> TokenStream {
let bytes = hash.as_bytes().iter().copied().map(Literal::u8_unsuffixed); let bytes = hash.as_bytes().iter().copied().map(Literal::u8_unsuffixed);
quote! { quote! {
H256([#( #bytes ),*]) ethers_core::types::H256([#( #bytes ),*])
} }
} }
@ -452,7 +452,7 @@ mod tests {
"000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f".parse().unwrap() "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f".parse().unwrap()
), ),
{ {
H256([ ethers_core::types::H256([
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31
]) ])

View File

@ -39,7 +39,7 @@ fn expand_function(function: &Function, alias: Option<Ident>) -> Result<TokenStr
let outputs = expand_fn_outputs(&function.outputs)?; let outputs = expand_fn_outputs(&function.outputs)?;
let result = quote! { ContractCall<M, #outputs> }; let result = quote! { ethers_contract::builders::ContractCall<M, #outputs> };
let arg = expand_inputs_call_arg(&function.inputs); let arg = expand_inputs_call_arg(&function.inputs);
let doc = util::expand_doc(&format!( let doc = util::expand_doc(&format!(

View File

@ -5,7 +5,7 @@ use quote::quote;
pub(crate) fn expand(kind: &ParamType) -> Result<TokenStream> { pub(crate) fn expand(kind: &ParamType) -> Result<TokenStream> {
match kind { match kind {
ParamType::Address => Ok(quote! { Address }), ParamType::Address => Ok(quote! { ethers_core::types::Address }),
ParamType::Bytes => Ok(quote! { Vec<u8> }), ParamType::Bytes => Ok(quote! { Vec<u8> }),
ParamType::Int(n) => match n / 8 { ParamType::Int(n) => match n / 8 {
1 => Ok(quote! { i8 }), 1 => Ok(quote! { i8 }),
@ -22,7 +22,7 @@ pub(crate) fn expand(kind: &ParamType) -> Result<TokenStream> {
3..=4 => Ok(quote! { u32 }), 3..=4 => Ok(quote! { u32 }),
5..=8 => Ok(quote! { u64 }), 5..=8 => Ok(quote! { u64 }),
9..=16 => Ok(quote! { u128 }), 9..=16 => Ok(quote! { u128 }),
17..=32 => Ok(quote! { U256 }), 17..=32 => Ok(quote! { ethers_core::types::U256 }),
_ => Err(anyhow!("unsupported solidity type uint{}", n)), _ => Err(anyhow!("unsupported solidity type uint{}", n)),
}, },
ParamType::Bool => Ok(quote! { bool }), ParamType::Bool => Ok(quote! { bool }),

View File

@ -206,13 +206,13 @@ pub fn derive_abi_event(input: TokenStream) -> TokenStream {
let anon = attributes.anonymous.map(|(b, _)| b).unwrap_or_default(); let anon = attributes.anonymous.map(|(b, _)| b).unwrap_or_default();
let ethevent_impl = quote! { let ethevent_impl = quote! {
impl ethers::contract::EthEvent for #name { impl ethers_contract::EthEvent for #name {
fn name() -> ::std::borrow::Cow<'static, str> { fn name() -> ::std::borrow::Cow<'static, str> {
#event_name.into() #event_name.into()
} }
fn signature() -> ethers::types::H256 { fn signature() -> ethers_core::types::H256 {
#signature #signature
} }
@ -220,7 +220,7 @@ pub fn derive_abi_event(input: TokenStream) -> TokenStream {
#abi.into() #abi.into()
} }
fn decode_log(log: &ethers::abi::RawLog) -> Result<Self, ethers::abi::Error> where Self: Sized { fn decode_log(log: &ethers_core::abi::RawLog) -> Result<Self, ethers_core::abi::Error> where Self: Sized {
#decode_log_impl #decode_log_impl
} }
@ -261,7 +261,7 @@ fn topic_param_type_quote(kind: &ParamType) -> proc_macro2::TokenStream {
| ParamType::Bytes | ParamType::Bytes
| ParamType::Array(_) | ParamType::Array(_)
| ParamType::FixedArray(_, _) | ParamType::FixedArray(_, _)
| ParamType::Tuple(_) => quote! {ethers::abi::ParamType::FixedBytes(32)}, | ParamType::Tuple(_) => quote! {ethers_core::abi::ParamType::FixedBytes(32)},
ty => param_type_quote(ty), ty => param_type_quote(ty),
} }
} }
@ -269,42 +269,42 @@ fn topic_param_type_quote(kind: &ParamType) -> proc_macro2::TokenStream {
fn param_type_quote(kind: &ParamType) -> proc_macro2::TokenStream { fn param_type_quote(kind: &ParamType) -> proc_macro2::TokenStream {
match kind { match kind {
ParamType::Address => { ParamType::Address => {
quote! {ethers::abi::ParamType::Address} quote! {ethers_core::abi::ParamType::Address}
} }
ParamType::Bytes => { ParamType::Bytes => {
quote! {ethers::abi::ParamType::Bytes} quote! {ethers_core::abi::ParamType::Bytes}
} }
ParamType::Int(size) => { ParamType::Int(size) => {
let size = Literal::usize_suffixed(*size); let size = Literal::usize_suffixed(*size);
quote! {ethers::abi::ParamType::Int(#size)} quote! {ethers_core::abi::ParamType::Int(#size)}
} }
ParamType::Uint(size) => { ParamType::Uint(size) => {
let size = Literal::usize_suffixed(*size); let size = Literal::usize_suffixed(*size);
quote! {ethers::abi::ParamType::Uint(#size)} quote! {ethers_core::abi::ParamType::Uint(#size)}
} }
ParamType::Bool => { ParamType::Bool => {
quote! {ethers::abi::ParamType::Bool} quote! {ethers_core::abi::ParamType::Bool}
} }
ParamType::String => { ParamType::String => {
quote! {ethers::abi::ParamType::String} quote! {ethers_core::abi::ParamType::String}
} }
ParamType::Array(ty) => { ParamType::Array(ty) => {
let ty = param_type_quote(&*ty); let ty = param_type_quote(&*ty);
quote! {ethers::abi::ParamType::Array(Box::new(#ty))} quote! {ethers_core::abi::ParamType::Array(Box::new(#ty))}
} }
ParamType::FixedBytes(size) => { ParamType::FixedBytes(size) => {
let size = Literal::usize_suffixed(*size); let size = Literal::usize_suffixed(*size);
quote! {ethers::abi::ParamType::FixedBytes(#size)} quote! {ethers_core::abi::ParamType::FixedBytes(#size)}
} }
ParamType::FixedArray(ty, size) => { ParamType::FixedArray(ty, size) => {
let ty = param_type_quote(&*ty); let ty = param_type_quote(&*ty);
let size = Literal::usize_suffixed(*size); let size = Literal::usize_suffixed(*size);
quote! {ethers::abi::ParamType::FixedArray(Box::new(#ty),#size)} quote! {ethers_core::abi::ParamType::FixedArray(Box::new(#ty),#size)}
} }
ParamType::Tuple(tuple) => { ParamType::Tuple(tuple) => {
let elements = tuple.iter().map(param_type_quote); let elements = tuple.iter().map(param_type_quote);
quote! { quote! {
ethers::abi::ParamType::Tuple( ethers_core::abi::ParamType::Tuple(
vec![ vec![
#( #elements ),* #( #elements ),*
] ]
@ -424,16 +424,16 @@ fn derive_decode_from_log_impl(
}, },
quote! { quote! {
if topic_tokens.len() != topics.len() { if topic_tokens.len() != topics.len() {
return Err(ethers::abi::Error::InvalidData); return Err(ethers_core::abi::Error::InvalidData);
} }
}, },
) )
} else { } else {
( (
quote! { quote! {
let event_signature = topics.get(0).ok_or(ethers::abi::Error::InvalidData)?; let event_signature = topics.get(0).ok_or(ethers_core::abi::Error::InvalidData)?;
if event_signature != &Self::signature() { if event_signature != &Self::signature() {
return Err(ethers::abi::Error::InvalidData); return Err(ethers_core::abi::Error::InvalidData);
} }
}, },
quote! { quote! {
@ -441,7 +441,7 @@ fn derive_decode_from_log_impl(
}, },
quote! { quote! {
if topic_tokens.is_empty() || topic_tokens.len() != topics.len() - 1 { if topic_tokens.is_empty() || topic_tokens.len() != topics.len() - 1 {
return Err(ethers::abi::Error::InvalidData); return Err(ethers_core::abi::Error::InvalidData);
} }
}, },
) )
@ -455,9 +455,9 @@ fn derive_decode_from_log_impl(
.all(|(idx, f)| f.index == idx) .all(|(idx, f)| f.index == idx)
{ {
quote! { quote! {
let topic_tokens = ethers::abi::decode(&topic_types, &flat_topics)?; let topic_tokens = ethers_core::abi::decode(&topic_types, &flat_topics)?;
#topic_tokens_len_check #topic_tokens_len_check
let data_tokens = ethers::abi::decode(&data_types, &data)?; let data_tokens = ethers_core::abi::decode(&data_types, &data)?;
let tokens:Vec<_> = topic_tokens.into_iter().chain(data_tokens.into_iter()).collect(); let tokens:Vec<_> = topic_tokens.into_iter().chain(data_tokens.into_iter()).collect();
} }
} else { } else {
@ -470,9 +470,9 @@ fn derive_decode_from_log_impl(
}); });
quote! { quote! {
let mut topic_tokens = ethers::abi::decode(&topic_types, &flat_topics)?; let mut topic_tokens = ethers_core::abi::decode(&topic_types, &flat_topics)?;
#topic_tokens_len_check #topic_tokens_len_check
let mut data_tokens = ethers::abi::decode(&data_types, &data)?; let mut data_tokens = ethers_core::abi::decode(&data_types, &data)?;
let mut tokens = Vec::with_capacity(topics.len() + data_tokens.len()); let mut tokens = Vec::with_capacity(topics.len() + data_tokens.len());
#( tokens.push(#swap_tokens); )* #( tokens.push(#swap_tokens); )*
} }
@ -480,7 +480,7 @@ fn derive_decode_from_log_impl(
Ok(quote! { Ok(quote! {
let ethers::abi::RawLog {data, topics} = log; let ethers_core::abi::RawLog {data, topics} = log;
#signature_check #signature_check
@ -491,7 +491,7 @@ fn derive_decode_from_log_impl(
#tokens_init #tokens_init
ethers::abi::Detokenize::from_tokens(tokens).map_err(|_|ethers::abi::Error::InvalidData) ethers_core::abi::Detokenize::from_tokens(tokens).map_err(|_|ethers_core::abi::Error::InvalidData)
}) })
} }
@ -678,7 +678,7 @@ fn parse_int_param_type(s: &str) -> Option<ParamType> {
fn signature(hash: &[u8]) -> proc_macro2::TokenStream { fn signature(hash: &[u8]) -> proc_macro2::TokenStream {
let bytes = hash.iter().copied().map(Literal::u8_unsuffixed); let bytes = hash.iter().copied().map(Literal::u8_unsuffixed);
quote! {ethers::types::H256([#( #bytes ),*])} quote! {ethers_core::types::H256([#( #bytes ),*])}
} }
fn parse_event(abi: &str) -> Result<Event, String> { fn parse_event(abi: &str) -> Result<Event, String> {
@ -727,13 +727,13 @@ fn derive_tokenizeable_impl(input: &DeriveInput) -> proc_macro2::TokenStream {
Fields::Named(ref fields) => { Fields::Named(ref fields) => {
let tokenize_predicates = fields.named.iter().map(|f| { let tokenize_predicates = fields.named.iter().map(|f| {
let ty = &f.ty; let ty = &f.ty;
quote_spanned! { f.span() => #ty: ethers::abi::Tokenize } quote_spanned! { f.span() => #ty: ethers_core::abi::Tokenize }
}); });
let tokenize_predicates = quote! { #(#tokenize_predicates,)* }; let tokenize_predicates = quote! { #(#tokenize_predicates,)* };
let assignments = fields.named.iter().map(|f| { let assignments = fields.named.iter().map(|f| {
let name = f.ident.as_ref().expect("Named fields have names"); let name = f.ident.as_ref().expect("Named fields have names");
quote_spanned! { f.span() => #name: ethers::abi::Tokenizable::from_token(iter.next().expect("tokens size is sufficient qed").into_token())? } quote_spanned! { f.span() => #name: ethers_core::abi::Tokenizable::from_token(iter.next().expect("tokens size is sufficient qed").into_token())? }
}); });
let init_struct_impl = quote! { Self { #(#assignments,)* } }; let init_struct_impl = quote! { Self { #(#assignments,)* } };
@ -753,12 +753,12 @@ fn derive_tokenizeable_impl(input: &DeriveInput) -> proc_macro2::TokenStream {
Fields::Unnamed(ref fields) => { Fields::Unnamed(ref fields) => {
let tokenize_predicates = fields.unnamed.iter().map(|f| { let tokenize_predicates = fields.unnamed.iter().map(|f| {
let ty = &f.ty; let ty = &f.ty;
quote_spanned! { f.span() => #ty: ethers::abi::Tokenize } quote_spanned! { f.span() => #ty: ethers_core::abi::Tokenize }
}); });
let tokenize_predicates = quote! { #(#tokenize_predicates,)* }; let tokenize_predicates = quote! { #(#tokenize_predicates,)* };
let assignments = fields.unnamed.iter().map(|f| { let assignments = fields.unnamed.iter().map(|f| {
quote_spanned! { f.span() => ethers::abi::Tokenizable::from_token(iter.next().expect("tokens size is sufficient qed").into_token())? } quote_spanned! { f.span() => ethers_core::abi::Tokenizable::from_token(iter.next().expect("tokens size is sufficient qed").into_token())? }
}); });
let init_struct_impl = quote! { Self(#(#assignments,)* ) }; let init_struct_impl = quote! { Self(#(#assignments,)* ) };
@ -794,17 +794,17 @@ fn derive_tokenizeable_impl(input: &DeriveInput) -> proc_macro2::TokenStream {
}; };
quote! { quote! {
impl<#generic_params> ethers::abi::Tokenizable for #name<#generic_args> impl<#generic_params> ethers_core::abi::Tokenizable for #name<#generic_args>
where where
#generic_predicates #generic_predicates
#tokenize_predicates #tokenize_predicates
{ {
fn from_token(token: ethers::abi::Token) -> Result<Self, ethers::abi::InvalidOutputType> where fn from_token(token: ethers_core::abi::Token) -> Result<Self, ethers_core::abi::InvalidOutputType> where
Self: Sized { Self: Sized {
if let ethers::abi::Token::Tuple(tokens) = token { if let ethers_core::abi::Token::Tuple(tokens) = token {
if tokens.len() != #params_len { if tokens.len() != #params_len {
return Err(ethers::abi::InvalidOutputType(format!( return Err(ethers_core::abi::InvalidOutputType(format!(
"Expected {} tokens, got {}: {:?}", "Expected {} tokens, got {}: {:?}",
#params_len, #params_len,
tokens.len(), tokens.len(),
@ -816,15 +816,15 @@ fn derive_tokenizeable_impl(input: &DeriveInput) -> proc_macro2::TokenStream {
Ok(#init_struct_impl) Ok(#init_struct_impl)
} else { } else {
Err(ethers::abi::InvalidOutputType(format!( Err(ethers_core::abi::InvalidOutputType(format!(
"Expected Tuple, got {:?}", "Expected Tuple, got {:?}",
token token
))) )))
} }
} }
fn into_token(self) -> ethers::abi::Token { fn into_token(self) -> ethers_core::abi::Token {
ethers::abi::Token::Tuple( ethers_core::abi::Token::Tuple(
vec![ vec![
#into_token_impl #into_token_impl
] ]
@ -832,7 +832,7 @@ fn derive_tokenizeable_impl(input: &DeriveInput) -> proc_macro2::TokenStream {
} }
} }
impl<#generic_params> ethers::abi::TokenizableItem for #name<#generic_args> impl<#generic_params> ethers_core::abi::TokenizableItem for #name<#generic_args>
where where
#generic_predicates #generic_predicates
#tokenize_predicates #tokenize_predicates

View File

@ -180,6 +180,7 @@ 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 name.
/// TODO(mattsse) keep this but remove event
pub fn event<D: Detokenize>(&self, name: &str) -> Result<Event<M, D>, Error> { pub fn event<D: Detokenize>(&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)?;

View File

@ -29,6 +29,19 @@ 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;
/// 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>
where
Self: Sized,
{
let filter = filter.event(&Self::abi_signature());
Event2 {
filter,
provider,
datatype: PhantomData,
}
}
} }
// Convenience implementation // Convenience implementation
@ -41,6 +54,167 @@ impl<T: EthEvent> EthLogDecode for T {
} }
} }
/// 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 Event2<'a, M, D> {
/// The event filter's state
pub filter: Filter,
pub(crate) provider: &'a M,
/// Stores the event datatype
pub(crate) datatype: PhantomData<D>,
}
// TODO: Improve these functions
impl<M, D: EthLogDecode> Event2<'_, 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, M, D> Event2<'a, M, D>
where
M: Middleware,
D: EthLogDecode,
{
/// 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, M, D> Event2<'a, M, D>
where
M: Middleware,
<M as Middleware>::Provider: PubsubClient,
D: EthLogDecode,
{
/// 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> Event2<'_, M, D>
where
M: Middleware,
D: EthLogDecode,
{
/// 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>> {
D::decode_log(&RawLog {
topics: log.topics,
data: log.data.to_vec(),
})
.map_err(From::from)
}
}
/// 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"]