1import {ApiPromise} from '@polkadot/api';2import {Contract} from 'web3-eth-contract';3import {expect} from 'chai';4import Web3 from 'web3';5import {createEthAccountWithBalance, evmCollectionHelpers, GAS_ARGS, getCollectionAddressFromResult, itWeb3, tokenIdToAddress} from '../../eth/util/helpers';6import nonFungibleAbi from '../nonFungibleAbi.json';78const createNestingCollection = async (9 api: ApiPromise,10 web3: Web3,11 owner: string,12): Promise<{ collectionId: number, collectionAddress: string, contract: Contract }> => {13 const collectionHelper = evmCollectionHelpers(web3, owner);14 15 const result = await collectionHelper.methods16 .createNonfungibleCollection('A', 'B', 'C')17 .send();18 const {collectionIdAddress: collectionAddress, collectionId} = await getCollectionAddressFromResult(api, result);1920 const contract = new web3.eth.Contract(nonFungibleAbi as any, collectionAddress, {from: owner, ...GAS_ARGS});21 await contract.methods.addCollectionAdmin(owner).send();22 await contract.methods.setCollectionNesting(true).send({from: owner});2324 return {collectionId, collectionAddress, contract};25};2627describe('Integration Test: EVM Nesting', () => {28 itWeb3('NFT: allows an Owner to nest/unnest their token', async ({api, web3, privateKeyWrapper}) => {29 const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);30 const {collectionId, contract} = await createNestingCollection(api, web3, owner);3132 33 const nftTokenId = await contract.methods.nextTokenId().call();34 await contract.methods.mint(35 owner,36 nftTokenId,37 ).send({from: owner});3839 40 const firstTargetNftTokenId = await contract.methods.nextTokenId().call();41 await contract.methods.mint(42 owner,43 firstTargetNftTokenId,44 ).send({from: owner});4546 const targetNftTokenAddress = tokenIdToAddress(collectionId, firstTargetNftTokenId);4748 await contract.methods.transfer(targetNftTokenAddress, nftTokenId).send({from: owner});49 expect(await contract.methods.ownerOf(nftTokenId).call()).to.be.equal(targetNftTokenAddress);5051 52 const secondTargetNftTokenId = await contract.methods.nextTokenId().call();53 await contract.methods.mint(54 owner,55 secondTargetNftTokenId,56 ).send({from: owner});57 const nextNftTokenAddress = tokenIdToAddress(collectionId, secondTargetNftTokenId);5859 await contract.methods.transfer(nextNftTokenAddress, nftTokenId).send({from: owner});60 expect(await contract.methods.ownerOf(nftTokenId).call()).to.be.equal(nextNftTokenAddress);61 });6263 itWeb3('NFT: allows an Owner to nest/unnest their token (Restricted nesting)', async ({api, web3, privateKeyWrapper}) => {64 const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);6566 const {collectionId: collectionIdA, collectionAddress: collectionAddressA, contract: contractA} = await createNestingCollection(api, web3, owner);67 const {collectionAddress: collectionAddressB, contract: contractB} = await createNestingCollection(api, web3, owner);68 await contractA.methods.setCollectionNesting(true, [collectionAddressA, collectionAddressB]).send({from: owner});6970 71 const targetNftTokenId = await contractA.methods.nextTokenId().call();72 await contractA.methods.mint(73 owner,74 targetNftTokenId,75 ).send({from: owner});76 const nftTokenAddressA1 = tokenIdToAddress(collectionIdA, targetNftTokenId);7778 79 const nftTokenIdA = await contractA.methods.nextTokenId().call();80 await contractA.methods.mint(81 owner,82 nftTokenIdA,83 ).send({from: owner});8485 86 const nftTokenIdB = await contractB.methods.nextTokenId().call();87 await contractB.methods.mint(88 owner,89 nftTokenIdB,90 ).send({from: owner});9192 93 await contractA.methods.transfer(nftTokenAddressA1, nftTokenIdA).send({from: owner});94 expect(await contractA.methods.ownerOf(nftTokenIdA).call()).to.be.equal(nftTokenAddressA1);9596 await contractB.methods.transfer(nftTokenAddressA1, nftTokenIdB).send({from: owner});97 expect(await contractB.methods.ownerOf(nftTokenIdB).call()).to.be.equal(nftTokenAddressA1);98 });99});100101describe('Negative Test: EVM Nesting', async() => {102 itWeb3('NFT: disallows to nest token if nesting is disabled', async ({api, web3, privateKeyWrapper}) => {103 const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);104105 const {collectionId, contract} = await createNestingCollection(api, web3, owner);106 await contract.methods.setCollectionNesting(false).send({from: owner});107108 109 const targetNftTokenId = await contract.methods.nextTokenId().call();110 await contract.methods.mint(111 owner,112 targetNftTokenId,113 ).send({from: owner});114115 const targetNftTokenAddress = tokenIdToAddress(collectionId, targetNftTokenId);116117 118 const nftTokenId = await contract.methods.nextTokenId().call();119 await contract.methods.mint(120 owner,121 nftTokenId,122 ).send({from: owner});123124 125 await expect(contract.methods126 .transfer(targetNftTokenAddress, nftTokenId)127 .call({from: owner})).to.be.rejectedWith('UserIsNotAllowedToNest');128 });129 130 itWeb3('NFT: disallows a non-Owner to nest someone else\'s token', async ({api, web3, privateKeyWrapper}) => {131 const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);132 const malignant = await createEthAccountWithBalance(api, web3, privateKeyWrapper);133134 const {collectionId, contract} = await createNestingCollection(api, web3, owner);135136 137 const targetTokenId = await contract.methods.nextTokenId().call();138 await contract.methods.mint(139 owner,140 targetTokenId,141 ).send({from: owner});142 const targetTokenAddress = tokenIdToAddress(collectionId, targetTokenId);143 144 145 const tokenId = await contract.methods.nextTokenId().call();146 await contract.methods.mint(147 malignant,148 tokenId,149 ).send({from: owner});150 151 152 await expect(contract.methods153 .transfer(targetTokenAddress, tokenId)154 .call({from: malignant})).to.be.rejectedWith('UserIsNotAllowedToNest');155 });156 157 itWeb3('NFT: disallows a non-Owner to nest someone else\'s token (Restricted nesting)', async ({api, web3, privateKeyWrapper}) => {158 const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);159 const malignant = await createEthAccountWithBalance(api, web3, privateKeyWrapper);160161 const {collectionId: collectionIdA, collectionAddress: collectionAddressA, contract: contractA} = await createNestingCollection(api, web3, owner);162 const {collectionAddress: collectionAddressB, contract: contractB} = await createNestingCollection(api, web3, owner);163164 await contractA.methods.setCollectionNesting(true, [collectionAddressA, collectionAddressB]).send({from: owner});165166 167 const nftTokenIdA = await contractA.methods.nextTokenId().call();168 await contractA.methods.mint(169 owner,170 nftTokenIdA,171 ).send({from: owner});172 const nftTokenAddressA = tokenIdToAddress(collectionIdA, nftTokenIdA);173174 175 const nftTokenIdB = await contractB.methods.nextTokenId().call();176 await contractB.methods.mint(177 malignant,178 nftTokenIdB,179 ).send({from: owner});180181 182 await expect(contractB.methods183 .transfer(nftTokenAddressA, nftTokenIdB)184 .call({from: malignant})).to.be.rejectedWith('UserIsNotAllowedToNest');185 });186 187 itWeb3('NFT: disallows to nest token in an unlisted collection', async ({api, web3, privateKeyWrapper}) => {188 const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);189190 const {collectionId: collectionIdA, collectionAddress: collectionAddressA, contract: contractA} = await createNestingCollection(api, web3, owner);191 const {contract: contractB} = await createNestingCollection(api, web3, owner);192193 await contractA.methods.setCollectionNesting(true, [collectionAddressA]).send({from: owner});194195 196 const nftTokenIdA = await contractA.methods.nextTokenId().call();197 await contractA.methods.mint(198 owner,199 nftTokenIdA,200 ).send({from: owner});201 const nftTokenAddressA = tokenIdToAddress(collectionIdA, nftTokenIdA);202203 204 const nftTokenIdB = await contractB.methods.nextTokenId().call();205 await contractB.methods.mint(206 owner,207 nftTokenIdB,208 ).send({from: owner});209210 211 await expect(contractB.methods212 .transfer(nftTokenAddressA, nftTokenIdB)213 .call()).to.be.rejectedWith('SourceCollectionIsNotAllowedToNest');214 });215});