git.delta.rocks / unique-network / refs/commits / 0427b9aac8a2

difftreelog

CORE-410 Adapt to prop check root owner

Trubnikov Sergey2022-07-07parent: #e574f04.patch.diff
in: master

3 files changed

modifiedpallets/refungible/src/common.rsdiffbeforeafterboth
327 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);
333333
334 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);
362369
363 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 )
modifiedpallets/refungible/src/lib.rsdiffbeforeafterboth
8787
88#![cfg_attr(not(feature = "std"), no_std)]88#![cfg_attr(not(feature = "std"), no_std)]
8989
90use 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 }
468472
473 #[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,490
481 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 )?;
483498
499 Ok(is_bundle_owner)
500 };
501
502 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);
507
508 let is_property_exists = TokenProperties::<T>::get((collection.id, token_id))
509 .get(&key)
510 .is_some();
511
512 match permission {
513 PropertyPermission { mutable: false, .. } if is_property_exists => {
514 return Err(<CommonError<T>>::NoPermission.into());
515 }
516
517 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_create
526 || (collection_admin && is_collection_admin())
527 || (token_owner && is_token_owner()?))
528 {
529 fail!(<CommonError<T>>::NoPermission);
530 }
531 }
532 }
533
534 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)?;
540
488 .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)?;
552
553 <PalletCommon<T>>::deposit_event(CommonEvent::TokenPropertyDeleted(
554 collection.id,
555 token_id,
556 key,
557 ));
558 }
559 }
560 }
495561
496 Ok(())562 Ok(())
497 }563 }
498564
499 #[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 }
513582
514 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;
591
520 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 ));
532
533 Ok(())
534 }600 }
535601
536 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)610
545 .cloned()
546 .unwrap_or_else(PropertyPermission::none);
547
548 // 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);
551
552 let check_token_owner = || -> DispatchResult {
553 ensure!(balance == total_pieces, <CommonError<T>>::NoPermission);
554 Ok(())
555 };
556
557 let is_property_exists = TokenProperties::<T>::get((collection.id, token_id))
558 .get(property_key)
559 .is_some();
560
561 match permission {
562 PropertyPermission { mutable: false, .. } if is_property_exists => {
563 Err(<CommonError<T>>::NoPermission.into())611 Self::modify_token_properties(
564 }
565
566 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 )
577
578 if collection_admin {
579 check_result = collection.check_is_owner_or_admin(sender);
580 }
581
582 if token_owner {
583 check_result.or_else(|_| check_token_owner())
584 } else {
585 check_result
586 }
587 }
588 }
589 }619 }
590620
591 #[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 }
604636
833 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 pieces
1052 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>>::RepartitionWhileNotOwningAllPieces
1057 );1090 );
10581091
modifiedprimitives/data-structs/src/lib.rsdiffbeforeafterboth

no syntactic changes