1use frame_support::{dispatch::DispatchResult, ensure};2use pallet_evm::PrecompileResult;3use sp_core::{H160, U256};4use sp_std::{borrow::ToOwned, vec::Vec};5use pallet_common::{6 CollectionById, CollectionHandle, CommonCollectionOperations, erc::CommonEvmHandler,7 eth::map_eth_to_id,8};9pub use pallet_common::dispatch::CollectionDispatch;10use pallet_fungible::{Pallet as PalletFungible, FungibleHandle};11use pallet_nonfungible::{Pallet as PalletNonfungible, NonfungibleHandle};12use pallet_refungible::{Pallet as PalletRefungible, RefungibleHandle, erc::RefungibleTokenHandle};13use up_data_structs::{14 CollectionMode, CreateCollectionData, MAX_DECIMAL_POINTS, mapping::TokenAddressMapping,15};1617pub enum CollectionDispatchT<T>18where19 T: pallet_fungible::Config + pallet_nonfungible::Config + pallet_refungible::Config,20{21 Fungible(FungibleHandle<T>),22 Nonfungible(NonfungibleHandle<T>),23 Refungible(RefungibleHandle<T>),24}25impl<T> CollectionDispatch<T> for CollectionDispatchT<T>26where27 T: pallet_common::Config28 + pallet_unique::Config29 + pallet_fungible::Config30 + pallet_nonfungible::Config31 + pallet_refungible::Config,32{33 fn create(sender: T::AccountId, data: CreateCollectionData<T::AccountId>) -> DispatchResult {34 let _id = match data.mode {35 CollectionMode::NFT => <PalletNonfungible<T>>::init_collection(sender, data)?,36 CollectionMode::Fungible(decimal_points) => {37 38 ensure!(39 decimal_points <= MAX_DECIMAL_POINTS,40 pallet_unique::Error::<T>::CollectionDecimalPointLimitExceeded41 );42 <PalletFungible<T>>::init_collection(sender, data)?43 }44 CollectionMode::ReFungible => <PalletRefungible<T>>::init_collection(sender, data)?,45 };46 Ok(())47 }4849 fn destroy(sender: T::CrossAccountId, collection: CollectionHandle<T>) -> DispatchResult {50 match collection.mode {51 CollectionMode::ReFungible => {52 PalletRefungible::destroy_collection(RefungibleHandle::cast(collection), &sender)?53 }54 CollectionMode::Fungible(_) => {55 PalletFungible::destroy_collection(FungibleHandle::cast(collection), &sender)?56 }57 CollectionMode::NFT => {58 PalletNonfungible::destroy_collection(NonfungibleHandle::cast(collection), &sender)?59 }60 }61 Ok(())62 }6364 fn dispatch(handle: CollectionHandle<T>) -> Self {65 match handle.mode {66 CollectionMode::Fungible(_) => Self::Fungible(FungibleHandle::cast(handle)),67 CollectionMode::NFT => Self::Nonfungible(NonfungibleHandle::cast(handle)),68 CollectionMode::ReFungible => Self::Refungible(RefungibleHandle::cast(handle)),69 }70 }7172 fn into_inner(self) -> CollectionHandle<T> {73 match self {74 Self::Fungible(f) => f.into_inner(),75 Self::Nonfungible(f) => f.into_inner(),76 Self::Refungible(f) => f.into_inner(),77 }78 }7980 fn as_dyn(&self) -> &dyn CommonCollectionOperations<T> {81 match self {82 Self::Fungible(h) => h,83 Self::Nonfungible(h) => h,84 Self::Refungible(h) => h,85 }86 }87}8889impl<T> pallet_evm::OnMethodCall<T> for CollectionDispatchT<T>90where91 T: pallet_common::Config92 + pallet_unique::Config93 + pallet_fungible::Config94 + pallet_nonfungible::Config95 + pallet_refungible::Config,96{97 fn is_reserved(target: &H160) -> bool {98 map_eth_to_id(target).is_some()99 }100 fn is_used(target: &H160) -> bool {101 map_eth_to_id(target)102 .map(<CollectionById<T>>::contains_key)103 .unwrap_or(false)104 }105 fn get_code(target: &H160) -> Option<Vec<u8>> {106 if let Some(collection_id) = map_eth_to_id(target) {107 let collection = <CollectionById<T>>::get(collection_id)?;108 Some(109 match collection.mode {110 CollectionMode::NFT => <NonfungibleHandle<T>>::CODE,111 CollectionMode::Fungible(_) => <FungibleHandle<T>>::CODE,112 CollectionMode::ReFungible => <RefungibleHandle<T>>::CODE,113 }114 .to_owned(),115 )116 } else if let Some((collection_id, _token_id)) =117 <T as pallet_common::Config>::EvmTokenAddressMapping::address_to_token(target)118 {119 let collection = <CollectionById<T>>::get(collection_id)?;120 if collection.mode != CollectionMode::ReFungible {121 return None;122 }123 124 Some(<RefungibleTokenHandle<T>>::CODE.to_owned())125 } else {126 None127 }128 }129 fn call(130 source: &H160,131 target: &H160,132 gas_limit: u64,133 input: &[u8],134 value: U256,135 ) -> Option<PrecompileResult> {136 if let Some(collection_id) = map_eth_to_id(target) {137 let collection = <CollectionHandle<T>>::new_with_gas_limit(collection_id, gas_limit)?;138 let dispatched = Self::dispatch(collection);139140 match dispatched {141 Self::Fungible(h) => h.call(source, input, value),142 Self::Nonfungible(h) => h.call(source, input, value),143 Self::Refungible(h) => h.call(source, input, value),144 }145 } else if let Some((collection_id, token_id)) =146 <T as pallet_common::Config>::EvmTokenAddressMapping::address_to_token(target)147 {148 let collection = <CollectionHandle<T>>::new_with_gas_limit(collection_id, gas_limit)?;149 if collection.mode != CollectionMode::ReFungible {150 return None;151 }152153 let handle = RefungibleHandle::cast(collection);154 155 RefungibleTokenHandle(handle, token_id).call(source, input, value)156 } else {157 None158 }159 }160}