Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Introduce EVMFungibleAdapter #1282

Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
76 changes: 75 additions & 1 deletion frame/evm/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -77,11 +77,12 @@ use frame_support::{
dispatch::{DispatchResultWithPostInfo, Pays, PostDispatchInfo},
storage::{child::KillStorageResult, KeyPrefixIterator},
traits::{
fungible::{Balanced, Credit, Debt},
tokens::{
currency::Currency,
fungible::Inspect,
imbalance::{Imbalance, OnUnbalanced, SignedImbalance},
ExistenceRequirement, Fortitude, Preservation, WithdrawReasons,
ExistenceRequirement, Fortitude, Precision, Preservation, WithdrawReasons,
},
FindAuthor, Get, Time,
},
Expand Down Expand Up @@ -1048,6 +1049,79 @@ where
}
}
}
/// Implements transaction payment for a pallet implementing the [`fungible`]
/// trait (eg. pallet_balances) using an unbalance handler (implementing
/// [`OnUnbalanced`]).
///
/// Equivalent of `EVMCurrencyAdapter` but for fungible traits. Similar to `FungibleAdapter` of
/// `pallet_transaction_payment`
pub struct EVMFungibleAdapter<F, OU>(sp_std::marker::PhantomData<(F, OU)>);

impl<T, F, OU> OnChargeEVMTransaction<T> for EVMFungibleAdapter<F, OU>
where
T: Config,
F: Balanced<T::AccountId>,
OU: OnUnbalanced<Credit<T::AccountId, F>>,
U256: UniqueSaturatedInto<<F as Inspect<<T as frame_system::Config>::AccountId>>::Balance>,
{
// Kept type as Option to satisfy bound of Default
type LiquidityInfo = Option<Credit<T::AccountId, F>>;

fn withdraw_fee(who: &H160, fee: U256) -> Result<Self::LiquidityInfo, Error<T>> {
if fee.is_zero() {
return Ok(None);
}
let account_id = T::AddressMapping::into_account_id(*who);
let imbalance = F::withdraw(
&account_id,
fee.unique_saturated_into(),
Precision::Exact,
Preservation::Preserve,
Fortitude::Polite,
)
.map_err(|_| Error::<T>::BalanceLow)?;
Ok(Some(imbalance))
}

fn correct_and_deposit_fee(
who: &H160,
corrected_fee: U256,
base_fee: U256,
already_withdrawn: Self::LiquidityInfo,
) -> Self::LiquidityInfo {
if let Some(paid) = already_withdrawn {
let account_id = T::AddressMapping::into_account_id(*who);

// Calculate how much refund we should return
let refund_amount = paid
.peek()
.saturating_sub(corrected_fee.unique_saturated_into());
// refund to the account that paid the fees.
let refund_imbalance = F::deposit(&account_id, refund_amount, Precision::BestEffort)
.unwrap_or_else(|_| Debt::<T::AccountId, F>::zero());

// merge the imbalance caused by paying the fees and refunding parts of it again.
let adjusted_paid = paid
.offset(refund_imbalance)
.same()
.unwrap_or_else(|_| Credit::<T::AccountId, F>::zero());

let (base_fee, tip) = adjusted_paid.split(base_fee.unique_saturated_into());
// Handle base fee. Can be either burned, rationed, etc ...
OU::on_unbalanced(base_fee);
return Some(tip);
}
None
}

fn pay_priority_fee(tip: Self::LiquidityInfo) {
// Default Ethereum behaviour: issue the tip to the block author.
if let Some(tip) = tip {
let account_id = T::AddressMapping::into_account_id(<Pallet<T>>::find_author());
let _ = F::deposit(&account_id, tip.peek(), Precision::BestEffort);
}
}
}
boundless-forest marked this conversation as resolved.
Show resolved Hide resolved

/// Implementation for () does not specify what to do with imbalance
impl<T> OnChargeEVMTransaction<T> for ()
Expand Down