1234567891011121314151617use core::marker::PhantomData;1819use frame_support::{dispatch::DispatchResultWithPostInfo, ensure, fail, weights::Weight};20use up_data_structs::{21 TokenId, CreateItemExData, CollectionId, budget::Budget, Property, PropertyKey,22 PropertyKeyPermission, PropertyValue,23};24use pallet_common::{25 CommonCollectionOperations, CommonWeightInfo, with_weight, weights::WeightInfo as _,26 PropertyKeyPermission,27};28use sp_runtime::DispatchError;29use sp_std::vec::Vec;3031use crate::{32 AccountBalance, Allowance, Config, CreateItemData, Error, NonfungibleHandle, Owned, Pallet,33 SelfWeightOf, TokenData, weights::WeightInfo, TokensMinted,34};3536pub struct CommonWeights<T: Config>(PhantomData<T>);37impl<T: Config> CommonWeightInfo<T::CrossAccountId> for CommonWeights<T> {38 fn create_item() -> Weight {39 <SelfWeightOf<T>>::create_item()40 }4142 fn create_multiple_items_ex(data: &CreateItemExData<T::CrossAccountId>) -> Weight {43 match data {44 CreateItemExData::NFT(t) => {45 <SelfWeightOf<T>>::create_multiple_items_ex(t.len() as u32)46 + t.iter()47 .map(|t| {48 if t.properties.len() > 0 {49 Self::set_token_properties(t.properties.len() as u32)50 } else {51 052 }53 })54 .sum::<u64>()55 }56 _ => 0,57 }58 }5960 fn create_multiple_items(data: &[up_data_structs::CreateItemData]) -> Weight {61 <SelfWeightOf<T>>::create_multiple_items(data.len() as u32)62 + data63 .iter()64 .filter_map(|t| match t {65 up_data_structs::CreateItemData::NFT(n) if n.properties.len() > 0 => {66 Some(Self::set_token_properties(n.properties.len() as u32))67 }68 _ => None,69 })70 .sum::<u64>()71 }7273 fn burn_item() -> Weight {74 <SelfWeightOf<T>>::burn_item()75 }7677 fn set_collection_properties(amount: u32) -> Weight {78 <pallet_common::SelfWeightOf<T>>::set_collection_properties(amount)79 }8081 fn delete_collection_properties(amount: u32) -> Weight {82 <pallet_common::SelfWeightOf<T>>::delete_collection_properties(amount)83 }8485 fn set_token_properties(amount: u32) -> Weight {86 <SelfWeightOf<T>>::set_token_properties(amount)87 }8889 fn delete_token_properties(amount: u32) -> Weight {90 <SelfWeightOf<T>>::delete_token_properties(amount)91 }9293 fn set_property_permissions(amount: u32) -> Weight {94 <SelfWeightOf<T>>::set_property_permissions(amount)95 }9697 fn transfer() -> Weight {98 <SelfWeightOf<T>>::transfer()99 }100101 fn approve() -> Weight {102 <SelfWeightOf<T>>::approve()103 }104105 fn transfer_from() -> Weight {106 <SelfWeightOf<T>>::transfer_from()107 }108109 fn burn_from() -> Weight {110 <SelfWeightOf<T>>::burn_from()111 }112}113114fn map_create_data<T: Config>(115 data: up_data_structs::CreateItemData,116 to: &T::CrossAccountId,117) -> Result<CreateItemData<T>, DispatchError> {118 match data {119 up_data_structs::CreateItemData::NFT(data) => Ok(CreateItemData::<T> {120 properties: data.properties,121 owner: to.clone(),122 }),123 _ => fail!(<Error<T>>::NotNonfungibleDataUsedToMintFungibleCollectionToken),124 }125}126127impl<T: Config> CommonCollectionOperations<T> for NonfungibleHandle<T> {128 fn create_item(129 &self,130 sender: T::CrossAccountId,131 to: T::CrossAccountId,132 data: up_data_structs::CreateItemData,133 nesting_budget: &dyn Budget,134 ) -> DispatchResultWithPostInfo {135 with_weight(136 <Pallet<T>>::create_item(137 self,138 &sender,139 map_create_data::<T>(data, &to)?,140 nesting_budget,141 ),142 <CommonWeights<T>>::create_item(),143 )144 }145146 fn create_multiple_items(147 &self,148 sender: T::CrossAccountId,149 to: T::CrossAccountId,150 data: Vec<up_data_structs::CreateItemData>,151 nesting_budget: &dyn Budget,152 ) -> DispatchResultWithPostInfo {153 let weight = <CommonWeights<T>>::create_multiple_items(&data);154 let data = data155 .into_iter()156 .map(|d| map_create_data::<T>(d, &to))157 .collect::<Result<Vec<_>, DispatchError>>()?;158159 with_weight(160 <Pallet<T>>::create_multiple_items(self, &sender, data, nesting_budget),161 weight,162 )163 }164165 fn create_multiple_items_ex(166 &self,167 sender: <T>::CrossAccountId,168 data: up_data_structs::CreateItemExData<<T>::CrossAccountId>,169 nesting_budget: &dyn Budget,170 ) -> DispatchResultWithPostInfo {171 let weight = <CommonWeights<T>>::create_multiple_items_ex(&data);172 let data = match data {173 up_data_structs::CreateItemExData::NFT(nft) => nft,174 _ => fail!(Error::<T>::NotNonfungibleDataUsedToMintFungibleCollectionToken),175 };176177 with_weight(178 <Pallet<T>>::create_multiple_items(self, &sender, data.into_inner(), nesting_budget),179 weight,180 )181 }182183 fn set_collection_properties(184 &self,185 sender: T::CrossAccountId,186 properties: Vec<Property>,187 ) -> DispatchResultWithPostInfo {188 let weight = <CommonWeights<T>>::set_collection_properties(properties.len() as u32);189190 with_weight(191 <Pallet<T>>::set_collection_properties(self, &sender, properties),192 weight,193 )194 }195196 fn delete_collection_properties(197 &self,198 sender: &T::CrossAccountId,199 property_keys: Vec<PropertyKey>,200 ) -> DispatchResultWithPostInfo {201 let weight = <CommonWeights<T>>::delete_collection_properties(property_keys.len() as u32);202203 with_weight(204 <Pallet<T>>::delete_collection_properties(self, sender, property_keys),205 weight,206 )207 }208209 fn set_token_properties(210 &self,211 sender: T::CrossAccountId,212 token_id: TokenId,213 properties: Vec<Property>,214 ) -> DispatchResultWithPostInfo {215 let weight = <CommonWeights<T>>::set_token_properties(properties.len() as u32);216217 with_weight(218 <Pallet<T>>::set_token_properties(self, &sender, token_id, properties),219 weight,220 )221 }222223 fn delete_token_properties(224 &self,225 sender: T::CrossAccountId,226 token_id: TokenId,227 property_keys: Vec<PropertyKey>,228 ) -> DispatchResultWithPostInfo {229 let weight = <CommonWeights<T>>::delete_token_properties(property_keys.len() as u32);230231 with_weight(232 <Pallet<T>>::delete_token_properties(self, &sender, token_id, property_keys),233 weight,234 )235 }236237 fn set_property_permissions(238 &self,239 sender: &T::CrossAccountId,240 property_permissions: Vec<PropertyKeyPermission>,241 ) -> DispatchResultWithPostInfo {242 let weight =243 <CommonWeights<T>>::set_property_permissions(property_permissions.len() as u32);244245 with_weight(246 <Pallet<T>>::set_property_permissions(self, sender, property_permissions),247 weight,248 )249 }250251 fn burn_item(252 &self,253 sender: T::CrossAccountId,254 token: TokenId,255 amount: u128,256 ) -> DispatchResultWithPostInfo {257 ensure!(amount <= 1, <Error<T>>::NonfungibleItemsHaveNoAmount);258 if amount == 1 {259 with_weight(260 <Pallet<T>>::burn(self, &sender, token),261 <CommonWeights<T>>::burn_item(),262 )263 } else {264 Ok(().into())265 }266 }267268 fn transfer(269 &self,270 from: T::CrossAccountId,271 to: T::CrossAccountId,272 token: TokenId,273 amount: u128,274 nesting_budget: &dyn Budget,275 ) -> DispatchResultWithPostInfo {276 ensure!(amount <= 1, <Error<T>>::NonfungibleItemsHaveNoAmount);277 if amount == 1 {278 with_weight(279 <Pallet<T>>::transfer(self, &from, &to, token, nesting_budget),280 <CommonWeights<T>>::transfer(),281 )282 } else {283 Ok(().into())284 }285 }286287 fn approve(288 &self,289 sender: T::CrossAccountId,290 spender: T::CrossAccountId,291 token: TokenId,292 amount: u128,293 ) -> DispatchResultWithPostInfo {294 ensure!(amount <= 1, <Error<T>>::NonfungibleItemsHaveNoAmount);295296 with_weight(297 if amount == 1 {298 <Pallet<T>>::set_allowance(self, &sender, token, Some(&spender))299 } else {300 <Pallet<T>>::set_allowance(self, &sender, token, None)301 },302 <CommonWeights<T>>::approve(),303 )304 }305306 fn transfer_from(307 &self,308 sender: T::CrossAccountId,309 from: T::CrossAccountId,310 to: T::CrossAccountId,311 token: TokenId,312 amount: u128,313 nesting_budget: &dyn Budget,314 ) -> DispatchResultWithPostInfo {315 ensure!(amount <= 1, <Error<T>>::NonfungibleItemsHaveNoAmount);316317 if amount == 1 {318 with_weight(319 <Pallet<T>>::transfer_from(self, &sender, &from, &to, token, nesting_budget),320 <CommonWeights<T>>::transfer_from(),321 )322 } else {323 Ok(().into())324 }325 }326327 fn burn_from(328 &self,329 sender: T::CrossAccountId,330 from: T::CrossAccountId,331 token: TokenId,332 amount: u128,333 nesting_budget: &dyn Budget,334 ) -> DispatchResultWithPostInfo {335 ensure!(amount <= 1, <Error<T>>::NonfungibleItemsHaveNoAmount);336337 if amount == 1 {338 with_weight(339 <Pallet<T>>::burn_from(self, &sender, &from, token, nesting_budget),340 <CommonWeights<T>>::burn_from(),341 )342 } else {343 Ok(().into())344 }345 }346347 fn check_nesting(348 &self,349 sender: T::CrossAccountId,350 from: (CollectionId, TokenId),351 under: TokenId,352 budget: &dyn Budget,353 ) -> sp_runtime::DispatchResult {354 <Pallet<T>>::check_nesting(self, sender, from, under, budget)355 }356357 fn account_tokens(&self, account: T::CrossAccountId) -> Vec<TokenId> {358 <Owned<T>>::iter_prefix((self.id, account))359 .map(|(id, _)| id)360 .collect()361 }362363 fn collection_tokens(&self) -> Vec<TokenId> {364 <TokenData<T>>::iter_prefix((self.id,))365 .map(|(id, _)| id)366 .collect()367 }368369 fn token_exists(&self, token: TokenId) -> bool {370 <Pallet<T>>::token_exists(self, token)371 }372373 fn last_token_id(&self) -> TokenId {374 TokenId(<TokensMinted<T>>::get(self.id))375 }376377 fn token_owner(&self, token: TokenId) -> Option<T::CrossAccountId> {378 <TokenData<T>>::get((self.id, token)).map(|t| t.owner)379 }380381 fn token_property(&self, token_id: TokenId, key: &PropertyKey) -> Option<PropertyValue> {382 <Pallet<T>>::token_properties((self.id, token_id))383 .get(key)384 .cloned()385 }386387 fn token_properties(&self, token_id: TokenId, keys: Option<Vec<PropertyKey>>) -> Vec<Property> {388 let properties = <Pallet<T>>::token_properties((self.id, token_id));389390 keys.map(|keys| {391 keys.into_iter()392 .filter_map(|key| {393 properties.get(&key).map(|value| Property {394 key,395 value: value.clone(),396 })397 })398 .collect()399 })400 .unwrap_or_else(|| {401 properties402 .into_iter()403 .map(|(key, value)| Property {404 key: key.clone(),405 value: value.clone(),406 })407 .collect()408 })409 }410411 fn total_supply(&self) -> u32 {412 <Pallet<T>>::total_supply(self)413 }414415 fn account_balance(&self, account: T::CrossAccountId) -> u32 {416 <AccountBalance<T>>::get((self.id, account))417 }418419 fn balance(&self, account: T::CrossAccountId, token: TokenId) -> u128 {420 if <TokenData<T>>::get((self.id, token))421 .map(|a| a.owner == account)422 .unwrap_or(false)423 {424 1425 } else {426 0427 }428 }429430 fn allowance(431 &self,432 sender: T::CrossAccountId,433 spender: T::CrossAccountId,434 token: TokenId,435 ) -> u128 {436 if <TokenData<T>>::get((self.id, token))437 .map(|a| a.owner != sender)438 .unwrap_or(true)439 {440 0441 } else if <Allowance<T>>::get((self.id, token)) == Some(spender) {442 1443 } else {444 0445 }446 }447}