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
use bech32::{Error as Bech32Error, FromBase32, ToBase32};
use std::error::Error as StdError;
use std::fmt;
use std::result::Result as StdResult;
pub type Result<T> = StdResult<T, Error>;
pub trait Bech32 {
const BECH32_HRP: &'static str;
fn try_from_bech32_str(bech32_str: &str) -> Result<Self>
where
Self: Sized;
fn to_bech32_str(&self) -> String;
}
pub fn to_bech32_from_bytes<B: Bech32>(bytes: &[u8]) -> String {
bech32::encode(B::BECH32_HRP, bytes.to_base32())
.unwrap_or_else(|e| panic!("Failed to build bech32: {}", e))
.to_string()
}
pub fn try_from_bech32_to_bytes<B: Bech32>(bech32_str: &str) -> Result<Vec<u8>> {
let (hrp, bech32_data) = bech32::decode(bech32_str)?;
if hrp != B::BECH32_HRP {
return Err(Error::HrpInvalid {
expected: B::BECH32_HRP,
actual: hrp,
});
}
Vec::<u8>::from_base32(&bech32_data).map_err(Into::into)
}
#[derive(Debug)]
pub enum Error {
Bech32Malformed(Bech32Error),
HrpInvalid {
expected: &'static str,
actual: String,
},
DataInvalid(Box<dyn StdError + Send + Sync + 'static>),
}
impl Error {
pub fn data_invalid(cause: impl StdError + Send + Sync + 'static) -> Self {
Error::DataInvalid(Box::new(cause))
}
}
impl From<Bech32Error> for Error {
fn from(error: Bech32Error) -> Self {
Error::Bech32Malformed(error)
}
}
impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter) -> StdResult<(), fmt::Error> {
match self {
Error::Bech32Malformed(_) => write!(f, "Failed to parse bech32, invalid data format"),
Error::HrpInvalid { expected, actual } => write!(
f,
"Parsed bech32 has invalid HRP prefix '{}', expected '{}'",
actual, expected
),
Error::DataInvalid(_) => write!(f, "Failed to parse data decoded from bech32"),
}
}
}
impl StdError for Error {
fn source(&self) -> Option<&(dyn StdError + 'static)> {
match self {
Error::Bech32Malformed(cause) => Some(cause),
Error::DataInvalid(cause) => Some(&**cause),
_ => None,
}
}
}