difftreelog
refactor remove outdated events
in: master
1 file changed
pallets/unique/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#![recursion_limit = "1024"]18#![cfg_attr(not(feature = "std"), no_std)]19#![allow(20 clippy::too_many_arguments,21 clippy::unnecessary_mut_passed,22 clippy::unused_unit23)]2425extern crate alloc;2627use frame_support::{28 decl_module, decl_storage, decl_error, decl_event,29 dispatch::DispatchResult,30 ensure,31 weights::{Weight},32 transactional,33 pallet_prelude::{DispatchResultWithPostInfo, ConstU32},34 BoundedVec,35};36use scale_info::TypeInfo;37use frame_system::{self as system, ensure_signed};38use sp_runtime::{sp_std::prelude::Vec};39use up_data_structs::{40 MAX_COLLECTION_NAME_LENGTH,41 MAX_COLLECTION_DESCRIPTION_LENGTH, MAX_TOKEN_PREFIX_LENGTH, AccessMode, CreateItemData,42 CollectionLimits, CollectionPermissions, CollectionId, CollectionMode, TokenId, SponsorshipState,43 CreateCollectionData, CreateItemExData, budget, Property, PropertyKey,44 PropertyKeyPermission,45};46use pallet_evm::account::CrossAccountId;47use pallet_common::{48 CollectionHandle, Pallet as PalletCommon, CommonWeightInfo, dispatch::dispatch_call,49 dispatch::CollectionDispatch,50};51pub mod eth;5253#[cfg(feature = "runtime-benchmarks")]54mod benchmarking;55pub mod weights;56use weights::WeightInfo;5758decl_error! {59 /// Error for non-fungible-token module.60 pub enum Error for Module<T: Config> {61 /// Decimal_points parameter must be lower than MAX_DECIMAL_POINTS constant, currently it is 30.62 CollectionDecimalPointLimitExceeded,63 /// This address is not set as sponsor, use setCollectionSponsor first.64 ConfirmUnsetSponsorFail,65 /// Length of items properties must be greater than 0.66 EmptyArgument,67 }68}6970pub trait Config: system::Config + pallet_common::Config + Sized + TypeInfo {71 type Event: From<Event<Self>> + Into<<Self as frame_system::Config>::Event>;7273 /// Weight information for extrinsics in this pallet.74 type WeightInfo: WeightInfo;75 type CommonWeightInfo: CommonWeightInfo<Self::CrossAccountId>;76}7778decl_event! {79 pub enum Event<T>80 where81 <T as frame_system::Config>::AccountId,82 <T as pallet_evm::account::Config>::CrossAccountId,83 {84 /// Collection sponsor was removed85 ///86 /// # Arguments87 ///88 /// * collection_id: Globally unique collection identifier.89 CollectionSponsorRemoved(CollectionId),9091 /// Collection admin was added92 ///93 /// # Arguments94 ///95 /// * collection_id: Globally unique collection identifier.96 ///97 /// * admin: Admin address.98 CollectionAdminAdded(CollectionId, CrossAccountId),99100 /// Collection owned was change101 ///102 /// # Arguments103 ///104 /// * collection_id: Globally unique collection identifier.105 ///106 /// * owner: New owner address.107 CollectionOwnedChanged(CollectionId, AccountId),108109 /// Collection sponsor was set110 ///111 /// # Arguments112 ///113 /// * collection_id: Globally unique collection identifier.114 ///115 /// * owner: New sponsor address.116 CollectionSponsorSet(CollectionId, AccountId),117118 /// const on chain schema was set119 ///120 /// # Arguments121 ///122 /// * collection_id: Globally unique collection identifier.123 ConstOnChainSchemaSet(CollectionId),124125 /// New sponsor was confirm126 ///127 /// # Arguments128 ///129 /// * collection_id: Globally unique collection identifier.130 ///131 /// * sponsor: New sponsor address.132 SponsorshipConfirmed(CollectionId, AccountId),133134 /// Collection admin was removed135 ///136 /// # Arguments137 ///138 /// * collection_id: Globally unique collection identifier.139 ///140 /// * admin: Admin address.141 CollectionAdminRemoved(CollectionId, CrossAccountId),142143 /// Address was remove from allow list144 ///145 /// # Arguments146 ///147 /// * collection_id: Globally unique collection identifier.148 ///149 /// * user: Address.150 AllowListAddressRemoved(CollectionId, CrossAccountId),151152 /// Address was add to allow list153 ///154 /// # Arguments155 ///156 /// * collection_id: Globally unique collection identifier.157 ///158 /// * user: Address.159 AllowListAddressAdded(CollectionId, CrossAccountId),160161 /// Collection limits was set162 ///163 /// # Arguments164 ///165 /// * collection_id: Globally unique collection identifier.166 CollectionLimitSet(CollectionId),167168 CollectionPermissionSet(CollectionId),169170 /// Mint permission was set171 ///172 /// # Arguments173 ///174 /// * collection_id: Globally unique collection identifier.175 MintPermissionSet(CollectionId),176177 /// Offchain schema was set178 ///179 /// # Arguments180 ///181 /// * collection_id: Globally unique collection identifier.182 OffchainSchemaSet(CollectionId),183184 /// Public access mode was set185 ///186 /// # Arguments187 ///188 /// * collection_id: Globally unique collection identifier.189 ///190 /// * mode: New access state.191 PublicAccessModeSet(CollectionId, AccessMode),192193 /// Schema version was set194 ///195 /// # Arguments196 ///197 /// * collection_id: Globally unique collection identifier.198 SchemaVersionSet(CollectionId),199 }200}201202type SelfWeightOf<T> = <T as Config>::WeightInfo;203204// # Used definitions205//206// ## User control levels207//208// chain-controlled - key is uncontrolled by user209// i.e autoincrementing index210// can use non-cryptographic hash211// real - key is controlled by user212// but it is hard to generate enough colliding values, i.e owner of signed txs213// can use non-cryptographic hash214// controlled - key is completly controlled by users215// i.e maps with mutable keys216// should use cryptographic hash217//218// ## User control level downgrade reasons219//220// ?1 - chain-controlled -> controlled221// collections/tokens can be destroyed, resulting in massive holes222// ?2 - chain-controlled -> controlled223// same as ?1, but can be only added, resulting in easier exploitation224// ?3 - real -> controlled225// no confirmation required, so addresses can be easily generated226decl_storage! {227 trait Store for Module<T: Config> as Unique {228229 //#region Private members230 /// Used for migrations231 ChainVersion: u64;232 //#endregion233234 //#region Tokens transfer rate limit baskets235 /// (Collection id (controlled?2), who created (real))236 /// TODO: Off chain worker should remove from this map when collection gets removed237 pub CreateItemBasket get(fn create_item_basket): map hasher(blake2_128_concat) (CollectionId, T::AccountId) => Option<T::BlockNumber>;238 /// Collection id (controlled?2), token id (controlled?2)239 pub NftTransferBasket get(fn nft_transfer_basket): double_map hasher(blake2_128_concat) CollectionId, hasher(blake2_128_concat) TokenId => Option<T::BlockNumber>;240 /// Collection id (controlled?2), owning user (real)241 pub FungibleTransferBasket get(fn fungible_transfer_basket): double_map hasher(blake2_128_concat) CollectionId, hasher(twox_64_concat) T::AccountId => Option<T::BlockNumber>;242 /// Collection id (controlled?2), token id (controlled?2)243 pub ReFungibleTransferBasket get(fn refungible_transfer_basket): nmap hasher(blake2_128_concat) CollectionId, hasher(blake2_128_concat) TokenId, hasher(twox_64_concat) T::AccountId => Option<T::BlockNumber>;244 //#endregion245246 /// Variable metadata sponsoring247 /// Collection id (controlled?2), token id (controlled?2)248 #[deprecated]249 pub VariableMetaDataBasket get(fn variable_meta_data_basket): double_map hasher(blake2_128_concat) CollectionId, hasher(blake2_128_concat) TokenId => Option<T::BlockNumber>;250 pub TokenPropertyBasket get(fn token_property_basket): double_map hasher(blake2_128_concat) CollectionId, hasher(blake2_128_concat) TokenId => Option<T::BlockNumber>;251252 /// Approval sponsoring253 pub NftApproveBasket get(fn nft_approve_basket): double_map hasher(blake2_128_concat) CollectionId, hasher(blake2_128_concat) TokenId => Option<T::BlockNumber>;254 pub FungibleApproveBasket get(fn fungible_approve_basket): double_map hasher(blake2_128_concat) CollectionId, hasher(twox_64_concat) T::AccountId => Option<T::BlockNumber>;255 pub RefungibleApproveBasket get(fn refungible_approve_basket): nmap hasher(blake2_128_concat) CollectionId, hasher(blake2_128_concat) TokenId, hasher(twox_64_concat) T::AccountId => Option<T::BlockNumber>;256 }257}258259decl_module! {260 pub struct Module<T: Config> for enum Call261 where262 origin: T::Origin263 {264 type Error = Error<T>;265266 fn deposit_event() = default;267268 fn on_initialize(_now: T::BlockNumber) -> Weight {269 0270 }271272 fn on_runtime_upgrade() -> Weight {273 let limit = None;274275 <VariableMetaDataBasket<T>>::remove_all(limit);276277 0278 }279280 /// This method creates a Collection of NFTs. Each Token may have multiple properties encoded as an array of bytes of certain length. The initial owner of the collection is set to the address that signed the transaction and can be changed later.281 ///282 /// # Permissions283 ///284 /// * Anyone.285 ///286 /// # Arguments287 ///288 /// * collection_name: UTF-16 string with collection name (limit 64 characters), will be stored as zero-terminated.289 ///290 /// * collection_description: UTF-16 string with collection description (limit 256 characters), will be stored as zero-terminated.291 ///292 /// * token_prefix: UTF-8 string with token prefix.293 ///294 /// * mode: [CollectionMode] collection type and type dependent data.295 // returns collection ID296 #[weight = <SelfWeightOf<T>>::create_collection()]297 #[transactional]298 #[deprecated]299 pub fn create_collection(origin,300 collection_name: BoundedVec<u16, ConstU32<MAX_COLLECTION_NAME_LENGTH>>,301 collection_description: BoundedVec<u16, ConstU32<MAX_COLLECTION_DESCRIPTION_LENGTH>>,302 token_prefix: BoundedVec<u8, ConstU32<MAX_TOKEN_PREFIX_LENGTH>>,303 mode: CollectionMode) -> DispatchResult {304 let data: CreateCollectionData<T::AccountId> = CreateCollectionData {305 name: collection_name,306 description: collection_description,307 token_prefix,308 mode,309 ..Default::default()310 };311 Self::create_collection_ex(origin, data)312 }313314 /// This method creates a collection315 ///316 /// Prefer it to deprecated [`created_collection`] method317 #[weight = <SelfWeightOf<T>>::create_collection()]318 #[transactional]319 pub fn create_collection_ex(origin, data: CreateCollectionData<T::AccountId>) -> DispatchResult {320 let sender = ensure_signed(origin)?;321322 // =========323324 T::CollectionDispatch::create(sender, data)?;325326 Ok(())327 }328329 /// **DANGEROUS**: Destroys collection and all NFTs within this collection. Users irrecoverably lose their assets and may lose real money.330 ///331 /// # Permissions332 ///333 /// * Collection Owner.334 ///335 /// # Arguments336 ///337 /// * collection_id: collection to destroy.338 #[weight = <SelfWeightOf<T>>::destroy_collection()]339 #[transactional]340 pub fn destroy_collection(origin, collection_id: CollectionId) -> DispatchResult {341 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);342 let collection = <CollectionHandle<T>>::try_get(collection_id)?;343344 // =========345346 T::CollectionDispatch::destroy(sender, collection)?;347348 <NftTransferBasket<T>>::remove_prefix(collection_id, None);349 <FungibleTransferBasket<T>>::remove_prefix(collection_id, None);350 <ReFungibleTransferBasket<T>>::remove_prefix((collection_id,), None);351352 <NftApproveBasket<T>>::remove_prefix(collection_id, None);353 <FungibleApproveBasket<T>>::remove_prefix(collection_id, None);354 <RefungibleApproveBasket<T>>::remove_prefix((collection_id,), None);355356 Ok(())357 }358359 /// Add an address to allow list.360 ///361 /// # Permissions362 ///363 /// * Collection Owner364 /// * Collection Admin365 ///366 /// # Arguments367 ///368 /// * collection_id.369 ///370 /// * address.371 #[weight = <SelfWeightOf<T>>::add_to_allow_list()]372 #[transactional]373 pub fn add_to_allow_list(origin, collection_id: CollectionId, address: T::CrossAccountId) -> DispatchResult{374375 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);376 let collection = <CollectionHandle<T>>::try_get(collection_id)?;377378 <PalletCommon<T>>::toggle_allowlist(379 &collection,380 &sender,381 &address,382 true,383 )?;384385 Self::deposit_event(Event::<T>::AllowListAddressAdded(386 collection_id,387 address388 ));389390 Ok(())391 }392393 /// Remove an address from allow list.394 ///395 /// # Permissions396 ///397 /// * Collection Owner398 /// * Collection Admin399 ///400 /// # Arguments401 ///402 /// * collection_id.403 ///404 /// * address.405 #[weight = <SelfWeightOf<T>>::remove_from_allow_list()]406 #[transactional]407 pub fn remove_from_allow_list(origin, collection_id: CollectionId, address: T::CrossAccountId) -> DispatchResult{408409 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);410 let collection = <CollectionHandle<T>>::try_get(collection_id)?;411412 <PalletCommon<T>>::toggle_allowlist(413 &collection,414 &sender,415 &address,416 false,417 )?;418419 <Pallet<T>>::deposit_event(Event::<T>::AllowListAddressRemoved(420 collection_id,421 address422 ));423424 Ok(())425 }426427 /// Change the owner of the collection.428 ///429 /// # Permissions430 ///431 /// * Collection Owner.432 ///433 /// # Arguments434 ///435 /// * collection_id.436 ///437 /// * new_owner.438 #[weight = <SelfWeightOf<T>>::change_collection_owner()]439 #[transactional]440 pub fn change_collection_owner(origin, collection_id: CollectionId, new_owner: T::AccountId) -> DispatchResult {441442 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);443444 let mut target_collection = <CollectionHandle<T>>::try_get(collection_id)?;445 target_collection.check_is_owner(&sender)?;446447 target_collection.owner = new_owner.clone();448 <Pallet<T>>::deposit_event(Event::<T>::CollectionOwnedChanged(449 collection_id,450 new_owner451 ));452453 target_collection.save()454 }455456 /// Adds an admin of the Collection.457 /// NFT Collection can be controlled by multiple admin addresses (some which can also be servers, for example). Admins can issue and burn NFTs, as well as add and remove other admins, but cannot change NFT or Collection ownership.458 ///459 /// # Permissions460 ///461 /// * Collection Owner.462 /// * Collection Admin.463 ///464 /// # Arguments465 ///466 /// * collection_id: ID of the Collection to add admin for.467 ///468 /// * new_admin_id: Address of new admin to add.469 #[weight = <SelfWeightOf<T>>::add_collection_admin()]470 #[transactional]471 pub fn add_collection_admin(origin, collection_id: CollectionId, new_admin_id: T::CrossAccountId) -> DispatchResult {472 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);473 let collection = <CollectionHandle<T>>::try_get(collection_id)?;474475 <Pallet<T>>::deposit_event(Event::<T>::CollectionAdminAdded(476 collection_id,477 new_admin_id.clone()478 ));479480 <PalletCommon<T>>::toggle_admin(&collection, &sender, &new_admin_id, true)481 }482483 /// Remove admin address of the Collection. An admin address can remove itself. List of admins may become empty, in which case only Collection Owner will be able to add an Admin.484 ///485 /// # Permissions486 ///487 /// * Collection Owner.488 /// * Collection Admin.489 ///490 /// # Arguments491 ///492 /// * collection_id: ID of the Collection to remove admin for.493 ///494 /// * account_id: Address of admin to remove.495 #[weight = <SelfWeightOf<T>>::remove_collection_admin()]496 #[transactional]497 pub fn remove_collection_admin(origin, collection_id: CollectionId, account_id: T::CrossAccountId) -> DispatchResult {498 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);499 let collection = <CollectionHandle<T>>::try_get(collection_id)?;500501 <Pallet<T>>::deposit_event(Event::<T>::CollectionAdminRemoved(502 collection_id,503 account_id.clone()504 ));505506 <PalletCommon<T>>::toggle_admin(&collection, &sender, &account_id, false)507 }508509 /// # Permissions510 ///511 /// * Collection Owner512 ///513 /// # Arguments514 ///515 /// * collection_id.516 ///517 /// * new_sponsor.518 #[weight = <SelfWeightOf<T>>::set_collection_sponsor()]519 #[transactional]520 pub fn set_collection_sponsor(origin, collection_id: CollectionId, new_sponsor: T::AccountId) -> DispatchResult {521 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);522523 let mut target_collection = <CollectionHandle<T>>::try_get(collection_id)?;524 target_collection.check_is_owner(&sender)?;525526 target_collection.set_sponsor(new_sponsor.clone());527528 <Pallet<T>>::deposit_event(Event::<T>::CollectionSponsorSet(529 collection_id,530 new_sponsor531 ));532533 target_collection.save()534 }535536 /// # Permissions537 ///538 /// * Sponsor.539 ///540 /// # Arguments541 ///542 /// * collection_id.543 #[weight = <SelfWeightOf<T>>::confirm_sponsorship()]544 #[transactional]545 pub fn confirm_sponsorship(origin, collection_id: CollectionId) -> DispatchResult {546 let sender = ensure_signed(origin)?;547548 let mut target_collection = <CollectionHandle<T>>::try_get(collection_id)?;549 ensure!(550 target_collection.confirm_sponsorship(&sender),551 Error::<T>::ConfirmUnsetSponsorFail552 );553554 <Pallet<T>>::deposit_event(Event::<T>::SponsorshipConfirmed(555 collection_id,556 sender557 ));558559 target_collection.save()560 }561562 /// Switch back to pay-per-own-transaction model.563 ///564 /// # Permissions565 ///566 /// * Collection owner.567 ///568 /// # Arguments569 ///570 /// * collection_id.571 #[weight = <SelfWeightOf<T>>::remove_collection_sponsor()]572 #[transactional]573 pub fn remove_collection_sponsor(origin, collection_id: CollectionId) -> DispatchResult {574 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);575576 let mut target_collection = <CollectionHandle<T>>::try_get(collection_id)?;577 target_collection.check_is_owner(&sender)?;578579 target_collection.sponsorship = SponsorshipState::Disabled;580581 <Pallet<T>>::deposit_event(Event::<T>::CollectionSponsorRemoved(582 collection_id583 ));584 target_collection.save()585 }586587 /// This method creates a concrete instance of NFT Collection created with CreateCollection method.588 ///589 /// # Permissions590 ///591 /// * Collection Owner.592 /// * Collection Admin.593 /// * Anyone if594 /// * Allow List is enabled, and595 /// * Address is added to allow list, and596 /// * MintPermission is enabled (see SetMintPermission method)597 ///598 /// # Arguments599 ///600 /// * collection_id: ID of the collection.601 ///602 /// * owner: Address, initial owner of the NFT.603 ///604 /// * data: Token data to store on chain.605 #[weight = T::CommonWeightInfo::create_item()]606 #[transactional]607 pub fn create_item(origin, collection_id: CollectionId, owner: T::CrossAccountId, data: CreateItemData) -> DispatchResultWithPostInfo {608 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);609 let budget = budget::Value::new(2);610611 dispatch_call::<T, _>(collection_id, |d| d.create_item(sender, owner, data, &budget))612 }613614 /// This method creates multiple items in a collection created with CreateCollection method.615 ///616 /// # Permissions617 ///618 /// * Collection Owner.619 /// * Collection Admin.620 /// * Anyone if621 /// * Allow List is enabled, and622 /// * Address is added to allow list, and623 /// * MintPermission is enabled (see SetMintPermission method)624 ///625 /// # Arguments626 ///627 /// * collection_id: ID of the collection.628 ///629 /// * itemsData: Array items properties. Each property is an array of bytes itself, see [create_item].630 ///631 /// * owner: Address, initial owner of the NFT.632 #[weight = T::CommonWeightInfo::create_multiple_items(&items_data)]633 #[transactional]634 pub fn create_multiple_items(origin, collection_id: CollectionId, owner: T::CrossAccountId, items_data: Vec<CreateItemData>) -> DispatchResultWithPostInfo {635 ensure!(!items_data.is_empty(), Error::<T>::EmptyArgument);636 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);637 let budget = budget::Value::new(2);638639 dispatch_call::<T, _>(collection_id, |d| d.create_multiple_items(sender, owner, items_data, &budget))640 }641642 #[weight = T::CommonWeightInfo::set_collection_properties(properties.len() as u32)]643 #[transactional]644 pub fn set_collection_properties(645 origin,646 collection_id: CollectionId,647 properties: Vec<Property>648 ) -> DispatchResultWithPostInfo {649 ensure!(!properties.is_empty(), Error::<T>::EmptyArgument);650651 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);652653 dispatch_call::<T, _>(collection_id, |d| d.set_collection_properties(sender, properties))654 }655656 #[weight = T::CommonWeightInfo::delete_collection_properties(property_keys.len() as u32)]657 #[transactional]658 pub fn delete_collection_properties(659 origin,660 collection_id: CollectionId,661 property_keys: Vec<PropertyKey>,662 ) -> DispatchResultWithPostInfo {663 ensure!(!property_keys.is_empty(), Error::<T>::EmptyArgument);664665 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);666667 dispatch_call::<T, _>(collection_id, |d| d.delete_collection_properties(&sender, property_keys))668 }669670 #[weight = T::CommonWeightInfo::set_token_properties(properties.len() as u32)]671 #[transactional]672 pub fn set_token_properties(673 origin,674 collection_id: CollectionId,675 token_id: TokenId,676 properties: Vec<Property>677 ) -> DispatchResultWithPostInfo {678 ensure!(!properties.is_empty(), Error::<T>::EmptyArgument);679680 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);681682 dispatch_call::<T, _>(collection_id, |d| d.set_token_properties(sender, token_id, properties))683 }684685 #[weight = T::CommonWeightInfo::delete_token_properties(property_keys.len() as u32)]686 #[transactional]687 pub fn delete_token_properties(688 origin,689 collection_id: CollectionId,690 token_id: TokenId,691 property_keys: Vec<PropertyKey>692 ) -> DispatchResultWithPostInfo {693 ensure!(!property_keys.is_empty(), Error::<T>::EmptyArgument);694695 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);696697 dispatch_call::<T, _>(collection_id, |d| d.delete_token_properties(sender, token_id, property_keys))698 }699700 #[weight = T::CommonWeightInfo::set_property_permissions(property_permissions.len() as u32)]701 #[transactional]702 pub fn set_property_permissions(703 origin,704 collection_id: CollectionId,705 property_permissions: Vec<PropertyKeyPermission>,706 ) -> DispatchResultWithPostInfo {707 ensure!(!property_permissions.is_empty(), Error::<T>::EmptyArgument);708709 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);710711 dispatch_call::<T, _>(collection_id, |d| d.set_property_permissions(&sender, property_permissions))712 }713714 #[weight = T::CommonWeightInfo::create_multiple_items_ex(&data)]715 #[transactional]716 pub fn create_multiple_items_ex(origin, collection_id: CollectionId, data: CreateItemExData<T::CrossAccountId>) -> DispatchResultWithPostInfo {717 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);718 let budget = budget::Value::new(2);719720 dispatch_call::<T, _>(collection_id, |d| d.create_multiple_items_ex(sender, data, &budget))721 }722723 // TODO! transaction weight724725 /// Set transfers_enabled value for particular collection726 ///727 /// # Permissions728 ///729 /// * Collection Owner.730 ///731 /// # Arguments732 ///733 /// * collection_id: ID of the collection.734 ///735 /// * value: New flag value.736 #[weight = <SelfWeightOf<T>>::set_transfers_enabled_flag()]737 #[transactional]738 pub fn set_transfers_enabled_flag(origin, collection_id: CollectionId, value: bool) -> DispatchResult {739 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);740 let mut target_collection = <CollectionHandle<T>>::try_get(collection_id)?;741 target_collection.check_is_owner(&sender)?;742743 // =========744745 target_collection.limits.transfers_enabled = Some(value);746 target_collection.save()747 }748749 /// Destroys a concrete instance of NFT.750 ///751 /// # Permissions752 ///753 /// * Collection Owner.754 /// * Collection Admin.755 /// * Current NFT Owner.756 ///757 /// # Arguments758 ///759 /// * collection_id: ID of the collection.760 ///761 /// * item_id: ID of NFT to burn.762 #[weight = T::CommonWeightInfo::burn_item()]763 #[transactional]764 pub fn burn_item(origin, collection_id: CollectionId, item_id: TokenId, value: u128) -> DispatchResultWithPostInfo {765 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);766767 let post_info = dispatch_call::<T, _>(collection_id, |d| d.burn_item(sender, item_id, value))?;768 if value == 1 {769 <NftTransferBasket<T>>::remove(collection_id, item_id);770 <NftApproveBasket<T>>::remove(collection_id, item_id);771 }772 // Those maps should be cleared only if token disappears completly, need to move this part of logic to pallets?773 // <FungibleApproveBasket<T>>::remove(collection_id, sender.as_sub());774 // <RefungibleApproveBasket<T>>::remove((collection_id, item_id, sender.as_sub()));775 Ok(post_info)776 }777778 /// Destroys a concrete instance of NFT on behalf of the owner779 /// See also: [`approve`]780 ///781 /// # Permissions782 ///783 /// * Collection Owner.784 /// * Collection Admin.785 /// * Current NFT Owner.786 ///787 /// # Arguments788 ///789 /// * collection_id: ID of the collection.790 ///791 /// * item_id: ID of NFT to burn.792 ///793 /// * from: owner of item794 #[weight = T::CommonWeightInfo::burn_from()]795 #[transactional]796 pub fn burn_from(origin, collection_id: CollectionId, from: T::CrossAccountId, item_id: TokenId, value: u128) -> DispatchResultWithPostInfo {797 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);798 let budget = budget::Value::new(2);799800 dispatch_call::<T, _>(collection_id, |d| d.burn_from(sender, from, item_id, value, &budget))801 }802803 /// Change ownership of the token.804 ///805 /// # Permissions806 ///807 /// * Collection Owner808 /// * Collection Admin809 /// * Current NFT owner810 ///811 /// # Arguments812 ///813 /// * recipient: Address of token recipient.814 ///815 /// * collection_id.816 ///817 /// * item_id: ID of the item818 /// * Non-Fungible Mode: Required.819 /// * Fungible Mode: Ignored.820 /// * Re-Fungible Mode: Required.821 ///822 /// * value: Amount to transfer.823 /// * Non-Fungible Mode: Ignored824 /// * Fungible Mode: Must specify transferred amount825 /// * Re-Fungible Mode: Must specify transferred portion (between 0 and 1)826 #[weight = T::CommonWeightInfo::transfer()]827 #[transactional]828 pub fn transfer(origin, recipient: T::CrossAccountId, collection_id: CollectionId, item_id: TokenId, value: u128) -> DispatchResultWithPostInfo {829 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);830 let budget = budget::Value::new(2);831832 dispatch_call::<T, _>(collection_id, |d| d.transfer(sender, recipient, item_id, value, &budget))833 }834835 /// Set, change, or remove approved address to transfer the ownership of the NFT.836 ///837 /// # Permissions838 ///839 /// * Collection Owner840 /// * Collection Admin841 /// * Current NFT owner842 ///843 /// # Arguments844 ///845 /// * approved: Address that is approved to transfer this NFT or zero (if needed to remove approval).846 ///847 /// * collection_id.848 ///849 /// * item_id: ID of the item.850 #[weight = T::CommonWeightInfo::approve()]851 #[transactional]852 pub fn approve(origin, spender: T::CrossAccountId, collection_id: CollectionId, item_id: TokenId, amount: u128) -> DispatchResultWithPostInfo {853 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);854855 dispatch_call::<T, _>(collection_id, |d| d.approve(sender, spender, item_id, amount))856 }857858 /// Change ownership of a NFT on behalf of the owner. See Approve method for additional information. After this method executes, the approval is removed so that the approved address will not be able to transfer this NFT again from this owner.859 ///860 /// # Permissions861 /// * Collection Owner862 /// * Collection Admin863 /// * Current NFT owner864 /// * Address approved by current NFT owner865 ///866 /// # Arguments867 ///868 /// * from: Address that owns token.869 ///870 /// * recipient: Address of token recipient.871 ///872 /// * collection_id.873 ///874 /// * item_id: ID of the item.875 ///876 /// * value: Amount to transfer.877 #[weight = T::CommonWeightInfo::transfer_from()]878 #[transactional]879 pub fn transfer_from(origin, from: T::CrossAccountId, recipient: T::CrossAccountId, collection_id: CollectionId, item_id: TokenId, value: u128 ) -> DispatchResultWithPostInfo {880 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);881 let budget = budget::Value::new(2);882883 dispatch_call::<T, _>(collection_id, |d| d.transfer_from(sender, from, recipient, item_id, value, &budget))884 }885886 #[weight = <SelfWeightOf<T>>::set_collection_limits()]887 #[transactional]888 pub fn set_collection_limits(889 origin,890 collection_id: CollectionId,891 new_limit: CollectionLimits,892 ) -> DispatchResult {893 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);894 let mut target_collection = <CollectionHandle<T>>::try_get(collection_id)?;895 target_collection.check_is_owner(&sender)?;896 let old_limit = &target_collection.limits;897898 target_collection.limits = <PalletCommon<T>>::clamp_limits(target_collection.mode.clone(), &old_limit, new_limit)?;899900 <Pallet<T>>::deposit_event(Event::<T>::CollectionLimitSet(901 collection_id902 ));903904 target_collection.save()905 }906907 #[weight = <SelfWeightOf<T>>::set_collection_limits()]908 #[transactional]909 pub fn set_collection_permissions(910 origin,911 collection_id: CollectionId,912 new_limit: CollectionPermissions,913 ) -> DispatchResult {914 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);915 let mut target_collection = <CollectionHandle<T>>::try_get(collection_id)?;916 target_collection.check_is_owner(&sender)?;917 let old_limit = &target_collection.permissions;918919 target_collection.permissions = <PalletCommon<T>>::clamp_permissions(target_collection.mode.clone(), &old_limit, new_limit)?;920921 <Pallet<T>>::deposit_event(Event::<T>::CollectionPermissionSet(922 collection_id923 ));924925 target_collection.save()926 }927 }928}