1234567891011121314151617use core::marker::PhantomData;1819use sp_std::collections::btree_map::BTreeMap;20use frame_support::{dispatch::DispatchResultWithPostInfo, ensure, fail, weights::Weight, traits::Get};21use up_data_structs::{22 CollectionId, TokenId, CreateItemExData, budget::Budget, Property, PropertyKey, PropertyValue,23 PropertyKeyPermission, CollectionPropertiesVec, CreateRefungibleExMultipleOwners,24 CreateRefungibleExSingleOwner, TokenOwnerError,25};26use pallet_common::{27 CommonCollectionOperations, CommonWeightInfo, RefungibleExtensions, with_weight,28 weights::WeightInfo as _,29};30use pallet_structure::Error as StructureError;31use sp_runtime::{DispatchError};32use sp_std::{vec::Vec, vec};3334use crate::{35 AccountBalance, Allowance, Balance, Config, Error, Owned, Pallet, RefungibleHandle,36 SelfWeightOf, weights::WeightInfo, TokensMinted, TotalSupply, CreateItemData,37};3839macro_rules! max_weight_of {40 ($($method:ident ($($args:tt)*)),*) => {41 Weight::zero()42 $(43 .max(<SelfWeightOf<T>>::$method($($args)*))44 )*45 };46}4748fn properties_weight<T: Config>(properties: &CollectionPropertiesVec) -> Weight {49 if properties.len() > 0 {50 <CommonWeights<T>>::set_token_properties(properties.len() as u32)51 } else {52 Weight::zero()53 }54}5556pub struct CommonWeights<T: Config>(PhantomData<T>);57impl<T: Config> CommonWeightInfo<T::CrossAccountId> for CommonWeights<T> {58 fn create_multiple_items(data: &[up_data_structs::CreateItemData]) -> Weight {59 <SelfWeightOf<T>>::create_multiple_items(data.len() as u32).saturating_add(60 data.iter()61 .map(|data| match data {62 up_data_structs::CreateItemData::ReFungible(rft_data) => {63 properties_weight::<T>(&rft_data.properties)64 }65 _ => Weight::zero(),66 })67 .fold(Weight::zero(), |a, b| a.saturating_add(b)),68 )69 }7071 fn create_multiple_items_ex(call: &CreateItemExData<T::CrossAccountId>) -> Weight {72 match call {73 CreateItemExData::RefungibleMultipleOwners(i) => {74 <SelfWeightOf<T>>::create_multiple_items_ex_multiple_owners(i.users.len() as u32)75 .saturating_add(properties_weight::<T>(&i.properties))76 }77 CreateItemExData::RefungibleMultipleItems(i) => {78 <SelfWeightOf<T>>::create_multiple_items_ex_multiple_items(i.len() as u32)79 .saturating_add(80 i.iter()81 .map(|d| properties_weight::<T>(&d.properties))82 .fold(Weight::zero(), |a, b| a.saturating_add(b)),83 )84 }85 _ => Weight::zero(),86 }87 }8889 fn burn_item() -> Weight {90 max_weight_of!(burn_item_partial(), burn_item_fully())91 }9293 fn set_collection_properties(amount: u32) -> Weight {94 <pallet_common::SelfWeightOf<T>>::set_collection_properties(amount)95 }9697 fn delete_collection_properties(amount: u32) -> Weight {98 <pallet_common::SelfWeightOf<T>>::delete_collection_properties(amount)99 }100101 fn set_token_properties(amount: u32) -> Weight {102 <SelfWeightOf<T>>::set_token_properties(amount)103 }104105 fn delete_token_properties(amount: u32) -> Weight {106 <SelfWeightOf<T>>::delete_token_properties(amount)107 }108109 fn set_token_property_permissions(amount: u32) -> Weight {110 <SelfWeightOf<T>>::set_token_property_permissions(amount)111 }112113 fn transfer() -> Weight {114 max_weight_of!(115 transfer_normal(),116 transfer_creating(),117 transfer_removing(),118 transfer_creating_removing()119 )120 }121122 fn approve() -> Weight {123 <SelfWeightOf<T>>::approve()124 }125126 fn approve_from() -> Weight {127 <SelfWeightOf<T>>::approve_from()128 }129130 fn transfer_from() -> Weight {131 max_weight_of!(132 transfer_from_normal(),133 transfer_from_creating(),134 transfer_from_removing(),135 transfer_from_creating_removing()136 )137 }138139 fn burn_from() -> Weight {140 <SelfWeightOf<T>>::burn_from()141 }142143 fn burn_recursively_self_raw() -> Weight {144 145 Self::burn_item() + T::DbWeight::get().reads(1)146 }147 fn burn_recursively_breadth_raw(_amount: u32) -> Weight {148 149 Weight::zero()150 }151152 fn token_owner() -> Weight {153 <SelfWeightOf<T>>::token_owner()154 }155156 fn set_allowance_for_all() -> Weight {157 <SelfWeightOf<T>>::set_allowance_for_all()158 }159160 fn force_repair_item() -> Weight {161 <SelfWeightOf<T>>::repair_item()162 }163}164165fn map_create_data<T: Config>(166 data: up_data_structs::CreateItemData,167 to: &T::CrossAccountId,168) -> Result<CreateItemData<T>, DispatchError> {169 match data {170 up_data_structs::CreateItemData::ReFungible(data) => Ok(CreateItemData::<T> {171 users: {172 let mut out = BTreeMap::new();173 out.insert(to.clone(), data.pieces);174 out.try_into().expect("limit > 0")175 },176 properties: data.properties,177 }),178 _ => fail!(<Error<T>>::NotRefungibleDataUsedToMintFungibleCollectionToken),179 }180}181182183184impl<T: Config> CommonCollectionOperations<T> for RefungibleHandle<T> {185 fn create_item(186 &self,187 sender: T::CrossAccountId,188 to: T::CrossAccountId,189 data: up_data_structs::CreateItemData,190 nesting_budget: &dyn Budget,191 ) -> DispatchResultWithPostInfo {192 let weight = <CommonWeights<T>>::create_item(&data);193 with_weight(194 <Pallet<T>>::create_item(195 self,196 &sender,197 map_create_data::<T>(data, &to)?,198 nesting_budget,199 ),200 weight,201 )202 }203204 fn create_multiple_items(205 &self,206 sender: T::CrossAccountId,207 to: T::CrossAccountId,208 data: Vec<up_data_structs::CreateItemData>,209 nesting_budget: &dyn Budget,210 ) -> DispatchResultWithPostInfo {211 let weight = <CommonWeights<T>>::create_multiple_items(&data);212 let data = data213 .into_iter()214 .map(|d| map_create_data::<T>(d, &to))215 .collect::<Result<Vec<_>, DispatchError>>()?;216217 with_weight(218 <Pallet<T>>::create_multiple_items(self, &sender, data, nesting_budget),219 weight,220 )221 }222223 fn create_multiple_items_ex(224 &self,225 sender: <T>::CrossAccountId,226 data: CreateItemExData<T::CrossAccountId>,227 nesting_budget: &dyn Budget,228 ) -> DispatchResultWithPostInfo {229 let weight = <CommonWeights<T>>::create_multiple_items_ex(&data);230 let data = match data {231 CreateItemExData::RefungibleMultipleOwners(CreateRefungibleExMultipleOwners {232 users,233 properties,234 }) => vec![CreateItemData::<T> { users, properties }],235 CreateItemExData::RefungibleMultipleItems(r) => r236 .into_inner()237 .into_iter()238 .map(239 |CreateRefungibleExSingleOwner {240 user,241 pieces,242 properties,243 }| CreateItemData::<T> {244 users: BTreeMap::from([(user, pieces)])245 .try_into()246 .expect("limit >= 1"),247 properties,248 },249 )250 .collect(),251 _ => fail!(<Error<T>>::NotRefungibleDataUsedToMintFungibleCollectionToken),252 };253254 with_weight(255 <Pallet<T>>::create_multiple_items(self, &sender, data, nesting_budget),256 weight,257 )258 }259260 fn burn_item(261 &self,262 sender: T::CrossAccountId,263 token: TokenId,264 amount: u128,265 ) -> DispatchResultWithPostInfo {266 with_weight(267 <Pallet<T>>::burn(self, &sender, token, amount),268 <CommonWeights<T>>::burn_item(),269 )270 }271272 fn burn_item_recursively(273 &self,274 sender: T::CrossAccountId,275 token: TokenId,276 self_budget: &dyn Budget,277 _breadth_budget: &dyn Budget,278 ) -> DispatchResultWithPostInfo {279 ensure!(self_budget.consume(), <StructureError<T>>::DepthLimit,);280 with_weight(281 <Pallet<T>>::burn(282 self,283 &sender,284 token,285 <Balance<T>>::get((self.id, token, &sender)),286 ),287 <CommonWeights<T>>::burn_recursively_self_raw(),288 )289 }290291 fn transfer(292 &self,293 from: T::CrossAccountId,294 to: T::CrossAccountId,295 token: TokenId,296 amount: u128,297 nesting_budget: &dyn Budget,298 ) -> DispatchResultWithPostInfo {299 with_weight(300 <Pallet<T>>::transfer(self, &from, &to, token, amount, nesting_budget),301 <CommonWeights<T>>::transfer(),302 )303 }304305 fn approve(306 &self,307 sender: T::CrossAccountId,308 spender: T::CrossAccountId,309 token: TokenId,310 amount: u128,311 ) -> DispatchResultWithPostInfo {312 with_weight(313 <Pallet<T>>::set_allowance(self, &sender, &spender, token, amount),314 <CommonWeights<T>>::approve(),315 )316 }317318 fn approve_from(319 &self,320 sender: T::CrossAccountId,321 from: T::CrossAccountId,322 to: T::CrossAccountId,323 token_id: TokenId,324 amount: u128,325 ) -> DispatchResultWithPostInfo {326 with_weight(327 <Pallet<T>>::set_allowance_from(self, &sender, &from, &to, token_id, amount),328 <CommonWeights<T>>::approve_from(),329 )330 }331332 fn transfer_from(333 &self,334 sender: T::CrossAccountId,335 from: T::CrossAccountId,336 to: T::CrossAccountId,337 token: TokenId,338 amount: u128,339 nesting_budget: &dyn Budget,340 ) -> DispatchResultWithPostInfo {341 with_weight(342 <Pallet<T>>::transfer_from(self, &sender, &from, &to, token, amount, nesting_budget),343 <CommonWeights<T>>::transfer_from(),344 )345 }346347 fn burn_from(348 &self,349 sender: T::CrossAccountId,350 from: T::CrossAccountId,351 token: TokenId,352 amount: u128,353 nesting_budget: &dyn Budget,354 ) -> DispatchResultWithPostInfo {355 with_weight(356 <Pallet<T>>::burn_from(self, &sender, &from, token, amount, nesting_budget),357 <CommonWeights<T>>::burn_from(),358 )359 }360361 fn set_collection_properties(362 &self,363 sender: T::CrossAccountId,364 properties: Vec<Property>,365 ) -> DispatchResultWithPostInfo {366 let weight = <CommonWeights<T>>::set_collection_properties(properties.len() as u32);367368 with_weight(369 <Pallet<T>>::set_collection_properties(self, &sender, properties),370 weight,371 )372 }373374 fn delete_collection_properties(375 &self,376 sender: &T::CrossAccountId,377 property_keys: Vec<PropertyKey>,378 ) -> DispatchResultWithPostInfo {379 let weight = <CommonWeights<T>>::delete_collection_properties(property_keys.len() as u32);380381 with_weight(382 <Pallet<T>>::delete_collection_properties(self, sender, property_keys),383 weight,384 )385 }386387 fn set_token_properties(388 &self,389 sender: T::CrossAccountId,390 token_id: TokenId,391 properties: Vec<Property>,392 nesting_budget: &dyn Budget,393 ) -> DispatchResultWithPostInfo {394 let weight = <CommonWeights<T>>::set_token_properties(properties.len() as u32);395396 with_weight(397 <Pallet<T>>::set_token_properties(398 self,399 &sender,400 token_id,401 properties.into_iter(),402 pallet_common::SetPropertyMode::ExistingToken,403 nesting_budget,404 ),405 weight,406 )407 }408409 fn set_token_property_permissions(410 &self,411 sender: &T::CrossAccountId,412 property_permissions: Vec<PropertyKeyPermission>,413 ) -> DispatchResultWithPostInfo {414 let weight =415 <CommonWeights<T>>::set_token_property_permissions(property_permissions.len() as u32);416417 with_weight(418 <Pallet<T>>::set_token_property_permissions(self, sender, property_permissions),419 weight,420 )421 }422423 fn delete_token_properties(424 &self,425 sender: T::CrossAccountId,426 token_id: TokenId,427 property_keys: Vec<PropertyKey>,428 nesting_budget: &dyn Budget,429 ) -> DispatchResultWithPostInfo {430 let weight = <CommonWeights<T>>::delete_token_properties(property_keys.len() as u32);431432 with_weight(433 <Pallet<T>>::delete_token_properties(434 self,435 &sender,436 token_id,437 property_keys.into_iter(),438 nesting_budget,439 ),440 weight,441 )442 }443444 fn check_nesting(445 &self,446 _sender: <T>::CrossAccountId,447 _from: (CollectionId, TokenId),448 _under: TokenId,449 _nesting_budget: &dyn Budget,450 ) -> sp_runtime::DispatchResult {451 fail!(<Error<T>>::RefungibleDisallowsNesting)452 }453454 fn nest(&self, _under: TokenId, _to_nest: (CollectionId, TokenId)) {}455456 fn unnest(&self, _under: TokenId, _to_nest: (CollectionId, TokenId)) {}457458 fn account_tokens(&self, account: T::CrossAccountId) -> Vec<TokenId> {459 <Owned<T>>::iter_prefix((self.id, account))460 .map(|(id, _)| id)461 .collect()462 }463464 fn collection_tokens(&self) -> Vec<TokenId> {465 <TotalSupply<T>>::iter_prefix((self.id,))466 .map(|(id, _)| id)467 .collect()468 }469470 fn token_exists(&self, token: TokenId) -> bool {471 <Pallet<T>>::token_exists(self, token)472 }473474 fn last_token_id(&self) -> TokenId {475 TokenId(<TokensMinted<T>>::get(self.id))476 }477478 fn token_owner(&self, token: TokenId) -> Result<T::CrossAccountId, TokenOwnerError> {479 <Pallet<T>>::token_owner(self.id, token)480 }481482 483 fn token_owners(&self, token: TokenId) -> Vec<T::CrossAccountId> {484 <Pallet<T>>::token_owners(self.id, token).unwrap_or_default()485 }486487 fn token_property(&self, token_id: TokenId, key: &PropertyKey) -> Option<PropertyValue> {488 <Pallet<T>>::token_properties((self.id, token_id))489 .get(key)490 .cloned()491 }492493 fn token_properties(&self, token_id: TokenId, keys: Option<Vec<PropertyKey>>) -> Vec<Property> {494 let properties = <Pallet<T>>::token_properties((self.id, token_id));495496 keys.map(|keys| {497 keys.into_iter()498 .filter_map(|key| {499 properties.get(&key).map(|value| Property {500 key,501 value: value.clone(),502 })503 })504 .collect()505 })506 .unwrap_or_else(|| {507 properties508 .into_iter()509 .map(|(key, value)| Property { key, value })510 .collect()511 })512 }513514 fn total_supply(&self) -> u32 {515 <Pallet<T>>::total_supply(self)516 }517518 fn account_balance(&self, account: T::CrossAccountId) -> u32 {519 <AccountBalance<T>>::get((self.id, account))520 }521522 fn balance(&self, account: T::CrossAccountId, token: TokenId) -> u128 {523 <Balance<T>>::get((self.id, token, account))524 }525526 fn allowance(527 &self,528 sender: T::CrossAccountId,529 spender: T::CrossAccountId,530 token: TokenId,531 ) -> u128 {532 <Allowance<T>>::get((self.id, token, sender, spender))533 }534535 fn refungible_extensions(&self) -> Option<&dyn RefungibleExtensions<T>> {536 Some(self)537 }538539 fn total_pieces(&self, token: TokenId) -> Option<u128> {540 <Pallet<T>>::total_pieces(self.id, token)541 }542543 fn set_allowance_for_all(544 &self,545 owner: T::CrossAccountId,546 operator: T::CrossAccountId,547 approve: bool,548 ) -> DispatchResultWithPostInfo {549 with_weight(550 <Pallet<T>>::set_allowance_for_all(self, &owner, &operator, approve),551 <CommonWeights<T>>::set_allowance_for_all(),552 )553 }554555 fn allowance_for_all(&self, owner: T::CrossAccountId, operator: T::CrossAccountId) -> bool {556 <Pallet<T>>::allowance_for_all(self, &owner, &operator)557 }558559 fn repair_item(&self, token: TokenId) -> DispatchResultWithPostInfo {560 with_weight(561 <Pallet<T>>::repair_item(self, token),562 <CommonWeights<T>>::force_repair_item(),563 )564 }565}566567impl<T: Config> RefungibleExtensions<T> for RefungibleHandle<T> {568 fn repartition(569 &self,570 owner: &T::CrossAccountId,571 token: TokenId,572 amount: u128,573 ) -> DispatchResultWithPostInfo {574 with_weight(575 <Pallet<T>>::repartition(self, owner, token, amount),576 <SelfWeightOf<T>>::repartition_item(),577 )578 }579}