Skip to content

Commit

Permalink
Merge pull request #75 from claddyy/lnurl
Browse files Browse the repository at this point in the history
Add support for LnUrl
  • Loading branch information
i5hi authored Oct 3, 2024
2 parents f1c232c + c59b8f7 commit b0c1f84
Show file tree
Hide file tree
Showing 3 changed files with 84 additions and 2 deletions.
4 changes: 2 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ panic = "abort"
[dependencies]
serde = { version = "1.0.0", features = ["derive"] }
serde_json = "1.0.0"
ureq = { version = "2.9.7", features = ["json", "native-tls"] }
ureq = { version = "2.5.0", features = ["json", "native-tls", "socks"] }
bip39 = "2.0.0"
electrum-client = "0.19.0"
bitcoin = {version = "0.31.2", features = ["rand", "base64", "rand-std"]}
Expand All @@ -34,7 +34,7 @@ log = "^0.4"
env_logger = "0.7"
native-tls = "0.2.11"
hex = "0.4"

lnurl-rs = "0.8.0"
[patch.crates-io]
secp256k1-zkp = {git = "https://github.com/BlockstreamResearch/rust-secp256k1-zkp.git", rev = "60e631c24588a0c9e271badd61959294848c665d"}

Expand Down
81 changes: 81 additions & 0 deletions src/util/lnurl.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
use crate::error::Error;
use lightning_invoice::Bolt11Invoice;
use lnurl::lightning_address::LightningAddress;
use lnurl::{lnurl::LnUrl, Builder, LnUrlResponse};
use std::str::FromStr;

pub fn fetch_invoice(address: &str, amount_msats: u64) -> Result<String, Error> {
let lnurl = match LnUrl::from_str(address) {
Ok(lnurl) => lnurl,
Err(_) => match LightningAddress::from_str(address) {
Ok(lightning_address) => lightning_address.lnurl(),
Err(_) => {
return Err(Error::Generic(
"Not a valude LnUrl or LnAddress".to_string(),
))
}
},
};

let client = Builder::default()
.build_blocking()
.map_err(|e| Error::Generic(e.to_string()))?;
let res = client
.make_request(&lnurl.url.to_lowercase())
.map_err(|e| Error::HTTP(e.to_string()))?;

match res {
LnUrlResponse::LnUrlPayResponse(pay) => {
let pay_result = client
.get_invoice(&pay, amount_msats, None, None)
.map_err(|e| Error::HTTP(e.to_string()))?;
let invoice =
Bolt11Invoice::from_str(pay_result.invoice()).map_err(|e| Error::Bolt11(e))?;

if invoice.amount_milli_satoshis() != Some(amount_msats) {
return Err(Error::Generic(
"Invoice amount doesn't match requested amount".to_string(),
));
}

Ok(pay_result.invoice().to_string())
}
_ => Err(Error::Generic("Unexpected response type".to_string())),
}
}

#[cfg(test)]
mod tests {
use super::*;

fn test_address(address: &str, amount_msats: u64, format: &str) {
let result = fetch_invoice(address, amount_msats);

match result {
Ok(invoice) => {
assert!(!invoice.is_empty(), "Invoice should not be empty");
assert!(
invoice.starts_with("lnbc"),
"Invoice should start with 'lnbc'"
);
println!("Successfully fetched invoice, format : {}", format)
}
Err(e) => {
println!("Error occured with {} format: {}", format, e.message());
}
}
}

#[test]
fn test_fetch_invoice() {
let amount_msats = 100000;
let lnurl = "lnurl1dp68gurn8ghj7um9wfmxjcm99e3k7mf0v9cxj0m385ekvcenxc6r2c35xvukxefcv5mkvv34x5ekzd3ev56nyd3hxqurzepexejxxepnxscrvwfnv9nxzcn9xq6xyefhvgcxxcmyxymnserxfq5fns";
let uppercase_lnurl = lnurl.to_uppercase();

test_address(lnurl, amount_msats, "LNURL");
test_address(&uppercase_lnurl, amount_msats, "LNURL");

let email_lnurl = "[email protected]";
test_address(email_lnurl, amount_msats, "Lightning Address");
}
}
1 change: 1 addition & 0 deletions src/util/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ use lightning_invoice::{Bolt11Invoice, RouteHintHop};
use crate::{error::Error, network::electrum::ElectrumConfig};

pub mod ec;
mod lnurl;
pub mod secrets;

/// Setup function that will only run once, even if called multiple times.
Expand Down

0 comments on commit b0c1f84

Please sign in to comment.