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

difftreelog

Merge pull request #612 from UniqueNetwork/tests/eth-tokens

ut-akuznetsov2022-09-30parents: #a667655 #ed1eea8.patch.diff
in: master
Tests (Eth): NFT, RFT & FT tests refactored for Playgrounds

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
14// You should have received a copy of the GNU General Public License14// You should have received a copy of the GNU General Public License
15// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.15// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
1616
17import {approveExpectSuccess, createCollection, createCollectionExpectSuccess, createFungibleItemExpectSuccess, transferExpectSuccess, transferFromExpectSuccess, UNIQUE} from '../util/helpers';17import {expect, itEth, usingEthPlaygrounds} from './util/playgrounds';
18import {collectionIdToAddress, createEthAccount, createEthAccountWithBalance, evmCollection, GAS_ARGS, itWeb3, normalizeEvents, recordEthFee, recordEvents, subToEth, transferBalanceToEth} from './util/helpers';18import {IKeyringPair} from '@polkadot/types/types';
19import fungibleAbi from './fungibleAbi.json';
20import {expect} from 'chai';
21import {submitTransactionAsync} from '../substrate/substrate-api';
2219
23describe('Fungible: Information getting', () => {20describe('Fungible: Information getting', () => {
24 itWeb3('totalSupply', async ({api, web3, privateKeyWrapper}) => {21 let donor: IKeyringPair;
22 let alice: IKeyringPair;
23
25 const collection = await createCollectionExpectSuccess({24 before(async function() {
25 await usingEthPlaygrounds(async (helper, privateKey) => {
26 name: 'token name',26 donor = privateKey('//Alice');
27 mode: {type: 'Fungible', decimalPoints: 0},27 [alice] = await helper.arrange.createAccounts([20n], donor);
28 });28 });
29 const alice = privateKeyWrapper('//Alice');29 });
3030
31 const caller = await createEthAccountWithBalance(api, web3, privateKeyWrapper);31 itEth('totalSupply', async ({helper}) => {
32 const caller = await helper.eth.createAccountWithBalance(donor);
33 const collection = await helper.ft.mintCollection(alice);
34 await collection.mint(alice, 200n);
3235
33 await createFungibleItemExpectSuccess(alice, collection, {Value: 200n}, {Substrate: alice.address});36 const contract = helper.ethNativeContract.collectionById(collection.collectionId, 'ft', caller);
34
35 const address = collectionIdToAddress(collection);
36 const contract = new web3.eth.Contract(fungibleAbi as any, address, {from: caller, ...GAS_ARGS});
37 const totalSupply = await contract.methods.totalSupply().call();37 const totalSupply = await contract.methods.totalSupply().call();
38
39 expect(totalSupply).to.equal('200');38 expect(totalSupply).to.equal('200');
40 });39 });
4140
42 itWeb3('balanceOf', async ({api, web3, privateKeyWrapper}) => {41 itEth('balanceOf', async ({helper}) => {
43 const collection = await createCollectionExpectSuccess({42 const caller = await helper.eth.createAccountWithBalance(donor);
44 name: 'token name',43 const collection = await helper.ft.mintCollection(alice);
45 mode: {type: 'Fungible', decimalPoints: 0},44 await collection.mint(alice, 200n, {Ethereum: caller});
46 });
47 const alice = privateKeyWrapper('//Alice');
4845
49 const caller = await createEthAccountWithBalance(api, web3, privateKeyWrapper);46 const contract = helper.ethNativeContract.collectionById(collection.collectionId, 'ft', caller);
50
51 await createFungibleItemExpectSuccess(alice, collection, {Value: 200n}, {Ethereum: caller});
52
53 const address = collectionIdToAddress(collection);
54 const contract = new web3.eth.Contract(fungibleAbi as any, address, {from: caller, ...GAS_ARGS});
55 const balance = await contract.methods.balanceOf(caller).call();47 const balance = await contract.methods.balanceOf(caller).call();
56
57 expect(balance).to.equal('200');48 expect(balance).to.equal('200');
58 });49 });
59});50});
6051
61describe('Fungible: Plain calls', () => {52describe('Fungible: Plain calls', () => {
62 itWeb3('Can perform mint()', async ({web3, api, privateKeyWrapper}) => {53 let donor: IKeyringPair;
54 let alice: IKeyringPair;
55
56 before(async function() {
57 await usingEthPlaygrounds(async (helper, privateKey) => {
63 const alice = privateKeyWrapper('//Alice');58 donor = privateKey('//Alice');
64 const collection = await createCollection(api, alice, {59 [alice] = await helper.arrange.createAccounts([20n], donor);
65 name: 'token name',
66 mode: {type: 'Fungible', decimalPoints: 0},
67 });60 });
61 });
6862
69 const receiver = createEthAccount(web3);63 itEth('Can perform mint()', async ({helper}) => {
64 const owner = await helper.eth.createAccountWithBalance(donor);
65 const receiver = helper.eth.createAccount();
66 const collection = await helper.ft.mintCollection(alice);
67 await collection.addAdmin(alice, {Ethereum: owner});
7068
71 const collectionIdAddress = collectionIdToAddress(collection.collectionId);69 const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId);
72 const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);70 const contract = helper.ethNativeContract.collection(collectionAddress, 'ft', owner);
73 const changeAdminTx = api.tx.unique.addCollectionAdmin(collection.collectionId, {Ethereum: owner});
74 await submitTransactionAsync(alice, changeAdminTx);
7571
76 const collectionContract = evmCollection(web3, owner, collectionIdAddress, {type: 'Fungible', decimalPoints: 0});72 const result = await contract.methods.mint(receiver, 100).send();
77 const result = await collectionContract.methods.mint(receiver, 100).send();
78 const events = normalizeEvents(result.events);
79 73
80 expect(events).to.be.deep.equal([74 const event = result.events.Transfer;
81 {
82 address: collectionIdAddress,75 expect(event.address).to.equal(collectionAddress);
83 event: 'Transfer',76 expect(event.returnValues.from).to.equal('0x0000000000000000000000000000000000000000');
84 args: {
85 from: '0x0000000000000000000000000000000000000000',
86 to: receiver,77 expect(event.returnValues.to).to.equal(receiver);
87 value: '100',78 expect(event.returnValues.value).to.equal('100');
88 },
89 },
90 ]);
91 });79 });
9280
93 itWeb3('Can perform mintBulk()', async ({web3, api, privateKeyWrapper}) => {81 itEth('Can perform mintBulk()', async ({helper}) => {
94 const alice = privateKeyWrapper('//Alice');82 const owner = await helper.eth.createAccountWithBalance(donor);
95 const collection = await createCollection(api, alice, {83 const bulkSize = 3;
96 name: 'token name',84 const receivers = [...new Array(bulkSize)].map(() => helper.eth.createAccount());
97 mode: {type: 'Fungible', decimalPoints: 0},85 const collection = await helper.ft.mintCollection(alice);
98 });86 await collection.addAdmin(alice, {Ethereum: owner});
9987
100 const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);88 const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId);
101 const receiver1 = createEthAccount(web3);89 const contract = helper.ethNativeContract.collection(collectionAddress, 'ft', owner);
102 const receiver2 = createEthAccount(web3);
103 const receiver3 = createEthAccount(web3);
10490
105 const collectionIdAddress = collectionIdToAddress(collection.collectionId);91 const result = await contract.methods.mintBulk(Array.from({length: bulkSize}, (_, i) => (
106 const changeAdminTx = api.tx.unique.addCollectionAdmin(collection.collectionId, {Ethereum: owner});
107 await submitTransactionAsync(alice, changeAdminTx);
108
109 const collectionContract = evmCollection(web3, owner, collectionIdAddress, {type: 'Fungible', decimalPoints: 0});
110 const result = await collectionContract.methods.mintBulk([
111 [receiver1, 10],92 [receivers[i], (i + 1) * 10]
112 [receiver2, 20],
113 [receiver3, 30],
114 ]).send();93 ))).send();
115 const events = normalizeEvents(result.events);94 const events = result.events.Transfer.sort((a: any, b: any) => +a.returnValues.value - b.returnValues.value);
116
117 expect(events).to.be.deep.contain({
118 address:collectionIdAddress,
119 event: 'Transfer',
120 args: {
121 from: '0x0000000000000000000000000000000000000000',
122 to: receiver1,95 for (let i = 0; i < bulkSize; i++) {
123 value: '10',
124 },96 const event = events[i];
125 });
126 97 expect(event.address).to.equal(collectionAddress);
127 expect(events).to.be.deep.contain({
128 address:collectionIdAddress,98 expect(event.returnValues.from).to.equal('0x0000000000000000000000000000000000000000');
129 event: 'Transfer',
130 args: {
131 from: '0x0000000000000000000000000000000000000000',
132 to: receiver2,
133 value: '20',
134 },
135 });
136 99 expect(event.returnValues.to).to.equal(receivers[i]);
137 expect(events).to.be.deep.contain({
138 address:collectionIdAddress,100 expect(event.returnValues.value).to.equal(String(10 * (i + 1)));
139 event: 'Transfer',
140 args: {
141 from: '0x0000000000000000000000000000000000000000',
142 to: receiver3,
143 value: '30',
144 },101 }
145 });
146 });102 });
147103
148 itWeb3('Can perform burn()', async ({web3, api, privateKeyWrapper}) => {104 itEth('Can perform burn()', async ({helper}) => {
149 const alice = privateKeyWrapper('//Alice');105 const owner = await helper.eth.createAccountWithBalance(donor);
150 const collection = await createCollection(api, alice, {106 const receiver = await helper.eth.createAccountWithBalance(donor);
151 name: 'token name',107 const collection = await helper.ft.mintCollection(alice);
152 mode: {type: 'Fungible', decimalPoints: 0},108 await collection.addAdmin(alice, {Ethereum: owner});
153 });
154109
155 const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);110 const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId);
156 const changeAdminTx = api.tx.unique.addCollectionAdmin(collection.collectionId, {Ethereum: owner});111 const contract = helper.ethNativeContract.collection(collectionAddress, 'ft', owner);
157 await submitTransactionAsync(alice, changeAdminTx);112 await contract.methods.mint(receiver, 100).send();
158 const receiver = await createEthAccountWithBalance(api, web3, privateKeyWrapper);
159113
160 const collectionIdAddress = collectionIdToAddress(collection.collectionId);114 const result = await contract.methods.burnFrom(receiver, 49).send({from: receiver});
161 const collectionContract = evmCollection(web3, owner, collectionIdAddress, {type: 'Fungible', decimalPoints: 0});
162 await collectionContract.methods.mint(receiver, 100).send();
163
164 const result = await collectionContract.methods.burnFrom(receiver, 49).send({from: receiver});
165 115
166 const events = normalizeEvents(result.events);116 const event = result.events.Transfer;
117 expect(event.address).to.equal(collectionAddress);
118 expect(event.returnValues.from).to.equal(receiver);
119 expect(event.returnValues.to).to.equal('0x0000000000000000000000000000000000000000');
120 expect(event.returnValues.value).to.equal('49');
167121
168 expect(events).to.be.deep.equal([122 const balance = await contract.methods.balanceOf(receiver).call();
169 {
170 address: collectionIdAddress,
171 event: 'Transfer',
172 args: {
173 from: receiver,
174 to: '0x0000000000000000000000000000000000000000',
175 value: '49',
176 },
177 },
178 ]);
179
180 const balance = await collectionContract.methods.balanceOf(receiver).call();
181 expect(balance).to.equal('51');123 expect(balance).to.equal('51');
182 });124 });
183125
184 itWeb3('Can perform approve()', async ({web3, api, privateKeyWrapper}) => {126 itEth('Can perform approve()', async ({helper}) => {
185 const collection = await createCollectionExpectSuccess({127 const owner = await helper.eth.createAccountWithBalance(donor);
186 name: 'token name',128 const spender = helper.eth.createAccount();
187 mode: {type: 'Fungible', decimalPoints: 0},129 const collection = await helper.ft.mintCollection(alice);
188 });
189 const alice = privateKeyWrapper('//Alice');130 await collection.mint(alice, 200n, {Ethereum: owner});
190131
191 const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);132 const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId);
133 const contract = helper.ethNativeContract.collection(collectionAddress, 'ft', owner);
192134
193 await createFungibleItemExpectSuccess(alice, collection, {Value: 200n}, {Ethereum: owner});
194
195 const spender = createEthAccount(web3);
196
197 const address = collectionIdToAddress(collection);
198 const contract = new web3.eth.Contract(fungibleAbi as any, address, {from: owner, ...GAS_ARGS});
199
200 {135 {
201 const result = await contract.methods.approve(spender, 100).send({from: owner});136 const result = await contract.methods.approve(spender, 100).send({from: owner});
202 const events = normalizeEvents(result.events);
203137
204 expect(events).to.be.deep.equal([138 const event = result.events.Approval;
205 {
206 address,139 expect(event.address).to.be.equal(collectionAddress);
207 event: 'Approval',140 expect(event.returnValues.owner).to.be.equal(owner);
208 args: {
209 owner,
210 spender,141 expect(event.returnValues.spender).to.be.equal(spender);
211 value: '100',142 expect(event.returnValues.value).to.be.equal('100');
212 },
213 },
214 ]);
215 }143 }
216144
217 {145 {
220 }148 }
221 });149 });
222150
223 itWeb3('Can perform transferFrom()', async ({web3, api, privateKeyWrapper}) => {151 itEth('Can perform transferFrom()', async ({helper}) => {
224 const collection = await createCollectionExpectSuccess({152 const owner = await helper.eth.createAccountWithBalance(donor);
225 name: 'token name',153 const spender = await helper.eth.createAccountWithBalance(donor);
226 mode: {type: 'Fungible', decimalPoints: 0},154 const receiver = helper.eth.createAccount();
227 });155 const collection = await helper.ft.mintCollection(alice);
228 const alice = privateKeyWrapper('//Alice');156 await collection.mint(alice, 200n, {Ethereum: owner});
229157
230 const owner = createEthAccount(web3);158 const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId);
231 await transferBalanceToEth(api, alice, owner);159 const contract = helper.ethNativeContract.collection(collectionAddress, 'ft', owner);
232160
233 await createFungibleItemExpectSuccess(alice, collection, {Value: 200n}, {Ethereum: owner});
234
235 const spender = createEthAccount(web3);
236 await transferBalanceToEth(api, alice, spender);
237
238 const receiver = createEthAccount(web3);
239
240 const address = collectionIdToAddress(collection);
241 const contract = new web3.eth.Contract(fungibleAbi as any, address, {from: owner, ...GAS_ARGS});
242
243 await contract.methods.approve(spender, 100).send();161 await contract.methods.approve(spender, 100).send();
244162
245 {163 {
246 const result = await contract.methods.transferFrom(owner, receiver, 49).send({from: spender});164 const result = await contract.methods.transferFrom(owner, receiver, 49).send({from: spender});
247 const events = normalizeEvents(result.events);165
166 let event = result.events.Transfer;
248 expect(events).to.be.deep.equal([167 expect(event.address).to.be.equal(collectionAddress);
249 {168 expect(event.returnValues.from).to.be.equal(owner);
250 address,
251 event: 'Transfer',
252 args: {
253 from: owner,
254 to: receiver,169 expect(event.returnValues.to).to.be.equal(receiver);
255 value: '49',170 expect(event.returnValues.value).to.be.equal('49');
256 },171
257 },172 event = result.events.Approval;
258 {173 expect(event.address).to.be.equal(collectionAddress);
259 address,
260 event: 'Approval',174 expect(event.returnValues.owner).to.be.equal(owner);
261 args: {
262 owner,
263 spender,175 expect(event.returnValues.spender).to.be.equal(spender);
264 value: '51',176 expect(event.returnValues.value).to.be.equal('51');
265 },
266 },
267 ]);
268 }177 }
269178
270 {179 {
278 }187 }
279 });188 });
280189
281 itWeb3('Can perform transfer()', async ({web3, api, privateKeyWrapper}) => {190 itEth('Can perform transfer()', async ({helper}) => {
282 const collection = await createCollectionExpectSuccess({191 const owner = await helper.eth.createAccountWithBalance(donor);
283 name: 'token name',192 const receiver = await helper.eth.createAccountWithBalance(donor);
284 mode: {type: 'Fungible', decimalPoints: 0},193 const collection = await helper.ft.mintCollection(alice);
285 });
286 const alice = privateKeyWrapper('//Alice');194 await collection.mint(alice, 200n, {Ethereum: owner});
287195
288 const owner = createEthAccount(web3);196 const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId);
289 await transferBalanceToEth(api, alice, owner);197 const contract = helper.ethNativeContract.collection(collectionAddress, 'ft', owner);
290198
291 await createFungibleItemExpectSuccess(alice, collection, {Value: 200n}, {Ethereum: owner});
292
293 const receiver = createEthAccount(web3);
294 await transferBalanceToEth(api, alice, receiver);
295
296 const address = collectionIdToAddress(collection);
297 const contract = new web3.eth.Contract(fungibleAbi as any, address, {from: owner, ...GAS_ARGS});
298
299 {199 {
300 const result = await contract.methods.transfer(receiver, 50).send({from: owner});200 const result = await contract.methods.transfer(receiver, 50).send({from: owner});
301 const events = normalizeEvents(result.events);201
202 const event = result.events.Transfer;
302 expect(events).to.be.deep.equal([203 expect(event.address).to.be.equal(collectionAddress);
303 {204 expect(event.returnValues.from).to.be.equal(owner);
304 address,
305 event: 'Transfer',
306 args: {
307 from: owner,
308 to: receiver,205 expect(event.returnValues.to).to.be.equal(receiver);
309 value: '50',206 expect(event.returnValues.value).to.be.equal('50');
310 },
311 },
312 ]);
313 }207 }
314208
315 {209 {
325});219});
326220
327describe('Fungible: Fees', () => {221describe('Fungible: Fees', () => {
328 itWeb3('approve() call fee is less than 0.2UNQ', async ({web3, api, privateKeyWrapper}) => {222 let donor: IKeyringPair;
223 let alice: IKeyringPair;
224
225 before(async function() {
226 await usingEthPlaygrounds(async (helper, privateKey) => {
329 const collection = await createCollectionExpectSuccess({227 donor = privateKey('//Alice');
330 mode: {type: 'Fungible', decimalPoints: 0},228 [alice] = await helper.arrange.createAccounts([20n], donor);
331 });229 });
332 const alice = privateKeyWrapper('//Alice');230 });
231
232 itEth('approve() call fee is less than 0.2UNQ', async ({helper}) => {
233 const owner = await helper.eth.createAccountWithBalance(donor);
234 const spender = helper.eth.createAccount();
235 const collection = await helper.ft.mintCollection(alice);
236 await collection.mint(alice, 200n, {Ethereum: owner});
333237
334 const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);238 const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId);
335 const spender = createEthAccount(web3);239 const contract = helper.ethNativeContract.collection(collectionAddress, 'ft', owner);
336240
337 await createFungibleItemExpectSuccess(alice, collection, {Value: 200n}, {Ethereum: owner});241 const cost = await helper.eth.recordCallFee(owner, () => contract.methods.approve(spender, 100).send({from: owner}));
338
339 const address = collectionIdToAddress(collection);
340 const contract = new web3.eth.Contract(fungibleAbi as any, address, {from: owner, ...GAS_ARGS});
341
342 const cost = await recordEthFee(api, owner, () => contract.methods.approve(spender, 100).send({from: owner}));
343 expect(cost < BigInt(0.2 * Number(UNIQUE)));242 expect(cost < BigInt(0.2 * Number(helper.balance.getOneTokenNominal())));
344 });243 });
345244
346 itWeb3('transferFrom() call fee is less than 0.2UNQ', async ({web3, api, privateKeyWrapper}) => {245 itEth('transferFrom() call fee is less than 0.2UNQ', async ({helper}) => {
347 const collection = await createCollectionExpectSuccess({246 const owner = await helper.eth.createAccountWithBalance(donor);
348 mode: {type: 'Fungible', decimalPoints: 0},247 const spender = await helper.eth.createAccountWithBalance(donor);
349 });248 const collection = await helper.ft.mintCollection(alice);
350 const alice = privateKeyWrapper('//Alice');249 await collection.mint(alice, 200n, {Ethereum: owner});
351250
352 const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);251 const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId);
353 const spender = await createEthAccountWithBalance(api, web3, privateKeyWrapper);252 const contract = helper.ethNativeContract.collection(collectionAddress, 'ft', owner);
354253
355 await createFungibleItemExpectSuccess(alice, collection, {Value: 200n}, {Ethereum: owner});
356
357 const address = collectionIdToAddress(collection);
358 const contract = new web3.eth.Contract(fungibleAbi as any, address, {from: owner, ...GAS_ARGS});
359
360 await contract.methods.approve(spender, 100).send({from: owner});254 await contract.methods.approve(spender, 100).send({from: owner});
361255
362 const cost = await recordEthFee(api, spender, () => contract.methods.transferFrom(owner, spender, 100).send({from: spender}));256 const cost = await helper.eth.recordCallFee(spender, () => contract.methods.transferFrom(owner, spender, 100).send({from: spender}));
363 expect(cost < BigInt(0.2 * Number(UNIQUE)));257 expect(cost < BigInt(0.2 * Number(helper.balance.getOneTokenNominal())));
364 });258 });
365259
366 itWeb3('transfer() call fee is less than 0.2UNQ', async ({web3, api, privateKeyWrapper}) => {260 itEth('transfer() call fee is less than 0.2UNQ', async ({helper}) => {
367 const collection = await createCollectionExpectSuccess({261 const owner = await helper.eth.createAccountWithBalance(donor);
368 mode: {type: 'Fungible', decimalPoints: 0},262 const receiver = helper.eth.createAccount();
369 });263 const collection = await helper.ft.mintCollection(alice);
370 const alice = privateKeyWrapper('//Alice');264 await collection.mint(alice, 200n, {Ethereum: owner});
371265
372 const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);266 const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId);
373 const receiver = createEthAccount(web3);267 const contract = helper.ethNativeContract.collection(collectionAddress, 'ft', owner);
374268
375 await createFungibleItemExpectSuccess(alice, collection, {Value: 200n}, {Ethereum: owner});269 const cost = await helper.eth.recordCallFee(owner, () => contract.methods.transfer(receiver, 100).send({from: owner}));
376
377 const address = collectionIdToAddress(collection);
378 const contract = new web3.eth.Contract(fungibleAbi as any, address, {from: owner, ...GAS_ARGS});
379
380 const cost = await recordEthFee(api, owner, () => contract.methods.transfer(receiver, 100).send({from: owner}));
381 expect(cost < BigInt(0.2 * Number(UNIQUE)));270 expect(cost < BigInt(0.2 * Number(helper.balance.getOneTokenNominal())));
382 });271 });
383});272});
384273
385describe('Fungible: Substrate calls', () => {274describe('Fungible: Substrate calls', () => {
386 itWeb3('Events emitted for approve()', async ({web3, privateKeyWrapper}) => {275 let donor: IKeyringPair;
276 let alice: IKeyringPair;
277
278 before(async function() {
279 await usingEthPlaygrounds(async (helper, privateKey) => {
387 const collection = await createCollectionExpectSuccess({280 donor = privateKey('//Alice');
388 mode: {type: 'Fungible', decimalPoints: 0},281 [alice] = await helper.arrange.createAccounts([20n], donor);
389 });282 });
390 const alice = privateKeyWrapper('//Alice');283 });
391284
392 const receiver = createEthAccount(web3);285 itEth('Events emitted for approve()', async ({helper}) => {
286 const receiver = helper.eth.createAccount();
287 const collection = await helper.ft.mintCollection(alice);
288 await collection.mint(alice, 200n);
393289
394 await createFungibleItemExpectSuccess(alice, collection, {Value: 200n});290 const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId);
291 const contract = helper.ethNativeContract.collection(collectionAddress, 'ft');
395292
396 const address = collectionIdToAddress(collection);293 const events: any = [];
397 const contract = new web3.eth.Contract(fungibleAbi as any, address);294 contract.events.allEvents((_: any, event: any) => {
398
399 const events = await recordEvents(contract, async () => {
400 await approveExpectSuccess(collection, 0, alice, {Ethereum: receiver}, 100);295 events.push(event);
401 });296 });
297 await collection.approveTokens(alice, {Ethereum: receiver}, 100n);
402298
403 expect(events).to.be.deep.equal([299 const event = events[0];
404 {
405 address,
406 event: 'Approval',300 expect(event.event).to.be.equal('Approval');
407 args: {301 expect(event.address).to.be.equal(collectionAddress);
408 owner: subToEth(alice.address),302 expect(event.returnValues.owner).to.be.equal(helper.address.substrateToEth(alice.address));
409 spender: receiver,303 expect(event.returnValues.spender).to.be.equal(receiver);
410 value: '100',304 expect(event.returnValues.value).to.be.equal('100');
411 },
412 },
413 ]);
414 });305 });
415306
416 itWeb3('Events emitted for transferFrom()', async ({web3, privateKeyWrapper}) => {307 itEth('Events emitted for transferFrom()', async ({helper}) => {
417 const collection = await createCollectionExpectSuccess({308 const [bob] = await helper.arrange.createAccounts([10n], donor);
418 mode: {type: 'Fungible', decimalPoints: 0},309 const receiver = helper.eth.createAccount();
419 });310 const collection = await helper.ft.mintCollection(alice);
420 const alice = privateKeyWrapper('//Alice');311 await collection.mint(alice, 200n);
421 const bob = privateKeyWrapper('//Bob');312 await collection.approveTokens(alice, {Substrate: bob.address}, 100n);
422313
423 const receiver = createEthAccount(web3);314 const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId);
315 const contract = helper.ethNativeContract.collection(collectionAddress, 'ft');
424316
425 await createFungibleItemExpectSuccess(alice, collection, {Value: 200n});317 const events: any = [];
426 await approveExpectSuccess(collection, 0, alice, bob.address, 100);
427
428 const address = collectionIdToAddress(collection);
429 const contract = new web3.eth.Contract(fungibleAbi as any, address);318 contract.events.allEvents((_: any, event: any) => {
430
431 const events = await recordEvents(contract, async () => {
432 await transferFromExpectSuccess(collection, 0, bob, alice, {Ethereum: receiver}, 51, 'Fungible');319 events.push(event);
433 });320 });
321 await collection.transferFrom(bob, {Substrate: alice.address}, {Ethereum: receiver}, 51n);
434322
435 expect(events).to.be.deep.equal([323 let event = events[0];
436 {
437 address,
438 event: 'Transfer',324 expect(event.event).to.be.equal('Transfer');
439 args: {325 expect(event.address).to.be.equal(collectionAddress);
440 from: subToEth(alice.address),
441 to: receiver,
442 value: '51',326 expect(event.returnValues.from).to.be.equal(helper.address.substrateToEth(alice.address));
443 },
444 },
445 {
446 address,
447 event: 'Approval',
448 args: {
449 owner: subToEth(alice.address),
450 spender: subToEth(bob.address),327 expect(event.returnValues.to).to.be.equal(receiver);
451 value: '49',328 expect(event.returnValues.value).to.be.equal('51');
452 },
453 },
454 ]);
455 });
456329
457 itWeb3('Events emitted for transfer()', async ({web3, privateKeyWrapper}) => {330 event = events[1];
458 const collection = await createCollectionExpectSuccess({331 expect(event.event).to.be.equal('Approval');
332 expect(event.address).to.be.equal(collectionAddress);
459 mode: {type: 'Fungible', decimalPoints: 0},333 expect(event.returnValues.owner).to.be.equal(helper.address.substrateToEth(alice.address));
460 });334 expect(event.returnValues.spender).to.be.equal(helper.address.substrateToEth(bob.address));
461 const alice = privateKeyWrapper('//Alice');335 expect(event.returnValues.value).to.be.equal('49');
462
463 const receiver = createEthAccount(web3);336 });
464337
465 await createFungibleItemExpectSuccess(alice, collection, {Value: 200n});338 itEth('Events emitted for transfer()', async ({helper}) => {
339 const receiver = helper.eth.createAccount();
340 const collection = await helper.ft.mintCollection(alice);
341 await collection.mint(alice, 200n);
466342
467 const address = collectionIdToAddress(collection);343 const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId);
468 const contract = new web3.eth.Contract(fungibleAbi as any, address);344 const contract = helper.ethNativeContract.collection(collectionAddress, 'ft');
469345
470 const events = await recordEvents(contract, async () => {346 const events: any = [];
347 contract.events.allEvents((_: any, event: any) => {
471 await transferExpectSuccess(collection, 0, alice, {Ethereum:receiver}, 51, 'Fungible');348 events.push(event);
472 });349 });
350 await collection.transfer(alice, {Ethereum:receiver}, 51n);
473351
474 expect(events).to.be.deep.equal([352 const event = events[0];
475 {
476 address,
477 event: 'Transfer',353 expect(event.event).to.be.equal('Transfer');
478 args: {354 expect(event.address).to.be.equal(collectionAddress);
479 from: subToEth(alice.address),355 expect(event.returnValues.from).to.be.equal(helper.address.substrateToEth(alice.address));
480 to: receiver,356 expect(event.returnValues.to).to.be.equal(receiver);
481 value: '51',357 expect(event.returnValues.value).to.be.equal('51');
482 },
483 },
484 ]);
485 });358 });
486});359});
487360
modifiedtests/src/eth/nonFungible.test.tsdiffbeforeafterboth
--- a/tests/src/eth/nonFungible.test.ts
+++ b/tests/src/eth/nonFungible.test.ts
@@ -14,72 +14,78 @@
 // You should have received a copy of the GNU General Public License
 // along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
 
-import {approveExpectSuccess, burnItemExpectSuccess, createCollectionExpectSuccess, createItemExpectSuccess, transferExpectSuccess, transferFromExpectSuccess, UNIQUE} from '../util/helpers';
-import {collectionIdToAddress, createEthAccount, createEthAccountWithBalance, evmCollection, evmCollectionHelpers, GAS_ARGS, getCollectionAddressFromResult, itWeb3, normalizeEvents, recordEthFee, recordEvents, subToEth, transferBalanceToEth} from './util/helpers';
-import nonFungibleAbi from './nonFungibleAbi.json';
-import {expect} from 'chai';
-import {submitTransactionAsync} from '../substrate/substrate-api';
+import {itEth, usingEthPlaygrounds, expect, EthUniqueHelper} from './util/playgrounds';
+import {IKeyringPair} from '@polkadot/types/types';
+import {Contract} from 'web3-eth-contract';
 
 describe('NFT: Information getting', () => {
-  itWeb3('totalSupply', async ({api, web3, privateKeyWrapper}) => {
-    const collection = await createCollectionExpectSuccess({
-      mode: {type: 'NFT'},
+  let donor: IKeyringPair;
+  let alice: IKeyringPair;
+
+  before(async function() {
+    await usingEthPlaygrounds(async (helper, privateKey) => {
+      donor = privateKey('//Alice');
+      [alice] = await helper.arrange.createAccounts([10n], donor);
     });
-    const alice = privateKeyWrapper('//Alice');
-    const caller = await createEthAccountWithBalance(api, web3, privateKeyWrapper);
+  });
+  
+  itEth('totalSupply', async ({helper}) => {
+    const collection = await helper.nft.mintCollection(alice, {});
+    await collection.mintToken(alice);
 
-    await createItemExpectSuccess(alice, collection, 'NFT', {Substrate: alice.address});
+    const caller = await helper.eth.createAccountWithBalance(donor);
 
-    const address = collectionIdToAddress(collection);
-    const contract = new web3.eth.Contract(nonFungibleAbi as any, address, {from: caller, ...GAS_ARGS});
+    const contract = helper.ethNativeContract.collectionById(collection.collectionId, 'nft', caller);
     const totalSupply = await contract.methods.totalSupply().call();
 
     expect(totalSupply).to.equal('1');
   });
 
-  itWeb3('balanceOf', async ({api, web3, privateKeyWrapper}) => {
-    const collection = await createCollectionExpectSuccess({
-      mode: {type: 'NFT'},
-    });
-    const alice = privateKeyWrapper('//Alice');
+  itEth('balanceOf', async ({helper}) => {
+    const collection = await helper.nft.mintCollection(alice, {});
+    const caller = await helper.eth.createAccountWithBalance(donor);
 
-    const caller = await createEthAccountWithBalance(api, web3, privateKeyWrapper);
-    await createItemExpectSuccess(alice, collection, 'NFT', {Ethereum:caller});
-    await createItemExpectSuccess(alice, collection, 'NFT', {Ethereum: caller});
-    await createItemExpectSuccess(alice, collection, 'NFT', {Ethereum: caller});
+    await collection.mintToken(alice, {Ethereum: caller});
+    await collection.mintToken(alice, {Ethereum: caller});
+    await collection.mintToken(alice, {Ethereum: caller});
 
-    const address = collectionIdToAddress(collection);
-    const contract = new web3.eth.Contract(nonFungibleAbi as any, address, {from: caller, ...GAS_ARGS});
+    const contract = helper.ethNativeContract.collectionById(collection.collectionId, 'nft', caller);
     const balance = await contract.methods.balanceOf(caller).call();
 
     expect(balance).to.equal('3');
   });
 
-  itWeb3('ownerOf', async ({api, web3, privateKeyWrapper}) => {
-    const collection = await createCollectionExpectSuccess({
-      mode: {type: 'NFT'},
-    });
-    const alice = privateKeyWrapper('//Alice');
+  itEth('ownerOf', async ({helper}) => {
+    const collection = await helper.nft.mintCollection(alice, {});
+    const caller = await helper.eth.createAccountWithBalance(donor);
 
-    const caller = await createEthAccountWithBalance(api, web3, privateKeyWrapper);
-    const tokenId = await createItemExpectSuccess(alice, collection, 'NFT', {Ethereum: caller});
+    const token = await collection.mintToken(alice, {Ethereum: caller});
 
-    const address = collectionIdToAddress(collection);
-    const contract = new web3.eth.Contract(nonFungibleAbi as any, address, {from: caller, ...GAS_ARGS});
-    const owner = await contract.methods.ownerOf(tokenId).call();
+    const contract = helper.ethNativeContract.collectionById(collection.collectionId, 'nft', caller);
+
+    const owner = await contract.methods.ownerOf(token.tokenId).call();
 
     expect(owner).to.equal(caller);
   });
 });
 
 describe('Check ERC721 token URI for NFT', () => {
-  itWeb3('Empty tokenURI', async ({web3, api, privateKeyWrapper}) => {
-    const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);
-    const helper = evmCollectionHelpers(web3, owner);
-    let result = await helper.methods.createERC721MetadataCompatibleCollection('Mint collection', '1', '1', '').send();
-    const {collectionIdAddress, collectionId} = await getCollectionAddressFromResult(api, result);
-    const receiver = createEthAccount(web3);
-    const contract = evmCollection(web3, owner, collectionIdAddress);
+  let donor: IKeyringPair;
+
+  before(async function() {
+    await usingEthPlaygrounds(async (_helper, privateKey) => {
+      donor = privateKey('//Alice');
+    });
+  });
+
+  async function setup(helper: EthUniqueHelper, tokenPrefix: string, propertyKey?: string, propertyValue?: string): Promise<{contract: Contract, nextTokenId: string}> {
+    const owner = await helper.eth.createAccountWithBalance(donor);
+    const receiver = helper.eth.createAccount();
+
+    const collectionHelper = helper.ethNativeContract.collectionHelpers(owner);
+    let result = await collectionHelper.methods.createERC721MetadataCompatibleCollection('Mint collection', 'a', 'b', tokenPrefix).send();
+    const collectionAddress = helper.ethAddress.normalizeAddress(result.events.CollectionCreated.returnValues.collectionId);
+    const contract = helper.ethNativeContract.collection(collectionAddress, 'nft', owner);
     
     const nextTokenId = await contract.methods.nextTokenId().call();
     expect(nextTokenId).to.be.equal('1');
@@ -88,162 +94,73 @@
       nextTokenId,
     ).send();
 
-    const events = normalizeEvents(result.events);
-    const address = collectionIdToAddress(collectionId);
+    if (propertyKey && propertyValue) {
+      // Set URL or suffix
+      await contract.methods.setProperty(nextTokenId, propertyKey, Buffer.from(propertyValue)).send();
+    }
 
-    expect(events).to.be.deep.equal([
-      {
-        address,
-        event: 'Transfer',
-        args: {
-          from: '0x0000000000000000000000000000000000000000',
-          to: receiver,
-          tokenId: nextTokenId,
-        },
-      },
-    ]);
+    const event = result.events.Transfer;
+    expect(event.address).to.be.equal(collectionAddress);
+    expect(event.returnValues.from).to.be.equal('0x0000000000000000000000000000000000000000');
+    expect(event.returnValues.to).to.be.equal(receiver);
+    expect(event.returnValues.tokenId).to.be.equal(nextTokenId);
 
+    return {contract, nextTokenId};
+  }
+
+  itEth('Empty tokenURI', async ({helper}) => {
+    const {contract, nextTokenId} = await setup(helper, '');
     expect(await contract.methods.tokenURI(nextTokenId).call()).to.be.equal('');
   });
 
-  itWeb3('TokenURI from url', async ({web3, api, privateKeyWrapper}) => {
-    const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);
-    const helper = evmCollectionHelpers(web3, owner);
-    let result = await helper.methods.createERC721MetadataCompatibleCollection('Mint collection', '1', '1', 'BaseURI_').send();
-    const {collectionIdAddress, collectionId} = await getCollectionAddressFromResult(api, result);
-    const receiver = createEthAccount(web3);
-    const contract = evmCollection(web3, owner, collectionIdAddress);
-    
-    const nextTokenId = await contract.methods.nextTokenId().call();
-    expect(nextTokenId).to.be.equal('1');
-    result = await contract.methods.mint(
-      receiver,
-      nextTokenId,
-    ).send();
-    
-    // Set URL
-    await contract.methods.setProperty(nextTokenId, 'url', Buffer.from('Token URI')).send();
-      
-    const events = normalizeEvents(result.events);
-    const address = collectionIdToAddress(collectionId);
-
-    expect(events).to.be.deep.equal([
-      {
-        address,
-        event: 'Transfer',
-        args: {
-          from: '0x0000000000000000000000000000000000000000',
-          to: receiver,
-          tokenId: nextTokenId,
-        },
-      },
-    ]);
-
+  itEth('TokenURI from url', async ({helper}) => {
+    const {contract, nextTokenId} = await setup(helper, 'BaseURI_', 'url', 'Token URI');
     expect(await contract.methods.tokenURI(nextTokenId).call()).to.be.equal('Token URI');
   });
 
-  itWeb3('TokenURI from baseURI + tokenId', async ({web3, api, privateKeyWrapper}) => {
-    const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);
-    const helper = evmCollectionHelpers(web3, owner);
-    let result = await helper.methods.createERC721MetadataCompatibleCollection('Mint collection', '1', '1', 'BaseURI_').send();
-    const {collectionIdAddress, collectionId} = await getCollectionAddressFromResult(api, result);
-    const receiver = createEthAccount(web3);
-    const contract = evmCollection(web3, owner, collectionIdAddress);
-    
-    const nextTokenId = await contract.methods.nextTokenId().call();
-    expect(nextTokenId).to.be.equal('1');
-    result = await contract.methods.mint(
-      receiver,
-      nextTokenId,
-    ).send();
-          
-    const events = normalizeEvents(result.events);
-    const address = collectionIdToAddress(collectionId);
-
-    expect(events).to.be.deep.equal([
-      {
-        address,
-        event: 'Transfer',
-        args: {
-          from: '0x0000000000000000000000000000000000000000',
-          to: receiver,
-          tokenId: nextTokenId,
-        },
-      },
-    ]);
-
+  itEth('TokenURI from baseURI + tokenId', async ({helper}) => {
+    const {contract, nextTokenId} = await setup(helper, 'BaseURI_');
     expect(await contract.methods.tokenURI(nextTokenId).call()).to.be.equal('BaseURI_' + nextTokenId);
   });
 
-  itWeb3('TokenURI from baseURI + suffix', async ({web3, api, privateKeyWrapper}) => {
-    const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);
-    const helper = evmCollectionHelpers(web3, owner);
-    let result = await helper.methods.createERC721MetadataCompatibleCollection('Mint collection', '1', '1', 'BaseURI_').send();
-    const {collectionIdAddress, collectionId} = await getCollectionAddressFromResult(api, result);
-    const receiver = createEthAccount(web3);
-    const contract = evmCollection(web3, owner, collectionIdAddress);
-    
-    const nextTokenId = await contract.methods.nextTokenId().call();
-    expect(nextTokenId).to.be.equal('1');
-    result = await contract.methods.mint(
-      receiver,
-      nextTokenId,
-    ).send();
-          
-    // Set suffix
+  itEth('TokenURI from baseURI + suffix', async ({helper}) => {
     const suffix = '/some/suffix';
-    await contract.methods.setProperty(nextTokenId, 'suffix', Buffer.from(suffix)).send();
-
-    const events = normalizeEvents(result.events);
-    const address = collectionIdToAddress(collectionId);
-
-    expect(events).to.be.deep.equal([
-      {
-        address,
-        event: 'Transfer',
-        args: {
-          from: '0x0000000000000000000000000000000000000000',
-          to: receiver,
-          tokenId: nextTokenId,
-        },
-      },
-    ]);
-
+    const {contract, nextTokenId} = await setup(helper, 'BaseURI_', 'suffix', suffix);
     expect(await contract.methods.tokenURI(nextTokenId).call()).to.be.equal('BaseURI_' + suffix);
   });
 });
 
 describe('NFT: Plain calls', () => {
-  itWeb3('Can perform mint()', async ({web3, api, privateKeyWrapper}) => {
-    const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);
-    const helper = evmCollectionHelpers(web3, owner);
-    let result = await helper.methods.createNonfungibleCollection('Mint collection', '6', '6').send();
-    const {collectionIdAddress, collectionId} = await getCollectionAddressFromResult(api, result);
-    const receiver = createEthAccount(web3);
-    const contract = evmCollection(web3, owner, collectionIdAddress);
+  let donor: IKeyringPair;
+  let alice: IKeyringPair;
+
+  before(async function() {
+    await usingEthPlaygrounds(async (helper, privateKey) => {
+      donor = privateKey('//Alice');
+      [alice] = await helper.arrange.createAccounts([10n], donor);
+    });
+  });
+
+  itEth('Can perform mint()', async ({helper}) => {
+    const owner = await helper.eth.createAccountWithBalance(donor);
+    const receiver = helper.eth.createAccount();
+
+    const {collectionAddress} = await helper.eth.createNonfungibleCollection(owner, 'Minty', '6', '6');
+    const contract = helper.ethNativeContract.collection(collectionAddress, 'nft', owner);
     const nextTokenId = await contract.methods.nextTokenId().call();
 
     expect(nextTokenId).to.be.equal('1');
-    result = await contract.methods.mintWithTokenURI(
+    const result = await contract.methods.mintWithTokenURI(
       receiver,
       nextTokenId,
       'Test URI',
     ).send();
 
-    const events = normalizeEvents(result.events);
-    const address = collectionIdToAddress(collectionId);
-
-    expect(events).to.be.deep.equal([
-      {
-        address,
-        event: 'Transfer',
-        args: {
-          from: '0x0000000000000000000000000000000000000000',
-          to: receiver,
-          tokenId: nextTokenId,
-        },
-      },
-    ]);
+    const event = result.events.Transfer;
+    expect(event.address).to.be.equal(collectionAddress);
+    expect(event.returnValues.from).to.be.equal('0x0000000000000000000000000000000000000000');
+    expect(event.returnValues.to).to.be.equal(receiver);
+    expect(event.returnValues.tokenId).to.be.equal(nextTokenId);
 
     expect(await contract.methods.tokenURI(nextTokenId).call()).to.be.equal('Test URI');
 
@@ -254,7 +171,8 @@
   });
 
   //TODO: CORE-302 add eth methods
-  itWeb3.skip('Can perform mintBulk()', async ({web3, api, privateKeyWrapper}) => {
+  /* todo:playgrounds skipped test!
+  itWeb3.skip('Can perform mintBulk()', async ({helper}) => {
     const collection = await createCollectionExpectSuccess({
       mode: {type: 'NFT'},
     });
@@ -316,107 +234,70 @@
       expect(await contract.methods.tokenURI(+nextTokenId + 2).call()).to.be.equal('Test URI 2');
     }
   });
-
-  itWeb3('Can perform burn()', async ({web3, api, privateKeyWrapper}) => {
-    const collection = await createCollectionExpectSuccess({
-      mode: {type: 'NFT'},
-    });
-    const alice = privateKeyWrapper('//Alice');
+  */
 
-    const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);
+  itEth('Can perform burn()', async ({helper}) => {
+    const caller = await helper.eth.createAccountWithBalance(donor);
 
-    const tokenId = await createItemExpectSuccess(alice, collection, 'NFT', {Ethereum: owner});
+    const collection = await helper.nft.mintCollection(alice, {});
+    const {tokenId} = await collection.mintToken(alice, {Ethereum: caller});
 
-    const address = collectionIdToAddress(collection);
-    const contract = new web3.eth.Contract(nonFungibleAbi as any, address, {from: owner, ...GAS_ARGS});
+    const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId);
+    const contract = helper.ethNativeContract.collection(collectionAddress, 'nft', caller);
 
     {
-      const result = await contract.methods.burn(tokenId).send({from: owner});
-      const events = normalizeEvents(result.events);
-
-      expect(events).to.be.deep.equal([
-        {
-          address,
-          event: 'Transfer',
-          args: {
-            from: owner,
-            to: '0x0000000000000000000000000000000000000000',
-            tokenId: tokenId.toString(),
-          },
-        },
-      ]);
+      const result = await contract.methods.burn(tokenId).send({from: caller});
+      
+      const event = result.events.Transfer;
+      expect(event.address).to.be.equal(collectionAddress);
+      expect(event.returnValues.from).to.be.equal(caller);
+      expect(event.returnValues.to).to.be.equal('0x0000000000000000000000000000000000000000');
+      expect(event.returnValues.tokenId).to.be.equal(`${tokenId}`);
     }
   });
 
-  itWeb3('Can perform approve()', async ({web3, api, privateKeyWrapper}) => {
-    const collection = await createCollectionExpectSuccess({
-      mode: {type: 'NFT'},
-    });
-    const alice = privateKeyWrapper('//Alice');
-
-    const owner = createEthAccount(web3);
-    await transferBalanceToEth(api, alice, owner);
-
-    const tokenId = await createItemExpectSuccess(alice, collection, 'NFT', {Ethereum: owner});
+  itEth('Can perform approve()', async ({helper}) => {
+    const owner = await helper.eth.createAccountWithBalance(donor);
+    const spender = helper.eth.createAccount();
 
-    const spender = createEthAccount(web3);
+    const collection = await helper.nft.mintCollection(alice, {});
+    const {tokenId} = await collection.mintToken(alice, {Ethereum: owner});
 
-    const address = collectionIdToAddress(collection);
-    const contract = new web3.eth.Contract(nonFungibleAbi as any, address);
+    const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId);
+    const contract = helper.ethNativeContract.collection(collectionAddress, 'nft', owner);
 
     {
-      const result = await contract.methods.approve(spender, tokenId).send({from: owner, ...GAS_ARGS});
-      const events = normalizeEvents(result.events);
+      const result = await contract.methods.approve(spender, tokenId).send({from: owner});
 
-      expect(events).to.be.deep.equal([
-        {
-          address,
-          event: 'Approval',
-          args: {
-            owner,
-            approved: spender,
-            tokenId: tokenId.toString(),
-          },
-        },
-      ]);
+      const event = result.events.Approval;
+      expect(event.address).to.be.equal(collectionAddress);
+      expect(event.returnValues.owner).to.be.equal(owner);
+      expect(event.returnValues.approved).to.be.equal(spender);
+      expect(event.returnValues.tokenId).to.be.equal(`${tokenId}`);
     }
   });
 
-  itWeb3('Can perform transferFrom()', async ({web3, api, privateKeyWrapper}) => {
-    const collection = await createCollectionExpectSuccess({
-      mode: {type: 'NFT'},
-    });
-    const alice = privateKeyWrapper('//Alice');
-
-    const owner = createEthAccount(web3);
-    await transferBalanceToEth(api, alice, owner);
+  itEth('Can perform transferFrom()', async ({helper}) => {
+    const owner = await helper.eth.createAccountWithBalance(donor);
+    const spender = await helper.eth.createAccountWithBalance(donor);
+    const receiver = helper.eth.createAccount();
 
-    const tokenId = await createItemExpectSuccess(alice, collection, 'NFT', {Ethereum: owner});
-
-    const spender = createEthAccount(web3);
-    await transferBalanceToEth(api, alice, spender);
-
-    const receiver = createEthAccount(web3);
+    const collection = await helper.nft.mintCollection(alice, {});
+    const {tokenId} = await collection.mintToken(alice, {Ethereum: owner});
 
-    const address = collectionIdToAddress(collection);
-    const contract = new web3.eth.Contract(nonFungibleAbi as any, address, {from: owner, ...GAS_ARGS});
+    const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId);
+    const contract = helper.ethNativeContract.collection(collectionAddress, 'nft', owner);
 
     await contract.methods.approve(spender, tokenId).send({from: owner});
 
     {
       const result = await contract.methods.transferFrom(owner, receiver, tokenId).send({from: spender});
-      const events = normalizeEvents(result.events);
-      expect(events).to.be.deep.equal([
-        {
-          address,
-          event: 'Transfer',
-          args: {
-            from: owner,
-            to: receiver,
-            tokenId: tokenId.toString(),
-          },
-        },
-      ]);
+
+      const event = result.events.Transfer;
+      expect(event.address).to.be.equal(collectionAddress);
+      expect(event.returnValues.from).to.be.equal(owner);
+      expect(event.returnValues.to).to.be.equal(receiver);
+      expect(event.returnValues.tokenId).to.be.equal(`${tokenId}`);
     }
 
     {
@@ -430,37 +311,24 @@
     }
   });
 
-  itWeb3('Can perform transfer()', async ({web3, api, privateKeyWrapper}) => {
-    const collection = await createCollectionExpectSuccess({
-      mode: {type: 'NFT'},
-    });
-    const alice = privateKeyWrapper('//Alice');
-
-    const owner = createEthAccount(web3);
-    await transferBalanceToEth(api, alice, owner);
-
-    const tokenId = await createItemExpectSuccess(alice, collection, 'NFT', {Ethereum: owner});
+  itEth('Can perform transfer()', async ({helper}) => {
+    const collection = await helper.nft.mintCollection(alice, {});
+    const owner = await helper.eth.createAccountWithBalance(donor);
+    const receiver = helper.eth.createAccount();
 
-    const receiver = createEthAccount(web3);
-    await transferBalanceToEth(api, alice, receiver);
+    const {tokenId} = await collection.mintToken(alice, {Ethereum: owner});
 
-    const address = collectionIdToAddress(collection);
-    const contract = new web3.eth.Contract(nonFungibleAbi as any, address, {from: owner, ...GAS_ARGS});
+    const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId);
+    const contract = helper.ethNativeContract.collection(collectionAddress, 'nft', owner);
 
     {
       const result = await contract.methods.transfer(receiver, tokenId).send({from: owner});
-      const events = normalizeEvents(result.events);
-      expect(events).to.be.deep.equal([
-        {
-          address,
-          event: 'Transfer',
-          args: {
-            from: owner,
-            to: receiver,
-            tokenId: tokenId.toString(),
-          },
-        },
-      ]);
+
+      const event = result.events.Transfer;
+      expect(event.address).to.be.equal(collectionAddress);
+      expect(event.returnValues.from).to.be.equal(owner);
+      expect(event.returnValues.to).to.be.equal(receiver);
+      expect(event.returnValues.tokenId).to.be.equal(`${tokenId}`);
     }
 
     {
@@ -476,237 +344,209 @@
 });
 
 describe('NFT: Fees', () => {
-  itWeb3('approve() call fee is less than 0.2UNQ', async ({web3, api, privateKeyWrapper}) => {
-    const collection = await createCollectionExpectSuccess({
-      mode: {type: 'NFT'},
+  let donor: IKeyringPair;
+  let alice: IKeyringPair;
+
+  before(async function() {
+    await usingEthPlaygrounds(async (helper, privateKey) => {
+      donor = privateKey('//Alice');
+      [alice] = await helper.arrange.createAccounts([10n], donor);
     });
-    const alice = privateKeyWrapper('//Alice');
+  });
+  
+  itEth('approve() call fee is less than 0.2UNQ', async ({helper}) => {
+    const owner = await helper.eth.createAccountWithBalance(donor);
+    const spender = helper.eth.createAccount();
 
-    const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);
-    const spender = createEthAccount(web3);
+    const collection = await helper.nft.mintCollection(alice, {});
+    const {tokenId} = await collection.mintToken(alice, {Ethereum: owner});
 
-    const tokenId = await createItemExpectSuccess(alice, collection, 'NFT', {Ethereum: owner});
+    const contract = helper.ethNativeContract.collectionById(collection.collectionId, 'nft', owner);
 
-    const address = collectionIdToAddress(collection);
-    const contract = new web3.eth.Contract(nonFungibleAbi as any, address, {from: owner, ...GAS_ARGS});
-
-    const cost = await recordEthFee(api, owner, () => contract.methods.approve(spender, tokenId).send({from: owner}));
-    expect(cost < BigInt(0.2 * Number(UNIQUE)));
+    const cost = await helper.eth.recordCallFee(owner, () => contract.methods.approve(spender, tokenId).send({from: owner}));
+    expect(cost < BigInt(0.2 * Number(helper.balance.getOneTokenNominal())));
   });
 
-  itWeb3('transferFrom() call fee is less than 0.2UNQ', async ({web3, api, privateKeyWrapper}) => {
-    const collection = await createCollectionExpectSuccess({
-      mode: {type: 'NFT'},
-    });
-    const alice = privateKeyWrapper('//Alice');
-
-    const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);
-    const spender = await createEthAccountWithBalance(api, web3, privateKeyWrapper);
+  itEth('transferFrom() call fee is less than 0.2UNQ', async ({helper}) => {
+    const owner = await helper.eth.createAccountWithBalance(donor);
+    const spender = await helper.eth.createAccountWithBalance(donor);
 
-    const tokenId = await createItemExpectSuccess(alice, collection, 'NFT', {Ethereum: owner});
+    const collection = await helper.nft.mintCollection(alice, {});
+    const {tokenId} = await collection.mintToken(alice, {Ethereum: owner});
 
-    const address = collectionIdToAddress(collection);
-    const contract = new web3.eth.Contract(nonFungibleAbi as any, address, {from: owner, ...GAS_ARGS});
+    const contract = helper.ethNativeContract.collectionById(collection.collectionId, 'nft', owner);
 
     await contract.methods.approve(spender, tokenId).send({from: owner});
 
-    const cost = await recordEthFee(api, spender, () => contract.methods.transferFrom(owner, spender, tokenId).send({from: spender}));
-    expect(cost < BigInt(0.2 * Number(UNIQUE)));
+    const cost = await helper.eth.recordCallFee(spender, () => contract.methods.transferFrom(owner, spender, tokenId).send({from: spender}));
+    expect(cost < BigInt(0.2 * Number(helper.balance.getOneTokenNominal())));
   });
 
-  itWeb3('transfer() call fee is less than 0.2UNQ', async ({web3, api, privateKeyWrapper}) => {
-    const collection = await createCollectionExpectSuccess({
-      mode: {type: 'NFT'},
-    });
-    const alice = privateKeyWrapper('//Alice');
+  itEth('transfer() call fee is less than 0.2UNQ', async ({helper}) => {
+    const owner = await helper.eth.createAccountWithBalance(donor);
+    const receiver = helper.eth.createAccount();
 
-    const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);
-    const receiver = createEthAccount(web3);
+    const collection = await helper.nft.mintCollection(alice, {});
+    const {tokenId} = await collection.mintToken(alice, {Ethereum: owner});
 
-    const tokenId = await createItemExpectSuccess(alice, collection, 'NFT', {Ethereum: owner});
+    const contract = helper.ethNativeContract.collectionById(collection.collectionId, 'nft', owner);
 
-    const address = collectionIdToAddress(collection);
-    const contract = new web3.eth.Contract(nonFungibleAbi as any, address, {from: owner, ...GAS_ARGS});
-
-    const cost = await recordEthFee(api, owner, () => contract.methods.transfer(receiver, tokenId).send({from: owner}));
-    expect(cost < BigInt(0.2 * Number(UNIQUE)));
+    const cost = await helper.eth.recordCallFee(owner, () => contract.methods.transfer(receiver, tokenId).send({from: owner}));
+    expect(cost < BigInt(0.2 * Number(helper.balance.getOneTokenNominal())));
   });
 });
 
 describe('NFT: Substrate calls', () => {
-  itWeb3('Events emitted for mint()', async ({web3, privateKeyWrapper}) => {
-    const collection = await createCollectionExpectSuccess({
-      mode: {type: 'NFT'},
+  let donor: IKeyringPair;
+  let alice: IKeyringPair;
+
+  before(async function() {
+    await usingEthPlaygrounds(async (helper, privateKey) => {
+      donor = privateKey('//Alice');
+      [alice] = await helper.arrange.createAccounts([20n], donor);
     });
-    const alice = privateKeyWrapper('//Alice');
+  });
 
-    const address = collectionIdToAddress(collection);
-    const contract = new web3.eth.Contract(nonFungibleAbi as any, address);
+  itEth('Events emitted for mint()', async ({helper}) => {
+    const collection = await helper.nft.mintCollection(alice, {});
+    const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId);
+    const contract = helper.ethNativeContract.collection(collectionAddress, 'nft');
 
-    let tokenId: number;
-    const events = await recordEvents(contract, async () => {
-      tokenId = await createItemExpectSuccess(alice, collection, 'NFT');
+    const events: any = [];
+    contract.events.allEvents((_: any, event: any) => {
+      events.push(event);
     });
+    const {tokenId} = await collection.mintToken(alice);
 
-    expect(events).to.be.deep.equal([
-      {
-        address,
-        event: 'Transfer',
-        args: {
-          from: '0x0000000000000000000000000000000000000000',
-          to: subToEth(alice.address),
-          tokenId: tokenId!.toString(),
-        },
-      },
-    ]);
+    const event = events[0];
+    expect(event.event).to.be.equal('Transfer');
+    expect(event.address).to.be.equal(collectionAddress);
+    expect(event.returnValues.from).to.be.equal('0x0000000000000000000000000000000000000000');
+    expect(event.returnValues.to).to.be.equal(helper.address.substrateToEth(alice.address));
+    expect(event.returnValues.tokenId).to.be.equal(tokenId.toString());
   });
 
-  itWeb3('Events emitted for burn()', async ({web3, privateKeyWrapper}) => {
-    const collection = await createCollectionExpectSuccess({
-      mode: {type: 'NFT'},
+  itEth('Events emitted for burn()', async ({helper}) => {
+    const collection = await helper.nft.mintCollection(alice, {});
+    const token = await collection.mintToken(alice);
+
+    const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId);
+    const contract = helper.ethNativeContract.collection(collectionAddress, 'nft');
+    
+    const events: any = [];
+    contract.events.allEvents((_: any, event: any) => {
+      events.push(event);
     });
-    const alice = privateKeyWrapper('//Alice');
 
-    const address = collectionIdToAddress(collection);
-    const contract = new web3.eth.Contract(nonFungibleAbi as any, address);
+    await token.burn(alice);
 
-    const tokenId = await createItemExpectSuccess(alice, collection, 'NFT');
-    const events = await recordEvents(contract, async () => {
-      await burnItemExpectSuccess(alice, collection, tokenId);
-    });
-
-    expect(events).to.be.deep.equal([
-      {
-        address,
-        event: 'Transfer',
-        args: {
-          from: subToEth(alice.address),
-          to: '0x0000000000000000000000000000000000000000',
-          tokenId: tokenId.toString(),
-        },
-      },
-    ]);
+    const event = events[0];
+    expect(event.event).to.be.equal('Transfer');
+    expect(event.address).to.be.equal(collectionAddress);
+    expect(event.returnValues.from).to.be.equal(helper.address.substrateToEth(alice.address));
+    expect(event.returnValues.to).to.be.equal('0x0000000000000000000000000000000000000000');
+    expect(event.returnValues.tokenId).to.be.equal(token.tokenId.toString());
   });
 
-  itWeb3('Events emitted for approve()', async ({web3, privateKeyWrapper}) => {
-    const collection = await createCollectionExpectSuccess({
-      mode: {type: 'NFT'},
-    });
-    const alice = privateKeyWrapper('//Alice');
+  itEth('Events emitted for approve()', async ({helper}) => {
+    const receiver = helper.eth.createAccount();
 
-    const receiver = createEthAccount(web3);
-
-    const tokenId = await createItemExpectSuccess(alice, collection, 'NFT');
-
-    const address = collectionIdToAddress(collection);
-    const contract = new web3.eth.Contract(nonFungibleAbi as any, address);
+    const collection = await helper.nft.mintCollection(alice, {});
+    const token = await collection.mintToken(alice);
 
-    const events = await recordEvents(contract, async () => {
-      await approveExpectSuccess(collection, tokenId, alice, {Ethereum: receiver}, 1);
+    const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId);
+    const contract = helper.ethNativeContract.collection(collectionAddress, 'nft');
+    
+    const events: any = [];
+    contract.events.allEvents((_: any, event: any) => {
+      events.push(event);
     });
 
-    expect(events).to.be.deep.equal([
-      {
-        address,
-        event: 'Approval',
-        args: {
-          owner: subToEth(alice.address),
-          approved: receiver,
-          tokenId: tokenId.toString(),
-        },
-      },
-    ]);
+    await token.approve(alice, {Ethereum: receiver});
+
+    const event = events[0];
+    expect(event.event).to.be.equal('Approval');
+    expect(event.address).to.be.equal(collectionAddress);
+    expect(event.returnValues.owner).to.be.equal(helper.address.substrateToEth(alice.address));
+    expect(event.returnValues.approved).to.be.equal(receiver);
+    expect(event.returnValues.tokenId).to.be.equal(token.tokenId.toString());
   });
 
-  itWeb3('Events emitted for transferFrom()', async ({web3, privateKeyWrapper}) => {
-    const collection = await createCollectionExpectSuccess({
-      mode: {type: 'NFT'},
-    });
-    const alice = privateKeyWrapper('//Alice');
-    const bob = privateKeyWrapper('//Bob');
+  itEth('Events emitted for transferFrom()', async ({helper}) => {
+    const [bob] = await helper.arrange.createAccounts([10n], donor);
+    const receiver = helper.eth.createAccount();
 
-    const receiver = createEthAccount(web3);
-
-    const tokenId = await createItemExpectSuccess(alice, collection, 'NFT');
-    await approveExpectSuccess(collection, tokenId, alice, bob.address, 1);
-
-    const address = collectionIdToAddress(collection);
-    const contract = new web3.eth.Contract(nonFungibleAbi as any, address);
+    const collection = await helper.nft.mintCollection(alice, {});
+    const token = await collection.mintToken(alice);
+    await token.approve(alice, {Substrate: bob.address});
 
-    const events = await recordEvents(contract, async () => {
-      await transferFromExpectSuccess(collection, tokenId, bob, alice, {Ethereum: receiver}, 1, 'NFT');
+    const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId);
+    const contract = helper.ethNativeContract.collection(collectionAddress, 'nft');
+    
+    const events: any = [];
+    contract.events.allEvents((_: any, event: any) => {
+      events.push(event);
     });
 
-    expect(events).to.be.deep.equal([
-      {
-        address,
-        event: 'Transfer',
-        args: {
-          from: subToEth(alice.address),
-          to: receiver,
-          tokenId: tokenId.toString(),
-        },
-      },
-    ]);
+    await token.transferFrom(bob, {Substrate: alice.address}, {Ethereum: receiver});
+    
+    const event = events[0];
+    expect(event.address).to.be.equal(collectionAddress);
+    expect(event.returnValues.from).to.be.equal(helper.address.substrateToEth(alice.address));
+    expect(event.returnValues.to).to.be.equal(receiver);
+    expect(event.returnValues.tokenId).to.be.equal(`${token.tokenId}`);
   });
 
-  itWeb3('Events emitted for transfer()', async ({web3, privateKeyWrapper}) => {
-    const collection = await createCollectionExpectSuccess({
-      mode: {type: 'NFT'},
-    });
-    const alice = privateKeyWrapper('//Alice');
+  itEth('Events emitted for transfer()', async ({helper}) => {
+    const receiver = helper.eth.createAccount();
 
-    const receiver = createEthAccount(web3);
+    const collection = await helper.nft.mintCollection(alice, {});
+    const token = await collection.mintToken(alice);
 
-    const tokenId = await createItemExpectSuccess(alice, collection, 'NFT');
-
-    const address = collectionIdToAddress(collection);
-    const contract = new web3.eth.Contract(nonFungibleAbi as any, address);
-
-    const events = await recordEvents(contract, async () => {
-      await transferExpectSuccess(collection, tokenId, alice, {Ethereum: receiver}, 1, 'NFT');
+    const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId);
+    const contract = helper.ethNativeContract.collection(collectionAddress, 'nft');
+    
+    const events: any = [];
+    contract.events.allEvents((_: any, event: any) => {
+      events.push(event);
     });
 
-    expect(events).to.be.deep.equal([
-      {
-        address,
-        event: 'Transfer',
-        args: {
-          from: subToEth(alice.address),
-          to: receiver,
-          tokenId: tokenId.toString(),
-        },
-      },
-    ]);
+    await token.transfer(alice, {Ethereum: receiver});
+    
+    const event = events[0];
+    expect(event.address).to.be.equal(collectionAddress);
+    expect(event.returnValues.from).to.be.equal(helper.address.substrateToEth(alice.address));
+    expect(event.returnValues.to).to.be.equal(receiver);
+    expect(event.returnValues.tokenId).to.be.equal(`${token.tokenId}`);
   });
 });
 
 describe('Common metadata', () => {
-  itWeb3('Returns collection name', async ({api, web3, privateKeyWrapper}) => {
-    const collection = await createCollectionExpectSuccess({
-      name: 'token name',
-      mode: {type: 'NFT'},
+  let donor: IKeyringPair;
+  let alice: IKeyringPair;
+
+  before(async function() {
+    await usingEthPlaygrounds(async (helper, privateKey) => {
+      donor = privateKey('//Alice');
+      [alice] = await helper.arrange.createAccounts([20n], donor);
     });
-    const caller = await createEthAccountWithBalance(api, web3, privateKeyWrapper);
+  });
+
+  itEth('Returns collection name', async ({helper}) => {
+    const caller = await helper.eth.createAccountWithBalance(donor);
+    const collection = await helper.nft.mintCollection(alice, {name: 'oh River', tokenPrefix: 'CHANGE'});
 
-    const address = collectionIdToAddress(collection);
-    const contract = new web3.eth.Contract(nonFungibleAbi as any, address, {from: caller, ...GAS_ARGS});
+    const contract = helper.ethNativeContract.collectionById(collection.collectionId, 'nft', caller);
     const name = await contract.methods.name().call();
-
-    expect(name).to.equal('token name');
+    expect(name).to.equal('oh River');
   });
 
-  itWeb3('Returns symbol name', async ({api, web3, privateKeyWrapper}) => {
-    const collection = await createCollectionExpectSuccess({
-      tokenPrefix: 'TOK',
-      mode: {type: 'NFT'},
-    });
-    const caller = await createEthAccountWithBalance(api, web3, privateKeyWrapper);
+  itEth('Returns symbol name', async ({helper}) => {
+    const caller = await helper.eth.createAccountWithBalance(donor);
+    const collection = await helper.nft.mintCollection(alice, {name: 'oh River', tokenPrefix: 'CHANGE'});
 
-    const address = collectionIdToAddress(collection);
-    const contract = new web3.eth.Contract(nonFungibleAbi as any, address, {from: caller, ...GAS_ARGS});
+    const contract = helper.ethNativeContract.collectionById(collection.collectionId, 'nft', caller);
     const symbol = await contract.methods.symbol().call();
-
-    expect(symbol).to.equal('TOK');
+    expect(symbol).to.equal('CHANGE');
   });
 });
\ No newline at end of file
modifiedtests/src/eth/reFungible.test.tsdiffbeforeafterboth
--- a/tests/src/eth/reFungible.test.ts
+++ b/tests/src/eth/reFungible.test.ts
@@ -14,33 +14,35 @@
 // You should have received a copy of the GNU General Public License
 // along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
 
-import {createCollectionExpectSuccess, UNIQUE, requirePallets, Pallets} from '../util/helpers';
-import {collectionIdToAddress, createEthAccount, createEthAccountWithBalance, evmCollection, evmCollectionHelpers, getCollectionAddressFromResult, itWeb3, normalizeEvents, recordEthFee, recordEvents, tokenIdToAddress, uniqueRefungibleToken} from './util/helpers';
-import {expect} from 'chai';
+import {Pallets, requirePalletsOrSkip} from '../util/playgrounds';
+import {expect, itEth, usingEthPlaygrounds} from './util/playgrounds';
+import {IKeyringPair} from '@polkadot/types/types';
 
 describe('Refungible: Information getting', () => {
+  let donor: IKeyringPair;
+
   before(async function() {
-    await requirePallets(this, [Pallets.ReFungible]);
+    await usingEthPlaygrounds(async (helper, privateKey) => {
+      requirePalletsOrSkip(this, helper, [Pallets.ReFungible]);
+
+      donor = privateKey('//Alice');
+    });
   });
 
-  itWeb3('totalSupply', async ({api, web3, privateKeyWrapper}) => {
-    const caller = await createEthAccountWithBalance(api, web3, privateKeyWrapper);
-    const helper = evmCollectionHelpers(web3, caller);
-    const result = await helper.methods.createRFTCollection('Mint collection', '6', '6').send();
-    const {collectionIdAddress} = await getCollectionAddressFromResult(api, result);
-    const contract = evmCollection(web3, caller, collectionIdAddress, {type: 'ReFungible'});
+  itEth('totalSupply', async ({helper}) => {
+    const caller = await helper.eth.createAccountWithBalance(donor);
+    const {collectionAddress} = await helper.eth.createRefungibleCollection(caller, 'TotalSupply', '6', '6');
+    const contract = helper.ethNativeContract.collection(collectionAddress, 'rft', caller);
     const nextTokenId = await contract.methods.nextTokenId().call();
     await contract.methods.mint(caller, nextTokenId).send();
     const totalSupply = await contract.methods.totalSupply().call();
     expect(totalSupply).to.equal('1');
   });
 
-  itWeb3('balanceOf', async ({api, web3, privateKeyWrapper}) => {
-    const caller = await createEthAccountWithBalance(api, web3, privateKeyWrapper);
-    const helper = evmCollectionHelpers(web3, caller);
-    const result = await helper.methods.createRFTCollection('Mint collection', '6', '6').send();
-    const {collectionIdAddress} = await getCollectionAddressFromResult(api, result);
-    const contract = evmCollection(web3, caller, collectionIdAddress, {type: 'ReFungible'});
+  itEth('balanceOf', async ({helper}) => {
+    const caller = await helper.eth.createAccountWithBalance(donor);
+    const {collectionAddress} = await helper.eth.createRefungibleCollection(caller, 'BalanceOf', '6', '6');
+    const contract = helper.ethNativeContract.collection(collectionAddress, 'rft', caller);
 
     {
       const nextTokenId = await contract.methods.nextTokenId().call();
@@ -56,38 +58,30 @@
     }
 
     const balance = await contract.methods.balanceOf(caller).call();
-
     expect(balance).to.equal('3');
   });
 
-  itWeb3('ownerOf', async ({api, web3, privateKeyWrapper}) => {
-    const caller = await createEthAccountWithBalance(api, web3, privateKeyWrapper);
-    const helper = evmCollectionHelpers(web3, caller);
-    const result = await helper.methods.createRFTCollection('Mint collection', '6', '6').send();
-    const {collectionIdAddress} = await getCollectionAddressFromResult(api, result);
-    const contract = evmCollection(web3, caller, collectionIdAddress, {type: 'ReFungible'});
+  itEth('ownerOf', async ({helper}) => {
+    const caller = await helper.eth.createAccountWithBalance(donor);
+    const {collectionAddress} = await helper.eth.createRefungibleCollection(caller, 'OwnerOf', '6', '6');
+    const contract = helper.ethNativeContract.collection(collectionAddress, 'rft', caller);
 
     const tokenId = await contract.methods.nextTokenId().call();
     await contract.methods.mint(caller, tokenId).send();
 
     const owner = await contract.methods.ownerOf(tokenId).call();
-
     expect(owner).to.equal(caller);
   });
 
-  itWeb3('ownerOf after burn', async ({api, web3, privateKeyWrapper}) => {
-    const caller = await createEthAccountWithBalance(api, web3, privateKeyWrapper);
-    const receiver = createEthAccount(web3);
-    const helper = evmCollectionHelpers(web3, caller);
-    const result = await helper.methods.createRFTCollection('Mint collection', '6', '6').send();
-    const {collectionIdAddress, collectionId} = await getCollectionAddressFromResult(api, result);
-    const contract = evmCollection(web3, caller, collectionIdAddress, {type: 'ReFungible'});
+  itEth('ownerOf after burn', async ({helper}) => {
+    const caller = await helper.eth.createAccountWithBalance(donor);
+    const receiver = helper.eth.createAccount();
+    const {collectionId, collectionAddress} = await helper.eth.createRefungibleCollection(caller, 'OwnerOf-AfterBurn', '6', '6');
+    const contract = helper.ethNativeContract.collection(collectionAddress, 'rft', caller);
 
     const tokenId = await contract.methods.nextTokenId().call();
     await contract.methods.mint(caller, tokenId).send();
-
-    const tokenAddress = tokenIdToAddress(collectionId, tokenId);
-    const tokenContract = uniqueRefungibleToken(web3, tokenAddress, caller);
+    const tokenContract = helper.ethNativeContract.rftTokenById(collectionId, tokenId, caller);
 
     await tokenContract.methods.repartition(2).send();
     await tokenContract.methods.transfer(receiver, 1).send();
@@ -95,80 +89,67 @@
     await tokenContract.methods.burnFrom(caller, 1).send();
 
     const owner = await contract.methods.ownerOf(tokenId).call();
-
     expect(owner).to.equal(receiver);
   });
 
-  itWeb3('ownerOf for partial ownership', async ({api, web3, privateKeyWrapper}) => {
-    const caller = await createEthAccountWithBalance(api, web3, privateKeyWrapper);
-    const receiver = createEthAccount(web3);
-    const helper = evmCollectionHelpers(web3, caller);
-    const result = await helper.methods.createRFTCollection('Mint collection', '6', '6').send();
-    const {collectionIdAddress, collectionId} = await getCollectionAddressFromResult(api, result);
-    const contract = evmCollection(web3, caller, collectionIdAddress, {type: 'ReFungible'});
+  itEth('ownerOf for partial ownership', async ({helper}) => {
+    const caller = await helper.eth.createAccountWithBalance(donor);
+    const receiver = helper.eth.createAccount();
+    const {collectionId, collectionAddress} = await helper.eth.createRefungibleCollection(caller, 'Partial-OwnerOf', '6', '6');
+    const contract = helper.ethNativeContract.collection(collectionAddress, 'rft', caller);
 
     const tokenId = await contract.methods.nextTokenId().call();
     await contract.methods.mint(caller, tokenId).send();
-
-    const tokenAddress = tokenIdToAddress(collectionId, tokenId);
-    const tokenContract = uniqueRefungibleToken(web3, tokenAddress, caller);
+    const tokenContract = helper.ethNativeContract.rftTokenById(collectionId, tokenId, caller);
 
     await tokenContract.methods.repartition(2).send();
     await tokenContract.methods.transfer(receiver, 1).send();
 
     const owner = await contract.methods.ownerOf(tokenId).call();
-
     expect(owner).to.equal('0xFFfFfFffFFfffFFfFFfFFFFFffFFFffffFfFFFfF');
   });
 });
 
 describe('Refungible: Plain calls', () => {
+  let donor: IKeyringPair;
+
   before(async function() {
-    await requirePallets(this, [Pallets.ReFungible]);
+    await usingEthPlaygrounds(async (helper, privateKey) => {
+      requirePalletsOrSkip(this, helper, [Pallets.ReFungible]);
+
+      donor = privateKey('//Alice');
+    });
   });
 
-  itWeb3('Can perform mint()', async ({web3, api, privateKeyWrapper}) => {
-    const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);
-    const helper = evmCollectionHelpers(web3, owner);
-    let result = await helper.methods.createRFTCollection('Mint collection', '6', '6').send();
-    const {collectionIdAddress} = await getCollectionAddressFromResult(api, result);
-    const receiver = createEthAccount(web3);
-    const contract = evmCollection(web3, owner, collectionIdAddress, {type: 'ReFungible'});
+  itEth('Can perform mint()', async ({helper}) => {
+    const owner = await helper.eth.createAccountWithBalance(donor);
+    const receiver = helper.eth.createAccount();
+    const {collectionAddress} = await helper.eth.createRefungibleCollection(owner, 'Minty', '6', '6');
+    const contract = helper.ethNativeContract.collection(collectionAddress, 'rft', owner);
+    
     const nextTokenId = await contract.methods.nextTokenId().call();
-
     expect(nextTokenId).to.be.equal('1');
-    result = await contract.methods.mintWithTokenURI(
+    const result = await contract.methods.mintWithTokenURI(
       receiver,
       nextTokenId,
       'Test URI',
     ).send();
 
-    const events = normalizeEvents(result.events);
-
-    expect(events).to.include.deep.members([
-      {
-        address: collectionIdAddress,
-        event: 'Transfer',
-        args: {
-          from: '0x0000000000000000000000000000000000000000',
-          to: receiver,
-          tokenId: nextTokenId,
-        },
-      },
-    ]);
+    const event = result.events.Transfer;
+    expect(event.address).to.equal(collectionAddress);
+    expect(event.returnValues.from).to.equal('0x0000000000000000000000000000000000000000');
+    expect(event.returnValues.to).to.equal(receiver);
+    expect(event.returnValues.tokenId).to.equal(nextTokenId);
 
     expect(await contract.methods.tokenURI(nextTokenId).call()).to.be.equal('Test URI');
   });
 
-  itWeb3('Can perform mintBulk()', async ({web3, api, privateKeyWrapper}) => {
-    const caller = await createEthAccountWithBalance(api, web3, privateKeyWrapper);
-    const helper = evmCollectionHelpers(web3, caller);
-    const result = await helper.methods.createRFTCollection('Mint collection', '6', '6').send();
-    const {collectionIdAddress} = await getCollectionAddressFromResult(api, result);
-    const contract = evmCollection(web3, caller, collectionIdAddress, {type: 'ReFungible'});
+  itEth('Can perform mintBulk()', async ({helper}) => {
+    const owner = await helper.eth.createAccountWithBalance(donor);
+    const receiver = helper.eth.createAccount();
+    const {collectionAddress} = await helper.eth.createRefungibleCollection(owner, 'MintBulky', '6', '6');
+    const contract = helper.ethNativeContract.collection(collectionAddress, 'rft', owner);
 
-    const receiver = createEthAccount(web3);
-
     {
       const nextTokenId = await contract.methods.nextTokenId().call();
       expect(nextTokenId).to.be.equal('1');
@@ -180,37 +161,15 @@
           [+nextTokenId + 2, 'Test URI 2'],
         ],
       ).send();
-      const events = normalizeEvents(result.events);
 
-      expect(events).to.include.deep.members([
-        {
-          address: collectionIdAddress,
-          event: 'Transfer',
-          args: {
-            from: '0x0000000000000000000000000000000000000000',
-            to: receiver,
-            tokenId: nextTokenId,
-          },
-        },
-        {
-          address: collectionIdAddress,
-          event: 'Transfer',
-          args: {
-            from: '0x0000000000000000000000000000000000000000',
-            to: receiver,
-            tokenId: String(+nextTokenId + 1),
-          },
-        },
-        {
-          address: collectionIdAddress,
-          event: 'Transfer',
-          args: {
-            from: '0x0000000000000000000000000000000000000000',
-            to: receiver,
-            tokenId: String(+nextTokenId + 2),
-          },
-        },
-      ]);
+      const events = result.events.Transfer;
+      for (let i = 0; i < 2; i++) {
+        const event = events[i];
+        expect(event.address).to.equal(collectionAddress);
+        expect(event.returnValues.from).to.equal('0x0000000000000000000000000000000000000000');
+        expect(event.returnValues.to).to.equal(receiver);
+        expect(event.returnValues.tokenId).to.equal(String(+nextTokenId + i));
+      }
 
       expect(await contract.methods.tokenURI(nextTokenId).call()).to.be.equal('Test URI 0');
       expect(await contract.methods.tokenURI(+nextTokenId + 1).call()).to.be.equal('Test URI 1');
@@ -218,76 +177,54 @@
     }
   });
 
-  itWeb3('Can perform burn()', async ({web3, api, privateKeyWrapper}) => {
-    const caller = await createEthAccountWithBalance(api, web3, privateKeyWrapper);
-    const helper = evmCollectionHelpers(web3, caller);
-    const result = await helper.methods.createRFTCollection('Mint collection', '6', '6').send();
-    const {collectionIdAddress} = await getCollectionAddressFromResult(api, result);
-    const contract = evmCollection(web3, caller, collectionIdAddress, {type: 'ReFungible'});
+  itEth('Can perform burn()', async ({helper}) => {
+    const caller = await helper.eth.createAccountWithBalance(donor);
+    const {collectionAddress} = await helper.eth.createRefungibleCollection(caller, 'Burny', '6', '6');
+    const contract = helper.ethNativeContract.collection(collectionAddress, 'rft', caller);
 
     const tokenId = await contract.methods.nextTokenId().call();
     await contract.methods.mint(caller, tokenId).send();
     {
       const result = await contract.methods.burn(tokenId).send();
-      const events = normalizeEvents(result.events);
-      expect(events).to.include.deep.members([
-        {
-          address: collectionIdAddress,
-          event: 'Transfer',
-          args: {
-            from: caller,
-            to: '0x0000000000000000000000000000000000000000',
-            tokenId: tokenId.toString(),
-          },
-        },
-      ]);
+      const event = result.events.Transfer;
+      expect(event.address).to.equal(collectionAddress);
+      expect(event.returnValues.from).to.equal(caller);
+      expect(event.returnValues.to).to.equal('0x0000000000000000000000000000000000000000');
+      expect(event.returnValues.tokenId).to.equal(tokenId.toString());
     }
   });
 
-  itWeb3('Can perform transferFrom()', async ({web3, api, privateKeyWrapper}) => {
-    const caller = await createEthAccountWithBalance(api, web3, privateKeyWrapper);
-    const helper = evmCollectionHelpers(web3, caller);
-    const result = await helper.methods.createRFTCollection('Mint collection', '6', '6').send();
-    const {collectionIdAddress, collectionId} = await getCollectionAddressFromResult(api, result);
-    const contract = evmCollection(web3, caller, collectionIdAddress, {type: 'ReFungible'});
-
-    const receiver = createEthAccount(web3);
+  itEth('Can perform transferFrom()', async ({helper}) => {
+    const caller = await helper.eth.createAccountWithBalance(donor);
+    const receiver = helper.eth.createAccount();
+    const {collectionId, collectionAddress} = await helper.eth.createRefungibleCollection(caller, 'TransferFromy', '6', '6');
+    const contract = helper.ethNativeContract.collection(collectionAddress, 'rft', caller);
 
     const tokenId = await contract.methods.nextTokenId().call();
+    const tokenAddress = helper.ethAddress.fromTokenId(collectionId, tokenId);
     await contract.methods.mint(caller, tokenId).send();
 
-    const address = tokenIdToAddress(collectionId, tokenId);
-    const tokenContract = uniqueRefungibleToken(web3, address, caller);
+    const tokenContract = helper.ethNativeContract.rftToken(tokenAddress, caller);
     await tokenContract.methods.repartition(15).send();
 
     {
-      const erc20Events = await recordEvents(tokenContract, async () => {
-        const result = await contract.methods.transferFrom(caller, receiver, tokenId).send();
-        const events = normalizeEvents(result.events);
-        expect(events).to.include.deep.members([
-          {
-            address: collectionIdAddress,
-            event: 'Transfer',
-            args: {
-              from: caller,
-              to: receiver,
-              tokenId: tokenId.toString(),
-            },
-          },
-        ]);
+      const tokenEvents: any = [];
+      tokenContract.events.allEvents((_: any, event: any) => {
+        tokenEvents.push(event);
       });
+      const result = await contract.methods.transferFrom(caller, receiver, tokenId).send();
+
+      let event = result.events.Transfer;
+      expect(event.address).to.equal(collectionAddress);
+      expect(event.returnValues.from).to.equal(caller);
+      expect(event.returnValues.to).to.equal(receiver);
+      expect(event.returnValues.tokenId).to.equal(tokenId.toString());
 
-      expect(erc20Events).to.include.deep.members([
-        {
-          address,
-          event: 'Transfer',
-          args: {
-            from: caller,
-            to: receiver,
-            value: '15',
-          },
-        },
-      ]);
+      event = tokenEvents[0];
+      expect(event.address).to.equal(tokenAddress);
+      expect(event.returnValues.from).to.equal(caller);
+      expect(event.returnValues.to).to.equal(receiver);
+      expect(event.returnValues.value).to.equal('15');
     }
 
     {
@@ -301,32 +238,23 @@
     }
   });
 
-  itWeb3('Can perform transfer()', async ({web3, api, privateKeyWrapper}) => {
-    const caller = await createEthAccountWithBalance(api, web3, privateKeyWrapper);
-    const helper = evmCollectionHelpers(web3, caller);
-    const result = await helper.methods.createRFTCollection('Mint collection', '6', '6').send();
-    const {collectionIdAddress} = await getCollectionAddressFromResult(api, result);
-    const contract = evmCollection(web3, caller, collectionIdAddress, {type: 'ReFungible'});
-
-    const receiver = createEthAccount(web3);
+  itEth('Can perform transfer()', async ({helper}) => {
+    const caller = await helper.eth.createAccountWithBalance(donor);
+    const receiver = helper.eth.createAccount();
+    const {collectionAddress} = await helper.eth.createRefungibleCollection(caller, 'Transferry', '6', '6');
+    const contract = helper.ethNativeContract.collection(collectionAddress, 'rft', caller);
 
     const tokenId = await contract.methods.nextTokenId().call();
     await contract.methods.mint(caller, tokenId).send();
 
     {
       const result = await contract.methods.transfer(receiver, tokenId).send();
-      const events = normalizeEvents(result.events);
-      expect(events).to.include.deep.members([
-        {
-          address: collectionIdAddress,
-          event: 'Transfer',
-          args: {
-            from: caller,
-            to: receiver,
-            tokenId: tokenId.toString(),
-          },
-        },
-      ]);
+      
+      const event = result.events.Transfer;
+      expect(event.address).to.equal(collectionAddress);
+      expect(event.returnValues.from).to.equal(caller);
+      expect(event.returnValues.to).to.equal(receiver);
+      expect(event.returnValues.tokenId).to.equal(tokenId.toString());
     }
 
     {
@@ -340,141 +268,127 @@
     }
   });
 
-  itWeb3('transfer event on transfer from partial ownership to full ownership', async ({api, web3, privateKeyWrapper}) => {
-    const caller = await createEthAccountWithBalance(api, web3, privateKeyWrapper);
-    const receiver = createEthAccount(web3);
-    const helper = evmCollectionHelpers(web3, caller);
-    const result = await helper.methods.createRFTCollection('Mint collection', '6', '6').send();
-    const {collectionIdAddress, collectionId} = await getCollectionAddressFromResult(api, result);
-    const contract = evmCollection(web3, caller, collectionIdAddress, {type: 'ReFungible'});
+  itEth('transfer event on transfer from partial ownership to full ownership', async ({helper}) => {
+    const caller = await helper.eth.createAccountWithBalance(donor);
+    const receiver = helper.eth.createAccount();
+    const {collectionId, collectionAddress} = await helper.eth.createRefungibleCollection(caller, 'Transferry-Partial-to-Full', '6', '6');
+    const contract = helper.ethNativeContract.collection(collectionAddress, 'rft', caller);
 
     const tokenId = await contract.methods.nextTokenId().call();
     await contract.methods.mint(caller, tokenId).send();
 
-    const tokenAddress = tokenIdToAddress(collectionId, tokenId);
-    const tokenContract = uniqueRefungibleToken(web3, tokenAddress, caller);
+    const tokenContract = helper.ethNativeContract.rftTokenById(collectionId, tokenId, caller);
 
     await tokenContract.methods.repartition(2).send();
     await tokenContract.methods.transfer(receiver, 1).send();
 
-    const events =  await recordEvents(contract, async () =>
-      await tokenContract.methods.transfer(receiver, 1).send());
-    expect(events).to.deep.equal([
-      {
-        address: collectionIdAddress,
-        event: 'Transfer',
-        args: {
-          from: '0xFFfFfFffFFfffFFfFFfFFFFFffFFFffffFfFFFfF',
-          to: receiver,
-          tokenId: tokenId.toString(),
-        },
-      },
-    ]);
+    const events: any = [];
+    contract.events.allEvents((_: any, event: any) => {
+      events.push(event);
+    });
+    await tokenContract.methods.transfer(receiver, 1).send();
+
+    const event = events[0];
+    expect(event.address).to.equal(collectionAddress);
+    expect(event.returnValues.from).to.equal('0xFFfFfFffFFfffFFfFFfFFFFFffFFFffffFfFFFfF');
+    expect(event.returnValues.to).to.equal(receiver);
+    expect(event.returnValues.tokenId).to.equal(tokenId.toString());
   });
 
-  itWeb3('transfer event on transfer from full ownership to partial ownership', async ({api, web3, privateKeyWrapper}) => {
-    const caller = await createEthAccountWithBalance(api, web3, privateKeyWrapper);
-    const receiver = createEthAccount(web3);
-    const helper = evmCollectionHelpers(web3, caller);
-    const result = await helper.methods.createRFTCollection('Mint collection', '6', '6').send();
-    const {collectionIdAddress, collectionId} = await getCollectionAddressFromResult(api, result);
-    const contract = evmCollection(web3, caller, collectionIdAddress, {type: 'ReFungible'});
+  itEth('transfer event on transfer from full ownership to partial ownership', async ({helper}) => {
+    const caller = await helper.eth.createAccountWithBalance(donor);
+    const receiver = helper.eth.createAccount();
+    const {collectionId, collectionAddress} = await helper.eth.createRefungibleCollection(caller, 'Transferry-Full-to-Partial', '6', '6');
+    const contract = helper.ethNativeContract.collection(collectionAddress, 'rft', caller);
 
     const tokenId = await contract.methods.nextTokenId().call();
     await contract.methods.mint(caller, tokenId).send();
 
-    const tokenAddress = tokenIdToAddress(collectionId, tokenId);
-    const tokenContract = uniqueRefungibleToken(web3, tokenAddress, caller);
+    const tokenContract = helper.ethNativeContract.rftTokenById(collectionId, tokenId, caller);
 
     await tokenContract.methods.repartition(2).send();
 
-    const events =  await recordEvents(contract, async () =>
-      await tokenContract.methods.transfer(receiver, 1).send());
+    const events: any = [];
+    contract.events.allEvents((_: any, event: any) => {
+      events.push(event);
+    });
+    await tokenContract.methods.transfer(receiver, 1).send();
 
-    expect(events).to.deep.equal([
-      {
-        address: collectionIdAddress,
-        event: 'Transfer',
-        args: {
-          from: caller,
-          to: '0xFFfFfFffFFfffFFfFFfFFFFFffFFFffffFfFFFfF',
-          tokenId: tokenId.toString(),
-        },
-      },
-    ]);
+    const event = events[0];
+    expect(event.address).to.equal(collectionAddress);
+    expect(event.returnValues.from).to.equal(caller);
+    expect(event.returnValues.to).to.equal('0xFFfFfFffFFfffFFfFFfFFFFFffFFFffffFfFFFfF');
+    expect(event.returnValues.tokenId).to.equal(tokenId.toString());
   });
 });
 
 describe('RFT: Fees', () => {
+  let donor: IKeyringPair;
+
   before(async function() {
-    await requirePallets(this, [Pallets.ReFungible]);
+    await usingEthPlaygrounds(async (helper, privateKey) => {
+      requirePalletsOrSkip(this, helper, [Pallets.ReFungible]);
+
+      donor = privateKey('//Alice');
+    });
   });
 
-  itWeb3('transferFrom() call fee is less than 0.2UNQ', async ({web3, api, privateKeyWrapper}) => {
-    const caller = await createEthAccountWithBalance(api, web3, privateKeyWrapper);
-    const helper = evmCollectionHelpers(web3, caller);
-    const result = await helper.methods.createRFTCollection('Mint collection', '6', '6').send();
-    const {collectionIdAddress} = await getCollectionAddressFromResult(api, result);
-    const contract = evmCollection(web3, caller, collectionIdAddress, {type: 'ReFungible'});
-
-    const receiver = createEthAccount(web3);
+  itEth('transferFrom() call fee is less than 0.2UNQ', async ({helper}) => {
+    const caller = await helper.eth.createAccountWithBalance(donor);
+    const receiver = helper.eth.createAccount();
+    const {collectionAddress} = await helper.eth.createRefungibleCollection(caller, 'Feeful-Transfer-From', '6', '6');
+    const contract = helper.ethNativeContract.collection(collectionAddress, 'rft', caller);
 
     const tokenId = await contract.methods.nextTokenId().call();
     await contract.methods.mint(caller, tokenId).send();
 
-    const cost = await recordEthFee(api, caller, () => contract.methods.transferFrom(caller, receiver, tokenId).send());
-    expect(cost < BigInt(0.2 * Number(UNIQUE)));
+    const cost = await helper.eth.recordCallFee(caller, () => contract.methods.transferFrom(caller, receiver, tokenId).send());
+    expect(cost < BigInt(0.2 * Number(helper.balance.getOneTokenNominal())));
     expect(cost > 0n);
   });
 
-  itWeb3('transfer() call fee is less than 0.2UNQ', async ({web3, api, privateKeyWrapper}) => {
-    const caller = await createEthAccountWithBalance(api, web3, privateKeyWrapper);
-    const helper = evmCollectionHelpers(web3, caller);
-    const result = await helper.methods.createRFTCollection('Mint collection', '6', '6').send();
-    const {collectionIdAddress} = await getCollectionAddressFromResult(api, result);
-    const contract = evmCollection(web3, caller, collectionIdAddress, {type: 'ReFungible'});
-
-    const receiver = createEthAccount(web3);
+  itEth('transfer() call fee is less than 0.2UNQ', async ({helper}) => {
+    const caller = await helper.eth.createAccountWithBalance(donor);
+    const receiver = helper.eth.createAccount();
+    const {collectionAddress} = await helper.eth.createRefungibleCollection(caller, 'Feeful-Transfer', '6', '6');
+    const contract = helper.ethNativeContract.collection(collectionAddress, 'rft', caller);
 
     const tokenId = await contract.methods.nextTokenId().call();
     await contract.methods.mint(caller, tokenId).send();
 
-    const cost = await recordEthFee(api, caller, () => contract.methods.transfer(receiver, tokenId).send());
-    expect(cost < BigInt(0.2 * Number(UNIQUE)));
+    const cost = await helper.eth.recordCallFee(caller, () => contract.methods.transfer(receiver, tokenId).send());
+    expect(cost < BigInt(0.2 * Number(helper.balance.getOneTokenNominal())));
     expect(cost > 0n);
   });
 });
 
 describe('Common metadata', () => {
+  let donor: IKeyringPair;
+  let alice: IKeyringPair;
+
   before(async function() {
-    await requirePallets(this, [Pallets.ReFungible]);
-  });
+    await usingEthPlaygrounds(async (helper, privateKey) => {
+      requirePalletsOrSkip(this, helper, [Pallets.ReFungible]);
 
-  itWeb3('Returns collection name', async ({api, web3, privateKeyWrapper}) => {
-    const collection = await createCollectionExpectSuccess({
-      name: 'token name',
-      mode: {type: 'ReFungible'},
+      donor = privateKey('//Alice');
+      [alice] = await helper.arrange.createAccounts([20n], donor);
     });
-    const caller = await createEthAccountWithBalance(api, web3, privateKeyWrapper);
+  });
 
-    const address = collectionIdToAddress(collection);
-    const contract = evmCollection(web3, caller, address, {type: 'ReFungible'});
+  itEth('Returns collection name', async ({helper}) => {
+    const caller = helper.eth.createAccount();
+    const collection = await helper.rft.mintCollection(alice, {name: 'Leviathan', tokenPrefix: '11'});
+    
+    const contract = helper.ethNativeContract.collectionById(collection.collectionId, 'rft', caller);
     const name = await contract.methods.name().call();
-
-    expect(name).to.equal('token name');
+    expect(name).to.equal('Leviathan');
   });
 
-  itWeb3('Returns symbol name', async ({api, web3, privateKeyWrapper}) => {
-    const collection = await createCollectionExpectSuccess({
-      tokenPrefix: 'TOK',
-      mode: {type: 'ReFungible'},
-    });
-    const caller = await createEthAccountWithBalance(api, web3, privateKeyWrapper);
-
-    const address = collectionIdToAddress(collection);
-    const contract = evmCollection(web3, caller, address, {type: 'ReFungible'});
+  itEth('Returns symbol name', async ({helper}) => {
+    const caller = await helper.eth.createAccountWithBalance(donor);
+    const {collectionAddress} = await helper.eth.createRefungibleCollection(caller, 'Leviathan', '', '12');
+    const contract = helper.ethNativeContract.collection(collectionAddress, 'rft', caller);
     const symbol = await contract.methods.symbol().call();
-
-    expect(symbol).to.equal('TOK');
+    expect(symbol).to.equal('12');
   });
 });
modifiedtests/src/eth/reFungibleToken.test.tsdiffbeforeafterboth
--- a/tests/src/eth/reFungibleToken.test.ts
+++ b/tests/src/eth/reFungibleToken.test.ts
@@ -14,82 +14,76 @@
 // You should have received a copy of the GNU General Public License
 // along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
 
-import {approve, createCollection, createRefungibleToken, transfer, transferFrom, UNIQUE, requirePallets, Pallets} from '../util/helpers';
-import {collectionIdToAddress, createEthAccount, createEthAccountWithBalance, createRFTCollection, evmCollection, evmCollectionHelpers, getCollectionAddressFromResult, itWeb3, normalizeEvents, recordEthFee, recordEvents, subToEth, tokenIdToAddress, transferBalanceToEth, uniqueRefungible, uniqueRefungibleToken} from './util/helpers';
+import {Pallets, requirePalletsOrSkip} from '../util/playgrounds';
+import {EthUniqueHelper, expect, itEth, usingEthPlaygrounds} from './util/playgrounds';
+import {IKeyringPair} from '@polkadot/types/types';
+import {Contract} from 'web3-eth-contract';
 
-import chai from 'chai';
-import chaiAsPromised from 'chai-as-promised';
-chai.use(chaiAsPromised);
-const expect = chai.expect;
+describe('Refungible token: Information getting', () => {
+  let donor: IKeyringPair;
+  let alice: IKeyringPair;
 
-describe('Refungible token: Information getting', () => {
   before(async function() {
-    await requirePallets(this, [Pallets.ReFungible]);
-  });
+    await usingEthPlaygrounds(async (helper, privateKey) => {
+      requirePalletsOrSkip(this, helper, [Pallets.ReFungible]);
 
-  itWeb3('totalSupply', async ({api, web3, privateKeyWrapper}) => {
-    const alice = privateKeyWrapper('//Alice');
-
-    const collectionId = (await createCollection(api, alice, {name: 'token name', mode: {type: 'ReFungible'}})).collectionId;
-
-    const caller = await createEthAccountWithBalance(api, web3, privateKeyWrapper);
+      donor = privateKey('//Alice');
+      [alice] = await helper.arrange.createAccounts([20n], donor);
+    });
+  });
 
-    const tokenId = (await createRefungibleToken(api, alice, collectionId, 200n, {Ethereum: caller})).itemId;
+  itEth('totalSupply', async ({helper}) => {
+    const caller = await helper.eth.createAccountWithBalance(donor);
+    const collection = await helper.rft.mintCollection(alice, {tokenPrefix: 'MUON'});
+    const {tokenId} = await collection.mintToken(alice, 200n, {Ethereum: caller});
 
-    const address = tokenIdToAddress(collectionId, tokenId);
-    const contract = uniqueRefungibleToken(web3, address, caller);
+    const contract = helper.ethNativeContract.rftTokenById(collection.collectionId, tokenId, caller);
     const totalSupply = await contract.methods.totalSupply().call();
-
     expect(totalSupply).to.equal('200');
   });
 
-  itWeb3('balanceOf', async ({api, web3, privateKeyWrapper}) => {
-    const alice = privateKeyWrapper('//Alice');
-
-    const collectionId = (await createCollection(api, alice, {name: 'token name', mode: {type: 'ReFungible'}})).collectionId;
+  itEth('balanceOf', async ({helper}) => {
+    const caller = await helper.eth.createAccountWithBalance(donor);
+    const collection = await helper.rft.mintCollection(alice, {tokenPrefix: 'MUON'});
+    const {tokenId} = await collection.mintToken(alice, 200n, {Ethereum: caller});
 
-    const caller = await createEthAccountWithBalance(api, web3, privateKeyWrapper);
-
-    const tokenId = (await createRefungibleToken(api, alice, collectionId, 200n, {Ethereum: caller})).itemId;
-
-    const address = tokenIdToAddress(collectionId, tokenId);
-    const contract = uniqueRefungibleToken(web3, address, caller);
+    const contract = helper.ethNativeContract.rftTokenById(collection.collectionId, tokenId, caller);
     const balance = await contract.methods.balanceOf(caller).call();
-
     expect(balance).to.equal('200');
   });
 
-  itWeb3('decimals', async ({api, web3, privateKeyWrapper}) => {
-    const alice = privateKeyWrapper('//Alice');
+  itEth('decimals', async ({helper}) => {
+    const caller = await helper.eth.createAccountWithBalance(donor);
+    const collection = await helper.rft.mintCollection(alice, {tokenPrefix: 'MUON'});
+    const {tokenId} = await collection.mintToken(alice, 200n, {Ethereum: caller});
 
-    const collectionId = (await createCollection(api, alice, {name: 'token name', mode: {type: 'ReFungible'}})).collectionId;
-
-    const caller = await createEthAccountWithBalance(api, web3, privateKeyWrapper);
-
-    const tokenId = (await createRefungibleToken(api, alice, collectionId, 200n, {Ethereum: caller})).itemId;
-
-    const address = tokenIdToAddress(collectionId, tokenId);
-    const contract = uniqueRefungibleToken(web3, address, caller);
+    const contract = helper.ethNativeContract.rftTokenById(collection.collectionId, tokenId, caller);
     const decimals = await contract.methods.decimals().call();
-
     expect(decimals).to.equal('0');
   });
 });
 
 // FIXME: Need erc721 for ReFubgible.
 describe('Check ERC721 token URI for ReFungible', () => {
+  let donor: IKeyringPair;
+
   before(async function() {
-    await requirePallets(this, [Pallets.ReFungible]);
+    await usingEthPlaygrounds(async (helper, privateKey) => {
+      requirePalletsOrSkip(this, helper, [Pallets.ReFungible]);
+
+      donor = privateKey('//Alice');
+    });
   });
 
-  itWeb3('Empty tokenURI', async ({web3, api, privateKeyWrapper}) => {
-    const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);
-    const helper = evmCollectionHelpers(web3, owner);
-    let result = await helper.methods.createERC721MetadataCompatibleCollection('Mint collection', '1', '1', '').send();
-    const {collectionIdAddress, collectionId} = await getCollectionAddressFromResult(api, result);
-    const receiver = createEthAccount(web3);
-    const contract = evmCollection(web3, owner, collectionIdAddress, {type: 'ReFungible'});
+  async function setup(helper: EthUniqueHelper, tokenPrefix: string, propertyKey?: string, propertyValue?: string): Promise<{contract: Contract, nextTokenId: string}> {
+    const owner = await helper.eth.createAccountWithBalance(donor);
+    const receiver = helper.eth.createAccount();
 
+    const collectionHelper = helper.ethNativeContract.collectionHelpers(owner);
+    let result = await collectionHelper.methods.createERC721MetadataCompatibleCollection('Mint collection', 'a', 'b', tokenPrefix).send();
+    const collectionAddress = helper.ethAddress.normalizeAddress(result.events.CollectionCreated.returnValues.collectionId);
+    const contract = helper.ethNativeContract.collection(collectionAddress, 'rft', owner);
+    
     const nextTokenId = await contract.methods.nextTokenId().call();
     expect(nextTokenId).to.be.equal('1');
     result = await contract.methods.mint(
@@ -97,166 +91,71 @@
       nextTokenId,
     ).send();
 
-    const events = normalizeEvents(result.events);
-    const address = collectionIdToAddress(collectionId);
+    if (propertyKey && propertyValue) {
+      // Set URL or suffix
+      await contract.methods.setProperty(nextTokenId, propertyKey, Buffer.from(propertyValue)).send();
+    }
+
+    const event = result.events.Transfer;
+    expect(event.address).to.be.equal(collectionAddress);
+    expect(event.returnValues.from).to.be.equal('0x0000000000000000000000000000000000000000');
+    expect(event.returnValues.to).to.be.equal(receiver);
+    expect(event.returnValues.tokenId).to.be.equal(nextTokenId);
 
-    expect(events).to.be.deep.equal([
-      {
-        address,
-        event: 'Transfer',
-        args: {
-          from: '0x0000000000000000000000000000000000000000',
-          to: receiver,
-          tokenId: nextTokenId,
-        },
-      },
-    ]);
+    return {contract, nextTokenId};
+  }
 
+  itEth('Empty tokenURI', async ({helper}) => {
+    const {contract, nextTokenId} = await setup(helper, '');
     expect(await contract.methods.tokenURI(nextTokenId).call()).to.be.equal('');
   });
-
-  itWeb3('TokenURI from url', async ({web3, api, privateKeyWrapper}) => {
-    const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);
-    const helper = evmCollectionHelpers(web3, owner);
-    let result = await helper.methods.createERC721MetadataCompatibleCollection('Mint collection', '1', '1', 'BaseURI_').send();
-    const {collectionIdAddress, collectionId} = await getCollectionAddressFromResult(api, result);
-    const receiver = createEthAccount(web3);
-    const contract = evmCollection(web3, owner, collectionIdAddress, {type: 'ReFungible'});
 
-    const nextTokenId = await contract.methods.nextTokenId().call();
-    expect(nextTokenId).to.be.equal('1');
-    result = await contract.methods.mint(
-      receiver,
-      nextTokenId,
-    ).send();
-
-    // Set URL
-    await contract.methods.setProperty(nextTokenId, 'url', Buffer.from('Token URI')).send();
-
-    const events = normalizeEvents(result.events);
-    const address = collectionIdToAddress(collectionId);
-
-    expect(events).to.be.deep.equal([
-      {
-        address,
-        event: 'Transfer',
-        args: {
-          from: '0x0000000000000000000000000000000000000000',
-          to: receiver,
-          tokenId: nextTokenId,
-        },
-      },
-    ]);
-
+  itEth('TokenURI from url', async ({helper}) => {
+    const {contract, nextTokenId} = await setup(helper, 'BaseURI_', 'url', 'Token URI');
     expect(await contract.methods.tokenURI(nextTokenId).call()).to.be.equal('Token URI');
   });
-
-  itWeb3('TokenURI from baseURI + tokenId', async ({web3, api, privateKeyWrapper}) => {
-    const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);
-    const helper = evmCollectionHelpers(web3, owner);
-    let result = await helper.methods.createERC721MetadataCompatibleCollection('Mint collection', '1', '1', 'BaseURI_').send();
-    const {collectionIdAddress, collectionId} = await getCollectionAddressFromResult(api, result);
-    const receiver = createEthAccount(web3);
-    const contract = evmCollection(web3, owner, collectionIdAddress, {type: 'ReFungible'});
 
-    const nextTokenId = await contract.methods.nextTokenId().call();
-    expect(nextTokenId).to.be.equal('1');
-    result = await contract.methods.mint(
-      receiver,
-      nextTokenId,
-    ).send();
-
-    const events = normalizeEvents(result.events);
-    const address = collectionIdToAddress(collectionId);
-
-    expect(events).to.be.deep.equal([
-      {
-        address,
-        event: 'Transfer',
-        args: {
-          from: '0x0000000000000000000000000000000000000000',
-          to: receiver,
-          tokenId: nextTokenId,
-        },
-      },
-    ]);
-
+  itEth('TokenURI from baseURI + tokenId', async ({helper}) => {
+    const {contract, nextTokenId} = await setup(helper, 'BaseURI_');
     expect(await contract.methods.tokenURI(nextTokenId).call()).to.be.equal('BaseURI_' + nextTokenId);
   });
 
-  itWeb3('TokenURI from baseURI + suffix', async ({web3, api, privateKeyWrapper}) => {
-    const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);
-    const helper = evmCollectionHelpers(web3, owner);
-    let result = await helper.methods.createERC721MetadataCompatibleCollection('Mint collection', '1', '1', 'BaseURI_').send();
-    const {collectionIdAddress, collectionId} = await getCollectionAddressFromResult(api, result);
-    const receiver = createEthAccount(web3);
-    const contract = evmCollection(web3, owner, collectionIdAddress, {type: 'ReFungible'});
-
-    const nextTokenId = await contract.methods.nextTokenId().call();
-    expect(nextTokenId).to.be.equal('1');
-    result = await contract.methods.mint(
-      receiver,
-      nextTokenId,
-    ).send();
-
-    // Set suffix
+  itEth('TokenURI from baseURI + suffix', async ({helper}) => {
     const suffix = '/some/suffix';
-    await contract.methods.setProperty(nextTokenId, 'suffix', Buffer.from(suffix)).send();
-
-    const events = normalizeEvents(result.events);
-    const address = collectionIdToAddress(collectionId);
-
-    expect(events).to.be.deep.equal([
-      {
-        address,
-        event: 'Transfer',
-        args: {
-          from: '0x0000000000000000000000000000000000000000',
-          to: receiver,
-          tokenId: nextTokenId,
-        },
-      },
-    ]);
-
+    const {contract, nextTokenId} = await setup(helper, 'BaseURI_', 'suffix', suffix);
     expect(await contract.methods.tokenURI(nextTokenId).call()).to.be.equal('BaseURI_' + suffix);
   });
 });
 
 describe('Refungible: Plain calls', () => {
+  let donor: IKeyringPair;
+  let alice: IKeyringPair;
+
   before(async function() {
-    await requirePallets(this, [Pallets.ReFungible]);
+    await usingEthPlaygrounds(async (helper, privateKey) => {
+      requirePalletsOrSkip(this, helper, [Pallets.ReFungible]);
+
+      donor = privateKey('//Alice');
+      [alice] = await helper.arrange.createAccounts([50n], donor);
+    });
   });
 
-  itWeb3('Can perform approve()', async ({web3, api, privateKeyWrapper}) => {
-    const alice = privateKeyWrapper('//Alice');
+  itEth('Can perform approve()', async ({helper}) => {
+    const owner = await helper.eth.createAccountWithBalance(donor);
+    const spender = helper.eth.createAccount();
+    const collection = await helper.rft.mintCollection(alice);
+    const {tokenId} = await collection.mintToken(alice, 200n, {Ethereum: owner});
 
-    const collectionId = (await createCollection(api, alice, {name: 'token name', mode: {type: 'ReFungible'}})).collectionId;
-
-    const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);
-
-    const tokenId = (await createRefungibleToken(api, alice, collectionId, 200n, {Ethereum: owner})).itemId;
-
-    const address = tokenIdToAddress(collectionId, tokenId);
+    const tokenAddress = helper.ethAddress.fromTokenId(collection.collectionId, tokenId);
+    const contract = helper.ethNativeContract.rftToken(tokenAddress, owner);
 
-    const spender = createEthAccount(web3);
-
-    const contract = uniqueRefungibleToken(web3, address, owner);
-
     {
       const result = await contract.methods.approve(spender, 100).send({from: owner});
-      const events = normalizeEvents(result.events);
-
-      expect(events).to.be.deep.equal([
-        {
-          address,
-          event: 'Approval',
-          args: {
-            owner,
-            spender,
-            value: '100',
-          },
-        },
-      ]);
+      const event = result.events.Approval;
+      expect(event.address).to.be.equal(tokenAddress);
+      expect(event.returnValues.owner).to.be.equal(owner);
+      expect(event.returnValues.spender).to.be.equal(spender);
+      expect(event.returnValues.value).to.be.equal('100');
     }
 
     {
@@ -265,49 +164,31 @@
     }
   });
 
-  itWeb3('Can perform transferFrom()', async ({web3, api, privateKeyWrapper}) => {
-    const alice = privateKeyWrapper('//Alice');
-
-    const collectionId = (await createCollection(api, alice, {name: 'token name', mode: {type: 'ReFungible'}})).collectionId;
+  itEth('Can perform transferFrom()', async ({helper}) => {
+    const owner = await helper.eth.createAccountWithBalance(donor);
+    const spender = await helper.eth.createAccountWithBalance(donor);
+    const receiver = helper.eth.createAccount();
+    const collection = await helper.rft.mintCollection(alice);
+    const {tokenId} = await collection.mintToken(alice, 200n, {Ethereum: owner});
 
-    const owner = createEthAccount(web3);
-    await transferBalanceToEth(api, alice, owner);
-
-    const tokenId = (await createRefungibleToken(api, alice, collectionId, 200n, {Ethereum: owner})).itemId;
-
-    const spender = createEthAccount(web3);
-    await transferBalanceToEth(api, alice, spender);
+    const tokenAddress = helper.ethAddress.fromTokenId(collection.collectionId, tokenId);
+    const contract = helper.ethNativeContract.rftToken(tokenAddress, owner);
 
-    const receiver = createEthAccount(web3);
-
-    const address = tokenIdToAddress(collectionId, tokenId);
-    const contract = uniqueRefungibleToken(web3, address, owner);
-
     await contract.methods.approve(spender, 100).send();
 
     {
       const result = await contract.methods.transferFrom(owner, receiver, 49).send({from: spender});
-      const events = normalizeEvents(result.events);
-      expect(events).to.include.deep.members([
-        {
-          address,
-          event: 'Transfer',
-          args: {
-            from: owner,
-            to: receiver,
-            value: '49',
-          },
-        },
-        {
-          address,
-          event: 'Approval',
-          args: {
-            owner,
-            spender,
-            value: '51',
-          },
-        },
-      ]);
+      let event = result.events.Transfer;
+      expect(event.address).to.be.equal(tokenAddress);
+      expect(event.returnValues.from).to.be.equal(owner);
+      expect(event.returnValues.to).to.be.equal(receiver);
+      expect(event.returnValues.value).to.be.equal('49');
+
+      event = result.events.Approval;
+      expect(event.address).to.be.equal(tokenAddress);
+      expect(event.returnValues.owner).to.be.equal(owner);
+      expect(event.returnValues.spender).to.be.equal(spender);
+      expect(event.returnValues.value).to.be.equal('51');
     }
 
     {
@@ -321,36 +202,22 @@
     }
   });
 
-  itWeb3('Can perform transfer()', async ({web3, api, privateKeyWrapper}) => {
-    const alice = privateKeyWrapper('//Alice');
+  itEth('Can perform transfer()', async ({helper}) => {
+    const owner = await helper.eth.createAccountWithBalance(donor);
+    const receiver = helper.eth.createAccount();
+    const collection = await helper.rft.mintCollection(alice);
+    const {tokenId} = await collection.mintToken(alice, 200n, {Ethereum: owner});
 
-    const collectionId = (await createCollection(api, alice, {name: 'token name', mode: {type: 'ReFungible'}})).collectionId;
-
-    const owner = createEthAccount(web3);
-    await transferBalanceToEth(api, alice, owner);
-
-    const tokenId = (await createRefungibleToken(api, alice, collectionId, 200n, {Ethereum: owner})).itemId;
-
-    const receiver = createEthAccount(web3);
-    await transferBalanceToEth(api, alice, receiver);
-
-    const address = tokenIdToAddress(collectionId, tokenId);
-    const contract = uniqueRefungibleToken(web3, address, owner);
+    const tokenAddress = helper.ethAddress.fromTokenId(collection.collectionId, tokenId);
+    const contract = helper.ethNativeContract.rftToken(tokenAddress, owner);
 
     {
       const result = await contract.methods.transfer(receiver, 50).send({from: owner});
-      const events = normalizeEvents(result.events);
-      expect(events).to.include.deep.members([
-        {
-          address,
-          event: 'Transfer',
-          args: {
-            from: owner,
-            to: receiver,
-            value: '50',
-          },
-        },
-      ]);
+      const event = result.events.Transfer;
+      expect(event.address).to.be.equal(tokenAddress);
+      expect(event.returnValues.from).to.be.equal(owner);
+      expect(event.returnValues.to).to.be.equal(receiver);
+      expect(event.returnValues.value).to.be.equal('50');
     }
 
     {
@@ -364,311 +231,262 @@
     }
   });
 
-  itWeb3('Can perform repartition()', async ({web3, api, privateKeyWrapper}) => {
-    const alice = privateKeyWrapper('//Alice');
-
-    const collectionId = (await createCollection(api, alice, {name: 'token name', mode: {type: 'ReFungible'}})).collectionId;
+  itEth('Can perform repartition()', async ({helper}) => {
+    const owner = await helper.eth.createAccountWithBalance(donor);
+    const receiver = await helper.eth.createAccountWithBalance(donor);
+    const collection = await helper.rft.mintCollection(alice);
+    const {tokenId} = await collection.mintToken(alice, 100n, {Ethereum: owner});
 
-    const owner = createEthAccount(web3);
-    await transferBalanceToEth(api, alice, owner);
+    const tokenAddress = helper.ethAddress.fromTokenId(collection.collectionId, tokenId);
+    const contract = helper.ethNativeContract.rftToken(tokenAddress, owner);
 
-    const receiver = createEthAccount(web3);
-    await transferBalanceToEth(api, alice, receiver);
-
-    const tokenId = (await createRefungibleToken(api, alice, collectionId, 100n, {Ethereum: owner})).itemId;
-
-    const address = tokenIdToAddress(collectionId, tokenId);
-    const contract = uniqueRefungibleToken(web3, address, owner);
-
     await contract.methods.repartition(200).send({from: owner});
     expect(+await contract.methods.balanceOf(owner).call()).to.be.equal(200);
     await contract.methods.transfer(receiver, 110).send({from: owner});
     expect(+await contract.methods.balanceOf(owner).call()).to.be.equal(90);
     expect(+await contract.methods.balanceOf(receiver).call()).to.be.equal(110);
 
-    await expect(contract.methods.repartition(80).send({from: owner})).to.eventually.be.rejected;
+    await expect(contract.methods.repartition(80).send({from: owner})).to.eventually.be.rejected; // Transaction is reverted
 
     await contract.methods.transfer(receiver, 90).send({from: owner});
     expect(+await contract.methods.balanceOf(owner).call()).to.be.equal(0);
     expect(+await contract.methods.balanceOf(receiver).call()).to.be.equal(200);
 
     await contract.methods.repartition(150).send({from: receiver});
-    await expect(contract.methods.transfer(owner, 160).send({from: receiver})).to.eventually.be.rejected;
+    await expect(contract.methods.transfer(owner, 160).send({from: receiver})).to.eventually.be.rejected; // Transaction is reverted
     expect(+await contract.methods.balanceOf(receiver).call()).to.be.equal(150);
   });
 
-  itWeb3('Can repartition with increased amount', async ({web3, api, privateKeyWrapper}) => {
-    const alice = privateKeyWrapper('//Alice');
-
-    const collectionId = (await createCollection(api, alice, {name: 'token name', mode: {type: 'ReFungible'}})).collectionId;
-
-    const owner = createEthAccount(web3);
-    await transferBalanceToEth(api, alice, owner);
-
-    const tokenId = (await createRefungibleToken(api, alice, collectionId, 100n, {Ethereum: owner})).itemId;
+  itEth('Can repartition with increased amount', async ({helper}) => {
+    const owner = await helper.eth.createAccountWithBalance(donor);
+    const collection = await helper.rft.mintCollection(alice);
+    const {tokenId} = await collection.mintToken(alice, 100n, {Ethereum: owner});
 
-    const address = tokenIdToAddress(collectionId, tokenId);
-    const contract = uniqueRefungibleToken(web3, address, owner);
+    const tokenAddress = helper.ethAddress.fromTokenId(collection.collectionId, tokenId);
+    const contract = helper.ethNativeContract.rftToken(tokenAddress, owner);
 
     const result = await contract.methods.repartition(200).send();
-    const events = normalizeEvents(result.events);
 
-    expect(events).to.deep.equal([
-      {
-        address,
-        event: 'Transfer',
-        args: {
-          from: '0x0000000000000000000000000000000000000000',
-          to: owner,
-          value: '100',
-        },
-      },
-    ]);
+    const event = result.events.Transfer;
+    expect(event.address).to.be.equal(tokenAddress);
+    expect(event.returnValues.from).to.be.equal('0x0000000000000000000000000000000000000000');
+    expect(event.returnValues.to).to.be.equal(owner);
+    expect(event.returnValues.value).to.be.equal('100');
   });
 
-  itWeb3('Can repartition with decreased amount', async ({web3, api, privateKeyWrapper}) => {
-    const alice = privateKeyWrapper('//Alice');
+  itEth('Can repartition with decreased amount', async ({helper}) => {
+    const owner = await helper.eth.createAccountWithBalance(donor);
+    const collection = await helper.rft.mintCollection(alice);
+    const {tokenId} = await collection.mintToken(alice, 100n, {Ethereum: owner});
 
-    const collectionId = (await createCollection(api, alice, {name: 'token name', mode: {type: 'ReFungible'}})).collectionId;
-
-    const owner = createEthAccount(web3);
-    await transferBalanceToEth(api, alice, owner);
-
-    const tokenId = (await createRefungibleToken(api, alice, collectionId, 100n, {Ethereum: owner})).itemId;
-
-    const address = tokenIdToAddress(collectionId, tokenId);
-    const contract = uniqueRefungibleToken(web3, address, owner);
+    const tokenAddress = helper.ethAddress.fromTokenId(collection.collectionId, tokenId);
+    const contract = helper.ethNativeContract.rftToken(tokenAddress, owner);
 
     const result = await contract.methods.repartition(50).send();
-    const events = normalizeEvents(result.events);
-    expect(events).to.deep.equal([
-      {
-        address,
-        event: 'Transfer',
-        args: {
-          from: owner,
-          to: '0x0000000000000000000000000000000000000000',
-          value: '50',
-        },
-      },
-    ]);
+    const event = result.events.Transfer;
+    expect(event.address).to.be.equal(tokenAddress);
+    expect(event.returnValues.from).to.be.equal(owner);
+    expect(event.returnValues.to).to.be.equal('0x0000000000000000000000000000000000000000');
+    expect(event.returnValues.value).to.be.equal('50');
   });
 
-  itWeb3('Receiving Transfer event on burning into full ownership', async ({web3, api, privateKeyWrapper}) => {
-    const caller = await createEthAccountWithBalance(api, web3, privateKeyWrapper);
-    const receiver = await createEthAccountWithBalance(api, web3, privateKeyWrapper);
-    const helper = evmCollectionHelpers(web3, caller);
-    const result = await helper.methods.createRFTCollection('Mint collection', '6', '6').send();
-    const {collectionIdAddress, collectionId} = await getCollectionAddressFromResult(api, result);
-    const contract = evmCollection(web3, caller, collectionIdAddress, {type: 'ReFungible'});
+  itEth('Receiving Transfer event on burning into full ownership', async ({helper}) => {
+    const caller = await helper.eth.createAccountWithBalance(donor);
+    const receiver = await helper.eth.createAccountWithBalance(donor);
+    const {collectionId, collectionAddress} = await helper.eth.createRefungibleCollection(caller, 'Devastation', '6', '6');
+    const contract = helper.ethNativeContract.collection(collectionAddress, 'rft', caller);
 
     const tokenId = await contract.methods.nextTokenId().call();
     await contract.methods.mint(caller, tokenId).send();
+    const tokenAddress = helper.ethAddress.fromTokenId(collectionId, tokenId);
+    const tokenContract = helper.ethNativeContract.rftToken(tokenAddress, caller);
 
-    const address = tokenIdToAddress(collectionId, tokenId);
-
-    const tokenContract =  uniqueRefungibleToken(web3, address, caller);
     await tokenContract.methods.repartition(2).send();
     await tokenContract.methods.transfer(receiver, 1).send();
 
-    const events =  await recordEvents(contract, async () =>
-      await tokenContract.methods.burnFrom(caller, 1).send());
-    expect(events).to.deep.equal([
-      {
-        address: collectionIdAddress,
-        event: 'Transfer',
-        args: {
-          from: '0xFFfFfFffFFfffFFfFFfFFFFFffFFFffffFfFFFfF',
-          to: receiver,
-          tokenId,
-        },
-      },
-    ]);
+    const events: any = [];
+    contract.events.allEvents((_: any, event: any) => {
+      events.push(event);
+    });
+    await tokenContract.methods.burnFrom(caller, 1).send();
+
+    const event = events[0];
+    expect(event.address).to.be.equal(collectionAddress);
+    expect(event.returnValues.from).to.be.equal('0xFFfFfFffFFfffFFfFFfFFFFFffFFFffffFfFFFfF');
+    expect(event.returnValues.to).to.be.equal(receiver);
+    expect(event.returnValues.tokenId).to.be.equal(tokenId);
   });
 });
 
 describe('Refungible: Fees', () => {
+  let donor: IKeyringPair;
+  let alice: IKeyringPair;
+
   before(async function() {
-    await requirePallets(this, [Pallets.ReFungible]);
+    await usingEthPlaygrounds(async (helper, privateKey) => {
+      requirePalletsOrSkip(this, helper, [Pallets.ReFungible]);
+
+      donor = privateKey('//Alice');
+      [alice] = await helper.arrange.createAccounts([50n], donor);
+    });
   });
 
-  itWeb3('approve() call fee is less than 0.2UNQ', async ({web3, api, privateKeyWrapper}) => {
-    const alice = privateKeyWrapper('//Alice');
+  itEth('approve() call fee is less than 0.2UNQ', async ({helper}) => {
+    const owner = await helper.eth.createAccountWithBalance(donor);
+    const spender = helper.eth.createAccount();
+    const collection = await helper.rft.mintCollection(alice);
+    const {tokenId} = await collection.mintToken(alice, 100n, {Ethereum: owner});
 
-    const collectionId = (await createCollection(api, alice, {mode: {type: 'ReFungible'}})).collectionId;
+    const tokenAddress = helper.ethAddress.fromTokenId(collection.collectionId, tokenId);
+    const contract = helper.ethNativeContract.rftToken(tokenAddress, owner);
 
-    const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);
-    const spender = createEthAccount(web3);
-
-    const tokenId = (await createRefungibleToken(api, alice, collectionId, 200n, {Ethereum: owner})).itemId;
-
-    const address = tokenIdToAddress(collectionId, tokenId);
-    const contract = uniqueRefungibleToken(web3, address, owner);
-
-    const cost = await recordEthFee(api, owner, () => contract.methods.approve(spender, 100).send({from: owner}));
-    expect(cost < BigInt(0.2 * Number(UNIQUE)));
+    const cost = await helper.eth.recordCallFee(owner, () => contract.methods.approve(spender, 100).send({from: owner}));
+    expect(cost < BigInt(0.2 * Number(helper.balance.getOneTokenNominal())));
   });
 
-  itWeb3('transferFrom() call fee is less than 0.2UNQ', async ({web3, api, privateKeyWrapper}) => {
-    const alice = privateKeyWrapper('//Alice');
-
-    const collectionId = (await createCollection(api, alice, {mode: {type: 'ReFungible'}})).collectionId;
-
-    const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);
-    const spender = await createEthAccountWithBalance(api, web3, privateKeyWrapper);
-
-    const tokenId = (await createRefungibleToken(api, alice, collectionId, 200n, {Ethereum: owner})).itemId;
+  itEth('transferFrom() call fee is less than 0.2UNQ', async ({helper}) => {
+    const owner = await helper.eth.createAccountWithBalance(donor);
+    const spender = await helper.eth.createAccountWithBalance(donor);
+    const collection = await helper.rft.mintCollection(alice);
+    const {tokenId} = await collection.mintToken(alice, 200n, {Ethereum: owner});
 
-    const address = tokenIdToAddress(collectionId, tokenId);
-    const contract = uniqueRefungibleToken(web3, address, owner);
+    const tokenAddress = helper.ethAddress.fromTokenId(collection.collectionId, tokenId);
+    const contract = helper.ethNativeContract.rftToken(tokenAddress, owner);
 
     await contract.methods.approve(spender, 100).send({from: owner});
 
-    const cost = await recordEthFee(api, spender, () => contract.methods.transferFrom(owner, spender, 100).send({from: spender}));
-    expect(cost < BigInt(0.2 * Number(UNIQUE)));
+    const cost = await helper.eth.recordCallFee(spender, () => contract.methods.transferFrom(owner, spender, 100).send({from: spender}));
+    expect(cost < BigInt(0.2 * Number(helper.balance.getOneTokenNominal())));
   });
 
-  itWeb3('transfer() call fee is less than 0.2UNQ', async ({web3, api, privateKeyWrapper}) => {
-    const alice = privateKeyWrapper('//Alice');
+  itEth('transfer() call fee is less than 0.2UNQ', async ({helper}) => {
+    const owner = await helper.eth.createAccountWithBalance(donor);
+    const receiver = helper.eth.createAccount();
+    const collection = await helper.rft.mintCollection(alice);
+    const {tokenId} = await collection.mintToken(alice, 200n, {Ethereum: owner});
 
-    const collectionId = (await createCollection(api, alice, {mode: {type: 'ReFungible'}})).collectionId;
+    const tokenAddress = helper.ethAddress.fromTokenId(collection.collectionId, tokenId);
+    const contract = helper.ethNativeContract.rftToken(tokenAddress, owner);
 
-    const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);
-    const receiver = createEthAccount(web3);
-
-    const tokenId = (await createRefungibleToken(api, alice, collectionId, 200n, {Ethereum: owner})).itemId;
-
-    const address = tokenIdToAddress(collectionId, tokenId);
-    const contract = uniqueRefungibleToken(web3, address, owner);
-
-    const cost = await recordEthFee(api, owner, () => contract.methods.transfer(receiver, 100).send({from: owner}));
-    expect(cost < BigInt(0.2 * Number(UNIQUE)));
+    const cost = await helper.eth.recordCallFee(owner, () => contract.methods.transfer(receiver, 100).send({from: owner}));
+    expect(cost < BigInt(0.2 * Number(helper.balance.getOneTokenNominal())));
   });
 });
 
 describe('Refungible: Substrate calls', () => {
+  let donor: IKeyringPair;
+  let alice: IKeyringPair;
+
   before(async function() {
-    await requirePallets(this, [Pallets.ReFungible]);
-  });
+    await usingEthPlaygrounds(async (helper, privateKey) => {
+      requirePalletsOrSkip(this, helper, [Pallets.ReFungible]);
 
-  itWeb3('Events emitted for approve()', async ({web3, api, privateKeyWrapper}) => {
-    const alice = privateKeyWrapper('//Alice');
-
-    const collectionId = (await createCollection(api, alice, {mode: {type: 'ReFungible'}})).collectionId;
-
-    const receiver = createEthAccount(web3);
+      donor = privateKey('//Alice');
+      [alice] = await helper.arrange.createAccounts([50n], donor);
+    });
+  });
 
-    const tokenId = (await createRefungibleToken(api, alice, collectionId, 200n)).itemId;
+  itEth('Events emitted for approve()', async ({helper}) => {
+    const receiver = helper.eth.createAccount();
+    const collection = await helper.rft.mintCollection(alice);
+    const token = await collection.mintToken(alice, 200n);
 
-    const address = tokenIdToAddress(collectionId, tokenId);
-    const contract = uniqueRefungibleToken(web3, address);
+    const tokenAddress = helper.ethAddress.fromTokenId(collection.collectionId, token.tokenId);
+    const contract = helper.ethNativeContract.rftToken(tokenAddress);
 
-    const events = await recordEvents(contract, async () => {
-      expect(await approve(api, collectionId, tokenId, alice, {Ethereum: receiver}, 100n)).to.be.true;
+    const events: any = [];
+    contract.events.allEvents((_: any, event: any) => {
+      events.push(event);
     });
+    expect(await token.approve(alice, {Ethereum: receiver}, 100n)).to.be.true;
 
-    expect(events).to.be.deep.equal([
-      {
-        address,
-        event: 'Approval',
-        args: {
-          owner: subToEth(alice.address),
-          spender: receiver,
-          value: '100',
-        },
-      },
-    ]);
+    const event = events[0];
+    expect(event.event).to.be.equal('Approval');
+    expect(event.address).to.be.equal(tokenAddress);
+    expect(event.returnValues.owner).to.be.equal(helper.address.substrateToEth(alice.address));
+    expect(event.returnValues.spender).to.be.equal(receiver);
+    expect(event.returnValues.value).to.be.equal('100');
   });
 
-  itWeb3('Events emitted for transferFrom()', async ({web3, api, privateKeyWrapper}) => {
-    const alice = privateKeyWrapper('//Alice');
+  itEth('Events emitted for transferFrom()', async ({helper}) => {
+    const [bob] = await helper.arrange.createAccounts([10n], donor);
+    const receiver = helper.eth.createAccount();
+    const collection = await helper.rft.mintCollection(alice);
+    const token = await collection.mintToken(alice, 200n);
+    await token.approve(alice, {Substrate: bob.address}, 100n);
 
-    const collectionId = (await createCollection(api, alice, {mode: {type: 'ReFungible'}})).collectionId;
-    const bob = privateKeyWrapper('//Bob');
+    const tokenAddress = helper.ethAddress.fromTokenId(collection.collectionId, token.tokenId);
+    const contract = helper.ethNativeContract.rftToken(tokenAddress);
 
-    const receiver = createEthAccount(web3);
+    const events: any = [];
+    contract.events.allEvents((_: any, event: any) => {
+      events.push(event);
+    });
 
-    const tokenId = (await createRefungibleToken(api, alice, collectionId, 200n)).itemId;
-    expect(await approve(api, collectionId, tokenId, alice, bob.address, 100n)).to.be.true;
+    expect(await token.transferFrom(bob, {Substrate: alice.address}, {Ethereum: receiver},  51n)).to.be.true;
 
-    const address = tokenIdToAddress(collectionId, tokenId);
-    const contract = uniqueRefungibleToken(web3, address);
+    let event = events[0];
+    expect(event.event).to.be.equal('Transfer');
+    expect(event.address).to.be.equal(tokenAddress);
+    expect(event.returnValues.from).to.be.equal(helper.address.substrateToEth(alice.address));
+    expect(event.returnValues.to).to.be.equal(receiver);
+    expect(event.returnValues.value).to.be.equal('51');
 
-    const events = await recordEvents(contract, async () => {
-      expect(await transferFrom(api, collectionId, tokenId, bob, alice, {Ethereum: receiver},  51n)).to.be.true;
-    });
-
-    expect(events).to.be.deep.equal([
-      {
-        address,
-        event: 'Transfer',
-        args: {
-          from: subToEth(alice.address),
-          to: receiver,
-          value: '51',
-        },
-      },
-      {
-        address,
-        event: 'Approval',
-        args: {
-          owner: subToEth(alice.address),
-          spender: subToEth(bob.address),
-          value: '49',
-        },
-      },
-    ]);
+    event = events[1];
+    expect(event.event).to.be.equal('Approval');
+    expect(event.address).to.be.equal(tokenAddress);
+    expect(event.returnValues.owner).to.be.equal(helper.address.substrateToEth(alice.address));
+    expect(event.returnValues.spender).to.be.equal(helper.address.substrateToEth(bob.address));
+    expect(event.returnValues.value).to.be.equal('49');
   });
 
-  itWeb3('Events emitted for transfer()', async ({web3, api, privateKeyWrapper}) => {
-    const alice = privateKeyWrapper('//Alice');
+  itEth('Events emitted for transfer()', async ({helper}) => {
+    const receiver = helper.eth.createAccount();
+    const collection = await helper.rft.mintCollection(alice);
+    const token = await collection.mintToken(alice, 200n);
 
-    const collectionId = (await createCollection(api, alice, {mode: {type: 'ReFungible'}})).collectionId;
+    const tokenAddress = helper.ethAddress.fromTokenId(collection.collectionId, token.tokenId);
+    const contract = helper.ethNativeContract.rftToken(tokenAddress);
 
-    const receiver = createEthAccount(web3);
-
-    const tokenId = (await createRefungibleToken(api, alice, collectionId, 200n)).itemId;
+    const events: any = [];
+    contract.events.allEvents((_: any, event: any) => {
+      events.push(event);
+    });
 
-    const address = tokenIdToAddress(collectionId, tokenId);
-    const contract = uniqueRefungibleToken(web3, address);
+    expect(await token.transfer(alice, {Ethereum: receiver},  51n)).to.be.true;
 
-    const events = await recordEvents(contract, async () => {
-      expect(await transfer(api, collectionId, tokenId, alice, {Ethereum: receiver},  51n)).to.be.true;
-    });
-
-    expect(events).to.be.deep.equal([
-      {
-        address,
-        event: 'Transfer',
-        args: {
-          from: subToEth(alice.address),
-          to: receiver,
-          value: '51',
-        },
-      },
-    ]);
+    const event = events[0];
+    expect(event.event).to.be.equal('Transfer');
+    expect(event.address).to.be.equal(tokenAddress);
+    expect(event.returnValues.from).to.be.equal(helper.address.substrateToEth(alice.address));
+    expect(event.returnValues.to).to.be.equal(receiver);
+    expect(event.returnValues.value).to.be.equal('51');
   });
 });
 
 describe('ERC 1633 implementation', () => {
+  let donor: IKeyringPair;
+
   before(async function() {
-    await requirePallets(this, [Pallets.ReFungible]);
-  });
+    await usingEthPlaygrounds(async (helper, privateKey) => {
+      requirePalletsOrSkip(this, helper, [Pallets.ReFungible]);
 
-  itWeb3('Default parent token address and id', async ({api, web3, privateKeyWrapper}) => {
-    const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);
+      donor = privateKey('//Alice');
+    });
+  });
 
-    const {collectionIdAddress, collectionId} = await createRFTCollection(api, web3, owner);
-    const refungibleContract = uniqueRefungible(web3, collectionIdAddress, owner);
-    const refungibleTokenId = await refungibleContract.methods.nextTokenId().call();
-    await refungibleContract.methods.mint(owner, refungibleTokenId).send();
+  itEth('Default parent token address and id', async ({helper}) => {
+    const owner = await helper.eth.createAccountWithBalance(donor);
 
-    const rftTokenAddress = tokenIdToAddress(collectionId, refungibleTokenId);
-    const refungibleTokenContract = uniqueRefungibleToken(web3, rftTokenAddress, owner);
+    const {collectionId, collectionAddress} = await helper.eth.createRefungibleCollection(owner, 'Sands', '', 'GRAIN');
+    const collectionContract = helper.ethNativeContract.collection(collectionAddress, 'rft', owner);
+    
+    const tokenId = await collectionContract.methods.nextTokenId().call();
+    await collectionContract.methods.mint(owner, tokenId).send();
+    const tokenAddress = helper.ethAddress.fromTokenId(collectionId, tokenId);
+    const tokenContract = helper.ethNativeContract.rftToken(tokenAddress, owner);
 
-    const tokenAddress = await refungibleTokenContract.methods.parentToken().call();
-    const tokenId = await refungibleTokenContract.methods.parentTokenId().call();
-    expect(tokenAddress).to.be.equal(collectionIdAddress);
-    expect(tokenId).to.be.equal(refungibleTokenId);
+    expect(await tokenContract.methods.parentToken().call()).to.be.equal(collectionAddress);
+    expect(await tokenContract.methods.parentTokenId().call()).to.be.equal(tokenId);
   });
 });
modifiedtests/src/eth/util/playgrounds/unique.dev.tsdiffbeforeafterboth
--- a/tests/src/eth/util/playgrounds/unique.dev.ts
+++ b/tests/src/eth/util/playgrounds/unique.dev.ts
@@ -117,13 +117,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);
   }
 }
 
@@ -176,6 +180,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
@@ -220,6 +235,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 {