git.delta.rocks / unique-network / refs/commits / 7eec33a3cc63

difftreelog

fix AbiRead implementations

Trubnikov Sergey2022-11-16parent: #b3e1096.patch.diff
in: master

5 files changed

modifiedcrates/evm-coder/procedural/src/abi_derive.rsdiffbeforeafterboth
--- a/crates/evm-coder/procedural/src/abi_derive.rs
+++ b/crates/evm-coder/procedural/src/abi_derive.rs
@@ -1,7 +1,6 @@
 use quote::quote;
 
 pub(crate) fn impl_abi_macro(ast: &syn::DeriveInput) -> syn::Result<proc_macro2::TokenStream> {
-	// dbg!(ast);
 	let name = &ast.ident;
 	let (is_named_fields, field_names, field_types, params_count) = match &ast.data {
 		syn::Data::Struct(ds) => match ds.fields {
@@ -31,7 +30,7 @@
 	let abi_type = impl_abi_type(name, field_types.clone());
 	let abi_read = impl_abi_read(name, is_named_fields, field_names.clone(), field_types);
 	let abi_write = impl_abi_write(name, is_named_fields, params_count, field_names);
-	println!("{}", abi_write);
+
 	Ok(quote! {
 		#can_be_plcaed_in_vec
 		#abi_type
@@ -112,14 +111,19 @@
 	quote!(
 		impl ::evm_coder::abi::AbiRead for #name {
 			fn abi_read(reader: &mut ::evm_coder::abi::AbiReader) -> ::evm_coder::execution::Result<Self> {
-				let size = if !<Self as ::evm_coder::abi::AbiType>::is_dynamic() {
+				let is_dynamic = <Self as ::evm_coder::abi::AbiType>::is_dynamic();
+				let size = if !is_dynamic {
 					Some(<Self as ::evm_coder::abi::AbiType>::size())
 				} else {
 					None
 				};
 				let mut subresult = reader.subresult(size)?;
 				#(
-					let #field_names = <#field_types as ::evm_coder::abi::AbiRead>::abi_read(&mut subresult)?;
+					let #field_names = {
+						let value = <#field_types as ::evm_coder::abi::AbiRead>::abi_read(&mut subresult)?;
+						if !is_dynamic {subresult.seek(<#field_types as ::evm_coder::abi::AbiType>::size())};
+						value
+					};
 				)*
 
 				#struct_constructor
modifiedcrates/evm-coder/src/abi/impls.rsdiffbeforeafterboth
--- a/crates/evm-coder/src/abi/impls.rs
+++ b/crates/evm-coder/src/abi/impls.rs
@@ -92,7 +92,7 @@
 	}
 }
 
-impl<R: AbiRead + sealed::CanBePlacedInVec> AbiRead for Vec<R> {
+impl<R: AbiType + 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;
@@ -100,6 +100,9 @@
 		let mut out = Vec::with_capacity(size);
 		for _ in 0..size {
 			out.push(<R>::abi_read(&mut sub)?);
+			if !<R>::is_dynamic() {
+				sub.subresult_offset += <R>::size()
+			};
 		}
 		Ok(out)
 	}
@@ -295,14 +298,19 @@
 
 		impl<$($ident),+> AbiRead for ($($ident,)+)
 		where
-			$($ident: AbiRead,)+
+			$($ident: AbiRead + AbiType,)+
 			($($ident,)+): AbiType,
 		{
 			fn abi_read(reader: &mut AbiReader) -> Result<($($ident,)+)> {
-				let size = if !<($($ident,)+)>::is_dynamic() { Some(<($($ident,)+)>::size()) } else { None };
+				let is_dynamic = <($($ident,)+)>::is_dynamic();
+				let size = if !is_dynamic { Some(<($($ident,)+)>::size()) } else { None };
 				let mut subresult = reader.subresult(size)?;
 				Ok((
-					$(<$ident>::abi_read(&mut subresult)?,)+
+					$({
+						let value = <$ident>::abi_read(&mut subresult)?;
+						if !is_dynamic {subresult.seek(<$ident as AbiType>::size())};
+						value
+					},)+
 				))
 			}
 		}
modifiedcrates/evm-coder/src/abi/mod.rsdiffbeforeafterboth
before · crates/evm-coder/src/abi/mod.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)]2021mod traits;22pub use traits::*;23mod impls;2425#[cfg(test)]26mod test;2728#[cfg(not(feature = "std"))]29use alloc::vec::Vec;30use evm_core::ExitError;31use primitive_types::{H160, U256};3233use crate::{34	execution::{Result, Error},35	types::*,36};3738const ABI_ALIGNMENT: usize = 32;3940/// View into RLP data, which provides method to read typed items from it41#[derive(Clone)]42pub struct AbiReader<'i> {43	buf: &'i [u8],44	subresult_offset: usize,45	offset: usize,46}47impl<'i> AbiReader<'i> {48	/// Start reading RLP buffer, assuming there is no padding bytes49	pub fn new(buf: &'i [u8]) -> Self {50		Self {51			buf,52			subresult_offset: 0,53			offset: 0,54		}55	}56	/// Start reading RLP buffer, parsing first 4 bytes as selector57	pub fn new_call(buf: &'i [u8]) -> Result<(bytes4, Self)> {58		if buf.len() < 4 {59			return Err(Error::Error(ExitError::OutOfOffset));60		}61		let mut method_id = [0; 4];62		method_id.copy_from_slice(&buf[0..4]);6364		Ok((65			method_id,66			Self {67				buf,68				subresult_offset: 4,69				offset: 4,70			},71		))72	}7374	fn read_pad<const S: usize>(75		buf: &[u8],76		offset: usize,77		pad_start: usize,78		pad_size: usize,79		block_start: usize,80		block_size: usize,81	) -> Result<[u8; S]> {82		if buf.len() - offset < ABI_ALIGNMENT {83			return Err(Error::Error(ExitError::OutOfOffset));84		}85		let mut block = [0; S];86		let is_pad_zeroed = buf[pad_start..pad_size].iter().all(|&v| v == 0);87		if !is_pad_zeroed {88			return Err(Error::Error(ExitError::InvalidRange));89		}90		block.copy_from_slice(&buf[block_start..block_size]);91		Ok(block)92	}9394	fn read_padleft<const S: usize>(&mut self) -> Result<[u8; S]> {95		let offset = self.offset;96		self.offset += ABI_ALIGNMENT;97		Self::read_pad(98			self.buf,99			offset,100			offset,101			offset + ABI_ALIGNMENT - S,102			offset + ABI_ALIGNMENT - S,103			offset + ABI_ALIGNMENT,104		)105	}106107	fn read_padright<const S: usize>(&mut self) -> Result<[u8; S]> {108		let offset = self.offset;109		self.offset += ABI_ALIGNMENT;110		Self::read_pad(111			self.buf,112			offset,113			offset + S,114			offset + ABI_ALIGNMENT,115			offset,116			offset + S,117		)118	}119120	/// Read [`H160`] at current position, then advance121	pub fn address(&mut self) -> Result<H160> {122		Ok(H160(self.read_padleft()?))123	}124125	/// Read [`bool`] at current position, then advance126	pub fn bool(&mut self) -> Result<bool> {127		let data: [u8; 1] = self.read_padleft()?;128		match data[0] {129			0 => Ok(false),130			1 => Ok(true),131			_ => Err(Error::Error(ExitError::InvalidRange)),132		}133	}134135	/// Read [`[u8; 4]`] at current position, then advance136	pub fn bytes4(&mut self) -> Result<[u8; 4]> {137		self.read_padright()138	}139140	/// Read [`Vec<u8>`] at current position, then advance141	pub fn bytes(&mut self) -> Result<Vec<u8>> {142		let mut subresult = self.subresult(None)?;143		let length = subresult.uint32()? as usize;144		if subresult.buf.len() < subresult.offset + length {145			return Err(Error::Error(ExitError::OutOfOffset));146		}147		Ok(subresult.buf[subresult.offset..subresult.offset + length].into())148	}149150	/// Read [`string`] at current position, then advance151	pub fn string(&mut self) -> Result<string> {152		string::from_utf8(self.bytes()?).map_err(|_| Error::Error(ExitError::InvalidRange))153	}154155	/// Read [`u8`] at current position, then advance156	pub fn uint8(&mut self) -> Result<u8> {157		Ok(self.read_padleft::<1>()?[0])158	}159160	/// Read [`u32`] at current position, then advance161	pub fn uint32(&mut self) -> Result<u32> {162		Ok(u32::from_be_bytes(self.read_padleft()?))163	}164165	/// Read [`u128`] at current position, then advance166	pub fn uint128(&mut self) -> Result<u128> {167		Ok(u128::from_be_bytes(self.read_padleft()?))168	}169170	/// Read [`U256`] at current position, then advance171	pub fn uint256(&mut self) -> Result<U256> {172		let buf: [u8; 32] = self.read_padleft()?;173		Ok(U256::from_big_endian(&buf))174	}175176	/// Read [`u64`] at current position, then advance177	pub fn uint64(&mut self) -> Result<u64> {178		Ok(u64::from_be_bytes(self.read_padleft()?))179	}180181	/// Read [`usize`] at current position, then advance182	#[deprecated = "dangerous, as usize may have different width in wasm and native execution"]183	pub fn read_usize(&mut self) -> Result<usize> {184		Ok(usize::from_be_bytes(self.read_padleft()?))185	}186187	/// Slice recursive buffer, advance one word for buffer offset188	/// If `size` is [`None`] then [`Self::offset`] and [`Self::subresult_offset`] evals from [`Self::buf`].189	pub fn subresult(&mut self, size: Option<usize>) -> Result<AbiReader<'i>> {190		let subresult_offset = self.subresult_offset;191		let offset = if let Some(size) = size {192			self.offset += size;193			self.subresult_offset += size;194			0195		} else {196			self.uint32()? as usize197		};198199		if offset + self.subresult_offset > self.buf.len() {200			return Err(Error::Error(ExitError::InvalidRange));201		}202203		let new_offset = offset + subresult_offset;204		Ok(AbiReader {205			buf: self.buf,206			subresult_offset: new_offset,207			offset: new_offset,208		})209	}210211	/// Is this parser reached end of buffer?212	pub fn is_finished(&self) -> bool {213		self.buf.len() == self.offset214	}215}216217/// Writer for RLP encoded data218#[derive(Default)]219pub struct AbiWriter {220	static_part: Vec<u8>,221	dynamic_part: Vec<(usize, AbiWriter)>,222	had_call: bool,223	is_dynamic: bool,224}225impl AbiWriter {226	/// Initialize internal buffers for output data, assuming no padding required227	pub fn new() -> Self {228		Self::default()229	}230231	/// Initialize internal buffers with data size232	pub fn new_dynamic(is_dynamic: bool) -> Self {233		Self {234			is_dynamic,235			..Default::default()236		}237	}238	/// Initialize internal buffers, inserting method selector at beginning239	pub fn new_call(method_id: u32) -> Self {240		let mut val = Self::new();241		val.static_part.extend(&method_id.to_be_bytes());242		val.had_call = true;243		val244	}245246	fn write_padleft(&mut self, block: &[u8]) {247		assert!(block.len() <= ABI_ALIGNMENT);248		self.static_part249			.extend(&[0; ABI_ALIGNMENT][0..ABI_ALIGNMENT - block.len()]);250		self.static_part.extend(block);251	}252253	fn write_padright(&mut self, block: &[u8]) {254		assert!(block.len() <= ABI_ALIGNMENT);255		self.static_part.extend(block);256		self.static_part257			.extend(&[0; ABI_ALIGNMENT][0..ABI_ALIGNMENT - block.len()]);258	}259260	/// Write [`H160`] to end of buffer261	pub fn address(&mut self, address: &H160) {262		self.write_padleft(&address.0)263	}264265	/// Write [`bool`] to end of buffer266	pub fn bool(&mut self, value: &bool) {267		self.write_padleft(&[if *value { 1 } else { 0 }])268	}269270	/// Write [`u8`] to end of buffer271	pub fn uint8(&mut self, value: &u8) {272		self.write_padleft(&[*value])273	}274275	/// Write [`u32`] to end of buffer276	pub fn uint32(&mut self, value: &u32) {277		self.write_padleft(&u32::to_be_bytes(*value))278	}279280	/// Write [`u128`] to end of buffer281	pub fn uint128(&mut self, value: &u128) {282		self.write_padleft(&u128::to_be_bytes(*value))283	}284285	/// Write [`U256`] to end of buffer286	pub fn uint256(&mut self, value: &U256) {287		let mut out = [0; 32];288		value.to_big_endian(&mut out);289		self.write_padleft(&out)290	}291292	/// Write [`usize`] to end of buffer293	#[deprecated = "dangerous, as usize may have different width in wasm and native execution"]294	pub fn write_usize(&mut self, value: &usize) {295		self.write_padleft(&usize::to_be_bytes(*value))296	}297298	/// Append recursive data, writing pending offset at end of buffer299	pub fn write_subresult(&mut self, result: Self) {300		self.dynamic_part.push((self.static_part.len(), result));301		// Empty block, to be filled later302		self.write_padleft(&[]);303	}304305	fn memory(&mut self, value: &[u8]) {306		let mut sub = Self::new();307		sub.uint32(&(value.len() as u32));308		for chunk in value.chunks(ABI_ALIGNMENT) {309			sub.write_padright(chunk);310		}311		self.write_subresult(sub);312	}313314	/// Append recursive [`str`] at end of buffer315	pub fn string(&mut self, value: &str) {316		self.memory(value.as_bytes())317	}318319	/// Append recursive [`[u8]`] at end of buffer320	pub fn bytes(&mut self, value: &[u8]) {321		self.memory(value)322	}323324	/// Finish writer, concatenating all internal buffers325	pub fn finish(mut self) -> Vec<u8> {326		for (static_offset, part) in self.dynamic_part {327			let part_offset = self.static_part.len()328				- if self.had_call { 4 } else { 0 }329				- if self.is_dynamic { ABI_ALIGNMENT } else { 0 };330331			let encoded_dynamic_offset = usize::to_be_bytes(part_offset);332			let start = static_offset + ABI_ALIGNMENT - encoded_dynamic_offset.len();333			let stop = static_offset + ABI_ALIGNMENT;334			self.static_part[start..stop].copy_from_slice(&encoded_dynamic_offset);335			self.static_part.extend(part.finish())336		}337		self.static_part338	}339}
after · crates/evm-coder/src/abi/mod.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)]2021mod traits;22pub use traits::*;23mod impls;2425#[cfg(test)]26mod test;2728#[cfg(not(feature = "std"))]29use alloc::vec::Vec;30use evm_core::ExitError;31use primitive_types::{H160, U256};3233use crate::{34	execution::{Result, Error},35	types::*,36};3738const ABI_ALIGNMENT: usize = 32;3940/// View into RLP data, which provides method to read typed items from it41#[derive(Clone)]42pub struct AbiReader<'i> {43	buf: &'i [u8],44	subresult_offset: usize,45	offset: usize,46}47impl<'i> AbiReader<'i> {48	/// Start reading RLP buffer, assuming there is no padding bytes49	pub fn new(buf: &'i [u8]) -> Self {50		Self {51			buf,52			subresult_offset: 0,53			offset: 0,54		}55	}56	/// Start reading RLP buffer, parsing first 4 bytes as selector57	pub fn new_call(buf: &'i [u8]) -> Result<(bytes4, Self)> {58		if buf.len() < 4 {59			return Err(Error::Error(ExitError::OutOfOffset));60		}61		let mut method_id = [0; 4];62		method_id.copy_from_slice(&buf[0..4]);6364		Ok((65			method_id,66			Self {67				buf,68				subresult_offset: 4,69				offset: 4,70			},71		))72	}7374	fn read_pad<const S: usize>(75		buf: &[u8],76		offset: usize,77		pad_start: usize,78		pad_end: usize,79		block_start: usize,80		block_end: usize,81	) -> Result<[u8; S]> {82		if buf.len() - offset < ABI_ALIGNMENT {83			return Err(Error::Error(ExitError::OutOfOffset));84		}85		let mut block = [0; S];86		let is_pad_zeroed = buf[pad_start..pad_end].iter().all(|&v| v == 0);87		if !is_pad_zeroed {88			return Err(Error::Error(ExitError::InvalidRange));89		}90		block.copy_from_slice(&buf[block_start..block_end]);91		Ok(block)92	}9394	fn read_padleft<const S: usize>(&mut self) -> Result<[u8; S]> {95		let offset = self.offset;96		self.offset += ABI_ALIGNMENT;97		Self::read_pad(98			self.buf,99			offset,100			offset,101			offset + ABI_ALIGNMENT - S,102			offset + ABI_ALIGNMENT - S,103			offset + ABI_ALIGNMENT,104		)105	}106107	fn read_padright<const S: usize>(&mut self) -> Result<[u8; S]> {108		let offset = self.offset;109		self.offset += ABI_ALIGNMENT;110		Self::read_pad(111			self.buf,112			offset,113			offset + S,114			offset + ABI_ALIGNMENT,115			offset,116			offset + S,117		)118	}119120	/// Read [`H160`] at current position, then advance121	pub fn address(&mut self) -> Result<H160> {122		Ok(H160(self.read_padleft()?))123	}124125	/// Read [`bool`] at current position, then advance126	pub fn bool(&mut self) -> Result<bool> {127		let data: [u8; 1] = self.read_padleft()?;128		match data[0] {129			0 => Ok(false),130			1 => Ok(true),131			_ => Err(Error::Error(ExitError::InvalidRange)),132		}133	}134135	/// Read [`[u8; 4]`] at current position, then advance136	pub fn bytes4(&mut self) -> Result<[u8; 4]> {137		self.read_padright()138	}139140	/// Read [`Vec<u8>`] at current position, then advance141	pub fn bytes(&mut self) -> Result<Vec<u8>> {142		let mut subresult = self.subresult(None)?;143		let length = subresult.uint32()? as usize;144		if subresult.buf.len() < subresult.offset + length {145			return Err(Error::Error(ExitError::OutOfOffset));146		}147		Ok(subresult.buf[subresult.offset..subresult.offset + length].into())148	}149150	/// Read [`string`] at current position, then advance151	pub fn string(&mut self) -> Result<string> {152		string::from_utf8(self.bytes()?).map_err(|_| Error::Error(ExitError::InvalidRange))153	}154155	/// Read [`u8`] at current position, then advance156	pub fn uint8(&mut self) -> Result<u8> {157		Ok(self.read_padleft::<1>()?[0])158	}159160	/// Read [`u32`] at current position, then advance161	pub fn uint32(&mut self) -> Result<u32> {162		Ok(u32::from_be_bytes(self.read_padleft()?))163	}164165	/// Read [`u128`] at current position, then advance166	pub fn uint128(&mut self) -> Result<u128> {167		Ok(u128::from_be_bytes(self.read_padleft()?))168	}169170	/// Read [`U256`] at current position, then advance171	pub fn uint256(&mut self) -> Result<U256> {172		let buf: [u8; 32] = self.read_padleft()?;173		Ok(U256::from_big_endian(&buf))174	}175176	/// Read [`u64`] at current position, then advance177	pub fn uint64(&mut self) -> Result<u64> {178		Ok(u64::from_be_bytes(self.read_padleft()?))179	}180181	/// Read [`usize`] at current position, then advance182	#[deprecated = "dangerous, as usize may have different width in wasm and native execution"]183	pub fn read_usize(&mut self) -> Result<usize> {184		Ok(usize::from_be_bytes(self.read_padleft()?))185	}186187	/// Slice recursive buffer, advance one word for buffer offset188	/// If `size` is [`None`] then [`Self::offset`] and [`Self::subresult_offset`] evals from [`Self::buf`].189	pub fn subresult(&mut self, size: Option<usize>) -> Result<AbiReader<'i>> {190		let subresult_offset = self.subresult_offset;191		let offset = if let Some(size) = size {192			self.offset += size;193			0194		} else {195			self.uint32()? as usize196		};197198		if offset + self.subresult_offset > self.buf.len() {199			return Err(Error::Error(ExitError::InvalidRange));200		}201202		let new_offset = offset + subresult_offset;203		Ok(AbiReader {204			buf: self.buf,205			subresult_offset: new_offset,206			offset: new_offset,207		})208	}209210	/// Notify about readed data portion.211	pub fn seek(&mut self, size: usize) {212		self.subresult_offset += size;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}
modifiedcrates/evm-coder/src/abi/test.rsdiffbeforeafterboth
--- a/crates/evm-coder/src/abi/test.rs
+++ b/crates/evm-coder/src/abi/test.rs
@@ -137,6 +137,27 @@
 }
 
 #[test]
+fn encode_decode_vec_tuple_uint8_uint8() {
+	test_impl::<Vec<(u8, u8)>>(
+		0xdeadbeef,
+		vec![(0x0A, 0x0B), (0x0C, 0x0D), (0x0E, 0x0F)],
+		&hex!(
+			"
+                deadbeef
+                0000000000000000000000000000000000000000000000000000000000000020
+                0000000000000000000000000000000000000000000000000000000000000003
+                000000000000000000000000000000000000000000000000000000000000000a
+                000000000000000000000000000000000000000000000000000000000000000b
+                000000000000000000000000000000000000000000000000000000000000000c
+                000000000000000000000000000000000000000000000000000000000000000d
+                000000000000000000000000000000000000000000000000000000000000000e
+                000000000000000000000000000000000000000000000000000000000000000f
+            "
+		),
+	);
+}
+
+#[test]
 fn encode_decode_vec_tuple_uint256_string() {
 	test_impl::<Vec<(uint256, string)>>(
         0xdeadbeef,
@@ -332,3 +353,175 @@
 		),
 	);
 }
+
+#[test]
+// #[ignore = "reason"]
+fn encode_decode_tuple0_tuple1_uint8_tuple1_string_bytes_tuple1_uint8_bytes() {
+	let int = 0xff;
+	let by = bytes(vec![0x11, 0x22, 0x33]);
+	let string = "some string".to_string();
+
+	test_impl::<((u8,), (String, bytes), (u8, bytes))>(
+		0xdeadbeef,
+		((int,), (string.clone(), by.clone()), (int, by)),
+		&hex!(
+			"
+                deadbeef
+                0000000000000000000000000000000000000000000000000000000000000020
+                00000000000000000000000000000000000000000000000000000000000000ff
+                0000000000000000000000000000000000000000000000000000000000000060
+                0000000000000000000000000000000000000000000000000000000000000120
+                0000000000000000000000000000000000000000000000000000000000000040
+                0000000000000000000000000000000000000000000000000000000000000080
+                000000000000000000000000000000000000000000000000000000000000000b
+                736f6d6520737472696e67000000000000000000000000000000000000000000
+                0000000000000000000000000000000000000000000000000000000000000003
+                1122330000000000000000000000000000000000000000000000000000000000
+                00000000000000000000000000000000000000000000000000000000000000ff
+                0000000000000000000000000000000000000000000000000000000000000040
+                0000000000000000000000000000000000000000000000000000000000000003
+                1122330000000000000000000000000000000000000000000000000000000000
+            "
+		),
+	);
+}
+
+#[test]
+fn encode_decode_tuple0_tuple1_uint8_tuple1_uint8_uint8_tuple1_uint8_uint8() {
+	test_impl::<((u8,), (u8, u8), (u8, u8))>(
+		0xdeadbeef,
+		((43,), (44, 45), (46, 47)),
+		&hex!(
+			"
+                deadbeef
+                000000000000000000000000000000000000000000000000000000000000002b
+                000000000000000000000000000000000000000000000000000000000000002c
+                000000000000000000000000000000000000000000000000000000000000002d
+                000000000000000000000000000000000000000000000000000000000000002e
+                000000000000000000000000000000000000000000000000000000000000002f
+            "
+		),
+	);
+}
+
+#[test]
+fn encode_decode_tuple0_tuple1_uint8_tuple1_uint8() {
+	test_impl::<((u8,), (u8,))>(
+		0xdeadbeef,
+		((43,), (44,)),
+		&hex!(
+			"
+                deadbeef
+                000000000000000000000000000000000000000000000000000000000000002b
+                000000000000000000000000000000000000000000000000000000000000002c
+            "
+		),
+	);
+}
+
+#[test]
+fn encode_decode_tuple0_tuple1_uint8_uint8() {
+	test_impl::<((u8, u8),)>(
+		0xdeadbeef,
+		((43, 44),),
+		&hex!(
+			"
+                deadbeef
+                000000000000000000000000000000000000000000000000000000000000002b
+                000000000000000000000000000000000000000000000000000000000000002c
+            "
+		),
+	);
+}
+
+#[test]
+fn encode_decode_tuple_uint8_uint8() {
+	test_impl::<(u8, u8)>(
+		0xdeadbeef,
+		(43, 44),
+		&hex!(
+			"
+                deadbeef
+                000000000000000000000000000000000000000000000000000000000000002b
+                000000000000000000000000000000000000000000000000000000000000002c
+            "
+		),
+	);
+}
+
+#[test]
+fn encode_decode_tuple0_tuple1_string() {
+	test_impl::<((String,),)>(
+		0xdeadbeef,
+		(("some string".to_string(),),),
+		&hex!(
+			"
+                deadbeef
+                0000000000000000000000000000000000000000000000000000000000000020
+                0000000000000000000000000000000000000000000000000000000000000020
+                0000000000000000000000000000000000000000000000000000000000000020
+                000000000000000000000000000000000000000000000000000000000000000b
+                736f6d6520737472696e67000000000000000000000000000000000000000000
+            "
+		),
+	);
+}
+
+#[test]
+fn encode_decode_tuple0_tuple1_uint8_string() {
+	test_impl::<((u8, String),)>(
+		0xdeadbeef,
+		((0xff, "some string".to_string()),),
+		&hex!(
+			"
+                deadbeef
+                0000000000000000000000000000000000000000000000000000000000000020
+                0000000000000000000000000000000000000000000000000000000000000020
+                00000000000000000000000000000000000000000000000000000000000000ff
+                0000000000000000000000000000000000000000000000000000000000000040
+                000000000000000000000000000000000000000000000000000000000000000b
+                736f6d6520737472696e67000000000000000000000000000000000000000000
+            "
+		),
+	);
+}
+
+#[test]
+fn encode_decode_tuple0_tuple1_string_bytes() {
+	test_impl::<((String, bytes),)>(
+		0xdeadbeef,
+		(("some string".to_string(), bytes(vec![1, 2, 3])),),
+		&hex!(
+			"
+                deadbeef
+                0000000000000000000000000000000000000000000000000000000000000020
+                0000000000000000000000000000000000000000000000000000000000000020
+                0000000000000000000000000000000000000000000000000000000000000040
+                0000000000000000000000000000000000000000000000000000000000000080
+                000000000000000000000000000000000000000000000000000000000000000b
+                736f6d6520737472696e67000000000000000000000000000000000000000000
+                0000000000000000000000000000000000000000000000000000000000000003
+                0102030000000000000000000000000000000000000000000000000000000000
+            "
+		),
+	);
+}
+
+#[test]
+fn encode_decode_tuple0_tuple1_uint8_tuple1_string() {
+	test_impl::<((u8,), (String,))>(
+		0xdeadbeef,
+		((0xff,), ("some string".to_string(),)),
+		&hex!(
+			"
+                deadbeef
+                0000000000000000000000000000000000000000000000000000000000000020
+                00000000000000000000000000000000000000000000000000000000000000ff
+                0000000000000000000000000000000000000000000000000000000000000040
+                0000000000000000000000000000000000000000000000000000000000000020
+                000000000000000000000000000000000000000000000000000000000000000b
+                736f6d6520737472696e67000000000000000000000000000000000000000000
+            "
+		),
+	);
+}
modifiedcrates/evm-coder/tests/abi_derive_generation.rsdiffbeforeafterboth
--- a/crates/evm-coder/tests/abi_derive_generation.rs
+++ b/crates/evm-coder/tests/abi_derive_generation.rs
@@ -1,7 +1,7 @@
 use evm_coder_procedural::AbiCoder;
 use evm_coder::{
 	types::*,
-	abi::{AbiType, AbiRead, AbiWrite},
+	abi::{AbiType, AbiRead, AbiWrite, AbiReader, AbiWriter},
 };
 
 // TODO: move to build_failed tests
@@ -406,66 +406,199 @@
 	);
 }
 
-fn test_impl<TypeStruct, TupleStruct, Tuple>(
-	type_struct_data: TypeStruct,
-	tuple_struct_data: TupleStruct,
+const FUNCTION_IDENTIFIER: u32 = 0xdeadbeef;
+
+fn test_impl<Tuple, TupleStruct, TypeStruct>(
 	tuple_data: Tuple,
+	tuple_struct_data: TupleStruct,
+	type_struct_data: TypeStruct,
 ) where
 	TypeStruct: AbiWrite + AbiRead + std::cmp::PartialEq + std::fmt::Debug,
+	TupleStruct: AbiWrite + AbiRead + std::cmp::PartialEq + std::fmt::Debug,
 	Tuple: AbiWrite + AbiRead + std::cmp::PartialEq + std::fmt::Debug,
 {
-	use evm_coder::abi::{AbiReader, AbiWriter};
-	const FUNCTION_IDENTIFIER: u32 = 0xdeadbeef;
+	let encoded_type_struct = test_abi_write_impl(&type_struct_data);
+	let encoded_tuple_struct = test_abi_write_impl(&tuple_struct_data);
+	let encoded_tuple = test_abi_write_impl(&tuple_data);
 
-	let mut writer = AbiWriter::new_call(FUNCTION_IDENTIFIER);
-	tuple_data.abi_write(&mut writer);
-	let encoded_tuple = writer.finish();
+	similar_asserts::assert_eq!(encoded_tuple, encoded_type_struct);
+	similar_asserts::assert_eq!(encoded_tuple, encoded_tuple_struct);
 
-	let mut writer = AbiWriter::new_call(FUNCTION_IDENTIFIER);
-	type_struct_data.abi_write(&mut writer);
-	let encoded_struct = writer.finish();
+	// dbg!(&encoded_tuple);
+	// dbg!(&encoded_tuple_struct);
+	// dbg!(&encoded_type_struct);
 
-	similar_asserts::assert_eq!(encoded_tuple, encoded_struct);
+	{
+		let (_, mut decoder) = AbiReader::new_call(&encoded_tuple).unwrap();
+		let restored_struct_data = <TypeStruct>::abi_read(&mut decoder).unwrap();
+		assert_eq!(restored_struct_data, type_struct_data);
+	}
+	{
+		let (_, mut decoder) = AbiReader::new_call(&encoded_tuple).unwrap();
+		let restored_struct_data = <TupleStruct>::abi_read(&mut decoder).unwrap();
+		assert_eq!(restored_struct_data, tuple_struct_data);
+	}
 
-	// let (_, mut decoder) = AbiReader::new_call(&encoded_tuple).unwrap();
-	// let restored_struct_data = <TypeStruct>::abi_read(&mut decoder).unwrap();
-	// assert_eq!(restored_struct_data, type_struct_data);
+	{
+		let (_, mut decoder) = AbiReader::new_call(&encoded_type_struct).unwrap();
+		let restored_tuple_data = <Tuple>::abi_read(&mut decoder).unwrap();
+		assert_eq!(restored_tuple_data, tuple_data);
+	}
+	{
+		let (_, mut decoder) = AbiReader::new_call(&encoded_tuple_struct).unwrap();
+		let restored_tuple_data = <Tuple>::abi_read(&mut decoder).unwrap();
+		assert_eq!(restored_tuple_data, tuple_data);
+	}
+}
 
-	// let (_, mut decoder) = AbiReader::new_call(&encoded_struct).unwrap();
-	// let restored_tuple_data = <Tuple>::abi_read(&mut decoder).unwrap();
-	// assert_eq!(restored_tuple_data, tuple_data);
+fn test_abi_write_impl<A>(data: &A) -> Vec<u8>
+where
+	A: AbiWrite + AbiRead + std::cmp::PartialEq + std::fmt::Debug,
+{
+	let mut writer = AbiWriter::new_call(FUNCTION_IDENTIFIER);
+	data.abi_write(&mut writer);
+	let encoded_tuple = writer.finish();
+	encoded_tuple
 }
 
 #[test]
 fn codec_struct_1_simple() {
 	let _a = 0xff;
-	test_impl::<TypeStruct1SimpleParam, TupleStruct1SimpleParam, (uint8,)>(
-		TypeStruct1SimpleParam { _a },
+	test_impl::<(uint8,), TupleStruct1SimpleParam, TypeStruct1SimpleParam>(
+		(_a,),
 		TupleStruct1SimpleParam(_a),
-		(_a,),
+		TypeStruct1SimpleParam { _a },
 	);
 }
 
 #[test]
 fn codec_struct_1_dynamic() {
 	let _a: String = "some string".into();
-	test_impl::<TypeStruct1DynamicParam, TupleStruct1DynamicParam, (String,)>(
-		TypeStruct1DynamicParam { _a: _a.clone() },
+	test_impl::<(String,), TupleStruct1DynamicParam, TypeStruct1DynamicParam>(
+		(_a.clone(),),
 		TupleStruct1DynamicParam(_a.clone()),
-		(_a,),
+		TypeStruct1DynamicParam { _a },
+	);
+}
+
+#[test]
+fn codec_struct_1_derived_simple() {
+	let _a: u8 = 0xff;
+	test_impl::<((u8,),), TupleStruct1DerivedSimpleParam, TypeStruct1DerivedSimpleParam>(
+		((_a,),),
+		TupleStruct1DerivedSimpleParam(TupleStruct1SimpleParam(_a)),
+		TypeStruct1DerivedSimpleParam {
+			_a: TypeStruct1SimpleParam { _a },
+		},
 	);
 }
 
 #[test]
+fn codec_struct_1_derived_dynamic() {
+	let _a: String = "some string".into();
+	test_impl::<((String,),), TupleStruct1DerivedDynamicParam, TypeStruct1DerivedDynamicParam>(
+		((_a.clone(),),),
+		TupleStruct1DerivedDynamicParam(TupleStruct1DynamicParam(_a.clone())),
+		TypeStruct1DerivedDynamicParam {
+			_a: TypeStruct1DynamicParam { _a },
+		},
+	);
+}
+
+#[test]
+fn codec_struct_2_simple() {
+	let _a = 0xff;
+	let _b = 0xbeefbaba;
+	test_impl::<(u8, u32), TupleStruct2SimpleParam, TypeStruct2SimpleParam>(
+		(_a, _b),
+		TupleStruct2SimpleParam(_a, _b),
+		TypeStruct2SimpleParam { _a, _b },
+	);
+}
+
+#[test]
 fn codec_struct_2_dynamic() {
 	let _a: String = "some string".into();
 	let _b: bytes = bytes(vec![0x11, 0x22, 0x33]);
-	test_impl::<TypeStruct2DynamicParam, TupleStruct2DynamicParam, (String, bytes)>(
-		TypeStruct2DynamicParam {
-			_a: _a.clone(),
-			_b: _b.clone(),
-		},
+	test_impl::<(String, bytes), TupleStruct2DynamicParam, TypeStruct2DynamicParam>(
+		(_a.clone(), _b.clone()),
 		TupleStruct2DynamicParam(_a.clone(), _b.clone()),
-		(_a, _b),
+		TypeStruct2DynamicParam { _a, _b },
+	);
+}
+
+#[test]
+fn codec_struct_2_mixed() {
+	let _a: u8 = 0xff;
+	let _b: bytes = bytes(vec![0x11, 0x22, 0x33]);
+	test_impl::<(u8, bytes), TupleStruct2MixedParam, TypeStruct2MixedParam>(
+		(_a.clone(), _b.clone()),
+		TupleStruct2MixedParam(_a.clone(), _b.clone()),
+		TypeStruct2MixedParam { _a, _b },
+	);
+}
+
+#[test]
+fn codec_struct_2_derived_simple() {
+	let _a = 0xff;
+	let _b = 0xbeefbaba;
+	test_impl::<((u8,), (u8, u32)), TupleStruct2DerivedSimpleParam, TypeStruct2DerivedSimpleParam>(
+		((_a,), (_a, _b)),
+		TupleStruct2DerivedSimpleParam(
+			TupleStruct1SimpleParam(_a),
+			TupleStruct2SimpleParam(_a, _b),
+		),
+		TypeStruct2DerivedSimpleParam {
+			_a: TypeStruct1SimpleParam { _a },
+			_b: TypeStruct2SimpleParam { _a, _b },
+		},
+	);
+}
+
+#[test]
+fn codec_struct_2_derived_dynamic() {
+	let _a = "some string".to_string();
+	let _b = bytes(vec![0x11, 0x22, 0x33]);
+	test_impl::<
+		((String,), (String, bytes)),
+		TupleStruct2DerivedDynamicParam,
+		TypeStruct2DerivedDynamicParam,
+	>(
+		((_a.clone(),), (_a.clone(), _b.clone())),
+		TupleStruct2DerivedDynamicParam(
+			TupleStruct1DynamicParam(_a.clone()),
+			TupleStruct2DynamicParam(_a.clone(), _b.clone()),
+		),
+		TypeStruct2DerivedDynamicParam {
+			_a: TypeStruct1DynamicParam { _a: _a.clone() },
+			_b: TypeStruct2DynamicParam { _a, _b },
+		},
+	);
+}
+
+#[test]
+fn codec_struct_3_derived_mixed() {
+	let int = 0xff;
+	let by = bytes(vec![0x11, 0x22, 0x33]);
+	let string = "some string".to_string();
+	test_impl::<
+		((u8,), (String, bytes), (u8, bytes)),
+		TupleStruct3DerivedMixedParam,
+		TypeStruct3DerivedMixedParam,
+	>(
+		((int,), (string.clone(), by.clone()), (int, by.clone())),
+		TupleStruct3DerivedMixedParam(
+			TupleStruct1SimpleParam(int),
+			TupleStruct2DynamicParam(string.clone(), by.clone()),
+			TupleStruct2MixedParam(int, by.clone()),
+		),
+		TypeStruct3DerivedMixedParam {
+			_a: TypeStruct1SimpleParam { _a: int },
+			_b: TypeStruct2DynamicParam {
+				_a: string.clone(),
+				_b: by.clone(),
+			},
+			_c: TypeStruct2MixedParam { _a: int, _b: by },
+		},
 	);
 }