Two additions surface withdraw-extension capabilities the ATM use
case in aiolabs/lamassu-next (issues #24, #25) needs but couldn't
reach over the nostr transport before:
## lnurlw_list_links (AUTH_ACCOUNT)
Enumerate withdraw links across all wallets owned by the calling
account, with `limit`/`offset` pagination matching the existing
HTTP `/api/v1/links`. Lets an ATM (or any client) re-discover its
links after a reconnect without having to keep its own index.
If `request.wallet_id` is supplied and matches one of the account's
wallets, narrows the listing to just that wallet — mirrors lnurlp's
list semantics.
Returns `{data: [...links], total: <int>}`.
## lnurlw_unique_hashes (AUTH_WALLET)
For an `is_unique=True` link, return the per-use `id_unique_hash`
values derived from each unredeemed slot in `link.usescsv`. Mirrors
the formula in `helpers.py:create_lnurl:13`:
id_unique_hash = shortuuid.uuid(name=link.id + link.unique_hash + index)
Without this RPC an ATM that wants to generate distinct QR codes
per use (lamassu-next #25) had to reimplement the derivation
client-side — fragile if the extension's hash format ever changes
upstream. With this RPC the ATM asks the server for the canonical
list of unredeemed hashes; each one becomes the trailing path
component of `/withdraw/api/v1/lnurl/<unique_hash>/<id_unique_hash>`.
`is_unique=False` links return an empty `unredeemed_hashes` list;
the base `unique_hash` alone identifies the callback path.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Hooks the existing withdraw CRUD into the LNbits nostr transport layer
so an HTTP-allergic client (e.g. lamassu-next ATM) can manage LNURL-
withdraw links over kind-21000 encrypted events instead of HTTP.
New `withdraw_start()` lifecycle hook (auto-invoked by the LNbits
extension manager) imports the transport's `register_rpc` and registers
four RPCs mirroring the Lightning.Pub `withdraw.*` contract exactly so
lamassu-next's adapter can be a pure name-translation layer:
lnurlw_create_link AUTH_WALLET
lnurlw_get_link AUTH_WALLET
lnurlw_update_link AUTH_WALLET
lnurlw_delete_link AUTH_WALLET
All handlers are thin shims around the existing crud.py functions —
no business logic duplication. *_get / *_update / *_delete verify
that the link's stored wallet matches the caller's wallet id.
Also registers a link-owner resolver with the core subscriptions
module (under tag "withdraw", extras-key "withdrawal_link_id" — the
exact field name views_lnurl.py:144 stamps on payment.extra when a
withdraw settles). That lets clients call
`subscribe_payments({tag:"withdraw", link_id:...})` and stream real-
time claim events without polling, with ownership enforced server-side.
The transport import is guarded by try/except ImportError so this
extension still loads cleanly against an LNbits build that doesn't
have nostr_transport.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>