difftreelog
style reformat code
in: master
19 files changed
client/rpc/src/lib.rsdiffbeforeafterboth--- a/client/rpc/src/lib.rs
+++ b/client/rpc/src/lib.rs
@@ -30,8 +30,7 @@
// RMRK
use rmrk_rpc::RmrkApi as RmrkRuntimeApi;
use up_data_structs::{
- RmrkCollectionId, RmrkNftId, RmrkBaseId, RmrkNftChild, RmrkThemeName,
- RmrkResourceId,
+ RmrkCollectionId, RmrkNftId, RmrkBaseId, RmrkNftChild, RmrkThemeName, RmrkResourceId,
};
pub use rmrk_unique_rpc::RmrkApi;
node/cli/src/service.rsdiffbeforeafterboth--- a/node/cli/src/service.rs
+++ b/node/cli/src/service.rs
@@ -364,7 +364,8 @@
RmrkBaseInfo<AccountId>,
RmrkPartType,
RmrkTheme,
- >*/ + substrate_frame_rpc_system::AccountNonceApi<Block, AccountId, Index>
+ >*/
+ + substrate_frame_rpc_system::AccountNonceApi<Block, AccountId, Index>
+ sp_api::Metadata<Block>
+ sp_offchain::OffchainWorkerApi<Block>
+ cumulus_primitives_core::CollectCollationInfo<Block>,
@@ -656,7 +657,8 @@
RmrkBaseInfo<AccountId>,
RmrkPartType,
RmrkTheme,
- >*/ + substrate_frame_rpc_system::AccountNonceApi<Block, AccountId, Index>
+ >*/
+ + substrate_frame_rpc_system::AccountNonceApi<Block, AccountId, Index>
+ sp_api::Metadata<Block>
+ sp_offchain::OffchainWorkerApi<Block>
+ cumulus_primitives_core::CollectCollationInfo<Block>
@@ -800,7 +802,8 @@
RmrkBaseInfo<AccountId>,
RmrkPartType,
RmrkTheme,
- >*/ + substrate_frame_rpc_system::AccountNonceApi<Block, AccountId, Index>
+ >*/
+ + substrate_frame_rpc_system::AccountNonceApi<Block, AccountId, Index>
+ sp_api::Metadata<Block>
+ sp_offchain::OffchainWorkerApi<Block>
+ cumulus_primitives_core::CollectCollationInfo<Block>
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#![cfg_attr(not(feature = "std"), no_std)]1819extern crate alloc;2021use core::ops::{Deref, DerefMut};22use pallet_evm_coder_substrate::{SubstrateRecorder, WithRecorder};23use sp_std::vec::Vec;24use pallet_evm::account::CrossAccountId;25use frame_support::{26 dispatch::{DispatchErrorWithPostInfo, DispatchResultWithPostInfo, Weight, PostDispatchInfo},27 ensure,28 traits::{Imbalance, Get, Currency, WithdrawReasons, ExistenceRequirement},29 BoundedVec,30 weights::Pays,31 transactional,32};33use pallet_evm::GasWeightMapping;34use up_data_structs::{35 COLLECTION_NUMBER_LIMIT,36 Collection,37 RpcCollection,38 CollectionId,39 CreateItemData,40 MAX_TOKEN_PREFIX_LENGTH,41 COLLECTION_ADMINS_LIMIT,42 TokenId,43 CollectionStats,44 MAX_TOKEN_OWNERSHIP,45 CollectionMode,46 NFT_SPONSOR_TRANSFER_TIMEOUT,47 FUNGIBLE_SPONSOR_TRANSFER_TIMEOUT,48 REFUNGIBLE_SPONSOR_TRANSFER_TIMEOUT,49 MAX_SPONSOR_TIMEOUT,50 CUSTOM_DATA_LIMIT,51 CollectionLimits,52 CreateCollectionData,53 SponsorshipState,54 CreateItemExData,55 SponsoringRateLimit,56 budget::Budget,57 COLLECTION_FIELD_LIMIT,58 PhantomType,59 Property,60 Properties,61 PropertiesPermissionMap,62 PropertyKey,63 PropertyValue,64 PropertyPermission,65 PropertiesError,66 PropertyKeyPermission,67 TokenData,68 TrySetProperty,69 PropertyScope,70 // RMRK71 RmrkCollectionInfo,72 RmrkInstanceInfo,73 RmrkResourceInfo,74 RmrkPropertyInfo,75 RmrkBaseInfo,76 RmrkPartType,77 RmrkTheme,78 RmrkNftChild,79 CollectionPermissions,80 SchemaVersion,81};8283pub use pallet::*;84use sp_core::H160;85use sp_runtime::{ArithmeticError, DispatchError, DispatchResult};86#[cfg(feature = "runtime-benchmarks")]87pub mod benchmarking;88pub mod dispatch;89pub mod erc;90pub mod eth;91pub mod weights;9293pub type SelfWeightOf<T> = <T as Config>::WeightInfo;9495#[must_use = "Should call submit_logs or save, otherwise some data will be lost for evm side"]96pub struct CollectionHandle<T: Config> {97 pub id: CollectionId,98 collection: Collection<T::AccountId>,99 pub recorder: SubstrateRecorder<T>,100}101impl<T: Config> WithRecorder<T> for CollectionHandle<T> {102 fn recorder(&self) -> &SubstrateRecorder<T> {103 &self.recorder104 }105 fn into_recorder(self) -> SubstrateRecorder<T> {106 self.recorder107 }108}109impl<T: Config> CollectionHandle<T> {110 pub fn new_with_gas_limit(id: CollectionId, gas_limit: u64) -> Option<Self> {111 <CollectionById<T>>::get(id).map(|collection| Self {112 id,113 collection,114 recorder: SubstrateRecorder::new(gas_limit),115 })116 }117118 pub fn new_with_recorder(id: CollectionId, recorder: SubstrateRecorder<T>) -> Option<Self> {119 <CollectionById<T>>::get(id).map(|collection| Self {120 id,121 collection,122 recorder,123 })124 }125126 pub fn new(id: CollectionId) -> Option<Self> {127 Self::new_with_gas_limit(id, u64::MAX)128 }129 pub fn try_get(id: CollectionId) -> Result<Self, DispatchError> {130 Ok(Self::new(id).ok_or(<Error<T>>::CollectionNotFound)?)131 }132 pub fn consume_store_reads(&self, reads: u64) -> evm_coder::execution::Result<()> {133 self.recorder134 .consume_gas(T::GasWeightMapping::weight_to_gas(135 <T as frame_system::Config>::DbWeight::get()136 .read137 .saturating_mul(reads),138 ))139 }140 pub fn consume_store_writes(&self, writes: u64) -> evm_coder::execution::Result<()> {141 self.recorder142 .consume_gas(T::GasWeightMapping::weight_to_gas(143 <T as frame_system::Config>::DbWeight::get()144 .write145 .saturating_mul(writes),146 ))147 }148 pub fn save(self) -> DispatchResult {149 <CollectionById<T>>::insert(self.id, self.collection);150 Ok(())151 }152153 pub fn set_sponsor(&mut self, sponsor: T::AccountId) {154 self.collection.sponsorship = SponsorshipState::Unconfirmed(sponsor);155 }156157 pub fn confirm_sponsorship(&mut self, sender: &T::AccountId) -> bool {158 if self.collection.sponsorship.pending_sponsor() != Some(sender) {159 return false;160 };161162 self.collection.sponsorship = SponsorshipState::Confirmed(sender.clone());163 true164 }165}166impl<T: Config> Deref for CollectionHandle<T> {167 type Target = Collection<T::AccountId>;168169 fn deref(&self) -> &Self::Target {170 &self.collection171 }172}173174impl<T: Config> DerefMut for CollectionHandle<T> {175 fn deref_mut(&mut self) -> &mut Self::Target {176 &mut self.collection177 }178}179180impl<T: Config> CollectionHandle<T> {181 pub fn check_is_owner(&self, subject: &T::CrossAccountId) -> DispatchResult {182 ensure!(*subject.as_sub() == self.owner, <Error<T>>::NoPermission);183 Ok(())184 }185 pub fn is_owner_or_admin(&self, subject: &T::CrossAccountId) -> bool {186 *subject.as_sub() == self.owner || <IsAdmin<T>>::get((self.id, subject))187 }188 pub fn check_is_owner_or_admin(&self, subject: &T::CrossAccountId) -> DispatchResult {189 ensure!(self.is_owner_or_admin(subject), <Error<T>>::NoPermission);190 Ok(())191 }192 pub fn ignores_allowance(&self, user: &T::CrossAccountId) -> bool {193 self.limits.owner_can_transfer() && self.is_owner_or_admin(user)194 }195 pub fn ignores_owned_amount(&self, user: &T::CrossAccountId) -> bool {196 self.limits.owner_can_transfer() && self.is_owner_or_admin(user)197 }198 pub fn check_allowlist(&self, user: &T::CrossAccountId) -> DispatchResult {199 ensure!(200 <Allowlist<T>>::get((self.id, user)),201 <Error<T>>::AddressNotInAllowlist202 );203 Ok(())204 }205}206207#[frame_support::pallet]208pub mod pallet {209 use super::*;210 use pallet_evm::account;211 use dispatch::CollectionDispatch;212 use frame_support::{Blake2_128Concat, pallet_prelude::*, storage::Key, traits::StorageVersion};213 use frame_system::pallet_prelude::*;214 use frame_support::traits::Currency;215 use up_data_structs::{TokenId, mapping::TokenAddressMapping};216 use scale_info::TypeInfo;217 use weights::WeightInfo;218219 #[pallet::config]220 pub trait Config:221 frame_system::Config + pallet_evm_coder_substrate::Config + TypeInfo + account::Config222 {223 type WeightInfo: WeightInfo;224 type Event: IsType<<Self as frame_system::Config>::Event> + From<Event<Self>>;225226 type Currency: Currency<Self::AccountId>;227228 #[pallet::constant]229 type CollectionCreationPrice: Get<230 <<Self as Config>::Currency as Currency<Self::AccountId>>::Balance,231 >;232 type CollectionDispatch: CollectionDispatch<Self>;233234 type TreasuryAccountId: Get<Self::AccountId>;235236 type EvmTokenAddressMapping: TokenAddressMapping<H160>;237 type CrossTokenAddressMapping: TokenAddressMapping<Self::CrossAccountId>;238 }239240 const STORAGE_VERSION: StorageVersion = StorageVersion::new(1);241242 #[pallet::pallet]243 #[pallet::storage_version(STORAGE_VERSION)]244 #[pallet::generate_store(pub(super) trait Store)]245 pub struct Pallet<T>(_);246247 #[pallet::extra_constants]248 impl<T: Config> Pallet<T> {249 pub fn collection_admins_limit() -> u32 {250 COLLECTION_ADMINS_LIMIT251 }252 }253254 #[pallet::event]255 #[pallet::generate_deposit(pub fn deposit_event)]256 pub enum Event<T: Config> {257 /// New collection was created258 ///259 /// # Arguments260 ///261 /// * collection_id: Globally unique identifier of newly created collection.262 ///263 /// * mode: [CollectionMode] converted into u8.264 ///265 /// * account_id: Collection owner.266 CollectionCreated(CollectionId, u8, T::AccountId),267268 /// New collection was destroyed269 ///270 /// # Arguments271 ///272 /// * collection_id: Globally unique identifier of collection.273 CollectionDestroyed(CollectionId),274275 /// New item was created.276 ///277 /// # Arguments278 ///279 /// * collection_id: Id of the collection where item was created.280 ///281 /// * item_id: Id of an item. Unique within the collection.282 ///283 /// * recipient: Owner of newly created item284 ///285 /// * amount: Always 1 for NFT286 ItemCreated(CollectionId, TokenId, T::CrossAccountId, u128),287288 /// Collection item was burned.289 ///290 /// # Arguments291 ///292 /// * collection_id.293 ///294 /// * item_id: Identifier of burned NFT.295 ///296 /// * owner: which user has destroyed its tokens297 ///298 /// * amount: Always 1 for NFT299 ItemDestroyed(CollectionId, TokenId, T::CrossAccountId, u128),300301 /// Item was transferred302 ///303 /// * collection_id: Id of collection to which item is belong304 ///305 /// * item_id: Id of an item306 ///307 /// * sender: Original owner of item308 ///309 /// * recipient: New owner of item310 ///311 /// * amount: Always 1 for NFT312 Transfer(313 CollectionId,314 TokenId,315 T::CrossAccountId,316 T::CrossAccountId,317 u128,318 ),319320 /// * collection_id321 ///322 /// * item_id323 ///324 /// * sender325 ///326 /// * spender327 ///328 /// * amount329 Approved(330 CollectionId,331 TokenId,332 T::CrossAccountId,333 T::CrossAccountId,334 u128,335 ),336337 CollectionPropertySet(CollectionId, PropertyKey),338339 CollectionPropertyDeleted(CollectionId, PropertyKey),340341 TokenPropertySet(CollectionId, TokenId, PropertyKey),342343 TokenPropertyDeleted(CollectionId, TokenId, PropertyKey),344345 PropertyPermissionSet(CollectionId, PropertyKey),346 }347348 #[pallet::error]349 pub enum Error<T> {350 /// This collection does not exist.351 CollectionNotFound,352 /// Sender parameter and item owner must be equal.353 MustBeTokenOwner,354 /// No permission to perform action355 NoPermission,356 /// Destroying only empty collections is allowed357 CantDestroyNotEmptyCollection,358 /// Collection is not in mint mode.359 PublicMintingNotAllowed,360 /// Address is not in allow list.361 AddressNotInAllowlist,362363 /// Collection name can not be longer than 63 char.364 CollectionNameLimitExceeded,365 /// Collection description can not be longer than 255 char.366 CollectionDescriptionLimitExceeded,367 /// Token prefix can not be longer than 15 char.368 CollectionTokenPrefixLimitExceeded,369 /// Total collections bound exceeded.370 TotalCollectionsLimitExceeded,371 /// Exceeded max admin count372 CollectionAdminCountExceeded,373 /// Collection limit bounds per collection exceeded374 CollectionLimitBoundsExceeded,375 /// Tried to enable permissions which are only permitted to be disabled376 OwnerPermissionsCantBeReverted,377 /// Collection settings not allowing items transferring378 TransferNotAllowed,379 /// Account token limit exceeded per collection380 AccountTokenLimitExceeded,381 /// Collection token limit exceeded382 CollectionTokenLimitExceeded,383 /// Metadata flag frozen384 MetadataFlagFrozen,385386 /// Item not exists.387 TokenNotFound,388 /// Item balance not enough.389 TokenValueTooLow,390 /// Requested value more than approved.391 ApprovedValueTooLow,392 /// Tried to approve more than owned393 CantApproveMoreThanOwned,394395 /// Can't transfer tokens to ethereum zero address396 AddressIsZero,397 /// Target collection doesn't supports this operation398 UnsupportedOperation,399400 /// Not sufficient founds to perform action401 NotSufficientFounds,402403 /// Collection has nesting disabled404 NestingIsDisabled,405 /// Only owner may nest tokens under this collection406 OnlyOwnerAllowedToNest,407 /// Only tokens from specific collections may nest tokens under this408 SourceCollectionIsNotAllowedToNest,409410 /// Tried to store more data than allowed in collection field411 CollectionFieldSizeExceeded,412413 /// Tried to store more property data than allowed414 NoSpaceForProperty,415416 /// Tried to store more property keys than allowed417 PropertyLimitReached,418419 /// Property key is too long420 PropertyKeyIsTooLong,421422 /// Only ASCII letters, digits, and '_', '-' are allowed423 InvalidCharacterInPropertyKey,424425 /// Empty property keys are forbidden426 EmptyPropertyKey,427 }428429 #[pallet::storage]430 pub type CreatedCollectionCount<T> = StorageValue<Value = CollectionId, QueryKind = ValueQuery>;431 #[pallet::storage]432 pub type DestroyedCollectionCount<T> =433 StorageValue<Value = CollectionId, QueryKind = ValueQuery>;434435 /// Collection info436 #[pallet::storage]437 pub type CollectionById<T> = StorageMap<438 Hasher = Blake2_128Concat,439 Key = CollectionId,440 Value = Collection<<T as frame_system::Config>::AccountId>,441 QueryKind = OptionQuery,442 >;443444 /// Collection properties445 #[pallet::storage]446 #[pallet::getter(fn collection_properties)]447 pub type CollectionProperties<T> = StorageMap<448 Hasher = Blake2_128Concat,449 Key = CollectionId,450 Value = Properties,451 QueryKind = ValueQuery,452 OnEmpty = up_data_structs::CollectionProperties,453 >;454455 #[pallet::storage]456 #[pallet::getter(fn property_permissions)]457 pub type CollectionPropertyPermissions<T> = StorageMap<458 Hasher = Blake2_128Concat,459 Key = CollectionId,460 Value = PropertiesPermissionMap,461 QueryKind = ValueQuery,462 >;463464 #[pallet::storage]465 pub type AdminAmount<T> = StorageMap<466 Hasher = Blake2_128Concat,467 Key = CollectionId,468 Value = u32,469 QueryKind = ValueQuery,470 >;471472 /// List of collection admins473 #[pallet::storage]474 pub type IsAdmin<T: Config> = StorageNMap<475 Key = (476 Key<Blake2_128Concat, CollectionId>,477 Key<Blake2_128Concat, T::CrossAccountId>,478 ),479 Value = bool,480 QueryKind = ValueQuery,481 >;482483 /// Allowlisted collection users484 #[pallet::storage]485 pub type Allowlist<T: Config> = StorageNMap<486 Key = (487 Key<Blake2_128Concat, CollectionId>,488 Key<Blake2_128Concat, T::CrossAccountId>,489 ),490 Value = bool,491 QueryKind = ValueQuery,492 >;493494 /// Not used by code, exists only to provide some types to metadata495 #[pallet::storage]496 pub type DummyStorageValue<T: Config> = StorageValue<497 Value = (498 CollectionStats,499 CollectionId,500 TokenId,501 PhantomType<(502 TokenData<T::CrossAccountId>,503 RpcCollection<T::AccountId>,504505 // RMRK506 RmrkCollectionInfo<T::AccountId>,507 RmrkInstanceInfo<T::AccountId>,508 RmrkResourceInfo,509 RmrkPropertyInfo,510 RmrkBaseInfo<T::AccountId>,511 RmrkPartType,512 RmrkTheme,513 RmrkNftChild,514 )>,515 ),516 QueryKind = OptionQuery,517 >;518519 #[pallet::hooks]520 impl<T: Config> Hooks<BlockNumberFor<T>> for Pallet<T> {521 fn on_runtime_upgrade() -> Weight {522 if StorageVersion::get::<Pallet<T>>() < StorageVersion::new(1) {523 use up_data_structs::{CollectionVersion1, CollectionVersion2};524 <CollectionById<T>>::translate::<CollectionVersion1<T::AccountId>, _>(|id, v| {525 let mut props = Vec::new();526 if !v.offchain_schema.is_empty() {527 props.push(Property {528 key: b"_old_offchainSchema".to_vec().try_into().unwrap(),529 value: v.offchain_schema.clone().into_inner().try_into().expect("offchain schema too big"),530 });531 }532 if !v.variable_on_chain_schema.is_empty() {533 props.push(Property {534 key: b"_old_variableOnChainSchema".to_vec().try_into().unwrap(),535 value: v.variable_on_chain_schema.clone().into_inner().try_into().expect("offchain schema too big"),536 });537 }538 if !v.const_on_chain_schema.is_empty() {539 props.push(Property {540 key: b"_old_constOnChainSchema".to_vec().try_into().unwrap(),541 value: v.const_on_chain_schema.clone().into_inner().try_into().expect("offchain schema too big"),542 });543 }544 props.push(Property {545 key: b"_old_schemaVersion".to_vec().try_into().unwrap(),546 value: match v.schema_version {547 SchemaVersion::ImageURL => b"ImageUrl".as_slice(),548 SchemaVersion::Unique => b"Unique".as_slice(),549 }.to_vec().try_into().unwrap(),550 });551 Self::set_scoped_collection_properties(552 id,553 PropertyScope::None,554 props.into_iter(),555 ).expect("existing data larger than properties");556 let mut new = CollectionVersion2::from(v.clone());557 new.permissions.access = Some(v.access);558 new.permissions.mint_mode = Some(v.mint_mode);559 Some(new)560 });561 }562563 0564 }565 }566}567568impl<T: Config> Pallet<T> {569 /// Ethereum receiver 0x0000000000000000000000000000000000000000 is reserved, and shouldn't own tokens570 pub fn ensure_correct_receiver(receiver: &T::CrossAccountId) -> DispatchResult {571 ensure!(572 &T::CrossAccountId::from_eth(H160([0; 20])) != receiver,573 <Error<T>>::AddressIsZero574 );575 Ok(())576 }577 pub fn adminlist(collection: CollectionId) -> Vec<T::CrossAccountId> {578 <IsAdmin<T>>::iter_prefix((collection,))579 .map(|(a, _)| a)580 .collect()581 }582 pub fn allowlist(collection: CollectionId) -> Vec<T::CrossAccountId> {583 <Allowlist<T>>::iter_prefix((collection,))584 .map(|(a, _)| a)585 .collect()586 }587 pub fn allowed(collection: CollectionId, user: T::CrossAccountId) -> bool {588 <Allowlist<T>>::get((collection, user))589 }590 pub fn collection_stats() -> CollectionStats {591 let created = <CreatedCollectionCount<T>>::get();592 let destroyed = <DestroyedCollectionCount<T>>::get();593 CollectionStats {594 created: created.0,595 destroyed: destroyed.0,596 alive: created.0 - destroyed.0,597 }598 }599600 pub fn effective_collection_limits(collection: CollectionId) -> Option<CollectionLimits> {601 let collection = <CollectionById<T>>::get(collection);602 if collection.is_none() {603 return None;604 }605606 let collection = collection.unwrap();607 let limits = collection.limits;608 let effective_limits = CollectionLimits {609 account_token_ownership_limit: Some(limits.account_token_ownership_limit()),610 sponsored_data_size: Some(limits.sponsored_data_size()),611 sponsored_data_rate_limit: Some(612 limits613 .sponsored_data_rate_limit614 .unwrap_or(SponsoringRateLimit::SponsoringDisabled),615 ),616 token_limit: Some(limits.token_limit()),617 sponsor_transfer_timeout: Some(limits.sponsor_transfer_timeout(618 match collection.mode {619 CollectionMode::NFT => NFT_SPONSOR_TRANSFER_TIMEOUT,620 CollectionMode::Fungible(_) => FUNGIBLE_SPONSOR_TRANSFER_TIMEOUT,621 CollectionMode::ReFungible => REFUNGIBLE_SPONSOR_TRANSFER_TIMEOUT,622 },623 )),624 sponsor_approve_timeout: Some(limits.sponsor_approve_timeout()),625 owner_can_transfer: Some(limits.owner_can_transfer()),626 owner_can_destroy: Some(limits.owner_can_destroy()),627 transfers_enabled: Some(limits.transfers_enabled()),628 };629630 Some(effective_limits)631 }632633 pub fn rpc_collection(collection: CollectionId) -> Option<RpcCollection<T::AccountId>> {634 let Collection {635 name,636 description,637 owner,638 mode,639 token_prefix,640 sponsorship,641 limits,642 permissions,643 } = <CollectionById<T>>::get(collection)?;644645 let token_property_permissions = <CollectionPropertyPermissions<T>>::get(collection)646 .into_iter()647 .map(|(key, permission)| PropertyKeyPermission {648 key,649 permission,650 })651 .collect();652653 let properties = <CollectionProperties<T>>::get(collection)654 .into_iter()655 .map(|(key, value)| Property {656 key,657 value,658 })659 .collect();660661 let permissions = CollectionPermissions {662 access: Some(permissions.access()),663 mint_mode: Some(permissions.mint_mode()),664 nesting: Some(permissions.nesting().clone()),665 };666667 Some(RpcCollection {668 name: name.into_inner(),669 description: description.into_inner(),670 owner,671 mode,672 token_prefix: token_prefix.into_inner(),673 sponsorship,674 limits,675 permissions,676 token_property_permissions,677 properties,678 })679 }680}681682macro_rules! limit_default {683 ($old:ident, $new:ident, $($field:ident $(($arg:expr))? => $check:expr),* $(,)?) => {{684 $(685 if let Some($new) = $new.$field {686 let $old = $old.$field($($arg)?);687 let _ = $new;688 let _ = $old;689 $check690 } else {691 $new.$field = $old.$field692 }693 )*694 }};695}696macro_rules! limit_default_clone {697 ($old:ident, $new:ident, $($field:ident $(($arg:expr))? => $check:expr),* $(,)?) => {{698 $(699 if let Some($new) = $new.$field.clone() {700 let $old = $old.$field($($arg)?);701 let _ = $new;702 let _ = $old;703 $check704 } else {705 $new.$field = $old.$field.clone()706 }707 )*708 }};709}710711impl<T: Config> Pallet<T> {712 pub fn init_collection(713 owner: T::AccountId,714 data: CreateCollectionData<T::AccountId>,715 ) -> Result<CollectionId, DispatchError> {716 {717 ensure!(718 data.token_prefix.len() <= MAX_TOKEN_PREFIX_LENGTH as usize,719 Error::<T>::CollectionTokenPrefixLimitExceeded720 );721 }722723 let created_count = <CreatedCollectionCount<T>>::get()724 .0725 .checked_add(1)726 .ok_or(ArithmeticError::Overflow)?;727 let destroyed_count = <DestroyedCollectionCount<T>>::get().0;728 let id = CollectionId(created_count);729730 // bound Total number of collections731 ensure!(732 created_count - destroyed_count <= COLLECTION_NUMBER_LIMIT,733 <Error<T>>::TotalCollectionsLimitExceeded734 );735736 // =========737738 let collection = Collection {739 owner: owner.clone(),740 name: data.name,741 mode: data.mode.clone(),742 description: data.description,743 token_prefix: data.token_prefix,744 sponsorship: data745 .pending_sponsor746 .map(SponsorshipState::Unconfirmed)747 .unwrap_or_default(),748 limits: data749 .limits750 .map(|limits| Self::clamp_limits(data.mode.clone(), &Default::default(), limits))751 .unwrap_or_else(|| Ok(CollectionLimits::default()))?,752 permissions: data753 .permissions754 .map(|permissions| Self::clamp_permissions(data.mode.clone(), &Default::default(), permissions))755 .unwrap_or_else(|| Ok(CollectionPermissions::default()))?,756 };757758 let mut collection_properties = up_data_structs::CollectionProperties::get();759 collection_properties760 .try_set_from_iter(data.properties.into_iter())761 .map_err(<Error<T>>::from)?;762763 CollectionProperties::<T>::insert(id, collection_properties);764765 let mut token_props_permissions = PropertiesPermissionMap::new();766 token_props_permissions767 .try_set_from_iter(data.token_property_permissions.into_iter())768 .map_err(<Error<T>>::from)?;769770 CollectionPropertyPermissions::<T>::insert(id, token_props_permissions);771772 // Take a (non-refundable) deposit of collection creation773 {774 let mut imbalance =775 <<<T as Config>::Currency as Currency<T::AccountId>>::PositiveImbalance>::zero();776 imbalance.subsume(777 <<T as Config>::Currency as Currency<T::AccountId>>::deposit_creating(778 &T::TreasuryAccountId::get(),779 T::CollectionCreationPrice::get(),780 ),781 );782 <T as Config>::Currency::settle(783 &owner,784 imbalance,785 WithdrawReasons::TRANSFER,786 ExistenceRequirement::KeepAlive,787 )788 .map_err(|_| Error::<T>::NotSufficientFounds)?;789 }790791 <CreatedCollectionCount<T>>::put(created_count);792 <Pallet<T>>::deposit_event(Event::CollectionCreated(id, data.mode.id(), owner.clone()));793 <CollectionById<T>>::insert(id, collection);794 Ok(id)795 }796797 pub fn destroy_collection(798 collection: CollectionHandle<T>,799 sender: &T::CrossAccountId,800 ) -> DispatchResult {801 ensure!(802 collection.limits.owner_can_destroy(),803 <Error<T>>::NoPermission,804 );805 collection.check_is_owner(sender)?;806807 let destroyed_collections = <DestroyedCollectionCount<T>>::get()808 .0809 .checked_add(1)810 .ok_or(ArithmeticError::Overflow)?;811812 // =========813814 <DestroyedCollectionCount<T>>::put(destroyed_collections);815 <CollectionById<T>>::remove(collection.id);816 <AdminAmount<T>>::remove(collection.id);817 <IsAdmin<T>>::remove_prefix((collection.id,), None);818 <Allowlist<T>>::remove_prefix((collection.id,), None);819 <CollectionProperties<T>>::remove(collection.id);820821 <Pallet<T>>::deposit_event(Event::CollectionDestroyed(collection.id));822 Ok(())823 }824825 pub fn set_collection_property(826 collection: &CollectionHandle<T>,827 sender: &T::CrossAccountId,828 property: Property,829 ) -> DispatchResult {830 collection.check_is_owner_or_admin(sender)?;831832 CollectionProperties::<T>::try_mutate(collection.id, |properties| {833 let property = property.clone();834 properties.try_set(property.key, property.value)835 })836 .map_err(<Error<T>>::from)?;837838 Self::deposit_event(Event::CollectionPropertySet(collection.id, property.key));839840 Ok(())841 }842843 pub fn set_scoped_collection_property(844 collection_id: CollectionId,845 scope: PropertyScope,846 property: Property,847 ) -> DispatchResult {848 CollectionProperties::<T>::try_mutate(collection_id, |properties| {849 properties.try_scoped_set(scope, property.key, property.value)850 })851 .map_err(<Error<T>>::from)?;852853 Ok(())854 }855856 pub fn set_scoped_collection_properties(857 collection_id: CollectionId,858 scope: PropertyScope,859 properties: impl Iterator<Item = Property>,860 ) -> DispatchResult {861 CollectionProperties::<T>::try_mutate(collection_id, |stored_properties| {862 stored_properties.try_scoped_set_from_iter(scope, properties)863 })864 .map_err(<Error<T>>::from)?;865866 Ok(())867 }868869 #[transactional]870 pub fn set_collection_properties(871 collection: &CollectionHandle<T>,872 sender: &T::CrossAccountId,873 properties: Vec<Property>,874 ) -> DispatchResult {875 for property in properties {876 Self::set_collection_property(collection, sender, property)?;877 }878879 Ok(())880 }881882 pub fn delete_collection_property(883 collection: &CollectionHandle<T>,884 sender: &T::CrossAccountId,885 property_key: PropertyKey,886 ) -> DispatchResult {887 collection.check_is_owner_or_admin(sender)?;888889 CollectionProperties::<T>::try_mutate(collection.id, |properties| {890 properties.remove(&property_key)891 })892 .map_err(<Error<T>>::from)?;893894 Self::deposit_event(Event::CollectionPropertyDeleted(895 collection.id,896 property_key,897 ));898899 Ok(())900 }901902 #[transactional]903 pub fn delete_collection_properties(904 collection: &CollectionHandle<T>,905 sender: &T::CrossAccountId,906 property_keys: Vec<PropertyKey>,907 ) -> DispatchResult {908 for key in property_keys {909 Self::delete_collection_property(collection, sender, key)?;910 }911912 Ok(())913 }914915 // For migrations916 pub fn set_property_permission_unchecked(917 collection: CollectionId,918 property_permission: PropertyKeyPermission,919 ) -> DispatchResult {920 <CollectionPropertyPermissions<T>>::try_mutate(collection, |permissions| {921 permissions.try_set(property_permission.key, property_permission.permission)922 })923 .map_err(<Error<T>>::from)?;924 Ok(())925 }926927 pub fn set_property_permission(928 collection: &CollectionHandle<T>,929 sender: &T::CrossAccountId,930 property_permission: PropertyKeyPermission,931 ) -> DispatchResult {932 collection.check_is_owner_or_admin(sender)?;933934 let all_permissions = CollectionPropertyPermissions::<T>::get(collection.id);935 let current_permission = all_permissions.get(&property_permission.key);936 if matches![937 current_permission,938 Some(PropertyPermission { mutable: false, .. })939 ] {940 return Err(<Error<T>>::NoPermission.into());941 }942943 CollectionPropertyPermissions::<T>::try_mutate(collection.id, |permissions| {944 let property_permission = property_permission.clone();945 permissions.try_set(property_permission.key, property_permission.permission)946 })947 .map_err(<Error<T>>::from)?;948949 Self::deposit_event(Event::PropertyPermissionSet(950 collection.id,951 property_permission.key,952 ));953954 Ok(())955 }956957 #[transactional]958 pub fn set_property_permissions(959 collection: &CollectionHandle<T>,960 sender: &T::CrossAccountId,961 property_permissions: Vec<PropertyKeyPermission>,962 ) -> DispatchResult {963 for prop_pemission in property_permissions {964 Self::set_property_permission(collection, sender, prop_pemission)?;965 }966967 Ok(())968 }969970 pub fn get_collection_property(971 collection_id: CollectionId,972 key: &PropertyKey,973 ) -> Option<PropertyValue> {974 Self::collection_properties(collection_id).get(key).cloned()975 }976977 pub fn bytes_keys_to_property_keys(978 keys: Vec<Vec<u8>>,979 ) -> Result<Vec<PropertyKey>, DispatchError> {980 keys.into_iter()981 .map(|key| -> Result<PropertyKey, DispatchError> {982 key.try_into()983 .map_err(|_| <Error<T>>::PropertyKeyIsTooLong.into())984 })985 .collect::<Result<Vec<PropertyKey>, DispatchError>>()986 }987988 pub fn filter_collection_properties(989 collection_id: CollectionId,990 keys: Option<Vec<PropertyKey>>,991 ) -> Result<Vec<Property>, DispatchError> {992 let properties = Self::collection_properties(collection_id);993994 let properties = keys995 .map(|keys| {996 keys.into_iter()997 .filter_map(|key| {998 properties.get(&key).map(|value| Property {999 key,1000 value: value.clone(),1001 })1002 })1003 .collect()1004 })1005 .unwrap_or_else(|| {1006 properties1007 .into_iter()1008 .map(|(key, value)| Property {1009 key,1010 value,1011 })1012 .collect()1013 });10141015 Ok(properties)1016 }10171018 pub fn filter_property_permissions(1019 collection_id: CollectionId,1020 keys: Option<Vec<PropertyKey>>,1021 ) -> Result<Vec<PropertyKeyPermission>, DispatchError> {1022 let permissions = Self::property_permissions(collection_id);10231024 let key_permissions = keys1025 .map(|keys| {1026 keys.into_iter()1027 .filter_map(|key| {1028 permissions1029 .get(&key)1030 .map(|permission| PropertyKeyPermission {1031 key,1032 permission: permission.clone(),1033 })1034 })1035 .collect()1036 })1037 .unwrap_or_else(|| {1038 permissions1039 .into_iter()1040 .map(|(key, permission)| PropertyKeyPermission {1041 key,1042 permission,1043 })1044 .collect()1045 });10461047 Ok(key_permissions)1048 }10491050 pub fn toggle_allowlist(1051 collection: &CollectionHandle<T>,1052 sender: &T::CrossAccountId,1053 user: &T::CrossAccountId,1054 allowed: bool,1055 ) -> DispatchResult {1056 collection.check_is_owner_or_admin(sender)?;10571058 // =========10591060 if allowed {1061 <Allowlist<T>>::insert((collection.id, user), true);1062 } else {1063 <Allowlist<T>>::remove((collection.id, user));1064 }10651066 Ok(())1067 }10681069 pub fn toggle_admin(1070 collection: &CollectionHandle<T>,1071 sender: &T::CrossAccountId,1072 user: &T::CrossAccountId,1073 admin: bool,1074 ) -> DispatchResult {1075 collection.check_is_owner_or_admin(sender)?;10761077 let was_admin = <IsAdmin<T>>::get((collection.id, user));1078 if was_admin == admin {1079 return Ok(());1080 }1081 let amount = <AdminAmount<T>>::get(collection.id);10821083 if admin {1084 let amount = amount1085 .checked_add(1)1086 .ok_or(<Error<T>>::CollectionAdminCountExceeded)?;1087 ensure!(1088 amount <= Self::collection_admins_limit(),1089 <Error<T>>::CollectionAdminCountExceeded,1090 );10911092 // =========10931094 <AdminAmount<T>>::insert(collection.id, amount);1095 <IsAdmin<T>>::insert((collection.id, user), true);1096 } else {1097 <AdminAmount<T>>::insert(collection.id, amount.saturating_sub(1));1098 <IsAdmin<T>>::remove((collection.id, user));1099 }11001101 Ok(())1102 }11031104 pub fn clamp_limits(1105 mode: CollectionMode,1106 old_limit: &CollectionLimits,1107 mut new_limit: CollectionLimits,1108 ) -> Result<CollectionLimits, DispatchError> {1109 limit_default!(old_limit, new_limit,1110 account_token_ownership_limit => ensure!(1111 new_limit <= MAX_TOKEN_OWNERSHIP,1112 <Error<T>>::CollectionLimitBoundsExceeded,1113 ),1114 sponsored_data_size => ensure!(1115 new_limit <= CUSTOM_DATA_LIMIT,1116 <Error<T>>::CollectionLimitBoundsExceeded,1117 ),11181119 sponsored_data_rate_limit => {},1120 token_limit => ensure!(1121 old_limit >= new_limit && new_limit > 0,1122 <Error<T>>::CollectionTokenLimitExceeded1123 ),11241125 sponsor_transfer_timeout(match mode {1126 CollectionMode::NFT => NFT_SPONSOR_TRANSFER_TIMEOUT,1127 CollectionMode::Fungible(_) => FUNGIBLE_SPONSOR_TRANSFER_TIMEOUT,1128 CollectionMode::ReFungible => REFUNGIBLE_SPONSOR_TRANSFER_TIMEOUT,1129 }) => ensure!(1130 new_limit <= MAX_SPONSOR_TIMEOUT,1131 <Error<T>>::CollectionLimitBoundsExceeded,1132 ),1133 sponsor_approve_timeout => {},1134 owner_can_transfer => ensure!(1135 old_limit || !new_limit,1136 <Error<T>>::OwnerPermissionsCantBeReverted,1137 ),1138 owner_can_destroy => ensure!(1139 old_limit || !new_limit,1140 <Error<T>>::OwnerPermissionsCantBeReverted,1141 ),1142 transfers_enabled => {},1143 );1144 Ok(new_limit)1145 }1146 pub fn clamp_permissions(1147 mode: CollectionMode,1148 old_limit: &CollectionPermissions,1149 mut new_limit: CollectionPermissions,1150 ) -> Result<CollectionPermissions, DispatchError> {1151 limit_default_clone!(old_limit, new_limit,1152 access => {},1153 mint_mode => {},1154 nesting => {},1155 );1156 Ok(new_limit)1157 }1158}11591160#[macro_export]1161macro_rules! unsupported {1162 () => {1163 Err(<Error<T>>::UnsupportedOperation.into())1164 };1165}11661167/// Worst cases1168pub trait CommonWeightInfo<CrossAccountId> {1169 fn create_item() -> Weight;1170 fn create_multiple_items(amount: &[CreateItemData]) -> Weight;1171 fn create_multiple_items_ex(cost: &CreateItemExData<CrossAccountId>) -> Weight;1172 fn burn_item() -> Weight;1173 fn set_collection_properties(amount: u32) -> Weight;1174 fn delete_collection_properties(amount: u32) -> Weight;1175 fn set_token_properties(amount: u32) -> Weight;1176 fn delete_token_properties(amount: u32) -> Weight;1177 fn set_property_permissions(amount: u32) -> Weight;1178 fn transfer() -> Weight;1179 fn approve() -> Weight;1180 fn transfer_from() -> Weight;1181 fn burn_from() -> Weight;1182}11831184pub trait CommonCollectionOperations<T: Config> {1185 fn create_item(1186 &self,1187 sender: T::CrossAccountId,1188 to: T::CrossAccountId,1189 data: CreateItemData,1190 nesting_budget: &dyn Budget,1191 ) -> DispatchResultWithPostInfo;1192 fn create_multiple_items(1193 &self,1194 sender: T::CrossAccountId,1195 to: T::CrossAccountId,1196 data: Vec<CreateItemData>,1197 nesting_budget: &dyn Budget,1198 ) -> DispatchResultWithPostInfo;1199 fn create_multiple_items_ex(1200 &self,1201 sender: T::CrossAccountId,1202 data: CreateItemExData<T::CrossAccountId>,1203 nesting_budget: &dyn Budget,1204 ) -> DispatchResultWithPostInfo;1205 fn burn_item(1206 &self,1207 sender: T::CrossAccountId,1208 token: TokenId,1209 amount: u128,1210 ) -> DispatchResultWithPostInfo;1211 fn set_collection_properties(1212 &self,1213 sender: T::CrossAccountId,1214 properties: Vec<Property>,1215 ) -> DispatchResultWithPostInfo;1216 fn delete_collection_properties(1217 &self,1218 sender: &T::CrossAccountId,1219 property_keys: Vec<PropertyKey>,1220 ) -> DispatchResultWithPostInfo;1221 fn set_token_properties(1222 &self,1223 sender: T::CrossAccountId,1224 token_id: TokenId,1225 property: Vec<Property>,1226 ) -> DispatchResultWithPostInfo;1227 fn delete_token_properties(1228 &self,1229 sender: T::CrossAccountId,1230 token_id: TokenId,1231 property_keys: Vec<PropertyKey>,1232 ) -> DispatchResultWithPostInfo;1233 fn set_property_permissions(1234 &self,1235 sender: &T::CrossAccountId,1236 property_permissions: Vec<PropertyKeyPermission>,1237 ) -> DispatchResultWithPostInfo;1238 fn transfer(1239 &self,1240 sender: T::CrossAccountId,1241 to: T::CrossAccountId,1242 token: TokenId,1243 amount: u128,1244 nesting_budget: &dyn Budget,1245 ) -> DispatchResultWithPostInfo;1246 fn approve(1247 &self,1248 sender: T::CrossAccountId,1249 spender: T::CrossAccountId,1250 token: TokenId,1251 amount: u128,1252 ) -> DispatchResultWithPostInfo;1253 fn transfer_from(1254 &self,1255 sender: T::CrossAccountId,1256 from: T::CrossAccountId,1257 to: T::CrossAccountId,1258 token: TokenId,1259 amount: u128,1260 nesting_budget: &dyn Budget,1261 ) -> DispatchResultWithPostInfo;1262 fn burn_from(1263 &self,1264 sender: T::CrossAccountId,1265 from: T::CrossAccountId,1266 token: TokenId,1267 amount: u128,1268 nesting_budget: &dyn Budget,1269 ) -> DispatchResultWithPostInfo;12701271 fn check_nesting(1272 &self,1273 sender: T::CrossAccountId,1274 from: (CollectionId, TokenId),1275 under: TokenId,1276 budget: &dyn Budget,1277 ) -> DispatchResult;12781279 fn nest(1280 &self,1281 under: TokenId,1282 to_nest: (CollectionId, TokenId)1283 );12841285 fn unnest(1286 &self,1287 under: TokenId,1288 to_nest: (CollectionId, TokenId)1289 );12901291 fn account_tokens(&self, account: T::CrossAccountId) -> Vec<TokenId>;1292 fn collection_tokens(&self) -> Vec<TokenId>;1293 fn token_exists(&self, token: TokenId) -> bool;1294 fn last_token_id(&self) -> TokenId;12951296 fn token_owner(&self, token: TokenId) -> Option<T::CrossAccountId>;1297 fn token_property(&self, token_id: TokenId, key: &PropertyKey) -> Option<PropertyValue>;1298 fn token_properties(&self, token_id: TokenId, keys: Option<Vec<PropertyKey>>) -> Vec<Property>;1299 /// Amount of unique collection tokens1300 fn total_supply(&self) -> u32;1301 /// Amount of different tokens account has (Applicable to nonfungible/refungible)1302 fn account_balance(&self, account: T::CrossAccountId) -> u32;1303 /// Amount of specific token account have (Applicable to fungible/refungible)1304 fn balance(&self, account: T::CrossAccountId, token: TokenId) -> u128;1305 fn allowance(1306 &self,1307 sender: T::CrossAccountId,1308 spender: T::CrossAccountId,1309 token: TokenId,1310 ) -> u128;1311}13121313// Flexible enough for implementing CommonCollectionOperations1314pub fn with_weight(res: DispatchResult, weight: Weight) -> DispatchResultWithPostInfo {1315 let post_info = PostDispatchInfo {1316 actual_weight: Some(weight),1317 pays_fee: Pays::Yes,1318 };1319 match res {1320 Ok(()) => Ok(post_info),1321 Err(error) => Err(DispatchErrorWithPostInfo { post_info, error }),1322 }1323}13241325impl<T: Config> From<PropertiesError> for Error<T> {1326 fn from(error: PropertiesError) -> Self {1327 match error {1328 PropertiesError::NoSpaceForProperty => Self::NoSpaceForProperty,1329 PropertiesError::PropertyLimitReached => Self::PropertyLimitReached,1330 PropertiesError::InvalidCharacterInPropertyKey => Self::InvalidCharacterInPropertyKey,1331 PropertiesError::PropertyKeyIsTooLong => Self::PropertyKeyIsTooLong,1332 PropertiesError::EmptyPropertyKey => Self::EmptyPropertyKey,1333 }1334 }1335}1// 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#![cfg_attr(not(feature = "std"), no_std)]1819extern crate alloc;2021use core::ops::{Deref, DerefMut};22use pallet_evm_coder_substrate::{SubstrateRecorder, WithRecorder};23use sp_std::vec::Vec;24use pallet_evm::account::CrossAccountId;25use frame_support::{26 dispatch::{DispatchErrorWithPostInfo, DispatchResultWithPostInfo, Weight, PostDispatchInfo},27 ensure,28 traits::{Imbalance, Get, Currency, WithdrawReasons, ExistenceRequirement},29 BoundedVec,30 weights::Pays,31 transactional,32};33use pallet_evm::GasWeightMapping;34use up_data_structs::{35 COLLECTION_NUMBER_LIMIT,36 Collection,37 RpcCollection,38 CollectionId,39 CreateItemData,40 MAX_TOKEN_PREFIX_LENGTH,41 COLLECTION_ADMINS_LIMIT,42 TokenId,43 CollectionStats,44 MAX_TOKEN_OWNERSHIP,45 CollectionMode,46 NFT_SPONSOR_TRANSFER_TIMEOUT,47 FUNGIBLE_SPONSOR_TRANSFER_TIMEOUT,48 REFUNGIBLE_SPONSOR_TRANSFER_TIMEOUT,49 MAX_SPONSOR_TIMEOUT,50 CUSTOM_DATA_LIMIT,51 CollectionLimits,52 CreateCollectionData,53 SponsorshipState,54 CreateItemExData,55 SponsoringRateLimit,56 budget::Budget,57 COLLECTION_FIELD_LIMIT,58 PhantomType,59 Property,60 Properties,61 PropertiesPermissionMap,62 PropertyKey,63 PropertyValue,64 PropertyPermission,65 PropertiesError,66 PropertyKeyPermission,67 TokenData,68 TrySetProperty,69 PropertyScope,70 // RMRK71 RmrkCollectionInfo,72 RmrkInstanceInfo,73 RmrkResourceInfo,74 RmrkPropertyInfo,75 RmrkBaseInfo,76 RmrkPartType,77 RmrkTheme,78 RmrkNftChild,79 CollectionPermissions,80 SchemaVersion,81};8283pub use pallet::*;84use sp_core::H160;85use sp_runtime::{ArithmeticError, DispatchError, DispatchResult};86#[cfg(feature = "runtime-benchmarks")]87pub mod benchmarking;88pub mod dispatch;89pub mod erc;90pub mod eth;91pub mod weights;9293pub type SelfWeightOf<T> = <T as Config>::WeightInfo;9495#[must_use = "Should call submit_logs or save, otherwise some data will be lost for evm side"]96pub struct CollectionHandle<T: Config> {97 pub id: CollectionId,98 collection: Collection<T::AccountId>,99 pub recorder: SubstrateRecorder<T>,100}101impl<T: Config> WithRecorder<T> for CollectionHandle<T> {102 fn recorder(&self) -> &SubstrateRecorder<T> {103 &self.recorder104 }105 fn into_recorder(self) -> SubstrateRecorder<T> {106 self.recorder107 }108}109impl<T: Config> CollectionHandle<T> {110 pub fn new_with_gas_limit(id: CollectionId, gas_limit: u64) -> Option<Self> {111 <CollectionById<T>>::get(id).map(|collection| Self {112 id,113 collection,114 recorder: SubstrateRecorder::new(gas_limit),115 })116 }117118 pub fn new_with_recorder(id: CollectionId, recorder: SubstrateRecorder<T>) -> Option<Self> {119 <CollectionById<T>>::get(id).map(|collection| Self {120 id,121 collection,122 recorder,123 })124 }125126 pub fn new(id: CollectionId) -> Option<Self> {127 Self::new_with_gas_limit(id, u64::MAX)128 }129 pub fn try_get(id: CollectionId) -> Result<Self, DispatchError> {130 Ok(Self::new(id).ok_or(<Error<T>>::CollectionNotFound)?)131 }132 pub fn consume_store_reads(&self, reads: u64) -> evm_coder::execution::Result<()> {133 self.recorder134 .consume_gas(T::GasWeightMapping::weight_to_gas(135 <T as frame_system::Config>::DbWeight::get()136 .read137 .saturating_mul(reads),138 ))139 }140 pub fn consume_store_writes(&self, writes: u64) -> evm_coder::execution::Result<()> {141 self.recorder142 .consume_gas(T::GasWeightMapping::weight_to_gas(143 <T as frame_system::Config>::DbWeight::get()144 .write145 .saturating_mul(writes),146 ))147 }148 pub fn save(self) -> DispatchResult {149 <CollectionById<T>>::insert(self.id, self.collection);150 Ok(())151 }152153 pub fn set_sponsor(&mut self, sponsor: T::AccountId) {154 self.collection.sponsorship = SponsorshipState::Unconfirmed(sponsor);155 }156157 pub fn confirm_sponsorship(&mut self, sender: &T::AccountId) -> bool {158 if self.collection.sponsorship.pending_sponsor() != Some(sender) {159 return false;160 };161162 self.collection.sponsorship = SponsorshipState::Confirmed(sender.clone());163 true164 }165}166impl<T: Config> Deref for CollectionHandle<T> {167 type Target = Collection<T::AccountId>;168169 fn deref(&self) -> &Self::Target {170 &self.collection171 }172}173174impl<T: Config> DerefMut for CollectionHandle<T> {175 fn deref_mut(&mut self) -> &mut Self::Target {176 &mut self.collection177 }178}179180impl<T: Config> CollectionHandle<T> {181 pub fn check_is_owner(&self, subject: &T::CrossAccountId) -> DispatchResult {182 ensure!(*subject.as_sub() == self.owner, <Error<T>>::NoPermission);183 Ok(())184 }185 pub fn is_owner_or_admin(&self, subject: &T::CrossAccountId) -> bool {186 *subject.as_sub() == self.owner || <IsAdmin<T>>::get((self.id, subject))187 }188 pub fn check_is_owner_or_admin(&self, subject: &T::CrossAccountId) -> DispatchResult {189 ensure!(self.is_owner_or_admin(subject), <Error<T>>::NoPermission);190 Ok(())191 }192 pub fn ignores_allowance(&self, user: &T::CrossAccountId) -> bool {193 self.limits.owner_can_transfer() && self.is_owner_or_admin(user)194 }195 pub fn ignores_owned_amount(&self, user: &T::CrossAccountId) -> bool {196 self.limits.owner_can_transfer() && self.is_owner_or_admin(user)197 }198 pub fn check_allowlist(&self, user: &T::CrossAccountId) -> DispatchResult {199 ensure!(200 <Allowlist<T>>::get((self.id, user)),201 <Error<T>>::AddressNotInAllowlist202 );203 Ok(())204 }205}206207#[frame_support::pallet]208pub mod pallet {209 use super::*;210 use pallet_evm::account;211 use dispatch::CollectionDispatch;212 use frame_support::{Blake2_128Concat, pallet_prelude::*, storage::Key, traits::StorageVersion};213 use frame_system::pallet_prelude::*;214 use frame_support::traits::Currency;215 use up_data_structs::{TokenId, mapping::TokenAddressMapping};216 use scale_info::TypeInfo;217 use weights::WeightInfo;218219 #[pallet::config]220 pub trait Config:221 frame_system::Config + pallet_evm_coder_substrate::Config + TypeInfo + account::Config222 {223 type WeightInfo: WeightInfo;224 type Event: IsType<<Self as frame_system::Config>::Event> + From<Event<Self>>;225226 type Currency: Currency<Self::AccountId>;227228 #[pallet::constant]229 type CollectionCreationPrice: Get<230 <<Self as Config>::Currency as Currency<Self::AccountId>>::Balance,231 >;232 type CollectionDispatch: CollectionDispatch<Self>;233234 type TreasuryAccountId: Get<Self::AccountId>;235236 type EvmTokenAddressMapping: TokenAddressMapping<H160>;237 type CrossTokenAddressMapping: TokenAddressMapping<Self::CrossAccountId>;238 }239240 const STORAGE_VERSION: StorageVersion = StorageVersion::new(1);241242 #[pallet::pallet]243 #[pallet::storage_version(STORAGE_VERSION)]244 #[pallet::generate_store(pub(super) trait Store)]245 pub struct Pallet<T>(_);246247 #[pallet::extra_constants]248 impl<T: Config> Pallet<T> {249 pub fn collection_admins_limit() -> u32 {250 COLLECTION_ADMINS_LIMIT251 }252 }253254 #[pallet::event]255 #[pallet::generate_deposit(pub fn deposit_event)]256 pub enum Event<T: Config> {257 /// New collection was created258 ///259 /// # Arguments260 ///261 /// * collection_id: Globally unique identifier of newly created collection.262 ///263 /// * mode: [CollectionMode] converted into u8.264 ///265 /// * account_id: Collection owner.266 CollectionCreated(CollectionId, u8, T::AccountId),267268 /// New collection was destroyed269 ///270 /// # Arguments271 ///272 /// * collection_id: Globally unique identifier of collection.273 CollectionDestroyed(CollectionId),274275 /// New item was created.276 ///277 /// # Arguments278 ///279 /// * collection_id: Id of the collection where item was created.280 ///281 /// * item_id: Id of an item. Unique within the collection.282 ///283 /// * recipient: Owner of newly created item284 ///285 /// * amount: Always 1 for NFT286 ItemCreated(CollectionId, TokenId, T::CrossAccountId, u128),287288 /// Collection item was burned.289 ///290 /// # Arguments291 ///292 /// * collection_id.293 ///294 /// * item_id: Identifier of burned NFT.295 ///296 /// * owner: which user has destroyed its tokens297 ///298 /// * amount: Always 1 for NFT299 ItemDestroyed(CollectionId, TokenId, T::CrossAccountId, u128),300301 /// Item was transferred302 ///303 /// * collection_id: Id of collection to which item is belong304 ///305 /// * item_id: Id of an item306 ///307 /// * sender: Original owner of item308 ///309 /// * recipient: New owner of item310 ///311 /// * amount: Always 1 for NFT312 Transfer(313 CollectionId,314 TokenId,315 T::CrossAccountId,316 T::CrossAccountId,317 u128,318 ),319320 /// * collection_id321 ///322 /// * item_id323 ///324 /// * sender325 ///326 /// * spender327 ///328 /// * amount329 Approved(330 CollectionId,331 TokenId,332 T::CrossAccountId,333 T::CrossAccountId,334 u128,335 ),336337 CollectionPropertySet(CollectionId, PropertyKey),338339 CollectionPropertyDeleted(CollectionId, PropertyKey),340341 TokenPropertySet(CollectionId, TokenId, PropertyKey),342343 TokenPropertyDeleted(CollectionId, TokenId, PropertyKey),344345 PropertyPermissionSet(CollectionId, PropertyKey),346 }347348 #[pallet::error]349 pub enum Error<T> {350 /// This collection does not exist.351 CollectionNotFound,352 /// Sender parameter and item owner must be equal.353 MustBeTokenOwner,354 /// No permission to perform action355 NoPermission,356 /// Destroying only empty collections is allowed357 CantDestroyNotEmptyCollection,358 /// Collection is not in mint mode.359 PublicMintingNotAllowed,360 /// Address is not in allow list.361 AddressNotInAllowlist,362363 /// Collection name can not be longer than 63 char.364 CollectionNameLimitExceeded,365 /// Collection description can not be longer than 255 char.366 CollectionDescriptionLimitExceeded,367 /// Token prefix can not be longer than 15 char.368 CollectionTokenPrefixLimitExceeded,369 /// Total collections bound exceeded.370 TotalCollectionsLimitExceeded,371 /// Exceeded max admin count372 CollectionAdminCountExceeded,373 /// Collection limit bounds per collection exceeded374 CollectionLimitBoundsExceeded,375 /// Tried to enable permissions which are only permitted to be disabled376 OwnerPermissionsCantBeReverted,377 /// Collection settings not allowing items transferring378 TransferNotAllowed,379 /// Account token limit exceeded per collection380 AccountTokenLimitExceeded,381 /// Collection token limit exceeded382 CollectionTokenLimitExceeded,383 /// Metadata flag frozen384 MetadataFlagFrozen,385386 /// Item not exists.387 TokenNotFound,388 /// Item balance not enough.389 TokenValueTooLow,390 /// Requested value more than approved.391 ApprovedValueTooLow,392 /// Tried to approve more than owned393 CantApproveMoreThanOwned,394395 /// Can't transfer tokens to ethereum zero address396 AddressIsZero,397 /// Target collection doesn't supports this operation398 UnsupportedOperation,399400 /// Not sufficient founds to perform action401 NotSufficientFounds,402403 /// Collection has nesting disabled404 NestingIsDisabled,405 /// Only owner may nest tokens under this collection406 OnlyOwnerAllowedToNest,407 /// Only tokens from specific collections may nest tokens under this408 SourceCollectionIsNotAllowedToNest,409410 /// Tried to store more data than allowed in collection field411 CollectionFieldSizeExceeded,412413 /// Tried to store more property data than allowed414 NoSpaceForProperty,415416 /// Tried to store more property keys than allowed417 PropertyLimitReached,418419 /// Property key is too long420 PropertyKeyIsTooLong,421422 /// Only ASCII letters, digits, and '_', '-' are allowed423 InvalidCharacterInPropertyKey,424425 /// Empty property keys are forbidden426 EmptyPropertyKey,427 }428429 #[pallet::storage]430 pub type CreatedCollectionCount<T> = StorageValue<Value = CollectionId, QueryKind = ValueQuery>;431 #[pallet::storage]432 pub type DestroyedCollectionCount<T> =433 StorageValue<Value = CollectionId, QueryKind = ValueQuery>;434435 /// Collection info436 #[pallet::storage]437 pub type CollectionById<T> = StorageMap<438 Hasher = Blake2_128Concat,439 Key = CollectionId,440 Value = Collection<<T as frame_system::Config>::AccountId>,441 QueryKind = OptionQuery,442 >;443444 /// Collection properties445 #[pallet::storage]446 #[pallet::getter(fn collection_properties)]447 pub type CollectionProperties<T> = StorageMap<448 Hasher = Blake2_128Concat,449 Key = CollectionId,450 Value = Properties,451 QueryKind = ValueQuery,452 OnEmpty = up_data_structs::CollectionProperties,453 >;454455 #[pallet::storage]456 #[pallet::getter(fn property_permissions)]457 pub type CollectionPropertyPermissions<T> = StorageMap<458 Hasher = Blake2_128Concat,459 Key = CollectionId,460 Value = PropertiesPermissionMap,461 QueryKind = ValueQuery,462 >;463464 #[pallet::storage]465 pub type AdminAmount<T> = StorageMap<466 Hasher = Blake2_128Concat,467 Key = CollectionId,468 Value = u32,469 QueryKind = ValueQuery,470 >;471472 /// List of collection admins473 #[pallet::storage]474 pub type IsAdmin<T: Config> = StorageNMap<475 Key = (476 Key<Blake2_128Concat, CollectionId>,477 Key<Blake2_128Concat, T::CrossAccountId>,478 ),479 Value = bool,480 QueryKind = ValueQuery,481 >;482483 /// Allowlisted collection users484 #[pallet::storage]485 pub type Allowlist<T: Config> = StorageNMap<486 Key = (487 Key<Blake2_128Concat, CollectionId>,488 Key<Blake2_128Concat, T::CrossAccountId>,489 ),490 Value = bool,491 QueryKind = ValueQuery,492 >;493494 /// Not used by code, exists only to provide some types to metadata495 #[pallet::storage]496 pub type DummyStorageValue<T: Config> = StorageValue<497 Value = (498 CollectionStats,499 CollectionId,500 TokenId,501 PhantomType<(502 TokenData<T::CrossAccountId>,503 RpcCollection<T::AccountId>,504 // RMRK505 RmrkCollectionInfo<T::AccountId>,506 RmrkInstanceInfo<T::AccountId>,507 RmrkResourceInfo,508 RmrkPropertyInfo,509 RmrkBaseInfo<T::AccountId>,510 RmrkPartType,511 RmrkTheme,512 RmrkNftChild,513 )>,514 ),515 QueryKind = OptionQuery,516 >;517518 #[pallet::hooks]519 impl<T: Config> Hooks<BlockNumberFor<T>> for Pallet<T> {520 fn on_runtime_upgrade() -> Weight {521 if StorageVersion::get::<Pallet<T>>() < StorageVersion::new(1) {522 use up_data_structs::{CollectionVersion1, CollectionVersion2};523 <CollectionById<T>>::translate::<CollectionVersion1<T::AccountId>, _>(|id, v| {524 let mut props = Vec::new();525 if !v.offchain_schema.is_empty() {526 props.push(Property {527 key: b"_old_offchainSchema".to_vec().try_into().unwrap(),528 value: v529 .offchain_schema530 .clone()531 .into_inner()532 .try_into()533 .expect("offchain schema too big"),534 });535 }536 if !v.variable_on_chain_schema.is_empty() {537 props.push(Property {538 key: b"_old_variableOnChainSchema".to_vec().try_into().unwrap(),539 value: v540 .variable_on_chain_schema541 .clone()542 .into_inner()543 .try_into()544 .expect("offchain schema too big"),545 });546 }547 if !v.const_on_chain_schema.is_empty() {548 props.push(Property {549 key: b"_old_constOnChainSchema".to_vec().try_into().unwrap(),550 value: v551 .const_on_chain_schema552 .clone()553 .into_inner()554 .try_into()555 .expect("offchain schema too big"),556 });557 }558 props.push(Property {559 key: b"_old_schemaVersion".to_vec().try_into().unwrap(),560 value: match v.schema_version {561 SchemaVersion::ImageURL => b"ImageUrl".as_slice(),562 SchemaVersion::Unique => b"Unique".as_slice(),563 }564 .to_vec()565 .try_into()566 .unwrap(),567 });568 Self::set_scoped_collection_properties(569 id,570 PropertyScope::None,571 props.into_iter(),572 )573 .expect("existing data larger than properties");574 let mut new = CollectionVersion2::from(v.clone());575 new.permissions.access = Some(v.access);576 new.permissions.mint_mode = Some(v.mint_mode);577 Some(new)578 });579 }580581 0582 }583 }584}585586impl<T: Config> Pallet<T> {587 /// Ethereum receiver 0x0000000000000000000000000000000000000000 is reserved, and shouldn't own tokens588 pub fn ensure_correct_receiver(receiver: &T::CrossAccountId) -> DispatchResult {589 ensure!(590 &T::CrossAccountId::from_eth(H160([0; 20])) != receiver,591 <Error<T>>::AddressIsZero592 );593 Ok(())594 }595 pub fn adminlist(collection: CollectionId) -> Vec<T::CrossAccountId> {596 <IsAdmin<T>>::iter_prefix((collection,))597 .map(|(a, _)| a)598 .collect()599 }600 pub fn allowlist(collection: CollectionId) -> Vec<T::CrossAccountId> {601 <Allowlist<T>>::iter_prefix((collection,))602 .map(|(a, _)| a)603 .collect()604 }605 pub fn allowed(collection: CollectionId, user: T::CrossAccountId) -> bool {606 <Allowlist<T>>::get((collection, user))607 }608 pub fn collection_stats() -> CollectionStats {609 let created = <CreatedCollectionCount<T>>::get();610 let destroyed = <DestroyedCollectionCount<T>>::get();611 CollectionStats {612 created: created.0,613 destroyed: destroyed.0,614 alive: created.0 - destroyed.0,615 }616 }617618 pub fn effective_collection_limits(collection: CollectionId) -> Option<CollectionLimits> {619 let collection = <CollectionById<T>>::get(collection);620 if collection.is_none() {621 return None;622 }623624 let collection = collection.unwrap();625 let limits = collection.limits;626 let effective_limits = CollectionLimits {627 account_token_ownership_limit: Some(limits.account_token_ownership_limit()),628 sponsored_data_size: Some(limits.sponsored_data_size()),629 sponsored_data_rate_limit: Some(630 limits631 .sponsored_data_rate_limit632 .unwrap_or(SponsoringRateLimit::SponsoringDisabled),633 ),634 token_limit: Some(limits.token_limit()),635 sponsor_transfer_timeout: Some(limits.sponsor_transfer_timeout(636 match collection.mode {637 CollectionMode::NFT => NFT_SPONSOR_TRANSFER_TIMEOUT,638 CollectionMode::Fungible(_) => FUNGIBLE_SPONSOR_TRANSFER_TIMEOUT,639 CollectionMode::ReFungible => REFUNGIBLE_SPONSOR_TRANSFER_TIMEOUT,640 },641 )),642 sponsor_approve_timeout: Some(limits.sponsor_approve_timeout()),643 owner_can_transfer: Some(limits.owner_can_transfer()),644 owner_can_destroy: Some(limits.owner_can_destroy()),645 transfers_enabled: Some(limits.transfers_enabled()),646 };647648 Some(effective_limits)649 }650651 pub fn rpc_collection(collection: CollectionId) -> Option<RpcCollection<T::AccountId>> {652 let Collection {653 name,654 description,655 owner,656 mode,657 token_prefix,658 sponsorship,659 limits,660 permissions,661 } = <CollectionById<T>>::get(collection)?;662663 let token_property_permissions = <CollectionPropertyPermissions<T>>::get(collection)664 .into_iter()665 .map(|(key, permission)| PropertyKeyPermission { key, permission })666 .collect();667668 let properties = <CollectionProperties<T>>::get(collection)669 .into_iter()670 .map(|(key, value)| Property { key, value })671 .collect();672673 let permissions = CollectionPermissions {674 access: Some(permissions.access()),675 mint_mode: Some(permissions.mint_mode()),676 nesting: Some(permissions.nesting().clone()),677 };678679 Some(RpcCollection {680 name: name.into_inner(),681 description: description.into_inner(),682 owner,683 mode,684 token_prefix: token_prefix.into_inner(),685 sponsorship,686 limits,687 permissions,688 token_property_permissions,689 properties,690 })691 }692}693694macro_rules! limit_default {695 ($old:ident, $new:ident, $($field:ident $(($arg:expr))? => $check:expr),* $(,)?) => {{696 $(697 if let Some($new) = $new.$field {698 let $old = $old.$field($($arg)?);699 let _ = $new;700 let _ = $old;701 $check702 } else {703 $new.$field = $old.$field704 }705 )*706 }};707}708macro_rules! limit_default_clone {709 ($old:ident, $new:ident, $($field:ident $(($arg:expr))? => $check:expr),* $(,)?) => {{710 $(711 if let Some($new) = $new.$field.clone() {712 let $old = $old.$field($($arg)?);713 let _ = $new;714 let _ = $old;715 $check716 } else {717 $new.$field = $old.$field.clone()718 }719 )*720 }};721}722723impl<T: Config> Pallet<T> {724 pub fn init_collection(725 owner: T::AccountId,726 data: CreateCollectionData<T::AccountId>,727 ) -> Result<CollectionId, DispatchError> {728 {729 ensure!(730 data.token_prefix.len() <= MAX_TOKEN_PREFIX_LENGTH as usize,731 Error::<T>::CollectionTokenPrefixLimitExceeded732 );733 }734735 let created_count = <CreatedCollectionCount<T>>::get()736 .0737 .checked_add(1)738 .ok_or(ArithmeticError::Overflow)?;739 let destroyed_count = <DestroyedCollectionCount<T>>::get().0;740 let id = CollectionId(created_count);741742 // bound Total number of collections743 ensure!(744 created_count - destroyed_count <= COLLECTION_NUMBER_LIMIT,745 <Error<T>>::TotalCollectionsLimitExceeded746 );747748 // =========749750 let collection = Collection {751 owner: owner.clone(),752 name: data.name,753 mode: data.mode.clone(),754 description: data.description,755 token_prefix: data.token_prefix,756 sponsorship: data757 .pending_sponsor758 .map(SponsorshipState::Unconfirmed)759 .unwrap_or_default(),760 limits: data761 .limits762 .map(|limits| Self::clamp_limits(data.mode.clone(), &Default::default(), limits))763 .unwrap_or_else(|| Ok(CollectionLimits::default()))?,764 permissions: data765 .permissions766 .map(|permissions| {767 Self::clamp_permissions(data.mode.clone(), &Default::default(), permissions)768 })769 .unwrap_or_else(|| Ok(CollectionPermissions::default()))?,770 };771772 let mut collection_properties = up_data_structs::CollectionProperties::get();773 collection_properties774 .try_set_from_iter(data.properties.into_iter())775 .map_err(<Error<T>>::from)?;776777 CollectionProperties::<T>::insert(id, collection_properties);778779 let mut token_props_permissions = PropertiesPermissionMap::new();780 token_props_permissions781 .try_set_from_iter(data.token_property_permissions.into_iter())782 .map_err(<Error<T>>::from)?;783784 CollectionPropertyPermissions::<T>::insert(id, token_props_permissions);785786 // Take a (non-refundable) deposit of collection creation787 {788 let mut imbalance =789 <<<T as Config>::Currency as Currency<T::AccountId>>::PositiveImbalance>::zero();790 imbalance.subsume(791 <<T as Config>::Currency as Currency<T::AccountId>>::deposit_creating(792 &T::TreasuryAccountId::get(),793 T::CollectionCreationPrice::get(),794 ),795 );796 <T as Config>::Currency::settle(797 &owner,798 imbalance,799 WithdrawReasons::TRANSFER,800 ExistenceRequirement::KeepAlive,801 )802 .map_err(|_| Error::<T>::NotSufficientFounds)?;803 }804805 <CreatedCollectionCount<T>>::put(created_count);806 <Pallet<T>>::deposit_event(Event::CollectionCreated(id, data.mode.id(), owner.clone()));807 <CollectionById<T>>::insert(id, collection);808 Ok(id)809 }810811 pub fn destroy_collection(812 collection: CollectionHandle<T>,813 sender: &T::CrossAccountId,814 ) -> DispatchResult {815 ensure!(816 collection.limits.owner_can_destroy(),817 <Error<T>>::NoPermission,818 );819 collection.check_is_owner(sender)?;820821 let destroyed_collections = <DestroyedCollectionCount<T>>::get()822 .0823 .checked_add(1)824 .ok_or(ArithmeticError::Overflow)?;825826 // =========827828 <DestroyedCollectionCount<T>>::put(destroyed_collections);829 <CollectionById<T>>::remove(collection.id);830 <AdminAmount<T>>::remove(collection.id);831 <IsAdmin<T>>::remove_prefix((collection.id,), None);832 <Allowlist<T>>::remove_prefix((collection.id,), None);833 <CollectionProperties<T>>::remove(collection.id);834835 <Pallet<T>>::deposit_event(Event::CollectionDestroyed(collection.id));836 Ok(())837 }838839 pub fn set_collection_property(840 collection: &CollectionHandle<T>,841 sender: &T::CrossAccountId,842 property: Property,843 ) -> DispatchResult {844 collection.check_is_owner_or_admin(sender)?;845846 CollectionProperties::<T>::try_mutate(collection.id, |properties| {847 let property = property.clone();848 properties.try_set(property.key, property.value)849 })850 .map_err(<Error<T>>::from)?;851852 Self::deposit_event(Event::CollectionPropertySet(collection.id, property.key));853854 Ok(())855 }856857 pub fn set_scoped_collection_property(858 collection_id: CollectionId,859 scope: PropertyScope,860 property: Property,861 ) -> DispatchResult {862 CollectionProperties::<T>::try_mutate(collection_id, |properties| {863 properties.try_scoped_set(scope, property.key, property.value)864 })865 .map_err(<Error<T>>::from)?;866867 Ok(())868 }869870 pub fn set_scoped_collection_properties(871 collection_id: CollectionId,872 scope: PropertyScope,873 properties: impl Iterator<Item = Property>,874 ) -> DispatchResult {875 CollectionProperties::<T>::try_mutate(collection_id, |stored_properties| {876 stored_properties.try_scoped_set_from_iter(scope, properties)877 })878 .map_err(<Error<T>>::from)?;879880 Ok(())881 }882883 #[transactional]884 pub fn set_collection_properties(885 collection: &CollectionHandle<T>,886 sender: &T::CrossAccountId,887 properties: Vec<Property>,888 ) -> DispatchResult {889 for property in properties {890 Self::set_collection_property(collection, sender, property)?;891 }892893 Ok(())894 }895896 pub fn delete_collection_property(897 collection: &CollectionHandle<T>,898 sender: &T::CrossAccountId,899 property_key: PropertyKey,900 ) -> DispatchResult {901 collection.check_is_owner_or_admin(sender)?;902903 CollectionProperties::<T>::try_mutate(collection.id, |properties| {904 properties.remove(&property_key)905 })906 .map_err(<Error<T>>::from)?;907908 Self::deposit_event(Event::CollectionPropertyDeleted(909 collection.id,910 property_key,911 ));912913 Ok(())914 }915916 #[transactional]917 pub fn delete_collection_properties(918 collection: &CollectionHandle<T>,919 sender: &T::CrossAccountId,920 property_keys: Vec<PropertyKey>,921 ) -> DispatchResult {922 for key in property_keys {923 Self::delete_collection_property(collection, sender, key)?;924 }925926 Ok(())927 }928929 // For migrations930 pub fn set_property_permission_unchecked(931 collection: CollectionId,932 property_permission: PropertyKeyPermission,933 ) -> DispatchResult {934 <CollectionPropertyPermissions<T>>::try_mutate(collection, |permissions| {935 permissions.try_set(property_permission.key, property_permission.permission)936 })937 .map_err(<Error<T>>::from)?;938 Ok(())939 }940941 pub fn set_property_permission(942 collection: &CollectionHandle<T>,943 sender: &T::CrossAccountId,944 property_permission: PropertyKeyPermission,945 ) -> DispatchResult {946 collection.check_is_owner_or_admin(sender)?;947948 let all_permissions = CollectionPropertyPermissions::<T>::get(collection.id);949 let current_permission = all_permissions.get(&property_permission.key);950 if matches![951 current_permission,952 Some(PropertyPermission { mutable: false, .. })953 ] {954 return Err(<Error<T>>::NoPermission.into());955 }956957 CollectionPropertyPermissions::<T>::try_mutate(collection.id, |permissions| {958 let property_permission = property_permission.clone();959 permissions.try_set(property_permission.key, property_permission.permission)960 })961 .map_err(<Error<T>>::from)?;962963 Self::deposit_event(Event::PropertyPermissionSet(964 collection.id,965 property_permission.key,966 ));967968 Ok(())969 }970971 #[transactional]972 pub fn set_property_permissions(973 collection: &CollectionHandle<T>,974 sender: &T::CrossAccountId,975 property_permissions: Vec<PropertyKeyPermission>,976 ) -> DispatchResult {977 for prop_pemission in property_permissions {978 Self::set_property_permission(collection, sender, prop_pemission)?;979 }980981 Ok(())982 }983984 pub fn get_collection_property(985 collection_id: CollectionId,986 key: &PropertyKey,987 ) -> Option<PropertyValue> {988 Self::collection_properties(collection_id).get(key).cloned()989 }990991 pub fn bytes_keys_to_property_keys(992 keys: Vec<Vec<u8>>,993 ) -> Result<Vec<PropertyKey>, DispatchError> {994 keys.into_iter()995 .map(|key| -> Result<PropertyKey, DispatchError> {996 key.try_into()997 .map_err(|_| <Error<T>>::PropertyKeyIsTooLong.into())998 })999 .collect::<Result<Vec<PropertyKey>, DispatchError>>()1000 }10011002 pub fn filter_collection_properties(1003 collection_id: CollectionId,1004 keys: Option<Vec<PropertyKey>>,1005 ) -> Result<Vec<Property>, DispatchError> {1006 let properties = Self::collection_properties(collection_id);10071008 let properties = keys1009 .map(|keys| {1010 keys.into_iter()1011 .filter_map(|key| {1012 properties.get(&key).map(|value| Property {1013 key,1014 value: value.clone(),1015 })1016 })1017 .collect()1018 })1019 .unwrap_or_else(|| {1020 properties1021 .into_iter()1022 .map(|(key, value)| Property { key, value })1023 .collect()1024 });10251026 Ok(properties)1027 }10281029 pub fn filter_property_permissions(1030 collection_id: CollectionId,1031 keys: Option<Vec<PropertyKey>>,1032 ) -> Result<Vec<PropertyKeyPermission>, DispatchError> {1033 let permissions = Self::property_permissions(collection_id);10341035 let key_permissions = keys1036 .map(|keys| {1037 keys.into_iter()1038 .filter_map(|key| {1039 permissions1040 .get(&key)1041 .map(|permission| PropertyKeyPermission {1042 key,1043 permission: permission.clone(),1044 })1045 })1046 .collect()1047 })1048 .unwrap_or_else(|| {1049 permissions1050 .into_iter()1051 .map(|(key, permission)| PropertyKeyPermission { key, permission })1052 .collect()1053 });10541055 Ok(key_permissions)1056 }10571058 pub fn toggle_allowlist(1059 collection: &CollectionHandle<T>,1060 sender: &T::CrossAccountId,1061 user: &T::CrossAccountId,1062 allowed: bool,1063 ) -> DispatchResult {1064 collection.check_is_owner_or_admin(sender)?;10651066 // =========10671068 if allowed {1069 <Allowlist<T>>::insert((collection.id, user), true);1070 } else {1071 <Allowlist<T>>::remove((collection.id, user));1072 }10731074 Ok(())1075 }10761077 pub fn toggle_admin(1078 collection: &CollectionHandle<T>,1079 sender: &T::CrossAccountId,1080 user: &T::CrossAccountId,1081 admin: bool,1082 ) -> DispatchResult {1083 collection.check_is_owner_or_admin(sender)?;10841085 let was_admin = <IsAdmin<T>>::get((collection.id, user));1086 if was_admin == admin {1087 return Ok(());1088 }1089 let amount = <AdminAmount<T>>::get(collection.id);10901091 if admin {1092 let amount = amount1093 .checked_add(1)1094 .ok_or(<Error<T>>::CollectionAdminCountExceeded)?;1095 ensure!(1096 amount <= Self::collection_admins_limit(),1097 <Error<T>>::CollectionAdminCountExceeded,1098 );10991100 // =========11011102 <AdminAmount<T>>::insert(collection.id, amount);1103 <IsAdmin<T>>::insert((collection.id, user), true);1104 } else {1105 <AdminAmount<T>>::insert(collection.id, amount.saturating_sub(1));1106 <IsAdmin<T>>::remove((collection.id, user));1107 }11081109 Ok(())1110 }11111112 pub fn clamp_limits(1113 mode: CollectionMode,1114 old_limit: &CollectionLimits,1115 mut new_limit: CollectionLimits,1116 ) -> Result<CollectionLimits, DispatchError> {1117 limit_default!(old_limit, new_limit,1118 account_token_ownership_limit => ensure!(1119 new_limit <= MAX_TOKEN_OWNERSHIP,1120 <Error<T>>::CollectionLimitBoundsExceeded,1121 ),1122 sponsored_data_size => ensure!(1123 new_limit <= CUSTOM_DATA_LIMIT,1124 <Error<T>>::CollectionLimitBoundsExceeded,1125 ),11261127 sponsored_data_rate_limit => {},1128 token_limit => ensure!(1129 old_limit >= new_limit && new_limit > 0,1130 <Error<T>>::CollectionTokenLimitExceeded1131 ),11321133 sponsor_transfer_timeout(match mode {1134 CollectionMode::NFT => NFT_SPONSOR_TRANSFER_TIMEOUT,1135 CollectionMode::Fungible(_) => FUNGIBLE_SPONSOR_TRANSFER_TIMEOUT,1136 CollectionMode::ReFungible => REFUNGIBLE_SPONSOR_TRANSFER_TIMEOUT,1137 }) => ensure!(1138 new_limit <= MAX_SPONSOR_TIMEOUT,1139 <Error<T>>::CollectionLimitBoundsExceeded,1140 ),1141 sponsor_approve_timeout => {},1142 owner_can_transfer => ensure!(1143 old_limit || !new_limit,1144 <Error<T>>::OwnerPermissionsCantBeReverted,1145 ),1146 owner_can_destroy => ensure!(1147 old_limit || !new_limit,1148 <Error<T>>::OwnerPermissionsCantBeReverted,1149 ),1150 transfers_enabled => {},1151 );1152 Ok(new_limit)1153 }1154 pub fn clamp_permissions(1155 mode: CollectionMode,1156 old_limit: &CollectionPermissions,1157 mut new_limit: CollectionPermissions,1158 ) -> Result<CollectionPermissions, DispatchError> {1159 limit_default_clone!(old_limit, new_limit,1160 access => {},1161 mint_mode => {},1162 nesting => {},1163 );1164 Ok(new_limit)1165 }1166}11671168#[macro_export]1169macro_rules! unsupported {1170 () => {1171 Err(<Error<T>>::UnsupportedOperation.into())1172 };1173}11741175/// Worst cases1176pub trait CommonWeightInfo<CrossAccountId> {1177 fn create_item() -> Weight;1178 fn create_multiple_items(amount: &[CreateItemData]) -> Weight;1179 fn create_multiple_items_ex(cost: &CreateItemExData<CrossAccountId>) -> Weight;1180 fn burn_item() -> Weight;1181 fn set_collection_properties(amount: u32) -> Weight;1182 fn delete_collection_properties(amount: u32) -> Weight;1183 fn set_token_properties(amount: u32) -> Weight;1184 fn delete_token_properties(amount: u32) -> Weight;1185 fn set_property_permissions(amount: u32) -> Weight;1186 fn transfer() -> Weight;1187 fn approve() -> Weight;1188 fn transfer_from() -> Weight;1189 fn burn_from() -> Weight;1190}11911192pub trait CommonCollectionOperations<T: Config> {1193 fn create_item(1194 &self,1195 sender: T::CrossAccountId,1196 to: T::CrossAccountId,1197 data: CreateItemData,1198 nesting_budget: &dyn Budget,1199 ) -> DispatchResultWithPostInfo;1200 fn create_multiple_items(1201 &self,1202 sender: T::CrossAccountId,1203 to: T::CrossAccountId,1204 data: Vec<CreateItemData>,1205 nesting_budget: &dyn Budget,1206 ) -> DispatchResultWithPostInfo;1207 fn create_multiple_items_ex(1208 &self,1209 sender: T::CrossAccountId,1210 data: CreateItemExData<T::CrossAccountId>,1211 nesting_budget: &dyn Budget,1212 ) -> DispatchResultWithPostInfo;1213 fn burn_item(1214 &self,1215 sender: T::CrossAccountId,1216 token: TokenId,1217 amount: u128,1218 ) -> DispatchResultWithPostInfo;1219 fn set_collection_properties(1220 &self,1221 sender: T::CrossAccountId,1222 properties: Vec<Property>,1223 ) -> DispatchResultWithPostInfo;1224 fn delete_collection_properties(1225 &self,1226 sender: &T::CrossAccountId,1227 property_keys: Vec<PropertyKey>,1228 ) -> DispatchResultWithPostInfo;1229 fn set_token_properties(1230 &self,1231 sender: T::CrossAccountId,1232 token_id: TokenId,1233 property: Vec<Property>,1234 ) -> DispatchResultWithPostInfo;1235 fn delete_token_properties(1236 &self,1237 sender: T::CrossAccountId,1238 token_id: TokenId,1239 property_keys: Vec<PropertyKey>,1240 ) -> DispatchResultWithPostInfo;1241 fn set_property_permissions(1242 &self,1243 sender: &T::CrossAccountId,1244 property_permissions: Vec<PropertyKeyPermission>,1245 ) -> DispatchResultWithPostInfo;1246 fn transfer(1247 &self,1248 sender: T::CrossAccountId,1249 to: T::CrossAccountId,1250 token: TokenId,1251 amount: u128,1252 nesting_budget: &dyn Budget,1253 ) -> DispatchResultWithPostInfo;1254 fn approve(1255 &self,1256 sender: T::CrossAccountId,1257 spender: T::CrossAccountId,1258 token: TokenId,1259 amount: u128,1260 ) -> DispatchResultWithPostInfo;1261 fn transfer_from(1262 &self,1263 sender: T::CrossAccountId,1264 from: T::CrossAccountId,1265 to: T::CrossAccountId,1266 token: TokenId,1267 amount: u128,1268 nesting_budget: &dyn Budget,1269 ) -> DispatchResultWithPostInfo;1270 fn burn_from(1271 &self,1272 sender: T::CrossAccountId,1273 from: T::CrossAccountId,1274 token: TokenId,1275 amount: u128,1276 nesting_budget: &dyn Budget,1277 ) -> DispatchResultWithPostInfo;12781279 fn check_nesting(1280 &self,1281 sender: T::CrossAccountId,1282 from: (CollectionId, TokenId),1283 under: TokenId,1284 budget: &dyn Budget,1285 ) -> DispatchResult;12861287 fn nest(&self, under: TokenId, to_nest: (CollectionId, TokenId));12881289 fn unnest(&self, under: TokenId, to_nest: (CollectionId, TokenId));12901291 fn account_tokens(&self, account: T::CrossAccountId) -> Vec<TokenId>;1292 fn collection_tokens(&self) -> Vec<TokenId>;1293 fn token_exists(&self, token: TokenId) -> bool;1294 fn last_token_id(&self) -> TokenId;12951296 fn token_owner(&self, token: TokenId) -> Option<T::CrossAccountId>;1297 fn token_property(&self, token_id: TokenId, key: &PropertyKey) -> Option<PropertyValue>;1298 fn token_properties(&self, token_id: TokenId, keys: Option<Vec<PropertyKey>>) -> Vec<Property>;1299 /// Amount of unique collection tokens1300 fn total_supply(&self) -> u32;1301 /// Amount of different tokens account has (Applicable to nonfungible/refungible)1302 fn account_balance(&self, account: T::CrossAccountId) -> u32;1303 /// Amount of specific token account have (Applicable to fungible/refungible)1304 fn balance(&self, account: T::CrossAccountId, token: TokenId) -> u128;1305 fn allowance(1306 &self,1307 sender: T::CrossAccountId,1308 spender: T::CrossAccountId,1309 token: TokenId,1310 ) -> u128;1311}13121313// Flexible enough for implementing CommonCollectionOperations1314pub fn with_weight(res: DispatchResult, weight: Weight) -> DispatchResultWithPostInfo {1315 let post_info = PostDispatchInfo {1316 actual_weight: Some(weight),1317 pays_fee: Pays::Yes,1318 };1319 match res {1320 Ok(()) => Ok(post_info),1321 Err(error) => Err(DispatchErrorWithPostInfo { post_info, error }),1322 }1323}13241325impl<T: Config> From<PropertiesError> for Error<T> {1326 fn from(error: PropertiesError) -> Self {1327 match error {1328 PropertiesError::NoSpaceForProperty => Self::NoSpaceForProperty,1329 PropertiesError::PropertyLimitReached => Self::PropertyLimitReached,1330 PropertiesError::InvalidCharacterInPropertyKey => Self::InvalidCharacterInPropertyKey,1331 PropertiesError::PropertyKeyIsTooLong => Self::PropertyKeyIsTooLong,1332 PropertiesError::EmptyPropertyKey => Self::EmptyPropertyKey,1333 }1334 }1335}pallets/fungible/src/common.rsdiffbeforeafterboth--- a/pallets/fungible/src/common.rs
+++ b/pallets/fungible/src/common.rs
@@ -298,17 +298,9 @@
fail!(<Error<T>>::FungibleDisallowsNesting)
}
- fn nest(
- &self,
- _under: TokenId,
- _to_nest: (CollectionId, TokenId)
- ) {}
+ fn nest(&self, _under: TokenId, _to_nest: (CollectionId, TokenId)) {}
- fn unnest(
- &self,
- _under: TokenId,
- _to_nest: (CollectionId, TokenId)
- ) {}
+ fn unnest(&self, _under: TokenId, _to_nest: (CollectionId, TokenId)) {}
fn collection_tokens(&self) -> Vec<TokenId> {
vec![TokenId::default()]
pallets/fungible/src/lib.rsdiffbeforeafterboth--- a/pallets/fungible/src/lib.rs
+++ b/pallets/fungible/src/lib.rs
@@ -184,11 +184,7 @@
if balance == 0 {
<Balance<T>>::remove((collection.id, owner));
- <PalletStructure<T>>::unnest_if_nested(
- owner,
- collection.id,
- TokenId::default()
- );
+ <PalletStructure<T>>::unnest_if_nested(owner, collection.id, TokenId::default());
} else {
<Balance<T>>::insert((collection.id, owner), balance);
}
@@ -249,18 +245,14 @@
to,
collection.id,
TokenId::default(),
- nesting_budget
+ nesting_budget,
)?;
if let Some(balance_to) = balance_to {
// from != to
if balance_from == 0 {
<Balance<T>>::remove((collection.id, from));
- <PalletStructure<T>>::unnest_if_nested(
- from,
- collection.id,
- TokenId::default()
- );
+ <PalletStructure<T>>::unnest_if_nested(from, collection.id, TokenId::default());
} else {
<Balance<T>>::insert((collection.id, from), balance_from);
}
@@ -333,7 +325,11 @@
<TotalSupply<T>>::insert(collection.id, total_supply);
for (user, amount) in balances {
<Balance<T>>::insert((collection.id, &user), amount);
- <PalletStructure<T>>::nest_if_sent_to_token_unchecked(&user, collection.id, TokenId::default());
+ <PalletStructure<T>>::nest_if_sent_to_token_unchecked(
+ &user,
+ collection.id,
+ TokenId::default(),
+ );
<PalletEvm<T>>::deposit_log(
ERC20Events::Transfer {
from: H160::default(),
pallets/nonfungible/src/common.rsdiffbeforeafterboth--- a/pallets/nonfungible/src/common.rs
+++ b/pallets/nonfungible/src/common.rs
@@ -22,7 +22,7 @@
PropertyKeyPermission, PropertyValue,
};
use pallet_common::{
- CommonCollectionOperations, CommonWeightInfo, with_weight, weights::WeightInfo as _
+ CommonCollectionOperations, CommonWeightInfo, with_weight, weights::WeightInfo as _,
};
use sp_runtime::DispatchError;
use sp_std::vec::Vec;
@@ -353,19 +353,11 @@
<Pallet<T>>::check_nesting(self, sender, from, under, budget)
}
- fn nest(
- &self,
- under: TokenId,
- to_nest: (CollectionId, TokenId)
- ) {
+ fn nest(&self, under: TokenId, to_nest: (CollectionId, TokenId)) {
<Pallet<T>>::nest((self.id, under), to_nest);
}
- fn unnest(
- &self,
- under: TokenId,
- to_unnest: (CollectionId, TokenId)
- ) {
+ fn unnest(&self, under: TokenId, to_unnest: (CollectionId, TokenId)) {
<Pallet<T>>::unnest((self.id, under), to_unnest);
}
@@ -415,10 +407,7 @@
.unwrap_or_else(|| {
properties
.into_iter()
- .map(|(key, value)| Property {
- key,
- value,
- })
+ .map(|(key, value)| Property { key, value })
.collect()
})
}
pallets/nonfungible/src/erc.rsdiffbeforeafterboth--- a/pallets/nonfungible/src/erc.rs
+++ b/pallets/nonfungible/src/erc.rs
@@ -426,11 +426,10 @@
Ok(a)
}
-fn has_token_permission<T: Config>(
- collection_id: CollectionId,
- key: &PropertyKey,
-) -> bool {
- if let Ok(token_property_permissions) = CollectionPropertyPermissions::<T>::try_get(collection_id) {
+fn has_token_permission<T: Config>(collection_id: CollectionId, key: &PropertyKey) -> bool {
+ if let Ok(token_property_permissions) =
+ CollectionPropertyPermissions::<T>::try_get(collection_id)
+ {
return token_property_permissions.contains_key(key);
}
pallets/nonfungible/src/lib.rsdiffbeforeafterboth--- a/pallets/nonfungible/src/lib.rs
+++ b/pallets/nonfungible/src/lib.rs
@@ -164,31 +164,44 @@
fn on_runtime_upgrade() -> Weight {
if StorageVersion::get::<Pallet<T>>() < StorageVersion::new(1) {
let mut had_consts = BTreeSet::new();
- <TokenData<T>>::translate::<ItemDataVersion1<T::CrossAccountId>, _>(|(collection, token), v| {
- let mut props = vec![];
- if !v.const_data.is_empty() {
- props.push(Property {
- key: b"_old_constData".to_vec().try_into().unwrap(),
- value: v.const_data.clone().into_inner().try_into().expect("const too long"),
- });
- had_consts.insert(collection);
- }
- if !v.variable_data.is_empty() {
- props.push(Property {
- key: b"_old_variableData".to_vec().try_into().unwrap(),
- value: v.variable_data.clone().into_inner().try_into().expect("variable too long"),
- })
- }
- if !props.is_empty() {
- Self::set_scoped_token_properties(
- collection,
- token,
- PropertyScope::None,
- props.into_iter(),
- ).expect("existing token data exceeds property storage");
- }
- Some(<ItemDataVersion2<T::CrossAccountId>>::from(v))
- });
+ <TokenData<T>>::translate::<ItemDataVersion1<T::CrossAccountId>, _>(
+ |(collection, token), v| {
+ let mut props = vec![];
+ if !v.const_data.is_empty() {
+ props.push(Property {
+ key: b"_old_constData".to_vec().try_into().unwrap(),
+ value: v
+ .const_data
+ .clone()
+ .into_inner()
+ .try_into()
+ .expect("const too long"),
+ });
+ had_consts.insert(collection);
+ }
+ if !v.variable_data.is_empty() {
+ props.push(Property {
+ key: b"_old_variableData".to_vec().try_into().unwrap(),
+ value: v
+ .variable_data
+ .clone()
+ .into_inner()
+ .try_into()
+ .expect("variable too long"),
+ })
+ }
+ if !props.is_empty() {
+ Self::set_scoped_token_properties(
+ collection,
+ token,
+ PropertyScope::None,
+ props.into_iter(),
+ )
+ .expect("existing token data exceeds property storage");
+ }
+ Some(<ItemDataVersion2<T::CrossAccountId>>::from(v))
+ },
+ );
for collection in had_consts {
<PalletCommon<T>>::set_property_permission_unchecked(
collection,
@@ -199,8 +212,9 @@
collection_admin: true,
token_owner: false,
},
- }
- ).expect("failed to configure permission");
+ },
+ )
+ .expect("failed to configure permission");
}
}
@@ -263,7 +277,7 @@
collection_id: CollectionId,
token_id: TokenId,
scope: PropertyScope,
- properties: impl Iterator<Item=Property>,
+ properties: impl Iterator<Item = Property>,
) -> DispatchResult {
TokenProperties::<T>::try_mutate((collection_id, token_id), |stored_properties| {
stored_properties.try_scoped_set_from_iter(scope, properties)
@@ -347,11 +361,7 @@
<AccountBalance<T>>::insert((collection.id, token_data.owner.clone()), balance);
}
- <PalletStructure<T>>::unnest_if_nested(
- &token_data.owner,
- collection.id,
- token
- );
+ <PalletStructure<T>>::unnest_if_nested(&token_data.owner, collection.id, token);
<Owned<T>>::remove((collection.id, &token_data.owner, token));
<TokensBurnt<T>>::insert(collection.id, burnt);
@@ -589,16 +599,12 @@
to,
collection.id,
token,
- nesting_budget
+ nesting_budget,
)?;
// =========
- <PalletStructure<T>>::unnest_if_nested(
- from,
- collection.id,
- token
- );
+ <PalletStructure<T>>::unnest_if_nested(from, collection.id, token);
<TokenData<T>>::insert(
(collection.id, token),
@@ -709,7 +715,11 @@
},
);
- <PalletStructure<T>>::nest_if_sent_to_token_unchecked(&data.owner, collection.id, TokenId(token));
+ <PalletStructure<T>>::nest_if_sent_to_token_unchecked(
+ &data.owner,
+ collection.id,
+ TokenId(token),
+ );
if let Err(e) = Self::set_token_properties(
collection,
@@ -958,31 +968,24 @@
Ok(())
}
- fn nest(
- under: (CollectionId, TokenId),
- to_nest: (CollectionId, TokenId),
- ) {
- <TokenChildren<T>>::insert(
- (under.0, under.1, (to_nest.0, to_nest.1)),
- true
- );
+ fn nest(under: (CollectionId, TokenId), to_nest: (CollectionId, TokenId)) {
+ <TokenChildren<T>>::insert((under.0, under.1, (to_nest.0, to_nest.1)), true);
}
- fn unnest(
- under: (CollectionId, TokenId),
- to_unnest: (CollectionId, TokenId),
- ) {
- <TokenChildren<T>>::remove(
- (under.0, under.1, to_unnest)
- );
+ fn unnest(under: (CollectionId, TokenId), to_unnest: (CollectionId, TokenId)) {
+ <TokenChildren<T>>::remove((under.0, under.1, to_unnest));
}
fn collection_has_tokens(collection_id: CollectionId) -> bool {
- <TokenData<T>>::iter_prefix((collection_id,)).next().is_some()
+ <TokenData<T>>::iter_prefix((collection_id,))
+ .next()
+ .is_some()
}
fn token_has_children(collection_id: CollectionId, token_id: TokenId) -> bool {
- <TokenChildren<T>>::iter_prefix((collection_id, token_id)).next().is_some()
+ <TokenChildren<T>>::iter_prefix((collection_id, token_id))
+ .next()
+ .is_some()
}
/// Delegated to `create_multiple_items`
pallets/proxy-rmrk-core/src/lib.rsdiffbeforeafterboth--- a/pallets/proxy-rmrk-core/src/lib.rs
+++ b/pallets/proxy-rmrk-core/src/lib.rs
@@ -21,7 +21,9 @@
use sp_runtime::{DispatchError, Permill, traits::StaticLookup};
use sp_std::vec::Vec;
use up_data_structs::*;
-use pallet_common::{Pallet as PalletCommon, Error as CommonError, CollectionHandle, CommonCollectionOperations};
+use pallet_common::{
+ Pallet as PalletCommon, Error as CommonError, CollectionHandle, CommonCollectionOperations,
+};
use pallet_nonfungible::{Pallet as PalletNft, NonfungibleHandle, TokenData};
use pallet_evm::account::CrossAccountId;
use core::convert::AsRef;
@@ -38,18 +40,17 @@
#[frame_support::pallet]
pub mod pallet {
- use super::*;
- use pallet_evm::account;
+ use super::*;
+ use pallet_evm::account;
#[pallet::config]
- pub trait Config: frame_system::Config
- + pallet_common::Config
- + pallet_nonfungible::Config
- + account::Config {
+ pub trait Config:
+ frame_system::Config + pallet_common::Config + pallet_nonfungible::Config + account::Config
+ {
type Event: From<Event<Self>> + IsType<<Self as frame_system::Config>::Event>;
}
- #[pallet::storage]
+ #[pallet::storage]
#[pallet::getter(fn collection_index)]
pub type CollectionIndex<T: Config> = StorageValue<_, RmrkCollectionId, ValueQuery>;
@@ -60,33 +61,33 @@
#[pallet::event]
#[pallet::generate_deposit(pub(super) fn deposit_event)]
pub enum Event<T: Config> {
- CollectionCreated {
+ CollectionCreated {
issuer: T::AccountId,
collection_id: RmrkCollectionId,
},
- CollectionDestroyed {
+ CollectionDestroyed {
issuer: T::AccountId,
collection_id: RmrkCollectionId,
},
- IssuerChanged {
+ IssuerChanged {
old_issuer: T::AccountId,
new_issuer: T::AccountId,
collection_id: RmrkCollectionId,
},
- CollectionLocked {
+ CollectionLocked {
issuer: T::AccountId,
collection_id: RmrkCollectionId,
},
- NftMinted {
+ NftMinted {
owner: T::AccountId,
collection_id: RmrkCollectionId,
nft_id: RmrkNftId,
},
- NFTBurned {
+ NFTBurned {
owner: T::AccountId,
nft_id: RmrkNftId,
},
- PropertySet {
+ PropertySet {
collection_id: RmrkCollectionId,
maybe_nft_id: Option<RmrkNftId>,
key: RmrkKeyString,
@@ -96,24 +97,24 @@
#[pallet::error]
pub enum Error<T> {
- /* Unique-specific events */
- CorruptedCollectionType,
- NftTypeEncodeError,
- RmrkPropertyKeyIsTooLong,
- RmrkPropertyValueIsTooLong,
+ /* Unique-specific events */
+ CorruptedCollectionType,
+ NftTypeEncodeError,
+ RmrkPropertyKeyIsTooLong,
+ RmrkPropertyValueIsTooLong,
- /* RMRK compatible events */
- CollectionNotEmpty,
- NoAvailableCollectionId,
- NoAvailableNftId,
- CollectionUnknown,
- NoPermission,
- CollectionFullOrLocked,
+ /* RMRK compatible events */
+ CollectionNotEmpty,
+ NoAvailableCollectionId,
+ NoAvailableNftId,
+ CollectionUnknown,
+ NoPermission,
+ CollectionFullOrLocked,
}
#[pallet::call]
impl<T: Config> Pallet<T> {
- #[pallet::weight(10_000 + T::DbWeight::get().reads_writes(1,1))]
+ #[pallet::weight(10_000 + T::DbWeight::get().reads_writes(1,1))]
#[transactional]
pub fn create_collection(
origin: OriginFor<T>,
@@ -121,127 +122,141 @@
max: Option<u32>,
symbol: RmrkCollectionSymbol,
) -> DispatchResult {
- let sender = ensure_signed(origin)?;
+ let sender = ensure_signed(origin)?;
- let limits = CollectionLimits {
- owner_can_transfer: Some(false),
- token_limit: max,
- ..Default::default()
- };
+ let limits = CollectionLimits {
+ owner_can_transfer: Some(false),
+ token_limit: max,
+ ..Default::default()
+ };
- let data = CreateCollectionData {
- limits: Some(limits),
- token_prefix: symbol.into_inner()
- .try_into()
- .map_err(|_| <CommonError<T>>::CollectionTokenPrefixLimitExceeded)?,
- ..Default::default()
- };
+ let data = CreateCollectionData {
+ limits: Some(limits),
+ token_prefix: symbol
+ .into_inner()
+ .try_into()
+ .map_err(|_| <CommonError<T>>::CollectionTokenPrefixLimitExceeded)?,
+ ..Default::default()
+ };
- let collection_id_res = <PalletNft<T>>::init_collection(sender.clone(), data);
+ let collection_id_res = <PalletNft<T>>::init_collection(sender.clone(), data);
- if let Err(DispatchError::Arithmetic(_)) = &collection_id_res {
- return Err(<Error<T>>::NoAvailableCollectionId.into());
- }
+ if let Err(DispatchError::Arithmetic(_)) = &collection_id_res {
+ return Err(<Error<T>>::NoAvailableCollectionId.into());
+ }
- let collection_id = collection_id_res?;
+ let collection_id = collection_id_res?;
- <PalletCommon<T>>::set_scoped_collection_properties(
- collection_id,
- PropertyScope::Rmrk,
- [
- Self::rmrk_property(Metadata, &metadata)?,
- Self::rmrk_property(CollectionType, &misc::CollectionType::Regular)?,
- ].into_iter()
- )?;
+ <PalletCommon<T>>::set_scoped_collection_properties(
+ collection_id,
+ PropertyScope::Rmrk,
+ [
+ Self::rmrk_property(Metadata, &metadata)?,
+ Self::rmrk_property(CollectionType, &misc::CollectionType::Regular)?,
+ ]
+ .into_iter(),
+ )?;
- <CollectionIndex<T>>::mutate(|n| *n += 1);
+ <CollectionIndex<T>>::mutate(|n| *n += 1);
- Self::deposit_event(Event::CollectionCreated {
- issuer: sender,
- collection_id: collection_id.0
- });
+ Self::deposit_event(Event::CollectionCreated {
+ issuer: sender,
+ collection_id: collection_id.0,
+ });
- Ok(())
- }
+ Ok(())
+ }
- #[pallet::weight(10_000 + T::DbWeight::get().reads_writes(1,1))]
+ #[pallet::weight(10_000 + T::DbWeight::get().reads_writes(1,1))]
#[transactional]
pub fn destroy_collection(
origin: OriginFor<T>,
collection_id: RmrkCollectionId,
) -> DispatchResult {
- let sender = ensure_signed(origin)?;
- let cross_sender = T::CrossAccountId::from_sub(sender.clone());
+ let sender = ensure_signed(origin)?;
+ let cross_sender = T::CrossAccountId::from_sub(sender.clone());
- let unique_collection_id = collection_id.into();
+ let unique_collection_id = collection_id.into();
- let collection = Self::get_typed_nft_collection(unique_collection_id, misc::CollectionType::Regular)?;
+ let collection = Self::get_typed_nft_collection(
+ unique_collection_id,
+ misc::CollectionType::Regular,
+ )?;
- ensure!(collection.total_supply() == 0, <Error<T>>::CollectionNotEmpty);
+ ensure!(
+ collection.total_supply() == 0,
+ <Error<T>>::CollectionNotEmpty
+ );
- <PalletNft<T>>::destroy_collection(collection, &cross_sender)
- .map_err(Self::map_common_err_to_proxy)?;
+ <PalletNft<T>>::destroy_collection(collection, &cross_sender)
+ .map_err(Self::map_common_err_to_proxy)?;
- Self::deposit_event(Event::CollectionDestroyed { issuer: sender, collection_id });
+ Self::deposit_event(Event::CollectionDestroyed {
+ issuer: sender,
+ collection_id,
+ });
- Ok(())
- }
+ Ok(())
+ }
- #[pallet::weight(10_000 + T::DbWeight::get().reads_writes(1,1))]
+ #[pallet::weight(10_000 + T::DbWeight::get().reads_writes(1,1))]
#[transactional]
pub fn change_collection_issuer(
origin: OriginFor<T>,
collection_id: RmrkCollectionId,
new_issuer: <T::Lookup as StaticLookup>::Source,
) -> DispatchResult {
- let sender = ensure_signed(origin)?;
+ let sender = ensure_signed(origin)?;
- let new_issuer = T::Lookup::lookup(new_issuer)?;
+ let new_issuer = T::Lookup::lookup(new_issuer)?;
- Self::change_collection_owner(
- collection_id.into(),
- misc::CollectionType::Regular,
- sender.clone(),
- new_issuer.clone()
- )?;
+ Self::change_collection_owner(
+ collection_id.into(),
+ misc::CollectionType::Regular,
+ sender.clone(),
+ new_issuer.clone(),
+ )?;
- Self::deposit_event(Event::IssuerChanged {
+ Self::deposit_event(Event::IssuerChanged {
old_issuer: sender,
new_issuer,
collection_id,
});
- Ok(())
- }
+ Ok(())
+ }
- #[pallet::weight(10_000 + T::DbWeight::get().reads_writes(1,1))]
+ #[pallet::weight(10_000 + T::DbWeight::get().reads_writes(1,1))]
#[transactional]
pub fn lock_collection(
origin: OriginFor<T>,
collection_id: RmrkCollectionId,
) -> DispatchResult {
- let sender = ensure_signed(origin)?;
- let cross_sender = T::CrossAccountId::from_sub(sender.clone());
+ let sender = ensure_signed(origin)?;
+ let cross_sender = T::CrossAccountId::from_sub(sender.clone());
- let collection = Self::get_typed_nft_collection(
- collection_id.into(),
- misc::CollectionType::Regular
- )?;
+ let collection = Self::get_typed_nft_collection(
+ collection_id.into(),
+ misc::CollectionType::Regular,
+ )?;
- Self::check_collection_owner(&collection, &cross_sender)?;
+ Self::check_collection_owner(&collection, &cross_sender)?;
- let token_count = collection.total_supply();
+ let token_count = collection.total_supply();
- let mut collection = collection.into_inner();
- collection.limits.token_limit = Some(token_count);
- collection.save()?;
+ let mut collection = collection.into_inner();
+ collection.limits.token_limit = Some(token_count);
+ collection.save()?;
- Self::deposit_event(Event::CollectionLocked { issuer: sender, collection_id });
+ Self::deposit_event(Event::CollectionLocked {
+ issuer: sender,
+ collection_id,
+ });
- Ok(())
- }
+ Ok(())
+ }
- #[pallet::weight(10_000 + T::DbWeight::get().reads_writes(1,1))]
+ #[pallet::weight(10_000 + T::DbWeight::get().reads_writes(1,1))]
#[transactional]
pub fn mint_nft(
origin: OriginFor<T>,
@@ -251,47 +266,49 @@
royalty_amount: Option<Permill>,
metadata: RmrkString,
) -> DispatchResult {
- let sender = ensure_signed(origin)?;
- let sender = T::CrossAccountId::from_sub(sender);
- let cross_owner = T::CrossAccountId::from_sub(owner.clone());
+ let sender = ensure_signed(origin)?;
+ let sender = T::CrossAccountId::from_sub(sender);
+ let cross_owner = T::CrossAccountId::from_sub(owner.clone());
- let royalty_info = royalty_amount.map(|amount| rmrk::RoyaltyInfo {
- recipient: recipient.unwrap_or_else(|| owner.clone()),
- amount
- });
+ let royalty_info = royalty_amount.map(|amount| rmrk::RoyaltyInfo {
+ recipient: recipient.unwrap_or_else(|| owner.clone()),
+ amount,
+ });
- let collection = Self::get_typed_nft_collection(
- collection_id.into(),
- misc::CollectionType::Regular,
- )?;
+ let collection = Self::get_typed_nft_collection(
+ collection_id.into(),
+ misc::CollectionType::Regular,
+ )?;
- let nft_id = Self::create_nft(
- &sender,
- &cross_owner,
- &collection,
- NftType::Regular,
- [
- Self::rmrk_property(RoyaltyInfo, &royalty_info)?,
- Self::rmrk_property(Metadata, &metadata)?,
- Self::rmrk_property(Equipped, &false)?,
- Self::rmrk_property(ResourceCollection, &None::<CollectionId>)?,
- Self::rmrk_property(ResourcePriorities, &<Vec<u8>>::new())?,
- ].into_iter()
- ).map_err(|err| match err {
- DispatchError::Arithmetic(_) => <Error<T>>::NoAvailableNftId.into(),
- err => Self::map_common_err_to_proxy(err)
- })?;
+ let nft_id = Self::create_nft(
+ &sender,
+ &cross_owner,
+ &collection,
+ NftType::Regular,
+ [
+ Self::rmrk_property(RoyaltyInfo, &royalty_info)?,
+ Self::rmrk_property(Metadata, &metadata)?,
+ Self::rmrk_property(Equipped, &false)?,
+ Self::rmrk_property(ResourceCollection, &None::<CollectionId>)?,
+ Self::rmrk_property(ResourcePriorities, &<Vec<u8>>::new())?,
+ ]
+ .into_iter(),
+ )
+ .map_err(|err| match err {
+ DispatchError::Arithmetic(_) => <Error<T>>::NoAvailableNftId.into(),
+ err => Self::map_common_err_to_proxy(err),
+ })?;
- Self::deposit_event(Event::NftMinted {
- owner,
- collection_id,
- nft_id: nft_id.0
- });
+ Self::deposit_event(Event::NftMinted {
+ owner,
+ collection_id,
+ nft_id: nft_id.0,
+ });
- Ok(())
- }
+ Ok(())
+ }
- #[pallet::weight(10_000 + T::DbWeight::get().reads_writes(1,1))]
+ #[pallet::weight(10_000 + T::DbWeight::get().reads_writes(1,1))]
#[transactional]
pub fn burn_nft(
origin: OriginFor<T>,
@@ -299,21 +316,24 @@
nft_id: RmrkNftId,
) -> DispatchResult {
let sender = ensure_signed(origin)?;
- let cross_sender = T::CrossAccountId::from_sub(sender.clone());
+ let cross_sender = T::CrossAccountId::from_sub(sender.clone());
- Self::destroy_nft(
- cross_sender,
- collection_id.into(),
- misc::CollectionType::Regular,
- nft_id.into()
- )?;
+ Self::destroy_nft(
+ cross_sender,
+ collection_id.into(),
+ misc::CollectionType::Regular,
+ nft_id.into(),
+ )?;
- Self::deposit_event(Event::NFTBurned { owner: sender, nft_id });
+ Self::deposit_event(Event::NFTBurned {
+ owner: sender,
+ nft_id,
+ });
- Ok(())
- }
+ Ok(())
+ }
- #[pallet::weight(10_000 + T::DbWeight::get().reads_writes(1,1))]
+ #[pallet::weight(10_000 + T::DbWeight::get().reads_writes(1,1))]
#[transactional]
pub fn set_property(
origin: OriginFor<T>,
@@ -322,323 +342,346 @@
key: RmrkKeyString,
value: RmrkValueString,
) -> DispatchResult {
- let sender = ensure_signed(origin)?;
- let sender = T::CrossAccountId::from_sub(sender);
+ let sender = ensure_signed(origin)?;
+ let sender = T::CrossAccountId::from_sub(sender);
- let collection_id: CollectionId = rmrk_collection_id.into();
+ let collection_id: CollectionId = rmrk_collection_id.into();
- match maybe_nft_id {
- Some(nft_id) => {
- let token_id: TokenId = nft_id.into();
+ match maybe_nft_id {
+ Some(nft_id) => {
+ let token_id: TokenId = nft_id.into();
- Self::ensure_nft_owner(collection_id, token_id, &sender)?;
- Self::ensure_nft_type(collection_id, token_id, NftType::Regular)?;
+ Self::ensure_nft_owner(collection_id, token_id, &sender)?;
+ Self::ensure_nft_type(collection_id, token_id, NftType::Regular)?;
- <PalletNft<T>>::set_scoped_token_property(
- collection_id,
- token_id,
- PropertyScope::Rmrk,
- Self::rmrk_property(UserProperty(key.as_slice()), &value)?
- )?;
- },
- None => {
- let collection = Self::get_typed_nft_collection(
- collection_id,
- misc::CollectionType::Regular
- )?;
+ <PalletNft<T>>::set_scoped_token_property(
+ collection_id,
+ token_id,
+ PropertyScope::Rmrk,
+ Self::rmrk_property(UserProperty(key.as_slice()), &value)?,
+ )?;
+ }
+ None => {
+ let collection = Self::get_typed_nft_collection(
+ collection_id,
+ misc::CollectionType::Regular,
+ )?;
- Self::check_collection_owner(&collection, &sender)?;
+ Self::check_collection_owner(&collection, &sender)?;
- <PalletCommon<T>>::set_scoped_collection_property(
- collection_id,
- PropertyScope::Rmrk,
- Self::rmrk_property(UserProperty(key.as_slice()), &value)?
- )?;
- }
- }
+ <PalletCommon<T>>::set_scoped_collection_property(
+ collection_id,
+ PropertyScope::Rmrk,
+ Self::rmrk_property(UserProperty(key.as_slice()), &value)?,
+ )?;
+ }
+ }
- Self::deposit_event(
- Event::PropertySet {
- collection_id: rmrk_collection_id,
- maybe_nft_id,
- key,
- value
- }
- );
+ Self::deposit_event(Event::PropertySet {
+ collection_id: rmrk_collection_id,
+ maybe_nft_id,
+ key,
+ value,
+ });
- Ok(())
- }
+ Ok(())
+ }
}
}
impl<T: Config> Pallet<T> {
- pub fn rmrk_property_key(rmrk_key: RmrkProperty) -> Result<PropertyKey, DispatchError> {
- let key = rmrk_key.to_key::<T>()?;
+ pub fn rmrk_property_key(rmrk_key: RmrkProperty) -> Result<PropertyKey, DispatchError> {
+ let key = rmrk_key.to_key::<T>()?;
- let scoped_key = PropertyScope::Rmrk.apply(key)
- .map_err(|_| <Error<T>>::RmrkPropertyKeyIsTooLong)?;
+ let scoped_key = PropertyScope::Rmrk
+ .apply(key)
+ .map_err(|_| <Error<T>>::RmrkPropertyKeyIsTooLong)?;
- Ok(scoped_key)
- }
+ Ok(scoped_key)
+ }
- pub fn rmrk_property<E: Encode>(rmrk_key: RmrkProperty, value: &E) -> Result<Property, DispatchError> {
- let key = rmrk_key.to_key::<T>()?;
+ pub fn rmrk_property<E: Encode>(
+ rmrk_key: RmrkProperty,
+ value: &E,
+ ) -> Result<Property, DispatchError> {
+ let key = rmrk_key.to_key::<T>()?;
- let value = value.encode()
- .try_into()
- .map_err(|_| <Error<T>>::RmrkPropertyValueIsTooLong)?;
+ let value = value
+ .encode()
+ .try_into()
+ .map_err(|_| <Error<T>>::RmrkPropertyValueIsTooLong)?;
- let property = Property {
- key,
- value,
- };
+ let property = Property { key, value };
- Ok(property)
- }
+ Ok(property)
+ }
- pub fn create_nft(
- sender: &T::CrossAccountId,
- owner: &T::CrossAccountId,
- collection: &NonfungibleHandle<T>,
- nft_type: NftType,
- properties: impl Iterator<Item=Property>
- ) -> Result<TokenId, DispatchError> {
- todo!("store nft type");
- let data = CreateNftExData {
- properties: BoundedVec::default(),
- owner: owner.clone(),
- };
+ pub fn create_nft(
+ sender: &T::CrossAccountId,
+ owner: &T::CrossAccountId,
+ collection: &NonfungibleHandle<T>,
+ nft_type: NftType,
+ properties: impl Iterator<Item = Property>,
+ ) -> Result<TokenId, DispatchError> {
+ todo!("store nft type");
+ let data = CreateNftExData {
+ properties: BoundedVec::default(),
+ owner: owner.clone(),
+ };
- let budget = budget::Value::new(2);
+ let budget = budget::Value::new(2);
- <PalletNft<T>>::create_item(
- collection,
- sender,
- data,
- &budget,
- )?;
+ <PalletNft<T>>::create_item(collection, sender, data, &budget)?;
- let nft_id = <PalletNft<T>>::current_token_id(collection.id);
+ let nft_id = <PalletNft<T>>::current_token_id(collection.id);
- <PalletNft<T>>::set_scoped_token_properties(
- collection.id,
- nft_id,
- PropertyScope::Rmrk,
- properties
- )?;
+ <PalletNft<T>>::set_scoped_token_properties(
+ collection.id,
+ nft_id,
+ PropertyScope::Rmrk,
+ properties,
+ )?;
- Ok(nft_id)
- }
+ Ok(nft_id)
+ }
- fn destroy_nft(
- sender: T::CrossAccountId,
- collection_id: CollectionId,
- collection_type: misc::CollectionType,
- token_id: TokenId
- ) -> DispatchResult {
- let collection = Self::get_typed_nft_collection(
- collection_id,
- collection_type
- )?;
+ fn destroy_nft(
+ sender: T::CrossAccountId,
+ collection_id: CollectionId,
+ collection_type: misc::CollectionType,
+ token_id: TokenId,
+ ) -> DispatchResult {
+ let collection = Self::get_typed_nft_collection(collection_id, collection_type)?;
- <PalletNft<T>>::burn(&collection, &sender, token_id)
- .map_err(Self::map_common_err_to_proxy)?;
+ <PalletNft<T>>::burn(&collection, &sender, token_id)
+ .map_err(Self::map_common_err_to_proxy)?;
- Ok(())
- }
+ Ok(())
+ }
- fn change_collection_owner(
- collection_id: CollectionId,
- collection_type: misc::CollectionType,
- sender: T::AccountId,
- new_owner: T::AccountId,
- ) -> DispatchResult {
- let collection = Self::get_typed_nft_collection(
- collection_id,
- collection_type
- )?;
- Self::check_collection_owner(&collection, &T::CrossAccountId::from_sub(sender))?;
+ fn change_collection_owner(
+ collection_id: CollectionId,
+ collection_type: misc::CollectionType,
+ sender: T::AccountId,
+ new_owner: T::AccountId,
+ ) -> DispatchResult {
+ let collection = Self::get_typed_nft_collection(collection_id, collection_type)?;
+ Self::check_collection_owner(&collection, &T::CrossAccountId::from_sub(sender))?;
- let mut collection = collection.into_inner();
+ let mut collection = collection.into_inner();
- collection.owner = new_owner;
- collection.save()
- }
+ collection.owner = new_owner;
+ collection.save()
+ }
- fn check_collection_owner(collection: &NonfungibleHandle<T>, account: &T::CrossAccountId) -> DispatchResult {
- collection.check_is_owner(account)
- .map_err(Self::map_common_err_to_proxy)
- }
+ fn check_collection_owner(
+ collection: &NonfungibleHandle<T>,
+ account: &T::CrossAccountId,
+ ) -> DispatchResult {
+ collection
+ .check_is_owner(account)
+ .map_err(Self::map_common_err_to_proxy)
+ }
- pub fn last_collection_idx() -> RmrkCollectionId {
- <CollectionIndex<T>>::get()
- }
+ pub fn last_collection_idx() -> RmrkCollectionId {
+ <CollectionIndex<T>>::get()
+ }
- pub fn get_nft_collection(collection_id: CollectionId) -> Result<NonfungibleHandle<T>, DispatchError> {
- let collection = <CollectionHandle<T>>::try_get(collection_id)
- .map_err(|_| <Error<T>>::CollectionUnknown)?;
+ pub fn get_nft_collection(
+ collection_id: CollectionId,
+ ) -> Result<NonfungibleHandle<T>, DispatchError> {
+ let collection = <CollectionHandle<T>>::try_get(collection_id)
+ .map_err(|_| <Error<T>>::CollectionUnknown)?;
- match collection.mode {
- CollectionMode::NFT => Ok(NonfungibleHandle::cast(collection)),
- _ => Err(<Error<T>>::CollectionUnknown.into())
- }
- }
+ match collection.mode {
+ CollectionMode::NFT => Ok(NonfungibleHandle::cast(collection)),
+ _ => Err(<Error<T>>::CollectionUnknown.into()),
+ }
+ }
- pub fn collection_exists(collection_id: CollectionId) -> bool {
- <CollectionHandle<T>>::try_get(collection_id).is_ok()
- }
+ pub fn collection_exists(collection_id: CollectionId) -> bool {
+ <CollectionHandle<T>>::try_get(collection_id).is_ok()
+ }
- pub fn nft_exists(collection_id: CollectionId, nft_id: TokenId) -> bool {
- <TokenData<T>>::contains_key((collection_id, nft_id))
- }
+ pub fn nft_exists(collection_id: CollectionId, nft_id: TokenId) -> bool {
+ <TokenData<T>>::contains_key((collection_id, nft_id))
+ }
- pub fn get_collection_property(collection_id: CollectionId, key: RmrkProperty) -> Result<PropertyValue, DispatchError> {
- let collection_property = <PalletCommon<T>>::collection_properties(collection_id)
- .get(&Self::rmrk_property_key(key)?)
- .ok_or(<Error<T>>::CollectionUnknown)?
- .clone();
+ pub fn get_collection_property(
+ collection_id: CollectionId,
+ key: RmrkProperty,
+ ) -> Result<PropertyValue, DispatchError> {
+ let collection_property = <PalletCommon<T>>::collection_properties(collection_id)
+ .get(&Self::rmrk_property_key(key)?)
+ .ok_or(<Error<T>>::CollectionUnknown)?
+ .clone();
- Ok(collection_property)
- }
+ Ok(collection_property)
+ }
- pub fn get_collection_type(collection_id: CollectionId) -> Result<misc::CollectionType, DispatchError> {
- let value = Self::get_collection_property(collection_id, CollectionType)?;
+ pub fn get_collection_type(
+ collection_id: CollectionId,
+ ) -> Result<misc::CollectionType, DispatchError> {
+ let value = Self::get_collection_property(collection_id, CollectionType)?;
- let mut value = value.as_slice();
+ let mut value = value.as_slice();
- misc::CollectionType::decode(&mut value)
- .map_err(|_| <Error<T>>::CorruptedCollectionType.into())
- }
+ misc::CollectionType::decode(&mut value)
+ .map_err(|_| <Error<T>>::CorruptedCollectionType.into())
+ }
- pub fn ensure_collection_type(collection_id: CollectionId, collection_type: misc::CollectionType) -> DispatchResult {
- let actual_type = Self::get_collection_type(collection_id)?;
- ensure!(actual_type == collection_type, <CommonError<T>>::NoPermission);
+ pub fn ensure_collection_type(
+ collection_id: CollectionId,
+ collection_type: misc::CollectionType,
+ ) -> DispatchResult {
+ let actual_type = Self::get_collection_type(collection_id)?;
+ ensure!(
+ actual_type == collection_type,
+ <CommonError<T>>::NoPermission
+ );
- Ok(())
- }
+ Ok(())
+ }
- pub fn get_nft_property(collection_id: CollectionId, nft_id: TokenId, key: RmrkProperty) -> Result<PropertyValue, DispatchError> {
- let nft_property = <PalletNft<T>>::token_properties((collection_id, nft_id))
- .get(&Self::rmrk_property_key(key)?)
- .ok_or(<Error<T>>::NoAvailableNftId)?
- .clone();
+ pub fn get_nft_property(
+ collection_id: CollectionId,
+ nft_id: TokenId,
+ key: RmrkProperty,
+ ) -> Result<PropertyValue, DispatchError> {
+ let nft_property = <PalletNft<T>>::token_properties((collection_id, nft_id))
+ .get(&Self::rmrk_property_key(key)?)
+ .ok_or(<Error<T>>::NoAvailableNftId)?
+ .clone();
- Ok(nft_property)
- }
+ Ok(nft_property)
+ }
- pub fn get_nft_type(_collection_id: CollectionId, _token_id: TokenId) -> Result<NftType, DispatchError> {
- todo!("should get it from properties?")
- }
+ pub fn get_nft_type(
+ _collection_id: CollectionId,
+ _token_id: TokenId,
+ ) -> Result<NftType, DispatchError> {
+ todo!("should get it from properties?")
+ }
- pub fn ensure_nft_type(collection_id: CollectionId, token_id: TokenId, nft_type: NftType) -> DispatchResult {
- let actual_type = Self::get_nft_type(collection_id, token_id)?;
- ensure!(actual_type == nft_type, <Error<T>>::NoPermission);
+ pub fn ensure_nft_type(
+ collection_id: CollectionId,
+ token_id: TokenId,
+ nft_type: NftType,
+ ) -> DispatchResult {
+ let actual_type = Self::get_nft_type(collection_id, token_id)?;
+ ensure!(actual_type == nft_type, <Error<T>>::NoPermission);
- Ok(())
- }
+ Ok(())
+ }
- pub fn ensure_nft_owner(
- collection_id: CollectionId,
- token_id: TokenId,
- possible_owner: &T::CrossAccountId
- ) -> DispatchResult {
- let token_data = <TokenData<T>>::get((collection_id, token_id))
- .ok_or(<Error<T>>::NoAvailableNftId)?;
+ pub fn ensure_nft_owner(
+ collection_id: CollectionId,
+ token_id: TokenId,
+ possible_owner: &T::CrossAccountId,
+ ) -> DispatchResult {
+ let token_data =
+ <TokenData<T>>::get((collection_id, token_id)).ok_or(<Error<T>>::NoAvailableNftId)?;
- ensure!(token_data.owner == *possible_owner, <Error<T>>::NoPermission);
+ ensure!(
+ token_data.owner == *possible_owner,
+ <Error<T>>::NoPermission
+ );
- Ok(())
- }
+ Ok(())
+ }
- pub fn filter_user_properties<Key, Value, R, Mapper>(
- collection_id: CollectionId,
- token_id: Option<TokenId>,
- filter_keys: Option<Vec<RmrkPropertyKey>>,
- mapper: Mapper,
- ) -> Result<Vec<R>, DispatchError>
- where
- Key: TryFrom<RmrkPropertyKey> + AsRef<[u8]>,
- Value: Decode + Default,
- Mapper: Fn(Key, Value) -> R
- {
- filter_keys.map(|keys| {
- let properties = keys.into_iter()
- .filter_map(|key| {
- let key: Key = key.try_into().ok()?;
+ pub fn filter_user_properties<Key, Value, R, Mapper>(
+ collection_id: CollectionId,
+ token_id: Option<TokenId>,
+ filter_keys: Option<Vec<RmrkPropertyKey>>,
+ mapper: Mapper,
+ ) -> Result<Vec<R>, DispatchError>
+ where
+ Key: TryFrom<RmrkPropertyKey> + AsRef<[u8]>,
+ Value: Decode + Default,
+ Mapper: Fn(Key, Value) -> R,
+ {
+ filter_keys
+ .map(|keys| {
+ let properties = keys
+ .into_iter()
+ .filter_map(|key| {
+ let key: Key = key.try_into().ok()?;
- let value = match token_id {
- Some(token_id) => Self::get_nft_property(
- collection_id,
- token_id,
- UserProperty(key.as_ref())
- ),
- None => Self::get_collection_property(
- collection_id,
- UserProperty(key.as_ref())
- )
- }.ok()?.decode_or_default();
+ let value = match token_id {
+ Some(token_id) => Self::get_nft_property(
+ collection_id,
+ token_id,
+ UserProperty(key.as_ref()),
+ ),
+ None => Self::get_collection_property(
+ collection_id,
+ UserProperty(key.as_ref()),
+ ),
+ }
+ .ok()?
+ .decode_or_default();
- Some(mapper(key, value))
- })
- .collect();
+ Some(mapper(key, value))
+ })
+ .collect();
- Ok(properties)
- }).unwrap_or_else(|| {
- let properties = Self::iterate_user_properties(collection_id, token_id, mapper)?
- .collect();
+ Ok(properties)
+ })
+ .unwrap_or_else(|| {
+ let properties =
+ Self::iterate_user_properties(collection_id, token_id, mapper)?.collect();
- Ok(properties)
- })
- }
+ Ok(properties)
+ })
+ }
- pub fn iterate_user_properties<Key, Value, R, Mapper>(
- collection_id: CollectionId,
- token_id: Option<TokenId>,
- mapper: Mapper,
- ) -> Result<impl Iterator<Item=R>, DispatchError>
- where
- Key: TryFrom<RmrkPropertyKey> + AsRef<[u8]>,
- Value: Decode + Default,
- Mapper: Fn(Key, Value) -> R
- {
- let key_prefix = Self::rmrk_property_key(UserProperty(b""))?;
+ pub fn iterate_user_properties<Key, Value, R, Mapper>(
+ collection_id: CollectionId,
+ token_id: Option<TokenId>,
+ mapper: Mapper,
+ ) -> Result<impl Iterator<Item = R>, DispatchError>
+ where
+ Key: TryFrom<RmrkPropertyKey> + AsRef<[u8]>,
+ Value: Decode + Default,
+ Mapper: Fn(Key, Value) -> R,
+ {
+ let key_prefix = Self::rmrk_property_key(UserProperty(b""))?;
- let properties = match token_id {
- Some(token_id) => <PalletNft<T>>::token_properties((collection_id, token_id)),
- None => <PalletCommon<T>>::collection_properties(collection_id)
- };
+ let properties = match token_id {
+ Some(token_id) => <PalletNft<T>>::token_properties((collection_id, token_id)),
+ None => <PalletCommon<T>>::collection_properties(collection_id),
+ };
- let properties = properties
- .into_iter()
- .filter_map(move |(key, value)| {
- let key = key.as_slice().strip_prefix(key_prefix.as_slice())?;
+ let properties = properties.into_iter().filter_map(move |(key, value)| {
+ let key = key.as_slice().strip_prefix(key_prefix.as_slice())?;
- let key: Key = key.to_vec().try_into().ok()?;
- let value: Value = value.decode_or_default();
+ let key: Key = key.to_vec().try_into().ok()?;
+ let value: Value = value.decode_or_default();
- Some(mapper(key, value))
- });
+ Some(mapper(key, value))
+ });
- Ok(properties)
- }
+ Ok(properties)
+ }
- pub fn get_typed_nft_collection(
- collection_id: CollectionId,
- collection_type: misc::CollectionType
- ) -> Result<NonfungibleHandle<T>, DispatchError> {
- Self::ensure_collection_type(collection_id, collection_type)?;
+ pub fn get_typed_nft_collection(
+ collection_id: CollectionId,
+ collection_type: misc::CollectionType,
+ ) -> Result<NonfungibleHandle<T>, DispatchError> {
+ Self::ensure_collection_type(collection_id, collection_type)?;
- Self::get_nft_collection(collection_id)
- }
+ Self::get_nft_collection(collection_id)
+ }
- fn map_common_err_to_proxy(err: DispatchError) -> DispatchError {
- map_common_err_to_proxy! {
- match err {
- NoPermission => NoPermission,
- CollectionTokenLimitExceeded => CollectionFullOrLocked,
- PublicMintingNotAllowed => NoPermission,
- TokenNotFound => NoAvailableNftId
- }
- }
- }
+ fn map_common_err_to_proxy(err: DispatchError) -> DispatchError {
+ map_common_err_to_proxy! {
+ match err {
+ NoPermission => NoPermission,
+ CollectionTokenLimitExceeded => CollectionFullOrLocked,
+ PublicMintingNotAllowed => NoPermission,
+ TokenNotFound => NoAvailableNftId
+ }
+ }
+ }
}
pallets/proxy-rmrk-core/src/misc.rsdiffbeforeafterboth--- a/pallets/proxy-rmrk-core/src/misc.rs
+++ b/pallets/proxy-rmrk-core/src/misc.rs
@@ -15,41 +15,42 @@
}
pub trait RmrkDecode<T: Decode + Default, S> {
- fn decode_or_default(&self) -> T;
+ fn decode_or_default(&self) -> T;
}
impl<T: Decode + Default, S> RmrkDecode<T, S> for BoundedVec<u8, S> {
- fn decode_or_default(&self) -> T {
- let mut value = self.as_slice();
+ fn decode_or_default(&self) -> T {
+ let mut value = self.as_slice();
- T::decode(&mut value).unwrap_or_default()
- }
+ T::decode(&mut value).unwrap_or_default()
+ }
}
pub trait RmrkRebind<T, S> {
- fn rebind(&self) -> BoundedVec<u8, S>;
+ fn rebind(&self) -> BoundedVec<u8, S>;
}
-impl<T, S> RmrkRebind<T, S> for BoundedVec<u8, T> where BoundedVec<u8, S>: TryFrom<Vec<u8>> {
- fn rebind(&self) -> BoundedVec<u8, S> {
- BoundedVec::<u8, S>::try_from(
- self.clone().into_inner()
- ).unwrap_or_default()
- }
+impl<T, S> RmrkRebind<T, S> for BoundedVec<u8, T>
+where
+ BoundedVec<u8, S>: TryFrom<Vec<u8>>,
+{
+ fn rebind(&self) -> BoundedVec<u8, S> {
+ BoundedVec::<u8, S>::try_from(self.clone().into_inner()).unwrap_or_default()
+ }
}
#[derive(Encode, Decode, PartialEq, Eq)]
pub enum CollectionType {
- Regular,
- Resource,
- Base,
+ Regular,
+ Resource,
+ Base,
}
#[derive(Encode, Decode, PartialEq, Eq)]
pub enum NftType {
- Regular,
- Resource,
- FixedPart,
- SlotPart,
- Theme
+ Regular,
+ Resource,
+ FixedPart,
+ SlotPart,
+ Theme,
}
pallets/proxy-rmrk-core/src/property.rsdiffbeforeafterboth--- a/pallets/proxy-rmrk-core/src/property.rs
+++ b/pallets/proxy-rmrk-core/src/property.rs
@@ -2,38 +2,38 @@
use core::convert::AsRef;
pub enum RmrkProperty<'r> {
- Metadata,
- CollectionType,
- RoyaltyInfo,
- Equipped,
- ResourceCollection,
- ResourcePriorities,
- ResourceType,
- PendingResourceAccept,
- PendingResourceRemoval,
- Parts,
- Base,
- Src,
- Slot,
- License,
- Thumb,
- EquippedNft,
- BaseType,
- ExternalPartId,
- EquippableList,
- ZIndex,
- ThemeName,
- ThemeInherit,
- UserProperty(&'r [u8]),
+ Metadata,
+ CollectionType,
+ RoyaltyInfo,
+ Equipped,
+ ResourceCollection,
+ ResourcePriorities,
+ ResourceType,
+ PendingResourceAccept,
+ PendingResourceRemoval,
+ Parts,
+ Base,
+ Src,
+ Slot,
+ License,
+ Thumb,
+ EquippedNft,
+ BaseType,
+ ExternalPartId,
+ EquippableList,
+ ZIndex,
+ ThemeName,
+ ThemeInherit,
+ UserProperty(&'r [u8]),
}
impl<'r> RmrkProperty<'r> {
- pub fn to_key<T: Config>(self) -> Result<PropertyKey, Error<T>> {
- fn get_bytes<T: AsRef<[u8]>>(container: &T) -> &[u8] {
- container.as_ref()
- }
+ pub fn to_key<T: Config>(self) -> Result<PropertyKey, Error<T>> {
+ fn get_bytes<T: AsRef<[u8]>>(container: &T) -> &[u8] {
+ container.as_ref()
+ }
- macro_rules! key {
+ macro_rules! key {
($($component:expr),+) => {
PropertyKey::try_from([$(key!(@ &$component)),+].concat())
.map_err(|_| <Error<T>>::RmrkPropertyKeyIsTooLong)
@@ -44,30 +44,30 @@
};
}
- match self {
- Self::Metadata => key!("metadata"),
- Self::CollectionType => key!("collection-type"),
- Self::RoyaltyInfo => key!("royalty-info"),
- Self::Equipped => key!("equipped"),
- Self::ResourceCollection => key!("resource-collection"),
- Self::ResourcePriorities => key!("resource-priorities"),
- Self::ResourceType => key!("resource-type"),
- Self::PendingResourceAccept => key!("pending-accept"),
- Self::PendingResourceRemoval => key!("pending-removal"),
- Self::Parts => key!("parts"),
- Self::Base => key!("base"),
- Self::Src => key!("src"),
- Self::Slot => key!("slot"),
- Self::License => key!("license"),
- Self::Thumb => key!("thumb"),
- Self::EquippedNft => key!("equipped-nft"),
- Self::BaseType => key!("base-type"),
- Self::ExternalPartId => key!("ext-part-id"),
- Self::EquippableList => key!("equippable-list"),
- Self::ZIndex => key!("z-index"),
- Self::ThemeName => key!("theme-name"),
- Self::ThemeInherit => key!("theme-inherit"),
- Self::UserProperty(name) => key!("userprop-", name),
- }
- }
+ match self {
+ Self::Metadata => key!("metadata"),
+ Self::CollectionType => key!("collection-type"),
+ Self::RoyaltyInfo => key!("royalty-info"),
+ Self::Equipped => key!("equipped"),
+ Self::ResourceCollection => key!("resource-collection"),
+ Self::ResourcePriorities => key!("resource-priorities"),
+ Self::ResourceType => key!("resource-type"),
+ Self::PendingResourceAccept => key!("pending-accept"),
+ Self::PendingResourceRemoval => key!("pending-removal"),
+ Self::Parts => key!("parts"),
+ Self::Base => key!("base"),
+ Self::Src => key!("src"),
+ Self::Slot => key!("slot"),
+ Self::License => key!("license"),
+ Self::Thumb => key!("thumb"),
+ Self::EquippedNft => key!("equipped-nft"),
+ Self::BaseType => key!("base-type"),
+ Self::ExternalPartId => key!("ext-part-id"),
+ Self::EquippableList => key!("equippable-list"),
+ Self::ZIndex => key!("z-index"),
+ Self::ThemeName => key!("theme-name"),
+ Self::ThemeInherit => key!("theme-inherit"),
+ Self::UserProperty(name) => key!("userprop-", name),
+ }
+ }
}
pallets/proxy-rmrk-equip/src/lib.rsdiffbeforeafterboth--- a/pallets/proxy-rmrk-equip/src/lib.rs
+++ b/pallets/proxy-rmrk-equip/src/lib.rs
@@ -21,7 +21,11 @@
use sp_runtime::DispatchError;
use up_data_structs::*;
use pallet_common::{Pallet as PalletCommon, Error as CommonError};
-use pallet_rmrk_core::{Pallet as PalletCore, misc::{self, *}, property::RmrkProperty::*};
+use pallet_rmrk_core::{
+ Pallet as PalletCore,
+ misc::{self, *},
+ property::RmrkProperty::*,
+};
use pallet_nonfungible::{Pallet as PalletNft, NonfungibleHandle};
use pallet_evm::account::CrossAccountId;
@@ -29,212 +33,206 @@
#[frame_support::pallet]
pub mod pallet {
- use super::*;
+ use super::*;
#[pallet::config]
- pub trait Config: frame_system::Config
- + pallet_rmrk_core::Config {
+ pub trait Config: frame_system::Config + pallet_rmrk_core::Config {
type Event: From<Event<Self>> + IsType<<Self as frame_system::Config>::Event>;
}
- #[pallet::storage]
+ #[pallet::storage]
#[pallet::getter(fn internal_part_id)]
- pub type InernalPartId<T: Config> = StorageDoubleMap<
- _,
- Twox64Concat,
- CollectionId,
- Twox64Concat,
- RmrkPartId,
- TokenId
- >;
+ pub type InernalPartId<T: Config> =
+ StorageDoubleMap<_, Twox64Concat, CollectionId, Twox64Concat, RmrkPartId, TokenId>;
- #[pallet::storage]
+ #[pallet::storage]
#[pallet::getter(fn base_has_default_theme)]
- pub type BaseHasDefaultTheme<T: Config> = StorageMap<
- _,
- Twox64Concat,
- CollectionId,
- bool,
- ValueQuery
- >;
+ pub type BaseHasDefaultTheme<T: Config> =
+ StorageMap<_, Twox64Concat, CollectionId, bool, ValueQuery>;
- #[pallet::pallet]
+ #[pallet::pallet]
#[pallet::generate_store(pub(super) trait Store)]
pub struct Pallet<T>(_);
#[pallet::event]
#[pallet::generate_deposit(pub(super) fn deposit_event)]
pub enum Event<T: Config> {
- BaseCreated {
+ BaseCreated {
issuer: T::AccountId,
base_id: RmrkBaseId,
},
- }
+ }
- #[pallet::error]
+ #[pallet::error]
pub enum Error<T> {
- PermissionError,
- NoAvailableBaseId,
- NoAvailablePartId,
- BaseDoesntExist,
- NeedsDefaultThemeFirst,
- }
+ PermissionError,
+ NoAvailableBaseId,
+ NoAvailablePartId,
+ BaseDoesntExist,
+ NeedsDefaultThemeFirst,
+ }
- #[pallet::call]
+ #[pallet::call]
impl<T: Config> Pallet<T> {
- #[pallet::weight(10_000 + T::DbWeight::get().reads_writes(1,1))]
- #[transactional]
+ #[pallet::weight(10_000 + T::DbWeight::get().reads_writes(1,1))]
+ #[transactional]
pub fn create_base(
origin: OriginFor<T>,
base_type: RmrkString,
symbol: RmrkString,
parts: BoundedVec<RmrkPartType, RmrkPartsLimit>,
) -> DispatchResult {
- let sender = ensure_signed(origin)?;
- let cross_sender = T::CrossAccountId::from_sub(sender.clone());
+ let sender = ensure_signed(origin)?;
+ let cross_sender = T::CrossAccountId::from_sub(sender.clone());
- let data = CreateCollectionData {
- limits: None,
- token_prefix: symbol.into_inner()
- .try_into()
- .map_err(|_| <CommonError<T>>::CollectionTokenPrefixLimitExceeded)?,
- ..Default::default()
- };
+ let data = CreateCollectionData {
+ limits: None,
+ token_prefix: symbol
+ .into_inner()
+ .try_into()
+ .map_err(|_| <CommonError<T>>::CollectionTokenPrefixLimitExceeded)?,
+ ..Default::default()
+ };
- let collection_id_res = <PalletNft<T>>::init_collection(sender.clone(), data);
+ let collection_id_res = <PalletNft<T>>::init_collection(sender.clone(), data);
- if let Err(DispatchError::Arithmetic(_)) = &collection_id_res {
- return Err(<Error<T>>::NoAvailableBaseId.into());
- }
+ if let Err(DispatchError::Arithmetic(_)) = &collection_id_res {
+ return Err(<Error<T>>::NoAvailableBaseId.into());
+ }
- let collection_id = collection_id_res?;
+ let collection_id = collection_id_res?;
- <PalletCommon<T>>::set_scoped_collection_properties(
- collection_id,
- PropertyScope::Rmrk,
- [
- <PalletCore<T>>::rmrk_property(CollectionType, &misc::CollectionType::Base)?,
- <PalletCore<T>>::rmrk_property(BaseType, &base_type)?,
- ].into_iter()
- )?;
+ <PalletCommon<T>>::set_scoped_collection_properties(
+ collection_id,
+ PropertyScope::Rmrk,
+ [
+ <PalletCore<T>>::rmrk_property(CollectionType, &misc::CollectionType::Base)?,
+ <PalletCore<T>>::rmrk_property(BaseType, &base_type)?,
+ ]
+ .into_iter(),
+ )?;
- let collection = <PalletCore<T>>::get_nft_collection(collection_id)?;
+ let collection = <PalletCore<T>>::get_nft_collection(collection_id)?;
- for part in parts {
- let part_id = part.id();
- let part_token_id = Self::create_part(
- &cross_sender,
- &collection,
- part
- )?;
+ for part in parts {
+ let part_id = part.id();
+ let part_token_id = Self::create_part(&cross_sender, &collection, part)?;
- <InernalPartId<T>>::insert(collection_id, part_id, part_token_id);
+ <InernalPartId<T>>::insert(collection_id, part_id, part_token_id);
- <PalletNft<T>>::set_scoped_token_property(
- collection_id,
- part_token_id,
- PropertyScope::Rmrk,
- <PalletCore<T>>::rmrk_property(ExternalPartId, &part_id)?
- )?;
- }
+ <PalletNft<T>>::set_scoped_token_property(
+ collection_id,
+ part_token_id,
+ PropertyScope::Rmrk,
+ <PalletCore<T>>::rmrk_property(ExternalPartId, &part_id)?,
+ )?;
+ }
- Self::deposit_event(Event::BaseCreated { issuer: sender, base_id: collection_id.0 });
+ Self::deposit_event(Event::BaseCreated {
+ issuer: sender,
+ base_id: collection_id.0,
+ });
- Ok(())
- }
+ Ok(())
+ }
- #[pallet::weight(10_000 + T::DbWeight::get().reads_writes(1,1))]
- #[transactional]
+ #[pallet::weight(10_000 + T::DbWeight::get().reads_writes(1,1))]
+ #[transactional]
pub fn theme_add(
origin: OriginFor<T>,
base_id: RmrkBaseId,
theme: RmrkTheme,
) -> DispatchResult {
- let sender = ensure_signed(origin)?;
+ let sender = ensure_signed(origin)?;
- let sender = T::CrossAccountId::from_sub(sender);
- let owner = &sender;
+ let sender = T::CrossAccountId::from_sub(sender);
+ let owner = &sender;
- let collection_id: CollectionId = base_id.into();
+ let collection_id: CollectionId = base_id.into();
- let collection = <PalletCore<T>>::get_typed_nft_collection(
- collection_id,
- misc::CollectionType::Base
- ).map_err(|_| <Error<T>>::BaseDoesntExist)?;
+ let collection = <PalletCore<T>>::get_typed_nft_collection(
+ collection_id,
+ misc::CollectionType::Base,
+ )
+ .map_err(|_| <Error<T>>::BaseDoesntExist)?;
- if theme.name.as_slice() == b"default" {
- <BaseHasDefaultTheme<T>>::insert(collection_id, true);
- } else if !Self::base_has_default_theme(collection_id) {
- return Err(<Error<T>>::NeedsDefaultThemeFirst.into());
- }
+ if theme.name.as_slice() == b"default" {
+ <BaseHasDefaultTheme<T>>::insert(collection_id, true);
+ } else if !Self::base_has_default_theme(collection_id) {
+ return Err(<Error<T>>::NeedsDefaultThemeFirst.into());
+ }
- let token_id = <PalletCore<T>>::create_nft(
- &sender,
- owner,
- &collection,
- NftType::Theme,
- [
- <PalletCore<T>>::rmrk_property(ThemeName, &theme.name)?,
- <PalletCore<T>>::rmrk_property(ThemeInherit, &theme.inherit)?
- ].into_iter()
- ).map_err(|_| <Error<T>>::PermissionError)?;
+ let token_id = <PalletCore<T>>::create_nft(
+ &sender,
+ owner,
+ &collection,
+ NftType::Theme,
+ [
+ <PalletCore<T>>::rmrk_property(ThemeName, &theme.name)?,
+ <PalletCore<T>>::rmrk_property(ThemeInherit, &theme.inherit)?,
+ ]
+ .into_iter(),
+ )
+ .map_err(|_| <Error<T>>::PermissionError)?;
- for property in theme.properties {
- <PalletNft<T>>::set_scoped_token_property(
- collection_id,
- token_id,
- PropertyScope::Rmrk,
- <PalletCore<T>>::rmrk_property(
- UserProperty(property.key.as_slice()),
- &property.value
- )?
- )?;
- }
+ for property in theme.properties {
+ <PalletNft<T>>::set_scoped_token_property(
+ collection_id,
+ token_id,
+ PropertyScope::Rmrk,
+ <PalletCore<T>>::rmrk_property(
+ UserProperty(property.key.as_slice()),
+ &property.value,
+ )?,
+ )?;
+ }
- Ok(())
- }
- }
+ Ok(())
+ }
+ }
}
impl<T: Config> Pallet<T> {
- fn create_part(
- sender: &T::CrossAccountId,
- collection: &NonfungibleHandle<T>,
- part: RmrkPartType
- ) -> Result<TokenId, DispatchError> {
- let owner = sender;
+ fn create_part(
+ sender: &T::CrossAccountId,
+ collection: &NonfungibleHandle<T>,
+ part: RmrkPartType,
+ ) -> Result<TokenId, DispatchError> {
+ let owner = sender;
- let src = part.src();
- let z_index = part.z_index();
+ let src = part.src();
+ let z_index = part.z_index();
- let nft_type = match part {
- RmrkPartType::FixedPart(_) => NftType::FixedPart,
- RmrkPartType::SlotPart(_) => NftType::SlotPart,
- };
+ let nft_type = match part {
+ RmrkPartType::FixedPart(_) => NftType::FixedPart,
+ RmrkPartType::SlotPart(_) => NftType::SlotPart,
+ };
- let token_id = <PalletCore<T>>::create_nft(
- sender,
- owner,
- collection,
- nft_type,
- [
- <PalletCore<T>>::rmrk_property(Src, &src)?,
- <PalletCore<T>>::rmrk_property(ZIndex, &z_index)?
- ].into_iter()
- ).map_err(|err| match err {
- DispatchError::Arithmetic(_) => <Error<T>>::NoAvailablePartId.into(),
- err => err
- })?;
+ let token_id = <PalletCore<T>>::create_nft(
+ sender,
+ owner,
+ collection,
+ nft_type,
+ [
+ <PalletCore<T>>::rmrk_property(Src, &src)?,
+ <PalletCore<T>>::rmrk_property(ZIndex, &z_index)?,
+ ]
+ .into_iter(),
+ )
+ .map_err(|err| match err {
+ DispatchError::Arithmetic(_) => <Error<T>>::NoAvailablePartId.into(),
+ err => err,
+ })?;
- if let RmrkPartType::SlotPart(part) = part {
- <PalletNft<T>>::set_scoped_token_property(
- collection.id,
- token_id,
- PropertyScope::Rmrk,
- <PalletCore<T>>::rmrk_property(EquippableList, &part.equippable)?
- )?;
- }
+ if let RmrkPartType::SlotPart(part) = part {
+ <PalletNft<T>>::set_scoped_token_property(
+ collection.id,
+ token_id,
+ PropertyScope::Rmrk,
+ <PalletCore<T>>::rmrk_property(EquippableList, &part.equippable)?,
+ )?;
+ }
- Ok(token_id)
- }
+ Ok(token_id)
+ }
}
pallets/refungible/src/common.rsdiffbeforeafterboth--- a/pallets/refungible/src/common.rs
+++ b/pallets/refungible/src/common.rs
@@ -313,17 +313,9 @@
fail!(<Error<T>>::RefungibleDisallowsNesting)
}
- fn nest(
- &self,
- _under: TokenId,
- _to_nest: (CollectionId, TokenId)
- ) {}
+ fn nest(&self, _under: TokenId, _to_nest: (CollectionId, TokenId)) {}
- fn unnest(
- &self,
- _under: TokenId,
- _to_nest: (CollectionId, TokenId)
- ) {}
+ fn unnest(&self, _under: TokenId, _to_nest: (CollectionId, TokenId)) {}
fn account_tokens(&self, account: T::CrossAccountId) -> Vec<TokenId> {
<Owned<T>>::iter_prefix((self.id, account))
pallets/refungible/src/lib.rsdiffbeforeafterboth--- a/pallets/refungible/src/lib.rs
+++ b/pallets/refungible/src/lib.rs
@@ -22,9 +22,7 @@
CreateCollectionData, CreateRefungibleExData, mapping::TokenAddressMapping, budget::Budget,
};
use pallet_evm::account::CrossAccountId;
-use pallet_common::{
- Error as CommonError, Event as CommonEvent, Pallet as PalletCommon,
-};
+use pallet_common::{Error as CommonError, Event as CommonEvent, Pallet as PalletCommon};
use pallet_structure::Pallet as PalletStructure;
use sp_runtime::{ArithmeticError, DispatchError, DispatchResult};
use sp_std::{vec::Vec, vec, collections::btree_map::BTreeMap};
@@ -230,7 +228,9 @@
}
fn collection_has_tokens(collection_id: CollectionId) -> bool {
- <TokenData<T>>::iter_prefix((collection_id,)).next().is_some()
+ <TokenData<T>>::iter_prefix((collection_id,))
+ .next()
+ .is_some()
}
pub fn burn_token(collection: &RefungibleHandle<T>, token_id: TokenId) -> DispatchResult {
@@ -388,18 +388,14 @@
to,
collection.id,
token,
- nesting_budget
+ nesting_budget,
)?;
if let Some(balance_to) = balance_to {
// from != to
if balance_from == 0 {
<Balance<T>>::remove((collection.id, token, from));
- <PalletStructure<T>>::unnest_if_nested(
- from,
- collection.id,
- token
- );
+ <PalletStructure<T>>::unnest_if_nested(from, collection.id, token);
} else {
<Balance<T>>::insert((collection.id, token, from), balance_from);
}
@@ -497,7 +493,6 @@
for (i, token) in data.iter().enumerate() {
let token_id = TokenId(first_token_id + i as u32 + 1);
for (to, _) in token.users.iter() {
-
<PalletStructure<T>>::check_nesting(
sender.clone(),
to,
@@ -531,7 +526,11 @@
}
<Balance<T>>::insert((collection.id, token_id, &user), amount);
<Owned<T>>::insert((collection.id, &user, TokenId(token_id)), true);
- <PalletStructure<T>>::nest_if_sent_to_token_unchecked(&user, collection.id, TokenId(token_id));
+ <PalletStructure<T>>::nest_if_sent_to_token_unchecked(
+ &user,
+ collection.id,
+ TokenId(token_id),
+ );
// TODO: ERC20 transfer event
<PalletCommon<T>>::deposit_event(CommonEvent::ItemCreated(
pallets/structure/src/lib.rsdiffbeforeafterboth--- a/pallets/structure/src/lib.rs
+++ b/pallets/structure/src/lib.rs
@@ -189,17 +189,11 @@
under: &T::CrossAccountId,
collection_id: CollectionId,
token_id: TokenId,
- nesting_budget: &dyn Budget
+ nesting_budget: &dyn Budget,
) -> DispatchResult {
- Self::try_exec_if_owner_is_valid_nft(
- under,
- |d, parent_id| d.check_nesting(
- from,
- (collection_id, token_id),
- parent_id,
- nesting_budget
- )
- )
+ Self::try_exec_if_owner_is_valid_nft(under, |d, parent_id| {
+ d.check_nesting(from, (collection_id, token_id), parent_id, nesting_budget)
+ })
}
pub fn nest_if_sent_to_token(
@@ -207,69 +201,51 @@
under: &T::CrossAccountId,
collection_id: CollectionId,
token_id: TokenId,
- nesting_budget: &dyn Budget
+ nesting_budget: &dyn Budget,
) -> DispatchResult {
- Self::try_exec_if_owner_is_valid_nft(
- under,
- |d, parent_id| {
- d.check_nesting(
- from,
- (collection_id, token_id),
- parent_id,
- nesting_budget
- )?;
+ Self::try_exec_if_owner_is_valid_nft(under, |d, parent_id| {
+ d.check_nesting(from, (collection_id, token_id), parent_id, nesting_budget)?;
- d.nest(parent_id, (collection_id, token_id));
+ d.nest(parent_id, (collection_id, token_id));
- Ok(())
- }
- )
+ Ok(())
+ })
}
pub fn nest_if_sent_to_token_unchecked(
owner: &T::CrossAccountId,
collection_id: CollectionId,
- token_id: TokenId
+ token_id: TokenId,
) {
- Self::exec_if_owner_is_valid_nft(
- owner,
- |d, parent_id| d.nest(
- parent_id,
- (collection_id, token_id)
- )
- );
+ Self::exec_if_owner_is_valid_nft(owner, |d, parent_id| {
+ d.nest(parent_id, (collection_id, token_id))
+ });
}
pub fn unnest_if_nested(
owner: &T::CrossAccountId,
collection_id: CollectionId,
- token_id: TokenId
+ token_id: TokenId,
) {
- Self::exec_if_owner_is_valid_nft(
- owner,
- |d, parent_id| d.unnest(
- parent_id,
- (collection_id, token_id)
- )
- );
+ Self::exec_if_owner_is_valid_nft(owner, |d, parent_id| {
+ d.unnest(parent_id, (collection_id, token_id))
+ });
}
fn exec_if_owner_is_valid_nft(
account: &T::CrossAccountId,
- action: impl FnOnce(&dyn CommonCollectionOperations<T>, TokenId)
+ action: impl FnOnce(&dyn CommonCollectionOperations<T>, TokenId),
) {
- Self::try_exec_if_owner_is_valid_nft(
- account,
- |d, id| {
- action(d, id);
- Ok(())
- }
- ).unwrap();
+ Self::try_exec_if_owner_is_valid_nft(account, |d, id| {
+ action(d, id);
+ Ok(())
+ })
+ .unwrap();
}
fn try_exec_if_owner_is_valid_nft(
account: &T::CrossAccountId,
- action: impl FnOnce(&dyn CommonCollectionOperations<T>, TokenId) -> DispatchResult
+ action: impl FnOnce(&dyn CommonCollectionOperations<T>, TokenId) -> DispatchResult,
) -> DispatchResult {
let account = T::CrossTokenAddressMapping::address_to_token(account);
pallets/unique/src/lib.rsdiffbeforeafterboth--- a/pallets/unique/src/lib.rs
+++ b/pallets/unique/src/lib.rs
@@ -37,11 +37,10 @@
use frame_system::{self as system, ensure_signed};
use sp_runtime::{sp_std::prelude::Vec};
use up_data_structs::{
- MAX_COLLECTION_NAME_LENGTH,
- MAX_COLLECTION_DESCRIPTION_LENGTH, MAX_TOKEN_PREFIX_LENGTH, AccessMode, CreateItemData,
- CollectionLimits, CollectionPermissions, CollectionId, CollectionMode, TokenId, SponsorshipState,
- CreateCollectionData, CreateItemExData, budget, Property, PropertyKey,
- PropertyKeyPermission,
+ MAX_COLLECTION_NAME_LENGTH, MAX_COLLECTION_DESCRIPTION_LENGTH, MAX_TOKEN_PREFIX_LENGTH,
+ AccessMode, CreateItemData, CollectionLimits, CollectionPermissions, CollectionId,
+ CollectionMode, TokenId, SponsorshipState, CreateCollectionData, CreateItemExData, budget,
+ Property, PropertyKey, PropertyKeyPermission,
};
use pallet_evm::account::CrossAccountId;
use pallet_common::{
primitives/data-structs/src/lib.rsdiffbeforeafterboth--- a/primitives/data-structs/src/lib.rs
+++ b/primitives/data-structs/src/lib.rs
@@ -49,7 +49,8 @@
},
NftChild as RmrkNftChild, AccountIdOrCollectionNftTuple as RmrkAccountIdOrCollectionNftTuple,
FixedPart as RmrkFixedPart, SlotPart as RmrkSlotPart, EquippableList as RmrkEquippableList,
- BasicResource as RmrkBasicResource, ComposableResource as RmrkComposableResource, SlotResource as RmrkSlotResource,
+ BasicResource as RmrkBasicResource, ComposableResource as RmrkComposableResource,
+ SlotResource as RmrkSlotResource,
};
mod bounded;
@@ -361,8 +362,7 @@
pub type CollectionPropertiesPermissionsVec =
BoundedVec<PropertyKeyPermission, ConstU32<MAX_PROPERTIES_PER_ITEM>>;
-pub type CollectionPropertiesVec =
- BoundedVec<Property, ConstU32<MAX_PROPERTIES_PER_ITEM>>;
+pub type CollectionPropertiesVec = BoundedVec<Property, ConstU32<MAX_PROPERTIES_PER_ITEM>>;
/// All fields are wrapped in `Option`s, where None means chain default
// When adding/removing fields from this struct - don't forget to also update clamp_limits
@@ -790,8 +790,8 @@
>::IntoIter;
fn into_iter(self) -> Self::IntoIter {
- self.0.into_iter()
- }
+ self.0.into_iter()
+ }
}
impl<Value> TrySetProperty for PropertiesMap<Value> {
@@ -853,8 +853,8 @@
type IntoIter = <PropertiesMap<PropertyValue> as IntoIterator>::IntoIter;
fn into_iter(self) -> Self::IntoIter {
- self.map.into_iter()
- }
+ self.map.into_iter()
+ }
}
impl TrySetProperty for Properties {
@@ -932,11 +932,7 @@
pub type RmrkCollectionInfo<AccountId> =
CollectionInfo<RmrkString, RmrkCollectionSymbol, AccountId>;
pub type RmrkInstanceInfo<AccountId> = NftInfo<AccountId, Permill, RmrkString>;
-pub type RmrkResourceInfo = ResourceInfo<
- RmrkBoundedResource,
- RmrkString,
- RmrkBoundedParts,
->;
+pub type RmrkResourceInfo = ResourceInfo<RmrkBoundedResource, RmrkString, RmrkBoundedParts>;
pub type RmrkPropertyInfo = PropertyInfo<RmrkKeyString, RmrkValueString>;
pub type RmrkBaseInfo<AccountId> = BaseInfo<AccountId, RmrkString>;
pub type RmrkPartType =
primitives/data-structs/src/rmrk.rsdiffbeforeafterboth--- a/primitives/data-structs/src/rmrk.rs
+++ b/primitives/data-structs/src/rmrk.rs
@@ -20,37 +20,37 @@
#[cfg(feature = "std")]
mod serialize {
- use core::convert::AsRef;
- use serde::ser::{self, Serialize};
+ use core::convert::AsRef;
+ use serde::ser::{self, Serialize};
- pub mod vec {
- use super::*;
+ pub mod vec {
+ use super::*;
- pub fn serialize<D, V, C>(value: &C, serializer: D) -> Result<D::Ok, D::Error>
- where
- D: ser::Serializer,
- V: Serialize,
- C: AsRef<[V]>,
- {
- value.as_ref().serialize(serializer)
- }
- }
+ pub fn serialize<D, V, C>(value: &C, serializer: D) -> Result<D::Ok, D::Error>
+ where
+ D: ser::Serializer,
+ V: Serialize,
+ C: AsRef<[V]>,
+ {
+ value.as_ref().serialize(serializer)
+ }
+ }
- pub mod opt_vec {
- use super::*;
+ pub mod opt_vec {
+ use super::*;
- pub fn serialize<D, V, C>(value: &Option<C>, serializer: D) -> Result<D::Ok, D::Error>
- where
- D: ser::Serializer,
- V: Serialize,
- C: AsRef<[V]>,
- {
- match value {
- Some(value) => super::vec::serialize(value, serializer),
- None => serializer.serialize_none()
- }
- }
- }
+ pub fn serialize<D, V, C>(value: &Option<C>, serializer: D) -> Result<D::Ok, D::Error>
+ where
+ D: ser::Serializer,
+ V: Serialize,
+ C: AsRef<[V]>,
+ {
+ match value {
+ Some(value) => super::vec::serialize(value, serializer),
+ None => serializer.serialize_none(),
+ }
+ }
+ }
}
/// Collection info.
@@ -58,13 +58,11 @@
#[derive(Encode, Decode, Debug, TypeInfo, MaxEncodedLen)]
#[cfg_attr(
feature = "std",
- serde(
- bound = r#"
+ serde(bound = r#"
AccountId: Serialize,
BoundedString: AsRef<[u8]>,
BoundedSymbol: AsRef<[u8]>
- "#
- )
+ "#)
)]
pub struct CollectionInfo<BoundedString, BoundedSymbol, AccountId> {
/// Current bidder and bid price.
@@ -91,9 +89,9 @@
#[derive(Encode, Decode, Debug, TypeInfo, MaxEncodedLen)]
pub struct RoyaltyInfo<AccountId, RoyaltyAmount> {
/// Recipient (AccountId) of the royalty
- pub recipient: AccountId,
+ pub recipient: AccountId,
/// Amount (Permill) of the royalty
- pub amount: RoyaltyAmount,
+ pub amount: RoyaltyAmount,
}
/// Nft info.
@@ -101,13 +99,11 @@
#[derive(Encode, Decode, Debug, TypeInfo, MaxEncodedLen)]
#[cfg_attr(
feature = "std",
- serde(
- bound = r#"
+ serde(bound = r#"
AccountId: Serialize,
RoyaltyAmount: Serialize,
BoundedString: AsRef<[u8]>
- "#
- )
+ "#)
)]
pub struct NftInfo<AccountId, RoyaltyAmount, BoundedString> {
/// The owner of the NFT, can be either an Account or a tuple (CollectionId, NftId)
@@ -129,22 +125,19 @@
#[derive(Encode, Decode, TypeInfo, MaxEncodedLen)]
pub struct NftChild {
pub collection_id: CollectionId,
- pub nft_id: NftId
+ pub nft_id: NftId,
}
#[cfg_attr(feature = "std", derive(Serialize))]
#[derive(Encode, Decode, PartialEq, TypeInfo)]
#[cfg_attr(
feature = "std",
- serde(
- bound = r#"
+ serde(bound = r#"
BoundedKey: AsRef<[u8]>,
BoundedValue: AsRef<[u8]>
- "#
- )
+ "#)
)]
-pub struct PropertyInfo<BoundedKey, BoundedValue>
-{
+pub struct PropertyInfo<BoundedKey, BoundedValue> {
/// Key of the property
#[cfg_attr(feature = "std", serde(with = "serialize::vec"))]
pub key: BoundedKey,
@@ -156,10 +149,7 @@
#[derive(Encode, Decode, Default, Eq, PartialEq, Clone, Debug, TypeInfo, MaxEncodedLen)]
#[cfg_attr(feature = "std", derive(Serialize))]
-#[cfg_attr(
- feature = "std",
- serde(bound = "BoundedString: AsRef<[u8]>")
-)]
+#[cfg_attr(feature = "std", serde(bound = "BoundedString: AsRef<[u8]>"))]
pub struct BasicResource<BoundedString> {
/// If the resource is Media, the base property is absent. Media src should be a URI like an
/// IPFS hash.
@@ -188,12 +178,10 @@
#[cfg_attr(feature = "std", derive(Serialize))]
#[cfg_attr(
feature = "std",
- serde(
- bound = r#"
+ serde(bound = r#"
BoundedString: AsRef<[u8]>,
BoundedParts: AsRef<[PartId]>
- "#
- )
+ "#)
)]
pub struct ComposableResource<BoundedString, BoundedParts> {
/// If a resource is composed, it will have an array of parts that compose it
@@ -235,10 +223,7 @@
#[derive(Encode, Decode, Eq, PartialEq, Clone, Debug, TypeInfo, MaxEncodedLen)]
#[cfg_attr(feature = "std", derive(Serialize))]
-#[cfg_attr(
- feature = "std",
- serde(bound = "BoundedString: AsRef<[u8]>")
-)]
+#[cfg_attr(feature = "std", serde(bound = "BoundedString: AsRef<[u8]>"))]
pub struct SlotResource<BoundedString> {
/// A Base is uniquely identified by the combination of the word `base`, its minting block
/// number, and user provided symbol during Base creation, glued by dashes `-`, e.g.
@@ -279,14 +264,12 @@
#[cfg_attr(feature = "std", derive(Serialize))]
#[cfg_attr(
feature = "std",
- serde(
- bound = r#"
+ serde(bound = r#"
BoundedString: AsRef<[u8]>,
BoundedParts: AsRef<[PartId]>
- "#
- )
+ "#)
)]
-#[derivative(Default(bound=""))]
+#[derivative(Default(bound = ""))]
pub enum ResourceTypes<BoundedString: Default, BoundedParts> {
#[derivative(Default)]
Basic(BasicResource<BoundedString>),
@@ -294,18 +277,15 @@
Slot(SlotResource<BoundedString>),
}
-
#[derive(Encode, Decode, Eq, PartialEq, Clone, Debug, TypeInfo, MaxEncodedLen)]
#[cfg_attr(feature = "std", derive(Serialize))]
#[cfg_attr(
feature = "std",
- serde(
- bound = r#"
+ serde(bound = r#"
BoundedResource: AsRef<[u8]>,
BoundedString: AsRef<[u8]>,
BoundedParts: AsRef<[PartId]>
- "#
- )
+ "#)
)]
pub struct ResourceInfo<BoundedResource, BoundedString: Default, BoundedParts> {
/// id is a 5-character string of reasonable uniqueness.
@@ -328,12 +308,10 @@
#[derive(Encode, Decode, Debug, TypeInfo, MaxEncodedLen)]
#[cfg_attr(
feature = "std",
- serde(
- bound = r#"
+ serde(bound = r#"
AccountId: Serialize,
BoundedString: AsRef<[u8]>
- "#
- )
+ "#)
)]
pub struct BaseInfo<AccountId, BoundedString> {
/// Original creator of the Base
@@ -350,10 +328,7 @@
#[cfg_attr(feature = "std", derive(Serialize))]
#[derive(Encode, Decode, Debug, TypeInfo, Clone, PartialEq, Eq, MaxEncodedLen)]
-#[cfg_attr(
- feature = "std",
- serde(bound = "BoundedString: AsRef<[u8]>")
-)]
+#[cfg_attr(feature = "std", serde(bound = "BoundedString: AsRef<[u8]>"))]
pub struct FixedPart<BoundedString> {
pub id: PartId,
pub z: ZIndex,
@@ -368,29 +343,24 @@
feature = "std",
serde(bound = "BoundedCollectionList: AsRef<[CollectionId]>")
)]
-#[derivative(Default(bound=""))]
+#[derivative(Default(bound = ""))]
pub enum EquippableList<BoundedCollectionList> {
All,
#[derivative(Default)]
Empty,
- Custom(
- #[cfg_attr(feature = "std", serde(with = "serialize::vec"))]
- BoundedCollectionList
- ),
+ Custom(#[cfg_attr(feature = "std", serde(with = "serialize::vec"))] BoundedCollectionList),
}
#[cfg_attr(feature = "std", derive(Serialize))]
#[derive(Encode, Decode, Debug, TypeInfo, Clone, PartialEq, Eq, MaxEncodedLen)]
#[cfg_attr(
feature = "std",
- serde(
- bound = r#"
+ serde(bound = r#"
BoundedString: AsRef<[u8]>,
BoundedCollectionList: AsRef<[CollectionId]>
- "#
- )
+ "#)
)]
pub struct SlotPart<BoundedString, BoundedCollectionList> {
pub id: PartId,
@@ -406,12 +376,10 @@
#[derive(Encode, Decode, Debug, TypeInfo, Clone, PartialEq, Eq, MaxEncodedLen)]
#[cfg_attr(
feature = "std",
- serde(
- bound = r#"
+ serde(bound = r#"
BoundedString: AsRef<[u8]>,
BoundedCollectionList: AsRef<[CollectionId]>
- "#
- )
+ "#)
)]
pub enum PartType<BoundedString, BoundedCollectionList> {
FixedPart(FixedPart<BoundedString>),
@@ -422,21 +390,21 @@
pub fn id(&self) -> PartId {
match self {
Self::FixedPart(part) => part.id,
- Self::SlotPart(part) => part.id
+ Self::SlotPart(part) => part.id,
}
}
pub fn src(&self) -> &BoundedString {
match self {
Self::FixedPart(part) => &part.src,
- Self::SlotPart(part) => &part.src
+ Self::SlotPart(part) => &part.src,
}
}
pub fn z_index(&self) -> ZIndex {
match self {
Self::FixedPart(part) => part.z,
- Self::SlotPart(part) => part.z
+ Self::SlotPart(part) => part.z,
}
}
}
@@ -445,12 +413,10 @@
#[derive(Encode, Decode, Debug, TypeInfo, Clone, PartialEq)]
#[cfg_attr(
feature = "std",
- serde(
- bound = r#"
+ serde(bound = r#"
BoundedString: AsRef<[u8]>,
PropertyList: AsRef<[ThemeProperty<BoundedString>]>,
- "#
- )
+ "#)
)]
pub struct Theme<BoundedString, PropertyList> {
/// Name of the theme
@@ -466,10 +432,7 @@
#[cfg_attr(feature = "std", derive(Eq, Serialize))]
#[derive(Encode, Decode, Debug, TypeInfo, Clone, PartialEq)]
-#[cfg_attr(
- feature = "std",
- serde(bound = "BoundedString: AsRef<[u8]>")
-)]
+#[cfg_attr(feature = "std", serde(bound = "BoundedString: AsRef<[u8]>"))]
pub struct ThemeProperty<BoundedString> {
/// Key of the property
#[cfg_attr(feature = "std", serde(with = "serialize::vec"))]
runtime/tests/src/tests.rsdiffbeforeafterboth--- a/runtime/tests/src/tests.rs
+++ b/runtime/tests/src/tests.rs
@@ -19,9 +19,9 @@
use up_data_structs::{
COLLECTION_NUMBER_LIMIT, CollectionId, CreateItemData, CreateFungibleData, CreateNftData,
CreateReFungibleData, MAX_DECIMAL_POINTS, COLLECTION_ADMINS_LIMIT, TokenId,
- MAX_TOKEN_OWNERSHIP, CreateCollectionData, CollectionMode,
- AccessMode, CollectionPermissions, PropertyKeyPermission, PropertyPermission,
- Property, CollectionPropertiesVec, CollectionPropertiesPermissionsVec,
+ MAX_TOKEN_OWNERSHIP, CreateCollectionData, CollectionMode, AccessMode, CollectionPermissions,
+ PropertyKeyPermission, PropertyPermission, Property, CollectionPropertiesVec,
+ CollectionPropertiesPermissionsVec,
};
use frame_support::{assert_noop, assert_ok, assert_err};
use sp_std::convert::TryInto;
@@ -47,12 +47,12 @@
fn default_nft_data() -> CreateNftData {
CreateNftData {
- properties: vec![
- Property {
- key: b"test-prop".to_vec().try_into().unwrap(),
- value: b"test-nft-prop".to_vec().try_into().unwrap(),
- },
- ].try_into().unwrap(),
+ properties: vec![Property {
+ key: b"test-prop".to_vec().try_into().unwrap(),
+ value: b"test-nft-prop".to_vec().try_into().unwrap(),
+ }]
+ .try_into()
+ .unwrap(),
}
}
@@ -77,22 +77,23 @@
let col_name1: Vec<u16> = "Test1\0".encode_utf16().collect::<Vec<u16>>();
let col_desc1: Vec<u16> = "TestDescription1\0".encode_utf16().collect::<Vec<u16>>();
let token_prefix1: Vec<u8> = b"token_prefix1\0".to_vec();
- let token_property_permissions: CollectionPropertiesPermissionsVec = vec![
- PropertyKeyPermission {
+ let token_property_permissions: CollectionPropertiesPermissionsVec =
+ vec![PropertyKeyPermission {
key: b"test-prop".to_vec().try_into().unwrap(),
permission: PropertyPermission {
mutable: true,
collection_admin: false,
token_owner: true,
},
- },
- ].try_into().unwrap();
- let properties: CollectionPropertiesVec = vec![
- Property {
- key: b"test-collection-prop".to_vec().try_into().unwrap(),
- value: b"test-collection-value".to_vec().try_into().unwrap(),
- }
- ].try_into().unwrap();
+ }]
+ .try_into()
+ .unwrap();
+ let properties: CollectionPropertiesVec = vec![Property {
+ key: b"test-collection-prop".to_vec().try_into().unwrap(),
+ value: b"test-collection-value".to_vec().try_into().unwrap(),
+ }]
+ .try_into()
+ .unwrap();
let data: CreateCollectionData<u64> = CreateCollectionData {
name: col_name1.try_into().unwrap(),
@@ -150,30 +151,21 @@
fn get_collection_property_permissions(collection_id: CollectionId) -> Vec<PropertyKeyPermission> {
<pallet_common::Pallet<Test>>::property_permissions(collection_id)
.into_iter()
- .map(|(key, permission)| PropertyKeyPermission {
- key,
- permission,
- })
+ .map(|(key, permission)| PropertyKeyPermission { key, permission })
.collect()
}
fn get_collection_properties(collection_id: CollectionId) -> Vec<Property> {
<pallet_common::Pallet<Test>>::collection_properties(collection_id)
.into_iter()
- .map(|(key, value)| Property {
- key,
- value,
- })
+ .map(|(key, value)| Property { key, value })
.collect()
}
fn get_token_properties(collection_id: CollectionId, token_id: TokenId) -> Vec<Property> {
<pallet_nonfungible::Pallet<Test>>::token_properties((collection_id, token_id))
.into_iter()
- .map(|(key, value)| Property {
- key,
- value,
- })
+ .map(|(key, value)| Property { key, value })
.collect()
}