1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
use std::str::FromStr;
use bitcoin::util::bip32::{self, ExtendedPubKey, Fingerprint};
use bitcoin::XpubIdentifier;
#[derive(
Clone,
Ord,
PartialOrd,
Eq,
PartialEq,
Hash,
Debug,
Display,
From,
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("")]
None,
#[from]
Fingerprint(Fingerprint),
#[from]
XpubIdentifier(XpubIdentifier),
#[from]
Xpub(ExtendedPubKey),
}
impl XpubRef {
pub fn is_some(&self) -> bool {
self != &XpubRef::None
}
pub fn fingerprint(&self) -> Option<Fingerprint> {
match self {
XpubRef::None => 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::None => None,
XpubRef::Fingerprint(_) => None,
XpubRef::XpubIdentifier(xpubid) => Some(*xpubid),
XpubRef::Xpub(xpub) => Some(xpub.identifier()),
}
}
pub fn xpubkey(&self) -> Option<ExtendedPubKey> {
match self {
XpubRef::None => None,
XpubRef::Fingerprint(_) => None,
XpubRef::XpubIdentifier(_) => None,
XpubRef::Xpub(xpub) => Some(xpub.clone()),
}
}
}
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::None);
}
if s.chars().nth(0) == Some('=') {
s = &s[2..s.len() - 1];
} else {
s = &s[1..s.len() - 1]
}
Ok(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))?)
}
}