From 73c612adfa944ebaaeff47fc70d693e0c087feb0 Mon Sep 17 00:00:00 2001 From: ekzyis Date: Thu, 6 Nov 2025 16:50:31 +0100 Subject: [PATCH 1/3] Better comments regarding lud16 domain handling in wallet forms --- wallets/client/components/form/hooks.js | 3 ++- wallets/client/components/form/index.js | 2 ++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/wallets/client/components/form/hooks.js b/wallets/client/components/form/hooks.js index 579ed176e..f3d1170ba 100644 --- a/wallets/client/components/form/hooks.js +++ b/wallets/client/components/form/hooks.js @@ -104,7 +104,7 @@ export function useProtocolForm (protocol) { 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 + // remove domain part since we will append it automatically on submit if lud16Domain is set if (lud16Domain && value) { value = value.split('@')[0] } @@ -120,6 +120,7 @@ export function useProtocolForm (protocol) { if (lud16Domain) { schema = schema.transform(({ address, ...rest }) => { return { + // append domain part to pass validation on submit address: address ? `${address}@${lud16Domain}` : '', ...rest } diff --git a/wallets/client/components/form/index.js b/wallets/client/components/form/index.js index 55dc93e97..77b545a29 100644 --- a/wallets/client/components/form/index.js +++ b/wallets/client/components/form/index.js @@ -100,6 +100,8 @@ function WalletProtocolForm () { // create a copy of values to avoid mutating the original const onSubmit = useCallback(async ({ ...values }) => { + // the schema transformation already does this to pass validation on submit + // so it would be better to use the transformed values instead of manually appending the domain part again here const lud16Domain = walletLud16Domain(wallet.name) if (values.address && lud16Domain) { values.address = `${values.address}@${lud16Domain}` From cc29bd6022eb98f8948739e5c627089ecfb06f50 Mon Sep 17 00:00:00 2001 From: ekzyis Date: Thu, 6 Nov 2025 17:10:30 +0100 Subject: [PATCH 2/3] Refactor initial values for forms with new field.populate callback --- wallets/client/components/form/hooks.js | 18 +++++++---------- wallets/client/components/form/index.js | 2 +- wallets/lib/protocols/index.js | 8 ++++++++ wallets/lib/protocols/lnAddr.js | 26 +++++++++++++++++++++++-- 4 files changed, 40 insertions(+), 14 deletions(-) diff --git a/wallets/client/components/form/hooks.js b/wallets/client/components/form/hooks.js index f3d1170ba..80830316f 100644 --- a/wallets/client/components/form/hooks.js +++ b/wallets/client/components/form/hooks.js @@ -2,7 +2,6 @@ import { isTemplate, isWallet, protocolClientSchema, protocolFields, protocolFor import { createContext, useContext, useEffect, useMemo, useCallback, useState } from 'react' import { useWalletProtocolUpsert } from '@/wallets/client/hooks' import { MultiStepForm, useFormState, useStep } from '@/components/multi-step-form' -import { parseNwcUrl } from '@/wallets/lib/validate' export const Step = { SEND: 'send', @@ -83,9 +82,9 @@ function useProtocolFormState (protocol) { } export function useProtocolForm (protocol) { + const [globalFormState] = useFormState() const [formState, setFormState] = useProtocolFormState(protocol) const [complementaryFormState] = useProtocolFormState({ name: protocol.name, send: !protocol.send }) - const [nwcSendFormState] = useProtocolFormState({ name: 'NWC', send: true }) const wallet = useWallet() const lud16Domain = walletLud16Domain(wallet.name) const fields = protocolFields(protocol) @@ -98,16 +97,13 @@ export function useProtocolForm (protocol) { value = complementaryFormState?.config?.[field.name] } - if (protocol.name === 'LN_ADDR' && field.name === 'address' && lud16Domain) { - // 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 - } + if (!value && field.populate && globalFormState) { + value = field.populate(wallet, globalFormState) + } + + if (lud16Domain && value) { // remove domain part since we will append it automatically on submit if lud16Domain is set - if (lud16Domain && value) { - value = value.split('@')[0] - } + value = value.split('@')[0] } return { diff --git a/wallets/client/components/form/index.js b/wallets/client/components/form/index.js index 77b545a29..f6be82f5a 100644 --- a/wallets/client/components/form/index.js +++ b/wallets/client/components/form/index.js @@ -182,7 +182,7 @@ function WalletProtocolFormField ({ type, ...props }) { const [protocol] = useProtocol() const formik = useFormikContext() - function transform ({ validate, encrypt, editable, help, share, ...props }) { + function transform ({ validate, encrypt, editable, help, share, populate, ...props }) { const [upperHint, bottomHint] = Array.isArray(props.hint) ? props.hint : [null, props.hint] const parseHelpText = text => Array.isArray(text) ? text.join('\n\n') : text diff --git a/wallets/lib/protocols/index.js b/wallets/lib/protocols/index.js index f89a59af5..9b1ce170a 100644 --- a/wallets/lib/protocols/index.js +++ b/wallets/lib/protocols/index.js @@ -36,6 +36,14 @@ import clinkSuite from './clink' * @property {string} [hint] - hint text shown below field * @property {boolean} [share] - whether field can be used to prepopulate field of complementary send/receive protocol * @property {boolean} [editable] - whether the field is editable after it was saved + * @property {ProtocolFieldPopulate} [populate] - function to populate the field using values from other protocol forms + */ + +/** + * @callback ProtocolFieldPopulate + * @param {Object} wallet - the wallet we are configuring + * @param {Object} formState - the current form state across all protocols + * @returns {string|null} - the value to populate the field with, or null if no value is available */ /** @type {Protocol[]} */ diff --git a/wallets/lib/protocols/lnAddr.js b/wallets/lib/protocols/lnAddr.js index 47f1398c8..155a5d09b 100644 --- a/wallets/lib/protocols/lnAddr.js +++ b/wallets/lib/protocols/lnAddr.js @@ -1,4 +1,5 @@ -import { externalLightningAddressValidator } from '@/wallets/lib/validate' +import { externalLightningAddressValidator, parseNwcUrl } from '@/wallets/lib/validate' +import { protocolFormId, walletLud16Domain } from '../util' // Lightning Address (LUD-16) // https://github.com/lnurl/luds/blob/luds/16.md @@ -13,8 +14,29 @@ export default { label: 'address', type: 'text', required: true, - validate: externalLightningAddressValidator + validate: externalLightningAddressValidator, + populate: addressPopulate } ], relationName: 'walletRecvLightningAddress' } + +function addressPopulate (wallet, formState) { + const nwcFormId = protocolFormId({ name: 'NWC', send: true }) + const nwcFormState = formState[nwcFormId] + if (!nwcFormState?.config?.url) { + return null + } + + const { lud16: nwcLud16 } = parseNwcUrl(nwcFormState.config.url) + if (!nwcLud16) { + return null + } + + const nwcLud16Domain = nwcLud16.split('@')[1] + if (nwcLud16Domain !== walletLud16Domain(wallet.name)) { + return null + } + + return nwcLud16 +} From 02a900d9529f0851ffa281b8d7e529024f957ec3 Mon Sep 17 00:00:00 2001 From: ekzyis Date: Thu, 6 Nov 2025 17:33:45 +0100 Subject: [PATCH 3/3] Only ignore NWC lud16 param on domain mismatch if domain is given --- wallets/lib/protocols/lnAddr.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/wallets/lib/protocols/lnAddr.js b/wallets/lib/protocols/lnAddr.js index 155a5d09b..8cd59015d 100644 --- a/wallets/lib/protocols/lnAddr.js +++ b/wallets/lib/protocols/lnAddr.js @@ -33,8 +33,9 @@ function addressPopulate (wallet, formState) { return null } + const lud16Domain = walletLud16Domain(wallet.name) const nwcLud16Domain = nwcLud16.split('@')[1] - if (nwcLud16Domain !== walletLud16Domain(wallet.name)) { + if (lud16Domain && nwcLud16Domain !== lud16Domain) { return null }