difftreelog
Added new call functions - The functions `description`, `crossOwnerOf`, `tokenProperties` to `ERC721UniqueExtensions` to solidity interfaces.
in: master
22 files changed
pallets/fungible/CHANGELOG.mddiffbeforeafterboth445<!-- bureaucrate goes here -->5<!-- bureaucrate goes here -->667## [0.1.8] - 2022-11-1889### Added1011- The function `description` to `ERC20UniqueExtensions` interface.127## [0.1.7] - 2022-11-1413## [0.1.7] - 2022-11-148149### Changed15### Changed101611- Added `transfer_cross` in eth functions.17- Added `transfer_cross` in eth functions.1819### Changed2021- Use named structure `EthCrossAccount` in eth functions.122213## [0.1.6] - 2022-11-0223## [0.1.6] - 2022-11-021424pallets/fungible/src/erc.rsdiffbeforeafterboth158where158where159 T::AccountId: From<[u8; 32]>,159 T::AccountId: From<[u8; 32]>,160{160{161 /// @notice A description for the collection.162 fn description(&self) -> Result<string> {163 Ok(decode_utf16(self.description.iter().copied())164 .map(|r| r.unwrap_or(REPLACEMENT_CHARACTER))165 .collect::<string>())166 }167161 #[weight(<SelfWeightOf<T>>::approve())]168 #[weight(<SelfWeightOf<T>>::approve())]162 fn approve_cross(169 fn approve_cross(pallets/fungible/src/stubs/UniqueFungible.soldiffbeforeafterboth439439440/// @dev the ERC-165 identifier for this interface is 0x29f4dcd9440/// @dev the ERC-165 identifier for this interface is 0x29f4dcd9441contract ERC20UniqueExtensions is Dummy, ERC165 {441contract ERC20UniqueExtensions is Dummy, ERC165 {442 /// @notice A description for the collection.443 /// @dev EVM selector for this function is: 0x7284e416,444 /// or in textual repr: description()445 function description() public view returns (string memory) {446 require(false, stub_error);447 dummy;448 return "";449 }450442 /// @dev EVM selector for this function is: 0x0ecd0ab0,451 /// @dev EVM selector for this function is: 0x0ecd0ab0,443 /// or in textual repr: approveCross((address,uint256),uint256)452 /// or in textual repr: approveCross((address,uint256),uint256)pallets/nonfungible/CHANGELOG.mddiffbeforeafterboth445<!-- bureaucrate goes here -->5<!-- bureaucrate goes here -->667## [0.1.10] - 2022-11-1889### Added1011- The functions `description`, `crossOwnerOf`, `tokenProperties` to `ERC721UniqueExtensions` interface.127## [0.1.9] - 2022-11-1413## [0.1.9] - 2022-11-148149### Changed15### Changedpallets/nonfungible/src/erc.rsdiffbeforeafterboth37use sp_std::vec::Vec;37use sp_std::vec::Vec;38use pallet_common::{38use pallet_common::{39 erc::{CommonEvmHandler, PrecompileResult, CollectionCall, static_property::key},39 erc::{CommonEvmHandler, PrecompileResult, CollectionCall, static_property::key},40 CollectionHandle, CollectionPropertyPermissions,40 CollectionHandle, CollectionPropertyPermissions, CommonCollectionOperations,41};41};42use pallet_evm::{account::CrossAccountId, PrecompileHandle};42use pallet_evm::{account::CrossAccountId, PrecompileHandle};43use pallet_evm_coder_substrate::call;43use pallet_evm_coder_substrate::call;278#[solidity_interface(name = ERC721Metadata, expect_selector = 0x5b5e139f)]278#[solidity_interface(name = ERC721Metadata, expect_selector = 0x5b5e139f)]279impl<T: Config> NonfungibleHandle<T>279impl<T: Config> NonfungibleHandle<T>280where280where281 T::AccountId: From<[u8; 32]>,281 T::AccountId: From<[u8; 32]> + AsRef<[u8; 32]>,282{282{283 /// @notice A descriptive name for a collection of NFTs in this contract283 /// @notice A descriptive name for a collection of NFTs in this contract284 /// @dev real implementation of this function lies in `ERC721UniqueExtensions`284 /// @dev real implementation of this function lies in `ERC721UniqueExtensions`686#[solidity_interface(name = ERC721UniqueExtensions)]686#[solidity_interface(name = ERC721UniqueExtensions)]687impl<T: Config> NonfungibleHandle<T>687impl<T: Config> NonfungibleHandle<T>688where688where689 T::AccountId: From<[u8; 32]>,689 T::AccountId: From<[u8; 32]> + AsRef<[u8; 32]>,690{690{691 /// @notice A descriptive name for a collection of NFTs in this contract691 /// @notice A descriptive name for a collection of NFTs in this contract692 fn name(&self) -> Result<string> {692 fn name(&self) -> Result<string> {700 Ok(string::from_utf8_lossy(&self.token_prefix).into())700 Ok(string::from_utf8_lossy(&self.token_prefix).into())701 }701 }702703 /// @notice A description for the collection.704 fn description(&self) -> Result<string> {705 Ok(decode_utf16(self.description.iter().copied())706 .map(|r| r.unwrap_or(REPLACEMENT_CHARACTER))707 .collect::<string>())708 }709710 /// Returns the owner (in cross format) of the token.711 ///712 /// @param tokenId Id for the token.713 fn cross_owner_of(&self, token_id: uint256) -> Result<EthCrossAccount> {714 Self::token_owner(&self, token_id.try_into()?)715 .map(|o| EthCrossAccount::from_sub_cross_account::<T>(&o))716 .ok_or(Error::Revert("key too large".into()))717 }718719 /// Returns the token properties.720 ///721 /// @param tokenId Id for the token.722 /// @param keys Properties keys. Empty keys for all propertyes.723 /// @return Vector of properties key/value pairs.724 fn token_properties(725 &self,726 token_id: uint256,727 keys: Vec<string>,728 ) -> Result<Vec<(string, bytes)>> {729 let keys = keys730 .into_iter()731 .map(|key| {732 <Vec<u8>>::from(key)733 .try_into()734 .map_err(|_| Error::Revert("key too large".into()))735 })736 .collect::<Result<Vec<_>>>()?;737738 <Self as CommonCollectionOperations<T>>::token_properties(739 &self,740 token_id.try_into()?,741 if keys.is_empty() { None } else { Some(keys) },742 )743 .into_iter()744 .map(|p| {745 let key = string::from_utf8(p.key.to_vec())746 .map_err(|e| Error::Revert(alloc::format!("{}", e)))?;747 let value = bytes(p.value.to_vec());748 Ok((key, value))749 })750 .collect::<Result<Vec<_>>>()751 }702752703 /// @notice Set or reaffirm the approved address for an NFT753 /// @notice Set or reaffirm the approved address for an NFT704 /// @dev The zero address indicates there is no approved address.754 /// @dev The zero address indicates there is no approved address.pallets/nonfungible/src/stubs/UniqueNFT.soldiffbeforeafterboth702 return "";702 return "";703 }703 }704705 /// @notice A description for the collection.706 /// @dev EVM selector for this function is: 0x7284e416,707 /// or in textual repr: description()708 function description() public view returns (string memory) {709 require(false, stub_error);710 dummy;711 return "";712 }713714 /// Returns the owner (in cross format) of the token.715 ///716 /// @param tokenId Id for the token.717 /// @dev EVM selector for this function is: 0x2b29dace,718 /// or in textual repr: crossOwnerOf(uint256)719 function crossOwnerOf(uint256 tokenId) public view returns (EthCrossAccount memory) {720 require(false, stub_error);721 tokenId;722 dummy;723 return EthCrossAccount(0x0000000000000000000000000000000000000000, 0);724 }725726 /// Returns the token properties.727 ///728 /// @param tokenId Id for the token.729 /// @param keys Properties keys. Empty keys for all propertyes.730 /// @return Vector of properties key/value pairs.731 /// @dev EVM selector for this function is: 0xefc26c69,732 /// or in textual repr: tokenProperties(uint256,string[])733 function tokenProperties(uint256 tokenId, string[] memory keys) public view returns (Tuple8[] memory) {734 require(false, stub_error);735 tokenId;736 keys;737 dummy;738 return new Tuple8[](0);739 }704740705 /// @notice Set or reaffirm the approved address for an NFT741 /// @notice Set or reaffirm the approved address for an NFT706 /// @dev The zero address indicates there is no approved address.742 /// @dev The zero address indicates there is no approved address.841 string field_1;877 string field_1;842}878}879880/// @dev anonymous struct881struct Tuple8 {882 string field_0;883 bytes field_1;884}843885844/// @title ERC-721 Non-Fungible Token Standard, optional enumeration extension886/// @title ERC-721 Non-Fungible Token Standard, optional enumeration extension845/// @dev See https://eips.ethereum.org/EIPS/eip-721887/// @dev See https://eips.ethereum.org/EIPS/eip-721pallets/refungible/CHANGELOG.mddiffbeforeafterboth445<!-- bureaucrate goes here -->5<!-- bureaucrate goes here -->667## [0.2.9] - 2022-11-1889### Added1011- The functions `description`, `crossOwnerOf`, `tokenProperties` to `ERC721UniqueExtensions` interface.127## [0.2.8] - 2022-11-1413## [0.2.8] - 2022-11-148149### Changed15### Changedpallets/refungible/src/erc.rsdiffbeforeafterboth33use pallet_common::{33use pallet_common::{34 CollectionHandle, CollectionPropertyPermissions,34 CollectionHandle, CollectionPropertyPermissions,35 erc::{CommonEvmHandler, CollectionCall, static_property::key},35 erc::{CommonEvmHandler, CollectionCall, static_property::key},36 CommonCollectionOperations,36};37};37use pallet_evm::{account::CrossAccountId, PrecompileHandle};38use pallet_evm::{account::CrossAccountId, PrecompileHandle};38use pallet_evm_coder_substrate::{call, dispatch_to_evm};39use pallet_evm_coder_substrate::{call, dispatch_to_evm};273#[solidity_interface(name = ERC721Metadata)]274#[solidity_interface(name = ERC721Metadata)]274impl<T: Config> RefungibleHandle<T>275impl<T: Config> RefungibleHandle<T>275where276where276 T::AccountId: From<[u8; 32]>,277 T::AccountId: From<[u8; 32]> + AsRef<[u8; 32]>,277{278{278 /// @notice A descriptive name for a collection of NFTs in this contract279 /// @notice A descriptive name for a collection of NFTs in this contract279 /// @dev real implementation of this function lies in `ERC721UniqueExtensions`280 /// @dev real implementation of this function lies in `ERC721UniqueExtensions`713#[solidity_interface(name = ERC721UniqueExtensions)]714#[solidity_interface(name = ERC721UniqueExtensions)]714impl<T: Config> RefungibleHandle<T>715impl<T: Config> RefungibleHandle<T>715where716where716 T::AccountId: From<[u8; 32]>,717 T::AccountId: From<[u8; 32]> + AsRef<[u8; 32]>,717{718{718 /// @notice A descriptive name for a collection of NFTs in this contract719 /// @notice A descriptive name for a collection of NFTs in this contract719 fn name(&self) -> Result<string> {720 fn name(&self) -> Result<string> {727 Ok(string::from_utf8_lossy(&self.token_prefix).into())728 Ok(string::from_utf8_lossy(&self.token_prefix).into())728 }729 }729730731 /// @notice A description for the collection.732 fn description(&self) -> Result<string> {733 Ok(decode_utf16(self.description.iter().copied())734 .map(|r| r.unwrap_or(REPLACEMENT_CHARACTER))735 .collect::<string>())736 }737738 /// Returns the owner (in cross format) of the token.739 ///740 /// @param tokenId Id for the token.741 fn cross_owner_of(&self, token_id: uint256) -> Result<EthCrossAccount> {742 Self::token_owner(&self, token_id.try_into()?)743 .map(|o| EthCrossAccount::from_sub_cross_account::<T>(&o))744 .ok_or(Error::Revert("key too large".into()))745 }746747 /// Returns the token properties.748 ///749 /// @param tokenId Id for the token.750 /// @param keys Properties keys. Empty keys for all propertyes.751 /// @return Vector of properties key/value pairs.752 fn token_properties(753 &self,754 token_id: uint256,755 keys: Vec<string>,756 ) -> Result<Vec<(string, bytes)>> {757 let keys = keys758 .into_iter()759 .map(|key| {760 <Vec<u8>>::from(key)761 .try_into()762 .map_err(|_| Error::Revert("key too large".into()))763 })764 .collect::<Result<Vec<_>>>()?;765766 <Self as CommonCollectionOperations<T>>::token_properties(767 &self,768 token_id.try_into()?,769 if keys.is_empty() { None } else { Some(keys) },770 )771 .into_iter()772 .map(|p| {773 let key = string::from_utf8(p.key.to_vec())774 .map_err(|e| Error::Revert(alloc::format!("{}", e)))?;775 let value = bytes(p.value.to_vec());776 Ok((key, value))777 })778 .collect::<Result<Vec<_>>>()779 }730 /// @notice Transfer ownership of an RFT780 /// @notice Transfer ownership of an RFT731 /// @dev Throws unless `msg.sender` is the current owner. Throws if `to`781 /// @dev Throws unless `msg.sender` is the current owner. Throws if `to`732 /// is the zero address. Throws if `tokenId` is not a valid RFT.782 /// is the zero address. Throws if `tokenId` is not a valid RFT.pallets/refungible/src/stubs/UniqueRefungible.soldiffbeforeafterboth700 return "";700 return "";701 }701 }702703 /// @notice A description for the collection.704 /// @dev EVM selector for this function is: 0x7284e416,705 /// or in textual repr: description()706 function description() public view returns (string memory) {707 require(false, stub_error);708 dummy;709 return "";710 }711712 /// Returns the owner (in cross format) of the token.713 ///714 /// @param tokenId Id for the token.715 /// @dev EVM selector for this function is: 0x2b29dace,716 /// or in textual repr: crossOwnerOf(uint256)717 function crossOwnerOf(uint256 tokenId) public view returns (EthCrossAccount memory) {718 require(false, stub_error);719 tokenId;720 dummy;721 return EthCrossAccount(0x0000000000000000000000000000000000000000, 0);722 }723724 /// Returns the token properties.725 ///726 /// @param tokenId Id for the token.727 /// @param keys Properties keys. Empty keys for all propertyes.728 /// @return Vector of properties key/value pairs.729 /// @dev EVM selector for this function is: 0xefc26c69,730 /// or in textual repr: tokenProperties(uint256,string[])731 function tokenProperties(uint256 tokenId, string[] memory keys) public view returns (Tuple8[] memory) {732 require(false, stub_error);733 tokenId;734 keys;735 dummy;736 return new Tuple8[](0);737 }702738703 /// @notice Transfer ownership of an RFT739 /// @notice Transfer ownership of an RFT704 /// @dev Throws unless `msg.sender` is the current owner. Throws if `to`740 /// @dev Throws unless `msg.sender` is the current owner. Throws if `to`840 string field_1;876 string field_1;841}877}878879/// @dev anonymous struct880struct Tuple8 {881 string field_0;882 bytes field_1;883}842884843/// @title ERC-721 Non-Fungible Token Standard, optional enumeration extension885/// @title ERC-721 Non-Fungible Token Standard, optional enumeration extension844/// @dev See https://eips.ethereum.org/EIPS/eip-721886/// @dev See https://eips.ethereum.org/EIPS/eip-721tests/src/eth/abi/fungible.jsondiffbeforeafterboth281 "stateMutability": "nonpayable",281 "stateMutability": "nonpayable",282 "type": "function"282 "type": "function"283 },283 },284 {285 "inputs": [],286 "name": "description",287 "outputs": [{ "internalType": "string", "name": "", "type": "string" }],288 "stateMutability": "view",289 "type": "function"290 },284 {291 {285 "inputs": [],292 "inputs": [],286 "name": "hasCollectionPendingSponsor",293 "name": "hasCollectionPendingSponsor",tests/src/eth/abi/nonFungible.jsondiffbeforeafterboth295 "stateMutability": "view",295 "stateMutability": "view",296 "type": "function"296 "type": "function"297 },297 },298 {299 "inputs": [300 { "internalType": "uint256", "name": "tokenId", "type": "uint256" }301 ],302 "name": "crossOwnerOf",303 "outputs": [304 {305 "components": [306 { "internalType": "address", "name": "eth", "type": "address" },307 { "internalType": "uint256", "name": "sub", "type": "uint256" }308 ],309 "internalType": "struct EthCrossAccount",310 "name": "",311 "type": "tuple"312 }313 ],314 "stateMutability": "view",315 "type": "function"316 },298 {317 {299 "inputs": [318 "inputs": [300 { "internalType": "string[]", "name": "keys", "type": "string[]" }319 { "internalType": "string[]", "name": "keys", "type": "string[]" }314 "stateMutability": "nonpayable",333 "stateMutability": "nonpayable",315 "type": "function"334 "type": "function"316 },335 },336 {337 "inputs": [],338 "name": "description",339 "outputs": [{ "internalType": "string", "name": "", "type": "string" }],340 "stateMutability": "view",341 "type": "function"342 },317 {343 {318 "inputs": [],344 "inputs": [],319 "name": "finishMinting",345 "name": "finishMinting",639 "stateMutability": "view",665 "stateMutability": "view",640 "type": "function"666 "type": "function"641 },667 },668 {669 "inputs": [670 { "internalType": "uint256", "name": "tokenId", "type": "uint256" },671 { "internalType": "string[]", "name": "keys", "type": "string[]" }672 ],673 "name": "tokenProperties",674 "outputs": [675 {676 "components": [677 { "internalType": "string", "name": "field_0", "type": "string" },678 { "internalType": "bytes", "name": "field_1", "type": "bytes" }679 ],680 "internalType": "struct Tuple8[]",681 "name": "",682 "type": "tuple[]"683 }684 ],685 "stateMutability": "view",686 "type": "function"687 },642 {688 {643 "inputs": [689 "inputs": [644 { "internalType": "uint256", "name": "tokenId", "type": "uint256" }690 { "internalType": "uint256", "name": "tokenId", "type": "uint256" }tests/src/eth/abi/reFungible.jsondiffbeforeafterboth277 "stateMutability": "view",277 "stateMutability": "view",278 "type": "function"278 "type": "function"279 },279 },280 {281 "inputs": [282 { "internalType": "uint256", "name": "tokenId", "type": "uint256" }283 ],284 "name": "crossOwnerOf",285 "outputs": [286 {287 "components": [288 { "internalType": "address", "name": "eth", "type": "address" },289 { "internalType": "uint256", "name": "sub", "type": "uint256" }290 ],291 "internalType": "struct EthCrossAccount",292 "name": "",293 "type": "tuple"294 }295 ],296 "stateMutability": "view",297 "type": "function"298 },280 {299 {281 "inputs": [300 "inputs": [282 { "internalType": "string[]", "name": "keys", "type": "string[]" }301 { "internalType": "string[]", "name": "keys", "type": "string[]" }296 "stateMutability": "nonpayable",315 "stateMutability": "nonpayable",297 "type": "function"316 "type": "function"298 },317 },318 {319 "inputs": [],320 "name": "description",321 "outputs": [{ "internalType": "string", "name": "", "type": "string" }],322 "stateMutability": "view",323 "type": "function"324 },299 {325 {300 "inputs": [],326 "inputs": [],301 "name": "finishMinting",327 "name": "finishMinting",630 "stateMutability": "view",656 "stateMutability": "view",631 "type": "function"657 "type": "function"632 },658 },659 {660 "inputs": [661 { "internalType": "uint256", "name": "tokenId", "type": "uint256" },662 { "internalType": "string[]", "name": "keys", "type": "string[]" }663 ],664 "name": "tokenProperties",665 "outputs": [666 {667 "components": [668 { "internalType": "string", "name": "field_0", "type": "string" },669 { "internalType": "bytes", "name": "field_1", "type": "bytes" }670 ],671 "internalType": "struct Tuple8[]",672 "name": "",673 "type": "tuple[]"674 }675 ],676 "stateMutability": "view",677 "type": "function"678 },633 {679 {634 "inputs": [680 "inputs": [635 { "internalType": "uint256", "name": "tokenId", "type": "uint256" }681 { "internalType": "uint256", "name": "tokenId", "type": "uint256" }tests/src/eth/api/UniqueFungible.soldiffbeforeafterboth292292293/// @dev the ERC-165 identifier for this interface is 0x29f4dcd9293/// @dev the ERC-165 identifier for this interface is 0x29f4dcd9294interface ERC20UniqueExtensions is Dummy, ERC165 {294interface ERC20UniqueExtensions is Dummy, ERC165 {295 /// @notice A description for the collection.296 /// @dev EVM selector for this function is: 0x7284e416,297 /// or in textual repr: description()298 function description() external view returns (string memory);299295 /// @dev EVM selector for this function is: 0x0ecd0ab0,300 /// @dev EVM selector for this function is: 0x0ecd0ab0,296 /// or in textual repr: approveCross((address,uint256),uint256)301 /// or in textual repr: approveCross((address,uint256),uint256)tests/src/eth/api/UniqueNFT.soldiffbeforeafterboth45 /// @param properties settable properties45 /// @param properties settable properties46 /// @dev EVM selector for this function is: 0x14ed3a6e,46 /// @dev EVM selector for this function is: 0x14ed3a6e,47 /// or in textual repr: setProperties(uint256,(string,bytes)[])47 /// or in textual repr: setProperties(uint256,(string,bytes)[])48 function setProperties(uint256 tokenId, Property[] memory properties) external;48 function setProperties(uint256 tokenId, Tuple21[] memory properties) external;494950 // /// @notice Delete token property value.50 // /// @notice Delete token property value.51 // /// @dev Throws error if `msg.sender` has no permission to edit the property.51 // /// @dev Throws error if `msg.sender` has no permission to edit the property.95 /// @param properties Vector of properties key/value pair.95 /// @param properties Vector of properties key/value pair.96 /// @dev EVM selector for this function is: 0x50b26b2a,96 /// @dev EVM selector for this function is: 0x50b26b2a,97 /// or in textual repr: setCollectionProperties((string,bytes)[])97 /// or in textual repr: setCollectionProperties((string,bytes)[])98 function setCollectionProperties(Property[] memory properties) external;98 function setCollectionProperties(Tuple21[] memory properties) external;9999100 // /// Delete collection property.100 // /// Delete collection property.101 // ///101 // ///127 /// @return Vector of properties key/value pairs.127 /// @return Vector of properties key/value pairs.128 /// @dev EVM selector for this function is: 0x285fb8e6,128 /// @dev EVM selector for this function is: 0x285fb8e6,129 /// or in textual repr: collectionProperties(string[])129 /// or in textual repr: collectionProperties(string[])130 function collectionProperties(string[] memory keys) external view returns (Tuple23[] memory);130 function collectionProperties(string[] memory keys) external view returns (Tuple21[] memory);131131132 // /// Set the sponsor of the collection.132 // /// Set the sponsor of the collection.133 // ///133 // ///169 /// @return Tuble with sponsor address and his substrate mirror. If there is no confirmed sponsor error "Contract has no sponsor" throw.169 /// @return Tuble with sponsor address and his substrate mirror. If there is no confirmed sponsor error "Contract has no sponsor" throw.170 /// @dev EVM selector for this function is: 0x6ec0a9f1,170 /// @dev EVM selector for this function is: 0x6ec0a9f1,171 /// or in textual repr: collectionSponsor()171 /// or in textual repr: collectionSponsor()172 function collectionSponsor() external view returns (Tuple26 memory);172 function collectionSponsor() external view returns (Tuple24 memory);173173174 /// Set limits for the collection.174 /// Set limits for the collection.175 /// @dev Throws error if limit not found.175 /// @dev Throws error if limit not found.346}346}347347348/// @dev anonymous struct348/// @dev anonymous struct349struct Tuple26 {349struct Tuple24 {350 address field_0;350 address field_0;351 uint256 field_1;351 uint256 field_1;352}352}353353354/// @dev anonymous struct354/// @dev anonymous struct355struct Tuple23 {355struct Tuple21 {356 string field_0;356 string field_0;357 bytes field_1;357 bytes field_1;358}358}452}452}453453454/// @title Unique extensions for ERC721.454/// @title Unique extensions for ERC721.455/// @dev the ERC-165 identifier for this interface is 0x0e9fc611455/// @dev the ERC-165 identifier for this interface is 0x244543ee456interface ERC721UniqueExtensions is Dummy, ERC165 {456interface ERC721UniqueExtensions is Dummy, ERC165 {457 /// @notice A descriptive name for a collection of NFTs in this contract457 /// @notice A descriptive name for a collection of NFTs in this contract458 /// @dev EVM selector for this function is: 0x06fdde03,458 /// @dev EVM selector for this function is: 0x06fdde03,464 /// or in textual repr: symbol()464 /// or in textual repr: symbol()465 function symbol() external view returns (string memory);465 function symbol() external view returns (string memory);466467 /// @notice A description for the collection.468 /// @dev EVM selector for this function is: 0x7284e416,469 /// or in textual repr: description()470 function description() external view returns (string memory);471472 /// Returns the owner (in cross format) of the token.473 ///474 /// @param tokenId Id for the token.475 /// @dev EVM selector for this function is: 0x2b29dace,476 /// or in textual repr: crossOwnerOf(uint256)477 function crossOwnerOf(uint256 tokenId) external view returns (EthCrossAccount memory);478479 /// Returns the token properties.480 ///481 /// @param tokenId Id for the token.482 /// @param keys Properties keys. Empty keys for all propertyes.483 /// @return Vector of properties key/value pairs.484 /// @dev EVM selector for this function is: 0xefc26c69,485 /// or in textual repr: tokenProperties(uint256,string[])486 function tokenProperties(uint256 tokenId, string[] memory keys) external view returns (Tuple7[] memory);466487467 /// @notice Set or reaffirm the approved address for an NFT488 /// @notice Set or reaffirm the approved address for an NFT468 /// @dev The zero address indicates there is no approved address.489 /// @dev The zero address indicates there is no approved address.546 // /// @param tokens array of pairs of token ID and token URI for minted tokens567 // /// @param tokens array of pairs of token ID and token URI for minted tokens547 // /// @dev EVM selector for this function is: 0x36543006,568 // /// @dev EVM selector for this function is: 0x36543006,548 // /// or in textual repr: mintBulkWithTokenURI(address,(uint256,string)[])569 // /// or in textual repr: mintBulkWithTokenURI(address,(uint256,string)[])549 // function mintBulkWithTokenURI(address to, Tuple11[] memory tokens) external returns (bool);570 // function mintBulkWithTokenURI(address to, Tuple10[] memory tokens) external returns (bool);550571551}572}552573553/// @dev anonymous struct574/// @dev anonymous struct554struct Tuple11 {575struct Tuple10 {555 uint256 field_0;576 uint256 field_0;556 string field_1;577 string field_1;557}578}579580/// @dev anonymous struct581struct Tuple7 {582 string field_0;583 bytes field_1;584}558585559/// @title ERC-721 Non-Fungible Token Standard, optional enumeration extension586/// @title ERC-721 Non-Fungible Token Standard, optional enumeration extension560/// @dev See https://eips.ethereum.org/EIPS/eip-721587/// @dev See https://eips.ethereum.org/EIPS/eip-721tests/src/eth/api/UniqueRefungible.soldiffbeforeafterboth462 /// or in textual repr: symbol()462 /// or in textual repr: symbol()463 function symbol() external view returns (string memory);463 function symbol() external view returns (string memory);464465 /// @notice A description for the collection.466 /// @dev EVM selector for this function is: 0x7284e416,467 /// or in textual repr: description()468 function description() external view returns (string memory);469470 /// Returns the owner (in cross format) of the token.471 ///472 /// @param tokenId Id for the token.473 /// @dev EVM selector for this function is: 0x2b29dace,474 /// or in textual repr: crossOwnerOf(uint256)475 function crossOwnerOf(uint256 tokenId) external view returns (EthCrossAccount memory);476477 /// Returns the token properties.478 ///479 /// @param tokenId Id for the token.480 /// @param keys Properties keys. Empty keys for all propertyes.481 /// @return Vector of properties key/value pairs.482 /// @dev EVM selector for this function is: 0xefc26c69,483 /// or in textual repr: tokenProperties(uint256,string[])484 function tokenProperties(uint256 tokenId, string[] memory keys) external view returns (Tuple7[] memory);464485465 /// @notice Transfer ownership of an RFT486 /// @notice Transfer ownership of an RFT466 /// @dev Throws unless `msg.sender` is the current owner. Throws if `to`487 /// @dev Throws unless `msg.sender` is the current owner. Throws if `to`555 string field_1;576 string field_1;556}577}578579/// @dev anonymous struct580struct Tuple7 {581 string field_0;582 bytes field_1;583}557584558/// @title ERC-721 Non-Fungible Token Standard, optional enumeration extension585/// @title ERC-721 Non-Fungible Token Standard, optional enumeration extension559/// @dev See https://eips.ethereum.org/EIPS/eip-721586/// @dev See https://eips.ethereum.org/EIPS/eip-721tests/src/eth/base.test.tsdiffbeforeafterboth117 });117 });118118119 itEth('ERC721UniqueExtensions support', async ({helper}) => {119 itEth('ERC721UniqueExtensions support', async ({helper}) => {120 await checkInterface(helper, '0x0e9fc611', true, true);120 await checkInterface(helper, '0x922a115f', true, true);121 });121 });122122123 itEth('ERC721Burnable - 0x42966c68 - support', async ({helper}) => {123 itEth('ERC721Burnable - 0x42966c68 - support', async ({helper}) => {tests/src/eth/createFTCollection.test.tsdiffbeforeafterboth36 const owner = await helper.eth.createAccountWithBalance(donor);36 const owner = await helper.eth.createAccountWithBalance(donor);37 const sponsor = await helper.eth.createAccountWithBalance(donor);37 const sponsor = await helper.eth.createAccountWithBalance(donor);38 const ss58Format = helper.chain.getChainProperties().ss58Format;38 const ss58Format = helper.chain.getChainProperties().ss58Format;39 const description = 'absolutely anything';40 39 const {collectionId, collectionAddress} = await helper.eth.createFungibleCollection(owner, 'Sponsor', DECIMALS, 'absolutely anything', 'ENVY');41 const {collectionId, collectionAddress} = await helper.eth.createFungibleCollection(owner, 'Sponsor', DECIMALS, description, 'ENVY');404241 const collection = helper.ethNativeContract.collection(collectionAddress, 'rft', owner, true);43 const collection = helper.ethNativeContract.collection(collectionAddress, 'ft', owner, true);42 await collection.methods.setCollectionSponsor(sponsor).send();44 await collection.methods.setCollectionSponsor(sponsor).send();434544 let data = (await helper.rft.getData(collectionId))!;46 let data = (await helper.rft.getData(collectionId))!;57 const owner = await helper.eth.createAccountWithBalance(donor);59 const owner = await helper.eth.createAccountWithBalance(donor);58 const sponsor = await helper.eth.createAccountWithBalance(donor);60 const sponsor = await helper.eth.createAccountWithBalance(donor);59 const ss58Format = helper.chain.getChainProperties().ss58Format;61 const ss58Format = helper.chain.getChainProperties().ss58Format;62 const description = 'absolutely anything';60 const {collectionId, collectionAddress} = await helper.eth.createFungibleCollection(owner, 'Sponsor', DECIMALS, 'absolutely anything', 'ENVY');63 const {collectionId, collectionAddress} = await helper.eth.createFungibleCollection(owner, 'Sponsor', DECIMALS, description, 'ENVY');6164 62 const collection = helper.ethNativeContract.collection(collectionAddress, 'rft', owner);65 const collection = helper.ethNativeContract.collection(collectionAddress, 'rft', owner);63 const sponsorCross = helper.ethCrossAccount.fromAddress(sponsor);66 const sponsorCross = helper.ethCrossAccount.fromAddress(sponsor);737674 data = (await helper.rft.getData(collectionId))!;77 data = (await helper.rft.getData(collectionId))!;75 expect(data.raw.sponsorship.Confirmed).to.be.equal(evmToAddress(sponsor, Number(ss58Format)));78 expect(data.raw.sponsorship.Confirmed).to.be.equal(evmToAddress(sponsor, Number(ss58Format)));79 expect(await collection.methods.description().call()).to.deep.equal(description);76 });80 });778178 itEth('Set limits', async ({helper}) => {82 itEth('Set limits', async ({helper}) => {tests/src/eth/createNFTCollection.test.tsdiffbeforeafterboth28 });28 });29 });29 });303031 itEth('Create collection with properties', async ({helper}) => {31 itEth('Create collection with properties & get desctription', async ({helper}) => {32 const owner = await helper.eth.createAccountWithBalance(donor);32 const owner = await helper.eth.createAccountWithBalance(donor);333334 const name = 'CollectionEVM';34 const name = 'CollectionEVM';37 const baseUri = 'BaseURI';37 const baseUri = 'BaseURI';383839 const {collectionId, collectionAddress, events} = await helper.eth.createERC721MetadataCompatibleNFTCollection(owner, name, description, prefix, baseUri);39 const {collectionId, collectionAddress, events} = await helper.eth.createERC721MetadataCompatibleNFTCollection(owner, name, description, prefix, baseUri);4040 const contract = helper.ethNativeContract.collection(collectionAddress, 'nft');41 41 expect(events).to.be.deep.equal([42 expect(events).to.be.deep.equal([42 {43 {57 expect(data.raw.tokenPrefix).to.be.eq(prefix);58 expect(data.raw.tokenPrefix).to.be.eq(prefix);58 expect(data.raw.mode).to.be.eq('NFT');59 expect(data.raw.mode).to.be.eq('NFT');5960 61 expect(await contract.methods.description().call()).to.deep.equal(description);62 60 const options = await collection.getOptions();63 const options = await collection.getOptions();61 expect(options.tokenPropertyPermissions).to.be.deep.equal([64 expect(options.tokenPropertyPermissions).to.be.deep.equal([92 expect(data.raw.sponsorship.Confirmed).to.be.equal(evmToAddress(sponsor, Number(ss58Format)));95 expect(data.raw.sponsorship.Confirmed).to.be.equal(evmToAddress(sponsor, Number(ss58Format)));93 });96 });949795 itEth('[cross] Set sponsorship', async ({helper}) => {98 itEth('[cross] Set sponsorship & get description', async ({helper}) => {96 const owner = await helper.eth.createAccountWithBalance(donor);99 const owner = await helper.eth.createAccountWithBalance(donor);97 const sponsor = await helper.eth.createAccountWithBalance(donor);100 const sponsor = await helper.eth.createAccountWithBalance(donor);98 const ss58Format = helper.chain.getChainProperties().ss58Format;101 const ss58Format = helper.chain.getChainProperties().ss58Format;102 const description = 'absolutely anything';99 const {collectionId, collectionAddress} = await helper.eth.createNFTCollection(owner, 'Sponsor', 'absolutely anything', 'ROC');103 const {collectionId, collectionAddress} = await helper.eth.createNFTCollection(owner, 'Sponsor', description, 'ROC');100104101 const collection = helper.ethNativeContract.collection(collectionAddress, 'nft', owner);105 const collection = helper.ethNativeContract.collection(collectionAddress, 'nft', owner);102 const sponsorCross = helper.ethCrossAccount.fromAddress(sponsor);106 const sponsorCross = helper.ethCrossAccount.fromAddress(sponsor);113 data = (await helper.nft.getData(collectionId))!;117 data = (await helper.nft.getData(collectionId))!;114 expect(data.raw.sponsorship.Confirmed).to.be.equal(evmToAddress(sponsor, Number(ss58Format)));118 expect(data.raw.sponsorship.Confirmed).to.be.equal(evmToAddress(sponsor, Number(ss58Format)));119 120 expect(await sponsorCollection.methods.description().call()).to.deep.equal(description);115 });121 });116122117 itEth('Set limits', async ({helper}) => {123 itEth('Set limits', async ({helper}) => {tests/src/eth/createRFTCollection.test.tsdiffbeforeafterboth535354 54 555556 itEth('Create collection with properties', async ({helper}) => {56 itEth('Create collection with properties & get description', async ({helper}) => {57 const owner = await helper.eth.createAccountWithBalance(donor);57 const owner = await helper.eth.createAccountWithBalance(donor);585859 const name = 'CollectionEVM';59 const name = 'CollectionEVM';60 const description = 'Some description';60 const description = 'Some description';61 const prefix = 'token prefix';61 const prefix = 'token prefix';62 const baseUri = 'BaseURI';62 const baseUri = 'BaseURI';636364 const {collectionId} = await helper.eth.createERC721MetadataCompatibleRFTCollection(owner, name, description, prefix, baseUri);64 const {collectionId, collectionAddress} = await helper.eth.createERC721MetadataCompatibleRFTCollection(owner, name, description, prefix, baseUri);65 const contract = helper.ethNativeContract.collection(collectionAddress, 'nft');656666 const collection = helper.rft.getCollectionObject(collectionId);67 const collection = helper.rft.getCollectionObject(collectionId);67 const data = (await collection.getData())!;68 const data = (await collection.getData())!;71 expect(data.raw.tokenPrefix).to.be.eq(prefix);72 expect(data.raw.tokenPrefix).to.be.eq(prefix);72 expect(data.raw.mode).to.be.eq('ReFungible');73 expect(data.raw.mode).to.be.eq('ReFungible');7475 expect(await contract.methods.description().call()).to.deep.equal(description);737674 const options = await collection.getOptions();77 const options = await collection.getOptions();75 expect(options.tokenPropertyPermissions).to.be.deep.equal([78 expect(options.tokenPropertyPermissions).to.be.deep.equal([tests/src/eth/nonFungible.test.tsdiffbeforeafterboth17import {itEth, usingEthPlaygrounds, expect, EthUniqueHelper} from './util';17import {itEth, usingEthPlaygrounds, expect, EthUniqueHelper} from './util';18import {IKeyringPair} from '@polkadot/types/types';18import {IKeyringPair} from '@polkadot/types/types';19import {Contract} from 'web3-eth-contract';19import {Contract} from 'web3-eth-contract';20import exp from 'constants';2021212222describe('NFT: Information getting', () => {23describe('NFT: Information getting', () => {149 });150 });150 });151 });151152152 itEth('Can perform mint()', async ({helper}) => {153 itEth('Can perform mint() & get crossOwner()', async ({helper}) => {153 const owner = await helper.eth.createAccountWithBalance(donor);154 const owner = await helper.eth.createAccountWithBalance(donor);154 const receiver = helper.eth.createAccount();155 const receiver = helper.eth.createAccount();155156166 expect(event.returnValues.to).to.be.equal(receiver);167 expect(event.returnValues.to).to.be.equal(receiver);167168168 expect(await contract.methods.tokenURI(tokenId).call()).to.be.equal('Test URI');169 expect(await contract.methods.tokenURI(tokenId).call()).to.be.equal('Test URI');169170 console.log(await contract.methods.crossOwnerOf(tokenId).call());171 expect(await contract.methods.crossOwnerOf(tokenId).call()).to.be.like([receiver, '0']);170 // TODO: this wont work right now, need release 919000 first172 // TODO: this wont work right now, need release 919000 first171 // await helper.methods.setOffchainSchema(collectionIdAddress, 'https://offchain-service.local/token-info/{id}').send();173 // await helper.methods.setOffchainSchema(collectionIdAddress, 'https://offchain-service.local/token-info/{id}').send();172 // const tokenUri = await contract.methods.tokenURI(nextTokenId).call();174 // const tokenUri = await contract.methods.tokenURI(nextTokenId).call();tests/src/eth/reFungible.test.tsdiffbeforeafterboth117 });117 });118 });118 });119119120 itEth('Can perform mint()', async ({helper}) => {120 itEth('Can perform mint() & crossOwnerOf()', async ({helper}) => {121 const owner = await helper.eth.createAccountWithBalance(donor);121 const owner = await helper.eth.createAccountWithBalance(donor);122 const receiver = helper.eth.createAccount();122 const receiver = helper.eth.createAccount();123 const {collectionAddress} = await helper.eth.createERC721MetadataCompatibleRFTCollection(owner, 'Minty', '6', '6', '');123 const {collectionAddress} = await helper.eth.createERC721MetadataCompatibleRFTCollection(owner, 'Minty', '6', '6', '');132 const tokenId = event.returnValues.tokenId;132 const tokenId = event.returnValues.tokenId;133 expect(tokenId).to.be.equal('1');133 expect(tokenId).to.be.equal('1');134134135 expect(await contract.methods.crossOwnerOf(tokenId).call()).to.be.like([receiver, '0']);135 expect(await contract.methods.tokenURI(tokenId).call()).to.be.equal('Test URI');136 expect(await contract.methods.tokenURI(tokenId).call()).to.be.equal('Test URI');136 });137 });137138tests/src/eth/tokenProperties.test.tsdiffbeforeafterboth14// You should have received a copy of the GNU General Public License14// You should have received a copy of the GNU General Public License15// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.15// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.161617import {itEth, usingEthPlaygrounds, expect} from './util';17import {itEth, usingEthPlaygrounds, expect, EthUniqueHelper} from './util';18import {IKeyringPair} from '@polkadot/types/types';18import {IKeyringPair} from '@polkadot/types/types';19import {ITokenPropertyPermission} from '../util/playgrounds/types';19import {ITokenPropertyPermission, TCollectionMode} from '../util/playgrounds/types';20import {Pallets} from '../util';20import {Pallets} from '../util';21import {UniqueNFTCollection, UniqueRFTCollection} from '../util/playgrounds/unique';212222describe('EVM token properties', () => {23describe('EVM token properties', () => {23 let donor: IKeyringPair;24 let donor: IKeyringPair;95 expect(value).to.equal('testValue');96 expect(value).to.equal('testValue');96 });97 });97 98 98 itEth('Can be multiple set for NFT ', async({helper}) => {99 async function checkProps(helper: EthUniqueHelper, mode: TCollectionMode) {99 const caller = await helper.eth.createAccountWithBalance(donor);100 const caller = await helper.eth.createAccountWithBalance(donor);100 101 101 const properties = Array(5).fill(0).map((_, i) => { return {key: `key_${i}`, value: Buffer.from(`value_${i}`)}; });102 const properties = Array(5).fill(0).map((_, i) => { return {key: `key_${i}`, value: Buffer.from(`value_${i}`)}; });102 const permissions: ITokenPropertyPermission[] = properties.map(p => { return {key: p.key, permission: {tokenOwner: true,103 const permissions: ITokenPropertyPermission[] = properties.map(p => { return {key: p.key, permission: {tokenOwner: true,103 collectionAdmin: true,104 collectionAdmin: true,104 mutable: true}}; });105 mutable: true}}; });105 106 106 const collection = await helper.nft.mintCollection(alice, {107 const collection = await helper[mode].mintCollection(alice, {107 tokenPrefix: 'ethp',108 tokenPrefix: 'ethp',108 tokenPropertyPermissions: permissions,109 tokenPropertyPermissions: permissions,109 });110 }) as UniqueNFTCollection | UniqueRFTCollection;110 111 111 const token = await collection.mintToken(alice);112 const token = await collection.mintToken(alice);112 113 116 await collection.addAdmin(alice, {Ethereum: caller});118 await collection.addAdmin(alice, {Ethereum: caller});117119 118 const address = helper.ethAddress.fromCollectionId(collection.collectionId);120 const address = helper.ethAddress.fromCollectionId(collection.collectionId);119 const contract = helper.ethNativeContract.collection(address, 'nft', caller);121 const contract = helper.ethNativeContract.collection(address, mode, caller);122 123 expect(await contract.methods.tokenProperties(token.tokenId, []).call()).to.be.deep.equal([]);120124121 await contract.methods.setProperties(token.tokenId, properties).send({from: caller});125 await contract.methods.setProperties(token.tokenId, properties).send({from: caller});122126123 const values = await token.getProperties(properties.map(p => p.key));127 const values = await token.getProperties(properties.map(p => p.key));124 expect(values).to.be.deep.equal(properties.map(p => { return {key: p.key, value: p.value.toString()}; }));128 expect(values).to.be.deep.equal(properties.map(p => { return {key: p.key, value: p.value.toString()}; }));129 130 expect(await contract.methods.tokenProperties(token.tokenId, []).call()).to.be.like(properties131 .map(p => { return helper.ethProperty.property(p.key, p.value.toString()); }));132 133 expect(await contract.methods.tokenProperties(token.tokenId, [properties[0].key]).call())134 .to.be.like([helper.ethProperty.property(properties[0].key, properties[0].value.toString())]);125 });135 }126 136 137 itEth('Can be multiple set/read for NFT ', async({helper}) => {138 await checkProps(helper, 'nft');139 });140 127 itEth.ifWithPallets('Can be multiple set for RFT ', [Pallets.ReFungible], async({helper}) => {141 itEth.ifWithPallets('Can be multiple set/read for RFT ', [Pallets.ReFungible], async({helper}) => {128 const caller = await helper.eth.createAccountWithBalance(donor);129 130 const properties = Array(5).fill(0).map((_, i) => { return {key: `key_${i}`, value: Buffer.from(`value_${i}`)}; });131 const permissions: ITokenPropertyPermission[] = properties.map(p => { return {key: p.key, permission: {tokenOwner: true,132 collectionAdmin: true,133 mutable: true}}; });134 135 const collection = await helper.rft.mintCollection(alice, {142 await checkProps(helper, 'rft');136 tokenPrefix: 'ethp',137 tokenPropertyPermissions: permissions,138 });139 140 const token = await collection.mintToken(alice);141 142 const valuesBefore = await token.getProperties(properties.map(p => p.key));143 expect(valuesBefore).to.be.deep.equal([]);144 145 await collection.addAdmin(alice, {Ethereum: caller});146147 const address = helper.ethAddress.fromCollectionId(collection.collectionId);148 const contract = helper.ethNativeContract.collection(address, 'rft', caller);149150 await contract.methods.setProperties(token.tokenId, properties).send({from: caller});151152 const values = await token.getProperties(properties.map(p => p.key));153 expect(values).to.be.deep.equal(properties.map(p => { return {key: p.key, value: p.value.toString()}; }));154 });143 });155144 156 itEth('Can be deleted', async({helper}) => {145 itEth('Can be deleted', async({helper}) => {