op_revm/transaction/
abstraction.rs

1use super::deposit::{DepositTransactionParts, DEPOSIT_TRANSACTION_TYPE};
2use auto_impl::auto_impl;
3use revm::{
4    context::TxEnv,
5    context_interface::transaction::Transaction,
6    primitives::{Address, Bytes, TxKind, B256, U256},
7};
8use std::vec;
9
10#[auto_impl(&, &mut, Box, Arc)]
11pub trait OpTxTr: Transaction {
12    fn enveloped_tx(&self) -> Option<&Bytes>;
13
14    /// Source hash of the deposit transaction
15    fn source_hash(&self) -> Option<B256>;
16
17    /// Mint of the deposit transaction
18    fn mint(&self) -> Option<u128>;
19
20    /// Whether the transaction is a system transaction
21    fn is_system_transaction(&self) -> bool;
22
23    /// Returns `true` if transaction is of type [`DEPOSIT_TRANSACTION_TYPE`].
24    fn is_deposit(&self) -> bool {
25        self.tx_type() == DEPOSIT_TRANSACTION_TYPE
26    }
27}
28
29#[derive(Clone, Debug, PartialEq, Eq)]
30#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
31pub struct OpTransaction<T: Transaction> {
32    pub base: T,
33    /// An enveloped EIP-2718 typed transaction
34    ///
35    /// This is used to compute the L1 tx cost using the L1 block info, as
36    /// opposed to requiring downstream apps to compute the cost
37    /// externally.
38    pub enveloped_tx: Option<Bytes>,
39    pub deposit: DepositTransactionParts,
40}
41
42impl<T: Transaction> OpTransaction<T> {
43    pub fn new(base: T) -> Self {
44        Self {
45            base,
46            enveloped_tx: None,
47            deposit: DepositTransactionParts::default(),
48        }
49    }
50}
51
52impl Default for OpTransaction<TxEnv> {
53    fn default() -> Self {
54        Self {
55            base: TxEnv::default(),
56            enveloped_tx: Some(vec![0x00].into()),
57            deposit: DepositTransactionParts::default(),
58        }
59    }
60}
61
62impl<T: Transaction> Transaction for OpTransaction<T> {
63    type AccessListItem = T::AccessListItem;
64    type Authorization = T::Authorization;
65
66    fn tx_type(&self) -> u8 {
67        self.base.tx_type()
68    }
69
70    fn caller(&self) -> Address {
71        self.base.caller()
72    }
73
74    fn gas_limit(&self) -> u64 {
75        self.base.gas_limit()
76    }
77
78    fn value(&self) -> U256 {
79        self.base.value()
80    }
81
82    fn input(&self) -> &Bytes {
83        self.base.input()
84    }
85
86    fn nonce(&self) -> u64 {
87        self.base.nonce()
88    }
89
90    fn kind(&self) -> TxKind {
91        self.base.kind()
92    }
93
94    fn chain_id(&self) -> Option<u64> {
95        self.base.chain_id()
96    }
97
98    fn access_list(&self) -> Option<impl Iterator<Item = &Self::AccessListItem>> {
99        self.base.access_list()
100    }
101
102    fn max_priority_fee_per_gas(&self) -> Option<u128> {
103        self.base.max_priority_fee_per_gas()
104    }
105
106    fn max_fee_per_gas(&self) -> u128 {
107        self.base.max_fee_per_gas()
108    }
109
110    fn gas_price(&self) -> u128 {
111        self.base.gas_price()
112    }
113
114    fn blob_versioned_hashes(&self) -> &[B256] {
115        self.base.blob_versioned_hashes()
116    }
117
118    fn max_fee_per_blob_gas(&self) -> u128 {
119        self.base.max_fee_per_blob_gas()
120    }
121
122    fn effective_gas_price(&self, base_fee: u128) -> u128 {
123        self.base.effective_gas_price(base_fee)
124    }
125
126    fn authorization_list_len(&self) -> usize {
127        self.base.authorization_list_len()
128    }
129
130    fn authorization_list(&self) -> impl Iterator<Item = &Self::Authorization> {
131        self.base.authorization_list()
132    }
133}
134
135impl<T: Transaction> OpTxTr for OpTransaction<T> {
136    fn enveloped_tx(&self) -> Option<&Bytes> {
137        self.enveloped_tx.as_ref()
138    }
139
140    fn source_hash(&self) -> Option<B256> {
141        if self.tx_type() != DEPOSIT_TRANSACTION_TYPE {
142            return None;
143        }
144        Some(self.deposit.source_hash)
145    }
146
147    fn mint(&self) -> Option<u128> {
148        self.deposit.mint
149    }
150
151    fn is_system_transaction(&self) -> bool {
152        self.deposit.is_system_transaction
153    }
154}
155
156#[cfg(test)]
157mod tests {
158    use crate::transaction::deposit::DEPOSIT_TRANSACTION_TYPE;
159
160    use super::*;
161    use revm::primitives::{Address, B256};
162
163    #[test]
164    fn test_deposit_transaction_fields() {
165        let op_tx = OpTransaction {
166            base: TxEnv {
167                tx_type: DEPOSIT_TRANSACTION_TYPE,
168                gas_limit: 10,
169                gas_price: 100,
170                gas_priority_fee: Some(5),
171                ..Default::default()
172            },
173            enveloped_tx: None,
174            deposit: DepositTransactionParts {
175                is_system_transaction: false,
176                mint: Some(0u128),
177                source_hash: B256::default(),
178            },
179        };
180        // Verify transaction type
181        assert_eq!(op_tx.tx_type(), DEPOSIT_TRANSACTION_TYPE);
182        // Verify common fields access
183        assert_eq!(op_tx.gas_limit(), 10);
184        assert_eq!(op_tx.kind(), revm::primitives::TxKind::Call(Address::ZERO));
185        // Verify gas related calculations
186        assert_eq!(op_tx.effective_gas_price(90), 95);
187        assert_eq!(op_tx.max_fee_per_gas(), 100);
188    }
189}