git.delta.rocks / unique-network / refs/commits / 3563d095a013

difftreelog

Merge pull request #881 from UniqueNetwork/fix/collection-owner-nesting

Yaroslav Bolyukin2023-02-11parents: #7467766 #4a2e26d.patch.diff
in: master
Fix/collection owner nesting

2 files changed

modifiedpallets/nonfungible/src/lib.rsdiffbeforeafterboth
--- a/pallets/nonfungible/src/lib.rs
+++ b/pallets/nonfungible/src/lib.rs
@@ -1273,12 +1273,16 @@
 				Some(from),
 				nesting_budget,
 			)? {
-			// Pass, token existence is checked in `check_indirectly_owned`
+			// Pass, token existence and ouroboros checks are done in `check_indirectly_owned`
 		} else if nesting.collection_admin && handle.is_owner_or_admin(&sender) {
-			ensure!(
-				<TokenData<T>>::contains_key((handle.id, under)),
-				<CommonError<T>>::TokenNotFound
-			);
+			// token existence and ouroboros checks are done in `get_checked_topmost_owner`
+			let _ = <PalletStructure<T>>::get_checked_topmost_owner(
+				handle.id,
+				under,
+				Some(from),
+				nesting_budget,
+			)?
+			.ok_or(<CommonError<T>>::TokenNotFound)?;
 		} else {
 			fail!(<CommonError<T>>::UserIsNotAllowedToNest);
 		}
modifiedtests/src/nesting/graphs.test.tsdiffbeforeafterboth
1616
17import {IKeyringPair} from '@polkadot/types/types';17import {IKeyringPair} from '@polkadot/types/types';
18import {expect, itSub, usingPlaygrounds} from '../util';18import {expect, itSub, usingPlaygrounds} from '../util';
19import {UniqueHelper, UniqueNFToken} from '../util/playgrounds/unique';19import {UniqueHelper, UniqueNFTCollection, UniqueNFToken} from '../util/playgrounds/unique';
2020
21/**21/**
22 * ```dot22 * ```dot
25 * 8 -> 525 * 8 -> 5
26 * ```26 * ```
27 */27 */
28async function buildComplexObjectGraph(helper: UniqueHelper, sender: IKeyringPair): Promise<UniqueNFToken[]> {28async function buildComplexObjectGraph(helper: UniqueHelper, sender: IKeyringPair): Promise<[UniqueNFTCollection,UniqueNFToken[]]> {
29 const collection = await helper.nft.mintCollection(sender, {permissions: {nesting: {tokenOwner: true}}});29 const collection = await helper.nft.mintCollection(sender, {permissions: {nesting: {tokenOwner: true}}});
30 const tokens = await collection.mintMultipleTokens(sender, Array(8).fill({owner: {Substrate: sender.address}}));30 const tokens = await collection.mintMultipleTokens(sender, Array(8).fill({owner: {Substrate: sender.address}}));
3131
37 await tokens[2].nest(sender, tokens[1]);37 await tokens[2].nest(sender, tokens[1]);
38 await tokens[1].nest(sender, tokens[0]);38 await tokens[1].nest(sender, tokens[0]);
3939
40 return tokens;40 return [collection, tokens];
41}41}
4242
43describe('Graphs', () => {43describe('Graphs', () => {
51 });51 });
5252
53 itSub('Ouroboros can\'t be created in a complex graph', async ({helper}) => {53 itSub('Ouroboros can\'t be created in a complex graph', async ({helper}) => {
54 const tokens = await buildComplexObjectGraph(helper, alice);54 const [collection, tokens] = await buildComplexObjectGraph(helper, alice);
55
56 await collection.setPermissions(alice, {nesting: {collectionAdmin: false, tokenOwner: true}});
5557
56 // to self58 // [token owner] to self
57 await expect(59 await expect(
58 tokens[0].nest(alice, tokens[0]),60 tokens[0].nest(alice, tokens[0]),
59 'first transaction',61 '[token owner] self-nesting is forbidden',
60 ).to.be.rejectedWith(/structure\.OuroborosDetected/);62 ).to.be.rejectedWith(/structure\.OuroborosDetected/);
61 // to nested part of graph63 // [token owner] to nested part of graph
62 await expect(64 await expect(
63 tokens[0].nest(alice, tokens[4]),65 tokens[0].nest(alice, tokens[4]),
64 'second transaction',66 '[token owner] cannot nest the root node into an internal node',
65 ).to.be.rejectedWith(/structure\.OuroborosDetected/);67 ).to.be.rejectedWith(/structure\.OuroborosDetected/);
66 await expect(68 await expect(
67 tokens[1].transferFrom(alice, tokens[0].nestingAccount(), tokens[7].nestingAccount()),69 tokens[1].transferFrom(alice, tokens[0].nestingAccount(), tokens[7].nestingAccount()),
68 'third transaction',70 '[token owner] cannot nest higher internal node into lower internal node',
69 ).to.be.rejectedWith(/structure\.OuroborosDetected/);71 ).to.be.rejectedWith(/structure\.OuroborosDetected/);
72
73 await collection.setPermissions(alice, {nesting: {collectionAdmin: true, tokenOwner: false}});
74
75 // [collection owner] to self
76 await expect(
77 tokens[0].nest(alice, tokens[0]),
78 '[collection owner] self-nesting is forbidden',
79 ).to.be.rejectedWith(/structure\.OuroborosDetected/);
80 // [collection owner] to nested part of graph
81 await expect(
82 tokens[0].nest(alice, tokens[4]),
83 '[collection owner] cannot nest the root node into an internal node',
84 ).to.be.rejectedWith(/structure\.OuroborosDetected/);
70 });85 });
71});86});
7287