On-chain ticket sales via native lnbits on-chain (no SatsPay) #41

Open
opened 2026-09-06 17:55:29 +00:00 by padreug · 1 comment
Owner

Upstream v1.6.8 sells tickets on-chain through SatsPay charges (per-purchase watchonly address, amount matching, hosted page, webhook back to /tickets/{id}/satspay-webhook, onchain_zeroconf / onchain_fasttrack per event). We use our own native on-chain port (aiolabs/lnbits#53) and don't want SatsPay.

Blocked on aiolabs/lnbits "purpose-bound receiving addresses": today a deposit is credited to the wallet with no tag, so on_invoice_paid never sees it and nothing links it to a ticket.

Once core can mint a tagged, amount-annotated address per purchase:

  • payment_method: "onchain" in api_ticket_create → create_onchain_address(event.wallet, tag="events", extra={"name","email","ticket_ids"}, amount_sat=price); rows created with payment_hash = <address or txid placeholder>; TicketPaymentRequest.onchain_address / onchain_amount_sat (upstream field names) + a BIP-21 URI.
  • on_invoice_paid matches on extra.tag as today; zero-conf policy = lnbits_onchain_receive_confirmations.
  • Add onchain to extra.payment_methods (#36) and the tickets_payment_methods NIP-52 tag; webapp renders an address QR.

Parity note for the #33 rebase: keep upstream's onchain_enabled/onchain_wallet_id fields out (they are SatsPay/watchonly-specific).

Upstream v1.6.8 sells tickets on-chain through SatsPay charges (per-purchase watchonly address, amount matching, hosted page, webhook back to `/tickets/{id}/satspay-webhook`, `onchain_zeroconf` / `onchain_fasttrack` per event). We use our own native on-chain port (aiolabs/lnbits#53) and don't want SatsPay. Blocked on aiolabs/lnbits "purpose-bound receiving addresses": today a deposit is credited to the wallet with no `tag`, so `on_invoice_paid` never sees it and nothing links it to a ticket. Once core can mint a tagged, amount-annotated address per purchase: - `payment_method: "onchain"` in `api_ticket_create` → `create_onchain_address(event.wallet, tag="events", extra={"name","email","ticket_ids"}, amount_sat=price)`; rows created with `payment_hash = <address or txid placeholder>`; `TicketPaymentRequest.onchain_address` / `onchain_amount_sat` (upstream field names) + a BIP-21 URI. - `on_invoice_paid` matches on `extra.tag` as today; zero-conf policy = `lnbits_onchain_receive_confirmations`. - Add `onchain` to `extra.payment_methods` (#36) and the `tickets_payment_methods` NIP-52 tag; webapp renders an address QR. Parity note for the #33 rebase: keep upstream's `onchain_enabled/onchain_wallet_id` fields out (they are SatsPay/watchonly-specific).
Author
Owner

Funding source for this is LNDRest, and the fork's LndRestWallet already carries the whole on-chain surface this needs — lnbits/wallets/lndrest.py on dev:

41:  Feature.onchain,
425: async def create_onchain_address(...)
453: async def pay_onchain(...)
512: async def onchain_deposits_stream(self) -> AsyncGenerator[OnchainDeposit, None]
532: async def estimate_onchain_fee(...)
548: async def list_onchain_deposits(...)
562: async def get_onchain_transaction(...)

So there's nothing to build on the wallet side; the gap is entirely the purpose-binding this issue already identifies.

Worth noting onchain_deposits_stream for whoever picks up aiolabs/lnbits#53: a push stream means the tagged-address work can credit and dispatch on arrival the way on_invoice_paid does today, rather than polling list_onchain_deposits on a timer. That's the property SatsPay's webhook was providing, and it's the reason dropping SatsPay costs us nothing architecturally.

Funding source for this is **LNDRest**, and the fork's `LndRestWallet` already carries the whole on-chain surface this needs — `lnbits/wallets/lndrest.py` on `dev`: ``` 41: Feature.onchain, 425: async def create_onchain_address(...) 453: async def pay_onchain(...) 512: async def onchain_deposits_stream(self) -> AsyncGenerator[OnchainDeposit, None] 532: async def estimate_onchain_fee(...) 548: async def list_onchain_deposits(...) 562: async def get_onchain_transaction(...) ``` So there's nothing to build on the wallet side; the gap is entirely the purpose-binding this issue already identifies. Worth noting `onchain_deposits_stream` for whoever picks up aiolabs/lnbits#53: a push stream means the tagged-address work can credit and dispatch on arrival the way `on_invoice_paid` does today, rather than polling `list_onchain_deposits` on a timer. That's the property SatsPay's webhook was providing, and it's the reason dropping SatsPay costs us nothing architecturally.
padreug referenced this issue from a commit 2026-09-28 22:10:57 +00:00
Sign in to join this conversation.
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
aiolabs/events#41
No description provided.