aboutsummaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/payments.js106
1 files changed, 104 insertions, 2 deletions
diff --git a/lib/payments.js b/lib/payments.js
index 369d0aec..098c16f7 100644
--- a/lib/payments.js
+++ b/lib/payments.js
@@ -15,6 +15,7 @@ import fs from "fs";
import EventEmitter from "events";
import crc32 from "buffer-crc32";
import { mqtt1, mqtt2 } from "$lib/mqtt";
+import ln from "$lib/ln";
export const types = {
internal: "internal",
@@ -72,7 +73,6 @@ export let debit = async (
ourfee || 0
);
-
if (r !== "ok") fail("Insufficient funds");
let p = {
@@ -160,7 +160,7 @@ export let credit = async (hash, amount, memo, ref, type = types.internal) => {
await s(`payment:${txid}:${vout}`, id);
} else {
await s(`payment:${hash}`, id);
- }
+ }
let m = await db.multi();
@@ -210,3 +210,105 @@ export let confirm = async (address, txid, vout) => {
.incrBy(`balance:${p.uid}`, p.amount)
.exec();
};
+
+export let payLightning = async (user, payreq, amount, maxfee, memo) => {
+ let p;
+ let hash = payreq;
+
+ amount = parseInt(amount);
+ if (amount < 0) fail("Invalid amount");
+
+ maxfee = maxfee ? parseInt(maxfee) : 0;
+ if (maxfee < 0) fail("Max fee cannot be negative");
+
+ let total = amount;
+ let { amount_msat, payment_hash } = await ln.decode(payreq);
+ if (amount_msat) total = Math.round(amount_msat / 1000);
+
+ let iid = await g(`invoice:${hash}`);
+ if (iid && iid.hash) iid = iid.hash;
+ let invoice = await g(`invoice:${iid}`);
+
+ if (invoice) {
+ if (invoice.uid === user.id) fail("Cannot send to self");
+ hash = payreq;
+ } else {
+ let r;
+
+ let { pays } = await ln.listpays(payreq);
+ if (pays.find(p => p.status === "complete"))
+ fail("Invoice has already been paid");
+
+ if (pays.find(p => p.status === "pending"))
+ fail("Payment is already underway");
+
+ p = await debit(payreq, total, maxfee, memo, user, types.lightning);
+
+ let check = async () => {
+ try {
+ let { pays } = await ln.listpays(payreq);
+
+ let recordExists = !!(await g(`payment:${p.id}`));
+ let paymentFailed =
+ !pays.length || pays.every(p => p.status === "failed");
+
+ l("checking", payreq, recordExists, paymentFailed);
+
+ if (recordExists && paymentFailed) {
+ await db.del(`payment:${p.id}`);
+
+ let credit = Math.round(total * config.fee) - p.ourfee;
+ warn("crediting balance", total + maxfee + p.ourfee);
+ await db.incrBy(`balance:${p.uid}`, total + maxfee + p.ourfee);
+
+ warn("crediting credits", credit);
+ await db.incrBy(`credit:${types.lightning}:${p.uid}`, credit);
+
+ warn("reversing payment", p.id);
+ await db.lRem(`${p.uid}:payments`, 1, p.id);
+
+ clearInterval(interval);
+ }
+ } catch (e) {
+ console.log(e);
+ err("Failed to reverse payment", r);
+ }
+ };
+
+ let interval = setInterval(check, 5000);
+
+ try {
+ l("paying lightning invoice", payreq);
+
+ r = await ln.pay({
+ bolt11: payreq.replace(/\s/g, "").toLowerCase(),
+ amount_msat: amount_msat ? undefined : amount * 1000,
+ maxfee: maxfee * 1000,
+ retry_for: 5
+ });
+
+ if (!(r.status === "complete" && r.payment_preimage))
+ fail("Payment did not complete");
+
+ l("payment completed", p.id, r.payment_preimage);
+
+ p.amount = -amount;
+ p.tip = total - amount;
+ p.fee = Math.round((r.amount_sent_msat - r.amount_msat) / 1000);
+ p.ref = r.payment_preimage;
+
+ await s(`payment:${p.id}`, p);
+
+ l("refunding fee", maxfee, p.fee, maxfee - p.fee, p.ref);
+ await db.incrBy(`balance:${p.uid}`, maxfee - p.fee);
+ } catch (e) {
+ warn("something went wrong", e.message);
+ await check();
+ throw e;
+ }
+
+ clearInterval(interval);
+ }
+
+ return p;
+};