Skip to content

feat(sdk): DotNS registry reads + writes in identity - #293

Merged
Imod7 merged 27 commits into
mainfrom
tg-dotns-registry-impl
Aug 20, 2026
Merged

feat(sdk): DotNS registry reads + writes in identity#293
Imod7 merged 27 commits into
mainfrom
tg-dotns-registry-impl

Conversation

@TarikGul

@TarikGul TarikGul commented Aug 11, 2026

Copy link
Copy Markdown
Member

Closes #301
Part of #303
Part of #286

Description

Implements the DotNS registry surface in @parity/product-sdk/identity, replacing the exported-but-throwing resolveDotNs / reverseDotNs / isDotNsAvailable stubs. Everything returns Result<T, DotNsError>; contract addresses default to the deployed set and are all overridable.

Reads. resolveDotNs hashes under the deployment's TLD, reads registry.owner and registry.resolver, then resolver.addressOf only when the pointer is the forward resolver. Three outcomes: ok(null) unregistered, ok({ name, owner }) registered with no forward address record, ok({ name, owner, address }) resolves (H160, not SS58). isDotNsAvailable asks registrarController.available(label) plus PopRules.classifyName, so a governance-reserved label is not reported as free. reverseDotNs calls reverseResolver.nameOf.

Writes return prepared calls the caller submits with their own signer. setDotNsRecord gives a BatchableCall[]: setResolver first when the pointer needs moving, then setAddress. prepareDotNsRegistration gives the commit call, secret, timing window, and a prepareRegisterCall() thunk for after minCommitmentAge (register consumes the commitment, so it cannot be built up front). Priced as max(priceWithoutCheck(label, owner).price, transferFloor(label, payer, owner)), matching what register charges.

The TLD is per network, and read from the chain

The part worth reviewing closely. DotNS fixes its TLD when DotnsProtocolRegistry.initialize runs, with no setter: .paseo on Paseo Asset Hub Next V2, .dot on Previewnet, operator-chosen elsewhere. An earlier revision of this branch hardcoded .dot, so on the SDK's own default chain every name read as unregistered with no error anywhere, because the wrong root yields a node the chain has never written to.

The SDK now reads protocolRegistry.tld() once per runtime and derives the node itself, so one read answers the question and tldNode() is only a cross-check. A deployment older than dotns b4096968 has no getter; there the TLD was a compile-time .dot, so an absent getter falls back to .dot with a warning. Any other failed read is an error, never a guess.

Contract addresses are the opposite: CREATE3-deterministic and identical on every network, verified on both. Hence PASEO_ASSETHUB_DOTNS becomes DOTNS_ADDRESSES, since the old name implied a per-network address table that does not exist.

Behaviour notes for callers

  • A foreign suffix is refused with reason "TldMismatch", not hashed under ours. alice.dot and alice.paseo are separate registrations that may have different owners, and the identity layer cannot link a name across deployments in either direction, so translating silently could return a stranger's address. The label-to-alias binding is chain-local, and from individuality v0.12.0 the personhood context carries the network suffix, so the alias is per-network too.
  • A bare multi-label name is no longer suffixed. bob.alice used to become bob.alice.dot; it is now refused, since telling it apart from alice.dot would need a hardcoded list of every network's TLD. A bare single label still works: alice gives alice.paseo.
  • Lite-person names must be passed flattened. The contract strips the dots before hashing, so alice.42 is stored as alice42. Resolve alice42.paseo.
  • namehash(name, tld) requires the root, as do the three name helpers. A default correct on one deployment is the defect this branch fixes.
  • New failure mode: isDotNsAvailable and prepareDotNsRegistration were never affected by the rooting bug, but now depend on the TLD read for validation, so a protocol-registry read failure fails a call that previously succeeded.
  • Breaking for anyone who imported the old stubs, which took no options and threw. Pre-1.0, so minor. New exports: DotNsTld, dotNsTld, DOT_TLD, stripSuffix, isConsistentDotNsTld, and the "TldMismatch" / "InvalidTld" reasons.

Verified against live chains

Unit tests could not have caught any of the three defects fixed here, so both deployments were exercised directly:

Next V2, .paseo Previewnet, .dot, no getter
resolveDotNs("dim2<own>") { name, owner: 0x4eD4A9b9... } { name, owner: 0x4eD4A9b9... }
resolveDotNs("dim2") bare same record same record
resolveDotNs("dim2<foreign>") err TldMismatch err TldMismatch
resolveDotNs("nosuchname9x") ok(null) ok(null)

The refusals point in opposite directions on the two chains, which is what distinguishes a per-network fix from relocated hardcoding.

142 unit tests, up from 83, each change also checked by reintroducing the defect and confirming the suite goes red (17 such checks, all caught). That mattered: the original bug survived three review passes because dotns-namehash.test.ts validated namehash against a reference implementation that reimplemented the same .dot rooting, so the tests could not have failed. The deterministic live values are pinned in tests (the .paseo tldNode, the dim2.paseo node, the content and PoP resolver addresses); owners are not, being mutable state.

Not covered: no write was submitted on chain; no name with a forward address record was found, so ok({ name, owner, address }) is unit-test-only; reverseDotNs and lite-person names were not exercised live. There is no automated live test, so nothing here detects rot.

Linked issues

Closes #301
Part of #303
Part of #286
  • Closes #301, "isDotNsAvailable() reports every name as available". Fully resolved. Its ask was "until real resolution lands, make it throw or return a typed error", and this lands the real reads instead, and availability now asks registrarController.available(label) plus PopRules.classifyName rather than inferring from a zero resolver. That also covers the aside in dotNS registry surface: the default Asset Hub contract addresses have no code on chain #303, which flagged the same resolver-zero inference.
  • Part of #303, not Closes. The issue is "the default Asset Hub contract addresses have no code on chain". The titled defect is gone: the defaults are now the CREATE3 set dotNS registry surface: the default Asset Hub contract addresses have no code on chain #303 itself names (registry 0xf34054fd…, registrar 0x4f06E818…), verified live on Next V2 and Previewnet. But neither of its two asks is implemented: no gateway walk at runtime, and no startup verification against DotnsProtocolRegistry that fails loudly on a mismatch. This PR does read one value from that contract at runtime (the TLD), which is the same direction, so it narrows dotNS registry surface: the default Asset Hub contract addresses have no code on chain #303 without answering it. Leaving it open is the tracking.
  • Part of #286, the personhood and individuality tracking issue. This PR is the dotNS implementation behind two of its sub-issues, so the tracker can follow it from here.

Not linked, having checked: #302 is a People-chain Resources.Consumers read, a different surface in the same file and untouched here; #287, #289, #291 are personhood helpers, ring VRF keys and game helpers.

Worth noting that #303 independently corroborates the central finding of this PR before it was made: it records owner(namehash("dim2.paseo")) as owned on Next V2 and owner(namehash("dim2.dot")) as owned on Previewnet, which is the per-network TLD in one line, measured by someone else on different scripts.

@github-actions

github-actions Bot commented Aug 11, 2026

Copy link
Copy Markdown

📦 Bundle size impact

Comparing 2026-08-20T10:28:58.399Z2026-08-20T10:28:12.176Z

Package Entry Bundled before Bundled after Δ Ship gzip Δ Shake ratio
🟢 @parity/product-sdk . 6.42 MB 6.42 MB +6 B (+0.0%) +1 B 0% (was 0%)
🟢 @parity/product-sdk ./core 6.42 MB 6.42 MB +6 B (+0.0%) 0 B 0% (was 0%)
🟠 @parity/product-sdk ./identity 57.0 KB 111.6 KB +54.6 KB (+95.9%) +4.1 KB 1% (was 61%)
🟠 @parity/product-sdk ./individuality 3.7 KB 53.9 KB +50.2 KB (+1363.1%) 0 B
🟢 @parity/product-sdk ./react 6.43 MB 6.43 MB +6 B (+0.0%) 0 B 0% (was 0%)

Thresholds — 🟡 ≥10% or ≥5.0 KB · 🟠 ≥20% or ≥15.0 KB (bundled). Percentage only applies once the baseline is ≥ 10 KB. Informational — this check never blocks merge.

@valentinfernandez1
valentinfernandez1 self-requested a review August 19, 2026 15:46

@valentinfernandez1 valentinfernandez1 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just some small nits but over all LGTM

Comment thread product-sdk/packages/sdk/src/identity/dotns-registry.ts Outdated
Comment thread product-sdk/packages/sdk/src/identity/dotns-registry.ts
@Imod7
Imod7 merged commit 2dc9c18 into main Aug 20, 2026
12 of 13 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

isDotNsAvailable() reports every name as available

3 participants