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 setCollectionPermissionsExpectSuccess(alice, collection, {nesting: {collectionAdmin: true}});458459 await addToAllowListExpectSuccess(alice, collection, bob.address);460 await enableAllowListExpectSuccess(alice, collection);461 await enablePublicMintingExpectSuccess(alice, collection);462463 464 const targetToken = await createItemExpectSuccess(bob, collection, 'NFT');465 const targetAddress = {Ethereum: tokenIdToAddress(collection, targetToken).toLowerCase()};466467 468 const newToken = await createItemExpectSuccess(bob, collection, 'NFT');469 await expect(executeTransaction(470 api, 471 alice, 472 api.tx.unique.transfer(targetAddress, collection, newToken, 1),473 ), 'while nesting another\'s token token').to.be.rejectedWith(/common\.AddressNotInAllowlist/);474 expect(await getTokenOwner(api, collection, newToken)).to.be.deep.equal({Substrate: bob.address});475476 477 const nestedToken = await createItemExpectSuccess(alice, collection, 'NFT', targetAddress);478 await expect(executeTransaction(479 api, 480 alice, 481 api.tx.unique.transferFrom(targetAddress, normalizeAccountId(alice), collection, nestedToken, 1),482 ), 'while unnesting another\'s token').to.be.rejectedWith(/common\.AddressNotInAllowlist/);483 expect(await getTokenOwner(api, collection, nestedToken)).to.be.deep.equal(targetAddress);484 expect(await getTopmostTokenOwner(api, collection, nestedToken)).to.be.deep.equal({Substrate: bob.address});485 });486 });487488 it('Admin (NFT): disallows an Admin to nest a token from an unlisted collection (Restricted nesting)', async () => {489 await usingApi(async api => {490 const collectionA = await createCollectionExpectSuccess({mode: {type: 'NFT'}});491 const collectionB = await createCollectionExpectSuccess({mode: {type: 'NFT'}});492 await setCollectionPermissionsExpectSuccess(alice, collectionA, {nesting: {collectionAdmin: true, restricted:[collectionA]}});493494 495 const targetToken = await createItemExpectSuccess(alice, collectionA, 'NFT');496497 498 const newToken = await createItemExpectSuccess(alice, collectionB, 'NFT');499 await expect(executeTransaction(500 api, 501 alice, 502 api.tx.unique.transfer({Ethereum: tokenIdToAddress(collectionA, targetToken)}, collectionB, newToken, 1),503 ), 'while nesting a foreign token').to.be.rejectedWith(/common\.SourceCollectionIsNotAllowedToNest/);504 expect(await getTokenOwner(api, collectionB, newToken)).to.be.deep.equal({Substrate: alice.address});505 });506 });507508 509510 it('NFT: disallows to nest token if nesting is disabled', async () => {511 await usingApi(async api => {512 const collection = await createCollectionExpectSuccess({mode: {type: 'NFT'}});513 await setCollectionPermissionsExpectSuccess(alice, collection, {nesting: {}});514 const targetToken = await createItemExpectSuccess(alice, collection, 'NFT');515516 517 await expect(executeTransaction(api, alice, api.tx.unique.createItem(518 collection,519 {Ethereum: tokenIdToAddress(collection, targetToken)},520 {nft: {}} as any,521 )), 'while creating nested token').to.be.rejectedWith(/^common\.UserIsNotAllowedToNest$/);522523 524 const newToken = await createItemExpectSuccess(alice, collection, 'NFT');525 526 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/);527 expect(await getTopmostTokenOwner(api, collection, newToken)).to.be.deep.equal({Substrate: alice.address});528 expect(await getTokenOwner(api, collection, newToken)).to.be.deep.equal({Substrate: alice.address});529 });530 });531532 it('NFT: disallows a non-Owner to nest someone else\'s token', async () => {533 await usingApi(async api => {534 const collection = await createCollectionExpectSuccess({mode: {type: 'NFT'}});535 await setCollectionPermissionsExpectSuccess(alice, collection, {nesting: {tokenOwner: true}});536537 await addToAllowListExpectSuccess(alice, collection, bob.address);538 await enableAllowListExpectSuccess(alice, collection);539 await enablePublicMintingExpectSuccess(alice, collection);540541 542 const targetToken = await createItemExpectSuccess(bob, collection, 'NFT');543544 545 await expect(executeTransaction(api, alice, api.tx.unique.createItem(546 collection,547 {Ethereum: tokenIdToAddress(collection, targetToken)},548 {nft: {}} as any,549 )), 'while creating nested token').to.be.rejectedWith(/common\.UserIsNotAllowedToNest/);550551 552 const newToken = await createItemExpectSuccess(alice, collection, 'NFT');553 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/);554 expect(await getTokenOwner(api, collection, newToken)).to.be.deep.equal({Substrate: alice.address});555 });556 });557558 it('NFT: disallows a non-Owner to nest someone else\'s token (Restricted nesting)', async () => {559 await usingApi(async api => {560 const collection = await createCollectionExpectSuccess({mode: {type: 'NFT'}});561 await setCollectionPermissionsExpectSuccess(alice, collection, {nesting: {tokenOwner: true, restricted:[collection]}});562563 await addToAllowListExpectSuccess(alice, collection, bob.address);564 await enableAllowListExpectSuccess(alice, collection);565 await enablePublicMintingExpectSuccess(alice, collection);566567 568 const targetToken = await createItemExpectSuccess(bob, collection, 'NFT');569570 571 await expect(executeTransaction(api, alice, api.tx.unique.createItem(572 collection,573 {Ethereum: tokenIdToAddress(collection, targetToken)},574 {nft: {}} as any,575 )), 'while creating nested token').to.be.rejectedWith(/common\.UserIsNotAllowedToNest/);576577 578 const newToken = await createItemExpectSuccess(alice, collection, 'NFT');579 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/);580 expect(await getTokenOwner(api, collection, newToken)).to.be.deep.equal({Substrate: alice.address});581 });582 });583584 it('NFT: disallows to nest token in an unlisted collection', async () => {585 await usingApi(async api => {586 const collection = await createCollectionExpectSuccess({mode: {type: 'NFT'}});587 await setCollectionPermissionsExpectSuccess(alice, collection, {nesting: {tokenOwner: true, restricted:[]}});588589 590 const targetToken = await createItemExpectSuccess(alice, collection, 'NFT');591592 593 await expect(executeTransaction(api, alice, api.tx.unique.createItem(594 collection,595 {Ethereum: tokenIdToAddress(collection, targetToken)},596 {nft: {}} as any,597 )), 'while creating nested token').to.be.rejectedWith(/common\.SourceCollectionIsNotAllowedToNest/);598599 600 const newToken = await createItemExpectSuccess(alice, collection, 'NFT');601 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/);602 expect(await getTokenOwner(api, collection, newToken)).to.be.deep.equal({Substrate: alice.address});603 });604 });605606 607608 it('Fungible: disallows to nest token if nesting is disabled', async () => {609 await usingApi(async api => {610 const collectionNFT = await createCollectionExpectSuccess({mode: {type: 'NFT'}});611 await setCollectionPermissionsExpectSuccess(alice, collectionNFT, {nesting: {}});612 const targetToken = await createItemExpectSuccess(alice, collectionNFT, 'NFT');613 const targetAddress = {Ethereum: tokenIdToAddress(collectionNFT, targetToken)};614615 const collectionFT = await createCollectionExpectSuccess({mode: {type: 'Fungible', decimalPoints: 0}});616617 618 await expect(executeTransaction(api, alice, api.tx.unique.createItem(619 collectionFT,620 targetAddress,621 {Fungible: {Value: 10}},622 )), 'while creating nested token').to.be.rejectedWith(/^common\.UserIsNotAllowedToNest$/);623624 625 const newToken = await createItemExpectSuccess(alice, collectionFT, 'Fungible');626 627 await expect(executeTransaction(api, alice, api.tx.unique.transfer(targetAddress, collectionFT, newToken, 1)), 'while nesting new token').to.be.rejectedWith(/common\.UserIsNotAllowedToNest/);628629 630 const newToken2 = await createItemExpectSuccess(alice, collectionFT, 'Fungible');631 632 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/);633 });634 });635636 it('Fungible: disallows a non-Owner to nest someone else\'s token', async () => {637 await usingApi(async api => {638 const collectionNFT = await createCollectionExpectSuccess({mode: {type: 'NFT'}});639 await setCollectionPermissionsExpectSuccess(alice, collectionNFT, {nesting: {tokenOwner: true}});640641 await addToAllowListExpectSuccess(alice, collectionNFT, bob.address);642 await enableAllowListExpectSuccess(alice, collectionNFT);643 await enablePublicMintingExpectSuccess(alice, collectionNFT);644645 646 const targetToken = await createItemExpectSuccess(bob, collectionNFT, 'NFT');647 const targetAddress = {Ethereum: tokenIdToAddress(collectionNFT, targetToken)};648649 const collectionFT = await createCollectionExpectSuccess({mode: {type: 'Fungible', decimalPoints: 0}});650651 652 await expect(executeTransaction(api, alice, api.tx.unique.createItem(653 collectionFT,654 targetAddress,655 {Fungible: {Value: 10}},656 )), 'while creating nested token').to.be.rejectedWith(/common\.UserIsNotAllowedToNest/);657658 659 const newToken = await createItemExpectSuccess(alice, collectionFT, 'Fungible');660 await expect(executeTransaction(api, alice, api.tx.unique.transfer(targetAddress, collectionFT, newToken, 1)), 'while nesting new token').to.be.rejectedWith(/common\.UserIsNotAllowedToNest/);661 });662 });663664 it('Fungible: disallows a non-Owner to nest someone else\'s token (Restricted nesting)', async () => {665 await usingApi(async api => {666 const collectionNFT = await createCollectionExpectSuccess({mode: {type: 'NFT'}});667 await addToAllowListExpectSuccess(alice, collectionNFT, bob.address);668 await enableAllowListExpectSuccess(alice, collectionNFT);669 await enablePublicMintingExpectSuccess(alice, collectionNFT);670671 672 const targetToken = await createItemExpectSuccess(bob, collectionNFT, 'NFT');673 const targetAddress = {Ethereum: tokenIdToAddress(collectionNFT, targetToken)};674675 const collectionFT = await createCollectionExpectSuccess({mode: {type: 'Fungible', decimalPoints: 0}});676 await setCollectionPermissionsExpectSuccess(alice, collectionNFT, {nesting: {tokenOwner: true, restricted:[collectionFT]}});677678 679 await expect(executeTransaction(api, alice, api.tx.unique.createItem(680 collectionFT,681 targetAddress,682 {Fungible: {Value: 10}},683 )), 'while creating nested token').to.be.rejectedWith(/common\.UserIsNotAllowedToNest/);684685 686 const newToken = await createItemExpectSuccess(alice, collectionFT, 'Fungible');687 await expect(executeTransaction(api, alice, api.tx.unique.transfer(targetAddress, collectionFT, newToken, 1)), 'while nesting new token').to.be.rejectedWith(/common\.UserIsNotAllowedToNest/);688 });689 });690691 it('Fungible: disallows to nest token in an unlisted collection', async () => {692 await usingApi(async api => {693 const collectionNFT = await createCollectionExpectSuccess({mode: {type: 'NFT'}});694 await setCollectionPermissionsExpectSuccess(alice, collectionNFT, {nesting: {tokenOwner: true, restricted:[]}});695696 697 const targetToken = await createItemExpectSuccess(alice, collectionNFT, 'NFT');698 const targetAddress = {Ethereum: tokenIdToAddress(collectionNFT, targetToken)};699700 const collectionFT = await createCollectionExpectSuccess({mode: {type: 'Fungible', decimalPoints: 0}});701702 703 await expect(executeTransaction(api, alice, api.tx.unique.createItem(704 collectionFT,705 targetAddress,706 {Fungible: {Value: 10}},707 )), 'while creating a nested token').to.be.rejectedWith(/common\.SourceCollectionIsNotAllowedToNest/);708709 710 const newToken = await createItemExpectSuccess(alice, collectionFT, 'Fungible');711 await expect(executeTransaction(api, alice, api.tx.unique.transfer(targetAddress, collectionFT, newToken, 1)), 'while nesting new token').to.be.rejectedWith(/common\.SourceCollectionIsNotAllowedToNest/);712 });713 });714715 716717 it('ReFungible: disallows to nest token if nesting is disabled', async () => {718 await usingApi(async api => {719 const collectionNFT = await createCollectionExpectSuccess({mode: {type: 'NFT'}});720 await setCollectionPermissionsExpectSuccess(alice, collectionNFT, {nesting: {}});721 const targetToken = await createItemExpectSuccess(alice, collectionNFT, 'NFT');722 const targetAddress = {Ethereum: tokenIdToAddress(collectionNFT, targetToken)};723724 const collectionRFT = await createCollectionExpectSuccess({mode: {type: 'ReFungible'}});725726 727 await expect(executeTransaction(api, alice, api.tx.unique.createItem(728 collectionRFT,729 targetAddress,730 {ReFungible: {pieces: 100}},731 )), 'while creating a nested token').to.be.rejectedWith(/^common\.UserIsNotAllowedToNest$/);732733 734 const newToken = await createItemExpectSuccess(alice, collectionRFT, 'ReFungible');735 736 await transferExpectFailure(collectionRFT, newToken, alice, targetAddress, 100);737 738 await expect(executeTransaction(api, alice, api.tx.unique.transfer(targetAddress, collectionRFT, newToken, 1)), 'while nesting new token').to.be.rejectedWith(/common\.UserIsNotAllowedToNest/);739740 741 const newToken2 = await createItemExpectSuccess(alice, collectionRFT, 'ReFungible');742 743 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/);744 });745 });746747 it('ReFungible: disallows a non-Owner to nest someone else\'s token', async () => {748 await usingApi(async api => {749 const collectionNFT = await createCollectionExpectSuccess({mode: {type: 'NFT'}});750 await setCollectionPermissionsExpectSuccess(alice, collectionNFT, {nesting: {tokenOwner: true}});751752 await addToAllowListExpectSuccess(alice, collectionNFT, bob.address);753 await enableAllowListExpectSuccess(alice, collectionNFT);754 await enablePublicMintingExpectSuccess(alice, collectionNFT);755756 757 const targetToken = await createItemExpectSuccess(bob, collectionNFT, 'NFT');758 const targetAddress = {Ethereum: tokenIdToAddress(collectionNFT, targetToken)};759760 const collectionRFT = await createCollectionExpectSuccess({mode: {type: 'ReFungible'}});761762 763 await expect(executeTransaction(api, alice, api.tx.unique.createItem(764 collectionRFT,765 targetAddress,766 {ReFungible: {pieces: 100}},767 )), 'while creating a nested token').to.be.rejectedWith(/common\.UserIsNotAllowedToNest/);768769 770 const newToken = await createItemExpectSuccess(alice, collectionRFT, 'ReFungible');771 await expect(executeTransaction(api, alice, api.tx.unique.transfer(targetAddress, collectionRFT, newToken, 1)), 'while nesting new token').to.be.rejectedWith(/common\.UserIsNotAllowedToNest/);772 });773 });774775 it('ReFungible: disallows a non-Owner to nest someone else\'s token (Restricted nesting)', async () => {776 await usingApi(async api => {777 const collectionNFT = await createCollectionExpectSuccess({mode: {type: 'NFT'}});778 await addToAllowListExpectSuccess(alice, collectionNFT, bob.address);779 await enableAllowListExpectSuccess(alice, collectionNFT);780 await enablePublicMintingExpectSuccess(alice, collectionNFT);781782 783 const targetToken = await createItemExpectSuccess(bob, collectionNFT, 'NFT');784 const targetAddress = {Ethereum: tokenIdToAddress(collectionNFT, targetToken)};785786 const collectionRFT = await createCollectionExpectSuccess({mode: {type: 'ReFungible'}});787 await setCollectionPermissionsExpectSuccess(alice, collectionNFT, {nesting: {tokenOwner: true, restricted:[collectionRFT]}});788789 790 await expect(executeTransaction(api, alice, api.tx.unique.createItem(791 collectionRFT,792 targetAddress,793 {ReFungible: {pieces: 100}},794 )), 'while creating a nested token').to.be.rejectedWith(/common\.UserIsNotAllowedToNest/);795796 797 const newToken = await createItemExpectSuccess(alice, collectionRFT, 'ReFungible');798 await expect(executeTransaction(api, alice, api.tx.unique.transfer(targetAddress, collectionRFT, newToken, 1)), 'while nesting new token').to.be.rejectedWith(/common\.UserIsNotAllowedToNest/);799 });800 });801802 it('ReFungible: disallows to nest token to an unlisted collection', async () => {803 await usingApi(async api => {804 const collectionNFT = await createCollectionExpectSuccess({mode: {type: 'NFT'}});805 await setCollectionPermissionsExpectSuccess(alice, collectionNFT, {nesting: {tokenOwner: true, restricted:[]}});806807 808 const targetToken = await createItemExpectSuccess(alice, collectionNFT, 'NFT');809 const targetAddress = {Ethereum: tokenIdToAddress(collectionNFT, targetToken)};810811 const collectionRFT = await createCollectionExpectSuccess({mode: {type: 'ReFungible'}});812813 814 await expect(executeTransaction(api, alice, api.tx.unique.createItem(815 collectionRFT,816 targetAddress,817 {ReFungible: {pieces: 100}},818 )), 'while creating a nested token').to.be.rejectedWith(/common\.SourceCollectionIsNotAllowedToNest/);819820 821 const newToken = await createItemExpectSuccess(alice, collectionRFT, 'ReFungible');822 await expect(executeTransaction(api, alice, api.tx.unique.transfer(targetAddress, collectionRFT, newToken, 1)), 'while nesting new token').to.be.rejectedWith(/common\.SourceCollectionIsNotAllowedToNest/);823 });824 });825});