difftreelog
test owner/admin unnest
in: master
2 files changed
tests/src/nesting/nest.test.tsdiffbeforeafterboth--- a/tests/src/nesting/nest.test.ts
+++ b/tests/src/nesting/nest.test.ts
@@ -16,7 +16,6 @@
import {IKeyringPair} from '@polkadot/types/types';
import {expect, itSub, Pallets, usingPlaygrounds} from '../util';
-import {UniqueNFToken, UniqueRFToken} from '../util/playgrounds/unique';
describe('Integration Test: Composite nesting tests', () => {
let alice: IKeyringPair;
@@ -139,7 +138,7 @@
before(async () => {
await usingPlaygrounds(async (helper, privateKey) => {
const donor = await privateKey({filename: __filename});
- [alice, bob, charlie] = await helper.arrange.createAccounts([100n, 20n, 20n], donor);
+ [alice, bob, charlie] = await helper.arrange.createAccounts([50n, 10n, 10n], donor);
});
});
@@ -335,205 +334,6 @@
const newToken = await collectionRFT.mintToken(charlie, 5n);
await newToken.transfer(charlie, targetToken.nestingAccount(), 2n);
expect(await newToken.getBalance(targetToken.nestingAccount())).to.be.equal(2n);
- });
-
- async function checkNestedRft({
- expectedBalance,
- childrenShouldPresent,
- nestedRft,
- targetNft,
- }: {
- expectedBalance: bigint,
- childrenShouldPresent: boolean,
- nestedRft: UniqueRFToken,
- targetNft: UniqueNFToken,
- }) {
- const balance = await nestedRft.getBalance(targetNft.nestingAccount());
- expect(balance).to.be.equal(expectedBalance);
-
- const children = await targetNft.getChildren();
-
- if (childrenShouldPresent) {
- expect(children[0]).to.be.deep.equal({
- collectionId: nestedRft.collectionId,
- tokenId: nestedRft.tokenId,
- });
- } else {
- expect(children.length).to.be.equal(0);
- }
- }
-
- itSub.ifWithPallets('ReFungible: allows a collection owner to transfer nested token', [Pallets.ReFungible], async ({helper}) => {
- const collectionNFT = await helper.nft.mintCollection(alice);
- const collectionRFT = await helper.rft.mintCollection(alice, {
- limits: {
- ownerCanTransfer: true,
- },
- });
-
- await collectionNFT.setPermissions(alice, {nesting: {tokenOwner: true}});
-
- const targetNft = await collectionNFT.mintToken(alice, {Substrate: charlie.address});
- const nestedRft = await collectionRFT.mintToken(alice, 5n, {Substrate: charlie.address});
-
- await nestedRft.transfer(charlie, targetNft.nestingAccount(), 5n);
- await checkNestedRft({
- expectedBalance: 5n,
- childrenShouldPresent: true,
- nestedRft,
- targetNft,
- });
-
- await nestedRft.transferFrom(alice, targetNft.nestingAccount(), {Substrate: bob.address}, 2n);
- await checkNestedRft({
- expectedBalance: 3n,
- childrenShouldPresent: true,
- nestedRft,
- targetNft,
- });
- expect(await nestedRft.getBalance({Substrate: bob.address})).to.be.equal(2n);
-
- await nestedRft.transferFrom(alice, targetNft.nestingAccount(), {Substrate: bob.address}, 3n);
- await checkNestedRft({
- expectedBalance: 0n,
- childrenShouldPresent: false,
- nestedRft,
- targetNft,
- });
- expect(await nestedRft.getBalance({Substrate: bob.address})).to.be.equal(5n);
- });
-
- itSub.ifWithPallets('ReFungible: allows a collection admin to transfer nested token', [Pallets.ReFungible], async ({helper}) => {
- const collectionNFT = await helper.nft.mintCollection(alice);
- const collectionRFT = await helper.rft.mintCollection(alice, {
- limits: {
- ownerCanTransfer: true,
- },
- });
- await collectionRFT.addAdmin(alice, {Substrate: bob.address});
-
- await collectionNFT.setPermissions(alice, {nesting: {tokenOwner: true}});
-
- const targetNft = await collectionNFT.mintToken(alice, {Substrate: charlie.address});
- const nestedRft = await collectionRFT.mintToken(alice, 5n, {Substrate: charlie.address});
-
- await nestedRft.transfer(charlie, targetNft.nestingAccount(), 5n);
- await checkNestedRft({
- expectedBalance: 5n,
- childrenShouldPresent: true,
- nestedRft,
- targetNft,
- });
-
- await nestedRft.transferFrom(bob, targetNft.nestingAccount(), {Substrate: bob.address}, 2n);
- await checkNestedRft({
- expectedBalance: 3n,
- childrenShouldPresent: true,
- nestedRft,
- targetNft,
- });
- expect(await nestedRft.getBalance({Substrate: bob.address})).to.be.equal(2n);
-
- await nestedRft.transferFrom(bob, targetNft.nestingAccount(), {Substrate: bob.address}, 3n);
- await checkNestedRft({
- expectedBalance: 0n,
- childrenShouldPresent: false,
- nestedRft,
- targetNft,
- });
- expect(await nestedRft.getBalance({Substrate: bob.address})).to.be.equal(5n);
- });
-
- itSub.ifWithPallets('ReFungible: allows a collection owner to burn nested token', [Pallets.ReFungible], async ({helper}) => {
- const collectionNFT = await helper.nft.mintCollection(alice, {
- limits: {
- ownerCanTransfer: true,
- },
- });
- const collectionRFT = await helper.rft.mintCollection(alice, {
- limits: {
- ownerCanTransfer: true,
- },
- });
-
- await collectionNFT.setPermissions(alice, {nesting: {tokenOwner: true}});
-
- const targetNft = await collectionNFT.mintToken(alice, {Substrate: charlie.address});
- const nestedRft = await collectionRFT.mintToken(alice, 5n, {Substrate: charlie.address});
-
- await nestedRft.transfer(charlie, targetNft.nestingAccount(), 5n);
- await checkNestedRft({
- expectedBalance: 5n,
- childrenShouldPresent: true,
- nestedRft,
- targetNft,
- });
-
- await nestedRft.burnFrom(alice, targetNft.nestingAccount(), 2n);
- await checkNestedRft({
- expectedBalance: 3n,
- childrenShouldPresent: true,
- nestedRft,
- targetNft,
- });
-
- await nestedRft.burnFrom(alice, targetNft.nestingAccount(), 3n);
- await checkNestedRft({
- expectedBalance: 0n,
- childrenShouldPresent: false,
- nestedRft,
- targetNft,
- });
-
- // Check if we can burn target NFT when all nested RFTs are gone
- await targetNft.burnFrom(alice, {Substrate: charlie.address});
- });
-
- itSub.ifWithPallets('ReFungible: allows a collection admin to burn nested token', [Pallets.ReFungible], async ({helper}) => {
- const collectionNFT = await helper.nft.mintCollection(alice, {
- limits: {
- ownerCanTransfer: true,
- },
- });
- const collectionRFT = await helper.rft.mintCollection(alice, {
- limits: {
- ownerCanTransfer: true,
- },
- });
- await collectionNFT.addAdmin(alice, {Substrate: bob.address});
- await collectionRFT.addAdmin(alice, {Substrate: bob.address});
-
- await collectionNFT.setPermissions(alice, {nesting: {tokenOwner: true}});
-
- const targetNft = await collectionNFT.mintToken(alice, {Substrate: charlie.address});
- const nestedRft = await collectionRFT.mintToken(alice, 5n, {Substrate: charlie.address});
-
- await nestedRft.transfer(charlie, targetNft.nestingAccount(), 5n);
- await checkNestedRft({
- expectedBalance: 5n,
- childrenShouldPresent: true,
- nestedRft,
- targetNft,
- });
-
- await nestedRft.burnFrom(bob, targetNft.nestingAccount(), 2n);
- await checkNestedRft({
- expectedBalance: 3n,
- childrenShouldPresent: true,
- nestedRft,
- targetNft,
- });
-
- await nestedRft.burnFrom(bob, targetNft.nestingAccount(), 3n);
- await checkNestedRft({
- expectedBalance: 0n,
- childrenShouldPresent: false,
- nestedRft,
- targetNft,
- });
-
- // Check if we can burn target NFT when all nested RFTs are gone
- await targetNft.burnFrom(bob, {Substrate: charlie.address});
});
});
tests/src/nesting/unnest.test.tsdiffbeforeafterboth1// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.2// This file is part of Unique Network.34// Unique Network is free software: you can redistribute it and/or modify5// it under the terms of the GNU General Public License as published by6// the Free Software Foundation, either version 3 of the License, or7// (at your option) any later version.89// Unique Network is distributed in the hope that it will be useful,10// but WITHOUT ANY WARRANTY; without even the implied warranty of11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the12// GNU General Public License for more details.1314// You should have received a copy of the GNU General Public License15// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.1617import {IKeyringPair} from '@polkadot/types/types';18import {expect, itSub, Pallets, usingPlaygrounds} from '../util';1920describe('Integration Test: Unnesting', () => {21 let alice: IKeyringPair;2223 before(async () => {24 await usingPlaygrounds(async (helper, privateKey) => {25 const donor = await privateKey({filename: __filename});26 [alice] = await helper.arrange.createAccounts([50n], donor);27 });28 });2930 itSub('NFT: allows the owner to successfully unnest a token', async ({helper}) => {31 const collection = await helper.nft.mintCollection(alice, {permissions: {nesting: {tokenOwner: true}}});32 const targetToken = await collection.mintToken(alice);3334 // Create a nested token35 const nestedToken = await collection.mintToken(alice, targetToken.nestingAccount());3637 // Unnest38 await expect(nestedToken.transferFrom(alice, targetToken.nestingAccount(), {Substrate: alice.address}), 'while unnesting').to.be.fulfilled;39 expect(await nestedToken.getOwner()).to.be.deep.equal({Substrate: alice.address});4041 // Nest and burn42 await nestedToken.nest(alice, targetToken);43 await expect(nestedToken.burnFrom(alice, targetToken.nestingAccount()), 'while burning').to.be.fulfilled;44 await expect(nestedToken.getOwner()).to.be.rejected;45 });4647 itSub('Fungible: allows the owner to successfully unnest a token', async ({helper}) => {48 const collection = await helper.nft.mintCollection(alice, {permissions: {nesting: {tokenOwner: true}}});49 const targetToken = await collection.mintToken(alice);5051 const collectionFT = await helper.ft.mintCollection(alice);5253 // Nest and unnest54 await collectionFT.mint(alice, 10n, targetToken.nestingAccount());55 await expect(collectionFT.transferFrom(alice, targetToken.nestingAccount(), {Substrate: alice.address}, 9n), 'while unnesting').to.be.fulfilled;56 expect(await collectionFT.getBalance({Substrate: alice.address})).to.be.equal(9n);57 expect(await collectionFT.getBalance(targetToken.nestingAccount())).to.be.equal(1n);5859 // Nest and burn60 await collectionFT.transfer(alice, targetToken.nestingAccount(), 5n);61 await expect(collectionFT.burnTokensFrom(alice, targetToken.nestingAccount(), 6n), 'while burning').to.be.fulfilled;62 expect(await collectionFT.getBalance({Substrate: alice.address})).to.be.equal(4n);63 expect(await collectionFT.getBalance(targetToken.nestingAccount())).to.be.equal(0n);64 expect(await targetToken.getChildren()).to.be.length(0);65 });6667 itSub.ifWithPallets('ReFungible: allows the owner to successfully unnest a token', [Pallets.ReFungible], async ({helper}) => {68 const collection = await helper.nft.mintCollection(alice, {permissions: {nesting: {tokenOwner: true}}});69 const targetToken = await collection.mintToken(alice);7071 const collectionRFT = await helper.rft.mintCollection(alice);7273 // Nest and unnest74 const token = await collectionRFT.mintToken(alice, 10n, targetToken.nestingAccount());75 await expect(token.transferFrom(alice, targetToken.nestingAccount(), {Substrate: alice.address}, 9n), 'while unnesting').to.be.fulfilled;76 expect(await token.getBalance({Substrate: alice.address})).to.be.equal(9n);77 expect(await token.getBalance(targetToken.nestingAccount())).to.be.equal(1n);7879 // Nest and burn80 await token.transfer(alice, targetToken.nestingAccount(), 5n);81 await expect(token.burnFrom(alice, targetToken.nestingAccount(), 6n), 'while burning').to.be.fulfilled;82 expect(await token.getBalance({Substrate: alice.address})).to.be.equal(4n);83 expect(await token.getBalance(targetToken.nestingAccount())).to.be.equal(0n);84 expect(await targetToken.getChildren()).to.be.length(0);85 });86});8788describe('Negative Test: Unnesting', () => {89 let alice: IKeyringPair;90 let bob: IKeyringPair;9192 before(async () => {93 await usingPlaygrounds(async (helper, privateKey) => {94 const donor = await privateKey({filename: __filename});95 [alice, bob] = await helper.arrange.createAccounts([50n, 10n], donor);96 });97 });9899 itSub('Disallows a non-owner to unnest/burn a token', async ({helper}) => {100 const collection = await helper.nft.mintCollection(alice, {permissions: {nesting: {tokenOwner: true}}});101 const targetToken = await collection.mintToken(alice);102103 // Create a nested token104 const nestedToken = await collection.mintToken(alice, targetToken.nestingAccount());105106 // Try to unnest107 await expect(nestedToken.unnest(bob, targetToken, {Substrate: alice.address})).to.be.rejectedWith(/common\.ApprovedValueTooLow/);108 expect(await nestedToken.getOwner()).to.be.deep.equal(targetToken.nestingAccount().toLowerCase());109110 // Try to burn111 await expect(nestedToken.burnFrom(bob, targetToken.nestingAccount())).to.be.rejectedWith(/common\.ApprovedValueTooLow/);112 expect(await nestedToken.getOwner()).to.be.deep.equal(targetToken.nestingAccount().toLowerCase());113 });114115 // todo another test for creating excessive depth matryoshka with Ethereum?116117 // Recursive nesting118 itSub('Prevents Ouroboros creation', async ({helper}) => {119 const collection = await helper.nft.mintCollection(alice, {permissions: {nesting: {tokenOwner: true}}});120 const targetToken = await collection.mintToken(alice);121122 // Fail to create a nested token ouroboros123 const nestedToken = await collection.mintToken(alice, targetToken.nestingAccount());124 await expect(targetToken.nest(alice, nestedToken)).to.be.rejectedWith(/^structure\.OuroborosDetected$/);125 });126});1// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.2// This file is part of Unique Network.34// Unique Network is free software: you can redistribute it and/or modify5// it under the terms of the GNU General Public License as published by6// the Free Software Foundation, either version 3 of the License, or7// (at your option) any later version.89// Unique Network is distributed in the hope that it will be useful,10// but WITHOUT ANY WARRANTY; without even the implied warranty of11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the12// GNU General Public License for more details.1314// You should have received a copy of the GNU General Public License15// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.1617import {IKeyringPair} from '@polkadot/types/types';18import {expect, itSub, Pallets, usingPlaygrounds} from '../util';19import {UniqueFTCollection, UniqueNFToken, UniqueRFToken} from '../util/playgrounds/unique';2021describe('Integration Test: Unnesting', () => {22 let alice: IKeyringPair;23 let bob: IKeyringPair;24 let charlie: IKeyringPair;2526 before(async () => {27 await usingPlaygrounds(async (helper, privateKey) => {28 const donor = await privateKey({filename: __filename});29 [alice, bob, charlie] = await helper.arrange.createAccounts([200n, 50n, 50n], donor);30 });31 });3233 itSub('NFT: allows the owner to successfully unnest a token', async ({helper}) => {34 const collection = await helper.nft.mintCollection(alice, {permissions: {nesting: {tokenOwner: true}}});35 const targetToken = await collection.mintToken(alice);3637 // Create a nested token38 const nestedToken = await collection.mintToken(alice, targetToken.nestingAccount());3940 // Unnest41 await expect(nestedToken.transferFrom(alice, targetToken.nestingAccount(), {Substrate: alice.address}), 'while unnesting').to.be.fulfilled;42 expect(await nestedToken.getOwner()).to.be.deep.equal({Substrate: alice.address});4344 // Nest and burn45 await nestedToken.nest(alice, targetToken);46 await expect(nestedToken.burnFrom(alice, targetToken.nestingAccount()), 'while burning').to.be.fulfilled;47 await expect(nestedToken.getOwner()).to.be.rejected;48 });4950 itSub('Fungible: allows the owner to successfully unnest a token', async ({helper}) => {51 const collection = await helper.nft.mintCollection(alice, {permissions: {nesting: {tokenOwner: true}}});52 const targetToken = await collection.mintToken(alice);5354 const collectionFT = await helper.ft.mintCollection(alice);5556 // Nest and unnest57 await collectionFT.mint(alice, 10n, targetToken.nestingAccount());58 await expect(collectionFT.transferFrom(alice, targetToken.nestingAccount(), {Substrate: alice.address}, 9n), 'while unnesting').to.be.fulfilled;59 expect(await collectionFT.getBalance({Substrate: alice.address})).to.be.equal(9n);60 expect(await collectionFT.getBalance(targetToken.nestingAccount())).to.be.equal(1n);6162 // Nest and burn63 await collectionFT.transfer(alice, targetToken.nestingAccount(), 5n);64 await expect(collectionFT.burnTokensFrom(alice, targetToken.nestingAccount(), 6n), 'while burning').to.be.fulfilled;65 expect(await collectionFT.getBalance({Substrate: alice.address})).to.be.equal(4n);66 expect(await collectionFT.getBalance(targetToken.nestingAccount())).to.be.equal(0n);67 expect(await targetToken.getChildren()).to.be.length(0);68 });6970 itSub.ifWithPallets('ReFungible: allows the owner to successfully unnest a token', [Pallets.ReFungible], async ({helper}) => {71 const collection = await helper.nft.mintCollection(alice, {permissions: {nesting: {tokenOwner: true}}});72 const targetToken = await collection.mintToken(alice);7374 const collectionRFT = await helper.rft.mintCollection(alice);7576 // Nest and unnest77 const token = await collectionRFT.mintToken(alice, 10n, targetToken.nestingAccount());78 await expect(token.transferFrom(alice, targetToken.nestingAccount(), {Substrate: alice.address}, 9n), 'while unnesting').to.be.fulfilled;79 expect(await token.getBalance({Substrate: alice.address})).to.be.equal(9n);80 expect(await token.getBalance(targetToken.nestingAccount())).to.be.equal(1n);8182 // Nest and burn83 await token.transfer(alice, targetToken.nestingAccount(), 5n);84 await expect(token.burnFrom(alice, targetToken.nestingAccount(), 6n), 'while burning').to.be.fulfilled;85 expect(await token.getBalance({Substrate: alice.address})).to.be.equal(4n);86 expect(await token.getBalance(targetToken.nestingAccount())).to.be.equal(0n);87 expect(await targetToken.getChildren()).to.be.length(0);88 });8990 async function checkNestedAmountState({91 expectedBalance,92 childrenShouldPresent,93 nested,94 targetNft,95 }: {96 expectedBalance: bigint,97 childrenShouldPresent: boolean,98 nested: UniqueFTCollection | UniqueRFToken,99 targetNft: UniqueNFToken,100 }) {101 const balance = await nested.getBalance(targetNft.nestingAccount());102 expect(balance).to.be.equal(expectedBalance);103104 const children = await targetNft.getChildren();105106 if (childrenShouldPresent) {107 expect(children[0]).to.be.deep.equal({108 collectionId: nested.collectionId,109 tokenId: (nested instanceof UniqueFTCollection) ? 0 : nested.tokenId,110 });111 } else {112 expect(children.length).to.be.equal(0);113 }114 }115116 function ownerOrAdminUnnestCases(modes: ('ft' | 'nft' | 'rft')[]): {117 mode: 'ft' | 'nft' | 'rft',118 sender: string,119 op: 'transfer' | 'burn',120 requiredPallets: Pallets[],121 }[] {122 const senders = ['owner', 'admin'];123 const ops = ['transfer', 'burn'];124125 const cases = [];126 for (const mode of modes) {127 const requiredPallets = (mode === 'rft')128 ? [Pallets.ReFungible]129 : [];130131 for (const sender of senders) {132 for (const op of ops) {133 cases.push({134 mode: mode as 'ft' | 'nft' | 'rft',135 sender,136 op: op as 'transfer' | 'burn',137 requiredPallets,138 });139 }140 }141 }142143 return cases;144 }145146 ownerOrAdminUnnestCases(['ft', 'rft']).map(testCase =>147 itSub.ifWithPallets(`[${testCase.mode}]: allows a collection ${testCase.sender} to ${testCase.op} nested token`, testCase.requiredPallets, async({helper}) => {148 const owner = alice;149 const admin = bob;150151 const unnester = (testCase.sender === 'owner')152 ? owner153 : admin;154155 const collectionNFT = await helper.nft.mintCollection(owner);156 await collectionNFT.setPermissions(owner, {nesting: {tokenOwner: true}});157158 const collectionNested = await helper[testCase.mode as 'ft' | 'rft'].mintCollection(owner, {159 limits: {160 ownerCanTransfer: true,161 },162 });163 await collectionNested.addAdmin(owner, {Substrate: admin.address});164165 const targetNft = await collectionNFT.mintToken(owner, {Substrate: charlie.address});166167 let nested: UniqueFTCollection | UniqueRFToken;168 const totalAmount = 5n;169 const firstUnnestAmount = 2n;170 const restUnnestAmount = totalAmount - firstUnnestAmount;171172 if (collectionNested instanceof UniqueFTCollection) {173 await collectionNested.mint(owner, totalAmount, {Substrate: charlie.address});174 nested = collectionNested;175 } else {176 nested = await collectionNested.mintToken(owner, totalAmount, {Substrate: charlie.address});177 }178179 // transfer/burn `amount` of nested assets by `unnester`.180 const doOperationAndCheck = async ({181 amount,182 shouldBeNestedAfterOp,183 }: {184 amount: bigint,185 shouldBeNestedAfterOp: boolean,186 }) => {187 const nestedBalanceBeforeOp = await nested.getBalance(targetNft.nestingAccount());188189 if (testCase.op === 'transfer') {190 const bobBalanceBeforeOp = await nested.getBalance({Substrate: bob.address});191192 await nested.transferFrom(unnester, targetNft.nestingAccount(), {Substrate: bob.address}, amount);193 expect(await nested.getBalance({Substrate: bob.address})).to.be.equal(bobBalanceBeforeOp + amount);194 } else {195 if (nested instanceof UniqueFTCollection) {196 await nested.burnTokensFrom(unnester, targetNft.nestingAccount(), amount);197 } else {198 await nested.burnFrom(unnester, targetNft.nestingAccount(), amount);199 }200 }201202 await checkNestedAmountState({203 expectedBalance: nestedBalanceBeforeOp - amount,204 childrenShouldPresent: shouldBeNestedAfterOp,205 nested,206 targetNft,207 });208 };209210 // Initial setup: nest (fungibles/rft parts).211 // Check NFT's balance of nested assets and NFT's children.212 await nested.transfer(charlie, targetNft.nestingAccount(), totalAmount);213 await checkNestedAmountState({214 expectedBalance: totalAmount,215 childrenShouldPresent: true,216 nested,217 targetNft,218 });219220 // Transfer/burn only a part of nested assets.221 // Check that NFT's balance of the nested assets correctly decreased and NFT's children are not changed.222 await doOperationAndCheck({223 amount: firstUnnestAmount,224 shouldBeNestedAfterOp: true,225 });226227 // Transfer/burn all remaining nested assets.228 // Check that NFT's balance of the nested assets is 0 and NFT has no more children.229 await doOperationAndCheck({230 amount: restUnnestAmount,231 shouldBeNestedAfterOp: false,232 });233 }));234235 ownerOrAdminUnnestCases(['nft']).map(testCase =>236 itSub(`[nft]: allows a collection ${testCase.sender} to ${testCase.op} nested token`, async ({helper}) => {237 const owner = alice;238 const admin = bob;239240 const unnester = (testCase.sender === 'owner')241 ? owner242 : admin;243244 const collectionNFT = await helper.nft.mintCollection(owner);245 await collectionNFT.setPermissions(owner, {nesting: {tokenOwner: true}});246247 const collectionNested = await helper.nft.mintCollection(owner, {248 limits: {249 ownerCanTransfer: true,250 },251 });252 await collectionNested.addAdmin(owner, {Substrate: admin.address});253254 const targetNft = await collectionNFT.mintToken(owner, {Substrate: charlie.address});255 const nested = await collectionNested.mintToken(owner, {Substrate: charlie.address});256257 await nested.transfer(charlie, targetNft.nestingAccount());258 expect(await targetNft.getChildren()).to.be.deep.equal([{259 collectionId: nested.collectionId,260 tokenId: nested.tokenId,261 }]);262263 if (testCase.op === 'transfer') {264 await nested.transferFrom(unnester, targetNft.nestingAccount(), {Substrate: bob.address});265 } else {266 await nested.burnFrom(unnester, targetNft.nestingAccount());267 }268269 expect((await targetNft.getChildren()).length).to.be.equal(0);270 }));271});272273describe('Negative Test: Unnesting', () => {274 let alice: IKeyringPair;275 let bob: IKeyringPair;276277 before(async () => {278 await usingPlaygrounds(async (helper, privateKey) => {279 const donor = await privateKey({filename: __filename});280 [alice, bob] = await helper.arrange.createAccounts([50n, 10n], donor);281 });282 });283284 itSub('Disallows a non-owner to unnest/burn a token', async ({helper}) => {285 const collection = await helper.nft.mintCollection(alice, {permissions: {nesting: {tokenOwner: true}}});286 const targetToken = await collection.mintToken(alice);287288 // Create a nested token289 const nestedToken = await collection.mintToken(alice, targetToken.nestingAccount());290291 // Try to unnest292 await expect(nestedToken.unnest(bob, targetToken, {Substrate: alice.address})).to.be.rejectedWith(/common\.ApprovedValueTooLow/);293 expect(await nestedToken.getOwner()).to.be.deep.equal(targetToken.nestingAccount().toLowerCase());294295 // Try to burn296 await expect(nestedToken.burnFrom(bob, targetToken.nestingAccount())).to.be.rejectedWith(/common\.ApprovedValueTooLow/);297 expect(await nestedToken.getOwner()).to.be.deep.equal(targetToken.nestingAccount().toLowerCase());298 });299300 // todo another test for creating excessive depth matryoshka with Ethereum?301302 // Recursive nesting303 itSub('Prevents Ouroboros creation', async ({helper}) => {304 const collection = await helper.nft.mintCollection(alice, {permissions: {nesting: {tokenOwner: true}}});305 const targetToken = await collection.mintToken(alice);306307 // Fail to create a nested token ouroboros308 const nestedToken = await collection.mintToken(alice, targetToken.nestingAccount());309 await expect(targetToken.nest(alice, nestedToken)).to.be.rejectedWith(/^structure\.OuroborosDetected$/);310 });311});