fix(bolt12): hand offers off as bitcoin:?lno= (BIP21), not lightning:

A BOLT12 offer (lno1…) is not a lightning: payload — that scheme is for BOLT11
lnbc… invoices. Per BIP21/BIP321 an offer travels as the lno parameter of a
bitcoin URI (bitcoin:?lno=lno1…), with the on-chain address optional so a
Lightning-only offer stands alone. The bech32 offer value is URL-safe, so no
percent-encoding is needed.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SpgpWLKzgD7vS9Fs4CXTR3
This commit is contained in:
Claude
2026-07-24 19:53:38 +00:00
parent 3a906e8b6b
commit 70d38b205e
@@ -545,9 +545,12 @@ fun payViaIntent(
/**
* Hands a reusable BOLT12 offer (`lno1…`, from a recipient's kind:10058) off to an
* installed wallet via the `lightning:` scheme — the same handoff [payViaIntent] uses
* for a BOLT11 invoice. The wallet collects the amount and completes the payment; this
* is a plain intent, not a NIP-57/NIP-XX zap, so it produces no Nostr receipt.
* installed wallet. Unlike a BOLT11 invoice, a BOLT12 offer is NOT a `lightning:`
* payload — that scheme is defined for `lnbc…` invoices. Offers travel as the `lno`
* parameter of a BIP21/BIP321 bitcoin URI (`bitcoin:?lno=lno1…`), where the on-chain
* address is optional so a Lightning-only offer stands on its own. The wallet resolves
* the offer, collects the amount, and completes the payment; this is a plain intent,
* not a NIP-57/NIP-XX zap, so it produces no Nostr receipt.
*/
fun payViaBolt12Intent(
offer: String,
@@ -556,7 +559,7 @@ fun payViaBolt12Intent(
onError: (String) -> Unit,
) {
try {
val intent = Intent(Intent.ACTION_VIEW, "lightning:$offer".toUri())
val intent = Intent(Intent.ACTION_VIEW, "bitcoin:?lno=$offer".toUri())
intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK
context.startActivity(intent)