Lortnoc Tahc 03 · Identity
ENS v2 · Permissioned Resolver

A name you own, with permissions you control.

Every record separately permissioned. Enforced on-chain, revoked in one transaction, without asking us for anything.

Why we built on it

The endgame is Lortnoc DM — our own protocol, where accounts aren’t ours to revoke. Selling those accounts is the business model.

That only works if two things hold. A handle has to be genuinely the buyer’s, surviving us if we disappear or are ordered to close it. And the infrastructure helping run it has to hold the least power we can give it — in a form the user can check and withdraw themselves, because a row in our database is only ever a claim about our future behaviour.

ENS v2 gives both. A sub-name they hold, resolving through a resolver they own, where our gateway is granted write access to exactly one text record and reverted on every other — revocable by them, in a single transaction, without asking us for anything.

How it works here

  1. Own resolver per account. Claiming a handle deploys a VerifiableFactory proxy of PermissionedResolverImpl — their contract, not a row in a shared one.
  2. Records carry the routing. pubkey, sui, walrus, inbox, discoverable, knock. Each one separately permissioned.
  3. Delegate exactly one record. authorizeTextRoles(name, "eth.lortnoc.inbox", gateway, true). Our gateway rotates the inbox pointer and is reverted on everything else.
  4. Revoke without us. Same call, grant=false. One transaction, the user’s signature.
  5. Prove it’s genuine. verifyContract(proxy) returns the implementation — checkable without trusting our backend.
  6. Unlinkable issuance. The paid claim burns a single-use zk nullifier on 0G, then a relayer issues the name on Sepolia — so the wallet that paid never signs for the handle. Verifiable: the address holding our founder handle has never sent a transaction. The registrar’s on-chain gate is currently open, so the nullifier is enforced by the relayer rather than the contract.
How a handle resolves — every hop is a real contract
ENS v2 rootRootRegistry → the ETHRegistry, on Sepolia
lortnoctahcour name, with our registry slotted underneath
LortnocRegistryissues handles on our rule, not on “this wallet paid”
your resolvera VerifiableFactory proxy only you administer

Every handle gets its own resolver contract, not a row in a shared one. verifyContract(proxy) returns the canonical implementation, so a stranger can confirm yours is genuine without trusting us.

What lives on your resolver, and who may write it
pubkeyhow people encrypt to you
you write · gateway reverted
suiwhere your conversations live
you write · gateway reverted
knockthe question strangers must answer
you write · gateway reverted
inboxrelay pointer — the one record we ask for
you write · gateway may write
authorizeTextRoles(name, "eth.lortnoc.inbox", gateway, true) One call grants write access to exactly one text key. The role is resourced by keccak256(node, part), so it cannot spill onto any other record — the gateway’s attempt to write pubkey reverts on-chain, not in our code.
gateway → inbox: permitted, revocable
gateway → pubkey, sui, knock: reverts

Same call with grant=false takes it back. One transaction, your signature, no request to us.

Why this needs v2

v2 did not just add features to v1. It made the registry pluggable, and the whole identity layer hangs off that one change.

IRegistry with a different ownership model

Slotting our own registry under lortnoctahc.eth and having it issue names on a rule that is not “this wallet paid” is what lets a handle be unlinkable to its payment. In v1 the thought is not expressible: you would be bolting policy onto a system whose ownership model already disagreed with you.

Per-record roles, resourced by keccak256(node, part)

This is what makes least-privilege real rather than aspirational. The gateway holds write access to exactly one text key and is reverted on every other. Not “shouldn’t” — reverts, on-chain, every time, whatever our backend intends.

verifyContract and TokenRegenerated

Two primitives that exist because someone thought past the happy path. verifyContract lets a counterparty confirm a resolver came from the canonical factory without trusting us at all. And bumping the token version on a role change, so revocation invalidates stale approvals, answers what happens after a revoke rather than during one.

A sharp edge worth knowing

grantRoles reverts on the resolver; the authorize*Roles wrappers are the way in. It is the first thing anyone reaching for EAC will try, and the failure is silent enough to cost an afternoon.

Discoverability is a dial, not a switch

Findability should not be one bit. Five rungs, held in a text record the user owns and writes:

GhostNot findable. Only someone handed the handle directly can reach them.
UnlistedResolvable if known. Not searchable, not reverse-linkable.
KnownFindable only by someone who already holds an identifier for them.
SearchableAppears in people-search, opt-in.
PublicFully linkable, deliberately.

What is built, and what is not. The record is live: a user sets their rung and it resolves like any other record. What does not exist yet is the CCIP-Read resolver that would enforce it — running real code on each lookup and answering differently per caller, so a profile resolves for a mutual and not for a stranger. Today the ladder is declared, not enforced.

We are specific about that because the enforcement is the interesting half. ENS roles govern writes; read-gating is a separate mechanism at the resolver, and only v2’s pluggable resolution makes it expressible at all. Claiming the dial works today would be claiming the part we have not written.

Specifics

Handle<name>.lortnoctahc.eth
RegistryLortnocRegistry, implements IRegistry, under lortnoctahc.eth
ResolverPer-account VerifiableFactory proxy of PermissionedResolverImpl
PermissionsEnhanced Access Control — per-record roles
DelegationauthorizeTextRoles(name, key, account, grant)
NetworkSepolia, deployment pinned to 2026-06-29

PS: There is a business model behind this.

An account is bought once, not funded by reading what you send. The unit economics are public.

See the numbers