ethers_signers/wallet/
mod.rs1mod mnemonic;
2pub use mnemonic::MnemonicBuilder;
3
4mod private_key;
5pub use private_key::WalletError;
6
7#[cfg(all(feature = "yubihsm", not(target_arch = "wasm32")))]
8mod yubi;
9
10use crate::{to_eip155_v, Signer};
11use ethers_core::{
12 k256::{
13 ecdsa::{signature::hazmat::PrehashSigner, RecoveryId, Signature as RecoverableSignature},
14 elliptic_curve::FieldBytes,
15 Secp256k1,
16 },
17 types::{
18 transaction::{eip2718::TypedTransaction, eip712::Eip712},
19 Address, Signature, H256, U256,
20 },
21 utils::hash_message,
22};
23
24use async_trait::async_trait;
25use std::fmt;
26
27#[derive(Clone)]
64pub struct Wallet<D: PrehashSigner<(RecoverableSignature, RecoveryId)>> {
65 pub(crate) signer: D,
67 pub(crate) address: Address,
69 pub(crate) chain_id: u64,
71}
72
73impl<D: PrehashSigner<(RecoverableSignature, RecoveryId)>> Wallet<D> {
74 pub fn new_with_signer(signer: D, address: Address, chain_id: u64) -> Self {
76 Wallet { signer, address, chain_id }
77 }
78}
79
80#[cfg_attr(target_arch = "wasm32", async_trait(?Send))]
81#[cfg_attr(not(target_arch = "wasm32"), async_trait)]
82impl<D: Sync + Send + PrehashSigner<(RecoverableSignature, RecoveryId)>> Signer for Wallet<D> {
83 type Error = WalletError;
84
85 async fn sign_message<S: Send + Sync + AsRef<[u8]>>(
86 &self,
87 message: S,
88 ) -> Result<Signature, Self::Error> {
89 let message = message.as_ref();
90 let message_hash = hash_message(message);
91
92 self.sign_hash(message_hash)
93 }
94
95 async fn sign_transaction(&self, tx: &TypedTransaction) -> Result<Signature, Self::Error> {
96 let mut tx_with_chain = tx.clone();
97 if tx_with_chain.chain_id().is_none() {
98 tx_with_chain.set_chain_id(self.chain_id);
100 }
101 self.sign_transaction_sync(&tx_with_chain)
102 }
103
104 async fn sign_typed_data<T: Eip712 + Send + Sync>(
105 &self,
106 payload: &T,
107 ) -> Result<Signature, Self::Error> {
108 let encoded =
109 payload.encode_eip712().map_err(|e| Self::Error::Eip712Error(e.to_string()))?;
110
111 self.sign_hash(H256::from(encoded))
112 }
113
114 fn address(&self) -> Address {
115 self.address
116 }
117
118 fn chain_id(&self) -> u64 {
120 self.chain_id
121 }
122
123 fn with_chain_id<T: Into<u64>>(mut self, chain_id: T) -> Self {
125 self.chain_id = chain_id.into();
126 self
127 }
128}
129
130impl<D: PrehashSigner<(RecoverableSignature, RecoveryId)>> Wallet<D> {
131 pub fn sign_transaction_sync(&self, tx: &TypedTransaction) -> Result<Signature, WalletError> {
135 let chain_id = tx.chain_id().map(|id| id.as_u64()).unwrap_or(self.chain_id);
137 let mut tx = tx.clone();
138 tx.set_chain_id(chain_id);
139
140 let sighash = tx.sighash();
141 let mut sig = self.sign_hash(sighash)?;
142
143 sig.v = to_eip155_v(sig.v as u8 - 27, chain_id);
145 Ok(sig)
146 }
147
148 pub fn sign_hash(&self, hash: H256) -> Result<Signature, WalletError> {
150 let (recoverable_sig, recovery_id) = self.signer.sign_prehash(hash.as_ref())?;
151
152 let v = u8::from(recovery_id) as u64 + 27;
153
154 let r_bytes: FieldBytes<Secp256k1> = recoverable_sig.r().into();
155 let s_bytes: FieldBytes<Secp256k1> = recoverable_sig.s().into();
156 let r = U256::from_big_endian(r_bytes.as_slice());
157 let s = U256::from_big_endian(s_bytes.as_slice());
158
159 Ok(Signature { r, s, v })
160 }
161
162 pub fn signer(&self) -> &D {
164 &self.signer
165 }
166}
167
168impl<D: PrehashSigner<(RecoverableSignature, RecoveryId)>> fmt::Debug for Wallet<D> {
170 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
171 f.debug_struct("Wallet")
172 .field("address", &self.address)
173 .field("chain_Id", &self.chain_id)
174 .finish()
175 }
176}