aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAdam Soltys <[email protected]>2025-09-18 14:42:13 -0700
committerAdam Soltys <[email protected]>2025-09-18 14:42:13 -0700
commit8c7fa95d44aabd38fadc3ef955d835ad3379ec6c (patch)
treec5c3b9f5490acd944656438d31355081835098d3
parentd2db386e53296babe4e4068ca8d68b3c052e0efb (diff)
downloadcoinos-server-8c7fa95d44aabd38fadc3ef955d835ad3379ec6c.tar.gz
coinos-server-8c7fa95d44aabd38fadc3ef955d835ad3379ec6c.zip
sendinvoice support
-rw-r--r--index.ts1
-rw-r--r--lib/invoices.ts29
-rw-r--r--lib/lightning.ts10
-rw-r--r--lib/payments.ts2
-rw-r--r--routes/payments.ts29
5 files changed, 56 insertions, 15 deletions
diff --git a/index.ts b/index.ts
index 0ca35ec5..d9538427 100644
--- a/index.ts
+++ b/index.ts
@@ -67,6 +67,7 @@ app.post("/zapRequest", auth, nostr.zapRequest);
app.get("/thread/:id", nostr.thread);
app.get("/info", payments.info);
+app.post("/sendinvoice", auth, payments.sendinvoice);
app.post("/payments", auth, payments.create);
app.get("/payments", auth, payments.list);
app.get("/payments/:hash", payments.get);
diff --git a/lib/invoices.ts b/lib/invoices.ts
index 45987ae1..1800b859 100644
--- a/lib/invoices.ts
+++ b/lib/invoices.ts
@@ -16,6 +16,7 @@ export const generate = async ({ invoice, user }) => {
let {
address_type,
bolt11,
+ bolt12,
aid,
currency,
expiry,
@@ -35,8 +36,8 @@ export const generate = async ({ invoice, user }) => {
secret,
} = invoice;
- amount = parseInt(amount || 0);
- tip = tip == null ? null : parseInt(tip);
+ amount = Number.parseInt(amount || 0);
+ tip = tip == null ? null : Number.parseInt(tip);
if (user) user = await getUser(user.username);
if (!user) fail("user not provided");
@@ -95,18 +96,26 @@ export const generate = async ({ invoice, user }) => {
text = r.bolt11;
paymentHash = r.payment_hash;
} else if (type === PaymentType.bolt12) {
- const r = await ln.offer({
- amount: amount ? `${amount + tip}sat` : "any",
- label: `${id} ${user.username} ${new Date()}`,
- description: memo || id,
- });
+ let r;
+ if (bolt12) {
+ const { id: nodeid } = await ln.getinfo();
+ r = await ln.decode(bolt12);
+ if (r.invoice_node_id !== nodeid) fail("invalid invoice");
+ amount = Math.round(r.invoice_amount_msat / 1000);
+ r.bolt12 = bolt12;
+ } else {
+ const r = await ln.offer({
+ amount: amount ? `${amount + tip}sat` : "any",
+ label: `${id} ${user.username} ${new Date()}`,
+ description: memo || id,
+ });
- if (await getInvoice(r.offer_id)) fail("Duplicate offer exists");
+ if (await getInvoice(r.offer_id)) fail("Duplicate offer exists");
+ await s(`invoice:${r.offer_id}`, id);
+ }
hash = r.bolt12;
text = r.bolt12;
-
- await s(`invoice:${r.offer_id}`, id);
} else if (type === PaymentType.bitcoin) {
address_type ||= "bech32";
hash = await bc.getNewAddress({ address_type });
diff --git a/lib/lightning.ts b/lib/lightning.ts
index 8f5f44bc..f8d0f6a4 100644
--- a/lib/lightning.ts
+++ b/lib/lightning.ts
@@ -27,7 +27,7 @@ export async function listenForLightning() {
try {
if (!preimage) return;
- const invoice = await getInvoice(bolt11 ?? local_offer_id);
+ const invoice = await getInvoice(bolt11 ?? local_offer_id ?? bolt12);
if (!invoice) return warn("received lightning with no invoice", bolt11);
const p = await getPayment(bolt11 || bolt12);
@@ -75,10 +75,10 @@ export async function replay(index) {
try {
if (!preimage) return;
- const invoice = await getInvoice(bolt11 ?? local_offer_id);
+ const invoice = await getInvoice(bolt11 ?? local_offer_id ?? bolt12);
if (!invoice) return warn("received lightning with no invoice", bolt11);
- const p = await getPayment(bolt11 || bolt12);
+ let p = await getPayment(bolt11 || bolt12);
if (p) return warn("already processed", bolt11 || bolt12);
if (invoice?.memo) {
@@ -93,13 +93,15 @@ export async function replay(index) {
}
}
- await credit({
+ p = await credit({
hash: bolt11 || bolt12,
amount: received,
memo: invoice.memo,
ref: preimage,
type: bolt12 ? PaymentType.bolt12 : PaymentType.lightning,
});
+
+ return p;
} catch (e) {
console.log(e);
err("problem receiving lightning payment", e.message);
diff --git a/lib/payments.ts b/lib/payments.ts
index 807c87fa..9b7c807b 100644
--- a/lib/payments.ts
+++ b/lib/payments.ts
@@ -185,7 +185,7 @@ export const credit = async ({
amount = parseInt(amount) || 0;
let inv;
- if (type === PaymentType.bolt12) {
+ if (type === PaymentType.bolt12 && !hash.startsWith("lni")) {
const { invoices } = await ln.listinvoices({ invstring: hash });
const { local_offer_id } = invoices[0];
inv = await getInvoice(local_offer_id);
diff --git a/routes/payments.ts b/routes/payments.ts
index 3d289a1d..9df20c76 100644
--- a/routes/payments.ts
+++ b/routes/payments.ts
@@ -3,6 +3,7 @@ import api from "$lib/api";
import { requirePin } from "$lib/auth";
import { db, g, s } from "$lib/db";
import { generate } from "$lib/invoices";
+import { replay } from "$lib/lightning";
import ln from "$lib/ln";
import { err, l, warn } from "$lib/logging";
import mqtt from "$lib/mqtt";
@@ -30,6 +31,7 @@ import {
} from "$lib/utils";
import rpc from "@coinos/rpc";
import got from "got";
+import { v4 } from "uuid";
export default {
async info(_, res) {
@@ -704,4 +706,31 @@ export default {
console.log(req.body);
res.send(req.body);
},
+
+ async sendinvoice(req, res) {
+ try {
+ const { user } = req;
+ const { invreq } = req.body;
+
+ const { amount_msat, bolt12, pay_index } = await ln.sendinvoice({
+ invreq,
+ label: v4(),
+ });
+
+ await generate({
+ invoice: {
+ amount: Math.round(amount_msat / 1000),
+ type: "bolt12",
+ bolt12,
+ },
+ user,
+ });
+
+ const p = await replay(pay_index);
+
+ res.send(p);
+ } catch (e) {
+ bail(res, e.message);
+ }
+ },
};