difftreelog
Revert "feat: burn children when destroying a collection"
in: master
This reverts commit 4b7f4d90a16f3a5ab26bed0511dabae078429724.
12 files changed
pallets/common/src/dispatch.rsdiffbeforeafterboth--- a/pallets/common/src/dispatch.rs
+++ b/pallets/common/src/dispatch.rs
@@ -6,7 +6,7 @@
weights::Pays,
traits::Get,
};
-use up_data_structs::{CollectionId, CreateCollectionData, budget::Budget};
+use up_data_structs::{CollectionId, CreateCollectionData};
use crate::{pallet::Config, CommonCollectionOperations, CollectionHandle};
@@ -57,11 +57,7 @@
pub trait CollectionDispatch<T: Config> {
fn create(sender: T::AccountId, data: CreateCollectionData<T::AccountId>) -> DispatchResult;
- fn destroy(
- sender: T::CrossAccountId,
- handle: CollectionHandle<T>,
- nesting_budget: &dyn Budget,
- ) -> DispatchResult;
+ fn destroy(sender: T::CrossAccountId, handle: CollectionHandle<T>) -> DispatchResult;
fn dispatch(handle: CollectionHandle<T>) -> Self;
fn into_inner(self) -> CollectionHandle<T>;
pallets/common/src/lib.rsdiffbeforeafterboth--- a/pallets/common/src/lib.rs
+++ b/pallets/common/src/lib.rs
@@ -1169,12 +1169,6 @@
token: TokenId,
amount: u128,
) -> DispatchResultWithPostInfo;
- fn burn_item_unchecked(
- &self,
- owner: &T::CrossAccountId,
- token: TokenId,
- amount: u128,
- ) -> DispatchResult;
fn set_collection_properties(
&self,
sender: T::CrossAccountId,
pallets/fungible/src/common.rsdiffbeforeafterboth--- a/pallets/fungible/src/common.rs
+++ b/pallets/fungible/src/common.rs
@@ -170,17 +170,6 @@
)
}
- fn burn_item_unchecked(
- &self,
- owner: &T::CrossAccountId,
- _token: TokenId,
- amount: u128,
- ) -> sp_runtime::DispatchResult {
- <Pallet<T>>::burn_item_unchecked(self, owner, amount)?;
-
- Ok(())
- }
-
fn transfer(
&self,
from: T::CrossAccountId,
pallets/fungible/src/lib.rsdiffbeforeafterboth--- a/pallets/fungible/src/lib.rs
+++ b/pallets/fungible/src/lib.rs
@@ -160,36 +160,6 @@
owner: &T::CrossAccountId,
amount: u128,
) -> DispatchResult {
- if collection.access == AccessMode::AllowList {
- collection.check_allowlist(owner)?;
- }
-
- // =========
-
- Self::burn_item_unchecked(collection, owner, amount)?;
-
- <PalletEvm<T>>::deposit_log(
- ERC20Events::Transfer {
- from: *owner.as_eth(),
- to: H160::default(),
- value: amount.into(),
- }
- .to_log(collection_id_to_address(collection.id)),
- );
- <PalletCommon<T>>::deposit_event(CommonEvent::ItemDestroyed(
- collection.id,
- TokenId::default(),
- owner.clone(),
- amount,
- ));
- Ok(())
- }
-
- pub fn burn_item_unchecked(
- collection: &FungibleHandle<T>,
- owner: &T::CrossAccountId,
- amount: u128,
- ) -> DispatchResult {
let total_supply = <TotalSupply<T>>::get(collection.id)
.checked_sub(amount)
.ok_or(<CommonError<T>>::TokenValueTooLow)?;
@@ -216,6 +186,20 @@
}
<TotalSupply<T>>::insert(collection.id, total_supply);
+ <PalletEvm<T>>::deposit_log(
+ ERC20Events::Transfer {
+ from: *owner.as_eth(),
+ to: H160::default(),
+ value: amount.into(),
+ }
+ .to_log(collection_id_to_address(collection.id)),
+ );
+ <PalletCommon<T>>::deposit_event(CommonEvent::ItemDestroyed(
+ collection.id,
+ TokenId::default(),
+ owner.clone(),
+ amount,
+ ));
Ok(())
}
pallets/nonfungible/src/common.rsdiffbeforeafterboth--- a/pallets/nonfungible/src/common.rs
+++ b/pallets/nonfungible/src/common.rs
@@ -264,19 +264,6 @@
}
}
- fn burn_item_unchecked(
- &self,
- owner:& T::CrossAccountId,
- token: TokenId,
- amount: u128,
- ) -> sp_runtime::DispatchResult {
- if amount == 1 {
- <Pallet<T>>::burn_item_unchecked(self, owner, token)
- } else {
- Ok(())
- }
- }
-
fn transfer(
&self,
from: T::CrossAccountId,
pallets/nonfungible/src/lib.rsdiffbeforeafterboth--- a/pallets/nonfungible/src/lib.rs
+++ b/pallets/nonfungible/src/lib.rs
@@ -27,7 +27,6 @@
use pallet_evm::{account::CrossAccountId, Pallet as PalletEvm};
use pallet_common::{
Error as CommonError, Pallet as PalletCommon, Event as CommonEvent, CollectionHandle,
- dispatch::CollectionDispatch,
eth::collection_id_to_address,
};
use pallet_structure::Pallet as PalletStructure;
@@ -80,8 +79,6 @@
NonfungibleItemsHaveNoAmount,
/// Unable to burn NFT with children
CantBurnNftWithChildren,
- /// Too many children to burn when destroying a collection
- TooManyChildrenToBurn,
}
#[pallet::config]
@@ -293,14 +290,13 @@
pub fn destroy_collection(
collection: NonfungibleHandle<T>,
sender: &T::CrossAccountId,
- nesting_budget: &dyn Budget,
) -> DispatchResult {
let id = collection.id;
// =========
- Self::burn_children_in_collection(id, nesting_budget)?;
PalletCommon::destroy_collection(collection.0, sender)?;
+
<TokenData<T>>::remove_prefix((id,), None);
<TokenChildren<T>>::remove_prefix((id,), None);
<Owned<T>>::remove_prefix((id,), None);
@@ -308,47 +304,9 @@
<TokensBurnt<T>>::remove(id);
<Allowance<T>>::remove_prefix((id,), None);
<AccountBalance<T>>::remove_prefix((id,), None);
- Ok(())
- }
-
- #[transactional]
- fn burn_children_in_collection(collection_id: CollectionId, nesting_budget: &dyn Budget) -> DispatchResult {
- for (parent_id, child) in <TokenChildren<T>>::drain_prefix((collection_id,))
- .map(|((parent_id, child), _)| (parent_id, child)) {
-
- let parent_address = T::CrossTokenAddressMapping::token_to_address(collection_id, parent_id);
- Self::burn_tree(parent_address, child.0, child.1, nesting_budget)?;
- }
-
Ok(())
}
- fn burn_tree(
- parent: T::CrossAccountId,
- collection_id: CollectionId,
- token_id: TokenId,
- nesting_budget: &dyn Budget
- ) -> DispatchResult {
- if !nesting_budget.consume() {
- return Err(<Error<T>>::TooManyChildrenToBurn.into());
- }
-
- let handle = <CollectionHandle<T>>::try_get(collection_id)?;
- let handle = T::CollectionDispatch::dispatch(handle);
- let handle = handle.as_dyn();
-
- let amount = handle.balance(parent.clone(), token_id);
-
- handle.burn_item_unchecked(&parent, token_id, amount)?;
-
- for child in <TokenChildren<T>>::drain_prefix((collection_id, token_id)).map(|(child, _)| child) {
- let parent = T::CrossTokenAddressMapping::token_to_address(collection_id, token_id);
- Self::burn_tree(parent, child.0, child.1, nesting_budget)?;
- }
-
- Ok(())
- }
-
pub fn burn(
collection: &NonfungibleHandle<T>,
sender: &T::CrossAccountId,
@@ -370,11 +328,31 @@
return Err(<Error<T>>::CantBurnNftWithChildren.into());
}
- let old_spender = <Allowance<T>>::get((collection.id, token));
+ let burnt = <TokensBurnt<T>>::get(collection.id)
+ .checked_add(1)
+ .ok_or(ArithmeticError::Overflow)?;
+
+ let balance = <AccountBalance<T>>::get((collection.id, token_data.owner.clone()))
+ .checked_sub(1)
+ .ok_or(ArithmeticError::Overflow)?;
+
+ if balance == 0 {
+ <AccountBalance<T>>::remove((collection.id, token_data.owner.clone()));
+ } else {
+ <AccountBalance<T>>::insert((collection.id, token_data.owner.clone()), balance);
+ }
+
+ if let Some(owner) = T::CrossTokenAddressMapping::address_to_token(&token_data.owner) {
+ Self::unnest(owner, (collection.id, token));
+ }
// =========
- Self::burn_item_unchecked(collection, &token_data.owner, token)?;
+ <Owned<T>>::remove((collection.id, &token_data.owner, token));
+ <TokensBurnt<T>>::insert(collection.id, burnt);
+ <TokenData<T>>::remove((collection.id, token));
+ <TokenProperties<T>>::remove((collection.id, token));
+ let old_spender = <Allowance<T>>::take((collection.id, token));
if let Some(old_spender) = old_spender {
<PalletCommon<T>>::deposit_event(CommonEvent::Approved(
@@ -400,40 +378,6 @@
token_data.owner,
1,
));
- Ok(())
- }
-
- pub fn burn_item_unchecked(
- collection: &NonfungibleHandle<T>,
- owner: &T::CrossAccountId,
- token: TokenId,
- ) -> DispatchResult {
- let burnt = <TokensBurnt<T>>::get(collection.id)
- .checked_add(1)
- .ok_or(ArithmeticError::Overflow)?;
-
- let balance = <AccountBalance<T>>::get((collection.id, owner.clone()))
- .checked_sub(1)
- .ok_or(ArithmeticError::Overflow)?;
-
- // =========
-
- if let Some(owner) = T::CrossTokenAddressMapping::address_to_token(owner) {
- Self::unnest(owner, (collection.id, token));
- }
-
- if balance == 0 {
- <AccountBalance<T>>::remove((collection.id, owner.clone()));
- } else {
- <AccountBalance<T>>::insert((collection.id, owner.clone()), balance);
- }
-
- <Owned<T>>::remove((collection.id, owner, token));
- <TokensBurnt<T>>::insert(collection.id, burnt);
- <TokenData<T>>::remove((collection.id, token));
- <TokenProperties<T>>::remove((collection.id, token));
- <Allowance<T>>::remove((collection.id, token));
-
Ok(())
}
pallets/proxy-rmrk-core/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 frame_support::{pallet_prelude::*, transactional, BoundedVec, dispatch::DispatchResult};20use frame_system::{pallet_prelude::*, ensure_signed};21use sp_runtime::{DispatchError, Permill, traits::StaticLookup};22use sp_std::vec::Vec;23use up_data_structs::*;24use pallet_common::{Pallet as PalletCommon, Error as CommonError, CollectionHandle, CommonCollectionOperations};25use pallet_nonfungible::{Pallet as PalletNft, NonfungibleHandle, TokenData};26use pallet_evm::account::CrossAccountId;27use core::convert::AsRef;2829pub use pallet::*;3031pub mod misc;32pub mod property;3334use misc::*;35pub use property::*;3637use RmrkProperty::*;3839#[frame_support::pallet]40pub mod pallet {41 use super::*;42 use pallet_evm::account;4344 #[pallet::config]45 pub trait Config: frame_system::Config46 + pallet_common::Config47 + pallet_nonfungible::Config48 + account::Config {49 type Event: From<Event<Self>> + IsType<<Self as frame_system::Config>::Event>;50 }5152 #[pallet::storage]53 #[pallet::getter(fn collection_index)]54 pub type CollectionIndex<T: Config> = StorageValue<_, RmrkCollectionId, ValueQuery>;5556 #[pallet::pallet]57 #[pallet::generate_store(pub(super) trait Store)]58 pub struct Pallet<T>(_);5960 #[pallet::event]61 #[pallet::generate_deposit(pub(super) fn deposit_event)]62 pub enum Event<T: Config> {63 CollectionCreated {64 issuer: T::AccountId,65 collection_id: RmrkCollectionId,66 },67 CollectionDestroyed {68 issuer: T::AccountId,69 collection_id: RmrkCollectionId,70 },71 IssuerChanged {72 old_issuer: T::AccountId,73 new_issuer: T::AccountId,74 collection_id: RmrkCollectionId,75 },76 CollectionLocked {77 issuer: T::AccountId,78 collection_id: RmrkCollectionId,79 },80 NftMinted {81 owner: T::AccountId,82 collection_id: RmrkCollectionId,83 nft_id: RmrkNftId,84 },85 NFTBurned {86 owner: T::AccountId,87 nft_id: RmrkNftId,88 },89 PropertySet {90 collection_id: RmrkCollectionId,91 maybe_nft_id: Option<RmrkNftId>,92 key: RmrkKeyString,93 value: RmrkValueString,94 },95 }9697 #[pallet::error]98 pub enum Error<T> {99 /* Unique-specific events */100 CorruptedCollectionType,101 NftTypeEncodeError,102 RmrkPropertyKeyIsTooLong,103 RmrkPropertyValueIsTooLong,104105 /* RMRK compatible events */106 CollectionNotEmpty,107 NoAvailableCollectionId,108 NoAvailableNftId,109 CollectionUnknown,110 NoPermission,111 CollectionFullOrLocked,112 }113114 #[pallet::call]115 impl<T: Config> Pallet<T> {116 #[pallet::weight(10_000 + T::DbWeight::get().reads_writes(1,1))]117 #[transactional]118 pub fn create_collection(119 origin: OriginFor<T>,120 metadata: RmrkString,121 max: Option<u32>,122 symbol: RmrkCollectionSymbol,123 ) -> DispatchResult {124 let sender = ensure_signed(origin)?;125126 let limits = CollectionLimits {127 owner_can_transfer: Some(false),128 token_limit: max,129 ..Default::default()130 };131132 let data = CreateCollectionData {133 limits: Some(limits),134 token_prefix: symbol.into_inner()135 .try_into()136 .map_err(|_| <CommonError<T>>::CollectionTokenPrefixLimitExceeded)?,137 ..Default::default()138 };139140 let collection_id_res = <PalletNft<T>>::init_collection(sender.clone(), data);141142 if let Err(DispatchError::Arithmetic(_)) = &collection_id_res {143 return Err(<Error<T>>::NoAvailableCollectionId.into());144 }145146 let collection_id = collection_id_res?;147148 <PalletCommon<T>>::set_scoped_collection_properties(149 collection_id,150 PropertyScope::Rmrk,151 [152 Self::rmrk_property(Metadata, &metadata)?,153 Self::rmrk_property(CollectionType, &misc::CollectionType::Regular)?,154 ].into_iter()155 )?;156157 <CollectionIndex<T>>::mutate(|n| *n += 1);158159 Self::deposit_event(Event::CollectionCreated {160 issuer: sender,161 collection_id: collection_id.0162 });163164 Ok(())165 }166167 #[pallet::weight(10_000 + T::DbWeight::get().reads_writes(1,1))]168 #[transactional]169 pub fn destroy_collection(170 origin: OriginFor<T>,171 collection_id: RmrkCollectionId,172 ) -> DispatchResult {173 let sender = ensure_signed(origin)?;174 let cross_sender = T::CrossAccountId::from_sub(sender.clone());175176 let unique_collection_id = collection_id.into();177178 let collection = Self::get_typed_nft_collection(unique_collection_id, misc::CollectionType::Regular)?;179180 ensure!(collection.total_supply() == 0, <Error<T>>::CollectionNotEmpty);181182 let empty_budget = budget::Value::new(0);183 <PalletNft<T>>::destroy_collection(collection, &cross_sender, &empty_budget)184 .map_err(Self::map_common_err_to_proxy)?;185186 Self::deposit_event(Event::CollectionDestroyed { issuer: sender, collection_id });187188 Ok(())189 }190191 #[pallet::weight(10_000 + T::DbWeight::get().reads_writes(1,1))]192 #[transactional]193 pub fn change_collection_issuer(194 origin: OriginFor<T>,195 collection_id: RmrkCollectionId,196 new_issuer: <T::Lookup as StaticLookup>::Source,197 ) -> DispatchResult {198 let sender = ensure_signed(origin)?;199200 let new_issuer = T::Lookup::lookup(new_issuer)?;201202 Self::change_collection_owner(203 collection_id.into(),204 misc::CollectionType::Regular,205 sender.clone(),206 new_issuer.clone()207 )?;208209 Self::deposit_event(Event::IssuerChanged {210 old_issuer: sender,211 new_issuer,212 collection_id,213 });214215 Ok(())216 }217218 #[pallet::weight(10_000 + T::DbWeight::get().reads_writes(1,1))]219 #[transactional]220 pub fn lock_collection(221 origin: OriginFor<T>,222 collection_id: RmrkCollectionId,223 ) -> DispatchResult {224 let sender = ensure_signed(origin)?;225 let cross_sender = T::CrossAccountId::from_sub(sender.clone());226227 let collection = Self::get_typed_nft_collection(228 collection_id.into(),229 misc::CollectionType::Regular230 )?;231232 Self::check_collection_owner(&collection, &cross_sender)?;233234 let token_count = collection.total_supply();235236 let mut collection = collection.into_inner();237 collection.limits.token_limit = Some(token_count);238 collection.save()?;239240 Self::deposit_event(Event::CollectionLocked { issuer: sender, collection_id });241242 Ok(())243 }244245 #[pallet::weight(10_000 + T::DbWeight::get().reads_writes(1,1))]246 #[transactional]247 pub fn mint_nft(248 origin: OriginFor<T>,249 owner: T::AccountId,250 collection_id: RmrkCollectionId,251 recipient: Option<T::AccountId>,252 royalty_amount: Option<Permill>,253 metadata: RmrkString,254 ) -> DispatchResult {255 let sender = ensure_signed(origin)?;256 let sender = T::CrossAccountId::from_sub(sender);257 let cross_owner = T::CrossAccountId::from_sub(owner.clone());258259 let royalty_info = royalty_amount.map(|amount| rmrk::RoyaltyInfo {260 recipient: recipient.unwrap_or_else(|| owner.clone()),261 amount262 });263264 let collection = Self::get_typed_nft_collection(265 collection_id.into(),266 misc::CollectionType::Regular,267 )?;268269 let nft_id = Self::create_nft(270 &sender,271 &cross_owner,272 &collection,273 NftType::Regular,274 [275 Self::rmrk_property(RoyaltyInfo, &royalty_info)?,276 Self::rmrk_property(Metadata, &metadata)?,277 Self::rmrk_property(Equipped, &false)?,278 Self::rmrk_property(ResourceCollection, &None::<CollectionId>)?,279 Self::rmrk_property(ResourcePriorities, &<Vec<u8>>::new())?,280 ].into_iter()281 ).map_err(|err| match err {282 DispatchError::Arithmetic(_) => <Error<T>>::NoAvailableNftId.into(),283 err => Self::map_common_err_to_proxy(err)284 })?;285286 Self::deposit_event(Event::NftMinted {287 owner,288 collection_id,289 nft_id: nft_id.0290 });291292 Ok(())293 }294295 #[pallet::weight(10_000 + T::DbWeight::get().reads_writes(1,1))]296 #[transactional]297 pub fn burn_nft(298 origin: OriginFor<T>,299 collection_id: RmrkCollectionId,300 nft_id: RmrkNftId,301 ) -> DispatchResult {302 let sender = ensure_signed(origin)?;303 let cross_sender = T::CrossAccountId::from_sub(sender.clone());304305 Self::destroy_nft(306 cross_sender,307 collection_id.into(),308 misc::CollectionType::Regular,309 nft_id.into()310 )?;311312 Self::deposit_event(Event::NFTBurned { owner: sender, nft_id });313314 Ok(())315 }316317 #[pallet::weight(10_000 + T::DbWeight::get().reads_writes(1,1))]318 #[transactional]319 pub fn set_property(320 origin: OriginFor<T>,321 #[pallet::compact] rmrk_collection_id: RmrkCollectionId,322 maybe_nft_id: Option<RmrkNftId>,323 key: RmrkKeyString,324 value: RmrkValueString,325 ) -> DispatchResult {326 let sender = ensure_signed(origin)?;327 let sender = T::CrossAccountId::from_sub(sender);328329 let collection_id: CollectionId = rmrk_collection_id.into();330331 match maybe_nft_id {332 Some(nft_id) => {333 let token_id: TokenId = nft_id.into();334335 Self::ensure_nft_owner(collection_id, token_id, &sender)?;336 Self::ensure_nft_type(collection_id, token_id, NftType::Regular)?;337338 <PalletNft<T>>::set_scoped_token_property(339 collection_id,340 token_id,341 PropertyScope::Rmrk,342 Self::rmrk_property(UserProperty(key.as_slice()), &value)?343 )?;344 },345 None => {346 let collection = Self::get_typed_nft_collection(347 collection_id,348 misc::CollectionType::Regular349 )?;350351 Self::check_collection_owner(&collection, &sender)?;352353 <PalletCommon<T>>::set_scoped_collection_property(354 collection_id,355 PropertyScope::Rmrk,356 Self::rmrk_property(UserProperty(key.as_slice()), &value)?357 )?;358 }359 }360361 Self::deposit_event(362 Event::PropertySet {363 collection_id: rmrk_collection_id,364 maybe_nft_id,365 key,366 value367 }368 );369370 Ok(())371 }372 }373}374375impl<T: Config> Pallet<T> {376 pub fn rmrk_property_key(rmrk_key: RmrkProperty) -> Result<PropertyKey, DispatchError> {377 let key = rmrk_key.to_key::<T>()?;378379 let scoped_key = PropertyScope::Rmrk.apply(key)380 .map_err(|_| <Error<T>>::RmrkPropertyKeyIsTooLong)?;381382 Ok(scoped_key)383 }384385 pub fn rmrk_property<E: Encode>(rmrk_key: RmrkProperty, value: &E) -> Result<Property, DispatchError> {386 let key = rmrk_key.to_key::<T>()?;387388 let value = value.encode()389 .try_into()390 .map_err(|_| <Error<T>>::RmrkPropertyValueIsTooLong)?;391392 let property = Property {393 key,394 value,395 };396397 Ok(property)398 }399400 pub fn create_nft(401 sender: &T::CrossAccountId,402 owner: &T::CrossAccountId,403 collection: &NonfungibleHandle<T>,404 nft_type: NftType,405 properties: impl Iterator<Item=Property>406 ) -> Result<TokenId, DispatchError> {407 todo!("store nft type");408 let data = CreateNftExData {409 properties: BoundedVec::default(),410 owner: owner.clone(),411 };412413 let budget = budget::Value::new(2);414415 <PalletNft<T>>::create_item(416 collection,417 sender,418 data,419 &budget,420 )?;421422 let nft_id = <PalletNft<T>>::current_token_id(collection.id);423424 <PalletNft<T>>::set_scoped_token_properties(425 collection.id,426 nft_id,427 PropertyScope::Rmrk,428 properties429 )?;430431 Ok(nft_id)432 }433434 fn destroy_nft(435 sender: T::CrossAccountId,436 collection_id: CollectionId,437 collection_type: misc::CollectionType,438 token_id: TokenId439 ) -> DispatchResult {440 let collection = Self::get_typed_nft_collection(441 collection_id,442 collection_type443 )?;444445 <PalletNft<T>>::burn(&collection, &sender, token_id)446 .map_err(Self::map_common_err_to_proxy)?;447448 Ok(())449 }450451 fn change_collection_owner(452 collection_id: CollectionId,453 collection_type: misc::CollectionType,454 sender: T::AccountId,455 new_owner: T::AccountId,456 ) -> DispatchResult {457 let collection = Self::get_typed_nft_collection(458 collection_id,459 collection_type460 )?;461 Self::check_collection_owner(&collection, &T::CrossAccountId::from_sub(sender))?;462463 let mut collection = collection.into_inner();464465 collection.owner = new_owner;466 collection.save()467 }468469 fn check_collection_owner(collection: &NonfungibleHandle<T>, account: &T::CrossAccountId) -> DispatchResult {470 collection.check_is_owner(account)471 .map_err(Self::map_common_err_to_proxy)472 }473474 pub fn last_collection_idx() -> RmrkCollectionId {475 <CollectionIndex<T>>::get()476 }477478 pub fn get_nft_collection(collection_id: CollectionId) -> Result<NonfungibleHandle<T>, DispatchError> {479 let collection = <CollectionHandle<T>>::try_get(collection_id)480 .map_err(|_| <Error<T>>::CollectionUnknown)?;481482 match collection.mode {483 CollectionMode::NFT => Ok(NonfungibleHandle::cast(collection)),484 _ => Err(<Error<T>>::CollectionUnknown.into())485 }486 }487488 pub fn collection_exists(collection_id: CollectionId) -> bool {489 <CollectionHandle<T>>::try_get(collection_id).is_ok()490 }491492 pub fn nft_exists(collection_id: CollectionId, nft_id: TokenId) -> bool {493 <TokenData<T>>::contains_key((collection_id, nft_id))494 }495496 pub fn get_collection_property(collection_id: CollectionId, key: RmrkProperty) -> Result<PropertyValue, DispatchError> {497 let collection_property = <PalletCommon<T>>::collection_properties(collection_id)498 .get(&Self::rmrk_property_key(key)?)499 .ok_or(<Error<T>>::CollectionUnknown)?500 .clone();501502 Ok(collection_property)503 }504505 pub fn get_collection_type(collection_id: CollectionId) -> Result<misc::CollectionType, DispatchError> {506 let value = Self::get_collection_property(collection_id, CollectionType)?;507508 let mut value = value.as_slice();509510 misc::CollectionType::decode(&mut value)511 .map_err(|_| <Error<T>>::CorruptedCollectionType.into())512 }513514 pub fn ensure_collection_type(collection_id: CollectionId, collection_type: misc::CollectionType) -> DispatchResult {515 let actual_type = Self::get_collection_type(collection_id)?;516 ensure!(actual_type == collection_type, <CommonError<T>>::NoPermission);517518 Ok(())519 }520521 pub fn get_nft_property(collection_id: CollectionId, nft_id: TokenId, key: RmrkProperty) -> Result<PropertyValue, DispatchError> {522 let nft_property = <PalletNft<T>>::token_properties((collection_id, nft_id))523 .get(&Self::rmrk_property_key(key)?)524 .ok_or(<Error<T>>::NoAvailableNftId)?525 .clone();526527 Ok(nft_property)528 }529530 pub fn get_nft_type(_collection_id: CollectionId, _token_id: TokenId) -> Result<NftType, DispatchError> {531 todo!("should get it from properties?")532 }533534 pub fn ensure_nft_type(collection_id: CollectionId, token_id: TokenId, nft_type: NftType) -> DispatchResult {535 let actual_type = Self::get_nft_type(collection_id, token_id)?;536 ensure!(actual_type == nft_type, <Error<T>>::NoPermission);537538 Ok(())539 }540541 pub fn ensure_nft_owner(542 collection_id: CollectionId,543 token_id: TokenId,544 possible_owner: &T::CrossAccountId545 ) -> DispatchResult {546 let token_data = <TokenData<T>>::get((collection_id, token_id))547 .ok_or(<Error<T>>::NoAvailableNftId)?;548549 ensure!(token_data.owner == *possible_owner, <Error<T>>::NoPermission);550551 Ok(())552 }553554 pub fn filter_user_properties<Key, Value, R, Mapper>(555 collection_id: CollectionId,556 token_id: Option<TokenId>,557 filter_keys: Option<Vec<RmrkPropertyKey>>,558 mapper: Mapper,559 ) -> Result<Vec<R>, DispatchError>560 where561 Key: TryFrom<RmrkPropertyKey> + AsRef<[u8]>,562 Value: Decode + Default,563 Mapper: Fn(Key, Value) -> R564 {565 filter_keys.map(|keys| {566 let properties = keys.into_iter()567 .filter_map(|key| {568 let key: Key = key.try_into().ok()?;569570 let value = match token_id {571 Some(token_id) => Self::get_nft_property(572 collection_id,573 token_id,574 UserProperty(key.as_ref())575 ),576 None => Self::get_collection_property(577 collection_id,578 UserProperty(key.as_ref())579 )580 }.ok()?.decode_or_default();581582 Some(mapper(key, value))583 })584 .collect();585586 Ok(properties)587 }).unwrap_or_else(|| {588 let properties = Self::iterate_user_properties(collection_id, token_id, mapper)?589 .collect();590591 Ok(properties)592 })593 }594595 pub fn iterate_user_properties<Key, Value, R, Mapper>(596 collection_id: CollectionId,597 token_id: Option<TokenId>,598 mapper: Mapper,599 ) -> Result<impl Iterator<Item=R>, DispatchError>600 where601 Key: TryFrom<RmrkPropertyKey> + AsRef<[u8]>,602 Value: Decode + Default,603 Mapper: Fn(Key, Value) -> R604 {605 let key_prefix = Self::rmrk_property_key(UserProperty(b""))?;606607 let properties = match token_id {608 Some(token_id) => <PalletNft<T>>::token_properties((collection_id, token_id)),609 None => <PalletCommon<T>>::collection_properties(collection_id)610 };611612 let properties = properties613 .into_iter()614 .filter_map(move |(key, value)| {615 let key = key.as_slice().strip_prefix(key_prefix.as_slice())?;616617 let key: Key = key.to_vec().try_into().ok()?;618 let value: Value = value.decode_or_default();619620 Some(mapper(key, value))621 });622623 Ok(properties)624 }625626 pub fn get_typed_nft_collection(627 collection_id: CollectionId,628 collection_type: misc::CollectionType629 ) -> Result<NonfungibleHandle<T>, DispatchError> {630 Self::ensure_collection_type(collection_id, collection_type)?;631632 Self::get_nft_collection(collection_id)633 }634635 fn map_common_err_to_proxy(err: DispatchError) -> DispatchError {636 map_common_err_to_proxy! {637 match err {638 NoPermission => NoPermission,639 CollectionTokenLimitExceeded => CollectionFullOrLocked,640 PublicMintingNotAllowed => NoPermission,641 TokenNotFound => NoAvailableNftId642 }643 }644 }645}1// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.2// This file is part of Unique Network.34// Unique Network is free software: you can redistribute it and/or modify5// it under the terms of the GNU General Public License as published by6// the Free Software Foundation, either version 3 of the License, or7// (at your option) any later version.89// Unique Network is distributed in the hope that it will be useful,10// but WITHOUT ANY WARRANTY; without even the implied warranty of11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the12// GNU General Public License for more details.1314// You should have received a copy of the GNU General Public License15// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.1617#![cfg_attr(not(feature = "std"), no_std)]1819use frame_support::{pallet_prelude::*, transactional, BoundedVec, dispatch::DispatchResult};20use frame_system::{pallet_prelude::*, ensure_signed};21use sp_runtime::{DispatchError, Permill, traits::StaticLookup};22use sp_std::vec::Vec;23use up_data_structs::*;24use pallet_common::{Pallet as PalletCommon, Error as CommonError, CollectionHandle, CommonCollectionOperations};25use pallet_nonfungible::{Pallet as PalletNft, NonfungibleHandle, TokenData};26use pallet_evm::account::CrossAccountId;27use core::convert::AsRef;2829pub use pallet::*;3031pub mod misc;32pub mod property;3334use misc::*;35pub use property::*;3637use RmrkProperty::*;3839#[frame_support::pallet]40pub mod pallet {41 use super::*;42 use pallet_evm::account;4344 #[pallet::config]45 pub trait Config: frame_system::Config46 + pallet_common::Config47 + pallet_nonfungible::Config48 + account::Config {49 type Event: From<Event<Self>> + IsType<<Self as frame_system::Config>::Event>;50 }5152 #[pallet::storage]53 #[pallet::getter(fn collection_index)]54 pub type CollectionIndex<T: Config> = StorageValue<_, RmrkCollectionId, ValueQuery>;5556 #[pallet::pallet]57 #[pallet::generate_store(pub(super) trait Store)]58 pub struct Pallet<T>(_);5960 #[pallet::event]61 #[pallet::generate_deposit(pub(super) fn deposit_event)]62 pub enum Event<T: Config> {63 CollectionCreated {64 issuer: T::AccountId,65 collection_id: RmrkCollectionId,66 },67 CollectionDestroyed {68 issuer: T::AccountId,69 collection_id: RmrkCollectionId,70 },71 IssuerChanged {72 old_issuer: T::AccountId,73 new_issuer: T::AccountId,74 collection_id: RmrkCollectionId,75 },76 CollectionLocked {77 issuer: T::AccountId,78 collection_id: RmrkCollectionId,79 },80 NftMinted {81 owner: T::AccountId,82 collection_id: RmrkCollectionId,83 nft_id: RmrkNftId,84 },85 NFTBurned {86 owner: T::AccountId,87 nft_id: RmrkNftId,88 },89 PropertySet {90 collection_id: RmrkCollectionId,91 maybe_nft_id: Option<RmrkNftId>,92 key: RmrkKeyString,93 value: RmrkValueString,94 },95 }9697 #[pallet::error]98 pub enum Error<T> {99 /* Unique-specific events */100 CorruptedCollectionType,101 NftTypeEncodeError,102 RmrkPropertyKeyIsTooLong,103 RmrkPropertyValueIsTooLong,104105 /* RMRK compatible events */106 CollectionNotEmpty,107 NoAvailableCollectionId,108 NoAvailableNftId,109 CollectionUnknown,110 NoPermission,111 CollectionFullOrLocked,112 }113114 #[pallet::call]115 impl<T: Config> Pallet<T> {116 #[pallet::weight(10_000 + T::DbWeight::get().reads_writes(1,1))]117 #[transactional]118 pub fn create_collection(119 origin: OriginFor<T>,120 metadata: RmrkString,121 max: Option<u32>,122 symbol: RmrkCollectionSymbol,123 ) -> DispatchResult {124 let sender = ensure_signed(origin)?;125126 let limits = CollectionLimits {127 owner_can_transfer: Some(false),128 token_limit: max,129 ..Default::default()130 };131132 let data = CreateCollectionData {133 limits: Some(limits),134 token_prefix: symbol.into_inner()135 .try_into()136 .map_err(|_| <CommonError<T>>::CollectionTokenPrefixLimitExceeded)?,137 ..Default::default()138 };139140 let collection_id_res = <PalletNft<T>>::init_collection(sender.clone(), data);141142 if let Err(DispatchError::Arithmetic(_)) = &collection_id_res {143 return Err(<Error<T>>::NoAvailableCollectionId.into());144 }145146 let collection_id = collection_id_res?;147148 <PalletCommon<T>>::set_scoped_collection_properties(149 collection_id,150 PropertyScope::Rmrk,151 [152 Self::rmrk_property(Metadata, &metadata)?,153 Self::rmrk_property(CollectionType, &misc::CollectionType::Regular)?,154 ].into_iter()155 )?;156157 <CollectionIndex<T>>::mutate(|n| *n += 1);158159 Self::deposit_event(Event::CollectionCreated {160 issuer: sender,161 collection_id: collection_id.0162 });163164 Ok(())165 }166167 #[pallet::weight(10_000 + T::DbWeight::get().reads_writes(1,1))]168 #[transactional]169 pub fn destroy_collection(170 origin: OriginFor<T>,171 collection_id: RmrkCollectionId,172 ) -> DispatchResult {173 let sender = ensure_signed(origin)?;174 let cross_sender = T::CrossAccountId::from_sub(sender.clone());175176 let unique_collection_id = collection_id.into();177178 let collection = Self::get_typed_nft_collection(unique_collection_id, misc::CollectionType::Regular)?;179180 ensure!(collection.total_supply() == 0, <Error<T>>::CollectionNotEmpty);181182 <PalletNft<T>>::destroy_collection(collection, &cross_sender)183 .map_err(Self::map_common_err_to_proxy)?;184185 Self::deposit_event(Event::CollectionDestroyed { issuer: sender, collection_id });186187 Ok(())188 }189190 #[pallet::weight(10_000 + T::DbWeight::get().reads_writes(1,1))]191 #[transactional]192 pub fn change_collection_issuer(193 origin: OriginFor<T>,194 collection_id: RmrkCollectionId,195 new_issuer: <T::Lookup as StaticLookup>::Source,196 ) -> DispatchResult {197 let sender = ensure_signed(origin)?;198199 let new_issuer = T::Lookup::lookup(new_issuer)?;200201 Self::change_collection_owner(202 collection_id.into(),203 misc::CollectionType::Regular,204 sender.clone(),205 new_issuer.clone()206 )?;207208 Self::deposit_event(Event::IssuerChanged {209 old_issuer: sender,210 new_issuer,211 collection_id,212 });213214 Ok(())215 }216217 #[pallet::weight(10_000 + T::DbWeight::get().reads_writes(1,1))]218 #[transactional]219 pub fn lock_collection(220 origin: OriginFor<T>,221 collection_id: RmrkCollectionId,222 ) -> DispatchResult {223 let sender = ensure_signed(origin)?;224 let cross_sender = T::CrossAccountId::from_sub(sender.clone());225226 let collection = Self::get_typed_nft_collection(227 collection_id.into(),228 misc::CollectionType::Regular229 )?;230231 Self::check_collection_owner(&collection, &cross_sender)?;232233 let token_count = collection.total_supply();234235 let mut collection = collection.into_inner();236 collection.limits.token_limit = Some(token_count);237 collection.save()?;238239 Self::deposit_event(Event::CollectionLocked { issuer: sender, collection_id });240241 Ok(())242 }243244 #[pallet::weight(10_000 + T::DbWeight::get().reads_writes(1,1))]245 #[transactional]246 pub fn mint_nft(247 origin: OriginFor<T>,248 owner: T::AccountId,249 collection_id: RmrkCollectionId,250 recipient: Option<T::AccountId>,251 royalty_amount: Option<Permill>,252 metadata: RmrkString,253 ) -> DispatchResult {254 let sender = ensure_signed(origin)?;255 let sender = T::CrossAccountId::from_sub(sender);256 let cross_owner = T::CrossAccountId::from_sub(owner.clone());257258 let royalty_info = royalty_amount.map(|amount| rmrk::RoyaltyInfo {259 recipient: recipient.unwrap_or_else(|| owner.clone()),260 amount261 });262263 let collection = Self::get_typed_nft_collection(264 collection_id.into(),265 misc::CollectionType::Regular,266 )?;267268 let nft_id = Self::create_nft(269 &sender,270 &cross_owner,271 &collection,272 NftType::Regular,273 [274 Self::rmrk_property(RoyaltyInfo, &royalty_info)?,275 Self::rmrk_property(Metadata, &metadata)?,276 Self::rmrk_property(Equipped, &false)?,277 Self::rmrk_property(ResourceCollection, &None::<CollectionId>)?,278 Self::rmrk_property(ResourcePriorities, &<Vec<u8>>::new())?,279 ].into_iter()280 ).map_err(|err| match err {281 DispatchError::Arithmetic(_) => <Error<T>>::NoAvailableNftId.into(),282 err => Self::map_common_err_to_proxy(err)283 })?;284285 Self::deposit_event(Event::NftMinted {286 owner,287 collection_id,288 nft_id: nft_id.0289 });290291 Ok(())292 }293294 #[pallet::weight(10_000 + T::DbWeight::get().reads_writes(1,1))]295 #[transactional]296 pub fn burn_nft(297 origin: OriginFor<T>,298 collection_id: RmrkCollectionId,299 nft_id: RmrkNftId,300 ) -> DispatchResult {301 let sender = ensure_signed(origin)?;302 let cross_sender = T::CrossAccountId::from_sub(sender.clone());303304 Self::destroy_nft(305 cross_sender,306 collection_id.into(),307 misc::CollectionType::Regular,308 nft_id.into()309 )?;310311 Self::deposit_event(Event::NFTBurned { owner: sender, nft_id });312313 Ok(())314 }315316 #[pallet::weight(10_000 + T::DbWeight::get().reads_writes(1,1))]317 #[transactional]318 pub fn set_property(319 origin: OriginFor<T>,320 #[pallet::compact] rmrk_collection_id: RmrkCollectionId,321 maybe_nft_id: Option<RmrkNftId>,322 key: RmrkKeyString,323 value: RmrkValueString,324 ) -> DispatchResult {325 let sender = ensure_signed(origin)?;326 let sender = T::CrossAccountId::from_sub(sender);327328 let collection_id: CollectionId = rmrk_collection_id.into();329330 match maybe_nft_id {331 Some(nft_id) => {332 let token_id: TokenId = nft_id.into();333334 Self::ensure_nft_owner(collection_id, token_id, &sender)?;335 Self::ensure_nft_type(collection_id, token_id, NftType::Regular)?;336337 <PalletNft<T>>::set_scoped_token_property(338 collection_id,339 token_id,340 PropertyScope::Rmrk,341 Self::rmrk_property(UserProperty(key.as_slice()), &value)?342 )?;343 },344 None => {345 let collection = Self::get_typed_nft_collection(346 collection_id,347 misc::CollectionType::Regular348 )?;349350 Self::check_collection_owner(&collection, &sender)?;351352 <PalletCommon<T>>::set_scoped_collection_property(353 collection_id,354 PropertyScope::Rmrk,355 Self::rmrk_property(UserProperty(key.as_slice()), &value)?356 )?;357 }358 }359360 Self::deposit_event(361 Event::PropertySet {362 collection_id: rmrk_collection_id,363 maybe_nft_id,364 key,365 value366 }367 );368369 Ok(())370 }371 }372}373374impl<T: Config> Pallet<T> {375 pub fn rmrk_property_key(rmrk_key: RmrkProperty) -> Result<PropertyKey, DispatchError> {376 let key = rmrk_key.to_key::<T>()?;377378 let scoped_key = PropertyScope::Rmrk.apply(key)379 .map_err(|_| <Error<T>>::RmrkPropertyKeyIsTooLong)?;380381 Ok(scoped_key)382 }383384 pub fn rmrk_property<E: Encode>(rmrk_key: RmrkProperty, value: &E) -> Result<Property, DispatchError> {385 let key = rmrk_key.to_key::<T>()?;386387 let value = value.encode()388 .try_into()389 .map_err(|_| <Error<T>>::RmrkPropertyValueIsTooLong)?;390391 let property = Property {392 key,393 value,394 };395396 Ok(property)397 }398399 pub fn create_nft(400 sender: &T::CrossAccountId,401 owner: &T::CrossAccountId,402 collection: &NonfungibleHandle<T>,403 nft_type: NftType,404 properties: impl Iterator<Item=Property>405 ) -> Result<TokenId, DispatchError> {406 todo!("store nft type");407 let data = CreateNftExData {408 properties: BoundedVec::default(),409 owner: owner.clone(),410 };411412 let budget = budget::Value::new(2);413414 <PalletNft<T>>::create_item(415 collection,416 sender,417 data,418 &budget,419 )?;420421 let nft_id = <PalletNft<T>>::current_token_id(collection.id);422423 <PalletNft<T>>::set_scoped_token_properties(424 collection.id,425 nft_id,426 PropertyScope::Rmrk,427 properties428 )?;429430 Ok(nft_id)431 }432433 fn destroy_nft(434 sender: T::CrossAccountId,435 collection_id: CollectionId,436 collection_type: misc::CollectionType,437 token_id: TokenId438 ) -> DispatchResult {439 let collection = Self::get_typed_nft_collection(440 collection_id,441 collection_type442 )?;443444 <PalletNft<T>>::burn(&collection, &sender, token_id)445 .map_err(Self::map_common_err_to_proxy)?;446447 Ok(())448 }449450 fn change_collection_owner(451 collection_id: CollectionId,452 collection_type: misc::CollectionType,453 sender: T::AccountId,454 new_owner: T::AccountId,455 ) -> DispatchResult {456 let collection = Self::get_typed_nft_collection(457 collection_id,458 collection_type459 )?;460 Self::check_collection_owner(&collection, &T::CrossAccountId::from_sub(sender))?;461462 let mut collection = collection.into_inner();463464 collection.owner = new_owner;465 collection.save()466 }467468 fn check_collection_owner(collection: &NonfungibleHandle<T>, account: &T::CrossAccountId) -> DispatchResult {469 collection.check_is_owner(account)470 .map_err(Self::map_common_err_to_proxy)471 }472473 pub fn last_collection_idx() -> RmrkCollectionId {474 <CollectionIndex<T>>::get()475 }476477 pub fn get_nft_collection(collection_id: CollectionId) -> Result<NonfungibleHandle<T>, DispatchError> {478 let collection = <CollectionHandle<T>>::try_get(collection_id)479 .map_err(|_| <Error<T>>::CollectionUnknown)?;480481 match collection.mode {482 CollectionMode::NFT => Ok(NonfungibleHandle::cast(collection)),483 _ => Err(<Error<T>>::CollectionUnknown.into())484 }485 }486487 pub fn collection_exists(collection_id: CollectionId) -> bool {488 <CollectionHandle<T>>::try_get(collection_id).is_ok()489 }490491 pub fn nft_exists(collection_id: CollectionId, nft_id: TokenId) -> bool {492 <TokenData<T>>::contains_key((collection_id, nft_id))493 }494495 pub fn get_collection_property(collection_id: CollectionId, key: RmrkProperty) -> Result<PropertyValue, DispatchError> {496 let collection_property = <PalletCommon<T>>::collection_properties(collection_id)497 .get(&Self::rmrk_property_key(key)?)498 .ok_or(<Error<T>>::CollectionUnknown)?499 .clone();500501 Ok(collection_property)502 }503504 pub fn get_collection_type(collection_id: CollectionId) -> Result<misc::CollectionType, DispatchError> {505 let value = Self::get_collection_property(collection_id, CollectionType)?;506507 let mut value = value.as_slice();508509 misc::CollectionType::decode(&mut value)510 .map_err(|_| <Error<T>>::CorruptedCollectionType.into())511 }512513 pub fn ensure_collection_type(collection_id: CollectionId, collection_type: misc::CollectionType) -> DispatchResult {514 let actual_type = Self::get_collection_type(collection_id)?;515 ensure!(actual_type == collection_type, <CommonError<T>>::NoPermission);516517 Ok(())518 }519520 pub fn get_nft_property(collection_id: CollectionId, nft_id: TokenId, key: RmrkProperty) -> Result<PropertyValue, DispatchError> {521 let nft_property = <PalletNft<T>>::token_properties((collection_id, nft_id))522 .get(&Self::rmrk_property_key(key)?)523 .ok_or(<Error<T>>::NoAvailableNftId)?524 .clone();525526 Ok(nft_property)527 }528529 pub fn get_nft_type(_collection_id: CollectionId, _token_id: TokenId) -> Result<NftType, DispatchError> {530 todo!("should get it from properties?")531 }532533 pub fn ensure_nft_type(collection_id: CollectionId, token_id: TokenId, nft_type: NftType) -> DispatchResult {534 let actual_type = Self::get_nft_type(collection_id, token_id)?;535 ensure!(actual_type == nft_type, <Error<T>>::NoPermission);536537 Ok(())538 }539540 pub fn ensure_nft_owner(541 collection_id: CollectionId,542 token_id: TokenId,543 possible_owner: &T::CrossAccountId544 ) -> DispatchResult {545 let token_data = <TokenData<T>>::get((collection_id, token_id))546 .ok_or(<Error<T>>::NoAvailableNftId)?;547548 ensure!(token_data.owner == *possible_owner, <Error<T>>::NoPermission);549550 Ok(())551 }552553 pub fn filter_user_properties<Key, Value, R, Mapper>(554 collection_id: CollectionId,555 token_id: Option<TokenId>,556 filter_keys: Option<Vec<RmrkPropertyKey>>,557 mapper: Mapper,558 ) -> Result<Vec<R>, DispatchError>559 where560 Key: TryFrom<RmrkPropertyKey> + AsRef<[u8]>,561 Value: Decode + Default,562 Mapper: Fn(Key, Value) -> R563 {564 filter_keys.map(|keys| {565 let properties = keys.into_iter()566 .filter_map(|key| {567 let key: Key = key.try_into().ok()?;568569 let value = match token_id {570 Some(token_id) => Self::get_nft_property(571 collection_id,572 token_id,573 UserProperty(key.as_ref())574 ),575 None => Self::get_collection_property(576 collection_id,577 UserProperty(key.as_ref())578 )579 }.ok()?.decode_or_default();580581 Some(mapper(key, value))582 })583 .collect();584585 Ok(properties)586 }).unwrap_or_else(|| {587 let properties = Self::iterate_user_properties(collection_id, token_id, mapper)?588 .collect();589590 Ok(properties)591 })592 }593594 pub fn iterate_user_properties<Key, Value, R, Mapper>(595 collection_id: CollectionId,596 token_id: Option<TokenId>,597 mapper: Mapper,598 ) -> Result<impl Iterator<Item=R>, DispatchError>599 where600 Key: TryFrom<RmrkPropertyKey> + AsRef<[u8]>,601 Value: Decode + Default,602 Mapper: Fn(Key, Value) -> R603 {604 let key_prefix = Self::rmrk_property_key(UserProperty(b""))?;605606 let properties = match token_id {607 Some(token_id) => <PalletNft<T>>::token_properties((collection_id, token_id)),608 None => <PalletCommon<T>>::collection_properties(collection_id)609 };610611 let properties = properties612 .into_iter()613 .filter_map(move |(key, value)| {614 let key = key.as_slice().strip_prefix(key_prefix.as_slice())?;615616 let key: Key = key.to_vec().try_into().ok()?;617 let value: Value = value.decode_or_default();618619 Some(mapper(key, value))620 });621622 Ok(properties)623 }624625 pub fn get_typed_nft_collection(626 collection_id: CollectionId,627 collection_type: misc::CollectionType628 ) -> Result<NonfungibleHandle<T>, DispatchError> {629 Self::ensure_collection_type(collection_id, collection_type)?;630631 Self::get_nft_collection(collection_id)632 }633634 fn map_common_err_to_proxy(err: DispatchError) -> DispatchError {635 map_common_err_to_proxy! {636 match err {637 NoPermission => NoPermission,638 CollectionTokenLimitExceeded => CollectionFullOrLocked,639 PublicMintingNotAllowed => NoPermission,640 TokenNotFound => NoAvailableNftId641 }642 }643 }644}pallets/refungible/src/common.rsdiffbeforeafterboth--- a/pallets/refungible/src/common.rs
+++ b/pallets/refungible/src/common.rs
@@ -205,15 +205,6 @@
)
}
- fn burn_item_unchecked(
- &self,
- owner: &T::CrossAccountId,
- token: TokenId,
- amount: u128,
- ) -> sp_runtime::DispatchResult {
- <Pallet<T>>::burn_item_unchecked(self, owner, token, amount)
- }
-
fn transfer(
&self,
from: T::CrossAccountId,
pallets/refungible/src/lib.rsdiffbeforeafterboth--- a/pallets/refungible/src/lib.rs
+++ b/pallets/refungible/src/lib.rs
@@ -245,25 +245,6 @@
token: TokenId,
amount: u128,
) -> DispatchResult {
- Self::burn_item_unchecked(collection, owner, token, amount)?;
-
- // TODO: ERC20 transfer event
- <PalletCommon<T>>::deposit_event(CommonEvent::ItemDestroyed(
- collection.id,
- token,
- owner.clone(),
- amount,
- ));
-
- Ok(())
- }
-
- pub fn burn_item_unchecked(
- collection: &RefungibleHandle<T>,
- owner: &T::CrossAccountId,
- token: TokenId,
- amount: u128,
- ) -> DispatchResult {
let total_supply = <TotalSupply<T>>::get((collection.id, token))
.checked_sub(amount)
.ok_or(<CommonError<T>>::TokenValueTooLow)?;
@@ -318,6 +299,13 @@
<Balance<T>>::insert((collection.id, token, owner), balance);
}
<TotalSupply<T>>::insert((collection.id, token), total_supply);
+ // TODO: ERC20 transfer event
+ <PalletCommon<T>>::deposit_event(CommonEvent::ItemDestroyed(
+ collection.id,
+ token,
+ owner.clone(),
+ amount,
+ ));
Ok(())
}
pallets/unique/src/lib.rsdiffbeforeafterboth--- a/pallets/unique/src/lib.rs
+++ b/pallets/unique/src/lib.rs
@@ -332,24 +332,15 @@
/// # Arguments
///
/// * collection_id: collection to destroy.
- #[weight =
- <SelfWeightOf<T>>::destroy_collection()
- + <SelfWeightOf<T>>::burn_children_in_collection(*max_children_to_burn)
- ]
+ #[weight = <SelfWeightOf<T>>::destroy_collection()]
#[transactional]
- pub fn destroy_collection(
- origin,
- collection_id: CollectionId,
- max_children_to_burn: u32,
- ) -> DispatchResult {
+ pub fn destroy_collection(origin, collection_id: CollectionId) -> DispatchResult {
let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);
let collection = <CollectionHandle<T>>::try_get(collection_id)?;
- let budget = budget::Value::new(max_children_to_burn);
-
// =========
- T::CollectionDispatch::destroy(sender, collection, &budget)?;
+ T::CollectionDispatch::destroy(sender, collection)?;
<NftTransferBasket<T>>::remove_prefix(collection_id, None);
<FungibleTransferBasket<T>>::remove_prefix(collection_id, None);
pallets/unique/src/weights.rsdiffbeforeafterboth--- a/pallets/unique/src/weights.rs
+++ b/pallets/unique/src/weights.rs
@@ -34,7 +34,6 @@
pub trait WeightInfo {
fn create_collection() -> Weight;
fn destroy_collection() -> Weight;
- fn burn_children_in_collection(max: u32) -> Weight;
fn add_to_allow_list() -> Weight;
fn remove_from_allow_list() -> Weight;
fn set_public_access_mode() -> Weight;
@@ -74,12 +73,6 @@
.saturating_add(T::DbWeight::get().reads(2 as Weight))
.saturating_add(T::DbWeight::get().writes(5 as Weight))
}
-
- fn burn_children_in_collection(max: u32) -> Weight {
- // TODO
- (50_000_000 as Weight).saturating_mul(max as Weight)
- }
-
// Storage: Common CollectionById (r:1 w:0)
// Storage: Common Allowlist (r:0 w:1)
fn add_to_allow_list() -> Weight {
@@ -199,12 +192,6 @@
.saturating_add(RocksDbWeight::get().reads(2 as Weight))
.saturating_add(RocksDbWeight::get().writes(5 as Weight))
}
-
- fn burn_children_in_collection(max: u32) -> Weight {
- // TODO
- (50_000_000 as Weight).saturating_mul(max as Weight)
- }
-
// Storage: Common CollectionById (r:1 w:0)
// Storage: Common Allowlist (r:0 w:1)
fn add_to_allow_list() -> Weight {
runtime/common/src/dispatch.rsdiffbeforeafterboth--- a/runtime/common/src/dispatch.rs
+++ b/runtime/common/src/dispatch.rs
@@ -1,4 +1,4 @@
-use frame_support::{dispatch::{DispatchResult}, ensure};
+use frame_support::{dispatch::DispatchResult, ensure};
use pallet_evm::PrecompileResult;
use sp_core::{H160, U256};
use sp_std::{borrow::ToOwned, vec::Vec};
@@ -12,7 +12,6 @@
use pallet_refungible::{Pallet as PalletRefungible, RefungibleHandle, erc::RefungibleTokenHandle};
use up_data_structs::{
CollectionMode, CreateCollectionData, MAX_DECIMAL_POINTS, mapping::TokenAddressMapping,
- budget::Budget,
};
pub enum CollectionDispatchT<T>
@@ -47,11 +46,7 @@
Ok(())
}
- fn destroy(
- sender: T::CrossAccountId,
- collection: CollectionHandle<T>,
- nesting_budget: &dyn Budget,
- ) -> DispatchResult {
+ fn destroy(sender: T::CrossAccountId, collection: CollectionHandle<T>) -> DispatchResult {
match collection.mode {
CollectionMode::ReFungible => {
PalletRefungible::destroy_collection(RefungibleHandle::cast(collection), &sender)?
@@ -60,11 +55,7 @@
PalletFungible::destroy_collection(FungibleHandle::cast(collection), &sender)?
}
CollectionMode::NFT => {
- PalletNonfungible::destroy_collection(
- NonfungibleHandle::cast(collection),
- &sender,
- nesting_budget,
- )?
+ PalletNonfungible::destroy_collection(NonfungibleHandle::cast(collection), &sender)?
}
}
Ok(())