12345678910111213141516171819use core::{convert::TryInto, marker::PhantomData};20use evm_coder::{Call, abi::AbiReader};21use pallet_common::{CollectionHandle, eth::map_eth_to_id};22use pallet_evm::account::CrossAccountId;23use pallet_evm_transaction_payment::CallContext;24use pallet_nonfungible::{25 Config as NonfungibleConfig,26 erc::{27 UniqueNFTCall, ERC721UniqueExtensionsCall, ERC721UniqueMintableCall, ERC721Call,28 TokenPropertiesCall,29 },30};31use pallet_fungible::{32 Config as FungibleConfig,33 erc::{UniqueFungibleCall, ERC20Call},34};35use pallet_refungible::{36 Config as RefungibleConfig,37 erc::UniqueRefungibleCall,38 erc_token::{RefungibleTokenHandle, UniqueRefungibleTokenCall},39 RefungibleHandle,40};41use pallet_unique::Config as UniqueConfig;42use sp_std::prelude::*;43use up_data_structs::{44 CollectionMode, CreateItemData, CreateNftData, mapping::TokenAddressMapping, TokenId,45};46use up_sponsorship::SponsorshipHandler;47use crate::{Runtime, runtime_common::sponsoring::*};4849mod refungible;5051pub type EvmSponsorshipHandler = (52 UniqueEthSponsorshipHandler<Runtime>,53 pallet_evm_contract_helpers::HelpersContractSponsoring<Runtime>,54);5556pub struct UniqueEthSponsorshipHandler<T: UniqueConfig>(PhantomData<*const T>);57impl<T: UniqueConfig + FungibleConfig + NonfungibleConfig + RefungibleConfig>58 SponsorshipHandler<T::CrossAccountId, CallContext> for UniqueEthSponsorshipHandler<T>59{60 fn get_sponsor(61 who: &T::CrossAccountId,62 call_context: &CallContext,63 ) -> Option<T::CrossAccountId> {64 if let Some(collection_id) = map_eth_to_id(&call_context.contract_address) {65 let collection = <CollectionHandle<T>>::new(collection_id)?;66 let sponsor = collection.sponsorship.sponsor()?.clone();67 let (method_id, mut reader) = AbiReader::new_call(&call_context.input).ok()?;68 Some(T::CrossAccountId::from_sub(match &collection.mode {69 CollectionMode::NFT => {70 let call = <UniqueNFTCall<T>>::parse(method_id, &mut reader).ok()??;71 match call {72 UniqueNFTCall::TokenProperties(TokenPropertiesCall::SetProperty {73 token_id,74 key,75 value,76 ..77 }) => {78 let token_id: TokenId = token_id.try_into().ok()?;79 withdraw_set_token_property::<T>(80 &collection,81 &who,82 &token_id,83 key.len() + value.len(),84 )85 .map(|()| sponsor)86 }87 UniqueNFTCall::ERC721UniqueExtensions(88 ERC721UniqueExtensionsCall::Transfer { token_id, .. },89 ) => {90 let token_id: TokenId = token_id.try_into().ok()?;91 withdraw_transfer::<T>(&collection, &who, &token_id).map(|()| sponsor)92 }93 UniqueNFTCall::ERC721UniqueMintable(94 ERC721UniqueMintableCall::Mint { .. }95 | ERC721UniqueMintableCall::MintCheckId { .. }96 | ERC721UniqueMintableCall::MintWithTokenUri { .. }97 | ERC721UniqueMintableCall::MintWithTokenUriCheckId { .. },98 ) => withdraw_create_item::<T>(99 &collection,100 &who,101 &CreateItemData::NFT(CreateNftData::default()),102 )103 .map(|()| sponsor),104 UniqueNFTCall::ERC721(ERC721Call::TransferFrom {105 token_id, from, ..106 }) => {107 let token_id: TokenId = token_id.try_into().ok()?;108 let from = T::CrossAccountId::from_eth(from);109 withdraw_transfer::<T>(&collection, &from, &token_id).map(|()| sponsor)110 }111 UniqueNFTCall::ERC721(ERC721Call::Approve { token_id, .. }) => {112 let token_id: TokenId = token_id.try_into().ok()?;113 withdraw_approve::<T>(&collection, who.as_sub(), &token_id)114 .map(|()| sponsor)115 }116 _ => None,117 }118 }119 CollectionMode::ReFungible => {120 let call = <UniqueRefungibleCall<T>>::parse(method_id, &mut reader).ok()??;121 refungible::call_sponsor(call, collection, who).map(|()| sponsor)122 }123 CollectionMode::Fungible(_) => {124 let call = <UniqueFungibleCall<T>>::parse(method_id, &mut reader).ok()??;125 match call {126 UniqueFungibleCall::ERC20(ERC20Call::Transfer { .. }) => {127 withdraw_transfer::<T>(&collection, who, &TokenId::default())128 .map(|()| sponsor)129 }130 UniqueFungibleCall::ERC20(ERC20Call::TransferFrom { from, .. }) => {131 let from = T::CrossAccountId::from_eth(from);132 withdraw_transfer::<T>(&collection, &from, &TokenId::default())133 .map(|()| sponsor)134 }135 UniqueFungibleCall::ERC20(ERC20Call::Approve { .. }) => {136 withdraw_approve::<T>(&collection, who.as_sub(), &TokenId::default())137 .map(|()| sponsor)138 }139 _ => None,140 }141 }142 }?))143 } else {144 let (collection_id, token_id) =145 T::EvmTokenAddressMapping::address_to_token(&call_context.contract_address)?;146 let collection = <CollectionHandle<T>>::new(collection_id)?;147 let sponsor = collection.sponsorship.sponsor()?.clone();148 let rft_collection = RefungibleHandle::cast(collection);149 let token = RefungibleTokenHandle(rft_collection, token_id);150 let (method_id, mut reader) = AbiReader::new_call(&call_context.input).ok()?;151 let call = <UniqueRefungibleTokenCall<T>>::parse(method_id, &mut reader).ok()??;152 Some(T::CrossAccountId::from_sub(153 refungible::token_call_sponsor(call, token, who).map(|()| sponsor)?,154 ))155 }156 }157}158159mod common {160 use super::*;161162 use pallet_common::erc::{CollectionCall};163164 pub fn collection_call_sponsor<T>(165 call: CollectionCall<T>,166 _collection: CollectionHandle<T>,167 _who: &T::CrossAccountId,168 ) -> Option<()>169 where170 T: UniqueConfig + FungibleConfig + NonfungibleConfig + RefungibleConfig,171 {172 use CollectionCall::*;173174 match call {175 176 ERC165Call(_, _)177 | CollectionProperty { .. }178 | CollectionProperties { .. }179 | HasCollectionPendingSponsor180 | CollectionSponsor181 | ContractAddress182 | AllowlistedCross { .. }183 | IsOwnerOrAdminEth { .. }184 | IsOwnerOrAdminCross { .. }185 | CollectionOwner186 | CollectionAdmins187 | CollectionLimits188 | CollectionNestingRestrictedIds189 | CollectionNestingPermissions190 | UniqueCollectionType => None,191192 193 AddToCollectionAllowList { .. }194 | AddToCollectionAllowListCross { .. }195 | RemoveFromCollectionAllowList { .. }196 | RemoveFromCollectionAllowListCross { .. }197 | AddCollectionAdminCross { .. }198 | RemoveCollectionAdminCross { .. }199 | AddCollectionAdmin { .. }200 | RemoveCollectionAdmin { .. }201 | SetNestingBool { .. }202 | SetNesting { .. }203 | SetCollectionAccess { .. }204 | SetCollectionMintMode { .. }205 | SetOwner { .. }206 | ChangeCollectionOwnerCross { .. }207 | SetCollectionProperty { .. }208 | SetCollectionProperties { .. }209 | DeleteCollectionProperty { .. }210 | DeleteCollectionProperties { .. }211 | SetCollectionSponsor { .. }212 | SetCollectionSponsorCross { .. }213 | SetCollectionLimit { .. }214 | ConfirmCollectionSponsorship215 | RemoveCollectionSponsor => None,216 }217 }218}