feat(machine): LNURL-withdraw executor for Bolt Card cash-out (LUD-03)
First, hardware-independent piece of Bolt Card tap-to-pay on the cash-out flow. When a customer taps a Bolt Card, the ATM (which already has its cash-out BOLT11) becomes the LNURL-*withdrawing* party: GET the card's lnurlw voucher → GET callback?k1=…&pr=<invoice> so the card's wallet pays the invoice. Settlement is still observed via the existing invoice watcher (a returned ok=true means "card accepted the pull", not "cash dispensed"). - electron/lnurl-withdraw.ts: executeLnurlWithdraw() + lnurlwToHttps(). Runs in the main process (Node fetch) to avoid renderer CORS, since LNURL endpoints send no CORS headers. Fully injectable fetch for testing. - electron/lnurl-withdraw.test.ts: 12 tests (scheme mapping, two-step happy path passing k1+pr, ERROR surfacing, non-withdraw tag, amount-over-limit short-circuit, callback decline, network failure). - IPC `lnurl:withdraw` (main) + preload + electron.d.ts. Next: pcscd + an nfc-pcsc reader driver (reads the NTAG424 NDEF lnurlw), then wire the tap into the cashOut displayingInvoice state + "tap or scan" UI. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
parent
c36c2fb1c4
commit
457761719f
5 changed files with 263 additions and 0 deletions
|
|
@ -127,6 +127,13 @@ contextBridge.exposeInMainWorld('electronAPI', {
|
|||
// Reload the renderer to re-attempt initialization (connectivity recovery).
|
||||
recoverApp: (): Promise<void> => ipcRenderer.invoke('app:recover'),
|
||||
|
||||
// Bolt Card cash-out: pull payment for the current invoice from a tapped card.
|
||||
lnurlWithdraw: (args: {
|
||||
lnurlw: string
|
||||
bolt11: string
|
||||
amountMsat?: number
|
||||
}): Promise<{ ok: boolean; reason?: string }> => ipcRenderer.invoke('lnurl:withdraw', args),
|
||||
|
||||
applyOperatorCassettesConfig: (
|
||||
payload: {
|
||||
positions: Record<string, { denomination: number; count: number }>
|
||||
|
|
@ -246,6 +253,11 @@ declare global {
|
|||
saveSpireSeed: (seed: string) => Promise<void>
|
||||
relaunchApp: () => Promise<void>
|
||||
recoverApp: () => Promise<void>
|
||||
lnurlWithdraw: (args: {
|
||||
lnurlw: string
|
||||
bolt11: string
|
||||
amountMsat?: number
|
||||
}) => Promise<{ ok: boolean; reason?: string }>
|
||||
applyOperatorCassettesConfig: (
|
||||
payload: { positions: Record<string, { denomination: number; count: number }> },
|
||||
eventCreatedAt: number
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue