use crate::Result;
use crate::transaction::{Signer as SignerTrait, Signature as TxSignature};
use alloy_primitives::{Address, B256, keccak256};
use rand::RngCore;
#[derive(Debug)]
pub struct Signer {
private_key: [u8; 32],
}
impl SignerTrait for Signer {
fn sign_hash(&self, _hash: &B256) -> std::result::Result<TxSignature, Box<dyn std::error::Error>> {
Ok(TxSignature::new(
B256::from_slice(&self.private_key),
B256::from_slice(&keccak256(&self.private_key)[..32]),
0, ))
}
fn address(&self) -> Address {
let hash = keccak256(&self.private_key);
Address::from_slice(&hash[12..32])
}
}
impl Signer {
pub fn from_private_key(private_key: &str) -> Result<Self> {
let key = private_key.trim_start_matches("0x");
let bytes = hex::decode(key).map_err(|e| crate::Error::InvalidHex(e.to_string()))?;
if bytes.len() != 32 {
return Err(crate::Error::InvalidPrivateKey("private key must be 32 bytes".into()));
}
let mut private_key = [0u8; 32];
private_key.copy_from_slice(&bytes);
Ok(Self { private_key })
}
}
#[derive(Debug, Clone)]
pub struct Wallet {
pub address: String,
pub private_key: Option<String>,
}
impl Wallet {
pub fn generate() -> Result<Self> {
let mut key = [0u8; 32];
rand::thread_rng().fill_bytes(&mut key);
let signer = Signer::from_private_key(&hex::encode(key))?;
Ok(Self {
address: signer.address().to_string(),
private_key: Some(format!("0x{}", hex::encode(key))),
})
}
pub fn from_private_key(private_key: &str) -> Result<Self> {
let signer = Signer::from_private_key(private_key)?;
Ok(Self {
address: signer.address().to_string(),
private_key: Some(private_key.to_string()),
})
}
}
pub fn generate_private_key() -> String {
let mut key = [0u8; 32];
rand::thread_rng().fill_bytes(&mut key);
format!("0x{}", hex::encode(key))
}
pub fn private_key_to_address(private_key: &str) -> Result<String> {
let signer = Signer::from_private_key(private_key)?;
Ok(signer.address().to_string())
}