rustywallet_address/bitcoin/
mod.rs1mod p2pkh;
4mod p2wpkh;
5mod p2tr;
6
7pub use p2pkh::*;
8pub use p2wpkh::*;
9pub use p2tr::*;
10
11use crate::error::AddressError;
12use crate::network::Network;
13
14#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
16pub enum BitcoinAddressType {
17 P2PKH,
19 P2WPKH,
21 P2TR,
23}
24
25impl std::fmt::Display for BitcoinAddressType {
26 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
27 match self {
28 BitcoinAddressType::P2PKH => write!(f, "P2PKH"),
29 BitcoinAddressType::P2WPKH => write!(f, "P2WPKH"),
30 BitcoinAddressType::P2TR => write!(f, "P2TR"),
31 }
32 }
33}
34
35#[derive(Debug, Clone, PartialEq, Eq)]
37pub struct BitcoinAddress {
38 address_type: BitcoinAddressType,
39 network: Network,
40 payload: Vec<u8>,
41 encoded: String,
42}
43
44impl BitcoinAddress {
45 #[inline]
47 pub fn address_type(&self) -> BitcoinAddressType {
48 self.address_type
49 }
50
51 #[inline]
53 pub fn network(&self) -> Network {
54 self.network
55 }
56
57 #[inline]
59 pub fn payload(&self) -> &[u8] {
60 &self.payload
61 }
62
63 pub fn parse(s: &str) -> Result<Self, AddressError> {
65 s.parse()
66 }
67
68 pub fn validate(s: &str) -> Result<(), AddressError> {
70 s.parse::<Self>().map(|_| ())
71 }
72}
73
74impl std::fmt::Display for BitcoinAddress {
75 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
76 write!(f, "{}", self.encoded)
77 }
78}
79
80impl std::str::FromStr for BitcoinAddress {
81 type Err = AddressError;
82
83 fn from_str(s: &str) -> Result<Self, Self::Err> {
84 if s.starts_with('1') || s.starts_with('m') || s.starts_with('n') {
86 return s.parse::<P2PKHAddress>().map(|a| a.into());
87 }
88
89 let lower = s.to_lowercase();
91 if lower.starts_with("bc1q") || lower.starts_with("tb1q") {
92 return s.parse::<P2WPKHAddress>().map(|a| a.into());
93 }
94 if lower.starts_with("bc1p") || lower.starts_with("tb1p") {
95 return s.parse::<P2TRAddress>().map(|a| a.into());
96 }
97
98 Err(AddressError::UnsupportedAddressType(format!(
99 "Unknown Bitcoin address format: {}",
100 s
101 )))
102 }
103}
104
105impl From<P2PKHAddress> for BitcoinAddress {
106 fn from(addr: P2PKHAddress) -> Self {
107 Self {
108 address_type: BitcoinAddressType::P2PKH,
109 network: addr.network(),
110 payload: addr.hash().to_vec(),
111 encoded: addr.to_string(),
112 }
113 }
114}
115
116impl From<P2WPKHAddress> for BitcoinAddress {
117 fn from(addr: P2WPKHAddress) -> Self {
118 Self {
119 address_type: BitcoinAddressType::P2WPKH,
120 network: addr.network(),
121 payload: addr.hash().to_vec(),
122 encoded: addr.to_string(),
123 }
124 }
125}
126
127impl From<P2TRAddress> for BitcoinAddress {
128 fn from(addr: P2TRAddress) -> Self {
129 Self {
130 address_type: BitcoinAddressType::P2TR,
131 network: addr.network(),
132 payload: addr.x_only_pubkey().to_vec(),
133 encoded: addr.to_string(),
134 }
135 }
136}