/** * Device-local record of an escrow token that was minted (funds locked) but not * yet confirmed on a relay. * * WHY: escrow creation mints P2PK-locked proofs and then publishes a kind-31872 * request carrying the token. If the publish fails, the token lived only in an * in-memory variable and the locked funds were unrecoverable. Persisting it here * before the publish keeps the buyer able to recover/refund. * * The token is a bearer instrument, but it is P2PK-locked to the seller with the * buyer's refund key — so storing it is safe and is exactly what protects the * buyer if the send does not go through. */ const STORAGE_KEY = 'skatespots:pending-escrow-v1'; export interface PendingEscrow { token: string; amountSats?: number; lockDays?: number; /** Unix seconds. */ at: number; } type Store = Record; function read(): Store { try { const raw = localStorage.getItem(STORAGE_KEY); if (!raw) return {}; const parsed = JSON.parse(raw); return parsed && typeof parsed === 'object' ? (parsed as Store) : {}; } catch { return {}; } } function write(store: Store): void { try { localStorage.setItem(STORAGE_KEY, JSON.stringify(store)); } catch { /* storage full / unavailable — best-effort */ } } function keyFor(listing: { pubkey: string; identifier: string }): string { return `30402:${listing.pubkey}:${listing.identifier}`; } export function savePendingEscrow( listing: { pubkey: string; identifier: string }, token: string, amountSats?: number, lockDays?: number, ): void { const store = read(); store[keyFor(listing)] = { token, amountSats, lockDays, at: Math.floor(Date.now() / 1000) }; write(store); } export function getPendingEscrow( listing: { pubkey: string; identifier: string }, ): PendingEscrow | undefined { return read()[keyFor(listing)]; } export function clearPendingEscrow(listing: { pubkey: string; identifier: string }): void { const store = read(); delete store[keyFor(listing)]; write(store); }