git.delta.rocks / unique-network / refs/commits / ec332a0b04f6

difftreelog

refactor(pallet-refungible) disallow invalid bulk mints

Yaroslav Bolyukin2022-08-04parent: #b7c1009.patch.diff
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

modifiedpallets/refungible/Cargo.tomldiffbeforeafterboth
--- a/pallets/refungible/Cargo.toml
+++ b/pallets/refungible/Cargo.toml
@@ -28,6 +28,7 @@
 sp-core = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.24" }
 sp-runtime = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.24" }
 sp-std = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.24" }
+derivative = { version = "2.2.0", features = ["use_core"] }
 
 [features]
 default = ["std"]
modifiedpallets/refungible/src/common.rsdiffbeforeafterboth
--- a/pallets/refungible/src/common.rs
+++ b/pallets/refungible/src/common.rs
@@ -19,8 +19,9 @@
 use sp_std::collections::btree_map::BTreeMap;
 use frame_support::{dispatch::DispatchResultWithPostInfo, ensure, fail, weights::Weight, traits::Get};
 use up_data_structs::{
-	CollectionId, TokenId, CreateItemExData, CreateRefungibleExData, budget::Budget, Property,
-	PropertyKey, PropertyValue, PropertyKeyPermission, CreateItemData, CollectionPropertiesVec,
+	CollectionId, TokenId, CreateItemExData, budget::Budget, Property, PropertyKey, PropertyValue,
+	PropertyKeyPermission, CollectionPropertiesVec, CreateRefungibleExMultipleOwners,
+	CreateRefungibleExSingleOwner,
 };
 use pallet_common::{
 	CommonCollectionOperations, CommonWeightInfo, RefungibleExtensions, with_weight,
@@ -32,7 +33,7 @@
 
 use crate::{
 	AccountBalance, Allowance, Balance, Config, Error, Owned, Pallet, RefungibleHandle,
-	SelfWeightOf, TokenData, weights::WeightInfo, TokensMinted, TotalSupply,
+	SelfWeightOf, TokenData, weights::WeightInfo, TokensMinted, TotalSupply, CreateItemData,
 };
 
 macro_rules! max_weight_of {
@@ -58,11 +59,11 @@
 		<SelfWeightOf<T>>::create_item()
 	}
 
-	fn create_multiple_items(data: &[CreateItemData]) -> Weight {
+	fn create_multiple_items(data: &[up_data_structs::CreateItemData]) -> Weight {
 		<SelfWeightOf<T>>::create_multiple_items(data.len() as u32).saturating_add(
 			data.iter()
 				.map(|data| match data {
-					CreateItemData::ReFungible(rft_data) => {
+					up_data_structs::CreateItemData::ReFungible(rft_data) => {
 						properties_weight::<T>(&rft_data.properties)
 					}
 					_ => 0,
@@ -152,9 +153,9 @@
 fn map_create_data<T: Config>(
 	data: up_data_structs::CreateItemData,
 	to: &T::CrossAccountId,
-) -> Result<CreateRefungibleExData<T::CrossAccountId>, DispatchError> {
+) -> Result<CreateItemData<T::CrossAccountId>, DispatchError> {
 	match data {
-		up_data_structs::CreateItemData::ReFungible(data) => Ok(CreateRefungibleExData {
+		up_data_structs::CreateItemData::ReFungible(data) => Ok(CreateItemData {
 			users: {
 				let mut out = BTreeMap::new();
 				out.insert(to.clone(), data.pieces);
@@ -214,12 +215,26 @@
 	) -> DispatchResultWithPostInfo {
 		let weight = <CommonWeights<T>>::create_multiple_items_ex(&data);
 		let data = match data {
-			CreateItemExData::RefungibleMultipleOwners(r) => vec![r],
-			CreateItemExData::RefungibleMultipleItems(r)
-				if r.iter().all(|i| i.users.len() == 1) =>
-			{
-				r.into_inner()
-			}
+			CreateItemExData::RefungibleMultipleOwners(CreateRefungibleExMultipleOwners {
+				users,
+				properties,
+			}) => vec![CreateItemData { users, properties }],
+			CreateItemExData::RefungibleMultipleItems(r) => r
+				.into_inner()
+				.into_iter()
+				.map(
+					|CreateRefungibleExSingleOwner {
+					     user,
+					     pieces,
+					     properties,
+					 }| CreateItemData {
+						users: BTreeMap::from([(user, pieces)])
+							.try_into()
+							.expect("limit >= 1"),
+						properties,
+					},
+				)
+				.collect(),
 			_ => fail!(<Error<T>>::NotRefungibleDataUsedToMintFungibleCollectionToken),
 		};
 
modifiedpallets/refungible/src/erc.rsdiffbeforeafterboth
--- a/pallets/refungible/src/erc.rs
+++ b/pallets/refungible/src/erc.rs
@@ -494,7 +494,7 @@
 		<Pallet<T>>::create_item(
 			self,
 			&caller,
-			CreateItemData::<T> {
+			CreateItemData::<T::CrossAccountId> {
 				users,
 				properties: CollectionPropertiesVec::default(),
 			},
@@ -560,7 +560,7 @@
 		<Pallet<T>>::create_item(
 			self,
 			&caller,
-			CreateItemData::<T> { users, properties },
+			CreateItemData::<T::CrossAccountId> { users, properties },
 			&budget,
 		)
 		.map_err(dispatch_to_evm::<T>)?;
@@ -717,7 +717,7 @@
 			.collect::<BTreeMap<_, _>>()
 			.try_into()
 			.unwrap();
-		let create_item_data = CreateItemData::<T> {
+		let create_item_data = CreateItemData::<T::CrossAccountId> {
 			users,
 			properties: CollectionPropertiesVec::default(),
 		};
@@ -777,7 +777,7 @@
 				})
 				.map_err(|e| Error::Revert(alloc::format!("Can't add property: {:?}", e)))?;
 
-			let create_item_data = CreateItemData::<T> {
+			let create_item_data = CreateItemData::<T::CrossAccountId> {
 				users: users.clone(),
 				properties,
 			};
modifiedpallets/refungible/src/lib.rsdiffbeforeafterboth
94use 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;
114118
115pub 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;
122126
127#[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;
126135
127/// Token data, stored independently from other data used to describe it136/// Token data, stored independently from other data used to describe it
873 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)
modifiedprimitives/data-structs/src/lib.rsdiffbeforeafterboth
--- a/primitives/data-structs/src/lib.rs
+++ b/primitives/data-structs/src/lib.rs
@@ -826,13 +826,23 @@
 /// Extended data for create ReFungible item.
 #[derive(Encode, Decode, MaxEncodedLen, PartialEq, Clone, TypeInfo, Derivative)]
 #[derivative(Debug(bound = "CrossAccountId: fmt::Debug + Ord"))]
-pub struct CreateRefungibleExData<CrossAccountId> {
+pub struct CreateRefungibleExMultipleOwners<CrossAccountId> {
 	#[derivative(Debug(format_with = "bounded::map_debug"))]
 	pub users: BoundedBTreeMap<CrossAccountId, u128, ConstU32<MAX_ITEMS_PER_BATCH>>,
 	#[derivative(Debug(format_with = "bounded::vec_debug"))]
 	pub properties: CollectionPropertiesVec,
 }
 
+/// Extended data for create ReFungible item.
+#[derive(Encode, Decode, MaxEncodedLen, PartialEq, Clone, TypeInfo, Derivative)]
+#[derivative(Debug(bound = "CrossAccountId: fmt::Debug"))]
+pub struct CreateRefungibleExSingleOwner<CrossAccountId> {
+	pub user: CrossAccountId,
+	pub pieces: u128,
+	#[derivative(Debug(format_with = "bounded::vec_debug"))]
+	pub properties: CollectionPropertiesVec,
+}
+
 /// Unified extended data for creating item.
 #[derive(Encode, Decode, MaxEncodedLen, PartialEq, Clone, TypeInfo, Derivative)]
 #[derivative(Debug(bound = "CrossAccountId: fmt::Debug + Ord"))]
@@ -853,12 +863,12 @@
 	/// many tokens, each may have only one owner
 	RefungibleMultipleItems(
 		#[derivative(Debug(format_with = "bounded::vec_debug"))]
-		BoundedVec<CreateRefungibleExData<CrossAccountId>, ConstU32<MAX_ITEMS_PER_BATCH>>,
+		BoundedVec<CreateRefungibleExSingleOwner<CrossAccountId>, ConstU32<MAX_ITEMS_PER_BATCH>>,
 	),
 
 	/// Extended data for create ReFungible item in case of
 	/// single token, which may have many owners
-	RefungibleMultipleOwners(CreateRefungibleExData<CrossAccountId>),
+	RefungibleMultipleOwners(CreateRefungibleExMultipleOwners<CrossAccountId>),
 }
 
 impl From<CreateNftData> for CreateItemData {