1234567891011121314151617use core::marker::PhantomData;1819use frame_support::{20 dispatch::DispatchResultWithPostInfo, ensure, fail, traits::Get, weights::Weight,21};22use pallet_common::{23 init_token_properties_delta, weights::WeightInfo as _, with_weight, CommonCollectionOperations,24 CommonWeightInfo, RefungibleExtensions,25};26use pallet_structure::{Error as StructureError, Pallet as PalletStructure};27use sp_runtime::DispatchError;28use sp_std::{collections::btree_map::BTreeMap, vec, vec::Vec};29use up_data_structs::{30 budget::Budget, CollectionId, CreateItemExData, CreateRefungibleExMultipleOwners,31 CreateRefungibleExSingleOwner, Property, PropertyKey, PropertyKeyPermission, PropertyValue,32 TokenId, TokenOwnerError,33};3435use crate::{36 weights::WeightInfo, AccountBalance, Allowance, Balance, Config, CreateItemData, Error, Owned,37 Pallet, RefungibleHandle, SelfWeightOf, TokenProperties, TokensMinted, TotalSupply,38};3940macro_rules! max_weight_of {41 ($($method:ident ($($args:tt)*)),*) => {42 Weight::zero()43 $(44 .max(<SelfWeightOf<T>>::$method($($args)*))45 )*46 };47}4849pub struct CommonWeights<T: Config>(PhantomData<T>);50impl<T: Config> CommonWeightInfo<T::CrossAccountId> for CommonWeights<T> {51 fn create_multiple_items(data: &[up_data_structs::CreateItemData]) -> Weight {52 <SelfWeightOf<T>>::create_multiple_items(data.len() as u32).saturating_add(53 init_token_properties_delta::<T, _>(54 data.iter().map(|data| match data {55 up_data_structs::CreateItemData::ReFungible(rft_data) => {56 rft_data.properties.len() as u3257 }58 _ => 0,59 }),60 <SelfWeightOf<T>>::init_token_properties,61 ),62 )63 }6465 fn create_multiple_items_ex(call: &CreateItemExData<T::CrossAccountId>) -> Weight {66 match call {67 CreateItemExData::RefungibleMultipleOwners(i) => {68 <SelfWeightOf<T>>::create_multiple_items_ex_multiple_owners(i.users.len() as u32)69 .saturating_add(init_token_properties_delta::<T, _>(70 [i.properties.len() as u32].into_iter(),71 <SelfWeightOf<T>>::init_token_properties,72 ))73 }74 CreateItemExData::RefungibleMultipleItems(i) => {75 <SelfWeightOf<T>>::create_multiple_items_ex_multiple_items(i.len() as u32)76 .saturating_add(init_token_properties_delta::<T, _>(77 i.iter().map(|d| d.properties.len() as u32),78 <SelfWeightOf<T>>::init_token_properties,79 ))80 }81 _ => Weight::zero(),82 }83 }8485 fn burn_item() -> Weight {86 max_weight_of!(burn_item_partial(), burn_item_fully())87 }8889 fn set_collection_properties(amount: u32) -> Weight {90 <pallet_common::SelfWeightOf<T>>::set_collection_properties(amount)91 }9293 fn delete_collection_properties(amount: u32) -> Weight {94 <pallet_common::SelfWeightOf<T>>::delete_collection_properties(amount)95 }9697 fn set_token_properties(amount: u32) -> Weight {98 <SelfWeightOf<T>>::set_token_properties(amount)99 }100101 fn delete_token_properties(amount: u32) -> Weight {102 <SelfWeightOf<T>>::delete_token_properties(amount)103 }104105 fn set_token_property_permissions(amount: u32) -> Weight {106 <SelfWeightOf<T>>::set_token_property_permissions(amount)107 }108109 fn transfer() -> Weight {110 max_weight_of!(111 transfer_normal(),112 transfer_creating(),113 transfer_removing(),114 transfer_creating_removing()115 )116 }117118 fn approve() -> Weight {119 <SelfWeightOf<T>>::approve()120 }121122 fn approve_from() -> Weight {123 <SelfWeightOf<T>>::approve_from()124 }125126 fn transfer_from() -> Weight {127 max_weight_of!(128 transfer_from_normal(),129 transfer_from_creating(),130 transfer_from_removing(),131 transfer_from_creating_removing()132 )133 }134135 fn burn_from() -> Weight {136 <SelfWeightOf<T>>::burn_from()137 }138139 fn burn_recursively_self_raw() -> Weight {140 141 Self::burn_item() + T::DbWeight::get().reads(1)142 }143 fn burn_recursively_breadth_raw(_amount: u32) -> Weight {144 145 Weight::zero()146 }147148 fn token_owner() -> Weight {149 <SelfWeightOf<T>>::token_owner()150 }151152 fn set_allowance_for_all() -> Weight {153 <SelfWeightOf<T>>::set_allowance_for_all()154 }155156 fn force_repair_item() -> Weight {157 <SelfWeightOf<T>>::repair_item()158 }159}160161fn map_create_data<T: Config>(162 data: up_data_structs::CreateItemData,163 to: &T::CrossAccountId,164) -> Result<CreateItemData<T>, DispatchError> {165 match data {166 up_data_structs::CreateItemData::ReFungible(data) => Ok(CreateItemData::<T> {167 users: {168 let mut out = BTreeMap::new();169 out.insert(to.clone(), data.pieces);170 out.try_into().expect("limit > 0")171 },172 properties: data.properties,173 }),174 _ => fail!(<Error<T>>::NotRefungibleDataUsedToMintFungibleCollectionToken),175 }176}177178179180impl<T: Config> CommonCollectionOperations<T> for RefungibleHandle<T> {181 fn create_item(182 &self,183 sender: T::CrossAccountId,184 to: T::CrossAccountId,185 data: up_data_structs::CreateItemData,186 nesting_budget: &dyn Budget,187 ) -> DispatchResultWithPostInfo {188 let weight = <CommonWeights<T>>::create_item(&data);189 with_weight(190 <Pallet<T>>::create_item(191 self,192 &sender,193 map_create_data::<T>(data, &to)?,194 nesting_budget,195 ),196 weight,197 )198 }199200 fn create_multiple_items(201 &self,202 sender: T::CrossAccountId,203 to: T::CrossAccountId,204 data: Vec<up_data_structs::CreateItemData>,205 nesting_budget: &dyn Budget,206 ) -> DispatchResultWithPostInfo {207 let weight = <CommonWeights<T>>::create_multiple_items(&data);208 let data = data209 .into_iter()210 .map(|d| map_create_data::<T>(d, &to))211 .collect::<Result<Vec<_>, DispatchError>>()?;212213 with_weight(214 <Pallet<T>>::create_multiple_items(self, &sender, data, nesting_budget),215 weight,216 )217 }218219 fn create_multiple_items_ex(220 &self,221 sender: <T>::CrossAccountId,222 data: CreateItemExData<T::CrossAccountId>,223 nesting_budget: &dyn Budget,224 ) -> DispatchResultWithPostInfo {225 let weight = <CommonWeights<T>>::create_multiple_items_ex(&data);226 let data = match data {227 CreateItemExData::RefungibleMultipleOwners(CreateRefungibleExMultipleOwners {228 users,229 properties,230 }) => vec![CreateItemData::<T> { users, properties }],231 CreateItemExData::RefungibleMultipleItems(r) => r232 .into_inner()233 .into_iter()234 .map(235 |CreateRefungibleExSingleOwner {236 user,237 pieces,238 properties,239 }| CreateItemData::<T> {240 users: BTreeMap::from([(user, pieces)])241 .try_into()242 .expect("limit >= 1"),243 properties,244 },245 )246 .collect(),247 _ => fail!(<Error<T>>::NotRefungibleDataUsedToMintFungibleCollectionToken),248 };249250 with_weight(251 <Pallet<T>>::create_multiple_items(self, &sender, data, nesting_budget),252 weight,253 )254 }255256 fn burn_item(257 &self,258 sender: T::CrossAccountId,259 token: TokenId,260 amount: u128,261 ) -> DispatchResultWithPostInfo {262 with_weight(263 <Pallet<T>>::burn(self, &sender, token, amount),264 <CommonWeights<T>>::burn_item(),265 )266 }267268 fn burn_item_recursively(269 &self,270 sender: T::CrossAccountId,271 token: TokenId,272 self_budget: &dyn Budget,273 _breadth_budget: &dyn Budget,274 ) -> DispatchResultWithPostInfo {275 ensure!(self_budget.consume(), <StructureError<T>>::DepthLimit,);276 with_weight(277 <Pallet<T>>::burn(278 self,279 &sender,280 token,281 <Balance<T>>::get((self.id, token, &sender)),282 ),283 <CommonWeights<T>>::burn_recursively_self_raw(),284 )285 }286287 fn transfer(288 &self,289 from: T::CrossAccountId,290 to: T::CrossAccountId,291 token: TokenId,292 amount: u128,293 nesting_budget: &dyn Budget,294 ) -> DispatchResultWithPostInfo {295 with_weight(296 <Pallet<T>>::transfer(self, &from, &to, token, amount, nesting_budget),297 <CommonWeights<T>>::transfer(),298 )299 }300301 fn approve(302 &self,303 sender: T::CrossAccountId,304 spender: T::CrossAccountId,305 token: TokenId,306 amount: u128,307 ) -> DispatchResultWithPostInfo {308 with_weight(309 <Pallet<T>>::set_allowance(self, &sender, &spender, token, amount),310 <CommonWeights<T>>::approve(),311 )312 }313314 fn approve_from(315 &self,316 sender: T::CrossAccountId,317 from: T::CrossAccountId,318 to: T::CrossAccountId,319 token_id: TokenId,320 amount: u128,321 ) -> DispatchResultWithPostInfo {322 with_weight(323 <Pallet<T>>::set_allowance_from(self, &sender, &from, &to, token_id, amount),324 <CommonWeights<T>>::approve_from(),325 )326 }327328 fn transfer_from(329 &self,330 sender: T::CrossAccountId,331 from: T::CrossAccountId,332 to: T::CrossAccountId,333 token: TokenId,334 amount: u128,335 nesting_budget: &dyn Budget,336 ) -> DispatchResultWithPostInfo {337 with_weight(338 <Pallet<T>>::transfer_from(self, &sender, &from, &to, token, amount, nesting_budget),339 <CommonWeights<T>>::transfer_from(),340 )341 }342343 fn burn_from(344 &self,345 sender: T::CrossAccountId,346 from: T::CrossAccountId,347 token: TokenId,348 amount: u128,349 nesting_budget: &dyn Budget,350 ) -> DispatchResultWithPostInfo {351 with_weight(352 <Pallet<T>>::burn_from(self, &sender, &from, token, amount, nesting_budget),353 <CommonWeights<T>>::burn_from(),354 )355 }356357 fn set_collection_properties(358 &self,359 sender: T::CrossAccountId,360 properties: Vec<Property>,361 ) -> DispatchResultWithPostInfo {362 let weight = <CommonWeights<T>>::set_collection_properties(properties.len() as u32);363364 with_weight(365 <Pallet<T>>::set_collection_properties(self, &sender, properties),366 weight,367 )368 }369370 fn delete_collection_properties(371 &self,372 sender: &T::CrossAccountId,373 property_keys: Vec<PropertyKey>,374 ) -> DispatchResultWithPostInfo {375 let weight = <CommonWeights<T>>::delete_collection_properties(property_keys.len() as u32);376377 with_weight(378 <Pallet<T>>::delete_collection_properties(self, sender, property_keys),379 weight,380 )381 }382383 fn set_token_properties(384 &self,385 sender: T::CrossAccountId,386 token_id: TokenId,387 properties: Vec<Property>,388 nesting_budget: &dyn Budget,389 ) -> DispatchResultWithPostInfo {390 let weight = <CommonWeights<T>>::set_token_properties(properties.len() as u32);391392 with_weight(393 <Pallet<T>>::set_token_properties(394 self,395 &sender,396 token_id,397 properties.into_iter(),398 nesting_budget,399 ),400 weight,401 )402 }403404 fn set_token_property_permissions(405 &self,406 sender: &T::CrossAccountId,407 property_permissions: Vec<PropertyKeyPermission>,408 ) -> DispatchResultWithPostInfo {409 let weight =410 <CommonWeights<T>>::set_token_property_permissions(property_permissions.len() as u32);411412 with_weight(413 <Pallet<T>>::set_token_property_permissions(self, sender, property_permissions),414 weight,415 )416 }417418 fn delete_token_properties(419 &self,420 sender: T::CrossAccountId,421 token_id: TokenId,422 property_keys: Vec<PropertyKey>,423 nesting_budget: &dyn Budget,424 ) -> DispatchResultWithPostInfo {425 let weight = <CommonWeights<T>>::delete_token_properties(property_keys.len() as u32);426427 with_weight(428 <Pallet<T>>::delete_token_properties(429 self,430 &sender,431 token_id,432 property_keys.into_iter(),433 nesting_budget,434 ),435 weight,436 )437 }438439 fn get_token_properties_raw(440 &self,441 token_id: TokenId,442 ) -> Option<up_data_structs::TokenProperties> {443 <TokenProperties<T>>::get((self.id, token_id))444 }445446 fn set_token_properties_raw(&self, token_id: TokenId, map: up_data_structs::TokenProperties) {447 <TokenProperties<T>>::insert((self.id, token_id), map)448 }449450 fn check_nesting(451 &self,452 _sender: <T>::CrossAccountId,453 _from: (CollectionId, TokenId),454 _under: TokenId,455 _nesting_budget: &dyn Budget,456 ) -> sp_runtime::DispatchResult {457 fail!(<Error<T>>::RefungibleDisallowsNesting)458 }459460 fn nest(&self, _under: TokenId, _to_nest: (CollectionId, TokenId)) {}461462 fn unnest(&self, _under: TokenId, _to_nest: (CollectionId, TokenId)) {}463464 fn account_tokens(&self, account: T::CrossAccountId) -> Vec<TokenId> {465 <Owned<T>>::iter_prefix((self.id, account))466 .map(|(id, _)| id)467 .collect()468 }469470 fn collection_tokens(&self) -> Vec<TokenId> {471 <TotalSupply<T>>::iter_prefix((self.id,))472 .map(|(id, _)| id)473 .collect()474 }475476 fn token_exists(&self, token: TokenId) -> bool {477 <Pallet<T>>::token_exists(self, token)478 }479480 fn last_token_id(&self) -> TokenId {481 TokenId(<TokensMinted<T>>::get(self.id))482 }483484 fn token_owner(&self, token: TokenId) -> Result<T::CrossAccountId, TokenOwnerError> {485 <Pallet<T>>::token_owner(self.id, token)486 }487488 fn check_token_indirect_owner(489 &self,490 token: TokenId,491 maybe_owner: &T::CrossAccountId,492 nesting_budget: &dyn Budget,493 ) -> Result<bool, DispatchError> {494 let balance = self.balance(maybe_owner.clone(), token);495 let total_pieces: u128 = <Pallet<T>>::total_pieces(self.id, token).unwrap_or(u128::MAX);496 if balance != total_pieces {497 return Ok(false);498 }499500 <PalletStructure<T>>::check_indirectly_owned(501 maybe_owner.clone(),502 self.id,503 token,504 None,505 nesting_budget,506 )507 }508509 510 fn token_owners(&self, token: TokenId) -> Vec<T::CrossAccountId> {511 <Pallet<T>>::token_owners(self.id, token).unwrap_or_default()512 }513514 fn token_property(&self, token_id: TokenId, key: &PropertyKey) -> Option<PropertyValue> {515 <Pallet<T>>::token_properties((self.id, token_id))?516 .get(key)517 .cloned()518 }519520 fn token_properties(&self, token_id: TokenId, keys: Option<Vec<PropertyKey>>) -> Vec<Property> {521 let Some(properties) = <Pallet<T>>::token_properties((self.id, token_id)) else {522 return vec![];523 };524525 keys.map(|keys| {526 keys.into_iter()527 .filter_map(|key| {528 properties.get(&key).map(|value| Property {529 key,530 value: value.clone(),531 })532 })533 .collect()534 })535 .unwrap_or_else(|| {536 properties537 .into_iter()538 .map(|(key, value)| Property { key, value })539 .collect()540 })541 }542543 fn total_supply(&self) -> u32 {544 <Pallet<T>>::total_supply(self)545 }546547 fn account_balance(&self, account: T::CrossAccountId) -> u32 {548 <AccountBalance<T>>::get((self.id, account))549 }550551 fn balance(&self, account: T::CrossAccountId, token: TokenId) -> u128 {552 <Balance<T>>::get((self.id, token, account))553 }554555 fn allowance(556 &self,557 sender: T::CrossAccountId,558 spender: T::CrossAccountId,559 token: TokenId,560 ) -> u128 {561 <Allowance<T>>::get((self.id, token, sender, spender))562 }563564 fn refungible_extensions(&self) -> Option<&dyn RefungibleExtensions<T>> {565 Some(self)566 }567568 fn total_pieces(&self, token: TokenId) -> Option<u128> {569 <Pallet<T>>::total_pieces(self.id, token)570 }571572 fn set_allowance_for_all(573 &self,574 owner: T::CrossAccountId,575 operator: T::CrossAccountId,576 approve: bool,577 ) -> DispatchResultWithPostInfo {578 with_weight(579 <Pallet<T>>::set_allowance_for_all(self, &owner, &operator, approve),580 <CommonWeights<T>>::set_allowance_for_all(),581 )582 }583584 fn allowance_for_all(&self, owner: T::CrossAccountId, operator: T::CrossAccountId) -> bool {585 <Pallet<T>>::allowance_for_all(self, &owner, &operator)586 }587588 fn repair_item(&self, token: TokenId) -> DispatchResultWithPostInfo {589 with_weight(590 <Pallet<T>>::repair_item(self, token),591 <CommonWeights<T>>::force_repair_item(),592 )593 }594}595596impl<T: Config> RefungibleExtensions<T> for RefungibleHandle<T> {597 fn repartition(598 &self,599 owner: &T::CrossAccountId,600 token: TokenId,601 amount: u128,602 ) -> DispatchResultWithPostInfo {603 with_weight(604 <Pallet<T>>::repartition(self, owner, token, amount),605 <SelfWeightOf<T>>::repartition_item(),606 )607 }608}