signet_sim/
item.rs

1use alloy::{
2    consensus::{Transaction, TxEnvelope},
3    eips::Decodable2718,
4};
5use signet_bundle::SignetEthBundle;
6
7/// An item that can be simulated.
8#[derive(Debug, Clone, PartialEq)]
9pub enum SimItem {
10    /// A bundle to be simulated.
11    Bundle(SignetEthBundle),
12
13    /// A transaction to be simulated.
14    Tx(TxEnvelope),
15}
16
17impl From<SignetEthBundle> for SimItem {
18    fn from(bundle: SignetEthBundle) -> Self {
19        Self::Bundle(bundle)
20    }
21}
22
23impl From<TxEnvelope> for SimItem {
24    fn from(tx: TxEnvelope) -> Self {
25        Self::Tx(tx)
26    }
27}
28
29impl SimItem {
30    /// Get the bundle if it is a bundle.
31    pub const fn as_bundle(&self) -> Option<&SignetEthBundle> {
32        match self {
33            Self::Bundle(bundle) => Some(bundle),
34            Self::Tx(_) => None,
35        }
36    }
37
38    /// Get the transaction if it is a transaction.
39    pub const fn as_tx(&self) -> Option<&TxEnvelope> {
40        match self {
41            Self::Bundle(_) => None,
42            Self::Tx(tx) => Some(tx),
43        }
44    }
45
46    /// Calculate the maximum gas fee payable, this may be used as a heuristic
47    /// to determine simulation order.
48    pub fn calculate_total_fee(&self, basefee: u64) -> u128 {
49        match self {
50            Self::Bundle(bundle) => {
51                let mut total_tx_fee = 0;
52                for tx in bundle.bundle.txs.iter() {
53                    let Ok(tx) = TxEnvelope::decode_2718(&mut tx.as_ref()) else {
54                        continue;
55                    };
56                    total_tx_fee += tx.effective_gas_price(Some(basefee)) * tx.gas_limit() as u128;
57                }
58                total_tx_fee
59            }
60            Self::Tx(tx) => tx.effective_gas_price(Some(basefee)) * tx.gas_limit() as u128,
61        }
62    }
63}
64
65// Testing functions
66impl SimItem {
67    /// Create an invalid test item. This will be a [`TxEnvelope`] containing
68    /// an EIP-1559 transaction with an invalid signature and hash.
69    #[doc(hidden)]
70    pub fn invalid_item() -> Self {
71        TxEnvelope::Eip1559(alloy::consensus::Signed::new_unchecked(
72            alloy::consensus::TxEip1559::default(),
73            alloy::signers::Signature::test_signature(),
74            Default::default(),
75        ))
76        .into()
77    }
78
79    /// Create an invalid test item with a given gas limit and max priority fee
80    /// per gas. As [`Self::invalid_test_item`] but with a custom gas limit and
81    /// `max_priority_fee_per_gas`.
82    #[doc(hidden)]
83    pub fn invalid_item_with_score(gas_limit: u64, mpfpg: u128) -> Self {
84        let tx = alloy::consensus::TxEip1559 {
85            gas_limit,
86            max_priority_fee_per_gas: mpfpg,
87            max_fee_per_gas: alloy::consensus::constants::GWEI_TO_WEI as u128,
88            ..Default::default()
89        };
90
91        let tx = TxEnvelope::Eip1559(alloy::consensus::Signed::new_unchecked(
92            tx,
93            alloy::signers::Signature::test_signature(),
94            Default::default(),
95        ));
96        tx.into()
97    }
98}