aboutsummaryrefslogtreecommitdiffstats
path: root/routes
diff options
context:
space:
mode:
authorAdam Soltys <[email protected]>2024-09-24 12:30:51 -0700
committerAdam Soltys <[email protected]>2024-09-24 12:30:51 -0700
commit80365c227c5a774ad65f5dad8b989e1966630160 (patch)
treea9d6cd130e48e815fb60b91263c5d9b5a83b8808 /routes
parent8c8c71d54d23960ffc4caa94619bae7c6a69514b (diff)
downloadcoinos-server-80365c227c5a774ad65f5dad8b989e1966630160.tar.gz
coinos-server-80365c227c5a774ad65f5dad8b989e1966630160.zip
reconcile onchain balance
Diffstat (limited to 'routes')
-rw-r--r--routes/payments.ts18
-rw-r--r--routes/users.ts90
2 files changed, 57 insertions, 51 deletions
diff --git a/routes/payments.ts b/routes/payments.ts
index 02056eeb..d4993b87 100644
--- a/routes/payments.ts
+++ b/routes/payments.ts
@@ -260,8 +260,10 @@ export default {
try {
let node = rpc({ ...config[type], wallet });
-
let { confirmations, details } = await node.getTransaction(txid);
+ let hot = wallet === config[type].wallet;
+ let aid;
+ if (!hot) aid = wallet;
for (let { address, amount, asset, category, vout } of details) {
if (!address) continue;
@@ -272,8 +274,14 @@ export default {
if (typeof p === "string") p = await g(`payment:${p}`);
if (!p) continue;
- if (confirmations >= 1) p.confirmed = true;
- await s(`payment:${p.id}`, p);
+ if (confirmations) {
+ p.confirmed = true;
+ await s(`payment:${p.id}`, p);
+ if (aid) await db.sRem(`inflight:${aid}`, p.id);
+ } else {
+ if (aid) await db.sAdd(`inflight:${aid}`, p.id);
+ }
+
emit(p.uid, "payment", p);
continue;
}
@@ -282,9 +290,6 @@ export default {
if (typeof p === "string") p = await g(`payment:${p}`);
if (!p) {
- let aid;
- let bal = await g(`balance:${wallet}`);
- if (bal !== null) aid = wallet;
await credit({
hash: address,
amount: sats(amount),
@@ -357,6 +362,7 @@ export default {
res.send(p);
} catch (e) {
+ console.log(e);
warn(user.username, "payment failed", e.message);
res.code(500).send(e.message);
}
diff --git a/routes/users.ts b/routes/users.ts
index 44a87c95..34d20584 100644
--- a/routes/users.ts
+++ b/routes/users.ts
@@ -1,7 +1,7 @@
import { appendFile } from "node:fs/promises";
import { g, s, db } from "$lib/db";
import config from "$config";
-import { SATS, pick, bail, fail, getUser, t } from "$lib/utils";
+import { pick, bail, fail, getUser } from "$lib/utils";
import jwt from "jsonwebtoken";
import { authenticator } from "otplib";
import whitelist from "$lib/whitelist";
@@ -10,7 +10,7 @@ import { emit } from "$lib/sockets";
import register from "$lib/register";
import { requirePin } from "$lib/auth";
import { v4 } from "uuid";
-import { credit, types } from "$lib/payments";
+import { reconcile, types } from "$lib/payments";
import { bech32 } from "bech32";
import { mail, templates } from "$lib/mail";
import upload from "$lib/upload";
@@ -594,29 +594,34 @@ export default {
},
async accounts(req, res) {
- let { user } = req;
+ try {
+ let { user } = req;
+
+ let accounts = [];
+ for (let id of await db.lRange(`${user.id}:accounts`, 0, -1)) {
+ let account = await g(`account:${id}`);
+ account.balance = await g(`balance:${id}`);
- let accounts = [];
- for (let id of await db.lRange(`${user.id}:accounts`, 0, -1)) {
- let account = await g(`account:${id}`);
- account.balance = await g(`balance:${id}`);
+ if (account.seed) await reconcile(account);
- if (account.type === "savings") {
+ accounts.push(account);
}
- accounts.push(account);
+ res.send(accounts.reverse());
+ } catch (e) {
+ console.log(e);
+ bail(res, e.message);
}
-
- res.send(accounts.reverse());
},
async createAccount(req, res) {
try {
let { fingerprint, pubkey, name, seed, type } = req.body;
let { user } = req;
+ let { id: uid } = user;
let id = v4();
- let account = { id, name, seed, type };
+ let account = { id, name, seed, type, uid, descriptors: [] };
let node = rpc(config[type]);
@@ -628,11 +633,10 @@ export default {
node = rpc({ ...config[type], wallet: id });
- let descriptors = [];
for (let i of [0, 1]) {
let desc = `wpkh([${fingerprint}]${pubkey}/${i}/*)`;
let { checksum } = await node.getDescriptorInfo(desc);
- descriptors.push({
+ account.descriptors.push({
desc: `${desc}#${checksum}`,
range: [0, 100],
next_index: 0,
@@ -642,34 +646,17 @@ export default {
});
}
- await node.importDescriptors(descriptors);
- let { total_amount } = await node.scanTxOutSet("start", descriptors);
- let amount = Math.round(total_amount * SATS);
- let { balanceAdjustment: memo } = t(user);
+ await node.importDescriptors(account.descriptors);
- if (amount) {
- let hash = v4();
- let inv = {
- memo,
- type: types.reconcile,
- hash,
- amount,
- uid: user.id,
- aid: id,
- };
- await s(`invoice:${hash}`, inv);
- await credit({
- hash,
- amount,
- type: types.reconcile,
- aid: id,
- });
- }
+ await db
+ .multi()
+ .set(`account:${id}`, JSON.stringify(account))
+ .set(`balance:${id}`, 0)
+ .set(`pending:${id}`, 0)
+ .lPush(`${user.id}:accounts`, id)
+ .exec();
- await s(`account:${id}`, account);
- await s(`balance:${id}`, amount);
- await s(`pending:${id}`, 0);
- await db.lPush(`${user.id}:accounts`, id);
+ await reconcile(account);
await appendFile("/bitcoin.conf", `wallet=${id}\n`);
@@ -691,12 +678,25 @@ export default {
},
async deleteAccount(req, res) {
- let { id } = req.body;
- let { id: uid } = req.user;
+ try {
+ let { id } = req.body;
+ let { id: uid } = req.user;
+ let { type } = await g(`account:${id}`);
+ let node = rpc({ ...config[type], wallet: id });
+ await node.unloadWallet(id);
- await db.lRem(`${uid}:accounts`, 1, id);
- await db.del(`account:${id}`);
+ await db
+ .multi()
+ .lRem(`${uid}:accounts`, 1, id)
+ .del(`account:${id}`)
+ .del(`balance:${id}`)
+ .del(`${id}:payments`)
+ .exec();
- res.send({ ok: true });
+ res.send({ ok: true });
+ } catch (e) {
+ console.log(e);
+ bail(res, e.message);
+ }
},
};