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)] async fn pay_lightning_invoice_argument() {
127 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}