fix: WebLN QR fallback for anon users (#1858)
* fix: WebLN QR fallback for anon users * wip: clear zap color on payment fail * reverse clearItemMeAnonSats * webln-specific retry bypass * cleanup * send WebLN payment when user is Anon AND on QR * skip wallet checking on anon * Use WalletError for all errors in webln.sendPayment --------- Co-authored-by: ekzyis <ek@stacker.news> Co-authored-by: Keyan <34140557+huumn@users.noreply.github.com>
This commit is contained in:
		
							parent
							
								
									5e7fd693f1
								
							
						
					
					
						commit
						f72af08882
					
				@ -1,8 +1,9 @@
 | 
			
		||||
import { useCallback } from 'react'
 | 
			
		||||
import Invoice from '@/components/invoice'
 | 
			
		||||
import { InvoiceCanceledError, InvoiceExpiredError } from '@/wallets/errors'
 | 
			
		||||
import { InvoiceCanceledError, InvoiceExpiredError, AnonWalletError } from '@/wallets/errors'
 | 
			
		||||
import { useShowModal } from '@/components/modal'
 | 
			
		||||
import useInvoice from '@/components/use-invoice'
 | 
			
		||||
import { sendPayment } from '@/wallets/webln/client'
 | 
			
		||||
 | 
			
		||||
export default function useQrPayment () {
 | 
			
		||||
  const invoice = useInvoice()
 | 
			
		||||
@ -16,6 +17,10 @@ export default function useQrPayment () {
 | 
			
		||||
      waitFor = inv => inv?.satsReceived > 0
 | 
			
		||||
    } = {}
 | 
			
		||||
  ) => {
 | 
			
		||||
    // if anon user and webln is available, try to pay with webln
 | 
			
		||||
    if (typeof window.webln !== 'undefined' && (walletError instanceof AnonWalletError)) {
 | 
			
		||||
      sendPayment(inv.bolt11).catch(e => { console.error('WebLN payment failed:', e) })
 | 
			
		||||
    }
 | 
			
		||||
    return await new Promise((resolve, reject) => {
 | 
			
		||||
      let paid
 | 
			
		||||
      const cancelAndReject = async (onClose) => {
 | 
			
		||||
 | 
			
		||||
@ -62,6 +62,13 @@ export class WalletsNotAvailableError extends WalletConfigurationError {
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export class AnonWalletError extends WalletConfigurationError {
 | 
			
		||||
  constructor () {
 | 
			
		||||
    super('anon cannot pay with wallets')
 | 
			
		||||
    this.name = 'AnonWalletError'
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export class WalletAggregateError extends WalletError {
 | 
			
		||||
  constructor (errors, invoice) {
 | 
			
		||||
    super('WalletAggregateError')
 | 
			
		||||
 | 
			
		||||
@ -4,23 +4,30 @@ import { formatSats } from '@/lib/format'
 | 
			
		||||
import useInvoice from '@/components/use-invoice'
 | 
			
		||||
import { FAST_POLL_INTERVAL, WALLET_SEND_PAYMENT_TIMEOUT_MS } from '@/lib/constants'
 | 
			
		||||
import {
 | 
			
		||||
  WalletsNotAvailableError, WalletSenderError, WalletAggregateError, WalletPaymentAggregateError,
 | 
			
		||||
  AnonWalletError, WalletsNotAvailableError, WalletSenderError, WalletAggregateError, WalletPaymentAggregateError,
 | 
			
		||||
  WalletNotEnabledError, WalletSendNotConfiguredError, WalletPaymentError, WalletError, WalletReceiverError
 | 
			
		||||
} from '@/wallets/errors'
 | 
			
		||||
import { canSend } from './common'
 | 
			
		||||
import { useWalletLoggerFactory } from './logger'
 | 
			
		||||
import { timeoutSignal, withTimeout } from '@/lib/time'
 | 
			
		||||
import { useMe } from '@/components/me'
 | 
			
		||||
 | 
			
		||||
export function useWalletPayment () {
 | 
			
		||||
  const wallets = useSendWallets()
 | 
			
		||||
  const sendPayment = useSendPayment()
 | 
			
		||||
  const loggerFactory = useWalletLoggerFactory()
 | 
			
		||||
  const invoiceHelper = useInvoice()
 | 
			
		||||
  const { me } = useMe()
 | 
			
		||||
 | 
			
		||||
  return useCallback(async (invoice, { waitFor, updateOnFallback } = {}) => {
 | 
			
		||||
    let aggregateError = new WalletAggregateError([])
 | 
			
		||||
    let latestInvoice = invoice
 | 
			
		||||
 | 
			
		||||
    // anon user cannot pay with wallets
 | 
			
		||||
    if (!me) {
 | 
			
		||||
      throw new AnonWalletError()
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // throw a special error that caller can handle separately if no payment was attempted
 | 
			
		||||
    if (wallets.length === 0) {
 | 
			
		||||
      throw new WalletsNotAvailableError()
 | 
			
		||||
 | 
			
		||||
@ -1,14 +1,19 @@
 | 
			
		||||
import { useEffect } from 'react'
 | 
			
		||||
import { SSR } from '@/lib/constants'
 | 
			
		||||
import { WalletError } from '../errors'
 | 
			
		||||
export * from '@/wallets/webln'
 | 
			
		||||
 | 
			
		||||
export const sendPayment = async (bolt11) => {
 | 
			
		||||
  if (typeof window.webln === 'undefined') {
 | 
			
		||||
    throw new Error('WebLN provider not found')
 | 
			
		||||
    throw new WalletError('WebLN provider not found')
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // this will prompt the user to unlock the wallet if it's locked
 | 
			
		||||
  await window.webln.enable()
 | 
			
		||||
  try {
 | 
			
		||||
    await window.webln.enable()
 | 
			
		||||
  } catch (err) {
 | 
			
		||||
    throw new WalletError(err.message)
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // this will prompt for payment if no budget is set
 | 
			
		||||
  const response = await window.webln.sendPayment(bolt11)
 | 
			
		||||
@ -16,7 +21,7 @@ export const sendPayment = async (bolt11) => {
 | 
			
		||||
    // sendPayment returns nothing if WebLN was enabled
 | 
			
		||||
    // but browser extension that provides WebLN was then disabled
 | 
			
		||||
    // without reloading the page
 | 
			
		||||
    throw new Error('sendPayment returned no response')
 | 
			
		||||
    throw new WalletError('sendPayment returned no response')
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  return response.preimage
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user