--- a/crates/evm-coder-macros/src/solidity_interface.rs +++ b/crates/evm-coder-macros/src/solidity_interface.rs @@ -4,7 +4,10 @@ use darling::FromMeta; use inflector::cases; use std::fmt::Write; -use syn::{FnArg, Generics, Ident, ImplItem, ImplItemMethod, ItemImpl, Meta, NestedMeta, PatType, Path, ReturnType, Type, spanned::Spanned}; +use syn::{ + FnArg, Generics, Ident, ImplItem, ImplItemMethod, ItemImpl, Meta, NestedMeta, PatType, Path, + ReturnType, Type, spanned::Spanned, +}; use crate::{ fn_selector_str, parse_ident_from_pat, parse_ident_from_path, parse_ident_from_type, @@ -163,6 +166,14 @@ } } } + + fn expand_solidity_argument(&self) -> proc_macro2::TokenStream { + let name = &self.name.to_string(); + let ty = &self.ty; + quote! { + >::new(#name) + } + } } #[derive(PartialEq)] @@ -376,10 +387,35 @@ } } } + + fn expand_solidity_function(&self) -> proc_macro2::TokenStream { + let camel_name = &self.camel_name; + let mutability = match self.mutability { + Mutability::Mutable => quote! {SolidityMutability::Mutable}, + Mutability::View => quote! { SolidityMutability::View }, + Mutability::Pure => quote! {SolidityMutability::Pure}, + }; + let result = &self.result; + + let args = self.args.iter().map(MethodArg::expand_solidity_argument); + + quote! { + SolidityFunction { + name: #camel_name, + mutability: #mutability, + args: ( + #( + #args, + )* + ), + result: >::default(), + } + } + } } pub struct SolidityInterface { - generics: Generics, + generics: Generics, name: Box, info: InterfaceInfo, methods: Vec, @@ -394,7 +430,7 @@ } } Ok(Self { - generics: value.generics.clone(), + generics: value.generics.clone(), name: value.self_ty.clone(), info, methods, @@ -403,8 +439,9 @@ pub fn expand(self) -> proc_macro2::TokenStream { let name = self.name; + let solidity_name = self.info.name.to_string(); let call_name = pascal_ident_to_call(&self.info.name); - let generics = self.generics; + let generics = self.generics; let call_sub = self .info @@ -436,6 +473,7 @@ let interface_id = self.methods.iter().map(Method::expand_interface_id); let parsers = self.methods.iter().map(Method::expand_parse); let call_variants_this = self.methods.iter().map(Method::expand_variant_call); + let solidity_functions = self.methods.iter().map(Method::expand_solidity_function); // let methods = self.methods.iter().map(Method::solidity_def); @@ -467,6 +505,19 @@ )* ) } + pub fn generate_solidity_interface() -> string { + use evm_coder::solidity::*; + use core::fmt::Write; + let interface = SolidityInterface { + name: #solidity_name, + functions: (#( + #solidity_functions, + )*), + }; + let mut out = string::new(); + let _ = interface.format(&mut out); + out + } } impl ::evm_coder::Call for #call_name { fn parse(method_id: u32, reader: &mut ::evm_coder::abi::AbiReader) -> ::evm_coder::execution::Result> { --- a/crates/evm-coder/src/solidity.rs +++ b/crates/evm-coder/src/solidity.rs @@ -1,3 +1,5 @@ +#[cfg(not(feature = "std"))] +use alloc::{string::String}; use core::{fmt, marker::PhantomData}; use impl_trait_for_tuples::impl_for_tuples; use crate::types::*; @@ -23,8 +25,13 @@ solidity_type_name! { uint8 => "uint8", + uint32 => "uint32", + uint128 => "uint128", + uint256 => "uint256", address => "address", string => "memory string", + bytes => "memory bytes", + bool => "bool", } impl SolidityTypeName for void { fn solidity_name(_writer: &mut impl fmt::Write) -> fmt::Result { @@ -43,6 +50,7 @@ fn len(&self) -> usize; } +#[derive(Default)] pub struct UnnamedArgument(PhantomData<*const T>); impl SolidityArguments for UnnamedArgument { @@ -64,6 +72,12 @@ pub struct NamedArgument(&'static str, PhantomData<*const T>); +impl NamedArgument { + pub fn new(name: &'static str) -> Self { + Self(name, Default::default()) + } +} + impl SolidityArguments for NamedArgument { fn solidity_name(&self, writer: &mut impl fmt::Write) -> fmt::Result { if !T::is_void() { @@ -96,10 +110,10 @@ for_tuples!( where #( Tuple: SolidityArguments ),* ); fn solidity_name(&self, writer: &mut impl fmt::Write) -> fmt::Result { - let mut first = false; + let mut first = true; for_tuples!( #( if !Tuple.is_empty() { - if first { + if !first { write!(writer, ", ")?; } first = false; @@ -113,7 +127,7 @@ } } -trait SolidityFunctions { +pub trait SolidityFunctions { fn solidity_name(&self, writer: &mut impl fmt::Write) -> fmt::Result; } @@ -123,23 +137,23 @@ Mutable, } pub struct SolidityFunction { - name: &'static str, - args: A, - result: R, - mutability: SolidityMutability, + pub name: &'static str, + pub args: A, + pub result: R, + pub mutability: SolidityMutability, } impl SolidityFunctions for SolidityFunction { fn solidity_name(&self, writer: &mut impl fmt::Write) -> fmt::Result { write!(writer, "function {}(", self.name)?; self.args.solidity_name(writer)?; - write!(writer, ") public")?; + write!(writer, ") external")?; match &self.mutability { SolidityMutability::Pure => write!(writer, " pure")?, SolidityMutability::View => write!(writer, " view")?, SolidityMutability::Mutable => {} } if !self.result.is_empty() { - write!(writer, "returns (")?; + write!(writer, " returns (")?; self.result.solidity_name(writer)?; write!(writer, ")")?; } @@ -159,3 +173,17 @@ Ok(()) } } + +pub struct SolidityInterface { + pub name: &'static str, + pub functions: F, +} + +impl SolidityInterface { + pub fn format(&self, out: &mut impl fmt::Write) -> fmt::Result { + writeln!(out, "interface {} {{", self.name)?; + self.functions.solidity_name(out)?; + writeln!(out, "}}")?; + Ok(()) + } +} \ No newline at end of file