//! Ethereum wallet implementation. use ethers::prelude::*; use ethers::signers::{LocalWallet, Signer, Wallet}; use ethers::utils::hex; use k256::ecdsa::SigningKey; use sha2::{Digest, Sha256}; use std::str::FromStr; use super::networks::NetworkConfig; use crate::error::CryptoError; use crate::keyspace::KeyPair; /// An Ethereum wallet derived from a keypair. #[derive(Debug, Clone)] pub struct EthereumWallet { pub address: Address, pub wallet: Wallet, pub network: NetworkConfig, } impl EthereumWallet { /// Creates a new Ethereum wallet from a keypair for a specific network. pub fn from_keypair( keypair: &crate::keyspace::keypair_types::KeyPair, network: NetworkConfig, ) -> Result { // Get the private key bytes from the keypair let private_key_bytes = keypair.signing_key.to_bytes(); // Convert to a hex string (without 0x prefix) let private_key_hex = hex::encode(private_key_bytes); // Create an Ethereum wallet from the private key let wallet = LocalWallet::from_str(&private_key_hex) .map_err(|_e| CryptoError::InvalidKeyLength)? .with_chain_id(network.chain_id); // Get the Ethereum address let address = wallet.address(); Ok(EthereumWallet { address, wallet, network, }) } /// Creates a new Ethereum wallet from a name and keypair (deterministic derivation) for a specific network. pub fn from_name_and_keypair( name: &str, keypair: &KeyPair, network: NetworkConfig, ) -> Result { // Get the private key bytes from the keypair let private_key_bytes = keypair.signing_key.to_bytes(); // Create a deterministic seed by combining name and private key let mut hasher = Sha256::default(); hasher.update(name.as_bytes()); hasher.update(&private_key_bytes); let seed = hasher.finalize(); // Use the seed as a private key let private_key_hex = hex::encode(seed); // Create an Ethereum wallet from the derived private key let wallet = LocalWallet::from_str(&private_key_hex) .map_err(|_e| CryptoError::InvalidKeyLength)? .with_chain_id(network.chain_id); // Get the Ethereum address let address = wallet.address(); Ok(EthereumWallet { address, wallet, network, }) } /// Creates a new Ethereum wallet from a private key for a specific network. pub fn from_private_key( private_key: &str, network: NetworkConfig, ) -> Result { // Remove 0x prefix if present let private_key_clean = private_key.trim_start_matches("0x"); // Create an Ethereum wallet from the private key let wallet = LocalWallet::from_str(private_key_clean) .map_err(|_e| CryptoError::InvalidKeyLength)? .with_chain_id(network.chain_id); // Get the Ethereum address let address = wallet.address(); Ok(EthereumWallet { address, wallet, network, }) } /// Gets the Ethereum address as a string. pub fn address_string(&self) -> String { format!("{:?}", self.address) } /// Signs a message with the Ethereum wallet. pub async fn sign_message(&self, message: &[u8]) -> Result { let signature = self .wallet .sign_message(message) .await .map_err(|e| CryptoError::SignatureFormatError(e.to_string()))?; Ok(signature.to_string()) } /// Gets the private key as a hex string. pub fn private_key_hex(&self) -> String { let bytes = self.wallet.signer().to_bytes(); hex::encode(bytes) } }