stacker.news/components/use-invoice.js
ekzyis a46f81f1e1
Receiver fallbacks (#1688)
* Use same naming scheme between ln containers and env vars

* Add router_lnd container

* Only open channels to router_lnd

* Use 1sat base fee and 0ppm fee rate

* Add script to test routing

* Also fund router_lnd wallet

* Receiver fallbacks

* Rename to predecessorId

* Remove useless wallet table join

* Missing renaming to predecessor

* Fix payment stuck on sender error

We want to await the invoice poll promise so we can check for receiver errors, but in case of sender errors, the promise will never settle.

* Don't log failed forwards as sender errors

* fix check for receiver error

---------

Co-authored-by: Keyan <34140557+huumn@users.noreply.github.com>
Co-authored-by: k00b <k00b@stacker.news>
2024-12-10 14:15:29 -06:00

62 lines
2.0 KiB
JavaScript

import { useApolloClient, useMutation } from '@apollo/client'
import { useCallback } from 'react'
import { InvoiceCanceledError, InvoiceExpiredError, WalletReceiverError } from '@/wallets/errors'
import { RETRY_PAID_ACTION } from '@/fragments/paidAction'
import { INVOICE, CANCEL_INVOICE } from '@/fragments/wallet'
export default function useInvoice () {
const client = useApolloClient()
const [retryPaidAction] = useMutation(RETRY_PAID_ACTION)
const [cancelInvoice] = useMutation(CANCEL_INVOICE)
const isInvoice = useCallback(async ({ id }, that) => {
const { data, error } = await client.query({ query: INVOICE, fetchPolicy: 'network-only', variables: { id } })
if (error) {
throw error
}
const { cancelled, cancelledAt, actionError, expiresAt, forwardStatus } = data.invoice
const expired = cancelledAt && new Date(expiresAt) < new Date(cancelledAt)
if (expired) {
throw new InvoiceExpiredError(data.invoice)
}
const failed = cancelled || actionError
if (failed && (forwardStatus && forwardStatus !== 'CONFIRMED')) {
throw new WalletReceiverError(data.invoice)
}
if (failed) {
throw new InvoiceCanceledError(data.invoice, actionError)
}
return { invoice: data.invoice, check: that(data.invoice) }
}, [client])
const cancel = useCallback(async ({ hash, hmac }) => {
if (!hash || !hmac) {
throw new Error('missing hash or hmac')
}
console.log('canceling invoice:', hash)
const { data } = await cancelInvoice({ variables: { hash, hmac } })
return data.cancelInvoice
}, [cancelInvoice])
const retry = useCallback(async ({ id, hash, hmac }, { update }) => {
console.log('retrying invoice:', hash)
const { data, error } = await retryPaidAction({ variables: { invoiceId: Number(id) }, update })
if (error) throw error
const newInvoice = data.retryPaidAction.invoice
console.log('new invoice:', newInvoice?.hash)
return newInvoice
}, [retryPaidAction])
return { cancel, retry, isInvoice }
}