use std::str::FromStr;
use bitcoin::util::bip32::{self, ExtendedPubKey, Fingerprint};
use bitcoin::XpubIdentifier;
#[derive(
Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash, Default, Debug, Display, From
)]
#[derive(StrictEncode, StrictDecode)]
#[cfg_attr(
feature = "serde",
derive(Serialize, Deserialize),
serde(crate = "serde_crate", rename_all = "camelCase", untagged)
)]
#[display("[{0}]", alt = "[{0:#}]")]
pub enum XpubRef {
#[display("")]
#[default]
Unknown,
#[from]
Fingerprint(Fingerprint),
#[from]
XpubIdentifier(XpubIdentifier),
#[from]
Xpub(ExtendedPubKey),
}
impl XpubRef {
pub fn is_some(&self) -> bool { self != &XpubRef::Unknown }
pub fn fingerprint(&self) -> Option<Fingerprint> {
match self {
XpubRef::Unknown => None,
XpubRef::Fingerprint(fp) => Some(*fp),
XpubRef::XpubIdentifier(xpubid) => Some(Fingerprint::from(&xpubid[0..4])),
XpubRef::Xpub(xpub) => Some(xpub.fingerprint()),
}
}
pub fn identifier(&self) -> Option<XpubIdentifier> {
match self {
XpubRef::Unknown => None,
XpubRef::Fingerprint(_) => None,
XpubRef::XpubIdentifier(xpubid) => Some(*xpubid),
XpubRef::Xpub(xpub) => Some(xpub.identifier()),
}
}
pub fn xpubkey(&self) -> Option<ExtendedPubKey> {
match self {
XpubRef::Unknown => None,
XpubRef::Fingerprint(_) => None,
XpubRef::XpubIdentifier(_) => None,
XpubRef::Xpub(xpub) => Some(*xpub),
}
}
}
impl FromStr for XpubRef {
type Err = bip32::Error;
fn from_str(mut s: &str) -> Result<Self, Self::Err> {
if s.is_empty() {
return Ok(XpubRef::Unknown);
}
if s.starts_with("=[") {
s = &s[2..s.len() - 1];
} else if s.starts_with('[') {
s = &s[1..s.len() - 1]
}
Fingerprint::from_str(s)
.map(XpubRef::from)
.or_else(|_| XpubIdentifier::from_str(s).map(XpubRef::from))
.map_err(|_| bip32::Error::InvalidDerivationPathFormat)
.or_else(|_| ExtendedPubKey::from_str(s).map(XpubRef::from))
}
}