refactor out array of hooks
This commit is contained in:
parent
61395a3525
commit
b608fb6848
@ -13,7 +13,7 @@ import { usePaidMutation } from './use-paid-mutation'
|
|||||||
import { ACT_MUTATION } from '@/fragments/paidAction'
|
import { ACT_MUTATION } from '@/fragments/paidAction'
|
||||||
import { meAnonSats } from '@/lib/apollo'
|
import { meAnonSats } from '@/lib/apollo'
|
||||||
import { BoostItemInput } from './adv-post-form'
|
import { BoostItemInput } from './adv-post-form'
|
||||||
import { useWallet } from '@/wallets/index'
|
import { useWalletsWithPayments } from '@/wallets/index'
|
||||||
|
|
||||||
const defaultTips = [100, 1000, 10_000, 100_000]
|
const defaultTips = [100, 1000, 10_000, 100_000]
|
||||||
|
|
||||||
@ -89,7 +89,7 @@ function BoostForm ({ step, onSubmit, children, item, oValue, inputRef, act = 'B
|
|||||||
export default function ItemAct ({ onClose, item, act = 'TIP', step, children, abortSignal }) {
|
export default function ItemAct ({ onClose, item, act = 'TIP', step, children, abortSignal }) {
|
||||||
const inputRef = useRef(null)
|
const inputRef = useRef(null)
|
||||||
const { me } = useMe()
|
const { me } = useMe()
|
||||||
const wallet = useWallet()
|
const wallets = useWalletsWithPayments()
|
||||||
const [oValue, setOValue] = useState()
|
const [oValue, setOValue] = useState()
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@ -117,7 +117,7 @@ export default function ItemAct ({ onClose, item, act = 'TIP', step, children, a
|
|||||||
if (!me) setItemMeAnonSats({ id: item.id, amount })
|
if (!me) setItemMeAnonSats({ id: item.id, amount })
|
||||||
}
|
}
|
||||||
|
|
||||||
const closeImmediately = !!wallet || me?.privates?.sats > Number(amount)
|
const closeImmediately = wallets.length > 0 || me?.privates?.sats > Number(amount)
|
||||||
if (closeImmediately) {
|
if (closeImmediately) {
|
||||||
onPaid()
|
onPaid()
|
||||||
}
|
}
|
||||||
@ -143,7 +143,7 @@ export default function ItemAct ({ onClose, item, act = 'TIP', step, children, a
|
|||||||
})
|
})
|
||||||
if (error) throw error
|
if (error) throw error
|
||||||
addCustomTip(Number(amount))
|
addCustomTip(Number(amount))
|
||||||
}, [me, actor, !!wallet, act, item.id, onClose, abortSignal, strike])
|
}, [me, actor, wallets.length, act, item.id, onClose, abortSignal, strike])
|
||||||
|
|
||||||
return act === 'BOOST'
|
return act === 'BOOST'
|
||||||
? <BoostForm step={step} onSubmit={onSubmit} item={item} inputRef={inputRef} act={act}>{children}</BoostForm>
|
? <BoostForm step={step} onSubmit={onSubmit} item={item} inputRef={inputRef} act={act}>{children}</BoostForm>
|
||||||
@ -260,7 +260,7 @@ export function useAct ({ query = ACT_MUTATION, ...options } = {}) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function useZap () {
|
export function useZap () {
|
||||||
const wallet = useWallet()
|
const wallets = useWalletsWithPayments()
|
||||||
const act = useAct()
|
const act = useAct()
|
||||||
const strike = useLightning()
|
const strike = useLightning()
|
||||||
const toaster = useToast()
|
const toaster = useToast()
|
||||||
@ -278,7 +278,7 @@ export function useZap () {
|
|||||||
await abortSignal.pause({ me, amount: sats })
|
await abortSignal.pause({ me, amount: sats })
|
||||||
strike()
|
strike()
|
||||||
// batch zaps if wallet is enabled or using fee credits so they can be executed serially in a single request
|
// batch zaps if wallet is enabled or using fee credits so they can be executed serially in a single request
|
||||||
const { error } = await act({ variables, optimisticResponse, context: { batch: !!wallet || me?.privates?.sats > sats } })
|
const { error } = await act({ variables, optimisticResponse, context: { batch: wallets.length > 0 || me?.privates?.sats > sats } })
|
||||||
if (error) throw error
|
if (error) throw error
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
if (error instanceof ActCanceledError) {
|
if (error instanceof ActCanceledError) {
|
||||||
@ -288,7 +288,7 @@ export function useZap () {
|
|||||||
const reason = error?.message || error?.toString?.()
|
const reason = error?.message || error?.toString?.()
|
||||||
toaster.danger(reason)
|
toaster.danger(reason)
|
||||||
}
|
}
|
||||||
}, [act, toaster, strike, !!wallet])
|
}, [act, toaster, strike, wallets.length])
|
||||||
}
|
}
|
||||||
|
|
||||||
export class ActCanceledError extends Error {
|
export class ActCanceledError extends Error {
|
||||||
|
@ -5,13 +5,11 @@ import { Button } from 'react-bootstrap'
|
|||||||
import { useToast } from './toast'
|
import { useToast } from './toast'
|
||||||
import { useShowModal } from './modal'
|
import { useShowModal } from './modal'
|
||||||
import { WALLET_LOGS } from '@/fragments/wallet'
|
import { WALLET_LOGS } from '@/fragments/wallet'
|
||||||
import { getWalletByType } from '@/wallets/common'
|
import { getWalletByType, walletTag } from '@/wallets/common'
|
||||||
import { gql, useLazyQuery, useMutation } from '@apollo/client'
|
import { gql, useLazyQuery, useMutation } from '@apollo/client'
|
||||||
import { useMe } from './me'
|
import { useMe } from './me'
|
||||||
import useIndexedDB, { getDbName } from './use-indexeddb'
|
import useIndexedDB, { getDbName } from './use-indexeddb'
|
||||||
import { SSR } from '@/lib/constants'
|
import { SSR } from '@/lib/constants'
|
||||||
import { decode as bolt11Decode } from 'bolt11'
|
|
||||||
import { formatMsats } from '@/lib/format'
|
|
||||||
import { useRouter } from 'next/router'
|
import { useRouter } from 'next/router'
|
||||||
|
|
||||||
export function WalletLogs ({ wallet, embedded }) {
|
export function WalletLogs ({ wallet, embedded }) {
|
||||||
@ -61,7 +59,7 @@ export function WalletLogs ({ wallet, embedded }) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function DeleteWalletLogsObstacle ({ wallet, setLogs, onClose }) {
|
function DeleteWalletLogsObstacle ({ wallet, setLogs, onClose }) {
|
||||||
const { deleteLogs } = useWalletLogger(wallet, setLogs)
|
const { deleteLogs } = useWalletLogManager(setLogs)
|
||||||
const toaster = useToast()
|
const toaster = useToast()
|
||||||
|
|
||||||
const prompt = `Do you really want to delete all ${wallet ? '' : 'wallet'} logs ${wallet ? 'of this wallet' : ''}?`
|
const prompt = `Do you really want to delete all ${wallet ? '' : 'wallet'} logs ${wallet ? 'of this wallet' : ''}?`
|
||||||
@ -110,11 +108,11 @@ function useWalletLogDB () {
|
|||||||
return { add, getPage, clear, error, notSupported }
|
return { add, getPage, clear, error, notSupported }
|
||||||
}
|
}
|
||||||
|
|
||||||
export function useWalletLogger (wallet, setLogs) {
|
export function useWalletLogManager (setLogs) {
|
||||||
const { add, clear, notSupported } = useWalletLogDB()
|
const { add, clear, notSupported } = useWalletLogDB()
|
||||||
|
|
||||||
const appendLog = useCallback(async (wallet, level, message, context) => {
|
const appendLog = useCallback(async (wallet, level, message, context) => {
|
||||||
const log = { wallet: tag(wallet), level, message, ts: +new Date(), context }
|
const log = { wallet: walletTag(wallet), level, message, ts: +new Date(), context }
|
||||||
try {
|
try {
|
||||||
if (notSupported) {
|
if (notSupported) {
|
||||||
console.log('cannot persist wallet log: indexeddb not supported')
|
console.log('cannot persist wallet log: indexeddb not supported')
|
||||||
@ -146,56 +144,20 @@ export function useWalletLogger (wallet, setLogs) {
|
|||||||
}
|
}
|
||||||
if (!wallet || wallet.sendPayment) {
|
if (!wallet || wallet.sendPayment) {
|
||||||
try {
|
try {
|
||||||
const walletTag = wallet ? tag(wallet) : null
|
const tag = wallet ? walletTag(wallet) : null
|
||||||
if (notSupported) {
|
if (notSupported) {
|
||||||
console.log('cannot clear wallet logs: indexeddb not supported')
|
console.log('cannot clear wallet logs: indexeddb not supported')
|
||||||
} else {
|
} else {
|
||||||
await clear('wallet_ts', walletTag ? window.IDBKeyRange.bound([walletTag, 0], [walletTag, Infinity]) : null)
|
await clear('wallet_ts', tag ? window.IDBKeyRange.bound([tag, 0], [tag, Infinity]) : null)
|
||||||
}
|
}
|
||||||
setLogs?.(logs => logs.filter(l => wallet ? l.wallet !== tag(wallet) : false))
|
setLogs?.(logs => logs.filter(l => wallet ? l.wallet !== tag : false))
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error('failed to delete logs', e)
|
console.error('failed to delete logs', e)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}, [clear, deleteServerWalletLogs, setLogs, notSupported])
|
}, [clear, deleteServerWalletLogs, setLogs, notSupported])
|
||||||
|
|
||||||
const log = useCallback(level => (message, context = {}) => {
|
return { appendLog, deleteLogs }
|
||||||
if (!wallet) {
|
|
||||||
// console.error('cannot log: no wallet set')
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if (context?.bolt11) {
|
|
||||||
// automatically populate context from bolt11 to avoid duplicating this code
|
|
||||||
const decoded = bolt11Decode(context.bolt11)
|
|
||||||
context = {
|
|
||||||
...context,
|
|
||||||
amount: formatMsats(decoded.millisatoshis),
|
|
||||||
payment_hash: decoded.tagsObject.payment_hash,
|
|
||||||
description: decoded.tagsObject.description,
|
|
||||||
created_at: new Date(decoded.timestamp * 1000).toISOString(),
|
|
||||||
expires_at: new Date(decoded.timeExpireDate * 1000).toISOString(),
|
|
||||||
// payments should affect wallet status
|
|
||||||
status: true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
context.send = true
|
|
||||||
|
|
||||||
appendLog(wallet, level, message, context)
|
|
||||||
console[level !== 'error' ? 'info' : 'error'](`[${tag(wallet)}]`, message)
|
|
||||||
}, [appendLog, wallet])
|
|
||||||
|
|
||||||
const logger = useMemo(() => ({
|
|
||||||
ok: (message, context) => log('ok')(message, context),
|
|
||||||
info: (message, context) => log('info')(message, context),
|
|
||||||
error: (message, context) => log('error')(message, context)
|
|
||||||
}), [log])
|
|
||||||
|
|
||||||
return { logger, deleteLogs }
|
|
||||||
}
|
|
||||||
|
|
||||||
function tag (walletDef) {
|
|
||||||
return walletDef.shortName || walletDef.name
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export function useWalletLogs (wallet, initialPage = 1, logsPerPage = 10) {
|
export function useWalletLogs (wallet, initialPage = 1, logsPerPage = 10) {
|
||||||
@ -227,7 +189,7 @@ export function useWalletLogs (wallet, initialPage = 1, logsPerPage = 10) {
|
|||||||
console.log('cannot get client wallet logs: indexeddb not supported')
|
console.log('cannot get client wallet logs: indexeddb not supported')
|
||||||
} else {
|
} else {
|
||||||
const indexName = walletDef ? 'wallet_ts' : 'ts'
|
const indexName = walletDef ? 'wallet_ts' : 'ts'
|
||||||
const query = walletDef ? window.IDBKeyRange.bound([tag(walletDef), -Infinity], [tag(walletDef), Infinity]) : null
|
const query = walletDef ? window.IDBKeyRange.bound([walletTag(walletDef), -Infinity], [walletTag(walletDef), Infinity]) : null
|
||||||
|
|
||||||
result = await getPage(page, pageSize, indexName, query, 'prev')
|
result = await getPage(page, pageSize, indexName, query, 'prev')
|
||||||
// if given wallet has no walletType it means logs are only stored in local IDB
|
// if given wallet has no walletType it means logs are only stored in local IDB
|
||||||
@ -272,7 +234,7 @@ export function useWalletLogs (wallet, initialPage = 1, logsPerPage = 10) {
|
|||||||
|
|
||||||
const newLogs = data.walletLogs.entries.map(({ createdAt, wallet: walletType, ...log }) => ({
|
const newLogs = data.walletLogs.entries.map(({ createdAt, wallet: walletType, ...log }) => ({
|
||||||
ts: +new Date(createdAt),
|
ts: +new Date(createdAt),
|
||||||
wallet: tag(getWalletByType(walletType)),
|
wallet: walletTag(getWalletByType(walletType)),
|
||||||
...log
|
...log
|
||||||
}))
|
}))
|
||||||
const combinedLogs = uniqueSort([...result.data, ...newLogs])
|
const combinedLogs = uniqueSort([...result.data, ...newLogs])
|
||||||
|
@ -27,6 +27,10 @@ export function getStorageKey (name, userId) {
|
|||||||
return storageKey
|
return storageKey
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function walletTag (walletDef) {
|
||||||
|
return walletDef.shortName || walletDef.name
|
||||||
|
}
|
||||||
|
|
||||||
export function walletPrioritySort (w1, w2) {
|
export function walletPrioritySort (w1, w2) {
|
||||||
// enabled/configured wallets always come before disabled/unconfigured wallets
|
// enabled/configured wallets always come before disabled/unconfigured wallets
|
||||||
if ((w1.config?.enabled && !w2.config?.enabled) || (isConfigured(w1) && !isConfigured(w2))) {
|
if ((w1.config?.enabled && !w2.config?.enabled) || (isConfigured(w1) && !isConfigured(w2))) {
|
||||||
|
@ -5,7 +5,7 @@ import { canReceive, canSend, getStorageKey, saveWalletLocally, siftConfig, upse
|
|||||||
import { useMutation } from '@apollo/client'
|
import { useMutation } from '@apollo/client'
|
||||||
import { generateMutation } from './graphql'
|
import { generateMutation } from './graphql'
|
||||||
import { REMOVE_WALLET } from '@/fragments/wallet'
|
import { REMOVE_WALLET } from '@/fragments/wallet'
|
||||||
import { useWalletLogger } from '@/components/wallet-logger'
|
import { useWalletLogger } from '@/wallets/logger'
|
||||||
import { useWallets } from '.'
|
import { useWallets } from '.'
|
||||||
import validateWallet from './validate'
|
import validateWallet from './validate'
|
||||||
|
|
||||||
|
@ -5,11 +5,8 @@ import { useApolloClient, useMutation, useQuery } from '@apollo/client'
|
|||||||
import { createContext, useCallback, useContext, useEffect, useMemo, useState } from 'react'
|
import { createContext, useCallback, useContext, useEffect, useMemo, useState } from 'react'
|
||||||
import { getStorageKey, getWalletByType, walletPrioritySort, canSend, isConfigured, upsertWalletVariables, siftConfig, saveWalletLocally } from './common'
|
import { getStorageKey, getWalletByType, walletPrioritySort, canSend, isConfigured, upsertWalletVariables, siftConfig, saveWalletLocally } from './common'
|
||||||
import useVault from '@/components/vault/use-vault'
|
import useVault from '@/components/vault/use-vault'
|
||||||
import { useWalletLogger } from '@/components/wallet-logger'
|
|
||||||
import { decode as bolt11Decode } from 'bolt11'
|
|
||||||
import walletDefs from '@/wallets/client'
|
import walletDefs from '@/wallets/client'
|
||||||
import { generateMutation } from './graphql'
|
import { generateMutation } from './graphql'
|
||||||
import { formatSats } from '@/lib/format'
|
|
||||||
|
|
||||||
const WalletsContext = createContext({
|
const WalletsContext = createContext({
|
||||||
wallets: []
|
wallets: []
|
||||||
@ -218,34 +215,13 @@ export function useWallets () {
|
|||||||
|
|
||||||
export function useWallet (name) {
|
export function useWallet (name) {
|
||||||
const { wallets } = useWallets()
|
const { wallets } = useWallets()
|
||||||
|
return wallets.find(w => w.def.name === name)
|
||||||
const wallet = useMemo(() => {
|
}
|
||||||
if (name) {
|
|
||||||
return wallets.find(w => w.def.name === name)
|
export function useWalletsWithPayments () {
|
||||||
}
|
const { wallets } = useWallets()
|
||||||
|
// return the first enabled wallet that is available and can send
|
||||||
// return the first enabled wallet that is available and can send
|
return wallets
|
||||||
return wallets
|
.filter(w => !w.def.isAvailable || w.def.isAvailable())
|
||||||
.filter(w => !w.def.isAvailable || w.def.isAvailable())
|
.filter(w => w.config?.enabled && canSend(w))
|
||||||
.filter(w => w.config?.enabled && canSend(w))[0]
|
|
||||||
}, [wallets, name])
|
|
||||||
|
|
||||||
const { logger } = useWalletLogger(wallet?.def)
|
|
||||||
|
|
||||||
const sendPayment = useCallback(async (bolt11) => {
|
|
||||||
const decoded = bolt11Decode(bolt11)
|
|
||||||
logger.info(`↗ sending payment: ${formatSats(decoded.satoshis)}`, { bolt11 })
|
|
||||||
try {
|
|
||||||
const preimage = await wallet.def.sendPayment(bolt11, wallet.config, { logger })
|
|
||||||
logger.ok(`↗ payment sent: ${formatSats(decoded.satoshis)}`, { bolt11, preimage })
|
|
||||||
} catch (err) {
|
|
||||||
const message = err.message || err.toString?.()
|
|
||||||
logger.error(`payment failed: ${message}`, { bolt11 })
|
|
||||||
throw err
|
|
||||||
}
|
|
||||||
}, [wallet, logger])
|
|
||||||
|
|
||||||
if (!wallet) return null
|
|
||||||
|
|
||||||
return { ...wallet, sendPayment }
|
|
||||||
}
|
}
|
||||||
|
45
wallets/logger.js
Normal file
45
wallets/logger.js
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
import { useCallback } from 'react'
|
||||||
|
import { decode as bolt11Decode } from 'bolt11'
|
||||||
|
import { formatMsats } from '@/lib/format'
|
||||||
|
import { walletTag } from '@/wallets/common'
|
||||||
|
import { useWalletLogManager } from '@/components/wallet-logger'
|
||||||
|
|
||||||
|
export function useWalletLoggerFactory () {
|
||||||
|
const { appendLog } = useWalletLogManager()
|
||||||
|
|
||||||
|
const log = useCallback((wallet, level) => (message, context = {}) => {
|
||||||
|
if (!wallet) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if (context?.bolt11) {
|
||||||
|
// automatically populate context from bolt11 to avoid duplicating this code
|
||||||
|
const decoded = bolt11Decode(context.bolt11)
|
||||||
|
context = {
|
||||||
|
...context,
|
||||||
|
amount: formatMsats(decoded.millisatoshis),
|
||||||
|
payment_hash: decoded.tagsObject.payment_hash,
|
||||||
|
description: decoded.tagsObject.description,
|
||||||
|
created_at: new Date(decoded.timestamp * 1000).toISOString(),
|
||||||
|
expires_at: new Date(decoded.timeExpireDate * 1000).toISOString(),
|
||||||
|
// payments should affect wallet status
|
||||||
|
status: true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
context.send = true
|
||||||
|
|
||||||
|
appendLog(wallet, level, message, context)
|
||||||
|
console[level !== 'error' ? 'info' : 'error'](`[${walletTag(wallet)}]`, message)
|
||||||
|
}, [appendLog])
|
||||||
|
|
||||||
|
return useCallback(wallet => ({
|
||||||
|
ok: (message, context) => log(wallet, 'ok')(message, context),
|
||||||
|
info: (message, context) => log(wallet, 'info')(message, context),
|
||||||
|
error: (message, context) => log(wallet, 'error')(message, context)
|
||||||
|
}), [log])
|
||||||
|
}
|
||||||
|
|
||||||
|
export function useWalletLogger (wallet) {
|
||||||
|
const factory = useWalletLoggerFactory()
|
||||||
|
return factory(wallet)
|
||||||
|
}
|
@ -1,8 +1,6 @@
|
|||||||
import { useCallback, useMemo } from 'react'
|
import { useCallback } from 'react'
|
||||||
import { useWallets } from '@/wallets'
|
import { useWalletsWithPayments } from '@/wallets'
|
||||||
import walletDefs from '@/wallets/client'
|
|
||||||
import { formatSats } from '@/lib/format'
|
import { formatSats } from '@/lib/format'
|
||||||
import { useWalletLogger } from '@/components/wallet-logger'
|
|
||||||
import { useInvoice } from '@/components/payment'
|
import { useInvoice } from '@/components/payment'
|
||||||
import { FAST_POLL_INTERVAL } from '@/lib/constants'
|
import { FAST_POLL_INTERVAL } from '@/lib/constants'
|
||||||
import {
|
import {
|
||||||
@ -10,57 +8,30 @@ import {
|
|||||||
WalletNotEnabledError, WalletSendNotConfiguredError, WalletPaymentError, WalletError
|
WalletNotEnabledError, WalletSendNotConfiguredError, WalletPaymentError, WalletError
|
||||||
} from '@/wallets/errors'
|
} from '@/wallets/errors'
|
||||||
import { canSend } from './common'
|
import { canSend } from './common'
|
||||||
|
import { useWalletLoggerFactory } from './logger'
|
||||||
|
|
||||||
export function useWalletPayment () {
|
export function useWalletPayment () {
|
||||||
const { wallets } = useWallets()
|
const wallets = useWalletsWithPayments()
|
||||||
|
const sendPayment = useSendPayment()
|
||||||
const invoiceHelper = useInvoice()
|
const invoiceHelper = useInvoice()
|
||||||
|
|
||||||
// XXX calling hooks in a loop is against the rules of hooks
|
return useCallback(async (invoice, { waitFor }) => {
|
||||||
//
|
|
||||||
// we do this here anyway since we need the logger for each wallet.
|
|
||||||
// hooks are always called in the same order since walletDefs does not change between renders.
|
|
||||||
//
|
|
||||||
// we don't use the return value of useWallets here because it is empty on first render
|
|
||||||
// so using it would change the order of the hooks between renders.
|
|
||||||
//
|
|
||||||
// see https://react.dev/reference/rules/rules-of-hooks
|
|
||||||
const loggers = walletDefs
|
|
||||||
.reduce((acc, def) => {
|
|
||||||
return {
|
|
||||||
...acc,
|
|
||||||
[def.name]: useWalletLogger(def)?.logger
|
|
||||||
}
|
|
||||||
}, {})
|
|
||||||
|
|
||||||
const walletsWithPayments = useMemo(() => {
|
|
||||||
return wallets
|
|
||||||
.filter(wallet => canSend(wallet) && wallet.config.enabled)
|
|
||||||
.map(wallet => {
|
|
||||||
const logger = loggers[wallet.def.name]
|
|
||||||
return {
|
|
||||||
...wallet,
|
|
||||||
sendPayment: sendPayment(wallet, logger)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}, [wallets, loggers])
|
|
||||||
|
|
||||||
const waitForPayment = useCallback(async (invoice, { waitFor }) => {
|
|
||||||
let walletError = new WalletAggregateError([])
|
let walletError = new WalletAggregateError([])
|
||||||
let walletInvoice = invoice
|
let walletInvoice = invoice
|
||||||
|
|
||||||
// throw a special error that caller can handle separately if no payment was attempted
|
// throw a special error that caller can handle separately if no payment was attempted
|
||||||
const noWalletAvailable = walletsWithPayments.length === 0
|
const noWalletAvailable = wallets.length === 0
|
||||||
if (noWalletAvailable) {
|
if (noWalletAvailable) {
|
||||||
throw new WalletsNotAvailableError()
|
throw new WalletsNotAvailableError()
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const [i, wallet] of walletsWithPayments.entries()) {
|
for (const [i, wallet] of wallets.entries()) {
|
||||||
const controller = invoiceController(walletInvoice, invoiceHelper.isInvoice)
|
const controller = invoiceController(walletInvoice, invoiceHelper.isInvoice)
|
||||||
try {
|
try {
|
||||||
return await new Promise((resolve, reject) => {
|
return await new Promise((resolve, reject) => {
|
||||||
// can't await wallet payments since we might pay hold invoices and thus payments might not settle immediately.
|
// can't await wallet payments since we might pay hold invoices and thus payments might not settle immediately.
|
||||||
// that's why we separately check if we received the payment with the invoice controller.
|
// that's why we separately check if we received the payment with the invoice controller.
|
||||||
wallet.sendPayment(walletInvoice).catch(reject)
|
sendPayment(wallet, walletInvoice).catch(reject)
|
||||||
controller.wait(waitFor)
|
controller.wait(waitFor)
|
||||||
.then(resolve)
|
.then(resolve)
|
||||||
.catch(reject)
|
.catch(reject)
|
||||||
@ -73,7 +44,7 @@ export function useWalletPayment () {
|
|||||||
await invoiceHelper.cancel(walletInvoice)
|
await invoiceHelper.cancel(walletInvoice)
|
||||||
|
|
||||||
// is there another wallet to try?
|
// is there another wallet to try?
|
||||||
const lastAttempt = i === walletsWithPayments.length - 1
|
const lastAttempt = i === wallets.length - 1
|
||||||
if (!lastAttempt) {
|
if (!lastAttempt) {
|
||||||
walletInvoice = await invoiceHelper.retry(walletInvoice)
|
walletInvoice = await invoiceHelper.retry(walletInvoice)
|
||||||
}
|
}
|
||||||
@ -103,12 +74,10 @@ export function useWalletPayment () {
|
|||||||
// only return payment errors
|
// only return payment errors
|
||||||
const paymentErrors = walletError.errors.filter(e => e instanceof WalletPaymentError)
|
const paymentErrors = walletError.errors.filter(e => e instanceof WalletPaymentError)
|
||||||
throw new WalletPaymentAggregateError(paymentErrors, walletInvoice)
|
throw new WalletPaymentAggregateError(paymentErrors, walletInvoice)
|
||||||
}, [walletsWithPayments, invoiceHelper])
|
}, [wallets, invoiceHelper, sendPayment])
|
||||||
|
|
||||||
return waitForPayment
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const invoiceController = (inv, isInvoice) => {
|
function invoiceController (inv, isInvoice) {
|
||||||
const controller = new AbortController()
|
const controller = new AbortController()
|
||||||
const signal = controller.signal
|
const signal = controller.signal
|
||||||
controller.wait = async (waitFor = inv => inv?.actionState === 'PAID') => {
|
controller.wait = async (waitFor = inv => inv?.actionState === 'PAID') => {
|
||||||
@ -146,8 +115,12 @@ const invoiceController = (inv, isInvoice) => {
|
|||||||
return controller
|
return controller
|
||||||
}
|
}
|
||||||
|
|
||||||
function sendPayment (wallet, logger) {
|
function useSendPayment () {
|
||||||
return async (invoice) => {
|
const factory = useWalletLoggerFactory()
|
||||||
|
|
||||||
|
return useCallback(async (wallet, invoice) => {
|
||||||
|
const logger = factory(wallet)
|
||||||
|
|
||||||
if (!wallet.config.enabled) {
|
if (!wallet.config.enabled) {
|
||||||
throw new WalletNotEnabledError(wallet.def.name)
|
throw new WalletNotEnabledError(wallet.def.name)
|
||||||
}
|
}
|
||||||
@ -167,5 +140,5 @@ function sendPayment (wallet, logger) {
|
|||||||
logger.error(`payment failed: ${message}`, { bolt11 })
|
logger.error(`payment failed: ${message}`, { bolt11 })
|
||||||
throw new WalletSenderError(wallet.def.name, invoice, message)
|
throw new WalletSenderError(wallet.def.name, invoice, message)
|
||||||
}
|
}
|
||||||
}
|
}, [factory])
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user