1#[cfg(feature = "alloc")]
4use alloc::{format, string::ToString};
5
6#[cfg(feature = "alloc")]
7use crate::{Error, Network};
8use core::fmt;
9#[cfg(feature = "alloc")]
10use core::str::FromStr;
11
12#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
14pub enum AddressType {
15 P2pkh,
17 P2shP2wpkh,
19 #[default]
21 P2wpkh,
22 P2tr,
24}
25
26impl AddressType {
27 #[inline]
29 #[must_use]
30 pub const fn purpose(self) -> u32 {
31 match self {
32 Self::P2pkh => 44,
33 Self::P2shP2wpkh => 49,
34 Self::P2wpkh => 84,
35 Self::P2tr => 86,
36 }
37 }
38
39 #[inline]
41 #[must_use]
42 pub const fn name(self) -> &'static str {
43 match self {
44 Self::P2pkh => "P2PKH (Legacy)",
45 Self::P2shP2wpkh => "P2SH-P2WPKH (SegWit)",
46 Self::P2wpkh => "P2WPKH (Native SegWit)",
47 Self::P2tr => "P2TR (Taproot)",
48 }
49 }
50}
51
52impl fmt::Display for AddressType {
53 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
54 write!(f, "{}", self.name())
55 }
56}
57
58#[cfg(feature = "alloc")]
60#[derive(Debug, Clone, PartialEq, Eq)]
61pub struct DerivationPath {
62 inner: bitcoin::bip32::DerivationPath,
63}
64
65#[cfg(feature = "alloc")]
66impl DerivationPath {
67 #[must_use]
71 pub fn bip_standard(
72 address_type: AddressType,
73 network: Network,
74 account: u32,
75 change: bool,
76 address_index: u32,
77 ) -> Self {
78 let purpose = address_type.purpose();
79 let coin_type = network.coin_type();
80 let change_val = if change { 1 } else { 0 };
81
82 let path_str = format!("m/{purpose}'/{coin_type}'/{account}'/{change_val}/{address_index}");
83
84 Self {
85 inner: path_str.parse().expect("valid BIP standard path"),
86 }
87 }
88
89 pub fn from_path_str(path: &str) -> Result<Self, Error> {
95 let inner = bitcoin::bip32::DerivationPath::from_str(path)
96 .map_err(|e| Error::InvalidDerivationPath(e.to_string()))?;
97 Ok(Self { inner })
98 }
99
100 #[inline]
102 #[must_use]
103 pub fn inner(&self) -> &bitcoin::bip32::DerivationPath {
104 &self.inner
105 }
106}
107
108#[cfg(feature = "alloc")]
109impl fmt::Display for DerivationPath {
110 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
111 write!(f, "m/{}", self.inner)
112 }
113}
114
115#[cfg(feature = "alloc")]
116impl AsRef<bitcoin::bip32::DerivationPath> for DerivationPath {
117 fn as_ref(&self) -> &bitcoin::bip32::DerivationPath {
118 &self.inner
119 }
120}