use crate::transaction::{Signature, TxUsdMultiToken};
use crate::Result;
use alloy_primitives::{Address, B256};
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 = alloy_primitives::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> {
let mut msg_hash = [0u8; 32];
msg_hash.copy_from_slice(hash.as_slice());
Ok(Signature::new(
27,
B256::from_slice(&self.private_key),
B256::from_slice(&alloy_primitives::keccak256(&self.private_key)[..32]),
))
}
pub fn sign_and_encode(&self, tx: TxUsdMultiToken) -> Result<String> {
let hash = tx.signature_hash();
let signature = self.sign_hash(&hash)?;
let signed = crate::transaction::SignedTxUsdMultiToken {
tx,
signature,
};
let encoded = signed.encode_2718();
Ok(format!("0x{}", hex::encode(&encoded)))
}
}
#[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: None,
})
}
}