git.delta.rocks / unique-network / refs/commits / 527498be3f5d

difftreelog

source

crates/evm-coder/src/abi.rs24.5 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.346pub trait AbiRead {347	/// Read item from current position, advanding decoder348	fn abi_read(reader: &mut AbiReader) -> Result<Self>349	where350		Self: Sized;351}352353macro_rules! impl_abi_readable {354	($ty:ty, $method:ident, $dynamic:literal) => {355		impl TypeHelper for $ty {356			fn is_dynamic() -> bool {357				$dynamic358			}359360			fn size() -> usize {361				ABI_ALIGNMENT362			}363		}364		impl AbiRead for $ty {365			fn abi_read(reader: &mut AbiReader) -> Result<$ty> {366				reader.$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);381382impl TypeHelper for bytes {383	fn is_dynamic() -> bool {384		true385	}386	fn size() -> usize {387		ABI_ALIGNMENT388	}389}390impl AbiRead for bytes {391	fn abi_read(reader: &mut AbiReader) -> Result<bytes> {392		Ok(bytes(reader.bytes()?))393	}394}395396mod sealed {397	/// Not all types can be placed in vec, i.e `Vec<u8>` is restricted, `bytes` should be used instead398	pub trait CanBePlacedInVec {}399}400401impl sealed::CanBePlacedInVec for U256 {}402impl sealed::CanBePlacedInVec for string {}403impl sealed::CanBePlacedInVec for H160 {}404impl sealed::CanBePlacedInVec for EthCrossAccount {}405406impl<R: AbiRead + sealed::CanBePlacedInVec> AbiRead for Vec<R> {407	fn abi_read(reader: &mut AbiReader) -> Result<Vec<R>> {408		let mut sub = reader.subresult(None)?;409		let size = sub.uint32()? as usize;410		sub.subresult_offset = sub.offset;411		let mut out = Vec::with_capacity(size);412		for _ in 0..size {413			out.push(<R>::abi_read(&mut sub)?);414		}415		Ok(out)416	}417}418419impl<R: Signature> Signature for Vec<R> {420	make_signature!(new nameof(R) fixed("[]"));421}422423impl TypeHelper for EthCrossAccount {424	fn is_dynamic() -> bool {425		address::is_dynamic() || uint256::is_dynamic()426	}427428	fn size() -> usize {429		<address as TypeHelper>::size() + <uint256 as TypeHelper>::size()430	}431}432433impl AbiRead for EthCrossAccount {434	fn abi_read(reader: &mut AbiReader) -> Result<EthCrossAccount> {435		let size = if !EthCrossAccount::is_dynamic() {436			Some(<EthCrossAccount as TypeHelper>::size())437		} else {438			None439		};440		let mut subresult = reader.subresult(size)?;441		let eth = <address>::abi_read(&mut subresult)?;442		let sub = <uint256>::abi_read(&mut subresult)?;443444		Ok(EthCrossAccount { eth, sub })445	}446}447448impl AbiWrite for EthCrossAccount {449	fn abi_write(&self, writer: &mut AbiWriter) {450		self.eth.abi_write(writer);451		self.sub.abi_write(writer);452	}453}454455macro_rules! impl_tuples {456	($($ident:ident)+) => {457		impl<$($ident: TypeHelper,)+> TypeHelper for ($($ident,)+)458		where459			$(460				$ident: TypeHelper,461			)+462		{463			fn is_dynamic() -> bool {464				false465				$(466					|| <$ident>::is_dynamic()467				)*468			}469470			fn size() -> usize {471				0 $(+ <$ident>::size())+472			}473		}474475		impl<$($ident),+> sealed::CanBePlacedInVec for ($($ident,)+) {}476477		impl<$($ident),+> AbiRead for ($($ident,)+)478		where479			$($ident: AbiRead,)+480			($($ident,)+): TypeHelper,481		{482			fn abi_read(reader: &mut AbiReader) -> Result<($($ident,)+)> {483				let size = if !<($($ident,)+)>::is_dynamic() { Some(<($($ident,)+)>::size()) } else { None };484				let mut subresult = reader.subresult(size)?;485				Ok((486					$(<$ident>::abi_read(&mut subresult)?,)+487				))488			}489		}490491		#[allow(non_snake_case)]492		impl<$($ident),+> AbiWrite for ($($ident,)+)493		where494			$($ident: AbiWrite,)+495		{496			fn abi_write(&self, writer: &mut AbiWriter) {497				let ($($ident,)+) = self;498				if writer.is_dynamic {499					let mut sub = AbiWriter::new();500					$($ident.abi_write(&mut sub);)+501					writer.write_subresult(sub);502				} else {503					$($ident.abi_write(writer);)+504				}505			}506		}507508		impl<$($ident),+> Signature for ($($ident,)+)509		where510		$($ident: Signature,)+511		{512			make_signature!(513				new fixed("(")514				$(nameof($ident) fixed(","))+515				shift_left(1)516				fixed(")")517			);518		}519	};520}521522impl_tuples! {A}523impl_tuples! {A B}524impl_tuples! {A B C}525impl_tuples! {A B C D}526impl_tuples! {A B C D E}527impl_tuples! {A B C D E F}528impl_tuples! {A B C D E F G}529impl_tuples! {A B C D E F G H}530impl_tuples! {A B C D E F G H I}531impl_tuples! {A B C D E F G H I J}532533/// For questions about inability to provide custom implementations,534/// see [`AbiRead`]535pub trait AbiWrite {536	/// Write value to end of specified encoder537	fn abi_write(&self, writer: &mut AbiWriter);538	/// Specialization for [`crate::solidity_interface`] implementation,539	/// see comment in `impl AbiWrite for ResultWithPostInfo`540	fn to_result(&self) -> ResultWithPostInfo<AbiWriter> {541		let mut writer = AbiWriter::new();542		self.abi_write(&mut writer);543		Ok(writer.into())544	}545}546547/// This particular AbiWrite implementation should be split to another trait,548/// which only implements `to_result`, but due to lack of specialization feature549/// in stable Rust, we can't have blanket impl of this trait `for T where T: AbiWrite`,550/// so here we abusing default trait methods for it551impl<T: AbiWrite> AbiWrite for ResultWithPostInfo<T> {552	fn abi_write(&self, _writer: &mut AbiWriter) {553		debug_assert!(false, "shouldn't be called, see comment")554	}555	fn to_result(&self) -> ResultWithPostInfo<AbiWriter> {556		match self {557			Ok(v) => Ok(WithPostDispatchInfo {558				post_info: v.post_info.clone(),559				data: {560					let mut out = AbiWriter::new();561					v.data.abi_write(&mut out);562					out563				},564			}),565			Err(e) => Err(e.clone()),566		}567	}568}569570macro_rules! impl_abi_writeable {571	($ty:ty, $method:ident) => {572		impl AbiWrite for $ty {573			fn abi_write(&self, writer: &mut AbiWriter) {574				writer.$method(&self)575			}576		}577	};578}579580impl_abi_writeable!(u8, uint8);581impl_abi_writeable!(u32, uint32);582impl_abi_writeable!(u128, uint128);583impl_abi_writeable!(U256, uint256);584impl_abi_writeable!(H160, address);585impl_abi_writeable!(bool, bool);586impl_abi_writeable!(&str, string);587588impl AbiWrite for string {589	fn abi_write(&self, writer: &mut AbiWriter) {590		writer.string(self)591	}592}593594impl AbiWrite for bytes {595	fn abi_write(&self, writer: &mut AbiWriter) {596		writer.bytes(self.0.as_slice())597	}598}599600impl<T: AbiWrite + TypeHelper> AbiWrite for Vec<T> {601	fn abi_write(&self, writer: &mut AbiWriter) {602		let is_dynamic = T::is_dynamic();603		let mut sub = if is_dynamic {604			AbiWriter::new_dynamic(is_dynamic)605		} else {606			AbiWriter::new()607		};608609		// Write items count610		(self.len() as u32).abi_write(&mut sub);611612		for item in self {613			item.abi_write(&mut sub);614		}615		writer.write_subresult(sub);616	}617}618619impl AbiWrite for () {620	fn abi_write(&self, _writer: &mut AbiWriter) {}621}622623/// Helper macros to parse reader into variables624#[deprecated]625#[macro_export]626macro_rules! abi_decode {627	($reader:expr, $($name:ident: $typ:ident),+ $(,)?) => {628		$(629			let $name = $reader.$typ()?;630		)+631	}632}633634/// Helper macros to construct RLP-encoded buffer635#[deprecated]636#[macro_export]637macro_rules! abi_encode {638	($($typ:ident($value:expr)),* $(,)?) => {{639		#[allow(unused_mut)]640		let mut writer = ::evm_coder::abi::AbiWriter::new();641		$(642			writer.$typ($value);643		)*644		writer645	}};646	(call $val:expr; $($typ:ident($value:expr)),* $(,)?) => {{647		#[allow(unused_mut)]648		let mut writer = ::evm_coder::abi::AbiWriter::new_call($val);649		$(650			writer.$typ($value);651		)*652		writer653	}}654}655656#[cfg(test)]657pub mod test {658	use crate::{659		abi::{AbiRead, AbiWrite},660		types::*,661	};662663	use super::{AbiReader, AbiWriter};664	use hex_literal::hex;665	use primitive_types::{H160, U256};666	use concat_idents::concat_idents;667668	macro_rules! test_impl {669		($name:ident, $type:ty, $function_identifier:expr, $decoded_data:expr, $encoded_data:expr) => {670			concat_idents!(test_name = encode_decode_, $name {671				#[test]672				fn test_name() {673					let function_identifier: u32 = $function_identifier;674					let decoded_data = $decoded_data;675					let encoded_data = $encoded_data;676677					let (call, mut decoder) = AbiReader::new_call(encoded_data).unwrap();678					assert_eq!(call, u32::to_be_bytes(function_identifier));679					let data = <$type>::abi_read(&mut decoder).unwrap();680					assert_eq!(data, decoded_data);681682					let mut writer = AbiWriter::new_call(function_identifier);683					decoded_data.abi_write(&mut writer);684					let ed = writer.finish();685					similar_asserts::assert_eq!(encoded_data, ed.as_slice());686				}687			});688		};689	}690691	macro_rules! test_impl_uint {692		($type:ident) => {693			test_impl!(694				$type,695				$type,696				0xdeadbeef,697				255 as $type,698				&hex!(699					"700						deadbeef701						00000000000000000000000000000000000000000000000000000000000000ff702					"703				)704			);705		};706	}707708	test_impl_uint!(uint8);709	test_impl_uint!(uint32);710	test_impl_uint!(uint128);711712	test_impl!(713		uint256,714		uint256,715		0xdeadbeef,716		U256([255, 0, 0, 0]),717		&hex!(718			"719				deadbeef720				00000000000000000000000000000000000000000000000000000000000000ff721			"722		)723	);724725	test_impl!(726		vec_tuple_address_uint256,727		Vec<(address, uint256)>,728		0x1ACF2D55,729		vec![730			(731				H160(hex!("2D2FF76104B7BACB2E8F6731D5BFC184EBECDDBC")),732				U256([10, 0, 0, 0]),733			),734			(735				H160(hex!("AB8E3D9134955566483B11E6825C9223B6737B10")),736				U256([20, 0, 0, 0]),737			),738			(739				H160(hex!("8C582BDF2953046705FC56F189385255EFC1BE18")),740				U256([30, 0, 0, 0]),741			),742		],743		&hex!(744			"745				1ACF2D55746				0000000000000000000000000000000000000000000000000000000000000020 // offset of (address, uint256)[]747				0000000000000000000000000000000000000000000000000000000000000003 // length of (address, uint256)[]748	749				0000000000000000000000002D2FF76104B7BACB2E8F6731D5BFC184EBECDDBC // address750				000000000000000000000000000000000000000000000000000000000000000A // uint256751	752				000000000000000000000000AB8E3D9134955566483B11E6825C9223B6737B10 // address753				0000000000000000000000000000000000000000000000000000000000000014 // uint256754	755				0000000000000000000000008C582BDF2953046705FC56F189385255EFC1BE18 // address756				000000000000000000000000000000000000000000000000000000000000001E // uint256757			"758		)759	);760761	test_impl!(762		vec_tuple_uint256_string,763		Vec<(uint256, string)>,764		0xdeadbeef,765		vec![766			(1.into(), "Test URI 0".to_string()),767			(11.into(), "Test URI 1".to_string()),768			(12.into(), "Test URI 2".to_string()),769		],770		&hex!(771			"772				deadbeef773				0000000000000000000000000000000000000000000000000000000000000020 // offset of (uint256, string)[]774				0000000000000000000000000000000000000000000000000000000000000003 // length of (uint256, string)[]775776				0000000000000000000000000000000000000000000000000000000000000060 // offset of first elem777				00000000000000000000000000000000000000000000000000000000000000e0 // offset of second elem778				0000000000000000000000000000000000000000000000000000000000000160 // offset of third elem779780				0000000000000000000000000000000000000000000000000000000000000001 // first token id?   					#60781				0000000000000000000000000000000000000000000000000000000000000040 // offset of string782				000000000000000000000000000000000000000000000000000000000000000a // size of string783				5465737420555249203000000000000000000000000000000000000000000000 // string784785				000000000000000000000000000000000000000000000000000000000000000b // second token id? Why ==11?			#e0786				0000000000000000000000000000000000000000000000000000000000000040 // offset of string787				000000000000000000000000000000000000000000000000000000000000000a // size of string788				5465737420555249203100000000000000000000000000000000000000000000 // string789790				000000000000000000000000000000000000000000000000000000000000000c // third token id?  Why ==12?			#160791				0000000000000000000000000000000000000000000000000000000000000040 // offset of string792				000000000000000000000000000000000000000000000000000000000000000a // size of string793				5465737420555249203200000000000000000000000000000000000000000000 // string794			"795		)796	);797798	#[test]799	fn dynamic_after_static() {800		let mut encoder = AbiWriter::new();801		encoder.bool(&true);802		encoder.string("test");803		let encoded = encoder.finish();804805		let mut encoder = AbiWriter::new();806		encoder.bool(&true);807		// Offset to subresult808		encoder.uint32(&(32 * 2));809		// Len of "test"810		encoder.uint32(&4);811		encoder.write_padright(&[b't', b'e', b's', b't']);812		let alternative_encoded = encoder.finish();813814		assert_eq!(encoded, alternative_encoded);815816		let mut decoder = AbiReader::new(&encoded);817		assert!(decoder.bool().unwrap());818		assert_eq!(decoder.string().unwrap(), "test");819	}820821	#[test]822	fn mint_sample() {823		let (call, mut decoder) = AbiReader::new_call(&hex!(824			"825				50bb4e7f826				000000000000000000000000ad2c0954693c2b5404b7e50967d3481bea432374827				0000000000000000000000000000000000000000000000000000000000000001828				0000000000000000000000000000000000000000000000000000000000000060829				0000000000000000000000000000000000000000000000000000000000000008830				5465737420555249000000000000000000000000000000000000000000000000831			"832		))833		.unwrap();834		assert_eq!(call, u32::to_be_bytes(0x50bb4e7f));835		assert_eq!(836			format!("{:?}", decoder.address().unwrap()),837			"0xad2c0954693c2b5404b7e50967d3481bea432374"838		);839		assert_eq!(decoder.uint32().unwrap(), 1);840		assert_eq!(decoder.string().unwrap(), "Test URI");841	}842843	#[test]844	fn parse_vec_with_dynamic_type() {845		let decoded_data = (846			0x36543006,847			vec![848				(1.into(), "Test URI 0".to_string()),849				(11.into(), "Test URI 1".to_string()),850				(12.into(), "Test URI 2".to_string()),851			],852		);853854		let encoded_data = &hex!(855			"856				36543006857				00000000000000000000000053744e6da587ba10b32a2554d2efdcd985bc27a3 // address858				0000000000000000000000000000000000000000000000000000000000000040 // offset of (uint256, string)[]859				0000000000000000000000000000000000000000000000000000000000000003 // length of (uint256, string)[]860861				0000000000000000000000000000000000000000000000000000000000000060 // offset of first elem862				00000000000000000000000000000000000000000000000000000000000000e0 // offset of second elem863				0000000000000000000000000000000000000000000000000000000000000160 // offset of third elem864865				0000000000000000000000000000000000000000000000000000000000000001 // first token id?   					#60866				0000000000000000000000000000000000000000000000000000000000000040 // offset of string867				000000000000000000000000000000000000000000000000000000000000000a // size of string868				5465737420555249203000000000000000000000000000000000000000000000 // string869870				000000000000000000000000000000000000000000000000000000000000000b // second token id? Why ==11?			#e0871				0000000000000000000000000000000000000000000000000000000000000040 // offset of string872				000000000000000000000000000000000000000000000000000000000000000a // size of string873				5465737420555249203100000000000000000000000000000000000000000000 // string874875				000000000000000000000000000000000000000000000000000000000000000c // third token id?  Why ==12?			#160876				0000000000000000000000000000000000000000000000000000000000000040 // offset of string877				000000000000000000000000000000000000000000000000000000000000000a // size of string878				5465737420555249203200000000000000000000000000000000000000000000 // string879			"880		);881882		let (call, mut decoder) = AbiReader::new_call(encoded_data).unwrap();883		assert_eq!(call, u32::to_be_bytes(decoded_data.0));884		let address = decoder.address().unwrap();885		let data = <Vec<(uint256, string)>>::abi_read(&mut decoder).unwrap();886		assert_eq!(data, decoded_data.1);887888		let mut writer = AbiWriter::new_call(decoded_data.0);889		address.abi_write(&mut writer);890		decoded_data.1.abi_write(&mut writer);891		let ed = writer.finish();892		similar_asserts::assert_eq!(encoded_data, ed.as_slice());893	}894}