1use crate::TransactionType;
2use context_interface::transaction::{
3 AccessList, AccessListItem, SignedAuthorization, Transaction,
4};
5use core::fmt::Debug;
6use primitives::{Address, Bytes, TxKind, B256, U256};
7use std::vec::Vec;
8
9#[derive(Clone, Debug, PartialEq, Eq)]
11#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
12pub struct TxEnv {
13 pub tx_type: u8,
14 pub caller: Address,
16 pub gas_limit: u64,
18 pub gas_price: u128,
20 pub kind: TxKind,
22 pub value: U256,
24 pub data: Bytes,
26
27 pub nonce: u64,
29
30 pub chain_id: Option<u64>,
38
39 pub access_list: AccessList,
45
46 pub gas_priority_fee: Option<u128>,
52
53 pub blob_hashes: Vec<B256>,
61
62 pub max_fee_per_blob_gas: u128,
68
69 pub authorization_list: Vec<SignedAuthorization>,
78}
79
80impl Default for TxEnv {
81 fn default() -> Self {
82 Self {
83 tx_type: 0,
84 caller: Address::default(),
85 gas_limit: 30_000_000,
86 gas_price: 0,
87 kind: TxKind::Call(Address::default()),
88 value: U256::ZERO,
89 data: Bytes::default(),
90 nonce: 0,
91 chain_id: Some(1), access_list: Default::default(),
93 gas_priority_fee: Some(0),
94 blob_hashes: Vec::new(),
95 max_fee_per_blob_gas: 0,
96 authorization_list: Vec::new(),
97 }
98 }
99}
100
101#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)]
102#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
103pub enum DeriveTxTypeError {
104 MissingTargetForEip4844,
105 MissingTargetForEip7702,
106}
107
108impl TxEnv {
109 pub fn derive_tx_type(&mut self) -> Result<(), DeriveTxTypeError> {
112 let mut tx_type = TransactionType::Legacy;
113
114 if !self.access_list.0.is_empty() {
115 tx_type = TransactionType::Eip2930;
116 }
117
118 if self.gas_priority_fee.is_some() {
119 tx_type = TransactionType::Eip1559;
120 }
121
122 if !self.blob_hashes.is_empty() {
123 if let TxKind::Call(_) = self.kind {
124 tx_type = TransactionType::Eip4844;
125 } else {
126 return Err(DeriveTxTypeError::MissingTargetForEip4844);
127 }
128 }
129
130 if !self.authorization_list.is_empty() {
131 if let TxKind::Call(_) = self.kind {
132 tx_type = TransactionType::Eip7702;
133 } else {
134 return Err(DeriveTxTypeError::MissingTargetForEip7702);
135 }
136 }
137
138 self.tx_type = tx_type as u8;
139 Ok(())
140 }
141}
142
143impl Transaction for TxEnv {
144 type AccessListItem = AccessListItem;
145 type Authorization = SignedAuthorization;
146
147 fn tx_type(&self) -> u8 {
148 self.tx_type
149 }
150
151 fn kind(&self) -> TxKind {
152 self.kind
153 }
154
155 fn caller(&self) -> Address {
156 self.caller
157 }
158
159 fn gas_limit(&self) -> u64 {
160 self.gas_limit
161 }
162
163 fn gas_price(&self) -> u128 {
164 self.gas_price
165 }
166
167 fn value(&self) -> U256 {
168 self.value
169 }
170
171 fn nonce(&self) -> u64 {
172 self.nonce
173 }
174
175 fn chain_id(&self) -> Option<u64> {
176 self.chain_id
177 }
178
179 fn access_list(&self) -> Option<impl Iterator<Item = &Self::AccessListItem>> {
180 Some(self.access_list.0.iter())
181 }
182
183 fn max_fee_per_gas(&self) -> u128 {
184 self.gas_price
185 }
186
187 fn max_fee_per_blob_gas(&self) -> u128 {
188 self.max_fee_per_blob_gas
189 }
190
191 fn authorization_list_len(&self) -> usize {
192 self.authorization_list.len()
193 }
194
195 fn authorization_list(&self) -> impl Iterator<Item = &Self::Authorization> {
196 self.authorization_list.iter()
197 }
198
199 fn input(&self) -> &Bytes {
200 &self.data
201 }
202
203 fn blob_versioned_hashes(&self) -> &[B256] {
204 &self.blob_hashes
205 }
206
207 fn max_priority_fee_per_gas(&self) -> Option<u128> {
208 self.gas_priority_fee
209 }
210}