git.delta.rocks / unique-network / refs/commits / 0257bf04211b

difftreelog

source

crates/evm-coder/src/abi.rs24.8 KiBsourcehistory
1// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.2// This file is part of Unique Network.34// Unique Network is free software: you can redistribute it and/or modify5// it under the terms of the GNU General Public License as published by6// the Free Software Foundation, either version 3 of the License, or7// (at your option) any later version.89// Unique Network is distributed in the hope that it will be useful,10// but WITHOUT ANY WARRANTY; without even the implied warranty of11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the12// GNU General Public License for more details.1314// You should have received a copy of the GNU General Public License15// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.1617//! Implementation of EVM RLP reader/writer1819#![allow(dead_code)]2021#[cfg(not(feature = "std"))]22use alloc::vec::Vec;23use evm_core::ExitError;24use primitive_types::{H160, U256};2526use crate::{27	execution::{Error, ResultWithPostInfo, WithPostDispatchInfo},28	types::*,29	make_signature,30	custom_signature::{SignatureUnit, SIGNATURE_SIZE_LIMIT},31};32use crate::execution::Result;3334const ABI_ALIGNMENT: usize = 32;3536trait TypeHelper {37	/// Is type dynamic sized.38	fn is_dynamic() -> bool;3940	/// Size for type aligned to [`ABI_ALIGNMENT`].41	fn size() -> usize;42}4344/// View into RLP data, which provides method to read typed items from it45#[derive(Clone)]46pub struct AbiReader<'i> {47	buf: &'i [u8],48	subresult_offset: usize,49	offset: usize,50}51impl<'i> AbiReader<'i> {52	/// Start reading RLP buffer, assuming there is no padding bytes53	pub fn new(buf: &'i [u8]) -> Self {54		Self {55			buf,56			subresult_offset: 0,57			offset: 0,58		}59	}60	/// Start reading RLP buffer, parsing first 4 bytes as selector61	pub fn new_call(buf: &'i [u8]) -> Result<(bytes4, Self)> {62		if buf.len() < 4 {63			return Err(Error::Error(ExitError::OutOfOffset));64		}65		let mut method_id = [0; 4];66		method_id.copy_from_slice(&buf[0..4]);6768		Ok((69			method_id,70			Self {71				buf,72				subresult_offset: 4,73				offset: 4,74			},75		))76	}7778	fn read_pad<const S: usize>(79		buf: &[u8],80		offset: usize,81		pad_start: usize,82		pad_size: usize,83		block_start: usize,84		block_size: usize,85	) -> Result<[u8; S]> {86		if buf.len() - offset < ABI_ALIGNMENT {87			return Err(Error::Error(ExitError::OutOfOffset));88		}89		let mut block = [0; S];90		let is_pad_zeroed = buf[pad_start..pad_size].iter().all(|&v| v == 0);91		if !is_pad_zeroed {92			return Err(Error::Error(ExitError::InvalidRange));93		}94		block.copy_from_slice(&buf[block_start..block_size]);95		Ok(block)96	}9798	fn read_padleft<const S: usize>(&mut self) -> Result<[u8; S]> {99		let offset = self.offset;100		self.offset += ABI_ALIGNMENT;101		Self::read_pad(102			self.buf,103			offset,104			offset,105			offset + ABI_ALIGNMENT - S,106			offset + ABI_ALIGNMENT - S,107			offset + ABI_ALIGNMENT,108		)109	}110111	fn read_padright<const S: usize>(&mut self) -> Result<[u8; S]> {112		let offset = self.offset;113		self.offset += ABI_ALIGNMENT;114		Self::read_pad(115			self.buf,116			offset,117			offset + S,118			offset + ABI_ALIGNMENT,119			offset,120			offset + S,121		)122	}123124	/// Read [`H160`] at current position, then advance125	pub fn address(&mut self) -> Result<H160> {126		Ok(H160(self.read_padleft()?))127	}128129	/// Read [`bool`] at current position, then advance130	pub fn bool(&mut self) -> Result<bool> {131		let data: [u8; 1] = self.read_padleft()?;132		match data[0] {133			0 => Ok(false),134			1 => Ok(true),135			_ => Err(Error::Error(ExitError::InvalidRange)),136		}137	}138139	/// Read [`[u8; 4]`] at current position, then advance140	pub fn bytes4(&mut self) -> Result<[u8; 4]> {141		self.read_padright()142	}143144	/// Read [`Vec<u8>`] at current position, then advance145	pub fn bytes(&mut self) -> Result<Vec<u8>> {146		let mut subresult = self.subresult(None)?;147		let length = subresult.uint32()? as usize;148		if subresult.buf.len() < subresult.offset + length {149			return Err(Error::Error(ExitError::OutOfOffset));150		}151		Ok(subresult.buf[subresult.offset..subresult.offset + length].into())152	}153154	/// Read [`string`] at current position, then advance155	pub fn string(&mut self) -> Result<string> {156		string::from_utf8(self.bytes()?).map_err(|_| Error::Error(ExitError::InvalidRange))157	}158159	/// Read [`u8`] at current position, then advance160	pub fn uint8(&mut self) -> Result<u8> {161		Ok(self.read_padleft::<1>()?[0])162	}163164	/// Read [`u32`] at current position, then advance165	pub fn uint32(&mut self) -> Result<u32> {166		Ok(u32::from_be_bytes(self.read_padleft()?))167	}168169	/// Read [`u128`] at current position, then advance170	pub fn uint128(&mut self) -> Result<u128> {171		Ok(u128::from_be_bytes(self.read_padleft()?))172	}173174	/// Read [`U256`] at current position, then advance175	pub fn uint256(&mut self) -> Result<U256> {176		let buf: [u8; 32] = self.read_padleft()?;177		Ok(U256::from_big_endian(&buf))178	}179180	/// Read [`u64`] at current position, then advance181	pub fn uint64(&mut self) -> Result<u64> {182		Ok(u64::from_be_bytes(self.read_padleft()?))183	}184185	/// Read [`usize`] at current position, then advance186	#[deprecated = "dangerous, as usize may have different width in wasm and native execution"]187	pub fn read_usize(&mut self) -> Result<usize> {188		Ok(usize::from_be_bytes(self.read_padleft()?))189	}190191	/// Slice recursive buffer, advance one word for buffer offset192	/// If `size` is [`None`] then [`Self::offset`] and [`Self::subresult_offset`] evals from [`Self::buf`].193	fn subresult(&mut self, size: Option<usize>) -> Result<AbiReader<'i>> {194		let subresult_offset = self.subresult_offset;195		let offset = if let Some(size) = size {196			self.offset += size;197			self.subresult_offset += size;198			0199		} else {200			self.uint32()? as usize201		};202203		if offset + self.subresult_offset > self.buf.len() {204			return Err(Error::Error(ExitError::InvalidRange));205		}206207		let new_offset = offset + subresult_offset;208		Ok(AbiReader {209			buf: self.buf,210			subresult_offset: new_offset,211			offset: new_offset,212		})213	}214215	/// Is this parser reached end of buffer?216	pub fn is_finished(&self) -> bool {217		self.buf.len() == self.offset218	}219}220221/// Writer for RLP encoded data222#[derive(Default)]223pub struct AbiWriter {224	static_part: Vec<u8>,225	dynamic_part: Vec<(usize, AbiWriter)>,226	had_call: bool,227	is_dynamic: bool,228}229impl AbiWriter {230	/// Initialize internal buffers for output data, assuming no padding required231	pub fn new() -> Self {232		Self::default()233	}234235	/// Initialize internal buffers with data size236	pub fn new_dynamic(is_dynamic: bool) -> Self {237		Self {238			is_dynamic,239			..Default::default()240		}241	}242	/// Initialize internal buffers, inserting method selector at beginning243	pub fn new_call(method_id: u32) -> Self {244		let mut val = Self::new();245		val.static_part.extend(&method_id.to_be_bytes());246		val.had_call = true;247		val248	}249250	fn write_padleft(&mut self, block: &[u8]) {251		assert!(block.len() <= ABI_ALIGNMENT);252		self.static_part253			.extend(&[0; ABI_ALIGNMENT][0..ABI_ALIGNMENT - block.len()]);254		self.static_part.extend(block);255	}256257	fn write_padright(&mut self, block: &[u8]) {258		assert!(block.len() <= ABI_ALIGNMENT);259		self.static_part.extend(block);260		self.static_part261			.extend(&[0; ABI_ALIGNMENT][0..ABI_ALIGNMENT - block.len()]);262	}263264	/// Write [`H160`] to end of buffer265	pub fn address(&mut self, address: &H160) {266		self.write_padleft(&address.0)267	}268269	/// Write [`bool`] to end of buffer270	pub fn bool(&mut self, value: &bool) {271		self.write_padleft(&[if *value { 1 } else { 0 }])272	}273274	/// Write [`u8`] to end of buffer275	pub fn uint8(&mut self, value: &u8) {276		self.write_padleft(&[*value])277	}278279	/// Write [`u32`] to end of buffer280	pub fn uint32(&mut self, value: &u32) {281		self.write_padleft(&u32::to_be_bytes(*value))282	}283284	/// Write [`u128`] to end of buffer285	pub fn uint128(&mut self, value: &u128) {286		self.write_padleft(&u128::to_be_bytes(*value))287	}288289	/// Write [`U256`] to end of buffer290	pub fn uint256(&mut self, value: &U256) {291		let mut out = [0; 32];292		value.to_big_endian(&mut out);293		self.write_padleft(&out)294	}295296	/// Write [`usize`] to end of buffer297	#[deprecated = "dangerous, as usize may have different width in wasm and native execution"]298	pub fn write_usize(&mut self, value: &usize) {299		self.write_padleft(&usize::to_be_bytes(*value))300	}301302	/// Append recursive data, writing pending offset at end of buffer303	pub fn write_subresult(&mut self, result: Self) {304		self.dynamic_part.push((self.static_part.len(), result));305		// Empty block, to be filled later306		self.write_padleft(&[]);307	}308309	fn memory(&mut self, value: &[u8]) {310		let mut sub = Self::new();311		sub.uint32(&(value.len() as u32));312		for chunk in value.chunks(ABI_ALIGNMENT) {313			sub.write_padright(chunk);314		}315		self.write_subresult(sub);316	}317318	/// Append recursive [`str`] at end of buffer319	pub fn string(&mut self, value: &str) {320		self.memory(value.as_bytes())321	}322323	/// Append recursive [`[u8]`] at end of buffer324	pub fn bytes(&mut self, value: &[u8]) {325		self.memory(value)326	}327328	/// Finish writer, concatenating all internal buffers329	pub fn finish(mut self) -> Vec<u8> {330		for (static_offset, part) in self.dynamic_part {331			let part_offset = self.static_part.len()332				- if self.had_call { 4 } else { 0 }333				- if self.is_dynamic { ABI_ALIGNMENT } else { 0 };334335			let encoded_dynamic_offset = usize::to_be_bytes(part_offset);336			let start = static_offset + ABI_ALIGNMENT - encoded_dynamic_offset.len();337			let stop = static_offset + ABI_ALIGNMENT;338			self.static_part[start..stop].copy_from_slice(&encoded_dynamic_offset);339			self.static_part.extend(part.finish())340		}341		self.static_part342	}343}344345/// [`AbiReader`] implements reading of many types, but it should346/// be limited to types defined in spec347///348/// As this trait can't be made sealed,349/// instead of having `impl AbiRead for T`, we have `impl AbiRead<T> for AbiReader`350pub trait AbiRead<T> {351	/// Read item from current position, advanding decoder352	fn abi_read(&mut self) -> Result<T>;353}354355macro_rules! impl_abi_readable {356	($ty:ty, $method:ident, $dynamic:literal) => {357		impl TypeHelper for $ty {358			fn is_dynamic() -> bool {359				$dynamic360			}361362			fn size() -> usize {363				ABI_ALIGNMENT364			}365		}366		impl AbiRead<$ty> for AbiReader<'_> {367			fn abi_read(&mut self) -> Result<$ty> {368				self.$method()369			}370		}371	};372}373374impl_abi_readable!(bool, bool, false);375impl_abi_readable!(uint8, uint8, false);376impl_abi_readable!(uint32, uint32, false);377impl_abi_readable!(uint64, uint64, false);378impl_abi_readable!(uint128, uint128, false);379impl_abi_readable!(uint256, uint256, false);380impl_abi_readable!(bytes4, bytes4, false);381impl_abi_readable!(address, address, false);382impl_abi_readable!(string, string, true);383384impl TypeHelper for bytes {385	fn is_dynamic() -> bool {386		true387	}388	fn size() -> usize {389		ABI_ALIGNMENT390	}391}392impl AbiRead<bytes> for AbiReader<'_> {393	fn abi_read(&mut self) -> Result<bytes> {394		Ok(bytes(self.bytes()?))395	}396}397398mod sealed {399	/// Not all types can be placed in vec, i.e `Vec<u8>` is restricted, `bytes` should be used instead400	pub trait CanBePlacedInVec {}401}402403impl sealed::CanBePlacedInVec for U256 {}404impl sealed::CanBePlacedInVec for string {}405impl sealed::CanBePlacedInVec for H160 {}406impl sealed::CanBePlacedInVec for EthCrossAccount {}407408impl<R: sealed::CanBePlacedInVec> AbiRead<Vec<R>> for AbiReader<'_>409where410	Self: AbiRead<R>,411{412	fn abi_read(&mut self) -> Result<Vec<R>> {413		let mut sub = self.subresult(None)?;414		let size = sub.uint32()? as usize;415		sub.subresult_offset = sub.offset;416		let mut out = Vec::with_capacity(size);417		for _ in 0..size {418			out.push(<Self as AbiRead<R>>::abi_read(&mut sub)?);419		}420		Ok(out)421	}422}423424impl<R: Signature> Signature for Vec<R> {425	make_signature!(new nameof(R) fixed("[]"));426}427428impl TypeHelper for EthCrossAccount {429	fn is_dynamic() -> bool {430		address::is_dynamic() || uint256::is_dynamic()431	}432433	fn size() -> usize {434		<address as TypeHelper>::size() + <uint256 as TypeHelper>::size()435	}436}437438impl AbiRead<EthCrossAccount> for AbiReader<'_> {439	fn abi_read(&mut self) -> Result<EthCrossAccount> {440		let size = if !EthCrossAccount::is_dynamic() {441			Some(<EthCrossAccount as TypeHelper>::size())442		} else {443			None444		};445		let mut subresult = self.subresult(size)?;446		let eth = <Self as AbiRead<address>>::abi_read(&mut subresult)?;447		let sub = <Self as AbiRead<uint256>>::abi_read(&mut subresult)?;448449		Ok(EthCrossAccount { eth, sub })450	}451}452453impl AbiWrite for EthCrossAccount {454	fn abi_write(&self, writer: &mut AbiWriter) {455		self.eth.abi_write(writer);456		self.sub.abi_write(writer);457	}458}459460macro_rules! impl_tuples {461	($($ident:ident)+) => {462		impl<$($ident: TypeHelper,)+> TypeHelper for ($($ident,)+)463		where464			$(465				$ident: TypeHelper,466			)+467		{468			fn is_dynamic() -> bool {469				false470				$(471					|| <$ident>::is_dynamic()472				)*473			}474475			fn size() -> usize {476				0 $(+ <$ident>::size())+477			}478		}479480		impl<$($ident),+> sealed::CanBePlacedInVec for ($($ident,)+) {}481482		impl<$($ident),+> AbiRead<($($ident,)+)> for AbiReader<'_>483		where484			$(485				Self: AbiRead<$ident>,486			)+487			($($ident,)+): TypeHelper,488		{489			fn abi_read(&mut self) -> Result<($($ident,)+)> {490				let size = if !<($($ident,)+)>::is_dynamic() { Some(<($($ident,)+)>::size()) } else { None };491				let mut subresult = self.subresult(size)?;492				Ok((493					$(<Self as AbiRead<$ident>>::abi_read(&mut subresult)?,)+494				))495			}496		}497498		#[allow(non_snake_case)]499		impl<$($ident),+> AbiWrite for ($($ident,)+)500		where501			$($ident: AbiWrite,)+502		{503			fn abi_write(&self, writer: &mut AbiWriter) {504				let ($($ident,)+) = self;505				if writer.is_dynamic {506					let mut sub = AbiWriter::new();507					$($ident.abi_write(&mut sub);)+508					writer.write_subresult(sub);509				} else {510					$($ident.abi_write(writer);)+511				}512			}513		}514515		impl<$($ident),+> Signature for ($($ident,)+)516		where517		$($ident: Signature,)+518		{519			make_signature!(520				new fixed("(")521				$(nameof($ident) fixed(","))+522				shift_left(1)523				fixed(")")524			);525		}526	};527}528529impl_tuples! {A}530impl_tuples! {A B}531impl_tuples! {A B C}532impl_tuples! {A B C D}533impl_tuples! {A B C D E}534impl_tuples! {A B C D E F}535impl_tuples! {A B C D E F G}536impl_tuples! {A B C D E F G H}537impl_tuples! {A B C D E F G H I}538impl_tuples! {A B C D E F G H I J}539540/// For questions about inability to provide custom implementations,541/// see [`AbiRead`]542pub trait AbiWrite {543	/// Write value to end of specified encoder544	fn abi_write(&self, writer: &mut AbiWriter);545	/// Specialization for [`crate::solidity_interface`] implementation,546	/// see comment in `impl AbiWrite for ResultWithPostInfo`547	fn to_result(&self) -> ResultWithPostInfo<AbiWriter> {548		let mut writer = AbiWriter::new();549		self.abi_write(&mut writer);550		Ok(writer.into())551	}552}553554/// This particular AbiWrite implementation should be split to another trait,555/// which only implements `to_result`, but due to lack of specialization feature556/// in stable Rust, we can't have blanket impl of this trait `for T where T: AbiWrite`,557/// so here we abusing default trait methods for it558impl<T: AbiWrite> AbiWrite for ResultWithPostInfo<T> {559	fn abi_write(&self, _writer: &mut AbiWriter) {560		debug_assert!(false, "shouldn't be called, see comment")561	}562	fn to_result(&self) -> ResultWithPostInfo<AbiWriter> {563		match self {564			Ok(v) => Ok(WithPostDispatchInfo {565				post_info: v.post_info.clone(),566				data: {567					let mut out = AbiWriter::new();568					v.data.abi_write(&mut out);569					out570				},571			}),572			Err(e) => Err(e.clone()),573		}574	}575}576577macro_rules! impl_abi_writeable {578	($ty:ty, $method:ident) => {579		impl AbiWrite for $ty {580			fn abi_write(&self, writer: &mut AbiWriter) {581				writer.$method(&self)582			}583		}584	};585}586587impl_abi_writeable!(u8, uint8);588impl_abi_writeable!(u32, uint32);589impl_abi_writeable!(u128, uint128);590impl_abi_writeable!(U256, uint256);591impl_abi_writeable!(H160, address);592impl_abi_writeable!(bool, bool);593impl_abi_writeable!(&str, string);594595impl AbiWrite for string {596	fn abi_write(&self, writer: &mut AbiWriter) {597		writer.string(self)598	}599}600601impl AbiWrite for bytes {602	fn abi_write(&self, writer: &mut AbiWriter) {603		writer.bytes(self.0.as_slice())604	}605}606607impl<T: AbiWrite + TypeHelper> AbiWrite for Vec<T> {608	fn abi_write(&self, writer: &mut AbiWriter) {609		let is_dynamic = T::is_dynamic();610		let mut sub = if is_dynamic {611			AbiWriter::new_dynamic(is_dynamic)612		} else {613			AbiWriter::new()614		};615616		// Write items count617		(self.len() as u32).abi_write(&mut sub);618619		for item in self {620			item.abi_write(&mut sub);621		}622		writer.write_subresult(sub);623	}624}625626impl AbiWrite for () {627	fn abi_write(&self, _writer: &mut AbiWriter) {}628}629630/// Helper macros to parse reader into variables631#[deprecated]632#[macro_export]633macro_rules! abi_decode {634	($reader:expr, $($name:ident: $typ:ident),+ $(,)?) => {635		$(636			let $name = $reader.$typ()?;637		)+638	}639}640641/// Helper macros to construct RLP-encoded buffer642#[deprecated]643#[macro_export]644macro_rules! abi_encode {645	($($typ:ident($value:expr)),* $(,)?) => {{646		#[allow(unused_mut)]647		let mut writer = ::evm_coder::abi::AbiWriter::new();648		$(649			writer.$typ($value);650		)*651		writer652	}};653	(call $val:expr; $($typ:ident($value:expr)),* $(,)?) => {{654		#[allow(unused_mut)]655		let mut writer = ::evm_coder::abi::AbiWriter::new_call($val);656		$(657			writer.$typ($value);658		)*659		writer660	}}661}662663#[cfg(test)]664pub mod test {665	use crate::{666		abi::{AbiRead, AbiWrite},667		types::*,668	};669670	use super::{AbiReader, AbiWriter};671	use hex_literal::hex;672	use primitive_types::{H160, U256};673	use concat_idents::concat_idents;674675	macro_rules! test_impl {676		($name:ident, $type:ty, $function_identifier:expr, $decoded_data:expr, $encoded_data:expr) => {677			concat_idents!(test_name = encode_decode_, $name {678				#[test]679				fn test_name() {680					let function_identifier: u32 = $function_identifier;681					let decoded_data = $decoded_data;682					let encoded_data = $encoded_data;683684					let (call, mut decoder) = AbiReader::new_call(encoded_data).unwrap();685					assert_eq!(call, u32::to_be_bytes(function_identifier));686					let data = <AbiReader<'_> as AbiRead<$type>>::abi_read(&mut decoder).unwrap();687					assert_eq!(data, decoded_data);688689					let mut writer = AbiWriter::new_call(function_identifier);690					decoded_data.abi_write(&mut writer);691					let ed = writer.finish();692					similar_asserts::assert_eq!(encoded_data, ed.as_slice());693				}694			});695		};696	}697698	macro_rules! test_impl_uint {699		($type:ident) => {700			test_impl!(701				$type,702				$type,703				0xdeadbeef,704				255 as $type,705				&hex!(706					"707						deadbeef708						00000000000000000000000000000000000000000000000000000000000000ff709					"710				)711			);712		};713	}714715	test_impl_uint!(uint8);716	test_impl_uint!(uint32);717	test_impl_uint!(uint128);718719	test_impl!(720		uint256,721		uint256,722		0xdeadbeef,723		U256([255, 0, 0, 0]),724		&hex!(725			"726				deadbeef727				00000000000000000000000000000000000000000000000000000000000000ff728			"729		)730	);731732	test_impl!(733		vec_tuple_address_uint256,734		Vec<(address, uint256)>,735		0x1ACF2D55,736		vec![737			(738				H160(hex!("2D2FF76104B7BACB2E8F6731D5BFC184EBECDDBC")),739				U256([10, 0, 0, 0]),740			),741			(742				H160(hex!("AB8E3D9134955566483B11E6825C9223B6737B10")),743				U256([20, 0, 0, 0]),744			),745			(746				H160(hex!("8C582BDF2953046705FC56F189385255EFC1BE18")),747				U256([30, 0, 0, 0]),748			),749		],750		&hex!(751			"752				1ACF2D55753				0000000000000000000000000000000000000000000000000000000000000020 // offset of (address, uint256)[]754				0000000000000000000000000000000000000000000000000000000000000003 // length of (address, uint256)[]755	756				0000000000000000000000002D2FF76104B7BACB2E8F6731D5BFC184EBECDDBC // address757				000000000000000000000000000000000000000000000000000000000000000A // uint256758	759				000000000000000000000000AB8E3D9134955566483B11E6825C9223B6737B10 // address760				0000000000000000000000000000000000000000000000000000000000000014 // uint256761	762				0000000000000000000000008C582BDF2953046705FC56F189385255EFC1BE18 // address763				000000000000000000000000000000000000000000000000000000000000001E // uint256764			"765		)766	);767768	test_impl!(769		vec_tuple_uint256_string,770		Vec<(uint256, string)>,771		0xdeadbeef,772		vec![773			(1.into(), "Test URI 0".to_string()),774			(11.into(), "Test URI 1".to_string()),775			(12.into(), "Test URI 2".to_string()),776		],777		&hex!(778			"779				deadbeef780				0000000000000000000000000000000000000000000000000000000000000020 // offset of (uint256, string)[]781				0000000000000000000000000000000000000000000000000000000000000003 // length of (uint256, string)[]782783				0000000000000000000000000000000000000000000000000000000000000060 // offset of first elem784				00000000000000000000000000000000000000000000000000000000000000e0 // offset of second elem785				0000000000000000000000000000000000000000000000000000000000000160 // offset of third elem786787				0000000000000000000000000000000000000000000000000000000000000001 // first token id?   					#60788				0000000000000000000000000000000000000000000000000000000000000040 // offset of string789				000000000000000000000000000000000000000000000000000000000000000a // size of string790				5465737420555249203000000000000000000000000000000000000000000000 // string791792				000000000000000000000000000000000000000000000000000000000000000b // second token id? Why ==11?			#e0793				0000000000000000000000000000000000000000000000000000000000000040 // offset of string794				000000000000000000000000000000000000000000000000000000000000000a // size of string795				5465737420555249203100000000000000000000000000000000000000000000 // string796797				000000000000000000000000000000000000000000000000000000000000000c // third token id?  Why ==12?			#160798				0000000000000000000000000000000000000000000000000000000000000040 // offset of string799				000000000000000000000000000000000000000000000000000000000000000a // size of string800				5465737420555249203200000000000000000000000000000000000000000000 // string801			"802		)803	);804805	#[test]806	fn dynamic_after_static() {807		let mut encoder = AbiWriter::new();808		encoder.bool(&true);809		encoder.string("test");810		let encoded = encoder.finish();811812		let mut encoder = AbiWriter::new();813		encoder.bool(&true);814		// Offset to subresult815		encoder.uint32(&(32 * 2));816		// Len of "test"817		encoder.uint32(&4);818		encoder.write_padright(&[b't', b'e', b's', b't']);819		let alternative_encoded = encoder.finish();820821		assert_eq!(encoded, alternative_encoded);822823		let mut decoder = AbiReader::new(&encoded);824		assert!(decoder.bool().unwrap());825		assert_eq!(decoder.string().unwrap(), "test");826	}827828	#[test]829	fn mint_sample() {830		let (call, mut decoder) = AbiReader::new_call(&hex!(831			"832				50bb4e7f833				000000000000000000000000ad2c0954693c2b5404b7e50967d3481bea432374834				0000000000000000000000000000000000000000000000000000000000000001835				0000000000000000000000000000000000000000000000000000000000000060836				0000000000000000000000000000000000000000000000000000000000000008837				5465737420555249000000000000000000000000000000000000000000000000838			"839		))840		.unwrap();841		assert_eq!(call, u32::to_be_bytes(0x50bb4e7f));842		assert_eq!(843			format!("{:?}", decoder.address().unwrap()),844			"0xad2c0954693c2b5404b7e50967d3481bea432374"845		);846		assert_eq!(decoder.uint32().unwrap(), 1);847		assert_eq!(decoder.string().unwrap(), "Test URI");848	}849850	#[test]851	fn parse_vec_with_dynamic_type() {852		let decoded_data = (853			0x36543006,854			vec![855				(1.into(), "Test URI 0".to_string()),856				(11.into(), "Test URI 1".to_string()),857				(12.into(), "Test URI 2".to_string()),858			],859		);860861		let encoded_data = &hex!(862			"863				36543006864				00000000000000000000000053744e6da587ba10b32a2554d2efdcd985bc27a3 // address865				0000000000000000000000000000000000000000000000000000000000000040 // offset of (uint256, string)[]866				0000000000000000000000000000000000000000000000000000000000000003 // length of (uint256, string)[]867868				0000000000000000000000000000000000000000000000000000000000000060 // offset of first elem869				00000000000000000000000000000000000000000000000000000000000000e0 // offset of second elem870				0000000000000000000000000000000000000000000000000000000000000160 // offset of third elem871872				0000000000000000000000000000000000000000000000000000000000000001 // first token id?   					#60873				0000000000000000000000000000000000000000000000000000000000000040 // offset of string874				000000000000000000000000000000000000000000000000000000000000000a // size of string875				5465737420555249203000000000000000000000000000000000000000000000 // string876877				000000000000000000000000000000000000000000000000000000000000000b // second token id? Why ==11?			#e0878				0000000000000000000000000000000000000000000000000000000000000040 // offset of string879				000000000000000000000000000000000000000000000000000000000000000a // size of string880				5465737420555249203100000000000000000000000000000000000000000000 // string881882				000000000000000000000000000000000000000000000000000000000000000c // third token id?  Why ==12?			#160883				0000000000000000000000000000000000000000000000000000000000000040 // offset of string884				000000000000000000000000000000000000000000000000000000000000000a // size of string885				5465737420555249203200000000000000000000000000000000000000000000 // string886			"887		);888889		let (call, mut decoder) = AbiReader::new_call(encoded_data).unwrap();890		assert_eq!(call, u32::to_be_bytes(decoded_data.0));891		let address = decoder.address().unwrap();892		let data =893			<AbiReader<'_> as AbiRead<Vec<(uint256, string)>>>::abi_read(&mut decoder).unwrap();894		assert_eq!(data, decoded_data.1);895896		let mut writer = AbiWriter::new_call(decoded_data.0);897		address.abi_write(&mut writer);898		decoded_data.1.abi_write(&mut writer);899		let ed = writer.finish();900		similar_asserts::assert_eq!(encoded_data, ed.as_slice());901	}902}