2024-07-01 12:02:29 -05:00
|
|
|
import { retryPaidAction } from '../paidAction'
|
2025-02-15 02:25:11 +01:00
|
|
|
import { USER_ID, WALLET_MAX_RETRIES, WALLET_RETRY_TIMEOUT_MS } from '@/lib/constants'
|
2024-07-04 12:30:42 -05:00
|
|
|
|
|
|
|
function paidActionType (actionType) {
|
|
|
|
switch (actionType) {
|
|
|
|
case 'ITEM_CREATE':
|
|
|
|
case 'ITEM_UPDATE':
|
|
|
|
return 'ItemPaidAction'
|
|
|
|
case 'ZAP':
|
|
|
|
case 'DOWN_ZAP':
|
2024-09-19 13:13:14 -05:00
|
|
|
case 'BOOST':
|
2024-07-04 12:30:42 -05:00
|
|
|
return 'ItemActPaidAction'
|
|
|
|
case 'TERRITORY_CREATE':
|
|
|
|
case 'TERRITORY_UPDATE':
|
|
|
|
case 'TERRITORY_BILLING':
|
|
|
|
case 'TERRITORY_UNARCHIVE':
|
|
|
|
return 'SubPaidAction'
|
|
|
|
case 'DONATE':
|
|
|
|
return 'DonatePaidAction'
|
|
|
|
case 'POLL_VOTE':
|
|
|
|
return 'PollVotePaidAction'
|
2024-11-16 01:38:14 +01:00
|
|
|
case 'RECEIVE':
|
|
|
|
return 'ReceivePaidAction'
|
2025-01-03 10:33:07 -06:00
|
|
|
case 'BUY_CREDITS':
|
|
|
|
return 'BuyCreditsPaidAction'
|
2024-07-04 12:30:42 -05:00
|
|
|
default:
|
|
|
|
throw new Error('Unknown action type')
|
|
|
|
}
|
|
|
|
}
|
2024-07-01 12:02:29 -05:00
|
|
|
|
|
|
|
export default {
|
2024-07-04 12:30:42 -05:00
|
|
|
Query: {
|
|
|
|
paidAction: async (parent, { invoiceId }, { models, me }) => {
|
2024-08-13 09:48:30 -05:00
|
|
|
const invoice = await models.invoice.findUnique({
|
|
|
|
where: {
|
|
|
|
id: invoiceId,
|
|
|
|
userId: me?.id ?? USER_ID.anon
|
|
|
|
}
|
|
|
|
})
|
2024-07-04 12:30:42 -05:00
|
|
|
if (!invoice) {
|
|
|
|
throw new Error('Invoice not found')
|
|
|
|
}
|
|
|
|
|
|
|
|
return {
|
|
|
|
type: paidActionType(invoice.actionType),
|
|
|
|
invoice,
|
|
|
|
result: invoice.actionResult,
|
2024-08-13 09:48:30 -05:00
|
|
|
paymentMethod: invoice.actionOptimistic ? 'OPTIMISTIC' : 'PESSIMISTIC'
|
2024-07-04 12:30:42 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
},
|
2024-07-01 12:02:29 -05:00
|
|
|
Mutation: {
|
2025-02-15 02:25:11 +01:00
|
|
|
retryPaidAction: async (parent, { invoiceId, newAttempt }, { models, me, lnd }) => {
|
2024-07-01 12:02:29 -05:00
|
|
|
if (!me) {
|
|
|
|
throw new Error('You must be logged in')
|
|
|
|
}
|
|
|
|
|
2025-02-15 02:25:11 +01:00
|
|
|
// make sure only one client at a time can retry by acquiring a lock that expires
|
|
|
|
const [invoice] = await models.$queryRaw`
|
|
|
|
UPDATE "Invoice"
|
|
|
|
SET "retryPendingSince" = now()
|
|
|
|
WHERE
|
|
|
|
id = ${invoiceId} AND
|
|
|
|
"userId" = ${me.id} AND
|
|
|
|
"actionState" = 'FAILED' AND
|
|
|
|
("retryPendingSince" IS NULL OR "retryPendingSince" < now() - ${`${WALLET_RETRY_TIMEOUT_MS} milliseconds`}::interval)
|
|
|
|
RETURNING *`
|
2024-07-01 12:02:29 -05:00
|
|
|
if (!invoice) {
|
2025-02-15 02:25:11 +01:00
|
|
|
throw new Error('Invoice not found or retry pending')
|
2024-07-01 12:02:29 -05:00
|
|
|
}
|
|
|
|
|
2025-02-15 02:25:11 +01:00
|
|
|
// do we want to retry a payment from the beginning with all sender and receiver wallets?
|
|
|
|
const paymentAttempt = newAttempt ? invoice.paymentAttempt + 1 : invoice.paymentAttempt
|
|
|
|
if (paymentAttempt > WALLET_MAX_RETRIES) {
|
|
|
|
throw new Error('Payment has been retried too many times')
|
2024-09-25 13:32:52 -05:00
|
|
|
}
|
|
|
|
|
2025-02-15 02:25:11 +01:00
|
|
|
const result = await retryPaidAction(invoice.actionType, { invoice }, { paymentAttempt, models, me, lnd })
|
2024-07-01 12:02:29 -05:00
|
|
|
|
|
|
|
return {
|
|
|
|
...result,
|
2024-07-04 12:30:42 -05:00
|
|
|
type: paidActionType(invoice.actionType)
|
2024-07-01 12:02:29 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
},
|
|
|
|
PaidAction: {
|
|
|
|
__resolveType: obj => obj.type
|
|
|
|
}
|
|
|
|
}
|