git.delta.rocks / unique-network / refs/commits / bf0e967f70e3

difftreelog

feat set/get tokenPropertyPermissions for NFT

Trubnikov Sergey2022-12-14parent: #7fd4751.patch.diff
in: master

7 files changed

modifiedpallets/common/src/eth.rsdiffbeforeafterboth
163 TokenOwner,163 TokenOwner,
164}164}
165
166#[derive(AbiCoder, Copy, Clone, Default, Debug)]
167#[repr(u8)]
168pub enum EthTokenPermissions {
169 #[default]
170 Mutable,
171 TokenOwner,
172 CollectionAdmin,
173}
165174
modifiedpallets/nonfungible/src/erc.rsdiffbeforeafterboth
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_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 }
90
91 /// @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;
101
102 let mut perms = <Vec<_>>::new();
103
104 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_COUNT
111 )
112 .as_str()
113 .into());
114 }
115
116 let mut token_permission = PropertyPermission {
117 mutable: false,
118 collection_admin: false,
119 token_owner: false,
120 };
121
122 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 = value
128 }
129 }
130 }
131
132 perms.push(PropertyKeyPermission {
133 key: <Vec<u8>>::from(key)
134 .try_into()
135 .map_err(|_| "too long key")?,
136 permission: token_permission,
137 });
138 }
139
140 <Pallet<T>>::set_property_permissions(self, &caller, perms).map_err(dispatch_to_evm::<T>)
141 }
142
143 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 }
88159
89 /// @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.
modifiedpallets/nonfungible/src/lib.rsdiffbeforeafterboth
103 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 }
837
838 pub fn token_property_permission(collection_id: CollectionId) -> PropertiesPermissionMap {
839 <PalletCommon<T>>::property_permissions(collection_id)
840 }
837841
838 pub fn check_token_immediate_ownership(842 pub fn check_token_immediate_ownership(
839 collection: &NonfungibleHandle<T>,843 collection: &NonfungibleHandle<T>,
modifiedpallets/nonfungible/src/stubs/UniqueNFT.soldiffbeforeafterboth
18}18}
1919
20/// @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 0xde0695c2
22contract 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 // }
39
23 /// @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 tokenOwner
36 ) 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 }
50
51 /// @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 }
4458
45 // /// @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}
134
135enum EthTokenPermissions {
136 Mutable,
137 TokenOwner,
138 CollectionAdmin
139}
140
141/// @dev anonymous struct
142struct Tuple48 {
143 string field_0;
144 Tuple46[] field_1;
145}
146
147/// @dev anonymous struct
148struct Tuple46 {
149 EthTokenPermissions field_0;
150 bool field_1;
151}
120152
121/// @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 0xb5e1747f
modifiedtests/src/eth/abi/nonFungible.jsondiffbeforeafterboth
697 },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" }
modifiedtests/src/eth/api/UniqueNFT.soldiffbeforeafterboth
13}13}
1414
15/// @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 0xde0695c2
17interface 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;
27
18 /// @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,34
28 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;
3238
33 // /// @notice Set token property value.39 // /// @notice Set token property value.
79 bytes value;85 bytes value;
80}86}
87
88enum EthTokenPermissions {
89 Mutable,
90 TokenOwner,
91 CollectionAdmin
92}
93
94/// @dev anonymous struct
95struct Tuple43 {
96 string field_0;
97 Tuple41[] field_1;
98}
99
100/// @dev anonymous struct
101struct Tuple41 {
102 EthTokenPermissions field_0;
103 bool field_1;
104}
81105
82/// @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 0xb5e1747f
modifiedtests/src/eth/tokenProperties.test.tsdiffbeforeafterboth
32 });32 });
33 });33 });
3434
35 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 }]);
50
51 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