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