Skip to content

docs(specs): specify the ENS integration - #93

Open
SupremaLex wants to merge 18 commits into
mainfrom
docs/ens-integration
Open

SupremaLex wants to merge 18 commits into
mainfrom
docs/ens-integration

Conversation

@SupremaLex

@SupremaLex SupremaLex commented Oct 2, 2026 •

Copy link
Copy Markdown
Member

Rewrites the ENS integration design (design/ens-integration.md) as a normative spec chapter, specs/ens-integration.md, and links it from the specification index (specs/libid.md).

The chapter follows the other specs:

  • terminology, assumptions (ASM-ENS-*) and security properties (SP-ENS-*);
  • requirements for the name grammar, the handle-to-label transform, the Handle Resolver, the Gateway and the keys (REQ-ENS-*);
  • conformance tests (TEST-ENS-01 to -13), security considerations, and a provenance table that says what is implemented where.

The design's reasoning survives as each requirement's "Necessity". Its open decisions are listed under "Not specified".

The spec follows the deployed code

Where the design and the deployed resolver and gateway disagreed, the spec says what the code does:

spec (= code)
EVM chain the Gateway does not index unsigned 503, so the client walks on to another URL in the resolver's list
Coin type 60 the ENS Chain's coin (ENS_CHAIN_ID), not always chain 1
Parent Name a deployment parameter: handles.link in production, a name under it such as testnet.handles.link
Handle rules the Gateway's built-in rules, the same for every chain
Records other than addr signed empty result; the node/name check (400) applies to addr only
Order of checks REQ-ENS-GW-11: the signed nulls come before the staleness check
Coin types ≥ 2^64 non-EVM, signed null
Interfaces the resolver announces ENSIP-10 and ERC-165, not ERC-7996
Signature 65-byte r‖s‖v, v 27 or 28, low s, over the bare digest

Decisions recorded

  • One Signer may serve resolvers on several chains, as the deployment does today. The digest binds the resolver's address, so resolvers sharing a Signer must sit at different addresses (REQ-ENS-KEY-02).
  • Labels refused so the gateway can read the handle back and wallets accept the name. The same rules are in @libid/ens (feat(ens): @libid/ens, the ENS name of a handle #109):
    • X: __ at the third and fourth characters, or any -;
    • GitHub: _, or -- at the third and fourth characters;
    • Workspace: -- at the third and fourth characters (xn-- domains), _at as a piece, an empty piece;
    • any label over 63 bytes.
  • Coin type 60 needs the ENS Chain indexed: a Gateway that answers it must index that chain (REQ-ENS-GW-12).
  • Gateways sharing a URL list must agree on Chain Labels (REQ-ENS-GW-13).
  • A Chain Label must not name a subname with its own deployment, such as testnet (REQ-ENS-NAME-05).

Not met or not enforced today

  • REQ-ENS-KEY-01 (cold owner key): not met. One online KMS key deploys the resolver, owns it, and owns the Parent Name. §11 says so.
  • Deployment rules with no check: REQ-ENS-KEY-02, NAME-05, GW-12 and GW-13. Both deploy paths use nonce-based forge create.
  • The SHOULD in REQ-ENS-LABEL-05: the Gateway still reads names outside the transform's output, such as ab--cd.x and _at.gmail.com.
  • Chain Labels: the indexer's ChainName::parse accepts labels the spec refuses (over 63 bytes, --).
  • Implemented elsewhere: the forward transform is @libid/ens (libID feat(ens): @libid/ens, the ENS name of a handle #109, open), and the HandleResolver NatSpec pointer moves to this spec in libID-contracts popup: mobile-WebKit flake in close-right-after-navigate (CI only) #86.
  • Deployment: production is on Ethereum mainnet, resolver 0xc09b…74CE, with the Gateway at names.handles.link serving chain 1. Sepolia's resolver points at the same Gateway, which by design does not serve it.

Checks

  • Every REQ/SP/ASM/TEST-ENS id is defined once, and every reference resolves.
  • pnpm -C site install --frozen-lockfile, build and test pass. The chapter publishes under /specs/ens-integration/.

🤖 Generated with Claude Code

https://claude.ai/code/session_01Ar21wPcHzNprswTzLJd3MA

Move design/ens-integration.md to docs/pages, where the Starlight site
publishes it at /docs/ens-integration/. The heading becomes the page's
title frontmatter; the text is unchanged.

Assisted-by: Claude Opus 5.5
Signed-off-by: SupremaLex <georglutsenko@gmail.com>
@cloudflare-workers-and-pages

cloudflare-workers-and-pages Bot commented Oct 2, 2026 •

Copy link
Copy Markdown

🚀 Deploying Preview to Cloudflare 🚀

Preview URL: https://docs-ens-integration.previews.lib.id, https://docs-ens-integration-libid.grounded-systems.workers.dev (commit 4d77835)

This URL reflects your latest Preview deployment

Preview Deployments by commit

Status Deployment URL Commit Updated (UTC) See this deployment's details
  • Build: Success ✅
  • Deployment: Success ✅

View logs ↗
https://9c77bb3f.previews.lib.id, https://9c77bb3f-libid.grounded-systems.workers.dev 4d77835 2026-10-05T16:43:08.058Z Visit the dashboard ↗
  • Build: Success ✅
  • Deployment: Success ✅

View logs ↗
https://a23eba91.previews.lib.id, https://a23eba91-libid.grounded-systems.workers.dev 91215f6 2026-10-05T15:16:46.660Z Visit the dashboard ↗
  • Build: Success ✅
  • Deployment: Success ✅

View logs ↗
https://1505ca1a.previews.lib.id, https://1505ca1a-libid.grounded-systems.workers.dev 3ae0186 2026-10-05T14:32:53.066Z Visit the dashboard ↗
  • Build: Success ✅
  • Deployment: Success ✅

View logs ↗
https://53721015.previews.lib.id, https://53721015-libid.grounded-systems.workers.dev 77f9be3 2026-10-05T10:31:00.712Z Visit the dashboard ↗
  • Build: Success ✅
  • Deployment: Success ✅

View logs ↗
https://b6bacc7d.previews.lib.id, https://b6bacc7d-libid.grounded-systems.workers.dev 1add2c3 2026-10-05T10:03:06.578Z Visit the dashboard ↗
  • Build: Failed ❌

View logs ↗
5ec4c6c 2026-10-02T15:10:46.948Z View logs ↗
  • Build: Failed ❌

View logs ↗
a239dba 2026-10-02T13:15:07.998Z View logs ↗

@Wondertan Wondertan left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we move this doc, I think we need to update the shape of the doc and clean it up a little bit, currently it is indeed a design doc.

Comment thread docs/pages/ens-integration.md Outdated
description: How libID handles resolve as ENS names in wallets.
---

**Status: design proposal.** Nothing here is built. It is not a protocol spec in

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is it still proposal tho? I thought it was implemented.

@SupremaLex
SupremaLex marked this pull request as draft October 2, 2026 13:25
Rewrite the ENS integration design as a normative spec chapter, with
assumptions, security properties, requirements and conformance vectors,
and link it from the specification index. Where the design and the
deployed resolver and gateway disagree, the spec follows the code: an
EVM chain the gateway does not index gets an unsigned 503 rather than a
signed null, the resolver also announces ERC-165, and the platform id
is the registry's for the platform key.

Assisted-by: Claude Opus 5.5
Signed-off-by: SupremaLex <georglutsenko@gmail.com>
@SupremaLex SupremaLex changed the title docs: publish the ENS integration design on the docs site docs(specs): specify the ENS integration Oct 2, 2026
Keep main's browser-ceremony chapters and the ENS chapter side by side
in the specification index and its ownership table.

Assisted-by: Claude Opus 5.5
Signed-off-by: SupremaLex <georglutsenko@gmail.com>
Drop REQ-ENS-KEY-02. The digest covers no chain ID, so an answer
replays across resolvers at one address that trust the same signer;
Security Considerations states when that replay is wrong.

Assisted-by: Claude Opus 5.5
Signed-off-by: SupremaLex <georglutsenko@gmail.com>
The digest binds an answer to its resolver's address, not its chain, so
one Signer may serve several chains while their resolvers' addresses
differ (REQ-ENS-KEY-02); SP-ENS-01 says so. Removing a Signer takes
effect at once on each chain, since the callback checks it when it
runs.

Assisted-by: Claude Opus 5.5
Signed-off-by: SupremaLex <georglutsenko@gmail.com>
Coin type 60 matches the chain whose ENS registry holds the Parent Name,
which the Gateway is configured with, not always chain 1. A coin type at
or above 2^64 names no EVM chain and gets a Signed Null.

Assisted-by: Claude Opus 5.5
Signed-off-by: SupremaLex <georglutsenko@gmail.com>
The Gateway answers under a configured domain: handles.link in
production, a name under it such as testnet.handles.link for a test
deployment. The grammar, the right-to-left parse and the foreign-name
400 refer to the Parent Name rather than the literal handles.link, and
TEST-ENS-06 covers a subname Parent Name.

Assisted-by: Claude Opus 5.5
Signed-off-by: SupremaLex <georglutsenko@gmail.com>
The Gateway checks an inverted handle against the rules built into it,
the same for every chain, so a binding admitted only under wider rules on
a chain gets a Signed Null; SP-ENS-03 now depends on the rules agreeing.
A Workspace label with '-' at its third and fourth characters, IDNA
domain labels among them, is refused, since ENSIP-15 refuses it. The
Security Considerations say plainly that the Gateway reads names outside
the transform's image, among them _at followed by gmail.com.

Assisted-by: Claude Opus 5.5
Signed-off-by: SupremaLex <georglutsenko@gmail.com>
The node/name comparison applies to addr calls only; any other record
gets the signed empty result once the name is wire-valid and under the
Parent Name. A label that is not UTF-8 is a wire error and gets HTTP 400.
REQ-ENS-GW-11 lists the steps in the order the Gateway takes them: the
Signed Nulls of REQ-ENS-GW-05 come before the staleness check and the
handle rules after it, and the consequence is stated. TEST-ENS-07 covers
the order and the 400s.

Assisted-by: Claude Opus 5.5
Signed-off-by: SupremaLex <georglutsenko@gmail.com>
REQ-ENS-RES-03 names the encoding OpenZeppelin ECDSA.recover accepts and
the other ways a malformed answer reverts; REQ-ENS-GW-08 requires the
Gateway to sign the digest unprefixed in that encoding. REQ-ENS-RES-05
requires every resolver URL to carry {sender} and {data}, since a URL
without {data} is fetched by POST and the Gateway serves GET only.

Assisted-by: Claude Opus 5.5
Signed-off-by: SupremaLex <georglutsenko@gmail.com>
The current deployment holds the Handle Resolver's owner, the deployer
and the Parent Name's owner as one key, so it does not meet
REQ-ENS-KEY-01; Security Considerations say so. Provenance records the
forward transform in @libid/ens (libID PR #109, unmerged) and what it
lacks, the unimplemented SHOULD of REQ-ENS-LABEL-05, where REQ-ENS-RES-05
is enforced, and the new REQ-ENS-GW-11.

Assisted-by: Claude Opus 5.5
Signed-off-by: SupremaLex <georglutsenko@gmail.com>
REQ-ENS-GW-06 applies before the handle rules and the holder, not before
every answer from the selected chain, matching REQ-ENS-GW-11. Reflows two
paragraphs.

Assisted-by: Claude Opus 5.5
Signed-off-by: SupremaLex <georglutsenko@gmail.com>
An uppercase label reaches REQ-ENS-GW-05 only for an addr call. Drops a
TEST-ENS-01 vector no normalized handle can produce: every platform's
rules keep a handle under 63 bytes.

Assisted-by: Claude Opus 5.5
Signed-off-by: SupremaLex <georglutsenko@gmail.com>
SupremaLex added a commit that referenced this pull request Oct 5, 2026
That revision has the Workspace refusal and the Parent Name parameter
the package implements.

Assisted-by: Claude Opus 5.5
Signed-off-by: SupremaLex <georglutsenko@gmail.com>
An X handle containing '-' has no name, since the '_' to '-' substitution
reverses only while no handle holds '-'; a GitHub handle containing '_' or
'--' at its third and fourth characters has no name. Both match @libid/ens.
A Chain Label is at most 63 bytes and has no '--' at its third and fourth
characters; Provenance records that the indexer's ChainName::parse does
not check either.

Assisted-by: Claude Opus 5.5
Signed-off-by: SupremaLex <georglutsenko@gmail.com>
REQ-ENS-NAME-05 keeps production Chain Labels off the first label of a
deployment under handles.link, such as testnet. REQ-ENS-GW-12 requires the
ENS Chain to be indexed for coin type 60 to answer, and REQ-ENS-GW-13
requires Gateways in one URL list to map Chain Labels alike, since an
unmapped label gets a Signed Null. ASM-ENS-01 no longer claims a client
never receives another chain's address; Security Considerations describe
MetaMask's fallback to addr(bytes32) and how a Chain Label defeats it.

Assisted-by: Claude Opus 5.5
Signed-off-by: SupremaLex <georglutsenko@gmail.com>
…t rules

TEST-ENS-08 to -12 cover the interface set, the OffchainLookup shape and
NoUrls, two-step non-renounceable ownership, the URL placeholders, and
{data} parsing. TEST-ENS-13 is a deployment check for REQ-ENS-KEY-02 and
the Chain Label, ENS Chain and shared-label rules. The ERC-7996 rationale
of REQ-ENS-RES-01 rests on the deployed Gateway refusing a mismatched
{sender}, which REQ-ENS-GW-08 permits. Step 3 of REQ-ENS-GW-11 includes an
addr call whose arguments do not decode. §4 points at §11.

Assisted-by: Claude Opus 5.5
Signed-off-by: SupremaLex <georglutsenko@gmail.com>
REQ-ENS-KEY-01 requires the owner key to be held cold, so the online KMS
deployer key that owns the current deployment visibly fails it. Its
necessity no longer says a URL buys nothing: a URL holder can serve a
signed answer until it expires and end lookups, which Security
Considerations now describe. Provenance records that nothing enforces
REQ-ENS-KEY-02 and that @libid/ens carries the refusals and a parent
option. libid.md names the Parent Name as a deployment parameter and lists
the ENS principals and trust roots.

Assisted-by: Claude Opus 5.5
Signed-off-by: SupremaLex <georglutsenko@gmail.com>
SP-ENS-03 also depends on REQ-ENS-GW-13. The KEY-01 consideration
describes what the deploy workflow does per environment, and the
REQ-ENS-RES-05 Provenance row names the workflow's placeholder check
beside the script's.

Assisted-by: Claude Opus 5.5
Signed-off-by: SupremaLex <georglutsenko@gmail.com>
SupremaLex added a commit that referenced this pull request Oct 5, 2026
Assisted-by: Claude Opus 5.5
Signed-off-by: SupremaLex <georglutsenko@gmail.com>
@SupremaLex
SupremaLex marked this pull request as ready for review October 6, 2026 08:16

This branch has not been deployed

No deployments
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