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