2021-10-07 18:37:59 +00:00
|
|
|
import models from '../../../../api/models'
|
|
|
|
import lnd from '../../../../api/lnd'
|
|
|
|
import { createInvoice } from 'ln-service'
|
2023-02-15 17:20:26 +00:00
|
|
|
import { lnurlPayDescriptionHashForUser } from '../../../../lib/lnurl'
|
2022-01-09 16:50:51 +00:00
|
|
|
import serialize from '../../../../api/resolvers/serial'
|
2023-02-14 18:46:34 +00:00
|
|
|
import * as secp256k1 from '@noble/secp256k1'
|
|
|
|
import { createHash } from 'crypto'
|
2021-10-07 18:37:59 +00:00
|
|
|
|
2023-02-14 18:46:34 +00:00
|
|
|
export default async ({ query: { username, amount, nostr } }, res) => {
|
2021-10-07 18:37:59 +00:00
|
|
|
const user = await models.user.findUnique({ where: { name: username } })
|
|
|
|
if (!user) {
|
|
|
|
return res.status(400).json({ status: 'ERROR', reason: `user @${username} does not exist` })
|
|
|
|
}
|
2023-02-14 18:46:34 +00:00
|
|
|
try {
|
|
|
|
// if nostr, decode, validate sig, check tags, set description hash
|
2023-02-15 17:20:26 +00:00
|
|
|
let description, descriptionHash, noteStr
|
2023-02-14 18:46:34 +00:00
|
|
|
if (nostr) {
|
2023-02-15 17:20:26 +00:00
|
|
|
noteStr = decodeURIComponent(nostr)
|
2023-02-14 18:46:34 +00:00
|
|
|
const note = JSON.parse(noteStr)
|
|
|
|
const hasPTag = note.tags?.filter(t => t[0] === 'p').length >= 1
|
|
|
|
const hasETag = note.tags?.filter(t => t[0] === 'e').length <= 1
|
|
|
|
if (await secp256k1.schnorr.verify(note.sig, note.id, note.pubkey) &&
|
|
|
|
hasPTag && hasETag) {
|
2023-02-15 17:20:26 +00:00
|
|
|
description = user.hideInvoiceDesc ? undefined : 'zap'
|
2023-02-14 18:46:34 +00:00
|
|
|
descriptionHash = createHash('sha256').update(noteStr).digest('hex')
|
|
|
|
} else {
|
|
|
|
res.status(400).json({ status: 'ERROR', reason: 'invalid NIP-57 note' })
|
|
|
|
return
|
|
|
|
}
|
|
|
|
} else {
|
2023-02-15 17:20:26 +00:00
|
|
|
description = user.hideInvoiceDesc ? undefined : `Funding @${username} on stacker.news`
|
2023-02-14 18:46:34 +00:00
|
|
|
descriptionHash = lnurlPayDescriptionHashForUser(username)
|
|
|
|
}
|
2021-10-07 18:37:59 +00:00
|
|
|
|
2023-02-14 18:46:34 +00:00
|
|
|
if (!amount || amount < 1000) {
|
|
|
|
return res.status(400).json({ status: 'ERROR', reason: 'amount must be >=1000 msats' })
|
|
|
|
}
|
2021-10-07 18:37:59 +00:00
|
|
|
|
2023-02-14 18:46:34 +00:00
|
|
|
// generate invoice
|
|
|
|
const expiresAt = new Date(new Date().setMinutes(new Date().getMinutes() + 1))
|
2021-10-07 18:37:59 +00:00
|
|
|
const invoice = await createInvoice({
|
2023-02-14 18:46:34 +00:00
|
|
|
description: description,
|
2021-10-07 20:36:12 +00:00
|
|
|
description_hash: descriptionHash,
|
2021-10-07 18:37:59 +00:00
|
|
|
lnd,
|
|
|
|
mtokens: amount,
|
|
|
|
expires_at: expiresAt
|
|
|
|
})
|
|
|
|
|
2022-01-09 16:50:51 +00:00
|
|
|
await serialize(models,
|
|
|
|
models.$queryRaw`SELECT * FROM create_invoice(${invoice.id}, ${invoice.request},
|
2023-02-15 17:20:26 +00:00
|
|
|
${expiresAt}, ${Number(amount)}, ${user.id}, ${noteStr || description})`)
|
2021-10-07 18:37:59 +00:00
|
|
|
|
|
|
|
return res.status(200).json({
|
2022-05-19 13:18:28 +00:00
|
|
|
pr: invoice.request,
|
|
|
|
routes: []
|
2021-10-07 18:37:59 +00:00
|
|
|
})
|
|
|
|
} catch (error) {
|
|
|
|
console.log(error)
|
2022-08-30 20:33:39 +00:00
|
|
|
res.status(400).json({ status: 'ERROR', reason: error.message })
|
2021-10-07 18:37:59 +00:00
|
|
|
}
|
|
|
|
}
|