diff --git a/wallets/client/components/form/hooks.js b/wallets/client/components/form/hooks.js index 579ed176e..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 - } - // remove domain part since we will append it automatically if lud16Domain is set - if (lud16Domain && value) { - value = value.split('@')[0] - } + 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 + value = value.split('@')[0] } return { @@ -120,6 +116,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..f6be82f5a 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}` @@ -180,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..8cd59015d 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,30 @@ 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 lud16Domain = walletLud16Domain(wallet.name) + const nwcLud16Domain = nwcLud16.split('@')[1] + if (lud16Domain && nwcLud16Domain !== lud16Domain) { + return null + } + + return nwcLud16 +}