Fix receiver fallback on caller error (#1907)
* Rename to createUserInvoice * Fix no receiver fallback on wrap, direct or autowithdrawal error * Fix missing error logs for direct payments
This commit is contained in:
parent
0032e064b2
commit
5e85147578
@ -3,7 +3,7 @@ import { datePivot } from '@/lib/time'
|
||||
import { PAID_ACTION_PAYMENT_METHODS, USER_ID } from '@/lib/constants'
|
||||
import { createHmac } from '@/api/resolvers/wallet'
|
||||
import { Prisma } from '@prisma/client'
|
||||
import { createWrappedInvoice, createInvoice as createUserInvoice } from '@/wallets/server'
|
||||
import { createWrappedInvoice, createUserInvoice } from '@/wallets/server'
|
||||
import { assertBelowMaxPendingInvoices, assertBelowMaxPendingDirectPayments } from './lib/assert'
|
||||
|
||||
import * as ITEM_CREATE from './itemCreate'
|
||||
@ -264,42 +264,51 @@ async function performDirectAction (actionType, args, incomingContext) {
|
||||
throw new NonInvoiceablePeerError()
|
||||
}
|
||||
|
||||
let invoiceObject
|
||||
|
||||
try {
|
||||
await assertBelowMaxPendingDirectPayments(userId, incomingContext)
|
||||
|
||||
const description = actionDescription ?? await paidActions[actionType].describe(args, incomingContext)
|
||||
invoiceObject = await createUserInvoice(userId, {
|
||||
|
||||
for await (const { invoice, logger, wallet } of createUserInvoice(userId, {
|
||||
msats: cost,
|
||||
description,
|
||||
expiry: INVOICE_EXPIRE_SECS
|
||||
}, { models, lnd })
|
||||
} catch (e) {
|
||||
console.error('failed to create outside invoice', e)
|
||||
throw new NonInvoiceablePeerError()
|
||||
}
|
||||
}, { models, lnd })) {
|
||||
let hash
|
||||
try {
|
||||
hash = parsePaymentRequest({ request: invoice }).id
|
||||
} catch (e) {
|
||||
console.error('failed to parse invoice', e)
|
||||
logger?.error('failed to parse invoice: ' + e.message, { bolt11: invoice })
|
||||
continue
|
||||
}
|
||||
|
||||
const { invoice, wallet } = invoiceObject
|
||||
const hash = parsePaymentRequest({ request: invoice }).id
|
||||
|
||||
const payment = await models.directPayment.create({
|
||||
data: {
|
||||
comment,
|
||||
lud18Data,
|
||||
desc: noteStr,
|
||||
bolt11: invoice,
|
||||
msats: cost,
|
||||
hash,
|
||||
walletId: wallet.id,
|
||||
receiverId: userId
|
||||
try {
|
||||
return {
|
||||
invoice: await models.directPayment.create({
|
||||
data: {
|
||||
comment,
|
||||
lud18Data,
|
||||
desc: noteStr,
|
||||
bolt11: invoice,
|
||||
msats: cost,
|
||||
hash,
|
||||
walletId: wallet.id,
|
||||
receiverId: userId
|
||||
}
|
||||
}),
|
||||
paymentMethod: 'DIRECT'
|
||||
}
|
||||
} catch (e) {
|
||||
console.error('failed to create direct payment', e)
|
||||
logger?.error('failed to create direct payment: ' + e.message, { bolt11: invoice })
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
return {
|
||||
invoice: payment,
|
||||
paymentMethod: 'DIRECT'
|
||||
} catch (e) {
|
||||
console.error('failed to create user invoice', e)
|
||||
}
|
||||
|
||||
throw new NonInvoiceablePeerError()
|
||||
}
|
||||
|
||||
export async function retryPaidAction (actionType, args, incomingContext) {
|
||||
|
@ -24,7 +24,7 @@ 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 }, { paymentAttempt, predecessorId, models }) {
|
||||
export async function * createUserInvoice (userId, { msats, description, descriptionHash, expiry = 360 }, { paymentAttempt, predecessorId, models }) {
|
||||
// get the wallets in order of priority
|
||||
const wallets = await getInvoiceableWallets(userId, {
|
||||
paymentAttempt,
|
||||
@ -72,44 +72,42 @@ export async function createInvoice (userId, { msats, description, descriptionHa
|
||||
}
|
||||
}
|
||||
|
||||
return { invoice, wallet, logger }
|
||||
yield { invoice, wallet, logger }
|
||||
} catch (err) {
|
||||
console.error('failed to create user invoice:', err)
|
||||
logger.error(err.message, { status: true })
|
||||
}
|
||||
}
|
||||
|
||||
throw new Error('no wallet to receive available')
|
||||
}
|
||||
|
||||
export async function createWrappedInvoice (userId,
|
||||
{ msats, feePercent, description, descriptionHash, expiry = 360 },
|
||||
{ paymentAttempt, predecessorId, models, me, lnd }) {
|
||||
let logger, bolt11
|
||||
try {
|
||||
const { invoice, wallet } = await createInvoice(userId, {
|
||||
// this is the amount the stacker will receive, the other (feePercent)% is our fee
|
||||
msats: toPositiveBigInt(msats) * (100n - feePercent) / 100n,
|
||||
description,
|
||||
descriptionHash,
|
||||
expiry
|
||||
}, { paymentAttempt, predecessorId, models })
|
||||
|
||||
logger = walletLogger({ wallet, models })
|
||||
bolt11 = invoice
|
||||
|
||||
const { invoice: wrappedInvoice, maxFee } =
|
||||
await wrapInvoice({ bolt11, feePercent }, { msats, description, descriptionHash }, { me, lnd })
|
||||
|
||||
return {
|
||||
invoice,
|
||||
wrappedInvoice: wrappedInvoice.request,
|
||||
wallet,
|
||||
maxFee
|
||||
// loop over all receiver wallet invoices until we successfully wrapped one
|
||||
for await (const { invoice, logger, wallet } of createUserInvoice(userId, {
|
||||
// this is the amount the stacker will receive, the other (feePercent)% is our fee
|
||||
msats: toPositiveBigInt(msats) * (100n - feePercent) / 100n,
|
||||
description,
|
||||
descriptionHash,
|
||||
expiry
|
||||
}, { paymentAttempt, predecessorId, models })) {
|
||||
let bolt11
|
||||
try {
|
||||
bolt11 = invoice
|
||||
const { invoice: wrappedInvoice, maxFee } = await wrapInvoice({ bolt11, feePercent }, { msats, description, descriptionHash }, { me, lnd })
|
||||
return {
|
||||
invoice,
|
||||
wrappedInvoice: wrappedInvoice.request,
|
||||
wallet,
|
||||
maxFee
|
||||
}
|
||||
} catch (e) {
|
||||
console.error('failed to wrap invoice:', e)
|
||||
logger?.error('failed to wrap invoice: ' + e.message, { bolt11 })
|
||||
}
|
||||
} catch (e) {
|
||||
logger?.error('invalid invoice: ' + e.message, { bolt11 })
|
||||
throw e
|
||||
}
|
||||
|
||||
throw new Error('no wallet to receive available')
|
||||
}
|
||||
|
||||
export async function getInvoiceableWallets (userId, { paymentAttempt, predecessorId, models }) {
|
||||
|
@ -1,6 +1,6 @@
|
||||
import { msatsSatsFloor, msatsToSats, satsToMsats } from '@/lib/format'
|
||||
import { createWithdrawal } from '@/api/resolvers/wallet'
|
||||
import { createInvoice } from '@/wallets/server'
|
||||
import { createUserInvoice } from '@/wallets/server'
|
||||
|
||||
export async function autoWithdraw ({ data: { id }, models, lnd }) {
|
||||
const user = await models.user.findUnique({ where: { id } })
|
||||
@ -42,14 +42,18 @@ export async function autoWithdraw ({ data: { id }, models, lnd }) {
|
||||
|
||||
if (pendingOrFailed.exists) return
|
||||
|
||||
const { invoice, wallet, logger } = await createInvoice(id, { msats, description: 'SN: autowithdrawal', expiry: 360 }, { models })
|
||||
|
||||
try {
|
||||
return await createWithdrawal(null,
|
||||
{ invoice, maxFee: msatsToSats(maxFeeMsats) },
|
||||
{ me: { id }, models, lnd, wallet, logger })
|
||||
} catch (err) {
|
||||
logger.error(`incoming payment failed: ${err}`, { bolt11: invoice })
|
||||
throw err
|
||||
for await (const { invoice, wallet, logger } of createUserInvoice(id, {
|
||||
msats,
|
||||
description: 'SN: autowithdrawal',
|
||||
expiry: 360
|
||||
}, { models })) {
|
||||
try {
|
||||
return await createWithdrawal(null,
|
||||
{ invoice, maxFee: msatsToSats(maxFeeMsats) },
|
||||
{ me: { id }, models, lnd, wallet, logger })
|
||||
} catch (err) {
|
||||
console.error('failed to create autowithdrawal:', err)
|
||||
logger?.error(`incoming payment failed: ${err}`, { bolt11: invoice })
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user