paid action limits (#1323)
This commit is contained in:
parent
67d71ef0c8
commit
df62cfb28c
@ -1,6 +1,6 @@
|
||||
import { createHodlInvoice, createInvoice, parsePaymentRequest } from 'ln-service'
|
||||
import { datePivot } from '@/lib/time'
|
||||
import { USER_ID } from '@/lib/constants'
|
||||
import { PAID_ACTION_TERMINAL_STATES, USER_ID } from '@/lib/constants'
|
||||
import { createHmac } from '../resolvers/wallet'
|
||||
import { Prisma } from '@prisma/client'
|
||||
import * as ITEM_CREATE from './itemCreate'
|
||||
@ -215,13 +215,30 @@ export async function retryPaidAction (actionType, args, context) {
|
||||
}
|
||||
|
||||
const INVOICE_EXPIRE_SECS = 600
|
||||
const MAX_PENDING_PAID_ACTIONS_PER_USER = 100
|
||||
|
||||
export async function createLightningInvoice (actionType, args, context) {
|
||||
// if the action has an invoiceable peer, we'll create a peer invoice
|
||||
// wrap it, and return the wrapped invoice
|
||||
const { cost, models, lnd } = context
|
||||
const { cost, models, lnd, me } = context
|
||||
const userId = await paidActions[actionType]?.invoiceablePeer?.(args, context)
|
||||
|
||||
// count pending invoices and bail if we're over the limit
|
||||
const pendingInvoices = await models.invoice.count({
|
||||
where: {
|
||||
userId: me?.id ?? USER_ID.anon,
|
||||
actionState: {
|
||||
// not in a terminal state. Note: null isn't counted by prisma
|
||||
notIn: PAID_ACTION_TERMINAL_STATES
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
console.log('pending paid actions', pendingInvoices)
|
||||
if (pendingInvoices >= MAX_PENDING_PAID_ACTIONS_PER_USER) {
|
||||
throw new Error('You have too many pending paid actions, cancel some or wait for them to expire')
|
||||
}
|
||||
|
||||
if (userId) {
|
||||
try {
|
||||
const description = await paidActions[actionType].describe(args, context)
|
||||
|
@ -3,6 +3,7 @@
|
||||
export const DEFAULT_SUBS = ['bitcoin', 'nostr', 'tech', 'meta', 'jobs']
|
||||
export const DEFAULT_SUBS_NO_JOBS = DEFAULT_SUBS.filter(s => s !== 'jobs')
|
||||
|
||||
export const PAID_ACTION_TERMINAL_STATES = ['FAILED', 'PAID', 'RETRYING']
|
||||
export const NOFOLLOW_LIMIT = 1000
|
||||
export const UNKNOWN_LINK_REL = 'noreferrer nofollow noopener'
|
||||
export const BOOST_MULT = 5000
|
||||
|
@ -7,9 +7,11 @@ import { addWalletLog } from '@/api/resolvers/wallet'
|
||||
import walletDefs from 'wallets/server'
|
||||
import { parsePaymentRequest } from 'ln-service'
|
||||
import { toPositiveNumber } from '@/lib/validate'
|
||||
|
||||
import { PAID_ACTION_TERMINAL_STATES } from '@/lib/constants'
|
||||
export default [lnd, cln, lnAddr, lnbits, nwc]
|
||||
|
||||
const MAX_PENDING_INVOICES_PER_WALLET = 25
|
||||
|
||||
export async function createInvoice (userId, { msats, description, descriptionHash, expiry = 360 }, { models }) {
|
||||
// get the wallets in order of priority
|
||||
const wallets = await models.wallet.findMany({
|
||||
@ -45,6 +47,31 @@ export async function createInvoice (userId, { msats, description, descriptionHa
|
||||
throw new Error(`no ${walletType} wallet found`)
|
||||
}
|
||||
|
||||
// check for pending withdrawals
|
||||
const pendingWithdrawals = await models.withdrawl.count({
|
||||
where: {
|
||||
walletId: walletFull.id,
|
||||
status: null
|
||||
}
|
||||
})
|
||||
|
||||
// and pending forwards
|
||||
const pendingForwards = await models.invoiceForward.count({
|
||||
where: {
|
||||
walletId: walletFull.id,
|
||||
invoice: {
|
||||
actionState: {
|
||||
notIn: PAID_ACTION_TERMINAL_STATES
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
console.log('pending invoices', pendingWithdrawals + pendingForwards)
|
||||
if (pendingWithdrawals + pendingForwards >= MAX_PENDING_INVOICES_PER_WALLET) {
|
||||
throw new Error('wallet has too many pending invoices')
|
||||
}
|
||||
|
||||
const invoice = await createInvoice({
|
||||
msats,
|
||||
description: wallet.user.hideInvoiceDesc ? undefined : description,
|
||||
|
@ -1,6 +1,6 @@
|
||||
import { getPaymentFailureStatus, hodlInvoiceCltvDetails } from '@/api/lnd'
|
||||
import { paidActions } from '@/api/paidAction'
|
||||
import { LND_PATHFINDING_TIMEOUT_MS } from '@/lib/constants'
|
||||
import { LND_PATHFINDING_TIMEOUT_MS, PAID_ACTION_TERMINAL_STATES } from '@/lib/constants'
|
||||
import { datePivot } from '@/lib/time'
|
||||
import { toPositiveNumber } from '@/lib/validate'
|
||||
import { Prisma } from '@prisma/client'
|
||||
@ -21,7 +21,7 @@ async function transitionInvoice (jobName, { invoiceId, fromState, toState, tran
|
||||
const currentDbInvoice = await models.invoice.findUnique({ where: { id: invoiceId } })
|
||||
console.log('invoice is in state', currentDbInvoice.actionState)
|
||||
|
||||
if (['FAILED', 'PAID', 'RETRYING'].includes(currentDbInvoice.actionState)) {
|
||||
if (PAID_ACTION_TERMINAL_STATES.includes(currentDbInvoice.actionState)) {
|
||||
console.log('invoice is already in a terminal state, skipping transition')
|
||||
return
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user