--- a/Makefile +++ b/Makefile @@ -18,6 +18,9 @@ COLLECTION_STUBS=./pallets/unique/src/eth/stubs/ COLLECTION_ABI=./tests/src/eth/collectionAbi.json +COLLECTION_HELPER_STUBS=$(COLLECTION_STUBS) +COLLECTION_HELPER_ABI=./tests/src/eth/collectionHelperAbi.json + TESTS_API=./tests/src/eth/api/ .PHONY: regenerate_solidity @@ -36,9 +39,13 @@ PACKAGE=pallet-evm-contract-helpers NAME=eth::contract_helpers_impl OUTPUT=$(CONTRACT_HELPERS_STUBS)/$@ ./.maintain/scripts/generate_sol.sh Collection.sol: - PACKAGE=pallet-unique NAME=eth::pallet_evm_collection::collection_iface OUTPUT=$(TESTS_API)/$@ ./.maintain/scripts/generate_sol.sh - PACKAGE=pallet-unique NAME=eth::pallet_evm_collection::collection_impl OUTPUT=$(COLLECTION_STUBS)/$@ ./.maintain/scripts/generate_sol.sh + PACKAGE=pallet-unique NAME=eth::evm_collection::collection_iface OUTPUT=$(TESTS_API)/$@ ./.maintain/scripts/generate_sol.sh + PACKAGE=pallet-unique NAME=eth::evm_collection::collection_impl OUTPUT=$(COLLECTION_STUBS)/$@ ./.maintain/scripts/generate_sol.sh +CollectionHelper.sol: + PACKAGE=pallet-unique NAME=eth::evm_collection::collection_helper_iface OUTPUT=$(TESTS_API)/$@ ./.maintain/scripts/generate_sol.sh + PACKAGE=pallet-unique NAME=eth::evm_collection::collection_helper_impl OUTPUT=$(COLLECTION_HELPER_STUBS)/$@ ./.maintain/scripts/generate_sol.sh + UniqueFungible: UniqueFungible.sol INPUT=$(FUNGIBLE_EVM_STUBS)/$< OUTPUT=$(FUNGIBLE_EVM_STUBS)/UniqueFungible.raw ./.maintain/scripts/compile_stub.sh INPUT=$(FUNGIBLE_EVM_STUBS)/$< OUTPUT=$(FUNGIBLE_EVM_ABI) ./.maintain/scripts/generate_abi.sh @@ -55,7 +62,11 @@ INPUT=$(COLLECTION_STUBS)/$< OUTPUT=$(COLLECTION_STUBS)/Collection.raw ./.maintain/scripts/compile_stub.sh INPUT=$(COLLECTION_STUBS)/$< OUTPUT=$(COLLECTION_ABI) ./.maintain/scripts/generate_abi.sh -evm_stubs: UniqueFungible UniqueNFT ContractHelpers Collection +CollectionHelper: CollectionHelper.sol + INPUT=$(COLLECTION_HELPER_STUBS)/$< OUTPUT=$(COLLECTION_HELPER_STUBS)/CollectionHelper.raw ./.maintain/scripts/compile_stub.sh + INPUT=$(COLLECTION_HELPER_STUBS)/$< OUTPUT=$(COLLECTION_HELPER_ABI) ./.maintain/scripts/generate_abi.sh + +evm_stubs: UniqueFungible UniqueNFT ContractHelpers Collection CollectionHelper .PHONY: _bench _bench: --- a/pallets/unique/src/eth/mod.rs +++ b/pallets/unique/src/eth/mod.rs @@ -112,7 +112,6 @@ use sp_std::{vec::Vec, rc::Rc}; use alloc::format; - // #[pallet::config] pub trait Config: frame_system::Config + pallet_evm_coder_substrate::Config @@ -122,8 +121,8 @@ type ContractAddress: Get; } - struct EvmCollection(Rc>); - impl WithRecorder for EvmCollection { + struct EvmCollectionHelper(Rc>); + impl WithRecorder for EvmCollectionHelper { fn recorder(&self) -> &SubstrateRecorder { &self.0 } @@ -132,19 +131,9 @@ self.0 } } - - #[derive(ToLog)] - pub enum EthCollectionEvent { - CollectionCreated { - #[indexed] - owner: address, - #[indexed] - collection_id: address, - }, - } - - #[solidity_interface(name = "Collection")] - impl EvmCollection { + + #[solidity_interface(name = "CollectionHelper")] + impl EvmCollectionHelper { fn create_721_collection( &self, caller: caller, @@ -188,14 +177,37 @@ }); Ok(address) } + } + + struct EvmCollection(Rc>); + impl WithRecorder for EvmCollection { + fn recorder(&self) -> &SubstrateRecorder { + &self.0 + } + + fn into_recorder(self) -> Rc> { + self.0 + } + } + + #[derive(ToLog)] + pub enum EthCollectionEvent { + CollectionCreated { + #[indexed] + owner: address, + #[indexed] + collection_id: address, + }, + } + #[solidity_interface(name = "Collection")] + impl EvmCollection { fn set_sponsor( &self, caller: caller, - collection_address: address, sponsor: address, ) -> Result { - let mut collection = collection_from_address(collection_address, &self.0)?; + let mut collection = collection_from_address(self.contract_address(caller).unwrap(), &self.0)?; check_is_owner(caller, &collection)?; let sponsor = T::CrossAccountId::from_eth(sponsor); @@ -203,8 +215,8 @@ save_eth(collection) } - fn confirm_sponsorship(&self, caller: caller, collection_address: address) -> Result { - let mut collection = collection_from_address(collection_address, &self.0)?; + fn confirm_sponsorship(&self, caller: caller) -> Result { + let mut collection = collection_from_address(self.contract_address(caller).unwrap(), &self.0)?; let caller = T::CrossAccountId::from_eth(caller); if !collection.confirm_sponsorship(caller.as_sub()) { return Err(Error::Revert("Caller is not set as sponsor".into())); @@ -215,10 +227,9 @@ fn set_limits( &self, caller: caller, - collection_address: address, limits_json: string, ) -> Result { - let mut collection = collection_from_address(collection_address, &self.0)?; + let mut collection = collection_from_address(self.contract_address(caller).unwrap(), &self.0)?; check_is_owner(caller, &collection)?; let limits = serde_json_core::from_str(limits_json.as_ref()) @@ -226,6 +237,10 @@ collection.limits = limits.0; save_eth(collection) } + + fn contract_address(&self, _caller: caller) -> Result
{ + Ok(self.0.contract()) + } } fn error_feild_too_long(feild: &str, bound: u32) -> Error { @@ -251,9 +266,9 @@ .map_err(pallet_evm_coder_substrate::dispatch_to_evm::)?; Ok(()) } - - pub struct CollectionOnMethodCall(PhantomData<*const T>); - impl OnMethodCall for CollectionOnMethodCall { + + pub struct CollectionHelperOnMethodCall(PhantomData<*const T>); + impl OnMethodCall for CollectionHelperOnMethodCall { fn is_reserved(contract: &sp_core::H160) -> bool { contract == &T::ContractAddress::get() } @@ -273,6 +288,36 @@ return None; } + let helpers = EvmCollectionHelper::(Rc::new(SubstrateRecorder::::new(*target, gas_left))); + pallet_evm_coder_substrate::call(*source, helpers, value, input) + } + + fn get_code(contract: &sp_core::H160) -> Option> { + (contract == &T::ContractAddress::get()) + .then(|| include_bytes!("./stubs/CollectionHelper.raw").to_vec()) + } + } + + generate_stubgen!(collection_helper_impl, CollectionHelperCall<()>, true); + generate_stubgen!(collection_helper_iface, CollectionHelperCall<()>, false); + + pub struct CollectionOnMethodCall(PhantomData<*const T>); + impl OnMethodCall for CollectionOnMethodCall { + fn is_reserved(contract: &sp_core::H160) -> bool { + contract == &T::ContractAddress::get() + } + + fn is_used(contract: &sp_core::H160) -> bool { + contract == &T::ContractAddress::get() + } + + fn call( + source: &sp_core::H160, + target: &sp_core::H160, + gas_left: u64, + input: &[u8], + value: sp_core::U256, + ) -> Option { let helpers = EvmCollection::(Rc::new(SubstrateRecorder::::new(*target, gas_left))); pallet_evm_coder_substrate::call(*source, helpers, value, input) } --- a/pallets/unique/src/eth/stubs/Collection.sol +++ b/pallets/unique/src/eth/stubs/Collection.sol @@ -21,48 +21,32 @@ } } -// Selector: 1e95830f +// Selector: 15cc740e contract Collection is Dummy, ERC165 { - // Selector: create721Collection(string,string,string) 951c0151 - function create721Collection( - string memory name, - string memory description, - string memory tokenPrefix - ) public view returns (address) { + // Selector: setSponsor(address) 59753fb1 + function setSponsor(address sponsor) public view { require(false, stub_error); - name; - description; - tokenPrefix; + sponsor; dummy; - return 0x0000000000000000000000000000000000000000; } - // Selector: setSponsor(address,address) f01fba93 - function setSponsor(address collectionAddress, address sponsor) - public - view - { + // Selector: confirmSponsorship() c8c6a056 + function confirmSponsorship() public view { require(false, stub_error); - collectionAddress; - sponsor; dummy; } - // Selector: confirmSponsorship(address) abc00001 - function confirmSponsorship(address collectionAddress) public view { + // Selector: setLimits(string) 72cb345d + function setLimits(string memory limitsJson) public view { require(false, stub_error); - collectionAddress; + limitsJson; dummy; } - // Selector: setLimits(address,string) d05638cc - function setLimits(address collectionAddress, string memory limitsJson) - public - view - { + // Selector: contractAddress() f6b4dfb4 + function contractAddress() public view returns (address) { require(false, stub_error); - collectionAddress; - limitsJson; dummy; + return 0x0000000000000000000000000000000000000000; } } --- /dev/null +++ b/pallets/unique/src/eth/stubs/CollectionHelper.sol @@ -0,0 +1,39 @@ +// SPDX-License-Identifier: OTHER +// This code is automatically generated + +pragma solidity >=0.8.0 <0.9.0; + +// Common stubs holder +contract Dummy { + uint8 dummy; + string stub_error = "this contract is implemented in native"; +} + +contract ERC165 is Dummy { + function supportsInterface(bytes4 interfaceID) + external + view + returns (bool) + { + require(false, stub_error); + interfaceID; + return true; + } +} + +// Selector: 951c0151 +contract CollectionHelper is Dummy, ERC165 { + // Selector: create721Collection(string,string,string) 951c0151 + function create721Collection( + string memory name, + string memory description, + string memory tokenPrefix + ) public view returns (address) { + require(false, stub_error); + name; + description; + tokenPrefix; + dummy; + return 0x0000000000000000000000000000000000000000; + } +} --- a/runtime/opal/src/lib.rs +++ b/runtime/opal/src/lib.rs @@ -308,6 +308,7 @@ pallet_evm_contract_helpers::HelpersOnMethodCall, CollectionDispatchT, evm_collection::CollectionOnMethodCall, + evm_collection::CollectionHelperOnMethodCall, ); type OnCreate = pallet_evm_contract_helpers::HelpersOnCreate; type ChainId = ChainId; @@ -978,7 +979,7 @@ ]); // 0x6c4e9fe1ae37a41e93cee429e8e1881abdcbb54f - pub const EvmCollectionAddress: H160 = H160([ + pub const EvmCollectionHelperAddress: H160 = H160([ 0x6c, 0x4e, 0x9f, 0xe1, 0xae, 0x37, 0xa4, 0x1e, 0x93, 0xce, 0xe4, 0x29, 0xe8, 0xe1, 0x88, 0x1a, 0xbd, 0xcb, 0xb5, 0x4f, ]); } @@ -989,7 +990,7 @@ } impl evm_collection::Config for Runtime { - type ContractAddress = EvmCollectionAddress; + type ContractAddress = EvmCollectionHelperAddress; } construct_runtime!( --- a/runtime/quartz/src/lib.rs +++ b/runtime/quartz/src/lib.rs @@ -280,6 +280,7 @@ pallet_evm_contract_helpers::HelpersOnMethodCall, CollectionDispatchT, evm_collection::CollectionOnMethodCall, + evm_collection::CollectionHelperOnMethodCall, ); type OnCreate = pallet_evm_contract_helpers::HelpersOnCreate; type ChainId = ChainId; @@ -955,7 +956,7 @@ ]); // 0x6c4e9fe1ae37a41e93cee429e8e1881abdcbb54f - pub const EvmCollectionAddress: H160 = H160([ + pub const EvmCollectionHelperAddress: H160 = H160([ 0x6c, 0x4e, 0x9f, 0xe1, 0xae, 0x37, 0xa4, 0x1e, 0x93, 0xce, 0xe4, 0x29, 0xe8, 0xe1, 0x88, 0x1a, 0xbd, 0xcb, 0xb5, 0x4f, ]); } @@ -966,7 +967,7 @@ } impl evm_collection::Config for Runtime { - type ContractAddress = EvmCollectionAddress; + type ContractAddress = EvmCollectionHelperAddress; } construct_runtime!( --- a/runtime/unique/src/lib.rs +++ b/runtime/unique/src/lib.rs @@ -284,6 +284,7 @@ pallet_evm_contract_helpers::HelpersOnMethodCall, CollectionDispatchT, evm_collection::CollectionOnMethodCall, + evm_collection::CollectionHelperOnMethodCall, ); type OnCreate = pallet_evm_contract_helpers::HelpersOnCreate; type ChainId = ChainId; @@ -960,7 +961,7 @@ ]); // 0x6c4e9fe1ae37a41e93cee429e8e1881abdcbb54f - pub const EvmCollectionAddress: H160 = H160([ + pub const EvmCollectionHelperAddress: H160 = H160([ 0x6c, 0x4e, 0x9f, 0xe1, 0xae, 0x37, 0xa4, 0x1e, 0x93, 0xce, 0xe4, 0x29, 0xe8, 0xe1, 0x88, 0x1a, 0xbd, 0xcb, 0xb5, 0x4f, ]); } @@ -971,7 +972,7 @@ } impl evm_collection::Config for Runtime { - type ContractAddress = EvmCollectionAddress; + type ContractAddress = EvmCollectionHelperAddress; } construct_runtime!( --- a/tests/src/eth/api/Collection.sol +++ b/tests/src/eth/api/Collection.sol @@ -12,25 +12,17 @@ function supportsInterface(bytes4 interfaceID) external view returns (bool); } -// Selector: 1e95830f +// Selector: 15cc740e interface Collection is Dummy, ERC165 { - // Selector: create721Collection(string,string,string) 951c0151 - function create721Collection( - string memory name, - string memory description, - string memory tokenPrefix - ) external view returns (address); + // Selector: setSponsor(address) 59753fb1 + function setSponsor(address sponsor) external view; - // Selector: setSponsor(address,address) f01fba93 - function setSponsor(address collectionAddress, address sponsor) - external - view; + // Selector: confirmSponsorship() c8c6a056 + function confirmSponsorship() external view; - // Selector: confirmSponsorship(address) abc00001 - function confirmSponsorship(address collectionAddress) external view; + // Selector: setLimits(string) 72cb345d + function setLimits(string memory limitsJson) external view; - // Selector: setLimits(address,string) d05638cc - function setLimits(address collectionAddress, string memory limitsJson) - external - view; + // Selector: contractAddress() f6b4dfb4 + function contractAddress() external view returns (address); } --- /dev/null +++ b/tests/src/eth/api/CollectionHelper.sol @@ -0,0 +1,23 @@ +// SPDX-License-Identifier: OTHER +// This code is automatically generated + +pragma solidity >=0.8.0 <0.9.0; + +// Common stubs holder +interface Dummy { + +} + +interface ERC165 is Dummy { + function supportsInterface(bytes4 interfaceID) external view returns (bool); +} + +// Selector: 951c0151 +interface CollectionHelper is Dummy, ERC165 { + // Selector: create721Collection(string,string,string) 951c0151 + function create721Collection( + string memory name, + string memory description, + string memory tokenPrefix + ) external view returns (address); +} --- a/tests/src/eth/collectionAbi.json +++ b/tests/src/eth/collectionAbi.json @@ -1,35 +1,20 @@ [ { - "inputs": [ - { - "internalType": "address", - "name": "collectionAddress", - "type": "address" - } - ], + "inputs": [], "name": "confirmSponsorship", "outputs": [], "stateMutability": "view", "type": "function" }, { - "inputs": [ - { "internalType": "string", "name": "name", "type": "string" }, - { "internalType": "string", "name": "description", "type": "string" }, - { "internalType": "string", "name": "tokenPrefix", "type": "string" } - ], - "name": "create721Collection", + "inputs": [], + "name": "contractAddress", "outputs": [{ "internalType": "address", "name": "", "type": "address" }], "stateMutability": "view", "type": "function" }, { "inputs": [ - { - "internalType": "address", - "name": "collectionAddress", - "type": "address" - }, { "internalType": "string", "name": "limitsJson", "type": "string" } ], "name": "setLimits", @@ -39,11 +24,6 @@ }, { "inputs": [ - { - "internalType": "address", - "name": "collectionAddress", - "type": "address" - }, { "internalType": "address", "name": "sponsor", "type": "address" } ], "name": "setSponsor", --- /dev/null +++ b/tests/src/eth/collectionHelperAbi.json @@ -0,0 +1,22 @@ +[ + { + "inputs": [ + { "internalType": "string", "name": "name", "type": "string" }, + { "internalType": "string", "name": "description", "type": "string" }, + { "internalType": "string", "name": "tokenPrefix", "type": "string" } + ], + "name": "create721Collection", + "outputs": [{ "internalType": "address", "name": "", "type": "address" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { "internalType": "bytes4", "name": "interfaceID", "type": "bytes4" } + ], + "name": "supportsInterface", + "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }], + "stateMutability": "view", + "type": "function" + } +] --- a/tests/src/eth/createCollection.test.ts +++ b/tests/src/eth/createCollection.test.ts @@ -20,11 +20,12 @@ import {expect} from 'chai'; import {getCreatedCollectionCount, getDetailedCollectionInfo} from '../util/helpers'; import { - collectionHelper, + evmCollectionHelper, collectionIdFromAddress, collectionIdToAddress, createEthAccount, createEthAccountWithBalance, + evmCollection, GAS_ARGS, itWeb3, normalizeAddress, @@ -41,7 +42,7 @@ describe('Create collection from EVM', () => { itWeb3('Create collection', async ({api, web3}) => { const owner = await createEthAccountWithBalance(api, web3); - const helper = collectionHelper(web3, owner); + const helper = evmCollectionHelper(web3, owner); const collectionName = 'CollectionEVM'; const description = 'Some description'; const tokenPrefix = 'token prefix'; @@ -63,26 +64,27 @@ itWeb3('Set sponsorship', async ({api, web3}) => { const owner = await createEthAccountWithBalance(api, web3); - const helper = collectionHelper(web3, owner); - let result = await helper.methods.create721Collection('Sponsor collection', '1', '1').send(); + const collectionHelper = evmCollectionHelper(web3, owner); + let result = await collectionHelper.methods.create721Collection('Sponsor collection', '1', '1').send(); const {collectionIdAddress, collectionId} = await getCollectionAddressFromResult(api, result); const sponsor = await createEthAccountWithBalance(api, web3); - result = await helper.methods.setSponsor(collectionIdAddress, sponsor).send(); - let collection = (await getDetailedCollectionInfo(api, collectionId))!; - expect(collection.sponsorship.isUnconfirmed).to.be.true; - expect(collection.sponsorship.asUnconfirmed.toHuman()).to.be.eq(evmToAddress(sponsor)); - await expect(helper.methods.confirmSponsorship(collectionIdAddress).call()).to.be.rejectedWith('Caller is not set as sponsor'); - const sponsorHelper = collectionHelper(web3, sponsor); - await sponsorHelper.methods.confirmSponsorship(collectionIdAddress).send(); - collection = (await getDetailedCollectionInfo(api, collectionId))!; - expect(collection.sponsorship.isConfirmed).to.be.true; - expect(collection.sponsorship.asConfirmed.toHuman()).to.be.eq(evmToAddress(sponsor)); + const collectionEvm = evmCollection(web3, owner, collectionIdAddress); + result = await collectionEvm.methods.setSponsor(sponsor).send(); + let collectionSub = (await getDetailedCollectionInfo(api, collectionId))!; + expect(collectionSub.sponsorship.isUnconfirmed).to.be.true; + expect(collectionSub.sponsorship.asUnconfirmed.toHuman()).to.be.eq(evmToAddress(sponsor)); + await expect(collectionEvm.methods.confirmSponsorship().call()).to.be.rejectedWith('Caller is not set as sponsor'); + const sponsorCollection = evmCollection(web3, sponsor, collectionIdAddress); + await sponsorCollection.methods.confirmSponsorship().send(); + collectionSub = (await getDetailedCollectionInfo(api, collectionId))!; + expect(collectionSub.sponsorship.isConfirmed).to.be.true; + expect(collectionSub.sponsorship.asConfirmed.toHuman()).to.be.eq(evmToAddress(sponsor)); }); itWeb3('Set limits', async ({api, web3}) => { const owner = await createEthAccountWithBalance(api, web3); - const helper = collectionHelper(web3, owner); - const result = await helper.methods.create721Collection('Const collection', '5', '5').send(); + const collectionHelper = evmCollectionHelper(web3, owner); + const result = await collectionHelper.methods.create721Collection('Const collection', '5', '5').send(); const {collectionIdAddress, collectionId} = await getCollectionAddressFromResult(api, result); const limits = { accountTokenOwnershipLimit: 1000, @@ -97,23 +99,24 @@ }; const limitsJson = JSON.stringify(limits, null, 1); - await helper.methods.setLimits(collectionIdAddress, limitsJson).send(); + const collectionEvm = evmCollection(web3, owner, collectionIdAddress); + await collectionEvm.methods.setLimits(limitsJson).send(); - const collection = (await getDetailedCollectionInfo(api, collectionId))!; - expect(collection.limits.accountTokenOwnershipLimit.unwrap().toNumber()).to.be.eq(limits.accountTokenOwnershipLimit); - expect(collection.limits.sponsoredDataSize.unwrap().toNumber()).to.be.eq(limits.sponsoredDataSize); - expect(collection.limits.sponsoredDataRateLimit.unwrap().asBlocks.toNumber()).to.be.eq(limits.sponsoredDataRateLimit.Blocks); - expect(collection.limits.tokenLimit.unwrap().toNumber()).to.be.eq(limits.tokenLimit); - expect(collection.limits.sponsorTransferTimeout.unwrap().toNumber()).to.be.eq(limits.sponsorTransferTimeout); - expect(collection.limits.sponsorApproveTimeout.unwrap().toNumber()).to.be.eq(limits.sponsorApproveTimeout); - expect(collection.limits.ownerCanTransfer.toHuman()).to.be.eq(limits.ownerCanTransfer); - expect(collection.limits.ownerCanDestroy.toHuman()).to.be.eq(limits.ownerCanDestroy); - expect(collection.limits.transfersEnabled.toHuman()).to.be.eq(limits.transfersEnabled); + const collectionSub = (await getDetailedCollectionInfo(api, collectionId))!; + expect(collectionSub.limits.accountTokenOwnershipLimit.unwrap().toNumber()).to.be.eq(limits.accountTokenOwnershipLimit); + expect(collectionSub.limits.sponsoredDataSize.unwrap().toNumber()).to.be.eq(limits.sponsoredDataSize); + expect(collectionSub.limits.sponsoredDataRateLimit.unwrap().asBlocks.toNumber()).to.be.eq(limits.sponsoredDataRateLimit.Blocks); + expect(collectionSub.limits.tokenLimit.unwrap().toNumber()).to.be.eq(limits.tokenLimit); + expect(collectionSub.limits.sponsorTransferTimeout.unwrap().toNumber()).to.be.eq(limits.sponsorTransferTimeout); + expect(collectionSub.limits.sponsorApproveTimeout.unwrap().toNumber()).to.be.eq(limits.sponsorApproveTimeout); + expect(collectionSub.limits.ownerCanTransfer.toHuman()).to.be.eq(limits.ownerCanTransfer); + expect(collectionSub.limits.ownerCanDestroy.toHuman()).to.be.eq(limits.ownerCanDestroy); + expect(collectionSub.limits.transfersEnabled.toHuman()).to.be.eq(limits.transfersEnabled); }); itWeb3('Check tokenURI', async ({web3, api}) => { const owner = await createEthAccountWithBalance(api, web3); - const helper = collectionHelper(web3, owner); + const helper = evmCollectionHelper(web3, owner); let result = await helper.methods.create721Collection('Mint collection', '6', '6').send(); const {collectionIdAddress, collectionId} = await getCollectionAddressFromResult(api, result); const receiver = createEthAccount(web3); @@ -154,7 +157,7 @@ describe('(!negative tests!) Create collection from EVM', () => { itWeb3('(!negative test!) Create collection (bad lengths)', async ({api, web3}) => { const owner = await createEthAccountWithBalance(api, web3); - const helper = collectionHelper(web3, owner); + const helper = evmCollectionHelper(web3, owner); { const MAX_NAME_LENGHT = 64; const collectionName = 'A'.repeat(MAX_NAME_LENGHT + 1); @@ -188,7 +191,7 @@ itWeb3('(!negative test!) Create collection (no funds)', async ({web3}) => { const owner = await createEthAccount(web3); - const helper = collectionHelper(web3, owner); + const helper = evmCollectionHelper(web3, owner); const collectionName = 'A'; const description = 'A'; const tokenPrefix = 'A'; @@ -200,24 +203,24 @@ itWeb3('(!negative test!) Collection address (Contract is not an unique collection)', async ({api, web3}) => { const owner = await createEthAccountWithBalance(api, web3); - const helper = collectionHelper(web3, owner); const collectionAddressWithBadPrefix = '0x00112233445566778899AABBCCDDEEFF00112233'; + const collectionEvm = evmCollection(web3, owner, collectionAddressWithBadPrefix); const EXPECTED_ERROR = 'Contract is not an unique collection'; { const sponsor = await createEthAccountWithBalance(api, web3); - await expect(helper.methods - .setSponsor(collectionAddressWithBadPrefix, sponsor) + await expect(collectionEvm.methods + .setSponsor(sponsor) .call()).to.be.rejectedWith(EXPECTED_ERROR); - const sponsorHelper = collectionHelper(web3, sponsor); - await expect(sponsorHelper.methods - .confirmSponsorship(collectionAddressWithBadPrefix) + const sponsorCollection = evmCollection(web3, sponsor, collectionAddressWithBadPrefix); + await expect(sponsorCollection.methods + .confirmSponsorship() .call()).to.be.rejectedWith(EXPECTED_ERROR); } { const limits = '{"account_token_ownership_limit":1000}'; - await expect(helper.methods - .setLimits(collectionAddressWithBadPrefix, limits) + await expect(collectionEvm.methods + .setLimits(limits) .call()).to.be.rejectedWith(EXPECTED_ERROR); } }); @@ -225,38 +228,39 @@ itWeb3('(!negative test!) Check owner', async ({api, web3}) => { const owner = await createEthAccountWithBalance(api, web3); const notOwner = await createEthAccount(web3); - const helperFromOwner = collectionHelper(web3, owner); - const helperFromNotOwner = collectionHelper(web3, notOwner); - const result = await helperFromOwner.methods.create721Collection('A', 'A', 'A').send(); + const collectionHelper = evmCollectionHelper(web3, owner); + const result = await collectionHelper.methods.create721Collection('A', 'A', 'A').send(); const {collectionIdAddress} = await getCollectionAddressFromResult(api, result); + const contractEvmFromNotOwner = evmCollection(web3, notOwner, collectionIdAddress); const EXPECTED_ERROR = 'NoPermission'; { const sponsor = await createEthAccountWithBalance(api, web3); - await expect(helperFromNotOwner.methods - .setSponsor(collectionIdAddress, sponsor) + await expect(contractEvmFromNotOwner.methods + .setSponsor(sponsor) .call()).to.be.rejectedWith(EXPECTED_ERROR); - const sponsorHelper = collectionHelper(web3, sponsor); - await expect(sponsorHelper.methods - .confirmSponsorship(collectionIdAddress) + const sponsorCollection = evmCollection(web3, sponsor, collectionIdAddress); + await expect(sponsorCollection.methods + .confirmSponsorship() .call()).to.be.rejectedWith('Caller is not set as sponsor'); } { const limits = '{"account_token_ownership_limit":1000}'; - await expect(helperFromNotOwner.methods - .setLimits(collectionIdAddress, limits) + await expect(contractEvmFromNotOwner.methods + .setLimits(limits) .call()).to.be.rejectedWith(EXPECTED_ERROR); } }); itWeb3('(!negative test!) Set limits', async ({api, web3}) => { const owner = await createEthAccountWithBalance(api, web3); - const helper = collectionHelper(web3, owner); - const result = await helper.methods.create721Collection('Schema collection', 'A', 'A').send(); + const collectionHelper = evmCollectionHelper(web3, owner); + const result = await collectionHelper.methods.create721Collection('Schema collection', 'A', 'A').send(); const {collectionIdAddress} = await getCollectionAddressFromResult(api, result); + const collectionEvm = evmCollection(web3, owner, collectionIdAddress); const badJson = '{accountTokenOwnershipLimit: 1000}'; - await expect(helper.methods - .setLimits(collectionIdAddress, badJson) + await expect(collectionEvm.methods + .setLimits(badJson) .call()).to.be.rejectedWith('Parse JSON error:'); }); }); \ No newline at end of file --- a/tests/src/eth/util/helpers.ts +++ b/tests/src/eth/util/helpers.ts @@ -29,6 +29,7 @@ import privateKey from '../../substrate/privateKey'; import contractHelpersAbi from './contractHelpersAbi.json'; import collectionAbi from '../collectionAbi.json'; +import collectionHelperAbi from '../collectionHelperAbi.json'; import getBalance from '../../substrate/get-balance'; import waitNewBlocks from '../../substrate/wait-new-blocks'; @@ -283,13 +284,23 @@ } /** - * pallet evm_collection + * evm collection helper * @param web3 * @param caller - eth address * @returns */ -export function collectionHelper(web3: Web3, caller: string) { - return new web3.eth.Contract(collectionAbi as any, '0x6c4e9fe1ae37a41e93cee429e8e1881abdcbb54f', {from: caller, ...GAS_ARGS}); +export function evmCollectionHelper(web3: Web3, caller: string) { + return new web3.eth.Contract(collectionHelperAbi as any, '0x6c4e9fe1ae37a41e93cee429e8e1881abdcbb54f', {from: caller, ...GAS_ARGS}); +} + +/** + * evm collection + * @param web3 + * @param caller - eth address + * @returns + */ +export function evmCollection(web3: Web3, caller: string, collection: string) { + return new web3.eth.Contract(collectionAbi as any, collection, {from: caller, ...GAS_ARGS}); } /** --- a/tests/src/interfaces/unique/types.ts +++ b/tests/src/interfaces/unique/types.ts @@ -6,9 +6,6 @@ import type { AccountId32, Call, H160, H256, MultiAddress, Perbill, Permill } from '@polkadot/types/interfaces/runtime'; import type { Event } from '@polkadot/types/interfaces/system'; -/** @name BTreeSet */ -export interface BTreeSet extends BTreeSet {} - /** @name CumulusPalletDmpQueueCall */ export interface CumulusPalletDmpQueueCall extends Enum { readonly isServiceOverweight: boolean;