use anyhow::Result;
use solana_sdk::signature::{read_keypair_file, Keypair, Signer};
use std::path::Path;
pub fn load_keypair(source: &str) -> Result<Keypair> {
let home = std::env::var("USERPROFILE")
.or_else(|_| std::env::var("HOME"))
.unwrap_or_else(|_| ".".to_string());
let expanded = source.replace("~", &home);
let expanded = if expanded.starts_with("\\\\") {
"\\\\".to_string() + &expanded[2..].replace("\\\\", "\\")
} else {
expanded.replace("\\\\", "\\")
};
let expanded = expanded.replace("//", "/");
let path = Path::new(&expanded);
if path.exists() {
return read_keypair_file(path)
.map_err(|e| anyhow::anyhow!("Failed to read existing keypair file {}: {}", expanded, e));
}
if source.starts_with('/') || source.starts_with('~') || source.starts_with("./") || source.contains(std::path::MAIN_SEPARATOR) {
return Err(anyhow::anyhow!("Keypair file path specified but not found: {}", expanded));
}
let bytes = bs58::decode(source)
.into_vec()
.map_err(|e| anyhow::anyhow!("Failed to decode base58 key (input: '{}'): {}", source, e))?;
Keypair::from_bytes(&bytes)
.map_err(|e| anyhow::anyhow!("Invalid keypair bytes: {}", e))
}
pub struct Wallet {
pub keypair: Keypair,
}
impl Wallet {
pub fn new(keypair: Keypair) -> Self {
Self { keypair }
}
pub fn from_source(source: &str) -> Result<Self> {
Ok(Self::new(load_keypair(source)?))
}
pub fn pubkey(&self) -> solana_sdk::pubkey::Pubkey {
self.keypair.pubkey()
}
}
impl std::fmt::Debug for Wallet {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "Wallet({})", self.pubkey())
}
}