1mod error;
20
21use core::ops::{Deref, DerefMut};
22
23pub use alloy_consensus;
24pub use alloy_network;
25pub use alloy_network::{TxSigner, TxSignerSync};
26pub use alloy_primitives;
27pub use alloy_primitives::{Address, B256, ChainId, U256};
28pub use alloy_signer;
29pub use alloy_signer::{Signature, Signer as AlloySigner, SignerSync};
30pub use alloy_signer_local;
31use alloy_signer_local::PrivateKeySigner;
32pub use error::Error;
33
34#[derive(Debug, Clone)]
48pub struct Signer {
49 inner: PrivateKeySigner,
50}
51
52impl Deref for Signer {
53 type Target = PrivateKeySigner;
54
55 #[inline]
56 fn deref(&self) -> &Self::Target {
57 &self.inner
58 }
59}
60
61impl DerefMut for Signer {
62 #[inline]
63 fn deref_mut(&mut self) -> &mut Self::Target {
64 &mut self.inner
65 }
66}
67
68impl From<PrivateKeySigner> for Signer {
69 #[inline]
70 fn from(inner: PrivateKeySigner) -> Self {
71 Self { inner }
72 }
73}
74
75impl From<Signer> for PrivateKeySigner {
76 #[inline]
77 fn from(signer: Signer) -> Self {
78 signer.inner
79 }
80}
81
82impl Signer {
83 pub fn from_bytes(bytes: &B256) -> Result<Self, Error> {
89 let inner =
90 PrivateKeySigner::from_bytes(bytes).map_err(|e| Error::InvalidKey(e.to_string()))?;
91 Ok(Self { inner })
92 }
93
94 pub fn from_hex(hex_str: &str) -> Result<Self, Error> {
104 let hex_str = hex_str.strip_prefix("0x").unwrap_or(hex_str);
105 let bytes: [u8; 32] = hex::decode(hex_str)?.try_into().map_err(|v: Vec<u8>| {
106 Error::InvalidKey(format!("expected 32 bytes, got {}", v.len()))
107 })?;
108 Self::from_bytes(&B256::from(bytes))
109 }
110
111 #[must_use]
113 pub fn random() -> Self {
114 Self {
115 inner: PrivateKeySigner::random(),
116 }
117 }
118
119 #[must_use]
121 pub fn into_inner(self) -> PrivateKeySigner {
122 self.inner
123 }
124}
125
126#[cfg(feature = "kobe")]
127impl Signer {
128 pub fn from_derived(derived: &kobe_evm::DerivedAddress) -> Result<Self, Error> {
134 Self::from_hex(&derived.private_key_hex)
135 }
136
137 pub fn from_standard_wallet(wallet: &kobe_evm::StandardWallet) -> Result<Self, Error> {
143 Self::from_hex(&wallet.secret_hex())
144 }
145}
146
147#[cfg(test)]
148mod tests {
149 use super::*;
150
151 #[test]
152 fn assert_send_sync() {
153 fn assert<T: Send + Sync>() {}
154 assert::<Signer>();
155 }
156
157 #[test]
158 fn assert_clone() {
159 let s = Signer::random();
160 let s2 = s.clone();
161 assert_eq!(s.address(), s2.address());
162 }
163
164 #[test]
165 fn random_signer() {
166 let s = Signer::random();
167 assert_ne!(s.address(), Address::ZERO);
168 }
169
170 #[test]
171 fn hex_roundtrip() {
172 let s = Signer::random();
173 let hex_key = hex::encode(s.inner.credential().to_bytes());
174 let restored = Signer::from_hex(&hex_key).unwrap();
175 assert_eq!(s.address(), restored.address());
176 }
177
178 #[test]
179 fn hex_with_prefix() {
180 let s = Signer::random();
181 let hex_key = format!("0x{}", hex::encode(s.inner.credential().to_bytes()));
182 let restored = Signer::from_hex(&hex_key).unwrap();
183 assert_eq!(s.address(), restored.address());
184 }
185
186 #[test]
187 fn sign_message_sync() {
188 let s = Signer::random();
189 let sig = s.sign_message_sync(b"hello").unwrap();
190 let recovered = sig.recover_address_from_msg("hello").unwrap();
191 assert_eq!(recovered, s.address());
192 }
193
194 #[test]
195 fn sign_hash_sync() {
196 let s = Signer::random();
197 let hash = B256::from([0xab; 32]);
198 let sig = s.sign_hash_sync(&hash).unwrap();
199 let recovered = sig.recover_address_from_prehash(&hash).unwrap();
200 assert_eq!(recovered, s.address());
201 }
202
203 #[test]
204 fn into_inner() {
205 let s = Signer::random();
206 let addr = s.address();
207 let inner = s.into_inner();
208 assert_eq!(inner.address(), addr);
209 }
210
211 #[test]
212 fn from_private_key_signer() {
213 let pks = PrivateKeySigner::random();
214 let addr = pks.address();
215 let s = Signer::from(pks);
216 assert_eq!(s.address(), addr);
217 }
218}