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};27use sp_runtime::DispatchError;28use sp_std::vec::Vec;2930use crate::{31 AccountBalance, Allowance, Config, CreateItemData, Error, NonfungibleHandle, Owned, Pallet,32 SelfWeightOf, TokenData, weights::WeightInfo, TokensMinted,33};3435pub struct CommonWeights<T: Config>(PhantomData<T>);36impl<T: Config> CommonWeightInfo<T::CrossAccountId> for CommonWeights<T> {37 fn create_item() -> Weight {38 <SelfWeightOf<T>>::create_item()39 }4041 fn create_multiple_items_ex(data: &CreateItemExData<T::CrossAccountId>) -> Weight {42 match data {43 CreateItemExData::NFT(t) => {44 <SelfWeightOf<T>>::create_multiple_items_ex(t.len() as u32)45 + t.iter()46 .map(|t| {47 if t.properties.len() > 0 {48 Self::set_token_properties(t.properties.len() as u32)49 } else {50 051 }52 })53 .sum::<u64>()54 }55 _ => 0,56 }57 }5859 fn create_multiple_items(data: &[up_data_structs::CreateItemData]) -> Weight {60 <SelfWeightOf<T>>::create_multiple_items(data.len() as u32)61 + data62 .iter()63 .filter_map(|t| match t {64 up_data_structs::CreateItemData::NFT(n) if n.properties.len() > 0 => {65 Some(Self::set_token_properties(n.properties.len() as u32))66 }67 _ => None,68 })69 .sum::<u64>()70 }7172 fn burn_item() -> Weight {73 <SelfWeightOf<T>>::burn_item()74 }7576 fn set_collection_properties(amount: u32) -> Weight {77 <pallet_common::SelfWeightOf<T>>::set_collection_properties(amount)78 }7980 fn delete_collection_properties(amount: u32) -> Weight {81 <pallet_common::SelfWeightOf<T>>::delete_collection_properties(amount)82 }8384 fn set_token_properties(amount: u32) -> Weight {85 <SelfWeightOf<T>>::set_token_properties(amount)86 }8788 fn delete_token_properties(amount: u32) -> Weight {89 <SelfWeightOf<T>>::delete_token_properties(amount)90 }9192 fn set_property_permissions(amount: u32) -> Weight {93 <SelfWeightOf<T>>::set_property_permissions(amount)94 }9596 fn transfer() -> Weight {97 <SelfWeightOf<T>>::transfer()98 }99100 fn approve() -> Weight {101 <SelfWeightOf<T>>::approve()102 }103104 fn transfer_from() -> Weight {105 <SelfWeightOf<T>>::transfer_from()106 }107108 fn burn_from() -> Weight {109 <SelfWeightOf<T>>::burn_from()110 }111}112113fn map_create_data<T: Config>(114 data: up_data_structs::CreateItemData,115 to: &T::CrossAccountId,116) -> Result<CreateItemData<T>, DispatchError> {117 match data {118 up_data_structs::CreateItemData::NFT(data) => Ok(CreateItemData::<T> {119 const_data: data.const_data,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 }380 fn const_metadata(&self, token: TokenId) -> Vec<u8> {381 <TokenData<T>>::get((self.id, token))382 .map(|t| t.const_data)383 .unwrap_or_default()384 .into_inner()385 }386387 fn token_property(&self, token_id: TokenId, key: &PropertyKey) -> Option<PropertyValue> {388 <Pallet<T>>::token_properties((self.id, token_id))389 .get(key)390 .cloned()391 }392393 fn token_properties(&self, token_id: TokenId, keys: Option<Vec<PropertyKey>>) -> Vec<Property> {394 let properties = <Pallet<T>>::token_properties((self.id, token_id));395396 keys.map(|keys| {397 keys.into_iter()398 .filter_map(|key| {399 properties.get(&key).map(|value| Property {400 key,401 value: value.clone(),402 })403 })404 .collect()405 })406 .unwrap_or_else(|| {407 properties408 .into_iter()409 .map(|(key, value)| Property {410 key: key.clone(),411 value: value.clone(),412 })413 .collect()414 })415 }416417 fn total_supply(&self) -> u32 {418 <Pallet<T>>::total_supply(self)419 }420421 fn account_balance(&self, account: T::CrossAccountId) -> u32 {422 <AccountBalance<T>>::get((self.id, account))423 }424425 fn balance(&self, account: T::CrossAccountId, token: TokenId) -> u128 {426 if <TokenData<T>>::get((self.id, token))427 .map(|a| a.owner == account)428 .unwrap_or(false)429 {430 1431 } else {432 0433 }434 }435436 fn allowance(437 &self,438 sender: T::CrossAccountId,439 spender: T::CrossAccountId,440 token: TokenId,441 ) -> u128 {442 if <TokenData<T>>::get((self.id, token))443 .map(|a| a.owner != sender)444 .unwrap_or(true)445 {446 0447 } else if <Allowance<T>>::get((self.id, token)) == Some(spender) {448 1449 } else {450 0451 }452 }453}