Skip to content

docs(design): what the gateway signs for, CORS, and ENSv2 - #29

Merged
xgreenx merged 4 commits into
design/ens-integrationfrom
design/ens-gateway-invocation
Sep 9, 2026
Merged

xgreenx merged 4 commits into
design/ens-integrationfrom
design/ens-gateway-invocation

Conversation

@xgreenx

@xgreenx xgreenx commented Sep 7, 2026

Copy link
Copy Markdown
Contributor

Stacked on #7 (design/ens-integration), so the diff is only what this adds. Companion to libid-org/libid-contracts#23, which pins the resolver side.

What this adds

  • What the gateway signs for (under The backend): the resolver in the digest is the address the gateway is configured to serve, never the {sender} in the path. Step 6 of the work list now says resolver, not sender. {sender} is logged, not parsed strictly (viem lowercases it). One instance per resolver.
  • CORS, on every response: why the browser fetches the gateway directly today, which headers, and that they belong in the binary rather than a proxy.
  • Direct invocation, later: the condition under which a future deployment may announce ERC-7996 with the multicall feature, and that it is a new deployment.
  • ENSv2 changes none of this (under Namespace): v2's DNSTLDResolver consults the v1 registry first and forwards to the resolver it finds, so the import and the resolver survive v2 unchanged; only .eth names have a migration.
  • One sentence in The trust model and one in the testing note, pointing at the above.

Why

ENS's ResolverCaller (today's mainnet UniversalResolver and v2's DNSTLDResolver share it) reaches a resolver by one of two routes. Through the batch gateway (ENSIP-21) the original sender survives, so {sender} is our resolver. Directly, which ERC-7996 switches on (ENSIP-22), the universal resolver raises the OffchainLookup again under its own address, so {sender} becomes the universal resolver. The doc previously specified signing for sender, which is the reference offchain-resolver gateway's behaviour and fails on the second route. Signing for a configured address holds on both and costs one setting.

The mainnet universal resolver's batch gateway provider advertises ["https://ccip-v3.ens.xyz", "x-batch-gateway:true"]; viem prefers the local marker and runs the batch gateway in the page, so the gateway is fetched cross-origin from the wallet's site today, not only under ERC-7996.

References: ENSIP-21, ENSIP-22, ResolverCaller.sol, CCIPReader.sol, DNSTLDResolver.sol, viem localBatchGatewayRequest.ts.

Observed

Sepolia handles.link already has an owner and a HandleResolver (0xd46181CAb629AEDA48406b462656513821De6775, ERC-7996 not announced, URL http://127.0.0.1:8080/ens/{sender}/{data}.json). Mainnet has neither yet. No gateway exists in the org, so the CORS requirement lands here rather than as a code change.

The gateway signs for the resolver address it is configured to serve, not
the {sender} in the path: through the batch gateway the two agree, but a
resolver announcing ERC-7996 is called directly and the universal resolver
raises the lookup again under its own address. CORS goes on every response
because viem runs the batch gateway in the page and fetches the gateway
cross-origin. ENSv2's DNS TLD resolver consults the v1 registry first, so
the import and the resolver survive v2 unchanged.

Assisted-by: Claude Fable 5.1
Signed-off-by: xgreenx <xgreenx9999@gmail.com>
… only method

The gateway in usernames-indexer#5 compares {sender} to its configured
resolver and answers a terminal 400 on mismatch; the digest never uses it.
Say so, instead of "logged and not parsed strictly". The resolver's urls
carry {data} and the deployment workflow refuses a template without it, so
ERC-3668's POST form never occurs; drop the OPTIONS clause that promised it.

Assisted-by: Claude Fable 5.1
Signed-off-by: xgreenx <xgreenx9999@gmail.com>
… no RPC

Aligns the backend section with usernames-indexer#7: answers come from the
indexed model, chains are whatever indexers have written into the store,
and the gateway takes no per-chain configuration.

Assisted-by: Claude Fable 5.1
Signed-off-by: xgreenx <xgreenx9999@gmail.com>
…d, and never decodes them

The backend block said "no database" and decoded the coin type, which is
not what usernames-indexer#7 does: the gateway reads the Postgres mirror
the indexer keeps, matches a coin type forward against the chains the store
holds, and answers null for a label that names another chain.

Assisted-by: Claude Fable 5.1
Signed-off-by: xgreenx <xgreenx9999@gmail.com>
@xgreenx
xgreenx merged commit 9aafeaa into design/ens-integration Sep 9, 2026
4 checks passed
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.

2 participants