From 42e0b55cf097d28904d23585caae74aa80122e6e Mon Sep 17 00:00:00 2001 From: iorveth Date: Fri, 25 Jun 2021 17:18:59 +0300 Subject: [PATCH 1/3] Uniques pallet: implement set_attribute & set_class_attribute nonfungibles trait functions --- frame/uniques/src/functions.rs | 45 ++++++++++++++- frame/uniques/src/impl_nonfungibles.rs | 39 ++++++++++++- frame/uniques/src/lib.rs | 78 +++++++++++--------------- 3 files changed, 114 insertions(+), 48 deletions(-) diff --git a/frame/uniques/src/functions.rs b/frame/uniques/src/functions.rs index 28ff5ac6a7033..0cc6a3cc3ca31 100644 --- a/frame/uniques/src/functions.rs +++ b/frame/uniques/src/functions.rs @@ -18,7 +18,7 @@ //! Various pieces of common functionality. use super::*; -use frame_support::{ensure, traits::Get}; +use frame_support::{ensure, traits::Get, BoundedVec}; use sp_runtime::{DispatchResult, DispatchError}; impl, I: 'static> Pallet { @@ -112,4 +112,47 @@ impl, I: 'static> Pallet { Self::deposit_event(Event::Burned(class, instance, owner)); Ok(()) } + + pub(super) fn do_set_attribute( + class: T::ClassId, + maybe_instance: Option, + maybe_check_owner: &Option, + key: BoundedVec, + value: BoundedVec, + with_details: impl FnOnce(&ClassDetailsFor) -> DispatchResult, + ) -> DispatchResult { + let mut class_details = Class::::get(&class).ok_or(Error::::Unknown)?; + with_details(&class_details)?; + + let maybe_is_frozen = match maybe_instance { + None => ClassMetadataOf::::get(class).map(|v| v.is_frozen), + Some(instance) => InstanceMetadataOf::::get(class, instance).map(|v| v.is_frozen), + }; + ensure!(!maybe_is_frozen.unwrap_or(false), Error::::Frozen); + + let attribute = Attribute::::get((class, maybe_instance, &key)); + if attribute.is_none() { + class_details.attributes.saturating_inc(); + } + let old_deposit = attribute.map_or(Zero::zero(), |m| m.1); + class_details.total_deposit.saturating_reduce(old_deposit); + let mut deposit = Zero::zero(); + if !class_details.free_holding && maybe_check_owner.is_some() { + deposit = T::DepositPerByte::get() + .saturating_mul(((key.len() + value.len()) as u32).into()) + .saturating_add(T::AttributeDepositBase::get()); + } + class_details.total_deposit.saturating_accrue(deposit); + if deposit > old_deposit { + T::Currency::reserve(&class_details.owner, deposit - old_deposit)?; + } else if deposit < old_deposit { + T::Currency::unreserve(&class_details.owner, old_deposit - deposit); + } + + Attribute::::insert((&class, maybe_instance, &key), (&value, deposit)); + Class::::insert(class, &class_details); + + Self::deposit_event(Event::AttributeSet(class, maybe_instance, key, value)); + Ok(()) + } } diff --git a/frame/uniques/src/impl_nonfungibles.rs b/frame/uniques/src/impl_nonfungibles.rs index c856e2cc5588b..70e641a4dd98a 100644 --- a/frame/uniques/src/impl_nonfungibles.rs +++ b/frame/uniques/src/impl_nonfungibles.rs @@ -18,7 +18,7 @@ //! Implementations for `nonfungibles` traits. use super::*; -use sp_std::convert::TryFrom; +use sp_std::convert::{TryFrom, TryInto}; use frame_support::traits::tokens::nonfungibles::{Inspect, Mutate, Transfer}; use frame_support::BoundedSlice; use sp_runtime::DispatchResult; @@ -95,6 +95,43 @@ impl, I: 'static> Mutate<::AccountId> for Pallet fn burn_from(class: &Self::ClassId, instance: &Self::InstanceId) -> DispatchResult { Self::do_burn(class.clone(), instance.clone(), |_, _| Ok(())) } + + fn set_attribute( + class: &Self::ClassId, + instance: &Self::InstanceId, + key: &[u8], + value: &[u8], + ) -> DispatchResult { + let bounded_key = key.to_vec().try_into().map_err(|_| Error::::KeyUpperBoundExceeded)?; + let bounded_value = value.to_vec().try_into().map_err(|_| Error::::ValueUpperBoundExceeded)?; + + Self::do_set_attribute( + class.clone(), + Some(instance.clone()), + &None, + bounded_key, + bounded_value, + |_| Ok(()), + ) + } + + fn set_class_attribute( + class: &Self::ClassId, + key: &[u8], + value: &[u8], + ) -> DispatchResult { + let bounded_key = key.to_vec().try_into().map_err(|_| Error::::KeyUpperBoundExceeded)?; + let bounded_value = value.to_vec().try_into().map_err(|_| Error::::ValueUpperBoundExceeded)?; + + Self::do_set_attribute( + class.clone(), + None, + &None, + bounded_key, + bounded_value, + |_| Ok(()), + ) + } } impl, I: 'static> Transfer for Pallet { diff --git a/frame/uniques/src/lib.rs b/frame/uniques/src/lib.rs index 70a9e58d7bfa7..ec8c5858096a7 100644 --- a/frame/uniques/src/lib.rs +++ b/frame/uniques/src/lib.rs @@ -266,6 +266,10 @@ pub mod pallet { NoDelegate, /// No approval exists that would allow the transfer. Unapproved, + /// Attribute key upper bound exceeded. + KeyUpperBoundExceeded, + /// Attribute value upper bound exceeded. + ValueUpperBoundExceeded, } #[pallet::hooks] @@ -927,52 +931,34 @@ pub mod pallet { /// /// Weight: `O(1)` #[pallet::weight(T::WeightInfo::set_attribute())] - pub fn set_attribute( - origin: OriginFor, - #[pallet::compact] class: T::ClassId, - maybe_instance: Option, - key: BoundedVec, - value: BoundedVec, - ) -> DispatchResult { - let maybe_check_owner = T::ForceOrigin::try_origin(origin) - .map(|_| None) - .or_else(|origin| ensure_signed(origin).map(Some))?; - - let mut class_details = Class::::get(&class).ok_or(Error::::Unknown)?; - if let Some(check_owner) = &maybe_check_owner { - ensure!(check_owner == &class_details.owner, Error::::NoPermission); - } - let maybe_is_frozen = match maybe_instance { - None => ClassMetadataOf::::get(class).map(|v| v.is_frozen), - Some(instance) => - InstanceMetadataOf::::get(class, instance).map(|v| v.is_frozen), - }; - ensure!(!maybe_is_frozen.unwrap_or(false), Error::::Frozen); - - let attribute = Attribute::::get((class, maybe_instance, &key)); - if attribute.is_none() { - class_details.attributes.saturating_inc(); - } - let old_deposit = attribute.map_or(Zero::zero(), |m| m.1); - class_details.total_deposit.saturating_reduce(old_deposit); - let mut deposit = Zero::zero(); - if !class_details.free_holding && maybe_check_owner.is_some() { - deposit = T::DepositPerByte::get() - .saturating_mul(((key.len() + value.len()) as u32).into()) - .saturating_add(T::AttributeDepositBase::get()); - } - class_details.total_deposit.saturating_accrue(deposit); - if deposit > old_deposit { - T::Currency::reserve(&class_details.owner, deposit - old_deposit)?; - } else if deposit < old_deposit { - T::Currency::unreserve(&class_details.owner, old_deposit - deposit); - } - - Attribute::::insert((&class, maybe_instance, &key), (&value, deposit)); - Class::::insert(class, &class_details); - Self::deposit_event(Event::AttributeSet(class, maybe_instance, key, value)); - Ok(()) - } + pub fn set_attribute( + origin: OriginFor, + #[pallet::compact] class: T::ClassId, + maybe_instance: Option, + key: BoundedVec, + value: BoundedVec, + ) -> DispatchResult { + let maybe_check_owner = T::ForceOrigin::try_origin(origin) + .map(|_| None) + .or_else(|origin| ensure_signed(origin).map(Some))?; + + Self::do_set_attribute( + class, + maybe_instance, + &maybe_check_owner, + key, + value, + |class_details| { + if let Some(check_owner) = &maybe_check_owner { + ensure!( + check_owner == &class_details.owner, + Error::::NoPermission + ); + } + Ok(()) + }, + ) + } /// Set an attribute for an asset class or instance. /// From eb6924d7ebd82ed63a131c684ab00907a682246e Mon Sep 17 00:00:00 2001 From: iorveth Date: Thu, 29 Jul 2021 14:25:54 +0300 Subject: [PATCH 2/3] Uniques pallet: fix whitespaces formatting --- frame/uniques/src/impl_nonfungibles.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frame/uniques/src/impl_nonfungibles.rs b/frame/uniques/src/impl_nonfungibles.rs index 70e641a4dd98a..a0fa4c2dfd134 100644 --- a/frame/uniques/src/impl_nonfungibles.rs +++ b/frame/uniques/src/impl_nonfungibles.rs @@ -115,7 +115,7 @@ impl, I: 'static> Mutate<::AccountId> for Pallet ) } - fn set_class_attribute( + fn set_class_attribute( class: &Self::ClassId, key: &[u8], value: &[u8], From 6fabf252387b41d081b849eab6acff64b060d253 Mon Sep 17 00:00:00 2001 From: iorveth Date: Thu, 29 Jul 2021 14:32:17 +0300 Subject: [PATCH 3/3] Uniques pallet: refactoring --- frame/uniques/src/functions.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/frame/uniques/src/functions.rs b/frame/uniques/src/functions.rs index 0cc6a3cc3ca31..9e01f90048a00 100644 --- a/frame/uniques/src/functions.rs +++ b/frame/uniques/src/functions.rs @@ -139,14 +139,14 @@ impl, I: 'static> Pallet { let mut deposit = Zero::zero(); if !class_details.free_holding && maybe_check_owner.is_some() { deposit = T::DepositPerByte::get() - .saturating_mul(((key.len() + value.len()) as u32).into()) + .saturating_mul((key.len().saturating_add(value.len()) as u32).into()) .saturating_add(T::AttributeDepositBase::get()); } class_details.total_deposit.saturating_accrue(deposit); if deposit > old_deposit { - T::Currency::reserve(&class_details.owner, deposit - old_deposit)?; + T::Currency::reserve(&class_details.owner, deposit.saturating_sub(old_deposit))?; } else if deposit < old_deposit { - T::Currency::unreserve(&class_details.owner, old_deposit - deposit); + T::Currency::unreserve(&class_details.owner, old_deposit.saturating_sub(deposit)); } Attribute::::insert((&class, maybe_instance, &key), (&value, deposit));