Skip to content

Commit 4a02cc7

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

File tree

2 files changed

+70
-35
lines changed

2 files changed

+70
-35
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: 68 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,9 @@ use bitcoin::{Amount, Txid};
2828
use std::sync::Arc;
2929
use std::vec::IntoIter;
3030

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

3336
#[derive(Debug, Clone)]
@@ -135,42 +138,72 @@ impl UnifiedQrPayment {
135138
///
136139
/// [BIP 21]: https://github.com/bitcoin/bips/blob/master/bip-0021.mediawiki
137140
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.");
163-
return Err(Error::InvalidAmount);
141+
let rt = tokio::runtime::Runtime::new().map_err(|e| {
142+
log_error!(self.logger, "Failed to create Tokio runtime: {}", e);
143+
Error::InvalidInvoice
144+
})?;
145+
146+
let instructions = rt
147+
.block_on(PaymentInstructions::parse(
148+
uri_str,
149+
self.config.network,
150+
&DummyHrnResolver,
151+
false,
152+
))
153+
.map_err(|e| {
154+
log_error!(self.logger, "Failed to parse payment instructions: {:?}", e);
155+
Error::InvalidUri
156+
})?;
157+
158+
match instructions {
159+
PaymentInstructions::ConfigurableAmount(_) => {
160+
log_error!(
161+
self.logger,
162+
"Configurable amount payments not supported in this version"
163+
);
164+
return Err(Error::InvalidUri);
164165
},
165-
};
166-
167-
let txid = self.onchain_payment.send_to_address(
168-
&uri_network_checked.address,
169-
amount.to_sat(),
170-
None,
171-
)?;
172-
173-
Ok(QrPaymentResult::Onchain { txid })
166+
PaymentInstructions::FixedAmount(instructions) => {
167+
for method in instructions.methods() {
168+
match method {
169+
PaymentMethod::LightningBolt12(offer) => {
170+
match self.bolt12_payment.send(&offer, None, None) {
171+
Ok(payment_id) => return Ok(QrPaymentResult::Bolt12 { payment_id }),
172+
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),
173+
}
174+
},
175+
PaymentMethod::LightningBolt11(invoice) => {
176+
match self.bolt11_invoice.send(&invoice, None) {
177+
Ok(payment_id) => return Ok(QrPaymentResult::Bolt11 { payment_id }),
178+
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),
179+
}
180+
},
181+
PaymentMethod::OnChain(address) => {
182+
let amount = match instructions.onchain_payment_amount() {
183+
Some(amount) => amount,
184+
None => {
185+
log_error!(
186+
self.logger,
187+
"No amount specified in the URI. Aborting the payment."
188+
);
189+
return Err(Error::InvalidAmount);
190+
},
191+
};
192+
193+
let txid = self.onchain_payment.send_to_address(
194+
&address,
195+
amount.sats().unwrap(),
196+
None,
197+
)?;
198+
return Ok(QrPaymentResult::Onchain { txid });
199+
},
200+
}
201+
}
202+
203+
log_error!(self.logger, "No payable methods found in URI");
204+
Err(Error::InvalidUri)
205+
},
206+
}
174207
}
175208
}
176209

0 commit comments

Comments
 (0)