feat: hydrate zap receipt kind 9735 - gatherZapSender, gatherZapped

This commit is contained in:
P. Reis 2024-09-16 13:13:55 -03:00
parent 6e2508063b
commit a2077e3d40

View file

@ -1,12 +1,15 @@
import { NStore } from '@nostrify/nostrify'; import { NStore } from '@nostrify/nostrify';
import { Kysely } from 'kysely'; import { Kysely } from 'kysely';
import { matchFilter } from 'nostr-tools'; import { matchFilter } from 'nostr-tools';
import { NSchema as n } from '@nostrify/nostrify';
import { z } from 'zod';
import { DittoTables } from '@/db/DittoTables.ts'; import { DittoTables } from '@/db/DittoTables.ts';
import { Conf } from '@/config.ts'; import { Conf } from '@/config.ts';
import { type DittoEvent } from '@/interfaces/DittoEvent.ts'; import { type DittoEvent } from '@/interfaces/DittoEvent.ts';
import { findQuoteTag } from '@/utils/tags.ts'; import { findQuoteTag } from '@/utils/tags.ts';
import { findQuoteInContent } from '@/utils/note.ts'; import { findQuoteInContent } from '@/utils/note.ts';
import { getAmount } from '@/utils/bolt11.ts';
import { Storages } from '@/storages.ts'; import { Storages } from '@/storages.ts';
interface HydrateOpts { interface HydrateOpts {
@ -58,6 +61,14 @@ async function hydrateEvents(opts: HydrateOpts): Promise<DittoEvent[]> {
cache.push(event); cache.push(event);
} }
for (const event of await gatherZapped({ events: cache, store, signal })) {
cache.push(event);
}
for (const event of await gatherZapSender({ events: cache, store, signal })) {
cache.push(event);
}
const stats = { const stats = {
authors: await gatherAuthorStats(cache, kysely as Kysely<DittoTables>), authors: await gatherAuthorStats(cache, kysely as Kysely<DittoTables>),
events: await gatherEventStats(cache, kysely as Kysely<DittoTables>), events: await gatherEventStats(cache, kysely as Kysely<DittoTables>),
@ -130,6 +141,27 @@ export function assembleEvents(
event.reported_notes = reportedEvents; event.reported_notes = reportedEvents;
} }
if (event.kind === 9735) {
const amountSchema = z.coerce.number().int().nonnegative().catch(0);
// amount in millisats
const amount = amountSchema.parse(getAmount(event?.tags.find(([name]) => name === 'bolt11')?.[1]));
event.zap_amount = amount;
const id = event.tags.find(([name]) => name === 'e')?.[1];
if (id) {
event.zapped = b.find((e) => matchFilter({ kinds: [1], ids: [id] }, e));
}
const zapRequestString = event?.tags?.find(([name]) => name === 'description')?.[1];
const zapRequest = n.json().pipe(n.event()).optional().catch(undefined).parse(zapRequestString);
// By getting the pubkey from the zap request we guarantee who is the sender
// some clients don't put the P tag in the zap receipt...
const zapSender = zapRequest?.pubkey;
if (zapSender) {
event.zap_sender = b.find((e) => matchFilter({ kinds: [0], authors: [zapSender] }, e)) ?? zapSender;
}
}
event.author_stats = stats.authors.find((stats) => stats.pubkey === event.pubkey); event.author_stats = stats.authors.find((stats) => stats.pubkey === event.pubkey);
event.event_stats = eventStats.find((stats) => stats.event_id === event.id); event.event_stats = eventStats.find((stats) => stats.event_id === event.id);
} }
@ -277,6 +309,48 @@ function gatherReportedProfiles({ events, store, signal }: HydrateOpts): Promise
); );
} }
/** Collect events being zapped. */
function gatherZapped({ events, store, signal }: HydrateOpts): Promise<DittoEvent[]> {
const ids = new Set<string>();
for (const event of events) {
if (event.kind === 9735) {
const id = event.tags.find(([name]) => name === 'e')?.[1];
if (id) {
ids.add(id);
}
}
}
return store.query(
[{ ids: [...ids], limit: ids.size }],
{ signal },
);
}
/** Collect author that zapped. */
function gatherZapSender({ events, store, signal }: HydrateOpts): Promise<DittoEvent[]> {
const pubkeys = new Set<string>();
for (const event of events) {
if (event.kind === 9735) {
const zapRequestString = event?.tags?.find(([name]) => name === 'description')?.[1];
const zapRequest = n.json().pipe(n.event()).optional().catch(undefined).parse(zapRequestString);
// By getting the pubkey from the zap request we guarantee who is the sender
// some clients don't put the P tag in the zap receipt...
const zapSender = zapRequest?.pubkey;
if (zapSender) {
pubkeys.add(zapSender);
}
}
}
return store.query(
[{ kinds: [0], limit: pubkeys.size }],
{ signal },
);
}
/** Collect author stats from the events. */ /** Collect author stats from the events. */
async function gatherAuthorStats( async function gatherAuthorStats(
events: DittoEvent[], events: DittoEvent[],