1import {expect} from 'chai';2import {tokenIdToAddress} from '../eth/util/helpers';3import usingApi, {executeTransaction} from '../substrate/substrate-api';4import {5 addCollectionAdminExpectSuccess,6 addToAllowListExpectSuccess,7 createCollectionExpectSuccess,8 createItemExpectSuccess,9 enableAllowListExpectSuccess,10 enablePublicMintingExpectSuccess,11 getTokenChildren,12 getTokenOwner,13 getTopmostTokenOwner,14 normalizeAccountId,15 setCollectionPermissionsExpectSuccess,16 transferExpectFailure,17 transferExpectSuccess,18 transferFromExpectSuccess,19} from '../util/helpers';20import {IKeyringPair} from '@polkadot/types/types';2122let alice: IKeyringPair;23let bob: IKeyringPair;24let charlie: IKeyringPair;2526describe('Integration Test: Composite nesting tests', () => {27 before(async () => {28 await usingApi(async (_, privateKeyWrapper) => {29 alice = privateKeyWrapper('//Alice');30 bob = privateKeyWrapper('//Bob');31 });32 });3334 it('Performs the full suite: bundles a token, transfers, and unnests', async () => {35 await usingApi(async api => {36 const collection = await createCollectionExpectSuccess({mode: {type: 'NFT'}});37 await setCollectionPermissionsExpectSuccess(alice, collection, {nesting: {tokenOwner: true}});38 const targetToken = await createItemExpectSuccess(alice, collection, 'NFT');3940 41 const nestedToken = await createItemExpectSuccess(alice, collection, 'NFT', {Ethereum: tokenIdToAddress(collection, targetToken)});42 expect(await getTopmostTokenOwner(api, collection, nestedToken)).to.be.deep.equal({Substrate: alice.address});43 expect(await getTokenOwner(api, collection, nestedToken)).to.be.deep.equal({Ethereum: tokenIdToAddress(collection, targetToken).toLowerCase()});4445 46 const newToken = await createItemExpectSuccess(alice, collection, 'NFT');4748 49 await transferExpectSuccess(collection, newToken, alice, {Ethereum: tokenIdToAddress(collection, targetToken)});50 expect(await getTopmostTokenOwner(api, collection, newToken)).to.be.deep.equal({Substrate: alice.address});51 expect(await getTokenOwner(api, collection, newToken)).to.be.deep.equal({Ethereum: tokenIdToAddress(collection, targetToken).toLowerCase()});5253 54 await transferExpectSuccess(collection, targetToken, alice, {Substrate: bob.address});55 expect(await getTopmostTokenOwner(api, collection, nestedToken)).to.be.deep.equal({Substrate: bob.address});56 expect(await getTokenOwner(api, collection, nestedToken)).to.be.deep.equal({Ethereum: tokenIdToAddress(collection, targetToken).toLowerCase()});5758 59 await transferFromExpectSuccess(collection, newToken, bob, {Ethereum: tokenIdToAddress(collection, targetToken)}, {Substrate: bob.address});60 expect(await getTokenOwner(api, collection, newToken)).to.be.deep.equal({Substrate: bob.address});61 });62 });6364 it('Transfers an already bundled token', async () => {65 await usingApi(async api => {66 const collection = await createCollectionExpectSuccess({mode: {type: 'NFT'}});67 await setCollectionPermissionsExpectSuccess(alice, collection, {nesting: {tokenOwner: true}});6869 const tokenA = await createItemExpectSuccess(alice, collection, 'NFT');70 const tokenB = await createItemExpectSuccess(alice, collection, 'NFT');7172 73 const tokenC = await createItemExpectSuccess(alice, collection, 'NFT', {Ethereum: tokenIdToAddress(collection, tokenA)});74 expect(await getTopmostTokenOwner(api, collection, tokenC)).to.be.deep.equal({Substrate: alice.address});75 expect(await getTokenOwner(api, collection, tokenC)).to.be.deep.equal({Ethereum: tokenIdToAddress(collection, tokenA).toLowerCase()});7677 78 await expect(executeTransaction(79 api,80 alice,81 api.tx.unique.transferFrom(82 normalizeAccountId({Ethereum: tokenIdToAddress(collection, tokenA)}),83 normalizeAccountId({Ethereum: tokenIdToAddress(collection, tokenB)}),84 collection,85 tokenC,86 1,87 ),88 )).to.not.be.rejected;89 expect(await getTopmostTokenOwner(api, collection, tokenC)).to.be.deep.equal({Substrate: alice.address});90 expect(await getTokenOwner(api, collection, tokenC)).to.be.deep.equal({Ethereum: tokenIdToAddress(collection, tokenB).toLowerCase()});91 });92 });9394 it('Checks token children', async () => {95 await usingApi(async api => {96 const collectionA = await createCollectionExpectSuccess({mode: {type: 'NFT'}});97 await setCollectionPermissionsExpectSuccess(alice, collectionA, {nesting: {tokenOwner: true}});98 const collectionB = await createCollectionExpectSuccess({mode: {type: 'Fungible', decimalPoints: 0}});99100 const targetToken = await createItemExpectSuccess(alice, collectionA, 'NFT');101 const targetAddress = {Ethereum: tokenIdToAddress(collectionA, targetToken)};102 let children = await getTokenChildren(api, collectionA, targetToken);103 expect(children.length).to.be.equal(0, 'Children length check at creation');104105 106 const tokenA = await createItemExpectSuccess(alice, collectionA, 'NFT', targetAddress);107 children = await getTokenChildren(api, collectionA, targetToken);108 expect(children.length).to.be.equal(1, 'Children length check at nesting #1');109 expect(children).to.have.deep.members([110 {token: tokenA, collection: collectionA},111 ], 'Children contents check at nesting #1');112113 114 const tokenB = await createItemExpectSuccess(alice, collectionA, 'NFT');115 await transferExpectSuccess(collectionA, tokenB, alice, targetAddress);116 children = await getTokenChildren(api, collectionA, targetToken);117 expect(children.length).to.be.equal(2, 'Children length check at nesting #2');118 expect(children).to.have.deep.members([119 {token: tokenA, collection: collectionA},120 {token: tokenB, collection: collectionA},121 ], 'Children contents check at nesting #2');122123 124 await transferExpectSuccess(collectionA, tokenB, alice, bob);125 children = await getTokenChildren(api, collectionA, targetToken);126 expect(children.length).to.be.equal(1, 'Children length check at unnesting');127 expect(children).to.be.have.deep.members([128 {token: tokenA, collection: collectionA},129 ], 'Children contents check at unnesting');130131 132 const tokenC = await createItemExpectSuccess(alice, collectionB, 'Fungible');133 await transferExpectSuccess(collectionB, tokenC, alice, targetAddress, 1, 'Fungible');134 children = await getTokenChildren(api, collectionA, targetToken);135 expect(children.length).to.be.equal(2, 'Children length check at nesting #3 (from another collection)');136 expect(children).to.be.have.deep.members([137 {token: tokenA, collection: collectionA},138 {token: tokenC, collection: collectionB},139 ], 'Children contents check at nesting #3 (from another collection)');140141 142 await transferFromExpectSuccess(collectionB, tokenC, alice, targetAddress, {Ethereum: tokenIdToAddress(collectionA, tokenA)}, 1, 'Fungible');143 children = await getTokenChildren(api, collectionA, targetToken);144 expect(children.length).to.be.equal(1, 'Children length check at deeper nesting');145 expect(children).to.be.have.deep.members([146 {token: tokenA, collection: collectionA},147 ], 'Children contents check at deeper nesting');148 });149 });150});151152describe('Integration Test: Various token type nesting', async () => {153 before(async () => {154 await usingApi(async (_, privateKeyWrapper) => {155 alice = privateKeyWrapper('//Alice');156 bob = privateKeyWrapper('//Bob');157 charlie = privateKeyWrapper('//Charlie');158 });159 });160161 it('Admin (NFT): allows an Admin to nest a token', async () => {162 await usingApi(async api => {163 const collection = await createCollectionExpectSuccess({mode: {type: 'NFT'}});164 await setCollectionPermissionsExpectSuccess(alice, collection, {nesting: {collectionAdmin: true}});165 await addCollectionAdminExpectSuccess(alice, collection, charlie.address);166 const targetToken = await createItemExpectSuccess(alice, collection, 'NFT');167168 169 const nestedToken = await createItemExpectSuccess(charlie, collection, 'NFT', {Ethereum: tokenIdToAddress(collection, targetToken)});170 expect(await getTopmostTokenOwner(api, collection, nestedToken)).to.be.deep.equal({Substrate: alice.address});171 expect(await getTokenOwner(api, collection, nestedToken)).to.be.deep.equal({Ethereum: tokenIdToAddress(collection, targetToken).toLowerCase()});172173 174 const newToken = await createItemExpectSuccess(charlie, collection, 'NFT');175 await transferExpectSuccess(collection, newToken, charlie, {Ethereum: tokenIdToAddress(collection, targetToken)});176 expect(await getTopmostTokenOwner(api, collection, newToken)).to.be.deep.equal({Substrate: alice.address});177 expect(await getTokenOwner(api, collection, newToken)).to.be.deep.equal({Ethereum: tokenIdToAddress(collection, targetToken).toLowerCase()});178 });179 });180181 it('Admin (NFT): allows an Admin to nest a token (Restricted nesting)', async () => {182 await usingApi(async api => {183 const collectionA = await createCollectionExpectSuccess({mode: {type: 'NFT'}});184 await addCollectionAdminExpectSuccess(alice, collectionA, charlie.address);185 const collectionB = await createCollectionExpectSuccess({mode: {type: 'NFT'}});186 await addCollectionAdminExpectSuccess(alice, collectionB, charlie.address);187 await setCollectionPermissionsExpectSuccess(alice, collectionA, {nesting: {collectionAdmin: true, restricted:[collectionA, collectionB]}});188 const targetToken = await createItemExpectSuccess(alice, collectionA, 'NFT');189190 191 const nestedToken = await createItemExpectSuccess(charlie, collectionB, 'NFT', {Ethereum: tokenIdToAddress(collectionA, targetToken)});192 expect(await getTopmostTokenOwner(api, collectionB, nestedToken)).to.be.deep.equal({Substrate: alice.address});193 expect(await getTokenOwner(api, collectionB, nestedToken)).to.be.deep.equal({Ethereum: tokenIdToAddress(collectionA, targetToken).toLowerCase()});194195 196 const newToken = await createItemExpectSuccess(charlie, collectionB, 'NFT');197 await transferExpectSuccess(collectionB, newToken, charlie, {Ethereum: tokenIdToAddress(collectionA, targetToken)});198 expect(await getTopmostTokenOwner(api, collectionB, newToken)).to.be.deep.equal({Substrate: alice.address});199 expect(await getTokenOwner(api, collectionB, newToken)).to.be.deep.equal({Ethereum: tokenIdToAddress(collectionA, targetToken).toLowerCase()});200 });201 });202203 204205 it('NFT: allows an Owner to nest/unnest their token', async () => {206 await usingApi(async api => {207 const collection = await createCollectionExpectSuccess({mode: {type: 'NFT'}});208 await setCollectionPermissionsExpectSuccess(alice, collection, {nesting: {tokenOwner: true}});209 const targetToken = await createItemExpectSuccess(alice, collection, 'NFT');210211 212 const nestedToken = await createItemExpectSuccess(alice, collection, 'NFT', {Ethereum: tokenIdToAddress(collection, targetToken)});213 expect(await getTopmostTokenOwner(api, collection, nestedToken)).to.be.deep.equal({Substrate: alice.address});214 expect(await getTokenOwner(api, collection, nestedToken)).to.be.deep.equal({Ethereum: tokenIdToAddress(collection, targetToken).toLowerCase()});215216 217 const newToken = await createItemExpectSuccess(alice, collection, 'NFT');218 await transferExpectSuccess(collection, newToken, alice, {Ethereum: tokenIdToAddress(collection, targetToken)});219 expect(await getTopmostTokenOwner(api, collection, newToken)).to.be.deep.equal({Substrate: alice.address});220 expect(await getTokenOwner(api, collection, newToken)).to.be.deep.equal({Ethereum: tokenIdToAddress(collection, targetToken).toLowerCase()});221 });222 });223224 it('NFT: allows an Owner to nest/unnest their token (Restricted nesting)', async () => {225 await usingApi(async api => {226 const collection = await createCollectionExpectSuccess({mode: {type: 'NFT'}});227 await setCollectionPermissionsExpectSuccess(alice, collection, {nesting: {tokenOwner: true, restricted:[collection]}});228 const targetToken = await createItemExpectSuccess(alice, collection, 'NFT');229230 231 const nestedToken = await createItemExpectSuccess(alice, collection, 'NFT', {Ethereum: tokenIdToAddress(collection, targetToken)});232 expect(await getTopmostTokenOwner(api, collection, nestedToken)).to.be.deep.equal({Substrate: alice.address});233 expect(await getTokenOwner(api, collection, nestedToken)).to.be.deep.equal({Ethereum: tokenIdToAddress(collection, targetToken).toLowerCase()});234235 236 const newToken = await createItemExpectSuccess(alice, collection, 'NFT');237 await transferExpectSuccess(collection, newToken, alice, {Ethereum: tokenIdToAddress(collection, targetToken)});238 expect(await getTopmostTokenOwner(api, collection, newToken)).to.be.deep.equal({Substrate: alice.address});239 expect(await getTokenOwner(api, collection, newToken)).to.be.deep.equal({Ethereum: tokenIdToAddress(collection, targetToken).toLowerCase()});240 });241 });242243 244245 it('Fungible: allows an Owner to nest/unnest their token', async () => {246 await usingApi(async api => {247 const collectionNFT = await createCollectionExpectSuccess({mode: {type: 'NFT'}});248 await setCollectionPermissionsExpectSuccess(alice, collectionNFT, {nesting: {tokenOwner: true}});249 const targetToken = await createItemExpectSuccess(alice, collectionNFT, 'NFT', {Substrate: alice.address});250 const targetAddress = {Ethereum: tokenIdToAddress(collectionNFT, targetToken)};251252 const collectionFT = await createCollectionExpectSuccess({mode: {type: 'Fungible', decimalPoints: 0}});253254 255 await expect(executeTransaction(api, alice, api.tx.unique.createItem(256 collectionFT,257 targetAddress,258 {Fungible: {Value: 10}},259 ))).to.not.be.rejected;260261 262 const newToken = await createItemExpectSuccess(alice, collectionFT, 'Fungible');263 await transferExpectSuccess(collectionFT, newToken, alice, targetAddress, 1, 'Fungible');264 });265 });266267 it('Fungible: allows an Owner to nest/unnest their token (Restricted nesting)', async () => {268 await usingApi(async api => {269 const collectionNFT = await createCollectionExpectSuccess({mode: {type: 'NFT'}});270 const targetToken = await createItemExpectSuccess(alice, collectionNFT, 'NFT', {Substrate: alice.address});271 const targetAddress = {Ethereum: tokenIdToAddress(collectionNFT, targetToken)};272273 const collectionFT = await createCollectionExpectSuccess({mode: {type: 'Fungible', decimalPoints: 0}});274275 await setCollectionPermissionsExpectSuccess(alice, collectionNFT, {nesting: {tokenOwner: true, restricted: [collectionFT]}});276277 278 await expect(executeTransaction(api, alice, api.tx.unique.createItem(279 collectionFT,280 targetAddress,281 {Fungible: {Value: 10}},282 ))).to.not.be.rejected;283284 285 const newToken = await createItemExpectSuccess(alice, collectionFT, 'Fungible');286 await transferExpectSuccess(collectionFT, newToken, alice, targetAddress, 1, 'Fungible');287 });288 });289290 291292 it('ReFungible: allows an Owner to nest/unnest their token', async () => {293 await usingApi(async api => {294 const collectionNFT = await createCollectionExpectSuccess({mode: {type: 'NFT'}});295 await setCollectionPermissionsExpectSuccess(alice, collectionNFT, {nesting: {tokenOwner: true}});296 const targetToken = await createItemExpectSuccess(alice, collectionNFT, 'NFT', {Substrate: alice.address});297 const targetAddress = {Ethereum: tokenIdToAddress(collectionNFT, targetToken)};298299 const collectionRFT = await createCollectionExpectSuccess({mode: {type: 'ReFungible'}});300301 302 await expect(executeTransaction(api, alice, api.tx.unique.createItem(303 collectionRFT,304 targetAddress,305 {ReFungible: {const_data: [], pieces: 100}},306 ))).to.not.be.rejected;307308 309 const newToken = await createItemExpectSuccess(alice, collectionRFT, 'ReFungible');310 await transferExpectSuccess(collectionRFT, newToken, alice, targetAddress, 100, 'ReFungible');311 });312 });313314 it('ReFungible: allows an Owner to nest/unnest their token (Restricted nesting)', async () => {315 await usingApi(async api => {316 const collectionNFT = await createCollectionExpectSuccess({mode: {type: 'NFT'}});317 const targetToken = await createItemExpectSuccess(alice, collectionNFT, 'NFT', {Substrate: alice.address});318 const targetAddress = {Ethereum: tokenIdToAddress(collectionNFT, targetToken)};319320 const collectionRFT = await createCollectionExpectSuccess({mode: {type: 'ReFungible'}});321322 await setCollectionPermissionsExpectSuccess(alice, collectionNFT, {nesting: {tokenOwner: true, restricted:[collectionRFT]}});323324 325 await expect(executeTransaction(api, alice, api.tx.unique.createItem(326 collectionRFT,327 targetAddress,328 {ReFungible: {const_data: [], pieces: 100}},329 ))).to.not.be.rejected;330331 332 const newToken = await createItemExpectSuccess(alice, collectionRFT, 'ReFungible');333 await transferExpectSuccess(collectionRFT, newToken, alice, targetAddress, 100, 'ReFungible');334 });335 });336});337338describe('Negative Test: Nesting', async() => {339 before(async () => {340 await usingApi(async (_, privateKeyWrapper) => {341 alice = privateKeyWrapper('//Alice');342 bob = privateKeyWrapper('//Bob');343 charlie = privateKeyWrapper('//Charlie');344 });345 });346347 it('Disallows excessive token nesting', async () => {348 await usingApi(async api => {349 const collection = await createCollectionExpectSuccess({mode: {type: 'NFT'}});350 await setCollectionPermissionsExpectSuccess(alice, collection, {nesting: {tokenOwner: true}});351 const targetToken = await createItemExpectSuccess(alice, collection, 'NFT');352353 const maxNestingLevel = 5;354 let prevToken = targetToken;355356 357 for (let i = 0; i < maxNestingLevel; i++) {358 const nestedToken = await createItemExpectSuccess(359 alice,360 collection,361 'NFT',362 {Ethereum: tokenIdToAddress(collection, prevToken)},363 );364365 prevToken = nestedToken;366 }367368 369 await expect(executeTransaction(api, alice, api.tx.unique.createItem(370 collection,371 {Ethereum: tokenIdToAddress(collection, prevToken)},372 {nft: {const_data: [], variable_data: []}} as any,373 )), 'while creating nested token').to.be.rejectedWith(/^structure\.DepthLimit$/);374375 expect(await getTopmostTokenOwner(api, collection, prevToken)).to.be.deep.equal({Substrate: alice.address});376 });377 });378379 380381 it('Admin (NFT): disallows an Admin to operate nesting when only TokenOwner is allowed', async () => {382 await usingApi(async api => {383 const collection = await createCollectionExpectSuccess({mode: {type: 'NFT'}});384 await setCollectionPermissionsExpectSuccess(alice, collection, {nesting: {tokenOwner: true}});385 await addCollectionAdminExpectSuccess(alice, collection, charlie.address);386 const targetToken = await createItemExpectSuccess(alice, collection, 'NFT');387388 389 await expect(executeTransaction(api, charlie, api.tx.unique.createItem(390 collection,391 {Ethereum: tokenIdToAddress(collection, targetToken)},392 {nft: {const_data: [], variable_data: []}} as any,393 )), 'while creating nested token').to.be.rejectedWith(/common\.UserIsNotAllowedToNest/);394395 396 const newToken = await createItemExpectSuccess(charlie, collection, 'NFT');397 await expect(executeTransaction(398 api, 399 charlie, 400 api.tx.unique.transfer({Ethereum: tokenIdToAddress(collection, targetToken)}, collection, newToken, 1),401 ), 'while nesting new token').to.be.rejectedWith(/common\.UserIsNotAllowedToNest/);402 expect(await getTokenOwner(api, collection, newToken)).to.be.deep.equal({Substrate: charlie.address});403 });404 });405406 it('Admin (NFT): disallows a Token Owner to operate nesting when only Admin is allowed', async () => {407 await usingApi(async api => {408 const collection = await createCollectionExpectSuccess({mode: {type: 'NFT'}});409 await setCollectionPermissionsExpectSuccess(alice, collection, {nesting: {collectionAdmin: true}});410 await addToAllowListExpectSuccess(alice, collection, charlie.address);411 await enableAllowListExpectSuccess(alice, collection);412 await enablePublicMintingExpectSuccess(alice, collection);413 const targetToken = await createItemExpectSuccess(alice, collection, 'NFT');414415 416 await expect(executeTransaction(api, charlie, api.tx.unique.createItem(417 collection,418 {Ethereum: tokenIdToAddress(collection, targetToken)},419 {nft: {const_data: [], variable_data: []}} as any,420 )), 'while creating nested token').to.be.rejectedWith(/common\.AddressNotInAllowlist/); 421422 423 const newToken = await createItemExpectSuccess(charlie, collection, 'NFT');424 await expect(executeTransaction(425 api, 426 charlie, 427 api.tx.unique.transfer({Ethereum: tokenIdToAddress(collection, targetToken)}, collection, newToken, 1),428 ), 'while nesting new token').to.be.rejectedWith(/common\.AddressNotInAllowlist/);429 expect(await getTokenOwner(api, collection, newToken)).to.be.deep.equal({Substrate: charlie.address});430 });431 });432433 it('Admin (NFT): disallows an Admin to nest and unnest someone else\'s token', async () => {434 await usingApi(async api => {435 const collection = await createCollectionExpectSuccess({mode: {type: 'NFT'}});436 await setCollectionPermissionsExpectSuccess(alice, collection, {nesting: {collectionAdmin: true}});437438 await addToAllowListExpectSuccess(alice, collection, charlie.address);439 await enableAllowListExpectSuccess(alice, collection);440 await enablePublicMintingExpectSuccess(alice, collection);441442 443 const targetToken = await createItemExpectSuccess(charlie, collection, 'NFT');444 const targetAddress = {Ethereum: tokenIdToAddress(collection, targetToken).toLowerCase()};445446 447 const newToken = await createItemExpectSuccess(charlie, collection, 'NFT');448 await expect(executeTransaction(449 api, 450 alice, 451 api.tx.unique.transfer(targetAddress, collection, newToken, 1),452 ), 'while nesting another\'s token token').to.be.rejectedWith(/common\.AddressNotInAllowlist/);453 expect(await getTokenOwner(api, collection, newToken)).to.be.deep.equal({Substrate: charlie.address});454455 456 const nestedToken = await createItemExpectSuccess(alice, collection, 'NFT', targetAddress);457 await expect(executeTransaction(458 api, 459 alice, 460 api.tx.unique.transferFrom(targetAddress, normalizeAccountId(alice), collection, nestedToken, 1),461 ), 'while unnesting another\'s token').to.be.rejectedWith(/common\.AddressNotInAllowlist/);462 expect(await getTokenOwner(api, collection, nestedToken)).to.be.deep.equal(targetAddress);463 expect(await getTopmostTokenOwner(api, collection, nestedToken)).to.be.deep.equal({Substrate: charlie.address});464 });465 });466467 it('Admin (NFT): disallows an Admin to nest a token from an unlisted collection (Restricted nesting)', async () => {468 await usingApi(async api => {469 const collectionA = await createCollectionExpectSuccess({mode: {type: 'NFT'}});470 const collectionB = await createCollectionExpectSuccess({mode: {type: 'NFT'}});471 await setCollectionPermissionsExpectSuccess(alice, collectionA, {nesting: {collectionAdmin: true, restricted:[collectionA]}});472473 474 const targetToken = await createItemExpectSuccess(alice, collectionA, 'NFT');475476 477 const newToken = await createItemExpectSuccess(alice, collectionB, 'NFT');478 await expect(executeTransaction(479 api, 480 alice, 481 api.tx.unique.transfer({Ethereum: tokenIdToAddress(collectionA, targetToken)}, collectionB, newToken, 1),482 ), 'while nesting a foreign token').to.be.rejectedWith(/common\.SourceCollectionIsNotAllowedToNest/);483 expect(await getTokenOwner(api, collectionB, newToken)).to.be.deep.equal({Substrate: alice.address});484 });485 });486487 488489 it('NFT: disallows to nest token if nesting is disabled', async () => {490 await usingApi(async api => {491 const collection = await createCollectionExpectSuccess({mode: {type: 'NFT'}});492 await setCollectionPermissionsExpectSuccess(alice, collection, {nesting: {}});493 const targetToken = await createItemExpectSuccess(alice, collection, 'NFT');494495 496 await expect(executeTransaction(api, alice, api.tx.unique.createItem(497 collection,498 {Ethereum: tokenIdToAddress(collection, targetToken)},499 {nft: {const_data: [], variable_data: []}} as any,500 )), 'while creating nested token').to.be.rejectedWith(/^common\.UserIsNotAllowedToNest$/);501502 503 const newToken = await createItemExpectSuccess(alice, collection, 'NFT');504 505 await expect(executeTransaction(api, alice, api.tx.unique.transfer({Ethereum: tokenIdToAddress(collection, targetToken)}, collection, newToken, 1)), 'while nesting new token').to.be.rejectedWith(/common\.UserIsNotAllowedToNest/);506 expect(await getTopmostTokenOwner(api, collection, newToken)).to.be.deep.equal({Substrate: alice.address});507 expect(await getTokenOwner(api, collection, newToken)).to.be.deep.equal({Substrate: alice.address});508 });509 });510511 it('NFT: disallows a non-Owner to nest someone else\'s token', async () => {512 await usingApi(async api => {513 const collection = await createCollectionExpectSuccess({mode: {type: 'NFT'}});514 await setCollectionPermissionsExpectSuccess(alice, collection, {nesting: {tokenOwner: true}});515516 await addToAllowListExpectSuccess(alice, collection, bob.address);517 await enableAllowListExpectSuccess(alice, collection);518 await enablePublicMintingExpectSuccess(alice, collection);519520 521 const targetToken = await createItemExpectSuccess(bob, collection, 'NFT');522523 524 await expect(executeTransaction(api, alice, api.tx.unique.createItem(525 collection,526 {Ethereum: tokenIdToAddress(collection, targetToken)},527 {nft: {const_data: [], variable_data: []}} as any,528 )), 'while creating nested token').to.be.rejectedWith(/common\.UserIsNotAllowedToNest/);529530 531 const newToken = await createItemExpectSuccess(alice, collection, 'NFT');532 await expect(executeTransaction(api, alice, api.tx.unique.transfer({Ethereum: tokenIdToAddress(collection, targetToken)}, collection, newToken, 1)), 'while nesting new token').to.be.rejectedWith(/common\.AddressNotInAllowlist/);533 expect(await getTokenOwner(api, collection, newToken)).to.be.deep.equal({Substrate: alice.address});534 });535 });536537 it('NFT: disallows a non-Owner to nest someone else\'s token (Restricted nesting)', async () => {538 await usingApi(async api => {539 const collection = await createCollectionExpectSuccess({mode: {type: 'NFT'}});540 await setCollectionPermissionsExpectSuccess(alice, collection, {nesting: {tokenOwner: true, restricted:[collection]}});541542 await addToAllowListExpectSuccess(alice, collection, bob.address);543 await enableAllowListExpectSuccess(alice, collection);544 await enablePublicMintingExpectSuccess(alice, collection);545546 547 const targetToken = await createItemExpectSuccess(bob, collection, 'NFT');548549 550 await expect(executeTransaction(api, alice, api.tx.unique.createItem(551 collection,552 {Ethereum: tokenIdToAddress(collection, targetToken)},553 {nft: {const_data: [], variable_data: []}} as any,554 )), 'while creating nested token').to.be.rejectedWith(/common\.UserIsNotAllowedToNest/);555556 557 const newToken = await createItemExpectSuccess(alice, collection, 'NFT');558 await expect(executeTransaction(api, alice, api.tx.unique.transfer({Ethereum: tokenIdToAddress(collection, targetToken)}, collection, newToken, 1)), 'while nesting new token').to.be.rejectedWith(/common\.AddressNotInAllowlist/);559 expect(await getTokenOwner(api, collection, newToken)).to.be.deep.equal({Substrate: alice.address});560 });561 });562563 it('NFT: disallows to nest token in an unlisted collection', async () => {564 await usingApi(async api => {565 const collection = await createCollectionExpectSuccess({mode: {type: 'NFT'}});566 await setCollectionPermissionsExpectSuccess(alice, collection, {nesting: {tokenOwner: true, restricted:[]}});567568 569 const targetToken = await createItemExpectSuccess(alice, collection, 'NFT');570571 572 await expect(executeTransaction(api, alice, api.tx.unique.createItem(573 collection,574 {Ethereum: tokenIdToAddress(collection, targetToken)},575 {nft: {const_data: [], variable_data: []}} as any,576 )), 'while creating nested token').to.be.rejectedWith(/common\.SourceCollectionIsNotAllowedToNest/);577578 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\.SourceCollectionIsNotAllowedToNest/);581 expect(await getTokenOwner(api, collection, newToken)).to.be.deep.equal({Substrate: alice.address});582 });583 });584585 586587 it('Fungible: disallows to nest token if nesting is disabled', async () => {588 await usingApi(async api => {589 const collectionNFT = await createCollectionExpectSuccess({mode: {type: 'NFT'}});590 await setCollectionPermissionsExpectSuccess(alice, collectionNFT, {nesting: {}});591 const targetToken = await createItemExpectSuccess(alice, collectionNFT, 'NFT');592 const targetAddress = {Ethereum: tokenIdToAddress(collectionNFT, targetToken)};593594 const collectionFT = await createCollectionExpectSuccess({mode: {type: 'Fungible', decimalPoints: 0}});595596 597 await expect(executeTransaction(api, alice, api.tx.unique.createItem(598 collectionFT,599 targetAddress,600 {Fungible: {Value: 10}},601 )), 'while creating nested token').to.be.rejectedWith(/^common\.UserIsNotAllowedToNest$/);602603 604 const newToken = await createItemExpectSuccess(alice, collectionFT, 'Fungible');605 606 await expect(executeTransaction(api, alice, api.tx.unique.transfer(targetAddress, collectionFT, newToken, 1)), 'while nesting new token').to.be.rejectedWith(/common\.UserIsNotAllowedToNest/);607608 609 const newToken2 = await createItemExpectSuccess(alice, collectionFT, 'Fungible');610 611 await expect(executeTransaction(api, alice, api.tx.unique.transfer({Ethereum: tokenIdToAddress(collectionFT, newToken)}, collectionFT, newToken2, 1)), 'while nesting new token inside fungible').to.be.rejectedWith(/fungible\.FungibleDisallowsNesting/);612 });613 });614615 it('Fungible: disallows a non-Owner to nest someone else\'s token', async () => {616 await usingApi(async api => {617 const collectionNFT = await createCollectionExpectSuccess({mode: {type: 'NFT'}});618 await setCollectionPermissionsExpectSuccess(alice, collectionNFT, {nesting: {tokenOwner: true}});619620 await addToAllowListExpectSuccess(alice, collectionNFT, bob.address);621 await enableAllowListExpectSuccess(alice, collectionNFT);622 await enablePublicMintingExpectSuccess(alice, collectionNFT);623624 625 const targetToken = await createItemExpectSuccess(bob, collectionNFT, 'NFT');626 const targetAddress = {Ethereum: tokenIdToAddress(collectionNFT, targetToken)};627628 const collectionFT = await createCollectionExpectSuccess({mode: {type: 'Fungible', decimalPoints: 0}});629630 631 await expect(executeTransaction(api, alice, api.tx.unique.createItem(632 collectionFT,633 targetAddress,634 {Fungible: {Value: 10}},635 )), 'while creating nested token').to.be.rejectedWith(/common\.UserIsNotAllowedToNest/);636637 638 const newToken = await createItemExpectSuccess(alice, collectionFT, 'Fungible');639 await expect(executeTransaction(api, alice, api.tx.unique.transfer(targetAddress, collectionFT, newToken, 1)), 'while nesting new token').to.be.rejectedWith(/common\.UserIsNotAllowedToNest/);640 });641 });642643 it('Fungible: disallows a non-Owner to nest someone else\'s token (Restricted nesting)', async () => {644 await usingApi(async api => {645 const collectionNFT = await createCollectionExpectSuccess({mode: {type: 'NFT'}});646 await addToAllowListExpectSuccess(alice, collectionNFT, bob.address);647 await enableAllowListExpectSuccess(alice, collectionNFT);648 await enablePublicMintingExpectSuccess(alice, collectionNFT);649650 651 const targetToken = await createItemExpectSuccess(bob, collectionNFT, 'NFT');652 const targetAddress = {Ethereum: tokenIdToAddress(collectionNFT, targetToken)};653654 const collectionFT = await createCollectionExpectSuccess({mode: {type: 'Fungible', decimalPoints: 0}});655 await setCollectionPermissionsExpectSuccess(alice, collectionNFT, {nesting: {tokenOwner: true, restricted:[collectionFT]}});656657 658 await expect(executeTransaction(api, alice, api.tx.unique.createItem(659 collectionFT,660 targetAddress,661 {Fungible: {Value: 10}},662 )), 'while creating nested token').to.be.rejectedWith(/common\.UserIsNotAllowedToNest/);663664 665 const newToken = await createItemExpectSuccess(alice, collectionFT, 'Fungible');666 await expect(executeTransaction(api, alice, api.tx.unique.transfer(targetAddress, collectionFT, newToken, 1)), 'while nesting new token').to.be.rejectedWith(/common\.UserIsNotAllowedToNest/);667 });668 });669670 it('Fungible: disallows to nest token in an unlisted collection', async () => {671 await usingApi(async api => {672 const collectionNFT = await createCollectionExpectSuccess({mode: {type: 'NFT'}});673 await setCollectionPermissionsExpectSuccess(alice, collectionNFT, {nesting: {tokenOwner: true, restricted:[]}});674675 676 const targetToken = await createItemExpectSuccess(alice, collectionNFT, 'NFT');677 const targetAddress = {Ethereum: tokenIdToAddress(collectionNFT, targetToken)};678679 const collectionFT = await createCollectionExpectSuccess({mode: {type: 'Fungible', decimalPoints: 0}});680681 682 await expect(executeTransaction(api, alice, api.tx.unique.createItem(683 collectionFT,684 targetAddress,685 {Fungible: {Value: 10}},686 )), 'while creating a nested token').to.be.rejectedWith(/common\.SourceCollectionIsNotAllowedToNest/);687688 689 const newToken = await createItemExpectSuccess(alice, collectionFT, 'Fungible');690 await expect(executeTransaction(api, alice, api.tx.unique.transfer(targetAddress, collectionFT, newToken, 1)), 'while nesting new token').to.be.rejectedWith(/common\.SourceCollectionIsNotAllowedToNest/);691 });692 });693694 695696 it('ReFungible: disallows to nest token if nesting is disabled', async () => {697 await usingApi(async api => {698 const collectionNFT = await createCollectionExpectSuccess({mode: {type: 'NFT'}});699 await setCollectionPermissionsExpectSuccess(alice, collectionNFT, {nesting: {}});700 const targetToken = await createItemExpectSuccess(alice, collectionNFT, 'NFT');701 const targetAddress = {Ethereum: tokenIdToAddress(collectionNFT, targetToken)};702703 const collectionRFT = await createCollectionExpectSuccess({mode: {type: 'ReFungible'}});704705 706 await expect(executeTransaction(api, alice, api.tx.unique.createItem(707 collectionRFT,708 targetAddress,709 {ReFungible: {const_data: [], pieces: 100}},710 )), 'while creating a nested token').to.be.rejectedWith(/^common\.UserIsNotAllowedToNest$/);711712 713 const newToken = await createItemExpectSuccess(alice, collectionRFT, 'ReFungible');714 715 await transferExpectFailure(collectionRFT, newToken, alice, targetAddress, 100);716 717 await expect(executeTransaction(api, alice, api.tx.unique.transfer(targetAddress, collectionRFT, newToken, 1)), 'while nesting new token').to.be.rejectedWith(/common\.UserIsNotAllowedToNest/);718719 720 const newToken2 = await createItemExpectSuccess(alice, collectionRFT, 'ReFungible');721 722 await expect(executeTransaction(api, alice, api.tx.unique.transfer({Ethereum: tokenIdToAddress(collectionRFT, newToken)}, collectionRFT, newToken2, 1)), 'while nesting new token inside refungible').to.be.rejectedWith(/refungible\.RefungibleDisallowsNesting/);723 });724 });725726 it('ReFungible: disallows a non-Owner to nest someone else\'s token', async () => {727 await usingApi(async api => {728 const collectionNFT = await createCollectionExpectSuccess({mode: {type: 'NFT'}});729 await setCollectionPermissionsExpectSuccess(alice, collectionNFT, {nesting: {tokenOwner: true}});730731 await addToAllowListExpectSuccess(alice, collectionNFT, bob.address);732 await enableAllowListExpectSuccess(alice, collectionNFT);733 await enablePublicMintingExpectSuccess(alice, collectionNFT);734735 736 const targetToken = await createItemExpectSuccess(bob, collectionNFT, 'NFT');737 const targetAddress = {Ethereum: tokenIdToAddress(collectionNFT, targetToken)};738739 const collectionRFT = await createCollectionExpectSuccess({mode: {type: 'ReFungible'}});740741 742 await expect(executeTransaction(api, alice, api.tx.unique.createItem(743 collectionRFT,744 targetAddress,745 {ReFungible: {const_data: [], pieces: 100}},746 )), 'while creating a nested token').to.be.rejectedWith(/common\.UserIsNotAllowedToNest/);747748 749 const newToken = await createItemExpectSuccess(alice, collectionRFT, 'ReFungible');750 await expect(executeTransaction(api, alice, api.tx.unique.transfer(targetAddress, collectionRFT, newToken, 1)), 'while nesting new token').to.be.rejectedWith(/common\.UserIsNotAllowedToNest/);751 });752 });753754 it('ReFungible: disallows a non-Owner to nest someone else\'s token (Restricted nesting)', async () => {755 await usingApi(async api => {756 const collectionNFT = await createCollectionExpectSuccess({mode: {type: 'NFT'}});757 await addToAllowListExpectSuccess(alice, collectionNFT, bob.address);758 await enableAllowListExpectSuccess(alice, collectionNFT);759 await enablePublicMintingExpectSuccess(alice, collectionNFT);760761 762 const targetToken = await createItemExpectSuccess(bob, collectionNFT, 'NFT');763 const targetAddress = {Ethereum: tokenIdToAddress(collectionNFT, targetToken)};764765 const collectionRFT = await createCollectionExpectSuccess({mode: {type: 'ReFungible'}});766 await setCollectionPermissionsExpectSuccess(alice, collectionNFT, {nesting: {tokenOwner: true, restricted:[collectionRFT]}});767768 769 await expect(executeTransaction(api, alice, api.tx.unique.createItem(770 collectionRFT,771 targetAddress,772 {ReFungible: {const_data: [], pieces: 100}},773 )), 'while creating a nested token').to.be.rejectedWith(/common\.UserIsNotAllowedToNest/);774775 776 const newToken = await createItemExpectSuccess(alice, collectionRFT, 'ReFungible');777 await expect(executeTransaction(api, alice, api.tx.unique.transfer(targetAddress, collectionRFT, newToken, 1)), 'while nesting new token').to.be.rejectedWith(/common\.UserIsNotAllowedToNest/);778 });779 });780781 it('ReFungible: disallows to nest token to an unlisted collection', async () => {782 await usingApi(async api => {783 const collectionNFT = await createCollectionExpectSuccess({mode: {type: 'NFT'}});784 await setCollectionPermissionsExpectSuccess(alice, collectionNFT, {nesting: {tokenOwner: true, restricted:[]}});785786 787 const targetToken = await createItemExpectSuccess(alice, collectionNFT, 'NFT');788 const targetAddress = {Ethereum: tokenIdToAddress(collectionNFT, targetToken)};789790 const collectionRFT = await createCollectionExpectSuccess({mode: {type: 'ReFungible'}});791792 793 await expect(executeTransaction(api, alice, api.tx.unique.createItem(794 collectionRFT,795 targetAddress,796 {ReFungible: {const_data: [], pieces: 100}},797 )), 'while creating a nested token').to.be.rejectedWith(/common\.SourceCollectionIsNotAllowedToNest/);798799 800 const newToken = await createItemExpectSuccess(alice, collectionRFT, 'ReFungible');801 await expect(executeTransaction(api, alice, api.tx.unique.transfer(targetAddress, collectionRFT, newToken, 1)), 'while nesting new token').to.be.rejectedWith(/common\.SourceCollectionIsNotAllowedToNest/);802 });803 });804});