git.delta.rocks / unique-network / refs/commits / bfab6035a123

difftreelog

source

runtime/common/ethereum/sponsoring.rs8.8 KiBsourcehistory
1// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.2// This file is part of Unique Network.34// Unique Network is free software: you can redistribute it and/or modify5// it under the terms of the GNU General Public License as published by6// the Free Software Foundation, either version 3 of the License, or7// (at your option) any later version.89// Unique Network is distributed in the hope that it will be useful,10// but WITHOUT ANY WARRANTY; without even the implied warranty of11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the12// GNU General Public License for more details.1314// You should have received a copy of the GNU General Public License15// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.1617//! Implements EVM sponsoring logic via TransactionValidityHack1819use 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			// let (method_id, mut reader) = AbiReader::new_call(&call_context.input).ok()?;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			// Token existance isn't checked at this point and should be checked in `withdraw` method.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			// Readonly226			ERC165Call(_, _)227			| CollectionProperty { .. }228			| CollectionProperties { .. }229			| HasCollectionPendingSponsor230			| CollectionSponsor231			| ContractAddress232			| AllowlistedCross { .. }233			| IsOwnerOrAdminEth { .. }234			| IsOwnerOrAdminCross { .. }235			| CollectionOwner236			| CollectionAdmins237			| CollectionLimits238			| CollectionNesting239			| CollectionNestingRestrictedIds240			| CollectionNestingPermissions241			| UniqueCollectionType => None,242243			// Not sponsored244			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}