From 5264f702a2217fe8815cb5275aca14a672f6d4bb Mon Sep 17 00:00:00 2001 From: Adam Soltys Date: Thu, 19 Jan 2023 16:00:38 -0800 Subject: refactor payment types --- lib/lightning.js | 33 +------------- lib/payments.js | 132 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ lib/utils.js | 2 +- 3 files changed, 135 insertions(+), 32 deletions(-) create mode 100644 lib/payments.js (limited to 'lib') diff --git a/lib/lightning.js b/lib/lightning.js index 86dfdb2b..c8daf8c8 100644 --- a/lib/lightning.js +++ b/lib/lightning.js @@ -5,6 +5,7 @@ import { callWebhook } from "$lib/webhooks"; import ln from "$lib/ln"; import { l, err, warn } from "$lib/logging"; import { g, s, t, db } from "$lib/db"; +import { credit, types } from "$lib/payments"; export async function listenForLightning() { let { @@ -33,37 +34,7 @@ export async function listenForLightning() { let amount = parseInt(received) - tip; if (amount < 0) throw new Error("amount out of range"); - let user = await g(`user:${uid}`); - - let payment = { - amount, - created: Date.now(), - currency, - fee: 0, - hash, - memo, - preimage, - rate, - tip, - type: "lightning", - uid - }; - - invoice.status = "paid"; - invoice.received += received; - - await s(`invoice:${hash}`, invoice); - await db.incrBy(`balance:${uid}`, received); - payment.invoice = invoice; - await s(`payment:${hash}`, payment); - await db.lPush(`${uid}:payments`, hash); - - callWebhook(invoice, payment); - - emit(uid, "payment", payment); - notify(user, `Received ${received} SAT`); - - l("lightning payment received", user.username, payment.amount, payment.tip); + await credit(hash, amount, memo, preimage, types.lightning); } catch (e) { console.log(e); err("problem receiving lightning payment", e.message); diff --git a/lib/payments.js b/lib/payments.js new file mode 100644 index 00000000..e12f7858 --- /dev/null +++ b/lib/payments.js @@ -0,0 +1,132 @@ +import config from "$config"; +import store from "$lib/store"; +import { emit } from "$lib/sockets"; +import { v4 } from "uuid"; +import { notify } from "$lib/notifications"; +import { db, g, s, t } from "$lib/db"; +import { l, err } from "$lib/logging"; +import { fail } from "$lib/utils"; +import { callWebhook } from "$lib/webhooks"; + +export const types = { + internal: "internal", + bitcoin: "bitcoin", + lightning: "lightning", + pot: "pot" +}; + +export let debit = async ( + user, + amount, + memo, + to, + type = types.internal, + id = v4() +) => { + let { id: uid, currency, username } = user; + to = to && to.id; + + amount = parseInt(amount); + + if (!amount || amount < 0) fail("Amount must be greater than zero"); + + await t(`balance:${uid}`, async balance => { + await new Promise(r => setTimeout(r, 100)); + if (balance < amount) fail("Insufficient funds"); + return balance - amount; + }); + + let fee = 0; + + let p = { + id, + amount: -amount, + memo, + uid, + rate: store.rates[currency], + currency, + type, + to, + created: Date.now() + }; + + if (!to) delete p.to; + + await s(`payment:${hash}`, p); + await db.lPush(`${uid}:payments`, hash); + + l("sent internal", user.username, amount); + emit(user.id, "payment", p); + + return p; +}; + +export let credit = async (hash, amount, memo, from, type = "internal") => { + amount = parseInt(amount); + let invoice = await g(`invoice:${hash}`); + if (!invoice) return; + + let user = await g(`user:${invoice.uid}`); + + let { id: uid, currency, username } = user; + + let p = { + hash, + amount, + uid, + rate: store.rates[currency], + currency, + memo, + from, + type, + confirmed: true, + created: Date.now() + }; + + let { tip } = invoice; + if (tip) { + p.tip = tip; + p.amount -= tip; + } + + invoice.received += amount; + + let balance = "balance"; + if (type === types.bitcoin) { + let [txid, vout] = from.split(":").slice(-2); + p.id = `${txid}:${vout}`; + p.confirmed = false; + balance = "pending"; + } else { + p.id = hash; + } + + await db + .multi() + .set(`invoice:${hash}`, JSON.stringify(invoice)) + .set(`payment:${p.id}`, JSON.stringify(p)) + .lPush(`${uid}:payments`, p.id) + .incrBy(`${balance}:${uid}`, amount) + .exec(); + + l("received internal", username, amount); + emit(uid, "payment", p); + notify(user, `Received ${amount} sats`); + callWebhook(invoice, p); + + return p; +}; + +export let confirm = async (address, txid, vout) => { + let id = `payment:${txid}:${vout}`; + let p = await g(id); + p.confirmed = true; + console.log("P", p); + + await db + .multi() + .set(id, JSON.stringify(p)) + .decrBy(`pending:${p.uid}`, p.amount) + .incrBy(`balance:${p.uid}`, p.amount) + .exec(); +}; diff --git a/lib/utils.js b/lib/utils.js index e653f235..b65f179a 100644 --- a/lib/utils.js +++ b/lib/utils.js @@ -23,7 +23,7 @@ export const fail = msg => { }; export const SATS = 100000000; -export const toSats = n => Math.round(n * SATS); +export const sats = n => Math.round(n * SATS); export const uniq = (a, k) => [...new Map(a.map(x => [k(x), x])).values()]; export const pick = (O, K) => -- cgit v1.2.3