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 budget::Budget,16};1718pub enum CollectionDispatchT<T>19where20 T: pallet_fungible::Config + pallet_nonfungible::Config + pallet_refungible::Config,21{22 Fungible(FungibleHandle<T>),23 Nonfungible(NonfungibleHandle<T>),24 Refungible(RefungibleHandle<T>),25}26impl<T> CollectionDispatch<T> for CollectionDispatchT<T>27where28 T: pallet_common::Config29 + pallet_unique::Config30 + pallet_fungible::Config31 + pallet_nonfungible::Config32 + pallet_refungible::Config,33{34 fn create(sender: T::AccountId, data: CreateCollectionData<T::AccountId>) -> DispatchResult {35 let _id = match data.mode {36 CollectionMode::NFT => <PalletNonfungible<T>>::init_collection(sender, data)?,37 CollectionMode::Fungible(decimal_points) => {38 39 ensure!(40 decimal_points <= MAX_DECIMAL_POINTS,41 pallet_unique::Error::<T>::CollectionDecimalPointLimitExceeded42 );43 <PalletFungible<T>>::init_collection(sender, data)?44 }45 CollectionMode::ReFungible => <PalletRefungible<T>>::init_collection(sender, data)?,46 };47 Ok(())48 }4950 fn destroy(51 sender: T::CrossAccountId,52 collection: CollectionHandle<T>,53 nesting_budget: &dyn Budget,54 ) -> DispatchResult {55 match collection.mode {56 CollectionMode::ReFungible => {57 PalletRefungible::destroy_collection(RefungibleHandle::cast(collection), &sender)?58 }59 CollectionMode::Fungible(_) => {60 PalletFungible::destroy_collection(FungibleHandle::cast(collection), &sender)?61 }62 CollectionMode::NFT => {63 PalletNonfungible::destroy_collection(64 NonfungibleHandle::cast(collection),65 &sender,66 nesting_budget,67 )?68 }69 }70 Ok(())71 }7273 fn dispatch(handle: CollectionHandle<T>) -> Self {74 match handle.mode {75 CollectionMode::Fungible(_) => Self::Fungible(FungibleHandle::cast(handle)),76 CollectionMode::NFT => Self::Nonfungible(NonfungibleHandle::cast(handle)),77 CollectionMode::ReFungible => Self::Refungible(RefungibleHandle::cast(handle)),78 }79 }8081 fn into_inner(self) -> CollectionHandle<T> {82 match self {83 Self::Fungible(f) => f.into_inner(),84 Self::Nonfungible(f) => f.into_inner(),85 Self::Refungible(f) => f.into_inner(),86 }87 }8889 fn as_dyn(&self) -> &dyn CommonCollectionOperations<T> {90 match self {91 Self::Fungible(h) => h,92 Self::Nonfungible(h) => h,93 Self::Refungible(h) => h,94 }95 }96}9798impl<T> pallet_evm::OnMethodCall<T> for CollectionDispatchT<T>99where100 T: pallet_common::Config101 + pallet_unique::Config102 + pallet_fungible::Config103 + pallet_nonfungible::Config104 + pallet_refungible::Config,105{106 fn is_reserved(target: &H160) -> bool {107 map_eth_to_id(target).is_some()108 }109 fn is_used(target: &H160) -> bool {110 map_eth_to_id(target)111 .map(<CollectionById<T>>::contains_key)112 .unwrap_or(false)113 }114 fn get_code(target: &H160) -> Option<Vec<u8>> {115 if let Some(collection_id) = map_eth_to_id(target) {116 let collection = <CollectionById<T>>::get(collection_id)?;117 Some(118 match collection.mode {119 CollectionMode::NFT => <NonfungibleHandle<T>>::CODE,120 CollectionMode::Fungible(_) => <FungibleHandle<T>>::CODE,121 CollectionMode::ReFungible => <RefungibleHandle<T>>::CODE,122 }123 .to_owned(),124 )125 } else if let Some((collection_id, _token_id)) =126 <T as pallet_common::Config>::EvmTokenAddressMapping::address_to_token(target)127 {128 let collection = <CollectionById<T>>::get(collection_id)?;129 if collection.mode != CollectionMode::ReFungible {130 return None;131 }132 133 Some(<RefungibleTokenHandle<T>>::CODE.to_owned())134 } else {135 None136 }137 }138 fn call(139 source: &H160,140 target: &H160,141 gas_limit: u64,142 input: &[u8],143 value: U256,144 ) -> Option<PrecompileResult> {145 if let Some(collection_id) = map_eth_to_id(target) {146 let collection = <CollectionHandle<T>>::new_with_gas_limit(collection_id, gas_limit)?;147 let dispatched = Self::dispatch(collection);148149 match dispatched {150 Self::Fungible(h) => h.call(source, input, value),151 Self::Nonfungible(h) => h.call(source, input, value),152 Self::Refungible(h) => h.call(source, input, value),153 }154 } else if let Some((collection_id, token_id)) =155 <T as pallet_common::Config>::EvmTokenAddressMapping::address_to_token(target)156 {157 let collection = <CollectionHandle<T>>::new_with_gas_limit(collection_id, gas_limit)?;158 if collection.mode != CollectionMode::ReFungible {159 return None;160 }161162 let handle = RefungibleHandle::cast(collection);163 164 RefungibleTokenHandle(handle, token_id).call(source, input, value)165 } else {166 None167 }168 }169}