Skip to content

Draft: LUD-XX – pinLimit for withdrawRequest (PIN protection for NFC/Boltcard)#290

Open
AxelHamburch wants to merge 10 commits into
lnurl:ludsfrom
AxelHamburch:draft/pinlimit-withdrawrequest
Open

Draft: LUD-XX – pinLimit for withdrawRequest (PIN protection for NFC/Boltcard)#290
AxelHamburch wants to merge 10 commits into
lnurl:ludsfrom
AxelHamburch:draft/pinlimit-withdrawrequest

Conversation

@AxelHamburch
Copy link
Copy Markdown
Contributor

@AxelHamburch AxelHamburch commented May 19, 2026

Summary

Clean resubmission of PR #200 (pinLimit for withdrawRequest), open since
February 2023 without being merged.

Supersedes #200. Related to governance discussion: #289.

Spec file: XX.md

What this adds

An optional pinLimit field to the withdrawRequest response (LUD-03 extension).
When present and the withdrawal amount meets or exceeds the threshold, the wallet
must collect a 4-digit numeric PIN before sending the callback. If the PIN is
absent or wrong, the SERVICE MUST reject the request — there is no fallback.

No LUD number is claimed. File is XX.md as placeholder.
Number to be assigned by a maintainer at merge time (per #289).

Why now

Changes vs PR #200

PR #200 This PR
LUD number LUD-21 (conflict) LUD-XX (placeholder)
HTTPS implicit explicit MUST
Brute-force protection SHOULD MUST
Service rejection if PIN missing unclear explicit MUST
Mermaid diagram none added (aligned with LUD-03)
Prior art reference none PR #200 cited

Known implementations (verified)

Project Evidence
SwissBitcoinPay/boltcard-tools-terminal PR #33 merged 2024-05-26
boltcard/boltcard-lndhub Release v0.2.0 (2023-08-06): "PIN feature added"

@andrerfneves andrerfneves added contested Competing proposals for the same LUD number — needs arbitration draft Spec exists but still being shaped lud-extension Adds a field or behavior to an existing LUD labels May 25, 2026
@AxelHamburch
Copy link
Copy Markdown
Contributor Author

Known Implementations of LUD-XX pinLimit

The following open-source projects implement the draft
LUD-XX pinLimit for withdrawRequest
spec. They were developed independently against the same draft and interoperate
end-to-end, demonstrating production readiness prior to formal number assignment.


Service-side implementations

These projects serve the withdrawRequest JSON and validate the pin parameter
on the callback.

lnbits/boltcards — LNbits extension

  • PR: lnbits/boltcards#67
  • Key commit: dc46cd1
  • Adds pinLimit field to withdrawRequest response
  • PIN stored as pbkdf2_hmac hash; validated on callback
  • Card disabled after 3 consecutive failures
  • PIN failure count persisted across taps (pin_total_attempts)
  • Frontend form fields for setting PIN and threshold (sats/msats)

bitPOS-app/bitpos — self-hosted Lightning PoS

  • File: artifacts/api-server/src/routes/lnurlw.ts
  • pinLimit included in withdrawRequest when card has a PIN set
  • pinLimitMsats = null maps to 0 on the wire (PIN always required)
  • PIN verified via bcrypt against stored hash
  • Atomic k1 consumption includes pinLockedAt guard (defence-in-depth)
  • Card locked in DB after 3 failures; fail counter reset on success

Terminal / wallet-side implementations

These projects read the withdrawRequest, detect pinLimit, and collect the
PIN from the user before sending the callback.

AxelHamburch/zapbox_extension — ZapBox NFC touch terminal (LNbits extension)

  • Commit: c111234
  • Detects pinLimit in withdrawRequest; compares price_msat >= pin_limit_msat
  • Sends pin_required WebSocket event to the ZapBox touch display with amount_sat, session_id, max_attempts
  • Device renders PIN pad and POSTs 4-digit PIN to /nfc/pin_submit?session_id=&pin=
  • Server-side coroutine awaits PIN via asyncio.Event (max 180 s timeout)
  • On wrong PIN: sends pin_error WS event with remaining attempts
  • On 3rd failure: raises HTTP 403; device shows blocked screen
  • Appends &pin=XXXX to the boltcards callback URL

Buho-Ecosystem/Buho_go — BuhoGO mobile wallet (Android/iOS)

  • Commit: 38ada0a
  • Branch: feature/bolt-card-pin-limit
  • pinLimit forwarded from fetchLNURLInfo into pendingPayment
  • After invoice creation, checks amount_sats × 1000 >= pinLimit
  • Shows fullscreen PinEntryDialog (4-digit numeric, spec-compliant)
  • User cancels → withdrawal resets silently; no callback sent
  • PIN appended as &pin=XXXX to callback URL via submitWithdrawCallback
  • Wrong PIN → service error surfaced to user; retry by sliding again
  • No PIN prompt when pinLimit absent or amount below threshold (existing flow unchanged)

End-to-end interoperability

NFC Card tap
     │
     ▼
LNURL-withdraw Service ──────────────────────── boltcards (LNbits)   PR #67
  returns withdrawRequest                        bitpos (self-hosted)  merged
  with optional pinLimit field
     │
     ▼
Terminal / Wallet ────────────────────────────── zapbox_extension      merged
  detects pinLimit                               Buho_go (mobile)      open PR
  prompts user for 4-digit PIN
  sends ?pin= in callback
     │
     ▼
Service validates PIN
  wrong PIN  → ERROR + attempts remaining
  3 failures → card blocked
  correct    → OK, payment settles

A card provisioned against boltcards or bitpos can be tapped at a
zapbox_extension terminal or paid via Buho_go — the PIN flow works
end-to-end across all combinations.

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

Labels

contested Competing proposals for the same LUD number — needs arbitration draft Spec exists but still being shaped lud-extension Adds a field or behavior to an existing LUD

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants