difftreelog
Merge pull request #776 from UniqueNetwork/feature/evm_set-get_tokenPropertyPermissions
in: master
Feature/evm_set-get_tokenPropertyPermissions
22 files changed
Cargo.lockdiffbeforeafterboth634263426343[[package]]6343[[package]]6344name = "pallet-nonfungible"6344name = "pallet-nonfungible"6345version = "0.1.9"6345version = "0.1.11"6346dependencies = [6346dependencies = [6347 "ethereum 0.14.0",6347 "ethereum 0.14.0",6348 "evm-coder",6348 "evm-coder",650165016502[[package]]6502[[package]]6503name = "pallet-refungible"6503name = "pallet-refungible"6504version = "0.2.8"6504version = "0.2.10"6505dependencies = [6505dependencies = [6506 "derivative",6506 "derivative",6507 "ethereum 0.14.0",6507 "ethereum 0.14.0",crates/evm-coder/tests/abi_derive_generation.rsdiffbeforeafterboth740 /// Some docs740 /// Some docs741 /// At multi741 /// At multi742 /// line742 /// line743 #[derive(AbiCoder, Debug, PartialEq, Default)]743 #[derive(AbiCoder, Debug, PartialEq, Default, Clone, Copy)]744 #[repr(u8)]744 #[repr(u8)]745 enum Color {745 enum Color {746 /// Docs for Red746 /// Docs for Redpallets/common/src/eth.rsdiffbeforeafterboth163 TokenOwner,163 TokenOwner,164}164}165166/// Ethereum representation of TokenPermissions (see [`up_data_structs::PropertyPermission`]) fields as an enumeration.167#[derive(AbiCoder, Copy, Clone, Default, Debug)]168#[repr(u8)]169pub enum EthTokenPermissions {170 /// Permission to change the property and property permission. See [`up_data_structs::PropertyPermission::mutable`]171 #[default]172 Mutable,173174 /// Change permission for the collection administrator. See [`up_data_structs::PropertyPermission::token_owner`]175 TokenOwner,176177 /// Permission to change the property for the owner of the token. See [`up_data_structs::PropertyPermission::collection_admin`]178 CollectionAdmin,179}165180pallets/nonfungible/CHANGELOG.mddiffbeforeafterboth445<!-- bureaucrate goes here -->5<!-- bureaucrate goes here -->667## [0.1.11] - 2022-12-1689### Added1011- The function `tokenPropertyPermissions` and `setTokenPropertyPermissions` to `TokenProperties` interface.1213### Changed1415- Hide `setTokenPropertyPermission` function in `TokenProperties` interface.167## [0.1.10] - 2022-11-1817## [0.1.10] - 2022-11-188189### Added19### Addedpallets/nonfungible/Cargo.tomldiffbeforeafterboth1[package]1[package]2name = "pallet-nonfungible"2name = "pallet-nonfungible"3version = "0.1.9"3version = "0.1.11"4license = "GPLv3"4license = "GPLv3"5edition = "2021"5edition = "2021"66pallets/nonfungible/src/erc.rsdiffbeforeafterboth34 CollectionPropertiesVec,34 CollectionPropertiesVec,35};35};36use pallet_evm_coder_substrate::dispatch_to_evm;36use pallet_evm_coder_substrate::dispatch_to_evm;37use sp_std::vec::Vec;37use sp_std::{vec::Vec, vec};38use pallet_common::{38use pallet_common::{39 CollectionHandle, CollectionPropertyPermissions, CommonCollectionOperations,39 CollectionHandle, CollectionPropertyPermissions, CommonCollectionOperations,40 erc::{CommonEvmHandler, PrecompileResult, CollectionCall, static_property::key},40 erc::{CommonEvmHandler, PrecompileResult, CollectionCall, static_property::key},41 eth::EthCrossAccount,41 eth::{EthCrossAccount, EthTokenPermissions},42};42};43use pallet_evm::{account::CrossAccountId, PrecompileHandle};43use pallet_evm::{account::CrossAccountId, PrecompileHandle};44use pallet_evm_coder_substrate::call;44use pallet_evm_coder_substrate::call;60 /// @param collectionAdmin Permission to mutate property by collection admin if property is mutable.60 /// @param collectionAdmin Permission to mutate property by collection admin if property is mutable.61 /// @param tokenOwner Permission to mutate property by token owner if property is mutable.61 /// @param tokenOwner Permission to mutate property by token owner if property is mutable.62 #[weight(<SelfWeightOf<T>>::set_token_property_permissions(1))]62 #[weight(<SelfWeightOf<T>>::set_token_property_permissions(1))]63 #[solidity(hide)]63 fn set_token_property_permission(64 fn set_token_property_permission(64 &mut self,65 &mut self,65 caller: caller,66 caller: caller,69 token_owner: bool,70 token_owner: bool,70 ) -> Result<()> {71 ) -> Result<()> {71 let caller = T::CrossAccountId::from_eth(caller);72 let caller = T::CrossAccountId::from_eth(caller);72 <Pallet<T>>::set_property_permission(73 <Pallet<T>>::set_token_property_permissions(73 self,74 self,74 &caller,75 &caller,75 PropertyKeyPermission {76 vec![PropertyKeyPermission {76 key: <Vec<u8>>::from(key)77 key: <Vec<u8>>::from(key)77 .try_into()78 .try_into()78 .map_err(|_| "too long key")?,79 .map_err(|_| "too long key")?,79 permission: PropertyPermission {80 permission: PropertyPermission {80 mutable: is_mutable,81 mutable: is_mutable,81 collection_admin,82 collection_admin,82 token_owner,83 token_owner,83 },84 },84 },85 }],85 )86 )86 .map_err(dispatch_to_evm::<T>)87 .map_err(dispatch_to_evm::<T>)87 }88 }8990 /// @notice Set permissions for token property.91 /// @dev Throws error if `msg.sender` is not admin or owner of the collection.92 /// @param permissions Permissions for keys.93 #[weight(<SelfWeightOf<T>>::set_token_property_permissions(permissions.len() as u32))]94 fn set_token_property_permissions(95 &mut self,96 caller: caller,97 permissions: Vec<(string, Vec<(EthTokenPermissions, bool)>)>,98 ) -> Result<()> {99 let caller = T::CrossAccountId::from_eth(caller);100 const PERMISSIONS_FIELDS_COUNT: usize = 3;101102 let mut perms = Vec::new();103104 for (key, pp) in permissions {105 if pp.len() > PERMISSIONS_FIELDS_COUNT {106 return Err(alloc::format!(107 "Actual number of fields {} for {}, which exceeds the maximum value of {}",108 pp.len(),109 stringify!(EthTokenPermissions),110 PERMISSIONS_FIELDS_COUNT111 )112 .as_str()113 .into());114 }115116 let mut token_permission = PropertyPermission::default();117118 for (perm, value) in pp {119 match perm {120 EthTokenPermissions::Mutable => token_permission.mutable = value,121 EthTokenPermissions::TokenOwner => token_permission.token_owner = value,122 EthTokenPermissions::CollectionAdmin => {123 token_permission.collection_admin = value124 }125 }126 }127128 perms.push(PropertyKeyPermission {129 key: key.into_bytes().try_into().map_err(|_| "too long key")?,130 permission: token_permission,131 });132 }133134 <Pallet<T>>::set_token_property_permissions(self, &caller, perms)135 .map_err(dispatch_to_evm::<T>)136 }137138 /// @notice Get permissions for token properties.139 fn token_property_permissions(140 &self,141 ) -> Result<Vec<(string, Vec<(EthTokenPermissions, bool)>)>> {142 let perms = <Pallet<T>>::token_property_permission(self.id);143 Ok(perms144 .into_iter()145 .map(|(key, pp)| {146 let key = string::from_utf8(key.into_inner()).expect("Stored key must be valid");147 let pp = vec![148 (EthTokenPermissions::Mutable, pp.mutable),149 (EthTokenPermissions::TokenOwner, pp.token_owner),150 (EthTokenPermissions::CollectionAdmin, pp.collection_admin),151 ];152 (key, pp)153 })154 .collect())155 }8815689 /// @notice Set token property value.157 /// @notice Set token property value.90 /// @dev Throws error if `msg.sender` has no permission to edit the property.158 /// @dev Throws error if `msg.sender` has no permission to edit the property.pallets/nonfungible/src/lib.rsdiffbeforeafterboth103 AccessMode, CollectionId, CollectionFlags, CustomDataLimit, TokenId, CreateCollectionData,103 AccessMode, CollectionId, CollectionFlags, CustomDataLimit, TokenId, CreateCollectionData,104 CreateNftExData, mapping::TokenAddressMapping, budget::Budget, Property, PropertyPermission,104 CreateNftExData, mapping::TokenAddressMapping, budget::Budget, Property, PropertyPermission,105 PropertyKey, PropertyValue, PropertyKeyPermission, Properties, PropertyScope, TrySetProperty,105 PropertyKey, PropertyValue, PropertyKeyPermission, Properties, PropertyScope, TrySetProperty,106 TokenChild, AuxPropertyValue,106 TokenChild, AuxPropertyValue, PropertiesPermissionMap,107};107};108use pallet_evm::{account::CrossAccountId, Pallet as PalletEvm};108use pallet_evm::{account::CrossAccountId, Pallet as PalletEvm};109use pallet_common::{109use pallet_common::{824 )824 )825 }825 }826826827 /// Set property permissions for the collection.828 ///829 /// Sender should be the owner or admin of the collection.830 pub fn set_property_permission(827 pub fn token_property_permission(collection_id: CollectionId) -> PropertiesPermissionMap {831 collection: &CollectionHandle<T>,832 sender: &T::CrossAccountId,833 permission: PropertyKeyPermission,834 ) -> DispatchResult {835 <PalletCommon<T>>::set_property_permission(collection, sender, permission)828 <PalletCommon<T>>::property_permissions(collection_id)836 }829 }837830838 pub fn check_token_immediate_ownership(831 pub fn check_token_immediate_ownership(pallets/nonfungible/src/stubs/UniqueNFT.soldiffbeforeafterboth18}18}191920/// @title A contract that allows to set and delete token properties and change token property permissions.20/// @title A contract that allows to set and delete token properties and change token property permissions.21/// @dev the ERC-165 identifier for this interface is 0x91a97a6821/// @dev the ERC-165 identifier for this interface is 0xde0695c222contract TokenProperties is Dummy, ERC165 {22contract TokenProperties is Dummy, ERC165 {23 // /// @notice Set permissions for token property.24 // /// @dev Throws error if `msg.sender` is not admin or owner of the collection.25 // /// @param key Property key.26 // /// @param isMutable Permission to mutate property.27 // /// @param collectionAdmin Permission to mutate property by collection admin if property is mutable.28 // /// @param tokenOwner Permission to mutate property by token owner if property is mutable.29 // /// @dev EVM selector for this function is: 0x222d97fa,30 // /// or in textual repr: setTokenPropertyPermission(string,bool,bool,bool)31 // function setTokenPropertyPermission(string memory key, bool isMutable, bool collectionAdmin, bool tokenOwner) public {32 // require(false, stub_error);33 // key;34 // isMutable;35 // collectionAdmin;36 // tokenOwner;37 // dummy = 0;38 // }3923 /// @notice Set permissions for token property.40 /// @notice Set permissions for token property.24 /// @dev Throws error if `msg.sender` is not admin or owner of the collection.41 /// @dev Throws error if `msg.sender` is not admin or owner of the collection.25 /// @param key Property key.42 /// @param permissions Permissions for keys.26 /// @param isMutable Permission to mutate property.27 /// @param collectionAdmin Permission to mutate property by collection admin if property is mutable.28 /// @param tokenOwner Permission to mutate property by token owner if property is mutable.29 /// @dev EVM selector for this function is: 0x222d97fa,43 /// @dev EVM selector for this function is: 0xbd92983a,30 /// or in textual repr: setTokenPropertyPermission(string,bool,bool,bool)44 /// or in textual repr: setTokenPropertyPermissions((string,(uint8,bool)[])[])31 function setTokenPropertyPermission(45 function setTokenPropertyPermissions(Tuple48[] memory permissions) public {32 string memory key,33 bool isMutable,34 bool collectionAdmin,35 bool tokenOwner36 ) public {37 require(false, stub_error);46 require(false, stub_error);38 key;47 permissions;39 isMutable;40 collectionAdmin;41 tokenOwner;42 dummy = 0;48 dummy = 0;43 }49 }5051 /// @dev EVM selector for this function is: 0xf23d7790,52 /// or in textual repr: tokenPropertyPermissions()53 function tokenPropertyPermissions() public view returns (Tuple48[] memory) {54 require(false, stub_error);55 dummy;56 return new Tuple48[](0);57 }445845 // /// @notice Set token property value.59 // /// @notice Set token property value.46 // /// @dev Throws error if `msg.sender` has no permission to edit the property.60 // /// @dev Throws error if `msg.sender` has no permission to edit the property.118 bytes value;132 bytes value;119}133}134135enum EthTokenPermissions {136 Mutable,137 TokenOwner,138 CollectionAdmin139}140141/// @dev anonymous struct142struct Tuple48 {143 string field_0;144 Tuple46[] field_1;145}146147/// @dev anonymous struct148struct Tuple46 {149 EthTokenPermissions field_0;150 bool field_1;151}120152121/// @title A contract that allows you to work with collections.153/// @title A contract that allows you to work with collections.122/// @dev the ERC-165 identifier for this interface is 0xb5e1747f154/// @dev the ERC-165 identifier for this interface is 0xb5e1747fpallets/refungible/CHANGELOG.mddiffbeforeafterboth445<!-- bureaucrate goes here -->5<!-- bureaucrate goes here -->667## [0.2.10] - 2022-12-1689### Added1011- The function `tokenPropertyPermissions` and `setTokenPropertyPermissions` to `TokenProperties` interface.1213### Changed1415- Hide `setTokenPropertyPermission` function in `TokenProperties` interface.167## [0.2.9] - 2022-11-1817## [0.2.9] - 2022-11-188189### Added19### Addedpallets/refungible/Cargo.tomldiffbeforeafterboth1[package]1[package]2name = "pallet-refungible"2name = "pallet-refungible"3version = "0.2.8"3version = "0.2.10"4license = "GPLv3"4license = "GPLv3"5edition = "2021"5edition = "2021"66pallets/refungible/src/erc.rsdiffbeforeafterboth33use pallet_common::{33use pallet_common::{34 CollectionHandle, CollectionPropertyPermissions, CommonCollectionOperations,34 CollectionHandle, CollectionPropertyPermissions, CommonCollectionOperations,35 erc::{CommonEvmHandler, CollectionCall, static_property::key},35 erc::{CommonEvmHandler, CollectionCall, static_property::key},36 eth::EthCrossAccount,36 eth::{EthCrossAccount, EthTokenPermissions},37 Error as CommonError,37 Error as CommonError,38};38};39use pallet_evm::{account::CrossAccountId, PrecompileHandle};39use pallet_evm::{account::CrossAccountId, PrecompileHandle};63 /// @param collectionAdmin Permission to mutate property by collection admin if property is mutable.63 /// @param collectionAdmin Permission to mutate property by collection admin if property is mutable.64 /// @param tokenOwner Permission to mutate property by token owner if property is mutable.64 /// @param tokenOwner Permission to mutate property by token owner if property is mutable.65 #[weight(<SelfWeightOf<T>>::set_token_property_permissions(1))]65 #[weight(<SelfWeightOf<T>>::set_token_property_permissions(1))]66 #[solidity(hide)]66 fn set_token_property_permission(67 fn set_token_property_permission(67 &mut self,68 &mut self,68 caller: caller,69 caller: caller,89 .map_err(dispatch_to_evm::<T>)90 .map_err(dispatch_to_evm::<T>)90 }91 }9293 /// @notice Set permissions for token property.94 /// @dev Throws error if `msg.sender` is not admin or owner of the collection.95 /// @param permissions Permissions for keys.96 #[weight(<SelfWeightOf<T>>::set_token_property_permissions(permissions.len() as u32))]97 fn set_token_property_permissions(98 &mut self,99 caller: caller,100 permissions: Vec<(string, Vec<(EthTokenPermissions, bool)>)>,101 ) -> Result<()> {102 let caller = T::CrossAccountId::from_eth(caller);103 const PERMISSIONS_FIELDS_COUNT: usize = 3;104105 let mut perms = Vec::new();106107 for (key, pp) in permissions {108 if pp.len() > PERMISSIONS_FIELDS_COUNT {109 return Err(alloc::format!(110 "Actual number of fields {} for {}, which exceeds the maximum value of {}",111 pp.len(),112 stringify!(EthTokenPermissions),113 PERMISSIONS_FIELDS_COUNT114 )115 .as_str()116 .into());117 }118119 let mut token_permission = PropertyPermission {120 mutable: false,121 collection_admin: false,122 token_owner: false,123 };124125 for (perm, value) in pp {126 match perm {127 EthTokenPermissions::Mutable => token_permission.mutable = value,128 EthTokenPermissions::TokenOwner => token_permission.token_owner = value,129 EthTokenPermissions::CollectionAdmin => {130 token_permission.collection_admin = value131 }132 }133 }134135 perms.push(PropertyKeyPermission {136 key: key.into_bytes().try_into().map_err(|_| "too long key")?,137 permission: token_permission,138 });139 }140141 <Pallet<T>>::set_token_property_permissions(self, &caller, perms)142 .map_err(dispatch_to_evm::<T>)143 }144145 /// @notice Get permissions for token properties.146 fn token_property_permissions(147 &self,148 ) -> Result<Vec<(string, Vec<(EthTokenPermissions, bool)>)>> {149 let perms = <Pallet<T>>::token_property_permission(self.id);150 Ok(perms151 .into_iter()152 .map(|(key, pp)| {153 let key = string::from_utf8(key.into_inner()).expect("Stored key must be valid");154 let pp = vec![155 (EthTokenPermissions::Mutable, pp.mutable),156 (EthTokenPermissions::TokenOwner, pp.token_owner),157 (EthTokenPermissions::CollectionAdmin, pp.collection_admin),158 ];159 (key, pp)160 })161 .collect())162 }9116392 /// @notice Set token property value.164 /// @notice Set token property value.93 /// @dev Throws error if `msg.sender` has no permission to edit the property.165 /// @dev Throws error if `msg.sender` has no permission to edit the property.pallets/refungible/src/lib.rsdiffbeforeafterboth113 AccessMode, budget::Budget, CollectionId, CollectionFlags, CollectionPropertiesVec,113 AccessMode, budget::Budget, CollectionId, CollectionFlags, CollectionPropertiesVec,114 CreateCollectionData, CustomDataLimit, mapping::TokenAddressMapping, MAX_ITEMS_PER_BATCH,114 CreateCollectionData, CustomDataLimit, mapping::TokenAddressMapping, MAX_ITEMS_PER_BATCH,115 MAX_REFUNGIBLE_PIECES, Property, PropertyKey, PropertyKeyPermission, PropertyPermission,115 MAX_REFUNGIBLE_PIECES, Property, PropertyKey, PropertyKeyPermission, PropertyPermission,116 PropertyScope, PropertyValue, TokenId, TrySetProperty,116 PropertyScope, PropertyValue, TokenId, TrySetProperty, PropertiesPermissionMap,117};117};118118119pub use pallet::*;119pub use pallet::*;1378 <PalletCommon<T>>::set_token_property_permissions(collection, sender, property_permissions)1378 <PalletCommon<T>>::set_token_property_permissions(collection, sender, property_permissions)1379 }1379 }13801381 pub fn token_property_permission(collection_id: CollectionId) -> PropertiesPermissionMap {1382 <PalletCommon<T>>::property_permissions(collection_id)1383 }138013841381 pub fn set_scoped_token_property_permissions(1385 pub fn set_scoped_token_property_permissions(1382 collection: &RefungibleHandle<T>,1386 collection: &RefungibleHandle<T>,pallets/refungible/src/stubs/UniqueRefungible.rawdiffbeforeafterbothbinary blob — no preview
pallets/refungible/src/stubs/UniqueRefungible.soldiffbeforeafterboth18}18}191920/// @title A contract that allows to set and delete token properties and change token property permissions.20/// @title A contract that allows to set and delete token properties and change token property permissions.21/// @dev the ERC-165 identifier for this interface is 0x91a97a6821/// @dev the ERC-165 identifier for this interface is 0xde0695c222contract TokenProperties is Dummy, ERC165 {22contract TokenProperties is Dummy, ERC165 {23 // /// @notice Set permissions for token property.24 // /// @dev Throws error if `msg.sender` is not admin or owner of the collection.25 // /// @param key Property key.26 // /// @param isMutable Permission to mutate property.27 // /// @param collectionAdmin Permission to mutate property by collection admin if property is mutable.28 // /// @param tokenOwner Permission to mutate property by token owner if property is mutable.29 // /// @dev EVM selector for this function is: 0x222d97fa,30 // /// or in textual repr: setTokenPropertyPermission(string,bool,bool,bool)31 // function setTokenPropertyPermission(string memory key, bool isMutable, bool collectionAdmin, bool tokenOwner) public {32 // require(false, stub_error);33 // key;34 // isMutable;35 // collectionAdmin;36 // tokenOwner;37 // dummy = 0;38 // }3923 /// @notice Set permissions for token property.40 /// @notice Set permissions for token property.24 /// @dev Throws error if `msg.sender` is not admin or owner of the collection.41 /// @dev Throws error if `msg.sender` is not admin or owner of the collection.25 /// @param key Property key.42 /// @param permissions Permissions for keys.26 /// @param isMutable Permission to mutate property.27 /// @param collectionAdmin Permission to mutate property by collection admin if property is mutable.28 /// @param tokenOwner Permission to mutate property by token owner if property is mutable.29 /// @dev EVM selector for this function is: 0x222d97fa,43 /// @dev EVM selector for this function is: 0xbd92983a,30 /// or in textual repr: setTokenPropertyPermission(string,bool,bool,bool)44 /// or in textual repr: setTokenPropertyPermissions((string,(uint8,bool)[])[])31 function setTokenPropertyPermission(45 function setTokenPropertyPermissions(Tuple53[] memory permissions) public {32 string memory key,33 bool isMutable,34 bool collectionAdmin,35 bool tokenOwner36 ) public {37 require(false, stub_error);46 require(false, stub_error);38 key;47 permissions;39 isMutable;40 collectionAdmin;41 tokenOwner;42 dummy = 0;48 dummy = 0;43 }49 }5051 /// @notice Get permissions for token properties.52 /// @dev EVM selector for this function is: 0xf23d7790,53 /// or in textual repr: tokenPropertyPermissions()54 function tokenPropertyPermissions() public view returns (Tuple53[] memory) {55 require(false, stub_error);56 dummy;57 return new Tuple53[](0);58 }445945 // /// @notice Set token property value.60 // /// @notice Set token property value.46 // /// @dev Throws error if `msg.sender` has no permission to edit the property.61 // /// @dev Throws error if `msg.sender` has no permission to edit the property.118 bytes value;133 bytes value;119}134}135136enum EthTokenPermissions {137 Mutable,138 TokenOwner,139 CollectionAdmin140}141142/// @dev anonymous struct143struct Tuple53 {144 string field_0;145 Tuple51[] field_1;146}147148/// @dev anonymous struct149struct Tuple51 {150 EthTokenPermissions field_0;151 bool field_1;152}120153121/// @title A contract that allows you to work with collections.154/// @title A contract that allows you to work with collections.122/// @dev the ERC-165 identifier for this interface is 0xb5e1747f155/// @dev the ERC-165 identifier for this interface is 0xb5e1747fprimitives/data-structs/src/lib.rsdiffbeforeafterboth1010pub type PropertyValue = BoundedBytes<ConstU32<MAX_PROPERTY_VALUE_LENGTH>>;1010pub type PropertyValue = BoundedBytes<ConstU32<MAX_PROPERTY_VALUE_LENGTH>>;101110111012/// Property permission.1012/// Property permission.1013#[derive(Encode, Decode, TypeInfo, Debug, MaxEncodedLen, PartialEq, Clone)]1013#[derive(Encode, Decode, TypeInfo, Debug, MaxEncodedLen, PartialEq, Clone, Default)]1014#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]1014#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]1015pub struct PropertyPermission {1015pub struct PropertyPermission {1016 /// Permission to change the property and property permission.1016 /// Permission to change the property and property permission.tests/src/eth/abi/nonFungible.jsondiffbeforeafterboth697 },697 },698 {698 {699 "inputs": [699 "inputs": [700 {701 "components": [700 { "internalType": "string", "name": "key", "type": "string" },702 { "internalType": "string", "name": "field_0", "type": "string" },703 {704 "components": [701 { "internalType": "bool", "name": "isMutable", "type": "bool" },705 {706 "internalType": "enum EthTokenPermissions",707 "name": "field_0",708 "type": "uint8"709 },702 { "internalType": "bool", "name": "collectionAdmin", "type": "bool" },710 { "internalType": "bool", "name": "field_1", "type": "bool" }711 ],712 "internalType": "struct Tuple46[]",713 "name": "field_1",714 "type": "tuple[]"715 }716 ],703 { "internalType": "bool", "name": "tokenOwner", "type": "bool" }717 "internalType": "struct Tuple48[]",718 "name": "permissions",719 "type": "tuple[]"720 }704 ],721 ],705 "name": "setTokenPropertyPermission",722 "name": "setTokenPropertyPermissions",706 "outputs": [],723 "outputs": [],707 "stateMutability": "nonpayable",724 "stateMutability": "nonpayable",708 "type": "function"725 "type": "function"742 "stateMutability": "view",759 "stateMutability": "view",743 "type": "function"760 "type": "function"744 },761 },762 {763 "inputs": [],764 "name": "tokenPropertyPermissions",765 "outputs": [766 {767 "components": [768 { "internalType": "string", "name": "field_0", "type": "string" },769 {770 "components": [771 {772 "internalType": "enum EthTokenPermissions",773 "name": "field_0",774 "type": "uint8"775 },776 { "internalType": "bool", "name": "field_1", "type": "bool" }777 ],778 "internalType": "struct Tuple46[]",779 "name": "field_1",780 "type": "tuple[]"781 }782 ],783 "internalType": "struct Tuple48[]",784 "name": "",785 "type": "tuple[]"786 }787 ],788 "stateMutability": "view",789 "type": "function"790 },745 {791 {746 "inputs": [792 "inputs": [747 { "internalType": "uint256", "name": "tokenId", "type": "uint256" }793 { "internalType": "uint256", "name": "tokenId", "type": "uint256" }tests/src/eth/abi/reFungible.jsondiffbeforeafterboth679 },679 },680 {680 {681 "inputs": [681 "inputs": [682 {683 "components": [682 { "internalType": "string", "name": "key", "type": "string" },684 { "internalType": "string", "name": "field_0", "type": "string" },685 {686 "components": [683 { "internalType": "bool", "name": "isMutable", "type": "bool" },687 {688 "internalType": "enum EthTokenPermissions",689 "name": "field_0",690 "type": "uint8"691 },684 { "internalType": "bool", "name": "collectionAdmin", "type": "bool" },692 { "internalType": "bool", "name": "field_1", "type": "bool" }693 ],694 "internalType": "struct Tuple51[]",695 "name": "field_1",696 "type": "tuple[]"697 }698 ],685 { "internalType": "bool", "name": "tokenOwner", "type": "bool" }699 "internalType": "struct Tuple53[]",700 "name": "permissions",701 "type": "tuple[]"702 }686 ],703 ],687 "name": "setTokenPropertyPermission",704 "name": "setTokenPropertyPermissions",688 "outputs": [],705 "outputs": [],689 "stateMutability": "nonpayable",706 "stateMutability": "nonpayable",690 "type": "function"707 "type": "function"733 "stateMutability": "view",750 "stateMutability": "view",734 "type": "function"751 "type": "function"735 },752 },753 {754 "inputs": [],755 "name": "tokenPropertyPermissions",756 "outputs": [757 {758 "components": [759 { "internalType": "string", "name": "field_0", "type": "string" },760 {761 "components": [762 {763 "internalType": "enum EthTokenPermissions",764 "name": "field_0",765 "type": "uint8"766 },767 { "internalType": "bool", "name": "field_1", "type": "bool" }768 ],769 "internalType": "struct Tuple51[]",770 "name": "field_1",771 "type": "tuple[]"772 }773 ],774 "internalType": "struct Tuple53[]",775 "name": "",776 "type": "tuple[]"777 }778 ],779 "stateMutability": "view",780 "type": "function"781 },736 {782 {737 "inputs": [783 "inputs": [738 { "internalType": "uint256", "name": "tokenId", "type": "uint256" }784 { "internalType": "uint256", "name": "tokenId", "type": "uint256" }tests/src/eth/api/UniqueNFT.soldiffbeforeafterboth13}13}141415/// @title A contract that allows to set and delete token properties and change token property permissions.15/// @title A contract that allows to set and delete token properties and change token property permissions.16/// @dev the ERC-165 identifier for this interface is 0x91a97a6816/// @dev the ERC-165 identifier for this interface is 0xde0695c217interface TokenProperties is Dummy, ERC165 {17interface TokenProperties is Dummy, ERC165 {18 // /// @notice Set permissions for token property.19 // /// @dev Throws error if `msg.sender` is not admin or owner of the collection.20 // /// @param key Property key.21 // /// @param isMutable Permission to mutate property.22 // /// @param collectionAdmin Permission to mutate property by collection admin if property is mutable.23 // /// @param tokenOwner Permission to mutate property by token owner if property is mutable.24 // /// @dev EVM selector for this function is: 0x222d97fa,25 // /// or in textual repr: setTokenPropertyPermission(string,bool,bool,bool)26 // function setTokenPropertyPermission(string memory key, bool isMutable, bool collectionAdmin, bool tokenOwner) external;2718 /// @notice Set permissions for token property.28 /// @notice Set permissions for token property.19 /// @dev Throws error if `msg.sender` is not admin or owner of the collection.29 /// @dev Throws error if `msg.sender` is not admin or owner of the collection.20 /// @param key Property key.30 /// @param permissions Permissions for keys.21 /// @param isMutable Permission to mutate property.22 /// @param collectionAdmin Permission to mutate property by collection admin if property is mutable.23 /// @param tokenOwner Permission to mutate property by token owner if property is mutable.24 /// @dev EVM selector for this function is: 0x222d97fa,31 /// @dev EVM selector for this function is: 0xbd92983a,25 /// or in textual repr: setTokenPropertyPermission(string,bool,bool,bool)32 /// or in textual repr: setTokenPropertyPermissions((string,(uint8,bool)[])[])26 function setTokenPropertyPermission(33 function setTokenPropertyPermissions(Tuple43[] memory permissions) external;27 string memory key,3428 bool isMutable,35 /// @dev EVM selector for this function is: 0xf23d7790,29 bool collectionAdmin,36 /// or in textual repr: tokenPropertyPermissions()30 bool tokenOwner37 function tokenPropertyPermissions() external view returns (Tuple43[] memory);31 ) external;323833 // /// @notice Set token property value.39 // /// @notice Set token property value.79 bytes value;85 bytes value;80}86}8788enum EthTokenPermissions {89 Mutable,90 TokenOwner,91 CollectionAdmin92}9394/// @dev anonymous struct95struct Tuple43 {96 string field_0;97 Tuple41[] field_1;98}99100/// @dev anonymous struct101struct Tuple41 {102 EthTokenPermissions field_0;103 bool field_1;104}8110582/// @title A contract that allows you to work with collections.106/// @title A contract that allows you to work with collections.83/// @dev the ERC-165 identifier for this interface is 0xb5e1747f107/// @dev the ERC-165 identifier for this interface is 0xb5e1747ftests/src/eth/api/UniqueRefungible.soldiffbeforeafterboth13}13}141415/// @title A contract that allows to set and delete token properties and change token property permissions.15/// @title A contract that allows to set and delete token properties and change token property permissions.16/// @dev the ERC-165 identifier for this interface is 0x91a97a6816/// @dev the ERC-165 identifier for this interface is 0xde0695c217interface TokenProperties is Dummy, ERC165 {17interface TokenProperties is Dummy, ERC165 {18 // /// @notice Set permissions for token property.19 // /// @dev Throws error if `msg.sender` is not admin or owner of the collection.20 // /// @param key Property key.21 // /// @param isMutable Permission to mutate property.22 // /// @param collectionAdmin Permission to mutate property by collection admin if property is mutable.23 // /// @param tokenOwner Permission to mutate property by token owner if property is mutable.24 // /// @dev EVM selector for this function is: 0x222d97fa,25 // /// or in textual repr: setTokenPropertyPermission(string,bool,bool,bool)26 // function setTokenPropertyPermission(string memory key, bool isMutable, bool collectionAdmin, bool tokenOwner) external;2718 /// @notice Set permissions for token property.28 /// @notice Set permissions for token property.19 /// @dev Throws error if `msg.sender` is not admin or owner of the collection.29 /// @dev Throws error if `msg.sender` is not admin or owner of the collection.20 /// @param key Property key.30 /// @param permissions Permissions for keys.21 /// @param isMutable Permission to mutate property.22 /// @param collectionAdmin Permission to mutate property by collection admin if property is mutable.23 /// @param tokenOwner Permission to mutate property by token owner if property is mutable.24 /// @dev EVM selector for this function is: 0x222d97fa,31 /// @dev EVM selector for this function is: 0xbd92983a,25 /// or in textual repr: setTokenPropertyPermission(string,bool,bool,bool)32 /// or in textual repr: setTokenPropertyPermissions((string,(uint8,bool)[])[])26 function setTokenPropertyPermission(33 function setTokenPropertyPermissions(Tuple47[] memory permissions) external;27 string memory key,3428 bool isMutable,35 /// @notice Get permissions for token properties.29 bool collectionAdmin,36 /// @dev EVM selector for this function is: 0xf23d7790,30 bool tokenOwner37 /// or in textual repr: tokenPropertyPermissions()31 ) external;38 function tokenPropertyPermissions() external view returns (Tuple47[] memory);323933 // /// @notice Set token property value.40 // /// @notice Set token property value.34 // /// @dev Throws error if `msg.sender` has no permission to edit the property.41 // /// @dev Throws error if `msg.sender` has no permission to edit the property.79 bytes value;86 bytes value;80}87}8889enum EthTokenPermissions {90 Mutable,91 TokenOwner,92 CollectionAdmin93}9495/// @dev anonymous struct96struct Tuple47 {97 string field_0;98 Tuple45[] field_1;99}100101/// @dev anonymous struct102struct Tuple45 {103 EthTokenPermissions field_0;104 bool field_1;105}8110682/// @title A contract that allows you to work with collections.107/// @title A contract that allows you to work with collections.83/// @dev the ERC-165 identifier for this interface is 0xb5e1747f108/// @dev the ERC-165 identifier for this interface is 0xb5e1747ftests/src/eth/events.test.tsdiffbeforeafterboth19import {EthUniqueHelper, itEth, usingEthPlaygrounds} from './util';19import {EthUniqueHelper, itEth, usingEthPlaygrounds} from './util';20import {IEvent, TCollectionMode} from '../util/playgrounds/types';20import {IEvent, TCollectionMode} from '../util/playgrounds/types';21import {Pallets, requirePalletsOrSkip} from '../util';21import {Pallets, requirePalletsOrSkip} from '../util';22import {NormalizedEvent} from './util/playgrounds/types';22import {EthTokenPermissions, NormalizedEvent} from './util/playgrounds/types';232324let donor: IKeyringPair;24let donor: IKeyringPair;25 25 119 ethEvents.push(event);119 ethEvents.push(event);120 });120 });121 const {unsubscribe, collectedEvents: subEvents} = await helper.subscribeEvents([{section: 'common', names: ['PropertyPermissionSet']}]);121 const {unsubscribe, collectedEvents: subEvents} = await helper.subscribeEvents([{section: 'common', names: ['PropertyPermissionSet']}]);122 await collection.methods.setTokenPropertyPermission('testKey', true, true, true).send({from: owner});122 await collection.methods.setTokenPropertyPermissions([123 ['A', [124 [EthTokenPermissions.Mutable, true], 125 [EthTokenPermissions.TokenOwner, true], 126 [EthTokenPermissions.CollectionAdmin, true]],127 ],128 ]).send({from: owner});123 await helper.wait.newBlocks(1);129 await helper.wait.newBlocks(1);124 expect(ethEvents).to.be.like([130 expect(ethEvents).to.be.like([125 {131 {374 const collectionHelper = helper.ethNativeContract.collectionHelpers(owner);380 const collectionHelper = helper.ethNativeContract.collectionHelpers(owner);375 const result = await collection.methods.mint(owner).send({from: owner});381 const result = await collection.methods.mint(owner).send({from: owner});376 const tokenId = result.events.Transfer.returnValues.tokenId;382 const tokenId = result.events.Transfer.returnValues.tokenId;377 await collection.methods.setTokenPropertyPermission('A', true, true, true).send({from: owner});383 await collection.methods.setTokenPropertyPermissions([384 ['A', [385 [EthTokenPermissions.Mutable, true], 386 [EthTokenPermissions.TokenOwner, true], 387 [EthTokenPermissions.CollectionAdmin, true]],388 ],389 ]).send({from: owner});378390379391380 const ethEvents: any = [];392 const ethEvents: any = [];tests/src/eth/tokenProperties.test.tsdiffbeforeafterboth20import {ITokenPropertyPermission} from '../util/playgrounds/types';20import {ITokenPropertyPermission} from '../util/playgrounds/types';21import {Pallets} from '../util';21import {Pallets} from '../util';22import {UniqueNFTCollection, UniqueNFToken, UniqueRFTCollection} from '../util/playgrounds/unique';22import {UniqueNFTCollection, UniqueNFToken, UniqueRFTCollection} from '../util/playgrounds/unique';23import {EthTokenPermissions} from './util/playgrounds/types';232424describe('EVM token properties', () => {25describe('EVM token properties', () => {25 let donor: IKeyringPair;26 let donor: IKeyringPair;32 });33 });33 });34 });343536 [37 {mode: 'nft' as const, requiredPallets: []},38 {mode: 'rft' as const, requiredPallets: [Pallets.ReFungible]},39 ].map(testCase =>35 itEth('Can be reconfigured', async({helper}) => {40 itEth.ifWithPallets(`[${testCase.mode}] Set and get token property permissions`, testCase.requiredPallets, async({helper}) => {36 const caller = await helper.eth.createAccountWithBalance(donor);41 const owner = await helper.eth.createAccountWithBalance(donor);42 const caller = await helper.ethCrossAccount.createAccountWithBalance(donor);37 for(const [mutable,collectionAdmin, tokenOwner] of cartesian([], [false, true], [false, true], [false, true])) {43 for(const [mutable,collectionAdmin, tokenOwner] of cartesian([], [false, true], [false, true], [false, true])) {38 const collection = await helper.nft.mintCollection(alice);44 const {collectionId, collectionAddress} = await helper.eth.createCollection(testCase.mode, owner, 'A', 'B', 'C');39 await collection.addAdmin(alice, {Ethereum: caller});40 41 const address = helper.ethAddress.fromCollectionId(collection.collectionId);45 const collection = await helper.ethNativeContract.collection(collectionAddress, testCase.mode, owner);42 const contract = helper.ethNativeContract.collection(address, 'nft', caller);46 await collection.methods.addCollectionAdminCross(caller).send({from: owner});43 4744 await contract.methods.setTokenPropertyPermission('testKey', mutable, collectionAdmin, tokenOwner).send({from: caller});48 await collection.methods.setTokenPropertyPermissions([45 49 ['testKey', [50 [EthTokenPermissions.Mutable, mutable], 51 [EthTokenPermissions.TokenOwner, tokenOwner], 52 [EthTokenPermissions.CollectionAdmin, collectionAdmin]],53 ],54 ]).send({from: caller.eth});55 46 expect(await collection.getPropertyPermissions()).to.be.deep.equal([{56 expect(await helper[testCase.mode].getPropertyPermissions(collectionId)).to.be.deep.equal([{47 key: 'testKey',57 key: 'testKey',48 permission: {mutable, collectionAdmin, tokenOwner},58 permission: {mutable, collectionAdmin, tokenOwner},49 }]);59 }]);6061 expect(await collection.methods.tokenPropertyPermissions().call({from: caller.eth})).to.be.like([62 ['testKey', [63 [EthTokenPermissions.Mutable.toString(), mutable], 64 [EthTokenPermissions.TokenOwner.toString(), tokenOwner], 65 [EthTokenPermissions.CollectionAdmin.toString(), collectionAdmin]],66 ],67 ]);50 }68 }51 });69 }));7071 [72 {mode: 'nft' as const, requiredPallets: []},73 {mode: 'rft' as const, requiredPallets: [Pallets.ReFungible]},74 ].map(testCase =>75 itEth.ifWithPallets(`[${testCase.mode}] Set and get multiple token property permissions as owner`, testCase.requiredPallets, async({helper}) => {76 const owner = await helper.eth.createAccountWithBalance(donor);77 78 const {collectionId, collectionAddress} = await helper.eth.createCollection(testCase.mode, owner, 'A', 'B', 'C');79 const collection = await helper.ethNativeContract.collection(collectionAddress, testCase.mode, owner);8081 await collection.methods.setTokenPropertyPermissions([82 ['testKey_0', [83 [EthTokenPermissions.Mutable, true], 84 [EthTokenPermissions.TokenOwner, true], 85 [EthTokenPermissions.CollectionAdmin, true]],86 ],87 ['testKey_1', [88 [EthTokenPermissions.Mutable, true], 89 [EthTokenPermissions.TokenOwner, false], 90 [EthTokenPermissions.CollectionAdmin, true]],91 ],92 ['testKey_2', [93 [EthTokenPermissions.Mutable, false], 94 [EthTokenPermissions.TokenOwner, true], 95 [EthTokenPermissions.CollectionAdmin, false]],96 ],97 ]).send({from: owner});98 99 expect(await helper[testCase.mode].getPropertyPermissions(collectionId)).to.be.deep.equal([100 {101 key: 'testKey_0',102 permission: {mutable: true, tokenOwner: true, collectionAdmin: true},103 },104 {105 key: 'testKey_1',106 permission: {mutable: true, tokenOwner: false, collectionAdmin: true},107 },108 {109 key: 'testKey_2',110 permission: {mutable: false, tokenOwner: true, collectionAdmin: false},111 },112 ]);113114 expect(await collection.methods.tokenPropertyPermissions().call({from: owner})).to.be.like([115 ['testKey_0', [116 [EthTokenPermissions.Mutable.toString(), true], 117 [EthTokenPermissions.TokenOwner.toString(), true], 118 [EthTokenPermissions.CollectionAdmin.toString(), true]],119 ],120 ['testKey_1', [121 [EthTokenPermissions.Mutable.toString(), true], 122 [EthTokenPermissions.TokenOwner.toString(), false], 123 [EthTokenPermissions.CollectionAdmin.toString(), true]],124 ],125 ['testKey_2', [126 [EthTokenPermissions.Mutable.toString(), false], 127 [EthTokenPermissions.TokenOwner.toString(), true], 128 [EthTokenPermissions.CollectionAdmin.toString(), false]],129 ],130 ]);131 132 }));133134 [135 {mode: 'nft' as const, requiredPallets: []},136 {mode: 'rft' as const, requiredPallets: [Pallets.ReFungible]},137 ].map(testCase =>138 itEth.ifWithPallets(`[${testCase.mode}] Set and get multiple token property permissions as admin`, testCase.requiredPallets, async({helper}) => {139 const owner = await helper.eth.createAccountWithBalance(donor);140 const caller = await helper.ethCrossAccount.createAccountWithBalance(donor);141 142 const {collectionId, collectionAddress} = await helper.eth.createCollection(testCase.mode, owner, 'A', 'B', 'C');143 const collection = await helper.ethNativeContract.collection(collectionAddress, testCase.mode, owner);144 await collection.methods.addCollectionAdminCross(caller).send({from: owner});145146 await collection.methods.setTokenPropertyPermissions([147 ['testKey_0', [148 [EthTokenPermissions.Mutable, true], 149 [EthTokenPermissions.TokenOwner, true], 150 [EthTokenPermissions.CollectionAdmin, true]],151 ],152 ['testKey_1', [153 [EthTokenPermissions.Mutable, true], 154 [EthTokenPermissions.TokenOwner, false], 155 [EthTokenPermissions.CollectionAdmin, true]],156 ],157 ['testKey_2', [158 [EthTokenPermissions.Mutable, false], 159 [EthTokenPermissions.TokenOwner, true], 160 [EthTokenPermissions.CollectionAdmin, false]],161 ],162 ]).send({from: caller.eth});163 164 expect(await helper[testCase.mode].getPropertyPermissions(collectionId)).to.be.deep.equal([165 {166 key: 'testKey_0',167 permission: {mutable: true, tokenOwner: true, collectionAdmin: true},168 },169 {170 key: 'testKey_1',171 permission: {mutable: true, tokenOwner: false, collectionAdmin: true},172 },173 {174 key: 'testKey_2',175 permission: {mutable: false, tokenOwner: true, collectionAdmin: false},176 },177 ]);178179 expect(await collection.methods.tokenPropertyPermissions().call({from: caller.eth})).to.be.like([180 ['testKey_0', [181 [EthTokenPermissions.Mutable.toString(), true], 182 [EthTokenPermissions.TokenOwner.toString(), true], 183 [EthTokenPermissions.CollectionAdmin.toString(), true]],184 ],185 ['testKey_1', [186 [EthTokenPermissions.Mutable.toString(), true], 187 [EthTokenPermissions.TokenOwner.toString(), false], 188 [EthTokenPermissions.CollectionAdmin.toString(), true]],189 ],190 ['testKey_2', [191 [EthTokenPermissions.Mutable.toString(), false], 192 [EthTokenPermissions.TokenOwner.toString(), true], 193 [EthTokenPermissions.CollectionAdmin.toString(), false]],194 ],195 ]);196 197 }));5219853 [199 [54 {200 {302 expect(actualProps).to.deep.eq(expectedProps);448 expect(actualProps).to.deep.eq(expectedProps);303 }));449 }));450451 [452 {mode: 'nft' as const, requiredPallets: []},453 {mode: 'rft' as const, requiredPallets: [Pallets.ReFungible]},454 ].map(testCase =>455 itEth.ifWithPallets(`[${testCase.mode}] Cant set token property permissions as non owner or admin`, testCase.requiredPallets, async({helper}) => {456 const owner = await helper.eth.createAccountWithBalance(donor);457 const caller = await helper.eth.createAccountWithBalance(donor);458 459 const {collectionAddress} = await helper.eth.createCollection(testCase.mode, owner, 'A', 'B', 'C');460 const collection = await helper.ethNativeContract.collection(collectionAddress, testCase.mode, owner);461 462 await expect(collection.methods.setTokenPropertyPermissions([463 ['testKey_0', [464 [EthTokenPermissions.Mutable, true], 465 [EthTokenPermissions.TokenOwner, true], 466 [EthTokenPermissions.CollectionAdmin, true]],467 ],468 ]).call({from: caller})).to.be.rejectedWith('NoPermission'); 469 }));470471 [472 {mode: 'nft' as const, requiredPallets: []},473 {mode: 'rft' as const, requiredPallets: [Pallets.ReFungible]},474 ].map(testCase =>475 itEth.ifWithPallets(`[${testCase.mode}] Cant set token property permissions with invalid character`, testCase.requiredPallets, async({helper}) => {476 const owner = await helper.eth.createAccountWithBalance(donor);477 478 const {collectionAddress} = await helper.eth.createCollection(testCase.mode, owner, 'A', 'B', 'C');479 const collection = await helper.ethNativeContract.collection(collectionAddress, testCase.mode, owner);480 481 await expect(collection.methods.setTokenPropertyPermissions([482 // "Space" is invalid character483 ['testKey 0', [484 [EthTokenPermissions.Mutable, true], 485 [EthTokenPermissions.TokenOwner, true], 486 [EthTokenPermissions.CollectionAdmin, true]],487 ],488 ]).call({from: owner})).to.be.rejectedWith('InvalidCharacterInPropertyKey'); 489 }));490 304});491});305492tests/src/eth/util/playgrounds/types.tsdiffbeforeafterboth202021export type EthProperty = string[];21export type EthProperty = string[];22222323export enum EthTokenPermissions {24 Mutable,25 TokenOwner,26 CollectionAdmin27}