Skip to content

Commit

Permalink
Add payjoin support
Browse files Browse the repository at this point in the history
  • Loading branch information
benthecarman committed Sep 25, 2023
1 parent 6b11497 commit f05bf81
Show file tree
Hide file tree
Showing 4 changed files with 95 additions and 21 deletions.
10 changes: 10 additions & 0 deletions waila-wasm/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -85,4 +85,14 @@ impl PaymentParams {
.nostr_pubkey()
.and_then(|key| key.to_bech32().ok())
}

#[wasm_bindgen(getter)]
pub fn payjoin_endpoint(&self) -> Option<String> {
self.params.payjoin_endpoint().map(|n| n.to_string())
}

#[wasm_bindgen(getter)]
pub fn disable_output_substitution(&self) -> Option<bool> {
self.params.disable_output_substitution()
}
}
4 changes: 3 additions & 1 deletion waila/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,13 @@ lightning-invoice = { version = "0.24.0", default-features = false }
lightning = { version = "0.0.116", default-features = false }
rgb-std = { version = "0.10.4", optional = true }
rgb-wallet = { version = "0.10.4", optional = true }
url = { version = "2.4.1", optional = true }

[features]
default = ["std"]
default = ["std", "payjoin"]
std = ["bitcoin/std", "lightning-invoice/std", "lightning/std"]
no-std = ["bitcoin/no-std", "lightning-invoice/no-std", "lightning/no-std"]
payjoin = ["url"]
rgb = ["rgb-std", "rgb-wallet"]

[package.metadata.wasm-pack.profile.release]
Expand Down
84 changes: 64 additions & 20 deletions waila/src/bip21.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,40 +5,54 @@ use std::convert::TryFrom;
use ::bip21::de::*;
use ::bip21::*;
use lightning_invoice::{Bolt11Invoice, ParseOrSemanticError};
use url::Url;

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

#[derive(Debug, Default, Eq, PartialEq, Clone, Hash)]
pub struct LightningExtras {
pub struct WailaExtras {
pub lightning: Option<Bolt11Invoice>,
pub pj: Option<Url>,
pjos: Option<bool>,
}

#[derive(Debug, Eq, PartialEq, Clone, Hash)]
pub enum LightningParseError {
MultipleParams,
impl WailaExtras {
pub fn disable_output_substitution(&self) -> bool {
self.pjos.unwrap_or(false)
}
}

#[derive(Debug, Eq, PartialEq, Clone)]
pub enum ExtraParamsParseError {
MultipleParams(String),
InvoiceParsingError,
MissingEndpoint,
NotUtf8(core::str::Utf8Error),
BadEndpoint(url::ParseError),
UnsecureEndpoint,
BadPjOs,
}

impl From<ParseOrSemanticError> for LightningParseError {
impl From<ParseOrSemanticError> for ExtraParamsParseError {
fn from(_e: ParseOrSemanticError) -> Self {
LightningParseError::InvoiceParsingError
ExtraParamsParseError::InvoiceParsingError
}
}

impl DeserializationError for LightningExtras {
type Error = LightningParseError;
impl DeserializationError for WailaExtras {
type Error = ExtraParamsParseError;
}

impl<'a> DeserializeParams<'a> for LightningExtras {
type DeserializationState = LightningExtras;
impl<'a> DeserializeParams<'a> for WailaExtras {
type DeserializationState = WailaExtras;
}

impl<'a> DeserializationState<'a> for LightningExtras {
type Value = LightningExtras;
impl<'a> DeserializationState<'a> for WailaExtras {
type Value = WailaExtras;

fn is_param_known(&self, param: &str) -> bool {
matches!(param, "lightning")
matches!(param, "lightning" | "pj" | "pjos")
}

fn deserialize_temp(
Expand All @@ -47,21 +61,51 @@ impl<'a> DeserializationState<'a> for LightningExtras {
value: Param<'_>,
) -> Result<ParamKind, <Self::Value as DeserializationError>::Error> {
match key {
"pj" if self.pj.is_none() => {
let endpoint = Cow::try_from(value).map_err(ExtraParamsParseError::NotUtf8)?;
let url = Url::parse(&endpoint).map_err(ExtraParamsParseError::BadEndpoint)?;
self.pj = Some(url);

Ok(ParamKind::Known)
}
"pj" => Err(ExtraParamsParseError::MultipleParams(key.to_string())),
"pjos" if self.pjos.is_none() => {
match &*Cow::try_from(value).map_err(|_| ExtraParamsParseError::BadPjOs)? {
"0" => self.pjos = Some(false),
"1" => self.pjos = Some(true),
_ => return Err(ExtraParamsParseError::BadPjOs),
}
Ok(ParamKind::Known)
}
"pjos" => Err(ExtraParamsParseError::MultipleParams(key.to_string())),
"lightning" if self.lightning.is_none() => {
let str =
Cow::try_from(value).map_err(|_| LightningParseError::InvoiceParsingError)?;
Cow::try_from(value).map_err(|_| ExtraParamsParseError::InvoiceParsingError)?;
let invoice = Bolt11Invoice::from_str(&str)?;
self.lightning = Some(invoice);

Ok(ParamKind::Known)
}
"lightning" => Err(LightningParseError::MultipleParams),
"lightning" => Err(ExtraParamsParseError::MultipleParams(key.to_string())),
_ => Ok(ParamKind::Unknown),
}
}

fn finalize(self) -> Result<Self::Value, <Self::Value as DeserializationError>::Error> {
Ok(self)
match (self.pj.as_ref(), self.pjos) {
(None, None) => Ok(self),
(None, Some(_)) => Err(ExtraParamsParseError::MissingEndpoint),
(Some(endpoint), _) => {
if endpoint.scheme() == "https"
|| endpoint.scheme() == "http"
&& endpoint.domain().unwrap_or_default().ends_with(".onion")
{
Ok(self)
} else {
Err(ExtraParamsParseError::UnsecureEndpoint)
}
}
}
}
}

Expand All @@ -72,9 +116,9 @@ mod test {

use lightning_invoice::Bolt11Invoice;

use crate::bip21::LightningExtras;
use crate::bip21::WailaExtras;

type UnifiedUri<'a> = bip21::Uri<'a, LightningExtras>;
type UnifiedUri<'a> = bip21::Uri<'a, WailaExtras>;

#[test]
fn test_ln_uri() {
Expand Down
18 changes: 18 additions & 0 deletions waila/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -217,6 +217,24 @@ impl PaymentParams<'_> {
PaymentParams::Rgb(_) => None,
}
}

#[cfg(feature = "payjoin")]
pub fn payjoin_endpoint(&self) -> Option<Url> {
if let PaymentParams::Bip21(uri) = self {
uri.extras.pj.clone()
} else {
None
}
}

#[cfg(feature = "payjoin")]
pub fn disable_output_substitution(&self) -> Option<bool> {
if let PaymentParams::Bip21(uri) = self {
Some(uri.extras.disable_output_substitution())
} else {
None
}
}
}

impl FromStr for PaymentParams<'_> {
Expand Down

0 comments on commit f05bf81

Please sign in to comment.