git.delta.rocks / unique-network / refs/commits / 3a1241714901

difftreelog

source

tests/src/nesting/nest.test.ts43.3 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} from '../util/helpers';20import {IKeyringPair} from '@polkadot/types/types';2122let alice: IKeyringPair;23let bob: IKeyringPair;24let charlie: IKeyringPair;2526describe('Integration Test: Composite nesting tests', () => {27  before(async () => {28    await usingApi(async (_, privateKeyWrapper) => {29      alice = privateKeyWrapper('//Alice');30      bob = privateKeyWrapper('//Bob');31    });32  });3334  it('Performs the full suite: bundles a token, transfers, and unnests', async () => {35    await usingApi(async api => {36      const collection = await createCollectionExpectSuccess({mode: {type: 'NFT'}});37      await setCollectionPermissionsExpectSuccess(alice, collection, {nesting: {tokenOwner: true}});38      const targetToken = await createItemExpectSuccess(alice, collection, 'NFT');3940      // Create a nested token41      const nestedToken = await createItemExpectSuccess(alice, collection, 'NFT', {Ethereum: tokenIdToAddress(collection, targetToken)});42      expect(await getTopmostTokenOwner(api, collection, nestedToken)).to.be.deep.equal({Substrate: alice.address});43      expect(await getTokenOwner(api, collection, nestedToken)).to.be.deep.equal({Ethereum: tokenIdToAddress(collection, targetToken).toLowerCase()});4445      // Create a token to be nested46      const newToken = await createItemExpectSuccess(alice, collection, 'NFT');4748      // Nest49      await transferExpectSuccess(collection, newToken, alice, {Ethereum: tokenIdToAddress(collection, targetToken)});50      expect(await getTopmostTokenOwner(api, collection, newToken)).to.be.deep.equal({Substrate: alice.address});51      expect(await getTokenOwner(api, collection, newToken)).to.be.deep.equal({Ethereum: tokenIdToAddress(collection, targetToken).toLowerCase()});5253      // Move bundle to different user54      await transferExpectSuccess(collection, targetToken, alice, {Substrate: bob.address});55      expect(await getTopmostTokenOwner(api, collection, nestedToken)).to.be.deep.equal({Substrate: bob.address});56      expect(await getTokenOwner(api, collection, nestedToken)).to.be.deep.equal({Ethereum: tokenIdToAddress(collection, targetToken).toLowerCase()});5758      // Unnest59      await transferFromExpectSuccess(collection, newToken, bob, {Ethereum: tokenIdToAddress(collection, targetToken)}, {Substrate: bob.address});60      expect(await getTokenOwner(api, collection, newToken)).to.be.deep.equal({Substrate: bob.address});61    });62  });6364  it('Transfers an already bundled token', async () => {65    await usingApi(async api => {66      const collection = await createCollectionExpectSuccess({mode: {type: 'NFT'}});67      await setCollectionPermissionsExpectSuccess(alice, collection, {nesting: {tokenOwner: true}});6869      const tokenA = await createItemExpectSuccess(alice, collection, 'NFT');70      const tokenB = await createItemExpectSuccess(alice, collection, 'NFT');7172      // Create a nested token73      const tokenC = await createItemExpectSuccess(alice, collection, 'NFT', {Ethereum: tokenIdToAddress(collection, tokenA)});74      expect(await getTopmostTokenOwner(api, collection, tokenC)).to.be.deep.equal({Substrate: alice.address});75      expect(await getTokenOwner(api, collection, tokenC)).to.be.deep.equal({Ethereum: tokenIdToAddress(collection, tokenA).toLowerCase()});7677      // Transfer the nested token to another token78      await expect(executeTransaction(79        api,80        alice,81        api.tx.unique.transferFrom(82          normalizeAccountId({Ethereum: tokenIdToAddress(collection, tokenA)}),83          normalizeAccountId({Ethereum: tokenIdToAddress(collection, tokenB)}),84          collection,85          tokenC,86          1,87        ),88      )).to.not.be.rejected;89      expect(await getTopmostTokenOwner(api, collection, tokenC)).to.be.deep.equal({Substrate: alice.address});90      expect(await getTokenOwner(api, collection, tokenC)).to.be.deep.equal({Ethereum: tokenIdToAddress(collection, tokenB).toLowerCase()});91    });92  });9394  it('Checks token children', async () => {95    await usingApi(async api => {96      const collectionA = await createCollectionExpectSuccess({mode: {type: 'NFT'}});97      await setCollectionPermissionsExpectSuccess(alice, collectionA, {nesting: {tokenOwner: true}});98      const collectionB = await createCollectionExpectSuccess({mode: {type: 'Fungible', decimalPoints: 0}});99100      const targetToken = await createItemExpectSuccess(alice, collectionA, 'NFT');101      const targetAddress = {Ethereum: tokenIdToAddress(collectionA, targetToken)};102      let children = await getTokenChildren(api, collectionA, targetToken);103      expect(children.length).to.be.equal(0, 'Children length check at creation');104105      // Create a nested NFT token106      const tokenA = await createItemExpectSuccess(alice, collectionA, 'NFT', targetAddress);107      children = await getTokenChildren(api, collectionA, targetToken);108      expect(children.length).to.be.equal(1, 'Children length check at nesting #1');109      expect(children).to.have.deep.members([110        {token: tokenA, collection: collectionA},111      ], 'Children contents check at nesting #1');112113      // Create then nest114      const tokenB = await createItemExpectSuccess(alice, collectionA, 'NFT');115      await transferExpectSuccess(collectionA, tokenB, alice, targetAddress);116      children = await getTokenChildren(api, collectionA, targetToken);117      expect(children.length).to.be.equal(2, 'Children length check at nesting #2');118      expect(children).to.have.deep.members([119        {token: tokenA, collection: collectionA},120        {token: tokenB, collection: collectionA},121      ], 'Children contents check at nesting #2');122123      // Move token B to a different user outside the nesting tree124      await transferExpectSuccess(collectionA, tokenB, alice, bob);125      children = await getTokenChildren(api, collectionA, targetToken);126      expect(children.length).to.be.equal(1, 'Children length check at unnesting');127      expect(children).to.be.have.deep.members([128        {token: tokenA, collection: collectionA},129      ], 'Children contents check at unnesting');130131      // Create a fungible token in another collection and then nest132      const tokenC = await createItemExpectSuccess(alice, collectionB, 'Fungible');133      await transferExpectSuccess(collectionB, tokenC, alice, targetAddress, 1, 'Fungible');134      children = await getTokenChildren(api, collectionA, targetToken);135      expect(children.length).to.be.equal(2, 'Children length check at nesting #3 (from another collection)');136      expect(children).to.be.have.deep.members([137        {token: tokenA, collection: collectionA},138        {token: tokenC, collection: collectionB},139      ], 'Children contents check at nesting #3 (from another collection)');140141      // Move the fungible token inside token A deeper in the nesting tree142      await transferFromExpectSuccess(collectionB, tokenC, alice, targetAddress, {Ethereum: tokenIdToAddress(collectionA, tokenA)}, 1, 'Fungible');143      children = await getTokenChildren(api, collectionA, targetToken);144      expect(children.length).to.be.equal(1, 'Children length check at deeper nesting');145      expect(children).to.be.have.deep.members([146        {token: tokenA, collection: collectionA},147      ], 'Children contents check at deeper nesting');148    });149  });150});151152describe('Integration Test: Various token type nesting', async () => {153  before(async () => {154    await usingApi(async (_, privateKeyWrapper) => {155      alice = privateKeyWrapper('//Alice');156      bob = privateKeyWrapper('//Bob');157      charlie = privateKeyWrapper('//Charlie');158    });159  });160161  it('Admin (NFT): allows an Admin to nest a token', async () => {162    await usingApi(async api => {163      const collection = await createCollectionExpectSuccess({mode: {type: 'NFT'}});164      await setCollectionPermissionsExpectSuccess(alice, collection, {nesting: {collectionAdmin: true}});165      await addCollectionAdminExpectSuccess(alice, collection, charlie.address);166      const targetToken = await createItemExpectSuccess(alice, collection, 'NFT');167168      // Create a nested token169      const nestedToken = await createItemExpectSuccess(charlie, collection, 'NFT', {Ethereum: tokenIdToAddress(collection, targetToken)});170      expect(await getTopmostTokenOwner(api, collection, nestedToken)).to.be.deep.equal({Substrate: alice.address});171      expect(await getTokenOwner(api, collection, nestedToken)).to.be.deep.equal({Ethereum: tokenIdToAddress(collection, targetToken).toLowerCase()});172173      // Create a token to be nested and nest174      const newToken = await createItemExpectSuccess(charlie, collection, 'NFT');175      await transferExpectSuccess(collection, newToken, charlie, {Ethereum: tokenIdToAddress(collection, targetToken)});176      expect(await getTopmostTokenOwner(api, collection, newToken)).to.be.deep.equal({Substrate: alice.address});177      expect(await getTokenOwner(api, collection, newToken)).to.be.deep.equal({Ethereum: tokenIdToAddress(collection, targetToken).toLowerCase()});178    });179  });180181  it('Admin (NFT): allows an Admin to nest a token (Restricted nesting)', async () => {182    await usingApi(async api => {183      const collectionA = await createCollectionExpectSuccess({mode: {type: 'NFT'}});184      await addCollectionAdminExpectSuccess(alice, collectionA, charlie.address);185      const collectionB = await createCollectionExpectSuccess({mode: {type: 'NFT'}});186      await addCollectionAdminExpectSuccess(alice, collectionB, charlie.address);187      await setCollectionPermissionsExpectSuccess(alice, collectionA, {nesting: {collectionAdmin: true, restricted:[collectionA, collectionB]}});188      const targetToken = await createItemExpectSuccess(alice, collectionA, 'NFT');189190      // Create a nested token191      const nestedToken = await createItemExpectSuccess(charlie, collectionB, 'NFT', {Ethereum: tokenIdToAddress(collectionA, targetToken)});192      expect(await getTopmostTokenOwner(api, collectionB, nestedToken)).to.be.deep.equal({Substrate: alice.address});193      expect(await getTokenOwner(api, collectionB, nestedToken)).to.be.deep.equal({Ethereum: tokenIdToAddress(collectionA, targetToken).toLowerCase()});194195      // Create a token to be nested and nest196      const newToken = await createItemExpectSuccess(charlie, collectionB, 'NFT');197      await transferExpectSuccess(collectionB, newToken, charlie, {Ethereum: tokenIdToAddress(collectionA, targetToken)});198      expect(await getTopmostTokenOwner(api, collectionB, newToken)).to.be.deep.equal({Substrate: alice.address});199      expect(await getTokenOwner(api, collectionB, newToken)).to.be.deep.equal({Ethereum: tokenIdToAddress(collectionA, targetToken).toLowerCase()});200    });201  });202203  // ---------- Non-Fungible ----------204205  it('NFT: allows an Owner to nest/unnest their token', async () => {206    await usingApi(async api => {207      const collection = await createCollectionExpectSuccess({mode: {type: 'NFT'}});208      await setCollectionPermissionsExpectSuccess(alice, collection, {nesting: {tokenOwner: true}});209      const targetToken = await createItemExpectSuccess(alice, collection, 'NFT');210211      // Create a nested token212      const nestedToken = await createItemExpectSuccess(alice, collection, 'NFT', {Ethereum: tokenIdToAddress(collection, targetToken)});213      expect(await getTopmostTokenOwner(api, collection, nestedToken)).to.be.deep.equal({Substrate: alice.address});214      expect(await getTokenOwner(api, collection, nestedToken)).to.be.deep.equal({Ethereum: tokenIdToAddress(collection, targetToken).toLowerCase()});215216      // Create a token to be nested and nest217      const newToken = await createItemExpectSuccess(alice, collection, 'NFT');218      await transferExpectSuccess(collection, newToken, alice, {Ethereum: tokenIdToAddress(collection, targetToken)});219      expect(await getTopmostTokenOwner(api, collection, newToken)).to.be.deep.equal({Substrate: alice.address});220      expect(await getTokenOwner(api, collection, newToken)).to.be.deep.equal({Ethereum: tokenIdToAddress(collection, targetToken).toLowerCase()});221    });222  });223224  it('NFT: allows an Owner to nest/unnest their token (Restricted nesting)', async () => {225    await usingApi(async api => {226      const collection = await createCollectionExpectSuccess({mode: {type: 'NFT'}});227      await setCollectionPermissionsExpectSuccess(alice, collection, {nesting: {tokenOwner: true, restricted:[collection]}});228      const targetToken = await createItemExpectSuccess(alice, collection, 'NFT');229230      // Create a nested token231      const nestedToken = await createItemExpectSuccess(alice, collection, 'NFT', {Ethereum: tokenIdToAddress(collection, targetToken)});232      expect(await getTopmostTokenOwner(api, collection, nestedToken)).to.be.deep.equal({Substrate: alice.address});233      expect(await getTokenOwner(api, collection, nestedToken)).to.be.deep.equal({Ethereum: tokenIdToAddress(collection, targetToken).toLowerCase()});234235      // Create a token to be nested and nest236      const newToken = await createItemExpectSuccess(alice, collection, 'NFT');237      await transferExpectSuccess(collection, newToken, alice, {Ethereum: tokenIdToAddress(collection, targetToken)});238      expect(await getTopmostTokenOwner(api, collection, newToken)).to.be.deep.equal({Substrate: alice.address});239      expect(await getTokenOwner(api, collection, newToken)).to.be.deep.equal({Ethereum: tokenIdToAddress(collection, targetToken).toLowerCase()});240    });241  });242243  // ---------- Fungible ----------244245  it('Fungible: allows an Owner to nest/unnest their token', async () => {246    await usingApi(async api => {247      const collectionNFT = await createCollectionExpectSuccess({mode: {type: 'NFT'}});248      await setCollectionPermissionsExpectSuccess(alice, collectionNFT, {nesting: {tokenOwner: true}});249      const targetToken = await createItemExpectSuccess(alice, collectionNFT, 'NFT', {Substrate: alice.address});250      const targetAddress = {Ethereum: tokenIdToAddress(collectionNFT, targetToken)};251252      const collectionFT = await createCollectionExpectSuccess({mode: {type: 'Fungible', decimalPoints: 0}});253254      // Create a nested token255      await expect(executeTransaction(api, alice, api.tx.unique.createItem(256        collectionFT,257        targetAddress,258        {Fungible: {Value: 10}},259      ))).to.not.be.rejected;260261      // Nest a new token262      const newToken = await createItemExpectSuccess(alice, collectionFT, 'Fungible');263      await transferExpectSuccess(collectionFT, newToken, alice, targetAddress, 1, 'Fungible');264    });265  });266267  it('Fungible: allows an Owner to nest/unnest their token (Restricted nesting)', async () => {268    await usingApi(async api => {269      const collectionNFT = await createCollectionExpectSuccess({mode: {type: 'NFT'}});270      const targetToken = await createItemExpectSuccess(alice, collectionNFT, 'NFT', {Substrate: alice.address});271      const targetAddress = {Ethereum: tokenIdToAddress(collectionNFT, targetToken)};272273      const collectionFT = await createCollectionExpectSuccess({mode: {type: 'Fungible', decimalPoints: 0}});274275      await setCollectionPermissionsExpectSuccess(alice, collectionNFT, {nesting: {tokenOwner: true, restricted: [collectionFT]}});276277      // Create a nested token278      await expect(executeTransaction(api, alice, api.tx.unique.createItem(279        collectionFT,280        targetAddress,281        {Fungible: {Value: 10}},282      ))).to.not.be.rejected;283284      // Nest a new token285      const newToken = await createItemExpectSuccess(alice, collectionFT, 'Fungible');286      await transferExpectSuccess(collectionFT, newToken, alice, targetAddress, 1, 'Fungible');287    });288  });289290  // ---------- Re-Fungible ----------291292  it('ReFungible: allows an Owner to nest/unnest their token', async () => {293    await usingApi(async api => {294      const collectionNFT = await createCollectionExpectSuccess({mode: {type: 'NFT'}});295      await setCollectionPermissionsExpectSuccess(alice, collectionNFT, {nesting: {tokenOwner: true}});296      const targetToken = await createItemExpectSuccess(alice, collectionNFT, 'NFT', {Substrate: alice.address});297      const targetAddress = {Ethereum: tokenIdToAddress(collectionNFT, targetToken)};298299      const collectionRFT = await createCollectionExpectSuccess({mode: {type: 'ReFungible'}});300301      // Create a nested token302      await expect(executeTransaction(api, alice, api.tx.unique.createItem(303        collectionRFT,304        targetAddress,305        {ReFungible: {const_data: [], pieces: 100}},306      ))).to.not.be.rejected;307308      // Nest a new token309      const newToken = await createItemExpectSuccess(alice, collectionRFT, 'ReFungible');310      await transferExpectSuccess(collectionRFT, newToken, alice, targetAddress, 100, 'ReFungible');311    });312  });313314  it('ReFungible: allows an Owner to nest/unnest their token (Restricted nesting)', async () => {315    await usingApi(async api => {316      const collectionNFT = await createCollectionExpectSuccess({mode: {type: 'NFT'}});317      const targetToken = await createItemExpectSuccess(alice, collectionNFT, 'NFT', {Substrate: alice.address});318      const targetAddress = {Ethereum: tokenIdToAddress(collectionNFT, targetToken)};319320      const collectionRFT = await createCollectionExpectSuccess({mode: {type: 'ReFungible'}});321322      await setCollectionPermissionsExpectSuccess(alice, collectionNFT, {nesting: {tokenOwner: true, restricted:[collectionRFT]}});323324      // Create a nested token325      await expect(executeTransaction(api, alice, api.tx.unique.createItem(326        collectionRFT,327        targetAddress,328        {ReFungible: {const_data: [], pieces: 100}},329      ))).to.not.be.rejected;330331      // Nest a new token332      const newToken = await createItemExpectSuccess(alice, collectionRFT, 'ReFungible');333      await transferExpectSuccess(collectionRFT, newToken, alice, targetAddress, 100, 'ReFungible');334    });335  });336});337338describe('Negative Test: Nesting', async() => {339  before(async () => {340    await usingApi(async (_, privateKeyWrapper) => {341      alice = privateKeyWrapper('//Alice');342      bob = privateKeyWrapper('//Bob');343      charlie = privateKeyWrapper('//Charlie');344    });345  });346347  it('Disallows excessive token nesting', async () => {348    await usingApi(async api => {349      const collection = await createCollectionExpectSuccess({mode: {type: 'NFT'}});350      await setCollectionPermissionsExpectSuccess(alice, collection, {nesting: {tokenOwner: true}});351      const targetToken = await createItemExpectSuccess(alice, collection, 'NFT');352353      const maxNestingLevel = 5;354      let prevToken = targetToken;355356      // Create a nested-token matryoshka357      for (let i = 0; i < maxNestingLevel; i++) {358        const nestedToken = await createItemExpectSuccess(359          alice,360          collection,361          'NFT',362          {Ethereum: tokenIdToAddress(collection, prevToken)},363        );364365        prevToken = nestedToken;366      }367368      // The nesting depth is limited by `maxNestingLevel`369      await expect(executeTransaction(api, alice, api.tx.unique.createItem(370        collection,371        {Ethereum: tokenIdToAddress(collection, prevToken)},372          {nft: {const_data: [], variable_data: []}} as any,373      )), 'while creating nested token').to.be.rejectedWith(/^structure\.DepthLimit$/);374375      expect(await getTopmostTokenOwner(api, collection, prevToken)).to.be.deep.equal({Substrate: alice.address});376    });377  });378379  // ---------- Admin ------------380381  it('Admin (NFT): disallows an Admin to operate nesting when only TokenOwner is allowed', async () => {382    await usingApi(async api => {383      const collection = await createCollectionExpectSuccess({mode: {type: 'NFT'}});384      await setCollectionPermissionsExpectSuccess(alice, collection, {nesting: {tokenOwner: true}});385      await addCollectionAdminExpectSuccess(alice, collection, charlie.address);386      const targetToken = await createItemExpectSuccess(alice, collection, 'NFT');387388      // Try to create a nested token as collection admin when it's disallowed389      await expect(executeTransaction(api, charlie, api.tx.unique.createItem(390        collection,391        {Ethereum: tokenIdToAddress(collection, targetToken)},392          {nft: {const_data: [], variable_data: []}} as any,393      )), 'while creating nested token').to.be.rejectedWith(/common\.UserIsNotAllowedToNest/);394395      // Try to create and nest a token in the wrong collection396      const newToken = await createItemExpectSuccess(charlie, collection, 'NFT');397      await expect(executeTransaction(398        api, 399        charlie, 400        api.tx.unique.transfer({Ethereum: tokenIdToAddress(collection, targetToken)}, collection, newToken, 1),401      ), 'while nesting new token').to.be.rejectedWith(/common\.UserIsNotAllowedToNest/);402      expect(await getTokenOwner(api, collection, newToken)).to.be.deep.equal({Substrate: charlie.address});403    });404  });405406  it('Admin (NFT): disallows a Token Owner to operate nesting when only Admin is allowed', async () => {407    await usingApi(async api => {408      const collection = await createCollectionExpectSuccess({mode: {type: 'NFT'}});409      await setCollectionPermissionsExpectSuccess(alice, collection, {nesting: {collectionAdmin: true}});410      await addToAllowListExpectSuccess(alice, collection, charlie.address);411      await enableAllowListExpectSuccess(alice, collection);412      await enablePublicMintingExpectSuccess(alice, collection);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, charlie, api.tx.unique.createItem(417        collection,418        {Ethereum: tokenIdToAddress(collection, targetToken)},419          {nft: {const_data: [], variable_data: []}} as any,420      )), 'while creating nested token').to.be.rejectedWith(/common\.AddressNotInAllowlist/); // todo is this right?421422      // Try to create and nest a token in the wrong collection423      const newToken = await createItemExpectSuccess(charlie, collection, 'NFT');424      await expect(executeTransaction(425        api, 426        charlie, 427        api.tx.unique.transfer({Ethereum: tokenIdToAddress(collection, targetToken)}, collection, newToken, 1),428      ), 'while nesting new token').to.be.rejectedWith(/common\.AddressNotInAllowlist/);429      expect(await getTokenOwner(api, collection, newToken)).to.be.deep.equal({Substrate: charlie.address});430    });431  });432433  it('Admin (NFT): disallows an Admin to nest and unnest someone else\'s token', async () => {434    await usingApi(async api => {435      const collection = await createCollectionExpectSuccess({mode: {type: 'NFT'}});436      await setCollectionPermissionsExpectSuccess(alice, collection, {nesting: {collectionAdmin: true}});437438      await addToAllowListExpectSuccess(alice, collection, charlie.address);439      await enableAllowListExpectSuccess(alice, collection);440      await enablePublicMintingExpectSuccess(alice, collection);441442      // Create a token to attempt to be nested into443      const targetToken = await createItemExpectSuccess(charlie, collection, 'NFT');444      const targetAddress = {Ethereum: tokenIdToAddress(collection, targetToken).toLowerCase()};445446      // Try to nest somebody else's token447      const newToken = await createItemExpectSuccess(charlie, collection, 'NFT');448      await expect(executeTransaction(449        api, 450        alice, 451        api.tx.unique.transfer(targetAddress, collection, newToken, 1),452      ), 'while nesting another\'s token token').to.be.rejectedWith(/common\.AddressNotInAllowlist/);453      expect(await getTokenOwner(api, collection, newToken)).to.be.deep.equal({Substrate: charlie.address});454455      // Nest a token as admin and try to unnest it, now belonging to someone else456      const nestedToken = await createItemExpectSuccess(alice, collection, 'NFT', targetAddress);457      await expect(executeTransaction(458        api, 459        alice, 460        api.tx.unique.transferFrom(targetAddress, normalizeAccountId(alice), collection, nestedToken, 1),461      ), 'while unnesting another\'s token').to.be.rejectedWith(/common\.AddressNotInAllowlist/);462      expect(await getTokenOwner(api, collection, nestedToken)).to.be.deep.equal(targetAddress);463      expect(await getTopmostTokenOwner(api, collection, nestedToken)).to.be.deep.equal({Substrate: charlie.address});464    });465  });466467  it('Admin (NFT): disallows an Admin to nest a token from an unlisted collection (Restricted nesting)', async () => {468    await usingApi(async api => {469      const collectionA = await createCollectionExpectSuccess({mode: {type: 'NFT'}});470      const collectionB = await createCollectionExpectSuccess({mode: {type: 'NFT'}});471      await setCollectionPermissionsExpectSuccess(alice, collectionA, {nesting: {collectionAdmin: true, restricted:[collectionA]}});472473      // Create a token to attempt to be nested into474      const targetToken = await createItemExpectSuccess(alice, collectionA, 'NFT');475476      // Try to create and nest a token in the wrong collection477      const newToken = await createItemExpectSuccess(alice, collectionB, 'NFT');478      await expect(executeTransaction(479        api, 480        alice, 481        api.tx.unique.transfer({Ethereum: tokenIdToAddress(collectionA, targetToken)}, collectionB, newToken, 1),482      ), 'while nesting a foreign token').to.be.rejectedWith(/common\.SourceCollectionIsNotAllowedToNest/);483      expect(await getTokenOwner(api, collectionB, newToken)).to.be.deep.equal({Substrate: alice.address});484    });485  });486487  // ---------- Non-Fungible ----------488489  it('NFT: disallows to nest token if nesting is disabled', async () => {490    await usingApi(async api => {491      const collection = await createCollectionExpectSuccess({mode: {type: 'NFT'}});492      await setCollectionPermissionsExpectSuccess(alice, collection, {nesting: {}});493      const targetToken = await createItemExpectSuccess(alice, collection, 'NFT');494495      // Try to create a nested token496      await expect(executeTransaction(api, alice, api.tx.unique.createItem(497        collection,498        {Ethereum: tokenIdToAddress(collection, targetToken)},499          {nft: {const_data: [], variable_data: []}} as any,500      )), 'while creating nested token').to.be.rejectedWith(/^common\.UserIsNotAllowedToNest$/);501502      // Create a token to be nested503      const newToken = await createItemExpectSuccess(alice, collection, 'NFT');504      // Try to nest505      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/);506      expect(await getTopmostTokenOwner(api, collection, newToken)).to.be.deep.equal({Substrate: alice.address});507      expect(await getTokenOwner(api, collection, newToken)).to.be.deep.equal({Substrate: alice.address});508    });509  });510511  it('NFT: disallows a non-Owner to nest someone else\'s token', async () => {512    await usingApi(async api => {513      const collection = await createCollectionExpectSuccess({mode: {type: 'NFT'}});514      await setCollectionPermissionsExpectSuccess(alice, collection, {nesting: {tokenOwner: true}});515516      await addToAllowListExpectSuccess(alice, collection, bob.address);517      await enableAllowListExpectSuccess(alice, collection);518      await enablePublicMintingExpectSuccess(alice, collection);519520      // Create a token to attempt to be nested into521      const targetToken = await createItemExpectSuccess(bob, collection, 'NFT');522523      // Try to create a nested token in the wrong collection524      await expect(executeTransaction(api, alice, api.tx.unique.createItem(525        collection,526        {Ethereum: tokenIdToAddress(collection, targetToken)},527          {nft: {const_data: [], variable_data: []}} as any,528      )), 'while creating nested token').to.be.rejectedWith(/common\.UserIsNotAllowedToNest/);529530      // Try to create and nest a token in the wrong collection531      const newToken = await createItemExpectSuccess(alice, collection, 'NFT');532      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/);533      expect(await getTokenOwner(api, collection, newToken)).to.be.deep.equal({Substrate: alice.address});534    });535  });536537  it('NFT: disallows a non-Owner to nest someone else\'s token (Restricted nesting)', async () => {538    await usingApi(async api => {539      const collection = await createCollectionExpectSuccess({mode: {type: 'NFT'}});540      await setCollectionPermissionsExpectSuccess(alice, collection, {nesting: {tokenOwner: true, restricted:[collection]}});541542      await addToAllowListExpectSuccess(alice, collection, bob.address);543      await enableAllowListExpectSuccess(alice, collection);544      await enablePublicMintingExpectSuccess(alice, collection);545546      // Create a token to attempt to be nested into547      const targetToken = await createItemExpectSuccess(bob, collection, 'NFT');548549      // Try to create a nested token in the wrong collection550      await expect(executeTransaction(api, alice, api.tx.unique.createItem(551        collection,552        {Ethereum: tokenIdToAddress(collection, targetToken)},553          {nft: {const_data: [], variable_data: []}} as any,554      )), 'while creating nested token').to.be.rejectedWith(/common\.UserIsNotAllowedToNest/);555556      // Try to create and nest a token in the wrong collection557      const newToken = await createItemExpectSuccess(alice, collection, 'NFT');558      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/);559      expect(await getTokenOwner(api, collection, newToken)).to.be.deep.equal({Substrate: alice.address});560    });561  });562563  it('NFT: disallows to nest token in an unlisted collection', async () => {564    await usingApi(async api => {565      const collection = await createCollectionExpectSuccess({mode: {type: 'NFT'}});566      await setCollectionPermissionsExpectSuccess(alice, collection, {nesting: {tokenOwner: true, restricted:[]}});567568      // Create a token to attempt to be nested into569      const targetToken = await createItemExpectSuccess(alice, collection, 'NFT');570571      // Try to create a nested token in the wrong collection572      await expect(executeTransaction(api, alice, api.tx.unique.createItem(573        collection,574        {Ethereum: tokenIdToAddress(collection, targetToken)},575          {nft: {const_data: [], variable_data: []}} as any,576      )), 'while creating nested token').to.be.rejectedWith(/common\.SourceCollectionIsNotAllowedToNest/);577578      // Try to create and nest a token in the wrong collection579      const newToken = await createItemExpectSuccess(alice, collection, 'NFT');580      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/);581      expect(await getTokenOwner(api, collection, newToken)).to.be.deep.equal({Substrate: alice.address});582    });583  });584585  // ---------- Fungible ----------586587  it('Fungible: disallows to nest token if nesting is disabled', async () => {588    await usingApi(async api => {589      const collectionNFT = await createCollectionExpectSuccess({mode: {type: 'NFT'}});590      await setCollectionPermissionsExpectSuccess(alice, collectionNFT, {nesting: {}});591      const targetToken = await createItemExpectSuccess(alice, collectionNFT, 'NFT');592      const targetAddress = {Ethereum: tokenIdToAddress(collectionNFT, targetToken)};593594      const collectionFT = await createCollectionExpectSuccess({mode: {type: 'Fungible', decimalPoints: 0}});595596      // Try to create a nested token597      await expect(executeTransaction(api, alice, api.tx.unique.createItem(598        collectionFT,599        targetAddress,600        {Fungible: {Value: 10}},601      )), 'while creating nested token').to.be.rejectedWith(/^common\.UserIsNotAllowedToNest$/);602603      // Create a token to be nested604      const newToken = await createItemExpectSuccess(alice, collectionFT, 'Fungible');605      // Try to nest606      await expect(executeTransaction(api, alice, api.tx.unique.transfer(targetAddress, collectionFT, newToken, 1)), 'while nesting new token').to.be.rejectedWith(/common\.UserIsNotAllowedToNest/);607608      // Create another token to be nested609      const newToken2 = await createItemExpectSuccess(alice, collectionFT, 'Fungible');610      // Try to nest inside a fungible token611      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/);612    });613  });614615  it('Fungible: disallows a non-Owner to nest someone else\'s token', async () => {616    await usingApi(async api => {617      const collectionNFT = await createCollectionExpectSuccess({mode: {type: 'NFT'}});618      await setCollectionPermissionsExpectSuccess(alice, collectionNFT, {nesting: {tokenOwner: true}});619620      await addToAllowListExpectSuccess(alice, collectionNFT, bob.address);621      await enableAllowListExpectSuccess(alice, collectionNFT);622      await enablePublicMintingExpectSuccess(alice, collectionNFT);623624      // Create a token to attempt to be nested into625      const targetToken = await createItemExpectSuccess(bob, collectionNFT, 'NFT');626      const targetAddress = {Ethereum: tokenIdToAddress(collectionNFT, targetToken)};627628      const collectionFT = await createCollectionExpectSuccess({mode: {type: 'Fungible', decimalPoints: 0}});629630      // Try to create a nested token in the wrong collection631      await expect(executeTransaction(api, alice, api.tx.unique.createItem(632        collectionFT,633        targetAddress,634        {Fungible: {Value: 10}},635      )), 'while creating nested token').to.be.rejectedWith(/common\.UserIsNotAllowedToNest/);636637      // Try to create and nest a token in the wrong collection638      const newToken = await createItemExpectSuccess(alice, collectionFT, 'Fungible');639      await expect(executeTransaction(api, alice, api.tx.unique.transfer(targetAddress, collectionFT, newToken, 1)), 'while nesting new token').to.be.rejectedWith(/common\.UserIsNotAllowedToNest/);640    });641  });642643  it('Fungible: disallows a non-Owner to nest someone else\'s token (Restricted nesting)', async () => {644    await usingApi(async api => {645      const collectionNFT = await createCollectionExpectSuccess({mode: {type: 'NFT'}});646      await addToAllowListExpectSuccess(alice, collectionNFT, bob.address);647      await enableAllowListExpectSuccess(alice, collectionNFT);648      await enablePublicMintingExpectSuccess(alice, collectionNFT);649650      // Create a token to attempt to be nested into651      const targetToken = await createItemExpectSuccess(bob, collectionNFT, 'NFT');652      const targetAddress = {Ethereum: tokenIdToAddress(collectionNFT, targetToken)};653654      const collectionFT = await createCollectionExpectSuccess({mode: {type: 'Fungible', decimalPoints: 0}});655      await setCollectionPermissionsExpectSuccess(alice, collectionNFT, {nesting: {tokenOwner: true, restricted:[collectionFT]}});656657      // Try to create a nested token in the wrong collection658      await expect(executeTransaction(api, alice, api.tx.unique.createItem(659        collectionFT,660        targetAddress,661        {Fungible: {Value: 10}},662      )), 'while creating nested token').to.be.rejectedWith(/common\.UserIsNotAllowedToNest/);663664      // Try to create and nest a token in the wrong collection665      const newToken = await createItemExpectSuccess(alice, collectionFT, 'Fungible');666      await expect(executeTransaction(api, alice, api.tx.unique.transfer(targetAddress, collectionFT, newToken, 1)), 'while nesting new token').to.be.rejectedWith(/common\.UserIsNotAllowedToNest/);667    });668  });669670  it('Fungible: disallows to nest token in an unlisted collection', async () => {671    await usingApi(async api => {672      const collectionNFT = await createCollectionExpectSuccess({mode: {type: 'NFT'}});673      await setCollectionPermissionsExpectSuccess(alice, collectionNFT, {nesting: {tokenOwner: true, restricted:[]}});674675      // Create a token to attempt to be nested into676      const targetToken = await createItemExpectSuccess(alice, collectionNFT, 'NFT');677      const targetAddress = {Ethereum: tokenIdToAddress(collectionNFT, targetToken)};678679      const collectionFT = await createCollectionExpectSuccess({mode: {type: 'Fungible', decimalPoints: 0}});680681      // Try to create a nested token in the wrong collection682      await expect(executeTransaction(api, alice, api.tx.unique.createItem(683        collectionFT,684        targetAddress,685        {Fungible: {Value: 10}},686      )), 'while creating a nested token').to.be.rejectedWith(/common\.SourceCollectionIsNotAllowedToNest/);687688      // Try to create and nest a token in the wrong collection689      const newToken = await createItemExpectSuccess(alice, collectionFT, 'Fungible');690      await expect(executeTransaction(api, alice, api.tx.unique.transfer(targetAddress, collectionFT, newToken, 1)), 'while nesting new token').to.be.rejectedWith(/common\.SourceCollectionIsNotAllowedToNest/);691    });692  });693694  // ---------- Re-Fungible ----------695696  it('ReFungible: disallows to nest token if nesting is disabled', async () => {697    await usingApi(async api => {698      const collectionNFT = await createCollectionExpectSuccess({mode: {type: 'NFT'}});699      await setCollectionPermissionsExpectSuccess(alice, collectionNFT, {nesting: {}});700      const targetToken = await createItemExpectSuccess(alice, collectionNFT, 'NFT');701      const targetAddress = {Ethereum: tokenIdToAddress(collectionNFT, targetToken)};702703      const collectionRFT = await createCollectionExpectSuccess({mode: {type: 'ReFungible'}});704705      // Create a nested token706      await expect(executeTransaction(api, alice, api.tx.unique.createItem(707        collectionRFT,708        targetAddress,709        {ReFungible: {const_data: [], pieces: 100}},710      )), 'while creating a nested token').to.be.rejectedWith(/^common\.UserIsNotAllowedToNest$/);711712      // Create a token to be nested713      const newToken = await createItemExpectSuccess(alice, collectionRFT, 'ReFungible');714      // Try to nest715      await transferExpectFailure(collectionRFT, newToken, alice, targetAddress, 100);716      // Try to nest717      await expect(executeTransaction(api, alice, api.tx.unique.transfer(targetAddress, collectionRFT, newToken, 1)), 'while nesting new token').to.be.rejectedWith(/common\.UserIsNotAllowedToNest/);718719      // Create another token to be nested720      const newToken2 = await createItemExpectSuccess(alice, collectionRFT, 'ReFungible');721      // Try to nest inside a fungible token722      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/);723    });724  });725726  it('ReFungible: disallows a non-Owner to nest someone else\'s token', async () => {727    await usingApi(async api => {728      const collectionNFT = await createCollectionExpectSuccess({mode: {type: 'NFT'}});729      await setCollectionPermissionsExpectSuccess(alice, collectionNFT, {nesting: {tokenOwner: true}});730731      await addToAllowListExpectSuccess(alice, collectionNFT, bob.address);732      await enableAllowListExpectSuccess(alice, collectionNFT);733      await enablePublicMintingExpectSuccess(alice, collectionNFT);734735      // Create a token to attempt to be nested into736      const targetToken = await createItemExpectSuccess(bob, collectionNFT, 'NFT');737      const targetAddress = {Ethereum: tokenIdToAddress(collectionNFT, targetToken)};738739      const collectionRFT = await createCollectionExpectSuccess({mode: {type: 'ReFungible'}});740741      // Try to create a nested token in the wrong collection742      await expect(executeTransaction(api, alice, api.tx.unique.createItem(743        collectionRFT,744        targetAddress,745        {ReFungible: {const_data: [], pieces: 100}},746      )), 'while creating a nested token').to.be.rejectedWith(/common\.UserIsNotAllowedToNest/);747748      // Try to create and nest a token in the wrong collection749      const newToken = await createItemExpectSuccess(alice, collectionRFT, 'ReFungible');750      await expect(executeTransaction(api, alice, api.tx.unique.transfer(targetAddress, collectionRFT, newToken, 1)), 'while nesting new token').to.be.rejectedWith(/common\.UserIsNotAllowedToNest/);751    });752  });753754  it('ReFungible: disallows a non-Owner to nest someone else\'s token (Restricted nesting)', async () => {755    await usingApi(async api => {756      const collectionNFT = await createCollectionExpectSuccess({mode: {type: 'NFT'}});757      await addToAllowListExpectSuccess(alice, collectionNFT, bob.address);758      await enableAllowListExpectSuccess(alice, collectionNFT);759      await enablePublicMintingExpectSuccess(alice, collectionNFT);760761      // Create a token to attempt to be nested into762      const targetToken = await createItemExpectSuccess(bob, collectionNFT, 'NFT');763      const targetAddress = {Ethereum: tokenIdToAddress(collectionNFT, targetToken)};764765      const collectionRFT = await createCollectionExpectSuccess({mode: {type: 'ReFungible'}});766      await setCollectionPermissionsExpectSuccess(alice, collectionNFT, {nesting: {tokenOwner: true, restricted:[collectionRFT]}});767768      // Try to create a nested token in the wrong collection769      await expect(executeTransaction(api, alice, api.tx.unique.createItem(770        collectionRFT,771        targetAddress,772        {ReFungible: {const_data: [], pieces: 100}},773      )), 'while creating a nested token').to.be.rejectedWith(/common\.UserIsNotAllowedToNest/);774775      // Try to create and nest a token in the wrong collection776      const newToken = await createItemExpectSuccess(alice, collectionRFT, 'ReFungible');777      await expect(executeTransaction(api, alice, api.tx.unique.transfer(targetAddress, collectionRFT, newToken, 1)), 'while nesting new token').to.be.rejectedWith(/common\.UserIsNotAllowedToNest/);778    });779  });780781  it('ReFungible: disallows to nest token to an unlisted collection', async () => {782    await usingApi(async api => {783      const collectionNFT = await createCollectionExpectSuccess({mode: {type: 'NFT'}});784      await setCollectionPermissionsExpectSuccess(alice, collectionNFT, {nesting: {tokenOwner: true, restricted:[]}});785786      // Create a token to attempt to be nested into787      const targetToken = await createItemExpectSuccess(alice, collectionNFT, 'NFT');788      const targetAddress = {Ethereum: tokenIdToAddress(collectionNFT, targetToken)};789790      const collectionRFT = await createCollectionExpectSuccess({mode: {type: 'ReFungible'}});791792      // Try to create a nested token in the wrong collection793      await expect(executeTransaction(api, alice, api.tx.unique.createItem(794        collectionRFT,795        targetAddress,796        {ReFungible: {const_data: [], pieces: 100}},797      )), 'while creating a nested token').to.be.rejectedWith(/common\.SourceCollectionIsNotAllowedToNest/);798799      // Try to create and nest a token in the wrong collection800      const newToken = await createItemExpectSuccess(alice, collectionRFT, 'ReFungible');801      await expect(executeTransaction(api, alice, api.tx.unique.transfer(targetAddress, collectionRFT, newToken, 1)), 'while nesting new token').to.be.rejectedWith(/common\.SourceCollectionIsNotAllowedToNest/);802    });803  });804});