From 1fe93b2e72cbb7c487bb83f23c87b475d6fe152b Mon Sep 17 00:00:00 2001 From: Trubnikov Sergey Date: Fri, 16 Dec 2022 09:41:01 +0000 Subject: [PATCH] fix: PR --- --- a/pallets/nonfungible/src/erc.rs +++ b/pallets/nonfungible/src/erc.rs @@ -90,6 +90,7 @@ /// @notice Set permissions for token property. /// @dev Throws error if `msg.sender` is not admin or owner of the collection. /// @param permissions Permissions for keys. + #[weight(>::set_token_property_permissions(permissions.len() as u32))] fn set_token_property_permissions( &mut self, caller: caller, @@ -98,7 +99,7 @@ let caller = T::CrossAccountId::from_eth(caller); const PERMISSIONS_FIELDS_COUNT: usize = 3; - let mut perms = >::new(); + let mut perms = Vec::new(); for (key, pp) in permissions { if pp.len() > PERMISSIONS_FIELDS_COUNT { @@ -112,11 +113,7 @@ .into()); } - let mut token_permission = PropertyPermission { - mutable: false, - collection_admin: false, - token_owner: false, - }; + let mut token_permission = PropertyPermission::default(); for (perm, value) in pp { match perm { @@ -129,9 +126,7 @@ } perms.push(PropertyKeyPermission { - key: >::from(key) - .try_into() - .map_err(|_| "too long key")?, + key: key.into_bytes().try_into().map_err(|_| "too long key")?, permission: token_permission, }); } @@ -144,17 +139,19 @@ fn token_property_permissions( &self, ) -> Result)>> { - let mut res = >::new(); - for (key, pp) in >::token_property_permission(self.id) { - let key = string::from_utf8(key.into_inner()).unwrap(); - let pp = vec![ - (EthTokenPermissions::Mutable, pp.mutable), - (EthTokenPermissions::TokenOwner, pp.token_owner), - (EthTokenPermissions::CollectionAdmin, pp.collection_admin), - ]; - res.push((key, pp)); - } - Ok(res) + let perms = >::token_property_permission(self.id); + Ok(perms + .into_iter() + .map(|(key, pp)| { + let key = string::from_utf8(key.into_inner()).expect("Stored key must be valid"); + let pp = vec![ + (EthTokenPermissions::Mutable, pp.mutable), + (EthTokenPermissions::TokenOwner, pp.token_owner), + (EthTokenPermissions::CollectionAdmin, pp.collection_admin), + ]; + (key, pp) + }) + .collect()) } /// @notice Set token property value. --- a/pallets/refungible/src/erc.rs +++ b/pallets/refungible/src/erc.rs @@ -93,6 +93,7 @@ /// @notice Set permissions for token property. /// @dev Throws error if `msg.sender` is not admin or owner of the collection. /// @param permissions Permissions for keys. + #[weight(>::set_token_property_permissions(permissions.len() as u32))] fn set_token_property_permissions( &mut self, caller: caller, @@ -101,7 +102,7 @@ let caller = T::CrossAccountId::from_eth(caller); const PERMISSIONS_FIELDS_COUNT: usize = 3; - let mut perms = >::new(); + let mut perms = Vec::new(); for (key, pp) in permissions { if pp.len() > PERMISSIONS_FIELDS_COUNT { @@ -132,9 +133,7 @@ } perms.push(PropertyKeyPermission { - key: >::from(key) - .try_into() - .map_err(|_| "too long key")?, + key: key.into_bytes().try_into().map_err(|_| "too long key")?, permission: token_permission, }); } @@ -147,18 +146,19 @@ fn token_property_permissions( &self, ) -> Result)>> { - let mut res = >::new(); - for (key, pp) in >::token_property_permission(self.id) { - let key = string::from_utf8(key.into_inner()).unwrap(); - let pp = [ - (EthTokenPermissions::Mutable, pp.mutable), - (EthTokenPermissions::TokenOwner, pp.token_owner), - (EthTokenPermissions::CollectionAdmin, pp.collection_admin), - ] - .into(); - res.push((key, pp)); - } - Ok(res) + let perms = >::token_property_permission(self.id); + Ok(perms + .into_iter() + .map(|(key, pp)| { + let key = string::from_utf8(key.into_inner()).expect("Stored key must be valid"); + let pp = vec![ + (EthTokenPermissions::Mutable, pp.mutable), + (EthTokenPermissions::TokenOwner, pp.token_owner), + (EthTokenPermissions::CollectionAdmin, pp.collection_admin), + ]; + (key, pp) + }) + .collect()) } /// @notice Set token property value. --- a/primitives/data-structs/src/lib.rs +++ b/primitives/data-structs/src/lib.rs @@ -1010,7 +1010,7 @@ pub type PropertyValue = BoundedBytes>; /// Property permission. -#[derive(Encode, Decode, TypeInfo, Debug, MaxEncodedLen, PartialEq, Clone)] +#[derive(Encode, Decode, TypeInfo, Debug, MaxEncodedLen, PartialEq, Clone, Default)] #[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))] pub struct PropertyPermission { /// Permission to change the property and property permission. --- a/tests/src/eth/tokenProperties.test.ts +++ b/tests/src/eth/tokenProperties.test.ts @@ -69,6 +69,134 @@ })); [ + {mode: 'nft' as const, requiredPallets: []}, + {mode: 'rft' as const, requiredPallets: [Pallets.ReFungible]}, + ].map(testCase => + itEth.ifWithPallets(`[${testCase.mode}] Set and get multiple token property permissions as owner`, testCase.requiredPallets, async({helper}) => { + const owner = await helper.eth.createAccountWithBalance(donor); + + const {collectionId, collectionAddress} = await helper.eth.createCollection(testCase.mode, owner, 'A', 'B', 'C'); + const collection = await helper.ethNativeContract.collection(collectionAddress, testCase.mode, owner); + + await collection.methods.setTokenPropertyPermissions([ + ['testKey_0', [ + [EthTokenPermissions.Mutable, true], + [EthTokenPermissions.TokenOwner, true], + [EthTokenPermissions.CollectionAdmin, true]], + ], + ['testKey_1', [ + [EthTokenPermissions.Mutable, true], + [EthTokenPermissions.TokenOwner, false], + [EthTokenPermissions.CollectionAdmin, true]], + ], + ['testKey_2', [ + [EthTokenPermissions.Mutable, false], + [EthTokenPermissions.TokenOwner, true], + [EthTokenPermissions.CollectionAdmin, false]], + ], + ]).send({from: owner}); + + expect(await helper[testCase.mode].getPropertyPermissions(collectionId)).to.be.deep.equal([ + { + key: 'testKey_0', + permission: {mutable: true, tokenOwner: true, collectionAdmin: true}, + }, + { + key: 'testKey_1', + permission: {mutable: true, tokenOwner: false, collectionAdmin: true}, + }, + { + key: 'testKey_2', + permission: {mutable: false, tokenOwner: true, collectionAdmin: false}, + }, + ]); + + expect(await collection.methods.tokenPropertyPermissions().call({from: owner})).to.be.like([ + ['testKey_0', [ + [EthTokenPermissions.Mutable.toString(), true], + [EthTokenPermissions.TokenOwner.toString(), true], + [EthTokenPermissions.CollectionAdmin.toString(), true]], + ], + ['testKey_1', [ + [EthTokenPermissions.Mutable.toString(), true], + [EthTokenPermissions.TokenOwner.toString(), false], + [EthTokenPermissions.CollectionAdmin.toString(), true]], + ], + ['testKey_2', [ + [EthTokenPermissions.Mutable.toString(), false], + [EthTokenPermissions.TokenOwner.toString(), true], + [EthTokenPermissions.CollectionAdmin.toString(), false]], + ], + ]); + + })); + + [ + {mode: 'nft' as const, requiredPallets: []}, + {mode: 'rft' as const, requiredPallets: [Pallets.ReFungible]}, + ].map(testCase => + itEth.ifWithPallets(`[${testCase.mode}] Set and get multiple token property permissions as admin`, testCase.requiredPallets, async({helper}) => { + const owner = await helper.eth.createAccountWithBalance(donor); + const caller = await helper.ethCrossAccount.createAccountWithBalance(donor); + + const {collectionId, collectionAddress} = await helper.eth.createCollection(testCase.mode, owner, 'A', 'B', 'C'); + const collection = await helper.ethNativeContract.collection(collectionAddress, testCase.mode, owner); + await collection.methods.addCollectionAdminCross(caller).send({from: owner}); + + await collection.methods.setTokenPropertyPermissions([ + ['testKey_0', [ + [EthTokenPermissions.Mutable, true], + [EthTokenPermissions.TokenOwner, true], + [EthTokenPermissions.CollectionAdmin, true]], + ], + ['testKey_1', [ + [EthTokenPermissions.Mutable, true], + [EthTokenPermissions.TokenOwner, false], + [EthTokenPermissions.CollectionAdmin, true]], + ], + ['testKey_2', [ + [EthTokenPermissions.Mutable, false], + [EthTokenPermissions.TokenOwner, true], + [EthTokenPermissions.CollectionAdmin, false]], + ], + ]).send({from: caller.eth}); + + expect(await helper[testCase.mode].getPropertyPermissions(collectionId)).to.be.deep.equal([ + { + key: 'testKey_0', + permission: {mutable: true, tokenOwner: true, collectionAdmin: true}, + }, + { + key: 'testKey_1', + permission: {mutable: true, tokenOwner: false, collectionAdmin: true}, + }, + { + key: 'testKey_2', + permission: {mutable: false, tokenOwner: true, collectionAdmin: false}, + }, + ]); + + expect(await collection.methods.tokenPropertyPermissions().call({from: caller.eth})).to.be.like([ + ['testKey_0', [ + [EthTokenPermissions.Mutable.toString(), true], + [EthTokenPermissions.TokenOwner.toString(), true], + [EthTokenPermissions.CollectionAdmin.toString(), true]], + ], + ['testKey_1', [ + [EthTokenPermissions.Mutable.toString(), true], + [EthTokenPermissions.TokenOwner.toString(), false], + [EthTokenPermissions.CollectionAdmin.toString(), true]], + ], + ['testKey_2', [ + [EthTokenPermissions.Mutable.toString(), false], + [EthTokenPermissions.TokenOwner.toString(), true], + [EthTokenPermissions.CollectionAdmin.toString(), false]], + ], + ]); + + })); + + [ { method: 'setProperties', methodParams: [[{key: 'testKey1', value: Buffer.from('testValue1')}, {key: 'testKey2', value: Buffer.from('testValue2')}]], @@ -319,6 +447,47 @@ const actualProps = await collectionEvm.methods.properties(token.tokenId, []).call(); expect(actualProps).to.deep.eq(expectedProps); })); + + [ + {mode: 'nft' as const, requiredPallets: []}, + {mode: 'rft' as const, requiredPallets: [Pallets.ReFungible]}, + ].map(testCase => + itEth.ifWithPallets(`[${testCase.mode}] Cant set token property permissions as non owner or admin`, testCase.requiredPallets, async({helper}) => { + const owner = await helper.eth.createAccountWithBalance(donor); + const caller = await helper.eth.createAccountWithBalance(donor); + + const {collectionAddress} = await helper.eth.createCollection(testCase.mode, owner, 'A', 'B', 'C'); + const collection = await helper.ethNativeContract.collection(collectionAddress, testCase.mode, owner); + + await expect(collection.methods.setTokenPropertyPermissions([ + ['testKey_0', [ + [EthTokenPermissions.Mutable, true], + [EthTokenPermissions.TokenOwner, true], + [EthTokenPermissions.CollectionAdmin, true]], + ], + ]).call({from: caller})).to.be.rejectedWith('NoPermission'); + })); + + [ + {mode: 'nft' as const, requiredPallets: []}, + {mode: 'rft' as const, requiredPallets: [Pallets.ReFungible]}, + ].map(testCase => + itEth.ifWithPallets(`[${testCase.mode}] Cant set token property permissions with invalid character`, testCase.requiredPallets, async({helper}) => { + const owner = await helper.eth.createAccountWithBalance(donor); + + const {collectionAddress} = await helper.eth.createCollection(testCase.mode, owner, 'A', 'B', 'C'); + const collection = await helper.ethNativeContract.collection(collectionAddress, testCase.mode, owner); + + await expect(collection.methods.setTokenPropertyPermissions([ + // "Space" is invalid character + ['testKey 0', [ + [EthTokenPermissions.Mutable, true], + [EthTokenPermissions.TokenOwner, true], + [EthTokenPermissions.CollectionAdmin, true]], + ], + ]).call({from: owner})).to.be.rejectedWith('InvalidCharacterInPropertyKey'); + })); + }); -- gitstuff