Repository navigation
feat(identity): one-call registry reads, a viem-free handle export, and the ENS Parent Name - #86
Open
SupremaLex wants to merge 11 commits into
Open
SupremaLex wants to merge 11 commits into
SupremaLex wants to merge 11 commits into
Conversation
Add five views to IdentityRegistry and IIdentityRegistry:
- handleBindingOf(platformId, handle) -> (holder, observedAt): resolveHandle's
reading (normalized on chain, refused text answers (0, 0), unwired platform
reverts UnknownPlatform) plus the binding's observedAt. A retired handle
answers a zero holder beside its watermark, as handleBinding does.
- idBindingOf(platformId, id) -> (holder, observedAt): resolveId plus
observedAt.
- handleOfId(platformId, id) -> (handle, current): the handle the identity
proved most recently and identitiesOf's handleCurrent for it; ("", false)
for an id never proved.
- idOfHandle(platformId, handle) -> id: the id of the identity the handle
belongs to now; empty when nobody holds it (never proved, or retired by a
rename) and for refused text.
- normalizeHandle(platformId, handle) -> normalized: joins the rules views
(rulesOf, handleHashOf, handleNodeOf): needs a configured platform only and
reverts UnusableHandle for refused text, as handleHashOf does.
resolveId and resolveHandle now read through idBindingOf and handleBindingOf,
handleHashOf hashes normalizeHandle's answer, and identitiesOf and handleOfId
share one helper for the latest handle and its current flag. No storage
change; the layout snapshot still matches.
The Rust sol! bindings and the TS resolve helpers (idBindingOf,
handleBindingOf, handleOfId, idOfHandle, normalizeHandle) expose the same
reads. SettableRegistry, the escrow tests' registry mock, implements the
widened interface.
Assisted-by: Claude Opus 5.5
Signed-off-by: SupremaLex <georglutsenko@gmail.com>
`@libid/contracts/identity` re-exports the resolvers and node hashing, which
import viem when the module loads, so a consumer that only normalizes a
handle had to install viem. The new `./handle` export carries handle.ts and
handleVectors.ts alone: normalize, rulesFor, Rules, RULES_*, HandleError,
the PLATFORM_*_KEY constants and the generated vector table. `./identity`
keeps exporting all of it.
Checked from the packed tarball installed alone in an empty directory:
`import('@libid/contracts/handle')` loads and normalizes, while
`@libid/contracts/identity` fails with ERR_MODULE_NOT_FOUND for viem.
Assisted-by: Claude Opus 5.5
Signed-off-by: SupremaLex <georglutsenko@gmail.com>
ENS_PARENT_NAME is `handles.link`, the name scripts/setup-ens-resolver.sh and the deploy workflow set HandleResolver on in production. The testnet deployment uses `testnet.handles.link` on Sepolia (deploy.yml). Exported from `@libid/contracts/identity` and the root; the Rust crate keeps no ENS constants, so it has no counterpart there. Assisted-by: Claude Opus 5.5 Signed-off-by: SupremaLex <georglutsenko@gmail.com>
libID PR #93 moves design/ens-integration.md to specs/ens-integration.md; the NatSpec now cites the spec and REQ-ENS-KEY-01. The existing rule against sharing a signing key between deployments that could land on one address agrees with REQ-ENS-KEY-02 and is unchanged. Assisted-by: Claude Opus 5.5 Signed-off-by: SupremaLex <georglutsenko@gmail.com>
- IIdentityRegistry describes itself as the registry's reads, for contracts and clients alike, rather than only what other contracts ask. - Its NatSpec for handleOfId and idOfHandle, and the Rust sol! docs, state that both revert UnknownPlatform for an unwired platform. - SettableRegistry's stubs for the five reads revert "not modelled" instead of answering made-up values a later escrow test could come to rely on. - resolveHandleAndId reads its handle node through _usableHandleNode, the gate the other handle reads share. - handleOfId documents that `current` reads the nodes and stays true after the rules narrow while resolveHandle, handleBindingOf and idOfHandle answer nobody; idOfHandle and handleOfId note how they differ from the raw handleNodeById/idNodeByHandle pointers an indexer may mirror under similar names. The names stay: idOfHandle is documented as live, and handleOfId returns the pointer's handle with `current` beside it. - Tests: handleBindingOf keeps platforms apart for `alice`, valid on X and GitHub; idOfHandle answers empty after the rules narrow, with resolveHandle and handleBindingOf, while handleOfId stays current. Assisted-by: Claude Opus 5.5 Signed-off-by: SupremaLex <georglutsenko@gmail.com>
- The resolvers' read helper takes its function name, arguments and result type from the generated identityRegistryAbi (viem's ContractFunctionName, ContractFunctionArgs and ContractFunctionReturnType), so a misspelled name or a result read in the wrong shape fails to compile. Every wrapper in resolve.ts uses it. - Tests for idBindingOf, handleBindingOf, handleOfId and idOfHandle run through a real viem PublicClient whose transport answers eth_call with results encoded by the ABI and decodes the calldata it receives, and they assert UnknownPlatform by name on a decoded revert. - The normalizeHandle wrapper is gone: it sent the handle to an RPC, and `normalize(handle, await rulesOf(reader, x))` gives the same answer locally. The README says so, and that rulesOf needs `/identity` (viem and an RPC). - HandleOfId.current and the README document that it reads the nodes and stays true after the rules narrow while handleBindingOf and idOfHandle answer null. Assisted-by: Claude Opus 5.5 Signed-off-by: SupremaLex <georglutsenko@gmail.com>
`@libid/contracts/handle` re-exports ENS_PARENT_NAME, which imports nothing. A test walks the subpath's relative imports from handle/index.ts and fails on any package specifier, viem included, and on any module joining the set it loads (handle/index, identity/ens, identity/handle, identity/handleVectors). Adding a viem import to identity/ens.ts makes it fail. Checked again from the packed tarball installed alone: the subpath loads and exports `handles.link`. Assisted-by: Claude Opus 5.5 Signed-off-by: SupremaLex <georglutsenko@gmail.com>
Cite libID's ENS integration spec by path, with no pull request number, and state what REQ-ENS-KEY-01 and REQ-ENS-KEY-02 require: the DNS registrar account, the Parent Name and resolver owner, and each Signer are distinct keys, and resolvers trusting one Signer sit at different addresses on whichever chains. The spec's note that the current deployment does not meet KEY-01 replaces the earlier wording about one identity. Assisted-by: Claude Opus 5.5 Signed-off-by: SupremaLex <georglutsenko@gmail.com>
The one-call read tests repeated the UnknownPlatform block for the four resolvers, the UnusableHandle encoding four times, and the X-without- underscores setup already used by the handleCurrent test. Each is one helper now. test_handleOfIdReadsTheNodesNotTheRules is dropped: test_idOfHandleFollowsTheRulesWhenTheyNarrow makes the same assertions after the same setup. Assisted-by: Claude Opus 5.5 Signed-off-by: SupremaLex <georglutsenko@gmail.com>
…ve.ts Five reads turned the zero address into null with the same ternary; they share `orNull`. The ABI return type `read` spelled twice is one alias. Assisted-by: Claude Opus 5.5 Signed-off-by: SupremaLex <georglutsenko@gmail.com>
The paragraph that described `normalize(handle, await rulesOf(...))` is a snippet with its import now, and the note on `current` under narrowed rules is one line; the full rule stays in `HandleOfId`'s doc comment. Assisted-by: Claude Opus 5.5 Signed-off-by: SupremaLex <georglutsenko@gmail.com>
SupremaLex
marked this pull request as ready for review
October 6, 2026 08:07
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Five read functions on
IdentityRegistry, a viem-free handle export in@libid/contracts, the ENS Parent Name as a constant, and a NatSpec pointer fix. This PR offers a menu: keep the reads that are worth keeping and drop the rest.The reads
All five are on
IdentityRegistryandIIdentityRegistry. Storage is unchanged; both storage-layout checks pass.handleBindingOf(platformId, handle)(holder, observedAt)resolveHandle's semantics. LibID (libID #71) needs this. Today it infers state from which registry call reverts.idBindingOf(platformId, id)(holder, observedAt)resolveIdplus the proof age.handleOfId(platformId, id)(handle, current)idOfHandle(platformId, handle)idnormalizeHandle(platformId, handle)normalized@libid/ens, the ENS gateway) can use the chain's rules instead of copies made at release time.Semantics:
UnknownPlatformon an unwired platform, asresolveHandleandresolveIddo.normalizeHandlefollowshandleHashOf: it answers for a platform with rules but no verifier, and revertsUnusableHandle(problem)on text the rules refuse.(0, 0)or"", not a revert.handleBindingOfgives(0, old observedAt), ashandleBindingdoes. That is the watermark a new proof has to beat.idOfHandlereturns""until another identity proves it, matchingresolveHandle's zero.resolveHandleandresolveIdnow go throughhandleBindingOfandidBindingOf.identitiesOfandhandleOfIdshare one_handleOf.handleHashOfhashesnormalizeHandle's result. No existing ABI changes.TS
@libid/contracts/handle:normalize,rulesFor, the rules, the handle vectors andENS_PARENT_NAME, with no viem at load time. A test walks the subpath's imports and fails on any import that isn't relative, viem included../identitystill needs viem. This lets@libid/ens(libID #109) drop its viem peer.ENS_PARENT_NAME = 'handles.link': also exported from./identityand the root. The doc comment says the testnet deployment usestestnet.handles.link.resolve.tswrapper now takes its function name, arguments and return type from the generatedidentityRegistryAbi. A misspelled name or a wrong tuple failstsc. The tests for the four new wrappers decode with the real ABI.normalizeHandlewrapper: it would send the handle text to the RPC. The README points tonormalize(handle, await rulesOf(...)), which runs locally. The contract view and its Rust binding stay.For review
IIdentityRegistry, which already carries reads (handleBinding,handleHashOf, …) and now describes itself as the registry's reads for contracts and clients alike. The escrow tests'SettableRegistrystubs revert ("not modelled"), so they can't give results the real registry never would.handleOfId.currentafter rules narrow. It staystruewhileresolveHandle,handleBindingOfandidOfHandleanswer zero for that handle. That matches the existingidentitiesOf.handleCurrent(pinned bytest_handleCurrentReadsTheNodesNotTheRules) and is documented in the NatSpec, the Rust docs and the TS type.idOfHandleis live: it answers only while the handle has a holder, unlike the rawidNodeByHandlepointer an indexer may mirror. The NatSpec says so.idPreimagesandhandlePreimagesexisted,handleOfIdandidOfHandlereturn empty for those bindings, the same gapidentitiesOfhas.resolveIdandresolveHandlecost about 110–150 gas more, because they run through the new reads, one code path kept on purpose.handleHashOfandhandleNodeOfcost 44–88 more, and the five new selectors add about 22 to dispatch.identitiesOfcosts about 74 more per item. Restoring main's exact loop body measured worse, so the cause looks like compiler output for the extra string-returning functions rather than this source. The committed verifier gas snapshots are unchanged.HandleResolverNatSpec. It cites libID's ENS integration spec (specs/ens-integration.md, REQ-ENS-KEY-01) without a PR number. It states the three-way key split, that the current deployment does not meet it yet, and that resolvers sharing a Signer must sit at different addresses (REQ-ENS-KEY-02).Checks
forge build, andforge test673/673, including 22 new tests: bound, unbound, refused and unwired cases, rename and takeover, two identities of one holder, platforms kept apart, rules that narrow, case and@variants, and agreement withidentitiesOf.forge fmt --check; both storage-layout scripts.regen-*.py --checkscripts; gas snapshots unchanged.cargo clippy -D warnings, andcargo test --allincluding the binding drift test and the anvil tests.cargo +nightly fmt --checkran on a local nightly, not CI's pin.🤖 Generated with Claude Code
https://claude.ai/code/session_01Ar21wPcHzNprswTzLJd3MA