--- a/pallets/fungible/src/erc.rs +++ b/pallets/fungible/src/erc.rs @@ -327,6 +327,15 @@ fn collection_helper_address(&self) -> Result
{ Ok(T::ContractAddress::get()) } + + /// @notice Balance of account + /// @param owner An cross address for whom to query the balance + /// @return The number of fingibles owned by `owner`, possibly zero + fn balance_of_cross(&self, owner: CrossAddress) -> Result { + self.consume_store_reads(1)?; + let balance = >::get((self.id, owner.into_sub_cross_account::()?)); + Ok(balance.into()) + } } #[solidity_interface( --- a/pallets/fungible/src/stubs/UniqueFungible.sol +++ b/pallets/fungible/src/stubs/UniqueFungible.sol @@ -511,7 +511,7 @@ bytes value; } -/// @dev the ERC-165 identifier for this interface is 0x85d7dea6 +/// @dev the ERC-165 identifier for this interface is 0x69d14d3e contract ERC20UniqueExtensions is Dummy, ERC165 { /// @dev Function to check the amount of tokens that an owner allowed to a spender. /// @param owner crossAddress The address which owns the funds. @@ -630,6 +630,18 @@ dummy; return 0x0000000000000000000000000000000000000000; } + + /// @notice Balance of account + /// @param owner An cross address for whom to query the balance + /// @return The number of fingibles owned by `owner`, possibly zero + /// @dev EVM selector for this function is: 0xec069398, + /// or in textual repr: balanceOfCross((address,uint256)) + function balanceOfCross(CrossAddress memory owner) public view returns (uint256) { + require(false, stub_error); + owner; + dummy; + return 0; + } } struct AmountForAddress { --- a/tests/src/eth/abi/fungible.json +++ b/tests/src/eth/abi/fungible.json @@ -181,6 +181,23 @@ { "internalType": "uint256", "name": "sub", "type": "uint256" } ], "internalType": "struct CrossAddress", + "name": "owner", + "type": "tuple" + } + ], + "name": "balanceOfCross", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { "internalType": "address", "name": "eth", "type": "address" }, + { "internalType": "uint256", "name": "sub", "type": "uint256" } + ], + "internalType": "struct CrossAddress", "name": "from", "type": "tuple" }, --- a/tests/src/eth/api/UniqueFungible.sol +++ b/tests/src/eth/api/UniqueFungible.sol @@ -353,7 +353,7 @@ bytes value; } -/// @dev the ERC-165 identifier for this interface is 0x85d7dea6 +/// @dev the ERC-165 identifier for this interface is 0x69d14d3e interface ERC20UniqueExtensions is Dummy, ERC165 { /// @dev Function to check the amount of tokens that an owner allowed to a spender. /// @param owner crossAddress The address which owns the funds. @@ -416,6 +416,13 @@ /// @dev EVM selector for this function is: 0x1896cce6, /// or in textual repr: collectionHelperAddress() function collectionHelperAddress() external view returns (address); + + /// @notice Balance of account + /// @param owner An cross address for whom to query the balance + /// @return The number of fingibles owned by `owner`, possibly zero + /// @dev EVM selector for this function is: 0xec069398, + /// or in textual repr: balanceOfCross((address,uint256)) + function balanceOfCross(CrossAddress memory owner) external view returns (uint256); } struct AmountForAddress { --- a/tests/src/eth/fungible.test.ts +++ b/tests/src/eth/fungible.test.ts @@ -427,6 +427,22 @@ const toBalanceAfter = await collection.getBalance({Ethereum: receiver}); expect(toBalanceAfter - toBalanceBefore).to.be.eq(51n); }); + + itEth('Check balanceOfCross()', async ({helper}) => { + const collection = await helper.ft.mintCollection(alice, {}); + const owner = await helper.ethCrossAccount.createAccountWithBalance(donor); + const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId); + const collectionEvm = await helper.ethNativeContract.collection(collectionAddress, 'ft', owner.eth); + + expect(BigInt(await collectionEvm.methods.balanceOfCross(owner).call({from: owner.eth})) === 0n).to.be.true; + + let sum = 0n; + for (let i = 1n; i < 100n; i++) { + await collection.mint(alice, 100n, {Ethereum: owner.eth}); + sum += 100n; + expect(BigInt(await collectionEvm.methods.balanceOfCross(owner).call({from: owner.eth})) === sum).to.be.true; + } + }); }); describe('Fungible: Fees', () => { --- a/tests/src/eth/reFungible.test.ts +++ b/tests/src/eth/reFungible.test.ts @@ -585,7 +585,7 @@ expect(event.returnValues.tokenId).to.equal(tokenId.toString()); }); - itEth('Check crossBalanceOf()', async ({helper}) => { + itEth('Check balanceOfCross()', async ({helper}) => { const collection = await helper.rft.mintCollection(minter, {}); const owner = await helper.ethCrossAccount.createAccountWithBalance(donor); const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId); --- a/tests/src/eth/tokens/minting.test.ts +++ b/tests/src/eth/tokens/minting.test.ts @@ -19,7 +19,7 @@ import {expect, itEth, usingEthPlaygrounds} from '../util'; -describe.only('Minting tokens', () => { +describe('Minting tokens', () => { let donor: IKeyringPair; let alice: IKeyringPair;