1use alloy_primitives::{Address, U256};
2
3use arb_primitives::multigas::MultiGas;
4use arbos::{
5 tx_processor::{
6 EndTxFeeDistribution, EndTxNormalParams, GasChargingError, GasChargingParams, TxProcessor,
7 },
8 util::tx_type_has_poster_costs,
9};
10
11use crate::hooks::{
12 ArbOsHooks, EndTxContext, GasChargingContext, GasChargingResult, StartTxContext,
13};
14
15#[derive(Debug)]
20pub struct DefaultArbOsHooks {
21 pub tx_proc: TxProcessor,
23 pub arbos_version: u64,
25 pub network_fee_account: Address,
27 pub infra_fee_account: Address,
29 pub min_base_fee: U256,
31 pub per_block_gas_limit: u64,
33 pub per_tx_gas_limit: u64,
35 pub coinbase: Address,
37 pub is_eth_call: bool,
39 pub l1_base_fee: U256,
41 pub calldata_pricing_increase_enabled: bool,
43}
44
45impl DefaultArbOsHooks {
46 pub fn new(
47 coinbase: Address,
48 arbos_version: u64,
49 network_fee_account: Address,
50 infra_fee_account: Address,
51 min_base_fee: U256,
52 per_block_gas_limit: u64,
53 per_tx_gas_limit: u64,
54 is_eth_call: bool,
55 l1_base_fee: U256,
56 calldata_pricing_increase_enabled: bool,
57 ) -> Self {
58 Self {
59 tx_proc: TxProcessor::new(coinbase),
60 arbos_version,
61 network_fee_account,
62 infra_fee_account,
63 min_base_fee,
64 per_block_gas_limit,
65 per_tx_gas_limit,
66 coinbase,
67 is_eth_call,
68 l1_base_fee,
69 calldata_pricing_increase_enabled,
70 }
71 }
72
73 pub fn compute_end_tx_fees(&self, ctx: &EndTxContext) -> EndTxFeeDistribution {
75 self.tx_proc
76 .compute_end_tx_fee_distribution(&EndTxNormalParams {
77 gas_used: ctx.gas_used,
78 gas_price: ctx.gas_price,
79 base_fee: ctx.base_fee,
80 coinbase: self.coinbase,
81 network_fee_account: self.network_fee_account,
82 infra_fee_account: self.infra_fee_account,
83 min_base_fee: self.min_base_fee,
84 arbos_version: self.arbos_version,
85 })
86 }
87}
88
89#[derive(Debug, thiserror::Error)]
91pub enum ArbHookError {
92 #[error("gas charging: {0}")]
93 GasCharging(#[from] GasChargingError),
94 #[error("state access: {0}")]
95 StateAccess(String),
96}
97
98impl ArbOsHooks for DefaultArbOsHooks {
99 type Error = ArbHookError;
100
101 fn start_tx(&mut self, ctx: &StartTxContext) -> Result<(), Self::Error> {
102 self.tx_proc.set_tx_type(ctx.tx_type as u8);
103 Ok(())
104 }
105
106 fn gas_charging(&mut self, ctx: &GasChargingContext) -> Result<GasChargingResult, Self::Error> {
107 let mut gas_remaining = ctx.gas_limit.saturating_sub(ctx.intrinsic_gas);
108
109 let skip_l1_charging = !tx_type_has_poster_costs(ctx.tx_type.as_u8());
110
111 let poster_cost = if skip_l1_charging {
113 U256::ZERO
114 } else {
115 ctx.poster_cost
116 };
117
118 let params = GasChargingParams {
119 base_fee: ctx.base_fee,
120 poster_cost,
121 is_gas_estimation: self.is_eth_call,
122 is_eth_call: self.is_eth_call,
123 skip_l1_charging,
124 min_base_fee: self.min_base_fee,
125 per_block_gas_limit: self.per_block_gas_limit,
126 per_tx_gas_limit: self.per_tx_gas_limit,
127 arbos_version: self.arbos_version,
128 };
129
130 self.tx_proc
131 .gas_charging_hook(&mut gas_remaining, ctx.intrinsic_gas, ¶ms)?;
132
133 let multi_gas = MultiGas::l1_calldata_gas(self.tx_proc.poster_gas);
135
136 Ok(GasChargingResult {
137 poster_cost: self.tx_proc.poster_fee,
138 poster_gas: self.tx_proc.poster_gas,
139 compute_hold_gas: self.tx_proc.compute_hold_gas,
140 calldata_units: ctx.calldata_units,
141 multi_gas,
142 })
143 }
144
145 fn end_tx(&mut self, _ctx: &EndTxContext) -> Result<(), Self::Error> {
146 Ok(())
149 }
150
151 fn nonrefundable_gas(&self) -> u64 {
152 self.tx_proc.nonrefundable_gas()
153 }
154
155 fn held_gas(&self) -> u64 {
156 self.tx_proc.held_gas()
157 }
158
159 fn scheduled_txs(&mut self) -> Vec<Vec<u8>> {
160 core::mem::take(&mut self.tx_proc.scheduled_txs)
161 }
162
163 fn drop_tip(&self) -> bool {
164 self.tx_proc.drop_tip(self.arbos_version)
165 }
166
167 fn gas_price_op(&self, gas_price: U256, base_fee: U256) -> U256 {
168 self.tx_proc
169 .gas_price_op(self.arbos_version, base_fee, gas_price)
170 }
171
172 fn msg_is_non_mutating(&self) -> bool {
173 self.is_eth_call
174 }
175
176 fn is_calldata_pricing_increase_enabled(&self) -> bool {
177 self.calldata_pricing_increase_enabled
178 }
179}