Skip to content

Commit 03e065e

Browse files
committed
continue receive flow on offer/invoice creation failure
1 parent 387cc2d commit 03e065e

File tree

2 files changed

+45
-21
lines changed

2 files changed

+45
-21
lines changed

src/payment/unified_qr.rs

Lines changed: 21 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -64,20 +64,33 @@ impl UnifiedQrPayment {
6464
/// Generates a URI with an on-chain address, [BOLT 11] invoice and [BOLT 12] offer.
6565
///
6666
/// The URI allows users to send the payment request allowing the wallet to decide
67-
/// which payment method to use. This enables a fallback mechanism: older wallets
68-
/// can always pay using the provided on-chain address, while newer wallets will
69-
/// typically opt to use the provided BOLT11 invoice or BOLT12 offer.
67+
/// which payment method to use. This enables a fallback mechanism:
68+
/// - Older wallets can always pay using the provided on-chain address
69+
/// - Newer wallets will typically opt to use the provided BOLT11 invoice or BOLT12 offer
70+
///
71+
/// The URI will always include an on-chain address, and will include a BOLT11 invoice and BOLT12 offer
72+
/// when they can be successfully generated. Offer generation may fail in certain conditions while still
73+
/// allowing invoice generation (see examples below).
7074
///
7175
/// # Parameters
7276
/// - `amount_sats`: The amount to be received, specified in satoshis.
7377
/// - `description`: A description or note associated with the payment.
7478
/// This message is visible to the payer and can provide context or details about the payment.
7579
/// - `expiry_sec`: The expiration time for the payment, specified in seconds.
7680
///
81+
/// # Examples
82+
/// ## When BOLT12 offer generation might fail
83+
/// A BOLT12 offer requires:
84+
/// - Sufficiently connected channels for pathfinding
85+
/// - Available liquidity in channels
86+
/// - Valid route hints
87+
/// If these conditions aren't met (e.g., when first setting up a node with no channels),
88+
/// the URI will still be generated but without the BOLT12 offer.
89+
///
7790
/// Returns a payable URI that can be used to request and receive a payment of the amount
78-
/// given. In case of an error, the function returns `Error::WalletOperationFailed`for on-chain
79-
/// address issues, `Error::InvoiceCreationFailed` for BOLT11 invoice issues, or
80-
/// `Error::OfferCreationFailed` for BOLT12 offer issues.
91+
/// given. Failure to generate the on-chain address will result in an error return
92+
/// (`Error::WalletOperationFailed`), while failures in invoice or offer generation will
93+
/// result in those components being omitted from the URI.
8194
///
8295
/// The generated URI can then be given to a QR code library.
8396
///
@@ -95,7 +108,7 @@ impl UnifiedQrPayment {
95108
Ok(offer) => Some(offer),
96109
Err(e) => {
97110
log_error!(self.logger, "Failed to create offer: {}", e);
98-
return Err(Error::OfferCreationFailed);
111+
None
99112
},
100113
};
101114

@@ -111,7 +124,7 @@ impl UnifiedQrPayment {
111124
Ok(invoice) => Some(invoice),
112125
Err(e) => {
113126
log_error!(self.logger, "Failed to create invoice {}", e);
114-
return Err(Error::InvoiceCreationFailed);
127+
None
115128
},
116129
};
117130

tests/integration_tests_rust.rs

Lines changed: 24 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1083,6 +1083,21 @@ fn generate_bip21_uri() {
10831083
let address_a = node_a.onchain_payment().new_address().unwrap();
10841084
let premined_sats = 5_000_000;
10851085

1086+
let expected_amount_sats = 100_000;
1087+
let expiry_sec = 4_000;
1088+
1089+
// Test 1: Verify URI generation (on-chain + BOLT11) works
1090+
// even before any channels are opened. This checks the graceful fallback behavior.
1091+
let initial_uqr_payment = node_b
1092+
.unified_qr_payment()
1093+
.receive(expected_amount_sats, "asdf", expiry_sec)
1094+
.expect("Failed to generate URI");
1095+
println!("Initial URI (no channels): {}", initial_uqr_payment);
1096+
1097+
assert!(initial_uqr_payment.contains("bitcoin:"));
1098+
assert!(initial_uqr_payment.contains("lightning="));
1099+
assert!(!initial_uqr_payment.contains("lno=")); // BOLT12 requires channels
1100+
10861101
premine_and_distribute_funds(
10871102
&bitcoind.client,
10881103
&electrsd.client,
@@ -1100,20 +1115,16 @@ fn generate_bip21_uri() {
11001115
expect_channel_ready_event!(node_a, node_b.node_id());
11011116
expect_channel_ready_event!(node_b, node_a.node_id());
11021117

1103-
let expected_amount_sats = 100_000;
1104-
let expiry_sec = 4_000;
1105-
1106-
let uqr_payment = node_b.unified_qr_payment().receive(expected_amount_sats, "asdf", expiry_sec);
1118+
// Test 2: Verify URI generation (on-chain + BOLT11 + BOLT12) works after channels are established.
1119+
let uqr_payment = node_b
1120+
.unified_qr_payment()
1121+
.receive(expected_amount_sats, "asdf", expiry_sec)
1122+
.expect("Failed to generate URI");
11071123

1108-
match uqr_payment.clone() {
1109-
Ok(ref uri) => {
1110-
println!("Generated URI: {}", uri);
1111-
assert!(uri.contains("bitcoin:"));
1112-
assert!(uri.contains("lightning="));
1113-
assert!(uri.contains("lno="));
1114-
},
1115-
Err(e) => panic!("Failed to generate URI: {:?}", e),
1116-
}
1124+
println!("Generated URI: {}", uqr_payment);
1125+
assert!(uqr_payment.contains("bitcoin:"));
1126+
assert!(uqr_payment.contains("lightning="));
1127+
assert!(uqr_payment.contains("lno="));
11171128
}
11181129

11191130
#[test]

0 commit comments

Comments
 (0)