Skip to content

Commit

Permalink
Only attempt payment 3 times
Browse files Browse the repository at this point in the history
  • Loading branch information
ekzyis committed Jan 7, 2025
1 parent 3e5cdcd commit 69d12f1
Show file tree
Hide file tree
Showing 6 changed files with 23 additions and 7 deletions.
7 changes: 5 additions & 2 deletions api/paidAction/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -328,7 +328,9 @@ export async function retryPaidAction (actionType, args, incomingContext) {
me: await models.user.findUnique({ where: { id: parseInt(me.id) } }),
cost: BigInt(msatsRequested),
actionId,
predecessorId: failedInvoice.id
predecessorId: failedInvoice.id,
// a locked invoice means we're retrying a payment from the beginning with all sender and receiver wallets
retry: failedInvoice.lockedAt ? failedInvoice.retry + 1 : failedInvoice.retry
}

let invoiceArgs
Expand Down Expand Up @@ -419,7 +421,7 @@ async function createSNInvoice (actionType, args, context) {
}

async function createDbInvoice (actionType, args, context) {
const { me, models, tx, cost, optimistic, actionId, invoiceArgs, predecessorId } = context
const { me, models, tx, cost, optimistic, actionId, invoiceArgs, retry, predecessorId } = context
const { bolt11, wrappedBolt11, preimage, wallet, maxFee } = invoiceArgs

const db = tx ?? models
Expand All @@ -445,6 +447,7 @@ async function createDbInvoice (actionType, args, context) {
actionArgs: args,
expiresAt,
actionId,
retry,
predecessorId
}

Expand Down
4 changes: 4 additions & 0 deletions api/resolvers/paidAction.js
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,10 @@ export default {
throw new Error(`Invoice is not in failed state: ${invoice.actionState}`)
}

if (invoice.retry > 2) {
throw new Error('Payment has been retried too many times')
}

const result = await retryPaidAction(invoice.actionType, { invoice }, { models, me, lnd })

return {
Expand Down
1 change: 1 addition & 0 deletions api/resolvers/wallet.js
Original file line number Diff line number Diff line change
Expand Up @@ -480,6 +480,7 @@ const resolvers = {
"cancelledAt" + $3::interval
)
AND "lockedAt" IS NULL
AND "retry" < 2
ORDER BY id DESC
FOR UPDATE SKIP LOCKED
)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
-- AlterTable
ALTER TABLE "Invoice" ADD COLUMN "retry" INTEGER NOT NULL DEFAULT 0;
1 change: 1 addition & 0 deletions prisma/schema.prisma
Original file line number Diff line number Diff line change
Expand Up @@ -925,6 +925,7 @@ model Invoice {
cancelledAt DateTime?
userCancel Boolean?
lockedAt DateTime?
retry Int @default(0)
msatsRequested BigInt
msatsReceived BigInt?
desc String?
Expand Down
15 changes: 10 additions & 5 deletions wallets/server.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,13 @@ export default [lnd, cln, lnAddr, lnbits, nwc, phoenixd, blink, lnc, webln]

const MAX_PENDING_INVOICES_PER_WALLET = 25

export async function createInvoice (userId, { msats, description, descriptionHash, expiry = 360 }, { predecessorId, models }) {
export async function createInvoice (userId, { msats, description, descriptionHash, expiry = 360 }, { retry, predecessorId, models }) {
// get the wallets in order of priority
const wallets = await getInvoiceableWallets(userId, { predecessorId, models })
const wallets = await getInvoiceableWallets(userId, {
retry,
predecessorId,
models
})

msats = toPositiveNumber(msats)

Expand Down Expand Up @@ -81,7 +85,7 @@ export async function createInvoice (userId, { msats, description, descriptionHa

export async function createWrappedInvoice (userId,
{ msats, feePercent, description, descriptionHash, expiry = 360 },
{ predecessorId, models, me, lnd }) {
{ retry, predecessorId, models, me, lnd }) {
let logger, bolt11
try {
const { invoice, wallet } = await createInvoice(userId, {
Expand All @@ -90,7 +94,7 @@ export async function createWrappedInvoice (userId,
description,
descriptionHash,
expiry
}, { predecessorId, models })
}, { retry, predecessorId, models })

logger = walletLogger({ wallet, models })
bolt11 = invoice
Expand All @@ -110,7 +114,7 @@ export async function createWrappedInvoice (userId,
}
}

export async function getInvoiceableWallets (userId, { predecessorId, models }) {
export async function getInvoiceableWallets (userId, { retry, predecessorId, models }) {
// filter out all wallets that have already been tried by recursively following the retry chain of predecessor invoices.
// the current predecessor invoice is in state 'FAILED' and not in state 'RETRYING' because we are currently retrying it
// so it has not been updated yet.
Expand Down Expand Up @@ -143,6 +147,7 @@ export async function getInvoiceableWallets (userId, { predecessorId, models })
FROM "Invoice"
JOIN "Retries" ON "Invoice"."id" = "Retries"."predecessorId"
WHERE "Invoice"."actionState" = 'RETRYING'
AND "Invoice"."retry" = ${retry}
)
SELECT
"InvoiceForward"."walletId"
Expand Down

0 comments on commit 69d12f1

Please sign in to comment.