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

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};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			// let (method_id, mut reader) = AbiReader::new_call(&call_context.input).ok()?;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			// Token existance isn't checked at this point and should be checked in `withdraw` method.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			// Readonly225			ERC165Call(_, _)226			| CollectionProperty { .. }227			| CollectionProperties { .. }228			| HasCollectionPendingSponsor229			| CollectionSponsor230			| ContractAddress231			| AllowlistedCross { .. }232			| IsOwnerOrAdminEth { .. }233			| IsOwnerOrAdminCross { .. }234			| CollectionOwner235			| CollectionAdmins236			| CollectionLimits237			| CollectionNesting238			| CollectionNestingRestrictedIds239			| CollectionNestingPermissions240			| UniqueCollectionType => None,241242			// Not sponsored243			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}