1- use crate :: { AnyNetwork , AnyTxEnvelope , AnyTypedTransaction , Network , NetworkWallet , TxSigner } ;
1+ use crate :: {
2+ AnyNetwork , AnyTxEnvelope , AnyTypedTransaction , FullSigner , Network , NetworkWallet , TxSigner ,
3+ } ;
24use alloy_consensus:: { SignableTransaction , TxEnvelope , TypedTransaction } ;
35use alloy_primitives:: { map:: AddressHashMap , Address , Signature } ;
4- use std:: { fmt:: Debug , sync:: Arc } ;
6+ use std:: { fmt:: Debug , ops :: Deref , sync:: Arc } ;
57
68use super :: Ethereum ;
79
810/// A wallet capable of signing any transaction for the Ethereum network.
911#[ derive( Clone , Default ) ]
1012pub struct EthereumWallet {
1113 default : Address ,
12- signers : AddressHashMap < Arc < dyn TxSigner < Signature > + Send + Sync > > ,
14+ signers : AddressHashMap < ArcFullSigner > ,
1315}
1416
1517impl std:: fmt:: Debug for EthereumWallet {
@@ -23,7 +25,7 @@ impl std::fmt::Debug for EthereumWallet {
2325
2426impl < S > From < S > for EthereumWallet
2527where
26- S : TxSigner < Signature > + Send + Sync + ' static ,
28+ S : FullSigner < Signature > + Send + Sync + ' static ,
2729{
2830 fn from ( signer : S ) -> Self {
2931 Self :: new ( signer)
@@ -34,7 +36,7 @@ impl EthereumWallet {
3436 /// Create a new signer with the given signer as the default signer.
3537 pub fn new < S > ( signer : S ) -> Self
3638 where
37- S : TxSigner < Signature > + Send + Sync + ' static ,
39+ S : FullSigner < Signature > + Send + Sync + ' static ,
3840 {
3941 let mut this = Self :: default ( ) ;
4042 this. register_default_signer ( signer) ;
@@ -48,9 +50,10 @@ impl EthereumWallet {
4850 /// [`TransactionRequest`]: alloy_rpc_types_eth::TransactionRequest
4951 pub fn register_signer < S > ( & mut self , signer : S )
5052 where
51- S : TxSigner < Signature > + Send + Sync + ' static ,
53+ S : FullSigner < Signature > + Send + Sync + ' static ,
5254 {
53- self . signers . insert ( signer. address ( ) , Arc :: new ( signer) ) ;
55+ let arc_signer = ArcFullSigner :: new ( signer) ;
56+ self . signers . insert ( arc_signer. address ( ) , arc_signer) ;
5457 }
5558
5659 /// Register a new signer on this object, and set it as the default signer.
@@ -61,9 +64,9 @@ impl EthereumWallet {
6164 /// [`TransactionRequest`]: alloy_rpc_types_eth::TransactionRequest
6265 pub fn register_default_signer < S > ( & mut self , signer : S )
6366 where
64- S : TxSigner < Signature > + Send + Sync + ' static ,
67+ S : FullSigner < Signature > + Send + Sync + ' static ,
6568 {
66- self . default = signer . address ( ) ;
69+ self . default = TxSigner :: address ( & signer ) ;
6770 self . register_signer ( signer) ;
6871 }
6972
@@ -90,15 +93,12 @@ impl EthereumWallet {
9093 }
9194
9295 /// Get the default signer.
93- pub fn default_signer ( & self ) -> Arc < dyn TxSigner < Signature > + Send + Sync + ' static > {
96+ pub fn default_signer ( & self ) -> ArcFullSigner {
9497 self . signers . get ( & self . default ) . cloned ( ) . expect ( "invalid signer" )
9598 }
9699
97100 /// Get the signer for the given address.
98- pub fn signer_by_address (
99- & self ,
100- address : Address ,
101- ) -> Option < Arc < dyn TxSigner < Signature > + Send + Sync + ' static > > {
101+ pub fn signer_by_address ( & self , address : Address ) -> Option < ArcFullSigner > {
102102 self . signers . get ( & address) . cloned ( )
103103 }
104104
@@ -115,6 +115,61 @@ impl EthereumWallet {
115115 . sign_transaction ( tx)
116116 . await
117117 }
118+
119+ /// Signs a hash with the given signer address.
120+ ///
121+ /// Hash can be arbitrary data or EIP-712 typed data hash.
122+ ///
123+ /// # Example
124+ ///
125+ /// ```ignore
126+ /// use alloy_sol_types::{sol, eip712_domain};
127+ /// use alloy_primitives::{address, keccak256, B256};
128+ /// use alloy_signer_local::PrivateKeySigner;
129+ /// sol! {
130+ /// struct Test {
131+ /// uint256 value;
132+ /// }
133+ /// }
134+ ///
135+ /// #[tokio::main]
136+ /// fn main() -> Result<(), Box<dyn std::error::Error>> {
137+ /// let domain = eip712_domain! {
138+ /// name: "Test",
139+ /// version: "1.0",
140+ /// chain_id: 1,
141+ /// verifying_contract: address!("0xB4e16d0168e52d35CaCD2c6185b44281Ec28C9Dc"),
142+ /// salt: keccak256("test_salt"),
143+ /// };
144+ ///
145+ /// let alice: PrivateKeySigner = "0x...".parse()?;
146+ /// let bob: PrivateKeySigner = "0x...".parse()?;
147+ ///
148+ /// let wallet = EthereumWallet::new(alice);
149+ /// wallet.register_signer(bob);
150+ ///
151+ /// let t = Test { value: U256::from(0x42) };
152+ ///
153+ /// let hash = t.eip712_signing_hash(&domain);
154+ ///
155+ /// let signature = wallet.sign_hash_with(alice.address(), &hash).await?;
156+ ///
157+ /// Ok(())
158+ /// }
159+ /// ```
160+ #[ cfg( feature = "eip712" ) ]
161+ pub async fn sign_hash_with (
162+ & self ,
163+ signer : Address ,
164+ hash : & alloy_primitives:: B256 ,
165+ ) -> alloy_signer:: Result < Signature > {
166+ self . signer_by_address ( signer)
167+ . ok_or_else ( || {
168+ alloy_signer:: Error :: other ( format ! ( "Missing signing credential for {signer}" ) )
169+ } ) ?
170+ . sign_hash ( hash)
171+ . await
172+ }
118173}
119174
120175impl < N > NetworkWallet < N > for EthereumWallet
@@ -207,3 +262,53 @@ impl<W: NetworkWallet<N>, N: Network> IntoWallet<N> for W {
207262 self
208263 }
209264}
265+
266+ /// Wrapper type for [`FullSigner`] that is used in [`EthereumWallet`].
267+ ///
268+ /// This is useful to disambiguate the function calls on a signer via [`EthereumWallet`] as
269+ /// [`TxSigner`] and [`Signer`] have the same methods e.g [`TxSigner::address`] and
270+ /// [`Signer::address`]
271+ ///
272+ /// [`Signer`]: alloy_signer::Signer
273+ /// [`Signer::address`]: alloy_signer::Signer::address
274+ #[ derive( Clone ) ]
275+ pub struct ArcFullSigner ( Arc < dyn FullSigner < Signature > + Send + Sync > ) ;
276+
277+ impl Debug for ArcFullSigner {
278+ fn fmt ( & self , f : & mut std:: fmt:: Formatter < ' _ > ) -> std:: fmt:: Result {
279+ f. debug_struct ( "ArcFullSigner" ) . field ( "address" , & self . address ( ) ) . finish ( )
280+ }
281+ }
282+
283+ impl ArcFullSigner {
284+ /// Create a new [`ArcFullSigner`] from a given [`FullSigner`].
285+ pub fn new < S > ( signer : S ) -> Self
286+ where
287+ S : FullSigner < Signature > + Send + Sync + ' static ,
288+ {
289+ Self ( Arc :: new ( signer) )
290+ }
291+
292+ /// Get the address of the signer.
293+ pub fn address ( & self ) -> Address {
294+ self . 0 . address ( )
295+ }
296+
297+ /// Get the underlying [`FullSigner`] as a reference.
298+ pub fn signer ( & self ) -> & dyn FullSigner < Signature > {
299+ self . 0 . as_ref ( )
300+ }
301+
302+ /// Get the underlying [`FullSigner`] as an owned value.
303+ pub fn into_signer ( self ) -> Arc < dyn FullSigner < Signature > + Send + Sync > {
304+ self . 0
305+ }
306+ }
307+
308+ impl Deref for ArcFullSigner {
309+ type Target = dyn FullSigner < Signature > + Send + Sync ;
310+
311+ fn deref ( & self ) -> & Self :: Target {
312+ self . 0 . as_ref ( )
313+ }
314+ }
0 commit comments