Skip to content

Migrate ENS resolution to the Universal Resolver#483

Open
tony8713 wants to merge 1 commit into
masterfrom
migrate-ens-universal-resolver
Open

Migrate ENS resolution to the Universal Resolver#483
tony8713 wants to merge 1 commit into
masterfrom
migrate-ens-universal-resolver

Conversation

@tony8713

Copy link
Copy Markdown
Contributor

Why

ENS reverse resolution went through the legacy ReverseRecords helper contract (getNames), which only reads on-chain reverse records. Two real-world failures ENS reported:

  • Addresses whose primary name is set via an off-chain / CCIP-Read resolver never resolved (e.g. avsa.eth, 0x809FA673fe2ab515FaA168259cB14E2BeDeBF68e).
  • The batch call reverts on some inputs (e.g. expired domains like 0x9c3aC02Cd616a82C83830e40D45c9534b32c4934), which could take the whole batch down.

What

Reverse and forward resolution now go through the ENS Universal Resolver (0xeEeEEEeE14D718C2B47D9923Deab1335E144EeEe) using a viem client boxed inside the address-resolver module (src/addressResolvers/universalResolver.ts). viem follows the CCIP-Read OffchainLookup flow natively (ethers v5 does not for raw calls), and the Universal Resolver forward-verifies the reverse claim on-chain. Each address/name is resolved independently via Promise.allSettled, so one bad entry can't fail the rest, and reverting/expired names return null instead of throwing.

The module's external API (lookupAddresses, resolveNames) is unchanged. Forward resolution no longer depends on the ENS subgraph, and the avatar resolver reads the avatar text record through the same client (the metadata.ens.domains fallback stays).

Notes:

  • viem stays boxed in that one module (plain JS in/out, no viem types leak); ethers v5 remains everywhere else.
  • viem and typescript are pinned exactly: viem 2.55 pulls an ox version whose experimental tempo module fails to type-check, and ts-jest 28 targets TypeScript < 5.0. viem 2.37.6 already ships the new Universal Resolver support and TS 5.4.5 (needed for viem's types) keeps the toolchain working.

Test plan

Live-verified against mainnet (rpc.snapshot.org):

  • Normal name: 0xE6D0Dd18C6C3a9Af8C2FaB57d6e6A38E29d513cC -> sdntestens.eth (and forward back).
  • Off-chain / CCIP resolver: 0x809FA673fe2ab515FaA168259cB14E2BeDeBF68e -> avsa.eth (previously unresolved).
  • Expired domain: 0x9c3aC02Cd616a82C83830e40D45c9534b32c4934 -> null, no throw.
  • Blank address returns {}; mixed batches isolate the bad entry.

yarn lint, yarn typecheck, and yarn build all pass. Full yarn test passes except for pre-existing shibarium / unstoppable-domains integration failures that are unrelated to this change (verified identical on master).

Reverse resolution went through the legacy ReverseRecords helper
(getNames), which only reads on-chain reverse records. Names served by
off-chain / CCIP-Read resolvers (e.g. avsa.eth) never resolved, and the
batch call reverts on some inputs (e.g. expired domains), taking the
whole batch down.

Route reverse and forward resolution through the ENS Universal Resolver
(0xeEeE…eEeE) via a viem client boxed inside the address-resolver module.
viem follows the CCIP-Read OffchainLookup flow natively, and the
Universal Resolver forward-verifies the reverse claim on-chain. Each
address/name resolves independently so one bad entry can't fail the rest.
Forward resolution no longer depends on the ENS subgraph, and the avatar
resolver reads its text record through the same client.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant