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.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.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.rsdiffbeforeafterboth--- a/pallets/refungible/src/lib.rs
+++ b/pallets/refungible/src/lib.rs
@@ -93,7 +93,9 @@
use codec::{Encode, Decode, MaxEncodedLen};
use core::ops::Deref;
use evm_coder::ToLog;
-use frame_support::{BoundedVec, ensure, fail, storage::with_transaction, transactional};
+use frame_support::{
+ BoundedVec, ensure, fail, storage::with_transaction, transactional, pallet_prelude::ConstU32,
+};
use pallet_evm::{account::CrossAccountId, Pallet as PalletEvm};
use pallet_evm_coder_substrate::WithRecorder;
use pallet_common::{
@@ -106,11 +108,13 @@
use sp_runtime::{ArithmeticError, DispatchError, DispatchResult, TransactionOutcome};
use sp_std::{vec::Vec, vec, collections::btree_map::BTreeMap};
use up_data_structs::{
- AccessMode, budget::Budget, CollectionId, CreateCollectionData, CreateRefungibleExData,
- CustomDataLimit, mapping::TokenAddressMapping, MAX_REFUNGIBLE_PIECES, TokenId, Property,
+ AccessMode, budget::Budget, CollectionId, CreateCollectionData, CustomDataLimit,
+ mapping::TokenAddressMapping, MAX_REFUNGIBLE_PIECES, MAX_ITEMS_PER_BATCH, TokenId, Property,
PropertyKey, PropertyKeyPermission, PropertyPermission, PropertyScope, PropertyValue,
- TrySetProperty,
+ TrySetProperty, CollectionPropertiesVec,
};
+use frame_support::BoundedBTreeMap;
+use derivative::Derivative;
pub use pallet::*;
#[cfg(feature = "runtime-benchmarks")]
@@ -120,8 +124,13 @@
pub mod erc_token;
pub mod weights;
-pub type CreateItemData<T> =
- CreateRefungibleExData<<T as pallet_evm::account::Config>::CrossAccountId>;
+#[derive(Derivative, Clone)]
+pub struct CreateItemData<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,
+}
pub(crate) type SelfWeightOf<T> = <T as Config>::WeightInfo;
/// Token data, stored independently from other data used to describe it
@@ -873,7 +882,7 @@
pub fn create_multiple_items(
collection: &RefungibleHandle<T>,
sender: &T::CrossAccountId,
- data: Vec<CreateItemData<T>>,
+ data: Vec<CreateItemData<T::CrossAccountId>>,
nesting_budget: &dyn Budget,
) -> DispatchResult {
if !collection.is_owner_or_admin(sender) {
@@ -1213,7 +1222,7 @@
pub fn create_item(
collection: &RefungibleHandle<T>,
sender: &T::CrossAccountId,
- data: CreateItemData<T>,
+ data: CreateItemData<T::CrossAccountId>,
nesting_budget: &dyn Budget,
) -> DispatchResult {
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 {