aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--lib/nostr.ts8
-rw-r--r--lib/notifications.ts47
-rw-r--r--lib/nwc.ts26
-rw-r--r--lib/payments.ts5
4 files changed, 70 insertions, 16 deletions
diff --git a/lib/nostr.ts b/lib/nostr.ts
index 9f5a2698..4c28ebc9 100644
--- a/lib/nostr.ts
+++ b/lib/nostr.ts
@@ -3,6 +3,7 @@ import { db, g, s } from "$lib/db";
import { l, warn } from "$lib/logging";
import { scan } from "$lib/strfry";
import { fail, fields, getUser, pick } from "$lib/utils";
+import { bytesToHex } from "@noble/hashes/utils";
import { finalizeEvent, getPublicKey, nip19, verifyEvent } from "nostr-tools";
import type { Event } from "nostr-tools";
import { AbstractSimplePool } from "nostr-tools/abstract-pool";
@@ -11,10 +12,12 @@ import { Relay } from "nostr-tools/relay";
export const EX = 60 * 60 * 24;
const coinos = await Relay.connect(config.nostr);
-export const serverPubkey = getPublicKey(
+export const serverSecret = bytesToHex(
nip19.decode(config.nostrKey).data as Uint8Array,
);
+export const serverPubkey = getPublicKey(serverSecret);
+
const alwaysTrue: any = (t: Event) => {
t[Symbol("verified")] = true;
return true;
@@ -40,7 +43,6 @@ export async function publish(ev, url = config.nostr) {
export async function handleZap(invoice, sender = undefined) {
try {
const pubkey = serverPubkey;
- const sk = nip19.decode(config.nostrKey).data as Uint8Array;
const zapreq = JSON.parse(invoice.description);
if (!zapreq.tags || zapreq.tags.length === 0) {
@@ -93,7 +95,7 @@ export async function handleZap(invoice, sender = undefined) {
tags.push(["preimage", invoice.payment_preimage]);
const ev = { pubkey, kind, created_at, content, tags };
- const signed = await finalizeEvent(ev, sk);
+ const signed = await finalizeEvent(ev, serverSecret);
l("sending receipt");
diff --git a/lib/notifications.ts b/lib/notifications.ts
index 8891d875..e988a728 100644
--- a/lib/notifications.ts
+++ b/lib/notifications.ts
@@ -1,10 +1,13 @@
import config from "$config";
import { db } from "$lib/db";
+import ln from "$lib/ln";
import { err, warn } from "$lib/logging";
import { mail, templates } from "$lib/mail";
import mqtt from "$lib/mqtt";
+import { publish, serverSecret } from "$lib/nostr";
import { emit } from "$lib/sockets";
-import { f, fiat, fmt, link, t } from "$lib/utils";
+import { f, fiat, fmt, getUser, link, nada, t } from "$lib/utils";
+import { finalizeEvent } from "nostr-tools";
import webpush from "web-push";
if (config.vapid) {
@@ -74,3 +77,45 @@ export const notify = async (p, user, withdrawal) => {
);
}
};
+
+export const nwcNotify = async (p) => {
+ try {
+ const user = await getUser(p.uid);
+ const pubkeys = await db.sMembers(`${user.id}:apps`);
+ if (pubkeys.length) {
+ let payment_hash = "";
+ if (p.type === "lightning") ({ payment_hash } = await ln.decode(p.hash));
+ for (const pubkey of pubkeys) {
+ const notification = {
+ type: p.amount > 0 ? "incoming" : "outgoing",
+ invoice: p.hash,
+ description: p.memo,
+ preimage: p.ref,
+ payment_hash: payment_hash,
+ amount: Math.abs(p.amount) * 1000,
+ fees_paid: (parseInt(p.fee) || 0) * 1000,
+ created_at: p.created,
+ settled_at: p.created,
+ };
+
+ const content = JSON.stringify({
+ notification_type: p.amount > 0 ? "payment_received" : "payment_sent",
+ notification,
+ });
+
+ const unsigned = {
+ content,
+ tags: [["p", pubkey]],
+ kind: 23196,
+ created_at: Math.floor(Date.now() / 1000),
+ };
+
+ const event = finalizeEvent(unsigned, serverSecret);
+
+ publish(event).catch(nada);
+ }
+ }
+ } catch (e) {
+ warn("nwc notification failed", e.message);
+ }
+};
diff --git a/lib/nwc.ts b/lib/nwc.ts
index 3f346b87..a902b0a6 100644
--- a/lib/nwc.ts
+++ b/lib/nwc.ts
@@ -22,6 +22,7 @@ const methods = [
"make_invoice",
"lookup_invoice",
"list_transactions",
+ "notifications",
];
const week = 7 * 24 * 60 * 60;
@@ -31,14 +32,19 @@ export default () => {
r.on("open", async (_) => {
r.subscribe("nwc", { kinds: [23194], "#p": [serverPubkey] });
- let info: UnsignedEvent = {
- created_at: Math.floor(Date.now() / 1000),
- kind: 13194,
- tags: [["p", serverPubkey]],
- pubkey: serverPubkey,
- content: methods.join(" "),
- };
- info = await finalizeEvent(info, sk);
+ const info = await finalizeEvent(
+ {
+ created_at: Math.floor(Date.now() / 1000),
+ kind: 13194,
+ tags: [
+ ["p", serverPubkey],
+ ["notifications", "payment_received payment_sent"],
+ ],
+ pubkey: serverPubkey,
+ content: methods.join(" "),
+ },
+ sk,
+ );
r.send(["EVENT", info]);
});
@@ -314,9 +320,7 @@ const handle = (method, params, ev, app, user) =>
async list_transactions() {
const { from, until, limit = 10, offset = 0, type } = params;
- const { pubkey } = app;
- const k = pubkey === user.pubkey ? user.id : pubkey;
- const payments = await db.lRange(`${k}:payments`, 0, -1);
+ const payments = await db.lRange(`${user.id}:payments`, 0, -1);
let transactions = [];
for (const pid of payments) {
diff --git a/lib/payments.ts b/lib/payments.ts
index c35c3795..a150e50c 100644
--- a/lib/payments.ts
+++ b/lib/payments.ts
@@ -5,7 +5,7 @@ import { generate } from "$lib/invoices";
import ln from "$lib/ln";
import { err, l, warn } from "$lib/logging";
import { handleZap } from "$lib/nostr";
-import { notify } from "$lib/notifications";
+import { notify, nwcNotify } from "$lib/notifications";
import {
SATS,
btc,
@@ -144,6 +144,7 @@ export const debit = async ({
l(user.username, "sent", type, amount);
//emit(user.id, "payment", p);
+ if (![types.lightning, types.bolt12].includes(type)) nwcNotify(p, user);
return p;
};
@@ -283,6 +284,7 @@ export const completePayment = async (inv, p, user) => {
}
}
+ nwcNotify(p);
notify(p, user, withdrawal);
l(username, "received", p.type, p.amount);
callWebhook(inv, p);
@@ -821,6 +823,7 @@ const finalize = async (r, p) => {
await db.sRem("pending", p.hash);
l("payment completed", p.id, r.payment_preimage);
+ nwcNotify(p);
const maxfee = p.fee;
const { amount_msat } = await ln.decode(p.hash);