12345678910111213141516171819#![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 36 fn is_dynamic() -> bool;3738 39 fn size() -> usize;40}414243#[derive(Clone)]44pub struct AbiReader<'i> {45 buf: &'i [u8],46 subresult_offset: usize,47 offset: usize,48}49impl<'i> AbiReader<'i> {50 51 pub fn new(buf: &'i [u8]) -> Self {52 Self {53 buf,54 subresult_offset: 0,55 offset: 0,56 }57 }58 59 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 123 pub fn address(&mut self) -> Result<H160> {124 Ok(H160(self.read_padleft()?))125 }126127 128 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 138 pub fn bytes4(&mut self) -> Result<[u8; 4]> {139 self.read_padright()140 }141142 143 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 153 pub fn string(&mut self) -> Result<string> {154 string::from_utf8(self.bytes()?).map_err(|_| Error::Error(ExitError::InvalidRange))155 }156157 158 pub fn uint8(&mut self) -> Result<u8> {159 Ok(self.read_padleft::<1>()?[0])160 }161162 163 pub fn uint32(&mut self) -> Result<u32> {164 Ok(u32::from_be_bytes(self.read_padleft()?))165 }166167 168 pub fn uint128(&mut self) -> Result<u128> {169 Ok(u128::from_be_bytes(self.read_padleft()?))170 }171172 173 pub fn uint256(&mut self) -> Result<U256> {174 let buf: [u8; 32] = self.read_padleft()?;175 Ok(U256::from_big_endian(&buf))176 }177178 179 pub fn uint64(&mut self) -> Result<u64> {180 Ok(u64::from_be_bytes(self.read_padleft()?))181 }182183 184 #[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 190 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 214 pub fn is_finished(&self) -> bool {215 self.buf.len() == self.offset216 }217}218219220#[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 229 pub fn new() -> Self {230 Self::default()231 }232233 234 pub fn new_dynamic(is_dynamic: bool) -> Self {235 Self {236 is_dynamic,237 ..Default::default()238 }239 }240 241 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 263 pub fn address(&mut self, address: &H160) {264 self.write_padleft(&address.0)265 }266267 268 pub fn bool(&mut self, value: &bool) {269 self.write_padleft(&[if *value { 1 } else { 0 }])270 }271272 273 pub fn uint8(&mut self, value: &u8) {274 self.write_padleft(&[*value])275 }276277 278 pub fn uint32(&mut self, value: &u32) {279 self.write_padleft(&u32::to_be_bytes(*value))280 }281282 283 pub fn uint128(&mut self, value: &u128) {284 self.write_padleft(&u128::to_be_bytes(*value))285 }286287 288 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 295 #[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 301 pub fn write_subresult(&mut self, result: Self) {302 self.dynamic_part.push((self.static_part.len(), result));303 304 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 317 pub fn string(&mut self, value: &str) {318 self.memory(value.as_bytes())319 }320321 322 pub fn bytes(&mut self, value: &[u8]) {323 self.memory(value)324 }325326 327 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}342343344345346347348pub trait AbiRead<T> {349 350 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);381382383impl 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 399 pub trait CanBePlacedInVec {}400}401402impl sealed::CanBePlacedInVec for U256 {}403impl sealed::CanBePlacedInVec for string {}404impl sealed::CanBePlacedInVec for H160 {}405impl sealed::CanBePlacedInVec for EthCrossAccount {}406407impl<R: sealed::CanBePlacedInVec> AbiRead<Vec<R>> for AbiReader<'_>408where409 Self: AbiRead<R>,410{411 fn abi_read(&mut self) -> Result<Vec<R>> {412 let mut sub = self.subresult(None)?;413 let size = sub.uint32()? as usize;414 sub.subresult_offset = sub.offset;415 let mut out = Vec::with_capacity(size);416 for _ in 0..size {417 out.push(<Self as AbiRead<R>>::abi_read(&mut sub)?);418 }419 Ok(out)420 }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<EthCrossAccount> for AbiReader<'_> {434 fn abi_read(&mut self) -> Result<EthCrossAccount> {435 let size = if !EthCrossAccount::is_dynamic() {436 Some(<EthCrossAccount as TypeHelper>::size())437 } else {438 None439 };440 let mut subresult = self.subresult(size)?;441 let eth = <Self as AbiRead<address>>::abi_read(&mut subresult)?;442 let sub = <Self as AbiRead<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 }474 impl<$($ident),+> sealed::CanBePlacedInVec for ($($ident,)+) {}475 impl<$($ident),+> AbiRead<($($ident,)+)> for AbiReader<'_>476 where477 $(478 Self: AbiRead<$ident>,479 )+480 ($($ident,)+): TypeHelper,481 {482 fn abi_read(&mut self) -> Result<($($ident,)+)> {483 let size = if !<($($ident,)+)>::is_dynamic() { Some(<($($ident,)+)>::size()) } else { None };484 let mut subresult = self.subresult(size)?;485 Ok((486 $(<Self as AbiRead<$ident>>::abi_read(&mut subresult)?,)+487 ))488 }489 }490 #[allow(non_snake_case)]491 impl<$($ident),+> AbiWrite for ($($ident,)+)492 where493 $($ident: AbiWrite,)+494 {495 fn abi_write(&self, writer: &mut AbiWriter) {496 let ($($ident,)+) = self;497 if writer.is_dynamic {498 let mut sub = AbiWriter::new();499 $($ident.abi_write(&mut sub);)+500 writer.write_subresult(sub);501 } else {502 $($ident.abi_write(writer);)+503 }504 }505 }506 };507}508509impl_tuples! {A}510impl_tuples! {A B}511impl_tuples! {A B C}512impl_tuples! {A B C D}513impl_tuples! {A B C D E}514impl_tuples! {A B C D E F}515impl_tuples! {A B C D E F G}516impl_tuples! {A B C D E F G H}517impl_tuples! {A B C D E F G H I}518impl_tuples! {A B C D E F G H I J}519520521522pub trait AbiWrite {523 524 fn abi_write(&self, writer: &mut AbiWriter);525 526 527 fn to_result(&self) -> ResultWithPostInfo<AbiWriter> {528 let mut writer = AbiWriter::new();529 self.abi_write(&mut writer);530 Ok(writer.into())531 }532}533534535536537538impl<T: AbiWrite> AbiWrite for ResultWithPostInfo<T> {539 fn abi_write(&self, _writer: &mut AbiWriter) {540 debug_assert!(false, "shouldn't be called, see comment")541 }542 fn to_result(&self) -> ResultWithPostInfo<AbiWriter> {543 match self {544 Ok(v) => Ok(WithPostDispatchInfo {545 post_info: v.post_info.clone(),546 data: {547 let mut out = AbiWriter::new();548 v.data.abi_write(&mut out);549 out550 },551 }),552 Err(e) => Err(e.clone()),553 }554 }555}556557macro_rules! impl_abi_writeable {558 ($ty:ty, $method:ident) => {559 impl AbiWrite for $ty {560 fn abi_write(&self, writer: &mut AbiWriter) {561 writer.$method(&self)562 }563 }564 };565}566567impl_abi_writeable!(u8, uint8);568impl_abi_writeable!(u32, uint32);569impl_abi_writeable!(u128, uint128);570impl_abi_writeable!(U256, uint256);571impl_abi_writeable!(H160, address);572impl_abi_writeable!(bool, bool);573impl_abi_writeable!(&str, string);574575impl AbiWrite for string {576 fn abi_write(&self, writer: &mut AbiWriter) {577 writer.string(self)578 }579}580581impl AbiWrite for bytes {582 fn abi_write(&self, writer: &mut AbiWriter) {583 writer.bytes(self.0.as_slice())584 }585}586587impl<T: AbiWrite + TypeHelper> AbiWrite for Vec<T> {588 fn abi_write(&self, writer: &mut AbiWriter) {589 let is_dynamic = T::is_dynamic();590 let mut sub = if is_dynamic {591 AbiWriter::new_dynamic(is_dynamic)592 } else {593 AbiWriter::new()594 };595596 597 (self.len() as u32).abi_write(&mut sub);598599 for item in self {600 item.abi_write(&mut sub);601 }602 writer.write_subresult(sub);603 }604}605606impl AbiWrite for () {607 fn abi_write(&self, _writer: &mut AbiWriter) {}608}609610611#[deprecated]612#[macro_export]613macro_rules! abi_decode {614 ($reader:expr, $($name:ident: $typ:ident),+ $(,)?) => {615 $(616 let $name = $reader.$typ()?;617 )+618 }619}620621622#[deprecated]623#[macro_export]624macro_rules! abi_encode {625 ($($typ:ident($value:expr)),* $(,)?) => {{626 #[allow(unused_mut)]627 let mut writer = ::evm_coder::abi::AbiWriter::new();628 $(629 writer.$typ($value);630 )*631 writer632 }};633 (call $val:expr; $($typ:ident($value:expr)),* $(,)?) => {{634 #[allow(unused_mut)]635 let mut writer = ::evm_coder::abi::AbiWriter::new_call($val);636 $(637 writer.$typ($value);638 )*639 writer640 }}641}642643#[cfg(test)]644pub mod test {645 use crate::{646 abi::{AbiRead, AbiWrite},647 types::*,648 };649650 use super::{AbiReader, AbiWriter};651 use hex_literal::hex;652 use primitive_types::{H160, U256};653 use concat_idents::concat_idents;654655 macro_rules! test_impl {656 ($name:ident, $type:ty, $function_identifier:expr, $decoded_data:expr, $encoded_data:expr) => {657 concat_idents!(test_name = encode_decode_, $name {658 #[test]659 fn test_name() {660 let function_identifier: u32 = $function_identifier;661 let decoded_data = $decoded_data;662 let encoded_data = $encoded_data;663664 let (call, mut decoder) = AbiReader::new_call(encoded_data).unwrap();665 assert_eq!(call, u32::to_be_bytes(function_identifier));666 let data = <AbiReader<'_> as AbiRead<$type>>::abi_read(&mut decoder).unwrap();667 assert_eq!(data, decoded_data);668669 let mut writer = AbiWriter::new_call(function_identifier);670 decoded_data.abi_write(&mut writer);671 let ed = writer.finish();672 similar_asserts::assert_eq!(encoded_data, ed.as_slice());673 }674 });675 };676 }677678 macro_rules! test_impl_uint {679 ($type:ident) => {680 test_impl!(681 $type,682 $type,683 0xdeadbeef,684 255 as $type,685 &hex!(686 "687 deadbeef688 00000000000000000000000000000000000000000000000000000000000000ff689 "690 )691 );692 };693 }694695 test_impl_uint!(uint8);696 test_impl_uint!(uint32);697 test_impl_uint!(uint128);698699 test_impl!(700 uint256,701 uint256,702 0xdeadbeef,703 U256([255, 0, 0, 0]),704 &hex!(705 "706 deadbeef707 00000000000000000000000000000000000000000000000000000000000000ff708 "709 )710 );711712 test_impl!(713 vec_tuple_address_uint256,714 Vec<(address, uint256)>,715 0x1ACF2D55,716 vec![717 (718 H160(hex!("2D2FF76104B7BACB2E8F6731D5BFC184EBECDDBC")),719 U256([10, 0, 0, 0]),720 ),721 (722 H160(hex!("AB8E3D9134955566483B11E6825C9223B6737B10")),723 U256([20, 0, 0, 0]),724 ),725 (726 H160(hex!("8C582BDF2953046705FC56F189385255EFC1BE18")),727 U256([30, 0, 0, 0]),728 ),729 ],730 &hex!(731 "732 1ACF2D55733 0000000000000000000000000000000000000000000000000000000000000020 // offset of (address, uint256)[]734 0000000000000000000000000000000000000000000000000000000000000003 // length of (address, uint256)[]735 736 0000000000000000000000002D2FF76104B7BACB2E8F6731D5BFC184EBECDDBC // address737 000000000000000000000000000000000000000000000000000000000000000A // uint256738 739 000000000000000000000000AB8E3D9134955566483B11E6825C9223B6737B10 // address740 0000000000000000000000000000000000000000000000000000000000000014 // uint256741 742 0000000000000000000000008C582BDF2953046705FC56F189385255EFC1BE18 // address743 000000000000000000000000000000000000000000000000000000000000001E // uint256744 "745 )746 );747748 test_impl!(749 vec_tuple_uint256_string,750 Vec<(uint256, string)>,751 0xdeadbeef,752 vec![753 (1.into(), "Test URI 0".to_string()),754 (11.into(), "Test URI 1".to_string()),755 (12.into(), "Test URI 2".to_string()),756 ],757 &hex!(758 "759 deadbeef760 0000000000000000000000000000000000000000000000000000000000000020 // offset of (uint256, string)[]761 0000000000000000000000000000000000000000000000000000000000000003 // length of (uint256, string)[]762763 0000000000000000000000000000000000000000000000000000000000000060 // offset of first elem764 00000000000000000000000000000000000000000000000000000000000000e0 // offset of second elem765 0000000000000000000000000000000000000000000000000000000000000160 // offset of third elem766767 0000000000000000000000000000000000000000000000000000000000000001 // first token id? #60768 0000000000000000000000000000000000000000000000000000000000000040 // offset of string769 000000000000000000000000000000000000000000000000000000000000000a // size of string770 5465737420555249203000000000000000000000000000000000000000000000 // string771772 000000000000000000000000000000000000000000000000000000000000000b // second token id? Why ==11? #e0773 0000000000000000000000000000000000000000000000000000000000000040 // offset of string774 000000000000000000000000000000000000000000000000000000000000000a // size of string775 5465737420555249203100000000000000000000000000000000000000000000 // string776777 000000000000000000000000000000000000000000000000000000000000000c // third token id? Why ==12? #160778 0000000000000000000000000000000000000000000000000000000000000040 // offset of string779 000000000000000000000000000000000000000000000000000000000000000a // size of string780 5465737420555249203200000000000000000000000000000000000000000000 // string781 "782 )783 );784785 #[test]786 fn dynamic_after_static() {787 let mut encoder = AbiWriter::new();788 encoder.bool(&true);789 encoder.string("test");790 let encoded = encoder.finish();791792 let mut encoder = AbiWriter::new();793 encoder.bool(&true);794 795 encoder.uint32(&(32 * 2));796 797 encoder.uint32(&4);798 encoder.write_padright(&[b't', b'e', b's', b't']);799 let alternative_encoded = encoder.finish();800801 assert_eq!(encoded, alternative_encoded);802803 let mut decoder = AbiReader::new(&encoded);804 assert!(decoder.bool().unwrap());805 assert_eq!(decoder.string().unwrap(), "test");806 }807808 #[test]809 fn mint_sample() {810 let (call, mut decoder) = AbiReader::new_call(&hex!(811 "812 50bb4e7f813 000000000000000000000000ad2c0954693c2b5404b7e50967d3481bea432374814 0000000000000000000000000000000000000000000000000000000000000001815 0000000000000000000000000000000000000000000000000000000000000060816 0000000000000000000000000000000000000000000000000000000000000008817 5465737420555249000000000000000000000000000000000000000000000000818 "819 ))820 .unwrap();821 assert_eq!(call, u32::to_be_bytes(0x50bb4e7f));822 assert_eq!(823 format!("{:?}", decoder.address().unwrap()),824 "0xad2c0954693c2b5404b7e50967d3481bea432374"825 );826 assert_eq!(decoder.uint32().unwrap(), 1);827 assert_eq!(decoder.string().unwrap(), "Test URI");828 }829830 #[test]831 fn parse_vec_with_dynamic_type() {832 let decoded_data = (833 0x36543006,834 vec![835 (1.into(), "Test URI 0".to_string()),836 (11.into(), "Test URI 1".to_string()),837 (12.into(), "Test URI 2".to_string()),838 ],839 );840841 let encoded_data = &hex!(842 "843 36543006844 00000000000000000000000053744e6da587ba10b32a2554d2efdcd985bc27a3 // address845 0000000000000000000000000000000000000000000000000000000000000040 // offset of (uint256, string)[]846 0000000000000000000000000000000000000000000000000000000000000003 // length of (uint256, string)[]847848 0000000000000000000000000000000000000000000000000000000000000060 // offset of first elem849 00000000000000000000000000000000000000000000000000000000000000e0 // offset of second elem850 0000000000000000000000000000000000000000000000000000000000000160 // offset of third elem851852 0000000000000000000000000000000000000000000000000000000000000001 // first token id? #60853 0000000000000000000000000000000000000000000000000000000000000040 // offset of string854 000000000000000000000000000000000000000000000000000000000000000a // size of string855 5465737420555249203000000000000000000000000000000000000000000000 // string856857 000000000000000000000000000000000000000000000000000000000000000b // second token id? Why ==11? #e0858 0000000000000000000000000000000000000000000000000000000000000040 // offset of string859 000000000000000000000000000000000000000000000000000000000000000a // size of string860 5465737420555249203100000000000000000000000000000000000000000000 // string861862 000000000000000000000000000000000000000000000000000000000000000c // third token id? Why ==12? #160863 0000000000000000000000000000000000000000000000000000000000000040 // offset of string864 000000000000000000000000000000000000000000000000000000000000000a // size of string865 5465737420555249203200000000000000000000000000000000000000000000 // string866 "867 );868869 let (call, mut decoder) = AbiReader::new_call(encoded_data).unwrap();870 assert_eq!(call, u32::to_be_bytes(decoded_data.0));871 let address = decoder.address().unwrap();872 let data =873 <AbiReader<'_> as AbiRead<Vec<(uint256, string)>>>::abi_read(&mut decoder).unwrap();874 assert_eq!(data, decoded_data.1);875876 let mut writer = AbiWriter::new_call(decoded_data.0);877 address.abi_write(&mut writer);878 decoded_data.1.abi_write(&mut writer);879 let ed = writer.finish();880 similar_asserts::assert_eq!(encoded_data, ed.as_slice());881 }882}