difftreelog
refactor(pallet-refungible) disallow invalid bulk mints
in: master
`create_multiple_items_ex` was allowing invalid (that will be always rejected at runtime level) refungible mint extrinsics, by passing multiple users into `RefungibleMultipleItems` call.
5 files changed
pallets/refungible/Cargo.tomldiffbeforeafterboth28sp-core = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.24" }28sp-core = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.24" }29sp-runtime = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.24" }29sp-runtime = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.24" }30sp-std = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.24" }30sp-std = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.24" }31derivative = { version = "2.2.0", features = ["use_core"] }313232[features]33[features]33default = ["std"]34default = ["std"]pallets/refungible/src/common.rsdiffbeforeafterboth19use sp_std::collections::btree_map::BTreeMap;19use sp_std::collections::btree_map::BTreeMap;20use frame_support::{dispatch::DispatchResultWithPostInfo, ensure, fail, weights::Weight, traits::Get};20use frame_support::{dispatch::DispatchResultWithPostInfo, ensure, fail, weights::Weight, traits::Get};21use up_data_structs::{21use up_data_structs::{22 CollectionId, TokenId, CreateItemExData, CreateRefungibleExData, budget::Budget, Property,22 CollectionId, TokenId, CreateItemExData, budget::Budget, Property, PropertyKey, PropertyValue,23 PropertyKey, PropertyValue, PropertyKeyPermission, CreateItemData, CollectionPropertiesVec,23 PropertyKeyPermission, CollectionPropertiesVec, CreateRefungibleExMultipleOwners,24 CreateRefungibleExSingleOwner,24};25};25use pallet_common::{26use pallet_common::{26 CommonCollectionOperations, CommonWeightInfo, RefungibleExtensions, with_weight,27 CommonCollectionOperations, CommonWeightInfo, RefungibleExtensions, with_weight,323333use crate::{34use crate::{34 AccountBalance, Allowance, Balance, Config, Error, Owned, Pallet, RefungibleHandle,35 AccountBalance, Allowance, Balance, Config, Error, Owned, Pallet, RefungibleHandle,35 SelfWeightOf, TokenData, weights::WeightInfo, TokensMinted, TotalSupply,36 SelfWeightOf, TokenData, weights::WeightInfo, TokensMinted, TotalSupply, CreateItemData,36};37};373838macro_rules! max_weight_of {39macro_rules! max_weight_of {58 <SelfWeightOf<T>>::create_item()59 <SelfWeightOf<T>>::create_item()59 }60 }606161 fn create_multiple_items(data: &[CreateItemData]) -> Weight {62 fn create_multiple_items(data: &[up_data_structs::CreateItemData]) -> Weight {62 <SelfWeightOf<T>>::create_multiple_items(data.len() as u32).saturating_add(63 <SelfWeightOf<T>>::create_multiple_items(data.len() as u32).saturating_add(63 data.iter()64 data.iter()64 .map(|data| match data {65 .map(|data| match data {65 CreateItemData::ReFungible(rft_data) => {66 up_data_structs::CreateItemData::ReFungible(rft_data) => {66 properties_weight::<T>(&rft_data.properties)67 properties_weight::<T>(&rft_data.properties)67 }68 }68 _ => 0,69 _ => 0,152fn map_create_data<T: Config>(153fn map_create_data<T: Config>(153 data: up_data_structs::CreateItemData,154 data: up_data_structs::CreateItemData,154 to: &T::CrossAccountId,155 to: &T::CrossAccountId,155) -> Result<CreateRefungibleExData<T::CrossAccountId>, DispatchError> {156) -> Result<CreateItemData<T::CrossAccountId>, DispatchError> {156 match data {157 match data {157 up_data_structs::CreateItemData::ReFungible(data) => Ok(CreateRefungibleExData {158 up_data_structs::CreateItemData::ReFungible(data) => Ok(CreateItemData {158 users: {159 users: {159 let mut out = BTreeMap::new();160 let mut out = BTreeMap::new();160 out.insert(to.clone(), data.pieces);161 out.insert(to.clone(), data.pieces);214 ) -> DispatchResultWithPostInfo {215 ) -> DispatchResultWithPostInfo {215 let weight = <CommonWeights<T>>::create_multiple_items_ex(&data);216 let weight = <CommonWeights<T>>::create_multiple_items_ex(&data);216 let data = match data {217 let data = match data {217 CreateItemExData::RefungibleMultipleOwners(r) => vec![r],218 CreateItemExData::RefungibleMultipleOwners(CreateRefungibleExMultipleOwners {219 users,220 properties,221 }) => vec![CreateItemData { users, properties }],218 CreateItemExData::RefungibleMultipleItems(r)222 CreateItemExData::RefungibleMultipleItems(r) => r223 .into_inner()224 .into_iter()219 if r.iter().all(|i| i.users.len() == 1) =>225 .map(220 {226 |CreateRefungibleExSingleOwner {227 user,228 pieces,229 properties,230 }| CreateItemData {231 users: BTreeMap::from([(user, pieces)])232 .try_into()233 .expect("limit >= 1"),234 properties,235 },236 )221 r.into_inner()237 .collect(),222 }223 _ => fail!(<Error<T>>::NotRefungibleDataUsedToMintFungibleCollectionToken),238 _ => fail!(<Error<T>>::NotRefungibleDataUsedToMintFungibleCollectionToken),224 };239 };225240pallets/refungible/src/erc.rsdiffbeforeafterboth494 <Pallet<T>>::create_item(494 <Pallet<T>>::create_item(495 self,495 self,496 &caller,496 &caller,497 CreateItemData::<T> {497 CreateItemData::<T::CrossAccountId> {498 users,498 users,499 properties: CollectionPropertiesVec::default(),499 properties: CollectionPropertiesVec::default(),500 },500 },560 <Pallet<T>>::create_item(560 <Pallet<T>>::create_item(561 self,561 self,562 &caller,562 &caller,563 CreateItemData::<T> { users, properties },563 CreateItemData::<T::CrossAccountId> { users, properties },564 &budget,564 &budget,565 )565 )566 .map_err(dispatch_to_evm::<T>)?;566 .map_err(dispatch_to_evm::<T>)?;717 .collect::<BTreeMap<_, _>>()717 .collect::<BTreeMap<_, _>>()718 .try_into()718 .try_into()719 .unwrap();719 .unwrap();720 let create_item_data = CreateItemData::<T> {720 let create_item_data = CreateItemData::<T::CrossAccountId> {721 users,721 users,722 properties: CollectionPropertiesVec::default(),722 properties: CollectionPropertiesVec::default(),723 };723 };777 })777 })778 .map_err(|e| Error::Revert(alloc::format!("Can't add property: {:?}", e)))?;778 .map_err(|e| Error::Revert(alloc::format!("Can't add property: {:?}", e)))?;779779780 let create_item_data = CreateItemData::<T> {780 let create_item_data = CreateItemData::<T::CrossAccountId> {781 users: users.clone(),781 users: users.clone(),782 properties,782 properties,783 };783 };pallets/refungible/src/lib.rsdiffbeforeafterboth94use core::ops::Deref;94use core::ops::Deref;95use evm_coder::ToLog;95use evm_coder::ToLog;96use frame_support::{BoundedVec, ensure, fail, storage::with_transaction, transactional};96use frame_support::{97 BoundedVec, ensure, fail, storage::with_transaction, transactional, pallet_prelude::ConstU32,98};97use pallet_evm::{account::CrossAccountId, Pallet as PalletEvm};99use pallet_evm::{account::CrossAccountId, Pallet as PalletEvm};98use pallet_evm_coder_substrate::WithRecorder;100use pallet_evm_coder_substrate::WithRecorder;106use sp_runtime::{ArithmeticError, DispatchError, DispatchResult, TransactionOutcome};108use sp_runtime::{ArithmeticError, DispatchError, DispatchResult, TransactionOutcome};107use sp_std::{vec::Vec, vec, collections::btree_map::BTreeMap};109use sp_std::{vec::Vec, vec, collections::btree_map::BTreeMap};108use up_data_structs::{110use up_data_structs::{109 AccessMode, budget::Budget, CollectionId, CreateCollectionData, CreateRefungibleExData,111 AccessMode, budget::Budget, CollectionId, CreateCollectionData, CustomDataLimit,110 CustomDataLimit, mapping::TokenAddressMapping, MAX_REFUNGIBLE_PIECES, TokenId, Property,112 mapping::TokenAddressMapping, MAX_REFUNGIBLE_PIECES, MAX_ITEMS_PER_BATCH, TokenId, Property,111 PropertyKey, PropertyKeyPermission, PropertyPermission, PropertyScope, PropertyValue,113 PropertyKey, PropertyKeyPermission, PropertyPermission, PropertyScope, PropertyValue,112 TrySetProperty,114 TrySetProperty, CollectionPropertiesVec,113};115};116use frame_support::BoundedBTreeMap;117use derivative::Derivative;114118115pub use pallet::*;119pub use pallet::*;116#[cfg(feature = "runtime-benchmarks")]120#[cfg(feature = "runtime-benchmarks")]120pub mod erc_token;124pub mod erc_token;121pub mod weights;125pub mod weights;122126127#[derive(Derivative, Clone)]123pub type CreateItemData<T> =128pub struct CreateItemData<CrossAccountId> {129 #[derivative(Debug(format_with = "bounded::map_debug"))]124 CreateRefungibleExData<<T as pallet_evm::account::Config>::CrossAccountId>;130 pub users: BoundedBTreeMap<CrossAccountId, u128, ConstU32<MAX_ITEMS_PER_BATCH>>,131 #[derivative(Debug(format_with = "bounded::vec_debug"))]132 pub properties: CollectionPropertiesVec,133}125pub(crate) type SelfWeightOf<T> = <T as Config>::WeightInfo;134pub(crate) type SelfWeightOf<T> = <T as Config>::WeightInfo;126135127/// Token data, stored independently from other data used to describe it136/// Token data, stored independently from other data used to describe it873 pub fn create_multiple_items(882 pub fn create_multiple_items(874 collection: &RefungibleHandle<T>,883 collection: &RefungibleHandle<T>,875 sender: &T::CrossAccountId,884 sender: &T::CrossAccountId,876 data: Vec<CreateItemData<T>>,885 data: Vec<CreateItemData<T::CrossAccountId>>,877 nesting_budget: &dyn Budget,886 nesting_budget: &dyn Budget,878 ) -> DispatchResult {887 ) -> DispatchResult {879 if !collection.is_owner_or_admin(sender) {888 if !collection.is_owner_or_admin(sender) {1213 pub fn create_item(1222 pub fn create_item(1214 collection: &RefungibleHandle<T>,1223 collection: &RefungibleHandle<T>,1215 sender: &T::CrossAccountId,1224 sender: &T::CrossAccountId,1216 data: CreateItemData<T>,1225 data: CreateItemData<T::CrossAccountId>,1217 nesting_budget: &dyn Budget,1226 nesting_budget: &dyn Budget,1218 ) -> DispatchResult {1227 ) -> DispatchResult {1219 Self::create_multiple_items(collection, sender, vec![data], nesting_budget)1228 Self::create_multiple_items(collection, sender, vec![data], nesting_budget)primitives/data-structs/src/lib.rsdiffbeforeafterboth826/// Extended data for create ReFungible item.826/// Extended data for create ReFungible item.827#[derive(Encode, Decode, MaxEncodedLen, PartialEq, Clone, TypeInfo, Derivative)]827#[derive(Encode, Decode, MaxEncodedLen, PartialEq, Clone, TypeInfo, Derivative)]828#[derivative(Debug(bound = "CrossAccountId: fmt::Debug + Ord"))]828#[derivative(Debug(bound = "CrossAccountId: fmt::Debug + Ord"))]829pub struct CreateRefungibleExData<CrossAccountId> {829pub struct CreateRefungibleExMultipleOwners<CrossAccountId> {830 #[derivative(Debug(format_with = "bounded::map_debug"))]830 #[derivative(Debug(format_with = "bounded::map_debug"))]831 pub users: BoundedBTreeMap<CrossAccountId, u128, ConstU32<MAX_ITEMS_PER_BATCH>>,831 pub users: BoundedBTreeMap<CrossAccountId, u128, ConstU32<MAX_ITEMS_PER_BATCH>>,832 #[derivative(Debug(format_with = "bounded::vec_debug"))]832 #[derivative(Debug(format_with = "bounded::vec_debug"))]833 pub properties: CollectionPropertiesVec,833 pub properties: CollectionPropertiesVec,834}834}835836/// Extended data for create ReFungible item.837#[derive(Encode, Decode, MaxEncodedLen, PartialEq, Clone, TypeInfo, Derivative)]838#[derivative(Debug(bound = "CrossAccountId: fmt::Debug"))]839pub struct CreateRefungibleExSingleOwner<CrossAccountId> {840 pub user: CrossAccountId,841 pub pieces: u128,842 #[derivative(Debug(format_with = "bounded::vec_debug"))]843 pub properties: CollectionPropertiesVec,844}835845836/// Unified extended data for creating item.846/// Unified extended data for creating item.837#[derive(Encode, Decode, MaxEncodedLen, PartialEq, Clone, TypeInfo, Derivative)]847#[derive(Encode, Decode, MaxEncodedLen, PartialEq, Clone, TypeInfo, Derivative)]853 /// many tokens, each may have only one owner863 /// many tokens, each may have only one owner854 RefungibleMultipleItems(864 RefungibleMultipleItems(855 #[derivative(Debug(format_with = "bounded::vec_debug"))]865 #[derivative(Debug(format_with = "bounded::vec_debug"))]856 BoundedVec<CreateRefungibleExData<CrossAccountId>, ConstU32<MAX_ITEMS_PER_BATCH>>,866 BoundedVec<CreateRefungibleExSingleOwner<CrossAccountId>, ConstU32<MAX_ITEMS_PER_BATCH>>,857 ),867 ),858868859 /// Extended data for create ReFungible item in case of869 /// Extended data for create ReFungible item in case of860 /// single token, which may have many owners870 /// single token, which may have many owners861 RefungibleMultipleOwners(CreateRefungibleExData<CrossAccountId>),871 RefungibleMultipleOwners(CreateRefungibleExMultipleOwners<CrossAccountId>),862}872}863873864impl From<CreateNftData> for CreateItemData {874impl From<CreateNftData> for CreateItemData {