reth_rpc_types_compat/
transaction.rs

1//! Compatibility functions for rpc `Transaction` type.
2
3use core::error;
4use std::fmt;
5
6use alloy_consensus::Transaction as _;
7use alloy_rpc_types_eth::{
8    request::{TransactionInput, TransactionRequest},
9    TransactionInfo,
10};
11use reth_primitives::{RecoveredTx, TransactionSigned};
12use serde::{Deserialize, Serialize};
13
14/// Create a new rpc transaction result for a mined transaction, using the given block hash,
15/// number, and tx index fields to populate the corresponding fields in the rpc result.
16///
17/// The block hash, number, and tx index fields should be from the original block where the
18/// transaction was mined.
19pub fn from_recovered_with_block_context<Tx, T: TransactionCompat<Tx>>(
20    tx: RecoveredTx<Tx>,
21    tx_info: TransactionInfo,
22    resp_builder: &T,
23) -> Result<T::Transaction, T::Error> {
24    resp_builder.fill(tx, tx_info)
25}
26
27/// Create a new rpc transaction result for a _pending_ signed transaction, setting block
28/// environment related fields to `None`.
29pub fn from_recovered<Tx, T: TransactionCompat<Tx>>(
30    tx: RecoveredTx<Tx>,
31    resp_builder: &T,
32) -> Result<T::Transaction, T::Error> {
33    resp_builder.fill(tx, TransactionInfo::default())
34}
35
36/// Builds RPC transaction w.r.t. network.
37pub trait TransactionCompat<T = TransactionSigned>:
38    Send + Sync + Unpin + Clone + fmt::Debug
39{
40    /// RPC transaction response type.
41    type Transaction: Serialize
42        + for<'de> Deserialize<'de>
43        + Send
44        + Sync
45        + Unpin
46        + Clone
47        + fmt::Debug
48        + alloy_consensus::transaction::ShieldableTransaction;
49
50    /// RPC transaction error type.
51    type Error: error::Error + Into<jsonrpsee_types::ErrorObject<'static>>;
52
53    /// Create a new rpc transaction result for a _pending_ signed transaction, setting block
54    /// environment related fields to `None`.
55    fn fill(
56        &self,
57        tx: RecoveredTx<T>,
58        tx_inf: TransactionInfo,
59    ) -> Result<Self::Transaction, Self::Error>;
60
61    /// Builds a fake transaction from a transaction request for inclusion into block built in
62    /// `eth_simulateV1`.
63    fn build_simulate_v1_transaction(&self, request: TransactionRequest) -> Result<T, Self::Error>;
64
65    /// Truncates the input of a transaction to only the first 4 bytes.
66    // todo: remove in favour of using constructor on `TransactionResponse` or similar
67    // <https://github.com/alloy-rs/alloy/issues/1315>.
68    fn otterscan_api_truncate_input(tx: &mut Self::Transaction);
69}
70
71/// Convert [`RecoveredTx`] to [`TransactionRequest`]
72pub fn transaction_to_call_request(tx: RecoveredTx) -> TransactionRequest {
73    let from = tx.signer();
74    let to = Some(tx.transaction.to().into());
75    let gas = tx.transaction.gas_limit();
76    let value = tx.transaction.value();
77    let input = tx.transaction.input().clone();
78    let nonce = tx.transaction.nonce();
79    let chain_id = tx.transaction.chain_id();
80    let access_list = tx.transaction.access_list().cloned();
81    let max_fee_per_blob_gas = tx.transaction.max_fee_per_blob_gas();
82    let authorization_list = tx.transaction.authorization_list().map(|l| l.to_vec());
83    let blob_versioned_hashes = tx.transaction.blob_versioned_hashes().map(Vec::from);
84    let tx_type = tx.transaction.tx_type();
85
86    // fees depending on the transaction type
87    let (gas_price, max_fee_per_gas) = if tx.is_dynamic_fee() {
88        (None, Some(tx.max_fee_per_gas()))
89    } else {
90        (Some(tx.max_fee_per_gas()), None)
91    };
92    let max_priority_fee_per_gas = tx.transaction.max_priority_fee_per_gas();
93
94    TransactionRequest {
95        from: Some(from),
96        to,
97        gas_price,
98        max_fee_per_gas,
99        max_priority_fee_per_gas,
100        gas: Some(gas),
101        value: Some(value),
102        input: TransactionInput::new(input),
103        nonce: Some(nonce),
104        chain_id,
105        access_list,
106        max_fee_per_blob_gas,
107        blob_versioned_hashes,
108        transaction_type: Some(tx_type.into()),
109        sidecar: None,
110        authorization_list,
111        // TODO: Peter/Christian?
112        // alloy_consensus::transaction::EncryptionPublicKey::new([0u8;33])
113        seismic_elements: None,
114    }
115}