From 1062e172486ebd682701c21d435a30708ce0361a Mon Sep 17 00:00:00 2001 From: bugrazoid Date: Fri, 27 May 2022 19:23:24 +0000 Subject: [PATCH] Merge pull request #343 from UniqueNetwork/feature/CORE-302 Feature/core 302 --- --- /dev/null +++ b/.maintain/scripts/generate_abi.sh @@ -0,0 +1,13 @@ +#!/bin/sh +set -eu + +dir=$PWD + +tmp=$(mktemp -d) +cd $tmp +cp $dir/$INPUT input.sol +solcjs --abi -p input.sol + +NAME=input_sol_$(basename $INPUT .sol) +mv $NAME.abi $NAME.json +prettier $NAME.json > $dir/$OUTPUT --- a/.maintain/scripts/generate_api.sh +++ /dev/null @@ -1,11 +0,0 @@ -#!/bin/sh -set -eu - -tmp=$(mktemp) -cargo test --package $PACKAGE -- $NAME --exact --nocapture --ignored | tee $tmp -raw=$(mktemp --suffix .sol) -sed -n '/=== SNIP START ===/, /=== SNIP END ===/{ /=== SNIP START ===/! { /=== SNIP END ===/! p } }' $tmp > $raw -formatted=$(mktemp) -prettier --use-tabs $raw > $formatted - -mv $formatted $OUTPUT --- /dev/null +++ b/.maintain/scripts/generate_sol.sh @@ -0,0 +1,11 @@ +#!/bin/sh +set -eu + +tmp=$(mktemp) +cargo test --package $PACKAGE -- $NAME --exact --nocapture --ignored | tee $tmp +raw=$(mktemp --suffix .sol) +sed -n '/=== SNIP START ===/, /=== SNIP END ===/{ /=== SNIP START ===/! { /=== SNIP END ===/! p } }' $tmp > $raw +formatted=$(mktemp) +prettier --use-tabs $raw > $formatted + +mv $formatted $OUTPUT --- a/Cargo.lock +++ b/Cargo.lock @@ -4290,6 +4290,9 @@ version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" +dependencies = [ + "spin", +] [[package]] name = "lazycell" @@ -5467,9 +5470,9 @@ [[package]] name = "once_cell" -version = "1.11.0" +version = "1.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b10983b38c53aebdf33f542c6275b0f58a238129d00c4ae0e6fb59738d783ca" +checksum = "7709cef83f0c1f58f666e746a08b21e0085f7440fa6a29cc194d68aac97a4225" [[package]] name = "opal-runtime" @@ -5917,6 +5920,7 @@ "frame-benchmarking", "frame-support", "frame-system", + "lazy_static", "pallet-evm", "pallet-evm-coder-substrate", "parity-scale-codec 3.1.2", @@ -6083,6 +6087,7 @@ "frame-support", "frame-system", "log", + "pallet-common", "pallet-evm", "pallet-evm-coder-substrate", "parity-scale-codec 3.1.2", @@ -6090,6 +6095,7 @@ "sp-core", "sp-runtime", "sp-std", + "up-data-structs", "up-sponsorship", ] @@ -6814,13 +6820,18 @@ name = "pallet-unique" version = "0.1.0" dependencies = [ + "ethereum", + "evm-coder", "frame-benchmarking", "frame-support", "frame-system", "pallet-common", "pallet-evm", + "pallet-evm-coder-substrate", + "pallet-nonfungible", "parity-scale-codec 3.1.2", "scale-info", + "serde", "sp-core", "sp-io", "sp-runtime", @@ -12005,9 +12016,9 @@ [[package]] name = "target-lexicon" -version = "0.12.3" +version = "0.12.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d7fa7e55043acb85fca6b3c01485a2eeb6b69c5d21002e273c79e465f43b7ac1" +checksum = "c02424087780c9b71cc96799eaeddff35af2bc513278cda5c99fc1f5d026d3c1" [[package]] name = "tempfile" --- a/Makefile +++ b/Makefile @@ -1,33 +1,61 @@ .PHONY: _help _help: @echo "regenerate_solidity - generate stubs/interfaces for contracts defined in native (via evm-coder)" - @echo "evm_stubs - recompile contract stubs" + @echo "evm_stubs - recompile contract stubs and ABI" @echo "bench - run frame-benchmarking" @echo " bench-evm-migration" @echo " bench-unique" +FUNGIBLE_EVM_STUBS=./pallets/fungible/src/stubs +FUNGIBLE_EVM_ABI=./tests/src/eth/fungibleAbi.json + +NONFUNGIBLE_EVM_STUBS=./pallets/nonfungible/src/stubs +NONFUNGIBLE_EVM_ABI=./tests/src/eth/nonFungibleAbi.json + +CONTRACT_HELPERS_STUBS=./pallets/evm-contract-helpers/src/stubs/ +CONTRACT_HELPERS_ABI=./tests/src/eth/util/contractHelpersAbi.json + +COLLECTION_HELPER_STUBS=./pallets/unique/src/eth/stubs/ +COLLECTION_HELPER_ABI=./tests/src/eth/collectionHelperAbi.json + +TESTS_API=./tests/src/eth/api/ + .PHONY: regenerate_solidity -regenerate_solidity: - PACKAGE=pallet-fungible NAME=erc::gen_iface OUTPUT=./tests/src/eth/api/UniqueFungible.sol ./.maintain/scripts/generate_api.sh - PACKAGE=pallet-nonfungible NAME=erc::gen_iface OUTPUT=./tests/src/eth/api/UniqueNFT.sol ./.maintain/scripts/generate_api.sh - PACKAGE=pallet-evm-contract-helpers NAME=eth::contract_helpers_iface OUTPUT=./tests/src/eth/api/ContractHelpers.sol ./.maintain/scripts/generate_api.sh +regenerate_solidity: UniqueFungible.sol UniqueNFT.sol ContractHelpers.sol CollectionHelper.sol + +UniqueFungible.sol: + PACKAGE=pallet-fungible NAME=erc::gen_iface OUTPUT=$(TESTS_API)/$@ ./.maintain/scripts/generate_sol.sh + PACKAGE=pallet-fungible NAME=erc::gen_impl OUTPUT=$(FUNGIBLE_EVM_STUBS)/$@ ./.maintain/scripts/generate_sol.sh + +UniqueNFT.sol: + PACKAGE=pallet-nonfungible NAME=erc::gen_iface OUTPUT=$(TESTS_API)/$@ ./.maintain/scripts/generate_sol.sh + PACKAGE=pallet-nonfungible NAME=erc::gen_impl OUTPUT=$(NONFUNGIBLE_EVM_STUBS)/$@ ./.maintain/scripts/generate_sol.sh + +ContractHelpers.sol: + PACKAGE=pallet-evm-contract-helpers NAME=eth::contract_helpers_iface OUTPUT=$(TESTS_API)/$@ ./.maintain/scripts/generate_sol.sh + PACKAGE=pallet-evm-contract-helpers NAME=eth::contract_helpers_impl OUTPUT=$(CONTRACT_HELPERS_STUBS)/$@ ./.maintain/scripts/generate_sol.sh + +CollectionHelper.sol: + PACKAGE=pallet-unique NAME=eth::collection_helper_iface OUTPUT=$(TESTS_API)/$@ ./.maintain/scripts/generate_sol.sh + PACKAGE=pallet-unique NAME=eth::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 - PACKAGE=pallet-fungible NAME=erc::gen_impl OUTPUT=./pallets/fungible/src/stubs/UniqueFungible.sol ./.maintain/scripts/generate_api.sh - PACKAGE=pallet-nonfungible NAME=erc::gen_impl OUTPUT=./pallets/nonfungible/src/stubs/UniqueNFT.sol ./.maintain/scripts/generate_api.sh - PACKAGE=pallet-evm-contract-helpers NAME=eth::contract_helpers_impl OUTPUT=./pallets/evm-contract-helpers/src/stubs/ContractHelpers.sol ./.maintain/scripts/generate_api.sh +UniqueNFT: UniqueNFT.sol + INPUT=$(NONFUNGIBLE_EVM_STUBS)/$< OUTPUT=$(NONFUNGIBLE_EVM_STUBS)/UniqueNFT.raw ./.maintain/scripts/compile_stub.sh + INPUT=$(NONFUNGIBLE_EVM_STUBS)/$< OUTPUT=$(NONFUNGIBLE_EVM_ABI) ./.maintain/scripts/generate_abi.sh -FUNGIBLE_EVM_STUBS=./pallets/fungible/src/stubs -NONFUNGIBLE_EVM_STUBS=./pallets/nonfungible/src/stubs -CONTRACT_HELPERS_STUBS=./pallets/evm-contract-helpers/src/stubs/ +ContractHelpers: ContractHelpers.sol + INPUT=$(CONTRACT_HELPERS_STUBS)/$< OUTPUT=$(CONTRACT_HELPERS_STUBS)/ContractHelpers.raw ./.maintain/scripts/compile_stub.sh + INPUT=$(CONTRACT_HELPERS_STUBS)/$< OUTPUT=$(CONTRACT_HELPERS_ABI) ./.maintain/scripts/generate_abi.sh -$(FUNGIBLE_EVM_STUBS)/UniqueFungible.raw: $(FUNGIBLE_EVM_STUBS)/UniqueFungible.sol - INPUT=$< OUTPUT=$@ ./.maintain/scripts/compile_stub.sh -$(NONFUNGIBLE_EVM_STUBS)/UniqueNFT.raw: $(NONFUNGIBLE_EVM_STUBS)/UniqueNFT.sol - INPUT=$< OUTPUT=$@ ./.maintain/scripts/compile_stub.sh -$(CONTRACT_HELPERS_STUBS)/ContractHelpers.raw: $(CONTRACT_HELPERS_STUBS)/ContractHelpers.sol - INPUT=$< OUTPUT=$@ ./.maintain/scripts/compile_stub.sh +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: $(FUNGIBLE_EVM_STUBS)/UniqueFungible.raw $(NONFUNGIBLE_EVM_STUBS)/UniqueNFT.raw $(CONTRACT_HELPERS_STUBS)/ContractHelpers.raw +evm_stubs: UniqueFungible UniqueNFT ContractHelpers CollectionHelper .PHONY: _bench _bench: --- a/crates/evm-coder/src/solidity.rs +++ b/crates/evm-coder/src/solidity.rs @@ -327,7 +327,7 @@ } } -#[impl_for_tuples(1, 5)] +#[impl_for_tuples(1, 12)] impl SolidityArguments for Tuple { for_tuples!( where #( Tuple: SolidityArguments ),* ); --- a/pallets/common/Cargo.toml +++ b/pallets/common/Cargo.toml @@ -16,16 +16,18 @@ sp-runtime = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.21" } sp-std = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.21" } sp-core = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.21" } +frame-benchmarking = { default-features = false, optional = true, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.21" } fp-evm-mapping = { default-features = false, git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.21-logs" } up-data-structs = { default-features = false, path = '../../primitives/data-structs' } pallet-evm-coder-substrate = { default-features = false, path = '../../pallets/evm-coder-substrate' } evm-coder = { default-features = false, path = '../../crates/evm-coder' } pallet-evm = { default-features = false, git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.21-logs" } + serde = { version = "1.0.130", default-features = false } scale-info = { version = "2.0.1", default-features = false, features = [ "derive", ] } -frame-benchmarking = { default-features = false, optional = true, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.21" } +lazy_static = { version = "1.4.0", default-features = false, features = ["spin_no_std"] } [features] default = ["std"] --- a/pallets/common/src/erc.rs +++ b/pallets/common/src/erc.rs @@ -14,12 +14,17 @@ // You should have received a copy of the GNU General Public License // along with Unique Network. If not, see . -use evm_coder::{solidity_interface, types::*, execution::Result}; +use evm_coder::{ + solidity_interface, + types::*, + execution::{Result, Error}, +}; pub use pallet_evm::{PrecompileOutput, PrecompileResult, account::CrossAccountId}; use pallet_evm_coder_substrate::dispatch_to_evm; use sp_core::{H160, U256}; use sp_std::vec::Vec; -use up_data_structs::Property; +use up_data_structs::{Property, SponsoringRateLimit}; +use alloc::format; use crate::{Pallet, CollectionHandle, Config, CollectionProperties}; @@ -31,7 +36,7 @@ fn call(self, source: &H160, input: &[u8], value: U256) -> Option; } -#[solidity_interface(name = "CollectionProperties")] +#[solidity_interface(name = "Collection")] impl CollectionHandle { fn set_collection_property(&mut self, caller: caller, key: string, value: bytes) -> Result<()> { let caller = T::CrossAccountId::from_eth(caller); @@ -64,4 +69,93 @@ Ok(prop.to_vec()) } + + fn eth_set_sponsor(&mut self, caller: caller, sponsor: address) -> Result { + check_is_owner(caller, self)?; + + let sponsor = T::CrossAccountId::from_eth(sponsor); + self.set_sponsor(sponsor.as_sub().clone()); + save(self); + Ok(()) + } + + fn eth_confirm_sponsorship(&mut self, caller: caller) -> Result { + let caller = T::CrossAccountId::from_eth(caller); + if !self.confirm_sponsorship(caller.as_sub()) { + return Err(Error::Revert("Caller is not set as sponsor".into())); + } + save(self); + Ok(()) + } + + fn set_limit(&mut self, caller: caller, limit: string, value: string) -> Result { + check_is_owner(caller, self)?; + let mut limits = self.limits.clone(); + + match limit.as_str() { + "accountTokenOwnershipLimit" => { + limits.account_token_ownership_limit = parse_int(value)?; + } + "sponsoredDataSize" => { + limits.sponsored_data_size = parse_int(value)?; + } + "sponsoredDataRateLimit" => { + limits.sponsored_data_rate_limit = + Some(SponsoringRateLimit::Blocks(parse_int(value)?.unwrap())); + } + "tokenLimit" => { + limits.token_limit = parse_int(value)?; + } + "sponsorTransferTimeout" => { + limits.sponsor_transfer_timeout = parse_int(value)?; + } + "sponsorApproveTimeout" => { + limits.sponsor_approve_timeout = parse_int(value)?; + } + "ownerCanTransfer" => { + limits.owner_can_transfer = parse_bool(value)?; + } + "ownerCanDestroy" => { + limits.owner_can_destroy = parse_bool(value)?; + } + "transfersEnabled" => { + limits.transfers_enabled = parse_bool(value)?; + } + _ => return Err(Error::Revert(format!("Unknown limit \"{}\"", limit))), + } + self.limits = >::clamp_limits(self.mode.clone(), &self.limits, limits) + .map_err(dispatch_to_evm::)?; + save(self); + Ok(()) + } + + fn contract_address(&self, _caller: caller) -> Result
{ + Ok(crate::eth::collection_id_to_address(self.id)) + } +} + +fn check_is_owner(caller: caller, collection: &CollectionHandle) -> Result<()> { + let caller = T::CrossAccountId::from_eth(caller); + collection + .check_is_owner(&caller) + .map_err(pallet_evm_coder_substrate::dispatch_to_evm::)?; + Ok(()) +} + +fn save(collection: &CollectionHandle) { + >::insert(collection.id, collection.collection.clone()); +} + +fn parse_int(value: string) -> Result> { + value + .parse::() + .map_err(|e| Error::Revert(format!("Int value \"{}\" parse error: {}", value, e))) + .map(|value| Some(value)) +} + +fn parse_bool(value: string) -> Result> { + value + .parse::() + .map_err(|e| Error::Revert(format!("Bool value \"{}\" parse error: {}", value, e))) + .map(|value| Some(value)) } --- a/pallets/common/src/eth.rs +++ b/pallets/common/src/eth.rs @@ -17,6 +17,14 @@ use up_data_structs::CollectionId; use sp_core::H160; +lazy_static::lazy_static! { + pub static ref KEY_TOKEN_URI: up_data_structs::PropertyKey = { + let key: evm_coder::types::string = "tokenURI".into(); //TODO: make static + let key: up_data_structs::PropertyKey = key.into_bytes().try_into().expect("Can't create \"tokenURI\" key"); + key + }; +} + // 0x17c4e6453Cc49AAAaEACA894e6D9683e00000001 - collection 1 // TODO: Unhardcode prefix const ETH_COLLECTION_PREFIX: [u8; 16] = [ @@ -37,3 +45,7 @@ out[16..20].copy_from_slice(&u32::to_be_bytes(id.0)); H160(out) } + +pub fn is_collection(address: &H160) -> bool { + address[0..16] == ETH_COLLECTION_PREFIX +} --- a/pallets/common/src/lib.rs +++ b/pallets/common/src/lib.rs @@ -114,6 +114,15 @@ recorder: SubstrateRecorder::new(gas_limit), }) } + + pub fn new_with_recorder(id: CollectionId, recorder: SubstrateRecorder) -> Option { + >::get(id).map(|collection| Self { + id, + collection, + recorder, + }) + } + pub fn new(id: CollectionId) -> Option { Self::new_with_gas_limit(id, u64::MAX) } @@ -140,6 +149,19 @@ >::insert(self.id, self.collection); Ok(()) } + + pub fn set_sponsor(&mut self, sponsor: T::AccountId) { + self.collection.sponsorship = SponsorshipState::Unconfirmed(sponsor); + } + + pub fn confirm_sponsorship(&mut self, sender: &T::AccountId) -> bool { + if self.collection.sponsorship.pending_sponsor() != Some(sender) { + return false; + }; + + self.collection.sponsorship = SponsorshipState::Confirmed(sender.clone()); + true + } } impl Deref for CollectionHandle { type Target = Collection; --- a/pallets/evm-contract-helpers/Cargo.toml +++ b/pallets/evm-contract-helpers/Cargo.toml @@ -8,18 +8,26 @@ scale-info = { version = "2.0.1", default-features = false, features = [ "derive", ] } -frame-support = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.21" } -frame-system = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.21" } -sp-runtime = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.21" } -sp-std = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.21" } -sp-core = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.21" } -evm-coder = { default-features = false, path = '../../crates/evm-coder' } -pallet-evm-coder-substrate = { default-features = false, path = '../../pallets/evm-coder-substrate' } +log = { default-features = false, version = "0.4.14" } + +# Substrate +frame-support = { default-features = false, git = 'https://github.com/paritytech/substrate.git', branch = 'polkadot-v0.9.21' } +frame-system = { default-features = false, git = 'https://github.com/paritytech/substrate.git', branch = 'polkadot-v0.9.21' } +sp-runtime = { default-features = false, git = 'https://github.com/paritytech/substrate.git', branch = 'polkadot-v0.9.21' } +sp-std = { default-features = false, git = 'https://github.com/paritytech/substrate.git', branch = 'polkadot-v0.9.21' } +sp-core = { default-features = false, git = 'https://github.com/paritytech/substrate.git', branch = 'polkadot-v0.9.21' } + +# Unique pallet-evm = { default-features = false, git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.21-logs" } fp-evm-mapping = { default-features = false, git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.21-logs" } up-sponsorship = { version = "0.1.0", default-features = false, git = "https://github.com/uniquenetwork/pallet-sponsoring", branch = "polkadot-v0.9.21" } -log = "0.4.14" +# Locals +evm-coder = { default-features = false, path = '../../crates/evm-coder' } +pallet-common = { default-features = false, path = '../../pallets/common' } +pallet-evm-coder-substrate = { default-features = false, path = '../../pallets/evm-coder-substrate' } +up-data-structs = { default-features = false, path = '../../primitives/data-structs', features = ['serde1'] } + [dependencies.codec] default-features = false features = ['derive'] --- a/pallets/fungible/src/erc.rs +++ b/pallets/fungible/src/erc.rs @@ -24,7 +24,7 @@ use pallet_evm::account::CrossAccountId; use pallet_evm_coder_substrate::{call, dispatch_to_evm}; use pallet_structure::{SelfWeightOf as StructureWeight, weights::WeightInfo as _}; -use pallet_common::{CollectionHandle, erc::CollectionPropertiesCall}; +use pallet_common::{CollectionHandle, erc::CollectionCall}; use crate::{ Allowance, Balance, Config, FungibleHandle, Pallet, SelfWeightOf, TotalSupply, @@ -150,7 +150,7 @@ is( ERC20, ERC20UniqueExtensions, - via("CollectionHandle", common_mut, CollectionProperties) + via("CollectionHandle", common_mut, Collection) ) )] impl FungibleHandle {} --- a/pallets/fungible/src/lib.rs +++ b/pallets/fungible/src/lib.rs @@ -33,7 +33,7 @@ use pallet_evm_coder_substrate::WithRecorder; use sp_core::H160; use sp_runtime::{ArithmeticError, DispatchError, DispatchResult}; -use sp_std::collections::btree_map::BTreeMap; +use sp_std::{collections::btree_map::BTreeMap}; pub use pallet::*; --- a/pallets/fungible/src/stubs/UniqueFungible.sol +++ b/pallets/fungible/src/stubs/UniqueFungible.sol @@ -127,8 +127,8 @@ } } -// Selector: 9b5e29c5 -contract CollectionProperties is Dummy, ERC165 { +// Selector: f5652829 +contract Collection is Dummy, ERC165 { // Selector: setCollectionProperty(string,bytes) 2f073f66 function setCollectionProperty(string memory key, bytes memory value) public @@ -159,6 +159,34 @@ dummy; return hex""; } + + // Selector: ethSetSponsor(address) 8f9af356 + function ethSetSponsor(address sponsor) public { + require(false, stub_error); + sponsor; + dummy = 0; + } + + // Selector: ethConfirmSponsorship() a8580d1a + function ethConfirmSponsorship() public { + require(false, stub_error); + dummy = 0; + } + + // Selector: setLimit(string,string) bf4d2014 + function setLimit(string memory limit, string memory value) public { + require(false, stub_error); + limit; + value; + dummy = 0; + } + + // Selector: contractAddress() f6b4dfb4 + function contractAddress() public view returns (address) { + require(false, stub_error); + dummy; + return 0x0000000000000000000000000000000000000000; + } } contract UniqueFungible is @@ -166,5 +194,5 @@ ERC165, ERC20, ERC20UniqueExtensions, - CollectionProperties + Collection {} --- a/pallets/nonfungible/src/common.rs +++ b/pallets/nonfungible/src/common.rs @@ -22,7 +22,7 @@ PropertyKeyPermission, PropertyValue, }; use pallet_common::{ - CommonCollectionOperations, CommonWeightInfo, with_weight, weights::WeightInfo as _, + CommonCollectionOperations, CommonWeightInfo, with_weight, weights::WeightInfo as _ }; use sp_runtime::DispatchError; use sp_std::vec::Vec; --- a/pallets/nonfungible/src/erc.rs +++ b/pallets/nonfungible/src/erc.rs @@ -21,13 +21,16 @@ }; use evm_coder::{ToLog, execution::*, generate_stubgen, solidity, solidity_interface, types::*, weight}; use frame_support::BoundedVec; -use up_data_structs::{TokenId, SchemaVersion, PropertyPermission, PropertyKeyPermission, Property}; +use up_data_structs::{ + TokenId, SchemaVersion, PropertyPermission, PropertyKeyPermission, Property, CollectionId, + PropertyKey, CollectionPropertiesVec, +}; use pallet_evm_coder_substrate::dispatch_to_evm; use sp_core::{H160, U256}; use sp_std::vec::Vec; use pallet_common::{ - erc::{CommonEvmHandler, PrecompileResult, CollectionPropertiesCall}, - CollectionHandle, + erc::{CommonEvmHandler, PrecompileResult, CollectionCall}, + CollectionHandle, CollectionPropertyPermissions, }; use pallet_evm::account::CrossAccountId; use pallet_evm_coder_substrate::call; @@ -158,12 +161,21 @@ /// Returns token's const_metadata #[solidity(rename_selector = "tokenURI")] fn token_uri(&self, token_id: uint256) -> Result { + let key = pallet_common::eth::KEY_TOKEN_URI.clone(); + if !has_token_permission::(self.id, &key) { + return Err("No tokenURI permission".into()); + } + self.consume_store_reads(1)?; - let _token_id: u32 = token_id.try_into().map_err(|_| "token id overflow")?; - Ok(string::from_utf8_lossy( - todo!() - ) - .into()) + let token_id: u32 = token_id.try_into().map_err(|_| "token id overflow")?; + + let properties = >::try_get((self.id, token_id)) + .map_err(|_| Error::Revert("Token properties not found".into()))?; + if let Some(property) = properties.get(&key) { + return Ok(string::from_utf8_lossy(property).into()); + } + + Err("Property tokenURI not found".into()) } } @@ -350,6 +362,12 @@ token_id: uint256, token_uri: string, ) -> Result { + let key = pallet_common::eth::KEY_TOKEN_URI.clone(); + let permission = get_token_permission::(self.id, &key)?; + if !permission.collection_admin { + return Err("Operation is not allowed".into()); + } + let caller = T::CrossAccountId::from_eth(caller); let to = T::CrossAccountId::from_eth(to); let token_id: u32 = token_id.try_into().map_err(|_| "amount overflow")?; @@ -365,13 +383,22 @@ return Err("item id should be next".into()); } - todo!("token uri"); + let mut properties = CollectionPropertiesVec::default(); + properties + .try_push(Property { + key, + value: token_uri + .into_bytes() + .try_into() + .map_err(|_| "token uri is too long")?, + }) + .map_err(|e| Error::Revert(alloc::format!("Can't add property: {:?}", e)))?; >::create_item( self, &caller, CreateItemData:: { - properties: BoundedVec::default(), + properties, owner: to, }, &budget, @@ -386,6 +413,30 @@ } } +fn get_token_permission( + collection_id: CollectionId, + key: &PropertyKey, +) -> Result { + let token_property_permissions = CollectionPropertyPermissions::::try_get(collection_id) + .map_err(|_| Error::Revert("No permissions for collection".into()))?; + let a = token_property_permissions + .get(key) + .map(|p| p.clone()) + .ok_or_else(|| Error::Revert("No permission".into()))?; + Ok(a) +} + +fn has_token_permission( + collection_id: CollectionId, + key: &PropertyKey, +) -> bool { + if let Ok(token_property_permissions) = CollectionPropertyPermissions::::try_get(collection_id) { + return token_property_permissions.contains_key(key); + } + + false +} + #[solidity_interface(name = "ERC721UniqueExtensions")] impl NonfungibleHandle { #[weight(>::transfer())] @@ -491,7 +542,6 @@ } expected_index = expected_index.checked_add(1).ok_or("item id overflow")?; - todo!("token uri"); data.push(CreateItemData:: { properties: BoundedVec::default(), owner: to.clone(), @@ -513,7 +563,7 @@ ERC721UniqueExtensions, ERC721Mintable, ERC721Burnable, - via("CollectionHandle", common_mut, CollectionProperties), + via("CollectionHandle", common_mut, Collection), TokenProperties, ) )] --- a/pallets/nonfungible/src/lib.rs +++ b/pallets/nonfungible/src/lib.rs @@ -33,9 +33,8 @@ use pallet_evm_coder_substrate::{SubstrateRecorder, WithRecorder}; use sp_core::H160; use sp_runtime::{ArithmeticError, DispatchError, DispatchResult, TransactionOutcome}; -use sp_std::{vec::Vec, vec, collections::btree_set::BTreeSet}; +use sp_std::{vec::Vec, vec, collections::btree_map::BTreeMap, collections::btree_set::BTreeSet}; use core::ops::Deref; -use sp_std::collections::btree_map::BTreeMap; use codec::{Encode, Decode, MaxEncodedLen}; use scale_info::TypeInfo; --- a/pallets/nonfungible/src/stubs/UniqueNFT.sol +++ b/pallets/nonfungible/src/stubs/UniqueNFT.sol @@ -330,40 +330,6 @@ } } -// Selector: 9b5e29c5 -contract CollectionProperties is Dummy, ERC165 { - // Selector: setCollectionProperty(string,bytes) 2f073f66 - function setCollectionProperty(string memory key, bytes memory value) - public - { - require(false, stub_error); - key; - value; - dummy = 0; - } - - // Selector: deleteCollectionProperty(string) 7b7debce - function deleteCollectionProperty(string memory key) public { - require(false, stub_error); - key; - dummy = 0; - } - - // Throws error if key not found - // - // Selector: collectionProperty(string) cf24fd6d - function collectionProperty(string memory key) - public - view - returns (bytes memory) - { - require(false, stub_error); - key; - dummy; - return hex""; - } -} - // Selector: d74d154f contract ERC721UniqueExtensions is Dummy, ERC165 { // Selector: transfer(address,uint256) a9059cbb @@ -414,6 +380,68 @@ } } +// Selector: f5652829 +contract Collection is Dummy, ERC165 { + // Selector: setCollectionProperty(string,bytes) 2f073f66 + function setCollectionProperty(string memory key, bytes memory value) + public + { + require(false, stub_error); + key; + value; + dummy = 0; + } + + // Selector: deleteCollectionProperty(string) 7b7debce + function deleteCollectionProperty(string memory key) public { + require(false, stub_error); + key; + dummy = 0; + } + + // Throws error if key not found + // + // Selector: collectionProperty(string) cf24fd6d + function collectionProperty(string memory key) + public + view + returns (bytes memory) + { + require(false, stub_error); + key; + dummy; + return hex""; + } + + // Selector: ethSetSponsor(address) 8f9af356 + function ethSetSponsor(address sponsor) public { + require(false, stub_error); + sponsor; + dummy = 0; + } + + // Selector: ethConfirmSponsorship() a8580d1a + function ethConfirmSponsorship() public { + require(false, stub_error); + dummy = 0; + } + + // Selector: setLimit(string,string) bf4d2014 + function setLimit(string memory limit, string memory value) public { + require(false, stub_error); + limit; + value; + dummy = 0; + } + + // Selector: contractAddress() f6b4dfb4 + function contractAddress() public view returns (address) { + require(false, stub_error); + dummy; + return 0x0000000000000000000000000000000000000000; + } +} + contract UniqueNFT is Dummy, ERC165, @@ -423,6 +451,6 @@ ERC721UniqueExtensions, ERC721Mintable, ERC721Burnable, - CollectionProperties, + Collection, TokenProperties {} --- a/pallets/unique/Cargo.toml +++ b/pallets/unique/Cargo.toml @@ -19,6 +19,7 @@ runtime-benchmarks = ['frame-benchmarking', 'pallet-common/runtime-benchmarks'] std = [ 'codec/std', + 'serde/std', 'frame-support/std', 'frame-system/std', 'pallet-evm/std', @@ -27,10 +28,25 @@ 'sp-std/std', 'sp-runtime/std', 'frame-benchmarking/std', + 'evm-coder/std', + 'pallet-evm-coder-substrate/std', + 'pallet-nonfungible/std', ] limit-testing = ["up-data-structs/limit-testing"] ################################################################################ +# Standart Dependencies + +[dependencies.serde] +default-features = false +features = ['derive'] +version = '1.0.130' + +[dependencies.ethereum] +version = "0.12.0" +default-features = false + +################################################################################ # Substrate Dependencies [dependencies.codec] @@ -74,7 +90,6 @@ default-features = false git = "https://github.com/paritytech/substrate" branch = "polkadot-v0.9.21" - ################################################################################ # Local Dependencies @@ -85,3 +100,6 @@ ] } pallet-evm = { default-features = false, git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.21-logs" } pallet-common = { default-features = false, path = "../common" } +evm-coder = { default-features = false, path = '../../crates/evm-coder' } +pallet-evm-coder-substrate = { default-features = false, path = '../../pallets/evm-coder-substrate' } +pallet-nonfungible = { default-features = false, path = '../../pallets/nonfungible' } --- /dev/null +++ b/pallets/unique/src/eth/mod.rs @@ -0,0 +1,171 @@ +// 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 . + +use core::marker::PhantomData; +use evm_coder::{execution::*, generate_stubgen, solidity_interface, types::*, ToLog}; +use ethereum as _; +use pallet_evm_coder_substrate::{SubstrateRecorder, WithRecorder}; +use pallet_evm::{OnMethodCall, PrecompileResult, account::CrossAccountId, Pallet as PalletEvm}; +use up_data_structs::{ + CreateCollectionData, MAX_COLLECTION_DESCRIPTION_LENGTH, MAX_TOKEN_PREFIX_LENGTH, + MAX_COLLECTION_NAME_LENGTH, +}; +use frame_support::traits::Get; +use sp_core::H160; +use pallet_common::CollectionById; + +use sp_std::vec::Vec; +use alloc::format; + +pub trait Config: + frame_system::Config + + pallet_evm_coder_substrate::Config + + pallet_evm::account::Config + + pallet_nonfungible::Config +{ + type ContractAddress: Get; +} + +struct EvmCollectionHelper(SubstrateRecorder); +impl WithRecorder for EvmCollectionHelper { + fn recorder(&self) -> &SubstrateRecorder { + &self.0 + } + + fn into_recorder(self) -> SubstrateRecorder { + self.0 + } +} + +#[solidity_interface(name = "CollectionHelper")] +impl EvmCollectionHelper { + fn create_721_collection( + &self, + caller: caller, + name: string, + description: string, + token_prefix: string, + ) -> Result
{ + let caller = T::CrossAccountId::from_eth(caller); + let name = name + .encode_utf16() + .collect::>() + .try_into() + .map_err(|_| error_feild_too_long(stringify!(name), MAX_COLLECTION_NAME_LENGTH))?; + let description = description + .encode_utf16() + .collect::>() + .try_into() + .map_err(|_| { + error_feild_too_long(stringify!(description), MAX_COLLECTION_DESCRIPTION_LENGTH) + })?; + let token_prefix = token_prefix + .into_bytes() + .try_into() + .map_err(|_| error_feild_too_long(stringify!(token_prefix), MAX_TOKEN_PREFIX_LENGTH))?; + + let key = pallet_common::eth::KEY_TOKEN_URI.clone(); + let permission = up_data_structs::PropertyPermission { + mutable: true, + collection_admin: true, + token_owner: false, + }; + let mut token_property_permissions = + up_data_structs::CollectionPropertiesPermissionsVec::default(); + token_property_permissions + .try_push(up_data_structs::PropertyKeyPermission { key, permission }) + .map_err(|e| Error::Revert(format!("{:?}", e)))?; + + let data = CreateCollectionData { + name, + description, + token_prefix, + token_property_permissions, + ..Default::default() + }; + + let collection_id = + >::init_collection(caller.as_sub().clone(), data) + .map_err(pallet_evm_coder_substrate::dispatch_to_evm::)?; + + let address = pallet_common::eth::collection_id_to_address(collection_id); + >::deposit_log( + EthCollectionEvent::CollectionCreated { + owner: *caller.as_eth(), + collection_id: address, + } + .to_log(address), + ); + Ok(address) + } + + fn is_collection_exist(&self, _caller: caller, collection_address: address) -> Result { + if let Some(id) = pallet_common::eth::map_eth_to_id(&collection_address) { + let collection_id = id; + return Ok(>::contains_key(collection_id)); + } + + Ok(false) + } +} + +#[derive(ToLog)] +pub enum EthCollectionEvent { + CollectionCreated { + #[indexed] + owner: address, + #[indexed] + collection_id: address, + }, +} + +pub struct CollectionHelperOnMethodCall(PhantomData<*const T>); +impl OnMethodCall for CollectionHelperOnMethodCall { + 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 { + if target != &T::ContractAddress::get() { + return None; + } + + let helpers = EvmCollectionHelper::(SubstrateRecorder::::new(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); + +fn error_feild_too_long(feild: &str, bound: u32) -> Error { + Error::Revert(format!("{} is too long. Max length is {}.", feild, bound)) +} --- /dev/null +++ b/pallets/unique/src/eth/stubs/CollectionHelper.sol @@ -0,0 +1,51 @@ +// 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: 56c215c5 +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; + } + + // Selector: isCollectionExist(address) c3de1494 + function isCollectionExist(address collectionAddress) + public + view + returns (bool) + { + require(false, stub_error); + collectionAddress; + dummy; + return false; + } +} --- a/pallets/unique/src/lib.rs +++ b/pallets/unique/src/lib.rs @@ -22,6 +22,8 @@ clippy::unused_unit )] +extern crate alloc; + use frame_support::{ decl_module, decl_storage, decl_error, decl_event, dispatch::DispatchResult, @@ -46,6 +48,7 @@ CollectionHandle, Pallet as PalletCommon, CommonWeightInfo, dispatch::dispatch_call, dispatch::CollectionDispatch, }; +pub mod eth; #[cfg(feature = "runtime-benchmarks")] mod benchmarking; @@ -520,7 +523,7 @@ let mut target_collection = >::try_get(collection_id)?; target_collection.check_is_owner(&sender)?; - target_collection.sponsorship = SponsorshipState::Unconfirmed(new_sponsor.clone()); + target_collection.set_sponsor(new_sponsor.clone()); >::deposit_event(Event::::CollectionSponsorSet( collection_id, @@ -544,11 +547,9 @@ let mut target_collection = >::try_get(collection_id)?; ensure!( - target_collection.sponsorship.pending_sponsor() == Some(&sender), + target_collection.confirm_sponsorship(&sender), Error::::ConfirmUnsetSponsorFail ); - - target_collection.sponsorship = SponsorshipState::Confirmed(sender.clone()); >::deposit_event(Event::::SponsorshipConfirmed( collection_id, --- a/primitives/data-structs/Cargo.toml +++ b/primitives/data-structs/Cargo.toml @@ -40,6 +40,6 @@ "sp-std/std", "pallet-evm/std", ] -serde1 = ["serde"] +serde1 = ["serde/alloc"] limit-testing = [] runtime-benchmarks = [] \ No newline at end of file --- a/primitives/data-structs/src/lib.rs +++ b/primitives/data-structs/src/lib.rs @@ -506,6 +506,7 @@ } #[derive(Encode, Decode, Debug, Clone, PartialEq, TypeInfo, MaxEncodedLen)] +#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))] pub enum MetaUpdatePermission { ItemOwner, Admin, @@ -760,6 +761,10 @@ self.0.get(key) } + pub fn contains_key(&self, key: &PropertyKey) -> bool { + self.0.contains_key(key) + } + fn check_property_key(key: &PropertyKey) -> Result<(), PropertiesError> { if key.is_empty() { return Err(PropertiesError::EmptyPropertyKey); --- a/runtime/opal/src/lib.rs +++ b/runtime/opal/src/lib.rs @@ -50,6 +50,7 @@ pub use pallet_balances::Call as BalancesCall; pub use pallet_evm::{ EnsureAddressTruncated, HashedAddressMapping, Runner, account::CrossAccountId as _, + OnMethodCall, Account as EVMAccount, FeeCalculator, GasWeightMapping, }; pub use frame_support::{ construct_runtime, match_types, @@ -79,7 +80,6 @@ }; use smallvec::smallvec; use codec::{Encode, Decode}; -use pallet_evm::{Account as EVMAccount, FeeCalculator, GasWeightMapping}; use fp_rpc::TransactionStatus; use sp_runtime::{ traits::{BlockNumberProvider, Dispatchable, PostDispatchInfoOf, Saturating}, @@ -306,6 +306,7 @@ pallet_evm_migration::OnMethodCall, pallet_evm_contract_helpers::HelpersOnMethodCall, CollectionDispatchT, + pallet_unique::eth::CollectionHelperOnMethodCall, ); type OnCreate = pallet_evm_contract_helpers::HelpersOnCreate; type ChainId = ChainId; @@ -974,6 +975,11 @@ pub const HelpersContractAddress: H160 = H160([ 0x84, 0x28, 0x99, 0xec, 0xf3, 0x80, 0x55, 0x3e, 0x8a, 0x4d, 0xe7, 0x5b, 0xf5, 0x34, 0xcd, 0xf6, 0xfb, 0xf6, 0x40, 0x49, ]); + + // 0x6c4e9fe1ae37a41e93cee429e8e1881abdcbb54f + 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, + ]); } impl pallet_evm_contract_helpers::Config for Runtime { @@ -981,6 +987,10 @@ type DefaultSponsoringRateLimit = DefaultSponsoringRateLimit; } +impl pallet_unique::eth::Config for Runtime { + type ContractAddress = EvmCollectionHelperAddress; +} + construct_runtime!( pub enum Runtime where Block = Block, --- a/runtime/quartz/src/lib.rs +++ b/runtime/quartz/src/lib.rs @@ -66,7 +66,6 @@ WeightToFeePolynomial, WeightToFeeCoefficient, WeightToFeeCoefficients, ConstantMultiplier, }, }; -use unique_runtime_common::dispatch::{CollectionDispatchT, CollectionDispatch}; use up_data_structs::*; // use pallet_contracts::weights::WeightInfo; // #[cfg(any(feature = "std", test))] @@ -116,7 +115,15 @@ //use xcm_executor::traits::MatchesFungible; use sp_runtime::traits::CheckedConversion; -use unique_runtime_common::{impl_common_runtime_apis, types::*, constants::*}; +use unique_runtime_common::{ + impl_common_runtime_apis, + types::*, + constants::*, + dispatch::{CollectionDispatchT, CollectionDispatch}, + sponsoring::UniqueSponsorshipHandler, + eth_sponsoring::UniqueEthSponsorshipHandler, + weights::CommonWeights, +}; pub const RUNTIME_NAME: &str = "quartz"; pub const TOKEN_SYMBOL: &str = "QTZ"; @@ -278,6 +285,7 @@ pallet_evm_migration::OnMethodCall, pallet_evm_contract_helpers::HelpersOnMethodCall, CollectionDispatchT, + pallet_unique::eth::CollectionHelperOnMethodCall, ); type OnCreate = pallet_evm_contract_helpers::HelpersOnCreate; type ChainId = ChainId; @@ -891,6 +899,7 @@ impl pallet_unique::Config for Runtime { type Event = Event; type WeightInfo = pallet_unique::weights::SubstrateWeight; + type CommonWeightInfo = CommonWeights; } parameter_types! { @@ -912,11 +921,11 @@ // } type EvmSponsorshipHandler = ( - pallet_unique::UniqueEthSponsorshipHandler, + UniqueEthSponsorshipHandler, pallet_evm_contract_helpers::HelpersContractSponsoring, ); type SponsorshipHandler = ( - pallet_unique::UniqueSponsorshipHandler, + UniqueSponsorshipHandler, //pallet_contract_helpers::ContractSponsorshipHandler, pallet_evm_transaction_payment::BridgeSponsorshipHandler, ); @@ -951,6 +960,11 @@ pub const HelpersContractAddress: H160 = H160([ 0x84, 0x28, 0x99, 0xec, 0xf3, 0x80, 0x55, 0x3e, 0x8a, 0x4d, 0xe7, 0x5b, 0xf5, 0x34, 0xcd, 0xf6, 0xfb, 0xf6, 0x40, 0x49, ]); + + // 0x6c4e9fe1ae37a41e93cee429e8e1881abdcbb54f + 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, + ]); } impl pallet_evm_contract_helpers::Config for Runtime { @@ -958,6 +972,10 @@ type DefaultSponsoringRateLimit = DefaultSponsoringRateLimit; } +impl pallet_unique::eth::Config for Runtime { + type ContractAddress = EvmCollectionHelperAddress; +} + construct_runtime!( pub enum Runtime where Block = Block, --- a/runtime/unique/src/lib.rs +++ b/runtime/unique/src/lib.rs @@ -49,7 +49,8 @@ // A few exports that help ease life for downstream crates. pub use pallet_balances::Call as BalancesCall; pub use pallet_evm::{ - EnsureAddressTruncated, HashedAddressMapping, Runner, account::CrossAccountId as _, + EnsureAddressTruncated, HashedAddressMapping, Runner, account::CrossAccountId as _, OnMethodCall, + Account as EVMAccount, FeeCalculator, GasWeightMapping, }; pub use frame_support::{ construct_runtime, match_types, @@ -84,7 +85,6 @@ }; use smallvec::smallvec; use codec::{Encode, Decode}; -use pallet_evm::{Account as EVMAccount, FeeCalculator, GasWeightMapping}; use fp_rpc::TransactionStatus; use sp_runtime::{ traits::{BlockNumberProvider, Dispatchable, PostDispatchInfoOf, Saturating}, @@ -120,7 +120,15 @@ //use xcm_executor::traits::MatchesFungible; use sp_runtime::traits::CheckedConversion; -use unique_runtime_common::{impl_common_runtime_apis, types::*, constants::*}; +use unique_runtime_common::{ + impl_common_runtime_apis, + types::*, + constants::*, + dispatch::{CollectionDispatchT, CollectionDispatch}, + sponsoring::UniqueSponsorshipHandler, + eth_sponsoring::UniqueEthSponsorshipHandler, + weights::CommonWeights, +}; pub const RUNTIME_NAME: &str = "unique"; pub const TOKEN_SYMBOL: &str = "UNQ"; @@ -282,6 +290,7 @@ pallet_evm_migration::OnMethodCall, pallet_evm_contract_helpers::HelpersOnMethodCall, CollectionDispatchT, + pallet_unique::eth::CollectionHelperOnMethodCall, ); type OnCreate = pallet_evm_contract_helpers::HelpersOnCreate; type ChainId = ChainId; @@ -956,6 +965,11 @@ pub const HelpersContractAddress: H160 = H160([ 0x84, 0x28, 0x99, 0xec, 0xf3, 0x80, 0x55, 0x3e, 0x8a, 0x4d, 0xe7, 0x5b, 0xf5, 0x34, 0xcd, 0xf6, 0xfb, 0xf6, 0x40, 0x49, ]); + + // 0x6c4e9fe1ae37a41e93cee429e8e1881abdcbb54f + 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, + ]); } impl pallet_evm_contract_helpers::Config for Runtime { @@ -963,6 +977,10 @@ type DefaultSponsoringRateLimit = DefaultSponsoringRateLimit; } +impl pallet_unique::eth::Config for Runtime { + type ContractAddress = EvmCollectionHelperAddress; +} + construct_runtime!( pub enum Runtime where Block = Block, --- a/tests/package.json +++ b/tests/package.json @@ -73,6 +73,7 @@ "testBlockProduction": "mocha --timeout 9999999 -r ts-node/register ./**/block-production.test.ts", "testEnableDisableTransfers": "mocha --timeout 9999999 -r ts-node/register ./**/enableDisableTransfer.test.ts", "testLimits": "mocha --timeout 9999999 -r ts-node/register ./**/limits.test.ts", + "testEthCreateCollection": "mocha --timeout 9999999 -r ts-node/register ./**/eth/createCollection.test.ts", "polkadot-types-fetch-metadata": "curl -H 'Content-Type: application/json' -d '{\"id\":\"1\", \"jsonrpc\":\"2.0\", \"method\": \"state_getMetadata\", \"params\":[]}' http://localhost:9933 > src/interfaces/metadata.json", "polkadot-types-from-defs": "ts-node ./node_modules/.bin/polkadot-types-from-defs --endpoint src/interfaces/metadata.json --input src/interfaces/ --package .", "polkadot-types-from-chain": "ts-node ./node_modules/.bin/polkadot-types-from-chain --endpoint src/interfaces/metadata.json --output src/interfaces/ --package .", @@ -88,7 +89,7 @@ "bignumber.js": "^9.0.2", "chai-as-promised": "^7.1.1", "find-process": "^1.4.7", - "solc": "^0.8.13", + "solc": "0.8.13", "web3": "^1.7.3" }, "standard": { --- /dev/null +++ b/tests/src/eth/api/CollectionHelper.sol @@ -0,0 +1,29 @@ +// 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: 56c215c5 +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); + + // Selector: isCollectionExist(address) c3de1494 + function isCollectionExist(address collectionAddress) + external + view + returns (bool); +} --- a/tests/src/eth/api/UniqueFungible.sol +++ b/tests/src/eth/api/UniqueFungible.sol @@ -65,8 +65,8 @@ returns (uint256); } -// Selector: 9b5e29c5 -interface CollectionProperties is Dummy, ERC165 { +// Selector: f5652829 +interface Collection is Dummy, ERC165 { // Selector: setCollectionProperty(string,bytes) 2f073f66 function setCollectionProperty(string memory key, bytes memory value) external; @@ -81,6 +81,18 @@ external view returns (bytes memory); + + // Selector: ethSetSponsor(address) 8f9af356 + function ethSetSponsor(address sponsor) external; + + // Selector: ethConfirmSponsorship() a8580d1a + function ethConfirmSponsorship() external; + + // Selector: setLimit(string,string) bf4d2014 + function setLimit(string memory limit, string memory value) external; + + // Selector: contractAddress() f6b4dfb4 + function contractAddress() external view returns (address); } interface UniqueFungible is @@ -88,5 +100,5 @@ ERC165, ERC20, ERC20UniqueExtensions, - CollectionProperties + Collection {} --- a/tests/src/eth/api/UniqueNFT.sol +++ b/tests/src/eth/api/UniqueNFT.sol @@ -191,24 +191,6 @@ function totalSupply() external view returns (uint256); } -// Selector: 9b5e29c5 -interface CollectionProperties is Dummy, ERC165 { - // Selector: setCollectionProperty(string,bytes) 2f073f66 - function setCollectionProperty(string memory key, bytes memory value) - external; - - // Selector: deleteCollectionProperty(string) 7b7debce - function deleteCollectionProperty(string memory key) external; - - // Throws error if key not found - // - // Selector: collectionProperty(string) cf24fd6d - function collectionProperty(string memory key) - external - view - returns (bytes memory); -} - // Selector: d74d154f interface ERC721UniqueExtensions is Dummy, ERC165 { // Selector: transfer(address,uint256) a9059cbb @@ -231,6 +213,36 @@ returns (bool); } +// Selector: f5652829 +interface Collection is Dummy, ERC165 { + // Selector: setCollectionProperty(string,bytes) 2f073f66 + function setCollectionProperty(string memory key, bytes memory value) + external; + + // Selector: deleteCollectionProperty(string) 7b7debce + function deleteCollectionProperty(string memory key) external; + + // Throws error if key not found + // + // Selector: collectionProperty(string) cf24fd6d + function collectionProperty(string memory key) + external + view + returns (bytes memory); + + // Selector: ethSetSponsor(address) 8f9af356 + function ethSetSponsor(address sponsor) external; + + // Selector: ethConfirmSponsorship() a8580d1a + function ethConfirmSponsorship() external; + + // Selector: setLimit(string,string) bf4d2014 + function setLimit(string memory limit, string memory value) external; + + // Selector: contractAddress() f6b4dfb4 + function contractAddress() external view returns (address); +} + interface UniqueNFT is Dummy, ERC165, @@ -240,6 +252,6 @@ ERC721UniqueExtensions, ERC721Mintable, ERC721Burnable, - CollectionProperties, + Collection, TokenProperties {} --- a/tests/src/eth/base.test.ts +++ b/tests/src/eth/base.test.ts @@ -14,7 +14,17 @@ // You should have received a copy of the GNU General Public License // along with Unique Network. If not, see . -import {collectionIdToAddress, createEthAccount, createEthAccountWithBalance, deployFlipper, ethBalanceViaSub, GAS_ARGS, itWeb3, recordEthFee, usingWeb3} from './util/helpers'; +import { + collectionIdToAddress, + createEthAccount, + createEthAccountWithBalance, + deployFlipper, + ethBalanceViaSub, + GAS_ARGS, + itWeb3, + recordEthFee, + usingWeb3, +} from './util/helpers'; import {expect} from 'chai'; import {createCollectionExpectSuccess, createItemExpectSuccess, UNIQUE} from '../util/helpers'; import nonFungibleAbi from './nonFungibleAbi.json'; --- /dev/null +++ b/tests/src/eth/collectionHelperAbi.json @@ -0,0 +1,35 @@ +[ + { + "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": "address", + "name": "collectionAddress", + "type": "address" + } + ], + "name": "isCollectionExist", + "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }], + "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/contractSponsoring.test.ts +++ b/tests/src/eth/contractSponsoring.test.ts @@ -29,19 +29,19 @@ normalizeEvents, subToEth, executeEthTxOnSub, + evmCollectionHelper, + getCollectionAddressFromResult, + evmCollection, } from './util/helpers'; import { addCollectionAdminExpectSuccess, createCollectionExpectSuccess, - getCreateCollectionResult, + getDetailedCollectionInfo, transferBalanceTo, } from '../util/helpers'; import nonFungibleAbi from './nonFungibleAbi.json'; -import { - submitTransactionAsync, -} from '../substrate/substrate-api'; import getBalance from '../substrate/get-balance'; -import {alicesPublicKey} from '../accounts'; +import {evmToAddress} from '@polkadot/util-crypto'; describe('Sponsoring EVM contracts', () => { itWeb3('Sponsoring can be set by the address that has deployed the contract', async ({api, web3}) => { @@ -221,89 +221,87 @@ expect(await helpers.methods.getSponsoringRateLimit(flipper.options.address).call()).to.be.equals('7200'); }); - itWeb3('Sponsoring evm address from substrate collection', async ({api, web3}) => { - const owner = privateKey('//Alice'); - const userEth = createEthAccount(web3); - const collectionId = await createCollectionExpectSuccess(); + //TODO: CORE-302 add eth methods + itWeb3.skip('Sponsoring evm address from substrate collection', async ({api, web3}) => { + const owner = await createEthAccountWithBalance(api, web3); + 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); + const collectionEvm = evmCollection(web3, owner, collectionIdAddress); + result = await collectionEvm.methods.ethSetSponsor(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.ethConfirmSponsorship().call()).to.be.rejectedWith('Caller is not set as sponsor'); - { - const tx = api.tx.unique.setCollectionSponsor(collectionId, owner.address); - const events = await submitTransactionAsync(owner, tx); - const result = getCreateCollectionResult(events); - expect(result.success).to.be.true; - } - { - const tx = api.tx.unique.confirmSponsorship(collectionId); - const events = await submitTransactionAsync(owner, tx); - const result = getCreateCollectionResult(events); - expect(result.success).to.be.true; - } + const sponsorCollection = evmCollection(web3, sponsor, collectionIdAddress); + await sponsorCollection.methods.ethConfirmSponsorship().send(); + collectionSub = (await getDetailedCollectionInfo(api, collectionId))!; + expect(collectionSub.sponsorship.isConfirmed).to.be.true; + expect(collectionSub.sponsorship.asConfirmed.toHuman()).to.be.eq(evmToAddress(sponsor)); - const address = collectionIdToAddress(collectionId); - const contract = new web3.eth.Contract(nonFungibleAbi as any, address, {from: userEth, ...GAS_ARGS}); + const user = createEthAccount(web3); + const userContract = evmCollection(web3, user, collectionIdAddress); + const nextTokenId = await userContract.methods.nextTokenId().call(); - { // This part should fail, because user not in access list and user have no money - const nextTokenId = await contract.methods.nextTokenId().call(); - expect(nextTokenId).to.be.equal('1'); - await expect(contract.methods.mintWithTokenURI( - userEth, - nextTokenId, - 'Test URI', - ).call({from: userEth})).to.be.rejectedWith(/PublicMintingNotAllowed/); - } - - { - const tx = api.tx.unique.setPublicAccessMode(collectionId, 'AllowList'); - const events = await submitTransactionAsync(owner, tx); - const result = getCreateCollectionResult(events); - expect(result.success).to.be.true; - } - { - const tx = api.tx.unique.addToAllowList(collectionId, {Ethereum: userEth}); - const events = await submitTransactionAsync(owner, tx); - const result = getCreateCollectionResult(events); - expect(result.success).to.be.true; - } - { - const tx = api.tx.unique.setMintPermission(collectionId, true); - const events = await submitTransactionAsync(owner, tx); - const result = getCreateCollectionResult(events); - expect(result.success).to.be.true; - } + expect(nextTokenId).to.be.equal('1'); + await expect(userContract.methods.mintWithTokenURI( + user, + nextTokenId, + 'Test URI', + ).call()).to.be.rejectedWith('PublicMintingNotAllowed'); + + // TODO: add this methods to eth + // { + // const tx = api.tx.unique.setPublicAccessMode(collectionId, 'AllowList'); + // const events = await submitTransactionAsync(owner, tx); + // const result = getCreateCollectionResult(events); + // expect(result.success).to.be.true; + // } + // { + // const tx = api.tx.unique.addToAllowList(collectionId, {Ethereum: userEth}); + // const events = await submitTransactionAsync(owner, tx); + // const result = getCreateCollectionResult(events); + // expect(result.success).to.be.true; + // } + // { + // const tx = api.tx.unique.setMintPermission(collectionId, true); + // const events = await submitTransactionAsync(owner, tx); + // const result = getCreateCollectionResult(events); + // expect(result.success).to.be.true; + // } - const [alicesBalanceBefore] = await getBalance(api, [alicesPublicKey]); + // const [alicesBalanceBefore] = await getBalance(api, [alicesPublicKey]); { - const nextTokenId = await contract.methods.nextTokenId().call(); + const nextTokenId = await userContract.methods.nextTokenId().call(); expect(nextTokenId).to.be.equal('1'); - const result = await contract.methods.mintWithTokenURI( - userEth, + const result = await userContract.methods.mintWithTokenURI( + user, nextTokenId, 'Test URI', - ).send({from: userEth}); + ).send(); const events = normalizeEvents(result.events); expect(events).to.be.deep.equal([ { - address, + collectionIdAddress, event: 'Transfer', args: { from: '0x0000000000000000000000000000000000000000', - to: userEth, + to: user, tokenId: nextTokenId, }, }, ]); - expect(await contract.methods.tokenURI(nextTokenId).call()).to.be.equal('Test URI'); + expect(await userContract.methods.tokenURI(nextTokenId).call()).to.be.equal('Test URI'); } - - const [alicesBalanceAfter] = await getBalance(api, [alicesPublicKey]); - expect(alicesBalanceAfter < alicesBalanceBefore).to.be.true; }); - - itWeb3('Check that transaction via EVM spend money from substrate address', async ({api, web3}) => { + //TODO: CORE-302 add eth methods + itWeb3.skip('Check that transaction via EVM spend money from substrate address', async ({api, web3}) => { const owner = privateKey('//Alice'); const user = privateKey(`//User/${Date.now()}`); const userEth = subToEth(user.address); --- /dev/null +++ b/tests/src/eth/createCollection.test.ts @@ -0,0 +1,236 @@ +// 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 . + +import {evmToAddress} from '@polkadot/util-crypto'; +import {expect} from 'chai'; +import {getCreatedCollectionCount, getDetailedCollectionInfo} from '../util/helpers'; +import { + evmCollectionHelper, + collectionIdToAddress, + createEthAccount, + createEthAccountWithBalance, + evmCollection, + itWeb3, + getCollectionAddressFromResult, +} from './util/helpers'; + +describe('Create collection from EVM', () => { + itWeb3('Create collection', async ({api, web3}) => { + const owner = await createEthAccountWithBalance(api, web3); + const helper = evmCollectionHelper(web3, owner); + const collectionName = 'CollectionEVM'; + const description = 'Some description'; + const tokenPrefix = 'token prefix'; + + const collectionCountBefore = await getCreatedCollectionCount(api); + const result = await helper.methods + .create721Collection(collectionName, description, tokenPrefix) + .send(); + const collectionCountAfter = await getCreatedCollectionCount(api); + + const {collectionId, collection} = await getCollectionAddressFromResult(api, result); + expect(collectionCountAfter - collectionCountBefore).to.be.eq(1); + expect(collectionId).to.be.eq(collectionCountAfter); + expect(collection.name.map(v => String.fromCharCode(v.toNumber())).join('')).to.be.eq(collectionName); + expect(collection.description.map(v => String.fromCharCode(v.toNumber())).join('')).to.be.eq(description); + expect(collection.tokenPrefix.toHuman()).to.be.eq(tokenPrefix); + expect(collection.schemaVersion.type).to.be.eq('ImageURL'); + }); + + itWeb3('Check collection address exist', async ({api, web3}) => { + const owner = await createEthAccountWithBalance(api, web3); + const collectionHelper = evmCollectionHelper(web3, owner); + + const expectedCollectionId = await getCreatedCollectionCount(api) + 1; + const expectedCollectionAddress = collectionIdToAddress(expectedCollectionId); + expect(await collectionHelper.methods + .isCollectionExist(expectedCollectionAddress) + .call()).to.be.false; + + await collectionHelper.methods + .create721Collection('A', 'A', 'A') + .send(); + + expect(await collectionHelper.methods + .isCollectionExist(expectedCollectionAddress) + .call()).to.be.true; + }); + + itWeb3('Set sponsorship', async ({api, web3}) => { + const owner = await createEthAccountWithBalance(api, web3); + 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); + const collectionEvm = evmCollection(web3, owner, collectionIdAddress); + result = await collectionEvm.methods.ethSetSponsor(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.ethConfirmSponsorship().call()).to.be.rejectedWith('Caller is not set as sponsor'); + const sponsorCollection = evmCollection(web3, sponsor, collectionIdAddress); + await sponsorCollection.methods.ethConfirmSponsorship().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 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, + sponsoredDataSize: 1024, + sponsoredDataRateLimit: 30, + tokenLimit: 1000000, + sponsorTransferTimeout: 6, + sponsorApproveTimeout: 6, + ownerCanTransfer: false, + ownerCanDestroy: false, + transfersEnabled: false, + }; + + const collectionEvm = evmCollection(web3, owner, collectionIdAddress); + await collectionEvm.methods.setLimit('accountTokenOwnershipLimit', limits.accountTokenOwnershipLimit.toString()).send(); + await collectionEvm.methods.setLimit('sponsoredDataSize', limits.sponsoredDataSize.toString()).send(); + await collectionEvm.methods.setLimit('sponsoredDataRateLimit', limits.sponsoredDataRateLimit.toString()).send(); + await collectionEvm.methods.setLimit('tokenLimit', limits.tokenLimit.toString()).send(); + await collectionEvm.methods.setLimit('sponsorTransferTimeout', limits.sponsorTransferTimeout.toString()).send(); + await collectionEvm.methods.setLimit('sponsorApproveTimeout', limits.sponsorApproveTimeout.toString()).send(); + await collectionEvm.methods.setLimit('ownerCanTransfer', limits.ownerCanTransfer.toString()).send(); + await collectionEvm.methods.setLimit('ownerCanDestroy', limits.ownerCanDestroy.toString()).send(); + await collectionEvm.methods.setLimit('transfersEnabled', limits.transfersEnabled.toString()).send(); + + 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); + 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('Collection address exist', async ({api, web3}) => { + const owner = await createEthAccountWithBalance(api, web3); + const collectionAddressForNonexistentCollection = '0x17C4E6453CC49AAAAEACA894E6D9683E00112233'; + const collectionHelper = evmCollectionHelper(web3, owner); + expect(await collectionHelper.methods + .isCollectionExist(collectionAddressForNonexistentCollection).call()) + .to.be.false; + + const result = await collectionHelper.methods.create721Collection('Collection address exist', '7', '7').send(); + const {collectionIdAddress} = await getCollectionAddressFromResult(api, result); + expect(await collectionHelper.methods + .isCollectionExist(collectionIdAddress).call()) + .to.be.true; + }); +}); + +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 = evmCollectionHelper(web3, owner); + { + const MAX_NAME_LENGHT = 64; + const collectionName = 'A'.repeat(MAX_NAME_LENGHT + 1); + const description = 'A'; + const tokenPrefix = 'A'; + + await expect(helper.methods + .create721Collection(collectionName, description, tokenPrefix) + .call()).to.be.rejectedWith('name is too long. Max length is ' + MAX_NAME_LENGHT); + + } + { + const MAX_DESCRIPTION_LENGHT = 256; + const collectionName = 'A'; + const description = 'A'.repeat(MAX_DESCRIPTION_LENGHT + 1); + const tokenPrefix = 'A'; + await expect(helper.methods + .create721Collection(collectionName, description, tokenPrefix) + .call()).to.be.rejectedWith('description is too long. Max length is ' + MAX_DESCRIPTION_LENGHT); + } + { + const MAX_TOKEN_PREFIX_LENGHT = 16; + const collectionName = 'A'; + const description = 'A'; + const tokenPrefix = 'A'.repeat(MAX_TOKEN_PREFIX_LENGHT + 1); + await expect(helper.methods + .create721Collection(collectionName, description, tokenPrefix) + .call()).to.be.rejectedWith('token_prefix is too long. Max length is ' + MAX_TOKEN_PREFIX_LENGHT); + } + }); + + itWeb3('(!negative test!) Create collection (no funds)', async ({web3}) => { + const owner = await createEthAccount(web3); + const helper = evmCollectionHelper(web3, owner); + const collectionName = 'A'; + const description = 'A'; + const tokenPrefix = 'A'; + + await expect(helper.methods + .create721Collection(collectionName, description, tokenPrefix) + .call()).to.be.rejectedWith('NotSufficientFounds'); + }); + + itWeb3('(!negative test!) Check owner', async ({api, web3}) => { + const owner = await createEthAccountWithBalance(api, web3); + const notOwner = await createEthAccount(web3); + 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(contractEvmFromNotOwner.methods + .ethSetSponsor(sponsor) + .call()).to.be.rejectedWith(EXPECTED_ERROR); + + const sponsorCollection = evmCollection(web3, sponsor, collectionIdAddress); + await expect(sponsorCollection.methods + .ethConfirmSponsorship() + .call()).to.be.rejectedWith('Caller is not set as sponsor'); + } + { + await expect(contractEvmFromNotOwner.methods + .setLimit('account_token_ownership_limit', '1000') + .call()).to.be.rejectedWith(EXPECTED_ERROR); + } + }); + + itWeb3('(!negative test!) Set limits', async ({api, web3}) => { + const owner = await createEthAccountWithBalance(api, web3); + 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); + await expect(collectionEvm.methods + .setLimit('badLimit', 'true') + .call()).to.be.rejectedWith('Unknown limit "badLimit"'); + await expect(collectionEvm.methods + .setLimit('sponsoredDataSize', 'badValue') + .call()).to.be.rejectedWith('Int value "badValue" parse error:'); + await expect(collectionEvm.methods + .setLimit('ownerCanTransfer', 'badValue') + .call()).to.be.rejectedWith('Bool value "badValue" parse error:'); + }); +}); \ No newline at end of file --- a/tests/src/eth/fungibleAbi.json +++ b/tests/src/eth/fungibleAbi.json @@ -1,175 +1,206 @@ [ - { - "constant": false, - "inputs": [ - { - "name": "_spender", - "type": "address" - }, - { - "name": "_value", - "type": "uint256" - } - ], - "name": "approve", - "outputs": [ - { - "name": "", - "type": "bool" - } - ], - "payable": false, - "stateMutability": "nonpayable", - "type": "function" - }, - { - "constant": true, - "inputs": [], - "name": "totalSupply", - "outputs": [ - { - "name": "", - "type": "uint256" - } - ], - "payable": false, - "stateMutability": "view", - "type": "function" - }, - { - "constant": false, - "inputs": [ - { - "name": "_from", - "type": "address" - }, - { - "name": "_to", - "type": "address" - }, - { - "name": "_value", - "type": "uint256" - } - ], - "name": "transferFrom", - "outputs": [ - { - "name": "", - "type": "bool" - } - ], - "payable": false, - "stateMutability": "nonpayable", - "type": "function" - }, - { - "constant": true, - "inputs": [ - { - "name": "_owner", - "type": "address" - } - ], - "name": "balanceOf", - "outputs": [ - { - "name": "balance", - "type": "uint256" - } - ], - "payable": false, - "stateMutability": "view", - "type": "function" - }, - { - "constant": false, - "inputs": [ - { - "name": "_to", - "type": "address" - }, - { - "name": "_value", - "type": "uint256" - } - ], - "name": "transfer", - "outputs": [ - { - "name": "", - "type": "bool" - } - ], - "payable": false, - "stateMutability": "nonpayable", - "type": "function" - }, - { - "constant": true, - "inputs": [ - { - "name": "_owner", - "type": "address" - }, - { - "name": "_spender", - "type": "address" - } - ], - "name": "allowance", - "outputs": [ - { - "name": "", - "type": "uint256" - } - ], - "payable": false, - "stateMutability": "view", - "type": "function" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "name": "owner", - "type": "address" - }, - { - "indexed": true, - "name": "spender", - "type": "address" - }, - { - "indexed": false, - "name": "value", - "type": "uint256" - } - ], - "name": "Approval", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "name": "from", - "type": "address" - }, - { - "indexed": true, - "name": "to", - "type": "address" - }, - { - "indexed": false, - "name": "value", - "type": "uint256" - } - ], - "name": "Transfer", - "type": "event" - } -] \ No newline at end of file + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "spender", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "value", + "type": "uint256" + } + ], + "name": "Approval", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "from", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "value", + "type": "uint256" + } + ], + "name": "Transfer", + "type": "event" + }, + { + "inputs": [ + { "internalType": "address", "name": "owner", "type": "address" }, + { "internalType": "address", "name": "spender", "type": "address" } + ], + "name": "allowance", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { "internalType": "address", "name": "spender", "type": "address" }, + { "internalType": "uint256", "name": "amount", "type": "uint256" } + ], + "name": "approve", + "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { "internalType": "address", "name": "owner", "type": "address" } + ], + "name": "balanceOf", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { "internalType": "address", "name": "from", "type": "address" }, + { "internalType": "uint256", "name": "amount", "type": "uint256" } + ], + "name": "burnFrom", + "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [{ "internalType": "string", "name": "key", "type": "string" }], + "name": "collectionProperty", + "outputs": [{ "internalType": "bytes", "name": "", "type": "bytes" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "contractAddress", + "outputs": [{ "internalType": "address", "name": "", "type": "address" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "decimals", + "outputs": [{ "internalType": "uint8", "name": "", "type": "uint8" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [{ "internalType": "string", "name": "key", "type": "string" }], + "name": "deleteCollectionProperty", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "ethConfirmSponsorship", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { "internalType": "address", "name": "sponsor", "type": "address" } + ], + "name": "ethSetSponsor", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "name", + "outputs": [{ "internalType": "string", "name": "", "type": "string" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { "internalType": "string", "name": "key", "type": "string" }, + { "internalType": "bytes", "name": "value", "type": "bytes" } + ], + "name": "setCollectionProperty", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { "internalType": "string", "name": "limit", "type": "string" }, + { "internalType": "string", "name": "value", "type": "string" } + ], + "name": "setLimit", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { "internalType": "bytes4", "name": "interfaceID", "type": "bytes4" } + ], + "name": "supportsInterface", + "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "symbol", + "outputs": [{ "internalType": "string", "name": "", "type": "string" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "totalSupply", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { "internalType": "address", "name": "to", "type": "address" }, + { "internalType": "uint256", "name": "amount", "type": "uint256" } + ], + "name": "transfer", + "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { "internalType": "address", "name": "from", "type": "address" }, + { "internalType": "address", "name": "to", "type": "address" }, + { "internalType": "uint256", "name": "amount", "type": "uint256" } + ], + "name": "transferFrom", + "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }], + "stateMutability": "nonpayable", + "type": "function" + } +] --- a/tests/src/eth/fungibleMetadataAbi.json +++ /dev/null @@ -1,41 +0,0 @@ -[ - { - "inputs": [], - "name": "name", - "outputs": [ - { - "internalType": "string", - "name": "", - "type": "string" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "symbol", - "outputs": [ - { - "internalType": "string", - "name": "", - "type": "string" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "decimals", - "outputs": [ - { - "internalType": "uint8", - "name": "", - "type": "uint8" - } - ], - "stateMutability": "view", - "type": "function" - } -] \ No newline at end of file --- a/tests/src/eth/metadata.test.ts +++ /dev/null @@ -1,210 +0,0 @@ -// 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 . - -import {expect} from 'chai'; -import {createCollectionExpectSuccess} from '../util/helpers'; -import {collectionIdToAddress, createEthAccount, createEthAccountWithBalance, GAS_ARGS, itWeb3, normalizeEvents} from './util/helpers'; -import fungibleMetadataAbi from './fungibleMetadataAbi.json'; -import privateKey from '../substrate/privateKey'; -import {submitTransactionAsync} from '../substrate/substrate-api'; -import nonFungibleAbi from './nonFungibleAbi.json'; - -describe('Common metadata', () => { - itWeb3('Returns collection name', async ({api, web3}) => { - const collection = await createCollectionExpectSuccess({ - name: 'token name', - mode: {type: 'NFT'}, - }); - const caller = await createEthAccountWithBalance(api, web3); - - const address = collectionIdToAddress(collection); - const contract = new web3.eth.Contract(fungibleMetadataAbi as any, address, {from: caller, ...GAS_ARGS}); - const name = await contract.methods.name().call(); - - expect(name).to.equal('token name'); - }); - - itWeb3('Returns symbol name', async ({api, web3}) => { - const collection = await createCollectionExpectSuccess({ - tokenPrefix: 'TOK', - mode: {type: 'NFT'}, - }); - const caller = await createEthAccountWithBalance(api, web3); - - const address = collectionIdToAddress(collection); - const contract = new web3.eth.Contract(fungibleMetadataAbi as any, address, {from: caller, ...GAS_ARGS}); - const symbol = await contract.methods.symbol().call(); - - expect(symbol).to.equal('TOK'); - }); -}); - -describe('Fungible metadata', () => { - itWeb3('Returns fungible decimals', async ({api, web3}) => { - const collection = await createCollectionExpectSuccess({ - mode: {type: 'Fungible', decimalPoints: 6}, - }); - const caller = await createEthAccountWithBalance(api, web3); - - const address = collectionIdToAddress(collection); - const contract = new web3.eth.Contract(fungibleMetadataAbi as any, address, {from: caller, ...GAS_ARGS}); - const decimals = await contract.methods.decimals().call(); - - expect(+decimals).to.equal(6); - }); -}); - -describe('Support ERC721Metadata', () => { - itWeb3('Check unsupport ERC721Metadata SchemaVersion::Unique', async ({web3, api}) => { - const collectionId = await createCollectionExpectSuccess({ - mode: {type: 'NFT'}, - schemaVersion: 'Unique', - name: 'some_name', - tokenPrefix: 'some_prefix', - }); - const collection = await api.rpc.unique.collectionById(collectionId); - expect(collection.isSome).to.be.true; - expect(collection.unwrap().schemaVersion.toHuman()).to.be.eq('Unique'); - - const alice = privateKey('//Alice'); - - const caller = await createEthAccountWithBalance(api, web3); - const changeAdminTx = api.tx.unique.addCollectionAdmin(collectionId, {Ethereum: caller}); - await submitTransactionAsync(alice, changeAdminTx); - - const address = collectionIdToAddress(collectionId); - const contract = new web3.eth.Contract(nonFungibleAbi as any, address, {from: caller, ...GAS_ARGS}); - - expect(await contract.methods.name().call()).to.be.eq('some_name'); - expect(await contract.methods.symbol().call()).to.be.eq('some_prefix'); - - const receiver = createEthAccount(web3); - const nextTokenId = await contract.methods.nextTokenId().call(); - expect(nextTokenId).to.be.equal('1'); - await expect(contract.methods.mintWithTokenURI( - receiver, - nextTokenId, - 'Test URI', - ).call({from: caller})).to.be.rejectedWith('Unsupported schema version! Support only ImageURL'); - - await expect(contract.methods.mintBulkWithTokenURI( - receiver, - [ - [nextTokenId, 'Test URI 0'], - [+nextTokenId + 1, 'Test URI 1'], - [+nextTokenId + 2, 'Test URI 2'], - ], - ).call({from: caller})).to.be.rejectedWith('Unsupported schema version! Support only ImageURL'); - }); - - itWeb3('Check support ERC721Metadata for SchemaVersion::ImageURL', async ({web3, api}) => { - const collectionId = await createCollectionExpectSuccess({ - mode: {type: 'NFT'}, - name: 'some_name', - tokenPrefix: 'some_prefix', - }); - const collection = await api.rpc.unique.collectionById(collectionId); - expect(collection.isSome).to.be.true; - expect(collection.unwrap().schemaVersion.toHuman()).to.be.eq('ImageURL'); - - const alice = privateKey('//Alice'); - - const caller = await createEthAccountWithBalance(api, web3); - const changeAdminTx = api.tx.unique.addCollectionAdmin(collectionId, {Ethereum: caller}); - await submitTransactionAsync(alice, changeAdminTx); - - const address = collectionIdToAddress(collectionId); - const contract = new web3.eth.Contract(nonFungibleAbi as any, address, {from: caller, ...GAS_ARGS}); - - expect(await contract.methods.name().call()).to.be.eq('some_name'); - expect(await contract.methods.symbol().call()).to.be.eq('some_prefix'); - - const receiver = createEthAccount(web3); - { // mintWithTokenURI - const nextTokenId = await contract.methods.nextTokenId().call(); - expect(nextTokenId).to.be.equal('1'); - const result = await contract.methods.mintWithTokenURI( - receiver, - nextTokenId, - 'Test URI', - ).send({from: caller}); - const events = normalizeEvents(result.events); - - expect(events).to.be.deep.equal([ - { - address, - event: 'Transfer', - args: { - from: '0x0000000000000000000000000000000000000000', - to: receiver, - tokenId: nextTokenId, - }, - }, - ]); - - expect(await contract.methods.tokenURI(nextTokenId).call()).to.be.equal('Test URI'); - } - - { // mintBulkWithTokenURI - const nextTokenId = await contract.methods.nextTokenId().call(); - expect(nextTokenId).to.be.equal('2'); - const result = await contract.methods.mintBulkWithTokenURI( - receiver, - [ - [nextTokenId, 'Test URI 0'], - [+nextTokenId + 1, 'Test URI 1'], - [+nextTokenId + 2, 'Test URI 2'], - ], - ).send({from: caller}); - const events = normalizeEvents(result.events); - - expect(events).to.be.deep.equal([ - { - address, - event: 'Transfer', - args: { - from: '0x0000000000000000000000000000000000000000', - to: receiver, - tokenId: nextTokenId, - }, - }, - { - address, - event: 'Transfer', - args: { - from: '0x0000000000000000000000000000000000000000', - to: receiver, - tokenId: String(+nextTokenId + 1), - }, - }, - { - address, - event: 'Transfer', - args: { - from: '0x0000000000000000000000000000000000000000', - to: receiver, - tokenId: String(+nextTokenId + 2), - }, - }, - ]); - - expect(await contract.methods.tokenURI(nextTokenId).call()).to.be.equal('Test URI 0'); - expect(await contract.methods.tokenURI(+nextTokenId + 1).call()).to.be.equal('Test URI 1'); - expect(await contract.methods.tokenURI(+nextTokenId + 2).call()).to.be.equal('Test URI 2'); - } - }); -}); - --- a/tests/src/eth/nonFungible.test.ts +++ b/tests/src/eth/nonFungible.test.ts @@ -16,7 +16,7 @@ import privateKey from '../substrate/privateKey'; import {approveExpectSuccess, burnItemExpectSuccess, createCollectionExpectSuccess, createItemExpectSuccess, transferExpectSuccess, transferFromExpectSuccess, UNIQUE} from '../util/helpers'; -import {collectionIdToAddress, createEthAccount, createEthAccountWithBalance, GAS_ARGS, itWeb3, normalizeEvents, recordEthFee, recordEvents, subToEth, transferBalanceToEth} from './util/helpers'; +import {collectionIdToAddress, createEthAccount, createEthAccountWithBalance, evmCollection, evmCollectionHelper, GAS_ARGS, getCollectionAddressFromResult, itWeb3, normalizeEvents, recordEthFee, recordEvents, subToEth, transferBalanceToEth} from './util/helpers'; import nonFungibleAbi from './nonFungibleAbi.json'; import {expect} from 'chai'; import {submitTransactionAsync} from '../substrate/substrate-api'; @@ -75,45 +75,46 @@ describe('NFT: Plain calls', () => { itWeb3('Can perform mint()', async ({web3, api}) => { - const collection = await createCollectionExpectSuccess({ - mode: {type: 'NFT'}, - }); - const alice = privateKey('//Alice'); - - const caller = await createEthAccountWithBalance(api, web3); - const changeAdminTx = api.tx.unique.addCollectionAdmin(collection, {Ethereum: caller}); - await submitTransactionAsync(alice, changeAdminTx); + const owner = await createEthAccountWithBalance(api, web3); + 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); + const contract = evmCollection(web3, owner, collectionIdAddress); + const nextTokenId = await contract.methods.nextTokenId().call(); - const address = collectionIdToAddress(collection); - const contract = new web3.eth.Contract(nonFungibleAbi as any, address, {from: caller, ...GAS_ARGS}); + expect(nextTokenId).to.be.equal('1'); + result = await contract.methods.mintWithTokenURI( + receiver, + nextTokenId, + 'Test URI', + ).send(); - { - const nextTokenId = await contract.methods.nextTokenId().call(); - expect(nextTokenId).to.be.equal('1'); - const result = await contract.methods.mintWithTokenURI( - receiver, - nextTokenId, - 'Test URI', - ).send({from: caller}); - const events = normalizeEvents(result.events); + const events = normalizeEvents(result.events); + const address = collectionIdToAddress(collectionId); - expect(events).to.be.deep.equal([ - { - address, - event: 'Transfer', - args: { - from: '0x0000000000000000000000000000000000000000', - to: receiver, - tokenId: nextTokenId, - }, + expect(events).to.be.deep.equal([ + { + address, + event: 'Transfer', + args: { + from: '0x0000000000000000000000000000000000000000', + to: receiver, + tokenId: nextTokenId, }, - ]); + }, + ]); + + expect(await contract.methods.tokenURI(nextTokenId).call()).to.be.equal('Test URI'); - expect(await contract.methods.tokenURI(nextTokenId).call()).to.be.equal('Test URI'); - } + // 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(); + // expect(tokenUri).to.be.equal(`https://offchain-service.local/token-info/${nextTokenId}`); }); - itWeb3('Can perform mintBulk()', async ({web3, api}) => { + + //TODO: CORE-302 add eth methods + itWeb3.skip('Can perform mintBulk()', async ({web3, api}) => { const collection = await createCollectionExpectSuccess({ mode: {type: 'NFT'}, }); @@ -539,3 +540,33 @@ ]); }); }); + +describe('Common metadata', () => { + itWeb3('Returns collection name', async ({api, web3}) => { + const collection = await createCollectionExpectSuccess({ + name: 'token name', + mode: {type: 'NFT'}, + }); + const caller = await createEthAccountWithBalance(api, web3); + + const address = collectionIdToAddress(collection); + const contract = new web3.eth.Contract(nonFungibleAbi as any, address, {from: caller, ...GAS_ARGS}); + const name = await contract.methods.name().call(); + + expect(name).to.equal('token name'); + }); + + itWeb3('Returns symbol name', async ({api, web3}) => { + const collection = await createCollectionExpectSuccess({ + tokenPrefix: 'TOK', + mode: {type: 'NFT'}, + }); + const caller = await createEthAccountWithBalance(api, web3); + + const address = collectionIdToAddress(collection); + const contract = new web3.eth.Contract(nonFungibleAbi as any, address, {from: caller, ...GAS_ARGS}); + const symbol = await contract.methods.symbol().call(); + + expect(symbol).to.equal('TOK'); + }); +}); \ No newline at end of file --- a/tests/src/eth/nonFungibleAbi.json +++ b/tests/src/eth/nonFungibleAbi.json @@ -1,738 +1,431 @@ [ - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "approved", - "type": "address" - }, - { - "indexed": true, - "internalType": "uint256", - "name": "tokenId", - "type": "uint256" - } - ], - "name": "Approval", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "operator", - "type": "address" - }, - { - "indexed": false, - "internalType": "bool", - "name": "approved", - "type": "bool" - } - ], - "name": "ApprovalForAll", - "type": "event" - }, - { - "anonymous": false, - "inputs": [], - "name": "MintingFinished", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "from", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "to", - "type": "address" - }, - { - "indexed": true, - "internalType": "uint256", - "name": "tokenId", - "type": "uint256" - } - ], - "name": "Transfer", - "type": "event" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "approved", - "type": "address" - }, - { - "internalType": "uint256", - "name": "tokenId", - "type": "uint256" - } - ], - "name": "approve", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "owner", - "type": "address" - } - ], - "name": "balanceOf", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "tokenId", - "type": "uint256" - } - ], - "name": "burn", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "from", - "type": "address" - }, - { - "internalType": "uint256", - "name": "tokenId", - "type": "uint256" - } - ], - "name": "burnFrom", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "string", - "name": "key", - "type": "string" - } - ], - "name": "collectionProperty", - "outputs": [ - { - "internalType": "bytes", - "name": "", - "type": "bytes" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "string", - "name": "key", - "type": "string" - } - ], - "name": "deleteCollectionProperty", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "tokenId", - "type": "uint256" - }, - { - "internalType": "string", - "name": "key", - "type": "string" - } - ], - "name": "deleteProperty", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "finishMinting", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "tokenId", - "type": "uint256" - } - ], - "name": "getApproved", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "internalType": "address", - "name": "operator", - "type": "address" - } - ], - "name": "isApprovedForAll", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "to", - "type": "address" - }, - { - "internalType": "uint256", - "name": "tokenId", - "type": "uint256" - } - ], - "name": "mint", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "to", - "type": "address" - }, - { - "internalType": "uint256[]", - "name": "tokenIds", - "type": "uint256[]" - } - ], - "name": "mintBulk", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "to", - "type": "address" - }, - { - "components": [ - { - "internalType": "uint256", - "name": "field_0", - "type": "uint256" - }, - { - "internalType": "string", - "name": "field_1", - "type": "string" - } - ], - "internalType": "struct Tuple0[]", - "name": "tokens", - "type": "tuple[]" - } - ], - "name": "mintBulkWithTokenURI", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "to", - "type": "address" - }, - { - "internalType": "uint256", - "name": "tokenId", - "type": "uint256" - }, - { - "internalType": "string", - "name": "tokenUri", - "type": "string" - } - ], - "name": "mintWithTokenURI", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "mintingFinished", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "name", - "outputs": [ - { - "internalType": "string", - "name": "", - "type": "string" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "nextTokenId", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "tokenId", - "type": "uint256" - } - ], - "name": "ownerOf", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "tokenId", - "type": "uint256" - }, - { - "internalType": "string", - "name": "key", - "type": "string" - } - ], - "name": "property", - "outputs": [ - { - "internalType": "bytes", - "name": "", - "type": "bytes" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "from", - "type": "address" - }, - { - "internalType": "address", - "name": "to", - "type": "address" - }, - { - "internalType": "uint256", - "name": "tokenId", - "type": "uint256" - } - ], - "name": "safeTransferFrom", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "from", - "type": "address" - }, - { - "internalType": "address", - "name": "to", - "type": "address" - }, - { - "internalType": "uint256", - "name": "tokenId", - "type": "uint256" - }, - { - "internalType": "bytes", - "name": "data", - "type": "bytes" - } - ], - "name": "safeTransferFromWithData", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "operator", - "type": "address" - }, - { - "internalType": "bool", - "name": "approved", - "type": "bool" - } - ], - "name": "setApprovalForAll", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "string", - "name": "key", - "type": "string" - }, - { - "internalType": "bytes", - "name": "value", - "type": "bytes" - } - ], - "name": "setCollectionProperty", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "tokenId", - "type": "uint256" - }, - { - "internalType": "string", - "name": "key", - "type": "string" - }, - { - "internalType": "bytes", - "name": "value", - "type": "bytes" - } - ], - "name": "setProperty", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "string", - "name": "key", - "type": "string" - }, - { - "internalType": "bool", - "name": "isMutable", - "type": "bool" - }, - { - "internalType": "bool", - "name": "collectionAdmin", - "type": "bool" - }, - { - "internalType": "bool", - "name": "tokenOwner", - "type": "bool" - } - ], - "name": "setTokenPropertyPermission", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes4", - "name": "interfaceID", - "type": "bytes4" - } - ], - "name": "supportsInterface", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "symbol", - "outputs": [ - { - "internalType": "string", - "name": "", - "type": "string" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "index", - "type": "uint256" - } - ], - "name": "tokenByIndex", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "internalType": "uint256", - "name": "index", - "type": "uint256" - } - ], - "name": "tokenOfOwnerByIndex", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "tokenId", - "type": "uint256" - } - ], - "name": "tokenURI", - "outputs": [ - { - "internalType": "string", - "name": "", - "type": "string" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "totalSupply", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "to", - "type": "address" - }, - { - "internalType": "uint256", - "name": "tokenId", - "type": "uint256" - } - ], - "name": "transfer", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "from", - "type": "address" - }, - { - "internalType": "address", - "name": "to", - "type": "address" - }, - { - "internalType": "uint256", - "name": "tokenId", - "type": "uint256" - } - ], - "name": "transferFrom", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - } -] \ No newline at end of file + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "approved", + "type": "address" + }, + { + "indexed": true, + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + } + ], + "name": "Approval", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "operator", + "type": "address" + }, + { + "indexed": false, + "internalType": "bool", + "name": "approved", + "type": "bool" + } + ], + "name": "ApprovalForAll", + "type": "event" + }, + { + "anonymous": false, + "inputs": [], + "name": "MintingFinished", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "from", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "indexed": true, + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + } + ], + "name": "Transfer", + "type": "event" + }, + { + "inputs": [ + { "internalType": "address", "name": "approved", "type": "address" }, + { "internalType": "uint256", "name": "tokenId", "type": "uint256" } + ], + "name": "approve", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { "internalType": "address", "name": "owner", "type": "address" } + ], + "name": "balanceOf", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { "internalType": "uint256", "name": "tokenId", "type": "uint256" } + ], + "name": "burn", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { "internalType": "address", "name": "from", "type": "address" }, + { "internalType": "uint256", "name": "tokenId", "type": "uint256" } + ], + "name": "burnFrom", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [{ "internalType": "string", "name": "key", "type": "string" }], + "name": "collectionProperty", + "outputs": [{ "internalType": "bytes", "name": "", "type": "bytes" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "contractAddress", + "outputs": [{ "internalType": "address", "name": "", "type": "address" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [{ "internalType": "string", "name": "key", "type": "string" }], + "name": "deleteCollectionProperty", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { "internalType": "uint256", "name": "tokenId", "type": "uint256" }, + { "internalType": "string", "name": "key", "type": "string" } + ], + "name": "deleteProperty", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "ethConfirmSponsorship", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { "internalType": "address", "name": "sponsor", "type": "address" } + ], + "name": "ethSetSponsor", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "finishMinting", + "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { "internalType": "uint256", "name": "tokenId", "type": "uint256" } + ], + "name": "getApproved", + "outputs": [{ "internalType": "address", "name": "", "type": "address" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { "internalType": "address", "name": "owner", "type": "address" }, + { "internalType": "address", "name": "operator", "type": "address" } + ], + "name": "isApprovedForAll", + "outputs": [{ "internalType": "address", "name": "", "type": "address" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { "internalType": "address", "name": "to", "type": "address" }, + { "internalType": "uint256", "name": "tokenId", "type": "uint256" } + ], + "name": "mint", + "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { "internalType": "address", "name": "to", "type": "address" }, + { "internalType": "uint256[]", "name": "tokenIds", "type": "uint256[]" } + ], + "name": "mintBulk", + "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { "internalType": "address", "name": "to", "type": "address" }, + { + "components": [ + { "internalType": "uint256", "name": "field_0", "type": "uint256" }, + { "internalType": "string", "name": "field_1", "type": "string" } + ], + "internalType": "struct Tuple0[]", + "name": "tokens", + "type": "tuple[]" + } + ], + "name": "mintBulkWithTokenURI", + "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { "internalType": "address", "name": "to", "type": "address" }, + { "internalType": "uint256", "name": "tokenId", "type": "uint256" }, + { "internalType": "string", "name": "tokenUri", "type": "string" } + ], + "name": "mintWithTokenURI", + "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "mintingFinished", + "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "name", + "outputs": [{ "internalType": "string", "name": "", "type": "string" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "nextTokenId", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { "internalType": "uint256", "name": "tokenId", "type": "uint256" } + ], + "name": "ownerOf", + "outputs": [{ "internalType": "address", "name": "", "type": "address" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { "internalType": "uint256", "name": "tokenId", "type": "uint256" }, + { "internalType": "string", "name": "key", "type": "string" } + ], + "name": "property", + "outputs": [{ "internalType": "bytes", "name": "", "type": "bytes" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { "internalType": "address", "name": "from", "type": "address" }, + { "internalType": "address", "name": "to", "type": "address" }, + { "internalType": "uint256", "name": "tokenId", "type": "uint256" } + ], + "name": "safeTransferFrom", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { "internalType": "address", "name": "from", "type": "address" }, + { "internalType": "address", "name": "to", "type": "address" }, + { "internalType": "uint256", "name": "tokenId", "type": "uint256" }, + { "internalType": "bytes", "name": "data", "type": "bytes" } + ], + "name": "safeTransferFromWithData", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { "internalType": "address", "name": "operator", "type": "address" }, + { "internalType": "bool", "name": "approved", "type": "bool" } + ], + "name": "setApprovalForAll", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { "internalType": "string", "name": "key", "type": "string" }, + { "internalType": "bytes", "name": "value", "type": "bytes" } + ], + "name": "setCollectionProperty", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { "internalType": "string", "name": "limit", "type": "string" }, + { "internalType": "string", "name": "value", "type": "string" } + ], + "name": "setLimit", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { "internalType": "uint256", "name": "tokenId", "type": "uint256" }, + { "internalType": "string", "name": "key", "type": "string" }, + { "internalType": "bytes", "name": "value", "type": "bytes" } + ], + "name": "setProperty", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { "internalType": "string", "name": "key", "type": "string" }, + { "internalType": "bool", "name": "isMutable", "type": "bool" }, + { "internalType": "bool", "name": "collectionAdmin", "type": "bool" }, + { "internalType": "bool", "name": "tokenOwner", "type": "bool" } + ], + "name": "setTokenPropertyPermission", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { "internalType": "bytes4", "name": "interfaceID", "type": "bytes4" } + ], + "name": "supportsInterface", + "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "symbol", + "outputs": [{ "internalType": "string", "name": "", "type": "string" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { "internalType": "uint256", "name": "index", "type": "uint256" } + ], + "name": "tokenByIndex", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { "internalType": "address", "name": "owner", "type": "address" }, + { "internalType": "uint256", "name": "index", "type": "uint256" } + ], + "name": "tokenOfOwnerByIndex", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { "internalType": "uint256", "name": "tokenId", "type": "uint256" } + ], + "name": "tokenURI", + "outputs": [{ "internalType": "string", "name": "", "type": "string" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "totalSupply", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { "internalType": "address", "name": "to", "type": "address" }, + { "internalType": "uint256", "name": "tokenId", "type": "uint256" } + ], + "name": "transfer", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { "internalType": "address", "name": "from", "type": "address" }, + { "internalType": "address", "name": "to", "type": "address" }, + { "internalType": "uint256", "name": "tokenId", "type": "uint256" } + ], + "name": "transferFrom", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + } +] --- a/tests/src/eth/proxy/nonFungibleProxy.test.ts +++ b/tests/src/eth/proxy/nonFungibleProxy.test.ts @@ -88,7 +88,8 @@ }); describe('NFT (Via EVM proxy): Plain calls', () => { - itWeb3('Can perform mint()', async ({web3, api}) => { + //TODO: CORE-302 add eth methods + itWeb3.skip('Can perform mint()', async ({web3, api}) => { const collection = await createCollectionExpectSuccess({ mode: {type: 'NFT'}, }); @@ -127,7 +128,9 @@ expect(await contract.methods.tokenURI(nextTokenId).call()).to.be.equal('Test URI'); } }); - itWeb3('Can perform mintBulk()', async ({web3, api}) => { + + //TODO: CORE-302 add eth methods + itWeb3.skip('Can perform mintBulk()', async ({web3, api}) => { const collection = await createCollectionExpectSuccess({ mode: {type: 'NFT'}, }); --- a/tests/src/eth/util/contractHelpersAbi.json +++ b/tests/src/eth/util/contractHelpersAbi.json @@ -1,216 +1,161 @@ [ - { - "inputs": [ - { - "internalType": "address", - "name": "contract", - "type": "address" - } - ], - "name": "allowlistEnabled", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "target", - "type": "address" - }, - { - "internalType": "address", - "name": "caller", - "type": "address" - } - ], - "name": "allowed", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "target", - "type": "address" - } - ], - "name": "contractOwner", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "target", - "type": "address" - } - ], - "name": "sponsoringEnabled", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "target", - "type": "address" - }, - { - "internalType": "address", - "name": "user", - "type": "address" - }, - { - "internalType": "bool", - "name": "isAllowed", - "type": "bool" - } - ], - "name": "toggleAllowed", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "target", - "type": "address" - }, - { - "internalType": "bool", - "name": "enabled", - "type": "bool" - } - ], - "name": "toggleAllowlist", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "target", - "type": "address" - }, - { - "internalType": "bool", - "name": "enabled", - "type": "bool" - } - ], - "name": "toggleSponsoring", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "target", - "type": "address" - }, - { - "internalType": "uint8", - "name": "mode", - "type": "uint8" - } - ], - "name": "setSponsoringMode", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "target", - "type": "address" - } - ], - "name": "sponsoringMode", - "outputs": [ - { - "internalType": "uint8", - "name": "", - "type": "uint8" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "target", - "type": "address" - }, - { - "internalType": "uint32", - "name": "limit", - "type": "uint32" - } - ], - "name": "setSponsoringRateLimit", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "contractAddress", - "type": "address" - } - ], - "name": "getSponsoringRateLimit", - "outputs": [ - { - "internalType": "uint32", - "name": "", - "type": "uint32" - } - ], - "stateMutability": "view", - "type": "function" - } + { + "inputs": [ + { + "internalType": "address", + "name": "contractAddress", + "type": "address" + }, + { "internalType": "address", "name": "user", "type": "address" } + ], + "name": "allowed", + "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "contractAddress", + "type": "address" + } + ], + "name": "allowlistEnabled", + "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "contractAddress", + "type": "address" + } + ], + "name": "contractOwner", + "outputs": [{ "internalType": "address", "name": "", "type": "address" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "contractAddress", + "type": "address" + } + ], + "name": "getSponsoringRateLimit", + "outputs": [{ "internalType": "uint32", "name": "", "type": "uint32" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "contractAddress", + "type": "address" + }, + { "internalType": "uint8", "name": "mode", "type": "uint8" } + ], + "name": "setSponsoringMode", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "contractAddress", + "type": "address" + }, + { "internalType": "uint32", "name": "rateLimit", "type": "uint32" } + ], + "name": "setSponsoringRateLimit", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "contractAddress", + "type": "address" + } + ], + "name": "sponsoringEnabled", + "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "contractAddress", + "type": "address" + } + ], + "name": "sponsoringMode", + "outputs": [{ "internalType": "uint8", "name": "", "type": "uint8" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { "internalType": "bytes4", "name": "interfaceID", "type": "bytes4" } + ], + "name": "supportsInterface", + "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "contractAddress", + "type": "address" + }, + { "internalType": "address", "name": "user", "type": "address" }, + { "internalType": "bool", "name": "allowed", "type": "bool" } + ], + "name": "toggleAllowed", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "contractAddress", + "type": "address" + }, + { "internalType": "bool", "name": "enabled", "type": "bool" } + ], + "name": "toggleAllowlist", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "contractAddress", + "type": "address" + }, + { "internalType": "bool", "name": "enabled", "type": "bool" } + ], + "name": "toggleSponsoring", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + } ] --- a/tests/src/eth/util/helpers.ts +++ b/tests/src/eth/util/helpers.ts @@ -23,11 +23,13 @@ import usingApi, {submitTransactionAsync} from '../../substrate/substrate-api'; import {IKeyringPair} from '@polkadot/types/types'; import {expect} from 'chai'; -import {CrossAccountId, getGenericResult, UNIQUE} from '../../util/helpers'; +import {CrossAccountId, getDetailedCollectionInfo, getGenericResult, UNIQUE} from '../../util/helpers'; import * as solc from 'solc'; import config from '../../config'; import privateKey from '../../substrate/privateKey'; import contractHelpersAbi from './contractHelpersAbi.json'; +import nonFungibleAbi from '../nonFungibleAbi.json'; +import collectionHelperAbi from '../collectionHelperAbi.json'; import getBalance from '../../substrate/get-balance'; import waitNewBlocks from '../../substrate/wait-new-blocks'; @@ -66,12 +68,30 @@ ]; } +export async function getCollectionAddressFromResult(api: ApiPromise, result: any) { + const collectionIdAddress = normalizeAddress(result.events[0].raw.topics[2]); + const collectionId = collectionIdFromAddress(collectionIdAddress); + const collection = (await getDetailedCollectionInfo(api, collectionId))!; + return {collectionIdAddress, collectionId, collection}; +} + export function collectionIdToAddress(collection: number): string { const buf = Buffer.from([0x17, 0xc4, 0xe6, 0x45, 0x3c, 0xc4, 0x9a, 0xaa, 0xae, 0xac, 0xa8, 0x94, 0xe6, 0xd9, 0x68, 0x3e, ...encodeIntBE(collection), ]); return Web3.utils.toChecksumAddress('0x' + buf.toString('hex')); } +export function collectionIdFromAddress(address: string): number { + if (!address.startsWith('0x')) + throw 'address not starts with "0x"'; + if (address.length > 42) + throw 'address length is more than 20 bytes'; + return Number('0x' + address.substring(address.length - 8)); +} + +export function normalizeAddress(address: string): string { + return '0x' + address.substring(address.length - 40); +} export function tokenIdToAddress(collection: number, token: number): string { const buf = Buffer.from([0xf8, 0x23, 0x8c, 0xcf, 0xff, 0x8e, 0xd8, 0x87, 0x46, 0x3f, 0xd5, 0xe0, @@ -271,6 +291,26 @@ return new web3.eth.Contract(contractHelpersAbi as any, '0x842899ECF380553E8a4de75bF534cdf6fBF64049', {from: caller, ...GAS_ARGS}); } +/** + * evm collection helper + * @param web3 + * @param caller - eth address + * @returns + */ +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(nonFungibleAbi as any, collection, {from: caller, ...GAS_ARGS}); +} + /** * Execute ethereum method call using substrate account * @param to target contract --- a/tests/src/interfaces/augment-types.ts +++ b/tests/src/interfaces/augment-types.ts @@ -1,7 +1,6 @@ // Auto-generated via `yarn polkadot-types-from-defs`, do not edit /* eslint-disable */ -import type { CumulusPalletDmpQueueCall, CumulusPalletDmpQueueConfigData, CumulusPalletDmpQueueError, CumulusPalletDmpQueueEvent, CumulusPalletDmpQueuePageIndexData, CumulusPalletParachainSystemCall, CumulusPalletParachainSystemError, CumulusPalletParachainSystemEvent, CumulusPalletParachainSystemRelayStateSnapshotMessagingStateSnapshot, CumulusPalletXcmCall, CumulusPalletXcmError, CumulusPalletXcmEvent, CumulusPalletXcmpQueueCall, CumulusPalletXcmpQueueError, CumulusPalletXcmpQueueEvent, CumulusPalletXcmpQueueInboundChannelDetails, CumulusPalletXcmpQueueInboundState, CumulusPalletXcmpQueueOutboundChannelDetails, CumulusPalletXcmpQueueOutboundState, CumulusPalletXcmpQueueQueueConfigData, CumulusPrimitivesParachainInherentParachainInherentData, EthbloomBloom, EthereumBlock, EthereumHeader, EthereumLog, EthereumReceiptEip658ReceiptData, EthereumReceiptReceiptV3, EthereumTransactionAccessListItem, EthereumTransactionEip1559Transaction, EthereumTransactionEip2930Transaction, EthereumTransactionLegacyTransaction, EthereumTransactionTransactionAction, EthereumTransactionTransactionSignature, EthereumTransactionTransactionV2, EthereumTypesHashH64, EvmCoreErrorExitError, EvmCoreErrorExitFatal, EvmCoreErrorExitReason, EvmCoreErrorExitRevert, EvmCoreErrorExitSucceed, FpRpcTransactionStatus, FrameSupportPalletId, FrameSupportTokensMiscBalanceStatus, FrameSupportWeightsDispatchClass, FrameSupportWeightsDispatchInfo, FrameSupportWeightsPays, FrameSupportWeightsPerDispatchClassU32, FrameSupportWeightsPerDispatchClassU64, FrameSupportWeightsPerDispatchClassWeightsPerClass, FrameSupportWeightsRuntimeDbWeight, FrameSupportWeightsWeightToFeeCoefficient, FrameSystemAccountInfo, FrameSystemCall, FrameSystemError, FrameSystemEvent, FrameSystemEventRecord, FrameSystemExtensionsCheckGenesis, FrameSystemExtensionsCheckNonce, FrameSystemExtensionsCheckSpecVersion, FrameSystemExtensionsCheckWeight, FrameSystemLastRuntimeUpgradeInfo, FrameSystemLimitsBlockLength, FrameSystemLimitsBlockWeights, FrameSystemLimitsWeightsPerClass, FrameSystemPhase, OpalRuntimeRuntime, OrmlVestingModuleCall, OrmlVestingModuleError, OrmlVestingModuleEvent, OrmlVestingVestingSchedule, PalletBalancesAccountData, PalletBalancesBalanceLock, PalletBalancesCall, PalletBalancesError, PalletBalancesEvent, PalletBalancesReasons, PalletBalancesReleases, PalletBalancesReserveData, PalletCommonError, PalletCommonEvent, PalletEthereumCall, PalletEthereumError, PalletEthereumEvent, PalletEthereumFakeTransactionFinalizer, PalletEvmAccountBasicCrossAccountIdRepr, PalletEvmCall, PalletEvmCoderSubstrateError, PalletEvmContractHelpersError, PalletEvmContractHelpersSponsoringModeT, PalletEvmError, PalletEvmEvent, PalletEvmMigrationCall, PalletEvmMigrationError, PalletFungibleError, PalletInflationCall, PalletNonfungibleError, PalletNonfungibleItemData, PalletRefungibleError, PalletRefungibleItemData, PalletRmrkCoreCall, PalletRmrkCoreError, PalletRmrkCoreEvent, PalletRmrkEquipCall, PalletRmrkEquipError, PalletRmrkEquipEvent, PalletStructureCall, PalletStructureError, PalletStructureEvent, PalletSudoCall, PalletSudoError, PalletSudoEvent, PalletTemplateTransactionPaymentCall, PalletTemplateTransactionPaymentChargeTransactionPayment, PalletTimestampCall, PalletTransactionPaymentReleases, PalletTreasuryCall, PalletTreasuryError, PalletTreasuryEvent, PalletTreasuryProposal, PalletUniqueCall, PalletUniqueError, PalletUniqueRawEvent, PalletXcmCall, PalletXcmError, PalletXcmEvent, PhantomTypeUpDataStructsBaseInfo, PhantomTypeUpDataStructsCollectionInfo, PhantomTypeUpDataStructsNftChild, PhantomTypeUpDataStructsNftInfo, PhantomTypeUpDataStructsPartType, PhantomTypeUpDataStructsPropertyInfo, PhantomTypeUpDataStructsResourceInfo, PhantomTypeUpDataStructsRpcCollection, PhantomTypeUpDataStructsTheme, PhantomTypeUpDataStructsTokenData, PolkadotCorePrimitivesInboundDownwardMessage, PolkadotCorePrimitivesInboundHrmpMessage, PolkadotCorePrimitivesOutboundHrmpMessage, PolkadotParachainPrimitivesXcmpMessageFormat, PolkadotPrimitivesV2AbridgedHostConfiguration, PolkadotPrimitivesV2AbridgedHrmpChannel, PolkadotPrimitivesV2PersistedValidationData, PolkadotPrimitivesV2UpgradeRestriction, SpCoreEcdsaSignature, SpCoreEd25519Signature, SpCoreSr25519Signature, SpRuntimeArithmeticError, SpRuntimeDigest, SpRuntimeDigestDigestItem, SpRuntimeDispatchError, SpRuntimeModuleError, SpRuntimeMultiSignature, SpRuntimeTokenError, SpRuntimeTransactionalError, SpTrieStorageProof, SpVersionRuntimeVersion, UpDataStructsAccessMode, UpDataStructsCollection, UpDataStructsCollectionField, UpDataStructsCollectionLimits, UpDataStructsCollectionMode, UpDataStructsCollectionStats, UpDataStructsCreateCollectionData, UpDataStructsCreateFungibleData, UpDataStructsCreateItemData, UpDataStructsCreateItemExData, UpDataStructsCreateNftData, UpDataStructsCreateNftExData, UpDataStructsCreateReFungibleData, UpDataStructsCreateRefungibleExData, UpDataStructsNestingRule, UpDataStructsProperties, UpDataStructsPropertiesMapBoundedVec, UpDataStructsPropertiesMapPropertyPermission, UpDataStructsProperty, UpDataStructsPropertyKeyPermission, UpDataStructsPropertyPermission, UpDataStructsRmrkAccountIdOrCollectionNftTuple, UpDataStructsRmrkBaseInfo, UpDataStructsRmrkBasicResource, UpDataStructsRmrkCollectionInfo, UpDataStructsRmrkComposableResource, UpDataStructsRmrkEquippableList, UpDataStructsRmrkFixedPart, UpDataStructsRmrkNftChild, UpDataStructsRmrkNftInfo, UpDataStructsRmrkPartType, UpDataStructsRmrkPropertyInfo, UpDataStructsRmrkResourceInfo, UpDataStructsRmrkResourceTypes, UpDataStructsRmrkRoyaltyInfo, UpDataStructsRmrkSlotPart, UpDataStructsRmrkSlotResource, UpDataStructsRmrkTheme, UpDataStructsRmrkThemeProperty, UpDataStructsRpcCollection, UpDataStructsSchemaVersion, UpDataStructsSponsoringRateLimit, UpDataStructsSponsorshipState, UpDataStructsTokenData, XcmDoubleEncoded, XcmV0Junction, XcmV0JunctionBodyId, XcmV0JunctionBodyPart, XcmV0JunctionNetworkId, XcmV0MultiAsset, XcmV0MultiLocation, XcmV0Order, XcmV0OriginKind, XcmV0Response, XcmV0Xcm, XcmV1Junction, XcmV1MultiAsset, XcmV1MultiLocation, XcmV1MultiassetAssetId, XcmV1MultiassetAssetInstance, XcmV1MultiassetFungibility, XcmV1MultiassetMultiAssetFilter, XcmV1MultiassetMultiAssets, XcmV1MultiassetWildFungibility, XcmV1MultiassetWildMultiAsset, XcmV1MultilocationJunctions, XcmV1Order, XcmV1Response, XcmV1Xcm, XcmV2Instruction, XcmV2Response, XcmV2TraitsError, XcmV2TraitsOutcome, XcmV2WeightLimit, XcmV2Xcm, XcmVersionedMultiAssets, XcmVersionedMultiLocation, XcmVersionedXcm } from './unique'; import type { Data, StorageKey } from '@polkadot/types'; import type { BitVec, Bool, Bytes, I128, I16, I256, I32, I64, I8, Json, Null, Raw, Text, Type, U128, U16, U256, U32, U64, U8, USize, bool, i128, i16, i256, i32, i64, i8, u128, u16, u256, u32, u64, u8, usize } from '@polkadot/types-codec'; import type { AssetApproval, AssetApprovalKey, AssetBalance, AssetDestroyWitness, AssetDetails, AssetMetadata, TAssetBalance, TAssetDepositBalance } from '@polkadot/types/interfaces/assets'; @@ -291,27 +290,6 @@ CoreOccupied: CoreOccupied; CrateVersion: CrateVersion; CreatedBlock: CreatedBlock; - CumulusPalletDmpQueueCall: CumulusPalletDmpQueueCall; - CumulusPalletDmpQueueConfigData: CumulusPalletDmpQueueConfigData; - CumulusPalletDmpQueueError: CumulusPalletDmpQueueError; - CumulusPalletDmpQueueEvent: CumulusPalletDmpQueueEvent; - CumulusPalletDmpQueuePageIndexData: CumulusPalletDmpQueuePageIndexData; - CumulusPalletParachainSystemCall: CumulusPalletParachainSystemCall; - CumulusPalletParachainSystemError: CumulusPalletParachainSystemError; - CumulusPalletParachainSystemEvent: CumulusPalletParachainSystemEvent; - CumulusPalletParachainSystemRelayStateSnapshotMessagingStateSnapshot: CumulusPalletParachainSystemRelayStateSnapshotMessagingStateSnapshot; - CumulusPalletXcmCall: CumulusPalletXcmCall; - CumulusPalletXcmError: CumulusPalletXcmError; - CumulusPalletXcmEvent: CumulusPalletXcmEvent; - CumulusPalletXcmpQueueCall: CumulusPalletXcmpQueueCall; - CumulusPalletXcmpQueueError: CumulusPalletXcmpQueueError; - CumulusPalletXcmpQueueEvent: CumulusPalletXcmpQueueEvent; - CumulusPalletXcmpQueueInboundChannelDetails: CumulusPalletXcmpQueueInboundChannelDetails; - CumulusPalletXcmpQueueInboundState: CumulusPalletXcmpQueueInboundState; - CumulusPalletXcmpQueueOutboundChannelDetails: CumulusPalletXcmpQueueOutboundChannelDetails; - CumulusPalletXcmpQueueOutboundState: CumulusPalletXcmpQueueOutboundState; - CumulusPalletXcmpQueueQueueConfigData: CumulusPalletXcmpQueueQueueConfigData; - CumulusPrimitivesParachainInherentParachainInherentData: CumulusPrimitivesParachainInherentParachainInherentData; Data: Data; DeferredOffenceOf: DeferredOffenceOf; DefunctVoter: DefunctVoter; @@ -378,25 +356,11 @@ EthAddress: EthAddress; EthBlock: EthBlock; EthBloom: EthBloom; - EthbloomBloom: EthbloomBloom; EthCallRequest: EthCallRequest; EthereumAccountId: EthereumAccountId; EthereumAddress: EthereumAddress; - EthereumBlock: EthereumBlock; - EthereumHeader: EthereumHeader; - EthereumLog: EthereumLog; EthereumLookupSource: EthereumLookupSource; - EthereumReceiptEip658ReceiptData: EthereumReceiptEip658ReceiptData; - EthereumReceiptReceiptV3: EthereumReceiptReceiptV3; EthereumSignature: EthereumSignature; - EthereumTransactionAccessListItem: EthereumTransactionAccessListItem; - EthereumTransactionEip1559Transaction: EthereumTransactionEip1559Transaction; - EthereumTransactionEip2930Transaction: EthereumTransactionEip2930Transaction; - EthereumTransactionLegacyTransaction: EthereumTransactionLegacyTransaction; - EthereumTransactionTransactionAction: EthereumTransactionTransactionAction; - EthereumTransactionTransactionSignature: EthereumTransactionTransactionSignature; - EthereumTransactionTransactionV2: EthereumTransactionTransactionV2; - EthereumTypesHashH64: EthereumTypesHashH64; EthFilter: EthFilter; EthFilterAddress: EthFilterAddress; EthFilterChanges: EthFilterChanges; @@ -433,11 +397,6 @@ EventMetadataV9: EventMetadataV9; EventRecord: EventRecord; EvmAccount: EvmAccount; - EvmCoreErrorExitError: EvmCoreErrorExitError; - EvmCoreErrorExitFatal: EvmCoreErrorExitFatal; - EvmCoreErrorExitReason: EvmCoreErrorExitReason; - EvmCoreErrorExitRevert: EvmCoreErrorExitRevert; - EvmCoreErrorExitSucceed: EvmCoreErrorExitSucceed; EvmLog: EvmLog; EvmVicinity: EvmVicinity; ExecReturnValue: ExecReturnValue; @@ -476,31 +435,6 @@ Forcing: Forcing; ForkTreePendingChange: ForkTreePendingChange; ForkTreePendingChangeNode: ForkTreePendingChangeNode; - FpRpcTransactionStatus: FpRpcTransactionStatus; - FrameSupportPalletId: FrameSupportPalletId; - FrameSupportTokensMiscBalanceStatus: FrameSupportTokensMiscBalanceStatus; - FrameSupportWeightsDispatchClass: FrameSupportWeightsDispatchClass; - FrameSupportWeightsDispatchInfo: FrameSupportWeightsDispatchInfo; - FrameSupportWeightsPays: FrameSupportWeightsPays; - FrameSupportWeightsPerDispatchClassU32: FrameSupportWeightsPerDispatchClassU32; - FrameSupportWeightsPerDispatchClassU64: FrameSupportWeightsPerDispatchClassU64; - FrameSupportWeightsPerDispatchClassWeightsPerClass: FrameSupportWeightsPerDispatchClassWeightsPerClass; - FrameSupportWeightsRuntimeDbWeight: FrameSupportWeightsRuntimeDbWeight; - FrameSupportWeightsWeightToFeeCoefficient: FrameSupportWeightsWeightToFeeCoefficient; - FrameSystemAccountInfo: FrameSystemAccountInfo; - FrameSystemCall: FrameSystemCall; - FrameSystemError: FrameSystemError; - FrameSystemEvent: FrameSystemEvent; - FrameSystemEventRecord: FrameSystemEventRecord; - FrameSystemExtensionsCheckGenesis: FrameSystemExtensionsCheckGenesis; - FrameSystemExtensionsCheckNonce: FrameSystemExtensionsCheckNonce; - FrameSystemExtensionsCheckSpecVersion: FrameSystemExtensionsCheckSpecVersion; - FrameSystemExtensionsCheckWeight: FrameSystemExtensionsCheckWeight; - FrameSystemLastRuntimeUpgradeInfo: FrameSystemLastRuntimeUpgradeInfo; - FrameSystemLimitsBlockLength: FrameSystemLimitsBlockLength; - FrameSystemLimitsBlockWeights: FrameSystemLimitsBlockWeights; - FrameSystemLimitsWeightsPerClass: FrameSystemLimitsWeightsPerClass; - FrameSystemPhase: FrameSystemPhase; FullIdentification: FullIdentification; FunctionArgumentMetadataLatest: FunctionArgumentMetadataLatest; FunctionArgumentMetadataV10: FunctionArgumentMetadataV10; @@ -716,7 +650,6 @@ OffchainAccuracyCompact: OffchainAccuracyCompact; OffenceDetails: OffenceDetails; Offender: Offender; - OpalRuntimeRuntime: OpalRuntimeRuntime; OpaqueCall: OpaqueCall; OpaqueMultiaddr: OpaqueMultiaddr; OpaqueNetworkState: OpaqueNetworkState; @@ -732,10 +665,6 @@ OriginKindV0: OriginKindV0; OriginKindV1: OriginKindV1; OriginKindV2: OriginKindV2; - OrmlVestingModuleCall: OrmlVestingModuleCall; - OrmlVestingModuleError: OrmlVestingModuleError; - OrmlVestingModuleEvent: OrmlVestingModuleEvent; - OrmlVestingVestingSchedule: OrmlVestingVestingSchedule; OutboundHrmpMessage: OutboundHrmpMessage; OutboundLaneData: OutboundLaneData; OutboundMessageFee: OutboundMessageFee; @@ -746,76 +675,21 @@ Owner: Owner; PageCounter: PageCounter; PageIndexData: PageIndexData; - PalletBalancesAccountData: PalletBalancesAccountData; - PalletBalancesBalanceLock: PalletBalancesBalanceLock; - PalletBalancesCall: PalletBalancesCall; - PalletBalancesError: PalletBalancesError; - PalletBalancesEvent: PalletBalancesEvent; - PalletBalancesReasons: PalletBalancesReasons; - PalletBalancesReleases: PalletBalancesReleases; - PalletBalancesReserveData: PalletBalancesReserveData; PalletCallMetadataLatest: PalletCallMetadataLatest; PalletCallMetadataV14: PalletCallMetadataV14; - PalletCommonError: PalletCommonError; - PalletCommonEvent: PalletCommonEvent; PalletConstantMetadataLatest: PalletConstantMetadataLatest; PalletConstantMetadataV14: PalletConstantMetadataV14; PalletErrorMetadataLatest: PalletErrorMetadataLatest; PalletErrorMetadataV14: PalletErrorMetadataV14; - PalletEthereumCall: PalletEthereumCall; - PalletEthereumError: PalletEthereumError; - PalletEthereumEvent: PalletEthereumEvent; - PalletEthereumFakeTransactionFinalizer: PalletEthereumFakeTransactionFinalizer; PalletEventMetadataLatest: PalletEventMetadataLatest; PalletEventMetadataV14: PalletEventMetadataV14; - PalletEvmAccountBasicCrossAccountIdRepr: PalletEvmAccountBasicCrossAccountIdRepr; - PalletEvmCall: PalletEvmCall; - PalletEvmCoderSubstrateError: PalletEvmCoderSubstrateError; - PalletEvmContractHelpersError: PalletEvmContractHelpersError; - PalletEvmContractHelpersSponsoringModeT: PalletEvmContractHelpersSponsoringModeT; - PalletEvmError: PalletEvmError; - PalletEvmEvent: PalletEvmEvent; - PalletEvmMigrationCall: PalletEvmMigrationCall; - PalletEvmMigrationError: PalletEvmMigrationError; - PalletFungibleError: PalletFungibleError; PalletId: PalletId; - PalletInflationCall: PalletInflationCall; PalletMetadataLatest: PalletMetadataLatest; PalletMetadataV14: PalletMetadataV14; - PalletNonfungibleError: PalletNonfungibleError; - PalletNonfungibleItemData: PalletNonfungibleItemData; - PalletRefungibleError: PalletRefungibleError; - PalletRefungibleItemData: PalletRefungibleItemData; - PalletRmrkCoreCall: PalletRmrkCoreCall; - PalletRmrkCoreError: PalletRmrkCoreError; - PalletRmrkCoreEvent: PalletRmrkCoreEvent; - PalletRmrkEquipCall: PalletRmrkEquipCall; - PalletRmrkEquipError: PalletRmrkEquipError; - PalletRmrkEquipEvent: PalletRmrkEquipEvent; PalletsOrigin: PalletsOrigin; PalletStorageMetadataLatest: PalletStorageMetadataLatest; PalletStorageMetadataV14: PalletStorageMetadataV14; - PalletStructureCall: PalletStructureCall; - PalletStructureError: PalletStructureError; - PalletStructureEvent: PalletStructureEvent; - PalletSudoCall: PalletSudoCall; - PalletSudoError: PalletSudoError; - PalletSudoEvent: PalletSudoEvent; - PalletTemplateTransactionPaymentCall: PalletTemplateTransactionPaymentCall; - PalletTemplateTransactionPaymentChargeTransactionPayment: PalletTemplateTransactionPaymentChargeTransactionPayment; - PalletTimestampCall: PalletTimestampCall; - PalletTransactionPaymentReleases: PalletTransactionPaymentReleases; - PalletTreasuryCall: PalletTreasuryCall; - PalletTreasuryError: PalletTreasuryError; - PalletTreasuryEvent: PalletTreasuryEvent; - PalletTreasuryProposal: PalletTreasuryProposal; - PalletUniqueCall: PalletUniqueCall; - PalletUniqueError: PalletUniqueError; - PalletUniqueRawEvent: PalletUniqueRawEvent; PalletVersion: PalletVersion; - PalletXcmCall: PalletXcmCall; - PalletXcmError: PalletXcmError; - PalletXcmEvent: PalletXcmEvent; ParachainDispatchOrigin: ParachainDispatchOrigin; ParachainInherentData: ParachainInherentData; ParachainProposal: ParachainProposal; @@ -855,27 +729,9 @@ PerU16: PerU16; Phantom: Phantom; PhantomData: PhantomData; - PhantomTypeUpDataStructsBaseInfo: PhantomTypeUpDataStructsBaseInfo; - PhantomTypeUpDataStructsCollectionInfo: PhantomTypeUpDataStructsCollectionInfo; - PhantomTypeUpDataStructsNftChild: PhantomTypeUpDataStructsNftChild; - PhantomTypeUpDataStructsNftInfo: PhantomTypeUpDataStructsNftInfo; - PhantomTypeUpDataStructsPartType: PhantomTypeUpDataStructsPartType; - PhantomTypeUpDataStructsPropertyInfo: PhantomTypeUpDataStructsPropertyInfo; - PhantomTypeUpDataStructsResourceInfo: PhantomTypeUpDataStructsResourceInfo; - PhantomTypeUpDataStructsRpcCollection: PhantomTypeUpDataStructsRpcCollection; - PhantomTypeUpDataStructsTheme: PhantomTypeUpDataStructsTheme; - PhantomTypeUpDataStructsTokenData: PhantomTypeUpDataStructsTokenData; Phase: Phase; PhragmenScore: PhragmenScore; Points: Points; - PolkadotCorePrimitivesInboundDownwardMessage: PolkadotCorePrimitivesInboundDownwardMessage; - PolkadotCorePrimitivesInboundHrmpMessage: PolkadotCorePrimitivesInboundHrmpMessage; - PolkadotCorePrimitivesOutboundHrmpMessage: PolkadotCorePrimitivesOutboundHrmpMessage; - PolkadotParachainPrimitivesXcmpMessageFormat: PolkadotParachainPrimitivesXcmpMessageFormat; - PolkadotPrimitivesV2AbridgedHostConfiguration: PolkadotPrimitivesV2AbridgedHostConfiguration; - PolkadotPrimitivesV2AbridgedHrmpChannel: PolkadotPrimitivesV2AbridgedHrmpChannel; - PolkadotPrimitivesV2PersistedValidationData: PolkadotPrimitivesV2PersistedValidationData; - PolkadotPrimitivesV2UpgradeRestriction: PolkadotPrimitivesV2UpgradeRestriction; PortableType: PortableType; PortableTypeV14: PortableTypeV14; Precommits: Precommits; @@ -1071,20 +927,7 @@ SolutionSupports: SolutionSupports; SpanIndex: SpanIndex; SpanRecord: SpanRecord; - SpCoreEcdsaSignature: SpCoreEcdsaSignature; - SpCoreEd25519Signature: SpCoreEd25519Signature; - SpCoreSr25519Signature: SpCoreSr25519Signature; SpecVersion: SpecVersion; - SpRuntimeArithmeticError: SpRuntimeArithmeticError; - SpRuntimeDigest: SpRuntimeDigest; - SpRuntimeDigestDigestItem: SpRuntimeDigestDigestItem; - SpRuntimeDispatchError: SpRuntimeDispatchError; - SpRuntimeModuleError: SpRuntimeModuleError; - SpRuntimeMultiSignature: SpRuntimeMultiSignature; - SpRuntimeTokenError: SpRuntimeTokenError; - SpRuntimeTransactionalError: SpRuntimeTransactionalError; - SpTrieStorageProof: SpTrieStorageProof; - SpVersionRuntimeVersion: SpVersionRuntimeVersion; Sr25519Signature: Sr25519Signature; StakingLedger: StakingLedger; StakingLedgerTo223: StakingLedgerTo223; @@ -1181,50 +1024,6 @@ UnlockChunk: UnlockChunk; UnrewardedRelayer: UnrewardedRelayer; UnrewardedRelayersState: UnrewardedRelayersState; - UpDataStructsAccessMode: UpDataStructsAccessMode; - UpDataStructsCollection: UpDataStructsCollection; - UpDataStructsCollectionField: UpDataStructsCollectionField; - UpDataStructsCollectionLimits: UpDataStructsCollectionLimits; - UpDataStructsCollectionMode: UpDataStructsCollectionMode; - UpDataStructsCollectionStats: UpDataStructsCollectionStats; - UpDataStructsCreateCollectionData: UpDataStructsCreateCollectionData; - UpDataStructsCreateFungibleData: UpDataStructsCreateFungibleData; - UpDataStructsCreateItemData: UpDataStructsCreateItemData; - UpDataStructsCreateItemExData: UpDataStructsCreateItemExData; - UpDataStructsCreateNftData: UpDataStructsCreateNftData; - UpDataStructsCreateNftExData: UpDataStructsCreateNftExData; - UpDataStructsCreateReFungibleData: UpDataStructsCreateReFungibleData; - UpDataStructsCreateRefungibleExData: UpDataStructsCreateRefungibleExData; - UpDataStructsNestingRule: UpDataStructsNestingRule; - UpDataStructsProperties: UpDataStructsProperties; - UpDataStructsPropertiesMapBoundedVec: UpDataStructsPropertiesMapBoundedVec; - UpDataStructsPropertiesMapPropertyPermission: UpDataStructsPropertiesMapPropertyPermission; - UpDataStructsProperty: UpDataStructsProperty; - UpDataStructsPropertyKeyPermission: UpDataStructsPropertyKeyPermission; - UpDataStructsPropertyPermission: UpDataStructsPropertyPermission; - UpDataStructsRmrkAccountIdOrCollectionNftTuple: UpDataStructsRmrkAccountIdOrCollectionNftTuple; - UpDataStructsRmrkBaseInfo: UpDataStructsRmrkBaseInfo; - UpDataStructsRmrkBasicResource: UpDataStructsRmrkBasicResource; - UpDataStructsRmrkCollectionInfo: UpDataStructsRmrkCollectionInfo; - UpDataStructsRmrkComposableResource: UpDataStructsRmrkComposableResource; - UpDataStructsRmrkEquippableList: UpDataStructsRmrkEquippableList; - UpDataStructsRmrkFixedPart: UpDataStructsRmrkFixedPart; - UpDataStructsRmrkNftChild: UpDataStructsRmrkNftChild; - UpDataStructsRmrkNftInfo: UpDataStructsRmrkNftInfo; - UpDataStructsRmrkPartType: UpDataStructsRmrkPartType; - UpDataStructsRmrkPropertyInfo: UpDataStructsRmrkPropertyInfo; - UpDataStructsRmrkResourceInfo: UpDataStructsRmrkResourceInfo; - UpDataStructsRmrkResourceTypes: UpDataStructsRmrkResourceTypes; - UpDataStructsRmrkRoyaltyInfo: UpDataStructsRmrkRoyaltyInfo; - UpDataStructsRmrkSlotPart: UpDataStructsRmrkSlotPart; - UpDataStructsRmrkSlotResource: UpDataStructsRmrkSlotResource; - UpDataStructsRmrkTheme: UpDataStructsRmrkTheme; - UpDataStructsRmrkThemeProperty: UpDataStructsRmrkThemeProperty; - UpDataStructsRpcCollection: UpDataStructsRpcCollection; - UpDataStructsSchemaVersion: UpDataStructsSchemaVersion; - UpDataStructsSponsoringRateLimit: UpDataStructsSponsoringRateLimit; - UpDataStructsSponsorshipState: UpDataStructsSponsorshipState; - UpDataStructsTokenData: UpDataStructsTokenData; UpgradeGoAhead: UpgradeGoAhead; UpgradeRestriction: UpgradeRestriction; UpwardMessage: UpwardMessage; @@ -1296,7 +1095,6 @@ WithdrawReasons: WithdrawReasons; Xcm: Xcm; XcmAssetId: XcmAssetId; - XcmDoubleEncoded: XcmDoubleEncoded; XcmError: XcmError; XcmErrorV0: XcmErrorV0; XcmErrorV1: XcmErrorV1; @@ -1309,41 +1107,8 @@ XcmOriginKind: XcmOriginKind; XcmpMessageFormat: XcmpMessageFormat; XcmV0: XcmV0; - XcmV0Junction: XcmV0Junction; - XcmV0JunctionBodyId: XcmV0JunctionBodyId; - XcmV0JunctionBodyPart: XcmV0JunctionBodyPart; - XcmV0JunctionNetworkId: XcmV0JunctionNetworkId; - XcmV0MultiAsset: XcmV0MultiAsset; - XcmV0MultiLocation: XcmV0MultiLocation; - XcmV0Order: XcmV0Order; - XcmV0OriginKind: XcmV0OriginKind; - XcmV0Response: XcmV0Response; - XcmV0Xcm: XcmV0Xcm; XcmV1: XcmV1; - XcmV1Junction: XcmV1Junction; - XcmV1MultiAsset: XcmV1MultiAsset; - XcmV1MultiassetAssetId: XcmV1MultiassetAssetId; - XcmV1MultiassetAssetInstance: XcmV1MultiassetAssetInstance; - XcmV1MultiassetFungibility: XcmV1MultiassetFungibility; - XcmV1MultiassetMultiAssetFilter: XcmV1MultiassetMultiAssetFilter; - XcmV1MultiassetMultiAssets: XcmV1MultiassetMultiAssets; - XcmV1MultiassetWildFungibility: XcmV1MultiassetWildFungibility; - XcmV1MultiassetWildMultiAsset: XcmV1MultiassetWildMultiAsset; - XcmV1MultiLocation: XcmV1MultiLocation; - XcmV1MultilocationJunctions: XcmV1MultilocationJunctions; - XcmV1Order: XcmV1Order; - XcmV1Response: XcmV1Response; - XcmV1Xcm: XcmV1Xcm; XcmV2: XcmV2; - XcmV2Instruction: XcmV2Instruction; - XcmV2Response: XcmV2Response; - XcmV2TraitsError: XcmV2TraitsError; - XcmV2TraitsOutcome: XcmV2TraitsOutcome; - XcmV2WeightLimit: XcmV2WeightLimit; - XcmV2Xcm: XcmV2Xcm; XcmVersion: XcmVersion; - XcmVersionedMultiAssets: XcmVersionedMultiAssets; - XcmVersionedMultiLocation: XcmVersionedMultiLocation; - XcmVersionedXcm: XcmVersionedXcm; } // InterfaceTypes } // declare module --- a/tests/src/interfaces/types.ts +++ b/tests/src/interfaces/types.ts @@ -1,5 +1,3 @@ // Auto-generated via `yarn polkadot-types-from-defs`, do not edit /* eslint-disable */ -export * from './unique/types'; -export * from './rmrk/types'; --- a/tests/yarn.lock +++ b/tests/yarn.lock @@ -8615,7 +8615,7 @@ resolved "https://registry.yarnpkg.com/slash/-/slash-3.0.0.tgz#6539be870c165adbd5240220dbe361f1bc4d4634" integrity sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q== -solc@^0.8.13: +solc@0.8.13: version "0.8.13" resolved "https://registry.yarnpkg.com/solc/-/solc-0.8.13.tgz#bafc7fcc11a627e2281e489076b80497123bb704" integrity sha512-C0yTN+rjEOGO6uVOXI8+EKa75SFMuZpQ2tryex4QxWIg0HRWZvCHKfVPuLZ5wx06Sb6GBp6uQA5yqQyXZnXOJw== -- gitstuff