# Guide: ENS Names & Integration

ChainRender integrates deeply with ENS — for naming apps, resolving them, and rendering ENS identity. This guide
covers all three, and the important design choice behind how it uses ENS.

## The design choice: the registrar is truth, ENS is a projection

ChainRender does **not** put your app's trust in ENS's ownership/governance model. Instead, apps are named via
subnames under `chainrender.eth`, managed by an **ownerless on-chain registrar** (`SubnameStakeRegistrar`). An
ENSIP-10 **wildcard resolver** then *reflects* that registrar into ENS, so `*.chainrender.eth` resolves normally
in any ENS-aware tool — but the source of truth is the on-chain registrar, not an ENS name someone could transfer
or a registry someone controls.

> **Why:** using a top-level ENS name directly would inherit ENS's own trust and governance surface. By making the
> registrar authoritative and ENS a read-only projection, ChainRender keeps naming ownerless and verifiable while
> still being fully ENS-compatible.

## 1. Naming your app (register a subname)

Register `myapp.chainrender.eth` by staking (refundable) in the registrar:

```
SubnameStakeRegistrar.register("myapp", appComponentHash)   // + a refundable stake
```

The registration is recorded on-chain at once, and the stake is a spam cost, not a fee; it's refundable.

> **Current status:** `ChainRenderResolver` (the ENSIP-10 wildcard resolver) is deployed on every chain, but
> `chainrender.eth` is **not yet pointed at it** in ENS, so `myapp.chainrender.eth` does not resolve through ENS yet.
> Resolve by label from the registrar (or the version registry, §3) until that wiring is done.

## 2. Resolving an app by name

Once `chainrender.eth` points at the wildcard resolver, any ENS-aware client will resolve `myapp.chainrender.eth` to
your app's component hash (the resolver answers `addr` with the contributor and `text("chainrender.component")` with
the hash). It reads the registrar; it does **not** yet follow versions (§3). You render that hash the usual way.

## 3. Versioned names (safe updates through the name)

If you use the versioned registry, `resolveCurrent(labelHash)` returns your app's **current version**, with
append-only history and a timelock on updates. (Following the current version *through the ENS name* needs a wildcard
resolver that reads `resolveCurrent()`; the deployed one does not yet.) Updating is `queueVersion(...)` — a public, delayed, observable
event, never a silent swap. See **[Concepts → Versioning](../concepts/versioning.md)**.

## 4. Rendering ENS identity in your UI

Separately from naming *apps*, ChainRender can render *users'* ENS identity as live on-chain UI via the
**EnsProfile resolver** — name, avatar, records, reverse-resolution (with forward-verification). Bind a data slot:

```ts
// EnsProfileResolver kinds: enstext · ensaddr · enscoin · ensowner · ensverify · agentverify — see the Resolvers reference
compose.slot("<kind>", { resolver: "0x<ens-profile-resolver>", arg: "<abi-encoded args for that kind>" }) // slot(bind, { resolver, arg });
```

This reads ENS on-chain at render time; it's Grade A (an on-chain read) and fails closed if the name doesn't
resolve. The resolver refuses a reverse name whose forward record points elsewhere — no spoofed identities.

## 5. ENS from a rich-media sketch (`window.CR_CHAIN`)

The EnsProfile resolver above is the **declarative** path (a data slot, resolved on-chain, Grade A). A **rich-media**
p5/three sketch can also resolve ENS **imperatively** through the injected `window.CR_CHAIN` bridge — useful for
turning raw hex addresses into readable names inside a live visualization:

```js
CR_CHAIN.ensName(addr)      // reverse-resolve an address -> "vitalik.eth" (or null)
CR_CHAIN.ensAddr(name)      // forward-resolve a name -> address (or null)
CR_CHAIN.ensText(name, key) // read a text record: avatar, url, com.twitter, …
```

Each is a direct on-chain read against the ENS registry and resolver (the namehash is computed client-side with a
vetted keccak), fails closed to `null`, and should be **cached per address** — never re-resolve the same address, and
never call it every frame. When `ensName` returns `null` (common on testnets, where few addresses have a reverse
record), fall back to a shortened hex address.

```js
var ensCache = {};
function nameFor(addr) {
  var k = addr.toLowerCase();
  if (ensCache[k] !== undefined) return ensCache[k] || shorten(addr);
  ensCache[k] = "pending";
  CR_CHAIN.ensName(addr).then(function (n) { ensCache[k] = n || null; });
  return shorten(addr); // show hex until the name resolves
}
```

> This is a **client-side enhancement** (Grade ⚙) over the on-chain floor — the same trust level as any `CR_CHAIN`
> read. For a *verifiable, forward-checked* identity rendered as part of the app itself, use the EnsProfile resolver
> in section 4. See **[Rich Media → Reading live on-chain data](../concepts/rich-media-p5-three.md)**.

## 6. Multichain extras: app manifest (`ensApp`) + chain-aware name (`ensNameChain`)

Two additive ENS reads go beyond records and reverse-resolution, via the **`EnsMultichainResolver`** (ownerless,
immutable, view-only, fails closed to `"-"`; the ENS registry is supplied at construction, never hardcoded):

| kind | args | renders |
|---|---|---|
| `ensApp` | `abi.encode(node)` | the `chainrender.app` text record a name points its app to |
| `ensNameChain` | `abi.encode(who, coinType)` | the **ENSIP-19** primary name for an address *on a given chain*, forward-verified |

**`ensApp`** reads a conventional `chainrender.app` text key off a name — ENS as ChainRender's own naming layer, so a
name can point at the app it represents (dogfood: `chainrender.eth` names its own apps). Grade A, an on-chain text read.

**`ensNameChain`** is the ENSIP-19 **multichain** verified reverse: the primary name for an address *per chain*, not
just mainnet. The reverse namespace is per-`coinType` (an EVM chain's coinType is `0x80000000 | chainId`; mainnet is
the special `60`), and the resolver **requires the forward round-trip** — `addr(namehash(name), coinType)` must equal
the address — so an unverified reverse record can never be shown. Grade A, pure on-chain reads.

```ts
// bind the chain-aware primary name for `who` on Sepolia (coinType 0x80aa36a7 = 0x80000000 | 11155111)
compose.slot("ensNameChain", { resolver: "0x<ens-multichain-resolver>", arg: encode(["address","uint256"], [who, 0x80aa36a7]) });
```

Both render a live value wherever the records exist on the chain's registry, and fail closed to `"-"` otherwise. The
Explorer's **ENS extras** card demonstrates them over an immutable demo ENS source (records anchored at seed); re-point
the resolver at the real `chainrender.eth` registry with no code change to read the live name.

## Summary

| Use | Mechanism | Trust property |
|---|---|---|
| Name your app | `SubnameStakeRegistrar` + ENSIP-10 wildcard | Ownerless; registrar is truth, ENS is a projection |
| Safe updates via the name | `SubnameVersionRegistry` | Append-only + timelock; no silent swap |
| Render a user's ENS identity | `EnsProfile` resolver | On-chain read, Grade A, forward-verified |
| App a name points to | `EnsMultichainResolver` · `ensApp` | On-chain `chainrender.app` text read, Grade A |
| Chain-aware primary name | `EnsMultichainResolver` · `ensNameChain` | ENSIP-19 per-coinType reverse, forward-verified, Grade A |

## Related
- **[Contracts → Registries](../contracts/registries.md)** · **[Concepts → Versioning](../concepts/versioning.md)**
- **[Reference → Resolver Catalog](../reference/resolvers.md)** (EnsProfile · EnsMultichain)
