Skip to content

Commit

Permalink
Add support for bolt12 offers in unified qrs
Browse files Browse the repository at this point in the history
  • Loading branch information
benthecarman committed Feb 11, 2024
1 parent 01b5d57 commit c576d20
Show file tree
Hide file tree
Showing 2 changed files with 34 additions and 3 deletions.
35 changes: 33 additions & 2 deletions waila/src/bip21.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,18 @@ use std::convert::TryFrom;
use ::bip21::de::*;
use ::bip21::*;
use bitcoin::address::NetworkUnchecked;
use lightning::offers::offer::Offer;
use lightning::offers::parse::Bolt12ParseError;
use lightning_invoice::{Bolt11Invoice, ParseOrSemanticError};
use url::Url;

/// This lets us parse `lightning` and payjoin parameters from a BIP21 URI.
/// This lets us parse `lightning`, bolt12, and payjoin parameters from a BIP21 URI.
pub type UnifiedUri<'a> = Uri<'a, NetworkUnchecked, WailaExtras>;

#[derive(Debug, Default, Eq, PartialEq, Clone, Hash)]
#[derive(Debug, Default, Clone)]
pub struct WailaExtras {
pub lightning: Option<Bolt11Invoice>,
pub b12: Option<Offer>,
pub pj: Option<Url>,
pjos: Option<bool>,
}
Expand All @@ -28,6 +31,7 @@ impl WailaExtras {
pub enum ExtraParamsParseError {
MultipleParams(String),
InvoiceParsingError,
Bolt12ParsingError,
MissingEndpoint,
NotUtf8(core::str::Utf8Error),
BadEndpoint(url::ParseError),
Expand All @@ -41,6 +45,12 @@ impl From<ParseOrSemanticError> for ExtraParamsParseError {
}
}

impl From<Bolt12ParseError> for ExtraParamsParseError {
fn from(_e: Bolt12ParseError) -> Self {
ExtraParamsParseError::Bolt12ParsingError
}
}

impl DeserializationError for WailaExtras {
type Error = ExtraParamsParseError;
}
Expand Down Expand Up @@ -88,6 +98,15 @@ impl<'a> DeserializationState<'a> for WailaExtras {
Ok(ParamKind::Known)
}
"lightning" => Err(ExtraParamsParseError::MultipleParams(key.to_string())),
"b12" if self.b12.is_none() => {
let str =
Cow::try_from(value).map_err(|_| ExtraParamsParseError::InvoiceParsingError)?;
let offer = Offer::from_str(&str)?;
self.b12 = Some(offer);

Ok(ParamKind::Known)
}
"b12" => Err(ExtraParamsParseError::MultipleParams(key.to_string())),
_ => Ok(ParamKind::Unknown),
}
}
Expand All @@ -113,6 +132,8 @@ impl<'a> DeserializationState<'a> for WailaExtras {
#[cfg(test)]
mod test {
use core::str::FromStr;
use lightning::offers::offer::Offer;
use lightning::util::ser::Writeable;
use std::convert::TryFrom;

use lightning_invoice::Bolt11Invoice;
Expand All @@ -129,6 +150,16 @@ mod test {
assert_eq!(uri.extras.lightning, Some(expected_invoice));
}

#[test]
fn test_offer_uri() {
let input = "bitcoin:BC1QYLH3U67J673H6Y6ALV70M0PL2YZ53TZHVXGG7U?amount=0.00001&label=sbddesign%3A%20For%20lunch%20Tuesday&message=For%20lunch%20Tuesday&b12=lno1qsgqmqvgm96frzdg8m0gc6nzeqffvzsqzrxqy32afmr3jn9ggkwg3egfwch2hy0l6jut6vfd8vpsc3h89l6u3dm4q2d6nuamav3w27xvdmv3lpgklhg7l5teypqz9l53hj7zvuaenh34xqsz2sa967yzqkylfu9xtcd5ymcmfp32h083e805y7jfd236w9afhavqqvl8uyma7x77yun4ehe9pnhu2gekjguexmxpqjcr2j822xr7q34p078gzslf9wpwz5y57alxu99s0z2ql0kfqvwhzycqq45ehh58xnfpuek80hw6spvwrvttjrrq9pphh0dpydh06qqspp5uq4gpyt6n9mwexde44qv7lstzzq60nr40ff38u27un6y53aypmx0p4qruk2tf9mjwqlhxak4znvna5y";
let offer = Offer::from_str("lno1qsgqmqvgm96frzdg8m0gc6nzeqffvzsqzrxqy32afmr3jn9ggkwg3egfwch2hy0l6jut6vfd8vpsc3h89l6u3dm4q2d6nuamav3w27xvdmv3lpgklhg7l5teypqz9l53hj7zvuaenh34xqsz2sa967yzqkylfu9xtcd5ymcmfp32h083e805y7jfd236w9afhavqqvl8uyma7x77yun4ehe9pnhu2gekjguexmxpqjcr2j822xr7q34p078gzslf9wpwz5y57alxu99s0z2ql0kfqvwhzycqq45ehh58xnfpuek80hw6spvwrvttjrrq9pphh0dpydh06qqspp5uq4gpyt6n9mwexde44qv7lstzzq60nr40ff38u27un6y53aypmx0p4qruk2tf9mjwqlhxak4znvna5y").unwrap();

let uri = UnifiedUri::from_str(input).unwrap();
assert!(uri.extras.lightning.is_none());
assert_eq!(uri.extras.b12.map(|i| i.encode()), Some(offer.encode()));
}

#[test]
fn test_no_ln_uri() {
let input = "bitcoin:1andreas3batLhQa2FawWjeyjCqyBzypd";
Expand Down
2 changes: 1 addition & 1 deletion waila/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -192,7 +192,7 @@ impl PaymentParams<'_> {
pub fn offer(&self) -> Option<Offer> {
match self {
PaymentParams::OnChain(_) => None,
PaymentParams::Bip21(_) => None,
PaymentParams::Bip21(uri) => uri.extras.b12.clone(),
PaymentParams::Bolt11(_) => None,
PaymentParams::Bolt12(offer) => Some(offer.clone()),
PaymentParams::Bolt12Refund(_) => None,
Expand Down

0 comments on commit c576d20

Please sign in to comment.