aboutsummaryrefslogtreecommitdiffstats
path: root/routes
diff options
context:
space:
mode:
authorAdam Soltys <[email protected]>2026-03-03 21:40:58 -0800
committerAdam Soltys <[email protected]>2026-03-03 21:40:58 -0800
commit55ae58daf23028fa0f647f7bb2b4b0f8cd751de7 (patch)
tree49f4031b81352bea5c963d4201250f24ee8bd2dd /routes
parent9507e040a03834f7d603c5c13a1f69ae6ef48b3a (diff)
downloadcoinos-server-55ae58daf23028fa0f647f7bb2b4b0f8cd751de7.tar.gz
coinos-server-55ae58daf23028fa0f647f7bb2b4b0f8cd751de7.zip
sync vault
Diffstat (limited to 'routes')
-rw-r--r--routes/payments.ts69
-rw-r--r--routes/users.ts2
2 files changed, 70 insertions, 1 deletions
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);