1234567891011121314151617use core::marker::PhantomData;1819use frame_support::{dispatch::DispatchResultWithPostInfo, fail, weights::Weight};20use pallet_common::{21 weights::WeightInfo as _, with_weight, write_token_properties_total_weight,22 CommonCollectionOperations, CommonWeightInfo, RefungibleExtensions,23};24use pallet_structure::Pallet as PalletStructure;25use sp_runtime::DispatchError;26use sp_std::{collections::btree_map::BTreeMap, vec, vec::Vec};27use up_data_structs::{28 budget::Budget, CollectionId, CreateItemExData, CreateRefungibleExMultipleOwners,29 CreateRefungibleExSingleOwner, Property, PropertyKey, PropertyKeyPermission, PropertyValue,30 TokenId, TokenOwnerError,31};3233use crate::{34 weights::WeightInfo, AccountBalance, Allowance, Balance, Config, CreateItemData, Error, Owned,35 Pallet, RefungibleHandle, SelfWeightOf, TokenProperties, TokensMinted, TotalSupply,36};3738macro_rules! max_weight_of {39 ($($method:ident ($($args:tt)*)),*) => {40 Weight::zero()41 $(42 .max(<SelfWeightOf<T>>::$method($($args)*))43 )*44 };45}4647pub struct CommonWeights<T: Config>(PhantomData<T>);48impl<T: Config> CommonWeightInfo<T::CrossAccountId> for CommonWeights<T> {49 fn create_multiple_items(data: &[up_data_structs::CreateItemData]) -> Weight {50 mint_with_props_weight::<T>(51 <SelfWeightOf<T>>::create_multiple_items(data.len() as u32),52 data.iter().map(|data| match data {53 up_data_structs::CreateItemData::ReFungible(rft_data) => {54 rft_data.properties.len() as u3255 }56 _ => 0,57 }),58 )59 }6061 fn create_multiple_items_ex(call: &CreateItemExData<T::CrossAccountId>) -> Weight {62 match call {63 CreateItemExData::RefungibleMultipleOwners(i) => mint_with_props_weight::<T>(64 <SelfWeightOf<T>>::create_multiple_items_ex_multiple_owners(i.users.len() as u32),65 [i.properties.len() as u32].into_iter(),66 ),67 CreateItemExData::RefungibleMultipleItems(i) => mint_with_props_weight::<T>(68 <SelfWeightOf<T>>::create_multiple_items_ex_multiple_items(i.len() as u32),69 i.iter().map(|d| d.properties.len() as u32),70 ),71 _ => Weight::zero(),72 }73 }7475 fn burn_item() -> Weight {76 max_weight_of!(burn_item_partial(), burn_item_fully())77 }7879 fn set_collection_properties(amount: u32) -> Weight {80 <pallet_common::SelfWeightOf<T>>::set_collection_properties(amount)81 }8283 fn set_token_properties(amount: u32) -> Weight {84 write_token_properties_total_weight::<T, _>([amount].into_iter(), |amount| {85 <SelfWeightOf<T>>::load_token_properties()86 .saturating_add(<SelfWeightOf<T>>::write_token_properties(amount))87 })88 }8990 fn set_token_property_permissions(amount: u32) -> Weight {91 <SelfWeightOf<T>>::set_token_property_permissions(amount)92 }9394 fn transfer() -> Weight {95 max_weight_of!(96 transfer_normal(),97 transfer_creating(),98 transfer_removing(),99 transfer_creating_removing()100 )101 }102103 fn approve() -> Weight {104 <SelfWeightOf<T>>::approve()105 }106107 fn approve_from() -> Weight {108 <SelfWeightOf<T>>::approve_from()109 }110111 fn transfer_from() -> Weight {112 max_weight_of!(113 transfer_from_normal(),114 transfer_from_creating(),115 transfer_from_removing(),116 transfer_from_creating_removing()117 )118 }119120 fn burn_from() -> Weight {121 <SelfWeightOf<T>>::burn_from()122 }123124 fn set_allowance_for_all() -> Weight {125 <SelfWeightOf<T>>::set_allowance_for_all()126 }127128 fn force_repair_item() -> Weight {129 <SelfWeightOf<T>>::repair_item()130 }131}132133134135136#[inline]137pub(crate) fn mint_with_props_weight<T: Config>(138 create_no_data_weight: Weight,139 token_properties_nums: impl Iterator<Item = u32> + Clone,140) -> Weight {141 create_no_data_weight.saturating_add(write_token_properties_total_weight::<T, _>(142 token_properties_nums,143 <SelfWeightOf<T>>::write_token_properties,144 ))145}146147fn map_create_data<T: Config>(148 data: up_data_structs::CreateItemData,149 to: &T::CrossAccountId,150) -> Result<CreateItemData<T>, DispatchError> {151 match data {152 up_data_structs::CreateItemData::ReFungible(data) => Ok(CreateItemData::<T> {153 users: {154 let mut out = BTreeMap::new();155 out.insert(to.clone(), data.pieces);156 out.try_into().expect("limit > 0")157 },158 properties: data.properties,159 }),160 _ => fail!(<Error<T>>::NotRefungibleDataUsedToMintFungibleCollectionToken),161 }162}163164165166impl<T: Config> CommonCollectionOperations<T> for RefungibleHandle<T> {167 fn create_item(168 &self,169 sender: T::CrossAccountId,170 to: T::CrossAccountId,171 data: up_data_structs::CreateItemData,172 nesting_budget: &dyn Budget,173 ) -> DispatchResultWithPostInfo {174 let weight = <CommonWeights<T>>::create_item(&data);175 with_weight(176 <Pallet<T>>::create_item(177 self,178 &sender,179 map_create_data::<T>(data, &to)?,180 nesting_budget,181 ),182 weight,183 )184 }185186 fn create_multiple_items(187 &self,188 sender: T::CrossAccountId,189 to: T::CrossAccountId,190 data: Vec<up_data_structs::CreateItemData>,191 nesting_budget: &dyn Budget,192 ) -> DispatchResultWithPostInfo {193 let weight = <CommonWeights<T>>::create_multiple_items(&data);194 let data = data195 .into_iter()196 .map(|d| map_create_data::<T>(d, &to))197 .collect::<Result<Vec<_>, DispatchError>>()?;198199 with_weight(200 <Pallet<T>>::create_multiple_items(self, &sender, data, nesting_budget),201 weight,202 )203 }204205 fn create_multiple_items_ex(206 &self,207 sender: <T>::CrossAccountId,208 data: CreateItemExData<T::CrossAccountId>,209 nesting_budget: &dyn Budget,210 ) -> DispatchResultWithPostInfo {211 let weight = <CommonWeights<T>>::create_multiple_items_ex(&data);212 let data = match data {213 CreateItemExData::RefungibleMultipleOwners(CreateRefungibleExMultipleOwners {214 users,215 properties,216 }) => vec![CreateItemData::<T> { users, properties }],217 CreateItemExData::RefungibleMultipleItems(r) => r218 .into_inner()219 .into_iter()220 .map(221 |CreateRefungibleExSingleOwner {222 user,223 pieces,224 properties,225 }| CreateItemData::<T> {226 users: BTreeMap::from([(user, pieces)])227 .try_into()228 .expect("limit >= 1"),229 properties,230 },231 )232 .collect(),233 _ => fail!(<Error<T>>::NotRefungibleDataUsedToMintFungibleCollectionToken),234 };235236 with_weight(237 <Pallet<T>>::create_multiple_items(self, &sender, data, nesting_budget),238 weight,239 )240 }241242 fn burn_item(243 &self,244 sender: T::CrossAccountId,245 token: TokenId,246 amount: u128,247 ) -> DispatchResultWithPostInfo {248 with_weight(249 <Pallet<T>>::burn(self, &sender, token, amount),250 <CommonWeights<T>>::burn_item(),251 )252 }253254 fn transfer(255 &self,256 from: T::CrossAccountId,257 to: T::CrossAccountId,258 token: TokenId,259 amount: u128,260 nesting_budget: &dyn Budget,261 ) -> DispatchResultWithPostInfo {262 with_weight(263 <Pallet<T>>::transfer(self, &from, &to, token, amount, nesting_budget),264 <CommonWeights<T>>::transfer(),265 )266 }267268 fn approve(269 &self,270 sender: T::CrossAccountId,271 spender: T::CrossAccountId,272 token: TokenId,273 amount: u128,274 ) -> DispatchResultWithPostInfo {275 with_weight(276 <Pallet<T>>::set_allowance(self, &sender, &spender, token, amount),277 <CommonWeights<T>>::approve(),278 )279 }280281 fn approve_from(282 &self,283 sender: T::CrossAccountId,284 from: T::CrossAccountId,285 to: T::CrossAccountId,286 token_id: TokenId,287 amount: u128,288 ) -> DispatchResultWithPostInfo {289 with_weight(290 <Pallet<T>>::set_allowance_from(self, &sender, &from, &to, token_id, amount),291 <CommonWeights<T>>::approve_from(),292 )293 }294295 fn transfer_from(296 &self,297 sender: T::CrossAccountId,298 from: T::CrossAccountId,299 to: T::CrossAccountId,300 token: TokenId,301 amount: u128,302 nesting_budget: &dyn Budget,303 ) -> DispatchResultWithPostInfo {304 with_weight(305 <Pallet<T>>::transfer_from(self, &sender, &from, &to, token, amount, nesting_budget),306 <CommonWeights<T>>::transfer_from(),307 )308 }309310 fn burn_from(311 &self,312 sender: T::CrossAccountId,313 from: T::CrossAccountId,314 token: TokenId,315 amount: u128,316 nesting_budget: &dyn Budget,317 ) -> DispatchResultWithPostInfo {318 with_weight(319 <Pallet<T>>::burn_from(self, &sender, &from, token, amount, nesting_budget),320 <CommonWeights<T>>::burn_from(),321 )322 }323324 fn set_collection_properties(325 &self,326 sender: T::CrossAccountId,327 properties: Vec<Property>,328 ) -> DispatchResultWithPostInfo {329 let weight = <CommonWeights<T>>::set_collection_properties(properties.len() as u32);330331 with_weight(332 <Pallet<T>>::set_collection_properties(self, &sender, properties),333 weight,334 )335 }336337 fn delete_collection_properties(338 &self,339 sender: &T::CrossAccountId,340 property_keys: Vec<PropertyKey>,341 ) -> DispatchResultWithPostInfo {342 let weight = <CommonWeights<T>>::delete_collection_properties(property_keys.len() as u32);343344 with_weight(345 <Pallet<T>>::delete_collection_properties(self, sender, property_keys),346 weight,347 )348 }349350 fn set_token_properties(351 &self,352 sender: T::CrossAccountId,353 token_id: TokenId,354 properties: Vec<Property>,355 nesting_budget: &dyn Budget,356 ) -> DispatchResultWithPostInfo {357 let weight = <CommonWeights<T>>::set_token_properties(properties.len() as u32);358359 with_weight(360 <Pallet<T>>::set_token_properties(361 self,362 &sender,363 token_id,364 properties.into_iter(),365 nesting_budget,366 ),367 weight,368 )369 }370371 fn set_token_property_permissions(372 &self,373 sender: &T::CrossAccountId,374 property_permissions: Vec<PropertyKeyPermission>,375 ) -> DispatchResultWithPostInfo {376 let weight =377 <CommonWeights<T>>::set_token_property_permissions(property_permissions.len() as u32);378379 with_weight(380 <Pallet<T>>::set_token_property_permissions(self, sender, property_permissions),381 weight,382 )383 }384385 fn delete_token_properties(386 &self,387 sender: T::CrossAccountId,388 token_id: TokenId,389 property_keys: Vec<PropertyKey>,390 nesting_budget: &dyn Budget,391 ) -> DispatchResultWithPostInfo {392 let weight = <CommonWeights<T>>::delete_token_properties(property_keys.len() as u32);393394 with_weight(395 <Pallet<T>>::delete_token_properties(396 self,397 &sender,398 token_id,399 property_keys.into_iter(),400 nesting_budget,401 ),402 weight,403 )404 }405406 fn get_token_properties_raw(407 &self,408 token_id: TokenId,409 ) -> Option<up_data_structs::TokenProperties> {410 <TokenProperties<T>>::get((self.id, token_id))411 }412413 fn set_token_properties_raw(&self, token_id: TokenId, map: up_data_structs::TokenProperties) {414 <TokenProperties<T>>::insert((self.id, token_id), map)415 }416417 fn check_nesting(418 &self,419 _sender: &<T>::CrossAccountId,420 _from: (CollectionId, TokenId),421 _under: TokenId,422 _nesting_budget: &dyn Budget,423 ) -> sp_runtime::DispatchResult {424 fail!(<Error<T>>::RefungibleDisallowsNesting)425 }426427 fn nest(&self, _under: TokenId, _to_nest: (CollectionId, TokenId)) {}428429 fn unnest(&self, _under: TokenId, _to_nest: (CollectionId, TokenId)) {}430431 fn account_tokens(&self, account: T::CrossAccountId) -> Vec<TokenId> {432 <Owned<T>>::iter_prefix((self.id, account))433 .map(|(id, _)| id)434 .collect()435 }436437 fn collection_tokens(&self) -> Vec<TokenId> {438 <TotalSupply<T>>::iter_prefix((self.id,))439 .map(|(id, _)| id)440 .collect()441 }442443 fn token_exists(&self, token: TokenId) -> bool {444 <Pallet<T>>::token_exists(self, token)445 }446447 fn last_token_id(&self) -> TokenId {448 TokenId(<TokensMinted<T>>::get(self.id))449 }450451 fn token_owner(&self, token: TokenId) -> Result<T::CrossAccountId, TokenOwnerError> {452 <Pallet<T>>::token_owner(self.id, token)453 }454455 fn check_token_indirect_owner(456 &self,457 token: TokenId,458 maybe_owner: &T::CrossAccountId,459 nesting_budget: &dyn Budget,460 ) -> Result<bool, DispatchError> {461 let balance = self.balance(maybe_owner.clone(), token);462 let total_pieces: u128 = <Pallet<T>>::total_pieces(self.id, token).unwrap_or(u128::MAX);463 if balance != total_pieces {464 return Ok(false);465 }466467 <PalletStructure<T>>::check_indirectly_owned(468 maybe_owner.clone(),469 self.id,470 token,471 None,472 nesting_budget,473 )474 }475476 477 fn token_owners(&self, token: TokenId) -> Vec<T::CrossAccountId> {478 <Pallet<T>>::token_owners(self.id, token).unwrap_or_default()479 }480481 fn token_property(&self, token_id: TokenId, key: &PropertyKey) -> Option<PropertyValue> {482 <Pallet<T>>::token_properties((self.id, token_id))?483 .get(key)484 .cloned()485 }486487 fn token_properties(&self, token_id: TokenId, keys: Option<Vec<PropertyKey>>) -> Vec<Property> {488 let Some(properties) = <Pallet<T>>::token_properties((self.id, token_id)) else {489 return vec![];490 };491492 keys.map(|keys| {493 keys.into_iter()494 .filter_map(|key| {495 properties.get(&key).map(|value| Property {496 key,497 value: value.clone(),498 })499 })500 .collect()501 })502 .unwrap_or_else(|| {503 properties504 .into_iter()505 .map(|(key, value)| Property { key, value })506 .collect()507 })508 }509510 fn total_supply(&self) -> u32 {511 <Pallet<T>>::total_supply(self)512 }513514 fn account_balance(&self, account: T::CrossAccountId) -> u32 {515 <AccountBalance<T>>::get((self.id, account))516 }517518 fn balance(&self, account: T::CrossAccountId, token: TokenId) -> u128 {519 <Balance<T>>::get((self.id, token, account))520 }521522 fn allowance(523 &self,524 sender: T::CrossAccountId,525 spender: T::CrossAccountId,526 token: TokenId,527 ) -> u128 {528 <Allowance<T>>::get((self.id, token, sender, spender))529 }530531 fn refungible_extensions(&self) -> Option<&dyn RefungibleExtensions<T>> {532 Some(self)533 }534535 fn total_pieces(&self, token: TokenId) -> Option<u128> {536 <Pallet<T>>::total_pieces(self.id, token)537 }538539 fn set_allowance_for_all(540 &self,541 owner: T::CrossAccountId,542 operator: T::CrossAccountId,543 approve: bool,544 ) -> DispatchResultWithPostInfo {545 with_weight(546 <Pallet<T>>::set_allowance_for_all(self, &owner, &operator, approve),547 <CommonWeights<T>>::set_allowance_for_all(),548 )549 }550551 fn allowance_for_all(&self, owner: T::CrossAccountId, operator: T::CrossAccountId) -> bool {552 <Pallet<T>>::allowance_for_all(self, &owner, &operator)553 }554555 fn repair_item(&self, token: TokenId) -> DispatchResultWithPostInfo {556 with_weight(557 <Pallet<T>>::repair_item(self, token),558 <CommonWeights<T>>::force_repair_item(),559 )560 }561}562563impl<T: Config> RefungibleExtensions<T> for RefungibleHandle<T> {564 fn repartition(565 &self,566 owner: &T::CrossAccountId,567 token: TokenId,568 amount: u128,569 ) -> DispatchResultWithPostInfo {570 with_weight(571 <Pallet<T>>::repartition(self, owner, token, amount),572 <SelfWeightOf<T>>::repartition_item(),573 )574 }575}