reth_rpc_convert/
rpc.rs

1use std::{fmt::Debug, future::Future};
2
3use alloy_consensus::{EthereumTxEnvelope, SignableTransaction, TxEip4844};
4use alloy_json_rpc::RpcObject;
5use alloy_network::{
6    primitives::HeaderResponse, Network, ReceiptResponse, TransactionResponse, TxSigner,
7};
8use alloy_primitives::Signature;
9use alloy_rpc_types_eth::TransactionRequest;
10
11/// RPC types used by the `eth_` RPC API.
12///
13/// This is a subset of [`Network`] trait with only RPC response types kept.
14pub trait RpcTypes: Send + Sync + Clone + Unpin + Debug + 'static {
15    /// Header response type.
16    type Header: RpcObject + HeaderResponse;
17    /// Receipt response type.
18    type Receipt: RpcObject + ReceiptResponse;
19    /// Transaction response type.
20    type TransactionResponse: RpcObject + TransactionResponse;
21    /// Transaction response type.
22    type TransactionRequest: RpcObject + AsRef<TransactionRequest> + AsMut<TransactionRequest>;
23}
24
25impl<T> RpcTypes for T
26where
27    T: Network<TransactionRequest: AsRef<TransactionRequest> + AsMut<TransactionRequest>> + Unpin,
28{
29    type Header = T::HeaderResponse;
30    type Receipt = T::ReceiptResponse;
31    type TransactionResponse = T::TransactionResponse;
32    type TransactionRequest = T::TransactionRequest;
33}
34
35/// Adapter for network specific transaction response.
36pub type RpcTransaction<T> = <T as RpcTypes>::TransactionResponse;
37
38/// Adapter for network specific receipt response.
39pub type RpcReceipt<T> = <T as RpcTypes>::Receipt;
40
41/// Adapter for network specific header response.
42pub type RpcHeader<T> = <T as RpcTypes>::Header;
43
44/// Adapter for network specific block type.
45pub type RpcBlock<T> = alloy_rpc_types_eth::Block<RpcTransaction<T>, RpcHeader<T>>;
46
47/// Adapter for network specific transaction request.
48pub type RpcTxReq<T> = <T as RpcTypes>::TransactionRequest;
49
50/// Error for [`SignableTxRequest`] trait.
51#[derive(Debug, thiserror::Error)]
52pub enum SignTxRequestError {
53    /// The transaction request is invalid.
54    #[error("invalid transaction request")]
55    InvalidTransactionRequest,
56
57    /// The signer is not supported.
58    #[error(transparent)]
59    SignerNotSupported(#[from] alloy_signer::Error),
60}
61
62/// An abstraction over transaction requests that can be signed.
63pub trait SignableTxRequest<T>: Send + Sync + 'static {
64    /// Attempts to build a transaction request and sign it with the given signer.
65    fn try_build_and_sign(
66        self,
67        signer: impl TxSigner<Signature> + Send,
68    ) -> impl Future<Output = Result<T, SignTxRequestError>> + Send;
69}
70
71impl SignableTxRequest<EthereumTxEnvelope<TxEip4844>> for TransactionRequest {
72    async fn try_build_and_sign(
73        self,
74        signer: impl TxSigner<Signature> + Send,
75    ) -> Result<EthereumTxEnvelope<TxEip4844>, SignTxRequestError> {
76        let mut tx =
77            self.build_typed_tx().map_err(|_| SignTxRequestError::InvalidTransactionRequest)?;
78        let signature = signer.sign_transaction(&mut tx).await?;
79        Ok(tx.into_signed(signature).into())
80    }
81}
82
83#[cfg(feature = "op")]
84impl SignableTxRequest<op_alloy_consensus::OpTxEnvelope>
85    for op_alloy_rpc_types::OpTransactionRequest
86{
87    async fn try_build_and_sign(
88        self,
89        signer: impl TxSigner<Signature> + Send,
90    ) -> Result<op_alloy_consensus::OpTxEnvelope, SignTxRequestError> {
91        let mut tx =
92            self.build_typed_tx().map_err(|_| SignTxRequestError::InvalidTransactionRequest)?;
93        let signature = signer.sign_transaction(&mut tx).await?;
94
95        // sanity check
96        if tx.is_deposit() {
97            return Err(SignTxRequestError::InvalidTransactionRequest);
98        }
99
100        Ok(tx.into_signed(signature).into())
101    }
102}