feat(machine): Bolt Card (NFC) tap-to-receive on cash-in
Tap-to-receive for the buy flow, the receive counterpart to #83's cash-out tap-to-pay. A Bolt Card only emits an lnurlw withdraw voucher (wrong direction to deposit into it), so the tap is used as an authenticated identity (external_id + SUN p/c) to resolve the card wallet's lnurlp/Lightning Address; the ATM then pays an invoice for the payout over its existing nostr transport. - electron/lnurl-pay.ts: resolveCardInvoice() — resolve card -> pay target -> LUD-16/LUD-06 -> BOLT11. scanUrlToResolver() is the single HTTPS-today / nostr-tomorrow transport seam. 13 tests. - IPC lnurl:pay-card (main-process HTTPS to dodge renderer CORS) + preload/electron.d.ts surface. - stores/atm.ts: handleBoltCardReceive() settles via the existing payInvoice -> PAYMENT_RECEIVED path; the one NFC listener now routes the same tap by flow (cash-out pulls, cash-in receives). - CashInView.vue: NFC status + dev tap input. - docs/boltcard-receive-resolver.md: spec for the custom LNbits /boltcards/api/v1/pay/<id> resolver endpoint (omni-private side). Card issuance is unchanged — same NDEF/keys/external_id; receive is a server-side reading of the same tap. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
parent
73376a6c68
commit
64582e7fe6
8 changed files with 605 additions and 31 deletions
|
|
@ -134,6 +134,13 @@ contextBridge.exposeInMainWorld('electronAPI', {
|
|||
amountMsat?: number
|
||||
}): Promise<{ ok: boolean; reason?: string }> => ipcRenderer.invoke('lnurl:withdraw', args),
|
||||
|
||||
// Bolt Card cash-in: resolve a tapped card + amount to a BOLT11 to pay.
|
||||
resolveCardInvoice: (args: {
|
||||
lnurlw: string
|
||||
amountMsat: number
|
||||
}): Promise<{ ok: boolean; bolt11?: string; reason?: string }> =>
|
||||
ipcRenderer.invoke('lnurl:pay-card', args),
|
||||
|
||||
applyOperatorCassettesConfig: (
|
||||
payload: {
|
||||
positions: Record<string, { denomination: number; count: number }>
|
||||
|
|
@ -272,6 +279,10 @@ declare global {
|
|||
bolt11: string
|
||||
amountMsat?: number
|
||||
}) => Promise<{ ok: boolean; reason?: string }>
|
||||
resolveCardInvoice: (args: {
|
||||
lnurlw: string
|
||||
amountMsat: number
|
||||
}) => Promise<{ ok: boolean; bolt11?: string; reason?: string }>
|
||||
applyOperatorCassettesConfig: (
|
||||
payload: { positions: Record<string, { denomination: number; count: number }> },
|
||||
eventCreatedAt: number
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue