Skip to content

Commit

Permalink
sdk-common: Expose if BIP353 is used for parsing (#1164)
Browse files Browse the repository at this point in the history
* sdk-common: Expose if BIP353 is used for parsing

* Clarify bip353_address field documentation
  • Loading branch information
danielgranhao authored Feb 7, 2025
1 parent 7a96ce7 commit 84578d9
Show file tree
Hide file tree
Showing 10 changed files with 137 additions and 67 deletions.
2 changes: 1 addition & 1 deletion libs/sdk-bindings/src/breez_sdk.udl
Original file line number Diff line number Diff line change
Expand Up @@ -744,7 +744,7 @@ interface InputType {
Bolt11(LNInvoice invoice);
NodeId(string node_id);
Url(string url);
LnUrlPay(LnUrlPayRequestData data);
LnUrlPay(LnUrlPayRequestData data, string? bip353_address);
LnUrlWithdraw(LnUrlWithdrawRequestData data);
LnUrlAuth(LnUrlAuthRequestData data);
LnUrlError(LnUrlErrorData data);
Expand Down
63 changes: 45 additions & 18 deletions libs/sdk-common/src/input_parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use std::ops::Not;
use std::str::FromStr;

use ::bip21::Uri;
use anyhow::{anyhow, Context, Result};
use anyhow::{anyhow, bail, Context, Result};
use bitcoin::bech32;
use bitcoin::bech32::FromBase32;
use hickory_resolver::config::{ResolverConfig, ResolverOpts};
Expand Down Expand Up @@ -117,11 +117,11 @@ lazy_static! {
/// async fn main() -> Result<()> {
/// let lnurl_pay_url = "lnurl1dp68gurn8ghj7mr0vdskc6r0wd6z7mrww4excttsv9un7um9wdekjmmw84jxywf5x43rvv35xgmr2enrxanr2cfcvsmnwe3jxcukvde48qukgdec89snwde3vfjxvepjxpjnjvtpxd3kvdnxx5crxwpjvyunsephsz36jf";
///
/// assert!(matches!( parse(lnurl_pay_url, None).await, Ok(LnUrlPay{data: _}) ));
/// assert!(matches!( parse(lnurl_pay_url, None).await, Ok(LnUrlPay{data: _, bip353_address: _}) ));
/// // assert!(matches!( parse("lnurlp://domain.com/lnurl-pay?key=val").await, Ok(LnUrlPay{data: _}) ));
/// // assert!(matches!( parse("[email protected]").await, Ok(LnUrlPay{data: _}) ));
///
/// if let Ok(LnUrlPay{data: pd}) = parse(lnurl_pay_url,None).await {
/// if let Ok(LnUrlPay{data: pd, bip353_address}) = parse(lnurl_pay_url,None).await {
/// assert_eq!(pd.callback, "https://localhost/lnurl-pay/callback/db945b624265fc7f5a8d77f269f7589d789a771bdfd20e91a3cf6f50382a98d7");
/// assert_eq!(pd.max_sendable, 16000); // Max sendable amount, in msats
/// assert_eq!(pd.max_sendable_sats(), 16); // Max sendable amount, in sats
Expand Down Expand Up @@ -206,14 +206,29 @@ pub async fn parse(
let input = input.trim();

// Try to parse the destination as a bip353 address.
let input_parsed = match bip353_parse(input, &DNS_RESOLVER).await {
Some(value) => value,
None => input.to_string(),
let (bip353_parsed_input, is_bip353) = match bip353_parse(input, &DNS_RESOLVER).await {
Some(value) => (value, true),
None => (input.to_string(), false),
};

let input = input_parsed.as_str();
if let Ok(input_type) = parse_core(&bip353_parsed_input).await {
let input_type = if is_bip353 {
match input_type {
#[cfg(feature = "liquid")]
InputType::Bolt12Offer { offer, .. } => InputType::Bolt12Offer {
offer,
bip353_address: Some(input.to_string()),
},
InputType::LnUrlPay { data, .. } => InputType::LnUrlPay {
data,
bip353_address: Some(input.to_string()),
},
i => bail!("Unexpected input type was resolved from a BIP353 address: {i:?}"),
}
} else {
input_type
};

if let Ok(input_type) = parse_core(input).await {
return Ok(input_type);
}

Expand Down Expand Up @@ -325,7 +340,10 @@ async fn parse_core(input: &str) -> Result<InputType> {

#[cfg(feature = "liquid")]
if let Ok(offer) = parse_bolt12_offer(input) {
return Ok(InputType::Bolt12Offer { offer });
return Ok(InputType::Bolt12Offer {
offer,
bip353_address: None,
});
}

if let Ok(invoice) = parse_invoice(input) {
Expand Down Expand Up @@ -412,8 +430,9 @@ async fn parse_external(
let input_type = lnurl_data.into();
let input_type = match input_type {
// Modify the LnUrlPay payload by adding the domain of the LNURL endpoint
InputType::LnUrlPay { data } => InputType::LnUrlPay {
InputType::LnUrlPay { data, .. } => InputType::LnUrlPay {
data: LnUrlPayRequestData { domain, ..data },
bip353_address: None,
},
_ => input_type,
};
Expand Down Expand Up @@ -588,12 +607,13 @@ async fn resolve_lnurl(
let temp = lnurl_data.into();
let temp = match temp {
// Modify the LnUrlPay payload by adding the domain of the LNURL endpoint
InputType::LnUrlPay { data } => InputType::LnUrlPay {
InputType::LnUrlPay { data, .. } => InputType::LnUrlPay {
data: LnUrlPayRequestData {
domain,
ln_address,
..data
},
bip353_address: None,
},
_ => temp,
};
Expand Down Expand Up @@ -628,6 +648,8 @@ pub enum InputType {
#[cfg(feature = "liquid")]
Bolt12Offer {
offer: LNOffer,
/// The BIP353 address from which this InputType was resolved
bip353_address: Option<String>,
},
NodeId {
node_id: String,
Expand All @@ -644,6 +666,8 @@ pub enum InputType {
/// - LUD-17 Support for lnurlp prefix with non-bech32-encoded LNURL URLs
LnUrlPay {
data: LnUrlPayRequestData,
/// The BIP353 address from which this InputType was resolved
bip353_address: Option<String>,
},

/// # Supported standards
Expand Down Expand Up @@ -705,7 +729,10 @@ pub enum LnUrlRequestData {
impl From<LnUrlRequestData> for InputType {
fn from(lnurl_data: LnUrlRequestData) -> Self {
match lnurl_data {
PayRequest { data } => Self::LnUrlPay { data },
PayRequest { data } => Self::LnUrlPay {
data,
bip353_address: None,
},
WithdrawRequest { data } => Self::LnUrlWithdraw { data },
AuthRequest { data } => Self::LnUrlAuth { data },
Error { data } => Self::LnUrlError { data },
Expand Down Expand Up @@ -1568,7 +1595,7 @@ pub(crate) mod tests {
("localhost".into(), format!("https://localhost{path}"), None)
);

if let InputType::LnUrlPay { data: pd } = parse(lnurl_pay_encoded, None).await? {
if let InputType::LnUrlPay { data: pd, .. } = parse(lnurl_pay_encoded, None).await? {
assert_eq!(pd.callback, "https://localhost/lnurl-pay/callback/db945b624265fc7f5a8d77f269f7589d789a771bdfd20e91a3cf6f50382a98d7");
assert_eq!(pd.max_sendable, 16000);
assert_eq!(pd.min_sendable, 4000);
Expand Down Expand Up @@ -1608,7 +1635,7 @@ pub(crate) mod tests {
] {
assert!(matches!(
parse(lnurl_pay, None).await?,
InputType::LnUrlPay { data: _ }
InputType::LnUrlPay { .. }
));
}
Ok(())
Expand All @@ -1622,7 +1649,7 @@ pub(crate) mod tests {
let ln_address = "[email protected]";
let _m = mock_lnurl_ln_address_endpoint(ln_address, None)?;

if let InputType::LnUrlPay { data: pd } = parse(ln_address, None).await? {
if let InputType::LnUrlPay { data: pd, .. } = parse(ln_address, None).await? {
assert_eq!(pd.callback, "https://localhost/lnurl-pay/callback/db945b624265fc7f5a8d77f269f7589d789a771bdfd20e91a3cf6f50382a98d7");
assert_eq!(pd.max_sendable, 16000);
assert_eq!(pd.min_sendable, 4000);
Expand Down Expand Up @@ -1665,7 +1692,7 @@ pub(crate) mod tests {
let server_ln_address = "[email protected]";
let _m = mock_lnurl_ln_address_endpoint(server_ln_address, None)?;

if let InputType::LnUrlPay { data: pd } = parse(ln_address, None).await? {
if let InputType::LnUrlPay { data: pd, .. } = parse(ln_address, None).await? {
assert_eq!(pd.callback, "https://localhost/lnurl-pay/callback/db945b624265fc7f5a8d77f269f7589d789a771bdfd20e91a3cf6f50382a98d7");
assert_eq!(pd.max_sendable, 16000);
assert_eq!(pd.min_sendable, 4000);
Expand Down Expand Up @@ -1871,7 +1898,7 @@ pub(crate) mod tests {
let _m = mock_lnurl_pay_endpoint(pay_path, None);

let lnurl_pay_url = format!("lnurlp://localhost{pay_path}");
if let InputType::LnUrlPay { data: pd } = parse(&lnurl_pay_url, None).await? {
if let InputType::LnUrlPay { data: pd, .. } = parse(&lnurl_pay_url, None).await? {
assert_eq!(pd.callback, "https://localhost/lnurl-pay/callback/db945b624265fc7f5a8d77f269f7589d789a771bdfd20e91a3cf6f50382a98d7");
assert_eq!(pd.max_sendable, 16000);
assert_eq!(pd.min_sendable, 4000);
Expand Down Expand Up @@ -2007,7 +2034,7 @@ pub(crate) mod tests {
}];

let input_type = parse(input, Some(&parsers)).await?;
if let InputType::LnUrlPay { data } = input_type {
if let InputType::LnUrlPay { data, .. } = input_type {
assert_eq!(data.callback, "callback_url");
assert_eq!(data.max_sendable, 57000);
assert_eq!(data.min_sendable, 57000);
Expand Down
33 changes: 25 additions & 8 deletions libs/sdk-core/src/binding.rs
Original file line number Diff line number Diff line change
Expand Up @@ -160,14 +160,31 @@ pub struct _LnUrlWithdrawRequestData {

#[frb(mirror(InputType))]
pub enum _InputType {
BitcoinAddress { address: BitcoinAddressData },
Bolt11 { invoice: LNInvoice },
NodeId { node_id: String },
Url { url: String },
LnUrlPay { data: LnUrlPayRequestData },
LnUrlWithdraw { data: LnUrlWithdrawRequestData },
LnUrlAuth { data: LnUrlAuthRequestData },
LnUrlError { data: LnUrlErrorData },
BitcoinAddress {
address: BitcoinAddressData,
},
Bolt11 {
invoice: LNInvoice,
},
NodeId {
node_id: String,
},
Url {
url: String,
},
LnUrlPay {
data: LnUrlPayRequestData,
bip353_address: Option<String>,
},
LnUrlWithdraw {
data: LnUrlWithdrawRequestData,
},
LnUrlAuth {
data: LnUrlAuthRequestData,
},
LnUrlError {
data: LnUrlErrorData,
},
}

#[frb(mirror(BitcoinAddressData))]
Expand Down
15 changes: 13 additions & 2 deletions libs/sdk-core/src/bridge_generated.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1009,8 +1009,12 @@ const _: fn() = || {
InputType::Url { url } => {
let _: String = url;
}
InputType::LnUrlPay { data } => {
InputType::LnUrlPay {
data,
bip353_address,
} => {
let _: LnUrlPayRequestData = data;
let _: Option<String> = bip353_address;
}
InputType::LnUrlWithdraw { data } => {
let _: LnUrlWithdrawRequestData = data;
Expand Down Expand Up @@ -1608,7 +1612,14 @@ impl support::IntoDart for mirror_InputType {
vec![2.into_dart(), node_id.into_into_dart().into_dart()]
}
InputType::Url { url } => vec![3.into_dart(), url.into_into_dart().into_dart()],
InputType::LnUrlPay { data } => vec![4.into_dart(), data.into_into_dart().into_dart()],
InputType::LnUrlPay {
data,
bip353_address,
} => vec![
4.into_dart(),
data.into_into_dart().into_dart(),
bip353_address.into_dart(),
],
InputType::LnUrlWithdraw { data } => {
vec![5.into_dart(), data.into_into_dart().into_dart()]
}
Expand Down
2 changes: 2 additions & 0 deletions libs/sdk-flutter/lib/bridge_generated.dart
Original file line number Diff line number Diff line change
Expand Up @@ -668,6 +668,7 @@ sealed class InputType with _$InputType {
}) = InputType_Url;
const factory InputType.lnUrlPay({
required LnUrlPayRequestData data,
String? bip353Address,
}) = InputType_LnUrlPay;
const factory InputType.lnUrlWithdraw({
required LnUrlWithdrawRequestData data,
Expand Down Expand Up @@ -3378,6 +3379,7 @@ class BreezSdkCoreImpl implements BreezSdkCore {
case 4:
return InputType_LnUrlPay(
data: _wire2api_box_autoadd_ln_url_pay_request_data(raw[1]),
bip353Address: _wire2api_opt_String(raw[2]),
);
case 5:
return InputType_LnUrlWithdraw(
Expand Down
Loading

0 comments on commit 84578d9

Please sign in to comment.