Reverse-lookup names (ENS / UD / ZNS) across send flow and tx history#6008
Reverse-lookup names (ENS / UD / ZNS) across send flow and tx history#6008
Conversation
Convert AddressModal and SendComponent to React.FC<Props>, and replace
the two `styled()` wrappers in SendScene2 with regular React Native
components driven by `useTheme()` + `cacheStyles()`. No behavior change.
The slider-view snapshot updates reflect two equivalent shifts: the old
`styled(View)` HOC was incidentally forwarding `hasNotifications` and
`insetBottom` as DOM props (which the underlying View ignored), and the
inlined style is now an array `[base, { bottom }]` rather than a merged
object. Both render to the same pixels.
Touched here in preparation for reverse-lookup edits in subsequent
commits, per the lint-warnings.sh workflow contract for files entering
the working set.
Introduces `src/util/nameServices.ts` with a `reverseLookupName(pluginId, address)` function that maps each chain to its supported reverse-lookup services and tries them in order (positive result wins, transient failures don't poison the cache). Service eligibility: - ZNS: zcash only - ENS: ethereum only (ENSIP-3 L1 mainnet via ethers v5 lookupAddress) - Unstoppable Domains: any EVM chain when UNSTOPPABLE_DOMAINS_API_KEY is set (UD reverse only resolves EVM addresses per their docs) The cache uses guard-on-success semantics: results are cached when the dispatch chain completes cleanly, but transient errors leave the entry empty so the next call retries. Inflight dedup prevents duplicate network hits when the same address renders in many list rows. This replaces the ad-hoc cache in `useZnsName` with a service-aware equivalent that subsequent commits will wire into the send and transaction-history scenes.
Adds `useReverseName` (a multi-service replacement for `useZnsName`) and the `NameServicePrefix` visual element, then swaps both TransactionListRow and TransactionDetailsScene over to the new hook. UX surfaces: - TransactionListRow: text-only render. The list is dense enough that an inline logo would crowd the row; the resolved name still appears, just without the badge. - TransactionDetailsScene: prefix the resolved name with a 1rem-tall logo. The prefix only renders when the displayed name actually came from a reverse lookup — user-set contact names and the default "To"/"From" label render plain. Missing logo assets (UD, ZNS today) fall back to no-prefix without reserving space. LoginActions swaps `clearZnsLookupCache` for `clearReverseLookupCache` on the same logout boundary so per-login cache state stays isolated. The legacy `useZnsName` hook has no remaining consumers and is removed. The TransactionDetailsScene snapshot picks up the new row-layout `<View>` wrapper that hosts the optional prefix; the wrapper is benign when no prefix is present.
Wires the reverse-lookup dispatcher into AddressTile2's address-entry
path and threads the result through SendScene2 so resolved names appear
in the send tile and persist into transaction metadata.
AddressTile2 changes:
- Replace `ChangeAddressResult.znsName` with `resolvedName`, a
`{ name, service }` pair that captures both forward-typed names
(alice.eth, alice.zcash, alice.zec) and reverse-resolved names from
raw addresses.
- After parseUri succeeds and we have a public address, attempt a
reverse lookup if no forward-typed name was captured. The dispatcher
caches per (pluginId, address) so repeated entry of the same address
is a no-op.
- New `recipientNameService` prop drives an inline `NameServicePrefix`
badge above the address. FIO and Zano handles continue to render
plain (no badge), preserving the prior look for those flows.
SendScene2 changes:
- Carry `resolvedName` through `spendTarget.otherParams` and the
`EditableAmountTile` title (still text-only per the design — the tile
is a confirmation snapshot, not the live entry surface).
- Generalize the post-broadcast `payeeName` derivation so any
single-resolved-name spendInfo (ENS / UD / ZNS) produces a payeeName,
replacing the chain-specific Zcash branch.
Outcome: pasting a 0x address to an Ethereum send shows the resolved
ENS / UD name above the hex address as soon as the lookup completes,
and that name persists as `payeeName` in the broadcasted transaction's
metadata so it surfaces in the transaction history.
When the user pastes or types a string that doesn't match any forward- domain pattern, attempt a reverse lookup against the wallet's pluginId and surface the resolved name in the input's `validLabel` slot. The existing forward-resolution path (which puts the resolved address in the same slot) is unchanged, so the green helper text is symmetric: - type alice.eth → see 0x… resolve below the input - paste 0x… → see alice.eth resolve below the input A monotonically increasing sequence counter scopes each lookup to the input it was issued for, so a slow late-arriving result can't clobber the label after the user has moved on. Adds the user-visible CHANGELOG entry covering the full reverse-lookup feature (this commit plus the prior three on this branch).
a1911f1 to
1c1a20a
Compare
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 2 potential issues.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit 1c1a20a. Configure here.
|
|
||
| if (allServicesSucceeded) { | ||
| cache.set(cacheKey(pluginId, address), null) | ||
| } |
There was a problem hiding this comment.
Uncached UD failures cause repeated network lookups
Medium Severity
For Ethereum mainnet (['ens', 'unstoppable']), when ENS returns null (no reverse record) and the UD SDK's reverse() throws a "no record" error (a permanent condition in the UD SDK), allServicesSucceeded becomes false and the null result is never cached. Since most Ethereum addresses lack UD reverse records, every navigation to a transaction list or re-mount triggers fresh ENS + UD network calls for each unique send-recipient address, defeating the cache entirely. The "guard-on-success" semantics correctly handle transient network errors but do not distinguish them from permanent "no record found" errors thrown by the UD SDK.
Additional Locations (1)
Reviewed by Cursor Bugbot for commit 1c1a20a. Configure here.
| parsedUri.publicAddress | ||
| ) | ||
| if (reverse != null) resolvedName = reverse | ||
| } |
There was a problem hiding this comment.
Reverse lookup blocks send flow without loading indicator
Medium Severity
The await reverseLookupName(…) call in changeAddress runs after setLoading(false) has already dismissed the full-screen spinner. For a first-time Ethereum address lookup this fires sequential network calls to ENS and Unstoppable Domains with no visible loading indicator, causing an unresponsive-looking pause of potentially several seconds before onChangeAddress completes.
Reviewed by Cursor Bugbot for commit 1c1a20a. Configure here.


CHANGELOG
Does this branch warrant an entry to the CHANGELOG?
Dependencies
none
Requirements
If you have made any visual changes to the GUI. Make sure you have:
Description
Asana task
Asana task
Reverse-resolve recipient addresses to ENS / Unstoppable Domains / ZNS names across the send flow, address modal, and transaction history. Previously only forward resolution worked (typing
alice.ethresolved to0x…); now pasting0x…surfacesalice.ethand that name persists into transaction metadata.What's in the branch (oldest → newest)
Fix lint warnings before reverse-lookup feature —
lint-warnings.shprep on the touched files: convertAddressModalandSendComponenttoReact.FC<Props>, and replace twostyled()wrappers inSendScene2withuseTheme()+cacheStyles()equivalents. Pure refactor; behavior preserved (snapshot diff is incidental DOM-prop leakage that the new code correctly drops).Add reverse-lookup dispatcher for ENS, UD, and ZNS — new
src/util/nameServices.tswith areverseLookupName(pluginId, address)function. Per-chain dispatch:ethersv5lookupAddress; ENSIP-19 multichain reverse needs ethers v6, out of scope).caip2.namespace === 'eip155'), only whenUNSTOPPABLE_DOMAINS_API_KEYis set. UD'sreverseonly resolves EVM addresses per their docs.Cache uses guard-on-success semantics: positive results cache eagerly, but transient errors don't get cached as
null(avoids poisoning addresses across the process lifetime). Inflight dedup prevents duplicate network hits when the same address renders in many list rows on first paint.Use reverse-lookup dispatcher in transaction history — adds
useReverseName(multi-service replacement for the olduseZnsName) and a smallNameServicePrefixvisual element (1rem inline logo). Swaps bothTransactionListRowandTransactionDetailsSceneover.TransactionListRow: text-only render (the row is dense; an inline logo would crowd it).TransactionDetailsScene: prefix the resolved name with a 1rem-tall logo, but only when the displayed name actually came from a reverse lookup. User-set contact names and the default "To"/"From" label render plain. Missing logo assets (UD, ZNS today) fall back to no-prefix without reserving space.Reverse-lookup names in send flow — wires the dispatcher into
AddressTile2's entry path. AfterparseUrisucceeds, attempts a reverse lookup if no forward-typed name was captured. The newrecipientNameServiceprop drives the inlineNameServicePrefixbadge above the address. FIO and Zano handles continue to render plain.SendScene2carriesresolvedNamethroughspendTarget.otherParamsand the post-broadcastpayeeNameso the resolved name persists into transaction metadata (the chain-specific Zcash branch is generalized to handle any service).Live reverse-lookup feedback in AddressModal — when the user pastes an address into the address modal, attempt a reverse lookup gated on
coreWallet.parseUrisucceeding (so we only hit the network when the input is a valid address for the chain — no per-keystroke lookups). Surfaces the resolved name in the input's existing greenvalidLabelslot, mirroring the forward-resolution UX. A monotonically increasing sequence counter scopes each lookup so a slow late-arriving result can't clobber the label after the user has moved on.Visual design notes
AddressTile2andTransactionDetailsScene. Transaction list rows stay text-only (per discussion).src/assets/images/ens_logo.png). UD and ZNS render text-only until assets are added — the component degrades gracefully (no placeholder, no reserved space).Caveats / known limitations
UNSTOPPABLE_DOMAINS_API_KEY; only resolves EVM addresses per UD's documentedResolution.reversescope.The dispatcher is structured so adding a new service or expanding chain support is a one-spot change in
getReverseLookupServices.Note
Medium Risk
Touches send-recipient handling and transaction display/metadata, adding new async network lookups and caching that could affect UI correctness or performance if misbehaving. Core funds flow remains unchanged, but name resolution failures/latency need verification across chains and environments (UD API key).
Overview
Adds multi-service reverse name resolution (ENS, Unstoppable Domains, ZNS) so pasted recipient addresses can display a human-readable name and persist that name through the send flow.
Introduces
util/nameServices+useReverseName(with caching/inflight dedupe) and replaces the Zcash-onlyuseZnsNameusages in transaction list/details; details view can now show an inline service badge via newNameServicePrefix.Updates
AddressTile2andAddressModalto attempt reverse lookup after successful address parsing (with stale-result guards), and refactorsSendScene2layout/styling while switching spend-target metadata fromznsNameto a genericresolvedName(name + service).Reviewed by Cursor Bugbot for commit 1c1a20a. Bugbot is set up for automated code reviews on this repo. Configure here.