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

difftreelog

feat regenerate solidity stubs

Yaroslav Bolyukin2021-11-02parent: #44992fc.patch.diff
in: master

15 files changed

modified.maintain/scripts/compile_stub.shdiffbeforeafterboth
--- a/.maintain/scripts/compile_stub.sh
+++ b/.maintain/scripts/compile_stub.sh
@@ -6,9 +6,9 @@
 tmp=$(mktemp -d)
 cd $tmp
 cp $dir/$INPUT input.sol
-solcjs --optimize --bin input.sol
+solcjs --optimize --bin input.sol -o $PWD
 
 mv input_sol_$(basename $OUTPUT .raw).bin out.bin
 xxd -r -p out.bin out.raw
 
-mv out.raw $dir/$OUTPUT
\ No newline at end of file
+mv out.raw $dir/$OUTPUT
modified.maintain/scripts/generate_api.shdiffbeforeafterboth
--- a/.maintain/scripts/generate_api.sh
+++ b/.maintain/scripts/generate_api.sh
@@ -9,4 +9,4 @@
 prettier --use-tabs $raw > $formatted
 solhint --fix $formatted
 
-mv $formatted $OUTPUT
\ No newline at end of file
+mv $formatted $OUTPUT
modifiedMakefilediffbeforeafterboth
--- a/Makefile
+++ b/Makefile
@@ -8,25 +8,26 @@
 
 .PHONY: regenerate_solidity
 regenerate_solidity:
-	PACKAGE=pallet-nft NAME=eth::erc::fungible_iface OUTPUT=./tests/src/eth/api/UniqueFungible.sol ./.maintain/scripts/generate_api.sh
-	PACKAGE=pallet-nft NAME=eth::erc::nft_iface OUTPUT=./tests/src/eth/api/UniqueNFT.sol ./.maintain/scripts/generate_api.sh
+	PACKAGE=pallet-fungible NAME=erc::gen_iface OUTPUT=./tests/src/eth/api/UniqueFungible.sol ./.maintain/scripts/generate_api.sh
+	PACKAGE=pallet-nonfungible NAME=erc::gen_iface OUTPUT=./tests/src/eth/api/UniqueNFT.sol ./.maintain/scripts/generate_api.sh
 	PACKAGE=pallet-evm-contract-helpers NAME=eth::contract_helpers_iface OUTPUT=./tests/src/eth/api/ContractHelpers.sol ./.maintain/scripts/generate_api.sh
 
-	PACKAGE=pallet-nft NAME=eth::erc::fungible_impl OUTPUT=./pallets/nft/src/eth/stubs/UniqueFungible.sol ./.maintain/scripts/generate_api.sh
-	PACKAGE=pallet-nft NAME=eth::erc::nft_impl OUTPUT=./pallets/nft/src/eth/stubs/UniqueNFT.sol ./.maintain/scripts/generate_api.sh
+	PACKAGE=pallet-fungible NAME=erc::gen_impl OUTPUT=./pallets/fungible/src/stubs/UniqueFungible.sol ./.maintain/scripts/generate_api.sh
+	PACKAGE=pallet-nonfungible NAME=erc::gen_impl OUTPUT=./pallets/nonfungible/src/stubs/UniqueNFT.sol ./.maintain/scripts/generate_api.sh
 	PACKAGE=pallet-evm-contract-helpers NAME=eth::contract_helpers_impl OUTPUT=./pallets/evm-contract-helpers/src/stubs/ContractHelpers.sol ./.maintain/scripts/generate_api.sh
 
-NFT_EVM_STUBS=./pallets/nft/src/eth/stubs
+FUNGIBLE_EVM_STUBS=./pallets/fungible/src/stubs
+NONFUNGIBLE_EVM_STUBS=./pallets/nonfungible/src/stubs
 CONTRACT_HELPERS_STUBS=./pallets/evm-contract-helpers/src/stubs/
 
-$(NFT_EVM_STUBS)/UniqueFungible.raw: $(NFT_EVM_STUBS)/UniqueFungible.sol
+$(FUNGIBLE_EVM_STUBS)/UniqueFungible.raw: $(FUNGIBLE_EVM_STUBS)/UniqueFungible.sol
 	INPUT=$< OUTPUT=$@ ./.maintain/scripts/compile_stub.sh
-$(NFT_EVM_STUBS)/UniqueNFT.raw: $(NFT_EVM_STUBS)/UniqueNFT.sol
+$(NONFUNGIBLE_EVM_STUBS)/UniqueNFT.raw: $(NONFUNGIBLE_EVM_STUBS)/UniqueNFT.sol
 	INPUT=$< OUTPUT=$@ ./.maintain/scripts/compile_stub.sh
 $(CONTRACT_HELPERS_STUBS)/ContractHelpers.raw: $(CONTRACT_HELPERS_STUBS)/ContractHelpers.sol
 	INPUT=$< OUTPUT=$@ ./.maintain/scripts/compile_stub.sh
 
-evm_stubs: $(NFT_EVM_STUBS)/UniqueFungible.raw $(NFT_EVM_STUBS)/UniqueNFT.raw $(CONTRACT_HELPERS_STUBS)/ContractHelpers.raw
+evm_stubs: $(FUNGIBLE_EVM_STUBS)/UniqueFungible.raw $(NONFUNGIBLE_EVM_STUBS)/UniqueNFT.raw $(CONTRACT_HELPERS_STUBS)/ContractHelpers.raw
 
 .PHONY: _bench
 _bench:
modifiedcrates/evm-coder-macros/src/solidity_interface.rsdiffbeforeafterboth
before · crates/evm-coder-macros/src/solidity_interface.rs
1#![allow(dead_code)]23use quote::quote;4use darling::{FromMeta, ToTokens};5use inflector::cases;6use std::fmt::Write;7use syn::{8	Expr, FnArg, GenericArgument, Generics, Ident, ImplItem, ImplItemMethod, ItemImpl, Lit, Meta,9	NestedMeta, PatType, Path, PathArguments, ReturnType, Type, spanned::Spanned,10};1112use crate::{13	fn_selector_str, parse_ident_from_pat, parse_ident_from_path, parse_path, parse_path_segment,14	parse_result_ok, pascal_ident_to_call, pascal_ident_to_snake_call, snake_ident_to_pascal,15	snake_ident_to_screaming,16};1718struct Is {19	name: Ident,20	pascal_call_name: Ident,21	snake_call_name: Ident,22}23impl Is {24	fn try_from(path: &Path) -> syn::Result<Self> {25		let name = parse_ident_from_path(path, false)?.clone();26		Ok(Self {27			pascal_call_name: pascal_ident_to_call(&name),28			snake_call_name: pascal_ident_to_snake_call(&name),29			name,30		})31	}3233	fn expand_call_def(&self) -> proc_macro2::TokenStream {34		let name = &self.name;35		let pascal_call_name = &self.pascal_call_name;36		quote! {37			#name(#pascal_call_name)38		}39	}4041	fn expand_interface_id(&self) -> proc_macro2::TokenStream {42		let pascal_call_name = &self.pascal_call_name;43		quote! {44			interface_id ^= #pascal_call_name::interface_id();45		}46	}4748	fn expand_supports_interface(&self) -> proc_macro2::TokenStream {49		let pascal_call_name = &self.pascal_call_name;50		quote! {51			#pascal_call_name::supports_interface(interface_id)52		}53	}5455	fn expand_variant_call(&self) -> proc_macro2::TokenStream {56		let name = &self.name;57		let pascal_call_name = &self.pascal_call_name;58		quote! {59			InternalCall::#name(call) => return <Self as ::evm_coder::Callable<#pascal_call_name>>::call(self, Msg {60				call,61				caller: c.caller,62				value: c.value,63			})64		}65	}6667	fn expand_parse(&self) -> proc_macro2::TokenStream {68		let name = &self.name;69		let pascal_call_name = &self.pascal_call_name;70		quote! {71			if let Some(parsed_call) = #pascal_call_name::parse(method_id, reader)? {72				return Ok(Some(Self::#name(parsed_call)))73			}74		}75	}7677	fn expand_generator(&self) -> proc_macro2::TokenStream {78		let pascal_call_name = &self.pascal_call_name;79		quote! {80			#pascal_call_name::generate_solidity_interface(tc, is_impl);81		}82	}8384	fn expand_event_generator(&self) -> proc_macro2::TokenStream {85		let name = &self.name;86		quote! {87			#name::generate_solidity_interface(tc, is_impl);88		}89	}90}9192#[derive(Default)]93struct IsList(Vec<Is>);94impl FromMeta for IsList {95	fn from_list(items: &[NestedMeta]) -> darling::Result<Self> {96		let mut out = Vec::new();97		for item in items {98			match item {99				NestedMeta::Meta(Meta::Path(path)) => out.push(Is::try_from(path)?),100				_ => return Err(syn::Error::new(item.span(), "expected path").into()),101			}102		}103		Ok(Self(out))104	}105}106107#[derive(FromMeta)]108pub struct InterfaceInfo {109	name: Ident,110	#[darling(default)]111	is: IsList,112	#[darling(default)]113	inline_is: IsList,114	#[darling(default)]115	events: IsList,116}117118#[derive(FromMeta)]119struct MethodInfo {120	#[darling(default)]121	rename_selector: Option<String>,122}123124enum AbiType {125	// type126	Plain(Ident),127	// (type1,type2)128	Tuple(Vec<AbiType>),129	// type[]130	Vec(Box<AbiType>),131	// type[20]132	Array(Box<AbiType>, usize),133}134impl AbiType {135	fn try_from(value: &Type) -> syn::Result<Self> {136		let value = Self::try_maybe_special_from(value)?;137		if value.is_special() {138			return Err(syn::Error::new(value.span(), "unexpected special type"));139		}140		Ok(value)141	}142	fn try_maybe_special_from(value: &Type) -> syn::Result<Self> {143		match value {144			Type::Array(arr) => {145				let wrapped = AbiType::try_from(&arr.elem)?;146				match &arr.len {147					Expr::Lit(l) => match &l.lit {148						Lit::Int(i) => {149							let num = i.base10_parse::<usize>()?;150							Ok(AbiType::Array(Box::new(wrapped), num as usize))151						}152						_ => Err(syn::Error::new(arr.len.span(), "should be int literal")),153					},154					_ => Err(syn::Error::new(arr.len.span(), "should be literal")),155				}156			}157			Type::Path(_) => {158				let path = parse_path(value)?;159				let segment = parse_path_segment(path)?;160				if segment.ident == "Vec" {161					let args = match &segment.arguments {162						PathArguments::AngleBracketed(e) => e,163						_ => {164							return Err(syn::Error::new(165								segment.arguments.span(),166								"missing Vec generic",167							))168						}169					};170					let args = &args.args;171					if args.len() != 1 {172						return Err(syn::Error::new(173							args.span(),174							"expected only one generic for vec",175						));176					}177					let arg = args.first().unwrap();178179					let ty = match arg {180						GenericArgument::Type(ty) => ty,181						_ => {182							return Err(syn::Error::new(183								arg.span(),184								"expected first generic to be type",185							))186						}187					};188189					let wrapped = AbiType::try_from(ty)?;190					Ok(Self::Vec(Box::new(wrapped)))191				} else {192					if !segment.arguments.is_empty() {193						return Err(syn::Error::new(194							segment.arguments.span(),195							"unexpected generic arguments for non-vec type",196						));197					}198					Ok(Self::Plain(segment.ident.clone()))199				}200			}201			Type::Tuple(t) => {202				let mut out = Vec::with_capacity(t.elems.len());203				for el in t.elems.iter() {204					out.push(AbiType::try_from(el)?)205				}206				Ok(Self::Tuple(out))207			}208			_ => Err(syn::Error::new(209				value.span(),210				"unexpected type, only arrays, plain types and tuples are supported",211			)),212		}213	}214	fn is_value(&self) -> bool {215		match self {216			Self::Plain(v) if v == "value" => true,217			_ => false,218		}219	}220	fn is_caller(&self) -> bool {221		match self {222			Self::Plain(v) if v == "caller" => true,223			_ => false,224		}225	}226	fn is_special(&self) -> bool {227		self.is_caller() || self.is_value()228	}229	fn selector_ty_buf(&self, buf: &mut String) -> std::fmt::Result {230		match self {231			AbiType::Plain(t) => {232				write!(buf, "{}", t)233			}234			AbiType::Tuple(t) => {235				write!(buf, "(")?;236				for (i, t) in t.iter().enumerate() {237					if i != 0 {238						write!(buf, ",")?;239					}240					t.selector_ty_buf(buf)?;241				}242				write!(buf, ")")243			}244			AbiType::Vec(v) => {245				v.selector_ty_buf(buf)?;246				write!(buf, "[]")247			}248			AbiType::Array(v, len) => {249				v.selector_ty_buf(buf)?;250				write!(buf, "[{}]", len)251			}252		}253	}254	fn selector_ty(&self) -> String {255		let mut out = String::new();256		self.selector_ty_buf(&mut out).expect("no fmt error");257		out258	}259}260impl ToTokens for AbiType {261	fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) {262		match self {263			AbiType::Plain(t) => tokens.extend(quote! {#t}),264			AbiType::Tuple(t) => {265				tokens.extend(quote! {(266					#(#t),*267				)});268			}269			AbiType::Vec(v) => tokens.extend(quote! {Vec<#v>}),270			AbiType::Array(v, l) => tokens.extend(quote! {[#v; #l]}),271		}272	}273}274275struct MethodArg {276	name: Ident,277	camel_name: String,278	ty: AbiType,279}280impl MethodArg {281	fn try_from(value: &PatType) -> syn::Result<Self> {282		let name = parse_ident_from_pat(&value.pat)?.clone();283		Ok(Self {284			camel_name: cases::camelcase::to_camel_case(&name.to_string()),285			name,286			ty: AbiType::try_maybe_special_from(&value.ty)?,287		})288	}289	fn is_value(&self) -> bool {290		self.ty.is_value()291	}292	fn is_caller(&self) -> bool {293		self.ty.is_caller()294	}295	fn is_special(&self) -> bool {296		self.ty.is_special()297	}298	fn selector_ty(&self) -> String {299		assert!(!self.is_special());300		self.ty.selector_ty()301	}302303	fn expand_call_def(&self) -> proc_macro2::TokenStream {304		assert!(!self.is_special());305		let name = &self.name;306		let ty = &self.ty;307308		quote! {309			#name: #ty310		}311	}312313	fn expand_parse(&self) -> proc_macro2::TokenStream {314		assert!(!self.is_special());315		let name = &self.name;316		quote! {317			#name: reader.abi_read()?318		}319	}320321	fn expand_call_arg(&self) -> proc_macro2::TokenStream {322		if self.is_value() {323			quote! {324				c.value.clone()325			}326		} else if self.is_caller() {327			quote! {328				c.caller.clone()329			}330		} else {331			let name = &self.name;332			quote! {333				#name334			}335		}336	}337338	fn expand_solidity_argument(&self) -> proc_macro2::TokenStream {339		let camel_name = &self.camel_name.to_string();340		let ty = &self.ty;341		quote! {342			<NamedArgument<#ty>>::new(#camel_name)343		}344	}345}346347#[derive(PartialEq)]348enum Mutability {349	Mutable,350	View,351	Pure,352}353354struct Method {355	name: Ident,356	camel_name: String,357	pascal_name: Ident,358	screaming_name: Ident,359	selector_str: String,360	selector: u32,361	args: Vec<MethodArg>,362	has_normal_args: bool,363	mutability: Mutability,364	result: Type,365}366impl Method {367	fn try_from(value: &ImplItemMethod) -> syn::Result<Self> {368		let mut info = MethodInfo {369			rename_selector: None,370		};371		for attr in &value.attrs {372			let ident = parse_ident_from_path(&attr.path, false)?;373			if ident == "solidity" {374				let args = attr.parse_meta().unwrap();375				info = MethodInfo::from_meta(&args).unwrap();376			} else if ident == "doc" {377				// TODO: Add docs to evm interfaces378			}379		}380		let ident = &value.sig.ident;381		let ident_str = ident.to_string();382		if !cases::snakecase::is_snake_case(&ident_str) {383			return Err(syn::Error::new(ident.span(), "method name should be snake_cased\nif alternative solidity name needs to be set - use #[solidity] attribute"));384		}385386		let mut mutability = Mutability::Pure;387388		if let Some(FnArg::Receiver(receiver)) = value389			.sig390			.inputs391			.iter()392			.find(|arg| matches!(arg, FnArg::Receiver(_)))393		{394			if receiver.reference.is_none() {395				return Err(syn::Error::new(396					receiver.span(),397					"receiver should be by ref",398				));399			}400			if receiver.mutability.is_some() {401				mutability = Mutability::Mutable;402			} else {403				mutability = Mutability::View;404			}405		}406		let mut args = Vec::new();407		for typ in value408			.sig409			.inputs410			.iter()411			.filter(|arg| matches!(arg, FnArg::Typed(_)))412		{413			let typ = match typ {414				FnArg::Typed(typ) => typ,415				_ => unreachable!(),416			};417			args.push(MethodArg::try_from(typ)?);418		}419420		if mutability != Mutability::Mutable && args.iter().any(|arg| arg.is_value()) {421			return Err(syn::Error::new(422				args.iter().find(|arg| arg.is_value()).unwrap().ty.span(),423				"payable function should be mutable",424			));425		}426427		let result = match &value.sig.output {428			ReturnType::Type(_, ty) => ty,429			_ => return Err(syn::Error::new(value.sig.output.span(), "interface method should return Result<value>\nif there is no value to return - specify void (which is alias to unit)")),430		};431		let result = parse_result_ok(result)?;432433		let camel_name = info434			.rename_selector435			.unwrap_or_else(|| cases::camelcase::to_camel_case(&ident.to_string()));436		let mut selector_str = camel_name.clone();437		selector_str.push('(');438		let mut has_normal_args = false;439		for (i, arg) in args.iter().filter(|arg| !arg.is_special()).enumerate() {440			if i != 0 {441				selector_str.push(',');442			}443			write!(selector_str, "{}", arg.selector_ty()).unwrap();444			has_normal_args = true;445		}446		selector_str.push(')');447		let selector = fn_selector_str(&selector_str);448449		Ok(Self {450			name: ident.clone(),451			camel_name,452			pascal_name: snake_ident_to_pascal(ident),453			screaming_name: snake_ident_to_screaming(ident),454			selector_str,455			selector,456			args,457			has_normal_args,458			mutability,459			result: result.clone(),460		})461	}462	fn expand_call_def(&self) -> proc_macro2::TokenStream {463		let defs = self464			.args465			.iter()466			.filter(|a| !a.is_special())467			.map(|a| a.expand_call_def());468		let pascal_name = &self.pascal_name;469470		if self.has_normal_args {471			quote! {472				#pascal_name {473					#(474						#defs,475					)*476				}477			}478		} else {479			quote! {#pascal_name}480		}481	}482483	fn expand_const(&self) -> proc_macro2::TokenStream {484		let screaming_name = &self.screaming_name;485		let selector = self.selector;486		let selector_str = &self.selector_str;487		quote! {488			#[doc = #selector_str]489			const #screaming_name: u32 = #selector;490		}491	}492493	fn expand_interface_id(&self) -> proc_macro2::TokenStream {494		let screaming_name = &self.screaming_name;495		quote! {496			interface_id ^= Self::#screaming_name;497		}498	}499500	fn expand_parse(&self) -> proc_macro2::TokenStream {501		let pascal_name = &self.pascal_name;502		let screaming_name = &self.screaming_name;503		if self.has_normal_args {504			let parsers = self505				.args506				.iter()507				.filter(|a| !a.is_special())508				.map(|a| a.expand_parse());509			quote! {510				Self::#screaming_name => return Ok(Some(Self::#pascal_name {511					#(512						#parsers,513					)*514				}))515			}516		} else {517			quote! { Self::#screaming_name => return Ok(Some(Self::#pascal_name)) }518		}519	}520521	fn expand_variant_call(&self) -> proc_macro2::TokenStream {522		let pascal_name = &self.pascal_name;523		let name = &self.name;524525		let matcher = if self.has_normal_args {526			let names = self527				.args528				.iter()529				.filter(|a| !a.is_special())530				.map(|a| &a.name);531532			quote! {{533				#(534					#names,535				)*536			}}537		} else {538			quote! {}539		};540541		let receiver = match self.mutability {542			Mutability::Mutable | Mutability::View => quote! {self.},543			Mutability::Pure => quote! {Self::},544		};545		let args = self.args.iter().map(|a| a.expand_call_arg());546547		quote! {548			InternalCall::#pascal_name #matcher => {549				let result = #receiver #name(550					#(551						#args,552					)*553				)?;554				(&result).abi_write(&mut writer);555			}556		}557	}558559	fn expand_solidity_function(&self) -> proc_macro2::TokenStream {560		let camel_name = &self.camel_name;561		let mutability = match self.mutability {562			Mutability::Mutable => quote! {SolidityMutability::Mutable},563			Mutability::View => quote! { SolidityMutability::View },564			Mutability::Pure => quote! {SolidityMutability::Pure},565		};566		let result = &self.result;567568		let args = self569			.args570			.iter()571			.filter(|a| !a.is_special())572			.map(MethodArg::expand_solidity_argument);573		let selector = format!("{} {:0>8x}", self.selector_str, self.selector);574575		quote! {576			SolidityFunction {577				selector: #selector,578				name: #camel_name,579				mutability: #mutability,580				args: (581					#(582						#args,583					)*584				),585				result: <UnnamedArgument<#result>>::default(),586			}587		}588	}589}590591pub struct SolidityInterface {592	generics: Generics,593	name: Box<syn::Type>,594	info: InterfaceInfo,595	methods: Vec<Method>,596}597impl SolidityInterface {598	pub fn try_from(info: InterfaceInfo, value: &ItemImpl) -> syn::Result<Self> {599		let mut methods = Vec::new();600601		for item in &value.items {602			if let ImplItem::Method(method) = item {603				methods.push(Method::try_from(method)?)604			}605		}606		Ok(Self {607			generics: value.generics.clone(),608			name: value.self_ty.clone(),609			info,610			methods,611		})612	}613	pub fn expand(self) -> proc_macro2::TokenStream {614		let name = self.name;615616		let solidity_name = self.info.name.to_string();617		let call_name = pascal_ident_to_call(&self.info.name);618		let generics = self.generics;619620		let call_sub = self621			.info622			.inline_is623			.0624			.iter()625			.chain(self.info.is.0.iter())626			.map(Is::expand_call_def);627		let call_parse = self628			.info629			.inline_is630			.0631			.iter()632			.chain(self.info.is.0.iter())633			.map(Is::expand_parse);634		let call_variants = self635			.info636			.inline_is637			.0638			.iter()639			.chain(self.info.is.0.iter())640			.map(Is::expand_variant_call);641642		let inline_interface_id = self.info.inline_is.0.iter().map(Is::expand_interface_id);643		let supports_interface = self.info.is.0.iter().map(Is::expand_supports_interface);644645		let calls = self.methods.iter().map(Method::expand_call_def);646		let consts = self.methods.iter().map(Method::expand_const);647		let interface_id = self.methods.iter().map(Method::expand_interface_id);648		let parsers = self.methods.iter().map(Method::expand_parse);649		let call_variants_this = self.methods.iter().map(Method::expand_variant_call);650		let solidity_functions = self.methods.iter().map(Method::expand_solidity_function);651652		// TODO: Inline inline_is653		let solidity_is = self654			.info655			.is656			.0657			.iter()658			.chain(self.info.inline_is.0.iter())659			.map(|is| is.name.to_string());660		let solidity_events_is = self.info.events.0.iter().map(|is| is.name.to_string());661		let solidity_generators = self662			.info663			.is664			.0665			.iter()666			.chain(self.info.inline_is.0.iter())667			.map(Is::expand_generator);668		let solidity_event_generators = self.info.events.0.iter().map(Is::expand_event_generator);669670		// let methods = self.methods.iter().map(Method::solidity_def);671672		quote! {673			#[derive(Debug)]674			pub enum #call_name {675				ERC165Call(::evm_coder::ERC165Call),676				#(677					#calls,678				)*679				#(680					#call_sub,681				)*682			}683			impl #call_name {684				#(685					#consts686				)*687				pub const fn interface_id() -> u32 {688					let mut interface_id = 0;689					#(#interface_id)*690					#(#inline_interface_id)*691					interface_id692				}693				pub fn supports_interface(interface_id: u32) -> bool {694					interface_id != 0xffffff && (695						interface_id == ::evm_coder::ERC165Call::INTERFACE_ID ||696						interface_id == Self::interface_id()697						#(698							|| #supports_interface699						)*700					)701				}702				pub fn generate_solidity_interface(tc: &evm_coder::solidity::TypeCollector, is_impl: bool) {703					use evm_coder::solidity::*;704					use core::fmt::Write;705					let interface = SolidityInterface {706						name: #solidity_name,707						is: &["Dummy", "ERC165", #(708							#solidity_is,709						)* #(710							#solidity_events_is,711						)* ],712						functions: (#(713							#solidity_functions,714						)*),715					};716					if is_impl {717						tc.collect("// Common stubs holder\ncontract Dummy {\n\tuint8 dummy;\n\tstring stub_error = \"this contract is implemented in native\";\n}\ninterface ERC165 {\n\tfunction supportsInterface(bytes4 interfaceID) external view returns (bool) {\n\t\trequire(false, stub_error);\n\t\tinterfaceID;\n\t\treturn true;\n\t}\n}\n".into());718					} else {719						tc.collect("// Common stubs holder\ninterface Dummy {\n}\ninterface ERC165 {\n\tfunction supportsInterface(bytes4 interfaceID) external view returns (bool);\n}\n".into());720					}721					#(722						#solidity_generators723					)*724					#(725						#solidity_event_generators726					)*727728					let mut out = string::new();729					// In solidity interface usage (is) should be preceeded by interface definition730					// This comment helps to sort it in a set731					if #solidity_name.starts_with("Inline") {732						out.push_str("// Inline\n");733					}734					let _ = interface.format(is_impl, &mut out, tc);735					tc.collect(out);736				}737			}738			impl ::evm_coder::Call for #call_name {739				fn parse(method_id: u32, reader: &mut ::evm_coder::abi::AbiReader) -> ::evm_coder::execution::Result<Option<Self>> {740					use ::evm_coder::abi::AbiRead;741					match method_id {742						::evm_coder::ERC165Call::INTERFACE_ID => return Ok(::evm_coder::ERC165Call::parse(method_id, reader)?.map(Self::ERC165Call)),743						#(744							#parsers,745						)*746						_ => {},747					}748					#(749						#call_parse750					)else*751					return Ok(None);752				}753			}754			impl #generics ::evm_coder::Callable<#call_name> for #name {755				#[allow(unreachable_code)] // In case of no inner calls756				fn call(&mut self, c: Msg<#call_name>) -> Result<::evm_coder::abi::AbiWriter> {757					use ::evm_coder::abi::AbiWrite;758					type InternalCall = #call_name;759					match c.call {760						#(761							#call_variants,762						)*763						InternalCall::ERC165Call(::evm_coder::ERC165Call::SupportsInterface {interface_id}) => {764							let mut writer = ::evm_coder::abi::AbiWriter::default();765							writer.bool(&InternalCall::supports_interface(interface_id));766							return Ok(writer);767						}768						_ => {},769					}770					let mut writer = ::evm_coder::abi::AbiWriter::default();771					match c.call {772						#(773							#call_variants_this,774						)*775						_ => unreachable!()776					}777					Ok(writer)778				}779			}780		}781	}782}
after · crates/evm-coder-macros/src/solidity_interface.rs
1#![allow(dead_code)]23use quote::quote;4use darling::{FromMeta, ToTokens};5use inflector::cases;6use std::fmt::Write;7use syn::{8	Expr, FnArg, GenericArgument, Generics, Ident, ImplItem, ImplItemMethod, ItemImpl, Lit, Meta,9	NestedMeta, PatType, Path, PathArguments, ReturnType, Type, spanned::Spanned,10};1112use crate::{13	fn_selector_str, parse_ident_from_pat, parse_ident_from_path, parse_path, parse_path_segment,14	parse_result_ok, pascal_ident_to_call, pascal_ident_to_snake_call, snake_ident_to_pascal,15	snake_ident_to_screaming,16};1718struct Is {19	name: Ident,20	pascal_call_name: Ident,21	snake_call_name: Ident,22}23impl Is {24	fn try_from(path: &Path) -> syn::Result<Self> {25		let name = parse_ident_from_path(path, false)?.clone();26		Ok(Self {27			pascal_call_name: pascal_ident_to_call(&name),28			snake_call_name: pascal_ident_to_snake_call(&name),29			name,30		})31	}3233	fn expand_call_def(&self) -> proc_macro2::TokenStream {34		let name = &self.name;35		let pascal_call_name = &self.pascal_call_name;36		quote! {37			#name(#pascal_call_name)38		}39	}4041	fn expand_interface_id(&self) -> proc_macro2::TokenStream {42		let pascal_call_name = &self.pascal_call_name;43		quote! {44			interface_id ^= #pascal_call_name::interface_id();45		}46	}4748	fn expand_supports_interface(&self) -> proc_macro2::TokenStream {49		let pascal_call_name = &self.pascal_call_name;50		quote! {51			#pascal_call_name::supports_interface(interface_id)52		}53	}5455	fn expand_variant_call(&self) -> proc_macro2::TokenStream {56		let name = &self.name;57		let pascal_call_name = &self.pascal_call_name;58		quote! {59			InternalCall::#name(call) => return <Self as ::evm_coder::Callable<#pascal_call_name>>::call(self, Msg {60				call,61				caller: c.caller,62				value: c.value,63			})64		}65	}6667	fn expand_parse(&self) -> proc_macro2::TokenStream {68		let name = &self.name;69		let pascal_call_name = &self.pascal_call_name;70		quote! {71			if let Some(parsed_call) = #pascal_call_name::parse(method_id, reader)? {72				return Ok(Some(Self::#name(parsed_call)))73			}74		}75	}7677	fn expand_generator(&self) -> proc_macro2::TokenStream {78		let pascal_call_name = &self.pascal_call_name;79		quote! {80			#pascal_call_name::generate_solidity_interface(tc, is_impl);81		}82	}8384	fn expand_event_generator(&self) -> proc_macro2::TokenStream {85		let name = &self.name;86		quote! {87			#name::generate_solidity_interface(tc, is_impl);88		}89	}90}9192#[derive(Default)]93struct IsList(Vec<Is>);94impl FromMeta for IsList {95	fn from_list(items: &[NestedMeta]) -> darling::Result<Self> {96		let mut out = Vec::new();97		for item in items {98			match item {99				NestedMeta::Meta(Meta::Path(path)) => out.push(Is::try_from(path)?),100				_ => return Err(syn::Error::new(item.span(), "expected path").into()),101			}102		}103		Ok(Self(out))104	}105}106107#[derive(FromMeta)]108pub struct InterfaceInfo {109	name: Ident,110	#[darling(default)]111	is: IsList,112	#[darling(default)]113	inline_is: IsList,114	#[darling(default)]115	events: IsList,116}117118#[derive(FromMeta)]119struct MethodInfo {120	#[darling(default)]121	rename_selector: Option<String>,122}123124enum AbiType {125	// type126	Plain(Ident),127	// (type1,type2)128	Tuple(Vec<AbiType>),129	// type[]130	Vec(Box<AbiType>),131	// type[20]132	Array(Box<AbiType>, usize),133}134impl AbiType {135	fn try_from(value: &Type) -> syn::Result<Self> {136		let value = Self::try_maybe_special_from(value)?;137		if value.is_special() {138			return Err(syn::Error::new(value.span(), "unexpected special type"));139		}140		Ok(value)141	}142	fn try_maybe_special_from(value: &Type) -> syn::Result<Self> {143		match value {144			Type::Array(arr) => {145				let wrapped = AbiType::try_from(&arr.elem)?;146				match &arr.len {147					Expr::Lit(l) => match &l.lit {148						Lit::Int(i) => {149							let num = i.base10_parse::<usize>()?;150							Ok(AbiType::Array(Box::new(wrapped), num as usize))151						}152						_ => Err(syn::Error::new(arr.len.span(), "should be int literal")),153					},154					_ => Err(syn::Error::new(arr.len.span(), "should be literal")),155				}156			}157			Type::Path(_) => {158				let path = parse_path(value)?;159				let segment = parse_path_segment(path)?;160				if segment.ident == "Vec" {161					let args = match &segment.arguments {162						PathArguments::AngleBracketed(e) => e,163						_ => {164							return Err(syn::Error::new(165								segment.arguments.span(),166								"missing Vec generic",167							))168						}169					};170					let args = &args.args;171					if args.len() != 1 {172						return Err(syn::Error::new(173							args.span(),174							"expected only one generic for vec",175						));176					}177					let arg = args.first().unwrap();178179					let ty = match arg {180						GenericArgument::Type(ty) => ty,181						_ => {182							return Err(syn::Error::new(183								arg.span(),184								"expected first generic to be type",185							))186						}187					};188189					let wrapped = AbiType::try_from(ty)?;190					Ok(Self::Vec(Box::new(wrapped)))191				} else {192					if !segment.arguments.is_empty() {193						return Err(syn::Error::new(194							segment.arguments.span(),195							"unexpected generic arguments for non-vec type",196						));197					}198					Ok(Self::Plain(segment.ident.clone()))199				}200			}201			Type::Tuple(t) => {202				let mut out = Vec::with_capacity(t.elems.len());203				for el in t.elems.iter() {204					out.push(AbiType::try_from(el)?)205				}206				Ok(Self::Tuple(out))207			}208			_ => Err(syn::Error::new(209				value.span(),210				"unexpected type, only arrays, plain types and tuples are supported",211			)),212		}213	}214	fn is_value(&self) -> bool {215		match self {216			Self::Plain(v) if v == "value" => true,217			_ => false,218		}219	}220	fn is_caller(&self) -> bool {221		match self {222			Self::Plain(v) if v == "caller" => true,223			_ => false,224		}225	}226	fn is_special(&self) -> bool {227		self.is_caller() || self.is_value()228	}229	fn selector_ty_buf(&self, buf: &mut String) -> std::fmt::Result {230		match self {231			AbiType::Plain(t) => {232				write!(buf, "{}", t)233			}234			AbiType::Tuple(t) => {235				write!(buf, "(")?;236				for (i, t) in t.iter().enumerate() {237					if i != 0 {238						write!(buf, ",")?;239					}240					t.selector_ty_buf(buf)?;241				}242				write!(buf, ")")243			}244			AbiType::Vec(v) => {245				v.selector_ty_buf(buf)?;246				write!(buf, "[]")247			}248			AbiType::Array(v, len) => {249				v.selector_ty_buf(buf)?;250				write!(buf, "[{}]", len)251			}252		}253	}254	fn selector_ty(&self) -> String {255		let mut out = String::new();256		self.selector_ty_buf(&mut out).expect("no fmt error");257		out258	}259}260impl ToTokens for AbiType {261	fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) {262		match self {263			AbiType::Plain(t) => tokens.extend(quote! {#t}),264			AbiType::Tuple(t) => {265				tokens.extend(quote! {(266					#(#t),*267				)});268			}269			AbiType::Vec(v) => tokens.extend(quote! {Vec<#v>}),270			AbiType::Array(v, l) => tokens.extend(quote! {[#v; #l]}),271		}272	}273}274275struct MethodArg {276	name: Ident,277	camel_name: String,278	ty: AbiType,279}280impl MethodArg {281	fn try_from(value: &PatType) -> syn::Result<Self> {282		let name = parse_ident_from_pat(&value.pat)?.clone();283		Ok(Self {284			camel_name: cases::camelcase::to_camel_case(&name.to_string()),285			name,286			ty: AbiType::try_maybe_special_from(&value.ty)?,287		})288	}289	fn is_value(&self) -> bool {290		self.ty.is_value()291	}292	fn is_caller(&self) -> bool {293		self.ty.is_caller()294	}295	fn is_special(&self) -> bool {296		self.ty.is_special()297	}298	fn selector_ty(&self) -> String {299		assert!(!self.is_special());300		self.ty.selector_ty()301	}302303	fn expand_call_def(&self) -> proc_macro2::TokenStream {304		assert!(!self.is_special());305		let name = &self.name;306		let ty = &self.ty;307308		quote! {309			#name: #ty310		}311	}312313	fn expand_parse(&self) -> proc_macro2::TokenStream {314		assert!(!self.is_special());315		let name = &self.name;316		quote! {317			#name: reader.abi_read()?318		}319	}320321	fn expand_call_arg(&self) -> proc_macro2::TokenStream {322		if self.is_value() {323			quote! {324				c.value.clone()325			}326		} else if self.is_caller() {327			quote! {328				c.caller.clone()329			}330		} else {331			let name = &self.name;332			quote! {333				#name334			}335		}336	}337338	fn expand_solidity_argument(&self) -> proc_macro2::TokenStream {339		let camel_name = &self.camel_name.to_string();340		let ty = &self.ty;341		quote! {342			<NamedArgument<#ty>>::new(#camel_name)343		}344	}345}346347#[derive(PartialEq)]348enum Mutability {349	Mutable,350	View,351	Pure,352}353354struct Method {355	name: Ident,356	camel_name: String,357	pascal_name: Ident,358	screaming_name: Ident,359	selector_str: String,360	selector: u32,361	args: Vec<MethodArg>,362	has_normal_args: bool,363	mutability: Mutability,364	result: Type,365}366impl Method {367	fn try_from(value: &ImplItemMethod) -> syn::Result<Self> {368		let mut info = MethodInfo {369			rename_selector: None,370		};371		for attr in &value.attrs {372			let ident = parse_ident_from_path(&attr.path, false)?;373			if ident == "solidity" {374				let args = attr.parse_meta().unwrap();375				info = MethodInfo::from_meta(&args).unwrap();376			} else if ident == "doc" {377				// TODO: Add docs to evm interfaces378			}379		}380		let ident = &value.sig.ident;381		let ident_str = ident.to_string();382		if !cases::snakecase::is_snake_case(&ident_str) {383			return Err(syn::Error::new(ident.span(), "method name should be snake_cased\nif alternative solidity name needs to be set - use #[solidity] attribute"));384		}385386		let mut mutability = Mutability::Pure;387388		if let Some(FnArg::Receiver(receiver)) = value389			.sig390			.inputs391			.iter()392			.find(|arg| matches!(arg, FnArg::Receiver(_)))393		{394			if receiver.reference.is_none() {395				return Err(syn::Error::new(396					receiver.span(),397					"receiver should be by ref",398				));399			}400			if receiver.mutability.is_some() {401				mutability = Mutability::Mutable;402			} else {403				mutability = Mutability::View;404			}405		}406		let mut args = Vec::new();407		for typ in value408			.sig409			.inputs410			.iter()411			.filter(|arg| matches!(arg, FnArg::Typed(_)))412		{413			let typ = match typ {414				FnArg::Typed(typ) => typ,415				_ => unreachable!(),416			};417			args.push(MethodArg::try_from(typ)?);418		}419420		if mutability != Mutability::Mutable && args.iter().any(|arg| arg.is_value()) {421			return Err(syn::Error::new(422				args.iter().find(|arg| arg.is_value()).unwrap().ty.span(),423				"payable function should be mutable",424			));425		}426427		let result = match &value.sig.output {428			ReturnType::Type(_, ty) => ty,429			_ => return Err(syn::Error::new(value.sig.output.span(), "interface method should return Result<value>\nif there is no value to return - specify void (which is alias to unit)")),430		};431		let result = parse_result_ok(result)?;432433		let camel_name = info434			.rename_selector435			.unwrap_or_else(|| cases::camelcase::to_camel_case(&ident.to_string()));436		let mut selector_str = camel_name.clone();437		selector_str.push('(');438		let mut has_normal_args = false;439		for (i, arg) in args.iter().filter(|arg| !arg.is_special()).enumerate() {440			if i != 0 {441				selector_str.push(',');442			}443			write!(selector_str, "{}", arg.selector_ty()).unwrap();444			has_normal_args = true;445		}446		selector_str.push(')');447		let selector = fn_selector_str(&selector_str);448449		Ok(Self {450			name: ident.clone(),451			camel_name,452			pascal_name: snake_ident_to_pascal(ident),453			screaming_name: snake_ident_to_screaming(ident),454			selector_str,455			selector,456			args,457			has_normal_args,458			mutability,459			result: result.clone(),460		})461	}462	fn expand_call_def(&self) -> proc_macro2::TokenStream {463		let defs = self464			.args465			.iter()466			.filter(|a| !a.is_special())467			.map(|a| a.expand_call_def());468		let pascal_name = &self.pascal_name;469470		if self.has_normal_args {471			quote! {472				#pascal_name {473					#(474						#defs,475					)*476				}477			}478		} else {479			quote! {#pascal_name}480		}481	}482483	fn expand_const(&self) -> proc_macro2::TokenStream {484		let screaming_name = &self.screaming_name;485		let selector = self.selector;486		let selector_str = &self.selector_str;487		quote! {488			#[doc = #selector_str]489			const #screaming_name: u32 = #selector;490		}491	}492493	fn expand_interface_id(&self) -> proc_macro2::TokenStream {494		let screaming_name = &self.screaming_name;495		quote! {496			interface_id ^= Self::#screaming_name;497		}498	}499500	fn expand_parse(&self) -> proc_macro2::TokenStream {501		let pascal_name = &self.pascal_name;502		let screaming_name = &self.screaming_name;503		if self.has_normal_args {504			let parsers = self505				.args506				.iter()507				.filter(|a| !a.is_special())508				.map(|a| a.expand_parse());509			quote! {510				Self::#screaming_name => return Ok(Some(Self::#pascal_name {511					#(512						#parsers,513					)*514				}))515			}516		} else {517			quote! { Self::#screaming_name => return Ok(Some(Self::#pascal_name)) }518		}519	}520521	fn expand_variant_call(&self) -> proc_macro2::TokenStream {522		let pascal_name = &self.pascal_name;523		let name = &self.name;524525		let matcher = if self.has_normal_args {526			let names = self527				.args528				.iter()529				.filter(|a| !a.is_special())530				.map(|a| &a.name);531532			quote! {{533				#(534					#names,535				)*536			}}537		} else {538			quote! {}539		};540541		let receiver = match self.mutability {542			Mutability::Mutable | Mutability::View => quote! {self.},543			Mutability::Pure => quote! {Self::},544		};545		let args = self.args.iter().map(|a| a.expand_call_arg());546547		quote! {548			InternalCall::#pascal_name #matcher => {549				let result = #receiver #name(550					#(551						#args,552					)*553				)?;554				(&result).abi_write(&mut writer);555			}556		}557	}558559	fn expand_solidity_function(&self) -> proc_macro2::TokenStream {560		let camel_name = &self.camel_name;561		let mutability = match self.mutability {562			Mutability::Mutable => quote! {SolidityMutability::Mutable},563			Mutability::View => quote! { SolidityMutability::View },564			Mutability::Pure => quote! {SolidityMutability::Pure},565		};566		let result = &self.result;567568		let args = self569			.args570			.iter()571			.filter(|a| !a.is_special())572			.map(MethodArg::expand_solidity_argument);573		let selector = format!("{} {:0>8x}", self.selector_str, self.selector);574575		quote! {576			SolidityFunction {577				selector: #selector,578				name: #camel_name,579				mutability: #mutability,580				args: (581					#(582						#args,583					)*584				),585				result: <UnnamedArgument<#result>>::default(),586			}587		}588	}589}590591pub struct SolidityInterface {592	generics: Generics,593	name: Box<syn::Type>,594	info: InterfaceInfo,595	methods: Vec<Method>,596}597impl SolidityInterface {598	pub fn try_from(info: InterfaceInfo, value: &ItemImpl) -> syn::Result<Self> {599		let mut methods = Vec::new();600601		for item in &value.items {602			if let ImplItem::Method(method) = item {603				methods.push(Method::try_from(method)?)604			}605		}606		Ok(Self {607			generics: value.generics.clone(),608			name: value.self_ty.clone(),609			info,610			methods,611		})612	}613	pub fn expand(self) -> proc_macro2::TokenStream {614		let name = self.name;615616		let solidity_name = self.info.name.to_string();617		let call_name = pascal_ident_to_call(&self.info.name);618		let generics = self.generics;619620		let call_sub = self621			.info622			.inline_is623			.0624			.iter()625			.chain(self.info.is.0.iter())626			.map(Is::expand_call_def);627		let call_parse = self628			.info629			.inline_is630			.0631			.iter()632			.chain(self.info.is.0.iter())633			.map(Is::expand_parse);634		let call_variants = self635			.info636			.inline_is637			.0638			.iter()639			.chain(self.info.is.0.iter())640			.map(Is::expand_variant_call);641642		let inline_interface_id = self.info.inline_is.0.iter().map(Is::expand_interface_id);643		let supports_interface = self.info.is.0.iter().map(Is::expand_supports_interface);644645		let calls = self.methods.iter().map(Method::expand_call_def);646		let consts = self.methods.iter().map(Method::expand_const);647		let interface_id = self.methods.iter().map(Method::expand_interface_id);648		let parsers = self.methods.iter().map(Method::expand_parse);649		let call_variants_this = self.methods.iter().map(Method::expand_variant_call);650		let solidity_functions = self.methods.iter().map(Method::expand_solidity_function);651652		// TODO: Inline inline_is653		let solidity_is = self654			.info655			.is656			.0657			.iter()658			.chain(self.info.inline_is.0.iter())659			.map(|is| is.name.to_string());660		let solidity_events_is = self.info.events.0.iter().map(|is| is.name.to_string());661		let solidity_generators = self662			.info663			.is664			.0665			.iter()666			.chain(self.info.inline_is.0.iter())667			.map(Is::expand_generator);668		let solidity_event_generators = self.info.events.0.iter().map(Is::expand_event_generator);669670		// let methods = self.methods.iter().map(Method::solidity_def);671672		quote! {673			#[derive(Debug)]674			pub enum #call_name {675				ERC165Call(::evm_coder::ERC165Call),676				#(677					#calls,678				)*679				#(680					#call_sub,681				)*682			}683			impl #call_name {684				#(685					#consts686				)*687				pub const fn interface_id() -> u32 {688					let mut interface_id = 0;689					#(#interface_id)*690					#(#inline_interface_id)*691					interface_id692				}693				pub fn supports_interface(interface_id: u32) -> bool {694					interface_id != 0xffffff && (695						interface_id == ::evm_coder::ERC165Call::INTERFACE_ID ||696						interface_id == Self::interface_id()697						#(698							|| #supports_interface699						)*700					)701				}702				pub fn generate_solidity_interface(tc: &evm_coder::solidity::TypeCollector, is_impl: bool) {703					use evm_coder::solidity::*;704					use core::fmt::Write;705					let interface = SolidityInterface {706						name: #solidity_name,707						is: &["Dummy", "ERC165", #(708							#solidity_is,709						)* #(710							#solidity_events_is,711						)* ],712						functions: (#(713							#solidity_functions,714						)*),715					};716					if is_impl {717						tc.collect("// Common stubs holder\ncontract Dummy {\n\tuint8 dummy;\n\tstring stub_error = \"this contract is implemented in native\";\n}\ncontract ERC165 is Dummy {\n\tfunction supportsInterface(bytes4 interfaceID) external view returns (bool) {\n\t\trequire(false, stub_error);\n\t\tinterfaceID;\n\t\treturn true;\n\t}\n}\n".into());718					} else {719						tc.collect("// Common stubs holder\ninterface Dummy {\n}\ninterface ERC165 is Dummy {\n\tfunction supportsInterface(bytes4 interfaceID) external view returns (bool);\n}\n".into());720					}721					#(722						#solidity_generators723					)*724					#(725						#solidity_event_generators726					)*727728					let mut out = string::new();729					// In solidity interface usage (is) should be preceeded by interface definition730					// This comment helps to sort it in a set731					if #solidity_name.starts_with("Inline") {732						out.push_str("// Inline\n");733					}734					let _ = interface.format(is_impl, &mut out, tc);735					tc.collect(out);736				}737			}738			impl ::evm_coder::Call for #call_name {739				fn parse(method_id: u32, reader: &mut ::evm_coder::abi::AbiReader) -> ::evm_coder::execution::Result<Option<Self>> {740					use ::evm_coder::abi::AbiRead;741					match method_id {742						::evm_coder::ERC165Call::INTERFACE_ID => return Ok(::evm_coder::ERC165Call::parse(method_id, reader)?.map(Self::ERC165Call)),743						#(744							#parsers,745						)*746						_ => {},747					}748					#(749						#call_parse750					)else*751					return Ok(None);752				}753			}754			impl #generics ::evm_coder::Callable<#call_name> for #name {755				#[allow(unreachable_code)] // In case of no inner calls756				fn call(&mut self, c: Msg<#call_name>) -> Result<::evm_coder::abi::AbiWriter> {757					use ::evm_coder::abi::AbiWrite;758					type InternalCall = #call_name;759					match c.call {760						#(761							#call_variants,762						)*763						InternalCall::ERC165Call(::evm_coder::ERC165Call::SupportsInterface {interface_id}) => {764							let mut writer = ::evm_coder::abi::AbiWriter::default();765							writer.bool(&InternalCall::supports_interface(interface_id));766							return Ok(writer);767						}768						_ => {},769					}770					let mut writer = ::evm_coder::abi::AbiWriter::default();771					match c.call {772						#(773							#call_variants_this,774						)*775						_ => unreachable!()776					}777					Ok(writer)778				}779			}780		}781	}782}
modifiedpallets/evm-contract-helpers/src/stubs/ContractHelpers.rawdiffbeforeafterboth

binary blob — no preview

modifiedpallets/evm-contract-helpers/src/stubs/ContractHelpers.soldiffbeforeafterboth
--- a/pallets/evm-contract-helpers/src/stubs/ContractHelpers.sol
+++ b/pallets/evm-contract-helpers/src/stubs/ContractHelpers.sol
@@ -9,7 +9,19 @@
 	string stub_error = "this contract is implemented in native";
 }
 
-contract ContractHelpers is Dummy {
+contract ERC165 is Dummy {
+	function supportsInterface(bytes4 interfaceID)
+		external
+		view
+		returns (bool)
+	{
+		require(false, stub_error);
+		interfaceID;
+		return true;
+	}
+}
+
+contract ContractHelpers is Dummy, ERC165 {
 	// Selector: contractOwner(address) 5152b14c
 	function contractOwner(address contractAddress)
 		public
modifiedpallets/fungible/Cargo.tomldiffbeforeafterboth
--- a/pallets/fungible/Cargo.toml
+++ b/pallets/fungible/Cargo.toml
@@ -18,8 +18,8 @@
 pallet-common = { default-features = false, path = '../common' }
 nft-data-structs = { default-features = false, path = '../../primitives/nft' }
 evm-coder = { default-features = false, path = '../../crates/evm-coder' }
+pallet-evm-coder-substrate = { default-features = false, path = '../evm-coder-substrate' }
 ethereum = { git = "https://github.com/purestake/ethereum", branch = "joshy-scale-info", default-features = false }
-pallet-evm-coder-substrate = { default-features = false, path = '../evm-coder-substrate' }
 frame-benchmarking = { default-features = false, optional = true, git = 'https://github.com/paritytech/substrate.git', branch = 'polkadot-v0.9.12' }
 scale-info = { version = "1.0.0", default-features = false, features = [
     "derive",
@@ -36,6 +36,7 @@
     "pallet-common/std",
     "evm-coder/std",
     "ethereum/std",
+    "pallet-evm-coder-substrate/std",
     'frame-benchmarking/std',
 ]
 runtime-benchmarks = ['frame-benchmarking', 'pallet-common/runtime-benchmarks']
modifiedpallets/fungible/src/erc.rsdiffbeforeafterboth
--- a/pallets/fungible/src/erc.rs
+++ b/pallets/fungible/src/erc.rs
@@ -111,7 +111,7 @@
 #[solidity_interface(name = "UniqueFungible", is(ERC20))]
 impl<T: Config> FungibleHandle<T> {}
 
-generate_stubgen!(get_impl, UniqueFungibleCall, true);
+generate_stubgen!(gen_impl, UniqueFungibleCall, true);
 generate_stubgen!(gen_iface, UniqueFungibleCall, false);
 
 impl<T: Config> CommonEvmHandler for FungibleHandle<T> {
modifiedpallets/fungible/src/stubs/UniqueFungible.rawdiffbeforeafterboth

binary blob — no preview

modifiedpallets/fungible/src/stubs/UniqueFungible.soldiffbeforeafterboth
--- a/pallets/fungible/src/stubs/UniqueFungible.sol
+++ b/pallets/fungible/src/stubs/UniqueFungible.sol
@@ -9,6 +9,18 @@
 	string stub_error = "this contract is implemented in native";
 }
 
+contract ERC165 is Dummy {
+	function supportsInterface(bytes4 interfaceID)
+		external
+		view
+		returns (bool)
+	{
+		require(false, stub_error);
+		interfaceID;
+		return true;
+	}
+}
+
 // Inline
 contract ERC20Events {
 	event Transfer(address indexed from, address indexed to, uint256 value);
@@ -19,8 +31,7 @@
 	);
 }
 
-// Inline
-contract InlineNameSymbol is Dummy {
+contract ERC20 is Dummy, ERC165, ERC20Events {
 	// Selector: name() 06fdde03
 	function name() public view returns (string memory) {
 		require(false, stub_error);
@@ -34,29 +45,14 @@
 		dummy;
 		return "";
 	}
-}
 
-// Inline
-contract InlineTotalSupply is Dummy {
 	// Selector: totalSupply() 18160ddd
 	function totalSupply() public view returns (uint256) {
 		require(false, stub_error);
 		dummy;
 		return 0;
 	}
-}
 
-contract ERC165 is Dummy {
-	// Selector: supportsInterface(bytes4) 01ffc9a7
-	function supportsInterface(uint32 interfaceId) public view returns (bool) {
-		require(false, stub_error);
-		interfaceId;
-		dummy;
-		return false;
-	}
-}
-
-contract ERC20 is Dummy, InlineNameSymbol, InlineTotalSupply, ERC20Events {
 	// Selector: decimals() 313ce567
 	function decimals() public view returns (uint8) {
 		require(false, stub_error);
modifiedpallets/nonfungible/src/stubs/UniqueNFT.rawdiffbeforeafterboth

binary blob — no preview

modifiedpallets/nonfungible/src/stubs/UniqueNFT.soldiffbeforeafterboth
--- a/pallets/nonfungible/src/stubs/UniqueNFT.sol
+++ b/pallets/nonfungible/src/stubs/UniqueNFT.sol
@@ -15,6 +15,18 @@
 	string stub_error = "this contract is implemented in native";
 }
 
+contract ERC165 is Dummy {
+	function supportsInterface(bytes4 interfaceID)
+		external
+		view
+		returns (bool)
+	{
+		require(false, stub_error);
+		interfaceID;
+		return true;
+	}
+}
+
 // Inline
 contract ERC721Events {
 	event Transfer(
@@ -37,43 +49,6 @@
 // Inline
 contract ERC721MintableEvents {
 	event MintingFinished();
-}
-
-// Inline
-contract InlineNameSymbol is Dummy {
-	// Selector: name() 06fdde03
-	function name() public view returns (string memory) {
-		require(false, stub_error);
-		dummy;
-		return "";
-	}
-
-	// Selector: symbol() 95d89b41
-	function symbol() public view returns (string memory) {
-		require(false, stub_error);
-		dummy;
-		return "";
-	}
-}
-
-// Inline
-contract InlineTotalSupply is Dummy {
-	// Selector: totalSupply() 18160ddd
-	function totalSupply() public view returns (uint256) {
-		require(false, stub_error);
-		dummy;
-		return 0;
-	}
-}
-
-contract ERC165 is Dummy {
-	// Selector: supportsInterface(bytes4) 01ffc9a7
-	function supportsInterface(uint32 interfaceId) public view returns (bool) {
-		require(false, stub_error);
-		interfaceId;
-		dummy;
-		return false;
-	}
 }
 
 contract ERC721 is Dummy, ERC165, ERC721Events {
@@ -172,7 +147,7 @@
 	}
 }
 
-contract ERC721Burnable is Dummy {
+contract ERC721Burnable is Dummy, ERC165 {
 	// Selector: burn(uint256) 42966c68
 	function burn(uint256 tokenId) public {
 		require(false, stub_error);
@@ -181,7 +156,7 @@
 	}
 }
 
-contract ERC721Enumerable is Dummy, InlineTotalSupply {
+contract ERC721Enumerable is Dummy, ERC165 {
 	// Selector: tokenByIndex(uint256) 4f6ccce7
 	function tokenByIndex(uint256 index) public view returns (uint256) {
 		require(false, stub_error);
@@ -202,9 +177,30 @@
 		dummy;
 		return 0;
 	}
+
+	// Selector: totalSupply() 18160ddd
+	function totalSupply() public view returns (uint256) {
+		require(false, stub_error);
+		dummy;
+		return 0;
+	}
 }
 
-contract ERC721Metadata is Dummy, InlineNameSymbol {
+contract ERC721Metadata is Dummy, ERC165 {
+	// Selector: name() 06fdde03
+	function name() public view returns (string memory) {
+		require(false, stub_error);
+		dummy;
+		return "";
+	}
+
+	// Selector: symbol() 95d89b41
+	function symbol() public view returns (string memory) {
+		require(false, stub_error);
+		dummy;
+		return "";
+	}
+
 	// Selector: tokenURI(uint256) c87b56dd
 	function tokenURI(uint256 tokenId) public view returns (string memory) {
 		require(false, stub_error);
@@ -214,7 +210,7 @@
 	}
 }
 
-contract ERC721Mintable is Dummy, ERC721MintableEvents {
+contract ERC721Mintable is Dummy, ERC165, ERC721MintableEvents {
 	// Selector: mintingFinished() 05d2035b
 	function mintingFinished() public view returns (bool) {
 		require(false, stub_error);
@@ -253,7 +249,7 @@
 	}
 }
 
-contract ERC721UniqueExtensions is Dummy {
+contract ERC721UniqueExtensions is Dummy, ERC165 {
 	// Selector: transfer(address,uint256) a9059cbb
 	function transfer(address to, uint256 tokenId) public {
 		require(false, stub_error);
@@ -262,6 +258,14 @@
 		dummy = 0;
 	}
 
+	// Selector: burnFrom(address,uint256) 79cc6790
+	function burnFrom(address from, uint256 tokenId) public {
+		require(false, stub_error);
+		from;
+		tokenId;
+		dummy = 0;
+	}
+
 	// Selector: nextTokenId() 75794a3c
 	function nextTokenId() public view returns (uint256) {
 		require(false, stub_error);
modifiedtests/src/eth/api/ContractHelpers.soldiffbeforeafterboth
--- a/tests/src/eth/api/ContractHelpers.sol
+++ b/tests/src/eth/api/ContractHelpers.sol
@@ -8,7 +8,11 @@
 
 }
 
-interface ContractHelpers is Dummy {
+interface ERC165 is Dummy {
+	function supportsInterface(bytes4 interfaceID) external view returns (bool);
+}
+
+interface ContractHelpers is Dummy, ERC165 {
 	// Selector: contractOwner(address) 5152b14c
 	function contractOwner(address contractAddress)
 		external
modifiedtests/src/eth/api/UniqueFungible.soldiffbeforeafterboth
--- a/tests/src/eth/api/UniqueFungible.sol
+++ b/tests/src/eth/api/UniqueFungible.sol
@@ -8,6 +8,10 @@
 
 }
 
+interface ERC165 is Dummy {
+	function supportsInterface(bytes4 interfaceID) external view returns (bool);
+}
+
 // Inline
 interface ERC20Events {
 	event Transfer(address indexed from, address indexed to, uint256 value);
@@ -18,27 +22,16 @@
 	);
 }
 
-// Inline
-interface InlineNameSymbol is Dummy {
+interface ERC20 is Dummy, ERC165, ERC20Events {
 	// Selector: name() 06fdde03
 	function name() external view returns (string memory);
 
 	// Selector: symbol() 95d89b41
 	function symbol() external view returns (string memory);
-}
 
-// Inline
-interface InlineTotalSupply is Dummy {
 	// Selector: totalSupply() 18160ddd
 	function totalSupply() external view returns (uint256);
-}
-
-interface ERC165 is Dummy {
-	// Selector: supportsInterface(bytes4) 01ffc9a7
-	function supportsInterface(uint32 interfaceId) external view returns (bool);
-}
 
-interface ERC20 is Dummy, InlineNameSymbol, InlineTotalSupply, ERC20Events {
 	// Selector: decimals() 313ce567
 	function decimals() external view returns (uint8);
 
modifiedtests/src/eth/api/UniqueNFT.soldiffbeforeafterboth
--- a/tests/src/eth/api/UniqueNFT.sol
+++ b/tests/src/eth/api/UniqueNFT.sol
@@ -14,6 +14,10 @@
 
 }
 
+interface ERC165 is Dummy {
+	function supportsInterface(bytes4 interfaceID) external view returns (bool);
+}
+
 // Inline
 interface ERC721Events {
 	event Transfer(
@@ -36,26 +40,6 @@
 // Inline
 interface ERC721MintableEvents {
 	event MintingFinished();
-}
-
-// Inline
-interface InlineNameSymbol is Dummy {
-	// Selector: name() 06fdde03
-	function name() external view returns (string memory);
-
-	// Selector: symbol() 95d89b41
-	function symbol() external view returns (string memory);
-}
-
-// Inline
-interface InlineTotalSupply is Dummy {
-	// Selector: totalSupply() 18160ddd
-	function totalSupply() external view returns (uint256);
-}
-
-interface ERC165 is Dummy {
-	// Selector: supportsInterface(bytes4) 01ffc9a7
-	function supportsInterface(uint32 interfaceId) external view returns (bool);
 }
 
 interface ERC721 is Dummy, ERC165, ERC721Events {
@@ -103,12 +87,12 @@
 		returns (address);
 }
 
-interface ERC721Burnable is Dummy {
+interface ERC721Burnable is Dummy, ERC165 {
 	// Selector: burn(uint256) 42966c68
 	function burn(uint256 tokenId) external;
 }
 
-interface ERC721Enumerable is Dummy, InlineTotalSupply {
+interface ERC721Enumerable is Dummy, ERC165 {
 	// Selector: tokenByIndex(uint256) 4f6ccce7
 	function tokenByIndex(uint256 index) external view returns (uint256);
 
@@ -117,14 +101,23 @@
 		external
 		view
 		returns (uint256);
+
+	// Selector: totalSupply() 18160ddd
+	function totalSupply() external view returns (uint256);
 }
 
-interface ERC721Metadata is Dummy, InlineNameSymbol {
+interface ERC721Metadata is Dummy, ERC165 {
+	// Selector: name() 06fdde03
+	function name() external view returns (string memory);
+
+	// Selector: symbol() 95d89b41
+	function symbol() external view returns (string memory);
+
 	// Selector: tokenURI(uint256) c87b56dd
 	function tokenURI(uint256 tokenId) external view returns (string memory);
 }
 
-interface ERC721Mintable is Dummy, ERC721MintableEvents {
+interface ERC721Mintable is Dummy, ERC165, ERC721MintableEvents {
 	// Selector: mintingFinished() 05d2035b
 	function mintingFinished() external view returns (bool);
 
@@ -142,10 +135,13 @@
 	function finishMinting() external returns (bool);
 }
 
-interface ERC721UniqueExtensions is Dummy {
+interface ERC721UniqueExtensions is Dummy, ERC165 {
 	// Selector: transfer(address,uint256) a9059cbb
 	function transfer(address to, uint256 tokenId) external;
 
+	// Selector: burnFrom(address,uint256) 79cc6790
+	function burnFrom(address from, uint256 tokenId) external;
+
 	// Selector: nextTokenId() 75794a3c
 	function nextTokenId() external view returns (uint256);