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
--- a/crates/evm-coder/src/abi.rs
+++ /dev/null
@@ -1,968 +0,0 @@
-// 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)]
-
-#[cfg(not(feature = "std"))]
-use alloc::vec::Vec;
-use evm_core::ExitError;
-use primitive_types::{H160, U256};
-
-use crate::{
-	execution::{Error, ResultWithPostInfo, WithPostDispatchInfo},
-	types::*,
-	make_signature,
-	custom_signature::{SignatureUnit},
-};
-use crate::execution::Result;
-
-const ABI_ALIGNMENT: usize = 32;
-
-trait TypeHelper {
-	/// Is type dynamic sized.
-	fn is_dynamic() -> bool;
-
-	/// Size for type aligned to [`ABI_ALIGNMENT`].
-	fn size() -> usize;
-}
-
-/// 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
-	}
-}
-
-/// [`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;
-}
-
-macro_rules! impl_abi_readable {
-	($ty:ty, $method:ident, $dynamic:literal) => {
-		impl sealed::CanBePlacedInVec for $ty {}
-
-		impl TypeHelper for $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!(bool, bool, false);
-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 TypeHelper for 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 TypeHelper for 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()?))
-	}
-}
-
-mod sealed {
-	/// Not all types can be placed in vec, i.e `Vec<u8>` is restricted, `bytes` should be used instead
-	pub trait CanBePlacedInVec {}
-}
-
-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: Signature> Signature for Vec<R> {
-	const SIGNATURE: SignatureUnit = make_signature!(new nameof(R::SIGNATURE) fixed("[]"));
-}
-
-impl sealed::CanBePlacedInVec for EthCrossAccount {}
-
-impl TypeHelper for EthCrossAccount {
-	fn is_dynamic() -> bool {
-		address::is_dynamic() || uint256::is_dynamic()
-	}
-
-	fn size() -> usize {
-		<address as TypeHelper>::size() + <uint256 as TypeHelper>::size()
-	}
-}
-
-impl AbiRead for EthCrossAccount {
-	fn abi_read(reader: &mut AbiReader) -> Result<EthCrossAccount> {
-		let size = if !EthCrossAccount::is_dynamic() {
-			Some(<EthCrossAccount as TypeHelper>::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_tuples {
-	($($ident:ident)+) => {
-		impl<$($ident: TypeHelper,)+> TypeHelper for ($($ident,)+)
-		where
-			$(
-				$ident: TypeHelper,
-			)+
-		{
-			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,)+): TypeHelper,
-		{
-			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<$($ident),+> Signature for ($($ident,)+)
-		where
-		$($ident: Signature,)+
-		{
-			const SIGNATURE: SignatureUnit = make_signature!(
-				new fixed("(")
-				$(nameof(<$ident>::SIGNATURE) fixed(","))+
-				shift_left(1)
-				fixed(")")
-			);
-		}
-	};
-}
-
-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}
-
-/// 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())
-	}
-}
-
-/// 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_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 + TypeHelper> 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) {}
-}
-
-/// Helper macros to parse reader into variables
-#[deprecated]
-#[macro_export]
-macro_rules! abi_decode {
-	($reader:expr, $($name:ident: $typ:ident),+ $(,)?) => {
-		$(
-			let $name = $reader.$typ()?;
-		)+
-	}
-}
-
-/// Helper macros to construct RLP-encoded buffer
-#[deprecated]
-#[macro_export]
-macro_rules! abi_encode {
-	($($typ:ident($value:expr)),* $(,)?) => {{
-		#[allow(unused_mut)]
-		let mut writer = ::evm_coder::abi::AbiWriter::new();
-		$(
-			writer.$typ($value);
-		)*
-		writer
-	}};
-	(call $val:expr; $($typ:ident($value:expr)),* $(,)?) => {{
-		#[allow(unused_mut)]
-		let mut writer = ::evm_coder::abi::AbiWriter::new_call($val);
-		$(
-			writer.$typ($value);
-		)*
-		writer
-	}}
-}
-
-#[cfg(test)]
-pub mod test {
-	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_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
-			"
-		)
-	);
-
-	#[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());
-	}
-}
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
after · crates/evm-coder/src/abi/test.rs
1use crate::{2	abi::{AbiRead, AbiWrite},3	types::*,4};56use super::{AbiReader, AbiWriter};7use hex_literal::hex;8use primitive_types::{H160, U256};9use concat_idents::concat_idents;1011macro_rules! test_impl {12    ($name:ident, $type:ty, $function_identifier:expr, $decoded_data:expr, $encoded_data:expr) => {13        concat_idents!(test_name = encode_decode_, $name {14            #[test]15            fn test_name() {16                let function_identifier: u32 = $function_identifier;17                let decoded_data = $decoded_data;18                let encoded_data = $encoded_data;1920                let (call, mut decoder) = AbiReader::new_call(encoded_data).unwrap();21                assert_eq!(call, u32::to_be_bytes(function_identifier));22                let data = <$type>::abi_read(&mut decoder).unwrap();23                assert_eq!(data, decoded_data);2425                let mut writer = AbiWriter::new_call(function_identifier);26                decoded_data.abi_write(&mut writer);27                let ed = writer.finish();28                similar_asserts::assert_eq!(encoded_data, ed.as_slice());29            }30        });31    };32}3334macro_rules! test_impl_uint {35	($type:ident) => {36		test_impl!(37			$type,38			$type,39			0xdeadbeef,40			255 as $type,41			&hex!(42				"43                    deadbeef44                    00000000000000000000000000000000000000000000000000000000000000ff45                "46			)47		);48	};49}5051test_impl_uint!(uint8);52test_impl_uint!(uint32);53test_impl_uint!(uint128);5455test_impl!(56	uint256,57	uint256,58	0xdeadbeef,59	U256([255, 0, 0, 0]),60	&hex!(61		"62            deadbeef63            00000000000000000000000000000000000000000000000000000000000000ff64        "65	)66);6768test_impl!(69    vec_tuple_address_uint256,70    Vec<(address, uint256)>,71    0x1ACF2D55,72    vec![73        (74            H160(hex!("2D2FF76104B7BACB2E8F6731D5BFC184EBECDDBC")),75            U256([10, 0, 0, 0]),76        ),77        (78            H160(hex!("AB8E3D9134955566483B11E6825C9223B6737B10")),79            U256([20, 0, 0, 0]),80        ),81        (82            H160(hex!("8C582BDF2953046705FC56F189385255EFC1BE18")),83            U256([30, 0, 0, 0]),84        ),85    ],86    &hex!(87        "88            1ACF2D5589            0000000000000000000000000000000000000000000000000000000000000020 // offset of (address, uint256)[]90            0000000000000000000000000000000000000000000000000000000000000003 // length of (address, uint256)[]9192            0000000000000000000000002D2FF76104B7BACB2E8F6731D5BFC184EBECDDBC // address93            000000000000000000000000000000000000000000000000000000000000000A // uint2569495            000000000000000000000000AB8E3D9134955566483B11E6825C9223B6737B10 // address96            0000000000000000000000000000000000000000000000000000000000000014 // uint2569798            0000000000000000000000008C582BDF2953046705FC56F189385255EFC1BE18 // address99            000000000000000000000000000000000000000000000000000000000000001E // uint256100        "101    )102);103104test_impl!(105    vec_tuple_uint256_string,106    Vec<(uint256, string)>,107    0xdeadbeef,108    vec![109        (1.into(), "Test URI 0".to_string()),110        (11.into(), "Test URI 1".to_string()),111        (12.into(), "Test URI 2".to_string()),112    ],113    &hex!(114        "115            deadbeef116            0000000000000000000000000000000000000000000000000000000000000020 // offset of (uint256, string)[]117            0000000000000000000000000000000000000000000000000000000000000003 // length of (uint256, string)[]118119            0000000000000000000000000000000000000000000000000000000000000060 // offset of first elem120            00000000000000000000000000000000000000000000000000000000000000e0 // offset of second elem121            0000000000000000000000000000000000000000000000000000000000000160 // offset of third elem122123            0000000000000000000000000000000000000000000000000000000000000001 // first token id?   					#60124            0000000000000000000000000000000000000000000000000000000000000040 // offset of string125            000000000000000000000000000000000000000000000000000000000000000a // size of string126            5465737420555249203000000000000000000000000000000000000000000000 // string127128            000000000000000000000000000000000000000000000000000000000000000b // second token id? Why ==11?			#e0129            0000000000000000000000000000000000000000000000000000000000000040 // offset of string130            000000000000000000000000000000000000000000000000000000000000000a // size of string131            5465737420555249203100000000000000000000000000000000000000000000 // string132133            000000000000000000000000000000000000000000000000000000000000000c // third token id?  Why ==12?			#160134            0000000000000000000000000000000000000000000000000000000000000040 // offset of string135            000000000000000000000000000000000000000000000000000000000000000a // size of string136            5465737420555249203200000000000000000000000000000000000000000000 // string137        "138    )139);140141#[test]142fn dynamic_after_static() {143	let mut encoder = AbiWriter::new();144	encoder.bool(&true);145	encoder.string("test");146	let encoded = encoder.finish();147148	let mut encoder = AbiWriter::new();149	encoder.bool(&true);150	// Offset to subresult151	encoder.uint32(&(32 * 2));152	// Len of "test"153	encoder.uint32(&4);154	encoder.write_padright(&[b't', b'e', b's', b't']);155	let alternative_encoded = encoder.finish();156157	assert_eq!(encoded, alternative_encoded);158159	let mut decoder = AbiReader::new(&encoded);160	assert!(decoder.bool().unwrap());161	assert_eq!(decoder.string().unwrap(), "test");162}163164#[test]165fn mint_sample() {166	let (call, mut decoder) = AbiReader::new_call(&hex!(167		"168            50bb4e7f169            000000000000000000000000ad2c0954693c2b5404b7e50967d3481bea432374170            0000000000000000000000000000000000000000000000000000000000000001171            0000000000000000000000000000000000000000000000000000000000000060172            0000000000000000000000000000000000000000000000000000000000000008173            5465737420555249000000000000000000000000000000000000000000000000174        "175	))176	.unwrap();177	assert_eq!(call, u32::to_be_bytes(0x50bb4e7f));178	assert_eq!(179		format!("{:?}", decoder.address().unwrap()),180		"0xad2c0954693c2b5404b7e50967d3481bea432374"181	);182	assert_eq!(decoder.uint32().unwrap(), 1);183	assert_eq!(decoder.string().unwrap(), "Test URI");184}185186#[test]187fn parse_vec_with_dynamic_type() {188	let decoded_data = (189		0x36543006,190		vec![191			(1.into(), "Test URI 0".to_string()),192			(11.into(), "Test URI 1".to_string()),193			(12.into(), "Test URI 2".to_string()),194		],195	);196197	let encoded_data = &hex!(198        "199            36543006200            00000000000000000000000053744e6da587ba10b32a2554d2efdcd985bc27a3 // address201            0000000000000000000000000000000000000000000000000000000000000040 // offset of (uint256, string)[]202            0000000000000000000000000000000000000000000000000000000000000003 // length of (uint256, string)[]203204            0000000000000000000000000000000000000000000000000000000000000060 // offset of first elem205            00000000000000000000000000000000000000000000000000000000000000e0 // offset of second elem206            0000000000000000000000000000000000000000000000000000000000000160 // offset of third elem207208            0000000000000000000000000000000000000000000000000000000000000001 // first token id?   					#60209            0000000000000000000000000000000000000000000000000000000000000040 // offset of string210            000000000000000000000000000000000000000000000000000000000000000a // size of string211            5465737420555249203000000000000000000000000000000000000000000000 // string212213            000000000000000000000000000000000000000000000000000000000000000b // second token id? Why ==11?			#e0214            0000000000000000000000000000000000000000000000000000000000000040 // offset of string215            000000000000000000000000000000000000000000000000000000000000000a // size of string216            5465737420555249203100000000000000000000000000000000000000000000 // string217218            000000000000000000000000000000000000000000000000000000000000000c // third token id?  Why ==12?			#160219            0000000000000000000000000000000000000000000000000000000000000040 // offset of string220            000000000000000000000000000000000000000000000000000000000000000a // size of string221            5465737420555249203200000000000000000000000000000000000000000000 // string222        "223    );224225	let (call, mut decoder) = AbiReader::new_call(encoded_data).unwrap();226	assert_eq!(call, u32::to_be_bytes(decoded_data.0));227	let address = decoder.address().unwrap();228	let data = <Vec<(uint256, string)>>::abi_read(&mut decoder).unwrap();229	assert_eq!(data, decoded_data.1);230231	let mut writer = AbiWriter::new_call(decoded_data.0);232	address.abi_write(&mut writer);233	decoded_data.1.abi_write(&mut writer);234	let ed = writer.finish();235	similar_asserts::assert_eq!(encoded_data, ed.as_slice());236}237238test_impl!(239	vec_tuple_string_bytes,240	Vec<(string, bytes)>,241	0xdeadbeef,242	vec![243		(244			"Test URI 0".to_string(),245			bytes(vec![246				0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11,247				0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11,248				0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11,249				0x11, 0x11, 0x11, 0x11, 0x11, 0x11250			])251		),252		(253			"Test URI 1".to_string(),254			bytes(vec![255				0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22,256				0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22,257				0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22,258				0x22, 0x22, 0x22, 0x22, 0x22259			])260		),261		("Test URI 2".to_string(), bytes(vec![0x33, 0x33])),262	],263	&hex!(264		"265            deadbeef266            0000000000000000000000000000000000000000000000000000000000000020267            0000000000000000000000000000000000000000000000000000000000000003268            269            0000000000000000000000000000000000000000000000000000000000000060270            0000000000000000000000000000000000000000000000000000000000000140271            0000000000000000000000000000000000000000000000000000000000000220272273            0000000000000000000000000000000000000000000000000000000000000040274            0000000000000000000000000000000000000000000000000000000000000080275            000000000000000000000000000000000000000000000000000000000000000a276            5465737420555249203000000000000000000000000000000000000000000000277            0000000000000000000000000000000000000000000000000000000000000030278            1111111111111111111111111111111111111111111111111111111111111111279            1111111111111111111111111111111100000000000000000000000000000000280281            0000000000000000000000000000000000000000000000000000000000000040282            0000000000000000000000000000000000000000000000000000000000000080283            000000000000000000000000000000000000000000000000000000000000000a284            5465737420555249203100000000000000000000000000000000000000000000285            000000000000000000000000000000000000000000000000000000000000002f286            2222222222222222222222222222222222222222222222222222222222222222287            2222222222222222222222222222220000000000000000000000000000000000288289            0000000000000000000000000000000000000000000000000000000000000040290            0000000000000000000000000000000000000000000000000000000000000080291            000000000000000000000000000000000000000000000000000000000000000a292            5465737420555249203200000000000000000000000000000000000000000000293            0000000000000000000000000000000000000000000000000000000000000002294            3333000000000000000000000000000000000000000000000000000000000000295        "296	)297);
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};