diff --git a/src/deps.ts b/src/deps.ts index bf23f9e..fa7ff6f 100644 --- a/src/deps.ts +++ b/src/deps.ts @@ -91,6 +91,6 @@ export { type LNURLDetails, type MapCache, NIP05, -} from 'https://gitlab.com/soapbox-pub/nlib/-/raw/137af48cbc2639a8969d233fc24d2b959f34782a/mod.ts'; +} from 'https://gitlab.com/soapbox-pub/nlib/-/raw/5d711597f3b2a163817cc1fb0f1f3ce8cede7cf7/mod.ts'; export type * as TypeFest from 'npm:type-fest@^4.3.0'; diff --git a/src/pipeline.ts b/src/pipeline.ts index 7ec7c18..0a6fbac 100644 --- a/src/pipeline.ts +++ b/src/pipeline.ts @@ -3,10 +3,9 @@ import { encryptAdmin } from '@/crypto.ts'; import { addRelays } from '@/db/relays.ts'; import { deleteAttachedMedia } from '@/db/unattached-media.ts'; import { findUser } from '@/db/users.ts'; -import { Debug, type Event } from '@/deps.ts'; +import { Debug, type Event, LNURL } from '@/deps.ts'; import { isEphemeralKind } from '@/kinds.ts'; import { isLocallyFollowed } from '@/queries.ts'; -import { lnurlCallbackResponseSchema } from '@/schemas/lnurl.ts'; import { updateStats } from '@/stats.ts'; import { client, eventsDB, memorelay, reqmeister } from '@/storages.ts'; import { Sub } from '@/subs.ts'; @@ -39,7 +38,7 @@ async function handleEvent(event: Event): Promise { trackHashtags(event), fetchRelatedEvents(event, data), processMedia(event, data), - submitZaps(event, data), + payZap(event, data), streamOut(event, data), broadcast(event, data), ]); @@ -163,47 +162,48 @@ function processMedia({ tags, pubkey }: Event, { user }: EventData) { } } -/** Submit zap requests to Lightning nodes (for local users only). */ -async function submitZaps(event: Event, data: EventData, signal = AbortSignal.timeout(5000)) { - if (event.kind === 9734 && data.user) { - const lnurl = event.tags.find(([name]) => name === 'lnurl')?.[1]; - const amount = event.tags.find(([name]) => name === 'amount')?.[1]; - if (lnurl && amount) { - try { - const details = await lnurlCache.fetch(lnurl, { signal }); - if (details.tag === 'payRequest' && details.allowsNostr && details.nostrPubkey) { - const callback = new URL(details.callback); - const params = new URLSearchParams(); - params.set('amount', amount); - params.set('nostr', JSON.stringify(event)); - params.set('lnurl', lnurl); - callback.search = params.toString(); - const response = await fetchWorker(callback, { signal }); - const json = await response.json(); - const { pr } = lnurlCallbackResponseSchema.parse(json); - const nwcRequestEvent = await signAdminEvent({ - kind: 23194, - content: await encryptAdmin( - event.pubkey, - JSON.stringify({ - method: 'pay_invoice', - params: { - invoice: pr, - }, - }), - ), - created_at: nostrNow(), - tags: [ - ['p', event.pubkey], - ['e', event.id], - ], - }); - await handleEvent(nwcRequestEvent); - } - } catch (e) { - debug('lnurl error:', e); - } +/** Emit Nostr Wallet Connect event from zaps so users may pay. */ +async function payZap(event: Event, data: EventData, signal = AbortSignal.timeout(5000)) { + if (event.kind !== 9734 || !data.user) return; + + const lnurl = event.tags.find(([name]) => name === 'lnurl')?.[1]; + const amount = Number(event.tags.find(([name]) => name === 'amount')?.[1]); + + if (!lnurl || !amount) return; + + try { + const details = await lnurlCache.fetch(lnurl, { signal }); + + if (details.tag !== 'payRequest' || !details.allowsNostr || !details.nostrPubkey) { + throw new Error('invalid lnurl'); } + + if (amount > details.maxSendable || amount < details.minSendable) { + throw new Error('amount out of range'); + } + + const { pr } = await LNURL.callback( + details.callback, + { amount, nostr: event, lnurl }, + { fetch: fetchWorker, signal }, + ); + + const nwcRequestEvent = await signAdminEvent({ + kind: 23194, + content: await encryptAdmin( + event.pubkey, + JSON.stringify({ method: 'pay_invoice', params: { invoice: pr } }), + ), + created_at: nostrNow(), + tags: [ + ['p', event.pubkey], + ['e', event.id], + ], + }); + + await handleEvent(nwcRequestEvent); + } catch (e) { + debug('lnurl error:', e); } } diff --git a/src/schemas/lnurl.ts b/src/schemas/lnurl.ts deleted file mode 100644 index e16f68c..0000000 --- a/src/schemas/lnurl.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { z } from '@/deps.ts'; - -const lnurlCallbackResponseSchema = z.object({ - pr: z.string(), - routes: z.unknown().array(), -}); - -export { lnurlCallbackResponseSchema };