LNBits as Nostr-native UI layer over Lightning.Pub #22

Open
opened 2026-06-13 22:02:49 +00:00 by padreug · 1 comment
Owner

Migrated from aiolabs/lamassu-next#22 — opened by @padreug on 2026-01-30.\n\n## Summary

Fork LNBits to use Lightning.Pub as its backend, making LNBits a pure UI layer for extensions while Lightning.Pub handles accounts and payments.

Key Insight

LNBits already has NIP-98 authentication built in (migration m022 added pubkey field). The architecture supports:

  • POST /api/v1/auth/nostr - Authenticate with signed Nostr event
  • get_account_by_pubkey() - Query users by npub
  • Auto-account creation when npub first authenticates

Proposed Architecture

LNBits (UI Layer)
├── Extensions (Bolt Cards, LNURLp, TPoS, etc.)
├── Core UI (Wallet view, settings)
└── Adapter Layer (NEW)
    ├── UserAdapter → Lightning.Pub accounts
    ├── WalletAdapter → Lightning.Pub balances
    └── PaymentAdapter → CLINK operations

Lightning.Pub (Backend)
├── Accounts (by npub)
├── Balances
├── Payments
└── LND connection

Implementation Strategy (Option C)

No table migration needed. Replace LNBits' CRUD layer with adapters that call Lightning.Pub.

  1. Create LightningPubWallet funding source - Translates LNBits wallet operations to CLINK
  2. Replace CRUD layer - Query Lightning.Pub instead of local PostgreSQL
  3. Add NIP-07 signing - Browser extension signs payment authorizations
  4. Keep everything else - Extensions, UI, API routes unchanged

Key Design Principle

LNBits never holds nsec. For payments:

  1. LNBits constructs unsigned CLINK Debit event
  2. Browser extension (nos2x, Alby) signs with user's nsec
  3. Signed event sent to Lightning.Pub
  4. Lightning.Pub verifies and executes

Files to Modify

File Change
lnbits/wallets/lightningpub.py NEW: CLINK funding source
lnbits/core/crud/users.py Lightning.Pub adapter
lnbits/core/crud/wallets.py Lightning.Pub adapter
lnbits/core/crud/payments.py Lightning.Pub adapter
lnbits/static/js/nostr-signer.js NEW: NIP-07 integration

Benefits

  • Access to full LNBits extension ecosystem
  • Single identity (npub) across ATM, wallet, web UI
  • Lightning.Pub remains single source of truth
  • User controls keys, signs all payment authorizations

Prerequisites

  • #21 - Hardware testing on Sintra (validate core ATM functionality first)
  • Lightning.Pub API documentation for required endpoints

References

> _Migrated from [aiolabs/lamassu-next#22](https://git.atitlan.io/aiolabs/lamassu-next/issues/22) — opened by @padreug on 2026-01-30._\n\n## Summary Fork LNBits to use Lightning.Pub as its backend, making LNBits a pure UI layer for extensions while Lightning.Pub handles accounts and payments. ## Key Insight LNBits already has NIP-98 authentication built in (migration m022 added `pubkey` field). The architecture supports: - `POST /api/v1/auth/nostr` - Authenticate with signed Nostr event - `get_account_by_pubkey()` - Query users by npub - Auto-account creation when npub first authenticates ## Proposed Architecture ``` LNBits (UI Layer) ├── Extensions (Bolt Cards, LNURLp, TPoS, etc.) ├── Core UI (Wallet view, settings) └── Adapter Layer (NEW) ├── UserAdapter → Lightning.Pub accounts ├── WalletAdapter → Lightning.Pub balances └── PaymentAdapter → CLINK operations Lightning.Pub (Backend) ├── Accounts (by npub) ├── Balances ├── Payments └── LND connection ``` ## Implementation Strategy (Option C) No table migration needed. Replace LNBits' CRUD layer with adapters that call Lightning.Pub. 1. **Create `LightningPubWallet` funding source** - Translates LNBits wallet operations to CLINK 2. **Replace CRUD layer** - Query Lightning.Pub instead of local PostgreSQL 3. **Add NIP-07 signing** - Browser extension signs payment authorizations 4. **Keep everything else** - Extensions, UI, API routes unchanged ## Key Design Principle LNBits never holds nsec. For payments: 1. LNBits constructs unsigned CLINK Debit event 2. Browser extension (nos2x, Alby) signs with user's nsec 3. Signed event sent to Lightning.Pub 4. Lightning.Pub verifies and executes ## Files to Modify | File | Change | |------|--------| | `lnbits/wallets/lightningpub.py` | NEW: CLINK funding source | | `lnbits/core/crud/users.py` | Lightning.Pub adapter | | `lnbits/core/crud/wallets.py` | Lightning.Pub adapter | | `lnbits/core/crud/payments.py` | Lightning.Pub adapter | | `lnbits/static/js/nostr-signer.js` | NEW: NIP-07 integration | ## Benefits - Access to full LNBits extension ecosystem - Single identity (npub) across ATM, wallet, web UI - Lightning.Pub remains single source of truth - User controls keys, signs all payment authorizations ## Prerequisites - [ ] #21 - Hardware testing on Sintra (validate core ATM functionality first) - [ ] Lightning.Pub API documentation for required endpoints ## References - LNBits repo: `~/dev/repos/lnbits.git` (also mirrored at aiolabs/lnbits) - NIP-98 HTTP Auth: https://github.com/nostr-protocol/nips/blob/master/98.md - LNBits NIP-98 implementation: `lnbits/core/views/auth_api.py` (lines 579-626) - LNBits Nostr utilities: `lnbits/utils/nostr.py`
Author
Owner

@padreug commented on 2026-05-13 (lamassu-next#22):

Direction inversion — this issue is superseded by the LNbits-as-backend migration

This issue proposed "LNbits as a Nostr-native UI layer over Lightning.Pub" — LNbits acting as a thin UI/wallet shell that calls LP's nostr RPC for actual Lightning operations.

Since then we've moved in the opposite direction: a nostr-native-transport branch on aiolabs/lnbits exposes LNbits itself as the backend, accessed by HTTP-allergic clients (e.g. this ATM) over kind-21000 NIP-44-encrypted RPC events. That's the inverse of what this issue describes.

Concretely, the LNbits transport now provides:

  • create_invoice, pay_invoice, get_payment, list_payments, get_wallet, list_wallets, create_wallet, decode_payment
  • lnurlw_create_link, lnurlw_get_link, lnurlw_update_link, lnurlw_delete_link, lnurlw_list_links, lnurlw_unique_hashes
  • lnurlp_create, lnurlp_get, lnurlp_list, lnurlp_update, lnurlp_delete
  • subscribe_payments({wallet_id?, payment_hash?, tag?, link_id?}) + unsubscribe

All NIP-44-encrypted over kind-21000 on whatever relay you configure (in dev: the in-process nostrrelay extension). For the ATM the data flow is now:

ATM → kind-21000 RPC event → LNbits → reply over relay → ATM

with subscribe_payments providing real-time settlement push (replaces the LP-only GetLiveUserOperations subscription that lamassu-next's client.ts consumed for withdraw.* link claims and ndebit success).

The CLINK-side of LP (ndebit/noffer, kinds 21001-21003) is not mirrored on LNbits — it remains a Lightning.Pub-only protocol. ATM flows that need CLINK still talk to LP for those; everything else can move to LNbits.

Suggested action: close this issue, or rescope it to "LP-only CLINK flows continue to live on LP; LNbits handles invoice/withdraw/wallet plumbing via the nostr transport." The current title is misleading vs the actual architecture.

References:

  • LNbits PR: aiolabs/lnbits#4
  • LNbits branch: nostr-native-transport
  • Driver script that exercises the contract end-to-end: ~/dev/lnbits/nostr-transport/misc-aio/transport_driver.py
> _@padreug commented on 2026-05-13 ([lamassu-next#22](https://git.atitlan.io/aiolabs/lamassu-next/issues/22#issuecomment-555)):_ ## Direction inversion — this issue is superseded by the LNbits-as-backend migration This issue proposed **"LNbits as a Nostr-native UI layer over Lightning.Pub"** — LNbits acting as a thin UI/wallet shell that calls LP's nostr RPC for actual Lightning operations. Since then we've moved in the **opposite** direction: a `nostr-native-transport` branch on `aiolabs/lnbits` exposes LNbits itself as the backend, accessed by HTTP-allergic clients (e.g. this ATM) over kind-21000 NIP-44-encrypted RPC events. That's the inverse of what this issue describes. Concretely, the LNbits transport now provides: - `create_invoice`, `pay_invoice`, `get_payment`, `list_payments`, `get_wallet`, `list_wallets`, `create_wallet`, `decode_payment` - `lnurlw_create_link`, `lnurlw_get_link`, `lnurlw_update_link`, `lnurlw_delete_link`, `lnurlw_list_links`, `lnurlw_unique_hashes` - `lnurlp_create`, `lnurlp_get`, `lnurlp_list`, `lnurlp_update`, `lnurlp_delete` - `subscribe_payments({wallet_id?, payment_hash?, tag?, link_id?})` + `unsubscribe` All NIP-44-encrypted over kind-21000 on whatever relay you configure (in dev: the in-process `nostrrelay` extension). For the ATM the data flow is now: > ATM → kind-21000 RPC event → LNbits → reply over relay → ATM with `subscribe_payments` providing real-time settlement push (replaces the LP-only `GetLiveUserOperations` subscription that lamassu-next's `client.ts` consumed for `withdraw.*` link claims and ndebit success). The CLINK-side of LP (ndebit/noffer, kinds 21001-21003) is **not** mirrored on LNbits — it remains a Lightning.Pub-only protocol. ATM flows that need CLINK still talk to LP for those; everything else can move to LNbits. **Suggested action:** close this issue, or rescope it to "LP-only CLINK flows continue to live on LP; LNbits handles invoice/withdraw/wallet plumbing via the nostr transport." The current title is misleading vs the actual architecture. References: - LNbits PR: https://git.atitlan.io/aiolabs/lnbits/pulls/4 - LNbits branch: `nostr-native-transport` - Driver script that exercises the contract end-to-end: `~/dev/lnbits/nostr-transport/misc-aio/transport_driver.py`
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/bitspire#22
No description provided.