--- a/Cargo.lock +++ b/Cargo.lock @@ -5543,8 +5543,6 @@ "pallet-nonfungible", "pallet-randomness-collective-flip", "pallet-refungible", - "pallet-rmrk-core", - "pallet-rmrk-equip", "pallet-session", "pallet-structure", "pallet-sudo", @@ -5561,7 +5559,6 @@ "parity-scale-codec", "polkadot-parachain", "precompile-utils-macro", - "rmrk-rpc", "scale-info", "serde", "smallvec", @@ -6772,43 +6769,6 @@ "parity-scale-codec", "scale-info", "sp-core", - "sp-runtime", - "sp-std", - "up-data-structs", -] - -[[package]] -name = "pallet-rmrk-core" -version = "0.1.2" -dependencies = [ - "frame-benchmarking", - "frame-support", - "frame-system", - "pallet-common", - "pallet-evm", - "pallet-nonfungible", - "pallet-structure", - "parity-scale-codec", - "rmrk-traits", - "scale-info", - "sp-runtime", - "sp-std", - "up-data-structs", -] - -[[package]] -name = "pallet-rmrk-equip" -version = "0.1.2" -dependencies = [ - "frame-benchmarking", - "frame-support", - "frame-system", - "pallet-common", - "pallet-evm", - "pallet-nonfungible", - "pallet-rmrk-core", - "parity-scale-codec", - "scale-info", "sp-runtime", "sp-std", "up-data-structs", @@ -9009,8 +8969,6 @@ "pallet-nonfungible", "pallet-randomness-collective-flip", "pallet-refungible", - "pallet-rmrk-core", - "pallet-rmrk-equip", "pallet-session", "pallet-structure", "pallet-sudo", @@ -9026,7 +8984,6 @@ "parity-scale-codec", "polkadot-parachain", "precompile-utils-macro", - "rmrk-rpc", "scale-info", "serde", "smallvec", @@ -9415,26 +9372,6 @@ ] [[package]] -name = "rmrk-rpc" -version = "0.0.2" -dependencies = [ - "parity-scale-codec", - "rmrk-traits", - "sp-api", - "sp-runtime", - "sp-std", -] - -[[package]] -name = "rmrk-traits" -version = "0.1.0" -dependencies = [ - "parity-scale-codec", - "scale-info", - "serde", -] - -[[package]] name = "rocksdb" version = "0.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -13026,7 +12963,6 @@ "pallet-evm", "parity-scale-codec", "quartz-runtime", - "rmrk-rpc", "sc-client-api", "sc-executor", "sc-rpc-api", @@ -13132,7 +13068,6 @@ "polkadot-primitives", "polkadot-service", "quartz-runtime", - "rmrk-rpc", "sc-basic-authorship", "sc-chain-spec", "sc-cli", @@ -13186,7 +13121,6 @@ "fp-storage", "jsonrpsee", "pallet-transaction-payment-rpc", - "rmrk-rpc", "sc-client-api", "sc-finality-grandpa", "sc-network", @@ -13265,8 +13199,6 @@ "pallet-nonfungible", "pallet-randomness-collective-flip", "pallet-refungible", - "pallet-rmrk-core", - "pallet-rmrk-equip", "pallet-session", "pallet-structure", "pallet-sudo", @@ -13282,7 +13214,6 @@ "parity-scale-codec", "polkadot-parachain", "precompile-utils-macro", - "rmrk-rpc", "scale-info", "serde", "smallvec", @@ -13361,7 +13292,6 @@ "frame-support", "pallet-evm", "parity-scale-codec", - "rmrk-traits", "scale-info", "serde", "sp-core", --- a/Cargo.toml +++ b/Cargo.toml @@ -43,9 +43,6 @@ pallet-inflation = { path = "pallets/inflation", default-features = false } pallet-maintenance = { default-features = false, path = "pallets/maintenance" } pallet-nonfungible = { default-features = false, path = "pallets/nonfungible" } -pallet-proxy-rmrk-core = { default-features = false, path = "pallets/proxy-rmrk-core", package = "pallet-rmrk-core" } -pallet-proxy-rmrk-equip = { default-features = false, path = "pallets/proxy-rmrk-equip", package = "pallet-rmrk-equip" } -rmrk-traits = { default-features = false, path = "primitives/rmrk-traits" } pallet-refungible = { default-features = false, path = "pallets/refungible" } pallet-structure = { default-features = false, path = "pallets/structure" } pallet-unique = { path = "pallets/unique", default-features = false } @@ -53,7 +50,6 @@ pallet-test-utils = { default-features = false, path = "test-pallets/utils" } pallet-app-promotion = { path = "pallets/app-promotion", default-features = false } app-promotion-rpc = { path = "primitives/app_promotion_rpc", default-features = false } -rmrk-rpc = { path = "primitives/rmrk-rpc", default-features = false } # Unique: Runtimes unique-runtime = { path = "runtime/unique" } --- a/Makefile +++ b/Makefile @@ -121,14 +121,6 @@ bench-scheduler: make _bench PALLET=unique-scheduler-v2 PALLET_DIR=scheduler-v2 -.PHONY: bench-rmrk-core -bench-rmrk-core: - make _bench PALLET=proxy-rmrk-core - -.PHONY: bench-rmrk-equip -bench-rmrk-equip: - make _bench PALLET=proxy-rmrk-equip - .PHONY: bench-foreign-assets bench-foreign-assets: make _bench PALLET=foreign-assets @@ -146,7 +138,7 @@ make _bench PALLET=app-promotion PALLET_DIR=app-promotion .PHONY: bench -# Disabled: bench-scheduler, bench-collator-selection, bench-identity, bench-rmrk-core, bench-rmrk-equip +# Disabled: bench-scheduler, bench-collator-selection, bench-identity bench: bench-common bench-evm-migration bench-unique bench-structure bench-fungible bench-refungible bench-nonfungible bench-configuration bench-foreign-assets .PHONY: check --- a/client/rpc/Cargo.toml +++ b/client/rpc/Cargo.toml @@ -14,7 +14,6 @@ codec = { workspace = true, package = "parity-scale-codec" } app-promotion-rpc = { workspace = true } -rmrk-rpc = { workspace = true } up-common = { workspace = true } up-data-structs = { workspace = true } up-pov-estimate-rpc = { workspace = true, optional = true } --- a/client/rpc/src/lib.rs +++ b/client/rpc/src/lib.rs @@ -17,7 +17,7 @@ // Original License use std::sync::Arc; -use codec::{Decode, Encode}; +use codec::Decode; use jsonrpsee::{ core::{RpcResult as Result}, proc_macros::rpc, @@ -32,15 +32,8 @@ use sp_blockchain::HeaderBackend; use up_rpc::UniqueApi as UniqueRuntimeApi; use app_promotion_rpc::AppPromotionApi as AppPromotionRuntimeApi; - -// RMRK -use rmrk_rpc::RmrkApi as RmrkRuntimeApi; -use up_data_structs::{ - RmrkCollectionId, RmrkNftId, RmrkBaseId, RmrkNftChild, RmrkThemeName, RmrkResourceId, -}; pub use app_promotion_unique_rpc::AppPromotionApiServer; -pub use rmrk_unique_rpc::RmrkApiServer; #[cfg(feature = "pov-estimate")] pub mod pov_estimate; @@ -300,129 +293,7 @@ ) -> Result>; } } - -mod rmrk_unique_rpc { - use super::*; - - #[rpc(server)] - #[async_trait] - pub trait RmrkApi< - BlockHash, - AccountId, - CollectionInfo, - NftInfo, - ResourceInfo, - PropertyInfo, - BaseInfo, - PartType, - Theme, - > - { - /// Get the latest created collection ID. - #[method(name = "rmrk_lastCollectionIdx")] - fn last_collection_idx(&self, at: Option) -> Result; - - /// Get collection info by ID. - #[method(name = "rmrk_collectionById")] - fn collection_by_id( - &self, - id: RmrkCollectionId, - at: Option, - ) -> Result>; - - /// Get NFT info by collection and NFT IDs. - #[method(name = "rmrk_nftById")] - fn nft_by_id( - &self, - collection_id: RmrkCollectionId, - nft_id: RmrkNftId, - at: Option, - ) -> Result>; - - /// Get tokens owned by an account in a collection. - #[method(name = "rmrk_accountTokens")] - fn account_tokens( - &self, - account_id: AccountId, - collection_id: RmrkCollectionId, - at: Option, - ) -> Result>; - - /// Get tokens nested in an NFT - its direct children (not the children's children). - #[method(name = "rmrk_nftChildren")] - fn nft_children( - &self, - collection_id: RmrkCollectionId, - nft_id: RmrkNftId, - at: Option, - ) -> Result>; - - /// Get collection properties, created by the user - not the proxy-specific properties. - #[method(name = "rmrk_collectionProperties")] - fn collection_properties( - &self, - collection_id: RmrkCollectionId, - filter_keys: Option>, - at: Option, - ) -> Result>; - - /// Get NFT properties, created by the user - not the proxy-specific properties. - #[method(name = "rmrk_nftProperties")] - fn nft_properties( - &self, - collection_id: RmrkCollectionId, - nft_id: RmrkNftId, - filter_keys: Option>, - at: Option, - ) -> Result>; - - /// Get data of resources of an NFT. - #[method(name = "rmrk_nftResources")] - fn nft_resources( - &self, - collection_id: RmrkCollectionId, - nft_id: RmrkNftId, - at: Option, - ) -> Result>; - /// Get the priority of a resource in an NFT. - #[method(name = "rmrk_nftResourcePriority")] - fn nft_resource_priority( - &self, - collection_id: RmrkCollectionId, - nft_id: RmrkNftId, - resource_id: RmrkResourceId, - at: Option, - ) -> Result>; - - /// Get base info by its ID. - #[method(name = "rmrk_base")] - fn base(&self, base_id: RmrkBaseId, at: Option) -> Result>; - - /// Get all parts of a base. - #[method(name = "rmrk_baseParts")] - fn base_parts(&self, base_id: RmrkBaseId, at: Option) -> Result>; - - /// Get the theme names belonging to a base. - #[method(name = "rmrk_themeNames")] - fn theme_names( - &self, - base_id: RmrkBaseId, - at: Option, - ) -> Result>; - - /// Get theme info, including properties, optionally limited to the provided keys. - #[method(name = "rmrk_themes")] - fn theme( - &self, - base_id: RmrkBaseId, - theme_name: String, - filter_keys: Option>, - at: Option, - ) -> Result>; - } -} - #[macro_export] macro_rules! define_struct_for_server_api { ($name:ident { $($arg:ident: $arg_ty:ty),+ $(,)? }) => { @@ -454,12 +325,6 @@ } } -define_struct_for_server_api! { - Rmrk { - client: Arc - } -} - macro_rules! pass_method { ( $method_name:ident( @@ -508,12 +373,6 @@ macro_rules! app_promotion_api { () => { dyn AppPromotionRuntimeApi - }; -} - -macro_rules! rmrk_api { - () => { - dyn RmrkRuntimeApi }; } @@ -627,94 +486,6 @@ .into_iter() .map(|(b, a)| (b, a.to_string())) .collect::>(), app_promotion_api); -} - -#[allow(deprecated)] -impl< - C, - Block, - AccountId, - CollectionInfo, - NftInfo, - ResourceInfo, - PropertyInfo, - BaseInfo, - PartType, - Theme, - > - rmrk_unique_rpc::RmrkApiServer< - ::Hash, - AccountId, - CollectionInfo, - NftInfo, - ResourceInfo, - PropertyInfo, - BaseInfo, - PartType, - Theme, - > for Rmrk -where - C: Send + Sync + 'static + ProvideRuntimeApi + HeaderBackend, - C::Api: RmrkRuntimeApi< - Block, - AccountId, - CollectionInfo, - NftInfo, - ResourceInfo, - PropertyInfo, - BaseInfo, - PartType, - Theme, - >, - AccountId: Decode + Encode, - CollectionInfo: Decode, - NftInfo: Decode, - ResourceInfo: Decode, - PropertyInfo: Decode, - BaseInfo: Decode, - PartType: Decode, - Theme: Decode, - Block: BlockT, -{ - pass_method!(last_collection_idx() -> RmrkCollectionId, rmrk_api); - pass_method!(collection_by_id(id: RmrkCollectionId) -> Option, rmrk_api); - pass_method!(nft_by_id(collection_id: RmrkCollectionId, nft_id: RmrkNftId) -> Option, rmrk_api); - pass_method!(account_tokens(account_id: AccountId, collection_id: RmrkCollectionId) -> Vec, rmrk_api); - pass_method!(nft_children(collection_id: RmrkCollectionId, nft_id: RmrkNftId) -> Vec, rmrk_api); - pass_method!( - collection_properties( - collection_id: RmrkCollectionId, - - #[map(|keys| string_keys_to_bytes_keys(keys))] - filter_keys: Option> - ) -> Vec, - rmrk_api - ); - pass_method!( - nft_properties( - collection_id: RmrkCollectionId, - nft_id: RmrkNftId, - - #[map(|keys| string_keys_to_bytes_keys(keys))] - filter_keys: Option> - ) -> Vec, - rmrk_api - ); - pass_method!(nft_resources(collection_id: RmrkCollectionId, nft_id: RmrkNftId) -> Vec, rmrk_api); - pass_method!(nft_resource_priority(collection_id: RmrkCollectionId, nft_id: RmrkNftId, resource_id: RmrkResourceId) -> Option, rmrk_api); - pass_method!(base(base_id: RmrkBaseId) -> Option, rmrk_api); - pass_method!(base_parts(base_id: RmrkBaseId) -> Vec, rmrk_api); - pass_method!(theme_names(base_id: RmrkBaseId) -> Vec, rmrk_api); - pass_method!( - theme( - base_id: RmrkBaseId, - - #[map(|n| n.into_bytes())] - theme_name: String, - - #[map(|keys| string_keys_to_bytes_keys(keys))] - filter_keys: Option> - ) -> Option, rmrk_api); } fn string_keys_to_bytes_keys(keys: Option>) -> Option>> { --- a/node/cli/Cargo.toml +++ b/node/cli/Cargo.toml @@ -89,7 +89,6 @@ fp-rpc = { workspace = true } app-promotion-rpc = { workspace = true } -rmrk-rpc = { workspace = true } uc-rpc = { workspace = true } unique-rpc = { workspace = true } up-pov-estimate-rpc = { workspace = true } --- a/node/cli/src/service.rs +++ b/node/cli/src/service.rs @@ -71,12 +71,6 @@ #[cfg(feature = "pov-estimate")] use crate::chain_spec::RuntimeIdentification; -// RMRK -use up_data_structs::{ - RmrkCollectionInfo, RmrkInstanceInfo, RmrkResourceInfo, RmrkPropertyInfo, RmrkBaseInfo, - RmrkPartType, RmrkTheme, -}; - /// Unique native executor instance. #[cfg(feature = "unique-runtime")] pub struct UniqueRuntimeExecutor; @@ -403,17 +397,7 @@ + sp_api::ApiExt> + up_rpc::UniqueApi + app_promotion_rpc::AppPromotionApi - + rmrk_rpc::RmrkApi< - Block, - AccountId, - RmrkCollectionInfo, - RmrkInstanceInfo, - RmrkResourceInfo, - RmrkPropertyInfo, - RmrkBaseInfo, - RmrkPartType, - RmrkTheme, - > + up_pov_estimate_rpc::PovEstimateApi + + up_pov_estimate_rpc::PovEstimateApi + substrate_frame_rpc_system::AccountNonceApi + sp_api::Metadata + sp_offchain::OffchainWorkerApi @@ -732,17 +716,7 @@ + sp_api::ApiExt> + up_rpc::UniqueApi + app_promotion_rpc::AppPromotionApi - + rmrk_rpc::RmrkApi< - Block, - AccountId, - RmrkCollectionInfo, - RmrkInstanceInfo, - RmrkResourceInfo, - RmrkPropertyInfo, - RmrkBaseInfo, - RmrkPartType, - RmrkTheme, - > + up_pov_estimate_rpc::PovEstimateApi + + up_pov_estimate_rpc::PovEstimateApi + substrate_frame_rpc_system::AccountNonceApi + sp_api::Metadata + sp_offchain::OffchainWorkerApi @@ -882,17 +856,7 @@ + sp_api::ApiExt> + up_rpc::UniqueApi + app_promotion_rpc::AppPromotionApi - + rmrk_rpc::RmrkApi< - Block, - AccountId, - RmrkCollectionInfo, - RmrkInstanceInfo, - RmrkResourceInfo, - RmrkPropertyInfo, - RmrkBaseInfo, - RmrkPartType, - RmrkTheme, - > + up_pov_estimate_rpc::PovEstimateApi + + up_pov_estimate_rpc::PovEstimateApi + substrate_frame_rpc_system::AccountNonceApi + sp_api::Metadata + sp_offchain::OffchainWorkerApi --- a/node/rpc/Cargo.toml +++ b/node/rpc/Cargo.toml @@ -33,7 +33,6 @@ fp-storage = { workspace = true } app-promotion-rpc = { workspace = true } -rmrk-rpc = { workspace = true } serde = { workspace = true } uc-rpc = { workspace = true } up-common = { workspace = true } --- a/node/rpc/src/lib.rs +++ b/node/rpc/src/lib.rs @@ -42,12 +42,6 @@ use up_common::types::opaque::*; -// RMRK -use up_data_structs::{ - RmrkCollectionInfo, RmrkInstanceInfo, RmrkResourceInfo, RmrkPropertyInfo, RmrkBaseInfo, - RmrkPartType, RmrkTheme, -}; - #[cfg(feature = "pov-estimate")] type FullBackend = sc_service::TFullBackend; @@ -164,17 +158,6 @@ ::CrossAccountId, AccountId, >, - C::Api: rmrk_rpc::RmrkApi< - Block, - AccountId, - RmrkCollectionInfo, - RmrkInstanceInfo, - RmrkResourceInfo, - RmrkPropertyInfo, - RmrkBaseInfo, - RmrkPartType, - RmrkTheme, - >, C::Api: up_pov_estimate_rpc::PovEstimateApi, B: sc_client_api::Backend + Send + Sync + 'static, B::State: sc_client_api::backend::StateBackend>, @@ -193,9 +176,6 @@ #[cfg(not(feature = "unique-runtime"))] use uc_rpc::{AppPromotionApiServer, AppPromotion}; - #[cfg(not(feature = "unique-runtime"))] - use uc_rpc::{RmrkApiServer, Rmrk}; - #[cfg(feature = "pov-estimate")] use uc_rpc::pov_estimate::{PovEstimateApiServer, PovEstimate}; @@ -267,9 +247,6 @@ #[cfg(not(feature = "unique-runtime"))] io.merge(AppPromotion::new(client.clone()).into_rpc())?; - - #[cfg(not(feature = "unique-runtime"))] - io.merge(Rmrk::new(client.clone()).into_rpc())?; #[cfg(feature = "pov-estimate")] io.merge( --- a/pallets/common/src/erc.rs +++ b/pallets/common/src/erc.rs @@ -33,7 +33,7 @@ }; use crate::{ - Pallet, CollectionHandle, Config, CollectionProperties, SelfWeightOf, eth, weights::WeightInfo, + Pallet, CollectionHandle, Config, CollectionProperties, eth, SelfWeightOf, weights::WeightInfo, }; frontier_contract! { --- a/pallets/common/src/lib.rs +++ b/pallets/common/src/lib.rs @@ -109,15 +109,6 @@ TokenData, TrySetProperty, PropertyScope, - // RMRK - RmrkCollectionInfo, - RmrkInstanceInfo, - RmrkResourceInfo, - RmrkPropertyInfo, - RmrkBaseInfo, - RmrkPartType, - RmrkBoundedTheme, - RmrkNftChild, CollectionPermissions, }; use up_pov_estimate_rpc::PovInfo; @@ -898,15 +889,6 @@ PhantomType<( TokenData, RpcCollection, - // RMRK - RmrkCollectionInfo, - RmrkInstanceInfo, - RmrkResourceInfo, - RmrkPropertyInfo, - RmrkBaseInfo, - RmrkPartType, - RmrkBoundedTheme, - RmrkNftChild, // PoV Estimate Info PovInfo, )>, --- a/pallets/fungible/src/erc.rs +++ b/pallets/fungible/src/erc.rs @@ -38,8 +38,8 @@ use sp_core::{U256, Get}; use crate::{ - Allowance, Balance, Config, FungibleHandle, Pallet, SelfWeightOf, TotalSupply, - weights::WeightInfo, + Allowance, Balance, Config, FungibleHandle, Pallet, TotalSupply, + SelfWeightOf, weights::WeightInfo, }; frontier_contract! { --- a/pallets/nonfungible/src/erc.rs +++ b/pallets/nonfungible/src/erc.rs @@ -47,7 +47,7 @@ use crate::{ AccountBalance, Config, CreateItemData, NonfungibleHandle, Pallet, TokenData, TokensMinted, - SelfWeightOf, weights::WeightInfo, TokenProperties, + TokenProperties, SelfWeightOf, weights::WeightInfo, }; frontier_contract! { --- a/pallets/nonfungible/src/lib.rs +++ b/pallets/nonfungible/src/lib.rs @@ -214,7 +214,7 @@ /// usual [`TokenProperties`] due to an unlimited number /// and separately stored and written-to key-value pairs. /// - /// Currently used to store RMRK data. + /// Currently unused. #[pallet::storage] #[pallet::getter(fn token_aux_property)] pub type TokenAuxProperties = StorageNMap< --- a/pallets/proxy-rmrk-core/CHANGELOG.md +++ /dev/null @@ -1,17 +0,0 @@ - -## [v0.1.2] 2022-08-16 - -### Other changes - -- build: Upgrade polkadot to v0.9.27 2c498572636f2b34d53b1c51b7283a761a7dc90a - -- build: Upgrade polkadot to v0.9.26 85515e54c4ca1b82a2630034e55dcc804c643bf8 - -- refactor: Remove `#[transactional]` from extrinsics 7fd36cea2f6e00c02c67ccc1de9649ae404efd31 - -Every extrinsic now runs in transaction implicitly, and -`#[transactional]` on pallet dispatchable is now meaningless - -Upstream-Change: https://github.com/paritytech/substrate/issues/10806 - -- build: Upgrade polkadot to v0.9.25 cdfb9bdc7b205ff1b5134f034ef9973d769e5e6b \ No newline at end of file --- a/pallets/proxy-rmrk-core/Cargo.toml +++ /dev/null @@ -1,41 +0,0 @@ -[package] -edition = "2021" -license = "GPLv3" -name = "pallet-rmrk-core" -version = "0.1.2" - -[dependencies] -# Note: `package = "parity-scale-codec"` must be supplied since the `Encode` macro searches for it. -codec = { workspace = true, package = "parity-scale-codec" } - -scale-info = { workspace = true } - -frame-benchmarking = { workspace = true, optional = true } -frame-support = { workspace = true } -frame-system = { workspace = true } -pallet-common = { workspace = true } -pallet-evm = { workspace = true } -pallet-nonfungible = { workspace = true } -pallet-structure = { workspace = true } -rmrk-traits = { workspace = true } -sp-runtime = { workspace = true } -sp-std = { workspace = true } -up-data-structs = { workspace = true } - -[features] -default = ["std"] -runtime-benchmarks = ['frame-benchmarking', 'frame-support/runtime-benchmarks', 'frame-system/runtime-benchmarks'] -std = [ - "frame-support/std", - "frame-system/std", - "pallet-common/std", - "pallet-evm/std", - "pallet-nonfungible/std", - "pallet-structure/std", - "rmrk-traits/std", - "sp-runtime/std", - "sp-std/std", - "up-data-structs/std", - 'frame-benchmarking/std', -] -try-runtime = ["frame-support/try-runtime"] --- a/pallets/proxy-rmrk-core/src/benchmarking.rs +++ /dev/null @@ -1,544 +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 . - -use sp_std::vec; - -use frame_benchmarking::{benchmarks, account}; -use frame_system::RawOrigin; -use frame_support::{ - traits::{Currency, Get}, - BoundedVec, -}; -use sp_runtime::Permill; - -use up_data_structs::*; - -use super::*; - -const SEED: u32 = 1; - -fn create_data>() -> BoundedVec { - vec![b'A'; S::get() as usize].try_into().expect("size == S") -} - -fn create_u32_array>() -> BoundedVec { - vec![0; S::get() as usize].try_into().expect("size == S") -} - -fn create_basic_resource() -> RmrkBasicResource { - RmrkBasicResource { - src: Some(create_data()), - metadata: Some(create_data()), - license: Some(create_data()), - thumb: Some(create_data()), - } -} - -fn create_composable_resource() -> RmrkComposableResource { - RmrkComposableResource { - parts: create_u32_array(), - base: 100, - src: Some(create_data()), - metadata: Some(create_data()), - license: Some(create_data()), - thumb: Some(create_data()), - } -} - -fn create_slot_resource() -> RmrkSlotResource { - RmrkSlotResource { - base: 100, - slot: 200, - src: Some(create_data()), - metadata: Some(create_data()), - license: Some(create_data()), - thumb: Some(create_data()), - } -} - -fn create_max_resource_types_array>(num: usize) -> BoundedVec { - vec![RmrkResourceTypes::Composable(create_composable_resource()); num] - .try_into() - .expect("num <= S") -} - -fn create_max_collection(owner: &T::AccountId) -> DispatchResult { - ::Currency::deposit_creating( - owner, - T::CollectionCreationPrice::get(), - ); - - let metadata = create_data(); - let max = None; - let symbol = create_data(); - - >::create_collection( - RawOrigin::Signed(owner.clone()).into(), - metadata, - max, - symbol, - ) -} - -fn create_nft(owner: &T::AccountId, collection_id: RmrkCollectionId) -> DispatchResult { - let royalty_recipient = Some(owner.clone()); - let royalty_amount = Some(Permill::from_percent(25)); - let metadata = create_data(); - let transferable = true; - - >::mint_nft( - RawOrigin::Signed(owner.clone()).into(), - None, - collection_id, - royalty_recipient, - royalty_amount, - metadata, - transferable, - None, - ) -} - -struct NftBuilder { - collection_id: RmrkCollectionId, - current_nft_id: RmrkNftId, -} - -impl NftBuilder { - fn new(collection_id: RmrkCollectionId) -> Self { - Self { - collection_id, - current_nft_id: 0, - } - } - - fn build(&mut self, owner: &T::AccountId) -> Result { - create_nft::(owner, self.collection_id)?; - self.current_nft_id += 1; - - Ok(self.current_nft_id) - } - - fn build_tower( - &mut self, - owner: &T::AccountId, - height: u32, - ) -> Result<(RmrkNftId, RmrkNftId), DispatchError> { - self.build::(owner)?; - - let root_nft_id = self.current_nft_id; - let mut prev_nft_id = root_nft_id; - - for _ in 0..height { - self.build::(owner)?; - - let new_owner = - >::CollectionAndNftTuple( - self.collection_id, - prev_nft_id, - ); - - >::send( - RawOrigin::Signed(owner.clone()).into(), - self.collection_id, - self.current_nft_id, - new_owner, - )?; - - prev_nft_id = self.current_nft_id; - } - - let deepest_nft_id = self.current_nft_id; - - Ok((root_nft_id, deepest_nft_id)) - } - - fn build_wide_tree( - &mut self, - owner: &T::AccountId, - width: u32, - ) -> Result { - self.build::(owner)?; - - let root_nft_id = self.current_nft_id; - - let root_owner = >::CollectionAndNftTuple( - self.collection_id, - root_nft_id, - ); - - for _ in 0..width { - self.build::(owner)?; - - >::send( - RawOrigin::Signed(owner.clone()).into(), - self.collection_id, - self.current_nft_id, - root_owner.clone(), - )?; - } - - Ok(root_nft_id) - } -} - -benchmarks! { - create_collection { - let caller = account("caller", 0, SEED); - ::Currency::deposit_creating(&caller, T::CollectionCreationPrice::get()); - let metadata = create_data(); - let max = None; - let symbol = create_data(); - }: _(RawOrigin::Signed(caller), metadata, max, symbol) - - destroy_collection { - let caller = account("caller", 0, SEED); - - create_max_collection::(&caller)?; - let collection_id = 0; - }: _(RawOrigin::Signed(caller), collection_id) - - change_collection_issuer { - let caller: T::AccountId = account("caller", 0, SEED); - - create_max_collection::(&caller)?; - let collection_id = 0; - - let new_owner: T::AccountId = account("new_owner", 0, SEED); - - let new_owner_source = T::Lookup::unlookup(new_owner); - }: _(RawOrigin::Signed(caller), collection_id, new_owner_source) - - lock_collection { - let caller: T::AccountId = account("caller", 0, SEED); - - create_max_collection::(&caller)?; - let collection_id = 0; - }: _(RawOrigin::Signed(caller), collection_id) - - mint_nft { - let b in 0..100; - - let caller: T::AccountId = account("caller", 0, SEED); - - create_max_collection::(&caller)?; - let collection_id = 0; - let owner = caller.clone(); - - let royalty_recipient = Some(caller.clone()); - let royalty_amount = Some(Permill::from_percent(25)); - let metadata = create_data(); - let transferable = true; - }: _( - RawOrigin::Signed(caller), - None, - collection_id, - royalty_recipient, - royalty_amount, - metadata, - transferable, - Some(create_max_resource_types_array(b as usize)) - ) - - burn_nft { - let b in 0..200; - - let caller: T::AccountId = account("caller", 0, SEED); - create_max_collection::(&caller)?; - let collection_id = 0; - - let mut nft_builder = NftBuilder::new(collection_id); - let root_nft_id = nft_builder.build_wide_tree::(&caller, b)?; - let max_burns = b + 1; - }: _( - RawOrigin::Signed(caller), - collection_id, - root_nft_id, - max_burns - ) - - send { - let caller: T::AccountId = account("caller", 0, SEED); - create_max_collection::(&caller)?; - let collection_id = 0; - - let mut nft_builder = NftBuilder::new(collection_id); - let src_nft_id = nft_builder.build::(&caller)?; - let (_, target_nft_id) = nft_builder.build_tower::(&caller, NESTING_BUDGET - 2)?; - }: _( - RawOrigin::Signed(caller), - collection_id, - src_nft_id, - >::CollectionAndNftTuple(collection_id, target_nft_id) - ) - - accept_nft { - let caller: T::AccountId = account("caller", 0, SEED); - let sender: T::AccountId = account("sender", 0, SEED); - - create_max_collection::(&sender)?; - let src_collection_id = 0; - - create_max_collection::(&caller)?; - let target_collection_id = 1; - - let mut src_nft_builder = NftBuilder::new(src_collection_id); - let src_nft_id = src_nft_builder.build::(&sender)?; - - let mut target_nft_builder = NftBuilder::new(target_collection_id); - let fake_target_nft_id = target_nft_builder.build::(&caller)?; - let (_, target_nft_id) = target_nft_builder.build_tower::(&caller, NESTING_BUDGET - 1)?; - - let new_owner = >::CollectionAndNftTuple( - target_collection_id, - fake_target_nft_id - ); - - let actual_new_owner = >::CollectionAndNftTuple( - target_collection_id, - target_nft_id - ); - - >::send( - RawOrigin::Signed(sender.clone()).into(), - src_collection_id, - src_nft_id, - new_owner, - )?; - }: _( - RawOrigin::Signed(caller), - src_collection_id, - src_nft_id, - actual_new_owner - ) - - reject_nft { - let caller: T::AccountId = account("caller", 0, SEED); - let sender: T::AccountId = account("sender", 0, SEED); - - create_max_collection::(&sender)?; - let src_collection_id = 0; - - create_max_collection::(&caller)?; - let target_collection_id = 1; - - let mut src_nft_builder = NftBuilder::new(src_collection_id); - let (src_root_nft_id, _) = src_nft_builder.build_tower::(&sender, NESTING_BUDGET - 1)?; - - let mut target_nft_builder = NftBuilder::new(target_collection_id); - let target_nft_id = target_nft_builder.build::(&caller)?; - - let new_owner = >::CollectionAndNftTuple( - target_collection_id, - target_nft_id - ); - - >::send( - RawOrigin::Signed(sender.clone()).into(), - src_collection_id, - src_root_nft_id, - new_owner, - )?; - }: _( - RawOrigin::Signed(caller), - src_collection_id, - src_root_nft_id - ) - - set_property { - let caller: T::AccountId = account("caller", 0, SEED); - create_max_collection::(&caller)?; - let collection_id = 0; - - let mut nft_builder = NftBuilder::new(collection_id); - let (_, nft_id) = nft_builder.build_tower::(&caller, NESTING_BUDGET - 1)?; - - let key = create_data(); - let value = create_data(); - }: _( - RawOrigin::Signed(caller), - collection_id, - Some(nft_id), - key, - value - ) - - set_priority { - let caller: T::AccountId = account("caller", 0, SEED); - create_max_collection::(&caller)?; - let collection_id = 0; - - let mut nft_builder = NftBuilder::new(collection_id); - let (_, nft_id) = nft_builder.build_tower::(&caller, NESTING_BUDGET - 1)?; - let priorities = create_u32_array(); - }: _( - RawOrigin::Signed(caller), - collection_id, - nft_id, - priorities - ) - - add_basic_resource { - let caller: T::AccountId = account("caller", 0, SEED); - - create_max_collection::(&caller)?; - let collection_id = 0; - - let mut nft_builder = NftBuilder::new(collection_id); - let (_, nft_id) = nft_builder.build_tower::(&caller, NESTING_BUDGET - 1)?; - let resource = create_basic_resource(); - }: _( - RawOrigin::Signed(caller), - collection_id, - nft_id, - resource - ) - - add_composable_resource { - let caller: T::AccountId = account("caller", 0, SEED); - - create_max_collection::(&caller)?; - let collection_id = 0; - - let mut nft_builder = NftBuilder::new(collection_id); - let (_, nft_id) = nft_builder.build_tower::(&caller, NESTING_BUDGET - 1)?; - let resource = create_composable_resource(); - }: _( - RawOrigin::Signed(caller), - collection_id, - nft_id, - resource - ) - - add_slot_resource { - let caller: T::AccountId = account("caller", 0, SEED); - - create_max_collection::(&caller)?; - let collection_id = 0; - - let mut nft_builder = NftBuilder::new(collection_id); - let (_, nft_id) = nft_builder.build_tower::(&caller, NESTING_BUDGET - 1)?; - let resource = create_slot_resource(); - }: _( - RawOrigin::Signed(caller), - collection_id, - nft_id, - resource - ) - - remove_resource { - let caller: T::AccountId = account("caller", 0, SEED); - - create_max_collection::(&caller)?; - let collection_id = 0; - - let mut nft_builder = NftBuilder::new(collection_id); - let (_, nft_id) = nft_builder.build_tower::(&caller, NESTING_BUDGET - 1)?; - let resource = create_basic_resource(); - - >::add_basic_resource( - RawOrigin::Signed(caller.clone()).into(), - collection_id, - nft_id, - resource - )?; - - let resource_id = 0; - }: _( - RawOrigin::Signed(caller), - collection_id, - nft_id, - resource_id - ) - - accept_resource { - let caller: T::AccountId = account("caller", 0, SEED); - let admin: T::AccountId = account("admin", 0, SEED); - - create_max_collection::(&admin)?; - let collection_id = 0; - - let mut nft_builder = NftBuilder::new(collection_id); - let root_nft_id = 1; - let (_, nested_nft_id) = nft_builder.build_tower::(&admin, NESTING_BUDGET - 1)?; - let resource = create_basic_resource(); - - let new_owner = >::AccountId(caller.clone()); - - >::send( - RawOrigin::Signed(admin.clone()).into(), - collection_id, - root_nft_id, - new_owner, - )?; - - >::add_basic_resource( - RawOrigin::Signed(admin.clone()).into(), - collection_id, - nested_nft_id, - resource - )?; - - let resource_id = 0; - }: _( - RawOrigin::Signed(caller), - collection_id, - nested_nft_id, - resource_id - ) - - accept_resource_removal { - let caller: T::AccountId = account("caller", 0, SEED); - let admin: T::AccountId = account("admin", 0, SEED); - - create_max_collection::(&admin)?; - let collection_id = 0; - - let mut nft_builder = NftBuilder::new(collection_id); - let root_nft_id = 1; - let (_, nested_nft_id) = nft_builder.build_tower::(&admin, NESTING_BUDGET - 1)?; - let resource = create_basic_resource(); - - >::add_basic_resource( - RawOrigin::Signed(admin.clone()).into(), - collection_id, - nested_nft_id, - resource - )?; - - let resource_id = 0; - - let new_owner = >::AccountId(caller.clone()); - - >::send( - RawOrigin::Signed(admin.clone()).into(), - collection_id, - root_nft_id, - new_owner, - )?; - - >::remove_resource( - RawOrigin::Signed(admin).into(), - collection_id, - nested_nft_id, - resource_id - )?; - }: _( - RawOrigin::Signed(caller), - collection_id, - nested_nft_id, - resource_id - ) -} --- a/pallets/proxy-rmrk-core/src/lib.rs +++ /dev/null @@ -1,2119 +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 . - -//! # RMRK Core Proxy Pallet -//! -//! A pallet used as proxy for RMRK Core (). -//! -//! - [`Config`] -//! - [`Call`] -//! - [`Pallet`] -//! -//! ## Overview -//! -//! The RMRK Core Proxy pallet mirrors the functionality of RMRK Core, -//! binding its externalities to Unique's own underlying structure. -//! It is purposed to mimic RMRK Core exactly, allowing seamless integrations -//! of solutions based on RMRK. -//! -//! RMRK Core itself contains essential functionality for RMRK's nested and -//! multi-resourced NFTs. -//! -//! *Note*, that while RMRK itself is subject to active development and restructuring, -//! the proxy may be caught temporarily out of date. -//! -//! ### What is RMRK? -//! -//! RMRK is a set of NFT standards which compose several "NFT 2.0 lego" primitives. -//! Putting these legos together allows a user to create NFT systems of arbitrary complexity. -//! -//! Meaning, RMRK NFTs are dynamic, able to nest into each other and form a hierarchy, -//! make use of specific changeable and partially shared metadata in the form of resources, -//! and more. -//! -//! Visit RMRK documentation and repositories to learn more: -//! - Docs: -//! - FAQ: -//! - Substrate code repository: -//! - RMRK specification repository: -//! -//! ## Terminology -//! -//! For more information on RMRK, see RMRK's own documentation. -//! -//! ### Intro to RMRK -//! -//! - **Resource:** Additional piece of metadata of an NFT usually serving to add -//! a piece of media on top of the root metadata (NFT's own), be it a different wing -//! on the root template bird or something entirely unrelated. -//! -//! - **Base:** A list of possible "components" - Parts, a combination of which can -//! be appended/equipped to/on an NFT. -//! -//! - **Part:** Something that, together with other Parts, can constitute an NFT. -//! Parts are defined in the Base to which they belong. Parts can be either -//! of the `slot` type or `fixed` type. Slots are intended for equippables. -//! Note that "part of something" and "Part of a Base" can be easily confused, -//! and so in this documentation these words are distinguished by the capital letter. -//! -//! - **Theme:** Named objects of variable => value pairs which get interpolated into -//! the Base's `themable` Parts. Themes can hold any value, but are often represented -//! in RMRK's examples as colors applied to visible Parts. -//! -//! ### Peculiarities in Unique -//! -//! - **Scoped properties:** Properties that are normally obscured from users. -//! Their purpose is to contain structured metadata that was not included in the Unique standard -//! for collections and tokens, meant to be operated on by proxies and other outliers. -//! Scoped property keys are prefixed with `some-scope:`, where `some-scope` is -//! an arbitrary keyword, like "rmrk". `:` is considered an unacceptable symbol in user-defined -//! properties, which, along with other safeguards, makes scoped ones impossible to tamper with. -//! -//! - **Auxiliary properties:** A slightly different structure of properties, -//! trading universality of use for more convenient storage, writes and access. -//! Meant to be inaccessible to end users. -//! -//! ## Proxy Implementation -//! -//! An external user is supposed to be able to utilize this proxy as they would -//! utilize RMRK, and get exactly the same results. Normally, Unique transactions -//! are off-limits to RMRK collections and tokens, and vice versa. However, -//! the information stored on chain can be freely interpreted by storage reads and Unique RPCs. -//! -//! ### ID Mapping -//! -//! RMRK's collections' IDs are counted independently of Unique's and start at 0. -//! Note that tokens' IDs still start at 1. -//! The collections themselves, as well as tokens, are stored as Unique collections, -//! and thus RMRK IDs are mapped to Unique IDs (but not vice versa). -//! -//! ### External/Internal Collection Insulation -//! -//! A Unique transaction cannot target collections purposed for RMRK, -//! and they are flagged as `external` to specify that. On the other hand, -//! due to the mapping, RMRK transactions and RPCs simply cannot reach Unique collections. -//! -//! ### Native Properties -//! -//! Many of RMRK's native parameters are stored as scoped properties of a collection -//! or an NFT on the chain. Scoped properties are prefixed with `rmrk:`, where `:` -//! is an unacceptable symbol in user-defined properties, which, along with other safeguards, -//! makes them impossible to tamper with. -//! -//! ### Collection and NFT Types, or Base, Parts and Themes Handling -//! -//! RMRK introduces the concept of a Base, which is a catalogue of Parts, -//! possible components of an NFT. Due to its similarity with the functionality -//! of a token collection, a Base is stored and handled as one, and the Base's Parts and Themes -//! are this collection's NFTs. See [`CollectionType`] and [`NftType`]. -//! -//! ## Interface -//! -//! ### Dispatchables -//! -//! - `create_collection` - Create a new collection of NFTs. -//! - `destroy_collection` - Destroy a collection. -//! - `change_collection_issuer` - Change the issuer of a collection. -//! Analogous to Unique's collection's [`owner`](up_data_structs::Collection). -//! - `lock_collection` - "Lock" the collection and prevent new token creation. **Cannot be undone.** -//! - `mint_nft` - Mint an NFT in a specified collection. -//! - `burn_nft` - Burn an NFT, destroying it and its nested tokens. -//! - `send` - Transfer an NFT from an account/NFT A to another account/NFT B. -//! - `accept_nft` - Accept an NFT sent from another account to self or an owned NFT. -//! - `reject_nft` - Reject an NFT sent from another account to self or owned NFT and **burn it**. -//! - `accept_resource` - Accept the addition of a newly created pending resource to an existing NFT. -//! - `accept_resource_removal` - Accept the removal of a removal-pending resource from an NFT. -//! - `set_property` - Add or edit a custom user property of a token or a collection. -//! - `set_priority` - Set a different order of resource priorities for an NFT. -//! - `add_basic_resource` - Create and set/propose a basic resource for an NFT. -//! - `add_composable_resource` - Create and set/propose a composable resource for an NFT. -//! - `add_slot_resource` - Create and set/propose a slot resource for an NFT. -//! - `remove_resource` - Remove and erase a resource from an NFT. - -#![cfg_attr(not(feature = "std"), no_std)] - -use frame_support::{pallet_prelude::*, BoundedVec, dispatch::DispatchResult}; -use frame_system::{pallet_prelude::*, ensure_signed}; -use sp_runtime::{DispatchError, Permill, traits::StaticLookup}; -use sp_std::{ - vec::Vec, - collections::{btree_set::BTreeSet, btree_map::BTreeMap}, -}; -use up_data_structs::{*, mapping::TokenAddressMapping}; -use pallet_common::{ - Pallet as PalletCommon, Error as CommonError, CollectionHandle, CommonCollectionOperations, -}; -use pallet_nonfungible::{Pallet as PalletNft, NonfungibleHandle, TokenData}; -use pallet_structure::{Pallet as PalletStructure, Error as StructureError}; -use pallet_evm::account::CrossAccountId; -use core::convert::AsRef; - -pub use pallet::*; - -#[cfg(feature = "runtime-benchmarks")] -pub mod benchmarking; -pub mod misc; -pub mod property; -pub mod rpc; -pub mod weights; - -pub type SelfWeightOf = ::WeightInfo; - -use weights::WeightInfo; -use misc::*; -pub use property::*; - -use RmrkProperty::*; - -/// A maximum number of levels of depth in the token nesting tree. -pub const NESTING_BUDGET: u32 = 5; - -type PendingTarget = (CollectionId, TokenId); -type PendingChild = (RmrkCollectionId, RmrkNftId); -type PendingChildrenSet = BTreeSet; - -type BasesMap = BTreeMap; - -#[frame_support::pallet] -pub mod pallet { - use super::*; - - #[pallet::config] - pub trait Config: - frame_system::Config - + pallet_common::Config - + pallet_nonfungible::Config - + pallet_evm::Config - { - /// Overarching event type. - type RuntimeEvent: From> + IsType<::RuntimeEvent>; - - /// The weight information of this pallet. - type WeightInfo: WeightInfo; - } - - /// Latest yet-unused collection ID. - #[pallet::storage] - #[pallet::getter(fn collection_index)] - pub type CollectionIndex = StorageValue<_, RmrkCollectionId, ValueQuery>; - - /// Mapping from RMRK collection ID to Unique's. - #[pallet::storage] - pub type UniqueCollectionId = - StorageMap<_, Twox64Concat, RmrkCollectionId, CollectionId, ValueQuery>; - - #[pallet::pallet] - #[pallet::generate_store(pub(super) trait Store)] - pub struct Pallet(_); - - #[pallet::event] - #[pallet::generate_deposit(pub(super) fn deposit_event)] - pub enum Event { - CollectionCreated { - issuer: T::AccountId, - collection_id: RmrkCollectionId, - }, - CollectionDestroyed { - issuer: T::AccountId, - collection_id: RmrkCollectionId, - }, - IssuerChanged { - old_issuer: T::AccountId, - new_issuer: T::AccountId, - collection_id: RmrkCollectionId, - }, - CollectionLocked { - issuer: T::AccountId, - collection_id: RmrkCollectionId, - }, - NftMinted { - owner: T::AccountId, - collection_id: RmrkCollectionId, - nft_id: RmrkNftId, - }, - NFTBurned { - owner: T::AccountId, - nft_id: RmrkNftId, - }, - NFTSent { - sender: T::AccountId, - recipient: RmrkAccountIdOrCollectionNftTuple, - collection_id: RmrkCollectionId, - nft_id: RmrkNftId, - approval_required: bool, - }, - NFTAccepted { - sender: T::AccountId, - recipient: RmrkAccountIdOrCollectionNftTuple, - collection_id: RmrkCollectionId, - nft_id: RmrkNftId, - }, - NFTRejected { - sender: T::AccountId, - collection_id: RmrkCollectionId, - nft_id: RmrkNftId, - }, - PropertySet { - collection_id: RmrkCollectionId, - maybe_nft_id: Option, - key: RmrkKeyString, - value: RmrkValueString, - }, - ResourceAdded { - nft_id: RmrkNftId, - resource_id: RmrkResourceId, - }, - ResourceRemoval { - nft_id: RmrkNftId, - resource_id: RmrkResourceId, - }, - ResourceAccepted { - nft_id: RmrkNftId, - resource_id: RmrkResourceId, - }, - ResourceRemovalAccepted { - nft_id: RmrkNftId, - resource_id: RmrkResourceId, - }, - PrioritySet { - collection_id: RmrkCollectionId, - nft_id: RmrkNftId, - }, - } - - #[pallet::error] - pub enum Error { - /* Unique proxy-specific events */ - /// Property of the type of RMRK collection could not be read successfully. - CorruptedCollectionType, - // NftTypeEncodeError, - /// Too many symbols supplied as the property key. The maximum is [256](up_data_structs::MAX_PROPERTY_KEY_LENGTH). - RmrkPropertyKeyIsTooLong, - /// Too many bytes supplied as the property value. The maximum is [32768](up_data_structs::MAX_PROPERTY_VALUE_LENGTH). - RmrkPropertyValueIsTooLong, - /// Could not find a property by the supplied key. - RmrkPropertyIsNotFound, - /// Something went wrong when decoding encoded data from the storage. - /// Perhaps, there was a wrong key supplied for the type, or the data was improperly stored. - UnableToDecodeRmrkData, - - /* RMRK compatible events */ - /// Only destroying collections without tokens is allowed. - CollectionNotEmpty, - /// Could not find an ID for a collection. It is likely there were too many collections created on the chain, causing an overflow. - NoAvailableCollectionId, - /// Token does not exist, or there is no suitable ID for it, likely too many tokens were created in a collection, causing an overflow. - NoAvailableNftId, - /// Collection does not exist, has a wrong type, or does not map to a Unique ID. - CollectionUnknown, - /// No permission to perform action. - NoPermission, - /// Token is marked as non-transferable, and thus cannot be transferred. - NonTransferable, - /// Too many tokens created in the collection, no new ones are allowed. - CollectionFullOrLocked, - /// No such resource found. - ResourceDoesntExist, - /// If an NFT is sent to a descendant, that would form a nesting loop, an ouroboros. - /// Sending to self is redundant. - CannotSendToDescendentOrSelf, - /// Not the target owner of the sent NFT. - CannotAcceptNonOwnedNft, - /// Not the target owner of the sent NFT. - CannotRejectNonOwnedNft, - /// NFT was not sent and is not pending. - CannotRejectNonPendingNft, - /// Resource is not pending for the operation. - ResourceNotPending, - /// Could not find an ID for the resource. It is likely there were too many resources created on an NFT, causing an overflow. - NoAvailableResourceId, - } - - #[pallet::call] - impl Pallet { - // todo :refactor replace every collection_id with rmrk_collection_id (and nft_id) in arguments for uniformity? - - /// Create a new collection of NFTs. - /// - /// # Permissions: - /// * Anyone - will be assigned as the issuer of the collection. - /// - /// # Arguments: - /// - `origin`: sender of the transaction - /// - `metadata`: Metadata describing the collection, e.g. IPFS hash. Cannot be changed. - /// - `max`: Optional maximum number of tokens. - /// - `symbol`: UTF-8 string with token prefix, by which to represent the token in wallets and UIs. - /// Analogous to Unique's [`token_prefix`](up_data_structs::Collection). Cannot be changed. - #[pallet::call_index(0)] - #[pallet::weight(>::create_collection())] - pub fn create_collection( - origin: OriginFor, - metadata: RmrkString, - max: Option, - symbol: RmrkCollectionSymbol, - ) -> DispatchResult { - let sender = ensure_signed(origin)?; - - let limits = CollectionLimits { - owner_can_transfer: Some(false), - token_limit: max, - ..Default::default() - }; - - let data = CreateCollectionData { - limits: Some(limits), - token_prefix: symbol - .into_inner() - .try_into() - .map_err(|_| >::CollectionTokenPrefixLimitExceeded)?, - permissions: Some(CollectionPermissions { - nesting: Some(NestingPermissions { - token_owner: true, - collection_admin: false, - restricted: None, - #[cfg(feature = "runtime-benchmarks")] - permissive: false, - }), - ..Default::default() - }), - ..Default::default() - }; - - let unique_collection_id = Self::init_collection( - T::CrossAccountId::from_sub(sender.clone()), - data, - [ - Self::encode_rmrk_property(Metadata, &metadata)?, - Self::encode_rmrk_property(CollectionType, &misc::CollectionType::Regular)?, - ] - .into_iter(), - )?; - let rmrk_collection_id = >::get(); - - >::insert(rmrk_collection_id, unique_collection_id); - - >::set_scoped_collection_property( - unique_collection_id, - RMRK_SCOPE, - Self::encode_rmrk_property(RmrkInternalCollectionId, &rmrk_collection_id)?, - )?; - - >::mutate(|n| *n += 1); - - Self::deposit_event(Event::CollectionCreated { - issuer: sender, - collection_id: rmrk_collection_id, - }); - - Ok(()) - } - - /// Destroy a collection. - /// - /// Only empty collections can be destroyed. If it has any tokens, they must be burned first. - /// - /// # Permissions: - /// * Collection issuer - /// - /// # Arguments: - /// - `origin`: sender of the transaction - /// - `collection_id`: RMRK ID of the collection to destroy. - #[pallet::call_index(1)] - #[pallet::weight(>::destroy_collection())] - pub fn destroy_collection( - origin: OriginFor, - collection_id: RmrkCollectionId, - ) -> DispatchResult { - let sender = ensure_signed(origin)?; - let cross_sender = T::CrossAccountId::from_sub(sender.clone()); - - let collection = Self::get_typed_nft_collection( - Self::unique_collection_id(collection_id)?, - misc::CollectionType::Regular, - )?; - collection.check_is_external()?; - - >::destroy_collection(collection, &cross_sender) - .map_err(Self::map_unique_err_to_proxy)?; - - Self::deposit_event(Event::CollectionDestroyed { - issuer: sender, - collection_id, - }); - - Ok(()) - } - - /// Change the issuer of a collection. Analogous to Unique's collection's [`owner`](up_data_structs::Collection). - /// - /// # Permissions: - /// * Collection issuer - /// - /// # Arguments: - /// - `origin`: sender of the transaction - /// - `collection_id`: RMRK collection ID to change the issuer of. - /// - `new_issuer`: Collection's new issuer. - #[pallet::call_index(2)] - #[pallet::weight(>::change_collection_issuer())] - pub fn change_collection_issuer( - origin: OriginFor, - collection_id: RmrkCollectionId, - new_issuer: ::Source, - ) -> DispatchResult { - let sender = ensure_signed(origin)?; - - let collection = Self::get_nft_collection(Self::unique_collection_id(collection_id)?)?; - collection.check_is_external()?; - - let new_issuer = T::Lookup::lookup(new_issuer)?; - - Self::change_collection_owner( - Self::unique_collection_id(collection_id)?, - misc::CollectionType::Regular, - sender.clone(), - new_issuer.clone(), - )?; - - Self::deposit_event(Event::IssuerChanged { - old_issuer: sender, - new_issuer, - collection_id, - }); - - Ok(()) - } - - /// "Lock" the collection and prevent new token creation. Cannot be undone. - /// - /// # Permissions: - /// * Collection issuer - /// - /// # Arguments: - /// - `origin`: sender of the transaction - /// - `collection_id`: RMRK ID of the collection to lock. - #[pallet::call_index(3)] - #[pallet::weight(>::lock_collection())] - pub fn lock_collection( - origin: OriginFor, - collection_id: RmrkCollectionId, - ) -> DispatchResult { - let sender = ensure_signed(origin)?; - let cross_sender = T::CrossAccountId::from_sub(sender.clone()); - - let collection = Self::get_typed_nft_collection( - Self::unique_collection_id(collection_id)?, - misc::CollectionType::Regular, - )?; - collection.check_is_external()?; - - Self::check_collection_owner(&collection, &cross_sender)?; - - let token_count = collection.total_supply(); - - let mut collection = collection.into_inner(); - collection.limits.token_limit = Some(token_count); - collection.save()?; - - Self::deposit_event(Event::CollectionLocked { - issuer: sender, - collection_id, - }); - - Ok(()) - } - - /// Mint an NFT in a specified collection. - /// - /// # Permissions: - /// * Collection issuer - /// - /// # Arguments: - /// - `origin`: sender of the transaction - /// - `owner`: Owner account of the NFT. If set to None, defaults to the sender (collection issuer). - /// - `collection_id`: RMRK collection ID for the NFT to be minted within. Cannot be changed. - /// - `recipient`: Receiver account of the royalty. Has no effect if the `royalty_amount` is not set. Cannot be changed. - /// - `royalty_amount`: Optional permillage reward from each trade for the `recipient`. Cannot be changed. - /// - `metadata`: Arbitrary data about an NFT, e.g. IPFS hash. Cannot be changed. - /// - `transferable`: Can this NFT be transferred? Cannot be changed. - /// - `resources`: Resource data to be added to the NFT immediately after minting. - #[pallet::call_index(4)] - #[pallet::weight(>::mint_nft(resources.as_ref().map(|r| r.len() as u32).unwrap_or(0)))] - pub fn mint_nft( - origin: OriginFor, - owner: Option, - collection_id: RmrkCollectionId, - recipient: Option, - royalty_amount: Option, - metadata: RmrkString, - transferable: bool, - resources: Option>, - ) -> DispatchResult { - let sender = ensure_signed(origin)?; - let cross_sender = T::CrossAccountId::from_sub(sender.clone()); - - let owner = owner.unwrap_or(sender.clone()); - let cross_owner = T::CrossAccountId::from_sub(owner.clone()); - - let collection = Self::get_typed_nft_collection( - Self::unique_collection_id(collection_id)?, - misc::CollectionType::Regular, - )?; - collection.check_is_external()?; - - let royalty_info = royalty_amount.map(|amount| rmrk_traits::RoyaltyInfo { - recipient: recipient.unwrap_or_else(|| owner.clone()), - amount, - }); - - let nft_id = Self::create_nft( - &cross_sender, - &cross_owner, - &collection, - [ - Self::encode_rmrk_property(TokenType, &NftType::Regular)?, - Self::encode_rmrk_property(Transferable, &transferable)?, - Self::encode_rmrk_property(PendingNftAccept, &None::)?, - Self::encode_rmrk_property(RoyaltyInfo, &royalty_info)?, - Self::encode_rmrk_property(Metadata, &metadata)?, - Self::encode_rmrk_property(Equipped, &false)?, - Self::encode_rmrk_property(ResourcePriorities, &>::new())?, - Self::encode_rmrk_property(NextResourceId, &(0 as RmrkResourceId))?, - Self::encode_rmrk_property(PendingChildren, &PendingChildrenSet::new())?, - Self::encode_rmrk_property(AssociatedBases, &BasesMap::new())?, - ] - .into_iter(), - ) - .map_err(|err| match err { - DispatchError::Arithmetic(_) => >::NoAvailableNftId.into(), - err => Self::map_unique_err_to_proxy(err), - })?; - - if let Some(resources) = resources { - for resource in resources { - Self::resource_add(sender.clone(), collection.id, nft_id, resource)?; - } - } - - Self::deposit_event(Event::NftMinted { - owner, - collection_id, - nft_id: nft_id.0, - }); - - Ok(()) - } - - /// Burn an NFT, destroying it and its nested tokens up to the specified limit. - /// If the burning budget is exceeded, the transaction is reverted. - /// - /// This is the way to burn a nested token as well. - /// - /// For more information, see [`burn_recursively`](pallet_nonfungible::pallet::Pallet::burn_recursively). - /// - /// # Permissions: - /// * Token owner - /// - /// # Arguments: - /// - `origin`: sender of the transaction - /// - `collection_id`: RMRK ID of the collection in which the NFT to burn belongs to. - /// - `nft_id`: ID of the NFT to be destroyed. - /// - `max_burns`: Maximum number of tokens to burn, assuming nesting. The transaction - /// is reverted if there are more tokens to burn in the nesting tree than this number. - /// This is primarily a mechanism of transaction weight control. - #[pallet::call_index(5)] - #[pallet::weight(>::burn_nft(*max_burns))] - pub fn burn_nft( - origin: OriginFor, - collection_id: RmrkCollectionId, - nft_id: RmrkNftId, - max_burns: u32, - ) -> DispatchResult { - let sender = ensure_signed(origin)?; - let cross_sender = T::CrossAccountId::from_sub(sender.clone()); - - let collection = Self::get_typed_nft_collection( - Self::unique_collection_id(collection_id)?, - misc::CollectionType::Regular, - )?; - collection.check_is_external()?; - - Self::destroy_nft( - cross_sender, - Self::unique_collection_id(collection_id)?, - nft_id.into(), - max_burns, - >::NoPermission, - ) - .map_err(|err| Self::map_unique_err_to_proxy(err.error))?; - - Self::deposit_event(Event::NFTBurned { - owner: sender, - nft_id, - }); - - Ok(()) - } - - /// Transfer an NFT from an account/NFT A to another account/NFT B. - /// The token must be transferable. Nesting cannot occur deeper than the [`NESTING_BUDGET`]. - /// - /// If the target owner is an NFT owned by another account, then the NFT will enter - /// the pending state and will have to be accepted by the other account. - /// - /// # Permissions: - /// - Token owner - /// - /// # Arguments: - /// - `origin`: sender of the transaction - /// - `rmrk_collection_id`: RMRK ID of the collection of the NFT to be transferred. - /// - `rmrk_nft_id`: ID of the NFT to be transferred. - /// - `new_owner`: New owner of the nft which can be either an account or a NFT. - #[pallet::call_index(6)] - #[pallet::weight(>::send())] - pub fn send( - origin: OriginFor, - rmrk_collection_id: RmrkCollectionId, - rmrk_nft_id: RmrkNftId, - new_owner: RmrkAccountIdOrCollectionNftTuple, - ) -> DispatchResult { - let sender = ensure_signed(origin.clone())?; - let cross_sender = T::CrossAccountId::from_sub(sender.clone()); - - let collection_id = Self::unique_collection_id(rmrk_collection_id)?; - let nft_id = rmrk_nft_id.into(); - - let collection = - Self::get_typed_nft_collection(collection_id, misc::CollectionType::Regular)?; - collection.check_is_external()?; - - let token_data = - >::get((collection_id, nft_id)).ok_or(>::NoAvailableNftId)?; - - let from = token_data.owner; - - ensure!( - Self::get_nft_property_decoded(collection_id, nft_id, RmrkProperty::Transferable)?, - >::NonTransferable - ); - - ensure!( - Self::get_nft_property_decoded::>( - collection_id, - nft_id, - RmrkProperty::PendingNftAccept - )? - .is_none(), - >::NoPermission - ); - - let target_owner; - let approval_required; - - match new_owner { - RmrkAccountIdOrCollectionNftTuple::AccountId(ref account_id) => { - target_owner = T::CrossAccountId::from_sub(account_id.clone()); - approval_required = false; - } - RmrkAccountIdOrCollectionNftTuple::CollectionAndNftTuple( - target_collection_id, - target_nft_id, - ) => { - let target_collection_id = Self::unique_collection_id(target_collection_id)?; - - let target_nft_budget = budget::Value::new(NESTING_BUDGET); - - let target_nft_owner = >::get_checked_topmost_owner( - target_collection_id, - target_nft_id.into(), - Some((collection_id, nft_id)), - &target_nft_budget, - ) - .map_err(Self::map_unique_err_to_proxy)? - .ok_or::(>::NoPermission.into())?; - - approval_required = cross_sender != target_nft_owner; - - if approval_required { - target_owner = target_nft_owner; - - >::set_scoped_token_property( - collection.id, - nft_id, - RMRK_SCOPE, - Self::encode_rmrk_property::>( - PendingNftAccept, - &Some((target_collection_id, target_nft_id.into())), - )?, - )?; - - Self::insert_pending_child( - (target_collection_id, target_nft_id.into()), - (rmrk_collection_id, rmrk_nft_id), - )?; - } else { - target_owner = T::CrossTokenAddressMapping::token_to_address( - target_collection_id, - target_nft_id.into(), - ); - } - } - } - - let src_nft_budget = budget::Value::new(NESTING_BUDGET); - - >::transfer_from( - &collection, - &cross_sender, - &from, - &target_owner, - nft_id, - &src_nft_budget, - ) - .map_err(Self::map_unique_err_to_proxy)?; - - Self::deposit_event(Event::NFTSent { - sender, - recipient: new_owner, - collection_id: rmrk_collection_id, - nft_id: rmrk_nft_id, - approval_required, - }); - - Ok(()) - } - - /// Accept an NFT sent from another account to self or an owned NFT. - /// - /// The NFT in question must be pending, and, thus, be [sent](`Pallet::send`) first. - /// - /// # Permissions: - /// - Token-owner-to-be - /// - /// # Arguments: - /// - `origin`: sender of the transaction - /// - `rmrk_collection_id`: RMRK collection ID of the NFT to be accepted. - /// - `rmrk_nft_id`: ID of the NFT to be accepted. - /// - `new_owner`: Either the sender's account ID or a sender-owned NFT, - /// whichever the accepted NFT was sent to. - #[pallet::call_index(7)] - #[pallet::weight(>::accept_nft())] - pub fn accept_nft( - origin: OriginFor, - rmrk_collection_id: RmrkCollectionId, - rmrk_nft_id: RmrkNftId, - new_owner: RmrkAccountIdOrCollectionNftTuple, - ) -> DispatchResult { - let sender = ensure_signed(origin.clone())?; - let cross_sender = T::CrossAccountId::from_sub(sender.clone()); - - let collection_id = Self::unique_collection_id(rmrk_collection_id)?; - let nft_id = rmrk_nft_id.into(); - - let collection = - Self::get_typed_nft_collection(collection_id, misc::CollectionType::Regular)?; - collection.check_is_external()?; - - let new_cross_owner = match new_owner { - RmrkAccountIdOrCollectionNftTuple::AccountId(ref account_id) => { - T::CrossAccountId::from_sub(account_id.clone()) - } - RmrkAccountIdOrCollectionNftTuple::CollectionAndNftTuple( - target_collection_id, - target_nft_id, - ) => { - let target_collection_id = Self::unique_collection_id(target_collection_id)?; - - T::CrossTokenAddressMapping::token_to_address( - target_collection_id, - TokenId(target_nft_id), - ) - } - }; - - let budget = budget::Value::new(NESTING_BUDGET); - - >::transfer( - &collection, - &cross_sender, - &new_cross_owner, - nft_id, - &budget, - ) - .map_err(|err| { - if err == >::UserIsNotAllowedToNest.into() { - >::CannotAcceptNonOwnedNft.into() - } else { - Self::map_unique_err_to_proxy(err) - } - })?; - - let pending_target = Self::get_nft_property_decoded::>( - collection_id, - nft_id, - RmrkProperty::PendingNftAccept, - )?; - - if let Some(pending_target) = pending_target { - Self::remove_pending_child(pending_target, (rmrk_collection_id, rmrk_nft_id))?; - - >::set_scoped_token_property( - collection.id, - nft_id, - RMRK_SCOPE, - Self::encode_rmrk_property(PendingNftAccept, &None::)?, - )?; - } - - Self::deposit_event(Event::NFTAccepted { - sender, - recipient: new_owner, - collection_id: rmrk_collection_id, - nft_id: rmrk_nft_id, - }); - - Ok(()) - } - - /// Reject an NFT sent from another account to self or owned NFT. - /// The NFT in question will not be sent back and burnt instead. - /// - /// The NFT in question must be pending, and, thus, be [sent](`Pallet::send`) first. - /// - /// # Permissions: - /// - Token-owner-to-be-not - /// - /// # Arguments: - /// - `origin`: sender of the transaction - /// - `rmrk_collection_id`: RMRK ID of the NFT to be rejected. - /// - `rmrk_nft_id`: ID of the NFT to be rejected. - #[pallet::call_index(8)] - #[pallet::weight(>::reject_nft())] - pub fn reject_nft( - origin: OriginFor, - rmrk_collection_id: RmrkCollectionId, - rmrk_nft_id: RmrkNftId, - ) -> DispatchResult { - let sender = ensure_signed(origin)?; - let cross_sender = T::CrossAccountId::from_sub(sender.clone()); - - let collection_id = Self::unique_collection_id(rmrk_collection_id)?; - let nft_id = rmrk_nft_id.into(); - - let collection = - Self::get_typed_nft_collection(collection_id, misc::CollectionType::Regular)?; - collection.check_is_external()?; - - ensure!( - >::get((collection_id, nft_id)).is_some(), - >::NoAvailableNftId - ); - - let pending_target = Self::get_nft_property_decoded::>( - collection_id, - nft_id, - RmrkProperty::PendingNftAccept, - )?; - - match pending_target { - Some(pending_target) => { - Self::remove_pending_child(pending_target, (rmrk_collection_id, rmrk_nft_id))? - } - None => return Err(>::CannotRejectNonPendingNft.into()), - } - - Self::destroy_nft( - cross_sender, - collection_id, - nft_id, - NESTING_BUDGET, - >::CannotRejectNonOwnedNft, - ) - .map_err(|err| Self::map_unique_err_to_proxy(err.error))?; - - Self::deposit_event(Event::NFTRejected { - sender, - collection_id: rmrk_collection_id, - nft_id: rmrk_nft_id, - }); - - Ok(()) - } - - /// Accept the addition of a newly created pending resource to an existing NFT. - /// - /// This transaction is needed when a resource is created and assigned to an NFT - /// by a non-owner, i.e. the collection issuer, with one of the - /// [`add_...` transactions](Pallet::add_basic_resource). - /// - /// # Permissions: - /// - Token owner - /// - /// # Arguments: - /// - `origin`: sender of the transaction - /// - `rmrk_collection_id`: RMRK collection ID of the NFT. - /// - `rmrk_nft_id`: ID of the NFT with a pending resource to be accepted. - /// - `resource_id`: ID of the newly created pending resource. - /// accept the addition of a new resource to an existing NFT - #[pallet::call_index(9)] - #[pallet::weight(>::accept_resource())] - pub fn accept_resource( - origin: OriginFor, - rmrk_collection_id: RmrkCollectionId, - rmrk_nft_id: RmrkNftId, - resource_id: RmrkResourceId, - ) -> DispatchResult { - let sender = ensure_signed(origin)?; - let cross_sender = T::CrossAccountId::from_sub(sender); - - let collection_id = Self::unique_collection_id(rmrk_collection_id) - .map_err(|_| >::ResourceDoesntExist)?; - let collection = - Self::get_typed_nft_collection(collection_id, misc::CollectionType::Regular)?; - collection.check_is_external()?; - - let nft_id = rmrk_nft_id.into(); - - let budget = budget::Value::new(NESTING_BUDGET); - - let nft_owner = - >::find_topmost_owner(collection_id, nft_id, &budget) - .map_err(|_| >::ResourceDoesntExist)? - .ok_or::(>::NoPermission.into())?; - - Self::try_mutate_resource_info(collection_id, nft_id, resource_id, |res| { - ensure!(res.pending, >::ResourceNotPending); - ensure!(cross_sender == nft_owner, >::NoPermission); - - res.pending = false; - - Ok(()) - })?; - - Self::deposit_event(Event::::ResourceAccepted { - nft_id: rmrk_nft_id, - resource_id, - }); - - Ok(()) - } - - /// Accept the removal of a removal-pending resource from an NFT. - /// - /// This transaction is needed when a non-owner, i.e. the collection issuer, - /// requests a [removal](`Pallet::remove_resource`) of a resource from an NFT. - /// - /// # Permissions: - /// - Token owner - /// - /// # Arguments: - /// - `origin`: sender of the transaction - /// - `rmrk_collection_id`: RMRK collection ID of the NFT. - /// - `rmrk_nft_id`: ID of the NFT with a resource to be removed. - /// - `resource_id`: ID of the removal-pending resource. - #[pallet::call_index(10)] - #[pallet::weight(>::accept_resource_removal())] - pub fn accept_resource_removal( - origin: OriginFor, - rmrk_collection_id: RmrkCollectionId, - rmrk_nft_id: RmrkNftId, - resource_id: RmrkResourceId, - ) -> DispatchResult { - let sender = ensure_signed(origin)?; - let cross_sender = T::CrossAccountId::from_sub(sender); - - let collection_id = Self::unique_collection_id(rmrk_collection_id) - .map_err(|_| >::ResourceDoesntExist)?; - let collection = - Self::get_typed_nft_collection(collection_id, misc::CollectionType::Regular)?; - collection.check_is_external()?; - - let nft_id = rmrk_nft_id.into(); - - let budget = budget::Value::new(NESTING_BUDGET); - - let nft_owner = - >::find_topmost_owner(collection_id, nft_id, &budget) - .map_err(|_| >::ResourceDoesntExist)? - .ok_or::(>::NoPermission.into())?; - - ensure!(cross_sender == nft_owner, >::NoPermission); - - let resource_id_key = Self::get_scoped_property_key(ResourceId(resource_id))?; - - let resource_info = >::token_aux_property(( - collection_id, - nft_id, - RMRK_SCOPE, - resource_id_key.clone(), - )) - .ok_or(>::ResourceDoesntExist)?; - - let resource_info: RmrkResourceInfo = Self::decode_property_value(&resource_info)?; - - ensure!( - resource_info.pending_removal, - >::ResourceNotPending - ); - - >::remove_token_aux_property( - collection_id, - nft_id, - RMRK_SCOPE, - resource_id_key, - ); - - if let RmrkResourceTypes::Composable(resource) = resource_info.resource { - let base_id = resource.base; - - Self::remove_associated_base_id(collection_id, nft_id, base_id)?; - } - - Self::deposit_event(Event::::ResourceRemovalAccepted { - nft_id: rmrk_nft_id, - resource_id, - }); - - Ok(()) - } - - /// Add or edit a custom user property, a key-value pair, describing the metadata - /// of a token or a collection, on either one of these. - /// - /// Note that in this proxy implementation many details regarding RMRK are stored - /// as scoped properties prefixed with "rmrk:", normally inaccessible - /// to external transactions and RPCs. - /// - /// # Permissions: - /// - Collection issuer - in case of collection property - /// - Token owner - in case of NFT property - /// - /// # Arguments: - /// - `origin`: sender of the transaction - /// - `rmrk_collection_id`: RMRK collection ID. - /// - `maybe_nft_id`: Optional ID of the NFT. If left empty, then the property is set for the collection. - /// - `key`: Key of the custom property to be referenced by. - /// - `value`: Value of the custom property to be stored. - #[pallet::call_index(11)] - #[pallet::weight(>::set_property())] - pub fn set_property( - origin: OriginFor, - #[pallet::compact] rmrk_collection_id: RmrkCollectionId, - maybe_nft_id: Option, - key: RmrkKeyString, - value: RmrkValueString, - ) -> DispatchResult { - let sender = ensure_signed(origin)?; - let sender = T::CrossAccountId::from_sub(sender); - - let collection_id = Self::unique_collection_id(rmrk_collection_id)?; - let collection = - Self::get_typed_nft_collection(collection_id, misc::CollectionType::Regular)?; - collection.check_is_external()?; - - let budget = budget::Value::new(NESTING_BUDGET); - - match maybe_nft_id { - Some(nft_id) => { - let token_id: TokenId = nft_id.into(); - - Self::ensure_nft_type(collection_id, token_id, NftType::Regular)?; - Self::ensure_nft_owner(collection_id, token_id, &sender, &budget)?; - - >::set_scoped_token_property( - collection_id, - token_id, - RMRK_SCOPE, - Self::encode_rmrk_property(UserProperty(key.as_slice()), &value)?, - )?; - } - None => { - let collection = Self::get_typed_nft_collection( - collection_id, - misc::CollectionType::Regular, - )?; - - Self::check_collection_owner(&collection, &sender)?; - - >::set_scoped_collection_property( - collection_id, - RMRK_SCOPE, - Self::encode_rmrk_property(UserProperty(key.as_slice()), &value)?, - )?; - } - } - - Self::deposit_event(Event::PropertySet { - collection_id: rmrk_collection_id, - maybe_nft_id, - key, - value, - }); - - Ok(()) - } - - /// Set a different order of resource priorities for an NFT. Priorities can be used, - /// for example, for order of rendering. - /// - /// Note that the priorities are not updated automatically, and are an empty vector - /// by default. There is no pre-set definition for the order to be particular, - /// it can be interpreted arbitrarily use-case by use-case. - /// - /// # Permissions: - /// - Token owner - /// - /// # Arguments: - /// - `origin`: sender of the transaction - /// - `rmrk_collection_id`: RMRK collection ID of the NFT. - /// - `rmrk_nft_id`: ID of the NFT to rearrange resource priorities for. - /// - `priorities`: Ordered vector of resource IDs. - #[pallet::call_index(12)] - #[pallet::weight(>::set_priority())] - pub fn set_priority( - origin: OriginFor, - rmrk_collection_id: RmrkCollectionId, - rmrk_nft_id: RmrkNftId, - priorities: BoundedVec, - ) -> DispatchResult { - let sender = ensure_signed(origin)?; - let sender = T::CrossAccountId::from_sub(sender); - - let collection_id = Self::unique_collection_id(rmrk_collection_id)?; - let nft_id = rmrk_nft_id.into(); - - let collection = - Self::get_typed_nft_collection(collection_id, misc::CollectionType::Regular)?; - collection.check_is_external()?; - - let budget = budget::Value::new(NESTING_BUDGET); - - Self::ensure_nft_type(collection_id, nft_id, NftType::Regular)?; - Self::ensure_nft_owner(collection_id, nft_id, &sender, &budget)?; - - >::set_scoped_token_property( - collection_id, - nft_id, - RMRK_SCOPE, - Self::encode_rmrk_property(ResourcePriorities, &priorities.into_inner())?, - )?; - - Self::deposit_event(Event::::PrioritySet { - collection_id: rmrk_collection_id, - nft_id: rmrk_nft_id, - }); - - Ok(()) - } - - /// Create and set/propose a basic resource for an NFT. - /// - /// A basic resource is the simplest, lacking a Base and anything that comes with it. - /// See RMRK docs for more information and examples. - /// - /// # Permissions: - /// - Collection issuer - if not the token owner, adding the resource will warrant - /// the owner's [acceptance](Pallet::accept_resource). - /// - /// # Arguments: - /// - `origin`: sender of the transaction - /// - `rmrk_collection_id`: RMRK collection ID of the NFT. - /// - `nft_id`: ID of the NFT to assign a resource to. - /// - `resource`: Data of the resource to be created. - #[pallet::call_index(13)] - #[pallet::weight(>::add_basic_resource())] - pub fn add_basic_resource( - origin: OriginFor, - rmrk_collection_id: RmrkCollectionId, - nft_id: RmrkNftId, - resource: RmrkBasicResource, - ) -> DispatchResult { - let sender = ensure_signed(origin.clone())?; - - let collection_id = Self::unique_collection_id(rmrk_collection_id)?; - let collection = - Self::get_typed_nft_collection(collection_id, misc::CollectionType::Regular)?; - collection.check_is_external()?; - - let resource_id = Self::resource_add( - sender, - collection_id, - nft_id.into(), - RmrkResourceTypes::Basic(resource), - )?; - - Self::deposit_event(Event::ResourceAdded { - nft_id, - resource_id, - }); - Ok(()) - } - - /// Create and set/propose a composable resource for an NFT. - /// - /// A composable resource links to a Base and has a subset of its Parts it is composed of. - /// See RMRK docs for more information and examples. - /// - /// # Permissions: - /// - Collection issuer - if not the token owner, adding the resource will warrant - /// the owner's [acceptance](Pallet::accept_resource). - /// - /// # Arguments: - /// - `origin`: sender of the transaction - /// - `rmrk_collection_id`: RMRK collection ID of the NFT. - /// - `nft_id`: ID of the NFT to assign a resource to. - /// - `resource`: Data of the resource to be created. - #[pallet::call_index(14)] - #[pallet::weight(>::add_composable_resource())] - pub fn add_composable_resource( - origin: OriginFor, - rmrk_collection_id: RmrkCollectionId, - nft_id: RmrkNftId, - resource: RmrkComposableResource, - ) -> DispatchResult { - let sender = ensure_signed(origin.clone())?; - - let collection_id = Self::unique_collection_id(rmrk_collection_id)?; - let collection = - Self::get_typed_nft_collection(collection_id, misc::CollectionType::Regular)?; - collection.check_is_external()?; - - let base_id = resource.base; - - let resource_id = Self::resource_add( - sender, - collection_id, - nft_id.into(), - RmrkResourceTypes::Composable(resource), - )?; - - >::try_mutate_token_aux_property( - collection_id, - nft_id.into(), - RMRK_SCOPE, - Self::get_scoped_property_key(AssociatedBases)?, - |value| -> DispatchResult { - let mut bases: BasesMap = match value { - Some(value) => Self::decode_property_value(value)?, - None => BasesMap::new(), - }; - - *bases.entry(base_id).or_insert(0) += 1; - - *value = Some(Self::encode_property_value(&bases)?); - Ok(()) - }, - )?; - - Self::deposit_event(Event::ResourceAdded { - nft_id, - resource_id, - }); - Ok(()) - } - - /// Create and set/propose a slot resource for an NFT. - /// - /// A slot resource links to a Base and a slot ID in it which it can fit into. - /// See RMRK docs for more information and examples. - /// - /// # Permissions: - /// - Collection issuer - if not the token owner, adding the resource will warrant - /// the owner's [acceptance](Pallet::accept_resource). - /// - /// # Arguments: - /// - `origin`: sender of the transaction - /// - `rmrk_collection_id`: RMRK collection ID of the NFT. - /// - `nft_id`: ID of the NFT to assign a resource to. - /// - `resource`: Data of the resource to be created. - #[pallet::call_index(15)] - #[pallet::weight(>::add_slot_resource())] - pub fn add_slot_resource( - origin: OriginFor, - rmrk_collection_id: RmrkCollectionId, - nft_id: RmrkNftId, - resource: RmrkSlotResource, - ) -> DispatchResult { - let sender = ensure_signed(origin.clone())?; - - let collection_id = Self::unique_collection_id(rmrk_collection_id)?; - let collection = - Self::get_typed_nft_collection(collection_id, misc::CollectionType::Regular)?; - collection.check_is_external()?; - - let resource_id = Self::resource_add( - sender, - collection_id, - nft_id.into(), - RmrkResourceTypes::Slot(resource), - )?; - - Self::deposit_event(Event::ResourceAdded { - nft_id, - resource_id, - }); - Ok(()) - } - - /// Remove and erase a resource from an NFT. - /// - /// If the sender does not own the NFT, then it will be pending confirmation, - /// and will have to be [accepted](Pallet::accept_resource_removal) by the token owner. - /// - /// # Permissions - /// - Collection issuer - /// - /// # Arguments - /// - `origin`: sender of the transaction - /// - `rmrk_collection_id`: RMRK ID of a collection to which the NFT making use of the resource belongs to. - /// - `nft_id`: ID of the NFT with a resource to be removed. - /// - `resource_id`: ID of the resource to be removed. - #[pallet::call_index(16)] - #[pallet::weight(>::remove_resource())] - pub fn remove_resource( - origin: OriginFor, - rmrk_collection_id: RmrkCollectionId, - nft_id: RmrkNftId, - resource_id: RmrkResourceId, - ) -> DispatchResult { - let sender = ensure_signed(origin.clone())?; - - let collection_id = Self::unique_collection_id(rmrk_collection_id)?; - let collection = - Self::get_typed_nft_collection(collection_id, misc::CollectionType::Regular)?; - collection.check_is_external()?; - - Self::resource_remove(sender, collection_id, nft_id.into(), resource_id)?; - - Self::deposit_event(Event::ResourceRemoval { - nft_id, - resource_id, - }); - Ok(()) - } - } -} - -impl Pallet { - /// Transform one of possible RMRK keys into a byte key with a RMRK scope. - pub fn get_scoped_property_key(rmrk_key: RmrkProperty) -> Result { - let key = rmrk_key.to_key::()?; - - let scoped_key = RMRK_SCOPE - .apply(key) - .map_err(|_| >::RmrkPropertyKeyIsTooLong)?; - - Ok(scoped_key) - } - - /// Form a Unique property, transforming a RMRK key into bytes (without assigning the scope yet) - /// and encoding the value from an arbitrary type into bytes. - pub fn encode_rmrk_property( - rmrk_key: RmrkProperty, - value: &E, - ) -> Result { - let key = rmrk_key.to_key::()?; - - let value = Self::encode_property_value(value)?; - - let property = Property { key, value }; - - Ok(property) - } - - /// Encode property value from an arbitrary type into bytes for storage. - pub fn encode_property_value>( - value: &E, - ) -> Result, DispatchError> { - let value = value - .encode() - .try_into() - .map_err(|_| >::RmrkPropertyValueIsTooLong)?; - - Ok(value) - } - - /// Decode property value from bytes into an arbitrary type. - pub fn decode_property_value>( - vec: &BoundedBytes, - ) -> Result { - vec.decode() - .map_err(|_| >::UnableToDecodeRmrkData.into()) - } - - /// Change the limit of a property value byte vector. - pub fn rebind(vec: &BoundedVec) -> Result, DispatchError> - where - BoundedVec: TryFrom>, - { - vec.rebind() - .map_err(|_| >::RmrkPropertyValueIsTooLong.into()) - } - - /// Initialize a new NFT collection with certain RMRK-scoped properties. - /// - /// See [`init_collection`](pallet_nonfungible::pallet::Pallet::init_collection) for more details. - fn init_collection( - sender: T::CrossAccountId, - data: CreateCollectionData, - properties: impl Iterator, - ) -> Result { - let collection_id = >::init_collection( - sender.clone(), - sender, - data, - up_data_structs::CollectionFlags { - external: true, - ..Default::default() - }, - ); - - if let Err(DispatchError::Arithmetic(_)) = &collection_id { - return Err(>::NoAvailableCollectionId.into()); - } - - >::set_scoped_collection_properties( - collection_id?, - RMRK_SCOPE, - properties, - )?; - - collection_id - } - - /// Mint a new NFT with certain RMRK-scoped properties. Sender must be the collection owner. - /// - /// See [`create_item`](pallet_nonfungible::pallet::Pallet::create_item) for more details. - pub fn create_nft( - sender: &T::CrossAccountId, - owner: &T::CrossAccountId, - collection: &NonfungibleHandle, - properties: impl Iterator, - ) -> Result { - let data = CreateNftExData { - properties: BoundedVec::default(), - owner: owner.clone(), - }; - - let budget = budget::Value::new(NESTING_BUDGET); - - >::create_item(collection, sender, data, &budget)?; - - let nft_id = >::current_token_id(collection.id); - - >::set_scoped_token_properties(collection.id, nft_id, RMRK_SCOPE, properties)?; - - Ok(nft_id) - } - - /// Burn an NFT, along with its nested children, limited by `max_burns`. The sender must be the token owner. - /// - /// See [`burn_recursively`](pallet_nonfungible::pallet::Pallet::burn_recursively) for more details. - fn destroy_nft( - sender: T::CrossAccountId, - collection_id: CollectionId, - token_id: TokenId, - max_burns: u32, - error_if_not_owned: Error, - ) -> DispatchResultWithPostInfo { - let collection = - Self::get_typed_nft_collection(collection_id, misc::CollectionType::Regular)?; - - let token_data = - >::get((collection_id, token_id)).ok_or(>::NoAvailableNftId)?; - - let from = token_data.owner; - - let owner_check_budget = budget::Value::new(NESTING_BUDGET); - - ensure!( - >::check_indirectly_owned( - sender.clone(), - collection_id, - token_id, - None, - &owner_check_budget - )?, - error_if_not_owned, - ); - - let burns_budget = budget::Value::new(max_burns); - let breadth_budget = budget::Value::new(max_burns); - - >::burn_recursively( - &collection, - &from, - token_id, - &burns_budget, - &breadth_budget, - ) - } - - /// Add a sent token pending acceptance to the target owning token as a property. - fn insert_pending_child( - target: (CollectionId, TokenId), - child: (RmrkCollectionId, RmrkNftId), - ) -> DispatchResult { - Self::mutate_pending_children(target, |pending_children| { - pending_children.insert(child); - }) - } - - /// Remove a sent token pending acceptance from the target token's properties. - fn remove_pending_child( - target: (CollectionId, TokenId), - child: (RmrkCollectionId, RmrkNftId), - ) -> DispatchResult { - Self::mutate_pending_children(target, |pending_children| { - pending_children.remove(&child); - }) - } - - /// Apply a mutation to the property of a token containing sent tokens - /// that are currently pending acceptance. - fn mutate_pending_children( - (target_collection_id, target_nft_id): (CollectionId, TokenId), - f: impl FnOnce(&mut PendingChildrenSet), - ) -> DispatchResult { - >::try_mutate_token_aux_property( - target_collection_id, - target_nft_id, - RMRK_SCOPE, - Self::get_scoped_property_key(PendingChildren)?, - |pending_children| -> DispatchResult { - let mut map = match pending_children { - Some(map) => Self::decode_property_value(map)?, - None => PendingChildrenSet::new(), - }; - - f(&mut map); - - *pending_children = Some(Self::encode_property_value(&map)?); - - Ok(()) - }, - ) - } - - /// Get an iterator from a token's property containing tokens sent to it - /// that are currently pending acceptance. - fn iterate_pending_children( - collection_id: CollectionId, - nft_id: TokenId, - ) -> Result, DispatchError> { - let property = >::token_aux_property(( - collection_id, - nft_id, - RMRK_SCOPE, - Self::get_scoped_property_key(PendingChildren)?, - )); - - let pending_children = match property { - Some(map) => Self::decode_property_value(&map)?, - None => PendingChildrenSet::new(), - }; - - Ok(pending_children.into_iter()) - } - - /// Get incremented resource ID from within an NFT's properties and store the new latest ID. - /// Thus, the returned resource ID should be used. - /// - /// Resource IDs are unique only across an NFT. - fn acquire_next_resource_id( - collection_id: CollectionId, - nft_id: TokenId, - ) -> Result { - let resource_id: RmrkResourceId = - Self::get_nft_property_decoded(collection_id, nft_id, NextResourceId)?; - - let next_id = resource_id - .checked_add(1) - .ok_or(>::NoAvailableResourceId)?; - - >::set_scoped_token_property( - collection_id, - nft_id, - RMRK_SCOPE, - Self::encode_rmrk_property(NextResourceId, &next_id)?, - )?; - - Ok(resource_id) - } - - /// Create and add a resource for a regular NFT, mark it as pending if the sender - /// is not the token owner. The sender must be the collection owner. - fn resource_add( - sender: T::AccountId, - collection_id: CollectionId, - nft_id: TokenId, - resource: RmrkResourceTypes, - ) -> Result { - let collection = - Self::get_typed_nft_collection(collection_id, misc::CollectionType::Regular)?; - ensure!(collection.owner == sender, Error::::NoPermission); - - let sender = T::CrossAccountId::from_sub(sender); - let budget = budget::Value::new(NESTING_BUDGET); - - let nft_owner = >::find_topmost_owner(collection_id, nft_id, &budget) - .map_err(Self::map_unique_err_to_proxy)? - .ok_or::(>::NoPermission.into())?; - - let pending = sender != nft_owner; - - let id = Self::acquire_next_resource_id(collection_id, nft_id)?; - - let resource_info = RmrkResourceInfo { - id, - resource, - pending, - pending_removal: false, - }; - - >::try_mutate_token_aux_property( - collection_id, - nft_id, - RMRK_SCOPE, - Self::get_scoped_property_key(ResourceId(id))?, - |value| -> DispatchResult { - *value = Some(Self::encode_property_value(&resource_info)?); - - Ok(()) - }, - )?; - - Ok(id) - } - - /// Designate a resource for erasure from an NFT, and remove it if the sender is the token owner. - /// The sender must be the collection owner. - fn resource_remove( - sender: T::AccountId, - collection_id: CollectionId, - nft_id: TokenId, - resource_id: RmrkResourceId, - ) -> DispatchResult { - let collection = - Self::get_typed_nft_collection(collection_id, misc::CollectionType::Regular)?; - ensure!(collection.owner == sender, Error::::NoPermission); - - let resource_id_key = Self::get_scoped_property_key(ResourceId(resource_id))?; - - let resource = >::token_aux_property(( - collection_id, - nft_id, - RMRK_SCOPE, - resource_id_key.clone(), - )) - .ok_or(>::ResourceDoesntExist)?; - - let resource_info: RmrkResourceInfo = Self::decode_property_value(&resource)?; - - let budget = up_data_structs::budget::Value::new(NESTING_BUDGET); - let topmost_owner = - >::find_topmost_owner(collection_id, nft_id, &budget)? - .ok_or::(>::NoPermission.into())?; - - let sender = T::CrossAccountId::from_sub(sender); - if topmost_owner == sender { - >::remove_token_aux_property( - collection_id, - nft_id, - RMRK_SCOPE, - Self::get_scoped_property_key(ResourceId(resource_id))?, - ); - - if let RmrkResourceTypes::Composable(resource) = resource_info.resource { - let base_id = resource.base; - - Self::remove_associated_base_id(collection_id, nft_id, base_id)?; - } - } else { - Self::try_mutate_resource_info(collection_id, nft_id, resource_id, |res| { - res.pending_removal = true; - - Ok(()) - })?; - } - - Ok(()) - } - - /// Remove a Base ID from an NFT if they are associated. - /// The Base itself is deleted if the number of associated NFTs reaches 0. - fn remove_associated_base_id( - collection_id: CollectionId, - nft_id: TokenId, - base_id: RmrkBaseId, - ) -> DispatchResult { - >::try_mutate_token_aux_property( - collection_id, - nft_id, - RMRK_SCOPE, - Self::get_scoped_property_key(AssociatedBases)?, - |value| -> DispatchResult { - let mut bases: BasesMap = match value { - Some(value) => Self::decode_property_value(value)?, - None => BasesMap::new(), - }; - - let remaining = bases.get(&base_id); - - if let Some(remaining) = remaining { - if let Some(0) | None = remaining.checked_sub(1) { - bases.remove(&base_id); - } - } - - *value = Some(Self::encode_property_value(&bases)?); - Ok(()) - }, - ) - } - - /// Apply a mutation to a resource stored in the token properties of an NFT. - fn try_mutate_resource_info( - collection_id: CollectionId, - nft_id: TokenId, - resource_id: RmrkResourceId, - f: impl FnOnce(&mut RmrkResourceInfo) -> DispatchResult, - ) -> DispatchResult { - >::try_mutate_token_aux_property( - collection_id, - nft_id, - RMRK_SCOPE, - Self::get_scoped_property_key(ResourceId(resource_id))?, - |value| match value { - Some(value) => { - let mut resource_info: RmrkResourceInfo = Self::decode_property_value(value)?; - - f(&mut resource_info)?; - - *value = Self::encode_property_value(&resource_info)?; - - Ok(()) - } - None => Err(>::ResourceDoesntExist.into()), - }, - ) - } - - /// Change the owner of an NFT collection, ensuring that the sender is the current owner. - fn change_collection_owner( - collection_id: CollectionId, - collection_type: misc::CollectionType, - sender: T::AccountId, - new_owner: T::AccountId, - ) -> DispatchResult { - let collection = Self::get_typed_nft_collection(collection_id, collection_type)?; - Self::check_collection_owner(&collection, &T::CrossAccountId::from_sub(sender))?; - - let mut collection = collection.into_inner(); - - collection.owner = new_owner; - collection.save() - } - - /// Ensure that an account is the collection owner/issuer, return an error if not. - pub fn check_collection_owner( - collection: &NonfungibleHandle, - account: &T::CrossAccountId, - ) -> DispatchResult { - collection - .check_is_owner(account) - .map_err(Self::map_unique_err_to_proxy) - } - - /// Get the latest yet-unused RMRK collection index from the storage. - pub fn last_collection_idx() -> RmrkCollectionId { - >::get() - } - - /// Get a mapping from a RMRK collection ID to its corresponding Unique collection ID. - pub fn unique_collection_id( - rmrk_collection_id: RmrkCollectionId, - ) -> Result { - >::try_get(rmrk_collection_id) - .map_err(|_| >::CollectionUnknown.into()) - } - - /// Get a mapping from a Unique collection ID to its RMRK collection ID counterpart, if it exists. - pub fn rmrk_collection_id( - unique_collection_id: CollectionId, - ) -> Result { - Self::get_collection_property_decoded(unique_collection_id, RmrkInternalCollectionId) - } - - /// Fetch a Unique NFT collection. - pub fn get_nft_collection( - collection_id: CollectionId, - ) -> Result, DispatchError> { - let collection = >::try_get(collection_id) - .map_err(|_| >::CollectionUnknown)?; - - match collection.mode { - CollectionMode::NFT => Ok(NonfungibleHandle::cast(collection)), - _ => Err(>::CollectionUnknown.into()), - } - } - - /// Check if an NFT collection with such an ID exists. - pub fn collection_exists(collection_id: CollectionId) -> bool { - >::try_get(collection_id).is_ok() - } - - /// Fetch and decode a RMRK-scoped collection property value in bytes. - pub fn get_collection_property( - collection_id: CollectionId, - key: RmrkProperty, - ) -> Result { - let collection_property = >::collection_properties(collection_id) - .get(&Self::get_scoped_property_key(key)?) - .ok_or(>::CollectionUnknown)? - .clone(); - - Ok(collection_property) - } - - /// Fetch a RMRK-scoped collection property and decode it from bytes into an appropriate type. - pub fn get_collection_property_decoded( - collection_id: CollectionId, - key: RmrkProperty, - ) -> Result { - Self::decode_property_value(&Self::get_collection_property(collection_id, key)?) - } - - /// Get the type of a collection stored as a scoped property. - /// - /// RMRK Core proxy differentiates between regular collections as well as RMRK Bases as collections. - pub fn get_collection_type( - collection_id: CollectionId, - ) -> Result { - Self::get_collection_property_decoded(collection_id, CollectionType).map_err(|err| { - if err != >::CollectionUnknown.into() { - >::CorruptedCollectionType.into() - } else { - err - } - }) - } - - /// Ensure that the type of the collection equals the provided type, - /// otherwise return an error. - pub fn ensure_collection_type( - collection_id: CollectionId, - collection_type: misc::CollectionType, - ) -> DispatchResult { - let actual_type = Self::get_collection_type(collection_id)?; - ensure!( - actual_type == collection_type, - >::NoPermission - ); - - Ok(()) - } - - /// Fetch an NFT collection, but make sure it has the appropriate type. - pub fn get_typed_nft_collection( - collection_id: CollectionId, - collection_type: misc::CollectionType, - ) -> Result, DispatchError> { - Self::ensure_collection_type(collection_id, collection_type)?; - - Self::get_nft_collection(collection_id) - } - - /// Same as [`get_typed_nft_collection`](crate::pallet::Pallet::get_typed_nft_collection), - /// but also return the Unique collection ID. - pub fn get_typed_nft_collection_mapped( - rmrk_collection_id: RmrkCollectionId, - collection_type: misc::CollectionType, - ) -> Result<(NonfungibleHandle, CollectionId), DispatchError> { - let unique_collection_id = match collection_type { - misc::CollectionType::Regular => Self::unique_collection_id(rmrk_collection_id)?, - _ => rmrk_collection_id.into(), - }; - - let collection = Self::get_typed_nft_collection(unique_collection_id, collection_type)?; - - Ok((collection, unique_collection_id)) - } - - /// Fetch and decode a RMRK-scoped NFT property value in bytes. - pub fn get_nft_property( - collection_id: CollectionId, - nft_id: TokenId, - key: RmrkProperty, - ) -> Result { - let nft_property = >::token_properties((collection_id, nft_id)) - .get(&Self::get_scoped_property_key(key)?) - .ok_or(>::RmrkPropertyIsNotFound)? - .clone(); - - Ok(nft_property) - } - - /// Fetch a RMRK-scoped NFT property and decode it from bytes into an appropriate type. - pub fn get_nft_property_decoded( - collection_id: CollectionId, - nft_id: TokenId, - key: RmrkProperty, - ) -> Result { - Self::decode_property_value(&Self::get_nft_property(collection_id, nft_id, key)?) - } - - /// Check that an NFT exists. - pub fn nft_exists(collection_id: CollectionId, nft_id: TokenId) -> bool { - >::contains_key((collection_id, nft_id)) - } - - /// Get the type of an NFT stored as a scoped property. - /// - /// RMRK Core proxy differentiates between regular NFTs, and RMRK Parts and Themes. - pub fn get_nft_type( - collection_id: CollectionId, - token_id: TokenId, - ) -> Result { - Self::get_nft_property_decoded(collection_id, token_id, TokenType) - .map_err(|_| >::NoAvailableNftId.into()) - } - - /// Ensure that the type of the NFT equals the provided type, otherwise return an error. - pub fn ensure_nft_type( - collection_id: CollectionId, - token_id: TokenId, - nft_type: NftType, - ) -> DispatchResult { - let actual_type = Self::get_nft_type(collection_id, token_id)?; - ensure!(actual_type == nft_type, >::NoPermission); - - Ok(()) - } - - /// Ensure that an account is the owner of the token, either directly - /// or at the top of the nesting hierarchy; return an error if it is not. - pub fn ensure_nft_owner( - collection_id: CollectionId, - token_id: TokenId, - possible_owner: &T::CrossAccountId, - nesting_budget: &dyn budget::Budget, - ) -> DispatchResult { - let is_owned = >::check_indirectly_owned( - possible_owner.clone(), - collection_id, - token_id, - None, - nesting_budget, - ) - .map_err(Self::map_unique_err_to_proxy)?; - - ensure!(is_owned, >::NoPermission); - - Ok(()) - } - - /// Fetch non-scoped properties of a collection or a token that match the filter keys supplied, - /// or, if None are provided, return all non-scoped properties. - pub fn filter_user_properties( - collection_id: CollectionId, - token_id: Option, - filter_keys: Option>, - mapper: Mapper, - ) -> Result, DispatchError> - where - Key: TryFrom + AsRef<[u8]>, - Value: Decode + Default, - Mapper: Fn(Key, Value) -> R, - { - filter_keys - .map(|keys| { - let properties = keys - .into_iter() - .filter_map(|key| { - let key: Key = key.try_into().ok()?; - - let value = match token_id { - Some(token_id) => Self::get_nft_property_decoded( - collection_id, - token_id, - UserProperty(key.as_ref()), - ), - None => Self::get_collection_property_decoded( - collection_id, - UserProperty(key.as_ref()), - ), - } - .ok()?; - - Some(mapper(key, value)) - }) - .collect(); - - Ok(properties) - }) - .unwrap_or_else(|| { - let properties = - Self::iterate_user_properties(collection_id, token_id, mapper)?.collect(); - - Ok(properties) - }) - } - - /// Get all non-scoped properties from a collection or a token, and apply some transformation, - /// supplied by `mapper`, to each key-value pair. - pub fn iterate_user_properties( - collection_id: CollectionId, - token_id: Option, - mapper: Mapper, - ) -> Result, DispatchError> - where - Key: TryFrom + AsRef<[u8]>, - Value: Decode + Default, - Mapper: Fn(Key, Value) -> R, - { - let properties = match token_id { - Some(token_id) => >::token_properties((collection_id, token_id)), - None => >::collection_properties(collection_id), - }; - - let properties = properties.into_iter().filter_map(move |(key, value)| { - let key = strip_key_prefix(&key, USER_PROPERTY_PREFIX)?; - - let key: Key = key.to_vec().try_into().ok()?; - let value: Value = value.decode().ok()?; - - Some(mapper(key, value)) - }); - - Ok(properties) - } - - /// Match Unique errors to RMRK's own and return the RMRK error if a match is successful. - fn map_unique_err_to_proxy(err: DispatchError) -> DispatchError { - map_unique_err_to_proxy! { - match err { - CommonError::NoPermission => NoPermission, - CommonError::CollectionTokenLimitExceeded => CollectionFullOrLocked, - CommonError::PublicMintingNotAllowed => NoPermission, - CommonError::TokenNotFound => NoAvailableNftId, - CommonError::ApprovedValueTooLow => NoPermission, - CommonError::CantDestroyNotEmptyCollection => CollectionNotEmpty, - StructureError::TokenNotFound => NoAvailableNftId, - StructureError::OuroborosDetected => CannotSendToDescendentOrSelf, - } - } - } -} --- a/pallets/proxy-rmrk-core/src/misc.rs +++ /dev/null @@ -1,84 +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 . - -//! Miscellaneous helpers and utilities used by the proxy pallet. - -use super::*; -use codec::{Encode, Decode, Error}; - -/// Match an error to a provided pattern matcher and get -/// the corresponding error of another type if a match is successful. -#[macro_export] -macro_rules! map_unique_err_to_proxy { - (match $err:ident { $($unique_err_ty:ident :: $unique_err:ident => $proxy_err:ident),+ $(,)? }) => { - $( - if $err == <$unique_err_ty>::$unique_err.into() { - return >::$proxy_err.into() - } else - )+ { - $err - } - }; -} - -/// Interface to decode some serialized bytes into an arbitrary type `T`, -/// preferably if these bytes were originally encoded from `T`. -pub trait RmrkDecode { - /// Try to decode self into an arbitrary type `T`. - fn decode(&self) -> Result; -} - -impl RmrkDecode for BoundedVec { - fn decode(&self) -> Result { - let mut value = self.as_slice(); - - T::decode(&mut value) - } -} - -/// Interface to "rebind" - change the limit of a bounded byte vector. -pub trait RmrkRebind { - /// Try to change the limit of a bounded byte vector. - fn rebind(&self) -> Result, Error>; -} - -impl RmrkRebind for BoundedVec -where - BoundedVec: TryFrom>, -{ - fn rebind(&self) -> Result, Error> { - BoundedVec::::try_from(self.clone().into_inner()) - .map_err(|_| "BoundedVec exceeds its limit".into()) - } -} - -/// RMRK Base shares functionality with a regular collection, and is thus -/// stored as one, but they are used for different purposes and need to be differentiated. -#[derive(Encode, Decode, PartialEq, Eq)] -pub enum CollectionType { - Regular, - Base, -} - -/// RMRK Base, being stored as a collection, can have different kinds of tokens, -/// all except the `Regular` type, which is attributed to `Regular` collection. -#[derive(Encode, Decode, PartialEq, Eq)] -pub enum NftType { - Regular, - FixedPart, - SlotPart, - Theme, -} --- a/pallets/proxy-rmrk-core/src/property.rs +++ /dev/null @@ -1,121 +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 . - -//! Details of storing and handling RMRK properties. - -use super::*; -use up_data_structs::PropertyScope; -use core::convert::AsRef; - -/// Property prefix for storing resources. -pub const RESOURCE_ID_PREFIX: &str = "rsid-"; -/// Property prefix for storing custom user-defined properties. -pub const USER_PROPERTY_PREFIX: &str = "userprop-"; -/// Property scope for RMRK, used to signify that this property -/// was created and is used by RMRK. -pub const RMRK_SCOPE: PropertyScope = PropertyScope::Rmrk; - -/// Predefined RMRK property keys for storage of RMRK data format on the Unique chain. -pub enum RmrkProperty<'r> { - Metadata, - CollectionType, - RmrkInternalCollectionId, - TokenType, - Transferable, - RoyaltyInfo, - Equipped, - ResourcePriorities, - NextResourceId, - ResourceId(RmrkResourceId), - PendingNftAccept, - PendingChildren, - AssociatedBases, - Parts, - Base, - Src, - EquippedNft, - BaseType, - ExternalPartId, - EquippableList, - ZIndex, - ThemeName, - ThemeInherit, - UserProperty(&'r [u8]), -} - -impl<'r> RmrkProperty<'r> { - /// Convert a predefined RMRK property key enum into string bytes. - pub fn to_key(self) -> Result> { - fn get_bytes>(container: &T) -> &[u8] { - container.as_ref() - } - - macro_rules! key { - ($($component:expr),+) => { - PropertyKey::try_from([$(key!(@ &$component)),+].concat()) - .map_err(|_| >::RmrkPropertyKeyIsTooLong) - }; - - (@ $key:expr) => { - get_bytes($key) - }; - } - - match self { - Self::Metadata => key!("metadata"), - Self::CollectionType => key!("collection-type"), - Self::RmrkInternalCollectionId => key!("internal-id"), - Self::TokenType => key!("token-type"), - Self::Transferable => key!("transferable"), - Self::RoyaltyInfo => key!("royalty-info"), - Self::Equipped => key!("equipped"), - Self::ResourcePriorities => key!("resource-priorities"), - Self::NextResourceId => key!("next-resource-id"), - Self::ResourceId(id) => key!(RESOURCE_ID_PREFIX, id.to_le_bytes()), - Self::PendingNftAccept => key!("pending-nft-accept"), - Self::PendingChildren => key!("pending-children"), - Self::AssociatedBases => key!("assoc-bases"), - Self::Parts => key!("parts"), - Self::Base => key!("base"), - Self::Src => key!("src"), - Self::EquippedNft => key!("equipped-nft"), - Self::BaseType => key!("base-type"), - Self::ExternalPartId => key!("ext-part-id"), - Self::EquippableList => key!("equippable-list"), - Self::ZIndex => key!("z-index"), - Self::ThemeName => key!("theme-name"), - Self::ThemeInherit => key!("theme-inherit"), - Self::UserProperty(name) => key!(USER_PROPERTY_PREFIX, name), - } - } -} - -/// Strip a property key of its prefix and RMRK scope. -pub fn strip_key_prefix(key: &PropertyKey, prefix: &str) -> Option { - let key_prefix = PropertyKey::try_from(prefix.as_bytes().to_vec()).ok()?; - let key_prefix = RMRK_SCOPE.apply(key_prefix).ok()?; - - key.as_slice() - .strip_prefix(key_prefix.as_slice())? - .to_vec() - .try_into() - .ok() -} - -/// Check that the key has the prefix. -pub fn is_valid_key_prefix(key: &PropertyKey, prefix: &str) -> bool { - strip_key_prefix(key, prefix).is_some() -} --- a/pallets/proxy-rmrk-core/src/rpc.rs +++ /dev/null @@ -1,293 +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 . - -//! Realizations of RMRK RPCs (remote procedure calls) related to the Core pallet. - -use super::*; - -/// Get the latest created collection ID. -pub fn last_collection_idx() -> Result { - Ok(>::last_collection_idx()) -} - -/// Get collection info by ID. -pub fn collection_by_id( - collection_id: RmrkCollectionId, -) -> Result>, DispatchError> { - let (collection, collection_id) = match >::get_typed_nft_collection_mapped( - collection_id, - misc::CollectionType::Regular, - ) { - Ok(c) => c, - Err(_) => return Ok(None), - }; - - let nfts_count = collection.total_supply(); - - Ok(Some(RmrkCollectionInfo { - issuer: collection.owner.clone(), - metadata: >::get_collection_property_decoded( - collection_id, - RmrkProperty::Metadata, - )?, - max: collection.limits.token_limit, - symbol: >::rebind(&collection.token_prefix)?, - nfts_count, - })) -} - -/// Get NFT info by collection and NFT IDs. -pub fn nft_by_id( - collection_id: RmrkCollectionId, - nft_by_id: RmrkNftId, -) -> Result>, DispatchError> { - let (collection, collection_id) = match >::get_typed_nft_collection_mapped( - collection_id, - misc::CollectionType::Regular, - ) { - Ok(c) => c, - Err(_) => return Ok(None), - }; - - let nft_id = TokenId(nft_by_id); - if !>::nft_exists(collection_id, nft_id) { - return Ok(None); - } - - let owner = match collection.token_owner(nft_id) { - Ok(owner) => match T::CrossTokenAddressMapping::address_to_token(&owner) { - Some((col, tok)) => { - let rmrk_collection = >::rmrk_collection_id(col)?; - - RmrkAccountIdOrCollectionNftTuple::CollectionAndNftTuple(rmrk_collection, tok.0) - } - None => RmrkAccountIdOrCollectionNftTuple::AccountId(owner.as_sub().clone()), - }, - _ => return Ok(None), - }; - - Ok(Some(RmrkInstanceInfo { - owner: owner, - royalty: >::get_nft_property_decoded( - collection_id, - nft_id, - RmrkProperty::RoyaltyInfo, - )?, - metadata: >::get_nft_property_decoded( - collection_id, - nft_id, - RmrkProperty::Metadata, - )?, - equipped: >::get_nft_property_decoded( - collection_id, - nft_id, - RmrkProperty::Equipped, - )?, - pending: >::get_nft_property_decoded( - collection_id, - nft_id, - RmrkProperty::PendingNftAccept, - )?, - })) -} - -/// Get tokens owned by an account in a collection. -pub fn account_tokens( - account_id: T::AccountId, - collection_id: RmrkCollectionId, -) -> Result, DispatchError> { - let cross_account_id = CrossAccountId::from_sub(account_id); - - let (collection, collection_id) = match >::get_typed_nft_collection_mapped( - collection_id, - misc::CollectionType::Regular, - ) { - Ok(c) => c, - Err(_) => return Ok(Vec::new()), - }; - - let tokens = collection - .account_tokens(cross_account_id) - .into_iter() - .filter(|token| { - let is_pending = >::get_nft_property_decoded( - collection_id, - *token, - RmrkProperty::PendingNftAccept, - ) - .unwrap_or(true); - - !is_pending - }) - .map(|token| token.0) - .collect(); - - Ok(tokens) -} - -/// Get tokens nested in an NFT - its direct children (not the children's children). -pub fn nft_children( - collection_id: RmrkCollectionId, - nft_id: RmrkNftId, -) -> Result, DispatchError> { - let collection_id = match >::unique_collection_id(collection_id) { - Ok(id) => id, - Err(_) => return Ok(Vec::new()), - }; - let nft_id = TokenId(nft_id); - if !>::nft_exists(collection_id, nft_id) { - return Ok(Vec::new()); - } - - Ok( - pallet_nonfungible::TokenChildren::::iter_prefix((collection_id, nft_id)) - .filter_map(|((child_collection, child_token), _)| { - let rmrk_child_collection = - >::rmrk_collection_id(child_collection).ok()?; - - Some(RmrkNftChild { - collection_id: rmrk_child_collection, - nft_id: child_token.0, - }) - }) - .chain( - >::iterate_pending_children(collection_id, nft_id)?.map( - |(child_collection, child_nft_id)| RmrkNftChild { - collection_id: child_collection, - nft_id: child_nft_id, - }, - ), - ) - .collect(), - ) -} - -/// Get collection properties, created by the user - not the proxy-specific properties. -pub fn collection_properties( - collection_id: RmrkCollectionId, - filter_keys: Option>, -) -> Result, DispatchError> { - let collection_id = match >::unique_collection_id(collection_id) { - Ok(id) => id, - Err(_) => return Ok(Vec::new()), - }; - if >::ensure_collection_type(collection_id, misc::CollectionType::Regular).is_err() { - return Ok(Vec::new()); - } - - let properties = >::filter_user_properties( - collection_id, - /* token_id = */ None, - filter_keys, - |key, value| RmrkPropertyInfo { key, value }, - )?; - - Ok(properties) -} - -/// Get NFT properties, created by the user - not the proxy-specific properties. -pub fn nft_properties( - collection_id: RmrkCollectionId, - nft_id: RmrkNftId, - filter_keys: Option>, -) -> Result, DispatchError> { - let collection_id = match >::unique_collection_id(collection_id) { - Ok(id) => id, - Err(_) => return Ok(Vec::new()), - }; - let token_id = TokenId(nft_id); - - if >::ensure_nft_type(collection_id, token_id, NftType::Regular).is_err() { - return Ok(Vec::new()); - } - - let properties = >::filter_user_properties( - collection_id, - Some(token_id), - filter_keys, - |key, value| RmrkPropertyInfo { key, value }, - )?; - - Ok(properties) -} - -/// Get full information on each resource of an NFT, including pending. -pub fn nft_resources( - collection_id: RmrkCollectionId, - nft_id: RmrkNftId, -) -> Result, DispatchError> { - let collection_id = match >::unique_collection_id(collection_id) { - Ok(id) => id, - Err(_) => return Ok(Vec::new()), - }; - if >::ensure_collection_type(collection_id, misc::CollectionType::Regular).is_err() { - return Ok(Vec::new()); - } - - let nft_id = TokenId(nft_id); - if >::ensure_nft_type(collection_id, nft_id, NftType::Regular).is_err() { - return Ok(Vec::new()); - } - - let resources = >::iterate_token_aux_properties( - collection_id, - nft_id, - PropertyScope::Rmrk, - ) - .filter_map(|(key, value)| { - if !is_valid_key_prefix(&key, RESOURCE_ID_PREFIX) { - return None; - } - - let resource_info: RmrkResourceInfo = >::decode_property_value(&value).ok()?; - - Some(resource_info) - }) - .collect(); - - Ok(resources) -} - -/// Get the priority of a resource in an NFT. -pub fn nft_resource_priority( - collection_id: RmrkCollectionId, - nft_id: RmrkNftId, - resource_id: RmrkResourceId, -) -> Result, DispatchError> { - let collection_id = match >::unique_collection_id(collection_id) { - Ok(id) => id, - Err(_) => return Ok(None), - }; - if >::ensure_collection_type(collection_id, misc::CollectionType::Regular).is_err() { - return Ok(None); - } - - let nft_id = TokenId(nft_id); - if >::ensure_nft_type(collection_id, nft_id, NftType::Regular).is_err() { - return Ok(None); - } - - let priorities: Vec<_> = >::get_nft_property_decoded( - collection_id, - nft_id, - RmrkProperty::ResourcePriorities, - )?; - Ok(priorities - .into_iter() - .enumerate() - .find(|(_, id)| *id == resource_id) - .map(|(priority, _): (usize, RmrkResourceId)| priority as u32)) -} --- a/pallets/proxy-rmrk-core/src/weights.rs +++ /dev/null @@ -1,480 +0,0 @@ -// Template adopted from https://github.com/paritytech/substrate/blob/master/.maintain/frame-weight-template.hbs - -//! Autogenerated weights for pallet_proxy_rmrk_core -//! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2022-08-15, STEPS: `50`, REPEAT: 80, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! EXECUTION: None, WASM-EXECUTION: Compiled, CHAIN: None, DB CACHE: 1024 - -// Executed Command: -// target/release/unique-collator -// benchmark -// pallet -// --pallet -// pallet-proxy-rmrk-core -// --wasm-execution -// compiled -// --extrinsic -// * -// --template -// .maintain/frame-weight-template.hbs -// --steps=50 -// --repeat=80 -// --heap-pages=4096 -// --output=./pallets/proxy-rmrk-core/src/weights.rs - -#![cfg_attr(rustfmt, rustfmt_skip)] -#![allow(unused_parens)] -#![allow(unused_imports)] -#![allow(clippy::unnecessary_cast)] - -use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; -use sp_std::marker::PhantomData; - -/// Weight functions needed for pallet_proxy_rmrk_core. -pub trait WeightInfo { - fn create_collection() -> Weight; - fn destroy_collection() -> Weight; - fn change_collection_issuer() -> Weight; - fn lock_collection() -> Weight; - fn mint_nft(b: u32, ) -> Weight; - fn burn_nft(b: u32, ) -> Weight; - fn send() -> Weight; - fn accept_nft() -> Weight; - fn reject_nft() -> Weight; - fn set_property() -> Weight; - fn set_priority() -> Weight; - fn add_basic_resource() -> Weight; - fn add_composable_resource() -> Weight; - fn add_slot_resource() -> Weight; - fn remove_resource() -> Weight; - fn accept_resource() -> Weight; - fn accept_resource_removal() -> Weight; -} - -/// Weights for pallet_proxy_rmrk_core using the Substrate node and recommended hardware. -pub struct SubstrateWeight(PhantomData); -impl WeightInfo for SubstrateWeight { - // Storage: Common CreatedCollectionCount (r:1 w:1) - // Storage: Common DestroyedCollectionCount (r:1 w:0) - // Storage: System Account (r:2 w:2) - // Storage: RmrkCore CollectionIndex (r:1 w:1) - // Storage: Common CollectionPropertyPermissions (r:0 w:1) - // Storage: Common CollectionProperties (r:0 w:1) - // Storage: Common CollectionById (r:0 w:1) - // Storage: RmrkCore UniqueCollectionId (r:0 w:1) - fn create_collection() -> Weight { - Weight::from_ref_time(49_754_000) - .saturating_add(T::DbWeight::get().reads(5 as u64)) - .saturating_add(T::DbWeight::get().writes(8 as u64)) - } - // Storage: RmrkCore UniqueCollectionId (r:1 w:0) - // Storage: Common CollectionProperties (r:1 w:1) - // Storage: Common CollectionById (r:1 w:1) - // Storage: Nonfungible TokenData (r:1 w:0) - // Storage: Common DestroyedCollectionCount (r:1 w:1) - // Storage: Nonfungible TokensMinted (r:0 w:1) - // Storage: Nonfungible TokensBurnt (r:0 w:1) - // Storage: Common AdminAmount (r:0 w:1) - fn destroy_collection() -> Weight { - Weight::from_ref_time(48_588_000) - .saturating_add(T::DbWeight::get().reads(5 as u64)) - .saturating_add(T::DbWeight::get().writes(6 as u64)) - } - // Storage: RmrkCore UniqueCollectionId (r:1 w:0) - // Storage: Common CollectionById (r:1 w:1) - // Storage: Common CollectionProperties (r:1 w:0) - fn change_collection_issuer() -> Weight { - Weight::from_ref_time(25_054_000) - .saturating_add(T::DbWeight::get().reads(3 as u64)) - .saturating_add(T::DbWeight::get().writes(1 as u64)) - } - // Storage: RmrkCore UniqueCollectionId (r:1 w:0) - // Storage: Common CollectionProperties (r:1 w:0) - // Storage: Common CollectionById (r:1 w:1) - // Storage: Nonfungible TokensMinted (r:1 w:0) - // Storage: Nonfungible TokensBurnt (r:1 w:0) - fn lock_collection() -> Weight { - Weight::from_ref_time(26_483_000) - .saturating_add(T::DbWeight::get().reads(5 as u64)) - .saturating_add(T::DbWeight::get().writes(1 as u64)) - } - // Storage: RmrkCore UniqueCollectionId (r:1 w:0) - // Storage: Common CollectionProperties (r:1 w:0) - // Storage: Common CollectionById (r:1 w:0) - // Storage: Nonfungible TokensMinted (r:1 w:1) - // Storage: Nonfungible AccountBalance (r:1 w:1) - // Storage: Nonfungible TokenProperties (r:1 w:1) - // Storage: Nonfungible TokenData (r:0 w:1) - // Storage: Nonfungible Owned (r:0 w:1) - // Storage: Nonfungible TokenAuxProperties (r:2 w:2) - fn mint_nft(b: u32, ) -> Weight { - Weight::from_ref_time(62_419_000) - // Standard Error: 7_000 - .saturating_add(Weight::from_ref_time(12_325_000).saturating_mul(b as u64)) - .saturating_add(T::DbWeight::get().reads(6 as u64)) - .saturating_add(T::DbWeight::get().reads((1 as u64).saturating_mul(b as u64))) - .saturating_add(T::DbWeight::get().writes(5 as u64)) - .saturating_add(T::DbWeight::get().writes((1 as u64).saturating_mul(b as u64))) - } - // Storage: RmrkCore UniqueCollectionId (r:1 w:0) - // Storage: Common CollectionProperties (r:1 w:0) - // Storage: Common CollectionById (r:1 w:0) - // Storage: Nonfungible TokenData (r:1 w:1) - // Storage: Nonfungible TokenChildren (r:1 w:0) - // Storage: Nonfungible TokensBurnt (r:1 w:1) - // Storage: Nonfungible AccountBalance (r:1 w:1) - // Storage: Nonfungible Allowance (r:1 w:0) - // Storage: Nonfungible Owned (r:0 w:1) - // Storage: Nonfungible TokenProperties (r:0 w:1) - fn burn_nft(b: u32, ) -> Weight { - (Weight::from_ref_time(0)) - // Standard Error: 1_488_000 - .saturating_add(Weight::from_ref_time(298_367_000).saturating_mul(b as u64)) - .saturating_add(T::DbWeight::get().reads(9 as u64)) - .saturating_add(T::DbWeight::get().reads((4 as u64).saturating_mul(b as u64))) - .saturating_add(T::DbWeight::get().writes(6 as u64)) - .saturating_add(T::DbWeight::get().writes((4 as u64).saturating_mul(b as u64))) - } - // Storage: RmrkCore UniqueCollectionId (r:1 w:0) - // Storage: Common CollectionProperties (r:1 w:0) - // Storage: Common CollectionById (r:1 w:0) - // Storage: Nonfungible TokenData (r:5 w:1) - // Storage: Nonfungible TokenProperties (r:1 w:0) - // Storage: Nonfungible AccountBalance (r:2 w:2) - // Storage: Nonfungible Allowance (r:1 w:0) - // Storage: Nonfungible TokenChildren (r:0 w:1) - // Storage: Nonfungible Owned (r:0 w:2) - fn send() -> Weight { - Weight::from_ref_time(81_942_000) - .saturating_add(T::DbWeight::get().reads(12 as u64)) - .saturating_add(T::DbWeight::get().writes(6 as u64)) - } - // Storage: RmrkCore UniqueCollectionId (r:2 w:0) - // Storage: Common CollectionProperties (r:1 w:0) - // Storage: Common CollectionById (r:2 w:0) - // Storage: Nonfungible TokenData (r:6 w:1) - // Storage: Nonfungible AccountBalance (r:2 w:2) - // Storage: Nonfungible Allowance (r:1 w:0) - // Storage: Nonfungible TokenProperties (r:1 w:1) - // Storage: Nonfungible TokenAuxProperties (r:1 w:1) - // Storage: Nonfungible TokenChildren (r:0 w:1) - // Storage: Nonfungible Owned (r:0 w:2) - fn accept_nft() -> Weight { - Weight::from_ref_time(97_925_000) - .saturating_add(T::DbWeight::get().reads(16 as u64)) - .saturating_add(T::DbWeight::get().writes(8 as u64)) - } - // Storage: RmrkCore UniqueCollectionId (r:1 w:0) - // Storage: Common CollectionProperties (r:1 w:0) - // Storage: Common CollectionById (r:1 w:0) - // Storage: Nonfungible TokenData (r:5 w:5) - // Storage: Nonfungible TokenProperties (r:1 w:5) - // Storage: Nonfungible TokenAuxProperties (r:1 w:1) - // Storage: Nonfungible TokenChildren (r:9 w:4) - // Storage: Nonfungible TokensBurnt (r:1 w:1) - // Storage: Nonfungible AccountBalance (r:5 w:5) - // Storage: Nonfungible Allowance (r:5 w:0) - // Storage: Nonfungible Owned (r:0 w:5) - fn reject_nft() -> Weight { - Weight::from_ref_time(277_794_000) - .saturating_add(T::DbWeight::get().reads(30 as u64)) - .saturating_add(T::DbWeight::get().writes(26 as u64)) - } - // Storage: RmrkCore UniqueCollectionId (r:1 w:0) - // Storage: Common CollectionProperties (r:1 w:0) - // Storage: Common CollectionById (r:1 w:0) - // Storage: Nonfungible TokenProperties (r:1 w:1) - // Storage: Nonfungible TokenData (r:5 w:0) - fn set_property() -> Weight { - Weight::from_ref_time(54_657_000) - .saturating_add(T::DbWeight::get().reads(9 as u64)) - .saturating_add(T::DbWeight::get().writes(1 as u64)) - } - // Storage: RmrkCore UniqueCollectionId (r:1 w:0) - // Storage: Common CollectionProperties (r:1 w:0) - // Storage: Common CollectionById (r:1 w:0) - // Storage: Nonfungible TokenProperties (r:1 w:1) - // Storage: Nonfungible TokenData (r:5 w:0) - fn set_priority() -> Weight { - Weight::from_ref_time(55_056_000) - .saturating_add(T::DbWeight::get().reads(9 as u64)) - .saturating_add(T::DbWeight::get().writes(1 as u64)) - } - // Storage: RmrkCore UniqueCollectionId (r:1 w:0) - // Storage: Common CollectionProperties (r:1 w:0) - // Storage: Common CollectionById (r:1 w:0) - // Storage: Nonfungible TokenData (r:5 w:0) - // Storage: Nonfungible TokenProperties (r:1 w:1) - // Storage: Nonfungible TokenAuxProperties (r:1 w:1) - fn add_basic_resource() -> Weight { - Weight::from_ref_time(61_673_000) - .saturating_add(T::DbWeight::get().reads(10 as u64)) - .saturating_add(T::DbWeight::get().writes(2 as u64)) - } - // Storage: RmrkCore UniqueCollectionId (r:1 w:0) - // Storage: Common CollectionProperties (r:1 w:0) - // Storage: Common CollectionById (r:1 w:0) - // Storage: Nonfungible TokenData (r:5 w:0) - // Storage: Nonfungible TokenProperties (r:1 w:1) - // Storage: Nonfungible TokenAuxProperties (r:2 w:2) - fn add_composable_resource() -> Weight { - Weight::from_ref_time(67_125_000) - .saturating_add(T::DbWeight::get().reads(11 as u64)) - .saturating_add(T::DbWeight::get().writes(3 as u64)) - } - // Storage: RmrkCore UniqueCollectionId (r:1 w:0) - // Storage: Common CollectionProperties (r:1 w:0) - // Storage: Common CollectionById (r:1 w:0) - // Storage: Nonfungible TokenData (r:5 w:0) - // Storage: Nonfungible TokenProperties (r:1 w:1) - // Storage: Nonfungible TokenAuxProperties (r:1 w:1) - fn add_slot_resource() -> Weight { - Weight::from_ref_time(69_058_000) - .saturating_add(T::DbWeight::get().reads(10 as u64)) - .saturating_add(T::DbWeight::get().writes(2 as u64)) - } - // Storage: RmrkCore UniqueCollectionId (r:1 w:0) - // Storage: Common CollectionProperties (r:1 w:0) - // Storage: Common CollectionById (r:1 w:0) - // Storage: Nonfungible TokenAuxProperties (r:1 w:1) - // Storage: Nonfungible TokenData (r:5 w:0) - fn remove_resource() -> Weight { - Weight::from_ref_time(53_427_000) - .saturating_add(T::DbWeight::get().reads(9 as u64)) - .saturating_add(T::DbWeight::get().writes(1 as u64)) - } - // Storage: RmrkCore UniqueCollectionId (r:1 w:0) - // Storage: Common CollectionProperties (r:1 w:0) - // Storage: Common CollectionById (r:1 w:0) - // Storage: Nonfungible TokenData (r:5 w:0) - // Storage: Nonfungible TokenAuxProperties (r:1 w:1) - fn accept_resource() -> Weight { - Weight::from_ref_time(50_623_000) - .saturating_add(T::DbWeight::get().reads(9 as u64)) - .saturating_add(T::DbWeight::get().writes(1 as u64)) - } - // Storage: RmrkCore UniqueCollectionId (r:1 w:0) - // Storage: Common CollectionProperties (r:1 w:0) - // Storage: Common CollectionById (r:1 w:0) - // Storage: Nonfungible TokenData (r:5 w:0) - // Storage: Nonfungible TokenAuxProperties (r:1 w:1) - fn accept_resource_removal() -> Weight { - Weight::from_ref_time(50_917_000) - .saturating_add(T::DbWeight::get().reads(9 as u64)) - .saturating_add(T::DbWeight::get().writes(1 as u64)) - } -} - -// For backwards compatibility and tests -impl WeightInfo for () { - // Storage: Common CreatedCollectionCount (r:1 w:1) - // Storage: Common DestroyedCollectionCount (r:1 w:0) - // Storage: System Account (r:2 w:2) - // Storage: RmrkCore CollectionIndex (r:1 w:1) - // Storage: Common CollectionPropertyPermissions (r:0 w:1) - // Storage: Common CollectionProperties (r:0 w:1) - // Storage: Common CollectionById (r:0 w:1) - // Storage: RmrkCore UniqueCollectionId (r:0 w:1) - fn create_collection() -> Weight { - Weight::from_ref_time(49_754_000) - .saturating_add(RocksDbWeight::get().reads(5 as u64)) - .saturating_add(RocksDbWeight::get().writes(8 as u64)) - } - // Storage: RmrkCore UniqueCollectionId (r:1 w:0) - // Storage: Common CollectionProperties (r:1 w:1) - // Storage: Common CollectionById (r:1 w:1) - // Storage: Nonfungible TokenData (r:1 w:0) - // Storage: Common DestroyedCollectionCount (r:1 w:1) - // Storage: Nonfungible TokensMinted (r:0 w:1) - // Storage: Nonfungible TokensBurnt (r:0 w:1) - // Storage: Common AdminAmount (r:0 w:1) - fn destroy_collection() -> Weight { - Weight::from_ref_time(48_588_000) - .saturating_add(RocksDbWeight::get().reads(5 as u64)) - .saturating_add(RocksDbWeight::get().writes(6 as u64)) - } - // Storage: RmrkCore UniqueCollectionId (r:1 w:0) - // Storage: Common CollectionById (r:1 w:1) - // Storage: Common CollectionProperties (r:1 w:0) - fn change_collection_issuer() -> Weight { - Weight::from_ref_time(25_054_000) - .saturating_add(RocksDbWeight::get().reads(3 as u64)) - .saturating_add(RocksDbWeight::get().writes(1 as u64)) - } - // Storage: RmrkCore UniqueCollectionId (r:1 w:0) - // Storage: Common CollectionProperties (r:1 w:0) - // Storage: Common CollectionById (r:1 w:1) - // Storage: Nonfungible TokensMinted (r:1 w:0) - // Storage: Nonfungible TokensBurnt (r:1 w:0) - fn lock_collection() -> Weight { - Weight::from_ref_time(26_483_000) - .saturating_add(RocksDbWeight::get().reads(5 as u64)) - .saturating_add(RocksDbWeight::get().writes(1 as u64)) - } - // Storage: RmrkCore UniqueCollectionId (r:1 w:0) - // Storage: Common CollectionProperties (r:1 w:0) - // Storage: Common CollectionById (r:1 w:0) - // Storage: Nonfungible TokensMinted (r:1 w:1) - // Storage: Nonfungible AccountBalance (r:1 w:1) - // Storage: Nonfungible TokenProperties (r:1 w:1) - // Storage: Nonfungible TokenData (r:0 w:1) - // Storage: Nonfungible Owned (r:0 w:1) - // Storage: Nonfungible TokenAuxProperties (r:2 w:2) - fn mint_nft(b: u32, ) -> Weight { - Weight::from_ref_time(62_419_000) - // Standard Error: 7_000 - .saturating_add(Weight::from_ref_time(12_325_000).saturating_mul(b as u64)) - .saturating_add(RocksDbWeight::get().reads(6 as u64)) - .saturating_add(RocksDbWeight::get().reads((1 as u64).saturating_mul(b as u64))) - .saturating_add(RocksDbWeight::get().writes(5 as u64)) - .saturating_add(RocksDbWeight::get().writes((1 as u64).saturating_mul(b as u64))) - } - // Storage: RmrkCore UniqueCollectionId (r:1 w:0) - // Storage: Common CollectionProperties (r:1 w:0) - // Storage: Common CollectionById (r:1 w:0) - // Storage: Nonfungible TokenData (r:1 w:1) - // Storage: Nonfungible TokenChildren (r:1 w:0) - // Storage: Nonfungible TokensBurnt (r:1 w:1) - // Storage: Nonfungible AccountBalance (r:1 w:1) - // Storage: Nonfungible Allowance (r:1 w:0) - // Storage: Nonfungible Owned (r:0 w:1) - // Storage: Nonfungible TokenProperties (r:0 w:1) - fn burn_nft(b: u32, ) -> Weight { - (Weight::from_ref_time(0)) - // Standard Error: 1_488_000 - .saturating_add(Weight::from_ref_time(298_367_000).saturating_mul(b as u64)) - .saturating_add(RocksDbWeight::get().reads(9 as u64)) - .saturating_add(RocksDbWeight::get().reads((4 as u64).saturating_mul(b as u64))) - .saturating_add(RocksDbWeight::get().writes(6 as u64)) - .saturating_add(RocksDbWeight::get().writes((4 as u64).saturating_mul(b as u64))) - } - // Storage: RmrkCore UniqueCollectionId (r:1 w:0) - // Storage: Common CollectionProperties (r:1 w:0) - // Storage: Common CollectionById (r:1 w:0) - // Storage: Nonfungible TokenData (r:5 w:1) - // Storage: Nonfungible TokenProperties (r:1 w:0) - // Storage: Nonfungible AccountBalance (r:2 w:2) - // Storage: Nonfungible Allowance (r:1 w:0) - // Storage: Nonfungible TokenChildren (r:0 w:1) - // Storage: Nonfungible Owned (r:0 w:2) - fn send() -> Weight { - Weight::from_ref_time(81_942_000) - .saturating_add(RocksDbWeight::get().reads(12 as u64)) - .saturating_add(RocksDbWeight::get().writes(6 as u64)) - } - // Storage: RmrkCore UniqueCollectionId (r:2 w:0) - // Storage: Common CollectionProperties (r:1 w:0) - // Storage: Common CollectionById (r:2 w:0) - // Storage: Nonfungible TokenData (r:6 w:1) - // Storage: Nonfungible AccountBalance (r:2 w:2) - // Storage: Nonfungible Allowance (r:1 w:0) - // Storage: Nonfungible TokenProperties (r:1 w:1) - // Storage: Nonfungible TokenAuxProperties (r:1 w:1) - // Storage: Nonfungible TokenChildren (r:0 w:1) - // Storage: Nonfungible Owned (r:0 w:2) - fn accept_nft() -> Weight { - Weight::from_ref_time(97_925_000) - .saturating_add(RocksDbWeight::get().reads(16 as u64)) - .saturating_add(RocksDbWeight::get().writes(8 as u64)) - } - // Storage: RmrkCore UniqueCollectionId (r:1 w:0) - // Storage: Common CollectionProperties (r:1 w:0) - // Storage: Common CollectionById (r:1 w:0) - // Storage: Nonfungible TokenData (r:5 w:5) - // Storage: Nonfungible TokenProperties (r:1 w:5) - // Storage: Nonfungible TokenAuxProperties (r:1 w:1) - // Storage: Nonfungible TokenChildren (r:9 w:4) - // Storage: Nonfungible TokensBurnt (r:1 w:1) - // Storage: Nonfungible AccountBalance (r:5 w:5) - // Storage: Nonfungible Allowance (r:5 w:0) - // Storage: Nonfungible Owned (r:0 w:5) - fn reject_nft() -> Weight { - Weight::from_ref_time(277_794_000) - .saturating_add(RocksDbWeight::get().reads(30 as u64)) - .saturating_add(RocksDbWeight::get().writes(26 as u64)) - } - // Storage: RmrkCore UniqueCollectionId (r:1 w:0) - // Storage: Common CollectionProperties (r:1 w:0) - // Storage: Common CollectionById (r:1 w:0) - // Storage: Nonfungible TokenProperties (r:1 w:1) - // Storage: Nonfungible TokenData (r:5 w:0) - fn set_property() -> Weight { - Weight::from_ref_time(54_657_000) - .saturating_add(RocksDbWeight::get().reads(9 as u64)) - .saturating_add(RocksDbWeight::get().writes(1 as u64)) - } - // Storage: RmrkCore UniqueCollectionId (r:1 w:0) - // Storage: Common CollectionProperties (r:1 w:0) - // Storage: Common CollectionById (r:1 w:0) - // Storage: Nonfungible TokenProperties (r:1 w:1) - // Storage: Nonfungible TokenData (r:5 w:0) - fn set_priority() -> Weight { - Weight::from_ref_time(55_056_000) - .saturating_add(RocksDbWeight::get().reads(9 as u64)) - .saturating_add(RocksDbWeight::get().writes(1 as u64)) - } - // Storage: RmrkCore UniqueCollectionId (r:1 w:0) - // Storage: Common CollectionProperties (r:1 w:0) - // Storage: Common CollectionById (r:1 w:0) - // Storage: Nonfungible TokenData (r:5 w:0) - // Storage: Nonfungible TokenProperties (r:1 w:1) - // Storage: Nonfungible TokenAuxProperties (r:1 w:1) - fn add_basic_resource() -> Weight { - Weight::from_ref_time(61_673_000) - .saturating_add(RocksDbWeight::get().reads(10 as u64)) - .saturating_add(RocksDbWeight::get().writes(2 as u64)) - } - // Storage: RmrkCore UniqueCollectionId (r:1 w:0) - // Storage: Common CollectionProperties (r:1 w:0) - // Storage: Common CollectionById (r:1 w:0) - // Storage: Nonfungible TokenData (r:5 w:0) - // Storage: Nonfungible TokenProperties (r:1 w:1) - // Storage: Nonfungible TokenAuxProperties (r:2 w:2) - fn add_composable_resource() -> Weight { - Weight::from_ref_time(67_125_000) - .saturating_add(RocksDbWeight::get().reads(11 as u64)) - .saturating_add(RocksDbWeight::get().writes(3 as u64)) - } - // Storage: RmrkCore UniqueCollectionId (r:1 w:0) - // Storage: Common CollectionProperties (r:1 w:0) - // Storage: Common CollectionById (r:1 w:0) - // Storage: Nonfungible TokenData (r:5 w:0) - // Storage: Nonfungible TokenProperties (r:1 w:1) - // Storage: Nonfungible TokenAuxProperties (r:1 w:1) - fn add_slot_resource() -> Weight { - Weight::from_ref_time(69_058_000) - .saturating_add(RocksDbWeight::get().reads(10 as u64)) - .saturating_add(RocksDbWeight::get().writes(2 as u64)) - } - // Storage: RmrkCore UniqueCollectionId (r:1 w:0) - // Storage: Common CollectionProperties (r:1 w:0) - // Storage: Common CollectionById (r:1 w:0) - // Storage: Nonfungible TokenAuxProperties (r:1 w:1) - // Storage: Nonfungible TokenData (r:5 w:0) - fn remove_resource() -> Weight { - Weight::from_ref_time(53_427_000) - .saturating_add(RocksDbWeight::get().reads(9 as u64)) - .saturating_add(RocksDbWeight::get().writes(1 as u64)) - } - // Storage: RmrkCore UniqueCollectionId (r:1 w:0) - // Storage: Common CollectionProperties (r:1 w:0) - // Storage: Common CollectionById (r:1 w:0) - // Storage: Nonfungible TokenData (r:5 w:0) - // Storage: Nonfungible TokenAuxProperties (r:1 w:1) - fn accept_resource() -> Weight { - Weight::from_ref_time(50_623_000) - .saturating_add(RocksDbWeight::get().reads(9 as u64)) - .saturating_add(RocksDbWeight::get().writes(1 as u64)) - } - // Storage: RmrkCore UniqueCollectionId (r:1 w:0) - // Storage: Common CollectionProperties (r:1 w:0) - // Storage: Common CollectionById (r:1 w:0) - // Storage: Nonfungible TokenData (r:5 w:0) - // Storage: Nonfungible TokenAuxProperties (r:1 w:1) - fn accept_resource_removal() -> Weight { - Weight::from_ref_time(50_917_000) - .saturating_add(RocksDbWeight::get().reads(9 as u64)) - .saturating_add(RocksDbWeight::get().writes(1 as u64)) - } -} --- a/pallets/proxy-rmrk-equip/CHANGELOG.md +++ /dev/null @@ -1,17 +0,0 @@ - -## [v0.1.2] 2022-08-16 - -### Other changes - -- build: Upgrade polkadot to v0.9.27 2c498572636f2b34d53b1c51b7283a761a7dc90a - -- build: Upgrade polkadot to v0.9.26 85515e54c4ca1b82a2630034e55dcc804c643bf8 - -- refactor: Remove `#[transactional]` from extrinsics 7fd36cea2f6e00c02c67ccc1de9649ae404efd31 - -Every extrinsic now runs in transaction implicitly, and -`#[transactional]` on pallet dispatchable is now meaningless - -Upstream-Change: https://github.com/paritytech/substrate/issues/10806 - -- build: Upgrade polkadot to v0.9.25 cdfb9bdc7b205ff1b5134f034ef9973d769e5e6b \ No newline at end of file --- a/pallets/proxy-rmrk-equip/Cargo.toml +++ /dev/null @@ -1,39 +0,0 @@ -[package] -edition = "2021" -license = "GPLv3" -name = "pallet-rmrk-equip" -version = "0.1.2" - -[dependencies] -# Note: `package = "parity-scale-codec"` must be supplied since the `Encode` macro searches for it. -codec = { workspace = true, package = "parity-scale-codec" } - -scale-info = { workspace = true } - -frame-benchmarking = {workspace = true, optional = true } -frame-support = { workspace = true } -frame-system = { workspace = true } -pallet-common = { workspace = true } -pallet-evm = { workspace = true } -pallet-nonfungible = { workspace = true } -pallet-proxy-rmrk-core = { workspace = true } -sp-runtime = { workspace = true } -sp-std = { workspace = true } -up-data-structs = { workspace = true } - -[features] -default = ["std"] -runtime-benchmarks = ['frame-benchmarking', 'frame-support/runtime-benchmarks', 'frame-system/runtime-benchmarks'] -std = [ - "frame-support/std", - "frame-system/std", - "pallet-common/std", - "pallet-evm/std", - "pallet-nonfungible/std", - "pallet-proxy-rmrk-core/std", - "sp-runtime/std", - "sp-std/std", - "up-data-structs/std", - 'frame-benchmarking/std', -] -try-runtime = ["frame-support/try-runtime"] --- a/pallets/proxy-rmrk-equip/src/benchmarking.rs +++ /dev/null @@ -1,136 +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 . - -use sp_std::vec; - -use frame_benchmarking::{benchmarks, account}; -use frame_system::RawOrigin; -use frame_support::{ - traits::{Currency, Get}, - BoundedVec, -}; - -use up_data_structs::*; - -use super::*; - -const SEED: u32 = 1; - -fn create_data>() -> BoundedVec { - vec![b'A'; S::get() as usize].try_into().expect("size == S") -} - -fn create_u32_array>() -> BoundedVec { - vec![0; S::get() as usize].try_into().expect("size == S") -} - -fn create_max_part(id: RmrkSlotId) -> RmrkPartType { - RmrkPartType::SlotPart(RmrkSlotPart { - id, - equippable: RmrkEquippableList::Custom(create_u32_array()), - src: create_data(), - z: 1, - }) -} - -fn create_parts_array>(num: u32) -> BoundedVec { - let mut parts: BoundedVec = vec![].try_into().expect("0 <= S"); - - for i in 0..num { - parts.try_push(create_max_part(i)).expect("num <= S"); - } - - parts -} - -fn create_max_theme_property() -> RmrkThemeProperty { - RmrkThemeProperty { - key: create_data(), - value: create_data(), - } -} - -fn create_theme_properties_array>(num: u32) -> BoundedVec { - vec![create_max_theme_property(); num as usize] - .try_into() - .expect("num <= S") -} - -fn create_max_theme(name: RmrkString, props_num: u32) -> RmrkBoundedTheme { - RmrkBoundedTheme { - name, - properties: create_theme_properties_array(props_num), - inherit: false, - } -} - -benchmarks! { - create_base { - let b in 0..RmrkPartsLimit::get(); - - let caller = account("caller", 0, SEED); - ::Currency::deposit_creating(&caller, T::CollectionCreationPrice::get()); - - let base_type = create_data(); - let symbol = create_data(); - let parts = create_parts_array(b); - }: _(RawOrigin::Signed(caller), base_type, symbol, parts) - - theme_add { - let b in 0..MaxPropertiesPerTheme::get(); - - let caller = account("caller", 0, SEED); - ::Currency::deposit_creating(&caller, T::CollectionCreationPrice::get()); - - let base_type = create_data(); - let symbol = create_data(); - let parts = create_parts_array(0); - - >::create_base(RawOrigin::Signed(caller.clone()).into(), base_type, symbol, parts)?; - let base_id = 1; - - - let default_theme_name = b"default".to_vec().try_into().expect("default is a valid name; qed"); - let default_theme = create_max_theme(default_theme_name, 0); - - >::theme_add(RawOrigin::Signed(caller.clone()).into(), base_id, default_theme)?; - - let theme = create_max_theme(create_data(), b); - }: _(RawOrigin::Signed(caller), base_id, theme) - - equippable { - let caller = account("caller", 0, SEED); - ::Currency::deposit_creating(&caller, T::CollectionCreationPrice::get()); - - let base_id = 1; - let slot_id = 42; - - let base_type = create_data(); - let symbol = create_data(); - let parts = vec! { - RmrkPartType::SlotPart(RmrkSlotPart { - id: slot_id, - equippable: RmrkEquippableList::All, - src: create_data(), - z: 1, - }) - }.try_into().expect("1 <= RmrkPartsLimit"); - - >::create_base(RawOrigin::Signed(caller.clone()).into(), base_type, symbol, parts)?; - - let equippables = RmrkEquippableList::Custom(create_u32_array()); - }: _(RawOrigin::Signed(caller), base_id, slot_id, equippables) -} --- a/pallets/proxy-rmrk-equip/src/lib.rs +++ /dev/null @@ -1,508 +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 . - -//! # RMRK Core Proxy Pallet -//! -//! A pallet used as proxy for RMRK Core (). -//! -//! - [`Config`] -//! - [`Call`] -//! - [`Pallet`] -//! -//! ## Overview -//! -//! The RMRK Equip Proxy pallet mirrors the functionality of RMRK Equip, -//! binding its externalities to Unique's own underlying structure. -//! It is purposed to mimic RMRK Equip exactly, allowing seamless integrations -//! of solutions based on RMRK. -//! -//! RMRK Equip itself contains functionality to equip NFTs, and work with Bases, -//! Parts, and Themes. See [Proxy Implementation](#proxy-implementation) for details. -//! -//! Equip Proxy is responsible for a more specific area of RMRK, and heavily relies on the Core. -//! For a more foundational description of proxy implementation, please refer to [`pallet_rmrk_core`]. -//! -//! *Note*, that while RMRK itself is subject to active development and restructuring, -//! the proxy may be caught temporarily out of date. -//! -//! ### What is RMRK? -//! -//! RMRK is a set of NFT standards which compose several "NFT 2.0 lego" primitives. -//! Putting these legos together allows a user to create NFT systems of arbitrary complexity. -//! -//! Meaning, RMRK NFTs are dynamic, able to nest into each other and form a hierarchy, -//! make use of specific changeable and partially shared metadata in the form of resources, -//! and more. -//! -//! Visit RMRK documentation and repositories to learn more: -//! - Docs: -//! - FAQ: -//! - Substrate code repository: -//! - RMRK spec repository: -//! -//! ## Terminology -//! -//! For more information on RMRK, see RMRK's own documentation. -//! -//! ### Intro to RMRK -//! -//! - **Resource:** Additional piece of metadata of an NFT usually serving to add -//! a piece of media on top of the root metadata (NFT's own), be it a different wing -//! on the root template bird or something entirely unrelated. -//! -//! - **Base:** A list of possible "components" - Parts, a combination of which can -//! be appended/equipped to/on an NFT. -//! -//! - **Part:** Something that, together with other Parts, can constitute an NFT. -//! Parts are defined in the Base to which they belong. Parts can be either -//! of the `slot` type or `fixed` type. Slots are intended for equippables. -//! Note that "part of something" and "Part of a Base" can be easily confused, -//! and so in this documentation these words are distinguished by the capital letter. -//! -//! - **Theme:** Named objects of variable => value pairs which get interpolated into -//! the Base's `themable` Parts. Themes can hold any value, but are often represented -//! in RMRK's examples as colors applied to visible Parts. -//! -//! ### Peculiarities in Unique -//! -//! - **Scoped properties:** Properties that are normally obscured from users. -//! Their purpose is to contain structured metadata that was not included in the Unique standard -//! for collections and tokens, meant to be operated on by proxies and other outliers. -//! Scoped property keys are prefixed with `some-scope:`, where `some-scope` is -//! an arbitrary keyword, like "rmrk". `:` is considered an unacceptable symbol in user-defined -//! properties, which, along with other safeguards, makes scoped ones impossible to tamper with. -//! -//! - **Auxiliary properties:** A slightly different structure of properties, -//! trading universality of use for more convenient storage, writes and access. -//! Meant to be inaccessible to end users. -//! -//! ## Proxy Implementation -//! -//! An external user is supposed to be able to utilize this proxy as they would -//! utilize RMRK, and get exactly the same results. Normally, Unique transactions -//! are off-limits to RMRK collections and tokens, and vice versa. However, -//! the information stored on chain can be freely interpreted by storage reads and Unique RPCs. -//! -//! ### ID Mapping -//! -//! RMRK's collections' IDs are counted independently of Unique's and start at 0. -//! Note that tokens' IDs still start at 1. -//! The collections themselves, as well as tokens, are stored as Unique collections, -//! and thus RMRK IDs are mapped to Unique IDs (but not vice versa). -//! -//! ### External/Internal Collection Insulation -//! -//! A Unique transaction cannot target collections purposed for RMRK, -//! and they are flagged as `external` to specify that. On the other hand, -//! due to the mapping, RMRK transactions and RPCs simply cannot reach Unique collections. -//! -//! ### Native Properties -//! -//! Many of RMRK's native parameters are stored as scoped properties of a collection -//! or an NFT on the chain. Scoped properties are prefixed with `rmrk:`, where `:` -//! is an unacceptable symbol in user-defined properties, which, along with other safeguards, -//! makes them impossible to tamper with. -//! -//! ### Collection and NFT Types, or Base, Parts and Themes Handling -//! -//! RMRK introduces the concept of a Base, which is a catalogue of Parts, -//! possible components of an NFT. Due to its similarity with the functionality -//! of a token collection, a Base is stored and handled as one, and the Base's Parts and Themes -//! are this collection's NFTs. See [`CollectionType`] and [`NftType`]. -//! -//! ## Interface -//! -//! ### Dispatchables -//! -//! - `create_base` - Create a new Base. -//! - `theme_add` - Add a Theme to a Base. -//! - `equippable` - Update the array of Collections allowed to be equipped to a Base's specified Slot Part. - -#![cfg_attr(not(feature = "std"), no_std)] - -use frame_support::{pallet_prelude::*, BoundedVec, dispatch::DispatchResult}; -use frame_system::{pallet_prelude::*, ensure_signed}; -use sp_runtime::DispatchError; -use up_data_structs::*; -use pallet_common::{Pallet as PalletCommon, Error as CommonError}; -use pallet_proxy_rmrk_core::{ - Pallet as PalletCore, Error as CoreError, - misc::{self, *}, - property::RmrkProperty::*, -}; -use pallet_nonfungible::{Pallet as PalletNft, NonfungibleHandle}; -use pallet_evm::account::CrossAccountId; -use weights::WeightInfo; - -pub use pallet::*; - -#[cfg(feature = "runtime-benchmarks")] -pub mod benchmarking; -pub mod rpc; -pub mod weights; - -pub type SelfWeightOf = ::WeightInfo; - -#[frame_support::pallet] -pub mod pallet { - use super::*; - - #[pallet::config] - pub trait Config: frame_system::Config + pallet_proxy_rmrk_core::Config { - /// Overarching event type. - type RuntimeEvent: From> + IsType<::RuntimeEvent>; - - /// The weight information of this pallet. - type WeightInfo: WeightInfo; - } - - /// Map of a Base ID and a Part ID to an NFT in the Base collection serving as the Part. - #[pallet::storage] - #[pallet::getter(fn internal_part_id)] - pub type InernalPartId = - StorageDoubleMap<_, Twox64Concat, CollectionId, Twox64Concat, RmrkPartId, TokenId>; - - /// Checkmark that a Base has a Theme NFT named "default". - #[pallet::storage] - #[pallet::getter(fn base_has_default_theme)] - pub type BaseHasDefaultTheme = - StorageMap<_, Twox64Concat, CollectionId, bool, ValueQuery>; - - #[pallet::pallet] - #[pallet::generate_store(pub(super) trait Store)] - pub struct Pallet(_); - - #[pallet::event] - #[pallet::generate_deposit(pub(super) fn deposit_event)] - pub enum Event { - BaseCreated { - issuer: T::AccountId, - base_id: RmrkBaseId, - }, - EquippablesUpdated { - base_id: RmrkBaseId, - slot_id: RmrkSlotId, - }, - } - - #[pallet::error] - pub enum Error { - /// No permission to perform action. - PermissionError, - /// Could not find an ID for a Base collection. It is likely there were too many collections created on the chain, causing an overflow. - NoAvailableBaseId, - /// Could not find a suitable ID for a Part, likely too many Part tokens were created in the Base, causing an overflow - NoAvailablePartId, - /// Base collection linked to this ID does not exist. - BaseDoesntExist, - /// No Theme named "default" is associated with the Base. - NeedsDefaultThemeFirst, - /// Part linked to this ID does not exist. - PartDoesntExist, - /// Cannot assign equippables to a fixed Part. - NoEquippableOnFixedPart, - } - - #[pallet::call] - impl Pallet { - /// Create a new Base. - /// - /// Modeled after the [Base interaction](https://github.com/rmrk-team/rmrk-spec/blob/master/standards/rmrk2.0.0/interactions/base.md) - /// - /// # Permissions - /// - Anyone - will be assigned as the issuer of the Base. - /// - /// # Arguments: - /// - `origin`: Caller, will be assigned as the issuer of the Base - /// - `base_type`: Arbitrary media type, e.g. "svg". - /// - `symbol`: Arbitrary client-chosen symbol. - /// - `parts`: Array of Fixed and Slot Parts composing the Base, - /// confined in length by [`RmrkPartsLimit`](up_data_structs::RmrkPartsLimit). - #[pallet::call_index(0)] - #[pallet::weight(>::create_base(parts.len() as u32))] - pub fn create_base( - origin: OriginFor, - base_type: RmrkString, - symbol: RmrkBaseSymbol, - parts: BoundedVec, - ) -> DispatchResult { - let sender = ensure_signed(origin)?; - let cross_sender = T::CrossAccountId::from_sub(sender.clone()); - - let data = CreateCollectionData { - limits: None, - token_prefix: symbol - .into_inner() - .try_into() - .map_err(|_| >::CollectionTokenPrefixLimitExceeded)?, - ..Default::default() - }; - - let collection_id_res = >::init_collection( - cross_sender.clone(), - cross_sender.clone(), - data, - up_data_structs::CollectionFlags { - external: true, - ..Default::default() - }, - ); - - if let Err(DispatchError::Arithmetic(_)) = &collection_id_res { - return Err(>::NoAvailableBaseId.into()); - } - - let collection_id = collection_id_res?; - - >::set_scoped_collection_properties( - collection_id, - PropertyScope::Rmrk, - [ - >::encode_rmrk_property( - CollectionType, - &misc::CollectionType::Base, - )?, - >::encode_rmrk_property(BaseType, &base_type)?, - ] - .into_iter(), - )?; - - let collection = >::get_nft_collection(collection_id)?; - - for part in parts { - Self::create_part(&cross_sender, &collection, part)?; - } - - Self::deposit_event(Event::BaseCreated { - issuer: sender, - base_id: collection_id.0, - }); - - Ok(()) - } - - /// Add a Theme to a Base. - /// A Theme named "default" is required prior to adding other Themes. - /// - /// Modeled after [Themeadd interaction](https://github.com/rmrk-team/rmrk-spec/blob/master/standards/rmrk2.0.0/interactions/themeadd.md). - /// - /// # Permissions: - /// - Base issuer - /// - /// # Arguments: - /// - `origin`: sender of the transaction - /// - `base_id`: Base ID containing the Theme to be updated. - /// - `theme`: Theme to add to the Base. A Theme has a name and properties, which are an - /// array of [key, value, inherit]. - /// - `key`: Arbitrary BoundedString, defined by client. - /// - `value`: Arbitrary BoundedString, defined by client. - /// - `inherit`: Optional bool. - #[pallet::call_index(1)] - #[pallet::weight(>::theme_add(theme.properties.len() as u32))] - pub fn theme_add( - origin: OriginFor, - base_id: RmrkBaseId, - theme: RmrkBoundedTheme, - ) -> DispatchResult { - let sender = ensure_signed(origin)?; - - let sender = T::CrossAccountId::from_sub(sender); - let owner = &sender; - - let collection_id: CollectionId = base_id.into(); - - let collection = Self::get_base(collection_id)?; - - if theme.name.as_slice() == b"default" { - >::insert(collection_id, true); - } else if !Self::base_has_default_theme(collection_id) { - return Err(>::NeedsDefaultThemeFirst.into()); - } - - let token_id = >::create_nft( - &sender, - owner, - &collection, - [ - >::encode_rmrk_property(TokenType, &NftType::Theme)?, - >::encode_rmrk_property(ThemeName, &theme.name)?, - >::encode_rmrk_property(ThemeInherit, &theme.inherit)?, - ] - .into_iter(), - ) - .map_err(|_| >::PermissionError)?; - - for property in theme.properties { - >::set_scoped_token_property( - collection_id, - token_id, - PropertyScope::Rmrk, - >::encode_rmrk_property( - UserProperty(property.key.as_slice()), - &property.value, - )?, - )?; - } - - Ok(()) - } - - /// Update the array of Collections allowed to be equipped to a Base's specified Slot Part. - /// - /// Modeled after [equippable interaction](https://github.com/rmrk-team/rmrk-spec/blob/master/standards/rmrk2.0.0/interactions/equippable.md). - /// - /// # Permissions: - /// - Base issuer - /// - /// # Arguments: - /// - `origin`: sender of the transaction - /// - `base_id`: Base containing the Slot Part to be updated. - /// - `slot_id`: Slot Part whose Equippable List is being updated . - /// - `equippables`: List of equippables that will override the current Equippables list. - #[pallet::call_index(2)] - #[pallet::weight(>::equippable())] - pub fn equippable( - origin: OriginFor, - base_id: RmrkBaseId, - slot_id: RmrkSlotId, - equippables: RmrkEquippableList, - ) -> DispatchResult { - let sender = ensure_signed(origin)?; - - let base_collection_id = base_id.into(); - let collection = Self::get_base(base_collection_id)?; - - >::check_collection_owner( - &collection, - &T::CrossAccountId::from_sub(sender), - ) - .map_err(|err| { - if err == >::NoPermission.into() { - >::PermissionError.into() - } else { - err - } - })?; - - let part_id = Self::internal_part_id(base_collection_id, slot_id) - .ok_or(>::PartDoesntExist)?; - - let nft_type = >::get_nft_type(base_collection_id, part_id) - .map_err(|_| >::PartDoesntExist)?; - - match nft_type { - NftType::Regular | NftType::Theme => return Err(>::PermissionError.into()), - NftType::FixedPart => return Err(>::NoEquippableOnFixedPart.into()), - NftType::SlotPart => { - >::set_scoped_token_property( - base_collection_id, - part_id, - PropertyScope::Rmrk, - >::encode_rmrk_property(EquippableList, &equippables)?, - )?; - } - } - - Self::deposit_event(Event::EquippablesUpdated { base_id, slot_id }); - - Ok(()) - } - } -} - -impl Pallet { - /// Create (or overwrite) a Part in a Base. - /// The Part and the Base are represented as an NFT and a Collection. - fn create_part( - sender: &T::CrossAccountId, - collection: &NonfungibleHandle, - part: RmrkPartType, - ) -> DispatchResult { - let owner = sender; - - let part_id = part.id(); - let src = part.src(); - let z_index = part.z_index(); - - let nft_type = match part { - RmrkPartType::FixedPart(_) => NftType::FixedPart, - RmrkPartType::SlotPart(_) => NftType::SlotPart, - }; - - let token_id = match Self::internal_part_id(collection.id, part_id) { - Some(token_id) => token_id, - None => { - let token_id = - >::create_nft(sender, owner, collection, [].into_iter()) - .map_err(|err| match err { - DispatchError::Arithmetic(_) => >::NoAvailablePartId.into(), - err => err, - })?; - - >::insert(collection.id, part_id, token_id); - - >::set_scoped_token_property( - collection.id, - token_id, - PropertyScope::Rmrk, - >::encode_rmrk_property(ExternalPartId, &part_id)?, - )?; - - token_id - } - }; - - >::set_scoped_token_properties( - collection.id, - token_id, - PropertyScope::Rmrk, - [ - >::encode_rmrk_property(TokenType, &nft_type)?, - >::encode_rmrk_property(Src, &src)?, - >::encode_rmrk_property(ZIndex, &z_index)?, - ] - .into_iter(), - )?; - - if let RmrkPartType::SlotPart(part) = part { - >::set_scoped_token_property( - collection.id, - token_id, - PropertyScope::Rmrk, - >::encode_rmrk_property(EquippableList, &part.equippable)?, - )?; - } - - Ok(()) - } - - /// Ensure that the collection under the Base ID is a Base collection, - /// and fetch it. - fn get_base(base_id: CollectionId) -> Result, DispatchError> { - let collection = - >::get_typed_nft_collection(base_id, misc::CollectionType::Base) - .map_err(|err| { - if err == >::CollectionUnknown.into() { - >::BaseDoesntExist.into() - } else { - err - } - })?; - collection.check_is_external()?; - - Ok(collection) - } -} --- a/pallets/proxy-rmrk-equip/src/rpc.rs +++ /dev/null @@ -1,208 +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 . - -//! Realizations of RMRK RPCs (remote procedure calls) related to the Equip pallet. - -use super::*; -use pallet_proxy_rmrk_core::{misc, property::*}; -use sp_std::vec::Vec; - -/// Get base info by its ID. -pub fn base( - base_id: RmrkBaseId, -) -> Result>, DispatchError> { - let (collection, collection_id) = - match >::get_typed_nft_collection_mapped(base_id, misc::CollectionType::Base) - { - Ok(c) => c, - Err(_) => return Ok(None), - }; - - Ok(Some(RmrkBaseInfo { - issuer: collection.owner.clone(), - base_type: >::get_collection_property_decoded( - collection_id, - RmrkProperty::BaseType, - )?, - symbol: >::rebind(&collection.token_prefix)?, - })) -} - -/// Get all parts of a base. -pub fn base_parts(base_id: RmrkBaseId) -> Result, DispatchError> { - use pallet_common::CommonCollectionOperations; - - let (collection, collection_id) = - match >::get_typed_nft_collection_mapped(base_id, misc::CollectionType::Base) - { - Ok(c) => c, - Err(_) => return Ok(Vec::new()), - }; - - let parts = collection - .collection_tokens() - .into_iter() - .filter_map(|token_id| { - let nft_type = >::get_nft_type(collection_id, token_id).ok()?; - - match nft_type { - NftType::FixedPart => Some(RmrkPartType::FixedPart(RmrkFixedPart { - id: >::get_nft_property_decoded( - collection_id, - token_id, - RmrkProperty::ExternalPartId, - ) - .ok()?, - src: >::get_nft_property_decoded( - collection_id, - token_id, - RmrkProperty::Src, - ) - .ok()?, - z: >::get_nft_property_decoded( - collection_id, - token_id, - RmrkProperty::ZIndex, - ) - .ok()?, - })), - NftType::SlotPart => Some(RmrkPartType::SlotPart(RmrkSlotPart { - id: >::get_nft_property_decoded( - collection_id, - token_id, - RmrkProperty::ExternalPartId, - ) - .ok()?, - src: >::get_nft_property_decoded( - collection_id, - token_id, - RmrkProperty::Src, - ) - .ok()?, - z: >::get_nft_property_decoded( - collection_id, - token_id, - RmrkProperty::ZIndex, - ) - .ok()?, - equippable: >::get_nft_property_decoded( - collection_id, - token_id, - RmrkProperty::EquippableList, - ) - .ok()?, - })), - _ => None, - } - }) - .collect(); - - Ok(parts) -} - -/// Get the theme names belonging to a base. -pub fn theme_names(base_id: RmrkBaseId) -> Result, DispatchError> { - use pallet_common::CommonCollectionOperations; - - let (collection, collection_id) = - match >::get_typed_nft_collection_mapped(base_id, misc::CollectionType::Base) - { - Ok(c) => c, - Err(_) => return Ok(Vec::new()), - }; - - let theme_names = collection - .collection_tokens() - .iter() - .filter_map(|token_id| { - let nft_type = >::get_nft_type(collection_id, *token_id).ok()?; - - match nft_type { - NftType::Theme => >::get_nft_property_decoded( - collection_id, - *token_id, - RmrkProperty::ThemeName, - ) - .ok(), - _ => None, - } - }) - .collect(); - - Ok(theme_names) -} - -/// Get theme info, including properties, optionally limited to the provided keys. -pub fn theme( - base_id: RmrkBaseId, - theme_name: RmrkThemeName, - filter_keys: Option>, -) -> Result, DispatchError> { - use pallet_common::CommonCollectionOperations; - - let (collection, collection_id) = - match >::get_typed_nft_collection_mapped(base_id, misc::CollectionType::Base) - { - Ok(c) => c, - Err(_) => return Ok(None), - }; - - let theme_info = collection - .collection_tokens() - .into_iter() - .find_map(|token_id| { - >::ensure_nft_type(collection_id, token_id, NftType::Theme).ok()?; - - let name: RmrkString = >::get_nft_property_decoded( - collection_id, - token_id, - RmrkProperty::ThemeName, - ) - .ok()?; - - if name == theme_name { - Some((name, token_id)) - } else { - None - } - }); - - let (name, theme_id) = match theme_info { - Some((name, theme_id)) => (name, theme_id), - None => return Ok(None), - }; - - let properties = >::filter_user_properties( - collection_id, - Some(theme_id), - filter_keys, - |key, value| RmrkThemeProperty { key, value }, - )?; - - let inherit = >::get_nft_property_decoded( - collection_id, - theme_id, - RmrkProperty::ThemeInherit, - )?; - - let theme = RmrkTheme { - name, - properties, - inherit, - }; - - Ok(Some(theme)) -} --- a/pallets/proxy-rmrk-equip/src/weights.rs +++ /dev/null @@ -1,138 +0,0 @@ -// Template adopted from https://github.com/paritytech/substrate/blob/master/.maintain/frame-weight-template.hbs - -//! Autogenerated weights for pallet_proxy_rmrk_equip -//! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2022-08-15, STEPS: `50`, REPEAT: 80, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! EXECUTION: None, WASM-EXECUTION: Compiled, CHAIN: None, DB CACHE: 1024 - -// Executed Command: -// target/release/unique-collator -// benchmark -// pallet -// --pallet -// pallet-proxy-rmrk-equip -// --wasm-execution -// compiled -// --extrinsic -// * -// --template -// .maintain/frame-weight-template.hbs -// --steps=50 -// --repeat=80 -// --heap-pages=4096 -// --output=./pallets/proxy-rmrk-equip/src/weights.rs - -#![cfg_attr(rustfmt, rustfmt_skip)] -#![allow(unused_parens)] -#![allow(unused_imports)] -#![allow(clippy::unnecessary_cast)] - -use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; -use sp_std::marker::PhantomData; - -/// Weight functions needed for pallet_proxy_rmrk_equip. -pub trait WeightInfo { - fn create_base(b: u32, ) -> Weight; - fn theme_add(b: u32, ) -> Weight; - fn equippable() -> Weight; -} - -/// Weights for pallet_proxy_rmrk_equip using the Substrate node and recommended hardware. -pub struct SubstrateWeight(PhantomData); -impl WeightInfo for SubstrateWeight { - // Storage: Common CreatedCollectionCount (r:1 w:1) - // Storage: Common DestroyedCollectionCount (r:1 w:0) - // Storage: System Account (r:2 w:2) - // Storage: Common CollectionPropertyPermissions (r:0 w:1) - // Storage: Common CollectionProperties (r:0 w:1) - // Storage: Common CollectionById (r:0 w:1) - // Storage: RmrkEquip InernalPartId (r:1 w:1) - // Storage: Nonfungible TokensMinted (r:1 w:1) - // Storage: Nonfungible AccountBalance (r:1 w:1) - // Storage: Nonfungible TokenProperties (r:1 w:1) - // Storage: Nonfungible TokenData (r:0 w:1) - // Storage: Nonfungible Owned (r:0 w:1) - fn create_base(b: u32, ) -> Weight { - Weight::from_ref_time(58_417_000) - // Standard Error: 27_000 - .saturating_add(Weight::from_ref_time(20_439_000).saturating_mul(b as u64)) - .saturating_add(T::DbWeight::get().reads(6 as u64)) - .saturating_add(T::DbWeight::get().reads((2 as u64).saturating_mul(b as u64))) - .saturating_add(T::DbWeight::get().writes(8 as u64)) - .saturating_add(T::DbWeight::get().writes((4 as u64).saturating_mul(b as u64))) - } - // Storage: Common CollectionProperties (r:1 w:0) - // Storage: Common CollectionById (r:1 w:0) - // Storage: RmrkEquip BaseHasDefaultTheme (r:1 w:0) - // Storage: Nonfungible TokensMinted (r:1 w:1) - // Storage: Nonfungible AccountBalance (r:1 w:1) - // Storage: Nonfungible TokenProperties (r:1 w:1) - // Storage: Nonfungible TokenData (r:0 w:1) - // Storage: Nonfungible Owned (r:0 w:1) - fn theme_add(b: u32, ) -> Weight { - Weight::from_ref_time(46_005_000) - // Standard Error: 42_000 - .saturating_add(Weight::from_ref_time(2_922_000).saturating_mul(b as u64)) - .saturating_add(T::DbWeight::get().reads(6 as u64)) - .saturating_add(T::DbWeight::get().writes(5 as u64)) - } - // Storage: Common CollectionProperties (r:1 w:0) - // Storage: Common CollectionById (r:1 w:0) - // Storage: RmrkEquip InernalPartId (r:1 w:0) - // Storage: Nonfungible TokenProperties (r:1 w:1) - fn equippable() -> Weight { - Weight::from_ref_time(32_526_000) - .saturating_add(T::DbWeight::get().reads(4 as u64)) - .saturating_add(T::DbWeight::get().writes(1 as u64)) - } -} - -// For backwards compatibility and tests -impl WeightInfo for () { - // Storage: Common CreatedCollectionCount (r:1 w:1) - // Storage: Common DestroyedCollectionCount (r:1 w:0) - // Storage: System Account (r:2 w:2) - // Storage: Common CollectionPropertyPermissions (r:0 w:1) - // Storage: Common CollectionProperties (r:0 w:1) - // Storage: Common CollectionById (r:0 w:1) - // Storage: RmrkEquip InernalPartId (r:1 w:1) - // Storage: Nonfungible TokensMinted (r:1 w:1) - // Storage: Nonfungible AccountBalance (r:1 w:1) - // Storage: Nonfungible TokenProperties (r:1 w:1) - // Storage: Nonfungible TokenData (r:0 w:1) - // Storage: Nonfungible Owned (r:0 w:1) - fn create_base(b: u32, ) -> Weight { - Weight::from_ref_time(58_417_000) - // Standard Error: 27_000 - .saturating_add(Weight::from_ref_time(20_439_000).saturating_mul(b as u64)) - .saturating_add(RocksDbWeight::get().reads(6 as u64)) - .saturating_add(RocksDbWeight::get().reads((2 as u64).saturating_mul(b as u64))) - .saturating_add(RocksDbWeight::get().writes(8 as u64)) - .saturating_add(RocksDbWeight::get().writes((4 as u64).saturating_mul(b as u64))) - } - // Storage: Common CollectionProperties (r:1 w:0) - // Storage: Common CollectionById (r:1 w:0) - // Storage: RmrkEquip BaseHasDefaultTheme (r:1 w:0) - // Storage: Nonfungible TokensMinted (r:1 w:1) - // Storage: Nonfungible AccountBalance (r:1 w:1) - // Storage: Nonfungible TokenProperties (r:1 w:1) - // Storage: Nonfungible TokenData (r:0 w:1) - // Storage: Nonfungible Owned (r:0 w:1) - fn theme_add(b: u32, ) -> Weight { - Weight::from_ref_time(46_005_000) - // Standard Error: 42_000 - .saturating_add(Weight::from_ref_time(2_922_000).saturating_mul(b as u64)) - .saturating_add(RocksDbWeight::get().reads(6 as u64)) - .saturating_add(RocksDbWeight::get().writes(5 as u64)) - } - // Storage: Common CollectionProperties (r:1 w:0) - // Storage: Common CollectionById (r:1 w:0) - // Storage: RmrkEquip InernalPartId (r:1 w:0) - // Storage: Nonfungible TokenProperties (r:1 w:1) - fn equippable() -> Weight { - Weight::from_ref_time(32_526_000) - .saturating_add(RocksDbWeight::get().reads(4 as u64)) - .saturating_add(RocksDbWeight::get().writes(1 as u64)) - } -} --- a/pallets/refungible/src/erc.rs +++ b/pallets/refungible/src/erc.rs @@ -48,8 +48,8 @@ }; use crate::{ - AccountBalance, Balance, Config, CreateItemData, Pallet, RefungibleHandle, SelfWeightOf, - TokenProperties, TokensMinted, TotalSupply, weights::WeightInfo, + AccountBalance, Balance, Config, CreateItemData, Pallet, RefungibleHandle, + TokenProperties, TokensMinted, TotalSupply, SelfWeightOf, weights::WeightInfo, }; frontier_contract! { --- a/pallets/refungible/src/erc_token.rs +++ b/pallets/refungible/src/erc_token.rs @@ -28,6 +28,7 @@ use pallet_common::{ erc::{CommonEvmHandler, PrecompileResult}, eth::{collection_id_to_address, CrossAddress}, + CommonWeightInfo, }; use pallet_evm::{account::CrossAccountId, PrecompileHandle}; use pallet_evm_coder_substrate::{ @@ -39,7 +40,7 @@ use sp_core::U256; use up_data_structs::TokenId; -use crate::{Allowance, Balance, Config, Pallet, RefungibleHandle, TotalSupply}; +use crate::{Allowance, Balance, Config, Pallet, RefungibleHandle, TotalSupply, common::CommonWeights, SelfWeightOf, weights::WeightInfo}; /// Refungible token handle contains information about token's collection and id /// --- a/primitives/data-structs/Cargo.toml +++ b/primitives/data-structs/Cargo.toml @@ -15,7 +15,6 @@ derivative = { workspace = true } frame-support = { workspace = true } pallet-evm = { workspace = true } -rmrk-traits = { workspace = true } scale-info = { workspace = true } serde = { workspace = true, optional = true } sp-core = { workspace = true } @@ -33,7 +32,6 @@ "codec/std", "frame-support/std", "pallet-evm/std", - "rmrk-traits/std", "serde/std", "serde1", "sp-core/std", --- a/primitives/data-structs/src/lib.rs +++ b/primitives/data-structs/src/lib.rs @@ -27,33 +27,18 @@ use frame_support::{ storage::{bounded_btree_map::BoundedBTreeMap, bounded_btree_set::BoundedBTreeSet}, traits::Get, - parameter_types, }; #[cfg(feature = "serde")] use serde::{Serialize, Deserialize}; use sp_core::U256; -use sp_runtime::{ArithmeticError, sp_std::prelude::Vec, Permill}; +use sp_runtime::{ArithmeticError, sp_std::prelude::Vec}; use codec::{Decode, Encode, EncodeLike, MaxEncodedLen}; use bondrewd::Bitfields; use frame_support::{BoundedVec, traits::ConstU32}; use derivative::Derivative; use scale_info::TypeInfo; - -// RMRK -use rmrk_traits::{ - CollectionInfo, NftInfo, ResourceInfo, PropertyInfo, BaseInfo, PartType, Theme, ThemeProperty, - ResourceTypes, BasicResource, ComposableResource, SlotResource, EquippableList, -}; -pub use rmrk_traits::{ - primitives::{ - CollectionId as RmrkCollectionId, NftId as RmrkNftId, BaseId as RmrkBaseId, - SlotId as RmrkSlotId, PartId as RmrkPartId, ResourceId as RmrkResourceId, - }, - NftChild as RmrkNftChild, AccountIdOrCollectionNftTuple as RmrkAccountIdOrCollectionNftTuple, - FixedPart as RmrkFixedPart, SlotPart as RmrkSlotPart, -}; mod bondrewd_codec; mod bounded; @@ -174,6 +159,12 @@ impl EncodeLike for CollectionId {} impl EncodeLike for u32 {} +impl From for CollectionId { + fn from(value: u32) -> Self { + Self(value) + } +} + /// Token id. #[derive( Encode, @@ -1367,73 +1358,3 @@ Properties::new(MAX_TOKEN_PROPERTIES_SIZE) } } - -// RMRK -// todo document? -parameter_types! { - #[derive(PartialEq, TypeInfo)] - pub const RmrkStringLimit: u32 = 128; - #[derive(PartialEq)] - pub const RmrkCollectionSymbolLimit: u32 = MAX_TOKEN_PREFIX_LENGTH; - #[derive(PartialEq)] - pub const RmrkResourceSymbolLimit: u32 = 10; - #[derive(PartialEq)] - pub const RmrkBaseSymbolLimit: u32 = MAX_TOKEN_PREFIX_LENGTH; - #[derive(PartialEq)] - pub const RmrkKeyLimit: u32 = 32; - #[derive(PartialEq)] - pub const RmrkValueLimit: u32 = 256; - #[derive(PartialEq)] - pub const RmrkMaxCollectionsEquippablePerPart: u32 = 100; - #[derive(PartialEq)] - pub const MaxPropertiesPerTheme: u32 = 5; - #[derive(PartialEq)] - pub const RmrkPartsLimit: u32 = 25; - #[derive(PartialEq)] - pub const RmrkMaxPriorities: u32 = 25; - #[derive(PartialEq)] - pub const MaxResourcesOnMint: u32 = 100; -} - -impl From for CollectionId { - fn from(id: RmrkCollectionId) -> Self { - Self(id) - } -} - -impl From for TokenId { - fn from(id: RmrkNftId) -> Self { - Self(id) - } -} - -pub type RmrkCollectionInfo = - CollectionInfo; -pub type RmrkInstanceInfo = NftInfo; -pub type RmrkResourceInfo = ResourceInfo; -pub type RmrkPropertyInfo = PropertyInfo; -pub type RmrkBaseInfo = BaseInfo; -pub type BoundedEquippableCollectionIds = - BoundedVec; -pub type RmrkPartType = PartType; -pub type RmrkEquippableList = EquippableList; -pub type RmrkThemeProperty = ThemeProperty; -pub type RmrkTheme = Theme>; -pub type RmrkBoundedTheme = Theme>; -pub type RmrkResourceTypes = ResourceTypes; - -pub type RmrkBasicResource = BasicResource; -pub type RmrkComposableResource = ComposableResource; -pub type RmrkSlotResource = SlotResource; - -pub type RmrkString = BoundedVec; -pub type RmrkCollectionSymbol = BoundedVec; -pub type RmrkBaseSymbol = BoundedVec; -pub type RmrkKeyString = BoundedVec; -pub type RmrkValueString = BoundedVec; -pub type RmrkBoundedResource = BoundedVec; -pub type RmrkBoundedParts = BoundedVec; // todo make sure it is needed - -pub type RmrkRpcString = Vec; -pub type RmrkThemeName = RmrkRpcString; -pub type RmrkPropertyKey = RmrkRpcString; --- a/primitives/rmrk-rpc/CHANGELOG.md +++ /dev/null @@ -1,10 +0,0 @@ - -## [v0.0.2] 2022-08-16 - -### Other changes - -- build: Upgrade polkadot to v0.9.27 2c498572636f2b34d53b1c51b7283a761a7dc90a - -- build: Upgrade polkadot to v0.9.26 85515e54c4ca1b82a2630034e55dcc804c643bf8 - -- build: Upgrade polkadot to v0.9.25 cdfb9bdc7b205ff1b5134f034ef9973d769e5e6b \ No newline at end of file --- a/primitives/rmrk-rpc/Cargo.toml +++ /dev/null @@ -1,16 +0,0 @@ -[package] -edition = "2021" -license = "" -name = "rmrk-rpc" -version = "0.0.2" - -[dependencies] -codec = { workspace = true } -rmrk-traits = { workspace = true } -sp-api = { workspace = true } -sp-runtime = { workspace = true } -sp-std = { workspace = true } - -[features] -default = ["std"] -std = ["codec/std", "rmrk-traits/std", "sp-api/std", "sp-runtime/std", "sp-std/std"] --- a/primitives/rmrk-rpc/src/lib.rs +++ /dev/null @@ -1,79 +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 . - -#![cfg_attr(not(feature = "std"), no_std)] - -use sp_api::{Encode, Decode}; -use sp_std::vec::Vec; -use sp_runtime::DispatchError; -use rmrk_traits::{primitives::*, NftChild}; - -pub type Result = core::result::Result; - -pub type RpcString = Vec; - -pub type PropertyKey = RpcString; - -pub type ThemeName = RpcString; - -sp_api::decl_runtime_apis! { - pub trait RmrkApi< - AccountId, - CollectionInfo, - NftInfo, - ResourceInfo, - PropertyInfo, - BaseInfo, - PartType, - Theme - > - where - AccountId: Encode, - CollectionInfo: Decode, - NftInfo: Decode, - ResourceInfo: Decode, - PropertyInfo: Decode, - BaseInfo: Decode, - PartType: Decode, - Theme: Decode, - { - fn last_collection_idx() -> Result; - - fn collection_by_id(id: CollectionId) -> Result>; - - fn nft_by_id(collection_id: CollectionId, nft_id: NftId) -> Result>; - - fn account_tokens(account_id: AccountId, collection_id: CollectionId) -> Result>; - - fn nft_children(collection_id: CollectionId, nft_id: NftId) -> Result>; - - fn collection_properties(collection_id: CollectionId, filter_keys: Option>) -> Result>; - - fn nft_properties(collection_id: CollectionId, nft_id: NftId, filter_keys: Option>) -> Result>; - - fn nft_resources(collection_id: CollectionId, nft_id: NftId) -> Result>; - - fn nft_resource_priority(collection_id: CollectionId, nft_id: NftId, resource_id: ResourceId) -> Result>; - - fn base(base_id: BaseId) -> Result>; - - fn base_parts(base_id: BaseId) -> Result>; - - fn theme_names(base_id: BaseId) -> Result>; - - fn theme(base_id: BaseId, theme_name: ThemeName, filter_keys: Option>) -> Result>; - } -} --- a/primitives/rmrk-traits/Cargo.toml +++ /dev/null @@ -1,21 +0,0 @@ -[package] -authors = ["RMRK Team", "Unique Network "] -description = "RMRK proxy data structs definitions" -edition = "2021" -homepage = "https://unique.network" -license = 'GPLv3' -name = "rmrk-traits" -repository = 'https://github.com/UniqueNetwork/unique-chain' -version = "0.1.0" - -[dependencies] -# Note: `package = "parity-scale-codec"` must be supplied since the `Encode` macro searches for it. -codec = { workspace = true, package = "parity-scale-codec" } - -scale-info = { workspace = true } -serde = { workspace = true, optional = true } - -[features] -default = ["std"] -serde1 = ["serde/alloc"] -std = ["codec/std", "serde/std", "serde1"] --- a/primitives/rmrk-traits/src/base.rs +++ /dev/null @@ -1,34 +0,0 @@ -// Copyright (C) 2021-2022 RMRK -// This file is part of rmrk-substrate. -// License: Apache 2.0 modified by RMRK, see https://github.com/rmrk-team/rmrk-substrate/blob/main/LICENSE - -use codec::{Decode, Encode, MaxEncodedLen}; -use scale_info::TypeInfo; - -#[cfg(feature = "std")] -use serde::Serialize; - -#[cfg(feature = "std")] -use crate::serialize; - -#[cfg_attr(feature = "std", derive(PartialEq, Eq, Serialize))] -#[derive(Encode, Decode, Debug, TypeInfo, MaxEncodedLen)] -#[cfg_attr( - feature = "std", - serde(bound = r#" - AccountId: Serialize, - BoundedString: AsRef<[u8]> - "#) -)] -pub struct BaseInfo { - /// Original creator of the Base - pub issuer: AccountId, - - /// Specifies how an NFT should be rendered, ie "svg" - #[cfg_attr(feature = "std", serde(with = "serialize::vec"))] - pub base_type: BoundedString, - - /// User provided symbol during Base creation - #[cfg_attr(feature = "std", serde(with = "serialize::vec"))] - pub symbol: BoundedString, -} --- a/primitives/rmrk-traits/src/collection.rs +++ /dev/null @@ -1,35 +0,0 @@ -// Copyright (C) 2021-2022 RMRK -// This file is part of rmrk-substrate. -// License: Apache 2.0 modified by RMRK, see https://github.com/rmrk-team/rmrk-substrate/blob/main/LICENSE - -use codec::{Decode, Encode, MaxEncodedLen}; -use scale_info::TypeInfo; - -#[cfg(feature = "std")] -use serde::Serialize; - -#[cfg(feature = "std")] -use crate::serialize; - -#[cfg_attr(feature = "std", derive(PartialEq, Eq, Serialize))] -#[derive(Encode, Decode, Debug, TypeInfo, MaxEncodedLen)] -#[cfg_attr( - feature = "std", - serde(bound = r#" - AccountId: Serialize, - BoundedString: AsRef<[u8]>, - BoundedSymbol: AsRef<[u8]> - "#) -)] -pub struct CollectionInfo { - /// Current bidder and bid price. - pub issuer: AccountId, - - #[cfg_attr(feature = "std", serde(with = "serialize::vec"))] - pub metadata: BoundedString, - pub max: Option, - - #[cfg_attr(feature = "std", serde(with = "serialize::vec"))] - pub symbol: BoundedSymbol, - pub nfts_count: u32, -} --- a/primitives/rmrk-traits/src/lib.rs +++ /dev/null @@ -1,33 +0,0 @@ -// Copyright (C) 2021-2022 RMRK -// This file is part of rmrk-substrate. -// License: Apache 2.0 modified by RMRK, see https://github.com/rmrk-team/rmrk-substrate/blob/main/LICENSE - -#![cfg_attr(not(feature = "std"), no_std)] - -pub mod base; -pub mod collection; -pub mod nft; -pub mod part; -pub mod property; -pub mod resource; -pub mod theme; - -#[cfg(feature = "std")] -mod serialize; - -pub use base::BaseInfo; -pub use part::{EquippableList, FixedPart, PartType, SlotPart}; -pub use theme::{Theme, ThemeProperty}; -pub use collection::CollectionInfo; -pub use nft::{AccountIdOrCollectionNftTuple, NftInfo, RoyaltyInfo, NftChild}; -pub use property::PropertyInfo; -pub use resource::{BasicResource, ComposableResource, ResourceInfo, ResourceTypes, SlotResource}; -pub mod primitives { - pub type CollectionId = u32; - pub type ResourceId = u32; - pub type NftId = u32; - pub type BaseId = u32; - pub type SlotId = u32; - pub type PartId = u32; - pub type ZIndex = u32; -} --- a/primitives/rmrk-traits/src/nft.rs +++ /dev/null @@ -1,65 +0,0 @@ -// Copyright (C) 2021-2022 RMRK -// This file is part of rmrk-substrate. -// License: Apache 2.0 modified by RMRK, see https://github.com/rmrk-team/rmrk-substrate/blob/main/LICENSE - -use codec::{Decode, Encode, MaxEncodedLen}; -use scale_info::TypeInfo; - -#[cfg(feature = "std")] -use serde::Serialize; - -#[cfg(feature = "std")] -use crate::serialize; - -use crate::primitives::*; - -#[derive(Encode, Decode, Eq, PartialEq, Copy, Clone, Debug, TypeInfo, MaxEncodedLen)] -#[cfg_attr(feature = "std", derive(Serialize))] -pub enum AccountIdOrCollectionNftTuple { - AccountId(AccountId), - CollectionAndNftTuple(CollectionId, NftId), -} - -/// Royalty information (recipient and amount) -#[cfg_attr(feature = "std", derive(PartialEq, Eq, Serialize))] -#[derive(Encode, Decode, Debug, TypeInfo, MaxEncodedLen)] -pub struct RoyaltyInfo { - /// Recipient (AccountId) of the royalty - pub recipient: AccountId, - /// Amount (Permill) of the royalty - pub amount: RoyaltyAmount, -} - -/// Nft info. -#[cfg_attr(feature = "std", derive(PartialEq, Eq, Serialize))] -#[derive(Encode, Decode, Debug, TypeInfo, MaxEncodedLen)] -#[cfg_attr( - feature = "std", - serde(bound = r#" - AccountId: Serialize, - RoyaltyAmount: Serialize, - BoundedString: AsRef<[u8]> - "#) -)] -pub struct NftInfo { - /// The owner of the NFT, can be either an Account or a tuple (CollectionId, NftId) - pub owner: AccountIdOrCollectionNftTuple, - /// Royalty (optional) - pub royalty: Option>, - - /// Arbitrary data about an instance, e.g. IPFS hash - #[cfg_attr(feature = "std", serde(with = "serialize::vec"))] - pub metadata: BoundedString, - - /// Equipped state - pub equipped: bool, - /// Pending state (if sent to NFT) - pub pending: bool, -} - -#[cfg_attr(feature = "std", derive(PartialEq, Eq, Serialize))] -#[derive(Encode, Decode, TypeInfo, MaxEncodedLen)] -pub struct NftChild { - pub collection_id: CollectionId, - pub nft_id: NftId, -} --- a/primitives/rmrk-traits/src/part.rs +++ /dev/null @@ -1,93 +0,0 @@ -// Copyright (C) 2021-2022 RMRK -// This file is part of rmrk-substrate. -// License: Apache 2.0 modified by RMRK, see https://github.com/rmrk-team/rmrk-substrate/blob/main/LICENSE - -use codec::{Decode, Encode, MaxEncodedLen}; -use scale_info::TypeInfo; - -#[cfg(feature = "std")] -use serde::Serialize; - -#[cfg(feature = "std")] -use crate::serialize; - -use crate::primitives::*; - -#[cfg_attr(feature = "std", derive(Serialize))] -#[derive(Encode, Decode, Debug, TypeInfo, Clone, PartialEq, Eq, MaxEncodedLen)] -#[cfg_attr(feature = "std", serde(bound = "BoundedString: AsRef<[u8]>"))] -pub struct FixedPart { - pub id: PartId, - pub z: ZIndex, - - #[cfg_attr(feature = "std", serde(with = "serialize::vec"))] - pub src: BoundedString, -} - -#[cfg_attr(feature = "std", derive(Serialize))] -#[derive(Encode, Decode, Debug, TypeInfo, Clone, PartialEq, Eq, MaxEncodedLen)] -#[cfg_attr( - feature = "std", - serde(bound = "BoundedCollectionList: AsRef<[CollectionId]>") -)] -pub enum EquippableList { - All, - Empty, - Custom(#[cfg_attr(feature = "std", serde(with = "serialize::vec"))] BoundedCollectionList), -} - -#[cfg_attr(feature = "std", derive(Serialize))] -#[derive(Encode, Decode, Debug, TypeInfo, Clone, PartialEq, Eq, MaxEncodedLen)] -#[cfg_attr( - feature = "std", - serde(bound = r#" - BoundedString: AsRef<[u8]>, - BoundedCollectionList: AsRef<[CollectionId]> - "#) -)] -pub struct SlotPart { - pub id: PartId, - pub equippable: EquippableList, - - #[cfg_attr(feature = "std", serde(with = "serialize::vec"))] - pub src: BoundedString, - - pub z: ZIndex, -} - -#[cfg_attr(feature = "std", derive(Serialize))] -#[derive(Encode, Decode, Debug, TypeInfo, Clone, PartialEq, Eq, MaxEncodedLen)] -#[cfg_attr( - feature = "std", - serde(bound = r#" - BoundedString: AsRef<[u8]>, - BoundedCollectionList: AsRef<[CollectionId]> - "#) -)] -pub enum PartType { - FixedPart(FixedPart), - SlotPart(SlotPart), -} - -impl PartType { - pub fn id(&self) -> PartId { - match self { - Self::FixedPart(part) => part.id, - Self::SlotPart(part) => part.id, - } - } - - pub fn src(&self) -> &BoundedString { - match self { - Self::FixedPart(part) => &part.src, - Self::SlotPart(part) => &part.src, - } - } - - pub fn z_index(&self) -> ZIndex { - match self { - Self::FixedPart(part) => part.z, - Self::SlotPart(part) => part.z, - } - } -} --- a/primitives/rmrk-traits/src/property.rs +++ /dev/null @@ -1,31 +0,0 @@ -// Copyright (C) 2021-2022 RMRK -// This file is part of rmrk-substrate. -// License: Apache 2.0 modified by RMRK, see https://github.com/rmrk-team/rmrk-substrate/blob/main/LICENSE - -use codec::{Decode, Encode}; -use scale_info::TypeInfo; - -#[cfg(feature = "std")] -use serde::Serialize; - -#[cfg(feature = "std")] -use crate::serialize; - -#[cfg_attr(feature = "std", derive(Serialize))] -#[derive(Encode, Decode, PartialEq, TypeInfo)] -#[cfg_attr( - feature = "std", - serde(bound = r#" - BoundedKey: AsRef<[u8]>, - BoundedValue: AsRef<[u8]> - "#) -)] -pub struct PropertyInfo { - /// Key of the property - #[cfg_attr(feature = "std", serde(with = "serialize::vec"))] - pub key: BoundedKey, - - /// Value of the property - #[cfg_attr(feature = "std", serde(with = "serialize::vec"))] - pub value: BoundedValue, -} --- a/primitives/rmrk-traits/src/resource.rs +++ /dev/null @@ -1,168 +0,0 @@ -// Copyright (C) 2021-2022 RMRK -// This file is part of rmrk-substrate. -// License: Apache 2.0 modified by RMRK, see https://github.com/rmrk-team/rmrk-substrate/blob/main/LICENSE - -use codec::{Decode, Encode, MaxEncodedLen}; -use scale_info::TypeInfo; - -#[cfg(feature = "std")] -use serde::Serialize; - -#[cfg(feature = "std")] -use crate::serialize; - -use crate::primitives::*; - -#[derive(Encode, Decode, Eq, PartialEq, Clone, Debug, TypeInfo, MaxEncodedLen)] -#[cfg_attr(feature = "std", derive(Serialize))] -#[cfg_attr(feature = "std", serde(bound = "BoundedString: AsRef<[u8]>"))] -pub struct BasicResource { - /// If the resource is Media, the base property is absent. Media src should be a URI like an - /// IPFS hash. - #[cfg_attr(feature = "std", serde(with = "serialize::opt_vec"))] - pub src: Option, - - /// Reference to IPFS location of metadata - #[cfg_attr(feature = "std", serde(with = "serialize::opt_vec"))] - pub metadata: Option, - - /// Optional location or identier of license - #[cfg_attr(feature = "std", serde(with = "serialize::opt_vec"))] - pub license: Option, - - /// If the resource has the thumb property, this will be a URI to a thumbnail of the given - /// resource. For example, if we have a composable NFT like a Kanaria bird, the resource is - /// complex and too detailed to show in a search-results page or a list. Also, if a bird owns - /// another bird, showing the full render of one bird inside the other's inventory might be a - /// bit of a strain on the browser. For this reason, the thumb value can contain a URI to an - /// image that is lighter and faster to load but representative of this resource. - #[cfg_attr(feature = "std", serde(with = "serialize::opt_vec"))] - pub thumb: Option, -} - -#[derive(Encode, Decode, Eq, PartialEq, Clone, Debug, TypeInfo, MaxEncodedLen)] -#[cfg_attr(feature = "std", derive(Serialize))] -#[cfg_attr( - feature = "std", - serde(bound = r#" - BoundedString: AsRef<[u8]>, - BoundedParts: AsRef<[PartId]> - "#) -)] -pub struct ComposableResource { - /// If a resource is composed, it will have an array of parts that compose it - #[cfg_attr(feature = "std", serde(with = "serialize::vec"))] - pub parts: BoundedParts, - - /// A Base is uniquely identified by the combination of the word `base`, its minting block - /// number, and user provided symbol during Base creation, glued by dashes `-`, e.g. - /// base-4477293-kanaria_superbird. - pub base: BaseId, - - /// If the resource is Media, the base property is absent. Media src should be a URI like an - /// IPFS hash. - #[cfg_attr(feature = "std", serde(with = "serialize::opt_vec"))] - pub src: Option, - - /// Reference to IPFS location of metadata - #[cfg_attr(feature = "std", serde(with = "serialize::opt_vec"))] - pub metadata: Option, - - /// If the resource has the slot property, it was designed to fit into a specific Base's slot. - /// The baseslot will be composed of two dot-delimited values, like so: - /// "base-4477293-kanaria_superbird.machine_gun_scope". This means: "This resource is - /// compatible with the machine_gun_scope slot of base base-4477293-kanaria_superbird - - /// Optional location or identier of license - #[cfg_attr(feature = "std", serde(with = "serialize::opt_vec"))] - pub license: Option, - - /// If the resource has the thumb property, this will be a URI to a thumbnail of the given - /// resource. For example, if we have a composable NFT like a Kanaria bird, the resource is - /// complex and too detailed to show in a search-results page or a list. Also, if a bird owns - /// another bird, showing the full render of one bird inside the other's inventory might be a - /// bit of a strain on the browser. For this reason, the thumb value can contain a URI to an - /// image that is lighter and faster to load but representative of this resource. - #[cfg_attr(feature = "std", serde(with = "serialize::opt_vec"))] - pub thumb: Option, -} - -#[derive(Encode, Decode, Eq, PartialEq, Clone, Debug, TypeInfo, MaxEncodedLen)] -#[cfg_attr(feature = "std", derive(Serialize))] -#[cfg_attr(feature = "std", serde(bound = "BoundedString: AsRef<[u8]>"))] -pub struct SlotResource { - /// A Base is uniquely identified by the combination of the word `base`, its minting block - /// number, and user provided symbol during Base creation, glued by dashes `-`, e.g. - /// base-4477293-kanaria_superbird. - pub base: BaseId, - - /// If the resource is Media, the base property is absent. Media src should be a URI like an - /// IPFS hash. - #[cfg_attr(feature = "std", serde(with = "serialize::opt_vec"))] - pub src: Option, - - /// Reference to IPFS location of metadata - #[cfg_attr(feature = "std", serde(with = "serialize::opt_vec"))] - pub metadata: Option, - - /// If the resource has the slot property, it was designed to fit into a specific Base's slot. - /// The baseslot will be composed of two dot-delimited values, like so: - /// "base-4477293-kanaria_superbird.machine_gun_scope". This means: "This resource is - /// compatible with the machine_gun_scope slot of base base-4477293-kanaria_superbird - pub slot: SlotId, - - /// The license field, if present, should contain a link to a license (IPFS or static HTTP - /// url), or an identifier, like RMRK_nocopy or ipfs://ipfs/someHashOfLicense. - #[cfg_attr(feature = "std", serde(with = "serialize::opt_vec"))] - pub license: Option, - - /// If the resource has the thumb property, this will be a URI to a thumbnail of the given - /// resource. For example, if we have a composable NFT like a Kanaria bird, the resource is - /// complex and too detailed to show in a search-results page or a list. Also, if a bird owns - /// another bird, showing the full render of one bird inside the other's inventory might be a - /// bit of a strain on the browser. For this reason, the thumb value can contain a URI to an - /// image that is lighter and faster to load but representative of this resource. - #[cfg_attr(feature = "std", serde(with = "serialize::opt_vec"))] - pub thumb: Option, -} - -#[derive(Encode, Decode, Eq, PartialEq, Clone, Debug, TypeInfo, MaxEncodedLen)] -#[cfg_attr(feature = "std", derive(Serialize))] -#[cfg_attr( - feature = "std", - serde(bound = r#" - BoundedString: AsRef<[u8]>, - BoundedParts: AsRef<[PartId]> - "#) -)] -pub enum ResourceTypes { - Basic(BasicResource), - Composable(ComposableResource), - Slot(SlotResource), -} - -#[derive(Encode, Decode, Eq, PartialEq, Clone, Debug, TypeInfo, MaxEncodedLen)] -#[cfg_attr(feature = "std", derive(Serialize))] -#[cfg_attr( - feature = "std", - serde(bound = r#" - BoundedString: AsRef<[u8]>, - BoundedParts: AsRef<[PartId]> - "#) -)] -pub struct ResourceInfo { - /// ID is a unique identifier for a resource across all those of a single NFT. - /// The combination of a collection ID, an NFT ID, and the resource ID must be - /// unique across the entire RMRK ecosystem. - //#[cfg_attr(feature = "std", serde(with = "serialize::vec"))] - pub id: ResourceId, - - /// Resource type and the accordingly structured data stored - pub resource: ResourceTypes, - - /// If resource is sent to non-rootowned NFT, pending will be false and need to be accepted - pub pending: bool, - - /// If resource removal request is sent by non-rootowned NFT, pending will be true and need to be accepted - pub pending_removal: bool, -} --- a/primitives/rmrk-traits/src/serialize.rs +++ /dev/null @@ -1,35 +0,0 @@ -// Copyright (C) 2021-2022 RMRK -// This file is part of rmrk-substrate. -// License: Apache 2.0 modified by RMRK, see https://github.com/rmrk-team/rmrk-substrate/blob/main/LICENSE - -use core::convert::AsRef; -use serde::ser::{self, Serialize}; - -pub mod vec { - use super::*; - - pub fn serialize(value: &C, serializer: D) -> Result - where - D: ser::Serializer, - V: Serialize, - C: AsRef<[V]>, - { - value.as_ref().serialize(serializer) - } -} - -pub mod opt_vec { - use super::*; - - pub fn serialize(value: &Option, serializer: D) -> Result - where - D: ser::Serializer, - V: Serialize, - C: AsRef<[V]>, - { - match value { - Some(value) => super::vec::serialize(value, serializer), - None => serializer.serialize_none(), - } - } -} --- a/primitives/rmrk-traits/src/theme.rs +++ /dev/null @@ -1,46 +0,0 @@ -// Copyright (C) 2021-2022 RMRK -// This file is part of rmrk-substrate. -// License: Apache 2.0 modified by RMRK, see https://github.com/rmrk-team/rmrk-substrate/blob/main/LICENSE - -use codec::{Decode, Encode}; -use scale_info::TypeInfo; - -#[cfg(feature = "std")] -use serde::Serialize; - -#[cfg(feature = "std")] -use crate::serialize; - -#[cfg_attr(feature = "std", derive(Eq, Serialize))] -#[derive(Encode, Decode, Debug, TypeInfo, Clone, PartialEq)] -#[cfg_attr( - feature = "std", - serde(bound = r#" - BoundedString: AsRef<[u8]>, - PropertyList: AsRef<[ThemeProperty]>, - "#) -)] -pub struct Theme { - /// Name of the theme - #[cfg_attr(feature = "std", serde(with = "serialize::vec"))] - pub name: BoundedString, - - /// Theme properties - #[cfg_attr(feature = "std", serde(with = "serialize::vec"))] - pub properties: PropertyList, - /// Inheritability - pub inherit: bool, -} - -#[cfg_attr(feature = "std", derive(Eq, Serialize))] -#[derive(Encode, Decode, Debug, TypeInfo, Clone, PartialEq)] -#[cfg_attr(feature = "std", serde(bound = "BoundedString: AsRef<[u8]>"))] -pub struct ThemeProperty { - /// Key of the property - #[cfg_attr(feature = "std", serde(with = "serialize::vec"))] - pub key: BoundedString, - - /// Value of the property - #[cfg_attr(feature = "std", serde(with = "serialize::vec"))] - pub value: BoundedString, -} --- a/runtime/common/config/pallets/mod.rs +++ b/runtime/common/config/pallets/mod.rs @@ -35,9 +35,6 @@ }; use sp_arithmetic::Perbill; -#[cfg(feature = "rmrk")] -pub mod rmrk; - #[cfg(feature = "scheduler")] pub mod scheduler; --- a/runtime/common/config/pallets/rmrk.rs +++ /dev/null @@ -1,27 +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 . - -use crate::{Runtime, RuntimeEvent}; - -impl pallet_proxy_rmrk_core::Config for Runtime { - type WeightInfo = pallet_proxy_rmrk_core::weights::SubstrateWeight; - type RuntimeEvent = RuntimeEvent; -} - -impl pallet_proxy_rmrk_equip::Config for Runtime { - type WeightInfo = pallet_proxy_rmrk_equip::weights::SubstrateWeight; - type RuntimeEvent = RuntimeEvent; -} --- a/runtime/common/construct_runtime.rs +++ b/runtime/common/construct_runtime.rs @@ -82,11 +82,9 @@ Nonfungible: pallet_nonfungible::{Pallet, Storage} = 69, Structure: pallet_structure::{Pallet, Call, Storage, Event} = 70, - #[cfg(feature = "rmrk")] - RmrkCore: pallet_proxy_rmrk_core::{Pallet, Call, Storage, Event} = 71, + // RmrkCore: pallet_proxy_rmrk_core::{Pallet, Call, Storage, Event} = 71, - #[cfg(feature = "rmrk")] - RmrkEquip: pallet_proxy_rmrk_equip::{Pallet, Call, Storage, Event} = 72, + // RmrkEquip: pallet_proxy_rmrk_equip::{Pallet, Call, Storage, Event} = 72, #[cfg(feature = "app-promotion")] AppPromotion: pallet_app_promotion::{Pallet, Call, Storage, Event} = 73, --- a/runtime/common/maintenance.rs +++ b/runtime/common/maintenance.rs @@ -70,11 +70,6 @@ #[cfg(feature = "scheduler")] RuntimeCall::Scheduler(_) => Err(TransactionValidityError::Invalid(InvalidTransaction::Call)), - #[cfg(feature = "rmrk")] - RuntimeCall::RmrkCore(_) | RuntimeCall::RmrkEquip(_) => { - Err(TransactionValidityError::Invalid(InvalidTransaction::Call)) - } - #[cfg(feature = "app-promotion")] RuntimeCall::AppPromotion(_) => { Err(TransactionValidityError::Invalid(InvalidTransaction::Call)) --- a/runtime/common/runtime_apis.rs +++ b/runtime/common/runtime_apis.rs @@ -231,149 +231,6 @@ } } - impl rmrk_rpc::RmrkApi< - Block, - AccountId, - RmrkCollectionInfo, - RmrkInstanceInfo, - RmrkResourceInfo, - RmrkPropertyInfo, - RmrkBaseInfo, - RmrkPartType, - RmrkTheme - > for Runtime { - fn last_collection_idx() -> Result { - #[cfg(feature = "rmrk")] - return pallet_proxy_rmrk_core::rpc::last_collection_idx::(); - - #[cfg(not(feature = "rmrk"))] - return unsupported!(); - } - - #[allow(unused_variables)] - fn collection_by_id(collection_id: RmrkCollectionId) -> Result>, DispatchError> { - #[cfg(feature = "rmrk")] - return pallet_proxy_rmrk_core::rpc::collection_by_id::(collection_id); - - #[cfg(not(feature = "rmrk"))] - return unsupported!(); - } - - #[allow(unused_variables)] - fn nft_by_id(collection_id: RmrkCollectionId, nft_by_id: RmrkNftId) -> Result>, DispatchError> { - #[cfg(feature = "rmrk")] - return pallet_proxy_rmrk_core::rpc::nft_by_id::(collection_id, nft_by_id); - - #[cfg(not(feature = "rmrk"))] - return unsupported!(); - } - - #[allow(unused_variables)] - fn account_tokens(account_id: AccountId, collection_id: RmrkCollectionId) -> Result, DispatchError> { - #[cfg(feature = "rmrk")] - return pallet_proxy_rmrk_core::rpc::account_tokens::(account_id, collection_id); - - #[cfg(not(feature = "rmrk"))] - return unsupported!(); - } - - #[allow(unused_variables)] - fn nft_children(collection_id: RmrkCollectionId, nft_id: RmrkNftId) -> Result, DispatchError> { - #[cfg(feature = "rmrk")] - return pallet_proxy_rmrk_core::rpc::nft_children::(collection_id, nft_id); - - #[cfg(not(feature = "rmrk"))] - return unsupported!(); - } - - #[allow(unused_variables)] - fn collection_properties( - collection_id: RmrkCollectionId, - filter_keys: Option> - ) -> Result, DispatchError> { - #[cfg(feature = "rmrk")] - return pallet_proxy_rmrk_core::rpc::collection_properties::(collection_id, filter_keys); - - #[cfg(not(feature = "rmrk"))] - return unsupported!(); - } - - #[allow(unused_variables)] - fn nft_properties( - collection_id: RmrkCollectionId, - nft_id: RmrkNftId, - filter_keys: Option> - ) -> Result, DispatchError> { - #[cfg(feature = "rmrk")] - return pallet_proxy_rmrk_core::rpc::nft_properties::(collection_id, nft_id, filter_keys); - - #[cfg(not(feature = "rmrk"))] - return unsupported!(); - } - - #[allow(unused_variables)] - fn nft_resources(collection_id: RmrkCollectionId,nft_id: RmrkNftId) -> Result, DispatchError> { - #[cfg(feature = "rmrk")] - return pallet_proxy_rmrk_core::rpc::nft_resources::(collection_id, nft_id); - - #[cfg(not(feature = "rmrk"))] - return unsupported!(); - } - - #[allow(unused_variables)] - fn nft_resource_priority( - collection_id: RmrkCollectionId, - nft_id: RmrkNftId, - resource_id: RmrkResourceId - ) -> Result, DispatchError> { - #[cfg(feature = "rmrk")] - return pallet_proxy_rmrk_core::rpc::nft_resource_priority::(collection_id, nft_id, resource_id); - - #[cfg(not(feature = "rmrk"))] - return unsupported!(); - } - - #[allow(unused_variables)] - fn base(base_id: RmrkBaseId) -> Result>, DispatchError> { - #[cfg(feature = "rmrk")] - return pallet_proxy_rmrk_equip::rpc::base::(base_id); - - #[cfg(not(feature = "rmrk"))] - return unsupported!(); - } - - #[allow(unused_variables)] - fn base_parts(base_id: RmrkBaseId) -> Result, DispatchError> { - #[cfg(feature = "rmrk")] - return pallet_proxy_rmrk_equip::rpc::base_parts::(base_id); - - #[cfg(not(feature = "rmrk"))] - return unsupported!(); - } - - #[allow(unused_variables)] - fn theme_names(base_id: RmrkBaseId) -> Result, DispatchError> { - #[cfg(feature = "rmrk")] - return pallet_proxy_rmrk_equip::rpc::theme_names::(base_id); - - #[cfg(not(feature = "rmrk"))] - return unsupported!(); - } - - #[allow(unused_variables)] - fn theme( - base_id: RmrkBaseId, - theme_name: RmrkThemeName, - filter_keys: Option> - ) -> Result, DispatchError> { - #[cfg(feature = "rmrk")] - return pallet_proxy_rmrk_equip::rpc::theme::(base_id, theme_name, filter_keys); - - #[cfg(not(feature = "rmrk"))] - return unsupported!(); - } - } - impl sp_api::Core for Runtime { fn version() -> RuntimeVersion { VERSION @@ -701,13 +558,7 @@ #[cfg(feature = "scheduler")] list_benchmark!(list, extra, pallet_unique_scheduler_v2, Scheduler); - - #[cfg(feature = "rmrk")] - list_benchmark!(list, extra, pallet_proxy_rmrk_core, RmrkCore); - #[cfg(feature = "rmrk")] - list_benchmark!(list, extra, pallet_proxy_rmrk_equip, RmrkEquip); - #[cfg(feature = "collator-selection")] list_benchmark!(list, extra, pallet_collator_selection, CollatorSelection); @@ -771,12 +622,6 @@ #[cfg(feature = "scheduler")] add_benchmark!(params, batches, pallet_unique_scheduler_v2, Scheduler); - - #[cfg(feature = "rmrk")] - add_benchmark!(params, batches, pallet_proxy_rmrk_core, RmrkCore); - - #[cfg(feature = "rmrk")] - add_benchmark!(params, batches, pallet_proxy_rmrk_equip, RmrkEquip); #[cfg(feature = "collator-selection")] add_benchmark!(params, batches, pallet_collator_selection, CollatorSelection); --- a/runtime/opal/Cargo.toml +++ b/runtime/opal/Cargo.toml @@ -41,8 +41,6 @@ 'pallet-inflation/runtime-benchmarks', 'pallet-maintenance/runtime-benchmarks', 'pallet-nonfungible/runtime-benchmarks', - 'pallet-proxy-rmrk-core/runtime-benchmarks', - 'pallet-proxy-rmrk-equip/runtime-benchmarks', 'pallet-refungible/runtime-benchmarks', 'pallet-structure/runtime-benchmarks', 'pallet-timestamp/runtime-benchmarks', @@ -95,8 +93,6 @@ 'pallet-identity/std', 'pallet-inflation/std', 'pallet-nonfungible/std', - 'pallet-proxy-rmrk-core/std', - 'pallet-proxy-rmrk-equip/std', 'pallet-randomness-collective-flip/std', 'pallet-refungible/std', 'pallet-structure/std', @@ -108,7 +104,6 @@ 'pallet-unique-scheduler-v2/std', 'pallet-unique/std', 'parachain-info/std', - 'rmrk-rpc/std', 'serde', 'sp-api/std', 'sp-block-builder/std', @@ -176,8 +171,6 @@ 'pallet-inflation/try-runtime', 'pallet-maintenance/try-runtime', 'pallet-nonfungible/try-runtime', - 'pallet-proxy-rmrk-core/try-runtime', - 'pallet-proxy-rmrk-equip/try-runtime', 'pallet-randomness-collective-flip/try-runtime', 'pallet-refungible/try-runtime', 'pallet-structure/try-runtime', @@ -197,7 +190,6 @@ foreign-assets = [] pallet-test-utils = [] refungible = [] -rmrk = [] scheduler = [] ################################################################################ @@ -282,14 +274,11 @@ pallet-inflation = { workspace = true } pallet-maintenance = { workspace = true } pallet-nonfungible = { workspace = true } -pallet-proxy-rmrk-core = { workspace = true } -pallet-proxy-rmrk-equip = { workspace = true } pallet-refungible = { workspace = true } pallet-structure = { workspace = true } pallet-unique = { workspace = true } pallet-unique-scheduler-v2 = { workspace = true } precompile-utils-macro = { workspace = true } -rmrk-rpc = { workspace = true } scale-info = { workspace = true } up-common = { workspace = true } up-data-structs = { workspace = true } --- a/runtime/quartz/Cargo.toml +++ b/runtime/quartz/Cargo.toml @@ -42,8 +42,6 @@ 'pallet-inflation/runtime-benchmarks', 'pallet-maintenance/runtime-benchmarks', 'pallet-nonfungible/runtime-benchmarks', - 'pallet-proxy-rmrk-core/runtime-benchmarks', - 'pallet-proxy-rmrk-equip/runtime-benchmarks', 'pallet-refungible/runtime-benchmarks', 'pallet-structure/runtime-benchmarks', 'pallet-timestamp/runtime-benchmarks', @@ -95,8 +93,6 @@ 'pallet-fungible/std', 'pallet-inflation/std', 'pallet-nonfungible/std', - 'pallet-proxy-rmrk-core/std', - 'pallet-proxy-rmrk-equip/std', 'pallet-randomness-collective-flip/std', 'pallet-refungible/std', 'pallet-structure/std', @@ -107,7 +103,6 @@ 'pallet-treasury/std', 'pallet-unique/std', 'parachain-info/std', - 'rmrk-rpc/std', 'serde', 'sp-api/std', 'sp-block-builder/std', @@ -171,8 +166,6 @@ 'pallet-inflation/try-runtime', 'pallet-maintenance/try-runtime', 'pallet-nonfungible/try-runtime', - 'pallet-proxy-rmrk-core/try-runtime', - 'pallet-proxy-rmrk-equip/try-runtime', 'pallet-randomness-collective-flip/try-runtime', 'pallet-refungible/try-runtime', 'pallet-structure/try-runtime', @@ -189,7 +182,6 @@ collator-selection = [] foreign-assets = [] refungible = [] -rmrk = [] scheduler = [] ################################################################################ @@ -228,7 +220,6 @@ pallet-xcm = { workspace = true } parachain-info = { workspace = true } polkadot-parachain = { workspace = true } -rmrk-rpc = { workspace = true } smallvec = { workspace = true } sp-api = { workspace = true } sp-arithmetic = { workspace = true } @@ -260,8 +251,6 @@ pallet-identity = { workspace = true } pallet-inflation = { workspace = true } pallet-nonfungible = { workspace = true } -pallet-proxy-rmrk-core = { workspace = true } -pallet-proxy-rmrk-equip = { workspace = true } pallet-refungible = { workspace = true } pallet-structure = { workspace = true } pallet-unique = { workspace = true } --- a/runtime/unique/Cargo.toml +++ b/runtime/unique/Cargo.toml @@ -39,8 +39,6 @@ 'pallet-inflation/runtime-benchmarks', 'pallet-maintenance/runtime-benchmarks', 'pallet-nonfungible/runtime-benchmarks', - 'pallet-proxy-rmrk-core/runtime-benchmarks', - 'pallet-proxy-rmrk-equip/runtime-benchmarks', 'pallet-refungible/runtime-benchmarks', 'pallet-structure/runtime-benchmarks', 'pallet-timestamp/runtime-benchmarks', @@ -93,8 +91,6 @@ 'pallet-fungible/std', 'pallet-inflation/std', 'pallet-nonfungible/std', - 'pallet-proxy-rmrk-core/std', - 'pallet-proxy-rmrk-equip/std', 'pallet-randomness-collective-flip/std', 'pallet-refungible/std', 'pallet-structure/std', @@ -105,7 +101,6 @@ 'pallet-treasury/std', 'pallet-unique/std', 'parachain-info/std', - 'rmrk-rpc/std', 'sp-api/std', 'sp-block-builder/std', 'sp-core/std', @@ -169,8 +164,6 @@ 'pallet-inflation/try-runtime', 'pallet-maintenance/try-runtime', 'pallet-nonfungible/try-runtime', - 'pallet-proxy-rmrk-core/try-runtime', - 'pallet-proxy-rmrk-equip/try-runtime', 'pallet-randomness-collective-flip/try-runtime', 'pallet-refungible/try-runtime', 'pallet-structure/try-runtime', @@ -187,7 +180,6 @@ collator-selection = [] foreign-assets = [] refungible = [] -rmrk = [] scheduler = [] ################################################################################ @@ -255,12 +247,9 @@ pallet-identity = { workspace = true } pallet-inflation = { workspace = true } pallet-nonfungible = { workspace = true } -pallet-proxy-rmrk-core = { workspace = true } -pallet-proxy-rmrk-equip = { workspace = true } pallet-refungible = { workspace = true } pallet-structure = { workspace = true } pallet-unique = { workspace = true } -rmrk-rpc = { workspace = true } scale-info = { workspace = true } up-common = { workspace = true } up-data-structs = { workspace = true } --- a/tests/package.json +++ b/tests/package.json @@ -43,7 +43,6 @@ "testEthFractionalizer": "yarn setup && mocha --timeout 9999999 -r ts-node/register './**/eth/fractionalizer/**/*.*test.ts'", "testEthMarketplace": "yarn setup && mocha --timeout 9999999 -r ts-node/register './**/eth/marketplace/**/*.*test.ts'", "testEvent": "yarn setup && mocha --timeout 9999999 -r ts-node/register ./src/check-event/*.*test.ts", - "testRmrk": "yarn setup && mocha --timeout 9999999 -r ts-node/register ./**/rmrk/*.*test.ts", "testEthPayable": "mocha --timeout 9999999 -r ts-node/register './**/eth/payable.test.ts'", "testEvmCoder": "mocha --timeout 9999999 -r ts-node/register './**/eth/evmCoder.test.ts'", "testNesting": "mocha --timeout 9999999 -r ts-node/register ./**/nest.test.ts", --- a/tests/src/.outdated/rmrk/acceptNft.seqtest.ts +++ /dev/null @@ -1,107 +0,0 @@ -import {expect} from 'chai'; -import {getApiConnection} from '../substrate/substrate-api'; -import { - createCollection, - mintNft, - sendNft, - acceptNft, -} from './util/tx'; -import {NftIdTuple} from './util/fetch'; -import {isNftChildOfAnother, expectTxFailure, requirePallets, Pallets} from './util/helpers'; - -describe('integration test: accept NFT', () => { - let api: any; - before(async function() { - api = await getApiConnection(); - await requirePallets(this, [Pallets.RmrkCore]); - }); - - - const alice = '//Alice'; - const bob = '//Bob'; - - const createTestCollection = async (issuerUri: string) => { - return await createCollection( - api, - issuerUri, - 'accept-metadata', - null, - 'acpt', - ); - }; - - it('accept NFT', async () => { - const ownerAlice = alice; - const ownerBob = bob; - - const aliceCollectionId = await createTestCollection(alice); - const bobCollectionId = await createTestCollection(bob); - - const parentNftId = await mintNft(api, alice, ownerAlice, aliceCollectionId, 'parent-nft-metadata'); - const childNftId = await mintNft(api, bob, ownerBob, bobCollectionId, 'child-nft-metadata'); - - const newOwnerNFT: NftIdTuple = [aliceCollectionId, parentNftId]; - - await sendNft(api, 'pending', ownerBob, bobCollectionId, childNftId, newOwnerNFT); - await acceptNft(api, alice, bobCollectionId, childNftId, newOwnerNFT); - - const isChild = await isNftChildOfAnother(api, bobCollectionId, childNftId, newOwnerNFT); - expect(isChild).to.be.true; - }); - - it('[negative] unable to accept NFT by a not-an-owner', async () => { - const ownerAlice = alice; - const ownerBob = bob; - - const aliceCollectionId = await createTestCollection(alice); - const bobCollectionId = await createTestCollection(bob); - - const parentNftId = await mintNft(api, alice, ownerAlice, aliceCollectionId, 'parent-nft-metadata'); - const childNftId = await mintNft(api, bob, ownerBob, bobCollectionId, 'child-nft-metadata'); - - const newOwnerNFT: NftIdTuple = [aliceCollectionId, parentNftId]; - - await sendNft(api, 'pending', ownerBob, bobCollectionId, childNftId, newOwnerNFT); - const tx = acceptNft(api, bob, bobCollectionId, childNftId, newOwnerNFT); - - await expectTxFailure(/rmrkCore\.NoPermission/, tx); - }); - - it('[negative] unable to accept non-existing NFT', async () => { - const collectionId = 0; - const maxNftId = 0xFFFFFFFF; - - const owner = alice; - const aliceCollectionId = await createTestCollection(alice); - - const parentNftId = await mintNft(api, alice, owner, aliceCollectionId, 'parent-nft-metadata'); - - const newOwnerNFT: NftIdTuple = [aliceCollectionId, parentNftId]; - - const tx = acceptNft(api, alice, collectionId, maxNftId, newOwnerNFT); - - await expectTxFailure(/rmrkCore\.NoAvailableNftId/, tx); - }); - - it('[negative] unable to accept NFT which is not sent', async () => { - const ownerAlice = alice; - const ownerBob = bob; - - const aliceCollectionId = await createTestCollection(alice); - const bobCollectionId = await createTestCollection(bob); - - const parentNftId = await mintNft(api, alice, ownerAlice, aliceCollectionId, 'parent-nft-metadata'); - const childNftId = await mintNft(api, bob, ownerBob, bobCollectionId, 'child-nft-metadata'); - - const newOwnerNFT: NftIdTuple = [aliceCollectionId, parentNftId]; - - const tx = acceptNft(api, alice, bobCollectionId, childNftId, newOwnerNFT); - - await expectTxFailure(/rmrkCore\.NoPermission/, tx); - - const isChild = await isNftChildOfAnother(api, bobCollectionId, childNftId, newOwnerNFT); - expect(isChild).to.be.false; - }); - - after(async() => { await api.disconnect(); }); -}); --- a/tests/src/.outdated/rmrk/addResource.seqtest.ts +++ /dev/null @@ -1,435 +0,0 @@ -import {expect} from 'chai'; -import {getApiConnection} from '../substrate/substrate-api'; -import {NftIdTuple} from './util/fetch'; -import {expectTxFailure, getResourceById, requirePallets, Pallets} from './util/helpers'; -import { - addNftBasicResource, - acceptNftResource, - createCollection, - mintNft, - sendNft, - addNftSlotResource, - addNftComposableResource, -} from './util/tx'; -import {RmrkTraitsResourceResourceInfo as ResourceInfo} from '@polkadot/types/lookup'; - -describe('integration test: add NFT resource', () => { - const alice = '//Alice'; - const bob = '//Bob'; - const src = 'test-res-src'; - const metadata = 'test-res-metadata'; - const license = 'test-res-license'; - const thumb = 'test-res-thumb'; - - const nonexistentId = 99999; - - let api: any; - before(async function() { - api = await getApiConnection(); - await requirePallets(this, [Pallets.RmrkCore]); - }); - - it('add resource', async () => { - const collectionIdAlice = await createCollection( - api, - alice, - 'test-metadata', - null, - 'test-symbol', - ); - - const nftAlice = await mintNft( - api, - alice, - alice, - collectionIdAlice, - 'nft-metadata', - ); - - await addNftBasicResource( - api, - alice, - 'added', - collectionIdAlice, - nftAlice, - src, - metadata, - license, - thumb, - ); - }); - - it('add a resource to the nested NFT', async () => { - const collectionIdAlice = await createCollection( - api, - alice, - 'test-metadata', - null, - 'test-symbol', - ); - - const parentNftId = await mintNft(api, alice, alice, collectionIdAlice, 'parent-nft-metadata'); - const childNftId = await mintNft(api, alice, alice, collectionIdAlice, 'child-nft-metadata'); - - const newOwnerNFT: NftIdTuple = [collectionIdAlice, parentNftId]; - - await sendNft(api, 'sent', alice, collectionIdAlice, childNftId, newOwnerNFT); - - await addNftBasicResource( - api, - alice, - 'added', - collectionIdAlice, - childNftId, - src, - metadata, - license, - thumb, - ); - }); - - it('add multiple resources', async () => { - const collectionIdAlice = await createCollection( - api, - alice, - 'test-metadata', - null, - 'test-symbol', - ); - - const nftAlice = await mintNft( - api, - alice, - alice, - collectionIdAlice, - 'nft-metadata', - ); - - const baseId = 42; - const slotId = 10; - const parts = [0, 5, 2]; - - const resourcesInfo = []; - const resourceNum = 4; - - const checkResource = (resource: ResourceInfo, resType: string, expectedId: number, expected: { - src: string, - metadata: string, - license: string, - thumb: string - }) => { - - // FIXME A workaround. It seems it is a PolkadotJS bug. - // All of the following are `false`. - // - // console.log('>>> basic:', resource.resource.isBasic); - // console.log('>>> composable:', resource.resource.isComposable); - // console.log('>>> slot:', resource.resource.isSlot); - const resourceJson = (resource.resource.toHuman() as any)[resType]; - - expect(resource.id.toNumber(), 'Error: Invalid resource Id') - .to.be.eq(expectedId); - - expect(resourceJson.src, 'Error: Invalid resource src') - .to.be.eq(expected.src); - expect(resourceJson.metadata, 'Error: Invalid resource metadata') - .to.be.eq(expected.metadata); - expect(resourceJson.license, 'Error: Invalid resource license') - .to.be.eq(expected.license); - expect(resourceJson.thumb, 'Error: Invalid resource thumb') - .to.be.eq(expected.thumb); - }; - - for (let i = 0; i < resourceNum; i++) { - resourcesInfo.push({ - src: src + 'r-' + i, - metadata: metadata + 'r-' + i, - license: license + 'r-' + i, - thumb: thumb + 'r-' + i, - }); - } - - const firstBasicResourceId = await addNftBasicResource( - api, - alice, - 'added', - collectionIdAlice, - nftAlice, - resourcesInfo[0].src, - resourcesInfo[0].metadata, - resourcesInfo[0].license, - resourcesInfo[0].thumb, - ); - - const secondBasicResourceId = await addNftBasicResource( - api, - alice, - 'added', - collectionIdAlice, - nftAlice, - resourcesInfo[1].src, - resourcesInfo[1].metadata, - resourcesInfo[1].license, - resourcesInfo[1].thumb, - ); - - const composableResourceId = await addNftComposableResource( - api, - alice, - 'added', - collectionIdAlice, - nftAlice, - parts, - baseId, - resourcesInfo[2].src, - resourcesInfo[2].metadata, - resourcesInfo[2].license, - resourcesInfo[2].thumb, - ); - - const slotResourceId = await addNftSlotResource( - api, - alice, - 'added', - collectionIdAlice, - nftAlice, - baseId, - slotId, - resourcesInfo[3].src, - resourcesInfo[3].metadata, - resourcesInfo[3].license, - resourcesInfo[3].thumb, - ); - - const firstResource = await getResourceById(api, collectionIdAlice, nftAlice, firstBasicResourceId); - await checkResource(firstResource, 'Basic', firstBasicResourceId, resourcesInfo[0]); - - const secondResource = await getResourceById(api, collectionIdAlice, nftAlice, secondBasicResourceId); - await checkResource(secondResource, 'Basic', secondBasicResourceId, resourcesInfo[1]); - - const composableResource = await getResourceById(api, collectionIdAlice, nftAlice, composableResourceId); - await checkResource(composableResource, 'Composable', composableResourceId, resourcesInfo[2]); - - const slotResource = await getResourceById(api, collectionIdAlice, nftAlice, slotResourceId); - await checkResource(slotResource, 'Slot', slotResourceId, resourcesInfo[3]); - }); - - it('[negative]: unable to add a resource to the non-existing NFT', async () => { - const collectionIdAlice = await createCollection( - api, - alice, - 'test-metadata', - null, - 'test-symbol', - ); - - const tx = addNftBasicResource( - api, - alice, - 'added', - collectionIdAlice, - nonexistentId, - src, - metadata, - license, - thumb, - ); - - await expectTxFailure(/rmrkCore\.NoAvailableNftId/, tx); - }); - - it('[negative]: unable to add a resource by a not-an-owner user', async () => { - const collectionIdAlice = await createCollection( - api, - alice, - 'test-metadata', - null, - 'test-symbol', - ); - - const nftAlice = await mintNft( - api, - alice, - alice, - collectionIdAlice, - 'nft-metadata', - ); - - const tx = addNftBasicResource( - api, - bob, - 'added', - collectionIdAlice, - nftAlice, - src, - metadata, - license, - thumb, - ); - - await expectTxFailure(/rmrkCore\.NoPermission/, tx); - }); - - it('[negative]: unable to add a resource to the nested NFT if it isnt root owned by the caller', async () => { - const collectionIdAlice = await createCollection( - api, - alice, - 'test-metadata', - null, - 'test-symbol', - ); - - const parentNftId = await mintNft(api, alice, alice, collectionIdAlice, 'parent-nft-metadata'); - const childNftId = await mintNft(api, alice, alice, collectionIdAlice, 'child-nft-metadata'); - - const newOwnerNFT: NftIdTuple = [collectionIdAlice, parentNftId]; - - await sendNft(api, 'sent', alice, collectionIdAlice, childNftId, newOwnerNFT); - - const tx = addNftBasicResource( - api, - bob, - 'added', - collectionIdAlice, - childNftId, - src, - metadata, - license, - thumb, - ); - - await expectTxFailure(/rmrkCore\.NoPermission/, tx); - }); - - it('accept resource', async () => { - const collectionIdBob = await createCollection( - api, - bob, - 'test-metadata', - null, - 'test-symbol', - ); - - const nftAlice = await mintNft( - api, - bob, - alice, - collectionIdBob, - 'nft-metadata', - ); - - const resourceId = await addNftBasicResource( - api, - bob, - 'pending', - collectionIdBob, - nftAlice, - src, - metadata, - license, - thumb, - ); - - await acceptNftResource(api, alice, collectionIdBob, nftAlice, resourceId); - }); - - it('[negative]: unable to accept a non-existing resource', async () => { - const collectionIdBob = await createCollection( - api, - bob, - 'test-metadata', - null, - 'test-symbol', - ); - - const nftAlice = await mintNft( - api, - bob, - alice, - collectionIdBob, - 'nft-metadata', - ); - - const tx = acceptNftResource(api, alice, collectionIdBob, nftAlice, nonexistentId); - await expectTxFailure(/rmrkCore\.ResourceDoesntExist/, tx); - }); - - it('[negative]: unable to accept a resource by a not-an-NFT-owner user', async () => { - const collectionIdBob = await createCollection( - api, - bob, - 'test-metadata', - null, - 'test-symbol', - ); - - const nftAlice = await mintNft( - api, - bob, - alice, - collectionIdBob, - 'nft-metadata', - ); - - const resourceId = await addNftBasicResource( - api, - bob, - 'pending', - collectionIdBob, - nftAlice, - src, - metadata, - license, - thumb, - ); - - const tx = acceptNftResource(api, bob, collectionIdBob, nftAlice, resourceId); - - await expectTxFailure(/rmrkCore\.NoPermission/, tx); - }); - - it('[negative]: unable to accept a resource to a non-target NFT', async () => { - const collectionIdBob = await createCollection( - api, - bob, - 'test-metadata', - null, - 'test-symbol', - ); - - const nftAlice = await mintNft( - api, - bob, - alice, - collectionIdBob, - 'nft-metadata', - ); - - const wrongNft = await mintNft( - api, - bob, - alice, - collectionIdBob, - 'nft-metadata', - ); - - const resourceId = await addNftBasicResource( - api, - bob, - 'pending', - collectionIdBob, - nftAlice, - src, - metadata, - license, - thumb, - ); - - const tx = acceptNftResource(api, bob, collectionIdBob, wrongNft, resourceId); - - await expectTxFailure(/rmrkCore\.ResourceDoesntExist/, tx); - }); - - - after(async() => { await api.disconnect(); }); -}); --- a/tests/src/.outdated/rmrk/addTheme.seqtest.ts +++ /dev/null @@ -1,129 +0,0 @@ -import {expect} from 'chai'; -import {getApiConnection} from '../substrate/substrate-api'; -import {createBase, addTheme} from './util/tx'; -import {expectTxFailure, requirePallets, Pallets} from './util/helpers'; -import {getThemeNames} from './util/fetch'; - -describe('integration test: add Theme to Base', () => { - let api: any; - before(async function() { - api = await getApiConnection(); - await requirePallets(this, [Pallets.RmrkEquip]); - }); - - const alice = '//Alice'; - const bob = '//Bob'; - - it('add default theme', async () => { - const baseId = await createBase(api, alice, 'default-themed-base', 'DTBase', []); - await addTheme(api, alice, baseId, { - name: 'default', - properties: [ - { - key: 'some-key', - value: 'some-key-value', - }, - { - key: 'another-key', - value: 'another-key-value', - }, - ], - }); - }); - - it('add default theme and a custom one', async () => { - const baseId = await createBase(api, alice, '2-themed-base', '2TBase', []); - await addTheme(api, alice, baseId, { - name: 'default', - properties: [ - { - key: 'default-key', - value: 'default-key-value', - }, - ], - }); - await addTheme(api, alice, baseId, { - name: 'custom-theme', - properties: [ - { - key: 'custom-key-0', - value: 'custom-key-value-0', - }, - { - key: 'custom-key-1', - value: 'custom-key-value-1', - }, - ], - }); - }); - - it('fetch filtered theme keys', async () => { - const baseId = await createBase(api, alice, '2-themed-base', '2TBase', []); - await addTheme(api, alice, baseId, { - name: 'default', - properties: [ - { - key: 'first-key', - value: 'first-key-value', - }, - { - key: 'second-key', - value: 'second-key-value', - }, - ], - }, ['second-key']); - }); - - it('fetch theme names', async() => { - const baseId = await createBase(api, alice, '3-themed-base', '3TBase', []); - const names = [ - 'default', - 'first-theme', - 'second-theme', - ]; - - for (let i = 0; i < names.length; i++) { - await addTheme(api, alice, baseId, {name: names[i], properties: [{key: 'dummy', value: 'dummy'}]}); - } - - const fetchedNames = await getThemeNames(api, baseId); - - for (let i = 0; i < names.length; i++) { - const isFound = fetchedNames.find((name) => name === names[i]) !== undefined; - - expect(isFound, 'Error: invalid theme names').to.be.true; - } - }); - - it('[negative] unable to add theme to non-existing base', async () => { - const maxBaseId = 0xFFFFFFFF; - const tx = addTheme(api, alice, maxBaseId, { - name: 'default', - properties: [], - }); - - await expectTxFailure(/rmrkEquip\.BaseDoesntExist/, tx); - }); - - it('[negative] unable to add custom theme if no default theme', async () => { - const baseId = await createBase(api, alice, 'no-default-themed-base', 'NDTBase', []); - const tx = addTheme(api, alice, baseId, { - name: 'custom-theme', - properties: [], - }); - - await expectTxFailure(/rmrkEquip\.NeedsDefaultThemeFirst/, tx); - }); - - it('[negative] unable to add theme by a not-an-owner', async () => { - const baseId = await createBase(api, alice, 'no-default-themed-base', 'NDTBase', []); - const tx = addTheme(api, bob, baseId, { - name: 'default', - properties: [], - }); - - await expectTxFailure(/rmrkEquip\.PermissionError/, tx); - }); - - after(async() => { await api.disconnect(); }); -}); --- a/tests/src/.outdated/rmrk/burnNft.seqtest.ts +++ /dev/null @@ -1,170 +0,0 @@ -import {getApiConnection} from '../substrate/substrate-api'; -import {expectTxFailure, requirePallets, Pallets} from './util/helpers'; -import {NftIdTuple, getChildren} from './util/fetch'; -import {burnNft, createCollection, sendNft, mintNft} from './util/tx'; - -import chai from 'chai'; -import chaiAsPromised from 'chai-as-promised'; - -chai.use(chaiAsPromised); -const expect = chai.expect; - -describe('integration test: burn nft', () => { - const alice = '//Alice'; - const bob = '//Bob'; - - let api: any; - before(async function() { - api = await getApiConnection(); - await requirePallets(this, [Pallets.RmrkCore]); - }); - - - it('burn nft', async () => { - await createCollection( - api, - alice, - 'test-metadata', - null, - 'test-symbol', - ).then(async (collectionId) => { - const nftId = await mintNft( - api, - alice, - alice, - collectionId, - 'nft-metadata', - ); - await burnNft(api, alice, collectionId, nftId); - }); - }); - - it('burn nft with children', async () => { - const collectionId = await createCollection( - api, - alice, - 'test-metadata', - null, - 'test-symbol', - ); - - const parentNftId = await mintNft( - api, - alice, - alice, - collectionId, - 'nft-metadata', - ); - - const childNftId = await mintNft( - api, - alice, - alice, - collectionId, - 'nft-metadata', - ); - - const newOwnerNFT: NftIdTuple = [collectionId, parentNftId]; - - await sendNft(api, 'sent', alice, collectionId, childNftId, newOwnerNFT); - - const childrenBefore = await getChildren(api, collectionId, parentNftId); - expect(childrenBefore.length === 1, 'Error: parent NFT should have children') - .to.be.true; - - const child = childrenBefore[0]; - expect(child.collectionId.eq(collectionId), 'Error: invalid child collection Id') - .to.be.true; - - expect(child.nftId.eq(childNftId), 'Error: invalid child NFT Id') - .to.be.true; - - await burnNft(api, alice, collectionId, parentNftId); - - const childrenAfter = await getChildren(api, collectionId, parentNftId); - - expect(childrenAfter.length === 0, 'Error: children should be burned').to.be.true; - }); - - it('burn child nft', async () => { - const collectionId = await createCollection( - api, - alice, - 'test-metadata', - null, - 'test-symbol', - ); - - const parentNftId = await mintNft( - api, - alice, - alice, - collectionId, - 'nft-metadata', - ); - - const childNftId = await mintNft( - api, - alice, - alice, - collectionId, - 'nft-metadata', - ); - - const newOwnerNFT: NftIdTuple = [collectionId, parentNftId]; - - await sendNft(api, 'sent', alice, collectionId, childNftId, newOwnerNFT); - - const childrenBefore = await getChildren(api, collectionId, parentNftId); - expect(childrenBefore.length === 1, 'Error: parent NFT should have children') - .to.be.true; - - const child = childrenBefore[0]; - expect(child.collectionId.eq(collectionId), 'Error: invalid child collection Id') - .to.be.true; - - expect(child.nftId.eq(childNftId), 'Error: invalid child NFT Id') - .to.be.true; - - await burnNft(api, alice, collectionId, childNftId); - - const childrenAfter = await getChildren(api, collectionId, parentNftId); - - expect(childrenAfter.length === 0, 'Error: children should be burned').to.be.true; - }); - - it('[negative] burn non-existing NFT', async () => { - await createCollection( - api, - alice, - 'test-metadata', - null, - 'test-symbol', - ).then(async (collectionId) => { - const tx = burnNft(api, alice, collectionId, 99999); - await expectTxFailure(/rmrkCore\.NoAvailableNftId/, tx); - }); - }); - - it('[negative] burn not an owner NFT user', async () => { - await createCollection( - api, - alice, - 'test-metadata', - null, - 'test-symbol', - ).then(async (collectionId) => { - const nftId = await mintNft( - api, - alice, - alice, - collectionId, - 'nft-metadata', - ); - const tx = burnNft(api, bob, collectionId, nftId); - await expectTxFailure(/rmrkCore\.NoPermission/, tx); - }); - }); - - after(async() => { await api.disconnect(); }); -}); --- a/tests/src/.outdated/rmrk/changeCollectionIssuer.seqtest.ts +++ /dev/null @@ -1,53 +0,0 @@ -import {getApiConnection} from '../substrate/substrate-api'; -import {expectTxFailure, requirePallets, Pallets} from './util/helpers'; -import { - changeIssuer, - createCollection, -} from './util/tx'; - -describe('integration test: collection issuer', () => { - const alice = '//Alice'; - const bob = '//Bob'; - - let api: any; - before(async function() { - api = await getApiConnection(); - await requirePallets(this, [Pallets.RmrkCore]); - }); - - - - it('change collection issuer', async () => { - await createCollection( - api, - alice, - 'test-metadata', - null, - 'test-symbol', - ).then(async (collectionId) => { - await changeIssuer(api, alice, collectionId, bob); - }); - }); - - it('[negative] change not an owner NFT collection issuer', async () => { - await createCollection(api, bob, 'test-metadata', null, 'test-symbol').then(async (collectionId) => { - const tx = changeIssuer(api, alice, collectionId, bob); - await expectTxFailure(/rmrkCore\.NoPermission/, tx); - }); - }); - - it('[negative] change non-existigit NFT collection issuer', async () => { - await createCollection( - api, - alice, - 'test-metadata', - null, - 'test-symbol', - ).then(async () => { - const tx = changeIssuer(api, alice, 99999, bob); - await expectTxFailure(/rmrkCore\.CollectionUnknown/, tx); - }); - }); - - after(async() => { await api.disconnect(); }); -}); --- a/tests/src/.outdated/rmrk/createBase.seqtest.ts +++ /dev/null @@ -1,88 +0,0 @@ -import {getApiConnection} from '../substrate/substrate-api'; -import {requirePallets, Pallets} from './util/helpers'; -import {createCollection, createBase} from './util/tx'; - -describe('integration test: create new Base', () => { - let api: any; - before(async function() { - api = await getApiConnection(); - await requirePallets(this, [Pallets.RmrkCore, Pallets.RmrkEquip]); - }); - - const alice = '//Alice'; - - it('create empty Base', async () => { - await createBase(api, alice, 'empty-base-type', 'EBase', []); - }); - - it('create Base with fixed part', async () => { - await createBase(api, alice, 'fixedpart-base-type', 'FPBase', [ - { - 'FixedPart': { - id: 42, - z: 0, - src: 'some-fixed-url', - }, - }, - ]); - }); - - it('create Base with slot part (no collection)', async () => { - await createBase(api, alice, 'slotpart-base-type', 'SPBase', [ - { - 'SlotPart': { - id: 112, - equippable: 'Empty', - z: 0, - src: 'some-fallback-slot-url', - }, - }, - ]); - }); - - it('create Base with slot part (any collection)', async () => { - await createBase(api, alice, 'slotpartany-base-type', 'SPABase', [ - { - 'SlotPart': { - id: 222, - equippable: 'All', - z: 1, - src: 'some-fallback-slot-url', - }, - }, - ]); - }); - - it('create Base with slot part (custom collections)', async () => { - const firstCollectionId = await createCollection( - api, - alice, - 'first-collection-meta', - null, - 'first-collection', - ); - - const secondCollectionId = await createCollection( - api, - alice, - 'first-collection-meta', - null, - 'first-collection', - ); - - await createBase(api, alice, 'slotpartcustom-base-type', 'SPCBase', [ - { - 'SlotPart': { - id: 1024, - equippable: { - 'Custom': [firstCollectionId, secondCollectionId], - }, - z: 2, - src: 'some-fallback-slot-url', - }, - }, - ]); - }); - - after(async() => { await api.disconnect(); }); -}); --- a/tests/src/.outdated/rmrk/createCollection.seqtest.ts +++ /dev/null @@ -1,25 +0,0 @@ -import {getApiConnection} from '../substrate/substrate-api'; -import {requirePallets, Pallets} from './util/helpers'; -import {createCollection} from './util/tx'; - -describe('Integration test: create new collection', () => { - let api: any; - before(async function () { - api = await getApiConnection(); - await requirePallets(this, [Pallets.RmrkCore]); - }); - - - - const alice = '//Alice'; - - it('create NFT collection', async () => { - await createCollection(api, alice, 'test-metadata', 42, 'test-symbol'); - }); - - it('create NFT collection without token limit', async () => { - await createCollection(api, alice, 'no-limit-metadata', null, 'no-limit-symbol'); - }); - - after(async() => { await api.disconnect(); }); -}); --- a/tests/src/.outdated/rmrk/deleteCollection.seqtest.ts +++ /dev/null @@ -1,46 +0,0 @@ -import {getApiConnection} from '../substrate/substrate-api'; -import {expectTxFailure, requirePallets, Pallets} from './util/helpers'; -import {createCollection, deleteCollection} from './util/tx'; - -describe('integration test: delete collection', () => { - let api: any; - before(async function () { - api = await getApiConnection(); - await requirePallets(this, [Pallets.RmrkCore]); - }); - - const alice = '//Alice'; - const bob = '//Bob'; - - it('delete NFT collection', async () => { - await createCollection( - api, - alice, - 'test-metadata', - null, - 'test-symbol', - ).then(async (collectionId) => { - await deleteCollection(api, alice, collectionId.toString()); - }); - }); - - it('[negative] delete non-existing NFT collection', async () => { - const tx = deleteCollection(api, alice, '99999'); - await expectTxFailure(/rmrkCore\.CollectionUnknown/, tx); - }); - - it('[negative] delete not an owner NFT collection', async () => { - await createCollection( - api, - alice, - 'test-metadata', - null, - 'test-symbol', - ).then(async (collectionId) => { - const tx = deleteCollection(api, bob, collectionId.toString()); - await expectTxFailure(/rmrkCore.NoPermission/, tx); - }); - }); - - after(async() => { await api.disconnect(); }); -}); --- a/tests/src/.outdated/rmrk/equipNft.seqtest.ts +++ /dev/null @@ -1,340 +0,0 @@ -import {ApiPromise} from '@polkadot/api'; -import {expect} from 'chai'; -import {getApiConnection} from '../substrate/substrate-api'; -import {getNft, NftIdTuple} from './util/fetch'; -import {expectTxFailure, requirePallets, Pallets} from './util/helpers'; -import { - addNftComposableResource, - addNftSlotResource, - createBase, - createCollection, - equipNft, - mintNft, - sendNft, - unequipNft, -} from './util/tx'; - -const alice = '//Alice'; -const bob = '//Bob'; - -const composableParts: number[] = [5, 2, 7]; -const composableSrc = 'test-cmp-src'; -const composableMetadata = 'test-cmp-metadata'; -const composableLicense = 'test-comp-license'; -const composableThumb = 'test-comp-thumb'; - -const slotSrc = 'test-slot-src'; -const slotLicense = 'test-slot-license'; -const slotMetadata = 'test-slot-metadata'; -const slotThumb = 'test-slot-thumb'; - -const slotId = 1; - -function createTestCollection(api: ApiPromise): Promise { - return createCollection( - api, - alice, - 'test-metadata', - null, - 'test-symbol', - ); -} - -async function mintTestNft(api: ApiPromise, collectionId: number): Promise { - return await mintNft( - api, - alice, - alice, - collectionId, - 'nft-metadata', - ); -} - -async function mintChildNft(api: ApiPromise, collectionId: number, parentNftId: number): Promise { - const nftChildId = await mintTestNft(api, collectionId); - - const parentNFT: NftIdTuple = [collectionId, parentNftId]; - - await sendNft(api, 'sent', alice, collectionId, nftChildId, parentNFT); - - return nftChildId; -} - -function createTestBase(api: ApiPromise): Promise { - return createBase(api, alice, 'test-base', 'DTBase', [ - { - SlotPart: { - id: slotId, - equippable: 'All', - z: 1, - src: slotSrc, - }, - }, - ]); -} - -async function addTestComposable(api: ApiPromise, collectionId: number, nftId: number, baseId: number) { - await addNftComposableResource( - api, - alice, - 'added', - collectionId, - nftId, - composableParts, - baseId, - composableSrc, - composableMetadata, - composableLicense, - composableThumb, - ); -} - -async function addTestSlot(api: ApiPromise, collectionId: number, nftId: number, baseId: number, slotId: number): Promise { - return await addNftSlotResource( - api, - alice, - 'added', - collectionId, - nftId, - baseId, - slotId, - slotSrc, - slotMetadata, - slotLicense, - slotThumb, - ); -} - -async function checkEquipStatus( - api: ApiPromise, - expectedStatus: 'equipped' | 'unequipped', - collectionId: number, - nftId: number, -) { - const itemNftDataOpt = await getNft(api, collectionId, nftId); - expect(itemNftDataOpt.isSome, 'Error: unable to fetch item NFT data'); - - const itemNftData = itemNftDataOpt.unwrap(); - expect(itemNftData.equipped.isTrue, `Error: item NFT should be ${expectedStatus}`) - .to.be.equal(expectedStatus === 'equipped'); -} - -describe.skip('integration test: Equip NFT', () => { - - let api: any; - - before(async function () { - api = await getApiConnection(); - await requirePallets(this, [Pallets.RmrkCore, Pallets.RmrkEquip]); - }); - - it('equip nft', async () => { - const collectionId = await createTestCollection(api); - const nftParentId = await mintTestNft(api, collectionId); - const nftChildId = await mintChildNft(api, collectionId, nftParentId); - - const baseId = await createTestBase(api); - - await addTestComposable(api, collectionId, nftParentId, baseId); - const resourceId = await addTestSlot(api, collectionId, nftChildId, baseId, slotId); - - const equipperNFT: NftIdTuple = [collectionId, nftParentId]; - const itemNFT: NftIdTuple = [collectionId, nftChildId]; - - await equipNft(api, alice, itemNFT, equipperNFT, resourceId, baseId, slotId); - - await checkEquipStatus(api, 'equipped', collectionId, nftChildId); - }); - - it('unequip nft', async () => { - const collectionId = await createTestCollection(api); - const nftParentId = await mintTestNft(api, collectionId); - const nftChildId = await mintChildNft(api, collectionId, nftParentId); - - const baseId = await createTestBase(api); - - await addTestComposable(api, collectionId, nftParentId, baseId); - const resourceId = await addTestSlot(api, collectionId, nftChildId, baseId, slotId); - - const equipperNFT: NftIdTuple = [collectionId, nftParentId]; - const itemNFT: NftIdTuple = [collectionId, nftChildId]; - - await equipNft(api, alice, itemNFT, equipperNFT, resourceId, baseId, slotId); - - await checkEquipStatus(api, 'equipped', collectionId, nftChildId); - - await unequipNft(api, alice, itemNFT, equipperNFT, resourceId, baseId, slotId); - await checkEquipStatus(api, 'unequipped', collectionId, nftChildId); - }); - - it('[negative] equip NFT onto non-existing NFT', async () => { - const collectionId = await createTestCollection(api); - - const nftChildId = await mintNft( - api, - alice, - alice, - collectionId, - 'nft-metadata', - ); - - const itemNFT: NftIdTuple = [collectionId, nftChildId]; - const invalidEquipperNFT: NftIdTuple = [collectionId, 9999999]; - - const baseId = 0; - const resourceId = 0; - - const tx = equipNft(api, alice, itemNFT, invalidEquipperNFT, resourceId, baseId, slotId); - await expectTxFailure(/rmrkCore\.NoAvailableNftId/, tx); - }); - - it('[negative] equip non-existing NFT', async () => { - const collectionId = await createTestCollection(api); - const nftParentId = await mintNft( - api, - alice, - alice, - collectionId, - 'nft-metadata', - ); - - const baseId = await createTestBase(api); - - await addTestComposable(api, collectionId, nftParentId, baseId); - - const equipperNFT: NftIdTuple = [collectionId, nftParentId]; - const invalidItemNFT: NftIdTuple = [collectionId, 99999999]; - - const resourceId = 0; - - const tx = equipNft(api, alice, invalidItemNFT, equipperNFT, resourceId, baseId, slotId); - await expectTxFailure(/rmrkCore\.NoAvailableNftId/, tx); - }); - - it('[negative] equip NFT by a not-an-owner user', async () => { - const collectionId = await createTestCollection(api); - const nftParentId = await mintTestNft(api, collectionId); - const nftChildId = await mintChildNft(api, collectionId, nftParentId); - - const baseId = await createTestBase(api); - - await addTestComposable(api, collectionId, nftParentId, baseId); - - const equipperNFT: NftIdTuple = [collectionId, nftParentId]; - const itemNFT: NftIdTuple = [collectionId, nftChildId]; - - const resourceId = await addTestSlot(api, collectionId, nftChildId, baseId, slotId); - - const tx = equipNft(api, bob, itemNFT, equipperNFT, resourceId, baseId, slotId); - await expectTxFailure(/rmrkEquip\.PermissionError/, tx); - }); - - it('[negative] unable to equip NFT onto indirect parent NFT', async () => { - const collectionId = await createTestCollection(api); - const nftParentId = await mintTestNft(api, collectionId); - const nftChildId = await mintChildNft(api, collectionId, nftParentId); - const nftGrandchildId = await mintChildNft(api, collectionId, nftChildId); - - const baseId = await createTestBase(api); - - await addTestComposable(api, collectionId, nftParentId, baseId); - const resourceId = await addTestSlot(api, collectionId, nftGrandchildId, baseId, slotId); - - const equipperNFT: NftIdTuple = [collectionId, nftParentId]; - const itemNFT: NftIdTuple = [collectionId, nftGrandchildId]; - - const tx = equipNft(api, alice, itemNFT, equipperNFT, resourceId, baseId, slotId); - await expectTxFailure(/rmrkEquip\.MustBeDirectParent/, tx); - }); - - it('[negative] unable to equip NFT onto parent NFT with another base', async () => { - const collectionId = await createTestCollection(api); - const nftParentId = await mintTestNft(api, collectionId); - const nftChildId = await mintChildNft(api, collectionId, nftParentId); - - const baseId = await createTestBase(api); - - await addTestComposable(api, collectionId, nftParentId, baseId); - const resourceId = await addTestSlot(api, collectionId, nftChildId, baseId, slotId); - - const equipperNFT: NftIdTuple = [collectionId, nftParentId]; - const itemNFT: NftIdTuple = [collectionId, nftChildId]; - - const invalidBaseId = 99999; - - const tx = equipNft(api, alice, itemNFT, equipperNFT, resourceId, invalidBaseId, slotId); - await expectTxFailure(/rmrkEquip\.NoResourceForThisBaseFoundOnNft/, tx); - }); - - it('[negative] unable to equip NFT into slot with another id', async () => { - const collectionId = await createTestCollection(api); - const nftParentId = await mintTestNft(api, collectionId); - const nftChildId = await mintChildNft(api, collectionId, nftParentId); - - const baseId = await createTestBase(api); - - await addTestComposable(api, collectionId, nftParentId, baseId); - const resourceId = await addTestSlot(api, collectionId, nftChildId, baseId, slotId); - - const equipperNFT: NftIdTuple = [collectionId, nftParentId]; - const itemNFT: NftIdTuple = [collectionId, nftChildId]; - - const incorrectSlotId = slotId + 1; - const tx = equipNft(api, alice, itemNFT, equipperNFT, resourceId, baseId, incorrectSlotId); - await expectTxFailure(/rmrkEquip\.ItemHasNoResourceToEquipThere/, tx); - }); - - it('[negative] unable to equip NFT with incorrect slot (fixed part)', async () => { - const collectionId = await createTestCollection(api); - const nftParentId = await mintTestNft(api, collectionId); - const nftChildId = await mintChildNft(api, collectionId, nftParentId); - - const baseId = await createBase(api, alice, 'test-base', 'DTBase', [ - { - FixedPart: { - id: slotId, - equippable: 'All', - z: 1, - src: slotSrc, - }, - }, - ]); - - await addTestComposable(api, collectionId, nftParentId, baseId); - const resourceId = await addTestSlot(api, collectionId, nftChildId, baseId, slotId); - - const equipperNFT: NftIdTuple = [collectionId, nftParentId]; - const itemNFT: NftIdTuple = [collectionId, nftChildId]; - - const tx = equipNft(api, alice, itemNFT, equipperNFT, resourceId, baseId, slotId); - await expectTxFailure(/rmrkEquip\.CantEquipFixedPart/, tx); - }); - - it('[negative] unable to equip NFT from a collection that is not allowed by the slot', async () => { - const collectionId = await createTestCollection(api); - const nftParentId = await mintTestNft(api, collectionId); - const nftChildId = await mintChildNft(api, collectionId, nftParentId); - - const baseId = await createBase(api, alice, 'test-base', 'DTBase', [ - { - SlotPart: { - id: 1, - z: 1, - equippable: 'Empty', - src: slotSrc, - }, - }, - ]); - - await addTestComposable(api, collectionId, nftParentId, baseId); - const resourceId = await addTestSlot(api, collectionId, nftChildId, baseId, slotId); - - const equipperNFT: NftIdTuple = [collectionId, nftParentId]; - const itemNFT: NftIdTuple = [collectionId, nftChildId]; - - const tx = equipNft(api, alice, itemNFT, equipperNFT, resourceId, baseId, slotId); - await expectTxFailure(/rmrkEquip\.CollectionNotEquippable/, tx); - }); - - after(async() => { await api.disconnect(); }); -}); --- a/tests/src/.outdated/rmrk/getOwnedNfts.seqtest.ts +++ /dev/null @@ -1,80 +0,0 @@ -import {expect} from 'chai'; -import {getApiConnection} from '../substrate/substrate-api'; -import {requirePallets, Pallets} from './util/helpers'; -import {getOwnedNfts} from './util/fetch'; -import {mintNft, createCollection} from './util/tx'; - -describe('integration test: get owned NFTs', () => { - let api: any; - - before(async function () { - api = await getApiConnection(); - await requirePallets(this, [Pallets.RmrkCore]); - }); - - - const alice = '//Alice'; - - it('fetch all NFTs owned by a user', async () => { - const owner = alice; - const collectionMetadata = 'aliceCollectionMetadata'; - const collectionMax = null; - const collectionSymbol = 'AliceSym'; - const recipientUri = null; - const royalty = null; - const nftMetadata = 'alice-NFT-metadata'; - - const collectionId = await createCollection( - api, - alice, - collectionMetadata, - collectionMax, - collectionSymbol, - ); - - const nftIds = [ - await mintNft( - api, - alice, - owner, - collectionId, - nftMetadata + '-0', - recipientUri, - royalty, - ), - await mintNft( - api, - alice, - owner, - collectionId, - nftMetadata + '-1', - recipientUri, - royalty, - ), - await mintNft( - api, - alice, - owner, - collectionId, - nftMetadata + '-2', - recipientUri, - royalty, - ), - ]; - - const ownedNfts = await getOwnedNfts(api, alice, collectionId); - - const isFound = (nftId: number) => { - return ownedNfts.find((ownedNftId) => { - return ownedNftId === nftId; - }) !== undefined; - }; - - nftIds.forEach((nftId) => { - expect(isFound(nftId), `NFT ${nftId} should be owned by ${alice}`) - .to.be.true; - }); - }); - - after(async() => { await api.disconnect(); }); -}); --- a/tests/src/.outdated/rmrk/lockCollection.seqtest.ts +++ /dev/null @@ -1,116 +0,0 @@ -import {getApiConnection} from '../substrate/substrate-api'; -import {expectTxFailure, requirePallets, Pallets} from './util/helpers'; -import {createCollection, lockCollection, mintNft} from './util/tx'; - -describe('integration test: lock collection', () => { - const alice = '//Alice'; - const bob = '//Bob'; - const max = 5; - - let api: any; - before(async function () { - api = await getApiConnection(); - await requirePallets(this, [Pallets.RmrkCore]); - }); - - it('lock collection', async () => { - await createCollection( - api, - alice, - 'test-metadata', - null, - 'test-symbol', - ).then(async (collectionId) => { - await lockCollection(api, alice, collectionId); - }); - }); - - it('[negative] lock non-existing NFT collection', async () => { - const tx = lockCollection(api, alice, 99999); - await expectTxFailure(/rmrkCore\.CollectionUnknown/, tx); - }); - - it('[negative] lock not an owner NFT collection issuer', async () => { - await createCollection( - api, - alice, - 'test-metadata', - null, - 'test-symbol', - ).then(async (collectionId) => { - const tx = lockCollection(api, bob, collectionId); - await expectTxFailure(/rmrkCore\.NoPermission/, tx); - }); - }); - - it('lock collection with minting', async () => { - await createCollection( - api, - alice, - 'test-metadata', - max, - 'test-symbol', - ).then(async (collectionId) => { - for (let i = 0; i < 5; i++) { - await mintNft( - api, - alice, - alice, - collectionId, - 'test-metadata', - null, - null, - ); - } - await lockCollection(api, alice, collectionId, max); - }); - }); - - it('[negative] unable to mint NFT inside a locked collection', async () => { - await createCollection( - api, - alice, - 'test-metadata', - max, - 'test-symbol', - ).then(async (collectionId) => { - await lockCollection(api, alice, collectionId); - const tx = mintNft( - api, - alice, - alice, - collectionId, - 'test-metadata', - null, - null, - ); - await expectTxFailure(/rmrkCore\.CollectionFullOrLocked/, tx); - }); - }); - - it('[negative] unable to mint NFT inside a full collection', async () => { - await createCollection(api, alice, 'test-metadata', 1, 'test-symbol').then(async (collectionId) => { - await mintNft( - api, - alice, - alice, - collectionId, - 'test-metadata', - null, - null, - ); - const tx = mintNft( - api, - alice, - alice, - collectionId, - 'test-metadata', - null, - null, - ); - await expectTxFailure(/rmrkCore\.CollectionFullOrLocked/, tx); - }); - }); - - after(async() => { await api.disconnect(); }); -}); --- a/tests/src/.outdated/rmrk/mintNft.seqtest.ts +++ /dev/null @@ -1,211 +0,0 @@ -import {expect} from 'chai'; -import {getApiConnection} from '../substrate/substrate-api'; -import {getNft} from './util/fetch'; -import {expectTxFailure, requirePallets, Pallets} from './util/helpers'; -import {createCollection, mintNft} from './util/tx'; - -describe('integration test: mint new NFT', () => { - let api: any; - - before(async function () { - api = await getApiConnection(); - await requirePallets(this, [Pallets.RmrkCore]); - }); - - - const alice = '//Alice'; - const bob = '//Bob'; - const maxCollectionId = 0xFFFFFFFF; - const maxNftId = 0xFFFFFFFF; - - it('mint NFT', async () => { - const owner = null; - const collectionMetadata = 'mintingCollectionMetadata'; - const collectionMax = null; - const collectionSymbol = 'MCS'; - const recipientUri = null; - const royalty = null; - const nftMetadata = 'NFT-test-metadata'; - - const collectionId = await createCollection( - api, - alice, - collectionMetadata, - collectionMax, - collectionSymbol, - ); - - await mintNft( - api, - alice, - owner, - collectionId, - nftMetadata, - recipientUri, - royalty, - ); - }); - - it('mint NFT and set another owner', async () => { - const owner = bob; - const collectionMetadata = 'setOwnerCollectionMetadata'; - const collectionMax = null; - const collectionSymbol = 'SOCS'; - const recipientUri = null; - const royalty = null; - const nftMetadata = 'setOwner-NFT-metadata'; - - const collectionId = await createCollection( - api, - alice, - collectionMetadata, - collectionMax, - collectionSymbol, - ); - - await mintNft( - api, - alice, - owner, - collectionId, - nftMetadata, - recipientUri, - royalty, - ); - }); - - it('mint NFT with recipient and roalty', async () => { - const owner = alice; - const collectionMetadata = 'mintingCollectionMetadata'; - const collectionMax = null; - const collectionSymbol = 'MCS'; - const recipientUri = bob; - const royalty = 70000; - const nftMetadata = 'recipient-royalty-NFT-test-metadata'; - - const collectionId = await createCollection( - api, - alice, - collectionMetadata, - collectionMax, - collectionSymbol, - ); - - await mintNft( - api, - alice, - owner, - collectionId, - nftMetadata, - recipientUri, - royalty, - ); - }); - - it('mint NFT with resources', async () => { - const owner = alice; - const collectionMetadata = 'mintingCollectionMetadata'; - const collectionMax = null; - const collectionSymbol = 'MCS'; - const nftMetadata = 'NFT-with-resources-test-metadata'; - const resources = [ - { - basic: { - metadata: 'basic-resource-nft-minting', - }, - }, { - slot: { - metadata: 'slot-resource-nft-minting', - slot: 9, - }, - }, { - composable: { - metadata: 'composable-resource-nft-minting', - parts: [0, 5, 2], - }, - }, { - slot: { - metadata: 'slot-resource-nft-minting-2', - thumb: 'srnm2', - base: 5, - }, - }, - ]; - - const collectionId = await createCollection( - api, - alice, - collectionMetadata, - collectionMax, - collectionSymbol, - ); - - await mintNft( - api, - alice, - owner, - collectionId, - nftMetadata, - null, - null, - true, - resources, - ); - }); - - it('[negative] unable to mint NFT within non-existing collection', async () => { - const owner = alice; - const recipientUri = null; - const royalty = null; - const nftMetadata = 'NFT-test-metadata'; - - const tx = mintNft( - api, - alice, - owner, - maxCollectionId, - nftMetadata, - recipientUri, - royalty, - ); - - await expectTxFailure(/rmrkCore\.CollectionUnknown/, tx); - }); - - it("[negative] unable to mint NFT by a user that isn't the owner of the collection", async () => { - const owner = alice; - const collectionMetadata = 'mintingCollectionMetadata'; - const collectionMax = null; - const collectionSymbol = 'MCS'; - const recipientUri = null; - const royalty = null; - const nftMetadata = 'NFT-test-metadata'; - - const collectionId = await createCollection( - api, - alice, - collectionMetadata, - collectionMax, - collectionSymbol, - ); - - const tx = mintNft( - api, - bob, - owner, - collectionId, - nftMetadata, - recipientUri, - royalty, - ); - - await expectTxFailure(/rmrkCore\.NoPermission/, tx); - }); - - it('[negative] unable to fetch non-existing NFT', async () => { - const nft = await getNft(api, maxCollectionId, maxNftId); - expect(nft.isSome).to.be.false; - }); - - after(async() => { await api.disconnect(); }); -}); --- a/tests/src/.outdated/rmrk/rejectNft.seqtest.ts +++ /dev/null @@ -1,94 +0,0 @@ -import {expect} from 'chai'; -import {getApiConnection} from '../substrate/substrate-api'; -import { - createCollection, - mintNft, - sendNft, - rejectNft, -} from './util/tx'; -import {NftIdTuple} from './util/fetch'; -import {isNftChildOfAnother, expectTxFailure, requirePallets, Pallets} from './util/helpers'; - -describe('integration test: reject NFT', () => { - let api: any; - before(async function () { - api = await getApiConnection(); - await requirePallets(this, [Pallets.RmrkCore]); - }); - - - - const alice = '//Alice'; - const bob = '//Bob'; - - const createTestCollection = async (issuerUri: string) => { - return await createCollection( - api, - issuerUri, - 'reject-metadata', - null, - 'rjct', - ); - }; - - it('reject NFT', async () => { - const ownerAlice = alice; - const ownerBob = bob; - - const aliceCollectionId = await createTestCollection(alice); - const bobCollectionId = await createTestCollection(bob); - - const parentNftId = await mintNft(api, alice, ownerAlice, aliceCollectionId, 'parent-nft-metadata'); - const childNftId = await mintNft(api, bob, ownerBob, bobCollectionId, 'child-nft-metadata'); - - const newOwnerNFT: NftIdTuple = [aliceCollectionId, parentNftId]; - - await sendNft(api, 'pending', ownerBob, bobCollectionId, childNftId, newOwnerNFT); - await rejectNft(api, alice, bobCollectionId, childNftId); - - const isChild = await isNftChildOfAnother(api, bobCollectionId, childNftId, newOwnerNFT); - expect(isChild, 'Error: rejected NFT is still a child of the target NFT').to.be.false; - }); - - it('[negative] unable to reject NFT by a not-an-owner', async () => { - const ownerAlice = alice; - const ownerBob = bob; - - const aliceCollectionId = await createTestCollection(alice); - const bobCollectionId = await createTestCollection(bob); - - const parentNftId = await mintNft(api, alice, ownerAlice, aliceCollectionId, 'parent-nft-metadata'); - const childNftId = await mintNft(api, bob, ownerBob, bobCollectionId, 'child-nft-metadata'); - - const newOwnerNFT: NftIdTuple = [aliceCollectionId, parentNftId]; - - await sendNft(api, 'pending', ownerBob, bobCollectionId, childNftId, newOwnerNFT); - const tx = rejectNft(api, bob, bobCollectionId, childNftId); - - await expectTxFailure(/rmrkCore\.CannotRejectNonOwnedNft/, tx); - }); - - it('[negative] unable to reject non-existing NFT', async () => { - const maxNftId = 0xFFFFFFFF; - - const collectionId = await createTestCollection(alice); - - const tx = rejectNft(api, alice, collectionId, maxNftId); - - await expectTxFailure(/rmrkCore\.NoAvailableNftId/, tx); - }); - - it('[negative] unable to reject NFT which is not sent', async () => { - const ownerAlice = alice; - - const collectionId = await createTestCollection(alice); - - const nftId = await mintNft(api, alice, ownerAlice, collectionId, 'parent-nft-metadata'); - - const tx = rejectNft(api, alice, collectionId, nftId); - - await expectTxFailure(/rmrkCore\.CannotRejectNonPendingNft/, tx); - }); - - after(async() => { await api.disconnect(); }); -}); --- a/tests/src/.outdated/rmrk/removeResource.seqtest.ts +++ /dev/null @@ -1,340 +0,0 @@ -import {getApiConnection} from '../substrate/substrate-api'; -import {NftIdTuple} from './util/fetch'; -import {expectTxFailure, requirePallets, Pallets} from './util/helpers'; -import { - acceptResourceRemoval, addNftBasicResource, createCollection, mintNft, removeNftResource, sendNft, -} from './util/tx'; - - - - -describe('Integration test: remove nft resource', () => { - let api: any; - before(async function() { - api = await getApiConnection(); - await requirePallets(this, [Pallets.RmrkCore]); - }); - - const alice = '//Alice'; - const bob = '//Bob'; - const src = 'test-basic-src'; - const metadata = 'test-basic-metadata'; - const license = 'test-basic-license'; - const thumb = 'test-basic-thumb'; - - it('deleting a resource directly by the NFT owner', async () => { - const collectionIdAlice = await createCollection( - api, - alice, - 'test-metadata', - null, - 'test-symbol', - ); - - const nftAlice = await mintNft( - api, - alice, - alice, - collectionIdAlice, - 'nft-metadata', - ); - - const resourceId = await addNftBasicResource( - api, - alice, - 'added', - collectionIdAlice, - nftAlice, - src, - metadata, - license, - thumb, - ); - - await removeNftResource(api, 'removed', alice, collectionIdAlice, nftAlice, resourceId); - }); - - it('deleting resources indirectly by the NFT owner', async () => { - const collectionIdAlice = await createCollection( - api, - alice, - 'test-metadata', - null, - 'test-symbol', - ); - - const parentNftId = await mintNft(api, alice, alice, collectionIdAlice, 'parent-nft-metadata'); - const childNftId = await mintNft(api, alice, alice, collectionIdAlice, 'child-nft-metadata'); - - const resourceId = await addNftBasicResource( - api, - alice, - 'added', - collectionIdAlice, - childNftId, - src, - metadata, - license, - thumb, - ); - - const newOwnerNFT: NftIdTuple = [collectionIdAlice, parentNftId]; - - await sendNft(api, 'sent', alice, collectionIdAlice, childNftId, newOwnerNFT); - - await removeNftResource(api, 'removed', alice, collectionIdAlice, childNftId, resourceId); - }); - - it('deleting a resource by the collection owner', async () => { - const collectionIdAlice = await createCollection( - api, - alice, - 'test-metadata', - null, - 'test-symbol', - ); - - const nftBob = await mintNft( - api, - alice, - bob, - collectionIdAlice, - 'nft-metadata', - ); - - const resourceId = await addNftBasicResource( - api, - alice, - 'pending', - collectionIdAlice, - nftBob, - src, - metadata, - license, - thumb, - ); - - await removeNftResource(api, 'pending', alice, collectionIdAlice, nftBob, resourceId); - await acceptResourceRemoval(api, bob, collectionIdAlice, nftBob, resourceId); - }); - - it('deleting a resource in a nested NFT by the collection owner', async () => { - const collectionIdAlice = await createCollection( - api, - alice, - 'test-metadata', - null, - 'test-symbol', - ); - - const parentNftId = await mintNft( - api, - alice, - bob, - collectionIdAlice, - 'parent-nft-metadata', - ); - const childNftId = await mintNft( - api, - alice, - bob, - collectionIdAlice, - 'child-nft-metadata', - ); - - const resourceId = await addNftBasicResource( - api, - alice, - 'pending', - collectionIdAlice, - childNftId, - src, - metadata, - license, - thumb, - ); - - const newOwnerNFT: NftIdTuple = [collectionIdAlice, parentNftId]; - - await sendNft(api, 'sent', bob, collectionIdAlice, childNftId, newOwnerNFT); - - await removeNftResource(api, 'pending', alice, collectionIdAlice, childNftId, resourceId); - await acceptResourceRemoval(api, bob, collectionIdAlice, childNftId, resourceId); - }); - - it('[negative]: can\'t delete a resource in a non-existing collection', async () => { - const collectionIdAlice = await createCollection( - api, - alice, - 'test-metadata', - null, - 'test-symbol', - ); - - const nftAlice = await mintNft( - api, - alice, - alice, - collectionIdAlice, - 'nft-metadata', - ); - - const resourceId = await addNftBasicResource( - api, - alice, - 'added', - collectionIdAlice, - nftAlice, - src, - metadata, - license, - thumb, - ); - - const tx = removeNftResource(api, 'removed', alice, 0xFFFFFFFF, nftAlice, resourceId); - await expectTxFailure(/rmrkCore\.CollectionUnknown/, tx); // FIXME: inappropriate error message (NoAvailableNftId) - }); - - it('[negative]: only collection owner can delete a resource', async () => { - const collectionIdAlice = await createCollection( - api, - alice, - 'test-metadata', - null, - 'test-symbol', - ); - - const nftAlice = await mintNft( - api, - alice, - alice, - collectionIdAlice, - 'nft-metadata', - ); - - const resourceId = await addNftBasicResource( - api, - alice, - 'added', - collectionIdAlice, - nftAlice, - src, - metadata, - license, - thumb, - ); - - const tx = removeNftResource(api, 'removed', bob, collectionIdAlice, nftAlice, resourceId); - await expectTxFailure(/rmrkCore\.NoPermission/, tx); - }); - - it('[negative]: cannot delete a resource that does not exist', async () => { - const collectionIdAlice = await createCollection( - api, - alice, - 'test-metadata', - null, - 'test-symbol', - ); - - const nftAlice = await mintNft( - api, - alice, - alice, - collectionIdAlice, - 'nft-metadata', - ); - - const tx = removeNftResource(api, 'removed', alice, collectionIdAlice, nftAlice, 127); - await expectTxFailure(/rmrkCore\.ResourceDoesntExist/, tx); - }); - - it('[negative]: Cannot accept deleting resource without owner attempt do delete it', async () => { - const collectionIdAlice = await createCollection( - api, - alice, - 'test-metadata', - null, - 'test-symbol', - ); - - const nftBob = await mintNft( - api, - alice, - bob, - collectionIdAlice, - 'nft-metadata', - ); - - const resourceId = await addNftBasicResource( - api, - alice, - 'pending', - collectionIdAlice, - nftBob, - src, - metadata, - license, - thumb, - ); - - const tx = acceptResourceRemoval(api, bob, collectionIdAlice, nftBob, resourceId); - await expectTxFailure(/rmrkCore\.ResourceNotPending/, tx); - }); - - it('[negative]: cannot confirm the deletion of a non-existing resource', async () => { - const collectionIdAlice = await createCollection( - api, - alice, - 'test-metadata', - null, - 'test-symbol', - ); - - const nftBob = await mintNft( - api, - alice, - bob, - collectionIdAlice, - 'nft-metadata', - ); - - const tx = acceptResourceRemoval(api, bob, collectionIdAlice, nftBob, 127); - await expectTxFailure(/rmrkCore\.ResourceDoesntExist/, tx); - }); - - it('[negative]: Non-owner user cannot confirm the deletion of resource', async () => { - const collectionIdAlice = await createCollection( - api, - alice, - 'test-metadata', - null, - 'test-symbol', - ); - - const nftAlice = await mintNft( - api, - alice, - alice, - collectionIdAlice, - 'nft-metadata', - ); - - const resourceId = await addNftBasicResource( - api, - alice, - 'added', - collectionIdAlice, - nftAlice, - src, - metadata, - license, - thumb, - ); - - const tx = acceptResourceRemoval(api, bob, collectionIdAlice, nftAlice, resourceId); - await expectTxFailure(/rmrkCore\.NoPermission/, tx); - }); - - after(async() => { await api.disconnect(); }); -}); --- a/tests/src/.outdated/rmrk/rmrkIsolation.seqtest.ts +++ /dev/null @@ -1,225 +0,0 @@ -import {executeTransaction} from '../substrate/substrate-api'; -import {IKeyringPair} from '@polkadot/types/types'; -import {itSub, expect, usingPlaygrounds, Pallets, requirePalletsOrSkip} from '../../util'; -import {UniqueHelper} from '../../util/playgrounds/unique'; - -let alice: IKeyringPair; -let bob: IKeyringPair; - -async function createRmrkCollection(helper: UniqueHelper, sender: IKeyringPair): Promise<{uniqueId: number, rmrkId: number}> { - const result = await helper.executeExtrinsic(sender, 'api.tx.rmrkCore.createCollection', ['metadata', null, 'symbol'], true); - - const uniqueId = helper.util.extractCollectionIdFromCreationResult(result); - - let rmrkId = null; - result.result.events.forEach(({event: {data, method, section}}) => { - if ((section === 'rmrkCore') && (method === 'CollectionCreated')) { - rmrkId = parseInt(data[1].toString(), 10); - } - }); - - if (rmrkId === null) { - throw Error('No rmrkCore.CollectionCreated event was found!'); - } - - return { - uniqueId, - rmrkId, - }; -} - -async function createRmrkNft(helper: UniqueHelper, sender: IKeyringPair, collectionId: number): Promise { - const result = await helper.executeExtrinsic( - sender, - 'api.tx.rmrkCore.mintNft', - [ - sender.address, - collectionId, - sender.address, - null, - 'nft-metadata', - true, - null, - ], - true, - ); - - let rmrkNftId = null; - result.result.events.forEach(({event: {data, method, section}}) => { - if ((section === 'rmrkCore') && (method === 'NftMinted')) { - rmrkNftId = parseInt(data[2].toString(), 10); - } - }); - - if (rmrkNftId === null) { - throw Error('No rmrkCore.NftMinted event was found!'); - } - - return rmrkNftId; -} - -describe('RMRK External Integration Test', () => { - before(async function() { - await usingPlaygrounds(async (_helper, privateKey) => { - alice = await privateKey('//Alice'); - }); - }); - - itSub.ifWithPallets('Creates a new RMRK collection that is mapped to a different ID and is tagged as external', [Pallets.RmrkCore], async ({helper}) => { - // throw away collection to bump last Unique collection ID to test ID mapping - await helper.nft.mintCollection(alice, {tokenPrefix: 'unqt'}); - - const collectionIds = await createRmrkCollection(helper, alice); - - expect(collectionIds.rmrkId).to.be.lessThan(collectionIds.uniqueId, 'collection ID mapping'); - - const collection = (await helper.nft.getCollectionObject(collectionIds.uniqueId).getData())!; // (await getDetailedCollectionInfo(api, collectionIds.uniqueId))!; - expect(collection.raw.readOnly, 'tagged external').to.be.true; - }); -}); - -describe('Negative Integration Test: External Collections, Internal Ops', () => { - let uniqueCollectionId: number; - let rmrkCollectionId: number; - let rmrkNftId: number; - let normalizedAlice: {Substrate: string}; - - before(async function() { - await usingPlaygrounds(async (helper, privateKey) => { - alice = await privateKey('//Alice'); - bob = await privateKey('//Bob'); - normalizedAlice = {Substrate: helper.address.normalizeSubstrateToChainFormat(alice.address)}; - - requirePalletsOrSkip(this, helper, [Pallets.RmrkCore]); - - const collectionIds = await createRmrkCollection(helper, alice); - uniqueCollectionId = collectionIds.uniqueId; - rmrkCollectionId = collectionIds.rmrkId; - - rmrkNftId = await createRmrkNft(helper, alice, rmrkCollectionId); - }); - }); - - itSub.ifWithPallets('[Negative] Forbids Unique operations with an external collection, handled by dispatch_call', [Pallets.RmrkCore], async ({helper}) => { - // Collection item creation - - await expect(helper.nft.mintToken(alice, {collectionId: uniqueCollectionId, owner: {Substrate: alice.address}}), 'creating item') - .to.be.rejectedWith(/common\.CollectionIsExternal/); - - const txCreateMultipleItems = helper.getApi().tx.unique.createMultipleItems(uniqueCollectionId, normalizedAlice, [{NFT: {}}, {NFT: {}}]); - await expect(executeTransaction(helper.getApi(), alice, txCreateMultipleItems), 'creating multiple') - .to.be.rejectedWith(/common\.CollectionIsExternal/); - - await expect(helper.nft.mintMultipleTokens(alice, uniqueCollectionId, [{owner: {Substrate: alice.address}}]), 'creating multiple ex') - .to.be.rejectedWith(/common\.CollectionIsExternal/); - - // Collection properties - - await expect(helper.nft.setProperties(alice, uniqueCollectionId, [{key: 'a', value: '1'}, {key: 'b'}]), 'setting collection properties') - .to.be.rejectedWith(/common\.CollectionIsExternal/); - - await expect(helper.nft.deleteProperties(alice, uniqueCollectionId, ['a']), 'deleting collection properties') - .to.be.rejectedWith(/common\.CollectionIsExternal/); - - await expect(helper.nft.setTokenPropertyPermissions(alice, uniqueCollectionId, [{key: 'a', permission: {mutable: true}}]), 'setting property permissions') - .to.be.rejectedWith(/common\.CollectionIsExternal/); - - // NFT - - await expect(helper.nft.burnToken(alice, uniqueCollectionId, rmrkNftId, 1n), 'burning') - .to.be.rejectedWith(/common\.CollectionIsExternal/); - - await expect(helper.nft.burnTokenFrom(alice, uniqueCollectionId, rmrkNftId, {Substrate: alice.address}, 1n), 'burning-from') - .to.be.rejectedWith(/common\.CollectionIsExternal/); - - await expect(helper.nft.transferToken(alice, uniqueCollectionId, rmrkNftId, {Substrate: bob.address}), 'transferring') - .to.be.rejectedWith(/common\.CollectionIsExternal/); - - await expect(helper.nft.approveToken(alice, uniqueCollectionId, rmrkNftId, {Substrate: bob.address}), 'approving') - .to.be.rejectedWith(/common\.CollectionIsExternal/); - - await expect(helper.nft.transferTokenFrom(alice, uniqueCollectionId, rmrkNftId, {Substrate: alice.address}, {Substrate: bob.address}), 'transferring-from') - .to.be.rejectedWith(/common\.CollectionIsExternal/); - - // NFT properties - - await expect(helper.nft.setTokenProperties(alice, uniqueCollectionId, rmrkNftId, [{key: 'a', value: '2'}]), 'setting token properties') - .to.be.rejectedWith(/common\.CollectionIsExternal/); - - await expect(helper.nft.deleteTokenProperties(alice, uniqueCollectionId, rmrkNftId, ['a'])) - .to.be.rejectedWith(/common\.CollectionIsExternal/); - }); - - itSub.ifWithPallets('[Negative] Forbids Unique collection operations with an external collection', [Pallets.RmrkCore], async ({helper}) => { - await expect(helper.nft.burn(alice, uniqueCollectionId), 'destroying collection') - .to.be.rejectedWith(/common\.CollectionIsExternal/); - - // Allow list - - await expect(helper.nft.addToAllowList(alice, uniqueCollectionId, {Substrate: bob.address}), 'adding to allow list') - .to.be.rejectedWith(/common\.CollectionIsExternal/); - - await expect(helper.nft.removeFromAllowList(alice, uniqueCollectionId, {Substrate: bob.address}), 'removing from allowlist') - .to.be.rejectedWith(/common\.CollectionIsExternal/); - - // Owner / Admin / Sponsor - - await expect(helper.nft.changeOwner(alice, uniqueCollectionId, bob.address), 'changing owner') - .to.be.rejectedWith(/common\.CollectionIsExternal/); - - await expect(helper.nft.addAdmin(alice, uniqueCollectionId, {Substrate: bob.address}), 'adding admin') - .to.be.rejectedWith(/common\.CollectionIsExternal/); - - await expect(helper.nft.removeAdmin(alice, uniqueCollectionId, {Substrate: bob.address}), 'removing admin') - .to.be.rejectedWith(/common\.CollectionIsExternal/); - - await expect(helper.nft.setSponsor(alice, uniqueCollectionId, bob.address), 'setting sponsor') - .to.be.rejectedWith(/common\.CollectionIsExternal/); - - await expect(helper.nft.confirmSponsorship(alice, uniqueCollectionId), 'confirming sponsor') - .to.be.rejectedWith(/common\.CollectionIsExternal/); - - await expect(helper.nft.removeSponsor(alice, uniqueCollectionId), 'removing sponsor') - .to.be.rejectedWith(/common\.CollectionIsExternal/); - - // Limits / permissions / transfers - - const txSetTransfers = helper.getApi().tx.unique.setTransfersEnabledFlag(uniqueCollectionId, true); - await expect(executeTransaction(helper.getApi(), alice, txSetTransfers), 'setting transfers enabled flag') - .to.be.rejectedWith(/common\.CollectionIsExternal/); - - await expect(helper.nft.setLimits(alice, uniqueCollectionId, {transfersEnabled: false}), 'setting collection limits') - .to.be.rejectedWith(/common\.CollectionIsExternal/); - - await expect(helper.nft.setPermissions(alice, uniqueCollectionId, {access: 'AllowList'}), 'setting collection permissions') - .to.be.rejectedWith(/common\.CollectionIsExternal/); - }); -}); - -describe('Negative Integration Test: Internal Collections, External Ops', () => { - let collectionId: number; - let nftId: number; - - before(async () => { - await usingPlaygrounds(async (helper, privateKey) => { - alice = await privateKey('//Alice'); - bob = await privateKey('//Bob'); - - const collection = await helper.nft.mintCollection(alice, {tokenPrefix: 'iceo'}); - collectionId = collection.collectionId; - nftId = (await collection.mintToken(alice)).tokenId; - }); - }); - - itSub.ifWithPallets('[Negative] Forbids RMRK operations with the internal collection and NFT (due to the lack of mapping)', [Pallets.RmrkCore], async ({helper}) => { - const api = helper.getApi(); - - const txChangeOwner = api.tx.rmrkCore.changeCollectionIssuer(collectionId, bob.address); - await expect(executeTransaction(api, alice, txChangeOwner), 'changing collection issuer') - .to.be.rejectedWith(/rmrkCore\.CollectionUnknown/); - - const maxBurns = 10; - const txBurnItem = api.tx.rmrkCore.burnNft(collectionId, nftId, maxBurns); - await expect(executeTransaction(api, alice, txBurnItem), 'burning NFT').to.be.rejectedWith(/rmrkCore\.CollectionUnknown/); - }); -}); --- a/tests/src/.outdated/rmrk/sendNft.seqtest.ts +++ /dev/null @@ -1,255 +0,0 @@ -import {expect} from 'chai'; -import {getApiConnection} from '../substrate/substrate-api'; -import {createCollection, mintNft, sendNft} from './util/tx'; -import {NftIdTuple} from './util/fetch'; -import {isNftChildOfAnother, expectTxFailure, requirePallets, Pallets} from './util/helpers'; - -describe('integration test: send NFT', () => { - let api: any; - before(async function () { - api = await getApiConnection(); - await requirePallets(this, [Pallets.RmrkCore]); - }); - - const maxNftId = 0xFFFFFFFF; - - const alice = '//Alice'; - const bob = '//Bob'; - - const createTestCollection = async (issuerUri: string) => { - return await createCollection( - api, - issuerUri, - 'nft-collection-metadata', - null, - 'nft-collection', - ); - }; - - - it('send NFT to another user', async () => { - const originalOwnerUri = alice; - const newOwnerUri = bob; - - const collectionId = await createTestCollection(alice); - - const nftId = await mintNft(api, alice, originalOwnerUri, collectionId, 'nft-metadata'); - - await sendNft(api, 'sent', originalOwnerUri, collectionId, nftId, newOwnerUri); - }); - - it('[negative] unable to send non-existing NFT', async () => { - const originalOwnerUri = alice; - const newOwnerUri = bob; - - const collectionId = 0; - const tx = sendNft(api, 'sent', originalOwnerUri, collectionId, maxNftId, newOwnerUri); - - await expectTxFailure(/rmrkCore\.NoAvailableNftId/, tx); - }); - - it('[negative] unable to send NFT by a not-an-owner', async () => { - const originalOwnerUri = alice; - const newOwnerUri = bob; - - const collectionId = await createTestCollection(alice); - - const nftId = await mintNft(api, alice, originalOwnerUri, collectionId, 'nft-metadata'); - - const tx = sendNft(api, 'sent', newOwnerUri, collectionId, nftId, newOwnerUri); - await expectTxFailure(/rmrkCore\.NoPermission/, tx); - }); - - it('send NFT to another NFT (same owner)', async () => { - const originalOwnerUri = alice; - - const collectionId = await createTestCollection(alice); - - const parentNftId = await mintNft(api, alice, originalOwnerUri, collectionId, 'parent-nft-metadata'); - const childNftId = await mintNft(api, alice, originalOwnerUri, collectionId, 'child-nft-metadata'); - - const newOwnerNFT: NftIdTuple = [collectionId, parentNftId]; - - await sendNft(api, 'sent', alice, collectionId, childNftId, newOwnerNFT); - - const isChild = await isNftChildOfAnother(api, collectionId, childNftId, newOwnerNFT); - expect(isChild).to.be.true; - }); - - it('[negative] send non-existing NFT to another NFT', async () => { - const originalOwnerUri = alice; - - const collectionId = await createTestCollection(alice); - - const parentNftId = await mintNft(api, alice, originalOwnerUri, collectionId, 'parent-nft-metadata'); - const childNftId = maxNftId; - - const newOwnerNFT: NftIdTuple = [collectionId, parentNftId]; - - const tx = sendNft(api, 'sent', alice, collectionId, childNftId, newOwnerNFT); - - await expectTxFailure(/rmrkCore\.NoAvailableNftId/, tx); - - const isChild = await isNftChildOfAnother(api, collectionId, childNftId, newOwnerNFT); - expect(isChild).to.be.false; - }); - - it('send NFT to another NFT (by not-an-owner)', async () => { - const originalOwnerUri = alice; - - const collectionId = await createTestCollection(alice); - - const author = alice; - const attacker = bob; - - const parentNftId = await mintNft(api, author, originalOwnerUri, collectionId, 'parent-nft-metadata'); - const childNftId = await mintNft(api, author, originalOwnerUri, collectionId, 'child-nft-metadata'); - - const newOwnerNFT: NftIdTuple = [collectionId, parentNftId]; - - const tx = sendNft(api, 'sent', attacker, collectionId, childNftId, newOwnerNFT); - - await expectTxFailure(/rmrkCore\.NoPermission/, tx); - - const isChild = await isNftChildOfAnother(api, collectionId, childNftId, newOwnerNFT); - expect(isChild).to.be.false; - }); - - it('[negative] send NFT to non-existing NFT', async () => { - const originalOwnerUri = alice; - - const collectionId = await createTestCollection(alice); - - const parentNftId = maxNftId; - const childNftId = await mintNft(api, alice, originalOwnerUri, collectionId, 'child-nft-metadata'); - - const newOwnerNFT: NftIdTuple = [collectionId, parentNftId]; - - const tx = sendNft(api, 'sent', alice, collectionId, childNftId, newOwnerNFT); - - await expectTxFailure(/rmrkCore\.NoAvailableNftId/, tx); - - const isChild = await isNftChildOfAnother(api, collectionId, childNftId, newOwnerNFT); - expect(isChild).to.be.false; - }); - - it('send NFT to another NFT owned by another user', async () => { - const ownerAlice = alice; - const ownerBob = bob; - - const aliceCollectionId = await createTestCollection(alice); - const bobCollectionId = await createTestCollection(bob); - - const parentNftId = await mintNft(api, alice, ownerAlice, aliceCollectionId, 'parent-nft-metadata'); - const childNftId = await mintNft(api, bob, ownerBob, bobCollectionId, 'child-nft-metadata'); - - const newOwnerNFT: NftIdTuple = [aliceCollectionId, parentNftId]; - - await sendNft(api, 'pending', bob, bobCollectionId, childNftId, newOwnerNFT); - }); - - it('[negative] unable to send NFT to itself', async () => { - const nftOwner = alice; - const collectionId = await createTestCollection(alice); - - const nftId = await mintNft(api, alice, nftOwner, collectionId, 'ouroboros-nft-metadata'); - - const newOwnerNFT: NftIdTuple = [collectionId, nftId]; - - const tx = sendNft(api, 'sent', alice, collectionId, nftId, newOwnerNFT); - - await expectTxFailure(/rmrkCore\.CannotSendToDescendentOrSelf/, tx); - - const isChild = await isNftChildOfAnother(api, collectionId, nftId, newOwnerNFT); - expect(isChild).to.be.false; - }); - - it('[negative] unable to send NFT to child NFT', async () => { - const originalOwnerUri = alice; - - const collectionId = await createTestCollection(alice); - - const parentNftId = await mintNft(api, alice, originalOwnerUri, collectionId, 'parent-nft-metadata'); - const childNftId = await mintNft(api, alice, originalOwnerUri, collectionId, 'child-nft-metadata'); - - const newOwnerNFT: NftIdTuple = [collectionId, parentNftId]; - - await sendNft(api, 'sent', alice, collectionId, childNftId, newOwnerNFT); - - const isChild = await isNftChildOfAnother(api, collectionId, childNftId, newOwnerNFT); - expect(isChild).to.be.true; - - const descendentOwner: NftIdTuple = [collectionId, childNftId]; - const tx = sendNft(api, 'sent', alice, collectionId, parentNftId, descendentOwner); - - await expectTxFailure(/rmrkCore\.CannotSendToDescendentOrSelf/, tx); - const isOuroboros = await isNftChildOfAnother(api, collectionId, parentNftId, descendentOwner); - expect(isOuroboros).to.be.false; - }); - - it('[negative] unable to send NFT to descendent NFT', async () => { - const originalOwnerUri = alice; - - const collectionId = await createTestCollection(alice); - - const parentNftId = await mintNft(api, alice, originalOwnerUri, collectionId, 'parent-nft-metadata'); - const childNftId = await mintNft(api, alice, originalOwnerUri, collectionId, 'child-nft-metadata'); - const grandsonNftId = await mintNft(api, alice, originalOwnerUri, collectionId, 'grandson-nft-metadata'); - - const ownerParentNFT: NftIdTuple = [collectionId, parentNftId]; - - await sendNft(api, 'sent', alice, collectionId, childNftId, ownerParentNFT); - - const isChild = await isNftChildOfAnother(api, collectionId, childNftId, ownerParentNFT); - expect(isChild).to.be.true; - - const ownerChildNFT: NftIdTuple = [collectionId, childNftId]; - await sendNft(api, 'sent', alice, collectionId, grandsonNftId, ownerChildNFT); - - const isGrandson = await isNftChildOfAnother(api, collectionId, grandsonNftId, ownerChildNFT); - expect(isGrandson).to.be.true; - - const ownerGrandsonNFT: NftIdTuple = [collectionId, grandsonNftId]; - const tx = sendNft(api, 'sent', alice, collectionId, parentNftId, ownerGrandsonNFT); - - await expectTxFailure(/rmrkCore\.CannotSendToDescendentOrSelf/, tx); - const isOuroboros = await isNftChildOfAnother(api, collectionId, parentNftId, ownerGrandsonNFT); - expect(isOuroboros).to.be.false; - }); - - it('send nested NFT to another user', async () => { - const originalOwner = alice; - const newOwner = bob; - - const collectionId = await createTestCollection(alice); - - const parentNftId = await mintNft(api, alice, originalOwner, collectionId, 'parent-nft-metadata'); - const childNftId = await mintNft(api, alice, originalOwner, collectionId, 'child-nft-metadata'); - - const parentNftTuple: NftIdTuple = [collectionId, parentNftId]; - - await sendNft(api, 'sent', originalOwner, collectionId, childNftId, parentNftTuple); - - await sendNft(api, 'sent', originalOwner, collectionId, childNftId, newOwner); - }); - - it('[negative] send nested NFT to another user (by a not-root-owner)', async () => { - const originalOwner = alice; - const newOwner = bob; - - const collectionId = await createTestCollection(alice); - - const parentNftId = await mintNft(api, alice, originalOwner, collectionId, 'parent-nft-metadata'); - const childNftId = await mintNft(api, alice, originalOwner, collectionId, 'child-nft-metadata'); - - const parentNftTuple: NftIdTuple = [collectionId, parentNftId]; - - await sendNft(api, 'sent', originalOwner, collectionId, childNftId, parentNftTuple); - - const tx = sendNft(api, 'sent', newOwner, collectionId, childNftId, newOwner); - - await expectTxFailure(/rmrkCore\.NoPermission/, tx); - }); - - after(async() => { await api.disconnect(); }); -}); --- a/tests/src/.outdated/rmrk/setCollectionProperty.seqtest.ts +++ /dev/null @@ -1,66 +0,0 @@ -import {getApiConnection} from '../substrate/substrate-api'; -import {expectTxFailure, requirePallets, Pallets} from './util/helpers'; -import {createCollection, setPropertyCollection} from './util/tx'; - -describe('integration test: set collection property', () => { - const alice = '//Alice'; - const bob = '//Bob'; - - let api: any; - before(async function () { - api = await getApiConnection(); - await requirePallets(this, [Pallets.RmrkCore]); - }); - - it('set collection property', async () => { - await createCollection( - api, - alice, - 'test-metadata', - null, - 'test-symbol', - ).then(async (collectionId) => { - await setPropertyCollection(api, alice, collectionId, 'test_key', '42'); - await setPropertyCollection(api, alice, collectionId, 'test_key', '10'); - await setPropertyCollection( - api, - alice, - collectionId, - 'second_test_key', - '111', - ); - }); - }); - - it('[negative] set non-existing collection property', async () => { - const tx = setPropertyCollection( - api, - alice, - 9999, - 'test_key', - '42', - ); - await expectTxFailure(/rmrkCore\.CollectionUnknown/, tx); - }); - - it('[negative] set property not an owner NFT collection issuer', async () => { - await createCollection( - api, - bob, - 'test-metadata', - null, - 'test-symbol', - ).then(async (collectionId) => { - const tx = setPropertyCollection( - api, - alice, - collectionId, - 'test_key', - '42', - ); - await expectTxFailure(/rmrkCore\.NoPermission/, tx); - }); - }); - - after(async() => { await api.disconnect(); }); -}); --- a/tests/src/.outdated/rmrk/setEquippableList.seqtest.ts +++ /dev/null @@ -1,114 +0,0 @@ -import {getApiConnection} from '../substrate/substrate-api'; -import {expectTxFailure, requirePallets, Pallets} from './util/helpers'; -import {createCollection, createBase, setEquippableList} from './util/tx'; - -describe("integration test: set slot's Equippable List", () => { - let api: any; - before(async function () { - api = await getApiConnection(); - await requirePallets(this, [Pallets.RmrkCore]); - }); - - const alice = '//Alice'; - const bob = '//Bob'; - - it("set Base's slot Equippable List", async () => { - const collectionIds = [ - await createCollection( - api, - alice, - 'equiplist-collection-metadata', - null, - 'equiplist-0', - ), - await createCollection( - api, - alice, - 'equiplist-collection-metadata', - null, - 'equiplist-1', - ), - ]; - - const slotId = 202; - - const baseId = await createBase(api, alice, 'slotpartany-base-type', 'slotpartany', [ - { - 'SlotPart': { - id: slotId, - equippable: 'All', - z: 1, - src: 'some-fallback-slot-url', - }, - }, - ]); - - await setEquippableList(api, alice, baseId, slotId, 'All'); - await setEquippableList(api, alice, baseId, slotId, 'Empty'); - await setEquippableList(api, alice, baseId, slotId, {'Custom': collectionIds}); - }); - - it('[negative] unable to set equippable list of a slot of non-existing base', async () => { - const maxBaseId = 0xFFFFFFFF; - const slotId = 0; - - const tx = setEquippableList(api, alice, maxBaseId, slotId, 'All'); - await expectTxFailure(/rmrkEquip\.BaseDoesntExist/, tx); - }); - - it('[negative] unable to set equippable list by a not-an-owner', async () => { - const slotId = 42; - - const baseId = await createBase(api, alice, 'slotpartany-base-type', 'slotpartany', [ - { - 'SlotPart': { - id: slotId, - equippable: 'All', - z: 1, - src: 'some-fallback-slot-url', - }, - }, - ]); - - const tx = setEquippableList(api, bob, baseId, slotId, 'All'); - await expectTxFailure(/rmrkEquip\.PermissionError/, tx); - }); - - it('[negative] unable to set equippable list to a fixed part', async () => { - const fixedPartId = 42; - - const baseId = await createBase(api, alice, 'fixedpart-base-type', 'fixedpart', [ - { - 'FixedPart': { - id: fixedPartId, - z: 0, - src: 'fixed-part-url', - }, - }, - ]); - - const tx = setEquippableList(api, alice, baseId, fixedPartId, 'All'); - await expectTxFailure(/rmrkEquip\.NoEquippableOnFixedPart/, tx); - }); - - it('[negative] unable to set equippable list to non-existing slot', async () => { - const slotId = 777; - const maxSlotId = 0xFFFFFFFF; - - const baseId = await createBase(api, alice, 'slotpartany-base-type', 'slotpartany', [ - { - 'SlotPart': { - id: slotId, - equippable: 'All', - z: 1, - src: 'some-fallback-slot-url', - }, - }, - ]); - - const tx = setEquippableList(api, alice, baseId, maxSlotId, 'All'); - await expectTxFailure(/rmrkEquip\.PartDoesntExist/, tx); - }); - - after(async() => { await api.disconnect(); }); -}); --- a/tests/src/.outdated/rmrk/setNftProperty.seqtest.ts +++ /dev/null @@ -1,88 +0,0 @@ -import {getApiConnection} from '../substrate/substrate-api'; -import {NftIdTuple} from './util/fetch'; -import {expectTxFailure, requirePallets, Pallets} from './util/helpers'; -import {createCollection, mintNft, sendNft, setNftProperty} from './util/tx'; - -describe('integration test: set NFT property', () => { - let api: any; - before(async function () { - api = await getApiConnection(); - await requirePallets(this, [Pallets.RmrkCore]); - }); - - const alice = '//Alice'; - const bob = '//Bob'; - - const createTestCollection = async (issuerUri: string) => { - return await createCollection( - api, - issuerUri, - 'setprop-nft-collection-metadata', - null, - 'setprop', - ); - }; - - it('set NFT property', async () => { - const ownerAlice = alice; - - const collectionId = await createTestCollection(alice); - const nftId = await mintNft(api, alice, ownerAlice, collectionId, 'prop-nft'); - - await setNftProperty(api, alice, collectionId, nftId, 'test-key', 'test-key-value'); - await setNftProperty(api, alice, collectionId, nftId, 'test-key', 'updated-key-value'); - await setNftProperty(api, alice, collectionId, nftId, 'second-test-key', 'second-test-key-value'); - }); - - it('[negative] unable to set a property of non-existing NFT', async () => { - const collectionId = 0; - const maxNftId = 0xFFFFFFFF; - - const tx = setNftProperty(api, alice, collectionId, maxNftId, 'test-key', 'test-value'); - - await expectTxFailure(/rmrkCore\.NoAvailableNftId/, tx); - }); - - it('[negative] unable to set a property by not-an-owner', async () => { - const ownerAlice = alice; - - const collectionId = await createTestCollection(alice); - const nftId = await mintNft(api, alice, ownerAlice, collectionId, 'prop-nft'); - - const tx = setNftProperty(api, bob, collectionId, nftId, 'test-key', 'test-key-value'); - - await expectTxFailure(/rmrkCore\.NoPermission/, tx); - }); - - it('set a property to nested NFT', async () => { - const ownerAlice = alice; - - const collectionId = await createTestCollection(alice); - const parentNftId = await mintNft(api, alice, ownerAlice, collectionId, 'prop-parent-nft'); - const childNftId = await mintNft(api, alice, ownerAlice, collectionId, 'prop-child-nft'); - - const ownerNft: NftIdTuple = [collectionId, parentNftId]; - - await sendNft(api, 'sent', ownerAlice, collectionId, childNftId, ownerNft); - - await setNftProperty(api, alice, collectionId, childNftId, 'test-key', 'test-key-value'); - }); - - it('[negative] set a property to nested NFT (by not-root-owner)', async () => { - const ownerAlice = alice; - - const collectionId = await createTestCollection(alice); - const parentNftId = await mintNft(api, alice, ownerAlice, collectionId, 'prop-parent-nft'); - const childNftId = await mintNft(api, alice, ownerAlice, collectionId, 'prop-child-nft'); - - const ownerNft: NftIdTuple = [collectionId, parentNftId]; - - await sendNft(api, 'sent', ownerAlice, collectionId, childNftId, ownerNft); - - const tx = setNftProperty(api, bob, collectionId, childNftId, 'test-key', 'test-key-value'); - - await expectTxFailure(/rmrkCore\.NoPermission/, tx); - }); - - after(async() => { await api.disconnect(); }); -}); --- a/tests/src/.outdated/rmrk/setResourcePriorities.seqtest.ts +++ /dev/null @@ -1,56 +0,0 @@ -import {getApiConnection} from '../substrate/substrate-api'; -import {expectTxFailure, requirePallets, Pallets} from './util/helpers'; -import {mintNft, createCollection, setResourcePriorities} from './util/tx'; - -describe('integration test: set NFT resource priorities', () => { - let api: any; - before(async function () { - api = await getApiConnection(); - await requirePallets(this, [Pallets.RmrkCore]); - }); - - const alice = '//Alice'; - const bob = '//Bob'; - - const createTestCollection = (issuerUri: string) => { - return createCollection( - api, - issuerUri, - 'resprio-collection-metadata', - null, - 'resprio', - ); - }; - - it('set NFT resource priorities', async () => { - const owner = alice; - - const collectionId = await createTestCollection(alice); - const nftId = await mintNft(api, alice, owner, collectionId, 'resprio-nft-metadata'); - - await setResourcePriorities(api, alice, collectionId, nftId, [10, 42]); - }); - - it('[negative] set NFT resource priorities by a not-an-owner', async () => { - const owner = alice; - const attacker = bob; - - const collectionId = await createTestCollection(alice); - const nftId = await mintNft(api, alice, owner, collectionId, 'resprio-nft-metadata'); - - const tx = setResourcePriorities(api, attacker, collectionId, nftId, [10, 42]); - - await expectTxFailure(/rmrkCore\.NoPermission/, tx); - }); - - it('[negative] set NFT resource priorities to non-existing NFT', async () => { - const collectionId = 0; - const maxNftId = 0xFFFFFFFF; - - const tx = setResourcePriorities(api, alice, collectionId, maxNftId, [10, 42]); - - await expectTxFailure(/rmrkCore\.NoAvailableNftId/, tx); - }); - - after(async() => { await api.disconnect(); }); -}); --- a/tests/src/.outdated/rmrk/util/fetch.ts +++ /dev/null @@ -1,130 +0,0 @@ -import {ApiPromise} from '@polkadot/api'; -import type {Option} from '@polkadot/types-codec'; -import type { - RmrkTraitsCollectionCollectionInfo as Collection, - RmrkTraitsNftNftInfo as Nft, - RmrkTraitsResourceResourceInfo as Resource, - RmrkTraitsBaseBaseInfo as Base, - RmrkTraitsPartPartType as PartType, - RmrkTraitsNftNftChild as NftChild, - RmrkTraitsTheme as Theme, - RmrkTraitsPropertyPropertyInfo as Property, -} from '../../../interfaces/default/types'; // '@polkadot/types/lookup'; -import '../../../interfaces/augment-api'; -import '../../../interfaces/augment-api-query'; -import privateKey from '../../substrate/privateKey'; - -export type NftIdTuple = [number, number]; - -export async function getCollectionsCount(api: ApiPromise): Promise { - return (await api.rpc.rmrk.lastCollectionIdx()).toNumber(); -} - -export function getCollection(api: ApiPromise, id: number): Promise> { - return api.rpc.rmrk.collectionById(id); -} - -export async function getOwnedNfts( - api: ApiPromise, - ownerUri: string, - collectionId: number, -): Promise { - const ss58Format = api.registry.getChainProperties()!.toJSON().ss58Format; - const owner = privateKey(ownerUri, Number(ss58Format)); - - return (await api.rpc.rmrk.accountTokens(owner.address, collectionId)) - .map((value) => value.toNumber()); -} - -export function getNft(api: ApiPromise, collectionId: number, nftId: number): Promise> { - return api.rpc.rmrk.nftById(collectionId, nftId); -} - -export async function getCollectionProperties(api: ApiPromise, collectionId: number): Promise { - return (await api.rpc.rmrk.collectionProperties(collectionId)).toArray(); -} - -export async function getNftProperties(api: ApiPromise, collectionId: number, nftId: number): Promise { - return (await api.rpc.rmrk.nftProperties(collectionId, nftId)).toArray(); -} - -export async function getChildren( - api: ApiPromise, - collectionId: number, - nftId: number, -): Promise { - return (await api.rpc.rmrk.nftChildren(collectionId, nftId)).toArray(); -} - -export function getBase(api: ApiPromise, baseId: number): Promise> { - return api.rpc.rmrk.base(baseId); -} - -export async function getParts(api: ApiPromise, baseId: number): Promise { - return (await api.rpc.rmrk.baseParts(baseId)).toArray(); -} - -export async function getEquippableList( - api: ApiPromise, - baseId: number, - slotId: number, -): Promise<'All' | 'Empty' | { 'Custom': number[] } | null> { - const parts = await getParts(api, baseId); - - const part = parts.find((part) => { - if (part.isSlotPart) { - return part.asSlotPart.id.toNumber() === slotId; - } else { - return false; - } - }); - - if (part) { - const slot = part.asSlotPart; - if (slot.equippable.isCustom) { - return { - 'Custom': slot.equippable.asCustom - .toArray() - .map((collectionId) => collectionId.toNumber()), - }; - } else if (slot.equippable.isAll) { - return 'All'; - } else { - return 'Empty'; - } - } else { - return null; - } -} - -export async function getResourcePriority( - api: ApiPromise, - collectionId: number, - nftId: number, - resourceId: number, -): Promise { - return (await api.rpc.rmrk.nftResourcePriority(collectionId, nftId, resourceId)) - .unwrap().toNumber(); -} - -export async function getThemeNames(api: ApiPromise, baseId: number): Promise { - return (await api.rpc.rmrk.themeNames(baseId)) - .map((name) => name.toUtf8()); -} - -export function getTheme( - api: ApiPromise, - baseId: number, - themeName: string, - keys: string[] | null = null, -): Promise> { - return api.rpc.rmrk.themes(baseId, themeName, keys); -} - -export async function getResources( - api: ApiPromise, - collectionId: number, - nftId: number, -): Promise { - return (await api.rpc.rmrk.nftResources(collectionId, nftId)).toArray(); -} --- a/tests/src/.outdated/rmrk/util/helpers.ts +++ /dev/null @@ -1,249 +0,0 @@ -import {ApiPromise} from '@polkadot/api'; -import { - RmrkTraitsNftAccountIdOrCollectionNftTuple as NftOwner, - RmrkTraitsPropertyPropertyInfo as Property, - RmrkTraitsResourceResourceInfo as ResourceInfo, -} from '@polkadot/types/lookup'; -import type {EventRecord} from '@polkadot/types/interfaces'; -import type {GenericEventData} from '@polkadot/types'; -import privateKey from '../../substrate/privateKey'; -import {NftIdTuple, getChildren, getOwnedNfts, getCollectionProperties, getNftProperties, getResources} from './fetch'; -import chaiAsPromised from 'chai-as-promised'; -import chai from 'chai'; -import {getApiConnection} from '../../substrate/substrate-api'; -import {Context} from 'mocha'; - -chai.use(chaiAsPromised); -const expect = chai.expect; - -interface TxResult { - success: boolean; - successData: T | null; -} - -export enum Pallets { - Inflation = 'inflation', - RmrkCore = 'rmrkcore', - RmrkEquip = 'rmrkequip', - ReFungible = 'refungible', - Fungible = 'fungible', - NFT = 'nonfungible', - Scheduler = 'scheduler', - AppPromotion = 'apppromotion', -} - -let modulesNames: any; -export function getModuleNames(api: ApiPromise): string[] { - if (typeof modulesNames === 'undefined') - modulesNames = api.runtimeMetadata.asLatest.pallets.map(m => m.name.toString().toLowerCase()); - return modulesNames; -} - -export async function missingRequiredPallets(requiredPallets: string[]): Promise { - const api = await getApiConnection(); - const pallets = getModuleNames(api); - await api.disconnect(); - - return requiredPallets.filter(p => !pallets.includes(p)); -} - -export async function requirePallets(mocha: Context, requiredPallets: string[]) { - const missingPallets = await missingRequiredPallets(requiredPallets); - - if (missingPallets.length > 0) { - const skippingTestMsg = `\tSkipping test "${mocha.test?.title}".`; - const missingPalletsMsg = `\tThe following pallets are missing:\n\t- ${missingPallets.join('\n\t- ')}`; - const skipMsg = `${skippingTestMsg}\n${missingPalletsMsg}`; - - console.error('\x1b[38:5:208m%s\x1b[0m', skipMsg); - - mocha.skip(); - } -} - -export function makeNftOwner(api: ApiPromise, owner: string | NftIdTuple): NftOwner { - const isNftSending = (typeof owner !== 'string'); - - if (isNftSending) { - return api.createType('RmrkTraitsNftAccountIdOrCollectionNftTuple', { - 'CollectionAndNftTuple': owner, - }); - } else { - const ss58Format = api.registry.getChainProperties()!.toJSON().ss58Format; - return api.createType('RmrkTraitsNftAccountIdOrCollectionNftTuple', { - AccountId: privateKey(owner, Number(ss58Format)).address, - }); - } -} - -export async function isNftOwnedBy( - api: ApiPromise, - owner: string | NftIdTuple, - collectionId: number, - nftId: number, -): Promise { - if (typeof owner === 'string') { - return (await getOwnedNfts(api, owner, collectionId)) - .find(ownedNftId => { - return ownedNftId === nftId; - }) !== undefined; - } else { - return (await getChildren(api, owner[0], owner[1])) - .find(child => { - return collectionId === child.collectionId.toNumber() - && nftId === child.nftId.toNumber(); - }) !== undefined; - } -} - -export function isPropertyExists( - key: string, - value: string, - props: Property[], -): boolean { - let isPropFound = false; - for (let i = 0; i < props.length && !isPropFound; i++) { - const fetchedProp = props[i]; - - isPropFound = fetchedProp.key.eq(key) - && fetchedProp.value.eq(value); - } - - return isPropFound; -} - -export async function isCollectionPropertyExists( - api: ApiPromise, - collectionId: number, - key: string, - value: string, -): Promise { - const fetchedProps = await getCollectionProperties(api, collectionId); - return isPropertyExists(key, value, fetchedProps); -} - -export async function isNftPropertyExists( - api: ApiPromise, - collectionId: number, - nftId: number, - key: string, - value: string, -): Promise { - const fetchedProps = await getNftProperties(api, collectionId, nftId); - return isPropertyExists(key, value, fetchedProps); -} - -export async function isNftChildOfAnother( - api: ApiPromise, - collectionId: number, - nftId: number, - parentNft: NftIdTuple, -): Promise { - return (await getChildren(api, parentNft[0], parentNft[1])) - .find((childNft) => { - return childNft.collectionId.toNumber() === collectionId - && childNft.nftId.toNumber() === nftId; - }) !== undefined; -} - -export function isTxResultSuccess(events: EventRecord[]): boolean { - let success = false; - - events.forEach(({event: {method}}) => { - if (method == 'ExtrinsicSuccess') { - success = true; - } - }); - - return success; -} - -export async function expectTxFailure(expectedError: RegExp, promise: Promise) { - await expect(promise).to.be.rejectedWith(expectedError); -} - -export function extractTxResult( - events: EventRecord[], - expectSection: string, - expectMethod: string, - extractAction: (data: any) => T, -): TxResult { - let success = false; - let successData = null; - events.forEach(({event: {data, method, section}}) => { - if (method == 'ExtrinsicSuccess') { - success = true; - } else if ((expectSection == section) && (expectMethod == method)) { - successData = extractAction(data); - } - }); - const result: TxResult = { - success, - successData, - }; - return result; -} - -export function extractRmrkCoreTxResult( - events: EventRecord[], - expectMethod: string, - extractAction: (data: GenericEventData) => T, -): TxResult { - return extractTxResult(events, 'rmrkCore', expectMethod, extractAction); -} - -export function extractRmrkEquipTxResult( - events: EventRecord[], - expectMethod: string, - extractAction: (data: GenericEventData) => T, -): TxResult { - return extractTxResult(events, 'rmrkEquip', expectMethod, extractAction); -} - -export async function findResourceById( - api: ApiPromise, - collectionId: number, - nftId: number, - resourceId: number, -): Promise { - const resources = await getResources(api, collectionId, nftId); - - let resource = null; - - for (let i = 0; i < resources.length; i++) { - const res = resources[i]; - - if (res.id.eq(resourceId)) { - resource = res; - break; - } - } - - return resource!; -} - -export async function getResourceById( - api: ApiPromise, - collectionId: number, - nftId: number, - resourceId: number, -): Promise { - const resource = await findResourceById( - api, - collectionId, - nftId, - resourceId, - ); - - expect(resource !== null, 'Error: resource was not found').to.be.true; - - return resource!; -} - -export function checkResourceStatus( - resource: ResourceInfo, - expectedStatus: 'pending' | 'added', -) { - expect(resource.pending.isTrue, `Error: added resource should be ${expectedStatus}`) - .to.be.equal(expectedStatus === 'pending'); -} --- a/tests/src/.outdated/rmrk/util/tx.ts +++ /dev/null @@ -1,1132 +0,0 @@ -import {ApiPromise} from '@polkadot/api'; -import {Bytes, Option, u32, Vec} from '@polkadot/types-codec'; -import { - RmrkTraitsNftAccountIdOrCollectionNftTuple as NftOwner, RmrkTraitsPartEquippableList as EquippableList, - RmrkTraitsPartPartType as PartType, RmrkTraitsResourceBasicResource as BasicResource, - RmrkTraitsResourceComposableResource as ComposableResource, RmrkTraitsResourceResourceInfo as ResourceInfo, RmrkTraitsResourceSlotResource as SlotResource, RmrkTraitsTheme as Theme, -} from '@polkadot/types/lookup'; -import {IKeyringPair} from '@polkadot/types/types'; -import chai from 'chai'; -import chaiAsPromised from 'chai-as-promised'; -import '../../../interfaces/augment-api'; -import privateKey from '../../substrate/privateKey'; -import {executeTransaction} from '../../substrate/substrate-api'; -import { - getBase, - getCollection, - getCollectionsCount, - getEquippableList, - getNft, - getParts, - getResources, - getResourcePriority, - getTheme, - NftIdTuple, -} from './fetch'; -import { - extractRmrkCoreTxResult, - extractRmrkEquipTxResult, isCollectionPropertyExists, isNftOwnedBy, isNftPropertyExists, isTxResultSuccess, makeNftOwner, - findResourceById, getResourceById, checkResourceStatus, -} from './helpers'; - -chai.use(chaiAsPromised); -const expect = chai.expect; - -export async function createCollection( - api: ApiPromise, - issuerUri: string, - metadata: string, - max: number | null, - symbol: string, -): Promise { - let collectionId = 0; - - const oldCollectionCount = await getCollectionsCount(api); - const maxOptional = max ? max.toString() : null; - const ss58Format = (api.registry.getChainProperties())!.toJSON().ss58Format; - const issuer = privateKey(issuerUri, Number(ss58Format)); - const tx = api.tx.rmrkCore.createCollection(metadata, maxOptional, symbol); - const events = await executeTransaction(api, issuer, tx); - - const collectionResult = extractRmrkCoreTxResult(events, 'CollectionCreated', (data) => { - return parseInt(data[1].toString(), 10); - }); - expect(collectionResult.success, 'Error: unable to create a collection').to.be.true; - - collectionId = collectionResult.successData!; - - const newCollectionCount = await getCollectionsCount(api); - const collectionOption = await getCollection(api, collectionId); - - expect(newCollectionCount).to.be.equal(oldCollectionCount + 1, 'Error: NFT collection count should increase'); - expect(collectionOption.isSome, 'Error: unable to fetch created NFT collection').to.be.true; - - const collection = collectionOption.unwrap(); - - expect(collection.metadata.toUtf8()).to.be.equal(metadata, 'Error: Invalid NFT collection metadata'); - expect(collection.max.isSome).to.be.equal(max !== null, 'Error: Invalid NFT collection max'); - - if (collection.max.isSome) { - expect(collection.max.unwrap().toNumber()).to.be.equal(max, 'Error: Invalid NFT collection max'); - } - expect(collection.symbol.toUtf8()).to.be.equal(symbol, "Error: Invalid NFT collection's symbol"); - expect(collection.nftsCount.toNumber()).to.be.equal(0, "Error: NFT collection shoudn't have any tokens"); - expect(collection.issuer.toString()).to.be.equal(issuer.address, 'Error: Invalid NFT collection issuer'); - - return collectionId; -} - -export async function changeIssuer( - api: ApiPromise, - issuerUri: string, - collectionId: number, - newIssuer: string, -) { - const ss58Format = api.registry.getChainProperties()!.toJSON().ss58Format; - const alice = privateKey(issuerUri, Number(ss58Format)); - const bob = privateKey(newIssuer, Number(ss58Format)); - - // This is only needed when RMRK uses `uniques` pallet by Parity - // let tx = api.tx.uniques.setAcceptOwnership( - // api.createType('Option', collectionId) - // ); - // let events = await executeTransaction(api, bob, tx); - // expect(isTxResultSuccess(events), 'Error: Unable to accept ownership').to.be.true; - - const tx = api.tx.rmrkCore.changeCollectionIssuer(collectionId, bob.address); - const events = await executeTransaction(api, alice, tx); - const changeIssuerResult = extractRmrkCoreTxResult(events, 'IssuerChanged', (data) => { - return parseInt(data[2].toString(), 10); - }); - expect(changeIssuerResult.success, 'Error: Unable to change NFT collection issuer').to.be.true; - expect(changeIssuerResult.successData!, 'Error: Invalid collection id after changing the issuer') - .to.be.eq(collectionId); - - await getCollection(api, collectionId).then((collectionOption) => { - const collection = collectionOption.unwrap(); - expect(collection.issuer.toString()) - .to.be.deep.eq(bob.address, 'Error: Invalid NFT collection issuer'); - }); -} - -export async function deleteCollection( - api: ApiPromise, - issuerUri: string, - collectionId: string, -): Promise { - const ss58Format = api.registry.getChainProperties()!.toJSON().ss58Format; - const issuer = privateKey(issuerUri, Number(ss58Format)); - const tx = api.tx.rmrkCore.destroyCollection(collectionId); - const events = await executeTransaction(api, issuer, tx); - - const collectionTxResult = extractRmrkCoreTxResult( - events, - 'CollectionDestroy', - (data) => { - return parseInt(data[1].toString(), 10); - }, - ); - expect(collectionTxResult.success, 'Error: Unable to delete NFT collection').to.be.true; - - const collection = await getCollection( - api, - parseInt(collectionId, 10), - ); - expect(collection.isEmpty, 'Error: NFT collection should be deleted').to.be.true; - - return 0; -} - -export async function negativeDeleteCollection( - api: ApiPromise, - issuerUri: string, - collectionId: string, -): Promise { - const ss58Format = api.registry.getChainProperties()!.toJSON().ss58Format; - const issuer = privateKey(issuerUri, Number(ss58Format)); - const tx = api.tx.rmrkCore.destroyCollection(collectionId); - await expect(executeTransaction(api, issuer, tx)).to.be.rejected; - - return 0; -} - -export async function setNftProperty( - api: ApiPromise, - issuerUri: string, - collectionId: number, - nftId: number, - key: string, - value: string, -) { - const ss58Format = api.registry.getChainProperties()!.toJSON().ss58Format; - const issuer = privateKey(issuerUri, Number(ss58Format)); - const nftIdOpt = api.createType('Option', nftId); - const tx = api.tx.rmrkCore.setProperty( - collectionId, - nftIdOpt, - key, - value, - ); - const events = await executeTransaction(api, issuer, tx); - - const propResult = extractRmrkCoreTxResult(events, 'PropertySet', (data) => { - return { - collectionId: parseInt(data[0].toString(), 10), - nftId: data[1] as Option, - key: data[2] as Bytes, - value: data[3] as Bytes, - }; - }); - - expect(propResult.success, 'Error: Unable to set NFT property').to.be.true; - const eventData = propResult.successData!; - const eventDescription = 'from set NFT property event'; - - expect(eventData.collectionId, 'Error: Invalid collection ID ' + eventDescription) - .to.be.equal(collectionId); - - expect(eventData.nftId.eq(nftIdOpt), 'Error: Invalid NFT ID ' + eventDescription) - .to.be.true; - - expect(eventData.key.eq(key), 'Error: Invalid property key ' + eventDescription) - .to.be.true; - - expect(eventData.value.eq(value), 'Error: Invalid property value ' + eventDescription) - .to.be.true; - - expect( - await isNftPropertyExists(api, collectionId, nftId, key, value), - 'Error: NFT property is not found', - ).to.be.true; -} - -export async function mintNft( - api: ApiPromise, - issuerUri: string, - ownerUri: string | null, - collectionId: number, - metadata: string, - recipientUri: string | null = null, - royalty: number | null = null, - transferable = true, - resources: {basic?: any, composable?: any, slot?: any}[] | null = null, -): Promise { - let nftId = 0; - const ss58Format = api.registry.getChainProperties()!.toJSON().ss58Format; - const issuer = privateKey(issuerUri, Number(ss58Format)); - const owner = ownerUri ? privateKey(ownerUri, Number(ss58Format)).address : null; - const recipient = recipientUri ? privateKey(recipientUri, Number(ss58Format)).address : null; - const royaltyOptional = royalty ? royalty.toString() : null; - - const actualOwnerUri = ownerUri ? ownerUri : issuerUri; - const actualOwnerAddress = ownerUri ? owner : issuer.address; - - const collectionOpt = await getCollection(api, collectionId); - - const tx = api.tx.rmrkCore.mintNft( - owner, - collectionId, - recipient, - royaltyOptional, - metadata, - transferable, - resources as any, - ); - - const events = await executeTransaction(api, issuer, tx); - const nftResult = extractRmrkCoreTxResult(events, 'NftMinted', (data) => { - return parseInt(data[2].toString(), 10); - }); - - expect(nftResult.success, 'Error: Unable to mint NFT').to.be.true; - - const newCollectionNftsCount = (await getCollection(api, collectionId)) - .unwrap() - .nftsCount - .toNumber(); - - const oldCollectionNftsCount = collectionOpt - .unwrap() - .nftsCount.toNumber(); - - expect(newCollectionNftsCount, 'Error: NFTs count should increase') - .to.be.equal(oldCollectionNftsCount + 1); - - nftId = nftResult.successData!; - - const nftOption = await getNft(api, collectionId, nftId); - - expect(nftOption.isSome, 'Error: Unable to fetch created NFT').to.be.true; - - const nft = nftOption.unwrap(); - - expect(nft.owner.isAccountId, 'Error: NFT owner should be some user').to.be.true; - expect(nft.owner.asAccountId.toString()).to.be.equal(actualOwnerAddress, 'Error: Invalid NFT owner'); - - const isOwnedInUniques = await isNftOwnedBy(api, actualOwnerUri, collectionId, nftId); - expect(isOwnedInUniques, `Error: created NFT is not actually owned by ${ownerUri}`) - .to.be.true; - - if (recipient === null && royalty === null) { - expect(nft.royalty.isNone, 'Error: Invalid NFT recipient') - .to.be.true; - } else { - expect(nft.royalty.isSome, 'Error: NFT royalty not found') - .to.be.true; - - const nftRoyalty = nft.royalty.unwrap(); - expect(nftRoyalty.recipient.eq(recipient), 'Error: Invalid NFT recipient') - .to.be.true; - - expect(nftRoyalty.amount.eq(royalty), 'Error: Invalid NFT royalty') - .to.be.true; - } - - expect(nft.metadata.toUtf8()).to.be.equal(metadata, 'Error: Invalid NFT metadata'); - - const nftResources = await getResources(api, collectionId, nftId); - if (resources == null) { - expect(nftResources, 'Error: Invalid NFT resources').to.be.empty; - } else { - expect(nftResources.length).to.be.equal(resources.length); - - for (let i = 0; i < resources.length; i++) { - let successFindingResource = false; - const resource = resources[i]; - // try to find the matching resource from the query - for (let j = 0; j < nftResources.length && !successFindingResource; j++) { - const nftResourceData = nftResources[j].toHuman(); - expect( - Object.prototype.hasOwnProperty.call(nftResourceData, 'resource'), - `Error: Corrupted resource data on resource #${i}`, - ).to.be.true; - const nftResource = nftResourceData.resource!; - type NftResourceKey = keyof typeof nftResource; - - let typedResource = null; - let typedNftResource = null; - - if (resource.basic && Object.prototype.hasOwnProperty.call(nftResource, 'Basic')) { - typedResource = resource.basic!; - typedNftResource = nftResource['Basic' as NftResourceKey]!; - } else if (resource.composable && Object.prototype.hasOwnProperty.call(nftResource, 'Composable')) { - typedResource = resource.composable!; - typedNftResource = nftResource['Composable' as NftResourceKey]! as any; - if (typedResource.parts != undefined && typedResource.parts.toString() != typedNftResource.parts.toString() - || typedResource.base != typedNftResource.base && typedResource.base != undefined) { - continue; - } - } else if (resource.slot && Object.prototype.hasOwnProperty.call(nftResource, 'Slot')) { - typedResource = resource.slot!; - typedNftResource = nftResource['Slot' as NftResourceKey]! as any; - if (typedResource.slot != typedNftResource.slot && typedResource.slot != undefined - || typedResource.base != typedNftResource.base && typedResource.base != undefined) { - continue; - } - } else { - continue; - } - - if (typedResource.src != typedNftResource.src - || typedResource.metadata != typedNftResource.metadata - || typedResource.thumb != typedNftResource.thumb - || typedResource.license != typedNftResource.license - ) { - continue; - } - - // do final checks since this is now established to be the resource we seek - expect(nftResourceData.pending, `Error: Resource #${i} is pending`).to.be.false; - expect(nftResourceData.pendingRemoval, `Error: Resource #${i} is pending removal`).to.be.false; - - // remove the matching resource from the resources we check - nftResources.splice(j, 1); - successFindingResource = true; - } - - expect(successFindingResource, `Error: Couldn't find resource #${i}'s counterpart among the returned`).to.be.true; - } - } - - return nftId; -} - -export async function sendNft( - api: ApiPromise, - expectedStatus: 'pending' | 'sent', - originalOwnerUri: string, - collectionId: number, - nftId: number, - newOwner: string | NftIdTuple, -) { - const ss58Format = api.registry.getChainProperties()!.toJSON().ss58Format; - const originalOwner = privateKey(originalOwnerUri, Number(ss58Format)); - const newOwnerObj = makeNftOwner(api, newOwner); - - const nftBeforeSendingOpt = await getNft(api, collectionId, nftId); - - const tx = api.tx.rmrkCore.send(collectionId, nftId, newOwnerObj); - const events = await executeTransaction(api, originalOwner, tx); - - const sendResult = extractRmrkCoreTxResult(events, 'NFTSent', (data) => { - return { - dstOwner: data[1] as NftOwner, - collectionId: parseInt(data[2].toString(), 10), - nftId: parseInt(data[3].toString(), 10), - }; - }); - - expect(sendResult.success, 'Error: Unable to send NFT').to.be.true; - const sendData = sendResult.successData!; - - expect(sendData.dstOwner.eq(newOwnerObj), 'Error: Invalid target user (from event data)') - .to.be.true; - - expect(sendData.collectionId) - .to.be.equal(collectionId, 'Error: Invalid collection ID (from event data)'); - - expect(sendData.nftId).to.be.equal(nftId, 'Error: Invalid NFT ID (from event data)'); - - expect(nftBeforeSendingOpt.isSome, 'Error: Unable to fetch NFT before sending').to.be.true; - - const nftBeforeSending = nftBeforeSendingOpt.unwrap(); - - const nftAfterSendingOpt = await getNft(api, collectionId, nftId); - - expect(nftAfterSendingOpt.isSome, 'Error: Unable to fetch NFT after sending').to.be.true; - - const nftAfterSending = nftAfterSendingOpt.unwrap(); - - const isOwnedByNewOwner = await isNftOwnedBy(api, newOwner, collectionId, nftId); - const isPending = expectedStatus === 'pending'; - - expect( - isOwnedByNewOwner, - `Error: The NFT should be owned by ${newOwner.toString()}`, - ).to.be.true; - - expect(nftAfterSending.royalty.eq(nftBeforeSending.royalty), 'Error: Invalid NFT royalty after sending') - .to.be.true; - - expect(nftAfterSending.metadata.eq(nftBeforeSending.metadata), 'Error: Invalid NFT metadata after sending') - .to.be.true; - - expect(nftAfterSending.equipped.eq(nftBeforeSending.equipped), 'Error: Invalid NFT equipped status after sending') - .to.be.true; - - expect(nftAfterSending.pending.eq(isPending), 'Error: Invalid NFT pending state') - .to.be.true; -} - -export async function acceptNft( - api: ApiPromise, - issuerUri: string, - collectionId: number, - nftId: number, - newOwner: string | [number, number], -) { - const ss58Format = api.registry.getChainProperties()!.toJSON().ss58Format; - const issuer = privateKey(issuerUri, Number(ss58Format)); - const newOwnerObj = makeNftOwner(api, newOwner); - - const nftBeforeOpt = await getNft(api, collectionId, nftId); - - const tx = api.tx.rmrkCore.acceptNft(collectionId, nftId, newOwnerObj); - const events = await executeTransaction(api, issuer, tx); - - const acceptResult = extractRmrkCoreTxResult(events, 'NFTAccepted', (data) => { - return { - recipient: data[1] as NftOwner, - collectionId: parseInt(data[2].toString(), 10), - nftId: parseInt(data[3].toString(), 10), - }; - }); - - expect(acceptResult.success, 'Error: Unable to accept NFT').to.be.true; - const acceptData = acceptResult.successData!; - - expect(acceptData.recipient.eq(newOwnerObj), 'Error: Invalid NFT recipient (from event data)') - .to.be.true; - - expect(acceptData.collectionId) - .to.be.equal(collectionId, 'Error: Invalid collection ID (from event data)'); - - expect(acceptData.nftId) - .to.be.equal(nftId, 'Error: Invalid NFT ID (from event data)'); - - const nftBefore = nftBeforeOpt.unwrap(); - - const isPendingBeforeAccept = nftBefore.pending.isTrue; - - const nftAfter = (await getNft(api, collectionId, nftId)).unwrap(); - const isPendingAfterAccept = nftAfter.pending.isTrue; - - expect(isPendingBeforeAccept, 'Error: NFT should be pending to be accepted') - .to.be.true; - - expect(isPendingAfterAccept, 'Error: NFT should NOT be pending after accept') - .to.be.false; - - const isOwnedInUniques = await isNftOwnedBy(api, newOwner, collectionId, nftId); - expect(isOwnedInUniques, `Error: created NFT is not actually owned by ${newOwner.toString()}`) - .to.be.true; -} - -export async function rejectNft( - api: ApiPromise, - issuerUri: string, - collectionId: number, - nftId: number, -) { - const ss58Format = api.registry.getChainProperties()!.toJSON().ss58Format; - const issuer = privateKey(issuerUri, Number(ss58Format)); - const nftBeforeOpt = await getNft(api, collectionId, nftId); - - const tx = api.tx.rmrkCore.rejectNft(collectionId, nftId); - const events = await executeTransaction(api, issuer, tx); - const rejectResult = extractRmrkCoreTxResult(events, 'NFTRejected', (data) => { - return { - collectionId: parseInt(data[1].toString(), 10), - nftId: parseInt(data[2].toString(), 10), - }; - }); - - const rejectData = rejectResult.successData!; - - expect(rejectData.collectionId) - .to.be.equal(collectionId, 'Error: Invalid collection ID (from event data)'); - - expect(rejectData.nftId) - .to.be.equal(nftId, 'Error: Invalid NFT ID (from event data)'); - - const nftBefore = nftBeforeOpt.unwrap(); - - const isPendingBeforeReject = nftBefore.pending.isTrue; - - const nftAfter = await getNft(api, collectionId, nftId); - - expect(isPendingBeforeReject, 'Error: NFT should be pending to be rejected') - .to.be.true; - - expect(nftAfter.isNone, 'Error: NFT should be burned after reject') - .to.be.true; -} - -export async function createBase( - api: ApiPromise, - issuerUri: string, - baseType: string, - symbol: string, - parts: object[], -): Promise { - let baseId = 0; - const ss58Format = api.registry.getChainProperties()!.toJSON().ss58Format; - const issuer = privateKey(issuerUri, Number(ss58Format)); - - const partTypes = api.createType('Vec', parts) as Vec; - - const tx = api.tx.rmrkEquip.createBase(baseType, symbol, partTypes); - const events = await executeTransaction(api, issuer, tx); - - const baseResult = extractRmrkEquipTxResult(events, 'BaseCreated', (data) => { - return parseInt(data[1].toString(), 10); - }); - - expect(baseResult.success, 'Error: Unable to create Base') - .to.be.true; - - baseId = baseResult.successData!; - const baseOptional = await getBase(api, baseId); - - expect(baseOptional.isSome, 'Error: Unable to fetch created Base') - .to.be.true; - - const base = baseOptional.unwrap(); - const baseParts = await getParts(api, baseId); - - expect(base.issuer.toString()).to.be.equal(issuer.address, 'Error: Invalid Base issuer'); - expect(base.baseType.toUtf8()).to.be.equal(baseType, 'Error: Invalid Base type'); - expect(base.symbol.toUtf8()).to.be.equal(symbol, 'Error: Invalid Base symbol'); - expect(partTypes.eq(baseParts), 'Error: Received invalid base parts').to.be.true; - - return baseId; -} - -export async function setResourcePriorities( - api: ApiPromise, - issuerUri: string, - collectionId: number, - nftId: number, - priorities: number[], -) { - const ss58Format = api.registry.getChainProperties()!.toJSON().ss58Format; - const issuer = privateKey(issuerUri, Number(ss58Format)); - - const prioritiesVec = api.createType('Vec', priorities); - const tx = api.tx.rmrkCore.setPriority(collectionId, nftId, prioritiesVec); - const events = await executeTransaction(api, issuer, tx); - - const prioResult = extractRmrkCoreTxResult(events, 'PrioritySet', (data) => { - return { - collectionId: parseInt(data[0].toString(), 10), - nftId: parseInt(data[1].toString(), 10), - }; - }); - - expect(prioResult.success, 'Error: Unable to set resource priorities').to.be.true; - const eventData = prioResult.successData!; - - expect(eventData.collectionId) - .to.be.equal(collectionId, 'Error: Invalid collection ID (set priorities event data)'); - - expect(eventData.nftId).to.be.equal(nftId, 'Error: Invalid NFT ID (set priorities event data'); - - for (let i = 0; i < priorities.length; i++) { - const resourceId = priorities[i]; - - const fetchedPrio = await getResourcePriority(api, collectionId, nftId, resourceId); - expect(fetchedPrio).to.be.equal(i, 'Error: Invalid priorities are set'); - } - -} - -export async function setEquippableList( - api: ApiPromise, - issuerUri: string, - baseId: number, - slotId: number, - equippableList: 'All' | 'Empty' | { 'Custom': number[] }, -) { - const ss58Format = api.registry.getChainProperties()!.toJSON().ss58Format; - const issuer = privateKey(issuerUri, Number(ss58Format)); - const equippable = api.createType('RmrkTraitsPartEquippableList', equippableList) as EquippableList; - - const tx = api.tx.rmrkEquip.equippable(baseId, slotId, equippable); - const events = await executeTransaction(api, issuer, tx); - - const equipListResult = extractRmrkEquipTxResult(events, 'EquippablesUpdated', (data) => { - return { - baseId: parseInt(data[0].toString(), 10), - slotId: parseInt(data[1].toString(), 10), - }; - }); - - expect(equipListResult.success, 'Error: unable to update equippable list').to.be.true; - const updateEvent = equipListResult.successData!; - - expect(updateEvent.baseId) - .to.be.equal(baseId, 'Error: invalid base ID from update equippable event'); - - expect(updateEvent.slotId) - .to.be.equal(slotId, 'Error: invalid base ID from update equippable event'); - - const fetchedEquippableList = await getEquippableList(api, baseId, slotId); - - expect(fetchedEquippableList, 'Error: unable to fetch equippable list').to.be.not.null; - if (fetchedEquippableList) { - expect(fetchedEquippableList) - .to.be.deep.equal(equippableList, 'Error: invalid equippable list was set'); - } -} - -export async function addTheme( - api: ApiPromise, - issuerUri: string, - baseId: number, - themeObj: object, - filterKeys: string[] | null = null, -) { - const ss58Format = api.registry.getChainProperties()!.toJSON().ss58Format; - const issuer = privateKey(issuerUri, Number(ss58Format)); - const theme = api.createType('RmrkTraitsTheme', themeObj) as Theme; - - const tx = api.tx.rmrkEquip.themeAdd(baseId, theme); - const events = await executeTransaction(api, issuer, tx); - - expect(isTxResultSuccess(events), 'Error: Unable to add Theme').to.be.true; - - const fetchedThemeOpt = await getTheme(api, baseId, theme.name.toUtf8(), null); - - expect(fetchedThemeOpt.isSome, 'Error: Unable to fetch theme').to.be.true; - - const fetchedTheme = fetchedThemeOpt.unwrap(); - - expect(theme.name.eq(fetchedTheme.name), 'Error: Invalid theme name').to.be.true; - - for (let i = 0; i < theme.properties.length; i++) { - const property = theme.properties[i]; - const propertyKey = property.key.toUtf8(); - - const propertyFoundCount = fetchedTheme.properties.filter((fetchedProp) => property.key.eq(fetchedProp.key)).length; - - expect(propertyFoundCount > 1, `Error: Too many properties with key ${propertyKey} found`) - .to.be.false; - - if (filterKeys) { - const isFiltered = fetchedTheme.properties.find((fetchedProp) => fetchedProp.key.eq(property.key)) === undefined; - - if (isFiltered) { - expect(propertyFoundCount === 0, `Error: Unexpected filtered key ${propertyKey}`) - .to.be.true; - continue; - } - } - - expect(propertyFoundCount === 1, `Error: The property with key ${propertyKey} is not found`) - .to.be.true; - } -} - -export async function lockCollection( - api: ApiPromise, - issuerUri: string, - collectionId: number, - max = 0, -) { - const ss58Format = api.registry.getChainProperties()!.toJSON().ss58Format; - const issuer = privateKey(issuerUri, Number(ss58Format)); - const tx = api.tx.rmrkCore.lockCollection(collectionId); - const events = await executeTransaction(api, issuer, tx); - const lockResult = extractRmrkCoreTxResult(events, 'CollectionLocked', (data) => { - return parseInt(data[1].toString(), 10); - }); - expect(lockResult.success, 'Error: Unable to lock a collection').to.be.true; - expect(lockResult.successData!, 'Error: Invalid collection was locked') - .to.be.eq(collectionId); - - await getCollection(api, collectionId).then((collectionOption) => { - const collection = collectionOption.unwrap(); - expect(collection.max.unwrap().toNumber()).to.be.equal(max); - }); -} - -export async function setPropertyCollection( - api: ApiPromise, - issuerUri: string, - collectionId: number, - key: string, - value: string, -) { - const ss58Format = api.registry.getChainProperties()!.toJSON().ss58Format; - const alice = privateKey(issuerUri, Number(ss58Format)); - - const tx = api.tx.rmrkCore.setProperty(collectionId, null, key, value); - const events = await executeTransaction(api, alice, tx); - const propResult = extractRmrkCoreTxResult(events, 'PropertySet', (data) => { - return { - collectionId: parseInt(data[0].toString(), 10), - nftId: data[1] as Option, - key: data[2] as Bytes, - value: data[3] as Bytes, - }; - }); - - expect(propResult.success, 'Error: Unable to set collection property').to.be.true; - const eventData = propResult.successData!; - const eventDescription = 'from set collection property event'; - - expect(eventData.collectionId, 'Error: Invalid collection ID ' + eventDescription) - .to.be.equal(collectionId); - - expect(eventData.nftId.eq(null), 'Error: Unexpected NFT ID ' + eventDescription) - .to.be.true; - - expect(eventData.key.eq(key), 'Error: Invalid property key ' + eventDescription) - .to.be.true; - - expect(eventData.value.eq(value), 'Error: Invalid property value ' + eventDescription) - .to.be.true; - - expect(await isCollectionPropertyExists(api, collectionId, key, value)) - .to.be.true; -} - -export async function burnNft( - api: ApiPromise, - issuerUri: string, - collectionId: number, - nftId: number, -) { - const ss58Format = api.registry.getChainProperties()!.toJSON().ss58Format; - const issuer = privateKey(issuerUri, Number(ss58Format)); - const maxBurns = 10; - const tx = api.tx.rmrkCore.burnNft(collectionId, nftId, maxBurns); - const events = await executeTransaction(api, issuer, tx); - const burnResult = extractRmrkCoreTxResult(events, 'NFTBurned', (data) => { - return parseInt(data[1].toString(), 10); - }); - - expect(burnResult.success, 'Error: Unable to burn an NFT').to.be.true; - expect(burnResult.successData!, 'Error: Invalid NFT was burned') - .to.be.eq(nftId); - - const nftBurned = await getNft(api, collectionId, nftId); - expect(nftBurned.isSome).to.be.false; -} - -export async function acceptNftResource( - api: ApiPromise, - issuerUri: string, - collectionId: number, - nftId: number, - resourceId: number, -) { - const ss58Format = api.registry.getChainProperties()!.toJSON().ss58Format; - const issuer = privateKey(issuerUri, Number(ss58Format)); - - const tx = api.tx.rmrkCore.acceptResource( - collectionId, - nftId, - resourceId, - ); - - const events = await executeTransaction(api, issuer, tx); - const acceptResult = extractRmrkCoreTxResult(events, 'ResourceAccepted', (data) => { - return { - nftId: parseInt(data[0].toString(), 10), - resourceId: parseInt(data[1].toString(), 10), - }; - }); - - expect(acceptResult.success, 'Error: Unable to accept a resource').to.be.true; - expect(acceptResult.successData!.nftId, 'Error: Invalid NFT ID while accepting a resource') - .to.be.eq(nftId); - expect(acceptResult.successData!.resourceId, 'Error: Invalid resource ID while accepting a resource') - .to.be.eq(resourceId); - - const resource = await getResourceById(api, collectionId, nftId, resourceId); - checkResourceStatus(resource, 'added'); -} - -async function executeResourceCreation( - api: ApiPromise, - issuer: IKeyringPair, - tx: any, - collectionId: number, - nftId: number, - expectedStatus: 'pending' | 'added', -): Promise { - const events = await executeTransaction(api, issuer, tx); - - const resourceResult = extractRmrkCoreTxResult(events, 'ResourceAdded', (data) => { - return parseInt(data[1].toString(), 10); - }); - expect(resourceResult.success, 'Error: Unable to add resource').to.be.true; - const resourceId = resourceResult.successData!; - - const resource = await getResourceById(api, collectionId, nftId, resourceId); - checkResourceStatus(resource, expectedStatus); - - return resource; -} - -export async function addNftBasicResource( - api: ApiPromise, - issuerUri: string, - expectedStatus: 'pending' | 'added', - collectionId: number, - nftId: number, - src: string | null, - metadata: string | null, - license: string | null, - thumb: string | null, -): Promise { - const ss58Format = api.registry.getChainProperties()!.toJSON().ss58Format; - const issuer = privateKey(issuerUri, Number(ss58Format)); - - const basicResource = api.createType('RmrkTraitsResourceBasicResource', { - src: src, - metadata: metadata, - license: license, - thumb: thumb, - }) as BasicResource; - - const tx = api.tx.rmrkCore.addBasicResource( - collectionId, - nftId, - basicResource, - ); - - const resource = await executeResourceCreation(api, issuer, tx, collectionId, nftId, expectedStatus); - - // FIXME A workaround. It seems it is a PolkadotJS bug. - // All of the following are `false`. - // - // console.log('>>> basic:', resource.resource.isBasic); - // console.log('>>> composable:', resource.resource.isComposable); - // console.log('>>> slot:', resource.resource.isSlot); - const resourceJson = resource.resource.toHuman() as any; - - expect(Object.prototype.hasOwnProperty.call(resourceJson, 'Basic'), 'Error: Expected basic resource type') - .to.be.true; - - const recvBasicRes = resourceJson['Basic']; - - expect(recvBasicRes.src, 'Error: Invalid basic resource src') - .to.be.eq(src); - expect(recvBasicRes.metadata, 'Error: basic first resource metadata') - .to.be.eq(metadata); - expect(recvBasicRes.license, 'Error: basic first resource license') - .to.be.eq(license); - expect(recvBasicRes.thumb, 'Error: basic first resource thumb') - .to.be.eq(thumb); - - return resource.id.toNumber(); -} - -export async function addNftComposableResource( - api: ApiPromise, - issuerUri: string, - expectedStatus: 'pending' | 'added', - collectionId: number, - nftId: number, - parts: number[], - baseId: number, - src: string | null, - metadata: string | null, - license: string | null, - thumb: string | null, -): Promise { - const ss58Format = api.registry.getChainProperties()!.toJSON().ss58Format; - const issuer = privateKey(issuerUri, Number(ss58Format)); - - const composableResource = api.createType('RmrkTraitsResourceComposableResource', { - parts: parts, // api.createType('Vec', parts), - base: baseId, - src: src, - metadata: metadata, - license: license, - thumb: thumb, - }) as ComposableResource; - - const tx = api.tx.rmrkCore.addComposableResource( - collectionId, - nftId, - composableResource, - ); - - const resource = await executeResourceCreation(api, issuer, tx, collectionId, nftId, expectedStatus); - - // FIXME A workaround. It seems it is a PolkadotJS bug. - // All of the following are `false`. - // - // console.log('>>> basic:', resource.resource.isBasic); - // console.log('>>> composable:', resource.resource.isComposable); - // console.log('>>> slot:', resource.resource.isSlot); - const resourceJson = resource.resource.toHuman() as any; - - expect(Object.prototype.hasOwnProperty.call(resourceJson, 'Composable'), 'Error: Expected composable resource type') - .to.be.true; - - const recvComposableRes = resourceJson['Composable']; - - expect(recvComposableRes.parts.toString(), 'Error: Invalid composable resource parts') - .to.be.eq(parts.toString()); - expect(recvComposableRes.base, 'Error: Invalid composable resource base id') - .to.be.eq(baseId.toString()); - expect(recvComposableRes.src, 'Error: Invalid composable resource src') - .to.be.eq(src); - expect(recvComposableRes.metadata, 'Error: Invalid composable resource metadata') - .to.be.eq(metadata); - expect(recvComposableRes.license, 'Error: Invalid composable resource license') - .to.be.eq(license); - expect(recvComposableRes.thumb, 'Error: Invalid composable resource thumb') - .to.be.eq(thumb); - - return resource.id.toNumber(); -} - -export async function addNftSlotResource( - api: ApiPromise, - issuerUri: string, - expectedStatus: 'pending' | 'added', - collectionId: number, - nftId: number, - baseId: number, - slotId: number, - src: string | null, - metadata: string | null, - license: string | null, - thumb: string | null, -): Promise { - const ss58Format = api.registry.getChainProperties()!.toJSON().ss58Format; - const issuer = privateKey(issuerUri, Number(ss58Format)); - - const slotResource = api.createType('RmrkTraitsResourceSlotResource', { - base: baseId, - src: src, - metadata, - slot: slotId, - license: license, - thumb: thumb, - }) as SlotResource; - - const tx = api.tx.rmrkCore.addSlotResource( - collectionId, - nftId, - slotResource, - ); - - const resource = await executeResourceCreation(api, issuer, tx, collectionId, nftId, expectedStatus); - - // FIXME A workaround. It seems it is a PolkadotJS bug. - // All of the following are `false`. - // - // console.log('>>> basic:', resource.resource.isBasic); - // console.log('>>> composable:', resource.resource.isComposable); - // console.log('>>> slot:', resource.resource.isSlot); - const resourceJson = resource.resource.toHuman() as any; - - expect(Object.prototype.hasOwnProperty.call(resourceJson, 'Slot'), 'Error: Expected slot resource type') - .to.be.true; - - const recvSlotRes = resourceJson['Slot']; - - expect(recvSlotRes.base, 'Error: Invalid slot resource base id') - .to.be.eq(baseId.toString()); - expect(recvSlotRes.slot, 'Error: Invalid slot resource slot id') - .to.be.eq(slotId.toString()); - expect(recvSlotRes.src, 'Error: Invalid slot resource src') - .to.be.eq(src); - expect(recvSlotRes.metadata, 'Error: Invalid slot resource metadata') - .to.be.eq(metadata); - expect(recvSlotRes.license, 'Error: Invalid slot resource license') - .to.be.eq(license); - expect(recvSlotRes.thumb, 'Error: Invalid slot resource thumb') - .to.be.eq(thumb); - - return resource.id.toNumber(); -} - -export async function equipNft( - api: ApiPromise, - issuerUri: string, - item: NftIdTuple, - equipper: NftIdTuple, - resource: number, - base: number, - slot: number, -) { - const ss58Format = api.registry.getChainProperties()!.toJSON().ss58Format; - const issuer = privateKey(issuerUri, Number(ss58Format)); - const tx = api.tx.rmrkEquip.equip(item, equipper, resource, base, slot); - const events = await executeTransaction(api, issuer, tx); - const equipResult = extractRmrkEquipTxResult(events, 'SlotEquipped', (data) => { - return { - item_collection: parseInt(data[0].toString(), 10), - item_nft: parseInt(data[1].toString(), 10), - base_id: parseInt(data[2].toString(), 10), - slot_id: parseInt(data[3].toString(), 10), - }; - }); - expect(equipResult.success, 'Error: Unable to equip an item').to.be.true; - expect(equipResult.successData!.item_collection, 'Error: Invalid item collection id') - .to.be.eq(item[0]); - expect(equipResult.successData!.item_nft, 'Error: Invalid item NFT id') - .to.be.eq(item[1]); - expect(equipResult.successData!.base_id, 'Error: Invalid base id') - .to.be.eq(base); - expect(equipResult.successData!.slot_id, 'Error: Invalid slot id') - .to.be.eq(slot); -} - -export async function unequipNft( - api: ApiPromise, - issuerUri: string, - item: any, - equipper: any, - resource: number, - base: number, - slot: number, -) { - const ss58Format = api.registry.getChainProperties()!.toJSON().ss58Format; - const issuer = privateKey(issuerUri, Number(ss58Format)); - const tx = api.tx.rmrkEquip.equip(item, equipper, resource, base, slot); - const events = await executeTransaction(api, issuer, tx); - - const unEquipResult = extractRmrkEquipTxResult( - events, - 'SlotUnequipped', - (data) => { - return { - item_collection: parseInt(data[0].toString(), 10), - item_nft: parseInt(data[1].toString(), 10), - base_id: parseInt(data[2].toString(), 10), - slot_id: parseInt(data[3].toString(), 10), - }; - }, - ); - - expect(unEquipResult.success, 'Error: Unable to unequip an item').to.be.true; - expect(unEquipResult.successData!.item_collection, 'Error: Invalid item collection id') - .to.be.eq(item[0]); - expect(unEquipResult.successData!.item_nft, 'Error: Invalid item NFT id') - .to.be.eq(item[1]); - expect(unEquipResult.successData!.base_id, 'Error: Invalid base id') - .to.be.eq(base); - expect(unEquipResult.successData!.slot_id, 'Error: Invalid slot id') - .to.be.eq(slot); -} - -export async function removeNftResource( - api: ApiPromise, - expectedStatus: 'pending' | 'removed', - issuerUri: string, - collectionId: number, - nftId: number, - resourceId: number, -) { - const ss58Format = api.registry.getChainProperties()!.toJSON().ss58Format; - const issuer = privateKey(issuerUri, Number(ss58Format)); - - const tx = api.tx.rmrkCore.removeResource(collectionId, nftId, resourceId); - const events = await executeTransaction(api, issuer, tx); - const removeResult = extractRmrkCoreTxResult(events, 'ResourceRemoval', (data) => { - return { - nftId: parseInt(data[0].toString(), 10), - resourceId: parseInt(data[1].toString(), 10), - }; - }); - expect(removeResult.success, 'Error: Unable to remove a resource').to.be.true; - expect(removeResult.successData!.nftId, 'Error: Invalid NFT Id while removing a resource') - .to.be.eq(nftId); - expect(removeResult.successData!.resourceId, 'Error: Invalid resource Id while removing a resource') - .to.be.eq(resourceId); - - const afterDeleting = await findResourceById(api, collectionId, nftId, resourceId); - - if (expectedStatus === 'pending') { - expect(afterDeleting).not.to.be.null; - expect(afterDeleting?.pendingRemoval.isTrue).to.be.equal(true); - } else { - expect(afterDeleting).to.be.null; - } -} - -export async function acceptResourceRemoval( - api: ApiPromise, - issuerUri: string, - collectionId: number, - nftId: number, - resourceId: number, -) { - const ss58Format = api.registry.getChainProperties()!.toJSON().ss58Format; - const issuer = privateKey(issuerUri, Number(ss58Format)); - - const tx = api.tx.rmrkCore.acceptResourceRemoval(collectionId, nftId, resourceId); - const events = await executeTransaction(api, issuer, tx); - const acceptResult = extractRmrkCoreTxResult(events, 'ResourceRemovalAccepted', (data) => { - return { - nftId: parseInt(data[0].toString(), 10), - resourceId: parseInt(data[1].toString(), 10), - }; - }); - expect(acceptResult.success, 'Error: Unable to accept a resource').to.be.true; - expect(acceptResult.successData!.nftId, 'Error: Invalid NFT Id while accepting a resource') - .to.be.eq(nftId); - expect(acceptResult.successData!.resourceId, 'Error: Invalid resource Id while accepting a resource') - .to.be.eq(resourceId); - - const afterDeleting = await findResourceById(api, collectionId, nftId, resourceId); - expect(afterDeleting, 'Error: resource deleting failed').to.be.null; -} --- a/tests/src/.outdated/substrate/substrate-api.ts +++ b/tests/src/.outdated/substrate/substrate-api.ts @@ -53,7 +53,6 @@ rpc: { unique: defs.unique.rpc, appPromotion: defs.appPromotion.rpc, - rmrk: defs.rmrk.rpc, eth: { feeHistory: { description: 'Dummy', --- a/tests/src/interfaces/definitions.ts +++ b/tests/src/interfaces/definitions.ts @@ -16,6 +16,5 @@ export {default as unique} from './unique/definitions'; export {default as appPromotion} from './appPromotion/definitions'; -export {default as rmrk} from './rmrk/definitions'; export {default as povinfo} from './povinfo/definitions'; export {default as default} from './default/definitions'; --- a/tests/src/interfaces/rmrk/definitions.ts +++ /dev/null @@ -1,118 +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 . - -type RpcParam = { - name: string; - type: string; - isOptional?: true; -}; - -const atParam = {name: 'at', type: 'Hash', isOptional: true}; -const fn = (description: string, params: RpcParam[], type: string) => ({ - description, - params: [...params, atParam], - type, -}); - -export default { - types: {}, - rpc: { - lastCollectionIdx: fn('Get the latest created collection id', [], 'u32'), - collectionById: fn('Get collection by id', [{name: 'id', type: 'u32'}], 'Option'), - nftById: fn( - 'Get NFT by collection id and NFT id', - [ - {name: 'collectionId', type: 'u32'}, - {name: 'nftId', type: 'u32'}, - ], - 'Option', - ), - accountTokens: fn( - 'Get tokens owned by an account in a collection', - [ - {name: 'accountId', type: 'AccountId32'}, - {name: 'collectionId', type: 'u32'}, - ], - 'Vec', - ), - nftChildren: fn( - 'Get NFT children', - [ - {name: 'collectionId', type: 'u32'}, - {name: 'nftId', type: 'u32'}, - ], - 'Vec', - ), - collectionProperties: fn( - 'Get collection properties', - [ - {name: 'collectionId', type: 'u32'}, - {name: 'filterKeys', type: 'Vec', isOptional: true}, - ], - 'Vec', - ), - nftProperties: fn( - 'Get NFT properties', - [ - {name: 'collectionId', type: 'u32'}, - {name: 'nftId', type: 'u32'}, - {name: 'filterKeys', type: 'Vec', isOptional: true}, - ], - 'Vec', - ), - nftResources: fn( - 'Get NFT resources', - [ - {name: 'collectionId', type: 'u32'}, - {name: 'nftId', type: 'u32'}, - ], - 'Vec', - ), - nftResourcePriority: fn( - 'Get NFT resource priorities', - [ - {name: 'collectionId', type: 'u32'}, - {name: 'nftId', type: 'u32'}, - {name: 'resourceId', type: 'u32'}, - ], - 'Option', - ), - base: fn( - 'Get base info', - [{name: 'baseId', type: 'u32'}], - 'Option', - ), - baseParts: fn( - 'Get all Base\'s parts', - [{name: 'baseId', type: 'u32'}], - 'Vec', - ), - themeNames: fn( - 'Get Base\'s theme names', - [{name: 'baseId', type: 'u32'}], - 'Vec', - ), - themes: fn( - 'Get Theme\'s keys values', - [ - {name: 'baseId', type: 'u32'}, - {name: 'themeName', type: 'String'}, - {name: 'keys', type: 'Option>'}, - ], - 'Option', - ), - }, -}; --- a/tests/src/interfaces/rmrk/index.ts +++ /dev/null @@ -1,4 +0,0 @@ -// Auto-generated via `yarn polkadot-types-from-defs`, do not edit -/* eslint-disable */ - -export * from './types'; --- a/tests/src/interfaces/rmrk/types.ts +++ /dev/null @@ -1,4 +0,0 @@ -// Auto-generated via `yarn polkadot-types-from-defs`, do not edit -/* eslint-disable */ - -export type PHANTOM_RMRK = 'rmrk'; --- a/tests/src/pallet-presence.test.ts +++ b/tests/src/pallet-presence.test.ts @@ -64,7 +64,6 @@ const refungible = 'refungible'; const foreignAssets = 'foreignassets'; - const _rmrkPallets = ['rmrkcore', 'rmrkequip']; const appPromotion = 'apppromotion'; const collatorSelection = ['authorship', 'session', 'collatorselection', 'identity']; const testUtils = 'testutils'; --- a/tests/src/util/index.ts +++ b/tests/src/util/index.ts @@ -106,8 +106,6 @@ export enum Pallets { Inflation = 'inflation', - RmrkCore = 'rmrkcore', - RmrkEquip = 'rmrkequip', ReFungible = 'refungible', Fungible = 'fungible', NFT = 'nonfungible', --- a/tests/src/util/playgrounds/unique.dev.ts +++ b/tests/src/util/playgrounds/unique.dev.ts @@ -106,7 +106,6 @@ unique: defs.unique.rpc, appPromotion: defs.appPromotion.rpc, povinfo: defs.povinfo.rpc, - rmrk: defs.rmrk.rpc, eth: { feeHistory: { description: 'Dummy',