chore: upgrade to ENSv2 (Universal Resolver)#49
Conversation
Route the package-level Resolve and ReverseResolve through the ENS Universal Resolver proxy at 0xeEeEEEeE14D718C2B47D9923Deab1335E144EeEe instead of walking the legacy registry. CCIP-Read (ERC-3668) is followed transparently via a new ccipread package, so offchain and L2 names now resolve correctly. Legacy Resolver/Registry/ReverseResolver/Name types keep their existing behaviour so write paths (SetAddress, SetText, etc.) are unaffected and no public function signatures change. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
| func TestResolveEthereum(t *testing.T) { | ||
| expected := "de0b295669a9fd93d5f28d9ec85e40f4cb697bae" | ||
| actual, err := Resolve(client, "ethereum.eth") | ||
| func TestResolveVitalik(t *testing.T) { |
There was a problem hiding this comment.
Do not test for vitalik.eth, he might change his address and this test will break than. Better to use any of the resolution-tests: https://github.com/ensdomains/resolution-tests/blob/main/test-cases.json
There was a problem hiding this comment.
Good point, agreed vitalik.eth is fragile. I've removed TestResolveVitalik entirely in e68d7b4 rather than adding yet another fixture: forward-resolution coverage already lives in universalresolver_test.go against the canonical ur.integration-tests.eth and test.offchaindemo.eth. The package-level Resolve is just a thin wrapper around UniversalResolver.ResolveAddress, so duplicating the assertion here didn't add much.
| name: "Invalid ENS domain", | ||
| expected: "", | ||
| input: "foo.bar", | ||
| input: "sirnotappearinginthisregistry.eth", |
There was a problem hiding this comment.
Fair concern. I switched to a longer descriptive label in e68d7b4 (this-name-is-not-registered-go-ens-test-fixture-do-not-register.eth) and added a comment flagging the registration-risk caveat. Worth noting: any .eth name is technically registerable, so this just makes a collision extremely less likely rather than impossible.
- Drop TestResolveVitalik from resolver_test.go: vitalik.eth's address could change, and the rename was unnecessary churn since broader Resolve coverage already lives in universalresolver_test.go. - Replace sirnotappearinginthisregistry.eth in tokenid_test.go with a longer, descriptive label that's much less likely to be registered; add a comment noting the registration-risk caveat. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Hey! I'm Dhaiwat from DevRel at ENS Labs, and I'm working with library maintainers across the ecosystem to get them ready for ENSv2. Closes #38 (Support CCIP Read and ENSIP-10).
This PR routes ENS resolution through the Universal Resolver (ENSv2) instead of the legacy ENS registry. ENSIP-10 wildcard resolution and EIP-3668 CCIP-Read both fall out of this routing.
ResolveandReverseResolvethrough the Universal Resolver at0xeEeEEEeE14D718C2B47D9923Deab1335E144EeEe. Without this, names with offchain (CCIP-Read) or L2 records — including the wildcard ENSv2 names rolling out now — silently return0x0or fail becausego-enswas walking the legacy registry directly instead of the UR proxy.ccipreadpackage implementing the ERC-3668OffchainLookupflow: decodes the revert viarpc.DataError, queries gateway URLs (GET when the URL contains{data}/{sender}, POST otherwise; 4xx aborts and 5xx falls through to the next URL), and re-invokes the callback selector. Bounded to 4 hops, matching viem/ethers.contracts/universalresolver/(ABI from ens-contractsstaging).UniversalResolverwrapper at the package root (Resolve,ResolveAddress,Reverse) plus aDNSEncodehelper for thebytes nameargument.ResolverNotFoundError(Error →"unregistered name", wrapsErrUnregistered),EmptyAddressError(wrapsErrNoAddress),ResolverNotContractError,UnsupportedResolverProfileError,ResolverErrorError,HTTPGatewayError,ReverseAddressMismatchError. Existing strings like"unregistered name"are preserved so most downstream error checks keep working.ur.integration-tests.eth(UR sentinel) andtest.offchaindemo.eth(CCIP-Read end-to-end), plus 6 unit tests for the error decoder. RPC defaults tohttps://ethereum.publicnode.comand is overridable viaGO_ENS_TEST_RPC. Three pre-existing tests had stale assertions updated.Resolver/Registry/ReverseResolver/Nametypes keep all their methods — write paths (SetAddress,SetText,SetContenthash, etc.) still target specific resolver contracts via the registry.Resolver.Address()/Name.Address(coinType)still walk the legacy path because they're paired with write methods on the same struct; happy to migrate those reads through UR too in a follow-up if you want full coverage.Verification
A/B test against the upstream
@latestversion vs this branch:ens.Resolve(client, "ur.integration-tests.eth")wealdtech/go-ens/v3@latest0x1111111111111111111111111111111111111111(legacy v1)0x2222222222222222222222222222222222222222(ENSv2 ✅)To verify the upgrade, resolve
ur.integration-tests.eth: it should return0x2222222222222222222222222222222222222222via the Universal Resolver. Legacy resolution returns0x1111111111111111111111111111111111111111, so seeing the latter means the upgrade did not take effect.You can read more about ENSv2 readiness here: https://docs.ens.domains/web/ensv2-readiness