1234567891011121314151617use frame_support::{dispatch::DispatchResult, ensure};18use pallet_evm::{PrecompileHandle, PrecompileResult};19use sp_core::H160;20use sp_std::{borrow::ToOwned, vec::Vec};21use pallet_common::{22 CollectionById, CollectionHandle, CommonCollectionOperations, erc::CommonEvmHandler,23 eth::map_eth_to_id,24};25pub use pallet_common::dispatch::CollectionDispatch;26use pallet_fungible::{Pallet as PalletFungible, FungibleHandle};27use pallet_nonfungible::{Pallet as PalletNonfungible, NonfungibleHandle};28use pallet_refungible::{Pallet as PalletRefungible, RefungibleHandle, erc20::RefungibleTokenHandle};29use up_data_structs::{30 CollectionMode, CreateCollectionData, MAX_DECIMAL_POINTS, mapping::TokenAddressMapping,31};3233pub enum CollectionDispatchT<T>34where35 T: pallet_fungible::Config + pallet_nonfungible::Config + pallet_refungible::Config,36{37 Fungible(FungibleHandle<T>),38 Nonfungible(NonfungibleHandle<T>),39 Refungible(RefungibleHandle<T>),40}41impl<T> CollectionDispatch<T> for CollectionDispatchT<T>42where43 T: pallet_common::Config44 + pallet_unique::Config45 + pallet_fungible::Config46 + pallet_nonfungible::Config47 + pallet_refungible::Config,48{49 fn create(50 sender: T::CrossAccountId,51 data: CreateCollectionData<T::AccountId>,52 ) -> DispatchResult {53 let _id = match data.mode {54 CollectionMode::NFT => <PalletNonfungible<T>>::init_collection(sender, data, false)?,55 CollectionMode::Fungible(decimal_points) => {56 57 ensure!(58 decimal_points <= MAX_DECIMAL_POINTS,59 pallet_unique::Error::<T>::CollectionDecimalPointLimitExceeded60 );61 <PalletFungible<T>>::init_collection(sender, data)?62 }63 CollectionMode::ReFungible => <PalletRefungible<T>>::init_collection(sender, data)?,64 };65 Ok(())66 }6768 fn destroy(sender: T::CrossAccountId, collection: CollectionHandle<T>) -> DispatchResult {69 match collection.mode {70 CollectionMode::ReFungible => {71 PalletRefungible::destroy_collection(RefungibleHandle::cast(collection), &sender)?72 }73 CollectionMode::Fungible(_) => {74 PalletFungible::destroy_collection(FungibleHandle::cast(collection), &sender)?75 }76 CollectionMode::NFT => {77 PalletNonfungible::destroy_collection(NonfungibleHandle::cast(collection), &sender)?78 }79 }80 Ok(())81 }8283 fn dispatch(handle: CollectionHandle<T>) -> Self {84 match handle.mode {85 CollectionMode::Fungible(_) => Self::Fungible(FungibleHandle::cast(handle)),86 CollectionMode::NFT => Self::Nonfungible(NonfungibleHandle::cast(handle)),87 CollectionMode::ReFungible => Self::Refungible(RefungibleHandle::cast(handle)),88 }89 }9091 fn into_inner(self) -> CollectionHandle<T> {92 match self {93 Self::Fungible(f) => f.into_inner(),94 Self::Nonfungible(f) => f.into_inner(),95 Self::Refungible(f) => f.into_inner(),96 }97 }9899 fn as_dyn(&self) -> &dyn CommonCollectionOperations<T> {100 match self {101 Self::Fungible(h) => h,102 Self::Nonfungible(h) => h,103 Self::Refungible(h) => h,104 }105 }106}107108impl<T> pallet_evm::OnMethodCall<T> for CollectionDispatchT<T>109where110 T: pallet_common::Config111 + pallet_unique::Config112 + pallet_fungible::Config113 + pallet_nonfungible::Config114 + pallet_refungible::Config,115 T::AccountId: From<[u8; 32]>,116{117 fn is_reserved(target: &H160) -> bool {118 map_eth_to_id(target).is_some()119 }120 fn is_used(target: &H160) -> bool {121 map_eth_to_id(target)122 .map(<CollectionById<T>>::contains_key)123 .unwrap_or(false)124 }125 fn get_code(target: &H160) -> Option<Vec<u8>> {126 if let Some(collection_id) = map_eth_to_id(target) {127 let collection = <CollectionById<T>>::get(collection_id)?;128 Some(129 match collection.mode {130 CollectionMode::NFT => <NonfungibleHandle<T>>::CODE,131 CollectionMode::Fungible(_) => <FungibleHandle<T>>::CODE,132 CollectionMode::ReFungible => <RefungibleHandle<T>>::CODE,133 }134 .to_owned(),135 )136 } else if let Some((collection_id, _token_id)) =137 <T as pallet_common::Config>::EvmTokenAddressMapping::address_to_token(target)138 {139 let collection = <CollectionById<T>>::get(collection_id)?;140 if collection.mode != CollectionMode::ReFungible {141 return None;142 }143 144 Some(<RefungibleTokenHandle<T>>::CODE.to_owned())145 } else {146 None147 }148 }149 fn call(handle: &mut impl PrecompileHandle) -> Option<PrecompileResult> {150 if let Some(collection_id) = map_eth_to_id(&handle.code_address()) {151 let collection =152 <CollectionHandle<T>>::new_with_gas_limit(collection_id, handle.remaining_gas())?;153 let dispatched = Self::dispatch(collection);154155 match dispatched {156 Self::Fungible(h) => h.call(handle),157 Self::Nonfungible(h) => h.call(handle),158 Self::Refungible(h) => h.call(handle),159 }160 } else if let Some((collection_id, token_id)) =161 <T as pallet_common::Config>::EvmTokenAddressMapping::address_to_token(162 &handle.code_address(),163 ) {164 let collection =165 <CollectionHandle<T>>::new_with_gas_limit(collection_id, handle.remaining_gas())?;166 if collection.mode != CollectionMode::ReFungible {167 return None;168 }169170 let h = RefungibleHandle::cast(collection);171 172 RefungibleTokenHandle(h, token_id).call(handle)173 } else {174 None175 }176 }177}