git.delta.rocks / unique-network / refs/commits / 5a3fe2c70832

difftreelog

refactor unify function and type signature handling

Yaroslav Bolyukin2022-11-02parent: #4c1a924.patch.diff
in: master

12 files changed

modifiedcrates/evm-coder/procedural/src/solidity_interface.rsdiffbeforeafterboth
--- a/crates/evm-coder/procedural/src/solidity_interface.rs
+++ b/crates/evm-coder/procedural/src/solidity_interface.rs
@@ -24,8 +24,8 @@
 use quote::{quote, format_ident};
 use inflector::cases;
 use syn::{
-	Expr, FnArg, GenericArgument, Generics, Ident, ImplItem, ImplItemMethod, ItemImpl, Lit, Meta,
-	MetaNameValue, PatType, PathArguments, ReturnType, Type,
+	Expr, FnArg, Generics, Ident, ImplItem, ImplItemMethod, ItemImpl, Lit, Meta, MetaNameValue,
+	PatType, ReturnType, Type,
 	spanned::Spanned,
 	parse::{Parse, ParseStream},
 	parenthesized, Token, LitInt, LitStr,
@@ -601,12 +601,12 @@
 		let screaming_name_signature = format_ident!("{}_SIGNATURE", &self.screaming_name);
 		let custom_signature = self.expand_custom_signature();
 		quote! {
-			const #screaming_name_signature: ::evm_coder::custom_signature::FunctionSignature = #custom_signature;
+			const #screaming_name_signature: ::evm_coder::custom_signature::SignatureUnit = #custom_signature;
 			const #screaming_name: ::evm_coder::types::bytes4 = {
 				let mut sum = ::evm_coder::sha3_const::Keccak256::new();
 				let mut pos = 0;
-				while pos < Self::#screaming_name_signature.unit.len {
-					sum = sum.update(&[Self::#screaming_name_signature.unit.data[pos]; 1]);
+				while pos < Self::#screaming_name_signature.len {
+					sum = sum.update(&[Self::#screaming_name_signature.data[pos]; 1]);
 					pos += 1;
 				}
 				let a = sum.finalize();
@@ -710,192 +710,28 @@
 			};
 			quote! {
 				Self::#pascal_name #matcher => ().into()
-			}
-		}
-	}
-
-	fn expand_type(ty: &Type, token_stream: &mut proc_macro2::TokenStream, read_signature: bool) {
-		match ty {
-			Type::Path(tp) => {
-				if let Some(qself) = &tp.qself {
-					panic!("no receiver expected {:?}", qself.ty.span());
-				}
-				let path = &tp.path;
-				if path.segments.len() != 1 {
-					panic!("expected path to have only one segment {:?}", path.span());
-				}
-				let last_segment = path.segments.last().unwrap();
-
-				if last_segment.ident == "Vec" {
-					let args = match &last_segment.arguments {
-						PathArguments::AngleBracketed(e) => e,
-						_ => {
-							panic!("missing Vec generic {:?}", last_segment.arguments.span());
-						}
-					};
-					let args = &args.args;
-					if args.len() != 1 {
-						panic!("expected only one generic for vec {:?}", args.span());
-					}
-					let arg = args.first().expect("first arg");
-
-					let ty = match arg {
-						GenericArgument::Type(ty) => ty,
-						_ => {
-							panic!("expected first generic to be type {:?}", arg.span());
-						}
-					};
-
-					let mut vec_token = proc_macro2::TokenStream::new();
-					Self::expand_type(ty, &mut vec_token, false);
-					vec_token = if read_signature {
-						quote! { (<Vec<#vec_token>>::SIGNATURE) }
-					} else {
-						quote! { <Vec<#vec_token>> }
-					};
-					token_stream.extend(vec_token);
-				} else {
-					if !last_segment.arguments.is_empty() {
-						panic!(
-							"unexpected generic arguments for non-vec type {:?}",
-							last_segment.arguments.span()
-						);
-					}
-
-					let ident = &last_segment.ident;
-					let plain_token = if read_signature {
-						quote! {
-							(<#ident>::SIGNATURE)
-						}
-					} else {
-						quote! {
-							#ident
-						}
-					};
-
-					token_stream.extend(plain_token);
-				}
-			}
-
-			Type::Tuple(tt) => {
-				// for ty in tt.elems.iter() {
-				// 	out.push(AbiType::try_from(ty)?)
-				// }
-
-				let mut tuple_types = proc_macro2::TokenStream::new();
-				let mut is_first = true;
-
-				for ty in tt.elems.iter() {
-					if is_first {
-						is_first = false
-					} else {
-						tuple_types.extend(quote!(,));
-					}
-					Self::expand_type(ty, &mut tuple_types, false);
-				}
-				tuple_types = if read_signature {
-					quote! { (<(#tuple_types)>::SIGNATURE) }
-				} else {
-					quote! { (#tuple_types) }
-				};
-				token_stream.extend(tuple_types);
 			}
-
-			// Type::Array(arr) => {
-			// 	let wrapped = AbiType::try_from(&arr.elem)?;
-			// 	match &arr.len {
-			// 		Expr::Lit(l) => match &l.lit {
-			// 			Lit::Int(i) => {
-			// 				let num = i.base10_parse::<usize>()?;
-			// 				Ok(AbiType::Array(Box::new(wrapped), num as usize))
-			// 			}
-			// 			_ => Err(syn::Error::new(arr.len.span(), "should be int literal")),
-			// 		},
-			// 		_ => Err(syn::Error::new(arr.len.span(), "should be literal")),
-			// 	}
-			// }
-			_ => panic!("Unexpected type {ty:?}"),
 		}
-		// match ty {
-		// 	AbiType::Plain(ref ident) => {
-		// 		let plain_token = if read_signature {
-		// 			quote! {
-		// 				(<#ident>::SIGNATURE)
-		// 			}
-		// 		} else {
-		// 			quote! {
-		// 				#ident
-		// 			}
-		// 		};
-
-		// 		token_stream.extend(plain_token);
-		// 	}
-
-		// 	AbiType::Tuple(ref tuple_type) => {
-		// 		let mut tuple_types = proc_macro2::TokenStream::new();
-		// 		let mut is_first = true;
-
-		// 		for ty in tuple_type {
-		// 			if is_first {
-		// 				is_first = false
-		// 			} else {
-		// 				tuple_types.extend(quote!(,));
-		// 			}
-		// 			Self::expand_type(ty, &mut tuple_types, false);
-		// 		}
-		// 		tuple_types = if read_signature {
-		// 			quote! { (<(#tuple_types)>::SIGNATURE) }
-		// 		} else {
-		// 			quote! { (#tuple_types) }
-		// 		};
-		// 		token_stream.extend(tuple_types);
-		// 	}
-
-		// 	AbiType::Vec(ref vec_type) => {
-		// 		let mut vec_token = proc_macro2::TokenStream::new();
-		// 		Self::expand_type(vec_type.as_ref(), &mut vec_token, false);
-		// 		vec_token = if read_signature {
-		// 			quote! { (<Vec<#vec_token>>::SIGNATURE) }
-		// 		} else {
-		// 			quote! { <Vec<#vec_token>> }
-		// 		};
-		// 		token_stream.extend(vec_token);
-		// 	}
-
-		// 	AbiType::Array(_, _) => todo!("Array eth signature"),
-		// };
 	}
 
 	fn expand_custom_signature(&self) -> proc_macro2::TokenStream {
-		let mut token_stream = TokenStream::new();
+		let mut args = TokenStream::new();
 
 		let mut is_first = true;
-		for arg in &self.args {
-			if arg.is_special() {
-				continue;
-			}
-
-			if is_first {
-				is_first = false;
-			} else {
-				token_stream.extend(quote!(,));
-			}
-			Self::expand_type(&arg.ty, &mut token_stream, true);
+		for arg in self.args.iter().filter(|a| !a.is_special()) {
+			is_first = false;
+			let ty = &arg.ty;
+			args.extend(quote! {nameof(#ty)});
+			args.extend(quote! {fixed(",")})
 		}
 
+		// Remove trailing comma
 		if !is_first {
-			token_stream.extend(quote!(,));
+			args.extend(quote! {shift_left(1)})
 		}
 
 		let func_name = self.camel_name.clone();
-		let func_name = quote!(SignaturePreferences {
-			open_name: Some(SignatureUnit::new(#func_name)),
-			open_delimiter: Some(SignatureUnit::new("(")),
-			param_delimiter: Some(SignatureUnit::new(",")),
-			close_delimiter: Some(SignatureUnit::new(")")),
-			close_name: None,
-		});
-		quote!({ ::evm_coder::make_signature!(new fn(#func_name), #token_stream) })
+		quote! { ::evm_coder::make_signature!(new fixed(#func_name) fixed("(") #args fixed(")")) }
 	}
 
 	fn expand_solidity_function(&self) -> proc_macro2::TokenStream {
@@ -916,12 +752,6 @@
 		let screaming_name = &self.screaming_name;
 		let hide = self.hide;
 		let custom_signature = self.expand_custom_signature();
-		let custom_signature = quote!(
-			{
-				const cs: FunctionSignature = #custom_signature;
-				cs
-			}
-		);
 		let is_payable = self.has_value_args;
 
 		quote! {
modifiedcrates/evm-coder/src/abi.rsdiffbeforeafterboth
before · crates/evm-coder/src/abi.rs
1// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.2// This file is part of Unique Network.34// Unique Network is free software: you can redistribute it and/or modify5// it under the terms of the GNU General Public License as published by6// the Free Software Foundation, either version 3 of the License, or7// (at your option) any later version.89// Unique Network is distributed in the hope that it will be useful,10// but WITHOUT ANY WARRANTY; without even the implied warranty of11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the12// GNU General Public License for more details.1314// You should have received a copy of the GNU General Public License15// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.1617//! Implementation of EVM RLP reader/writer1819#![allow(dead_code)]2021#[cfg(not(feature = "std"))]22use alloc::vec::Vec;23use evm_core::ExitError;24use primitive_types::{H160, U256};2526use crate::{27	execution::{Error, ResultWithPostInfo, WithPostDispatchInfo},28	types::*,29	make_signature,30	custom_signature::{SignatureUnit, SIGNATURE_SIZE_LIMIT},31};32use crate::execution::Result;3334const ABI_ALIGNMENT: usize = 32;3536trait TypeHelper {37	/// Is type dynamic sized.38	fn is_dynamic() -> bool;3940	/// Size for type aligned to [`ABI_ALIGNMENT`].41	fn size() -> usize;42}4344/// View into RLP data, which provides method to read typed items from it45#[derive(Clone)]46pub struct AbiReader<'i> {47	buf: &'i [u8],48	subresult_offset: usize,49	offset: usize,50}51impl<'i> AbiReader<'i> {52	/// Start reading RLP buffer, assuming there is no padding bytes53	pub fn new(buf: &'i [u8]) -> Self {54		Self {55			buf,56			subresult_offset: 0,57			offset: 0,58		}59	}60	/// Start reading RLP buffer, parsing first 4 bytes as selector61	pub fn new_call(buf: &'i [u8]) -> Result<(bytes4, Self)> {62		if buf.len() < 4 {63			return Err(Error::Error(ExitError::OutOfOffset));64		}65		let mut method_id = [0; 4];66		method_id.copy_from_slice(&buf[0..4]);6768		Ok((69			method_id,70			Self {71				buf,72				subresult_offset: 4,73				offset: 4,74			},75		))76	}7778	fn read_pad<const S: usize>(79		buf: &[u8],80		offset: usize,81		pad_start: usize,82		pad_size: usize,83		block_start: usize,84		block_size: usize,85	) -> Result<[u8; S]> {86		if buf.len() - offset < ABI_ALIGNMENT {87			return Err(Error::Error(ExitError::OutOfOffset));88		}89		let mut block = [0; S];90		let is_pad_zeroed = buf[pad_start..pad_size].iter().all(|&v| v == 0);91		if !is_pad_zeroed {92			return Err(Error::Error(ExitError::InvalidRange));93		}94		block.copy_from_slice(&buf[block_start..block_size]);95		Ok(block)96	}9798	fn read_padleft<const S: usize>(&mut self) -> Result<[u8; S]> {99		let offset = self.offset;100		self.offset += ABI_ALIGNMENT;101		Self::read_pad(102			self.buf,103			offset,104			offset,105			offset + ABI_ALIGNMENT - S,106			offset + ABI_ALIGNMENT - S,107			offset + ABI_ALIGNMENT,108		)109	}110111	fn read_padright<const S: usize>(&mut self) -> Result<[u8; S]> {112		let offset = self.offset;113		self.offset += ABI_ALIGNMENT;114		Self::read_pad(115			self.buf,116			offset,117			offset + S,118			offset + ABI_ALIGNMENT,119			offset,120			offset + S,121		)122	}123124	/// Read [`H160`] at current position, then advance125	pub fn address(&mut self) -> Result<H160> {126		Ok(H160(self.read_padleft()?))127	}128129	/// Read [`bool`] at current position, then advance130	pub fn bool(&mut self) -> Result<bool> {131		let data: [u8; 1] = self.read_padleft()?;132		match data[0] {133			0 => Ok(false),134			1 => Ok(true),135			_ => Err(Error::Error(ExitError::InvalidRange)),136		}137	}138139	/// Read [`[u8; 4]`] at current position, then advance140	pub fn bytes4(&mut self) -> Result<[u8; 4]> {141		self.read_padright()142	}143144	/// Read [`Vec<u8>`] at current position, then advance145	pub fn bytes(&mut self) -> Result<Vec<u8>> {146		let mut subresult = self.subresult(None)?;147		let length = subresult.uint32()? as usize;148		if subresult.buf.len() < subresult.offset + length {149			return Err(Error::Error(ExitError::OutOfOffset));150		}151		Ok(subresult.buf[subresult.offset..subresult.offset + length].into())152	}153154	/// Read [`string`] at current position, then advance155	pub fn string(&mut self) -> Result<string> {156		string::from_utf8(self.bytes()?).map_err(|_| Error::Error(ExitError::InvalidRange))157	}158159	/// Read [`u8`] at current position, then advance160	pub fn uint8(&mut self) -> Result<u8> {161		Ok(self.read_padleft::<1>()?[0])162	}163164	/// Read [`u32`] at current position, then advance165	pub fn uint32(&mut self) -> Result<u32> {166		Ok(u32::from_be_bytes(self.read_padleft()?))167	}168169	/// Read [`u128`] at current position, then advance170	pub fn uint128(&mut self) -> Result<u128> {171		Ok(u128::from_be_bytes(self.read_padleft()?))172	}173174	/// Read [`U256`] at current position, then advance175	pub fn uint256(&mut self) -> Result<U256> {176		let buf: [u8; 32] = self.read_padleft()?;177		Ok(U256::from_big_endian(&buf))178	}179180	/// Read [`u64`] at current position, then advance181	pub fn uint64(&mut self) -> Result<u64> {182		Ok(u64::from_be_bytes(self.read_padleft()?))183	}184185	/// Read [`usize`] at current position, then advance186	#[deprecated = "dangerous, as usize may have different width in wasm and native execution"]187	pub fn read_usize(&mut self) -> Result<usize> {188		Ok(usize::from_be_bytes(self.read_padleft()?))189	}190191	/// Slice recursive buffer, advance one word for buffer offset192	/// If `size` is [`None`] then [`Self::offset`] and [`Self::subresult_offset`] evals from [`Self::buf`].193	fn subresult(&mut self, size: Option<usize>) -> Result<AbiReader<'i>> {194		let subresult_offset = self.subresult_offset;195		let offset = if let Some(size) = size {196			self.offset += size;197			self.subresult_offset += size;198			0199		} else {200			self.uint32()? as usize201		};202203		if offset + self.subresult_offset > self.buf.len() {204			return Err(Error::Error(ExitError::InvalidRange));205		}206207		let new_offset = offset + subresult_offset;208		Ok(AbiReader {209			buf: self.buf,210			subresult_offset: new_offset,211			offset: new_offset,212		})213	}214215	/// Is this parser reached end of buffer?216	pub fn is_finished(&self) -> bool {217		self.buf.len() == self.offset218	}219}220221/// Writer for RLP encoded data222#[derive(Default)]223pub struct AbiWriter {224	static_part: Vec<u8>,225	dynamic_part: Vec<(usize, AbiWriter)>,226	had_call: bool,227	is_dynamic: bool,228}229impl AbiWriter {230	/// Initialize internal buffers for output data, assuming no padding required231	pub fn new() -> Self {232		Self::default()233	}234235	/// Initialize internal buffers with data size236	pub fn new_dynamic(is_dynamic: bool) -> Self {237		Self {238			is_dynamic,239			..Default::default()240		}241	}242	/// Initialize internal buffers, inserting method selector at beginning243	pub fn new_call(method_id: u32) -> Self {244		let mut val = Self::new();245		val.static_part.extend(&method_id.to_be_bytes());246		val.had_call = true;247		val248	}249250	fn write_padleft(&mut self, block: &[u8]) {251		assert!(block.len() <= ABI_ALIGNMENT);252		self.static_part253			.extend(&[0; ABI_ALIGNMENT][0..ABI_ALIGNMENT - block.len()]);254		self.static_part.extend(block);255	}256257	fn write_padright(&mut self, block: &[u8]) {258		assert!(block.len() <= ABI_ALIGNMENT);259		self.static_part.extend(block);260		self.static_part261			.extend(&[0; ABI_ALIGNMENT][0..ABI_ALIGNMENT - block.len()]);262	}263264	/// Write [`H160`] to end of buffer265	pub fn address(&mut self, address: &H160) {266		self.write_padleft(&address.0)267	}268269	/// Write [`bool`] to end of buffer270	pub fn bool(&mut self, value: &bool) {271		self.write_padleft(&[if *value { 1 } else { 0 }])272	}273274	/// Write [`u8`] to end of buffer275	pub fn uint8(&mut self, value: &u8) {276		self.write_padleft(&[*value])277	}278279	/// Write [`u32`] to end of buffer280	pub fn uint32(&mut self, value: &u32) {281		self.write_padleft(&u32::to_be_bytes(*value))282	}283284	/// Write [`u128`] to end of buffer285	pub fn uint128(&mut self, value: &u128) {286		self.write_padleft(&u128::to_be_bytes(*value))287	}288289	/// Write [`U256`] to end of buffer290	pub fn uint256(&mut self, value: &U256) {291		let mut out = [0; 32];292		value.to_big_endian(&mut out);293		self.write_padleft(&out)294	}295296	/// Write [`usize`] to end of buffer297	#[deprecated = "dangerous, as usize may have different width in wasm and native execution"]298	pub fn write_usize(&mut self, value: &usize) {299		self.write_padleft(&usize::to_be_bytes(*value))300	}301302	/// Append recursive data, writing pending offset at end of buffer303	pub fn write_subresult(&mut self, result: Self) {304		self.dynamic_part.push((self.static_part.len(), result));305		// Empty block, to be filled later306		self.write_padleft(&[]);307	}308309	fn memory(&mut self, value: &[u8]) {310		let mut sub = Self::new();311		sub.uint32(&(value.len() as u32));312		for chunk in value.chunks(ABI_ALIGNMENT) {313			sub.write_padright(chunk);314		}315		self.write_subresult(sub);316	}317318	/// Append recursive [`str`] at end of buffer319	pub fn string(&mut self, value: &str) {320		self.memory(value.as_bytes())321	}322323	/// Append recursive [`[u8]`] at end of buffer324	pub fn bytes(&mut self, value: &[u8]) {325		self.memory(value)326	}327328	/// Finish writer, concatenating all internal buffers329	pub fn finish(mut self) -> Vec<u8> {330		for (static_offset, part) in self.dynamic_part {331			let part_offset = self.static_part.len()332				- if self.had_call { 4 } else { 0 }333				- if self.is_dynamic { ABI_ALIGNMENT } else { 0 };334335			let encoded_dynamic_offset = usize::to_be_bytes(part_offset);336			let start = static_offset + ABI_ALIGNMENT - encoded_dynamic_offset.len();337			let stop = static_offset + ABI_ALIGNMENT;338			self.static_part[start..stop].copy_from_slice(&encoded_dynamic_offset);339			self.static_part.extend(part.finish())340		}341		self.static_part342	}343}344345/// [`AbiReader`] implements reading of many types.346pub trait AbiRead {347	/// Read item from current position, advanding decoder348	fn abi_read(reader: &mut AbiReader) -> Result<Self>349	where350		Self: Sized;351}352353macro_rules! impl_abi_readable {354	($ty:ty, $method:ident, $dynamic:literal) => {355		impl sealed::CanBePlacedInVec for $ty {}356357		impl TypeHelper for $ty {358			fn is_dynamic() -> bool {359				$dynamic360			}361362			fn size() -> usize {363				ABI_ALIGNMENT364			}365		}366367		impl AbiRead for $ty {368			fn abi_read(reader: &mut AbiReader) -> Result<$ty> {369				reader.$method()370			}371		}372	};373}374375impl_abi_readable!(bool, bool, false);376impl_abi_readable!(uint32, uint32, false);377impl_abi_readable!(uint64, uint64, false);378impl_abi_readable!(uint128, uint128, false);379impl_abi_readable!(uint256, uint256, false);380impl_abi_readable!(bytes4, bytes4, false);381impl_abi_readable!(address, address, false);382impl_abi_readable!(string, string, true);383384impl TypeHelper for uint8 {385	fn is_dynamic() -> bool {386		false387	}388	fn size() -> usize {389		ABI_ALIGNMENT390	}391}392impl AbiRead for uint8 {393	fn abi_read(reader: &mut AbiReader) -> Result<uint8> {394		reader.uint8()395	}396}397398impl TypeHelper for bytes {399	fn is_dynamic() -> bool {400		true401	}402	fn size() -> usize {403		ABI_ALIGNMENT404	}405}406impl AbiRead for bytes {407	fn abi_read(reader: &mut AbiReader) -> Result<bytes> {408		Ok(bytes(reader.bytes()?))409	}410}411412mod sealed {413	/// Not all types can be placed in vec, i.e `Vec<u8>` is restricted, `bytes` should be used instead414	pub trait CanBePlacedInVec {}415}416417impl<R: AbiRead + sealed::CanBePlacedInVec> AbiRead for Vec<R> {418	fn abi_read(reader: &mut AbiReader) -> Result<Vec<R>> {419		let mut sub = reader.subresult(None)?;420		let size = sub.uint32()? as usize;421		sub.subresult_offset = sub.offset;422		let mut out = Vec::with_capacity(size);423		for _ in 0..size {424			out.push(<R>::abi_read(&mut sub)?);425		}426		Ok(out)427	}428}429430impl<R: Signature> Signature for Vec<R> {431	make_signature!(new nameof(R) fixed("[]"));432}433434impl sealed::CanBePlacedInVec for EthCrossAccount {}435436impl TypeHelper for EthCrossAccount {437	fn is_dynamic() -> bool {438		address::is_dynamic() || uint256::is_dynamic()439	}440441	fn size() -> usize {442		<address as TypeHelper>::size() + <uint256 as TypeHelper>::size()443	}444}445446impl AbiRead for EthCrossAccount {447	fn abi_read(reader: &mut AbiReader) -> Result<EthCrossAccount> {448		let size = if !EthCrossAccount::is_dynamic() {449			Some(<EthCrossAccount as TypeHelper>::size())450		} else {451			None452		};453		let mut subresult = reader.subresult(size)?;454		let eth = <address>::abi_read(&mut subresult)?;455		let sub = <uint256>::abi_read(&mut subresult)?;456457		Ok(EthCrossAccount { eth, sub })458	}459}460461impl AbiWrite for EthCrossAccount {462	fn abi_write(&self, writer: &mut AbiWriter) {463		self.eth.abi_write(writer);464		self.sub.abi_write(writer);465	}466}467468macro_rules! impl_tuples {469	($($ident:ident)+) => {470		impl<$($ident: TypeHelper,)+> TypeHelper for ($($ident,)+)471		where472			$(473				$ident: TypeHelper,474			)+475		{476			fn is_dynamic() -> bool {477				false478				$(479					|| <$ident>::is_dynamic()480				)*481			}482483			fn size() -> usize {484				0 $(+ <$ident>::size())+485			}486		}487488		impl<$($ident),+> sealed::CanBePlacedInVec for ($($ident,)+) {}489490		impl<$($ident),+> AbiRead for ($($ident,)+)491		where492			$($ident: AbiRead,)+493			($($ident,)+): TypeHelper,494		{495			fn abi_read(reader: &mut AbiReader) -> Result<($($ident,)+)> {496				let size = if !<($($ident,)+)>::is_dynamic() { Some(<($($ident,)+)>::size()) } else { None };497				let mut subresult = reader.subresult(size)?;498				Ok((499					$(<$ident>::abi_read(&mut subresult)?,)+500				))501			}502		}503504		#[allow(non_snake_case)]505		impl<$($ident),+> AbiWrite for ($($ident,)+)506		where507			$($ident: AbiWrite,)+508		{509			fn abi_write(&self, writer: &mut AbiWriter) {510				let ($($ident,)+) = self;511				if writer.is_dynamic {512					let mut sub = AbiWriter::new();513					$($ident.abi_write(&mut sub);)+514					writer.write_subresult(sub);515				} else {516					$($ident.abi_write(writer);)+517				}518			}519		}520521		impl<$($ident),+> Signature for ($($ident,)+)522		where523		$($ident: Signature,)+524		{525			make_signature!(526				new fixed("(")527				$(nameof($ident) fixed(","))+528				shift_left(1)529				fixed(")")530			);531		}532	};533}534535impl_tuples! {A}536impl_tuples! {A B}537impl_tuples! {A B C}538impl_tuples! {A B C D}539impl_tuples! {A B C D E}540impl_tuples! {A B C D E F}541impl_tuples! {A B C D E F G}542impl_tuples! {A B C D E F G H}543impl_tuples! {A B C D E F G H I}544impl_tuples! {A B C D E F G H I J}545546/// For questions about inability to provide custom implementations,547/// see [`AbiRead`]548pub trait AbiWrite {549	/// Write value to end of specified encoder550	fn abi_write(&self, writer: &mut AbiWriter);551	/// Specialization for [`crate::solidity_interface`] implementation,552	/// see comment in `impl AbiWrite for ResultWithPostInfo`553	fn to_result(&self) -> ResultWithPostInfo<AbiWriter> {554		let mut writer = AbiWriter::new();555		self.abi_write(&mut writer);556		Ok(writer.into())557	}558}559560/// This particular AbiWrite implementation should be split to another trait,561/// which only implements `to_result`, but due to lack of specialization feature562/// in stable Rust, we can't have blanket impl of this trait `for T where T: AbiWrite`,563/// so here we abusing default trait methods for it564impl<T: AbiWrite> AbiWrite for ResultWithPostInfo<T> {565	fn abi_write(&self, _writer: &mut AbiWriter) {566		debug_assert!(false, "shouldn't be called, see comment")567	}568	fn to_result(&self) -> ResultWithPostInfo<AbiWriter> {569		match self {570			Ok(v) => Ok(WithPostDispatchInfo {571				post_info: v.post_info.clone(),572				data: {573					let mut out = AbiWriter::new();574					v.data.abi_write(&mut out);575					out576				},577			}),578			Err(e) => Err(e.clone()),579		}580	}581}582583macro_rules! impl_abi_writeable {584	($ty:ty, $method:ident) => {585		impl AbiWrite for $ty {586			fn abi_write(&self, writer: &mut AbiWriter) {587				writer.$method(&self)588			}589		}590	};591}592593impl_abi_writeable!(u8, uint8);594impl_abi_writeable!(u32, uint32);595impl_abi_writeable!(u128, uint128);596impl_abi_writeable!(U256, uint256);597impl_abi_writeable!(H160, address);598impl_abi_writeable!(bool, bool);599impl_abi_writeable!(&str, string);600601impl AbiWrite for string {602	fn abi_write(&self, writer: &mut AbiWriter) {603		writer.string(self)604	}605}606607impl AbiWrite for bytes {608	fn abi_write(&self, writer: &mut AbiWriter) {609		writer.bytes(self.0.as_slice())610	}611}612613impl<T: AbiWrite + TypeHelper> AbiWrite for Vec<T> {614	fn abi_write(&self, writer: &mut AbiWriter) {615		let is_dynamic = T::is_dynamic();616		let mut sub = if is_dynamic {617			AbiWriter::new_dynamic(is_dynamic)618		} else {619			AbiWriter::new()620		};621622		// Write items count623		(self.len() as u32).abi_write(&mut sub);624625		for item in self {626			item.abi_write(&mut sub);627		}628		writer.write_subresult(sub);629	}630}631632impl AbiWrite for () {633	fn abi_write(&self, _writer: &mut AbiWriter) {}634}635636/// Helper macros to parse reader into variables637#[deprecated]638#[macro_export]639macro_rules! abi_decode {640	($reader:expr, $($name:ident: $typ:ident),+ $(,)?) => {641		$(642			let $name = $reader.$typ()?;643		)+644	}645}646647/// Helper macros to construct RLP-encoded buffer648#[deprecated]649#[macro_export]650macro_rules! abi_encode {651	($($typ:ident($value:expr)),* $(,)?) => {{652		#[allow(unused_mut)]653		let mut writer = ::evm_coder::abi::AbiWriter::new();654		$(655			writer.$typ($value);656		)*657		writer658	}};659	(call $val:expr; $($typ:ident($value:expr)),* $(,)?) => {{660		#[allow(unused_mut)]661		let mut writer = ::evm_coder::abi::AbiWriter::new_call($val);662		$(663			writer.$typ($value);664		)*665		writer666	}}667}668669#[cfg(test)]670pub mod test {671	use crate::{672		abi::{AbiRead, AbiWrite},673		types::*,674	};675676	use super::{AbiReader, AbiWriter};677	use hex_literal::hex;678	use primitive_types::{H160, U256};679	use concat_idents::concat_idents;680681	macro_rules! test_impl {682		($name:ident, $type:ty, $function_identifier:expr, $decoded_data:expr, $encoded_data:expr) => {683			concat_idents!(test_name = encode_decode_, $name {684				#[test]685				fn test_name() {686					let function_identifier: u32 = $function_identifier;687					let decoded_data = $decoded_data;688					let encoded_data = $encoded_data;689690					let (call, mut decoder) = AbiReader::new_call(encoded_data).unwrap();691					assert_eq!(call, u32::to_be_bytes(function_identifier));692					let data = <$type>::abi_read(&mut decoder).unwrap();693					assert_eq!(data, decoded_data);694695					let mut writer = AbiWriter::new_call(function_identifier);696					decoded_data.abi_write(&mut writer);697					let ed = writer.finish();698					similar_asserts::assert_eq!(encoded_data, ed.as_slice());699				}700			});701		};702	}703704	macro_rules! test_impl_uint {705		($type:ident) => {706			test_impl!(707				$type,708				$type,709				0xdeadbeef,710				255 as $type,711				&hex!(712					"713						deadbeef714						00000000000000000000000000000000000000000000000000000000000000ff715					"716				)717			);718		};719	}720721	test_impl_uint!(uint8);722	test_impl_uint!(uint32);723	test_impl_uint!(uint128);724725	test_impl!(726		uint256,727		uint256,728		0xdeadbeef,729		U256([255, 0, 0, 0]),730		&hex!(731			"732				deadbeef733				00000000000000000000000000000000000000000000000000000000000000ff734			"735		)736	);737738	test_impl!(739		vec_tuple_address_uint256,740		Vec<(address, uint256)>,741		0x1ACF2D55,742		vec![743			(744				H160(hex!("2D2FF76104B7BACB2E8F6731D5BFC184EBECDDBC")),745				U256([10, 0, 0, 0]),746			),747			(748				H160(hex!("AB8E3D9134955566483B11E6825C9223B6737B10")),749				U256([20, 0, 0, 0]),750			),751			(752				H160(hex!("8C582BDF2953046705FC56F189385255EFC1BE18")),753				U256([30, 0, 0, 0]),754			),755		],756		&hex!(757			"758				1ACF2D55759				0000000000000000000000000000000000000000000000000000000000000020 // offset of (address, uint256)[]760				0000000000000000000000000000000000000000000000000000000000000003 // length of (address, uint256)[]761	762				0000000000000000000000002D2FF76104B7BACB2E8F6731D5BFC184EBECDDBC // address763				000000000000000000000000000000000000000000000000000000000000000A // uint256764	765				000000000000000000000000AB8E3D9134955566483B11E6825C9223B6737B10 // address766				0000000000000000000000000000000000000000000000000000000000000014 // uint256767	768				0000000000000000000000008C582BDF2953046705FC56F189385255EFC1BE18 // address769				000000000000000000000000000000000000000000000000000000000000001E // uint256770			"771		)772	);773774	test_impl!(775		vec_tuple_uint256_string,776		Vec<(uint256, string)>,777		0xdeadbeef,778		vec![779			(1.into(), "Test URI 0".to_string()),780			(11.into(), "Test URI 1".to_string()),781			(12.into(), "Test URI 2".to_string()),782		],783		&hex!(784			"785				deadbeef786				0000000000000000000000000000000000000000000000000000000000000020 // offset of (uint256, string)[]787				0000000000000000000000000000000000000000000000000000000000000003 // length of (uint256, string)[]788789				0000000000000000000000000000000000000000000000000000000000000060 // offset of first elem790				00000000000000000000000000000000000000000000000000000000000000e0 // offset of second elem791				0000000000000000000000000000000000000000000000000000000000000160 // offset of third elem792793				0000000000000000000000000000000000000000000000000000000000000001 // first token id?   					#60794				0000000000000000000000000000000000000000000000000000000000000040 // offset of string795				000000000000000000000000000000000000000000000000000000000000000a // size of string796				5465737420555249203000000000000000000000000000000000000000000000 // string797798				000000000000000000000000000000000000000000000000000000000000000b // second token id? Why ==11?			#e0799				0000000000000000000000000000000000000000000000000000000000000040 // offset of string800				000000000000000000000000000000000000000000000000000000000000000a // size of string801				5465737420555249203100000000000000000000000000000000000000000000 // string802803				000000000000000000000000000000000000000000000000000000000000000c // third token id?  Why ==12?			#160804				0000000000000000000000000000000000000000000000000000000000000040 // offset of string805				000000000000000000000000000000000000000000000000000000000000000a // size of string806				5465737420555249203200000000000000000000000000000000000000000000 // string807			"808		)809	);810811	#[test]812	fn dynamic_after_static() {813		let mut encoder = AbiWriter::new();814		encoder.bool(&true);815		encoder.string("test");816		let encoded = encoder.finish();817818		let mut encoder = AbiWriter::new();819		encoder.bool(&true);820		// Offset to subresult821		encoder.uint32(&(32 * 2));822		// Len of "test"823		encoder.uint32(&4);824		encoder.write_padright(&[b't', b'e', b's', b't']);825		let alternative_encoded = encoder.finish();826827		assert_eq!(encoded, alternative_encoded);828829		let mut decoder = AbiReader::new(&encoded);830		assert!(decoder.bool().unwrap());831		assert_eq!(decoder.string().unwrap(), "test");832	}833834	#[test]835	fn mint_sample() {836		let (call, mut decoder) = AbiReader::new_call(&hex!(837			"838				50bb4e7f839				000000000000000000000000ad2c0954693c2b5404b7e50967d3481bea432374840				0000000000000000000000000000000000000000000000000000000000000001841				0000000000000000000000000000000000000000000000000000000000000060842				0000000000000000000000000000000000000000000000000000000000000008843				5465737420555249000000000000000000000000000000000000000000000000844			"845		))846		.unwrap();847		assert_eq!(call, u32::to_be_bytes(0x50bb4e7f));848		assert_eq!(849			format!("{:?}", decoder.address().unwrap()),850			"0xad2c0954693c2b5404b7e50967d3481bea432374"851		);852		assert_eq!(decoder.uint32().unwrap(), 1);853		assert_eq!(decoder.string().unwrap(), "Test URI");854	}855856	#[test]857	fn parse_vec_with_dynamic_type() {858		let decoded_data = (859			0x36543006,860			vec![861				(1.into(), "Test URI 0".to_string()),862				(11.into(), "Test URI 1".to_string()),863				(12.into(), "Test URI 2".to_string()),864			],865		);866867		let encoded_data = &hex!(868			"869				36543006870				00000000000000000000000053744e6da587ba10b32a2554d2efdcd985bc27a3 // address871				0000000000000000000000000000000000000000000000000000000000000040 // offset of (uint256, string)[]872				0000000000000000000000000000000000000000000000000000000000000003 // length of (uint256, string)[]873874				0000000000000000000000000000000000000000000000000000000000000060 // offset of first elem875				00000000000000000000000000000000000000000000000000000000000000e0 // offset of second elem876				0000000000000000000000000000000000000000000000000000000000000160 // offset of third elem877878				0000000000000000000000000000000000000000000000000000000000000001 // first token id?   					#60879				0000000000000000000000000000000000000000000000000000000000000040 // offset of string880				000000000000000000000000000000000000000000000000000000000000000a // size of string881				5465737420555249203000000000000000000000000000000000000000000000 // string882883				000000000000000000000000000000000000000000000000000000000000000b // second token id? Why ==11?			#e0884				0000000000000000000000000000000000000000000000000000000000000040 // offset of string885				000000000000000000000000000000000000000000000000000000000000000a // size of string886				5465737420555249203100000000000000000000000000000000000000000000 // string887888				000000000000000000000000000000000000000000000000000000000000000c // third token id?  Why ==12?			#160889				0000000000000000000000000000000000000000000000000000000000000040 // offset of string890				000000000000000000000000000000000000000000000000000000000000000a // size of string891				5465737420555249203200000000000000000000000000000000000000000000 // string892			"893		);894895		let (call, mut decoder) = AbiReader::new_call(encoded_data).unwrap();896		assert_eq!(call, u32::to_be_bytes(decoded_data.0));897		let address = decoder.address().unwrap();898		let data = <Vec<(uint256, string)>>::abi_read(&mut decoder).unwrap();899		assert_eq!(data, decoded_data.1);900901		let mut writer = AbiWriter::new_call(decoded_data.0);902		address.abi_write(&mut writer);903		decoded_data.1.abi_write(&mut writer);904		let ed = writer.finish();905		similar_asserts::assert_eq!(encoded_data, ed.as_slice());906	}907}
after · crates/evm-coder/src/abi.rs
1// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.2// This file is part of Unique Network.34// Unique Network is free software: you can redistribute it and/or modify5// it under the terms of the GNU General Public License as published by6// the Free Software Foundation, either version 3 of the License, or7// (at your option) any later version.89// Unique Network is distributed in the hope that it will be useful,10// but WITHOUT ANY WARRANTY; without even the implied warranty of11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the12// GNU General Public License for more details.1314// You should have received a copy of the GNU General Public License15// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.1617//! Implementation of EVM RLP reader/writer1819#![allow(dead_code)]2021#[cfg(not(feature = "std"))]22use alloc::vec::Vec;23use evm_core::ExitError;24use primitive_types::{H160, U256};2526use crate::{27	execution::{Error, ResultWithPostInfo, WithPostDispatchInfo},28	types::*,29	make_signature,30	custom_signature::{SignatureUnit},31};32use crate::execution::Result;3334const ABI_ALIGNMENT: usize = 32;3536trait TypeHelper {37	/// Is type dynamic sized.38	fn is_dynamic() -> bool;3940	/// Size for type aligned to [`ABI_ALIGNMENT`].41	fn size() -> usize;42}4344/// View into RLP data, which provides method to read typed items from it45#[derive(Clone)]46pub struct AbiReader<'i> {47	buf: &'i [u8],48	subresult_offset: usize,49	offset: usize,50}51impl<'i> AbiReader<'i> {52	/// Start reading RLP buffer, assuming there is no padding bytes53	pub fn new(buf: &'i [u8]) -> Self {54		Self {55			buf,56			subresult_offset: 0,57			offset: 0,58		}59	}60	/// Start reading RLP buffer, parsing first 4 bytes as selector61	pub fn new_call(buf: &'i [u8]) -> Result<(bytes4, Self)> {62		if buf.len() < 4 {63			return Err(Error::Error(ExitError::OutOfOffset));64		}65		let mut method_id = [0; 4];66		method_id.copy_from_slice(&buf[0..4]);6768		Ok((69			method_id,70			Self {71				buf,72				subresult_offset: 4,73				offset: 4,74			},75		))76	}7778	fn read_pad<const S: usize>(79		buf: &[u8],80		offset: usize,81		pad_start: usize,82		pad_size: usize,83		block_start: usize,84		block_size: usize,85	) -> Result<[u8; S]> {86		if buf.len() - offset < ABI_ALIGNMENT {87			return Err(Error::Error(ExitError::OutOfOffset));88		}89		let mut block = [0; S];90		let is_pad_zeroed = buf[pad_start..pad_size].iter().all(|&v| v == 0);91		if !is_pad_zeroed {92			return Err(Error::Error(ExitError::InvalidRange));93		}94		block.copy_from_slice(&buf[block_start..block_size]);95		Ok(block)96	}9798	fn read_padleft<const S: usize>(&mut self) -> Result<[u8; S]> {99		let offset = self.offset;100		self.offset += ABI_ALIGNMENT;101		Self::read_pad(102			self.buf,103			offset,104			offset,105			offset + ABI_ALIGNMENT - S,106			offset + ABI_ALIGNMENT - S,107			offset + ABI_ALIGNMENT,108		)109	}110111	fn read_padright<const S: usize>(&mut self) -> Result<[u8; S]> {112		let offset = self.offset;113		self.offset += ABI_ALIGNMENT;114		Self::read_pad(115			self.buf,116			offset,117			offset + S,118			offset + ABI_ALIGNMENT,119			offset,120			offset + S,121		)122	}123124	/// Read [`H160`] at current position, then advance125	pub fn address(&mut self) -> Result<H160> {126		Ok(H160(self.read_padleft()?))127	}128129	/// Read [`bool`] at current position, then advance130	pub fn bool(&mut self) -> Result<bool> {131		let data: [u8; 1] = self.read_padleft()?;132		match data[0] {133			0 => Ok(false),134			1 => Ok(true),135			_ => Err(Error::Error(ExitError::InvalidRange)),136		}137	}138139	/// Read [`[u8; 4]`] at current position, then advance140	pub fn bytes4(&mut self) -> Result<[u8; 4]> {141		self.read_padright()142	}143144	/// Read [`Vec<u8>`] at current position, then advance145	pub fn bytes(&mut self) -> Result<Vec<u8>> {146		let mut subresult = self.subresult(None)?;147		let length = subresult.uint32()? as usize;148		if subresult.buf.len() < subresult.offset + length {149			return Err(Error::Error(ExitError::OutOfOffset));150		}151		Ok(subresult.buf[subresult.offset..subresult.offset + length].into())152	}153154	/// Read [`string`] at current position, then advance155	pub fn string(&mut self) -> Result<string> {156		string::from_utf8(self.bytes()?).map_err(|_| Error::Error(ExitError::InvalidRange))157	}158159	/// Read [`u8`] at current position, then advance160	pub fn uint8(&mut self) -> Result<u8> {161		Ok(self.read_padleft::<1>()?[0])162	}163164	/// Read [`u32`] at current position, then advance165	pub fn uint32(&mut self) -> Result<u32> {166		Ok(u32::from_be_bytes(self.read_padleft()?))167	}168169	/// Read [`u128`] at current position, then advance170	pub fn uint128(&mut self) -> Result<u128> {171		Ok(u128::from_be_bytes(self.read_padleft()?))172	}173174	/// Read [`U256`] at current position, then advance175	pub fn uint256(&mut self) -> Result<U256> {176		let buf: [u8; 32] = self.read_padleft()?;177		Ok(U256::from_big_endian(&buf))178	}179180	/// Read [`u64`] at current position, then advance181	pub fn uint64(&mut self) -> Result<u64> {182		Ok(u64::from_be_bytes(self.read_padleft()?))183	}184185	/// Read [`usize`] at current position, then advance186	#[deprecated = "dangerous, as usize may have different width in wasm and native execution"]187	pub fn read_usize(&mut self) -> Result<usize> {188		Ok(usize::from_be_bytes(self.read_padleft()?))189	}190191	/// Slice recursive buffer, advance one word for buffer offset192	/// If `size` is [`None`] then [`Self::offset`] and [`Self::subresult_offset`] evals from [`Self::buf`].193	fn subresult(&mut self, size: Option<usize>) -> Result<AbiReader<'i>> {194		let subresult_offset = self.subresult_offset;195		let offset = if let Some(size) = size {196			self.offset += size;197			self.subresult_offset += size;198			0199		} else {200			self.uint32()? as usize201		};202203		if offset + self.subresult_offset > self.buf.len() {204			return Err(Error::Error(ExitError::InvalidRange));205		}206207		let new_offset = offset + subresult_offset;208		Ok(AbiReader {209			buf: self.buf,210			subresult_offset: new_offset,211			offset: new_offset,212		})213	}214215	/// Is this parser reached end of buffer?216	pub fn is_finished(&self) -> bool {217		self.buf.len() == self.offset218	}219}220221/// Writer for RLP encoded data222#[derive(Default)]223pub struct AbiWriter {224	static_part: Vec<u8>,225	dynamic_part: Vec<(usize, AbiWriter)>,226	had_call: bool,227	is_dynamic: bool,228}229impl AbiWriter {230	/// Initialize internal buffers for output data, assuming no padding required231	pub fn new() -> Self {232		Self::default()233	}234235	/// Initialize internal buffers with data size236	pub fn new_dynamic(is_dynamic: bool) -> Self {237		Self {238			is_dynamic,239			..Default::default()240		}241	}242	/// Initialize internal buffers, inserting method selector at beginning243	pub fn new_call(method_id: u32) -> Self {244		let mut val = Self::new();245		val.static_part.extend(&method_id.to_be_bytes());246		val.had_call = true;247		val248	}249250	fn write_padleft(&mut self, block: &[u8]) {251		assert!(block.len() <= ABI_ALIGNMENT);252		self.static_part253			.extend(&[0; ABI_ALIGNMENT][0..ABI_ALIGNMENT - block.len()]);254		self.static_part.extend(block);255	}256257	fn write_padright(&mut self, block: &[u8]) {258		assert!(block.len() <= ABI_ALIGNMENT);259		self.static_part.extend(block);260		self.static_part261			.extend(&[0; ABI_ALIGNMENT][0..ABI_ALIGNMENT - block.len()]);262	}263264	/// Write [`H160`] to end of buffer265	pub fn address(&mut self, address: &H160) {266		self.write_padleft(&address.0)267	}268269	/// Write [`bool`] to end of buffer270	pub fn bool(&mut self, value: &bool) {271		self.write_padleft(&[if *value { 1 } else { 0 }])272	}273274	/// Write [`u8`] to end of buffer275	pub fn uint8(&mut self, value: &u8) {276		self.write_padleft(&[*value])277	}278279	/// Write [`u32`] to end of buffer280	pub fn uint32(&mut self, value: &u32) {281		self.write_padleft(&u32::to_be_bytes(*value))282	}283284	/// Write [`u128`] to end of buffer285	pub fn uint128(&mut self, value: &u128) {286		self.write_padleft(&u128::to_be_bytes(*value))287	}288289	/// Write [`U256`] to end of buffer290	pub fn uint256(&mut self, value: &U256) {291		let mut out = [0; 32];292		value.to_big_endian(&mut out);293		self.write_padleft(&out)294	}295296	/// Write [`usize`] to end of buffer297	#[deprecated = "dangerous, as usize may have different width in wasm and native execution"]298	pub fn write_usize(&mut self, value: &usize) {299		self.write_padleft(&usize::to_be_bytes(*value))300	}301302	/// Append recursive data, writing pending offset at end of buffer303	pub fn write_subresult(&mut self, result: Self) {304		self.dynamic_part.push((self.static_part.len(), result));305		// Empty block, to be filled later306		self.write_padleft(&[]);307	}308309	fn memory(&mut self, value: &[u8]) {310		let mut sub = Self::new();311		sub.uint32(&(value.len() as u32));312		for chunk in value.chunks(ABI_ALIGNMENT) {313			sub.write_padright(chunk);314		}315		self.write_subresult(sub);316	}317318	/// Append recursive [`str`] at end of buffer319	pub fn string(&mut self, value: &str) {320		self.memory(value.as_bytes())321	}322323	/// Append recursive [`[u8]`] at end of buffer324	pub fn bytes(&mut self, value: &[u8]) {325		self.memory(value)326	}327328	/// Finish writer, concatenating all internal buffers329	pub fn finish(mut self) -> Vec<u8> {330		for (static_offset, part) in self.dynamic_part {331			let part_offset = self.static_part.len()332				- if self.had_call { 4 } else { 0 }333				- if self.is_dynamic { ABI_ALIGNMENT } else { 0 };334335			let encoded_dynamic_offset = usize::to_be_bytes(part_offset);336			let start = static_offset + ABI_ALIGNMENT - encoded_dynamic_offset.len();337			let stop = static_offset + ABI_ALIGNMENT;338			self.static_part[start..stop].copy_from_slice(&encoded_dynamic_offset);339			self.static_part.extend(part.finish())340		}341		self.static_part342	}343}344345/// [`AbiReader`] implements reading of many types.346pub trait AbiRead {347	/// Read item from current position, advanding decoder348	fn abi_read(reader: &mut AbiReader) -> Result<Self>349	where350		Self: Sized;351}352353macro_rules! impl_abi_readable {354	($ty:ty, $method:ident, $dynamic:literal) => {355		impl sealed::CanBePlacedInVec for $ty {}356357		impl TypeHelper for $ty {358			fn is_dynamic() -> bool {359				$dynamic360			}361362			fn size() -> usize {363				ABI_ALIGNMENT364			}365		}366367		impl AbiRead for $ty {368			fn abi_read(reader: &mut AbiReader) -> Result<$ty> {369				reader.$method()370			}371		}372	};373}374375impl_abi_readable!(bool, bool, false);376impl_abi_readable!(uint32, uint32, false);377impl_abi_readable!(uint64, uint64, false);378impl_abi_readable!(uint128, uint128, false);379impl_abi_readable!(uint256, uint256, false);380impl_abi_readable!(bytes4, bytes4, false);381impl_abi_readable!(address, address, false);382impl_abi_readable!(string, string, true);383384impl TypeHelper for uint8 {385	fn is_dynamic() -> bool {386		false387	}388	fn size() -> usize {389		ABI_ALIGNMENT390	}391}392impl AbiRead for uint8 {393	fn abi_read(reader: &mut AbiReader) -> Result<uint8> {394		reader.uint8()395	}396}397398impl TypeHelper for bytes {399	fn is_dynamic() -> bool {400		true401	}402	fn size() -> usize {403		ABI_ALIGNMENT404	}405}406impl AbiRead for bytes {407	fn abi_read(reader: &mut AbiReader) -> Result<bytes> {408		Ok(bytes(reader.bytes()?))409	}410}411412mod sealed {413	/// Not all types can be placed in vec, i.e `Vec<u8>` is restricted, `bytes` should be used instead414	pub trait CanBePlacedInVec {}415}416417impl<R: AbiRead + sealed::CanBePlacedInVec> AbiRead for Vec<R> {418	fn abi_read(reader: &mut AbiReader) -> Result<Vec<R>> {419		let mut sub = reader.subresult(None)?;420		let size = sub.uint32()? as usize;421		sub.subresult_offset = sub.offset;422		let mut out = Vec::with_capacity(size);423		for _ in 0..size {424			out.push(<R>::abi_read(&mut sub)?);425		}426		Ok(out)427	}428}429430impl<R: Signature> Signature for Vec<R> {431	const SIGNATURE: SignatureUnit = make_signature!(new nameof(R) fixed("[]"));432}433434impl sealed::CanBePlacedInVec for EthCrossAccount {}435436impl TypeHelper for EthCrossAccount {437	fn is_dynamic() -> bool {438		address::is_dynamic() || uint256::is_dynamic()439	}440441	fn size() -> usize {442		<address as TypeHelper>::size() + <uint256 as TypeHelper>::size()443	}444}445446impl AbiRead for EthCrossAccount {447	fn abi_read(reader: &mut AbiReader) -> Result<EthCrossAccount> {448		let size = if !EthCrossAccount::is_dynamic() {449			Some(<EthCrossAccount as TypeHelper>::size())450		} else {451			None452		};453		let mut subresult = reader.subresult(size)?;454		let eth = <address>::abi_read(&mut subresult)?;455		let sub = <uint256>::abi_read(&mut subresult)?;456457		Ok(EthCrossAccount { eth, sub })458	}459}460461impl AbiWrite for EthCrossAccount {462	fn abi_write(&self, writer: &mut AbiWriter) {463		self.eth.abi_write(writer);464		self.sub.abi_write(writer);465	}466}467468macro_rules! impl_tuples {469	($($ident:ident)+) => {470		impl<$($ident: TypeHelper,)+> TypeHelper for ($($ident,)+)471		where472			$(473				$ident: TypeHelper,474			)+475		{476			fn is_dynamic() -> bool {477				false478				$(479					|| <$ident>::is_dynamic()480				)*481			}482483			fn size() -> usize {484				0 $(+ <$ident>::size())+485			}486		}487488		impl<$($ident),+> sealed::CanBePlacedInVec for ($($ident,)+) {}489490		impl<$($ident),+> AbiRead for ($($ident,)+)491		where492			$($ident: AbiRead,)+493			($($ident,)+): TypeHelper,494		{495			fn abi_read(reader: &mut AbiReader) -> Result<($($ident,)+)> {496				let size = if !<($($ident,)+)>::is_dynamic() { Some(<($($ident,)+)>::size()) } else { None };497				let mut subresult = reader.subresult(size)?;498				Ok((499					$(<$ident>::abi_read(&mut subresult)?,)+500				))501			}502		}503504		#[allow(non_snake_case)]505		impl<$($ident),+> AbiWrite for ($($ident,)+)506		where507			$($ident: AbiWrite,)+508		{509			fn abi_write(&self, writer: &mut AbiWriter) {510				let ($($ident,)+) = self;511				if writer.is_dynamic {512					let mut sub = AbiWriter::new();513					$($ident.abi_write(&mut sub);)+514					writer.write_subresult(sub);515				} else {516					$($ident.abi_write(writer);)+517				}518			}519		}520521		impl<$($ident),+> Signature for ($($ident,)+)522		where523		$($ident: Signature,)+524		{525			const SIGNATURE: SignatureUnit = make_signature!(526				new fixed("(")527				$(nameof($ident) fixed(","))+528				shift_left(1)529				fixed(")")530			);531		}532	};533}534535impl_tuples! {A}536impl_tuples! {A B}537impl_tuples! {A B C}538impl_tuples! {A B C D}539impl_tuples! {A B C D E}540impl_tuples! {A B C D E F}541impl_tuples! {A B C D E F G}542impl_tuples! {A B C D E F G H}543impl_tuples! {A B C D E F G H I}544impl_tuples! {A B C D E F G H I J}545546/// For questions about inability to provide custom implementations,547/// see [`AbiRead`]548pub trait AbiWrite {549	/// Write value to end of specified encoder550	fn abi_write(&self, writer: &mut AbiWriter);551	/// Specialization for [`crate::solidity_interface`] implementation,552	/// see comment in `impl AbiWrite for ResultWithPostInfo`553	fn to_result(&self) -> ResultWithPostInfo<AbiWriter> {554		let mut writer = AbiWriter::new();555		self.abi_write(&mut writer);556		Ok(writer.into())557	}558}559560/// This particular AbiWrite implementation should be split to another trait,561/// which only implements `to_result`, but due to lack of specialization feature562/// in stable Rust, we can't have blanket impl of this trait `for T where T: AbiWrite`,563/// so here we abusing default trait methods for it564impl<T: AbiWrite> AbiWrite for ResultWithPostInfo<T> {565	fn abi_write(&self, _writer: &mut AbiWriter) {566		debug_assert!(false, "shouldn't be called, see comment")567	}568	fn to_result(&self) -> ResultWithPostInfo<AbiWriter> {569		match self {570			Ok(v) => Ok(WithPostDispatchInfo {571				post_info: v.post_info.clone(),572				data: {573					let mut out = AbiWriter::new();574					v.data.abi_write(&mut out);575					out576				},577			}),578			Err(e) => Err(e.clone()),579		}580	}581}582583macro_rules! impl_abi_writeable {584	($ty:ty, $method:ident) => {585		impl AbiWrite for $ty {586			fn abi_write(&self, writer: &mut AbiWriter) {587				writer.$method(&self)588			}589		}590	};591}592593impl_abi_writeable!(u8, uint8);594impl_abi_writeable!(u32, uint32);595impl_abi_writeable!(u128, uint128);596impl_abi_writeable!(U256, uint256);597impl_abi_writeable!(H160, address);598impl_abi_writeable!(bool, bool);599impl_abi_writeable!(&str, string);600601impl AbiWrite for string {602	fn abi_write(&self, writer: &mut AbiWriter) {603		writer.string(self)604	}605}606607impl AbiWrite for bytes {608	fn abi_write(&self, writer: &mut AbiWriter) {609		writer.bytes(self.0.as_slice())610	}611}612613impl<T: AbiWrite + TypeHelper> AbiWrite for Vec<T> {614	fn abi_write(&self, writer: &mut AbiWriter) {615		let is_dynamic = T::is_dynamic();616		let mut sub = if is_dynamic {617			AbiWriter::new_dynamic(is_dynamic)618		} else {619			AbiWriter::new()620		};621622		// Write items count623		(self.len() as u32).abi_write(&mut sub);624625		for item in self {626			item.abi_write(&mut sub);627		}628		writer.write_subresult(sub);629	}630}631632impl AbiWrite for () {633	fn abi_write(&self, _writer: &mut AbiWriter) {}634}635636/// Helper macros to parse reader into variables637#[deprecated]638#[macro_export]639macro_rules! abi_decode {640	($reader:expr, $($name:ident: $typ:ident),+ $(,)?) => {641		$(642			let $name = $reader.$typ()?;643		)+644	}645}646647/// Helper macros to construct RLP-encoded buffer648#[deprecated]649#[macro_export]650macro_rules! abi_encode {651	($($typ:ident($value:expr)),* $(,)?) => {{652		#[allow(unused_mut)]653		let mut writer = ::evm_coder::abi::AbiWriter::new();654		$(655			writer.$typ($value);656		)*657		writer658	}};659	(call $val:expr; $($typ:ident($value:expr)),* $(,)?) => {{660		#[allow(unused_mut)]661		let mut writer = ::evm_coder::abi::AbiWriter::new_call($val);662		$(663			writer.$typ($value);664		)*665		writer666	}}667}668669#[cfg(test)]670pub mod test {671	use crate::{672		abi::{AbiRead, AbiWrite},673		types::*,674	};675676	use super::{AbiReader, AbiWriter};677	use hex_literal::hex;678	use primitive_types::{H160, U256};679	use concat_idents::concat_idents;680681	macro_rules! test_impl {682		($name:ident, $type:ty, $function_identifier:expr, $decoded_data:expr, $encoded_data:expr) => {683			concat_idents!(test_name = encode_decode_, $name {684				#[test]685				fn test_name() {686					let function_identifier: u32 = $function_identifier;687					let decoded_data = $decoded_data;688					let encoded_data = $encoded_data;689690					let (call, mut decoder) = AbiReader::new_call(encoded_data).unwrap();691					assert_eq!(call, u32::to_be_bytes(function_identifier));692					let data = <$type>::abi_read(&mut decoder).unwrap();693					assert_eq!(data, decoded_data);694695					let mut writer = AbiWriter::new_call(function_identifier);696					decoded_data.abi_write(&mut writer);697					let ed = writer.finish();698					similar_asserts::assert_eq!(encoded_data, ed.as_slice());699				}700			});701		};702	}703704	macro_rules! test_impl_uint {705		($type:ident) => {706			test_impl!(707				$type,708				$type,709				0xdeadbeef,710				255 as $type,711				&hex!(712					"713						deadbeef714						00000000000000000000000000000000000000000000000000000000000000ff715					"716				)717			);718		};719	}720721	test_impl_uint!(uint8);722	test_impl_uint!(uint32);723	test_impl_uint!(uint128);724725	test_impl!(726		uint256,727		uint256,728		0xdeadbeef,729		U256([255, 0, 0, 0]),730		&hex!(731			"732				deadbeef733				00000000000000000000000000000000000000000000000000000000000000ff734			"735		)736	);737738	test_impl!(739		vec_tuple_address_uint256,740		Vec<(address, uint256)>,741		0x1ACF2D55,742		vec![743			(744				H160(hex!("2D2FF76104B7BACB2E8F6731D5BFC184EBECDDBC")),745				U256([10, 0, 0, 0]),746			),747			(748				H160(hex!("AB8E3D9134955566483B11E6825C9223B6737B10")),749				U256([20, 0, 0, 0]),750			),751			(752				H160(hex!("8C582BDF2953046705FC56F189385255EFC1BE18")),753				U256([30, 0, 0, 0]),754			),755		],756		&hex!(757			"758				1ACF2D55759				0000000000000000000000000000000000000000000000000000000000000020 // offset of (address, uint256)[]760				0000000000000000000000000000000000000000000000000000000000000003 // length of (address, uint256)[]761762				0000000000000000000000002D2FF76104B7BACB2E8F6731D5BFC184EBECDDBC // address763				000000000000000000000000000000000000000000000000000000000000000A // uint256764765				000000000000000000000000AB8E3D9134955566483B11E6825C9223B6737B10 // address766				0000000000000000000000000000000000000000000000000000000000000014 // uint256767768				0000000000000000000000008C582BDF2953046705FC56F189385255EFC1BE18 // address769				000000000000000000000000000000000000000000000000000000000000001E // uint256770			"771		)772	);773774	test_impl!(775		vec_tuple_uint256_string,776		Vec<(uint256, string)>,777		0xdeadbeef,778		vec![779			(1.into(), "Test URI 0".to_string()),780			(11.into(), "Test URI 1".to_string()),781			(12.into(), "Test URI 2".to_string()),782		],783		&hex!(784			"785				deadbeef786				0000000000000000000000000000000000000000000000000000000000000020 // offset of (uint256, string)[]787				0000000000000000000000000000000000000000000000000000000000000003 // length of (uint256, string)[]788789				0000000000000000000000000000000000000000000000000000000000000060 // offset of first elem790				00000000000000000000000000000000000000000000000000000000000000e0 // offset of second elem791				0000000000000000000000000000000000000000000000000000000000000160 // offset of third elem792793				0000000000000000000000000000000000000000000000000000000000000001 // first token id?   					#60794				0000000000000000000000000000000000000000000000000000000000000040 // offset of string795				000000000000000000000000000000000000000000000000000000000000000a // size of string796				5465737420555249203000000000000000000000000000000000000000000000 // string797798				000000000000000000000000000000000000000000000000000000000000000b // second token id? Why ==11?			#e0799				0000000000000000000000000000000000000000000000000000000000000040 // offset of string800				000000000000000000000000000000000000000000000000000000000000000a // size of string801				5465737420555249203100000000000000000000000000000000000000000000 // string802803				000000000000000000000000000000000000000000000000000000000000000c // third token id?  Why ==12?			#160804				0000000000000000000000000000000000000000000000000000000000000040 // offset of string805				000000000000000000000000000000000000000000000000000000000000000a // size of string806				5465737420555249203200000000000000000000000000000000000000000000 // string807			"808		)809	);810811	#[test]812	fn dynamic_after_static() {813		let mut encoder = AbiWriter::new();814		encoder.bool(&true);815		encoder.string("test");816		let encoded = encoder.finish();817818		let mut encoder = AbiWriter::new();819		encoder.bool(&true);820		// Offset to subresult821		encoder.uint32(&(32 * 2));822		// Len of "test"823		encoder.uint32(&4);824		encoder.write_padright(&[b't', b'e', b's', b't']);825		let alternative_encoded = encoder.finish();826827		assert_eq!(encoded, alternative_encoded);828829		let mut decoder = AbiReader::new(&encoded);830		assert!(decoder.bool().unwrap());831		assert_eq!(decoder.string().unwrap(), "test");832	}833834	#[test]835	fn mint_sample() {836		let (call, mut decoder) = AbiReader::new_call(&hex!(837			"838				50bb4e7f839				000000000000000000000000ad2c0954693c2b5404b7e50967d3481bea432374840				0000000000000000000000000000000000000000000000000000000000000001841				0000000000000000000000000000000000000000000000000000000000000060842				0000000000000000000000000000000000000000000000000000000000000008843				5465737420555249000000000000000000000000000000000000000000000000844			"845		))846		.unwrap();847		assert_eq!(call, u32::to_be_bytes(0x50bb4e7f));848		assert_eq!(849			format!("{:?}", decoder.address().unwrap()),850			"0xad2c0954693c2b5404b7e50967d3481bea432374"851		);852		assert_eq!(decoder.uint32().unwrap(), 1);853		assert_eq!(decoder.string().unwrap(), "Test URI");854	}855856	#[test]857	fn parse_vec_with_dynamic_type() {858		let decoded_data = (859			0x36543006,860			vec![861				(1.into(), "Test URI 0".to_string()),862				(11.into(), "Test URI 1".to_string()),863				(12.into(), "Test URI 2".to_string()),864			],865		);866867		let encoded_data = &hex!(868			"869				36543006870				00000000000000000000000053744e6da587ba10b32a2554d2efdcd985bc27a3 // address871				0000000000000000000000000000000000000000000000000000000000000040 // offset of (uint256, string)[]872				0000000000000000000000000000000000000000000000000000000000000003 // length of (uint256, string)[]873874				0000000000000000000000000000000000000000000000000000000000000060 // offset of first elem875				00000000000000000000000000000000000000000000000000000000000000e0 // offset of second elem876				0000000000000000000000000000000000000000000000000000000000000160 // offset of third elem877878				0000000000000000000000000000000000000000000000000000000000000001 // first token id?   					#60879				0000000000000000000000000000000000000000000000000000000000000040 // offset of string880				000000000000000000000000000000000000000000000000000000000000000a // size of string881				5465737420555249203000000000000000000000000000000000000000000000 // string882883				000000000000000000000000000000000000000000000000000000000000000b // second token id? Why ==11?			#e0884				0000000000000000000000000000000000000000000000000000000000000040 // offset of string885				000000000000000000000000000000000000000000000000000000000000000a // size of string886				5465737420555249203100000000000000000000000000000000000000000000 // string887888				000000000000000000000000000000000000000000000000000000000000000c // third token id?  Why ==12?			#160889				0000000000000000000000000000000000000000000000000000000000000040 // offset of string890				000000000000000000000000000000000000000000000000000000000000000a // size of string891				5465737420555249203200000000000000000000000000000000000000000000 // string892			"893		);894895		let (call, mut decoder) = AbiReader::new_call(encoded_data).unwrap();896		assert_eq!(call, u32::to_be_bytes(decoded_data.0));897		let address = decoder.address().unwrap();898		let data = <Vec<(uint256, string)>>::abi_read(&mut decoder).unwrap();899		assert_eq!(data, decoded_data.1);900901		let mut writer = AbiWriter::new_call(decoded_data.0);902		address.abi_write(&mut writer);903		decoded_data.1.abi_write(&mut writer);904		let ed = writer.finish();905		similar_asserts::assert_eq!(encoded_data, ed.as_slice());906	}907}
modifiedcrates/evm-coder/src/custom_signature.rsdiffbeforeafterboth
--- a/crates/evm-coder/src/custom_signature.rs
+++ b/crates/evm-coder/src/custom_signature.rs
@@ -74,132 +74,11 @@
 //!	impl<T: SoliditySignature> SoliditySignature for Vec<T> {
 //!		make_signature!(new nameof(T) fixed("[]"));
 //!	}
-//!
-//! // Function signature settings
-//! const SIGNATURE_PREFERENCES: SignaturePreferences = SignaturePreferences {
-//!		open_name: Some(SignatureUnit::new("some_funk")),
-//!		open_delimiter: Some(SignatureUnit::new("(")),
-//!		param_delimiter: Some(SignatureUnit::new(",")),
-//!		close_delimiter: Some(SignatureUnit::new(")")),
-//!		close_name: None,
-//!	};
-//!
-//! // Create functions signatures
-//! fn make_func_without_args() {
-//!		const SIG: FunctionSignature = make_signature!(
-//!			new fn(SIGNATURE_PREFERENCES),
-//!		);
-//!		let name = SIG.as_str();
-//!		similar_asserts::assert_eq!(name, "some_funk()");
-//!	}
-//!
-//! fn make_func_with_3_args() {
-//!		const SIG: FunctionSignature = make_signature!(
-//!			new fn(SIGNATURE_PREFERENCES),
-//!			(<u8>::SIGNATURE),
-//!			(<u8>::SIGNATURE),
-//!			(<Vec<u8>>::SIGNATURE),
-//!		);
-//!		let name = SIG.as_str();
-//!		similar_asserts::assert_eq!(name, "some_funk(uint8,uint8,uint8[])");
-//!	}
 //! ```
-use core::str::from_utf8;
 
 /// The maximum length of the signature.
 pub const SIGNATURE_SIZE_LIMIT: usize = 256;
-
-/// Function signature formatting preferences.
-#[derive(Debug)]
-pub struct SignaturePreferences {
-	/// The name of the function before the list of parameters: `*some*(param1,param2)func`
-	pub open_name: Option<SignatureUnit>,
-	/// Opening separator: `some*(*param1,param2)func`
-	pub open_delimiter: Option<SignatureUnit>,
-	/// Parameters separator: `some(param1*,*param2)func`
-	pub param_delimiter: Option<SignatureUnit>,
-	/// Closinging separator: `some(param1,param2*)*func`
-	pub close_delimiter: Option<SignatureUnit>,
-	/// The name of the function after the list of parameters: `some(param1,param2)*func*`
-	pub close_name: Option<SignatureUnit>,
-}
-
-/// Constructs and stores the signature of the function.
-#[derive(Debug)]
-pub struct FunctionSignature {
-	/// Storage for function signature.
-	pub unit: SignatureUnit,
-	preferences: SignaturePreferences,
-}
 
-impl FunctionSignature {
-	/// Start constructing the signature. It is written to the storage
-	/// [`SignaturePreferences::open_name`] and [`SignaturePreferences::open_delimiter`].
-	pub const fn new(preferences: SignaturePreferences) -> FunctionSignature {
-		let mut dst = [0_u8; SIGNATURE_SIZE_LIMIT];
-		let mut dst_offset = 0;
-		if let Some(ref name) = preferences.open_name {
-			crate::make_signature!(@copy(name.data, dst, name.len, dst_offset));
-		}
-		if let Some(ref delimiter) = preferences.open_delimiter {
-			crate::make_signature!(@copy(delimiter.data, dst, delimiter.len, dst_offset));
-		}
-		FunctionSignature {
-			unit: SignatureUnit {
-				data: dst,
-				len: dst_offset,
-			},
-			preferences,
-		}
-	}
-
-	/// Add a function parameter to the signature. It is written to the storage
-	/// `param` [`SignatureUnit`] and [`SignaturePreferences::param_delimiter`].
-	pub const fn add_param(
-		signature: FunctionSignature,
-		param: SignatureUnit,
-	) -> FunctionSignature {
-		let mut dst = signature.unit.data;
-		let mut dst_offset = signature.unit.len;
-		crate::make_signature!(@copy(param.data, dst, param.len, dst_offset));
-		if let Some(ref delimiter) = signature.preferences.param_delimiter {
-			crate::make_signature!(@copy(delimiter.data, dst, delimiter.len, dst_offset));
-		}
-		FunctionSignature {
-			unit: SignatureUnit {
-				data: dst,
-				len: dst_offset,
-			},
-			..signature
-		}
-	}
-
-	/// Complete signature construction. It is written to the storage
-	/// [`SignaturePreferences::close_delimiter`] and [`SignaturePreferences::close_name`].
-	pub const fn done(signature: FunctionSignature, owerride: bool) -> FunctionSignature {
-		let mut dst = signature.unit.data;
-		let mut dst_offset = signature.unit.len - if owerride { 1 } else { 0 };
-		if let Some(ref delimiter) = signature.preferences.close_delimiter {
-			crate::make_signature!(@copy(delimiter.data, dst, delimiter.len, dst_offset));
-		}
-		if let Some(ref name) = signature.preferences.close_name {
-			crate::make_signature!(@copy(name.data, dst, name.len, dst_offset));
-		}
-		FunctionSignature {
-			unit: SignatureUnit {
-				data: dst,
-				len: dst_offset,
-			},
-			..signature
-		}
-	}
-
-	/// Represent the signature as `&str'.
-	pub fn as_str(&self) -> &str {
-		from_utf8(&self.unit.data[..self.unit.len]).expect("bad utf-8")
-	}
-}
-
 /// Storage for the signature or its elements.
 #[derive(Debug)]
 pub struct SignatureUnit {
@@ -222,6 +101,10 @@
 			len: name_len,
 		}
 	}
+	/// String conversion
+	pub fn as_str(&self) -> Option<&str> {
+		core::str::from_utf8(&self.data[0..self.len]).ok()
+	}
 }
 
 /// ### Macro to create signatures of types and functions.
@@ -231,85 +114,52 @@
 /// make_signature!(new fixed("uint8")); // Simple type
 /// make_signature!(new fixed("(") nameof(u8) fixed(",") nameof(u8) fixed(")")); // Composite type
 /// ```
-/// Format for creating a function of the function:
-/// ```ignore
-/// const SIG: FunctionSignature = make_signature!(
-///		new fn(SIGNATURE_PREFERENCES),
-///		(u8::SIGNATURE),
-///		(<(u8,u8)>::SIGNATURE),
-///	);
-/// ```
 #[macro_export]
 macro_rules! make_signature {
-	(new fn($func:expr)$(,)*) => {
-		{
-			let fs = FunctionSignature::new($func);
-			let fs = FunctionSignature::done(fs, false);
-			fs
-		}
-	};
-	(new fn($func:expr), $($tt:tt,)*) => {
-		{
-			let fs = FunctionSignature::new($func);
-			let fs = make_signature!(@param; fs, $($tt),*);
-			fs
-		}
+	(new $($tt:tt)*) => {
+		($crate::custom_signature::SignatureUnit {
+			data: {
+				let mut out = [0u8; $crate::custom_signature::SIGNATURE_SIZE_LIMIT];
+				let mut dst_offset = 0;
+				$crate::make_signature!(@data(out, dst_offset); $($tt)*);
+				out
+			},
+			len: {0 + $crate::make_signature!(@size; $($tt)*)},
+		})
 	};
 
-	(@param; $func:expr) => {
-		FunctionSignature::done($func, true)
+	(@size;) => {
+		0
 	};
-	(@param; $func:expr, $param:expr) => {
-		make_signature!(@param; FunctionSignature::add_param($func, $param))
+	(@size; fixed($expr:expr) $($tt:tt)*) => {
+		$expr.len() + $crate::make_signature!(@size; $($tt)*)
 	};
-	(@param; $func:expr, $param:expr, $($tt:tt),*) => {
-		make_signature!(@param; FunctionSignature::add_param($func, $param), $($tt),*)
+	(@size; nameof($expr:ty) $($tt:tt)*) => {
+		<$expr>::SIGNATURE.len + $crate::make_signature!(@size; $($tt)*)
 	};
-
-    (new $($tt:tt)*) => {
-        const SIGNATURE: SignatureUnit = SignatureUnit {
-			data: {
-				let mut out = [0u8; SIGNATURE_SIZE_LIMIT];
-				let mut dst_offset = 0;
-				make_signature!(@data(out, dst_offset); $($tt)*);
-				out
-			},
-			len: {0 + make_signature!(@size; $($tt)*)},
-        };
-    };
-
-    (@size;) => {
-        0
-    };
-    (@size; fixed($expr:expr) $($tt:tt)*) => {
-        $expr.len() + make_signature!(@size; $($tt)*)
-    };
-    (@size; nameof($expr:ty) $($tt:tt)*) => {
-		<$expr>::SIGNATURE.len + make_signature!(@size; $($tt)*)
-    };
 	(@size; shift_left($expr:expr) $($tt:tt)*) => {
-		make_signature!(@size; $($tt)*) - $expr
+		$crate::make_signature!(@size; $($tt)*) - $expr
 	};
 
-    (@data($dst:ident, $dst_offset:ident);) => {};
-    (@data($dst:ident, $dst_offset:ident); fixed($expr:expr) $($tt:tt)*) => {
-        {
-            let data = $expr.as_bytes();
+	(@data($dst:ident, $dst_offset:ident);) => {};
+	(@data($dst:ident, $dst_offset:ident); fixed($expr:expr) $($tt:tt)*) => {
+		{
+			let data = $expr.as_bytes();
 			let data_len = data.len();
-			make_signature!(@copy(data, $dst, data_len, $dst_offset));
-        }
-        make_signature!(@data($dst, $dst_offset); $($tt)*)
-    };
-    (@data($dst:ident, $dst_offset:ident); nameof($expr:ty) $($tt:tt)*) => {
-        {
-            make_signature!(@copy(&<$expr>::SIGNATURE.data, $dst, <$expr>::SIGNATURE.len, $dst_offset));
-        }
-        make_signature!(@data($dst, $dst_offset); $($tt)*)
-    };
+			$crate::make_signature!(@copy(data, $dst, data_len, $dst_offset));
+		}
+		$crate::make_signature!(@data($dst, $dst_offset); $($tt)*)
+	};
+	(@data($dst:ident, $dst_offset:ident); nameof($expr:ty) $($tt:tt)*) => {
+		{
+			$crate::make_signature!(@copy(&<$expr>::SIGNATURE.data, $dst, <$expr>::SIGNATURE.len, $dst_offset));
+		}
+		$crate::make_signature!(@data($dst, $dst_offset); $($tt)*)
+	};
 	(@data($dst:ident, $dst_offset:ident); shift_left($expr:expr) $($tt:tt)*) => {
-        $dst_offset -= $expr;
-        make_signature!(@data($dst, $dst_offset); $($tt)*)
-    };
+		$dst_offset -= $expr;
+		$crate::make_signature!(@data($dst, $dst_offset); $($tt)*)
+	};
 
 	(@copy($src:expr, $dst:expr, $src_len:expr, $dst_offset:ident)) => {
 		{
@@ -328,7 +178,7 @@
 mod test {
 	use core::str::from_utf8;
 
-	use super::{SIGNATURE_SIZE_LIMIT, SignatureUnit, FunctionSignature, SignaturePreferences};
+	use super::{SIGNATURE_SIZE_LIMIT, SignatureUnit};
 
 	trait Name {
 		const SIGNATURE: SignatureUnit;
@@ -339,19 +189,21 @@
 	}
 
 	impl Name for u8 {
-		make_signature!(new fixed("uint8"));
+		const SIGNATURE: SignatureUnit = make_signature!(new fixed("uint8"));
 	}
 	impl Name for u32 {
-		make_signature!(new fixed("uint32"));
+		const SIGNATURE: SignatureUnit = make_signature!(new fixed("uint32"));
 	}
 	impl<T: Name> Name for Vec<T> {
-		make_signature!(new nameof(T) fixed("[]"));
+		const SIGNATURE: SignatureUnit = make_signature!(new nameof(T) fixed("[]"));
 	}
 	impl<A: Name, B: Name> Name for (A, B) {
-		make_signature!(new fixed("(") nameof(A) fixed(",") nameof(B) fixed(")"));
+		const SIGNATURE: SignatureUnit =
+			make_signature!(new fixed("(") nameof(A) fixed(",") nameof(B) fixed(")"));
 	}
 	impl<A: Name> Name for (A,) {
-		make_signature!(new fixed("(") nameof(A) fixed(",") shift_left(1) fixed(")"));
+		const SIGNATURE: SignatureUnit =
+			make_signature!(new fixed("(") nameof(A) fixed(",") shift_left(1) fixed(")"));
 	}
 
 	struct MaxSize();
@@ -361,14 +213,6 @@
 			len: SIGNATURE_SIZE_LIMIT,
 		};
 	}
-
-	const SIGNATURE_PREFERENCES: SignaturePreferences = SignaturePreferences {
-		open_name: Some(SignatureUnit::new("some_funk")),
-		open_delimiter: Some(SignatureUnit::new("(")),
-		param_delimiter: Some(SignatureUnit::new(",")),
-		close_delimiter: Some(SignatureUnit::new(")")),
-		close_name: None,
-	};
 
 	#[test]
 	fn simple() {
@@ -421,68 +265,6 @@
 	#[test]
 	fn max_size() {
 		assert_eq!(<MaxSize>::name(), "!".repeat(SIGNATURE_SIZE_LIMIT));
-	}
-
-	#[test]
-	fn make_func_without_args() {
-		const SIG: FunctionSignature = make_signature!(
-			new fn(SIGNATURE_PREFERENCES)
-		);
-		let name = SIG.as_str();
-		similar_asserts::assert_eq!(name, "some_funk()");
-	}
-
-	#[test]
-	fn make_func_with_1_args() {
-		const SIG: FunctionSignature = make_signature!(
-			new fn(SIGNATURE_PREFERENCES),
-			(<u8>::SIGNATURE),
-		);
-		let name = SIG.as_str();
-		similar_asserts::assert_eq!(name, "some_funk(uint8)");
-	}
-
-	#[test]
-	fn make_func_with_2_args() {
-		const SIG: FunctionSignature = make_signature!(
-			new fn(SIGNATURE_PREFERENCES),
-			(u8::SIGNATURE),
-			(<Vec<u32>>::SIGNATURE),
-		);
-		let name = SIG.as_str();
-		similar_asserts::assert_eq!(name, "some_funk(uint8,uint32[])");
-	}
-
-	#[test]
-	fn make_func_with_3_args() {
-		const SIG: FunctionSignature = make_signature!(
-			new fn(SIGNATURE_PREFERENCES),
-			(<u8>::SIGNATURE),
-			(<u32>::SIGNATURE),
-			(<Vec<u32>>::SIGNATURE),
-		);
-		let name = SIG.as_str();
-		similar_asserts::assert_eq!(name, "some_funk(uint8,uint32,uint32[])");
-	}
-
-	#[test]
-	fn make_slice_from_signature() {
-		const SIG: FunctionSignature = make_signature!(
-			new fn(SIGNATURE_PREFERENCES),
-			(<u8>::SIGNATURE),
-			(<u32>::SIGNATURE),
-			(<Vec<u32>>::SIGNATURE),
-		);
-		const NAME: [u8; SIG.unit.len] = {
-			let mut name: [u8; SIG.unit.len] = [0; SIG.unit.len];
-			let mut i = 0;
-			while i < SIG.unit.len {
-				name[i] = SIG.unit.data[i];
-				i += 1;
-			}
-			name
-		};
-		similar_asserts::assert_eq!(&NAME, b"some_funk(uint8,uint32,uint32[])");
 	}
 
 	#[test]
modifiedcrates/evm-coder/src/lib.rsdiffbeforeafterboth
--- a/crates/evm-coder/src/lib.rs
+++ b/crates/evm-coder/src/lib.rs
@@ -122,7 +122,7 @@
 	use primitive_types::{U256, H160, H256};
 	use core::str::from_utf8;
 
-	use crate::custom_signature::{SignatureUnit, SIGNATURE_SIZE_LIMIT};
+	use crate::custom_signature::SignatureUnit;
 
 	pub trait Signature {
 		const SIGNATURE: SignatureUnit;
@@ -133,14 +133,14 @@
 	}
 
 	impl Signature for bool {
-		make_signature!(new fixed("bool"));
+		const SIGNATURE: SignatureUnit = make_signature!(new fixed("bool"));
 	}
 
 	macro_rules! define_simple_type {
 		(type $ident:ident = $ty:ty) => {
 			pub type $ident = $ty;
 			impl Signature for $ty {
-				make_signature!(new fixed(stringify!($ident)));
+				const SIGNATURE: SignatureUnit = make_signature!(new fixed(stringify!($ident)));
 			}
 		};
 	}
@@ -165,7 +165,7 @@
 	#[derive(Default, Debug)]
 	pub struct bytes(pub Vec<u8>);
 	impl Signature for bytes {
-		make_signature!(new fixed("bytes"));
+		const SIGNATURE: SignatureUnit = make_signature!(new fixed("bytes"));
 	}
 
 	/// Solidity doesn't have `void` type, however we have special implementation
@@ -259,7 +259,7 @@
 	}
 
 	impl Signature for EthCrossAccount {
-		make_signature!(new fixed("(address,uint256)"));
+		const SIGNATURE: SignatureUnit = make_signature!(new fixed("(address,uint256)"));
 	}
 
 	/// Convert `CrossAccountId` to `uint256`.
modifiedcrates/evm-coder/src/solidity.rsdiffbeforeafterboth
--- a/crates/evm-coder/src/solidity.rs
+++ b/crates/evm-coder/src/solidity.rs
@@ -32,7 +32,7 @@
 	cmp::Reverse,
 };
 use impl_trait_for_tuples::impl_for_tuples;
-use crate::{types::*, custom_signature::FunctionSignature};
+use crate::{types::*, custom_signature::SignatureUnit};
 
 #[derive(Default)]
 pub struct TypeCollector {
@@ -486,7 +486,7 @@
 	pub docs: &'static [&'static str],
 	pub selector: u32,
 	pub hide: bool,
-	pub custom_signature: FunctionSignature,
+	pub custom_signature: SignatureUnit,
 	pub name: &'static str,
 	pub args: A,
 	pub result: R,
@@ -512,7 +512,7 @@
 		writeln!(
 			writer,
 			"\t{hide_comment}///  or in textual repr: {}",
-			self.custom_signature.as_str()
+			self.custom_signature.as_str().expect("bad utf-8")
 		)?;
 		write!(writer, "\t{hide_comment}function {}(", self.name)?;
 		self.args.solidity_name(writer, tc)?;
modifiedpallets/common/src/erc.rsdiffbeforeafterboth
--- a/pallets/common/src/erc.rs
+++ b/pallets/common/src/erc.rs
@@ -21,8 +21,6 @@
 	types::*,
 	execution::{Result, Error},
 	weight,
-	custom_signature::{SignatureUnit, FunctionSignature, SignaturePreferences},
-	make_signature,
 };
 pub use pallet_evm::{PrecompileOutput, PrecompileResult, PrecompileHandle, account::CrossAccountId};
 use pallet_evm_coder_substrate::dispatch_to_evm;
modifiedpallets/evm-contract-helpers/src/eth.rsdiffbeforeafterboth
--- a/pallets/evm-contract-helpers/src/eth.rs
+++ b/pallets/evm-contract-helpers/src/eth.rs
@@ -19,13 +19,7 @@
 extern crate alloc;
 use core::marker::PhantomData;
 use evm_coder::{
-	abi::AbiWriter,
-	execution::Result,
-	generate_stubgen, solidity_interface,
-	types::*,
-	ToLog,
-	custom_signature::{SignatureUnit, FunctionSignature, SignaturePreferences},
-	make_signature,
+	abi::AbiWriter, execution::Result, generate_stubgen, solidity_interface, types::*, ToLog,
 };
 use pallet_evm::{
 	ExitRevert, OnCreate, OnMethodCall, PrecompileResult, PrecompileFailure, PrecompileHandle,
modifiedpallets/fungible/src/erc.rsdiffbeforeafterboth
--- a/pallets/fungible/src/erc.rs
+++ b/pallets/fungible/src/erc.rs
@@ -19,15 +19,7 @@
 extern crate alloc;
 use core::char::{REPLACEMENT_CHARACTER, decode_utf16};
 use core::convert::TryInto;
-use evm_coder::{
-	ToLog,
-	execution::*,
-	generate_stubgen, solidity_interface,
-	types::*,
-	weight,
-	custom_signature::{SignatureUnit, FunctionSignature, SignaturePreferences},
-	make_signature,
-};
+use evm_coder::{ToLog, execution::*, generate_stubgen, solidity_interface, types::*, weight};
 use up_data_structs::CollectionMode;
 use pallet_common::erc::{CommonEvmHandler, PrecompileResult};
 use sp_std::vec::Vec;
modifiedpallets/nonfungible/src/erc.rsdiffbeforeafterboth
--- a/pallets/nonfungible/src/erc.rs
+++ b/pallets/nonfungible/src/erc.rs
@@ -24,15 +24,7 @@
 	char::{REPLACEMENT_CHARACTER, decode_utf16},
 	convert::TryInto,
 };
-use evm_coder::{
-	ToLog,
-	execution::*,
-	generate_stubgen, solidity, solidity_interface,
-	types::*,
-	weight,
-	custom_signature::{SignatureUnit, FunctionSignature, SignaturePreferences},
-	make_signature,
-};
+use evm_coder::{ToLog, execution::*, generate_stubgen, solidity, solidity_interface, types::*, weight};
 use frame_support::BoundedVec;
 use up_data_structs::{
 	TokenId, PropertyPermission, PropertyKeyPermission, Property, CollectionId, PropertyKey,
modifiedpallets/refungible/src/erc.rsdiffbeforeafterboth
--- a/pallets/refungible/src/erc.rs
+++ b/pallets/refungible/src/erc.rs
@@ -25,15 +25,7 @@
 	char::{REPLACEMENT_CHARACTER, decode_utf16},
 	convert::TryInto,
 };
-use evm_coder::{
-	ToLog,
-	execution::*,
-	generate_stubgen, solidity, solidity_interface,
-	types::*,
-	weight,
-	custom_signature::{SignatureUnit, FunctionSignature, SignaturePreferences},
-	make_signature,
-};
+use evm_coder::{ToLog, execution::*, generate_stubgen, solidity, solidity_interface, types::*, weight};
 use frame_support::{BoundedBTreeMap, BoundedVec};
 use pallet_common::{
 	CollectionHandle, CollectionPropertyPermissions,
modifiedpallets/refungible/src/erc_token.rsdiffbeforeafterboth
--- a/pallets/refungible/src/erc_token.rs
+++ b/pallets/refungible/src/erc_token.rs
@@ -29,15 +29,7 @@
 	convert::TryInto,
 	ops::Deref,
 };
-use evm_coder::{
-	ToLog,
-	execution::*,
-	generate_stubgen, solidity_interface,
-	types::*,
-	weight,
-	custom_signature::{SignatureUnit, FunctionSignature, SignaturePreferences},
-	make_signature,
-};
+use evm_coder::{ToLog, execution::*, generate_stubgen, solidity_interface, types::*, weight};
 use pallet_common::{
 	CommonWeightInfo,
 	erc::{CommonEvmHandler, PrecompileResult},
modifiedpallets/unique/src/eth/mod.rsdiffbeforeafterboth
--- a/pallets/unique/src/eth/mod.rs
+++ b/pallets/unique/src/eth/mod.rs
@@ -18,13 +18,7 @@
 
 use core::marker::PhantomData;
 use ethereum as _;
-use evm_coder::{
-	execution::*,
-	generate_stubgen, solidity, solidity_interface,
-	types::*,
-	custom_signature::{SignatureUnit, FunctionSignature, SignaturePreferences},
-	make_signature, weight,
-};
+use evm_coder::{execution::*, generate_stubgen, solidity, solidity_interface, types::*, weight};
 use frame_support::traits::Get;
 use crate::Pallet;