ERCs

ERC-181 — Reverse ENS resolution

eips.ethereum.org/EIPS/eip-181

ERC-137 maps name → address. ERC-181 maps address → name. Resolved via the addr.reverse subdomain: <address-without-0x>.addr.reverse resolves to the canonical name for an address.

import { eip155_1 } from "@ethernauta/chain/eip155-1";
import { AddressSchema } from "@ethernauta/core";
import { get_ens_name } from "@ethernauta/ens";
import { create_reader, encode_chain_id, http } from "@ethernauta/transport";
import { parse } from "valibot";

const CHAIN_ID = encode_chain_id({ namespace: "eip155", reference: eip155_1.chainId });
const reader = create_reader([
  { chainId: CHAIN_ID, transports: [http("https://ethereum-rpc.publicnode.com")] },
]);
const address = parse(AddressSchema, "0xd8dA6BF26964aF9D7eED9e03E53415D37aA96045");

const name = await get_ens_name({ address })(reader({ chain_id: CHAIN_ID }));
// → "vitalik.eth" or null

Surface

The lower-level method bindings live under @ethernauta/erc/181. Most dapps use get_ens_name from @ethernauta/ens instead, which composes both the reverse record lookup and the forward verification step.

MethodShapePurpose
name({ node })Callable<string>Read the name text record at a reverse node.
set_name({ name })Signable<Hash32>Owner sets their primary name.

Forward verification

A reverse record alone is claim-only — an attacker could set bob.eth as their reverse name without owning it. The canonical resolution flow does the round trip:

  1. Reverse: addressclaimed_name.
  2. Forward: claimed_nameforward_address.
  3. Valid iff forward_address === address.

get_ens_name performs both steps. If the verification fails it returns null.

See also