difftreelog
Merge pull request #340 from UniqueNetwork/bugfix/CORE-317
in: master
CORE-317 Fix ERC165 support interface
7 files changed
crates/evm-coder-macros/src/solidity_interface.rsdiffbeforeafterboth--- a/crates/evm-coder-macros/src/solidity_interface.rs
+++ b/crates/evm-coder-macros/src/solidity_interface.rs
@@ -57,7 +57,7 @@
fn expand_interface_id(&self) -> proc_macro2::TokenStream {
let pascal_call_name = &self.pascal_call_name;
quote! {
- interface_id ^= #pascal_call_name::interface_id();
+ interface_id ^= u32::from_be_bytes(#pascal_call_name::interface_id());
}
}
@@ -540,18 +540,18 @@
fn expand_const(&self) -> proc_macro2::TokenStream {
let screaming_name = &self.screaming_name;
- let selector = self.selector;
+ let selector = u32::to_be_bytes(self.selector);
let selector_str = &self.selector_str;
quote! {
#[doc = #selector_str]
- const #screaming_name: u32 = #selector;
+ const #screaming_name: ::evm_coder::types::bytes4 = [#(#selector,)*];
}
}
fn expand_interface_id(&self) -> proc_macro2::TokenStream {
let screaming_name = &self.screaming_name;
quote! {
- interface_id ^= Self::#screaming_name;
+ interface_id ^= u32::from_be_bytes(Self::#screaming_name);
}
}
@@ -831,14 +831,14 @@
#(
#consts
)*
- pub fn interface_id() -> u32 {
+ pub fn interface_id() -> ::evm_coder::types::bytes4 {
let mut interface_id = 0;
#(#interface_id)*
#(#inline_interface_id)*
- interface_id
+ u32::to_be_bytes(interface_id)
}
- pub fn supports_interface(interface_id: u32) -> bool {
- interface_id != 0xffffff && (
+ pub fn supports_interface(interface_id: ::evm_coder::types::bytes4) -> bool {
+ interface_id != u32::to_be_bytes(0xffffff) && (
interface_id == ::evm_coder::ERC165Call::INTERFACE_ID ||
interface_id == Self::interface_id()
#(
@@ -884,7 +884,7 @@
}
}
impl #gen_ref ::evm_coder::Call for #call_name #gen_ref {
- fn parse(method_id: u32, reader: &mut ::evm_coder::abi::AbiReader) -> ::evm_coder::execution::Result<Option<Self>> {
+ fn parse(method_id: ::evm_coder::types::bytes4, reader: &mut ::evm_coder::abi::AbiReader) -> ::evm_coder::execution::Result<Option<Self>> {
use ::evm_coder::abi::AbiRead;
match method_id {
::evm_coder::ERC165Call::INTERFACE_ID => return Ok(
crates/evm-coder-macros/src/to_log.rsdiffbeforeafterboth--- a/crates/evm-coder-macros/src/to_log.rs
+++ b/crates/evm-coder-macros/src/to_log.rs
@@ -199,7 +199,7 @@
use evm_coder::solidity::*;
use core::fmt::Write;
let interface = SolidityInterface {
- selector: 0,
+ selector: [0; 4],
name: #solidity_name,
is: &[],
functions: (#(
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//! TODO: I misunterstood therminology, abi IS rlp encoded, so18//! this module should be replaced with rlp crate1920#![allow(dead_code)]2122#[cfg(not(feature = "std"))]23use alloc::vec::Vec;24use evm_core::ExitError;25use primitive_types::{H160, U256};2627use crate::{28 execution::{Error, ResultWithPostInfo, WithPostDispatchInfo},29 types::string,30};31use crate::execution::Result;3233const ABI_ALIGNMENT: usize = 32;3435#[derive(Clone)]36pub struct AbiReader<'i> {37 buf: &'i [u8],38 subresult_offset: usize,39 offset: usize,40}41impl<'i> AbiReader<'i> {42 pub fn new(buf: &'i [u8]) -> Self {43 Self {44 buf,45 subresult_offset: 0,46 offset: 0,47 }48 }49 pub fn new_call(buf: &'i [u8]) -> Result<(u32, Self)> {50 if buf.len() < 4 {51 return Err(Error::Error(ExitError::OutOfOffset));52 }53 let mut method_id = [0; 4];54 method_id.copy_from_slice(&buf[0..4]);5556 Ok((57 u32::from_be_bytes(method_id),58 Self {59 buf,60 subresult_offset: 4,61 offset: 4,62 },63 ))64 }6566 fn read_padleft<const S: usize>(&mut self) -> Result<[u8; S]> {67 if self.buf.len() - self.offset < ABI_ALIGNMENT {68 return Err(Error::Error(ExitError::OutOfOffset));69 }70 let mut block = [0; S];71 // Verify padding is empty72 if !self.buf[self.offset..self.offset + ABI_ALIGNMENT - S]73 .iter()74 .all(|&v| v == 0)75 {76 return Err(Error::Error(ExitError::InvalidRange));77 }78 block.copy_from_slice(79 &self.buf[self.offset + ABI_ALIGNMENT - S..self.offset + ABI_ALIGNMENT],80 );81 self.offset += ABI_ALIGNMENT;82 Ok(block)83 }8485 pub fn address(&mut self) -> Result<H160> {86 Ok(H160(self.read_padleft()?))87 }8889 pub fn bool(&mut self) -> Result<bool> {90 let data: [u8; 1] = self.read_padleft()?;91 match data[0] {92 0 => Ok(false),93 1 => Ok(true),94 _ => Err(Error::Error(ExitError::InvalidRange)),95 }96 }9798 pub fn bytes4(&mut self) -> Result<[u8; 4]> {99 self.read_padleft()100 }101102 pub fn bytes(&mut self) -> Result<Vec<u8>> {103 let mut subresult = self.subresult()?;104 let length = subresult.read_usize()?;105 if subresult.buf.len() <= subresult.offset + length {106 return Err(Error::Error(ExitError::OutOfOffset));107 }108 Ok(subresult.buf[subresult.offset..subresult.offset + length].into())109 }110 pub fn string(&mut self) -> Result<string> {111 string::from_utf8(self.bytes()?).map_err(|_| Error::Error(ExitError::InvalidRange))112 }113114 pub fn uint8(&mut self) -> Result<u8> {115 Ok(self.read_padleft::<1>()?[0])116 }117118 pub fn uint32(&mut self) -> Result<u32> {119 Ok(u32::from_be_bytes(self.read_padleft()?))120 }121122 pub fn uint128(&mut self) -> Result<u128> {123 Ok(u128::from_be_bytes(self.read_padleft()?))124 }125126 pub fn uint256(&mut self) -> Result<U256> {127 let buf: [u8; 32] = self.read_padleft()?;128 Ok(U256::from_big_endian(&buf))129 }130131 pub fn uint64(&mut self) -> Result<u64> {132 Ok(u64::from_be_bytes(self.read_padleft()?))133 }134135 pub fn read_usize(&mut self) -> Result<usize> {136 Ok(usize::from_be_bytes(self.read_padleft()?))137 }138139 fn subresult(&mut self) -> Result<AbiReader<'i>> {140 let offset = self.read_usize()?;141 if offset + self.subresult_offset > self.buf.len() {142 return Err(Error::Error(ExitError::InvalidRange));143 }144 Ok(AbiReader {145 buf: self.buf,146 subresult_offset: offset + self.subresult_offset,147 offset: offset + self.subresult_offset,148 })149 }150151 pub fn is_finished(&self) -> bool {152 self.buf.len() == self.offset153 }154}155156#[derive(Default)]157pub struct AbiWriter {158 static_part: Vec<u8>,159 dynamic_part: Vec<(usize, AbiWriter)>,160}161impl AbiWriter {162 pub fn new() -> Self {163 Self::default()164 }165 pub fn new_call(method_id: u32) -> Self {166 let mut val = Self::new();167 val.static_part.extend(&method_id.to_be_bytes());168 val169 }170171 fn write_padleft(&mut self, block: &[u8]) {172 assert!(block.len() <= ABI_ALIGNMENT);173 self.static_part174 .extend(&[0; ABI_ALIGNMENT][0..ABI_ALIGNMENT - block.len()]);175 self.static_part.extend(block);176 }177178 fn write_padright(&mut self, bytes: &[u8]) {179 assert!(bytes.len() <= ABI_ALIGNMENT);180 self.static_part.extend(bytes);181 self.static_part182 .extend(&[0; ABI_ALIGNMENT][0..ABI_ALIGNMENT - bytes.len()]);183 }184185 pub fn address(&mut self, address: &H160) {186 self.write_padleft(&address.0)187 }188189 pub fn bool(&mut self, value: &bool) {190 self.write_padleft(&[if *value { 1 } else { 0 }])191 }192193 pub fn uint8(&mut self, value: &u8) {194 self.write_padleft(&[*value])195 }196197 pub fn uint32(&mut self, value: &u32) {198 self.write_padleft(&u32::to_be_bytes(*value))199 }200201 pub fn uint128(&mut self, value: &u128) {202 self.write_padleft(&u128::to_be_bytes(*value))203 }204205 pub fn uint256(&mut self, value: &U256) {206 let mut out = [0; 32];207 value.to_big_endian(&mut out);208 self.write_padleft(&out)209 }210211 pub fn write_usize(&mut self, value: &usize) {212 self.write_padleft(&usize::to_be_bytes(*value))213 }214215 pub fn write_subresult(&mut self, result: Self) {216 self.dynamic_part.push((self.static_part.len(), result));217 // Empty block, to be filled later218 self.write_padleft(&[]);219 }220221 pub fn memory(&mut self, value: &[u8]) {222 let mut sub = Self::new();223 sub.write_usize(&value.len());224 for chunk in value.chunks(ABI_ALIGNMENT) {225 sub.write_padright(chunk);226 }227 self.write_subresult(sub);228 }229230 pub fn string(&mut self, value: &str) {231 self.memory(value.as_bytes())232 }233234 pub fn bytes(&mut self, value: &[u8]) {235 self.memory(value)236 }237238 pub fn finish(mut self) -> Vec<u8> {239 for (static_offset, part) in self.dynamic_part {240 let part_offset = self.static_part.len();241242 let encoded_dynamic_offset = usize::to_be_bytes(part_offset);243 self.static_part[static_offset + ABI_ALIGNMENT - encoded_dynamic_offset.len()244 ..static_offset + ABI_ALIGNMENT]245 .copy_from_slice(&encoded_dynamic_offset);246 self.static_part.extend(part.finish())247 }248 self.static_part249 }250}251252pub trait AbiRead<T> {253 fn abi_read(&mut self) -> Result<T>;254}255256macro_rules! impl_abi_readable {257 ($ty:ty, $method:ident) => {258 impl AbiRead<$ty> for AbiReader<'_> {259 fn abi_read(&mut self) -> Result<$ty> {260 self.$method()261 }262 }263 };264}265266impl_abi_readable!(u8, uint8);267impl_abi_readable!(u32, uint32);268impl_abi_readable!(u64, uint64);269impl_abi_readable!(u128, uint128);270impl_abi_readable!(U256, uint256);271impl_abi_readable!(H160, address);272impl_abi_readable!(Vec<u8>, bytes);273impl_abi_readable!(bool, bool);274impl_abi_readable!(string, string);275276mod sealed {277 /// Not all types can be placed in vec, i.e `Vec<u8>` is restricted, `bytes` should be used instead278 pub trait CanBePlacedInVec {}279}280281impl sealed::CanBePlacedInVec for U256 {}282impl sealed::CanBePlacedInVec for string {}283impl sealed::CanBePlacedInVec for H160 {}284285impl<R: sealed::CanBePlacedInVec> AbiRead<Vec<R>> for AbiReader<'_>286where287 Self: AbiRead<R>,288{289 fn abi_read(&mut self) -> Result<Vec<R>> {290 let mut sub = self.subresult()?;291 let size = sub.read_usize()?;292 sub.subresult_offset = sub.offset;293 let mut out = Vec::with_capacity(size);294 for _ in 0..size {295 out.push(<Self as AbiRead<R>>::abi_read(&mut sub)?);296 }297 Ok(out)298 }299}300301macro_rules! impl_tuples {302 ($($ident:ident)+) => {303 impl<$($ident),+> sealed::CanBePlacedInVec for ($($ident,)+) {}304 impl<$($ident),+> AbiRead<($($ident,)+)> for AbiReader<'_>305 where306 $(Self: AbiRead<$ident>),+307 {308 fn abi_read(&mut self) -> Result<($($ident,)+)> {309 let mut subresult = self.subresult()?;310 Ok((311 $(<Self as AbiRead<$ident>>::abi_read(&mut subresult)?,)+312 ))313 }314 }315 };316}317318impl_tuples! {A}319impl_tuples! {A B}320impl_tuples! {A B C}321impl_tuples! {A B C D}322impl_tuples! {A B C D E}323impl_tuples! {A B C D E F}324impl_tuples! {A B C D E F G}325impl_tuples! {A B C D E F G H}326impl_tuples! {A B C D E F G H I}327impl_tuples! {A B C D E F G H I J}328329pub trait AbiWrite {330 fn abi_write(&self, writer: &mut AbiWriter);331 fn to_result(&self) -> ResultWithPostInfo<AbiWriter> {332 let mut writer = AbiWriter::new();333 self.abi_write(&mut writer);334 Ok(writer.into())335 }336}337338impl<T: AbiWrite> AbiWrite for ResultWithPostInfo<T> {339 // this particular AbiWrite implementation should be split to another trait,340 // which only implements [`to_result`]341 //342 // But due to lack of specialization feature in stable Rust, we can't have343 // blanket impl of this trait `for T where T: AbiWrite`, so here we abusing344 // default trait methods for it345 fn abi_write(&self, _writer: &mut AbiWriter) {346 debug_assert!(false, "shouldn't be called, see comment")347 }348 fn to_result(&self) -> ResultWithPostInfo<AbiWriter> {349 match self {350 Ok(v) => Ok(WithPostDispatchInfo {351 post_info: v.post_info.clone(),352 data: {353 let mut out = AbiWriter::new();354 v.data.abi_write(&mut out);355 out356 },357 }),358 Err(e) => Err(e.clone()),359 }360 }361}362363macro_rules! impl_abi_writeable {364 ($ty:ty, $method:ident) => {365 impl AbiWrite for $ty {366 fn abi_write(&self, writer: &mut AbiWriter) {367 writer.$method(&self)368 }369 }370 };371}372373impl_abi_writeable!(u8, uint8);374impl_abi_writeable!(u32, uint32);375impl_abi_writeable!(u128, uint128);376impl_abi_writeable!(U256, uint256);377impl_abi_writeable!(H160, address);378impl_abi_writeable!(bool, bool);379impl_abi_writeable!(&str, string);380impl AbiWrite for &string {381 fn abi_write(&self, writer: &mut AbiWriter) {382 writer.string(self)383 }384}385impl AbiWrite for &Vec<u8> {386 fn abi_write(&self, writer: &mut AbiWriter) {387 writer.bytes(self)388 }389}390391impl AbiWrite for () {392 fn abi_write(&self, _writer: &mut AbiWriter) {}393}394395#[macro_export]396macro_rules! abi_decode {397 ($reader:expr, $($name:ident: $typ:ident),+ $(,)?) => {398 $(399 let $name = $reader.$typ()?;400 )+401 }402}403#[macro_export]404macro_rules! abi_encode {405 ($($typ:ident($value:expr)),* $(,)?) => {{406 #[allow(unused_mut)]407 let mut writer = ::evm_coder::abi::AbiWriter::new();408 $(409 writer.$typ($value);410 )*411 writer412 }};413 (call $val:expr; $($typ:ident($value:expr)),* $(,)?) => {{414 #[allow(unused_mut)]415 let mut writer = ::evm_coder::abi::AbiWriter::new_call($val);416 $(417 writer.$typ($value);418 )*419 writer420 }}421}422423#[cfg(test)]424pub mod test {425 use crate::{426 abi::AbiRead,427 types::{string, uint256},428 };429430 use super::{AbiReader, AbiWriter};431 use hex_literal::hex;432433 #[test]434 fn dynamic_after_static() {435 let mut encoder = AbiWriter::new();436 encoder.bool(&true);437 encoder.string("test");438 let encoded = encoder.finish();439440 let mut encoder = AbiWriter::new();441 encoder.bool(&true);442 // Offset to subresult443 encoder.uint32(&(32 * 2));444 // Len of "test"445 encoder.uint32(&4);446 encoder.write_padright(&[b't', b'e', b's', b't']);447 let alternative_encoded = encoder.finish();448449 assert_eq!(encoded, alternative_encoded);450451 let mut decoder = AbiReader::new(&encoded);452 assert_eq!(decoder.bool().unwrap(), true);453 assert_eq!(decoder.string().unwrap(), "test");454 }455456 #[test]457 fn mint_sample() {458 let (call, mut decoder) = AbiReader::new_call(&hex!(459 "460 50bb4e7f461 000000000000000000000000ad2c0954693c2b5404b7e50967d3481bea432374462 0000000000000000000000000000000000000000000000000000000000000001463 0000000000000000000000000000000000000000000000000000000000000060464 0000000000000000000000000000000000000000000000000000000000000008465 5465737420555249000000000000000000000000000000000000000000000000466 "467 ))468 .unwrap();469 assert_eq!(call, 0x50bb4e7f);470 assert_eq!(471 format!("{:?}", decoder.address().unwrap()),472 "0xad2c0954693c2b5404b7e50967d3481bea432374"473 );474 assert_eq!(decoder.uint32().unwrap(), 1);475 assert_eq!(decoder.string().unwrap(), "Test URI");476 }477478 #[test]479 fn mint_bulk() {480 let (call, mut decoder) = AbiReader::new_call(&hex!(481 "482 36543006483 00000000000000000000000053744e6da587ba10b32a2554d2efdcd985bc27a3 // address484 0000000000000000000000000000000000000000000000000000000000000040 // offset of (uint256, string)[]485 0000000000000000000000000000000000000000000000000000000000000003 // length of (uint256, string)[]486487 0000000000000000000000000000000000000000000000000000000000000060 // offset of first elem488 00000000000000000000000000000000000000000000000000000000000000e0 // offset of second elem489 0000000000000000000000000000000000000000000000000000000000000160 // offset of third elem490491 0000000000000000000000000000000000000000000000000000000000000001 // first token id? #60492 0000000000000000000000000000000000000000000000000000000000000040 // offset of string493 000000000000000000000000000000000000000000000000000000000000000a // size of string494 5465737420555249203000000000000000000000000000000000000000000000 // string495496 000000000000000000000000000000000000000000000000000000000000000b // second token id? Why ==11? #e0497 0000000000000000000000000000000000000000000000000000000000000040 // offset of string498 000000000000000000000000000000000000000000000000000000000000000a // size of string499 5465737420555249203100000000000000000000000000000000000000000000 // string500501 000000000000000000000000000000000000000000000000000000000000000c // third token id? Why ==12? #160502 0000000000000000000000000000000000000000000000000000000000000040 // offset of string503 000000000000000000000000000000000000000000000000000000000000000a // size of string504 5465737420555249203200000000000000000000000000000000000000000000 // string505 "506 ))507 .unwrap();508 assert_eq!(call, 0x36543006);509 let _ = decoder.address().unwrap();510 let data =511 <AbiReader<'_> as AbiRead<Vec<(uint256, string)>>>::abi_read(&mut decoder).unwrap();512 assert_eq!(513 data,514 vec![515 (1.into(), "Test URI 0".to_string()),516 (11.into(), "Test URI 1".to_string()),517 (12.into(), "Test URI 2".to_string())518 ]519 );520 }521}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//! TODO: I misunterstood therminology, abi IS rlp encoded, so18//! this module should be replaced with rlp crate1920#![allow(dead_code)]2122#[cfg(not(feature = "std"))]23use alloc::vec::Vec;24use evm_core::ExitError;25use primitive_types::{H160, U256};2627use crate::{28 execution::{Error, ResultWithPostInfo, WithPostDispatchInfo},29 types::{string, self},30};31use crate::execution::Result;3233const ABI_ALIGNMENT: usize = 32;3435#[derive(Clone)]36pub struct AbiReader<'i> {37 buf: &'i [u8],38 subresult_offset: usize,39 offset: usize,40}41impl<'i> AbiReader<'i> {42 pub fn new(buf: &'i [u8]) -> Self {43 Self {44 buf,45 subresult_offset: 0,46 offset: 0,47 }48 }49 pub fn new_call(buf: &'i [u8]) -> Result<(types::bytes4, Self)> {50 if buf.len() < 4 {51 return Err(Error::Error(ExitError::OutOfOffset));52 }53 let mut method_id = [0; 4];54 method_id.copy_from_slice(&buf[0..4]);5556 Ok((57 method_id,58 Self {59 buf,60 subresult_offset: 4,61 offset: 4,62 },63 ))64 }6566 fn read_pad<const S: usize>(67 buf: &[u8],68 offset: usize,69 pad_start: usize,70 pad_size: usize,71 block_start: usize,72 block_size: usize,73 ) -> Result<[u8; S]> {74 if buf.len() - offset < ABI_ALIGNMENT {75 return Err(Error::Error(ExitError::OutOfOffset));76 }77 let mut block = [0; S];78 // Verify padding is empty79 if !buf[pad_start..pad_size].iter().all(|&v| v == 0) {80 return Err(Error::Error(ExitError::InvalidRange));81 }82 block.copy_from_slice(&buf[block_start..block_size]);83 Ok(block)84 }8586 fn read_padleft<const S: usize>(&mut self) -> Result<[u8; S]> {87 let offset = self.offset;88 self.offset += ABI_ALIGNMENT;89 Self::read_pad(90 self.buf,91 offset,92 offset,93 offset + ABI_ALIGNMENT - S,94 offset + ABI_ALIGNMENT - S,95 offset + ABI_ALIGNMENT,96 )97 }9899 fn read_padright<const S: usize>(&mut self) -> Result<[u8; S]> {100 let offset = self.offset;101 self.offset += ABI_ALIGNMENT;102 Self::read_pad(103 self.buf,104 offset,105 offset + S,106 offset + ABI_ALIGNMENT,107 offset,108 offset + S,109 )110 }111112 pub fn address(&mut self) -> Result<H160> {113 Ok(H160(self.read_padleft()?))114 }115116 pub fn bool(&mut self) -> Result<bool> {117 let data: [u8; 1] = self.read_padleft()?;118 match data[0] {119 0 => Ok(false),120 1 => Ok(true),121 _ => Err(Error::Error(ExitError::InvalidRange)),122 }123 }124125 pub fn bytes4(&mut self) -> Result<[u8; 4]> {126 self.read_padright()127 }128129 pub fn bytes(&mut self) -> Result<Vec<u8>> {130 let mut subresult = self.subresult()?;131 let length = subresult.read_usize()?;132 if subresult.buf.len() <= subresult.offset + length {133 return Err(Error::Error(ExitError::OutOfOffset));134 }135 Ok(subresult.buf[subresult.offset..subresult.offset + length].into())136 }137 pub fn string(&mut self) -> Result<string> {138 string::from_utf8(self.bytes()?).map_err(|_| Error::Error(ExitError::InvalidRange))139 }140141 pub fn uint8(&mut self) -> Result<u8> {142 Ok(self.read_padleft::<1>()?[0])143 }144145 pub fn uint32(&mut self) -> Result<u32> {146 Ok(u32::from_be_bytes(self.read_padleft()?))147 }148149 pub fn uint128(&mut self) -> Result<u128> {150 Ok(u128::from_be_bytes(self.read_padleft()?))151 }152153 pub fn uint256(&mut self) -> Result<U256> {154 let buf: [u8; 32] = self.read_padleft()?;155 Ok(U256::from_big_endian(&buf))156 }157158 pub fn uint64(&mut self) -> Result<u64> {159 Ok(u64::from_be_bytes(self.read_padleft()?))160 }161162 pub fn read_usize(&mut self) -> Result<usize> {163 Ok(usize::from_be_bytes(self.read_padleft()?))164 }165166 fn subresult(&mut self) -> Result<AbiReader<'i>> {167 let offset = self.read_usize()?;168 if offset + self.subresult_offset > self.buf.len() {169 return Err(Error::Error(ExitError::InvalidRange));170 }171 Ok(AbiReader {172 buf: self.buf,173 subresult_offset: offset + self.subresult_offset,174 offset: offset + self.subresult_offset,175 })176 }177178 pub fn is_finished(&self) -> bool {179 self.buf.len() == self.offset180 }181}182183#[derive(Default)]184pub struct AbiWriter {185 static_part: Vec<u8>,186 dynamic_part: Vec<(usize, AbiWriter)>,187}188impl AbiWriter {189 pub fn new() -> Self {190 Self::default()191 }192 pub fn new_call(method_id: u32) -> Self {193 let mut val = Self::new();194 val.static_part.extend(&method_id.to_be_bytes());195 val196 }197198 fn write_padleft(&mut self, block: &[u8]) {199 assert!(block.len() <= ABI_ALIGNMENT);200 self.static_part201 .extend(&[0; ABI_ALIGNMENT][0..ABI_ALIGNMENT - block.len()]);202 self.static_part.extend(block);203 }204205 fn write_padright(&mut self, bytes: &[u8]) {206 assert!(bytes.len() <= ABI_ALIGNMENT);207 self.static_part.extend(bytes);208 self.static_part209 .extend(&[0; ABI_ALIGNMENT][0..ABI_ALIGNMENT - bytes.len()]);210 }211212 pub fn address(&mut self, address: &H160) {213 self.write_padleft(&address.0)214 }215216 pub fn bool(&mut self, value: &bool) {217 self.write_padleft(&[if *value { 1 } else { 0 }])218 }219220 pub fn uint8(&mut self, value: &u8) {221 self.write_padleft(&[*value])222 }223224 pub fn uint32(&mut self, value: &u32) {225 self.write_padleft(&u32::to_be_bytes(*value))226 }227228 pub fn uint128(&mut self, value: &u128) {229 self.write_padleft(&u128::to_be_bytes(*value))230 }231232 pub fn uint256(&mut self, value: &U256) {233 let mut out = [0; 32];234 value.to_big_endian(&mut out);235 self.write_padleft(&out)236 }237238 pub fn write_usize(&mut self, value: &usize) {239 self.write_padleft(&usize::to_be_bytes(*value))240 }241242 pub fn write_subresult(&mut self, result: Self) {243 self.dynamic_part.push((self.static_part.len(), result));244 // Empty block, to be filled later245 self.write_padleft(&[]);246 }247248 pub fn memory(&mut self, value: &[u8]) {249 let mut sub = Self::new();250 sub.write_usize(&value.len());251 for chunk in value.chunks(ABI_ALIGNMENT) {252 sub.write_padright(chunk);253 }254 self.write_subresult(sub);255 }256257 pub fn string(&mut self, value: &str) {258 self.memory(value.as_bytes())259 }260261 pub fn bytes(&mut self, value: &[u8]) {262 self.memory(value)263 }264265 pub fn finish(mut self) -> Vec<u8> {266 for (static_offset, part) in self.dynamic_part {267 let part_offset = self.static_part.len();268269 let encoded_dynamic_offset = usize::to_be_bytes(part_offset);270 self.static_part[static_offset + ABI_ALIGNMENT - encoded_dynamic_offset.len()271 ..static_offset + ABI_ALIGNMENT]272 .copy_from_slice(&encoded_dynamic_offset);273 self.static_part.extend(part.finish())274 }275 self.static_part276 }277}278279pub trait AbiRead<T> {280 fn abi_read(&mut self) -> Result<T>;281}282283macro_rules! impl_abi_readable {284 ($ty:ty, $method:ident) => {285 impl AbiRead<$ty> for AbiReader<'_> {286 fn abi_read(&mut self) -> Result<$ty> {287 self.$method()288 }289 }290 };291}292293impl_abi_readable!(u8, uint8);294impl_abi_readable!(u32, uint32);295impl_abi_readable!(u64, uint64);296impl_abi_readable!(u128, uint128);297impl_abi_readable!(U256, uint256);298impl_abi_readable!([u8; 4], bytes4);299impl_abi_readable!(H160, address);300impl_abi_readable!(Vec<u8>, bytes);301impl_abi_readable!(bool, bool);302impl_abi_readable!(string, string);303304mod sealed {305 /// Not all types can be placed in vec, i.e `Vec<u8>` is restricted, `bytes` should be used instead306 pub trait CanBePlacedInVec {}307}308309impl sealed::CanBePlacedInVec for U256 {}310impl sealed::CanBePlacedInVec for string {}311impl sealed::CanBePlacedInVec for H160 {}312313impl<R: sealed::CanBePlacedInVec> AbiRead<Vec<R>> for AbiReader<'_>314where315 Self: AbiRead<R>,316{317 fn abi_read(&mut self) -> Result<Vec<R>> {318 let mut sub = self.subresult()?;319 let size = sub.read_usize()?;320 sub.subresult_offset = sub.offset;321 let mut out = Vec::with_capacity(size);322 for _ in 0..size {323 out.push(<Self as AbiRead<R>>::abi_read(&mut sub)?);324 }325 Ok(out)326 }327}328329macro_rules! impl_tuples {330 ($($ident:ident)+) => {331 impl<$($ident),+> sealed::CanBePlacedInVec for ($($ident,)+) {}332 impl<$($ident),+> AbiRead<($($ident,)+)> for AbiReader<'_>333 where334 $(Self: AbiRead<$ident>),+335 {336 fn abi_read(&mut self) -> Result<($($ident,)+)> {337 let mut subresult = self.subresult()?;338 Ok((339 $(<Self as AbiRead<$ident>>::abi_read(&mut subresult)?,)+340 ))341 }342 }343 };344}345346impl_tuples! {A}347impl_tuples! {A B}348impl_tuples! {A B C}349impl_tuples! {A B C D}350impl_tuples! {A B C D E}351impl_tuples! {A B C D E F}352impl_tuples! {A B C D E F G}353impl_tuples! {A B C D E F G H}354impl_tuples! {A B C D E F G H I}355impl_tuples! {A B C D E F G H I J}356357pub trait AbiWrite {358 fn abi_write(&self, writer: &mut AbiWriter);359 fn to_result(&self) -> ResultWithPostInfo<AbiWriter> {360 let mut writer = AbiWriter::new();361 self.abi_write(&mut writer);362 Ok(writer.into())363 }364}365366impl<T: AbiWrite> AbiWrite for ResultWithPostInfo<T> {367 // this particular AbiWrite implementation should be split to another trait,368 // which only implements [`to_result`]369 //370 // But due to lack of specialization feature in stable Rust, we can't have371 // blanket impl of this trait `for T where T: AbiWrite`, so here we abusing372 // default trait methods for it373 fn abi_write(&self, _writer: &mut AbiWriter) {374 debug_assert!(false, "shouldn't be called, see comment")375 }376 fn to_result(&self) -> ResultWithPostInfo<AbiWriter> {377 match self {378 Ok(v) => Ok(WithPostDispatchInfo {379 post_info: v.post_info.clone(),380 data: {381 let mut out = AbiWriter::new();382 v.data.abi_write(&mut out);383 out384 },385 }),386 Err(e) => Err(e.clone()),387 }388 }389}390391macro_rules! impl_abi_writeable {392 ($ty:ty, $method:ident) => {393 impl AbiWrite for $ty {394 fn abi_write(&self, writer: &mut AbiWriter) {395 writer.$method(&self)396 }397 }398 };399}400401impl_abi_writeable!(u8, uint8);402impl_abi_writeable!(u32, uint32);403impl_abi_writeable!(u128, uint128);404impl_abi_writeable!(U256, uint256);405impl_abi_writeable!(H160, address);406impl_abi_writeable!(bool, bool);407impl_abi_writeable!(&str, string);408impl AbiWrite for &string {409 fn abi_write(&self, writer: &mut AbiWriter) {410 writer.string(self)411 }412}413impl AbiWrite for &Vec<u8> {414 fn abi_write(&self, writer: &mut AbiWriter) {415 writer.bytes(self)416 }417}418419impl AbiWrite for () {420 fn abi_write(&self, _writer: &mut AbiWriter) {}421}422423#[macro_export]424macro_rules! abi_decode {425 ($reader:expr, $($name:ident: $typ:ident),+ $(,)?) => {426 $(427 let $name = $reader.$typ()?;428 )+429 }430}431#[macro_export]432macro_rules! abi_encode {433 ($($typ:ident($value:expr)),* $(,)?) => {{434 #[allow(unused_mut)]435 let mut writer = ::evm_coder::abi::AbiWriter::new();436 $(437 writer.$typ($value);438 )*439 writer440 }};441 (call $val:expr; $($typ:ident($value:expr)),* $(,)?) => {{442 #[allow(unused_mut)]443 let mut writer = ::evm_coder::abi::AbiWriter::new_call($val);444 $(445 writer.$typ($value);446 )*447 writer448 }}449}450451#[cfg(test)]452pub mod test {453 use crate::{454 abi::AbiRead,455 types::{string, uint256},456 };457458 use super::{AbiReader, AbiWriter};459 use hex_literal::hex;460461 #[test]462 fn dynamic_after_static() {463 let mut encoder = AbiWriter::new();464 encoder.bool(&true);465 encoder.string("test");466 let encoded = encoder.finish();467468 let mut encoder = AbiWriter::new();469 encoder.bool(&true);470 // Offset to subresult471 encoder.uint32(&(32 * 2));472 // Len of "test"473 encoder.uint32(&4);474 encoder.write_padright(&[b't', b'e', b's', b't']);475 let alternative_encoded = encoder.finish();476477 assert_eq!(encoded, alternative_encoded);478479 let mut decoder = AbiReader::new(&encoded);480 assert_eq!(decoder.bool().unwrap(), true);481 assert_eq!(decoder.string().unwrap(), "test");482 }483484 #[test]485 fn mint_sample() {486 let (call, mut decoder) = AbiReader::new_call(&hex!(487 "488 50bb4e7f489 000000000000000000000000ad2c0954693c2b5404b7e50967d3481bea432374490 0000000000000000000000000000000000000000000000000000000000000001491 0000000000000000000000000000000000000000000000000000000000000060492 0000000000000000000000000000000000000000000000000000000000000008493 5465737420555249000000000000000000000000000000000000000000000000494 "495 ))496 .unwrap();497 assert_eq!(call, u32::to_be_bytes(0x50bb4e7f));498 assert_eq!(499 format!("{:?}", decoder.address().unwrap()),500 "0xad2c0954693c2b5404b7e50967d3481bea432374"501 );502 assert_eq!(decoder.uint32().unwrap(), 1);503 assert_eq!(decoder.string().unwrap(), "Test URI");504 }505506 #[test]507 fn mint_bulk() {508 let (call, mut decoder) = AbiReader::new_call(&hex!(509 "510 36543006511 00000000000000000000000053744e6da587ba10b32a2554d2efdcd985bc27a3 // address512 0000000000000000000000000000000000000000000000000000000000000040 // offset of (uint256, string)[]513 0000000000000000000000000000000000000000000000000000000000000003 // length of (uint256, string)[]514515 0000000000000000000000000000000000000000000000000000000000000060 // offset of first elem516 00000000000000000000000000000000000000000000000000000000000000e0 // offset of second elem517 0000000000000000000000000000000000000000000000000000000000000160 // offset of third elem518519 0000000000000000000000000000000000000000000000000000000000000001 // first token id? #60520 0000000000000000000000000000000000000000000000000000000000000040 // offset of string521 000000000000000000000000000000000000000000000000000000000000000a // size of string522 5465737420555249203000000000000000000000000000000000000000000000 // string523524 000000000000000000000000000000000000000000000000000000000000000b // second token id? Why ==11? #e0525 0000000000000000000000000000000000000000000000000000000000000040 // offset of string526 000000000000000000000000000000000000000000000000000000000000000a // size of string527 5465737420555249203100000000000000000000000000000000000000000000 // string528529 000000000000000000000000000000000000000000000000000000000000000c // third token id? Why ==12? #160530 0000000000000000000000000000000000000000000000000000000000000040 // offset of string531 000000000000000000000000000000000000000000000000000000000000000a // size of string532 5465737420555249203200000000000000000000000000000000000000000000 // string533 "534 ))535 .unwrap();536 assert_eq!(call, u32::to_be_bytes(0x36543006));537 let _ = decoder.address().unwrap();538 let data =539 <AbiReader<'_> as AbiRead<Vec<(uint256, string)>>>::abi_read(&mut decoder).unwrap();540 assert_eq!(541 data,542 vec![543 (1.into(), "Test URI 0".to_string()),544 (11.into(), "Test URI 1".to_string()),545 (12.into(), "Test URI 2".to_string())546 ]547 );548 }549}crates/evm-coder/src/lib.rsdiffbeforeafterboth--- a/crates/evm-coder/src/lib.rs
+++ b/crates/evm-coder/src/lib.rs
@@ -44,7 +44,7 @@
pub type uint128 = u128;
pub type uint256 = U256;
- pub type bytes4 = u32;
+ pub type bytes4 = [u8; 4];
pub type topic = H256;
@@ -71,7 +71,7 @@
}
pub trait Call: Sized {
- fn parse(selector: u32, input: &mut AbiReader) -> execution::Result<Option<Self>>;
+ fn parse(selector: types::bytes4, input: &mut AbiReader) -> execution::Result<Option<Self>>;
}
pub type Weight = u64;
@@ -93,11 +93,11 @@
}
impl ERC165Call {
- pub const INTERFACE_ID: types::bytes4 = 0x01ffc9a7;
+ pub const INTERFACE_ID: types::bytes4 = u32::to_be_bytes(0x01ffc9a7);
}
impl Call for ERC165Call {
- fn parse(selector: u32, input: &mut AbiReader) -> execution::Result<Option<Self>> {
+ fn parse(selector: types::bytes4, input: &mut AbiReader) -> execution::Result<Option<Self>> {
if selector != Self::INTERFACE_ID {
return Ok(None);
}
crates/evm-coder/src/solidity.rsdiffbeforeafterboth--- a/crates/evm-coder/src/solidity.rs
+++ b/crates/evm-coder/src/solidity.rs
@@ -103,6 +103,7 @@
uint64 => "uint64" true = "0",
uint128 => "uint128" true = "0",
uint256 => "uint256" true = "0",
+ bytes4 => "bytes4" true = "bytes4(0)",
address => "address" true = "0x0000000000000000000000000000000000000000",
string => "string" false = "\"\"",
bytes => "bytes" false = "hex\"\"",
@@ -473,7 +474,7 @@
}
pub struct SolidityInterface<F: SolidityFunctions> {
- pub selector: u32,
+ pub selector: bytes4,
pub name: &'static str,
pub is: &'static [&'static str],
pub functions: F,
@@ -486,8 +487,13 @@
out: &mut impl fmt::Write,
tc: &TypeCollector,
) -> fmt::Result {
- if self.selector != 0 {
- writeln!(out, "// Selector: {:0>8x}", self.selector)?;
+ const ZERO_BYTES: [u8; 4] = [0; 4];
+ if self.selector != ZERO_BYTES {
+ writeln!(
+ out,
+ "// Selector: {:0>8x}",
+ u32::from_be_bytes(self.selector)
+ )?;
}
if is_impl {
write!(out, "contract ")?;
tests/src/eth/base.test.tsdiffbeforeafterboth--- a/tests/src/eth/base.test.ts
+++ b/tests/src/eth/base.test.ts
@@ -14,11 +14,13 @@
// You should have received a copy of the GNU General Public License
// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
-import {collectionIdToAddress, createEthAccount, createEthAccountWithBalance, deployFlipper, ethBalanceViaSub, GAS_ARGS, itWeb3, recordEthFee} from './util/helpers';
+import {collectionIdToAddress, createEthAccount, createEthAccountWithBalance, deployFlipper, ethBalanceViaSub, GAS_ARGS, itWeb3, recordEthFee, usingWeb3} from './util/helpers';
import {expect} from 'chai';
import {createCollectionExpectSuccess, createItemExpectSuccess, UNIQUE} from '../util/helpers';
import nonFungibleAbi from './nonFungibleAbi.json';
import privateKey from '../substrate/privateKey';
+import {Contract} from 'web3-eth-contract';
+import Web3 from 'web3';
describe('Contract calls', () => {
itWeb3('Call of simple contract fee is less than 0.2 UNQ', async ({web3, api}) => {
@@ -60,3 +62,53 @@
expect(Math.abs(fee - expectedFee)).to.be.lessThan(tolerance);
});
});
+
+describe('ERC165 tests', async () => {
+ // https://eips.ethereum.org/EIPS/eip-165
+
+ let collection: number;
+ let minter: string;
+
+ function contract(web3: Web3): Contract {
+ return new web3.eth.Contract(nonFungibleAbi as any, collectionIdToAddress(collection), {from: minter, ...GAS_ARGS});
+ }
+
+ before(async () => {
+ await usingWeb3 (async (web3) => {
+ collection = await createCollectionExpectSuccess();
+ minter = createEthAccount(web3);
+ });
+ });
+
+ itWeb3('interfaceID == 0xffffffff always false', async ({web3}) => {
+ expect(await contract(web3).methods.supportsInterface('0xffffffff').call()).to.be.false;
+ });
+
+ itWeb3('ERC721 support', async ({web3}) => {
+ expect(await contract(web3).methods.supportsInterface('0x58800161').call()).to.be.true;
+ });
+
+ itWeb3('ERC721Metadata support', async ({web3}) => {
+ expect(await contract(web3).methods.supportsInterface('0x5b5e139f').call()).to.be.true;
+ });
+
+ itWeb3('ERC721Mintable support', async ({web3}) => {
+ expect(await contract(web3).methods.supportsInterface('0x68ccfe89').call()).to.be.true;
+ });
+
+ itWeb3('ERC721Enumerable support', async ({web3}) => {
+ expect(await contract(web3).methods.supportsInterface('0x780e9d63').call()).to.be.true;
+ });
+
+ itWeb3('ERC721UniqueExtensions support', async ({web3}) => {
+ expect(await contract(web3).methods.supportsInterface('0xe562194d').call()).to.be.true;
+ });
+
+ itWeb3('ERC721Burnable support', async ({web3}) => {
+ expect(await contract(web3).methods.supportsInterface('0x42966c68').call()).to.be.true;
+ });
+
+ itWeb3('ERC165 support', async ({web3}) => {
+ expect(await contract(web3).methods.supportsInterface('0x01ffc9a7').call()).to.be.true;
+ });
+});
tests/src/eth/nonFungibleAbi.jsondiffbeforeafterboth--- a/tests/src/eth/nonFungibleAbi.json
+++ b/tests/src/eth/nonFungibleAbi.json
@@ -466,9 +466,9 @@
{
"inputs": [
{
- "internalType": "uint32",
+ "internalType": "bytes4",
"name": "interfaceId",
- "type": "uint32"
+ "type": "bytes4"
}
],
"name": "supportsInterface",