1234567891011121314151617#![cfg_attr(not(feature = "std"), no_std)]1819use frame_support::{pallet_prelude::*, transactional, BoundedVec, dispatch::DispatchResult};20use frame_system::{pallet_prelude::*, ensure_signed};21use sp_runtime::DispatchError;22use up_data_structs::*;23use pallet_common::{Pallet as PalletCommon, Error as CommonError, CollectionHandle};24use pallet_rmrk_core::{Pallet as PalletCore, rmrk_property, misc::*};25use pallet_nonfungible::{Pallet as PalletNft};26use pallet_evm::account::CrossAccountId;2728pub use pallet::*;2930#[frame_support::pallet]31pub mod pallet {32 use super::*;3334 #[pallet::config]35 pub trait Config: frame_system::Config36 + pallet_rmrk_core::Config {37 type Event: From<Event<Self>> + IsType<<Self as frame_system::Config>::Event>;38 }3940 #[pallet::storage]41 #[pallet::getter(fn internal_part_id)]42 pub type InernalPartId<T: Config> = StorageDoubleMap<43 _,44 Twox64Concat,45 CollectionId,46 Twox64Concat,47 RmrkPartId,48 TokenId49 >;5051 #[pallet::pallet]52 #[pallet::generate_store(pub(super) trait Store)]53 pub struct Pallet<T>(_);5455 #[pallet::event]56 #[pallet::generate_deposit(pub(super) fn deposit_event)]57 pub enum Event<T: Config> {58 BaseCreated {59 issuer: T::AccountId,60 base_id: RmrkBaseId,61 },62 }6364 #[pallet::error]65 pub enum Error<T> {66 NoAvailableBaseId,67 }6869 #[pallet::call]70 impl<T: Config> Pallet<T> {71 #[pallet::weight(10_000 + T::DbWeight::get().reads_writes(1,1))]72 #[transactional]73 pub fn create_base(74 origin: OriginFor<T>,75 base_type: RmrkString,76 symbol: RmrkString,77 parts: BoundedVec<RmrkPartType, RmrkPartsLimit>,78 ) -> DispatchResult {79 let sender = ensure_signed(origin)?;80 let cross_sender = T::CrossAccountId::from_sub(sender.clone());8182 let data = CreateCollectionData {83 limits: None,84 token_prefix: symbol.into_inner()85 .try_into()86 .map_err(|_| <CommonError<T>>::CollectionTokenPrefixLimitExceeded)?,87 ..Default::default()88 };8990 let collection_id_res = <PalletNft<T>>::init_collection(sender.clone(), data);9192 if let Err(DispatchError::Arithmetic(_)) = &collection_id_res {93 return Err(<Error<T>>::NoAvailableBaseId.into());94 }9596 let collection_id = collection_id_res?;9798 let collection = <PalletCore<T>>::get_nft_collection(collection_id)?.into_inner();99100 <PalletCommon<T>>::set_scoped_collection_properties(101 &collection,102 PropertyScope::Rmrk,103 [104 rmrk_property!(Config=T, CollectionType: CollectionType::Base)?,105 rmrk_property!(Config=T, BaseType: base_type)?,106 ].into_iter()107 )?;108109 for part in parts {110 let part_id = part.id();111 let part_token_id = Self::create_part(112 &cross_sender,113 &collection,114 part115 )?;116117 <InernalPartId<T>>::insert(collection_id, part_id, part_token_id);118119 <PalletNft<T>>::set_scoped_token_property(120 &collection,121 part_token_id,122 PropertyScope::Rmrk,123 rmrk_property!(Config=T, ExternalPartId: part_id)?124 )?;125 }126127 Self::deposit_event(Event::BaseCreated { issuer: sender, base_id: collection_id.0 });128129 Ok(())130 }131 }132}133134impl<T: Config> Pallet<T> {135 fn create_part(136 sender: &T::CrossAccountId,137 collection: &CollectionHandle<T>,138 part: RmrkPartType139 ) -> Result<TokenId, DispatchError> {140 let owner = sender;141142 let src = part.src();143 let z_index = part.z_index();144145 let nft_type = match part {146 RmrkPartType::FixedPart(_) => NftType::FixedPart,147 RmrkPartType::SlotPart(_) => NftType::SlotPart,148 };149150 let token_id = <PalletCore<T>>::create_nft(151 sender,152 owner,153 collection.id,154 CollectionType::Base,155 nft_type,156 [157 rmrk_property!(Config=T, Src: src)?,158 rmrk_property!(Config=T, ZIndex: z_index)?159 ].into_iter()160 )?;161162 if let RmrkPartType::SlotPart(part) = part {163 <PalletNft<T>>::set_scoped_token_property(164 collection,165 token_id,166 PropertyScope::Rmrk,167 rmrk_property!(Config=T, EquippableList: part.equippable)?168 )?;169 }170171 Ok(token_id)172 }173}