Fix text record resolution and enhance CCIP-Read handling#111
Conversation
Text records returned empty because NAME_SERVICE_INTERFACE was missing the getTextRecord read fragment — ethers treated the method as non-existent and the resolver's catch-all swallowed the error as "no record". CCIP-Read POSTs from the ENS app were also rejected because they send Content-Type: text/plain to skip CORS preflight, which express.json() ignored by default.
…olver This commit introduces a comprehensive RFC-style documentation for the Signed-Gateway UniversalResolver, detailing its architecture, interfaces, and EIP-712 payload. The document outlines the resolver's functionality, including its integration with the L2 NameService and the trusted-gateway signature model, replacing the previous zkSync storage proof design.
LCOV of commit
|
There was a problem hiding this comment.
Pull request overview
This PR migrates ENS offchain resolution to a signed-gateway CCIP-Read (ERC-3668) model: the L1 UniversalResolver reverts with OffchainLookup, the gateway resolves against L2 NameService, then returns an EIP-712 signed payload that the L1 resolver verifies.
Changes:
- Replaced storage-proof based verification in
UniversalResolverwith EIP-712 signature verification and trusted signer rotation. - Added a new gateway
/resolveendpoint plus L2 resolution + signing utilities to supportaddr,addr-multichain, andtext. - Added protocol documentation and a Foundry test suite covering core success/failure paths and signer rotation.
Reviewed changes
Copilot reviewed 10 out of 10 changed files in this pull request and generated 11 comments.
Show a summary per file
| File | Description |
|---|---|
src/nameservice/UniversalResolver.sol |
Switches resolver to CCIP-Read + EIP-712 signed responses; adds trusted signers and URL rotation. |
clk-gateway/src/routes/resolve.ts |
Implements the CCIP-Read callback endpoint (/resolve) that decodes (name,data), resolves via L2, and signs responses. |
clk-gateway/src/resolver/resolveFromL2.ts |
Adds L2 resolution dispatcher for addr, addr-multichain, and text and returns ABI-encoded results. |
clk-gateway/src/resolver/signResolution.ts |
Adds EIP-712 signing for Resolution(name,data,result,expiresAt) and ABI-encodes the callback response payload. |
clk-gateway/src/setup.ts |
Wires env/config for resolver signer, L1 resolver address, chainId, and signature TTL. |
clk-gateway/src/index.ts |
Extends JSON parsing to accept text/plain and registers the new /resolve router. |
clk-gateway/src/interfaces.ts |
Extends NameService interface with getTextRecord. |
script/DeployL1Ens.s.sol |
Refactors deployment for signed-gateway resolver model and adds optional ENS setResolver step. |
test/nameservice/UniversalResolver.t.sol |
Adds Foundry tests for signature verification, TTL bounds, signer rotation, and interface support. |
src/nameservice/doc/signed-resolver-protocol.md |
Adds RFC-style protocol specification for the signed-gateway resolver model. |
aliXsed
left a comment
There was a problem hiding this comment.
Consolidated inline review — 10 items across the changeset, ordered by priority.
|
Tracking issue for evaluating a trustless alternative to the signed-gateway interim solution: NodleCode/meta#169 — Evaluate Unruggable Gateways ZkSync support as replacement for trusted signed-gateway. The signed-gateway model in this PR is standards-compliant (ERC-3668, ENSIP-10) and matches what Coinbase/Uniswap/ENS reference use in production. However, Unruggable Gateways already has ZkSync support ( |
Restore the original storage-proof UniversalResolver.sol as a historical artifact. The new EIP-712 signed-gateway model lives in SignedUniversalResolver.sol with its own test and deploy script.
The resolver now validates the domain segment of DNS-encoded names against an allowlist (isAllowedDomain), preventing it from blindly triggering OffchainLookup if the ENS registry mistakenly points an unrelated domain at this contract. Adds addDomain/removeDomain admin functions, constructor initial domain parameter, and fuzz tests covering TTL/expiry arithmetic and DNS parsing.
Constructor now takes string[] instead of a single string, so both "nodl" and "clk" can be allowlisted at deploy time. Deploy script reads NS_DOMAINS (comma-separated) with fallback to NS_DOMAIN.
Use calldata instead of memory for string params, pre-increment for counters, extract _bareDomainResponse helper to reduce resolve() line count, and deduplicate callData/extraData in OffchainLookup.
This pull request introduces a new signed-gateway UniversalResolver integration for ENS offchain resolution, adding a
/resolveendpoint that supports CCIP-Read (ERC-3668) with EIP-712 signatures, and refactors deployment scripts and configuration to support the new model. The changes include new resolver logic, EIP-712 signing, configuration wiring, and a simplified deployment script.New ENS Gateway Resolution Functionality:
/resolveroute that implements the CCIP-Read (ERC-3668) callback endpoint, decoding ENS resolution requests, routing them to the correct L2 NameService, and returning EIP-712 signed responses for use with the L1 UniversalResolver. [1] [2] [3]resolveFromL2utility to parse DNS-encoded ENS names, supportaddr,addr-multichain, andtextlookups, and return ABI-encoded results.signResolutionResponsefor EIP-712 signing of resolution results, matching the L1 UniversalResolver contract.Configuration and Setup Updates:
setup.tsto wire up the new resolver signer, L1 resolver address, and signature TTL, and export them for use in the new route. [1] [2] [3] [4]getTextRecordfunction needed by the gateway.Deployment Script Changes:
These changes collectively enable secure, offchain ENS resolution via a gateway that signs responses for L1 verification, modernizing the resolver infrastructure and deployment flow.