example_erc20_gas/
handler.rs1use revm::{
2 context::{journaled_state::account::JournaledAccountTr, Cfg},
3 context_interface::{result::HaltReason, Block, ContextTr, JournalTr, Transaction},
4 handler::{
5 pre_execution::{calculate_caller_fee, validate_account_nonce_and_code_with_components},
6 EvmTr, EvmTrError, FrameResult, FrameTr, Handler,
7 },
8 interpreter::{interpreter_action::FrameInit, InitialAndFloorGas},
9 primitives::{hardfork::SpecId, U256},
10 state::EvmState,
11};
12
13use crate::{erc_address_storage, TOKEN};
14
15#[derive(Debug)]
19pub struct Erc20MainnetHandler<EVM, ERROR, FRAME> {
20 _phantom: core::marker::PhantomData<(EVM, ERROR, FRAME)>,
21}
22
23impl<CTX, ERROR, FRAME> Erc20MainnetHandler<CTX, ERROR, FRAME> {
24 pub const fn new() -> Self {
26 Self {
27 _phantom: core::marker::PhantomData,
28 }
29 }
30}
31
32impl<EVM, ERROR, FRAME> Default for Erc20MainnetHandler<EVM, ERROR, FRAME> {
33 fn default() -> Self {
34 Self::new()
35 }
36}
37
38impl<EVM, ERROR, FRAME> Handler for Erc20MainnetHandler<EVM, ERROR, FRAME>
39where
40 EVM: EvmTr<Context: ContextTr<Journal: JournalTr<State = EvmState>>, Frame = FRAME>,
41 FRAME: FrameTr<FrameResult = FrameResult, FrameInit = FrameInit>,
42 ERROR: EvmTrError<EVM>,
43{
44 type Evm = EVM;
45 type Error = ERROR;
46 type HaltReason = HaltReason;
47
48 fn validate_against_state_and_deduct_caller(
49 &self,
50 evm: &mut Self::Evm,
51 _init_and_floor_gas: &mut InitialAndFloorGas,
52 ) -> Result<(), ERROR> {
53 let (block, tx, cfg, journal, _, _) = evm.ctx_mut().all_mut();
54
55 journal.load_account_mut(TOKEN)?.touch();
57
58 let mut caller_account = journal.load_account_with_code_mut(tx.caller())?;
60
61 validate_account_nonce_and_code_with_components(&caller_account.account().info, tx, cfg)?;
62
63 caller_account.touch();
65 if tx.kind().is_call() {
66 caller_account.bump_nonce();
67 }
68
69 let account_balance_slot = erc_address_storage(tx.caller());
70
71 drop(caller_account); let account_balance = journal.sload(TOKEN, account_balance_slot)?.data;
75
76 let new_balance = calculate_caller_fee(account_balance, tx, block, cfg)?;
77
78 journal.sstore(TOKEN, account_balance_slot, new_balance)?;
80
81 Ok(())
82 }
83
84 fn reimburse_caller(
85 &self,
86 evm: &mut Self::Evm,
87 exec_result: &mut <<Self::Evm as EvmTr>::Frame as FrameTr>::FrameResult,
88 ) -> Result<(), Self::Error> {
89 let context = evm.ctx();
90 let basefee = context.block().basefee() as u128;
91 let caller = context.tx().caller();
92 let effective_gas_price = context.tx().effective_gas_price(basefee);
93 let gas = exec_result.gas();
94
95 let reimbursement =
96 effective_gas_price.saturating_mul((gas.remaining() + gas.refunded() as u64) as u128);
97
98 let account_balance_slot = erc_address_storage(caller);
99
100 let account_balance = context
102 .journal_mut()
103 .sload(TOKEN, account_balance_slot)?
104 .data;
105
106 context.journal_mut().sstore(
108 TOKEN,
109 account_balance_slot,
110 account_balance + U256::from(reimbursement),
111 )?;
112
113 Ok(())
114 }
115
116 fn reward_beneficiary(
117 &self,
118 evm: &mut Self::Evm,
119 exec_result: &mut <<Self::Evm as EvmTr>::Frame as FrameTr>::FrameResult,
120 ) -> Result<(), Self::Error> {
121 let context = evm.ctx();
122 let tx = context.tx();
123 let beneficiary = context.block().beneficiary();
124 let basefee = context.block().basefee() as u128;
125 let effective_gas_price = tx.effective_gas_price(basefee);
126 let gas = exec_result.gas();
127
128 let coinbase_gas_price = if context.cfg().spec().into().is_enabled_in(SpecId::LONDON) {
129 effective_gas_price.saturating_sub(basefee)
130 } else {
131 effective_gas_price
132 };
133
134 let reward = coinbase_gas_price.saturating_mul(gas.used() as u128);
135
136 let beneficiary_slot = erc_address_storage(beneficiary);
137 let journal = context.journal_mut();
139 let beneficiary_balance = journal.sload(TOKEN, beneficiary_slot)?.data;
140 journal.sstore(
142 TOKEN,
143 beneficiary_slot,
144 beneficiary_balance + U256::from(reward),
145 )?;
146
147 Ok(())
148 }
149}