difftreelog
add `collectionHelperAddress` method to `ERC721` & `ERC20` interfaces.
in: master
14 files changed
pallets/fungible/src/erc.rsdiffbeforeafterboth1// 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/>.1617//! ERC-20 standart support implementation.1819extern crate alloc;20use core::char::{REPLACEMENT_CHARACTER, decode_utf16};21use core::convert::TryInto;22use evm_coder::{23 abi::AbiType, ToLog, execution::*, generate_stubgen, solidity, solidity_interface, types::*,24 weight,25};26use up_data_structs::CollectionMode;27use pallet_common::erc::{CommonEvmHandler, PrecompileResult};28use sp_std::vec::Vec;29use pallet_evm::{account::CrossAccountId, PrecompileHandle};30use pallet_evm_coder_substrate::{call, dispatch_to_evm};31use pallet_structure::{SelfWeightOf as StructureWeight, weights::WeightInfo as _};32use pallet_common::{CollectionHandle, erc::CollectionCall};33use sp_core::Get;3435use crate::{36 Allowance, Balance, Config, FungibleHandle, Pallet, SelfWeightOf, TotalSupply,37 weights::WeightInfo,38};3940#[derive(ToLog)]41pub enum ERC20Events {42 Transfer {43 #[indexed]44 from: address,45 #[indexed]46 to: address,47 value: uint256,48 },49 Approval {50 #[indexed]51 owner: address,52 #[indexed]53 spender: address,54 value: uint256,55 },56}5758#[solidity_interface(name = ERC20, events(ERC20Events))]59impl<T: Config> FungibleHandle<T> {60 fn name(&self) -> Result<string> {61 Ok(decode_utf16(self.name.iter().copied())62 .map(|r| r.unwrap_or(REPLACEMENT_CHARACTER))63 .collect::<string>())64 }65 fn symbol(&self) -> Result<string> {66 Ok(string::from_utf8_lossy(&self.token_prefix).into())67 }68 fn total_supply(&self) -> Result<uint256> {69 self.consume_store_reads(1)?;70 Ok(<TotalSupply<T>>::get(self.id).into())71 }7273 fn decimals(&self) -> Result<uint8> {74 Ok(if let CollectionMode::Fungible(decimals) = &self.mode {75 *decimals76 } else {77 unreachable!()78 })79 }80 fn balance_of(&self, owner: address) -> Result<uint256> {81 self.consume_store_reads(1)?;82 let owner = T::CrossAccountId::from_eth(owner);83 let balance = <Balance<T>>::get((self.id, owner));84 Ok(balance.into())85 }86 #[weight(<SelfWeightOf<T>>::transfer())]87 fn transfer(&mut self, caller: caller, to: address, amount: uint256) -> Result<bool> {88 let caller = T::CrossAccountId::from_eth(caller);89 let to = T::CrossAccountId::from_eth(to);90 let amount = amount.try_into().map_err(|_| "amount overflow")?;91 let budget = self92 .recorder93 .weight_calls_budget(<StructureWeight<T>>::find_parent());9495 <Pallet<T>>::transfer(self, &caller, &to, amount, &budget).map_err(|_| "transfer error")?;96 Ok(true)97 }9899 #[weight(<SelfWeightOf<T>>::transfer_from())]100 fn transfer_from(101 &mut self,102 caller: caller,103 from: address,104 to: address,105 amount: uint256,106 ) -> Result<bool> {107 let caller = T::CrossAccountId::from_eth(caller);108 let from = T::CrossAccountId::from_eth(from);109 let to = T::CrossAccountId::from_eth(to);110 let amount = amount.try_into().map_err(|_| "amount overflow")?;111 let budget = self112 .recorder113 .weight_calls_budget(<StructureWeight<T>>::find_parent());114115 <Pallet<T>>::transfer_from(self, &caller, &from, &to, amount, &budget)116 .map_err(dispatch_to_evm::<T>)?;117 Ok(true)118 }119 #[weight(<SelfWeightOf<T>>::approve())]120 fn approve(&mut self, caller: caller, spender: address, amount: uint256) -> Result<bool> {121 let caller = T::CrossAccountId::from_eth(caller);122 let spender = T::CrossAccountId::from_eth(spender);123 let amount = amount.try_into().map_err(|_| "amount overflow")?;124125 <Pallet<T>>::set_allowance(self, &caller, &spender, amount)126 .map_err(dispatch_to_evm::<T>)?;127 Ok(true)128 }129 fn allowance(&self, owner: address, spender: address) -> Result<uint256> {130 self.consume_store_reads(1)?;131 let owner = T::CrossAccountId::from_eth(owner);132 let spender = T::CrossAccountId::from_eth(spender);133134 Ok(<Allowance<T>>::get((self.id, owner, spender)).into())135 }136137 /// @notice Returns collection helper contract address138 fn collection_helper_address(&self) -> Result<address> {139 Ok(T::ContractAddress::get())140 }141}142143#[solidity_interface(name = ERC20Mintable)]144impl<T: Config> FungibleHandle<T> {145 /// Mint tokens for `to` account.146 /// @param to account that will receive minted tokens147 /// @param amount amount of tokens to mint148 #[weight(<SelfWeightOf<T>>::create_item())]149 fn mint(&mut self, caller: caller, to: address, amount: uint256) -> Result<bool> {150 let caller = T::CrossAccountId::from_eth(caller);151 let to = T::CrossAccountId::from_eth(to);152 let amount = amount.try_into().map_err(|_| "amount overflow")?;153 let budget = self154 .recorder155 .weight_calls_budget(<StructureWeight<T>>::find_parent());156 <Pallet<T>>::create_item(&self, &caller, (to, amount), &budget)157 .map_err(dispatch_to_evm::<T>)?;158 Ok(true)159 }160}161162#[solidity_interface(name = ERC20UniqueExtensions)]163impl<T: Config> FungibleHandle<T>164where165 T::AccountId: From<[u8; 32]>,166{167 /// @notice A description for the collection.168 fn description(&self) -> Result<string> {169 Ok(decode_utf16(self.description.iter().copied())170 .map(|r| r.unwrap_or(REPLACEMENT_CHARACTER))171 .collect::<string>())172 }173174 #[weight(<SelfWeightOf<T>>::approve())]175 fn approve_cross(176 &mut self,177 caller: caller,178 spender: EthCrossAccount,179 amount: uint256,180 ) -> Result<bool> {181 let caller = T::CrossAccountId::from_eth(caller);182 let spender = spender.into_sub_cross_account::<T>()?;183 let amount = amount.try_into().map_err(|_| "amount overflow")?;184185 <Pallet<T>>::set_allowance(self, &caller, &spender, amount)186 .map_err(dispatch_to_evm::<T>)?;187 Ok(true)188 }189190 /// Burn tokens from account191 /// @dev Function that burns an `amount` of the tokens of a given account,192 /// deducting from the sender's allowance for said account.193 /// @param from The account whose tokens will be burnt.194 /// @param amount The amount that will be burnt.195 #[solidity(hide)]196 #[weight(<SelfWeightOf<T>>::burn_from())]197 fn burn_from(&mut self, caller: caller, from: address, amount: uint256) -> Result<bool> {198 let caller = T::CrossAccountId::from_eth(caller);199 let from = T::CrossAccountId::from_eth(from);200 let amount = amount.try_into().map_err(|_| "amount overflow")?;201 let budget = self202 .recorder203 .weight_calls_budget(<StructureWeight<T>>::find_parent());204205 <Pallet<T>>::burn_from(self, &caller, &from, amount, &budget)206 .map_err(dispatch_to_evm::<T>)?;207 Ok(true)208 }209210 /// Burn tokens from account211 /// @dev Function that burns an `amount` of the tokens of a given account,212 /// deducting from the sender's allowance for said account.213 /// @param from The account whose tokens will be burnt.214 /// @param amount The amount that will be burnt.215 #[weight(<SelfWeightOf<T>>::burn_from())]216 fn burn_from_cross(217 &mut self,218 caller: caller,219 from: EthCrossAccount,220 amount: uint256,221 ) -> Result<bool> {222 let caller = T::CrossAccountId::from_eth(caller);223 let from = from.into_sub_cross_account::<T>()?;224 let amount = amount.try_into().map_err(|_| "amount overflow")?;225 let budget = self226 .recorder227 .weight_calls_budget(<StructureWeight<T>>::find_parent());228229 <Pallet<T>>::burn_from(self, &caller, &from, amount, &budget)230 .map_err(dispatch_to_evm::<T>)?;231 Ok(true)232 }233234 /// Mint tokens for multiple accounts.235 /// @param amounts array of pairs of account address and amount236 #[weight(<SelfWeightOf<T>>::create_multiple_items_ex(amounts.len() as u32))]237 fn mint_bulk(&mut self, caller: caller, amounts: Vec<(address, uint256)>) -> Result<bool> {238 let caller = T::CrossAccountId::from_eth(caller);239 let budget = self240 .recorder241 .weight_calls_budget(<StructureWeight<T>>::find_parent());242 let amounts = amounts243 .into_iter()244 .map(|(to, amount)| {245 Ok((246 T::CrossAccountId::from_eth(to),247 amount.try_into().map_err(|_| "amount overflow")?,248 ))249 })250 .collect::<Result<_>>()?;251252 <Pallet<T>>::create_multiple_items(&self, &caller, amounts, &budget)253 .map_err(dispatch_to_evm::<T>)?;254 Ok(true)255 }256257 #[weight(<SelfWeightOf<T>>::transfer())]258 fn transfer_cross(259 &mut self,260 caller: caller,261 to: EthCrossAccount,262 amount: uint256,263 ) -> Result<bool> {264 let caller = T::CrossAccountId::from_eth(caller);265 let to = to.into_sub_cross_account::<T>()?;266 let amount = amount.try_into().map_err(|_| "amount overflow")?;267 let budget = self268 .recorder269 .weight_calls_budget(<StructureWeight<T>>::find_parent());270271 <Pallet<T>>::transfer(self, &caller, &to, amount, &budget).map_err(|_| "transfer error")?;272 Ok(true)273 }274275 #[weight(<SelfWeightOf<T>>::transfer_from())]276 fn transfer_from_cross(277 &mut self,278 caller: caller,279 from: EthCrossAccount,280 to: EthCrossAccount,281 amount: uint256,282 ) -> Result<bool> {283 let caller = T::CrossAccountId::from_eth(caller);284 let from = from.into_sub_cross_account::<T>()?;285 let to = to.into_sub_cross_account::<T>()?;286 let amount = amount.try_into().map_err(|_| "amount overflow")?;287 let budget = self288 .recorder289 .weight_calls_budget(<StructureWeight<T>>::find_parent());290291 <Pallet<T>>::transfer_from(self, &caller, &from, &to, amount, &budget)292 .map_err(dispatch_to_evm::<T>)?;293 Ok(true)294 }295}296297#[solidity_interface(298 name = UniqueFungible,299 is(300 ERC20,301 ERC20Mintable,302 ERC20UniqueExtensions,303 Collection(via(common_mut returns CollectionHandle<T>)),304 )305)]306impl<T: Config> FungibleHandle<T> where T::AccountId: From<[u8; 32]> + AsRef<[u8; 32]> {}307308generate_stubgen!(gen_impl, UniqueFungibleCall<()>, true);309generate_stubgen!(gen_iface, UniqueFungibleCall<()>, false);310311impl<T: Config> CommonEvmHandler for FungibleHandle<T>312where313 T::AccountId: From<[u8; 32]> + AsRef<[u8; 32]>,314{315 const CODE: &'static [u8] = include_bytes!("./stubs/UniqueFungible.raw");316317 fn call(self, handle: &mut impl PrecompileHandle) -> Option<PrecompileResult> {318 call::<T, UniqueFungibleCall<T>, _, _>(handle, self)319 }320}pallets/fungible/src/stubs/UniqueFungible.soldiffbeforeafterboth--- a/pallets/fungible/src/stubs/UniqueFungible.sol
+++ b/pallets/fungible/src/stubs/UniqueFungible.sol
@@ -547,7 +547,7 @@
event Approval(address indexed owner, address indexed spender, uint256 value);
}
-/// @dev the ERC-165 identifier for this interface is 0x942e8b22
+/// @dev the ERC-165 identifier for this interface is 0x8cb847c4
contract ERC20 is Dummy, ERC165, ERC20Events {
/// @dev EVM selector for this function is: 0x06fdde03,
/// or in textual repr: name()
@@ -634,6 +634,15 @@
dummy;
return 0;
}
+
+ /// @notice Returns collection helper contract address
+ /// @dev EVM selector for this function is: 0x1896cce6,
+ /// or in textual repr: collectionHelperAddress()
+ function collectionHelperAddress() public view returns (address) {
+ require(false, stub_error);
+ dummy;
+ return 0x0000000000000000000000000000000000000000;
+ }
}
contract UniqueFungible is Dummy, ERC165, ERC20, ERC20Mintable, ERC20UniqueExtensions, Collection {}
pallets/nonfungible/src/erc.rsdiffbeforeafterboth--- a/pallets/nonfungible/src/erc.rs
+++ b/pallets/nonfungible/src/erc.rs
@@ -42,6 +42,7 @@
use pallet_evm::{account::CrossAccountId, PrecompileHandle};
use pallet_evm_coder_substrate::call;
use pallet_structure::{SelfWeightOf as StructureWeight, weights::WeightInfo as _};
+use sp_core::Get;
use crate::{
AccountBalance, Config, CreateItemData, NonfungibleHandle, Pallet, TokenData, TokensMinted,
@@ -489,6 +490,11 @@
// TODO: Not implemetable
Err("not implemented".into())
}
+
+ /// @notice Returns collection helper contract address
+ fn collection_helper_address(&self) -> Result<address> {
+ Ok(T::ContractAddress::get())
+ }
}
/// @title ERC721 Token that can be irreversibly burned (destroyed).
pallets/nonfungible/src/stubs/UniqueNFT.soldiffbeforeafterboth--- a/pallets/nonfungible/src/stubs/UniqueNFT.sol
+++ b/pallets/nonfungible/src/stubs/UniqueNFT.sol
@@ -920,7 +920,7 @@
/// @title ERC-721 Non-Fungible Token Standard
/// @dev See https://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md
-/// @dev the ERC-165 identifier for this interface is 0x80ac58cd
+/// @dev the ERC-165 identifier for this interface is 0x983a942b
contract ERC721 is Dummy, ERC165, ERC721Events {
/// @notice Count all NFTs assigned to an owner
/// @dev NFTs assigned to the zero address are considered invalid, and this
@@ -1050,6 +1050,15 @@
dummy;
return 0x0000000000000000000000000000000000000000;
}
+
+ /// @notice Returns collection helper contract address
+ /// @dev EVM selector for this function is: 0x1896cce6,
+ /// or in textual repr: collectionHelperAddress()
+ function collectionHelperAddress() public view returns (address) {
+ require(false, stub_error);
+ dummy;
+ return 0x0000000000000000000000000000000000000000;
+ }
}
contract UniqueNFT is
pallets/refungible/src/erc.rsdiffbeforeafterboth--- a/pallets/refungible/src/erc.rs
+++ b/pallets/refungible/src/erc.rs
@@ -38,7 +38,7 @@
use pallet_evm::{account::CrossAccountId, PrecompileHandle};
use pallet_evm_coder_substrate::{call, dispatch_to_evm};
use pallet_structure::{SelfWeightOf as StructureWeight, weights::WeightInfo as _};
-use sp_core::H160;
+use sp_core::{H160, Get};
use sp_std::{collections::btree_map::BTreeMap, vec::Vec, vec};
use up_data_structs::{
CollectionId, CollectionPropertiesVec, mapping::TokenAddressMapping, Property, PropertyKey,
@@ -482,6 +482,11 @@
// TODO: Not implemetable
Err("not implemented".into())
}
+
+ /// @notice Returns collection helper contract address
+ fn collection_helper_address(&self) -> Result<address> {
+ Ok(T::ContractAddress::get())
+ }
}
/// Returns amount of pieces of `token` that `owner` have
pallets/refungible/src/stubs/UniqueRefungible.soldiffbeforeafterboth--- a/pallets/refungible/src/stubs/UniqueRefungible.sol
+++ b/pallets/refungible/src/stubs/UniqueRefungible.sol
@@ -919,7 +919,7 @@
/// @title ERC-721 Non-Fungible Token Standard
/// @dev See https://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md
-/// @dev the ERC-165 identifier for this interface is 0x58800161
+/// @dev the ERC-165 identifier for this interface is 0x4016cd87
contract ERC721 is Dummy, ERC165, ERC721Events {
/// @notice Count all RFTs assigned to an owner
/// @dev RFTs assigned to the zero address are considered invalid, and this
@@ -1047,6 +1047,15 @@
dummy;
return 0x0000000000000000000000000000000000000000;
}
+
+ /// @notice Returns collection helper contract address
+ /// @dev EVM selector for this function is: 0x1896cce6,
+ /// or in textual repr: collectionHelperAddress()
+ function collectionHelperAddress() public view returns (address) {
+ require(false, stub_error);
+ dummy;
+ return 0x0000000000000000000000000000000000000000;
+ }
}
contract UniqueRefungible is
tests/src/apiConsts.test.tsdiffbeforeafterboth--- a/tests/src/apiConsts.test.ts
+++ b/tests/src/apiConsts.test.ts
@@ -117,4 +117,4 @@
function checkConst<T>(constValue: any, expectedValue: T) {
expect(constValue.toBigInt()).equal(expectedValue);
-}
+}
\ No newline at end of file
tests/src/eth/abi/fungible.jsondiffbeforeafterboth--- a/tests/src/eth/abi/fungible.json
+++ b/tests/src/eth/abi/fungible.json
@@ -201,6 +201,13 @@
},
{
"inputs": [],
+ "name": "collectionHelperAddress",
+ "outputs": [{ "internalType": "address", "name": "", "type": "address" }],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [],
"name": "collectionOwner",
"outputs": [
{
tests/src/eth/abi/nonFungible.jsondiffbeforeafterboth--- a/tests/src/eth/abi/nonFungible.json
+++ b/tests/src/eth/abi/nonFungible.json
@@ -231,6 +231,13 @@
},
{
"inputs": [],
+ "name": "collectionHelperAddress",
+ "outputs": [{ "internalType": "address", "name": "", "type": "address" }],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [],
"name": "collectionOwner",
"outputs": [
{
tests/src/eth/abi/reFungible.jsondiffbeforeafterboth--- a/tests/src/eth/abi/reFungible.json
+++ b/tests/src/eth/abi/reFungible.json
@@ -213,6 +213,13 @@
},
{
"inputs": [],
+ "name": "collectionHelperAddress",
+ "outputs": [{ "internalType": "address", "name": "", "type": "address" }],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [],
"name": "collectionOwner",
"outputs": [
{
tests/src/eth/api/UniqueFungible.soldiffbeforeafterboth--- a/tests/src/eth/api/UniqueFungible.sol
+++ b/tests/src/eth/api/UniqueFungible.sol
@@ -354,7 +354,7 @@
event Approval(address indexed owner, address indexed spender, uint256 value);
}
-/// @dev the ERC-165 identifier for this interface is 0x942e8b22
+/// @dev the ERC-165 identifier for this interface is 0x8cb847c4
interface ERC20 is Dummy, ERC165, ERC20Events {
/// @dev EVM selector for this function is: 0x06fdde03,
/// or in textual repr: name()
@@ -395,6 +395,11 @@
/// @dev EVM selector for this function is: 0xdd62ed3e,
/// or in textual repr: allowance(address,address)
function allowance(address owner, address spender) external view returns (uint256);
+
+ /// @notice Returns collection helper contract address
+ /// @dev EVM selector for this function is: 0x1896cce6,
+ /// or in textual repr: collectionHelperAddress()
+ function collectionHelperAddress() external view returns (address);
}
interface UniqueFungible is Dummy, ERC165, ERC20, ERC20Mintable, ERC20UniqueExtensions, Collection {}
tests/src/eth/api/UniqueNFT.soldiffbeforeafterboth--- a/tests/src/eth/api/UniqueNFT.sol
+++ b/tests/src/eth/api/UniqueNFT.sol
@@ -605,7 +605,7 @@
/// @title ERC-721 Non-Fungible Token Standard
/// @dev See https://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md
-/// @dev the ERC-165 identifier for this interface is 0x80ac58cd
+/// @dev the ERC-165 identifier for this interface is 0x983a942b
interface ERC721 is Dummy, ERC165, ERC721Events {
/// @notice Count all NFTs assigned to an owner
/// @dev NFTs assigned to the zero address are considered invalid, and this
@@ -685,6 +685,11 @@
/// @dev EVM selector for this function is: 0xe985e9c5,
/// or in textual repr: isApprovedForAll(address,address)
function isApprovedForAll(address owner, address operator) external view returns (address);
+
+ /// @notice Returns collection helper contract address
+ /// @dev EVM selector for this function is: 0x1896cce6,
+ /// or in textual repr: collectionHelperAddress()
+ function collectionHelperAddress() external view returns (address);
}
interface UniqueNFT is
tests/src/eth/api/UniqueRefungible.soldiffbeforeafterboth--- a/tests/src/eth/api/UniqueRefungible.sol
+++ b/tests/src/eth/api/UniqueRefungible.sol
@@ -604,7 +604,7 @@
/// @title ERC-721 Non-Fungible Token Standard
/// @dev See https://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md
-/// @dev the ERC-165 identifier for this interface is 0x58800161
+/// @dev the ERC-165 identifier for this interface is 0x4016cd87
interface ERC721 is Dummy, ERC165, ERC721Events {
/// @notice Count all RFTs assigned to an owner
/// @dev RFTs assigned to the zero address are considered invalid, and this
@@ -682,6 +682,11 @@
/// @dev EVM selector for this function is: 0xe985e9c5,
/// or in textual repr: isApprovedForAll(address,address)
function isApprovedForAll(address owner, address operator) external view returns (address);
+
+ /// @notice Returns collection helper contract address
+ /// @dev EVM selector for this function is: 0x1896cce6,
+ /// or in textual repr: collectionHelperAddress()
+ function collectionHelperAddress() external view returns (address);
}
interface UniqueRefungible is
tests/src/eth/collectionHelperAddress.test.tsdiffbeforeafterboth--- /dev/null
+++ b/tests/src/eth/collectionHelperAddress.test.ts
@@ -0,0 +1,57 @@
+// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
+// This file is part of Unique Network.
+
+// Unique Network is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// Unique Network is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
+
+import {itEth, usingEthPlaygrounds, expect} from './util';
+import {IKeyringPair} from '@polkadot/types/types';
+
+const EVM_COLLECTION_HELPERS_ADDRESS = '0x6c4e9fe1ae37a41e93cee429e8e1881abdcbb54f';
+
+describe('[eth]CollectionHelerpAddress test: ERC721 ', () => {
+ let donor: IKeyringPair;
+
+ before(async function() {
+ await usingEthPlaygrounds(async (helper, privateKey) => {
+ donor = await privateKey({filename: __filename});
+ });
+ });
+
+ itEth('NFT\\RFT', async ({helper}) => {
+ const owner = await helper.eth.createAccountWithBalance(donor);
+
+ const {collectionAddress: nftCollectionAddress} = await helper.eth.createNFTCollection(owner, 'Sponsor', 'absolutely anything', 'ROC');
+ const nftCollection = helper.ethNativeContract.collection(nftCollectionAddress, 'nft', owner);
+
+ const {collectionAddress: rftCollectionAddress} = await helper.eth.createRFTCollection(owner, 'Sponsor', 'absolutely anything', 'ROC');
+ const rftCollection = helper.ethNativeContract.collection(rftCollectionAddress, 'rft', owner);
+
+ expect((await nftCollection.methods.collectionHelperAddress().call())
+ .toString().toLowerCase()).to.be.equal(EVM_COLLECTION_HELPERS_ADDRESS);
+
+ expect((await rftCollection.methods.collectionHelperAddress().call())
+ .toString().toLowerCase()).to.be.equal(EVM_COLLECTION_HELPERS_ADDRESS);
+ });
+
+ itEth('FT', async ({helper}) => {
+ const owner = await helper.eth.createAccountWithBalance(donor);
+
+ const {collectionAddress} = await helper.eth.createFungibleCollection(owner, 'Sponsor', 18, 'absolutely anything', 'ROC');
+ const collection = helper.ethNativeContract.collection(collectionAddress, 'ft', owner);
+
+ expect((await collection.methods.collectionHelperAddress().call())
+ .toString().toLowerCase()).to.be.equal(EVM_COLLECTION_HELPERS_ADDRESS);
+ });
+
+});