--- a/pallets/nonfungible/src/erc.rs +++ b/pallets/nonfungible/src/erc.rs @@ -225,10 +225,6 @@ /// @return token's const_metadata #[solidity(rename_selector = "tokenURI")] fn token_uri(&self, token_id: uint256) -> Result { - if !self.supports_metadata() { - return Ok("".into()); - } - let token_id_u32: u32 = token_id.try_into().map_err(|_| "token id overflow")?; match get_token_property(self, token_id_u32, &key::url()).as_deref() { @@ -714,13 +710,17 @@ impl NonfungibleHandle { pub fn supports_metadata(&self) -> bool { - if let Some(erc721_metadata) = + let has_metadata_support_enabled = if let Some(erc721_metadata) = pallet_common::Pallet::::get_collection_property(self.id, &key::erc721_metadata()) { *erc721_metadata.into_inner() == *value::ERC721_METADATA_SUPPORTED } else { false - } + }; + + let has_url_property_permissions = get_token_permission::(self.id, &key::url()).is_ok(); + + has_metadata_support_enabled && has_url_property_permissions } } --- a/pallets/nonfungible/src/lib.rs +++ b/pallets/nonfungible/src/lib.rs @@ -108,7 +108,6 @@ use pallet_evm::{account::CrossAccountId, Pallet as PalletEvm}; use pallet_common::{ Error as CommonError, Pallet as PalletCommon, Event as CommonEvent, CollectionHandle, - erc::static_property::{key, value}, eth::collection_id_to_address, }; use pallet_structure::{Pallet as PalletStructure, Error as StructureError}; --- a/pallets/refungible/src/erc.rs +++ b/pallets/refungible/src/erc.rs @@ -218,10 +218,6 @@ /// @return token's const_metadata #[solidity(rename_selector = "tokenURI")] fn token_uri(&self, token_id: uint256) -> Result { - if !self.supports_metadata() { - return Ok("".into()); - } - let token_id_u32: u32 = token_id.try_into().map_err(|_| "token id overflow")?; match get_token_property(self, token_id_u32, &key::url()).as_deref() { @@ -770,13 +766,17 @@ impl RefungibleHandle { pub fn supports_metadata(&self) -> bool { - if let Some(erc721_metadata) = + let has_metadata_support_enabled = if let Some(erc721_metadata) = pallet_common::Pallet::::get_collection_property(self.id, &key::erc721_metadata()) { *erc721_metadata.into_inner() == *value::ERC721_METADATA_SUPPORTED } else { false - } + }; + + let has_url_property_permissions = get_token_permission::(self.id, &key::url()).is_ok(); + + has_metadata_support_enabled && has_url_property_permissions } } --- a/pallets/refungible/src/lib.rs +++ b/pallets/refungible/src/lib.rs @@ -101,10 +101,7 @@ use pallet_evm::{account::CrossAccountId, Pallet as PalletEvm}; use pallet_evm_coder_substrate::WithRecorder; use pallet_common::{ - CommonCollectionOperations, - erc::static_property::{key, value}, - Error as CommonError, - eth::collection_id_to_address, + CommonCollectionOperations, Error as CommonError, eth::collection_id_to_address, Event as CommonEvent, Pallet as PalletCommon, }; use pallet_structure::Pallet as PalletStructure; --- a/tests/src/eth/base.test.ts +++ b/tests/src/eth/base.test.ts @@ -80,7 +80,23 @@ await usingEthPlaygrounds(async (helper, privateKey) => { const donor = privateKey('//Alice'); const [alice] = await helper.arrange.createAccounts([10n], donor); - ({collectionId: collection} = await helper.nft.mintCollection(alice, {name: 'test', description: 'test', tokenPrefix: 'test', properties: [{key: 'ERC721Metadata', value: '1'}]})); + ({collectionId: collection} = await helper.nft.mintCollection( + alice, + { + name: 'test', + description: 'test', + tokenPrefix: 'test', + properties: [{key: 'ERC721Metadata', value: '1'}], + tokenPropertyPermissions: [{ + key: 'URI', + permission: { + mutable: true, + collectionAdmin: true, + tokenOwner: false, + }, + }], + }, + )); minter = helper.eth.createAccount(); }); }); --- a/tests/src/eth/collectionProperties.test.ts +++ b/tests/src/eth/collectionProperties.test.ts @@ -67,7 +67,15 @@ itEth('ERC721Metadata property can be set for NFT collection', async({helper}) => { const caller = await helper.eth.createAccountWithBalance(donor); - const collection = await helper.nft.mintCollection(donor, {name: 'col', description: 'descr', tokenPrefix: 'COL'}); + const tokenPropertyPermissions = [{ + key: 'URI', + permission: { + mutable: true, + collectionAdmin: true, + tokenOwner: false, + }, + }]; + const collection = await helper.nft.mintCollection(donor, {name: 'col', description: 'descr', tokenPrefix: 'COL', tokenPropertyPermissions}); await collection.addAdmin(donor, {Ethereum: caller}); const contract = helper.ethNativeContract.collectionById(collection.collectionId, 'nft', caller); @@ -83,7 +91,15 @@ itEth.ifWithPallets('ERC721Metadata property can be set for RFT collection', [Pallets.ReFungible], async({helper}) => { const caller = await helper.eth.createAccountWithBalance(donor); - const collection = await helper.rft.mintCollection(donor, {name: 'col', description: 'descr', tokenPrefix: 'COL'}); + const tokenPropertyPermissions = [{ + key: 'URI', + permission: { + mutable: true, + collectionAdmin: true, + tokenOwner: false, + }, + }]; + const collection = await helper.rft.mintCollection(donor, {name: 'col', description: 'descr', tokenPrefix: 'COL', tokenPropertyPermissions}); await collection.addAdmin(donor, {Ethereum: caller}); --- a/tests/src/eth/nonFungible.test.ts +++ b/tests/src/eth/nonFungible.test.ts @@ -501,7 +501,23 @@ itEth('Returns collection name', async ({helper}) => { const caller = await helper.eth.createAccountWithBalance(donor); - const collection = await helper.nft.mintCollection(alice, {name: 'oh River', tokenPrefix: 'CHANGE', properties: [{key: 'ERC721Metadata', value: '1'}]}); + const tokenPropertyPermissions = [{ + key: 'URI', + permission: { + mutable: true, + collectionAdmin: true, + tokenOwner: false, + }, + }]; + const collection = await helper.nft.mintCollection( + alice, + { + name: 'oh River', + tokenPrefix: 'CHANGE', + properties: [{key: 'ERC721Metadata', value: '1'}], + tokenPropertyPermissions, + }, + ); const contract = helper.ethNativeContract.collectionById(collection.collectionId, 'nft', caller); const name = await contract.methods.name().call(); @@ -510,7 +526,23 @@ itEth('Returns symbol name', async ({helper}) => { const caller = await helper.eth.createAccountWithBalance(donor); - const collection = await helper.nft.mintCollection(alice, {name: 'oh River', tokenPrefix: 'CHANGE', properties: [{key: 'ERC721Metadata', value: '1'}]}); + const tokenPropertyPermissions = [{ + key: 'URI', + permission: { + mutable: true, + collectionAdmin: true, + tokenOwner: false, + }, + }]; + const collection = await helper.nft.mintCollection( + alice, + { + name: 'oh River', + tokenPrefix: 'CHANGE', + properties: [{key: 'ERC721Metadata', value: '1'}], + tokenPropertyPermissions, + }, + ); const contract = helper.ethNativeContract.collectionById(collection.collectionId, 'nft', caller); const symbol = await contract.methods.symbol().call(); --- a/tests/src/eth/reFungible.test.ts +++ b/tests/src/eth/reFungible.test.ts @@ -377,7 +377,23 @@ itEth('Returns collection name', async ({helper}) => { const caller = helper.eth.createAccount(); - const collection = await helper.rft.mintCollection(alice, {name: 'Leviathan', tokenPrefix: '11', properties: [{key: 'ERC721Metadata', value: '1'}]}); + const tokenPropertyPermissions = [{ + key: 'URI', + permission: { + mutable: true, + collectionAdmin: true, + tokenOwner: false, + }, + }]; + const collection = await helper.rft.mintCollection( + alice, + { + name: 'Leviathan', + tokenPrefix: '11', + properties: [{key: 'ERC721Metadata', value: '1'}], + tokenPropertyPermissions, + }, + ); const contract = helper.ethNativeContract.collectionById(collection.collectionId, 'rft', caller); const name = await contract.methods.name().call(); @@ -386,7 +402,24 @@ itEth('Returns symbol name', async ({helper}) => { const caller = await helper.eth.createAccountWithBalance(donor); - const {collectionId} = await helper.rft.mintCollection(alice, {name: 'Leviathan', tokenPrefix: '12', properties: [{key: 'ERC721Metadata', value: '1'}]}); + const tokenPropertyPermissions = [{ + key: 'URI', + permission: { + mutable: true, + collectionAdmin: true, + tokenOwner: false, + }, + }]; + const {collectionId} = await helper.rft.mintCollection( + alice, + { + name: 'Leviathan', + tokenPrefix: '12', + properties: [{key: 'ERC721Metadata', value: '1'}], + tokenPropertyPermissions, + }, + ); + const contract = helper.ethNativeContract.collectionById(collectionId, 'rft', caller); const symbol = await contract.methods.symbol().call(); expect(symbol).to.equal('12'); --- a/tests/src/eth/util/playgrounds/unique.dev.ts +++ b/tests/src/eth/util/playgrounds/unique.dev.ts @@ -213,7 +213,7 @@ async createERC721MetadataCompatibleRFTCollection(signer: string, name: string, description: string, tokenPrefix: string, baseUri: string): Promise<{collectionId: number, collectionAddress: string}> { const collectionCreationPrice = this.helper.balance.getCollectionCreationPrice(); const collectionHelper = this.helper.ethNativeContract.collectionHelpers(signer); - + const result = await collectionHelper.methods.createERC721MetadataCompatibleRFTCollection(name, description, tokenPrefix, baseUri).send({value: Number(collectionCreationPrice)}); const collectionAddress = this.helper.ethAddress.normalizeAddress(result.events.CollectionCreated.returnValues.collectionId);