difftreelog
CORE-317 Fix ERC165 support interface
in: master
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>(buf: &[u8], offset: usize, pad_start: usize, pad_size: usize, block_start: usize, block_size: usize) -> Result<[u8; S]> {67 if self.buf.len() - self.offset < ABI_ALIGNMENT {67 if buf.len() - offset < ABI_ALIGNMENT {68 return Err(Error::Error(ExitError::OutOfOffset));68 return Err(Error::Error(ExitError::OutOfOffset));69 }69 }70 let mut block = [0; S];70 let mut block = [0; S];71 // Verify padding is empty71 // Verify padding is empty72 if !self.buf[self.offset..self.offset + ABI_ALIGNMENT - S]72 if !buf[pad_start..pad_size]73 .iter()73 .iter()74 .all(|&v| v == 0)74 .all(|&v| v == 0)75 {75 {76 return Err(Error::Error(ExitError::InvalidRange));76 return Err(Error::Error(ExitError::InvalidRange));77 }77 }78 block.copy_from_slice(78 block.copy_from_slice(79 &self.buf[self.offset + ABI_ALIGNMENT - S..self.offset + ABI_ALIGNMENT],79 &buf[block_start..block_size],80 );80 );81 self.offset += ABI_ALIGNMENT;82 Ok(block)81 Ok(block)83 }82 }848384 fn read_padleft<const S: usize>(&mut self) -> Result<[u8; S]> {85 let offset = self.offset;86 self.offset += ABI_ALIGNMENT;87 Self::read_pad(88 self.buf,89 offset,90 offset, 91 offset + ABI_ALIGNMENT - S,92 offset + ABI_ALIGNMENT - S,93 offset + ABI_ALIGNMENT94 )95 }9697 fn read_padright<const S: usize>(&mut self) -> Result<[u8; S]> {98 let offset = self.offset;99 self.offset += ABI_ALIGNMENT;100 Self::read_pad(101 self.buf,102 offset,103 offset + S, 104 offset + ABI_ALIGNMENT,105 offset,106 offset + S107 )108 }109 85 pub fn address(&mut self) -> Result<H160> {110 pub fn address(&mut self) -> Result<H160> {86 Ok(H160(self.read_padleft()?))111 Ok(H160(self.read_padleft()?))96 }121 }9712298 pub fn bytes4(&mut self) -> Result<[u8; 4]> {123 pub fn bytes4(&mut self) -> Result<[u8; 4]> {99 self.read_padleft()124 self.read_padright()100 }125 }101126102 pub fn bytes(&mut self) -> Result<Vec<u8>> {127 pub fn bytes(&mut self) -> Result<Vec<u8>> {268impl_abi_readable!(u64, uint64);293impl_abi_readable!(u64, uint64);269impl_abi_readable!(u128, uint128);294impl_abi_readable!(u128, uint128);270impl_abi_readable!(U256, uint256);295impl_abi_readable!(U256, uint256);296impl_abi_readable!([u8; 4], bytes4);271impl_abi_readable!(H160, address);297impl_abi_readable!(H160, address);272impl_abi_readable!(Vec<u8>, bytes);298impl_abi_readable!(Vec<u8>, bytes);273impl_abi_readable!(bool, bool);299impl_abi_readable!(bool, bool);466 "492 "467 ))493 ))468 .unwrap();494 .unwrap();469 assert_eq!(call, 0x50bb4e7f);495 assert_eq!(call, u32::to_be_bytes(0x50bb4e7f));470 assert_eq!(496 assert_eq!(471 format!("{:?}", decoder.address().unwrap()),497 format!("{:?}", decoder.address().unwrap()),472 "0xad2c0954693c2b5404b7e50967d3481bea432374"498 "0xad2c0954693c2b5404b7e50967d3481bea432374"505 "531 "506 ))532 ))507 .unwrap();533 .unwrap();508 assert_eq!(call, 0x36543006);534 assert_eq!(call, u32::to_be_bytes(0x36543006));509 let _ = decoder.address().unwrap();535 let _ = decoder.address().unwrap();510 let data =536 let data =511 <AbiReader<'_> as AbiRead<Vec<(uint256, string)>>>::abi_read(&mut decoder).unwrap();537 <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!(out, "// Selector: {:0>8x}", u32::from_be_bytes(self.selector))?;491 }493 }492 if is_impl {494 if is_impl {493 write!(out, "contract ")?;495 write!(out, "contract ")?;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}) => {60 });62 });61});63});6465describe('ERC165 tests', async () => {66 // https://eips.ethereum.org/EIPS/eip-1656768 let collection: number;69 let minter: string;7071 function contract(web3: Web3): Contract {72 return new web3.eth.Contract(nonFungibleAbi as any, collectionIdToAddress(collection), {from: minter, ...GAS_ARGS});73 }7475 before(async () => {76 await usingWeb3 (async (web3) => {77 collection = await createCollectionExpectSuccess();78 minter = createEthAccount(web3);79 });80 });81 82 itWeb3('interfaceID == 0xffffffff always false', async ({web3}) => {83 expect(await contract(web3).methods.supportsInterface('0xffffffff').call()).to.be.false;84 });8586 itWeb3('ERC721 support', async ({web3}) => {87 expect(await contract(web3).methods.supportsInterface('0x58800161').call()).to.be.true;88 });8990 itWeb3('ERC721Metadata support', async ({web3}) => {91 expect(await contract(web3).methods.supportsInterface('0x5b5e139f').call()).to.be.true;92 });9394 itWeb3('ERC721Mintable support', async ({web3}) => {95 expect(await contract(web3).methods.supportsInterface('0x68ccfe89').call()).to.be.true;96 });9798 itWeb3('ERC721Enumerable support', async ({web3}) => {99 expect(await contract(web3).methods.supportsInterface('0x780e9d63').call()).to.be.true;100 });101102 itWeb3('ERC721UniqueExtensions support', async ({web3}) => {103 expect(await contract(web3).methods.supportsInterface('0xe562194d').call()).to.be.true;104 });105106 itWeb3('ERC721Burnable support', async ({web3}) => {107 expect(await contract(web3).methods.supportsInterface('0x42966c68').call()).to.be.true;108 });109110 itWeb3('ERC165 support', async ({web3}) => {111 expect(await contract(web3).methods.supportsInterface('0x01ffc9a7').call()).to.be.true;112 });113});62114tests/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",