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 if collection.mode != CollectionMode::ReFungible {148 return None;149 }150 let sponsor = collection.sponsorship.sponsor()?.clone();151 let rft_collection = RefungibleHandle::cast(collection);152 153 let token = RefungibleTokenHandle(rft_collection, token_id);154155 let (method_id, mut reader) = AbiReader::new_call(&call_context.input).ok()?;156 let call = <UniqueRefungibleTokenCall<T>>::parse(method_id, &mut reader).ok()??;157 Some(T::CrossAccountId::from_sub(158 refungible::token_call_sponsor(call, token, who).map(|()| sponsor)?,159 ))160 }161 }162}163164mod common {165 use super::*;166167 use pallet_common::erc::{CollectionCall};168169 pub fn collection_call_sponsor<T>(170 call: CollectionCall<T>,171 _collection: CollectionHandle<T>,172 _who: &T::CrossAccountId,173 ) -> Option<()>174 where175 T: UniqueConfig + FungibleConfig + NonfungibleConfig + RefungibleConfig,176 {177 use CollectionCall::*;178179 match call {180 181 ERC165Call(_, _)182 | CollectionProperty { .. }183 | CollectionProperties { .. }184 | HasCollectionPendingSponsor185 | CollectionSponsor186 | ContractAddress187 | AllowlistedCross { .. }188 | IsOwnerOrAdminEth { .. }189 | IsOwnerOrAdminCross { .. }190 | CollectionOwner191 | CollectionAdmins192 | CollectionLimits193 | CollectionNestingRestrictedIds194 | CollectionNestingPermissions195 | UniqueCollectionType => None,196197 198 AddToCollectionAllowList { .. }199 | AddToCollectionAllowListCross { .. }200 | RemoveFromCollectionAllowList { .. }201 | RemoveFromCollectionAllowListCross { .. }202 | AddCollectionAdminCross { .. }203 | RemoveCollectionAdminCross { .. }204 | AddCollectionAdmin { .. }205 | RemoveCollectionAdmin { .. }206 | SetNestingBool { .. }207 | SetNesting { .. }208 | SetCollectionAccess { .. }209 | SetCollectionMintMode { .. }210 | SetOwner { .. }211 | ChangeCollectionOwnerCross { .. }212 | SetCollectionProperty { .. }213 | SetCollectionProperties { .. }214 | DeleteCollectionProperty { .. }215 | DeleteCollectionProperties { .. }216 | SetCollectionSponsor { .. }217 | SetCollectionSponsorCross { .. }218 | SetCollectionLimit { .. }219 | ConfirmCollectionSponsorship220 | RemoveCollectionSponsor => None,221 }222 }223}