Skip to content
This repository has been archived by the owner on Oct 19, 2024. It is now read-only.

refactor(abigen): solidity types expansion #2131

Merged
merged 7 commits into from
Feb 14, 2023
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
62 changes: 2 additions & 60 deletions ethers-contract/ethers-contract-abigen/src/contract/common.rs
Original file line number Diff line number Diff line change
@@ -1,66 +1,8 @@
use super::{types, util, Context};
use ethers_core::{
abi::{Param, ParamType},
macros::{ethers_contract_crate, ethers_core_crate, ethers_providers_crate},
};
use super::Context;
use ethers_core::macros::{ethers_contract_crate, ethers_core_crate, ethers_providers_crate};
use proc_macro2::{Ident, Literal, TokenStream};
use quote::quote;

/// Expands to the `name : type` pairs for the params
pub(crate) fn expand_params<'a, F>(
params: &[Param],
resolve_tuple: F,
) -> eyre::Result<Vec<(TokenStream, TokenStream)>>
where
F: Fn(&str) -> Option<&'a str>,
{
params
.iter()
.enumerate()
.map(|(idx, param)| {
let name = util::expand_input_name(idx, &param.name);
let ty = expand_param_type(param, &param.kind, |s| resolve_tuple(s))?;
Ok((name, ty))
})
.collect()
}

/// returns the Tokenstream for the corresponding rust type
pub(crate) fn expand_param_type<'a, F>(
param: &Param,
kind: &ParamType,
resolve_tuple: F,
) -> eyre::Result<TokenStream>
where
F: Fn(&str) -> Option<&'a str>,
{
match kind {
ParamType::Array(ty) => {
let ty = expand_param_type(param, ty, resolve_tuple)?;
Ok(quote! {
::std::vec::Vec<#ty>
})
}
ParamType::FixedArray(ty, size) => {
let ty = expand_param_type(param, ty, resolve_tuple)?;
let size = *size;
Ok(quote! {[#ty; #size]})
}
ParamType::Tuple(_) => {
let ty = if let Some(rust_struct_name) =
param.internal_type.as_ref().and_then(|s| resolve_tuple(s.as_str()))
{
let ident = util::ident(rust_struct_name);
quote! {#ident}
} else {
types::expand(kind)?
};
Ok(ty)
}
_ => types::expand(kind),
}
}

pub(crate) fn imports(name: &str) -> TokenStream {
let doc_str = format!("{name} was auto-generated with ethers-rs Abigen. More information at: https://github.com/gakonst/ethers-rs");

Expand Down
10 changes: 7 additions & 3 deletions ethers-contract/ethers-contract-abigen/src/contract/errors.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
//! derive error bindings

use super::{util, Context};
use crate::contract::common::{expand_data_struct, expand_data_tuple, expand_params};
use super::{
common::{expand_data_struct, expand_data_tuple},
types, util, Context,
};
use ethers_core::{
abi::{ethabi::AbiError, ErrorExt},
macros::{ethers_contract_crate, ethers_core_crate},
Expand Down Expand Up @@ -81,7 +83,9 @@ impl Context {

/// Expands to the `name : type` pairs of the function's outputs
fn expand_error_params(&self, error: &AbiError) -> Result<Vec<(TokenStream, TokenStream)>> {
expand_params(&error.inputs, |s| self.internal_structs.get_struct_type(s))
types::expand_params(&error.inputs, |p| {
p.internal_type.as_deref().and_then(|s| self.internal_structs.get_struct_type(s))
})
}

/// The name ident of the errors enum
Expand Down
94 changes: 8 additions & 86 deletions ethers-contract/ethers-contract-abigen/src/contract/events.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
use super::{types, util, Context};
use crate::util::can_derive_defaults;
use ethers_core::{
abi::{Event, EventExt, EventParam, Param, ParamType},
abi::{Event, EventExt, Param},
macros::{ethers_contract_crate, ethers_core_crate},
};
use eyre::Result;
use inflector::Inflector;
use proc_macro2::{Ident, Literal, TokenStream};
use proc_macro2::{Ident, TokenStream};
use quote::quote;
use std::collections::BTreeMap;

Expand Down Expand Up @@ -136,85 +136,6 @@ impl Context {
}
}

/// Expands an event property type.
///
/// Note that this is slightly different from expanding a Solidity type as
/// complex types like arrays and strings get emitted as hashes when they are
/// indexed.
/// If a complex types matches with a struct previously parsed by the internal structs,
/// we can replace it
fn expand_input_type(
&self,
event: &Event,
input: &EventParam,
idx: usize,
) -> Result<TokenStream> {
let ethers_core = ethers_core_crate();
Ok(match (&input.kind, input.indexed) {
(ParamType::Array(_), true) => {
quote! { #ethers_core::types::H256 }
}
(ParamType::FixedArray(_, _), true) => {
quote! { #ethers_core::types::H256 }
}
(ParamType::Tuple(..), true) => {
quote! { #ethers_core::types::H256 }
}
(ParamType::Bytes, true) | (ParamType::String, true) => {
quote! { #ethers_core::types::H256 }
}
(ParamType::Tuple(_), false) => {
let ty = if let Some(rust_struct_name) =
self.internal_structs.get_event_input_struct_type(&event.name, idx)
{
let ident = util::ident(rust_struct_name);
quote! {#ident}
} else {
types::expand(&input.kind)?
};
ty
}
(ParamType::Array(_), _) => {
// represents an array of a struct
if let Some(rust_struct_name) =
self.internal_structs.get_event_input_struct_type(&event.name, idx)
{
let ty = util::ident(rust_struct_name);
return Ok(quote! {::std::vec::Vec<#ty>})
}
types::expand(&input.kind)?
}
(ParamType::FixedArray(_, size), _) => {
// represents a fixed array of a struct
if let Some(rust_struct_name) =
self.internal_structs.get_event_input_struct_type(&event.name, idx)
{
let ty = util::ident(rust_struct_name);
let size = Literal::usize_unsuffixed(*size);
return Ok(quote! {[#ty; #size]})
}
types::expand(&input.kind)?
}
(kind, _) => types::expand(kind)?,
})
}

/// Expands the name-type pairs for the given inputs
fn expand_event_params(&self, event: &Event) -> Result<Vec<(TokenStream, TokenStream, bool)>> {
event
.inputs
.iter()
.enumerate()
.map(|(idx, input)| {
// NOTE: Events can contain nameless values.
let name = util::expand_input_name(idx, &input.name);
let ty = self.expand_input_type(event, input, idx)?;

Ok((name, ty, input.indexed))
})
.collect()
}

/// Expands into a single method for contracting an event stream.
fn expand_filter(&self, event: &Event) -> TokenStream {
let name = &event.name;
Expand Down Expand Up @@ -251,7 +172,7 @@ impl Context {

let event_name = event_struct_name(&event.name, sig);

let params = self.expand_event_params(event)?;
let params = types::expand_event_inputs(event, &self.internal_structs)?;
// expand as a tuple if all fields are anonymous
let all_anonymous_fields = event.inputs.iter().all(|input| input.name.is_empty());
let data_type_definition = if all_anonymous_fields {
Expand Down Expand Up @@ -355,6 +276,7 @@ mod tests {
use super::*;
use crate::Abigen;
use ethers_core::abi::{EventParam, Hash, ParamType};
use proc_macro2::Literal;

/// Expands a 256-bit `Hash` into a literal representation that can be used with
/// quasi-quoting for code generation. We do this to avoid allocating at runtime
Expand Down Expand Up @@ -443,7 +365,7 @@ mod tests {
};

let cx = test_context();
let params = cx.expand_event_params(&event).unwrap();
let params = types::expand_event_inputs(&event, &cx.internal_structs).unwrap();
let name = event_struct_name(&event.name, None);
let definition = expand_data_struct(&name, &params);

Expand All @@ -467,7 +389,7 @@ mod tests {
};

let cx = test_context_with_alias("Foo(bool,address)", "FooAliased");
let params = cx.expand_event_params(&event).unwrap();
let params = types::expand_event_inputs(&event, &cx.internal_structs).unwrap();
let alias = Some(util::ident("FooAliased"));
let name = event_struct_name(&event.name, alias);
let definition = expand_data_struct(&name, &params);
Expand All @@ -492,7 +414,7 @@ mod tests {
};

let cx = test_context();
let params = cx.expand_event_params(&event).unwrap();
let params = types::expand_event_inputs(&event, &cx.internal_structs).unwrap();
let name = event_struct_name(&event.name, None);
let definition = expand_data_tuple(&name, &params);

Expand All @@ -513,7 +435,7 @@ mod tests {
};

let cx = test_context_with_alias("Foo(bool,address)", "FooAliased");
let params = cx.expand_event_params(&event).unwrap();
let params = types::expand_event_inputs(&event, &cx.internal_structs).unwrap();
let alias = Some(util::ident("FooAliased"));
let name = event_struct_name(&event.name, alias);
let definition = expand_data_tuple(&name, &params);
Expand Down
Loading