Use NWC lud16 parameter as initial value for lightning addresses (#2564)

* Also check protocol name before setting address field

* Add comment why we remove the domain part if lud16Domain is set

* Refactor NWC url parsing

* Use NWC's lud16 parameter as initial value

* Select lnAddr form by default if lud16 was parsed
This commit is contained in:
ekzyis 2025-09-22 00:35:44 +02:00 committed by GitHub
parent fe160ef698
commit a544e3952d
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 28 additions and 16 deletions

View File

@ -2,6 +2,7 @@ import { isTemplate, isWallet, protocolClientSchema, protocolFields, protocolFor
import { createContext, useContext, useEffect, useMemo, useCallback, useState } from 'react' import { createContext, useContext, useEffect, useMemo, useCallback, useState } from 'react'
import { useWalletProtocolUpsert } from '@/wallets/client/hooks' import { useWalletProtocolUpsert } from '@/wallets/client/hooks'
import { MultiStepForm, useFormState, useStep } from '@/components/multi-step-form' import { MultiStepForm, useFormState, useStep } from '@/components/multi-step-form'
import { parseNwcUrl } from '@/wallets/lib/validate'
export const Step = { export const Step = {
SEND: 'send', SEND: 'send',
@ -50,14 +51,21 @@ export function useWalletProtocols () {
export function useProtocol () { export function useProtocol () {
const { protocol, setProtocol } = useContext(WalletMultiStepFormContext) const { protocol, setProtocol } = useContext(WalletMultiStepFormContext)
const protocols = useWalletProtocols() const protocols = useWalletProtocols()
const [lnAddrForm] = useProtocolForm({ name: 'LN_ADDR', send: false })
useEffect(() => { useEffect(() => {
// when we move between send and receive, we need to make sure that we've selected a protocol // this makes sure that we've always selected a protocol (that exists) when moving between send and receive
// that actually exists, so if the protocol is not found, we set it to the first protocol
if (!protocol || !protocols.find(p => p.id === protocol.id)) { if (!protocol || !protocols.find(p => p.id === protocol.id)) {
// we switch to the LN_ADDR protocol form if it exists and there's an initial value
// else we just select the first protocol.
const lnAddrProto = protocols.find(p => p.name === 'LN_ADDR')
if (lnAddrForm?.initial.address && lnAddrProto) {
setProtocol(lnAddrProto)
} else {
setProtocol(protocols[0]) setProtocol(protocols[0])
} }
}, [protocol, protocols, setProtocol]) }
}, [protocol, protocols, setProtocol, lnAddrForm])
// make sure we always have a protocol, even on first render before useEffect runs // make sure we always have a protocol, even on first render before useEffect runs
return useMemo(() => [protocol ?? protocols[0], setProtocol], [protocol, protocols, setProtocol]) return useMemo(() => [protocol ?? protocols[0], setProtocol], [protocol, protocols, setProtocol])
@ -77,6 +85,7 @@ function useProtocolFormState (protocol) {
export function useProtocolForm (protocol) { export function useProtocolForm (protocol) {
const [formState, setFormState] = useProtocolFormState(protocol) const [formState, setFormState] = useProtocolFormState(protocol)
const [complementaryFormState] = useProtocolFormState({ name: protocol.name, send: !protocol.send }) const [complementaryFormState] = useProtocolFormState({ name: protocol.name, send: !protocol.send })
const [nwcSendFormState] = useProtocolFormState({ name: 'NWC', send: true })
const wallet = useWallet() const wallet = useWallet()
const lud16Domain = walletLud16Domain(wallet.name) const lud16Domain = walletLud16Domain(wallet.name)
const fields = protocolFields(protocol) const fields = protocolFields(protocol)
@ -89,9 +98,17 @@ export function useProtocolForm (protocol) {
value = complementaryFormState?.config?.[field.name] value = complementaryFormState?.config?.[field.name]
} }
if (field.name === 'address' && lud16Domain && value) { if (protocol.name === 'LN_ADDR' && field.name === 'address') {
// automatically set lightning addresses from NWC urls if lud16 parameter is present
if (nwcSendFormState?.config?.url) {
const { lud16 } = parseNwcUrl(nwcSendFormState.config.url)
if (lud16?.split('@')[1] === lud16Domain) value = lud16
}
// remove domain part since we will append it automatically if lud16Domain is set
if (lud16Domain && value) {
value = value.split('@')[0] value = value.split('@')[0]
} }
}
return { return {
...acc, ...acc,

View File

@ -57,17 +57,12 @@ export function parseNwcUrl (walletConnectUrl) {
// See https://stackoverflow.com/questions/56804936/how-does-only-numbers-in-url-resolve-to-a-domain // See https://stackoverflow.com/questions/56804936/how-does-only-numbers-in-url-resolve-to-a-domain
// However, this seems to only get triggered if a wallet pubkey only contains digits so this is pretty improbable. // However, this seems to only get triggered if a wallet pubkey only contains digits so this is pretty improbable.
const url = new URL(walletConnectUrl) const url = new URL(walletConnectUrl)
const params = {} return {
params.walletPubkey = url.host walletPubkey: url.host,
const secret = url.searchParams.get('secret') secret: url.searchParams.get('secret'),
const relayUrls = url.searchParams.getAll('relay') relayUrls: url.searchParams.getAll('relay'),
if (secret) { lud16: url.searchParams.get('lud16')
params.secret = secret
} }
if (relayUrls) {
params.relayUrls = relayUrls
}
return params
} }
export const socketValidator = (msg = 'invalid socket') => export const socketValidator = (msg = 'invalid socket') =>