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} from '../util/helpers';21import {IKeyringPair} from '@polkadot/types/types';2223let alice: IKeyringPair;24let bob: IKeyringPair;25let charlie: IKeyringPair;2627describe('Integration Test: Composite nesting tests', () => {28 before(async () => {29 await usingApi(async (_, privateKeyWrapper) => {30 alice = privateKeyWrapper('//Alice');31 bob = privateKeyWrapper('//Bob');32 });33 });3435 it('Performs the full suite: bundles a token, transfers, and unnests', async () => {36 await usingApi(async api => {37 const collection = await createCollectionExpectSuccess({mode: {type: 'NFT'}});38 await setCollectionPermissionsExpectSuccess(alice, collection, {nesting: {tokenOwner: true}});39 const targetToken = await createItemExpectSuccess(alice, collection, 'NFT');4041 42 const nestedToken = await createItemExpectSuccess(alice, collection, 'NFT', {Ethereum: tokenIdToAddress(collection, targetToken)});43 expect(await getTopmostTokenOwner(api, collection, nestedToken)).to.be.deep.equal({Substrate: alice.address});44 expect(await getTokenOwner(api, collection, nestedToken)).to.be.deep.equal({Ethereum: tokenIdToAddress(collection, targetToken).toLowerCase()});4546 47 const newToken = await createItemExpectSuccess(alice, collection, 'NFT');4849 50 await transferExpectSuccess(collection, newToken, alice, {Ethereum: tokenIdToAddress(collection, targetToken)});51 expect(await getTopmostTokenOwner(api, collection, newToken)).to.be.deep.equal({Substrate: alice.address});52 expect(await getTokenOwner(api, collection, newToken)).to.be.deep.equal({Ethereum: tokenIdToAddress(collection, targetToken).toLowerCase()});5354 55 await transferExpectSuccess(collection, targetToken, alice, {Substrate: bob.address});56 expect(await getTopmostTokenOwner(api, collection, nestedToken)).to.be.deep.equal({Substrate: bob.address});57 expect(await getTokenOwner(api, collection, nestedToken)).to.be.deep.equal({Ethereum: tokenIdToAddress(collection, targetToken).toLowerCase()});5859 60 await transferFromExpectSuccess(collection, newToken, bob, {Ethereum: tokenIdToAddress(collection, targetToken)}, {Substrate: bob.address});61 expect(await getTokenOwner(api, collection, newToken)).to.be.deep.equal({Substrate: bob.address});62 });63 });6465 it('Transfers an already bundled token', async () => {66 await usingApi(async api => {67 const collection = await createCollectionExpectSuccess({mode: {type: 'NFT'}});68 await setCollectionPermissionsExpectSuccess(alice, collection, {nesting: {tokenOwner: true}});6970 const tokenA = await createItemExpectSuccess(alice, collection, 'NFT');71 const tokenB = await createItemExpectSuccess(alice, collection, 'NFT');7273 74 const tokenC = await createItemExpectSuccess(alice, collection, 'NFT', {Ethereum: tokenIdToAddress(collection, tokenA)});75 expect(await getTopmostTokenOwner(api, collection, tokenC)).to.be.deep.equal({Substrate: alice.address});76 expect(await getTokenOwner(api, collection, tokenC)).to.be.deep.equal({Ethereum: tokenIdToAddress(collection, tokenA).toLowerCase()});7778 79 await expect(executeTransaction(80 api,81 alice,82 api.tx.unique.transferFrom(83 normalizeAccountId({Ethereum: tokenIdToAddress(collection, tokenA)}),84 normalizeAccountId({Ethereum: tokenIdToAddress(collection, tokenB)}),85 collection,86 tokenC,87 1,88 ),89 )).to.not.be.rejected;90 expect(await getTopmostTokenOwner(api, collection, tokenC)).to.be.deep.equal({Substrate: alice.address});91 expect(await getTokenOwner(api, collection, tokenC)).to.be.deep.equal({Ethereum: tokenIdToAddress(collection, tokenB).toLowerCase()});92 });93 });9495 it('Checks token children', async () => {96 await usingApi(async api => {97 const collectionA = await createCollectionExpectSuccess({mode: {type: 'NFT'}});98 await setCollectionLimitsExpectSuccess(alice, collectionA, {ownerCanTransfer: true});99 await setCollectionPermissionsExpectSuccess(alice, collectionA, {nesting: {tokenOwner: true}});100 const collectionB = await createCollectionExpectSuccess({mode: {type: 'Fungible', decimalPoints: 0}});101102 const targetToken = await createItemExpectSuccess(alice, collectionA, 'NFT');103 const targetAddress = {Ethereum: tokenIdToAddress(collectionA, targetToken)};104 let children = await getTokenChildren(api, collectionA, targetToken);105 expect(children.length).to.be.equal(0, 'Children length check at creation');106107 108 const tokenA = await createItemExpectSuccess(alice, collectionA, 'NFT', targetAddress);109 children = await getTokenChildren(api, collectionA, targetToken);110 expect(children.length).to.be.equal(1, 'Children length check at nesting #1');111 expect(children).to.have.deep.members([112 {token: tokenA, collection: collectionA},113 ], 'Children contents check at nesting #1');114115 116 const tokenB = await createItemExpectSuccess(alice, collectionA, 'NFT');117 await transferExpectSuccess(collectionA, tokenB, alice, targetAddress);118 children = await getTokenChildren(api, collectionA, targetToken);119 expect(children.length).to.be.equal(2, 'Children length check at nesting #2');120 expect(children).to.have.deep.members([121 {token: tokenA, collection: collectionA},122 {token: tokenB, collection: collectionA},123 ], 'Children contents check at nesting #2');124125 126 await transferExpectSuccess(collectionA, tokenB, alice, bob);127 children = await getTokenChildren(api, collectionA, targetToken);128 expect(children.length).to.be.equal(1, 'Children length check at unnesting');129 expect(children).to.be.have.deep.members([130 {token: tokenA, collection: collectionA},131 ], 'Children contents check at unnesting');132133 134 const tokenC = await createItemExpectSuccess(alice, collectionB, 'Fungible');135 await transferExpectSuccess(collectionB, tokenC, alice, targetAddress, 1, 'Fungible');136 children = await getTokenChildren(api, collectionA, targetToken);137 expect(children.length).to.be.equal(2, 'Children length check at nesting #3 (from another collection)');138 expect(children).to.be.have.deep.members([139 {token: tokenA, collection: collectionA},140 {token: tokenC, collection: collectionB},141 ], 'Children contents check at nesting #3 (from another collection)');142143 144 await transferFromExpectSuccess(collectionB, tokenC, alice, targetAddress, {Ethereum: tokenIdToAddress(collectionA, tokenA)}, 1, 'Fungible');145 children = await getTokenChildren(api, collectionA, targetToken);146 expect(children.length).to.be.equal(1, 'Children length check at deeper nesting');147 expect(children).to.be.have.deep.members([148 {token: tokenA, collection: collectionA},149 ], 'Children contents check at deeper nesting');150 });151 });152});153154describe('Integration Test: Various token type nesting', async () => {155 before(async () => {156 await usingApi(async (_, privateKeyWrapper) => {157 alice = privateKeyWrapper('//Alice');158 bob = privateKeyWrapper('//Bob');159 charlie = privateKeyWrapper('//Charlie');160 });161 });162163 it('Admin (NFT): allows an Admin to nest a token', async () => {164 await usingApi(async api => {165 const collection = await createCollectionExpectSuccess({mode: {type: 'NFT'}});166 await setCollectionPermissionsExpectSuccess(alice, collection, {nesting: {collectionAdmin: true}});167 await addCollectionAdminExpectSuccess(alice, collection, bob.address);168 const targetToken = await createItemExpectSuccess(alice, collection, 'NFT', charlie.address);169170 171 const nestedToken = await createItemExpectSuccess(bob, collection, 'NFT', {Ethereum: tokenIdToAddress(collection, targetToken)});172 expect(await getTopmostTokenOwner(api, collection, nestedToken)).to.be.deep.equal({Substrate: charlie.address});173 expect(await getTokenOwner(api, collection, nestedToken)).to.be.deep.equal({Ethereum: tokenIdToAddress(collection, targetToken).toLowerCase()});174175 176 const newToken = await createItemExpectSuccess(bob, collection, 'NFT');177 await transferExpectSuccess(collection, newToken, bob, {Ethereum: tokenIdToAddress(collection, targetToken)});178 expect(await getTopmostTokenOwner(api, collection, newToken)).to.be.deep.equal({Substrate: charlie.address});179 expect(await getTokenOwner(api, collection, newToken)).to.be.deep.equal({Ethereum: tokenIdToAddress(collection, targetToken).toLowerCase()});180 });181 });182183 it('Admin (NFT): Admin and Token Owner can operate together', async () => {184 await usingApi(async api => {185 const collection = await createCollectionExpectSuccess({mode: {type: 'NFT'}});186 await setCollectionPermissionsExpectSuccess(alice, collection, {nesting: {tokenOwner: true, collectionAdmin: true}});187 await addCollectionAdminExpectSuccess(alice, collection, bob.address);188 const targetToken = await createItemExpectSuccess(alice, collection, 'NFT', charlie.address);189190 191 const nestedToken = await createItemExpectSuccess(bob, collection, 'NFT', {Ethereum: tokenIdToAddress(collection, targetToken)});192 expect(await getTopmostTokenOwner(api, collection, nestedToken)).to.be.deep.equal({Substrate: charlie.address});193 expect(await getTokenOwner(api, collection, nestedToken)).to.be.deep.equal({Ethereum: tokenIdToAddress(collection, targetToken).toLowerCase()});194195 196 const newToken = await createItemExpectSuccess(alice, collection, 'NFT', charlie.address);197 await transferExpectSuccess(collection, newToken, charlie, {Ethereum: tokenIdToAddress(collection, nestedToken)});198 expect(await getTopmostTokenOwner(api, collection, newToken)).to.be.deep.equal({Substrate: charlie.address});199 expect(await getTokenOwner(api, collection, newToken)).to.be.deep.equal({Ethereum: tokenIdToAddress(collection, nestedToken).toLowerCase()});200 });201 });202203 it('Admin (NFT): allows an Admin to nest a token (Restricted nesting)', async () => {204 await usingApi(async api => {205 const collectionA = await createCollectionExpectSuccess({mode: {type: 'NFT'}});206 await addCollectionAdminExpectSuccess(alice, collectionA, bob.address);207 const collectionB = await createCollectionExpectSuccess({mode: {type: 'NFT'}});208 await addCollectionAdminExpectSuccess(alice, collectionB, bob.address);209 await setCollectionPermissionsExpectSuccess(alice, collectionA, {nesting: {collectionAdmin: true, restricted:[collectionA, collectionB]}});210 const targetToken = await createItemExpectSuccess(alice, collectionA, 'NFT', charlie.address);211212 213 const nestedToken = await createItemExpectSuccess(bob, collectionB, 'NFT', {Ethereum: tokenIdToAddress(collectionA, targetToken)});214 expect(await getTopmostTokenOwner(api, collectionB, nestedToken)).to.be.deep.equal({Substrate: charlie.address});215 expect(await getTokenOwner(api, collectionB, nestedToken)).to.be.deep.equal({Ethereum: tokenIdToAddress(collectionA, targetToken).toLowerCase()});216217 218 const newToken = await createItemExpectSuccess(bob, collectionB, 'NFT');219 await transferExpectSuccess(collectionB, newToken, bob, {Ethereum: tokenIdToAddress(collectionA, targetToken)});220 expect(await getTopmostTokenOwner(api, collectionB, newToken)).to.be.deep.equal({Substrate: charlie.address});221 expect(await getTokenOwner(api, collectionB, newToken)).to.be.deep.equal({Ethereum: tokenIdToAddress(collectionA, targetToken).toLowerCase()});222 });223 });224225 226227 it('NFT: allows an Owner to nest/unnest their token', async () => {228 await usingApi(async api => {229 const collection = await createCollectionExpectSuccess({mode: {type: 'NFT'}});230 await setCollectionPermissionsExpectSuccess(alice, collection, {nesting: {tokenOwner: true}});231 const targetToken = await createItemExpectSuccess(alice, collection, 'NFT');232233 234 const nestedToken = await createItemExpectSuccess(alice, collection, 'NFT', {Ethereum: tokenIdToAddress(collection, targetToken)});235 expect(await getTopmostTokenOwner(api, collection, nestedToken)).to.be.deep.equal({Substrate: alice.address});236 expect(await getTokenOwner(api, collection, nestedToken)).to.be.deep.equal({Ethereum: tokenIdToAddress(collection, targetToken).toLowerCase()});237238 239 const newToken = await createItemExpectSuccess(alice, collection, 'NFT');240 await transferExpectSuccess(collection, newToken, alice, {Ethereum: tokenIdToAddress(collection, targetToken)});241 expect(await getTopmostTokenOwner(api, collection, newToken)).to.be.deep.equal({Substrate: alice.address});242 expect(await getTokenOwner(api, collection, newToken)).to.be.deep.equal({Ethereum: tokenIdToAddress(collection, targetToken).toLowerCase()});243 });244 });245246 it('NFT: allows an Owner to nest/unnest their token (Restricted nesting)', async () => {247 await usingApi(async api => {248 const collection = await createCollectionExpectSuccess({mode: {type: 'NFT'}});249 await setCollectionPermissionsExpectSuccess(alice, collection, {nesting: {tokenOwner: true, restricted:[collection]}});250 const targetToken = await createItemExpectSuccess(alice, collection, 'NFT');251252 253 const nestedToken = await createItemExpectSuccess(alice, collection, 'NFT', {Ethereum: tokenIdToAddress(collection, targetToken)});254 expect(await getTopmostTokenOwner(api, collection, nestedToken)).to.be.deep.equal({Substrate: alice.address});255 expect(await getTokenOwner(api, collection, nestedToken)).to.be.deep.equal({Ethereum: tokenIdToAddress(collection, targetToken).toLowerCase()});256257 258 const newToken = await createItemExpectSuccess(alice, collection, 'NFT');259 await transferExpectSuccess(collection, newToken, alice, {Ethereum: tokenIdToAddress(collection, targetToken)});260 expect(await getTopmostTokenOwner(api, collection, newToken)).to.be.deep.equal({Substrate: alice.address});261 expect(await getTokenOwner(api, collection, newToken)).to.be.deep.equal({Ethereum: tokenIdToAddress(collection, targetToken).toLowerCase()});262 });263 });264265 266267 it('Fungible: allows an Owner to nest/unnest their token', async () => {268 await usingApi(async api => {269 const collectionNFT = await createCollectionExpectSuccess({mode: {type: 'NFT'}});270 await setCollectionPermissionsExpectSuccess(alice, collectionNFT, {nesting: {tokenOwner: true}});271 const targetToken = await createItemExpectSuccess(alice, collectionNFT, 'NFT', {Substrate: alice.address});272 const targetAddress = {Ethereum: tokenIdToAddress(collectionNFT, targetToken)};273274 const collectionFT = await createCollectionExpectSuccess({mode: {type: 'Fungible', decimalPoints: 0}});275276 277 await expect(executeTransaction(api, alice, api.tx.unique.createItem(278 collectionFT,279 targetAddress,280 {Fungible: {Value: 10}},281 ))).to.not.be.rejected;282283 284 const newToken = await createItemExpectSuccess(alice, collectionFT, 'Fungible');285 await transferExpectSuccess(collectionFT, newToken, alice, targetAddress, 1, 'Fungible');286 });287 });288289 it('Fungible: allows an Owner to nest/unnest their token (Restricted nesting)', async () => {290 await usingApi(async api => {291 const collectionNFT = await createCollectionExpectSuccess({mode: {type: 'NFT'}});292 const targetToken = await createItemExpectSuccess(alice, collectionNFT, 'NFT', {Substrate: alice.address});293 const targetAddress = {Ethereum: tokenIdToAddress(collectionNFT, targetToken)};294295 const collectionFT = await createCollectionExpectSuccess({mode: {type: 'Fungible', decimalPoints: 0}});296297 await setCollectionPermissionsExpectSuccess(alice, collectionNFT, {nesting: {tokenOwner: true, restricted: [collectionFT]}});298299 300 await expect(executeTransaction(api, alice, api.tx.unique.createItem(301 collectionFT,302 targetAddress,303 {Fungible: {Value: 10}},304 ))).to.not.be.rejected;305306 307 const newToken = await createItemExpectSuccess(alice, collectionFT, 'Fungible');308 await transferExpectSuccess(collectionFT, newToken, alice, targetAddress, 1, 'Fungible');309 });310 });311312 313314 it('ReFungible: allows an Owner to nest/unnest their token', async () => {315 await usingApi(async api => {316 const collectionNFT = await createCollectionExpectSuccess({mode: {type: 'NFT'}});317 await setCollectionPermissionsExpectSuccess(alice, collectionNFT, {nesting: {tokenOwner: true}});318 const targetToken = await createItemExpectSuccess(alice, collectionNFT, 'NFT', {Substrate: alice.address});319 const targetAddress = {Ethereum: tokenIdToAddress(collectionNFT, targetToken)};320321 const collectionRFT = await createCollectionExpectSuccess({mode: {type: 'ReFungible'}});322323 324 await expect(executeTransaction(api, alice, api.tx.unique.createItem(325 collectionRFT,326 targetAddress,327 {ReFungible: {pieces: 100}},328 ))).to.not.be.rejected;329330 331 const newToken = await createItemExpectSuccess(alice, collectionRFT, 'ReFungible');332 await transferExpectSuccess(collectionRFT, newToken, alice, targetAddress, 100, 'ReFungible');333 });334 });335336 it('ReFungible: allows an Owner to nest/unnest their token (Restricted nesting)', async () => {337 await usingApi(async api => {338 const collectionNFT = await createCollectionExpectSuccess({mode: {type: 'NFT'}});339 const targetToken = await createItemExpectSuccess(alice, collectionNFT, 'NFT', {Substrate: alice.address});340 const targetAddress = {Ethereum: tokenIdToAddress(collectionNFT, targetToken)};341342 const collectionRFT = await createCollectionExpectSuccess({mode: {type: 'ReFungible'}});343344 await setCollectionPermissionsExpectSuccess(alice, collectionNFT, {nesting: {tokenOwner: true, restricted:[collectionRFT]}});345346 347 await expect(executeTransaction(api, alice, api.tx.unique.createItem(348 collectionRFT,349 targetAddress,350 {ReFungible: {pieces: 100}},351 ))).to.not.be.rejected;352353 354 const newToken = await createItemExpectSuccess(alice, collectionRFT, 'ReFungible');355 await transferExpectSuccess(collectionRFT, newToken, alice, targetAddress, 100, 'ReFungible');356 });357 });358});359360describe('Negative Test: Nesting', async() => {361 before(async () => {362 await usingApi(async (_, privateKeyWrapper) => {363 alice = privateKeyWrapper('//Alice');364 bob = privateKeyWrapper('//Bob');365 });366 });367368 it('Disallows excessive token nesting', async () => {369 await usingApi(async api => {370 const collection = await createCollectionExpectSuccess({mode: {type: 'NFT'}});371 await setCollectionPermissionsExpectSuccess(alice, collection, {nesting: {tokenOwner: true}});372 const targetToken = await createItemExpectSuccess(alice, collection, 'NFT');373374 const maxNestingLevel = 5;375 let prevToken = targetToken;376377 378 for (let i = 0; i < maxNestingLevel; i++) {379 const nestedToken = await createItemExpectSuccess(380 alice,381 collection,382 'NFT',383 {Ethereum: tokenIdToAddress(collection, prevToken)},384 );385386 prevToken = nestedToken;387 }388389 390 await expect(executeTransaction(api, alice, api.tx.unique.createItem(391 collection,392 {Ethereum: tokenIdToAddress(collection, prevToken)},393 {nft: {}} as any,394 )), 'while creating nested token').to.be.rejectedWith(/^structure\.DepthLimit$/);395396 expect(await getTopmostTokenOwner(api, collection, prevToken)).to.be.deep.equal({Substrate: alice.address});397 });398 });399400 401402 it('Admin (NFT): disallows an Admin to operate nesting when only TokenOwner is allowed', async () => {403 await usingApi(async api => {404 const collection = await createCollectionExpectSuccess({mode: {type: 'NFT'}});405 await setCollectionPermissionsExpectSuccess(alice, collection, {nesting: {tokenOwner: true}});406 await addCollectionAdminExpectSuccess(alice, collection, bob.address);407 const targetToken = await createItemExpectSuccess(alice, collection, 'NFT');408409 410 await expect(executeTransaction(api, bob, api.tx.unique.createItem(411 collection,412 {Ethereum: tokenIdToAddress(collection, targetToken)},413 {nft: {}} as any,414 )), 'while creating nested token').to.be.rejectedWith(/common\.UserIsNotAllowedToNest/);415416 417 const newToken = await createItemExpectSuccess(bob, collection, 'NFT');418 await expect(executeTransaction(419 api, 420 bob, 421 api.tx.unique.transfer({Ethereum: tokenIdToAddress(collection, targetToken)}, collection, newToken, 1),422 ), 'while nesting new token').to.be.rejectedWith(/common\.UserIsNotAllowedToNest/);423 expect(await getTokenOwner(api, collection, newToken)).to.be.deep.equal({Substrate: bob.address});424 });425 });426427 it('Admin (NFT): disallows a Token Owner to operate nesting when only Admin is allowed', async () => {428 await usingApi(async api => {429 const collection = await createCollectionExpectSuccess({mode: {type: 'NFT'}});430 await setCollectionPermissionsExpectSuccess(alice, collection, {nesting: {collectionAdmin: true}});431 await addToAllowListExpectSuccess(alice, collection, bob.address);432 await enableAllowListExpectSuccess(alice, collection);433 await enablePublicMintingExpectSuccess(alice, collection);434 const targetToken = await createItemExpectSuccess(alice, collection, 'NFT');435436 437 await expect(executeTransaction(api, bob, api.tx.unique.createItem(438 collection,439 {Ethereum: tokenIdToAddress(collection, targetToken)},440 {nft: {}} as any,441 )), 'while creating nested token').to.be.rejectedWith(/common\.AddressNotInAllowlist/); 442443 444 const newToken = await createItemExpectSuccess(bob, collection, 'NFT');445 await expect(executeTransaction(446 api, 447 bob, 448 api.tx.unique.transfer({Ethereum: tokenIdToAddress(collection, targetToken)}, collection, newToken, 1),449 ), 'while nesting new token').to.be.rejectedWith(/common\.AddressNotInAllowlist/);450 expect(await getTokenOwner(api, collection, newToken)).to.be.deep.equal({Substrate: bob.address});451 });452 });453454 it('Admin (NFT): disallows an Admin to nest and unnest someone else\'s token', async () => {455 await usingApi(async api => {456 const collection = await createCollectionExpectSuccess({mode: {type: 'NFT'}});457 await setCollectionLimitsExpectSuccess(alice, collection, {ownerCanTransfer: true});458 await setCollectionPermissionsExpectSuccess(alice, collection, {nesting: {collectionAdmin: true}});459460 await addToAllowListExpectSuccess(alice, collection, bob.address);461 await enableAllowListExpectSuccess(alice, collection);462 await enablePublicMintingExpectSuccess(alice, collection);463464 465 const targetToken = await createItemExpectSuccess(bob, collection, 'NFT');466 const targetAddress = {Ethereum: tokenIdToAddress(collection, targetToken).toLowerCase()};467468 469 const newToken = await createItemExpectSuccess(bob, collection, 'NFT');470 await expect(executeTransaction(471 api, 472 alice, 473 api.tx.unique.transfer(targetAddress, collection, newToken, 1),474 ), 'while nesting another\'s token token').to.be.rejectedWith(/common\.AddressNotInAllowlist/);475 expect(await getTokenOwner(api, collection, newToken)).to.be.deep.equal({Substrate: bob.address});476477 478 const nestedToken = await createItemExpectSuccess(alice, collection, 'NFT', targetAddress);479 await expect(executeTransaction(480 api, 481 alice, 482 api.tx.unique.transferFrom(targetAddress, normalizeAccountId(alice), collection, nestedToken, 1),483 ), 'while unnesting another\'s token').to.be.rejectedWith(/common\.AddressNotInAllowlist/);484 expect(await getTokenOwner(api, collection, nestedToken)).to.be.deep.equal(targetAddress);485 expect(await getTopmostTokenOwner(api, collection, nestedToken)).to.be.deep.equal({Substrate: bob.address});486 });487 });488489 it('Admin (NFT): disallows an Admin to nest a token from an unlisted collection (Restricted nesting)', async () => {490 await usingApi(async api => {491 const collectionA = await createCollectionExpectSuccess({mode: {type: 'NFT'}});492 const collectionB = await createCollectionExpectSuccess({mode: {type: 'NFT'}});493 await setCollectionPermissionsExpectSuccess(alice, collectionA, {nesting: {collectionAdmin: true, restricted:[collectionA]}});494495 496 const targetToken = await createItemExpectSuccess(alice, collectionA, 'NFT');497498 499 const newToken = await createItemExpectSuccess(alice, collectionB, 'NFT');500 await expect(executeTransaction(501 api, 502 alice, 503 api.tx.unique.transfer({Ethereum: tokenIdToAddress(collectionA, targetToken)}, collectionB, newToken, 1),504 ), 'while nesting a foreign token').to.be.rejectedWith(/common\.SourceCollectionIsNotAllowedToNest/);505 expect(await getTokenOwner(api, collectionB, newToken)).to.be.deep.equal({Substrate: alice.address});506 });507 });508509 510511 it('NFT: disallows to nest token if nesting is disabled', async () => {512 await usingApi(async api => {513 const collection = await createCollectionExpectSuccess({mode: {type: 'NFT'}});514 await setCollectionPermissionsExpectSuccess(alice, collection, {nesting: {}});515 const targetToken = await createItemExpectSuccess(alice, collection, 'NFT');516517 518 await expect(executeTransaction(api, alice, api.tx.unique.createItem(519 collection,520 {Ethereum: tokenIdToAddress(collection, targetToken)},521 {nft: {}} as any,522 )), 'while creating nested token').to.be.rejectedWith(/^common\.UserIsNotAllowedToNest$/);523524 525 const newToken = await createItemExpectSuccess(alice, collection, 'NFT');526 527 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/);528 expect(await getTopmostTokenOwner(api, collection, newToken)).to.be.deep.equal({Substrate: alice.address});529 expect(await getTokenOwner(api, collection, newToken)).to.be.deep.equal({Substrate: alice.address});530 });531 });532533 it('NFT: disallows a non-Owner to nest someone else\'s token', async () => {534 await usingApi(async api => {535 const collection = await createCollectionExpectSuccess({mode: {type: 'NFT'}});536 await setCollectionPermissionsExpectSuccess(alice, collection, {nesting: {tokenOwner: true}});537538 await addToAllowListExpectSuccess(alice, collection, bob.address);539 await enableAllowListExpectSuccess(alice, collection);540 await enablePublicMintingExpectSuccess(alice, collection);541542 543 const targetToken = await createItemExpectSuccess(bob, collection, 'NFT');544545 546 await expect(executeTransaction(api, alice, api.tx.unique.createItem(547 collection,548 {Ethereum: tokenIdToAddress(collection, targetToken)},549 {nft: {}} as any,550 )), 'while creating nested token').to.be.rejectedWith(/common\.UserIsNotAllowedToNest/);551552 553 const newToken = await createItemExpectSuccess(alice, collection, 'NFT');554 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/);555 expect(await getTokenOwner(api, collection, newToken)).to.be.deep.equal({Substrate: alice.address});556 });557 });558559 it('NFT: disallows a non-Owner to nest someone else\'s token (Restricted nesting)', async () => {560 await usingApi(async api => {561 const collection = await createCollectionExpectSuccess({mode: {type: 'NFT'}});562 await setCollectionPermissionsExpectSuccess(alice, collection, {nesting: {tokenOwner: true, restricted:[collection]}});563564 await addToAllowListExpectSuccess(alice, collection, bob.address);565 await enableAllowListExpectSuccess(alice, collection);566 await enablePublicMintingExpectSuccess(alice, collection);567568 569 const targetToken = await createItemExpectSuccess(bob, collection, 'NFT');570571 572 await expect(executeTransaction(api, alice, api.tx.unique.createItem(573 collection,574 {Ethereum: tokenIdToAddress(collection, targetToken)},575 {nft: {}} as any,576 )), 'while creating nested token').to.be.rejectedWith(/common\.UserIsNotAllowedToNest/);577578 579 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\.AddressNotInAllowlist/);581 expect(await getTokenOwner(api, collection, newToken)).to.be.deep.equal({Substrate: alice.address});582 });583 });584585 it('NFT: disallows to nest token in an unlisted collection', async () => {586 await usingApi(async api => {587 const collection = await createCollectionExpectSuccess({mode: {type: 'NFT'}});588 await setCollectionPermissionsExpectSuccess(alice, collection, {nesting: {tokenOwner: true, restricted:[]}});589590 591 const targetToken = await createItemExpectSuccess(alice, collection, 'NFT');592593 594 await expect(executeTransaction(api, alice, api.tx.unique.createItem(595 collection,596 {Ethereum: tokenIdToAddress(collection, targetToken)},597 {nft: {}} as any,598 )), 'while creating nested token').to.be.rejectedWith(/common\.SourceCollectionIsNotAllowedToNest/);599600 601 const newToken = await createItemExpectSuccess(alice, collection, 'NFT');602 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/);603 expect(await getTokenOwner(api, collection, newToken)).to.be.deep.equal({Substrate: alice.address});604 });605 });606607 608609 it('Fungible: disallows to nest token if nesting is disabled', async () => {610 await usingApi(async api => {611 const collectionNFT = await createCollectionExpectSuccess({mode: {type: 'NFT'}});612 await setCollectionPermissionsExpectSuccess(alice, collectionNFT, {nesting: {}});613 const targetToken = await createItemExpectSuccess(alice, collectionNFT, 'NFT');614 const targetAddress = {Ethereum: tokenIdToAddress(collectionNFT, targetToken)};615616 const collectionFT = await createCollectionExpectSuccess({mode: {type: 'Fungible', decimalPoints: 0}});617618 619 await expect(executeTransaction(api, alice, api.tx.unique.createItem(620 collectionFT,621 targetAddress,622 {Fungible: {Value: 10}},623 )), 'while creating nested token').to.be.rejectedWith(/^common\.UserIsNotAllowedToNest$/);624625 626 const newToken = await createItemExpectSuccess(alice, collectionFT, 'Fungible');627 628 await expect(executeTransaction(api, alice, api.tx.unique.transfer(targetAddress, collectionFT, newToken, 1)), 'while nesting new token').to.be.rejectedWith(/common\.UserIsNotAllowedToNest/);629630 631 const newToken2 = await createItemExpectSuccess(alice, collectionFT, 'Fungible');632 633 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/);634 });635 });636637 it('Fungible: disallows a non-Owner to nest someone else\'s token', async () => {638 await usingApi(async api => {639 const collectionNFT = await createCollectionExpectSuccess({mode: {type: 'NFT'}});640 await setCollectionPermissionsExpectSuccess(alice, collectionNFT, {nesting: {tokenOwner: true}});641642 await addToAllowListExpectSuccess(alice, collectionNFT, bob.address);643 await enableAllowListExpectSuccess(alice, collectionNFT);644 await enablePublicMintingExpectSuccess(alice, collectionNFT);645646 647 const targetToken = await createItemExpectSuccess(bob, collectionNFT, 'NFT');648 const targetAddress = {Ethereum: tokenIdToAddress(collectionNFT, targetToken)};649650 const collectionFT = await createCollectionExpectSuccess({mode: {type: 'Fungible', decimalPoints: 0}});651652 653 await expect(executeTransaction(api, alice, api.tx.unique.createItem(654 collectionFT,655 targetAddress,656 {Fungible: {Value: 10}},657 )), 'while creating nested token').to.be.rejectedWith(/common\.UserIsNotAllowedToNest/);658659 660 const newToken = await createItemExpectSuccess(alice, collectionFT, 'Fungible');661 await expect(executeTransaction(api, alice, api.tx.unique.transfer(targetAddress, collectionFT, newToken, 1)), 'while nesting new token').to.be.rejectedWith(/common\.UserIsNotAllowedToNest/);662 });663 });664665 it('Fungible: disallows a non-Owner to nest someone else\'s token (Restricted nesting)', async () => {666 await usingApi(async api => {667 const collectionNFT = await createCollectionExpectSuccess({mode: {type: 'NFT'}});668 await addToAllowListExpectSuccess(alice, collectionNFT, bob.address);669 await enableAllowListExpectSuccess(alice, collectionNFT);670 await enablePublicMintingExpectSuccess(alice, collectionNFT);671672 673 const targetToken = await createItemExpectSuccess(bob, collectionNFT, 'NFT');674 const targetAddress = {Ethereum: tokenIdToAddress(collectionNFT, targetToken)};675676 const collectionFT = await createCollectionExpectSuccess({mode: {type: 'Fungible', decimalPoints: 0}});677 await setCollectionPermissionsExpectSuccess(alice, collectionNFT, {nesting: {tokenOwner: true, restricted:[collectionFT]}});678679 680 await expect(executeTransaction(api, alice, api.tx.unique.createItem(681 collectionFT,682 targetAddress,683 {Fungible: {Value: 10}},684 )), 'while creating nested token').to.be.rejectedWith(/common\.UserIsNotAllowedToNest/);685686 687 const newToken = await createItemExpectSuccess(alice, collectionFT, 'Fungible');688 await expect(executeTransaction(api, alice, api.tx.unique.transfer(targetAddress, collectionFT, newToken, 1)), 'while nesting new token').to.be.rejectedWith(/common\.UserIsNotAllowedToNest/);689 });690 });691692 it('Fungible: disallows to nest token in an unlisted collection', async () => {693 await usingApi(async api => {694 const collectionNFT = await createCollectionExpectSuccess({mode: {type: 'NFT'}});695 await setCollectionPermissionsExpectSuccess(alice, collectionNFT, {nesting: {tokenOwner: true, restricted:[]}});696697 698 const targetToken = await createItemExpectSuccess(alice, collectionNFT, 'NFT');699 const targetAddress = {Ethereum: tokenIdToAddress(collectionNFT, targetToken)};700701 const collectionFT = await createCollectionExpectSuccess({mode: {type: 'Fungible', decimalPoints: 0}});702703 704 await expect(executeTransaction(api, alice, api.tx.unique.createItem(705 collectionFT,706 targetAddress,707 {Fungible: {Value: 10}},708 )), 'while creating a nested token').to.be.rejectedWith(/common\.SourceCollectionIsNotAllowedToNest/);709710 711 const newToken = await createItemExpectSuccess(alice, collectionFT, 'Fungible');712 await expect(executeTransaction(api, alice, api.tx.unique.transfer(targetAddress, collectionFT, newToken, 1)), 'while nesting new token').to.be.rejectedWith(/common\.SourceCollectionIsNotAllowedToNest/);713 });714 });715716 717718 it('ReFungible: disallows to nest token if nesting is disabled', async () => {719 await usingApi(async api => {720 const collectionNFT = await createCollectionExpectSuccess({mode: {type: 'NFT'}});721 await setCollectionPermissionsExpectSuccess(alice, collectionNFT, {nesting: {}});722 const targetToken = await createItemExpectSuccess(alice, collectionNFT, 'NFT');723 const targetAddress = {Ethereum: tokenIdToAddress(collectionNFT, targetToken)};724725 const collectionRFT = await createCollectionExpectSuccess({mode: {type: 'ReFungible'}});726727 728 await expect(executeTransaction(api, alice, api.tx.unique.createItem(729 collectionRFT,730 targetAddress,731 {ReFungible: {pieces: 100}},732 )), 'while creating a nested token').to.be.rejectedWith(/^common\.UserIsNotAllowedToNest$/);733734 735 const newToken = await createItemExpectSuccess(alice, collectionRFT, 'ReFungible');736 737 await transferExpectFailure(collectionRFT, newToken, alice, targetAddress, 100);738 739 await expect(executeTransaction(api, alice, api.tx.unique.transfer(targetAddress, collectionRFT, newToken, 1)), 'while nesting new token').to.be.rejectedWith(/common\.UserIsNotAllowedToNest/);740741 742 const newToken2 = await createItemExpectSuccess(alice, collectionRFT, 'ReFungible');743 744 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/);745 });746 });747748 it('ReFungible: disallows a non-Owner to nest someone else\'s token', async () => {749 await usingApi(async api => {750 const collectionNFT = await createCollectionExpectSuccess({mode: {type: 'NFT'}});751 await setCollectionPermissionsExpectSuccess(alice, collectionNFT, {nesting: {tokenOwner: true}});752753 await addToAllowListExpectSuccess(alice, collectionNFT, bob.address);754 await enableAllowListExpectSuccess(alice, collectionNFT);755 await enablePublicMintingExpectSuccess(alice, collectionNFT);756757 758 const targetToken = await createItemExpectSuccess(bob, collectionNFT, 'NFT');759 const targetAddress = {Ethereum: tokenIdToAddress(collectionNFT, targetToken)};760761 const collectionRFT = await createCollectionExpectSuccess({mode: {type: 'ReFungible'}});762763 764 await expect(executeTransaction(api, alice, api.tx.unique.createItem(765 collectionRFT,766 targetAddress,767 {ReFungible: {pieces: 100}},768 )), 'while creating a nested token').to.be.rejectedWith(/common\.UserIsNotAllowedToNest/);769770 771 const newToken = await createItemExpectSuccess(alice, collectionRFT, 'ReFungible');772 await expect(executeTransaction(api, alice, api.tx.unique.transfer(targetAddress, collectionRFT, newToken, 1)), 'while nesting new token').to.be.rejectedWith(/common\.UserIsNotAllowedToNest/);773 });774 });775776 it('ReFungible: disallows a non-Owner to nest someone else\'s token (Restricted nesting)', async () => {777 await usingApi(async api => {778 const collectionNFT = await createCollectionExpectSuccess({mode: {type: 'NFT'}});779 await addToAllowListExpectSuccess(alice, collectionNFT, bob.address);780 await enableAllowListExpectSuccess(alice, collectionNFT);781 await enablePublicMintingExpectSuccess(alice, collectionNFT);782783 784 const targetToken = await createItemExpectSuccess(bob, collectionNFT, 'NFT');785 const targetAddress = {Ethereum: tokenIdToAddress(collectionNFT, targetToken)};786787 const collectionRFT = await createCollectionExpectSuccess({mode: {type: 'ReFungible'}});788 await setCollectionPermissionsExpectSuccess(alice, collectionNFT, {nesting: {tokenOwner: true, restricted:[collectionRFT]}});789790 791 await expect(executeTransaction(api, alice, api.tx.unique.createItem(792 collectionRFT,793 targetAddress,794 {ReFungible: {pieces: 100}},795 )), 'while creating a nested token').to.be.rejectedWith(/common\.UserIsNotAllowedToNest/);796797 798 const newToken = await createItemExpectSuccess(alice, collectionRFT, 'ReFungible');799 await expect(executeTransaction(api, alice, api.tx.unique.transfer(targetAddress, collectionRFT, newToken, 1)), 'while nesting new token').to.be.rejectedWith(/common\.UserIsNotAllowedToNest/);800 });801 });802803 it('ReFungible: disallows to nest token to an unlisted collection', async () => {804 await usingApi(async api => {805 const collectionNFT = await createCollectionExpectSuccess({mode: {type: 'NFT'}});806 await setCollectionPermissionsExpectSuccess(alice, collectionNFT, {nesting: {tokenOwner: true, restricted:[]}});807808 809 const targetToken = await createItemExpectSuccess(alice, collectionNFT, 'NFT');810 const targetAddress = {Ethereum: tokenIdToAddress(collectionNFT, targetToken)};811812 const collectionRFT = await createCollectionExpectSuccess({mode: {type: 'ReFungible'}});813814 815 await expect(executeTransaction(api, alice, api.tx.unique.createItem(816 collectionRFT,817 targetAddress,818 {ReFungible: {pieces: 100}},819 )), 'while creating a nested token').to.be.rejectedWith(/common\.SourceCollectionIsNotAllowedToNest/);820821 822 const newToken = await createItemExpectSuccess(alice, collectionRFT, 'ReFungible');823 await expect(executeTransaction(api, alice, api.tx.unique.transfer(targetAddress, collectionRFT, newToken, 1)), 'while nesting new token').to.be.rejectedWith(/common\.SourceCollectionIsNotAllowedToNest/);824 });825 });826});