Remove NWC, return a Ln-Invoice header on the zap endpoint
This commit is contained in:
parent
a690fa3096
commit
78044cc8b6
|
@ -15,7 +15,7 @@ import { renderReblog, renderStatus } from '@/views/mastodon/statuses.ts';
|
|||
import { Storages } from '@/storages.ts';
|
||||
import { hydrateEvents } from '@/storages/hydrate.ts';
|
||||
import { createEvent, paginationSchema, parseBody, updateListEvent } from '@/utils/api.ts';
|
||||
import { getLnurl } from '@/utils/lnurl.ts';
|
||||
import { getInvoice, getLnurl } from '@/utils/lnurl.ts';
|
||||
import { lookupPubkey } from '@/utils/lookup.ts';
|
||||
import { addTag, deleteTag } from '@/utils/tags.ts';
|
||||
import { asyncReplaceAll } from '@/utils/text.ts';
|
||||
|
@ -450,15 +450,16 @@ const zapController: AppController = async (c) => {
|
|||
const author = target?.author;
|
||||
const meta = n.json().pipe(n.metadata()).catch({}).parse(author?.content);
|
||||
const lnurl = getLnurl(meta);
|
||||
const amount = params.data.amount;
|
||||
|
||||
if (target && lnurl) {
|
||||
await createEvent({
|
||||
const nostr = await createEvent({
|
||||
kind: 9734,
|
||||
content: params.data.comment ?? '',
|
||||
tags: [
|
||||
['e', target.id],
|
||||
['p', target.pubkey],
|
||||
['amount', params.data.amount.toString()],
|
||||
['amount', amount.toString()],
|
||||
['relays', Conf.relay],
|
||||
['lnurl', lnurl],
|
||||
],
|
||||
|
@ -467,7 +468,11 @@ const zapController: AppController = async (c) => {
|
|||
const status = await renderStatus(target, { viewerPubkey: await c.get('signer')?.getPublicKey() });
|
||||
status.zapped = true;
|
||||
|
||||
return c.json(status);
|
||||
return c.json(status, {
|
||||
headers: {
|
||||
'Ln-Invoice': await getInvoice({ amount, nostr, lnurl }, signal),
|
||||
},
|
||||
});
|
||||
} else {
|
||||
return c.json({ error: 'Event not found.' }, 404);
|
||||
}
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
import { NKinds, NostrEvent, NPolicy, NSchema as n } from '@nostrify/nostrify';
|
||||
import { LNURL } from '@nostrify/nostrify/ln';
|
||||
import { PipePolicy } from '@nostrify/nostrify/policies';
|
||||
import Debug from '@soapbox/stickynotes/debug';
|
||||
import { sql } from 'kysely';
|
||||
|
@ -12,15 +11,12 @@ import { DittoEvent } from '@/interfaces/DittoEvent.ts';
|
|||
import { DVM } from '@/pipeline/DVM.ts';
|
||||
import { MuteListPolicy } from '@/policies/MuteListPolicy.ts';
|
||||
import { RelayError } from '@/RelayError.ts';
|
||||
import { hydrateEvents, purifyEvent } from '@/storages/hydrate.ts';
|
||||
import { hydrateEvents } from '@/storages/hydrate.ts';
|
||||
import { Storages } from '@/storages.ts';
|
||||
import { eventAge, nostrDate, nostrNow, parseNip05, Time } from '@/utils.ts';
|
||||
import { fetchWorker } from '@/workers/fetch.ts';
|
||||
import { eventAge, nostrDate, parseNip05, Time } from '@/utils.ts';
|
||||
import { policyWorker } from '@/workers/policy.ts';
|
||||
import { TrendsWorker } from '@/workers/trends.ts';
|
||||
import { verifyEventWorker } from '@/workers/verify.ts';
|
||||
import { AdminSigner } from '@/signers/AdminSigner.ts';
|
||||
import { lnurlCache } from '@/utils/lnurl.ts';
|
||||
import { nip05Cache } from '@/utils/nip05.ts';
|
||||
import { updateStats } from '@/utils/stats.ts';
|
||||
import { getTagSet } from '@/utils/tags.ts';
|
||||
|
@ -48,7 +44,6 @@ async function handleEvent(event: DittoEvent, signal: AbortSignal): Promise<void
|
|||
DVM.event(event),
|
||||
trackHashtags(event),
|
||||
processMedia(event),
|
||||
payZap(event, signal),
|
||||
streamOut(event),
|
||||
]);
|
||||
}
|
||||
|
@ -189,53 +184,6 @@ function processMedia({ tags, pubkey, user }: DittoEvent) {
|
|||
}
|
||||
}
|
||||
|
||||
/** Emit Nostr Wallet Connect event from zaps so users may pay. */
|
||||
async function payZap(event: DittoEvent, signal: AbortSignal) {
|
||||
if (event.kind !== 9734) 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: purifyEvent(event), lnurl },
|
||||
{ fetch: fetchWorker, signal },
|
||||
);
|
||||
|
||||
const signer = new AdminSigner();
|
||||
|
||||
const nwcRequestEvent = await signer.signEvent({
|
||||
kind: 23194,
|
||||
content: await signer.nip04.encrypt(
|
||||
event.pubkey,
|
||||
JSON.stringify({ method: 'pay_invoice', params: { invoice: pr } }),
|
||||
),
|
||||
created_at: nostrNow(),
|
||||
tags: [
|
||||
['p', event.pubkey],
|
||||
['e', event.id],
|
||||
],
|
||||
});
|
||||
|
||||
await handleEvent(nwcRequestEvent, signal);
|
||||
} catch (e) {
|
||||
debug('lnurl error:', e);
|
||||
}
|
||||
}
|
||||
|
||||
/** Determine if the event is being received in a timely manner. */
|
||||
function isFresh(event: NostrEvent): boolean {
|
||||
return eventAge(event) < Time.seconds(10);
|
||||
|
|
|
@ -4,6 +4,7 @@ import Debug from '@soapbox/stickynotes/debug';
|
|||
import { SimpleLRU } from '@/utils/SimpleLRU.ts';
|
||||
import { Time } from '@/utils/time.ts';
|
||||
import { fetchWorker } from '@/workers/fetch.ts';
|
||||
import { NostrEvent } from '@nostrify/nostrify';
|
||||
|
||||
const debug = Debug('ditto:lnurl');
|
||||
|
||||
|
@ -38,4 +39,32 @@ function getLnurl({ lud06, lud16 }: { lud06?: string; lud16?: string }, limit?:
|
|||
}
|
||||
}
|
||||
|
||||
export { getLnurl, lnurlCache };
|
||||
interface CallbackParams {
|
||||
amount: number;
|
||||
nostr: NostrEvent;
|
||||
lnurl: string;
|
||||
}
|
||||
|
||||
async function getInvoice(params: CallbackParams, signal?: AbortSignal): Promise<string> {
|
||||
const { amount, lnurl } = params;
|
||||
|
||||
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,
|
||||
params,
|
||||
{ fetch: fetchWorker, signal },
|
||||
);
|
||||
|
||||
return pr;
|
||||
}
|
||||
|
||||
export { getInvoice, getLnurl, lnurlCache };
|
||||
|
|
Loading…
Reference in New Issue