From 55ae58daf23028fa0f647f7bb2b4b0f8cd751de7 Mon Sep 17 00:00:00 2001 From: Adam Soltys Date: Tue, 3 Mar 2026 21:40:58 -0800 Subject: sync vault --- routes/payments.ts | 69 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ routes/users.ts | 2 +- 2 files changed, 70 insertions(+), 1 deletion(-) (limited to 'routes') diff --git a/routes/payments.ts b/routes/payments.ts index 98581ebd..524f6f4d 100644 --- a/routes/payments.ts +++ b/routes/payments.ts @@ -23,6 +23,7 @@ import { sendInternal, sendLightning, sendOnchain, + syncBitcoinVault, } from "$lib/payments"; import { emit } from "$lib/sockets"; import { @@ -1116,4 +1117,72 @@ export default { return bail(c, e.message); } }, + + async bitcoinSync(c) { + try { + const user = c.get("user"); + const { aid } = await c.req.json(); + const { id: uid } = user; + + const pos = await db.lPos(`${uid}:accounts`, aid); + if (pos === null) return bail(c, "account not found"); + + const account = await g(`account:${aid}`); + if (!account?.pubkey || !account?.fingerprint) return bail(c, "not a bitcoin vault"); + + const lockKey = `btcsynclock:${aid}`; + const gotLock = await db.set(lockKey, "1", { NX: true, EX: 30 }); + if (!gotLock) return c.json({ synced: 0, received: 0, payments: [] }); + + try { + const { pendingTotal, newPayments } = await syncBitcoinVault(account, user); + + let received = 0; + const payments = []; + + for (const p of newPayments) { + if (p.amount > 0) { + received += p.amount; + payments.push(p); + + const invoiceIds = await db.lRange(`${aid}:invoices`, 0, 20); + for (const iid of invoiceIds) { + const inv = await getInvoice(iid); + if (!inv || inv.type !== "bitcoin") continue; + if (inv.received >= inv.amount && inv.amount > 0) continue; + if (inv.amount > 0 && p.amount < inv.amount) continue; + inv.received = (inv.received || 0) + p.amount; + p.iid = iid; + await s(`invoice:${iid}`, inv); + await s(`payment:${p.id}`, p); + emit(uid, "payment", p); + break; + } + } + } + + // Compute balance from payments + const paymentIds = await db.lRange(`${aid}:payments`, 0, -1); + const paymentKeys = paymentIds.map((pid) => `payment:${pid}`); + const allPayments = await gfAll(paymentKeys); + let balance = 0; + for (const pay of allPayments) { + if (pay) balance += pay.amount; + } + balance = Math.max(balance, 0); + + return c.json({ + synced: newPayments.length, + received, + payments, + balance, + pending: pendingTotal, + }); + } finally { + await db.del(lockKey); + } + } catch (e) { + return bail(c, e.message); + } + }, }; diff --git a/routes/users.ts b/routes/users.ts index 6948fb28..027d836e 100644 --- a/routes/users.ts +++ b/routes/users.ts @@ -894,7 +894,7 @@ export default { await importAccountHistory(account); } - if (account.type === PaymentType.ark) { + if (account.type === PaymentType.ark || (account.pubkey && account.fingerprint)) { const paymentIds = (await db.lRange(`${aid}:payments`, 0, -1)) as string[]; const paymentKeys = paymentIds.map((pid) => `payment:${pid}`); const payments = await gfAll(paymentKeys); -- cgit v1.2.3