Skip to content

Commit 2aecd58

Browse files
committed
Replace parts of the QR-code scanning with bitcoin-payment-instructions from rust-bitcoin
1 parent 387cc2d commit 2aecd58

File tree

2 files changed

+79
-42
lines changed

2 files changed

+79
-42
lines changed

Cargo.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,8 @@ log = { version = "0.4.22", default-features = false, features = ["std"]}
8787
vss-client = "0.3"
8888
prost = { version = "0.11.6", default-features = false}
8989

90+
bitcoin-payment-instructions = { version = "0.4.0" }
91+
9092
[target.'cfg(windows)'.dependencies]
9193
winapi = { version = "0.3", features = ["winbase"] }
9294

src/payment/unified_qr.rs

Lines changed: 77 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ use crate::logger::{log_error, LdkLogger, Logger};
1616
use crate::payment::{bolt11::maybe_wrap_invoice, Bolt11Payment, Bolt12Payment, OnchainPayment};
1717
use crate::Config;
1818

19+
use bitcoin::script::Instruction;
1920
use lightning::ln::channelmanager::PaymentId;
2021
use lightning::offers::offer::Offer;
2122
use lightning_invoice::{Bolt11Invoice, Bolt11InvoiceDescription, Description};
@@ -28,6 +29,9 @@ use bitcoin::{Amount, Txid};
2829
use std::sync::Arc;
2930
use std::vec::IntoIter;
3031

32+
use bitcoin_payment_instructions::hrn_resolution::DummyHrnResolver;
33+
use bitcoin_payment_instructions::{PaymentInstructions, PaymentMethod};
34+
3135
type Uri<'a> = bip21::Uri<'a, NetworkChecked, Extras>;
3236

3337
#[derive(Debug, Clone)]
@@ -90,14 +94,14 @@ impl UnifiedQrPayment {
9094

9195
let amount_msats = amount_sats * 1_000;
9296

93-
let bolt12_offer = match self.bolt12_payment.receive(amount_msats, description, None, None)
94-
{
95-
Ok(offer) => Some(offer),
96-
Err(e) => {
97-
log_error!(self.logger, "Failed to create offer: {}", e);
98-
return Err(Error::OfferCreationFailed);
99-
},
100-
};
97+
// let bolt12_offer = match self.bolt12_payment.receive(amount_msats, description, None, None)
98+
// {
99+
// Ok(offer) => Some(offer),
100+
// Err(e) => {
101+
// log_error!(self.logger, "Failed to create offer: {}", e);
102+
// return Err(Error::OfferCreationFailed);
103+
// },
104+
// };
101105

102106
let invoice_description = Bolt11InvoiceDescription::Direct(
103107
Description::new(description.to_string()).map_err(|_| Error::InvoiceCreationFailed)?,
@@ -115,7 +119,7 @@ impl UnifiedQrPayment {
115119
},
116120
};
117121

118-
let extras = Extras { bolt11_invoice, bolt12_offer };
122+
let extras = Extras { bolt11_invoice, bolt12_offer: None };
119123

120124
let mut uri = Uri::with_extras(onchain_address, extras);
121125
uri.amount = Some(Amount::from_sat(amount_sats));
@@ -135,42 +139,73 @@ impl UnifiedQrPayment {
135139
///
136140
/// [BIP 21]: https://github.com/bitcoin/bips/blob/master/bip-0021.mediawiki
137141
pub fn send(&self, uri_str: &str) -> Result<QrPaymentResult, Error> {
138-
let uri: bip21::Uri<NetworkUnchecked, Extras> =
139-
uri_str.parse().map_err(|_| Error::InvalidUri)?;
140-
141-
let uri_network_checked =
142-
uri.clone().require_network(self.config.network).map_err(|_| Error::InvalidNetwork)?;
143-
144-
if let Some(offer) = uri_network_checked.extras.bolt12_offer {
145-
match self.bolt12_payment.send(&offer, None, None) {
146-
Ok(payment_id) => return Ok(QrPaymentResult::Bolt12 { payment_id }),
147-
Err(e) => log_error!(self.logger, "Failed to send BOLT12 offer: {:?}. This is part of a unified QR code payment. Falling back to the BOLT11 invoice.", e),
148-
}
149-
}
150-
151-
if let Some(invoice) = uri_network_checked.extras.bolt11_invoice {
152-
let invoice = maybe_wrap_invoice(invoice);
153-
match self.bolt11_invoice.send(&invoice, None) {
154-
Ok(payment_id) => return Ok(QrPaymentResult::Bolt11 { payment_id }),
155-
Err(e) => log_error!(self.logger, "Failed to send BOLT11 invoice: {:?}. This is part of a unified QR code payment. Falling back to the on-chain transaction.", e),
156-
}
157-
}
158-
159-
let amount = match uri_network_checked.amount {
160-
Some(amount) => amount,
161-
None => {
162-
log_error!(self.logger, "No amount specified in the URI. Aborting the payment.");
142+
let rt = tokio::runtime::Runtime::new().map_err(|e| {
143+
log_error!(self.logger, "Failed to create Tokio runtime: {}", e);
144+
Error::InvalidInvoice
145+
})?;
146+
147+
let instructions = rt
148+
.block_on(PaymentInstructions::parse(
149+
uri_str,
150+
self.config.network,
151+
&DummyHrnResolver,
152+
false,
153+
))
154+
.map_err(|e| {
155+
log_error!(self.logger, "Failed to parse payment instructions: {:?}", e);
156+
Error::InvalidUri
157+
})?;
158+
159+
match instructions {
160+
PaymentInstructions::ConfigurableAmount(_) => {
161+
log_error!(
162+
self.logger,
163+
"Configurable amount payments not supported in this version"
164+
);
165+
return Err(Error::InvalidUri);
163166
return Err(Error::InvalidAmount);
164167
},
165-
};
166-
167-
let txid = self.onchain_payment.send_to_address(
168-
&uri_network_checked.address,
169-
amount.to_sat(),
170-
None,
171-
)?;
168+
PaymentInstructions::FixedAmount(instructions) => {
169+
for method in instructions.methods() {
170+
match method {
171+
PaymentMethod::LightningBolt12(offer) => {
172+
match self.bolt12_payment.send(&offer, None, None) {
173+
Ok(payment_id) => return Ok(QrPaymentResult::Bolt12 { payment_id }),
174+
Err(e) => log_error!(self.logger, "Failed to send BOLT12 offer: {:?}. This is part of a unified QR code payment. Falling back to the BOLT11 invoice.", e),
175+
}
176+
},
177+
PaymentMethod::LightningBolt11(invoice) => {
178+
match self.bolt11_invoice.send(&invoice, None) {
179+
Ok(payment_id) => return Ok(QrPaymentResult::Bolt11 { payment_id }),
180+
Err(e) => log_error!(self.logger, "Failed to send BOLT11 invoice: {:?}. This is part of a unified QR code payment. Falling back to the on-chain transaction.", e),
181+
}
182+
},
183+
PaymentMethod::OnChain(address) => {
184+
let amount = match instructions.onchain_payment_amount() {
185+
Some(amount) => amount,
186+
None => {
187+
log_error!(
188+
self.logger,
189+
"No amount specified in the URI. Aborting the payment."
190+
);
191+
return Err(Error::InvalidAmount);
192+
},
193+
};
194+
195+
let txid = self.onchain_payment.send_to_address(
196+
&address,
197+
amount.sats().unwrap(),
198+
None,
199+
)?;
200+
return Ok(QrPaymentResult::Onchain { txid });
201+
},
202+
}
203+
}
204+
},
205+
}
172206

173-
Ok(QrPaymentResult::Onchain { txid })
207+
log_error!(self.logger, "No valid payment method found in the URI.");
208+
Err(Error::InvalidUri)
174209
}
175210
}
176211

0 commit comments

Comments
 (0)