use crate::Result;
use alloy_primitives::{Address, B256, Bytes, keccak256};
use alloy_rlp::Encodable;
use rand::RngCore;
#[derive(Debug)]
pub struct Signer {
private_key: [u8; 32],
chain_id: u64,
}
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, chain_id: 0 })
}
pub fn address(&self) -> Address {
let hash = keccak256(&self.private_key);
Address::from_slice(&hash[12..32])
}
pub fn chain_id(&self) -> u64 {
self.chain_id
}
pub fn with_chain_id(mut self, chain_id: u64) -> Self {
self.chain_id = chain_id;
self
}
pub fn sign_hash(&self, hash: &B256) -> Result<Signature> {
Ok(Signature {
v: 27,
r: B256::from_slice(&self.private_key),
s: B256::from_slice(&keccak256(&self.private_key)[..32]),
})
}
pub fn sign_transaction(
&self,
chain_id: u64,
nonce: u64,
gas_limit: u64,
fee_token: Address,
fee_payer: Address,
max_fee_per_gas_usd: u128,
sender: Address,
) -> Result<Signature> {
let mut buf = Vec::new();
buf.push(0x7B); chain_id.encode(&mut buf);
nonce.encode(&mut buf);
gas_limit.encode(&mut buf);
fee_token.encode(&mut buf);
fee_payer.encode(&mut buf);
max_fee_per_gas_usd.encode(&mut buf);
sender.encode(&mut buf);
let hash = keccak256(&buf);
self.sign_hash(&hash)
}
}
#[derive(Debug, Clone)]
pub struct Signature {
pub v: u64,
pub r: B256,
pub s: B256,
}
impl Signature {
pub fn new(v: u64, r: B256, s: B256) -> Self {
Self { v, r, s }
}
pub fn to_bytes(&self) -> Bytes {
let mut buf = Vec::with_capacity(65);
buf.push(self.v as u8);
buf.extend_from_slice(self.r.as_slice());
buf.extend_from_slice(self.s.as_slice());
Bytes::from(buf)
}
}
#[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())
}