git.delta.rocks / unique-network / refs/commits / dc753ac3eb78

difftreelog

feat solidity code generation

Yaroslav Bolyukin2021-07-22parent: #ab49fc9.patch.diff
in: master

2 files changed

modifiedcrates/evm-coder-macros/src/solidity_interface.rsdiffbeforeafterboth
--- 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! {
+			<NamedArgument<#ty>>::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: <UnnamedArgument<#result>>::default(),
+			}
+		}
+	}
 }
 
 pub struct SolidityInterface {
-    generics: Generics,
+	generics: Generics,
 	name: Box<syn::Type>,
 	info: InterfaceInfo,
 	methods: Vec<Method>,
@@ -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<Option<Self>> {
modifiedcrates/evm-coder/src/solidity.rsdiffbeforeafterboth
before · crates/evm-coder/src/solidity.rs
1use core::{fmt, marker::PhantomData};2use impl_trait_for_tuples::impl_for_tuples;3use crate::types::*;45pub trait SolidityTypeName: 'static {6	fn solidity_name(writer: &mut impl fmt::Write) -> fmt::Result;7	fn is_void() -> bool {8		false9	}10}1112macro_rules! solidity_type_name {13    ($($ty:ident => $name:expr),* $(,)?) => {14        $(15            impl SolidityTypeName for $ty {16                fn solidity_name(writer: &mut impl core::fmt::Write) -> core::fmt::Result {17                    write!(writer, $name)18                }19            }20        )*21    };22}2324solidity_type_name! {25	uint8 => "uint8",26	address => "address",27	string => "memory string",28}29impl SolidityTypeName for void {30	fn solidity_name(_writer: &mut impl fmt::Write) -> fmt::Result {31		Ok(())32	}33	fn is_void() -> bool {34		true35	}36}3738pub trait SolidityArguments {39	fn solidity_name(&self, writer: &mut impl fmt::Write) -> fmt::Result;40	fn is_empty(&self) -> bool {41		self.len() == 042	}43	fn len(&self) -> usize;44}4546pub struct UnnamedArgument<T>(PhantomData<*const T>);4748impl<T: SolidityTypeName> SolidityArguments for UnnamedArgument<T> {49	fn solidity_name(&self, writer: &mut impl fmt::Write) -> fmt::Result {50		if !T::is_void() {51			T::solidity_name(writer)52		} else {53			Ok(())54		}55	}56	fn len(&self) -> usize {57		if T::is_void() {58			059		} else {60			161		}62	}63}6465pub struct NamedArgument<T>(&'static str, PhantomData<*const T>);6667impl<T: SolidityTypeName> SolidityArguments for NamedArgument<T> {68	fn solidity_name(&self, writer: &mut impl fmt::Write) -> fmt::Result {69		if !T::is_void() {70			T::solidity_name(writer)?;71			write!(writer, " {}", self.0)72		} else {73			Ok(())74		}75	}76	fn len(&self) -> usize {77		if T::is_void() {78			079		} else {80			181		}82	}83}8485impl SolidityArguments for () {86	fn solidity_name(&self, _writer: &mut impl fmt::Write) -> fmt::Result {87		Ok(())88	}89	fn len(&self) -> usize {90		091	}92}9394#[impl_for_tuples(1, 5)]95impl SolidityArguments for Tuple {96	for_tuples!( where #( Tuple: SolidityArguments ),* );9798	fn solidity_name(&self, writer: &mut impl fmt::Write) -> fmt::Result {99		let mut first = false;100		for_tuples!( #(101            if !Tuple.is_empty() {102                if first {103                    write!(writer, ", ")?;104                }105                first = false;106                Tuple.solidity_name(writer)?;107            }108        )* );109		Ok(())110	}111	fn len(&self) -> usize {112		for_tuples!( #( Tuple.len() )+* )113	}114}115116trait SolidityFunctions {117	fn solidity_name(&self, writer: &mut impl fmt::Write) -> fmt::Result;118}119120pub enum SolidityMutability {121	Pure,122	View,123	Mutable,124}125pub struct SolidityFunction<A, R> {126	name: &'static str,127	args: A,128	result: R,129	mutability: SolidityMutability,130}131impl<A: SolidityArguments, R: SolidityArguments> SolidityFunctions for SolidityFunction<A, R> {132	fn solidity_name(&self, writer: &mut impl fmt::Write) -> fmt::Result {133		write!(writer, "function {}(", self.name)?;134		self.args.solidity_name(writer)?;135		write!(writer, ") public")?;136		match &self.mutability {137			SolidityMutability::Pure => write!(writer, " pure")?,138			SolidityMutability::View => write!(writer, " view")?,139			SolidityMutability::Mutable => {}140		}141		if !self.result.is_empty() {142			write!(writer, "returns (")?;143			self.result.solidity_name(writer)?;144			write!(writer, ")")?;145		}146		writeln!(writer, ";")147	}148}149150#[impl_for_tuples(0, 12)]151impl SolidityFunctions for Tuple {152	for_tuples!( where #( Tuple: SolidityFunctions ),* );153154	fn solidity_name(&self, writer: &mut impl fmt::Write) -> fmt::Result {155		let mut first = false;156		for_tuples!( #(157            Tuple.solidity_name(writer)?;158        )* );159		Ok(())160	}161}
after · crates/evm-coder/src/solidity.rs
1#[cfg(not(feature = "std"))]2use alloc::{string::String};3use core::{fmt, marker::PhantomData};4use impl_trait_for_tuples::impl_for_tuples;5use crate::types::*;67pub trait SolidityTypeName: 'static {8	fn solidity_name(writer: &mut impl fmt::Write) -> fmt::Result;9	fn is_void() -> bool {10		false11	}12}1314macro_rules! solidity_type_name {15    ($($ty:ident => $name:expr),* $(,)?) => {16        $(17            impl SolidityTypeName for $ty {18                fn solidity_name(writer: &mut impl core::fmt::Write) -> core::fmt::Result {19                    write!(writer, $name)20                }21            }22        )*23    };24}2526solidity_type_name! {27	uint8 => "uint8",28	uint32 => "uint32",29	uint128 => "uint128",30	uint256 => "uint256",31	address => "address",32	string => "memory string",33	bytes => "memory bytes",34	bool => "bool",35}36impl SolidityTypeName for void {37	fn solidity_name(_writer: &mut impl fmt::Write) -> fmt::Result {38		Ok(())39	}40	fn is_void() -> bool {41		true42	}43}4445pub trait SolidityArguments {46	fn solidity_name(&self, writer: &mut impl fmt::Write) -> fmt::Result;47	fn is_empty(&self) -> bool {48		self.len() == 049	}50	fn len(&self) -> usize;51}5253#[derive(Default)]54pub struct UnnamedArgument<T>(PhantomData<*const T>);5556impl<T: SolidityTypeName> SolidityArguments for UnnamedArgument<T> {57	fn solidity_name(&self, writer: &mut impl fmt::Write) -> fmt::Result {58		if !T::is_void() {59			T::solidity_name(writer)60		} else {61			Ok(())62		}63	}64	fn len(&self) -> usize {65		if T::is_void() {66			067		} else {68			169		}70	}71}7273pub struct NamedArgument<T>(&'static str, PhantomData<*const T>);7475impl<T> NamedArgument<T> {76	pub fn new(name: &'static str) -> Self {77		Self(name, Default::default())78	}79}8081impl<T: SolidityTypeName> SolidityArguments for NamedArgument<T> {82	fn solidity_name(&self, writer: &mut impl fmt::Write) -> fmt::Result {83		if !T::is_void() {84			T::solidity_name(writer)?;85			write!(writer, " {}", self.0)86		} else {87			Ok(())88		}89	}90	fn len(&self) -> usize {91		if T::is_void() {92			093		} else {94			195		}96	}97}9899impl SolidityArguments for () {100	fn solidity_name(&self, _writer: &mut impl fmt::Write) -> fmt::Result {101		Ok(())102	}103	fn len(&self) -> usize {104		0105	}106}107108#[impl_for_tuples(1, 5)]109impl SolidityArguments for Tuple {110	for_tuples!( where #( Tuple: SolidityArguments ),* );111112	fn solidity_name(&self, writer: &mut impl fmt::Write) -> fmt::Result {113		let mut first = true;114		for_tuples!( #(115            if !Tuple.is_empty() {116                if !first {117                    write!(writer, ", ")?;118                }119                first = false;120                Tuple.solidity_name(writer)?;121            }122        )* );123		Ok(())124	}125	fn len(&self) -> usize {126		for_tuples!( #( Tuple.len() )+* )127	}128}129130pub trait SolidityFunctions {131	fn solidity_name(&self, writer: &mut impl fmt::Write) -> fmt::Result;132}133134pub enum SolidityMutability {135	Pure,136	View,137	Mutable,138}139pub struct SolidityFunction<A, R> {140	pub name: &'static str,141	pub args: A,142	pub result: R,143	pub mutability: SolidityMutability,144}145impl<A: SolidityArguments, R: SolidityArguments> SolidityFunctions for SolidityFunction<A, R> {146	fn solidity_name(&self, writer: &mut impl fmt::Write) -> fmt::Result {147		write!(writer, "function {}(", self.name)?;148		self.args.solidity_name(writer)?;149		write!(writer, ") external")?;150		match &self.mutability {151			SolidityMutability::Pure => write!(writer, " pure")?,152			SolidityMutability::View => write!(writer, " view")?,153			SolidityMutability::Mutable => {}154		}155		if !self.result.is_empty() {156			write!(writer, " returns (")?;157			self.result.solidity_name(writer)?;158			write!(writer, ")")?;159		}160		writeln!(writer, ";")161	}162}163164#[impl_for_tuples(0, 12)]165impl SolidityFunctions for Tuple {166	for_tuples!( where #( Tuple: SolidityFunctions ),* );167168	fn solidity_name(&self, writer: &mut impl fmt::Write) -> fmt::Result {169		let mut first = false;170		for_tuples!( #(171            Tuple.solidity_name(writer)?;172        )* );173		Ok(())174	}175}176177pub struct SolidityInterface<F: SolidityFunctions> {178	pub name: &'static str,179	pub functions: F,180}181182impl<F: SolidityFunctions> SolidityInterface<F> {183	pub fn format(&self, out: &mut impl fmt::Write) -> fmt::Result {184		writeln!(out, "interface {} {{", self.name)?;185		self.functions.solidity_name(out)?;186		writeln!(out, "}}")?;187		Ok(())188	}189}