Skip to content

BOLT-12: support payer proofs for offer payments #2569

Description

@frnandu

Context

NWC-321 (pay method) supports payer_proof in its response (field payer_proof, format lnp1...). BOLT-12 defines a payer proof: a message signed by the payer that commits to the payer id, payment hash, the recipient's offer signing pubkey, and optionally selected invoice fields. Unlike a preimage (which only proves an HTLC was settled), a payer proof lets the payer prove to a third party who paid whom for what (e.g. for refund disputes or receipts).

Related: BOLT-12 offer payments were added in #2543 / feat/bolt12-nwc.

What needs to be done

  1. In lnclient/ldk/ldk.go PayOfferSync, capture the Bolt12Invoice returned in the PaymentSuccessful event (upstream ldk-node exposes it as bolt12_invoice on the event).
  2. Call Bolt12Payment().CreatePayerProof(paymentId, preimage, invoice, options) (upstream API) to obtain the lnp1... payer proof.
  3. Return it from PayOfferSync (extend lnclient.PayOfferResponse with e.g. PayerProof string).
  4. In transactions.PayOfferSync, store the payer proof in the transaction metadata (e.g. metadata.payer_proof).
  5. In nip47/controllers/pay_controller.go (payBolt12), include payer_proof in the NWC-321 pay result per the spec (field already defined in NWC-321).
  6. Consider surfacing it in the transaction list UI (frontend/src/components/TransactionItem.tsx).

Blocking

  • Alby's ldk-node fork (https://github.com/getAlby/ldk-node) and the Go bindings (https://github.com/getAlby/ldk-node-go, currently pinned at v0.0.0-20260805080406-af22e238c194, bindings from 2026-04) predate upstream payer-proof support:
    • EventPaymentSuccessful in the bindings has no Bolt12Invoice field (only PaymentId, PaymentHash, PaymentPreimage, FeePaidMsat).
    • No CreatePayerProof binding exists.
  • Once the fork is synced to an upstream ldk-node release containing create_payer_proof and bindings are regenerated, the steps above can be implemented without further external changes.

Notes

  • Payments settled via a static invoice (async payments) cannot be proven this way (upstream limitation) — only regular BOLT-12 offer payments.
  • Until this lands, the best available proof of payment for a BOLT-12 offer payment is preimage + payment hash + offer ID in transaction metadata.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions