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

difftreelog

feat Add AbiWrite support for vec with dynamic type

Trubnikov Sergey2022-10-24parent: #88bc48d.patch.diff
in: master

6 files changed

modifiedcrates/evm-coder/Cargo.tomldiffbeforeafterboth
--- a/crates/evm-coder/Cargo.toml
+++ b/crates/evm-coder/Cargo.toml
@@ -22,6 +22,7 @@
 # We want to assert some large binary blobs equality in tests
 hex = "0.4.3"
 hex-literal = "0.3.4"
+similar-asserts = "1.4.2"
 
 [features]
 default = ["std"]
modifiedcrates/evm-coder/src/abi.rsdiffbeforeafterboth
before · crates/evm-coder/src/abi.rs
1// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.2// This file is part of Unique Network.34// Unique Network is free software: you can redistribute it and/or modify5// it under the terms of the GNU General Public License as published by6// the Free Software Foundation, either version 3 of the License, or7// (at your option) any later version.89// Unique Network is distributed in the hope that it will be useful,10// but WITHOUT ANY WARRANTY; without even the implied warranty of11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the12// GNU General Public License for more details.1314// You should have received a copy of the GNU General Public License15// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.1617//! Implementation of EVM RLP reader/writer1819#![allow(dead_code)]2021#[cfg(not(feature = "std"))]22use alloc::vec::Vec;23use evm_core::ExitError;24use primitive_types::{H160, U256};2526use crate::{27	execution::{Error, ResultWithPostInfo, WithPostDispatchInfo},28	types::{string, self},29};30use crate::execution::Result;3132const ABI_ALIGNMENT: usize = 32;3334trait TypeHelper {35	/// Is type dynamic sized.36	fn is_dynamic() -> bool;3738	/// Size for type aligned to [`ABI_ALIGNMENT`].39	fn size() -> usize;40}4142/// View into RLP data, which provides method to read typed items from it43#[derive(Clone)]44pub struct AbiReader<'i> {45	buf: &'i [u8],46	subresult_offset: usize,47	offset: usize,48}49impl<'i> AbiReader<'i> {50	/// Start reading RLP buffer, assuming there is no padding bytes51	pub fn new(buf: &'i [u8]) -> Self {52		Self {53			buf,54			subresult_offset: 0,55			offset: 0,56		}57	}58	/// Start reading RLP buffer, parsing first 4 bytes as selector59	pub fn new_call(buf: &'i [u8]) -> Result<(types::bytes4, Self)> {60		if buf.len() < 4 {61			return Err(Error::Error(ExitError::OutOfOffset));62		}63		let mut method_id = [0; 4];64		method_id.copy_from_slice(&buf[0..4]);6566		Ok((67			method_id,68			Self {69				buf,70				subresult_offset: 4,71				offset: 4,72			},73		))74	}7576	fn read_pad<const S: usize>(77		buf: &[u8],78		offset: usize,79		pad_start: usize,80		pad_size: usize,81		block_start: usize,82		block_size: usize,83	) -> Result<[u8; S]> {84		if buf.len() - offset < ABI_ALIGNMENT {85			return Err(Error::Error(ExitError::OutOfOffset));86		}87		let mut block = [0; S];88		let is_pad_zeroed = buf[pad_start..pad_size].iter().all(|&v| v == 0);89		if !is_pad_zeroed {90			return Err(Error::Error(ExitError::InvalidRange));91		}92		block.copy_from_slice(&buf[block_start..block_size]);93		Ok(block)94	}9596	fn read_padleft<const S: usize>(&mut self) -> Result<[u8; S]> {97		let offset = self.offset;98		self.offset += ABI_ALIGNMENT;99		Self::read_pad(100			self.buf,101			offset,102			offset,103			offset + ABI_ALIGNMENT - S,104			offset + ABI_ALIGNMENT - S,105			offset + ABI_ALIGNMENT,106		)107	}108109	fn read_padright<const S: usize>(&mut self) -> Result<[u8; S]> {110		let offset = self.offset;111		self.offset += ABI_ALIGNMENT;112		Self::read_pad(113			self.buf,114			offset,115			offset + S,116			offset + ABI_ALIGNMENT,117			offset,118			offset + S,119		)120	}121122	/// Read [`H160`] at current position, then advance123	pub fn address(&mut self) -> Result<H160> {124		Ok(H160(self.read_padleft()?))125	}126127	/// Read [`bool`] at current position, then advance128	pub fn bool(&mut self) -> Result<bool> {129		let data: [u8; 1] = self.read_padleft()?;130		match data[0] {131			0 => Ok(false),132			1 => Ok(true),133			_ => Err(Error::Error(ExitError::InvalidRange)),134		}135	}136137	/// Read [`[u8; 4]`] at current position, then advance138	pub fn bytes4(&mut self) -> Result<[u8; 4]> {139		self.read_padright()140	}141142	/// Read [`Vec<u8>`] at current position, then advance143	pub fn bytes(&mut self) -> Result<Vec<u8>> {144		let mut subresult = self.subresult(None)?;145		let length = subresult.uint32()? as usize;146		if subresult.buf.len() < subresult.offset + length {147			return Err(Error::Error(ExitError::OutOfOffset));148		}149		Ok(subresult.buf[subresult.offset..subresult.offset + length].into())150	}151152	/// Read [`string`] at current position, then advance153	pub fn string(&mut self) -> Result<string> {154		string::from_utf8(self.bytes()?).map_err(|_| Error::Error(ExitError::InvalidRange))155	}156157	/// Read [`u8`] at current position, then advance158	pub fn uint8(&mut self) -> Result<u8> {159		Ok(self.read_padleft::<1>()?[0])160	}161162	/// Read [`u32`] at current position, then advance163	pub fn uint32(&mut self) -> Result<u32> {164		Ok(u32::from_be_bytes(self.read_padleft()?))165	}166167	/// Read [`u128`] at current position, then advance168	pub fn uint128(&mut self) -> Result<u128> {169		Ok(u128::from_be_bytes(self.read_padleft()?))170	}171172	/// Read [`U256`] at current position, then advance173	pub fn uint256(&mut self) -> Result<U256> {174		let buf: [u8; 32] = self.read_padleft()?;175		Ok(U256::from_big_endian(&buf))176	}177178	/// Read [`u64`] at current position, then advance179	pub fn uint64(&mut self) -> Result<u64> {180		Ok(u64::from_be_bytes(self.read_padleft()?))181	}182183	/// Read [`usize`] at current position, then advance184	#[deprecated = "dangerous, as usize may have different width in wasm and native execution"]185	pub fn read_usize(&mut self) -> Result<usize> {186		Ok(usize::from_be_bytes(self.read_padleft()?))187	}188189	/// Slice recursive buffer, advance one word for buffer offset190	/// If `size` is [`None`] then [`Self::offset`] and [`Self::subresult_offset`] evals from [`Self::buf`].191	fn subresult(&mut self, size: Option<usize>) -> Result<AbiReader<'i>> {192		let subresult_offset = self.subresult_offset;193		let offset = if let Some(size) = size {194			self.offset += size;195			self.subresult_offset += size;196			0197		} else {198			self.uint32()? as usize199		};200201		if offset + self.subresult_offset > self.buf.len() {202			return Err(Error::Error(ExitError::InvalidRange));203		}204205		let new_offset = offset + subresult_offset;206		Ok(AbiReader {207			buf: self.buf,208			subresult_offset: new_offset,209			offset: new_offset,210		})211	}212213	/// Is this parser reached end of buffer?214	pub fn is_finished(&self) -> bool {215		self.buf.len() == self.offset216	}217}218219/// Writer for RLP encoded data220#[derive(Default)]221pub struct AbiWriter {222	static_part: Vec<u8>,223	dynamic_part: Vec<(usize, AbiWriter)>,224	had_call: bool,225	is_dynamic: bool,226}227impl AbiWriter {228	/// Initialize internal buffers for output data, assuming no padding required229	pub fn new() -> Self {230		Self::default()231	}232233	/// Initialize internal buffers with data size234	pub fn new_dynamic(is_dynamic: bool) -> Self {235		Self {236			is_dynamic,237			..Default::default()238		}239	}240	/// Initialize internal buffers, inserting method selector at beginning241	pub fn new_call(method_id: u32) -> Self {242		let mut val = Self::new();243		val.static_part.extend(&method_id.to_be_bytes());244		val.had_call = true;245		val246	}247248	fn write_padleft(&mut self, block: &[u8]) {249		assert!(block.len() <= ABI_ALIGNMENT);250		self.static_part251			.extend(&[0; ABI_ALIGNMENT][0..ABI_ALIGNMENT - block.len()]);252		self.static_part.extend(block);253	}254255	fn write_padright(&mut self, bytes: &[u8]) {256		assert!(bytes.len() <= ABI_ALIGNMENT);257		self.static_part.extend(bytes);258		self.static_part259			.extend(&[0; ABI_ALIGNMENT][0..ABI_ALIGNMENT - bytes.len()]);260	}261262	/// Write [`H160`] to end of buffer263	pub fn address(&mut self, address: &H160) {264		self.write_padleft(&address.0)265	}266267	/// Write [`bool`] to end of buffer268	pub fn bool(&mut self, value: &bool) {269		self.write_padleft(&[if *value { 1 } else { 0 }])270	}271272	/// Write [`u8`] to end of buffer273	pub fn uint8(&mut self, value: &u8) {274		self.write_padleft(&[*value])275	}276277	/// Write [`u32`] to end of buffer278	pub fn uint32(&mut self, value: &u32) {279		self.write_padleft(&u32::to_be_bytes(*value))280	}281282	/// Write [`u128`] to end of buffer283	pub fn uint128(&mut self, value: &u128) {284		self.write_padleft(&u128::to_be_bytes(*value))285	}286287	/// Write [`U256`] to end of buffer288	pub fn uint256(&mut self, value: &U256) {289		let mut out = [0; 32];290		value.to_big_endian(&mut out);291		self.write_padleft(&out)292	}293294	/// Write [`usize`] to end of buffer295	#[deprecated = "dangerous, as usize may have different width in wasm and native execution"]296	pub fn write_usize(&mut self, value: &usize) {297		self.write_padleft(&usize::to_be_bytes(*value))298	}299300	/// Append recursive data, writing pending offset at end of buffer301	pub fn write_subresult(&mut self, result: Self) {302		self.dynamic_part.push((self.static_part.len(), result));303		// Empty block, to be filled later304		self.write_padleft(&[]);305	}306307	fn memory(&mut self, value: &[u8]) {308		let mut sub = Self::new();309		sub.uint32(&(value.len() as u32));310		for chunk in value.chunks(ABI_ALIGNMENT) {311			sub.write_padright(chunk);312		}313		self.write_subresult(sub);314	}315316	/// Append recursive [`str`] at end of buffer317	pub fn string(&mut self, value: &str) {318		self.memory(value.as_bytes())319	}320321	/// Append recursive [`[u8]`] at end of buffer322	pub fn bytes(&mut self, value: &[u8]) {323		self.memory(value)324	}325326	/// Finish writer, concatenating all internal buffers327	pub fn finish(mut self) -> Vec<u8> {328		for (static_offset, part) in self.dynamic_part {329			let part_offset = self.static_part.len()330				- if self.had_call { 4 } else { 0 }331				- if self.is_dynamic { ABI_ALIGNMENT } else { 0 };332333			let encoded_dynamic_offset = usize::to_be_bytes(part_offset);334			let start = static_offset + ABI_ALIGNMENT - encoded_dynamic_offset.len();335			let stop = static_offset + ABI_ALIGNMENT;336			self.static_part[start..stop].copy_from_slice(&encoded_dynamic_offset);337			self.static_part.extend(part.finish())338		}339		self.static_part340	}341}342343/// [`AbiReader`] implements reading of many types, but it should344/// be limited to types defined in spec345///346/// As this trait can't be made sealed,347/// instead of having `impl AbiRead for T`, we have `impl AbiRead<T> for AbiReader`348pub trait AbiRead<T> {349	/// Read item from current position, advanding decoder350	fn abi_read(&mut self) -> Result<T>;351}352353macro_rules! impl_abi_readable {354	($ty:ty, $method:ident, $dynamic:literal) => {355		impl TypeHelper for $ty {356			fn is_dynamic() -> bool {357				$dynamic358			}359360			fn size() -> usize {361				ABI_ALIGNMENT362			}363		}364		impl AbiRead<$ty> for AbiReader<'_> {365			fn abi_read(&mut self) -> Result<$ty> {366				self.$method()367			}368		}369	};370}371372impl_abi_readable!(u8, uint8, false);373impl_abi_readable!(u32, uint32, false);374impl_abi_readable!(u64, uint64, false);375impl_abi_readable!(u128, uint128, false);376impl_abi_readable!(U256, uint256, false);377impl_abi_readable!([u8; 4], bytes4, false);378impl_abi_readable!(H160, address, false);379impl_abi_readable!(Vec<u8>, bytes, true);380impl_abi_readable!(bool, bool, true);381impl_abi_readable!(string, string, true);382383mod sealed {384	/// Not all types can be placed in vec, i.e `Vec<u8>` is restricted, `bytes` should be used instead385	pub trait CanBePlacedInVec {}386}387388impl sealed::CanBePlacedInVec for U256 {}389impl sealed::CanBePlacedInVec for string {}390impl sealed::CanBePlacedInVec for H160 {}391392impl<R: sealed::CanBePlacedInVec> AbiRead<Vec<R>> for AbiReader<'_>393where394	Self: AbiRead<R>,395{396	fn abi_read(&mut self) -> Result<Vec<R>> {397		let mut sub = self.subresult(None)?;398		let size = sub.uint32()? as usize;399		sub.subresult_offset = sub.offset;400		let mut out = Vec::with_capacity(size);401		for _ in 0..size {402			out.push(<Self as AbiRead<R>>::abi_read(&mut sub)?);403		}404		Ok(out)405	}406}407408macro_rules! impl_tuples {409	($($ident:ident)+) => {410		impl<$($ident: TypeHelper,)+> TypeHelper for ($($ident,)+)411		where412			$(413				$ident: TypeHelper,414			)+415		{416			fn is_dynamic() -> bool {417				false418				$(419					|| <$ident>::is_dynamic()420				)*421			}422423			fn size() -> usize {424				0 $(+ <$ident>::size())+425			}426		}427		impl<$($ident),+> sealed::CanBePlacedInVec for ($($ident,)+) {}428		impl<$($ident),+> AbiRead<($($ident,)+)> for AbiReader<'_>429		where430			$(431				Self: AbiRead<$ident>,432			)+433			($($ident,)+): TypeHelper,434		{435			fn abi_read(&mut self) -> Result<($($ident,)+)> {436				let size = if !<($($ident,)+)>::is_dynamic() { Some(<($($ident,)+)>::size()) } else { None };437				let mut subresult = self.subresult(size)?;438				Ok((439					$(<Self as AbiRead<$ident>>::abi_read(&mut subresult)?,)+440				))441			}442		}443		#[allow(non_snake_case)]444		impl<$($ident),+> AbiWrite for ($($ident,)+)445		where446			$($ident: AbiWrite,)+447		{448			fn abi_write(&self, writer: &mut AbiWriter) {449				let ($($ident,)+) = self;450				if writer.is_dynamic {451					let mut sub = AbiWriter::new();452					$($ident.abi_write(&mut sub);)+453					writer.write_subresult(sub);454				} else {455					$($ident.abi_write(writer);)+456				}457			}458		}459	};460}461462impl_tuples! {A}463impl_tuples! {A B}464impl_tuples! {A B C}465impl_tuples! {A B C D}466impl_tuples! {A B C D E}467impl_tuples! {A B C D E F}468impl_tuples! {A B C D E F G}469impl_tuples! {A B C D E F G H}470impl_tuples! {A B C D E F G H I}471impl_tuples! {A B C D E F G H I J}472473/// For questions about inability to provide custom implementations,474/// see [`AbiRead`]475pub trait AbiWrite {476	/// Write value to end of specified encoder477	fn abi_write(&self, writer: &mut AbiWriter);478	/// Specialization for [`crate::solidity_interface`] implementation,479	/// see comment in `impl AbiWrite for ResultWithPostInfo`480	fn to_result(&self) -> ResultWithPostInfo<AbiWriter> {481		let mut writer = AbiWriter::new();482		self.abi_write(&mut writer);483		Ok(writer.into())484	}485}486487/// This particular AbiWrite implementation should be split to another trait,488/// which only implements `to_result`, but due to lack of specialization feature489/// in stable Rust, we can't have blanket impl of this trait `for T where T: AbiWrite`,490/// so here we abusing default trait methods for it491impl<T: AbiWrite> AbiWrite for ResultWithPostInfo<T> {492	fn abi_write(&self, _writer: &mut AbiWriter) {493		debug_assert!(false, "shouldn't be called, see comment")494	}495	fn to_result(&self) -> ResultWithPostInfo<AbiWriter> {496		match self {497			Ok(v) => Ok(WithPostDispatchInfo {498				post_info: v.post_info.clone(),499				data: {500					let mut out = AbiWriter::new();501					v.data.abi_write(&mut out);502					out503				},504			}),505			Err(e) => Err(e.clone()),506		}507	}508}509510macro_rules! impl_abi_writeable {511	($ty:ty, $method:ident) => {512		impl AbiWrite for $ty {513			fn abi_write(&self, writer: &mut AbiWriter) {514				writer.$method(&self)515			}516		}517	};518}519520impl_abi_writeable!(u8, uint8);521impl_abi_writeable!(u32, uint32);522impl_abi_writeable!(u128, uint128);523impl_abi_writeable!(U256, uint256);524impl_abi_writeable!(H160, address);525impl_abi_writeable!(bool, bool);526impl_abi_writeable!(&str, string);527impl AbiWrite for string {528	fn abi_write(&self, writer: &mut AbiWriter) {529		writer.string(self)530	}531}532// impl AbiWrite for Vec<u8> {533// 	fn abi_write(&self, writer: &mut AbiWriter) {534// 		writer.bytes(self)535// 	}536// }537538impl<T: AbiWrite + TypeHelper> AbiWrite for Vec<T> {539	fn abi_write(&self, writer: &mut AbiWriter) {540		let is_dynamic = T::is_dynamic();541		let mut sub = if is_dynamic {542			AbiWriter::new_dynamic(is_dynamic)543		} else {544			AbiWriter::new()545		};546547		// Write items count548		(self.len() as u32).abi_write(&mut sub);549550		for item in self {551			item.abi_write(&mut sub);552		}553		writer.write_subresult(sub);554	}555}556557impl AbiWrite for () {558	fn abi_write(&self, _writer: &mut AbiWriter) {}559}560561/// Helper macros to parse reader into variables562#[deprecated]563#[macro_export]564macro_rules! abi_decode {565	($reader:expr, $($name:ident: $typ:ident),+ $(,)?) => {566		$(567			let $name = $reader.$typ()?;568		)+569	}570}571572/// Helper macros to construct RLP-encoded buffer573#[deprecated]574#[macro_export]575macro_rules! abi_encode {576	($($typ:ident($value:expr)),* $(,)?) => {{577		#[allow(unused_mut)]578		let mut writer = ::evm_coder::abi::AbiWriter::new();579		$(580			writer.$typ($value);581		)*582		writer583	}};584	(call $val:expr; $($typ:ident($value:expr)),* $(,)?) => {{585		#[allow(unused_mut)]586		let mut writer = ::evm_coder::abi::AbiWriter::new_call($val);587		$(588			writer.$typ($value);589		)*590		writer591	}}592}593594#[cfg(test)]595pub mod test {596	use crate::{597		abi::{AbiRead, AbiWrite},598		types::{string, uint256, address},599	};600601	use super::{AbiReader, AbiWriter};602	use hex_literal::hex;603	use primitive_types::{H160, U256};604605	#[test]606	fn dynamic_after_static() {607		let mut encoder = AbiWriter::new();608		encoder.bool(&true);609		encoder.string("test");610		let encoded = encoder.finish();611612		let mut encoder = AbiWriter::new();613		encoder.bool(&true);614		// Offset to subresult615		encoder.uint32(&(32 * 2));616		// Len of "test"617		encoder.uint32(&4);618		encoder.write_padright(&[b't', b'e', b's', b't']);619		let alternative_encoded = encoder.finish();620621		assert_eq!(encoded, alternative_encoded);622623		let mut decoder = AbiReader::new(&encoded);624		assert!(decoder.bool().unwrap());625		assert_eq!(decoder.string().unwrap(), "test");626	}627628	#[test]629	fn mint_sample() {630		let (call, mut decoder) = AbiReader::new_call(&hex!(631			"632				50bb4e7f633				000000000000000000000000ad2c0954693c2b5404b7e50967d3481bea432374634				0000000000000000000000000000000000000000000000000000000000000001635				0000000000000000000000000000000000000000000000000000000000000060636				0000000000000000000000000000000000000000000000000000000000000008637				5465737420555249000000000000000000000000000000000000000000000000638			"639		))640		.unwrap();641		assert_eq!(call, u32::to_be_bytes(0x50bb4e7f));642		assert_eq!(643			format!("{:?}", decoder.address().unwrap()),644			"0xad2c0954693c2b5404b7e50967d3481bea432374"645		);646		assert_eq!(decoder.uint32().unwrap(), 1);647		assert_eq!(decoder.string().unwrap(), "Test URI");648	}649650	#[test]651	fn parse_vec_with_dynamic_type() {652		let decoded_data = (653			0x36543006,654			vec![655				(1.into(), "Test URI 0".to_string()),656				(11.into(), "Test URI 1".to_string()),657				(12.into(), "Test URI 2".to_string()),658			],659		);660661		let encoded_data = &hex!(662			"663				36543006664				00000000000000000000000053744e6da587ba10b32a2554d2efdcd985bc27a3 // address665				0000000000000000000000000000000000000000000000000000000000000040 // offset of (uint256, string)[]666				0000000000000000000000000000000000000000000000000000000000000003 // length of (uint256, string)[]667668				0000000000000000000000000000000000000000000000000000000000000060 // offset of first elem669				00000000000000000000000000000000000000000000000000000000000000e0 // offset of second elem670				0000000000000000000000000000000000000000000000000000000000000160 // offset of third elem671672				0000000000000000000000000000000000000000000000000000000000000001 // first token id?   					#60673				0000000000000000000000000000000000000000000000000000000000000040 // offset of string674				000000000000000000000000000000000000000000000000000000000000000a // size of string675				5465737420555249203000000000000000000000000000000000000000000000 // string676677				000000000000000000000000000000000000000000000000000000000000000b // second token id? Why ==11?			#e0678				0000000000000000000000000000000000000000000000000000000000000040 // offset of string679				000000000000000000000000000000000000000000000000000000000000000a // size of string680				5465737420555249203100000000000000000000000000000000000000000000 // string681682				000000000000000000000000000000000000000000000000000000000000000c // third token id?  Why ==12?			#160683				0000000000000000000000000000000000000000000000000000000000000040 // offset of string684				000000000000000000000000000000000000000000000000000000000000000a // size of string685				5465737420555249203200000000000000000000000000000000000000000000 // string686			"687		);688689		let (call, mut decoder) = AbiReader::new_call(encoded_data).unwrap();690		assert_eq!(call, u32::to_be_bytes(decoded_data.0));691		let address = decoder.address().unwrap();692		let data =693			<AbiReader<'_> as AbiRead<Vec<(uint256, string)>>>::abi_read(&mut decoder).unwrap();694		assert_eq!(data, decoded_data.1);695696		let mut writer = AbiWriter::new_call(decoded_data.0);697		address.abi_write(&mut writer);698		decoded_data.1.abi_write(&mut writer);699		let ed = writer.finish();700		similar_asserts::assert_eq!(encoded_data, ed.as_slice());701	}702703	#[test]704	fn parse_vec_with_simple_type() {705		let decoded_data = (706			0x1ACF2D55,707			vec![708				(709					H160(hex!("2D2FF76104B7BACB2E8F6731D5BFC184EBECDDBC")),710					U256([10, 0, 0, 0]),711				),712				(713					H160(hex!("AB8E3D9134955566483B11E6825C9223B6737B10")),714					U256([20, 0, 0, 0]),715				),716				(717					H160(hex!("8C582BDF2953046705FC56F189385255EFC1BE18")),718					U256([30, 0, 0, 0]),719				),720			],721		);722723		let encoded_data = &hex!(724			"725				1ACF2D55726				0000000000000000000000000000000000000000000000000000000000000020 // offset of (address, uint256)[]727				0000000000000000000000000000000000000000000000000000000000000003 // length of (address, uint256)[]728729				0000000000000000000000002D2FF76104B7BACB2E8F6731D5BFC184EBECDDBC // address730				000000000000000000000000000000000000000000000000000000000000000A // uint256731732				000000000000000000000000AB8E3D9134955566483B11E6825C9223B6737B10 // address733				0000000000000000000000000000000000000000000000000000000000000014 // uint256734735				0000000000000000000000008C582BDF2953046705FC56F189385255EFC1BE18 // address736				000000000000000000000000000000000000000000000000000000000000001E // uint256737			"738		);739740		let (call, mut decoder) = AbiReader::new_call(encoded_data).unwrap();741		assert_eq!(call, u32::to_be_bytes(decoded_data.0));742		let data =743			<AbiReader<'_> as AbiRead<Vec<(address, uint256)>>>::abi_read(&mut decoder).unwrap();744		assert_eq!(data.len(), 3);745		assert_eq!(data, decoded_data.1);746747		let mut writer = AbiWriter::new_call(decoded_data.0);748		decoded_data.1.abi_write(&mut writer);749		let ed = writer.finish();750		assert_eq!(encoded_data, ed.as_slice());751	}752}
after · crates/evm-coder/src/abi.rs
1// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.2// This file is part of Unique Network.34// Unique Network is free software: you can redistribute it and/or modify5// it under the terms of the GNU General Public License as published by6// the Free Software Foundation, either version 3 of the License, or7// (at your option) any later version.89// Unique Network is distributed in the hope that it will be useful,10// but WITHOUT ANY WARRANTY; without even the implied warranty of11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the12// GNU General Public License for more details.1314// You should have received a copy of the GNU General Public License15// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.1617//! Implementation of EVM RLP reader/writer1819#![allow(dead_code)]2021#[cfg(not(feature = "std"))]22use alloc::vec::Vec;23use evm_core::ExitError;24use primitive_types::{H160, U256};2526use crate::{27	execution::{Error, ResultWithPostInfo, WithPostDispatchInfo},28	types::*,29};30use crate::execution::Result;3132const ABI_ALIGNMENT: usize = 32;3334trait TypeHelper {35	/// Is type dynamic sized.36	fn is_dynamic() -> bool;3738	/// Size for type aligned to [`ABI_ALIGNMENT`].39	fn size() -> usize;40}4142/// View into RLP data, which provides method to read typed items from it43#[derive(Clone)]44pub struct AbiReader<'i> {45	buf: &'i [u8],46	subresult_offset: usize,47	offset: usize,48}49impl<'i> AbiReader<'i> {50	/// Start reading RLP buffer, assuming there is no padding bytes51	pub fn new(buf: &'i [u8]) -> Self {52		Self {53			buf,54			subresult_offset: 0,55			offset: 0,56		}57	}58	/// Start reading RLP buffer, parsing first 4 bytes as selector59	pub fn new_call(buf: &'i [u8]) -> Result<(bytes4, Self)> {60		if buf.len() < 4 {61			return Err(Error::Error(ExitError::OutOfOffset));62		}63		let mut method_id = [0; 4];64		method_id.copy_from_slice(&buf[0..4]);6566		Ok((67			method_id,68			Self {69				buf,70				subresult_offset: 4,71				offset: 4,72			},73		))74	}7576	fn read_pad<const S: usize>(77		buf: &[u8],78		offset: usize,79		pad_start: usize,80		pad_size: usize,81		block_start: usize,82		block_size: usize,83	) -> Result<[u8; S]> {84		if buf.len() - offset < ABI_ALIGNMENT {85			return Err(Error::Error(ExitError::OutOfOffset));86		}87		let mut block = [0; S];88		let is_pad_zeroed = buf[pad_start..pad_size].iter().all(|&v| v == 0);89		if !is_pad_zeroed {90			return Err(Error::Error(ExitError::InvalidRange));91		}92		block.copy_from_slice(&buf[block_start..block_size]);93		Ok(block)94	}9596	fn read_padleft<const S: usize>(&mut self) -> Result<[u8; S]> {97		let offset = self.offset;98		self.offset += ABI_ALIGNMENT;99		Self::read_pad(100			self.buf,101			offset,102			offset,103			offset + ABI_ALIGNMENT - S,104			offset + ABI_ALIGNMENT - S,105			offset + ABI_ALIGNMENT,106		)107	}108109	fn read_padright<const S: usize>(&mut self) -> Result<[u8; S]> {110		let offset = self.offset;111		self.offset += ABI_ALIGNMENT;112		Self::read_pad(113			self.buf,114			offset,115			offset + S,116			offset + ABI_ALIGNMENT,117			offset,118			offset + S,119		)120	}121122	/// Read [`H160`] at current position, then advance123	pub fn address(&mut self) -> Result<H160> {124		Ok(H160(self.read_padleft()?))125	}126127	/// Read [`bool`] at current position, then advance128	pub fn bool(&mut self) -> Result<bool> {129		let data: [u8; 1] = self.read_padleft()?;130		match data[0] {131			0 => Ok(false),132			1 => Ok(true),133			_ => Err(Error::Error(ExitError::InvalidRange)),134		}135	}136137	/// Read [`[u8; 4]`] at current position, then advance138	pub fn bytes4(&mut self) -> Result<[u8; 4]> {139		self.read_padright()140	}141142	/// Read [`Vec<u8>`] at current position, then advance143	pub fn bytes(&mut self) -> Result<Vec<u8>> {144		let mut subresult = self.subresult(None)?;145		let length = subresult.uint32()? as usize;146		if subresult.buf.len() < subresult.offset + length {147			return Err(Error::Error(ExitError::OutOfOffset));148		}149		Ok(subresult.buf[subresult.offset..subresult.offset + length].into())150	}151152	/// Read [`string`] at current position, then advance153	pub fn string(&mut self) -> Result<string> {154		string::from_utf8(self.bytes()?).map_err(|_| Error::Error(ExitError::InvalidRange))155	}156157	/// Read [`u8`] at current position, then advance158	pub fn uint8(&mut self) -> Result<u8> {159		Ok(self.read_padleft::<1>()?[0])160	}161162	/// Read [`u32`] at current position, then advance163	pub fn uint32(&mut self) -> Result<u32> {164		Ok(u32::from_be_bytes(self.read_padleft()?))165	}166167	/// Read [`u128`] at current position, then advance168	pub fn uint128(&mut self) -> Result<u128> {169		Ok(u128::from_be_bytes(self.read_padleft()?))170	}171172	/// Read [`U256`] at current position, then advance173	pub fn uint256(&mut self) -> Result<U256> {174		let buf: [u8; 32] = self.read_padleft()?;175		Ok(U256::from_big_endian(&buf))176	}177178	/// Read [`u64`] at current position, then advance179	pub fn uint64(&mut self) -> Result<u64> {180		Ok(u64::from_be_bytes(self.read_padleft()?))181	}182183	/// Read [`usize`] at current position, then advance184	#[deprecated = "dangerous, as usize may have different width in wasm and native execution"]185	pub fn read_usize(&mut self) -> Result<usize> {186		Ok(usize::from_be_bytes(self.read_padleft()?))187	}188189	/// Slice recursive buffer, advance one word for buffer offset190	/// If `size` is [`None`] then [`Self::offset`] and [`Self::subresult_offset`] evals from [`Self::buf`].191	fn subresult(&mut self, size: Option<usize>) -> Result<AbiReader<'i>> {192		let subresult_offset = self.subresult_offset;193		let offset = if let Some(size) = size {194			self.offset += size;195			self.subresult_offset += size;196			0197		} else {198			self.uint32()? as usize199		};200201		if offset + self.subresult_offset > self.buf.len() {202			return Err(Error::Error(ExitError::InvalidRange));203		}204205		let new_offset = offset + subresult_offset;206		Ok(AbiReader {207			buf: self.buf,208			subresult_offset: new_offset,209			offset: new_offset,210		})211	}212213	/// Is this parser reached end of buffer?214	pub fn is_finished(&self) -> bool {215		self.buf.len() == self.offset216	}217}218219/// Writer for RLP encoded data220#[derive(Default)]221pub struct AbiWriter {222	static_part: Vec<u8>,223	dynamic_part: Vec<(usize, AbiWriter)>,224	had_call: bool,225	is_dynamic: bool,226}227impl AbiWriter {228	/// Initialize internal buffers for output data, assuming no padding required229	pub fn new() -> Self {230		Self::default()231	}232233	/// Initialize internal buffers with data size234	pub fn new_dynamic(is_dynamic: bool) -> Self {235		Self {236			is_dynamic,237			..Default::default()238		}239	}240	/// Initialize internal buffers, inserting method selector at beginning241	pub fn new_call(method_id: u32) -> Self {242		let mut val = Self::new();243		val.static_part.extend(&method_id.to_be_bytes());244		val.had_call = true;245		val246	}247248	fn write_padleft(&mut self, block: &[u8]) {249		assert!(block.len() <= ABI_ALIGNMENT);250		self.static_part251			.extend(&[0; ABI_ALIGNMENT][0..ABI_ALIGNMENT - block.len()]);252		self.static_part.extend(block);253	}254255	fn write_padright(&mut self, block: &[u8]) {256		assert!(block.len() <= ABI_ALIGNMENT);257		self.static_part.extend(block);258		self.static_part259			.extend(&[0; ABI_ALIGNMENT][0..ABI_ALIGNMENT - block.len()]);260	}261262	/// Write [`H160`] to end of buffer263	pub fn address(&mut self, address: &H160) {264		self.write_padleft(&address.0)265	}266267	/// Write [`bool`] to end of buffer268	pub fn bool(&mut self, value: &bool) {269		self.write_padleft(&[if *value { 1 } else { 0 }])270	}271272	/// Write [`u8`] to end of buffer273	pub fn uint8(&mut self, value: &u8) {274		self.write_padleft(&[*value])275	}276277	/// Write [`u32`] to end of buffer278	pub fn uint32(&mut self, value: &u32) {279		self.write_padleft(&u32::to_be_bytes(*value))280	}281282	/// Write [`u128`] to end of buffer283	pub fn uint128(&mut self, value: &u128) {284		self.write_padleft(&u128::to_be_bytes(*value))285	}286287	/// Write [`U256`] to end of buffer288	pub fn uint256(&mut self, value: &U256) {289		let mut out = [0; 32];290		value.to_big_endian(&mut out);291		self.write_padleft(&out)292	}293294	/// Write [`usize`] to end of buffer295	#[deprecated = "dangerous, as usize may have different width in wasm and native execution"]296	pub fn write_usize(&mut self, value: &usize) {297		self.write_padleft(&usize::to_be_bytes(*value))298	}299300	/// Append recursive data, writing pending offset at end of buffer301	pub fn write_subresult(&mut self, result: Self) {302		self.dynamic_part.push((self.static_part.len(), result));303		// Empty block, to be filled later304		self.write_padleft(&[]);305	}306307	fn memory(&mut self, value: &[u8]) {308		let mut sub = Self::new();309		sub.uint32(&(value.len() as u32));310		for chunk in value.chunks(ABI_ALIGNMENT) {311			sub.write_padright(chunk);312		}313		self.write_subresult(sub);314	}315316	/// Append recursive [`str`] at end of buffer317	pub fn string(&mut self, value: &str) {318		self.memory(value.as_bytes())319	}320321	/// Append recursive [`[u8]`] at end of buffer322	pub fn bytes(&mut self, value: &[u8]) {323		self.memory(value)324	}325326	/// Finish writer, concatenating all internal buffers327	pub fn finish(mut self) -> Vec<u8> {328		for (static_offset, part) in self.dynamic_part {329			let part_offset = self.static_part.len()330				- if self.had_call { 4 } else { 0 }331				- if self.is_dynamic { ABI_ALIGNMENT } else { 0 };332333			let encoded_dynamic_offset = usize::to_be_bytes(part_offset);334			let start = static_offset + ABI_ALIGNMENT - encoded_dynamic_offset.len();335			let stop = static_offset + ABI_ALIGNMENT;336			self.static_part[start..stop].copy_from_slice(&encoded_dynamic_offset);337			self.static_part.extend(part.finish())338		}339		self.static_part340	}341}342343/// [`AbiReader`] implements reading of many types, but it should344/// be limited to types defined in spec345///346/// As this trait can't be made sealed,347/// instead of having `impl AbiRead for T`, we have `impl AbiRead<T> for AbiReader`348pub trait AbiRead<T> {349	/// Read item from current position, advanding decoder350	fn abi_read(&mut self) -> Result<T>;351}352353macro_rules! impl_abi_readable {354	($ty:ty, $method:ident, $dynamic:literal) => {355		impl TypeHelper for $ty {356			fn is_dynamic() -> bool {357				$dynamic358			}359360			fn size() -> usize {361				ABI_ALIGNMENT362			}363		}364		impl AbiRead<$ty> for AbiReader<'_> {365			fn abi_read(&mut self) -> Result<$ty> {366				self.$method()367			}368		}369	};370}371372impl_abi_readable!(bool, bool, false);373impl_abi_readable!(uint8, uint8, false);374impl_abi_readable!(uint32, uint32, false);375impl_abi_readable!(uint64, uint64, false);376impl_abi_readable!(uint128, uint128, false);377impl_abi_readable!(uint256, uint256, false);378impl_abi_readable!(bytes4, bytes4, false);379impl_abi_readable!(address, address, false);380impl_abi_readable!(string, string, true);381// impl_abi_readable!(bytes, bytes, true);382383impl TypeHelper for bytes {384	fn is_dynamic() -> bool {385		true386	}387	fn size() -> usize {388		ABI_ALIGNMENT389	}390}391impl AbiRead<bytes> for AbiReader<'_> {392	fn abi_read(&mut self) -> Result<bytes> {393		Ok(bytes(self.bytes()?))394	}395}396397mod sealed {398	/// Not all types can be placed in vec, i.e `Vec<u8>` is restricted, `bytes` should be used instead399	pub trait CanBePlacedInVec {}400}401402impl sealed::CanBePlacedInVec for U256 {}403impl sealed::CanBePlacedInVec for string {}404impl sealed::CanBePlacedInVec for H160 {}405406impl<R: sealed::CanBePlacedInVec> AbiRead<Vec<R>> for AbiReader<'_>407where408	Self: AbiRead<R>,409{410	fn abi_read(&mut self) -> Result<Vec<R>> {411		let mut sub = self.subresult(None)?;412		let size = sub.uint32()? as usize;413		sub.subresult_offset = sub.offset;414		let mut out = Vec::with_capacity(size);415		for _ in 0..size {416			out.push(<Self as AbiRead<R>>::abi_read(&mut sub)?);417		}418		Ok(out)419	}420}421422macro_rules! impl_tuples {423	($($ident:ident)+) => {424		impl<$($ident: TypeHelper,)+> TypeHelper for ($($ident,)+)425		where426			$(427				$ident: TypeHelper,428			)+429		{430			fn is_dynamic() -> bool {431				false432				$(433					|| <$ident>::is_dynamic()434				)*435			}436437			fn size() -> usize {438				0 $(+ <$ident>::size())+439			}440		}441		impl<$($ident),+> sealed::CanBePlacedInVec for ($($ident,)+) {}442		impl<$($ident),+> AbiRead<($($ident,)+)> for AbiReader<'_>443		where444			$(445				Self: AbiRead<$ident>,446			)+447			($($ident,)+): TypeHelper,448		{449			fn abi_read(&mut self) -> Result<($($ident,)+)> {450				let size = if !<($($ident,)+)>::is_dynamic() { Some(<($($ident,)+)>::size()) } else { None };451				let mut subresult = self.subresult(size)?;452				Ok((453					$(<Self as AbiRead<$ident>>::abi_read(&mut subresult)?,)+454				))455			}456		}457		#[allow(non_snake_case)]458		impl<$($ident),+> AbiWrite for ($($ident,)+)459		where460			$($ident: AbiWrite,)+461		{462			fn abi_write(&self, writer: &mut AbiWriter) {463				let ($($ident,)+) = self;464				if writer.is_dynamic {465					let mut sub = AbiWriter::new();466					$($ident.abi_write(&mut sub);)+467					writer.write_subresult(sub);468				} else {469					$($ident.abi_write(writer);)+470				}471			}472		}473	};474}475476impl_tuples! {A}477impl_tuples! {A B}478impl_tuples! {A B C}479impl_tuples! {A B C D}480impl_tuples! {A B C D E}481impl_tuples! {A B C D E F}482impl_tuples! {A B C D E F G}483impl_tuples! {A B C D E F G H}484impl_tuples! {A B C D E F G H I}485impl_tuples! {A B C D E F G H I J}486487/// For questions about inability to provide custom implementations,488/// see [`AbiRead`]489pub trait AbiWrite {490	/// Write value to end of specified encoder491	fn abi_write(&self, writer: &mut AbiWriter);492	/// Specialization for [`crate::solidity_interface`] implementation,493	/// see comment in `impl AbiWrite for ResultWithPostInfo`494	fn to_result(&self) -> ResultWithPostInfo<AbiWriter> {495		let mut writer = AbiWriter::new();496		self.abi_write(&mut writer);497		Ok(writer.into())498	}499}500501/// This particular AbiWrite implementation should be split to another trait,502/// which only implements `to_result`, but due to lack of specialization feature503/// in stable Rust, we can't have blanket impl of this trait `for T where T: AbiWrite`,504/// so here we abusing default trait methods for it505impl<T: AbiWrite> AbiWrite for ResultWithPostInfo<T> {506	fn abi_write(&self, _writer: &mut AbiWriter) {507		debug_assert!(false, "shouldn't be called, see comment")508	}509	fn to_result(&self) -> ResultWithPostInfo<AbiWriter> {510		match self {511			Ok(v) => Ok(WithPostDispatchInfo {512				post_info: v.post_info.clone(),513				data: {514					let mut out = AbiWriter::new();515					v.data.abi_write(&mut out);516					out517				},518			}),519			Err(e) => Err(e.clone()),520		}521	}522}523524macro_rules! impl_abi_writeable {525	($ty:ty, $method:ident) => {526		impl AbiWrite for $ty {527			fn abi_write(&self, writer: &mut AbiWriter) {528				writer.$method(&self)529			}530		}531	};532}533534impl_abi_writeable!(u8, uint8);535impl_abi_writeable!(u32, uint32);536impl_abi_writeable!(u128, uint128);537impl_abi_writeable!(U256, uint256);538impl_abi_writeable!(H160, address);539impl_abi_writeable!(bool, bool);540impl_abi_writeable!(&str, string);541542impl AbiWrite for string {543	fn abi_write(&self, writer: &mut AbiWriter) {544		writer.string(self)545	}546}547548impl AbiWrite for bytes {549	fn abi_write(&self, writer: &mut AbiWriter) {550		writer.bytes(self.0.as_slice())551	}552}553554impl<T: AbiWrite + TypeHelper> AbiWrite for Vec<T> {555	fn abi_write(&self, writer: &mut AbiWriter) {556		let is_dynamic = T::is_dynamic();557		let mut sub = if is_dynamic {558			AbiWriter::new_dynamic(is_dynamic)559		} else {560			AbiWriter::new()561		};562563		// Write items count564		(self.len() as u32).abi_write(&mut sub);565566		for item in self {567			item.abi_write(&mut sub);568		}569		writer.write_subresult(sub);570	}571}572573impl AbiWrite for () {574	fn abi_write(&self, _writer: &mut AbiWriter) {}575}576577/// Helper macros to parse reader into variables578#[deprecated]579#[macro_export]580macro_rules! abi_decode {581	($reader:expr, $($name:ident: $typ:ident),+ $(,)?) => {582		$(583			let $name = $reader.$typ()?;584		)+585	}586}587588/// Helper macros to construct RLP-encoded buffer589#[deprecated]590#[macro_export]591macro_rules! abi_encode {592	($($typ:ident($value:expr)),* $(,)?) => {{593		#[allow(unused_mut)]594		let mut writer = ::evm_coder::abi::AbiWriter::new();595		$(596			writer.$typ($value);597		)*598		writer599	}};600	(call $val:expr; $($typ:ident($value:expr)),* $(,)?) => {{601		#[allow(unused_mut)]602		let mut writer = ::evm_coder::abi::AbiWriter::new_call($val);603		$(604			writer.$typ($value);605		)*606		writer607	}}608}609610#[cfg(test)]611pub mod test {612	use crate::{613		abi::{AbiRead, AbiWrite},614		types::{string, uint256, address},615	};616617	use super::{AbiReader, AbiWriter};618	use hex_literal::hex;619	use primitive_types::{H160, U256};620621	#[test]622	fn dynamic_after_static() {623		let mut encoder = AbiWriter::new();624		encoder.bool(&true);625		encoder.string("test");626		let encoded = encoder.finish();627628		let mut encoder = AbiWriter::new();629		encoder.bool(&true);630		// Offset to subresult631		encoder.uint32(&(32 * 2));632		// Len of "test"633		encoder.uint32(&4);634		encoder.write_padright(&[b't', b'e', b's', b't']);635		let alternative_encoded = encoder.finish();636637		assert_eq!(encoded, alternative_encoded);638639		let mut decoder = AbiReader::new(&encoded);640		assert!(decoder.bool().unwrap());641		assert_eq!(decoder.string().unwrap(), "test");642	}643644	#[test]645	fn mint_sample() {646		let (call, mut decoder) = AbiReader::new_call(&hex!(647			"648				50bb4e7f649				000000000000000000000000ad2c0954693c2b5404b7e50967d3481bea432374650				0000000000000000000000000000000000000000000000000000000000000001651				0000000000000000000000000000000000000000000000000000000000000060652				0000000000000000000000000000000000000000000000000000000000000008653				5465737420555249000000000000000000000000000000000000000000000000654			"655		))656		.unwrap();657		assert_eq!(call, u32::to_be_bytes(0x50bb4e7f));658		assert_eq!(659			format!("{:?}", decoder.address().unwrap()),660			"0xad2c0954693c2b5404b7e50967d3481bea432374"661		);662		assert_eq!(decoder.uint32().unwrap(), 1);663		assert_eq!(decoder.string().unwrap(), "Test URI");664	}665666	#[test]667	fn parse_vec_with_dynamic_type() {668		let decoded_data = (669			0x36543006,670			vec![671				(1.into(), "Test URI 0".to_string()),672				(11.into(), "Test URI 1".to_string()),673				(12.into(), "Test URI 2".to_string()),674			],675		);676677		let encoded_data = &hex!(678			"679				36543006680				00000000000000000000000053744e6da587ba10b32a2554d2efdcd985bc27a3 // address681				0000000000000000000000000000000000000000000000000000000000000040 // offset of (uint256, string)[]682				0000000000000000000000000000000000000000000000000000000000000003 // length of (uint256, string)[]683684				0000000000000000000000000000000000000000000000000000000000000060 // offset of first elem685				00000000000000000000000000000000000000000000000000000000000000e0 // offset of second elem686				0000000000000000000000000000000000000000000000000000000000000160 // offset of third elem687688				0000000000000000000000000000000000000000000000000000000000000001 // first token id?   					#60689				0000000000000000000000000000000000000000000000000000000000000040 // offset of string690				000000000000000000000000000000000000000000000000000000000000000a // size of string691				5465737420555249203000000000000000000000000000000000000000000000 // string692693				000000000000000000000000000000000000000000000000000000000000000b // second token id? Why ==11?			#e0694				0000000000000000000000000000000000000000000000000000000000000040 // offset of string695				000000000000000000000000000000000000000000000000000000000000000a // size of string696				5465737420555249203100000000000000000000000000000000000000000000 // string697698				000000000000000000000000000000000000000000000000000000000000000c // third token id?  Why ==12?			#160699				0000000000000000000000000000000000000000000000000000000000000040 // offset of string700				000000000000000000000000000000000000000000000000000000000000000a // size of string701				5465737420555249203200000000000000000000000000000000000000000000 // string702			"703		);704705		let (call, mut decoder) = AbiReader::new_call(encoded_data).unwrap();706		assert_eq!(call, u32::to_be_bytes(decoded_data.0));707		let address = decoder.address().unwrap();708		let data =709			<AbiReader<'_> as AbiRead<Vec<(uint256, string)>>>::abi_read(&mut decoder).unwrap();710		assert_eq!(data, decoded_data.1);711712		let mut writer = AbiWriter::new_call(decoded_data.0);713		address.abi_write(&mut writer);714		decoded_data.1.abi_write(&mut writer);715		let ed = writer.finish();716		similar_asserts::assert_eq!(encoded_data, ed.as_slice());717	}718719	#[test]720	fn parse_vec_with_simple_type() {721		let decoded_data = (722			0x1ACF2D55,723			vec![724				(725					H160(hex!("2D2FF76104B7BACB2E8F6731D5BFC184EBECDDBC")),726					U256([10, 0, 0, 0]),727				),728				(729					H160(hex!("AB8E3D9134955566483B11E6825C9223B6737B10")),730					U256([20, 0, 0, 0]),731				),732				(733					H160(hex!("8C582BDF2953046705FC56F189385255EFC1BE18")),734					U256([30, 0, 0, 0]),735				),736			],737		);738739		let encoded_data = &hex!(740			"741				1ACF2D55742				0000000000000000000000000000000000000000000000000000000000000020 // offset of (address, uint256)[]743				0000000000000000000000000000000000000000000000000000000000000003 // length of (address, uint256)[]744745				0000000000000000000000002D2FF76104B7BACB2E8F6731D5BFC184EBECDDBC // address746				000000000000000000000000000000000000000000000000000000000000000A // uint256747748				000000000000000000000000AB8E3D9134955566483B11E6825C9223B6737B10 // address749				0000000000000000000000000000000000000000000000000000000000000014 // uint256750751				0000000000000000000000008C582BDF2953046705FC56F189385255EFC1BE18 // address752				000000000000000000000000000000000000000000000000000000000000001E // uint256753			"754		);755756		let (call, mut decoder) = AbiReader::new_call(encoded_data).unwrap();757		assert_eq!(call, u32::to_be_bytes(decoded_data.0));758		let data =759			<AbiReader<'_> as AbiRead<Vec<(address, uint256)>>>::abi_read(&mut decoder).unwrap();760		assert_eq!(data.len(), 3);761		assert_eq!(data, decoded_data.1);762763		let mut writer = AbiWriter::new_call(decoded_data.0);764		decoded_data.1.abi_write(&mut writer);765		let ed = writer.finish();766		assert_eq!(encoded_data, ed.as_slice());767	}768}
modifiedcrates/evm-coder/src/lib.rsdiffbeforeafterboth
--- a/crates/evm-coder/src/lib.rs
+++ b/crates/evm-coder/src/lib.rs
@@ -133,8 +133,10 @@
 	pub type string = ::alloc::string::String;
 	#[cfg(feature = "std")]
 	pub type string = ::std::string::String;
-	pub type bytes = Vec<u8>;
 
+	#[derive(Default, Debug)]
+	pub struct bytes(pub Vec<u8>);
+
 	/// Solidity doesn't have `void` type, however we have special implementation
 	/// for empty tuple return type
 	pub type void = ();
@@ -157,6 +159,30 @@
 		/// and there is no `receiver()` function defined.
 		pub value: U256,
 	}
+
+	impl From<Vec<u8>> for bytes {
+		fn from(src: Vec<u8>) -> Self {
+			Self(src)
+		}
+	}
+
+	impl Into<Vec<u8>> for bytes {
+		fn into(self) -> Vec<u8> {
+			self.0
+		}
+	}
+
+	impl bytes {
+		#[must_use]
+		pub fn len(&self) -> usize {
+			self.0.len()
+		}
+
+		#[must_use]
+		pub fn is_empty(&self) -> bool {
+			self.len() == 0
+		}
+	}
 }
 
 /// Parseable EVM call, this trait should be implemented with [`solidity_interface`] macro
modifiedpallets/common/src/erc.rsdiffbeforeafterboth
--- a/pallets/common/src/erc.rs
+++ b/pallets/common/src/erc.rs
@@ -85,7 +85,7 @@
 		let key = <Vec<u8>>::from(key)
 			.try_into()
 			.map_err(|_| "key too large")?;
-		let value = value.try_into().map_err(|_| "value too large")?;
+		let value = value.0.try_into().map_err(|_| "value too large")?;
 
 		<Pallet<T>>::set_collection_property(self, &caller, Property { key, value })
 			.map_err(dispatch_to_evm::<T>)
@@ -120,7 +120,7 @@
 		let props = <CollectionProperties<T>>::get(self.id);
 		let prop = props.get(&key).ok_or("key not found")?;
 
-		Ok(prop.to_vec())
+		Ok(bytes(prop.to_vec()))
 	}
 
 	/// Set the sponsor of the collection.
modifiedpallets/nonfungible/src/erc.rsdiffbeforeafterboth
--- a/pallets/nonfungible/src/erc.rs
+++ b/pallets/nonfungible/src/erc.rs
@@ -97,7 +97,7 @@
 		let key = <Vec<u8>>::from(key)
 			.try_into()
 			.map_err(|_| "key too long")?;
-		let value = value.try_into().map_err(|_| "value too long")?;
+		let value = value.0.try_into().map_err(|_| "value too long")?;
 
 		let nesting_budget = self
 			.recorder
@@ -146,7 +146,7 @@
 		let props = <TokenProperties<T>>::get((self.id, token_id));
 		let prop = props.get(&key).ok_or("key not found")?;
 
-		Ok(prop.to_vec())
+		Ok(prop.to_vec().into())
 	}
 }
 
modifiedpallets/refungible/src/erc.rsdiffbeforeafterboth
--- a/pallets/refungible/src/erc.rs
+++ b/pallets/refungible/src/erc.rs
@@ -100,7 +100,7 @@
 		let key = <Vec<u8>>::from(key)
 			.try_into()
 			.map_err(|_| "key too long")?;
-		let value = value.try_into().map_err(|_| "value too long")?;
+		let value = value.0.try_into().map_err(|_| "value too long")?;
 
 		let nesting_budget = self
 			.recorder
@@ -149,7 +149,7 @@
 		let props = <TokenProperties<T>>::get((self.id, token_id));
 		let prop = props.get(&key).ok_or("key not found")?;
 
-		Ok(prop.to_vec())
+		Ok(prop.to_vec().into())
 	}
 }