1234567891011121314151617use core::marker::PhantomData;1819use frame_support::{dispatch::DispatchResultWithPostInfo, ensure, fail, weights::Weight};20use pallet_common::{21 weights::WeightInfo as _, with_weight, write_token_properties_total_weight,22 CommonCollectionOperations, CommonWeightInfo, RefungibleExtensions,23 SelfWeightOf as PalletCommonWeightOf,24};25use pallet_structure::Pallet as PalletStructure;26use sp_runtime::DispatchError;27use sp_std::{vec, vec::Vec};28use up_data_structs::{29 budget::Budget, CollectionId, CreateItemExData, Property, PropertyKey, PropertyKeyPermission,30 PropertyValue, TokenId, TokenOwnerError,31};3233use crate::{34 weights::WeightInfo, AccountBalance, Allowance, Config, CreateItemData, Error,35 NonfungibleHandle, Owned, Pallet, SelfWeightOf, TokenData, TokenProperties, TokensMinted,36};3738pub struct CommonWeights<T: Config>(PhantomData<T>);39impl<T: Config> CommonWeightInfo<T::CrossAccountId> for CommonWeights<T> {40 fn create_multiple_items_ex(data: &CreateItemExData<T::CrossAccountId>) -> Weight {41 match data {42 CreateItemExData::NFT(t) => <SelfWeightOf<T>>::create_multiple_items_ex(t.len() as u32)43 .saturating_add(write_token_properties_total_weight::<T, _>(44 t.iter().map(|t| t.properties.len() as u32),45 <SelfWeightOf<T>>::write_token_properties,46 )),47 _ => Weight::zero(),48 }49 }5051 fn create_multiple_items(data: &[up_data_structs::CreateItemData]) -> Weight {52 <SelfWeightOf<T>>::create_multiple_items(data.len() as u32).saturating_add(53 write_token_properties_total_weight::<T, _>(54 data.iter().map(|t| match t {55 up_data_structs::CreateItemData::NFT(n) => n.properties.len() as u32,56 _ => 0,57 }),58 <SelfWeightOf<T>>::write_token_properties,59 ),60 )61 }6263 fn burn_item() -> Weight {64 <SelfWeightOf<T>>::burn_item()65 }6667 fn set_collection_properties(amount: u32) -> Weight {68 <pallet_common::SelfWeightOf<T>>::set_collection_properties(amount)69 }7071 fn set_token_properties(amount: u32) -> Weight {72 write_token_properties_total_weight::<T, _>([amount].into_iter(), |amount| {73 <SelfWeightOf<T>>::load_token_properties()74 .saturating_add(<SelfWeightOf<T>>::write_token_properties(amount))75 })76 }7778 fn delete_token_properties(amount: u32) -> Weight {79 Self::set_token_properties(amount)80 }8182 fn set_token_property_permissions(amount: u32) -> Weight {83 <SelfWeightOf<T>>::set_token_property_permissions(amount)84 }8586 fn transfer() -> Weight {87 <SelfWeightOf<T>>::transfer_raw()88 .saturating_add(<PalletCommonWeightOf<T>>::check_accesslist().saturating_mul(2))89 }9091 fn approve() -> Weight {92 <SelfWeightOf<T>>::approve()93 }9495 fn approve_from() -> Weight {96 <SelfWeightOf<T>>::approve_from()97 }9899 fn transfer_from() -> Weight {100 Self::transfer().saturating_add(<SelfWeightOf<T>>::check_allowed_raw())101 }102103 fn burn_from() -> Weight {104 <SelfWeightOf<T>>::burn_from()105 }106107 fn set_allowance_for_all() -> Weight {108 <SelfWeightOf<T>>::set_allowance_for_all()109 }110111 fn force_repair_item() -> Weight {112 <SelfWeightOf<T>>::repair_item()113 }114}115116fn map_create_data<T: Config>(117 data: up_data_structs::CreateItemData,118 to: &T::CrossAccountId,119) -> Result<CreateItemData<T>, DispatchError> {120 match data {121 up_data_structs::CreateItemData::NFT(data) => Ok(CreateItemData::<T> {122 properties: data.properties,123 owner: to.clone(),124 }),125 _ => fail!(<Error<T>>::NotNonfungibleDataUsedToMintFungibleCollectionToken),126 }127}128129130131impl<T: Config> CommonCollectionOperations<T> for NonfungibleHandle<T> {132 fn create_item(133 &self,134 sender: T::CrossAccountId,135 to: T::CrossAccountId,136 data: up_data_structs::CreateItemData,137 nesting_budget: &dyn Budget,138 ) -> DispatchResultWithPostInfo {139 let weight = <CommonWeights<T>>::create_item(&data);140 with_weight(141 <Pallet<T>>::create_item(142 self,143 &sender,144 map_create_data::<T>(data, &to)?,145 nesting_budget,146 ),147 weight,148 )149 }150151 fn create_multiple_items(152 &self,153 sender: T::CrossAccountId,154 to: T::CrossAccountId,155 data: Vec<up_data_structs::CreateItemData>,156 nesting_budget: &dyn Budget,157 ) -> DispatchResultWithPostInfo {158 let weight = <CommonWeights<T>>::create_multiple_items(&data);159 let data = data160 .into_iter()161 .map(|d| map_create_data::<T>(d, &to))162 .collect::<Result<Vec<_>, DispatchError>>()?;163164 with_weight(165 <Pallet<T>>::create_multiple_items(self, &sender, data, nesting_budget),166 weight,167 )168 }169170 fn create_multiple_items_ex(171 &self,172 sender: <T>::CrossAccountId,173 data: up_data_structs::CreateItemExData<<T>::CrossAccountId>,174 nesting_budget: &dyn Budget,175 ) -> DispatchResultWithPostInfo {176 let weight = <CommonWeights<T>>::create_multiple_items_ex(&data);177 let data = match data {178 up_data_structs::CreateItemExData::NFT(nft) => nft,179 _ => fail!(Error::<T>::NotNonfungibleDataUsedToMintFungibleCollectionToken),180 };181182 with_weight(183 <Pallet<T>>::create_multiple_items(self, &sender, data.into_inner(), nesting_budget),184 weight,185 )186 }187188 fn set_collection_properties(189 &self,190 sender: T::CrossAccountId,191 properties: Vec<Property>,192 ) -> DispatchResultWithPostInfo {193 let weight = <CommonWeights<T>>::set_collection_properties(properties.len() as u32);194195 with_weight(196 <Pallet<T>>::set_collection_properties(self, &sender, properties),197 weight,198 )199 }200201 fn delete_collection_properties(202 &self,203 sender: &T::CrossAccountId,204 property_keys: Vec<PropertyKey>,205 ) -> DispatchResultWithPostInfo {206 let weight = <CommonWeights<T>>::delete_collection_properties(property_keys.len() as u32);207208 with_weight(209 <Pallet<T>>::delete_collection_properties(self, sender, property_keys),210 weight,211 )212 }213214 fn set_token_properties(215 &self,216 sender: T::CrossAccountId,217 token_id: TokenId,218 properties: Vec<Property>,219 nesting_budget: &dyn Budget,220 ) -> DispatchResultWithPostInfo {221 let weight = <CommonWeights<T>>::set_token_properties(properties.len() as u32);222223 with_weight(224 <Pallet<T>>::set_token_properties(225 self,226 &sender,227 token_id,228 properties.into_iter(),229 nesting_budget,230 ),231 weight,232 )233 }234235 fn delete_token_properties(236 &self,237 sender: T::CrossAccountId,238 token_id: TokenId,239 property_keys: Vec<PropertyKey>,240 nesting_budget: &dyn Budget,241 ) -> DispatchResultWithPostInfo {242 let weight = <CommonWeights<T>>::delete_token_properties(property_keys.len() as u32);243244 with_weight(245 <Pallet<T>>::delete_token_properties(246 self,247 &sender,248 token_id,249 property_keys.into_iter(),250 nesting_budget,251 ),252 weight,253 )254 }255256 fn get_token_properties_raw(257 &self,258 token_id: TokenId,259 ) -> Option<up_data_structs::TokenProperties> {260 <TokenProperties<T>>::get((self.id, token_id))261 }262263 fn set_token_properties_raw(&self, token_id: TokenId, map: up_data_structs::TokenProperties) {264 <TokenProperties<T>>::insert((self.id, token_id), map)265 }266267 fn set_token_property_permissions(268 &self,269 sender: &T::CrossAccountId,270 property_permissions: Vec<PropertyKeyPermission>,271 ) -> DispatchResultWithPostInfo {272 let weight =273 <CommonWeights<T>>::set_token_property_permissions(property_permissions.len() as u32);274275 with_weight(276 <Pallet<T>>::set_token_property_permissions(self, sender, property_permissions),277 weight,278 )279 }280281 fn burn_item(282 &self,283 sender: T::CrossAccountId,284 token: TokenId,285 amount: u128,286 ) -> DispatchResultWithPostInfo {287 ensure!(amount <= 1, <Error<T>>::NonfungibleItemsHaveNoAmount);288 if amount == 1 {289 with_weight(290 <Pallet<T>>::burn(self, &sender, token),291 <CommonWeights<T>>::burn_item(),292 )293 } else {294 <Pallet<T>>::check_token_immediate_ownership(self, token, &sender)?;295 Ok(().into())296 }297 }298299 fn transfer(300 &self,301 from: T::CrossAccountId,302 to: T::CrossAccountId,303 token: TokenId,304 amount: u128,305 nesting_budget: &dyn Budget,306 ) -> DispatchResultWithPostInfo {307 ensure!(amount <= 1, <Error<T>>::NonfungibleItemsHaveNoAmount);308 if amount == 1 {309 <Pallet<T>>::transfer(self, &from, &to, token, nesting_budget)310 } else {311 <Pallet<T>>::check_token_immediate_ownership(self, token, &from)?;312 Ok(().into())313 }314 }315316 fn approve(317 &self,318 sender: T::CrossAccountId,319 spender: T::CrossAccountId,320 token: TokenId,321 amount: u128,322 ) -> DispatchResultWithPostInfo {323 ensure!(amount <= 1, <Error<T>>::NonfungibleItemsHaveNoAmount);324325 with_weight(326 if amount == 1 {327 <Pallet<T>>::set_allowance(self, &sender, token, Some(&spender))328 } else {329 <Pallet<T>>::set_allowance(self, &sender, token, None)330 },331 <CommonWeights<T>>::approve(),332 )333 }334335 fn approve_from(336 &self,337 sender: T::CrossAccountId,338 from: T::CrossAccountId,339 to: T::CrossAccountId,340 token: TokenId,341 amount: u128,342 ) -> DispatchResultWithPostInfo {343 ensure!(amount <= 1, <Error<T>>::NonfungibleItemsHaveNoAmount);344345 with_weight(346 if amount == 1 {347 <Pallet<T>>::set_allowance_from(self, &sender, &from, token, Some(&to))348 } else {349 <Pallet<T>>::set_allowance_from(self, &sender, &from, token, None)350 },351 <CommonWeights<T>>::approve_from(),352 )353 }354355 fn transfer_from(356 &self,357 sender: T::CrossAccountId,358 from: T::CrossAccountId,359 to: T::CrossAccountId,360 token: TokenId,361 amount: u128,362 nesting_budget: &dyn Budget,363 ) -> DispatchResultWithPostInfo {364 ensure!(amount <= 1, <Error<T>>::NonfungibleItemsHaveNoAmount);365366 if amount == 1 {367 <Pallet<T>>::transfer_from(self, &sender, &from, &to, token, nesting_budget)368 } else {369 <Pallet<T>>::check_allowed(self, &sender, &from, token, nesting_budget)?;370371 Ok(().into())372 }373 }374375 fn burn_from(376 &self,377 sender: T::CrossAccountId,378 from: T::CrossAccountId,379 token: TokenId,380 amount: u128,381 nesting_budget: &dyn Budget,382 ) -> DispatchResultWithPostInfo {383 ensure!(amount <= 1, <Error<T>>::NonfungibleItemsHaveNoAmount);384385 if amount == 1 {386 with_weight(387 <Pallet<T>>::burn_from(self, &sender, &from, token, nesting_budget),388 <CommonWeights<T>>::burn_from(),389 )390 } else {391 <Pallet<T>>::check_allowed(self, &sender, &from, token, nesting_budget)?;392393 Ok(().into())394 }395 }396397 fn check_nesting(398 &self,399 sender: T::CrossAccountId,400 from: (CollectionId, TokenId),401 under: TokenId,402 nesting_budget: &dyn Budget,403 ) -> sp_runtime::DispatchResult {404 <Pallet<T>>::check_nesting(self, sender, from, under, nesting_budget)405 }406407 fn nest(&self, under: TokenId, to_nest: (CollectionId, TokenId)) {408 <Pallet<T>>::nest((self.id, under), to_nest);409 }410411 fn unnest(&self, under: TokenId, to_unnest: (CollectionId, TokenId)) {412 <Pallet<T>>::unnest((self.id, under), to_unnest);413 }414415 fn account_tokens(&self, account: T::CrossAccountId) -> Vec<TokenId> {416 <Owned<T>>::iter_prefix((self.id, account))417 .map(|(id, _)| id)418 .collect()419 }420421 fn collection_tokens(&self) -> Vec<TokenId> {422 <TokenData<T>>::iter_prefix((self.id,))423 .map(|(id, _)| id)424 .collect()425 }426427 fn token_exists(&self, token: TokenId) -> bool {428 <Pallet<T>>::token_exists(self, token)429 }430431 fn last_token_id(&self) -> TokenId {432 TokenId(<TokensMinted<T>>::get(self.id))433 }434435 fn token_owner(&self, token: TokenId) -> Result<T::CrossAccountId, TokenOwnerError> {436 <TokenData<T>>::get((self.id, token))437 .map(|t| t.owner)438 .ok_or(TokenOwnerError::NotFound)439 }440441 fn check_token_indirect_owner(442 &self,443 token: TokenId,444 maybe_owner: &T::CrossAccountId,445 nesting_budget: &dyn Budget,446 ) -> Result<bool, DispatchError> {447 <PalletStructure<T>>::check_indirectly_owned(448 maybe_owner.clone(),449 self.id,450 token,451 None,452 nesting_budget,453 )454 }455456 457 fn token_owners(&self, token: TokenId) -> Vec<T::CrossAccountId> {458 self.token_owner(token).map_or_else(|_| vec![], |t| vec![t])459 }460461 fn token_property(&self, token_id: TokenId, key: &PropertyKey) -> Option<PropertyValue> {462 <Pallet<T>>::token_properties((self.id, token_id))?463 .get(key)464 .cloned()465 }466467 fn token_properties(&self, token_id: TokenId, keys: Option<Vec<PropertyKey>>) -> Vec<Property> {468 let Some(properties) = <Pallet<T>>::token_properties((self.id, token_id)) else {469 return vec![];470 };471472 keys.map(|keys| {473 keys.into_iter()474 .filter_map(|key| {475 properties.get(&key).map(|value| Property {476 key,477 value: value.clone(),478 })479 })480 .collect()481 })482 .unwrap_or_else(|| {483 properties484 .into_iter()485 .map(|(key, value)| Property { key, value })486 .collect()487 })488 }489490 fn total_supply(&self) -> u32 {491 <Pallet<T>>::total_supply(self)492 }493494 fn account_balance(&self, account: T::CrossAccountId) -> u32 {495 <AccountBalance<T>>::get((self.id, account))496 }497498 fn balance(&self, account: T::CrossAccountId, token: TokenId) -> u128 {499 if <TokenData<T>>::get((self.id, token))500 .map(|a| a.owner == account)501 .unwrap_or(false)502 {503 1504 } else {505 0506 }507 }508509 fn allowance(510 &self,511 sender: T::CrossAccountId,512 spender: T::CrossAccountId,513 token: TokenId,514 ) -> u128 {515 if <TokenData<T>>::get((self.id, token))516 .map(|a| a.owner != sender)517 .unwrap_or(true)518 {519 0520 } else if <Allowance<T>>::get((self.id, token)) == Some(spender) {521 1522 } else {523 0524 }525 }526527 fn refungible_extensions(&self) -> Option<&dyn RefungibleExtensions<T>> {528 None529 }530531 fn total_pieces(&self, token: TokenId) -> Option<u128> {532 if <TokenData<T>>::contains_key((self.id, token)) {533 Some(1)534 } else {535 None536 }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}