From 48762e7ec75600a3f3462372d5c3a7e92845b8aa Mon Sep 17 00:00:00 2001 From: PraetorP Date: Fri, 18 Nov 2022 08:56:05 +0000 Subject: [PATCH] Added new call functions - The functions `description`, `crossOwnerOf`, `tokenProperties` to `ERC721UniqueExtensions` to solidity interfaces. --- --- a/pallets/fungible/CHANGELOG.md +++ b/pallets/fungible/CHANGELOG.md @@ -4,12 +4,22 @@ +## [0.1.8] - 2022-11-18 + +### Added + +- The function `description` to `ERC20UniqueExtensions` interface. + ## [0.1.7] - 2022-11-14 ### Changed - Added `transfer_cross` in eth functions. +### Changed + +- Use named structure `EthCrossAccount` in eth functions. + ## [0.1.6] - 2022-11-02 ### Changed --- a/pallets/fungible/src/erc.rs +++ b/pallets/fungible/src/erc.rs @@ -158,6 +158,13 @@ where T::AccountId: From<[u8; 32]>, { + /// @notice A description for the collection. + fn description(&self) -> Result { + Ok(decode_utf16(self.description.iter().copied()) + .map(|r| r.unwrap_or(REPLACEMENT_CHARACTER)) + .collect::()) + } + #[weight(>::approve())] fn approve_cross( &mut self, --- a/pallets/fungible/src/stubs/UniqueFungible.sol +++ b/pallets/fungible/src/stubs/UniqueFungible.sol @@ -439,6 +439,15 @@ /// @dev the ERC-165 identifier for this interface is 0x29f4dcd9 contract ERC20UniqueExtensions is Dummy, ERC165 { + /// @notice A description for the collection. + /// @dev EVM selector for this function is: 0x7284e416, + /// or in textual repr: description() + function description() public view returns (string memory) { + require(false, stub_error); + dummy; + return ""; + } + /// @dev EVM selector for this function is: 0x0ecd0ab0, /// or in textual repr: approveCross((address,uint256),uint256) function approveCross(EthCrossAccount memory spender, uint256 amount) public returns (bool) { --- a/pallets/nonfungible/CHANGELOG.md +++ b/pallets/nonfungible/CHANGELOG.md @@ -4,6 +4,12 @@ +## [0.1.10] - 2022-11-18 + +### Added + +- The functions `description`, `crossOwnerOf`, `tokenProperties` to `ERC721UniqueExtensions` interface. + ## [0.1.9] - 2022-11-14 ### Changed --- a/pallets/nonfungible/src/erc.rs +++ b/pallets/nonfungible/src/erc.rs @@ -37,7 +37,7 @@ use sp_std::vec::Vec; use pallet_common::{ erc::{CommonEvmHandler, PrecompileResult, CollectionCall, static_property::key}, - CollectionHandle, CollectionPropertyPermissions, + CollectionHandle, CollectionPropertyPermissions, CommonCollectionOperations, }; use pallet_evm::{account::CrossAccountId, PrecompileHandle}; use pallet_evm_coder_substrate::call; @@ -278,7 +278,7 @@ #[solidity_interface(name = ERC721Metadata, expect_selector = 0x5b5e139f)] impl NonfungibleHandle where - T::AccountId: From<[u8; 32]>, + T::AccountId: From<[u8; 32]> + AsRef<[u8; 32]>, { /// @notice A descriptive name for a collection of NFTs in this contract /// @dev real implementation of this function lies in `ERC721UniqueExtensions` @@ -686,7 +686,7 @@ #[solidity_interface(name = ERC721UniqueExtensions)] impl NonfungibleHandle where - T::AccountId: From<[u8; 32]>, + T::AccountId: From<[u8; 32]> + AsRef<[u8; 32]>, { /// @notice A descriptive name for a collection of NFTs in this contract fn name(&self) -> Result { @@ -700,6 +700,56 @@ Ok(string::from_utf8_lossy(&self.token_prefix).into()) } + /// @notice A description for the collection. + fn description(&self) -> Result { + Ok(decode_utf16(self.description.iter().copied()) + .map(|r| r.unwrap_or(REPLACEMENT_CHARACTER)) + .collect::()) + } + + /// Returns the owner (in cross format) of the token. + /// + /// @param tokenId Id for the token. + fn cross_owner_of(&self, token_id: uint256) -> Result { + Self::token_owner(&self, token_id.try_into()?) + .map(|o| EthCrossAccount::from_sub_cross_account::(&o)) + .ok_or(Error::Revert("key too large".into())) + } + + /// Returns the token properties. + /// + /// @param tokenId Id for the token. + /// @param keys Properties keys. Empty keys for all propertyes. + /// @return Vector of properties key/value pairs. + fn token_properties( + &self, + token_id: uint256, + keys: Vec, + ) -> Result> { + let keys = keys + .into_iter() + .map(|key| { + >::from(key) + .try_into() + .map_err(|_| Error::Revert("key too large".into())) + }) + .collect::>>()?; + + >::token_properties( + &self, + token_id.try_into()?, + if keys.is_empty() { None } else { Some(keys) }, + ) + .into_iter() + .map(|p| { + let key = string::from_utf8(p.key.to_vec()) + .map_err(|e| Error::Revert(alloc::format!("{}", e)))?; + let value = bytes(p.value.to_vec()); + Ok((key, value)) + }) + .collect::>>() + } + /// @notice Set or reaffirm the approved address for an NFT /// @dev The zero address indicates there is no approved address. /// @dev Throws unless `msg.sender` is the current NFT owner, or an authorized --- a/pallets/nonfungible/src/stubs/UniqueNFT.sol +++ b/pallets/nonfungible/src/stubs/UniqueNFT.sol @@ -702,6 +702,42 @@ return ""; } + /// @notice A description for the collection. + /// @dev EVM selector for this function is: 0x7284e416, + /// or in textual repr: description() + function description() public view returns (string memory) { + require(false, stub_error); + dummy; + return ""; + } + + /// Returns the owner (in cross format) of the token. + /// + /// @param tokenId Id for the token. + /// @dev EVM selector for this function is: 0x2b29dace, + /// or in textual repr: crossOwnerOf(uint256) + function crossOwnerOf(uint256 tokenId) public view returns (EthCrossAccount memory) { + require(false, stub_error); + tokenId; + dummy; + return EthCrossAccount(0x0000000000000000000000000000000000000000, 0); + } + + /// Returns the token properties. + /// + /// @param tokenId Id for the token. + /// @param keys Properties keys. Empty keys for all propertyes. + /// @return Vector of properties key/value pairs. + /// @dev EVM selector for this function is: 0xefc26c69, + /// or in textual repr: tokenProperties(uint256,string[]) + function tokenProperties(uint256 tokenId, string[] memory keys) public view returns (Tuple8[] memory) { + require(false, stub_error); + tokenId; + keys; + dummy; + return new Tuple8[](0); + } + /// @notice Set or reaffirm the approved address for an NFT /// @dev The zero address indicates there is no approved address. /// @dev Throws unless `msg.sender` is the current NFT owner, or an authorized @@ -841,6 +877,12 @@ string field_1; } +/// @dev anonymous struct +struct Tuple8 { + string field_0; + bytes field_1; +} + /// @title ERC-721 Non-Fungible Token Standard, optional enumeration extension /// @dev See https://eips.ethereum.org/EIPS/eip-721 /// @dev the ERC-165 identifier for this interface is 0x780e9d63 --- a/pallets/refungible/CHANGELOG.md +++ b/pallets/refungible/CHANGELOG.md @@ -4,6 +4,12 @@ +## [0.2.9] - 2022-11-18 + +### Added + +- The functions `description`, `crossOwnerOf`, `tokenProperties` to `ERC721UniqueExtensions` interface. + ## [0.2.8] - 2022-11-14 ### Changed --- a/pallets/refungible/src/erc.rs +++ b/pallets/refungible/src/erc.rs @@ -33,6 +33,7 @@ use pallet_common::{ CollectionHandle, CollectionPropertyPermissions, erc::{CommonEvmHandler, CollectionCall, static_property::key}, + CommonCollectionOperations, }; use pallet_evm::{account::CrossAccountId, PrecompileHandle}; use pallet_evm_coder_substrate::{call, dispatch_to_evm}; @@ -273,7 +274,7 @@ #[solidity_interface(name = ERC721Metadata)] impl RefungibleHandle where - T::AccountId: From<[u8; 32]>, + T::AccountId: From<[u8; 32]> + AsRef<[u8; 32]>, { /// @notice A descriptive name for a collection of NFTs in this contract /// @dev real implementation of this function lies in `ERC721UniqueExtensions` @@ -713,7 +714,7 @@ #[solidity_interface(name = ERC721UniqueExtensions)] impl RefungibleHandle where - T::AccountId: From<[u8; 32]>, + T::AccountId: From<[u8; 32]> + AsRef<[u8; 32]>, { /// @notice A descriptive name for a collection of NFTs in this contract fn name(&self) -> Result { @@ -727,6 +728,55 @@ Ok(string::from_utf8_lossy(&self.token_prefix).into()) } + /// @notice A description for the collection. + fn description(&self) -> Result { + Ok(decode_utf16(self.description.iter().copied()) + .map(|r| r.unwrap_or(REPLACEMENT_CHARACTER)) + .collect::()) + } + + /// Returns the owner (in cross format) of the token. + /// + /// @param tokenId Id for the token. + fn cross_owner_of(&self, token_id: uint256) -> Result { + Self::token_owner(&self, token_id.try_into()?) + .map(|o| EthCrossAccount::from_sub_cross_account::(&o)) + .ok_or(Error::Revert("key too large".into())) + } + + /// Returns the token properties. + /// + /// @param tokenId Id for the token. + /// @param keys Properties keys. Empty keys for all propertyes. + /// @return Vector of properties key/value pairs. + fn token_properties( + &self, + token_id: uint256, + keys: Vec, + ) -> Result> { + let keys = keys + .into_iter() + .map(|key| { + >::from(key) + .try_into() + .map_err(|_| Error::Revert("key too large".into())) + }) + .collect::>>()?; + + >::token_properties( + &self, + token_id.try_into()?, + if keys.is_empty() { None } else { Some(keys) }, + ) + .into_iter() + .map(|p| { + let key = string::from_utf8(p.key.to_vec()) + .map_err(|e| Error::Revert(alloc::format!("{}", e)))?; + let value = bytes(p.value.to_vec()); + Ok((key, value)) + }) + .collect::>>() + } /// @notice Transfer ownership of an RFT /// @dev Throws unless `msg.sender` is the current owner. Throws if `to` /// is the zero address. Throws if `tokenId` is not a valid RFT. --- a/pallets/refungible/src/stubs/UniqueRefungible.sol +++ b/pallets/refungible/src/stubs/UniqueRefungible.sol @@ -700,6 +700,42 @@ return ""; } + /// @notice A description for the collection. + /// @dev EVM selector for this function is: 0x7284e416, + /// or in textual repr: description() + function description() public view returns (string memory) { + require(false, stub_error); + dummy; + return ""; + } + + /// Returns the owner (in cross format) of the token. + /// + /// @param tokenId Id for the token. + /// @dev EVM selector for this function is: 0x2b29dace, + /// or in textual repr: crossOwnerOf(uint256) + function crossOwnerOf(uint256 tokenId) public view returns (EthCrossAccount memory) { + require(false, stub_error); + tokenId; + dummy; + return EthCrossAccount(0x0000000000000000000000000000000000000000, 0); + } + + /// Returns the token properties. + /// + /// @param tokenId Id for the token. + /// @param keys Properties keys. Empty keys for all propertyes. + /// @return Vector of properties key/value pairs. + /// @dev EVM selector for this function is: 0xefc26c69, + /// or in textual repr: tokenProperties(uint256,string[]) + function tokenProperties(uint256 tokenId, string[] memory keys) public view returns (Tuple8[] memory) { + require(false, stub_error); + tokenId; + keys; + dummy; + return new Tuple8[](0); + } + /// @notice Transfer ownership of an RFT /// @dev Throws unless `msg.sender` is the current owner. Throws if `to` /// is the zero address. Throws if `tokenId` is not a valid RFT. @@ -840,6 +876,12 @@ string field_1; } +/// @dev anonymous struct +struct Tuple8 { + string field_0; + bytes field_1; +} + /// @title ERC-721 Non-Fungible Token Standard, optional enumeration extension /// @dev See https://eips.ethereum.org/EIPS/eip-721 /// @dev the ERC-165 identifier for this interface is 0x780e9d63 --- a/tests/src/eth/abi/fungible.json +++ b/tests/src/eth/abi/fungible.json @@ -283,6 +283,13 @@ }, { "inputs": [], + "name": "description", + "outputs": [{ "internalType": "string", "name": "", "type": "string" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], "name": "hasCollectionPendingSponsor", "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }], "stateMutability": "view", --- a/tests/src/eth/abi/nonFungible.json +++ b/tests/src/eth/abi/nonFungible.json @@ -297,6 +297,25 @@ }, { "inputs": [ + { "internalType": "uint256", "name": "tokenId", "type": "uint256" } + ], + "name": "crossOwnerOf", + "outputs": [ + { + "components": [ + { "internalType": "address", "name": "eth", "type": "address" }, + { "internalType": "uint256", "name": "sub", "type": "uint256" } + ], + "internalType": "struct EthCrossAccount", + "name": "", + "type": "tuple" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ { "internalType": "string[]", "name": "keys", "type": "string[]" } ], "name": "deleteCollectionProperties", @@ -316,6 +335,13 @@ }, { "inputs": [], + "name": "description", + "outputs": [{ "internalType": "string", "name": "", "type": "string" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], "name": "finishMinting", "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }], "stateMutability": "nonpayable", @@ -641,6 +667,26 @@ }, { "inputs": [ + { "internalType": "uint256", "name": "tokenId", "type": "uint256" }, + { "internalType": "string[]", "name": "keys", "type": "string[]" } + ], + "name": "tokenProperties", + "outputs": [ + { + "components": [ + { "internalType": "string", "name": "field_0", "type": "string" }, + { "internalType": "bytes", "name": "field_1", "type": "bytes" } + ], + "internalType": "struct Tuple8[]", + "name": "", + "type": "tuple[]" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ { "internalType": "uint256", "name": "tokenId", "type": "uint256" } ], "name": "tokenURI", --- a/tests/src/eth/abi/reFungible.json +++ b/tests/src/eth/abi/reFungible.json @@ -279,6 +279,25 @@ }, { "inputs": [ + { "internalType": "uint256", "name": "tokenId", "type": "uint256" } + ], + "name": "crossOwnerOf", + "outputs": [ + { + "components": [ + { "internalType": "address", "name": "eth", "type": "address" }, + { "internalType": "uint256", "name": "sub", "type": "uint256" } + ], + "internalType": "struct EthCrossAccount", + "name": "", + "type": "tuple" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ { "internalType": "string[]", "name": "keys", "type": "string[]" } ], "name": "deleteCollectionProperties", @@ -298,6 +317,13 @@ }, { "inputs": [], + "name": "description", + "outputs": [{ "internalType": "string", "name": "", "type": "string" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], "name": "finishMinting", "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }], "stateMutability": "nonpayable", @@ -632,6 +658,26 @@ }, { "inputs": [ + { "internalType": "uint256", "name": "tokenId", "type": "uint256" }, + { "internalType": "string[]", "name": "keys", "type": "string[]" } + ], + "name": "tokenProperties", + "outputs": [ + { + "components": [ + { "internalType": "string", "name": "field_0", "type": "string" }, + { "internalType": "bytes", "name": "field_1", "type": "bytes" } + ], + "internalType": "struct Tuple8[]", + "name": "", + "type": "tuple[]" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ { "internalType": "uint256", "name": "tokenId", "type": "uint256" } ], "name": "tokenURI", --- a/tests/src/eth/api/UniqueFungible.sol +++ b/tests/src/eth/api/UniqueFungible.sol @@ -292,6 +292,11 @@ /// @dev the ERC-165 identifier for this interface is 0x29f4dcd9 interface ERC20UniqueExtensions is Dummy, ERC165 { + /// @notice A description for the collection. + /// @dev EVM selector for this function is: 0x7284e416, + /// or in textual repr: description() + function description() external view returns (string memory); + /// @dev EVM selector for this function is: 0x0ecd0ab0, /// or in textual repr: approveCross((address,uint256),uint256) function approveCross(EthCrossAccount memory spender, uint256 amount) external returns (bool); --- a/tests/src/eth/api/UniqueNFT.sol +++ b/tests/src/eth/api/UniqueNFT.sol @@ -45,7 +45,7 @@ /// @param properties settable properties /// @dev EVM selector for this function is: 0x14ed3a6e, /// or in textual repr: setProperties(uint256,(string,bytes)[]) - function setProperties(uint256 tokenId, Property[] memory properties) external; + function setProperties(uint256 tokenId, Tuple21[] memory properties) external; // /// @notice Delete token property value. // /// @dev Throws error if `msg.sender` has no permission to edit the property. @@ -95,7 +95,7 @@ /// @param properties Vector of properties key/value pair. /// @dev EVM selector for this function is: 0x50b26b2a, /// or in textual repr: setCollectionProperties((string,bytes)[]) - function setCollectionProperties(Property[] memory properties) external; + function setCollectionProperties(Tuple21[] memory properties) external; // /// Delete collection property. // /// @@ -127,7 +127,7 @@ /// @return Vector of properties key/value pairs. /// @dev EVM selector for this function is: 0x285fb8e6, /// or in textual repr: collectionProperties(string[]) - function collectionProperties(string[] memory keys) external view returns (Tuple23[] memory); + function collectionProperties(string[] memory keys) external view returns (Tuple21[] memory); // /// Set the sponsor of the collection. // /// @@ -169,7 +169,7 @@ /// @return Tuble with sponsor address and his substrate mirror. If there is no confirmed sponsor error "Contract has no sponsor" throw. /// @dev EVM selector for this function is: 0x6ec0a9f1, /// or in textual repr: collectionSponsor() - function collectionSponsor() external view returns (Tuple26 memory); + function collectionSponsor() external view returns (Tuple24 memory); /// Set limits for the collection. /// @dev Throws error if limit not found. @@ -346,13 +346,13 @@ } /// @dev anonymous struct -struct Tuple26 { +struct Tuple24 { address field_0; uint256 field_1; } /// @dev anonymous struct -struct Tuple23 { +struct Tuple21 { string field_0; bytes field_1; } @@ -452,7 +452,7 @@ } /// @title Unique extensions for ERC721. -/// @dev the ERC-165 identifier for this interface is 0x0e9fc611 +/// @dev the ERC-165 identifier for this interface is 0x244543ee interface ERC721UniqueExtensions is Dummy, ERC165 { /// @notice A descriptive name for a collection of NFTs in this contract /// @dev EVM selector for this function is: 0x06fdde03, @@ -464,6 +464,27 @@ /// or in textual repr: symbol() function symbol() external view returns (string memory); + /// @notice A description for the collection. + /// @dev EVM selector for this function is: 0x7284e416, + /// or in textual repr: description() + function description() external view returns (string memory); + + /// Returns the owner (in cross format) of the token. + /// + /// @param tokenId Id for the token. + /// @dev EVM selector for this function is: 0x2b29dace, + /// or in textual repr: crossOwnerOf(uint256) + function crossOwnerOf(uint256 tokenId) external view returns (EthCrossAccount memory); + + /// Returns the token properties. + /// + /// @param tokenId Id for the token. + /// @param keys Properties keys. Empty keys for all propertyes. + /// @return Vector of properties key/value pairs. + /// @dev EVM selector for this function is: 0xefc26c69, + /// or in textual repr: tokenProperties(uint256,string[]) + function tokenProperties(uint256 tokenId, string[] memory keys) external view returns (Tuple7[] memory); + /// @notice Set or reaffirm the approved address for an NFT /// @dev The zero address indicates there is no approved address. /// @dev Throws unless `msg.sender` is the current NFT owner, or an authorized @@ -546,16 +567,22 @@ // /// @param tokens array of pairs of token ID and token URI for minted tokens // /// @dev EVM selector for this function is: 0x36543006, // /// or in textual repr: mintBulkWithTokenURI(address,(uint256,string)[]) - // function mintBulkWithTokenURI(address to, Tuple11[] memory tokens) external returns (bool); + // function mintBulkWithTokenURI(address to, Tuple10[] memory tokens) external returns (bool); } /// @dev anonymous struct -struct Tuple11 { +struct Tuple10 { uint256 field_0; string field_1; } +/// @dev anonymous struct +struct Tuple7 { + string field_0; + bytes field_1; +} + /// @title ERC-721 Non-Fungible Token Standard, optional enumeration extension /// @dev See https://eips.ethereum.org/EIPS/eip-721 /// @dev the ERC-165 identifier for this interface is 0x780e9d63 --- a/tests/src/eth/api/UniqueRefungible.sol +++ b/tests/src/eth/api/UniqueRefungible.sol @@ -462,6 +462,27 @@ /// or in textual repr: symbol() function symbol() external view returns (string memory); + /// @notice A description for the collection. + /// @dev EVM selector for this function is: 0x7284e416, + /// or in textual repr: description() + function description() external view returns (string memory); + + /// Returns the owner (in cross format) of the token. + /// + /// @param tokenId Id for the token. + /// @dev EVM selector for this function is: 0x2b29dace, + /// or in textual repr: crossOwnerOf(uint256) + function crossOwnerOf(uint256 tokenId) external view returns (EthCrossAccount memory); + + /// Returns the token properties. + /// + /// @param tokenId Id for the token. + /// @param keys Properties keys. Empty keys for all propertyes. + /// @return Vector of properties key/value pairs. + /// @dev EVM selector for this function is: 0xefc26c69, + /// or in textual repr: tokenProperties(uint256,string[]) + function tokenProperties(uint256 tokenId, string[] memory keys) external view returns (Tuple7[] memory); + /// @notice Transfer ownership of an RFT /// @dev Throws unless `msg.sender` is the current owner. Throws if `to` /// is the zero address. Throws if `tokenId` is not a valid RFT. @@ -555,6 +576,12 @@ string field_1; } +/// @dev anonymous struct +struct Tuple7 { + string field_0; + bytes field_1; +} + /// @title ERC-721 Non-Fungible Token Standard, optional enumeration extension /// @dev See https://eips.ethereum.org/EIPS/eip-721 /// @dev the ERC-165 identifier for this interface is 0x780e9d63 --- a/tests/src/eth/base.test.ts +++ b/tests/src/eth/base.test.ts @@ -117,7 +117,7 @@ }); itEth('ERC721UniqueExtensions support', async ({helper}) => { - await checkInterface(helper, '0x0e9fc611', true, true); + await checkInterface(helper, '0x922a115f', true, true); }); itEth('ERC721Burnable - 0x42966c68 - support', async ({helper}) => { --- a/tests/src/eth/createFTCollection.test.ts +++ b/tests/src/eth/createFTCollection.test.ts @@ -36,9 +36,11 @@ 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.createFungibleCollection(owner, 'Sponsor', DECIMALS, 'absolutely anything', 'ENVY'); + const description = 'absolutely anything'; + + const {collectionId, collectionAddress} = await helper.eth.createFungibleCollection(owner, 'Sponsor', DECIMALS, description, 'ENVY'); - const collection = helper.ethNativeContract.collection(collectionAddress, 'rft', owner, true); + const collection = helper.ethNativeContract.collection(collectionAddress, 'ft', owner, true); await collection.methods.setCollectionSponsor(sponsor).send(); let data = (await helper.rft.getData(collectionId))!; @@ -57,8 +59,9 @@ 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.createFungibleCollection(owner, 'Sponsor', DECIMALS, 'absolutely anything', 'ENVY'); - + const description = 'absolutely anything'; + const {collectionId, collectionAddress} = await helper.eth.createFungibleCollection(owner, 'Sponsor', DECIMALS, description, 'ENVY'); + const collection = helper.ethNativeContract.collection(collectionAddress, 'rft', owner); const sponsorCross = helper.ethCrossAccount.fromAddress(sponsor); await collection.methods.setCollectionSponsorCross(sponsorCross).send(); @@ -73,6 +76,7 @@ data = (await helper.rft.getData(collectionId))!; expect(data.raw.sponsorship.Confirmed).to.be.equal(evmToAddress(sponsor, Number(ss58Format))); + expect(await collection.methods.description().call()).to.deep.equal(description); }); itEth('Set limits', async ({helper}) => { --- a/tests/src/eth/createNFTCollection.test.ts +++ b/tests/src/eth/createNFTCollection.test.ts @@ -28,7 +28,7 @@ }); }); - itEth('Create collection with properties', async ({helper}) => { + itEth('Create collection with properties & get desctription', async ({helper}) => { const owner = await helper.eth.createAccountWithBalance(donor); const name = 'CollectionEVM'; @@ -37,7 +37,8 @@ const baseUri = 'BaseURI'; const {collectionId, collectionAddress, events} = await helper.eth.createERC721MetadataCompatibleNFTCollection(owner, name, description, prefix, baseUri); - + const contract = helper.ethNativeContract.collection(collectionAddress, 'nft'); + expect(events).to.be.deep.equal([ { address: '0x6C4E9fE1AE37a41E93CEE429e8E1881aBdcbb54F', @@ -56,7 +57,9 @@ expect(data.description).to.be.eq(description); expect(data.raw.tokenPrefix).to.be.eq(prefix); expect(data.raw.mode).to.be.eq('NFT'); - + + expect(await contract.methods.description().call()).to.deep.equal(description); + const options = await collection.getOptions(); expect(options.tokenPropertyPermissions).to.be.deep.equal([ { @@ -92,11 +95,12 @@ expect(data.raw.sponsorship.Confirmed).to.be.equal(evmToAddress(sponsor, Number(ss58Format))); }); - itEth('[cross] Set sponsorship', async ({helper}) => { + itEth('[cross] Set sponsorship & get description', async ({helper}) => { 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.createNFTCollection(owner, 'Sponsor', 'absolutely anything', 'ROC'); + const description = 'absolutely anything'; + const {collectionId, collectionAddress} = await helper.eth.createNFTCollection(owner, 'Sponsor', description, 'ROC'); const collection = helper.ethNativeContract.collection(collectionAddress, 'nft', owner); const sponsorCross = helper.ethCrossAccount.fromAddress(sponsor); @@ -112,6 +116,8 @@ data = (await helper.nft.getData(collectionId))!; expect(data.raw.sponsorship.Confirmed).to.be.equal(evmToAddress(sponsor, Number(ss58Format))); + + expect(await sponsorCollection.methods.description().call()).to.deep.equal(description); }); itEth('Set limits', async ({helper}) => { --- a/tests/src/eth/createRFTCollection.test.ts +++ b/tests/src/eth/createRFTCollection.test.ts @@ -53,7 +53,7 @@ - itEth('Create collection with properties', async ({helper}) => { + itEth('Create collection with properties & get description', async ({helper}) => { const owner = await helper.eth.createAccountWithBalance(donor); const name = 'CollectionEVM'; @@ -61,7 +61,8 @@ const prefix = 'token prefix'; const baseUri = 'BaseURI'; - const {collectionId} = await helper.eth.createERC721MetadataCompatibleRFTCollection(owner, name, description, prefix, baseUri); + const {collectionId, collectionAddress} = await helper.eth.createERC721MetadataCompatibleRFTCollection(owner, name, description, prefix, baseUri); + const contract = helper.ethNativeContract.collection(collectionAddress, 'nft'); const collection = helper.rft.getCollectionObject(collectionId); const data = (await collection.getData())!; @@ -71,6 +72,8 @@ expect(data.raw.tokenPrefix).to.be.eq(prefix); expect(data.raw.mode).to.be.eq('ReFungible'); + expect(await contract.methods.description().call()).to.deep.equal(description); + const options = await collection.getOptions(); expect(options.tokenPropertyPermissions).to.be.deep.equal([ { --- a/tests/src/eth/nonFungible.test.ts +++ b/tests/src/eth/nonFungible.test.ts @@ -17,6 +17,7 @@ import {itEth, usingEthPlaygrounds, expect, EthUniqueHelper} from './util'; import {IKeyringPair} from '@polkadot/types/types'; import {Contract} from 'web3-eth-contract'; +import exp from 'constants'; describe('NFT: Information getting', () => { @@ -149,7 +150,7 @@ }); }); - itEth('Can perform mint()', async ({helper}) => { + itEth('Can perform mint() & get crossOwner()', async ({helper}) => { const owner = await helper.eth.createAccountWithBalance(donor); const receiver = helper.eth.createAccount(); @@ -166,7 +167,8 @@ expect(event.returnValues.to).to.be.equal(receiver); expect(await contract.methods.tokenURI(tokenId).call()).to.be.equal('Test URI'); - + console.log(await contract.methods.crossOwnerOf(tokenId).call()); + expect(await contract.methods.crossOwnerOf(tokenId).call()).to.be.like([receiver, '0']); // TODO: this wont work right now, need release 919000 first // await helper.methods.setOffchainSchema(collectionIdAddress, 'https://offchain-service.local/token-info/{id}').send(); // const tokenUri = await contract.methods.tokenURI(nextTokenId).call(); --- a/tests/src/eth/reFungible.test.ts +++ b/tests/src/eth/reFungible.test.ts @@ -117,7 +117,7 @@ }); }); - itEth('Can perform mint()', async ({helper}) => { + itEth('Can perform mint() & crossOwnerOf()', async ({helper}) => { const owner = await helper.eth.createAccountWithBalance(donor); const receiver = helper.eth.createAccount(); const {collectionAddress} = await helper.eth.createERC721MetadataCompatibleRFTCollection(owner, 'Minty', '6', '6', ''); @@ -132,6 +132,7 @@ const tokenId = event.returnValues.tokenId; expect(tokenId).to.be.equal('1'); + expect(await contract.methods.crossOwnerOf(tokenId).call()).to.be.like([receiver, '0']); expect(await contract.methods.tokenURI(tokenId).call()).to.be.equal('Test URI'); }); --- a/tests/src/eth/tokenProperties.test.ts +++ b/tests/src/eth/tokenProperties.test.ts @@ -14,10 +14,11 @@ // You should have received a copy of the GNU General Public License // along with Unique Network. If not, see . -import {itEth, usingEthPlaygrounds, expect} from './util'; +import {itEth, usingEthPlaygrounds, expect, EthUniqueHelper} from './util'; import {IKeyringPair} from '@polkadot/types/types'; -import {ITokenPropertyPermission} from '../util/playgrounds/types'; +import {ITokenPropertyPermission, TCollectionMode} from '../util/playgrounds/types'; import {Pallets} from '../util'; +import {UniqueNFTCollection, UniqueRFTCollection} from '../util/playgrounds/unique'; describe('EVM token properties', () => { let donor: IKeyringPair; @@ -95,7 +96,7 @@ expect(value).to.equal('testValue'); }); - itEth('Can be multiple set for NFT ', async({helper}) => { + async function checkProps(helper: EthUniqueHelper, mode: TCollectionMode) { const caller = await helper.eth.createAccountWithBalance(donor); const properties = Array(5).fill(0).map((_, i) => { return {key: `key_${i}`, value: Buffer.from(`value_${i}`)}; }); @@ -103,56 +104,44 @@ collectionAdmin: true, mutable: true}}; }); - const collection = await helper.nft.mintCollection(alice, { + const collection = await helper[mode].mintCollection(alice, { tokenPrefix: 'ethp', tokenPropertyPermissions: permissions, - }); + }) as UniqueNFTCollection | UniqueRFTCollection; const token = await collection.mintToken(alice); const valuesBefore = await token.getProperties(properties.map(p => p.key)); expect(valuesBefore).to.be.deep.equal([]); + await collection.addAdmin(alice, {Ethereum: caller}); - + const address = helper.ethAddress.fromCollectionId(collection.collectionId); - const contract = helper.ethNativeContract.collection(address, 'nft', caller); + const contract = helper.ethNativeContract.collection(address, mode, caller); + + expect(await contract.methods.tokenProperties(token.tokenId, []).call()).to.be.deep.equal([]); await contract.methods.setProperties(token.tokenId, properties).send({from: caller}); const values = await token.getProperties(properties.map(p => p.key)); expect(values).to.be.deep.equal(properties.map(p => { return {key: p.key, value: p.value.toString()}; })); - }); - - itEth.ifWithPallets('Can be multiple set for RFT ', [Pallets.ReFungible], async({helper}) => { - const caller = await helper.eth.createAccountWithBalance(donor); - const properties = Array(5).fill(0).map((_, i) => { return {key: `key_${i}`, value: Buffer.from(`value_${i}`)}; }); - const permissions: ITokenPropertyPermission[] = properties.map(p => { return {key: p.key, permission: {tokenOwner: true, - collectionAdmin: true, - mutable: true}}; }); - - const collection = await helper.rft.mintCollection(alice, { - tokenPrefix: 'ethp', - tokenPropertyPermissions: permissions, - }); - - const token = await collection.mintToken(alice); - - const valuesBefore = await token.getProperties(properties.map(p => p.key)); - expect(valuesBefore).to.be.deep.equal([]); + expect(await contract.methods.tokenProperties(token.tokenId, []).call()).to.be.like(properties + .map(p => { return helper.ethProperty.property(p.key, p.value.toString()); })); - await collection.addAdmin(alice, {Ethereum: caller}); - - const address = helper.ethAddress.fromCollectionId(collection.collectionId); - const contract = helper.ethNativeContract.collection(address, 'rft', caller); - - await contract.methods.setProperties(token.tokenId, properties).send({from: caller}); - - const values = await token.getProperties(properties.map(p => p.key)); - expect(values).to.be.deep.equal(properties.map(p => { return {key: p.key, value: p.value.toString()}; })); + expect(await contract.methods.tokenProperties(token.tokenId, [properties[0].key]).call()) + .to.be.like([helper.ethProperty.property(properties[0].key, properties[0].value.toString())]); + } + + itEth('Can be multiple set/read for NFT ', async({helper}) => { + await checkProps(helper, 'nft'); + }); + + itEth.ifWithPallets('Can be multiple set/read for RFT ', [Pallets.ReFungible], async({helper}) => { + await checkProps(helper, 'rft'); }); - + itEth('Can be deleted', async({helper}) => { const caller = await helper.eth.createAccountWithBalance(donor); const collection = await helper.nft.mintCollection(alice, { -- gitstuff