From 876ef621bd1e3674dfd64218ba576789929e6885 Mon Sep 17 00:00:00 2001 From: Grigoriy Simonov Date: Tue, 13 Sep 2022 07:05:03 +0000 Subject: [PATCH] feat: add conditional supportInterface for ERC721Metadata --- --- a/pallets/common/src/erc.rs +++ b/pallets/common/src/erc.rs @@ -684,6 +684,11 @@ pub fn parent_nft() -> up_data_structs::PropertyKey { property_key_from_bytes(b"parentNft").expect(EXPECT_CONVERT_ERROR) } + + /// Key "parentNft". + pub fn erc721_metadata() -> up_data_structs::PropertyKey { + property_key_from_bytes(b"ERC721Metadata").expect(EXPECT_CONVERT_ERROR) + } } /// Values. @@ -693,10 +698,21 @@ /// Value "ERC721Metadata". pub const ERC721_METADATA: &[u8] = b"ERC721Metadata"; + /// Value "1" ERC721 metadata supported. + pub const ERC721_METADATA_SUPPORTED: &[u8] = b"1"; + + /// Value "0" ERC721 metadata supported. + pub const ERC721_METADATA_UNSUPPORTED: &[u8] = b"0"; + /// Value for [`ERC721_METADATA`]. pub fn erc721() -> up_data_structs::PropertyValue { property_value_from_bytes(ERC721_METADATA).expect(EXPECT_CONVERT_ERROR) } + + /// Value for [`ERC721_METADATA`]. + pub fn erc721_metadata_supported() -> up_data_structs::PropertyValue { + property_value_from_bytes(ERC721_METADATA_SUPPORTED).expect(EXPECT_CONVERT_ERROR) + } } /// Convert `byte` to [`PropertyKey`]. --- a/pallets/nonfungible/src/erc.rs +++ b/pallets/nonfungible/src/erc.rs @@ -232,7 +232,7 @@ if !url.is_empty() { return Ok(url); } - } else if !is_erc721_metadata_compatible::(self.id) { + } else if !self.supports_metadata() { return Err("tokenURI not set".into()); } @@ -548,17 +548,6 @@ } Err("Property tokenURI not found".into()) -} - -fn is_erc721_metadata_compatible(collection_id: CollectionId) -> bool { - if let Some(shema_name) = - pallet_common::Pallet::::get_collection_property(collection_id, &key::schema_name()) - { - let shema_name = shema_name.into_inner(); - shema_name == property_value::ERC721_METADATA - } else { - false - } } fn get_token_permission( @@ -577,16 +566,6 @@ Ok(a) } -fn has_token_permission(collection_id: CollectionId, key: &PropertyKey) -> bool { - if let Ok(token_property_permissions) = - CollectionPropertyPermissions::::try_get(collection_id) - { - return token_property_permissions.contains_key(key); - } - - false -} - /// @title Unique extensions for ERC721. #[solidity_interface(name = ERC721UniqueExtensions)] impl NonfungibleHandle { @@ -731,7 +710,7 @@ name = UniqueNFT, is( ERC721, - ERC721Metadata, + ERC721Metadata(if(this.supports_metadata())), ERC721Enumerable, ERC721UniqueExtensions, ERC721Mintable, --- a/pallets/nonfungible/src/lib.rs +++ b/pallets/nonfungible/src/lib.rs @@ -108,6 +108,7 @@ 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}; @@ -295,6 +296,19 @@ &mut self.0 } } + +impl NonfungibleHandle { + pub fn supports_metadata(&self) -> bool { + 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 + } + } +} + impl WithRecorder for NonfungibleHandle { fn recorder(&self) -> &SubstrateRecorder { self.0.recorder() --- a/pallets/refungible/src/erc.rs +++ b/pallets/refungible/src/erc.rs @@ -228,7 +228,7 @@ if !url.is_empty() { return Ok(url); } - } else if !is_erc721_metadata_compatible::(self.id) { + } else if !self.supports_metadata() { return Err("tokenURI not set".into()); } @@ -578,17 +578,6 @@ Err("Property tokenURI not found".into()) } -fn is_erc721_metadata_compatible(collection_id: CollectionId) -> bool { - if let Some(shema_name) = - pallet_common::Pallet::::get_collection_property(collection_id, &key::schema_name()) - { - let shema_name = shema_name.into_inner(); - shema_name == property_value::ERC721_METADATA - } else { - false - } -} - fn get_token_permission( collection_id: CollectionId, key: &PropertyKey, @@ -780,7 +769,7 @@ name = UniqueRefungible, is( ERC721, - ERC721Metadata, + ERC721Metadata(if(this.supports_metadata())), ERC721Enumerable, ERC721UniqueExtensions, ERC721Mintable, --- a/pallets/refungible/src/lib.rs +++ b/pallets/refungible/src/lib.rs @@ -92,14 +92,19 @@ use codec::{Encode, Decode, MaxEncodedLen}; use core::ops::Deref; +use derivative::Derivative; use evm_coder::ToLog; use frame_support::{ - BoundedVec, ensure, fail, storage::with_transaction, transactional, pallet_prelude::ConstU32, + BoundedBTreeMap, BoundedVec, ensure, fail, storage::with_transaction, transactional, + pallet_prelude::ConstU32, }; use pallet_evm::{account::CrossAccountId, Pallet as PalletEvm}; use pallet_evm_coder_substrate::WithRecorder; use pallet_common::{ - CommonCollectionOperations, Error as CommonError, eth::collection_id_to_address, + CommonCollectionOperations, + erc::static_property::{key, value}, + Error as CommonError, + eth::collection_id_to_address, Event as CommonEvent, Pallet as PalletCommon, }; use pallet_structure::Pallet as PalletStructure; @@ -113,8 +118,6 @@ MAX_REFUNGIBLE_PIECES, Property, PropertyKey, PropertyKeyPermission, PropertyPermission, PropertyScope, PropertyValue, TokenId, TrySetProperty, }; -use frame_support::BoundedBTreeMap; -use derivative::Derivative; pub use pallet::*; #[cfg(feature = "runtime-benchmarks")] @@ -301,6 +304,18 @@ } } +impl RefungibleHandle { + pub fn supports_metadata(&self) -> bool { + 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 + } + } +} + impl Deref for RefungibleHandle { type Target = pallet_common::CollectionHandle; --- a/pallets/unique/src/eth/mod.rs +++ b/pallets/unique/src/eth/mod.rs @@ -130,6 +130,13 @@ }) .map_err(|e| Error::Revert(format!("{:?}", e)))?; + properties + .try_push(up_data_structs::Property { + key: key::erc721_metadata(), + value: property_value::erc721_metadata_supported(), + }) + .map_err(|e| Error::Revert(format!("{:?}", e)))?; + if !base_uri_value.is_empty() { properties .try_push(up_data_structs::Property { @@ -212,7 +219,8 @@ /// @param tokenPrefix Token prefix to represent the collection tokens in UI and user applications /// @return address Address of the newly created collection #[weight(>::create_collection())] - fn create_nonfungible_collection( + #[solidity(rename_selector = "createNFTCollection")] + fn create_nft_collection( &mut self, caller: caller, value: value, @@ -239,9 +247,26 @@ let address = pallet_common::eth::collection_id_to_address(collection_id); Ok(address) } + /// Create an NFT collection + /// @param name Name of the collection + /// @param description Informative description of the collection + /// @param tokenPrefix Token prefix to represent the collection tokens in UI and user applications + /// @return address Address of the newly created collection + #[weight(>::create_collection())] + #[deprecated(note = "mathod was renamed to `create_nft_collection`, prefer it instead")] + fn create_nonfungible_collection( + &mut self, + caller: caller, + value: value, + name: string, + description: string, + token_prefix: string, + ) -> Result
{ + self.create_nft_collection(caller, value, name, description, token_prefix) + } #[weight(>::create_collection())] - #[solidity(rename_selector = "createERC721MetadataCompatibleCollection")] + #[solidity(rename_selector = "createERC721MetadataNFTCollection")] fn create_nonfungible_collection_with_properties( &mut self, caller: caller, @@ -273,6 +298,27 @@ #[weight(>::create_collection())] #[solidity(rename_selector = "createRFTCollection")] + fn create_rft_collection( + &mut self, + caller: caller, + value: value, + name: string, + description: string, + token_prefix: string, + ) -> Result
{ + create_refungible_collection_internal::( + caller, + value, + name, + description, + token_prefix, + Default::default(), + false, + ) + } + + #[weight(>::create_collection())] + #[deprecated(note = "mathod was renamed to `create_rft_collection`, prefer it instead")] fn create_refungible_collection( &mut self, caller: caller, @@ -293,7 +339,7 @@ } #[weight(>::create_collection())] - #[solidity(rename_selector = "createERC721MetadataCompatibleRFTCollection")] + #[solidity(rename_selector = "createERC721MetadataRFTCollection")] fn create_refungible_collection_with_properties( &mut self, caller: caller, --- a/pallets/unique/src/eth/stubs/CollectionHelpers.sol +++ b/pallets/unique/src/eth/stubs/CollectionHelpers.sol @@ -23,13 +23,33 @@ } /// @title Contract, which allows users to operate with collections -/// @dev the ERC-165 identifier for this interface is 0x5ad4f440 +/// @dev the ERC-165 identifier for this interface is 0xf62c7aa9 contract CollectionHelpers is Dummy, ERC165, CollectionHelpersEvents { /// Create an NFT collection /// @param name Name of the collection /// @param description Informative description of the collection /// @param tokenPrefix Token prefix to represent the collection tokens in UI and user applications /// @return address Address of the newly created collection + /// @dev EVM selector for this function is: 0x844af658, + /// or in textual repr: createNFTCollection(string,string,string) + function createNFTCollection( + string memory name, + string memory description, + string memory tokenPrefix + ) public payable returns (address) { + require(false, stub_error); + name; + description; + tokenPrefix; + dummy = 0; + return 0x0000000000000000000000000000000000000000; + } + + /// Create an NFT collection + /// @param name Name of the collection + /// @param description Informative description of the collection + /// @param tokenPrefix Token prefix to represent the collection tokens in UI and user applications + /// @return address Address of the newly created collection /// @dev EVM selector for this function is: 0xe34a6844, /// or in textual repr: createNonfungibleCollection(string,string,string) function createNonfungibleCollection( @@ -45,9 +65,9 @@ return 0x0000000000000000000000000000000000000000; } - /// @dev EVM selector for this function is: 0xa634a5f9, - /// or in textual repr: createERC721MetadataCompatibleCollection(string,string,string,string) - function createERC721MetadataCompatibleCollection( + /// @dev EVM selector for this function is: 0xd1df968c, + /// or in textual repr: createERC721MetadataNFTCollection(string,string,string,string) + function createERC721MetadataNFTCollection( string memory name, string memory description, string memory tokenPrefix, @@ -77,9 +97,24 @@ return 0x0000000000000000000000000000000000000000; } - /// @dev EVM selector for this function is: 0xa5596388, - /// or in textual repr: createERC721MetadataCompatibleRFTCollection(string,string,string,string) - function createERC721MetadataCompatibleRFTCollection( + /// @dev EVM selector for this function is: 0x44a68ad5, + /// or in textual repr: createRefungibleCollection(string,string,string) + function createRefungibleCollection( + string memory name, + string memory description, + string memory tokenPrefix + ) public payable returns (address) { + require(false, stub_error); + name; + description; + tokenPrefix; + dummy = 0; + return 0x0000000000000000000000000000000000000000; + } + + /// @dev EVM selector for this function is: 0xbea6a299, + /// or in textual repr: createERC721MetadataRFTCollection(string,string,string,string) + function createERC721MetadataRFTCollection( string memory name, string memory description, string memory tokenPrefix, --- a/tests/src/deprecated-helpers/eth/helpers.ts +++ b/tests/src/deprecated-helpers/eth/helpers.ts @@ -150,10 +150,10 @@ } -export async function createNonfungibleCollection(api: ApiPromise, web3: Web3, owner: string) { +export async function createNFTCollection(api: ApiPromise, web3: Web3, owner: string) { const collectionHelper = evmCollectionHelpers(web3, owner); const result = await collectionHelper.methods - .createNonfungibleCollection('A', 'B', 'C') + .createNFTCollection('A', 'B', 'C') .send({value: Number(2n * UNIQUE)}); return await getCollectionAddressFromResult(api, result); } --- a/tests/src/deprecated-helpers/helpers.ts +++ b/tests/src/deprecated-helpers/helpers.ts @@ -433,6 +433,7 @@ mode: {type: 'NFT'}, name: 'name', tokenPrefix: 'prefix', + properties: [{key: 'ERC721Metadata', value: '1'}], }; export async function @@ -441,7 +442,7 @@ sender: IKeyringPair, params: Partial = {}, ): Promise { - const {name, description, mode, tokenPrefix} = {...defaultCreateCollectionParams, ...params}; + const {name, description, mode, tokenPrefix, properties} = {...defaultCreateCollectionParams, ...params}; let modeprm = {}; if (mode.type === 'NFT') { @@ -457,6 +458,7 @@ description: strToUTF16(description), tokenPrefix: strToUTF16(tokenPrefix), mode: modeprm as any, + properties, }); const events = await executeTransaction(api, sender, tx); return getCreateCollectionResult(events); --- a/tests/src/eth/allowlist.test.ts +++ b/tests/src/eth/allowlist.test.ts @@ -78,7 +78,7 @@ const owner = await helper.eth.createAccountWithBalance(donor); const user = helper.eth.createAccount(); - const {collectionAddress} = await helper.eth.createNonfungibleCollection(owner, 'A', 'B', 'C'); + const {collectionAddress} = await helper.eth.createNFTCollection(owner, 'A', 'B', 'C'); const collectionEvm = helper.ethNativeContract.collection(collectionAddress, 'nft', owner); expect(await collectionEvm.methods.allowed(user).call({from: owner})).to.be.false; @@ -94,7 +94,7 @@ // const owner = await helper.eth.createAccountWithBalance(donor); // const user = donor; - // const {collectionAddress, collectionId} = await helper.eth.createNonfungibleCollection(owner, 'A', 'B', 'C'); + // const {collectionAddress, collectionId} = await helper.eth.createNFTCollection(owner, 'A', 'B', 'C'); // const collectionEvm = helper.ethNativeContract.collection(collectionAddress, 'nft', owner); // expect(await helper.collection.allowed(collectionId, {Substrate: user.address})).to.be.false; @@ -110,7 +110,7 @@ const notOwner = await helper.eth.createAccountWithBalance(donor); const user = helper.eth.createAccount(); - const {collectionAddress} = await helper.eth.createNonfungibleCollection(owner, 'A', 'B', 'C'); + const {collectionAddress} = await helper.eth.createNFTCollection(owner, 'A', 'B', 'C'); const collectionEvm = helper.ethNativeContract.collection(collectionAddress, 'nft', owner); expect(await collectionEvm.methods.allowed(user).call({from: owner})).to.be.false; @@ -129,7 +129,7 @@ // const notOwner = await helper.eth.createAccountWithBalance(donor); // const user = donor; - // const {collectionAddress, collectionId} = await helper.eth.createNonfungibleCollection(owner, 'A', 'B', 'C'); + // const {collectionAddress, collectionId} = await helper.eth.createNFTCollection(owner, 'A', 'B', 'C'); // const collectionEvm = helper.ethNativeContract.collection(collectionAddress, 'nft', owner); // expect(await helper.collection.allowed(collectionId, {Substrate: user.address})).to.be.false; --- a/tests/src/eth/api/CollectionHelpers.sol +++ b/tests/src/eth/api/CollectionHelpers.sol @@ -18,13 +18,26 @@ } /// @title Contract, which allows users to operate with collections -/// @dev the ERC-165 identifier for this interface is 0x5ad4f440 +/// @dev the ERC-165 identifier for this interface is 0xf62c7aa9 interface CollectionHelpers is Dummy, ERC165, CollectionHelpersEvents { /// Create an NFT collection /// @param name Name of the collection /// @param description Informative description of the collection /// @param tokenPrefix Token prefix to represent the collection tokens in UI and user applications /// @return address Address of the newly created collection + /// @dev EVM selector for this function is: 0x844af658, + /// or in textual repr: createNFTCollection(string,string,string) + function createNFTCollection( + string memory name, + string memory description, + string memory tokenPrefix + ) external payable returns (address); + + /// Create an NFT collection + /// @param name Name of the collection + /// @param description Informative description of the collection + /// @param tokenPrefix Token prefix to represent the collection tokens in UI and user applications + /// @return address Address of the newly created collection /// @dev EVM selector for this function is: 0xe34a6844, /// or in textual repr: createNonfungibleCollection(string,string,string) function createNonfungibleCollection( @@ -33,9 +46,9 @@ string memory tokenPrefix ) external payable returns (address); - /// @dev EVM selector for this function is: 0xa634a5f9, - /// or in textual repr: createERC721MetadataCompatibleCollection(string,string,string,string) - function createERC721MetadataCompatibleCollection( + /// @dev EVM selector for this function is: 0xd1df968c, + /// or in textual repr: createERC721MetadataNFTCollection(string,string,string,string) + function createERC721MetadataNFTCollection( string memory name, string memory description, string memory tokenPrefix, @@ -50,9 +63,17 @@ string memory tokenPrefix ) external payable returns (address); - /// @dev EVM selector for this function is: 0xa5596388, - /// or in textual repr: createERC721MetadataCompatibleRFTCollection(string,string,string,string) - function createERC721MetadataCompatibleRFTCollection( + /// @dev EVM selector for this function is: 0x44a68ad5, + /// or in textual repr: createRefungibleCollection(string,string,string) + function createRefungibleCollection( + string memory name, + string memory description, + string memory tokenPrefix + ) external payable returns (address); + + /// @dev EVM selector for this function is: 0xbea6a299, + /// or in textual repr: createERC721MetadataRFTCollection(string,string,string,string) + function createERC721MetadataRFTCollection( string memory name, string memory description, string memory tokenPrefix, --- a/tests/src/eth/collectionAdmin.test.ts +++ b/tests/src/eth/collectionAdmin.test.ts @@ -38,7 +38,7 @@ itEth('Add admin by owner', async ({helper}) => { const owner = await helper.eth.createAccountWithBalance(donor); - const {collectionAddress, collectionId} = await helper.eth.createNonfungibleCollection(owner, 'A', 'B', 'C'); + const {collectionAddress, collectionId} = await helper.eth.createNFTCollection(owner, 'A', 'B', 'C'); const collectionEvm = helper.ethNativeContract.collection(collectionAddress, 'nft', owner); const newAdmin = helper.eth.createAccount(); @@ -51,7 +51,7 @@ itEth.skip('Add substrate admin by owner', async ({helper}) => { const owner = await helper.eth.createAccountWithBalance(donor); - const {collectionAddress, collectionId} = await helper.eth.createNonfungibleCollection(owner, 'A', 'B', 'C'); + const {collectionAddress, collectionId} = await helper.eth.createNFTCollection(owner, 'A', 'B', 'C'); const collectionEvm = helper.ethNativeContract.collection(collectionAddress, 'nft', owner); const [newAdmin] = await helper.arrange.createAccounts([10n], donor); @@ -64,7 +64,7 @@ itEth('Verify owner or admin', async ({helper}) => { const owner = await helper.eth.createAccountWithBalance(donor); - const {collectionAddress} = await helper.eth.createNonfungibleCollection(owner, 'A', 'B', 'C'); + const {collectionAddress} = await helper.eth.createNFTCollection(owner, 'A', 'B', 'C'); const newAdmin = helper.eth.createAccount(); const collectionEvm = helper.ethNativeContract.collection(collectionAddress, 'nft', owner); @@ -75,7 +75,7 @@ itEth('(!negative tests!) Add admin by ADMIN is not allowed', async ({helper}) => { const owner = await helper.eth.createAccountWithBalance(donor); - const {collectionAddress, collectionId} = await helper.eth.createNonfungibleCollection(owner, 'A', 'B', 'C'); + const {collectionAddress, collectionId} = await helper.eth.createNFTCollection(owner, 'A', 'B', 'C'); const admin = await helper.eth.createAccountWithBalance(donor); const collectionEvm = helper.ethNativeContract.collection(collectionAddress, 'nft', owner); @@ -93,7 +93,7 @@ itEth('(!negative tests!) Add admin by USER is not allowed', async ({helper}) => { const owner = await helper.eth.createAccountWithBalance(donor); - const {collectionAddress, collectionId} = await helper.eth.createNonfungibleCollection(owner, 'A', 'B', 'C'); + const {collectionAddress, collectionId} = await helper.eth.createNFTCollection(owner, 'A', 'B', 'C'); const notAdmin = await helper.eth.createAccountWithBalance(donor); const collectionEvm = helper.ethNativeContract.collection(collectionAddress, 'nft', owner); @@ -108,7 +108,7 @@ itEth.skip('(!negative tests!) Add substrate admin by ADMIN is not allowed', async ({helper}) => { const owner = await helper.eth.createAccountWithBalance(donor); - const {collectionAddress, collectionId} = await helper.eth.createNonfungibleCollection(owner, 'A', 'B', 'C'); + const {collectionAddress, collectionId} = await helper.eth.createNFTCollection(owner, 'A', 'B', 'C'); const admin = await helper.eth.createAccountWithBalance(donor); const collectionEvm = helper.ethNativeContract.collection(collectionAddress, 'nft', owner); @@ -126,7 +126,7 @@ itEth.skip('(!negative tests!) Add substrate admin by USER is not allowed', async ({helper}) => { const owner = await helper.eth.createAccountWithBalance(donor); - const {collectionAddress, collectionId} = await helper.eth.createNonfungibleCollection(owner, 'A', 'B', 'C'); + const {collectionAddress, collectionId} = await helper.eth.createNFTCollection(owner, 'A', 'B', 'C'); const notAdmin0 = await helper.eth.createAccountWithBalance(donor); const collectionEvm = helper.ethNativeContract.collection(collectionAddress, 'nft', owner); @@ -150,7 +150,7 @@ itEth('Remove admin by owner', async ({helper}) => { const owner = await helper.eth.createAccountWithBalance(donor); - const {collectionAddress, collectionId} = await helper.eth.createNonfungibleCollection(owner, 'A', 'B', 'C'); + const {collectionAddress, collectionId} = await helper.eth.createNFTCollection(owner, 'A', 'B', 'C'); const newAdmin = helper.eth.createAccount(); const collectionEvm = helper.ethNativeContract.collection(collectionAddress, 'nft', owner); @@ -170,7 +170,7 @@ itEth.skip('Remove substrate admin by owner', async ({helper}) => { const owner = await helper.eth.createAccountWithBalance(donor); - const {collectionAddress, collectionId} = await helper.eth.createNonfungibleCollection(owner, 'A', 'B', 'C'); + const {collectionAddress, collectionId} = await helper.eth.createNFTCollection(owner, 'A', 'B', 'C'); const [newAdmin] = await helper.arrange.createAccounts([10n], donor); const collectionEvm = helper.ethNativeContract.collection(collectionAddress, 'nft', owner); @@ -188,7 +188,7 @@ itEth('(!negative tests!) Remove admin by ADMIN is not allowed', async ({helper}) => { const owner = await helper.eth.createAccountWithBalance(donor); - const {collectionAddress, collectionId} = await helper.eth.createNonfungibleCollection(owner, 'A', 'B', 'C'); + const {collectionAddress, collectionId} = await helper.eth.createNFTCollection(owner, 'A', 'B', 'C'); const collectionEvm = helper.ethNativeContract.collection(collectionAddress, 'nft', owner); @@ -210,7 +210,7 @@ itEth('(!negative tests!) Remove admin by USER is not allowed', async ({helper}) => { const owner = await helper.eth.createAccountWithBalance(donor); - const {collectionAddress, collectionId} = await helper.eth.createNonfungibleCollection(owner, 'A', 'B', 'C'); + const {collectionAddress, collectionId} = await helper.eth.createNFTCollection(owner, 'A', 'B', 'C'); const collectionEvm = helper.ethNativeContract.collection(collectionAddress, 'nft', owner); @@ -230,7 +230,7 @@ itEth.skip('(!negative tests!) Remove substrate admin by ADMIN is not allowed', async ({helper}) => { const owner = await helper.eth.createAccountWithBalance(donor); - const {collectionAddress, collectionId} = await helper.eth.createNonfungibleCollection(owner, 'A', 'B', 'C'); + const {collectionAddress, collectionId} = await helper.eth.createNFTCollection(owner, 'A', 'B', 'C'); const [adminSub] = await helper.arrange.createAccounts([10n], donor); const collectionEvm = helper.ethNativeContract.collection(collectionAddress, 'nft', owner); @@ -250,7 +250,7 @@ itEth.skip('(!negative tests!) Remove substrate admin by USER is not allowed', async ({helper}) => { const owner = await helper.eth.createAccountWithBalance(donor); - const {collectionAddress, collectionId} = await helper.eth.createNonfungibleCollection(owner, 'A', 'B', 'C'); + const {collectionAddress, collectionId} = await helper.eth.createNFTCollection(owner, 'A', 'B', 'C'); const [adminSub] = await helper.arrange.createAccounts([10n], donor); const collectionEvm = helper.ethNativeContract.collection(collectionAddress, 'nft', owner); @@ -279,7 +279,7 @@ itEth('Change owner', async ({helper}) => { const owner = await helper.eth.createAccountWithBalance(donor); const newOwner = await helper.eth.createAccountWithBalance(donor); - const {collectionAddress} = await helper.eth.createNonfungibleCollection(owner, 'A', 'B', 'C'); + const {collectionAddress} = await helper.eth.createNFTCollection(owner, 'A', 'B', 'C'); const collectionEvm = helper.ethNativeContract.collection(collectionAddress, 'nft', owner); await collectionEvm.methods.setOwner(newOwner).send(); @@ -291,7 +291,7 @@ itEth('change owner call fee', async ({helper}) => { const owner = await helper.eth.createAccountWithBalance(donor); const newOwner = await helper.eth.createAccountWithBalance(donor); - const {collectionAddress} = await helper.eth.createNonfungibleCollection(owner, 'A', 'B', 'C'); + const {collectionAddress} = await helper.eth.createNFTCollection(owner, 'A', 'B', 'C'); const collectionEvm = helper.ethNativeContract.collection(collectionAddress, 'nft', owner); const cost = await recordEthFee(helper, owner, () => collectionEvm.methods.setOwner(newOwner).send()); expect(cost < BigInt(0.2 * Number(helper.balance.getOneTokenNominal()))); @@ -301,7 +301,7 @@ itEth('(!negative tests!) call setOwner by non owner', async ({helper}) => { const owner = await helper.eth.createAccountWithBalance(donor); const newOwner = await helper.eth.createAccountWithBalance(donor); - const {collectionAddress} = await helper.eth.createNonfungibleCollection(owner, 'A', 'B', 'C'); + const {collectionAddress} = await helper.eth.createNFTCollection(owner, 'A', 'B', 'C'); const collectionEvm = helper.ethNativeContract.collection(collectionAddress, 'nft', owner); await expect(collectionEvm.methods.setOwner(newOwner).send({from: newOwner})).to.be.rejected; @@ -321,7 +321,7 @@ itEth.skip('Change owner', async ({helper}) => { const owner = await helper.eth.createAccountWithBalance(donor); const [newOwner] = await helper.arrange.createAccounts([10n], donor); - const {collectionAddress} = await helper.eth.createNonfungibleCollection(owner, 'A', 'B', 'C'); + const {collectionAddress} = await helper.eth.createNFTCollection(owner, 'A', 'B', 'C'); const collectionEvm = helper.ethNativeContract.collection(collectionAddress, 'nft', owner); expect(await collectionEvm.methods.isOwnerOrAdmin(owner).call()).to.be.true; @@ -336,7 +336,7 @@ itEth.skip('change owner call fee', async ({helper}) => { const owner = await helper.eth.createAccountWithBalance(donor); const [newOwner] = await helper.arrange.createAccounts([10n], donor); - const {collectionAddress} = await helper.eth.createNonfungibleCollection(owner, 'A', 'B', 'C'); + const {collectionAddress} = await helper.eth.createNFTCollection(owner, 'A', 'B', 'C'); const collectionEvm = helper.ethNativeContract.collection(collectionAddress, 'nft', owner); const cost = await recordEthFee(helper, owner, () => collectionEvm.methods.setOwnerSubstrate(newOwner.addressRaw).send()); @@ -348,7 +348,7 @@ const owner = await helper.eth.createAccountWithBalance(donor); const otherReceiver = await helper.eth.createAccountWithBalance(donor); const [newOwner] = await helper.arrange.createAccounts([10n], donor); - const {collectionAddress} = await helper.eth.createNonfungibleCollection(owner, 'A', 'B', 'C'); + const {collectionAddress} = await helper.eth.createNFTCollection(owner, 'A', 'B', 'C'); const collectionEvm = helper.ethNativeContract.collection(collectionAddress, 'nft', owner); await expect(collectionEvm.methods.setOwnerSubstrate(newOwner.addressRaw).send({from: otherReceiver})).to.be.rejected; --- a/tests/src/eth/collectionHelpersAbi.json +++ b/tests/src/eth/collectionHelpersAbi.json @@ -32,7 +32,7 @@ { "internalType": "string", "name": "tokenPrefix", "type": "string" }, { "internalType": "string", "name": "baseUri", "type": "string" } ], - "name": "createERC721MetadataCompatibleCollection", + "name": "createERC721MetadataNFTCollection", "outputs": [{ "internalType": "address", "name": "", "type": "address" }], "stateMutability": "payable", "type": "function" @@ -44,7 +44,18 @@ { "internalType": "string", "name": "tokenPrefix", "type": "string" }, { "internalType": "string", "name": "baseUri", "type": "string" } ], - "name": "createERC721MetadataCompatibleRFTCollection", + "name": "createERC721MetadataRFTCollection", + "outputs": [{ "internalType": "address", "name": "", "type": "address" }], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { "internalType": "string", "name": "name", "type": "string" }, + { "internalType": "string", "name": "description", "type": "string" }, + { "internalType": "string", "name": "tokenPrefix", "type": "string" } + ], + "name": "createNFTCollection", "outputs": [{ "internalType": "address", "name": "", "type": "address" }], "stateMutability": "payable", "type": "function" @@ -73,6 +84,17 @@ }, { "inputs": [ + { "internalType": "string", "name": "name", "type": "string" }, + { "internalType": "string", "name": "description", "type": "string" }, + { "internalType": "string", "name": "tokenPrefix", "type": "string" } + ], + "name": "createRefungibleCollection", + "outputs": [{ "internalType": "address", "name": "", "type": "address" }], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ { "internalType": "address", "name": "collectionAddress", --- a/tests/src/eth/collectionProperties.test.ts +++ b/tests/src/eth/collectionProperties.test.ts @@ -24,7 +24,7 @@ const raw = (await collection.getData())?.raw; - expect(raw.properties[0].value).to.equal('testValue'); + expect(raw.properties[1].value).to.equal('testValue'); }); itEth('Can be deleted', async({helper}) => { @@ -54,3 +54,46 @@ expect(value).to.equal(helper.getWeb3().utils.toHex('testValue')); }); }); + +describe('Supports ERC721Metadata', () => { + let donor: IKeyringPair; + + before(async function() { + await usingEthPlaygrounds(async (_helper, privateKey) => { + donor = privateKey('//Alice'); + }); + }); + + 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'}); + + await collection.addAdmin(donor, {Ethereum: caller}); + const contract = helper.ethNativeContract.collectionById(collection.collectionId, 'nft', caller); + + await contract.methods.setCollectionProperty('ERC721Metadata', Buffer.from('1')).send({from: caller}); + + expect(await contract.methods.supportsInterface('0x5b5e139f').call()).to.be.true; + + await contract.methods.setCollectionProperty('ERC721Metadata', Buffer.from('0')).send({from: caller}); + + expect(await contract.methods.supportsInterface('0x5b5e139f').call()).to.be.false; + }); + + itEth('ERC721Metadata property can be set for RFT collection', async({helper}) => { + const caller = await helper.eth.createAccountWithBalance(donor); + const collection = await helper.rft.mintCollection(donor, {name: 'col', description: 'descr', tokenPrefix: 'COL'}); + + await collection.addAdmin(donor, {Ethereum: caller}); + + const contract = helper.ethNativeContract.collectionById(collection.collectionId, 'nft', caller); + + await contract.methods.setCollectionProperty('ERC721Metadata', Buffer.from('1')).send({from: caller}); + + expect(await contract.methods.supportsInterface('0x5b5e139f').call()).to.be.true; + + await contract.methods.setCollectionProperty('ERC721Metadata', Buffer.from('0')).send({from: caller}); + + expect(await contract.methods.supportsInterface('0x5b5e139f').call()).to.be.false; + }); +}); --- a/tests/src/eth/collectionSponsoring.test.ts +++ b/tests/src/eth/collectionSponsoring.test.ts @@ -54,7 +54,7 @@ // itWeb3('Set substrate sponsor', async ({api, web3, privateKeyWrapper}) => { // const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper); // const collectionHelpers = evmCollectionHelpers(web3, owner); - // let result = await collectionHelpers.methods.createNonfungibleCollection('Sponsor collection', '1', '1').send(); + // let result = await collectionHelpers.methods.createNFTCollection('Sponsor collection', '1', '1').send(); // const {collectionIdAddress, collectionId} = await getCollectionAddressFromResult(api, result); // const sponsor = privateKeyWrapper('//Alice'); // const collectionEvm = evmCollection(web3, owner, collectionIdAddress); @@ -75,7 +75,7 @@ const owner = await helper.eth.createAccountWithBalance(donor); const collectionHelpers = helper.ethNativeContract.collectionHelpers(owner); - let result = await collectionHelpers.methods.createNonfungibleCollection('Sponsor collection', '1', '1').send({value: Number(2n * nominal)}); + let result = await collectionHelpers.methods.createNFTCollection('Sponsor collection', '1', '1').send({value: Number(2n * nominal)}); const collectionIdAddress = helper.ethAddress.normalizeAddress(result.events.CollectionCreated.returnValues.collectionId); const sponsor = await helper.eth.createAccountWithBalance(donor); const collectionEvm = helper.ethNativeContract.collection(collectionIdAddress, 'nft', owner); @@ -97,7 +97,7 @@ const owner = await helper.eth.createAccountWithBalance(donor); const collectionHelpers = helper.ethNativeContract.collectionHelpers(owner); - let result = await collectionHelpers.methods.createNonfungibleCollection('Sponsor collection', '1', '1').send({value: Number(2n * nominal)}); + let result = await collectionHelpers.methods.createERC721MetadataNFTCollection('Sponsor collection', '1', '1', '').send({value: Number(2n * nominal)}); const collectionIdAddress = helper.ethAddress.normalizeAddress(result.events.CollectionCreated.returnValues.collectionId); const collectionId = helper.ethAddress.extractCollectionId(collectionIdAddress); const collection = helper.nft.getCollectionObject(collectionId); @@ -167,7 +167,7 @@ // itWeb3('Sponsoring collection from substrate address via access list', async ({api, web3, privateKeyWrapper}) => { // const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper); // const collectionHelpers = evmCollectionHelpers(web3, owner); - // const result = await collectionHelpers.methods.createNonfungibleCollection('Sponsor collection', '1', '1').send(); + // const result = await collectionHelpers.methods.createERC721MetadataNFTCollection('Sponsor collection', '1', '1', '').send(); // const {collectionIdAddress, collectionId} = await getCollectionAddressFromResult(api, result); // const sponsor = privateKeyWrapper('//Alice'); // const collectionEvm = evmCollection(web3, owner, collectionIdAddress); @@ -223,7 +223,7 @@ const owner = await helper.eth.createAccountWithBalance(donor); const collectionHelpers = helper.ethNativeContract.collectionHelpers(owner); - let result = await collectionHelpers.methods.createNonfungibleCollection('Sponsor collection', '1', '1').send({value: Number(2n * nominal)}); + let result = await collectionHelpers.methods.createERC721MetadataNFTCollection('Sponsor collection', '1', '1', '').send({value: Number(2n * nominal)}); const collectionIdAddress = helper.ethAddress.normalizeAddress(result.events.CollectionCreated.returnValues.collectionId); const collectionId = helper.ethAddress.extractCollectionId(collectionIdAddress); const collection = helper.nft.getCollectionObject(collectionId); --- a/tests/src/eth/createNFTCollection.test.ts +++ b/tests/src/eth/createNFTCollection.test.ts @@ -37,7 +37,7 @@ // todo:playgrounds this might fail when in async environment. const collectionCountBefore = +(await helper.callRpc('api.rpc.unique.collectionStats')).created; - const {collectionId} = await helper.eth.createNonfungibleCollection(owner, name, description, prefix); + const {collectionId} = await helper.eth.createNFTCollection(owner, name, description, prefix); const collectionCountAfter = +(await helper.callRpc('api.rpc.unique.collectionStats')).created; const collection = helper.nft.getCollectionObject(collectionId); @@ -64,7 +64,7 @@ .call()).to.be.false; await collectionHelpers.methods - .createNonfungibleCollection('A', 'A', 'A') + .createNFTCollection('A', 'A', 'A') .send({value: Number(2n * helper.balance.getOneTokenNominal())}); expect(await collectionHelpers.methods @@ -76,7 +76,7 @@ const owner = await helper.eth.createAccountWithBalance(donor); const sponsor = await helper.eth.createAccountWithBalance(donor); const ss58Format = helper.chain.getChainProperties().ss58Format; - const {collectionId, collectionAddress} = await helper.eth.createNonfungibleCollection(owner, 'Sponsor', 'absolutely anything', 'ROC'); + const {collectionId, collectionAddress} = await helper.eth.createNFTCollection(owner, 'Sponsor', 'absolutely anything', 'ROC'); const collection = helper.ethNativeContract.collection(collectionAddress, 'nft', owner); await collection.methods.setCollectionSponsor(sponsor).send(); @@ -95,7 +95,7 @@ itEth('Set limits', async ({helper}) => { const owner = await helper.eth.createAccountWithBalance(donor); - const {collectionId, collectionAddress} = await helper.eth.createNonfungibleCollection(owner, 'Limits', 'absolutely anything', 'FLO'); + const {collectionId, collectionAddress} = await helper.eth.createNFTCollection(owner, 'Limits', 'absolutely anything', 'FLO'); const limits = { accountTokenOwnershipLimit: 1000, sponsoredDataSize: 1024, @@ -138,7 +138,7 @@ .methods.isCollectionExist(collectionAddressForNonexistentCollection).call()) .to.be.false; - const {collectionAddress} = await helper.eth.createNonfungibleCollection(owner, 'Exister', 'absolutely anything', 'EVC'); + const {collectionAddress} = await helper.eth.createNFTCollection(owner, 'Exister', 'absolutely anything', 'EVC'); expect(await helper.ethNativeContract.collectionHelpers(collectionAddress) .methods.isCollectionExist(collectionAddress).call()) .to.be.true; @@ -166,7 +166,7 @@ const tokenPrefix = 'A'; await expect(collectionHelper.methods - .createNonfungibleCollection(collectionName, description, tokenPrefix) + .createNFTCollection(collectionName, description, tokenPrefix) .call({value: Number(2n * nominal)})).to.be.rejectedWith('name is too long. Max length is ' + MAX_NAME_LENGTH); } @@ -176,7 +176,7 @@ const description = 'A'.repeat(MAX_DESCRIPTION_LENGTH + 1); const tokenPrefix = 'A'; await expect(collectionHelper.methods - .createNonfungibleCollection(collectionName, description, tokenPrefix) + .createNFTCollection(collectionName, description, tokenPrefix) .call({value: Number(2n * nominal)})).to.be.rejectedWith('description is too long. Max length is ' + MAX_DESCRIPTION_LENGTH); } { @@ -185,7 +185,7 @@ const description = 'A'; const tokenPrefix = 'A'.repeat(MAX_TOKEN_PREFIX_LENGTH + 1); await expect(collectionHelper.methods - .createNonfungibleCollection(collectionName, description, tokenPrefix) + .createNFTCollection(collectionName, description, tokenPrefix) .call({value: Number(2n * nominal)})).to.be.rejectedWith('token_prefix is too long. Max length is ' + MAX_TOKEN_PREFIX_LENGTH); } }); @@ -194,14 +194,14 @@ const owner = await helper.eth.createAccountWithBalance(donor); const collectionHelper = helper.ethNativeContract.collectionHelpers(owner); await expect(collectionHelper.methods - .createNonfungibleCollection('Peasantry', 'absolutely anything', 'CVE') + .createNFTCollection('Peasantry', 'absolutely anything', 'CVE') .call({value: Number(1n * nominal)})).to.be.rejectedWith('Sent amount not equals to collection creation price (2000000000000000000)'); }); itEth('(!negative test!) Check owner', async ({helper}) => { const owner = await helper.eth.createAccountWithBalance(donor); const malfeasant = helper.eth.createAccount(); - const {collectionAddress} = await helper.eth.createNonfungibleCollection(owner, 'Transgressed', 'absolutely anything', 'COR'); + const {collectionAddress} = await helper.eth.createNFTCollection(owner, 'Transgressed', 'absolutely anything', 'COR'); const malfeasantCollection = helper.ethNativeContract.collection(collectionAddress, 'nft', malfeasant); const EXPECTED_ERROR = 'NoPermission'; { @@ -224,7 +224,7 @@ itEth('(!negative test!) Set limits', async ({helper}) => { const owner = await helper.eth.createAccountWithBalance(donor); - const {collectionAddress} = await helper.eth.createNonfungibleCollection(owner, 'Limits', 'absolutely anything', 'OLF'); + const {collectionAddress} = await helper.eth.createNFTCollection(owner, 'Limits', 'absolutely anything', 'OLF'); const collectionEvm = helper.ethNativeContract.collection(collectionAddress, 'nft', owner); await expect(collectionEvm.methods .setCollectionLimit('badLimit', 'true') --- a/tests/src/eth/createRFTCollection.test.ts +++ b/tests/src/eth/createRFTCollection.test.ts @@ -39,7 +39,7 @@ // todo:playgrounds this might fail when in async environment. const collectionCountBefore = +(await helper.callRpc('api.rpc.unique.collectionStats')).created; - const {collectionId} = await helper.eth.createRefungibleCollection(owner, name, description, prefix); + const {collectionId} = await helper.eth.createRFTCollection(owner, name, description, prefix); const collectionCountAfter = +(await helper.callRpc('api.rpc.unique.collectionStats')).created; const data = (await helper.rft.getData(collectionId))!; @@ -77,7 +77,7 @@ const owner = await helper.eth.createAccountWithBalance(donor); const sponsor = await helper.eth.createAccountWithBalance(donor); const ss58Format = helper.chain.getChainProperties().ss58Format; - const {collectionId, collectionAddress} = await helper.eth.createRefungibleCollection(owner, 'Sponsor', 'absolutely anything', 'ENVY'); + const {collectionId, collectionAddress} = await helper.eth.createRFTCollection(owner, 'Sponsor', 'absolutely anything', 'ENVY'); const collection = helper.ethNativeContract.collection(collectionAddress, 'rft', owner); await collection.methods.setCollectionSponsor(sponsor).send(); @@ -96,7 +96,7 @@ itEth('Set limits', async ({helper}) => { const owner = await helper.eth.createAccountWithBalance(donor); - const {collectionId, collectionAddress} = await helper.eth.createRefungibleCollection(owner, 'Limits', 'absolutely anything', 'INSI'); + const {collectionId, collectionAddress} = await helper.eth.createRFTCollection(owner, 'Limits', 'absolutely anything', 'INSI'); const limits = { accountTokenOwnershipLimit: 1000, sponsoredDataSize: 1024, @@ -139,7 +139,7 @@ .methods.isCollectionExist(collectionAddressForNonexistentCollection).call()) .to.be.false; - const {collectionAddress} = await helper.eth.createRefungibleCollection(owner, 'Exister', 'absolutely anything', 'WIWT'); + const {collectionAddress} = await helper.eth.createRFTCollection(owner, 'Exister', 'absolutely anything', 'WIWT'); expect(await helper.ethNativeContract.collectionHelpers(collectionAddress) .methods.isCollectionExist(collectionAddress).call()) .to.be.true; @@ -202,7 +202,7 @@ itEth('(!negative test!) Check owner', async ({helper}) => { const owner = await helper.eth.createAccountWithBalance(donor); const peasant = helper.eth.createAccount(); - const {collectionAddress} = await helper.eth.createRefungibleCollection(owner, 'Transgressed', 'absolutely anything', 'YVNE'); + const {collectionAddress} = await helper.eth.createRFTCollection(owner, 'Transgressed', 'absolutely anything', 'YVNE'); const peasantCollection = helper.ethNativeContract.collection(collectionAddress, 'rft', peasant); const EXPECTED_ERROR = 'NoPermission'; { @@ -225,7 +225,7 @@ itEth('(!negative test!) Set limits', async ({helper}) => { const owner = await helper.eth.createAccountWithBalance(donor); - const {collectionAddress} = await helper.eth.createRefungibleCollection(owner, 'Limits', 'absolutely anything', 'ISNI'); + const {collectionAddress} = await helper.eth.createRFTCollection(owner, 'Limits', 'absolutely anything', 'ISNI'); const collectionEvm = helper.ethNativeContract.collection(collectionAddress, 'rft', owner); await expect(collectionEvm.methods .setCollectionLimit('badLimit', 'true') --- a/tests/src/eth/evmCoder.test.ts +++ b/tests/src/eth/evmCoder.test.ts @@ -65,7 +65,7 @@ itEth('Call non-existing function', async ({helper}) => { const owner = await helper.eth.createAccountWithBalance(donor); - const collection = await helper.eth.createNonfungibleCollection(owner, 'EVMCODER', '', 'TEST'); + const collection = await helper.eth.createNFTCollection(owner, 'EVMCODER', '', 'TEST'); const contract = await helper.ethContract.deployByCode(owner, 'Test', getContractSource(collection.collectionAddress, '0x1bfed5D614b886b9Ab2eA4CBAc22A96B7EC29c9c')); const testContract = await helper.ethContract.deployByCode(owner, 'Test', getContractSource(collection.collectionAddress, contract.options.address)); { --- a/tests/src/eth/fractionalizer/fractionalizer.test.ts +++ b/tests/src/eth/fractionalizer/fractionalizer.test.ts @@ -62,7 +62,7 @@ const mintRFTToken = async (helper: EthUniqueHelper, owner: string, fractionalizer: Contract, amount: bigint): Promise<{ nftCollectionAddress: string, nftTokenId: number, rftTokenAddress: string }> => { - const nftCollection = await helper.eth.createNonfungibleCollection(owner, 'nft', 'NFT collection', 'NFT'); + const nftCollection = await helper.eth.createNFTCollection(owner, 'nft', 'NFT collection', 'NFT'); const nftContract = helper.ethNativeContract.collection(nftCollection.collectionAddress, 'nft', owner); const nftTokenId = await nftContract.methods.nextTokenId().call(); await nftContract.methods.mint(owner, nftTokenId).send({from: owner}); @@ -92,7 +92,7 @@ itEth('Set RFT collection', async ({helper}) => { const owner = await helper.eth.createAccountWithBalance(donor, 10n); const fractionalizer = await deployContract(helper, owner); - const rftCollection = await helper.eth.createRefungibleCollection(owner, 'rft', 'RFT collection', 'RFT'); + const rftCollection = await helper.eth.createRFTCollection(owner, 'rft', 'RFT collection', 'RFT'); const rftContract = helper.ethNativeContract.collection(rftCollection.collectionAddress, 'rft', owner); await rftContract.methods.addCollectionAdmin(fractionalizer.options.address).send({from: owner}); @@ -121,7 +121,7 @@ itEth('Set Allowlist', async ({helper}) => { const owner = await helper.eth.createAccountWithBalance(donor, 20n); const {contract: fractionalizer} = await initContract(helper, owner); - const nftCollection = await helper.eth.createNonfungibleCollection(owner, 'nft', 'NFT collection', 'NFT'); + const nftCollection = await helper.eth.createNFTCollection(owner, 'nft', 'NFT collection', 'NFT'); const result1 = await fractionalizer.methods.setNftCollectionIsAllowed(nftCollection.collectionAddress, true).send({from: owner}); expect(result1.events).to.be.like({ @@ -146,7 +146,7 @@ itEth('NFT to RFT', async ({helper}) => { const owner = await helper.eth.createAccountWithBalance(donor, 20n); - const nftCollection = await helper.eth.createNonfungibleCollection(owner, 'nft', 'NFT collection', 'NFT'); + const nftCollection = await helper.eth.createNFTCollection(owner, 'nft', 'NFT collection', 'NFT'); const nftContract = helper.ethNativeContract.collection(nftCollection.collectionAddress, 'nft', owner); const nftTokenId = await nftContract.methods.nextTokenId().call(); await nftContract.methods.mint(owner, nftTokenId).send({from: owner}); @@ -231,7 +231,7 @@ itEth('call setRFTCollection twice', async ({helper}) => { const owner = await helper.eth.createAccountWithBalance(donor, 20n); - const rftCollection = await helper.eth.createRefungibleCollection(owner, 'rft', 'RFT collection', 'RFT'); + const rftCollection = await helper.eth.createRFTCollection(owner, 'rft', 'RFT collection', 'RFT'); const refungibleContract = helper.ethNativeContract.collection(rftCollection.collectionAddress, 'rft', owner); const fractionalizer = await deployContract(helper, owner); @@ -244,7 +244,7 @@ itEth('call setRFTCollection with NFT collection', async ({helper}) => { const owner = await helper.eth.createAccountWithBalance(donor, 20n); - const nftCollection = await helper.eth.createNonfungibleCollection(owner, 'nft', 'NFT collection', 'NFT'); + const nftCollection = await helper.eth.createNFTCollection(owner, 'nft', 'NFT collection', 'NFT'); const nftContract = helper.ethNativeContract.collection(nftCollection.collectionAddress, 'nft', owner); const fractionalizer = await deployContract(helper, owner); @@ -257,7 +257,7 @@ itEth('call setRFTCollection while not collection admin', async ({helper}) => { const owner = await helper.eth.createAccountWithBalance(donor, 20n); const fractionalizer = await deployContract(helper, owner); - const rftCollection = await helper.eth.createRefungibleCollection(owner, 'rft', 'RFT collection', 'RFT'); + const rftCollection = await helper.eth.createRFTCollection(owner, 'rft', 'RFT collection', 'RFT'); await expect(fractionalizer.methods.setRFTCollection(rftCollection.collectionAddress).call()) .to.be.rejectedWith(/Fractionalizer contract should be an admin of the collection$/g); @@ -278,7 +278,7 @@ itEth('call nft2rft without setting RFT collection for contract', async ({helper}) => { const owner = await helper.eth.createAccountWithBalance(donor, 20n); - const nftCollection = await helper.eth.createNonfungibleCollection(owner, 'nft', 'NFT collection', 'NFT'); + const nftCollection = await helper.eth.createNFTCollection(owner, 'nft', 'NFT collection', 'NFT'); const nftContract = helper.ethNativeContract.collection(nftCollection.collectionAddress, 'nft', owner); const nftTokenId = await nftContract.methods.nextTokenId().call(); await nftContract.methods.mint(owner, nftTokenId).send({from: owner}); @@ -293,7 +293,7 @@ const owner = await helper.eth.createAccountWithBalance(donor, 20n); const nftOwner = await helper.eth.createAccountWithBalance(donor, 10n); - const nftCollection = await helper.eth.createNonfungibleCollection(owner, 'nft', 'NFT collection', 'NFT'); + const nftCollection = await helper.eth.createNFTCollection(owner, 'nft', 'NFT collection', 'NFT'); const nftContract = helper.ethNativeContract.collection(nftCollection.collectionAddress, 'nft', owner); const nftTokenId = await nftContract.methods.nextTokenId().call(); await nftContract.methods.mint(owner, nftTokenId).send({from: owner}); @@ -310,7 +310,7 @@ itEth('call nft2rft while not in list of allowed accounts', async ({helper}) => { const owner = await helper.eth.createAccountWithBalance(donor, 20n); - const nftCollection = await helper.eth.createNonfungibleCollection(owner, 'nft', 'NFT collection', 'NFT'); + const nftCollection = await helper.eth.createNFTCollection(owner, 'nft', 'NFT collection', 'NFT'); const nftContract = helper.ethNativeContract.collection(nftCollection.collectionAddress, 'nft', owner); const nftTokenId = await nftContract.methods.nextTokenId().call(); await nftContract.methods.mint(owner, nftTokenId).send({from: owner}); @@ -325,7 +325,7 @@ itEth('call nft2rft while fractionalizer doesnt have approval for nft token', async ({helper}) => { const owner = await helper.eth.createAccountWithBalance(donor, 20n); - const nftCollection = await helper.eth.createNonfungibleCollection(owner, 'nft', 'NFT collection', 'NFT'); + const nftCollection = await helper.eth.createNFTCollection(owner, 'nft', 'NFT collection', 'NFT'); const nftContract = helper.ethNativeContract.collection(nftCollection.collectionAddress, 'nft', owner); const nftTokenId = await nftContract.methods.nextTokenId().call(); await nftContract.methods.mint(owner, nftTokenId).send({from: owner}); @@ -341,7 +341,7 @@ const owner = await helper.eth.createAccountWithBalance(donor, 20n); const fractionalizer = await deployContract(helper, owner); - const rftCollection = await helper.eth.createRefungibleCollection(owner, 'rft', 'RFT collection', 'RFT'); + const rftCollection = await helper.eth.createRFTCollection(owner, 'rft', 'RFT collection', 'RFT'); const refungibleContract = helper.ethNativeContract.collection(rftCollection.collectionAddress, 'rft', owner); const rftTokenId = await refungibleContract.methods.nextTokenId().call(); await refungibleContract.methods.mint(owner, rftTokenId).send({from: owner}); @@ -354,7 +354,7 @@ const owner = await helper.eth.createAccountWithBalance(donor, 20n); const {contract: fractionalizer} = await initContract(helper, owner); - const rftCollection = await helper.eth.createRefungibleCollection(owner, 'rft', 'RFT collection', 'RFT'); + const rftCollection = await helper.eth.createRFTCollection(owner, 'rft', 'RFT collection', 'RFT'); const refungibleContract = helper.ethNativeContract.collection(rftCollection.collectionAddress, 'rft', owner); const rftTokenId = await refungibleContract.methods.nextTokenId().call(); await refungibleContract.methods.mint(owner, rftTokenId).send({from: owner}); @@ -365,7 +365,7 @@ itEth('call rft2nft for RFT token that was not minted by fractionalizer contract', async ({helper}) => { const owner = await helper.eth.createAccountWithBalance(donor, 20n); - const rftCollection = await helper.eth.createRefungibleCollection(owner, 'rft', 'RFT collection', 'RFT'); + const rftCollection = await helper.eth.createRFTCollection(owner, 'rft', 'RFT collection', 'RFT'); const refungibleContract = helper.ethNativeContract.collection(rftCollection.collectionAddress, 'rft', owner); const fractionalizer = await deployContract(helper, owner); @@ -432,7 +432,7 @@ await fractionalizer.methods.setRFTCollection(rftCollectionAddress).send({from: owner}); await helper.executeExtrinsic(donor, 'api.tx.unique.setTransfersEnabledFlag', [rftCollection.collectionId, false], true); - const nftCollection = await helper.eth.createNonfungibleCollection(owner, 'nft', 'NFT collection', 'NFT'); + const nftCollection = await helper.eth.createNFTCollection(owner, 'nft', 'NFT collection', 'NFT'); const nftContract = helper.ethNativeContract.collection(nftCollection.collectionAddress, 'nft', owner); const nftTokenId = await nftContract.methods.nextTokenId().call(); await nftContract.methods.mint(owner, nftTokenId).send({from: owner}); --- a/tests/src/eth/nesting/nest.test.ts +++ b/tests/src/eth/nesting/nest.test.ts @@ -7,7 +7,7 @@ helper: EthUniqueHelper, owner: string, ): Promise<{ collectionId: number, collectionAddress: string, contract: Contract }> => { - const {collectionAddress, collectionId} = await helper.eth.createNonfungibleCollection(owner, 'A', 'B', 'C'); + const {collectionAddress, collectionId} = await helper.eth.createNFTCollection(owner, 'A', 'B', 'C'); const contract = helper.ethNativeContract.collection(collectionAddress, 'nft', owner); await contract.methods.setCollectionNesting(true).send({from: owner}); --- a/tests/src/eth/nonFungible.test.ts +++ b/tests/src/eth/nonFungible.test.ts @@ -84,7 +84,7 @@ const receiver = helper.eth.createAccount(); const collectionHelper = helper.ethNativeContract.collectionHelpers(owner); - let result = await collectionHelper.methods.createERC721MetadataCompatibleCollection('Mint collection', 'a', 'b', tokenPrefix).send({value: Number(2n * helper.balance.getOneTokenNominal())}); + let result = await collectionHelper.methods.createERC721MetadataNFTCollection('Mint collection', 'a', 'b', tokenPrefix).send({value: Number(2n * helper.balance.getOneTokenNominal())}); const collectionAddress = helper.ethAddress.normalizeAddress(result.events.CollectionCreated.returnValues.collectionId); const contract = helper.ethNativeContract.collection(collectionAddress, 'nft', owner); @@ -146,7 +146,7 @@ const owner = await helper.eth.createAccountWithBalance(donor); const receiver = helper.eth.createAccount(); - const {collectionAddress} = await helper.eth.createNonfungibleCollection(owner, 'Minty', '6', '6'); + const {collectionAddress} = await helper.eth.createERC721MetadataNFTCollection(owner, 'Mint collection', '6', '6', ''); const contract = helper.ethNativeContract.collection(collectionAddress, 'nft', owner); const nextTokenId = await contract.methods.nextTokenId().call(); --- a/tests/src/eth/payable.test.ts +++ b/tests/src/eth/payable.test.ts @@ -146,7 +146,7 @@ const caller = await helper.eth.createAccountWithBalance(donor); const contract = await deployProxyContract(helper, deployer); - const collectionAddress = (await contract.methods.createNonfungibleCollection().send({from: caller, value: Number(CONTRACT_BALANCE)})).events.CollectionCreated.returnValues.collection; + const collectionAddress = (await contract.methods.createNFTCollection().send({from: caller, value: Number(CONTRACT_BALANCE)})).events.CollectionCreated.returnValues.collection; const initialCallerBalance = await helper.balance.getEthereum(caller); const initialContractBalance = await helper.balance.getEthereum(contract.options.address); await contract.methods.mintNftToken(collectionAddress).send({from: caller}); @@ -164,7 +164,7 @@ const initialCallerBalance = await helper.balance.getEthereum(caller); const initialContractBalance = await helper.balance.getEthereum(contract.options.address); - await contract.methods.createNonfungibleCollection().send({from: caller, value: Number(CONTRACT_BALANCE)}); + await contract.methods.createNFTCollection().send({from: caller, value: Number(CONTRACT_BALANCE)}); const finalCallerBalance = await helper.balance.getEthereum(caller); const finalContractBalance = await helper.balance.getEthereum(contract.options.address); expect(finalCallerBalance < initialCallerBalance).to.be.true; @@ -177,8 +177,8 @@ const caller = await helper.eth.createAccountWithBalance(donor); const collectionHelper = helper.ethNativeContract.collectionHelpers(caller); - await expect(collectionHelper.methods.createNonfungibleCollection('A', 'B', 'C').call({value: Number(SMALL_FEE)})).to.be.rejectedWith('Sent amount not equals to collection creation price (2000000000000000000)'); - await expect(collectionHelper.methods.createNonfungibleCollection('A', 'B', 'C').call({value: Number(BIG_FEE)})).to.be.rejectedWith('Sent amount not equals to collection creation price (2000000000000000000)'); + await expect(collectionHelper.methods.createNFTCollection('A', 'B', 'C').call({value: Number(SMALL_FEE)})).to.be.rejectedWith('Sent amount not equals to collection creation price (2000000000000000000)'); + await expect(collectionHelper.methods.createNFTCollection('A', 'B', 'C').call({value: Number(BIG_FEE)})).to.be.rejectedWith('Sent amount not equals to collection creation price (2000000000000000000)'); }); itEth('Negative test: call createRFTCollection with wrong fee', async({helper}) => { @@ -227,9 +227,9 @@ InnerContract(innerContract).flip(); } - function createNonfungibleCollection() external payable { + function createNFTCollection() external payable { address collectionHelpers = 0x6C4E9fE1AE37a41E93CEE429e8E1881aBdcbb54F; - address nftCollection = CollectionHelpers(collectionHelpers).createNonfungibleCollection{value: msg.value}("A", "B", "C"); + address nftCollection = CollectionHelpers(collectionHelpers).createNFTCollection{value: msg.value}("A", "B", "C"); emit CollectionCreated(nftCollection); } --- a/tests/src/eth/proxy/nonFungibleProxy.test.ts +++ b/tests/src/eth/proxy/nonFungibleProxy.test.ts @@ -101,7 +101,7 @@ itEth('Can perform mint()', async ({helper}) => { const owner = await helper.eth.createAccountWithBalance(donor); - const {collectionAddress} = await helper.eth.createNonfungibleCollection(owner, 'A', 'A', 'A'); + const {collectionAddress} = await helper.eth.createERC721MetadataNFTCollection(owner, 'A', 'A', 'A', ''); const caller = await helper.eth.createAccountWithBalance(donor); const receiver = helper.eth.createAccount(); --- a/tests/src/eth/reFungible.test.ts +++ b/tests/src/eth/reFungible.test.ts @@ -31,7 +31,7 @@ itEth('totalSupply', async ({helper}) => { const caller = await helper.eth.createAccountWithBalance(donor); - const {collectionAddress} = await helper.eth.createRefungibleCollection(caller, 'TotalSupply', '6', '6'); + const {collectionAddress} = await helper.eth.createRFTCollection(caller, 'TotalSupply', '6', '6'); const contract = helper.ethNativeContract.collection(collectionAddress, 'rft', caller); const nextTokenId = await contract.methods.nextTokenId().call(); await contract.methods.mint(caller, nextTokenId).send(); @@ -41,7 +41,7 @@ itEth('balanceOf', async ({helper}) => { const caller = await helper.eth.createAccountWithBalance(donor); - const {collectionAddress} = await helper.eth.createRefungibleCollection(caller, 'BalanceOf', '6', '6'); + const {collectionAddress} = await helper.eth.createRFTCollection(caller, 'BalanceOf', '6', '6'); const contract = helper.ethNativeContract.collection(collectionAddress, 'rft', caller); { @@ -63,7 +63,7 @@ itEth('ownerOf', async ({helper}) => { const caller = await helper.eth.createAccountWithBalance(donor); - const {collectionAddress} = await helper.eth.createRefungibleCollection(caller, 'OwnerOf', '6', '6'); + const {collectionAddress} = await helper.eth.createRFTCollection(caller, 'OwnerOf', '6', '6'); const contract = helper.ethNativeContract.collection(collectionAddress, 'rft', caller); const tokenId = await contract.methods.nextTokenId().call(); @@ -76,7 +76,7 @@ itEth('ownerOf after burn', async ({helper}) => { const caller = await helper.eth.createAccountWithBalance(donor); const receiver = helper.eth.createAccount(); - const {collectionId, collectionAddress} = await helper.eth.createRefungibleCollection(caller, 'OwnerOf-AfterBurn', '6', '6'); + const {collectionId, collectionAddress} = await helper.eth.createRFTCollection(caller, 'OwnerOf-AfterBurn', '6', '6'); const contract = helper.ethNativeContract.collection(collectionAddress, 'rft', caller); const tokenId = await contract.methods.nextTokenId().call(); @@ -95,7 +95,7 @@ itEth('ownerOf for partial ownership', async ({helper}) => { const caller = await helper.eth.createAccountWithBalance(donor); const receiver = helper.eth.createAccount(); - const {collectionId, collectionAddress} = await helper.eth.createRefungibleCollection(caller, 'Partial-OwnerOf', '6', '6'); + const {collectionId, collectionAddress} = await helper.eth.createRFTCollection(caller, 'Partial-OwnerOf', '6', '6'); const contract = helper.ethNativeContract.collection(collectionAddress, 'rft', caller); const tokenId = await contract.methods.nextTokenId().call(); @@ -124,7 +124,7 @@ itEth('Can perform mint()', async ({helper}) => { const owner = await helper.eth.createAccountWithBalance(donor); const receiver = helper.eth.createAccount(); - const {collectionAddress} = await helper.eth.createRefungibleCollection(owner, 'Minty', '6', '6'); + const {collectionAddress} = await helper.eth.createERC721MetadataRFTCollection(owner, 'Minty', '6', '6', ''); const contract = helper.ethNativeContract.collection(collectionAddress, 'rft', owner); const nextTokenId = await contract.methods.nextTokenId().call(); @@ -147,7 +147,7 @@ itEth('Can perform mintBulk()', async ({helper}) => { const owner = await helper.eth.createAccountWithBalance(donor); const receiver = helper.eth.createAccount(); - const {collectionAddress} = await helper.eth.createRefungibleCollection(owner, 'MintBulky', '6', '6'); + const {collectionAddress} = await helper.eth.createERC721MetadataRFTCollection(owner, 'MintBulky', '6', '6', ''); const contract = helper.ethNativeContract.collection(collectionAddress, 'rft', owner); { @@ -179,7 +179,7 @@ itEth('Can perform burn()', async ({helper}) => { const caller = await helper.eth.createAccountWithBalance(donor); - const {collectionAddress} = await helper.eth.createRefungibleCollection(caller, 'Burny', '6', '6'); + const {collectionAddress} = await helper.eth.createRFTCollection(caller, 'Burny', '6', '6'); const contract = helper.ethNativeContract.collection(collectionAddress, 'rft', caller); const tokenId = await contract.methods.nextTokenId().call(); @@ -197,7 +197,7 @@ itEth('Can perform transferFrom()', async ({helper}) => { const caller = await helper.eth.createAccountWithBalance(donor); const receiver = helper.eth.createAccount(); - const {collectionId, collectionAddress} = await helper.eth.createRefungibleCollection(caller, 'TransferFromy', '6', '6'); + const {collectionId, collectionAddress} = await helper.eth.createRFTCollection(caller, 'TransferFromy', '6', '6'); const contract = helper.ethNativeContract.collection(collectionAddress, 'rft', caller); const tokenId = await contract.methods.nextTokenId().call(); @@ -241,7 +241,7 @@ itEth('Can perform transfer()', async ({helper}) => { const caller = await helper.eth.createAccountWithBalance(donor); const receiver = helper.eth.createAccount(); - const {collectionAddress} = await helper.eth.createRefungibleCollection(caller, 'Transferry', '6', '6'); + const {collectionAddress} = await helper.eth.createRFTCollection(caller, 'Transferry', '6', '6'); const contract = helper.ethNativeContract.collection(collectionAddress, 'rft', caller); const tokenId = await contract.methods.nextTokenId().call(); @@ -271,7 +271,7 @@ itEth('transfer event on transfer from partial ownership to full ownership', async ({helper}) => { const caller = await helper.eth.createAccountWithBalance(donor); const receiver = helper.eth.createAccount(); - const {collectionId, collectionAddress} = await helper.eth.createRefungibleCollection(caller, 'Transferry-Partial-to-Full', '6', '6'); + const {collectionId, collectionAddress} = await helper.eth.createRFTCollection(caller, 'Transferry-Partial-to-Full', '6', '6'); const contract = helper.ethNativeContract.collection(collectionAddress, 'rft', caller); const tokenId = await contract.methods.nextTokenId().call(); @@ -298,7 +298,7 @@ itEth('transfer event on transfer from full ownership to partial ownership', async ({helper}) => { const caller = await helper.eth.createAccountWithBalance(donor); const receiver = helper.eth.createAccount(); - const {collectionId, collectionAddress} = await helper.eth.createRefungibleCollection(caller, 'Transferry-Full-to-Partial', '6', '6'); + const {collectionId, collectionAddress} = await helper.eth.createRFTCollection(caller, 'Transferry-Full-to-Partial', '6', '6'); const contract = helper.ethNativeContract.collection(collectionAddress, 'rft', caller); const tokenId = await contract.methods.nextTokenId().call(); @@ -336,7 +336,7 @@ itEth('transferFrom() call fee is less than 0.2UNQ', async ({helper}) => { const caller = await helper.eth.createAccountWithBalance(donor); const receiver = helper.eth.createAccount(); - const {collectionAddress} = await helper.eth.createRefungibleCollection(caller, 'Feeful-Transfer-From', '6', '6'); + const {collectionAddress} = await helper.eth.createRFTCollection(caller, 'Feeful-Transfer-From', '6', '6'); const contract = helper.ethNativeContract.collection(collectionAddress, 'rft', caller); const tokenId = await contract.methods.nextTokenId().call(); @@ -350,7 +350,7 @@ itEth('transfer() call fee is less than 0.2UNQ', async ({helper}) => { const caller = await helper.eth.createAccountWithBalance(donor); const receiver = helper.eth.createAccount(); - const {collectionAddress} = await helper.eth.createRefungibleCollection(caller, 'Feeful-Transfer', '6', '6'); + const {collectionAddress} = await helper.eth.createRFTCollection(caller, 'Feeful-Transfer', '6', '6'); const contract = helper.ethNativeContract.collection(collectionAddress, 'rft', caller); const tokenId = await contract.methods.nextTokenId().call(); @@ -386,8 +386,8 @@ itEth('Returns symbol name', async ({helper}) => { const caller = await helper.eth.createAccountWithBalance(donor); - const {collectionAddress} = await helper.eth.createRefungibleCollection(caller, 'Leviathan', '', '12'); - const contract = helper.ethNativeContract.collection(collectionAddress, 'rft', caller); + const {collectionId} = await helper.rft.mintCollection(alice, {name: 'Leviathan', tokenPrefix: '12'}); + const contract = helper.ethNativeContract.collectionById(collectionId, 'rft', caller); const symbol = await contract.methods.symbol().call(); expect(symbol).to.equal('12'); }); --- a/tests/src/eth/reFungibleToken.test.ts +++ b/tests/src/eth/reFungibleToken.test.ts @@ -81,7 +81,7 @@ const receiver = helper.eth.createAccount(); const collectionHelper = helper.ethNativeContract.collectionHelpers(owner); - let result = await collectionHelper.methods.createERC721MetadataCompatibleCollection('Mint collection', 'a', 'b', tokenPrefix).send({value: Number(2n * helper.balance.getOneTokenNominal())}); + let result = await collectionHelper.methods.createERC721MetadataNFTCollection('Mint collection', 'a', 'b', tokenPrefix).send({value: Number(2n * helper.balance.getOneTokenNominal())}); const collectionAddress = helper.ethAddress.normalizeAddress(result.events.CollectionCreated.returnValues.collectionId); const contract = helper.ethNativeContract.collection(collectionAddress, 'rft', owner); @@ -294,7 +294,7 @@ itEth('Receiving Transfer event on burning into full ownership', async ({helper}) => { const caller = await helper.eth.createAccountWithBalance(donor); const receiver = await helper.eth.createAccountWithBalance(donor); - const {collectionId, collectionAddress} = await helper.eth.createRefungibleCollection(caller, 'Devastation', '6', '6'); + const {collectionId, collectionAddress} = await helper.eth.createRFTCollection(caller, 'Devastation', '6', '6'); const contract = helper.ethNativeContract.collection(collectionAddress, 'rft', caller); const tokenId = await contract.methods.nextTokenId().call(); @@ -479,7 +479,7 @@ itEth('Default parent token address and id', async ({helper}) => { const owner = await helper.eth.createAccountWithBalance(donor); - const {collectionId, collectionAddress} = await helper.eth.createRefungibleCollection(owner, 'Sands', '', 'GRAIN'); + const {collectionId, collectionAddress} = await helper.eth.createRFTCollection(owner, 'Sands', '', 'GRAIN'); const collectionContract = helper.ethNativeContract.collection(collectionAddress, 'rft', owner); const tokenId = await collectionContract.methods.nextTokenId().call(); --- a/tests/src/eth/util/playgrounds/unique.dev.ts +++ b/tests/src/eth/util/playgrounds/unique.dev.ts @@ -174,11 +174,23 @@ return await this.helper.callRpc('api.rpc.eth.call', [{from: signer, to: contractAddress, data: abi}]); } - async createNonfungibleCollection(signer: string, name: string, description: string, tokenPrefix: string): Promise<{collectionId: number, collectionAddress: string}> { + async createNFTCollection(signer: string, name: string, description: string, tokenPrefix: string): Promise<{collectionId: number, collectionAddress: string}> { const collectionCreationPrice = this.helper.balance.getCollectionCreationPrice(); const collectionHelper = this.helper.ethNativeContract.collectionHelpers(signer); - const result = await collectionHelper.methods.createNonfungibleCollection(name, description, tokenPrefix).send({value: Number(collectionCreationPrice)}); + const result = await collectionHelper.methods.createNFTCollection(name, description, tokenPrefix).send({value: Number(collectionCreationPrice)}); + + const collectionAddress = this.helper.ethAddress.normalizeAddress(result.events.CollectionCreated.returnValues.collectionId); + const collectionId = this.helper.ethAddress.extractCollectionId(collectionAddress); + + return {collectionId, collectionAddress}; + } + + async createERC721MetadataNFTCollection(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.createERC721MetadataNFTCollection(name, description, tokenPrefix, baseUri).send({value: Number(collectionCreationPrice)}); const collectionAddress = this.helper.ethAddress.normalizeAddress(result.events.CollectionCreated.returnValues.collectionId); const collectionId = this.helper.ethAddress.extractCollectionId(collectionAddress); @@ -186,7 +198,7 @@ return {collectionId, collectionAddress}; } - async createRefungibleCollection(signer: string, name: string, description: string, tokenPrefix: string): Promise<{collectionId: number, collectionAddress: string}> { + async createRFTCollection(signer: string, name: string, description: string, tokenPrefix: string): Promise<{collectionId: number, collectionAddress: string}> { const collectionCreationPrice = this.helper.balance.getCollectionCreationPrice(); const collectionHelper = this.helper.ethNativeContract.collectionHelpers(signer); @@ -198,6 +210,18 @@ return {collectionId, collectionAddress}; } + async createERC721MetadataRFTCollection(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.createERC721MetadataRFTCollection(name, description, tokenPrefix, baseUri).send({value: Number(collectionCreationPrice)}); + + const collectionAddress = this.helper.ethAddress.normalizeAddress(result.events.CollectionCreated.returnValues.collectionId); + const collectionId = this.helper.ethAddress.extractCollectionId(collectionAddress); + + return {collectionId, collectionAddress}; + } + async deployCollectorContract(signer: string): Promise { return await this.helper.ethContract.deployByCode(signer, 'Collector', ` // SPDX-License-Identifier: UNLICENSED --- a/tests/src/nesting/properties.test.ts +++ b/tests/src/nesting/properties.test.ts @@ -18,6 +18,52 @@ import {itSub, Pallets, requirePalletsOrSkip, usingPlaygrounds, expect} from '../util/playgrounds'; import {UniqueHelper, UniqueBaseCollection, UniqueNFTCollection, UniqueNFToken, UniqueRFTCollection, UniqueRFToken} from '../util/playgrounds/unique'; + +describe('Composite Properties Test', () => { + let alice: IKeyringPair; + + before(async () => { + await usingPlaygrounds(async (helper, privateKey) => { + const donor = privateKey('//Alice'); + [alice] = await helper.arrange.createAccounts([50n], donor); + }); + }); + + async function testMakeSureSuppliesRequired(baseCollection: UniqueNFTCollection | UniqueRFTCollection) { + + const collectionOption = await baseCollection.getOptions(); + expect(collectionOption).is.not.null; + let collection = collectionOption; + expect(collection.tokenPropertyPermissions).to.be.empty; + expect(collection.properties).to.be.deep.equal([{key: 'ERC721Metadata', value: '1'}]); + + const propertyPermissions = [ + {key: 'mindgame', permission: {collectionAdmin: true, mutable: false, tokenOwner: true}}, + {key: 'skullduggery', permission: {collectionAdmin: false, mutable: true, tokenOwner: false}}, + ]; + await expect(await baseCollection.setTokenPropertyPermissions(alice, propertyPermissions)).to.be.true; + + const collectionProperties = [ + {key: 'ERC721Metadata', value: '1'}, + {key: 'black_hole', value: 'LIGO'}, + {key: 'electron', value: 'come bond'}, + ]; + + await expect(await baseCollection.setProperties(alice, collectionProperties)).to.be.true; + + collection = await baseCollection.getOptions(); + expect(collection.tokenPropertyPermissions).to.be.deep.equal(propertyPermissions); + expect(collection.properties).to.be.deep.equal(collectionProperties); + } + + itSub('Makes sure collectionById supplies required fields for NFT', async ({helper}) => { + await testMakeSureSuppliesRequired(await helper.nft.mintCollection(alice, {name: 'A', description: 'B', tokenPrefix: 'C'})); + }); + + itSub.ifWithPallets('Makes sure collectionById supplies required fields for ReFungible', [Pallets.ReFungible], async ({helper}) => { + await testMakeSureSuppliesRequired(await helper.rft.mintCollection(alice, {name: 'A', description: 'B', tokenPrefix: 'C'})); + }); +}); // ---------- COLLECTION PROPERTIES describe('Integration Test: Collection Properties', () => { @@ -33,7 +79,11 @@ itSub('Properties are initially empty', async ({helper}) => { const collection = await helper.nft.mintCollection(alice); - expect(await collection.getProperties()).to.be.empty; + const properties = await collection.getProperties(); + expect(properties).to.be.deep.equal([{ + 'key': 'ERC721Metadata', + 'value': '1', + }]); }); async function testSetsPropertiesForCollection(collection: UniqueBaseCollection) { @@ -150,7 +200,11 @@ await expect(collection.setProperties(bob, [{key: 'electron', value: 'come bond'}, {key: 'black_hole', value: 'LIGO'}])) .to.be.rejectedWith(/common\.NoPermission/); - expect(await collection.getProperties()).to.be.empty; + const properties = await collection.getProperties(); + expect(properties).to.be.deep.equal([{ + 'key': 'ERC721Metadata', + 'value': '1', + }]); } itSub('Fails to set properties in a NFT collection if not its onwer/administrator', async ({helper}) => { @@ -202,7 +256,11 @@ await expect(collection.setProperties(alice, propertiesToBeSet)). to.be.rejectedWith(/common\.PropertyLimitReached/); - expect(await collection.getProperties()).to.be.empty; + const properties = await collection.getProperties(); + expect(properties).to.be.deep.equal([{ + 'key': 'ERC721Metadata', + 'value': '1', + }]); } itSub('Fails to set more properties than it is allowed (NFT)', async ({helper}) => { --- a/tests/src/util/playgrounds/unique.ts +++ b/tests/src/util/playgrounds/unique.ts @@ -981,6 +981,10 @@ return (await this.helper.callRpc('api.rpc.unique.collectionProperties', [collectionId, propertyKeys])).toHuman(); } + async getCollectionOptions(collectionId: number) { + return (await this.helper.callRpc('api.rpc.unique.collectionById', [collectionId])).toHuman(); + } + /** * Deletes onchain properties from the collection. * @@ -1293,6 +1297,7 @@ async mintCollection(signer: TSigner, collectionOptions: ICollectionCreationOptions, mode: 'NFT' | 'RFT'): Promise { collectionOptions = JSON.parse(JSON.stringify(collectionOptions)) as ICollectionCreationOptions; // Clone object collectionOptions.mode = (mode === 'NFT') ? {nft: null} : {refungible: null}; + collectionOptions.properties = collectionOptions.properties || [{key: 'ERC721Metadata', value: '1'}]; for (const key of ['name', 'description', 'tokenPrefix']) { if (typeof collectionOptions[key as 'name' | 'description' | 'tokenPrefix'] === 'string') collectionOptions[key as 'name' | 'description' | 'tokenPrefix'] = this.helper.util.str2vec(collectionOptions[key as 'name' | 'description' | 'tokenPrefix'] as string); } @@ -2476,6 +2481,10 @@ return await this.helper.collection.getTokenNextSponsored(this.collectionId, tokenId, addressObj); } + async getOptions() { + return await this.helper.collection.getCollectionOptions(this.collectionId); + } + async setSponsor(signer: TSigner, sponsorAddress: TSubstrateAccount) { return await this.helper.collection.setSponsor(signer, this.collectionId, sponsorAddress); } -- gitstuff