Support JIT invoicing on donations to rewards pool (#515)
* Support JIT invoicing on donations to rewards pool Now you can just-in-time fund your account to donate to SN's reward pool. You can also donate without an account via the @anon account, also using JIT invoices. * Ensure donate amount is numeric * Explicit error checking for hash being required for invoice validation * let donation exceptions bubble for jit funding --------- Co-authored-by: keyan <keyan.kousha+huumn@gmail.com>
This commit is contained in:
parent
9f333518c1
commit
9c774d596b
|
@ -38,7 +38,10 @@ export async function commentFilterClause (me, models) {
|
|||
return clause
|
||||
}
|
||||
|
||||
async function checkInvoice (models, hash, hmac, fee) {
|
||||
export async function checkInvoice (models, hash, hmac, fee) {
|
||||
if (!hash) {
|
||||
throw new GraphQLError('hash required', { extensions: { code: 'BAD_INPUT' } })
|
||||
}
|
||||
if (!hmac) {
|
||||
throw new GraphQLError('hmac required', { extensions: { code: 'BAD_INPUT' } })
|
||||
}
|
||||
|
|
|
@ -1,8 +1,9 @@
|
|||
import { GraphQLError } from 'graphql'
|
||||
import { settleHodlInvoice } from 'ln-service'
|
||||
import { amountSchema, ssValidate } from '../../lib/validate'
|
||||
import serialize from './serial'
|
||||
import { ANON_USER_ID } from '../../lib/constants'
|
||||
import { getItem } from './item'
|
||||
import { getItem, checkInvoice } from './item'
|
||||
|
||||
export default {
|
||||
Query: {
|
||||
|
@ -102,17 +103,38 @@ export default {
|
|||
}
|
||||
},
|
||||
Mutation: {
|
||||
donateToRewards: async (parent, { sats }, { me, models }) => {
|
||||
if (!me) {
|
||||
throw new GraphQLError('you must be logged in', { extensions: { code: 'UNAUTHENTICATED' } })
|
||||
donateToRewards: async (parent, { sats, hash, hmac }, { me, models, lnd }) => {
|
||||
if (!me && !hash) {
|
||||
throw new GraphQLError('you must be logged in or pay', { extensions: { code: 'FORBIDDEN' } })
|
||||
}
|
||||
let user
|
||||
if (me) {
|
||||
user = me
|
||||
}
|
||||
|
||||
let invoice
|
||||
if (hash) {
|
||||
invoice = await checkInvoice(models, hash, hmac, sats)
|
||||
user = invoice.user
|
||||
}
|
||||
|
||||
await ssValidate(amountSchema, { amount: sats })
|
||||
|
||||
await serialize(models,
|
||||
const trx = [
|
||||
models.$queryRawUnsafe(
|
||||
'SELECT donate($1::INTEGER, $2::INTEGER)',
|
||||
sats, Number(me.id)))
|
||||
sats, Number(user.id))
|
||||
]
|
||||
|
||||
if (invoice) {
|
||||
trx.unshift(models.$queryRaw`UPDATE users SET msats = msats + ${invoice.msatsReceived} WHERE id = ${user.id}`)
|
||||
trx.push(models.invoice.update({ where: { hash: invoice.hash }, data: { confirmedAt: new Date() } }))
|
||||
}
|
||||
await serialize(models, ...trx)
|
||||
|
||||
if (invoice?.isHeld) {
|
||||
await settleHodlInvoice({ secret: invoice.preimage, lnd })
|
||||
}
|
||||
|
||||
return sats
|
||||
}
|
||||
|
|
|
@ -7,7 +7,7 @@ export default gql`
|
|||
}
|
||||
|
||||
extend type Mutation {
|
||||
donateToRewards(sats: Int!): Int!
|
||||
donateToRewards(sats: Int!, hash: String, hmac: String): Int!
|
||||
}
|
||||
|
||||
type Rewards {
|
||||
|
|
|
@ -92,8 +92,8 @@ export function DonateButton () {
|
|||
const toaster = useToast()
|
||||
const [donateToRewards] = useMutation(
|
||||
gql`
|
||||
mutation donateToRewards($sats: Int!) {
|
||||
donateToRewards(sats: $sats)
|
||||
mutation donateToRewards($sats: Int!, $hash: String, $hmac: String) {
|
||||
donateToRewards(sats: $sats, hash: $hash, hmac: $hmac)
|
||||
}`)
|
||||
|
||||
return (
|
||||
|
@ -104,24 +104,28 @@ export function DonateButton () {
|
|||
amount: 1000
|
||||
}}
|
||||
schema={amountSchema}
|
||||
onSubmit={async ({ amount }) => {
|
||||
try {
|
||||
await donateToRewards({
|
||||
variables: {
|
||||
sats: Number(amount)
|
||||
}
|
||||
})
|
||||
onClose()
|
||||
toaster.success('donated')
|
||||
} catch (err) {
|
||||
console.error(err)
|
||||
invoiceable
|
||||
onSubmit={async ({ amount, hash, hmac }) => {
|
||||
const { error } = await donateToRewards({
|
||||
variables: {
|
||||
sats: Number(amount),
|
||||
hash,
|
||||
hmac
|
||||
}
|
||||
})
|
||||
if (error) {
|
||||
console.error(error)
|
||||
toaster.danger('failed to donate')
|
||||
} else {
|
||||
toaster.success('donated')
|
||||
}
|
||||
onClose()
|
||||
}}
|
||||
>
|
||||
<Input
|
||||
label='amount'
|
||||
name='amount'
|
||||
type='number'
|
||||
required
|
||||
autoFocus
|
||||
append={<InputGroup.Text className='text-monospace'>sats</InputGroup.Text>}
|
||||
|
|
Loading…
Reference in New Issue