From b905adaff48faa2649018e34a06f8a591272d4d9 Mon Sep 17 00:00:00 2001 From: Yaroslav Bolyukin Date: Tue, 27 Jul 2021 16:34:57 +0000 Subject: [PATCH] refactor: extract evm transaction payment --- --- /dev/null +++ b/pallets/evm-transaction-payment/Cargo.toml @@ -0,0 +1,37 @@ +[package] +name = "pallet-evm-transaction-payment" +version = "0.1.0" +edition = "2018" + +[dependencies] +frame-support = { default-features = false, version = '3.0.0', git = 'https://github.com/paritytech/substrate.git', branch = 'polkadot-v0.9.8' } +frame-system = { default-features = false, version = '3.0.0', git = 'https://github.com/paritytech/substrate.git', branch = 'polkadot-v0.9.8' } +sp-runtime = { default-features = false, version = '3.0.0', git = 'https://github.com/paritytech/substrate.git', branch = 'polkadot-v0.9.8' } +sp-std = { default-features = false, version = '3.0.0', git = 'https://github.com/paritytech/substrate.git', branch = 'polkadot-v0.9.8' } +sp-io = { default-features = false, version = '3.0.0', git = 'https://github.com/paritytech/substrate.git', branch = 'polkadot-v0.9.8' } +sp-core = { default-features = false, version = '3.0.0', git = 'https://github.com/paritytech/substrate.git', branch = 'polkadot-v0.9.8' } +pallet-evm = { default-features = false, version = "5.0.0-dev", git = "https://github.com/uniquenetwork/frontier.git", branch = "injected-transactions-parachain" } +fp-evm = { default-features = false, version = "2.0.0", git = "https://github.com/uniquenetwork/frontier.git", branch = "injected-transactions-parachain" } +pallet-ethereum = { default-features = false, version = "3.0.0-dev", git = "https://github.com/uniquenetwork/frontier.git", branch = "injected-transactions-parachain" } +up-sponsorship = { default-features = false, path = '../../primitives/sponsorship' } + +[dependencies.codec] +default-features = false +features = ['derive'] +package = 'parity-scale-codec' +version = '2.0.0' + +[features] +default = ["std"] +std = [ + "frame-support/std", + "frame-system/std", + "sp-runtime/std", + "sp-std/std", + "sp-io/std", + "sp-core/std", + "pallet-evm/std", + "pallet-ethereum/std", + "fp-evm/std", + "up-sponsorship/std", +] --- /dev/null +++ b/pallets/evm-transaction-payment/src/lib.rs @@ -0,0 +1,98 @@ +#![cfg_attr(not(feature = "std"), no_std)] + +pub use pallet::*; + +#[frame_support::pallet] +pub mod pallet { + use core::marker::PhantomData; + use frame_support::traits::Currency; + use pallet_evm::EVMCurrencyAdapter; + use fp_evm::WithdrawReason; + use sp_core::{H160, U256}; + use sp_runtime::TransactionOutcome; + use up_sponsorship::SponsorshipHandler; + use sp_std::vec::Vec; + + type NegativeImbalanceOf = + ::AccountId>>::NegativeImbalance; + + #[pallet::config] + pub trait Config: frame_system::Config { + type SponsorshipHandler: SponsorshipHandler)>; + type Currency: Currency; + } + + #[pallet::pallet] + #[pallet::generate_store(pub(super) trait Store)] + pub struct Pallet(_); + + pub struct ChargeEvmLiquidityInfo + where + T: Config, + T: pallet_evm::Config, + { + who: H160, + negative_imbalance: NegativeImbalanceOf<::Currency, T>, + } + + pub struct TransactionValidityHack(PhantomData<*const T>); + impl fp_evm::TransactionValidityHack for TransactionValidityHack { + fn who_pays_fee(origin: H160, reason: &WithdrawReason) -> Option { + match reason { + WithdrawReason::Call { target, input } => { + // This method is only used for checking, we shouldn't touch storage in it + frame_support::storage::with_transaction(|| { + TransactionOutcome::Rollback(T::SponsorshipHandler::get_sponsor( + &origin, + &(*target, input.clone()), + )) + }) + } + _ => None, + } + } + } + + pub struct OnChargeTransaction(PhantomData<*const T>); + impl pallet_evm::OnChargeEVMTransaction for OnChargeTransaction + where + T: Config, + T: pallet_evm::Config, + { + type LiquidityInfo = Option>; + + fn withdraw_fee( + who: &H160, + reason: WithdrawReason, + fee: U256, + ) -> core::result::Result> { + let mut who_pays_fee = *who; + if let WithdrawReason::Call { target, input } = &reason { + who_pays_fee = T::SponsorshipHandler::get_sponsor(who, &(*target, input.clone())) + .unwrap_or(who_pays_fee); + } + let negative_imbalance = + EVMCurrencyAdapter::<::Currency, ()>::withdraw_fee( + &who_pays_fee, + reason, + fee, + )?; + Ok(negative_imbalance.map(|i| ChargeEvmLiquidityInfo { + who: who_pays_fee, + negative_imbalance: i, + })) + } + + fn correct_and_deposit_fee( + who: &H160, + corrected_fee: U256, + already_withdrawn: Self::LiquidityInfo, + ) -> core::result::Result<(), pallet_evm::Error> { + EVMCurrencyAdapter::<::Currency, ()>::correct_and_deposit_fee( + &already_withdrawn.as_ref().map(|e| e.who).unwrap_or(*who), + corrected_fee, + already_withdrawn.map(|e| e.negative_imbalance), + ) + } + } +} --- a/pallets/nft/src/eth/sponsoring.rs +++ b/pallets/nft/src/eth/sponsoring.rs @@ -1,35 +1,22 @@ //! Implements EVM sponsoring logic via OnChargeEVMTransaction use crate::{ - Collection, ChainLimit, CollectionById, Config, NftTransferBasket, FungibleTransferBasket, - eth::account::EvmBackwardsAddressMapping, + ChainLimit, Collection, CollectionById, Config, FungibleTransferBasket, NftTransferBasket, + eth::{account::EvmBackwardsAddressMapping, map_eth_to_id}, }; -use evm_coder::abi::AbiReader; +use evm_coder::{Call, abi::AbiReader}; use frame_support::{ storage::{StorageMap, StorageDoubleMap, StorageValue}, - traits::Currency, }; -use pallet_evm::{EVMCurrencyAdapter, WithdrawReason}; -use sp_core::{H160, U256}; +use sp_core::H160; use sp_std::prelude::*; +use up_sponsorship::SponsorshipHandler; use super::{ account::CrossAccountId, erc::{UniqueFungibleCall, UniqueNFTCall, ERC721Call, ERC20Call, ERC721UniqueExtensionsCall}, }; use core::convert::TryInto; - -type NegativeImbalanceOf = - ::AccountId>>::NegativeImbalance; - -pub struct ChargeEvmTransaction; -pub struct ChargeEvmLiquidityInfo -where - T: Config, - T: pallet_evm::Config, -{ - who: H160, - negative_imbalance: NegativeImbalanceOf<::Currency, T>, -} +use core::marker::PhantomData; struct AnyError; @@ -46,10 +33,9 @@ .map_err(|_| AnyError)? .ok_or(AnyError)?; match call { - UniqueNFTCall::ERC721UniqueExtensions(ERC721UniqueExtensionsCall::Transfer { - token_id, - .. - }) + UniqueNFTCall::ERC721UniqueExtensions( + ERC721UniqueExtensionsCall::TransferNft { token_id, .. }, + ) | UniqueNFTCall::ERC721(ERC721Call::TransferFrom { token_id, .. }) => { let token_id: u32 = token_id.try_into().map_err(|_| AnyError)?; let block_number = >::block_number() as T::BlockNumber; @@ -118,53 +104,23 @@ Err(AnyError) } -impl pallet_evm::OnChargeEVMTransaction for ChargeEvmTransaction -where - T: Config, - T: pallet_evm::Config, -{ - type LiquidityInfo = Option>; - - fn withdraw_fee( - who: &H160, - reason: WithdrawReason, - fee: U256, - ) -> Result> { - let mut who_pays_fee = *who; - if let WithdrawReason::Call { target, input } = &reason { - if let Some(collection_id) = crate::eth::map_eth_to_id(target) { - if let Some(collection) = >::get(collection_id) { - if let Some(sponsor) = collection.sponsorship.sponsor() { - if try_sponsor(who, collection_id, &collection, input).is_ok() { - who_pays_fee = - T::EvmBackwardsAddressMapping::from_account_id(sponsor.clone()); - } - } +pub struct NftEthSponsorshipHandler(PhantomData<*const T>); +impl SponsorshipHandler)> for NftEthSponsorshipHandler { + fn get_sponsor(who: &H160, call: &(H160, Vec)) -> Option { + if let Some(collection_id) = map_eth_to_id(&call.0) { + if let Some(collection) = >::get(collection_id) { + if !collection.sponsorship.confirmed() { + return None; + } + if try_sponsor(who, collection_id, &collection, &call.1).is_ok() { + return collection + .sponsorship + .sponsor() + .cloned() + .map(T::EvmBackwardsAddressMapping::from_account_id); } } } - - // TODO: Pay fee from substrate address - let negative_imbalance = EVMCurrencyAdapter::<::Currency, ()>::withdraw_fee( - &who_pays_fee, - reason, - fee, - )?; - Ok(negative_imbalance.map(|i| ChargeEvmLiquidityInfo { - who: who_pays_fee, - negative_imbalance: i, - })) - } - - fn correct_and_deposit_fee( - who: &H160, - corrected_fee: U256, - already_withdrawn: Self::LiquidityInfo, - ) -> Result<(), pallet_evm::Error> { - EVMCurrencyAdapter::<::Currency, ()>::correct_and_deposit_fee( - &already_withdrawn.as_ref().map(|e| e.who).unwrap_or(*who), - corrected_fee, - already_withdrawn.map(|e| e.negative_imbalance), - ) + None } } -- gitstuff