diff options
| author | Adam Soltys <[email protected]> | 2024-09-24 12:30:51 -0700 |
|---|---|---|
| committer | Adam Soltys <[email protected]> | 2024-09-24 12:30:51 -0700 |
| commit | 80365c227c5a774ad65f5dad8b989e1966630160 (patch) | |
| tree | a9d6cd130e48e815fb60b91263c5d9b5a83b8808 /lib | |
| parent | 8c8c71d54d23960ffc4caa94619bae7c6a69514b (diff) | |
| download | coinos-server-80365c227c5a774ad65f5dad8b989e1966630160.tar.gz coinos-server-80365c227c5a774ad65f5dad8b989e1966630160.zip | |
reconcile onchain balance
Diffstat (limited to 'lib')
| -rw-r--r-- | lib/invoices.ts | 5 | ||||
| -rw-r--r-- | lib/payments.ts | 72 | ||||
| -rw-r--r-- | lib/register.ts | 20 |
3 files changed, 83 insertions, 14 deletions
diff --git a/lib/invoices.ts b/lib/invoices.ts index 60bcba0f..d7f09de5 100644 --- a/lib/invoices.ts +++ b/lib/invoices.ts @@ -51,13 +51,15 @@ export let generate = async ({ invoice, user }) => { let id = v4(); - let hash, text; + let hash, text, path; if (account.seed) { type = "bitcoin"; let node = rpc({ ...config[type], wallet: aid }); hash = await node.getNewAddress(); text = bip21(hash, invoice); + + ({ hdkeypath: path } = await node.getAddressInfo(hash)); } else if (type === types.lightning) { let r; if (bolt11) { @@ -107,6 +109,7 @@ export let generate = async ({ invoice, user }) => { received: 0, request_id, memoPrompt, + path, prompt, secret, text, diff --git a/lib/payments.ts b/lib/payments.ts index 6d83b28f..9d2d9b79 100644 --- a/lib/payments.ts +++ b/lib/payments.ts @@ -11,6 +11,7 @@ import { fail, fiat, getInvoice, + getUser, sleep, SATS, sats, @@ -154,7 +155,7 @@ export let credit = async ({ return; } - let { tip } = inv; + let { path, tip } = inv; tip = parseInt(tip) || 0; if (!memo) ({ memo } = inv); @@ -162,7 +163,7 @@ export let credit = async ({ if (amount < 0 || tip < 0) fail("Invalid amount"); if (type === types.internal) amount += tip; - let user = await g(`user:${inv.uid}`); + let user = await getUser(inv.uid); let { id: uid, currency, username } = user; let rates = await g("rates"); @@ -186,6 +187,7 @@ export let credit = async ({ iid: inv.id, hash, amount: amount - tip, + path, uid, rate, currency, @@ -319,7 +321,7 @@ export let completePayment = async (p, user) => { }; let pay = async ({ aid = undefined, amount, to, user }) => { - if (!aid) aid = user.id; + if (!aid) aid = user.id; amount = parseInt(amount) || 0; let lnurl, pr; if (to.includes("@") && to.includes(".")) { @@ -440,6 +442,7 @@ export let sendOnchain = async (params) => { let amount = total - change; + console.log("debiting", aid, amount); let p = await debit({ aid, hash: txid, @@ -613,7 +616,6 @@ export let sendInternal = async ({ invoice = await generate({ invoice: { amount, type: "lightning" }, user: recipient, - sender, }); let { hash } = invoice; @@ -718,11 +720,16 @@ export let build = async ({ let { vin } = await node.decodeRawTransaction(tx.hex); for (let { txid, vout } of vin) { - let nonWitnessUtxo = await node.getRawTransaction(txid); - let tx = await node.decodeRawTransaction(nonWitnessUtxo); - let { address } = tx.vout[vout].scriptPubKey; + let rawTx = await node.getRawTransaction(txid); + let tx = await node.decodeRawTransaction(rawTx); + let prevOutput = tx.vout[vout]; + let { address } = prevOutput.scriptPubKey; let { hdkeypath: path } = await node.getAddressInfo(address); - inputs.push({ nonWitnessUtxo, path }); + let witnessUtxo = { + amount: Math.round(prevOutput.value * SATS), + script: prevOutput.scriptPubKey.hex, + }; + inputs.push({ witnessUtxo, path }); } return { feeRate, ourfee, fee, fees, hex: tx.hex, inputs }; @@ -760,3 +767,52 @@ export let catchUp = async () => { setTimeout(catchUp, 10000); }; + +export let reconcile = async (account) => { + let { descriptors, id, uid, type } = account; + let user = await getUser(uid); + let node = rpc({ ...config[type], wallet: id }); + let { total_amount } = await node.scanTxOutSet("start", descriptors); + let total = Math.round(total_amount * SATS); + let { balanceAdjustment: memo } = t(user); + + let balance = await g(`balance:${id}`); + + let inflight = 0; + for (let pid of await db.sMembers(`inflight:${id}`)) { + let p = await g(`payment:${pid}`); + inflight += Math.abs(p.amount) + p.fee; + } + + balance += inflight; + + let amount = Math.abs(total - balance); + let hash = v4(); + + if (total > balance) { + let inv = { + memo, + type: types.reconcile, + hash, + amount, + uid, + aid: id, + }; + await s(`invoice:${hash}`, inv); + await credit({ + hash, + amount, + type: types.reconcile, + aid: id, + }); + } else if (total < balance) { + await debit({ + aid: id, + amount, + hash: v4(), + memo, + user, + type: types.reconcile, + }); + } +}; diff --git a/lib/register.ts b/lib/register.ts index eb20ae23..f2e97fed 100644 --- a/lib/register.ts +++ b/lib/register.ts @@ -4,7 +4,7 @@ import { v4 } from "uuid"; import config from "$config"; import countries from "$lib/countries"; -import { s } from "$lib/db"; +import { db } from "$lib/db"; import { l, warn } from "$lib/logging"; import { fail, getUser } from "$lib/utils"; @@ -52,10 +52,20 @@ export default async (user, ip) => { user.migrated = true; user.locktime = 300; - await s(`user:${id}`, user); - await s(`user:${username}`, id); - await s(`user:${pubkey}`, id); - await s(`balance:${id}`, 0); + let account = JSON.stringify({ + id, + type: "ecash", + name: "Spending", + }); + + db.multi() + .set(`user:${id}`, JSON.stringify(user)) + .set(`user:${username}`, id) + .set(`user:${pubkey}`, id) + .set(`balance:${id}`, 0) + .set(`account:${id}`, account) + .lPush(`${id}:accounts`, id) + .exec(); l("new user", username); |
