difftreelog
feat burn children when destroying a collection
in: master
12 files changed
pallets/common/src/dispatch.rsdiffbeforeafterboth6 weights::Pays,6 weights::Pays,7 traits::Get,7 traits::Get,8};8};9use up_data_structs::{CollectionId, CreateCollectionData};9use up_data_structs::{CollectionId, CreateCollectionData, budget::Budget};101011use crate::{pallet::Config, CommonCollectionOperations, CollectionHandle};11use crate::{pallet::Config, CommonCollectionOperations, CollectionHandle};121259 fn create(sender: T::AccountId, data: CreateCollectionData<T::AccountId>) -> DispatchResult;59 fn create(sender: T::AccountId, data: CreateCollectionData<T::AccountId>) -> DispatchResult;60 fn destroy(sender: T::CrossAccountId, handle: CollectionHandle<T>) -> DispatchResult;60 fn destroy(61 sender: T::CrossAccountId,62 handle: CollectionHandle<T>,63 nesting_budget: &dyn Budget,64 ) -> DispatchResult;616562 fn dispatch(handle: CollectionHandle<T>) -> Self;66 fn dispatch(handle: CollectionHandle<T>) -> Self;pallets/common/src/lib.rsdiffbeforeafterboth1169 token: TokenId,1169 token: TokenId,1170 amount: u128,1170 amount: u128,1171 ) -> DispatchResultWithPostInfo;1171 ) -> DispatchResultWithPostInfo;1172 fn burn_item_unchecked(1173 &self,1174 owner: &T::CrossAccountId,1175 token: TokenId,1176 amount: u128,1177 ) -> DispatchResult;1172 fn set_collection_properties(1178 fn set_collection_properties(1173 &self,1179 &self,1174 sender: T::CrossAccountId,1180 sender: T::CrossAccountId,pallets/fungible/src/common.rsdiffbeforeafterboth170 )170 )171 }171 }172173 fn burn_item_unchecked(174 &self,175 owner: &T::CrossAccountId,176 _token: TokenId,177 amount: u128,178 ) -> sp_runtime::DispatchResult {179 <Pallet<T>>::burn_item_unchecked(self, owner, amount)?;180181 Ok(())182 }172183173 fn transfer(184 fn transfer(174 &self,185 &self,pallets/fungible/src/lib.rsdiffbeforeafterboth155 Ok(())155 Ok(())156 }156 }157158 pub fn burn(159 collection: &FungibleHandle<T>,160 owner: &T::CrossAccountId,161 amount: u128,162 ) -> DispatchResult {163 if collection.access == AccessMode::AllowList {164 collection.check_allowlist(owner)?;165 }166167 // =========168169 Self::burn_item_unchecked(collection, owner, amount)?;170171 <PalletEvm<T>>::deposit_log(172 ERC20Events::Transfer {173 from: *owner.as_eth(),174 to: H160::default(),175 value: amount.into(),176 }177 .to_log(collection_id_to_address(collection.id)),178 );179 <PalletCommon<T>>::deposit_event(CommonEvent::ItemDestroyed(180 collection.id,181 TokenId::default(),182 owner.clone(),183 amount,184 ));185 Ok(())186 }157187158 pub fn burn(188 pub fn burn_item_unchecked(159 collection: &FungibleHandle<T>,189 collection: &FungibleHandle<T>,160 owner: &T::CrossAccountId,190 owner: &T::CrossAccountId,161 amount: u128,191 amount: u128,186 }216 }187 <TotalSupply<T>>::insert(collection.id, total_supply);217 <TotalSupply<T>>::insert(collection.id, total_supply);188218189 <PalletEvm<T>>::deposit_log(190 ERC20Events::Transfer {191 from: *owner.as_eth(),192 to: H160::default(),193 value: amount.into(),194 }195 .to_log(collection_id_to_address(collection.id)),196 );197 <PalletCommon<T>>::deposit_event(CommonEvent::ItemDestroyed(198 collection.id,199 TokenId::default(),200 owner.clone(),201 amount,202 ));203 Ok(())219 Ok(())204 }220 }205221pallets/nonfungible/src/common.rsdiffbeforeafterboth264 }264 }265 }265 }266267 fn burn_item_unchecked(268 &self,269 owner:& T::CrossAccountId,270 token: TokenId,271 amount: u128,272 ) -> sp_runtime::DispatchResult {273 if amount == 1 {274 <Pallet<T>>::burn_item_unchecked(self, owner, token)275 } else {276 Ok(())277 }278 }266279267 fn transfer(280 fn transfer(268 &self,281 &self,pallets/nonfungible/src/lib.rsdiffbeforeafterboth27use pallet_evm::{account::CrossAccountId, Pallet as PalletEvm};27use pallet_evm::{account::CrossAccountId, Pallet as PalletEvm};28use pallet_common::{28use pallet_common::{29 Error as CommonError, Pallet as PalletCommon, Event as CommonEvent, CollectionHandle,29 Error as CommonError, Pallet as PalletCommon, Event as CommonEvent, CollectionHandle,30 dispatch::CollectionDispatch,30 eth::collection_id_to_address,31 eth::collection_id_to_address,31};32};32use pallet_structure::Pallet as PalletStructure;33use pallet_structure::Pallet as PalletStructure;79 NonfungibleItemsHaveNoAmount,80 NonfungibleItemsHaveNoAmount,80 /// Unable to burn NFT with children81 /// Unable to burn NFT with children81 CantBurnNftWithChildren,82 CantBurnNftWithChildren,83 /// Too many children to burn when destroying a collection84 TooManyChildrenToBurn,82 }85 }838684 #[pallet::config]87 #[pallet::config]290 pub fn destroy_collection(293 pub fn destroy_collection(291 collection: NonfungibleHandle<T>,294 collection: NonfungibleHandle<T>,292 sender: &T::CrossAccountId,295 sender: &T::CrossAccountId,296 nesting_budget: &dyn Budget,293 ) -> DispatchResult {297 ) -> DispatchResult {294 let id = collection.id;298 let id = collection.id;295299296 // =========300 // =========297301302 Self::burn_children_in_collection(id, nesting_budget)?;298 PalletCommon::destroy_collection(collection.0, sender)?;303 PalletCommon::destroy_collection(collection.0, sender)?;299300 <TokenData<T>>::remove_prefix((id,), None);304 <TokenData<T>>::remove_prefix((id,), None);307 Ok(())311 Ok(())308 }312 }313314 #[transactional]315 fn burn_children_in_collection(collection_id: CollectionId, nesting_budget: &dyn Budget) -> DispatchResult {316 for (parent_id, child) in <TokenChildren<T>>::drain_prefix((collection_id,))317 .map(|((parent_id, child), _)| (parent_id, child)) {318319 let parent_address = T::CrossTokenAddressMapping::token_to_address(collection_id, parent_id);320 Self::burn_tree(parent_address, child.0, child.1, nesting_budget)?;321 }322323 Ok(())324 }325326 fn burn_tree(327 parent: T::CrossAccountId,328 collection_id: CollectionId,329 token_id: TokenId,330 nesting_budget: &dyn Budget331 ) -> DispatchResult {332 if !nesting_budget.consume() {333 return Err(<Error<T>>::TooManyChildrenToBurn.into());334 }335336 let handle = <CollectionHandle<T>>::try_get(collection_id)?;337 let handle = T::CollectionDispatch::dispatch(handle);338 let handle = handle.as_dyn();339340 let amount = handle.balance(parent.clone(), token_id);341342 handle.burn_item_unchecked(&parent, token_id, amount)?;343344 for child in <TokenChildren<T>>::drain_prefix((collection_id, token_id)).map(|(child, _)| child) {345 let parent = T::CrossTokenAddressMapping::token_to_address(collection_id, token_id);346 Self::burn_tree(parent, child.0, child.1, nesting_budget)?;347 }348349 Ok(())350 }309351310 pub fn burn(352 pub fn burn(311 collection: &NonfungibleHandle<T>,353 collection: &NonfungibleHandle<T>,328 return Err(<Error<T>>::CantBurnNftWithChildren.into());370 return Err(<Error<T>>::CantBurnNftWithChildren.into());329 }371 }330372331 let burnt = <TokensBurnt<T>>::get(collection.id)373 let old_spender = <Allowance<T>>::get((collection.id, token));332 .checked_add(1)333 .ok_or(ArithmeticError::Overflow)?;334335 let balance = <AccountBalance<T>>::get((collection.id, token_data.owner.clone()))336 .checked_sub(1)337 .ok_or(ArithmeticError::Overflow)?;338339 if balance == 0 {340 <AccountBalance<T>>::remove((collection.id, token_data.owner.clone()));341 } else {342 <AccountBalance<T>>::insert((collection.id, token_data.owner.clone()), balance);343 }344345 if let Some(owner) = T::CrossTokenAddressMapping::address_to_token(&token_data.owner) {346 Self::unnest(owner, (collection.id, token));347 }348374349 // =========375 // =========350376351 <Owned<T>>::remove((collection.id, &token_data.owner, token));377 Self::burn_item_unchecked(collection, &token_data.owner, token)?;352 <TokensBurnt<T>>::insert(collection.id, burnt);353 <TokenData<T>>::remove((collection.id, token));354 <TokenProperties<T>>::remove((collection.id, token));355 let old_spender = <Allowance<T>>::take((collection.id, token));356378357 if let Some(old_spender) = old_spender {379 if let Some(old_spender) = old_spender {358 <PalletCommon<T>>::deposit_event(CommonEvent::Approved(380 <PalletCommon<T>>::deposit_event(CommonEvent::Approved(381 Ok(())403 Ok(())382 }404 }405406 pub fn burn_item_unchecked(407 collection: &NonfungibleHandle<T>,408 owner: &T::CrossAccountId,409 token: TokenId,410 ) -> DispatchResult {411 let burnt = <TokensBurnt<T>>::get(collection.id)412 .checked_add(1)413 .ok_or(ArithmeticError::Overflow)?;414415 let balance = <AccountBalance<T>>::get((collection.id, owner.clone()))416 .checked_sub(1)417 .ok_or(ArithmeticError::Overflow)?;418419 // =========420421 if let Some(owner) = T::CrossTokenAddressMapping::address_to_token(owner) {422 Self::unnest(owner, (collection.id, token));423 }424425 if balance == 0 {426 <AccountBalance<T>>::remove((collection.id, owner.clone()));427 } else {428 <AccountBalance<T>>::insert((collection.id, owner.clone()), balance);429 }430431 <Owned<T>>::remove((collection.id, owner, token));432 <TokensBurnt<T>>::insert(collection.id, burnt);433 <TokenData<T>>::remove((collection.id, token));434 <TokenProperties<T>>::remove((collection.id, token));435 <Allowance<T>>::remove((collection.id, token));436437 Ok(())438 }383439384 pub fn set_token_property(440 pub fn set_token_property(385 collection: &NonfungibleHandle<T>,441 collection: &NonfungibleHandle<T>,pallets/proxy-rmrk-core/src/lib.rsdiffbeforeafterboth179179180 ensure!(collection.total_supply() == 0, <Error<T>>::CollectionNotEmpty);180 ensure!(collection.total_supply() == 0, <Error<T>>::CollectionNotEmpty);181181182 let empty_budget = budget::Value::new(0);182 <PalletNft<T>>::destroy_collection(collection, &cross_sender)183 <PalletNft<T>>::destroy_collection(collection, &cross_sender, &empty_budget)183 .map_err(Self::map_common_err_to_proxy)?;184 .map_err(Self::map_common_err_to_proxy)?;184185185 Self::deposit_event(Event::CollectionDestroyed { issuer: sender, collection_id });186 Self::deposit_event(Event::CollectionDestroyed { issuer: sender, collection_id });pallets/refungible/src/common.rsdiffbeforeafterboth205 )205 )206 }206 }207208 fn burn_item_unchecked(209 &self,210 owner: &T::CrossAccountId,211 token: TokenId,212 amount: u128,213 ) -> sp_runtime::DispatchResult {214 <Pallet<T>>::burn_item_unchecked(self, owner, token, amount)215 }207216208 fn transfer(217 fn transfer(209 &self,218 &self,pallets/refungible/src/lib.rsdiffbeforeafterboth239 Ok(())239 Ok(())240 }240 }241242 pub fn burn(243 collection: &RefungibleHandle<T>,244 owner: &T::CrossAccountId,245 token: TokenId,246 amount: u128,247 ) -> DispatchResult {248 Self::burn_item_unchecked(collection, owner, token, amount)?;249250 // TODO: ERC20 transfer event251 <PalletCommon<T>>::deposit_event(CommonEvent::ItemDestroyed(252 collection.id,253 token,254 owner.clone(),255 amount,256 ));257258 Ok(())259 }241260242 pub fn burn(261 pub fn burn_item_unchecked(243 collection: &RefungibleHandle<T>,262 collection: &RefungibleHandle<T>,244 owner: &T::CrossAccountId,263 owner: &T::CrossAccountId,245 token: TokenId,264 token: TokenId,299 <Balance<T>>::insert((collection.id, token, owner), balance);318 <Balance<T>>::insert((collection.id, token, owner), balance);300 }319 }301 <TotalSupply<T>>::insert((collection.id, token), total_supply);320 <TotalSupply<T>>::insert((collection.id, token), total_supply);302 // TODO: ERC20 transfer event303 <PalletCommon<T>>::deposit_event(CommonEvent::ItemDestroyed(304 collection.id,305 token,306 owner.clone(),307 amount,308 ));309 Ok(())321 Ok(())310 }322 }311323pallets/unique/src/lib.rsdiffbeforeafterboth334 /// * collection_id: collection to destroy.334 /// * collection_id: collection to destroy.335 #[weight = <SelfWeightOf<T>>::destroy_collection()]335 #[weight =336 <SelfWeightOf<T>>::destroy_collection()337 + <SelfWeightOf<T>>::burn_children_in_collection(*max_children_to_burn)338 ]336 #[transactional]339 #[transactional]337 pub fn destroy_collection(origin, collection_id: CollectionId) -> DispatchResult {340 pub fn destroy_collection(341 origin,342 collection_id: CollectionId,343 max_children_to_burn: u32,344 ) -> DispatchResult {338 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);345 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);339 let collection = <CollectionHandle<T>>::try_get(collection_id)?;346 let collection = <CollectionHandle<T>>::try_get(collection_id)?;347348 let budget = budget::Value::new(max_children_to_burn);340349341 // =========350 // =========342351343 T::CollectionDispatch::destroy(sender, collection)?;352 T::CollectionDispatch::destroy(sender, collection, &budget)?;344353345 <NftTransferBasket<T>>::remove_prefix(collection_id, None);354 <NftTransferBasket<T>>::remove_prefix(collection_id, None);346 <FungibleTransferBasket<T>>::remove_prefix(collection_id, None);355 <FungibleTransferBasket<T>>::remove_prefix(collection_id, None);pallets/unique/src/weights.rsdiffbeforeafterboth34pub trait WeightInfo {34pub trait WeightInfo {35 fn create_collection() -> Weight;35 fn create_collection() -> Weight;36 fn destroy_collection() -> Weight;36 fn destroy_collection() -> Weight;37 fn burn_children_in_collection(max: u32) -> Weight;37 fn add_to_allow_list() -> Weight;38 fn add_to_allow_list() -> Weight;38 fn remove_from_allow_list() -> Weight;39 fn remove_from_allow_list() -> Weight;39 fn set_public_access_mode() -> Weight;40 fn set_public_access_mode() -> Weight;74 .saturating_add(T::DbWeight::get().writes(5 as Weight))75 .saturating_add(T::DbWeight::get().writes(5 as Weight))75 }76 }7778 fn burn_children_in_collection(max: u32) -> Weight {79 // TODO80 (50_000_000 as Weight).saturating_mul(max as Weight)81 }8276 // Storage: Common CollectionById (r:1 w:0)83 // Storage: Common CollectionById (r:1 w:0)77 // Storage: Common Allowlist (r:0 w:1)84 // Storage: Common Allowlist (r:0 w:1)193 .saturating_add(RocksDbWeight::get().writes(5 as Weight))200 .saturating_add(RocksDbWeight::get().writes(5 as Weight))194 }201 }202203 fn burn_children_in_collection(max: u32) -> Weight {204 // TODO205 (50_000_000 as Weight).saturating_mul(max as Weight)206 }207195 // Storage: Common CollectionById (r:1 w:0)208 // Storage: Common CollectionById (r:1 w:0)196 // Storage: Common Allowlist (r:0 w:1)209 // Storage: Common Allowlist (r:0 w:1)runtime/common/src/dispatch.rsdiffbeforeafterboth1use frame_support::{dispatch::DispatchResult, ensure};1use frame_support::{dispatch::{DispatchResult}, ensure};2use pallet_evm::PrecompileResult;2use pallet_evm::PrecompileResult;3use sp_core::{H160, U256};3use sp_core::{H160, U256};4use sp_std::{borrow::ToOwned, vec::Vec};4use sp_std::{borrow::ToOwned, vec::Vec};12use pallet_refungible::{Pallet as PalletRefungible, RefungibleHandle, erc::RefungibleTokenHandle};12use pallet_refungible::{Pallet as PalletRefungible, RefungibleHandle, erc::RefungibleTokenHandle};13use up_data_structs::{13use up_data_structs::{14 CollectionMode, CreateCollectionData, MAX_DECIMAL_POINTS, mapping::TokenAddressMapping,14 CollectionMode, CreateCollectionData, MAX_DECIMAL_POINTS, mapping::TokenAddressMapping,15 budget::Budget,15};16};161717pub enum CollectionDispatchT<T>18pub enum CollectionDispatchT<T>484949 fn destroy(sender: T::CrossAccountId, collection: CollectionHandle<T>) -> DispatchResult {50 fn destroy(51 sender: T::CrossAccountId,52 collection: CollectionHandle<T>,53 nesting_budget: &dyn Budget,54 ) -> DispatchResult {50 match collection.mode {55 match collection.mode {51 CollectionMode::ReFungible => {56 CollectionMode::ReFungible => {57 CollectionMode::NFT => {62 CollectionMode::NFT => {58 PalletNonfungible::destroy_collection(NonfungibleHandle::cast(collection), &sender)?63 PalletNonfungible::destroy_collection(64 NonfungibleHandle::cast(collection),65 &sender,66 nesting_budget,67 )?59 }68 }60 }69 }