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 <SelfWeightOf<T>>::create_multiple_items(data.len() as u32).saturating_add(51 write_token_properties_total_weight::<T, _>(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 <SelfWeightOf<T>>::write_token_properties,59 ),60 )61 }6263 fn create_multiple_items_ex(call: &CreateItemExData<T::CrossAccountId>) -> Weight {64 match call {65 CreateItemExData::RefungibleMultipleOwners(i) => {66 <SelfWeightOf<T>>::create_multiple_items_ex_multiple_owners(i.users.len() as u32)67 .saturating_add(write_token_properties_total_weight::<T, _>(68 [i.properties.len() as u32].into_iter(),69 <SelfWeightOf<T>>::write_token_properties,70 ))71 }72 CreateItemExData::RefungibleMultipleItems(i) => {73 <SelfWeightOf<T>>::create_multiple_items_ex_multiple_items(i.len() as u32)74 .saturating_add(write_token_properties_total_weight::<T, _>(75 i.iter().map(|d| d.properties.len() as u32),76 <SelfWeightOf<T>>::write_token_properties,77 ))78 }79 _ => Weight::zero(),80 }81 }8283 fn burn_item() -> Weight {84 max_weight_of!(burn_item_partial(), burn_item_fully())85 }8687 fn set_collection_properties(amount: u32) -> Weight {88 <pallet_common::SelfWeightOf<T>>::set_collection_properties(amount)89 }9091 fn set_token_properties(amount: u32) -> Weight {92 write_token_properties_total_weight::<T, _>([amount].into_iter(), |amount| {93 <SelfWeightOf<T>>::load_token_properties()94 + <SelfWeightOf<T>>::write_token_properties(amount)95 })96 }9798 fn set_token_property_permissions(amount: u32) -> Weight {99 <SelfWeightOf<T>>::set_token_property_permissions(amount)100 }101102 fn transfer() -> Weight {103 max_weight_of!(104 transfer_normal(),105 transfer_creating(),106 transfer_removing(),107 transfer_creating_removing()108 )109 }110111 fn approve() -> Weight {112 <SelfWeightOf<T>>::approve()113 }114115 fn approve_from() -> Weight {116 <SelfWeightOf<T>>::approve_from()117 }118119 fn transfer_from() -> Weight {120 max_weight_of!(121 transfer_from_normal(),122 transfer_from_creating(),123 transfer_from_removing(),124 transfer_from_creating_removing()125 )126 }127128 fn burn_from() -> Weight {129 <SelfWeightOf<T>>::burn_from()130 }131132 fn set_allowance_for_all() -> Weight {133 <SelfWeightOf<T>>::set_allowance_for_all()134 }135136 fn force_repair_item() -> Weight {137 <SelfWeightOf<T>>::repair_item()138 }139}140141fn map_create_data<T: Config>(142 data: up_data_structs::CreateItemData,143 to: &T::CrossAccountId,144) -> Result<CreateItemData<T>, DispatchError> {145 match data {146 up_data_structs::CreateItemData::ReFungible(data) => Ok(CreateItemData::<T> {147 users: {148 let mut out = BTreeMap::new();149 out.insert(to.clone(), data.pieces);150 out.try_into().expect("limit > 0")151 },152 properties: data.properties,153 }),154 _ => fail!(<Error<T>>::NotRefungibleDataUsedToMintFungibleCollectionToken),155 }156}157158159160impl<T: Config> CommonCollectionOperations<T> for RefungibleHandle<T> {161 fn create_item(162 &self,163 sender: T::CrossAccountId,164 to: T::CrossAccountId,165 data: up_data_structs::CreateItemData,166 nesting_budget: &dyn Budget,167 ) -> DispatchResultWithPostInfo {168 let weight = <CommonWeights<T>>::create_item(&data);169 with_weight(170 <Pallet<T>>::create_item(171 self,172 &sender,173 map_create_data::<T>(data, &to)?,174 nesting_budget,175 ),176 weight,177 )178 }179180 fn create_multiple_items(181 &self,182 sender: T::CrossAccountId,183 to: T::CrossAccountId,184 data: Vec<up_data_structs::CreateItemData>,185 nesting_budget: &dyn Budget,186 ) -> DispatchResultWithPostInfo {187 let weight = <CommonWeights<T>>::create_multiple_items(&data);188 let data = data189 .into_iter()190 .map(|d| map_create_data::<T>(d, &to))191 .collect::<Result<Vec<_>, DispatchError>>()?;192193 with_weight(194 <Pallet<T>>::create_multiple_items(self, &sender, data, nesting_budget),195 weight,196 )197 }198199 fn create_multiple_items_ex(200 &self,201 sender: <T>::CrossAccountId,202 data: CreateItemExData<T::CrossAccountId>,203 nesting_budget: &dyn Budget,204 ) -> DispatchResultWithPostInfo {205 let weight = <CommonWeights<T>>::create_multiple_items_ex(&data);206 let data = match data {207 CreateItemExData::RefungibleMultipleOwners(CreateRefungibleExMultipleOwners {208 users,209 properties,210 }) => vec![CreateItemData::<T> { users, properties }],211 CreateItemExData::RefungibleMultipleItems(r) => r212 .into_inner()213 .into_iter()214 .map(215 |CreateRefungibleExSingleOwner {216 user,217 pieces,218 properties,219 }| CreateItemData::<T> {220 users: BTreeMap::from([(user, pieces)])221 .try_into()222 .expect("limit >= 1"),223 properties,224 },225 )226 .collect(),227 _ => fail!(<Error<T>>::NotRefungibleDataUsedToMintFungibleCollectionToken),228 };229230 with_weight(231 <Pallet<T>>::create_multiple_items(self, &sender, data, nesting_budget),232 weight,233 )234 }235236 fn burn_item(237 &self,238 sender: T::CrossAccountId,239 token: TokenId,240 amount: u128,241 ) -> DispatchResultWithPostInfo {242 with_weight(243 <Pallet<T>>::burn(self, &sender, token, amount),244 <CommonWeights<T>>::burn_item(),245 )246 }247248 fn transfer(249 &self,250 from: T::CrossAccountId,251 to: T::CrossAccountId,252 token: TokenId,253 amount: u128,254 nesting_budget: &dyn Budget,255 ) -> DispatchResultWithPostInfo {256 with_weight(257 <Pallet<T>>::transfer(self, &from, &to, token, amount, nesting_budget),258 <CommonWeights<T>>::transfer(),259 )260 }261262 fn approve(263 &self,264 sender: T::CrossAccountId,265 spender: T::CrossAccountId,266 token: TokenId,267 amount: u128,268 ) -> DispatchResultWithPostInfo {269 with_weight(270 <Pallet<T>>::set_allowance(self, &sender, &spender, token, amount),271 <CommonWeights<T>>::approve(),272 )273 }274275 fn approve_from(276 &self,277 sender: T::CrossAccountId,278 from: T::CrossAccountId,279 to: T::CrossAccountId,280 token_id: TokenId,281 amount: u128,282 ) -> DispatchResultWithPostInfo {283 with_weight(284 <Pallet<T>>::set_allowance_from(self, &sender, &from, &to, token_id, amount),285 <CommonWeights<T>>::approve_from(),286 )287 }288289 fn transfer_from(290 &self,291 sender: T::CrossAccountId,292 from: T::CrossAccountId,293 to: T::CrossAccountId,294 token: TokenId,295 amount: u128,296 nesting_budget: &dyn Budget,297 ) -> DispatchResultWithPostInfo {298 with_weight(299 <Pallet<T>>::transfer_from(self, &sender, &from, &to, token, amount, nesting_budget),300 <CommonWeights<T>>::transfer_from(),301 )302 }303304 fn burn_from(305 &self,306 sender: T::CrossAccountId,307 from: T::CrossAccountId,308 token: TokenId,309 amount: u128,310 nesting_budget: &dyn Budget,311 ) -> DispatchResultWithPostInfo {312 with_weight(313 <Pallet<T>>::burn_from(self, &sender, &from, token, amount, nesting_budget),314 <CommonWeights<T>>::burn_from(),315 )316 }317318 fn set_collection_properties(319 &self,320 sender: T::CrossAccountId,321 properties: Vec<Property>,322 ) -> DispatchResultWithPostInfo {323 let weight = <CommonWeights<T>>::set_collection_properties(properties.len() as u32);324325 with_weight(326 <Pallet<T>>::set_collection_properties(self, &sender, properties),327 weight,328 )329 }330331 fn delete_collection_properties(332 &self,333 sender: &T::CrossAccountId,334 property_keys: Vec<PropertyKey>,335 ) -> DispatchResultWithPostInfo {336 let weight = <CommonWeights<T>>::delete_collection_properties(property_keys.len() as u32);337338 with_weight(339 <Pallet<T>>::delete_collection_properties(self, sender, property_keys),340 weight,341 )342 }343344 fn set_token_properties(345 &self,346 sender: T::CrossAccountId,347 token_id: TokenId,348 properties: Vec<Property>,349 nesting_budget: &dyn Budget,350 ) -> DispatchResultWithPostInfo {351 let weight = <CommonWeights<T>>::set_token_properties(properties.len() as u32);352353 with_weight(354 <Pallet<T>>::set_token_properties(355 self,356 &sender,357 token_id,358 properties.into_iter(),359 nesting_budget,360 ),361 weight,362 )363 }364365 fn set_token_property_permissions(366 &self,367 sender: &T::CrossAccountId,368 property_permissions: Vec<PropertyKeyPermission>,369 ) -> DispatchResultWithPostInfo {370 let weight =371 <CommonWeights<T>>::set_token_property_permissions(property_permissions.len() as u32);372373 with_weight(374 <Pallet<T>>::set_token_property_permissions(self, sender, property_permissions),375 weight,376 )377 }378379 fn delete_token_properties(380 &self,381 sender: T::CrossAccountId,382 token_id: TokenId,383 property_keys: Vec<PropertyKey>,384 nesting_budget: &dyn Budget,385 ) -> DispatchResultWithPostInfo {386 let weight = <CommonWeights<T>>::delete_token_properties(property_keys.len() as u32);387388 with_weight(389 <Pallet<T>>::delete_token_properties(390 self,391 &sender,392 token_id,393 property_keys.into_iter(),394 nesting_budget,395 ),396 weight,397 )398 }399400 fn get_token_properties_raw(401 &self,402 token_id: TokenId,403 ) -> Option<up_data_structs::TokenProperties> {404 <TokenProperties<T>>::get((self.id, token_id))405 }406407 fn set_token_properties_raw(&self, token_id: TokenId, map: up_data_structs::TokenProperties) {408 <TokenProperties<T>>::insert((self.id, token_id), map)409 }410411 fn check_nesting(412 &self,413 _sender: <T>::CrossAccountId,414 _from: (CollectionId, TokenId),415 _under: TokenId,416 _nesting_budget: &dyn Budget,417 ) -> sp_runtime::DispatchResult {418 fail!(<Error<T>>::RefungibleDisallowsNesting)419 }420421 fn nest(&self, _under: TokenId, _to_nest: (CollectionId, TokenId)) {}422423 fn unnest(&self, _under: TokenId, _to_nest: (CollectionId, TokenId)) {}424425 fn account_tokens(&self, account: T::CrossAccountId) -> Vec<TokenId> {426 <Owned<T>>::iter_prefix((self.id, account))427 .map(|(id, _)| id)428 .collect()429 }430431 fn collection_tokens(&self) -> Vec<TokenId> {432 <TotalSupply<T>>::iter_prefix((self.id,))433 .map(|(id, _)| id)434 .collect()435 }436437 fn token_exists(&self, token: TokenId) -> bool {438 <Pallet<T>>::token_exists(self, token)439 }440441 fn last_token_id(&self) -> TokenId {442 TokenId(<TokensMinted<T>>::get(self.id))443 }444445 fn token_owner(&self, token: TokenId) -> Result<T::CrossAccountId, TokenOwnerError> {446 <Pallet<T>>::token_owner(self.id, token)447 }448449 fn check_token_indirect_owner(450 &self,451 token: TokenId,452 maybe_owner: &T::CrossAccountId,453 nesting_budget: &dyn Budget,454 ) -> Result<bool, DispatchError> {455 let balance = self.balance(maybe_owner.clone(), token);456 let total_pieces: u128 = <Pallet<T>>::total_pieces(self.id, token).unwrap_or(u128::MAX);457 if balance != total_pieces {458 return Ok(false);459 }460461 <PalletStructure<T>>::check_indirectly_owned(462 maybe_owner.clone(),463 self.id,464 token,465 None,466 nesting_budget,467 )468 }469470 471 fn token_owners(&self, token: TokenId) -> Vec<T::CrossAccountId> {472 <Pallet<T>>::token_owners(self.id, token).unwrap_or_default()473 }474475 fn token_property(&self, token_id: TokenId, key: &PropertyKey) -> Option<PropertyValue> {476 <Pallet<T>>::token_properties((self.id, token_id))?477 .get(key)478 .cloned()479 }480481 fn token_properties(&self, token_id: TokenId, keys: Option<Vec<PropertyKey>>) -> Vec<Property> {482 let Some(properties) = <Pallet<T>>::token_properties((self.id, token_id)) else {483 return vec![];484 };485486 keys.map(|keys| {487 keys.into_iter()488 .filter_map(|key| {489 properties.get(&key).map(|value| Property {490 key,491 value: value.clone(),492 })493 })494 .collect()495 })496 .unwrap_or_else(|| {497 properties498 .into_iter()499 .map(|(key, value)| Property { key, value })500 .collect()501 })502 }503504 fn total_supply(&self) -> u32 {505 <Pallet<T>>::total_supply(self)506 }507508 fn account_balance(&self, account: T::CrossAccountId) -> u32 {509 <AccountBalance<T>>::get((self.id, account))510 }511512 fn balance(&self, account: T::CrossAccountId, token: TokenId) -> u128 {513 <Balance<T>>::get((self.id, token, account))514 }515516 fn allowance(517 &self,518 sender: T::CrossAccountId,519 spender: T::CrossAccountId,520 token: TokenId,521 ) -> u128 {522 <Allowance<T>>::get((self.id, token, sender, spender))523 }524525 fn refungible_extensions(&self) -> Option<&dyn RefungibleExtensions<T>> {526 Some(self)527 }528529 fn total_pieces(&self, token: TokenId) -> Option<u128> {530 <Pallet<T>>::total_pieces(self.id, token)531 }532533 fn set_allowance_for_all(534 &self,535 owner: T::CrossAccountId,536 operator: T::CrossAccountId,537 approve: bool,538 ) -> DispatchResultWithPostInfo {539 with_weight(540 <Pallet<T>>::set_allowance_for_all(self, &owner, &operator, approve),541 <CommonWeights<T>>::set_allowance_for_all(),542 )543 }544545 fn allowance_for_all(&self, owner: T::CrossAccountId, operator: T::CrossAccountId) -> bool {546 <Pallet<T>>::allowance_for_all(self, &owner, &operator)547 }548549 fn repair_item(&self, token: TokenId) -> DispatchResultWithPostInfo {550 with_weight(551 <Pallet<T>>::repair_item(self, token),552 <CommonWeights<T>>::force_repair_item(),553 )554 }555}556557impl<T: Config> RefungibleExtensions<T> for RefungibleHandle<T> {558 fn repartition(559 &self,560 owner: &T::CrossAccountId,561 token: TokenId,562 amount: u128,563 ) -> DispatchResultWithPostInfo {564 with_weight(565 <Pallet<T>>::repartition(self, owner, token, amount),566 <SelfWeightOf<T>>::repartition_item(),567 )568 }569}