Skip to content

Name resolution: support name services that expose the ENS resolver profile without a registry (e.g. .gwei / GNS) #5600

Description

@petfold

Summary

resolver-options already lets an operator route a TLD to a contract and an RPC endpoint ([tld:][contract-addr@]url), but the ENS client assumes the contract is an ENS registry and calls owner/resolver on it before reading contenthash. Name services that skip the registry and expose the ENS resolver profile directly on the name contract cannot be resolved, although they store Swarm contenthash records in the standard encoding.

Concrete case: the Gwei Name Service (.gwei, https://gwei.domains, contracts https://github.com/lucadonnoh/gwei-names). Its NameNFT at 0x9D51D507BC7264d4fE8Ad1cf7Fe191933A0a81d6 (Ethereum mainnet) implements

function contenthash(bytes32 node) public view returns (bytes memory)
function addr(bytes32 node) public view returns (address)
function addr(bytes32 node, uint256 coinType) public view returns (bytes memory)
function text(bytes32 node, string calldata key) public view returns (string memory)
function supportsInterface(bytes4) // 0x3b3b57de, 0xf1cb7e06, 0x59d1d43c, 0xbc1c58d1

with EIP-137 namehash nodes (token id = uint256(namehash)), but has no owner(bytes32) / resolver(bytes32) registry functions. Freedom Browser resolves .gwei natively and <name>.gwei.domains serves Swarm content, so .gwei sites on Swarm exist today; Bee (and therefore Swarm Desktop) cannot open them.

Where it fails

pkg/resolver/client/ens/ens.go:

  • wrapDial calls registry.Owner("") on the configured address to check that "the ENS registry client is deployed" — fails for a resolver-only contract.
  • wrapResolve calls registry.Owner(name), then registry.Resolver(name), then Contenthash(); the first two have no counterpart on GNS. (Its contractAddr parameter is currently unused, _ common.Address.)

Proposal

Treat the configured contract as a resolver when it is not a registry, either by auto-detection or by an explicit marker:

  1. In wrapDial, if registry.Owner("") fails, probe supportsInterface(0xbc1c58d1) (contenthash profile, EIP-165) on the same address; if true, remember the address as a direct resolver.
  2. In wrapResolve, for a direct resolver: r, err := goens.NewResolverAt(ethCl, name, contractAddr) then r.Contenthash() and goens.ContenthashToString as today. Skip the owner check (an unregistered name yields an empty contenthash → ErrNotFound).

Alternatively an explicit syntax, e.g. gwei:resolver=0x9D51…81d6@https://rpc, if auto-detection is undesirable. go-ens already has everything needed (NewResolverAt, Contenthash), so the change is confined to ens.go plus a unit test with a mocked resolver-only contract.

Expected result

resolver-options:
  - "gwei:0x9D51D507BC7264d4fE8Ad1cf7Fe191933A0a81d6@https://<mainnet rpc>"

GET /bzz/swarmtyp.gwei/ serves the Swarm feed manifest the name points at (today b656fac57eb02756af40279cf70275969c9f9219818af7cceee34101f169a100; the name is live for testing, contenthash set with the Swarm codec). The same mechanism would cover other registry-less services that adopt the resolver profile.

Context

swarmtyp (https://github.com/petfold/swarmtyp), a collaborative Typst editor served from Swarm, uses swarmtyp.gwei as its address; users on Freedom or a web gateway can open it by name, users on Swarm Desktop / Bee have to use the raw reference. Notes in docs/decisions.md D-25 of that repo.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions