difftreelog
refactor external generation of call parsers
in: master
4 files changed
crates/evm-coder-macros/src/lib.rsdiffbeforeafterboth5use proc_macro::TokenStream;5use proc_macro::TokenStream;6use quote::quote;6use quote::quote;7use sha3::{Digest, Keccak256};7use sha3::{Digest, Keccak256};8use syn::{8use syn::{AttributeArgs, DeriveInput, GenericArgument, Ident, ItemImpl, Pat, Path, PathArguments, PathSegment, Type, parse_macro_input, spanned::Spanned};9 AttributeArgs, DeriveInput, GenericArgument, Ident, ItemTrait, Pat, Path, PathArguments,10 PathSegment, Type, parse_macro_input, spanned::Spanned,11};12913mod solidity_interface;10mod solidity_interface;189 let args = parse_macro_input!(args as AttributeArgs);186 let args = parse_macro_input!(args as AttributeArgs);190 let args = solidity_interface::InterfaceInfo::from_list(&args).unwrap();187 let args = solidity_interface::InterfaceInfo::from_list(&args).unwrap();191188192 let input: ItemTrait = match syn::parse(stream) {189 let input: ItemImpl = match syn::parse(stream) {193 Ok(t) => t,190 Ok(t) => t,194 Err(e) => return e.to_compile_error().into(),191 Err(e) => return e.to_compile_error().into(),195 };192 };196193197 match solidity_interface::SolidityInterface::try_from(args, &input) {194 let expanded = match solidity_interface::SolidityInterface::try_from(args, &input) {198 Ok(v) => v.expand(),195 Ok(v) => v.expand(),199 Err(e) => e.to_compile_error(),196 Err(e) => e.to_compile_error(),200 }197 };198199 (quote! {200 #input201202 #expanded201 .into()203 }).into()202}204}203205204#[proc_macro_attribute]206#[proc_macro_attribute]crates/evm-coder-macros/src/solidity_interface.rsdiffbeforeafterboth4use darling::FromMeta;4use darling::FromMeta;5use inflector::cases;5use inflector::cases;6use std::fmt::Write;6use std::fmt::Write;7use syn::{FnArg, Ident, ItemTrait, Meta, NestedMeta, PatType, Path, ReturnType, TraitItem, TraitItemMethod, Type, Visibility, spanned::Spanned};7use syn::{8 FnArg, Ident, ImplItem, ImplItemMethod, ItemImpl, Meta, NestedMeta, PatType, Path, ReturnType,9 Type, spanned::Spanned,10};8119use crate::{12use crate::{515452 fn expand_variant_call(&self) -> proc_macro2::TokenStream {55 fn expand_variant_call(&self) -> proc_macro2::TokenStream {53 let name = &self.name;56 let name = &self.name;54 let snake_call_name = &self.snake_call_name;57 let pascal_call_name = &self.pascal_call_name;55 quote! {58 quote! {56 InternalCall::#name(call) => return self.#snake_call_name(Msg {59 InternalCall::#name(call) => return <Self as ::evm_coder::Callable<#pascal_call_name>>::call(self, Msg {57 call,60 call,58 caller: c.caller,61 caller: c.caller,59 value: c.value,62 value: c.value,60 })63 })61 }64 }62 }65 }6364 fn expand_call_inner(&self) -> proc_macro2::TokenStream {65 let snake_call_name = &self.snake_call_name;66 let pascal_call_name = &self.pascal_call_name;67 quote! {68 fn #snake_call_name(&mut self, c: Msg<#pascal_call_name>) -> Result<::evm_coder::abi::AbiWriter>;69 }70 }716672 fn expand_parse(&self) -> proc_macro2::TokenStream {67 fn expand_parse(&self) -> proc_macro2::TokenStream {73 let name = &self.name;68 let name = &self.name;979298#[derive(FromMeta)]93#[derive(FromMeta)]99pub struct InterfaceInfo {94pub struct InterfaceInfo {95 name: Ident,100 #[darling(default)]96 #[darling(default)]101 is: IsList,97 is: IsList,102 #[darling(default)]98 #[darling(default)]192 result: Type,188 result: Type,193}189}194impl Method {190impl Method {195 fn try_from(value: &TraitItemMethod) -> syn::Result<Self> {191 fn try_from(value: &ImplItemMethod) -> syn::Result<Self> {196 let mut info = MethodInfo {192 let mut info = MethodInfo {197 rename_selector: None,193 rename_selector: None,198 };194 };386}382}387383388pub struct SolidityInterface {384pub struct SolidityInterface {389 vis: Visibility,385 name: Box<syn::Type>,390 name: Ident,386 ident: Ident,391 info: InterfaceInfo,387 info: InterfaceInfo,392 methods: Vec<Method>,388 methods: Vec<Method>,393 items: Vec<TraitItem>,394}389}395impl SolidityInterface {390impl SolidityInterface {396 pub fn try_from(info: InterfaceInfo, value: &ItemTrait) -> syn::Result<Self> {391 pub fn try_from(info: InterfaceInfo, value: &ItemImpl) -> syn::Result<Self> {397 let mut methods = Vec::new();392 let mut methods = Vec::new();398393399 for item in &value.items {394 for item in &value.items {400 match item {395 if let ImplItem::Method(method) = item {401 TraitItem::Method(method) => methods.push(Method::try_from(method)?),396 methods.push(Method::try_from(method)?)402 _ => {}403 }397 }404 }398 }405 Ok(Self {399 Ok(Self {406 vis: value.vis.clone(),400 name: value.self_ty.clone(),407 name: value.ident.clone(),401 ident: parse_ident_from_type(&value.self_ty)?.clone(),408 info,402 info,409 methods,403 methods,410 items: value.items.clone(),411 })404 })412 }405 }413 pub fn expand(self) -> proc_macro2::TokenStream {406 pub fn expand(self) -> proc_macro2::TokenStream {414 let vis = self.vis;415 let name = self.name;407 let name = self.name;416 let items = self.items;417408418 let call_name = pascal_ident_to_call(&name);409 let call_name = pascal_ident_to_call(&self.info.name);419410420 let call_sub = self411 let call_sub = self421 .info412 .info424 .iter()415 .iter()425 .chain(self.info.is.0.iter())416 .chain(self.info.is.0.iter())426 .map(Is::expand_call_def);417 .map(Is::expand_call_def);427 let call_inner = self428 .info429 .inline_is430 .0431 .iter()432 .chain(self.info.is.0.iter())433 .map(Is::expand_call_inner);434 let call_parse = self418 let call_parse = self435 .info419 .info436 .inline_is420 .inline_is459443460 quote! {444 quote! {461 #[derive(Debug)]445 #[derive(Debug)]462 #vis enum #call_name {446 pub enum #call_name {463 #(447 #(464 #calls,448 #calls,465 )*449 )*501 return Ok(None);485 return Ok(None);502 }486 }503 }487 }504 #vis trait #name {505 #(506 #items507 )*508 #(509 #call_inner510 )*511 }512 impl<T> ::evm_coder::Callable for T where T: #name {488 impl ::evm_coder::Callable<#call_name> for #name {513 type Call = #call_name;514 #[allow(unreachable_code)] // In case of no inner calls489 #[allow(unreachable_code)] // In case of no inner calls515 fn call(&mut self, c: Msg<#call_name>) -> Result<::evm_coder::abi::AbiWriter> {490 fn call(&mut self, c: Msg<#call_name>) -> Result<::evm_coder::abi::AbiWriter> {516 use ::evm_coder::abi::AbiWrite;491 use ::evm_coder::abi::AbiWrite;crates/evm-coder/src/lib.rsdiffbeforeafterboth57 fn parse(selector: u32, input: &mut AbiReader) -> execution::Result<Option<Self>>;57 fn parse(selector: u32, input: &mut AbiReader) -> execution::Result<Option<Self>>;58}58}595960pub trait Callable {60pub trait Callable<C: Call> {61 type Call: Call;62 fn call(&mut self, call: types::Msg<Self::Call>) -> execution::Result<AbiWriter>;61 fn call(&mut self, call: types::Msg<C>) -> execution::Result<AbiWriter>;63}62}646365#[cfg(test)]64#[cfg(test)]66mod tests {65mod tests {crates/evm-coder/tests/a.rsdiffbeforeafterboth3use evm_coder::{solidity_interface, types::*, ToLog, execution::Result};3use evm_coder::{solidity_interface, types::*, ToLog, execution::Result};4use evm_coder_macros::solidity;4use evm_coder_macros::solidity;56struct Impls;576#[solidity_interface]8#[solidity_interface(name = "OurInterface")]7trait OurInterface {9impl Impls {8 fn fn_a(&self, input: uint256) -> Result<bool>;10 fn fn_a(&self, input: uint256) -> Result<bool> {11 todo!()12 }9}13}101411#[solidity_interface]15#[solidity_interface(name = "OurInterface1")]12trait OurInterface1 {16impl Impls {13 fn fn_b(&self, input: uint128) -> Result<uint32>;17 fn fn_b(&self, input: uint128) -> Result<uint32> {18 todo!()19 }14}20}152116#[solidity_interface(is(OurInterface), inline_is(OurInterface1), events(ERC721Log))]22#[solidity_interface(name = "OurInterface2", is(OurInterface), inline_is(OurInterface1), events(ERC721Log))]17trait OurInterface2 {23impl Impls {18 #[solidity(rename_selector = "fnK")]24 #[solidity(rename_selector = "fnK")]19 fn fn_c(&self, input: uint32) -> Result<uint8>;25 fn fn_c(&self, input: uint32) -> Result<uint8> {26 todo!()27 }20 fn fn_d(&self, value: uint32) -> Result<uint32>;28 fn fn_d(&self, value: uint32) -> Result<uint32> {29 todo!()30 }213122 fn caller_sensitive(&self, caller: caller) -> Result<uint8>;32 fn caller_sensitive(&self, caller: caller) -> Result<uint8> {33 todo!()34 }23 fn payable(&mut self, value: value) -> Result<uint8>;35 fn payable(&mut self, value: value) -> Result<uint8> {36 todo!()37 }24}38}253926#[derive(ToLog)]40#[derive(ToLog)]39 },53 },40}54}5556struct ERC20;415742#[solidity_interface]58#[solidity_interface(name = "ERC20")]43trait ERC20 {59impl ERC20 {44 fn decimals(&self) -> Result<uint8>;60 fn decimals(&self) -> Result<uint8> {61 todo!()62 }45 fn balance_of(&self, owner: address) -> Result<uint256>;63 fn balance_of(&self, owner: address) -> Result<uint256> {64 todo!()65 }46 fn transfer(&mut self, caller: caller, to: address, value: uint256) -> Result<bool>;66 fn transfer(&mut self, caller: caller, to: address, value: uint256) -> Result<bool> {67 todo!()68 }47 fn transfer_from(69 fn transfer_from(48 &mut self,70 &mut self,49 caller: caller,71 caller: caller,50 from: address,72 from: address,51 to: address,73 to: address,52 value: uint256,74 value: uint256,53 ) -> Result<bool>;75 ) -> Result<bool> {76 todo!()77 }54 fn approve(&mut self, caller: caller, spender: address, value: uint256) -> Result<bool>;78 fn approve(&mut self, caller: caller, spender: address, value: uint256) -> Result<bool> {79 todo!()80 }55 fn allowance(&self, owner: address, spender: address) -> Result<uint256>;81 fn allowance(&self, owner: address, spender: address) -> Result<uint256> {82 todo!()83 }56}84}5785