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.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"]
pallets/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),
};
pallets/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,
};
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.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 {