git.delta.rocks / unique-network / refs/commits / 25ce44862797

difftreelog

test fixed and improved tests for ERC721Metadata compatible collections. WIP, 1 test still fails

Alex Saft2022-10-15parent: #49ed2a2.patch.diff
in: master

13 files changed

modifiedtests/src/eth/base.test.tsdiffbeforeafterboth
--- a/tests/src/eth/base.test.ts
+++ b/tests/src/eth/base.test.ts
@@ -23,7 +23,7 @@
 describe('Contract calls', () => {
   let donor: IKeyringPair;
 
-  before(async function() {
+  before(async function () {
     await usingEthPlaygrounds(async (_helper, privateKey) => {
       donor = privateKey('//Alice');
     });
@@ -40,7 +40,12 @@
   itEth('Balance transfer fee is less than 0.2 UNQ', async ({helper}) => {
     const userA = await helper.eth.createAccountWithBalance(donor);
     const userB = helper.eth.createAccount();
-    const cost = await helper.eth.calculateFee({Ethereum: userA}, () => helper.getWeb3().eth.sendTransaction({from: userA, to: userB, value: '1000000', gas: helper.eth.DEFAULT_GAS}));
+    const cost = await helper.eth.calculateFee({Ethereum: userA}, () => helper.getWeb3().eth.sendTransaction({
+      from: userA,
+      to: userB,
+      value: '1000000',
+      gas: helper.eth.DEFAULT_GAS
+    }));
     const balanceB = await helper.balance.getEthereum(userB);
     expect(cost - balanceB < BigInt(0.2 * Number(helper.balance.getOneTokenNominal()))).to.be.true;
   });
@@ -69,67 +74,59 @@
 describe('ERC165 tests', async () => {
   // https://eips.ethereum.org/EIPS/eip-165
 
-  let collection: number;
+  let erc721MetadataCompatibleNftCollectionId: number;
+  let simpleNftCollectionId: number;
   let minter: string;
 
-  function contract(helper: EthUniqueHelper): Contract {
-    return helper.ethNativeContract.collection(helper.ethAddress.fromCollectionId(collection), 'nft', minter);
+  const BASE_URI = 'base/';
+
+  async function checkInterface(helper: EthUniqueHelper, interfaceId: string, simpleResult: boolean, compatibleResult: boolean) {
+    const simple = helper.ethNativeContract.collection(helper.ethAddress.fromCollectionId(simpleNftCollectionId), 'nft', minter);
+    const compatible = helper.ethNativeContract.collection(helper.ethAddress.fromCollectionId(erc721MetadataCompatibleNftCollectionId), 'nft', minter);
+
+    expect(await simple.methods.supportsInterface(interfaceId).call()).to.equal(simpleResult, `empty (not ERC721Metadata compatible) NFT collection returns not ${simpleResult}`);
+    expect(await compatible.methods.supportsInterface(interfaceId).call()).to.equal(compatibleResult, `ERC721Metadata compatible NFT collection returns not ${compatibleResult}`);
   }
 
   before(async () => {
     await usingEthPlaygrounds(async (helper, privateKey) => {
       const donor = privateKey('//Alice');
-      const [alice] = await helper.arrange.createAccounts([10n], donor);
-      ({collectionId: collection} = await helper.nft.mintCollection(
-        alice,
-        {
-          name: 'test',
-          description: 'test',
-          tokenPrefix: 'test',
-          properties: [{key: 'ERC721Metadata', value: '1'}],
-          tokenPropertyPermissions: [{
-            key: 'URI',
-            permission: {
-              mutable: true,
-              collectionAdmin: true,
-              tokenOwner: false,
-            },
-          }],
-        },
-      ));
-      minter = helper.eth.createAccount();
+      minter = await helper.eth.createAccountWithBalance(donor);
+
+      simpleNftCollectionId = (await helper.eth.createNFTCollection(minter, 'n', 'd', 'p')).collectionId;
+      erc721MetadataCompatibleNftCollectionId = (await helper.eth.createERC721MetadataCompatibleNFTCollection(minter, 'n', 'd', 'p', BASE_URI)).collectionId;
     });
   });
 
-  itEth('interfaceID == 0xffffffff always false', async ({helper}) => {
-    expect(await contract(helper).methods.supportsInterface('0xffffffff').call()).to.be.false;
+  itEth('nonexistent interfaceID - 0xffffffff - always false', async ({helper}) => {
+    await checkInterface(helper, '0xffffffff', false, false);
   });
 
-  itEth('ERC721 support', async ({helper}) => {
-    expect(await contract(helper).methods.supportsInterface('0x780e9d63').call()).to.be.true;
+  itEth('ERC721 - 0x780e9d63 - support', async ({helper}) => {
+    await checkInterface(helper, '0x780e9d63', true, true);
   });
 
-  itEth('ERC721Metadata support', async ({helper}) => {
-    expect(await contract(helper).methods.supportsInterface('0x5b5e139f').call()).to.be.true;
+  itEth('ERC721Metadata - 0x5b5e139f - support', async ({helper}) => {
+    await checkInterface(helper, '0x5b5e139f', false, true);
   });
 
-  itEth('ERC721Mintable support', async ({helper}) => {
-    expect(await contract(helper).methods.supportsInterface('0x68ccfe89').call()).to.be.true;
+  itEth('ERC721UniqueMintable - 0x476ff149 - support', async ({helper}) => {
+    await checkInterface(helper, '0x476ff149', true, true);
   });
 
-  itEth('ERC721Enumerable support', async ({helper}) => {
-    expect(await contract(helper).methods.supportsInterface('0x780e9d63').call()).to.be.true;
+  itEth('ERC721Enumerable - 0x780e9d63 - support', async ({helper}) => {
+    await checkInterface(helper, '0x780e9d63', true, true);
   });
 
-  itEth('ERC721UniqueExtensions support', async ({helper}) => {
-    expect(await contract(helper).methods.supportsInterface('0xd74d154f').call()).to.be.true;
+  itEth('ERC721UniqueExtensions - 0x4468500d - support', async ({helper}) => {
+    await checkInterface(helper, '0x4468500d', true, true);
   });
 
-  itEth('ERC721Burnable support', async ({helper}) => {
-    expect(await contract(helper).methods.supportsInterface('0x42966c68').call()).to.be.true;
+  itEth('ERC721Burnable - 0x42966c68 - support', async ({helper}) => {
+    await checkInterface(helper, '0x42966c68', true, true);
   });
 
-  itEth('ERC165 support', async ({helper}) => {
-    expect(await contract(helper).methods.supportsInterface('0x01ffc9a7').call()).to.be.true;
+  itEth('ERC165 - 0x01ffc9a7 - support', async ({helper}) => {
+    await checkInterface(helper, '0x01ffc9a7', true, true);
   });
 });
modifiedtests/src/eth/collectionProperties.test.tsdiffbeforeafterboth
--- a/tests/src/eth/collectionProperties.test.ts
+++ b/tests/src/eth/collectionProperties.test.ts
@@ -1,6 +1,7 @@
-import {itEth, usingEthPlaygrounds, expect} from './util/playgrounds';
+import {itEth, usingEthPlaygrounds, expect, EthUniqueHelper} from './util/playgrounds';
 import {IKeyringPair} from '@polkadot/types/types';
 import {Pallets} from '../util/playgrounds';
+import {IProperty, ITokenPropertyPermission} from "../util/playgrounds/types";
 
 describe('EVM collection properties', () => {
   let donor: IKeyringPair;
@@ -65,52 +66,82 @@
     });
   });
 
-  itEth('ERC721Metadata property can be set for NFT collection', async({helper}) => {
+  const checkERC721Metadata = async (helper: EthUniqueHelper, mode: 'nft' | 'rft') => {
     const caller = await helper.eth.createAccountWithBalance(donor);
-    const tokenPropertyPermissions = [{
-      key: 'URI',
-      permission: {
-        mutable: true,
-        collectionAdmin: true,
-        tokenOwner: false,
-      },
-    }];
-    const collection = await helper.nft.mintCollection(donor, {name: 'col', description: 'descr', tokenPrefix: 'COL', tokenPropertyPermissions});
+    const bruh = await helper.eth.createAccountWithBalance(donor);
 
-    await collection.addAdmin(donor, {Ethereum: caller});
-    const contract = helper.ethNativeContract.collectionById(collection.collectionId, 'nft', caller);
+    const BASE_URI = 'base/'
+    const SUFFIX = 'suffix1'
+    const URI = 'uri1'
 
-    await contract.methods.setCollectionProperty('ERC721Metadata', Buffer.from('1')).send({from: caller});
+    const collectionHelpers = helper.ethNativeContract.collectionHelpers(caller);
+    const creatorMethod = mode === 'rft' ? 'createRFTCollection' : 'createNFTCollection'
 
-    expect(await contract.methods.supportsInterface('0x5b5e139f').call()).to.be.true;
+    const {collectionId, collectionAddress} = await helper.eth[creatorMethod](caller, 'n', 'd', 'p')
 
-    await contract.methods.setCollectionProperty('ERC721Metadata', Buffer.from('0')).send({from: caller});
+    const contract = helper.ethNativeContract.collectionById(collectionId, mode, caller);
+    await contract.methods.addCollectionAdmin(bruh).send(); // to check that admin will work too
 
+    const collection1 = await helper.nft.getCollectionObject(collectionId);
+    const data1 = await collection1.getData()
+    expect(data1?.raw.flags.erc721metadata).to.be.false;
     expect(await contract.methods.supportsInterface('0x5b5e139f').call()).to.be.false;
-  });
 
-  itEth.ifWithPallets('ERC721Metadata property can be set for RFT collection', [Pallets.ReFungible], async({helper}) => {
-    const caller = await helper.eth.createAccountWithBalance(donor);
-    const tokenPropertyPermissions = [{
-      key: 'URI',
-      permission: {
-        mutable: true,
-        collectionAdmin: true,
-        tokenOwner: false,
-      },
-    }];
-    const collection = await helper.rft.mintCollection(donor, {name: 'col', description: 'descr', tokenPrefix: 'COL', tokenPropertyPermissions});
+    await collectionHelpers.methods.makeCollectionERC721MetadataCompatible(collectionAddress, BASE_URI)
+      .send({from: bruh});
 
-    await collection.addAdmin(donor, {Ethereum: caller});
+    expect(await contract.methods.supportsInterface('0x5b5e139f').call()).to.be.true;
 
-    const contract = helper.ethNativeContract.collectionById(collection.collectionId, 'nft', caller);
+    const collection2 = await helper.nft.getCollectionObject(collectionId);
+    const data2 = await collection2.getData()
+    expect(data2?.raw.flags.erc721metadata).to.be.true;
 
-    await contract.methods.setCollectionProperty('ERC721Metadata', Buffer.from('1')).send({from: caller});
+    const TPPs = data2?.raw.tokenPropertyPermissions
+    expect(TPPs?.length).to.equal(2);
 
-    expect(await contract.methods.supportsInterface('0x5b5e139f').call()).to.be.true;
+    expect(TPPs.find((tpp: ITokenPropertyPermission) => {
+      return tpp.key === "URI" && tpp.permission.mutable && tpp.permission.collectionAdmin && !tpp.permission.tokenOwner
+    })).to.be.not.null
 
-    await contract.methods.setCollectionProperty('ERC721Metadata', Buffer.from('0')).send({from: caller});
+    expect(TPPs.find((tpp: ITokenPropertyPermission) => {
+      return tpp.key === "URISuffix" && tpp.permission.mutable && tpp.permission.collectionAdmin && !tpp.permission.tokenOwner
+    })).to.be.not.null
+
+    expect(data2?.raw.properties?.find((property: IProperty) => {
+      return property.key === "baseURI" && property.value === BASE_URI
+    })).to.be.not.null
+
+    const token1Result = await contract.methods.mint(bruh).send();
+    const tokenId1 = token1Result.events.Transfer.returnValues.tokenId;
+
+    expect(await contract.methods.tokenURI(tokenId1).call()).to.equal(BASE_URI);
+
+    await contract.methods.setProperty(tokenId1, "URISuffix", Buffer.from(SUFFIX)).send();
+    expect(await contract.methods.tokenURI(tokenId1).call()).to.equal(BASE_URI + SUFFIX);
 
-    expect(await contract.methods.supportsInterface('0x5b5e139f').call()).to.be.false;
+    await contract.methods.setProperty(tokenId1, "URI", Buffer.from(URI)).send();
+    expect(await contract.methods.tokenURI(tokenId1).call()).to.equal(URI);
+
+    await contract.methods.deleteProperty(tokenId1, "URI").send();
+    expect(await contract.methods.tokenURI(tokenId1).call()).to.equal(BASE_URI + SUFFIX);
+
+    const token2Result = await contract.methods.mintWithTokenURI(bruh, URI).send();
+    const tokenId2 = token2Result.events.Transfer.returnValues.tokenId;
+
+    expect(await contract.methods.tokenURI(tokenId2).call()).to.equal(URI);
+
+    await contract.methods.deleteProperty(tokenId2, "URI").send();
+    expect(await contract.methods.tokenURI(tokenId2).call()).to.equal(BASE_URI);
+
+    await contract.methods.setProperty(tokenId2, "URISuffix", Buffer.from(SUFFIX)).send();
+    expect(await contract.methods.tokenURI(tokenId2).call()).to.equal(BASE_URI + SUFFIX);
+  }
+
+  itEth('ERC721Metadata property can be set for NFT collection', async({helper}) => {
+    await checkERC721Metadata(helper, 'nft');
+  });
+
+  itEth.ifWithPallets('ERC721Metadata property can be set for RFT collection', [Pallets.ReFungible], async({helper}) => {
+    await checkERC721Metadata(helper, 'rft');
   });
 });
modifiedtests/src/eth/collectionSponsoring.test.tsdiffbeforeafterboth
--- a/tests/src/eth/collectionSponsoring.test.ts
+++ b/tests/src/eth/collectionSponsoring.test.ts
@@ -33,9 +33,8 @@
 
     await collection.addToAllowList(alice, {Ethereum: minter});
 
-    const nextTokenId = await contract.methods.nextTokenId().call();
-    expect(nextTokenId).to.equal('1');
-    const result = await contract.methods.mint(minter, nextTokenId).send();
+    const result = await contract.methods.mint(minter).send();
+
     const events = helper.eth.normalizeEvents(result.events);
     expect(events).to.be.deep.equal([
       {
@@ -44,7 +43,7 @@
         args: {
           from: '0x0000000000000000000000000000000000000000',
           to: minter,
-          tokenId: nextTokenId,
+          tokenId: '1',
         },
       },
     ]);
@@ -62,11 +61,11 @@
   //   expect(await collectionEvm.methods.hasCollectionPendingSponsor().call({from: owner})).to.be.false;
   //   result = await collectionEvm.methods.setCollectionSponsorSubstrate(sponsor.addressRaw).send({from: owner});
   //   expect(await collectionEvm.methods.hasCollectionPendingSponsor().call({from: owner})).to.be.true;
-    
+
   //   const confirmTx = await api.tx.unique.confirmSponsorship(collectionId);
   //   await submitTransactionAsync(sponsor, confirmTx);
   //   expect(await collectionEvm.methods.hasCollectionPendingSponsor().call({from: owner})).to.be.false;
-    
+
   //   const sponsorTuple = await collectionEvm.methods.collectionSponsor().call({from: owner});
   //   expect(bigIntToSub(api, BigInt(sponsorTuple[1]))).to.be.eq(sponsor.address);
   // });
@@ -83,28 +82,26 @@
     expect(await collectionEvm.methods.hasCollectionPendingSponsor().call({from: owner})).to.be.false;
     result = await collectionEvm.methods.setCollectionSponsor(sponsor).send({from: owner});
     expect(await collectionEvm.methods.hasCollectionPendingSponsor().call({from: owner})).to.be.true;
-    
+
     await collectionEvm.methods.confirmCollectionSponsorship().send({from: sponsor});
     expect(await collectionEvm.methods.hasCollectionPendingSponsor().call({from: owner})).to.be.false;
-    
+
     await collectionEvm.methods.removeCollectionSponsor().send({from: owner});
-    
+
     const sponsorTuple = await collectionEvm.methods.collectionSponsor().call({from: owner});
     expect(sponsorTuple.field_0).to.be.eq('0x0000000000000000000000000000000000000000');
   });
 
   itEth('Sponsoring collection from evm address via access list', async ({helper}) => {
     const owner = await helper.eth.createAccountWithBalance(donor);
-    const collectionHelpers = helper.ethNativeContract.collectionHelpers(owner);
 
-    let result = await collectionHelpers.methods.createERC721MetadataCompatibleNFTCollection('Sponsor collection', '1', '1', '').send({value: Number(2n * nominal)});
-    const collectionIdAddress = helper.ethAddress.normalizeAddress(result.events.CollectionCreated.returnValues.collectionId);
-    const collectionId = helper.ethAddress.extractCollectionId(collectionIdAddress);
+    const {collectionId, collectionAddress} = await helper.eth.createERC721MetadataCompatibleNFTCollection(owner, 'Sponsor collection', '1', '1', '');
+
     const collection = helper.nft.getCollectionObject(collectionId);
     const sponsor = await helper.eth.createAccountWithBalance(donor);
-    const collectionEvm = helper.ethNativeContract.collection(collectionIdAddress, 'nft', owner);
+    const collectionEvm = helper.ethNativeContract.collection(collectionAddress, 'nft', owner);
 
-    result = await collectionEvm.methods.setCollectionSponsor(sponsor).send({from: owner});
+    await collectionEvm.methods.setCollectionSponsor(sponsor).send({from: owner});
     let collectionData = (await collection.getData())!;
     expect(collectionData.raw.sponsorship.Unconfirmed).to.be.eq(helper.address.ethToSubstrate(sponsor, true));
     await expect(collectionEvm.methods.confirmCollectionSponsorship().call()).to.be.rejectedWith('caller is not set as sponsor');
@@ -133,23 +130,17 @@
     const sponsorBalanceBefore = await helper.balance.getSubstrate(helper.address.ethToSubstrate(sponsor));
 
     {
-      const nextTokenId = await collectionEvm.methods.nextTokenId().call();
-      expect(nextTokenId).to.be.equal('1');
-      const result = await collectionEvm.methods.mintWithTokenURI(
-        user,
-        nextTokenId,
-        'Test URI',
-      ).send({from: user});
+      const result = await collectionEvm.methods.mintWithTokenURI(user, 'Test URI').send({from: user});
       const events = helper.eth.normalizeEvents(result.events);
 
       expect(events).to.be.deep.equal([
         {
-          address: collectionIdAddress,
+          address: collectionAddress,
           event: 'Transfer',
           args: {
             from: '0x0000000000000000000000000000000000000000',
             to: user,
-            tokenId: nextTokenId,
+            tokenId: '1',
           },
         },
       ]);
@@ -173,10 +164,10 @@
   //   const collectionEvm = evmCollection(web3, owner, collectionIdAddress);
 
   //   await collectionEvm.methods.setCollectionSponsorSubstrate(sponsor.addressRaw).send({from: owner});
-    
+
   //   const confirmTx = await api.tx.unique.confirmSponsorship(collectionId);
   //   await submitTransactionAsync(sponsor, confirmTx);
-    
+
   //   const user = createEthAccount(web3);
   //   const nextTokenId = await collectionEvm.methods.nextTokenId().call();
   //   expect(nextTokenId).to.be.equal('1');
@@ -221,39 +212,32 @@
 
   itEth('Check that transaction via EVM spend money from sponsor address', async ({helper}) => {
     const owner = await helper.eth.createAccountWithBalance(donor);
-    const collectionHelpers = helper.ethNativeContract.collectionHelpers(owner);
 
-    let result = await collectionHelpers.methods.createERC721MetadataCompatibleNFTCollection('Sponsor collection', '1', '1', '').send({value: Number(2n * nominal)});
-    const collectionIdAddress = helper.ethAddress.normalizeAddress(result.events.CollectionCreated.returnValues.collectionId);
-    const collectionId = helper.ethAddress.extractCollectionId(collectionIdAddress);
+    const {collectionAddress, collectionId} = await helper.eth.createERC721MetadataCompatibleNFTCollection(owner,'Sponsor collection', '1', '1', '');
     const collection = helper.nft.getCollectionObject(collectionId);
     const sponsor = await helper.eth.createAccountWithBalance(donor);
-    const collectionEvm = helper.ethNativeContract.collection(collectionIdAddress, 'nft', owner);
+    const collectionEvm = helper.ethNativeContract.collection(collectionAddress, 'nft', owner);
 
-    result = await collectionEvm.methods.setCollectionSponsor(sponsor).send();
+    await collectionEvm.methods.setCollectionSponsor(sponsor).send();
     let collectionData = (await collection.getData())!;
     expect(collectionData.raw.sponsorship.Unconfirmed).to.be.eq(helper.address.ethToSubstrate(sponsor, true));
     await expect(collectionEvm.methods.confirmCollectionSponsorship().call()).to.be.rejectedWith('caller is not set as sponsor');
 
-    const sponsorCollection = helper.ethNativeContract.collection(collectionIdAddress, 'nft', sponsor);
+    const sponsorCollection = helper.ethNativeContract.collection(collectionAddress, 'nft', sponsor);
     await sponsorCollection.methods.confirmCollectionSponsorship().send();
     collectionData = (await collection.getData())!;
     expect(collectionData.raw.sponsorship.Confirmed).to.be.eq(helper.address.ethToSubstrate(sponsor, true));
 
     const user = helper.eth.createAccount();
     await collectionEvm.methods.addCollectionAdmin(user).send();
-    
+
     const ownerBalanceBefore = await helper.balance.getSubstrate(helper.address.ethToSubstrate(owner));
     const sponsorBalanceBefore = await helper.balance.getSubstrate(helper.address.ethToSubstrate(sponsor));
 
-    const userCollectionEvm = helper.ethNativeContract.collection(collectionIdAddress, 'nft', user);
-    const nextTokenId = await userCollectionEvm.methods.nextTokenId().call();
-    expect(nextTokenId).to.be.equal('1');
-    result = await userCollectionEvm.methods.mintWithTokenURI(
-      user,
-      nextTokenId,
-      'Test URI',
-    ).send();
+    const userCollectionEvm = helper.ethNativeContract.collection(collectionAddress, 'nft', user);
+
+    let result = await userCollectionEvm.methods.mintWithTokenURI(user, 'Test URI',).send();
+    const tokenId = result.events.Transfer.returnValues.tokenId;
 
     const events = helper.eth.normalizeEvents(result.events);
     const address = helper.ethAddress.fromCollectionId(collectionId);
@@ -265,12 +249,12 @@
         args: {
           from: '0x0000000000000000000000000000000000000000',
           to: user,
-          tokenId: nextTokenId,
+          tokenId: '1',
         },
       },
     ]);
-    expect(await userCollectionEvm.methods.tokenURI(nextTokenId).call()).to.be.equal('Test URI');
-  
+    expect(await userCollectionEvm.methods.tokenURI(tokenId).call()).to.be.equal('Test URI');
+
     const ownerBalanceAfter = await helper.balance.getSubstrate(helper.address.ethToSubstrate(owner));
     expect(ownerBalanceAfter).to.be.eq(ownerBalanceBefore);
     const sponsorBalanceAfter = await helper.balance.getSubstrate(helper.address.ethToSubstrate(sponsor));
modifiedtests/src/eth/fractionalizer/Fractionalizer.soldiffbeforeafterboth
--- a/tests/src/eth/fractionalizer/Fractionalizer.sol
+++ b/tests/src/eth/fractionalizer/Fractionalizer.sol
@@ -124,8 +124,7 @@
 		address rftTokenAddress;
 		UniqueRefungibleToken rftTokenContract;
 		if (nft2rftMapping[_collection][_token] == 0) {
-			rftTokenId = rftCollectionContract.nextTokenId();
-			rftCollectionContract.mint(address(this), rftTokenId);
+            rftTokenId = rftCollectionContract.mint(address(this));
 			rftTokenAddress = rftCollectionContract.tokenContractAddress(rftTokenId);
 			nft2rftMapping[_collection][_token] = rftTokenId;
 			rft2nftMapping[rftTokenAddress] = Token(_collection, _token);
modifiedtests/src/eth/fractionalizer/fractionalizer.test.tsdiffbeforeafterboth
before · tests/src/eth/fractionalizer/fractionalizer.test.ts
1// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.2// This file is part of Unique Network.34// Unique Network is free software: you can redistribute it and/or modify5// it under the terms of the GNU General Public License as published by6// the Free Software Foundation, either version 3 of the License, or7// (at your option) any later version.89// Unique Network is distributed in the hope that it will be useful,10// but WITHOUT ANY WARRANTY; without even the implied warranty of11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the12// GNU General Public License for more details.1314// You should have received a copy of the GNU General Public License15// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.161718import {readFile} from 'fs/promises';1920import {IKeyringPair} from '@polkadot/types/types';21import {evmToAddress} from '@polkadot/util-crypto';2223import {Contract} from 'web3-eth-contract';2425import {usingEthPlaygrounds, expect, itEth, EthUniqueHelper} from '../util/playgrounds';26import {CompiledContract} from '../util/playgrounds/types';27import {requirePalletsOrSkip, Pallets} from '../../util/playgrounds';282930let compiledFractionalizer: CompiledContract;3132const compileContract = async (helper: EthUniqueHelper): Promise<CompiledContract> => {33  if(!compiledFractionalizer) {34    compiledFractionalizer = await helper.ethContract.compile('Fractionalizer', (await readFile(`${__dirname}/Fractionalizer.sol`)).toString(), [35      {solPath: 'api/CollectionHelpers.sol', fsPath: `${__dirname}/../api/CollectionHelpers.sol`},36      {solPath: 'api/ContractHelpers.sol', fsPath: `${__dirname}/../api/ContractHelpers.sol`},37      {solPath: 'api/UniqueRefungibleToken.sol', fsPath: `${__dirname}/../api/UniqueRefungibleToken.sol`},38      {solPath: 'api/UniqueRefungible.sol', fsPath: `${__dirname}/../api/UniqueRefungible.sol`},39      {solPath: 'api/UniqueNFT.sol', fsPath: `${__dirname}/../api/UniqueNFT.sol`},40    ]);41  }42  return compiledFractionalizer;43};444546const deployContract = async (helper: EthUniqueHelper, owner: string): Promise<Contract> => {47  const compiled = await compileContract(helper);48  return await helper.ethContract.deployByAbi(owner, compiled.abi, compiled.object);49};505152const initContract = async (helper: EthUniqueHelper, owner: string): Promise<{contract: Contract, rftCollectionAddress: string}> => {53  const fractionalizer = await deployContract(helper, owner);54  const amount = 10n * helper.balance.getOneTokenNominal();55  const web3 = helper.getWeb3();56  await web3.eth.sendTransaction({from: owner, to: fractionalizer.options.address, value: `${amount}`, gas: helper.eth.DEFAULT_GAS});57  const result = await fractionalizer.methods.createAndSetRFTCollection('A', 'B', 'C').send({value: Number(2n * helper.balance.getOneTokenNominal())});58  const rftCollectionAddress = result.events.RFTCollectionSet.returnValues._collection;59  return {contract: fractionalizer, rftCollectionAddress};60};6162const mintRFTToken = async (helper: EthUniqueHelper, owner: string, fractionalizer: Contract, amount: bigint): Promise<{63  nftCollectionAddress: string, nftTokenId: number, rftTokenAddress: string64}> => {65  const nftCollection = await helper.eth.createNFTCollection(owner, 'nft', 'NFT collection', 'NFT');66  const nftContract = helper.ethNativeContract.collection(nftCollection.collectionAddress, 'nft', owner);67  const nftTokenId = await nftContract.methods.nextTokenId().call();68  await nftContract.methods.mint(owner, nftTokenId).send({from: owner});6970  await fractionalizer.methods.setNftCollectionIsAllowed(nftCollection.collectionAddress, true).send({from: owner});71  await nftContract.methods.approve(fractionalizer.options.address, nftTokenId).send({from: owner});72  const result = await fractionalizer.methods.nft2rft(nftCollection.collectionAddress, nftTokenId, amount).send({from: owner});73  const {_collection, _tokenId, _rftToken} = result.events.Fractionalized.returnValues;74  return {75    nftCollectionAddress: _collection,76    nftTokenId: _tokenId,77    rftTokenAddress: _rftToken,78  };79};808182describe('Fractionalizer contract usage', () => {83  let donor: IKeyringPair;8485  before(async function() {86    await usingEthPlaygrounds(async (helper: EthUniqueHelper, privateKey) => {87      requirePalletsOrSkip(this, helper, [Pallets.ReFungible]);88      donor = privateKey('//Alice');89    });90  });9192  itEth('Set RFT collection', async ({helper}) => {93    const owner = await helper.eth.createAccountWithBalance(donor, 10n);94    const fractionalizer = await deployContract(helper, owner);95    const rftCollection = await helper.eth.createRFTCollection(owner, 'rft', 'RFT collection', 'RFT');96    const rftContract = helper.ethNativeContract.collection(rftCollection.collectionAddress, 'rft', owner);9798    await rftContract.methods.addCollectionAdmin(fractionalizer.options.address).send({from: owner});99    const result = await fractionalizer.methods.setRFTCollection(rftCollection.collectionAddress).send({from: owner});100    expect(result.events).to.be.like({101      RFTCollectionSet: {102        returnValues: {103          _collection: rftCollection.collectionAddress,104        },105      },106    });107  });108109  itEth('Mint RFT collection', async ({helper}) => {110    const owner = await helper.eth.createAccountWithBalance(donor, 10n);111    const fractionalizer = await deployContract(helper, owner);112    await helper.balance.transferToSubstrate(donor, evmToAddress(fractionalizer.options.address), 10n * helper.balance.getOneTokenNominal());113114    const result = await fractionalizer.methods.createAndSetRFTCollection('A', 'B', 'C').send({from: owner, value: Number(2n * helper.balance.getOneTokenNominal())});115    expect(result.events).to.be.like({116      RFTCollectionSet: {},117    });118    expect(result.events.RFTCollectionSet.returnValues._collection).to.be.ok;119  });120121  itEth('Set Allowlist', async ({helper}) => {122    const owner = await helper.eth.createAccountWithBalance(donor, 20n);123    const {contract: fractionalizer} = await initContract(helper, owner);124    const nftCollection = await helper.eth.createNFTCollection(owner, 'nft', 'NFT collection', 'NFT');125126    const result1 = await fractionalizer.methods.setNftCollectionIsAllowed(nftCollection.collectionAddress, true).send({from: owner});127    expect(result1.events).to.be.like({128      AllowListSet: {129        returnValues: {130          _collection: nftCollection.collectionAddress,131          _status: true,132        },133      },134    });135    const result2 = await fractionalizer.methods.setNftCollectionIsAllowed(nftCollection.collectionAddress, false).send({from: owner});136    expect(result2.events).to.be.like({137      AllowListSet: {138        returnValues: {139          _collection: nftCollection.collectionAddress,140          _status: false,141        },142      },143    });144  });145146  itEth('NFT to RFT', async ({helper}) => {147    const owner = await helper.eth.createAccountWithBalance(donor, 20n);148149    const nftCollection = await helper.eth.createNFTCollection(owner, 'nft', 'NFT collection', 'NFT');150    const nftContract = helper.ethNativeContract.collection(nftCollection.collectionAddress, 'nft', owner);151    const nftTokenId = await nftContract.methods.nextTokenId().call();152    await nftContract.methods.mint(owner, nftTokenId).send({from: owner});153154    const {contract: fractionalizer} = await initContract(helper, owner);155156    await fractionalizer.methods.setNftCollectionIsAllowed(nftCollection.collectionAddress, true).send({from: owner});157    await nftContract.methods.approve(fractionalizer.options.address, nftTokenId).send({from: owner});158    const result = await fractionalizer.methods.nft2rft(nftCollection.collectionAddress, nftTokenId, 100).send({from: owner});159    expect(result.events).to.be.like({160      Fractionalized: {161        returnValues: {162          _collection: nftCollection.collectionAddress,163          _tokenId: nftTokenId,164          _amount: '100',165        },166      },167    });168    const rftTokenAddress = result.events.Fractionalized.returnValues._rftToken;169170    const rftTokenContract = helper.ethNativeContract.rftToken(rftTokenAddress);171    expect(await rftTokenContract.methods.balanceOf(owner).call()).to.equal('100');172  });173174  itEth('RFT to NFT', async ({helper}) => {175    const owner = await helper.eth.createAccountWithBalance(donor, 20n);176177    const {contract: fractionalizer, rftCollectionAddress} = await initContract(helper, owner);178    const {rftTokenAddress, nftCollectionAddress, nftTokenId} = await mintRFTToken(helper, owner, fractionalizer, 100n);179180    const {collectionId, tokenId} = helper.ethAddress.extractTokenId(rftTokenAddress);181    const refungibleAddress = helper.ethAddress.fromCollectionId(collectionId);182    expect(rftCollectionAddress).to.be.equal(refungibleAddress);183    const refungibleTokenContract = helper.ethNativeContract.rftToken(rftTokenAddress, owner);184    await refungibleTokenContract.methods.approve(fractionalizer.options.address, 100).send({from: owner});185    const result = await fractionalizer.methods.rft2nft(refungibleAddress, tokenId).send({from: owner});186    expect(result.events).to.be.like({187      Defractionalized: {188        returnValues: {189          _rftToken: rftTokenAddress,190          _nftCollection: nftCollectionAddress,191          _nftTokenId: nftTokenId,192        },193      },194    });195  });196197  itEth('Test fractionalizer NFT <-> RFT mapping ', async ({helper}) => {198    const owner = await helper.eth.createAccountWithBalance(donor, 20n);199200    const {contract: fractionalizer, rftCollectionAddress} = await initContract(helper, owner);201    const {rftTokenAddress, nftCollectionAddress, nftTokenId} = await mintRFTToken(helper, owner, fractionalizer, 100n);202203    const {collectionId, tokenId} = helper.ethAddress.extractTokenId(rftTokenAddress);204    const refungibleAddress = helper.ethAddress.fromCollectionId(collectionId);205    expect(rftCollectionAddress).to.be.equal(refungibleAddress);206    const refungibleTokenContract = helper.ethNativeContract.rftToken(rftTokenAddress, owner);207    await refungibleTokenContract.methods.approve(fractionalizer.options.address, 100).send({from: owner});208209    const rft2nft = await fractionalizer.methods.rft2nftMapping(rftTokenAddress).call();210    expect(rft2nft).to.be.like({211      _collection: nftCollectionAddress,212      _tokenId: nftTokenId,213    });214215    const nft2rft = await fractionalizer.methods.nft2rftMapping(nftCollectionAddress, nftTokenId).call();216    expect(nft2rft).to.be.eq(tokenId.toString());217  });218});219220221222describe('Negative Integration Tests for fractionalizer', () => {223  let donor: IKeyringPair;224225  before(async function() {226    await usingEthPlaygrounds(async (helper: EthUniqueHelper, privateKey) => {227      requirePalletsOrSkip(this, helper, [Pallets.ReFungible]);228      donor = privateKey('//Alice');229    });230  });231232  itEth('call setRFTCollection twice', async ({helper}) => {233    const owner = await helper.eth.createAccountWithBalance(donor, 20n);234    const rftCollection = await helper.eth.createRFTCollection(owner, 'rft', 'RFT collection', 'RFT');235    const refungibleContract = helper.ethNativeContract.collection(rftCollection.collectionAddress, 'rft', owner);236237    const fractionalizer = await deployContract(helper, owner);238    await refungibleContract.methods.addCollectionAdmin(fractionalizer.options.address).send({from: owner});239    await fractionalizer.methods.setRFTCollection(rftCollection.collectionAddress).send({from: owner});240241    await expect(fractionalizer.methods.setRFTCollection(rftCollection.collectionAddress).call())242      .to.be.rejectedWith(/RFT collection is already set$/g);243  });244245  itEth('call setRFTCollection with NFT collection', async ({helper}) => {246    const owner = await helper.eth.createAccountWithBalance(donor, 20n);247    const nftCollection = await helper.eth.createNFTCollection(owner, 'nft', 'NFT collection', 'NFT');248    const nftContract = helper.ethNativeContract.collection(nftCollection.collectionAddress, 'nft', owner);249250    const fractionalizer = await deployContract(helper, owner);251    await nftContract.methods.addCollectionAdmin(fractionalizer.options.address).send({from: owner});252253    await expect(fractionalizer.methods.setRFTCollection(nftCollection.collectionAddress).call())254      .to.be.rejectedWith(/Wrong collection type. Collection is not refungible.$/g);255  });256257  itEth('call setRFTCollection while not collection admin', async ({helper}) => {258    const owner = await helper.eth.createAccountWithBalance(donor, 20n);259    const fractionalizer = await deployContract(helper, owner);260    const rftCollection = await helper.eth.createRFTCollection(owner, 'rft', 'RFT collection', 'RFT');261262    await expect(fractionalizer.methods.setRFTCollection(rftCollection.collectionAddress).call())263      .to.be.rejectedWith(/Fractionalizer contract should be an admin of the collection$/g);264  });265266  itEth('call setRFTCollection after createAndSetRFTCollection', async ({helper}) => {267    const owner = await helper.eth.createAccountWithBalance(donor, 20n);268    const fractionalizer = await deployContract(helper, owner);269    await helper.balance.transferToSubstrate(donor, evmToAddress(fractionalizer.options.address), 10n * helper.balance.getOneTokenNominal());270271    const result = await fractionalizer.methods.createAndSetRFTCollection('A', 'B', 'C').send({from: owner, value: Number(2n * helper.balance.getOneTokenNominal())});272    const collectionIdAddress = result.events.RFTCollectionSet.returnValues._collection;273274    await expect(fractionalizer.methods.setRFTCollection(collectionIdAddress).call())275      .to.be.rejectedWith(/RFT collection is already set$/g);276  });277278  itEth('call nft2rft without setting RFT collection for contract', async ({helper}) => {279    const owner = await helper.eth.createAccountWithBalance(donor, 20n);280281    const nftCollection = await helper.eth.createNFTCollection(owner, 'nft', 'NFT collection', 'NFT');282    const nftContract = helper.ethNativeContract.collection(nftCollection.collectionAddress, 'nft', owner);283    const nftTokenId = await nftContract.methods.nextTokenId().call();284    await nftContract.methods.mint(owner, nftTokenId).send({from: owner});285286    const fractionalizer = await deployContract(helper, owner);287288    await expect(fractionalizer.methods.nft2rft(nftCollection.collectionAddress, nftTokenId, 100).call())289      .to.be.rejectedWith(/RFT collection is not set$/g);290  });291292  itEth('call nft2rft while not owner of NFT token', async ({helper}) => {293    const owner = await helper.eth.createAccountWithBalance(donor, 20n);294    const nftOwner = await helper.eth.createAccountWithBalance(donor, 10n);295296    const nftCollection = await helper.eth.createNFTCollection(owner, 'nft', 'NFT collection', 'NFT');297    const nftContract = helper.ethNativeContract.collection(nftCollection.collectionAddress, 'nft', owner);298    const nftTokenId = await nftContract.methods.nextTokenId().call();299    await nftContract.methods.mint(owner, nftTokenId).send({from: owner});300    await nftContract.methods.transfer(nftOwner, 1).send({from: owner});301302303    const {contract: fractionalizer} = await initContract(helper, owner);304    await fractionalizer.methods.setNftCollectionIsAllowed(nftCollection.collectionAddress, true).send({from: owner});305306    await expect(fractionalizer.methods.nft2rft(nftCollection.collectionAddress, nftTokenId, 100).call({from: owner}))307      .to.be.rejectedWith(/Only token owner could fractionalize it$/g);308  });309310  itEth('call nft2rft while not in list of allowed accounts', async ({helper}) => {311    const owner = await helper.eth.createAccountWithBalance(donor, 20n);312313    const nftCollection = await helper.eth.createNFTCollection(owner, 'nft', 'NFT collection', 'NFT');314    const nftContract = helper.ethNativeContract.collection(nftCollection.collectionAddress, 'nft', owner);315    const nftTokenId = await nftContract.methods.nextTokenId().call();316    await nftContract.methods.mint(owner, nftTokenId).send({from: owner});317318    const {contract: fractionalizer} = await initContract(helper, owner);319320    await nftContract.methods.approve(fractionalizer.options.address, nftTokenId).send({from: owner});321    await expect(fractionalizer.methods.nft2rft(nftCollection.collectionAddress, nftTokenId, 100).call())322      .to.be.rejectedWith(/Fractionalization of this collection is not allowed by admin$/g);323  });324325  itEth('call nft2rft while fractionalizer doesnt have approval for nft token', async ({helper}) => {326    const owner = await helper.eth.createAccountWithBalance(donor, 20n);327328    const nftCollection = await helper.eth.createNFTCollection(owner, 'nft', 'NFT collection', 'NFT');329    const nftContract = helper.ethNativeContract.collection(nftCollection.collectionAddress, 'nft', owner);330    const nftTokenId = await nftContract.methods.nextTokenId().call();331    await nftContract.methods.mint(owner, nftTokenId).send({from: owner});332333    const {contract: fractionalizer} = await initContract(helper, owner);334335    await fractionalizer.methods.setNftCollectionIsAllowed(nftCollection.collectionAddress, true).send({from: owner});336    await expect(fractionalizer.methods.nft2rft(nftCollection.collectionAddress, nftTokenId, 100).call())337      .to.be.rejectedWith(/ApprovedValueTooLow$/g);338  });339340  itEth('call rft2nft without setting RFT collection for contract', async ({helper}) => {341    const owner = await helper.eth.createAccountWithBalance(donor, 20n);342343    const fractionalizer = await deployContract(helper, owner);344    const rftCollection = await helper.eth.createRFTCollection(owner, 'rft', 'RFT collection', 'RFT');345    const refungibleContract = helper.ethNativeContract.collection(rftCollection.collectionAddress, 'rft', owner);346    const rftTokenId = await refungibleContract.methods.nextTokenId().call();347    await refungibleContract.methods.mint(owner, rftTokenId).send({from: owner});348    349    await expect(fractionalizer.methods.rft2nft(rftCollection.collectionAddress, rftTokenId).call({from: owner}))350      .to.be.rejectedWith(/RFT collection is not set$/g);351  });352353  itEth('call rft2nft for RFT token that is not from configured RFT collection', async ({helper}) => {354    const owner = await helper.eth.createAccountWithBalance(donor, 20n);355356    const {contract: fractionalizer} = await initContract(helper, owner);357    const rftCollection = await helper.eth.createRFTCollection(owner, 'rft', 'RFT collection', 'RFT');358    const refungibleContract = helper.ethNativeContract.collection(rftCollection.collectionAddress, 'rft', owner);359    const rftTokenId = await refungibleContract.methods.nextTokenId().call();360    await refungibleContract.methods.mint(owner, rftTokenId).send({from: owner});361    362    await expect(fractionalizer.methods.rft2nft(rftCollection.collectionAddress, rftTokenId).call())363      .to.be.rejectedWith(/Wrong RFT collection$/g);364  });365366  itEth('call rft2nft for RFT token that was not minted by fractionalizer contract', async ({helper}) => {367    const owner = await helper.eth.createAccountWithBalance(donor, 20n);368    const rftCollection = await helper.eth.createRFTCollection(owner, 'rft', 'RFT collection', 'RFT');369    const refungibleContract = helper.ethNativeContract.collection(rftCollection.collectionAddress, 'rft', owner);370371    const fractionalizer = await deployContract(helper, owner);372373    await refungibleContract.methods.addCollectionAdmin(fractionalizer.options.address).send({from: owner});374    await fractionalizer.methods.setRFTCollection(rftCollection.collectionAddress).send({from: owner});375376    const rftTokenId = await refungibleContract.methods.nextTokenId().call();377    await refungibleContract.methods.mint(owner, rftTokenId).send({from: owner});378    379    await expect(fractionalizer.methods.rft2nft(rftCollection.collectionAddress, rftTokenId).call())380      .to.be.rejectedWith(/No corresponding NFT token found$/g);381  });382383  itEth('call rft2nft without owning all RFT pieces', async ({helper}) => {384    const owner = await helper.eth.createAccountWithBalance(donor, 20n);385    const receiver = await helper.eth.createAccountWithBalance(donor, 10n);386387    const {contract: fractionalizer, rftCollectionAddress} = await initContract(helper, owner);388    const {rftTokenAddress} = await mintRFTToken(helper, owner, fractionalizer, 100n);389    390    const {tokenId} = helper.ethAddress.extractTokenId(rftTokenAddress);391    const refungibleTokenContract = helper.ethNativeContract.rftToken(rftTokenAddress, owner);392    await refungibleTokenContract.methods.transfer(receiver, 50).send({from: owner});393    await refungibleTokenContract.methods.approve(fractionalizer.options.address, 50).send({from: receiver});394    await expect(fractionalizer.methods.rft2nft(rftCollectionAddress, tokenId).call({from: receiver}))395      .to.be.rejectedWith(/Not all pieces are owned by the caller$/g);396  });397398  itEth('send QTZ/UNQ to contract from non owner', async ({helper}) => {399    const owner = await helper.eth.createAccountWithBalance(donor, 20n);400    const payer = await helper.eth.createAccountWithBalance(donor, 10n);401402    const fractionalizer = await deployContract(helper, owner);403    const amount = 10n * helper.balance.getOneTokenNominal();404    const web3 = helper.getWeb3();405    await expect(web3.eth.sendTransaction({from: payer, to: fractionalizer.options.address, value: `${amount}`, gas: helper.eth.DEFAULT_GAS})).to.be.rejected;406  });407408  itEth('fractionalize NFT with NFT transfers disallowed', async ({helper}) => {409    const nftCollection = await helper.nft.mintCollection(donor, {name: 'A', description: 'B', tokenPrefix: 'C'});410411    const owner = await helper.eth.createAccountWithBalance(donor, 20n);412    const nftToken = await nftCollection.mintToken(donor, {Ethereum: owner});413    await helper.executeExtrinsic(donor, 'api.tx.unique.setTransfersEnabledFlag', [nftCollection.collectionId, false], true);414    const nftCollectionAddress = helper.ethAddress.fromCollectionId(nftCollection.collectionId);415    const {contract: fractionalizer} = await initContract(helper, owner);416    await fractionalizer.methods.setNftCollectionIsAllowed(nftCollectionAddress, true).send({from: owner});417418    const nftContract = helper.ethNativeContract.collection(nftCollectionAddress, 'nft', owner);419    await nftContract.methods.approve(fractionalizer.options.address, nftToken.tokenId).send({from: owner});420    await expect(fractionalizer.methods.nft2rft(nftCollectionAddress, nftToken.tokenId, 100).call())421      .to.be.rejectedWith(/TransferNotAllowed$/g);422  });423  424  itEth('fractionalize NFT with RFT transfers disallowed', async ({helper}) => {425    const owner = await helper.eth.createAccountWithBalance(donor, 20n);426427    const rftCollection = await helper.rft.mintCollection(donor, {name: 'A', description: 'B', tokenPrefix: 'C'});428    const rftCollectionAddress = helper.ethAddress.fromCollectionId(rftCollection.collectionId);429    const fractionalizer = await deployContract(helper, owner);430    await rftCollection.addAdmin(donor, {Ethereum: fractionalizer.options.address});431432    await fractionalizer.methods.setRFTCollection(rftCollectionAddress).send({from: owner});433    await helper.executeExtrinsic(donor, 'api.tx.unique.setTransfersEnabledFlag', [rftCollection.collectionId, false], true);434435    const nftCollection = await helper.eth.createNFTCollection(owner, 'nft', 'NFT collection', 'NFT');436    const nftContract = helper.ethNativeContract.collection(nftCollection.collectionAddress, 'nft', owner);437    const nftTokenId = await nftContract.methods.nextTokenId().call();438    await nftContract.methods.mint(owner, nftTokenId).send({from: owner});439440    await fractionalizer.methods.setNftCollectionIsAllowed(nftCollection.collectionAddress, true).send({from: owner});441    await nftContract.methods.approve(fractionalizer.options.address, nftTokenId).send({from: owner});442443    await expect(fractionalizer.methods.nft2rft(nftCollection.collectionAddress, nftTokenId, 100n).call())444      .to.be.rejectedWith(/TransferNotAllowed$/g);445  });446});
modifiedtests/src/eth/nesting/nest.test.tsdiffbeforeafterboth
--- a/tests/src/eth/nesting/nest.test.ts
+++ b/tests/src/eth/nesting/nest.test.ts
@@ -29,74 +29,53 @@
     itEth('NFT: allows an Owner to nest/unnest their token', async ({helper}) => {
       const owner = await helper.eth.createAccountWithBalance(donor);
       const {collectionId, contract} = await createNestingCollection(helper, owner);
-  
-      // Create a token to be nested
-      const targetNFTTokenId = await contract.methods.nextTokenId().call();
-      await contract.methods.mint(
-        owner,
-        targetNFTTokenId,
-      ).send({from: owner});
-  
+
+      // Create a token to be nested to
+      const mintingTargetNFTTokenIdResult = await contract.methods.mint(owner).send({from: owner});
+      const targetNFTTokenId = mintingTargetNFTTokenIdResult.events.Transfer.returnValues.tokenId;
       const targetNftTokenAddress = helper.ethAddress.fromTokenId(collectionId, targetNFTTokenId);
-  
+
       // Create a nested token
-      const firstTokenId = await contract.methods.nextTokenId().call();
-      await contract.methods.mint(
-        targetNftTokenAddress,
-        firstTokenId,
-      ).send({from: owner});
-  
+      const mintingFirstTokenIdResult = await contract.methods.mint(targetNftTokenAddress).send({from: owner});
+      const firstTokenId = mintingFirstTokenIdResult.events.Transfer.returnValues.tokenId;
       expect(await contract.methods.ownerOf(firstTokenId).call()).to.be.equal(targetNftTokenAddress);
-  
+
       // Create a token to be nested and nest
-      const secondTokenId = await contract.methods.nextTokenId().call();
-      await contract.methods.mint(
-        owner,
-        secondTokenId,
-      ).send({from: owner});
-  
+      const mintingSecondTokenIdResult = await contract.methods.mint(owner).send({from: owner});
+      const secondTokenId = mintingSecondTokenIdResult.events.Transfer.returnValues.tokenId;
+
       await contract.methods.transfer(targetNftTokenAddress, secondTokenId).send({from: owner});
-  
       expect(await contract.methods.ownerOf(secondTokenId).call()).to.be.equal(targetNftTokenAddress);
-  
+
       // Unnest token back
       await contract.methods.transferFrom(targetNftTokenAddress, owner, secondTokenId).send({from: owner});
       expect(await contract.methods.ownerOf(secondTokenId).call()).to.be.equal(owner);
     });
-  
+
     itEth('NFT: allows an Owner to nest/unnest their token (Restricted nesting)', async ({helper}) => {
       const owner = await helper.eth.createAccountWithBalance(donor);
-  
+
       const {collectionId: collectionIdA, collectionAddress: collectionAddressA, contract: contractA} = await createNestingCollection(helper, owner);
       const {collectionAddress: collectionAddressB, contract: contractB} = await createNestingCollection(helper, owner);
       await contractA.methods.setCollectionNesting(true, [collectionAddressA, collectionAddressB]).send({from: owner});
-  
+
       // Create a token to nest into
-      const targetNftTokenId = await contractA.methods.nextTokenId().call();
-      await contractA.methods.mint(
-        owner,
-        targetNftTokenId,
-      ).send({from: owner});
+      const mintingtargetNftTokenIdResult = await contractA.methods.mint(owner).send({from: owner});
+      const targetNftTokenId = mintingtargetNftTokenIdResult.events.Transfer.returnValues.tokenId;
       const nftTokenAddressA1 = helper.ethAddress.fromTokenId(collectionIdA, targetNftTokenId);
-  
+
       // Create a token for nesting in the same collection as the target
-      const nftTokenIdA = await contractA.methods.nextTokenId().call();
-      await contractA.methods.mint(
-        owner,
-        nftTokenIdA,
-      ).send({from: owner});
-  
+      const mintingTokenIdAResult = await contractA.methods.mint(owner).send({from: owner});
+      const nftTokenIdA = mintingTokenIdAResult.events.Transfer.returnValues.tokenId;
+
       // Create a token for nesting in a different collection
-      const nftTokenIdB = await contractB.methods.nextTokenId().call();
-      await contractB.methods.mint(
-        owner,
-        nftTokenIdB,
-      ).send({from: owner});
-  
+      const mintingTokenIdBResult = await contractB.methods.mint(owner).send({from: owner});
+      const nftTokenIdB = mintingTokenIdBResult.events.Transfer.returnValues.tokenId;
+
       // Nest
       await contractA.methods.transfer(nftTokenAddressA1, nftTokenIdA).send({from: owner});
       expect(await contractA.methods.ownerOf(nftTokenIdA).call()).to.be.equal(nftTokenAddressA1);
-  
+
       await contractB.methods.transfer(nftTokenAddressA1, nftTokenIdB).send({from: owner});
       expect(await contractB.methods.ownerOf(nftTokenIdB).call()).to.be.equal(nftTokenAddressA1);
     });
@@ -105,112 +84,88 @@
   describe('Negative Test: EVM Nesting', async() => {
     itEth('NFT: disallows to nest token if nesting is disabled', async ({helper}) => {
       const owner = await helper.eth.createAccountWithBalance(donor);
-  
+
       const {collectionId, contract} = await createNestingCollection(helper, owner);
       await contract.methods.setCollectionNesting(false).send({from: owner});
-  
+
       // Create a token to nest into
-      const targetNftTokenId = await contract.methods.nextTokenId().call();
-      await contract.methods.mint(
-        owner,
-        targetNftTokenId,
-      ).send({from: owner});
-  
-      const targetNftTokenAddress = helper.ethAddress.fromTokenId(collectionId, targetNftTokenId);
-  
+      const mintingTargetTokenIdResult = await contract.methods.mint(owner).send({from: owner});
+      const targetTokenId = mintingTargetTokenIdResult.events.Transfer.returnValues.tokenId;
+      const targetNftTokenAddress = helper.ethAddress.fromTokenId(collectionId, targetTokenId);
+
       // Create a token to nest
-      const nftTokenId = await contract.methods.nextTokenId().call();
-      await contract.methods.mint(
-        owner,
-        nftTokenId,
-      ).send({from: owner});
-  
+      const mintingNftTokenIdResult = await contract.methods.mint(owner).send({from: owner});
+      const nftTokenId = mintingNftTokenIdResult.events.Transfer.returnValues.tokenId;
+
       // Try to nest
       await expect(contract.methods
         .transfer(targetNftTokenAddress, nftTokenId)
         .call({from: owner})).to.be.rejectedWith('UserIsNotAllowedToNest');
     });
-  
+
     itEth('NFT: disallows a non-Owner to nest someone else\'s token', async ({helper}) => {
       const owner = await helper.eth.createAccountWithBalance(donor);
       const malignant = await helper.eth.createAccountWithBalance(donor);
-  
+
       const {collectionId, contract} = await createNestingCollection(helper, owner);
-  
+
       // Mint a token
-      const targetTokenId = await contract.methods.nextTokenId().call();
-      await contract.methods.mint(
-        owner,
-        targetTokenId,
-      ).send({from: owner});
+      const mintingTargetTokenIdResult = await contract.methods.mint(owner).send({from: owner});
+      const targetTokenId = mintingTargetTokenIdResult.events.Transfer.returnValues.tokenId;
       const targetTokenAddress = helper.ethAddress.fromTokenId(collectionId, targetTokenId);
-  
+
       // Mint a token belonging to a different account
-      const tokenId = await contract.methods.nextTokenId().call();
-      await contract.methods.mint(
-        malignant,
-        tokenId,
-      ).send({from: owner});
-  
+      const mintingTokenIdResult = await contract.methods.mint(malignant).send({from: owner});
+      const tokenId = mintingTokenIdResult.events.Transfer.returnValues.tokenId;
+
       // Try to nest one token in another as a non-owner account
       await expect(contract.methods
         .transfer(targetTokenAddress, tokenId)
         .call({from: malignant})).to.be.rejectedWith('UserIsNotAllowedToNest');
     });
-  
+
     itEth('NFT: disallows a non-Owner to nest someone else\'s token (Restricted nesting)', async ({helper}) => {
       const owner = await helper.eth.createAccountWithBalance(donor);
       const malignant = await helper.eth.createAccountWithBalance(donor);
-  
+
       const {collectionId: collectionIdA, collectionAddress: collectionAddressA, contract: contractA} = await createNestingCollection(helper, owner);
       const {collectionAddress: collectionAddressB, contract: contractB} = await createNestingCollection(helper, owner);
-  
+
       await contractA.methods.setCollectionNesting(true, [collectionAddressA, collectionAddressB]).send({from: owner});
-  
+
       // Create a token in one collection
-      const nftTokenIdA = await contractA.methods.nextTokenId().call();
-      await contractA.methods.mint(
-        owner,
-        nftTokenIdA,
-      ).send({from: owner});
+      const mintingTokenIdAResult = await contractA.methods.mint(owner).send({from: owner});
+      const nftTokenIdA = mintingTokenIdAResult.events.Transfer.returnValues.tokenId;
       const nftTokenAddressA = helper.ethAddress.fromTokenId(collectionIdA, nftTokenIdA);
-  
-      // Create a token in another collection belonging to someone else
-      const nftTokenIdB = await contractB.methods.nextTokenId().call();
-      await contractB.methods.mint(
-        malignant,
-        nftTokenIdB,
-      ).send({from: owner});
-  
+
+      // Create a token in another collection
+      const mintingTokenIdBResult = await contractB.methods.mint(malignant).send({from: owner});
+      const nftTokenIdB = mintingTokenIdBResult.events.Transfer.returnValues.tokenId;
+
       // Try to drag someone else's token into the other collection and nest
       await expect(contractB.methods
         .transfer(nftTokenAddressA, nftTokenIdB)
         .call({from: malignant})).to.be.rejectedWith('UserIsNotAllowedToNest');
     });
-  
+
     itEth('NFT: disallows to nest token in an unlisted collection', async ({helper}) => {
       const owner = await helper.eth.createAccountWithBalance(donor);
-  
+
       const {collectionId: collectionIdA, collectionAddress: collectionAddressA, contract: contractA} = await createNestingCollection(helper, owner);
       const {contract: contractB} = await createNestingCollection(helper, owner);
-  
+
       await contractA.methods.setCollectionNesting(true, [collectionAddressA]).send({from: owner});
-  
+
       // Create a token in one collection
-      const nftTokenIdA = await contractA.methods.nextTokenId().call();
-      await contractA.methods.mint(
-        owner,
-        nftTokenIdA,
-      ).send({from: owner});
+      const mintingTokenIdAResult = await contractA.methods.mint(owner).send({from: owner});
+      const nftTokenIdA = mintingTokenIdAResult.events.Transfer.returnValues.tokenId;
       const nftTokenAddressA = helper.ethAddress.fromTokenId(collectionIdA, nftTokenIdA);
-  
+
       // Create a token in another collection
-      const nftTokenIdB = await contractB.methods.nextTokenId().call();
-      await contractB.methods.mint(
-        owner,
-        nftTokenIdB,
-      ).send({from: owner});
-  
+      const mintingTokenIdBResult = await contractB.methods.mint(owner).send({from: owner});
+      const nftTokenIdB = mintingTokenIdBResult.events.Transfer.returnValues.tokenId;
+
+
       // Try to nest into a token in the other collection, disallowed in the first
       await expect(contractB.methods
         .transfer(nftTokenAddressA, nftTokenIdB)
modifiedtests/src/eth/nonFungible.test.tsdiffbeforeafterboth
--- a/tests/src/eth/nonFungible.test.ts
+++ b/tests/src/eth/nonFungible.test.ts
@@ -29,7 +29,7 @@
       [alice] = await helper.arrange.createAccounts([10n], donor);
     });
   });
-  
+
   itEth('totalSupply', async ({helper}) => {
     const collection = await helper.nft.mintCollection(alice, {});
     await collection.mintToken(alice);
@@ -95,26 +95,23 @@
 
     const {collectionAddress} = await helper.eth.createERC721MetadataCompatibleNFTCollection(owner, 'Mint collection', 'a', 'b', baseUri);
     const contract = helper.ethNativeContract.collection(collectionAddress, 'nft', owner);
-    
-    const nextTokenId = await contract.methods.nextTokenId().call();
-    expect(nextTokenId).to.be.equal('1');
-    const result = await contract.methods.mint(
-      receiver,
-      nextTokenId,
-    ).send();
 
+    const result = await contract.methods.mint(receiver).send();
+    const tokenId = result.events.Transfer.returnValues.tokenId;
+    expect(tokenId).to.be.equal('1');
+
     if (propertyKey && propertyValue) {
       // Set URL or suffix
-      await contract.methods.setProperty(nextTokenId, propertyKey, Buffer.from(propertyValue)).send();
+      await contract.methods.setProperty(tokenId, propertyKey, Buffer.from(propertyValue)).send();
     }
 
     const event = result.events.Transfer;
     expect(event.address).to.be.equal(collectionAddress);
     expect(event.returnValues.from).to.be.equal('0x0000000000000000000000000000000000000000');
     expect(event.returnValues.to).to.be.equal(receiver);
-    expect(event.returnValues.tokenId).to.be.equal(nextTokenId);
+    expect(event.returnValues.tokenId).to.be.equal(tokenId);
 
-    return {contract, nextTokenId};
+    return {contract, nextTokenId: tokenId};
   }
 
   itEth('Empty tokenURI', async ({helper}) => {
@@ -156,22 +153,17 @@
 
     const {collectionAddress} = await helper.eth.createERC721MetadataCompatibleNFTCollection(owner, 'Mint collection', '6', '6', '');
     const contract = helper.ethNativeContract.collection(collectionAddress, 'nft', owner);
-    const nextTokenId = await contract.methods.nextTokenId().call();
 
-    expect(nextTokenId).to.be.equal('1');
-    const result = await contract.methods.mintWithTokenURI(
-      receiver,
-      nextTokenId,
-      'Test URI',
-    ).send();
+    const result = await contract.methods.mintWithTokenURI(receiver, 'Test URI').send();
+    const tokenId = result.events.Transfer.returnValues.tokenId;
+    expect(tokenId).to.be.equal('1');
 
     const event = result.events.Transfer;
     expect(event.address).to.be.equal(collectionAddress);
     expect(event.returnValues.from).to.be.equal('0x0000000000000000000000000000000000000000');
     expect(event.returnValues.to).to.be.equal(receiver);
-    expect(event.returnValues.tokenId).to.be.equal(nextTokenId);
 
-    expect(await contract.methods.tokenURI(nextTokenId).call()).to.be.equal('Test URI');
+    expect(await contract.methods.tokenURI(tokenId).call()).to.be.equal('Test URI');
 
     // TODO: this wont work right now, need release 919000 first
     // await helper.methods.setOffchainSchema(collectionIdAddress, 'https://offchain-service.local/token-info/{id}').send();
@@ -224,7 +216,7 @@
 
     {
       const result = await contract.methods.burn(tokenId).send({from: caller});
-      
+
       const event = result.events.Transfer;
       expect(event.address).to.be.equal(collectionAddress);
       expect(event.returnValues.from).to.be.equal(caller);
@@ -330,7 +322,7 @@
       [alice] = await helper.arrange.createAccounts([10n], donor);
     });
   });
-  
+
   itEth('approve() call fee is less than 0.2UNQ', async ({helper}) => {
     const owner = await helper.eth.createAccountWithBalance(donor);
     const spender = helper.eth.createAccount();
@@ -409,7 +401,7 @@
 
     const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId);
     const contract = helper.ethNativeContract.collection(collectionAddress, 'nft');
-    
+
     const events: any = [];
     contract.events.allEvents((_: any, event: any) => {
       events.push(event);
@@ -433,7 +425,7 @@
 
     const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId);
     const contract = helper.ethNativeContract.collection(collectionAddress, 'nft');
-    
+
     const events: any = [];
     contract.events.allEvents((_: any, event: any) => {
       events.push(event);
@@ -459,14 +451,14 @@
 
     const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId);
     const contract = helper.ethNativeContract.collection(collectionAddress, 'nft');
-    
+
     const events: any = [];
     contract.events.allEvents((_: any, event: any) => {
       events.push(event);
     });
 
     await token.transferFrom(bob, {Substrate: alice.address}, {Ethereum: receiver});
-    
+
     const event = events[0];
     expect(event.address).to.be.equal(collectionAddress);
     expect(event.returnValues.from).to.be.equal(helper.address.substrateToEth(alice.address));
@@ -482,14 +474,14 @@
 
     const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId);
     const contract = helper.ethNativeContract.collection(collectionAddress, 'nft');
-    
+
     const events: any = [];
     contract.events.allEvents((_: any, event: any) => {
       events.push(event);
     });
 
     await token.transfer(alice, {Ethereum: receiver});
-    
+
     const event = events[0];
     expect(event.address).to.be.equal(collectionAddress);
     expect(event.returnValues.from).to.be.equal(helper.address.substrateToEth(alice.address));
@@ -558,4 +550,4 @@
     const symbol = await contract.methods.symbol().call();
     expect(symbol).to.equal('CHANGE');
   });
-});
\ No newline at end of file
+});
modifiedtests/src/eth/payable.test.tsdiffbeforeafterboth
--- a/tests/src/eth/payable.test.ts
+++ b/tests/src/eth/payable.test.ts
@@ -118,7 +118,7 @@
     const deployer = await helper.eth.createAccountWithBalance(donor);
     const caller = await helper.eth.createAccountWithBalance(donor);
     const contract = await helper.eth.deployFlipper(deployer);
-    
+
     const initialCallerBalance = await helper.balance.getEthereum(caller);
     await contract.methods.flip().send({from: caller});
     const finalCallerBalance = await helper.balance.getEthereum(caller);
@@ -129,7 +129,7 @@
     const deployer = await helper.eth.createAccountWithBalance(donor);
     const caller = await helper.eth.createAccountWithBalance(donor);
     const contract = await deployProxyContract(helper, deployer);
-    
+
     const initialCallerBalance = await helper.balance.getEthereum(caller);
     const initialContractBalance = await helper.balance.getEthereum(contract.options.address);
     await contract.methods.flip().send({from: caller});
@@ -138,7 +138,7 @@
     expect(finalCallerBalance < initialCallerBalance).to.be.true;
     expect(finalContractBalance == initialContractBalance).to.be.true;
   });
-  
+
   itEth('Fee for nested calls to native methods is withdrawn from the user', async({helper}) => {
     const CONTRACT_BALANCE = 2n * helper.balance.getOneTokenNominal();
 
@@ -155,7 +155,7 @@
     expect(finalCallerBalance < initialCallerBalance).to.be.true;
     expect(finalContractBalance == initialContractBalance).to.be.true;
   });
-  
+
   itEth('Fee for nested calls to create*Collection methods is withdrawn from the user and from the contract', async({helper}) => {
     const CONTRACT_BALANCE = 2n * helper.balance.getOneTokenNominal();
     const deployer = await helper.eth.createAccountWithBalance(donor);
@@ -176,7 +176,7 @@
     const BIG_FEE = 3n * helper.balance.getOneTokenNominal();
     const caller = await helper.eth.createAccountWithBalance(donor);
     const collectionHelper = helper.ethNativeContract.collectionHelpers(caller);
-        
+
     await expect(collectionHelper.methods.createNFTCollection('A', 'B', 'C').call({value: Number(SMALL_FEE)})).to.be.rejectedWith('Sent amount not equals to collection creation price (2000000000000000000)');
     await expect(collectionHelper.methods.createNFTCollection('A', 'B', 'C').call({value: Number(BIG_FEE)})).to.be.rejectedWith('Sent amount not equals to collection creation price (2000000000000000000)');
   });
@@ -186,7 +186,7 @@
     const BIG_FEE = 3n * helper.balance.getOneTokenNominal();
     const caller = await helper.eth.createAccountWithBalance(donor);
     const collectionHelper = helper.ethNativeContract.collectionHelpers(caller);
-        
+
     await expect(collectionHelper.methods.createRFTCollection('A', 'B', 'C').call({value: Number(SMALL_FEE)})).to.be.rejectedWith('Sent amount not equals to collection creation price (2000000000000000000)');
     await expect(collectionHelper.methods.createRFTCollection('A', 'B', 'C').call({value: Number(BIG_FEE)})).to.be.rejectedWith('Sent amount not equals to collection creation price (2000000000000000000)');
   });
@@ -235,8 +235,7 @@
 
         function mintNftToken(address collectionAddress) external  {
           UniqueNFT collection = UniqueNFT(collectionAddress);
-          uint256 tokenId = collection.nextTokenId();
-          collection.mint(msg.sender, tokenId);
+          uint256 tokenId = collection.mint(msg.sender);
           emit TokenMinted(tokenId);
         }
 
modifiedtests/src/eth/proxy/UniqueNFTProxy.soldiffbeforeafterboth
--- a/tests/src/eth/proxy/UniqueNFTProxy.sol
+++ b/tests/src/eth/proxy/UniqueNFTProxy.sol
@@ -120,20 +120,19 @@
         return proxied.mintingFinished();
     }
 
-    function mint(address to, uint256 tokenId)
+    function mint(address to)
         external
         override
-        returns (bool)
+        returns (uint256)
     {
-        return proxied.mint(to, tokenId);
+        return proxied.mint(to);
     }
 
     function mintWithTokenURI(
         address to,
-        uint256 tokenId,
         string memory tokenUri
-    ) external override returns (bool) {
-        return proxied.mintWithTokenURI(to, tokenId, tokenUri);
+    ) external override returns (uint256) {
+        return proxied.mintWithTokenURI(to, tokenUri);
     }
 
     function finishMinting() external override returns (bool) {
@@ -169,7 +168,7 @@
         return proxied.mintBulk(to, tokenIds);
     }
 
-    function mintBulkWithTokenURI(address to, Tuple0[] memory tokens)
+    function mintBulkWithTokenURI(address to, Tuple6[] memory tokens)
         external
         override
         returns (bool)
modifiedtests/src/eth/proxy/nonFungibleProxy.test.tsdiffbeforeafterboth
--- a/tests/src/eth/proxy/nonFungibleProxy.test.ts
+++ b/tests/src/eth/proxy/nonFungibleProxy.test.ts
@@ -111,13 +111,10 @@
     await collectionEvmOwned.methods.addCollectionAdmin(contract.options.address).send();
 
     {
-      const nextTokenId = await contract.methods.nextTokenId().call();
-      expect(nextTokenId).to.be.equal('1');
-      const result = await contract.methods.mintWithTokenURI(
-        receiver,
-        nextTokenId,
-        'Test URI',
-      ).send({from: caller});
+      const result = await contract.methods.mintWithTokenURI(receiver, 'Test URI').send({from: caller});
+      const tokenId = result.events.Transfer.returnValues.tokenId;
+      expect(tokenId).to.be.equal('1');
+
       const events = helper.eth.normalizeEvents(result.events);
       events[0].address = events[0].address.toLocaleLowerCase();
 
@@ -128,12 +125,12 @@
           args: {
             from: '0x0000000000000000000000000000000000000000',
             to: receiver,
-            tokenId: nextTokenId,
+            tokenId,
           },
         },
       ]);
 
-      expect(await contract.methods.tokenURI(nextTokenId).call()).to.be.equal('Test URI');
+      expect(await contract.methods.tokenURI(tokenId).call()).to.be.equal('Test URI');
     }
   });
 
modifiedtests/src/eth/reFungible.test.tsdiffbeforeafterboth
--- a/tests/src/eth/reFungible.test.ts
+++ b/tests/src/eth/reFungible.test.ts
@@ -33,8 +33,9 @@
     const caller = await helper.eth.createAccountWithBalance(donor);
     const {collectionAddress} = await helper.eth.createRFTCollection(caller, 'TotalSupply', '6', '6');
     const contract = helper.ethNativeContract.collection(collectionAddress, 'rft', caller);
-    const nextTokenId = await contract.methods.nextTokenId().call();
-    await contract.methods.mint(caller, nextTokenId).send();
+
+    await contract.methods.mint(caller).send();
+
     const totalSupply = await contract.methods.totalSupply().call();
     expect(totalSupply).to.equal('1');
   });
@@ -44,18 +45,9 @@
     const {collectionAddress} = await helper.eth.createRFTCollection(caller, 'BalanceOf', '6', '6');
     const contract = helper.ethNativeContract.collection(collectionAddress, 'rft', caller);
 
-    {
-      const nextTokenId = await contract.methods.nextTokenId().call();
-      await contract.methods.mint(caller, nextTokenId).send();
-    }
-    {
-      const nextTokenId = await contract.methods.nextTokenId().call();
-      await contract.methods.mint(caller, nextTokenId).send();
-    }
-    {
-      const nextTokenId = await contract.methods.nextTokenId().call();
-      await contract.methods.mint(caller, nextTokenId).send();
-    }
+    await contract.methods.mint(caller).send();
+    await contract.methods.mint(caller).send();
+    await contract.methods.mint(caller).send();
 
     const balance = await contract.methods.balanceOf(caller).call();
     expect(balance).to.equal('3');
@@ -66,8 +58,8 @@
     const {collectionAddress} = await helper.eth.createRFTCollection(caller, 'OwnerOf', '6', '6');
     const contract = helper.ethNativeContract.collection(collectionAddress, 'rft', caller);
 
-    const tokenId = await contract.methods.nextTokenId().call();
-    await contract.methods.mint(caller, tokenId).send();
+    const result = await contract.methods.mint(caller).send();
+    const tokenId = result.events.Transfer.returnValues.tokenId;
 
     const owner = await contract.methods.ownerOf(tokenId).call();
     expect(owner).to.equal(caller);
@@ -79,8 +71,8 @@
     const {collectionId, collectionAddress} = await helper.eth.createRFTCollection(caller, 'OwnerOf-AfterBurn', '6', '6');
     const contract = helper.ethNativeContract.collection(collectionAddress, 'rft', caller);
 
-    const tokenId = await contract.methods.nextTokenId().call();
-    await contract.methods.mint(caller, tokenId).send();
+    const result = await contract.methods.mint(caller).send();
+    const tokenId = result.events.Transfer.returnValues.tokenId;
     const tokenContract = helper.ethNativeContract.rftTokenById(collectionId, tokenId, caller);
 
     await tokenContract.methods.repartition(2).send();
@@ -98,8 +90,8 @@
     const {collectionId, collectionAddress} = await helper.eth.createRFTCollection(caller, 'Partial-OwnerOf', '6', '6');
     const contract = helper.ethNativeContract.collection(collectionAddress, 'rft', caller);
 
-    const tokenId = await contract.methods.nextTokenId().call();
-    await contract.methods.mint(caller, tokenId).send();
+    const result = await contract.methods.mint(caller).send();
+    const tokenId = result.events.Transfer.returnValues.tokenId;
     const tokenContract = helper.ethNativeContract.rftTokenById(collectionId, tokenId, caller);
 
     await tokenContract.methods.repartition(2).send();
@@ -126,22 +118,17 @@
     const receiver = helper.eth.createAccount();
     const {collectionAddress} = await helper.eth.createERC721MetadataCompatibleRFTCollection(owner, 'Minty', '6', '6', '');
     const contract = helper.ethNativeContract.collection(collectionAddress, 'rft', owner);
-    
-    const nextTokenId = await contract.methods.nextTokenId().call();
-    expect(nextTokenId).to.be.equal('1');
-    const result = await contract.methods.mintWithTokenURI(
-      receiver,
-      nextTokenId,
-      'Test URI',
-    ).send();
 
+    const result = await contract.methods.mintWithTokenURI(receiver, 'Test URI').send();
+
     const event = result.events.Transfer;
     expect(event.address).to.equal(collectionAddress);
     expect(event.returnValues.from).to.equal('0x0000000000000000000000000000000000000000');
     expect(event.returnValues.to).to.equal(receiver);
-    expect(event.returnValues.tokenId).to.equal(nextTokenId);
+    const tokenId = event.returnValues.tokenId;
+    expect(tokenId).to.be.equal('1');
 
-    expect(await contract.methods.tokenURI(nextTokenId).call()).to.be.equal('Test URI');
+    expect(await contract.methods.tokenURI(tokenId).call()).to.be.equal('Test URI');
   });
 
   itEth('Can perform mintBulk()', async ({helper}) => {
@@ -182,8 +169,8 @@
     const {collectionAddress} = await helper.eth.createRFTCollection(caller, 'Burny', '6', '6');
     const contract = helper.ethNativeContract.collection(collectionAddress, 'rft', caller);
 
-    const tokenId = await contract.methods.nextTokenId().call();
-    await contract.methods.mint(caller, tokenId).send();
+    const result = await contract.methods.mint(caller).send();
+    const tokenId = result.events.Transfer.returnValues.tokenId;
     {
       const result = await contract.methods.burn(tokenId).send();
       const event = result.events.Transfer;
@@ -200,9 +187,10 @@
     const {collectionId, collectionAddress} = await helper.eth.createRFTCollection(caller, 'TransferFromy', '6', '6');
     const contract = helper.ethNativeContract.collection(collectionAddress, 'rft', caller);
 
-    const tokenId = await contract.methods.nextTokenId().call();
+    const result = await contract.methods.mint(caller).send();
+    const tokenId = result.events.Transfer.returnValues.tokenId;
+
     const tokenAddress = helper.ethAddress.fromTokenId(collectionId, tokenId);
-    await contract.methods.mint(caller, tokenId).send();
 
     const tokenContract = helper.ethNativeContract.rftToken(tokenAddress, caller);
     await tokenContract.methods.repartition(15).send();
@@ -244,12 +232,12 @@
     const {collectionAddress} = await helper.eth.createRFTCollection(caller, 'Transferry', '6', '6');
     const contract = helper.ethNativeContract.collection(collectionAddress, 'rft', caller);
 
-    const tokenId = await contract.methods.nextTokenId().call();
-    await contract.methods.mint(caller, tokenId).send();
+    const result = await contract.methods.mint(caller).send();
+    const tokenId = result.events.Transfer.returnValues.tokenId;
 
     {
       const result = await contract.methods.transfer(receiver, tokenId).send();
-      
+
       const event = result.events.Transfer;
       expect(event.address).to.equal(collectionAddress);
       expect(event.returnValues.from).to.equal(caller);
@@ -274,8 +262,8 @@
     const {collectionId, collectionAddress} = await helper.eth.createRFTCollection(caller, 'Transferry-Partial-to-Full', '6', '6');
     const contract = helper.ethNativeContract.collection(collectionAddress, 'rft', caller);
 
-    const tokenId = await contract.methods.nextTokenId().call();
-    await contract.methods.mint(caller, tokenId).send();
+    const result = await contract.methods.mint(caller).send();
+    const tokenId = result.events.Transfer.returnValues.tokenId;
 
     const tokenContract = helper.ethNativeContract.rftTokenById(collectionId, tokenId, caller);
 
@@ -301,8 +289,8 @@
     const {collectionId, collectionAddress} = await helper.eth.createRFTCollection(caller, 'Transferry-Full-to-Partial', '6', '6');
     const contract = helper.ethNativeContract.collection(collectionAddress, 'rft', caller);
 
-    const tokenId = await contract.methods.nextTokenId().call();
-    await contract.methods.mint(caller, tokenId).send();
+    const result = await contract.methods.mint(caller).send();
+    const tokenId = result.events.Transfer.returnValues.tokenId;
 
     const tokenContract = helper.ethNativeContract.rftTokenById(collectionId, tokenId, caller);
 
@@ -339,8 +327,8 @@
     const {collectionAddress} = await helper.eth.createRFTCollection(caller, 'Feeful-Transfer-From', '6', '6');
     const contract = helper.ethNativeContract.collection(collectionAddress, 'rft', caller);
 
-    const tokenId = await contract.methods.nextTokenId().call();
-    await contract.methods.mint(caller, tokenId).send();
+    const result = await contract.methods.mint(caller).send();
+    const tokenId = result.events.Transfer.returnValues.tokenId;
 
     const cost = await helper.eth.recordCallFee(caller, () => contract.methods.transferFrom(caller, receiver, tokenId).send());
     expect(cost < BigInt(0.2 * Number(helper.balance.getOneTokenNominal())));
@@ -353,8 +341,8 @@
     const {collectionAddress} = await helper.eth.createRFTCollection(caller, 'Feeful-Transfer', '6', '6');
     const contract = helper.ethNativeContract.collection(collectionAddress, 'rft', caller);
 
-    const tokenId = await contract.methods.nextTokenId().call();
-    await contract.methods.mint(caller, tokenId).send();
+    const result = await contract.methods.mint(caller).send();
+    const tokenId = result.events.Transfer.returnValues.tokenId;
 
     const cost = await helper.eth.recordCallFee(caller, () => contract.methods.transfer(receiver, tokenId).send());
     expect(cost < BigInt(0.2 * Number(helper.balance.getOneTokenNominal())));
@@ -394,7 +382,7 @@
         tokenPropertyPermissions,
       },
     );
-    
+
     const contract = helper.ethNativeContract.collectionById(collection.collectionId, 'rft', caller);
     const name = await contract.methods.name().call();
     expect(name).to.equal('Leviathan');
modifiedtests/src/eth/reFungibleToken.test.tsdiffbeforeafterboth
--- a/tests/src/eth/reFungibleToken.test.ts
+++ b/tests/src/eth/reFungibleToken.test.ts
@@ -82,26 +82,22 @@
 
     const {collectionAddress} = await helper.eth.createERC721MetadataCompatibleRFTCollection(owner, 'Mint collection', 'a', 'b', baseUri);
     const contract = helper.ethNativeContract.collection(collectionAddress, 'rft', owner);
-    
-    const nextTokenId = await contract.methods.nextTokenId().call();
-    expect(nextTokenId).to.be.equal('1');
-    const result = await contract.methods.mint(
-      receiver,
-      nextTokenId,
-    ).send();
 
-    if (propertyKey && propertyValue) {
-      // Set URL or suffix
-      await contract.methods.setProperty(nextTokenId, propertyKey, Buffer.from(propertyValue)).send();
-    }
+    const result = await contract.methods.mint(receiver).send();
 
     const event = result.events.Transfer;
+    const tokenId = event.returnValues.tokenId;
+    expect(tokenId).to.be.equal('1');
     expect(event.address).to.be.equal(collectionAddress);
     expect(event.returnValues.from).to.be.equal('0x0000000000000000000000000000000000000000');
     expect(event.returnValues.to).to.be.equal(receiver);
-    expect(event.returnValues.tokenId).to.be.equal(nextTokenId);
 
-    return {contract, nextTokenId};
+    if (propertyKey && propertyValue) {
+      // Set URL or suffix
+      await contract.methods.setProperty(tokenId, propertyKey, Buffer.from(propertyValue)).send();
+    }
+
+    return {contract, nextTokenId: tokenId};
   }
 
   itEth('Empty tokenURI', async ({helper}) => {
@@ -295,8 +291,8 @@
     const {collectionId, collectionAddress} = await helper.eth.createRFTCollection(caller, 'Devastation', '6', '6');
     const contract = helper.ethNativeContract.collection(collectionAddress, 'rft', caller);
 
-    const tokenId = await contract.methods.nextTokenId().call();
-    await contract.methods.mint(caller, tokenId).send();
+    const result = await contract.methods.mint(caller).send();
+    const tokenId = result.events.Transfer.returnValues.tokenId;
     const tokenAddress = helper.ethAddress.fromTokenId(collectionId, tokenId);
     const tokenContract = helper.ethNativeContract.rftToken(tokenAddress, caller);
 
@@ -479,9 +475,10 @@
 
     const {collectionId, collectionAddress} = await helper.eth.createRFTCollection(owner, 'Sands', '', 'GRAIN');
     const collectionContract = helper.ethNativeContract.collection(collectionAddress, 'rft', owner);
-    
-    const tokenId = await collectionContract.methods.nextTokenId().call();
-    await collectionContract.methods.mint(owner, tokenId).send();
+
+    const result = await collectionContract.methods.mint(owner).send();
+    const tokenId = result.events.Transfer.returnValues.tokenId;
+
     const tokenAddress = helper.ethAddress.fromTokenId(collectionId, tokenId);
     const tokenContract = helper.ethNativeContract.rftToken(tokenAddress, owner);
 
modifiedtests/src/eth/util/playgrounds/unique.dev.tsdiffbeforeafterboth
--- a/tests/src/eth/util/playgrounds/unique.dev.ts
+++ b/tests/src/eth/util/playgrounds/unique.dev.ts
@@ -43,12 +43,12 @@
     if(!imports) return function(path: string) {
       return {error: `File not found: ${path}`};
     };
-  
+
     const knownImports = {} as {[key: string]: string};
     for(const imp of imports) {
       knownImports[imp.solPath] = (await readFile(imp.fsPath)).toString();
     }
-  
+
     return function(path: string) {
       if(path in knownImports) return {contents: knownImports[path]};
       return {error: `File not found: ${path}`};
@@ -71,7 +71,7 @@
         },
       },
     }), {import: await this.findImports(imports)})).contracts[`${name}.sol`][name];
-  
+
     return {
       abi: out.abi,
       object: '0x' + out.evm.bytecode.object,
@@ -94,7 +94,7 @@
   }
 
 }
-  
+
 class NativeContractGroup extends EthGroupBase {
 
   contractHelpers(caller: string): Contract {
@@ -145,14 +145,14 @@
   async createAccountWithBalance(donor: IKeyringPair, amount=1000n) {
     const account = this.createAccount();
     await this.transferBalanceFromSubstrate(donor, account, amount);
-  
+
     return account;
   }
 
   async transferBalanceFromSubstrate(donor: IKeyringPair, recepient: string, amount=1000n, inTokens=true) {
     return await this.helper.balance.transferToSubstrate(donor, evmToAddress(recepient), amount * (inTokens ? this.helper.balance.getOneTokenNominal() : 1n));
   }
-  
+
   async getCollectionCreationFee(signer: string) {
     const collectionHelper = this.helper.ethNativeContract.collectionHelpers(signer);
     return await collectionHelper.methods.collectionCreationFee().call();
@@ -177,7 +177,7 @@
   async createNFTCollection(signer: string, name: string, description: string, tokenPrefix: string): Promise<{collectionId: number, collectionAddress: string}> {
     const collectionCreationPrice = this.helper.balance.getCollectionCreationPrice();
     const collectionHelper = this.helper.ethNativeContract.collectionHelpers(signer);
-        
+
     const result = await collectionHelper.methods.createNFTCollection(name, description, tokenPrefix).send({value: Number(collectionCreationPrice)});
 
     const collectionAddress = this.helper.ethAddress.normalizeAddress(result.events.CollectionCreated.returnValues.collectionId);
@@ -187,13 +187,11 @@
   }
 
   async createERC721MetadataCompatibleNFTCollection(signer: string, name: string, description: string, tokenPrefix: string, baseUri: string): Promise<{collectionId: number, collectionAddress: string}> {
-    const collectionCreationPrice = this.helper.balance.getCollectionCreationPrice();
     const collectionHelper = this.helper.ethNativeContract.collectionHelpers(signer);
-        
-    const result = await collectionHelper.methods.createERC721MetadataCompatibleNFTCollection(name, description, tokenPrefix, baseUri).send({value: Number(collectionCreationPrice)});
 
-    const collectionAddress = this.helper.ethAddress.normalizeAddress(result.events.CollectionCreated.returnValues.collectionId);
-    const collectionId = this.helper.ethAddress.extractCollectionId(collectionAddress);
+    const {collectionId, collectionAddress} = await this.createNFTCollection(signer, name, description, tokenPrefix)
+
+    await collectionHelper.methods.makeCollectionERC721MetadataCompatible(collectionAddress, baseUri).send();
 
     return {collectionId, collectionAddress};
   }
@@ -201,7 +199,7 @@
   async createRFTCollection(signer: string, name: string, description: string, tokenPrefix: string): Promise<{collectionId: number, collectionAddress: string}> {
     const collectionCreationPrice = this.helper.balance.getCollectionCreationPrice();
     const collectionHelper = this.helper.ethNativeContract.collectionHelpers(signer);
-        
+
     const result = await collectionHelper.methods.createRFTCollection(name, description, tokenPrefix).send({value: Number(collectionCreationPrice)});
 
     const collectionAddress = this.helper.ethAddress.normalizeAddress(result.events.CollectionCreated.returnValues.collectionId);
@@ -211,13 +209,11 @@
   }
 
   async createERC721MetadataCompatibleRFTCollection(signer: string, name: string, description: string, tokenPrefix: string, baseUri: string): Promise<{collectionId: number, collectionAddress: string}> {
-    const collectionCreationPrice = this.helper.balance.getCollectionCreationPrice();
     const collectionHelper = this.helper.ethNativeContract.collectionHelpers(signer);
-    
-    const result = await collectionHelper.methods.createERC721MetadataCompatibleRFTCollection(name, description, tokenPrefix, baseUri).send({value: Number(collectionCreationPrice)});
 
-    const collectionAddress = this.helper.ethAddress.normalizeAddress(result.events.CollectionCreated.returnValues.collectionId);
-    const collectionId = this.helper.ethAddress.extractCollectionId(collectionAddress);
+    const {collectionId, collectionAddress} = await this.createRFTCollection(signer, name, description, tokenPrefix)
+
+    await collectionHelper.methods.makeCollectionERC721MetadataCompatible(collectionAddress, baseUri).send();
 
     return {collectionId, collectionAddress};
   }
@@ -312,7 +308,7 @@
     };
     return await this.helper.arrange.calculcateFee(address, wrappedCode);
   }
-}  
+}
 
 class EthAddressGroup extends EthGroupBase {
   extractCollectionId(address: string): number {
@@ -343,8 +339,8 @@
   normalizeAddress(address: string): string {
     return '0x' + address.substring(address.length - 40);
   }
-}  
- 
+}
+
 export type EthUniqueHelperConstructor = new (...args: any[]) => EthUniqueHelper;
 
 export class EthUniqueHelper extends DevUniqueHelper {
@@ -396,4 +392,3 @@
     return newHelper;
   }
 }
-  
\ No newline at end of file