aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAdam Soltys <[email protected]>2025-01-16 14:57:14 -0800
committerAdam Soltys <[email protected]>2025-01-16 14:57:14 -0800
commitef71c296071be3081b3ac0d742283a261135ae6d (patch)
treead74616c3e32c306ad5c1ded6b1ecf4da85f0591
parent127806d1b703eb3d144e302f20268a7555f9b016 (diff)
downloadcoinos-server-ef71c296071be3081b3ac0d742283a261135ae6d.tar.gz
coinos-server-ef71c296071be3081b3ac0d742283a261135ae6d.zip
zap endpoints
-rw-r--r--index.ts3
-rw-r--r--lib/nostr.ts41
-rw-r--r--routes/nostr.ts95
3 files changed, 102 insertions, 37 deletions
diff --git a/index.ts b/index.ts
index e4212c0e..0c2010ed 100644
--- a/index.ts
+++ b/index.ts
@@ -55,6 +55,9 @@ app.get("/:pubkey/followers", nostr.followers);
app.get("/:pubkey/follows", nostr.follows);
app.get("/event/:id", nostr.event);
app.post("/event", auth, nostr.publish);
+app.get("/zaps/:id", nostr.zaps);
+app.post("/zap", auth, nostr.zap);
+app.post("/zapRequest", auth, nostr.zapRequest);
app.get("/info", payments.info);
app.post("/payments", auth, payments.create);
diff --git a/lib/nostr.ts b/lib/nostr.ts
index 5ef8af3d..f5d85ea0 100644
--- a/lib/nostr.ts
+++ b/lib/nostr.ts
@@ -1,7 +1,7 @@
import config from "$config";
-import { g, s } from "$lib/db";
+import { db, g, s } from "$lib/db";
import { l } from "$lib/logging";
-import { count, scan } from "$lib/strfry";
+import { count, scan, sync } from "$lib/strfry";
import { fail } from "$lib/utils";
import { finalizeEvent, getPublicKey, nip19 } from "nostr-tools";
import { AbstractSimplePool } from "nostr-tools/abstract-pool";
@@ -125,36 +125,21 @@ export const getRelays = async (pubkey): Promise<any> => {
return { read, write };
};
-export const getProfile = async (pubkey, relays = [config.nostr]) => {
- let profile = await g(`${pubkey}:profile`);
+export const getProfile = async (pubkey) => {
+ let profile = await g(`profile:${pubkey}`);
+ if (profile) return profile;
- if (!profile) {
- const pubkeys = [pubkey];
- let filter: any = { authors: pubkeys, kinds: [0] };
+ const filter = { authors: [pubkey], kinds: [0] };
+ const events = await scan(filter);
- let ev = await pool.get(relays, filter, opts);
-
- if (!ev) {
- ({ write: relays } = await getRelays(pubkey));
- ev = await pool.get(relays, filter, opts);
- }
-
- if (!ev) {
- filter = { cache: ["user_infos", { pubkeys }] };
- ev = (await pool.querySync([config.cache], filter, opts)).find(
- (e) => e.kind === 0,
- );
- }
-
- if (ev) {
- send(ev);
- profile = JSON.parse(ev.content);
- } else {
- profile = anon(pubkey);
- }
+ if (events.length) {
+ profile = JSON.parse(events[0].content);
+ } else {
+ profile = anon(pubkey);
}
- await s(`${pubkey}:profile`, profile);
+ await db.set(`profile:${pubkey}`, JSON.stringify(profile), { EX: 300 });
+
return profile;
};
diff --git a/routes/nostr.ts b/routes/nostr.ts
index f43f3517..21f85aea 100644
--- a/routes/nostr.ts
+++ b/routes/nostr.ts
@@ -1,5 +1,6 @@
import config from "$config";
import { db, g } from "$lib/db";
+import ln from "$lib/ln";
import {
anon,
getCount,
@@ -8,24 +9,69 @@ import {
send,
serverPubkey,
} from "$lib/nostr";
-import { scan } from "$lib/strfry";
+import { scan, sync } from "$lib/strfry";
import { bail, fail, fields, getUser } from "$lib/utils";
+import got from "got";
import { decode } from "nostr-tools/nip19";
import type { ProfilePointer } from "nostr-tools/nip19";
+import { getZapEndpoint, makeZapRequest } from "nostr-tools/nip57";
export default {
async event(req, res) {
- const {
- params: { id },
- } = req;
- const event = await g(`ev:${id}`);
- if (!event) return bail(res, "event not found");
+ let { id } = req.params;
+ if (id.startsWith("nevent")) id = decode(id).data.id;
+ if (id.startsWith("note")) id = decode(id).data;
+ const filter = { ids: [id] };
+ let events = await scan(filter);
+ if (!events.length) {
+ await sync("wss://relay.primal.net", filter);
+ events = await scan(filter);
+ }
+ if (!events.length) return bail(res, "event not found");
+ res.send(events[0]);
+ },
- const { pubkey } = event;
+ async zaps(req, res) {
+ try {
+ let { id } = req.params;
+ if (id.startsWith("nevent")) id = decode(id).data.id;
+ if (id.startsWith("note")) id = decode(id).data;
+ const filter = { kinds: [9735], "#e": [id] };
+ let events = await scan(filter);
+ if (!events.length) {
+ await sync("wss://relay.primal.net", filter);
+ events = await scan(filter);
+ }
+ if (!events.length) return bail(res, "event not found");
- event.user = (await g(`user:${pubkey}`)) || anon(pubkey);
+ const zaps = [];
+ for (const { tags } of events) {
+ const bolt11 = tags.find((t) => t[0] === "bolt11")?.[1];
+ const description = tags.find((t) => t[0] === "description")?.[1];
+ const { pubkey } = JSON.parse(description);
+ let amount = 0;
+ try {
+ const { amount_msat } = await ln.decode(bolt11);
+ if (amount_msat) amount = Math.round(amount_msat / 1000);
+ } catch (e) {}
- res.send(event);
+ let user;
+ if (pubkey) {
+ try {
+ user = await getUser(pubkey, fields);
+ if (!user) user = await getProfile(pubkey);
+ user.pubkey = pubkey;
+ } catch (e) {}
+ }
+
+ zaps.push({ amount, user });
+ }
+
+ res.send(zaps.filter((z) => z.amount > 0));
+ } catch (e) {
+ console.log(e);
+ bail(res, e.message);
+ }
},
async publish(req, res) {
@@ -180,4 +226,35 @@ export default {
recipient.relays = relays;
res.send(recipient);
},
+
+ async zapRequest(req, res) {
+ try {
+ const { amount, pubkey, id } = req.body;
+ const event = await makeZapRequest({
+ profile: pubkey,
+ event: id,
+ amount,
+ relays: [config.nostr],
+ comment: "",
+ });
+
+ res.send(event);
+ } catch (e) {
+ console.log(e);
+ }
+ },
+
+ async zap(req, res) {
+ const { event } = req.body;
+ const amount = event.tags.find((t) => t[0] === "amount")[1];
+ const pubkey = event.tags.find((t) => t[0] === "p")[1];
+ const content = JSON.stringify(await getProfile(pubkey));
+ const callback = await getZapEndpoint({ content });
+ const url = new URL(callback);
+ url.searchParams.set("amount", amount * 1000);
+ url.searchParams.set("nostr", encodeURIComponent(JSON.stringify(event)));
+ const json = await got(url.toString()).json();
+
+ res.send(json);
+ },
};