difftreelog
fix(foreign-assets) make benchmarks do updates
in: master
6 files changed
pallets/app-promotion/Cargo.tomldiffbeforeafterboth--- a/pallets/app-promotion/Cargo.toml
+++ b/pallets/app-promotion/Cargo.toml
@@ -66,8 +66,6 @@
pallet-common ={ default-features = false, path = "../common" }
pallet-unique ={ default-features = false, path = "../unique" }
pallet-evm-contract-helpers ={ default-features = false, path = "../evm-contract-helpers" }
-
-[dev-dependencies]
pallet-evm-migration ={ default-features = false, path = "../evm-migration" }
################################################################################
pallets/app-promotion/src/benchmarking.rsdiffbeforeafterboth--- a/pallets/app-promotion/src/benchmarking.rs
+++ b/pallets/app-promotion/src/benchmarking.rs
@@ -20,11 +20,10 @@
use crate::Pallet as PromototionPallet;
use sp_runtime::traits::Bounded;
-use sp_std::vec;
use frame_benchmarking::{benchmarks, account};
use frame_support::traits::OnInitialize;
-use frame_system::{Origin, RawOrigin};
+use frame_system::RawOrigin;
use pallet_unique::benchmarking::create_nft_collection;
use pallet_evm_migration::Pallet as EvmMigrationPallet;
pallets/common/src/benchmarking.rsdiffbeforeafterboth--- a/pallets/common/src/benchmarking.rs
+++ b/pallets/common/src/benchmarking.rs
@@ -19,8 +19,8 @@
use pallet_evm::account::CrossAccountId;
use frame_benchmarking::{benchmarks, account};
use up_data_structs::{
- CollectionMode, CreateCollectionData, CollectionId, Property, PropertyKey, PropertyValue,
- CollectionPermissions, NestingPermissions, MAX_COLLECTION_NAME_LENGTH,
+ CollectionMode, CollectionFlags, CreateCollectionData, CollectionId, Property, PropertyKey,
+ PropertyValue, CollectionPermissions, NestingPermissions, MAX_COLLECTION_NAME_LENGTH,
MAX_COLLECTION_DESCRIPTION_LENGTH, MAX_TOKEN_PREFIX_LENGTH, MAX_PROPERTIES_PER_ITEM,
};
use frame_support::{
@@ -116,7 +116,7 @@
create_collection_raw(
owner,
CollectionMode::NFT,
- |owner, data| <Pallet<T>>::init_collection(owner, data, true),
+ |owner, data| <Pallet<T>>::init_collection(owner, data, CollectionFlags::default()),
|h| h,
)
}
pallets/common/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//! # Common pallet18//!19//! The Common pallet provides functionality for handling collections.20//!21//! ## Overview22//!23//! The Common pallet provides an interface for common collection operations for different collection types24//! (see [CommonCollectionOperations]), as well as a generic dispatcher for these, see [dispatch] module.25//! It also provides this functionality to EVM, see [erc] and [eth] modules.26//!27//! The Common pallet provides functions for:28//!29//! - Setting and approving collection sponsor.30//! - Get\set\delete allow list.31//! - Get\set\delete collection properties.32//! - Get\set\delete collection property permissions.33//! - Get\set\delete token property permissions.34//! - Get\set\delete collection administrators.35//! - Checking access permissions.36//!37//! ### Terminology38//! **Collection sponsor** - For the collection, you can set a sponsor, at whose expense it will39//! be possible to mint tokens.40//!41//! **Allow list** - List of users who have the right to minting tokens.42//!43//! **Collection properties** - Collection properties are simply key-value stores where various44//! metadata can be placed.45//!46//! **Permissions on token properties** - For each property in the token can be set permission47//! to change, see [`PropertyPermission`].48//!49//! **Collection administrator** - For a collection, you can set administrators who have the right50//! to most actions on the collection.5152#![warn(missing_docs)]53#![cfg_attr(not(feature = "std"), no_std)]54extern crate alloc;5556use core::ops::{Deref, DerefMut};57use pallet_evm_coder_substrate::{SubstrateRecorder, WithRecorder};58use sp_std::vec::Vec;59use pallet_evm::{account::CrossAccountId, Pallet as PalletEvm};60use evm_coder::ToLog;61use frame_support::{62 dispatch::{DispatchErrorWithPostInfo, DispatchResultWithPostInfo, Weight, PostDispatchInfo},63 ensure,64 traits::{Imbalance, Get, Currency, WithdrawReasons, ExistenceRequirement},65 weights::Pays,66 transactional,67};68use pallet_evm::GasWeightMapping;69use up_data_structs::{70 COLLECTION_NUMBER_LIMIT,71 Collection,72 RpcCollection,73 CollectionFlags,74 CollectionId,75 CreateItemData,76 MAX_TOKEN_PREFIX_LENGTH,77 COLLECTION_ADMINS_LIMIT,78 TokenId,79 TokenChild,80 CollectionStats,81 MAX_TOKEN_OWNERSHIP,82 CollectionMode,83 NFT_SPONSOR_TRANSFER_TIMEOUT,84 FUNGIBLE_SPONSOR_TRANSFER_TIMEOUT,85 REFUNGIBLE_SPONSOR_TRANSFER_TIMEOUT,86 MAX_SPONSOR_TIMEOUT,87 CUSTOM_DATA_LIMIT,88 CollectionLimits,89 CreateCollectionData,90 SponsorshipState,91 CreateItemExData,92 SponsoringRateLimit,93 budget::Budget,94 PhantomType,95 Property,96 Properties,97 PropertiesPermissionMap,98 PropertyKey,99 PropertyValue,100 PropertyPermission,101 PropertiesError,102 PropertyKeyPermission,103 TokenData,104 TrySetProperty,105 PropertyScope,106 // RMRK107 RmrkCollectionInfo,108 RmrkInstanceInfo,109 RmrkResourceInfo,110 RmrkPropertyInfo,111 RmrkBaseInfo,112 RmrkPartType,113 RmrkBoundedTheme,114 RmrkNftChild,115 CollectionPermissions,116};117118pub use pallet::*;119use sp_core::H160;120use sp_runtime::{ArithmeticError, DispatchError, DispatchResult};121#[cfg(feature = "runtime-benchmarks")]122pub mod benchmarking;123pub mod dispatch;124pub mod erc;125pub mod eth;126pub mod weights;127128/// Weight info.129pub type SelfWeightOf<T> = <T as Config>::WeightInfo;130131/// Collection handle contains information about collection data and id.132/// Also provides functionality to count consumed gas.133///134/// CollectionHandle is used as a generic wrapper for collections of all types.135/// It allows to perform common operations and queries on any collection type,136/// both completely general for all, as well as their respective implementations of [`CommonCollectionOperations`].137#[must_use = "Should call submit_logs or save, otherwise some data will be lost for evm side"]138pub struct CollectionHandle<T: Config> {139 /// Collection id140 pub id: CollectionId,141 collection: Collection<T::AccountId>,142 /// Substrate recorder for counting consumed gas143 pub recorder: SubstrateRecorder<T>,144}145146impl<T: Config> WithRecorder<T> for CollectionHandle<T> {147 fn recorder(&self) -> &SubstrateRecorder<T> {148 &self.recorder149 }150 fn into_recorder(self) -> SubstrateRecorder<T> {151 self.recorder152 }153}154155impl<T: Config> CollectionHandle<T> {156 /// Same as [CollectionHandle::new] but with an explicit gas limit.157 pub fn new_with_gas_limit(id: CollectionId, gas_limit: u64) -> Option<Self> {158 <CollectionById<T>>::get(id).map(|collection| Self {159 id,160 collection,161 recorder: SubstrateRecorder::new(gas_limit),162 })163 }164165 /// Same as [CollectionHandle::new] but with an existed [`SubstrateRecorder`].166 pub fn new_with_recorder(id: CollectionId, recorder: SubstrateRecorder<T>) -> Option<Self> {167 <CollectionById<T>>::get(id).map(|collection| Self {168 id,169 collection,170 recorder,171 })172 }173174 /// Retrives collection data from storage and creates collection handle with default parameters.175 /// If collection not found return `None`176 pub fn new(id: CollectionId) -> Option<Self> {177 Self::new_with_gas_limit(id, u64::MAX)178 }179180 /// Same as [`CollectionHandle::new`] but if collection not found [CollectionNotFound](Error::CollectionNotFound) returned.181 pub fn try_get(id: CollectionId) -> Result<Self, DispatchError> {182 Ok(Self::new(id).ok_or(<Error<T>>::CollectionNotFound)?)183 }184185 /// Consume gas for reading.186 pub fn consume_store_reads(&self, reads: u64) -> evm_coder::execution::Result<()> {187 self.recorder188 .consume_gas(T::GasWeightMapping::weight_to_gas(189 <T as frame_system::Config>::DbWeight::get()190 .read191 .saturating_mul(reads),192 ))193 }194195 /// Consume gas for writing.196 pub fn consume_store_writes(&self, writes: u64) -> evm_coder::execution::Result<()> {197 self.recorder198 .consume_gas(T::GasWeightMapping::weight_to_gas(199 <T as frame_system::Config>::DbWeight::get()200 .write201 .saturating_mul(writes),202 ))203 }204205 /// Consume gas for reading and writing.206 pub fn consume_store_reads_and_writes(207 &self,208 reads: u64,209 writes: u64,210 ) -> evm_coder::execution::Result<()> {211 let weight = <T as frame_system::Config>::DbWeight::get();212 let reads = weight.read.saturating_mul(reads);213 let writes = weight.read.saturating_mul(writes);214 self.recorder215 .consume_gas(T::GasWeightMapping::weight_to_gas(216 reads.saturating_add(writes),217 ))218 }219220 /// Save collection to storage.221 pub fn save(&self) -> DispatchResult {222 <CollectionById<T>>::insert(self.id, &self.collection);223 Ok(())224 }225226 /// Set collection sponsor.227 ///228 /// Unique collections allows sponsoring for certain actions.229 /// This method allows you to set the sponsor of the collection.230 /// In order for sponsorship to become active, it must be confirmed through [`Self::confirm_sponsorship`].231 pub fn set_sponsor(&mut self, sponsor: T::AccountId) -> DispatchResult {232 self.collection.sponsorship = SponsorshipState::Unconfirmed(sponsor);233 Ok(())234 }235236 /// Confirm sponsorship237 ///238 /// In order for the sponsorship to become active, the user set as the sponsor must confirm their participation.239 /// Before confirming sponsorship, the user must be specified as the sponsor of the collection via [`Self::set_sponsor`].240 pub fn confirm_sponsorship(&mut self, sender: &T::AccountId) -> Result<bool, DispatchError> {241 if self.collection.sponsorship.pending_sponsor() != Some(sender) {242 return Ok(false);243 }244245 self.collection.sponsorship = SponsorshipState::Confirmed(sender.clone());246 Ok(true)247 }248249 /// Remove collection sponsor.250 pub fn remove_sponsor(&mut self) -> DispatchResult {251 self.collection.sponsorship = SponsorshipState::Disabled;252 Ok(())253 }254255 /// Checks that the collection was created with, and must be operated upon through **Unique API**.256 /// Now check only the `external` flag and if it's **true**, then return [`Error::CollectionIsExternal`] error.257 pub fn check_is_internal(&self) -> DispatchResult {258 if self.flags.external {259 return Err(<Error<T>>::CollectionIsExternal)?;260 }261262 Ok(())263 }264265 /// Checks that the collection was created with, and must be operated upon through an **assimilated API**.266 /// Now check only the `external` flag and if it's **false**, then return [`Error::CollectionIsInternal`] error.267 pub fn check_is_external(&self) -> DispatchResult {268 if !self.flags.external {269 return Err(<Error<T>>::CollectionIsInternal)?;270 }271272 Ok(())273 }274}275276impl<T: Config> Deref for CollectionHandle<T> {277 type Target = Collection<T::AccountId>;278279 fn deref(&self) -> &Self::Target {280 &self.collection281 }282}283284impl<T: Config> DerefMut for CollectionHandle<T> {285 fn deref_mut(&mut self) -> &mut Self::Target {286 &mut self.collection287 }288}289290impl<T: Config> CollectionHandle<T> {291 /// Checks if the `user` is the owner of the collection.292 pub fn check_is_owner(&self, user: &T::CrossAccountId) -> DispatchResult {293 ensure!(*user.as_sub() == self.owner, <Error<T>>::NoPermission);294 Ok(())295 }296297 /// Returns **true** if the `user` is the owner or administrator of the collection.298 pub fn is_owner_or_admin(&self, user: &T::CrossAccountId) -> bool {299 *user.as_sub() == self.owner || <IsAdmin<T>>::get((self.id, user))300 }301302 /// Checks if the `user` is the owner or administrator of the collection.303 pub fn check_is_owner_or_admin(&self, user: &T::CrossAccountId) -> DispatchResult {304 ensure!(self.is_owner_or_admin(user), <Error<T>>::NoPermission);305 Ok(())306 }307308 /// Return **true** if `user` was not allowed to have tokens, and he can ignore such restrictions.309 pub fn ignores_allowance(&self, user: &T::CrossAccountId) -> bool {310 self.limits.owner_can_transfer() && self.is_owner_or_admin(user)311 }312313 /// Return **true** if `user` does not have enough token parts, and he can ignore such restrictions.314 pub fn ignores_owned_amount(&self, user: &T::CrossAccountId) -> bool {315 self.limits.owner_can_transfer() && self.is_owner_or_admin(user)316 }317318 /// Checks if the user is in the allow list. If not [Error::AddressNotInAllowlist] returns.319 pub fn check_allowlist(&self, user: &T::CrossAccountId) -> DispatchResult {320 ensure!(321 <Allowlist<T>>::get((self.id, user)),322 <Error<T>>::AddressNotInAllowlist323 );324 Ok(())325 }326327 /// Changes collection owner to another account328 /// #### Store read/writes329 /// 1 writes330 fn set_owner_internal(331 &mut self,332 caller: T::CrossAccountId,333 new_owner: T::CrossAccountId,334 ) -> DispatchResult {335 self.check_is_owner(&caller)?;336 self.collection.owner = new_owner.as_sub().clone();337 self.save()338 }339}340341#[frame_support::pallet]342pub mod pallet {343 use super::*;344 use pallet_evm::account;345 use dispatch::CollectionDispatch;346 use frame_support::{Blake2_128Concat, pallet_prelude::*, storage::Key, traits::StorageVersion};347 use frame_system::pallet_prelude::*;348 use frame_support::traits::Currency;349 use up_data_structs::{TokenId, mapping::TokenAddressMapping, CollectionFlags};350 use scale_info::TypeInfo;351 use weights::WeightInfo;352353 #[pallet::config]354 pub trait Config:355 frame_system::Config356 + pallet_evm_coder_substrate::Config357 + pallet_evm::Config358 + TypeInfo359 + account::Config360 {361 /// Weight information for functions of this pallet.362 type WeightInfo: WeightInfo;363364 /// Events compatible with [`frame_system::Config::Event`].365 type Event: IsType<<Self as frame_system::Config>::Event> + From<Event<Self>>;366367 /// Handler of accounts and payment.368 type Currency: Currency<Self::AccountId>;369370 /// Set price to create a collection.371 #[pallet::constant]372 type CollectionCreationPrice: Get<373 <<Self as Config>::Currency as Currency<Self::AccountId>>::Balance,374 >;375376 /// Dispatcher of operations on collections.377 type CollectionDispatch: CollectionDispatch<Self>;378379 /// Account which holds the chain's treasury.380 type TreasuryAccountId: Get<Self::AccountId>;381382 /// Address under which the CollectionHelper contract would be available.383 type ContractAddress: Get<H160>;384385 /// Mapper for token addresses to Ethereum addresses.386 type EvmTokenAddressMapping: TokenAddressMapping<H160>;387388 /// Mapper for token addresses to [`CrossAccountId`].389 type CrossTokenAddressMapping: TokenAddressMapping<Self::CrossAccountId>;390 }391392 const STORAGE_VERSION: StorageVersion = StorageVersion::new(1);393394 #[pallet::pallet]395 #[pallet::storage_version(STORAGE_VERSION)]396 #[pallet::generate_store(pub(super) trait Store)]397 pub struct Pallet<T>(_);398399 #[pallet::extra_constants]400 impl<T: Config> Pallet<T> {401 /// Maximum admins per collection.402 pub fn collection_admins_limit() -> u32 {403 COLLECTION_ADMINS_LIMIT404 }405 }406407 #[pallet::event]408 #[pallet::generate_deposit(pub fn deposit_event)]409 pub enum Event<T: Config> {410 /// New collection was created411 CollectionCreated(412 /// Globally unique identifier of newly created collection.413 CollectionId,414 /// [`CollectionMode`] converted into _u8_.415 u8,416 /// Collection owner.417 T::AccountId,418 ),419420 /// New collection was destroyed421 CollectionDestroyed(422 /// Globally unique identifier of collection.423 CollectionId,424 ),425426 /// New item was created.427 ItemCreated(428 /// Id of the collection where item was created.429 CollectionId,430 /// Id of an item. Unique within the collection.431 TokenId,432 /// Owner of newly created item433 T::CrossAccountId,434 /// Always 1 for NFT435 u128,436 ),437438 /// Collection item was burned.439 ItemDestroyed(440 /// Id of the collection where item was destroyed.441 CollectionId,442 /// Identifier of burned NFT.443 TokenId,444 /// Which user has destroyed its tokens.445 T::CrossAccountId,446 /// Amount of token pieces destroed. Always 1 for NFT.447 u128,448 ),449450 /// Item was transferred451 Transfer(452 /// Id of collection to which item is belong.453 CollectionId,454 /// Id of an item.455 TokenId,456 /// Original owner of item.457 T::CrossAccountId,458 /// New owner of item.459 T::CrossAccountId,460 /// Amount of token pieces transfered. Always 1 for NFT.461 u128,462 ),463464 /// Amount pieces of token owned by `sender` was approved for `spender`.465 Approved(466 /// Id of collection to which item is belong.467 CollectionId,468 /// Id of an item.469 TokenId,470 /// Original owner of item.471 T::CrossAccountId,472 /// Id for which the approval was granted.473 T::CrossAccountId,474 /// Amount of token pieces transfered. Always 1 for NFT.475 u128,476 ),477478 /// The colletion property has been added or edited.479 CollectionPropertySet(480 /// Id of collection to which property has been set.481 CollectionId,482 /// The property that was set.483 PropertyKey,484 ),485486 /// The property has been deleted.487 CollectionPropertyDeleted(488 /// Id of collection to which property has been deleted.489 CollectionId,490 /// The property that was deleted.491 PropertyKey,492 ),493494 /// The token property has been added or edited.495 TokenPropertySet(496 /// Identifier of the collection whose token has the property set.497 CollectionId,498 /// The token for which the property was set.499 TokenId,500 /// The property that was set.501 PropertyKey,502 ),503504 /// The token property has been deleted.505 TokenPropertyDeleted(506 /// Identifier of the collection whose token has the property deleted.507 CollectionId,508 /// The token for which the property was deleted.509 TokenId,510 /// The property that was deleted.511 PropertyKey,512 ),513514 /// The token property permission of a collection has been set.515 PropertyPermissionSet(516 /// ID of collection to which property permission has been set.517 CollectionId,518 /// The property permission that was set.519 PropertyKey,520 ),521 }522523 #[pallet::error]524 pub enum Error<T> {525 /// This collection does not exist.526 CollectionNotFound,527 /// Sender parameter and item owner must be equal.528 MustBeTokenOwner,529 /// No permission to perform action530 NoPermission,531 /// Destroying only empty collections is allowed532 CantDestroyNotEmptyCollection,533 /// Collection is not in mint mode.534 PublicMintingNotAllowed,535 /// Address is not in allow list.536 AddressNotInAllowlist,537538 /// Collection name can not be longer than 63 char.539 CollectionNameLimitExceeded,540 /// Collection description can not be longer than 255 char.541 CollectionDescriptionLimitExceeded,542 /// Token prefix can not be longer than 15 char.543 CollectionTokenPrefixLimitExceeded,544 /// Total collections bound exceeded.545 TotalCollectionsLimitExceeded,546 /// Exceeded max admin count547 CollectionAdminCountExceeded,548 /// Collection limit bounds per collection exceeded549 CollectionLimitBoundsExceeded,550 /// Tried to enable permissions which are only permitted to be disabled551 OwnerPermissionsCantBeReverted,552 /// Collection settings not allowing items transferring553 TransferNotAllowed,554 /// Account token limit exceeded per collection555 AccountTokenLimitExceeded,556 /// Collection token limit exceeded557 CollectionTokenLimitExceeded,558 /// Metadata flag frozen559 MetadataFlagFrozen,560561 /// Item does not exist562 TokenNotFound,563 /// Item is balance not enough564 TokenValueTooLow,565 /// Requested value is more than the approved566 ApprovedValueTooLow,567 /// Tried to approve more than owned568 CantApproveMoreThanOwned,569570 /// Can't transfer tokens to ethereum zero address571 AddressIsZero,572573 /// The operation is not supported574 UnsupportedOperation,575576 /// Insufficient funds to perform an action577 NotSufficientFounds,578579 /// User does not satisfy the nesting rule580 UserIsNotAllowedToNest,581 /// Only tokens from specific collections may nest tokens under this one582 SourceCollectionIsNotAllowedToNest,583584 /// Tried to store more data than allowed in collection field585 CollectionFieldSizeExceeded,586587 /// Tried to store more property data than allowed588 NoSpaceForProperty,589590 /// Tried to store more property keys than allowed591 PropertyLimitReached,592593 /// Property key is too long594 PropertyKeyIsTooLong,595596 /// Only ASCII letters, digits, and symbols `_`, `-`, and `.` are allowed597 InvalidCharacterInPropertyKey,598599 /// Empty property keys are forbidden600 EmptyPropertyKey,601602 /// Tried to access an external collection with an internal API603 CollectionIsExternal,604605 /// Tried to access an internal collection with an external API606 CollectionIsInternal,607 }608609 /// Storage of the count of created collections. Essentially contains the last collection ID.610 #[pallet::storage]611 pub type CreatedCollectionCount<T> = StorageValue<Value = CollectionId, QueryKind = ValueQuery>;612613 /// Storage of the count of deleted collections.614 #[pallet::storage]615 pub type DestroyedCollectionCount<T> =616 StorageValue<Value = CollectionId, QueryKind = ValueQuery>;617618 /// Storage of collection info.619 #[pallet::storage]620 pub type CollectionById<T> = StorageMap<621 Hasher = Blake2_128Concat,622 Key = CollectionId,623 Value = Collection<<T as frame_system::Config>::AccountId>,624 QueryKind = OptionQuery,625 >;626627 /// Storage of collection properties.628 #[pallet::storage]629 #[pallet::getter(fn collection_properties)]630 pub type CollectionProperties<T> = StorageMap<631 Hasher = Blake2_128Concat,632 Key = CollectionId,633 Value = Properties,634 QueryKind = ValueQuery,635 OnEmpty = up_data_structs::CollectionProperties,636 >;637638 /// Storage of token property permissions of a collection.639 #[pallet::storage]640 #[pallet::getter(fn property_permissions)]641 pub type CollectionPropertyPermissions<T> = StorageMap<642 Hasher = Blake2_128Concat,643 Key = CollectionId,644 Value = PropertiesPermissionMap,645 QueryKind = ValueQuery,646 >;647648 /// Storage of the amount of collection admins.649 #[pallet::storage]650 pub type AdminAmount<T> = StorageMap<651 Hasher = Blake2_128Concat,652 Key = CollectionId,653 Value = u32,654 QueryKind = ValueQuery,655 >;656657 /// List of collection admins.658 #[pallet::storage]659 pub type IsAdmin<T: Config> = StorageNMap<660 Key = (661 Key<Blake2_128Concat, CollectionId>,662 Key<Blake2_128Concat, T::CrossAccountId>,663 ),664 Value = bool,665 QueryKind = ValueQuery,666 >;667668 /// Allowlisted collection users.669 #[pallet::storage]670 pub type Allowlist<T: Config> = StorageNMap<671 Key = (672 Key<Blake2_128Concat, CollectionId>,673 Key<Blake2_128Concat, T::CrossAccountId>,674 ),675 Value = bool,676 QueryKind = ValueQuery,677 >;678679 /// Not used by code, exists only to provide some types to metadata.680 #[pallet::storage]681 pub type DummyStorageValue<T: Config> = StorageValue<682 Value = (683 CollectionStats,684 CollectionId,685 TokenId,686 TokenChild,687 PhantomType<(688 TokenData<T::CrossAccountId>,689 RpcCollection<T::AccountId>,690 // RMRK691 RmrkCollectionInfo<T::AccountId>,692 RmrkInstanceInfo<T::AccountId>,693 RmrkResourceInfo,694 RmrkPropertyInfo,695 RmrkBaseInfo<T::AccountId>,696 RmrkPartType,697 RmrkBoundedTheme,698 RmrkNftChild,699 )>,700 ),701 QueryKind = OptionQuery,702 >;703704 #[pallet::hooks]705 impl<T: Config> Hooks<BlockNumberFor<T>> for Pallet<T> {706 fn on_runtime_upgrade() -> Weight {707 StorageVersion::new(1).put::<Pallet<T>>();708709 0710 }711 }712}713714impl<T: Config> Pallet<T> {715 /// Enshure that receiver address is correct.716 ///717 /// Ethereum receiver 0x0000000000000000000000000000000000000000 is reserved, and shouldn't own tokens.718 pub fn ensure_correct_receiver(receiver: &T::CrossAccountId) -> DispatchResult {719 ensure!(720 &T::CrossAccountId::from_eth(H160([0; 20])) != receiver,721 <Error<T>>::AddressIsZero722 );723 Ok(())724 }725726 /// Get a vector of collection admins.727 pub fn adminlist(collection: CollectionId) -> Vec<T::CrossAccountId> {728 <IsAdmin<T>>::iter_prefix((collection,))729 .map(|(a, _)| a)730 .collect()731 }732733 /// Get a vector of users allowed to mint tokens.734 pub fn allowlist(collection: CollectionId) -> Vec<T::CrossAccountId> {735 <Allowlist<T>>::iter_prefix((collection,))736 .map(|(a, _)| a)737 .collect()738 }739740 /// Is `user` allowed to mint token in `collection`.741 pub fn allowed(collection: CollectionId, user: T::CrossAccountId) -> bool {742 <Allowlist<T>>::get((collection, user))743 }744745 /// Get statistics of collections.746 pub fn collection_stats() -> CollectionStats {747 let created = <CreatedCollectionCount<T>>::get();748 let destroyed = <DestroyedCollectionCount<T>>::get();749 CollectionStats {750 created: created.0,751 destroyed: destroyed.0,752 alive: created.0 - destroyed.0,753 }754 }755756 /// Get the effective limits for the collection.757 pub fn effective_collection_limits(collection: CollectionId) -> Option<CollectionLimits> {758 let collection = <CollectionById<T>>::get(collection)?;759 let limits = collection.limits;760 let effective_limits = CollectionLimits {761 account_token_ownership_limit: Some(limits.account_token_ownership_limit()),762 sponsored_data_size: Some(limits.sponsored_data_size()),763 sponsored_data_rate_limit: Some(764 limits765 .sponsored_data_rate_limit766 .unwrap_or(SponsoringRateLimit::SponsoringDisabled),767 ),768 token_limit: Some(limits.token_limit()),769 sponsor_transfer_timeout: Some(limits.sponsor_transfer_timeout(770 match collection.mode {771 CollectionMode::NFT => NFT_SPONSOR_TRANSFER_TIMEOUT,772 CollectionMode::Fungible(_) => FUNGIBLE_SPONSOR_TRANSFER_TIMEOUT,773 CollectionMode::ReFungible => REFUNGIBLE_SPONSOR_TRANSFER_TIMEOUT,774 },775 )),776 sponsor_approve_timeout: Some(limits.sponsor_approve_timeout()),777 owner_can_transfer: Some(limits.owner_can_transfer()),778 owner_can_destroy: Some(limits.owner_can_destroy()),779 transfers_enabled: Some(limits.transfers_enabled()),780 };781782 Some(effective_limits)783 }784785 /// Returns information about the `collection` adapted for rpc.786 pub fn rpc_collection(collection: CollectionId) -> Option<RpcCollection<T::AccountId>> {787 let Collection {788 name,789 description,790 owner,791 mode,792 token_prefix,793 sponsorship,794 limits,795 permissions,796 flags,797 } = <CollectionById<T>>::get(collection)?;798799 let token_property_permissions = <CollectionPropertyPermissions<T>>::get(collection)800 .into_iter()801 .map(|(key, permission)| PropertyKeyPermission { key, permission })802 .collect();803804 let properties = <CollectionProperties<T>>::get(collection)805 .into_iter()806 .map(|(key, value)| Property { key, value })807 .collect();808809 let permissions = CollectionPermissions {810 access: Some(permissions.access()),811 mint_mode: Some(permissions.mint_mode()),812 nesting: Some(permissions.nesting().clone()),813 };814815 Some(RpcCollection {816 name: name.into_inner(),817 description: description.into_inner(),818 owner,819 mode,820 token_prefix: token_prefix.into_inner(),821 sponsorship,822 limits,823 permissions,824 token_property_permissions,825 properties,826 read_only: flags.external,827 foreign: flags.foreign,828 })829 }830}831832macro_rules! limit_default {833 ($old:ident, $new:ident, $($field:ident $(($arg:expr))? => $check:expr),* $(,)?) => {{834 $(835 if let Some($new) = $new.$field {836 let $old = $old.$field($($arg)?);837 let _ = $new;838 let _ = $old;839 $check840 } else {841 $new.$field = $old.$field842 }843 )*844 }};845}846macro_rules! limit_default_clone {847 ($old:ident, $new:ident, $($field:ident $(($arg:expr))? => $check:expr),* $(,)?) => {{848 $(849 if let Some($new) = $new.$field.clone() {850 let $old = $old.$field($($arg)?);851 let _ = $new;852 let _ = $old;853 $check854 } else {855 $new.$field = $old.$field.clone()856 }857 )*858 }};859}860861impl<T: Config> Pallet<T> {862 /// Create new collection.863 ///864 /// * `owner` - The owner of the collection.865 /// * `data` - Description of the created collection.866 /// * `flags` - Extra flags to store.867 pub fn init_collection(868 owner: T::CrossAccountId,869 data: CreateCollectionData<T::AccountId>,870 flags: CollectionFlags,871 ) -> Result<CollectionId, DispatchError> {872 {873 ensure!(874 data.token_prefix.len() <= MAX_TOKEN_PREFIX_LENGTH as usize,875 Error::<T>::CollectionTokenPrefixLimitExceeded876 );877 }878879 let created_count = <CreatedCollectionCount<T>>::get()880 .0881 .checked_add(1)882 .ok_or(ArithmeticError::Overflow)?;883 let destroyed_count = <DestroyedCollectionCount<T>>::get().0;884 let id = CollectionId(created_count);885886 // bound Total number of collections887 ensure!(888 created_count - destroyed_count <= COLLECTION_NUMBER_LIMIT,889 <Error<T>>::TotalCollectionsLimitExceeded890 );891892 // =========893894 let collection = Collection {895 owner: owner.as_sub().clone(),896 name: data.name,897 mode: data.mode.clone(),898 description: data.description,899 token_prefix: data.token_prefix,900 sponsorship: data901 .pending_sponsor902 .map(SponsorshipState::Unconfirmed)903 .unwrap_or_default(),904 limits: data905 .limits906 .map(|limits| Self::clamp_limits(data.mode.clone(), &Default::default(), limits))907 .unwrap_or_else(|| Ok(CollectionLimits::default()))?,908 permissions: data909 .permissions910 .map(|permissions| {911 Self::clamp_permissions(data.mode.clone(), &Default::default(), permissions)912 })913 .unwrap_or_else(|| Ok(CollectionPermissions::default()))?,914 flags,915 };916917 let mut collection_properties = up_data_structs::CollectionProperties::get();918 collection_properties919 .try_set_from_iter(data.properties.into_iter())920 .map_err(<Error<T>>::from)?;921922 CollectionProperties::<T>::insert(id, collection_properties);923924 let mut token_props_permissions = PropertiesPermissionMap::new();925 token_props_permissions926 .try_set_from_iter(data.token_property_permissions.into_iter())927 .map_err(<Error<T>>::from)?;928929 CollectionPropertyPermissions::<T>::insert(id, token_props_permissions);930931 // Take a (non-refundable) deposit of collection creation932 {933 let mut imbalance =934 <<<T as Config>::Currency as Currency<T::AccountId>>::PositiveImbalance>::zero();935 imbalance.subsume(936 <<T as Config>::Currency as Currency<T::AccountId>>::deposit_creating(937 &T::TreasuryAccountId::get(),938 T::CollectionCreationPrice::get(),939 ),940 );941 <T as Config>::Currency::settle(942 owner.as_sub(),943 imbalance,944 WithdrawReasons::TRANSFER,945 ExistenceRequirement::KeepAlive,946 )947 .map_err(|_| Error::<T>::NotSufficientFounds)?;948 }949950 <CreatedCollectionCount<T>>::put(created_count);951 <Pallet<T>>::deposit_event(Event::CollectionCreated(952 id,953 data.mode.id(),954 owner.as_sub().clone(),955 ));956 <PalletEvm<T>>::deposit_log(957 erc::CollectionHelpersEvents::CollectionCreated {958 owner: *owner.as_eth(),959 collection_id: eth::collection_id_to_address(id),960 }961 .to_log(T::ContractAddress::get()),962 );963 <CollectionById<T>>::insert(id, collection);964 Ok(id)965 }966967 /// Destroy collection.968 ///969 /// * `collection` - Collection handler.970 /// * `sender` - The owner or administrator of the collection.971 pub fn destroy_collection(972 collection: CollectionHandle<T>,973 sender: &T::CrossAccountId,974 ) -> DispatchResult {975 ensure!(976 collection.limits.owner_can_destroy(),977 <Error<T>>::NoPermission,978 );979 collection.check_is_owner(sender)?;980981 let destroyed_collections = <DestroyedCollectionCount<T>>::get()982 .0983 .checked_add(1)984 .ok_or(ArithmeticError::Overflow)?;985986 // =========987988 <DestroyedCollectionCount<T>>::put(destroyed_collections);989 <CollectionById<T>>::remove(collection.id);990 <AdminAmount<T>>::remove(collection.id);991 let _ = <IsAdmin<T>>::clear_prefix((collection.id,), u32::MAX, None);992 let _ = <Allowlist<T>>::clear_prefix((collection.id,), u32::MAX, None);993 <CollectionProperties<T>>::remove(collection.id);994995 <Pallet<T>>::deposit_event(Event::CollectionDestroyed(collection.id));996 Ok(())997 }998999 /// Set collection property.1000 ///1001 /// * `collection` - Collection handler.1002 /// * `sender` - The owner or administrator of the collection.1003 /// * `property` - The property to set.1004 pub fn set_collection_property(1005 collection: &CollectionHandle<T>,1006 sender: &T::CrossAccountId,1007 property: Property,1008 ) -> DispatchResult {1009 collection.check_is_owner_or_admin(sender)?;10101011 CollectionProperties::<T>::try_mutate(collection.id, |properties| {1012 let property = property.clone();1013 properties.try_set(property.key, property.value)1014 })1015 .map_err(<Error<T>>::from)?;10161017 Self::deposit_event(Event::CollectionPropertySet(collection.id, property.key));10181019 Ok(())1020 }10211022 /// Set scouped collection property.1023 ///1024 /// * `collection_id` - ID of the collection for which the property is being set.1025 /// * `scope` - Property scope.1026 /// * `property` - The property to set.1027 pub fn set_scoped_collection_property(1028 collection_id: CollectionId,1029 scope: PropertyScope,1030 property: Property,1031 ) -> DispatchResult {1032 CollectionProperties::<T>::try_mutate(collection_id, |properties| {1033 properties.try_scoped_set(scope, property.key, property.value)1034 })1035 .map_err(<Error<T>>::from)?;10361037 Ok(())1038 }10391040 /// Set scouped collection properties.1041 ///1042 /// * `collection_id` - ID of the collection for which the properties is being set.1043 /// * `scope` - Property scope.1044 /// * `properties` - The properties to set.1045 pub fn set_scoped_collection_properties(1046 collection_id: CollectionId,1047 scope: PropertyScope,1048 properties: impl Iterator<Item = Property>,1049 ) -> DispatchResult {1050 CollectionProperties::<T>::try_mutate(collection_id, |stored_properties| {1051 stored_properties.try_scoped_set_from_iter(scope, properties)1052 })1053 .map_err(<Error<T>>::from)?;10541055 Ok(())1056 }10571058 /// Set collection properties.1059 ///1060 /// * `collection` - Collection handler.1061 /// * `sender` - The owner or administrator of the collection.1062 /// * `properties` - The properties to set.1063 #[transactional]1064 pub fn set_collection_properties(1065 collection: &CollectionHandle<T>,1066 sender: &T::CrossAccountId,1067 properties: Vec<Property>,1068 ) -> DispatchResult {1069 for property in properties {1070 Self::set_collection_property(collection, sender, property)?;1071 }10721073 Ok(())1074 }10751076 /// Delete collection property.1077 ///1078 /// * `collection` - Collection handler.1079 /// * `sender` - The owner or administrator of the collection.1080 /// * `property` - The property to delete.1081 pub fn delete_collection_property(1082 collection: &CollectionHandle<T>,1083 sender: &T::CrossAccountId,1084 property_key: PropertyKey,1085 ) -> DispatchResult {1086 collection.check_is_owner_or_admin(sender)?;10871088 CollectionProperties::<T>::try_mutate(collection.id, |properties| {1089 properties.remove(&property_key)1090 })1091 .map_err(<Error<T>>::from)?;10921093 Self::deposit_event(Event::CollectionPropertyDeleted(1094 collection.id,1095 property_key,1096 ));10971098 Ok(())1099 }11001101 /// Delete collection properties.1102 ///1103 /// * `collection` - Collection handler.1104 /// * `sender` - The owner or administrator of the collection.1105 /// * `properties` - The properties to delete.1106 #[transactional]1107 pub fn delete_collection_properties(1108 collection: &CollectionHandle<T>,1109 sender: &T::CrossAccountId,1110 property_keys: Vec<PropertyKey>,1111 ) -> DispatchResult {1112 for key in property_keys {1113 Self::delete_collection_property(collection, sender, key)?;1114 }11151116 Ok(())1117 }11181119 /// Set collection propetry permission without any checks.1120 ///1121 /// Used for migrations.1122 ///1123 /// * `collection` - Collection handler.1124 /// * `property_permissions` - Property permissions.1125 pub fn set_property_permission_unchecked(1126 collection: CollectionId,1127 property_permission: PropertyKeyPermission,1128 ) -> DispatchResult {1129 <CollectionPropertyPermissions<T>>::try_mutate(collection, |permissions| {1130 permissions.try_set(property_permission.key, property_permission.permission)1131 })1132 .map_err(<Error<T>>::from)?;1133 Ok(())1134 }11351136 /// Set collection property permission.1137 ///1138 /// * `collection` - Collection handler.1139 /// * `sender` - The owner or administrator of the collection.1140 /// * `property_permission` - Property permission.1141 pub fn set_property_permission(1142 collection: &CollectionHandle<T>,1143 sender: &T::CrossAccountId,1144 property_permission: PropertyKeyPermission,1145 ) -> DispatchResult {1146 Self::set_scoped_property_permission(1147 collection,1148 sender,1149 PropertyScope::None,1150 property_permission,1151 )1152 }11531154 /// Set collection property permission with scope.1155 ///1156 /// * `collection` - Collection handler.1157 /// * `sender` - The owner or administrator of the collection.1158 /// * `scope` - Property scope.1159 /// * `property_permission` - Property permission.1160 pub fn set_scoped_property_permission(1161 collection: &CollectionHandle<T>,1162 sender: &T::CrossAccountId,1163 scope: PropertyScope,1164 property_permission: PropertyKeyPermission,1165 ) -> DispatchResult {1166 collection.check_is_owner_or_admin(sender)?;11671168 let all_permissions = CollectionPropertyPermissions::<T>::get(collection.id);1169 let current_permission = all_permissions.get(&property_permission.key);1170 if matches![1171 current_permission,1172 Some(PropertyPermission { mutable: false, .. })1173 ] {1174 return Err(<Error<T>>::NoPermission.into());1175 }11761177 CollectionPropertyPermissions::<T>::try_mutate(collection.id, |permissions| {1178 let property_permission = property_permission.clone();1179 permissions.try_scoped_set(1180 scope,1181 property_permission.key,1182 property_permission.permission,1183 )1184 })1185 .map_err(<Error<T>>::from)?;11861187 Self::deposit_event(Event::PropertyPermissionSet(1188 collection.id,1189 property_permission.key,1190 ));11911192 Ok(())1193 }11941195 /// Set token property permission.1196 ///1197 /// * `collection` - Collection handler.1198 /// * `sender` - The owner or administrator of the collection.1199 /// * `property_permissions` - Property permissions.1200 #[transactional]1201 pub fn set_token_property_permissions(1202 collection: &CollectionHandle<T>,1203 sender: &T::CrossAccountId,1204 property_permissions: Vec<PropertyKeyPermission>,1205 ) -> DispatchResult {1206 Self::set_scoped_token_property_permissions(1207 collection,1208 sender,1209 PropertyScope::None,1210 property_permissions,1211 )1212 }12131214 /// Set token property permission with scope.1215 ///1216 /// * `collection` - Collection handler.1217 /// * `sender` - The owner or administrator of the collection.1218 /// * `scope` - Property scope.1219 /// * `property_permissions` - Property permissions.1220 #[transactional]1221 pub fn set_scoped_token_property_permissions(1222 collection: &CollectionHandle<T>,1223 sender: &T::CrossAccountId,1224 scope: PropertyScope,1225 property_permissions: Vec<PropertyKeyPermission>,1226 ) -> DispatchResult {1227 for prop_pemission in property_permissions {1228 Self::set_scoped_property_permission(collection, sender, scope, prop_pemission)?;1229 }12301231 Ok(())1232 }12331234 /// Get collection property.1235 pub fn get_collection_property(1236 collection_id: CollectionId,1237 key: &PropertyKey,1238 ) -> Option<PropertyValue> {1239 Self::collection_properties(collection_id).get(key).cloned()1240 }12411242 /// Convert byte vector to property key vector.1243 pub fn bytes_keys_to_property_keys(1244 keys: Vec<Vec<u8>>,1245 ) -> Result<Vec<PropertyKey>, DispatchError> {1246 keys.into_iter()1247 .map(|key| -> Result<PropertyKey, DispatchError> {1248 key.try_into()1249 .map_err(|_| <Error<T>>::PropertyKeyIsTooLong.into())1250 })1251 .collect::<Result<Vec<PropertyKey>, DispatchError>>()1252 }12531254 /// Get properties according to given keys.1255 pub fn filter_collection_properties(1256 collection_id: CollectionId,1257 keys: Option<Vec<PropertyKey>>,1258 ) -> Result<Vec<Property>, DispatchError> {1259 let properties = Self::collection_properties(collection_id);12601261 let properties = keys1262 .map(|keys| {1263 keys.into_iter()1264 .filter_map(|key| {1265 properties.get(&key).map(|value| Property {1266 key,1267 value: value.clone(),1268 })1269 })1270 .collect()1271 })1272 .unwrap_or_else(|| {1273 properties1274 .into_iter()1275 .map(|(key, value)| Property { key, value })1276 .collect()1277 });12781279 Ok(properties)1280 }12811282 /// Get property permissions according to given keys.1283 pub fn filter_property_permissions(1284 collection_id: CollectionId,1285 keys: Option<Vec<PropertyKey>>,1286 ) -> Result<Vec<PropertyKeyPermission>, DispatchError> {1287 let permissions = Self::property_permissions(collection_id);12881289 let key_permissions = keys1290 .map(|keys| {1291 keys.into_iter()1292 .filter_map(|key| {1293 permissions1294 .get(&key)1295 .map(|permission| PropertyKeyPermission {1296 key,1297 permission: permission.clone(),1298 })1299 })1300 .collect()1301 })1302 .unwrap_or_else(|| {1303 permissions1304 .into_iter()1305 .map(|(key, permission)| PropertyKeyPermission { key, permission })1306 .collect()1307 });13081309 Ok(key_permissions)1310 }13111312 /// Toggle `user` participation in the `collection`'s allow list.1313 /// #### Store read/writes1314 /// 1 writes1315 pub fn toggle_allowlist(1316 collection: &CollectionHandle<T>,1317 sender: &T::CrossAccountId,1318 user: &T::CrossAccountId,1319 allowed: bool,1320 ) -> DispatchResult {1321 collection.check_is_owner_or_admin(sender)?;13221323 // =========13241325 if allowed {1326 <Allowlist<T>>::insert((collection.id, user), true);1327 } else {1328 <Allowlist<T>>::remove((collection.id, user));1329 }13301331 Ok(())1332 }13331334 /// Toggle `user` participation in the `collection`'s admin list.1335 /// #### Store read/writes1336 /// 2 writes1337 pub fn toggle_admin(1338 collection: &CollectionHandle<T>,1339 sender: &T::CrossAccountId,1340 user: &T::CrossAccountId,1341 admin: bool,1342 ) -> DispatchResult {1343 collection.check_is_owner(sender)?;13441345 let was_admin = <IsAdmin<T>>::get((collection.id, user));1346 if was_admin == admin {1347 return Ok(());1348 }1349 let amount = <AdminAmount<T>>::get(collection.id);13501351 if admin {1352 let amount = amount1353 .checked_add(1)1354 .ok_or(<Error<T>>::CollectionAdminCountExceeded)?;1355 ensure!(1356 amount <= Self::collection_admins_limit(),1357 <Error<T>>::CollectionAdminCountExceeded,1358 );13591360 // =========13611362 <AdminAmount<T>>::insert(collection.id, amount);1363 <IsAdmin<T>>::insert((collection.id, user), true);1364 } else {1365 <AdminAmount<T>>::insert(collection.id, amount.saturating_sub(1));1366 <IsAdmin<T>>::remove((collection.id, user));1367 }13681369 Ok(())1370 }13711372 /// Merge set fields from `new_limit` to `old_limit`.1373 pub fn clamp_limits(1374 mode: CollectionMode,1375 old_limit: &CollectionLimits,1376 mut new_limit: CollectionLimits,1377 ) -> Result<CollectionLimits, DispatchError> {1378 let limits = old_limit;1379 limit_default!(old_limit, new_limit,1380 account_token_ownership_limit => ensure!(1381 new_limit <= MAX_TOKEN_OWNERSHIP,1382 <Error<T>>::CollectionLimitBoundsExceeded,1383 ),1384 sponsored_data_size => ensure!(1385 new_limit <= CUSTOM_DATA_LIMIT,1386 <Error<T>>::CollectionLimitBoundsExceeded,1387 ),13881389 sponsored_data_rate_limit => {},1390 token_limit => ensure!(1391 old_limit >= new_limit && new_limit > 0,1392 <Error<T>>::CollectionTokenLimitExceeded1393 ),13941395 sponsor_transfer_timeout(match mode {1396 CollectionMode::NFT => NFT_SPONSOR_TRANSFER_TIMEOUT,1397 CollectionMode::Fungible(_) => FUNGIBLE_SPONSOR_TRANSFER_TIMEOUT,1398 CollectionMode::ReFungible => REFUNGIBLE_SPONSOR_TRANSFER_TIMEOUT,1399 }) => ensure!(1400 new_limit <= MAX_SPONSOR_TIMEOUT,1401 <Error<T>>::CollectionLimitBoundsExceeded,1402 ),1403 sponsor_approve_timeout => {},1404 owner_can_transfer => ensure!(1405 !limits.owner_can_transfer_instaled() ||1406 old_limit || !new_limit,1407 <Error<T>>::OwnerPermissionsCantBeReverted,1408 ),1409 owner_can_destroy => ensure!(1410 old_limit || !new_limit,1411 <Error<T>>::OwnerPermissionsCantBeReverted,1412 ),1413 transfers_enabled => {},1414 );1415 Ok(new_limit)1416 }14171418 /// Merge set fields from `new_permission` to `old_permission`.1419 pub fn clamp_permissions(1420 _mode: CollectionMode,1421 old_permission: &CollectionPermissions,1422 mut new_permission: CollectionPermissions,1423 ) -> Result<CollectionPermissions, DispatchError> {1424 limit_default_clone!(old_permission, new_permission,1425 access => {},1426 mint_mode => {},1427 nesting => { /* todo check for permissive, if only it gets out of benchmarks */ },1428 );1429 Ok(new_permission)1430 }1431}14321433/// Indicates unsupported methods by returning [Error::UnsupportedOperation].1434#[macro_export]1435macro_rules! unsupported {1436 ($runtime:path) => {1437 Err($crate::Error::<$runtime>::UnsupportedOperation.into())1438 };1439}14401441/// Return weights for various worst-case operations.1442pub trait CommonWeightInfo<CrossAccountId> {1443 /// Weight of item creation.1444 fn create_item() -> Weight;14451446 /// Weight of items creation.1447 fn create_multiple_items(amount: &[CreateItemData]) -> Weight;14481449 /// Weight of items creation.1450 fn create_multiple_items_ex(cost: &CreateItemExData<CrossAccountId>) -> Weight;14511452 /// The weight of the burning item.1453 fn burn_item() -> Weight;14541455 /// Property setting weight.1456 ///1457 /// * `amount`- The number of properties to set.1458 fn set_collection_properties(amount: u32) -> Weight;14591460 /// Collection property deletion weight.1461 ///1462 /// * `amount`- The number of properties to set.1463 fn delete_collection_properties(amount: u32) -> Weight;14641465 /// Token property setting weight.1466 ///1467 /// * `amount`- The number of properties to set.1468 fn set_token_properties(amount: u32) -> Weight;14691470 /// Token property deletion weight.1471 ///1472 /// * `amount`- The number of properties to delete.1473 fn delete_token_properties(amount: u32) -> Weight;14741475 /// Token property permissions set weight.1476 ///1477 /// * `amount`- The number of property permissions to set.1478 fn set_token_property_permissions(amount: u32) -> Weight;14791480 /// Transfer price of the token or its parts.1481 fn transfer() -> Weight;14821483 /// The price of setting the permission of the operation from another user.1484 fn approve() -> Weight;14851486 /// Transfer price from another user.1487 fn transfer_from() -> Weight;14881489 /// The price of burning a token from another user.1490 fn burn_from() -> Weight;14911492 /// Differs from burn_item in case of Fungible and Refungible, as it should burn1493 /// whole users's balance.1494 ///1495 /// This method shouldn't be used directly, as it doesn't count breadth price, use [burn_recursively](CommonWeightInfo::burn_recursively) instead1496 fn burn_recursively_self_raw() -> Weight;14971498 /// Cost of iterating over `amount` children while burning, without counting child burning itself.1499 ///1500 /// This method shouldn't be used directly, as it doesn't count depth price, use [burn_recursively](CommonWeightInfo::burn_recursively) instead1501 fn burn_recursively_breadth_raw(amount: u32) -> Weight;15021503 /// The price of recursive burning a token.1504 ///1505 /// `max_selfs` - The maximum burning weight of the token itself.1506 /// `max_breadth` - The maximum number of nested tokens to burn.1507 fn burn_recursively(max_selfs: u32, max_breadth: u32) -> Weight {1508 Self::burn_recursively_self_raw()1509 .saturating_mul(max_selfs.max(1) as u64)1510 .saturating_add(Self::burn_recursively_breadth_raw(max_breadth))1511 }15121513 /// The price of retrieving token owner1514 fn token_owner() -> Weight;1515}15161517/// Weight info extension trait for refungible pallet.1518pub trait RefungibleExtensionsWeightInfo {1519 /// Weight of token repartition.1520 fn repartition() -> Weight;1521}15221523/// Common collection operations.1524///1525/// It wraps methods in Fungible, Nonfungible and Refungible pallets1526/// and adds weight info.1527pub trait CommonCollectionOperations<T: Config> {1528 /// Create token.1529 ///1530 /// * `sender` - The user who mint the token and pays for the transaction.1531 /// * `to` - The user who will own the token.1532 /// * `data` - Token data.1533 /// * `nesting_budget` - A budget that can be spent on nesting tokens.1534 fn create_item(1535 &self,1536 sender: T::CrossAccountId,1537 to: T::CrossAccountId,1538 data: CreateItemData,1539 nesting_budget: &dyn Budget,1540 ) -> DispatchResultWithPostInfo;15411542 /// Create multiple tokens.1543 ///1544 /// * `sender` - The user who mint the token and pays for the transaction.1545 /// * `to` - The user who will own the token.1546 /// * `data` - Token data.1547 /// * `nesting_budget` - A budget that can be spent on nesting tokens.1548 fn create_multiple_items(1549 &self,1550 sender: T::CrossAccountId,1551 to: T::CrossAccountId,1552 data: Vec<CreateItemData>,1553 nesting_budget: &dyn Budget,1554 ) -> DispatchResultWithPostInfo;15551556 /// Create multiple tokens.1557 ///1558 /// * `sender` - The user who mint the token and pays for the transaction.1559 /// * `to` - The user who will own the token.1560 /// * `data` - Token data.1561 /// * `nesting_budget` - A budget that can be spent on nesting tokens.1562 fn create_multiple_items_ex(1563 &self,1564 sender: T::CrossAccountId,1565 data: CreateItemExData<T::CrossAccountId>,1566 nesting_budget: &dyn Budget,1567 ) -> DispatchResultWithPostInfo;15681569 /// Burn token.1570 ///1571 /// * `sender` - The user who owns the token.1572 /// * `token` - Token id that will burned.1573 /// * `amount` - The number of parts of the token that will be burned.1574 fn burn_item(1575 &self,1576 sender: T::CrossAccountId,1577 token: TokenId,1578 amount: u128,1579 ) -> DispatchResultWithPostInfo;15801581 /// Burn token and all nested tokens recursievly.1582 ///1583 /// * `sender` - The user who owns the token.1584 /// * `token` - Token id that will burned.1585 /// * `self_budget` - The budget that can be spent on burning tokens.1586 /// * `breadth_budget` - The budget that can be spent on burning nested tokens.1587 fn burn_item_recursively(1588 &self,1589 sender: T::CrossAccountId,1590 token: TokenId,1591 self_budget: &dyn Budget,1592 breadth_budget: &dyn Budget,1593 ) -> DispatchResultWithPostInfo;15941595 /// Set collection properties.1596 ///1597 /// * `sender` - Must be either the owner of the collection or its admin.1598 /// * `properties` - Properties to be set.1599 fn set_collection_properties(1600 &self,1601 sender: T::CrossAccountId,1602 properties: Vec<Property>,1603 ) -> DispatchResultWithPostInfo;16041605 /// Delete collection properties.1606 ///1607 /// * `sender` - Must be either the owner of the collection or its admin.1608 /// * `properties` - The properties to be removed.1609 fn delete_collection_properties(1610 &self,1611 sender: &T::CrossAccountId,1612 property_keys: Vec<PropertyKey>,1613 ) -> DispatchResultWithPostInfo;16141615 /// Set token properties.1616 ///1617 /// The appropriate [`PropertyPermission`] for the token property1618 /// must be set with [`Self::set_token_property_permissions`].1619 ///1620 /// * `sender` - Must be either the owner of the token or its admin.1621 /// * `token_id` - The token for which the properties are being set.1622 /// * `properties` - Properties to be set.1623 /// * `budget` - Budget for setting properties.1624 fn set_token_properties(1625 &self,1626 sender: T::CrossAccountId,1627 token_id: TokenId,1628 properties: Vec<Property>,1629 budget: &dyn Budget,1630 ) -> DispatchResultWithPostInfo;16311632 /// Remove token properties.1633 ///1634 /// The appropriate [`PropertyPermission`] for the token property1635 /// must be set with [`Self::set_token_property_permissions`].1636 ///1637 /// * `sender` - Must be either the owner of the token or its admin.1638 /// * `token_id` - The token for which the properties are being remove.1639 /// * `property_keys` - Keys to remove corresponding properties.1640 /// * `budget` - Budget for removing properties.1641 fn delete_token_properties(1642 &self,1643 sender: T::CrossAccountId,1644 token_id: TokenId,1645 property_keys: Vec<PropertyKey>,1646 budget: &dyn Budget,1647 ) -> DispatchResultWithPostInfo;16481649 /// Set token property permissions.1650 ///1651 /// * `sender` - Must be either the owner of the token or its admin.1652 /// * `token_id` - The token for which the properties are being set.1653 /// * `property_permissions` - Property permissions to be set.1654 /// * `budget` - Budget for setting properties.1655 fn set_token_property_permissions(1656 &self,1657 sender: &T::CrossAccountId,1658 property_permissions: Vec<PropertyKeyPermission>,1659 ) -> DispatchResultWithPostInfo;16601661 /// Transfer amount of token pieces.1662 ///1663 /// * `sender` - Donor user.1664 /// * `to` - Recepient user.1665 /// * `token` - The token of which parts are being sent.1666 /// * `amount` - The number of parts of the token that will be transferred.1667 /// * `budget` - The maximum budget that can be spent on the transfer.1668 fn transfer(1669 &self,1670 sender: T::CrossAccountId,1671 to: T::CrossAccountId,1672 token: TokenId,1673 amount: u128,1674 budget: &dyn Budget,1675 ) -> DispatchResultWithPostInfo;16761677 /// Grant access to another account to transfer parts of the token owned by the calling user via [Self::transfer_from].1678 ///1679 /// * `sender` - The user who grants access to the token.1680 /// * `spender` - The user to whom the rights are granted.1681 /// * `token` - The token to which access is granted.1682 /// * `amount` - The amount of pieces that another user can dispose of.1683 fn approve(1684 &self,1685 sender: T::CrossAccountId,1686 spender: T::CrossAccountId,1687 token: TokenId,1688 amount: u128,1689 ) -> DispatchResultWithPostInfo;16901691 /// Send parts of a token owned by another user.1692 ///1693 /// Before calling this method, you must grant rights to the calling user via [`Self::approve`].1694 ///1695 /// * `sender` - The user who must have access to the token (see [`Self::approve`]).1696 /// * `from` - The user who owns the token.1697 /// * `to` - Recepient user.1698 /// * `token` - The token of which parts are being sent.1699 /// * `amount` - The number of parts of the token that will be transferred.1700 /// * `budget` - The maximum budget that can be spent on the transfer.1701 fn transfer_from(1702 &self,1703 sender: T::CrossAccountId,1704 from: T::CrossAccountId,1705 to: T::CrossAccountId,1706 token: TokenId,1707 amount: u128,1708 budget: &dyn Budget,1709 ) -> DispatchResultWithPostInfo;17101711 /// Burn parts of a token owned by another user.1712 ///1713 /// Before calling this method, you must grant rights to the calling user via [`Self::approve`].1714 ///1715 /// * `sender` - The user who must have access to the token (see [`Self::approve`]).1716 /// * `from` - The user who owns the token.1717 /// * `token` - The token of which parts are being sent.1718 /// * `amount` - The number of parts of the token that will be transferred.1719 /// * `budget` - The maximum budget that can be spent on the burn.1720 fn burn_from(1721 &self,1722 sender: T::CrossAccountId,1723 from: T::CrossAccountId,1724 token: TokenId,1725 amount: u128,1726 budget: &dyn Budget,1727 ) -> DispatchResultWithPostInfo;17281729 /// Check permission to nest token.1730 ///1731 /// * `sender` - The user who initiated the check.1732 /// * `from` - The token that is checked for embedding.1733 /// * `under` - Token under which to check.1734 /// * `budget` - The maximum budget that can be spent on the check.1735 fn check_nesting(1736 &self,1737 sender: T::CrossAccountId,1738 from: (CollectionId, TokenId),1739 under: TokenId,1740 budget: &dyn Budget,1741 ) -> DispatchResult;17421743 /// Nest one token into another.1744 ///1745 /// * `under` - Token holder.1746 /// * `to_nest` - Nested token.1747 fn nest(&self, under: TokenId, to_nest: (CollectionId, TokenId));17481749 /// Unnest token.1750 ///1751 /// * `under` - Token holder.1752 /// * `to_nest` - Token to unnest.1753 fn unnest(&self, under: TokenId, to_nest: (CollectionId, TokenId));17541755 /// Get all user tokens.1756 ///1757 /// * `account` - Account for which you need to get tokens.1758 fn account_tokens(&self, account: T::CrossAccountId) -> Vec<TokenId>;17591760 /// Get all the tokens in the collection.1761 fn collection_tokens(&self) -> Vec<TokenId>;17621763 /// Check if the token exists.1764 ///1765 /// * `token` - Id token to check.1766 fn token_exists(&self, token: TokenId) -> bool;17671768 /// Get the id of the last minted token.1769 fn last_token_id(&self) -> TokenId;17701771 /// Get the owner of the token.1772 ///1773 /// * `token` - The token for which you need to find out the owner.1774 fn token_owner(&self, token: TokenId) -> Option<T::CrossAccountId>;17751776 /// Returns 10 tokens owners in no particular order.1777 ///1778 /// * `token` - The token for which you need to find out the owners.1779 fn token_owners(&self, token: TokenId) -> Vec<T::CrossAccountId>;17801781 /// Get the value of the token property by key.1782 ///1783 /// * `token` - Token with the property to get.1784 /// * `key` - Property name.1785 fn token_property(&self, token_id: TokenId, key: &PropertyKey) -> Option<PropertyValue>;17861787 /// Get a set of token properties by key vector.1788 ///1789 /// * `token` - Token with the property to get.1790 /// * `keys` - Vector of property keys. If this parameter is [None](sp_std::result::Result),1791 /// then all properties are returned.1792 fn token_properties(&self, token: TokenId, keys: Option<Vec<PropertyKey>>) -> Vec<Property>;17931794 /// Amount of unique collection tokens1795 fn total_supply(&self) -> u32;17961797 /// Amount of different tokens account has.1798 ///1799 /// * `account` - The account for which need to get the balance.1800 fn account_balance(&self, account: T::CrossAccountId) -> u32;18011802 /// Amount of specific token account have.1803 fn balance(&self, account: T::CrossAccountId, token: TokenId) -> u128;18041805 /// Amount of token pieces1806 fn total_pieces(&self, token: TokenId) -> Option<u128>;18071808 /// Get the number of parts of the token that a trusted user can manage.1809 ///1810 /// * `sender` - Trusted user.1811 /// * `spender` - Owner of the token.1812 /// * `token` - The token for which to get the value.1813 fn allowance(1814 &self,1815 sender: T::CrossAccountId,1816 spender: T::CrossAccountId,1817 token: TokenId,1818 ) -> u128;18191820 /// Get extension for RFT collection.1821 fn refungible_extensions(&self) -> Option<&dyn RefungibleExtensions<T>>;1822}18231824/// Extension for RFT collection.1825pub trait RefungibleExtensions<T>1826where1827 T: Config,1828{1829 /// Change the number of parts of the token.1830 ///1831 /// When the value changes down, this function is equivalent to burning parts of the token.1832 ///1833 /// * `sender` - The user calling the repartition operation. Must be the owner of the token.1834 /// * `token` - The token for which you want to change the number of parts.1835 /// * `amount` - The new value of the parts of the token.1836 fn repartition(1837 &self,1838 sender: &T::CrossAccountId,1839 token: TokenId,1840 amount: u128,1841 ) -> DispatchResultWithPostInfo;1842}18431844/// Merge [`DispatchResult`] with [`Weight`] into [`DispatchResultWithPostInfo`].1845///1846/// Used for [`CommonCollectionOperations`] implementations and flexible enough to do so.1847pub fn with_weight(res: DispatchResult, weight: Weight) -> DispatchResultWithPostInfo {1848 let post_info = PostDispatchInfo {1849 actual_weight: Some(weight),1850 pays_fee: Pays::Yes,1851 };1852 match res {1853 Ok(()) => Ok(post_info),1854 Err(error) => Err(DispatchErrorWithPostInfo { post_info, error }),1855 }1856}18571858impl<T: Config> From<PropertiesError> for Error<T> {1859 fn from(error: PropertiesError) -> Self {1860 match error {1861 PropertiesError::NoSpaceForProperty => Self::NoSpaceForProperty,1862 PropertiesError::PropertyLimitReached => Self::PropertyLimitReached,1863 PropertiesError::InvalidCharacterInPropertyKey => Self::InvalidCharacterInPropertyKey,1864 PropertiesError::PropertyKeyIsTooLong => Self::PropertyKeyIsTooLong,1865 PropertiesError::EmptyPropertyKey => Self::EmptyPropertyKey,1866 }1867 }1868}pallets/foreign-assets/src/benchmarking.rsdiffbeforeafterboth--- a/pallets/foreign-assets/src/benchmarking.rs
+++ b/pallets/foreign-assets/src/benchmarking.rs
@@ -16,11 +16,10 @@
#![allow(missing_docs)]
-use super::{Config, Pallet};
+use super::{Config, Pallet, Call};
use frame_benchmarking::{benchmarks, account};
use frame_system::RawOrigin;
use crate::AssetMetadata;
-use crate::Pallet as ForeignAssets;
use xcm::opaque::latest::Junction::Parachain;
use xcm::VersionedMultiLocation;
use frame_support::{
@@ -30,7 +29,6 @@
benchmarks! {
register_foreign_asset {
- let origin: RawOrigin<T::AccountId> = frame_system::RawOrigin::Root;
let owner: T::AccountId = account("user", 0, 1);
let location: VersionedMultiLocation = VersionedMultiLocation::from(Parachain(1000).into());
let metadata: AssetMetadata<<<T as Config>::Currency as Currency<<T as frame_system::Config>::AccountId>>::Balance> = AssetMetadata{
@@ -44,12 +42,9 @@
balance = balance * balance;
<T as Config>::Currency::make_free_balance_be(&owner,
balance);
- }: {
- ForeignAssets::<T>::register_foreign_asset(origin.into(), owner, Box::new(location), Box::new(metadata))?
- }
+ }: _(RawOrigin::Root, owner, Box::new(location), Box::new(metadata))
update_foreign_asset {
- let origin: RawOrigin<T::AccountId> = frame_system::RawOrigin::Root;
let owner: T::AccountId = account("user", 0, 1);
let location: VersionedMultiLocation = VersionedMultiLocation::from(Parachain(2000).into());
let metadata: AssetMetadata<<<T as Config>::Currency as Currency<<T as frame_system::Config>::AccountId>>::Balance> = AssetMetadata{
@@ -68,9 +63,6 @@
4_000_000_000u32.into();
balance = balance * balance;
<T as Config>::Currency::make_free_balance_be(&owner, balance);
- ForeignAssets::<T>::register_foreign_asset(origin.clone().into(), owner, Box::new(location.clone()), Box::new(metadata))?;
-
- }: {
- ForeignAssets::<T>::update_foreign_asset(origin.into(), 0, Box::new(location), Box::new(metadata2))?
- }
+ Pallet::<T>::register_foreign_asset(RawOrigin::Root.into(), owner, Box::new(location.clone()), Box::new(metadata))?;
+ }: _(RawOrigin::Root, 0, Box::new(location), Box::new(metadata2))
}
pallets/foreign-assets/src/weights.rsdiffbeforeafterboth--- a/pallets/foreign-assets/src/weights.rs
+++ b/pallets/foreign-assets/src/weights.rs
@@ -1,43 +1,94 @@
+// Template adopted from https://github.com/paritytech/substrate/blob/master/.maintain/frame-weight-template.hbs
+//! Autogenerated weights for pallet_foreign_assets
+//!
+//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev
+//! DATE: 2022-09-16, 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-foreign-assets
+// --wasm-execution
+// compiled
+// --extrinsic
+// *
+// --template
+// .maintain/frame-weight-template.hbs
+// --steps=50
+// --repeat=80
+// --heap-pages=4096
+// --output=./pallets/foreign-assets/src/weights.rs
+
#![cfg_attr(rustfmt, rustfmt_skip)]
#![allow(unused_parens)]
#![allow(unused_imports)]
+#![allow(missing_docs)]
#![allow(clippy::unnecessary_cast)]
use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}};
use sp_std::marker::PhantomData;
-/// Weight functions needed for module_asset_registry.
+/// Weight functions needed for pallet_foreign_assets.
pub trait WeightInfo {
fn register_foreign_asset() -> Weight;
fn update_foreign_asset() -> Weight;
}
-/// Weights for pallet_fungible using the Substrate node and recommended hardware.
+/// Weights for pallet_foreign_assets using the Substrate node and recommended hardware.
pub struct SubstrateWeight<T>(PhantomData<T>);
impl<T: frame_system::Config> WeightInfo for SubstrateWeight<T> {
+ // Storage: Common CreatedCollectionCount (r:1 w:1)
+ // Storage: Common DestroyedCollectionCount (r:1 w:0)
+ // Storage: System Account (r:2 w:2)
+ // Storage: ForeignAssets NextForeignAssetId (r:1 w:1)
+ // Storage: ForeignAssets LocationToCurrencyIds (r:1 w:1)
+ // Storage: ForeignAssets ForeignAssetLocations (r:1 w:1)
+ // Storage: ForeignAssets AssetMetadatas (r:1 w:1)
+ // Storage: ForeignAssets AssetBinding (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)
fn register_foreign_asset() -> Weight {
- (29_819_000 as Weight)
- .saturating_add(T::DbWeight::get().reads(2 as Weight))
- .saturating_add(T::DbWeight::get().writes(3 as Weight))
+ (52_161_000 as Weight)
+ .saturating_add(T::DbWeight::get().reads(9 as Weight))
+ .saturating_add(T::DbWeight::get().writes(11 as Weight))
}
+ // Storage: ForeignAssets ForeignAssetLocations (r:1 w:1)
+ // Storage: ForeignAssets AssetMetadatas (r:1 w:1)
fn update_foreign_asset() -> Weight {
- (25_119_000 as Weight)
- .saturating_add(T::DbWeight::get().reads(1 as Weight))
- .saturating_add(T::DbWeight::get().writes(1 as Weight))
+ (19_111_000 as Weight)
+ .saturating_add(T::DbWeight::get().reads(2 as Weight))
+ .saturating_add(T::DbWeight::get().writes(2 as Weight))
}
}
// 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: ForeignAssets NextForeignAssetId (r:1 w:1)
+ // Storage: ForeignAssets LocationToCurrencyIds (r:1 w:1)
+ // Storage: ForeignAssets ForeignAssetLocations (r:1 w:1)
+ // Storage: ForeignAssets AssetMetadatas (r:1 w:1)
+ // Storage: ForeignAssets AssetBinding (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)
fn register_foreign_asset() -> Weight {
- (29_819_000 as Weight)
- .saturating_add(RocksDbWeight::get().reads(2 as Weight))
- .saturating_add(RocksDbWeight::get().writes(3 as Weight))
+ (52_161_000 as Weight)
+ .saturating_add(RocksDbWeight::get().reads(9 as Weight))
+ .saturating_add(RocksDbWeight::get().writes(11 as Weight))
}
+ // Storage: ForeignAssets ForeignAssetLocations (r:1 w:1)
+ // Storage: ForeignAssets AssetMetadatas (r:1 w:1)
fn update_foreign_asset() -> Weight {
- (25_119_000 as Weight)
- .saturating_add(RocksDbWeight::get().reads(1 as Weight))
- .saturating_add(RocksDbWeight::get().writes(1 as Weight))
+ (19_111_000 as Weight)
+ .saturating_add(RocksDbWeight::get().reads(2 as Weight))
+ .saturating_add(RocksDbWeight::get().writes(2 as Weight))
}
-}
\ No newline at end of file
+}