difftreelog
Nesting tests refactoring WIP
in: master
5 files changed
tests/src/nesting/nest.test.tsdiffbeforeafterboth72 });72 });73 });73 });7475 itSub('Admin (NFT): allows an Admin to nest a token', async ({helper}) => {76 const collection = await helper.nft.mintCollection(alice, {permissions: {nesting: {collectionAdmin: true}}});77 await collection.addAdmin(alice, {Substrate: bob.address});78 const targetToken = await collection.mintToken(alice, {Substrate: charlie.address});7980 // Create an immediately nested token81 const nestedToken = await collection.mintToken(bob, targetToken.nestingAccount());82 expect(await nestedToken.getTopmostOwner()).to.be.deep.equal({Substrate: charlie.address});83 expect(await nestedToken.getOwner()).to.be.deep.equal(targetToken.nestingAccount().toLowerCase());8485 // Create a token to be nested and nest86 const newToken = await collection.mintToken(bob);87 await newToken.nest(bob, targetToken);88 expect(await newToken.getTopmostOwner()).to.be.deep.equal({Substrate: charlie.address});89 expect(await newToken.getOwner()).to.be.deep.equal(targetToken.nestingAccount().toLowerCase());90 });9192 itSub('Admin (NFT): Admin and Token Owner can operate together', async ({helper}) => {93 const collection = await helper.nft.mintCollection(alice, {permissions: {nesting: {collectionAdmin: true, tokenOwner: true}}});94 await collection.addAdmin(alice, {Substrate: bob.address});95 const targetToken = await collection.mintToken(alice, {Substrate: charlie.address});9697 // Create an immediately nested token by an administrator98 const nestedToken = await collection.mintToken(bob, targetToken.nestingAccount());99 expect(await nestedToken.getTopmostOwner()).to.be.deep.equal({Substrate: charlie.address});100 expect(await nestedToken.getOwner()).to.be.deep.equal(targetToken.nestingAccount().toLowerCase());101102 // Create a token to be nested and nest103 const newToken = await collection.mintToken(alice, {Substrate: charlie.address});104 await newToken.nest(charlie, targetToken);105 expect(await newToken.getTopmostOwner()).to.be.deep.equal({Substrate: charlie.address});106 expect(await newToken.getOwner()).to.be.deep.equal(targetToken.nestingAccount().toLowerCase());107 });108109 itSub('Admin (NFT): allows an Admin to nest a token (Restricted nesting)', async ({helper}) => {110 const collectionA = await helper.nft.mintCollection(alice);111 await collectionA.addAdmin(alice, {Substrate: bob.address});112 const collectionB = await helper.nft.mintCollection(alice);113 await collectionB.addAdmin(alice, {Substrate: bob.address});114 await collectionA.setPermissions(alice, {nesting: {collectionAdmin: true, restricted:[collectionB.collectionId]}});115 const targetToken = await collectionA.mintToken(alice, {Substrate: charlie.address});116117 // Create an immediately nested token118 const nestedToken = await collectionB.mintToken(bob, targetToken.nestingAccount());119 expect(await nestedToken.getTopmostOwner()).to.be.deep.equal({Substrate: charlie.address});120 expect(await nestedToken.getOwner()).to.be.deep.equal(targetToken.nestingAccount().toLowerCase());121122 // Create a token to be nested and nest123 const newToken = await collectionB.mintToken(bob);124 await newToken.nest(bob, targetToken);125 expect(await newToken.getTopmostOwner()).to.be.deep.equal({Substrate: charlie.address});126 expect(await newToken.getOwner()).to.be.deep.equal(targetToken.nestingAccount().toLowerCase());127 });128129 // ---------- Non-Fungible ----------130131 itSub('NFT: allows an Owner to nest/unnest their token', async ({helper}) => {132 const collection = await helper.nft.mintCollection(alice, {permissions: {access: 'AllowList', mintMode: true, nesting: {tokenOwner: true}}});133 await collection.addToAllowList(alice, {Substrate: charlie.address});134 const targetToken = await collection.mintToken(charlie);135 await collection.addToAllowList(alice, targetToken.nestingAccount());136137 // Create an immediately nested token138 const nestedToken = await collection.mintToken(charlie, targetToken.nestingAccount());139 expect(await nestedToken.getTopmostOwner()).to.be.deep.equal({Substrate: charlie.address});140 expect(await nestedToken.getOwner()).to.be.deep.equal(targetToken.nestingAccount().toLowerCase());141142 // Create a token to be nested and nest143 const newToken = await collection.mintToken(charlie);144 await newToken.nest(charlie, targetToken);145 expect(await newToken.getTopmostOwner()).to.be.deep.equal({Substrate: charlie.address});146 expect(await newToken.getOwner()).to.be.deep.equal(targetToken.nestingAccount().toLowerCase());147 });148149 itSub('NFT: allows an Owner to nest/unnest their token (Restricted nesting)', async ({helper}) => {150 const collectionA = await helper.nft.mintCollection(alice);151 const collectionB = await helper.nft.mintCollection(alice);152 //await collectionB.addAdmin(alice, {Substrate: bob.address});153 const targetToken = await collectionA.mintToken(alice, {Substrate: charlie.address});154155 await collectionA.setPermissions(alice, {access: 'AllowList', mintMode: true, nesting: {tokenOwner: true, restricted:[collectionB.collectionId]}});156 await collectionA.addToAllowList(alice, {Substrate: charlie.address});157 await collectionA.addToAllowList(alice, targetToken.nestingAccount());158159 await collectionB.setPermissions(alice, {access: 'AllowList', mintMode: true});160 await collectionB.addToAllowList(alice, {Substrate: charlie.address});161 await collectionB.addToAllowList(alice, targetToken.nestingAccount());162163 // Create an immediately nested token164 const nestedToken = await collectionB.mintToken(charlie, targetToken.nestingAccount());165 expect(await nestedToken.getTopmostOwner()).to.be.deep.equal({Substrate: charlie.address});166 expect(await nestedToken.getOwner()).to.be.deep.equal(targetToken.nestingAccount().toLowerCase());167168 // Create a token to be nested and nest169 const newToken = await collectionB.mintToken(charlie);170 await newToken.nest(charlie, targetToken);171 expect(await newToken.getTopmostOwner()).to.be.deep.equal({Substrate: charlie.address});172 expect(await newToken.getOwner()).to.be.deep.equal(targetToken.nestingAccount().toLowerCase());173 });174175 // ---------- Fungible ----------176177 itSub('Fungible: allows an Owner to nest/unnest their token', async ({helper}) => {178 const collectionNFT = await helper.nft.mintCollection(alice, {permissions: {access: 'AllowList', mintMode: true, nesting: {tokenOwner: true}}});179 const collectionFT = await helper.ft.mintCollection(alice);180 const targetToken = await collectionNFT.mintToken(alice, {Substrate: charlie.address});181182 await collectionNFT.addToAllowList(alice, {Substrate: charlie.address});183 await collectionNFT.addToAllowList(alice, targetToken.nestingAccount());184185 await collectionFT.setPermissions(alice, {access: 'AllowList', mintMode: true});186 await collectionFT.addToAllowList(alice, {Substrate: charlie.address});187 await collectionFT.addToAllowList(alice, targetToken.nestingAccount());188189 // Create an immediately nested token190 await collectionFT.mint(charlie, 5n, targetToken.nestingAccount());191 expect(await collectionFT.getBalance(targetToken.nestingAccount())).to.be.equal(5n);192193 // Create a token to be nested and nest194 await collectionFT.mint(charlie, 5n);195 await collectionFT.transfer(charlie, targetToken.nestingAccount(), 2n);196 expect(await collectionFT.getBalance(targetToken.nestingAccount())).to.be.equal(7n);197 });198199 itSub('Fungible: allows an Owner to nest/unnest their token (Restricted nesting)', async ({helper}) => {200 const collectionNFT = await helper.nft.mintCollection(alice);201 const collectionFT = await helper.ft.mintCollection(alice);202 const targetToken = await collectionNFT.mintToken(alice, {Substrate: charlie.address});203204 await collectionNFT.setPermissions(alice, {access: 'AllowList', mintMode: true, nesting: {tokenOwner: true, restricted:[collectionFT.collectionId]}});205 await collectionNFT.addToAllowList(alice, {Substrate: charlie.address});206 await collectionNFT.addToAllowList(alice, targetToken.nestingAccount());207208 await collectionFT.setPermissions(alice, {access: 'AllowList', mintMode: true});209 await collectionFT.addToAllowList(alice, {Substrate: charlie.address});210 await collectionFT.addToAllowList(alice, targetToken.nestingAccount());211212 // Create an immediately nested token213 await collectionFT.mint(charlie, 5n, targetToken.nestingAccount());214 expect(await collectionFT.getBalance(targetToken.nestingAccount())).to.be.equal(5n);215216 // Create a token to be nested and nest217 await collectionFT.mint(charlie, 5n);218 await collectionFT.transfer(charlie, targetToken.nestingAccount(), 2n);219 expect(await collectionFT.getBalance(targetToken.nestingAccount())).to.be.equal(7n);220 });22174222 itSub.ifWithPallets('ReFungible: getTopmostOwner works correctly with Nesting', [Pallets.ReFungible], async({helper}) => {75 itSub.ifWithPallets('ReFungible: getTopmostOwner works correctly with Nesting', [Pallets.ReFungible], async({helper}) => {223 const collectionNFT = await helper.nft.mintCollection(alice, {76 const collectionNFT = await helper.nft.mintCollection(alice, {263 });116 });264 });117 });265266 itSub('Disallows excessive token nesting', async ({helper}) => {267 const collection = await helper.nft.mintCollection(alice, {permissions: {nesting: {tokenOwner: true}}});268 let token = await collection.mintToken(alice);269270 const maxNestingLevel = 5;271272 // Create a nested-token matryoshka273 for (let i = 0; i < maxNestingLevel; i++) {274 token = await collection.mintToken(alice, token.nestingAccount());275 }276277 // The nesting depth is limited by `maxNestingLevel`278 await expect(collection.mintToken(alice, token.nestingAccount()))279 .to.be.rejectedWith(/structure\.DepthLimit/);280 expect(await token.getTopmostOwner()).to.be.deep.equal({Substrate: alice.address});281 expect(await token.getChildren()).to.be.length(0);282 });283284 // ---------- Admin ------------285118286 itSub('Admin (NFT): disallows an Admin to operate nesting when only TokenOwner is allowed', async ({helper}) => {119 itSub('Admin (NFT): disallows an Admin to operate nesting when only TokenOwner is allowed', async ({helper}) => {287 const collection = await helper.nft.mintCollection(alice, {permissions: {nesting: {tokenOwner: true}}});120 const collection = await helper.nft.mintCollection(alice, {permissions: {nesting: {tokenOwner: true}}});302 });135 });303136304 itSub('Admin (NFT): disallows a Token Owner to operate nesting when only Admin is allowed', async ({helper}) => {137 itSub('Admin (NFT): disallows a Token Owner to operate nesting when only Admin is allowed', async ({helper}) => {305 const collection = await helper.nft.mintCollection(alice, {permissions: {access: 'AllowList', mintMode: true, nesting: {collectionAdmin: true}}});138 const collectionAlice = await helper.nft.mintCollection(alice, {permissions: {access: 'AllowList', mintMode: true, nesting: {collectionAdmin: true}}});306 const targetToken = await collection.mintToken(alice, {Substrate: bob.address});139 const targetTokenBob = await collectionAlice.mintToken(alice, {Substrate: bob.address});307 await collection.addToAllowList(alice, {Substrate: bob.address});140 await collectionAlice.addToAllowList(alice, {Substrate: bob.address});308 await collection.addToAllowList(alice, targetToken.nestingAccount());141 await collectionAlice.addToAllowList(alice, targetTokenBob.nestingAccount());309142310 // Try to create a nested token as token owner when it's disallowed143 // Try to create a nested token as token owner when it's disallowed311 await expect(collection.mintToken(bob, targetToken.nestingAccount()))144 await expect(collectionAlice.mintToken(bob, targetTokenBob.nestingAccount()))312 .to.be.rejectedWith(/common\.UserIsNotAllowedToNest/);145 .to.be.rejectedWith(/common\.UserIsNotAllowedToNest/);313146314 // Try to create a token to be nested and nest147 // Try to create a token to be nested and nest315 const newToken = await collection.mintToken(bob);148 const newToken = await collectionAlice.mintToken(bob);316 await expect(newToken.nest(bob, targetToken))149 await expect(newToken.nest(bob, targetTokenBob))317 .to.be.rejectedWith(/common\.UserIsNotAllowedToNest/);150 .to.be.rejectedWith(/common\.UserIsNotAllowedToNest/);318151319 expect(await targetToken.getChildren()).to.be.length(0);152 expect(await targetTokenBob.getChildren()).to.be.length(0);320 expect(await newToken.getOwner()).to.be.deep.equal({Substrate: bob.address});153 expect(await newToken.getOwner()).to.be.deep.equal({Substrate: bob.address});321 });154 });322155342 expect(await nestedToken.getOwner()).to.be.deep.equal(targetToken.nestingAccount().toLowerCase());175 expect(await nestedToken.getOwner()).to.be.deep.equal(targetToken.nestingAccount().toLowerCase());343 });176 });344345 itSub('Admin (NFT): disallows an Admin to nest a token from an unlisted collection (Restricted nesting)', async ({helper}) => {346 const collectionA = await helper.nft.mintCollection(alice);347 const collectionB = await helper.nft.mintCollection(alice);348 await collectionA.setPermissions(alice, {nesting: {collectionAdmin: true, restricted: [collectionA.collectionId]}});349 const targetToken = await collectionA.mintToken(alice);350351 // Try to create a nested token from another collection352 await expect(collectionB.mintToken(alice, targetToken.nestingAccount()))353 .to.be.rejectedWith(/common\.SourceCollectionIsNotAllowedToNest/);354355 // Create a token in another collection yet to be nested and try to nest356 const newToken = await collectionB.mintToken(alice);357 await expect(newToken.nest(alice, targetToken))358 .to.be.rejectedWith(/common\.SourceCollectionIsNotAllowedToNest/);359360 expect(await targetToken.getChildren()).to.be.length(0);361 expect(await newToken.getOwner()).to.be.deep.equal({Substrate: alice.address});362 });363364 // ---------- Non-Fungible ----------365366 itSub('NFT: disallows to nest token if nesting is disabled', async ({helper}) => {367 // Collection is implicitly not allowed nesting at creation368 const collection = await helper.nft.mintCollection(alice);369 const targetToken = await collection.mintToken(alice);370371 // Try to create a nested token as token owner when it's disallowed372 await expect(collection.mintToken(alice, targetToken.nestingAccount()))373 .to.be.rejectedWith(/common\.UserIsNotAllowedToNest/);374375 // Try to create a token to be nested and nest376 const newToken = await collection.mintToken(alice);377 await expect(newToken.nest(alice, targetToken))378 .to.be.rejectedWith(/common\.UserIsNotAllowedToNest/);379380 expect(await targetToken.getChildren()).to.be.length(0);381 expect(await newToken.getOwner()).to.be.deep.equal({Substrate: alice.address});382 });383384 itSub('NFT: disallows a non-Owner to nest someone else\'s token', async ({helper}) => {385 const collection = await helper.nft.mintCollection(alice);386 const targetToken = await collection.mintToken(alice);387388 await collection.setPermissions(alice, {access: 'AllowList', mintMode: true, nesting: {tokenOwner: true}});389 await collection.addToAllowList(alice, {Substrate: bob.address});390 await collection.addToAllowList(alice, targetToken.nestingAccount());391392 // Try to create a token to be nested and nest393 const newToken = await collection.mintToken(alice);394 await expect(newToken.nest(bob, targetToken)).to.be.rejectedWith(/common\.NoPermission/);395396 expect(await targetToken.getChildren()).to.be.length(0);397 expect(await newToken.getOwner()).to.be.deep.equal({Substrate: alice.address});398 });399400 itSub('NFT: disallows a non-Owner to nest someone else\'s token (Restricted nesting)', async ({helper}) => {401 const collection = await helper.nft.mintCollection(alice);402 const targetToken = await collection.mintToken(alice);403404 await collection.setPermissions(alice, {access: 'AllowList', mintMode: true, nesting: {tokenOwner: true}});405 await collection.addToAllowList(alice, {Substrate: bob.address});406 await collection.addToAllowList(alice, targetToken.nestingAccount());407408 const collectionB = await helper.nft.mintCollection(alice, {permissions: {access: 'AllowList', mintMode: true}});409 await collectionB.addToAllowList(alice, {Substrate: bob.address});410 await collectionB.addToAllowList(alice, targetToken.nestingAccount());411412 // Try to create a token to be nested and nest413 const newToken = await collectionB.mintToken(alice);414 await expect(newToken.nest(bob, targetToken)).to.be.rejectedWith(/common\.NoPermission/);415416 expect(await targetToken.getChildren()).to.be.length(0);417 expect(await newToken.getOwner()).to.be.deep.equal({Substrate: alice.address});418 });419420 itSub('NFT: disallows to nest token in an unlisted collection', async ({helper}) => {421 // Create collection with restricted nesting -- even self is not allowed422 const collection = await helper.nft.mintCollection(alice, {permissions: {access: 'AllowList', mintMode: true, nesting: {tokenOwner: true, restricted: []}}});423 const targetToken = await collection.mintToken(alice, {Substrate: bob.address});424425 await collection.addToAllowList(alice, {Substrate: bob.address});426 await collection.addToAllowList(alice, targetToken.nestingAccount());427428 // Try to mint in own collection after allowlisting the accounts429 await expect(collection.mintToken(bob, targetToken.nestingAccount()))430 .to.be.rejectedWith(/common\.SourceCollectionIsNotAllowedToNest/);431 });432433 // ---------- Fungible ----------434435 itSub('Fungible: disallows to nest token if nesting is disabled', async ({helper}) => {436 const collectionNFT = await helper.nft.mintCollection(alice);437 const collectionFT = await helper.ft.mintCollection(alice);438 const targetToken = await collectionNFT.mintToken(alice);439440 // Try to create an immediately nested token441 await expect(collectionFT.mint(alice, 5n, targetToken.nestingAccount()))442 .to.be.rejectedWith(/common\.UserIsNotAllowedToNest/);443444 // Try to create a token to be nested and nest445 await collectionFT.mint(alice, 5n);446 await expect(collectionFT.transfer(alice, targetToken.nestingAccount(), 2n))447 .to.be.rejectedWith(/common\.UserIsNotAllowedToNest/);448 expect(await collectionFT.getBalance({Substrate: alice.address})).to.be.equal(5n);449 });450177451 itSub('Fungible: disallows a non-Owner to unnest someone else\'s token', async ({helper}) => {178 itSub('Fungible: disallows a non-Owner to unnest someone else\'s token', async ({helper}) => {452 const collectionNFT = await helper.nft.mintCollection(alice, {permissions: {nesting: {collectionAdmin: true, tokenOwner: true}}});179 const collectionNFT = await helper.nft.mintCollection(alice, {permissions: {nesting: {collectionAdmin: true, tokenOwner: true}}});478 expect(await collectionFT.getBalance(targetToken.nestingAccount())).to.be.equal(5n);205 expect(await collectionFT.getBalance(targetToken.nestingAccount())).to.be.equal(5n);479 });206 });480207481 itSub('Fungible: disallows to nest token in an unlisted collection', async ({helper}) => {482 const collectionNFT = await helper.nft.mintCollection(alice, {permissions: {nesting: {collectionAdmin: true, tokenOwner: true, restricted: []}}});483 const collectionFT = await helper.ft.mintCollection(alice);484 const targetToken = await collectionNFT.mintToken(alice);485486 // Try to mint an immediately nested token487 await expect(collectionFT.mint(alice, 5n, targetToken.nestingAccount()))488 .to.be.rejectedWith(/common\.SourceCollectionIsNotAllowedToNest/);489490 // Mint a token and try to nest it491 await collectionFT.mint(alice, 5n);492 await expect(collectionFT.transfer(alice, targetToken.nestingAccount(), 1n))493 .to.be.rejectedWith(/common\.SourceCollectionIsNotAllowedToNest/);494495 expect(await collectionFT.getBalance(targetToken.nestingAccount())).to.be.equal(0n);496 expect(await collectionFT.getBalance({Substrate: alice.address})).to.be.equal(5n);497 });498});208});499209tests/src/sub/nesting/admin.test.tsdiffbeforeafterbothno changes
tests/src/sub/nesting/common.test.tsdiffbeforeafterboth19import {UniqueNFTCollection, UniqueRFTCollection} from '../../util/playgrounds/unique';19import {UniqueNFTCollection, UniqueRFTCollection} from '../../util/playgrounds/unique';202021let alice: IKeyringPair;21let alice: IKeyringPair;22let bob: IKeyringPair;222323before(async () => {24before(async () => {24 await usingPlaygrounds(async (helper, privateKey) => {25 await usingPlaygrounds(async (helper, privateKey) => {25 const donor = await privateKey({filename: __filename});26 const donor = await privateKey({filename: __filename});26 [alice] = await helper.arrange.createAccounts([100n], donor);27 [alice, bob] = await helper.arrange.createAccounts([100n, 100n], donor);27 });28 });28});29});293030[31[31 {mode: 'nft' as const, requiredPallets: []},32 {mode: 'nft' as const, restrictedMode: true, requiredPallets: []},33 {mode: 'nft' as const, restrictedMode: false, requiredPallets: []},32 {mode: 'rft' as const, requiredPallets: [Pallets.ReFungible]},34 {mode: 'rft' as const, restrictedMode: true, requiredPallets: [Pallets.ReFungible]},35 {mode: 'rft' as const, restrictedMode: false, requiredPallets: [Pallets.ReFungible]},33].map(testCase => {36].map(testCase => {34 itSub.ifWithPallets(`Owner can nest ${testCase.mode.toUpperCase()} in NFT`, testCase.requiredPallets, async ({helper}) => {37 itSub.ifWithPallets(`Token owner can nest ${testCase.mode.toUpperCase()} in NFT if "tokenOwner" permission set ${testCase.restrictedMode ? 'in restricted mode': ''}`, testCase.requiredPallets, async ({helper}) => {35 // Only NFT allows nesting, permissions should be set:38 // Only NFT can be target for nesting in36 const aliceNFTCollection = await helper.nft.mintCollection(alice, {permissions: {nesting: {tokenOwner: true}}});39 const targetNFTCollection = await helper.nft.mintCollection(alice);37 const targetToken = await aliceNFTCollection.mintToken(alice);40 const targetTokenBob = await targetNFTCollection.mintToken(alice, {Substrate: bob.address});384139 const collectionForNesting = await helper[testCase.mode].mintCollection(alice);42 const collectionForNesting = await helper[testCase.mode].mintCollection(bob);43 // permissions should be set:44 await targetNFTCollection.setPermissions(alice, {45 nesting: {tokenOwner: true, restricted: testCase.restrictedMode ? [collectionForNesting.collectionId] : null},46 });404741 // 1. Alice can immediately create nested token:48 // 1. Bob can immediately create nested token:42 const nestedToken1 = testCase.mode === 'nft'49 const nestedToken1 = testCase.mode === 'nft'43 ? await (collectionForNesting as UniqueNFTCollection).mintToken(alice, targetToken.nestingAccount())50 ? await (collectionForNesting as UniqueNFTCollection).mintToken(bob, targetTokenBob.nestingAccount())44 : await (collectionForNesting as UniqueRFTCollection).mintToken(alice, 10n, targetToken.nestingAccount());51 : await (collectionForNesting as UniqueRFTCollection).mintToken(bob, 10n, targetTokenBob.nestingAccount());45 expect(await nestedToken1.getTopmostOwner()).to.be.deep.equal({Substrate: alice.address});52 expect(await nestedToken1.getTopmostOwner()).to.be.deep.equal({Substrate: bob.address});46 expect(await nestedToken1.getOwner()).to.be.deep.equal(targetToken.nestingAccount().toLowerCase());53 expect(await nestedToken1.getOwner()).to.be.deep.equal(targetTokenBob.nestingAccount().toLowerCase());475448 // 2. Alice can mint and nest token:55 // 2. Bob can mint and nest token:49 const nestedToken2 = await collectionForNesting.mintToken(alice);56 const nestedToken2 = await collectionForNesting.mintToken(bob);50 await nestedToken2.nest(alice, targetToken);57 await nestedToken2.nest(bob, targetTokenBob);51 expect(await nestedToken2.getTopmostOwner()).to.be.deep.equal({Substrate: alice.address});58 expect(await nestedToken2.getTopmostOwner()).to.be.deep.equal({Substrate: bob.address});52 expect(await nestedToken2.getOwner()).to.be.deep.equal(targetToken.nestingAccount().toLowerCase());59 expect(await nestedToken2.getOwner()).to.be.deep.equal(targetTokenBob.nestingAccount().toLowerCase());53 });60 });54});61});5562566364[65 {restrictedMode: true},66 {restrictedMode: false},67].map(testCase => {57itSub('Owner can nest FT in NFT', async ({helper}) => {68 itSub(`Token owner can nest FT in NFT if "tokenOwner" permission set ${testCase.restrictedMode ? 'in restricted mode': ''}`, async ({helper}) => {58 // Only NFT allows nesting, permissions should be set:69 // Only NFT allows nesting, permissions should be set:59 const aliceNFTCollection = await helper.nft.mintCollection(alice, {permissions: {nesting: {tokenOwner: true}}});70 const targetNFTCollection = await helper.nft.mintCollection(alice);60 const targetToken = await aliceNFTCollection.mintToken(alice);71 const targetTokenBob = await targetNFTCollection.mintToken(alice, {Substrate: bob.address});617262 const collectionForNesting = await helper.ft.mintCollection(alice);73 const collectionForNesting = await helper.ft.mintCollection(bob);74 // permissions should be set:75 await targetNFTCollection.setPermissions(alice, {76 nesting: {tokenOwner: true, restricted: testCase.restrictedMode ? [collectionForNesting.collectionId] : null},77 });637864 // 1. Alice can immediately create nested tokens:79 // 1. Alice can immediately create nested tokens:65 await collectionForNesting.mint(alice, 100n, targetToken.nestingAccount());80 await collectionForNesting.mint(bob, 100n, targetTokenBob.nestingAccount());66 expect(await collectionForNesting.getTop10Owners()).deep.eq([targetToken.nestingAccount().toLowerCase()]);81 expect(await collectionForNesting.getTop10Owners()).deep.eq([targetTokenBob.nestingAccount().toLowerCase()]);67 expect(await collectionForNesting.getBalance(targetToken.nestingAccount())).eq(100n);82 expect(await collectionForNesting.getBalance(targetTokenBob.nestingAccount())).eq(100n);688369 // 2. Alice can mint and nest token:84 // 2. Alice can mint and nest token:70 await collectionForNesting.mint(alice, 100n);85 await collectionForNesting.mint(bob, 100n);71 await collectionForNesting.transfer(alice, targetToken.nestingAccount(), 50n);86 await collectionForNesting.transfer(bob, targetTokenBob.nestingAccount(), 50n);72 expect(await collectionForNesting.getBalance(targetToken.nestingAccount())).eq(150n);87 expect(await collectionForNesting.getBalance(targetTokenBob.nestingAccount())).eq(150n);73});88 });89});7490759176itSub.ifWithPallets('Owner can transferFrom nested tokens', [Pallets.ReFungible], async ({helper}) => {92itSub.ifWithPallets('Owner can unnest tokens using transferFrom', [Pallets.ReFungible], async ({helper}) => {77 const collectionToNest = await helper.nft.mintCollection(alice, {permissions: {nesting: {tokenOwner: true}}});93 const collectionToNest = await helper.nft.mintCollection(alice, {permissions: {nesting: {tokenOwner: true}}});78 const tokenA = await collectionToNest.mintToken(alice);94 const tokenA = await collectionToNest.mintToken(alice);79 const tokenB = await collectionToNest.mintToken(alice);95 const tokenB = await collectionToNest.mintToken(alice);tests/src/sub/nesting/negative.test.tsdiffbeforeafterboth161617import {IKeyringPair} from '@polkadot/types/types';17import {IKeyringPair} from '@polkadot/types/types';18import {expect, itSub, Pallets, usingPlaygrounds} from '../../util';18import {expect, itSub, Pallets, usingPlaygrounds} from '../../util';19import {UniqueNFTCollection, UniqueRFTCollection} from '../../util/playgrounds/unique';19import {UniqueFTCollection, UniqueNFTCollection, UniqueNFToken, UniqueRFTCollection, UniqueRFToken} from '../../util/playgrounds/unique';20import {itEth} from '../../eth/util';20import {itEth} from '../../eth/util';212122let alice: IKeyringPair;22let alice: IKeyringPair;23let bob: IKeyringPair;232424before(async () => {25before(async () => {25 await usingPlaygrounds(async (helper, privateKey) => {26 await usingPlaygrounds(async (helper, privateKey) => {26 const donor = await privateKey({filename: __filename});27 const donor = await privateKey({filename: __filename});27 [alice] = await helper.arrange.createAccounts([50n], donor);28 [alice, bob] = await helper.arrange.createAccounts([100n, 100n], donor);28 });29 });29});30});303131[32[32 {mode: 'nft' as const, requiredPallets: []},33 {mode: 'nft' as const, requiredPallets: []},33 {mode: 'rft' as const, requiredPallets: [Pallets.ReFungible]},34 {mode: 'rft' as const, requiredPallets: [Pallets.ReFungible]},34].map(testCase => {35].map(testCase => {35 itSub.ifWithPallets(`Owner cannot nest ${testCase.mode.toUpperCase()} if nesting not allowed`, testCase.requiredPallets, async ({helper}) => {36 itSub.ifWithPallets(`Owner cannot nest ${testCase.mode.toUpperCase()} if nesting is disabled`, testCase.requiredPallets, async ({helper}) => {36 // Create default collection, permissions are not set:37 // Create default collection, permissions are not set:37 const aliceNFTCollection = await helper.nft.mintCollection(alice);38 const aliceNFTCollection = await helper.nft.mintCollection(alice);38 const targetToken = await aliceNFTCollection.mintToken(alice);39 const targetToken = await aliceNFTCollection.mintToken(alice);51 });52 });52});53});535454itSub('Owner cannot nest FT if nesting not allowed', async ({helper}) => {55itSub('Owner cannot nest FT if nesting is disabled', async ({helper}) => {55 // Create default collection, permissions are not set:56 // Create default collection, permissions are not set:56 const aliceNFTCollection = await helper.nft.mintCollection(alice);57 const aliceNFTCollection = await helper.nft.mintCollection(alice);57 const targetToken = await aliceNFTCollection.mintToken(alice);58 const targetToken = await aliceNFTCollection.mintToken(alice);66 await expect(collectionForNesting.transfer(alice, targetToken.nestingAccount(), 50n)).to.be.rejectedWith('common.UserIsNotAllowedToNest');67 await expect(collectionForNesting.transfer(alice, targetToken.nestingAccount(), 50n)).to.be.rejectedWith('common.UserIsNotAllowedToNest');67});68});6970[71 {mode: 'nft' as const},72 {mode: 'rft' as const},73 {mode: 'ft' as const},74].map(testCase => {75 itSub(`Non-owner and non-admin cannot nest ${testCase.mode.toUpperCase()} in someone else's tokens`, async ({helper}) => {76 const targetCollection = await helper.nft.mintCollection(alice, {permissions:77 {nesting: {tokenOwner: true, collectionAdmin: true}},78 });79 const targetToken = await targetCollection.mintToken(alice);8081 const nestedCollectionBob = await helper[testCase.mode].mintCollection(bob);8283 let nestedTokenBob: UniqueNFToken | UniqueRFToken;84 switch (testCase.mode) {85 case 'nft': nestedTokenBob = await (nestedCollectionBob as UniqueNFTCollection).mintToken(bob); break;86 case 'rft': nestedTokenBob = await (nestedCollectionBob as UniqueRFTCollection).mintToken(bob, 100n); break;87 case 'ft': await (nestedCollectionBob as UniqueFTCollection).mint(bob, 100n); break;88 }8990 // Bob non-owner of targetToken and non admin of targetCollection, so91 // 1. cannot mint nested token:92 switch (testCase.mode) {93 case 'nft': await expect((nestedCollectionBob as UniqueNFTCollection).mintToken(bob, targetToken.nestingAccount())).to.be.rejectedWith('common.UserIsNotAllowedToNest'); break;94 case 'rft': await expect((nestedCollectionBob as UniqueRFTCollection).mintToken(bob, 100n, targetToken.nestingAccount())).to.be.rejectedWith('common.UserIsNotAllowedToNest'); break;95 case 'ft': await expect((nestedCollectionBob as UniqueFTCollection).mint(bob, 100n, targetToken.nestingAccount())).to.be.rejectedWith('common.UserIsNotAllowedToNest'); break;96 }9798 // 2. cannot nest existing token:99 switch (testCase.mode) {100 case 'nft':101 case 'rft': await expect(nestedTokenBob!.transfer(bob, targetToken.nestingAccount())).to.be.rejectedWith('common.UserIsNotAllowedToNest'); break;102 case 'ft': await expect((nestedCollectionBob as UniqueFTCollection).transfer(bob, targetToken.nestingAccount(), 100n)).to.be.rejectedWith('common.UserIsNotAllowedToNest'); break;103 }104 });105});106107[108 {mode: 'nft' as const, nesting: {tokenOwner: true, collectionAdmin: false}},109 {mode: 'nft' as const, nesting: {tokenOwner: false, collectionAdmin: true}},110].map(testCase => {111 itSub(`${testCase.nesting.tokenOwner ? 'Admin' : 'Token owner'} cannot nest when only ${testCase.nesting.tokenOwner ? 'tokenOwner' : 'collectionAdmin'} is allowed`, async ({helper}) => {112 // Create collection with tokenOwner or create collection with collectionAdmin permission:113 const targetCollection = await helper.nft.mintCollection(alice, {permissions: {nesting: testCase.nesting}});114 const targetTokenAlice = await targetCollection.mintToken(alice);115 await targetCollection.addAdmin(alice, {Substrate: bob.address});116117 const nestedCollectionAlice = await helper[testCase.mode].mintCollection(alice);118 const nestedCollectionBob = await helper[testCase.mode].mintCollection(bob);119 // if nesting permissions restricted for token owner – minter is bob (admin),120 // if collectionAdmin – alice (owner)121122 // FIXME: nesting allowed only for admin but token owner can nest anyway:123 testCase.nesting.tokenOwner124 ? await expect(nestedCollectionBob.mintToken(bob, targetTokenAlice.nestingAccount())).to.be.rejectedWith(/common\.UserIsNotAllowedToNest/)125 : await expect(nestedCollectionAlice.mintToken(alice, targetTokenAlice.nestingAccount())).to.be.rejectedWith(/common\.UserIsNotAllowedToNest/);126 });127});6812869itSub.ifWithPallets('Cannot nest in non existing token', [Pallets.ReFungible], async ({helper}) => {129itSub.ifWithPallets('Cannot nest in non existing token', [Pallets.ReFungible], async ({helper}) => {70 const collection = await helper.nft.mintCollection(alice);130 const collection = await helper.nft.mintCollection(alice);104 }164 }105});165});106166107itEth.ifWithPallets('Cannot nest to collection address', [Pallets.ReFungible], async({helper}) => {167itEth.ifWithPallets('Cannot nest in collection address', [Pallets.ReFungible], async({helper}) => {108 const existingCollection = await helper.nft.mintCollection(alice);168 const existingCollection = await helper.nft.mintCollection(alice);109 const existingCollectionAddress = helper.ethAddress.fromCollectionId(existingCollection.collectionId);169 const existingCollectionAddress = helper.ethAddress.fromCollectionId(existingCollection.collectionId);110 const futureCollectionAddress = helper.ethAddress.fromCollectionId(99999999);170 const futureCollectionAddress = helper.ethAddress.fromCollectionId(99999999);141 await expect(ftCollection.transfer(alice, {Ethereum: helper.ethAddress.fromTokenId(ftCollection.collectionId, 0)})).to.be.rejectedWith('fungible.FungibleDisallowsNesting');201 await expect(ftCollection.transfer(alice, {Ethereum: helper.ethAddress.fromTokenId(ftCollection.collectionId, 0)})).to.be.rejectedWith('fungible.FungibleDisallowsNesting');142});202});203204itSub('Cannot nest in restricted collection if collection is not in the list', async ({helper}) => {205 const {collectionId: allowedCollectionId} = await helper.nft.mintCollection(alice);206 const notAllowedCollectionNFT = await helper.nft.mintCollection(alice);207 const notAllowedCollectionRFT = await helper.rft.mintCollection(alice);208 const notAllowedCollectionFT = await helper.ft.mintCollection(alice);209210 // Collection restricted to allowedCollectionId211 const restrictedCollectionA = await helper.nft.mintCollection(alice, {permissions:212 {nesting: {tokenOwner: true, restricted: [allowedCollectionId]}},213 });214 // Create collection with restricted nesting -- even self is not allowed215 const restrictedCollectionB = await helper.nft.mintCollection(alice, {permissions:216 {nesting: {tokenOwner: true, restricted: []}},217 });218219 const targetTokenA = await restrictedCollectionA.mintToken(alice);220 const targetTokenB = await restrictedCollectionB.mintToken(alice);221222 // 1. Cannot mint in own collection after allowlisting the accounts:223 await expect(restrictedCollectionA.mintToken(alice, targetTokenA.nestingAccount())).to.be.rejectedWith(/common\.SourceCollectionIsNotAllowedToNest/);224 await expect(restrictedCollectionB.mintToken(alice, targetTokenB.nestingAccount())).to.be.rejectedWith(/common\.SourceCollectionIsNotAllowedToNest/);225226 // 2. Cannot mint from notAllowedCollection:227 await expect(notAllowedCollectionNFT.mintToken(alice, targetTokenA.nestingAccount())).to.be.rejectedWith(/common\.SourceCollectionIsNotAllowedToNest/);228 await expect(notAllowedCollectionNFT.mintToken(alice, targetTokenB.nestingAccount())).to.be.rejectedWith(/common\.SourceCollectionIsNotAllowedToNest/);229 await expect(notAllowedCollectionRFT.mintToken(alice, 100n, targetTokenA.nestingAccount())).to.be.rejectedWith(/common\.SourceCollectionIsNotAllowedToNest/);230 await expect(notAllowedCollectionRFT.mintToken(alice, 100n, targetTokenB.nestingAccount())).to.be.rejectedWith(/common\.SourceCollectionIsNotAllowedToNest/);231 await expect(notAllowedCollectionFT.mint(alice, 100n, targetTokenA.nestingAccount())).to.be.rejectedWith(/common\.SourceCollectionIsNotAllowedToNest/);232 await expect(notAllowedCollectionFT.mint(alice, 100n, targetTokenB.nestingAccount())).to.be.rejectedWith(/common\.SourceCollectionIsNotAllowedToNest/);233});234235itSub('Cannot create nesting chains greater than 5', async ({helper}) => {236 const collection = await helper.nft.mintCollection(alice, {permissions: {nesting: {tokenOwner: true}}});237 let token = await collection.mintToken(alice);238239 const maxNestingLevel = 5;240241 // Create a nested-token matryoshka242 for (let i = 0; i < maxNestingLevel; i++) {243 token = await collection.mintToken(alice, token.nestingAccount());244 }245246 // The nesting depth is limited by `maxNestingLevel`247 // 1. Cannot mint:248 await expect(collection.mintToken(alice, token.nestingAccount()))249 .to.be.rejectedWith(/structure\.DepthLimit/);250 // 2. Cannot transfer:251 const anotherToken = await collection.mintToken(alice);252 await expect(anotherToken.transfer(alice, token.nestingAccount()))253 .to.be.rejectedWith(/structure\.DepthLimit/);254 // 3. Cannot nest FT pieces:255 const ftCollection = await helper.ft.mintCollection(alice);256 await expect(ftCollection.mint(alice, 100n, token.nestingAccount()))257 .to.be.rejectedWith(/structure\.DepthLimit/);258259 expect(await token.getTopmostOwner()).to.be.deep.equal({Substrate: alice.address});260 expect(await token.getChildren()).to.has.length(0);261});143262tests/src/sub/refungible/nesting.test.tsdiffbeforeafterboth116 });116 });117 });117 });118119 itSub('cannot nest token if nesting is disabled', async ({helper}) => {120 const collectionNFT = await helper.nft.mintCollection(alice);121 const collectionRFT = await helper.rft.mintCollection(alice);122 const targetToken = await collectionNFT.mintToken(alice);123124 // Try to create an immediately nested token125 await expect(collectionRFT.mintToken(alice, 5n, targetToken.nestingAccount()))126 .to.be.rejectedWith(/common\.UserIsNotAllowedToNest/);127128 // Try to create a token to be nested and nest129 const token = await collectionRFT.mintToken(alice, 5n);130 await expect(token.transfer(alice, targetToken.nestingAccount(), 2n))131 .to.be.rejectedWith(/common\.UserIsNotAllowedToNest/);132 expect(await token.getBalance({Substrate: alice.address})).to.be.equal(5n);133 });134118135 [119 [136 {restrictedMode: true},120 {restrictedMode: true},162 });146 });163 });147 });164165 itSub('ReFungible: disallows to nest token to an unlisted collection', async ({helper}) => {166 const collectionNFT = await helper.nft.mintCollection(alice, {permissions: {nesting: {tokenOwner: true, restricted: []}}});167 const collectionRFT = await helper.rft.mintCollection(alice);168 const targetToken = await collectionNFT.mintToken(alice);169170 // Try to create an immediately nested token171 await expect(collectionRFT.mintToken(alice, 5n, targetToken.nestingAccount()))172 .to.be.rejectedWith(/common\.SourceCollectionIsNotAllowedToNest/);173174 // Try to create a token to be nested and nest175 const token = await collectionRFT.mintToken(alice, 5n);176 await expect(token.transfer(alice, targetToken.nestingAccount(), 2n))177 .to.be.rejectedWith(/common\.SourceCollectionIsNotAllowedToNest/);178 expect(await token.getBalance({Substrate: alice.address})).to.be.equal(5n);179 });180});148});181149