feat(machine): open a verified Bolt Card session at tap-to-enter
Entry now spends the tap's single-use SUN once, on the card server's new /session endpoint (aiolabs/boltcards feat/card-session-endpoint), instead of parsing the lnurlw locally and deferring every check to Complete. The server proves a genuine, non-replayed card and returns the wallet balance plus the hit-keyed LUD-03 withdraw and LUD-06 pay second steps — the same single-use bearer /scan and /pay hand out — so Complete still needs no second tap and the ATM holds no p/c for the visit. - electron/boltcard-session.ts: /scan → /session URL derivation, response parsing, 404 → 'card server does not support sessions'. - lnurl-withdraw / lnurl-pay: the second steps are now callable on their own (executeWithdrawCallback, resolveInvoiceFromPayStep); the tap paths are unchanged and reuse them. - IPC: lnurl:open-card-session, lnurl:withdraw-session, lnurl:pay-session. - store: handleBoltCardEntry opens the session then authorizes the server-returned external_id; the payment handlers take a source (raw tap or session); a withheld withdraw step declines with the server's reason. The boltcard AccessScan no longer carries the lnurlw. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
parent
ce4b5a5dc6
commit
735132b032
12 changed files with 639 additions and 63 deletions
|
|
@ -141,6 +141,23 @@ contextBridge.exposeInMainWorld('electronAPI', {
|
|||
}): Promise<{ ok: boolean; bolt11?: string; reason?: string }> =>
|
||||
ipcRenderer.invoke('lnurl:pay-card', args),
|
||||
|
||||
// Bolt Card tap-to-enter: one verified session per tap (balance + fiat +
|
||||
// the withdraw/pay second steps reused at Complete). Payload shapes are
|
||||
// declared in src/types/electron.d.ts (CardSession).
|
||||
openCardSession: (args: { lnurlw: string }): Promise<unknown> =>
|
||||
ipcRenderer.invoke('lnurl:open-card-session', args),
|
||||
withdrawWithSession: (args: {
|
||||
withdraw: { callback: string; k1: string; minWithdrawable?: number; maxWithdrawable?: number }
|
||||
bolt11: string
|
||||
amountMsat?: number
|
||||
}): Promise<{ ok: boolean; reason?: string }> =>
|
||||
ipcRenderer.invoke('lnurl:withdraw-session', args),
|
||||
resolveSessionInvoice: (args: {
|
||||
pay: { callback: string; minSendable?: number; maxSendable?: number; metadata?: string }
|
||||
amountMsat: number
|
||||
}): Promise<{ ok: boolean; bolt11?: string; reason?: string }> =>
|
||||
ipcRenderer.invoke('lnurl:pay-session', args),
|
||||
|
||||
applyOperatorCassettesConfig: (
|
||||
payload: {
|
||||
positions: Record<string, { denomination: number; count: number }>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue