difftreelog
CORE-410 Adapt to prop check root owner
in: master
3 files changed
pallets/refungible/src/common.rsdiffbeforeafterboth327 sender: T::CrossAccountId,327 sender: T::CrossAccountId,328 token_id: TokenId,328 token_id: TokenId,329 properties: Vec<Property>,329 properties: Vec<Property>,330 _nesting_budget: &dyn Budget,330 nesting_budget: &dyn Budget,331 ) -> DispatchResultWithPostInfo {331 ) -> DispatchResultWithPostInfo {332 let weight = <CommonWeights<T>>::set_token_properties(properties.len() as u32);332 let weight = <CommonWeights<T>>::set_token_properties(properties.len() as u32);333333334 with_weight(334 with_weight(335 <Pallet<T>>::set_token_properties(self, &sender, token_id, properties, false),335 <Pallet<T>>::set_token_properties(336 self,337 &sender,338 token_id,339 properties.into_iter(),340 false,341 nesting_budget,342 ),336 weight,343 weight,337 )344 )356 sender: T::CrossAccountId,363 sender: T::CrossAccountId,357 token_id: TokenId,364 token_id: TokenId,358 property_keys: Vec<PropertyKey>,365 property_keys: Vec<PropertyKey>,359 _nesting_budget: &dyn Budget,366 nesting_budget: &dyn Budget,360 ) -> DispatchResultWithPostInfo {367 ) -> DispatchResultWithPostInfo {361 let weight = <CommonWeights<T>>::delete_token_properties(property_keys.len() as u32);368 let weight = <CommonWeights<T>>::delete_token_properties(property_keys.len() as u32);362369363 with_weight(370 with_weight(364 <Pallet<T>>::delete_token_properties(self, &sender, token_id, property_keys),371 <Pallet<T>>::delete_token_properties(372 self,373 &sender,374 token_id,375 property_keys.into_iter(),376 nesting_budget,377 ),365 weight,378 weight,366 )379 )pallets/refungible/src/lib.rsdiffbeforeafterboth878788#![cfg_attr(not(feature = "std"), no_std)]88#![cfg_attr(not(feature = "std"), no_std)]898990use frame_support::{ensure, BoundedVec, transactional, storage::with_transaction};90use frame_support::{ensure, fail, BoundedVec, transactional, storage::with_transaction};91use up_data_structs::{91use up_data_structs::{92 AccessMode, CollectionId, CustomDataLimit, MAX_REFUNGIBLE_PIECES, TokenId,92 AccessMode, CollectionId, CustomDataLimit, MAX_REFUNGIBLE_PIECES, TokenId,93 CreateCollectionData, CreateRefungibleExData, mapping::TokenAddressMapping, budget::Budget,93 CreateCollectionData, CreateRefungibleExData, mapping::TokenAddressMapping, budget::Budget,94 Property, PropertyScope, TrySetProperty, PropertyKey, PropertyPermission, PropertyKeyPermission94 Property, PropertyScope, TrySetProperty, PropertyKey, PropertyValue, PropertyPermission,95 PropertyKeyPermission,95};96};96use pallet_evm::account::CrossAccountId;97use pallet_evm::account::CrossAccountId;97use pallet_common::{Error as CommonError, Event as CommonEvent, Pallet as PalletCommon, CommonCollectionOperations as _};98use pallet_common::{99 Error as CommonError, Event as CommonEvent, Pallet as PalletCommon,100 CommonCollectionOperations as _,101};98use pallet_structure::Pallet as PalletStructure;102use pallet_structure::Pallet as PalletStructure;99use sp_runtime::{ArithmeticError, DispatchError, DispatchResult, TransactionOutcome};103use sp_runtime::{ArithmeticError, DispatchError, DispatchResult, TransactionOutcome};466 Ok(())470 Ok(())467 }471 }468472473 #[transactional]469 pub fn set_token_property(474 fn modify_token_properties(470 collection: &RefungibleHandle<T>,475 collection: &RefungibleHandle<T>,471 sender: &T::CrossAccountId,476 sender: &T::CrossAccountId,472 token_id: TokenId,477 token_id: TokenId,473 property: Property,478 properties: impl Iterator<Item = (PropertyKey, Option<PropertyValue>)>,474 is_token_create: bool,479 is_token_create: bool,480 nesting_budget: &dyn Budget,475 ) -> DispatchResult {481 ) -> DispatchResult {482 let is_collection_admin = || collection.is_owner_or_admin(sender);483 let is_token_owner = || -> Result<bool, DispatchError> {484 let balance = collection.balance(sender.clone(), token_id);485 let total_pieces: u128 =476 Self::check_token_change_permission(486 Self::total_pieces(collection.id, token_id).unwrap_or(u128::MAX);477 collection,487 if balance != total_pieces {478 sender,488 return Ok(false);479 token_id,489 }480 &property.key,490481 is_token_create,491 let is_bundle_owner = <PalletStructure<T>>::check_indirectly_owned(492 sender.clone(),493 collection.id,494 token_id,495 None,496 nesting_budget,482 )?;497 )?;483498499 Ok(is_bundle_owner)500 };501502 for (key, value) in properties {503 let permission = <PalletCommon<T>>::property_permissions(collection.id)504 .get(&key)505 .cloned()506 .unwrap_or_else(PropertyPermission::none);507508 let is_property_exists = TokenProperties::<T>::get((collection.id, token_id))509 .get(&key)510 .is_some();511512 match permission {513 PropertyPermission { mutable: false, .. } if is_property_exists => {514 return Err(<CommonError<T>>::NoPermission.into());515 }516517 PropertyPermission {518 collection_admin,519 token_owner,520 ..521 } => {522 //TODO: investigate threats during public minting.523 let is_token_create =524 is_token_create && (collection_admin || token_owner) && value.is_some();525 if !(is_token_create526 || (collection_admin && is_collection_admin())527 || (token_owner && is_token_owner()?))528 {529 fail!(<CommonError<T>>::NoPermission);530 }531 }532 }533534 match value {535 Some(value) => {484 <TokenProperties<T>>::try_mutate((collection.id, token_id), |properties| {536 <TokenProperties<T>>::try_mutate((collection.id, token_id), |properties| {485 let property = property.clone();486 properties.try_set(property.key, property.value)537 properties.try_set(key.clone(), value)487 })538 })539 .map_err(<CommonError<T>>::from)?;540488 .map_err(<CommonError<T>>::from)?;541 <PalletCommon<T>>::deposit_event(CommonEvent::TokenPropertySet(489542 collection.id,490 <PalletCommon<T>>::deposit_event(CommonEvent::TokenPropertySet(543 token_id,491 collection.id,544 key,492 token_id,545 ));493 property.key,546 }494 ));547 None => {548 <TokenProperties<T>>::try_mutate((collection.id, token_id), |properties| {549 properties.remove(&key)550 })551 .map_err(<CommonError<T>>::from)?;552553 <PalletCommon<T>>::deposit_event(CommonEvent::TokenPropertyDeleted(554 collection.id,555 token_id,556 key,557 ));558 }559 }560 }495561496 Ok(())562 Ok(())497 }563 }498564499 #[transactional]500 pub fn set_token_properties(565 pub fn set_token_properties(501 collection: &RefungibleHandle<T>,566 collection: &RefungibleHandle<T>,502 sender: &T::CrossAccountId,567 sender: &T::CrossAccountId,503 token_id: TokenId,568 token_id: TokenId,504 properties: Vec<Property>,569 properties: impl Iterator<Item = Property>,505 is_token_create: bool,570 is_token_create: bool,571 nesting_budget: &dyn Budget,506 ) -> DispatchResult {572 ) -> DispatchResult {507 for property in properties {508 Self::set_token_property(collection, sender, token_id, property, is_token_create)?;573 Self::modify_token_properties(509 }574 collection,510575 sender,511 Ok(())576 token_id,577 properties.map(|p| (p.key, Some(p.value))),578 is_token_create,579 nesting_budget,580 )512 }581 }513582514 pub fn delete_token_property(583 pub fn set_token_property(515 collection: &RefungibleHandle<T>,584 collection: &RefungibleHandle<T>,516 sender: &T::CrossAccountId,585 sender: &T::CrossAccountId,517 token_id: TokenId,586 token_id: TokenId,518 property_key: PropertyKey,587 property: Property,588 nesting_budget: &dyn Budget,519 ) -> DispatchResult {589 ) -> DispatchResult {590 let is_token_create = false;591520 Self::check_token_change_permission(collection, sender, token_id, &property_key, false)?;592 Self::set_token_properties(521593 collection,522 <TokenProperties<T>>::try_mutate((collection.id, token_id), |properties| {594 sender,523 properties.remove(&property_key)595 token_id,524 })596 [property].into_iter(),525 .map_err(<CommonError<T>>::from)?;597 is_token_create,526598 nesting_budget,527 <PalletCommon<T>>::deposit_event(CommonEvent::TokenPropertyDeleted(599 )528 collection.id,529 token_id,530 property_key,531 ));532533 Ok(())534 }600 }535601536 fn check_token_change_permission(602 pub fn delete_token_properties(537 collection: &RefungibleHandle<T>,603 collection: &RefungibleHandle<T>,538 sender: &T::CrossAccountId,604 sender: &T::CrossAccountId,539 token_id: TokenId,605 token_id: TokenId,540 property_key: &PropertyKey,606 property_keys: impl Iterator<Item = PropertyKey>,541 is_token_create: bool,607 nesting_budget: &dyn Budget,542 ) -> DispatchResult {608 ) -> DispatchResult {543 let permission = <PalletCommon<T>>::property_permissions(collection.id)609 let is_token_create = false;544 .get(property_key)610545 .cloned()546 .unwrap_or_else(PropertyPermission::none);547548 // Not "try_fold" because total count of pieces is limited by 'MAX_REFUNGIBLE_PIECES'.549 let total_pieces: u128 = <Balance<T>>::iter_prefix((collection.id, token_id,)).fold(0, |total, piece| total + piece.1);550 let balance = collection.balance(sender.clone(), token_id);551552 let check_token_owner = || -> DispatchResult {553 ensure!(balance == total_pieces, <CommonError<T>>::NoPermission);554 Ok(())555 };556557 let is_property_exists = TokenProperties::<T>::get((collection.id, token_id))558 .get(property_key)559 .is_some();560561 match permission {562 PropertyPermission { mutable: false, .. } if is_property_exists => {563 Err(<CommonError<T>>::NoPermission.into())611 Self::modify_token_properties(564 }565566 PropertyPermission {567 collection_admin,612 collection,568 token_owner,613 sender,569 ..614 token_id,570 } => {571 //TODO: investigate threats during public minting.572 if is_token_create && (collection_admin || token_owner) {573 return Ok(());615 property_keys.into_iter().map(|key| (key, None)),574 }616 is_token_create,575617 nesting_budget,576 let mut check_result = Err(<CommonError<T>>::NoPermission.into());618 )577578 if collection_admin {579 check_result = collection.check_is_owner_or_admin(sender);580 }581582 if token_owner {583 check_result.or_else(|_| check_token_owner())584 } else {585 check_result586 }587 }588 }589 }619 }590620591 #[transactional]592 pub fn delete_token_properties(621 pub fn delete_token_property(593 collection: &RefungibleHandle<T>,622 collection: &RefungibleHandle<T>,594 sender: &T::CrossAccountId,623 sender: &T::CrossAccountId,595 token_id: TokenId,624 token_id: TokenId,596 property_keys: Vec<PropertyKey>,625 property_key: PropertyKey,626 nesting_budget: &dyn Budget,597 ) -> DispatchResult {627 ) -> DispatchResult {598 for key in property_keys {599 Self::delete_token_property(collection, sender, token_id, key)?;628 Self::delete_token_properties(600 }629 collection,601630 sender,602 Ok(())631 token_id,632 [property_key].into_iter(),633 nesting_budget,634 )603 }635 }604636833 collection,865 collection,834 sender,866 sender,835 TokenId(token_id),867 TokenId(token_id),836 data.properties.clone().into_inner(),868 data.properties.clone().into_iter(),837 true,869 true,870 nesting_budget,838 ) {871 ) {839 return TransactionOutcome::Rollback(Err(e));872 return TransactionOutcome::Rollback(Err(e));840 }873 }1049 );1082 );1050 ensure!(amount > 0, <CommonError<T>>::TokenValueTooLow);1083 ensure!(amount > 0, <CommonError<T>>::TokenValueTooLow);1051 // Ensure user owns all pieces1084 // Ensure user owns all pieces1052 let total_supply = <TotalSupply<T>>::get((collection.id, token));1085 let total_pieces = Self::total_pieces(collection.id, token).unwrap_or(u128::MAX);1053 let balance = <Balance<T>>::get((collection.id, token, owner));1086 let balance = <Balance<T>>::get((collection.id, token, owner));1054 ensure!(1087 ensure!(1055 total_supply == balance,1088 total_pieces == balance,1056 <Error<T>>::RepartitionWhileNotOwningAllPieces1089 <Error<T>>::RepartitionWhileNotOwningAllPieces1057 );1090 );10581091primitives/data-structs/src/lib.rsdiffbeforeafterbothno syntactic changes