use crate::bitcoin::BitcoinAddress;
use crate::error::AddressError;
use crate::ethereum::EthereumAddress;
use crate::network::Network;
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum Address {
Bitcoin(BitcoinAddress),
Ethereum(EthereumAddress),
}
impl Address {
pub fn parse(s: &str) -> Result<Self, AddressError> {
s.parse()
}
pub fn validate(s: &str) -> Result<(), AddressError> {
s.parse::<Self>().map(|_| ())
}
pub fn network(&self) -> Network {
match self {
Address::Bitcoin(addr) => addr.network(),
Address::Ethereum(_) => Network::Ethereum,
}
}
#[inline]
pub fn is_bitcoin(&self) -> bool {
matches!(self, Address::Bitcoin(_))
}
#[inline]
pub fn is_ethereum(&self) -> bool {
matches!(self, Address::Ethereum(_))
}
}
impl std::fmt::Display for Address {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Address::Bitcoin(addr) => write!(f, "{}", addr),
Address::Ethereum(addr) => write!(f, "{}", addr),
}
}
}
impl std::str::FromStr for Address {
type Err = AddressError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
if s.starts_with("0x") || s.starts_with("0X") {
return s.parse::<EthereumAddress>().map(Address::Ethereum);
}
s.parse::<BitcoinAddress>().map(Address::Bitcoin)
}
}
impl From<BitcoinAddress> for Address {
fn from(addr: BitcoinAddress) -> Self {
Address::Bitcoin(addr)
}
}
impl From<EthereumAddress> for Address {
fn from(addr: EthereumAddress) -> Self {
Address::Ethereum(addr)
}
}
pub trait AddressFormat: Sized {
fn parse(s: &str) -> Result<Self, AddressError>;
fn validate(s: &str) -> Result<(), AddressError>;
fn to_string(&self) -> String;
}
#[cfg(test)]
mod tests {
use super::*;
use crate::bitcoin::{P2PKHAddress, P2TRAddress, P2WPKHAddress};
use rustywallet_keys::private_key::PrivateKey;
#[test]
fn test_address_detection_p2pkh() {
let pk = PrivateKey::random();
let pubkey = pk.public_key();
let addr = P2PKHAddress::from_public_key(&pubkey, Network::BitcoinMainnet).unwrap();
let parsed: Address = addr.to_string().parse().unwrap();
assert!(parsed.is_bitcoin());
}
#[test]
fn test_address_detection_p2wpkh() {
let pk = PrivateKey::random();
let pubkey = pk.public_key();
let addr = P2WPKHAddress::from_public_key(&pubkey, Network::BitcoinMainnet).unwrap();
let parsed: Address = addr.to_string().parse().unwrap();
assert!(parsed.is_bitcoin());
}
#[test]
fn test_address_detection_p2tr() {
let pk = PrivateKey::random();
let pubkey = pk.public_key();
let addr = P2TRAddress::from_public_key(&pubkey, Network::BitcoinMainnet).unwrap();
let parsed: Address = addr.to_string().parse().unwrap();
assert!(parsed.is_bitcoin());
}
#[test]
fn test_address_detection_ethereum() {
let pk = PrivateKey::random();
let pubkey = pk.public_key();
let addr = EthereumAddress::from_public_key(&pubkey).unwrap();
let parsed: Address = addr.to_string().parse().unwrap();
assert!(parsed.is_ethereum());
}
}