getAlby / getAlby/hub

BOLT-12: support payer proofs for offer payments

Open
#2,569 0 comments 0 reactions 0 assignees View on GitHub
Dominant language
TypeScript
Stars
280
Forks
132
Avg merge
4d 15h
Merged PRs (30d)
11

Description

## 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.

Contributor guide

No contributing guide indexed for this repository

Research direction

Start by checking lnclient/ldk/ldk.go and the pinned ldk-node Go bindings for Bolt12Invoice and CreatePayerProof support. Then trace PayOfferSync, transactions.PayOfferSync, nip47/controllers/pay_controller.go, and frontend/src/components/TransactionItem.tsx. Done means payer_proof is created for regular BOLT-12 offer payments, stored in metadata, and returned by NWC-321; implementation is blocked until the fork and bindings are updated.

Written by the indexing model from the issue text.

Assessment

Tech stack
go, typescript
Domain
api, backend, frontend, payments
Issue type
Feature
Difficulty
4/5
Estimated time
3-5 days
Activity status
Active
Clarity
Clearly specified
Newbie friendliness
42/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.