git.delta.rocks / unique-network / refs/commits / 71150e7c9b75

difftreelog

feat use new ethereum sponsoring interface

Yaroslav Bolyukin2023-10-02parent: #6ab76d3.patch.diff
in: master

2 files changed

modifiedpallets/evm-transaction-payment/src/lib.rsdiffbeforeafterboth
60 pub struct Pallet<T>(_);60 pub struct Pallet<T>(_);
61}61}
6262
63/// Implements [`fp_evm::TransactionValidityHack`], which provides sponsor address to pallet-evm
64pub struct TransactionValidityHack<T: Config>(PhantomData<*const T>);
65impl<T: Config> fp_evm::TransactionValidityHack<T::CrossAccountId> for TransactionValidityHack<T> {63fn who_pays_fee<T: Config>(
66 fn who_pays_fee(
67 origin: H160,64 origin: H160,
68 max_fee: U256,65 max_fee: U256,
69 reason: &WithdrawReason,66 reason: &WithdrawReason,
70 ) -> Option<T::CrossAccountId> {67) -> Option<T::CrossAccountId> {
71 match reason {68 match reason {
72 WithdrawReason::Call { target, input } => {69 WithdrawReason::Call { target, input, .. } => {
73 let origin_sub = T::CrossAccountId::from_eth(origin);70 let origin_sub = T::CrossAccountId::from_eth(origin);
74 let call_context = CallContext {71 let call_context = CallContext {
75 contract_address: *target,72 contract_address: *target,
81 _ => None,78 _ => None,
82 }79 }
83 }80}
84}81
8582fn get_sponsor<T: Config>(
83 source: H160,
84 max_fee_per_gas: Option<U256>,
85 gas_limit: u64,
86 reason: &WithdrawReason,
87 is_transactional: bool,
88 is_check: bool,
89) -> Option<T::CrossAccountId> {
90 let accept_gas_fee = |gas_fee| {
91 let (base_fee, _) = T::FeeCalculator::min_gas_price();
92 base_fee <= gas_fee && gas_fee <= base_fee * 21 / 10
93 };
94 let (max_fee_per_gas, may_sponsor) = match (max_fee_per_gas, is_transactional) {
95 (Some(max_fee_per_gas), _) => (max_fee_per_gas, accept_gas_fee(max_fee_per_gas)),
96 // Gas price check is skipped for non-transactional calls that don't
97 // define a `max_fee_per_gas` input.
98 (None, false) => (Default::default(), true),
99 _ => return None,
100 };
101
102 let max_fee = max_fee_per_gas.saturating_mul(gas_limit.into());
103
104 // #[cfg(feature = "debug-logging")]
105 // log::trace!(target: "sponsoring", "checking who will pay fee for {:?} {:?}", source, reason);
106 with_transaction(|| {
107 let result = may_sponsor
108 .then(|| who_pays_fee::<T>(source, max_fee, reason))
109 .flatten();
110 if is_check {
111 TransactionOutcome::Rollback(Ok::<_, DispatchError>(result))
112 } else {
113 TransactionOutcome::Commit(Ok(result))
114 }
115 })
116 .ok()
117 .flatten()
118}
86/// Implements sponsoring for evm calls performed from pallet-evm (via api.tx.ethereum.transact/api.tx.evm.call)119/// Implements sponsoring for evm calls performed from pallet-evm (via api.tx.ethereum.transact/api.tx.evm.call)
87pub struct BridgeSponsorshipHandler<T>(PhantomData<T>);120pub struct BridgeSponsorshipHandler<T>(PhantomData<T>);
88impl<T, C> SponsorshipHandler<T::AccountId, C> for BridgeSponsorshipHandler<T>121impl<T, C> SponsorshipHandler<T::AccountId, C> for BridgeSponsorshipHandler<T>
128 }161 }
129}162}
163
164/// Set transaction sponsor if available and enough balance.
165pub struct TransactionValidity<T>(PhantomData<T>);
166impl<T: Config> OnCheckEvmTransaction<T> for TransactionValidity<T> {
167 fn on_check_evm_transaction(
168 v: &mut CheckEvmTransaction,
169 origin: &T::CrossAccountId,
170 ) -> Result<(), TransactionValidationError> {
171 let who = &v.who;
172 let max_fee_per_gas = Some(v.transaction_fee_input()?.0);
173 let gas_limit = v.transaction.gas_limit.low_u64();
174 let reason = if let Some(to) = v.transaction.to {
175 WithdrawReason::Call {
176 target: to,
177 input: v.transaction.input.clone(),
178 max_fee_per_gas,
179 gas_limit,
180 is_transactional: v.config.is_transactional,
181 is_check: true,
182 }
183 } else {
184 WithdrawReason::Create
185 };
186 let sponsor = get_sponsor::<T>(
187 *origin.as_eth(),
188 max_fee_per_gas,
189 gas_limit,
190 &reason,
191 v.config.is_transactional,
192 true,
193 )
194 .as_ref()
195 .map(pallet_evm::Pallet::<T>::account_basic_by_id)
196 .map(|v| v.0);
197 let fee = max_fee_per_gas
198 .unwrap()
199 .saturating_mul(v.transaction.gas_limit);
200 if let Some(sponsor) = sponsor.as_ref() {
201 if who.balance < v.transaction.value || sponsor.balance < fee {
202 return Err(TransactionValidationError::BalanceTooLow.into());
203 }
204 } else {
205 let total_payment = v.transaction.value.saturating_add(fee);
206 if who.balance < total_payment {
207 return Err(TransactionValidationError::BalanceTooLow.into());
208 }
209 }
210
211 let who = sponsor.unwrap_or_else(|| v.who.clone());
212 v.who.balance = who.balance;
213 Ok(())
214 }
215}
216
217/// Implements the transaction payment for a pallet implementing the `Currency`
218/// trait (eg. the pallet_balances) using an unbalance handler (implementing
219/// `OnUnbalanced`).
220/// Similar to `CurrencyAdapter` of `pallet_transaction_payment`
221pub struct WrappedEVMCurrencyAdapter<C, OU>(sp_std::marker::PhantomData<(C, OU)>);
222impl<T, C, OU> OnChargeEVMTransaction<T> for WrappedEVMCurrencyAdapter<C, OU>
223where
224 T: Config,
225 C: Currency<<T as frame_system::Config>::AccountId>,
226 C::PositiveImbalance: Imbalance<
227 <C as Currency<<T as frame_system::Config>::AccountId>>::Balance,
228 Opposite = C::NegativeImbalance,
229 >,
230 C::NegativeImbalance: Imbalance<
231 <C as Currency<<T as frame_system::Config>::AccountId>>::Balance,
232 Opposite = C::PositiveImbalance,
233 >,
234 OU: OnUnbalanced<NegativeImbalanceOf<C, T>>,
235 U256: UniqueSaturatedInto<<C as Currency<<T as frame_system::Config>::AccountId>>::Balance>,
236{
237 // Kept type as Option to satisfy bound of Default
238 type LiquidityInfo = (Option<NegativeImbalanceOf<C, T>>, Option<T::CrossAccountId>);
239
240 fn withdraw_fee(
241 who: &T::CrossAccountId,
242 reason: WithdrawReason,
243 fee: U256,
244 ) -> Result<Self::LiquidityInfo, pallet_evm::Error<T>> {
245 let sponsor = match reason {
246 WithdrawReason::Call {
247 max_fee_per_gas,
248 gas_limit,
249 is_transactional,
250 is_check,
251 ..
252 } => get_sponsor::<T>(
253 *who.as_eth(),
254 max_fee_per_gas,
255 gas_limit,
256 &reason,
257 is_transactional,
258 is_check,
259 ),
260 _ => None,
261 };
262
263 let who = sponsor.as_ref().unwrap_or(who);
264 <pallet_evm::EVMCurrencyAdapter<C, OU> as OnChargeEVMTransaction<T>>::withdraw_fee(
265 who, reason, fee,
266 )
267 .map(|li| (li, sponsor))
268 }
269
270 fn correct_and_deposit_fee(
271 who: &T::CrossAccountId,
272 corrected_fee: U256,
273 base_fee: U256,
274 already_withdrawn: Self::LiquidityInfo,
275 ) -> Self::LiquidityInfo {
276 let (already_withdrawn, sponsor) = already_withdrawn;
277 let who = sponsor.as_ref().unwrap_or(who);
278 (
279 <pallet_evm::EVMCurrencyAdapter<C, OU> as OnChargeEVMTransaction<T>>::correct_and_deposit_fee(
280 who,
281 corrected_fee,
282 base_fee,
283 already_withdrawn,
284 ),
285 None
286 )
287 }
288
289 fn pay_priority_fee(tip: Self::LiquidityInfo) {
290 <pallet_evm::EVMCurrencyAdapter<C, OU> as OnChargeEVMTransaction<T>>::pay_priority_fee(
291 tip.0,
292 )
293 }
294}
130295
modifiedruntime/common/config/ethereum.rsdiffbeforeafterboth
89 type OnCreate = pallet_evm_contract_helpers::HelpersOnCreate<Self>;89 type OnCreate = pallet_evm_contract_helpers::HelpersOnCreate<Self>;
90 type ChainId = ChainId;90 type ChainId = ChainId;
91 type Runner = pallet_evm::runner::stack::Runner<Self>;91 type Runner = pallet_evm::runner::stack::Runner<Self>;
92 type OnChargeTransaction = pallet_evm::EVMCurrencyAdapter<Balances, DealWithFees>;92 type OnChargeTransaction =
93 type TransactionValidityHack = pallet_evm_transaction_payment::TransactionValidityHack<Self>;93 pallet_evm_transaction_payment::WrappedEVMCurrencyAdapter<Balances, DealWithFees>;
94 type FindAuthor = EthereumFindAuthor<Aura>;94 type FindAuthor = EthereumFindAuthor<Aura>;
95 type Timestamp = crate::Timestamp;95 type Timestamp = crate::Timestamp;
96 type WeightInfo = pallet_evm::weights::SubstrateWeight<Self>;96 type WeightInfo = pallet_evm::weights::SubstrateWeight<Self>;
97 type GasLimitPovSizeRatio = ProofSizePerGas;97 type GasLimitPovSizeRatio = ProofSizePerGas;
98 type OnCheckEvmTransaction = pallet_evm_transaction_payment::TransactionValidity<Self>;
98}99}
99100
100impl pallet_evm_migration::Config for Runtime {101impl pallet_evm_migration::Config for Runtime {