1use crate::Result;
4use crate::transaction::{Signer as SignerTrait, Signature as TxSignature};
5use alloy_primitives::{Address, B256};
6use alloy_signer::SignerSync;
7use alloy_signer_local::PrivateKeySigner;
8use rand::RngCore;
9
10#[derive(Debug)]
12pub struct EcdsaSigner {
13 signer: PrivateKeySigner,
14}
15
16impl SignerTrait for EcdsaSigner {
17 fn sign_hash(&self, hash: &B256) -> std::result::Result<TxSignature, Box<dyn std::error::Error>> {
18 let signature = self.signer.sign_hash_sync(hash)?;
20 let v = if signature.v() { 1 } else { 0 };
22 Ok(TxSignature::new(
23 signature.r().into(),
24 signature.s().into(),
25 v,
26 ))
27 }
28
29 fn address(&self) -> Address {
30 self.signer.address()
31 }
32}
33
34impl EcdsaSigner {
35 pub fn inner(&self) -> &PrivateKeySigner {
37 &self.signer
38 }
39
40 pub fn from_private_key(private_key: &str) -> Result<Self> {
42 let key = private_key.trim_start_matches("0x");
43 let bytes = hex::decode(key).map_err(|e| crate::Error::InvalidHex(e.to_string()))?;
44
45 if bytes.len() != 32 {
46 return Err(crate::Error::InvalidPrivateKey("private key must be 32 bytes".into()));
47 }
48
49 let signer = PrivateKeySigner::from_slice(&bytes)
50 .map_err(|e| crate::Error::InvalidPrivateKey(e.to_string()))?;
51
52 Ok(Self { signer })
53 }
54}
55
56pub use crate::transaction::Signer as Signer;
58
59#[derive(Debug, Clone)]
61pub struct Wallet {
62 pub address: String,
63 pub private_key: Option<String>,
64}
65
66impl Wallet {
67 pub fn generate() -> Result<Self> {
68 let mut key = [0u8; 32];
69 rand::thread_rng().fill_bytes(&mut key);
70
71 let signer = EcdsaSigner::from_private_key(&hex::encode(key))?;
72 Ok(Self {
73 address: signer.address().to_string(),
74 private_key: Some(format!("0x{}", hex::encode(key))),
75 })
76 }
77
78 pub fn from_private_key(private_key: &str) -> Result<Self> {
79 let signer = EcdsaSigner::from_private_key(private_key)?;
80 Ok(Self {
81 address: signer.address().to_string(),
82 private_key: Some(private_key.to_string()),
83 })
84 }
85}
86
87pub fn generate_private_key() -> String {
89 let mut key = [0u8; 32];
90 rand::thread_rng().fill_bytes(&mut key);
91 format!("0x{}", hex::encode(key))
92}
93
94pub fn private_key_to_address(private_key: &str) -> Result<String> {
96 let signer = EcdsaSigner::from_private_key(private_key)?;
97 Ok(signer.address().to_string())
98}