1import {expect} from 'chai';2import {tokenIdToAddress} from '../eth/util/helpers';3import privateKey from '../substrate/privateKey';4import usingApi, {executeTransaction} from '../substrate/substrate-api';5import {6 createCollectionExpectSuccess,7 createItemExpectFailure, 8 createItemExpectSuccess,9 getTokenOwner, 10 getTopmostTokenOwner, 11 normalizeAccountId, 12 setCollectionLimitsExpectSuccess, 13 transferExpectSuccess, 14} from '../util/helpers';15import {IKeyringPair} from '@polkadot/types/types';1617let alice: IKeyringPair;18let bob: IKeyringPair;1920describe('Integration Test: Unnesting', () => {21 before(async () => {22 alice = privateKey('//Alice');23 bob = privateKey('//Bob');24 });2526 it('Allows the owner to successfully unnest a token', async () => {27 await usingApi(async api => {28 const collection = await createCollectionExpectSuccess({mode: {type: 'NFT'}});29 await setCollectionLimitsExpectSuccess(alice, collection, {nestingRule: 'Owner'});30 const targetToken = await createItemExpectSuccess(alice, collection, 'NFT');31 const targetAddress = {Ethereum: tokenIdToAddress(collection, targetToken)};3233 34 const nestedToken = await createItemExpectSuccess(alice, collection, 'NFT', targetAddress);3536 37 await expect(executeTransaction(38 api, 39 alice, 40 api.tx.unique.transferFrom(normalizeAccountId(targetAddress), normalizeAccountId(alice), collection, nestedToken, 1),41 )).to.not.be.rejected;42 expect(await getTokenOwner(api, collection, nestedToken)).to.be.deep.equal({Substrate: alice.address});4344 45 await transferExpectSuccess(collection, nestedToken, alice, targetAddress);46 await expect(executeTransaction(47 api, 48 alice, 49 api.tx.unique.burnFrom(collection, normalizeAccountId(alice.address), nestedToken, 1),50 )).to.not.be.rejected;51 await expect(getTokenOwner(api, collection, nestedToken)).to.be.rejected; 52 });53 });5455 56});5758describe('Negative Test: Unnesting', () => {59 before(async () => {60 alice = privateKey('//Alice');61 bob = privateKey('//Bob');62 });63 64 it('Disallows a non-owner to unnest/burn a token', async () => {65 await usingApi(async api => {66 const collection = await createCollectionExpectSuccess({mode: {type: 'NFT'}});67 await setCollectionLimitsExpectSuccess(alice, collection, {nestingRule: 'Owner'});68 const targetToken = await createItemExpectSuccess(alice, collection, 'NFT');69 const targetAddress = {Ethereum: tokenIdToAddress(collection, targetToken)};7071 72 const nestedToken = await createItemExpectSuccess(alice, collection, 'NFT', targetAddress);7374 75 await expect(executeTransaction(76 api, 77 bob, 78 api.tx.unique.transferFrom(normalizeAccountId(targetAddress), normalizeAccountId(bob), collection, nestedToken, 1),79 )).to.be.rejectedWith(/^common\.ApprovedValueTooLow$/);80 81 expect(await getTokenOwner(api, collection, nestedToken)).to.be.deep.equal({Ethereum: tokenIdToAddress(collection, targetToken).toLowerCase()});8283 84 await expect(executeTransaction(85 api, 86 bob, 87 api.tx.unique.burnFrom(collection, normalizeAccountId(bob.address), nestedToken, 1),88 )).to.not.be.rejectedWith(/^common\.ApprovedValueTooLow$/);89 expect(await getTokenOwner(api, collection, nestedToken)).to.be.deep.equal({Ethereum: tokenIdToAddress(collection, targetToken).toLowerCase()});90 });91 });92 93 it('Disallows excessive token nesting', async () => {94 await usingApi(async api => {95 const collection = await createCollectionExpectSuccess({mode: {type: 'NFT'}});96 await setCollectionLimitsExpectSuccess(alice, collection, {nestingRule: 'Owner'});97 const targetToken = await createItemExpectSuccess(alice, collection, 'NFT');9899 100 const nestedToken1 = await createItemExpectSuccess(alice, collection, 'NFT', {Ethereum: tokenIdToAddress(collection, targetToken)});101 const nestedToken2 = await createItemExpectSuccess(alice, collection, 'NFT', {Ethereum: tokenIdToAddress(collection, nestedToken1)});102 103 await createItemExpectFailure(alice, collection, 'NFT', {Ethereum: tokenIdToAddress(collection, nestedToken2)});104105 expect(await getTopmostTokenOwner(api, collection, nestedToken2)).to.be.deep.equal({Substrate: alice.address});106 });107 });108109 110 111 112 it('Prevents Ouroboros-nested operations', async () => { 113 await usingApi(async api => {114 const collection = await createCollectionExpectSuccess({mode: {type: 'NFT'}});115 await setCollectionLimitsExpectSuccess(alice, collection, {nestingRule: 'Owner'});116 const targetToken = await createItemExpectSuccess(alice, collection, 'NFT');117118 119 const nestedToken = await createItemExpectSuccess(alice, collection, 'NFT', {Ethereum: tokenIdToAddress(collection, targetToken)});120 await transferExpectSuccess(collection, targetToken, alice, {Ethereum: tokenIdToAddress(collection, nestedToken)});121122 expect(await getTokenOwner(api, collection, nestedToken)).to.be.deep.equal({Ethereum: tokenIdToAddress(collection, targetToken).toLowerCase()});123124 125 await expect(getTopmostTokenOwner(api, collection, nestedToken)).to.be.rejected; 126 127 });128 });129});