lightning_signer/util/
invoice_utils.rs1use core::str::FromStr;
2
3use crate::invoice::*;
4use crate::prelude::*;
5use crate::util::status::{invalid_argument, Status};
6
7impl FromStr for Invoice {
8 type Err = Status;
9 fn from_str(invstr: &str) -> Result<Self, Self::Err> {
10 let maybe_bolt12 = WrappedBolt12Invoice::from_str(invstr);
12 match maybe_bolt12 {
13 Ok(bolt12) => Ok(Invoice::Bolt12(bolt12.0)),
14 Err(bolt12err) => {
15 let bolt11_raw = invstr.parse::<bolt11::SignedRawBolt11Invoice>().map_err(|e| {
16 Status::invalid_argument(format!(
17 "invoice not bolt12: {:?} and not bolt11: {:?}",
18 bolt12err, e
19 ))
20 })?;
21 Ok(Invoice::try_from(bolt11_raw)?)
22 }
23 }
24 }
25}
26
27impl TryFrom<bolt11::SignedRawBolt11Invoice> for Invoice {
29 type Error = Status;
30 fn try_from(bolt11_raw: bolt11::SignedRawBolt11Invoice) -> Result<Self, Self::Error> {
31 let bolt11 = bolt11::Bolt11Invoice::from_signed(bolt11_raw)
33 .map_err(|e| invalid_argument(e.to_string()))?;
34 Ok(Invoice::Bolt11(bolt11))
35 }
36}
37
38use bitcoin::bech32;
42use bitcoin::bech32::FromBase32;
43use lightning::offers::parse::Bolt12ParseError;
44
45struct WrappedBolt12Invoice(bolt12::Bolt12Invoice);
46
47impl FromStr for WrappedBolt12Invoice {
48 type Err = Bolt12ParseError;
49
50 fn from_str(s: &str) -> Result<WrappedBolt12Invoice, <WrappedBolt12Invoice as FromStr>::Err> {
51 const BECH32_HRP: &'static str = "lni";
52
53 let encoded = match s.split('+').skip(1).next() {
55 Some(_) => {
56 for chunk in s.split('+') {
57 let chunk = chunk.trim_start();
58 if chunk.is_empty() || chunk.contains(char::is_whitespace) {
59 return Err(Bolt12ParseError::InvalidContinuation);
60 }
61 }
62
63 let s: String = s.chars().filter(|c| *c != '+' && !c.is_whitespace()).collect();
64 Bech32String::Owned(s)
65 }
66 None => Bech32String::Borrowed(s),
67 };
68
69 let (hrp, data) = bech32::decode_without_checksum(encoded.as_ref())?;
70
71 if hrp != BECH32_HRP {
72 return Err(Bolt12ParseError::InvalidBech32Hrp);
73 }
74
75 let data = Vec::<u8>::from_base32(&data)?;
76 Ok(WrappedBolt12Invoice(bolt12::Bolt12Invoice::try_from(data)?))
77 }
78}
79
80enum Bech32String<'a> {
82 Borrowed(&'a str),
83 Owned(String),
84}
85
86impl<'a> AsRef<str> for Bech32String<'a> {
87 fn as_ref(&self) -> &str {
88 match self {
89 Bech32String::Borrowed(s) => s,
90 Bech32String::Owned(s) => s,
91 }
92 }
93}