mod alloy_types;
pub mod eip2930;
pub mod eip7702;
pub mod transaction_type;
pub use alloy_types::{
AccessList, AccessListItem, Authorization, RecoveredAuthority, RecoveredAuthorization,
SignedAuthorization,
};
pub use eip2930::AccessListItemTr;
pub use eip7702::AuthorizationTr;
pub use transaction_type::TransactionType;
use crate::result::InvalidTransaction;
use auto_impl::auto_impl;
use core::cmp::min;
use core::fmt::Debug;
use primitives::{eip4844::GAS_PER_BLOB, Address, Bytes, TxKind, B256, U256};
pub trait TransactionError: Debug + core::error::Error {}
#[auto_impl(&, Box, Arc, Rc)]
pub trait Transaction {
type AccessListItem<'a>: AccessListItemTr
where
Self: 'a;
type Authorization<'a>: AuthorizationTr
where
Self: 'a;
fn tx_type(&self) -> u8;
fn caller(&self) -> Address;
fn gas_limit(&self) -> u64;
fn value(&self) -> U256;
fn input(&self) -> &Bytes;
fn nonce(&self) -> u64;
fn kind(&self) -> TxKind;
fn chain_id(&self) -> Option<u64>;
fn gas_price(&self) -> u128;
fn access_list(&self) -> Option<impl Iterator<Item = Self::AccessListItem<'_>>>;
fn blob_versioned_hashes(&self) -> &[B256];
fn max_fee_per_blob_gas(&self) -> u128;
fn total_blob_gas(&self) -> u64 {
GAS_PER_BLOB * self.blob_versioned_hashes().len() as u64
}
fn calc_max_data_fee(&self) -> U256 {
U256::from((self.total_blob_gas() as u128).saturating_mul(self.max_fee_per_blob_gas()))
}
fn authorization_list_len(&self) -> usize;
fn authorization_list(&self) -> impl Iterator<Item = Self::Authorization<'_>>;
fn max_fee_per_gas(&self) -> u128 {
self.gas_price()
}
fn max_priority_fee_per_gas(&self) -> Option<u128>;
fn effective_gas_price(&self, base_fee: u128) -> u128 {
if self.tx_type() == TransactionType::Legacy as u8
|| self.tx_type() == TransactionType::Eip2930 as u8
{
return self.gas_price();
}
let max_price = self.gas_price();
let Some(max_priority_fee) = self.max_priority_fee_per_gas() else {
return max_price;
};
min(max_price, base_fee.saturating_add(max_priority_fee))
}
fn max_balance_spending(&self) -> Result<U256, InvalidTransaction> {
let mut max_balance_spending = (self.gas_limit() as u128)
.checked_mul(self.max_fee_per_gas())
.and_then(|gas_cost| U256::from(gas_cost).checked_add(self.value()))
.ok_or(InvalidTransaction::OverflowPaymentInTransaction)?;
if self.tx_type() == TransactionType::Eip4844 {
let data_fee = self.calc_max_data_fee();
max_balance_spending = max_balance_spending
.checked_add(data_fee)
.ok_or(InvalidTransaction::OverflowPaymentInTransaction)?;
}
Ok(max_balance_spending)
}
fn effective_balance_spending(
&self,
base_fee: u128,
blob_price: u128,
) -> Result<U256, InvalidTransaction> {
let mut effective_balance_spending = (self.gas_limit() as u128)
.checked_mul(self.effective_gas_price(base_fee))
.and_then(|gas_cost| U256::from(gas_cost).checked_add(self.value()))
.ok_or(InvalidTransaction::OverflowPaymentInTransaction)?;
if self.tx_type() == TransactionType::Eip4844 {
let blob_gas = self.total_blob_gas() as u128;
effective_balance_spending = effective_balance_spending
.checked_add(U256::from(blob_price.saturating_mul(blob_gas)))
.ok_or(InvalidTransaction::OverflowPaymentInTransaction)?;
}
Ok(effective_balance_spending)
}
}