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
--- a/tests/src/eth/fungible.test.ts
+++ b/tests/src/eth/fungible.test.ts
@@ -14,204 +14,132 @@
 // 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, createCollection, createCollectionExpectSuccess, createFungibleItemExpectSuccess, transferExpectSuccess, transferFromExpectSuccess, UNIQUE} from '../util/helpers';
-import {collectionIdToAddress, createEthAccount, createEthAccountWithBalance, evmCollection, GAS_ARGS, itWeb3, normalizeEvents, recordEthFee, recordEvents, subToEth, transferBalanceToEth} from './util/helpers';
-import fungibleAbi from './fungibleAbi.json';
-import {expect} from 'chai';
-import {submitTransactionAsync} from '../substrate/substrate-api';
+import {expect, itEth, usingEthPlaygrounds} from './util/playgrounds';
+import {IKeyringPair} from '@polkadot/types/types';
 
 describe('Fungible: Information getting', () => {
-  itWeb3('totalSupply', async ({api, web3, privateKeyWrapper}) => {
-    const collection = await createCollectionExpectSuccess({
-      name: 'token name',
-      mode: {type: 'Fungible', decimalPoints: 0},
+  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 caller = await createEthAccountWithBalance(api, web3, privateKeyWrapper);
+  itEth('totalSupply', async ({helper}) => {
+    const caller = await helper.eth.createAccountWithBalance(donor);
+    const collection = await helper.ft.mintCollection(alice);
+    await collection.mint(alice, 200n);
 
-    await createFungibleItemExpectSuccess(alice, collection, {Value: 200n}, {Substrate: alice.address});
-
-    const address = collectionIdToAddress(collection);
-    const contract = new web3.eth.Contract(fungibleAbi as any, address, {from: caller, ...GAS_ARGS});
+    const contract = helper.ethNativeContract.collectionById(collection.collectionId, 'ft', caller);
     const totalSupply = await contract.methods.totalSupply().call();
-
     expect(totalSupply).to.equal('200');
   });
 
-  itWeb3('balanceOf', async ({api, web3, privateKeyWrapper}) => {
-    const collection = await createCollectionExpectSuccess({
-      name: 'token name',
-      mode: {type: 'Fungible', decimalPoints: 0},
-    });
-    const alice = privateKeyWrapper('//Alice');
+  itEth('balanceOf', async ({helper}) => {
+    const caller = await helper.eth.createAccountWithBalance(donor);
+    const collection = await helper.ft.mintCollection(alice);
+    await collection.mint(alice, 200n, {Ethereum: caller});
 
-    const caller = await createEthAccountWithBalance(api, web3, privateKeyWrapper);
-
-    await createFungibleItemExpectSuccess(alice, collection, {Value: 200n}, {Ethereum: caller});
-
-    const address = collectionIdToAddress(collection);
-    const contract = new web3.eth.Contract(fungibleAbi as any, address, {from: caller, ...GAS_ARGS});
+    const contract = helper.ethNativeContract.collectionById(collection.collectionId, 'ft', caller);
     const balance = await contract.methods.balanceOf(caller).call();
-
     expect(balance).to.equal('200');
   });
 });
 
 describe('Fungible: Plain calls', () => {
-  itWeb3('Can perform mint()', async ({web3, api, privateKeyWrapper}) => {
-    const alice = privateKeyWrapper('//Alice');
-    const collection = await createCollection(api, alice, {
-      name: 'token name',
-      mode: {type: 'Fungible', decimalPoints: 0},
+  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 receiver = createEthAccount(web3);
+  itEth('Can perform mint()', async ({helper}) => {
+    const owner = await helper.eth.createAccountWithBalance(donor);
+    const receiver = helper.eth.createAccount();
+    const collection = await helper.ft.mintCollection(alice);
+    await collection.addAdmin(alice, {Ethereum: owner});
 
-    const collectionIdAddress = collectionIdToAddress(collection.collectionId);
-    const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);
-    const changeAdminTx = api.tx.unique.addCollectionAdmin(collection.collectionId, {Ethereum: owner});
-    await submitTransactionAsync(alice, changeAdminTx);
+    const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId);
+    const contract = helper.ethNativeContract.collection(collectionAddress, 'ft', owner);
 
-    const collectionContract = evmCollection(web3, owner, collectionIdAddress, {type: 'Fungible', decimalPoints: 0});
-    const result = await collectionContract.methods.mint(receiver, 100).send();
-    const events = normalizeEvents(result.events);
+    const result = await contract.methods.mint(receiver, 100).send();
     
-    expect(events).to.be.deep.equal([
-      {
-        address: collectionIdAddress,
-        event: 'Transfer',
-        args: {
-          from: '0x0000000000000000000000000000000000000000',
-          to: receiver,
-          value: '100',
-        },
-      },
-    ]);
+    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.value).to.equal('100');
   });
-
-  itWeb3('Can perform mintBulk()', async ({web3, api, privateKeyWrapper}) => {
-    const alice = privateKeyWrapper('//Alice');
-    const collection = await createCollection(api, alice, {
-      name: 'token name',
-      mode: {type: 'Fungible', decimalPoints: 0},
-    });
 
-    const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);
-    const receiver1 = createEthAccount(web3);
-    const receiver2 = createEthAccount(web3);
-    const receiver3 = createEthAccount(web3);
-
-    const collectionIdAddress = collectionIdToAddress(collection.collectionId);
-    const changeAdminTx = api.tx.unique.addCollectionAdmin(collection.collectionId, {Ethereum: owner});
-    await submitTransactionAsync(alice, changeAdminTx);
+  itEth('Can perform mintBulk()', async ({helper}) => {
+    const owner = await helper.eth.createAccountWithBalance(donor);
+    const bulkSize = 3;
+    const receivers = [...new Array(bulkSize)].map(() => helper.eth.createAccount());
+    const collection = await helper.ft.mintCollection(alice);
+    await collection.addAdmin(alice, {Ethereum: owner});
 
-    const collectionContract = evmCollection(web3, owner, collectionIdAddress, {type: 'Fungible', decimalPoints: 0});
-    const result = await collectionContract.methods.mintBulk([
-      [receiver1, 10],
-      [receiver2, 20],
-      [receiver3, 30],
-    ]).send();
-    const events = normalizeEvents(result.events);
+    const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId);
+    const contract = helper.ethNativeContract.collection(collectionAddress, 'ft', owner);
 
-    expect(events).to.be.deep.contain({
-      address:collectionIdAddress,
-      event: 'Transfer',
-      args: {
-        from: '0x0000000000000000000000000000000000000000',
-        to: receiver1,
-        value: '10',
-      },
-    });
-    
-    expect(events).to.be.deep.contain({
-      address:collectionIdAddress,
-      event: 'Transfer',
-      args: {
-        from: '0x0000000000000000000000000000000000000000',
-        to: receiver2,
-        value: '20',
-      },
-    });
-    
-    expect(events).to.be.deep.contain({
-      address:collectionIdAddress,
-      event: 'Transfer',
-      args: {
-        from: '0x0000000000000000000000000000000000000000',
-        to: receiver3,
-        value: '30',
-      },
-    });
+    const result = await contract.methods.mintBulk(Array.from({length: bulkSize}, (_, i) => (
+      [receivers[i], (i + 1) * 10]
+    ))).send();
+    const events = result.events.Transfer.sort((a: any, b: any) => +a.returnValues.value - b.returnValues.value);
+    for (let i = 0; i < bulkSize; i++) {
+      const event = events[i];
+      expect(event.address).to.equal(collectionAddress);
+      expect(event.returnValues.from).to.equal('0x0000000000000000000000000000000000000000');
+      expect(event.returnValues.to).to.equal(receivers[i]);
+      expect(event.returnValues.value).to.equal(String(10 * (i + 1)));
+    }
   });
 
-  itWeb3('Can perform burn()', async ({web3, api, privateKeyWrapper}) => {
-    const alice = privateKeyWrapper('//Alice');
-    const collection = await createCollection(api, alice, {
-      name: 'token name',
-      mode: {type: 'Fungible', decimalPoints: 0},
-    });
-
-    const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);
-    const changeAdminTx = api.tx.unique.addCollectionAdmin(collection.collectionId, {Ethereum: owner});
-    await submitTransactionAsync(alice, changeAdminTx);
-    const receiver = await createEthAccountWithBalance(api, web3, privateKeyWrapper);
+  itEth('Can perform burn()', async ({helper}) => {
+    const owner = await helper.eth.createAccountWithBalance(donor);
+    const receiver = await helper.eth.createAccountWithBalance(donor);
+    const collection = await helper.ft.mintCollection(alice);
+    await collection.addAdmin(alice, {Ethereum: owner});
 
-    const collectionIdAddress = collectionIdToAddress(collection.collectionId);
-    const collectionContract = evmCollection(web3, owner, collectionIdAddress, {type: 'Fungible', decimalPoints: 0});
-    await collectionContract.methods.mint(receiver, 100).send();
+    const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId);
+    const contract = helper.ethNativeContract.collection(collectionAddress, 'ft', owner);
+    await contract.methods.mint(receiver, 100).send();
 
-    const result = await collectionContract.methods.burnFrom(receiver, 49).send({from: receiver});
+    const result = await contract.methods.burnFrom(receiver, 49).send({from: receiver});
     
-    const events = normalizeEvents(result.events);
-
-    expect(events).to.be.deep.equal([
-      {
-        address: collectionIdAddress,
-        event: 'Transfer',
-        args: {
-          from: receiver,
-          to: '0x0000000000000000000000000000000000000000',
-          value: '49',
-        },
-      },
-    ]);
+    const event = result.events.Transfer;
+    expect(event.address).to.equal(collectionAddress);
+    expect(event.returnValues.from).to.equal(receiver);
+    expect(event.returnValues.to).to.equal('0x0000000000000000000000000000000000000000');
+    expect(event.returnValues.value).to.equal('49');
 
-    const balance = await collectionContract.methods.balanceOf(receiver).call();
+    const balance = await contract.methods.balanceOf(receiver).call();
     expect(balance).to.equal('51');
   });
 
-  itWeb3('Can perform approve()', async ({web3, api, privateKeyWrapper}) => {
-    const collection = await createCollectionExpectSuccess({
-      name: 'token name',
-      mode: {type: 'Fungible', decimalPoints: 0},
-    });
-    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.ft.mintCollection(alice);
+    await collection.mint(alice, 200n, {Ethereum: owner});
 
-    const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);
-
-    await createFungibleItemExpectSuccess(alice, collection, {Value: 200n}, {Ethereum: owner});
-
-    const spender = createEthAccount(web3);
+    const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId);
+    const contract = helper.ethNativeContract.collection(collectionAddress, 'ft', owner);
 
-    const address = collectionIdToAddress(collection);
-    const contract = new web3.eth.Contract(fungibleAbi as any, address, {from: owner, ...GAS_ARGS});
-
     {
       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(collectionAddress);
+      expect(event.returnValues.owner).to.be.equal(owner);
+      expect(event.returnValues.spender).to.be.equal(spender);
+      expect(event.returnValues.value).to.be.equal('100');
     }
 
     {
@@ -220,51 +148,32 @@
     }
   });
 
-  itWeb3('Can perform transferFrom()', async ({web3, api, privateKeyWrapper}) => {
-    const collection = await createCollectionExpectSuccess({
-      name: 'token name',
-      mode: {type: 'Fungible', decimalPoints: 0},
-    });
-    const alice = privateKeyWrapper('//Alice');
-
-    const owner = createEthAccount(web3);
-    await transferBalanceToEth(api, alice, owner);
-
-    await createFungibleItemExpectSuccess(alice, collection, {Value: 200n}, {Ethereum: owner});
-
-    const spender = createEthAccount(web3);
-    await transferBalanceToEth(api, alice, spender);
-
-    const receiver = createEthAccount(web3);
+  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.ft.mintCollection(alice);
+    await collection.mint(alice, 200n, {Ethereum: owner});
 
-    const address = collectionIdToAddress(collection);
-    const contract = new web3.eth.Contract(fungibleAbi as any, address, {from: owner, ...GAS_ARGS});
+    const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId);
+    const contract = helper.ethNativeContract.collection(collectionAddress, 'ft', 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.be.deep.equal([
-        {
-          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(collectionAddress);
+      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(collectionAddress);
+      expect(event.returnValues.owner).to.be.equal(owner);
+      expect(event.returnValues.spender).to.be.equal(spender);
+      expect(event.returnValues.value).to.be.equal('51');
     }
 
     {
@@ -278,38 +187,23 @@
     }
   });
 
-  itWeb3('Can perform transfer()', async ({web3, api, privateKeyWrapper}) => {
-    const collection = await createCollectionExpectSuccess({
-      name: 'token name',
-      mode: {type: 'Fungible', decimalPoints: 0},
-    });
-    const alice = privateKeyWrapper('//Alice');
-
-    const owner = createEthAccount(web3);
-    await transferBalanceToEth(api, alice, owner);
-
-    await createFungibleItemExpectSuccess(alice, collection, {Value: 200n}, {Ethereum: owner});
-
-    const receiver = createEthAccount(web3);
-    await transferBalanceToEth(api, alice, receiver);
+  itEth('Can perform transfer()', async ({helper}) => {
+    const owner = await helper.eth.createAccountWithBalance(donor);
+    const receiver = await helper.eth.createAccountWithBalance(donor);
+    const collection = await helper.ft.mintCollection(alice);
+    await collection.mint(alice, 200n, {Ethereum: owner});
 
-    const address = collectionIdToAddress(collection);
-    const contract = new web3.eth.Contract(fungibleAbi as any, address, {from: owner, ...GAS_ARGS});
+    const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId);
+    const contract = helper.ethNativeContract.collection(collectionAddress, 'ft', owner);
 
     {
       const result = await contract.methods.transfer(receiver, 50).send({from: owner});
-      const events = normalizeEvents(result.events);
-      expect(events).to.be.deep.equal([
-        {
-          address,
-          event: 'Transfer',
-          args: {
-            from: owner,
-            to: receiver,
-            value: '50',
-          },
-        },
-      ]);
+      
+      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.value).to.be.equal('50');
     }
 
     {
@@ -325,162 +219,141 @@
 });
 
 describe('Fungible: Fees', () => {
-  itWeb3('approve() call fee is less than 0.2UNQ', async ({web3, api, privateKeyWrapper}) => {
-    const collection = await createCollectionExpectSuccess({
-      mode: {type: 'Fungible', decimalPoints: 0},
+  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');
+  });
+  
+  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.ft.mintCollection(alice);
+    await collection.mint(alice, 200n, {Ethereum: owner});
 
-    const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);
-    const spender = createEthAccount(web3);
-
-    await createFungibleItemExpectSuccess(alice, collection, {Value: 200n}, {Ethereum: owner});
+    const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId);
+    const contract = helper.ethNativeContract.collection(collectionAddress, 'ft', owner);
 
-    const address = collectionIdToAddress(collection);
-    const contract = new web3.eth.Contract(fungibleAbi as any, address, {from: owner, ...GAS_ARGS});
-
-    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 collection = await createCollectionExpectSuccess({
-      mode: {type: 'Fungible', decimalPoints: 0},
-    });
-    const alice = privateKeyWrapper('//Alice');
-
-    const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);
-    const spender = await createEthAccountWithBalance(api, web3, privateKeyWrapper);
-
-    await createFungibleItemExpectSuccess(alice, collection, {Value: 200n}, {Ethereum: owner});
+  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.ft.mintCollection(alice);
+    await collection.mint(alice, 200n, {Ethereum: owner});
 
-    const address = collectionIdToAddress(collection);
-    const contract = new web3.eth.Contract(fungibleAbi as any, address, {from: owner, ...GAS_ARGS});
+    const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId);
+    const contract = helper.ethNativeContract.collection(collectionAddress, 'ft', 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 collection = await createCollectionExpectSuccess({
-      mode: {type: 'Fungible', decimalPoints: 0},
-    });
-    const alice = privateKeyWrapper('//Alice');
 
-    const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);
-    const receiver = createEthAccount(web3);
-
-    await createFungibleItemExpectSuccess(alice, collection, {Value: 200n}, {Ethereum: owner});
+  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.ft.mintCollection(alice);
+    await collection.mint(alice, 200n, {Ethereum: owner});
 
-    const address = collectionIdToAddress(collection);
-    const contract = new web3.eth.Contract(fungibleAbi as any, address, {from: owner, ...GAS_ARGS});
+    const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId);
+    const contract = helper.ethNativeContract.collection(collectionAddress, 'ft', 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('Fungible: Substrate calls', () => {
-  itWeb3('Events emitted for approve()', async ({web3, privateKeyWrapper}) => {
-    const collection = await createCollectionExpectSuccess({
-      mode: {type: 'Fungible', decimalPoints: 0},
+  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 receiver = createEthAccount(web3);
+  itEth('Events emitted for approve()', async ({helper}) => {
+    const receiver = helper.eth.createAccount();
+    const collection = await helper.ft.mintCollection(alice);
+    await collection.mint(alice, 200n);
 
-    await createFungibleItemExpectSuccess(alice, collection, {Value: 200n});
+    const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId);
+    const contract = helper.ethNativeContract.collection(collectionAddress, 'ft');
 
-    const address = collectionIdToAddress(collection);
-    const contract = new web3.eth.Contract(fungibleAbi as any, address);
-
-    const events = await recordEvents(contract, async () => {
-      await approveExpectSuccess(collection, 0, alice, {Ethereum: receiver}, 100);
+    const events: any = [];
+    contract.events.allEvents((_: any, event: any) => {
+      events.push(event);
     });
+    await collection.approveTokens(alice, {Ethereum: receiver}, 100n);
 
-    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(collectionAddress);
+    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, privateKeyWrapper}) => {
-    const collection = await createCollectionExpectSuccess({
-      mode: {type: 'Fungible', decimalPoints: 0},
-    });
-    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 collection = await helper.ft.mintCollection(alice);
+    await collection.mint(alice, 200n);
+    await collection.approveTokens(alice, {Substrate: bob.address}, 100n);
 
-    const receiver = createEthAccount(web3);
+    const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId);
+    const contract = helper.ethNativeContract.collection(collectionAddress, 'ft');
 
-    await createFungibleItemExpectSuccess(alice, collection, {Value: 200n});
-    await approveExpectSuccess(collection, 0, alice, bob.address, 100);
+    const events: any = [];
+    contract.events.allEvents((_: any, event: any) => {
+      events.push(event);
+    });
+    await collection.transferFrom(bob, {Substrate: alice.address}, {Ethereum: receiver}, 51n);
 
-    const address = collectionIdToAddress(collection);
-    const contract = new web3.eth.Contract(fungibleAbi as any, address);
+    let 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(receiver);
+    expect(event.returnValues.value).to.be.equal('51');
 
-    const events = await recordEvents(contract, async () => {
-      await transferFromExpectSuccess(collection, 0, bob, alice, {Ethereum: receiver}, 51, 'Fungible');
-    });
-
-    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(collectionAddress);
+    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, privateKeyWrapper}) => {
-    const collection = await createCollectionExpectSuccess({
-      mode: {type: 'Fungible', decimalPoints: 0},
-    });
-    const alice = privateKeyWrapper('//Alice');
+  itEth('Events emitted for transfer()', async ({helper}) => {
+    const receiver = helper.eth.createAccount();
+    const collection = await helper.ft.mintCollection(alice);
+    await collection.mint(alice, 200n);
 
-    const receiver = createEthAccount(web3);
+    const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId);
+    const contract = helper.ethNativeContract.collection(collectionAddress, 'ft');
 
-    await createFungibleItemExpectSuccess(alice, collection, {Value: 200n});
-
-    const address = collectionIdToAddress(collection);
-    const contract = new web3.eth.Contract(fungibleAbi as any, address);
-
-    const events = await recordEvents(contract, async () => {
-      await transferExpectSuccess(collection, 0, alice, {Ethereum:receiver}, 51, 'Fungible');
+    const events: any = [];
+    contract.events.allEvents((_: any, event: any) => {
+      events.push(event);
     });
+    await collection.transfer(alice, {Ethereum:receiver}, 51n);
 
-    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(collectionAddress);
+    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');
   });
 });
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
before · tests/src/eth/reFungibleToken.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 {approve, createCollection, createRefungibleToken, transfer, transferFrom, UNIQUE, requirePallets, Pallets} from '../util/helpers';18import {collectionIdToAddress, createEthAccount, createEthAccountWithBalance, createRFTCollection, evmCollection, evmCollectionHelpers, getCollectionAddressFromResult, itWeb3, normalizeEvents, recordEthFee, recordEvents, subToEth, tokenIdToAddress, transferBalanceToEth, uniqueRefungible, uniqueRefungibleToken} from './util/helpers';1920import chai from 'chai';21import chaiAsPromised from 'chai-as-promised';22chai.use(chaiAsPromised);23const expect = chai.expect;2425describe('Refungible token: Information getting', () => {26  before(async function() {27    await requirePallets(this, [Pallets.ReFungible]);28  });2930  itWeb3('totalSupply', async ({api, web3, privateKeyWrapper}) => {31    const alice = privateKeyWrapper('//Alice');3233    const collectionId = (await createCollection(api, alice, {name: 'token name', mode: {type: 'ReFungible'}})).collectionId;3435    const caller = await createEthAccountWithBalance(api, web3, privateKeyWrapper);3637    const tokenId = (await createRefungibleToken(api, alice, collectionId, 200n, {Ethereum: caller})).itemId;3839    const address = tokenIdToAddress(collectionId, tokenId);40    const contract = uniqueRefungibleToken(web3, address, caller);41    const totalSupply = await contract.methods.totalSupply().call();4243    expect(totalSupply).to.equal('200');44  });4546  itWeb3('balanceOf', async ({api, web3, privateKeyWrapper}) => {47    const alice = privateKeyWrapper('//Alice');4849    const collectionId = (await createCollection(api, alice, {name: 'token name', mode: {type: 'ReFungible'}})).collectionId;5051    const caller = await createEthAccountWithBalance(api, web3, privateKeyWrapper);5253    const tokenId = (await createRefungibleToken(api, alice, collectionId, 200n, {Ethereum: caller})).itemId;5455    const address = tokenIdToAddress(collectionId, tokenId);56    const contract = uniqueRefungibleToken(web3, address, caller);57    const balance = await contract.methods.balanceOf(caller).call();5859    expect(balance).to.equal('200');60  });6162  itWeb3('decimals', async ({api, web3, privateKeyWrapper}) => {63    const alice = privateKeyWrapper('//Alice');6465    const collectionId = (await createCollection(api, alice, {name: 'token name', mode: {type: 'ReFungible'}})).collectionId;6667    const caller = await createEthAccountWithBalance(api, web3, privateKeyWrapper);6869    const tokenId = (await createRefungibleToken(api, alice, collectionId, 200n, {Ethereum: caller})).itemId;7071    const address = tokenIdToAddress(collectionId, tokenId);72    const contract = uniqueRefungibleToken(web3, address, caller);73    const decimals = await contract.methods.decimals().call();7475    expect(decimals).to.equal('0');76  });77});7879// FIXME: Need erc721 for ReFubgible.80describe('Check ERC721 token URI for ReFungible', () => {81  before(async function() {82    await requirePallets(this, [Pallets.ReFungible]);83  });8485  itWeb3('Empty tokenURI', async ({web3, api, privateKeyWrapper}) => {86    const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);87    const helper = evmCollectionHelpers(web3, owner);88    let result = await helper.methods.createERC721MetadataCompatibleCollection('Mint collection', '1', '1', '').send();89    const {collectionIdAddress, collectionId} = await getCollectionAddressFromResult(api, result);90    const receiver = createEthAccount(web3);91    const contract = evmCollection(web3, owner, collectionIdAddress, {type: 'ReFungible'});9293    const nextTokenId = await contract.methods.nextTokenId().call();94    expect(nextTokenId).to.be.equal('1');95    result = await contract.methods.mint(96      receiver,97      nextTokenId,98    ).send();99100    const events = normalizeEvents(result.events);101    const address = collectionIdToAddress(collectionId);102103    expect(events).to.be.deep.equal([104      {105        address,106        event: 'Transfer',107        args: {108          from: '0x0000000000000000000000000000000000000000',109          to: receiver,110          tokenId: nextTokenId,111        },112      },113    ]);114115    expect(await contract.methods.tokenURI(nextTokenId).call()).to.be.equal('');116  });117118  itWeb3('TokenURI from url', async ({web3, api, privateKeyWrapper}) => {119    const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);120    const helper = evmCollectionHelpers(web3, owner);121    let result = await helper.methods.createERC721MetadataCompatibleCollection('Mint collection', '1', '1', 'BaseURI_').send();122    const {collectionIdAddress, collectionId} = await getCollectionAddressFromResult(api, result);123    const receiver = createEthAccount(web3);124    const contract = evmCollection(web3, owner, collectionIdAddress, {type: 'ReFungible'});125126    const nextTokenId = await contract.methods.nextTokenId().call();127    expect(nextTokenId).to.be.equal('1');128    result = await contract.methods.mint(129      receiver,130      nextTokenId,131    ).send();132133    // Set URL134    await contract.methods.setProperty(nextTokenId, 'url', Buffer.from('Token URI')).send();135136    const events = normalizeEvents(result.events);137    const address = collectionIdToAddress(collectionId);138139    expect(events).to.be.deep.equal([140      {141        address,142        event: 'Transfer',143        args: {144          from: '0x0000000000000000000000000000000000000000',145          to: receiver,146          tokenId: nextTokenId,147        },148      },149    ]);150151    expect(await contract.methods.tokenURI(nextTokenId).call()).to.be.equal('Token URI');152  });153154  itWeb3('TokenURI from baseURI + tokenId', async ({web3, api, privateKeyWrapper}) => {155    const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);156    const helper = evmCollectionHelpers(web3, owner);157    let result = await helper.methods.createERC721MetadataCompatibleCollection('Mint collection', '1', '1', 'BaseURI_').send();158    const {collectionIdAddress, collectionId} = await getCollectionAddressFromResult(api, result);159    const receiver = createEthAccount(web3);160    const contract = evmCollection(web3, owner, collectionIdAddress, {type: 'ReFungible'});161162    const nextTokenId = await contract.methods.nextTokenId().call();163    expect(nextTokenId).to.be.equal('1');164    result = await contract.methods.mint(165      receiver,166      nextTokenId,167    ).send();168169    const events = normalizeEvents(result.events);170    const address = collectionIdToAddress(collectionId);171172    expect(events).to.be.deep.equal([173      {174        address,175        event: 'Transfer',176        args: {177          from: '0x0000000000000000000000000000000000000000',178          to: receiver,179          tokenId: nextTokenId,180        },181      },182    ]);183184    expect(await contract.methods.tokenURI(nextTokenId).call()).to.be.equal('BaseURI_' + nextTokenId);185  });186187  itWeb3('TokenURI from baseURI + suffix', async ({web3, api, privateKeyWrapper}) => {188    const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);189    const helper = evmCollectionHelpers(web3, owner);190    let result = await helper.methods.createERC721MetadataCompatibleCollection('Mint collection', '1', '1', 'BaseURI_').send();191    const {collectionIdAddress, collectionId} = await getCollectionAddressFromResult(api, result);192    const receiver = createEthAccount(web3);193    const contract = evmCollection(web3, owner, collectionIdAddress, {type: 'ReFungible'});194195    const nextTokenId = await contract.methods.nextTokenId().call();196    expect(nextTokenId).to.be.equal('1');197    result = await contract.methods.mint(198      receiver,199      nextTokenId,200    ).send();201202    // Set suffix203    const suffix = '/some/suffix';204    await contract.methods.setProperty(nextTokenId, 'suffix', Buffer.from(suffix)).send();205206    const events = normalizeEvents(result.events);207    const address = collectionIdToAddress(collectionId);208209    expect(events).to.be.deep.equal([210      {211        address,212        event: 'Transfer',213        args: {214          from: '0x0000000000000000000000000000000000000000',215          to: receiver,216          tokenId: nextTokenId,217        },218      },219    ]);220221    expect(await contract.methods.tokenURI(nextTokenId).call()).to.be.equal('BaseURI_' + suffix);222  });223});224225describe('Refungible: Plain calls', () => {226  before(async function() {227    await requirePallets(this, [Pallets.ReFungible]);228  });229230  itWeb3('Can perform approve()', async ({web3, api, privateKeyWrapper}) => {231    const alice = privateKeyWrapper('//Alice');232233    const collectionId = (await createCollection(api, alice, {name: 'token name', mode: {type: 'ReFungible'}})).collectionId;234235    const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);236237    const tokenId = (await createRefungibleToken(api, alice, collectionId, 200n, {Ethereum: owner})).itemId;238239    const address = tokenIdToAddress(collectionId, tokenId);240241    const spender = createEthAccount(web3);242243    const contract = uniqueRefungibleToken(web3, address, owner);244245    {246      const result = await contract.methods.approve(spender, 100).send({from: owner});247      const events = normalizeEvents(result.events);248249      expect(events).to.be.deep.equal([250        {251          address,252          event: 'Approval',253          args: {254            owner,255            spender,256            value: '100',257          },258        },259      ]);260    }261262    {263      const allowance = await contract.methods.allowance(owner, spender).call();264      expect(+allowance).to.equal(100);265    }266  });267268  itWeb3('Can perform transferFrom()', async ({web3, api, privateKeyWrapper}) => {269    const alice = privateKeyWrapper('//Alice');270271    const collectionId = (await createCollection(api, alice, {name: 'token name', mode: {type: 'ReFungible'}})).collectionId;272273    const owner = createEthAccount(web3);274    await transferBalanceToEth(api, alice, owner);275276    const tokenId = (await createRefungibleToken(api, alice, collectionId, 200n, {Ethereum: owner})).itemId;277278    const spender = createEthAccount(web3);279    await transferBalanceToEth(api, alice, spender);280281    const receiver = createEthAccount(web3);282283    const address = tokenIdToAddress(collectionId, tokenId);284    const contract = uniqueRefungibleToken(web3, address, owner);285286    await contract.methods.approve(spender, 100).send();287288    {289      const result = await contract.methods.transferFrom(owner, receiver, 49).send({from: spender});290      const events = normalizeEvents(result.events);291      expect(events).to.include.deep.members([292        {293          address,294          event: 'Transfer',295          args: {296            from: owner,297            to: receiver,298            value: '49',299          },300        },301        {302          address,303          event: 'Approval',304          args: {305            owner,306            spender,307            value: '51',308          },309        },310      ]);311    }312313    {314      const balance = await contract.methods.balanceOf(receiver).call();315      expect(+balance).to.equal(49);316    }317318    {319      const balance = await contract.methods.balanceOf(owner).call();320      expect(+balance).to.equal(151);321    }322  });323324  itWeb3('Can perform transfer()', async ({web3, api, privateKeyWrapper}) => {325    const alice = privateKeyWrapper('//Alice');326327    const collectionId = (await createCollection(api, alice, {name: 'token name', mode: {type: 'ReFungible'}})).collectionId;328329    const owner = createEthAccount(web3);330    await transferBalanceToEth(api, alice, owner);331332    const tokenId = (await createRefungibleToken(api, alice, collectionId, 200n, {Ethereum: owner})).itemId;333334    const receiver = createEthAccount(web3);335    await transferBalanceToEth(api, alice, receiver);336337    const address = tokenIdToAddress(collectionId, tokenId);338    const contract = uniqueRefungibleToken(web3, address, owner);339340    {341      const result = await contract.methods.transfer(receiver, 50).send({from: owner});342      const events = normalizeEvents(result.events);343      expect(events).to.include.deep.members([344        {345          address,346          event: 'Transfer',347          args: {348            from: owner,349            to: receiver,350            value: '50',351          },352        },353      ]);354    }355356    {357      const balance = await contract.methods.balanceOf(owner).call();358      expect(+balance).to.equal(150);359    }360361    {362      const balance = await contract.methods.balanceOf(receiver).call();363      expect(+balance).to.equal(50);364    }365  });366367  itWeb3('Can perform repartition()', async ({web3, api, privateKeyWrapper}) => {368    const alice = privateKeyWrapper('//Alice');369370    const collectionId = (await createCollection(api, alice, {name: 'token name', mode: {type: 'ReFungible'}})).collectionId;371372    const owner = createEthAccount(web3);373    await transferBalanceToEth(api, alice, owner);374375    const receiver = createEthAccount(web3);376    await transferBalanceToEth(api, alice, receiver);377378    const tokenId = (await createRefungibleToken(api, alice, collectionId, 100n, {Ethereum: owner})).itemId;379380    const address = tokenIdToAddress(collectionId, tokenId);381    const contract = uniqueRefungibleToken(web3, address, owner);382383    await contract.methods.repartition(200).send({from: owner});384    expect(+await contract.methods.balanceOf(owner).call()).to.be.equal(200);385    await contract.methods.transfer(receiver, 110).send({from: owner});386    expect(+await contract.methods.balanceOf(owner).call()).to.be.equal(90);387    expect(+await contract.methods.balanceOf(receiver).call()).to.be.equal(110);388389    await expect(contract.methods.repartition(80).send({from: owner})).to.eventually.be.rejected;390391    await contract.methods.transfer(receiver, 90).send({from: owner});392    expect(+await contract.methods.balanceOf(owner).call()).to.be.equal(0);393    expect(+await contract.methods.balanceOf(receiver).call()).to.be.equal(200);394395    await contract.methods.repartition(150).send({from: receiver});396    await expect(contract.methods.transfer(owner, 160).send({from: receiver})).to.eventually.be.rejected;397    expect(+await contract.methods.balanceOf(receiver).call()).to.be.equal(150);398  });399400  itWeb3('Can repartition with increased amount', async ({web3, api, privateKeyWrapper}) => {401    const alice = privateKeyWrapper('//Alice');402403    const collectionId = (await createCollection(api, alice, {name: 'token name', mode: {type: 'ReFungible'}})).collectionId;404405    const owner = createEthAccount(web3);406    await transferBalanceToEth(api, alice, owner);407408    const tokenId = (await createRefungibleToken(api, alice, collectionId, 100n, {Ethereum: owner})).itemId;409410    const address = tokenIdToAddress(collectionId, tokenId);411    const contract = uniqueRefungibleToken(web3, address, owner);412413    const result = await contract.methods.repartition(200).send();414    const events = normalizeEvents(result.events);415416    expect(events).to.deep.equal([417      {418        address,419        event: 'Transfer',420        args: {421          from: '0x0000000000000000000000000000000000000000',422          to: owner,423          value: '100',424        },425      },426    ]);427  });428429  itWeb3('Can repartition with decreased amount', async ({web3, api, privateKeyWrapper}) => {430    const alice = privateKeyWrapper('//Alice');431432    const collectionId = (await createCollection(api, alice, {name: 'token name', mode: {type: 'ReFungible'}})).collectionId;433434    const owner = createEthAccount(web3);435    await transferBalanceToEth(api, alice, owner);436437    const tokenId = (await createRefungibleToken(api, alice, collectionId, 100n, {Ethereum: owner})).itemId;438439    const address = tokenIdToAddress(collectionId, tokenId);440    const contract = uniqueRefungibleToken(web3, address, owner);441442    const result = await contract.methods.repartition(50).send();443    const events = normalizeEvents(result.events);444    expect(events).to.deep.equal([445      {446        address,447        event: 'Transfer',448        args: {449          from: owner,450          to: '0x0000000000000000000000000000000000000000',451          value: '50',452        },453      },454    ]);455  });456457  itWeb3('Receiving Transfer event on burning into full ownership', async ({web3, api, privateKeyWrapper}) => {458    const caller = await createEthAccountWithBalance(api, web3, privateKeyWrapper);459    const receiver = await createEthAccountWithBalance(api, web3, privateKeyWrapper);460    const helper = evmCollectionHelpers(web3, caller);461    const result = await helper.methods.createRFTCollection('Mint collection', '6', '6').send();462    const {collectionIdAddress, collectionId} = await getCollectionAddressFromResult(api, result);463    const contract = evmCollection(web3, caller, collectionIdAddress, {type: 'ReFungible'});464465    const tokenId = await contract.methods.nextTokenId().call();466    await contract.methods.mint(caller, tokenId).send();467468    const address = tokenIdToAddress(collectionId, tokenId);469470    const tokenContract =  uniqueRefungibleToken(web3, address, caller);471    await tokenContract.methods.repartition(2).send();472    await tokenContract.methods.transfer(receiver, 1).send();473474    const events =  await recordEvents(contract, async () =>475      await tokenContract.methods.burnFrom(caller, 1).send());476    expect(events).to.deep.equal([477      {478        address: collectionIdAddress,479        event: 'Transfer',480        args: {481          from: '0xFFfFfFffFFfffFFfFFfFFFFFffFFFffffFfFFFfF',482          to: receiver,483          tokenId,484        },485      },486    ]);487  });488});489490describe('Refungible: Fees', () => {491  before(async function() {492    await requirePallets(this, [Pallets.ReFungible]);493  });494495  itWeb3('approve() call fee is less than 0.2UNQ', async ({web3, api, privateKeyWrapper}) => {496    const alice = privateKeyWrapper('//Alice');497498    const collectionId = (await createCollection(api, alice, {mode: {type: 'ReFungible'}})).collectionId;499500    const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);501    const spender = createEthAccount(web3);502503    const tokenId = (await createRefungibleToken(api, alice, collectionId, 200n, {Ethereum: owner})).itemId;504505    const address = tokenIdToAddress(collectionId, tokenId);506    const contract = uniqueRefungibleToken(web3, address, owner);507508    const cost = await recordEthFee(api, owner, () => contract.methods.approve(spender, 100).send({from: owner}));509    expect(cost < BigInt(0.2 * Number(UNIQUE)));510  });511512  itWeb3('transferFrom() call fee is less than 0.2UNQ', async ({web3, api, privateKeyWrapper}) => {513    const alice = privateKeyWrapper('//Alice');514515    const collectionId = (await createCollection(api, alice, {mode: {type: 'ReFungible'}})).collectionId;516517    const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);518    const spender = await createEthAccountWithBalance(api, web3, privateKeyWrapper);519520    const tokenId = (await createRefungibleToken(api, alice, collectionId, 200n, {Ethereum: owner})).itemId;521522    const address = tokenIdToAddress(collectionId, tokenId);523    const contract = uniqueRefungibleToken(web3, address, owner);524525    await contract.methods.approve(spender, 100).send({from: owner});526527    const cost = await recordEthFee(api, spender, () => contract.methods.transferFrom(owner, spender, 100).send({from: spender}));528    expect(cost < BigInt(0.2 * Number(UNIQUE)));529  });530531  itWeb3('transfer() call fee is less than 0.2UNQ', async ({web3, api, privateKeyWrapper}) => {532    const alice = privateKeyWrapper('//Alice');533534    const collectionId = (await createCollection(api, alice, {mode: {type: 'ReFungible'}})).collectionId;535536    const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);537    const receiver = createEthAccount(web3);538539    const tokenId = (await createRefungibleToken(api, alice, collectionId, 200n, {Ethereum: owner})).itemId;540541    const address = tokenIdToAddress(collectionId, tokenId);542    const contract = uniqueRefungibleToken(web3, address, owner);543544    const cost = await recordEthFee(api, owner, () => contract.methods.transfer(receiver, 100).send({from: owner}));545    expect(cost < BigInt(0.2 * Number(UNIQUE)));546  });547});548549describe('Refungible: Substrate calls', () => {550  before(async function() {551    await requirePallets(this, [Pallets.ReFungible]);552  });553554  itWeb3('Events emitted for approve()', async ({web3, api, privateKeyWrapper}) => {555    const alice = privateKeyWrapper('//Alice');556557    const collectionId = (await createCollection(api, alice, {mode: {type: 'ReFungible'}})).collectionId;558559    const receiver = createEthAccount(web3);560561    const tokenId = (await createRefungibleToken(api, alice, collectionId, 200n)).itemId;562563    const address = tokenIdToAddress(collectionId, tokenId);564    const contract = uniqueRefungibleToken(web3, address);565566    const events = await recordEvents(contract, async () => {567      expect(await approve(api, collectionId, tokenId, alice, {Ethereum: receiver}, 100n)).to.be.true;568    });569570    expect(events).to.be.deep.equal([571      {572        address,573        event: 'Approval',574        args: {575          owner: subToEth(alice.address),576          spender: receiver,577          value: '100',578        },579      },580    ]);581  });582583  itWeb3('Events emitted for transferFrom()', async ({web3, api, privateKeyWrapper}) => {584    const alice = privateKeyWrapper('//Alice');585586    const collectionId = (await createCollection(api, alice, {mode: {type: 'ReFungible'}})).collectionId;587    const bob = privateKeyWrapper('//Bob');588589    const receiver = createEthAccount(web3);590591    const tokenId = (await createRefungibleToken(api, alice, collectionId, 200n)).itemId;592    expect(await approve(api, collectionId, tokenId, alice, bob.address, 100n)).to.be.true;593594    const address = tokenIdToAddress(collectionId, tokenId);595    const contract = uniqueRefungibleToken(web3, address);596597    const events = await recordEvents(contract, async () => {598      expect(await transferFrom(api, collectionId, tokenId, bob, alice, {Ethereum: receiver},  51n)).to.be.true;599    });600601    expect(events).to.be.deep.equal([602      {603        address,604        event: 'Transfer',605        args: {606          from: subToEth(alice.address),607          to: receiver,608          value: '51',609        },610      },611      {612        address,613        event: 'Approval',614        args: {615          owner: subToEth(alice.address),616          spender: subToEth(bob.address),617          value: '49',618        },619      },620    ]);621  });622623  itWeb3('Events emitted for transfer()', async ({web3, api, privateKeyWrapper}) => {624    const alice = privateKeyWrapper('//Alice');625626    const collectionId = (await createCollection(api, alice, {mode: {type: 'ReFungible'}})).collectionId;627628    const receiver = createEthAccount(web3);629630    const tokenId = (await createRefungibleToken(api, alice, collectionId, 200n)).itemId;631632    const address = tokenIdToAddress(collectionId, tokenId);633    const contract = uniqueRefungibleToken(web3, address);634635    const events = await recordEvents(contract, async () => {636      expect(await transfer(api, collectionId, tokenId, alice, {Ethereum: receiver},  51n)).to.be.true;637    });638639    expect(events).to.be.deep.equal([640      {641        address,642        event: 'Transfer',643        args: {644          from: subToEth(alice.address),645          to: receiver,646          value: '51',647        },648      },649    ]);650  });651});652653describe('ERC 1633 implementation', () => {654  before(async function() {655    await requirePallets(this, [Pallets.ReFungible]);656  });657658  itWeb3('Default parent token address and id', async ({api, web3, privateKeyWrapper}) => {659    const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);660661    const {collectionIdAddress, collectionId} = await createRFTCollection(api, web3, owner);662    const refungibleContract = uniqueRefungible(web3, collectionIdAddress, owner);663    const refungibleTokenId = await refungibleContract.methods.nextTokenId().call();664    await refungibleContract.methods.mint(owner, refungibleTokenId).send();665666    const rftTokenAddress = tokenIdToAddress(collectionId, refungibleTokenId);667    const refungibleTokenContract = uniqueRefungibleToken(web3, rftTokenAddress, owner);668669    const tokenAddress = await refungibleTokenContract.methods.parentToken().call();670    const tokenId = await refungibleTokenContract.methods.parentTokenId().call();671    expect(tokenAddress).to.be.equal(collectionIdAddress);672    expect(tokenId).to.be.equal(refungibleTokenId);673  });674});
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 {