git.delta.rocks / unique-network / refs/commits / ed1eea85386f

difftreelog

tests(eth): NFT, RFT, FT tests refactored for playgrounds

Fahrrader2022-09-27parent: #edc6ac8.patch.diff
in: master

6 files changed

modifiedtests/package.jsondiffbeforeafterboth
--- a/tests/package.json
+++ b/tests/package.json
@@ -87,8 +87,11 @@
     "testLimits": "mocha --timeout 9999999 -r ts-node/register ./**/limits.test.ts",
     "testEthCreateNFTCollection": "mocha --timeout 9999999 -r ts-node/register ./**/eth/createNFTCollection.test.ts",
     "testEthCreateRFTCollection": "mocha --timeout 9999999 -r ts-node/register ./**/eth/createRFTCollection.test.ts",
+    "testEthNFT": "mocha --timeout 9999999 -r ts-node/register ./**/eth/nonFungible.test.ts",
     "testRFT": "mocha --timeout 9999999 -r ts-node/register ./**/refungible.test.ts",
+    "testEthRFT": "mocha --timeout 9999999 -r ts-node/register ./**/eth/reFungible.test.ts ./**/eth/reFungibleToken.test.ts",
     "testFT": "mocha --timeout 9999999 -r ts-node/register ./**/fungible.test.ts",
+    "testEthFT": "mocha --timeout 9999999 -r ts-node/register ./**/eth/fungible.test.ts",
     "testRPC": "mocha --timeout 9999999 -r ts-node/register ./**/rpc.test.ts",
     "testPromotion": "mocha --timeout 9999999 -r ts-node/register ./**/app-promotion.test.ts",
     "polkadot-types-fetch-metadata": "curl -H 'Content-Type: application/json' -d '{\"id\":\"1\", \"jsonrpc\":\"2.0\", \"method\": \"state_getMetadata\", \"params\":[]}' http://localhost:9933 > src/interfaces/metadata.json",
modifiedtests/src/eth/fungible.test.tsdiffbeforeafterboth
before · tests/src/eth/fungible.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/>.1617import {approveExpectSuccess, createCollection, createCollectionExpectSuccess, createFungibleItemExpectSuccess, transferExpectSuccess, transferFromExpectSuccess, UNIQUE} from '../util/helpers';18import {collectionIdToAddress, createEthAccount, createEthAccountWithBalance, evmCollection, GAS_ARGS, itWeb3, normalizeEvents, recordEthFee, recordEvents, subToEth, transferBalanceToEth} from './util/helpers';19import fungibleAbi from './fungibleAbi.json';20import {expect} from 'chai';21import {submitTransactionAsync} from '../substrate/substrate-api';2223describe('Fungible: Information getting', () => {24  itWeb3('totalSupply', async ({api, web3, privateKeyWrapper}) => {25    const collection = await createCollectionExpectSuccess({26      name: 'token name',27      mode: {type: 'Fungible', decimalPoints: 0},28    });29    const alice = privateKeyWrapper('//Alice');3031    const caller = await createEthAccountWithBalance(api, web3, privateKeyWrapper);3233    await createFungibleItemExpectSuccess(alice, collection, {Value: 200n}, {Substrate: alice.address});3435    const address = collectionIdToAddress(collection);36    const contract = new web3.eth.Contract(fungibleAbi as any, address, {from: caller, ...GAS_ARGS});37    const totalSupply = await contract.methods.totalSupply().call();3839    expect(totalSupply).to.equal('200');40  });4142  itWeb3('balanceOf', async ({api, web3, privateKeyWrapper}) => {43    const collection = await createCollectionExpectSuccess({44      name: 'token name',45      mode: {type: 'Fungible', decimalPoints: 0},46    });47    const alice = privateKeyWrapper('//Alice');4849    const caller = await createEthAccountWithBalance(api, web3, privateKeyWrapper);5051    await createFungibleItemExpectSuccess(alice, collection, {Value: 200n}, {Ethereum: caller});5253    const address = collectionIdToAddress(collection);54    const contract = new web3.eth.Contract(fungibleAbi as any, address, {from: caller, ...GAS_ARGS});55    const balance = await contract.methods.balanceOf(caller).call();5657    expect(balance).to.equal('200');58  });59});6061describe('Fungible: Plain calls', () => {62  itWeb3('Can perform mint()', async ({web3, api, privateKeyWrapper}) => {63    const alice = privateKeyWrapper('//Alice');64    const collection = await createCollection(api, alice, {65      name: 'token name',66      mode: {type: 'Fungible', decimalPoints: 0},67    });6869    const receiver = createEthAccount(web3);7071    const collectionIdAddress = collectionIdToAddress(collection.collectionId);72    const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);73    const changeAdminTx = api.tx.unique.addCollectionAdmin(collection.collectionId, {Ethereum: owner});74    await submitTransactionAsync(alice, changeAdminTx);7576    const collectionContract = evmCollection(web3, owner, collectionIdAddress, {type: 'Fungible', decimalPoints: 0});77    const result = await collectionContract.methods.mint(receiver, 100).send();78    const events = normalizeEvents(result.events);79    80    expect(events).to.be.deep.equal([81      {82        address: collectionIdAddress,83        event: 'Transfer',84        args: {85          from: '0x0000000000000000000000000000000000000000',86          to: receiver,87          value: '100',88        },89      },90    ]);91  });9293  itWeb3('Can perform mintBulk()', async ({web3, api, privateKeyWrapper}) => {94    const alice = privateKeyWrapper('//Alice');95    const collection = await createCollection(api, alice, {96      name: 'token name',97      mode: {type: 'Fungible', decimalPoints: 0},98    });99100    const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);101    const receiver1 = createEthAccount(web3);102    const receiver2 = createEthAccount(web3);103    const receiver3 = createEthAccount(web3);104105    const collectionIdAddress = collectionIdToAddress(collection.collectionId);106    const changeAdminTx = api.tx.unique.addCollectionAdmin(collection.collectionId, {Ethereum: owner});107    await submitTransactionAsync(alice, changeAdminTx);108109    const collectionContract = evmCollection(web3, owner, collectionIdAddress, {type: 'Fungible', decimalPoints: 0});110    const result = await collectionContract.methods.mintBulk([111      [receiver1, 10],112      [receiver2, 20],113      [receiver3, 30],114    ]).send();115    const events = normalizeEvents(result.events);116117    expect(events).to.be.deep.contain({118      address:collectionIdAddress,119      event: 'Transfer',120      args: {121        from: '0x0000000000000000000000000000000000000000',122        to: receiver1,123        value: '10',124      },125    });126    127    expect(events).to.be.deep.contain({128      address:collectionIdAddress,129      event: 'Transfer',130      args: {131        from: '0x0000000000000000000000000000000000000000',132        to: receiver2,133        value: '20',134      },135    });136    137    expect(events).to.be.deep.contain({138      address:collectionIdAddress,139      event: 'Transfer',140      args: {141        from: '0x0000000000000000000000000000000000000000',142        to: receiver3,143        value: '30',144      },145    });146  });147148  itWeb3('Can perform burn()', async ({web3, api, privateKeyWrapper}) => {149    const alice = privateKeyWrapper('//Alice');150    const collection = await createCollection(api, alice, {151      name: 'token name',152      mode: {type: 'Fungible', decimalPoints: 0},153    });154155    const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);156    const changeAdminTx = api.tx.unique.addCollectionAdmin(collection.collectionId, {Ethereum: owner});157    await submitTransactionAsync(alice, changeAdminTx);158    const receiver = await createEthAccountWithBalance(api, web3, privateKeyWrapper);159160    const collectionIdAddress = collectionIdToAddress(collection.collectionId);161    const collectionContract = evmCollection(web3, owner, collectionIdAddress, {type: 'Fungible', decimalPoints: 0});162    await collectionContract.methods.mint(receiver, 100).send();163164    const result = await collectionContract.methods.burnFrom(receiver, 49).send({from: receiver});165    166    const events = normalizeEvents(result.events);167168    expect(events).to.be.deep.equal([169      {170        address: collectionIdAddress,171        event: 'Transfer',172        args: {173          from: receiver,174          to: '0x0000000000000000000000000000000000000000',175          value: '49',176        },177      },178    ]);179180    const balance = await collectionContract.methods.balanceOf(receiver).call();181    expect(balance).to.equal('51');182  });183184  itWeb3('Can perform approve()', async ({web3, api, privateKeyWrapper}) => {185    const collection = await createCollectionExpectSuccess({186      name: 'token name',187      mode: {type: 'Fungible', decimalPoints: 0},188    });189    const alice = privateKeyWrapper('//Alice');190191    const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);192193    await createFungibleItemExpectSuccess(alice, collection, {Value: 200n}, {Ethereum: owner});194195    const spender = createEthAccount(web3);196197    const address = collectionIdToAddress(collection);198    const contract = new web3.eth.Contract(fungibleAbi as any, address, {from: owner, ...GAS_ARGS});199200    {201      const result = await contract.methods.approve(spender, 100).send({from: owner});202      const events = normalizeEvents(result.events);203204      expect(events).to.be.deep.equal([205        {206          address,207          event: 'Approval',208          args: {209            owner,210            spender,211            value: '100',212          },213        },214      ]);215    }216217    {218      const allowance = await contract.methods.allowance(owner, spender).call();219      expect(+allowance).to.equal(100);220    }221  });222223  itWeb3('Can perform transferFrom()', async ({web3, api, privateKeyWrapper}) => {224    const collection = await createCollectionExpectSuccess({225      name: 'token name',226      mode: {type: 'Fungible', decimalPoints: 0},227    });228    const alice = privateKeyWrapper('//Alice');229230    const owner = createEthAccount(web3);231    await transferBalanceToEth(api, alice, owner);232233    await createFungibleItemExpectSuccess(alice, collection, {Value: 200n}, {Ethereum: owner});234235    const spender = createEthAccount(web3);236    await transferBalanceToEth(api, alice, spender);237238    const receiver = createEthAccount(web3);239240    const address = collectionIdToAddress(collection);241    const contract = new web3.eth.Contract(fungibleAbi as any, address, {from: owner, ...GAS_ARGS});242243    await contract.methods.approve(spender, 100).send();244245    {246      const result = await contract.methods.transferFrom(owner, receiver, 49).send({from: spender});247      const events = normalizeEvents(result.events);248      expect(events).to.be.deep.equal([249        {250          address,251          event: 'Transfer',252          args: {253            from: owner,254            to: receiver,255            value: '49',256          },257        },258        {259          address,260          event: 'Approval',261          args: {262            owner,263            spender,264            value: '51',265          },266        },267      ]);268    }269270    {271      const balance = await contract.methods.balanceOf(receiver).call();272      expect(+balance).to.equal(49);273    }274275    {276      const balance = await contract.methods.balanceOf(owner).call();277      expect(+balance).to.equal(151);278    }279  });280281  itWeb3('Can perform transfer()', async ({web3, api, privateKeyWrapper}) => {282    const collection = await createCollectionExpectSuccess({283      name: 'token name',284      mode: {type: 'Fungible', decimalPoints: 0},285    });286    const alice = privateKeyWrapper('//Alice');287288    const owner = createEthAccount(web3);289    await transferBalanceToEth(api, alice, owner);290291    await createFungibleItemExpectSuccess(alice, collection, {Value: 200n}, {Ethereum: owner});292293    const receiver = createEthAccount(web3);294    await transferBalanceToEth(api, alice, receiver);295296    const address = collectionIdToAddress(collection);297    const contract = new web3.eth.Contract(fungibleAbi as any, address, {from: owner, ...GAS_ARGS});298299    {300      const result = await contract.methods.transfer(receiver, 50).send({from: owner});301      const events = normalizeEvents(result.events);302      expect(events).to.be.deep.equal([303        {304          address,305          event: 'Transfer',306          args: {307            from: owner,308            to: receiver,309            value: '50',310          },311        },312      ]);313    }314315    {316      const balance = await contract.methods.balanceOf(owner).call();317      expect(+balance).to.equal(150);318    }319320    {321      const balance = await contract.methods.balanceOf(receiver).call();322      expect(+balance).to.equal(50);323    }324  });325});326327describe('Fungible: Fees', () => {328  itWeb3('approve() call fee is less than 0.2UNQ', async ({web3, api, privateKeyWrapper}) => {329    const collection = await createCollectionExpectSuccess({330      mode: {type: 'Fungible', decimalPoints: 0},331    });332    const alice = privateKeyWrapper('//Alice');333334    const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);335    const spender = createEthAccount(web3);336337    await createFungibleItemExpectSuccess(alice, collection, {Value: 200n}, {Ethereum: owner});338339    const address = collectionIdToAddress(collection);340    const contract = new web3.eth.Contract(fungibleAbi as any, address, {from: owner, ...GAS_ARGS});341342    const cost = await recordEthFee(api, owner, () => contract.methods.approve(spender, 100).send({from: owner}));343    expect(cost < BigInt(0.2 * Number(UNIQUE)));344  });345346  itWeb3('transferFrom() call fee is less than 0.2UNQ', async ({web3, api, privateKeyWrapper}) => {347    const collection = await createCollectionExpectSuccess({348      mode: {type: 'Fungible', decimalPoints: 0},349    });350    const alice = privateKeyWrapper('//Alice');351352    const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);353    const spender = await createEthAccountWithBalance(api, web3, privateKeyWrapper);354355    await createFungibleItemExpectSuccess(alice, collection, {Value: 200n}, {Ethereum: owner});356357    const address = collectionIdToAddress(collection);358    const contract = new web3.eth.Contract(fungibleAbi as any, address, {from: owner, ...GAS_ARGS});359360    await contract.methods.approve(spender, 100).send({from: owner});361362    const cost = await recordEthFee(api, spender, () => contract.methods.transferFrom(owner, spender, 100).send({from: spender}));363    expect(cost < BigInt(0.2 * Number(UNIQUE)));364  });365366  itWeb3('transfer() call fee is less than 0.2UNQ', async ({web3, api, privateKeyWrapper}) => {367    const collection = await createCollectionExpectSuccess({368      mode: {type: 'Fungible', decimalPoints: 0},369    });370    const alice = privateKeyWrapper('//Alice');371372    const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);373    const receiver = createEthAccount(web3);374375    await createFungibleItemExpectSuccess(alice, collection, {Value: 200n}, {Ethereum: owner});376377    const address = collectionIdToAddress(collection);378    const contract = new web3.eth.Contract(fungibleAbi as any, address, {from: owner, ...GAS_ARGS});379380    const cost = await recordEthFee(api, owner, () => contract.methods.transfer(receiver, 100).send({from: owner}));381    expect(cost < BigInt(0.2 * Number(UNIQUE)));382  });383});384385describe('Fungible: Substrate calls', () => {386  itWeb3('Events emitted for approve()', async ({web3, privateKeyWrapper}) => {387    const collection = await createCollectionExpectSuccess({388      mode: {type: 'Fungible', decimalPoints: 0},389    });390    const alice = privateKeyWrapper('//Alice');391392    const receiver = createEthAccount(web3);393394    await createFungibleItemExpectSuccess(alice, collection, {Value: 200n});395396    const address = collectionIdToAddress(collection);397    const contract = new web3.eth.Contract(fungibleAbi as any, address);398399    const events = await recordEvents(contract, async () => {400      await approveExpectSuccess(collection, 0, alice, {Ethereum: receiver}, 100);401    });402403    expect(events).to.be.deep.equal([404      {405        address,406        event: 'Approval',407        args: {408          owner: subToEth(alice.address),409          spender: receiver,410          value: '100',411        },412      },413    ]);414  });415416  itWeb3('Events emitted for transferFrom()', async ({web3, privateKeyWrapper}) => {417    const collection = await createCollectionExpectSuccess({418      mode: {type: 'Fungible', decimalPoints: 0},419    });420    const alice = privateKeyWrapper('//Alice');421    const bob = privateKeyWrapper('//Bob');422423    const receiver = createEthAccount(web3);424425    await createFungibleItemExpectSuccess(alice, collection, {Value: 200n});426    await approveExpectSuccess(collection, 0, alice, bob.address, 100);427428    const address = collectionIdToAddress(collection);429    const contract = new web3.eth.Contract(fungibleAbi as any, address);430431    const events = await recordEvents(contract, async () => {432      await transferFromExpectSuccess(collection, 0, bob, alice, {Ethereum: receiver}, 51, 'Fungible');433    });434435    expect(events).to.be.deep.equal([436      {437        address,438        event: 'Transfer',439        args: {440          from: subToEth(alice.address),441          to: receiver,442          value: '51',443        },444      },445      {446        address,447        event: 'Approval',448        args: {449          owner: subToEth(alice.address),450          spender: subToEth(bob.address),451          value: '49',452        },453      },454    ]);455  });456457  itWeb3('Events emitted for transfer()', async ({web3, privateKeyWrapper}) => {458    const collection = await createCollectionExpectSuccess({459      mode: {type: 'Fungible', decimalPoints: 0},460    });461    const alice = privateKeyWrapper('//Alice');462463    const receiver = createEthAccount(web3);464465    await createFungibleItemExpectSuccess(alice, collection, {Value: 200n});466467    const address = collectionIdToAddress(collection);468    const contract = new web3.eth.Contract(fungibleAbi as any, address);469470    const events = await recordEvents(contract, async () => {471      await transferExpectSuccess(collection, 0, alice, {Ethereum:receiver}, 51, 'Fungible');472    });473474    expect(events).to.be.deep.equal([475      {476        address,477        event: 'Transfer',478        args: {479          from: subToEth(alice.address),480          to: receiver,481          value: '51',482        },483      },484    ]);485  });486});
modifiedtests/src/eth/nonFungible.test.tsdiffbeforeafterboth
--- a/tests/src/eth/nonFungible.test.ts
+++ b/tests/src/eth/nonFungible.test.ts
@@ -14,72 +14,78 @@
 // You should have received a copy of the GNU General Public License
 // along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
 
-import {approveExpectSuccess, burnItemExpectSuccess, createCollectionExpectSuccess, createItemExpectSuccess, transferExpectSuccess, transferFromExpectSuccess, UNIQUE} from '../util/helpers';
-import {collectionIdToAddress, createEthAccount, createEthAccountWithBalance, evmCollection, evmCollectionHelpers, GAS_ARGS, getCollectionAddressFromResult, itWeb3, normalizeEvents, recordEthFee, recordEvents, subToEth, transferBalanceToEth} from './util/helpers';
-import nonFungibleAbi from './nonFungibleAbi.json';
-import {expect} from 'chai';
-import {submitTransactionAsync} from '../substrate/substrate-api';
+import {itEth, usingEthPlaygrounds, expect, EthUniqueHelper} from './util/playgrounds';
+import {IKeyringPair} from '@polkadot/types/types';
+import {Contract} from 'web3-eth-contract';
 
 describe('NFT: Information getting', () => {
-  itWeb3('totalSupply', async ({api, web3, privateKeyWrapper}) => {
-    const collection = await createCollectionExpectSuccess({
-      mode: {type: 'NFT'},
+  let donor: IKeyringPair;
+  let alice: IKeyringPair;
+
+  before(async function() {
+    await usingEthPlaygrounds(async (helper, privateKey) => {
+      donor = privateKey('//Alice');
+      [alice] = await helper.arrange.createAccounts([10n], donor);
     });
-    const alice = privateKeyWrapper('//Alice');
-    const caller = await createEthAccountWithBalance(api, web3, privateKeyWrapper);
+  });
+  
+  itEth('totalSupply', async ({helper}) => {
+    const collection = await helper.nft.mintCollection(alice, {});
+    await collection.mintToken(alice);
 
-    await createItemExpectSuccess(alice, collection, 'NFT', {Substrate: alice.address});
+    const caller = await helper.eth.createAccountWithBalance(donor);
 
-    const address = collectionIdToAddress(collection);
-    const contract = new web3.eth.Contract(nonFungibleAbi as any, address, {from: caller, ...GAS_ARGS});
+    const contract = helper.ethNativeContract.collectionById(collection.collectionId, 'nft', caller);
     const totalSupply = await contract.methods.totalSupply().call();
 
     expect(totalSupply).to.equal('1');
   });
 
-  itWeb3('balanceOf', async ({api, web3, privateKeyWrapper}) => {
-    const collection = await createCollectionExpectSuccess({
-      mode: {type: 'NFT'},
-    });
-    const alice = privateKeyWrapper('//Alice');
+  itEth('balanceOf', async ({helper}) => {
+    const collection = await helper.nft.mintCollection(alice, {});
+    const caller = await helper.eth.createAccountWithBalance(donor);
 
-    const caller = await createEthAccountWithBalance(api, web3, privateKeyWrapper);
-    await createItemExpectSuccess(alice, collection, 'NFT', {Ethereum:caller});
-    await createItemExpectSuccess(alice, collection, 'NFT', {Ethereum: caller});
-    await createItemExpectSuccess(alice, collection, 'NFT', {Ethereum: caller});
+    await collection.mintToken(alice, {Ethereum: caller});
+    await collection.mintToken(alice, {Ethereum: caller});
+    await collection.mintToken(alice, {Ethereum: caller});
 
-    const address = collectionIdToAddress(collection);
-    const contract = new web3.eth.Contract(nonFungibleAbi as any, address, {from: caller, ...GAS_ARGS});
+    const contract = helper.ethNativeContract.collectionById(collection.collectionId, 'nft', caller);
     const balance = await contract.methods.balanceOf(caller).call();
 
     expect(balance).to.equal('3');
   });
 
-  itWeb3('ownerOf', async ({api, web3, privateKeyWrapper}) => {
-    const collection = await createCollectionExpectSuccess({
-      mode: {type: 'NFT'},
-    });
-    const alice = privateKeyWrapper('//Alice');
+  itEth('ownerOf', async ({helper}) => {
+    const collection = await helper.nft.mintCollection(alice, {});
+    const caller = await helper.eth.createAccountWithBalance(donor);
 
-    const caller = await createEthAccountWithBalance(api, web3, privateKeyWrapper);
-    const tokenId = await createItemExpectSuccess(alice, collection, 'NFT', {Ethereum: caller});
+    const token = await collection.mintToken(alice, {Ethereum: caller});
 
-    const address = collectionIdToAddress(collection);
-    const contract = new web3.eth.Contract(nonFungibleAbi as any, address, {from: caller, ...GAS_ARGS});
-    const owner = await contract.methods.ownerOf(tokenId).call();
+    const contract = helper.ethNativeContract.collectionById(collection.collectionId, 'nft', caller);
+
+    const owner = await contract.methods.ownerOf(token.tokenId).call();
 
     expect(owner).to.equal(caller);
   });
 });
 
 describe('Check ERC721 token URI for NFT', () => {
-  itWeb3('Empty tokenURI', async ({web3, api, privateKeyWrapper}) => {
-    const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);
-    const helper = evmCollectionHelpers(web3, owner);
-    let result = await helper.methods.createERC721MetadataCompatibleCollection('Mint collection', '1', '1', '').send();
-    const {collectionIdAddress, collectionId} = await getCollectionAddressFromResult(api, result);
-    const receiver = createEthAccount(web3);
-    const contract = evmCollection(web3, owner, collectionIdAddress);
+  let donor: IKeyringPair;
+
+  before(async function() {
+    await usingEthPlaygrounds(async (_helper, privateKey) => {
+      donor = privateKey('//Alice');
+    });
+  });
+
+  async function setup(helper: EthUniqueHelper, tokenPrefix: string, propertyKey?: string, propertyValue?: string): Promise<{contract: Contract, nextTokenId: string}> {
+    const owner = await helper.eth.createAccountWithBalance(donor);
+    const receiver = helper.eth.createAccount();
+
+    const collectionHelper = helper.ethNativeContract.collectionHelpers(owner);
+    let result = await collectionHelper.methods.createERC721MetadataCompatibleCollection('Mint collection', 'a', 'b', tokenPrefix).send();
+    const collectionAddress = helper.ethAddress.normalizeAddress(result.events.CollectionCreated.returnValues.collectionId);
+    const contract = helper.ethNativeContract.collection(collectionAddress, 'nft', owner);
     
     const nextTokenId = await contract.methods.nextTokenId().call();
     expect(nextTokenId).to.be.equal('1');
@@ -88,162 +94,73 @@
       nextTokenId,
     ).send();
 
-    const events = normalizeEvents(result.events);
-    const address = collectionIdToAddress(collectionId);
+    if (propertyKey && propertyValue) {
+      // Set URL or suffix
+      await contract.methods.setProperty(nextTokenId, propertyKey, Buffer.from(propertyValue)).send();
+    }
 
-    expect(events).to.be.deep.equal([
-      {
-        address,
-        event: 'Transfer',
-        args: {
-          from: '0x0000000000000000000000000000000000000000',
-          to: receiver,
-          tokenId: nextTokenId,
-        },
-      },
-    ]);
+    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);
 
+    return {contract, nextTokenId};
+  }
+
+  itEth('Empty tokenURI', async ({helper}) => {
+    const {contract, nextTokenId} = await setup(helper, '');
     expect(await contract.methods.tokenURI(nextTokenId).call()).to.be.equal('');
   });
 
-  itWeb3('TokenURI from url', async ({web3, api, privateKeyWrapper}) => {
-    const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);
-    const helper = evmCollectionHelpers(web3, owner);
-    let result = await helper.methods.createERC721MetadataCompatibleCollection('Mint collection', '1', '1', 'BaseURI_').send();
-    const {collectionIdAddress, collectionId} = await getCollectionAddressFromResult(api, result);
-    const receiver = createEthAccount(web3);
-    const contract = evmCollection(web3, owner, collectionIdAddress);
-    
-    const nextTokenId = await contract.methods.nextTokenId().call();
-    expect(nextTokenId).to.be.equal('1');
-    result = await contract.methods.mint(
-      receiver,
-      nextTokenId,
-    ).send();
-    
-    // Set URL
-    await contract.methods.setProperty(nextTokenId, 'url', Buffer.from('Token URI')).send();
-      
-    const events = normalizeEvents(result.events);
-    const address = collectionIdToAddress(collectionId);
-
-    expect(events).to.be.deep.equal([
-      {
-        address,
-        event: 'Transfer',
-        args: {
-          from: '0x0000000000000000000000000000000000000000',
-          to: receiver,
-          tokenId: nextTokenId,
-        },
-      },
-    ]);
-
+  itEth('TokenURI from url', async ({helper}) => {
+    const {contract, nextTokenId} = await setup(helper, 'BaseURI_', 'url', 'Token URI');
     expect(await contract.methods.tokenURI(nextTokenId).call()).to.be.equal('Token URI');
   });
 
-  itWeb3('TokenURI from baseURI + tokenId', async ({web3, api, privateKeyWrapper}) => {
-    const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);
-    const helper = evmCollectionHelpers(web3, owner);
-    let result = await helper.methods.createERC721MetadataCompatibleCollection('Mint collection', '1', '1', 'BaseURI_').send();
-    const {collectionIdAddress, collectionId} = await getCollectionAddressFromResult(api, result);
-    const receiver = createEthAccount(web3);
-    const contract = evmCollection(web3, owner, collectionIdAddress);
-    
-    const nextTokenId = await contract.methods.nextTokenId().call();
-    expect(nextTokenId).to.be.equal('1');
-    result = await contract.methods.mint(
-      receiver,
-      nextTokenId,
-    ).send();
-          
-    const events = normalizeEvents(result.events);
-    const address = collectionIdToAddress(collectionId);
-
-    expect(events).to.be.deep.equal([
-      {
-        address,
-        event: 'Transfer',
-        args: {
-          from: '0x0000000000000000000000000000000000000000',
-          to: receiver,
-          tokenId: nextTokenId,
-        },
-      },
-    ]);
-
+  itEth('TokenURI from baseURI + tokenId', async ({helper}) => {
+    const {contract, nextTokenId} = await setup(helper, 'BaseURI_');
     expect(await contract.methods.tokenURI(nextTokenId).call()).to.be.equal('BaseURI_' + nextTokenId);
   });
 
-  itWeb3('TokenURI from baseURI + suffix', async ({web3, api, privateKeyWrapper}) => {
-    const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);
-    const helper = evmCollectionHelpers(web3, owner);
-    let result = await helper.methods.createERC721MetadataCompatibleCollection('Mint collection', '1', '1', 'BaseURI_').send();
-    const {collectionIdAddress, collectionId} = await getCollectionAddressFromResult(api, result);
-    const receiver = createEthAccount(web3);
-    const contract = evmCollection(web3, owner, collectionIdAddress);
-    
-    const nextTokenId = await contract.methods.nextTokenId().call();
-    expect(nextTokenId).to.be.equal('1');
-    result = await contract.methods.mint(
-      receiver,
-      nextTokenId,
-    ).send();
-          
-    // Set suffix
+  itEth('TokenURI from baseURI + suffix', async ({helper}) => {
     const suffix = '/some/suffix';
-    await contract.methods.setProperty(nextTokenId, 'suffix', Buffer.from(suffix)).send();
-
-    const events = normalizeEvents(result.events);
-    const address = collectionIdToAddress(collectionId);
-
-    expect(events).to.be.deep.equal([
-      {
-        address,
-        event: 'Transfer',
-        args: {
-          from: '0x0000000000000000000000000000000000000000',
-          to: receiver,
-          tokenId: nextTokenId,
-        },
-      },
-    ]);
-
+    const {contract, nextTokenId} = await setup(helper, 'BaseURI_', 'suffix', suffix);
     expect(await contract.methods.tokenURI(nextTokenId).call()).to.be.equal('BaseURI_' + suffix);
   });
 });
 
 describe('NFT: Plain calls', () => {
-  itWeb3('Can perform mint()', async ({web3, api, privateKeyWrapper}) => {
-    const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);
-    const helper = evmCollectionHelpers(web3, owner);
-    let result = await helper.methods.createNonfungibleCollection('Mint collection', '6', '6').send();
-    const {collectionIdAddress, collectionId} = await getCollectionAddressFromResult(api, result);
-    const receiver = createEthAccount(web3);
-    const contract = evmCollection(web3, owner, collectionIdAddress);
+  let donor: IKeyringPair;
+  let alice: IKeyringPair;
+
+  before(async function() {
+    await usingEthPlaygrounds(async (helper, privateKey) => {
+      donor = privateKey('//Alice');
+      [alice] = await helper.arrange.createAccounts([10n], donor);
+    });
+  });
+
+  itEth('Can perform mint()', async ({helper}) => {
+    const owner = await helper.eth.createAccountWithBalance(donor);
+    const receiver = helper.eth.createAccount();
+
+    const {collectionAddress} = await helper.eth.createNonfungibleCollection(owner, 'Minty', '6', '6');
+    const contract = helper.ethNativeContract.collection(collectionAddress, 'nft', owner);
     const nextTokenId = await contract.methods.nextTokenId().call();
 
     expect(nextTokenId).to.be.equal('1');
-    result = await contract.methods.mintWithTokenURI(
+    const result = await contract.methods.mintWithTokenURI(
       receiver,
       nextTokenId,
       'Test URI',
     ).send();
 
-    const events = normalizeEvents(result.events);
-    const address = collectionIdToAddress(collectionId);
-
-    expect(events).to.be.deep.equal([
-      {
-        address,
-        event: 'Transfer',
-        args: {
-          from: '0x0000000000000000000000000000000000000000',
-          to: receiver,
-          tokenId: nextTokenId,
-        },
-      },
-    ]);
+    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');
 
@@ -254,7 +171,8 @@
   });
 
   //TODO: CORE-302 add eth methods
-  itWeb3.skip('Can perform mintBulk()', async ({web3, api, privateKeyWrapper}) => {
+  /* todo:playgrounds skipped test!
+  itWeb3.skip('Can perform mintBulk()', async ({helper}) => {
     const collection = await createCollectionExpectSuccess({
       mode: {type: 'NFT'},
     });
@@ -316,107 +234,70 @@
       expect(await contract.methods.tokenURI(+nextTokenId + 2).call()).to.be.equal('Test URI 2');
     }
   });
-
-  itWeb3('Can perform burn()', async ({web3, api, privateKeyWrapper}) => {
-    const collection = await createCollectionExpectSuccess({
-      mode: {type: 'NFT'},
-    });
-    const alice = privateKeyWrapper('//Alice');
+  */
 
-    const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);
+  itEth('Can perform burn()', async ({helper}) => {
+    const caller = await helper.eth.createAccountWithBalance(donor);
 
-    const tokenId = await createItemExpectSuccess(alice, collection, 'NFT', {Ethereum: owner});
+    const collection = await helper.nft.mintCollection(alice, {});
+    const {tokenId} = await collection.mintToken(alice, {Ethereum: caller});
 
-    const address = collectionIdToAddress(collection);
-    const contract = new web3.eth.Contract(nonFungibleAbi as any, address, {from: owner, ...GAS_ARGS});
+    const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId);
+    const contract = helper.ethNativeContract.collection(collectionAddress, 'nft', caller);
 
     {
-      const result = await contract.methods.burn(tokenId).send({from: owner});
-      const events = normalizeEvents(result.events);
-
-      expect(events).to.be.deep.equal([
-        {
-          address,
-          event: 'Transfer',
-          args: {
-            from: owner,
-            to: '0x0000000000000000000000000000000000000000',
-            tokenId: tokenId.toString(),
-          },
-        },
-      ]);
+      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);
+      expect(event.returnValues.to).to.be.equal('0x0000000000000000000000000000000000000000');
+      expect(event.returnValues.tokenId).to.be.equal(`${tokenId}`);
     }
   });
 
-  itWeb3('Can perform approve()', async ({web3, api, privateKeyWrapper}) => {
-    const collection = await createCollectionExpectSuccess({
-      mode: {type: 'NFT'},
-    });
-    const alice = privateKeyWrapper('//Alice');
-
-    const owner = createEthAccount(web3);
-    await transferBalanceToEth(api, alice, owner);
-
-    const tokenId = await createItemExpectSuccess(alice, collection, 'NFT', {Ethereum: owner});
+  itEth('Can perform approve()', async ({helper}) => {
+    const owner = await helper.eth.createAccountWithBalance(donor);
+    const spender = helper.eth.createAccount();
 
-    const spender = createEthAccount(web3);
+    const collection = await helper.nft.mintCollection(alice, {});
+    const {tokenId} = await collection.mintToken(alice, {Ethereum: owner});
 
-    const address = collectionIdToAddress(collection);
-    const contract = new web3.eth.Contract(nonFungibleAbi as any, address);
+    const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId);
+    const contract = helper.ethNativeContract.collection(collectionAddress, 'nft', owner);
 
     {
-      const result = await contract.methods.approve(spender, tokenId).send({from: owner, ...GAS_ARGS});
-      const events = normalizeEvents(result.events);
+      const result = await contract.methods.approve(spender, tokenId).send({from: owner});
 
-      expect(events).to.be.deep.equal([
-        {
-          address,
-          event: 'Approval',
-          args: {
-            owner,
-            approved: spender,
-            tokenId: tokenId.toString(),
-          },
-        },
-      ]);
+      const event = result.events.Approval;
+      expect(event.address).to.be.equal(collectionAddress);
+      expect(event.returnValues.owner).to.be.equal(owner);
+      expect(event.returnValues.approved).to.be.equal(spender);
+      expect(event.returnValues.tokenId).to.be.equal(`${tokenId}`);
     }
   });
 
-  itWeb3('Can perform transferFrom()', async ({web3, api, privateKeyWrapper}) => {
-    const collection = await createCollectionExpectSuccess({
-      mode: {type: 'NFT'},
-    });
-    const alice = privateKeyWrapper('//Alice');
-
-    const owner = createEthAccount(web3);
-    await transferBalanceToEth(api, alice, owner);
+  itEth('Can perform transferFrom()', async ({helper}) => {
+    const owner = await helper.eth.createAccountWithBalance(donor);
+    const spender = await helper.eth.createAccountWithBalance(donor);
+    const receiver = helper.eth.createAccount();
 
-    const tokenId = await createItemExpectSuccess(alice, collection, 'NFT', {Ethereum: owner});
-
-    const spender = createEthAccount(web3);
-    await transferBalanceToEth(api, alice, spender);
-
-    const receiver = createEthAccount(web3);
+    const collection = await helper.nft.mintCollection(alice, {});
+    const {tokenId} = await collection.mintToken(alice, {Ethereum: owner});
 
-    const address = collectionIdToAddress(collection);
-    const contract = new web3.eth.Contract(nonFungibleAbi as any, address, {from: owner, ...GAS_ARGS});
+    const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId);
+    const contract = helper.ethNativeContract.collection(collectionAddress, 'nft', owner);
 
     await contract.methods.approve(spender, tokenId).send({from: owner});
 
     {
       const result = await contract.methods.transferFrom(owner, receiver, tokenId).send({from: spender});
-      const events = normalizeEvents(result.events);
-      expect(events).to.be.deep.equal([
-        {
-          address,
-          event: 'Transfer',
-          args: {
-            from: owner,
-            to: receiver,
-            tokenId: tokenId.toString(),
-          },
-        },
-      ]);
+
+      const event = result.events.Transfer;
+      expect(event.address).to.be.equal(collectionAddress);
+      expect(event.returnValues.from).to.be.equal(owner);
+      expect(event.returnValues.to).to.be.equal(receiver);
+      expect(event.returnValues.tokenId).to.be.equal(`${tokenId}`);
     }
 
     {
@@ -430,37 +311,24 @@
     }
   });
 
-  itWeb3('Can perform transfer()', async ({web3, api, privateKeyWrapper}) => {
-    const collection = await createCollectionExpectSuccess({
-      mode: {type: 'NFT'},
-    });
-    const alice = privateKeyWrapper('//Alice');
-
-    const owner = createEthAccount(web3);
-    await transferBalanceToEth(api, alice, owner);
-
-    const tokenId = await createItemExpectSuccess(alice, collection, 'NFT', {Ethereum: owner});
+  itEth('Can perform transfer()', async ({helper}) => {
+    const collection = await helper.nft.mintCollection(alice, {});
+    const owner = await helper.eth.createAccountWithBalance(donor);
+    const receiver = helper.eth.createAccount();
 
-    const receiver = createEthAccount(web3);
-    await transferBalanceToEth(api, alice, receiver);
+    const {tokenId} = await collection.mintToken(alice, {Ethereum: owner});
 
-    const address = collectionIdToAddress(collection);
-    const contract = new web3.eth.Contract(nonFungibleAbi as any, address, {from: owner, ...GAS_ARGS});
+    const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId);
+    const contract = helper.ethNativeContract.collection(collectionAddress, 'nft', owner);
 
     {
       const result = await contract.methods.transfer(receiver, tokenId).send({from: owner});
-      const events = normalizeEvents(result.events);
-      expect(events).to.be.deep.equal([
-        {
-          address,
-          event: 'Transfer',
-          args: {
-            from: owner,
-            to: receiver,
-            tokenId: tokenId.toString(),
-          },
-        },
-      ]);
+
+      const event = result.events.Transfer;
+      expect(event.address).to.be.equal(collectionAddress);
+      expect(event.returnValues.from).to.be.equal(owner);
+      expect(event.returnValues.to).to.be.equal(receiver);
+      expect(event.returnValues.tokenId).to.be.equal(`${tokenId}`);
     }
 
     {
@@ -476,237 +344,209 @@
 });
 
 describe('NFT: Fees', () => {
-  itWeb3('approve() call fee is less than 0.2UNQ', async ({web3, api, privateKeyWrapper}) => {
-    const collection = await createCollectionExpectSuccess({
-      mode: {type: 'NFT'},
+  let donor: IKeyringPair;
+  let alice: IKeyringPair;
+
+  before(async function() {
+    await usingEthPlaygrounds(async (helper, privateKey) => {
+      donor = privateKey('//Alice');
+      [alice] = await helper.arrange.createAccounts([10n], donor);
     });
-    const alice = privateKeyWrapper('//Alice');
+  });
+  
+  itEth('approve() call fee is less than 0.2UNQ', async ({helper}) => {
+    const owner = await helper.eth.createAccountWithBalance(donor);
+    const spender = helper.eth.createAccount();
 
-    const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);
-    const spender = createEthAccount(web3);
+    const collection = await helper.nft.mintCollection(alice, {});
+    const {tokenId} = await collection.mintToken(alice, {Ethereum: owner});
 
-    const tokenId = await createItemExpectSuccess(alice, collection, 'NFT', {Ethereum: owner});
+    const contract = helper.ethNativeContract.collectionById(collection.collectionId, 'nft', owner);
 
-    const address = collectionIdToAddress(collection);
-    const contract = new web3.eth.Contract(nonFungibleAbi as any, address, {from: owner, ...GAS_ARGS});
-
-    const cost = await recordEthFee(api, owner, () => contract.methods.approve(spender, tokenId).send({from: owner}));
-    expect(cost < BigInt(0.2 * Number(UNIQUE)));
+    const cost = await helper.eth.recordCallFee(owner, () => contract.methods.approve(spender, tokenId).send({from: owner}));
+    expect(cost < BigInt(0.2 * Number(helper.balance.getOneTokenNominal())));
   });
 
-  itWeb3('transferFrom() call fee is less than 0.2UNQ', async ({web3, api, privateKeyWrapper}) => {
-    const collection = await createCollectionExpectSuccess({
-      mode: {type: 'NFT'},
-    });
-    const alice = privateKeyWrapper('//Alice');
-
-    const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);
-    const spender = await createEthAccountWithBalance(api, web3, privateKeyWrapper);
+  itEth('transferFrom() call fee is less than 0.2UNQ', async ({helper}) => {
+    const owner = await helper.eth.createAccountWithBalance(donor);
+    const spender = await helper.eth.createAccountWithBalance(donor);
 
-    const tokenId = await createItemExpectSuccess(alice, collection, 'NFT', {Ethereum: owner});
+    const collection = await helper.nft.mintCollection(alice, {});
+    const {tokenId} = await collection.mintToken(alice, {Ethereum: owner});
 
-    const address = collectionIdToAddress(collection);
-    const contract = new web3.eth.Contract(nonFungibleAbi as any, address, {from: owner, ...GAS_ARGS});
+    const contract = helper.ethNativeContract.collectionById(collection.collectionId, 'nft', owner);
 
     await contract.methods.approve(spender, tokenId).send({from: owner});
 
-    const cost = await recordEthFee(api, spender, () => contract.methods.transferFrom(owner, spender, tokenId).send({from: spender}));
-    expect(cost < BigInt(0.2 * Number(UNIQUE)));
+    const cost = await helper.eth.recordCallFee(spender, () => contract.methods.transferFrom(owner, spender, tokenId).send({from: spender}));
+    expect(cost < BigInt(0.2 * Number(helper.balance.getOneTokenNominal())));
   });
 
-  itWeb3('transfer() call fee is less than 0.2UNQ', async ({web3, api, privateKeyWrapper}) => {
-    const collection = await createCollectionExpectSuccess({
-      mode: {type: 'NFT'},
-    });
-    const alice = privateKeyWrapper('//Alice');
+  itEth('transfer() call fee is less than 0.2UNQ', async ({helper}) => {
+    const owner = await helper.eth.createAccountWithBalance(donor);
+    const receiver = helper.eth.createAccount();
 
-    const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);
-    const receiver = createEthAccount(web3);
+    const collection = await helper.nft.mintCollection(alice, {});
+    const {tokenId} = await collection.mintToken(alice, {Ethereum: owner});
 
-    const tokenId = await createItemExpectSuccess(alice, collection, 'NFT', {Ethereum: owner});
+    const contract = helper.ethNativeContract.collectionById(collection.collectionId, 'nft', owner);
 
-    const address = collectionIdToAddress(collection);
-    const contract = new web3.eth.Contract(nonFungibleAbi as any, address, {from: owner, ...GAS_ARGS});
-
-    const cost = await recordEthFee(api, owner, () => contract.methods.transfer(receiver, tokenId).send({from: owner}));
-    expect(cost < BigInt(0.2 * Number(UNIQUE)));
+    const cost = await helper.eth.recordCallFee(owner, () => contract.methods.transfer(receiver, tokenId).send({from: owner}));
+    expect(cost < BigInt(0.2 * Number(helper.balance.getOneTokenNominal())));
   });
 });
 
 describe('NFT: Substrate calls', () => {
-  itWeb3('Events emitted for mint()', async ({web3, privateKeyWrapper}) => {
-    const collection = await createCollectionExpectSuccess({
-      mode: {type: 'NFT'},
+  let donor: IKeyringPair;
+  let alice: IKeyringPair;
+
+  before(async function() {
+    await usingEthPlaygrounds(async (helper, privateKey) => {
+      donor = privateKey('//Alice');
+      [alice] = await helper.arrange.createAccounts([20n], donor);
     });
-    const alice = privateKeyWrapper('//Alice');
+  });
 
-    const address = collectionIdToAddress(collection);
-    const contract = new web3.eth.Contract(nonFungibleAbi as any, address);
+  itEth('Events emitted for mint()', async ({helper}) => {
+    const collection = await helper.nft.mintCollection(alice, {});
+    const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId);
+    const contract = helper.ethNativeContract.collection(collectionAddress, 'nft');
 
-    let tokenId: number;
-    const events = await recordEvents(contract, async () => {
-      tokenId = await createItemExpectSuccess(alice, collection, 'NFT');
+    const events: any = [];
+    contract.events.allEvents((_: any, event: any) => {
+      events.push(event);
     });
+    const {tokenId} = await collection.mintToken(alice);
 
-    expect(events).to.be.deep.equal([
-      {
-        address,
-        event: 'Transfer',
-        args: {
-          from: '0x0000000000000000000000000000000000000000',
-          to: subToEth(alice.address),
-          tokenId: tokenId!.toString(),
-        },
-      },
-    ]);
+    const event = events[0];
+    expect(event.event).to.be.equal('Transfer');
+    expect(event.address).to.be.equal(collectionAddress);
+    expect(event.returnValues.from).to.be.equal('0x0000000000000000000000000000000000000000');
+    expect(event.returnValues.to).to.be.equal(helper.address.substrateToEth(alice.address));
+    expect(event.returnValues.tokenId).to.be.equal(tokenId.toString());
   });
 
-  itWeb3('Events emitted for burn()', async ({web3, privateKeyWrapper}) => {
-    const collection = await createCollectionExpectSuccess({
-      mode: {type: 'NFT'},
+  itEth('Events emitted for burn()', async ({helper}) => {
+    const collection = await helper.nft.mintCollection(alice, {});
+    const token = await collection.mintToken(alice);
+
+    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);
     });
-    const alice = privateKeyWrapper('//Alice');
 
-    const address = collectionIdToAddress(collection);
-    const contract = new web3.eth.Contract(nonFungibleAbi as any, address);
+    await token.burn(alice);
 
-    const tokenId = await createItemExpectSuccess(alice, collection, 'NFT');
-    const events = await recordEvents(contract, async () => {
-      await burnItemExpectSuccess(alice, collection, tokenId);
-    });
-
-    expect(events).to.be.deep.equal([
-      {
-        address,
-        event: 'Transfer',
-        args: {
-          from: subToEth(alice.address),
-          to: '0x0000000000000000000000000000000000000000',
-          tokenId: tokenId.toString(),
-        },
-      },
-    ]);
+    const event = events[0];
+    expect(event.event).to.be.equal('Transfer');
+    expect(event.address).to.be.equal(collectionAddress);
+    expect(event.returnValues.from).to.be.equal(helper.address.substrateToEth(alice.address));
+    expect(event.returnValues.to).to.be.equal('0x0000000000000000000000000000000000000000');
+    expect(event.returnValues.tokenId).to.be.equal(token.tokenId.toString());
   });
 
-  itWeb3('Events emitted for approve()', async ({web3, privateKeyWrapper}) => {
-    const collection = await createCollectionExpectSuccess({
-      mode: {type: 'NFT'},
-    });
-    const alice = privateKeyWrapper('//Alice');
+  itEth('Events emitted for approve()', async ({helper}) => {
+    const receiver = helper.eth.createAccount();
 
-    const receiver = createEthAccount(web3);
-
-    const tokenId = await createItemExpectSuccess(alice, collection, 'NFT');
-
-    const address = collectionIdToAddress(collection);
-    const contract = new web3.eth.Contract(nonFungibleAbi as any, address);
+    const collection = await helper.nft.mintCollection(alice, {});
+    const token = await collection.mintToken(alice);
 
-    const events = await recordEvents(contract, async () => {
-      await approveExpectSuccess(collection, tokenId, alice, {Ethereum: receiver}, 1);
+    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);
     });
 
-    expect(events).to.be.deep.equal([
-      {
-        address,
-        event: 'Approval',
-        args: {
-          owner: subToEth(alice.address),
-          approved: receiver,
-          tokenId: tokenId.toString(),
-        },
-      },
-    ]);
+    await token.approve(alice, {Ethereum: receiver});
+
+    const event = events[0];
+    expect(event.event).to.be.equal('Approval');
+    expect(event.address).to.be.equal(collectionAddress);
+    expect(event.returnValues.owner).to.be.equal(helper.address.substrateToEth(alice.address));
+    expect(event.returnValues.approved).to.be.equal(receiver);
+    expect(event.returnValues.tokenId).to.be.equal(token.tokenId.toString());
   });
 
-  itWeb3('Events emitted for transferFrom()', async ({web3, privateKeyWrapper}) => {
-    const collection = await createCollectionExpectSuccess({
-      mode: {type: 'NFT'},
-    });
-    const alice = privateKeyWrapper('//Alice');
-    const bob = privateKeyWrapper('//Bob');
+  itEth('Events emitted for transferFrom()', async ({helper}) => {
+    const [bob] = await helper.arrange.createAccounts([10n], donor);
+    const receiver = helper.eth.createAccount();
 
-    const receiver = createEthAccount(web3);
-
-    const tokenId = await createItemExpectSuccess(alice, collection, 'NFT');
-    await approveExpectSuccess(collection, tokenId, alice, bob.address, 1);
-
-    const address = collectionIdToAddress(collection);
-    const contract = new web3.eth.Contract(nonFungibleAbi as any, address);
+    const collection = await helper.nft.mintCollection(alice, {});
+    const token = await collection.mintToken(alice);
+    await token.approve(alice, {Substrate: bob.address});
 
-    const events = await recordEvents(contract, async () => {
-      await transferFromExpectSuccess(collection, tokenId, bob, alice, {Ethereum: receiver}, 1, 'NFT');
+    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);
     });
 
-    expect(events).to.be.deep.equal([
-      {
-        address,
-        event: 'Transfer',
-        args: {
-          from: subToEth(alice.address),
-          to: receiver,
-          tokenId: tokenId.toString(),
-        },
-      },
-    ]);
+    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));
+    expect(event.returnValues.to).to.be.equal(receiver);
+    expect(event.returnValues.tokenId).to.be.equal(`${token.tokenId}`);
   });
 
-  itWeb3('Events emitted for transfer()', async ({web3, privateKeyWrapper}) => {
-    const collection = await createCollectionExpectSuccess({
-      mode: {type: 'NFT'},
-    });
-    const alice = privateKeyWrapper('//Alice');
+  itEth('Events emitted for transfer()', async ({helper}) => {
+    const receiver = helper.eth.createAccount();
 
-    const receiver = createEthAccount(web3);
+    const collection = await helper.nft.mintCollection(alice, {});
+    const token = await collection.mintToken(alice);
 
-    const tokenId = await createItemExpectSuccess(alice, collection, 'NFT');
-
-    const address = collectionIdToAddress(collection);
-    const contract = new web3.eth.Contract(nonFungibleAbi as any, address);
-
-    const events = await recordEvents(contract, async () => {
-      await transferExpectSuccess(collection, tokenId, alice, {Ethereum: receiver}, 1, 'NFT');
+    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);
     });
 
-    expect(events).to.be.deep.equal([
-      {
-        address,
-        event: 'Transfer',
-        args: {
-          from: subToEth(alice.address),
-          to: receiver,
-          tokenId: tokenId.toString(),
-        },
-      },
-    ]);
+    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));
+    expect(event.returnValues.to).to.be.equal(receiver);
+    expect(event.returnValues.tokenId).to.be.equal(`${token.tokenId}`);
   });
 });
 
 describe('Common metadata', () => {
-  itWeb3('Returns collection name', async ({api, web3, privateKeyWrapper}) => {
-    const collection = await createCollectionExpectSuccess({
-      name: 'token name',
-      mode: {type: 'NFT'},
+  let donor: IKeyringPair;
+  let alice: IKeyringPair;
+
+  before(async function() {
+    await usingEthPlaygrounds(async (helper, privateKey) => {
+      donor = privateKey('//Alice');
+      [alice] = await helper.arrange.createAccounts([20n], donor);
     });
-    const caller = await createEthAccountWithBalance(api, web3, privateKeyWrapper);
+  });
+
+  itEth('Returns collection name', async ({helper}) => {
+    const caller = await helper.eth.createAccountWithBalance(donor);
+    const collection = await helper.nft.mintCollection(alice, {name: 'oh River', tokenPrefix: 'CHANGE'});
 
-    const address = collectionIdToAddress(collection);
-    const contract = new web3.eth.Contract(nonFungibleAbi as any, address, {from: caller, ...GAS_ARGS});
+    const contract = helper.ethNativeContract.collectionById(collection.collectionId, 'nft', caller);
     const name = await contract.methods.name().call();
-
-    expect(name).to.equal('token name');
+    expect(name).to.equal('oh River');
   });
 
-  itWeb3('Returns symbol name', async ({api, web3, privateKeyWrapper}) => {
-    const collection = await createCollectionExpectSuccess({
-      tokenPrefix: 'TOK',
-      mode: {type: 'NFT'},
-    });
-    const caller = await createEthAccountWithBalance(api, web3, privateKeyWrapper);
+  itEth('Returns symbol name', async ({helper}) => {
+    const caller = await helper.eth.createAccountWithBalance(donor);
+    const collection = await helper.nft.mintCollection(alice, {name: 'oh River', tokenPrefix: 'CHANGE'});
 
-    const address = collectionIdToAddress(collection);
-    const contract = new web3.eth.Contract(nonFungibleAbi as any, address, {from: caller, ...GAS_ARGS});
+    const contract = helper.ethNativeContract.collectionById(collection.collectionId, 'nft', caller);
     const symbol = await contract.methods.symbol().call();
-
-    expect(symbol).to.equal('TOK');
+    expect(symbol).to.equal('CHANGE');
   });
 });
\ No newline at end of file
modifiedtests/src/eth/reFungible.test.tsdiffbeforeafterboth
--- a/tests/src/eth/reFungible.test.ts
+++ b/tests/src/eth/reFungible.test.ts
@@ -14,33 +14,35 @@
 // You should have received a copy of the GNU General Public License
 // along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
 
-import {createCollectionExpectSuccess, UNIQUE, requirePallets, Pallets} from '../util/helpers';
-import {collectionIdToAddress, createEthAccount, createEthAccountWithBalance, evmCollection, evmCollectionHelpers, getCollectionAddressFromResult, itWeb3, normalizeEvents, recordEthFee, recordEvents, tokenIdToAddress, uniqueRefungibleToken} from './util/helpers';
-import {expect} from 'chai';
+import {Pallets, requirePalletsOrSkip} from '../util/playgrounds';
+import {expect, itEth, usingEthPlaygrounds} from './util/playgrounds';
+import {IKeyringPair} from '@polkadot/types/types';
 
 describe('Refungible: Information getting', () => {
+  let donor: IKeyringPair;
+
   before(async function() {
-    await requirePallets(this, [Pallets.ReFungible]);
+    await usingEthPlaygrounds(async (helper, privateKey) => {
+      requirePalletsOrSkip(this, helper, [Pallets.ReFungible]);
+
+      donor = privateKey('//Alice');
+    });
   });
 
-  itWeb3('totalSupply', async ({api, web3, privateKeyWrapper}) => {
-    const caller = await createEthAccountWithBalance(api, web3, privateKeyWrapper);
-    const helper = evmCollectionHelpers(web3, caller);
-    const result = await helper.methods.createRFTCollection('Mint collection', '6', '6').send();
-    const {collectionIdAddress} = await getCollectionAddressFromResult(api, result);
-    const contract = evmCollection(web3, caller, collectionIdAddress, {type: 'ReFungible'});
+  itEth('totalSupply', async ({helper}) => {
+    const caller = await helper.eth.createAccountWithBalance(donor);
+    const {collectionAddress} = await helper.eth.createRefungibleCollection(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();
     const totalSupply = await contract.methods.totalSupply().call();
     expect(totalSupply).to.equal('1');
   });
 
-  itWeb3('balanceOf', async ({api, web3, privateKeyWrapper}) => {
-    const caller = await createEthAccountWithBalance(api, web3, privateKeyWrapper);
-    const helper = evmCollectionHelpers(web3, caller);
-    const result = await helper.methods.createRFTCollection('Mint collection', '6', '6').send();
-    const {collectionIdAddress} = await getCollectionAddressFromResult(api, result);
-    const contract = evmCollection(web3, caller, collectionIdAddress, {type: 'ReFungible'});
+  itEth('balanceOf', async ({helper}) => {
+    const caller = await helper.eth.createAccountWithBalance(donor);
+    const {collectionAddress} = await helper.eth.createRefungibleCollection(caller, 'BalanceOf', '6', '6');
+    const contract = helper.ethNativeContract.collection(collectionAddress, 'rft', caller);
 
     {
       const nextTokenId = await contract.methods.nextTokenId().call();
@@ -56,38 +58,30 @@
     }
 
     const balance = await contract.methods.balanceOf(caller).call();
-
     expect(balance).to.equal('3');
   });
 
-  itWeb3('ownerOf', async ({api, web3, privateKeyWrapper}) => {
-    const caller = await createEthAccountWithBalance(api, web3, privateKeyWrapper);
-    const helper = evmCollectionHelpers(web3, caller);
-    const result = await helper.methods.createRFTCollection('Mint collection', '6', '6').send();
-    const {collectionIdAddress} = await getCollectionAddressFromResult(api, result);
-    const contract = evmCollection(web3, caller, collectionIdAddress, {type: 'ReFungible'});
+  itEth('ownerOf', async ({helper}) => {
+    const caller = await helper.eth.createAccountWithBalance(donor);
+    const {collectionAddress} = await helper.eth.createRefungibleCollection(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 owner = await contract.methods.ownerOf(tokenId).call();
-
     expect(owner).to.equal(caller);
   });
 
-  itWeb3('ownerOf after burn', async ({api, web3, privateKeyWrapper}) => {
-    const caller = await createEthAccountWithBalance(api, web3, privateKeyWrapper);
-    const receiver = createEthAccount(web3);
-    const helper = evmCollectionHelpers(web3, caller);
-    const result = await helper.methods.createRFTCollection('Mint collection', '6', '6').send();
-    const {collectionIdAddress, collectionId} = await getCollectionAddressFromResult(api, result);
-    const contract = evmCollection(web3, caller, collectionIdAddress, {type: 'ReFungible'});
+  itEth('ownerOf after burn', async ({helper}) => {
+    const caller = await helper.eth.createAccountWithBalance(donor);
+    const receiver = helper.eth.createAccount();
+    const {collectionId, collectionAddress} = await helper.eth.createRefungibleCollection(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 tokenAddress = tokenIdToAddress(collectionId, tokenId);
-    const tokenContract = uniqueRefungibleToken(web3, tokenAddress, caller);
+    const tokenContract = helper.ethNativeContract.rftTokenById(collectionId, tokenId, caller);
 
     await tokenContract.methods.repartition(2).send();
     await tokenContract.methods.transfer(receiver, 1).send();
@@ -95,80 +89,67 @@
     await tokenContract.methods.burnFrom(caller, 1).send();
 
     const owner = await contract.methods.ownerOf(tokenId).call();
-
     expect(owner).to.equal(receiver);
   });
 
-  itWeb3('ownerOf for partial ownership', async ({api, web3, privateKeyWrapper}) => {
-    const caller = await createEthAccountWithBalance(api, web3, privateKeyWrapper);
-    const receiver = createEthAccount(web3);
-    const helper = evmCollectionHelpers(web3, caller);
-    const result = await helper.methods.createRFTCollection('Mint collection', '6', '6').send();
-    const {collectionIdAddress, collectionId} = await getCollectionAddressFromResult(api, result);
-    const contract = evmCollection(web3, caller, collectionIdAddress, {type: 'ReFungible'});
+  itEth('ownerOf for partial ownership', async ({helper}) => {
+    const caller = await helper.eth.createAccountWithBalance(donor);
+    const receiver = helper.eth.createAccount();
+    const {collectionId, collectionAddress} = await helper.eth.createRefungibleCollection(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 tokenAddress = tokenIdToAddress(collectionId, tokenId);
-    const tokenContract = uniqueRefungibleToken(web3, tokenAddress, caller);
+    const tokenContract = helper.ethNativeContract.rftTokenById(collectionId, tokenId, caller);
 
     await tokenContract.methods.repartition(2).send();
     await tokenContract.methods.transfer(receiver, 1).send();
 
     const owner = await contract.methods.ownerOf(tokenId).call();
-
     expect(owner).to.equal('0xFFfFfFffFFfffFFfFFfFFFFFffFFFffffFfFFFfF');
   });
 });
 
 describe('Refungible: Plain calls', () => {
+  let donor: IKeyringPair;
+
   before(async function() {
-    await requirePallets(this, [Pallets.ReFungible]);
+    await usingEthPlaygrounds(async (helper, privateKey) => {
+      requirePalletsOrSkip(this, helper, [Pallets.ReFungible]);
+
+      donor = privateKey('//Alice');
+    });
   });
 
-  itWeb3('Can perform mint()', async ({web3, api, privateKeyWrapper}) => {
-    const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);
-    const helper = evmCollectionHelpers(web3, owner);
-    let result = await helper.methods.createRFTCollection('Mint collection', '6', '6').send();
-    const {collectionIdAddress} = await getCollectionAddressFromResult(api, result);
-    const receiver = createEthAccount(web3);
-    const contract = evmCollection(web3, owner, collectionIdAddress, {type: 'ReFungible'});
+  itEth('Can perform mint()', async ({helper}) => {
+    const owner = await helper.eth.createAccountWithBalance(donor);
+    const receiver = helper.eth.createAccount();
+    const {collectionAddress} = await helper.eth.createRefungibleCollection(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');
-    result = await contract.methods.mintWithTokenURI(
+    const result = await contract.methods.mintWithTokenURI(
       receiver,
       nextTokenId,
       'Test URI',
     ).send();
 
-    const events = normalizeEvents(result.events);
-
-    expect(events).to.include.deep.members([
-      {
-        address: collectionIdAddress,
-        event: 'Transfer',
-        args: {
-          from: '0x0000000000000000000000000000000000000000',
-          to: receiver,
-          tokenId: nextTokenId,
-        },
-      },
-    ]);
+    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);
 
     expect(await contract.methods.tokenURI(nextTokenId).call()).to.be.equal('Test URI');
   });
 
-  itWeb3('Can perform mintBulk()', async ({web3, api, privateKeyWrapper}) => {
-    const caller = await createEthAccountWithBalance(api, web3, privateKeyWrapper);
-    const helper = evmCollectionHelpers(web3, caller);
-    const result = await helper.methods.createRFTCollection('Mint collection', '6', '6').send();
-    const {collectionIdAddress} = await getCollectionAddressFromResult(api, result);
-    const contract = evmCollection(web3, caller, collectionIdAddress, {type: 'ReFungible'});
+  itEth('Can perform mintBulk()', async ({helper}) => {
+    const owner = await helper.eth.createAccountWithBalance(donor);
+    const receiver = helper.eth.createAccount();
+    const {collectionAddress} = await helper.eth.createRefungibleCollection(owner, 'MintBulky', '6', '6');
+    const contract = helper.ethNativeContract.collection(collectionAddress, 'rft', owner);
 
-    const receiver = createEthAccount(web3);
-
     {
       const nextTokenId = await contract.methods.nextTokenId().call();
       expect(nextTokenId).to.be.equal('1');
@@ -180,37 +161,15 @@
           [+nextTokenId + 2, 'Test URI 2'],
         ],
       ).send();
-      const events = normalizeEvents(result.events);
 
-      expect(events).to.include.deep.members([
-        {
-          address: collectionIdAddress,
-          event: 'Transfer',
-          args: {
-            from: '0x0000000000000000000000000000000000000000',
-            to: receiver,
-            tokenId: nextTokenId,
-          },
-        },
-        {
-          address: collectionIdAddress,
-          event: 'Transfer',
-          args: {
-            from: '0x0000000000000000000000000000000000000000',
-            to: receiver,
-            tokenId: String(+nextTokenId + 1),
-          },
-        },
-        {
-          address: collectionIdAddress,
-          event: 'Transfer',
-          args: {
-            from: '0x0000000000000000000000000000000000000000',
-            to: receiver,
-            tokenId: String(+nextTokenId + 2),
-          },
-        },
-      ]);
+      const events = result.events.Transfer;
+      for (let i = 0; i < 2; i++) {
+        const event = events[i];
+        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(String(+nextTokenId + i));
+      }
 
       expect(await contract.methods.tokenURI(nextTokenId).call()).to.be.equal('Test URI 0');
       expect(await contract.methods.tokenURI(+nextTokenId + 1).call()).to.be.equal('Test URI 1');
@@ -218,76 +177,54 @@
     }
   });
 
-  itWeb3('Can perform burn()', async ({web3, api, privateKeyWrapper}) => {
-    const caller = await createEthAccountWithBalance(api, web3, privateKeyWrapper);
-    const helper = evmCollectionHelpers(web3, caller);
-    const result = await helper.methods.createRFTCollection('Mint collection', '6', '6').send();
-    const {collectionIdAddress} = await getCollectionAddressFromResult(api, result);
-    const contract = evmCollection(web3, caller, collectionIdAddress, {type: 'ReFungible'});
+  itEth('Can perform burn()', async ({helper}) => {
+    const caller = await helper.eth.createAccountWithBalance(donor);
+    const {collectionAddress} = await helper.eth.createRefungibleCollection(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.burn(tokenId).send();
-      const events = normalizeEvents(result.events);
-      expect(events).to.include.deep.members([
-        {
-          address: collectionIdAddress,
-          event: 'Transfer',
-          args: {
-            from: caller,
-            to: '0x0000000000000000000000000000000000000000',
-            tokenId: tokenId.toString(),
-          },
-        },
-      ]);
+      const event = result.events.Transfer;
+      expect(event.address).to.equal(collectionAddress);
+      expect(event.returnValues.from).to.equal(caller);
+      expect(event.returnValues.to).to.equal('0x0000000000000000000000000000000000000000');
+      expect(event.returnValues.tokenId).to.equal(tokenId.toString());
     }
   });
 
-  itWeb3('Can perform transferFrom()', async ({web3, api, privateKeyWrapper}) => {
-    const caller = await createEthAccountWithBalance(api, web3, privateKeyWrapper);
-    const helper = evmCollectionHelpers(web3, caller);
-    const result = await helper.methods.createRFTCollection('Mint collection', '6', '6').send();
-    const {collectionIdAddress, collectionId} = await getCollectionAddressFromResult(api, result);
-    const contract = evmCollection(web3, caller, collectionIdAddress, {type: 'ReFungible'});
-
-    const receiver = createEthAccount(web3);
+  itEth('Can perform transferFrom()', async ({helper}) => {
+    const caller = await helper.eth.createAccountWithBalance(donor);
+    const receiver = helper.eth.createAccount();
+    const {collectionId, collectionAddress} = await helper.eth.createRefungibleCollection(caller, 'TransferFromy', '6', '6');
+    const contract = helper.ethNativeContract.collection(collectionAddress, 'rft', caller);
 
     const tokenId = await contract.methods.nextTokenId().call();
+    const tokenAddress = helper.ethAddress.fromTokenId(collectionId, tokenId);
     await contract.methods.mint(caller, tokenId).send();
 
-    const address = tokenIdToAddress(collectionId, tokenId);
-    const tokenContract = uniqueRefungibleToken(web3, address, caller);
+    const tokenContract = helper.ethNativeContract.rftToken(tokenAddress, caller);
     await tokenContract.methods.repartition(15).send();
 
     {
-      const erc20Events = await recordEvents(tokenContract, async () => {
-        const result = await contract.methods.transferFrom(caller, receiver, tokenId).send();
-        const events = normalizeEvents(result.events);
-        expect(events).to.include.deep.members([
-          {
-            address: collectionIdAddress,
-            event: 'Transfer',
-            args: {
-              from: caller,
-              to: receiver,
-              tokenId: tokenId.toString(),
-            },
-          },
-        ]);
+      const tokenEvents: any = [];
+      tokenContract.events.allEvents((_: any, event: any) => {
+        tokenEvents.push(event);
       });
+      const result = await contract.methods.transferFrom(caller, receiver, tokenId).send();
+
+      let event = result.events.Transfer;
+      expect(event.address).to.equal(collectionAddress);
+      expect(event.returnValues.from).to.equal(caller);
+      expect(event.returnValues.to).to.equal(receiver);
+      expect(event.returnValues.tokenId).to.equal(tokenId.toString());
 
-      expect(erc20Events).to.include.deep.members([
-        {
-          address,
-          event: 'Transfer',
-          args: {
-            from: caller,
-            to: receiver,
-            value: '15',
-          },
-        },
-      ]);
+      event = tokenEvents[0];
+      expect(event.address).to.equal(tokenAddress);
+      expect(event.returnValues.from).to.equal(caller);
+      expect(event.returnValues.to).to.equal(receiver);
+      expect(event.returnValues.value).to.equal('15');
     }
 
     {
@@ -301,32 +238,23 @@
     }
   });
 
-  itWeb3('Can perform transfer()', async ({web3, api, privateKeyWrapper}) => {
-    const caller = await createEthAccountWithBalance(api, web3, privateKeyWrapper);
-    const helper = evmCollectionHelpers(web3, caller);
-    const result = await helper.methods.createRFTCollection('Mint collection', '6', '6').send();
-    const {collectionIdAddress} = await getCollectionAddressFromResult(api, result);
-    const contract = evmCollection(web3, caller, collectionIdAddress, {type: 'ReFungible'});
-
-    const receiver = createEthAccount(web3);
+  itEth('Can perform transfer()', async ({helper}) => {
+    const caller = await helper.eth.createAccountWithBalance(donor);
+    const receiver = helper.eth.createAccount();
+    const {collectionAddress} = await helper.eth.createRefungibleCollection(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.transfer(receiver, tokenId).send();
-      const events = normalizeEvents(result.events);
-      expect(events).to.include.deep.members([
-        {
-          address: collectionIdAddress,
-          event: 'Transfer',
-          args: {
-            from: caller,
-            to: receiver,
-            tokenId: tokenId.toString(),
-          },
-        },
-      ]);
+      
+      const event = result.events.Transfer;
+      expect(event.address).to.equal(collectionAddress);
+      expect(event.returnValues.from).to.equal(caller);
+      expect(event.returnValues.to).to.equal(receiver);
+      expect(event.returnValues.tokenId).to.equal(tokenId.toString());
     }
 
     {
@@ -340,141 +268,127 @@
     }
   });
 
-  itWeb3('transfer event on transfer from partial ownership to full ownership', async ({api, web3, privateKeyWrapper}) => {
-    const caller = await createEthAccountWithBalance(api, web3, privateKeyWrapper);
-    const receiver = createEthAccount(web3);
-    const helper = evmCollectionHelpers(web3, caller);
-    const result = await helper.methods.createRFTCollection('Mint collection', '6', '6').send();
-    const {collectionIdAddress, collectionId} = await getCollectionAddressFromResult(api, result);
-    const contract = evmCollection(web3, caller, collectionIdAddress, {type: 'ReFungible'});
+  itEth('transfer event on transfer from partial ownership to full ownership', async ({helper}) => {
+    const caller = await helper.eth.createAccountWithBalance(donor);
+    const receiver = helper.eth.createAccount();
+    const {collectionId, collectionAddress} = await helper.eth.createRefungibleCollection(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 tokenAddress = tokenIdToAddress(collectionId, tokenId);
-    const tokenContract = uniqueRefungibleToken(web3, tokenAddress, caller);
+    const tokenContract = helper.ethNativeContract.rftTokenById(collectionId, tokenId, caller);
 
     await tokenContract.methods.repartition(2).send();
     await tokenContract.methods.transfer(receiver, 1).send();
 
-    const events =  await recordEvents(contract, async () =>
-      await tokenContract.methods.transfer(receiver, 1).send());
-    expect(events).to.deep.equal([
-      {
-        address: collectionIdAddress,
-        event: 'Transfer',
-        args: {
-          from: '0xFFfFfFffFFfffFFfFFfFFFFFffFFFffffFfFFFfF',
-          to: receiver,
-          tokenId: tokenId.toString(),
-        },
-      },
-    ]);
+    const events: any = [];
+    contract.events.allEvents((_: any, event: any) => {
+      events.push(event);
+    });
+    await tokenContract.methods.transfer(receiver, 1).send();
+
+    const event = events[0];
+    expect(event.address).to.equal(collectionAddress);
+    expect(event.returnValues.from).to.equal('0xFFfFfFffFFfffFFfFFfFFFFFffFFFffffFfFFFfF');
+    expect(event.returnValues.to).to.equal(receiver);
+    expect(event.returnValues.tokenId).to.equal(tokenId.toString());
   });
 
-  itWeb3('transfer event on transfer from full ownership to partial ownership', async ({api, web3, privateKeyWrapper}) => {
-    const caller = await createEthAccountWithBalance(api, web3, privateKeyWrapper);
-    const receiver = createEthAccount(web3);
-    const helper = evmCollectionHelpers(web3, caller);
-    const result = await helper.methods.createRFTCollection('Mint collection', '6', '6').send();
-    const {collectionIdAddress, collectionId} = await getCollectionAddressFromResult(api, result);
-    const contract = evmCollection(web3, caller, collectionIdAddress, {type: 'ReFungible'});
+  itEth('transfer event on transfer from full ownership to partial ownership', async ({helper}) => {
+    const caller = await helper.eth.createAccountWithBalance(donor);
+    const receiver = helper.eth.createAccount();
+    const {collectionId, collectionAddress} = await helper.eth.createRefungibleCollection(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 tokenAddress = tokenIdToAddress(collectionId, tokenId);
-    const tokenContract = uniqueRefungibleToken(web3, tokenAddress, caller);
+    const tokenContract = helper.ethNativeContract.rftTokenById(collectionId, tokenId, caller);
 
     await tokenContract.methods.repartition(2).send();
 
-    const events =  await recordEvents(contract, async () =>
-      await tokenContract.methods.transfer(receiver, 1).send());
+    const events: any = [];
+    contract.events.allEvents((_: any, event: any) => {
+      events.push(event);
+    });
+    await tokenContract.methods.transfer(receiver, 1).send();
 
-    expect(events).to.deep.equal([
-      {
-        address: collectionIdAddress,
-        event: 'Transfer',
-        args: {
-          from: caller,
-          to: '0xFFfFfFffFFfffFFfFFfFFFFFffFFFffffFfFFFfF',
-          tokenId: tokenId.toString(),
-        },
-      },
-    ]);
+    const event = events[0];
+    expect(event.address).to.equal(collectionAddress);
+    expect(event.returnValues.from).to.equal(caller);
+    expect(event.returnValues.to).to.equal('0xFFfFfFffFFfffFFfFFfFFFFFffFFFffffFfFFFfF');
+    expect(event.returnValues.tokenId).to.equal(tokenId.toString());
   });
 });
 
 describe('RFT: Fees', () => {
+  let donor: IKeyringPair;
+
   before(async function() {
-    await requirePallets(this, [Pallets.ReFungible]);
+    await usingEthPlaygrounds(async (helper, privateKey) => {
+      requirePalletsOrSkip(this, helper, [Pallets.ReFungible]);
+
+      donor = privateKey('//Alice');
+    });
   });
 
-  itWeb3('transferFrom() call fee is less than 0.2UNQ', async ({web3, api, privateKeyWrapper}) => {
-    const caller = await createEthAccountWithBalance(api, web3, privateKeyWrapper);
-    const helper = evmCollectionHelpers(web3, caller);
-    const result = await helper.methods.createRFTCollection('Mint collection', '6', '6').send();
-    const {collectionIdAddress} = await getCollectionAddressFromResult(api, result);
-    const contract = evmCollection(web3, caller, collectionIdAddress, {type: 'ReFungible'});
-
-    const receiver = createEthAccount(web3);
+  itEth('transferFrom() call fee is less than 0.2UNQ', async ({helper}) => {
+    const caller = await helper.eth.createAccountWithBalance(donor);
+    const receiver = helper.eth.createAccount();
+    const {collectionAddress} = await helper.eth.createRefungibleCollection(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 cost = await recordEthFee(api, caller, () => contract.methods.transferFrom(caller, receiver, tokenId).send());
-    expect(cost < BigInt(0.2 * Number(UNIQUE)));
+    const cost = await helper.eth.recordCallFee(caller, () => contract.methods.transferFrom(caller, receiver, tokenId).send());
+    expect(cost < BigInt(0.2 * Number(helper.balance.getOneTokenNominal())));
     expect(cost > 0n);
   });
 
-  itWeb3('transfer() call fee is less than 0.2UNQ', async ({web3, api, privateKeyWrapper}) => {
-    const caller = await createEthAccountWithBalance(api, web3, privateKeyWrapper);
-    const helper = evmCollectionHelpers(web3, caller);
-    const result = await helper.methods.createRFTCollection('Mint collection', '6', '6').send();
-    const {collectionIdAddress} = await getCollectionAddressFromResult(api, result);
-    const contract = evmCollection(web3, caller, collectionIdAddress, {type: 'ReFungible'});
-
-    const receiver = createEthAccount(web3);
+  itEth('transfer() call fee is less than 0.2UNQ', async ({helper}) => {
+    const caller = await helper.eth.createAccountWithBalance(donor);
+    const receiver = helper.eth.createAccount();
+    const {collectionAddress} = await helper.eth.createRefungibleCollection(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 cost = await recordEthFee(api, caller, () => contract.methods.transfer(receiver, tokenId).send());
-    expect(cost < BigInt(0.2 * Number(UNIQUE)));
+    const cost = await helper.eth.recordCallFee(caller, () => contract.methods.transfer(receiver, tokenId).send());
+    expect(cost < BigInt(0.2 * Number(helper.balance.getOneTokenNominal())));
     expect(cost > 0n);
   });
 });
 
 describe('Common metadata', () => {
+  let donor: IKeyringPair;
+  let alice: IKeyringPair;
+
   before(async function() {
-    await requirePallets(this, [Pallets.ReFungible]);
-  });
+    await usingEthPlaygrounds(async (helper, privateKey) => {
+      requirePalletsOrSkip(this, helper, [Pallets.ReFungible]);
 
-  itWeb3('Returns collection name', async ({api, web3, privateKeyWrapper}) => {
-    const collection = await createCollectionExpectSuccess({
-      name: 'token name',
-      mode: {type: 'ReFungible'},
+      donor = privateKey('//Alice');
+      [alice] = await helper.arrange.createAccounts([20n], donor);
     });
-    const caller = await createEthAccountWithBalance(api, web3, privateKeyWrapper);
+  });
 
-    const address = collectionIdToAddress(collection);
-    const contract = evmCollection(web3, caller, address, {type: 'ReFungible'});
+  itEth('Returns collection name', async ({helper}) => {
+    const caller = helper.eth.createAccount();
+    const collection = await helper.rft.mintCollection(alice, {name: 'Leviathan', tokenPrefix: '11'});
+    
+    const contract = helper.ethNativeContract.collectionById(collection.collectionId, 'rft', caller);
     const name = await contract.methods.name().call();
-
-    expect(name).to.equal('token name');
+    expect(name).to.equal('Leviathan');
   });
 
-  itWeb3('Returns symbol name', async ({api, web3, privateKeyWrapper}) => {
-    const collection = await createCollectionExpectSuccess({
-      tokenPrefix: 'TOK',
-      mode: {type: 'ReFungible'},
-    });
-    const caller = await createEthAccountWithBalance(api, web3, privateKeyWrapper);
-
-    const address = collectionIdToAddress(collection);
-    const contract = evmCollection(web3, caller, address, {type: 'ReFungible'});
+  itEth('Returns symbol name', async ({helper}) => {
+    const caller = await helper.eth.createAccountWithBalance(donor);
+    const {collectionAddress} = await helper.eth.createRefungibleCollection(caller, 'Leviathan', '', '12');
+    const contract = helper.ethNativeContract.collection(collectionAddress, 'rft', caller);
     const symbol = await contract.methods.symbol().call();
-
-    expect(symbol).to.equal('TOK');
+    expect(symbol).to.equal('12');
   });
 });
modifiedtests/src/eth/reFungibleToken.test.tsdiffbeforeafterboth
--- a/tests/src/eth/reFungibleToken.test.ts
+++ b/tests/src/eth/reFungibleToken.test.ts
@@ -14,82 +14,76 @@
 // You should have received a copy of the GNU General Public License
 // along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
 
-import {approve, createCollection, createRefungibleToken, transfer, transferFrom, UNIQUE, requirePallets, Pallets} from '../util/helpers';
-import {collectionIdToAddress, createEthAccount, createEthAccountWithBalance, createRFTCollection, evmCollection, evmCollectionHelpers, getCollectionAddressFromResult, itWeb3, normalizeEvents, recordEthFee, recordEvents, subToEth, tokenIdToAddress, transferBalanceToEth, uniqueRefungible, uniqueRefungibleToken} from './util/helpers';
+import {Pallets, requirePalletsOrSkip} from '../util/playgrounds';
+import {EthUniqueHelper, expect, itEth, usingEthPlaygrounds} from './util/playgrounds';
+import {IKeyringPair} from '@polkadot/types/types';
+import {Contract} from 'web3-eth-contract';
 
-import chai from 'chai';
-import chaiAsPromised from 'chai-as-promised';
-chai.use(chaiAsPromised);
-const expect = chai.expect;
+describe('Refungible token: Information getting', () => {
+  let donor: IKeyringPair;
+  let alice: IKeyringPair;
 
-describe('Refungible token: Information getting', () => {
   before(async function() {
-    await requirePallets(this, [Pallets.ReFungible]);
-  });
+    await usingEthPlaygrounds(async (helper, privateKey) => {
+      requirePalletsOrSkip(this, helper, [Pallets.ReFungible]);
 
-  itWeb3('totalSupply', async ({api, web3, privateKeyWrapper}) => {
-    const alice = privateKeyWrapper('//Alice');
-
-    const collectionId = (await createCollection(api, alice, {name: 'token name', mode: {type: 'ReFungible'}})).collectionId;
-
-    const caller = await createEthAccountWithBalance(api, web3, privateKeyWrapper);
+      donor = privateKey('//Alice');
+      [alice] = await helper.arrange.createAccounts([20n], donor);
+    });
+  });
 
-    const tokenId = (await createRefungibleToken(api, alice, collectionId, 200n, {Ethereum: caller})).itemId;
+  itEth('totalSupply', async ({helper}) => {
+    const caller = await helper.eth.createAccountWithBalance(donor);
+    const collection = await helper.rft.mintCollection(alice, {tokenPrefix: 'MUON'});
+    const {tokenId} = await collection.mintToken(alice, 200n, {Ethereum: caller});
 
-    const address = tokenIdToAddress(collectionId, tokenId);
-    const contract = uniqueRefungibleToken(web3, address, caller);
+    const contract = helper.ethNativeContract.rftTokenById(collection.collectionId, tokenId, caller);
     const totalSupply = await contract.methods.totalSupply().call();
-
     expect(totalSupply).to.equal('200');
   });
 
-  itWeb3('balanceOf', async ({api, web3, privateKeyWrapper}) => {
-    const alice = privateKeyWrapper('//Alice');
-
-    const collectionId = (await createCollection(api, alice, {name: 'token name', mode: {type: 'ReFungible'}})).collectionId;
+  itEth('balanceOf', async ({helper}) => {
+    const caller = await helper.eth.createAccountWithBalance(donor);
+    const collection = await helper.rft.mintCollection(alice, {tokenPrefix: 'MUON'});
+    const {tokenId} = await collection.mintToken(alice, 200n, {Ethereum: caller});
 
-    const caller = await createEthAccountWithBalance(api, web3, privateKeyWrapper);
-
-    const tokenId = (await createRefungibleToken(api, alice, collectionId, 200n, {Ethereum: caller})).itemId;
-
-    const address = tokenIdToAddress(collectionId, tokenId);
-    const contract = uniqueRefungibleToken(web3, address, caller);
+    const contract = helper.ethNativeContract.rftTokenById(collection.collectionId, tokenId, caller);
     const balance = await contract.methods.balanceOf(caller).call();
-
     expect(balance).to.equal('200');
   });
 
-  itWeb3('decimals', async ({api, web3, privateKeyWrapper}) => {
-    const alice = privateKeyWrapper('//Alice');
+  itEth('decimals', async ({helper}) => {
+    const caller = await helper.eth.createAccountWithBalance(donor);
+    const collection = await helper.rft.mintCollection(alice, {tokenPrefix: 'MUON'});
+    const {tokenId} = await collection.mintToken(alice, 200n, {Ethereum: caller});
 
-    const collectionId = (await createCollection(api, alice, {name: 'token name', mode: {type: 'ReFungible'}})).collectionId;
-
-    const caller = await createEthAccountWithBalance(api, web3, privateKeyWrapper);
-
-    const tokenId = (await createRefungibleToken(api, alice, collectionId, 200n, {Ethereum: caller})).itemId;
-
-    const address = tokenIdToAddress(collectionId, tokenId);
-    const contract = uniqueRefungibleToken(web3, address, caller);
+    const contract = helper.ethNativeContract.rftTokenById(collection.collectionId, tokenId, caller);
     const decimals = await contract.methods.decimals().call();
-
     expect(decimals).to.equal('0');
   });
 });
 
 // FIXME: Need erc721 for ReFubgible.
 describe('Check ERC721 token URI for ReFungible', () => {
+  let donor: IKeyringPair;
+
   before(async function() {
-    await requirePallets(this, [Pallets.ReFungible]);
+    await usingEthPlaygrounds(async (helper, privateKey) => {
+      requirePalletsOrSkip(this, helper, [Pallets.ReFungible]);
+
+      donor = privateKey('//Alice');
+    });
   });
 
-  itWeb3('Empty tokenURI', async ({web3, api, privateKeyWrapper}) => {
-    const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);
-    const helper = evmCollectionHelpers(web3, owner);
-    let result = await helper.methods.createERC721MetadataCompatibleCollection('Mint collection', '1', '1', '').send();
-    const {collectionIdAddress, collectionId} = await getCollectionAddressFromResult(api, result);
-    const receiver = createEthAccount(web3);
-    const contract = evmCollection(web3, owner, collectionIdAddress, {type: 'ReFungible'});
+  async function setup(helper: EthUniqueHelper, tokenPrefix: string, propertyKey?: string, propertyValue?: string): Promise<{contract: Contract, nextTokenId: string}> {
+    const owner = await helper.eth.createAccountWithBalance(donor);
+    const receiver = helper.eth.createAccount();
 
+    const collectionHelper = helper.ethNativeContract.collectionHelpers(owner);
+    let result = await collectionHelper.methods.createERC721MetadataCompatibleCollection('Mint collection', 'a', 'b', tokenPrefix).send();
+    const collectionAddress = helper.ethAddress.normalizeAddress(result.events.CollectionCreated.returnValues.collectionId);
+    const contract = helper.ethNativeContract.collection(collectionAddress, 'rft', owner);
+    
     const nextTokenId = await contract.methods.nextTokenId().call();
     expect(nextTokenId).to.be.equal('1');
     result = await contract.methods.mint(
@@ -97,166 +91,71 @@
       nextTokenId,
     ).send();
 
-    const events = normalizeEvents(result.events);
-    const address = collectionIdToAddress(collectionId);
+    if (propertyKey && propertyValue) {
+      // Set URL or suffix
+      await contract.methods.setProperty(nextTokenId, 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(events).to.be.deep.equal([
-      {
-        address,
-        event: 'Transfer',
-        args: {
-          from: '0x0000000000000000000000000000000000000000',
-          to: receiver,
-          tokenId: nextTokenId,
-        },
-      },
-    ]);
+    return {contract, nextTokenId};
+  }
 
+  itEth('Empty tokenURI', async ({helper}) => {
+    const {contract, nextTokenId} = await setup(helper, '');
     expect(await contract.methods.tokenURI(nextTokenId).call()).to.be.equal('');
   });
-
-  itWeb3('TokenURI from url', async ({web3, api, privateKeyWrapper}) => {
-    const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);
-    const helper = evmCollectionHelpers(web3, owner);
-    let result = await helper.methods.createERC721MetadataCompatibleCollection('Mint collection', '1', '1', 'BaseURI_').send();
-    const {collectionIdAddress, collectionId} = await getCollectionAddressFromResult(api, result);
-    const receiver = createEthAccount(web3);
-    const contract = evmCollection(web3, owner, collectionIdAddress, {type: 'ReFungible'});
 
-    const nextTokenId = await contract.methods.nextTokenId().call();
-    expect(nextTokenId).to.be.equal('1');
-    result = await contract.methods.mint(
-      receiver,
-      nextTokenId,
-    ).send();
-
-    // Set URL
-    await contract.methods.setProperty(nextTokenId, 'url', Buffer.from('Token URI')).send();
-
-    const events = normalizeEvents(result.events);
-    const address = collectionIdToAddress(collectionId);
-
-    expect(events).to.be.deep.equal([
-      {
-        address,
-        event: 'Transfer',
-        args: {
-          from: '0x0000000000000000000000000000000000000000',
-          to: receiver,
-          tokenId: nextTokenId,
-        },
-      },
-    ]);
-
+  itEth('TokenURI from url', async ({helper}) => {
+    const {contract, nextTokenId} = await setup(helper, 'BaseURI_', 'url', 'Token URI');
     expect(await contract.methods.tokenURI(nextTokenId).call()).to.be.equal('Token URI');
   });
-
-  itWeb3('TokenURI from baseURI + tokenId', async ({web3, api, privateKeyWrapper}) => {
-    const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);
-    const helper = evmCollectionHelpers(web3, owner);
-    let result = await helper.methods.createERC721MetadataCompatibleCollection('Mint collection', '1', '1', 'BaseURI_').send();
-    const {collectionIdAddress, collectionId} = await getCollectionAddressFromResult(api, result);
-    const receiver = createEthAccount(web3);
-    const contract = evmCollection(web3, owner, collectionIdAddress, {type: 'ReFungible'});
 
-    const nextTokenId = await contract.methods.nextTokenId().call();
-    expect(nextTokenId).to.be.equal('1');
-    result = await contract.methods.mint(
-      receiver,
-      nextTokenId,
-    ).send();
-
-    const events = normalizeEvents(result.events);
-    const address = collectionIdToAddress(collectionId);
-
-    expect(events).to.be.deep.equal([
-      {
-        address,
-        event: 'Transfer',
-        args: {
-          from: '0x0000000000000000000000000000000000000000',
-          to: receiver,
-          tokenId: nextTokenId,
-        },
-      },
-    ]);
-
+  itEth('TokenURI from baseURI + tokenId', async ({helper}) => {
+    const {contract, nextTokenId} = await setup(helper, 'BaseURI_');
     expect(await contract.methods.tokenURI(nextTokenId).call()).to.be.equal('BaseURI_' + nextTokenId);
   });
 
-  itWeb3('TokenURI from baseURI + suffix', async ({web3, api, privateKeyWrapper}) => {
-    const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);
-    const helper = evmCollectionHelpers(web3, owner);
-    let result = await helper.methods.createERC721MetadataCompatibleCollection('Mint collection', '1', '1', 'BaseURI_').send();
-    const {collectionIdAddress, collectionId} = await getCollectionAddressFromResult(api, result);
-    const receiver = createEthAccount(web3);
-    const contract = evmCollection(web3, owner, collectionIdAddress, {type: 'ReFungible'});
-
-    const nextTokenId = await contract.methods.nextTokenId().call();
-    expect(nextTokenId).to.be.equal('1');
-    result = await contract.methods.mint(
-      receiver,
-      nextTokenId,
-    ).send();
-
-    // Set suffix
+  itEth('TokenURI from baseURI + suffix', async ({helper}) => {
     const suffix = '/some/suffix';
-    await contract.methods.setProperty(nextTokenId, 'suffix', Buffer.from(suffix)).send();
-
-    const events = normalizeEvents(result.events);
-    const address = collectionIdToAddress(collectionId);
-
-    expect(events).to.be.deep.equal([
-      {
-        address,
-        event: 'Transfer',
-        args: {
-          from: '0x0000000000000000000000000000000000000000',
-          to: receiver,
-          tokenId: nextTokenId,
-        },
-      },
-    ]);
-
+    const {contract, nextTokenId} = await setup(helper, 'BaseURI_', 'suffix', suffix);
     expect(await contract.methods.tokenURI(nextTokenId).call()).to.be.equal('BaseURI_' + suffix);
   });
 });
 
 describe('Refungible: Plain calls', () => {
+  let donor: IKeyringPair;
+  let alice: IKeyringPair;
+
   before(async function() {
-    await requirePallets(this, [Pallets.ReFungible]);
+    await usingEthPlaygrounds(async (helper, privateKey) => {
+      requirePalletsOrSkip(this, helper, [Pallets.ReFungible]);
+
+      donor = privateKey('//Alice');
+      [alice] = await helper.arrange.createAccounts([50n], donor);
+    });
   });
 
-  itWeb3('Can perform approve()', async ({web3, api, privateKeyWrapper}) => {
-    const alice = privateKeyWrapper('//Alice');
+  itEth('Can perform approve()', async ({helper}) => {
+    const owner = await helper.eth.createAccountWithBalance(donor);
+    const spender = helper.eth.createAccount();
+    const collection = await helper.rft.mintCollection(alice);
+    const {tokenId} = await collection.mintToken(alice, 200n, {Ethereum: owner});
 
-    const collectionId = (await createCollection(api, alice, {name: 'token name', mode: {type: 'ReFungible'}})).collectionId;
-
-    const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);
-
-    const tokenId = (await createRefungibleToken(api, alice, collectionId, 200n, {Ethereum: owner})).itemId;
-
-    const address = tokenIdToAddress(collectionId, tokenId);
+    const tokenAddress = helper.ethAddress.fromTokenId(collection.collectionId, tokenId);
+    const contract = helper.ethNativeContract.rftToken(tokenAddress, owner);
 
-    const spender = createEthAccount(web3);
-
-    const contract = uniqueRefungibleToken(web3, address, owner);
-
     {
       const result = await contract.methods.approve(spender, 100).send({from: owner});
-      const events = normalizeEvents(result.events);
-
-      expect(events).to.be.deep.equal([
-        {
-          address,
-          event: 'Approval',
-          args: {
-            owner,
-            spender,
-            value: '100',
-          },
-        },
-      ]);
+      const event = result.events.Approval;
+      expect(event.address).to.be.equal(tokenAddress);
+      expect(event.returnValues.owner).to.be.equal(owner);
+      expect(event.returnValues.spender).to.be.equal(spender);
+      expect(event.returnValues.value).to.be.equal('100');
     }
 
     {
@@ -265,49 +164,31 @@
     }
   });
 
-  itWeb3('Can perform transferFrom()', async ({web3, api, privateKeyWrapper}) => {
-    const alice = privateKeyWrapper('//Alice');
-
-    const collectionId = (await createCollection(api, alice, {name: 'token name', mode: {type: 'ReFungible'}})).collectionId;
+  itEth('Can perform transferFrom()', async ({helper}) => {
+    const owner = await helper.eth.createAccountWithBalance(donor);
+    const spender = await helper.eth.createAccountWithBalance(donor);
+    const receiver = helper.eth.createAccount();
+    const collection = await helper.rft.mintCollection(alice);
+    const {tokenId} = await collection.mintToken(alice, 200n, {Ethereum: owner});
 
-    const owner = createEthAccount(web3);
-    await transferBalanceToEth(api, alice, owner);
-
-    const tokenId = (await createRefungibleToken(api, alice, collectionId, 200n, {Ethereum: owner})).itemId;
-
-    const spender = createEthAccount(web3);
-    await transferBalanceToEth(api, alice, spender);
+    const tokenAddress = helper.ethAddress.fromTokenId(collection.collectionId, tokenId);
+    const contract = helper.ethNativeContract.rftToken(tokenAddress, owner);
 
-    const receiver = createEthAccount(web3);
-
-    const address = tokenIdToAddress(collectionId, tokenId);
-    const contract = uniqueRefungibleToken(web3, address, owner);
-
     await contract.methods.approve(spender, 100).send();
 
     {
       const result = await contract.methods.transferFrom(owner, receiver, 49).send({from: spender});
-      const events = normalizeEvents(result.events);
-      expect(events).to.include.deep.members([
-        {
-          address,
-          event: 'Transfer',
-          args: {
-            from: owner,
-            to: receiver,
-            value: '49',
-          },
-        },
-        {
-          address,
-          event: 'Approval',
-          args: {
-            owner,
-            spender,
-            value: '51',
-          },
-        },
-      ]);
+      let event = result.events.Transfer;
+      expect(event.address).to.be.equal(tokenAddress);
+      expect(event.returnValues.from).to.be.equal(owner);
+      expect(event.returnValues.to).to.be.equal(receiver);
+      expect(event.returnValues.value).to.be.equal('49');
+
+      event = result.events.Approval;
+      expect(event.address).to.be.equal(tokenAddress);
+      expect(event.returnValues.owner).to.be.equal(owner);
+      expect(event.returnValues.spender).to.be.equal(spender);
+      expect(event.returnValues.value).to.be.equal('51');
     }
 
     {
@@ -321,36 +202,22 @@
     }
   });
 
-  itWeb3('Can perform transfer()', async ({web3, api, privateKeyWrapper}) => {
-    const alice = privateKeyWrapper('//Alice');
+  itEth('Can perform transfer()', async ({helper}) => {
+    const owner = await helper.eth.createAccountWithBalance(donor);
+    const receiver = helper.eth.createAccount();
+    const collection = await helper.rft.mintCollection(alice);
+    const {tokenId} = await collection.mintToken(alice, 200n, {Ethereum: owner});
 
-    const collectionId = (await createCollection(api, alice, {name: 'token name', mode: {type: 'ReFungible'}})).collectionId;
-
-    const owner = createEthAccount(web3);
-    await transferBalanceToEth(api, alice, owner);
-
-    const tokenId = (await createRefungibleToken(api, alice, collectionId, 200n, {Ethereum: owner})).itemId;
-
-    const receiver = createEthAccount(web3);
-    await transferBalanceToEth(api, alice, receiver);
-
-    const address = tokenIdToAddress(collectionId, tokenId);
-    const contract = uniqueRefungibleToken(web3, address, owner);
+    const tokenAddress = helper.ethAddress.fromTokenId(collection.collectionId, tokenId);
+    const contract = helper.ethNativeContract.rftToken(tokenAddress, owner);
 
     {
       const result = await contract.methods.transfer(receiver, 50).send({from: owner});
-      const events = normalizeEvents(result.events);
-      expect(events).to.include.deep.members([
-        {
-          address,
-          event: 'Transfer',
-          args: {
-            from: owner,
-            to: receiver,
-            value: '50',
-          },
-        },
-      ]);
+      const event = result.events.Transfer;
+      expect(event.address).to.be.equal(tokenAddress);
+      expect(event.returnValues.from).to.be.equal(owner);
+      expect(event.returnValues.to).to.be.equal(receiver);
+      expect(event.returnValues.value).to.be.equal('50');
     }
 
     {
@@ -364,311 +231,262 @@
     }
   });
 
-  itWeb3('Can perform repartition()', async ({web3, api, privateKeyWrapper}) => {
-    const alice = privateKeyWrapper('//Alice');
-
-    const collectionId = (await createCollection(api, alice, {name: 'token name', mode: {type: 'ReFungible'}})).collectionId;
+  itEth('Can perform repartition()', async ({helper}) => {
+    const owner = await helper.eth.createAccountWithBalance(donor);
+    const receiver = await helper.eth.createAccountWithBalance(donor);
+    const collection = await helper.rft.mintCollection(alice);
+    const {tokenId} = await collection.mintToken(alice, 100n, {Ethereum: owner});
 
-    const owner = createEthAccount(web3);
-    await transferBalanceToEth(api, alice, owner);
+    const tokenAddress = helper.ethAddress.fromTokenId(collection.collectionId, tokenId);
+    const contract = helper.ethNativeContract.rftToken(tokenAddress, owner);
 
-    const receiver = createEthAccount(web3);
-    await transferBalanceToEth(api, alice, receiver);
-
-    const tokenId = (await createRefungibleToken(api, alice, collectionId, 100n, {Ethereum: owner})).itemId;
-
-    const address = tokenIdToAddress(collectionId, tokenId);
-    const contract = uniqueRefungibleToken(web3, address, owner);
-
     await contract.methods.repartition(200).send({from: owner});
     expect(+await contract.methods.balanceOf(owner).call()).to.be.equal(200);
     await contract.methods.transfer(receiver, 110).send({from: owner});
     expect(+await contract.methods.balanceOf(owner).call()).to.be.equal(90);
     expect(+await contract.methods.balanceOf(receiver).call()).to.be.equal(110);
 
-    await expect(contract.methods.repartition(80).send({from: owner})).to.eventually.be.rejected;
+    await expect(contract.methods.repartition(80).send({from: owner})).to.eventually.be.rejected; // Transaction is reverted
 
     await contract.methods.transfer(receiver, 90).send({from: owner});
     expect(+await contract.methods.balanceOf(owner).call()).to.be.equal(0);
     expect(+await contract.methods.balanceOf(receiver).call()).to.be.equal(200);
 
     await contract.methods.repartition(150).send({from: receiver});
-    await expect(contract.methods.transfer(owner, 160).send({from: receiver})).to.eventually.be.rejected;
+    await expect(contract.methods.transfer(owner, 160).send({from: receiver})).to.eventually.be.rejected; // Transaction is reverted
     expect(+await contract.methods.balanceOf(receiver).call()).to.be.equal(150);
   });
 
-  itWeb3('Can repartition with increased amount', async ({web3, api, privateKeyWrapper}) => {
-    const alice = privateKeyWrapper('//Alice');
-
-    const collectionId = (await createCollection(api, alice, {name: 'token name', mode: {type: 'ReFungible'}})).collectionId;
-
-    const owner = createEthAccount(web3);
-    await transferBalanceToEth(api, alice, owner);
-
-    const tokenId = (await createRefungibleToken(api, alice, collectionId, 100n, {Ethereum: owner})).itemId;
+  itEth('Can repartition with increased amount', async ({helper}) => {
+    const owner = await helper.eth.createAccountWithBalance(donor);
+    const collection = await helper.rft.mintCollection(alice);
+    const {tokenId} = await collection.mintToken(alice, 100n, {Ethereum: owner});
 
-    const address = tokenIdToAddress(collectionId, tokenId);
-    const contract = uniqueRefungibleToken(web3, address, owner);
+    const tokenAddress = helper.ethAddress.fromTokenId(collection.collectionId, tokenId);
+    const contract = helper.ethNativeContract.rftToken(tokenAddress, owner);
 
     const result = await contract.methods.repartition(200).send();
-    const events = normalizeEvents(result.events);
 
-    expect(events).to.deep.equal([
-      {
-        address,
-        event: 'Transfer',
-        args: {
-          from: '0x0000000000000000000000000000000000000000',
-          to: owner,
-          value: '100',
-        },
-      },
-    ]);
+    const event = result.events.Transfer;
+    expect(event.address).to.be.equal(tokenAddress);
+    expect(event.returnValues.from).to.be.equal('0x0000000000000000000000000000000000000000');
+    expect(event.returnValues.to).to.be.equal(owner);
+    expect(event.returnValues.value).to.be.equal('100');
   });
 
-  itWeb3('Can repartition with decreased amount', async ({web3, api, privateKeyWrapper}) => {
-    const alice = privateKeyWrapper('//Alice');
+  itEth('Can repartition with decreased amount', async ({helper}) => {
+    const owner = await helper.eth.createAccountWithBalance(donor);
+    const collection = await helper.rft.mintCollection(alice);
+    const {tokenId} = await collection.mintToken(alice, 100n, {Ethereum: owner});
 
-    const collectionId = (await createCollection(api, alice, {name: 'token name', mode: {type: 'ReFungible'}})).collectionId;
-
-    const owner = createEthAccount(web3);
-    await transferBalanceToEth(api, alice, owner);
-
-    const tokenId = (await createRefungibleToken(api, alice, collectionId, 100n, {Ethereum: owner})).itemId;
-
-    const address = tokenIdToAddress(collectionId, tokenId);
-    const contract = uniqueRefungibleToken(web3, address, owner);
+    const tokenAddress = helper.ethAddress.fromTokenId(collection.collectionId, tokenId);
+    const contract = helper.ethNativeContract.rftToken(tokenAddress, owner);
 
     const result = await contract.methods.repartition(50).send();
-    const events = normalizeEvents(result.events);
-    expect(events).to.deep.equal([
-      {
-        address,
-        event: 'Transfer',
-        args: {
-          from: owner,
-          to: '0x0000000000000000000000000000000000000000',
-          value: '50',
-        },
-      },
-    ]);
+    const event = result.events.Transfer;
+    expect(event.address).to.be.equal(tokenAddress);
+    expect(event.returnValues.from).to.be.equal(owner);
+    expect(event.returnValues.to).to.be.equal('0x0000000000000000000000000000000000000000');
+    expect(event.returnValues.value).to.be.equal('50');
   });
 
-  itWeb3('Receiving Transfer event on burning into full ownership', async ({web3, api, privateKeyWrapper}) => {
-    const caller = await createEthAccountWithBalance(api, web3, privateKeyWrapper);
-    const receiver = await createEthAccountWithBalance(api, web3, privateKeyWrapper);
-    const helper = evmCollectionHelpers(web3, caller);
-    const result = await helper.methods.createRFTCollection('Mint collection', '6', '6').send();
-    const {collectionIdAddress, collectionId} = await getCollectionAddressFromResult(api, result);
-    const contract = evmCollection(web3, caller, collectionIdAddress, {type: 'ReFungible'});
+  itEth('Receiving Transfer event on burning into full ownership', async ({helper}) => {
+    const caller = await helper.eth.createAccountWithBalance(donor);
+    const receiver = await helper.eth.createAccountWithBalance(donor);
+    const {collectionId, collectionAddress} = await helper.eth.createRefungibleCollection(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 tokenAddress = helper.ethAddress.fromTokenId(collectionId, tokenId);
+    const tokenContract = helper.ethNativeContract.rftToken(tokenAddress, caller);
 
-    const address = tokenIdToAddress(collectionId, tokenId);
-
-    const tokenContract =  uniqueRefungibleToken(web3, address, caller);
     await tokenContract.methods.repartition(2).send();
     await tokenContract.methods.transfer(receiver, 1).send();
 
-    const events =  await recordEvents(contract, async () =>
-      await tokenContract.methods.burnFrom(caller, 1).send());
-    expect(events).to.deep.equal([
-      {
-        address: collectionIdAddress,
-        event: 'Transfer',
-        args: {
-          from: '0xFFfFfFffFFfffFFfFFfFFFFFffFFFffffFfFFFfF',
-          to: receiver,
-          tokenId,
-        },
-      },
-    ]);
+    const events: any = [];
+    contract.events.allEvents((_: any, event: any) => {
+      events.push(event);
+    });
+    await tokenContract.methods.burnFrom(caller, 1).send();
+
+    const event = events[0];
+    expect(event.address).to.be.equal(collectionAddress);
+    expect(event.returnValues.from).to.be.equal('0xFFfFfFffFFfffFFfFFfFFFFFffFFFffffFfFFFfF');
+    expect(event.returnValues.to).to.be.equal(receiver);
+    expect(event.returnValues.tokenId).to.be.equal(tokenId);
   });
 });
 
 describe('Refungible: Fees', () => {
+  let donor: IKeyringPair;
+  let alice: IKeyringPair;
+
   before(async function() {
-    await requirePallets(this, [Pallets.ReFungible]);
+    await usingEthPlaygrounds(async (helper, privateKey) => {
+      requirePalletsOrSkip(this, helper, [Pallets.ReFungible]);
+
+      donor = privateKey('//Alice');
+      [alice] = await helper.arrange.createAccounts([50n], donor);
+    });
   });
 
-  itWeb3('approve() call fee is less than 0.2UNQ', async ({web3, api, privateKeyWrapper}) => {
-    const alice = privateKeyWrapper('//Alice');
+  itEth('approve() call fee is less than 0.2UNQ', async ({helper}) => {
+    const owner = await helper.eth.createAccountWithBalance(donor);
+    const spender = helper.eth.createAccount();
+    const collection = await helper.rft.mintCollection(alice);
+    const {tokenId} = await collection.mintToken(alice, 100n, {Ethereum: owner});
 
-    const collectionId = (await createCollection(api, alice, {mode: {type: 'ReFungible'}})).collectionId;
+    const tokenAddress = helper.ethAddress.fromTokenId(collection.collectionId, tokenId);
+    const contract = helper.ethNativeContract.rftToken(tokenAddress, owner);
 
-    const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);
-    const spender = createEthAccount(web3);
-
-    const tokenId = (await createRefungibleToken(api, alice, collectionId, 200n, {Ethereum: owner})).itemId;
-
-    const address = tokenIdToAddress(collectionId, tokenId);
-    const contract = uniqueRefungibleToken(web3, address, owner);
-
-    const cost = await recordEthFee(api, owner, () => contract.methods.approve(spender, 100).send({from: owner}));
-    expect(cost < BigInt(0.2 * Number(UNIQUE)));
+    const cost = await helper.eth.recordCallFee(owner, () => contract.methods.approve(spender, 100).send({from: owner}));
+    expect(cost < BigInt(0.2 * Number(helper.balance.getOneTokenNominal())));
   });
 
-  itWeb3('transferFrom() call fee is less than 0.2UNQ', async ({web3, api, privateKeyWrapper}) => {
-    const alice = privateKeyWrapper('//Alice');
-
-    const collectionId = (await createCollection(api, alice, {mode: {type: 'ReFungible'}})).collectionId;
-
-    const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);
-    const spender = await createEthAccountWithBalance(api, web3, privateKeyWrapper);
-
-    const tokenId = (await createRefungibleToken(api, alice, collectionId, 200n, {Ethereum: owner})).itemId;
+  itEth('transferFrom() call fee is less than 0.2UNQ', async ({helper}) => {
+    const owner = await helper.eth.createAccountWithBalance(donor);
+    const spender = await helper.eth.createAccountWithBalance(donor);
+    const collection = await helper.rft.mintCollection(alice);
+    const {tokenId} = await collection.mintToken(alice, 200n, {Ethereum: owner});
 
-    const address = tokenIdToAddress(collectionId, tokenId);
-    const contract = uniqueRefungibleToken(web3, address, owner);
+    const tokenAddress = helper.ethAddress.fromTokenId(collection.collectionId, tokenId);
+    const contract = helper.ethNativeContract.rftToken(tokenAddress, owner);
 
     await contract.methods.approve(spender, 100).send({from: owner});
 
-    const cost = await recordEthFee(api, spender, () => contract.methods.transferFrom(owner, spender, 100).send({from: spender}));
-    expect(cost < BigInt(0.2 * Number(UNIQUE)));
+    const cost = await helper.eth.recordCallFee(spender, () => contract.methods.transferFrom(owner, spender, 100).send({from: spender}));
+    expect(cost < BigInt(0.2 * Number(helper.balance.getOneTokenNominal())));
   });
 
-  itWeb3('transfer() call fee is less than 0.2UNQ', async ({web3, api, privateKeyWrapper}) => {
-    const alice = privateKeyWrapper('//Alice');
+  itEth('transfer() call fee is less than 0.2UNQ', async ({helper}) => {
+    const owner = await helper.eth.createAccountWithBalance(donor);
+    const receiver = helper.eth.createAccount();
+    const collection = await helper.rft.mintCollection(alice);
+    const {tokenId} = await collection.mintToken(alice, 200n, {Ethereum: owner});
 
-    const collectionId = (await createCollection(api, alice, {mode: {type: 'ReFungible'}})).collectionId;
+    const tokenAddress = helper.ethAddress.fromTokenId(collection.collectionId, tokenId);
+    const contract = helper.ethNativeContract.rftToken(tokenAddress, owner);
 
-    const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);
-    const receiver = createEthAccount(web3);
-
-    const tokenId = (await createRefungibleToken(api, alice, collectionId, 200n, {Ethereum: owner})).itemId;
-
-    const address = tokenIdToAddress(collectionId, tokenId);
-    const contract = uniqueRefungibleToken(web3, address, owner);
-
-    const cost = await recordEthFee(api, owner, () => contract.methods.transfer(receiver, 100).send({from: owner}));
-    expect(cost < BigInt(0.2 * Number(UNIQUE)));
+    const cost = await helper.eth.recordCallFee(owner, () => contract.methods.transfer(receiver, 100).send({from: owner}));
+    expect(cost < BigInt(0.2 * Number(helper.balance.getOneTokenNominal())));
   });
 });
 
 describe('Refungible: Substrate calls', () => {
+  let donor: IKeyringPair;
+  let alice: IKeyringPair;
+
   before(async function() {
-    await requirePallets(this, [Pallets.ReFungible]);
-  });
+    await usingEthPlaygrounds(async (helper, privateKey) => {
+      requirePalletsOrSkip(this, helper, [Pallets.ReFungible]);
 
-  itWeb3('Events emitted for approve()', async ({web3, api, privateKeyWrapper}) => {
-    const alice = privateKeyWrapper('//Alice');
-
-    const collectionId = (await createCollection(api, alice, {mode: {type: 'ReFungible'}})).collectionId;
-
-    const receiver = createEthAccount(web3);
+      donor = privateKey('//Alice');
+      [alice] = await helper.arrange.createAccounts([50n], donor);
+    });
+  });
 
-    const tokenId = (await createRefungibleToken(api, alice, collectionId, 200n)).itemId;
+  itEth('Events emitted for approve()', async ({helper}) => {
+    const receiver = helper.eth.createAccount();
+    const collection = await helper.rft.mintCollection(alice);
+    const token = await collection.mintToken(alice, 200n);
 
-    const address = tokenIdToAddress(collectionId, tokenId);
-    const contract = uniqueRefungibleToken(web3, address);
+    const tokenAddress = helper.ethAddress.fromTokenId(collection.collectionId, token.tokenId);
+    const contract = helper.ethNativeContract.rftToken(tokenAddress);
 
-    const events = await recordEvents(contract, async () => {
-      expect(await approve(api, collectionId, tokenId, alice, {Ethereum: receiver}, 100n)).to.be.true;
+    const events: any = [];
+    contract.events.allEvents((_: any, event: any) => {
+      events.push(event);
     });
+    expect(await token.approve(alice, {Ethereum: receiver}, 100n)).to.be.true;
 
-    expect(events).to.be.deep.equal([
-      {
-        address,
-        event: 'Approval',
-        args: {
-          owner: subToEth(alice.address),
-          spender: receiver,
-          value: '100',
-        },
-      },
-    ]);
+    const event = events[0];
+    expect(event.event).to.be.equal('Approval');
+    expect(event.address).to.be.equal(tokenAddress);
+    expect(event.returnValues.owner).to.be.equal(helper.address.substrateToEth(alice.address));
+    expect(event.returnValues.spender).to.be.equal(receiver);
+    expect(event.returnValues.value).to.be.equal('100');
   });
 
-  itWeb3('Events emitted for transferFrom()', async ({web3, api, privateKeyWrapper}) => {
-    const alice = privateKeyWrapper('//Alice');
+  itEth('Events emitted for transferFrom()', async ({helper}) => {
+    const [bob] = await helper.arrange.createAccounts([10n], donor);
+    const receiver = helper.eth.createAccount();
+    const collection = await helper.rft.mintCollection(alice);
+    const token = await collection.mintToken(alice, 200n);
+    await token.approve(alice, {Substrate: bob.address}, 100n);
 
-    const collectionId = (await createCollection(api, alice, {mode: {type: 'ReFungible'}})).collectionId;
-    const bob = privateKeyWrapper('//Bob');
+    const tokenAddress = helper.ethAddress.fromTokenId(collection.collectionId, token.tokenId);
+    const contract = helper.ethNativeContract.rftToken(tokenAddress);
 
-    const receiver = createEthAccount(web3);
+    const events: any = [];
+    contract.events.allEvents((_: any, event: any) => {
+      events.push(event);
+    });
 
-    const tokenId = (await createRefungibleToken(api, alice, collectionId, 200n)).itemId;
-    expect(await approve(api, collectionId, tokenId, alice, bob.address, 100n)).to.be.true;
+    expect(await token.transferFrom(bob, {Substrate: alice.address}, {Ethereum: receiver},  51n)).to.be.true;
 
-    const address = tokenIdToAddress(collectionId, tokenId);
-    const contract = uniqueRefungibleToken(web3, address);
+    let event = events[0];
+    expect(event.event).to.be.equal('Transfer');
+    expect(event.address).to.be.equal(tokenAddress);
+    expect(event.returnValues.from).to.be.equal(helper.address.substrateToEth(alice.address));
+    expect(event.returnValues.to).to.be.equal(receiver);
+    expect(event.returnValues.value).to.be.equal('51');
 
-    const events = await recordEvents(contract, async () => {
-      expect(await transferFrom(api, collectionId, tokenId, bob, alice, {Ethereum: receiver},  51n)).to.be.true;
-    });
-
-    expect(events).to.be.deep.equal([
-      {
-        address,
-        event: 'Transfer',
-        args: {
-          from: subToEth(alice.address),
-          to: receiver,
-          value: '51',
-        },
-      },
-      {
-        address,
-        event: 'Approval',
-        args: {
-          owner: subToEth(alice.address),
-          spender: subToEth(bob.address),
-          value: '49',
-        },
-      },
-    ]);
+    event = events[1];
+    expect(event.event).to.be.equal('Approval');
+    expect(event.address).to.be.equal(tokenAddress);
+    expect(event.returnValues.owner).to.be.equal(helper.address.substrateToEth(alice.address));
+    expect(event.returnValues.spender).to.be.equal(helper.address.substrateToEth(bob.address));
+    expect(event.returnValues.value).to.be.equal('49');
   });
 
-  itWeb3('Events emitted for transfer()', async ({web3, api, privateKeyWrapper}) => {
-    const alice = privateKeyWrapper('//Alice');
+  itEth('Events emitted for transfer()', async ({helper}) => {
+    const receiver = helper.eth.createAccount();
+    const collection = await helper.rft.mintCollection(alice);
+    const token = await collection.mintToken(alice, 200n);
 
-    const collectionId = (await createCollection(api, alice, {mode: {type: 'ReFungible'}})).collectionId;
+    const tokenAddress = helper.ethAddress.fromTokenId(collection.collectionId, token.tokenId);
+    const contract = helper.ethNativeContract.rftToken(tokenAddress);
 
-    const receiver = createEthAccount(web3);
-
-    const tokenId = (await createRefungibleToken(api, alice, collectionId, 200n)).itemId;
+    const events: any = [];
+    contract.events.allEvents((_: any, event: any) => {
+      events.push(event);
+    });
 
-    const address = tokenIdToAddress(collectionId, tokenId);
-    const contract = uniqueRefungibleToken(web3, address);
+    expect(await token.transfer(alice, {Ethereum: receiver},  51n)).to.be.true;
 
-    const events = await recordEvents(contract, async () => {
-      expect(await transfer(api, collectionId, tokenId, alice, {Ethereum: receiver},  51n)).to.be.true;
-    });
-
-    expect(events).to.be.deep.equal([
-      {
-        address,
-        event: 'Transfer',
-        args: {
-          from: subToEth(alice.address),
-          to: receiver,
-          value: '51',
-        },
-      },
-    ]);
+    const event = events[0];
+    expect(event.event).to.be.equal('Transfer');
+    expect(event.address).to.be.equal(tokenAddress);
+    expect(event.returnValues.from).to.be.equal(helper.address.substrateToEth(alice.address));
+    expect(event.returnValues.to).to.be.equal(receiver);
+    expect(event.returnValues.value).to.be.equal('51');
   });
 });
 
 describe('ERC 1633 implementation', () => {
+  let donor: IKeyringPair;
+
   before(async function() {
-    await requirePallets(this, [Pallets.ReFungible]);
-  });
+    await usingEthPlaygrounds(async (helper, privateKey) => {
+      requirePalletsOrSkip(this, helper, [Pallets.ReFungible]);
 
-  itWeb3('Default parent token address and id', async ({api, web3, privateKeyWrapper}) => {
-    const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);
+      donor = privateKey('//Alice');
+    });
+  });
 
-    const {collectionIdAddress, collectionId} = await createRFTCollection(api, web3, owner);
-    const refungibleContract = uniqueRefungible(web3, collectionIdAddress, owner);
-    const refungibleTokenId = await refungibleContract.methods.nextTokenId().call();
-    await refungibleContract.methods.mint(owner, refungibleTokenId).send();
+  itEth('Default parent token address and id', async ({helper}) => {
+    const owner = await helper.eth.createAccountWithBalance(donor);
 
-    const rftTokenAddress = tokenIdToAddress(collectionId, refungibleTokenId);
-    const refungibleTokenContract = uniqueRefungibleToken(web3, rftTokenAddress, owner);
+    const {collectionId, collectionAddress} = await helper.eth.createRefungibleCollection(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 tokenAddress = helper.ethAddress.fromTokenId(collectionId, tokenId);
+    const tokenContract = helper.ethNativeContract.rftToken(tokenAddress, owner);
 
-    const tokenAddress = await refungibleTokenContract.methods.parentToken().call();
-    const tokenId = await refungibleTokenContract.methods.parentTokenId().call();
-    expect(tokenAddress).to.be.equal(collectionIdAddress);
-    expect(tokenId).to.be.equal(refungibleTokenId);
+    expect(await tokenContract.methods.parentToken().call()).to.be.equal(collectionAddress);
+    expect(await tokenContract.methods.parentTokenId().call()).to.be.equal(tokenId);
   });
 });
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
@@ -116,13 +116,17 @@
     return new web3.eth.Contract(abi as any, address, {gas: this.helper.eth.DEFAULT_GAS, ...(caller ? {from: caller} : {})});
   }
 
-  rftTokenByAddress(address: string, caller?: string): Contract {
+  collectionById(collectionId: number, mode: 'nft' | 'rft' | 'ft', caller?: string): Contract {
+    return this.collection(this.helper.ethAddress.fromCollectionId(collectionId), mode, caller);
+  }
+
+  rftToken(address: string, caller?: string): Contract {
     const web3 = this.helper.getWeb3();
     return new web3.eth.Contract(refungibleTokenAbi as any, address, {gas: this.helper.eth.DEFAULT_GAS, ...(caller ? {from: caller} : {})});
   }
 
-  rftToken(collectionId: number, tokenId: number, caller?: string): Contract {
-    return this.rftTokenByAddress(this.helper.ethAddress.fromTokenId(collectionId, tokenId), caller);
+  rftTokenById(collectionId: number, tokenId: number, caller?: string): Contract {
+    return this.rftToken(this.helper.ethAddress.fromTokenId(collectionId, tokenId), caller);
   }
 }
 
@@ -171,6 +175,17 @@
     return {collectionId, collectionAddress};
   }
 
+  async createRefungibleCollection(signer: string, name: string, description: string, tokenPrefix: string): Promise<{collectionId: number, collectionAddress: string}> {
+    const collectionHelper = this.helper.ethNativeContract.collectionHelpers(signer);
+        
+    const result = await collectionHelper.methods.createRFTCollection(name, description, tokenPrefix).send();
+
+    const collectionAddress = this.helper.ethAddress.normalizeAddress(result.events.CollectionCreated.returnValues.collectionId);
+    const collectionId = this.helper.ethAddress.extractCollectionId(collectionAddress);
+
+    return {collectionId, collectionAddress};
+  }
+
   async deployCollectorContract(signer: string): Promise<Contract> {
     return await this.helper.ethContract.deployByCode(signer, 'Collector', `
     // SPDX-License-Identifier: UNLICENSED
@@ -215,6 +230,16 @@
     }
   `);
   }
+
+  async recordCallFee(user: string, call: () => Promise<any>): Promise<bigint> {
+    const before = await this.helper.balance.getEthereum(user);
+    await call();
+    // In dev mode, the transaction might not finish processing in time
+    await this.helper.wait.newBlocks(1);
+    const after = await this.helper.balance.getEthereum(user);
+
+    return before - after;
+  }
 }  
   
 class EthAddressGroup extends EthGroupBase {