Skip to content

Commit

Permalink
Introduce EVMFungibleAdapter (polkadot-evm#1282) (#22)
Browse files Browse the repository at this point in the history
* new EVMFungibleAdapter struct

* Update comment

Co-authored-by: Ahmad Kaouk <[email protected]>
  • Loading branch information
boundless-forest and ahmadkaouk authored May 7, 2024
1 parent ac278aa commit a562b66
Showing 1 changed file with 75 additions and 1 deletion.
76 changes: 75 additions & 1 deletion frame/evm/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -76,11 +76,12 @@ use scale_info::TypeInfo;
use frame_support::{
dispatch::{DispatchResultWithPostInfo, Pays, PostDispatchInfo},
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 @@ -1012,6 +1013,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);
}
}
}

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

0 comments on commit a562b66

Please sign in to comment.