Refactor wallet error handling with inheritance
This commit is contained in:
parent
ed82d9cfc0
commit
413f76c33a
|
@ -8,7 +8,7 @@ import Bolt11Info from './bolt11-info'
|
|||
import { useQuery } from '@apollo/client'
|
||||
import { INVOICE } from '@/fragments/wallet'
|
||||
import { FAST_POLL_INTERVAL, SSR } from '@/lib/constants'
|
||||
import { NoWalletAvailableError } from '@/wallets/errors'
|
||||
import { WalletError } from '@/wallets/errors'
|
||||
import ItemJob from './item-job'
|
||||
import Item from './item'
|
||||
import { CommentFlat } from './comment'
|
||||
|
@ -104,7 +104,7 @@ export default function Invoice ({
|
|||
return (
|
||||
<>
|
||||
{/* TODO: handle aggregated wallet errors */}
|
||||
{walletError && !(walletError instanceof NoWalletAvailableError) &&
|
||||
{walletError instanceof WalletError &&
|
||||
<div className='text-center fw-bold text-info mb-3' style={{ lineHeight: 1.25 }}>
|
||||
Paying from attached wallet failed:
|
||||
<code> {walletError.message}</code>
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import { useApolloClient, useLazyQuery, useMutation } from '@apollo/client'
|
||||
import { useCallback, useState } from 'react'
|
||||
import { useInvoice, useQrPayment } from './payment'
|
||||
import { InvoiceCanceledError, InvoiceExpiredError, NoWalletAvailableError, WalletAggregateError } from '@/wallets/errors'
|
||||
import { InvoiceCanceledError, InvoiceExpiredError, WalletError } from '@/wallets/errors'
|
||||
import { GET_PAID_ACTION } from '@/fragments/paidAction'
|
||||
import { useWalletPayment } from '@/wallets/payment'
|
||||
|
||||
|
@ -39,7 +39,7 @@ export function usePaidMutation (mutation,
|
|||
try {
|
||||
return await waitForWalletPayment(walletInvoice, waitFor)
|
||||
} catch (err) {
|
||||
if (err instanceof WalletAggregateError || err instanceof NoWalletAvailableError) {
|
||||
if (err instanceof WalletError) {
|
||||
walletError = err
|
||||
// wallet payment error handling always creates a new invoice to retry
|
||||
if (err.newInvoice) walletInvoice = err.newInvoice
|
||||
|
|
|
@ -14,39 +14,44 @@ export class InvoiceExpiredError extends Error {
|
|||
}
|
||||
}
|
||||
|
||||
export class WalletNotEnabledError extends Error {
|
||||
export class WalletError extends Error {}
|
||||
export class WalletPaymentError extends WalletError {}
|
||||
export class WalletConfigurationError extends WalletError {}
|
||||
|
||||
export class WalletNotEnabledError extends WalletConfigurationError {
|
||||
constructor (name) {
|
||||
super(`wallet is not enabled: ${name}`)
|
||||
this.name = 'WalletNotEnabledError'
|
||||
}
|
||||
}
|
||||
|
||||
export class WalletSendNotConfiguredError extends Error {
|
||||
export class WalletSendNotConfiguredError extends WalletConfigurationError {
|
||||
constructor (name) {
|
||||
super(`wallet send is not configured: ${name}`)
|
||||
this.name = 'WalletSendNotConfiguredError'
|
||||
}
|
||||
}
|
||||
|
||||
export class SenderError extends Error {
|
||||
export class WalletSenderError extends WalletPaymentError {
|
||||
constructor (name, invoice, message) {
|
||||
super(`${name} failed to pay invoice ${invoice.hash}: ${message}`)
|
||||
this.name = 'SenderError'
|
||||
this.name = 'WalletSenderError'
|
||||
this.invoice = invoice
|
||||
}
|
||||
}
|
||||
|
||||
export class WalletAggregateError extends AggregateError {
|
||||
constructor (errors, newInvoice) {
|
||||
super(errors)
|
||||
this.name = 'WalletAggregateError'
|
||||
this.newInvoice = newInvoice
|
||||
export class WalletsNotAvailableError extends WalletConfigurationError {
|
||||
constructor () {
|
||||
super('no wallet available')
|
||||
this.name = 'WalletsNotAvailableError'
|
||||
}
|
||||
}
|
||||
|
||||
export class NoWalletAvailableError extends Error {
|
||||
constructor () {
|
||||
super('no wallet for payments available')
|
||||
this.name = 'NoWalletAvailableError'
|
||||
export class WalletAggregateError extends WalletError {
|
||||
constructor (errors, newInvoice) {
|
||||
super('WalletAggregateError')
|
||||
this.name = 'WalletAggregateError'
|
||||
this.errors = errors
|
||||
this.newInvoice = newInvoice
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,7 +5,10 @@ import { formatSats } from '@/lib/format'
|
|||
import { useWalletLogger } from '@/components/wallet-logger'
|
||||
import { useInvoice } from '@/components/payment'
|
||||
import { FAST_POLL_INTERVAL } from '@/lib/constants'
|
||||
import { NoWalletAvailableError, SenderError, WalletAggregateError, WalletNotEnabledError, WalletSendNotConfiguredError } from '@/wallets/errors'
|
||||
import {
|
||||
WalletsNotAvailableError, WalletSenderError, WalletAggregateError, WalletNotEnabledError,
|
||||
WalletSendNotConfiguredError, WalletPaymentError, WalletError, WalletConfigurationError
|
||||
} from '@/wallets/errors'
|
||||
import { canSend } from './common'
|
||||
|
||||
export function useWalletPayment () {
|
||||
|
@ -57,7 +60,7 @@ export function useWalletPayment () {
|
|||
} catch (err) {
|
||||
// cancel invoice to make sure it cannot be paid later.
|
||||
// we only need to do this if payment was attempted which is not the case if the wallet is not enabled.
|
||||
const paymentAttempt = !(err instanceof WalletNotEnabledError || err instanceof WalletSendNotConfiguredError)
|
||||
const paymentAttempt = err instanceof WalletPaymentError
|
||||
if (paymentAttempt) {
|
||||
await invoiceHelper.cancel(walletInvoice)
|
||||
|
||||
|
@ -75,7 +78,7 @@ export function useWalletPayment () {
|
|||
|
||||
// try next wallet if the payment failed because of the wallet
|
||||
// and not because it expired or was canceled
|
||||
const isWalletError = err instanceof WalletNotEnabledError || err instanceof WalletSendNotConfiguredError || err instanceof SenderError
|
||||
const isWalletError = err instanceof WalletError
|
||||
if (isWalletError) {
|
||||
walletError = new WalletAggregateError([...walletError.errors, err], walletInvoice)
|
||||
continue
|
||||
|
@ -90,14 +93,14 @@ export function useWalletPayment () {
|
|||
|
||||
// if we reach this line, no wallet payment succeeded
|
||||
|
||||
// if no wallet is enabled, throw a special error that caller can handle separately
|
||||
const noWalletAvailable = walletError.errors.every(e => e instanceof WalletNotEnabledError)
|
||||
// throw a special error that caller can handle separately if no payment was attempted
|
||||
const noWalletAvailable = walletError.errors.every(e => e instanceof WalletConfigurationError)
|
||||
if (noWalletAvailable) {
|
||||
throw new NoWalletAvailableError()
|
||||
throw new WalletsNotAvailableError()
|
||||
}
|
||||
|
||||
// ignore errors from disabled wallets, only return payment errors
|
||||
const paymentErrors = walletError.errors.filter(e => !(e instanceof WalletNotEnabledError))
|
||||
// only return payment errors
|
||||
const paymentErrors = walletError.errors.filter(e => e instanceof WalletPaymentError)
|
||||
throw new WalletAggregateError(paymentErrors, walletInvoice)
|
||||
}, [walletsWithPayments, invoiceHelper])
|
||||
|
||||
|
@ -160,7 +163,7 @@ function sendPayment (wallet, logger) {
|
|||
} catch (err) {
|
||||
const message = err.message || err.toString?.()
|
||||
logger.error(`payment failed: ${message}`, { bolt11 })
|
||||
throw new SenderError(wallet.def.name, invoice, message)
|
||||
throw new WalletSenderError(wallet.def.name, invoice, message)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue