From 6e3cf5e45846f834d8e3d4a3c2053f34d1fc6f58 Mon Sep 17 00:00:00 2001 From: Yaroslav Bolyukin Date: Wed, 19 Apr 2023 08:05:13 +0000 Subject: [PATCH] Merge pull request #919 from UniqueNetwork/feature/crossBalanceOf --- --- 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/pallets/nonfungible/src/erc.rs +++ b/pallets/nonfungible/src/erc.rs @@ -749,12 +749,29 @@ /// Returns the owner (in cross format) of the token. /// /// @param tokenId Id for the token. + #[solidity(hide)] fn cross_owner_of(&self, token_id: U256) -> Result { + Self::owner_of_cross(&self, token_id) + } + + /// Returns the owner (in cross format) of the token. + /// + /// @param tokenId Id for the token. + fn owner_of_cross(&self, token_id: U256) -> Result { Self::token_owner(&self, token_id.try_into()?) .map(|o| eth::CrossAddress::from_sub_cross_account::(&o)) .map_err(|_| Error::Revert("token not found".into())) } + /// @notice Count all NFTs assigned to an owner + /// @param owner An cross address for whom to query the balance + /// @return The number of NFTs owned by `owner`, possibly zero + fn balance_of_cross(&self, owner: eth::CrossAddress) -> Result { + self.consume_store_reads(1)?; + let balance = >::get((self.id, owner.into_sub_cross_account::()?)); + Ok(balance.into()) + } + /// Returns the token properties. /// /// @param tokenId Id for the token. --- a/pallets/nonfungible/src/stubs/UniqueNFT.sol +++ b/pallets/nonfungible/src/stubs/UniqueNFT.sol @@ -774,7 +774,7 @@ } /// @title Unique extensions for ERC721. -/// @dev the ERC-165 identifier for this interface is 0x16de3152 +/// @dev the ERC-165 identifier for this interface is 0x307b061a contract ERC721UniqueExtensions is Dummy, ERC165 { /// @notice A descriptive name for a collection of NFTs in this contract /// @dev EVM selector for this function is: 0x06fdde03, @@ -803,18 +803,42 @@ return ""; } + // /// Returns the owner (in cross format) of the token. + // /// + // /// @param tokenId Id for the token. + // /// @dev EVM selector for this function is: 0x2b29dace, + // /// or in textual repr: crossOwnerOf(uint256) + // function crossOwnerOf(uint256 tokenId) public view returns (CrossAddress memory) { + // require(false, stub_error); + // tokenId; + // dummy; + // return CrossAddress(0x0000000000000000000000000000000000000000,0); + // } + /// Returns the owner (in cross format) of the token. /// /// @param tokenId Id for the token. - /// @dev EVM selector for this function is: 0x2b29dace, - /// or in textual repr: crossOwnerOf(uint256) - function crossOwnerOf(uint256 tokenId) public view returns (CrossAddress memory) { + /// @dev EVM selector for this function is: 0xcaa3a4d0, + /// or in textual repr: ownerOfCross(uint256) + function ownerOfCross(uint256 tokenId) public view returns (CrossAddress memory) { require(false, stub_error); tokenId; dummy; return CrossAddress(0x0000000000000000000000000000000000000000, 0); } + /// @notice Count all NFTs assigned to an owner + /// @param owner An cross address for whom to query the balance + /// @return The number of NFTs 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; + } + /// Returns the token properties. /// /// @param tokenId Id for the token. --- a/pallets/refungible/src/erc.rs +++ b/pallets/refungible/src/erc.rs @@ -783,7 +783,15 @@ /// Returns the owner (in cross format) of the token. /// /// @param tokenId Id for the token. + #[solidity(hide)] fn cross_owner_of(&self, token_id: U256) -> Result { + Self::owner_of_cross(&self, token_id) + } + + /// Returns the owner (in cross format) of the token. + /// + /// @param tokenId Id for the token. + fn owner_of_cross(&self, token_id: U256) -> Result { Self::token_owner(&self, token_id.try_into()?) .map(|o| eth::CrossAddress::from_sub_cross_account::(&o)) .or_else(|err| match err { @@ -794,6 +802,15 @@ }) } + /// @notice Count all RFTs assigned to an owner + /// @param owner An cross address for whom to query the balance + /// @return The number of RFTs owned by `owner`, possibly zero + fn balance_of_cross(&self, owner: eth::CrossAddress) -> Result { + self.consume_store_reads(1)?; + let balance = >::get((self.id, owner.into_sub_cross_account::()?)); + Ok(balance.into()) + } + /// Returns the token properties. /// /// @param tokenId Id for the token. --- a/pallets/refungible/src/erc_token.rs +++ b/pallets/refungible/src/erc_token.rs @@ -283,6 +283,16 @@ .map_err(dispatch_to_evm::)?; Ok(true) } + + /// @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, self.1, owner.into_sub_cross_account::()?)); + Ok(balance.into()) + } + /// @dev Function that changes total amount of the tokens. /// Throws if `msg.sender` doesn't owns all of the tokens. /// @param amount New total amount of the tokens. --- a/pallets/refungible/src/stubs/UniqueRefungible.sol +++ b/pallets/refungible/src/stubs/UniqueRefungible.sol @@ -774,7 +774,7 @@ } /// @title Unique extensions for ERC721. -/// @dev the ERC-165 identifier for this interface is 0xb365c124 +/// @dev the ERC-165 identifier for this interface is 0x95c0f66c contract ERC721UniqueExtensions is Dummy, ERC165 { /// @notice A descriptive name for a collection of NFTs in this contract /// @dev EVM selector for this function is: 0x06fdde03, @@ -803,18 +803,42 @@ return ""; } + // /// Returns the owner (in cross format) of the token. + // /// + // /// @param tokenId Id for the token. + // /// @dev EVM selector for this function is: 0x2b29dace, + // /// or in textual repr: crossOwnerOf(uint256) + // function crossOwnerOf(uint256 tokenId) public view returns (CrossAddress memory) { + // require(false, stub_error); + // tokenId; + // dummy; + // return CrossAddress(0x0000000000000000000000000000000000000000,0); + // } + /// Returns the owner (in cross format) of the token. /// /// @param tokenId Id for the token. - /// @dev EVM selector for this function is: 0x2b29dace, - /// or in textual repr: crossOwnerOf(uint256) - function crossOwnerOf(uint256 tokenId) public view returns (CrossAddress memory) { + /// @dev EVM selector for this function is: 0xcaa3a4d0, + /// or in textual repr: ownerOfCross(uint256) + function ownerOfCross(uint256 tokenId) public view returns (CrossAddress memory) { require(false, stub_error); tokenId; dummy; return CrossAddress(0x0000000000000000000000000000000000000000, 0); } + /// @notice Count all RFTs assigned to an owner + /// @param owner An cross address for whom to query the balance + /// @return The number of RFTs 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; + } + /// Returns the token properties. /// /// @param tokenId Id for the token. --- a/pallets/refungible/src/stubs/UniqueRefungibleToken.sol +++ b/pallets/refungible/src/stubs/UniqueRefungibleToken.sol @@ -36,7 +36,7 @@ } } -/// @dev the ERC-165 identifier for this interface is 0x01d536fc +/// @dev the ERC-165 identifier for this interface is 0xedd3a564 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. @@ -97,6 +97,18 @@ return false; } + /// @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; + } + /// @dev Function that changes total amount of the tokens. /// Throws if `msg.sender` doesn't owns all of the tokens. /// @param amount New total amount of the tokens. --- a/runtime/common/ethereum/sponsoring/refungible.rs +++ b/runtime/common/ethereum/sponsoring/refungible.rs @@ -227,6 +227,8 @@ | Symbol | Description | CrossOwnerOf { .. } + | OwnerOfCross { .. } + | BalanceOfCross { .. } | Properties { .. } | NextTokenId | TokenContractAddress { .. } @@ -341,9 +343,11 @@ ERC165Call(_, _) => None, // Not sponsored - AllowanceCross { .. } | BurnFrom { .. } | BurnFromCross { .. } | Repartition { .. } => { - None - } + AllowanceCross { .. } + | BalanceOfCross { .. } + | BurnFrom { .. } + | BurnFromCross { .. } + | Repartition { .. } => None, TransferCross { .. } | TransferFromCross { .. } => { let RefungibleTokenHandle(handle, token_id) = token; --- 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/abi/nonFungible.json +++ b/tests/src/eth/abi/nonFungible.json @@ -177,6 +177,23 @@ }, { "inputs": [ + { + "components": [ + { "internalType": "address", "name": "eth", "type": "address" }, + { "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": [ { "internalType": "uint256", "name": "tokenId", "type": "uint256" } ], "name": "burn", @@ -386,25 +403,6 @@ }, { "inputs": [ - { "internalType": "uint256", "name": "tokenId", "type": "uint256" } - ], - "name": "crossOwnerOf", - "outputs": [ - { - "components": [ - { "internalType": "address", "name": "eth", "type": "address" }, - { "internalType": "uint256", "name": "sub", "type": "uint256" } - ], - "internalType": "struct CrossAddress", - "name": "", - "type": "tuple" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ { "internalType": "string[]", "name": "keys", "type": "string[]" } ], "name": "deleteCollectionProperties", @@ -540,6 +538,25 @@ }, { "inputs": [ + { "internalType": "uint256", "name": "tokenId", "type": "uint256" } + ], + "name": "ownerOfCross", + "outputs": [ + { + "components": [ + { "internalType": "address", "name": "eth", "type": "address" }, + { "internalType": "uint256", "name": "sub", "type": "uint256" } + ], + "internalType": "struct CrossAddress", + "name": "", + "type": "tuple" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ { "internalType": "uint256", "name": "tokenId", "type": "uint256" }, { "internalType": "string[]", "name": "keys", "type": "string[]" } ], --- a/tests/src/eth/abi/reFungible.json +++ b/tests/src/eth/abi/reFungible.json @@ -159,6 +159,23 @@ }, { "inputs": [ + { + "components": [ + { "internalType": "address", "name": "eth", "type": "address" }, + { "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": [ { "internalType": "uint256", "name": "tokenId", "type": "uint256" } ], "name": "burn", @@ -368,25 +385,6 @@ }, { "inputs": [ - { "internalType": "uint256", "name": "tokenId", "type": "uint256" } - ], - "name": "crossOwnerOf", - "outputs": [ - { - "components": [ - { "internalType": "address", "name": "eth", "type": "address" }, - { "internalType": "uint256", "name": "sub", "type": "uint256" } - ], - "internalType": "struct CrossAddress", - "name": "", - "type": "tuple" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ { "internalType": "string[]", "name": "keys", "type": "string[]" } ], "name": "deleteCollectionProperties", @@ -522,6 +520,25 @@ }, { "inputs": [ + { "internalType": "uint256", "name": "tokenId", "type": "uint256" } + ], + "name": "ownerOfCross", + "outputs": [ + { + "components": [ + { "internalType": "address", "name": "eth", "type": "address" }, + { "internalType": "uint256", "name": "sub", "type": "uint256" } + ], + "internalType": "struct CrossAddress", + "name": "", + "type": "tuple" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ { "internalType": "uint256", "name": "tokenId", "type": "uint256" }, { "internalType": "string[]", "name": "keys", "type": "string[]" } ], --- a/tests/src/eth/abi/reFungibleToken.json +++ b/tests/src/eth/abi/reFungibleToken.json @@ -130,6 +130,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/api/UniqueNFT.sol +++ b/tests/src/eth/api/UniqueNFT.sol @@ -533,7 +533,7 @@ } /// @title Unique extensions for ERC721. -/// @dev the ERC-165 identifier for this interface is 0x16de3152 +/// @dev the ERC-165 identifier for this interface is 0x307b061a interface ERC721UniqueExtensions is Dummy, ERC165 { /// @notice A descriptive name for a collection of NFTs in this contract /// @dev EVM selector for this function is: 0x06fdde03, @@ -550,12 +550,26 @@ /// or in textual repr: description() function description() external view returns (string memory); + // /// Returns the owner (in cross format) of the token. + // /// + // /// @param tokenId Id for the token. + // /// @dev EVM selector for this function is: 0x2b29dace, + // /// or in textual repr: crossOwnerOf(uint256) + // function crossOwnerOf(uint256 tokenId) external view returns (CrossAddress memory); + /// Returns the owner (in cross format) of the token. /// /// @param tokenId Id for the token. - /// @dev EVM selector for this function is: 0x2b29dace, - /// or in textual repr: crossOwnerOf(uint256) - function crossOwnerOf(uint256 tokenId) external view returns (CrossAddress memory); + /// @dev EVM selector for this function is: 0xcaa3a4d0, + /// or in textual repr: ownerOfCross(uint256) + function ownerOfCross(uint256 tokenId) external view returns (CrossAddress memory); + + /// @notice Count all NFTs assigned to an owner + /// @param owner An cross address for whom to query the balance + /// @return The number of NFTs 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); /// Returns the token properties. /// --- a/tests/src/eth/api/UniqueRefungible.sol +++ b/tests/src/eth/api/UniqueRefungible.sol @@ -533,7 +533,7 @@ } /// @title Unique extensions for ERC721. -/// @dev the ERC-165 identifier for this interface is 0xb365c124 +/// @dev the ERC-165 identifier for this interface is 0x95c0f66c interface ERC721UniqueExtensions is Dummy, ERC165 { /// @notice A descriptive name for a collection of NFTs in this contract /// @dev EVM selector for this function is: 0x06fdde03, @@ -550,12 +550,26 @@ /// or in textual repr: description() function description() external view returns (string memory); + // /// Returns the owner (in cross format) of the token. + // /// + // /// @param tokenId Id for the token. + // /// @dev EVM selector for this function is: 0x2b29dace, + // /// or in textual repr: crossOwnerOf(uint256) + // function crossOwnerOf(uint256 tokenId) external view returns (CrossAddress memory); + /// Returns the owner (in cross format) of the token. /// /// @param tokenId Id for the token. - /// @dev EVM selector for this function is: 0x2b29dace, - /// or in textual repr: crossOwnerOf(uint256) - function crossOwnerOf(uint256 tokenId) external view returns (CrossAddress memory); + /// @dev EVM selector for this function is: 0xcaa3a4d0, + /// or in textual repr: ownerOfCross(uint256) + function ownerOfCross(uint256 tokenId) external view returns (CrossAddress memory); + + /// @notice Count all RFTs assigned to an owner + /// @param owner An cross address for whom to query the balance + /// @return The number of RFTs 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); /// Returns the token properties. /// --- a/tests/src/eth/api/UniqueRefungibleToken.sol +++ b/tests/src/eth/api/UniqueRefungibleToken.sol @@ -23,7 +23,7 @@ function parentTokenId() external view returns (uint256); } -/// @dev the ERC-165 identifier for this interface is 0x01d536fc +/// @dev the ERC-165 identifier for this interface is 0xedd3a564 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. @@ -60,6 +60,13 @@ /// or in textual repr: approveCross((address,uint256),uint256) function approveCross(CrossAddress memory spender, uint256 amount) external returns (bool); + /// @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); + /// @dev Function that changes total amount of the tokens. /// Throws if `msg.sender` doesn't owns all of the tokens. /// @param amount New total amount of the tokens. --- a/tests/src/eth/fungible.test.ts +++ b/tests/src/eth/fungible.test.ts @@ -427,6 +427,33 @@ 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 other = await helper.ethCrossAccount.createAccountWithBalance(donor); + const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId); + const collectionEvm = await helper.ethNativeContract.collection(collectionAddress, 'ft', owner.eth); + + expect(await collectionEvm.methods.balanceOfCross(owner).call({from: owner.eth})).to.be.eq('0'); + expect(await collectionEvm.methods.balanceOfCross(other).call({from: owner.eth})).to.be.eq('0'); + + await collection.mint(alice, 100n, {Ethereum: owner.eth}); + expect(await collectionEvm.methods.balanceOfCross(owner).call({from: owner.eth})).to.be.eq('100'); + expect(await collectionEvm.methods.balanceOfCross(other).call({from: owner.eth})).to.be.eq('0'); + + await collectionEvm.methods.transferCross(other, 50n).send({from: owner.eth}); + expect(await collectionEvm.methods.balanceOfCross(owner).call({from: owner.eth})).to.be.eq('50'); + expect(await collectionEvm.methods.balanceOfCross(other).call({from: owner.eth})).to.be.eq('50'); + + await collectionEvm.methods.transferCross(other, 50n).send({from: owner.eth}); + expect(await collectionEvm.methods.balanceOfCross(owner).call({from: owner.eth})).to.be.eq('0'); + expect(await collectionEvm.methods.balanceOfCross(other).call({from: owner.eth})).to.be.eq('100'); + + await collectionEvm.methods.transferCross(owner, 100n).send({from: other.eth}); + expect(await collectionEvm.methods.balanceOfCross(owner).call({from: owner.eth})).to.be.eq('100'); + expect(await collectionEvm.methods.balanceOfCross(other).call({from: owner.eth})).to.be.eq('0'); + }); }); describe('Fungible: Fees', () => { --- a/tests/src/eth/nonFungible.test.ts +++ b/tests/src/eth/nonFungible.test.ts @@ -662,6 +662,38 @@ // Cannot transfer token if it does not exist: await expect(collectionEvm.methods[testCase](receiver, 999999).send({from: sender})).to.be.rejected; })); + + itEth('Check balanceOfCross()', async ({helper}) => { + const collection = await helper.nft.mintCollection(minter, {}); + const owner = await helper.ethCrossAccount.createAccountWithBalance(donor); + const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId); + const collectionEvm = await helper.ethNativeContract.collection(collectionAddress, 'nft', owner.eth); + + expect(await collectionEvm.methods.balanceOfCross(owner).call({from: owner.eth})).to.be.eq('0'); + + for (let i = 1; i < 10; i++) { + await collection.mintToken(minter, {Ethereum: owner.eth}); + expect(await collectionEvm.methods.balanceOfCross(owner).call({from: owner.eth})).to.be.eq(i.toString()); + } + }); + + itEth('Check ownerOfCross()', async ({helper}) => { + const collection = await helper.nft.mintCollection(minter, {}); + let owner = await helper.ethCrossAccount.createAccountWithBalance(donor); + const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId); + const collectionEvm = await helper.ethNativeContract.collection(collectionAddress, 'nft', owner.eth); + const {tokenId} = await collection.mintToken(minter, {Ethereum: owner.eth}); + + for (let i = 1n; i < 10n; i++) { + const ownerCross = await collectionEvm.methods.ownerOfCross(tokenId).call({from: owner.eth}); + expect(ownerCross.eth).to.be.eq(owner.eth); + expect(ownerCross.sub).to.be.eq(owner.sub); + + const newOwner = await helper.ethCrossAccount.createAccountWithBalance(donor); + await collectionEvm.methods.transferCross(newOwner, tokenId).send({from: owner.eth}); + owner = newOwner; + } + }); }); describe('NFT: Fees', () => { --- a/tests/src/eth/reFungible.test.ts +++ b/tests/src/eth/reFungible.test.ts @@ -584,6 +584,46 @@ expect(event.returnValues.to).to.equal('0xFFfFfFffFFfffFFfFFfFFFFFffFFFffffFfFFFfF'); expect(event.returnValues.tokenId).to.equal(tokenId.toString()); }); + + 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); + const collectionEvm = await helper.ethNativeContract.collection(collectionAddress, 'nft', owner.eth); + + expect(await collectionEvm.methods.balanceOfCross(owner).call({from: owner.eth})).to.be.eq('0'); + + for (let i = 1n; i < 10n; i++) { + await collection.mintToken(minter, 100n, {Ethereum: owner.eth}); + expect(await collectionEvm.methods.balanceOfCross(owner).call({from: owner.eth})).to.be.eq(i.toString()); + } + }); + + itEth('Check ownerOfCross()', async ({helper}) => { + const collection = await helper.rft.mintCollection(minter, {}); + let owner = await helper.ethCrossAccount.createAccountWithBalance(donor); + const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId); + const collectionEvm = await helper.ethNativeContract.collection(collectionAddress, 'nft', owner.eth); + const {tokenId} = await collection.mintToken(minter, 100n,{Ethereum: owner.eth}); + + for (let i = 1n; i < 10n; i++) { + const ownerCross = await collectionEvm.methods.ownerOfCross(tokenId).call({from: owner.eth}); + expect(ownerCross.eth).to.be.eq(owner.eth); + expect(ownerCross.sub).to.be.eq(owner.sub); + + const newOwner = await helper.ethCrossAccount.createAccountWithBalance(donor); + await collectionEvm.methods.transferCross(newOwner, tokenId).send({from: owner.eth}); + owner = newOwner; + } + + const tokenAddress = helper.ethAddress.fromTokenId(collection.collectionId, tokenId); + const tokenContract = await helper.ethNativeContract.rftToken(tokenAddress, owner.eth, true); + const newOwner = await helper.ethCrossAccount.createAccountWithBalance(donor); + await tokenContract.methods.transferCross(newOwner, 50).send({from: owner.eth}); + const ownerCross = await collectionEvm.methods.ownerOfCross(tokenId).call({from: owner.eth}); + expect(ownerCross.eth.toUpperCase()).to.be.eq('0XFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF'); + expect(ownerCross.sub).to.be.eq('0'); + }); }); describe('RFT: Fees', () => { --- a/tests/src/eth/reFungibleToken.test.ts +++ b/tests/src/eth/reFungibleToken.test.ts @@ -466,6 +466,35 @@ expect(await collection.getTokenBalance(tokenId, {Substrate: ownerSub.address})).to.be.equal(150n); } }); + + itEth('Check balanceOfCross()', async ({helper}) => { + const collection = await helper.rft.mintCollection(alice, {}); + const owner = await helper.ethCrossAccount.createAccountWithBalance(donor); + const other = await helper.ethCrossAccount.createAccountWithBalance(donor); + const {tokenId} = await collection.mintToken(alice, 200n, {Ethereum: owner.eth}); + const tokenAddress = helper.ethAddress.fromTokenId(collection.collectionId, tokenId); + const tokenContract = await helper.ethNativeContract.rftToken(tokenAddress, owner.eth); + + expect(await tokenContract.methods.balanceOfCross(owner).call({from: owner.eth})).to.be.eq('200'); + expect(await tokenContract.methods.balanceOfCross(other).call({from: owner.eth})).to.be.eq('0'); + + await tokenContract.methods.repartition(100n).send({from: owner.eth}); + expect(await tokenContract.methods.balanceOfCross(owner).call({from: owner.eth})).to.be.eq('100'); + expect(await tokenContract.methods.balanceOfCross(other).call({from: owner.eth})).to.be.eq('0'); + + await tokenContract.methods.transferCross(other, 50n).send({from: owner.eth}); + expect(await tokenContract.methods.balanceOfCross(owner).call({from: owner.eth})).to.be.eq('50'); + expect(await tokenContract.methods.balanceOfCross(other).call({from: owner.eth})).to.be.eq('50'); + + await tokenContract.methods.transferCross(other, 50n).send({from: owner.eth}); + expect(await tokenContract.methods.balanceOfCross(owner).call({from: owner.eth})).to.be.eq('0'); + expect(await tokenContract.methods.balanceOfCross(other).call({from: owner.eth})).to.be.eq('100'); + + await tokenContract.methods.repartition(1000n).send({from: other.eth}); + await tokenContract.methods.transferCross(owner, 500n).send({from: other.eth}); + expect(await tokenContract.methods.balanceOfCross(owner).call({from: owner.eth})).to.be.eq('500'); + expect(await tokenContract.methods.balanceOfCross(other).call({from: owner.eth})).to.be.eq('500'); + }); }); describe('Refungible: Fees', () => { --- a/tests/src/eth/tokens/minting.test.ts +++ b/tests/src/eth/tokens/minting.test.ts @@ -63,7 +63,7 @@ const tokenId = event.returnValues.tokenId; expect(tokenId).to.be.equal('1'); expect(await helper.collection.getLastTokenId(collection.collectionId)).to.eq(1); - expect(await contract.methods.crossOwnerOf(tokenId).call()).to.be.like([receiver, '0']); + expect(await contract.methods.ownerOfCross(tokenId).call()).to.be.like([receiver, '0']); } }); }); @@ -97,7 +97,7 @@ const tokenId = event.returnValues.tokenId; expect(tokenId).to.be.equal('1'); expect(await helper.collection.getLastTokenId(collectionId)).to.eq(1); - expect(await collection.methods.crossOwnerOf(tokenId).call()).to.be.like([receiver, '0']); + expect(await collection.methods.ownerOfCross(tokenId).call()).to.be.like([receiver, '0']); } }); }); @@ -131,7 +131,7 @@ const tokenId = event.returnValues.tokenId; expect(tokenId).to.be.equal('1'); expect(await helper.collection.getLastTokenId(collectionId)).to.eq(1); - expect(await collection.methods.crossOwnerOf(tokenId).call()).to.be.like([receiver, '0']); + expect(await collection.methods.ownerOfCross(tokenId).call()).to.be.like([receiver, '0']); } }); }); @@ -157,7 +157,7 @@ expect(event.returnValues.to).to.be.equal(receiver); expect(await contract.methods.tokenURI(tokenId).call()).to.be.equal('Test URI'); - expect(await contract.methods.crossOwnerOf(tokenId).call()).to.be.like([receiver, '0']); + expect(await contract.methods.ownerOfCross(tokenId).call()).to.be.like([receiver, '0']); // TODO: this wont work right now, need release 919000 first // await helper.methods.setOffchainSchema(collectionIdAddress, 'https://offchain-service.local/token-info/{id}').send(); // const tokenUri = await contract.methods.tokenURI(nextTokenId).call(); -- gitstuff