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)]
mod #name_mod {
#imports
#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`
/// client at the given `Address`. The contract derefs to a `ethers::Contract`
/// object
pub fn new<T: Into<Address>>(address: T, client: Arc<M>) -> Self {
let contract = Contract::new(address.into(), #abi_name.clone(), client);
pub fn new<T: Into<ethers_core::types::Address>>(address: T, client: ::std::sync::Arc<M>) -> Self {
let contract = ethers_contract::Contract::new(address.into(), #abi_name.clone(), client);
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 {
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"));
}
} else {
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"));
}
};
@ -47,17 +47,17 @@ pub(crate) fn struct_declaration(cx: &Context, abi_name: &proc_macro2::Ident) ->
// Struct declaration
#[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
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 }
}
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 {
f.debug_tuple(stringify!(#name))
.field(&self.address())

View File

@ -63,19 +63,19 @@ impl Context {
#(#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 {
#(
if let Ok(decoded) = #variants::from_token(token.clone()) {
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 {
#(
#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 {
fn decode_log(log: &ethers::abi::RawLog) -> Result<Self, ethers::abi::Error>
impl ethers_contract::EthLogDecode for #enum_name {
fn decode_log(log: &ethers_core::abi::RawLog) -> Result<Self, ethers_core::abi::Error>
where
Self: Sized,
{
@ -95,7 +95,7 @@ impl Context {
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>});
}
}
quote! { H256 }
quote! { ethers_core::types::H256 }
}
(ParamType::FixedArray(ty, size), true) => {
if let ParamType::Tuple(..) = **ty {
@ -162,7 +162,7 @@ impl Context {
return Ok(quote! {[#ty; #size]});
}
}
quote! { H256 }
quote! { ethers_core::types::H256 }
}
(ParamType::Tuple(..), true) => {
// represents an struct
@ -175,11 +175,11 @@ impl Context {
{
quote! {#ty}
} else {
quote! { H256 }
quote! { ethers_core::types::H256 }
}
}
(ParamType::Bytes, true) | (ParamType::String, true) => {
quote! { H256 }
quote! { ethers_core::types::H256 }
}
(kind, _) => types::expand(kind)?,
})
@ -213,7 +213,7 @@ impl Context {
let doc = util::expand_doc(&format!("Gets the contract's `{}` event", event.name));
quote! {
#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)")
}
}
@ -239,7 +239,7 @@ impl Context {
let event_abi_name = &event.name;
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 )]
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);
quote! {
H256([#( #bytes ),*])
ethers_core::types::H256([#( #bytes ),*])
}
}
@ -452,7 +452,7 @@ mod tests {
"000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f".parse().unwrap()
),
{
H256([
ethers_core::types::H256([
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
])

View File

@ -39,7 +39,7 @@ fn expand_function(function: &Function, alias: Option<Ident>) -> Result<TokenStr
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 doc = util::expand_doc(&format!(

View File

@ -5,7 +5,7 @@ use quote::quote;
pub(crate) fn expand(kind: &ParamType) -> Result<TokenStream> {
match kind {
ParamType::Address => Ok(quote! { Address }),
ParamType::Address => Ok(quote! { ethers_core::types::Address }),
ParamType::Bytes => Ok(quote! { Vec<u8> }),
ParamType::Int(n) => match n / 8 {
1 => Ok(quote! { i8 }),
@ -22,7 +22,7 @@ pub(crate) fn expand(kind: &ParamType) -> Result<TokenStream> {
3..=4 => Ok(quote! { u32 }),
5..=8 => Ok(quote! { u64 }),
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)),
},
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 ethevent_impl = quote! {
impl ethers::contract::EthEvent for #name {
impl ethers_contract::EthEvent for #name {
fn name() -> ::std::borrow::Cow<'static, str> {
#event_name.into()
}
fn signature() -> ethers::types::H256 {
fn signature() -> ethers_core::types::H256 {
#signature
}
@ -220,7 +220,7 @@ pub fn derive_abi_event(input: TokenStream) -> TokenStream {
#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
}
@ -261,7 +261,7 @@ fn topic_param_type_quote(kind: &ParamType) -> proc_macro2::TokenStream {
| ParamType::Bytes
| ParamType::Array(_)
| ParamType::FixedArray(_, _)
| ParamType::Tuple(_) => quote! {ethers::abi::ParamType::FixedBytes(32)},
| ParamType::Tuple(_) => quote! {ethers_core::abi::ParamType::FixedBytes(32)},
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 {
match kind {
ParamType::Address => {
quote! {ethers::abi::ParamType::Address}
quote! {ethers_core::abi::ParamType::Address}
}
ParamType::Bytes => {
quote! {ethers::abi::ParamType::Bytes}
quote! {ethers_core::abi::ParamType::Bytes}
}
ParamType::Int(size) => {
let size = Literal::usize_suffixed(*size);
quote! {ethers::abi::ParamType::Int(#size)}
quote! {ethers_core::abi::ParamType::Int(#size)}
}
ParamType::Uint(size) => {
let size = Literal::usize_suffixed(*size);
quote! {ethers::abi::ParamType::Uint(#size)}
quote! {ethers_core::abi::ParamType::Uint(#size)}
}
ParamType::Bool => {
quote! {ethers::abi::ParamType::Bool}
quote! {ethers_core::abi::ParamType::Bool}
}
ParamType::String => {
quote! {ethers::abi::ParamType::String}
quote! {ethers_core::abi::ParamType::String}
}
ParamType::Array(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) => {
let size = Literal::usize_suffixed(*size);
quote! {ethers::abi::ParamType::FixedBytes(#size)}
quote! {ethers_core::abi::ParamType::FixedBytes(#size)}
}
ParamType::FixedArray(ty, size) => {
let ty = param_type_quote(&*ty);
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) => {
let elements = tuple.iter().map(param_type_quote);
quote! {
ethers::abi::ParamType::Tuple(
ethers_core::abi::ParamType::Tuple(
vec![
#( #elements ),*
]
@ -424,16 +424,16 @@ fn derive_decode_from_log_impl(
},
quote! {
if topic_tokens.len() != topics.len() {
return Err(ethers::abi::Error::InvalidData);
return Err(ethers_core::abi::Error::InvalidData);
}
},
)
} else {
(
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() {
return Err(ethers::abi::Error::InvalidData);
return Err(ethers_core::abi::Error::InvalidData);
}
},
quote! {
@ -441,7 +441,7 @@ fn derive_decode_from_log_impl(
},
quote! {
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)
{
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
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();
}
} else {
@ -470,9 +470,9 @@ fn derive_decode_from_log_impl(
});
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
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());
#( tokens.push(#swap_tokens); )*
}
@ -480,7 +480,7 @@ fn derive_decode_from_log_impl(
Ok(quote! {
let ethers::abi::RawLog {data, topics} = log;
let ethers_core::abi::RawLog {data, topics} = log;
#signature_check
@ -491,7 +491,7 @@ fn derive_decode_from_log_impl(
#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 {
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> {
@ -727,13 +727,13 @@ fn derive_tokenizeable_impl(input: &DeriveInput) -> proc_macro2::TokenStream {
Fields::Named(ref fields) => {
let tokenize_predicates = fields.named.iter().map(|f| {
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 assignments = fields.named.iter().map(|f| {
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,)* } };
@ -753,12 +753,12 @@ fn derive_tokenizeable_impl(input: &DeriveInput) -> proc_macro2::TokenStream {
Fields::Unnamed(ref fields) => {
let tokenize_predicates = fields.unnamed.iter().map(|f| {
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 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,)* ) };
@ -794,17 +794,17 @@ fn derive_tokenizeable_impl(input: &DeriveInput) -> proc_macro2::TokenStream {
};
quote! {
impl<#generic_params> ethers::abi::Tokenizable for #name<#generic_args>
impl<#generic_params> ethers_core::abi::Tokenizable for #name<#generic_args>
where
#generic_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 {
if let ethers::abi::Token::Tuple(tokens) = token {
if let ethers_core::abi::Token::Tuple(tokens) = token {
if tokens.len() != #params_len {
return Err(ethers::abi::InvalidOutputType(format!(
return Err(ethers_core::abi::InvalidOutputType(format!(
"Expected {} tokens, got {}: {:?}",
#params_len,
tokens.len(),
@ -816,15 +816,15 @@ fn derive_tokenizeable_impl(input: &DeriveInput) -> proc_macro2::TokenStream {
Ok(#init_struct_impl)
} else {
Err(ethers::abi::InvalidOutputType(format!(
Err(ethers_core::abi::InvalidOutputType(format!(
"Expected Tuple, got {:?}",
token
)))
}
}
fn into_token(self) -> ethers::abi::Token {
ethers::abi::Token::Tuple(
fn into_token(self) -> ethers_core::abi::Token {
ethers_core::abi::Token::Tuple(
vec![
#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
#generic_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.
/// TODO(mattsse) keep this but remove event
pub fn event<D: Detokenize>(&self, name: &str) -> Result<Event<M, D>, Error> {
// get the event's full 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
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
@ -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
#[derive(Debug)]
#[must_use = "event filters do nothing unless you `query` or `stream` them"]