git.delta.rocks / unique-network / refs/commits / 6069e8a874a9

difftreelog

source

tests/src/nesting/nest.test.ts45.0 KiBsourcehistory
1import {expect} from 'chai';2import {tokenIdToAddress} from '../eth/util/helpers';3import usingApi, {executeTransaction} from '../substrate/substrate-api';4import {5  addCollectionAdminExpectSuccess,6  addToAllowListExpectSuccess,7  createCollectionExpectSuccess,8  createItemExpectSuccess,9  enableAllowListExpectSuccess,10  enablePublicMintingExpectSuccess,11  getTokenChildren,12  getTokenOwner,13  getTopmostTokenOwner,14  normalizeAccountId,15  setCollectionPermissionsExpectSuccess,16  transferExpectFailure,17  transferExpectSuccess,18  transferFromExpectSuccess,19  setCollectionLimitsExpectSuccess,20  requirePallets,21  Pallets,22} from '../util/helpers';23import {IKeyringPair} from '@polkadot/types/types';2425let alice: IKeyringPair;26let bob: IKeyringPair;27let charlie: IKeyringPair;2829describe('Integration Test: Composite nesting tests', () => {30  before(async () => {31    await usingApi(async (_, privateKeyWrapper) => {32      alice = privateKeyWrapper('//Alice');33      bob = privateKeyWrapper('//Bob');34    });35  });3637  it('Performs the full suite: bundles a token, transfers, and unnests', async () => {38    await usingApi(async api => {39      const collection = await createCollectionExpectSuccess({mode: {type: 'NFT'}});40      await setCollectionPermissionsExpectSuccess(alice, collection, {nesting: {tokenOwner: true}});41      const targetToken = await createItemExpectSuccess(alice, collection, 'NFT');4243      // Create a nested token44      const nestedToken = await createItemExpectSuccess(alice, collection, 'NFT', {Ethereum: tokenIdToAddress(collection, targetToken)});45      expect(await getTopmostTokenOwner(api, collection, nestedToken)).to.be.deep.equal({Substrate: alice.address});46      expect(await getTokenOwner(api, collection, nestedToken)).to.be.deep.equal({Ethereum: tokenIdToAddress(collection, targetToken).toLowerCase()});4748      // Create a token to be nested49      const newToken = await createItemExpectSuccess(alice, collection, 'NFT');5051      // Nest52      await transferExpectSuccess(collection, newToken, alice, {Ethereum: tokenIdToAddress(collection, targetToken)});53      expect(await getTopmostTokenOwner(api, collection, newToken)).to.be.deep.equal({Substrate: alice.address});54      expect(await getTokenOwner(api, collection, newToken)).to.be.deep.equal({Ethereum: tokenIdToAddress(collection, targetToken).toLowerCase()});5556      // Move bundle to different user57      await transferExpectSuccess(collection, targetToken, alice, {Substrate: bob.address});58      expect(await getTopmostTokenOwner(api, collection, nestedToken)).to.be.deep.equal({Substrate: bob.address});59      expect(await getTokenOwner(api, collection, nestedToken)).to.be.deep.equal({Ethereum: tokenIdToAddress(collection, targetToken).toLowerCase()});6061      // Unnest62      await transferFromExpectSuccess(collection, newToken, bob, {Ethereum: tokenIdToAddress(collection, targetToken)}, {Substrate: bob.address});63      expect(await getTokenOwner(api, collection, newToken)).to.be.deep.equal({Substrate: bob.address});64    });65  });6667  it('Transfers an already bundled token', async () => {68    await usingApi(async api => {69      const collection = await createCollectionExpectSuccess({mode: {type: 'NFT'}});70      await setCollectionPermissionsExpectSuccess(alice, collection, {nesting: {tokenOwner: true}});7172      const tokenA = await createItemExpectSuccess(alice, collection, 'NFT');73      const tokenB = await createItemExpectSuccess(alice, collection, 'NFT');7475      // Create a nested token76      const tokenC = await createItemExpectSuccess(alice, collection, 'NFT', {Ethereum: tokenIdToAddress(collection, tokenA)});77      expect(await getTopmostTokenOwner(api, collection, tokenC)).to.be.deep.equal({Substrate: alice.address});78      expect(await getTokenOwner(api, collection, tokenC)).to.be.deep.equal({Ethereum: tokenIdToAddress(collection, tokenA).toLowerCase()});7980      // Transfer the nested token to another token81      await expect(executeTransaction(82        api,83        alice,84        api.tx.unique.transferFrom(85          normalizeAccountId({Ethereum: tokenIdToAddress(collection, tokenA)}),86          normalizeAccountId({Ethereum: tokenIdToAddress(collection, tokenB)}),87          collection,88          tokenC,89          1,90        ),91      )).to.not.be.rejected;92      expect(await getTopmostTokenOwner(api, collection, tokenC)).to.be.deep.equal({Substrate: alice.address});93      expect(await getTokenOwner(api, collection, tokenC)).to.be.deep.equal({Ethereum: tokenIdToAddress(collection, tokenB).toLowerCase()});94    });95  });9697  it('Checks token children', async () => {98    await usingApi(async api => {99      const collectionA = await createCollectionExpectSuccess({mode: {type: 'NFT'}});100      await setCollectionLimitsExpectSuccess(alice, collectionA, {ownerCanTransfer: true});101      await setCollectionPermissionsExpectSuccess(alice, collectionA, {nesting: {tokenOwner: true}});102      const collectionB = await createCollectionExpectSuccess({mode: {type: 'Fungible', decimalPoints: 0}});103104      const targetToken = await createItemExpectSuccess(alice, collectionA, 'NFT');105      const targetAddress = {Ethereum: tokenIdToAddress(collectionA, targetToken)};106      let children = await getTokenChildren(api, collectionA, targetToken);107      expect(children.length).to.be.equal(0, 'Children length check at creation');108109      // Create a nested NFT token110      const tokenA = await createItemExpectSuccess(alice, collectionA, 'NFT', targetAddress);111      children = await getTokenChildren(api, collectionA, targetToken);112      expect(children.length).to.be.equal(1, 'Children length check at nesting #1');113      expect(children).to.have.deep.members([114        {token: tokenA, collection: collectionA},115      ], 'Children contents check at nesting #1');116117      // Create then nest118      const tokenB = await createItemExpectSuccess(alice, collectionA, 'NFT');119      await transferExpectSuccess(collectionA, tokenB, alice, targetAddress);120      children = await getTokenChildren(api, collectionA, targetToken);121      expect(children.length).to.be.equal(2, 'Children length check at nesting #2');122      expect(children).to.have.deep.members([123        {token: tokenA, collection: collectionA},124        {token: tokenB, collection: collectionA},125      ], 'Children contents check at nesting #2');126127      // Move token B to a different user outside the nesting tree128      await transferFromExpectSuccess(collectionA, tokenB, alice, targetAddress, bob);129      children = await getTokenChildren(api, collectionA, targetToken);130      expect(children.length).to.be.equal(1, 'Children length check at unnesting');131      expect(children).to.be.have.deep.members([132        {token: tokenA, collection: collectionA},133      ], 'Children contents check at unnesting');134135      // Create a fungible token in another collection and then nest136      const tokenC = await createItemExpectSuccess(alice, collectionB, 'Fungible');137      await transferExpectSuccess(collectionB, tokenC, alice, targetAddress, 1, 'Fungible');138      children = await getTokenChildren(api, collectionA, targetToken);139      expect(children.length).to.be.equal(2, 'Children length check at nesting #3 (from another collection)');140      expect(children).to.be.have.deep.members([141        {token: tokenA, collection: collectionA},142        {token: tokenC, collection: collectionB},143      ], 'Children contents check at nesting #3 (from another collection)');144145      // Move the fungible token inside token A deeper in the nesting tree146      await transferFromExpectSuccess(collectionB, tokenC, alice, targetAddress, {Ethereum: tokenIdToAddress(collectionA, tokenA)}, 1, 'Fungible');147      children = await getTokenChildren(api, collectionA, targetToken);148      expect(children.length).to.be.equal(1, 'Children length check at deeper nesting');149      expect(children).to.be.have.deep.members([150        {token: tokenA, collection: collectionA},151      ], 'Children contents check at deeper nesting');152    });153  });154});155156describe('Integration Test: Various token type nesting', async () => {157  before(async () => {158    await usingApi(async (_, privateKeyWrapper) => {159      alice = privateKeyWrapper('//Alice');160      bob = privateKeyWrapper('//Bob');161      charlie = privateKeyWrapper('//Charlie');162    });163  });164165  it('Admin (NFT): allows an Admin to nest a token', async () => {166    await usingApi(async api => {167      const collection = await createCollectionExpectSuccess({mode: {type: 'NFT'}});168      await setCollectionPermissionsExpectSuccess(alice, collection, {nesting: {collectionAdmin: true}});169      await addCollectionAdminExpectSuccess(alice, collection, bob.address);170      const targetToken = await createItemExpectSuccess(alice, collection, 'NFT', charlie.address);171172      // Create a nested token173      const nestedToken = await createItemExpectSuccess(bob, collection, 'NFT', {Ethereum: tokenIdToAddress(collection, targetToken)});174      expect(await getTopmostTokenOwner(api, collection, nestedToken)).to.be.deep.equal({Substrate: charlie.address});175      expect(await getTokenOwner(api, collection, nestedToken)).to.be.deep.equal({Ethereum: tokenIdToAddress(collection, targetToken).toLowerCase()});176177      // Create a token to be nested and nest178      const newToken = await createItemExpectSuccess(bob, collection, 'NFT');179      await transferExpectSuccess(collection, newToken, bob, {Ethereum: tokenIdToAddress(collection, targetToken)});180      expect(await getTopmostTokenOwner(api, collection, newToken)).to.be.deep.equal({Substrate: charlie.address});181      expect(await getTokenOwner(api, collection, newToken)).to.be.deep.equal({Ethereum: tokenIdToAddress(collection, targetToken).toLowerCase()});182    });183  });184185  it('Admin (NFT): Admin and Token Owner can operate together', async () => {186    await usingApi(async api => {187      const collection = await createCollectionExpectSuccess({mode: {type: 'NFT'}});188      await setCollectionPermissionsExpectSuccess(alice, collection, {nesting: {tokenOwner: true, collectionAdmin: true}});189      await addCollectionAdminExpectSuccess(alice, collection, bob.address);190      const targetToken = await createItemExpectSuccess(alice, collection, 'NFT', charlie.address);191192      // Create a nested token by an administrator193      const nestedToken = await createItemExpectSuccess(bob, collection, 'NFT', {Ethereum: tokenIdToAddress(collection, targetToken)});194      expect(await getTopmostTokenOwner(api, collection, nestedToken)).to.be.deep.equal({Substrate: charlie.address});195      expect(await getTokenOwner(api, collection, nestedToken)).to.be.deep.equal({Ethereum: tokenIdToAddress(collection, targetToken).toLowerCase()});196197      // Create a token and allow the owner to nest too198      const newToken = await createItemExpectSuccess(alice, collection, 'NFT', charlie.address);199      await transferExpectSuccess(collection, newToken, charlie, {Ethereum: tokenIdToAddress(collection, nestedToken)});200      expect(await getTopmostTokenOwner(api, collection, newToken)).to.be.deep.equal({Substrate: charlie.address});201      expect(await getTokenOwner(api, collection, newToken)).to.be.deep.equal({Ethereum: tokenIdToAddress(collection, nestedToken).toLowerCase()});202    });203  });204205  it('Admin (NFT): allows an Admin to nest a token (Restricted nesting)', async () => {206    await usingApi(async api => {207      const collectionA = await createCollectionExpectSuccess({mode: {type: 'NFT'}});208      await addCollectionAdminExpectSuccess(alice, collectionA, bob.address);209      const collectionB = await createCollectionExpectSuccess({mode: {type: 'NFT'}});210      await addCollectionAdminExpectSuccess(alice, collectionB, bob.address);211      await setCollectionPermissionsExpectSuccess(alice, collectionA, {nesting: {collectionAdmin: true, restricted:[collectionA, collectionB]}});212      const targetToken = await createItemExpectSuccess(alice, collectionA, 'NFT', charlie.address);213214      // Create a nested token215      const nestedToken = await createItemExpectSuccess(bob, collectionB, 'NFT', {Ethereum: tokenIdToAddress(collectionA, targetToken)});216      expect(await getTopmostTokenOwner(api, collectionB, nestedToken)).to.be.deep.equal({Substrate: charlie.address});217      expect(await getTokenOwner(api, collectionB, nestedToken)).to.be.deep.equal({Ethereum: tokenIdToAddress(collectionA, targetToken).toLowerCase()});218219      // Create a token to be nested and nest220      const newToken = await createItemExpectSuccess(bob, collectionB, 'NFT');221      await transferExpectSuccess(collectionB, newToken, bob, {Ethereum: tokenIdToAddress(collectionA, targetToken)});222      expect(await getTopmostTokenOwner(api, collectionB, newToken)).to.be.deep.equal({Substrate: charlie.address});223      expect(await getTokenOwner(api, collectionB, newToken)).to.be.deep.equal({Ethereum: tokenIdToAddress(collectionA, targetToken).toLowerCase()});224    });225  });226227  // ---------- Non-Fungible ----------228229  it('NFT: allows an Owner to nest/unnest their token', async () => {230    await usingApi(async api => {231      const collection = await createCollectionExpectSuccess({mode: {type: 'NFT'}});232      await setCollectionPermissionsExpectSuccess(alice, collection, {nesting: {tokenOwner: true}});233      const targetToken = await createItemExpectSuccess(alice, collection, 'NFT');234235      // Create a nested token236      const nestedToken = await createItemExpectSuccess(alice, collection, 'NFT', {Ethereum: tokenIdToAddress(collection, targetToken)});237      expect(await getTopmostTokenOwner(api, collection, nestedToken)).to.be.deep.equal({Substrate: alice.address});238      expect(await getTokenOwner(api, collection, nestedToken)).to.be.deep.equal({Ethereum: tokenIdToAddress(collection, targetToken).toLowerCase()});239240      // Create a token to be nested and nest241      const newToken = await createItemExpectSuccess(alice, collection, 'NFT');242      await transferExpectSuccess(collection, newToken, alice, {Ethereum: tokenIdToAddress(collection, targetToken)});243      expect(await getTopmostTokenOwner(api, collection, newToken)).to.be.deep.equal({Substrate: alice.address});244      expect(await getTokenOwner(api, collection, newToken)).to.be.deep.equal({Ethereum: tokenIdToAddress(collection, targetToken).toLowerCase()});245    });246  });247248  it('NFT: allows an Owner to nest/unnest their token (Restricted nesting)', async () => {249    await usingApi(async api => {250      const collection = await createCollectionExpectSuccess({mode: {type: 'NFT'}});251      await setCollectionPermissionsExpectSuccess(alice, collection, {nesting: {tokenOwner: true, restricted:[collection]}});252      const targetToken = await createItemExpectSuccess(alice, collection, 'NFT');253254      // Create a nested token255      const nestedToken = await createItemExpectSuccess(alice, collection, 'NFT', {Ethereum: tokenIdToAddress(collection, targetToken)});256      expect(await getTopmostTokenOwner(api, collection, nestedToken)).to.be.deep.equal({Substrate: alice.address});257      expect(await getTokenOwner(api, collection, nestedToken)).to.be.deep.equal({Ethereum: tokenIdToAddress(collection, targetToken).toLowerCase()});258259      // Create a token to be nested and nest260      const newToken = await createItemExpectSuccess(alice, collection, 'NFT');261      await transferExpectSuccess(collection, newToken, alice, {Ethereum: tokenIdToAddress(collection, targetToken)});262      expect(await getTopmostTokenOwner(api, collection, newToken)).to.be.deep.equal({Substrate: alice.address});263      expect(await getTokenOwner(api, collection, newToken)).to.be.deep.equal({Ethereum: tokenIdToAddress(collection, targetToken).toLowerCase()});264    });265  });266267  // ---------- Fungible ----------268269  it('Fungible: allows an Owner to nest/unnest their token', async () => {270    await usingApi(async api => {271      const collectionNFT = await createCollectionExpectSuccess({mode: {type: 'NFT'}});272      await setCollectionPermissionsExpectSuccess(alice, collectionNFT, {nesting: {tokenOwner: true}});273      const targetToken = await createItemExpectSuccess(alice, collectionNFT, 'NFT', {Substrate: alice.address});274      const targetAddress = {Ethereum: tokenIdToAddress(collectionNFT, targetToken)};275276      const collectionFT = await createCollectionExpectSuccess({mode: {type: 'Fungible', decimalPoints: 0}});277278      // Create a nested token279      await expect(executeTransaction(api, alice, api.tx.unique.createItem(280        collectionFT,281        targetAddress,282        {Fungible: {Value: 10}},283      ))).to.not.be.rejected;284285      // Nest a new token286      const newToken = await createItemExpectSuccess(alice, collectionFT, 'Fungible');287      await transferExpectSuccess(collectionFT, newToken, alice, targetAddress, 1, 'Fungible');288    });289  });290291  it('Fungible: allows an Owner to nest/unnest their token (Restricted nesting)', async () => {292    await usingApi(async api => {293      const collectionNFT = await createCollectionExpectSuccess({mode: {type: 'NFT'}});294      const targetToken = await createItemExpectSuccess(alice, collectionNFT, 'NFT', {Substrate: alice.address});295      const targetAddress = {Ethereum: tokenIdToAddress(collectionNFT, targetToken)};296297      const collectionFT = await createCollectionExpectSuccess({mode: {type: 'Fungible', decimalPoints: 0}});298299      await setCollectionPermissionsExpectSuccess(alice, collectionNFT, {nesting: {tokenOwner: true, restricted: [collectionFT]}});300301      // Create a nested token302      await expect(executeTransaction(api, alice, api.tx.unique.createItem(303        collectionFT,304        targetAddress,305        {Fungible: {Value: 10}},306      ))).to.not.be.rejected;307308      // Nest a new token309      const newToken = await createItemExpectSuccess(alice, collectionFT, 'Fungible');310      await transferExpectSuccess(collectionFT, newToken, alice, targetAddress, 1, 'Fungible');311    });312  });313314  // ---------- Re-Fungible ----------315316  it('ReFungible: allows an Owner to nest/unnest their token', async function() {317    await requirePallets(this, [Pallets.ReFungible]);318319    await usingApi(async api => {320      const collectionNFT = await createCollectionExpectSuccess({mode: {type: 'NFT'}});321      await setCollectionPermissionsExpectSuccess(alice, collectionNFT, {nesting: {tokenOwner: true}});322      const targetToken = await createItemExpectSuccess(alice, collectionNFT, 'NFT', {Substrate: alice.address});323      const targetAddress = {Ethereum: tokenIdToAddress(collectionNFT, targetToken)};324325      const collectionRFT = await createCollectionExpectSuccess({mode: {type: 'ReFungible'}});326327      // Create a nested token328      await expect(executeTransaction(api, alice, api.tx.unique.createItem(329        collectionRFT,330        targetAddress,331        {ReFungible: {pieces: 100}},332      ))).to.not.be.rejected;333334      // Nest a new token335      const newToken = await createItemExpectSuccess(alice, collectionRFT, 'ReFungible');336      await transferExpectSuccess(collectionRFT, newToken, alice, targetAddress, 100, 'ReFungible');337    });338  });339340  it('ReFungible: allows an Owner to nest/unnest their token (Restricted nesting)', async function() {341    await requirePallets(this, [Pallets.ReFungible]);342343    await usingApi(async api => {344      const collectionNFT = await createCollectionExpectSuccess({mode: {type: 'NFT'}});345      const targetToken = await createItemExpectSuccess(alice, collectionNFT, 'NFT', {Substrate: alice.address});346      const targetAddress = {Ethereum: tokenIdToAddress(collectionNFT, targetToken)};347348      const collectionRFT = await createCollectionExpectSuccess({mode: {type: 'ReFungible'}});349350      await setCollectionPermissionsExpectSuccess(alice, collectionNFT, {nesting: {tokenOwner: true, restricted:[collectionRFT]}});351352      // Create a nested token353      await expect(executeTransaction(api, alice, api.tx.unique.createItem(354        collectionRFT,355        targetAddress,356        {ReFungible: {pieces: 100}},357      ))).to.not.be.rejected;358359      // Nest a new token360      const newToken = await createItemExpectSuccess(alice, collectionRFT, 'ReFungible');361      await transferExpectSuccess(collectionRFT, newToken, alice, targetAddress, 100, 'ReFungible');362    });363  });364});365366describe('Negative Test: Nesting', async() => {367  before(async () => {368    await usingApi(async (_, privateKeyWrapper) => {369      alice = privateKeyWrapper('//Alice');370      bob = privateKeyWrapper('//Bob');371    });372  });373374  it('Disallows excessive token nesting', async () => {375    await usingApi(async api => {376      const collection = await createCollectionExpectSuccess({mode: {type: 'NFT'}});377      await setCollectionPermissionsExpectSuccess(alice, collection, {nesting: {tokenOwner: true}});378      const targetToken = await createItemExpectSuccess(alice, collection, 'NFT');379380      const maxNestingLevel = 5;381      let prevToken = targetToken;382383      // Create a nested-token matryoshka384      for (let i = 0; i < maxNestingLevel; i++) {385        const nestedToken = await createItemExpectSuccess(386          alice,387          collection,388          'NFT',389          {Ethereum: tokenIdToAddress(collection, prevToken)},390        );391392        prevToken = nestedToken;393      }394395      // The nesting depth is limited by `maxNestingLevel`396      await expect(executeTransaction(api, alice, api.tx.unique.createItem(397        collection,398        {Ethereum: tokenIdToAddress(collection, prevToken)},399          {nft: {}} as any,400      )), 'while creating nested token').to.be.rejectedWith(/^structure\.DepthLimit$/);401402      expect(await getTopmostTokenOwner(api, collection, prevToken)).to.be.deep.equal({Substrate: alice.address});403    });404  });405406  // ---------- Admin ------------407408  it('Admin (NFT): disallows an Admin to operate nesting when only TokenOwner is allowed', async () => {409    await usingApi(async api => {410      const collection = await createCollectionExpectSuccess({mode: {type: 'NFT'}});411      await setCollectionPermissionsExpectSuccess(alice, collection, {nesting: {tokenOwner: true}});412      await addCollectionAdminExpectSuccess(alice, collection, bob.address);413      const targetToken = await createItemExpectSuccess(alice, collection, 'NFT');414415      // Try to create a nested token as collection admin when it's disallowed416      await expect(executeTransaction(api, bob, api.tx.unique.createItem(417        collection,418        {Ethereum: tokenIdToAddress(collection, targetToken)},419          {nft: {}} as any,420      )), 'while creating nested token').to.be.rejectedWith(/common\.UserIsNotAllowedToNest/);421422      // Try to create and nest a token in the wrong collection423      const newToken = await createItemExpectSuccess(bob, collection, 'NFT');424      await expect(executeTransaction(425        api, 426        bob, 427        api.tx.unique.transfer({Ethereum: tokenIdToAddress(collection, targetToken)}, collection, newToken, 1),428      ), 'while nesting new token').to.be.rejectedWith(/common\.UserIsNotAllowedToNest/);429      expect(await getTokenOwner(api, collection, newToken)).to.be.deep.equal({Substrate: bob.address});430    });431  });432433  it('Admin (NFT): disallows a Token Owner to operate nesting when only Admin is allowed', async () => {434    await usingApi(async api => {435      const collection = await createCollectionExpectSuccess({mode: {type: 'NFT'}});436      await setCollectionPermissionsExpectSuccess(alice, collection, {nesting: {collectionAdmin: true}});437      await addToAllowListExpectSuccess(alice, collection, bob.address);438      await enableAllowListExpectSuccess(alice, collection);439      await enablePublicMintingExpectSuccess(alice, collection);440      const targetToken = await createItemExpectSuccess(alice, collection, 'NFT');441442      // Try to create a nested token as collection admin when it's disallowed443      await expect(executeTransaction(api, bob, api.tx.unique.createItem(444        collection,445        {Ethereum: tokenIdToAddress(collection, targetToken)},446          {nft: {}} as any,447      )), 'while creating nested token').to.be.rejectedWith(/common\.AddressNotInAllowlist/); 448449      // Try to create and nest a token in the wrong collection450      const newToken = await createItemExpectSuccess(bob, collection, 'NFT');451      await expect(executeTransaction(452        api, 453        bob, 454        api.tx.unique.transfer({Ethereum: tokenIdToAddress(collection, targetToken)}, collection, newToken, 1),455      ), 'while nesting new token').to.be.rejectedWith(/common\.AddressNotInAllowlist/);456      expect(await getTokenOwner(api, collection, newToken)).to.be.deep.equal({Substrate: bob.address});457    });458  });459460  it('Admin (NFT): disallows an Admin to nest and unnest someone else\'s token', async () => {461    await usingApi(async api => {462      const collection = await createCollectionExpectSuccess({mode: {type: 'NFT'}});463      await setCollectionLimitsExpectSuccess(alice, collection, {ownerCanTransfer: true});464      await setCollectionPermissionsExpectSuccess(alice, collection, {nesting: {collectionAdmin: true}});465466      await addToAllowListExpectSuccess(alice, collection, bob.address);467      await enableAllowListExpectSuccess(alice, collection);468      await enablePublicMintingExpectSuccess(alice, collection);469470      // Create a token to attempt to be nested into471      const targetToken = await createItemExpectSuccess(bob, collection, 'NFT');472      const targetAddress = {Ethereum: tokenIdToAddress(collection, targetToken).toLowerCase()};473474      // Try to nest somebody else's token475      const newToken = await createItemExpectSuccess(bob, collection, 'NFT');476      await expect(executeTransaction(477        api, 478        alice, 479        api.tx.unique.transferFrom(targetAddress, {Substrate: bob.address}, collection, newToken, 1),480      ), 'while nesting another\'s token token').to.be.rejectedWith(/common\.AddressNotInAllowlist/);481      expect(await getTokenOwner(api, collection, newToken)).to.be.deep.equal({Substrate: bob.address});482483      // Nest a token as admin and try to unnest it, now belonging to someone else484      const nestedToken = await createItemExpectSuccess(alice, collection, 'NFT', targetAddress);485      await expect(executeTransaction(486        api, 487        alice, 488        api.tx.unique.transferFrom(targetAddress, normalizeAccountId(alice), collection, nestedToken, 1),489      ), 'while unnesting another\'s token').to.be.rejectedWith(/common\.AddressNotInAllowlist/);490      expect(await getTokenOwner(api, collection, nestedToken)).to.be.deep.equal(targetAddress);491      expect(await getTopmostTokenOwner(api, collection, nestedToken)).to.be.deep.equal({Substrate: bob.address});492    });493  });494495  it('Admin (NFT): disallows an Admin to nest a token from an unlisted collection (Restricted nesting)', async () => {496    await usingApi(async api => {497      const collectionA = await createCollectionExpectSuccess({mode: {type: 'NFT'}});498      const collectionB = await createCollectionExpectSuccess({mode: {type: 'NFT'}});499      await setCollectionPermissionsExpectSuccess(alice, collectionA, {nesting: {collectionAdmin: true, restricted:[collectionA]}});500501      // Create a token to attempt to be nested into502      const targetToken = await createItemExpectSuccess(alice, collectionA, 'NFT');503504      // Try to create and nest a token in the wrong collection505      const newToken = await createItemExpectSuccess(alice, collectionB, 'NFT');506      await expect(executeTransaction(507        api, 508        alice, 509        api.tx.unique.transfer({Ethereum: tokenIdToAddress(collectionA, targetToken)}, collectionB, newToken, 1),510      ), 'while nesting a foreign token').to.be.rejectedWith(/common\.SourceCollectionIsNotAllowedToNest/);511      expect(await getTokenOwner(api, collectionB, newToken)).to.be.deep.equal({Substrate: alice.address});512    });513  });514515  // ---------- Non-Fungible ----------516517  it('NFT: disallows to nest token if nesting is disabled', async () => {518    await usingApi(async api => {519      const collection = await createCollectionExpectSuccess({mode: {type: 'NFT'}});520      await setCollectionPermissionsExpectSuccess(alice, collection, {nesting: {}});521      const targetToken = await createItemExpectSuccess(alice, collection, 'NFT');522523      // Try to create a nested token524      await expect(executeTransaction(api, alice, api.tx.unique.createItem(525        collection,526        {Ethereum: tokenIdToAddress(collection, targetToken)},527          {nft: {}} as any,528      )), 'while creating nested token').to.be.rejectedWith(/^common\.UserIsNotAllowedToNest$/);529530      // Create a token to be nested531      const newToken = await createItemExpectSuccess(alice, collection, 'NFT');532      // Try to nest533      await expect(executeTransaction(api, alice, api.tx.unique.transfer({Ethereum: tokenIdToAddress(collection, targetToken)}, collection, newToken, 1)), 'while nesting new token').to.be.rejectedWith(/common\.UserIsNotAllowedToNest/);534      expect(await getTopmostTokenOwner(api, collection, newToken)).to.be.deep.equal({Substrate: alice.address});535      expect(await getTokenOwner(api, collection, newToken)).to.be.deep.equal({Substrate: alice.address});536    });537  });538539  it('NFT: disallows a non-Owner to nest someone else\'s token', async () => {540    await usingApi(async api => {541      const collection = await createCollectionExpectSuccess({mode: {type: 'NFT'}});542      await setCollectionPermissionsExpectSuccess(alice, collection, {nesting: {tokenOwner: true}});543544      await addToAllowListExpectSuccess(alice, collection, bob.address);545      await enableAllowListExpectSuccess(alice, collection);546      await enablePublicMintingExpectSuccess(alice, collection);547548      // Create a token to attempt to be nested into549      const targetToken = await createItemExpectSuccess(bob, collection, 'NFT');550551      // Try to create a nested token in the wrong collection552      await expect(executeTransaction(api, alice, api.tx.unique.createItem(553        collection,554        {Ethereum: tokenIdToAddress(collection, targetToken)},555          {nft: {}} as any,556      )), 'while creating nested token').to.be.rejectedWith(/common\.UserIsNotAllowedToNest/);557558      // Try to create and nest a token in the wrong collection559      const newToken = await createItemExpectSuccess(alice, collection, 'NFT');560      await expect(executeTransaction(api, alice, api.tx.unique.transfer({Ethereum: tokenIdToAddress(collection, targetToken)}, collection, newToken, 1)), 'while nesting new token').to.be.rejectedWith(/common\.AddressNotInAllowlist/);561      expect(await getTokenOwner(api, collection, newToken)).to.be.deep.equal({Substrate: alice.address});562    });563  });564565  it('NFT: disallows a non-Owner to nest someone else\'s token (Restricted nesting)', async () => {566    await usingApi(async api => {567      const collection = await createCollectionExpectSuccess({mode: {type: 'NFT'}});568      await setCollectionPermissionsExpectSuccess(alice, collection, {nesting: {tokenOwner: true, restricted:[collection]}});569570      await addToAllowListExpectSuccess(alice, collection, bob.address);571      await enableAllowListExpectSuccess(alice, collection);572      await enablePublicMintingExpectSuccess(alice, collection);573574      // Create a token to attempt to be nested into575      const targetToken = await createItemExpectSuccess(bob, collection, 'NFT');576577      // Try to create a nested token in the wrong collection578      await expect(executeTransaction(api, alice, api.tx.unique.createItem(579        collection,580        {Ethereum: tokenIdToAddress(collection, targetToken)},581          {nft: {}} as any,582      )), 'while creating nested token').to.be.rejectedWith(/common\.UserIsNotAllowedToNest/);583584      // Try to create and nest a token in the wrong collection585      const newToken = await createItemExpectSuccess(alice, collection, 'NFT');586      await expect(executeTransaction(api, alice, api.tx.unique.transfer({Ethereum: tokenIdToAddress(collection, targetToken)}, collection, newToken, 1)), 'while nesting new token').to.be.rejectedWith(/common\.AddressNotInAllowlist/);587      expect(await getTokenOwner(api, collection, newToken)).to.be.deep.equal({Substrate: alice.address});588    });589  });590591  it('NFT: disallows to nest token in an unlisted collection', async () => {592    await usingApi(async api => {593      const collection = await createCollectionExpectSuccess({mode: {type: 'NFT'}});594      await setCollectionPermissionsExpectSuccess(alice, collection, {nesting: {tokenOwner: true, restricted:[]}});595596      // Create a token to attempt to be nested into597      const targetToken = await createItemExpectSuccess(alice, collection, 'NFT');598599      // Try to create a nested token in the wrong collection600      await expect(executeTransaction(api, alice, api.tx.unique.createItem(601        collection,602        {Ethereum: tokenIdToAddress(collection, targetToken)},603          {nft: {}} as any,604      )), 'while creating nested token').to.be.rejectedWith(/common\.SourceCollectionIsNotAllowedToNest/);605606      // Try to create and nest a token in the wrong collection607      const newToken = await createItemExpectSuccess(alice, collection, 'NFT');608      await expect(executeTransaction(api, alice, api.tx.unique.transfer({Ethereum: tokenIdToAddress(collection, targetToken)}, collection, newToken, 1)), 'while nesting new token').to.be.rejectedWith(/common\.SourceCollectionIsNotAllowedToNest/);609      expect(await getTokenOwner(api, collection, newToken)).to.be.deep.equal({Substrate: alice.address});610    });611  });612613  // ---------- Fungible ----------614615  it('Fungible: disallows to nest token if nesting is disabled', async () => {616    await usingApi(async api => {617      const collectionNFT = await createCollectionExpectSuccess({mode: {type: 'NFT'}});618      await setCollectionPermissionsExpectSuccess(alice, collectionNFT, {nesting: {}});619      const targetToken = await createItemExpectSuccess(alice, collectionNFT, 'NFT');620      const targetAddress = {Ethereum: tokenIdToAddress(collectionNFT, targetToken)};621622      const collectionFT = await createCollectionExpectSuccess({mode: {type: 'Fungible', decimalPoints: 0}});623624      // Try to create a nested token625      await expect(executeTransaction(api, alice, api.tx.unique.createItem(626        collectionFT,627        targetAddress,628        {Fungible: {Value: 10}},629      )), 'while creating nested token').to.be.rejectedWith(/^common\.UserIsNotAllowedToNest$/);630631      // Create a token to be nested632      const newToken = await createItemExpectSuccess(alice, collectionFT, 'Fungible');633      // Try to nest634      await expect(executeTransaction(api, alice, api.tx.unique.transfer(targetAddress, collectionFT, newToken, 1)), 'while nesting new token').to.be.rejectedWith(/common\.UserIsNotAllowedToNest/);635636      // Create another token to be nested637      const newToken2 = await createItemExpectSuccess(alice, collectionFT, 'Fungible');638      // Try to nest inside a fungible token639      await expect(executeTransaction(api, alice, api.tx.unique.transfer({Ethereum: tokenIdToAddress(collectionFT, newToken)}, collectionFT, newToken2, 1)), 'while nesting new token inside fungible').to.be.rejectedWith(/fungible\.FungibleDisallowsNesting/);640    });641  });642643  it('Fungible: disallows a non-Owner to nest someone else\'s token', async () => {644    await usingApi(async api => {645      const collectionNFT = await createCollectionExpectSuccess({mode: {type: 'NFT'}});646      await setCollectionPermissionsExpectSuccess(alice, collectionNFT, {nesting: {tokenOwner: true}});647648      await addToAllowListExpectSuccess(alice, collectionNFT, bob.address);649      await enableAllowListExpectSuccess(alice, collectionNFT);650      await enablePublicMintingExpectSuccess(alice, collectionNFT);651652      // Create a token to attempt to be nested into653      const targetToken = await createItemExpectSuccess(bob, collectionNFT, 'NFT');654      const targetAddress = {Ethereum: tokenIdToAddress(collectionNFT, targetToken)};655656      const collectionFT = await createCollectionExpectSuccess({mode: {type: 'Fungible', decimalPoints: 0}});657658      // Try to create a nested token in the wrong collection659      await expect(executeTransaction(api, alice, api.tx.unique.createItem(660        collectionFT,661        targetAddress,662        {Fungible: {Value: 10}},663      )), 'while creating nested token').to.be.rejectedWith(/common\.UserIsNotAllowedToNest/);664665      // Try to create and nest a token in the wrong collection666      const newToken = await createItemExpectSuccess(alice, collectionFT, 'Fungible');667      await expect(executeTransaction(api, alice, api.tx.unique.transfer(targetAddress, collectionFT, newToken, 1)), 'while nesting new token').to.be.rejectedWith(/common\.UserIsNotAllowedToNest/);668    });669  });670671  it('Fungible: disallows a non-Owner to nest someone else\'s token (Restricted nesting)', async () => {672    await usingApi(async api => {673      const collectionNFT = await createCollectionExpectSuccess({mode: {type: 'NFT'}});674      await addToAllowListExpectSuccess(alice, collectionNFT, bob.address);675      await enableAllowListExpectSuccess(alice, collectionNFT);676      await enablePublicMintingExpectSuccess(alice, collectionNFT);677678      // Create a token to attempt to be nested into679      const targetToken = await createItemExpectSuccess(bob, collectionNFT, 'NFT');680      const targetAddress = {Ethereum: tokenIdToAddress(collectionNFT, targetToken)};681682      const collectionFT = await createCollectionExpectSuccess({mode: {type: 'Fungible', decimalPoints: 0}});683      await setCollectionPermissionsExpectSuccess(alice, collectionNFT, {nesting: {tokenOwner: true, restricted:[collectionFT]}});684685      // Try to create a nested token in the wrong collection686      await expect(executeTransaction(api, alice, api.tx.unique.createItem(687        collectionFT,688        targetAddress,689        {Fungible: {Value: 10}},690      )), 'while creating nested token').to.be.rejectedWith(/common\.UserIsNotAllowedToNest/);691692      // Try to create and nest a token in the wrong collection693      const newToken = await createItemExpectSuccess(alice, collectionFT, 'Fungible');694      await expect(executeTransaction(api, alice, api.tx.unique.transfer(targetAddress, collectionFT, newToken, 1)), 'while nesting new token').to.be.rejectedWith(/common\.UserIsNotAllowedToNest/);695    });696  });697698  it('Fungible: disallows to nest token in an unlisted collection', async () => {699    await usingApi(async api => {700      const collectionNFT = await createCollectionExpectSuccess({mode: {type: 'NFT'}});701      await setCollectionPermissionsExpectSuccess(alice, collectionNFT, {nesting: {tokenOwner: true, restricted:[]}});702703      // Create a token to attempt to be nested into704      const targetToken = await createItemExpectSuccess(alice, collectionNFT, 'NFT');705      const targetAddress = {Ethereum: tokenIdToAddress(collectionNFT, targetToken)};706707      const collectionFT = await createCollectionExpectSuccess({mode: {type: 'Fungible', decimalPoints: 0}});708709      // Try to create a nested token in the wrong collection710      await expect(executeTransaction(api, alice, api.tx.unique.createItem(711        collectionFT,712        targetAddress,713        {Fungible: {Value: 10}},714      )), 'while creating a nested token').to.be.rejectedWith(/common\.SourceCollectionIsNotAllowedToNest/);715716      // Try to create and nest a token in the wrong collection717      const newToken = await createItemExpectSuccess(alice, collectionFT, 'Fungible');718      await expect(executeTransaction(api, alice, api.tx.unique.transfer(targetAddress, collectionFT, newToken, 1)), 'while nesting new token').to.be.rejectedWith(/common\.SourceCollectionIsNotAllowedToNest/);719    });720  });721722  // ---------- Re-Fungible ----------723724  it('ReFungible: disallows to nest token if nesting is disabled', async function() {725    await requirePallets(this, [Pallets.ReFungible]);726727    await usingApi(async api => {728      const collectionNFT = await createCollectionExpectSuccess({mode: {type: 'NFT'}});729      await setCollectionPermissionsExpectSuccess(alice, collectionNFT, {nesting: {}});730      const targetToken = await createItemExpectSuccess(alice, collectionNFT, 'NFT');731      const targetAddress = {Ethereum: tokenIdToAddress(collectionNFT, targetToken)};732733      const collectionRFT = await createCollectionExpectSuccess({mode: {type: 'ReFungible'}});734735      // Create a nested token736      await expect(executeTransaction(api, alice, api.tx.unique.createItem(737        collectionRFT,738        targetAddress,739        {ReFungible: {pieces: 100}},740      )), 'while creating a nested token').to.be.rejectedWith(/^common\.UserIsNotAllowedToNest$/);741742      // Create a token to be nested743      const newToken = await createItemExpectSuccess(alice, collectionRFT, 'ReFungible');744      // Try to nest745      await transferExpectFailure(collectionRFT, newToken, alice, targetAddress, 100);746      // Try to nest747      await expect(executeTransaction(api, alice, api.tx.unique.transfer(targetAddress, collectionRFT, newToken, 1)), 'while nesting new token').to.be.rejectedWith(/common\.UserIsNotAllowedToNest/);748749      // Create another token to be nested750      const newToken2 = await createItemExpectSuccess(alice, collectionRFT, 'ReFungible');751      // Try to nest inside a fungible token752      await expect(executeTransaction(api, alice, api.tx.unique.transfer({Ethereum: tokenIdToAddress(collectionRFT, newToken)}, collectionRFT, newToken2, 1)), 'while nesting new token inside refungible').to.be.rejectedWith(/refungible\.RefungibleDisallowsNesting/);753    });754  });755756  it('ReFungible: disallows a non-Owner to nest someone else\'s token', async function() {757    await requirePallets(this, [Pallets.ReFungible]);758759    await usingApi(async api => {760      const collectionNFT = await createCollectionExpectSuccess({mode: {type: 'NFT'}});761      await setCollectionPermissionsExpectSuccess(alice, collectionNFT, {nesting: {tokenOwner: true}});762763      await addToAllowListExpectSuccess(alice, collectionNFT, bob.address);764      await enableAllowListExpectSuccess(alice, collectionNFT);765      await enablePublicMintingExpectSuccess(alice, collectionNFT);766767      // Create a token to attempt to be nested into768      const targetToken = await createItemExpectSuccess(bob, collectionNFT, 'NFT');769      const targetAddress = {Ethereum: tokenIdToAddress(collectionNFT, targetToken)};770771      const collectionRFT = await createCollectionExpectSuccess({mode: {type: 'ReFungible'}});772773      // Try to create a nested token in the wrong collection774      await expect(executeTransaction(api, alice, api.tx.unique.createItem(775        collectionRFT,776        targetAddress,777        {ReFungible: {pieces: 100}},778      )), 'while creating a nested token').to.be.rejectedWith(/common\.UserIsNotAllowedToNest/);779780      // Try to create and nest a token in the wrong collection781      const newToken = await createItemExpectSuccess(alice, collectionRFT, 'ReFungible');782      await expect(executeTransaction(api, alice, api.tx.unique.transfer(targetAddress, collectionRFT, newToken, 1)), 'while nesting new token').to.be.rejectedWith(/common\.UserIsNotAllowedToNest/);783    });784  });785786  it('ReFungible: disallows a non-Owner to nest someone else\'s token (Restricted nesting)', async function() {787    await requirePallets(this, [Pallets.ReFungible]);788789    await usingApi(async api => {790      const collectionNFT = await createCollectionExpectSuccess({mode: {type: 'NFT'}});791      await addToAllowListExpectSuccess(alice, collectionNFT, bob.address);792      await enableAllowListExpectSuccess(alice, collectionNFT);793      await enablePublicMintingExpectSuccess(alice, collectionNFT);794795      // Create a token to attempt to be nested into796      const targetToken = await createItemExpectSuccess(bob, collectionNFT, 'NFT');797      const targetAddress = {Ethereum: tokenIdToAddress(collectionNFT, targetToken)};798799      const collectionRFT = await createCollectionExpectSuccess({mode: {type: 'ReFungible'}});800      await setCollectionPermissionsExpectSuccess(alice, collectionNFT, {nesting: {tokenOwner: true, restricted:[collectionRFT]}});801802      // Try to create a nested token in the wrong collection803      await expect(executeTransaction(api, alice, api.tx.unique.createItem(804        collectionRFT,805        targetAddress,806        {ReFungible: {pieces: 100}},807      )), 'while creating a nested token').to.be.rejectedWith(/common\.UserIsNotAllowedToNest/);808809      // Try to create and nest a token in the wrong collection810      const newToken = await createItemExpectSuccess(alice, collectionRFT, 'ReFungible');811      await expect(executeTransaction(api, alice, api.tx.unique.transfer(targetAddress, collectionRFT, newToken, 1)), 'while nesting new token').to.be.rejectedWith(/common\.UserIsNotAllowedToNest/);812    });813  });814815  it('ReFungible: disallows to nest token to an unlisted collection', async function() {816    await requirePallets(this, [Pallets.ReFungible]);817818    await usingApi(async api => {819      const collectionNFT = await createCollectionExpectSuccess({mode: {type: 'NFT'}});820      await setCollectionPermissionsExpectSuccess(alice, collectionNFT, {nesting: {tokenOwner: true, restricted:[]}});821822      // Create a token to attempt to be nested into823      const targetToken = await createItemExpectSuccess(alice, collectionNFT, 'NFT');824      const targetAddress = {Ethereum: tokenIdToAddress(collectionNFT, targetToken)};825826      const collectionRFT = await createCollectionExpectSuccess({mode: {type: 'ReFungible'}});827828      // Try to create a nested token in the wrong collection829      await expect(executeTransaction(api, alice, api.tx.unique.createItem(830        collectionRFT,831        targetAddress,832        {ReFungible: {pieces: 100}},833      )), 'while creating a nested token').to.be.rejectedWith(/common\.SourceCollectionIsNotAllowedToNest/);834835      // Try to create and nest a token in the wrong collection836      const newToken = await createItemExpectSuccess(alice, collectionRFT, 'ReFungible');837      await expect(executeTransaction(api, alice, api.tx.unique.transfer(targetAddress, collectionRFT, newToken, 1)), 'while nesting new token').to.be.rejectedWith(/common\.SourceCollectionIsNotAllowedToNest/);838    });839  });840});