reth_optimism_rpc/eth/
receipt.rs

1//! Loads and formats OP receipt RPC response.
2
3use alloy_consensus::transaction::TransactionMeta;
4use alloy_eips::eip2718::Encodable2718;
5use alloy_rpc_types_eth::{Log, TransactionReceipt};
6use op_alloy_consensus::{OpDepositReceipt, OpDepositReceiptWithBloom, OpReceiptEnvelope};
7use op_alloy_rpc_types::{L1BlockInfo, OpTransactionReceipt, OpTransactionReceiptFields};
8use reth_chainspec::ChainSpecProvider;
9use reth_node_api::{FullNodeComponents, NodeTypes};
10use reth_optimism_chainspec::OpChainSpec;
11use reth_optimism_evm::RethL1BlockInfo;
12use reth_optimism_forks::OpHardforks;
13use reth_optimism_primitives::{OpReceipt, OpTransactionSigned};
14use reth_rpc_eth_api::{helpers::LoadReceipt, FromEthApiError, RpcReceipt};
15use reth_rpc_eth_types::{receipt::build_receipt, EthApiError};
16use reth_storage_api::{ReceiptProvider, TransactionsProvider};
17
18use crate::{OpEthApi, OpEthApiError};
19
20impl<N> LoadReceipt for OpEthApi<N>
21where
22    Self: Send + Sync,
23    N: FullNodeComponents<Types: NodeTypes<ChainSpec = OpChainSpec>>,
24    Self::Provider: TransactionsProvider<Transaction = OpTransactionSigned>
25        + ReceiptProvider<Receipt = OpReceipt>,
26{
27    async fn build_transaction_receipt(
28        &self,
29        tx: OpTransactionSigned,
30        meta: TransactionMeta,
31        receipt: OpReceipt,
32    ) -> Result<RpcReceipt<Self::NetworkTypes>, Self::Error> {
33        let (block, receipts) = self
34            .inner
35            .eth_api
36            .cache()
37            .get_block_and_receipts(meta.block_hash)
38            .await
39            .map_err(Self::Error::from_eth_err)?
40            .ok_or(Self::Error::from_eth_err(EthApiError::HeaderNotFound(
41                meta.block_hash.into(),
42            )))?;
43
44        let mut l1_block_info =
45            reth_optimism_evm::extract_l1_info(block.body()).map_err(OpEthApiError::from)?;
46
47        Ok(OpReceiptBuilder::new(
48            &self.inner.eth_api.provider().chain_spec(),
49            &tx,
50            meta,
51            &receipt,
52            &receipts,
53            &mut l1_block_info,
54        )?
55        .build())
56    }
57}
58
59/// L1 fee and data gas for a non-deposit transaction, or deposit nonce and receipt version for a
60/// deposit transaction.
61#[derive(Debug, Clone)]
62pub struct OpReceiptFieldsBuilder {
63    /// Block number.
64    pub block_number: u64,
65    /// Block timestamp.
66    pub block_timestamp: u64,
67    /// The L1 fee for transaction.
68    pub l1_fee: Option<u128>,
69    /// L1 gas used by transaction.
70    pub l1_data_gas: Option<u128>,
71    /// L1 fee scalar.
72    pub l1_fee_scalar: Option<f64>,
73    /* ---------------------------------------- Bedrock ---------------------------------------- */
74    /// The base fee of the L1 origin block.
75    pub l1_base_fee: Option<u128>,
76    /* --------------------------------------- Regolith ---------------------------------------- */
77    /// Deposit nonce, if this is a deposit transaction.
78    pub deposit_nonce: Option<u64>,
79    /* ---------------------------------------- Canyon ----------------------------------------- */
80    /// Deposit receipt version, if this is a deposit transaction.
81    pub deposit_receipt_version: Option<u64>,
82    /* ---------------------------------------- Ecotone ---------------------------------------- */
83    /// The current L1 fee scalar.
84    pub l1_base_fee_scalar: Option<u128>,
85    /// The current L1 blob base fee.
86    pub l1_blob_base_fee: Option<u128>,
87    /// The current L1 blob base fee scalar.
88    pub l1_blob_base_fee_scalar: Option<u128>,
89    /// The current operator fee scalar.
90    pub operator_fee_scalar: Option<u128>,
91    /// The current L1 blob base fee scalar.
92    pub operator_fee_constant: Option<u128>,
93}
94
95impl OpReceiptFieldsBuilder {
96    /// Returns a new builder.
97    pub const fn new(block_timestamp: u64, block_number: u64) -> Self {
98        Self {
99            block_number,
100            block_timestamp,
101            l1_fee: None,
102            l1_data_gas: None,
103            l1_fee_scalar: None,
104            l1_base_fee: None,
105            deposit_nonce: None,
106            deposit_receipt_version: None,
107            l1_base_fee_scalar: None,
108            l1_blob_base_fee: None,
109            l1_blob_base_fee_scalar: None,
110            operator_fee_scalar: None,
111            operator_fee_constant: None,
112        }
113    }
114
115    /// Applies [`L1BlockInfo`](op_revm::L1BlockInfo).
116    pub fn l1_block_info(
117        mut self,
118        chain_spec: &OpChainSpec,
119        tx: &OpTransactionSigned,
120        l1_block_info: &mut op_revm::L1BlockInfo,
121    ) -> Result<Self, OpEthApiError> {
122        let raw_tx = tx.encoded_2718();
123        let timestamp = self.block_timestamp;
124
125        self.l1_fee = Some(
126            l1_block_info
127                .l1_tx_data_fee(chain_spec, timestamp, &raw_tx, tx.is_deposit())
128                .map_err(|_| OpEthApiError::L1BlockFeeError)?
129                .saturating_to(),
130        );
131
132        self.l1_data_gas = Some(
133            l1_block_info
134                .l1_data_gas(chain_spec, timestamp, &raw_tx)
135                .map_err(|_| OpEthApiError::L1BlockGasError)?
136                .saturating_add(l1_block_info.l1_fee_overhead.unwrap_or_default())
137                .saturating_to(),
138        );
139
140        self.l1_fee_scalar = (!chain_spec.is_ecotone_active_at_timestamp(timestamp))
141            .then_some(f64::from(l1_block_info.l1_base_fee_scalar) / 1_000_000.0);
142
143        self.l1_base_fee = Some(l1_block_info.l1_base_fee.saturating_to());
144        self.l1_base_fee_scalar = Some(l1_block_info.l1_base_fee_scalar.saturating_to());
145        self.l1_blob_base_fee = l1_block_info.l1_blob_base_fee.map(|fee| fee.saturating_to());
146        self.l1_blob_base_fee_scalar =
147            l1_block_info.l1_blob_base_fee_scalar.map(|scalar| scalar.saturating_to());
148
149        // If the operator fee params are both set to 0, we don't add them to the receipt.
150        let operator_fee_scalar_has_non_zero_value: bool =
151            l1_block_info.operator_fee_scalar.is_some_and(|scalar| !scalar.is_zero());
152
153        let operator_fee_constant_has_non_zero_value =
154            l1_block_info.operator_fee_constant.is_some_and(|constant| !constant.is_zero());
155
156        if operator_fee_scalar_has_non_zero_value || operator_fee_constant_has_non_zero_value {
157            self.operator_fee_scalar =
158                l1_block_info.operator_fee_scalar.map(|scalar| scalar.saturating_to());
159            self.operator_fee_constant =
160                l1_block_info.operator_fee_constant.map(|constant| constant.saturating_to());
161        }
162
163        Ok(self)
164    }
165
166    /// Applies deposit transaction metadata: deposit nonce.
167    pub const fn deposit_nonce(mut self, nonce: Option<u64>) -> Self {
168        self.deposit_nonce = nonce;
169        self
170    }
171
172    /// Applies deposit transaction metadata: deposit receipt version.
173    pub const fn deposit_version(mut self, version: Option<u64>) -> Self {
174        self.deposit_receipt_version = version;
175        self
176    }
177
178    /// Builds the [`OpTransactionReceiptFields`] object.
179    pub const fn build(self) -> OpTransactionReceiptFields {
180        let Self {
181            block_number: _,    // used to compute other fields
182            block_timestamp: _, // used to compute other fields
183            l1_fee,
184            l1_data_gas: l1_gas_used,
185            l1_fee_scalar,
186            l1_base_fee: l1_gas_price,
187            deposit_nonce,
188            deposit_receipt_version,
189            l1_base_fee_scalar,
190            l1_blob_base_fee,
191            l1_blob_base_fee_scalar,
192            operator_fee_scalar,
193            operator_fee_constant,
194        } = self;
195
196        OpTransactionReceiptFields {
197            l1_block_info: L1BlockInfo {
198                l1_gas_price,
199                l1_gas_used,
200                l1_fee,
201                l1_fee_scalar,
202                l1_base_fee_scalar,
203                l1_blob_base_fee,
204                l1_blob_base_fee_scalar,
205                operator_fee_scalar,
206                operator_fee_constant,
207            },
208            deposit_nonce,
209            deposit_receipt_version,
210        }
211    }
212}
213
214/// Builds an [`OpTransactionReceipt`].
215#[derive(Debug)]
216pub struct OpReceiptBuilder {
217    /// Core receipt, has all the fields of an L1 receipt and is the basis for the OP receipt.
218    pub core_receipt: TransactionReceipt<OpReceiptEnvelope<Log>>,
219    /// Additional OP receipt fields.
220    pub op_receipt_fields: OpTransactionReceiptFields,
221}
222
223impl OpReceiptBuilder {
224    /// Returns a new builder.
225    pub fn new(
226        chain_spec: &OpChainSpec,
227        transaction: &OpTransactionSigned,
228        meta: TransactionMeta,
229        receipt: &OpReceipt,
230        all_receipts: &[OpReceipt],
231        l1_block_info: &mut op_revm::L1BlockInfo,
232    ) -> Result<Self, OpEthApiError> {
233        let timestamp = meta.timestamp;
234        let block_number = meta.block_number;
235        let core_receipt =
236            build_receipt(transaction, meta, receipt, all_receipts, None, |receipt_with_bloom| {
237                match receipt {
238                    OpReceipt::Legacy(_) => OpReceiptEnvelope::<Log>::Legacy(receipt_with_bloom),
239                    OpReceipt::Eip2930(_) => OpReceiptEnvelope::<Log>::Eip2930(receipt_with_bloom),
240                    OpReceipt::Eip1559(_) => OpReceiptEnvelope::<Log>::Eip1559(receipt_with_bloom),
241                    OpReceipt::Eip7702(_) => OpReceiptEnvelope::<Log>::Eip7702(receipt_with_bloom),
242                    OpReceipt::Deposit(receipt) => {
243                        OpReceiptEnvelope::<Log>::Deposit(OpDepositReceiptWithBloom::<Log> {
244                            receipt: OpDepositReceipt::<Log> {
245                                inner: receipt_with_bloom.receipt,
246                                deposit_nonce: receipt.deposit_nonce,
247                                deposit_receipt_version: receipt.deposit_receipt_version,
248                            },
249                            logs_bloom: receipt_with_bloom.logs_bloom,
250                        })
251                    }
252                }
253            })?;
254
255        let op_receipt_fields = OpReceiptFieldsBuilder::new(timestamp, block_number)
256            .l1_block_info(chain_spec, transaction, l1_block_info)?
257            .build();
258
259        Ok(Self { core_receipt, op_receipt_fields })
260    }
261
262    /// Builds [`OpTransactionReceipt`] by combing core (l1) receipt fields and additional OP
263    /// receipt fields.
264    pub fn build(self) -> OpTransactionReceipt {
265        let Self { core_receipt: inner, op_receipt_fields } = self;
266
267        let OpTransactionReceiptFields { l1_block_info, .. } = op_receipt_fields;
268
269        OpTransactionReceipt { inner, l1_block_info }
270    }
271}
272
273#[cfg(test)]
274mod test {
275    use super::*;
276    use alloy_consensus::{Block, BlockBody};
277    use alloy_primitives::{hex, U256};
278    use op_alloy_network::eip2718::Decodable2718;
279    use reth_optimism_chainspec::{BASE_MAINNET, OP_MAINNET};
280
281    /// OP Mainnet transaction at index 0 in block 124665056.
282    ///
283    /// <https://optimistic.etherscan.io/tx/0x312e290cf36df704a2217b015d6455396830b0ce678b860ebfcc30f41403d7b1>
284    const TX_SET_L1_BLOCK_OP_MAINNET_BLOCK_124665056: [u8; 251] = hex!(
285        "7ef8f8a0683079df94aa5b9cf86687d739a60a9b4f0835e520ec4d664e2e415dca17a6df94deaddeaddeaddeaddeaddeaddeaddeaddead00019442000000000000000000000000000000000000158080830f424080b8a4440a5e200000146b000f79c500000000000000040000000066d052e700000000013ad8a3000000000000000000000000000000000000000000000000000000003ef1278700000000000000000000000000000000000000000000000000000000000000012fdf87b89884a61e74b322bbcf60386f543bfae7827725efaaf0ab1de2294a590000000000000000000000006887246668a3b87f54deb3b94ba47a6f63f32985"
286    );
287
288    /// OP Mainnet transaction at index 1 in block 124665056.
289    ///
290    /// <https://optimistic.etherscan.io/tx/0x1059e8004daff32caa1f1b1ef97fe3a07a8cf40508f5b835b66d9420d87c4a4a>
291    const TX_1_OP_MAINNET_BLOCK_124665056: [u8; 1176] = hex!(
292        "02f904940a8303fba78401d6d2798401db2b6d830493e0943e6f4f7866654c18f536170780344aa8772950b680b904246a761202000000000000000000000000087000a300de7200382b55d40045000000e5d60e0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000014000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003a0000000000000000000000000000000000000000000000000000000000000022482ad56cb0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000120000000000000000000000000dc6ff44d5d932cbd77b52e5612ba0529dc6226f1000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000044095ea7b300000000000000000000000021c4928109acb0659a88ae5329b5374a3024694c0000000000000000000000000000000000000000000000049b9ca9a6943400000000000000000000000000000000000000000000000000000000000000000000000000000000000021c4928109acb0659a88ae5329b5374a3024694c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000024b6b55f250000000000000000000000000000000000000000000000049b9ca9a694340000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000415ec214a3950bea839a7e6fbb0ba1540ac2076acd50820e2d5ef83d0902cdffb24a47aff7de5190290769c4f0a9c6fabf63012986a0d590b1b571547a8c7050ea1b00000000000000000000000000000000000000000000000000000000000000c080a06db770e6e25a617fe9652f0958bd9bd6e49281a53036906386ed39ec48eadf63a07f47cf51a4a40b4494cf26efc686709a9b03939e20ee27e59682f5faa536667e"
293    );
294
295    /// Timestamp of OP mainnet block 124665056.
296    ///
297    /// <https://optimistic.etherscan.io/block/124665056>
298    const BLOCK_124665056_TIMESTAMP: u64 = 1724928889;
299
300    /// L1 block info for transaction at index 1 in block 124665056.
301    ///
302    /// <https://optimistic.etherscan.io/tx/0x1059e8004daff32caa1f1b1ef97fe3a07a8cf40508f5b835b66d9420d87c4a4a>
303    const TX_META_TX_1_OP_MAINNET_BLOCK_124665056: OpTransactionReceiptFields =
304        OpTransactionReceiptFields {
305            l1_block_info: L1BlockInfo {
306                l1_gas_price: Some(1055991687), // since bedrock l1 base fee
307                l1_gas_used: Some(4471),
308                l1_fee: Some(24681034813),
309                l1_fee_scalar: None,
310                l1_base_fee_scalar: Some(5227),
311                l1_blob_base_fee: Some(1),
312                l1_blob_base_fee_scalar: Some(1014213),
313                operator_fee_scalar: None,
314                operator_fee_constant: None,
315            },
316            deposit_nonce: None,
317            deposit_receipt_version: None,
318        };
319
320    #[test]
321    fn op_receipt_fields_from_block_and_tx() {
322        // rig
323        let tx_0 = OpTransactionSigned::decode_2718(
324            &mut TX_SET_L1_BLOCK_OP_MAINNET_BLOCK_124665056.as_slice(),
325        )
326        .unwrap();
327
328        let tx_1 =
329            OpTransactionSigned::decode_2718(&mut TX_1_OP_MAINNET_BLOCK_124665056.as_slice())
330                .unwrap();
331
332        let block: Block<OpTransactionSigned> = Block {
333            body: BlockBody { transactions: [tx_0, tx_1.clone()].to_vec(), ..Default::default() },
334            ..Default::default()
335        };
336
337        let mut l1_block_info =
338            reth_optimism_evm::extract_l1_info(&block.body).expect("should extract l1 info");
339
340        // test
341        assert!(OP_MAINNET.is_fjord_active_at_timestamp(BLOCK_124665056_TIMESTAMP));
342
343        let receipt_meta = OpReceiptFieldsBuilder::new(BLOCK_124665056_TIMESTAMP, 124665056)
344            .l1_block_info(&OP_MAINNET, &tx_1, &mut l1_block_info)
345            .expect("should parse revm l1 info")
346            .build();
347
348        let L1BlockInfo {
349            l1_gas_price,
350            l1_gas_used,
351            l1_fee,
352            l1_fee_scalar,
353            l1_base_fee_scalar,
354            l1_blob_base_fee,
355            l1_blob_base_fee_scalar,
356            operator_fee_scalar,
357            operator_fee_constant,
358        } = receipt_meta.l1_block_info;
359
360        assert_eq!(
361            l1_gas_price, TX_META_TX_1_OP_MAINNET_BLOCK_124665056.l1_block_info.l1_gas_price,
362            "incorrect l1 base fee (former gas price)"
363        );
364        assert_eq!(
365            l1_gas_used, TX_META_TX_1_OP_MAINNET_BLOCK_124665056.l1_block_info.l1_gas_used,
366            "incorrect l1 gas used"
367        );
368        assert_eq!(
369            l1_fee, TX_META_TX_1_OP_MAINNET_BLOCK_124665056.l1_block_info.l1_fee,
370            "incorrect l1 fee"
371        );
372        assert_eq!(
373            l1_fee_scalar, TX_META_TX_1_OP_MAINNET_BLOCK_124665056.l1_block_info.l1_fee_scalar,
374            "incorrect l1 fee scalar"
375        );
376        assert_eq!(
377            l1_base_fee_scalar,
378            TX_META_TX_1_OP_MAINNET_BLOCK_124665056.l1_block_info.l1_base_fee_scalar,
379            "incorrect l1 base fee scalar"
380        );
381        assert_eq!(
382            l1_blob_base_fee,
383            TX_META_TX_1_OP_MAINNET_BLOCK_124665056.l1_block_info.l1_blob_base_fee,
384            "incorrect l1 blob base fee"
385        );
386        assert_eq!(
387            l1_blob_base_fee_scalar,
388            TX_META_TX_1_OP_MAINNET_BLOCK_124665056.l1_block_info.l1_blob_base_fee_scalar,
389            "incorrect l1 blob base fee scalar"
390        );
391        assert_eq!(
392            operator_fee_scalar,
393            TX_META_TX_1_OP_MAINNET_BLOCK_124665056.l1_block_info.operator_fee_scalar,
394            "incorrect operator fee scalar"
395        );
396        assert_eq!(
397            operator_fee_constant,
398            TX_META_TX_1_OP_MAINNET_BLOCK_124665056.l1_block_info.operator_fee_constant,
399            "incorrect operator fee constant"
400        );
401    }
402
403    #[test]
404    fn op_non_zero_operator_fee_params_included_in_receipt() {
405        let tx_1 =
406            OpTransactionSigned::decode_2718(&mut TX_1_OP_MAINNET_BLOCK_124665056.as_slice())
407                .unwrap();
408
409        let mut l1_block_info = op_revm::L1BlockInfo::default();
410
411        l1_block_info.operator_fee_scalar = Some(U256::ZERO);
412        l1_block_info.operator_fee_constant = Some(U256::from(2));
413
414        let receipt_meta = OpReceiptFieldsBuilder::new(BLOCK_124665056_TIMESTAMP, 124665056)
415            .l1_block_info(&OP_MAINNET, &tx_1, &mut l1_block_info)
416            .expect("should parse revm l1 info")
417            .build();
418
419        let L1BlockInfo { operator_fee_scalar, operator_fee_constant, .. } =
420            receipt_meta.l1_block_info;
421
422        assert_eq!(operator_fee_scalar, Some(0), "incorrect operator fee scalar");
423        assert_eq!(operator_fee_constant, Some(2), "incorrect operator fee constant");
424    }
425
426    #[test]
427    fn op_zero_operator_fee_params_not_included_in_receipt() {
428        let tx_1 =
429            OpTransactionSigned::decode_2718(&mut TX_1_OP_MAINNET_BLOCK_124665056.as_slice())
430                .unwrap();
431
432        let mut l1_block_info = op_revm::L1BlockInfo::default();
433
434        l1_block_info.operator_fee_scalar = Some(U256::ZERO);
435        l1_block_info.operator_fee_constant = Some(U256::ZERO);
436
437        let receipt_meta = OpReceiptFieldsBuilder::new(BLOCK_124665056_TIMESTAMP, 124665056)
438            .l1_block_info(&OP_MAINNET, &tx_1, &mut l1_block_info)
439            .expect("should parse revm l1 info")
440            .build();
441
442        let L1BlockInfo { operator_fee_scalar, operator_fee_constant, .. } =
443            receipt_meta.l1_block_info;
444
445        assert_eq!(operator_fee_scalar, None, "incorrect operator fee scalar");
446        assert_eq!(operator_fee_constant, None, "incorrect operator fee constant");
447    }
448
449    // <https://github.com/paradigmxyz/reth/issues/12177>
450    #[test]
451    fn base_receipt_gas_fields() {
452        // https://basescan.org/tx/0x510fd4c47d78ba9f97c91b0f2ace954d5384c169c9545a77a373cf3ef8254e6e
453        let system = hex!(
454            "7ef8f8a0389e292420bcbf9330741f72074e39562a09ff5a00fd22e4e9eee7e34b81bca494deaddeaddeaddeaddeaddeaddeaddeaddead00019442000000000000000000000000000000000000158080830f424080b8a4440a5e20000008dd00101c120000000000000004000000006721035b00000000014189960000000000000000000000000000000000000000000000000000000349b4dcdc000000000000000000000000000000000000000000000000000000004ef9325cc5991ce750960f636ca2ffbb6e209bb3ba91412f21dd78c14ff154d1930f1f9a0000000000000000000000005050f69a9786f081509234f1a7f4684b5e5b76c9"
455        );
456        let tx_0 = OpTransactionSigned::decode_2718(&mut &system[..]).unwrap();
457
458        let block: alloy_consensus::Block<OpTransactionSigned> = Block {
459            body: BlockBody { transactions: vec![tx_0], ..Default::default() },
460            ..Default::default()
461        };
462        let mut l1_block_info =
463            reth_optimism_evm::extract_l1_info(&block.body).expect("should extract l1 info");
464
465        // https://basescan.org/tx/0xf9420cbaf66a2dda75a015488d37262cbfd4abd0aad7bb2be8a63e14b1fa7a94
466        let tx = hex!(
467            "02f86c8221058034839a4ae283021528942f16386bb37709016023232523ff6d9daf444be380841249c58bc080a001b927eda2af9b00b52a57be0885e0303c39dd2831732e14051c2336470fd468a0681bf120baf562915841a48601c2b54a6742511e535cf8f71c95115af7ff63bd"
468        );
469        let tx_1 = OpTransactionSigned::decode_2718(&mut &tx[..]).unwrap();
470
471        let receipt_meta = OpReceiptFieldsBuilder::new(1730216981, 21713817)
472            .l1_block_info(&BASE_MAINNET, &tx_1, &mut l1_block_info)
473            .expect("should parse revm l1 info")
474            .build();
475
476        let L1BlockInfo {
477            l1_gas_price,
478            l1_gas_used,
479            l1_fee,
480            l1_fee_scalar,
481            l1_base_fee_scalar,
482            l1_blob_base_fee,
483            l1_blob_base_fee_scalar,
484            operator_fee_scalar,
485            operator_fee_constant,
486        } = receipt_meta.l1_block_info;
487
488        assert_eq!(l1_gas_price, Some(14121491676), "incorrect l1 base fee (former gas price)");
489        assert_eq!(l1_gas_used, Some(1600), "incorrect l1 gas used");
490        assert_eq!(l1_fee, Some(191150293412), "incorrect l1 fee");
491        assert!(l1_fee_scalar.is_none(), "incorrect l1 fee scalar");
492        assert_eq!(l1_base_fee_scalar, Some(2269), "incorrect l1 base fee scalar");
493        assert_eq!(l1_blob_base_fee, Some(1324954204), "incorrect l1 blob base fee");
494        assert_eq!(l1_blob_base_fee_scalar, Some(1055762), "incorrect l1 blob base fee scalar");
495        assert_eq!(operator_fee_scalar, None, "incorrect operator fee scalar");
496        assert_eq!(operator_fee_constant, None, "incorrect operator fee constant");
497    }
498}