1234567891011121314151617use core::marker::PhantomData;1819use sp_std::collections::btree_map::BTreeMap;20use frame_support::{dispatch::DispatchResultWithPostInfo, ensure, fail, weights::Weight, traits::Get};21use up_data_structs::{22 CollectionId, TokenId, CreateItemExData, budget::Budget, Property, PropertyKey, PropertyValue,23 PropertyKeyPermission, CreateRefungibleExMultipleOwners, CreateRefungibleExSingleOwner,24 TokenOwnerError,25};26use pallet_common::{27 CommonCollectionOperations, CommonWeightInfo, RefungibleExtensions, with_weight,28 weights::WeightInfo as _, init_token_properties_delta,29};30use pallet_structure::{Pallet as PalletStructure, Error as StructureError};31use sp_runtime::{DispatchError};32use sp_std::{vec::Vec, vec};3334use crate::{35 AccountBalance, Allowance, Balance, Config, Error, Owned, Pallet, RefungibleHandle,36 SelfWeightOf, weights::WeightInfo, TokensMinted, TotalSupply, CreateItemData, TokenProperties,37};3839macro_rules! max_weight_of {40 ($($method:ident ($($args:tt)*)),*) => {41 Weight::zero()42 $(43 .max(<SelfWeightOf<T>>::$method($($args)*))44 )*45 };46}4748pub struct CommonWeights<T: Config>(PhantomData<T>);49impl<T: Config> CommonWeightInfo<T::CrossAccountId> for CommonWeights<T> {50 fn create_multiple_items(data: &[up_data_structs::CreateItemData]) -> Weight {51 <SelfWeightOf<T>>::create_multiple_items(data.len() as u32).saturating_add(52 init_token_properties_delta::<T, _>(53 data.iter().map(|data| match data {54 up_data_structs::CreateItemData::ReFungible(rft_data) => {55 rft_data.properties.len() as u3256 }57 _ => 0,58 }),59 <SelfWeightOf<T>>::init_token_properties,60 ),61 )62 }6364 fn create_multiple_items_ex(call: &CreateItemExData<T::CrossAccountId>) -> Weight {65 match call {66 CreateItemExData::RefungibleMultipleOwners(i) => {67 <SelfWeightOf<T>>::create_multiple_items_ex_multiple_owners(i.users.len() as u32)68 .saturating_add(init_token_properties_delta::<T, _>(69 [i.properties.len() as u32].into_iter(),70 <SelfWeightOf<T>>::init_token_properties,71 ))72 }73 CreateItemExData::RefungibleMultipleItems(i) => {74 <SelfWeightOf<T>>::create_multiple_items_ex_multiple_items(i.len() as u32)75 .saturating_add(init_token_properties_delta::<T, _>(76 i.iter().map(|d| d.properties.len() as u32),77 <SelfWeightOf<T>>::init_token_properties,78 ))79 }80 _ => Weight::zero(),81 }82 }8384 fn burn_item() -> Weight {85 max_weight_of!(burn_item_partial(), burn_item_fully())86 }8788 fn set_collection_properties(amount: u32) -> Weight {89 <pallet_common::SelfWeightOf<T>>::set_collection_properties(amount)90 }9192 fn delete_collection_properties(amount: u32) -> Weight {93 <pallet_common::SelfWeightOf<T>>::delete_collection_properties(amount)94 }9596 fn set_token_properties(amount: u32) -> Weight {97 <SelfWeightOf<T>>::set_token_properties(amount)98 }99100 fn delete_token_properties(amount: u32) -> Weight {101 <SelfWeightOf<T>>::delete_token_properties(amount)102 }103104 fn set_token_property_permissions(amount: u32) -> Weight {105 <SelfWeightOf<T>>::set_token_property_permissions(amount)106 }107108 fn transfer() -> Weight {109 max_weight_of!(110 transfer_normal(),111 transfer_creating(),112 transfer_removing(),113 transfer_creating_removing()114 )115 }116117 fn approve() -> Weight {118 <SelfWeightOf<T>>::approve()119 }120121 fn approve_from() -> Weight {122 <SelfWeightOf<T>>::approve_from()123 }124125 fn transfer_from() -> Weight {126 max_weight_of!(127 transfer_from_normal(),128 transfer_from_creating(),129 transfer_from_removing(),130 transfer_from_creating_removing()131 )132 }133134 fn burn_from() -> Weight {135 <SelfWeightOf<T>>::burn_from()136 }137138 fn burn_recursively_self_raw() -> Weight {139 140 Self::burn_item() + T::DbWeight::get().reads(1)141 }142 fn burn_recursively_breadth_raw(_amount: u32) -> Weight {143 144 Weight::zero()145 }146147 fn token_owner() -> Weight {148 <SelfWeightOf<T>>::token_owner()149 }150151 fn set_allowance_for_all() -> Weight {152 <SelfWeightOf<T>>::set_allowance_for_all()153 }154155 fn force_repair_item() -> Weight {156 <SelfWeightOf<T>>::repair_item()157 }158}159160fn map_create_data<T: Config>(161 data: up_data_structs::CreateItemData,162 to: &T::CrossAccountId,163) -> Result<CreateItemData<T>, DispatchError> {164 match data {165 up_data_structs::CreateItemData::ReFungible(data) => Ok(CreateItemData::<T> {166 users: {167 let mut out = BTreeMap::new();168 out.insert(to.clone(), data.pieces);169 out.try_into().expect("limit > 0")170 },171 properties: data.properties,172 }),173 _ => fail!(<Error<T>>::NotRefungibleDataUsedToMintFungibleCollectionToken),174 }175}176177178179impl<T: Config> CommonCollectionOperations<T> for RefungibleHandle<T> {180 fn create_item(181 &self,182 sender: T::CrossAccountId,183 to: T::CrossAccountId,184 data: up_data_structs::CreateItemData,185 nesting_budget: &dyn Budget,186 ) -> DispatchResultWithPostInfo {187 let weight = <CommonWeights<T>>::create_item(&data);188 with_weight(189 <Pallet<T>>::create_item(190 self,191 &sender,192 map_create_data::<T>(data, &to)?,193 nesting_budget,194 ),195 weight,196 )197 }198199 fn create_multiple_items(200 &self,201 sender: T::CrossAccountId,202 to: T::CrossAccountId,203 data: Vec<up_data_structs::CreateItemData>,204 nesting_budget: &dyn Budget,205 ) -> DispatchResultWithPostInfo {206 let weight = <CommonWeights<T>>::create_multiple_items(&data);207 let data = data208 .into_iter()209 .map(|d| map_create_data::<T>(d, &to))210 .collect::<Result<Vec<_>, DispatchError>>()?;211212 with_weight(213 <Pallet<T>>::create_multiple_items(self, &sender, data, nesting_budget),214 weight,215 )216 }217218 fn create_multiple_items_ex(219 &self,220 sender: <T>::CrossAccountId,221 data: CreateItemExData<T::CrossAccountId>,222 nesting_budget: &dyn Budget,223 ) -> DispatchResultWithPostInfo {224 let weight = <CommonWeights<T>>::create_multiple_items_ex(&data);225 let data = match data {226 CreateItemExData::RefungibleMultipleOwners(CreateRefungibleExMultipleOwners {227 users,228 properties,229 }) => vec![CreateItemData::<T> { users, properties }],230 CreateItemExData::RefungibleMultipleItems(r) => r231 .into_inner()232 .into_iter()233 .map(234 |CreateRefungibleExSingleOwner {235 user,236 pieces,237 properties,238 }| CreateItemData::<T> {239 users: BTreeMap::from([(user, pieces)])240 .try_into()241 .expect("limit >= 1"),242 properties,243 },244 )245 .collect(),246 _ => fail!(<Error<T>>::NotRefungibleDataUsedToMintFungibleCollectionToken),247 };248249 with_weight(250 <Pallet<T>>::create_multiple_items(self, &sender, data, nesting_budget),251 weight,252 )253 }254255 fn burn_item(256 &self,257 sender: T::CrossAccountId,258 token: TokenId,259 amount: u128,260 ) -> DispatchResultWithPostInfo {261 with_weight(262 <Pallet<T>>::burn(self, &sender, token, amount),263 <CommonWeights<T>>::burn_item(),264 )265 }266267 fn burn_item_recursively(268 &self,269 sender: T::CrossAccountId,270 token: TokenId,271 self_budget: &dyn Budget,272 _breadth_budget: &dyn Budget,273 ) -> DispatchResultWithPostInfo {274 ensure!(self_budget.consume(), <StructureError<T>>::DepthLimit,);275 with_weight(276 <Pallet<T>>::burn(277 self,278 &sender,279 token,280 <Balance<T>>::get((self.id, token, &sender)),281 ),282 <CommonWeights<T>>::burn_recursively_self_raw(),283 )284 }285286 fn transfer(287 &self,288 from: T::CrossAccountId,289 to: T::CrossAccountId,290 token: TokenId,291 amount: u128,292 nesting_budget: &dyn Budget,293 ) -> DispatchResultWithPostInfo {294 with_weight(295 <Pallet<T>>::transfer(self, &from, &to, token, amount, nesting_budget),296 <CommonWeights<T>>::transfer(),297 )298 }299300 fn approve(301 &self,302 sender: T::CrossAccountId,303 spender: T::CrossAccountId,304 token: TokenId,305 amount: u128,306 ) -> DispatchResultWithPostInfo {307 with_weight(308 <Pallet<T>>::set_allowance(self, &sender, &spender, token, amount),309 <CommonWeights<T>>::approve(),310 )311 }312313 fn approve_from(314 &self,315 sender: T::CrossAccountId,316 from: T::CrossAccountId,317 to: T::CrossAccountId,318 token_id: TokenId,319 amount: u128,320 ) -> DispatchResultWithPostInfo {321 with_weight(322 <Pallet<T>>::set_allowance_from(self, &sender, &from, &to, token_id, amount),323 <CommonWeights<T>>::approve_from(),324 )325 }326327 fn transfer_from(328 &self,329 sender: T::CrossAccountId,330 from: T::CrossAccountId,331 to: T::CrossAccountId,332 token: TokenId,333 amount: u128,334 nesting_budget: &dyn Budget,335 ) -> DispatchResultWithPostInfo {336 with_weight(337 <Pallet<T>>::transfer_from(self, &sender, &from, &to, token, amount, nesting_budget),338 <CommonWeights<T>>::transfer_from(),339 )340 }341342 fn burn_from(343 &self,344 sender: T::CrossAccountId,345 from: T::CrossAccountId,346 token: TokenId,347 amount: u128,348 nesting_budget: &dyn Budget,349 ) -> DispatchResultWithPostInfo {350 with_weight(351 <Pallet<T>>::burn_from(self, &sender, &from, token, amount, nesting_budget),352 <CommonWeights<T>>::burn_from(),353 )354 }355356 fn set_collection_properties(357 &self,358 sender: T::CrossAccountId,359 properties: Vec<Property>,360 ) -> DispatchResultWithPostInfo {361 let weight = <CommonWeights<T>>::set_collection_properties(properties.len() as u32);362363 with_weight(364 <Pallet<T>>::set_collection_properties(self, &sender, properties),365 weight,366 )367 }368369 fn delete_collection_properties(370 &self,371 sender: &T::CrossAccountId,372 property_keys: Vec<PropertyKey>,373 ) -> DispatchResultWithPostInfo {374 let weight = <CommonWeights<T>>::delete_collection_properties(property_keys.len() as u32);375376 with_weight(377 <Pallet<T>>::delete_collection_properties(self, sender, property_keys),378 weight,379 )380 }381382 fn set_token_properties(383 &self,384 sender: T::CrossAccountId,385 token_id: TokenId,386 properties: Vec<Property>,387 nesting_budget: &dyn Budget,388 ) -> DispatchResultWithPostInfo {389 let weight = <CommonWeights<T>>::set_token_properties(properties.len() as u32);390391 with_weight(392 <Pallet<T>>::set_token_properties(393 self,394 &sender,395 token_id,396 properties.into_iter(),397 nesting_budget,398 ),399 weight,400 )401 }402403 fn set_token_property_permissions(404 &self,405 sender: &T::CrossAccountId,406 property_permissions: Vec<PropertyKeyPermission>,407 ) -> DispatchResultWithPostInfo {408 let weight =409 <CommonWeights<T>>::set_token_property_permissions(property_permissions.len() as u32);410411 with_weight(412 <Pallet<T>>::set_token_property_permissions(self, sender, property_permissions),413 weight,414 )415 }416417 fn delete_token_properties(418 &self,419 sender: T::CrossAccountId,420 token_id: TokenId,421 property_keys: Vec<PropertyKey>,422 nesting_budget: &dyn Budget,423 ) -> DispatchResultWithPostInfo {424 let weight = <CommonWeights<T>>::delete_token_properties(property_keys.len() as u32);425426 with_weight(427 <Pallet<T>>::delete_token_properties(428 self,429 &sender,430 token_id,431 property_keys.into_iter(),432 nesting_budget,433 ),434 weight,435 )436 }437438 fn get_token_properties_raw(439 &self,440 token_id: TokenId,441 ) -> Option<up_data_structs::TokenProperties> {442 <TokenProperties<T>>::get((self.id, token_id))443 }444445 fn set_token_properties_raw(&self, token_id: TokenId, map: up_data_structs::TokenProperties) {446 <TokenProperties<T>>::insert((self.id, token_id), map)447 }448449 fn check_nesting(450 &self,451 _sender: <T>::CrossAccountId,452 _from: (CollectionId, TokenId),453 _under: TokenId,454 _nesting_budget: &dyn Budget,455 ) -> sp_runtime::DispatchResult {456 fail!(<Error<T>>::RefungibleDisallowsNesting)457 }458459 fn nest(&self, _under: TokenId, _to_nest: (CollectionId, TokenId)) {}460461 fn unnest(&self, _under: TokenId, _to_nest: (CollectionId, TokenId)) {}462463 fn account_tokens(&self, account: T::CrossAccountId) -> Vec<TokenId> {464 <Owned<T>>::iter_prefix((self.id, account))465 .map(|(id, _)| id)466 .collect()467 }468469 fn collection_tokens(&self) -> Vec<TokenId> {470 <TotalSupply<T>>::iter_prefix((self.id,))471 .map(|(id, _)| id)472 .collect()473 }474475 fn token_exists(&self, token: TokenId) -> bool {476 <Pallet<T>>::token_exists(self, token)477 }478479 fn last_token_id(&self) -> TokenId {480 TokenId(<TokensMinted<T>>::get(self.id))481 }482483 fn token_owner(&self, token: TokenId) -> Result<T::CrossAccountId, TokenOwnerError> {484 <Pallet<T>>::token_owner(self.id, token)485 }486487 fn check_token_indirect_owner(488 &self,489 token: TokenId,490 maybe_owner: &T::CrossAccountId,491 nesting_budget: &dyn Budget,492 ) -> Result<bool, DispatchError> {493 let balance = self.balance(maybe_owner.clone(), token);494 let total_pieces: u128 = <Pallet<T>>::total_pieces(self.id, token).unwrap_or(u128::MAX);495 if balance != total_pieces {496 return Ok(false);497 }498499 let is_bundle_owner = <PalletStructure<T>>::check_indirectly_owned(500 maybe_owner.clone(),501 self.id,502 token,503 None,504 nesting_budget,505 )?;506507 Ok(is_bundle_owner)508 }509510 511 fn token_owners(&self, token: TokenId) -> Vec<T::CrossAccountId> {512 <Pallet<T>>::token_owners(self.id, token).unwrap_or_default()513 }514515 fn token_property(&self, token_id: TokenId, key: &PropertyKey) -> Option<PropertyValue> {516 <Pallet<T>>::token_properties((self.id, token_id))?517 .get(key)518 .cloned()519 }520521 fn token_properties(&self, token_id: TokenId, keys: Option<Vec<PropertyKey>>) -> Vec<Property> {522 let Some(properties) = <Pallet<T>>::token_properties((self.id, token_id)) else {523 return vec![];524 };525526 keys.map(|keys| {527 keys.into_iter()528 .filter_map(|key| {529 properties.get(&key).map(|value| Property {530 key,531 value: value.clone(),532 })533 })534 .collect()535 })536 .unwrap_or_else(|| {537 properties538 .into_iter()539 .map(|(key, value)| Property { key, value })540 .collect()541 })542 }543544 fn total_supply(&self) -> u32 {545 <Pallet<T>>::total_supply(self)546 }547548 fn account_balance(&self, account: T::CrossAccountId) -> u32 {549 <AccountBalance<T>>::get((self.id, account))550 }551552 fn balance(&self, account: T::CrossAccountId, token: TokenId) -> u128 {553 <Balance<T>>::get((self.id, token, account))554 }555556 fn allowance(557 &self,558 sender: T::CrossAccountId,559 spender: T::CrossAccountId,560 token: TokenId,561 ) -> u128 {562 <Allowance<T>>::get((self.id, token, sender, spender))563 }564565 fn refungible_extensions(&self) -> Option<&dyn RefungibleExtensions<T>> {566 Some(self)567 }568569 fn total_pieces(&self, token: TokenId) -> Option<u128> {570 <Pallet<T>>::total_pieces(self.id, token)571 }572573 fn set_allowance_for_all(574 &self,575 owner: T::CrossAccountId,576 operator: T::CrossAccountId,577 approve: bool,578 ) -> DispatchResultWithPostInfo {579 with_weight(580 <Pallet<T>>::set_allowance_for_all(self, &owner, &operator, approve),581 <CommonWeights<T>>::set_allowance_for_all(),582 )583 }584585 fn allowance_for_all(&self, owner: T::CrossAccountId, operator: T::CrossAccountId) -> bool {586 <Pallet<T>>::allowance_for_all(self, &owner, &operator)587 }588589 fn repair_item(&self, token: TokenId) -> DispatchResultWithPostInfo {590 with_weight(591 <Pallet<T>>::repair_item(self, token),592 <CommonWeights<T>>::force_repair_item(),593 )594 }595}596597impl<T: Config> RefungibleExtensions<T> for RefungibleHandle<T> {598 fn repartition(599 &self,600 owner: &T::CrossAccountId,601 token: TokenId,602 amount: u128,603 ) -> DispatchResultWithPostInfo {604 with_weight(605 <Pallet<T>>::repartition(self, owner, token, amount),606 <SelfWeightOf<T>>::repartition_item(),607 )608 }609}