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.rsdiffbeforeafterboth57 fn expand_interface_id(&self) -> proc_macro2::TokenStream {57 fn expand_interface_id(&self) -> proc_macro2::TokenStream {58 let pascal_call_name = &self.pascal_call_name;58 let pascal_call_name = &self.pascal_call_name;59 quote! {59 quote! {60 interface_id ^= #pascal_call_name::interface_id();60 interface_id ^= u32::from_be_bytes(#pascal_call_name::interface_id());61 }61 }62 }62 }6363540540541 fn expand_const(&self) -> proc_macro2::TokenStream {541 fn expand_const(&self) -> proc_macro2::TokenStream {542 let screaming_name = &self.screaming_name;542 let screaming_name = &self.screaming_name;543 let selector = self.selector;543 let selector = u32::to_be_bytes(self.selector);544 let selector_str = &self.selector_str;544 let selector_str = &self.selector_str;545 quote! {545 quote! {546 #[doc = #selector_str]546 #[doc = #selector_str]547 const #screaming_name: u32 = #selector;547 const #screaming_name: ::evm_coder::types::bytes4 = [#(#selector,)*];548 }548 }549 }549 }550550551 fn expand_interface_id(&self) -> proc_macro2::TokenStream {551 fn expand_interface_id(&self) -> proc_macro2::TokenStream {552 let screaming_name = &self.screaming_name;552 let screaming_name = &self.screaming_name;553 quote! {553 quote! {554 interface_id ^= Self::#screaming_name;554 interface_id ^= u32::from_be_bytes(Self::#screaming_name);555 }555 }556 }556 }557557831 #(831 #(832 #consts832 #consts833 )*833 )*834 pub fn interface_id() -> u32 {834 pub fn interface_id() -> ::evm_coder::types::bytes4 {835 let mut interface_id = 0;835 let mut interface_id = 0;836 #(#interface_id)*836 #(#interface_id)*837 #(#inline_interface_id)*837 #(#inline_interface_id)*838 interface_id838 u32::to_be_bytes(interface_id)839 }839 }840 pub fn supports_interface(interface_id: u32) -> bool {840 pub fn supports_interface(interface_id: ::evm_coder::types::bytes4) -> bool {841 interface_id != 0xffffff && (841 interface_id != u32::to_be_bytes(0xffffff) && (842 interface_id == ::evm_coder::ERC165Call::INTERFACE_ID ||842 interface_id == ::evm_coder::ERC165Call::INTERFACE_ID ||843 interface_id == Self::interface_id()843 interface_id == Self::interface_id()844 #(844 #(884 }884 }885 }885 }886 impl #gen_ref ::evm_coder::Call for #call_name #gen_ref {886 impl #gen_ref ::evm_coder::Call for #call_name #gen_ref {887 fn parse(method_id: u32, reader: &mut ::evm_coder::abi::AbiReader) -> ::evm_coder::execution::Result<Option<Self>> {887 fn parse(method_id: ::evm_coder::types::bytes4, reader: &mut ::evm_coder::abi::AbiReader) -> ::evm_coder::execution::Result<Option<Self>> {888 use ::evm_coder::abi::AbiRead;888 use ::evm_coder::abi::AbiRead;889 match method_id {889 match method_id {890 ::evm_coder::ERC165Call::INTERFACE_ID => return Ok(890 ::evm_coder::ERC165Call::INTERFACE_ID => return Ok(crates/evm-coder-macros/src/to_log.rsdiffbeforeafterboth199 use evm_coder::solidity::*;199 use evm_coder::solidity::*;200 use core::fmt::Write;200 use core::fmt::Write;201 let interface = SolidityInterface {201 let interface = SolidityInterface {202 selector: 0,202 selector: [0; 4],203 name: #solidity_name,203 name: #solidity_name,204 is: &[],204 is: &[],205 functions: (#(205 functions: (#(crates/evm-coder/src/abi.rsdiffbeforeafterboth262627use crate::{27use crate::{28 execution::{Error, ResultWithPostInfo, WithPostDispatchInfo},28 execution::{Error, ResultWithPostInfo, WithPostDispatchInfo},29 types::string,29 types::{string, self},30};30};31use crate::execution::Result;31use crate::execution::Result;323246 offset: 0,46 offset: 0,47 }47 }48 }48 }49 pub fn new_call(buf: &'i [u8]) -> Result<(u32, Self)> {49 pub fn new_call(buf: &'i [u8]) -> Result<(types::bytes4, Self)> {50 if buf.len() < 4 {50 if buf.len() < 4 {51 return Err(Error::Error(ExitError::OutOfOffset));51 return Err(Error::Error(ExitError::OutOfOffset));52 }52 }53 let mut method_id = [0; 4];53 let mut method_id = [0; 4];54 method_id.copy_from_slice(&buf[0..4]);54 method_id.copy_from_slice(&buf[0..4]);555556 Ok((56 Ok((57 u32::from_be_bytes(method_id),57 method_id,58 Self {58 Self {59 buf,59 buf,60 subresult_offset: 4,60 subresult_offset: 4,63 ))63 ))64 }64 }656566 fn read_padleft<const S: usize>(&mut self) -> Result<[u8; S]> {66 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]> {67 if self.buf.len() - self.offset < ABI_ALIGNMENT {74 if buf.len() - offset < ABI_ALIGNMENT {68 return Err(Error::Error(ExitError::OutOfOffset));75 return Err(Error::Error(ExitError::OutOfOffset));69 }76 }70 let mut block = [0; S];77 let mut block = [0; S];71 // Verify padding is empty78 // Verify padding is empty72 if !self.buf[self.offset..self.offset + ABI_ALIGNMENT - S]79 if !buf[pad_start..pad_size].iter().all(|&v| v == 0) {73 .iter()74 .all(|&v| v == 0)75 {76 return Err(Error::Error(ExitError::InvalidRange));80 return Err(Error::Error(ExitError::InvalidRange));77 }81 }78 block.copy_from_slice(82 block.copy_from_slice(&buf[block_start..block_size]);79 &self.buf[self.offset + ABI_ALIGNMENT - S..self.offset + ABI_ALIGNMENT],80 );81 self.offset += ABI_ALIGNMENT;82 Ok(block)83 Ok(block)83 }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 }8411185 pub fn address(&mut self) -> Result<H160> {112 pub fn address(&mut self) -> Result<H160> {86 Ok(H160(self.read_padleft()?))113 Ok(H160(self.read_padleft()?))96 }123 }9712498 pub fn bytes4(&mut self) -> Result<[u8; 4]> {125 pub fn bytes4(&mut self) -> Result<[u8; 4]> {99 self.read_padleft()126 self.read_padright()100 }127 }101128102 pub fn bytes(&mut self) -> Result<Vec<u8>> {129 pub fn bytes(&mut self) -> Result<Vec<u8>> {268impl_abi_readable!(u64, uint64);295impl_abi_readable!(u64, uint64);269impl_abi_readable!(u128, uint128);296impl_abi_readable!(u128, uint128);270impl_abi_readable!(U256, uint256);297impl_abi_readable!(U256, uint256);298impl_abi_readable!([u8; 4], bytes4);271impl_abi_readable!(H160, address);299impl_abi_readable!(H160, address);272impl_abi_readable!(Vec<u8>, bytes);300impl_abi_readable!(Vec<u8>, bytes);273impl_abi_readable!(bool, bool);301impl_abi_readable!(bool, bool);466 "494 "467 ))495 ))468 .unwrap();496 .unwrap();469 assert_eq!(call, 0x50bb4e7f);497 assert_eq!(call, u32::to_be_bytes(0x50bb4e7f));470 assert_eq!(498 assert_eq!(471 format!("{:?}", decoder.address().unwrap()),499 format!("{:?}", decoder.address().unwrap()),472 "0xad2c0954693c2b5404b7e50967d3481bea432374"500 "0xad2c0954693c2b5404b7e50967d3481bea432374"505 "533 "506 ))534 ))507 .unwrap();535 .unwrap();508 assert_eq!(call, 0x36543006);536 assert_eq!(call, u32::to_be_bytes(0x36543006));509 let _ = decoder.address().unwrap();537 let _ = decoder.address().unwrap();510 let data =538 let data =511 <AbiReader<'_> as AbiRead<Vec<(uint256, string)>>>::abi_read(&mut decoder).unwrap();539 <AbiReader<'_> as AbiRead<Vec<(uint256, string)>>>::abi_read(&mut decoder).unwrap();crates/evm-coder/src/lib.rsdiffbeforeafterboth44 pub type uint128 = u128;44 pub type uint128 = u128;45 pub type uint256 = U256;45 pub type uint256 = U256;464647 pub type bytes4 = u32;47 pub type bytes4 = [u8; 4];484849 pub type topic = H256;49 pub type topic = H256;505071}71}727273pub trait Call: Sized {73pub trait Call: Sized {74 fn parse(selector: u32, input: &mut AbiReader) -> execution::Result<Option<Self>>;74 fn parse(selector: types::bytes4, input: &mut AbiReader) -> execution::Result<Option<Self>>;75}75}767677pub type Weight = u64;77pub type Weight = u64;93}93}949495impl ERC165Call {95impl ERC165Call {96 pub const INTERFACE_ID: types::bytes4 = 0x01ffc9a7;96 pub const INTERFACE_ID: types::bytes4 = u32::to_be_bytes(0x01ffc9a7);97}97}989899impl Call for ERC165Call {99impl Call for ERC165Call {100 fn parse(selector: u32, input: &mut AbiReader) -> execution::Result<Option<Self>> {100 fn parse(selector: types::bytes4, input: &mut AbiReader) -> execution::Result<Option<Self>> {101 if selector != Self::INTERFACE_ID {101 if selector != Self::INTERFACE_ID {102 return Ok(None);102 return Ok(None);103 }103 }crates/evm-coder/src/solidity.rsdiffbeforeafterboth103 uint64 => "uint64" true = "0",103 uint64 => "uint64" true = "0",104 uint128 => "uint128" true = "0",104 uint128 => "uint128" true = "0",105 uint256 => "uint256" true = "0",105 uint256 => "uint256" true = "0",106 bytes4 => "bytes4" true = "bytes4(0)",106 address => "address" true = "0x0000000000000000000000000000000000000000",107 address => "address" true = "0x0000000000000000000000000000000000000000",107 string => "string" false = "\"\"",108 string => "string" false = "\"\"",108 bytes => "bytes" false = "hex\"\"",109 bytes => "bytes" false = "hex\"\"",473}474}474475475pub struct SolidityInterface<F: SolidityFunctions> {476pub struct SolidityInterface<F: SolidityFunctions> {476 pub selector: u32,477 pub selector: bytes4,477 pub name: &'static str,478 pub name: &'static str,478 pub is: &'static [&'static str],479 pub is: &'static [&'static str],479 pub functions: F,480 pub functions: F,486 out: &mut impl fmt::Write,487 out: &mut impl fmt::Write,487 tc: &TypeCollector,488 tc: &TypeCollector,488 ) -> fmt::Result {489 ) -> fmt::Result {490 const ZERO_BYTES: [u8; 4] = [0; 4];489 if self.selector != 0 {491 if self.selector != ZERO_BYTES {490 writeln!(out, "// Selector: {:0>8x}", self.selector)?;492 writeln!(493 out,494 "// Selector: {:0>8x}",495 u32::from_be_bytes(self.selector)496 )?;491 }497 }492 if is_impl {498 if is_impl {tests/src/eth/base.test.tsdiffbeforeafterboth14// You should have received a copy of the GNU General Public License14// You should have received a copy of the GNU General Public License15// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.15// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.161617import {collectionIdToAddress, createEthAccount, createEthAccountWithBalance, deployFlipper, ethBalanceViaSub, GAS_ARGS, itWeb3, recordEthFee} from './util/helpers';17import {collectionIdToAddress, createEthAccount, createEthAccountWithBalance, deployFlipper, ethBalanceViaSub, GAS_ARGS, itWeb3, recordEthFee, usingWeb3} from './util/helpers';18import {expect} from 'chai';18import {expect} from 'chai';19import {createCollectionExpectSuccess, createItemExpectSuccess, UNIQUE} from '../util/helpers';19import {createCollectionExpectSuccess, createItemExpectSuccess, UNIQUE} from '../util/helpers';20import nonFungibleAbi from './nonFungibleAbi.json';20import nonFungibleAbi from './nonFungibleAbi.json';21import privateKey from '../substrate/privateKey';21import privateKey from '../substrate/privateKey';22import {Contract} from 'web3-eth-contract';23import Web3 from 'web3';222423describe('Contract calls', () => {25describe('Contract calls', () => {24 itWeb3('Call of simple contract fee is less than 0.2 UNQ', async ({web3, api}) => {26 itWeb3('Call of simple contract fee is less than 0.2 UNQ', async ({web3, api}) => {61 });63 });62});64});6566describe('ERC165 tests', async () => {67 // https://eips.ethereum.org/EIPS/eip-1656869 let collection: number;70 let minter: string;7172 function contract(web3: Web3): Contract {73 return new web3.eth.Contract(nonFungibleAbi as any, collectionIdToAddress(collection), {from: minter, ...GAS_ARGS});74 }7576 before(async () => {77 await usingWeb3 (async (web3) => {78 collection = await createCollectionExpectSuccess();79 minter = createEthAccount(web3);80 });81 });82 83 itWeb3('interfaceID == 0xffffffff always false', async ({web3}) => {84 expect(await contract(web3).methods.supportsInterface('0xffffffff').call()).to.be.false;85 });8687 itWeb3('ERC721 support', async ({web3}) => {88 expect(await contract(web3).methods.supportsInterface('0x58800161').call()).to.be.true;89 });9091 itWeb3('ERC721Metadata support', async ({web3}) => {92 expect(await contract(web3).methods.supportsInterface('0x5b5e139f').call()).to.be.true;93 });9495 itWeb3('ERC721Mintable support', async ({web3}) => {96 expect(await contract(web3).methods.supportsInterface('0x68ccfe89').call()).to.be.true;97 });9899 itWeb3('ERC721Enumerable support', async ({web3}) => {100 expect(await contract(web3).methods.supportsInterface('0x780e9d63').call()).to.be.true;101 });102103 itWeb3('ERC721UniqueExtensions support', async ({web3}) => {104 expect(await contract(web3).methods.supportsInterface('0xe562194d').call()).to.be.true;105 });106107 itWeb3('ERC721Burnable support', async ({web3}) => {108 expect(await contract(web3).methods.supportsInterface('0x42966c68').call()).to.be.true;109 });110111 itWeb3('ERC165 support', async ({web3}) => {112 expect(await contract(web3).methods.supportsInterface('0x01ffc9a7').call()).to.be.true;113 });114});63115tests/src/eth/nonFungibleAbi.jsondiffbeforeafterboth466 {466 {467 "inputs": [467 "inputs": [468 {468 {469 "internalType": "uint32",469 "internalType": "bytes4",470 "name": "interfaceId",470 "name": "interfaceId",471 "type": "uint32"471 "type": "bytes4"472 }472 }473 ],473 ],474 "name": "supportsInterface",474 "name": "supportsInterface",