12345678910111213141516171819use core::{convert::TryInto, marker::PhantomData};20use evm_coder::{Call};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, Pallet as NonfungiblePallet, NonfungibleHandle,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>59where60 T::AccountId: From<[u8; 32]>,61{62 fn get_sponsor(63 who: &T::CrossAccountId,64 call_context: &CallContext,65 ) -> Option<T::CrossAccountId> {66 if let Some(collection_id) = map_eth_to_id(&call_context.contract_address) {67 let collection = <CollectionHandle<T>>::new(collection_id)?;68 let sponsor = collection.sponsorship.sponsor()?.clone();69 70 Some(T::CrossAccountId::from_sub(match &collection.mode {71 CollectionMode::NFT => {72 let collection = NonfungibleHandle::cast(collection);73 let call = <UniqueNFTCall<T>>::parse_full(&call_context.input).ok()??;74 match call {75 UniqueNFTCall::TokenProperties(call) => match call {76 TokenPropertiesCall::SetProperty {77 token_id,78 key,79 value,80 ..81 } => {82 let token_id: TokenId = token_id.try_into().ok()?;83 withdraw_set_existing_token_property::<T>(84 &collection,85 who,86 &token_id,87 key.len() + value.len(),88 )89 .map(|()| sponsor)90 }91 TokenPropertiesCall::SetProperties {92 token_id,93 properties,94 ..95 } => {96 let token_id: TokenId = token_id.try_into().ok()?;97 let data_size = properties98 .into_iter()99 .map(|p| p.key().len() + p.value().len())100 .sum();101102 withdraw_set_existing_token_property::<T>(103 &collection,104 who,105 &token_id,106 data_size,107 )108 .map(|()| sponsor)109 }110 _ => None,111 },112 UniqueNFTCall::ERC721UniqueExtensions(call) => match call {113 ERC721UniqueExtensionsCall::Transfer { token_id, .. } => {114 let token_id: TokenId = token_id.try_into().ok()?;115 withdraw_transfer::<T>(&collection, who, &token_id)116 .map(|()| sponsor)117 }118 ERC721UniqueExtensionsCall::MintCross { properties, .. } => {119 withdraw_create_item::<T>(120 &collection,121 who,122 &CreateItemData::NFT(CreateNftData::default()),123 )?;124125 let token_id =126 <NonfungiblePallet<T>>::next_token_id(&collection).ok()?;127 let data_size: usize = properties128 .into_iter()129 .map(|p| p.key().len() + p.value().len())130 .sum();131132 withdraw_set_token_property::<T>(&collection, &token_id, data_size)133 .map(|()| sponsor)134 }135 _ => None,136 },137 UniqueNFTCall::ERC721UniqueMintable(138 ERC721UniqueMintableCall::Mint { .. }139 | ERC721UniqueMintableCall::MintCheckId { .. }140 | ERC721UniqueMintableCall::MintWithTokenUri { .. }141 | ERC721UniqueMintableCall::MintWithTokenUriCheckId { .. },142 ) => withdraw_create_item::<T>(143 &collection,144 who,145 &CreateItemData::NFT(CreateNftData::default()),146 )147 .map(|()| sponsor),148 UniqueNFTCall::ERC721(ERC721Call::TransferFrom {149 token_id, from, ..150 }) => {151 let token_id: TokenId = token_id.try_into().ok()?;152 let from = T::CrossAccountId::from_eth(from);153 withdraw_transfer::<T>(&collection, &from, &token_id).map(|()| sponsor)154 }155 UniqueNFTCall::ERC721(ERC721Call::Approve { token_id, .. }) => {156 let token_id: TokenId = token_id.try_into().ok()?;157 withdraw_approve::<T>(&collection, who.as_sub(), &token_id)158 .map(|()| sponsor)159 }160 _ => None,161 }162 }163 CollectionMode::ReFungible => {164 let call =165 <UniqueRefungibleCall<T>>::parse_full(&call_context.input).ok()??;166 refungible::call_sponsor(call, collection, who).map(|()| sponsor)167 }168 CollectionMode::Fungible(_) => {169 let call = <UniqueFungibleCall<T>>::parse_full(&call_context.input).ok()??;170 match call {171 UniqueFungibleCall::ERC20(ERC20Call::Transfer { .. }) => {172 withdraw_transfer::<T>(&collection, who, &TokenId::default())173 .map(|()| sponsor)174 }175 UniqueFungibleCall::ERC20(ERC20Call::TransferFrom { from, .. }) => {176 let from = T::CrossAccountId::from_eth(from);177 withdraw_transfer::<T>(&collection, &from, &TokenId::default())178 .map(|()| sponsor)179 }180 UniqueFungibleCall::ERC20(ERC20Call::Approve { .. }) => {181 withdraw_approve::<T>(&collection, who.as_sub(), &TokenId::default())182 .map(|()| sponsor)183 }184 _ => None,185 }186 }187 }?))188 } else {189 let (collection_id, token_id) =190 T::EvmTokenAddressMapping::address_to_token(&call_context.contract_address)?;191 let collection = <CollectionHandle<T>>::new(collection_id)?;192 if collection.mode != CollectionMode::ReFungible {193 return None;194 }195 let sponsor = collection.sponsorship.sponsor()?.clone();196 let rft_collection = RefungibleHandle::cast(collection);197 198 let token = RefungibleTokenHandle(rft_collection, token_id);199200 let call = <UniqueRefungibleTokenCall<T>>::parse_full(&call_context.input).ok()??;201 Some(T::CrossAccountId::from_sub(202 refungible::token_call_sponsor(call, token, who).map(|()| sponsor)?,203 ))204 }205 }206}207208mod common {209 use super::*;210211 use pallet_common::erc::{CollectionCall};212213 pub fn collection_call_sponsor<T>(214 call: CollectionCall<T>,215 _collection: CollectionHandle<T>,216 _who: &T::CrossAccountId,217 ) -> Option<()>218 where219 T: UniqueConfig + FungibleConfig + NonfungibleConfig + RefungibleConfig,220 {221 use CollectionCall::*;222223 match call {224 225 ERC165Call(_, _)226 | CollectionProperty { .. }227 | CollectionProperties { .. }228 | HasCollectionPendingSponsor229 | CollectionSponsor230 | ContractAddress231 | AllowlistedCross { .. }232 | IsOwnerOrAdminEth { .. }233 | IsOwnerOrAdminCross { .. }234 | CollectionOwner235 | CollectionAdmins236 | CollectionLimits237 | CollectionNesting238 | CollectionNestingRestrictedIds239 | CollectionNestingPermissions240 | UniqueCollectionType => None,241242 243 AddToCollectionAllowList { .. }244 | AddToCollectionAllowListCross { .. }245 | RemoveFromCollectionAllowList { .. }246 | RemoveFromCollectionAllowListCross { .. }247 | AddCollectionAdminCross { .. }248 | RemoveCollectionAdminCross { .. }249 | AddCollectionAdmin { .. }250 | RemoveCollectionAdmin { .. }251 | SetNestingBool { .. }252 | SetNesting { .. }253 | SetNestingCollectionIds { .. }254 | SetCollectionAccess { .. }255 | SetCollectionMintMode { .. }256 | SetOwner { .. }257 | ChangeCollectionOwnerCross { .. }258 | SetCollectionProperty { .. }259 | SetCollectionProperties { .. }260 | DeleteCollectionProperty { .. }261 | DeleteCollectionProperties { .. }262 | SetCollectionSponsor { .. }263 | SetCollectionSponsorCross { .. }264 | SetCollectionLimit { .. }265 | ConfirmCollectionSponsorship266 | RemoveCollectionSponsor => None,267 }268 }269}