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.setCollectionNesting(true).send({from: owner});2223 return {collectionId, collectionAddress, contract};24};2526describe('Integration Test: EVM Nesting', () => {27 itWeb3('NFT: allows an Owner to nest/unnest their token', async ({api, web3, privateKeyWrapper}) => {28 const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);29 const {collectionId, contract} = await createNestingCollection(api, web3, owner);3031 32 const targetNFTTokenId = await contract.methods.nextTokenId().call();33 await contract.methods.mint(34 owner,35 targetNFTTokenId,36 ).send({from: owner});3738 const targetNftTokenAddress = tokenIdToAddress(collectionId, targetNFTTokenId);3940 41 const firstTokenId = await contract.methods.nextTokenId().call();42 await contract.methods.mint(43 targetNftTokenAddress,44 firstTokenId,45 ).send({from: owner});4647 expect(await contract.methods.ownerOf(firstTokenId).call()).to.be.equal(targetNftTokenAddress);4849 50 const secondTokenId = await contract.methods.nextTokenId().call();51 await contract.methods.mint(52 owner,53 secondTokenId,54 ).send({from: owner});5556 await contract.methods.transfer(targetNftTokenAddress, secondTokenId).send({from: owner});5758 expect(await contract.methods.ownerOf(secondTokenId).call()).to.be.equal(targetNftTokenAddress);5960 61 await contract.methods.transferFrom(targetNftTokenAddress, owner, secondTokenId).send({from: owner});62 expect(await contract.methods.ownerOf(secondTokenId).call()).to.be.equal(owner);63 });6465 itWeb3('NFT: allows an Owner to nest/unnest their token (Restricted nesting)', async ({api, web3, privateKeyWrapper}) => {66 const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);6768 const {collectionId: collectionIdA, collectionAddress: collectionAddressA, contract: contractA} = await createNestingCollection(api, web3, owner);69 const {collectionAddress: collectionAddressB, contract: contractB} = await createNestingCollection(api, web3, owner);70 await contractA.methods.setCollectionNesting(true, [collectionAddressA, collectionAddressB]).send({from: owner});7172 73 const targetNftTokenId = await contractA.methods.nextTokenId().call();74 await contractA.methods.mint(75 owner,76 targetNftTokenId,77 ).send({from: owner});78 const nftTokenAddressA1 = tokenIdToAddress(collectionIdA, targetNftTokenId);7980 81 const nftTokenIdA = await contractA.methods.nextTokenId().call();82 await contractA.methods.mint(83 owner,84 nftTokenIdA,85 ).send({from: owner});8687 88 const nftTokenIdB = await contractB.methods.nextTokenId().call();89 await contractB.methods.mint(90 owner,91 nftTokenIdB,92 ).send({from: owner});9394 95 await contractA.methods.transfer(nftTokenAddressA1, nftTokenIdA).send({from: owner});96 expect(await contractA.methods.ownerOf(nftTokenIdA).call()).to.be.equal(nftTokenAddressA1);9798 await contractB.methods.transfer(nftTokenAddressA1, nftTokenIdB).send({from: owner});99 expect(await contractB.methods.ownerOf(nftTokenIdB).call()).to.be.equal(nftTokenAddressA1);100 });101});102103describe('Negative Test: EVM Nesting', async() => {104 itWeb3('NFT: disallows to nest token if nesting is disabled', async ({api, web3, privateKeyWrapper}) => {105 const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);106107 const {collectionId, contract} = await createNestingCollection(api, web3, owner);108 await contract.methods.setCollectionNesting(false).send({from: owner});109110 111 const targetNftTokenId = await contract.methods.nextTokenId().call();112 await contract.methods.mint(113 owner,114 targetNftTokenId,115 ).send({from: owner});116117 const targetNftTokenAddress = tokenIdToAddress(collectionId, targetNftTokenId);118119 120 const nftTokenId = await contract.methods.nextTokenId().call();121 await contract.methods.mint(122 owner,123 nftTokenId,124 ).send({from: owner});125126 127 await expect(contract.methods128 .transfer(targetNftTokenAddress, nftTokenId)129 .call({from: owner})).to.be.rejectedWith('UserIsNotAllowedToNest');130 });131132 itWeb3('NFT: disallows a non-Owner to nest someone else\'s token', async ({api, web3, privateKeyWrapper}) => {133 const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);134 const malignant = await createEthAccountWithBalance(api, web3, privateKeyWrapper);135136 const {collectionId, contract} = await createNestingCollection(api, web3, owner);137138 139 const targetTokenId = await contract.methods.nextTokenId().call();140 await contract.methods.mint(141 owner,142 targetTokenId,143 ).send({from: owner});144 const targetTokenAddress = tokenIdToAddress(collectionId, targetTokenId);145146 147 const tokenId = await contract.methods.nextTokenId().call();148 await contract.methods.mint(149 malignant,150 tokenId,151 ).send({from: owner});152153 154 await expect(contract.methods155 .transfer(targetTokenAddress, tokenId)156 .call({from: malignant})).to.be.rejectedWith('UserIsNotAllowedToNest');157 });158159 itWeb3('NFT: disallows a non-Owner to nest someone else\'s token (Restricted nesting)', async ({api, web3, privateKeyWrapper}) => {160 const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);161 const malignant = await createEthAccountWithBalance(api, web3, privateKeyWrapper);162163 const {collectionId: collectionIdA, collectionAddress: collectionAddressA, contract: contractA} = await createNestingCollection(api, web3, owner);164 const {collectionAddress: collectionAddressB, contract: contractB} = await createNestingCollection(api, web3, owner);165166 await contractA.methods.setCollectionNesting(true, [collectionAddressA, collectionAddressB]).send({from: owner});167168 169 const nftTokenIdA = await contractA.methods.nextTokenId().call();170 await contractA.methods.mint(171 owner,172 nftTokenIdA,173 ).send({from: owner});174 const nftTokenAddressA = tokenIdToAddress(collectionIdA, nftTokenIdA);175176 177 const nftTokenIdB = await contractB.methods.nextTokenId().call();178 await contractB.methods.mint(179 malignant,180 nftTokenIdB,181 ).send({from: owner});182183 184 await expect(contractB.methods185 .transfer(nftTokenAddressA, nftTokenIdB)186 .call({from: malignant})).to.be.rejectedWith('UserIsNotAllowedToNest');187 });188189 itWeb3('NFT: disallows to nest token in an unlisted collection', async ({api, web3, privateKeyWrapper}) => {190 const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);191192 const {collectionId: collectionIdA, collectionAddress: collectionAddressA, contract: contractA} = await createNestingCollection(api, web3, owner);193 const {contract: contractB} = await createNestingCollection(api, web3, owner);194195 await contractA.methods.setCollectionNesting(true, [collectionAddressA]).send({from: owner});196197 198 const nftTokenIdA = await contractA.methods.nextTokenId().call();199 await contractA.methods.mint(200 owner,201 nftTokenIdA,202 ).send({from: owner});203 const nftTokenAddressA = tokenIdToAddress(collectionIdA, nftTokenIdA);204205 206 const nftTokenIdB = await contractB.methods.nextTokenId().call();207 await contractB.methods.mint(208 owner,209 nftTokenIdB,210 ).send({from: owner});211212 213 await expect(contractB.methods214 .transfer(nftTokenAddressA, nftTokenIdB)215 .call()).to.be.rejectedWith('SourceCollectionIsNotAllowedToNest');216 });217});