From afe096e516fc4c0da7ab55da07a177667a816d9a Mon Sep 17 00:00:00 2001 From: ekzyis Date: Thu, 15 Feb 2024 18:20:15 +0100 Subject: [PATCH] Fix QR code interaction with WebLN provider (#834) * Fix passing of bolt11 for QR payments * Fix missing provider check * Only cancel invoice if hash and hmac were given * Fix duplicate toast on error * Fix relay might not be set yet when sendPayment is called --- components/qr.js | 9 +++------ components/webln/index.js | 3 ++- components/webln/nwc.js | 41 +++++++++++++++++++-------------------- 3 files changed, 25 insertions(+), 28 deletions(-) diff --git a/components/qr.js b/components/qr.js index 422b9c74..45a499be 100644 --- a/components/qr.js +++ b/components/qr.js @@ -3,27 +3,24 @@ import { CopyInput, InputSkeleton } from './form' import InvoiceStatus from './invoice-status' import { useEffect } from 'react' import { useWebLN } from './webln' -import { useToast } from './toast' export default function Qr ({ asIs, value, webLn, statusVariant, description, status }) { const qrValue = asIs ? value : 'lightning:' + value.toUpperCase() const provider = useWebLN() - const toaster = useToast() useEffect(() => { async function effect () { - if (webLn) { + if (webLn && provider?.enabled) { try { - await provider.sendPayment(value) + await provider.sendPayment({ bolt11: value }) } catch (e) { console.log(e?.message) - toaster.danger(`${provider.name}: ${e?.message}`) } } } effect() - }, []) + }, [provider]) return ( <> diff --git a/components/webln/index.js b/components/webln/index.js index 3f4d072e..da36550b 100644 --- a/components/webln/index.js +++ b/components/webln/index.js @@ -87,7 +87,8 @@ function RawWebLNProvider ({ children }) { autohide: false, onCancel: async () => { try { - await cancelInvoice({ variables: { hash, hmac } }) + // hash and hmac are only passed for HODL invoices + if (hash && hmac) await cancelInvoice({ variables: { hash, hmac } }) canceled = true toaster.warning('payment canceled') removeToast = undefined diff --git a/components/webln/nwc.js b/components/webln/nwc.js index f59330e9..190d436c 100644 --- a/components/webln/nwc.js +++ b/components/webln/nwc.js @@ -1,6 +1,6 @@ // https://github.com/getAlby/js-sdk/blob/master/src/webln/NostrWeblnProvider.ts -import { createContext, useCallback, useContext, useEffect, useState } from 'react' +import { createContext, useCallback, useContext, useEffect, useRef, useState } from 'react' import { Relay, finalizeEvent, nip04 } from 'nostr-tools' import { parseNwcUrl } from '../../lib/url' @@ -13,11 +13,21 @@ export function NWCProvider ({ children }) { const [secret, setSecret] = useState() const [enabled, setEnabled] = useState() const [initialized, setInitialized] = useState(false) - const [relay, setRelay] = useState() + + const relayRef = useRef() const name = 'NWC' const storageKey = 'webln:provider:nwc' + const updateRelay = async (relayUrl) => { + try { + relayRef.current?.close() + if (relayUrl) relayRef.current = await Relay.connect(relayUrl) + } catch (err) { + console.error(err) + } + } + const loadConfig = useCallback(async () => { const configStr = window.localStorage.getItem(storageKey) if (!configStr) { @@ -39,6 +49,7 @@ export function NWCProvider ({ children }) { try { const supported = await validateParams(params) setEnabled(supported.includes('pay_invoice')) + await updateRelay(params.relayUrl) } catch (err) { console.error('invalid NWC config:', err) setEnabled(false) @@ -69,6 +80,7 @@ export function NWCProvider ({ children }) { try { const supported = await validateParams(params) setEnabled(supported.includes('pay_invoice')) + await updateRelay(params.relayUrl) } catch (err) { console.error('invalid NWC config:', err) setEnabled(false) @@ -85,25 +97,12 @@ export function NWCProvider ({ children }) { setEnabled(undefined) }, []) - useEffect(() => { - let relay - (async function () { - if (relayUrl) { - relay = await Relay.connect(relayUrl) - setRelay(relay) - } - })().catch((err) => { - console.error(err) - setRelay(null) - }) - return () => { - relay?.close() - setRelay(null) - } - }, [relayUrl]) - const sendPayment = useCallback((bolt11) => { return new Promise(function (resolve, reject) { + const relay = relayRef.current + if (!relay) { + return reject(new Error('not connected to relay')) + } (async function () { // XXX set this to mock NWC relays const MOCK_NWC_RELAY = false @@ -168,9 +167,9 @@ export function NWCProvider ({ children }) { }) })().catch(reject) }) - }, [relay, walletPubkey, secret]) + }, [walletPubkey, secret]) - const getInfo = useCallback(() => getInfoWithRelay(relay, walletPubkey), [relay, walletPubkey]) + const getInfo = useCallback(() => getInfoWithRelay(relayRef?.current, walletPubkey), [relayRef?.current, walletPubkey]) useEffect(() => { loadConfig().catch(console.error)