difftreelog
refactor remove meta update permission
in: master
11 files changed
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)]1819use core::ops::{Deref, DerefMut};20use pallet_evm_coder_substrate::{SubstrateRecorder, WithRecorder};21use sp_std::vec::Vec;22use pallet_evm::account::CrossAccountId;23use frame_support::{24 dispatch::{DispatchErrorWithPostInfo, DispatchResultWithPostInfo, Weight, PostDispatchInfo},25 ensure, fail,26 traits::{Imbalance, Get, Currency, WithdrawReasons, ExistenceRequirement},27 BoundedVec,28 weights::Pays,29};30use pallet_evm::GasWeightMapping;31use up_data_structs::{32 COLLECTION_NUMBER_LIMIT, Collection, RpcCollection, CollectionId, CreateItemData,33 MAX_TOKEN_PREFIX_LENGTH, COLLECTION_ADMINS_LIMIT, MetaUpdatePermission, TokenId,34 CollectionStats, MAX_TOKEN_OWNERSHIP, CollectionMode, NFT_SPONSOR_TRANSFER_TIMEOUT,35 FUNGIBLE_SPONSOR_TRANSFER_TIMEOUT, REFUNGIBLE_SPONSOR_TRANSFER_TIMEOUT, MAX_SPONSOR_TIMEOUT,36 CUSTOM_DATA_LIMIT, CollectionLimits, CreateCollectionData, SponsorshipState,37 CreateItemExData, SponsoringRateLimit, budget::Budget, COLLECTION_FIELD_LIMIT, CollectionField,38 PhantomType, Property, Properties, PropertiesPermissionMap, PropertyKey, PropertyPermission,39 PropertiesError, PropertyKeyPermission, TokenData, TrySet,40};41pub use pallet::*;42use sp_core::H160;43use sp_runtime::{ArithmeticError, DispatchError, DispatchResult};44#[cfg(feature = "runtime-benchmarks")]45pub mod benchmarking;46pub mod dispatch;47pub mod erc;48pub mod eth;4950#[must_use = "Should call submit_logs or save, otherwise some data will be lost for evm side"]51pub struct CollectionHandle<T: Config> {52 pub id: CollectionId,53 collection: Collection<T::AccountId>,54 pub recorder: SubstrateRecorder<T>,55}56impl<T: Config> WithRecorder<T> for CollectionHandle<T> {57 fn recorder(&self) -> &SubstrateRecorder<T> {58 &self.recorder59 }60 fn into_recorder(self) -> SubstrateRecorder<T> {61 self.recorder62 }63}64impl<T: Config> CollectionHandle<T> {65 pub fn new_with_gas_limit(id: CollectionId, gas_limit: u64) -> Option<Self> {66 <CollectionById<T>>::get(id).map(|collection| Self {67 id,68 collection,69 recorder: SubstrateRecorder::new(gas_limit),70 })71 }72 pub fn new(id: CollectionId) -> Option<Self> {73 Self::new_with_gas_limit(id, u64::MAX)74 }75 pub fn try_get(id: CollectionId) -> Result<Self, DispatchError> {76 Ok(Self::new(id).ok_or(<Error<T>>::CollectionNotFound)?)77 }78 pub fn consume_store_reads(&self, reads: u64) -> evm_coder::execution::Result<()> {79 self.recorder80 .consume_gas(T::GasWeightMapping::weight_to_gas(81 <T as frame_system::Config>::DbWeight::get()82 .read83 .saturating_mul(reads),84 ))85 }86 pub fn consume_store_writes(&self, writes: u64) -> evm_coder::execution::Result<()> {87 self.recorder88 .consume_gas(T::GasWeightMapping::weight_to_gas(89 <T as frame_system::Config>::DbWeight::get()90 .write91 .saturating_mul(writes),92 ))93 }94 pub fn save(self) -> DispatchResult {95 <CollectionById<T>>::insert(self.id, self.collection);96 Ok(())97 }98}99impl<T: Config> Deref for CollectionHandle<T> {100 type Target = Collection<T::AccountId>;101102 fn deref(&self) -> &Self::Target {103 &self.collection104 }105}106107impl<T: Config> DerefMut for CollectionHandle<T> {108 fn deref_mut(&mut self) -> &mut Self::Target {109 &mut self.collection110 }111}112113impl<T: Config> CollectionHandle<T> {114 pub fn check_is_owner(&self, subject: &T::CrossAccountId) -> DispatchResult {115 ensure!(*subject.as_sub() == self.owner, <Error<T>>::NoPermission);116 Ok(())117 }118 pub fn is_owner_or_admin(&self, subject: &T::CrossAccountId) -> bool {119 *subject.as_sub() == self.owner || <IsAdmin<T>>::get((self.id, subject))120 }121 pub fn check_is_owner_or_admin(&self, subject: &T::CrossAccountId) -> DispatchResult {122 ensure!(self.is_owner_or_admin(subject), <Error<T>>::NoPermission);123 Ok(())124 }125 pub fn ignores_allowance(&self, user: &T::CrossAccountId) -> bool {126 self.limits.owner_can_transfer() && self.is_owner_or_admin(user)127 }128 pub fn ignores_owned_amount(&self, user: &T::CrossAccountId) -> bool {129 self.limits.owner_can_transfer() && self.is_owner_or_admin(user)130 }131 pub fn check_allowlist(&self, user: &T::CrossAccountId) -> DispatchResult {132 ensure!(133 <Allowlist<T>>::get((self.id, user)),134 <Error<T>>::AddressNotInAllowlist135 );136 Ok(())137 }138139 pub fn check_can_update_meta(140 &self,141 subject: &T::CrossAccountId,142 item_owner: &T::CrossAccountId,143 ) -> DispatchResult {144 match self.meta_update_permission {145 MetaUpdatePermission::ItemOwner => {146 ensure!(subject == item_owner, <Error<T>>::NoPermission);147 Ok(())148 }149 MetaUpdatePermission::Admin => self.check_is_owner_or_admin(subject),150 MetaUpdatePermission::None => fail!(<Error<T>>::NoPermission),151 }152 }153}154155#[frame_support::pallet]156pub mod pallet {157 use super::*;158 use pallet_evm::account;159 use dispatch::CollectionDispatch;160 use frame_support::{Blake2_128Concat, pallet_prelude::*, storage::Key, traits::StorageVersion};161 use frame_system::pallet_prelude::*;162 use frame_support::traits::Currency;163 use up_data_structs::{TokenId, mapping::TokenAddressMapping};164 use scale_info::TypeInfo;165166 #[pallet::config]167 pub trait Config:168 frame_system::Config + pallet_evm_coder_substrate::Config + TypeInfo + account::Config169 {170 type Event: IsType<<Self as frame_system::Config>::Event> + From<Event<Self>>;171172 type Currency: Currency<Self::AccountId>;173174 #[pallet::constant]175 type CollectionCreationPrice: Get<176 <<Self as Config>::Currency as Currency<Self::AccountId>>::Balance,177 >;178 type CollectionDispatch: CollectionDispatch<Self>;179180 type TreasuryAccountId: Get<Self::AccountId>;181182 type EvmTokenAddressMapping: TokenAddressMapping<H160>;183 type CrossTokenAddressMapping: TokenAddressMapping<Self::CrossAccountId>;184 }185186 const STORAGE_VERSION: StorageVersion = StorageVersion::new(1);187188 #[pallet::pallet]189 #[pallet::storage_version(STORAGE_VERSION)]190 #[pallet::generate_store(pub(super) trait Store)]191 pub struct Pallet<T>(_);192193 #[pallet::extra_constants]194 impl<T: Config> Pallet<T> {195 pub fn collection_admins_limit() -> u32 {196 COLLECTION_ADMINS_LIMIT197 }198 }199200 #[pallet::event]201 #[pallet::generate_deposit(pub fn deposit_event)]202 pub enum Event<T: Config> {203 /// New collection was created204 ///205 /// # Arguments206 ///207 /// * collection_id: Globally unique identifier of newly created collection.208 ///209 /// * mode: [CollectionMode] converted into u8.210 ///211 /// * account_id: Collection owner.212 CollectionCreated(CollectionId, u8, T::AccountId),213214 /// New collection was destroyed215 ///216 /// # Arguments217 ///218 /// * collection_id: Globally unique identifier of collection.219 CollectionDestroyed(CollectionId),220221 /// New item was created.222 ///223 /// # Arguments224 ///225 /// * collection_id: Id of the collection where item was created.226 ///227 /// * item_id: Id of an item. Unique within the collection.228 ///229 /// * recipient: Owner of newly created item230 ///231 /// * amount: Always 1 for NFT232 ItemCreated(CollectionId, TokenId, T::CrossAccountId, u128),233234 /// Collection item was burned.235 ///236 /// # Arguments237 ///238 /// * collection_id.239 ///240 /// * item_id: Identifier of burned NFT.241 ///242 /// * owner: which user has destroyed its tokens243 ///244 /// * amount: Always 1 for NFT245 ItemDestroyed(CollectionId, TokenId, T::CrossAccountId, u128),246247 /// Item was transferred248 ///249 /// * collection_id: Id of collection to which item is belong250 ///251 /// * item_id: Id of an item252 ///253 /// * sender: Original owner of item254 ///255 /// * recipient: New owner of item256 ///257 /// * amount: Always 1 for NFT258 Transfer(259 CollectionId,260 TokenId,261 T::CrossAccountId,262 T::CrossAccountId,263 u128,264 ),265266 /// * collection_id267 ///268 /// * item_id269 ///270 /// * sender271 ///272 /// * spender273 ///274 /// * amount275 Approved(276 CollectionId,277 TokenId,278 T::CrossAccountId,279 T::CrossAccountId,280 u128,281 ),282283 CollectionPropertySet(CollectionId, PropertyKey),284285 CollectionPropertyDeleted(CollectionId, PropertyKey),286287 TokenPropertySet(CollectionId, TokenId, PropertyKey),288289 TokenPropertyDeleted(CollectionId, TokenId, PropertyKey),290291 PropertyPermissionSet(CollectionId, PropertyKey),292 }293294 #[pallet::error]295 pub enum Error<T> {296 /// This collection does not exist.297 CollectionNotFound,298 /// Sender parameter and item owner must be equal.299 MustBeTokenOwner,300 /// No permission to perform action301 NoPermission,302 /// Collection is not in mint mode.303 PublicMintingNotAllowed,304 /// Address is not in allow list.305 AddressNotInAllowlist,306307 /// Collection name can not be longer than 63 char.308 CollectionNameLimitExceeded,309 /// Collection description can not be longer than 255 char.310 CollectionDescriptionLimitExceeded,311 /// Token prefix can not be longer than 15 char.312 CollectionTokenPrefixLimitExceeded,313 /// Total collections bound exceeded.314 TotalCollectionsLimitExceeded,315 /// Exceeded max admin count316 CollectionAdminCountExceeded,317 /// Collection limit bounds per collection exceeded318 CollectionLimitBoundsExceeded,319 /// Tried to enable permissions which are only permitted to be disabled320 OwnerPermissionsCantBeReverted,321 /// Collection settings not allowing items transferring322 TransferNotAllowed,323 /// Account token limit exceeded per collection324 AccountTokenLimitExceeded,325 /// Collection token limit exceeded326 CollectionTokenLimitExceeded,327 /// Metadata flag frozen328 MetadataFlagFrozen,329330 /// Item not exists.331 TokenNotFound,332 /// Item balance not enough.333 TokenValueTooLow,334 /// Requested value more than approved.335 ApprovedValueTooLow,336 /// Tried to approve more than owned337 CantApproveMoreThanOwned,338339 /// Can't transfer tokens to ethereum zero address340 AddressIsZero,341 /// Target collection doesn't supports this operation342 UnsupportedOperation,343344 /// Not sufficient founds to perform action345 NotSufficientFounds,346347 /// Collection has nesting disabled348 NestingIsDisabled,349 /// Only owner may nest tokens under this collection350 OnlyOwnerAllowedToNest,351 /// Only tokens from specific collections may nest tokens under this352 SourceCollectionIsNotAllowedToNest,353354 /// Tried to store more data than allowed in collection field355 CollectionFieldSizeExceeded,356357 /// Tried to store more property data than allowed358 NoSpaceForProperty,359360 /// Tried to store more property keys than allowed361 PropertyLimitReached,362363 /// Unable to read array of unbounded keys364 UnableToReadUnboundedKeys,365366 /// Only ASCII letters, digits, and '_', '-' are allowed367 InvalidCharacterInPropertyKey,368369 /// Empty property keys are forbidden370 EmptyPropertyKey,371 }372373 #[pallet::storage]374 pub type CreatedCollectionCount<T> = StorageValue<Value = CollectionId, QueryKind = ValueQuery>;375 #[pallet::storage]376 pub type DestroyedCollectionCount<T> =377 StorageValue<Value = CollectionId, QueryKind = ValueQuery>;378379 /// Collection info380 #[pallet::storage]381 pub type CollectionById<T> = StorageMap<382 Hasher = Blake2_128Concat,383 Key = CollectionId,384 Value = Collection<<T as frame_system::Config>::AccountId>,385 QueryKind = OptionQuery,386 >;387388 /// Collection properties389 #[pallet::storage]390 #[pallet::getter(fn collection_properties)]391 pub type CollectionProperties<T> = StorageMap<392 Hasher = Blake2_128Concat,393 Key = CollectionId,394 Value = Properties,395 QueryKind = ValueQuery,396 OnEmpty = up_data_structs::CollectionProperties,397 >;398399 #[pallet::storage]400 #[pallet::getter(fn property_permissions)]401 pub type CollectionPropertyPermissions<T> = StorageMap<402 Hasher = Blake2_128Concat,403 Key = CollectionId,404 Value = PropertiesPermissionMap,405 QueryKind = ValueQuery,406 >;407408 /// Large variable-size collection fields are extracted here409 #[pallet::storage]410 pub type CollectionData<T> = StorageNMap<411 Key = (412 Key<Twox64Concat, CollectionId>,413 Key<Twox64Concat, CollectionField>,414 ),415 Value = BoundedVec<u8, ConstU32<COLLECTION_FIELD_LIMIT>>,416 QueryKind = ValueQuery,417 >;418419 #[pallet::storage]420 pub type AdminAmount<T> = StorageMap<421 Hasher = Blake2_128Concat,422 Key = CollectionId,423 Value = u32,424 QueryKind = ValueQuery,425 >;426427 /// List of collection admins428 #[pallet::storage]429 pub type IsAdmin<T: Config> = StorageNMap<430 Key = (431 Key<Blake2_128Concat, CollectionId>,432 Key<Blake2_128Concat, T::CrossAccountId>,433 ),434 Value = bool,435 QueryKind = ValueQuery,436 >;437438 /// Allowlisted collection users439 #[pallet::storage]440 pub type Allowlist<T: Config> = StorageNMap<441 Key = (442 Key<Blake2_128Concat, CollectionId>,443 Key<Blake2_128Concat, T::CrossAccountId>,444 ),445 Value = bool,446 QueryKind = ValueQuery,447 >;448449 /// Not used by code, exists only to provide some types to metadata450 #[pallet::storage]451 pub type DummyStorageValue<T: Config> = StorageValue<452 Value = (453 CollectionStats,454 CollectionId,455 TokenId,456 PhantomType<TokenData<T::CrossAccountId>>,457 PhantomType<RpcCollection<T::AccountId>>,458 ),459 QueryKind = OptionQuery,460 >;461462 #[pallet::hooks]463 impl<T: Config> Hooks<BlockNumberFor<T>> for Pallet<T> {464 fn on_runtime_upgrade() -> Weight {465 if StorageVersion::get::<Pallet<T>>() < StorageVersion::new(1) {466 use up_data_structs::{CollectionVersion1, CollectionVersion2};467 <CollectionById<T>>::translate::<CollectionVersion1<T::AccountId>, _>(|id, v| {468 Self::set_field_raw(469 id,470 CollectionField::OffchainSchema,471 v.offchain_schema.clone().into_inner(),472 )473 .expect("data has lower bounds than field");474 Self::set_field_raw(475 id,476 CollectionField::ConstOnChainSchema,477 v.const_on_chain_schema.clone().into_inner(),478 )479 .expect("data has lower bounds than field");480481 Some(CollectionVersion2::from(v))482 });483 }484485 0486 }487 }488}489490impl<T: Config> Pallet<T> {491 /// Ethereum receiver 0x0000000000000000000000000000000000000000 is reserved, and shouldn't own tokens492 pub fn ensure_correct_receiver(receiver: &T::CrossAccountId) -> DispatchResult {493 ensure!(494 &T::CrossAccountId::from_eth(H160([0; 20])) != receiver,495 <Error<T>>::AddressIsZero496 );497 Ok(())498 }499 pub fn adminlist(collection: CollectionId) -> Vec<T::CrossAccountId> {500 <IsAdmin<T>>::iter_prefix((collection,))501 .map(|(a, _)| a)502 .collect()503 }504 pub fn allowlist(collection: CollectionId) -> Vec<T::CrossAccountId> {505 <Allowlist<T>>::iter_prefix((collection,))506 .map(|(a, _)| a)507 .collect()508 }509 pub fn allowed(collection: CollectionId, user: T::CrossAccountId) -> bool {510 <Allowlist<T>>::get((collection, user))511 }512 pub fn collection_stats() -> CollectionStats {513 let created = <CreatedCollectionCount<T>>::get();514 let destroyed = <DestroyedCollectionCount<T>>::get();515 CollectionStats {516 created: created.0,517 destroyed: destroyed.0,518 alive: created.0 - destroyed.0,519 }520 }521522 pub fn effective_collection_limits(collection: CollectionId) -> Option<CollectionLimits> {523 let collection = <CollectionById<T>>::get(collection);524 if collection.is_none() {525 return None;526 }527528 let collection = collection.unwrap();529 let limits = collection.limits;530 let effective_limits = CollectionLimits {531 account_token_ownership_limit: Some(limits.account_token_ownership_limit()),532 sponsored_data_size: Some(limits.sponsored_data_size()),533 sponsored_data_rate_limit: Some(534 limits535 .sponsored_data_rate_limit536 .unwrap_or(SponsoringRateLimit::SponsoringDisabled),537 ),538 token_limit: Some(limits.token_limit()),539 sponsor_transfer_timeout: Some(limits.sponsor_transfer_timeout(540 match collection.mode {541 CollectionMode::NFT => NFT_SPONSOR_TRANSFER_TIMEOUT,542 CollectionMode::Fungible(_) => FUNGIBLE_SPONSOR_TRANSFER_TIMEOUT,543 CollectionMode::ReFungible => REFUNGIBLE_SPONSOR_TRANSFER_TIMEOUT,544 },545 )),546 sponsor_approve_timeout: Some(limits.sponsor_approve_timeout()),547 owner_can_transfer: Some(limits.owner_can_transfer()),548 owner_can_destroy: Some(limits.owner_can_destroy()),549 transfers_enabled: Some(limits.transfers_enabled()),550 nesting_rule: Some(limits.nesting_rule().clone()),551 };552553 Some(effective_limits)554 }555556 pub fn rpc_collection(collection: CollectionId) -> Option<RpcCollection<T::AccountId>> {557 let Collection {558 name,559 description,560 owner,561 mode,562 access,563 token_prefix,564 mint_mode,565 schema_version,566 sponsorship,567 limits,568 meta_update_permission,569 } = <CollectionById<T>>::get(collection)?;570571 let token_property_permissions = <CollectionPropertyPermissions<T>>::get(collection)572 .iter()573 .map(|(key, permission)| PropertyKeyPermission {574 key: key.clone(),575 permission: permission.clone(),576 })577 .collect();578579 let properties = <CollectionProperties<T>>::get(collection)580 .iter()581 .map(|(key, value)| Property {582 key: key.clone(),583 value: value.clone(),584 })585 .collect();586587 Some(RpcCollection {588 name: name.into_inner(),589 description: description.into_inner(),590 owner,591 mode,592 access,593 token_prefix: token_prefix.into_inner(),594 mint_mode,595 schema_version,596 sponsorship,597 limits,598 meta_update_permission,599 offchain_schema: <CollectionData<T>>::get((600 collection,601 CollectionField::OffchainSchema,602 ))603 .into_inner(),604 const_on_chain_schema: <CollectionData<T>>::get((605 collection,606 CollectionField::ConstOnChainSchema,607 ))608 .into_inner(),609 token_property_permissions,610 properties,611 })612 }613}614615impl<T: Config> Pallet<T> {616 pub fn init_collection(617 owner: T::AccountId,618 data: CreateCollectionData<T::AccountId>,619 ) -> Result<CollectionId, DispatchError> {620 {621 ensure!(622 data.token_prefix.len() <= MAX_TOKEN_PREFIX_LENGTH as usize,623 Error::<T>::CollectionTokenPrefixLimitExceeded624 );625 }626627 let created_count = <CreatedCollectionCount<T>>::get()628 .0629 .checked_add(1)630 .ok_or(ArithmeticError::Overflow)?;631 let destroyed_count = <DestroyedCollectionCount<T>>::get().0;632 let id = CollectionId(created_count);633634 // bound Total number of collections635 ensure!(636 created_count - destroyed_count <= COLLECTION_NUMBER_LIMIT,637 <Error<T>>::TotalCollectionsLimitExceeded638 );639640 // =========641642 let collection = Collection {643 owner: owner.clone(),644 name: data.name,645 mode: data.mode.clone(),646 mint_mode: false,647 access: data.access.unwrap_or_default(),648 description: data.description,649 token_prefix: data.token_prefix,650 schema_version: data.schema_version.unwrap_or_default(),651 sponsorship: data652 .pending_sponsor653 .map(SponsorshipState::Unconfirmed)654 .unwrap_or_default(),655 limits: data656 .limits657 .map(|limits| Self::clamp_limits(data.mode.clone(), &Default::default(), limits))658 .unwrap_or_else(|| Ok(CollectionLimits::default()))?,659 meta_update_permission: data.meta_update_permission.unwrap_or_default(),660 };661662 let mut collection_properties = up_data_structs::CollectionProperties::get();663 collection_properties664 .try_set_from_iter(data.properties.into_iter().map(|p| (p.key, p.value)))665 .map_err(<Error<T>>::from)?;666667 CollectionProperties::<T>::insert(id, collection_properties);668669 let mut token_props_permissions = PropertiesPermissionMap::new();670 token_props_permissions671 .try_set_from_iter(672 data.token_property_permissions673 .into_iter()674 .map(|property| (property.key, property.permission)),675 )676 .map_err(<Error<T>>::from)?;677678 CollectionPropertyPermissions::<T>::insert(id, token_props_permissions);679680 // Take a (non-refundable) deposit of collection creation681 {682 let mut imbalance =683 <<<T as Config>::Currency as Currency<T::AccountId>>::PositiveImbalance>::zero();684 imbalance.subsume(685 <<T as Config>::Currency as Currency<T::AccountId>>::deposit_creating(686 &T::TreasuryAccountId::get(),687 T::CollectionCreationPrice::get(),688 ),689 );690 <T as Config>::Currency::settle(691 &owner,692 imbalance,693 WithdrawReasons::TRANSFER,694 ExistenceRequirement::KeepAlive,695 )696 .map_err(|_| Error::<T>::NotSufficientFounds)?;697 }698699 <CreatedCollectionCount<T>>::put(created_count);700 <Pallet<T>>::deposit_event(Event::CollectionCreated(id, data.mode.id(), owner.clone()));701 <CollectionById<T>>::insert(id, collection);702 Self::set_field_raw(703 id,704 CollectionField::OffchainSchema,705 data.offchain_schema.into_inner(),706 )707 .expect("data has lower bounds than field");708 Self::set_field_raw(709 id,710 CollectionField::ConstOnChainSchema,711 data.const_on_chain_schema.into_inner(),712 )713 .expect("data has lower bounds than field");714 Ok(id)715 }716717 pub fn destroy_collection(718 collection: CollectionHandle<T>,719 sender: &T::CrossAccountId,720 ) -> DispatchResult {721 ensure!(722 collection.limits.owner_can_destroy(),723 <Error<T>>::NoPermission,724 );725 collection.check_is_owner(sender)?;726727 let destroyed_collections = <DestroyedCollectionCount<T>>::get()728 .0729 .checked_add(1)730 .ok_or(ArithmeticError::Overflow)?;731732 // =========733734 <DestroyedCollectionCount<T>>::put(destroyed_collections);735 <CollectionById<T>>::remove(collection.id);736 <CollectionData<T>>::remove_prefix((collection.id,), None);737 <AdminAmount<T>>::remove(collection.id);738 <IsAdmin<T>>::remove_prefix((collection.id,), None);739 <Allowlist<T>>::remove_prefix((collection.id,), None);740741 <Pallet<T>>::deposit_event(Event::CollectionDestroyed(collection.id));742 Ok(())743 }744745 pub fn set_collection_property(746 collection: &CollectionHandle<T>,747 sender: &T::CrossAccountId,748 property: Property,749 ) -> DispatchResult {750 collection.check_is_owner_or_admin(sender)?;751752 CollectionProperties::<T>::try_mutate(collection.id, |properties| {753 let property = property.clone();754 properties.try_set(property.key, property.value)755 })756 .map_err(<Error<T>>::from)?;757758 Self::deposit_event(Event::CollectionPropertySet(collection.id, property.key));759760 Ok(())761 }762763 pub fn set_collection_properties(764 collection: &CollectionHandle<T>,765 sender: &T::CrossAccountId,766 properties: Vec<Property>,767 ) -> DispatchResult {768 for property in properties {769 Self::set_collection_property(collection, sender, property)?;770 }771772 Ok(())773 }774775 pub fn delete_collection_property(776 collection: &CollectionHandle<T>,777 sender: &T::CrossAccountId,778 property_key: PropertyKey,779 ) -> DispatchResult {780 collection.check_is_owner_or_admin(sender)?;781782 CollectionProperties::<T>::try_mutate(collection.id, |properties| {783 properties.remove(&property_key)784 })785 .map_err(<Error<T>>::from)?;786787 Self::deposit_event(Event::CollectionPropertyDeleted(788 collection.id,789 property_key,790 ));791792 Ok(())793 }794795 pub fn delete_collection_properties(796 collection: &CollectionHandle<T>,797 sender: &T::CrossAccountId,798 property_keys: Vec<PropertyKey>,799 ) -> DispatchResult {800 for key in property_keys {801 Self::delete_collection_property(collection, sender, key)?;802 }803804 Ok(())805 }806807 pub fn set_property_permission(808 collection: &CollectionHandle<T>,809 sender: &T::CrossAccountId,810 property_permission: PropertyKeyPermission,811 ) -> DispatchResult {812 collection.check_is_owner_or_admin(sender)?;813814 let all_permissions = CollectionPropertyPermissions::<T>::get(collection.id);815 let current_permission = all_permissions.get(&property_permission.key);816 if matches![817 current_permission,818 Some(PropertyPermission { mutable: false, .. })819 ] {820 return Err(<Error<T>>::NoPermission.into());821 }822823 CollectionPropertyPermissions::<T>::try_mutate(collection.id, |permissions| {824 let property_permission = property_permission.clone();825 permissions.try_set(property_permission.key, property_permission.permission)826 })827 .map_err(<Error<T>>::from)?;828829 Self::deposit_event(Event::PropertyPermissionSet(830 collection.id,831 property_permission.key,832 ));833834 Ok(())835 }836837 pub fn set_property_permissions(838 collection: &CollectionHandle<T>,839 sender: &T::CrossAccountId,840 property_permissions: Vec<PropertyKeyPermission>,841 ) -> DispatchResult {842 for prop_pemission in property_permissions {843 Self::set_property_permission(collection, sender, prop_pemission)?;844 }845846 Ok(())847 }848849 pub fn bytes_keys_to_property_keys(850 keys: Vec<Vec<u8>>,851 ) -> Result<Vec<PropertyKey>, DispatchError> {852 keys.into_iter()853 .map(|key| -> Result<PropertyKey, DispatchError> {854 key.try_into()855 .map_err(|_| <Error<T>>::UnableToReadUnboundedKeys.into())856 })857 .collect::<Result<Vec<PropertyKey>, DispatchError>>()858 }859860 pub fn check_property_key(key: &PropertyKey) -> Result<(), DispatchError> {861 let key_str = sp_std::str::from_utf8(key.as_slice())862 .map_err(|_| <Error<T>>::InvalidCharacterInPropertyKey)?;863864 for ch in key_str.chars() {865 if !ch.is_ascii_alphanumeric() && ch != '_' && ch != '-' {866 return Err(<Error<T>>::InvalidCharacterInPropertyKey.into());867 }868 }869870 Ok(())871 }872873 pub fn filter_collection_properties(874 collection_id: CollectionId,875 keys: Vec<PropertyKey>,876 ) -> Result<Vec<Property>, DispatchError> {877 let properties = Self::collection_properties(collection_id);878879 let properties = keys880 .into_iter()881 .filter_map(|key| {882 properties.get(&key).map(|value| Property {883 key,884 value: value.clone(),885 })886 })887 .collect();888889 Ok(properties)890 }891892 pub fn filter_property_permissions(893 collection_id: CollectionId,894 keys: Vec<PropertyKey>,895 ) -> Result<Vec<PropertyKeyPermission>, DispatchError> {896 let permissions = Self::property_permissions(collection_id);897898 let key_permissions = keys899 .into_iter()900 .filter_map(|key| {901 permissions902 .get(&key)903 .map(|permission| PropertyKeyPermission {904 key,905 permission: permission.clone(),906 })907 })908 .collect();909910 Ok(key_permissions)911 }912913 fn set_field_raw(914 collection_id: CollectionId,915 field: CollectionField,916 value: Vec<u8>,917 ) -> DispatchResult {918 if !value.is_empty() {919 <CollectionData<T>>::insert(920 (collection_id, field),921 BoundedVec::try_from(value).map_err(|_| <Error<T>>::CollectionFieldSizeExceeded)?,922 )923 } else {924 <CollectionData<T>>::remove((collection_id, field));925 }926 Ok(())927 }928929 pub fn set_field(930 collection: &CollectionHandle<T>,931 sender: &T::CrossAccountId,932 field: CollectionField,933 value: Vec<u8>,934 ) -> DispatchResult {935 collection.check_is_owner_or_admin(sender)?;936937 // =========938939 Self::set_field_raw(collection.id, field, value)940 }941942 pub fn toggle_allowlist(943 collection: &CollectionHandle<T>,944 sender: &T::CrossAccountId,945 user: &T::CrossAccountId,946 allowed: bool,947 ) -> DispatchResult {948 collection.check_is_owner_or_admin(sender)?;949950 // =========951952 if allowed {953 <Allowlist<T>>::insert((collection.id, user), true);954 } else {955 <Allowlist<T>>::remove((collection.id, user));956 }957958 Ok(())959 }960961 pub fn toggle_admin(962 collection: &CollectionHandle<T>,963 sender: &T::CrossAccountId,964 user: &T::CrossAccountId,965 admin: bool,966 ) -> DispatchResult {967 collection.check_is_owner_or_admin(sender)?;968969 let was_admin = <IsAdmin<T>>::get((collection.id, user));970 if was_admin == admin {971 return Ok(());972 }973 let amount = <AdminAmount<T>>::get(collection.id);974975 if admin {976 let amount = amount977 .checked_add(1)978 .ok_or(<Error<T>>::CollectionAdminCountExceeded)?;979 ensure!(980 amount <= Self::collection_admins_limit(),981 <Error<T>>::CollectionAdminCountExceeded,982 );983984 // =========985986 <AdminAmount<T>>::insert(collection.id, amount);987 <IsAdmin<T>>::insert((collection.id, user), true);988 } else {989 <AdminAmount<T>>::insert(collection.id, amount.saturating_sub(1));990 <IsAdmin<T>>::remove((collection.id, user));991 }992993 Ok(())994 }995996 pub fn clamp_limits(997 mode: CollectionMode,998 old_limit: &CollectionLimits,999 mut new_limit: CollectionLimits,1000 ) -> Result<CollectionLimits, DispatchError> {1001 macro_rules! limit_default {1002 ($old:ident, $new:ident, $($field:ident $(($arg:expr))? => $check:expr),* $(,)?) => {{1003 $(1004 if let Some($new) = $new.$field {1005 let $old = $old.$field($($arg)?);1006 let _ = $new;1007 let _ = $old;1008 $check1009 } else {1010 $new.$field = $old.$field1011 }1012 )*1013 }};1014 }10151016 limit_default!(old_limit, new_limit,1017 account_token_ownership_limit => ensure!(1018 new_limit <= MAX_TOKEN_OWNERSHIP,1019 <Error<T>>::CollectionLimitBoundsExceeded,1020 ),1021 sponsor_transfer_timeout(match mode {1022 CollectionMode::NFT => NFT_SPONSOR_TRANSFER_TIMEOUT,1023 CollectionMode::Fungible(_) => FUNGIBLE_SPONSOR_TRANSFER_TIMEOUT,1024 CollectionMode::ReFungible => REFUNGIBLE_SPONSOR_TRANSFER_TIMEOUT,1025 }) => ensure!(1026 new_limit <= MAX_SPONSOR_TIMEOUT,1027 <Error<T>>::CollectionLimitBoundsExceeded,1028 ),1029 sponsored_data_size => ensure!(1030 new_limit <= CUSTOM_DATA_LIMIT,1031 <Error<T>>::CollectionLimitBoundsExceeded,1032 ),1033 token_limit => ensure!(1034 old_limit >= new_limit && new_limit > 0,1035 <Error<T>>::CollectionTokenLimitExceeded1036 ),1037 owner_can_transfer => ensure!(1038 old_limit || !new_limit,1039 <Error<T>>::OwnerPermissionsCantBeReverted,1040 ),1041 owner_can_destroy => ensure!(1042 old_limit || !new_limit,1043 <Error<T>>::OwnerPermissionsCantBeReverted,1044 ),1045 sponsored_data_rate_limit => {},1046 transfers_enabled => {},1047 );1048 Ok(new_limit)1049 }1050}10511052#[macro_export]1053macro_rules! unsupported {1054 () => {1055 Err(<Error<T>>::UnsupportedOperation.into())1056 };1057}10581059/// Worst cases1060pub trait CommonWeightInfo<CrossAccountId> {1061 fn create_item() -> Weight;1062 fn create_multiple_items(amount: u32) -> Weight;1063 fn create_multiple_items_ex(cost: &CreateItemExData<CrossAccountId>) -> Weight;1064 fn burn_item() -> Weight;1065 fn set_collection_properties(amount: u32) -> Weight;1066 fn delete_collection_properties(amount: u32) -> Weight;1067 fn set_token_properties(amount: u32) -> Weight;1068 fn delete_token_properties(amount: u32) -> Weight;1069 fn set_property_permissions(amount: u32) -> Weight;1070 fn transfer() -> Weight;1071 fn approve() -> Weight;1072 fn transfer_from() -> Weight;1073 fn burn_from() -> Weight;1074}10751076pub trait CommonCollectionOperations<T: Config> {1077 fn create_item(1078 &self,1079 sender: T::CrossAccountId,1080 to: T::CrossAccountId,1081 data: CreateItemData,1082 nesting_budget: &dyn Budget,1083 ) -> DispatchResultWithPostInfo;1084 fn create_multiple_items(1085 &self,1086 sender: T::CrossAccountId,1087 to: T::CrossAccountId,1088 data: Vec<CreateItemData>,1089 nesting_budget: &dyn Budget,1090 ) -> DispatchResultWithPostInfo;1091 fn create_multiple_items_ex(1092 &self,1093 sender: T::CrossAccountId,1094 data: CreateItemExData<T::CrossAccountId>,1095 nesting_budget: &dyn Budget,1096 ) -> DispatchResultWithPostInfo;1097 fn burn_item(1098 &self,1099 sender: T::CrossAccountId,1100 token: TokenId,1101 amount: u128,1102 ) -> DispatchResultWithPostInfo;1103 fn set_collection_properties(1104 &self,1105 sender: T::CrossAccountId,1106 properties: Vec<Property>,1107 ) -> DispatchResultWithPostInfo;1108 fn delete_collection_properties(1109 &self,1110 sender: &T::CrossAccountId,1111 property_keys: Vec<PropertyKey>,1112 ) -> DispatchResultWithPostInfo;1113 fn set_token_properties(1114 &self,1115 sender: T::CrossAccountId,1116 token_id: TokenId,1117 property: Vec<Property>,1118 ) -> DispatchResultWithPostInfo;1119 fn delete_token_properties(1120 &self,1121 sender: T::CrossAccountId,1122 token_id: TokenId,1123 property_keys: Vec<PropertyKey>,1124 ) -> DispatchResultWithPostInfo;1125 fn set_property_permissions(1126 &self,1127 sender: &T::CrossAccountId,1128 property_permissions: Vec<PropertyKeyPermission>,1129 ) -> DispatchResultWithPostInfo;1130 fn transfer(1131 &self,1132 sender: T::CrossAccountId,1133 to: T::CrossAccountId,1134 token: TokenId,1135 amount: u128,1136 nesting_budget: &dyn Budget,1137 ) -> DispatchResultWithPostInfo;1138 fn approve(1139 &self,1140 sender: T::CrossAccountId,1141 spender: T::CrossAccountId,1142 token: TokenId,1143 amount: u128,1144 ) -> DispatchResultWithPostInfo;1145 fn transfer_from(1146 &self,1147 sender: T::CrossAccountId,1148 from: T::CrossAccountId,1149 to: T::CrossAccountId,1150 token: TokenId,1151 amount: u128,1152 nesting_budget: &dyn Budget,1153 ) -> DispatchResultWithPostInfo;1154 fn burn_from(1155 &self,1156 sender: T::CrossAccountId,1157 from: T::CrossAccountId,1158 token: TokenId,1159 amount: u128,1160 nesting_budget: &dyn Budget,1161 ) -> DispatchResultWithPostInfo;11621163 fn check_nesting(1164 &self,1165 sender: T::CrossAccountId,1166 from: (CollectionId, TokenId),1167 under: TokenId,1168 budget: &dyn Budget,1169 ) -> DispatchResult;11701171 fn account_tokens(&self, account: T::CrossAccountId) -> Vec<TokenId>;1172 fn collection_tokens(&self) -> Vec<TokenId>;1173 fn token_exists(&self, token: TokenId) -> bool;1174 fn last_token_id(&self) -> TokenId;11751176 fn token_owner(&self, token: TokenId) -> Option<T::CrossAccountId>;1177 fn const_metadata(&self, token: TokenId) -> Vec<u8>;1178 fn token_properties(&self, token_id: TokenId, keys: Vec<PropertyKey>) -> Vec<Property>;1179 /// Amount of unique collection tokens1180 fn total_supply(&self) -> u32;1181 /// Amount of different tokens account has (Applicable to nonfungible/refungible)1182 fn account_balance(&self, account: T::CrossAccountId) -> u32;1183 /// Amount of specific token account have (Applicable to fungible/refungible)1184 fn balance(&self, account: T::CrossAccountId, token: TokenId) -> u128;1185 fn allowance(1186 &self,1187 sender: T::CrossAccountId,1188 spender: T::CrossAccountId,1189 token: TokenId,1190 ) -> u128;1191}11921193// Flexible enough for implementing CommonCollectionOperations1194pub fn with_weight(res: DispatchResult, weight: Weight) -> DispatchResultWithPostInfo {1195 let post_info = PostDispatchInfo {1196 actual_weight: Some(weight),1197 pays_fee: Pays::Yes,1198 };1199 match res {1200 Ok(()) => Ok(post_info),1201 Err(error) => Err(DispatchErrorWithPostInfo { post_info, error }),1202 }1203}12041205impl<T: Config> From<PropertiesError> for Error<T> {1206 fn from(error: PropertiesError) -> Self {1207 match error {1208 PropertiesError::NoSpaceForProperty => Self::NoSpaceForProperty,1209 PropertiesError::PropertyLimitReached => Self::PropertyLimitReached,1210 PropertiesError::InvalidCharacterInPropertyKey => Self::InvalidCharacterInPropertyKey,1211 PropertiesError::EmptyPropertyKey => Self::EmptyPropertyKey,1212 }1213 }1214}pallets/unique/src/benchmarking.rsdiffbeforeafterboth--- a/pallets/unique/src/benchmarking.rs
+++ b/pallets/unique/src/benchmarking.rs
@@ -168,9 +168,4 @@
nesting_rule: None,
};
}: set_collection_limits(RawOrigin::Signed(caller.clone()), collection, cl)
-
- set_meta_update_permission_flag {
- let caller: T::AccountId = account("caller", 0, SEED);
- let collection = create_nft_collection::<T>(caller.clone())?;
- }: _(RawOrigin::Signed(caller.clone()), collection, MetaUpdatePermission::Admin)
}
pallets/unique/src/lib.rsdiffbeforeafterboth--- a/pallets/unique/src/lib.rs
+++ b/pallets/unique/src/lib.rs
@@ -38,12 +38,12 @@
CONST_ON_CHAIN_SCHEMA_LIMIT, OFFCHAIN_SCHEMA_LIMIT,
MAX_COLLECTION_NAME_LENGTH, MAX_COLLECTION_DESCRIPTION_LENGTH, MAX_TOKEN_PREFIX_LENGTH,
AccessMode, CreateItemData, CollectionLimits, CollectionId, CollectionMode, TokenId,
- SchemaVersion, SponsorshipState, MetaUpdatePermission, CreateCollectionData,
+ SchemaVersion, SponsorshipState, CreateCollectionData,
CreateItemExData, budget, CollectionField, Property, PropertyKey, PropertyKeyPermission,
};
use pallet_evm::account::CrossAccountId;
use pallet_common::{
- CollectionHandle, Pallet as PalletCommon, Error as CommonError, CommonWeightInfo,
+ CollectionHandle, Pallet as PalletCommon, CommonWeightInfo,
dispatch::dispatch_call, dispatch::CollectionDispatch,
};
@@ -925,34 +925,6 @@
let budget = budget::Value::new(2);
dispatch_call::<T, _>(collection_id, |d| d.transfer_from(sender, from, recipient, item_id, value, &budget))
- }
-
- /// Set meta_update_permission value for particular collection
- ///
- /// # Permissions
- ///
- /// * Collection Owner.
- ///
- /// # Arguments
- ///
- /// * collection_id: ID of the collection.
- ///
- /// * value: New flag value.
- #[weight = <SelfWeightOf<T>>::set_meta_update_permission_flag()]
- #[transactional]
- pub fn set_meta_update_permission_flag(origin, collection_id: CollectionId, value: MetaUpdatePermission) -> DispatchResult {
- let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);
- let mut target_collection = <CollectionHandle<T>>::try_get(collection_id)?;
-
- ensure!(
- target_collection.meta_update_permission != MetaUpdatePermission::None,
- <CommonError<T>>::MetadataFlagFrozen,
- );
- target_collection.check_is_owner(&sender)?;
-
- target_collection.meta_update_permission = value;
-
- target_collection.save()
}
/// Set schema standard
pallets/unique/src/weights.rsdiffbeforeafterboth--- a/pallets/unique/src/weights.rs
+++ b/pallets/unique/src/weights.rs
@@ -49,7 +49,6 @@
fn set_const_on_chain_schema(b: u32, ) -> Weight;
fn set_schema_version() -> Weight;
fn set_collection_limits() -> Weight;
- fn set_meta_update_permission_flag() -> Weight;
}
/// Weights for pallet_unique using the Substrate node and recommended hardware.
@@ -167,12 +166,6 @@
// Storage: Common CollectionById (r:1 w:1)
fn set_collection_limits() -> Weight {
(15_339_000 as Weight)
- .saturating_add(T::DbWeight::get().reads(1 as Weight))
- .saturating_add(T::DbWeight::get().writes(1 as Weight))
- }
- // Storage: Common CollectionById (r:1 w:1)
- fn set_meta_update_permission_flag() -> Weight {
- (7_214_000 as Weight)
.saturating_add(T::DbWeight::get().reads(1 as Weight))
.saturating_add(T::DbWeight::get().writes(1 as Weight))
}
@@ -292,12 +285,6 @@
// Storage: Common CollectionById (r:1 w:1)
fn set_collection_limits() -> Weight {
(15_339_000 as Weight)
- .saturating_add(RocksDbWeight::get().reads(1 as Weight))
- .saturating_add(RocksDbWeight::get().writes(1 as Weight))
- }
- // Storage: Common CollectionById (r:1 w:1)
- fn set_meta_update_permission_flag() -> Weight {
- (7_214_000 as Weight)
.saturating_add(RocksDbWeight::get().reads(1 as Weight))
.saturating_add(RocksDbWeight::get().writes(1 as Weight))
}
primitives/data-structs/src/lib.rsdiffbeforeafterboth--- a/primitives/data-structs/src/lib.rs
+++ b/primitives/data-structs/src/lib.rs
@@ -308,6 +308,7 @@
#[version(..2)]
pub const_on_chain_schema: BoundedVec<u8, ConstU32<CONST_ON_CHAIN_SCHEMA_LIMIT>>,
+ #[version(..2)]
pub meta_update_permission: MetaUpdatePermission,
}
@@ -327,7 +328,6 @@
pub sponsorship: SponsorshipState<AccountId>,
pub limits: CollectionLimits,
pub const_on_chain_schema: Vec<u8>,
- pub meta_update_permission: MetaUpdatePermission,
pub token_property_permissions: Vec<PropertyKeyPermission>,
pub properties: Vec<Property>,
}
@@ -353,7 +353,6 @@
pub pending_sponsor: Option<AccountId>,
pub limits: Option<CollectionLimits>,
pub const_on_chain_schema: BoundedVec<u8, ConstU32<CONST_ON_CHAIN_SCHEMA_LIMIT>>,
- pub meta_update_permission: Option<MetaUpdatePermission>,
pub token_property_permissions: CollectionPropertiesPermissionsVec,
pub properties: CollectionPropertiesVec,
}
@@ -493,17 +492,10 @@
}
#[derive(Encode, Decode, Debug, Clone, PartialEq, TypeInfo, MaxEncodedLen)]
-#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]
pub enum MetaUpdatePermission {
ItemOwner,
Admin,
None,
-}
-
-impl Default for MetaUpdatePermission {
- fn default() -> Self {
- Self::ItemOwner
- }
}
#[derive(Encode, Decode, MaxEncodedLen, PartialEq, Clone, Debug, TypeInfo)]
runtime/tests/src/tests.rsdiffbeforeafterboth--- a/runtime/tests/src/tests.rs
+++ b/runtime/tests/src/tests.rs
@@ -18,7 +18,7 @@
use crate::{Test, TestCrossAccountId, CollectionCreationPrice, Origin, Unique, new_test_ext};
use up_data_structs::{
COLLECTION_NUMBER_LIMIT, CollectionId, CreateItemData, CreateFungibleData, CreateNftData,
- CreateReFungibleData, MAX_DECIMAL_POINTS, COLLECTION_ADMINS_LIMIT, MetaUpdatePermission,
+ CreateReFungibleData, MAX_DECIMAL_POINTS, COLLECTION_ADMINS_LIMIT,
TokenId, MAX_TOKEN_OWNERSHIP, CreateCollectionData, CollectionField, SchemaVersion,
CollectionMode, AccessMode,
};
@@ -2467,32 +2467,6 @@
assert_eq!(
<pallet_nonfungible::AccountBalance<Test>>::get((collection_id, account(2))),
1
- );
- });
-}
-
-#[test]
-fn set_variable_meta_flag_after_freeze() {
- new_test_ext().execute_with(|| {
- // default_limits();
-
- let collection_id =
- create_test_collection_for_owner(&CollectionMode::NFT, 2, CollectionId(1));
-
- let origin2 = Origin::signed(2);
-
- assert_ok!(Unique::set_meta_update_permission_flag(
- origin2.clone(),
- collection_id,
- MetaUpdatePermission::None,
- ));
- assert_noop!(
- Unique::set_meta_update_permission_flag(
- origin2.clone(),
- collection_id,
- MetaUpdatePermission::Admin
- ),
- CommonError::<Test>::MetadataFlagFrozen
);
});
}
tests/src/createCollection.test.tsdiffbeforeafterboth--- a/tests/src/createCollection.test.ts
+++ b/tests/src/createCollection.test.ts
@@ -74,7 +74,6 @@
accountTokenOwnershipLimit: 3,
},
constOnChainSchema: '0x333333',
- metaUpdatePermission: 'Admin',
});
const events = await submitTransactionAsync(alice, tx);
const result = getCreateCollectionResult(events);
@@ -91,7 +90,6 @@
expect(collection.sponsorship.asUnconfirmed.toString()).to.equal(bob.address);
expect(collection.limits.accountTokenOwnershipLimit.unwrap().toNumber()).to.equal(3);
expect(collection.constOnChainSchema.toString()).to.equal('0x333333');
- expect(collection.metaUpdatePermission.isAdmin).to.be.true;
});
});
});
tests/src/eth/nonFungible.test.tsdiffbeforeafterboth--- a/tests/src/eth/nonFungible.test.ts
+++ b/tests/src/eth/nonFungible.test.ts
@@ -15,7 +15,7 @@
// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
import privateKey from '../substrate/privateKey';
-import {approveExpectSuccess, burnItemExpectSuccess, createCollectionExpectSuccess, createItemExpectSuccess, transferExpectSuccess, transferFromExpectSuccess, UNIQUE, setMetadataUpdatePermissionFlagExpectSuccess} from '../util/helpers';
+import {approveExpectSuccess, burnItemExpectSuccess, createCollectionExpectSuccess, createItemExpectSuccess, transferExpectSuccess, transferFromExpectSuccess, UNIQUE} from '../util/helpers';
import {collectionIdToAddress, createEthAccount, createEthAccountWithBalance, GAS_ARGS, itWeb3, normalizeEvents, recordEthFee, recordEvents, subToEth, transferBalanceToEth} from './util/helpers';
import nonFungibleAbi from './nonFungibleAbi.json';
import {expect} from 'chai';
tests/src/eth/proxy/nonFungibleProxy.test.tsdiffbeforeafterboth--- a/tests/src/eth/proxy/nonFungibleProxy.test.ts
+++ b/tests/src/eth/proxy/nonFungibleProxy.test.ts
@@ -15,7 +15,7 @@
// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
import privateKey from '../../substrate/privateKey';
-import {createCollectionExpectSuccess, createItemExpectSuccess, setMetadataUpdatePermissionFlagExpectSuccess} from '../../util/helpers';
+import {createCollectionExpectSuccess, createItemExpectSuccess} from '../../util/helpers';
import {collectionIdToAddress, createEthAccount, createEthAccountWithBalance, GAS_ARGS, itWeb3, normalizeEvents} from '../util/helpers';
import nonFungibleAbi from '../nonFungibleAbi.json';
import {expect} from 'chai';
tests/src/nesting/migration-check.test.tsdiffbeforeafterboth--- a/tests/src/nesting/migration-check.test.ts
+++ b/tests/src/nesting/migration-check.test.ts
@@ -37,7 +37,6 @@
accountTokenOwnershipLimit: 3,
},
constOnChainSchema: '0x333333',
- metaUpdatePermission: 'Admin',
});
const events = await submitTransactionAsync(alice, tx);
const result = getCreateCollectionResult(events);
tests/src/util/helpers.tsdiffbeforeafterboth--- a/tests/src/util/helpers.ts
+++ b/tests/src/util/helpers.ts
@@ -650,28 +650,6 @@
});
}
-export async function setMetadataUpdatePermissionFlagExpectSuccess(sender: IKeyringPair, collectionId: number, flag: string) {
-
- await usingApi(async (api) => {
- const tx = api.tx.unique.setMetaUpdatePermissionFlag(collectionId, flag as any);
- const events = await submitTransactionAsync(sender, tx);
- const result = getGenericResult(events);
-
- expect(result.success).to.be.true;
- });
-}
-
-export async function setMetadataUpdatePermissionFlagExpectFailure(sender: IKeyringPair, collectionId: number, flag: string) {
-
- await usingApi(async (api) => {
- const tx = api.tx.unique.setMetaUpdatePermissionFlag(collectionId, flag as any);
- const events = await expect(submitTransactionExpectFailAsync(sender, tx)).to.be.rejected;
- const result = getGenericResult(events);
-
- expect(result.success).to.be.false;
- });
-}
-
export async function enableContractSponsoringExpectSuccess(sender: IKeyringPair, contractAddress: AccountId | string, enable: boolean) {
await usingApi(async (api) => {
const tx = api.tx.unique.enableContractSponsoring(contractAddress, enable);