difftreelog
feat set/get tokenPropertyPermissions for NFT
in: master
7 files changed
pallets/common/src/eth.rsdiffbeforeafterboth163 TokenOwner,163 TokenOwner,164}164}165166#[derive(AbiCoder, Copy, Clone, Default, Debug)]167#[repr(u8)]168pub enum EthTokenPermissions {169 #[default]170 Mutable,171 TokenOwner,172 CollectionAdmin,173}165174pallets/nonfungible/src/erc.rsdiffbeforeafterboth38use 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_property_permissions(73 self,74 self,74 &caller,75 &caller,75 PropertyKeyPermission {76 [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")?,81 collection_admin,82 collection_admin,82 token_owner,83 token_owner,83 },84 },84 },85 }]86 .into(),85 )87 )86 .map_err(dispatch_to_evm::<T>)88 .map_err(dispatch_to_evm::<T>)87 }89 }9091 /// @notice Set permissions for token property.92 /// @dev Throws error if `msg.sender` is not admin or owner of the collection.93 /// @param permissions Permissions for keys.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 {117 mutable: false,118 collection_admin: false,119 token_owner: false,120 };121122 for (perm, value) in pp {123 match perm {124 EthTokenPermissions::Mutable => token_permission.mutable = value,125 EthTokenPermissions::TokenOwner => token_permission.token_owner = value,126 EthTokenPermissions::CollectionAdmin => {127 token_permission.collection_admin = value128 }129 }130 }131132 perms.push(PropertyKeyPermission {133 key: <Vec<u8>>::from(key)134 .try_into()135 .map_err(|_| "too long key")?,136 permission: token_permission,137 });138 }139140 <Pallet<T>>::set_property_permissions(self, &caller, perms).map_err(dispatch_to_evm::<T>)141 }142143 fn token_property_permissions(144 &self,145 ) -> Result<Vec<(string, Vec<(EthTokenPermissions, bool)>)>> {146 let mut res = <Vec<_>>::new();147 for (key, pp) in <Pallet<T>>::token_property_permission(self.id) {148 let key = string::from_utf8(key.into_inner()).unwrap();149 let pp = [150 (EthTokenPermissions::Mutable, pp.mutable),151 (EthTokenPermissions::TokenOwner, pp.token_owner),152 (EthTokenPermissions::CollectionAdmin, pp.collection_admin),153 ]154 .into();155 res.push((key, pp));156 }157 Ok(res)158 }8815989 /// @notice Set token property value.160 /// @notice Set token property value.90 /// @dev Throws error if `msg.sender` has no permission to edit the property.161 /// @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::{827 /// Set property permissions for the collection.827 /// Set property permissions for the collection.828 ///828 ///829 /// Sender should be the owner or admin of the collection.829 /// Sender should be the owner or admin of the collection.830 pub fn set_property_permission(830 pub fn set_property_permissions(831 collection: &CollectionHandle<T>,831 collection: &CollectionHandle<T>,832 sender: &T::CrossAccountId,832 sender: &T::CrossAccountId,833 permission: PropertyKeyPermission,833 permission: Vec<PropertyKeyPermission>,834 ) -> DispatchResult {834 ) -> DispatchResult {835 <PalletCommon<T>>::set_property_permission(collection, sender, permission)835 <PalletCommon<T>>::set_token_property_permissions(collection, sender, permission)836 }836 }837838 pub fn token_property_permission(collection_id: CollectionId) -> PropertiesPermissionMap {839 <PalletCommon<T>>::property_permissions(collection_id)840 }837841838 pub fn check_token_immediate_ownership(842 pub fn check_token_immediate_ownership(839 collection: &NonfungibleHandle<T>,843 collection: &NonfungibleHandle<T>,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 0xb5e1747ftests/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/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/tokenProperties.test.tsdiffbeforeafterboth32 });32 });33 });33 });343435 itEth('Can be reconfigured', async({helper}) => {35 itEth.only('Can be reconfigured', async({helper}) => {36 const caller = await helper.eth.createAccountWithBalance(donor);36 const caller = await helper.eth.createAccountWithBalance(donor);37 for(const [mutable,collectionAdmin, tokenOwner] of cartesian([], [false, true], [false, true], [false, true])) {37 for(const [mutable,collectionAdmin, tokenOwner] of cartesian([], [false, true], [false, true], [false, true])) {38 const collection = await helper.nft.mintCollection(alice);38 const collection = await helper.nft.mintCollection(alice);41 const address = helper.ethAddress.fromCollectionId(collection.collectionId);41 const address = helper.ethAddress.fromCollectionId(collection.collectionId);42 const contract = helper.ethNativeContract.collection(address, 'nft', caller);42 const contract = helper.ethNativeContract.collection(address, 'nft', caller);43 43 44 await contract.methods.setTokenPropertyPermission('testKey', mutable, collectionAdmin, tokenOwner).send({from: caller});44 await contract.methods.setTokenPropertyPermissions([['testKey', [[0, mutable], [1, tokenOwner], [2, collectionAdmin]]]]).send({from: caller});45 45 46 expect(await collection.getPropertyPermissions()).to.be.deep.equal([{46 expect(await collection.getPropertyPermissions()).to.be.deep.equal([{47 key: 'testKey',47 key: 'testKey',48 permission: {mutable, collectionAdmin, tokenOwner},48 permission: {mutable, collectionAdmin, tokenOwner},49 }]);49 }]);5051 expect(await contract.methods.tokenPropertyPermissions().call({from: caller})).to.be.like([52 ['testKey', [['0', mutable], ['1', tokenOwner], ['2', collectionAdmin]]]53 ]);50 }54 }51 });55 });5256