ca11ac9fb8
* wip backend optimism * another inch * make action state transitions only happen once * another inch * almost ready for testing * use interactive txs * another inch * ready for basic testing * lint fix * inches * wip item update * get item update to work * donate and downzap * inchy inch * fix territory paid actions * wip usePaidMutation * usePaidMutation error handling * PENDING_HELD and HELD transitions, gql paidAction return types * mostly working pessimism * make sure invoice field is present in optimisticResponse * inches * show optimistic values to current me * first pass at notifications and payment status reporting * fix migration to have withdrawal hash * reverse optimism on payment failure * Revert "Optimistic updates via pending sats in item context (#1229)" This reverts commit 93713b33df9bc3701dc5a692b86a04ff64e8cfb1. * add onCompleted to usePaidMutation * onPaid and onPayError for new comments * use 'IS DISTINCT FROM' for NULL invoiceActionState columns * make usePaidMutation easier to read * enhance invoice qr * prevent actions on unpaid items * allow navigation to action's invoice * retry create item * start edit window after item is paid for * fix ux of retries from notifications * refine retries * fix optimistic downzaps * remember item updates can't be retried * store reference to action item in invoice * remove invoice modal layout shift * fix destructuring * fix zap undos * make sure ItemAct is paid in aggregate queries * dont toast on long press zap undo * fix delete and remindme bots * optimistic poll votes with retries * fix retry notifications and invoice item context * fix pessimisitic typo * item mentions and mention notifications * dont show payment retry on item popover * make bios work * refactor paidAction transitions * remove stray console.log * restore docker compose nwc settings * add new todos * persist qr modal on post submission + unify item form submission * fix post edit threshold * make bounty payments work * make job posting work * remove more store procedure usage ... document serialization concerns * dont use dynamic imports for paid action modules * inline comment denormalization * create item starts with median votes * fix potential of serialization anomalies in zaps * dont trigger notification indicator on successful paid action invoices * ignore invoiceId on territory actions and add optimistic concurrency control * begin docs for paid actions * better error toasts and fix apollo cache warnings * small documentation enhancements * improve paid action docs * optimistic concurrency control for territory updates * use satsToMsats and msatsToSats helpers * explictly type raw query template parameters * improve consistency of nested relation names * complete paid action docs * useEffect for canEdit on payment * make sure invoiceId is provided when required * don't return null when expecting array * remove buy credits * move verifyPayment to paidAction * fix comments invoicePaidAt time zone * close nwc connections once * grouped logs for paid actions * stop invoiceWaitUntilPaid if not attempting to pay * allow actionState to transition directly from HELD to PAID * make paid mutation wait until pessimistic are fully paid * change button text when form submits/pays * pulsing form submit button * ignore me in notification indicator for territory subscription * filter unpaid items from more queries * fix donation stike timing * fix pending poll vote * fix recent item notifcation padding * no default form submitting button text * don't show paying on submit button on free edits * fix territory autorenew with fee credits * reorg readme * allow jobs to be editted forever * fix image uploads * more filter fixes for aggregate views * finalize paid action invoice expirations * remove unnecessary async * keep clientside cache normal/consistent * add more detail to paid action doc * improve paid action table * remove actionType guard * fix top territories * typo api/paidAction/README.md Co-authored-by: ekzyis <ek@stacker.news> * typo components/use-paid-mutation.js Co-authored-by: ekzyis <ek@stacker.news> * Apply suggestions from code review Co-authored-by: ekzyis <ek@stacker.news> * encorporate ek feeback * more ek suggestions * fix 'cost to post' hover on items * Apply suggestions from code review Co-authored-by: ekzyis <ek@stacker.news> --------- Co-authored-by: ekzyis <ek@stacker.news>
77 lines
3.1 KiB
JavaScript
77 lines
3.1 KiB
JavaScript
import { GraphQLError } from 'graphql'
|
|
import retry from 'async-retry'
|
|
import Prisma from '@prisma/client'
|
|
import { msatsToSats, numWithUnits } from '@/lib/format'
|
|
import { BALANCE_LIMIT_MSATS } from '@/lib/constants'
|
|
|
|
export default async function serialize (trx, { models, lnd }) {
|
|
// wrap first argument in array if not array already
|
|
const isArray = Array.isArray(trx)
|
|
if (!isArray) trx = [trx]
|
|
|
|
// conditional queries can be added inline using && syntax
|
|
// we filter any falsy value out here
|
|
trx = trx.filter(q => !!q)
|
|
|
|
const results = await retry(async bail => {
|
|
try {
|
|
const [, ...results] = await models.$transaction(
|
|
[models.$executeRaw`SELECT ASSERT_SERIALIZED()`, ...trx],
|
|
{ isolationLevel: Prisma.TransactionIsolationLevel.Serializable })
|
|
return results
|
|
} catch (error) {
|
|
console.log(error)
|
|
// two cases where we get insufficient funds:
|
|
// 1. plpgsql function raises
|
|
// 2. constraint violation via a prisma call
|
|
// XXX prisma does not provide a way to distinguish these cases so we
|
|
// have to check the error message
|
|
if (error.message.includes('SN_INSUFFICIENT_FUNDS') ||
|
|
error.message.includes('\\"users\\" violates check constraint \\"msats_positive\\"')) {
|
|
bail(new GraphQLError('insufficient funds', { extensions: { code: 'BAD_INPUT' } }))
|
|
}
|
|
if (error.message.includes('SN_NOT_SERIALIZABLE')) {
|
|
bail(new Error('wallet balance transaction is not serializable'))
|
|
}
|
|
if (error.message.includes('SN_CONFIRMED_WITHDRAWL_EXISTS')) {
|
|
bail(new Error('withdrawal invoice already confirmed (to withdraw again create a new invoice)'))
|
|
}
|
|
if (error.message.includes('SN_PENDING_WITHDRAWL_EXISTS')) {
|
|
bail(new Error('withdrawal invoice exists and is pending'))
|
|
}
|
|
if (error.message.includes('SN_INELIGIBLE')) {
|
|
bail(new Error('user ineligible for gift'))
|
|
}
|
|
if (error.message.includes('SN_UNSUPPORTED')) {
|
|
bail(new Error('unsupported action'))
|
|
}
|
|
if (error.message.includes('SN_DUPLICATE')) {
|
|
bail(new Error('duplicate not allowed'))
|
|
}
|
|
if (error.message.includes('SN_REVOKED_OR_EXHAUSTED')) {
|
|
bail(new Error('faucet has been revoked or is exhausted'))
|
|
}
|
|
if (error.message.includes('SN_INV_PENDING_LIMIT')) {
|
|
bail(new Error('too many pending invoices'))
|
|
}
|
|
if (error.message.includes('SN_INV_EXCEED_BALANCE')) {
|
|
bail(new Error(`pending invoices and withdrawals must not cause balance to exceed ${numWithUnits(msatsToSats(BALANCE_LIMIT_MSATS))}`))
|
|
}
|
|
if (error.message.includes('40001') || error.code === 'P2034') {
|
|
throw new Error('wallet balance serialization failure - try again')
|
|
}
|
|
if (error.message.includes('23514') || ['P2002', 'P2003', 'P2004'].includes(error.code)) {
|
|
bail(new Error('constraint failure'))
|
|
}
|
|
bail(error)
|
|
}
|
|
}, {
|
|
minTimeout: 10,
|
|
maxTimeout: 100,
|
|
retries: 10
|
|
})
|
|
|
|
// if first argument was not an array, unwrap the result
|
|
return isArray ? results : results[0]
|
|
}
|