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
11pub trait RpcTypes: Send + Sync + Clone + Unpin + Debug + 'static {
15 type Header: RpcObject + HeaderResponse;
17 type Receipt: RpcObject + ReceiptResponse;
19 type TransactionResponse: RpcObject + TransactionResponse;
21 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
35pub type RpcTransaction<T> = <T as RpcTypes>::TransactionResponse;
37
38pub type RpcReceipt<T> = <T as RpcTypes>::Receipt;
40
41pub type RpcHeader<T> = <T as RpcTypes>::Header;
43
44pub type RpcBlock<T> = alloy_rpc_types_eth::Block<RpcTransaction<T>, RpcHeader<T>>;
46
47pub type RpcTxReq<T> = <T as RpcTypes>::TransactionRequest;
49
50#[derive(Debug, thiserror::Error)]
52pub enum SignTxRequestError {
53 #[error("invalid transaction request")]
55 InvalidTransactionRequest,
56
57 #[error(transparent)]
59 SignerNotSupported(#[from] alloy_signer::Error),
60}
61
62pub trait SignableTxRequest<T>: Send + Sync + 'static {
64 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 if tx.is_deposit() {
97 return Err(SignTxRequestError::InvalidTransactionRequest);
98 }
99
100 Ok(tx.into_signed(signature).into())
101 }
102}