difftreelog
Merge pull request #881 from UniqueNetwork/fix/collection-owner-nesting
in: master
Fix/collection owner nesting
2 files changed
pallets/nonfungible/src/lib.rsdiffbeforeafterboth1273 Some(from),1273 Some(from),1274 nesting_budget,1274 nesting_budget,1275 )? {1275 )? {1276 // Pass, token existence is checked in `check_indirectly_owned`1276 // Pass, token existence and ouroboros checks are done in `check_indirectly_owned`1277 } else if nesting.collection_admin && handle.is_owner_or_admin(&sender) {1277 } else if nesting.collection_admin && handle.is_owner_or_admin(&sender) {1278 ensure!(1278 // token existence and ouroboros checks are done in `get_checked_topmost_owner`1279 <TokenData<T>>::contains_key((handle.id, under)),1279 let _ = <PalletStructure<T>>::get_checked_topmost_owner(1280 handle.id,1281 under,1282 Some(from),1283 nesting_budget,1284 )?1280 <CommonError<T>>::TokenNotFound1285 .ok_or(<CommonError<T>>::TokenNotFound)?;1281 );1282 } else {1286 } else {1283 fail!(<CommonError<T>>::UserIsNotAllowedToNest);1287 fail!(<CommonError<T>>::UserIsNotAllowedToNest);1284 }1288 }tests/src/nesting/graphs.test.tsdiffbeforeafterboth--- a/tests/src/nesting/graphs.test.ts
+++ b/tests/src/nesting/graphs.test.ts
@@ -16,7 +16,7 @@
import {IKeyringPair} from '@polkadot/types/types';
import {expect, itSub, usingPlaygrounds} from '../util';
-import {UniqueHelper, UniqueNFToken} from '../util/playgrounds/unique';
+import {UniqueHelper, UniqueNFTCollection, UniqueNFToken} from '../util/playgrounds/unique';
/**
* ```dot
@@ -25,7 +25,7 @@
* 8 -> 5
* ```
*/
-async function buildComplexObjectGraph(helper: UniqueHelper, sender: IKeyringPair): Promise<UniqueNFToken[]> {
+async function buildComplexObjectGraph(helper: UniqueHelper, sender: IKeyringPair): Promise<[UniqueNFTCollection,UniqueNFToken[]]> {
const collection = await helper.nft.mintCollection(sender, {permissions: {nesting: {tokenOwner: true}}});
const tokens = await collection.mintMultipleTokens(sender, Array(8).fill({owner: {Substrate: sender.address}}));
@@ -37,7 +37,7 @@
await tokens[2].nest(sender, tokens[1]);
await tokens[1].nest(sender, tokens[0]);
- return tokens;
+ return [collection, tokens];
}
describe('Graphs', () => {
@@ -51,21 +51,36 @@
});
itSub('Ouroboros can\'t be created in a complex graph', async ({helper}) => {
- const tokens = await buildComplexObjectGraph(helper, alice);
+ const [collection, tokens] = await buildComplexObjectGraph(helper, alice);
+
+ await collection.setPermissions(alice, {nesting: {collectionAdmin: false, tokenOwner: true}});
- // to self
+ // [token owner] to self
await expect(
tokens[0].nest(alice, tokens[0]),
- 'first transaction',
+ '[token owner] self-nesting is forbidden',
).to.be.rejectedWith(/structure\.OuroborosDetected/);
- // to nested part of graph
+ // [token owner] to nested part of graph
await expect(
tokens[0].nest(alice, tokens[4]),
- 'second transaction',
+ '[token owner] cannot nest the root node into an internal node',
).to.be.rejectedWith(/structure\.OuroborosDetected/);
await expect(
tokens[1].transferFrom(alice, tokens[0].nestingAccount(), tokens[7].nestingAccount()),
- 'third transaction',
+ '[token owner] cannot nest higher internal node into lower internal node',
+ ).to.be.rejectedWith(/structure\.OuroborosDetected/);
+
+ await collection.setPermissions(alice, {nesting: {collectionAdmin: true, tokenOwner: false}});
+
+ // [collection owner] to self
+ await expect(
+ tokens[0].nest(alice, tokens[0]),
+ '[collection owner] self-nesting is forbidden',
+ ).to.be.rejectedWith(/structure\.OuroborosDetected/);
+ // [collection owner] to nested part of graph
+ await expect(
+ tokens[0].nest(alice, tokens[4]),
+ '[collection owner] cannot nest the root node into an internal node',
).to.be.rejectedWith(/structure\.OuroborosDetected/);
});
});