alloy_network/transaction/signer.rs
1use crate::{Network, TransactionBuilder};
2use alloy_consensus::SignableTransaction;
3use alloy_primitives::Address;
4use alloy_signer::{Signer, SignerSync};
5use async_trait::async_trait;
6use auto_impl::auto_impl;
7use futures_utils_wasm::impl_future;
8
9/// A wallet capable of signing any transaction for the given network.
10///
11/// Network crate authors should implement this trait on a type capable of
12/// signing any transaction (regardless of signature type) on a given network.
13/// Signer crate authors should instead implement [`TxSigner`] to signify
14/// signing capability for specific signature types.
15///
16/// Network wallets are expected to contain one or more signing credentials,
17/// keyed by signing address. The default signer address should be used when
18/// no specific signer address is specified.
19#[auto_impl(&, &mut, Box, Rc, Arc)]
20pub trait NetworkWallet<N: Network>: std::fmt::Debug + Send + Sync {
21 /// Get the default signer address. This address should be used
22 /// in [`NetworkWallet::sign_transaction_from`] when no specific signer is
23 /// specified.
24 fn default_signer_address(&self) -> Address;
25
26 /// Return true if the signer contains a credential for the given address.
27 fn has_signer_for(&self, address: &Address) -> bool;
28
29 /// Return an iterator of all signer addresses.
30 fn signer_addresses(&self) -> impl Iterator<Item = Address>;
31
32 /// Asynchronously sign an unsigned transaction, with a specified
33 /// credential.
34 #[doc(alias = "sign_tx_from")]
35 fn sign_transaction_from(
36 &self,
37 sender: Address,
38 tx: N::UnsignedTx,
39 ) -> impl_future!(<Output = alloy_signer::Result<N::TxEnvelope>>);
40
41 /// Asynchronously sign an unsigned transaction.
42 #[doc(alias = "sign_tx")]
43 fn sign_transaction(
44 &self,
45 tx: N::UnsignedTx,
46 ) -> impl_future!(<Output = alloy_signer::Result<N::TxEnvelope>>) {
47 self.sign_transaction_from(self.default_signer_address(), tx)
48 }
49
50 /// Asynchronously sign a transaction request, using the sender specified
51 /// in the `from` field.
52 fn sign_request(
53 &self,
54 request: N::TransactionRequest,
55 ) -> impl_future!(<Output = alloy_signer::Result<N::TxEnvelope>>) {
56 async move {
57 let sender = request.from().unwrap_or_else(|| self.default_signer_address());
58 let tx = request.build_unsigned().map_err(alloy_signer::Error::other)?;
59 self.sign_transaction_from(sender, tx).await
60 }
61 }
62}
63
64/// Asynchronous transaction signer, capable of signing any [`SignableTransaction`] for the given
65/// `Signature` type.
66///
67/// A signer should hold an optional [`ChainId`] value, which is used for [EIP-155] replay
68/// protection.
69///
70/// If `chain_id` is Some, [EIP-155] should be applied to the input transaction in
71/// [`sign_transaction`](Self::sign_transaction), and to the resulting signature in all the methods.
72/// If `chain_id` is None, [EIP-155] should not be applied.
73///
74/// Synchronous signers should implement both this trait and [`TxSignerSync`].
75///
76/// [EIP-155]: https://eips.ethereum.org/EIPS/eip-155
77/// [`ChainId`]: alloy_primitives::ChainId
78#[cfg_attr(target_family = "wasm", async_trait(?Send))]
79#[cfg_attr(not(target_family = "wasm"), async_trait)]
80#[auto_impl(&, &mut, Box, Rc, Arc)]
81#[doc(alias = "TransactionSigner")]
82pub trait TxSigner<Signature> {
83 /// Get the address of the signer.
84 fn address(&self) -> Address;
85
86 /// Asynchronously sign an unsigned transaction.
87 #[doc(alias = "sign_tx")]
88 async fn sign_transaction(
89 &self,
90 tx: &mut dyn SignableTransaction<Signature>,
91 ) -> alloy_signer::Result<Signature>;
92}
93
94/// Synchronous transaction signer, capable of signing any [`SignableTransaction`] for the given
95/// `Signature` type.
96///
97/// A signer should hold an optional [`ChainId`] value, which is used for [EIP-155] replay
98/// protection.
99///
100/// If `chain_id` is Some, [EIP-155] should be applied to the input transaction in
101/// [`sign_transaction_sync`](Self::sign_transaction_sync), and to the resulting signature in all
102/// the methods. If `chain_id` is None, [EIP-155] should not be applied.
103///
104/// Synchronous signers should also implement [`TxSigner`], as they are always able to by delegating
105/// the asynchronous methods to the synchronous ones.
106///
107/// [EIP-155]: https://eips.ethereum.org/EIPS/eip-155
108/// [`ChainId`]: alloy_primitives::ChainId
109#[auto_impl(&, &mut, Box, Rc, Arc)]
110#[doc(alias = "TransactionSignerSync")]
111pub trait TxSignerSync<Signature> {
112 /// Get the address of the signer.
113 fn address(&self) -> Address;
114
115 /// Synchronously sign an unsigned transaction.
116 #[doc(alias = "sign_tx_sync")]
117 fn sign_transaction_sync(
118 &self,
119 tx: &mut dyn SignableTransaction<Signature>,
120 ) -> alloy_signer::Result<Signature>;
121}
122
123/// A unifying trait for asynchronous Ethereum signers that combine the functionalities of both
124/// [`Signer`] and [`TxSigner`].
125///
126/// This trait enables dynamic dispatch (e.g., using `Box<dyn FullSigner>`) for types that combine
127/// both asynchronous Ethereum signing and transaction signing functionalities.
128pub trait FullSigner<S>: Signer<S> + TxSigner<S> {}
129impl<T, S> FullSigner<S> for T where T: Signer<S> + TxSigner<S> {}
130
131/// A unifying trait for synchronous Ethereum signers that implement both [`SignerSync`] and
132/// [`TxSignerSync`].
133///
134/// This trait enables dynamic dispatch (e.g., using `Box<dyn FullSignerSync>`) for types that
135/// combine both synchronous Ethereum signing and transaction signing functionalities.
136pub trait FullSignerSync<S>: SignerSync<S> + TxSignerSync<S> {}
137impl<T, S> FullSignerSync<S> for T where T: SignerSync<S> + TxSignerSync<S> {}
138
139#[cfg(test)]
140mod tests {
141 use super::*;
142
143 struct _ObjectSafe(Box<dyn FullSigner<()>>, Box<dyn FullSignerSync<()>>);
144}