difftreelog
refactor move properties around
in: master
18 files changed
client/rpc/src/lib.rsdiffbeforeafterboth--- a/client/rpc/src/lib.rs
+++ b/client/rpc/src/lib.rs
@@ -73,13 +73,6 @@
token: TokenId,
at: Option<BlockHash>,
) -> Result<Option<CrossAccountId>>;
- #[rpc(name = "unique_constMetadata")]
- fn const_metadata(
- &self,
- collection: CollectionId,
- token: TokenId,
- at: Option<BlockHash>,
- ) -> Result<Vec<u8>>;
#[rpc(name = "unique_collectionProperties")]
fn collection_properties(
@@ -418,9 +411,6 @@
);
pass_method!(
topmost_token_owner(collection: CollectionId, token: TokenId) -> Option<CrossAccountId>, unique_api
- );
- pass_method!(
- const_metadata(collection: CollectionId, token: TokenId) -> Vec<u8>, unique_api
);
pass_method!(total_supply(collection: CollectionId) -> u32, unique_api);
pass_method!(account_balance(collection: CollectionId, account: CrossAccountId) -> u32, unique_api);
pallets/common/src/benchmarking.rsdiffbeforeafterboth--- a/pallets/common/src/benchmarking.rs
+++ b/pallets/common/src/benchmarking.rs
@@ -86,8 +86,6 @@
let name = create_u16_data::<MAX_COLLECTION_NAME_LENGTH>();
let description = create_u16_data::<MAX_COLLECTION_DESCRIPTION_LENGTH>();
let token_prefix = create_data::<MAX_TOKEN_PREFIX_LENGTH>();
- let offchain_schema = create_data::<OFFCHAIN_SCHEMA_LIMIT>();
- let const_on_chain_schema = create_data::<CONST_ON_CHAIN_SCHEMA_LIMIT>();
handler(
owner,
CreateCollectionData {
@@ -95,8 +93,6 @@
name,
description,
token_prefix,
- offchain_schema,
- const_on_chain_schema,
..Default::default()
},
)
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 CollectionField,59 PhantomType,60 Property,61 Properties,62 PropertiesPermissionMap,63 PropertyKey,64 PropertyValue,65 PropertyPermission,66 PropertiesError,67 PropertyKeyPermission,68 TokenData,69 TrySetProperty,70 PropertyScope,71 // RMRK72 RmrkCollectionInfo,73 RmrkInstanceInfo,74 RmrkResourceInfo,75 RmrkPropertyInfo,76 RmrkBaseInfo,77 RmrkPartType,78 RmrkTheme,79 RmrkNftChild,80};8182pub use pallet::*;83use sp_core::H160;84use sp_runtime::{ArithmeticError, DispatchError, DispatchResult};85#[cfg(feature = "runtime-benchmarks")]86pub mod benchmarking;87pub mod dispatch;88pub mod erc;89pub mod eth;90pub mod weights;9192pub type SelfWeightOf<T> = <T as Config>::WeightInfo;9394#[must_use = "Should call submit_logs or save, otherwise some data will be lost for evm side"]95pub struct CollectionHandle<T: Config> {96 pub id: CollectionId,97 collection: Collection<T::AccountId>,98 pub recorder: SubstrateRecorder<T>,99}100impl<T: Config> WithRecorder<T> for CollectionHandle<T> {101 fn recorder(&self) -> &SubstrateRecorder<T> {102 &self.recorder103 }104 fn into_recorder(self) -> SubstrateRecorder<T> {105 self.recorder106 }107}108impl<T: Config> CollectionHandle<T> {109 pub fn new_with_gas_limit(id: CollectionId, gas_limit: u64) -> Option<Self> {110 <CollectionById<T>>::get(id).map(|collection| Self {111 id,112 collection,113 recorder: SubstrateRecorder::new(gas_limit),114 })115 }116 pub fn new(id: CollectionId) -> Option<Self> {117 Self::new_with_gas_limit(id, u64::MAX)118 }119 pub fn try_get(id: CollectionId) -> Result<Self, DispatchError> {120 Ok(Self::new(id).ok_or(<Error<T>>::CollectionNotFound)?)121 }122 pub fn consume_store_reads(&self, reads: u64) -> evm_coder::execution::Result<()> {123 self.recorder124 .consume_gas(T::GasWeightMapping::weight_to_gas(125 <T as frame_system::Config>::DbWeight::get()126 .read127 .saturating_mul(reads),128 ))129 }130 pub fn consume_store_writes(&self, writes: u64) -> evm_coder::execution::Result<()> {131 self.recorder132 .consume_gas(T::GasWeightMapping::weight_to_gas(133 <T as frame_system::Config>::DbWeight::get()134 .write135 .saturating_mul(writes),136 ))137 }138 pub fn save(self) -> DispatchResult {139 <CollectionById<T>>::insert(self.id, self.collection);140 Ok(())141 }142}143impl<T: Config> Deref for CollectionHandle<T> {144 type Target = Collection<T::AccountId>;145146 fn deref(&self) -> &Self::Target {147 &self.collection148 }149}150151impl<T: Config> DerefMut for CollectionHandle<T> {152 fn deref_mut(&mut self) -> &mut Self::Target {153 &mut self.collection154 }155}156157impl<T: Config> CollectionHandle<T> {158 pub fn check_is_owner(&self, subject: &T::CrossAccountId) -> DispatchResult {159 ensure!(*subject.as_sub() == self.owner, <Error<T>>::NoPermission);160 Ok(())161 }162 pub fn is_owner_or_admin(&self, subject: &T::CrossAccountId) -> bool {163 *subject.as_sub() == self.owner || <IsAdmin<T>>::get((self.id, subject))164 }165 pub fn check_is_owner_or_admin(&self, subject: &T::CrossAccountId) -> DispatchResult {166 ensure!(self.is_owner_or_admin(subject), <Error<T>>::NoPermission);167 Ok(())168 }169 pub fn ignores_allowance(&self, user: &T::CrossAccountId) -> bool {170 self.limits.owner_can_transfer() && self.is_owner_or_admin(user)171 }172 pub fn ignores_owned_amount(&self, user: &T::CrossAccountId) -> bool {173 self.limits.owner_can_transfer() && self.is_owner_or_admin(user)174 }175 pub fn check_allowlist(&self, user: &T::CrossAccountId) -> DispatchResult {176 ensure!(177 <Allowlist<T>>::get((self.id, user)),178 <Error<T>>::AddressNotInAllowlist179 );180 Ok(())181 }182}183184#[frame_support::pallet]185pub mod pallet {186 use super::*;187 use pallet_evm::account;188 use dispatch::CollectionDispatch;189 use frame_support::{Blake2_128Concat, pallet_prelude::*, storage::Key, traits::StorageVersion};190 use frame_system::pallet_prelude::*;191 use frame_support::traits::Currency;192 use up_data_structs::{TokenId, mapping::TokenAddressMapping};193 use scale_info::TypeInfo;194 use weights::WeightInfo;195196 #[pallet::config]197 pub trait Config:198 frame_system::Config + pallet_evm_coder_substrate::Config + TypeInfo + account::Config199 {200 type WeightInfo: WeightInfo;201 type Event: IsType<<Self as frame_system::Config>::Event> + From<Event<Self>>;202203 type Currency: Currency<Self::AccountId>;204205 #[pallet::constant]206 type CollectionCreationPrice: Get<207 <<Self as Config>::Currency as Currency<Self::AccountId>>::Balance,208 >;209 type CollectionDispatch: CollectionDispatch<Self>;210211 type TreasuryAccountId: Get<Self::AccountId>;212213 type EvmTokenAddressMapping: TokenAddressMapping<H160>;214 type CrossTokenAddressMapping: TokenAddressMapping<Self::CrossAccountId>;215 }216217 const STORAGE_VERSION: StorageVersion = StorageVersion::new(1);218219 #[pallet::pallet]220 #[pallet::storage_version(STORAGE_VERSION)]221 #[pallet::generate_store(pub(super) trait Store)]222 pub struct Pallet<T>(_);223224 #[pallet::extra_constants]225 impl<T: Config> Pallet<T> {226 pub fn collection_admins_limit() -> u32 {227 COLLECTION_ADMINS_LIMIT228 }229 }230231 #[pallet::event]232 #[pallet::generate_deposit(pub fn deposit_event)]233 pub enum Event<T: Config> {234 /// New collection was created235 ///236 /// # Arguments237 ///238 /// * collection_id: Globally unique identifier of newly created collection.239 ///240 /// * mode: [CollectionMode] converted into u8.241 ///242 /// * account_id: Collection owner.243 CollectionCreated(CollectionId, u8, T::AccountId),244245 /// New collection was destroyed246 ///247 /// # Arguments248 ///249 /// * collection_id: Globally unique identifier of collection.250 CollectionDestroyed(CollectionId),251252 /// New item was created.253 ///254 /// # Arguments255 ///256 /// * collection_id: Id of the collection where item was created.257 ///258 /// * item_id: Id of an item. Unique within the collection.259 ///260 /// * recipient: Owner of newly created item261 ///262 /// * amount: Always 1 for NFT263 ItemCreated(CollectionId, TokenId, T::CrossAccountId, u128),264265 /// Collection item was burned.266 ///267 /// # Arguments268 ///269 /// * collection_id.270 ///271 /// * item_id: Identifier of burned NFT.272 ///273 /// * owner: which user has destroyed its tokens274 ///275 /// * amount: Always 1 for NFT276 ItemDestroyed(CollectionId, TokenId, T::CrossAccountId, u128),277278 /// Item was transferred279 ///280 /// * collection_id: Id of collection to which item is belong281 ///282 /// * item_id: Id of an item283 ///284 /// * sender: Original owner of item285 ///286 /// * recipient: New owner of item287 ///288 /// * amount: Always 1 for NFT289 Transfer(290 CollectionId,291 TokenId,292 T::CrossAccountId,293 T::CrossAccountId,294 u128,295 ),296297 /// * collection_id298 ///299 /// * item_id300 ///301 /// * sender302 ///303 /// * spender304 ///305 /// * amount306 Approved(307 CollectionId,308 TokenId,309 T::CrossAccountId,310 T::CrossAccountId,311 u128,312 ),313314 CollectionPropertySet(CollectionId, PropertyKey),315316 CollectionPropertyDeleted(CollectionId, PropertyKey),317318 TokenPropertySet(CollectionId, TokenId, PropertyKey),319320 TokenPropertyDeleted(CollectionId, TokenId, PropertyKey),321322 PropertyPermissionSet(CollectionId, PropertyKey),323 }324325 #[pallet::error]326 pub enum Error<T> {327 /// This collection does not exist.328 CollectionNotFound,329 /// Sender parameter and item owner must be equal.330 MustBeTokenOwner,331 /// No permission to perform action332 NoPermission,333 /// Collection is not in mint mode.334 PublicMintingNotAllowed,335 /// Address is not in allow list.336 AddressNotInAllowlist,337338 /// Collection name can not be longer than 63 char.339 CollectionNameLimitExceeded,340 /// Collection description can not be longer than 255 char.341 CollectionDescriptionLimitExceeded,342 /// Token prefix can not be longer than 15 char.343 CollectionTokenPrefixLimitExceeded,344 /// Total collections bound exceeded.345 TotalCollectionsLimitExceeded,346 /// Exceeded max admin count347 CollectionAdminCountExceeded,348 /// Collection limit bounds per collection exceeded349 CollectionLimitBoundsExceeded,350 /// Tried to enable permissions which are only permitted to be disabled351 OwnerPermissionsCantBeReverted,352 /// Collection settings not allowing items transferring353 TransferNotAllowed,354 /// Account token limit exceeded per collection355 AccountTokenLimitExceeded,356 /// Collection token limit exceeded357 CollectionTokenLimitExceeded,358 /// Metadata flag frozen359 MetadataFlagFrozen,360361 /// Item not exists.362 TokenNotFound,363 /// Item balance not enough.364 TokenValueTooLow,365 /// Requested value more than approved.366 ApprovedValueTooLow,367 /// Tried to approve more than owned368 CantApproveMoreThanOwned,369370 /// Can't transfer tokens to ethereum zero address371 AddressIsZero,372 /// Target collection doesn't supports this operation373 UnsupportedOperation,374375 /// Not sufficient founds to perform action376 NotSufficientFounds,377378 /// Collection has nesting disabled379 NestingIsDisabled,380 /// Only owner may nest tokens under this collection381 OnlyOwnerAllowedToNest,382 /// Only tokens from specific collections may nest tokens under this383 SourceCollectionIsNotAllowedToNest,384385 /// Tried to store more data than allowed in collection field386 CollectionFieldSizeExceeded,387388 /// Tried to store more property data than allowed389 NoSpaceForProperty,390391 /// Tried to store more property keys than allowed392 PropertyLimitReached,393394 /// Property key is too long395 PropertyKeyIsTooLong,396397 /// Only ASCII letters, digits, and '_', '-' are allowed398 InvalidCharacterInPropertyKey,399400 /// Empty property keys are forbidden401 EmptyPropertyKey,402 }403404 #[pallet::storage]405 pub type CreatedCollectionCount<T> = StorageValue<Value = CollectionId, QueryKind = ValueQuery>;406 #[pallet::storage]407 pub type DestroyedCollectionCount<T> =408 StorageValue<Value = CollectionId, QueryKind = ValueQuery>;409410 /// Collection info411 #[pallet::storage]412 pub type CollectionById<T> = StorageMap<413 Hasher = Blake2_128Concat,414 Key = CollectionId,415 Value = Collection<<T as frame_system::Config>::AccountId>,416 QueryKind = OptionQuery,417 >;418419 /// Collection properties420 #[pallet::storage]421 #[pallet::getter(fn collection_properties)]422 pub type CollectionProperties<T> = StorageMap<423 Hasher = Blake2_128Concat,424 Key = CollectionId,425 Value = Properties,426 QueryKind = ValueQuery,427 OnEmpty = up_data_structs::CollectionProperties,428 >;429430 #[pallet::storage]431 #[pallet::getter(fn property_permissions)]432 pub type CollectionPropertyPermissions<T> = StorageMap<433 Hasher = Blake2_128Concat,434 Key = CollectionId,435 Value = PropertiesPermissionMap,436 QueryKind = ValueQuery,437 >;438439 /// Large variable-size collection fields are extracted here440 #[pallet::storage]441 pub type CollectionData<T> = StorageNMap<442 Key = (443 Key<Twox64Concat, CollectionId>,444 Key<Twox64Concat, CollectionField>,445 ),446 Value = BoundedVec<u8, ConstU32<COLLECTION_FIELD_LIMIT>>,447 QueryKind = ValueQuery,448 >;449450 #[pallet::storage]451 pub type AdminAmount<T> = StorageMap<452 Hasher = Blake2_128Concat,453 Key = CollectionId,454 Value = u32,455 QueryKind = ValueQuery,456 >;457458 /// List of collection admins459 #[pallet::storage]460 pub type IsAdmin<T: Config> = StorageNMap<461 Key = (462 Key<Blake2_128Concat, CollectionId>,463 Key<Blake2_128Concat, T::CrossAccountId>,464 ),465 Value = bool,466 QueryKind = ValueQuery,467 >;468469 /// Allowlisted collection users470 #[pallet::storage]471 pub type Allowlist<T: Config> = StorageNMap<472 Key = (473 Key<Blake2_128Concat, CollectionId>,474 Key<Blake2_128Concat, T::CrossAccountId>,475 ),476 Value = bool,477 QueryKind = ValueQuery,478 >;479480 /// Not used by code, exists only to provide some types to metadata481 #[pallet::storage]482 pub type DummyStorageValue<T: Config> = StorageValue<483 Value = (484 CollectionStats,485 CollectionId,486 TokenId,487 PhantomType<TokenData<T::CrossAccountId>>,488 PhantomType<RpcCollection<T::AccountId>>,489 // RMRK490 PhantomType<RmrkCollectionInfo<T::AccountId>>,491 PhantomType<RmrkInstanceInfo<T::AccountId>>,492 PhantomType<RmrkResourceInfo>,493 PhantomType<RmrkPropertyInfo>,494 PhantomType<RmrkBaseInfo<T::AccountId>>,495 PhantomType<RmrkPartType>,496 PhantomType<RmrkTheme>,497 PhantomType<RmrkNftChild>,498 ),499 QueryKind = OptionQuery,500 >;501502 #[pallet::hooks]503 impl<T: Config> Hooks<BlockNumberFor<T>> for Pallet<T> {504 fn on_runtime_upgrade() -> Weight {505 if StorageVersion::get::<Pallet<T>>() < StorageVersion::new(1) {506 use up_data_structs::{CollectionVersion1, CollectionVersion2};507 <CollectionById<T>>::translate::<CollectionVersion1<T::AccountId>, _>(|id, v| {508 Self::set_field_raw(509 id,510 CollectionField::OffchainSchema,511 v.offchain_schema.clone().into_inner(),512 )513 .expect("data has lower bounds than field");514 Self::set_field_raw(515 id,516 CollectionField::ConstOnChainSchema,517 v.const_on_chain_schema.clone().into_inner(),518 )519 .expect("data has lower bounds than field");520521 Some(CollectionVersion2::from(v))522 });523 }524525 0526 }527 }528}529530impl<T: Config> Pallet<T> {531 /// Ethereum receiver 0x0000000000000000000000000000000000000000 is reserved, and shouldn't own tokens532 pub fn ensure_correct_receiver(receiver: &T::CrossAccountId) -> DispatchResult {533 ensure!(534 &T::CrossAccountId::from_eth(H160([0; 20])) != receiver,535 <Error<T>>::AddressIsZero536 );537 Ok(())538 }539 pub fn adminlist(collection: CollectionId) -> Vec<T::CrossAccountId> {540 <IsAdmin<T>>::iter_prefix((collection,))541 .map(|(a, _)| a)542 .collect()543 }544 pub fn allowlist(collection: CollectionId) -> Vec<T::CrossAccountId> {545 <Allowlist<T>>::iter_prefix((collection,))546 .map(|(a, _)| a)547 .collect()548 }549 pub fn allowed(collection: CollectionId, user: T::CrossAccountId) -> bool {550 <Allowlist<T>>::get((collection, user))551 }552 pub fn collection_stats() -> CollectionStats {553 let created = <CreatedCollectionCount<T>>::get();554 let destroyed = <DestroyedCollectionCount<T>>::get();555 CollectionStats {556 created: created.0,557 destroyed: destroyed.0,558 alive: created.0 - destroyed.0,559 }560 }561562 pub fn effective_collection_limits(collection: CollectionId) -> Option<CollectionLimits> {563 let collection = <CollectionById<T>>::get(collection);564 if collection.is_none() {565 return None;566 }567568 let collection = collection.unwrap();569 let limits = collection.limits;570 let effective_limits = CollectionLimits {571 account_token_ownership_limit: Some(limits.account_token_ownership_limit()),572 sponsored_data_size: Some(limits.sponsored_data_size()),573 sponsored_data_rate_limit: Some(574 limits575 .sponsored_data_rate_limit576 .unwrap_or(SponsoringRateLimit::SponsoringDisabled),577 ),578 token_limit: Some(limits.token_limit()),579 sponsor_transfer_timeout: Some(limits.sponsor_transfer_timeout(580 match collection.mode {581 CollectionMode::NFT => NFT_SPONSOR_TRANSFER_TIMEOUT,582 CollectionMode::Fungible(_) => FUNGIBLE_SPONSOR_TRANSFER_TIMEOUT,583 CollectionMode::ReFungible => REFUNGIBLE_SPONSOR_TRANSFER_TIMEOUT,584 },585 )),586 sponsor_approve_timeout: Some(limits.sponsor_approve_timeout()),587 owner_can_transfer: Some(limits.owner_can_transfer()),588 owner_can_destroy: Some(limits.owner_can_destroy()),589 transfers_enabled: Some(limits.transfers_enabled()),590 nesting_rule: Some(limits.nesting_rule().clone()),591 };592593 Some(effective_limits)594 }595596 pub fn rpc_collection(collection: CollectionId) -> Option<RpcCollection<T::AccountId>> {597 let Collection {598 name,599 description,600 owner,601 mode,602 access,603 token_prefix,604 mint_mode,605 schema_version,606 sponsorship,607 limits,608 } = <CollectionById<T>>::get(collection)?;609610 let token_property_permissions = <CollectionPropertyPermissions<T>>::get(collection)611 .into_iter()612 .map(|(key, permission)| PropertyKeyPermission {613 key,614 permission,615 })616 .collect();617618 let properties = <CollectionProperties<T>>::get(collection)619 .into_iter()620 .map(|(key, value)| Property {621 key,622 value,623 })624 .collect();625626 Some(RpcCollection {627 name: name.into_inner(),628 description: description.into_inner(),629 owner,630 mode,631 access,632 token_prefix: token_prefix.into_inner(),633 mint_mode,634 schema_version,635 sponsorship,636 limits,637 offchain_schema: <CollectionData<T>>::get((638 collection,639 CollectionField::OffchainSchema,640 ))641 .into_inner(),642 const_on_chain_schema: <CollectionData<T>>::get((643 collection,644 CollectionField::ConstOnChainSchema,645 ))646 .into_inner(),647 token_property_permissions,648 properties,649 })650 }651}652653impl<T: Config> Pallet<T> {654 pub fn init_collection(655 owner: T::AccountId,656 data: CreateCollectionData<T::AccountId>,657 ) -> Result<CollectionId, DispatchError> {658 {659 ensure!(660 data.token_prefix.len() <= MAX_TOKEN_PREFIX_LENGTH as usize,661 Error::<T>::CollectionTokenPrefixLimitExceeded662 );663 }664665 let created_count = <CreatedCollectionCount<T>>::get()666 .0667 .checked_add(1)668 .ok_or(ArithmeticError::Overflow)?;669 let destroyed_count = <DestroyedCollectionCount<T>>::get().0;670 let id = CollectionId(created_count);671672 // bound Total number of collections673 ensure!(674 created_count - destroyed_count <= COLLECTION_NUMBER_LIMIT,675 <Error<T>>::TotalCollectionsLimitExceeded676 );677678 // =========679680 let collection = Collection {681 owner: owner.clone(),682 name: data.name,683 mode: data.mode.clone(),684 mint_mode: false,685 access: data.access.unwrap_or_default(),686 description: data.description,687 token_prefix: data.token_prefix,688 schema_version: data.schema_version.unwrap_or_default(),689 sponsorship: data690 .pending_sponsor691 .map(SponsorshipState::Unconfirmed)692 .unwrap_or_default(),693 limits: data694 .limits695 .map(|limits| Self::clamp_limits(data.mode.clone(), &Default::default(), limits))696 .unwrap_or_else(|| Ok(CollectionLimits::default()))?,697 };698699 let mut collection_properties = up_data_structs::CollectionProperties::get();700 collection_properties701 .try_set_from_iter(data.properties.into_iter())702 .map_err(<Error<T>>::from)?;703704 CollectionProperties::<T>::insert(id, collection_properties);705706 let mut token_props_permissions = PropertiesPermissionMap::new();707 token_props_permissions708 .try_set_from_iter(data.token_property_permissions.into_iter())709 .map_err(<Error<T>>::from)?;710711 CollectionPropertyPermissions::<T>::insert(id, token_props_permissions);712713 // Take a (non-refundable) deposit of collection creation714 {715 let mut imbalance =716 <<<T as Config>::Currency as Currency<T::AccountId>>::PositiveImbalance>::zero();717 imbalance.subsume(718 <<T as Config>::Currency as Currency<T::AccountId>>::deposit_creating(719 &T::TreasuryAccountId::get(),720 T::CollectionCreationPrice::get(),721 ),722 );723 <T as Config>::Currency::settle(724 &owner,725 imbalance,726 WithdrawReasons::TRANSFER,727 ExistenceRequirement::KeepAlive,728 )729 .map_err(|_| Error::<T>::NotSufficientFounds)?;730 }731732 <CreatedCollectionCount<T>>::put(created_count);733 <Pallet<T>>::deposit_event(Event::CollectionCreated(id, data.mode.id(), owner.clone()));734 <CollectionById<T>>::insert(id, collection);735 Self::set_field_raw(736 id,737 CollectionField::OffchainSchema,738 data.offchain_schema.into_inner(),739 )740 .expect("data has lower bounds than field");741 Self::set_field_raw(742 id,743 CollectionField::ConstOnChainSchema,744 data.const_on_chain_schema.into_inner(),745 )746 .expect("data has lower bounds than field");747 Ok(id)748 }749750 pub fn destroy_collection(751 collection: CollectionHandle<T>,752 sender: &T::CrossAccountId,753 ) -> DispatchResult {754 ensure!(755 collection.limits.owner_can_destroy(),756 <Error<T>>::NoPermission,757 );758 collection.check_is_owner(sender)?;759760 let destroyed_collections = <DestroyedCollectionCount<T>>::get()761 .0762 .checked_add(1)763 .ok_or(ArithmeticError::Overflow)?;764765 // =========766767 <DestroyedCollectionCount<T>>::put(destroyed_collections);768 <CollectionById<T>>::remove(collection.id);769 <CollectionData<T>>::remove_prefix((collection.id,), None);770 <AdminAmount<T>>::remove(collection.id);771 <IsAdmin<T>>::remove_prefix((collection.id,), None);772 <Allowlist<T>>::remove_prefix((collection.id,), None);773 <CollectionProperties<T>>::remove(collection.id);774775 <Pallet<T>>::deposit_event(Event::CollectionDestroyed(collection.id));776 Ok(())777 }778779 pub fn set_collection_property(780 collection: &CollectionHandle<T>,781 sender: &T::CrossAccountId,782 property: Property,783 ) -> DispatchResult {784 collection.check_is_owner_or_admin(sender)?;785786 CollectionProperties::<T>::try_mutate(collection.id, |properties| {787 let property = property.clone();788 properties.try_set(property.key, property.value)789 })790 .map_err(<Error<T>>::from)?;791792 Self::deposit_event(Event::CollectionPropertySet(collection.id, property.key));793794 Ok(())795 }796797 pub fn set_scoped_collection_property(798 collection_id: CollectionId,799 scope: PropertyScope,800 property: Property,801 ) -> DispatchResult {802 CollectionProperties::<T>::try_mutate(collection_id, |properties| {803 properties.try_scoped_set(scope, property.key, property.value)804 })805 .map_err(<Error<T>>::from)?;806807 Ok(())808 }809810 pub fn set_scoped_collection_properties(811 collection_id: CollectionId,812 scope: PropertyScope,813 properties: impl Iterator<Item = Property>,814 ) -> DispatchResult {815 CollectionProperties::<T>::try_mutate(collection_id, |stored_properties| {816 stored_properties.try_scoped_set_from_iter(scope, properties)817 })818 .map_err(<Error<T>>::from)?;819820 Ok(())821 }822823 #[transactional]824 pub fn set_collection_properties(825 collection: &CollectionHandle<T>,826 sender: &T::CrossAccountId,827 properties: Vec<Property>,828 ) -> DispatchResult {829 for property in properties {830 Self::set_collection_property(collection, sender, property)?;831 }832833 Ok(())834 }835836 pub fn delete_collection_property(837 collection: &CollectionHandle<T>,838 sender: &T::CrossAccountId,839 property_key: PropertyKey,840 ) -> DispatchResult {841 collection.check_is_owner_or_admin(sender)?;842843 CollectionProperties::<T>::try_mutate(collection.id, |properties| {844 properties.remove(&property_key)845 })846 .map_err(<Error<T>>::from)?;847848 Self::deposit_event(Event::CollectionPropertyDeleted(849 collection.id,850 property_key,851 ));852853 Ok(())854 }855856 #[transactional]857 pub fn delete_collection_properties(858 collection: &CollectionHandle<T>,859 sender: &T::CrossAccountId,860 property_keys: Vec<PropertyKey>,861 ) -> DispatchResult {862 for key in property_keys {863 Self::delete_collection_property(collection, sender, key)?;864 }865866 Ok(())867 }868869 pub fn set_property_permission(870 collection: &CollectionHandle<T>,871 sender: &T::CrossAccountId,872 property_permission: PropertyKeyPermission,873 ) -> DispatchResult {874 collection.check_is_owner_or_admin(sender)?;875876 let all_permissions = CollectionPropertyPermissions::<T>::get(collection.id);877 let current_permission = all_permissions.get(&property_permission.key);878 if matches![879 current_permission,880 Some(PropertyPermission { mutable: false, .. })881 ] {882 return Err(<Error<T>>::NoPermission.into());883 }884885 CollectionPropertyPermissions::<T>::try_mutate(collection.id, |permissions| {886 let property_permission = property_permission.clone();887 permissions.try_set(property_permission.key, property_permission.permission)888 })889 .map_err(<Error<T>>::from)?;890891 Self::deposit_event(Event::PropertyPermissionSet(892 collection.id,893 property_permission.key,894 ));895896 Ok(())897 }898899 #[transactional]900 pub fn set_property_permissions(901 collection: &CollectionHandle<T>,902 sender: &T::CrossAccountId,903 property_permissions: Vec<PropertyKeyPermission>,904 ) -> DispatchResult {905 for prop_pemission in property_permissions {906 Self::set_property_permission(collection, sender, prop_pemission)?;907 }908909 Ok(())910 }911912 pub fn get_collection_property(913 collection_id: CollectionId,914 key: &PropertyKey,915 ) -> Option<PropertyValue> {916 Self::collection_properties(collection_id).get(key).cloned()917 }918919 pub fn bytes_keys_to_property_keys(920 keys: Vec<Vec<u8>>,921 ) -> Result<Vec<PropertyKey>, DispatchError> {922 keys.into_iter()923 .map(|key| -> Result<PropertyKey, DispatchError> {924 key.try_into()925 .map_err(|_| <Error<T>>::PropertyKeyIsTooLong.into())926 })927 .collect::<Result<Vec<PropertyKey>, DispatchError>>()928 }929930 pub fn filter_collection_properties(931 collection_id: CollectionId,932 keys: Option<Vec<PropertyKey>>,933 ) -> Result<Vec<Property>, DispatchError> {934 let properties = Self::collection_properties(collection_id);935936 let properties = keys937 .map(|keys| {938 keys.into_iter()939 .filter_map(|key| {940 properties.get(&key).map(|value| Property {941 key,942 value: value.clone(),943 })944 })945 .collect()946 })947 .unwrap_or_else(|| {948 properties949 .into_iter()950 .map(|(key, value)| Property {951 key,952 value,953 })954 .collect()955 });956957 Ok(properties)958 }959960 pub fn filter_property_permissions(961 collection_id: CollectionId,962 keys: Option<Vec<PropertyKey>>,963 ) -> Result<Vec<PropertyKeyPermission>, DispatchError> {964 let permissions = Self::property_permissions(collection_id);965966 let key_permissions = keys967 .map(|keys| {968 keys.into_iter()969 .filter_map(|key| {970 permissions971 .get(&key)972 .map(|permission| PropertyKeyPermission {973 key,974 permission: permission.clone(),975 })976 })977 .collect()978 })979 .unwrap_or_else(|| {980 permissions981 .into_iter()982 .map(|(key, permission)| PropertyKeyPermission {983 key,984 permission,985 })986 .collect()987 });988989 Ok(key_permissions)990 }991992 fn set_field_raw(993 collection_id: CollectionId,994 field: CollectionField,995 value: Vec<u8>,996 ) -> DispatchResult {997 if !value.is_empty() {998 <CollectionData<T>>::insert(999 (collection_id, field),1000 BoundedVec::try_from(value).map_err(|_| <Error<T>>::CollectionFieldSizeExceeded)?,1001 )1002 } else {1003 <CollectionData<T>>::remove((collection_id, field));1004 }1005 Ok(())1006 }10071008 pub fn set_field(1009 collection: &CollectionHandle<T>,1010 sender: &T::CrossAccountId,1011 field: CollectionField,1012 value: Vec<u8>,1013 ) -> DispatchResult {1014 collection.check_is_owner_or_admin(sender)?;10151016 // =========10171018 Self::set_field_raw(collection.id, field, value)1019 }10201021 pub fn toggle_allowlist(1022 collection: &CollectionHandle<T>,1023 sender: &T::CrossAccountId,1024 user: &T::CrossAccountId,1025 allowed: bool,1026 ) -> DispatchResult {1027 collection.check_is_owner_or_admin(sender)?;10281029 // =========10301031 if allowed {1032 <Allowlist<T>>::insert((collection.id, user), true);1033 } else {1034 <Allowlist<T>>::remove((collection.id, user));1035 }10361037 Ok(())1038 }10391040 pub fn toggle_admin(1041 collection: &CollectionHandle<T>,1042 sender: &T::CrossAccountId,1043 user: &T::CrossAccountId,1044 admin: bool,1045 ) -> DispatchResult {1046 collection.check_is_owner_or_admin(sender)?;10471048 let was_admin = <IsAdmin<T>>::get((collection.id, user));1049 if was_admin == admin {1050 return Ok(());1051 }1052 let amount = <AdminAmount<T>>::get(collection.id);10531054 if admin {1055 let amount = amount1056 .checked_add(1)1057 .ok_or(<Error<T>>::CollectionAdminCountExceeded)?;1058 ensure!(1059 amount <= Self::collection_admins_limit(),1060 <Error<T>>::CollectionAdminCountExceeded,1061 );10621063 // =========10641065 <AdminAmount<T>>::insert(collection.id, amount);1066 <IsAdmin<T>>::insert((collection.id, user), true);1067 } else {1068 <AdminAmount<T>>::insert(collection.id, amount.saturating_sub(1));1069 <IsAdmin<T>>::remove((collection.id, user));1070 }10711072 Ok(())1073 }10741075 pub fn clamp_limits(1076 mode: CollectionMode,1077 old_limit: &CollectionLimits,1078 mut new_limit: CollectionLimits,1079 ) -> Result<CollectionLimits, DispatchError> {1080 macro_rules! limit_default {1081 ($old:ident, $new:ident, $($field:ident $(($arg:expr))? => $check:expr),* $(,)?) => {{1082 $(1083 if let Some($new) = $new.$field {1084 let $old = $old.$field($($arg)?);1085 let _ = $new;1086 let _ = $old;1087 $check1088 } else {1089 $new.$field = $old.$field1090 }1091 )*1092 }};1093 }10941095 limit_default!(old_limit, new_limit,1096 account_token_ownership_limit => ensure!(1097 new_limit <= MAX_TOKEN_OWNERSHIP,1098 <Error<T>>::CollectionLimitBoundsExceeded,1099 ),1100 sponsor_transfer_timeout(match mode {1101 CollectionMode::NFT => NFT_SPONSOR_TRANSFER_TIMEOUT,1102 CollectionMode::Fungible(_) => FUNGIBLE_SPONSOR_TRANSFER_TIMEOUT,1103 CollectionMode::ReFungible => REFUNGIBLE_SPONSOR_TRANSFER_TIMEOUT,1104 }) => ensure!(1105 new_limit <= MAX_SPONSOR_TIMEOUT,1106 <Error<T>>::CollectionLimitBoundsExceeded,1107 ),1108 sponsored_data_size => ensure!(1109 new_limit <= CUSTOM_DATA_LIMIT,1110 <Error<T>>::CollectionLimitBoundsExceeded,1111 ),1112 token_limit => ensure!(1113 old_limit >= new_limit && new_limit > 0,1114 <Error<T>>::CollectionTokenLimitExceeded1115 ),1116 owner_can_transfer => ensure!(1117 old_limit || !new_limit,1118 <Error<T>>::OwnerPermissionsCantBeReverted,1119 ),1120 owner_can_destroy => ensure!(1121 old_limit || !new_limit,1122 <Error<T>>::OwnerPermissionsCantBeReverted,1123 ),1124 sponsored_data_rate_limit => {},1125 transfers_enabled => {},1126 );1127 Ok(new_limit)1128 }1129}11301131#[macro_export]1132macro_rules! unsupported {1133 () => {1134 Err(<Error<T>>::UnsupportedOperation.into())1135 };1136}11371138/// Worst cases1139pub trait CommonWeightInfo<CrossAccountId> {1140 fn create_item() -> Weight;1141 fn create_multiple_items(amount: &[CreateItemData]) -> Weight;1142 fn create_multiple_items_ex(cost: &CreateItemExData<CrossAccountId>) -> Weight;1143 fn burn_item() -> Weight;1144 fn set_collection_properties(amount: u32) -> Weight;1145 fn delete_collection_properties(amount: u32) -> Weight;1146 fn set_token_properties(amount: u32) -> Weight;1147 fn delete_token_properties(amount: u32) -> Weight;1148 fn set_property_permissions(amount: u32) -> Weight;1149 fn transfer() -> Weight;1150 fn approve() -> Weight;1151 fn transfer_from() -> Weight;1152 fn burn_from() -> Weight;1153}11541155pub trait CommonCollectionOperations<T: Config> {1156 fn create_item(1157 &self,1158 sender: T::CrossAccountId,1159 to: T::CrossAccountId,1160 data: CreateItemData,1161 nesting_budget: &dyn Budget,1162 ) -> DispatchResultWithPostInfo;1163 fn create_multiple_items(1164 &self,1165 sender: T::CrossAccountId,1166 to: T::CrossAccountId,1167 data: Vec<CreateItemData>,1168 nesting_budget: &dyn Budget,1169 ) -> DispatchResultWithPostInfo;1170 fn create_multiple_items_ex(1171 &self,1172 sender: T::CrossAccountId,1173 data: CreateItemExData<T::CrossAccountId>,1174 nesting_budget: &dyn Budget,1175 ) -> DispatchResultWithPostInfo;1176 fn burn_item(1177 &self,1178 sender: T::CrossAccountId,1179 token: TokenId,1180 amount: u128,1181 ) -> DispatchResultWithPostInfo;1182 fn set_collection_properties(1183 &self,1184 sender: T::CrossAccountId,1185 properties: Vec<Property>,1186 ) -> DispatchResultWithPostInfo;1187 fn delete_collection_properties(1188 &self,1189 sender: &T::CrossAccountId,1190 property_keys: Vec<PropertyKey>,1191 ) -> DispatchResultWithPostInfo;1192 fn set_token_properties(1193 &self,1194 sender: T::CrossAccountId,1195 token_id: TokenId,1196 property: Vec<Property>,1197 ) -> DispatchResultWithPostInfo;1198 fn delete_token_properties(1199 &self,1200 sender: T::CrossAccountId,1201 token_id: TokenId,1202 property_keys: Vec<PropertyKey>,1203 ) -> DispatchResultWithPostInfo;1204 fn set_property_permissions(1205 &self,1206 sender: &T::CrossAccountId,1207 property_permissions: Vec<PropertyKeyPermission>,1208 ) -> DispatchResultWithPostInfo;1209 fn transfer(1210 &self,1211 sender: T::CrossAccountId,1212 to: T::CrossAccountId,1213 token: TokenId,1214 amount: u128,1215 nesting_budget: &dyn Budget,1216 ) -> DispatchResultWithPostInfo;1217 fn approve(1218 &self,1219 sender: T::CrossAccountId,1220 spender: T::CrossAccountId,1221 token: TokenId,1222 amount: u128,1223 ) -> DispatchResultWithPostInfo;1224 fn transfer_from(1225 &self,1226 sender: T::CrossAccountId,1227 from: T::CrossAccountId,1228 to: T::CrossAccountId,1229 token: TokenId,1230 amount: u128,1231 nesting_budget: &dyn Budget,1232 ) -> DispatchResultWithPostInfo;1233 fn burn_from(1234 &self,1235 sender: T::CrossAccountId,1236 from: T::CrossAccountId,1237 token: TokenId,1238 amount: u128,1239 nesting_budget: &dyn Budget,1240 ) -> DispatchResultWithPostInfo;12411242 fn check_nesting(1243 &self,1244 sender: T::CrossAccountId,1245 from: (CollectionId, TokenId),1246 under: TokenId,1247 budget: &dyn Budget,1248 ) -> DispatchResult;12491250 fn account_tokens(&self, account: T::CrossAccountId) -> Vec<TokenId>;1251 fn collection_tokens(&self) -> Vec<TokenId>;1252 fn token_exists(&self, token: TokenId) -> bool;1253 fn last_token_id(&self) -> TokenId;12541255 fn token_owner(&self, token: TokenId) -> Option<T::CrossAccountId>;1256 fn const_metadata(&self, token: TokenId) -> Vec<u8>;1257 fn token_property(&self, token_id: TokenId, key: &PropertyKey) -> Option<PropertyValue>;1258 fn token_properties(&self, token_id: TokenId, keys: Option<Vec<PropertyKey>>) -> Vec<Property>;1259 /// Amount of unique collection tokens1260 fn total_supply(&self) -> u32;1261 /// Amount of different tokens account has (Applicable to nonfungible/refungible)1262 fn account_balance(&self, account: T::CrossAccountId) -> u32;1263 /// Amount of specific token account have (Applicable to fungible/refungible)1264 fn balance(&self, account: T::CrossAccountId, token: TokenId) -> u128;1265 fn allowance(1266 &self,1267 sender: T::CrossAccountId,1268 spender: T::CrossAccountId,1269 token: TokenId,1270 ) -> u128;1271}12721273// Flexible enough for implementing CommonCollectionOperations1274pub fn with_weight(res: DispatchResult, weight: Weight) -> DispatchResultWithPostInfo {1275 let post_info = PostDispatchInfo {1276 actual_weight: Some(weight),1277 pays_fee: Pays::Yes,1278 };1279 match res {1280 Ok(()) => Ok(post_info),1281 Err(error) => Err(DispatchErrorWithPostInfo { post_info, error }),1282 }1283}12841285impl<T: Config> From<PropertiesError> for Error<T> {1286 fn from(error: PropertiesError) -> Self {1287 match error {1288 PropertiesError::NoSpaceForProperty => Self::NoSpaceForProperty,1289 PropertiesError::PropertyLimitReached => Self::PropertyLimitReached,1290 PropertiesError::InvalidCharacterInPropertyKey => Self::InvalidCharacterInPropertyKey,1291 PropertiesError::PropertyKeyIsTooLong => Self::PropertyKeyIsTooLong,1292 PropertiesError::EmptyPropertyKey => Self::EmptyPropertyKey,1293 }1294 }1295}pallets/fungible/src/common.rsdiffbeforeafterboth--- a/pallets/fungible/src/common.rs
+++ b/pallets/fungible/src/common.rs
@@ -51,27 +51,27 @@
<SelfWeightOf<T>>::burn_item()
}
- fn set_collection_properties(amount: u32) -> Weight {
+ fn set_collection_properties(_amount: u32) -> Weight {
// Error
0
}
- fn delete_collection_properties(amount: u32) -> Weight {
+ fn delete_collection_properties(_amount: u32) -> Weight {
// Error
0
}
- fn set_token_properties(amount: u32) -> Weight {
+ fn set_token_properties(_amount: u32) -> Weight {
// Error
0
}
- fn delete_token_properties(amount: u32) -> Weight {
+ fn delete_token_properties(_amount: u32) -> Weight {
// Error
0
}
- fn set_property_permissions(amount: u32) -> Weight {
+ fn set_property_permissions(_amount: u32) -> Weight {
// Error
0
}
@@ -320,9 +320,6 @@
fn token_owner(&self, _token: TokenId) -> Option<T::CrossAccountId> {
None
- }
- fn const_metadata(&self, _token: TokenId) -> Vec<u8> {
- Vec::new()
}
fn token_property(&self, _token_id: TokenId, _key: &PropertyKey) -> Option<PropertyValue> {
pallets/fungible/src/lib.rsdiffbeforeafterboth--- a/pallets/fungible/src/lib.rs
+++ b/pallets/fungible/src/lib.rs
@@ -168,7 +168,7 @@
.checked_sub(amount)
.ok_or(<CommonError<T>>::TokenValueTooLow)?;
- if collection.access == AccessMode::AllowList {
+ if collection.permissions.access() == AccessMode::AllowList {
collection.check_allowlist(owner)?;
}
@@ -210,7 +210,7 @@
<CommonError<T>>::TransferNotAllowed,
);
- if collection.access == AccessMode::AllowList {
+ if collection.permissions.access() == AccessMode::AllowList {
collection.check_allowlist(from)?;
collection.check_allowlist(to)?;
}
@@ -280,7 +280,7 @@
) -> DispatchResult {
if !collection.is_owner_or_admin(sender) {
ensure!(
- collection.mint_mode,
+ collection.permissions.mint_mode(),
<CommonError<T>>::PublicMintingNotAllowed
);
collection.check_allowlist(sender)?;
@@ -380,7 +380,7 @@
spender: &T::CrossAccountId,
amount: u128,
) -> DispatchResult {
- if collection.access == AccessMode::AllowList {
+ if collection.permissions.access() == AccessMode::AllowList {
collection.check_allowlist(owner)?;
collection.check_allowlist(spender)?;
}
@@ -408,7 +408,7 @@
if spender.conv_eq(from) {
return Ok(None);
}
- if collection.access == AccessMode::AllowList {
+ if collection.permissions.access() == AccessMode::AllowList {
// `from`, `to` checked in [`transfer`]
collection.check_allowlist(spender)?;
}
pallets/nonfungible/src/benchmarking.rsdiffbeforeafterboth--- a/pallets/nonfungible/src/benchmarking.rs
+++ b/pallets/nonfungible/src/benchmarking.rs
@@ -29,9 +29,7 @@
const SEED: u32 = 1;
fn create_max_item_data<T: Config>(owner: T::CrossAccountId) -> CreateItemData<T> {
- let const_data = create_data::<CUSTOM_DATA_LIMIT>();
CreateItemData::<T> {
- const_data,
owner,
properties: Default::default(),
}
pallets/nonfungible/src/common.rsdiffbeforeafterboth--- a/pallets/nonfungible/src/common.rs
+++ b/pallets/nonfungible/src/common.rs
@@ -116,7 +116,6 @@
) -> Result<CreateItemData<T>, DispatchError> {
match data {
up_data_structs::CreateItemData::NFT(data) => Ok(CreateItemData::<T> {
- const_data: data.const_data,
properties: data.properties,
owner: to.clone(),
}),
@@ -376,12 +375,6 @@
fn token_owner(&self, token: TokenId) -> Option<T::CrossAccountId> {
<TokenData<T>>::get((self.id, token)).map(|t| t.owner)
- }
- fn const_metadata(&self, token: TokenId) -> Vec<u8> {
- <TokenData<T>>::get((self.id, token))
- .map(|t| t.const_data)
- .unwrap_or_default()
- .into_inner()
}
fn token_property(&self, token_id: TokenId, key: &PropertyKey) -> Option<PropertyValue> {
pallets/nonfungible/src/erc.rsdiffbeforeafterboth--- a/pallets/nonfungible/src/erc.rs
+++ b/pallets/nonfungible/src/erc.rs
@@ -109,15 +109,6 @@
}
}
-fn error_unsupported_schema_version() -> Error {
- alloc::format!(
- "Unsupported schema version! Support only {:?}",
- SchemaVersion::ImageURL
- )
- .as_str()
- .into()
-}
-
#[derive(ToLog)]
pub enum ERC721Events {
Transfer {
@@ -167,16 +158,10 @@
/// Returns token's const_metadata
#[solidity(rename_selector = "tokenURI")]
fn token_uri(&self, token_id: uint256) -> Result<string> {
- if !matches!(self.schema_version, SchemaVersion::ImageURL) {
- return Err(error_unsupported_schema_version());
- }
-
self.consume_store_reads(1)?;
- let token_id: u32 = token_id.try_into().map_err(|_| "token id overflow")?;
+ let _token_id: u32 = token_id.try_into().map_err(|_| "token id overflow")?;
Ok(string::from_utf8_lossy(
- &<TokenData<T>>::get((self.id, token_id))
- .ok_or("token not found")?
- .const_data,
+ todo!()
)
.into())
}
@@ -344,7 +329,6 @@
self,
&caller,
CreateItemData::<T> {
- const_data: BoundedVec::default(),
properties: BoundedVec::default(),
owner: to,
},
@@ -366,10 +350,6 @@
token_id: uint256,
token_uri: string,
) -> Result<bool> {
- if !matches!(self.schema_version, SchemaVersion::ImageURL) {
- return Err(error_unsupported_schema_version());
- }
-
let caller = T::CrossAccountId::from_eth(caller);
let to = T::CrossAccountId::from_eth(to);
let token_id: u32 = token_id.try_into().map_err(|_| "amount overflow")?;
@@ -385,13 +365,12 @@
return Err("item id should be next".into());
}
+ todo!("token uri");
+
<Pallet<T>>::create_item(
self,
&caller,
CreateItemData::<T> {
- const_data: Vec::<u8>::from(token_uri)
- .try_into()
- .map_err(|_| "token uri is too long")?,
properties: BoundedVec::default(),
owner: to,
},
@@ -477,7 +456,6 @@
}
let data = (0..total_tokens)
.map(|_| CreateItemData::<T> {
- const_data: BoundedVec::default(),
properties: BoundedVec::default(),
owner: to.clone(),
})
@@ -496,10 +474,6 @@
to: address,
tokens: Vec<(uint256, string)>,
) -> Result<bool> {
- if !matches!(self.schema_version, SchemaVersion::ImageURL) {
- return Err(error_unsupported_schema_version());
- }
-
let caller = T::CrossAccountId::from_eth(caller);
let to = T::CrossAccountId::from_eth(to);
let mut expected_index = <TokensMinted<T>>::get(self.id)
@@ -517,10 +491,8 @@
}
expected_index = expected_index.checked_add(1).ok_or("item id overflow")?;
+ todo!("token uri");
data.push(CreateItemData::<T> {
- const_data: Vec::<u8>::from(token_uri)
- .try_into()
- .map_err(|_| "token uri is too long")?,
properties: BoundedVec::default(),
owner: to.clone(),
});
pallets/nonfungible/src/lib.rsdiffbeforeafterboth--- a/pallets/nonfungible/src/lib.rs
+++ b/pallets/nonfungible/src/lib.rs
@@ -33,7 +33,7 @@
use pallet_evm_coder_substrate::{SubstrateRecorder, WithRecorder};
use sp_core::H160;
use sp_runtime::{ArithmeticError, DispatchError, DispatchResult, TransactionOutcome};
-use sp_std::{vec::Vec, vec};
+use sp_std::{vec::Vec, vec, collections::btree_set::BTreeSet};
use core::ops::Deref;
use sp_std::collections::btree_map::BTreeMap;
use codec::{Encode, Decode, MaxEncodedLen};
@@ -52,6 +52,7 @@
#[struct_versioning::versioned(version = 2, upper)]
#[derive(Encode, Decode, TypeInfo, MaxEncodedLen)]
pub struct ItemData<CrossAccountId> {
+ #[version(..2)]
pub const_data: BoundedVec<u8, CustomDataLimit>,
#[version(..2)]
@@ -148,9 +149,45 @@
impl<T: Config> Hooks<BlockNumberFor<T>> for Pallet<T> {
fn on_runtime_upgrade() -> Weight {
if StorageVersion::get::<Pallet<T>>() < StorageVersion::new(1) {
- <TokenData<T>>::translate_values::<ItemDataVersion1<T::CrossAccountId>, _>(|v| {
+ 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))
- })
+ });
+ for collection in had_consts {
+ <PalletCommon<T>>::set_property_permission_unchecked(
+ collection,
+ PropertyKeyPermission {
+ key: b"_old_constData".to_vec().try_into().unwrap(),
+ permission: PropertyPermission {
+ mutable: false,
+ collection_admin: true,
+ token_owner: false,
+ },
+ }
+ ).expect("failed to configure permission");
+ }
}
0
@@ -267,7 +304,7 @@
<CommonError<T>>::NoPermission
);
- if collection.access == AccessMode::AllowList {
+ if collection.permissions.access() == AccessMode::AllowList {
collection.check_allowlist(sender)?;
}
@@ -493,7 +530,7 @@
<CommonError<T>>::NoPermission
);
- if collection.access == AccessMode::AllowList {
+ if collection.permissions.access() == AccessMode::AllowList {
collection.check_allowlist(from)?;
collection.check_allowlist(to)?;
}
@@ -579,7 +616,7 @@
) -> DispatchResult {
if !collection.is_owner_or_admin(sender) {
ensure!(
- collection.mint_mode,
+ collection.permissions.mint_mode(),
<CommonError<T>>::PublicMintingNotAllowed
);
collection.check_allowlist(sender)?;
@@ -639,7 +676,7 @@
<TokenData<T>>::insert(
(collection.id, token),
ItemData {
- const_data: data.const_data.clone(),
+ // const_data: data.const_data.clone(),
owner: data.owner.clone(),
},
);
@@ -756,7 +793,7 @@
token: TokenId,
spender: Option<&T::CrossAccountId>,
) -> DispatchResult {
- if collection.access == AccessMode::AllowList {
+ if collection.permissions.access() == AccessMode::AllowList {
collection.check_allowlist(sender)?;
if let Some(spender) = spender {
collection.check_allowlist(spender)?;
@@ -791,7 +828,7 @@
if spender.conv_eq(from) {
return Ok(());
}
- if collection.access == AccessMode::AllowList {
+ if collection.permissions.access() == AccessMode::AllowList {
// `from`, `to` checked in [`transfer`]
collection.check_allowlist(spender)?;
}
@@ -875,7 +912,7 @@
);
Ok(())
}
- match handle.limits.nesting_rule() {
+ match handle.permissions.nesting() {
NestingRule::Disabled => fail!(<CommonError<T>>::NestingIsDisabled),
NestingRule::Owner => {
ensure_sender_allowed::<T>(handle.id, under, from, sender, nesting_budget)?
pallets/proxy-rmrk-core/src/lib.rsdiffbeforeafterboth--- a/pallets/proxy-rmrk-core/src/lib.rs
+++ b/pallets/proxy-rmrk-core/src/lib.rs
@@ -403,10 +403,8 @@
nft_type: NftType,
properties: impl Iterator<Item=Property>
) -> Result<TokenId, DispatchError> {
+ todo!("store nft type");
let data = CreateNftExData {
- const_data: nft_type.encode()
- .try_into()
- .map_err(|_| <Error<T>>::NftTypeEncodeError)?,
properties: BoundedVec::default(),
owner: owner.clone(),
};
@@ -528,13 +526,8 @@
Ok(nft_property)
}
- pub fn get_nft_type(collection_id: CollectionId, token_id: TokenId) -> Result<NftType, DispatchError> {
- let token_data = <TokenData<T>>::get((collection_id, token_id))
- .ok_or(<Error<T>>::NoAvailableNftId)?;
-
- let mut const_data = token_data.const_data.as_slice();
-
- NftType::decode(&mut const_data).map_err(|_| <Error<T>>::NoAvailableNftId.into())
+ 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 {
pallets/refungible/src/common.rsdiffbeforeafterboth--- a/pallets/refungible/src/common.rs
+++ b/pallets/refungible/src/common.rs
@@ -336,11 +336,6 @@
fn token_owner(&self, _token: TokenId) -> Option<T::CrossAccountId> {
None
}
- fn const_metadata(&self, token: TokenId) -> Vec<u8> {
- <TokenData<T>>::get((self.id, token))
- .const_data
- .into_inner()
- }
fn token_property(&self, _token_id: TokenId, _key: &PropertyKey) -> Option<PropertyValue> {
None
pallets/refungible/src/lib.rsdiffbeforeafterboth--- a/pallets/refungible/src/lib.rs
+++ b/pallets/refungible/src/lib.rs
@@ -321,7 +321,7 @@
<CommonError<T>>::TransferNotAllowed
);
- if collection.access == AccessMode::AllowList {
+ if collection.permissions.access() == AccessMode::AllowList {
collection.check_allowlist(from)?;
collection.check_allowlist(to)?;
}
@@ -424,7 +424,7 @@
) -> DispatchResult {
if !collection.is_owner_or_admin(sender) {
ensure!(
- collection.mint_mode,
+ collection.permissions.mint_mode(),
<CommonError<T>>::PublicMintingNotAllowed
);
collection.check_allowlist(sender)?;
@@ -566,7 +566,7 @@
token: TokenId,
amount: u128,
) -> DispatchResult {
- if collection.access == AccessMode::AllowList {
+ if collection.permissions.access() == AccessMode::AllowList {
collection.check_allowlist(sender)?;
collection.check_allowlist(spender)?;
}
@@ -598,7 +598,7 @@
if spender.conv_eq(from) {
return Ok(None);
}
- if collection.access == AccessMode::AllowList {
+ if collection.permissions.access() == AccessMode::AllowList {
// `from`, `to` checked in [`transfer`]
collection.check_allowlist(spender)?;
}
pallets/unique/src/benchmarking.rsdiffbeforeafterboth--- a/pallets/unique/src/benchmarking.rs
+++ b/pallets/unique/src/benchmarking.rs
@@ -130,26 +130,6 @@
let collection = create_nft_collection::<T>(caller.clone())?;
}: _(RawOrigin::Signed(caller.clone()), collection, false)
- set_offchain_schema {
- let b in 0..OFFCHAIN_SCHEMA_LIMIT;
-
- let caller: T::AccountId = account("caller", 0, SEED);
- let collection = create_nft_collection::<T>(caller.clone())?;
- let data = create_var_data(b);
- }: set_offchain_schema(RawOrigin::Signed(caller.clone()), collection, data)
-
- set_const_on_chain_schema {
- let b in 0..CONST_ON_CHAIN_SCHEMA_LIMIT;
-
- let caller: T::AccountId = account("caller", 0, SEED);
- let collection = create_nft_collection::<T>(caller.clone())?;
- let data = create_var_data(b);
- }: set_const_on_chain_schema(RawOrigin::Signed(caller.clone()), collection, data)
-
- set_schema_version {
- let caller: T::AccountId = account("caller", 0, SEED);
- let collection = create_nft_collection::<T>(caller.clone())?;
- }: set_schema_version(RawOrigin::Signed(caller.clone()), collection, SchemaVersion::Unique)
set_collection_limits{
let caller: T::AccountId = account("caller", 0, SEED);
pallets/unique/src/lib.rsdiffbeforeafterboth--- a/pallets/unique/src/lib.rs
+++ b/pallets/unique/src/lib.rs
@@ -35,10 +35,10 @@
use frame_system::{self as system, ensure_signed};
use sp_runtime::{sp_std::prelude::Vec};
use up_data_structs::{
- CONST_ON_CHAIN_SCHEMA_LIMIT, OFFCHAIN_SCHEMA_LIMIT, MAX_COLLECTION_NAME_LENGTH,
+ MAX_COLLECTION_NAME_LENGTH,
MAX_COLLECTION_DESCRIPTION_LENGTH, MAX_TOKEN_PREFIX_LENGTH, AccessMode, CreateItemData,
- CollectionLimits, CollectionId, CollectionMode, TokenId, SchemaVersion, SponsorshipState,
- CreateCollectionData, CreateItemExData, budget, CollectionField, Property, PropertyKey,
+ CollectionLimits, CollectionPermissions, CollectionId, CollectionMode, TokenId, SponsorshipState,
+ CreateCollectionData, CreateItemExData, budget, Property, PropertyKey,
PropertyKeyPermission,
};
use pallet_evm::account::CrossAccountId;
@@ -162,6 +162,8 @@
/// * collection_id: Globally unique collection identifier.
CollectionLimitSet(CollectionId),
+ CollectionPermissionSet(CollectionId),
+
/// Mint permission was set
///
/// # Arguments
@@ -417,67 +419,6 @@
));
Ok(())
- }
-
- /// Toggle between normal and allow list access for the methods with access for `Anyone`.
- ///
- /// # Permissions
- ///
- /// * Collection Owner.
- ///
- /// # Arguments
- ///
- /// * collection_id.
- ///
- /// * mode: [AccessMode]
- #[weight = <SelfWeightOf<T>>::set_public_access_mode()]
- #[transactional]
- pub fn set_public_access_mode(origin, collection_id: CollectionId, mode: AccessMode) -> DispatchResult
- {
- let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);
-
- let mut target_collection = <CollectionHandle<T>>::try_get(collection_id)?;
- target_collection.check_is_owner(&sender)?;
-
- target_collection.access = mode.clone();
-
- <Pallet<T>>::deposit_event(Event::<T>::PublicAccessModeSet(
- collection_id,
- mode
- ));
-
- target_collection.save()
- }
-
- /// Allows Anyone to create tokens if:
- /// * Allow List is enabled, and
- /// * Address is added to allow list, and
- /// * This method was called with True parameter
- ///
- /// # Permissions
- /// * Collection Owner
- ///
- /// # Arguments
- ///
- /// * collection_id.
- ///
- /// * mint_permission: Boolean parameter. If True, allows minting to Anyone with conditions above.
- #[weight = <SelfWeightOf<T>>::set_mint_permission()]
- #[transactional]
- pub fn set_mint_permission(origin, collection_id: CollectionId, mint_permission: bool) -> DispatchResult
- {
- let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);
-
- let mut target_collection = <CollectionHandle<T>>::try_get(collection_id)?;
- target_collection.check_is_owner(&sender)?;
-
- target_collection.mint_mode = mint_permission;
-
- <Pallet<T>>::deposit_event(Event::<T>::MintPermissionSet(
- collection_id
- ));
-
- target_collection.save()
}
/// Change the owner of the collection.
@@ -941,118 +882,42 @@
dispatch_call::<T, _>(collection_id, |d| d.transfer_from(sender, from, recipient, item_id, value, &budget))
}
- /// Set schema standard
- /// ImageURL
- /// Unique
- ///
- /// # Permissions
- ///
- /// * Collection Owner
- /// * Collection Admin
- ///
- /// # Arguments
- ///
- /// * collection_id.
- ///
- /// * schema: SchemaVersion: enum
- #[weight = <SelfWeightOf<T>>::set_schema_version()]
+ #[weight = <SelfWeightOf<T>>::set_collection_limits()]
#[transactional]
- pub fn set_schema_version(
+ pub fn set_collection_limits(
origin,
collection_id: CollectionId,
- version: SchemaVersion
+ new_limit: CollectionLimits,
) -> DispatchResult {
let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);
let mut target_collection = <CollectionHandle<T>>::try_get(collection_id)?;
- target_collection.check_is_owner_or_admin(&sender)?;
- target_collection.schema_version = version;
-
- <Pallet<T>>::deposit_event(Event::<T>::SchemaVersionSet(
- collection_id
- ));
-
- target_collection.save()
- }
-
- /// Set off-chain data schema.
- ///
- /// # Permissions
- ///
- /// * Collection Owner
- /// * Collection Admin
- ///
- /// # Arguments
- ///
- /// * collection_id.
- ///
- /// * schema: String representing the offchain data schema.
- #[weight = <SelfWeightOf<T>>::set_offchain_schema(schema.len() as u32)]
- #[transactional]
- pub fn set_offchain_schema(
- origin,
- collection_id: CollectionId,
- schema: BoundedVec<u8, ConstU32<OFFCHAIN_SCHEMA_LIMIT>>,
- ) -> DispatchResult {
- let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);
- let collection = <CollectionHandle<T>>::try_get(collection_id)?;
+ target_collection.check_is_owner(&sender)?;
+ let old_limit = &target_collection.limits;
- // =========
+ target_collection.limits = <PalletCommon<T>>::clamp_limits(target_collection.mode.clone(), &old_limit, new_limit)?;
- <PalletCommon<T>>::set_field(&collection, &sender, CollectionField::OffchainSchema, schema.into_inner())?;
-
- <Pallet<T>>::deposit_event(Event::<T>::OffchainSchemaSet(
+ <Pallet<T>>::deposit_event(Event::<T>::CollectionLimitSet(
collection_id
));
- Ok(())
- }
- /// Set const on-chain data schema.
- ///
- /// # Permissions
- ///
- /// * Collection Owner
- /// * Collection Admin
- ///
- /// # Arguments
- ///
- /// * collection_id.
- ///
- /// * schema: String representing the const on-chain data schema.
- #[weight = <SelfWeightOf<T>>::set_const_on_chain_schema(schema.len() as u32)]
- #[transactional]
- pub fn set_const_on_chain_schema (
- origin,
- collection_id: CollectionId,
- schema: BoundedVec<u8, ConstU32<CONST_ON_CHAIN_SCHEMA_LIMIT>>
- ) -> DispatchResult {
- let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);
- let collection = <CollectionHandle<T>>::try_get(collection_id)?;
-
- // =========
-
- <PalletCommon<T>>::set_field(&collection, &sender, CollectionField::ConstOnChainSchema, schema.into_inner())?;
-
- <Pallet<T>>::deposit_event(Event::<T>::ConstOnChainSchemaSet(
- collection_id
- ));
- Ok(())
+ target_collection.save()
}
#[weight = <SelfWeightOf<T>>::set_collection_limits()]
#[transactional]
- pub fn set_collection_limits(
+ pub fn set_collection_permissions(
origin,
collection_id: CollectionId,
- new_limit: CollectionLimits,
+ new_limit: CollectionPermissions,
) -> DispatchResult {
let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);
let mut target_collection = <CollectionHandle<T>>::try_get(collection_id)?;
target_collection.check_is_owner(&sender)?;
- let old_limit = &target_collection.limits;
+ let old_limit = &target_collection.permissions;
- target_collection.limits = <PalletCommon<T>>::clamp_limits(target_collection.mode.clone(), &old_limit, new_limit)?;
+ target_collection.permissions = <PalletCommon<T>>::clamp_permissions(target_collection.mode.clone(), &old_limit, new_limit)?;
- <Pallet<T>>::deposit_event(Event::<T>::CollectionLimitSet(
+ <Pallet<T>>::deposit_event(Event::<T>::CollectionPermissionSet(
collection_id
));
primitives/data-structs/src/lib.rsdiffbeforeafterboth--- a/primitives/data-structs/src/lib.rs
+++ b/primitives/data-structs/src/lib.rs
@@ -186,7 +186,6 @@
#[derive(Encode, Decode, Clone, PartialEq, TypeInfo)]
#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]
pub struct TokenData<CrossAccountId> {
- pub const_data: Vec<u8>,
pub properties: Vec<Property>,
pub owner: Option<CrossAccountId>,
}
@@ -223,7 +222,7 @@
fn resolve(who: &AccountId, call: &Call) -> Option<AccountId>;
}
-#[derive(Encode, Decode, Eq, Debug, Clone, PartialEq, TypeInfo, MaxEncodedLen)]
+#[derive(Encode, Decode, Eq, Debug, Clone, Copy, PartialEq, TypeInfo, MaxEncodedLen)]
#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]
pub enum AccessMode {
Normal,
@@ -296,22 +295,26 @@
pub struct Collection<AccountId> {
pub owner: AccountId,
pub mode: CollectionMode,
+ #[version(..2)]
pub access: AccessMode,
pub name: BoundedVec<u16, ConstU32<MAX_COLLECTION_NAME_LENGTH>>,
pub description: BoundedVec<u16, ConstU32<MAX_COLLECTION_DESCRIPTION_LENGTH>>,
pub token_prefix: BoundedVec<u8, ConstU32<MAX_TOKEN_PREFIX_LENGTH>>,
+
+ #[version(..2)]
pub mint_mode: bool,
#[version(..2)]
pub offchain_schema: BoundedVec<u8, ConstU32<OFFCHAIN_SCHEMA_LIMIT>>,
+ #[version(..2)]
pub schema_version: SchemaVersion,
pub sponsorship: SponsorshipState<AccountId>,
- #[version(..2)]
- pub limits: CollectionLimitsVersion1, // Collection private restrictions
- #[version(2.., upper(limits.into()))]
- pub limits: CollectionLimitsVersion2,
+ pub limits: CollectionLimits,
+
+ #[version(2.., upper(Default::default()))]
+ pub permissions: CollectionPermissions,
#[version(..2)]
pub variable_on_chain_schema: BoundedVec<u8, ConstU32<VARIABLE_ON_CHAIN_SCHEMA_LIMIT>>,
@@ -329,27 +332,16 @@
pub struct RpcCollection<AccountId> {
pub owner: AccountId,
pub mode: CollectionMode,
- pub access: AccessMode,
pub name: Vec<u16>,
pub description: Vec<u16>,
pub token_prefix: Vec<u8>,
- pub mint_mode: bool,
- pub offchain_schema: Vec<u8>,
- pub schema_version: SchemaVersion,
pub sponsorship: SponsorshipState<AccountId>,
pub limits: CollectionLimits,
- pub const_on_chain_schema: Vec<u8>,
+ pub permissions: CollectionPermissions,
pub token_property_permissions: Vec<PropertyKeyPermission>,
pub properties: Vec<Property>,
}
-#[derive(Encode, Decode, Clone, PartialEq, TypeInfo, MaxEncodedLen)]
-#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]
-pub enum CollectionField {
- ConstOnChainSchema,
- OffchainSchema,
-}
-
#[derive(Encode, Decode, Clone, PartialEq, TypeInfo, Derivative, MaxEncodedLen)]
#[derivative(Debug, Default(bound = ""))]
pub struct CreateCollectionData<AccountId> {
@@ -359,11 +351,9 @@
pub name: BoundedVec<u16, ConstU32<MAX_COLLECTION_NAME_LENGTH>>,
pub description: BoundedVec<u16, ConstU32<MAX_COLLECTION_DESCRIPTION_LENGTH>>,
pub token_prefix: BoundedVec<u8, ConstU32<MAX_TOKEN_PREFIX_LENGTH>>,
- pub offchain_schema: BoundedVec<u8, ConstU32<OFFCHAIN_SCHEMA_LIMIT>>,
- pub schema_version: Option<SchemaVersion>,
pub pending_sponsor: Option<AccountId>,
pub limits: Option<CollectionLimits>,
- pub const_on_chain_schema: BoundedVec<u8, ConstU32<CONST_ON_CHAIN_SCHEMA_LIMIT>>,
+ pub permissions: Option<CollectionPermissions>,
pub token_property_permissions: CollectionPropertiesPermissionsVec,
pub properties: CollectionPropertiesVec,
}
@@ -375,7 +365,6 @@
BoundedVec<Property, ConstU32<MAX_PROPERTIES_PER_ITEM>>;
/// All fields are wrapped in `Option`s, where None means chain default
-#[struct_versioning::versioned(version = 2, upper)]
#[derive(Encode, Decode, Debug, Default, Clone, PartialEq, TypeInfo, MaxEncodedLen)]
#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]
pub struct CollectionLimits {
@@ -395,9 +384,6 @@
pub owner_can_transfer: Option<bool>,
pub owner_can_destroy: Option<bool>,
pub transfers_enabled: Option<bool>,
-
- #[version(2.., upper(None))]
- pub nesting_rule: Option<NestingRule>,
}
impl CollectionLimits {
@@ -444,9 +430,26 @@
SponsoringRateLimit::Blocks(v) => Some(v.min(MAX_SPONSOR_TIMEOUT)),
}
}
- pub fn nesting_rule(&self) -> &NestingRule {
+}
+
+#[derive(Encode, Decode, Debug, Default, Clone, PartialEq, TypeInfo, MaxEncodedLen)]
+#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]
+pub struct CollectionPermissions {
+ pub access: Option<AccessMode>,
+ pub mint_mode: Option<bool>,
+ pub nesting: Option<NestingRule>,
+}
+
+impl CollectionPermissions {
+ pub fn access(&self) -> AccessMode {
+ self.access.unwrap_or(AccessMode::Normal)
+ }
+ pub fn mint_mode(&self) -> bool {
+ self.mint_mode.unwrap_or(false)
+ }
+ pub fn nesting(&self) -> &NestingRule {
static DEFAULT: NestingRule = NestingRule::Disabled;
- self.nesting_rule.as_ref().unwrap_or(&DEFAULT)
+ self.nesting.as_ref().unwrap_or(&DEFAULT)
}
}
@@ -520,8 +523,6 @@
#[derive(Encode, Decode, MaxEncodedLen, PartialEq, Clone, TypeInfo, Derivative)]
#[derivative(Debug)]
pub struct CreateNftExData<CrossAccountId> {
- #[derivative(Debug(format_with = "bounded::vec_debug"))]
- pub const_data: BoundedVec<u8, CustomDataLimit>,
#[derivative(Debug(format_with = "bounded::vec_debug"))]
pub properties: CollectionPropertiesVec,
pub owner: CrossAccountId,
primitives/rpc/src/lib.rsdiffbeforeafterboth--- a/primitives/rpc/src/lib.rs
+++ b/primitives/rpc/src/lib.rs
@@ -41,7 +41,6 @@
fn token_owner(collection: CollectionId, token: TokenId) -> Result<Option<CrossAccountId>>;
fn topmost_token_owner(collection: CollectionId, token: TokenId) -> Result<Option<CrossAccountId>>;
- fn const_metadata(collection: CollectionId, token: TokenId) -> Result<Vec<u8>>;
fn collection_properties(collection: CollectionId, properties: Option<Vec<Vec<u8>>>) -> Result<Vec<Property>>;
runtime/common/src/runtime_apis.rsdiffbeforeafterboth--- a/runtime/common/src/runtime_apis.rs
+++ b/runtime/common/src/runtime_apis.rs
@@ -29,9 +29,6 @@
Ok(Some(<pallet_structure::Pallet<Runtime>>::find_topmost_owner(collection, token, &budget)?))
}
- fn const_metadata(collection: CollectionId, token: TokenId) -> Result<Vec<u8>, DispatchError> {
- dispatch_unique_runtime!(collection.const_metadata(token))
- }
fn collection_properties(
collection: CollectionId,
@@ -73,7 +70,6 @@
keys: Option<Vec<Vec<u8>>>
) -> Result<TokenData<CrossAccountId>, DispatchError> {
let token_data = TokenData {
- const_data: Self::const_metadata(collection, token_id)?,
properties: Self::token_properties(collection, token_id, keys)?,
owner: Self::token_owner(collection, token_id)?
};
runtime/tests/src/tests.rsdiffbeforeafterboth--- a/runtime/tests/src/tests.rs
+++ b/runtime/tests/src/tests.rs
@@ -2399,28 +2399,6 @@
// #endregion
#[test]
-fn set_const_on_chain_schema() {
- new_test_ext().execute_with(|| {
- let collection_id = create_test_collection(&CollectionMode::NFT, CollectionId(1));
-
- let origin1 = Origin::signed(1);
- assert_ok!(Unique::set_const_on_chain_schema(
- origin1,
- collection_id,
- b"test const on chain schema".to_vec().try_into().unwrap()
- ));
-
- assert_eq!(
- <pallet_common::CollectionData<Test>>::get((
- collection_id,
- CollectionField::ConstOnChainSchema
- )),
- b"test const on chain schema".to_vec()
- );
- });
-}
-
-#[test]
fn collection_transfer_flag_works() {
new_test_ext().execute_with(|| {
let origin1 = Origin::signed(1);