bark/lightning/
mod.rs

1pub mod pay;
2pub mod receive;
3
4use anyhow::Context;
5use bitcoin::Amount;
6use bitcoin::hex::DisplayHex;
7use lightning_invoice::Bolt11Invoice;
8use lnurllib::LnUrlResponse;
9use lnurllib::lightning_address::LightningAddress;
10use log::info;
11
12use ark::lightning::{Bolt11InvoiceExt, Offer, Preimage};
13use bitcoin_ext::AmountExt;
14
15use crate::Wallet;
16
17pub async fn pay_invoice(
18	invoice: Bolt11Invoice,
19	amount: Option<Amount>,
20	comment: Option<String>,
21	no_sync: bool,
22	wallet: &Wallet,
23) -> anyhow::Result<Preimage> {
24	let amount = invoice.get_final_amount(amount)?;
25	if comment.is_some() {
26		bail!("comment not supported for bolt11 invoice");
27	}
28
29	if !no_sync {
30		info!("Syncing wallet...");
31		wallet.sync().await;
32	}
33	info!("Sending bolt11 payment of {} to invoice {}", amount, invoice);
34	let preimage = wallet.pay_lightning_invoice(invoice, Some(amount)).await?;
35	info!("Payment preimage received: {}", preimage.as_hex());
36
37	Ok(preimage)
38}
39
40pub async fn pay_offer(
41	offer: Offer,
42	amount: Option<Amount>,
43	comment: Option<String>,
44	no_sync: bool,
45	wallet: &Wallet,
46) -> anyhow::Result<Preimage> {
47	if comment.is_some() {
48		bail!("comment not supported for bolt12 offer");
49	}
50
51	if !no_sync {
52		info!("Syncing wallet...");
53		wallet.sync().await;
54	}
55
56	info!("Sending bolt12 payment of {:?} to offer {}", amount, offer);
57	let (invoice, preimage) = wallet.pay_lightning_offer(offer, amount).await?;
58	info!("Paid invoice: {:?}", invoice);
59	info!("Payment preimage received: {}", preimage.as_hex());
60
61	Ok(preimage)
62}
63
64pub async fn pay_lnaddr(
65	lnaddr: LightningAddress,
66	amount: Option<Amount>,
67	comment: Option<String>,
68	no_sync: bool,
69	wallet: &Wallet,
70) -> anyhow::Result<Preimage> {
71	let amount = amount.context("amount missing")?;
72
73	if !no_sync {
74		info!("Syncing wallet...");
75		wallet.sync().await;
76	}
77	info!("Sending {} to lightning address {}", amount, lnaddr);
78	let comment = comment.as_ref().map(|c| c.as_str());
79	let (inv, preimage) = wallet.pay_lightning_address(&lnaddr, amount, comment).await?;
80	info!("Paid invoice {}", inv);
81	info!("Payment preimage received: {}", preimage.as_hex());
82
83	Ok(preimage)
84}
85
86async fn lnurlp_invoice(
87	lnurlp: &str,
88	amount: Amount,
89	comment: Option<&str>,
90) -> anyhow::Result<Bolt11Invoice> {
91	let client = lnurllib::Builder::default().build_async().context("lnurl client error")?;
92	let resp = match client.make_request(lnurlp).await.context("failed to make lnurl request")? {
93		LnUrlResponse::LnUrlPayResponse(v) => v,
94		LnUrlResponse::LnUrlWithdrawResponse(_) => bail!("received lnurl withdraw"),
95		LnUrlResponse::LnUrlChannelResponse(_) => bail!("received lnurl channel"),
96	};
97
98	let invoice = client.get_invoice(&resp, amount.to_msat(), None, comment).await
99		.context("failed to fetch invoice from lnurlpay")?.pr;
100
101	Ok(invoice.parse().with_context(|| format!("received invalid invoice: {}", invoice))?)
102}
103
104async fn lnaddr_invoice(
105	addr: &LightningAddress,
106	amount: Amount,
107	comment: Option<&str>,
108) -> anyhow::Result<Bolt11Invoice> {
109	let lnurl = addr.lnurlp_url();
110	Ok(lnurlp_invoice(&lnurl, amount, comment).await?)
111}
112
113
114#[cfg(test)]
115mod test {
116	use std::str::FromStr;
117	use std::sync::Arc;
118
119	use bitcoin::Network;
120	use ark::lightning::{Bolt12Invoice, Bolt12InvoiceExt, Invoice};
121	use lightning_invoice::Bolt11Invoice;
122
123	use crate::{Config, SqliteClient, Wallet};
124
125	#[allow(unused)] // just exists for compile check
126	async fn pay_lightning_invoice_argument() {
127		//! Check the different possible argument for pay_lightning_invoice
128
129		let db = Arc::new(SqliteClient::open("").unwrap());
130		let w = Wallet::open(
131			&"".parse().unwrap(), db, Config::network_default(Network::Regtest),
132		).await.unwrap();
133
134		let bolt11 = Bolt11Invoice::from_str("").unwrap();
135		w.pay_lightning_invoice(bolt11, None).await.unwrap();
136
137		let bolt12 = Bolt12Invoice::from_str("").unwrap();
138		w.pay_lightning_invoice(bolt12, None).await.unwrap();
139
140		let string = format!("lnbc1..");
141		w.pay_lightning_invoice(string, None).await.unwrap();
142
143		let strr = "lnbc1..";
144		w.pay_lightning_invoice(strr, None).await.unwrap();
145
146		let invoice = Invoice::Bolt11("".parse().unwrap());
147		w.pay_lightning_invoice(invoice, None).await.unwrap();
148	}
149}