mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-04-26 23:57:56 +00:00
41dbed0b90
* Copy Uniques into Nfts * Connect new pallet * Update weights * Nfts: Multiple approvals (#12178) * multiple approvals * clear * tests & clean up * fix in logic & fmt * fix benchmarks * deadline * test deadline * current_block + deadline * update ApprovedTransfer event * benchmark * docs * Update frame/nfts/src/lib.rs Co-authored-by: Jegor Sidorenko <5252494+jsidorenko@users.noreply.github.com> * fmt fix * Update frame/nfts/src/lib.rs Co-authored-by: Jegor Sidorenko <5252494+jsidorenko@users.noreply.github.com> * update tests * anyone can cancel * Update frame/nfts/src/tests.rs Co-authored-by: Jegor Sidorenko <5252494+jsidorenko@users.noreply.github.com> * fmt * fix logic * unnecessary line * ".git/.scripts/bench-bot.sh" pallet dev pallet_nfts * Update frame/nfts/src/lib.rs * Update lib.rs * fmt * Update frame/nfts/src/lib.rs Co-authored-by: Squirrel <gilescope@gmail.com> * Update frame/nfts/src/lib.rs Co-authored-by: Squirrel <gilescope@gmail.com> * fmt * Update frame/nfts/src/lib.rs Co-authored-by: Squirrel <gilescope@gmail.com> * suggestion * new line * ".git/.scripts/bench-bot.sh" pallet dev pallet_nfts Co-authored-by: Jegor Sidorenko <5252494+jsidorenko@users.noreply.github.com> Co-authored-by: command-bot <> Co-authored-by: Squirrel <gilescope@gmail.com> * Fixes * cargo fmt * Fixes * Fixes * Fix CI * Nfts: Fix Auto-Increment (#12223) * commit * passing benchmarks * clean up * sync * runtime implementation * fix * fmt * fix benchmark * cfg * remove try-increment-id * remove unused error * impl Incrementable for unsigned types * clean up * fix in tests * not needed anymore * Use OptionQuery Co-authored-by: Keith Yeung <kungfukeith11@gmail.com> * Rename Origin to RuntimeOrigin * [Uniques V2] Tips (#12168) * Allow to add tips when buying an NFT * Chore * Rework tips feature * Add weights + benchmarks * Convert tuple to struct * Fix benchmark * ".git/.scripts/bench-bot.sh" pallet dev pallet_nfts * Update frame/nfts/src/benchmarking.rs Co-authored-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io> * Fix benchmarks * Revert the bounded_vec![] approach * ".git/.scripts/bench-bot.sh" pallet dev pallet_nfts Co-authored-by: command-bot <> Co-authored-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io> * [Uniques V2] Atomic NFTs swap (#12285) * Atomic NFTs swap * Fmt * Fix benchmark * Rename swap -> atomic_swap * Update target balance * Rollback * Fix * ".git/.scripts/bench-bot.sh" pallet dev pallet_nfts * Make desired item optional * Apply suggestions * Update frame/nfts/src/features/atomic_swap.rs Co-authored-by: Squirrel <gilescope@gmail.com> * Rename fields * Optimisation * Add a comment * deadline -> maybe_deadline * Add docs * Change comments * Add price direction field * ".git/.scripts/bench-bot.sh" pallet dev pallet_nfts * Wrap price and direction * Fix benchmarks * Use ensure! instead of if {} * Make duration param mandatory and limit it to MaxDeadlineDuration * Make the code safer * Fix clippy * Chore * Remove unused vars * try * try 2 * try 3 Co-authored-by: command-bot <> Co-authored-by: Squirrel <gilescope@gmail.com> * [Uniques V2] Feature flags (#12367) * Basics * WIP: change the data format * Refactor * Remove redundant new() method * Rename settings * Enable tests * Chore * Change params order * Delete the config on collection removal * Chore * Remove redundant system features * Rename force_item_status to force_collection_status * Update node runtime * Chore * Remove thaw_collection * Chore * Connect collection.is_frozen to config * Allow to lock the collection in a new way * Move free_holding into settings * Connect collection's metadata locker to feature flags * DRY * Chore * Connect pallet level feature flags * Prepare tests for the new changes * Implement Item settings * Allow to lock the metadata or attributes of an item * Common -> Settings * Extract settings related code to a separate file * Move feature flag checks inside the do_* methods * Split settings.rs into parts * Extract repeated code into macro * Extract macros into their own file * Chore * Fix traits * Fix traits * Test SystemFeatures * Fix benchmarks * Add missing benchmark * Fix node/runtime/lib.rs * ".git/.scripts/bench-bot.sh" pallet dev pallet_nfts * Keep item's config on burn if it's not empty * Fix the merge artifacts * Fmt * Add SystemFeature::NoSwaps check * Rename SystemFeatures to PalletFeatures * Rename errors * Add docs * Change error message * Rework pallet features * Move macros * Change comments * Fmt * Refactor Incrementable * Use pub(crate) for do_* functions * Update comments * Refactor freeze and lock functions * Rework Collection config and Item confg api * Chore * Make clippy happy * Chore * Update comment * RequiredDeposit => DepositRequired * Address comments Co-authored-by: command-bot <> * [Uniques V2] Refactor roles (#12437) * Basics * WIP: change the data format * Refactor * Remove redundant new() method * Rename settings * Enable tests * Chore * Change params order * Delete the config on collection removal * Chore * Remove redundant system features * Rename force_item_status to force_collection_status * Update node runtime * Chore * Remove thaw_collection * Chore * Connect collection.is_frozen to config * Allow to lock the collection in a new way * Move free_holding into settings * Connect collection's metadata locker to feature flags * DRY * Chore * Connect pallet level feature flags * Prepare tests for the new changes * Implement Item settings * Allow to lock the metadata or attributes of an item * Common -> Settings * Extract settings related code to a separate file * Move feature flag checks inside the do_* methods * Split settings.rs into parts * Extract repeated code into macro * Extract macros into their own file * Chore * Fix traits * Fix traits * Test SystemFeatures * Fix benchmarks * Add missing benchmark * Fix node/runtime/lib.rs * ".git/.scripts/bench-bot.sh" pallet dev pallet_nfts * Keep item's config on burn if it's not empty * Fix the merge artifacts * Fmt * Add SystemFeature::NoSwaps check * Refactor roles structure * Rename SystemFeatures to PalletFeatures * Rename errors * Add docs * Change error message * Rework pallet features * Move macros * Change comments * Fmt * Refactor Incrementable * Use pub(crate) for do_* functions * Update comments * Refactor freeze and lock functions * Rework Collection config and Item confg api * Chore * Make clippy happy * Chore * Fix artifacts * Address comments * Further refactoring * Add comments * Add tests for group_roles_by_account() * Update frame/nfts/src/impl_nonfungibles.rs * Add test * Replace Itertools group_by with a custom implementation * ItemsNotTransferable => ItemsNonTransferable * Update frame/nfts/src/features/roles.rs Co-authored-by: Muharem Ismailov <ismailov.m.h@gmail.com> * Address PR comments * Add missed comment Co-authored-by: command-bot <> Co-authored-by: Muharem Ismailov <ismailov.m.h@gmail.com> * Fix copy * Remove storage_prefix * Remove transactional * Initial commit SFT pallet. * Update comment * [Uniques V2] Minting options (#12483) * Basics * WIP: change the data format * Refactor * Remove redundant new() method * Rename settings * Enable tests * Chore * Change params order * Delete the config on collection removal * Chore * Remove redundant system features * Rename force_item_status to force_collection_status * Update node runtime * Chore * Remove thaw_collection * Chore * Connect collection.is_frozen to config * Allow to lock the collection in a new way * Move free_holding into settings * Connect collection's metadata locker to feature flags * DRY * Chore * Connect pallet level feature flags * Prepare tests for the new changes * Implement Item settings * Allow to lock the metadata or attributes of an item * Common -> Settings * Extract settings related code to a separate file * Move feature flag checks inside the do_* methods * Split settings.rs into parts * Extract repeated code into macro * Extract macros into their own file * Chore * Fix traits * Fix traits * Test SystemFeatures * Fix benchmarks * Add missing benchmark * Fix node/runtime/lib.rs * ".git/.scripts/bench-bot.sh" pallet dev pallet_nfts * Keep item's config on burn if it's not empty * Fix the merge artifacts * Fmt * Add SystemFeature::NoSwaps check * Rename SystemFeatures to PalletFeatures * Rename errors * Add docs * Change error message * Change the format of CollectionConfig to store more data * Move max supply to the CollectionConfig and allow to change it * Remove ItemConfig from the mint() function and use the one set in mint settings * Add different mint options * Allow to change the mint settings * Add a force_mint() method * Check mint params * Some optimisations * Cover with tests * Remove merge artifacts * Chore * Use the new has_role() method * Rework item deposits * More tests * Refactoring * Address comments * Refactor lock_collection() * Update frame/nfts/src/types.rs Co-authored-by: Squirrel <gilescope@gmail.com> * Update frame/nfts/src/types.rs Co-authored-by: Squirrel <gilescope@gmail.com> * Update frame/nfts/src/lib.rs Co-authored-by: Squirrel <gilescope@gmail.com> * Update frame/nfts/src/lib.rs Co-authored-by: Squirrel <gilescope@gmail.com> * Private => Issuer * Add more tests * Fix benchmarks * Add benchmarks for new methods * [Uniques v2] Refactoring (#12570) * Move do_set_price() and do_buy_item() to buy_sell.rs * Move approvals to feature file * Move metadata to feature files * Move the rest of methods to feature files * Remove artifacts * Split force_collection_status into 2 methods * Fix benchmarks * Fix benchmarks * Update deps Co-authored-by: command-bot <> Co-authored-by: Squirrel <gilescope@gmail.com> * Rename module to NFT fractionalisation * Loose coupling for pallet-assets * cargo fmt * [Uniques V2] Smart attributes (#12702) * Basics * WIP: change the data format * Refactor * Remove redundant new() method * Rename settings * Enable tests * Chore * Change params order * Delete the config on collection removal * Chore * Remove redundant system features * Rename force_item_status to force_collection_status * Update node runtime * Chore * Remove thaw_collection * Chore * Connect collection.is_frozen to config * Allow to lock the collection in a new way * Move free_holding into settings * Connect collection's metadata locker to feature flags * DRY * Chore * Connect pallet level feature flags * Prepare tests for the new changes * Implement Item settings * Allow to lock the metadata or attributes of an item * Common -> Settings * Extract settings related code to a separate file * Move feature flag checks inside the do_* methods * Split settings.rs into parts * Extract repeated code into macro * Extract macros into their own file * Chore * Fix traits * Fix traits * Test SystemFeatures * Fix benchmarks * Add missing benchmark * Fix node/runtime/lib.rs * ".git/.scripts/bench-bot.sh" pallet dev pallet_nfts * Keep item's config on burn if it's not empty * Fix the merge artifacts * Fmt * Add SystemFeature::NoSwaps check * Rename SystemFeatures to PalletFeatures * Rename errors * Add docs * Change error message * Change the format of CollectionConfig to store more data * Move max supply to the CollectionConfig and allow to change it * Remove ItemConfig from the mint() function and use the one set in mint settings * Add different mint options * Allow to change the mint settings * Add a force_mint() method * Check mint params * Some optimisations * Cover with tests * Remove merge artifacts * Chore * Use the new has_role() method * Rework item deposits * More tests * Refactoring * Address comments * Refactor lock_collection() * Update frame/nfts/src/types.rs Co-authored-by: Squirrel <gilescope@gmail.com> * Update frame/nfts/src/types.rs Co-authored-by: Squirrel <gilescope@gmail.com> * Update frame/nfts/src/lib.rs Co-authored-by: Squirrel <gilescope@gmail.com> * Update frame/nfts/src/lib.rs Co-authored-by: Squirrel <gilescope@gmail.com> * Private => Issuer * Add more tests * Fix benchmarks * Add benchmarks for new methods * [Uniques v2] Refactoring (#12570) * Move do_set_price() and do_buy_item() to buy_sell.rs * Move approvals to feature file * Move metadata to feature files * Move the rest of methods to feature files * Remove artifacts * Smart attributes * Split force_collection_status into 2 methods * Fix benchmarks * Fix benchmarks * Update deps * Fix merge artifact * Weights + benchmarks + docs * Change params order * Chore * Update frame/nfts/src/lib.rs Co-authored-by: Squirrel <gilescope@gmail.com> * Update frame/nfts/src/lib.rs Co-authored-by: Squirrel <gilescope@gmail.com> * Update docs * Update frame/nfts/src/lib.rs Co-authored-by: Squirrel <gilescope@gmail.com> * Add PalletId * Chore * Add tests * More tests * Add doc * Update errors snapshots * Ensure we track the owner_deposit field correctly Co-authored-by: command-bot <> Co-authored-by: Squirrel <gilescope@gmail.com> * [Uniques V2] Final improvements (#12736) * Use KeyPrefixIterator instead of Box * Change create_collection() * Restrict from claiming NFTs twice * Update Readme * Remove dead code * Refactoring * Update readme * Fix clippy * Update frame/nfts/src/lib.rs Co-authored-by: Squirrel <gilescope@gmail.com> * ".git/.scripts/bench-bot.sh" pallet dev pallet_nfts * Update docs * Typo * Fix benchmarks * Add more docs * Replace uniques with nfts, add minted volume storage * DepositRequired setting should affect only the attributes within the CollectionOwner namespace * Add unlock functionality * [NFTs] Implement missed methods to set the attributes from other pallets (#12919) * Implement missed methods to set the attributes from other pallets * Revert snapshots * Update snapshot * Update snapshot * Revert snapshot changes * Update snapshots * Yet another snapshot update.. * Asset to NFT id storage mutations * Minor fixes * Minor comments * cargo fmt * Remove benchmarking, unused clone() * Update frame/support/src/traits/tokens/nonfungible_v2.rs Co-authored-by: joe petrowski <25483142+joepetrowski@users.noreply.github.com> * Update frame/support/src/traits/tokens/nonfungible_v2.rs Co-authored-by: joe petrowski <25483142+joepetrowski@users.noreply.github.com> * Update frame/support/src/traits/tokens/nonfungible_v2.rs Co-authored-by: joe petrowski <25483142+joepetrowski@users.noreply.github.com> * Update frame/support/src/traits/tokens/nonfungibles_v2.rs Co-authored-by: joe petrowski <25483142+joepetrowski@users.noreply.github.com> * Update frame/nfts/src/lib.rs Co-authored-by: joe petrowski <25483142+joepetrowski@users.noreply.github.com> * Update frame/nfts/src/lib.rs Co-authored-by: joe petrowski <25483142+joepetrowski@users.noreply.github.com> * Update frame/nfts/src/lib.rs Co-authored-by: joe petrowski <25483142+joepetrowski@users.noreply.github.com> * Update frame/nfts/src/lib.rs Co-authored-by: joe petrowski <25483142+joepetrowski@users.noreply.github.com> * Update frame/nfts/src/lib.rs Co-authored-by: joe petrowski <25483142+joepetrowski@users.noreply.github.com> * Update frame/support/src/traits/tokens/nonfungible_v2.rs * Update frame/nfts/src/lib.rs Co-authored-by: joe petrowski <25483142+joepetrowski@users.noreply.github.com> * Update frame/support/src/traits/tokens/nonfungibles_v2.rs Co-authored-by: joe petrowski <25483142+joepetrowski@users.noreply.github.com> * Update frame/nfts/src/lib.rs Co-authored-by: joe petrowski <25483142+joepetrowski@users.noreply.github.com> * Update frame/nfts/src/lib.rs Co-authored-by: joe petrowski <25483142+joepetrowski@users.noreply.github.com> * Update frame/nfts/src/lib.rs Co-authored-by: joe petrowski <25483142+joepetrowski@users.noreply.github.com> * Update frame/nfts/src/lib.rs Co-authored-by: joe petrowski <25483142+joepetrowski@users.noreply.github.com> * Address comments * [NFTs] Add the new `owner` param to mint() method (#12997) * Add the new `owner` param to mint() method * Fmt * Address comments * ".git/.scripts/bench-bot.sh" pallet dev pallet_nfts * Fmt * Update frame/nfts/src/common_functions.rs Co-authored-by: joe petrowski <25483142+joepetrowski@users.noreply.github.com> * Update frame/nfts/src/types.rs Co-authored-by: joe petrowski <25483142+joepetrowski@users.noreply.github.com> * Update frame/nfts/src/types.rs Co-authored-by: joe petrowski <25483142+joepetrowski@users.noreply.github.com> * Update frame/nfts/src/types.rs Co-authored-by: joe petrowski <25483142+joepetrowski@users.noreply.github.com> * Update frame/nfts/src/types.rs Co-authored-by: joe petrowski <25483142+joepetrowski@users.noreply.github.com> * Update frame/nfts/src/types.rs Co-authored-by: joe petrowski <25483142+joepetrowski@users.noreply.github.com> * Add call indexes * Update snapshots * Refactor nft fractionalisation pallet (#13008) * Refactoring * Make it compile * Add tests * Rename * Rework nfts locking * Update cargo.lock * Connect the latest changes to the runtime-kitchensink * Add benchmarks, fix other issues * Chore * Chore 2 * Chore 3 * Add runtime-benchmarks * Rename * Set metadata * Make fields public * Chore * Created asset shouldn't be sufficient * Add documentation * minor edit to docs * Minor corrections Co-authored-by: lana-shanghai <svetlana.konstantinovna@gmail.com> * fmt * Add fee reserved before creating an asset * Use ReservableCurrency for fee deposit * Improvements * Revert fmt changes * A bit more cleanup * Consistent naming * Make it more generic * Leftover * Use Vec<u8> instead of String * Update to the latest + improve the Locker trait * Refactor NFTs locker * Replace Vec with BoundedVec, add clearer errors * cargo fmt * Add README about unlocking NFTs * add constant definition * add fortitude & precision to asset related functions * fix mock and tests * transfer ExistentialDeposit to pallet if it's balance is below * Refactoring * Simplify the locking mechanism * Use PalletAttributes enum instead of the LOCKED_NFT_KEY * Fix benchmark * Add missing licence details * Update Cargo.toml * ".git/.scripts/commands/bench/bench.sh" pallet dev pallet_nft_fractionalization * Apply suggestions from code review Co-authored-by: joe petrowski <25483142+joepetrowski@users.noreply.github.com> * Update frame/nft-fractionalization/README.md Co-authored-by: joe petrowski <25483142+joepetrowski@users.noreply.github.com> --------- Co-authored-by: Jegor Sidorenko <jegor@parity.io> Co-authored-by: Sergej Sakac <73715684+Szegoo@users.noreply.github.com> Co-authored-by: Jegor Sidorenko <5252494+jsidorenko@users.noreply.github.com> Co-authored-by: Squirrel <gilescope@gmail.com> Co-authored-by: Keith Yeung <kungfukeith11@gmail.com> Co-authored-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io> Co-authored-by: Muharem Ismailov <ismailov.m.h@gmail.com> Co-authored-by: command-bot <> Co-authored-by: joe petrowski <25483142+joepetrowski@users.noreply.github.com>
413 lines
14 KiB
Rust
413 lines
14 KiB
Rust
// This file is part of Substrate.
|
|
|
|
// Copyright (C) Parity Technologies (UK) Ltd.
|
|
// SPDX-License-Identifier: Apache-2.0
|
|
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
|
|
use crate::*;
|
|
use frame_support::pallet_prelude::*;
|
|
|
|
impl<T: Config<I>, I: 'static> Pallet<T, I> {
|
|
pub(crate) fn do_set_attribute(
|
|
origin: T::AccountId,
|
|
collection: T::CollectionId,
|
|
maybe_item: Option<T::ItemId>,
|
|
namespace: AttributeNamespace<T::AccountId>,
|
|
key: BoundedVec<u8, T::KeyLimit>,
|
|
value: BoundedVec<u8, T::ValueLimit>,
|
|
depositor: T::AccountId,
|
|
) -> DispatchResult {
|
|
ensure!(
|
|
Self::is_pallet_feature_enabled(PalletFeature::Attributes),
|
|
Error::<T, I>::MethodDisabled
|
|
);
|
|
|
|
ensure!(
|
|
Self::is_valid_namespace(&origin, &namespace, &collection, &maybe_item)?,
|
|
Error::<T, I>::NoPermission
|
|
);
|
|
|
|
let collection_config = Self::get_collection_config(&collection)?;
|
|
// for the `CollectionOwner` namespace we need to check if the collection/item is not locked
|
|
match namespace {
|
|
AttributeNamespace::CollectionOwner => match maybe_item {
|
|
None => {
|
|
ensure!(
|
|
collection_config.is_setting_enabled(CollectionSetting::UnlockedAttributes),
|
|
Error::<T, I>::LockedCollectionAttributes
|
|
)
|
|
},
|
|
Some(item) => {
|
|
let maybe_is_locked = Self::get_item_config(&collection, &item)
|
|
.map(|c| c.has_disabled_setting(ItemSetting::UnlockedAttributes))?;
|
|
ensure!(!maybe_is_locked, Error::<T, I>::LockedItemAttributes);
|
|
},
|
|
},
|
|
_ => (),
|
|
}
|
|
|
|
let mut collection_details =
|
|
Collection::<T, I>::get(&collection).ok_or(Error::<T, I>::UnknownCollection)?;
|
|
|
|
let attribute = Attribute::<T, I>::get((collection, maybe_item, &namespace, &key));
|
|
let attribute_exists = attribute.is_some();
|
|
if !attribute_exists {
|
|
collection_details.attributes.saturating_inc();
|
|
}
|
|
|
|
let old_deposit =
|
|
attribute.map_or(AttributeDeposit { account: None, amount: Zero::zero() }, |m| m.1);
|
|
|
|
let mut deposit = Zero::zero();
|
|
// disabled DepositRequired setting only affects the CollectionOwner namespace
|
|
if collection_config.is_setting_enabled(CollectionSetting::DepositRequired) ||
|
|
namespace != AttributeNamespace::CollectionOwner
|
|
{
|
|
deposit = T::DepositPerByte::get()
|
|
.saturating_mul(((key.len() + value.len()) as u32).into())
|
|
.saturating_add(T::AttributeDepositBase::get());
|
|
}
|
|
|
|
let is_collection_owner_namespace = namespace == AttributeNamespace::CollectionOwner;
|
|
let is_depositor_collection_owner =
|
|
is_collection_owner_namespace && collection_details.owner == depositor;
|
|
|
|
// NOTE: in the CollectionOwner namespace if the depositor is `None` that means the deposit
|
|
// was paid by the collection's owner.
|
|
let old_depositor =
|
|
if is_collection_owner_namespace && old_deposit.account.is_none() && attribute_exists {
|
|
Some(collection_details.owner.clone())
|
|
} else {
|
|
old_deposit.account
|
|
};
|
|
let depositor_has_changed = old_depositor != Some(depositor.clone());
|
|
|
|
// NOTE: when we transfer an item, we don't move attributes in the ItemOwner namespace.
|
|
// When the new owner updates the same attribute, we will update the depositor record
|
|
// and return the deposit to the previous owner.
|
|
if depositor_has_changed {
|
|
if let Some(old_depositor) = old_depositor {
|
|
T::Currency::unreserve(&old_depositor, old_deposit.amount);
|
|
}
|
|
T::Currency::reserve(&depositor, deposit)?;
|
|
} else if deposit > old_deposit.amount {
|
|
T::Currency::reserve(&depositor, deposit - old_deposit.amount)?;
|
|
} else if deposit < old_deposit.amount {
|
|
T::Currency::unreserve(&depositor, old_deposit.amount - deposit);
|
|
}
|
|
|
|
if is_depositor_collection_owner {
|
|
if !depositor_has_changed {
|
|
collection_details.owner_deposit.saturating_reduce(old_deposit.amount);
|
|
}
|
|
collection_details.owner_deposit.saturating_accrue(deposit);
|
|
}
|
|
|
|
let new_deposit_owner = match is_depositor_collection_owner {
|
|
true => None,
|
|
false => Some(depositor),
|
|
};
|
|
Attribute::<T, I>::insert(
|
|
(&collection, maybe_item, &namespace, &key),
|
|
(&value, AttributeDeposit { account: new_deposit_owner, amount: deposit }),
|
|
);
|
|
|
|
Collection::<T, I>::insert(collection, &collection_details);
|
|
Self::deposit_event(Event::AttributeSet { collection, maybe_item, key, value, namespace });
|
|
Ok(())
|
|
}
|
|
|
|
pub(crate) fn do_force_set_attribute(
|
|
set_as: Option<T::AccountId>,
|
|
collection: T::CollectionId,
|
|
maybe_item: Option<T::ItemId>,
|
|
namespace: AttributeNamespace<T::AccountId>,
|
|
key: BoundedVec<u8, T::KeyLimit>,
|
|
value: BoundedVec<u8, T::ValueLimit>,
|
|
) -> DispatchResult {
|
|
let mut collection_details =
|
|
Collection::<T, I>::get(&collection).ok_or(Error::<T, I>::UnknownCollection)?;
|
|
|
|
let attribute = Attribute::<T, I>::get((collection, maybe_item, &namespace, &key));
|
|
if let Some((_, deposit)) = attribute {
|
|
if deposit.account != set_as && deposit.amount != Zero::zero() {
|
|
if let Some(deposit_account) = deposit.account {
|
|
T::Currency::unreserve(&deposit_account, deposit.amount);
|
|
}
|
|
}
|
|
} else {
|
|
collection_details.attributes.saturating_inc();
|
|
}
|
|
|
|
Attribute::<T, I>::insert(
|
|
(&collection, maybe_item, &namespace, &key),
|
|
(&value, AttributeDeposit { account: set_as, amount: Zero::zero() }),
|
|
);
|
|
Collection::<T, I>::insert(collection, &collection_details);
|
|
Self::deposit_event(Event::AttributeSet { collection, maybe_item, key, value, namespace });
|
|
Ok(())
|
|
}
|
|
|
|
pub(crate) fn do_set_attributes_pre_signed(
|
|
origin: T::AccountId,
|
|
data: PreSignedAttributesOf<T, I>,
|
|
signer: T::AccountId,
|
|
) -> DispatchResult {
|
|
let PreSignedAttributes { collection, item, attributes, namespace, deadline } = data;
|
|
|
|
ensure!(
|
|
attributes.len() <= T::MaxAttributesPerCall::get() as usize,
|
|
Error::<T, I>::MaxAttributesLimitReached
|
|
);
|
|
|
|
let now = frame_system::Pallet::<T>::block_number();
|
|
ensure!(deadline >= now, Error::<T, I>::DeadlineExpired);
|
|
|
|
let item_details =
|
|
Item::<T, I>::get(&collection, &item).ok_or(Error::<T, I>::UnknownItem)?;
|
|
ensure!(item_details.owner == origin, Error::<T, I>::NoPermission);
|
|
|
|
// Only the CollectionOwner and Account() namespaces could be updated in this way.
|
|
// For the Account() namespace we check and set the approval if it wasn't set before.
|
|
match &namespace {
|
|
AttributeNamespace::CollectionOwner => {},
|
|
AttributeNamespace::Account(account) => {
|
|
ensure!(account == &signer, Error::<T, I>::NoPermission);
|
|
let approvals = ItemAttributesApprovalsOf::<T, I>::get(&collection, &item);
|
|
if !approvals.contains(account) {
|
|
Self::do_approve_item_attributes(
|
|
origin.clone(),
|
|
collection,
|
|
item,
|
|
account.clone(),
|
|
)?;
|
|
}
|
|
},
|
|
_ => return Err(Error::<T, I>::WrongNamespace.into()),
|
|
}
|
|
|
|
for (key, value) in attributes {
|
|
Self::do_set_attribute(
|
|
signer.clone(),
|
|
collection,
|
|
Some(item),
|
|
namespace.clone(),
|
|
Self::construct_attribute_key(key)?,
|
|
Self::construct_attribute_value(value)?,
|
|
origin.clone(),
|
|
)?;
|
|
}
|
|
Self::deposit_event(Event::PreSignedAttributesSet { collection, item, namespace });
|
|
Ok(())
|
|
}
|
|
|
|
pub(crate) fn do_clear_attribute(
|
|
maybe_check_origin: Option<T::AccountId>,
|
|
collection: T::CollectionId,
|
|
maybe_item: Option<T::ItemId>,
|
|
namespace: AttributeNamespace<T::AccountId>,
|
|
key: BoundedVec<u8, T::KeyLimit>,
|
|
) -> DispatchResult {
|
|
let (_, deposit) = Attribute::<T, I>::take((collection, maybe_item, &namespace, &key))
|
|
.ok_or(Error::<T, I>::AttributeNotFound)?;
|
|
|
|
if let Some(check_origin) = &maybe_check_origin {
|
|
// validate the provided namespace when it's not a root call and the caller is not
|
|
// the same as the `deposit.account` (e.g. the deposit was paid by different account)
|
|
if deposit.account != maybe_check_origin {
|
|
ensure!(
|
|
Self::is_valid_namespace(&check_origin, &namespace, &collection, &maybe_item)?,
|
|
Error::<T, I>::NoPermission
|
|
);
|
|
}
|
|
|
|
// can't clear `CollectionOwner` type attributes if the collection/item is locked
|
|
match namespace {
|
|
AttributeNamespace::CollectionOwner => match maybe_item {
|
|
None => {
|
|
let collection_config = Self::get_collection_config(&collection)?;
|
|
ensure!(
|
|
collection_config
|
|
.is_setting_enabled(CollectionSetting::UnlockedAttributes),
|
|
Error::<T, I>::LockedCollectionAttributes
|
|
)
|
|
},
|
|
Some(item) => {
|
|
// NOTE: if the item was previously burned, the ItemConfigOf record
|
|
// might not exist. In that case, we allow to clear the attribute.
|
|
let maybe_is_locked = Self::get_item_config(&collection, &item)
|
|
.map_or(None, |c| {
|
|
Some(c.has_disabled_setting(ItemSetting::UnlockedAttributes))
|
|
});
|
|
if let Some(is_locked) = maybe_is_locked {
|
|
ensure!(!is_locked, Error::<T, I>::LockedItemAttributes);
|
|
// Only the collection's admin can clear attributes in that namespace.
|
|
// e.g. in off-chain mints, the attribute's depositor will be the item's
|
|
// owner, that's why we need to do this extra check.
|
|
ensure!(
|
|
Self::has_role(&collection, &check_origin, CollectionRole::Admin),
|
|
Error::<T, I>::NoPermission
|
|
);
|
|
}
|
|
},
|
|
},
|
|
_ => (),
|
|
};
|
|
}
|
|
|
|
let mut collection_details =
|
|
Collection::<T, I>::get(&collection).ok_or(Error::<T, I>::UnknownCollection)?;
|
|
|
|
collection_details.attributes.saturating_dec();
|
|
|
|
match deposit.account {
|
|
Some(deposit_account) => {
|
|
T::Currency::unreserve(&deposit_account, deposit.amount);
|
|
},
|
|
None if namespace == AttributeNamespace::CollectionOwner => {
|
|
collection_details.owner_deposit.saturating_reduce(deposit.amount);
|
|
T::Currency::unreserve(&collection_details.owner, deposit.amount);
|
|
},
|
|
_ => (),
|
|
}
|
|
|
|
Collection::<T, I>::insert(collection, &collection_details);
|
|
Self::deposit_event(Event::AttributeCleared { collection, maybe_item, key, namespace });
|
|
|
|
Ok(())
|
|
}
|
|
|
|
pub(crate) fn do_approve_item_attributes(
|
|
check_origin: T::AccountId,
|
|
collection: T::CollectionId,
|
|
item: T::ItemId,
|
|
delegate: T::AccountId,
|
|
) -> DispatchResult {
|
|
ensure!(
|
|
Self::is_pallet_feature_enabled(PalletFeature::Attributes),
|
|
Error::<T, I>::MethodDisabled
|
|
);
|
|
|
|
let details = Item::<T, I>::get(&collection, &item).ok_or(Error::<T, I>::UnknownItem)?;
|
|
ensure!(check_origin == details.owner, Error::<T, I>::NoPermission);
|
|
|
|
ItemAttributesApprovalsOf::<T, I>::try_mutate(collection, item, |approvals| {
|
|
approvals
|
|
.try_insert(delegate.clone())
|
|
.map_err(|_| Error::<T, I>::ReachedApprovalLimit)?;
|
|
|
|
Self::deposit_event(Event::ItemAttributesApprovalAdded { collection, item, delegate });
|
|
Ok(())
|
|
})
|
|
}
|
|
|
|
pub(crate) fn do_cancel_item_attributes_approval(
|
|
check_origin: T::AccountId,
|
|
collection: T::CollectionId,
|
|
item: T::ItemId,
|
|
delegate: T::AccountId,
|
|
witness: CancelAttributesApprovalWitness,
|
|
) -> DispatchResult {
|
|
ensure!(
|
|
Self::is_pallet_feature_enabled(PalletFeature::Attributes),
|
|
Error::<T, I>::MethodDisabled
|
|
);
|
|
|
|
let details = Item::<T, I>::get(&collection, &item).ok_or(Error::<T, I>::UnknownItem)?;
|
|
ensure!(check_origin == details.owner, Error::<T, I>::NoPermission);
|
|
|
|
ItemAttributesApprovalsOf::<T, I>::try_mutate(collection, item, |approvals| {
|
|
approvals.remove(&delegate);
|
|
|
|
let mut attributes: u32 = 0;
|
|
let mut deposited: DepositBalanceOf<T, I> = Zero::zero();
|
|
for (_, (_, deposit)) in Attribute::<T, I>::drain_prefix((
|
|
&collection,
|
|
Some(item),
|
|
AttributeNamespace::Account(delegate.clone()),
|
|
)) {
|
|
attributes.saturating_inc();
|
|
deposited = deposited.saturating_add(deposit.amount);
|
|
}
|
|
ensure!(attributes <= witness.account_attributes, Error::<T, I>::BadWitness);
|
|
|
|
if !deposited.is_zero() {
|
|
T::Currency::unreserve(&delegate, deposited);
|
|
}
|
|
|
|
Self::deposit_event(Event::ItemAttributesApprovalRemoved {
|
|
collection,
|
|
item,
|
|
delegate,
|
|
});
|
|
Ok(())
|
|
})
|
|
}
|
|
|
|
fn is_valid_namespace(
|
|
origin: &T::AccountId,
|
|
namespace: &AttributeNamespace<T::AccountId>,
|
|
collection: &T::CollectionId,
|
|
maybe_item: &Option<T::ItemId>,
|
|
) -> Result<bool, DispatchError> {
|
|
let mut result = false;
|
|
match namespace {
|
|
AttributeNamespace::CollectionOwner =>
|
|
result = Self::has_role(&collection, &origin, CollectionRole::Admin),
|
|
AttributeNamespace::ItemOwner =>
|
|
if let Some(item) = maybe_item {
|
|
let item_details =
|
|
Item::<T, I>::get(&collection, &item).ok_or(Error::<T, I>::UnknownItem)?;
|
|
result = origin == &item_details.owner
|
|
},
|
|
AttributeNamespace::Account(account_id) =>
|
|
if let Some(item) = maybe_item {
|
|
let approvals = ItemAttributesApprovalsOf::<T, I>::get(&collection, &item);
|
|
result = account_id == origin && approvals.contains(&origin)
|
|
},
|
|
_ => (),
|
|
};
|
|
Ok(result)
|
|
}
|
|
|
|
/// A helper method to construct attribute's key.
|
|
pub fn construct_attribute_key(
|
|
key: Vec<u8>,
|
|
) -> Result<BoundedVec<u8, T::KeyLimit>, DispatchError> {
|
|
Ok(BoundedVec::try_from(key).map_err(|_| Error::<T, I>::IncorrectData)?)
|
|
}
|
|
|
|
/// A helper method to construct attribute's value.
|
|
pub fn construct_attribute_value(
|
|
value: Vec<u8>,
|
|
) -> Result<BoundedVec<u8, T::ValueLimit>, DispatchError> {
|
|
Ok(BoundedVec::try_from(value).map_err(|_| Error::<T, I>::IncorrectData)?)
|
|
}
|
|
|
|
/// A helper method to check whether a system attribute is set for a given item.
|
|
pub fn has_system_attribute(
|
|
collection: &T::CollectionId,
|
|
item: &T::ItemId,
|
|
attribute_key: PalletAttributes<T::CollectionId>,
|
|
) -> Result<bool, DispatchError> {
|
|
let attribute = (
|
|
&collection,
|
|
Some(item),
|
|
AttributeNamespace::Pallet,
|
|
&Self::construct_attribute_key(attribute_key.encode())?,
|
|
);
|
|
Ok(Attribute::<T, I>::contains_key(attribute))
|
|
}
|
|
}
|