12345678910111213141516171819use core::{convert::TryInto, marker::PhantomData};2021use evm_coder::Call;22use pallet_common::{eth::map_eth_to_id, CollectionHandle};23use pallet_evm::account::CrossAccountId;24use pallet_evm_transaction_payment::CallContext;25use pallet_fungible::{26 erc::{ERC20Call, UniqueFungibleCall},27 Config as FungibleConfig,28};29use pallet_nonfungible::{30 erc::{31 ERC721Call, ERC721UniqueExtensionsCall, ERC721UniqueMintableCall, TokenPropertiesCall,32 UniqueNFTCall,33 },34 Config as NonfungibleConfig, NonfungibleHandle, Pallet as NonfungiblePallet,35};36use pallet_refungible::{37 erc::UniqueRefungibleCall,38 erc_token::{RefungibleTokenHandle, UniqueRefungibleTokenCall},39 Config as RefungibleConfig, RefungibleHandle,40};41use pallet_unique::Config as UniqueConfig;42use sp_std::prelude::*;43use up_data_structs::{44 mapping::TokenAddressMapping, CollectionMode, CreateItemData, CreateNftData, TokenId,45};46use up_sponsorship::SponsorshipHandler;4748use crate::{runtime_common::sponsoring::*, Runtime};4950mod refungible;5152pub type EvmSponsorshipHandler = (53 UniqueEthSponsorshipHandler<Runtime>,54 pallet_evm_contract_helpers::HelpersContractSponsoring<Runtime>,55);5657pub struct UniqueEthSponsorshipHandler<T: UniqueConfig>(PhantomData<*const T>);58impl<T: UniqueConfig + FungibleConfig + NonfungibleConfig + RefungibleConfig>59 SponsorshipHandler<T::CrossAccountId, CallContext> for UniqueEthSponsorshipHandler<T>60where61 T::AccountId: From<[u8; 32]>,62{63 fn get_sponsor(64 who: &T::CrossAccountId,65 call_context: &CallContext,66 ) -> Option<T::CrossAccountId> {67 if let Some(collection_id) = map_eth_to_id(&call_context.contract_address) {68 let collection = <CollectionHandle<T>>::new(collection_id)?;69 let sponsor = collection.sponsorship.sponsor()?.clone();70 71 Some(T::CrossAccountId::from_sub(match &collection.mode {72 CollectionMode::NFT => {73 let collection = NonfungibleHandle::cast(collection);74 let call = <UniqueNFTCall<T>>::parse_full(&call_context.input).ok()??;75 match call {76 UniqueNFTCall::TokenProperties(call) => match call {77 TokenPropertiesCall::SetProperty {78 token_id,79 key,80 value,81 ..82 } => {83 let token_id: TokenId = token_id.try_into().ok()?;84 withdraw_set_existing_token_property::<T>(85 &collection,86 who,87 &token_id,88 key.len() + value.len(),89 )90 .map(|()| sponsor)91 }92 TokenPropertiesCall::SetProperties {93 token_id,94 properties,95 ..96 } => {97 let token_id: TokenId = token_id.try_into().ok()?;98 let data_size = properties99 .into_iter()100 .map(|p| p.key().len() + p.value().len())101 .sum();102103 withdraw_set_existing_token_property::<T>(104 &collection,105 who,106 &token_id,107 data_size,108 )109 .map(|()| sponsor)110 }111 _ => None,112 },113 UniqueNFTCall::ERC721UniqueExtensions(call) => match call {114 ERC721UniqueExtensionsCall::Transfer { token_id, .. } => {115 let token_id: TokenId = token_id.try_into().ok()?;116 withdraw_transfer::<T>(&collection, who, &token_id)117 .map(|()| sponsor)118 }119 ERC721UniqueExtensionsCall::MintCross { properties, .. } => {120 withdraw_create_item::<T>(121 &collection,122 who,123 &CreateItemData::NFT(CreateNftData::default()),124 )?;125126 let token_id =127 <NonfungiblePallet<T>>::next_token_id(&collection).ok()?;128 let data_size: usize = properties129 .into_iter()130 .map(|p| p.key().len() + p.value().len())131 .sum();132133 withdraw_set_token_property::<T>(&collection, &token_id, data_size)134 .map(|()| sponsor)135 }136 _ => None,137 },138 UniqueNFTCall::ERC721UniqueMintable(139 ERC721UniqueMintableCall::Mint { .. }140 | ERC721UniqueMintableCall::MintCheckId { .. }141 | ERC721UniqueMintableCall::MintWithTokenUri { .. }142 | ERC721UniqueMintableCall::MintWithTokenUriCheckId { .. },143 ) => withdraw_create_item::<T>(144 &collection,145 who,146 &CreateItemData::NFT(CreateNftData::default()),147 )148 .map(|()| sponsor),149 UniqueNFTCall::ERC721(ERC721Call::TransferFrom {150 token_id, from, ..151 }) => {152 let token_id: TokenId = token_id.try_into().ok()?;153 let from = T::CrossAccountId::from_eth(from);154 withdraw_transfer::<T>(&collection, &from, &token_id).map(|()| sponsor)155 }156 UniqueNFTCall::ERC721(ERC721Call::Approve { token_id, .. }) => {157 let token_id: TokenId = token_id.try_into().ok()?;158 withdraw_approve::<T>(&collection, who.as_sub(), &token_id)159 .map(|()| sponsor)160 }161 _ => None,162 }163 }164 CollectionMode::ReFungible => {165 let call =166 <UniqueRefungibleCall<T>>::parse_full(&call_context.input).ok()??;167 refungible::call_sponsor(call, collection, who).map(|()| sponsor)168 }169 CollectionMode::Fungible(_) => {170 let call = <UniqueFungibleCall<T>>::parse_full(&call_context.input).ok()??;171 match call {172 UniqueFungibleCall::ERC20(ERC20Call::Transfer { .. }) => {173 withdraw_transfer::<T>(&collection, who, &TokenId::default())174 .map(|()| sponsor)175 }176 UniqueFungibleCall::ERC20(ERC20Call::TransferFrom { from, .. }) => {177 let from = T::CrossAccountId::from_eth(from);178 withdraw_transfer::<T>(&collection, &from, &TokenId::default())179 .map(|()| sponsor)180 }181 UniqueFungibleCall::ERC20(ERC20Call::Approve { .. }) => {182 withdraw_approve::<T>(&collection, who.as_sub(), &TokenId::default())183 .map(|()| sponsor)184 }185 _ => None,186 }187 }188 }?))189 } else {190 let (collection_id, token_id) =191 T::EvmTokenAddressMapping::address_to_token(&call_context.contract_address)?;192 let collection = <CollectionHandle<T>>::new(collection_id)?;193 if collection.mode != CollectionMode::ReFungible {194 return None;195 }196 let sponsor = collection.sponsorship.sponsor()?.clone();197 let rft_collection = RefungibleHandle::cast(collection);198 199 let token = RefungibleTokenHandle(rft_collection, token_id);200201 let call = <UniqueRefungibleTokenCall<T>>::parse_full(&call_context.input).ok()??;202 Some(T::CrossAccountId::from_sub(203 refungible::token_call_sponsor(call, token, who).map(|()| sponsor)?,204 ))205 }206 }207}208209mod common {210 use pallet_common::erc::CollectionCall;211212 use super::*;213214 pub fn collection_call_sponsor<T>(215 call: CollectionCall<T>,216 _collection: CollectionHandle<T>,217 _who: &T::CrossAccountId,218 ) -> Option<()>219 where220 T: UniqueConfig + FungibleConfig + NonfungibleConfig + RefungibleConfig,221 {222 use CollectionCall::*;223224 match call {225 226 ERC165Call(_, _)227 | CollectionProperty { .. }228 | CollectionProperties { .. }229 | HasCollectionPendingSponsor230 | CollectionSponsor231 | ContractAddress232 | AllowlistedCross { .. }233 | IsOwnerOrAdminEth { .. }234 | IsOwnerOrAdminCross { .. }235 | CollectionOwner236 | CollectionAdmins237 | CollectionLimits238 | CollectionNesting239 | CollectionNestingRestrictedIds240 | CollectionNestingPermissions241 | UniqueCollectionType => None,242243 244 AddToCollectionAllowList { .. }245 | AddToCollectionAllowListCross { .. }246 | RemoveFromCollectionAllowList { .. }247 | RemoveFromCollectionAllowListCross { .. }248 | AddCollectionAdminCross { .. }249 | RemoveCollectionAdminCross { .. }250 | AddCollectionAdmin { .. }251 | RemoveCollectionAdmin { .. }252 | SetNestingBool { .. }253 | SetNesting { .. }254 | SetNestingCollectionIds { .. }255 | SetCollectionAccess { .. }256 | SetCollectionMintMode { .. }257 | SetOwner { .. }258 | ChangeCollectionOwnerCross { .. }259 | SetCollectionProperty { .. }260 | SetCollectionProperties { .. }261 | DeleteCollectionProperty { .. }262 | DeleteCollectionProperties { .. }263 | SetCollectionSponsor { .. }264 | SetCollectionSponsorCross { .. }265 | SetCollectionLimit { .. }266 | ConfirmCollectionSponsorship267 | RemoveCollectionSponsor => None,268 }269 }270}