191 lines
5.7 KiB
Rust
191 lines
5.7 KiB
Rust
use super::{util, Context};
|
|
|
|
use crate::contract::types;
|
|
use ethers_core::{
|
|
abi::{Param, ParamType},
|
|
macros::{ethers_contract_crate, ethers_core_crate, ethers_providers_crate},
|
|
};
|
|
use proc_macro2::{Ident, 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, ¶m.name);
|
|
let ty = expand_param_type(param, ¶m.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 = util::expand_doc(&format!("{} was auto-generated with ethers-rs Abigen. More information at: https://github.com/gakonst/ethers-rs", name));
|
|
|
|
let ethers_core = ethers_core_crate();
|
|
let ethers_providers = ethers_providers_crate();
|
|
let ethers_contract = ethers_contract_crate();
|
|
|
|
quote! {
|
|
#![allow(clippy::enum_variant_names)]
|
|
#![allow(dead_code)]
|
|
#![allow(clippy::type_complexity)]
|
|
#![allow(unused_imports)]
|
|
#doc
|
|
|
|
use std::sync::Arc;
|
|
use #ethers_core::{
|
|
abi::{Abi, Token, Detokenize, InvalidOutputType, Tokenizable},
|
|
types::*, // import all the types so that we can codegen for everything
|
|
};
|
|
use #ethers_contract::{Contract, builders::{ContractCall, Event}, Lazy};
|
|
use #ethers_providers::Middleware;
|
|
}
|
|
}
|
|
|
|
/// Generates the static `Abi` constants and the contract struct
|
|
pub(crate) fn struct_declaration(cx: &Context) -> TokenStream {
|
|
let name = &cx.contract_ident;
|
|
let abi = &cx.abi_str;
|
|
|
|
let abi_name = cx.inline_abi_ident();
|
|
|
|
let ethers_core = ethers_core_crate();
|
|
let ethers_providers = ethers_providers_crate();
|
|
let ethers_contract = ethers_contract_crate();
|
|
|
|
let abi_parse = if !cx.human_readable {
|
|
quote! {
|
|
pub static #abi_name: #ethers_contract::Lazy<#ethers_core::abi::Abi> = #ethers_contract::Lazy::new(|| #ethers_core::utils::__serde_json::from_str(#abi)
|
|
.expect("invalid abi"));
|
|
}
|
|
} else {
|
|
quote! {
|
|
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"));
|
|
}
|
|
};
|
|
|
|
let bytecode = if let Some(ref bytecode) = cx.contract_bytecode {
|
|
let bytecode_name = cx.inline_bytecode_ident();
|
|
let hex_bytecode = format!("{}", bytecode);
|
|
quote! {
|
|
/// Bytecode of the #name contract
|
|
pub static #bytecode_name: #ethers_contract::Lazy<#ethers_core::types::Bytes> = #ethers_contract::Lazy::new(|| #hex_bytecode.parse()
|
|
.expect("invalid bytecode"));
|
|
}
|
|
} else {
|
|
quote! {}
|
|
};
|
|
|
|
quote! {
|
|
// Inline ABI declaration
|
|
#abi_parse
|
|
|
|
#bytecode
|
|
|
|
// Struct declaration
|
|
pub struct #name<M>(#ethers_contract::Contract<M>);
|
|
|
|
impl<M> Clone for #name<M> {
|
|
fn clone(&self) -> Self {
|
|
#name(self.0.clone())
|
|
}
|
|
}
|
|
|
|
// Deref to the inner contract in order to access more specific functions functions
|
|
impl<M> std::ops::Deref for #name<M> {
|
|
type Target = #ethers_contract::Contract<M>;
|
|
|
|
fn deref(&self) -> &Self::Target { &self.0 }
|
|
}
|
|
|
|
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())
|
|
.finish()
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/// Expands to the tuple struct definition
|
|
pub(crate) fn expand_data_tuple(
|
|
name: &Ident,
|
|
params: &[(TokenStream, TokenStream)],
|
|
) -> TokenStream {
|
|
let fields = params
|
|
.iter()
|
|
.map(|(_, ty)| {
|
|
quote! {
|
|
pub #ty }
|
|
})
|
|
.collect::<Vec<_>>();
|
|
|
|
if fields.is_empty() {
|
|
quote! { struct #name; }
|
|
} else {
|
|
quote! { struct #name( #( #fields ),* ); }
|
|
}
|
|
}
|
|
|
|
/// Expands to a struct definition with named fields
|
|
pub(crate) fn expand_data_struct(
|
|
name: &Ident,
|
|
params: &[(TokenStream, TokenStream)],
|
|
) -> TokenStream {
|
|
let fields = params
|
|
.iter()
|
|
.map(|(name, ty)| {
|
|
quote! { pub #name: #ty }
|
|
})
|
|
.collect::<Vec<_>>();
|
|
|
|
quote! { struct #name { #( #fields, )* } }
|
|
}
|