git.delta.rocks / unique-network / refs/commits / 2ca9f675f8fe

difftreelog

refactor abi module

Trubnikov Sergey2022-11-03parent: #20c9944.patch.diff
in: master

17 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
@@ -328,14 +328,14 @@
 	}
 }
 
-trait AbiType {
+trait AbiTypeHelper {
 	fn plain(&self) -> syn::Result<&Ident>;
 	fn is_value(&self) -> bool;
 	fn is_caller(&self) -> bool;
 	fn is_special(&self) -> bool;
 }
 
-impl AbiType for Type {
+impl AbiTypeHelper for Type {
 	fn plain(&self) -> syn::Result<&Ident> {
 		let path = parse_path(self)?;
 		let segment = parse_path_segment(path)?;
deletedcrates/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},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::SIGNATURE) 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>::SIGNATURE) 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_impl!(812		vec_tuple_string_bytes,813		Vec<(string, bytes)>,814		0xdeadbeef,815		vec![816			(817				"Test URI 0".to_string(),818				bytes(vec![819					0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11,820					0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11,821					0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11,822					0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11823				])824			),825			(826				"Test URI 1".to_string(),827				bytes(vec![828					0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22,829					0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22,830					0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22,831					0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22832				])833			),834			("Test URI 2".to_string(), bytes(vec![0x33, 0x33])),835		],836		&hex!(837			"838				deadbeef839				0000000000000000000000000000000000000000000000000000000000000020840				0000000000000000000000000000000000000000000000000000000000000003841				842				0000000000000000000000000000000000000000000000000000000000000060843				0000000000000000000000000000000000000000000000000000000000000140844				0000000000000000000000000000000000000000000000000000000000000220845846				0000000000000000000000000000000000000000000000000000000000000040847				0000000000000000000000000000000000000000000000000000000000000080848				000000000000000000000000000000000000000000000000000000000000000a849				5465737420555249203000000000000000000000000000000000000000000000850				0000000000000000000000000000000000000000000000000000000000000030851				1111111111111111111111111111111111111111111111111111111111111111852				1111111111111111111111111111111100000000000000000000000000000000853854				0000000000000000000000000000000000000000000000000000000000000040855				0000000000000000000000000000000000000000000000000000000000000080856				000000000000000000000000000000000000000000000000000000000000000a857				5465737420555249203100000000000000000000000000000000000000000000858				000000000000000000000000000000000000000000000000000000000000002f859				2222222222222222222222222222222222222222222222222222222222222222860				2222222222222222222222222222220000000000000000000000000000000000861862				0000000000000000000000000000000000000000000000000000000000000040863				0000000000000000000000000000000000000000000000000000000000000080864				000000000000000000000000000000000000000000000000000000000000000a865				5465737420555249203200000000000000000000000000000000000000000000866				0000000000000000000000000000000000000000000000000000000000000002867				3333000000000000000000000000000000000000000000000000000000000000868			"869		)870	);871872	#[test]873	fn dynamic_after_static() {874		let mut encoder = AbiWriter::new();875		encoder.bool(&true);876		encoder.string("test");877		let encoded = encoder.finish();878879		let mut encoder = AbiWriter::new();880		encoder.bool(&true);881		// Offset to subresult882		encoder.uint32(&(32 * 2));883		// Len of "test"884		encoder.uint32(&4);885		encoder.write_padright(&[b't', b'e', b's', b't']);886		let alternative_encoded = encoder.finish();887888		assert_eq!(encoded, alternative_encoded);889890		let mut decoder = AbiReader::new(&encoded);891		assert!(decoder.bool().unwrap());892		assert_eq!(decoder.string().unwrap(), "test");893	}894895	#[test]896	fn mint_sample() {897		let (call, mut decoder) = AbiReader::new_call(&hex!(898			"899				50bb4e7f900				000000000000000000000000ad2c0954693c2b5404b7e50967d3481bea432374901				0000000000000000000000000000000000000000000000000000000000000001902				0000000000000000000000000000000000000000000000000000000000000060903				0000000000000000000000000000000000000000000000000000000000000008904				5465737420555249000000000000000000000000000000000000000000000000905			"906		))907		.unwrap();908		assert_eq!(call, u32::to_be_bytes(0x50bb4e7f));909		assert_eq!(910			format!("{:?}", decoder.address().unwrap()),911			"0xad2c0954693c2b5404b7e50967d3481bea432374"912		);913		assert_eq!(decoder.uint32().unwrap(), 1);914		assert_eq!(decoder.string().unwrap(), "Test URI");915	}916917	#[test]918	fn parse_vec_with_dynamic_type() {919		let decoded_data = (920			0x36543006,921			vec![922				(1.into(), "Test URI 0".to_string()),923				(11.into(), "Test URI 1".to_string()),924				(12.into(), "Test URI 2".to_string()),925			],926		);927928		let encoded_data = &hex!(929			"930				36543006931				00000000000000000000000053744e6da587ba10b32a2554d2efdcd985bc27a3 // address932				0000000000000000000000000000000000000000000000000000000000000040 // offset of (uint256, string)[]933				0000000000000000000000000000000000000000000000000000000000000003 // length of (uint256, string)[]934935				0000000000000000000000000000000000000000000000000000000000000060 // offset of first elem936				00000000000000000000000000000000000000000000000000000000000000e0 // offset of second elem937				0000000000000000000000000000000000000000000000000000000000000160 // offset of third elem938939				0000000000000000000000000000000000000000000000000000000000000001 // first token id?   					#60940				0000000000000000000000000000000000000000000000000000000000000040 // offset of string941				000000000000000000000000000000000000000000000000000000000000000a // size of string942				5465737420555249203000000000000000000000000000000000000000000000 // string943944				000000000000000000000000000000000000000000000000000000000000000b // second token id? Why ==11?			#e0945				0000000000000000000000000000000000000000000000000000000000000040 // offset of string946				000000000000000000000000000000000000000000000000000000000000000a // size of string947				5465737420555249203100000000000000000000000000000000000000000000 // string948949				000000000000000000000000000000000000000000000000000000000000000c // third token id?  Why ==12?			#160950				0000000000000000000000000000000000000000000000000000000000000040 // offset of string951				000000000000000000000000000000000000000000000000000000000000000a // size of string952				5465737420555249203200000000000000000000000000000000000000000000 // string953			"954		);955956		let (call, mut decoder) = AbiReader::new_call(encoded_data).unwrap();957		assert_eq!(call, u32::to_be_bytes(decoded_data.0));958		let address = decoder.address().unwrap();959		let data = <Vec<(uint256, string)>>::abi_read(&mut decoder).unwrap();960		assert_eq!(data, decoded_data.1);961962		let mut writer = AbiWriter::new_call(decoded_data.0);963		address.abi_write(&mut writer);964		decoded_data.1.abi_write(&mut writer);965		let ed = writer.finish();966		similar_asserts::assert_eq!(encoded_data, ed.as_slice());967	}968}
addedcrates/evm-coder/src/abi/impls.rsdiffbeforeafterboth
--- /dev/null
+++ b/crates/evm-coder/src/abi/impls.rs
@@ -0,0 +1,303 @@
+use crate::{
+	execution::{Result, ResultWithPostInfo, WithPostDispatchInfo},
+	types::*,
+	make_signature,
+	custom_signature::SignatureUnit,
+};
+use super::{traits::*, ABI_ALIGNMENT, AbiReader, AbiWriter};
+use primitive_types::{U256, H160};
+
+#[cfg(not(feature = "std"))]
+use alloc::vec::Vec;
+
+macro_rules! impl_abi_readable {
+	($ty:ty, $method:ident, $dynamic:literal) => {
+		impl sealed::CanBePlacedInVec for $ty {}
+
+		impl AbiType for $ty {
+			const SIGNATURE: SignatureUnit = make_signature!(new fixed(stringify!($ty)));
+
+			fn is_dynamic() -> bool {
+				$dynamic
+			}
+
+			fn size() -> usize {
+				ABI_ALIGNMENT
+			}
+		}
+
+		impl AbiRead for $ty {
+			fn abi_read(reader: &mut AbiReader) -> Result<$ty> {
+				reader.$method()
+			}
+		}
+	};
+}
+
+impl_abi_readable!(uint32, uint32, false);
+impl_abi_readable!(uint64, uint64, false);
+impl_abi_readable!(uint128, uint128, false);
+impl_abi_readable!(uint256, uint256, false);
+impl_abi_readable!(bytes4, bytes4, false);
+impl_abi_readable!(address, address, false);
+impl_abi_readable!(string, string, true);
+
+impl sealed::CanBePlacedInVec for bool {}
+
+impl AbiType for bool {
+	const SIGNATURE: SignatureUnit = make_signature!(new fixed("bool"));
+
+	fn is_dynamic() -> bool {
+		false
+	}
+	fn size() -> usize {
+		ABI_ALIGNMENT
+	}
+}
+impl AbiRead for bool {
+	fn abi_read(reader: &mut AbiReader) -> Result<bool> {
+		reader.bool()
+	}
+}
+
+impl AbiType for uint8 {
+	const SIGNATURE: SignatureUnit = make_signature!(new fixed("uint8"));
+
+	fn is_dynamic() -> bool {
+		false
+	}
+	fn size() -> usize {
+		ABI_ALIGNMENT
+	}
+}
+impl AbiRead for uint8 {
+	fn abi_read(reader: &mut AbiReader) -> Result<uint8> {
+		reader.uint8()
+	}
+}
+
+impl AbiType for bytes {
+	const SIGNATURE: SignatureUnit = make_signature!(new fixed("bytes"));
+
+	fn is_dynamic() -> bool {
+		true
+	}
+	fn size() -> usize {
+		ABI_ALIGNMENT
+	}
+}
+impl AbiRead for bytes {
+	fn abi_read(reader: &mut AbiReader) -> Result<bytes> {
+		Ok(bytes(reader.bytes()?))
+	}
+}
+
+impl<R: AbiRead + sealed::CanBePlacedInVec> AbiRead for Vec<R> {
+	fn abi_read(reader: &mut AbiReader) -> Result<Vec<R>> {
+		let mut sub = reader.subresult(None)?;
+		let size = sub.uint32()? as usize;
+		sub.subresult_offset = sub.offset;
+		let mut out = Vec::with_capacity(size);
+		for _ in 0..size {
+			out.push(<R>::abi_read(&mut sub)?);
+		}
+		Ok(out)
+	}
+}
+
+impl<R: AbiType> AbiType for Vec<R> {
+	const SIGNATURE: SignatureUnit = make_signature!(new nameof(R::SIGNATURE) fixed("[]"));
+
+	fn is_dynamic() -> bool {
+		true
+	}
+
+	fn size() -> usize {
+		ABI_ALIGNMENT
+	}
+}
+
+impl sealed::CanBePlacedInVec for EthCrossAccount {}
+
+impl AbiType for EthCrossAccount {
+	const SIGNATURE: SignatureUnit = make_signature!(new fixed("(address,uint256)"));
+
+	fn is_dynamic() -> bool {
+		address::is_dynamic() || uint256::is_dynamic()
+	}
+
+	fn size() -> usize {
+		<address as AbiType>::size() + <uint256 as AbiType>::size()
+	}
+}
+
+impl AbiRead for EthCrossAccount {
+	fn abi_read(reader: &mut AbiReader) -> Result<EthCrossAccount> {
+		let size = if !EthCrossAccount::is_dynamic() {
+			Some(<EthCrossAccount as AbiType>::size())
+		} else {
+			None
+		};
+		let mut subresult = reader.subresult(size)?;
+		let eth = <address>::abi_read(&mut subresult)?;
+		let sub = <uint256>::abi_read(&mut subresult)?;
+
+		Ok(EthCrossAccount { eth, sub })
+	}
+}
+
+impl AbiWrite for EthCrossAccount {
+	fn abi_write(&self, writer: &mut AbiWriter) {
+		self.eth.abi_write(writer);
+		self.sub.abi_write(writer);
+	}
+}
+
+macro_rules! impl_abi_writeable {
+	($ty:ty, $method:ident) => {
+		impl AbiWrite for $ty {
+			fn abi_write(&self, writer: &mut AbiWriter) {
+				writer.$method(&self)
+			}
+		}
+	};
+}
+
+impl_abi_writeable!(u8, uint8);
+impl_abi_writeable!(u32, uint32);
+impl_abi_writeable!(u128, uint128);
+impl_abi_writeable!(U256, uint256);
+impl_abi_writeable!(H160, address);
+impl_abi_writeable!(bool, bool);
+impl_abi_writeable!(&str, string);
+
+impl AbiWrite for string {
+	fn abi_write(&self, writer: &mut AbiWriter) {
+		writer.string(self)
+	}
+}
+
+impl AbiWrite for bytes {
+	fn abi_write(&self, writer: &mut AbiWriter) {
+		writer.bytes(self.0.as_slice())
+	}
+}
+
+impl<T: AbiWrite + AbiType> AbiWrite for Vec<T> {
+	fn abi_write(&self, writer: &mut AbiWriter) {
+		let is_dynamic = T::is_dynamic();
+		let mut sub = if is_dynamic {
+			AbiWriter::new_dynamic(is_dynamic)
+		} else {
+			AbiWriter::new()
+		};
+
+		// Write items count
+		(self.len() as u32).abi_write(&mut sub);
+
+		for item in self {
+			item.abi_write(&mut sub);
+		}
+		writer.write_subresult(sub);
+	}
+}
+
+impl AbiWrite for () {
+	fn abi_write(&self, _writer: &mut AbiWriter) {}
+}
+
+/// This particular AbiWrite implementation should be split to another trait,
+/// which only implements `to_result`, but due to lack of specialization feature
+/// in stable Rust, we can't have blanket impl of this trait `for T where T: AbiWrite`,
+/// so here we abusing default trait methods for it
+impl<T: AbiWrite> AbiWrite for ResultWithPostInfo<T> {
+	fn abi_write(&self, _writer: &mut AbiWriter) {
+		debug_assert!(false, "shouldn't be called, see comment")
+	}
+	fn to_result(&self) -> ResultWithPostInfo<AbiWriter> {
+		match self {
+			Ok(v) => Ok(WithPostDispatchInfo {
+				post_info: v.post_info.clone(),
+				data: {
+					let mut out = AbiWriter::new();
+					v.data.abi_write(&mut out);
+					out
+				},
+			}),
+			Err(e) => Err(e.clone()),
+		}
+	}
+}
+
+macro_rules! impl_tuples {
+	($($ident:ident)+) => {
+		impl<$($ident: AbiType,)+> AbiType for ($($ident,)+)
+		where
+        $(
+            $ident: AbiType,
+        )+
+		{
+            const SIGNATURE: SignatureUnit = make_signature!(
+                new fixed("(")
+                $(nameof(<$ident>::SIGNATURE) fixed(","))+
+                shift_left(1)
+                fixed(")")
+            );
+
+			fn is_dynamic() -> bool {
+				false
+				$(
+					|| <$ident>::is_dynamic()
+				)*
+			}
+
+			fn size() -> usize {
+				0 $(+ <$ident>::size())+
+			}
+		}
+
+		impl<$($ident),+> sealed::CanBePlacedInVec for ($($ident,)+) {}
+
+		impl<$($ident),+> AbiRead for ($($ident,)+)
+		where
+			$($ident: AbiRead,)+
+			($($ident,)+): AbiType,
+		{
+			fn abi_read(reader: &mut AbiReader) -> Result<($($ident,)+)> {
+				let size = if !<($($ident,)+)>::is_dynamic() { Some(<($($ident,)+)>::size()) } else { None };
+				let mut subresult = reader.subresult(size)?;
+				Ok((
+					$(<$ident>::abi_read(&mut subresult)?,)+
+				))
+			}
+		}
+
+		#[allow(non_snake_case)]
+		impl<$($ident),+> AbiWrite for ($($ident,)+)
+		where
+			$($ident: AbiWrite,)+
+		{
+			fn abi_write(&self, writer: &mut AbiWriter) {
+				let ($($ident,)+) = self;
+				if writer.is_dynamic {
+					let mut sub = AbiWriter::new();
+					$($ident.abi_write(&mut sub);)+
+					writer.write_subresult(sub);
+				} else {
+					$($ident.abi_write(writer);)+
+				}
+			}
+		}
+	};
+}
+
+impl_tuples! {A}
+impl_tuples! {A B}
+impl_tuples! {A B C}
+impl_tuples! {A B C D}
+impl_tuples! {A B C D E}
+impl_tuples! {A B C D E F}
+impl_tuples! {A B C D E F G}
+impl_tuples! {A B C D E F G H}
+impl_tuples! {A B C D E F G H I}
+impl_tuples! {A B C D E F G H I J}
addedcrates/evm-coder/src/abi/mod.rsdiffbeforeafterboth
--- /dev/null
+++ b/crates/evm-coder/src/abi/mod.rs
@@ -0,0 +1,339 @@
+// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
+// This file is part of Unique Network.
+
+// Unique Network is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// Unique Network is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
+
+//! Implementation of EVM RLP reader/writer
+
+#![allow(dead_code)]
+
+mod traits;
+pub use traits::*;
+mod impls;
+
+#[cfg(test)]
+mod test;
+
+#[cfg(not(feature = "std"))]
+use alloc::vec::Vec;
+use evm_core::ExitError;
+use primitive_types::{H160, U256};
+
+use crate::{
+	execution::{Result, Error},
+	types::*,
+};
+
+const ABI_ALIGNMENT: usize = 32;
+
+/// View into RLP data, which provides method to read typed items from it
+#[derive(Clone)]
+pub struct AbiReader<'i> {
+	buf: &'i [u8],
+	subresult_offset: usize,
+	offset: usize,
+}
+impl<'i> AbiReader<'i> {
+	/// Start reading RLP buffer, assuming there is no padding bytes
+	pub fn new(buf: &'i [u8]) -> Self {
+		Self {
+			buf,
+			subresult_offset: 0,
+			offset: 0,
+		}
+	}
+	/// Start reading RLP buffer, parsing first 4 bytes as selector
+	pub fn new_call(buf: &'i [u8]) -> Result<(bytes4, Self)> {
+		if buf.len() < 4 {
+			return Err(Error::Error(ExitError::OutOfOffset));
+		}
+		let mut method_id = [0; 4];
+		method_id.copy_from_slice(&buf[0..4]);
+
+		Ok((
+			method_id,
+			Self {
+				buf,
+				subresult_offset: 4,
+				offset: 4,
+			},
+		))
+	}
+
+	fn read_pad<const S: usize>(
+		buf: &[u8],
+		offset: usize,
+		pad_start: usize,
+		pad_size: usize,
+		block_start: usize,
+		block_size: usize,
+	) -> Result<[u8; S]> {
+		if buf.len() - offset < ABI_ALIGNMENT {
+			return Err(Error::Error(ExitError::OutOfOffset));
+		}
+		let mut block = [0; S];
+		let is_pad_zeroed = buf[pad_start..pad_size].iter().all(|&v| v == 0);
+		if !is_pad_zeroed {
+			return Err(Error::Error(ExitError::InvalidRange));
+		}
+		block.copy_from_slice(&buf[block_start..block_size]);
+		Ok(block)
+	}
+
+	fn read_padleft<const S: usize>(&mut self) -> Result<[u8; S]> {
+		let offset = self.offset;
+		self.offset += ABI_ALIGNMENT;
+		Self::read_pad(
+			self.buf,
+			offset,
+			offset,
+			offset + ABI_ALIGNMENT - S,
+			offset + ABI_ALIGNMENT - S,
+			offset + ABI_ALIGNMENT,
+		)
+	}
+
+	fn read_padright<const S: usize>(&mut self) -> Result<[u8; S]> {
+		let offset = self.offset;
+		self.offset += ABI_ALIGNMENT;
+		Self::read_pad(
+			self.buf,
+			offset,
+			offset + S,
+			offset + ABI_ALIGNMENT,
+			offset,
+			offset + S,
+		)
+	}
+
+	/// Read [`H160`] at current position, then advance
+	pub fn address(&mut self) -> Result<H160> {
+		Ok(H160(self.read_padleft()?))
+	}
+
+	/// Read [`bool`] at current position, then advance
+	pub fn bool(&mut self) -> Result<bool> {
+		let data: [u8; 1] = self.read_padleft()?;
+		match data[0] {
+			0 => Ok(false),
+			1 => Ok(true),
+			_ => Err(Error::Error(ExitError::InvalidRange)),
+		}
+	}
+
+	/// Read [`[u8; 4]`] at current position, then advance
+	pub fn bytes4(&mut self) -> Result<[u8; 4]> {
+		self.read_padright()
+	}
+
+	/// Read [`Vec<u8>`] at current position, then advance
+	pub fn bytes(&mut self) -> Result<Vec<u8>> {
+		let mut subresult = self.subresult(None)?;
+		let length = subresult.uint32()? as usize;
+		if subresult.buf.len() < subresult.offset + length {
+			return Err(Error::Error(ExitError::OutOfOffset));
+		}
+		Ok(subresult.buf[subresult.offset..subresult.offset + length].into())
+	}
+
+	/// Read [`string`] at current position, then advance
+	pub fn string(&mut self) -> Result<string> {
+		string::from_utf8(self.bytes()?).map_err(|_| Error::Error(ExitError::InvalidRange))
+	}
+
+	/// Read [`u8`] at current position, then advance
+	pub fn uint8(&mut self) -> Result<u8> {
+		Ok(self.read_padleft::<1>()?[0])
+	}
+
+	/// Read [`u32`] at current position, then advance
+	pub fn uint32(&mut self) -> Result<u32> {
+		Ok(u32::from_be_bytes(self.read_padleft()?))
+	}
+
+	/// Read [`u128`] at current position, then advance
+	pub fn uint128(&mut self) -> Result<u128> {
+		Ok(u128::from_be_bytes(self.read_padleft()?))
+	}
+
+	/// Read [`U256`] at current position, then advance
+	pub fn uint256(&mut self) -> Result<U256> {
+		let buf: [u8; 32] = self.read_padleft()?;
+		Ok(U256::from_big_endian(&buf))
+	}
+
+	/// Read [`u64`] at current position, then advance
+	pub fn uint64(&mut self) -> Result<u64> {
+		Ok(u64::from_be_bytes(self.read_padleft()?))
+	}
+
+	/// Read [`usize`] at current position, then advance
+	#[deprecated = "dangerous, as usize may have different width in wasm and native execution"]
+	pub fn read_usize(&mut self) -> Result<usize> {
+		Ok(usize::from_be_bytes(self.read_padleft()?))
+	}
+
+	/// Slice recursive buffer, advance one word for buffer offset
+	/// If `size` is [`None`] then [`Self::offset`] and [`Self::subresult_offset`] evals from [`Self::buf`].
+	fn subresult(&mut self, size: Option<usize>) -> Result<AbiReader<'i>> {
+		let subresult_offset = self.subresult_offset;
+		let offset = if let Some(size) = size {
+			self.offset += size;
+			self.subresult_offset += size;
+			0
+		} else {
+			self.uint32()? as usize
+		};
+
+		if offset + self.subresult_offset > self.buf.len() {
+			return Err(Error::Error(ExitError::InvalidRange));
+		}
+
+		let new_offset = offset + subresult_offset;
+		Ok(AbiReader {
+			buf: self.buf,
+			subresult_offset: new_offset,
+			offset: new_offset,
+		})
+	}
+
+	/// Is this parser reached end of buffer?
+	pub fn is_finished(&self) -> bool {
+		self.buf.len() == self.offset
+	}
+}
+
+/// Writer for RLP encoded data
+#[derive(Default)]
+pub struct AbiWriter {
+	static_part: Vec<u8>,
+	dynamic_part: Vec<(usize, AbiWriter)>,
+	had_call: bool,
+	is_dynamic: bool,
+}
+impl AbiWriter {
+	/// Initialize internal buffers for output data, assuming no padding required
+	pub fn new() -> Self {
+		Self::default()
+	}
+
+	/// Initialize internal buffers with data size
+	pub fn new_dynamic(is_dynamic: bool) -> Self {
+		Self {
+			is_dynamic,
+			..Default::default()
+		}
+	}
+	/// Initialize internal buffers, inserting method selector at beginning
+	pub fn new_call(method_id: u32) -> Self {
+		let mut val = Self::new();
+		val.static_part.extend(&method_id.to_be_bytes());
+		val.had_call = true;
+		val
+	}
+
+	fn write_padleft(&mut self, block: &[u8]) {
+		assert!(block.len() <= ABI_ALIGNMENT);
+		self.static_part
+			.extend(&[0; ABI_ALIGNMENT][0..ABI_ALIGNMENT - block.len()]);
+		self.static_part.extend(block);
+	}
+
+	fn write_padright(&mut self, block: &[u8]) {
+		assert!(block.len() <= ABI_ALIGNMENT);
+		self.static_part.extend(block);
+		self.static_part
+			.extend(&[0; ABI_ALIGNMENT][0..ABI_ALIGNMENT - block.len()]);
+	}
+
+	/// Write [`H160`] to end of buffer
+	pub fn address(&mut self, address: &H160) {
+		self.write_padleft(&address.0)
+	}
+
+	/// Write [`bool`] to end of buffer
+	pub fn bool(&mut self, value: &bool) {
+		self.write_padleft(&[if *value { 1 } else { 0 }])
+	}
+
+	/// Write [`u8`] to end of buffer
+	pub fn uint8(&mut self, value: &u8) {
+		self.write_padleft(&[*value])
+	}
+
+	/// Write [`u32`] to end of buffer
+	pub fn uint32(&mut self, value: &u32) {
+		self.write_padleft(&u32::to_be_bytes(*value))
+	}
+
+	/// Write [`u128`] to end of buffer
+	pub fn uint128(&mut self, value: &u128) {
+		self.write_padleft(&u128::to_be_bytes(*value))
+	}
+
+	/// Write [`U256`] to end of buffer
+	pub fn uint256(&mut self, value: &U256) {
+		let mut out = [0; 32];
+		value.to_big_endian(&mut out);
+		self.write_padleft(&out)
+	}
+
+	/// Write [`usize`] to end of buffer
+	#[deprecated = "dangerous, as usize may have different width in wasm and native execution"]
+	pub fn write_usize(&mut self, value: &usize) {
+		self.write_padleft(&usize::to_be_bytes(*value))
+	}
+
+	/// Append recursive data, writing pending offset at end of buffer
+	pub fn write_subresult(&mut self, result: Self) {
+		self.dynamic_part.push((self.static_part.len(), result));
+		// Empty block, to be filled later
+		self.write_padleft(&[]);
+	}
+
+	fn memory(&mut self, value: &[u8]) {
+		let mut sub = Self::new();
+		sub.uint32(&(value.len() as u32));
+		for chunk in value.chunks(ABI_ALIGNMENT) {
+			sub.write_padright(chunk);
+		}
+		self.write_subresult(sub);
+	}
+
+	/// Append recursive [`str`] at end of buffer
+	pub fn string(&mut self, value: &str) {
+		self.memory(value.as_bytes())
+	}
+
+	/// Append recursive [`[u8]`] at end of buffer
+	pub fn bytes(&mut self, value: &[u8]) {
+		self.memory(value)
+	}
+
+	/// Finish writer, concatenating all internal buffers
+	pub fn finish(mut self) -> Vec<u8> {
+		for (static_offset, part) in self.dynamic_part {
+			let part_offset = self.static_part.len()
+				- if self.had_call { 4 } else { 0 }
+				- if self.is_dynamic { ABI_ALIGNMENT } else { 0 };
+
+			let encoded_dynamic_offset = usize::to_be_bytes(part_offset);
+			let start = static_offset + ABI_ALIGNMENT - encoded_dynamic_offset.len();
+			let stop = static_offset + ABI_ALIGNMENT;
+			self.static_part[start..stop].copy_from_slice(&encoded_dynamic_offset);
+			self.static_part.extend(part.finish())
+		}
+		self.static_part
+	}
+}
addedcrates/evm-coder/src/abi/test.rsdiffbeforeafterboth
--- /dev/null
+++ b/crates/evm-coder/src/abi/test.rs
@@ -0,0 +1,297 @@
+use crate::{
+	abi::{AbiRead, AbiWrite},
+	types::*,
+};
+
+use super::{AbiReader, AbiWriter};
+use hex_literal::hex;
+use primitive_types::{H160, U256};
+use concat_idents::concat_idents;
+
+macro_rules! test_impl {
+    ($name:ident, $type:ty, $function_identifier:expr, $decoded_data:expr, $encoded_data:expr) => {
+        concat_idents!(test_name = encode_decode_, $name {
+            #[test]
+            fn test_name() {
+                let function_identifier: u32 = $function_identifier;
+                let decoded_data = $decoded_data;
+                let encoded_data = $encoded_data;
+
+                let (call, mut decoder) = AbiReader::new_call(encoded_data).unwrap();
+                assert_eq!(call, u32::to_be_bytes(function_identifier));
+                let data = <$type>::abi_read(&mut decoder).unwrap();
+                assert_eq!(data, decoded_data);
+
+                let mut writer = AbiWriter::new_call(function_identifier);
+                decoded_data.abi_write(&mut writer);
+                let ed = writer.finish();
+                similar_asserts::assert_eq!(encoded_data, ed.as_slice());
+            }
+        });
+    };
+}
+
+macro_rules! test_impl_uint {
+	($type:ident) => {
+		test_impl!(
+			$type,
+			$type,
+			0xdeadbeef,
+			255 as $type,
+			&hex!(
+				"
+                    deadbeef
+                    00000000000000000000000000000000000000000000000000000000000000ff
+                "
+			)
+		);
+	};
+}
+
+test_impl_uint!(uint8);
+test_impl_uint!(uint32);
+test_impl_uint!(uint128);
+
+test_impl!(
+	uint256,
+	uint256,
+	0xdeadbeef,
+	U256([255, 0, 0, 0]),
+	&hex!(
+		"
+            deadbeef
+            00000000000000000000000000000000000000000000000000000000000000ff
+        "
+	)
+);
+
+test_impl!(
+    vec_tuple_address_uint256,
+    Vec<(address, uint256)>,
+    0x1ACF2D55,
+    vec![
+        (
+            H160(hex!("2D2FF76104B7BACB2E8F6731D5BFC184EBECDDBC")),
+            U256([10, 0, 0, 0]),
+        ),
+        (
+            H160(hex!("AB8E3D9134955566483B11E6825C9223B6737B10")),
+            U256([20, 0, 0, 0]),
+        ),
+        (
+            H160(hex!("8C582BDF2953046705FC56F189385255EFC1BE18")),
+            U256([30, 0, 0, 0]),
+        ),
+    ],
+    &hex!(
+        "
+            1ACF2D55
+            0000000000000000000000000000000000000000000000000000000000000020 // offset of (address, uint256)[]
+            0000000000000000000000000000000000000000000000000000000000000003 // length of (address, uint256)[]
+
+            0000000000000000000000002D2FF76104B7BACB2E8F6731D5BFC184EBECDDBC // address
+            000000000000000000000000000000000000000000000000000000000000000A // uint256
+
+            000000000000000000000000AB8E3D9134955566483B11E6825C9223B6737B10 // address
+            0000000000000000000000000000000000000000000000000000000000000014 // uint256
+
+            0000000000000000000000008C582BDF2953046705FC56F189385255EFC1BE18 // address
+            000000000000000000000000000000000000000000000000000000000000001E // uint256
+        "
+    )
+);
+
+test_impl!(
+    vec_tuple_uint256_string,
+    Vec<(uint256, string)>,
+    0xdeadbeef,
+    vec![
+        (1.into(), "Test URI 0".to_string()),
+        (11.into(), "Test URI 1".to_string()),
+        (12.into(), "Test URI 2".to_string()),
+    ],
+    &hex!(
+        "
+            deadbeef
+            0000000000000000000000000000000000000000000000000000000000000020 // offset of (uint256, string)[]
+            0000000000000000000000000000000000000000000000000000000000000003 // length of (uint256, string)[]
+
+            0000000000000000000000000000000000000000000000000000000000000060 // offset of first elem
+            00000000000000000000000000000000000000000000000000000000000000e0 // offset of second elem
+            0000000000000000000000000000000000000000000000000000000000000160 // offset of third elem
+
+            0000000000000000000000000000000000000000000000000000000000000001 // first token id?   					#60
+            0000000000000000000000000000000000000000000000000000000000000040 // offset of string
+            000000000000000000000000000000000000000000000000000000000000000a // size of string
+            5465737420555249203000000000000000000000000000000000000000000000 // string
+
+            000000000000000000000000000000000000000000000000000000000000000b // second token id? Why ==11?			#e0
+            0000000000000000000000000000000000000000000000000000000000000040 // offset of string
+            000000000000000000000000000000000000000000000000000000000000000a // size of string
+            5465737420555249203100000000000000000000000000000000000000000000 // string
+
+            000000000000000000000000000000000000000000000000000000000000000c // third token id?  Why ==12?			#160
+            0000000000000000000000000000000000000000000000000000000000000040 // offset of string
+            000000000000000000000000000000000000000000000000000000000000000a // size of string
+            5465737420555249203200000000000000000000000000000000000000000000 // string
+        "
+    )
+);
+
+#[test]
+fn dynamic_after_static() {
+	let mut encoder = AbiWriter::new();
+	encoder.bool(&true);
+	encoder.string("test");
+	let encoded = encoder.finish();
+
+	let mut encoder = AbiWriter::new();
+	encoder.bool(&true);
+	// Offset to subresult
+	encoder.uint32(&(32 * 2));
+	// Len of "test"
+	encoder.uint32(&4);
+	encoder.write_padright(&[b't', b'e', b's', b't']);
+	let alternative_encoded = encoder.finish();
+
+	assert_eq!(encoded, alternative_encoded);
+
+	let mut decoder = AbiReader::new(&encoded);
+	assert!(decoder.bool().unwrap());
+	assert_eq!(decoder.string().unwrap(), "test");
+}
+
+#[test]
+fn mint_sample() {
+	let (call, mut decoder) = AbiReader::new_call(&hex!(
+		"
+            50bb4e7f
+            000000000000000000000000ad2c0954693c2b5404b7e50967d3481bea432374
+            0000000000000000000000000000000000000000000000000000000000000001
+            0000000000000000000000000000000000000000000000000000000000000060
+            0000000000000000000000000000000000000000000000000000000000000008
+            5465737420555249000000000000000000000000000000000000000000000000
+        "
+	))
+	.unwrap();
+	assert_eq!(call, u32::to_be_bytes(0x50bb4e7f));
+	assert_eq!(
+		format!("{:?}", decoder.address().unwrap()),
+		"0xad2c0954693c2b5404b7e50967d3481bea432374"
+	);
+	assert_eq!(decoder.uint32().unwrap(), 1);
+	assert_eq!(decoder.string().unwrap(), "Test URI");
+}
+
+#[test]
+fn parse_vec_with_dynamic_type() {
+	let decoded_data = (
+		0x36543006,
+		vec![
+			(1.into(), "Test URI 0".to_string()),
+			(11.into(), "Test URI 1".to_string()),
+			(12.into(), "Test URI 2".to_string()),
+		],
+	);
+
+	let encoded_data = &hex!(
+        "
+            36543006
+            00000000000000000000000053744e6da587ba10b32a2554d2efdcd985bc27a3 // address
+            0000000000000000000000000000000000000000000000000000000000000040 // offset of (uint256, string)[]
+            0000000000000000000000000000000000000000000000000000000000000003 // length of (uint256, string)[]
+
+            0000000000000000000000000000000000000000000000000000000000000060 // offset of first elem
+            00000000000000000000000000000000000000000000000000000000000000e0 // offset of second elem
+            0000000000000000000000000000000000000000000000000000000000000160 // offset of third elem
+
+            0000000000000000000000000000000000000000000000000000000000000001 // first token id?   					#60
+            0000000000000000000000000000000000000000000000000000000000000040 // offset of string
+            000000000000000000000000000000000000000000000000000000000000000a // size of string
+            5465737420555249203000000000000000000000000000000000000000000000 // string
+
+            000000000000000000000000000000000000000000000000000000000000000b // second token id? Why ==11?			#e0
+            0000000000000000000000000000000000000000000000000000000000000040 // offset of string
+            000000000000000000000000000000000000000000000000000000000000000a // size of string
+            5465737420555249203100000000000000000000000000000000000000000000 // string
+
+            000000000000000000000000000000000000000000000000000000000000000c // third token id?  Why ==12?			#160
+            0000000000000000000000000000000000000000000000000000000000000040 // offset of string
+            000000000000000000000000000000000000000000000000000000000000000a // size of string
+            5465737420555249203200000000000000000000000000000000000000000000 // string
+        "
+    );
+
+	let (call, mut decoder) = AbiReader::new_call(encoded_data).unwrap();
+	assert_eq!(call, u32::to_be_bytes(decoded_data.0));
+	let address = decoder.address().unwrap();
+	let data = <Vec<(uint256, string)>>::abi_read(&mut decoder).unwrap();
+	assert_eq!(data, decoded_data.1);
+
+	let mut writer = AbiWriter::new_call(decoded_data.0);
+	address.abi_write(&mut writer);
+	decoded_data.1.abi_write(&mut writer);
+	let ed = writer.finish();
+	similar_asserts::assert_eq!(encoded_data, ed.as_slice());
+}
+
+test_impl!(
+	vec_tuple_string_bytes,
+	Vec<(string, bytes)>,
+	0xdeadbeef,
+	vec![
+		(
+			"Test URI 0".to_string(),
+			bytes(vec![
+				0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11,
+				0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11,
+				0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11,
+				0x11, 0x11, 0x11, 0x11, 0x11, 0x11
+			])
+		),
+		(
+			"Test URI 1".to_string(),
+			bytes(vec![
+				0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22,
+				0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22,
+				0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22,
+				0x22, 0x22, 0x22, 0x22, 0x22
+			])
+		),
+		("Test URI 2".to_string(), bytes(vec![0x33, 0x33])),
+	],
+	&hex!(
+		"
+            deadbeef
+            0000000000000000000000000000000000000000000000000000000000000020
+            0000000000000000000000000000000000000000000000000000000000000003
+            
+            0000000000000000000000000000000000000000000000000000000000000060
+            0000000000000000000000000000000000000000000000000000000000000140
+            0000000000000000000000000000000000000000000000000000000000000220
+
+            0000000000000000000000000000000000000000000000000000000000000040
+            0000000000000000000000000000000000000000000000000000000000000080
+            000000000000000000000000000000000000000000000000000000000000000a
+            5465737420555249203000000000000000000000000000000000000000000000
+            0000000000000000000000000000000000000000000000000000000000000030
+            1111111111111111111111111111111111111111111111111111111111111111
+            1111111111111111111111111111111100000000000000000000000000000000
+
+            0000000000000000000000000000000000000000000000000000000000000040
+            0000000000000000000000000000000000000000000000000000000000000080
+            000000000000000000000000000000000000000000000000000000000000000a
+            5465737420555249203100000000000000000000000000000000000000000000
+            000000000000000000000000000000000000000000000000000000000000002f
+            2222222222222222222222222222222222222222222222222222222222222222
+            2222222222222222222222222222220000000000000000000000000000000000
+
+            0000000000000000000000000000000000000000000000000000000000000040
+            0000000000000000000000000000000000000000000000000000000000000080
+            000000000000000000000000000000000000000000000000000000000000000a
+            5465737420555249203200000000000000000000000000000000000000000000
+            0000000000000000000000000000000000000000000000000000000000000002
+            3333000000000000000000000000000000000000000000000000000000000000
+        "
+	)
+);
addedcrates/evm-coder/src/abi/traits.rsdiffbeforeafterboth
--- /dev/null
+++ b/crates/evm-coder/src/abi/traits.rs
@@ -0,0 +1,51 @@
+use super::{AbiReader, AbiWriter};
+use crate::{
+	custom_signature::*,
+	execution::{Result, ResultWithPostInfo},
+};
+use core::str::from_utf8;
+
+/// Helper for type.
+pub trait AbiType {
+	/// Signature for Etherium ABI.
+	const SIGNATURE: SignatureUnit;
+
+	/// Signature as str.
+	fn as_str() -> &'static str {
+		from_utf8(&Self::SIGNATURE.data[..Self::SIGNATURE.len]).expect("bad utf-8")
+	}
+
+	/// Is type dynamic sized.
+	fn is_dynamic() -> bool;
+
+	/// Size for type aligned to [`ABI_ALIGNMENT`].
+	fn size() -> usize;
+}
+
+/// Sealed traits.
+pub mod sealed {
+	/// Not all types can be placed in vec, i.e `Vec<u8>` is restricted, `bytes` should be used instead
+	pub trait CanBePlacedInVec {}
+}
+
+/// [`AbiReader`] implements reading of many types.
+pub trait AbiRead {
+	/// Read item from current position, advanding decoder
+	fn abi_read(reader: &mut AbiReader) -> Result<Self>
+	where
+		Self: Sized;
+}
+
+/// For questions about inability to provide custom implementations,
+/// see [`AbiRead`]
+pub trait AbiWrite {
+	/// Write value to end of specified encoder
+	fn abi_write(&self, writer: &mut AbiWriter);
+	/// Specialization for [`crate::solidity_interface`] implementation,
+	/// see comment in `impl AbiWrite for ResultWithPostInfo`
+	fn to_result(&self) -> ResultWithPostInfo<AbiWriter> {
+		let mut writer = AbiWriter::new();
+		self.abi_write(&mut writer);
+		Ok(writer.into())
+	}
+}
modifiedcrates/evm-coder/src/lib.rsdiffbeforeafterboth
--- a/crates/evm-coder/src/lib.rs
+++ b/crates/evm-coder/src/lib.rs
@@ -121,53 +121,24 @@
 	use alloc::{vec::Vec};
 	use pallet_evm::account::CrossAccountId;
 	use primitive_types::{U256, H160, H256};
-	use core::str::from_utf8;
-
-	use crate::custom_signature::SignatureUnit;
-
-	pub trait Signature {
-		const SIGNATURE: SignatureUnit;
-
-		fn as_str() -> &'static str {
-			from_utf8(&Self::SIGNATURE.data[..Self::SIGNATURE.len]).expect("bad utf-8")
-		}
-	}
-
-	impl Signature for 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 {
-				const SIGNATURE: SignatureUnit = make_signature!(new fixed(stringify!($ident)));
-			}
-		};
-	}
 
-	define_simple_type!(type address = H160);
-
-	define_simple_type!(type uint8 = u8);
-	define_simple_type!(type uint16 = u16);
-	define_simple_type!(type uint32 = u32);
-	define_simple_type!(type uint64 = u64);
-	define_simple_type!(type uint128 = u128);
-	define_simple_type!(type uint256 = U256);
-	define_simple_type!(type bytes4 = [u8; 4]);
-
-	define_simple_type!(type topic = H256);
+	pub type address = H160;
+	pub type uint8 = u8;
+	pub type uint16 = u16;
+	pub type uint32 = u32;
+	pub type uint64 = u64;
+	pub type uint128 = u128;
+	pub type uint256 = U256;
+	pub type bytes4 = [u8; 4];
+	pub type topic = H256;
 
 	#[cfg(not(feature = "std"))]
-	define_simple_type!(type string = ::alloc::string::String);
+	pub type string = ::alloc::string::String;
 	#[cfg(feature = "std")]
-	define_simple_type!(type string = ::std::string::String);
+	pub type string = ::std::string::String;
 
 	#[derive(Default, Debug, PartialEq)]
 	pub struct bytes(pub Vec<u8>);
-	impl Signature for bytes {
-		const SIGNATURE: SignatureUnit = make_signature!(new fixed("bytes"));
-	}
 
 	/// Solidity doesn't have `void` type, however we have special implementation
 	/// for empty tuple return type
@@ -257,10 +228,6 @@
 				Err("All fields of cross account is non zeroed".into())
 			}
 		}
-	}
-
-	impl Signature for EthCrossAccount {
-		const SIGNATURE: SignatureUnit = make_signature!(new fixed("(address,uint256)"));
 	}
 
 	/// Convert `CrossAccountId` to `uint256`.
modifiedcrates/evm-coder/tests/random.rsdiffbeforeafterboth
--- a/crates/evm-coder/tests/random.rs
+++ b/crates/evm-coder/tests/random.rs
@@ -16,8 +16,9 @@
 
 #![allow(dead_code)] // This test only checks that macros is not panicking
 
-use evm_coder::{ToLog, execution::Result, solidity_interface, types::*, solidity, weight};
-use evm_coder::{types::Signature};
+use evm_coder::{
+	abi::AbiType, ToLog, execution::Result, solidity_interface, types::*, solidity, weight,
+};
 
 pub struct Impls;
 
modifiedcrates/evm-coder/tests/solidity_generation.rsdiffbeforeafterboth
--- a/crates/evm-coder/tests/solidity_generation.rs
+++ b/crates/evm-coder/tests/solidity_generation.rs
@@ -14,8 +14,7 @@
 // You should have received a copy of the GNU General Public License
 // along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
 
-use evm_coder::{execution::Result, generate_stubgen, solidity_interface, types::*};
-use evm_coder::{types::Signature};
+use evm_coder::{abi::AbiType, execution::Result, generate_stubgen, solidity_interface, types::*};
 
 pub struct ERC20;
 
modifiedpallets/common/src/erc.rsdiffbeforeafterboth
--- a/pallets/common/src/erc.rs
+++ b/pallets/common/src/erc.rs
@@ -17,6 +17,7 @@
 //! This module contains the implementation of pallet methods for evm.
 
 use evm_coder::{
+	abi::AbiType,
 	solidity_interface, solidity, ToLog,
 	types::*,
 	execution::{Result, Error},
modifiedpallets/evm-contract-helpers/src/eth.rsdiffbeforeafterboth
--- a/pallets/evm-contract-helpers/src/eth.rs
+++ b/pallets/evm-contract-helpers/src/eth.rs
@@ -19,7 +19,11 @@
 extern crate alloc;
 use core::marker::PhantomData;
 use evm_coder::{
-	abi::AbiWriter, execution::Result, generate_stubgen, solidity_interface, types::*, ToLog,
+	abi::{AbiWriter, AbiType},
+	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,7 +19,9 @@
 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};
+use evm_coder::{
+	abi::AbiType, 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,7 +24,10 @@
 	char::{REPLACEMENT_CHARACTER, decode_utf16},
 	convert::TryInto,
 };
-use evm_coder::{ToLog, execution::*, generate_stubgen, solidity, solidity_interface, types::*, weight};
+use evm_coder::{
+	abi::AbiType, 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,7 +25,10 @@
 	char::{REPLACEMENT_CHARACTER, decode_utf16},
 	convert::TryInto,
 };
-use evm_coder::{ToLog, execution::*, generate_stubgen, solidity, solidity_interface, types::*, weight};
+use evm_coder::{
+	abi::AbiType, 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,7 +29,9 @@
 	convert::TryInto,
 	ops::Deref,
 };
-use evm_coder::{ToLog, execution::*, generate_stubgen, solidity_interface, types::*, weight};
+use evm_coder::{
+	abi::AbiType, ToLog, execution::*, generate_stubgen, solidity_interface, types::*, weight,
+};
 use pallet_common::{
 	CommonWeightInfo,
 	erc::{CommonEvmHandler, PrecompileResult},
modifiedpallets/unique/Cargo.tomldiffbeforeafterboth
--- a/pallets/unique/Cargo.toml
+++ b/pallets/unique/Cargo.toml
@@ -35,6 +35,7 @@
 try-runtime = ["frame-support/try-runtime"]
 limit-testing = ["up-data-structs/limit-testing"]
 stubgen = ["evm-coder/stubgen", "pallet-common/stubgen"]
+
 ################################################################################
 # Standart Dependencies
 
modifiedpallets/unique/src/eth/mod.rsdiffbeforeafterboth
--- a/pallets/unique/src/eth/mod.rs
+++ b/pallets/unique/src/eth/mod.rs
@@ -18,14 +18,16 @@
 
 use core::marker::PhantomData;
 use ethereum as _;
-use evm_coder::{execution::*, generate_stubgen, solidity, solidity_interface, types::*, weight};
+use evm_coder::{
+	abi::AbiType, execution::*, generate_stubgen, solidity, solidity_interface, types::*, weight,
+};
 use frame_support::traits::Get;
 use crate::Pallet;
 
 use pallet_common::{
 	CollectionById,
 	dispatch::CollectionDispatch,
-	erc::{static_property::key, CollectionHelpersEvents},
+	erc::{CollectionHelpersEvents, static_property::key},
 	Pallet as PalletCommon,
 };
 use pallet_evm::{account::CrossAccountId, OnMethodCall, PrecompileHandle, PrecompileResult};