difftreelog
fixup(imports): post-rebase
in: master
14 files changed
Cargo.tomldiffbeforeafterboth--- a/Cargo.toml
+++ b/Cargo.toml
@@ -26,8 +26,8 @@
opt-level = 3
[profile.integration-tests]
+debug-assertions = true
inherits = "release"
-debug-assertions = true
[workspace.dependencies]
# Unique
node/cli/src/command.rsdiffbeforeafterboth--- a/node/cli/src/command.rs
+++ b/node/cli/src/command.rs
@@ -32,20 +32,15 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-use std::time::Duration;
-
-use codec::Encode;
-use cumulus_client_cli::generate_genesis_block;
use cumulus_primitives_core::ParaId;
-use log::{debug, info};
+use log::info;
use sc_cli::{
ChainSpec, CliConfiguration, DefaultConfigurationValues, ImportParams, KeystoreParams,
- NetworkParams, Result, RuntimeVersion, SharedParams, SubstrateCli,
+ NetworkParams, Result, SharedParams, SubstrateCli,
};
use sc_service::config::{BasePath, PrometheusConfig};
-use sp_core::hexdisplay::HexDisplay;
-use sp_runtime::traits::{AccountIdConversion, Block as BlockT};
-use up_common::types::opaque::{Block, RuntimeId};
+use sp_runtime::traits::AccountIdConversion;
+use up_common::types::opaque::RuntimeId;
#[cfg(feature = "runtime-benchmarks")]
use crate::chain_spec::default_runtime;
node/cli/src/service.rsdiffbeforeafterboth--- a/node/cli/src/service.rs
+++ b/node/cli/src/service.rs
@@ -824,8 +824,8 @@
{
use fc_consensus::FrontierBlockImport;
use sc_consensus_manual_seal::{
- run_manual_seal, run_delayed_finalize, EngineCommand, ManualSealParams,
- DelayedFinalizeParams,
+ run_delayed_finalize, run_manual_seal, DelayedFinalizeParams, EngineCommand,
+ ManualSealParams,
};
let sc_service::PartialComponents {
pallets/collator-selection/src/benchmarking.rsdiffbeforeafterboth--- a/pallets/collator-selection/src/benchmarking.rs
+++ b/pallets/collator-selection/src/benchmarking.rs
@@ -35,15 +35,15 @@
use frame_benchmarking::{account, benchmarks, impl_benchmark_test_suite, whitelisted_caller};
use frame_support::{
assert_ok,
- parity_scale_codec::Decode,
traits::{
fungible::{Inspect, Mutate},
EnsureOrigin, Get,
},
};
-use frame_system::{EventRecord, RawOrigin};
+use frame_system::{pallet_prelude::*, EventRecord, RawOrigin};
use pallet_authorship::EventHandler;
use pallet_session::{self as session, SessionManager};
+use parity_scale_codec::Decode;
use sp_std::prelude::*;
use super::*;
@@ -338,7 +338,7 @@
register_candidates::<T>(c);
let new_block: BlockNumberFor<T>= 1800u32.into();
- let zero_block: T::BlockNumber = 0u32.into();
+ let zero_block: BlockNumberFor<T> = 0u32.into();
let candidates = <Candidates<T>>::get();
let non_removals = c.saturating_sub(r);
pallets/common/src/lib.rsdiffbeforeafterboth--- a/pallets/common/src/lib.rs
+++ b/pallets/common/src/lib.rs
@@ -54,9 +54,9 @@
extern crate alloc;
use core::{
+ marker::PhantomData,
ops::{Deref, DerefMut},
slice::from_ref,
- marker::PhantomData,
};
use evm_coder::ToLog;
pallets/configuration/src/benchmarking.rsdiffbeforeafterboth--- a/pallets/configuration/src/benchmarking.rs
+++ b/pallets/configuration/src/benchmarking.rs
@@ -18,7 +18,7 @@
use frame_benchmarking::benchmarks;
use frame_support::assert_ok;
-use frame_system::{EventRecord, RawOrigin};
+use frame_system::{pallet_prelude::*, EventRecord, RawOrigin};
use super::*;
pallets/inflation/src/benchmarking.rsdiffbeforeafterboth--- a/pallets/inflation/src/benchmarking.rs
+++ b/pallets/inflation/src/benchmarking.rs
@@ -17,7 +17,7 @@
#![cfg(feature = "runtime-benchmarks")]
use frame_benchmarking::benchmarks;
-use frame_support::traits::OnInitialize;
+use frame_support::{pallet_prelude::*, traits::Hooks};
use super::*;
use crate::Pallet as Inflation;
@@ -25,9 +25,9 @@
benchmarks! {
on_initialize {
- let block1: T::BlockNumber = T::BlockNumber::from(1u32);
- let block2: T::BlockNumber = T::BlockNumber::from(2u32);
- Inflation::<T>::on_initialize(block1); // Create Treasury account
- }: { Inflation::<T>::on_initialize(block2); } // Benchmark deposit_into_existing path
+ let block1: BlockNumberFor<T> = 1u32.into();
+ let block2: BlockNumberFor<T> = 2u32.into();
+ <Inflation<T> as Hooks>::on_initialize(block1); // Create Treasury account
+ }: { <Inflation<T> as Hooks>::on_initialize(block2); } // Benchmark deposit_into_existing path
}
pallets/nonfungible/src/benchmarking.rsdiffbeforeafterboth--- a/pallets/nonfungible/src/benchmarking.rs
+++ b/pallets/nonfungible/src/benchmarking.rs
@@ -18,7 +18,7 @@
use pallet_common::{
bench_init,
benchmarking::{
- create_collection_raw, property_key, property_value, load_is_admin_and_property_permissions,
+ create_collection_raw, load_is_admin_and_property_permissions, property_key, property_value,
},
CommonCollectionOperations,
};
pallets/nonfungible/src/lib.rsdiffbeforeafterboth1// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.2// This file is part of Unique Network.34// Unique Network is free software: you can redistribute it and/or modify5// it under the terms of the GNU General Public License as published by6// the Free Software Foundation, either version 3 of the License, or7// (at your option) any later version.89// Unique Network is distributed in the hope that it will be useful,10// but WITHOUT ANY WARRANTY; without even the implied warranty of11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the12// GNU General Public License for more details.1314// You should have received a copy of the GNU General Public License15// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.1617//! # Nonfungible Pallet18//!19//! The Nonfungible pallet provides functionality for handling nonfungible collections and tokens.20//!21//! - [`Config`]22//! - [`NonfungibleHandle`]23//! - [`Pallet`]24//! - [`CommonWeights`](common::CommonWeights)25//!26//! ## Overview27//!28//! The Nonfungible pallet provides functions for:29//!30//! - NFT collection creation and removal31//! - Minting and burning of NFT tokens32//! - Retrieving account balances33//! - Transfering NFT tokens34//! - Setting and checking allowance for NFT tokens35//! - Setting properties and permissions for NFT collections and tokens36//! - Nesting and unnesting tokens37//!38//! ### Terminology39//!40//! - **NFT token:** Non fungible token.41//!42//! - **NFT Collection:** A collection of NFT tokens. All NFT tokens are part of a collection.43//! Each collection can define it's own properties, properties for it's tokens and set of permissions.44//!45//! - **Balance:** Number of NFT tokens owned by an account46//!47//! - **Allowance:** NFT tokens owned by one account that another account is allowed to make operations on48//!49//! - **Burning:** The process of “deleting” a token from a collection and from50//! an account balance of the owner.51//!52//! - **Nesting:** Setting up parent-child relationship between tokens. Nested tokens are inhereting53//! owner from their parent. There could be multiple levels of nesting. Token couldn't be nested in54//! it's child token i.e. parent-child relationship graph shouldn't have cycles.55//!56//! - **Properties:** Key-Values pairs. Token properties are attached to a token. Collection properties are57//! attached to a collection. Set of permissions could be defined for each property.58//!59//! ### Implementations60//!61//! The Nonfungible pallet provides implementations for the following traits. If these traits provide62//! the functionality that you need, then you can avoid coupling with the Nonfungible pallet.63//!64//! - [`CommonWeightInfo`](pallet_common::CommonWeightInfo): Functions for retrieval of transaction weight65//! - [`CommonCollectionOperations`](pallet_common::CommonCollectionOperations): Functions for dealing66//! with collections67//!68//! ## Interface69//!70//! ### Dispatchable Functions71//!72//! - `init_collection` - Create NFT collection. NFT collection can be configured to allow or deny access for73//! some accounts.74//! - `destroy_collection` - Destroy exising NFT collection. There should be no tokens in the collection.75//! - `burn` - Burn NFT token owned by account.76//! - `transfer` - Transfer NFT token. Transfers should be enabled for NFT collection.77//! Nests the NFT token if it is sent to another token.78//! - `create_item` - Mint NFT token in collection. Sender should have permission to mint tokens.79//! - `set_allowance` - Set allowance for another account.80//! - `set_token_property` - Set token property value.81//! - `delete_token_property` - Remove property from the token.82//! - `set_collection_properties` - Set collection properties.83//! - `delete_collection_properties` - Remove properties from the collection.84//! - `set_property_permission` - Set collection property permission.85//! - `set_token_property_permissions` - Set token property permissions.86//!87//! ## Assumptions88//!89//! * To perform operations on tokens sender should be in collection's allow list if collection access mode is `AllowList`.9091#![cfg_attr(not(feature = "std"), no_std)]9293use core::ops::Deref;9495use erc::ERC721Events;96use evm_coder::ToLog;97use frame_support::{98 dispatch::{Pays, PostDispatchInfo},99 ensure, fail,100 pallet_prelude::*,101 storage::with_transaction,102 transactional, BoundedVec,103};104pub use pallet::*;105use pallet_common::{106 eth::collection_id_to_address, helpers::add_weight_to_post_info,107 weights::WeightInfo as CommonWeightInfo, CollectionHandle, Error as CommonError,108 Event as CommonEvent, Pallet as PalletCommon, SelfWeightOf as PalletCommonWeightOf,109};110use pallet_evm::{account::CrossAccountId, Pallet as PalletEvm};111use pallet_evm_coder_substrate::{SubstrateRecorder, WithRecorder};112use pallet_structure::{Error as StructureError, Pallet as PalletStructure};113use parity_scale_codec::{Decode, Encode, MaxEncodedLen};114use scale_info::TypeInfo;115use sp_core::{Get, H160};116use sp_runtime::{ArithmeticError, DispatchError, DispatchResult, TransactionOutcome};117use sp_std::{collections::btree_map::BTreeMap, vec, vec::Vec};118use up_data_structs::{119 budget::Budget, mapping::TokenAddressMapping, AccessMode, AuxPropertyValue, CollectionId,120 CreateCollectionData, CreateNftExData, CustomDataLimit, PropertiesPermissionMap, Property,121 PropertyKey, PropertyKeyPermission, PropertyScope, PropertyValue, TokenChild, TokenId,122 TokenProperties as TokenPropertiesT,123};124use weights::WeightInfo;125#[cfg(feature = "runtime-benchmarks")]126pub mod benchmarking;127pub mod common;128pub mod erc;129pub mod weights;130131pub type CreateItemData<T> = CreateNftExData<<T as pallet_evm::Config>::CrossAccountId>;132pub(crate) type SelfWeightOf<T> = <T as Config>::WeightInfo;133134/// Token data, stored independently from other data used to describe it135/// for the convenience of database access. Notably contains the owner account address.136#[struct_versioning::versioned(version = 2, upper)]137#[derive(Encode, Decode, TypeInfo, MaxEncodedLen)]138pub struct ItemData<CrossAccountId> {139 #[version(..2)]140 pub const_data: BoundedVec<u8, CustomDataLimit>,141142 #[version(..2)]143 pub variable_data: BoundedVec<u8, CustomDataLimit>,144145 pub owner: CrossAccountId,146}147148#[frame_support::pallet]149pub mod pallet {150 use frame_support::{151 pallet_prelude::*, storage::Key, traits::StorageVersion, Blake2_128Concat, Twox64Concat,152 };153 use up_data_structs::{CollectionId, TokenId};154155 use super::{weights::WeightInfo, *};156157 #[pallet::error]158 pub enum Error<T> {159 /// Not Nonfungible item data used to mint in Nonfungible collection.160 NotNonfungibleDataUsedToMintFungibleCollectionToken,161 /// Used amount > 1 with NFT162 NonfungibleItemsHaveNoAmount,163 /// Unable to burn NFT with children164 CantBurnNftWithChildren,165 }166167 #[pallet::config]168 pub trait Config:169 frame_system::Config + pallet_common::Config + pallet_structure::Config + pallet_evm::Config170 {171 type WeightInfo: WeightInfo;172 }173174 const STORAGE_VERSION: StorageVersion = StorageVersion::new(1);175176 #[pallet::pallet]177 #[pallet::storage_version(STORAGE_VERSION)]178 pub struct Pallet<T>(_);179180 /// Total amount of minted tokens in a collection.181 #[pallet::storage]182 pub type TokensMinted<T: Config> =183 StorageMap<Hasher = Twox64Concat, Key = CollectionId, Value = u32, QueryKind = ValueQuery>;184185 /// Amount of burnt tokens in a collection.186 #[pallet::storage]187 pub type TokensBurnt<T: Config> =188 StorageMap<Hasher = Twox64Concat, Key = CollectionId, Value = u32, QueryKind = ValueQuery>;189190 /// Token data, used to partially describe a token.191 #[pallet::storage]192 pub type TokenData<T: Config> = StorageNMap<193 Key = (Key<Twox64Concat, CollectionId>, Key<Twox64Concat, TokenId>),194 Value = ItemData<T::CrossAccountId>,195 QueryKind = OptionQuery,196 >;197198 /// Map of key-value pairs, describing the metadata of a token.199 #[pallet::storage]200 #[pallet::getter(fn token_properties)]201 pub type TokenProperties<T: Config> = StorageNMap<202 Key = (Key<Twox64Concat, CollectionId>, Key<Twox64Concat, TokenId>),203 Value = TokenPropertiesT,204 QueryKind = OptionQuery,205 >;206207 /// Custom data of a token that is serialized to bytes,208 /// primarily reserved for on-chain operations,209 /// normally obscured from the external users.210 ///211 /// Auxiliary properties are slightly different from212 /// usual [`TokenProperties`] due to an unlimited number213 /// and separately stored and written-to key-value pairs.214 ///215 /// Currently unused.216 #[pallet::storage]217 #[pallet::getter(fn token_aux_property)]218 pub type TokenAuxProperties<T: Config> = StorageNMap<219 Key = (220 Key<Twox64Concat, CollectionId>,221 Key<Twox64Concat, TokenId>,222 Key<Twox64Concat, PropertyScope>,223 Key<Twox64Concat, PropertyKey>,224 ),225 Value = AuxPropertyValue,226 QueryKind = OptionQuery,227 >;228229 /// Used to enumerate tokens owned by account.230 #[pallet::storage]231 pub type Owned<T: Config> = StorageNMap<232 Key = (233 Key<Twox64Concat, CollectionId>,234 Key<Blake2_128Concat, T::CrossAccountId>,235 Key<Twox64Concat, TokenId>,236 ),237 Value = bool,238 QueryKind = ValueQuery,239 >;240241 /// Used to enumerate token's children.242 #[pallet::storage]243 #[pallet::getter(fn token_children)]244 pub type TokenChildren<T: Config> = StorageNMap<245 Key = (246 Key<Twox64Concat, CollectionId>,247 Key<Twox64Concat, TokenId>,248 Key<Twox64Concat, (CollectionId, TokenId)>,249 ),250 Value = bool,251 QueryKind = ValueQuery,252 >;253254 /// Amount of tokens owned by an account in a collection.255 #[pallet::storage]256 pub type AccountBalance<T: Config> = StorageNMap<257 Key = (258 Key<Twox64Concat, CollectionId>,259 Key<Blake2_128Concat, T::CrossAccountId>,260 ),261 Value = u32,262 QueryKind = ValueQuery,263 >;264265 /// Allowance set by a token owner for another user to perform one of certain transactions on a token.266 #[pallet::storage]267 pub type Allowance<T: Config> = StorageNMap<268 Key = (Key<Twox64Concat, CollectionId>, Key<Twox64Concat, TokenId>),269 Value = T::CrossAccountId,270 QueryKind = OptionQuery,271 >;272273 /// Operator set by a wallet owner that could perform certain transactions on all tokens in the wallet.274 #[pallet::storage]275 pub type CollectionAllowance<T: Config> = StorageNMap<276 Key = (277 Key<Twox64Concat, CollectionId>,278 Key<Blake2_128Concat, T::CrossAccountId>,279 Key<Blake2_128Concat, T::CrossAccountId>,280 ),281 Value = bool,282 QueryKind = ValueQuery,283 >;284285 #[pallet::genesis_config]286 pub struct GenesisConfig<T>(PhantomData<T>);287288 impl<T: Config> Default for GenesisConfig<T> {289 fn default() -> Self {290 Self(Default::default())291 }292 }293294 #[pallet::genesis_build]295 impl<T: Config> BuildGenesisConfig for GenesisConfig<T> {296 fn build(&self) {297 StorageVersion::new(1).put::<Pallet<T>>();298 }299 }300}301302pub struct NonfungibleHandle<T: Config>(pallet_common::CollectionHandle<T>);303impl<T: Config> NonfungibleHandle<T> {304 pub fn cast(inner: pallet_common::CollectionHandle<T>) -> Self {305 Self(inner)306 }307 pub fn into_inner(self) -> pallet_common::CollectionHandle<T> {308 self.0309 }310 pub fn common_mut(&mut self) -> &mut pallet_common::CollectionHandle<T> {311 &mut self.0312 }313}314315impl<T: Config> WithRecorder<T> for NonfungibleHandle<T> {316 fn recorder(&self) -> &SubstrateRecorder<T> {317 self.0.recorder()318 }319 fn into_recorder(self) -> SubstrateRecorder<T> {320 self.0.into_recorder()321 }322}323impl<T: Config> Deref for NonfungibleHandle<T> {324 type Target = pallet_common::CollectionHandle<T>;325326 fn deref(&self) -> &Self::Target {327 &self.0328 }329}330331impl<T: Config> Pallet<T> {332 /// Get number of NFT tokens in collection.333 pub fn total_supply(collection: &NonfungibleHandle<T>) -> u32 {334 <TokensMinted<T>>::get(collection.id) - <TokensBurnt<T>>::get(collection.id)335 }336337 /// Check that NFT token exists.338 ///339 /// - `token`: Token ID.340 pub fn token_exists(collection: &NonfungibleHandle<T>, token: TokenId) -> bool {341 <TokenData<T>>::contains_key((collection.id, token))342 }343344 /// Add or edit auxiliary data for the property.345 ///346 /// - `f`: function that adds or edits auxiliary data.347 pub fn try_mutate_token_aux_property<R, E>(348 collection_id: CollectionId,349 token_id: TokenId,350 scope: PropertyScope,351 key: PropertyKey,352 f: impl FnOnce(&mut Option<AuxPropertyValue>) -> Result<R, E>,353 ) -> Result<R, E> {354 <TokenAuxProperties<T>>::try_mutate((collection_id, token_id, scope, key), f)355 }356357 /// Remove auxiliary data for the property.358 pub fn remove_token_aux_property(359 collection_id: CollectionId,360 token_id: TokenId,361 scope: PropertyScope,362 key: PropertyKey,363 ) {364 <TokenAuxProperties<T>>::remove((collection_id, token_id, scope, key));365 }366367 /// Get all auxiliary data in a given scope.368 ///369 /// Returns iterator over Property Key - Data pairs.370 pub fn iterate_token_aux_properties(371 collection_id: CollectionId,372 token_id: TokenId,373 scope: PropertyScope,374 ) -> impl Iterator<Item = (PropertyKey, AuxPropertyValue)> {375 <TokenAuxProperties<T>>::iter_prefix((collection_id, token_id, scope))376 }377378 /// Get ID of the last minted token379 pub fn current_token_id(collection_id: CollectionId) -> TokenId {380 TokenId(<TokensMinted<T>>::get(collection_id))381 }382}383384// unchecked calls skips any permission checks385impl<T: Config> Pallet<T> {386 /// Create NFT collection387 ///388 /// `init_collection` will take non-refundable deposit for collection creation.389 ///390 /// - `data`: Contains settings for collection limits and permissions.391 pub fn init_collection(392 owner: T::CrossAccountId,393 payer: T::CrossAccountId,394 data: CreateCollectionData<T::CrossAccountId>,395 ) -> Result<CollectionId, DispatchError> {396 <PalletCommon<T>>::init_collection(owner, payer, data)397 }398399 /// Destroy NFT collection400 ///401 /// `destroy_collection` will throw error if collection contains any tokens.402 /// Only owner can destroy collection.403 pub fn destroy_collection(404 collection: NonfungibleHandle<T>,405 sender: &T::CrossAccountId,406 ) -> DispatchResult {407 let id = collection.id;408409 if Self::collection_has_tokens(id) {410 return Err(<CommonError<T>>::CantDestroyNotEmptyCollection.into());411 }412413 // =========414415 PalletCommon::destroy_collection(collection.0, sender)?;416417 let _ = <TokenData<T>>::clear_prefix((id,), u32::MAX, None);418 let _ = <TokenChildren<T>>::clear_prefix((id,), u32::MAX, None);419 let _ = <Owned<T>>::clear_prefix((id,), u32::MAX, None);420 <TokensMinted<T>>::remove(id);421 <TokensBurnt<T>>::remove(id);422 let _ = <Allowance<T>>::clear_prefix((id,), u32::MAX, None);423 let _ = <AccountBalance<T>>::clear_prefix((id,), u32::MAX, None);424 let _ = <CollectionAllowance<T>>::clear_prefix((id,), u32::MAX, None);425 Ok(())426 }427428 /// Burn NFT token429 ///430 /// `burn` removes `token` from the `collection`, from it's owner and from the parent token431 /// if the token is nested.432 /// Only the owner can `burn` the token. The `token` shouldn't have any nested tokens.433 /// Also removes all corresponding properties and auxiliary properties.434 ///435 /// - `token`: Token that should be burned436 /// - `collection`: Collection that contains the token437 pub fn burn(438 collection: &NonfungibleHandle<T>,439 sender: &T::CrossAccountId,440 token: TokenId,441 ) -> DispatchResult {442 let token_data =443 <TokenData<T>>::get((collection.id, token)).ok_or(<CommonError<T>>::TokenNotFound)?;444 ensure!(&token_data.owner == sender, <CommonError<T>>::NoPermission);445446 if collection.permissions.access() == AccessMode::AllowList {447 collection.check_allowlist(sender)?;448 }449450 if Self::token_has_children(collection.id, token) {451 return Err(<Error<T>>::CantBurnNftWithChildren.into());452 }453454 let burnt = <TokensBurnt<T>>::get(collection.id)455 .checked_add(1)456 .ok_or(ArithmeticError::Overflow)?;457458 let balance = <AccountBalance<T>>::get((collection.id, token_data.owner.clone()))459 .checked_sub(1)460 .ok_or(ArithmeticError::Overflow)?;461462 // =========463464 if balance == 0 {465 <AccountBalance<T>>::remove((collection.id, token_data.owner.clone()));466 } else {467 <AccountBalance<T>>::insert((collection.id, token_data.owner.clone()), balance);468 }469470 <PalletStructure<T>>::unnest_if_nested(&token_data.owner, collection.id, token);471472 <Owned<T>>::remove((collection.id, &token_data.owner, token));473 <TokensBurnt<T>>::insert(collection.id, burnt);474 <TokenData<T>>::remove((collection.id, token));475 <TokenProperties<T>>::remove((collection.id, token));476 let _ = <TokenAuxProperties<T>>::clear_prefix((collection.id, token), u32::MAX, None);477 let old_spender = <Allowance<T>>::take((collection.id, token));478479 if let Some(old_spender) = old_spender {480 <PalletCommon<T>>::deposit_event(CommonEvent::Approved(481 collection.id,482 token,483 token_data.owner.clone(),484 old_spender,485 0,486 ));487 }488489 <PalletEvm<T>>::deposit_log(490 ERC721Events::Transfer {491 from: *token_data.owner.as_eth(),492 to: H160::default(),493 token_id: token.into(),494 }495 .to_log(collection_id_to_address(collection.id)),496 );497 <PalletCommon<T>>::deposit_event(CommonEvent::ItemDestroyed(498 collection.id,499 token,500 token_data.owner,501 1,502 ));503 Ok(())504 }505506 /// Same as [`burn`] but burns all the tokens that are nested in the token first507 ///508 /// - `self_budget`: Limit for searching children in depth.509 /// - `breadth_budget`: Limit of breadth of searching children.510 ///511 /// [`burn`]: struct.Pallet.html#method.burn512 #[transactional]513 pub fn burn_recursively(514 collection: &NonfungibleHandle<T>,515 sender: &T::CrossAccountId,516 token: TokenId,517 self_budget: &dyn Budget,518 breadth_budget: &dyn Budget,519 ) -> DispatchResultWithPostInfo {520 ensure!(self_budget.consume(), <StructureError<T>>::DepthLimit,);521522 let current_token_account =523 T::CrossTokenAddressMapping::token_to_address(collection.id, token);524525 let mut weight = Weight::zero();526527 // This method is transactional, if user in fact doesn't have permissions to remove token -528 // tokens removed here will be restored after rejected transaction529 for ((collection, token), _) in <TokenChildren<T>>::iter_prefix((collection.id, token)) {530 ensure!(breadth_budget.consume(), <StructureError<T>>::BreadthLimit,);531 let PostDispatchInfo { actual_weight, .. } =532 <PalletStructure<T>>::burn_item_recursively(533 current_token_account.clone(),534 collection,535 token,536 self_budget,537 breadth_budget,538 )?;539 if let Some(actual_weight) = actual_weight {540 weight = weight.saturating_add(actual_weight);541 }542 }543544 Self::burn(collection, sender, token)?;545 DispatchResultWithPostInfo::Ok(PostDispatchInfo {546 actual_weight: Some(weight + <SelfWeightOf<T>>::burn_item()),547 pays_fee: Pays::Yes,548 })549 }550551 /// A batch operation to add, edit or remove properties for a token.552 ///553 /// - `nesting_budget`: Limit for searching parents in-depth to check ownership.554 ///555 /// All affected properties should have `mutable` permission556 /// to be **deleted** or to be **set more than once**,557 /// and the sender should have permission to edit those properties.558 ///559 /// This function fires an event for each property change.560 /// In case of an error, all the changes (including the events) will be reverted561 /// since the function is transactional.562 #[transactional]563 fn modify_token_properties(564 collection: &NonfungibleHandle<T>,565 sender: &T::CrossAccountId,566 token_id: TokenId,567 properties_updates: impl Iterator<Item = (PropertyKey, Option<PropertyValue>)>,568 nesting_budget: &dyn Budget,569 ) -> DispatchResult {570 let mut property_writer =571 pallet_common::property_writer_for_existing_token(collection, sender);572573 property_writer.write_token_properties(574 sender,575 token_id,576 properties_updates,577 nesting_budget,578 erc::ERC721TokenEvent::TokenChanged {579 token_id: token_id.into(),580 }581 .to_log(T::ContractAddress::get()),582 )583 }584585 pub fn next_token_id(collection: &NonfungibleHandle<T>) -> Result<TokenId, DispatchError> {586 let next_token_id = <TokensMinted<T>>::get(collection.id)587 .checked_add(1)588 .ok_or(<CommonError<T>>::CollectionTokenLimitExceeded)?;589590 ensure!(591 collection.limits.token_limit() >= next_token_id,592 <CommonError<T>>::CollectionTokenLimitExceeded593 );594595 Ok(TokenId(next_token_id))596 }597598 /// Batch operation to add or edit properties for the token599 ///600 /// Same as [`modify_token_properties`] but doesn't allow to remove properties601 ///602 /// [`modify_token_properties`]: struct.Pallet.html#method.modify_token_properties603 pub fn set_token_properties(604 collection: &NonfungibleHandle<T>,605 sender: &T::CrossAccountId,606 token_id: TokenId,607 properties: impl Iterator<Item = Property>,608 nesting_budget: &dyn Budget,609 ) -> DispatchResult {610 Self::modify_token_properties(611 collection,612 sender,613 token_id,614 properties.map(|p| (p.key, Some(p.value))),615 nesting_budget,616 )617 }618619 /// Add or edit single property for the token620 ///621 /// Calls [`set_token_properties`] internally622 ///623 /// [`set_token_properties`]: struct.Pallet.html#method.set_token_properties624 pub fn set_token_property(625 collection: &NonfungibleHandle<T>,626 sender: &T::CrossAccountId,627 token_id: TokenId,628 property: Property,629 nesting_budget: &dyn Budget,630 ) -> DispatchResult {631 Self::set_token_properties(632 collection,633 sender,634 token_id,635 [property].into_iter(),636 nesting_budget,637 )638 }639640 /// Batch operation to remove properties from the token641 ///642 /// Same as [`modify_token_properties`] but doesn't allow to add or edit properties643 ///644 /// [`modify_token_properties`]: struct.Pallet.html#method.modify_token_properties645 pub fn delete_token_properties(646 collection: &NonfungibleHandle<T>,647 sender: &T::CrossAccountId,648 token_id: TokenId,649 property_keys: impl Iterator<Item = PropertyKey>,650 nesting_budget: &dyn Budget,651 ) -> DispatchResult {652 Self::modify_token_properties(653 collection,654 sender,655 token_id,656 property_keys.into_iter().map(|key| (key, None)),657 nesting_budget,658 )659 }660661 /// Remove single property from the token662 ///663 /// Calls [`delete_token_properties`] internally664 ///665 /// [`delete_token_properties`]: struct.Pallet.html#method.delete_token_properties666 pub fn delete_token_property(667 collection: &NonfungibleHandle<T>,668 sender: &T::CrossAccountId,669 token_id: TokenId,670 property_key: PropertyKey,671 nesting_budget: &dyn Budget,672 ) -> DispatchResult {673 Self::delete_token_properties(674 collection,675 sender,676 token_id,677 [property_key].into_iter(),678 nesting_budget,679 )680 }681682 /// Add or edit properties for the collection683 pub fn set_collection_properties(684 collection: &NonfungibleHandle<T>,685 sender: &T::CrossAccountId,686 properties: Vec<Property>,687 ) -> DispatchResult {688 <PalletCommon<T>>::set_collection_properties(collection, sender, properties.into_iter())689 }690691 /// Remove properties from the collection692 pub fn delete_collection_properties(693 collection: &CollectionHandle<T>,694 sender: &T::CrossAccountId,695 property_keys: Vec<PropertyKey>,696 ) -> DispatchResult {697 <PalletCommon<T>>::delete_collection_properties(698 collection,699 sender,700 property_keys.into_iter(),701 )702 }703704 /// Set property permissions for the token.705 ///706 /// Sender should be the owner or admin of token's collection.707 pub fn set_token_property_permissions(708 collection: &CollectionHandle<T>,709 sender: &T::CrossAccountId,710 property_permissions: Vec<PropertyKeyPermission>,711 ) -> DispatchResult {712 <PalletCommon<T>>::set_token_property_permissions(collection, sender, property_permissions)713 }714715 /// Set property permissions for the token with scope.716 ///717 /// Sender should be the owner or admin of token's collection.718 pub fn set_scoped_token_property_permissions(719 collection: &CollectionHandle<T>,720 sender: &T::CrossAccountId,721 scope: PropertyScope,722 property_permissions: Vec<PropertyKeyPermission>,723 ) -> DispatchResult {724 <PalletCommon<T>>::set_scoped_token_property_permissions(725 collection,726 sender,727 scope,728 property_permissions,729 )730 }731732 pub fn token_property_permission(collection_id: CollectionId) -> PropertiesPermissionMap {733 <PalletCommon<T>>::property_permissions(collection_id)734 }735736 pub fn check_token_immediate_ownership(737 collection: &NonfungibleHandle<T>,738 token: TokenId,739 possible_owner: &T::CrossAccountId,740 ) -> DispatchResult {741 let token_data =742 <TokenData<T>>::get((collection.id, token)).ok_or(<CommonError<T>>::TokenNotFound)?;743 ensure!(744 &token_data.owner == possible_owner,745 <CommonError<T>>::NoPermission746 );747 Ok(())748 }749750 /// Transfer NFT token from one account to another.751 ///752 /// `from` account stops being the owner and `to` account becomes the owner of the token.753 /// If `to` is token than `to` becomes owner of the token and the token become nested.754 /// Unnests token from previous parent if it was nested before.755 /// Removes allowance for the token if there was any.756 /// Throws if transfers aren't allowed for collection or if receiver reached token ownership limit.757 ///758 /// - `nesting_budget`: Limit for token nesting depth759 pub fn transfer(760 collection: &NonfungibleHandle<T>,761 from: &T::CrossAccountId,762 to: &T::CrossAccountId,763 token: TokenId,764 nesting_budget: &dyn Budget,765 ) -> DispatchResultWithPostInfo {766 ensure!(767 collection.limits.transfers_enabled(),768 <CommonError<T>>::TransferNotAllowed769 );770771 let mut actual_weight = <SelfWeightOf<T>>::transfer_raw();772 let token_data =773 <TokenData<T>>::get((collection.id, token)).ok_or(<CommonError<T>>::TokenNotFound)?;774 ensure!(&token_data.owner == from, <CommonError<T>>::NoPermission);775776 if collection.permissions.access() == AccessMode::AllowList {777 collection.check_allowlist(from)?;778 collection.check_allowlist(to)?;779 actual_weight += <PalletCommonWeightOf<T>>::check_accesslist() * 2;780 }781 <PalletCommon<T>>::ensure_correct_receiver(to)?;782783 let balance_from = <AccountBalance<T>>::get((collection.id, from))784 .checked_sub(1)785 .ok_or(<CommonError<T>>::TokenValueTooLow)?;786 let balance_to = if from != to {787 let balance_to = <AccountBalance<T>>::get((collection.id, to))788 .checked_add(1)789 .ok_or(ArithmeticError::Overflow)?;790791 ensure!(792 balance_to < collection.limits.account_token_ownership_limit(),793 <CommonError<T>>::AccountTokenLimitExceeded,794 );795796 Some(balance_to)797 } else {798 None799 };800801 <PalletStructure<T>>::nest_if_sent_to_token(802 from.clone(),803 to,804 collection.id,805 token,806 nesting_budget,807 )?;808809 // =========810811 <PalletStructure<T>>::unnest_if_nested(&token_data.owner, collection.id, token);812813 <TokenData<T>>::insert((collection.id, token), ItemData { owner: to.clone() });814815 if let Some(balance_to) = balance_to {816 // from != to817 if balance_from == 0 {818 <AccountBalance<T>>::remove((collection.id, from));819 } else {820 <AccountBalance<T>>::insert((collection.id, from), balance_from);821 }822 <AccountBalance<T>>::insert((collection.id, to), balance_to);823 <Owned<T>>::remove((collection.id, from, token));824 <Owned<T>>::insert((collection.id, to, token), true);825 }826 Self::set_allowance_unchecked(collection, from, token, None, true);827828 <PalletEvm<T>>::deposit_log(829 ERC721Events::Transfer {830 from: *from.as_eth(),831 to: *to.as_eth(),832 token_id: token.into(),833 }834 .to_log(collection_id_to_address(collection.id)),835 );836 <PalletCommon<T>>::deposit_event(CommonEvent::Transfer(837 collection.id,838 token,839 from.clone(),840 to.clone(),841 1,842 ));843844 Ok(PostDispatchInfo {845 actual_weight: Some(actual_weight),846 pays_fee: Pays::Yes,847 })848 }849850 /// Batch operation to mint multiple NFT tokens.851 ///852 /// The sender should be the owner/admin of the collection or collection should be configured853 /// to allow public minting.854 /// Throws if amount of tokens reached it's limit for the collection or if caller reached855 /// token ownership limit.856 ///857 /// - `data`: Contains list of token properties and users who will become the owners of the858 /// corresponging tokens.859 /// - `nesting_budget`: Limit for token nesting depth860 pub fn create_multiple_items(861 collection: &NonfungibleHandle<T>,862 sender: &T::CrossAccountId,863 data: Vec<CreateItemData<T>>,864 nesting_budget: &dyn Budget,865 ) -> DispatchResult {866 if !collection.is_owner_or_admin(sender) {867 ensure!(868 collection.permissions.mint_mode(),869 <CommonError<T>>::PublicMintingNotAllowed870 );871 collection.check_allowlist(sender)?;872873 for item in data.iter() {874 collection.check_allowlist(&item.owner)?;875 }876 }877878 for data in data.iter() {879 <PalletCommon<T>>::ensure_correct_receiver(&data.owner)?;880 }881882 let first_token = <TokensMinted<T>>::get(collection.id);883 let tokens_minted = first_token884 .checked_add(data.len() as u32)885 .ok_or(ArithmeticError::Overflow)?;886 ensure!(887 tokens_minted <= collection.limits.token_limit(),888 <CommonError<T>>::CollectionTokenLimitExceeded889 );890891 let mut balances = BTreeMap::new();892 for data in &data {893 let balance = balances894 .entry(&data.owner)895 .or_insert_with(|| <AccountBalance<T>>::get((collection.id, &data.owner)));896 *balance = balance.checked_add(1).ok_or(ArithmeticError::Overflow)?;897898 ensure!(899 *balance <= collection.limits.account_token_ownership_limit(),900 <CommonError<T>>::AccountTokenLimitExceeded,901 );902 }903904 for (i, data) in data.iter().enumerate() {905 let token = TokenId(first_token + i as u32 + 1);906907 <PalletStructure<T>>::check_nesting(908 sender.clone(),909 &data.owner,910 collection.id,911 token,912 nesting_budget,913 )?;914 }915916 // =========917918 let mut property_writer = pallet_common::property_writer_for_new_token(collection, sender);919920 with_transaction(|| {921 for (i, data) in data.iter().enumerate() {922 let token = first_token + i as u32 + 1;923924 <TokenData<T>>::insert(925 (collection.id, token),926 ItemData {927 // const_data: data.const_data.clone(),928 owner: data.owner.clone(),929 },930 );931932 let token = TokenId(token);933934 <PalletStructure<T>>::nest_if_sent_to_token_unchecked(935 &data.owner,936 collection.id,937 token,938 );939940 if let Err(e) = property_writer.write_token_properties(941 sender.conv_eq(&data.owner),942 token,943 data.properties.clone().into_iter(),944 erc::ERC721TokenEvent::TokenChanged {945 token_id: token.into(),946 }947 .to_log(T::ContractAddress::get()),948 ) {949 return TransactionOutcome::Rollback(Err(e));950 }951 }952 TransactionOutcome::Commit(Ok(()))953 })?;954955 <TokensMinted<T>>::insert(collection.id, tokens_minted);956 for (account, balance) in balances {957 <AccountBalance<T>>::insert((collection.id, account), balance);958 }959 for (i, data) in data.into_iter().enumerate() {960 let token = first_token + i as u32 + 1;961 <Owned<T>>::insert((collection.id, &data.owner, token), true);962963 <PalletEvm<T>>::deposit_log(964 ERC721Events::Transfer {965 from: H160::default(),966 to: *data.owner.as_eth(),967 token_id: token.into(),968 }969 .to_log(collection_id_to_address(collection.id)),970 );971 <PalletCommon<T>>::deposit_event(CommonEvent::ItemCreated(972 collection.id,973 TokenId(token),974 data.owner.clone(),975 1,976 ));977 }978 Ok(())979 }980981 pub fn set_allowance_unchecked(982 collection: &NonfungibleHandle<T>,983 sender: &T::CrossAccountId,984 token: TokenId,985 spender: Option<&T::CrossAccountId>,986 assume_implicit_eth: bool,987 ) {988 if let Some(spender) = spender {989 let old_spender = <Allowance<T>>::get((collection.id, token));990 <Allowance<T>>::insert((collection.id, token), spender);991 // In ERC721 there is only one possible approved user of token, so we set992 // approved user to spender993 <PalletEvm<T>>::deposit_log(994 ERC721Events::Approval {995 owner: *sender.as_eth(),996 approved: *spender.as_eth(),997 token_id: token.into(),998 }999 .to_log(collection_id_to_address(collection.id)),1000 );1001 // In Unique chain, any token can have any amount of approved users, so we need to1002 // set allowance of old owner to 0, and allowance of new owner to 11003 if old_spender.as_ref() != Some(spender) {1004 if let Some(old_owner) = old_spender {1005 <PalletCommon<T>>::deposit_event(CommonEvent::Approved(1006 collection.id,1007 token,1008 sender.clone(),1009 old_owner,1010 0,1011 ));1012 }1013 <PalletCommon<T>>::deposit_event(CommonEvent::Approved(1014 collection.id,1015 token,1016 sender.clone(),1017 spender.clone(),1018 1,1019 ));1020 }1021 } else {1022 let old_spender = <Allowance<T>>::take((collection.id, token));1023 if !assume_implicit_eth {1024 // In ERC721 there is only one possible approved user of token, so we set1025 // approved user to zero address1026 <PalletEvm<T>>::deposit_log(1027 ERC721Events::Approval {1028 owner: *sender.as_eth(),1029 approved: H160::default(),1030 token_id: token.into(),1031 }1032 .to_log(collection_id_to_address(collection.id)),1033 );1034 }1035 // In Unique chain, any token can have any amount of approved users, so we need to1036 // set allowance of old owner to 01037 if let Some(old_spender) = old_spender {1038 <PalletCommon<T>>::deposit_event(CommonEvent::Approved(1039 collection.id,1040 token,1041 sender.clone(),1042 old_spender,1043 0,1044 ));1045 }1046 }1047 }10481049 pub fn get_allowance(1050 collection: &NonfungibleHandle<T>,1051 token_id: TokenId,1052 ) -> Result<Option<T::CrossAccountId>, DispatchError> {1053 ensure!(1054 <TokenData<T>>::get((collection.id, token_id)).is_some(),1055 <CommonError<T>>::TokenNotFound1056 );1057 Ok(<Allowance<T>>::get((collection.id, token_id)))1058 }10591060 /// Set allowance for the spender to `transfer` or `burn` sender's token.1061 ///1062 /// - `token`: Token the spender is allowed to `transfer` or `burn`.1063 pub fn set_allowance(1064 collection: &NonfungibleHandle<T>,1065 sender: &T::CrossAccountId,1066 token: TokenId,1067 spender: Option<&T::CrossAccountId>,1068 ) -> DispatchResult {1069 if collection.permissions.access() == AccessMode::AllowList {1070 collection.check_allowlist(sender)?;1071 if let Some(spender) = spender {1072 collection.check_allowlist(spender)?;1073 }1074 }10751076 if let Some(spender) = spender {1077 <PalletCommon<T>>::ensure_correct_receiver(spender)?;1078 }10791080 let token_data =1081 <TokenData<T>>::get((collection.id, token)).ok_or(<CommonError<T>>::TokenNotFound)?;1082 if &token_data.owner != sender {1083 ensure!(1084 collection.ignores_owned_amount(sender),1085 <CommonError<T>>::CantApproveMoreThanOwned1086 );1087 }10881089 // =========10901091 Self::set_allowance_unchecked(collection, sender, token, spender, false);1092 Ok(())1093 }10941095 /// Set allowance for the spender to `transfer` or `burn` sender's token from eth mirror.1096 ///1097 /// - `from`: Address of sender's eth mirror.1098 /// - `to`: Adress of spender.1099 /// - `token`: Token the spender is allowed to `transfer` or `burn`.1100 pub fn set_allowance_from(1101 collection: &NonfungibleHandle<T>,1102 sender: &T::CrossAccountId,1103 from: &T::CrossAccountId,1104 token: TokenId,1105 to: Option<&T::CrossAccountId>,1106 ) -> DispatchResult {1107 if collection.permissions.access() == AccessMode::AllowList {1108 collection.check_allowlist(sender)?;1109 collection.check_allowlist(from)?;1110 if let Some(to) = to {1111 collection.check_allowlist(to)?;1112 }1113 }11141115 if let Some(to) = to {1116 <PalletCommon<T>>::ensure_correct_receiver(to)?;1117 }11181119 ensure!(1120 sender.conv_eq(from),1121 <CommonError<T>>::AddressIsNotEthMirror1122 );11231124 let token_data =1125 <TokenData<T>>::get((collection.id, token)).ok_or(<CommonError<T>>::TokenNotFound)?;1126 if token_data.owner != *from {1127 ensure!(1128 collection.limits.owner_can_transfer()1129 && (collection.is_owner_or_admin(sender) || collection.is_owner_or_admin(from)),1130 <CommonError<T>>::CantApproveMoreThanOwned1131 );1132 }11331134 // =========11351136 Self::set_allowance_unchecked(collection, from, token, to, false);1137 Ok(())1138 }11391140 /// Checks allowance for the spender to use the token.1141 fn check_allowed(1142 collection: &NonfungibleHandle<T>,1143 spender: &T::CrossAccountId,1144 from: &T::CrossAccountId,1145 token: TokenId,1146 nesting_budget: &dyn Budget,1147 ) -> DispatchResult {1148 if spender.conv_eq(from) {1149 return Ok(());1150 }1151 if collection.permissions.access() == AccessMode::AllowList {1152 // `from`, `to` checked in [`transfer`]1153 collection.check_allowlist(spender)?;1154 }11551156 if collection.ignores_token_restrictions(spender) {1157 return Ok(());1158 }11591160 if let Some(source) = T::CrossTokenAddressMapping::address_to_token(from) {1161 ensure!(1162 <PalletStructure<T>>::check_indirectly_owned(1163 spender.clone(),1164 source.0,1165 source.1,1166 None,1167 nesting_budget1168 )?,1169 <CommonError<T>>::ApprovedValueTooLow,1170 );1171 return Ok(());1172 }1173 if <Allowance<T>>::get((collection.id, token)).as_ref() == Some(spender) {1174 return Ok(());1175 }1176 if <CollectionAllowance<T>>::get((collection.id, from, spender)) {1177 return Ok(());1178 }11791180 Err(<CommonError<T>>::ApprovedValueTooLow.into())1181 }11821183 /// Transfer NFT token from one account to another.1184 ///1185 /// Same as the [`transfer`] but spender doesn't needs to be the owner of the token.1186 /// The owner should set allowance for the spender to transfer token.1187 ///1188 /// [`transfer`]: struct.Pallet.html#method.transfer1189 pub fn transfer_from(1190 collection: &NonfungibleHandle<T>,1191 spender: &T::CrossAccountId,1192 from: &T::CrossAccountId,1193 to: &T::CrossAccountId,1194 token: TokenId,1195 nesting_budget: &dyn Budget,1196 ) -> DispatchResultWithPostInfo {1197 Self::check_allowed(collection, spender, from, token, nesting_budget)?;11981199 // =========12001201 // Allowance is reset in [`transfer`]1202 let mut result = Self::transfer(collection, from, to, token, nesting_budget);1203 add_weight_to_post_info(&mut result, <SelfWeightOf<T>>::check_allowed_raw());1204 result1205 }12061207 /// Burn NFT token for `from` account.1208 ///1209 /// Same as the [`burn`] but spender doesn't need to be an owner of the token. The owner should1210 /// set allowance for the spender to burn token.1211 ///1212 /// [`burn`]: struct.Pallet.html#method.burn1213 pub fn burn_from(1214 collection: &NonfungibleHandle<T>,1215 spender: &T::CrossAccountId,1216 from: &T::CrossAccountId,1217 token: TokenId,1218 nesting_budget: &dyn Budget,1219 ) -> DispatchResult {1220 Self::check_allowed(collection, spender, from, token, nesting_budget)?;12211222 // =========12231224 Self::burn(collection, from, token)1225 }12261227 /// Check that `from` token could be nested in `under` token.1228 ///1229 pub fn check_nesting(1230 handle: &NonfungibleHandle<T>,1231 sender: T::CrossAccountId,1232 from: (CollectionId, TokenId),1233 under: TokenId,1234 nesting_budget: &dyn Budget,1235 ) -> DispatchResult {1236 let nesting = handle.permissions.nesting();12371238 #[cfg(not(feature = "runtime-benchmarks"))]1239 let permissive = false;1240 #[cfg(feature = "runtime-benchmarks")]1241 let permissive = nesting.permissive;12421243 if permissive {1244 ensure!(1245 <TokenData<T>>::contains_key((handle.id, under)),1246 <CommonError<T>>::TokenNotFound1247 );1248 } else if nesting.token_owner1249 && <PalletStructure<T>>::check_indirectly_owned(1250 sender.clone(),1251 handle.id,1252 under,1253 Some(from),1254 nesting_budget,1255 )? {1256 // Pass, token existence and ouroboros checks are done in `check_indirectly_owned`1257 } else if nesting.collection_admin && handle.is_owner_or_admin(&sender) {1258 // token existence and ouroboros checks are done in `get_checked_topmost_owner`1259 let _ = <PalletStructure<T>>::get_checked_topmost_owner(1260 handle.id,1261 under,1262 Some(from),1263 nesting_budget,1264 )?1265 .ok_or(<CommonError<T>>::TokenNotFound)?;1266 } else {1267 fail!(<CommonError<T>>::UserIsNotAllowedToNest);1268 }12691270 if let Some(whitelist) = &nesting.restricted {1271 ensure!(1272 whitelist.contains(&from.0),1273 <CommonError<T>>::SourceCollectionIsNotAllowedToNest1274 );1275 }1276 Ok(())1277 }12781279 fn nest(under: (CollectionId, TokenId), to_nest: (CollectionId, TokenId)) {1280 if to_nest.0 != pallet_common::NATIVE_FUNGIBLE_COLLECTION_ID {1281 <TokenChildren<T>>::insert((under.0, under.1, to_nest), true);1282 }1283 }12841285 fn unnest(under: (CollectionId, TokenId), to_unnest: (CollectionId, TokenId)) {1286 if to_unnest.0 != pallet_common::NATIVE_FUNGIBLE_COLLECTION_ID {1287 <TokenChildren<T>>::remove((under.0, under.1, to_unnest));1288 }1289 }12901291 fn collection_has_tokens(collection_id: CollectionId) -> bool {1292 <TokenData<T>>::iter_prefix((collection_id,))1293 .next()1294 .is_some()1295 }12961297 fn token_has_children(collection_id: CollectionId, token_id: TokenId) -> bool {1298 <TokenChildren<T>>::iter_prefix((collection_id, token_id))1299 .next()1300 .is_some()1301 }13021303 pub fn token_children_ids(collection_id: CollectionId, token_id: TokenId) -> Vec<TokenChild> {1304 <TokenChildren<T>>::iter_prefix((collection_id, token_id))1305 .map(|((child_collection_id, child_id), _)| TokenChild {1306 collection: child_collection_id,1307 token: child_id,1308 })1309 .collect()1310 }13111312 /// Mint single NFT token.1313 ///1314 /// Delegated to [`create_multiple_items`]1315 ///1316 /// [`create_multiple_items`]: struct.Pallet.html#method.create_multiple_items1317 pub fn create_item(1318 collection: &NonfungibleHandle<T>,1319 sender: &T::CrossAccountId,1320 data: CreateItemData<T>,1321 nesting_budget: &dyn Budget,1322 ) -> DispatchResult {1323 Self::create_multiple_items(collection, sender, vec![data], nesting_budget)1324 }13251326 /// Sets or unsets the approval of a given operator.1327 ///1328 /// The `operator` is allowed to transfer all token pieces of the `owner` on their behalf.1329 /// - `owner`: Token owner1330 /// - `operator`: Operator1331 /// - `approve`: Should operator status be granted or revoked?1332 pub fn set_allowance_for_all(1333 collection: &NonfungibleHandle<T>,1334 owner: &T::CrossAccountId,1335 operator: &T::CrossAccountId,1336 approve: bool,1337 ) -> DispatchResult {1338 <PalletCommon<T>>::set_allowance_for_all(1339 collection,1340 owner,1341 operator,1342 approve,1343 || <CollectionAllowance<T>>::insert((collection.id, owner, operator), approve),1344 ERC721Events::ApprovalForAll {1345 owner: *owner.as_eth(),1346 operator: *operator.as_eth(),1347 approved: approve,1348 }1349 .to_log(collection_id_to_address(collection.id)),1350 )1351 }13521353 /// Tells whether the given `owner` approves the `operator`.1354 pub fn allowance_for_all(1355 collection: &NonfungibleHandle<T>,1356 owner: &T::CrossAccountId,1357 operator: &T::CrossAccountId,1358 ) -> bool {1359 <CollectionAllowance<T>>::get((collection.id, owner, operator))1360 }13611362 pub fn repair_item(collection: &NonfungibleHandle<T>, token: TokenId) -> DispatchResult {1363 <TokenProperties<T>>::mutate((collection.id, token), |properties| {1364 if let Some(properties) = properties {1365 properties.recompute_consumed_space();1366 }1367 });13681369 Ok(())1370 }1371}pallets/refungible/src/benchmarking.rsdiffbeforeafterboth--- a/pallets/refungible/src/benchmarking.rs
+++ b/pallets/refungible/src/benchmarking.rs
@@ -20,7 +20,7 @@
use pallet_common::{
bench_init,
benchmarking::{
- create_collection_raw, property_key, property_value, load_is_admin_and_property_permissions,
+ create_collection_raw, load_is_admin_and_property_permissions, property_key, property_value,
},
};
use sp_std::prelude::*;
pallets/refungible/src/lib.rsdiffbeforeafterboth--- a/pallets/refungible/src/lib.rs
+++ b/pallets/refungible/src/lib.rs
@@ -106,7 +106,7 @@
budget::Budget, mapping::TokenAddressMapping, AccessMode, CollectionId, CreateCollectionData,
CreateRefungibleExMultipleOwners, PropertiesPermissionMap, Property, PropertyKey,
PropertyKeyPermission, PropertyScope, PropertyValue, TokenId, TokenOwnerError,
- TokenProperties as TokenPropertiesT, TrySetProperty, MAX_REFUNGIBLE_PIECES,
+ TokenProperties as TokenPropertiesT, MAX_REFUNGIBLE_PIECES,
};
use crate::{erc::ERC721Events, erc_token::ERC20Events};
runtime/opal/src/xcm_barrier.rsdiffbeforeafterboth--- a/runtime/opal/src/xcm_barrier.rs
+++ b/runtime/opal/src/xcm_barrier.rs
@@ -15,8 +15,10 @@
// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
use frame_support::{match_types, traits::Everything};
-use xcm::latest::{Junctions::*, MultiLocation};
-use staging_xcm_builder::{AllowTopLevelPaidExecutionFrom, TakeWeightCredit, AllowExplicitUnpaidExecutionFrom};
+use staging_xcm::latest::{Junctions::*, MultiLocation};
+use staging_xcm_builder::{
+ AllowExplicitUnpaidExecutionFrom, AllowTopLevelPaidExecutionFrom, TakeWeightCredit,
+};
match_types! {
pub type ParentOnly: impl Contains<MultiLocation> = {
runtime/quartz/src/xcm_barrier.rsdiffbeforeafterboth--- a/runtime/quartz/src/xcm_barrier.rs
+++ b/runtime/quartz/src/xcm_barrier.rs
@@ -17,8 +17,8 @@
use frame_support::{match_types, traits::Everything};
use staging_xcm::latest::{Junctions::*, MultiLocation};
use staging_xcm_builder::{
- AllowKnownQueryResponses, AllowSubscriptionsFrom, TakeWeightCredit,
- AllowTopLevelPaidExecutionFrom, AllowExplicitUnpaidExecutionFrom,
+ AllowExplicitUnpaidExecutionFrom, AllowKnownQueryResponses, AllowSubscriptionsFrom,
+ AllowTopLevelPaidExecutionFrom, TakeWeightCredit,
};
use crate::PolkadotXcm;
runtime/unique/src/xcm_barrier.rsdiffbeforeafterboth--- a/runtime/unique/src/xcm_barrier.rs
+++ b/runtime/unique/src/xcm_barrier.rs
@@ -17,8 +17,8 @@
use frame_support::{match_types, traits::Everything};
use staging_xcm::latest::{Junctions::*, MultiLocation};
use staging_xcm_builder::{
- AllowKnownQueryResponses, AllowSubscriptionsFrom, TakeWeightCredit,
- AllowTopLevelPaidExecutionFrom, AllowExplicitUnpaidExecutionFrom,
+ AllowExplicitUnpaidExecutionFrom, AllowKnownQueryResponses, AllowSubscriptionsFrom,
+ AllowTopLevelPaidExecutionFrom, TakeWeightCredit,
};
use crate::PolkadotXcm;