difftreelog
refactor abi module
in: master
17 files changed
crates/evm-coder/procedural/src/solidity_interface.rsdiffbeforeafterboth--- a/crates/evm-coder/procedural/src/solidity_interface.rs
+++ b/crates/evm-coder/procedural/src/solidity_interface.rs
@@ -328,14 +328,14 @@
}
}
-trait AbiType {
+trait AbiTypeHelper {
fn plain(&self) -> syn::Result<&Ident>;
fn is_value(&self) -> bool;
fn is_caller(&self) -> bool;
fn is_special(&self) -> bool;
}
-impl AbiType for Type {
+impl AbiTypeHelper for Type {
fn plain(&self) -> syn::Result<&Ident> {
let path = parse_path(self)?;
let segment = parse_path_segment(path)?;
crates/evm-coder/src/abi.rsdiffbeforeafterboth1// 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},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 sealed::CanBePlacedInVec for $ty {}356357 impl TypeHelper for $ty {358 fn is_dynamic() -> bool {359 $dynamic360 }361362 fn size() -> usize {363 ABI_ALIGNMENT364 }365 }366367 impl AbiRead for $ty {368 fn abi_read(reader: &mut AbiReader) -> Result<$ty> {369 reader.$method()370 }371 }372 };373}374375impl_abi_readable!(bool, bool, 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 uint8 {385 fn is_dynamic() -> bool {386 false387 }388 fn size() -> usize {389 ABI_ALIGNMENT390 }391}392impl AbiRead for uint8 {393 fn abi_read(reader: &mut AbiReader) -> Result<uint8> {394 reader.uint8()395 }396}397398impl TypeHelper for bytes {399 fn is_dynamic() -> bool {400 true401 }402 fn size() -> usize {403 ABI_ALIGNMENT404 }405}406impl AbiRead for bytes {407 fn abi_read(reader: &mut AbiReader) -> Result<bytes> {408 Ok(bytes(reader.bytes()?))409 }410}411412mod sealed {413 /// Not all types can be placed in vec, i.e `Vec<u8>` is restricted, `bytes` should be used instead414 pub trait CanBePlacedInVec {}415}416417impl<R: AbiRead + sealed::CanBePlacedInVec> AbiRead for Vec<R> {418 fn abi_read(reader: &mut AbiReader) -> Result<Vec<R>> {419 let mut sub = reader.subresult(None)?;420 let size = sub.uint32()? as usize;421 sub.subresult_offset = sub.offset;422 let mut out = Vec::with_capacity(size);423 for _ in 0..size {424 out.push(<R>::abi_read(&mut sub)?);425 }426 Ok(out)427 }428}429430impl<R: Signature> Signature for Vec<R> {431 const SIGNATURE: SignatureUnit = make_signature!(new nameof(R::SIGNATURE) fixed("[]"));432}433434impl sealed::CanBePlacedInVec for EthCrossAccount {}435436impl TypeHelper for EthCrossAccount {437 fn is_dynamic() -> bool {438 address::is_dynamic() || uint256::is_dynamic()439 }440441 fn size() -> usize {442 <address as TypeHelper>::size() + <uint256 as TypeHelper>::size()443 }444}445446impl AbiRead for EthCrossAccount {447 fn abi_read(reader: &mut AbiReader) -> Result<EthCrossAccount> {448 let size = if !EthCrossAccount::is_dynamic() {449 Some(<EthCrossAccount as TypeHelper>::size())450 } else {451 None452 };453 let mut subresult = reader.subresult(size)?;454 let eth = <address>::abi_read(&mut subresult)?;455 let sub = <uint256>::abi_read(&mut subresult)?;456457 Ok(EthCrossAccount { eth, sub })458 }459}460461impl AbiWrite for EthCrossAccount {462 fn abi_write(&self, writer: &mut AbiWriter) {463 self.eth.abi_write(writer);464 self.sub.abi_write(writer);465 }466}467468macro_rules! impl_tuples {469 ($($ident:ident)+) => {470 impl<$($ident: TypeHelper,)+> TypeHelper for ($($ident,)+)471 where472 $(473 $ident: TypeHelper,474 )+475 {476 fn is_dynamic() -> bool {477 false478 $(479 || <$ident>::is_dynamic()480 )*481 }482483 fn size() -> usize {484 0 $(+ <$ident>::size())+485 }486 }487488 impl<$($ident),+> sealed::CanBePlacedInVec for ($($ident,)+) {}489490 impl<$($ident),+> AbiRead for ($($ident,)+)491 where492 $($ident: AbiRead,)+493 ($($ident,)+): TypeHelper,494 {495 fn abi_read(reader: &mut AbiReader) -> Result<($($ident,)+)> {496 let size = if !<($($ident,)+)>::is_dynamic() { Some(<($($ident,)+)>::size()) } else { None };497 let mut subresult = reader.subresult(size)?;498 Ok((499 $(<$ident>::abi_read(&mut subresult)?,)+500 ))501 }502 }503504 #[allow(non_snake_case)]505 impl<$($ident),+> AbiWrite for ($($ident,)+)506 where507 $($ident: AbiWrite,)+508 {509 fn abi_write(&self, writer: &mut AbiWriter) {510 let ($($ident,)+) = self;511 if writer.is_dynamic {512 let mut sub = AbiWriter::new();513 $($ident.abi_write(&mut sub);)+514 writer.write_subresult(sub);515 } else {516 $($ident.abi_write(writer);)+517 }518 }519 }520521 impl<$($ident),+> Signature for ($($ident,)+)522 where523 $($ident: Signature,)+524 {525 const SIGNATURE: SignatureUnit = make_signature!(526 new fixed("(")527 $(nameof(<$ident>::SIGNATURE) fixed(","))+528 shift_left(1)529 fixed(")")530 );531 }532 };533}534535impl_tuples! {A}536impl_tuples! {A B}537impl_tuples! {A B C}538impl_tuples! {A B C D}539impl_tuples! {A B C D E}540impl_tuples! {A B C D E F}541impl_tuples! {A B C D E F G}542impl_tuples! {A B C D E F G H}543impl_tuples! {A B C D E F G H I}544impl_tuples! {A B C D E F G H I J}545546/// For questions about inability to provide custom implementations,547/// see [`AbiRead`]548pub trait AbiWrite {549 /// Write value to end of specified encoder550 fn abi_write(&self, writer: &mut AbiWriter);551 /// Specialization for [`crate::solidity_interface`] implementation,552 /// see comment in `impl AbiWrite for ResultWithPostInfo`553 fn to_result(&self) -> ResultWithPostInfo<AbiWriter> {554 let mut writer = AbiWriter::new();555 self.abi_write(&mut writer);556 Ok(writer.into())557 }558}559560/// This particular AbiWrite implementation should be split to another trait,561/// which only implements `to_result`, but due to lack of specialization feature562/// in stable Rust, we can't have blanket impl of this trait `for T where T: AbiWrite`,563/// so here we abusing default trait methods for it564impl<T: AbiWrite> AbiWrite for ResultWithPostInfo<T> {565 fn abi_write(&self, _writer: &mut AbiWriter) {566 debug_assert!(false, "shouldn't be called, see comment")567 }568 fn to_result(&self) -> ResultWithPostInfo<AbiWriter> {569 match self {570 Ok(v) => Ok(WithPostDispatchInfo {571 post_info: v.post_info.clone(),572 data: {573 let mut out = AbiWriter::new();574 v.data.abi_write(&mut out);575 out576 },577 }),578 Err(e) => Err(e.clone()),579 }580 }581}582583macro_rules! impl_abi_writeable {584 ($ty:ty, $method:ident) => {585 impl AbiWrite for $ty {586 fn abi_write(&self, writer: &mut AbiWriter) {587 writer.$method(&self)588 }589 }590 };591}592593impl_abi_writeable!(u8, uint8);594impl_abi_writeable!(u32, uint32);595impl_abi_writeable!(u128, uint128);596impl_abi_writeable!(U256, uint256);597impl_abi_writeable!(H160, address);598impl_abi_writeable!(bool, bool);599impl_abi_writeable!(&str, string);600601impl AbiWrite for string {602 fn abi_write(&self, writer: &mut AbiWriter) {603 writer.string(self)604 }605}606607impl AbiWrite for bytes {608 fn abi_write(&self, writer: &mut AbiWriter) {609 writer.bytes(self.0.as_slice())610 }611}612613impl<T: AbiWrite + TypeHelper> AbiWrite for Vec<T> {614 fn abi_write(&self, writer: &mut AbiWriter) {615 let is_dynamic = T::is_dynamic();616 let mut sub = if is_dynamic {617 AbiWriter::new_dynamic(is_dynamic)618 } else {619 AbiWriter::new()620 };621622 // Write items count623 (self.len() as u32).abi_write(&mut sub);624625 for item in self {626 item.abi_write(&mut sub);627 }628 writer.write_subresult(sub);629 }630}631632impl AbiWrite for () {633 fn abi_write(&self, _writer: &mut AbiWriter) {}634}635636/// Helper macros to parse reader into variables637#[deprecated]638#[macro_export]639macro_rules! abi_decode {640 ($reader:expr, $($name:ident: $typ:ident),+ $(,)?) => {641 $(642 let $name = $reader.$typ()?;643 )+644 }645}646647/// Helper macros to construct RLP-encoded buffer648#[deprecated]649#[macro_export]650macro_rules! abi_encode {651 ($($typ:ident($value:expr)),* $(,)?) => {{652 #[allow(unused_mut)]653 let mut writer = ::evm_coder::abi::AbiWriter::new();654 $(655 writer.$typ($value);656 )*657 writer658 }};659 (call $val:expr; $($typ:ident($value:expr)),* $(,)?) => {{660 #[allow(unused_mut)]661 let mut writer = ::evm_coder::abi::AbiWriter::new_call($val);662 $(663 writer.$typ($value);664 )*665 writer666 }}667}668669#[cfg(test)]670pub mod test {671 use crate::{672 abi::{AbiRead, AbiWrite},673 types::*,674 };675676 use super::{AbiReader, AbiWriter};677 use hex_literal::hex;678 use primitive_types::{H160, U256};679 use concat_idents::concat_idents;680681 macro_rules! test_impl {682 ($name:ident, $type:ty, $function_identifier:expr, $decoded_data:expr, $encoded_data:expr) => {683 concat_idents!(test_name = encode_decode_, $name {684 #[test]685 fn test_name() {686 let function_identifier: u32 = $function_identifier;687 let decoded_data = $decoded_data;688 let encoded_data = $encoded_data;689690 let (call, mut decoder) = AbiReader::new_call(encoded_data).unwrap();691 assert_eq!(call, u32::to_be_bytes(function_identifier));692 let data = <$type>::abi_read(&mut decoder).unwrap();693 assert_eq!(data, decoded_data);694695 let mut writer = AbiWriter::new_call(function_identifier);696 decoded_data.abi_write(&mut writer);697 let ed = writer.finish();698 similar_asserts::assert_eq!(encoded_data, ed.as_slice());699 }700 });701 };702 }703704 macro_rules! test_impl_uint {705 ($type:ident) => {706 test_impl!(707 $type,708 $type,709 0xdeadbeef,710 255 as $type,711 &hex!(712 "713 deadbeef714 00000000000000000000000000000000000000000000000000000000000000ff715 "716 )717 );718 };719 }720721 test_impl_uint!(uint8);722 test_impl_uint!(uint32);723 test_impl_uint!(uint128);724725 test_impl!(726 uint256,727 uint256,728 0xdeadbeef,729 U256([255, 0, 0, 0]),730 &hex!(731 "732 deadbeef733 00000000000000000000000000000000000000000000000000000000000000ff734 "735 )736 );737738 test_impl!(739 vec_tuple_address_uint256,740 Vec<(address, uint256)>,741 0x1ACF2D55,742 vec![743 (744 H160(hex!("2D2FF76104B7BACB2E8F6731D5BFC184EBECDDBC")),745 U256([10, 0, 0, 0]),746 ),747 (748 H160(hex!("AB8E3D9134955566483B11E6825C9223B6737B10")),749 U256([20, 0, 0, 0]),750 ),751 (752 H160(hex!("8C582BDF2953046705FC56F189385255EFC1BE18")),753 U256([30, 0, 0, 0]),754 ),755 ],756 &hex!(757 "758 1ACF2D55759 0000000000000000000000000000000000000000000000000000000000000020 // offset of (address, uint256)[]760 0000000000000000000000000000000000000000000000000000000000000003 // length of (address, uint256)[]761762 0000000000000000000000002D2FF76104B7BACB2E8F6731D5BFC184EBECDDBC // address763 000000000000000000000000000000000000000000000000000000000000000A // uint256764765 000000000000000000000000AB8E3D9134955566483B11E6825C9223B6737B10 // address766 0000000000000000000000000000000000000000000000000000000000000014 // uint256767768 0000000000000000000000008C582BDF2953046705FC56F189385255EFC1BE18 // address769 000000000000000000000000000000000000000000000000000000000000001E // uint256770 "771 )772 );773774 test_impl!(775 vec_tuple_uint256_string,776 Vec<(uint256, string)>,777 0xdeadbeef,778 vec![779 (1.into(), "Test URI 0".to_string()),780 (11.into(), "Test URI 1".to_string()),781 (12.into(), "Test URI 2".to_string()),782 ],783 &hex!(784 "785 deadbeef786 0000000000000000000000000000000000000000000000000000000000000020 // offset of (uint256, string)[]787 0000000000000000000000000000000000000000000000000000000000000003 // length of (uint256, string)[]788789 0000000000000000000000000000000000000000000000000000000000000060 // offset of first elem790 00000000000000000000000000000000000000000000000000000000000000e0 // offset of second elem791 0000000000000000000000000000000000000000000000000000000000000160 // offset of third elem792793 0000000000000000000000000000000000000000000000000000000000000001 // first token id? #60794 0000000000000000000000000000000000000000000000000000000000000040 // offset of string795 000000000000000000000000000000000000000000000000000000000000000a // size of string796 5465737420555249203000000000000000000000000000000000000000000000 // string797798 000000000000000000000000000000000000000000000000000000000000000b // second token id? Why ==11? #e0799 0000000000000000000000000000000000000000000000000000000000000040 // offset of string800 000000000000000000000000000000000000000000000000000000000000000a // size of string801 5465737420555249203100000000000000000000000000000000000000000000 // string802803 000000000000000000000000000000000000000000000000000000000000000c // third token id? Why ==12? #160804 0000000000000000000000000000000000000000000000000000000000000040 // offset of string805 000000000000000000000000000000000000000000000000000000000000000a // size of string806 5465737420555249203200000000000000000000000000000000000000000000 // string807 "808 )809 );810811 test_impl!(812 vec_tuple_string_bytes,813 Vec<(string, bytes)>,814 0xdeadbeef,815 vec![816 (817 "Test URI 0".to_string(),818 bytes(vec![819 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11,820 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11,821 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11,822 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11823 ])824 ),825 (826 "Test URI 1".to_string(),827 bytes(vec![828 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22,829 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22,830 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22,831 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22832 ])833 ),834 ("Test URI 2".to_string(), bytes(vec![0x33, 0x33])),835 ],836 &hex!(837 "838 deadbeef839 0000000000000000000000000000000000000000000000000000000000000020840 0000000000000000000000000000000000000000000000000000000000000003841 842 0000000000000000000000000000000000000000000000000000000000000060843 0000000000000000000000000000000000000000000000000000000000000140844 0000000000000000000000000000000000000000000000000000000000000220845846 0000000000000000000000000000000000000000000000000000000000000040847 0000000000000000000000000000000000000000000000000000000000000080848 000000000000000000000000000000000000000000000000000000000000000a849 5465737420555249203000000000000000000000000000000000000000000000850 0000000000000000000000000000000000000000000000000000000000000030851 1111111111111111111111111111111111111111111111111111111111111111852 1111111111111111111111111111111100000000000000000000000000000000853854 0000000000000000000000000000000000000000000000000000000000000040855 0000000000000000000000000000000000000000000000000000000000000080856 000000000000000000000000000000000000000000000000000000000000000a857 5465737420555249203100000000000000000000000000000000000000000000858 000000000000000000000000000000000000000000000000000000000000002f859 2222222222222222222222222222222222222222222222222222222222222222860 2222222222222222222222222222220000000000000000000000000000000000861862 0000000000000000000000000000000000000000000000000000000000000040863 0000000000000000000000000000000000000000000000000000000000000080864 000000000000000000000000000000000000000000000000000000000000000a865 5465737420555249203200000000000000000000000000000000000000000000866 0000000000000000000000000000000000000000000000000000000000000002867 3333000000000000000000000000000000000000000000000000000000000000868 "869 )870 );871872 #[test]873 fn dynamic_after_static() {874 let mut encoder = AbiWriter::new();875 encoder.bool(&true);876 encoder.string("test");877 let encoded = encoder.finish();878879 let mut encoder = AbiWriter::new();880 encoder.bool(&true);881 // Offset to subresult882 encoder.uint32(&(32 * 2));883 // Len of "test"884 encoder.uint32(&4);885 encoder.write_padright(&[b't', b'e', b's', b't']);886 let alternative_encoded = encoder.finish();887888 assert_eq!(encoded, alternative_encoded);889890 let mut decoder = AbiReader::new(&encoded);891 assert!(decoder.bool().unwrap());892 assert_eq!(decoder.string().unwrap(), "test");893 }894895 #[test]896 fn mint_sample() {897 let (call, mut decoder) = AbiReader::new_call(&hex!(898 "899 50bb4e7f900 000000000000000000000000ad2c0954693c2b5404b7e50967d3481bea432374901 0000000000000000000000000000000000000000000000000000000000000001902 0000000000000000000000000000000000000000000000000000000000000060903 0000000000000000000000000000000000000000000000000000000000000008904 5465737420555249000000000000000000000000000000000000000000000000905 "906 ))907 .unwrap();908 assert_eq!(call, u32::to_be_bytes(0x50bb4e7f));909 assert_eq!(910 format!("{:?}", decoder.address().unwrap()),911 "0xad2c0954693c2b5404b7e50967d3481bea432374"912 );913 assert_eq!(decoder.uint32().unwrap(), 1);914 assert_eq!(decoder.string().unwrap(), "Test URI");915 }916917 #[test]918 fn parse_vec_with_dynamic_type() {919 let decoded_data = (920 0x36543006,921 vec![922 (1.into(), "Test URI 0".to_string()),923 (11.into(), "Test URI 1".to_string()),924 (12.into(), "Test URI 2".to_string()),925 ],926 );927928 let encoded_data = &hex!(929 "930 36543006931 00000000000000000000000053744e6da587ba10b32a2554d2efdcd985bc27a3 // address932 0000000000000000000000000000000000000000000000000000000000000040 // offset of (uint256, string)[]933 0000000000000000000000000000000000000000000000000000000000000003 // length of (uint256, string)[]934935 0000000000000000000000000000000000000000000000000000000000000060 // offset of first elem936 00000000000000000000000000000000000000000000000000000000000000e0 // offset of second elem937 0000000000000000000000000000000000000000000000000000000000000160 // offset of third elem938939 0000000000000000000000000000000000000000000000000000000000000001 // first token id? #60940 0000000000000000000000000000000000000000000000000000000000000040 // offset of string941 000000000000000000000000000000000000000000000000000000000000000a // size of string942 5465737420555249203000000000000000000000000000000000000000000000 // string943944 000000000000000000000000000000000000000000000000000000000000000b // second token id? Why ==11? #e0945 0000000000000000000000000000000000000000000000000000000000000040 // offset of string946 000000000000000000000000000000000000000000000000000000000000000a // size of string947 5465737420555249203100000000000000000000000000000000000000000000 // string948949 000000000000000000000000000000000000000000000000000000000000000c // third token id? Why ==12? #160950 0000000000000000000000000000000000000000000000000000000000000040 // offset of string951 000000000000000000000000000000000000000000000000000000000000000a // size of string952 5465737420555249203200000000000000000000000000000000000000000000 // string953 "954 );955956 let (call, mut decoder) = AbiReader::new_call(encoded_data).unwrap();957 assert_eq!(call, u32::to_be_bytes(decoded_data.0));958 let address = decoder.address().unwrap();959 let data = <Vec<(uint256, string)>>::abi_read(&mut decoder).unwrap();960 assert_eq!(data, decoded_data.1);961962 let mut writer = AbiWriter::new_call(decoded_data.0);963 address.abi_write(&mut writer);964 decoded_data.1.abi_write(&mut writer);965 let ed = writer.finish();966 similar_asserts::assert_eq!(encoded_data, ed.as_slice());967 }968}crates/evm-coder/src/abi/impls.rsdiffbeforeafterboth--- /dev/null
+++ b/crates/evm-coder/src/abi/impls.rs
@@ -0,0 +1,303 @@
+use crate::{
+ execution::{Result, ResultWithPostInfo, WithPostDispatchInfo},
+ types::*,
+ make_signature,
+ custom_signature::SignatureUnit,
+};
+use super::{traits::*, ABI_ALIGNMENT, AbiReader, AbiWriter};
+use primitive_types::{U256, H160};
+
+#[cfg(not(feature = "std"))]
+use alloc::vec::Vec;
+
+macro_rules! impl_abi_readable {
+ ($ty:ty, $method:ident, $dynamic:literal) => {
+ impl sealed::CanBePlacedInVec for $ty {}
+
+ impl AbiType for $ty {
+ const SIGNATURE: SignatureUnit = make_signature!(new fixed(stringify!($ty)));
+
+ fn is_dynamic() -> bool {
+ $dynamic
+ }
+
+ fn size() -> usize {
+ ABI_ALIGNMENT
+ }
+ }
+
+ impl AbiRead for $ty {
+ fn abi_read(reader: &mut AbiReader) -> Result<$ty> {
+ reader.$method()
+ }
+ }
+ };
+}
+
+impl_abi_readable!(uint32, uint32, false);
+impl_abi_readable!(uint64, uint64, false);
+impl_abi_readable!(uint128, uint128, false);
+impl_abi_readable!(uint256, uint256, false);
+impl_abi_readable!(bytes4, bytes4, false);
+impl_abi_readable!(address, address, false);
+impl_abi_readable!(string, string, true);
+
+impl sealed::CanBePlacedInVec for bool {}
+
+impl AbiType for bool {
+ const SIGNATURE: SignatureUnit = make_signature!(new fixed("bool"));
+
+ fn is_dynamic() -> bool {
+ false
+ }
+ fn size() -> usize {
+ ABI_ALIGNMENT
+ }
+}
+impl AbiRead for bool {
+ fn abi_read(reader: &mut AbiReader) -> Result<bool> {
+ reader.bool()
+ }
+}
+
+impl AbiType for uint8 {
+ const SIGNATURE: SignatureUnit = make_signature!(new fixed("uint8"));
+
+ fn is_dynamic() -> bool {
+ false
+ }
+ fn size() -> usize {
+ ABI_ALIGNMENT
+ }
+}
+impl AbiRead for uint8 {
+ fn abi_read(reader: &mut AbiReader) -> Result<uint8> {
+ reader.uint8()
+ }
+}
+
+impl AbiType for bytes {
+ const SIGNATURE: SignatureUnit = make_signature!(new fixed("bytes"));
+
+ fn is_dynamic() -> bool {
+ true
+ }
+ fn size() -> usize {
+ ABI_ALIGNMENT
+ }
+}
+impl AbiRead for bytes {
+ fn abi_read(reader: &mut AbiReader) -> Result<bytes> {
+ Ok(bytes(reader.bytes()?))
+ }
+}
+
+impl<R: AbiRead + sealed::CanBePlacedInVec> AbiRead for Vec<R> {
+ fn abi_read(reader: &mut AbiReader) -> Result<Vec<R>> {
+ let mut sub = reader.subresult(None)?;
+ let size = sub.uint32()? as usize;
+ sub.subresult_offset = sub.offset;
+ let mut out = Vec::with_capacity(size);
+ for _ in 0..size {
+ out.push(<R>::abi_read(&mut sub)?);
+ }
+ Ok(out)
+ }
+}
+
+impl<R: AbiType> AbiType for Vec<R> {
+ const SIGNATURE: SignatureUnit = make_signature!(new nameof(R::SIGNATURE) fixed("[]"));
+
+ fn is_dynamic() -> bool {
+ true
+ }
+
+ fn size() -> usize {
+ ABI_ALIGNMENT
+ }
+}
+
+impl sealed::CanBePlacedInVec for EthCrossAccount {}
+
+impl AbiType for EthCrossAccount {
+ const SIGNATURE: SignatureUnit = make_signature!(new fixed("(address,uint256)"));
+
+ fn is_dynamic() -> bool {
+ address::is_dynamic() || uint256::is_dynamic()
+ }
+
+ fn size() -> usize {
+ <address as AbiType>::size() + <uint256 as AbiType>::size()
+ }
+}
+
+impl AbiRead for EthCrossAccount {
+ fn abi_read(reader: &mut AbiReader) -> Result<EthCrossAccount> {
+ let size = if !EthCrossAccount::is_dynamic() {
+ Some(<EthCrossAccount as AbiType>::size())
+ } else {
+ None
+ };
+ let mut subresult = reader.subresult(size)?;
+ let eth = <address>::abi_read(&mut subresult)?;
+ let sub = <uint256>::abi_read(&mut subresult)?;
+
+ Ok(EthCrossAccount { eth, sub })
+ }
+}
+
+impl AbiWrite for EthCrossAccount {
+ fn abi_write(&self, writer: &mut AbiWriter) {
+ self.eth.abi_write(writer);
+ self.sub.abi_write(writer);
+ }
+}
+
+macro_rules! impl_abi_writeable {
+ ($ty:ty, $method:ident) => {
+ impl AbiWrite for $ty {
+ fn abi_write(&self, writer: &mut AbiWriter) {
+ writer.$method(&self)
+ }
+ }
+ };
+}
+
+impl_abi_writeable!(u8, uint8);
+impl_abi_writeable!(u32, uint32);
+impl_abi_writeable!(u128, uint128);
+impl_abi_writeable!(U256, uint256);
+impl_abi_writeable!(H160, address);
+impl_abi_writeable!(bool, bool);
+impl_abi_writeable!(&str, string);
+
+impl AbiWrite for string {
+ fn abi_write(&self, writer: &mut AbiWriter) {
+ writer.string(self)
+ }
+}
+
+impl AbiWrite for bytes {
+ fn abi_write(&self, writer: &mut AbiWriter) {
+ writer.bytes(self.0.as_slice())
+ }
+}
+
+impl<T: AbiWrite + AbiType> AbiWrite for Vec<T> {
+ fn abi_write(&self, writer: &mut AbiWriter) {
+ let is_dynamic = T::is_dynamic();
+ let mut sub = if is_dynamic {
+ AbiWriter::new_dynamic(is_dynamic)
+ } else {
+ AbiWriter::new()
+ };
+
+ // Write items count
+ (self.len() as u32).abi_write(&mut sub);
+
+ for item in self {
+ item.abi_write(&mut sub);
+ }
+ writer.write_subresult(sub);
+ }
+}
+
+impl AbiWrite for () {
+ fn abi_write(&self, _writer: &mut AbiWriter) {}
+}
+
+/// This particular AbiWrite implementation should be split to another trait,
+/// which only implements `to_result`, but due to lack of specialization feature
+/// in stable Rust, we can't have blanket impl of this trait `for T where T: AbiWrite`,
+/// so here we abusing default trait methods for it
+impl<T: AbiWrite> AbiWrite for ResultWithPostInfo<T> {
+ fn abi_write(&self, _writer: &mut AbiWriter) {
+ debug_assert!(false, "shouldn't be called, see comment")
+ }
+ fn to_result(&self) -> ResultWithPostInfo<AbiWriter> {
+ match self {
+ Ok(v) => Ok(WithPostDispatchInfo {
+ post_info: v.post_info.clone(),
+ data: {
+ let mut out = AbiWriter::new();
+ v.data.abi_write(&mut out);
+ out
+ },
+ }),
+ Err(e) => Err(e.clone()),
+ }
+ }
+}
+
+macro_rules! impl_tuples {
+ ($($ident:ident)+) => {
+ impl<$($ident: AbiType,)+> AbiType for ($($ident,)+)
+ where
+ $(
+ $ident: AbiType,
+ )+
+ {
+ const SIGNATURE: SignatureUnit = make_signature!(
+ new fixed("(")
+ $(nameof(<$ident>::SIGNATURE) fixed(","))+
+ shift_left(1)
+ fixed(")")
+ );
+
+ fn is_dynamic() -> bool {
+ false
+ $(
+ || <$ident>::is_dynamic()
+ )*
+ }
+
+ fn size() -> usize {
+ 0 $(+ <$ident>::size())+
+ }
+ }
+
+ impl<$($ident),+> sealed::CanBePlacedInVec for ($($ident,)+) {}
+
+ impl<$($ident),+> AbiRead for ($($ident,)+)
+ where
+ $($ident: AbiRead,)+
+ ($($ident,)+): AbiType,
+ {
+ fn abi_read(reader: &mut AbiReader) -> Result<($($ident,)+)> {
+ let size = if !<($($ident,)+)>::is_dynamic() { Some(<($($ident,)+)>::size()) } else { None };
+ let mut subresult = reader.subresult(size)?;
+ Ok((
+ $(<$ident>::abi_read(&mut subresult)?,)+
+ ))
+ }
+ }
+
+ #[allow(non_snake_case)]
+ impl<$($ident),+> AbiWrite for ($($ident,)+)
+ where
+ $($ident: AbiWrite,)+
+ {
+ fn abi_write(&self, writer: &mut AbiWriter) {
+ let ($($ident,)+) = self;
+ if writer.is_dynamic {
+ let mut sub = AbiWriter::new();
+ $($ident.abi_write(&mut sub);)+
+ writer.write_subresult(sub);
+ } else {
+ $($ident.abi_write(writer);)+
+ }
+ }
+ }
+ };
+}
+
+impl_tuples! {A}
+impl_tuples! {A B}
+impl_tuples! {A B C}
+impl_tuples! {A B C D}
+impl_tuples! {A B C D E}
+impl_tuples! {A B C D E F}
+impl_tuples! {A B C D E F G}
+impl_tuples! {A B C D E F G H}
+impl_tuples! {A B C D E F G H I}
+impl_tuples! {A B C D E F G H I J}
crates/evm-coder/src/abi/mod.rsdiffbeforeafterboth--- /dev/null
+++ b/crates/evm-coder/src/abi/mod.rs
@@ -0,0 +1,339 @@
+// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
+// This file is part of Unique Network.
+
+// Unique Network is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// Unique Network is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
+
+//! Implementation of EVM RLP reader/writer
+
+#![allow(dead_code)]
+
+mod traits;
+pub use traits::*;
+mod impls;
+
+#[cfg(test)]
+mod test;
+
+#[cfg(not(feature = "std"))]
+use alloc::vec::Vec;
+use evm_core::ExitError;
+use primitive_types::{H160, U256};
+
+use crate::{
+ execution::{Result, Error},
+ types::*,
+};
+
+const ABI_ALIGNMENT: usize = 32;
+
+/// View into RLP data, which provides method to read typed items from it
+#[derive(Clone)]
+pub struct AbiReader<'i> {
+ buf: &'i [u8],
+ subresult_offset: usize,
+ offset: usize,
+}
+impl<'i> AbiReader<'i> {
+ /// Start reading RLP buffer, assuming there is no padding bytes
+ pub fn new(buf: &'i [u8]) -> Self {
+ Self {
+ buf,
+ subresult_offset: 0,
+ offset: 0,
+ }
+ }
+ /// Start reading RLP buffer, parsing first 4 bytes as selector
+ pub fn new_call(buf: &'i [u8]) -> Result<(bytes4, Self)> {
+ if buf.len() < 4 {
+ return Err(Error::Error(ExitError::OutOfOffset));
+ }
+ let mut method_id = [0; 4];
+ method_id.copy_from_slice(&buf[0..4]);
+
+ Ok((
+ method_id,
+ Self {
+ buf,
+ subresult_offset: 4,
+ offset: 4,
+ },
+ ))
+ }
+
+ fn read_pad<const S: usize>(
+ buf: &[u8],
+ offset: usize,
+ pad_start: usize,
+ pad_size: usize,
+ block_start: usize,
+ block_size: usize,
+ ) -> Result<[u8; S]> {
+ if buf.len() - offset < ABI_ALIGNMENT {
+ return Err(Error::Error(ExitError::OutOfOffset));
+ }
+ let mut block = [0; S];
+ let is_pad_zeroed = buf[pad_start..pad_size].iter().all(|&v| v == 0);
+ if !is_pad_zeroed {
+ return Err(Error::Error(ExitError::InvalidRange));
+ }
+ block.copy_from_slice(&buf[block_start..block_size]);
+ Ok(block)
+ }
+
+ fn read_padleft<const S: usize>(&mut self) -> Result<[u8; S]> {
+ let offset = self.offset;
+ self.offset += ABI_ALIGNMENT;
+ Self::read_pad(
+ self.buf,
+ offset,
+ offset,
+ offset + ABI_ALIGNMENT - S,
+ offset + ABI_ALIGNMENT - S,
+ offset + ABI_ALIGNMENT,
+ )
+ }
+
+ fn read_padright<const S: usize>(&mut self) -> Result<[u8; S]> {
+ let offset = self.offset;
+ self.offset += ABI_ALIGNMENT;
+ Self::read_pad(
+ self.buf,
+ offset,
+ offset + S,
+ offset + ABI_ALIGNMENT,
+ offset,
+ offset + S,
+ )
+ }
+
+ /// Read [`H160`] at current position, then advance
+ pub fn address(&mut self) -> Result<H160> {
+ Ok(H160(self.read_padleft()?))
+ }
+
+ /// Read [`bool`] at current position, then advance
+ pub fn bool(&mut self) -> Result<bool> {
+ let data: [u8; 1] = self.read_padleft()?;
+ match data[0] {
+ 0 => Ok(false),
+ 1 => Ok(true),
+ _ => Err(Error::Error(ExitError::InvalidRange)),
+ }
+ }
+
+ /// Read [`[u8; 4]`] at current position, then advance
+ pub fn bytes4(&mut self) -> Result<[u8; 4]> {
+ self.read_padright()
+ }
+
+ /// Read [`Vec<u8>`] at current position, then advance
+ pub fn bytes(&mut self) -> Result<Vec<u8>> {
+ let mut subresult = self.subresult(None)?;
+ let length = subresult.uint32()? as usize;
+ if subresult.buf.len() < subresult.offset + length {
+ return Err(Error::Error(ExitError::OutOfOffset));
+ }
+ Ok(subresult.buf[subresult.offset..subresult.offset + length].into())
+ }
+
+ /// Read [`string`] at current position, then advance
+ pub fn string(&mut self) -> Result<string> {
+ string::from_utf8(self.bytes()?).map_err(|_| Error::Error(ExitError::InvalidRange))
+ }
+
+ /// Read [`u8`] at current position, then advance
+ pub fn uint8(&mut self) -> Result<u8> {
+ Ok(self.read_padleft::<1>()?[0])
+ }
+
+ /// Read [`u32`] at current position, then advance
+ pub fn uint32(&mut self) -> Result<u32> {
+ Ok(u32::from_be_bytes(self.read_padleft()?))
+ }
+
+ /// Read [`u128`] at current position, then advance
+ pub fn uint128(&mut self) -> Result<u128> {
+ Ok(u128::from_be_bytes(self.read_padleft()?))
+ }
+
+ /// Read [`U256`] at current position, then advance
+ pub fn uint256(&mut self) -> Result<U256> {
+ let buf: [u8; 32] = self.read_padleft()?;
+ Ok(U256::from_big_endian(&buf))
+ }
+
+ /// Read [`u64`] at current position, then advance
+ pub fn uint64(&mut self) -> Result<u64> {
+ Ok(u64::from_be_bytes(self.read_padleft()?))
+ }
+
+ /// Read [`usize`] at current position, then advance
+ #[deprecated = "dangerous, as usize may have different width in wasm and native execution"]
+ pub fn read_usize(&mut self) -> Result<usize> {
+ Ok(usize::from_be_bytes(self.read_padleft()?))
+ }
+
+ /// Slice recursive buffer, advance one word for buffer offset
+ /// If `size` is [`None`] then [`Self::offset`] and [`Self::subresult_offset`] evals from [`Self::buf`].
+ fn subresult(&mut self, size: Option<usize>) -> Result<AbiReader<'i>> {
+ let subresult_offset = self.subresult_offset;
+ let offset = if let Some(size) = size {
+ self.offset += size;
+ self.subresult_offset += size;
+ 0
+ } else {
+ self.uint32()? as usize
+ };
+
+ if offset + self.subresult_offset > self.buf.len() {
+ return Err(Error::Error(ExitError::InvalidRange));
+ }
+
+ let new_offset = offset + subresult_offset;
+ Ok(AbiReader {
+ buf: self.buf,
+ subresult_offset: new_offset,
+ offset: new_offset,
+ })
+ }
+
+ /// Is this parser reached end of buffer?
+ pub fn is_finished(&self) -> bool {
+ self.buf.len() == self.offset
+ }
+}
+
+/// Writer for RLP encoded data
+#[derive(Default)]
+pub struct AbiWriter {
+ static_part: Vec<u8>,
+ dynamic_part: Vec<(usize, AbiWriter)>,
+ had_call: bool,
+ is_dynamic: bool,
+}
+impl AbiWriter {
+ /// Initialize internal buffers for output data, assuming no padding required
+ pub fn new() -> Self {
+ Self::default()
+ }
+
+ /// Initialize internal buffers with data size
+ pub fn new_dynamic(is_dynamic: bool) -> Self {
+ Self {
+ is_dynamic,
+ ..Default::default()
+ }
+ }
+ /// Initialize internal buffers, inserting method selector at beginning
+ pub fn new_call(method_id: u32) -> Self {
+ let mut val = Self::new();
+ val.static_part.extend(&method_id.to_be_bytes());
+ val.had_call = true;
+ val
+ }
+
+ fn write_padleft(&mut self, block: &[u8]) {
+ assert!(block.len() <= ABI_ALIGNMENT);
+ self.static_part
+ .extend(&[0; ABI_ALIGNMENT][0..ABI_ALIGNMENT - block.len()]);
+ self.static_part.extend(block);
+ }
+
+ fn write_padright(&mut self, block: &[u8]) {
+ assert!(block.len() <= ABI_ALIGNMENT);
+ self.static_part.extend(block);
+ self.static_part
+ .extend(&[0; ABI_ALIGNMENT][0..ABI_ALIGNMENT - block.len()]);
+ }
+
+ /// Write [`H160`] to end of buffer
+ pub fn address(&mut self, address: &H160) {
+ self.write_padleft(&address.0)
+ }
+
+ /// Write [`bool`] to end of buffer
+ pub fn bool(&mut self, value: &bool) {
+ self.write_padleft(&[if *value { 1 } else { 0 }])
+ }
+
+ /// Write [`u8`] to end of buffer
+ pub fn uint8(&mut self, value: &u8) {
+ self.write_padleft(&[*value])
+ }
+
+ /// Write [`u32`] to end of buffer
+ pub fn uint32(&mut self, value: &u32) {
+ self.write_padleft(&u32::to_be_bytes(*value))
+ }
+
+ /// Write [`u128`] to end of buffer
+ pub fn uint128(&mut self, value: &u128) {
+ self.write_padleft(&u128::to_be_bytes(*value))
+ }
+
+ /// Write [`U256`] to end of buffer
+ pub fn uint256(&mut self, value: &U256) {
+ let mut out = [0; 32];
+ value.to_big_endian(&mut out);
+ self.write_padleft(&out)
+ }
+
+ /// Write [`usize`] to end of buffer
+ #[deprecated = "dangerous, as usize may have different width in wasm and native execution"]
+ pub fn write_usize(&mut self, value: &usize) {
+ self.write_padleft(&usize::to_be_bytes(*value))
+ }
+
+ /// Append recursive data, writing pending offset at end of buffer
+ pub fn write_subresult(&mut self, result: Self) {
+ self.dynamic_part.push((self.static_part.len(), result));
+ // Empty block, to be filled later
+ self.write_padleft(&[]);
+ }
+
+ fn memory(&mut self, value: &[u8]) {
+ let mut sub = Self::new();
+ sub.uint32(&(value.len() as u32));
+ for chunk in value.chunks(ABI_ALIGNMENT) {
+ sub.write_padright(chunk);
+ }
+ self.write_subresult(sub);
+ }
+
+ /// Append recursive [`str`] at end of buffer
+ pub fn string(&mut self, value: &str) {
+ self.memory(value.as_bytes())
+ }
+
+ /// Append recursive [`[u8]`] at end of buffer
+ pub fn bytes(&mut self, value: &[u8]) {
+ self.memory(value)
+ }
+
+ /// Finish writer, concatenating all internal buffers
+ pub fn finish(mut self) -> Vec<u8> {
+ for (static_offset, part) in self.dynamic_part {
+ let part_offset = self.static_part.len()
+ - if self.had_call { 4 } else { 0 }
+ - if self.is_dynamic { ABI_ALIGNMENT } else { 0 };
+
+ let encoded_dynamic_offset = usize::to_be_bytes(part_offset);
+ let start = static_offset + ABI_ALIGNMENT - encoded_dynamic_offset.len();
+ let stop = static_offset + ABI_ALIGNMENT;
+ self.static_part[start..stop].copy_from_slice(&encoded_dynamic_offset);
+ self.static_part.extend(part.finish())
+ }
+ self.static_part
+ }
+}
crates/evm-coder/src/abi/test.rsdiffbeforeafterboth--- /dev/null
+++ b/crates/evm-coder/src/abi/test.rs
@@ -0,0 +1,297 @@
+use crate::{
+ abi::{AbiRead, AbiWrite},
+ types::*,
+};
+
+use super::{AbiReader, AbiWriter};
+use hex_literal::hex;
+use primitive_types::{H160, U256};
+use concat_idents::concat_idents;
+
+macro_rules! test_impl {
+ ($name:ident, $type:ty, $function_identifier:expr, $decoded_data:expr, $encoded_data:expr) => {
+ concat_idents!(test_name = encode_decode_, $name {
+ #[test]
+ fn test_name() {
+ let function_identifier: u32 = $function_identifier;
+ let decoded_data = $decoded_data;
+ let encoded_data = $encoded_data;
+
+ let (call, mut decoder) = AbiReader::new_call(encoded_data).unwrap();
+ assert_eq!(call, u32::to_be_bytes(function_identifier));
+ let data = <$type>::abi_read(&mut decoder).unwrap();
+ assert_eq!(data, decoded_data);
+
+ let mut writer = AbiWriter::new_call(function_identifier);
+ decoded_data.abi_write(&mut writer);
+ let ed = writer.finish();
+ similar_asserts::assert_eq!(encoded_data, ed.as_slice());
+ }
+ });
+ };
+}
+
+macro_rules! test_impl_uint {
+ ($type:ident) => {
+ test_impl!(
+ $type,
+ $type,
+ 0xdeadbeef,
+ 255 as $type,
+ &hex!(
+ "
+ deadbeef
+ 00000000000000000000000000000000000000000000000000000000000000ff
+ "
+ )
+ );
+ };
+}
+
+test_impl_uint!(uint8);
+test_impl_uint!(uint32);
+test_impl_uint!(uint128);
+
+test_impl!(
+ uint256,
+ uint256,
+ 0xdeadbeef,
+ U256([255, 0, 0, 0]),
+ &hex!(
+ "
+ deadbeef
+ 00000000000000000000000000000000000000000000000000000000000000ff
+ "
+ )
+);
+
+test_impl!(
+ vec_tuple_address_uint256,
+ Vec<(address, uint256)>,
+ 0x1ACF2D55,
+ vec![
+ (
+ H160(hex!("2D2FF76104B7BACB2E8F6731D5BFC184EBECDDBC")),
+ U256([10, 0, 0, 0]),
+ ),
+ (
+ H160(hex!("AB8E3D9134955566483B11E6825C9223B6737B10")),
+ U256([20, 0, 0, 0]),
+ ),
+ (
+ H160(hex!("8C582BDF2953046705FC56F189385255EFC1BE18")),
+ U256([30, 0, 0, 0]),
+ ),
+ ],
+ &hex!(
+ "
+ 1ACF2D55
+ 0000000000000000000000000000000000000000000000000000000000000020 // offset of (address, uint256)[]
+ 0000000000000000000000000000000000000000000000000000000000000003 // length of (address, uint256)[]
+
+ 0000000000000000000000002D2FF76104B7BACB2E8F6731D5BFC184EBECDDBC // address
+ 000000000000000000000000000000000000000000000000000000000000000A // uint256
+
+ 000000000000000000000000AB8E3D9134955566483B11E6825C9223B6737B10 // address
+ 0000000000000000000000000000000000000000000000000000000000000014 // uint256
+
+ 0000000000000000000000008C582BDF2953046705FC56F189385255EFC1BE18 // address
+ 000000000000000000000000000000000000000000000000000000000000001E // uint256
+ "
+ )
+);
+
+test_impl!(
+ vec_tuple_uint256_string,
+ Vec<(uint256, string)>,
+ 0xdeadbeef,
+ vec![
+ (1.into(), "Test URI 0".to_string()),
+ (11.into(), "Test URI 1".to_string()),
+ (12.into(), "Test URI 2".to_string()),
+ ],
+ &hex!(
+ "
+ deadbeef
+ 0000000000000000000000000000000000000000000000000000000000000020 // offset of (uint256, string)[]
+ 0000000000000000000000000000000000000000000000000000000000000003 // length of (uint256, string)[]
+
+ 0000000000000000000000000000000000000000000000000000000000000060 // offset of first elem
+ 00000000000000000000000000000000000000000000000000000000000000e0 // offset of second elem
+ 0000000000000000000000000000000000000000000000000000000000000160 // offset of third elem
+
+ 0000000000000000000000000000000000000000000000000000000000000001 // first token id? #60
+ 0000000000000000000000000000000000000000000000000000000000000040 // offset of string
+ 000000000000000000000000000000000000000000000000000000000000000a // size of string
+ 5465737420555249203000000000000000000000000000000000000000000000 // string
+
+ 000000000000000000000000000000000000000000000000000000000000000b // second token id? Why ==11? #e0
+ 0000000000000000000000000000000000000000000000000000000000000040 // offset of string
+ 000000000000000000000000000000000000000000000000000000000000000a // size of string
+ 5465737420555249203100000000000000000000000000000000000000000000 // string
+
+ 000000000000000000000000000000000000000000000000000000000000000c // third token id? Why ==12? #160
+ 0000000000000000000000000000000000000000000000000000000000000040 // offset of string
+ 000000000000000000000000000000000000000000000000000000000000000a // size of string
+ 5465737420555249203200000000000000000000000000000000000000000000 // string
+ "
+ )
+);
+
+#[test]
+fn dynamic_after_static() {
+ let mut encoder = AbiWriter::new();
+ encoder.bool(&true);
+ encoder.string("test");
+ let encoded = encoder.finish();
+
+ let mut encoder = AbiWriter::new();
+ encoder.bool(&true);
+ // Offset to subresult
+ encoder.uint32(&(32 * 2));
+ // Len of "test"
+ encoder.uint32(&4);
+ encoder.write_padright(&[b't', b'e', b's', b't']);
+ let alternative_encoded = encoder.finish();
+
+ assert_eq!(encoded, alternative_encoded);
+
+ let mut decoder = AbiReader::new(&encoded);
+ assert!(decoder.bool().unwrap());
+ assert_eq!(decoder.string().unwrap(), "test");
+}
+
+#[test]
+fn mint_sample() {
+ let (call, mut decoder) = AbiReader::new_call(&hex!(
+ "
+ 50bb4e7f
+ 000000000000000000000000ad2c0954693c2b5404b7e50967d3481bea432374
+ 0000000000000000000000000000000000000000000000000000000000000001
+ 0000000000000000000000000000000000000000000000000000000000000060
+ 0000000000000000000000000000000000000000000000000000000000000008
+ 5465737420555249000000000000000000000000000000000000000000000000
+ "
+ ))
+ .unwrap();
+ assert_eq!(call, u32::to_be_bytes(0x50bb4e7f));
+ assert_eq!(
+ format!("{:?}", decoder.address().unwrap()),
+ "0xad2c0954693c2b5404b7e50967d3481bea432374"
+ );
+ assert_eq!(decoder.uint32().unwrap(), 1);
+ assert_eq!(decoder.string().unwrap(), "Test URI");
+}
+
+#[test]
+fn parse_vec_with_dynamic_type() {
+ let decoded_data = (
+ 0x36543006,
+ vec![
+ (1.into(), "Test URI 0".to_string()),
+ (11.into(), "Test URI 1".to_string()),
+ (12.into(), "Test URI 2".to_string()),
+ ],
+ );
+
+ let encoded_data = &hex!(
+ "
+ 36543006
+ 00000000000000000000000053744e6da587ba10b32a2554d2efdcd985bc27a3 // address
+ 0000000000000000000000000000000000000000000000000000000000000040 // offset of (uint256, string)[]
+ 0000000000000000000000000000000000000000000000000000000000000003 // length of (uint256, string)[]
+
+ 0000000000000000000000000000000000000000000000000000000000000060 // offset of first elem
+ 00000000000000000000000000000000000000000000000000000000000000e0 // offset of second elem
+ 0000000000000000000000000000000000000000000000000000000000000160 // offset of third elem
+
+ 0000000000000000000000000000000000000000000000000000000000000001 // first token id? #60
+ 0000000000000000000000000000000000000000000000000000000000000040 // offset of string
+ 000000000000000000000000000000000000000000000000000000000000000a // size of string
+ 5465737420555249203000000000000000000000000000000000000000000000 // string
+
+ 000000000000000000000000000000000000000000000000000000000000000b // second token id? Why ==11? #e0
+ 0000000000000000000000000000000000000000000000000000000000000040 // offset of string
+ 000000000000000000000000000000000000000000000000000000000000000a // size of string
+ 5465737420555249203100000000000000000000000000000000000000000000 // string
+
+ 000000000000000000000000000000000000000000000000000000000000000c // third token id? Why ==12? #160
+ 0000000000000000000000000000000000000000000000000000000000000040 // offset of string
+ 000000000000000000000000000000000000000000000000000000000000000a // size of string
+ 5465737420555249203200000000000000000000000000000000000000000000 // string
+ "
+ );
+
+ let (call, mut decoder) = AbiReader::new_call(encoded_data).unwrap();
+ assert_eq!(call, u32::to_be_bytes(decoded_data.0));
+ let address = decoder.address().unwrap();
+ let data = <Vec<(uint256, string)>>::abi_read(&mut decoder).unwrap();
+ assert_eq!(data, decoded_data.1);
+
+ let mut writer = AbiWriter::new_call(decoded_data.0);
+ address.abi_write(&mut writer);
+ decoded_data.1.abi_write(&mut writer);
+ let ed = writer.finish();
+ similar_asserts::assert_eq!(encoded_data, ed.as_slice());
+}
+
+test_impl!(
+ vec_tuple_string_bytes,
+ Vec<(string, bytes)>,
+ 0xdeadbeef,
+ vec![
+ (
+ "Test URI 0".to_string(),
+ bytes(vec![
+ 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11,
+ 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11,
+ 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11,
+ 0x11, 0x11, 0x11, 0x11, 0x11, 0x11
+ ])
+ ),
+ (
+ "Test URI 1".to_string(),
+ bytes(vec![
+ 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22,
+ 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22,
+ 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22,
+ 0x22, 0x22, 0x22, 0x22, 0x22
+ ])
+ ),
+ ("Test URI 2".to_string(), bytes(vec![0x33, 0x33])),
+ ],
+ &hex!(
+ "
+ deadbeef
+ 0000000000000000000000000000000000000000000000000000000000000020
+ 0000000000000000000000000000000000000000000000000000000000000003
+
+ 0000000000000000000000000000000000000000000000000000000000000060
+ 0000000000000000000000000000000000000000000000000000000000000140
+ 0000000000000000000000000000000000000000000000000000000000000220
+
+ 0000000000000000000000000000000000000000000000000000000000000040
+ 0000000000000000000000000000000000000000000000000000000000000080
+ 000000000000000000000000000000000000000000000000000000000000000a
+ 5465737420555249203000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000030
+ 1111111111111111111111111111111111111111111111111111111111111111
+ 1111111111111111111111111111111100000000000000000000000000000000
+
+ 0000000000000000000000000000000000000000000000000000000000000040
+ 0000000000000000000000000000000000000000000000000000000000000080
+ 000000000000000000000000000000000000000000000000000000000000000a
+ 5465737420555249203100000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000002f
+ 2222222222222222222222222222222222222222222222222222222222222222
+ 2222222222222222222222222222220000000000000000000000000000000000
+
+ 0000000000000000000000000000000000000000000000000000000000000040
+ 0000000000000000000000000000000000000000000000000000000000000080
+ 000000000000000000000000000000000000000000000000000000000000000a
+ 5465737420555249203200000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000002
+ 3333000000000000000000000000000000000000000000000000000000000000
+ "
+ )
+);
crates/evm-coder/src/abi/traits.rsdiffbeforeafterboth--- /dev/null
+++ b/crates/evm-coder/src/abi/traits.rs
@@ -0,0 +1,51 @@
+use super::{AbiReader, AbiWriter};
+use crate::{
+ custom_signature::*,
+ execution::{Result, ResultWithPostInfo},
+};
+use core::str::from_utf8;
+
+/// Helper for type.
+pub trait AbiType {
+ /// Signature for Etherium ABI.
+ const SIGNATURE: SignatureUnit;
+
+ /// Signature as str.
+ fn as_str() -> &'static str {
+ from_utf8(&Self::SIGNATURE.data[..Self::SIGNATURE.len]).expect("bad utf-8")
+ }
+
+ /// Is type dynamic sized.
+ fn is_dynamic() -> bool;
+
+ /// Size for type aligned to [`ABI_ALIGNMENT`].
+ fn size() -> usize;
+}
+
+/// Sealed traits.
+pub mod sealed {
+ /// Not all types can be placed in vec, i.e `Vec<u8>` is restricted, `bytes` should be used instead
+ pub trait CanBePlacedInVec {}
+}
+
+/// [`AbiReader`] implements reading of many types.
+pub trait AbiRead {
+ /// Read item from current position, advanding decoder
+ fn abi_read(reader: &mut AbiReader) -> Result<Self>
+ where
+ Self: Sized;
+}
+
+/// For questions about inability to provide custom implementations,
+/// see [`AbiRead`]
+pub trait AbiWrite {
+ /// Write value to end of specified encoder
+ fn abi_write(&self, writer: &mut AbiWriter);
+ /// Specialization for [`crate::solidity_interface`] implementation,
+ /// see comment in `impl AbiWrite for ResultWithPostInfo`
+ fn to_result(&self) -> ResultWithPostInfo<AbiWriter> {
+ let mut writer = AbiWriter::new();
+ self.abi_write(&mut writer);
+ Ok(writer.into())
+ }
+}
crates/evm-coder/src/lib.rsdiffbeforeafterboth--- a/crates/evm-coder/src/lib.rs
+++ b/crates/evm-coder/src/lib.rs
@@ -121,53 +121,24 @@
use alloc::{vec::Vec};
use pallet_evm::account::CrossAccountId;
use primitive_types::{U256, H160, H256};
- use core::str::from_utf8;
-
- use crate::custom_signature::SignatureUnit;
-
- pub trait Signature {
- const SIGNATURE: SignatureUnit;
-
- fn as_str() -> &'static str {
- from_utf8(&Self::SIGNATURE.data[..Self::SIGNATURE.len]).expect("bad utf-8")
- }
- }
-
- impl Signature for bool {
- const SIGNATURE: SignatureUnit = make_signature!(new fixed("bool"));
- }
-
- macro_rules! define_simple_type {
- (type $ident:ident = $ty:ty) => {
- pub type $ident = $ty;
- impl Signature for $ty {
- const SIGNATURE: SignatureUnit = make_signature!(new fixed(stringify!($ident)));
- }
- };
- }
- define_simple_type!(type address = H160);
-
- define_simple_type!(type uint8 = u8);
- define_simple_type!(type uint16 = u16);
- define_simple_type!(type uint32 = u32);
- define_simple_type!(type uint64 = u64);
- define_simple_type!(type uint128 = u128);
- define_simple_type!(type uint256 = U256);
- define_simple_type!(type bytes4 = [u8; 4]);
-
- define_simple_type!(type topic = H256);
+ pub type address = H160;
+ pub type uint8 = u8;
+ pub type uint16 = u16;
+ pub type uint32 = u32;
+ pub type uint64 = u64;
+ pub type uint128 = u128;
+ pub type uint256 = U256;
+ pub type bytes4 = [u8; 4];
+ pub type topic = H256;
#[cfg(not(feature = "std"))]
- define_simple_type!(type string = ::alloc::string::String);
+ pub type string = ::alloc::string::String;
#[cfg(feature = "std")]
- define_simple_type!(type string = ::std::string::String);
+ pub type string = ::std::string::String;
#[derive(Default, Debug, PartialEq)]
pub struct bytes(pub Vec<u8>);
- impl Signature for bytes {
- const SIGNATURE: SignatureUnit = make_signature!(new fixed("bytes"));
- }
/// Solidity doesn't have `void` type, however we have special implementation
/// for empty tuple return type
@@ -257,10 +228,6 @@
Err("All fields of cross account is non zeroed".into())
}
}
- }
-
- impl Signature for EthCrossAccount {
- const SIGNATURE: SignatureUnit = make_signature!(new fixed("(address,uint256)"));
}
/// Convert `CrossAccountId` to `uint256`.
crates/evm-coder/tests/random.rsdiffbeforeafterboth--- a/crates/evm-coder/tests/random.rs
+++ b/crates/evm-coder/tests/random.rs
@@ -16,8 +16,9 @@
#![allow(dead_code)] // This test only checks that macros is not panicking
-use evm_coder::{ToLog, execution::Result, solidity_interface, types::*, solidity, weight};
-use evm_coder::{types::Signature};
+use evm_coder::{
+ abi::AbiType, ToLog, execution::Result, solidity_interface, types::*, solidity, weight,
+};
pub struct Impls;
crates/evm-coder/tests/solidity_generation.rsdiffbeforeafterboth--- a/crates/evm-coder/tests/solidity_generation.rs
+++ b/crates/evm-coder/tests/solidity_generation.rs
@@ -14,8 +14,7 @@
// You should have received a copy of the GNU General Public License
// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
-use evm_coder::{execution::Result, generate_stubgen, solidity_interface, types::*};
-use evm_coder::{types::Signature};
+use evm_coder::{abi::AbiType, execution::Result, generate_stubgen, solidity_interface, types::*};
pub struct ERC20;
pallets/common/src/erc.rsdiffbeforeafterboth--- a/pallets/common/src/erc.rs
+++ b/pallets/common/src/erc.rs
@@ -17,6 +17,7 @@
//! This module contains the implementation of pallet methods for evm.
use evm_coder::{
+ abi::AbiType,
solidity_interface, solidity, ToLog,
types::*,
execution::{Result, Error},
pallets/evm-contract-helpers/src/eth.rsdiffbeforeafterboth--- a/pallets/evm-contract-helpers/src/eth.rs
+++ b/pallets/evm-contract-helpers/src/eth.rs
@@ -19,7 +19,11 @@
extern crate alloc;
use core::marker::PhantomData;
use evm_coder::{
- abi::AbiWriter, execution::Result, generate_stubgen, solidity_interface, types::*, ToLog,
+ abi::{AbiWriter, AbiType},
+ execution::Result,
+ generate_stubgen, solidity_interface,
+ types::*,
+ ToLog,
};
use pallet_evm::{
ExitRevert, OnCreate, OnMethodCall, PrecompileResult, PrecompileFailure, PrecompileHandle,
pallets/fungible/src/erc.rsdiffbeforeafterboth--- a/pallets/fungible/src/erc.rs
+++ b/pallets/fungible/src/erc.rs
@@ -19,7 +19,9 @@
extern crate alloc;
use core::char::{REPLACEMENT_CHARACTER, decode_utf16};
use core::convert::TryInto;
-use evm_coder::{ToLog, execution::*, generate_stubgen, solidity_interface, types::*, weight};
+use evm_coder::{
+ abi::AbiType, ToLog, execution::*, generate_stubgen, solidity_interface, types::*, weight,
+};
use up_data_structs::CollectionMode;
use pallet_common::erc::{CommonEvmHandler, PrecompileResult};
use sp_std::vec::Vec;
pallets/nonfungible/src/erc.rsdiffbeforeafterboth--- a/pallets/nonfungible/src/erc.rs
+++ b/pallets/nonfungible/src/erc.rs
@@ -24,7 +24,10 @@
char::{REPLACEMENT_CHARACTER, decode_utf16},
convert::TryInto,
};
-use evm_coder::{ToLog, execution::*, generate_stubgen, solidity, solidity_interface, types::*, weight};
+use evm_coder::{
+ abi::AbiType, ToLog, execution::*, generate_stubgen, solidity, solidity_interface, types::*,
+ weight,
+};
use frame_support::BoundedVec;
use up_data_structs::{
TokenId, PropertyPermission, PropertyKeyPermission, Property, CollectionId, PropertyKey,
pallets/refungible/src/erc.rsdiffbeforeafterboth--- a/pallets/refungible/src/erc.rs
+++ b/pallets/refungible/src/erc.rs
@@ -25,7 +25,10 @@
char::{REPLACEMENT_CHARACTER, decode_utf16},
convert::TryInto,
};
-use evm_coder::{ToLog, execution::*, generate_stubgen, solidity, solidity_interface, types::*, weight};
+use evm_coder::{
+ abi::AbiType, ToLog, execution::*, generate_stubgen, solidity, solidity_interface, types::*,
+ weight,
+};
use frame_support::{BoundedBTreeMap, BoundedVec};
use pallet_common::{
CollectionHandle, CollectionPropertyPermissions,
pallets/refungible/src/erc_token.rsdiffbeforeafterboth--- a/pallets/refungible/src/erc_token.rs
+++ b/pallets/refungible/src/erc_token.rs
@@ -29,7 +29,9 @@
convert::TryInto,
ops::Deref,
};
-use evm_coder::{ToLog, execution::*, generate_stubgen, solidity_interface, types::*, weight};
+use evm_coder::{
+ abi::AbiType, ToLog, execution::*, generate_stubgen, solidity_interface, types::*, weight,
+};
use pallet_common::{
CommonWeightInfo,
erc::{CommonEvmHandler, PrecompileResult},
pallets/unique/Cargo.tomldiffbeforeafterboth--- a/pallets/unique/Cargo.toml
+++ b/pallets/unique/Cargo.toml
@@ -35,6 +35,7 @@
try-runtime = ["frame-support/try-runtime"]
limit-testing = ["up-data-structs/limit-testing"]
stubgen = ["evm-coder/stubgen", "pallet-common/stubgen"]
+
################################################################################
# Standart Dependencies
pallets/unique/src/eth/mod.rsdiffbeforeafterboth--- a/pallets/unique/src/eth/mod.rs
+++ b/pallets/unique/src/eth/mod.rs
@@ -18,14 +18,16 @@
use core::marker::PhantomData;
use ethereum as _;
-use evm_coder::{execution::*, generate_stubgen, solidity, solidity_interface, types::*, weight};
+use evm_coder::{
+ abi::AbiType, execution::*, generate_stubgen, solidity, solidity_interface, types::*, weight,
+};
use frame_support::traits::Get;
use crate::Pallet;
use pallet_common::{
CollectionById,
dispatch::CollectionDispatch,
- erc::{static_property::key, CollectionHelpersEvents},
+ erc::{CollectionHelpersEvents, static_property::key},
Pallet as PalletCommon,
};
use pallet_evm::{account::CrossAccountId, OnMethodCall, PrecompileHandle, PrecompileResult};