1import {expect} from 'chai';2import {tokenIdToAddress} from '../eth/util/helpers';3import privateKey from '../substrate/privateKey';4import usingApi, {executeTransaction} from '../substrate/substrate-api';5import {6 addToAllowListExpectSuccess,7 createCollectionExpectSuccess,8 createItemExpectFailure, 9 createItemExpectSuccess,10 enableAllowListExpectSuccess,11 enablePublicMintingExpectSuccess,12 getTokenOwner, 13 getTopmostTokenOwner, 14 setCollectionLimitsExpectSuccess, 15 transferExpectFailure, 16 transferExpectSuccess, 17 transferFromExpectSuccess,18} from '../util/helpers';19import {IKeyringPair} from '@polkadot/types/types';2021let alice: IKeyringPair;22let bob: IKeyringPair;2324describe('Integration Test: Nesting', () => {25 before(async () => {26 await usingApi(async api => {27 alice = privateKey('//Alice');28 bob = privateKey('//Bob');29 });30 });3132 3334 35 36 it('NFT: allows to nest/unnest token if nesting rule is Owner', async () => {37 await usingApi(async api => {38 const collection = await createCollectionExpectSuccess({mode: {type: 'NFT'}});39 await setCollectionLimitsExpectSuccess(alice, collection, {nestingRule: 'Owner'});40 const targetToken = await createItemExpectSuccess(alice, collection, 'NFT');4142 43 const nestedToken = await createItemExpectSuccess(alice, collection, 'NFT', {Ethereum: tokenIdToAddress(collection, targetToken)});44 expect(await getTopmostTokenOwner(api, collection, nestedToken)).to.be.deep.equal({Substrate: alice.address});45 expect(await getTokenOwner(api, collection, nestedToken)).to.be.deep.equal({Ethereum: tokenIdToAddress(collection, targetToken).toLowerCase()});4647 48 const newToken = await createItemExpectSuccess(alice, collection, 'NFT');49 50 51 await transferExpectSuccess(collection, newToken, alice, {Ethereum: tokenIdToAddress(collection, targetToken)});52 expect(await getTopmostTokenOwner(api, collection, nestedToken)).to.be.deep.equal({Substrate: alice.address});53 expect(await getTokenOwner(api, collection, nestedToken)).to.be.deep.equal({Ethereum: tokenIdToAddress(collection, targetToken).toLowerCase()});5455 56 await transferExpectSuccess(collection, targetToken, alice, {Substrate: bob.address});57 expect(await getTopmostTokenOwner(api, collection, nestedToken)).to.be.deep.equal({Substrate: bob.address});58 expect(await getTokenOwner(api, collection, nestedToken)).to.be.deep.equal({Ethereum: tokenIdToAddress(collection, targetToken).toLowerCase()});5960 61 await transferFromExpectSuccess(collection, newToken, bob, {Ethereum: tokenIdToAddress(collection, targetToken)}, {Substrate: bob.address});62 expect(await getTokenOwner(api, collection, newToken)).to.be.deep.equal({Substrate: bob.address});63 });64 });6566 it('NFT: allows to nest/unnest token if Owner-Restricted', async () => {67 await usingApi(async api => {68 const collection = await createCollectionExpectSuccess({mode: {type: 'NFT'}});69 await setCollectionLimitsExpectSuccess(alice, collection, {nestingRule: {OwnerRestricted:[collection]}});70 const targetToken = await createItemExpectSuccess(alice, collection, 'NFT');7172 73 const nestedToken = await createItemExpectSuccess(alice, collection, 'NFT', {Ethereum: tokenIdToAddress(collection, targetToken)});74 expect(await getTopmostTokenOwner(api, collection, nestedToken)).to.be.deep.equal({Substrate: alice.address});75 expect(await getTokenOwner(api, collection, nestedToken)).to.be.deep.equal({Ethereum: tokenIdToAddress(collection, targetToken).toLowerCase()});7677 78 const newToken = await createItemExpectSuccess(alice, collection, 'NFT');79 80 81 await transferExpectSuccess(collection, newToken, alice, {Ethereum: tokenIdToAddress(collection, targetToken)});82 expect(await getTopmostTokenOwner(api, collection, nestedToken)).to.be.deep.equal({Substrate: alice.address});83 expect(await getTokenOwner(api, collection, nestedToken)).to.be.deep.equal({Ethereum: tokenIdToAddress(collection, targetToken).toLowerCase()});8485 86 await transferExpectSuccess(collection, targetToken, alice, {Substrate: bob.address});87 expect(await getTopmostTokenOwner(api, collection, nestedToken)).to.be.deep.equal({Substrate: bob.address});88 expect(await getTokenOwner(api, collection, nestedToken)).to.be.deep.equal({Ethereum: tokenIdToAddress(collection, targetToken).toLowerCase()});89 90 91 await transferFromExpectSuccess(collection, newToken, bob, {Ethereum: tokenIdToAddress(collection, targetToken)}, {Substrate: bob.address});92 expect(await getTokenOwner(api, collection, newToken)).to.be.deep.equal({Substrate: bob.address});93 });94 });9596 9798 it('Fungible: allows to nest/unnest token if Owner', async () => {99 await usingApi(async api => {100 const collectionNFT = await createCollectionExpectSuccess({mode: {type: 'NFT'}});101 await setCollectionLimitsExpectSuccess(alice, collectionNFT, {nestingRule: 'Owner'});102 const targetToken = await createItemExpectSuccess(alice, collectionNFT, 'NFT', {Substrate: alice.address});103 const targetAddress = {Ethereum: tokenIdToAddress(collectionNFT, targetToken)};104105 const collectionFT = await createCollectionExpectSuccess({mode: {type: 'Fungible', decimalPoints: 0}});106107 108 await expect(executeTransaction(api, alice, api.tx.unique.createItem(109 collectionFT, 110 targetAddress, 111 {Fungible: {Value: 10}},112 ))).to.not.be.rejected;113114 115 const newToken = await createItemExpectSuccess(alice, collectionFT, 'Fungible');116 117 await transferExpectSuccess(collectionFT, newToken, alice, targetAddress, 1, 'Fungible');118 119 await transferExpectSuccess(collectionNFT, targetToken, alice, {Substrate: bob.address});120 121 await transferFromExpectSuccess(collectionFT, newToken, bob, targetAddress, {Substrate: bob.address}, 1, 'Fungible');122 });123 });124125 it('Fungible: allows to nest/unnest token if Owner-Restricted', async () => {126 await usingApi(async api => {127 const collectionNFT = await createCollectionExpectSuccess({mode: {type: 'NFT'}});128 const targetToken = await createItemExpectSuccess(alice, collectionNFT, 'NFT', {Substrate: alice.address});129 const targetAddress = {Ethereum: tokenIdToAddress(collectionNFT, targetToken)};130131 const collectionFT = await createCollectionExpectSuccess({mode: {type: 'Fungible', decimalPoints: 0}});132133 await setCollectionLimitsExpectSuccess(alice, collectionNFT, {nestingRule: {OwnerRestricted:[collectionFT]}});134135 136 await expect(executeTransaction(api, alice, api.tx.unique.createItem(137 collectionFT, 138 targetAddress, 139 {Fungible: {Value: 10}},140 ))).to.not.be.rejected;141142 143 const newToken = await createItemExpectSuccess(alice, collectionFT, 'Fungible');144 145 await transferExpectSuccess(collectionFT, newToken, alice, targetAddress, 1, 'Fungible');146 147 await transferExpectSuccess(collectionNFT, targetToken, alice, {Substrate: bob.address});148 149 await transferFromExpectSuccess(collectionFT, newToken, bob, targetAddress, {Substrate: bob.address}, 1, 'Fungible');150 });151 });152153 154155 it('ReFungible: allows to nest/unnest token if Owner', async () => {156 await usingApi(async api => {157 const collectionNFT = await createCollectionExpectSuccess({mode: {type: 'NFT'}});158 await setCollectionLimitsExpectSuccess(alice, collectionNFT, {nestingRule: 'Owner'});159 const targetToken = await createItemExpectSuccess(alice, collectionNFT, 'NFT', {Substrate: alice.address});160 const targetAddress = {Ethereum: tokenIdToAddress(collectionNFT, targetToken)};161162 const collectionRFT = await createCollectionExpectSuccess({mode: {type: 'ReFungible'}});163164 165 await expect(executeTransaction(api, alice, api.tx.unique.createItem(166 collectionRFT, 167 targetAddress, 168 {ReFungible: {const_data: [], variable_data: [], pieces: 100}},169 ))).to.not.be.rejected;170171 172 const newToken = await createItemExpectSuccess(alice, collectionRFT, 'ReFungible');173 174 await transferExpectSuccess(collectionRFT, newToken, alice, targetAddress, 100, 'ReFungible');175 176 await transferExpectSuccess(collectionNFT, targetToken, alice, {Substrate: bob.address});177 178 await transferFromExpectSuccess(collectionRFT, newToken, bob, targetAddress, {Substrate: bob.address}, 100, 'ReFungible');179 });180 });181182 it('ReFungible: allows to nest/unnest token if Owner-Restricted', async () => {183 await usingApi(async api => {184 const collectionNFT = await createCollectionExpectSuccess({mode: {type: 'NFT'}});185 const targetToken = await createItemExpectSuccess(alice, collectionNFT, 'NFT', {Substrate: alice.address});186 const targetAddress = {Ethereum: tokenIdToAddress(collectionNFT, targetToken)};187188 const collectionRFT = await createCollectionExpectSuccess({mode: {type: 'ReFungible'}});189190 await setCollectionLimitsExpectSuccess(alice, collectionNFT, {nestingRule: {OwnerRestricted:[collectionRFT]}});191192 193 await expect(executeTransaction(api, alice, api.tx.unique.createItem(194 collectionRFT, 195 targetAddress,196 {ReFungible: {const_data: [], variable_data: [], pieces: 100}},197 ))).to.not.be.rejected;198199 200 const newToken = await createItemExpectSuccess(alice, collectionRFT, 'ReFungible');201 202 await transferExpectSuccess(collectionRFT, newToken, alice, targetAddress, 100, 'ReFungible');203 204 await transferExpectSuccess(collectionNFT, targetToken, alice, {Substrate: bob.address});205 206 await transferFromExpectSuccess(collectionRFT, newToken, bob, targetAddress, {Substrate: bob.address}, 100, 'ReFungible');207 });208 });209});210211describe('Negative Test: Nesting', async() => {212 before(async () => {213 await usingApi(async api => {214 alice = privateKey('//Alice');215 bob = privateKey('//Bob');216 });217 });218219 220221 it('NFT: disallows to nest token if nesting is disabled', async () => {222 await usingApi(async api => {223 const collection = await createCollectionExpectSuccess({mode: {type: 'NFT'}});224 await setCollectionLimitsExpectSuccess(alice, collection, {nestingRule: 'Disabled'});225 const targetToken = await createItemExpectSuccess(alice, collection, 'NFT');226227 228 await expect(executeTransaction(api, alice, api.tx.unique.createItem(229 collection, 230 {Ethereum: tokenIdToAddress(collection, targetToken)}, 231 {nft: {const_data: [], variable_data: []}} as any,232 ))).to.be.rejectedWith(/^common\.NestingIsDisabled$/);233234 235 const newToken = await createItemExpectSuccess(alice, collection, 'NFT');236 237 await transferExpectFailure(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({Substrate: alice.address});240 });241 });242243 it('NFT: disallows to nest token if not Owner', async () => {244 await usingApi(async api => {245 const collection = await createCollectionExpectSuccess({mode: {type: 'NFT'}});246 await setCollectionLimitsExpectSuccess(alice, collection, {nestingRule: 'Owner'});247248 await addToAllowListExpectSuccess(alice, collection, bob.address);249 await enableAllowListExpectSuccess(alice, collection);250 await enablePublicMintingExpectSuccess(alice, collection);251252 253 const targetToken = await createItemExpectSuccess(bob, collection, 'NFT');254255 256 await createItemExpectFailure(alice, collection, 'NFT', {Ethereum: tokenIdToAddress(collection, targetToken)});257258 259 const newToken = await createItemExpectSuccess(alice, collection, 'NFT');260 await transferExpectFailure(collection, newToken, alice, {Ethereum: tokenIdToAddress(collection, targetToken)});261 expect(await getTokenOwner(api, collection, newToken)).to.be.deep.equal({Substrate: alice.address});262 });263 });264265 it('NFT: disallows to nest token if not Owner (Restricted nesting)', async () => {266 await usingApi(async api => {267 const collection = await createCollectionExpectSuccess({mode: {type: 'NFT'}});268 await setCollectionLimitsExpectSuccess(alice, collection, {nestingRule: {OwnerRestricted:[collection]}});269270 await addToAllowListExpectSuccess(alice, collection, bob.address);271 await enableAllowListExpectSuccess(alice, collection);272 await enablePublicMintingExpectSuccess(alice, collection);273274 275 const targetToken = await createItemExpectSuccess(bob, collection, 'NFT');276277 278 await createItemExpectFailure(alice, collection, 'NFT', {Ethereum: tokenIdToAddress(collection, targetToken)});279280 281 const newToken = await createItemExpectSuccess(alice, collection, 'NFT');282 await transferExpectFailure(collection, newToken, alice, {Ethereum: tokenIdToAddress(collection, targetToken)});283 expect(await getTokenOwner(api, collection, newToken)).to.be.deep.equal({Substrate: alice.address});284 });285 });286287 it('NFT: disallows to nest token to an unlisted collection', async () => {288 await usingApi(async api => {289 const collection = await createCollectionExpectSuccess({mode: {type: 'NFT'}});290 await setCollectionLimitsExpectSuccess(alice, collection, {nestingRule: {OwnerRestricted:[]}});291292 293 const targetToken = await createItemExpectSuccess(alice, collection, 'NFT');294295 296 await createItemExpectFailure(alice, collection, 'NFT', {Ethereum: tokenIdToAddress(collection, targetToken)});297298 299 const newToken = await createItemExpectSuccess(alice, collection, 'NFT');300 await transferExpectFailure(collection, newToken, alice, {Ethereum: tokenIdToAddress(collection, targetToken)});301 expect(await getTokenOwner(api, collection, newToken)).to.be.deep.equal({Substrate: alice.address});302 });303 });304305 306307 it('Fungible: disallows to nest token if nesting is disabled', async () => {308 await usingApi(async api => {309 const collectionNFT = await createCollectionExpectSuccess({mode: {type: 'NFT'}});310 await setCollectionLimitsExpectSuccess(alice, collectionNFT, {nestingRule: 'Disabled'});311 const targetToken = await createItemExpectSuccess(alice, collectionNFT, 'NFT');312 const targetAddress = {Ethereum: tokenIdToAddress(collectionNFT, targetToken)};313314 const collectionFT = await createCollectionExpectSuccess({mode: {type: 'Fungible', decimalPoints: 0}});315316 317 await expect(executeTransaction(api, alice, api.tx.unique.createItem(318 collectionFT, 319 targetAddress, 320 {Fungible: {Value: 10}},321 ))).to.be.rejectedWith(/^common\.NestingIsDisabled$/);322323 324 const newToken = await createItemExpectSuccess(alice, collectionFT, 'Fungible');325 326 await transferExpectFailure(collectionFT, newToken, alice, targetAddress, 1);327 });328 });329330 it('Fungible: disallows to nest token if not Owner', async () => {331 await usingApi(async api => {332 const collectionNFT = await createCollectionExpectSuccess({mode: {type: 'NFT'}});333 await setCollectionLimitsExpectSuccess(alice, collectionNFT, {nestingRule: 'Owner'});334335 await addToAllowListExpectSuccess(alice, collectionNFT, bob.address);336 await enableAllowListExpectSuccess(alice, collectionNFT);337 await enablePublicMintingExpectSuccess(alice, collectionNFT);338339 340 const targetToken = await createItemExpectSuccess(bob, collectionNFT, 'NFT');341 const targetAddress = {Ethereum: tokenIdToAddress(collectionNFT, targetToken)};342343 const collectionFT = await createCollectionExpectSuccess({mode: {type: 'Fungible', decimalPoints: 0}});344345 346 await expect(executeTransaction(api, alice, api.tx.unique.createItem(347 collectionFT, 348 targetAddress, 349 {Fungible: {Value: 10}},350 ))).to.be.rejected;351352 353 const newToken = await createItemExpectSuccess(alice, collectionFT, 'Fungible');354 await transferExpectFailure(collectionFT, newToken, alice, targetAddress, 1);355 });356 });357358 it('Fungible: disallows to nest token if not Owner (Restricted nesting)', async () => {359 await usingApi(async api => {360 const collectionNFT = await createCollectionExpectSuccess({mode: {type: 'NFT'}});361 await setCollectionLimitsExpectSuccess(alice, collectionNFT, {nestingRule: {OwnerRestricted:[collectionNFT]}}); 362363 await addToAllowListExpectSuccess(alice, collectionNFT, bob.address);364 await enableAllowListExpectSuccess(alice, collectionNFT);365 await enablePublicMintingExpectSuccess(alice, collectionNFT);366367 368 const targetToken = await createItemExpectSuccess(bob, collectionNFT, 'NFT');369 const targetAddress = {Ethereum: tokenIdToAddress(collectionNFT, targetToken)};370371 const collectionFT = await createCollectionExpectSuccess({mode: {type: 'Fungible', decimalPoints: 0}});372373 374 await expect(executeTransaction(api, alice, api.tx.unique.createItem(375 collectionFT, 376 targetAddress, 377 {Fungible: {Value: 10}},378 ))).to.be.rejected;379380 381 const newToken = await createItemExpectSuccess(alice, collectionFT, 'Fungible');382 await transferExpectFailure(collectionFT, newToken, alice, targetAddress, 1);383 });384 });385386 it('Fungible: disallows to nest token to an unlisted collection', async () => {387 await usingApi(async api => {388 const collectionNFT = await createCollectionExpectSuccess({mode: {type: 'NFT'}});389 await setCollectionLimitsExpectSuccess(alice, collectionNFT, {nestingRule: {OwnerRestricted:[]}});390391 392 const targetToken = await createItemExpectSuccess(alice, collectionNFT, 'NFT');393 const targetAddress = {Ethereum: tokenIdToAddress(collectionNFT, targetToken)};394395 const collectionFT = await createCollectionExpectSuccess({mode: {type: 'Fungible', decimalPoints: 0}});396397 398 await expect(executeTransaction(api, alice, api.tx.unique.createItem(399 collectionFT, 400 targetAddress, 401 {Fungible: {Value: 10}},402 ))).to.be.rejected;403404 405 const newToken = await createItemExpectSuccess(alice, collectionFT, 'Fungible');406 await transferExpectFailure(collectionFT, newToken, alice, targetAddress, 1);407 });408 });409410 411412 it('ReFungible: disallows to nest token if nesting is disabled', async () => {413 await usingApi(async api => {414 const collectionNFT = await createCollectionExpectSuccess({mode: {type: 'NFT'}});415 await setCollectionLimitsExpectSuccess(alice, collectionNFT, {nestingRule: 'Disabled'});416 const targetToken = await createItemExpectSuccess(alice, collectionNFT, 'NFT');417 const targetAddress = {Ethereum: tokenIdToAddress(collectionNFT, targetToken)};418419 const collectionRFT = await createCollectionExpectSuccess({mode: {type: 'ReFungible'}});420421 422 await expect(executeTransaction(api, alice, api.tx.unique.createItem(423 collectionRFT, 424 targetAddress, 425 {ReFungible: {const_data: [], variable_data: [], pieces: 100}},426 ))).to.be.rejectedWith(/^common\.NestingIsDisabled$/);427428 429 const newToken = await createItemExpectSuccess(alice, collectionRFT, 'ReFungible');430 431 await transferExpectFailure(collectionRFT, newToken, alice, targetAddress, 100);432 });433 });434435 it('ReFungible: disallows to nest token if not Owner', async () => {436 await usingApi(async api => {437 const collectionNFT = await createCollectionExpectSuccess({mode: {type: 'NFT'}});438 await setCollectionLimitsExpectSuccess(alice, collectionNFT, {nestingRule: 'Owner'});439440 await addToAllowListExpectSuccess(alice, collectionNFT, bob.address);441 await enableAllowListExpectSuccess(alice, collectionNFT);442 await enablePublicMintingExpectSuccess(alice, collectionNFT);443444 445 const targetToken = await createItemExpectSuccess(bob, collectionNFT, 'NFT');446 const targetAddress = {Ethereum: tokenIdToAddress(collectionNFT, targetToken)};447448 const collectionRFT = await createCollectionExpectSuccess({mode: {type: 'ReFungible'}});449450 451 await expect(executeTransaction(api, alice, api.tx.unique.createItem(452 collectionRFT, 453 targetAddress, 454 {ReFungible: {const_data: [], variable_data: [], pieces: 100}},455 ))).to.be.rejected;456457 458 const newToken = await createItemExpectSuccess(alice, collectionRFT, 'ReFungible');459 await transferExpectFailure(collectionRFT, newToken, alice, targetAddress, 100);460 });461 });462463 it('ReFungible: disallows to nest token if not Owner (Restricted nesting)', async () => {464 await usingApi(async api => {465 const collectionNFT = await createCollectionExpectSuccess({mode: {type: 'NFT'}});466 await setCollectionLimitsExpectSuccess(alice, collectionNFT, {nestingRule: {OwnerRestricted:[collectionNFT]}});467468 await addToAllowListExpectSuccess(alice, collectionNFT, bob.address);469 await enableAllowListExpectSuccess(alice, collectionNFT);470 await enablePublicMintingExpectSuccess(alice, collectionNFT);471472 473 const targetToken = await createItemExpectSuccess(bob, collectionNFT, 'NFT');474 const targetAddress = {Ethereum: tokenIdToAddress(collectionNFT, targetToken)};475476 const collectionRFT = await createCollectionExpectSuccess({mode: {type: 'ReFungible'}});477478 479 await expect(executeTransaction(api, alice, api.tx.unique.createItem(480 collectionRFT, 481 targetAddress, 482 {ReFungible: {const_data: [], variable_data: [], pieces: 100}},483 ))).to.be.rejected;484485 486 const newToken = await createItemExpectSuccess(alice, collectionRFT, 'ReFungible');487 await transferExpectFailure(collectionRFT, newToken, alice, targetAddress, 100);488 });489 });490491 it('ReFungible: disallows to nest token to an unlisted collection', async () => {492 await usingApi(async api => {493 const collectionNFT = await createCollectionExpectSuccess({mode: {type: 'NFT'}});494 await setCollectionLimitsExpectSuccess(alice, collectionNFT, {nestingRule: {OwnerRestricted:[]}});495496 497 const targetToken = await createItemExpectSuccess(alice, collectionNFT, 'NFT');498 const targetAddress = {Ethereum: tokenIdToAddress(collectionNFT, targetToken)};499500 const collectionRFT = await createCollectionExpectSuccess({mode: {type: 'ReFungible'}});501502 503 await expect(executeTransaction(api, alice, api.tx.unique.createItem(504 collectionRFT, 505 targetAddress, 506 {ReFungible: {const_data: [], variable_data: [], pieces: 100}},507 ))).to.be.rejected;508509 510 const newToken = await createItemExpectSuccess(alice, collectionRFT, 'ReFungible');511 await transferExpectFailure(collectionRFT, newToken, alice, targetAddress, 100);512 });513 });514});