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

difftreelog

refac: rename substrate methods to cross

Trubnikov Sergey2022-09-28parent: #01b189e.patch.diff
in: master

16 files changed

modifiedpallets/common/src/erc.rsdiffbeforeafterboth
--- a/pallets/common/src/erc.rs
+++ b/pallets/common/src/erc.rs
@@ -656,7 +656,7 @@
 
 	/// Get collection owner.
 	///
-	/// @return Tuple with sponsor address and his substrate mirror.
+	/// @return Tuble with sponsor address and his substrate mirror.
 	/// If address is canonical then substrate mirror is zero and vice versa.
 	fn collection_owner(&self) -> Result<(address, uint256)> {
 		Ok(convert_cross_account_to_tuple::<T>(
modifiedpallets/fungible/src/stubs/UniqueFungible.rawdiffbeforeafterboth

binary blob — no preview

modifiedpallets/fungible/src/stubs/UniqueFungible.soldiffbeforeafterboth
--- a/pallets/fungible/src/stubs/UniqueFungible.sol
+++ b/pallets/fungible/src/stubs/UniqueFungible.sol
@@ -385,7 +385,7 @@
 
 	/// Get collection owner.
 	///
-	/// @return Tuple with sponsor address and his substrate mirror.
+	/// @return Tuble with sponsor address and his substrate mirror.
 	/// If address is canonical then substrate mirror is zero and vice versa.
 	/// @dev EVM selector for this function is: 0xdf727d3b,
 	///  or in textual repr: collectionOwner()
modifiedpallets/nonfungible/src/stubs/UniqueNFT.rawdiffbeforeafterboth

binary blob — no preview

modifiedpallets/nonfungible/src/stubs/UniqueNFT.soldiffbeforeafterboth
--- a/pallets/nonfungible/src/stubs/UniqueNFT.sol
+++ b/pallets/nonfungible/src/stubs/UniqueNFT.sol
@@ -471,7 +471,7 @@
 
 	/// Get collection owner.
 	///
-	/// @return Tuple with sponsor address and his substrate mirror.
+	/// @return Tuble with sponsor address and his substrate mirror.
 	/// If address is canonical then substrate mirror is zero and vice versa.
 	/// @dev EVM selector for this function is: 0xdf727d3b,
 	///  or in textual repr: collectionOwner()
modifiedpallets/refungible/src/stubs/UniqueRefungible.rawdiffbeforeafterboth

binary blob — no preview

modifiedpallets/refungible/src/stubs/UniqueRefungible.soldiffbeforeafterboth
--- a/pallets/refungible/src/stubs/UniqueRefungible.sol
+++ b/pallets/refungible/src/stubs/UniqueRefungible.sol
@@ -471,7 +471,7 @@
 
 	/// Get collection owner.
 	///
-	/// @return Tuple with sponsor address and his substrate mirror.
+	/// @return Tuble with sponsor address and his substrate mirror.
 	/// If address is canonical then substrate mirror is zero and vice versa.
 	/// @dev EVM selector for this function is: 0xdf727d3b,
 	///  or in textual repr: collectionOwner()
modifiedtests/src/eth/allowlist.test.tsdiffbeforeafterboth
--- a/tests/src/eth/allowlist.test.ts
+++ b/tests/src/eth/allowlist.test.ts
@@ -89,21 +89,21 @@
     expect(await collectionEvm.methods.allowed(user).call({from: owner})).to.be.false;
   });
 
-  //itEth('Collection allowlist can be added and removed by [cross] address', async ({helper}) => {
-  //  const owner = await helper.eth.createAccountWithBalance(donor);
-  //  const user = donor;
-  //  
-  //  const {collectionAddress, collectionId} = await helper.eth.createNFTCollection(owner, 'A', 'B', 'C');
-  //  const collectionEvm = helper.ethNativeContract.collection(collectionAddress, 'nft', owner);
-  //  const userCross = helper.ethCrossAccount.fromKeyringPair(user);
-  //  
-  //  expect(await helper.collection.allowed(collectionId, {Substrate: user.address})).to.be.false;
-  //  await collectionEvm.methods.addToCollectionAllowListCross(userCross).send({from: owner});
-  //  expect(await helper.collection.allowed(collectionId, {Substrate: user.address})).to.be.true;
-  //  
-  //  await collectionEvm.methods.removeFromCollectionAllowListCross(userCross).send({from: owner});
-  //  expect(await helper.collection.allowed(collectionId, {Substrate: user.address})).to.be.false;
-  //});
+  itEth('Collection allowlist can be added and removed by [cross] address', async ({helper}) => {
+    const owner = await helper.eth.createAccountWithBalance(donor);
+    const user = donor;
+    
+    const {collectionAddress, collectionId} = await helper.eth.createNonfungibleCollection(owner, 'A', 'B', 'C');
+    const collectionEvm = helper.ethNativeContract.collection(collectionAddress, 'nft', owner);
+    const userCross = helper.ethCrossAccount.fromKeyringPair(user);
+    
+    expect(await helper.collection.allowed(collectionId, {Substrate: user.address})).to.be.false;
+    await collectionEvm.methods.addToCollectionAllowListCross(userCross).send({from: owner});
+    expect(await helper.collection.allowed(collectionId, {Substrate: user.address})).to.be.true;
+    
+    await collectionEvm.methods.removeFromCollectionAllowListCross(userCross).send({from: owner});
+    expect(await helper.collection.allowed(collectionId, {Substrate: user.address})).to.be.false;
+  });
 
   itEth('Collection allowlist can not be add and remove [eth] address by not owner', async ({helper}) => {
     const owner = await helper.eth.createAccountWithBalance(donor);
@@ -122,22 +122,22 @@
     expect(await collectionEvm.methods.allowed(user).call({from: owner})).to.be.true;
   });
 
-  //itEth('Collection allowlist can not be add and remove [cross] address by not owner', async ({helper}) => {
-  //  const owner = await helper.eth.createAccountWithBalance(donor);
-  //  const notOwner = await helper.eth.createAccountWithBalance(donor);
-  //  const user = donor;
-  //  
-  //  const {collectionAddress, collectionId} = await helper.eth.createNFTCollection(owner, 'A', 'B', 'C');
-  //  const collectionEvm = helper.ethNativeContract.collection(collectionAddress, 'nft', owner);
-  //  
-  //  expect(await helper.collection.allowed(collectionId, {Substrate: user.address})).to.be.false;
-  //  const userCross = helper.ethCrossAccount.fromKeyringPair(user);
-  //  await expect(collectionEvm.methods.addToCollectionAllowListCross(userCross).call({from: notOwner})).to.be.rejectedWith('NoPermission');
-  //  expect(await helper.collection.allowed(collectionId, {Substrate: user.address})).to.be.false;
-  //  await collectionEvm.methods.addToCollectionAllowListCross(userCross).send({from: owner});
-  //  
-  //  expect(await helper.collection.allowed(collectionId, {Substrate: user.address})).to.be.true;
-  //  await expect(collectionEvm.methods.removeFromCollectionAllowListCross(userCross).call({from: notOwner})).to.be.rejectedWith('NoPermission');
-  //  expect(await helper.collection.allowed(collectionId, {Substrate: user.address})).to.be.true;
-  //});
+  itEth('Collection allowlist can not be add and remove [cross] address by not owner', async ({helper}) => {
+    const owner = await helper.eth.createAccountWithBalance(donor);
+    const notOwner = await helper.eth.createAccountWithBalance(donor);
+    const user = donor;
+    
+    const {collectionAddress, collectionId} = await helper.eth.createNonfungibleCollection(owner, 'A', 'B', 'C');
+    const collectionEvm = helper.ethNativeContract.collection(collectionAddress, 'nft', owner);
+    
+    expect(await helper.collection.allowed(collectionId, {Substrate: user.address})).to.be.false;
+    const userCross = helper.ethCrossAccount.fromKeyringPair(user);
+    await expect(collectionEvm.methods.addToCollectionAllowListCross(userCross).call({from: notOwner})).to.be.rejectedWith('NoPermission');
+    expect(await helper.collection.allowed(collectionId, {Substrate: user.address})).to.be.false;
+    await collectionEvm.methods.addToCollectionAllowListCross(userCross).send({from: owner});
+    
+    expect(await helper.collection.allowed(collectionId, {Substrate: user.address})).to.be.true;
+    await expect(collectionEvm.methods.removeFromCollectionAllowListCross(userCross).call({from: notOwner})).to.be.rejectedWith('NoPermission');
+    expect(await helper.collection.allowed(collectionId, {Substrate: user.address})).to.be.true;
+  });
 });
modifiedtests/src/eth/api/UniqueFungible.soldiffbeforeafterboth
--- a/tests/src/eth/api/UniqueFungible.sol
+++ b/tests/src/eth/api/UniqueFungible.sol
@@ -249,7 +249,7 @@
 
 	/// Get collection owner.
 	///
-	/// @return Tuple with sponsor address and his substrate mirror.
+	/// @return Tuble with sponsor address and his substrate mirror.
 	/// If address is canonical then substrate mirror is zero and vice versa.
 	/// @dev EVM selector for this function is: 0xdf727d3b,
 	///  or in textual repr: collectionOwner()
modifiedtests/src/eth/api/UniqueNFT.soldiffbeforeafterboth
--- a/tests/src/eth/api/UniqueNFT.sol
+++ b/tests/src/eth/api/UniqueNFT.sol
@@ -306,7 +306,7 @@
 
 	/// Get collection owner.
 	///
-	/// @return Tuple with sponsor address and his substrate mirror.
+	/// @return Tuble with sponsor address and his substrate mirror.
 	/// If address is canonical then substrate mirror is zero and vice versa.
 	/// @dev EVM selector for this function is: 0xdf727d3b,
 	///  or in textual repr: collectionOwner()
modifiedtests/src/eth/api/UniqueRefungible.soldiffbeforeafterboth
--- a/tests/src/eth/api/UniqueRefungible.sol
+++ b/tests/src/eth/api/UniqueRefungible.sol
@@ -306,7 +306,7 @@
 
 	/// Get collection owner.
 	///
-	/// @return Tuple with sponsor address and his substrate mirror.
+	/// @return Tuble with sponsor address and his substrate mirror.
 	/// If address is canonical then substrate mirror is zero and vice versa.
 	/// @dev EVM selector for this function is: 0xdf727d3b,
 	///  or in textual repr: collectionOwner()
modifiedtests/src/eth/collectionAdmin.test.tsdiffbeforeafterboth
--- a/tests/src/eth/collectionAdmin.test.ts
+++ b/tests/src/eth/collectionAdmin.test.ts
@@ -53,10 +53,10 @@
   itEth('Add cross account admin by owner', async ({helper, privateKey}) => {
     const owner = await helper.eth.createAccountWithBalance(donor);
         
-    const {collectionAddress, collectionId} = await helper.eth.createNFTCollection(owner, 'A', 'B', 'C');
+    const {collectionAddress, collectionId} = await helper.eth.createNonfungibleCollection(owner, 'A', 'B', 'C');
     const collectionEvm = helper.ethNativeContract.collection(collectionAddress, 'nft', owner);
     
-    const newAdmin = await privateKey('//Bob');
+    const newAdmin = privateKey('//Bob');
     const newAdminCross = helper.ethCrossAccount.fromKeyringPair(newAdmin);
     await collectionEvm.methods.addCollectionAdminCross(newAdminCross).send();
 
modifiedtests/src/eth/fungible.test.tsdiffbeforeafterboth
before · tests/src/eth/fungible.test.ts
1// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.2// This file is part of Unique Network.34// Unique Network is free software: you can redistribute it and/or modify5// it under the terms of the GNU General Public License as published by6// the Free Software Foundation, either version 3 of the License, or7// (at your option) any later version.89// Unique Network is distributed in the hope that it will be useful,10// but WITHOUT ANY WARRANTY; without even the implied warranty of11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the12// GNU General Public License for more details.1314// You should have received a copy of the GNU General Public License15// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.1617import {expect, itEth, usingEthPlaygrounds} from './util';18import {IKeyringPair} from '@polkadot/types/types';1920describe('Fungible: Information getting', () => {21  let donor: IKeyringPair;22  let alice: IKeyringPair;2324  before(async function() {25    await usingEthPlaygrounds(async (helper, privateKey) => {26      donor = await privateKey({filename: __filename});27      [alice] = await helper.arrange.createAccounts([20n], donor);28    });29  });3031  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);3536    const contract = helper.ethNativeContract.collectionById(collection.collectionId, 'ft', caller);37    const totalSupply = await contract.methods.totalSupply().call();38    expect(totalSupply).to.equal('200');39  });4041  itEth('balanceOf', async ({helper}) => {42    const caller = await helper.eth.createAccountWithBalance(donor);43    const collection = await helper.ft.mintCollection(alice);44    await collection.mint(alice, 200n, {Ethereum: caller});4546    const contract = helper.ethNativeContract.collectionById(collection.collectionId, 'ft', caller);47    const balance = await contract.methods.balanceOf(caller).call();48    expect(balance).to.equal('200');49  });50});5152describe('Fungible: Plain calls', () => {53  let donor: IKeyringPair;54  let alice: IKeyringPair;5556  before(async function() {57    await usingEthPlaygrounds(async (helper, privateKey) => {58      donor = await privateKey({filename: __filename});59      [alice] = await helper.arrange.createAccounts([20n], donor);60    });61  });6263  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});6869    const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId);70    const contract = helper.ethNativeContract.collection(collectionAddress, 'ft', owner);7172    const result = await contract.methods.mint(receiver, 100).send();73    74    const event = result.events.Transfer;75    expect(event.address).to.equal(collectionAddress);76    expect(event.returnValues.from).to.equal('0x0000000000000000000000000000000000000000');77    expect(event.returnValues.to).to.equal(receiver);78    expect(event.returnValues.value).to.equal('100');79  });8081  itEth('Can perform mintBulk()', async ({helper}) => {82    const owner = await helper.eth.createAccountWithBalance(donor);83    const bulkSize = 3;84    const receivers = [...new Array(bulkSize)].map(() => helper.eth.createAccount());85    const collection = await helper.ft.mintCollection(alice);86    await collection.addAdmin(alice, {Ethereum: owner});8788    const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId);89    const contract = helper.ethNativeContract.collection(collectionAddress, 'ft', owner);9091    const result = await contract.methods.mintBulk(Array.from({length: bulkSize}, (_, i) => (92      [receivers[i], (i + 1) * 10]93    ))).send();94    const events = result.events.Transfer.sort((a: any, b: any) => +a.returnValues.value - b.returnValues.value);95    for (let i = 0; i < bulkSize; i++) {96      const event = events[i];97      expect(event.address).to.equal(collectionAddress);98      expect(event.returnValues.from).to.equal('0x0000000000000000000000000000000000000000');99      expect(event.returnValues.to).to.equal(receivers[i]);100      expect(event.returnValues.value).to.equal(String(10 * (i + 1)));101    }102  });103104  itEth('Can perform burn()', async ({helper}) => {105    const owner = await helper.eth.createAccountWithBalance(donor);106    const receiver = await helper.eth.createAccountWithBalance(donor);107    const collection = await helper.ft.mintCollection(alice);108    await collection.addAdmin(alice, {Ethereum: owner});109110    const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId);111    const contract = helper.ethNativeContract.collection(collectionAddress, 'ft', owner);112    await contract.methods.mint(receiver, 100).send();113114    const result = await contract.methods.burnFrom(receiver, 49).send({from: receiver});115    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');121122    const balance = await contract.methods.balanceOf(receiver).call();123    expect(balance).to.equal('51');124  });125126  itEth('Can perform approve()', async ({helper}) => {127    const owner = await helper.eth.createAccountWithBalance(donor);128    const spender = helper.eth.createAccount();129    const collection = await helper.ft.mintCollection(alice);130    await collection.mint(alice, 200n, {Ethereum: owner});131132    const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId);133    const contract = helper.ethNativeContract.collection(collectionAddress, 'ft', owner);134135    {136      const result = await contract.methods.approve(spender, 100).send({from: owner});137138      const event = result.events.Approval;139      expect(event.address).to.be.equal(collectionAddress);140      expect(event.returnValues.owner).to.be.equal(owner);141      expect(event.returnValues.spender).to.be.equal(spender);142      expect(event.returnValues.value).to.be.equal('100');143    }144145    {146      const allowance = await contract.methods.allowance(owner, spender).call();147      expect(+allowance).to.equal(100);148    }149  });150151  itEth('Can perform burnFromCross()', async ({helper, privateKey}) => {152    const alice = await privateKey('//Alice');153    const sender = await helper.eth.createAccountWithBalance(alice, 100n);154155    const collection = await helper.ft.mintCollection(alice, {name: 'A', description: 'B', tokenPrefix: 'C'}, 0);156157    await collection.mint(alice, 200n, {Substrate: alice.address});158    await collection.approveTokens(alice, {Ethereum: sender}, 100n);159160    const address = helper.ethAddress.fromCollectionId(collection.collectionId);161    const contract = helper.ethNativeContract.collection(address, 'ft');162163    const fromBalanceBefore = await collection.getBalance({Substrate: alice.address});164    165    const ownerCross = helper.ethCrossAccount.fromKeyringPair(alice);166    const result = await contract.methods.burnFromCross(ownerCross, 49).send({from: sender});167    const events = result.events;168169    expect(events).to.be.like({170      Transfer: {171        address: helper.ethAddress.fromCollectionId(collection.collectionId),172        event: 'Transfer',173        returnValues: {174          from: helper.address.substrateToEth(alice.address),175          to: '0x0000000000000000000000000000000000000000',176          value: '49',177        },178      },179      Approval: {180        address: helper.ethAddress.fromCollectionId(collection.collectionId),181        returnValues: {182          owner: helper.address.substrateToEth(alice.address),183          spender: sender,184          value: '51',185        },186        event: 'Approval',187      },188    });189190    const fromBalanceAfter = await collection.getBalance({Substrate: alice.address});191    expect(fromBalanceBefore - fromBalanceAfter).to.be.eq(49n);192  });193194  itEth('Can perform transferFrom()', async ({helper}) => {195    const owner = await helper.eth.createAccountWithBalance(donor);196    const spender = await helper.eth.createAccountWithBalance(donor);197    const receiver = helper.eth.createAccount();198    const collection = await helper.ft.mintCollection(alice);199    await collection.mint(alice, 200n, {Ethereum: owner});200201    const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId);202    const contract = helper.ethNativeContract.collection(collectionAddress, 'ft', owner);203204    await contract.methods.approve(spender, 100).send();205206    {207      const result = await contract.methods.transferFrom(owner, receiver, 49).send({from: spender});208      209      let event = result.events.Transfer;210      expect(event.address).to.be.equal(collectionAddress);211      expect(event.returnValues.from).to.be.equal(owner);212      expect(event.returnValues.to).to.be.equal(receiver);213      expect(event.returnValues.value).to.be.equal('49');214215      event = result.events.Approval;216      expect(event.address).to.be.equal(collectionAddress);217      expect(event.returnValues.owner).to.be.equal(owner);218      expect(event.returnValues.spender).to.be.equal(spender);219      expect(event.returnValues.value).to.be.equal('51');220    }221222    {223      const balance = await contract.methods.balanceOf(receiver).call();224      expect(+balance).to.equal(49);225    }226227    {228      const balance = await contract.methods.balanceOf(owner).call();229      expect(+balance).to.equal(151);230    }231  });232233  itEth('Can perform transfer()', async ({helper}) => {234    const owner = await helper.eth.createAccountWithBalance(donor);235    const receiver = await helper.eth.createAccountWithBalance(donor);236    const collection = await helper.ft.mintCollection(alice);237    await collection.mint(alice, 200n, {Ethereum: owner});238239    const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId);240    const contract = helper.ethNativeContract.collection(collectionAddress, 'ft', owner);241242    {243      const result = await contract.methods.transfer(receiver, 50).send({from: owner});244      245      const event = result.events.Transfer;246      expect(event.address).to.be.equal(collectionAddress);247      expect(event.returnValues.from).to.be.equal(owner);248      expect(event.returnValues.to).to.be.equal(receiver);249      expect(event.returnValues.value).to.be.equal('50');250    }251252    {253      const balance = await contract.methods.balanceOf(owner).call();254      expect(+balance).to.equal(150);255    }256257    {258      const balance = await contract.methods.balanceOf(receiver).call();259      expect(+balance).to.equal(50);260    }261  });262263  itEth('Can perform transferFromCross()', async ({helper, privateKey}) => {264    const alice = await privateKey('//Alice');265    const sender = await helper.eth.createAccountWithBalance(alice, 100n);266267    const collection = await helper.ft.mintCollection(alice, {name: 'A', description: 'B', tokenPrefix: 'C'}, 0);268269    const receiver = helper.eth.createAccount();270271    await collection.mint(alice, 200n, {Substrate: alice.address});272    await collection.approveTokens(alice, {Ethereum: sender}, 100n);273274    const address = helper.ethAddress.fromCollectionId(collection.collectionId);275    const contract = helper.ethNativeContract.collection(address, 'ft');276277    const from = helper.ethCrossAccount.fromKeyringPair(alice);278    const to = helper.ethCrossAccount.fromAddress(receiver);279280    const fromBalanceBefore = await collection.getBalance({Substrate: alice.address});281    const toBalanceBefore = await collection.getBalance({Ethereum: receiver});282    283    const result = await contract.methods.transferFromCross(from, to, 51).send({from: sender});284285    expect(result.events).to.be.like({286      Transfer: {287        address,288        event: 'Transfer',289        returnValues: {290          from: helper.address.substrateToEth(alice.address),291          to: receiver,292          value: '51',293        },294      },295      Approval: {296        address,297        event: 'Approval',298        returnValues: {299          owner: helper.address.substrateToEth(alice.address),300          spender: sender,301          value: '49',302        },303      }});304305    const fromBalanceAfter = await collection.getBalance({Substrate: alice.address});306    expect(fromBalanceBefore - fromBalanceAfter).to.be.eq(51n);307    const toBalanceAfter = await collection.getBalance({Ethereum: receiver});308    expect(toBalanceAfter - toBalanceBefore).to.be.eq(51n);309  });310});311312describe('Fungible: Fees', () => {313  let donor: IKeyringPair;314  let alice: IKeyringPair;315316  before(async function() {317    await usingEthPlaygrounds(async (helper, privateKey) => {318      donor = await privateKey({filename: __filename});319      [alice] = await helper.arrange.createAccounts([20n], donor);320    });321  });322  323  itEth('approve() call fee is less than 0.2UNQ', async ({helper}) => {324    const owner = await helper.eth.createAccountWithBalance(donor);325    const spender = helper.eth.createAccount();326    const collection = await helper.ft.mintCollection(alice);327    await collection.mint(alice, 200n, {Ethereum: owner});328329    const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId);330    const contract = helper.ethNativeContract.collection(collectionAddress, 'ft', owner);331332    const cost = await helper.eth.recordCallFee(owner, () => contract.methods.approve(spender, 100).send({from: owner}));333    expect(cost < BigInt(0.2 * Number(helper.balance.getOneTokenNominal())));334  });335336  itEth('transferFrom() call fee is less than 0.2UNQ', async ({helper}) => {337    const owner = await helper.eth.createAccountWithBalance(donor);338    const spender = await helper.eth.createAccountWithBalance(donor);339    const collection = await helper.ft.mintCollection(alice);340    await collection.mint(alice, 200n, {Ethereum: owner});341342    const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId);343    const contract = helper.ethNativeContract.collection(collectionAddress, 'ft', owner);344345    await contract.methods.approve(spender, 100).send({from: owner});346347    const cost = await helper.eth.recordCallFee(spender, () => contract.methods.transferFrom(owner, spender, 100).send({from: spender}));348    expect(cost < BigInt(0.2 * Number(helper.balance.getOneTokenNominal())));349  });350351  itEth('transfer() call fee is less than 0.2UNQ', async ({helper}) => {352    const owner = await helper.eth.createAccountWithBalance(donor);353    const receiver = helper.eth.createAccount();354    const collection = await helper.ft.mintCollection(alice);355    await collection.mint(alice, 200n, {Ethereum: owner});356357    const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId);358    const contract = helper.ethNativeContract.collection(collectionAddress, 'ft', owner);359360    const cost = await helper.eth.recordCallFee(owner, () => contract.methods.transfer(receiver, 100).send({from: owner}));361    expect(cost < BigInt(0.2 * Number(helper.balance.getOneTokenNominal())));362  });363});364365describe('Fungible: Substrate calls', () => {366  let donor: IKeyringPair;367  let alice: IKeyringPair;368369  before(async function() {370    await usingEthPlaygrounds(async (helper, privateKey) => {371      donor = await privateKey({filename: __filename});372      [alice] = await helper.arrange.createAccounts([20n], donor);373    });374  });375376  itEth('Events emitted for approve()', async ({helper}) => {377    const receiver = helper.eth.createAccount();378    const collection = await helper.ft.mintCollection(alice);379    await collection.mint(alice, 200n);380381    const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId);382    const contract = helper.ethNativeContract.collection(collectionAddress, 'ft');383384    const events: any = [];385    contract.events.allEvents((_: any, event: any) => {386      events.push(event);387    });388    389    await collection.approveTokens(alice, {Ethereum: receiver}, 100n);390    if (events.length == 0) await helper.wait.newBlocks(1);391    const event = events[0];392393    expect(event.event).to.be.equal('Approval');394    expect(event.address).to.be.equal(collectionAddress);395    expect(event.returnValues.owner).to.be.equal(helper.address.substrateToEth(alice.address));396    expect(event.returnValues.spender).to.be.equal(receiver);397    expect(event.returnValues.value).to.be.equal('100');398  });399400  itEth('Events emitted for transferFrom()', async ({helper}) => {401    const [bob] = await helper.arrange.createAccounts([10n], donor);402    const receiver = helper.eth.createAccount();403    const collection = await helper.ft.mintCollection(alice);404    await collection.mint(alice, 200n);405    await collection.approveTokens(alice, {Substrate: bob.address}, 100n);406407    const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId);408    const contract = helper.ethNativeContract.collection(collectionAddress, 'ft');409410    const events: any = [];411    contract.events.allEvents((_: any, event: any) => {412      events.push(event);413    });414415    await collection.transferFrom(bob, {Substrate: alice.address}, {Ethereum: receiver}, 51n);416    if (events.length == 0) await helper.wait.newBlocks(1);417    let event = events[0];418419    expect(event.event).to.be.equal('Transfer');420    expect(event.address).to.be.equal(collectionAddress);421    expect(event.returnValues.from).to.be.equal(helper.address.substrateToEth(alice.address));422    expect(event.returnValues.to).to.be.equal(receiver);423    expect(event.returnValues.value).to.be.equal('51');424425    event = events[1];426    expect(event.event).to.be.equal('Approval');427    expect(event.address).to.be.equal(collectionAddress);428    expect(event.returnValues.owner).to.be.equal(helper.address.substrateToEth(alice.address));429    expect(event.returnValues.spender).to.be.equal(helper.address.substrateToEth(bob.address));430    expect(event.returnValues.value).to.be.equal('49');431  });432433  itEth('Events emitted for transfer()', async ({helper}) => {434    const receiver = helper.eth.createAccount();435    const collection = await helper.ft.mintCollection(alice);436    await collection.mint(alice, 200n);437438    const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId);439    const contract = helper.ethNativeContract.collection(collectionAddress, 'ft');440441    const events: any = [];442    contract.events.allEvents((_: any, event: any) => {443      events.push(event);444    });445    446    await collection.transfer(alice, {Ethereum:receiver}, 51n);447    if (events.length == 0) await helper.wait.newBlocks(1);448    const event = events[0];449450    expect(event.event).to.be.equal('Transfer');451    expect(event.address).to.be.equal(collectionAddress);452    expect(event.returnValues.from).to.be.equal(helper.address.substrateToEth(alice.address));453    expect(event.returnValues.to).to.be.equal(receiver);454    expect(event.returnValues.value).to.be.equal('51');455  });456457  itEth('Events emitted for transferFromCross()', async ({helper, privateKey}) => {458    const alice = await privateKey('//Alice');459    const sender = await helper.eth.createAccountWithBalance(alice, 100n);460461    const collection = await helper.ft.mintCollection(alice, {name: 'A', description: 'B', tokenPrefix: 'C'}, 0);462463    const receiver = helper.eth.createAccount();464465    await collection.mint(alice, 200n, {Substrate: alice.address});466    await collection.approveTokens(alice, {Ethereum: sender}, 100n);467468    const address = helper.ethAddress.fromCollectionId(collection.collectionId);469    const contract = helper.ethNativeContract.collection(address, 'ft');470471    const from = helper.ethCrossAccount.fromKeyringPair(alice);472    const to = helper.ethCrossAccount.fromAddress(receiver);473    474    const result = await contract.methods.transferFromCross(from, to, 51).send({from: sender});475476    expect(result.events).to.be.like({477      Transfer: {478        address,479        event: 'Transfer',480        returnValues: {481          from: helper.address.substrateToEth(alice.address),482          to: receiver,483          value: '51',484        },485      },486      Approval: {487        address,488        event: 'Approval',489        returnValues: {490          owner: helper.address.substrateToEth(alice.address),491          spender: sender,492          value: '49',493        },494      }});495  });496});
after · tests/src/eth/fungible.test.ts
1// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.2// This file is part of Unique Network.34// Unique Network is free software: you can redistribute it and/or modify5// it under the terms of the GNU General Public License as published by6// the Free Software Foundation, either version 3 of the License, or7// (at your option) any later version.89// Unique Network is distributed in the hope that it will be useful,10// but WITHOUT ANY WARRANTY; without even the implied warranty of11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the12// GNU General Public License for more details.1314// You should have received a copy of the GNU General Public License15// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.1617import {expect, itEth, usingEthPlaygrounds} from './util';18import {IKeyringPair} from '@polkadot/types/types';1920describe('Fungible: Information getting', () => {21  let donor: IKeyringPair;22  let alice: IKeyringPair;2324  before(async function() {25    await usingEthPlaygrounds(async (helper, privateKey) => {26      donor = await privateKey({filename: __filename});27      [alice] = await helper.arrange.createAccounts([20n], donor);28    });29  });3031  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);3536    const contract = helper.ethNativeContract.collectionById(collection.collectionId, 'ft', caller);37    const totalSupply = await contract.methods.totalSupply().call();38    expect(totalSupply).to.equal('200');39  });4041  itEth('balanceOf', async ({helper}) => {42    const caller = await helper.eth.createAccountWithBalance(donor);43    const collection = await helper.ft.mintCollection(alice);44    await collection.mint(alice, 200n, {Ethereum: caller});4546    const contract = helper.ethNativeContract.collectionById(collection.collectionId, 'ft', caller);47    const balance = await contract.methods.balanceOf(caller).call();48    expect(balance).to.equal('200');49  });50});5152describe('Fungible: Plain calls', () => {53  let donor: IKeyringPair;54  let alice: IKeyringPair;5556  before(async function() {57    await usingEthPlaygrounds(async (helper, privateKey) => {58      donor = await privateKey({filename: __filename});59      [alice] = await helper.arrange.createAccounts([20n], donor);60    });61  });6263  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});6869    const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId);70    const contract = helper.ethNativeContract.collection(collectionAddress, 'ft', owner);7172    const result = await contract.methods.mint(receiver, 100).send();73    74    const event = result.events.Transfer;75    expect(event.address).to.equal(collectionAddress);76    expect(event.returnValues.from).to.equal('0x0000000000000000000000000000000000000000');77    expect(event.returnValues.to).to.equal(receiver);78    expect(event.returnValues.value).to.equal('100');79  });8081  itEth('Can perform mintBulk()', async ({helper}) => {82    const owner = await helper.eth.createAccountWithBalance(donor);83    const bulkSize = 3;84    const receivers = [...new Array(bulkSize)].map(() => helper.eth.createAccount());85    const collection = await helper.ft.mintCollection(alice);86    await collection.addAdmin(alice, {Ethereum: owner});8788    const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId);89    const contract = helper.ethNativeContract.collection(collectionAddress, 'ft', owner);9091    const result = await contract.methods.mintBulk(Array.from({length: bulkSize}, (_, i) => (92      [receivers[i], (i + 1) * 10]93    ))).send();94    const events = result.events.Transfer.sort((a: any, b: any) => +a.returnValues.value - b.returnValues.value);95    for (let i = 0; i < bulkSize; i++) {96      const event = events[i];97      expect(event.address).to.equal(collectionAddress);98      expect(event.returnValues.from).to.equal('0x0000000000000000000000000000000000000000');99      expect(event.returnValues.to).to.equal(receivers[i]);100      expect(event.returnValues.value).to.equal(String(10 * (i + 1)));101    }102  });103104  itEth('Can perform burn()', async ({helper}) => {105    const owner = await helper.eth.createAccountWithBalance(donor);106    const receiver = await helper.eth.createAccountWithBalance(donor);107    const collection = await helper.ft.mintCollection(alice);108    await collection.addAdmin(alice, {Ethereum: owner});109110    const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId);111    const contract = helper.ethNativeContract.collection(collectionAddress, 'ft', owner);112    await contract.methods.mint(receiver, 100).send();113114    const result = await contract.methods.burnFrom(receiver, 49).send({from: receiver});115    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');121122    const balance = await contract.methods.balanceOf(receiver).call();123    expect(balance).to.equal('51');124  });125126  itEth('Can perform approve()', async ({helper}) => {127    const owner = await helper.eth.createAccountWithBalance(donor);128    const spender = helper.eth.createAccount();129    const collection = await helper.ft.mintCollection(alice);130    await collection.mint(alice, 200n, {Ethereum: owner});131132    const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId);133    const contract = helper.ethNativeContract.collection(collectionAddress, 'ft', owner);134135    {136      const result = await contract.methods.approve(spender, 100).send({from: owner});137138      const event = result.events.Approval;139      expect(event.address).to.be.equal(collectionAddress);140      expect(event.returnValues.owner).to.be.equal(owner);141      expect(event.returnValues.spender).to.be.equal(spender);142      expect(event.returnValues.value).to.be.equal('100');143    }144145    {146      const allowance = await contract.methods.allowance(owner, spender).call();147      expect(+allowance).to.equal(100);148    }149  });150151  itEth('Can perform burnFromCross()', async ({helper, privateKey}) => {152    const alice = privateKey('//Alice');153    const sender = await helper.eth.createAccountWithBalance(alice, 100n);154155    const collection = await helper.ft.mintCollection(alice, {name: 'A', description: 'B', tokenPrefix: 'C'}, 0);156157    await collection.mint(alice, 200n, {Substrate: alice.address});158    await collection.approveTokens(alice, {Ethereum: sender}, 100n);159160    const address = helper.ethAddress.fromCollectionId(collection.collectionId);161    const contract = helper.ethNativeContract.collection(address, 'ft');162163    const fromBalanceBefore = await collection.getBalance({Substrate: alice.address});164    165    const ownerCross = helper.ethCrossAccount.fromKeyringPair(alice);166    const result = await contract.methods.burnFromCross(ownerCross, 49).send({from: sender});167    const events = result.events;168169    expect(events).to.be.like({170      Transfer: {171        address: helper.ethAddress.fromCollectionId(collection.collectionId),172        event: 'Transfer',173        returnValues: {174          from: helper.address.substrateToEth(alice.address),175          to: '0x0000000000000000000000000000000000000000',176          value: '49',177        },178      },179      Approval: {180        address: helper.ethAddress.fromCollectionId(collection.collectionId),181        returnValues: {182          owner: helper.address.substrateToEth(alice.address),183          spender: sender,184          value: '51',185        },186        event: 'Approval',187      },188    });189190    const fromBalanceAfter = await collection.getBalance({Substrate: alice.address});191    expect(fromBalanceBefore - fromBalanceAfter).to.be.eq(49n);192  });193194  itEth('Can perform transferFrom()', async ({helper}) => {195    const owner = await helper.eth.createAccountWithBalance(donor);196    const spender = await helper.eth.createAccountWithBalance(donor);197    const receiver = helper.eth.createAccount();198    const collection = await helper.ft.mintCollection(alice);199    await collection.mint(alice, 200n, {Ethereum: owner});200201    const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId);202    const contract = helper.ethNativeContract.collection(collectionAddress, 'ft', owner);203204    await contract.methods.approve(spender, 100).send();205206    {207      const result = await contract.methods.transferFrom(owner, receiver, 49).send({from: spender});208      209      let event = result.events.Transfer;210      expect(event.address).to.be.equal(collectionAddress);211      expect(event.returnValues.from).to.be.equal(owner);212      expect(event.returnValues.to).to.be.equal(receiver);213      expect(event.returnValues.value).to.be.equal('49');214215      event = result.events.Approval;216      expect(event.address).to.be.equal(collectionAddress);217      expect(event.returnValues.owner).to.be.equal(owner);218      expect(event.returnValues.spender).to.be.equal(spender);219      expect(event.returnValues.value).to.be.equal('51');220    }221222    {223      const balance = await contract.methods.balanceOf(receiver).call();224      expect(+balance).to.equal(49);225    }226227    {228      const balance = await contract.methods.balanceOf(owner).call();229      expect(+balance).to.equal(151);230    }231  });232233  itEth('Can perform transfer()', async ({helper}) => {234    const owner = await helper.eth.createAccountWithBalance(donor);235    const receiver = await helper.eth.createAccountWithBalance(donor);236    const collection = await helper.ft.mintCollection(alice);237    await collection.mint(alice, 200n, {Ethereum: owner});238239    const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId);240    const contract = helper.ethNativeContract.collection(collectionAddress, 'ft', owner);241242    {243      const result = await contract.methods.transfer(receiver, 50).send({from: owner});244      245      const event = result.events.Transfer;246      expect(event.address).to.be.equal(collectionAddress);247      expect(event.returnValues.from).to.be.equal(owner);248      expect(event.returnValues.to).to.be.equal(receiver);249      expect(event.returnValues.value).to.be.equal('50');250    }251252    {253      const balance = await contract.methods.balanceOf(owner).call();254      expect(+balance).to.equal(150);255    }256257    {258      const balance = await contract.methods.balanceOf(receiver).call();259      expect(+balance).to.equal(50);260    }261  });262263  itEth('Can perform transferFromCross()', async ({helper, privateKey}) => {264    const alice = privateKey('//Alice');265    const sender = await helper.eth.createAccountWithBalance(alice, 100n);266267    const collection = await helper.ft.mintCollection(alice, {name: 'A', description: 'B', tokenPrefix: 'C'}, 0);268269    const receiver = helper.eth.createAccount();270271    await collection.mint(alice, 200n, {Substrate: alice.address});272    await collection.approveTokens(alice, {Ethereum: sender}, 100n);273274    const address = helper.ethAddress.fromCollectionId(collection.collectionId);275    const contract = helper.ethNativeContract.collection(address, 'ft');276277    const from = helper.ethCrossAccount.fromKeyringPair(alice);278    const to = helper.ethCrossAccount.fromAddress(receiver);279280    const fromBalanceBefore = await collection.getBalance({Substrate: alice.address});281    const toBalanceBefore = await collection.getBalance({Ethereum: receiver});282    283    const result = await contract.methods.transferFromCross(from, to, 51).send({from: sender});284285    expect(result.events).to.be.like({286      Transfer: {287        address,288        event: 'Transfer',289        returnValues: {290          from: helper.address.substrateToEth(alice.address),291          to: receiver,292          value: '51',293        },294      },295      Approval: {296        address,297        event: 'Approval',298        returnValues: {299          owner: helper.address.substrateToEth(alice.address),300          spender: sender,301          value: '49',302        },303      }});304305    const fromBalanceAfter = await collection.getBalance({Substrate: alice.address});306    expect(fromBalanceBefore - fromBalanceAfter).to.be.eq(51n);307    const toBalanceAfter = await collection.getBalance({Ethereum: receiver});308    expect(toBalanceAfter - toBalanceBefore).to.be.eq(51n);309  });310});311312describe('Fungible: Fees', () => {313  let donor: IKeyringPair;314  let alice: IKeyringPair;315316  before(async function() {317    await usingEthPlaygrounds(async (helper, privateKey) => {318      donor = await privateKey({filename: __filename});319      [alice] = await helper.arrange.createAccounts([20n], donor);320    });321  });322  323  itEth('approve() call fee is less than 0.2UNQ', async ({helper}) => {324    const owner = await helper.eth.createAccountWithBalance(donor);325    const spender = helper.eth.createAccount();326    const collection = await helper.ft.mintCollection(alice);327    await collection.mint(alice, 200n, {Ethereum: owner});328329    const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId);330    const contract = helper.ethNativeContract.collection(collectionAddress, 'ft', owner);331332    const cost = await helper.eth.recordCallFee(owner, () => contract.methods.approve(spender, 100).send({from: owner}));333    expect(cost < BigInt(0.2 * Number(helper.balance.getOneTokenNominal())));334  });335336  itEth('transferFrom() call fee is less than 0.2UNQ', async ({helper}) => {337    const owner = await helper.eth.createAccountWithBalance(donor);338    const spender = await helper.eth.createAccountWithBalance(donor);339    const collection = await helper.ft.mintCollection(alice);340    await collection.mint(alice, 200n, {Ethereum: owner});341342    const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId);343    const contract = helper.ethNativeContract.collection(collectionAddress, 'ft', owner);344345    await contract.methods.approve(spender, 100).send({from: owner});346347    const cost = await helper.eth.recordCallFee(spender, () => contract.methods.transferFrom(owner, spender, 100).send({from: spender}));348    expect(cost < BigInt(0.2 * Number(helper.balance.getOneTokenNominal())));349  });350351  itEth('transfer() call fee is less than 0.2UNQ', async ({helper}) => {352    const owner = await helper.eth.createAccountWithBalance(donor);353    const receiver = helper.eth.createAccount();354    const collection = await helper.ft.mintCollection(alice);355    await collection.mint(alice, 200n, {Ethereum: owner});356357    const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId);358    const contract = helper.ethNativeContract.collection(collectionAddress, 'ft', owner);359360    const cost = await helper.eth.recordCallFee(owner, () => contract.methods.transfer(receiver, 100).send({from: owner}));361    expect(cost < BigInt(0.2 * Number(helper.balance.getOneTokenNominal())));362  });363});364365describe('Fungible: Substrate calls', () => {366  let donor: IKeyringPair;367  let alice: IKeyringPair;368369  before(async function() {370    await usingEthPlaygrounds(async (helper, privateKey) => {371      donor = await privateKey({filename: __filename});372      [alice] = await helper.arrange.createAccounts([20n], donor);373    });374  });375376  itEth('Events emitted for approve()', async ({helper}) => {377    const receiver = helper.eth.createAccount();378    const collection = await helper.ft.mintCollection(alice);379    await collection.mint(alice, 200n);380381    const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId);382    const contract = helper.ethNativeContract.collection(collectionAddress, 'ft');383384    const events: any = [];385    contract.events.allEvents((_: any, event: any) => {386      events.push(event);387    });388    389    await collection.approveTokens(alice, {Ethereum: receiver}, 100n);390    if (events.length == 0) await helper.wait.newBlocks(1);391    const event = events[0];392393    expect(event.event).to.be.equal('Approval');394    expect(event.address).to.be.equal(collectionAddress);395    expect(event.returnValues.owner).to.be.equal(helper.address.substrateToEth(alice.address));396    expect(event.returnValues.spender).to.be.equal(receiver);397    expect(event.returnValues.value).to.be.equal('100');398  });399400  itEth('Events emitted for transferFrom()', async ({helper}) => {401    const [bob] = await helper.arrange.createAccounts([10n], donor);402    const receiver = helper.eth.createAccount();403    const collection = await helper.ft.mintCollection(alice);404    await collection.mint(alice, 200n);405    await collection.approveTokens(alice, {Substrate: bob.address}, 100n);406407    const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId);408    const contract = helper.ethNativeContract.collection(collectionAddress, 'ft');409410    const events: any = [];411    contract.events.allEvents((_: any, event: any) => {412      events.push(event);413    });414415    await collection.transferFrom(bob, {Substrate: alice.address}, {Ethereum: receiver}, 51n);416    if (events.length == 0) await helper.wait.newBlocks(1);417    let event = events[0];418419    expect(event.event).to.be.equal('Transfer');420    expect(event.address).to.be.equal(collectionAddress);421    expect(event.returnValues.from).to.be.equal(helper.address.substrateToEth(alice.address));422    expect(event.returnValues.to).to.be.equal(receiver);423    expect(event.returnValues.value).to.be.equal('51');424425    event = events[1];426    expect(event.event).to.be.equal('Approval');427    expect(event.address).to.be.equal(collectionAddress);428    expect(event.returnValues.owner).to.be.equal(helper.address.substrateToEth(alice.address));429    expect(event.returnValues.spender).to.be.equal(helper.address.substrateToEth(bob.address));430    expect(event.returnValues.value).to.be.equal('49');431  });432433  itEth('Events emitted for transfer()', async ({helper}) => {434    const receiver = helper.eth.createAccount();435    const collection = await helper.ft.mintCollection(alice);436    await collection.mint(alice, 200n);437438    const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId);439    const contract = helper.ethNativeContract.collection(collectionAddress, 'ft');440441    const events: any = [];442    contract.events.allEvents((_: any, event: any) => {443      events.push(event);444    });445    446    await collection.transfer(alice, {Ethereum:receiver}, 51n);447    if (events.length == 0) await helper.wait.newBlocks(1);448    const event = events[0];449450    expect(event.event).to.be.equal('Transfer');451    expect(event.address).to.be.equal(collectionAddress);452    expect(event.returnValues.from).to.be.equal(helper.address.substrateToEth(alice.address));453    expect(event.returnValues.to).to.be.equal(receiver);454    expect(event.returnValues.value).to.be.equal('51');455  });456457  itEth('Events emitted for transferFromCross()', async ({helper, privateKey}) => {458    const alice = privateKey('//Alice');459    const sender = await helper.eth.createAccountWithBalance(alice, 100n);460461    const collection = await helper.ft.mintCollection(alice, {name: 'A', description: 'B', tokenPrefix: 'C'}, 0);462463    const receiver = helper.eth.createAccount();464465    await collection.mint(alice, 200n, {Substrate: alice.address});466    await collection.approveTokens(alice, {Ethereum: sender}, 100n);467468    const address = helper.ethAddress.fromCollectionId(collection.collectionId);469    const contract = helper.ethNativeContract.collection(address, 'ft');470471    const from = helper.ethCrossAccount.fromKeyringPair(alice);472    const to = helper.ethCrossAccount.fromAddress(receiver);473    474    const result = await contract.methods.transferFromCross(from, to, 51).send({from: sender});475476    expect(result.events).to.be.like({477      Transfer: {478        address,479        event: 'Transfer',480        returnValues: {481          from: helper.address.substrateToEth(alice.address),482          to: receiver,483          value: '51',484        },485      },486      Approval: {487        address,488        event: 'Approval',489        returnValues: {490          owner: helper.address.substrateToEth(alice.address),491          spender: sender,492          value: '49',493        },494      }});495  });496});
modifiedtests/src/eth/nonFungible.test.tsdiffbeforeafterboth
--- a/tests/src/eth/nonFungible.test.ts
+++ b/tests/src/eth/nonFungible.test.ts
@@ -247,10 +247,10 @@
   });
 
   itEth('Can perform burnFromCross()', async ({helper, privateKey}) => {
-    const alice = await privateKey('//Alice');
+    const alice = privateKey('//Alice');
     const collection = await helper.nft.mintCollection(alice, {name: 'A', description: 'B', tokenPrefix: 'C'});
 
-    const owner = await privateKey('//Bob');
+    const owner = privateKey('//Bob');
     const spender = await helper.eth.createAccountWithBalance(alice, 100n);
 
     const token = await collection.mintToken(alice, {Substrate: owner.address});
@@ -277,11 +277,11 @@
   });
 
   itEth('Can perform approveCross()', async ({helper, privateKey}) => {
-    const alice = await privateKey('//Alice');
+    const alice = privateKey('//Alice');
     const collection = await helper.nft.mintCollection(alice, {name: 'A', description: 'B', tokenPrefix: 'C'});
 
     const owner = await helper.eth.createAccountWithBalance(alice, 100n);
-    const receiver = await privateKey('//Charlie');
+    const receiver = privateKey('//Charlie');
 
     const token = await collection.mintToken(alice, {Ethereum: owner});
 
@@ -410,12 +410,12 @@
   });
 
   itEth('Can perform transferFromCross()', async ({helper, privateKey}) => {
-    const alice = await privateKey('//Alice');
+    const alice = privateKey('//Alice');
     const collection = await helper.nft.mintCollection(alice, {name: 'A', description: 'B', tokenPrefix: 'C'});
 
-    const owner = await privateKey('//Bob');
+    const owner = privateKey('//Bob');
     const spender = await helper.eth.createAccountWithBalance(alice, 100n);
-    const receiver = await privateKey('//Charlie');
+    const receiver = privateKey('//Charlie');
 
     const token = await collection.mintToken(alice, {Substrate: owner.address});
 
modifiedtests/src/eth/reFungible.test.tsdiffbeforeafterboth
--- a/tests/src/eth/reFungible.test.ts
+++ b/tests/src/eth/reFungible.test.ts
@@ -228,7 +228,7 @@
   });
 
   itEth('Can perform burnFrom()', async ({helper, privateKey}) => {
-    const alice = await privateKey('//Alice');
+    const alice = privateKey('//Alice');
     const collection = await helper.rft.mintCollection(alice, {name: 'A', description: 'B', tokenPrefix: 'C'});
 
     const owner = await helper.eth.createAccountWithBalance(alice, 100n);
@@ -262,10 +262,10 @@
   });
 
   itEth('Can perform burnFromCross()', async ({helper, privateKey}) => {
-    const alice = await privateKey('//Alice');
+    const alice = privateKey('//Alice');
     const collection = await helper.rft.mintCollection(alice, {name: 'A', description: 'B', tokenPrefix: 'C'});
 
-    const owner = await privateKey('//Bob');
+    const owner = privateKey('//Bob');
     const spender = await helper.eth.createAccountWithBalance(alice, 100n);
 
     const token = await collection.mintToken(alice, 100n, {Substrate: owner.address});
@@ -295,12 +295,12 @@
   });
 
   itEth('Can perform transferFromCross()', async ({helper, privateKey}) => {
-    const alice = await privateKey('//Alice');
+    const alice = privateKey('//Alice');
     const collection = await helper.rft.mintCollection(alice, {name: 'A', description: 'B', tokenPrefix: 'C'});
 
-    const owner = await privateKey('//Bob');
+    const owner = privateKey('//Bob');
     const spender = await helper.eth.createAccountWithBalance(alice, 100n);
-    const receiver = await privateKey('//Charlie');
+    const receiver = privateKey('//Charlie');
 
     const token = await collection.mintToken(alice, 100n, {Substrate: owner.address});
 
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
@@ -381,6 +381,46 @@
   }
 }
 
+export class EthCrossAccountGroup extends EthGroupBase {
+  fromAddress(address: TEthereumAccount): TEthCrossAccount {
+    return {
+      0: address,
+      1: '0',
+      field_0: address,
+      field_1: '0',
+    };
+  }
+
+  fromKeyringPair(keyring: IKeyringPair): TEthCrossAccount {
+    return {
+      0: '0x0000000000000000000000000000000000000000',
+      1: keyring.addressRaw,
+      field_0: '0x0000000000000000000000000000000000000000',
+      field_1: keyring.addressRaw,
+    };
+  }
+}
+
+export class EthCrossAccountGroup extends EthGroupBase {
+  fromAddress(address: TEthereumAccount): TEthCrossAccount {
+    return {
+      0: address,
+      1: '0',
+      field_0: address,
+      field_1: '0',
+    };
+  }
+
+  fromKeyringPair(keyring: IKeyringPair): TEthCrossAccount {
+    return {
+      0: '0x0000000000000000000000000000000000000000',
+      1: keyring.addressRaw,
+      field_0: '0x0000000000000000000000000000000000000000',
+      field_1: keyring.addressRaw,
+    };
+  }
+}
+
 export class EthUniqueHelper extends DevUniqueHelper {
   web3: Web3 | null = null;
   web3Provider: WebsocketProvider | null = null;