git.delta.rocks / unique-network / refs/commits / 0902e70cd1b8

difftreelog

CORE-317 Fix ERC165 support interface

Trubnikov Sergey2022-04-11parent: #219f5f0.patch.diff
in: master

7 files changed

modifiedcrates/evm-coder-macros/src/solidity_interface.rsdiffbeforeafterboth
57 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 }
6363
540540
541 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 }
550550
551 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 }
557557
831 #(831 #(
832 #consts832 #consts
833 )*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(
modifiedcrates/evm-coder-macros/src/to_log.rsdiffbeforeafterboth
199 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: (#(
modifiedcrates/evm-coder/src/abi.rsdiffbeforeafterboth
2626
27use 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;
3232
46 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]);
5555
56 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 }
6565
66 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 empty
72 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 }
8483
84 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_ALIGNMENT
94 )
95 }
96
97 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 + S
107 )
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 }
97122
98 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 }
101126
102 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();
modifiedcrates/evm-coder/src/lib.rsdiffbeforeafterboth
44 pub type uint128 = u128;44 pub type uint128 = u128;
45 pub type uint256 = U256;45 pub type uint256 = U256;
4646
47 pub type bytes4 = u32;47 pub type bytes4 = [u8; 4];
4848
49 pub type topic = H256;49 pub type topic = H256;
5050
71}71}
7272
73pub 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}
7676
77pub type Weight = u64;77pub type Weight = u64;
93}93}
9494
95impl 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}
9898
99impl 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 }
modifiedcrates/evm-coder/src/solidity.rsdiffbeforeafterboth
103 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}
474475
475pub 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 ")?;
modifiedtests/src/eth/base.test.tsdiffbeforeafterboth
14// You should have received a copy of the GNU General Public License14// You should have received a copy of the GNU General Public License
15// 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/>.
1616
17import {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';
2224
23describe('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});
64
65describe('ERC165 tests', async () => {
66 // https://eips.ethereum.org/EIPS/eip-165
67
68 let collection: number;
69 let minter: string;
70
71 function contract(web3: Web3): Contract {
72 return new web3.eth.Contract(nonFungibleAbi as any, collectionIdToAddress(collection), {from: minter, ...GAS_ARGS});
73 }
74
75 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 });
85
86 itWeb3('ERC721 support', async ({web3}) => {
87 expect(await contract(web3).methods.supportsInterface('0x58800161').call()).to.be.true;
88 });
89
90 itWeb3('ERC721Metadata support', async ({web3}) => {
91 expect(await contract(web3).methods.supportsInterface('0x5b5e139f').call()).to.be.true;
92 });
93
94 itWeb3('ERC721Mintable support', async ({web3}) => {
95 expect(await contract(web3).methods.supportsInterface('0x68ccfe89').call()).to.be.true;
96 });
97
98 itWeb3('ERC721Enumerable support', async ({web3}) => {
99 expect(await contract(web3).methods.supportsInterface('0x780e9d63').call()).to.be.true;
100 });
101
102 itWeb3('ERC721UniqueExtensions support', async ({web3}) => {
103 expect(await contract(web3).methods.supportsInterface('0xe562194d').call()).to.be.true;
104 });
105
106 itWeb3('ERC721Burnable support', async ({web3}) => {
107 expect(await contract(web3).methods.supportsInterface('0x42966c68').call()).to.be.true;
108 });
109
110 itWeb3('ERC165 support', async ({web3}) => {
111 expect(await contract(web3).methods.supportsInterface('0x01ffc9a7').call()).to.be.true;
112 });
113});
62114
modifiedtests/src/eth/nonFungibleAbi.jsondiffbeforeafterboth
466 {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",