1234567891011121314151617use frame_support::{dispatch::DispatchResult, ensure, fail};18use pallet_balances_adapter::NativeFungibleHandle;19pub use pallet_common::dispatch::CollectionDispatch;20#[cfg(not(feature = "refungible"))]21use pallet_common::unsupported;22use pallet_common::{23 erc::CommonEvmHandler, eth::map_eth_to_id, CollectionById, CollectionHandle,24 CommonCollectionOperations,25};26use pallet_evm::{PrecompileHandle, PrecompileResult};27use pallet_fungible::{FungibleHandle, Pallet as PalletFungible};28use pallet_nonfungible::{NonfungibleHandle, Pallet as PalletNonfungible};29use pallet_refungible::{30 erc_token::RefungibleTokenHandle, Pallet as PalletRefungible, RefungibleHandle,31};32use sp_core::H160;33use sp_runtime::DispatchError;34use sp_std::{borrow::ToOwned, vec::Vec};35use up_data_structs::{36 mapping::TokenAddressMapping, CollectionId, CollectionMode, CreateCollectionData,37 MAX_DECIMAL_POINTS,38};3940pub enum CollectionDispatchT<T>41where42 T: pallet_fungible::Config43 + pallet_nonfungible::Config44 + pallet_refungible::Config45 + pallet_balances_adapter::Config,46{47 Fungible(FungibleHandle<T>),48 Nonfungible(NonfungibleHandle<T>),49 Refungible(RefungibleHandle<T>),50 NativeFungible(NativeFungibleHandle<T>),51}5253impl<T> CollectionDispatch<T> for CollectionDispatchT<T>54where55 T: pallet_common::Config56 + pallet_unique::Config57 + pallet_fungible::Config58 + pallet_nonfungible::Config59 + pallet_refungible::Config60 + pallet_balances_adapter::Config,61{62 fn check_is_internal(&self) -> DispatchResult {63 match self {64 Self::Fungible(h) => h.check_is_internal(),65 Self::Nonfungible(h) => h.check_is_internal(),66 Self::Refungible(h) => h.check_is_internal(),67 Self::NativeFungible(h) => h.check_is_internal(),68 }69 }7071 fn create(72 sender: T::CrossAccountId,73 payer: T::CrossAccountId,74 data: CreateCollectionData<T::CrossAccountId>,75 ) -> Result<CollectionId, DispatchError> {76 let id = match data.mode {77 CollectionMode::NFT => <PalletNonfungible<T>>::init_collection(sender, payer, data)?,78 CollectionMode::Fungible(decimal_points) => {79 80 ensure!(81 decimal_points <= MAX_DECIMAL_POINTS,82 pallet_unique::Error::<T>::CollectionDecimalPointLimitExceeded83 );84 <PalletFungible<T>>::init_collection(sender, payer, data)?85 }8687 #[cfg(feature = "refungible")]88 CollectionMode::ReFungible => <PalletRefungible<T>>::init_collection(sender, payer, data)?,8990 #[cfg(not(feature = "refungible"))]91 CollectionMode::ReFungible => return unsupported!(T),92 };93 Ok(id)94 }9596 fn destroy(sender: T::CrossAccountId, collection_id: CollectionId) -> DispatchResult {97 if collection_id == pallet_common::NATIVE_FUNGIBLE_COLLECTION_ID {98 fail!(<pallet_common::Error<T>>::UnsupportedOperation);99 }100101 let collection = <CollectionHandle<T>>::try_get(collection_id)?;102103 match collection.mode {104 CollectionMode::ReFungible => {105 PalletRefungible::destroy_collection(RefungibleHandle::cast(collection), &sender)?106 }107 CollectionMode::Fungible(_) => {108 PalletFungible::destroy_collection(FungibleHandle::cast(collection), &sender)?109 }110 CollectionMode::NFT => {111 PalletNonfungible::destroy_collection(NonfungibleHandle::cast(collection), &sender)?112 }113 }114 Ok(())115 }116117 fn dispatch(collection_id: CollectionId) -> Result<Self, DispatchError> {118 if collection_id == pallet_common::NATIVE_FUNGIBLE_COLLECTION_ID {119 return Ok(Self::NativeFungible(120 NativeFungibleHandle::new_with_gas_limit(u64::MAX),121 ));122 }123124 let handle = <CollectionHandle<T>>::try_get(collection_id)?;125 Ok(match handle.mode {126 CollectionMode::Fungible(_) => Self::Fungible(FungibleHandle::cast(handle)),127 CollectionMode::NFT => Self::Nonfungible(NonfungibleHandle::cast(handle)),128 CollectionMode::ReFungible => Self::Refungible(RefungibleHandle::cast(handle)),129 })130 }131132 fn as_dyn(&self) -> &dyn CommonCollectionOperations<T> {133 match self {134 Self::Fungible(h) => h,135 Self::Nonfungible(h) => h,136 Self::Refungible(h) => h,137 Self::NativeFungible(h) => h,138 }139 }140}141142impl<T> pallet_evm::OnMethodCall<T> for CollectionDispatchT<T>143where144 T: pallet_common::Config145 + pallet_unique::Config146 + pallet_fungible::Config147 + pallet_nonfungible::Config148 + pallet_refungible::Config149 + pallet_balances_adapter::Config,150 T::AccountId: From<[u8; 32]> + AsRef<[u8; 32]>,151{152 fn is_reserved(target: &H160) -> bool {153 map_eth_to_id(target).is_some()154 }155 fn is_used(target: &H160) -> bool {156 map_eth_to_id(target)157 .map(<CollectionById<T>>::contains_key)158 .unwrap_or(false)159 }160 fn get_code(target: &H160) -> Option<Vec<u8>> {161 if let Some(collection_id) = map_eth_to_id(target) {162 let collection = <CollectionById<T>>::get(collection_id)?;163 Some(164 match collection.mode {165 CollectionMode::NFT => <NonfungibleHandle<T>>::CODE,166 CollectionMode::Fungible(_) => <FungibleHandle<T>>::CODE,167 CollectionMode::ReFungible => <RefungibleHandle<T>>::CODE,168 }169 .to_owned(),170 )171 } else if let Some((collection_id, _token_id)) =172 <T as pallet_common::Config>::EvmTokenAddressMapping::address_to_token(target)173 {174 let collection = <CollectionById<T>>::get(collection_id)?;175 if collection.mode != CollectionMode::ReFungible {176 return None;177 }178 179 Some(<RefungibleTokenHandle<T>>::CODE.to_owned())180 } else {181 None182 }183 }184 fn call(handle: &mut impl PrecompileHandle) -> Option<PrecompileResult> {185 if let Some(collection_id) = map_eth_to_id(&handle.code_address()) {186 if collection_id == pallet_common::NATIVE_FUNGIBLE_COLLECTION_ID {187 <NativeFungibleHandle<T>>::new_with_gas_limit(handle.remaining_gas()).call(handle)188 } else {189 let collection = <CollectionHandle<T>>::new_with_gas_limit(190 collection_id,191 handle.remaining_gas(),192 )?;193194 match collection.mode {195 CollectionMode::Fungible(_) => FungibleHandle::cast(collection).call(handle),196 CollectionMode::NFT => NonfungibleHandle::cast(collection).call(handle),197 CollectionMode::ReFungible => RefungibleHandle::cast(collection).call(handle),198 }199 }200 } else if let Some((collection_id, token_id)) =201 <T as pallet_common::Config>::EvmTokenAddressMapping::address_to_token(202 &handle.code_address(),203 ) {204 let collection =205 <CollectionHandle<T>>::new_with_gas_limit(collection_id, handle.remaining_gas())?;206 if collection.mode != CollectionMode::ReFungible {207 return None;208 }209210 let h = RefungibleHandle::cast(collection);211 212 RefungibleTokenHandle(h, token_id).call(handle)213 } else {214 None215 }216 }217}