@parity/product-sdk 0.21.0 → 0.23.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (44) hide show
  1. package/dist/address/index.d.ts +1 -0
  2. package/dist/chunk-BRZNHTLQ.js +89 -0
  3. package/dist/chunk-BRZNHTLQ.js.map +1 -0
  4. package/dist/{chunk-6BI66XUJ.js → chunk-DHRCWMY5.js} +9 -10
  5. package/dist/chunk-DHRCWMY5.js.map +1 -0
  6. package/dist/core/index.d.ts +2 -2
  7. package/dist/core/index.js +2 -2
  8. package/dist/dotns-bswWAmR2.d.ts +136 -0
  9. package/dist/identity/index.d.ts +495 -49
  10. package/dist/identity/index.js +796 -46
  11. package/dist/identity/index.js.map +1 -1
  12. package/dist/index.d.ts +3 -3
  13. package/dist/index.js +2 -2
  14. package/dist/individuality/index.d.ts +1 -0
  15. package/dist/individuality/index.js +3 -0
  16. package/dist/individuality/index.js.map +1 -0
  17. package/dist/react/index.d.ts +2 -2
  18. package/dist/react/index.js +2 -2
  19. package/dist/testing/index.d.ts +2 -2
  20. package/dist/{types-CztPAgZT.d.ts → types-B5Zx4RNq.d.ts} +1 -1
  21. package/package.json +17 -12
  22. package/src/core/createApp.ts +10 -8
  23. package/src/identity/dotns-abis.test.ts +43 -0
  24. package/src/identity/dotns-abis.ts +309 -0
  25. package/src/identity/dotns-addresses.test.ts +536 -0
  26. package/src/identity/dotns-addresses.ts +320 -0
  27. package/src/identity/dotns-errors.ts +36 -0
  28. package/src/identity/dotns-namehash.test.ts +155 -0
  29. package/src/identity/dotns-namehash.ts +149 -0
  30. package/src/identity/dotns-owner.test.ts +92 -0
  31. package/src/identity/dotns-registry.test.ts +1309 -0
  32. package/src/identity/dotns-registry.ts +868 -0
  33. package/src/identity/dotns.test.ts +128 -0
  34. package/src/identity/dotns.ts +91 -78
  35. package/src/identity/index.test.ts +43 -0
  36. package/src/identity/index.ts +42 -16
  37. package/src/identity/types.ts +29 -38
  38. package/src/individuality/contract.test.ts +326 -0
  39. package/src/individuality/index.ts +8 -0
  40. package/dist/chunk-6BI66XUJ.js.map +0 -1
  41. package/dist/chunk-BIKT6X54.js +0 -70
  42. package/dist/chunk-BIKT6X54.js.map +0 -1
  43. package/dist/dotns-hLSvmo6u.d.ts +0 -178
  44. package/src/identity/product-account.ts +0 -164
@@ -0,0 +1,128 @@
1
+ // Copyright 2026 Parity Technologies (UK) Ltd.
2
+ // SPDX-License-Identifier: Apache-2.0
3
+ import { describe, expect, test } from "vitest";
4
+ import { stripSuffix } from "./dotns-namehash.js";
5
+ import { isResolvableDotNsName, isValidDotNsName, normalizeDotNsName } from "./dotns.js";
6
+
7
+ // The two deployments these helpers actually have to serve. Every case below
8
+ // runs against `.paseo` as well as `.dot`, because a helper that only behaves
9
+ // on a four-character suffix is the defect being fixed.
10
+ const DOT = ".dot";
11
+ const PASEO = ".paseo";
12
+
13
+ describe("stripSuffix", () => {
14
+ test("removes the suffix by its own length", () => {
15
+ expect(stripSuffix("alice.paseo", PASEO)).toBe("alice");
16
+ expect(stripSuffix("alice.dot", DOT)).toBe("alice");
17
+ });
18
+
19
+ test("a six-character suffix does not lose two characters to a hardcoded 4", () => {
20
+ // `slice(0, -4)` returns "alice.pa" here, which then hashes and queries
21
+ // as the subname `pa` under `alice`.
22
+ expect(stripSuffix("alice.paseo", PASEO)).not.toBe("alice.pa");
23
+ });
24
+
25
+ test("leaves a name that does not carry the suffix untouched", () => {
26
+ expect(stripSuffix("alice", PASEO)).toBe("alice");
27
+ expect(stripSuffix("alice.dot", PASEO)).toBe("alice.dot");
28
+ });
29
+
30
+ test("keeps subname structure", () => {
31
+ expect(stripSuffix("bob.alice.paseo", PASEO)).toBe("bob.alice");
32
+ });
33
+
34
+ test("a bare suffix strips to the empty label", () => {
35
+ expect(stripSuffix(".paseo", PASEO)).toBe("");
36
+ });
37
+ });
38
+
39
+ describe("normalizeDotNsName", () => {
40
+ test("appends the deployment's suffix to a bare label", () => {
41
+ expect(normalizeDotNsName("alice", PASEO)).toBe("alice.paseo");
42
+ expect(normalizeDotNsName("alice", DOT)).toBe("alice.dot");
43
+ });
44
+
45
+ test("is idempotent for a name that already carries the suffix", () => {
46
+ expect(normalizeDotNsName("alice.paseo", PASEO)).toBe("alice.paseo");
47
+ });
48
+
49
+ test("leaves a foreign suffix alone instead of burying it", () => {
50
+ // The rule this pins: appending only when there is no dot at all means
51
+ // `alice.dot` survives to be refused by validation. The `endsWith`
52
+ // rule would produce `alice.dot.paseo`, which is a well-formed subname
53
+ // and would resolve silently to a node nobody owns.
54
+ expect(normalizeDotNsName("alice.dot", PASEO)).toBe("alice.dot");
55
+ expect(normalizeDotNsName("alice.dot", PASEO)).not.toBe("alice.dot.paseo");
56
+ });
57
+
58
+ test("leaves a bare multi-label name alone", () => {
59
+ // Recorded behaviour change: this used to become `bob.alice.dot` and
60
+ // resolve. It is now left as-is and refused by validation, because
61
+ // telling `bob.alice` from `alice.dot` needs a list of known TLDs.
62
+ expect(normalizeDotNsName("bob.alice", PASEO)).toBe("bob.alice");
63
+ });
64
+
65
+ test("lowercases, trims, and drops a single trailing root dot", () => {
66
+ // Matches `normalize_host` in truapi-server, so a name arriving from a
67
+ // URL keys the same way here as it does in the host.
68
+ expect(normalizeDotNsName(" Alice.PASEO. ", PASEO)).toBe("alice.paseo");
69
+ expect(normalizeDotNsName("ALICE", PASEO)).toBe("alice.paseo");
70
+ });
71
+
72
+ test("drops only one trailing dot, so a doubled dot stays visible", () => {
73
+ // `alice.paseo..` is malformed and must reach validation as such
74
+ // rather than being quietly repaired into a valid name.
75
+ expect(normalizeDotNsName("alice.paseo..", PASEO)).toBe("alice.paseo.");
76
+ });
77
+ });
78
+
79
+ describe("isValidDotNsName", () => {
80
+ test("accepts one label under the deployment's suffix", () => {
81
+ expect(isValidDotNsName("alice.paseo", PASEO)).toBe(true);
82
+ expect(isValidDotNsName("alice.dot", DOT)).toBe(true);
83
+ });
84
+
85
+ test("refuses another deployment's suffix", () => {
86
+ expect(isValidDotNsName("alice.dot", PASEO)).toBe(false);
87
+ expect(isValidDotNsName("alice.paseo", DOT)).toBe(false);
88
+ });
89
+
90
+ test("refuses a subname, which the registrar cannot mint", () => {
91
+ expect(isValidDotNsName("bob.alice.paseo", PASEO)).toBe(false);
92
+ });
93
+
94
+ test("applies the label rule to the label, not to the suffix's length", () => {
95
+ // With a hardcoded `slice(0, -4)` the label here would be `dim2.pa`,
96
+ // which fails the label regex and would reject a registrable name.
97
+ expect(isValidDotNsName("dim2.paseo", PASEO)).toBe(true);
98
+ });
99
+
100
+ test("keeps the on-chain label rules", () => {
101
+ expect(isValidDotNsName("ab.paseo", PASEO)).toBe(false); // under 3 chars
102
+ expect(isValidDotNsName("-alice.paseo", PASEO)).toBe(false); // edge hyphen
103
+ expect(isValidDotNsName("al ice.paseo", PASEO)).toBe(false); // space
104
+ expect(isValidDotNsName(`${"a".repeat(64)}.paseo`, PASEO)).toBe(false); // over 63
105
+ });
106
+ });
107
+
108
+ describe("isResolvableDotNsName", () => {
109
+ test("accepts a subname, which the registry supports even though the registrar does not", () => {
110
+ expect(isResolvableDotNsName("bob.alice.paseo", PASEO)).toBe(true);
111
+ expect(isResolvableDotNsName("alice.paseo", PASEO)).toBe(true);
112
+ });
113
+
114
+ test("refuses another deployment's suffix", () => {
115
+ expect(isResolvableDotNsName("bob.alice.dot", PASEO)).toBe(false);
116
+ });
117
+
118
+ test("extracts the labels by suffix length, not by a constant 4", () => {
119
+ // `slice(0, -4)` would split `dim2.pa` into ["dim2", "pa"] and reject
120
+ // it on the 3-character minimum.
121
+ expect(isResolvableDotNsName("dim2.paseo", PASEO)).toBe(true);
122
+ });
123
+
124
+ test("refuses an empty label anywhere in the chain", () => {
125
+ expect(isResolvableDotNsName("bob..alice.paseo", PASEO)).toBe(false);
126
+ expect(isResolvableDotNsName(".paseo", PASEO)).toBe(false);
127
+ });
128
+ });
@@ -3,12 +3,16 @@
3
3
  /**
4
4
  * DotNS (Polkadot Name Service) utilities
5
5
  *
6
- * Provides name resolution for .dot domains
6
+ * Name validation and normalization. Every helper here takes the deployment's
7
+ * TLD suffix rather than assuming `.dot`: the TLD is fixed per network when the
8
+ * contracts initialise, so the same string is a valid name on one deployment
9
+ * and meaningless on another. `resolveTld` in `./dotns-registry.js` is what
10
+ * asks the chain which suffix is in play.
7
11
  */
8
12
 
9
13
  import { accountIdBytes } from "@parity/product-sdk-address";
10
14
  import { bytesToHex, hexToBytes } from "@parity/product-sdk-crypto";
11
- import { createLogger } from "@parity/product-sdk-logger";
15
+ import { stripSuffix } from "./dotns-namehash.js";
12
16
  import type {
13
17
  ChainDefinition,
14
18
  PalletsTypedef,
@@ -18,9 +22,6 @@ import type {
18
22
  StorageDescriptor,
19
23
  TxDescriptor,
20
24
  } from "polkadot-api";
21
- import type { DotNsRecord } from "./types.js";
22
-
23
- const log = createLogger("identity");
24
25
 
25
26
  type AnyDescriptorEntry<T> = Record<string, Record<string, T>>;
26
27
 
@@ -71,100 +72,103 @@ export type PeopleUsernameQueryApi = {
71
72
  };
72
73
 
73
74
  /**
74
- * Check if a string is a valid DotNS name
75
+ * Whether `name` is a single registrable label under `suffix`.
76
+ *
77
+ * `suffix` is the deployment's own TLD, including its leading dot, as
78
+ * `resolveTld` reports it — `".dot"` on Paseo Asset Hub Previewnet, `".paseo"`
79
+ * on Next V2. It is required rather than defaulted, because a name is only
80
+ * valid *relative to a deployment*: `alice.dot` is registrable on one network
81
+ * and meaningless on the other, and a default would silently pick one.
75
82
  *
76
- * @param name - Name to validate
77
- * @returns True if valid DotNS name
83
+ * @param name - Name to validate, already normalized by {@link normalizeDotNsName}
84
+ * @param suffix - The deployment's TLD suffix, e.g. `".paseo"`
78
85
  */
79
- export function isValidDotNsName(name: string): boolean {
80
- // Basic validation: alphanumeric, hyphens, ends with .dot
81
- if (!name.endsWith(".dot")) return false;
82
- const label = name.slice(0, -4);
83
- if (label.length < 3 || label.length > 63) return false;
84
- return /^[a-z0-9]([a-z0-9-]*[a-z0-9])?$/.test(label);
86
+ export function isValidDotNsName(name: string, suffix: string): boolean {
87
+ if (!name.endsWith(suffix)) return false;
88
+ return isValidLabel(stripSuffix(name, suffix));
85
89
  }
86
90
 
87
91
  /**
88
- * Normalize a DotNS name (lowercase, trim whitespace)
92
+ * One canonical DNS label, matching the on-chain rule.
89
93
  *
90
- * @param name - Name to normalize
91
- * @returns Normalized name
94
+ * `StringUtils.isSingleLabel` allows lowercase ASCII, digits and non-edge
95
+ * hyphens up to 63 characters, and the registrar additionally requires 3.
92
96
  */
93
- export function normalizeDotNsName(name: string): string {
94
- let normalized = name.toLowerCase().trim();
95
- if (!normalized.endsWith(".dot")) {
96
- normalized += ".dot";
97
- }
98
- return normalized;
97
+ function isValidLabel(label: string): boolean {
98
+ if (label.length < 3 || label.length > 63) return false;
99
+ return /^[a-z0-9]([a-z0-9-]*[a-z0-9])?$/.test(label);
99
100
  }
100
101
 
101
102
  /**
102
- * Resolve a DotNS name to an address.
103
+ * Whether a name can be resolved: one or more valid labels under `suffix`.
103
104
  *
104
- * @deprecated Not implemented — throws at runtime. Use
105
- * `wallet.signMessageWithDotNsIdentity({ peopleChain, username })` (which
106
- * internally calls {@link resolvePeopleUsernameOwner}) for the supported
107
- * People-chain username flow.
105
+ * Broader than {@link isValidDotNsName} on purpose. The registrar only mints
106
+ * single labels, so registration keeps the stricter rule, but the registry
107
+ * supports subnodes and `namehash` hashes them, so `bob.alice.paseo` is
108
+ * resolvable even though it is not registrable.
108
109
  *
109
- * @param name - DotNS name (e.g., "alice.dot")
110
- * @returns Resolved record or null if not found
110
+ * @param name - Name to check, already normalized by {@link normalizeDotNsName}
111
+ * @param suffix - The deployment's TLD suffix, e.g. `".paseo"`
111
112
  */
112
- export async function resolveDotNs(name: string): Promise<DotNsRecord | null> {
113
- const normalized = normalizeDotNsName(name);
114
-
115
- if (!isValidDotNsName(normalized)) {
116
- log.warn("Invalid DotNS name", { name });
117
- return null;
118
- }
119
-
120
- log.debug("Resolving DotNS name", { name: normalized });
121
-
122
- // TODO: Implement via PAPI query to DotNS pallet
123
- throw new Error(
124
- "resolveDotNs() is not yet implemented. " +
125
- "This is a skeleton for the Product SDK structure.",
126
- );
113
+ export function isResolvableDotNsName(name: string, suffix: string): boolean {
114
+ if (!name.endsWith(suffix)) return false;
115
+ const labels = stripSuffix(name, suffix).split(".");
116
+ return labels.length > 0 && labels.every(isValidLabel);
127
117
  }
128
118
 
129
119
  /**
130
- * Reverse resolve an address to a DotNS name.
120
+ * Normalize a DotNS name for the deployment identified by `suffix`.
131
121
  *
132
- * @deprecated Not implemented — throws at runtime. Reverse lookup will land
133
- * alongside future identity work; for now resolve forward via
134
- * `wallet.signMessageWithDotNsIdentity`.
122
+ * Case-folds, applies NFC, trims surrounding whitespace, and drops a single
123
+ * trailing root dot, so `Alice.PASEO.` keys the same as `alice.paseo`. This
124
+ * mirrors `normalize_host` in truapi-server, which is what turns a URL into a
125
+ * dotNS identifier — a name arriving from navigation has to key identically
126
+ * here or the two layers disagree about the same input.
135
127
  *
136
- * @param address - SS58 address
137
- * @returns Primary name or null if none set
138
- */
139
- export async function reverseDotNs(address: string): Promise<string | null> {
140
- log.debug("Reverse resolving address", { address });
141
-
142
- // TODO: Implement via PAPI query to DotNS pallet
143
- throw new Error(
144
- "reverseDotNs() is not yet implemented. " +
145
- "This is a skeleton for the Product SDK structure.",
146
- );
147
- }
148
-
149
- /**
150
- * Check if a DotNS name is available for registration.
128
+ * The NFC step is defensive only: {@link isValidLabel} and the on-chain
129
+ * `StringUtils.isSingleLabel` both allow lowercase ASCII alone, so no name that
130
+ * survives validation can differ between its composed and decomposed spellings.
131
+ * It costs nothing and it keeps this function honest if the label rule ever
132
+ * widens.
151
133
  *
152
- * @deprecated Not implemented — depends on {@link resolveDotNs} which throws.
134
+ * **The suffix is appended only when `name` contains no dot at all.** A bare
135
+ * label is the friendly path and gets the deployment's suffix; anything already
136
+ * carrying a dot is left exactly as written, so a name from another deployment
137
+ * survives to be refused by validation rather than being buried under our own
138
+ * suffix. Appending on `!endsWith(suffix)` instead would turn `alice.dot` into
139
+ * `alice.dot.paseo`, which is a well-formed subname and would resolve silently
140
+ * to a node nobody owns.
153
141
  *
154
- * @param name - Name to check
155
- * @returns True if available
142
+ * The cost of that rule: a bare multi-label name such as `bob.alice` is no
143
+ * longer completed to `bob.alice.paseo`. Distinguishing it from `alice.dot`
144
+ * would require a hardcoded list of every network's TLD, and there are already
145
+ * more TLDs deployed than any such list contains.
146
+ *
147
+ * @param name - Name to normalize
148
+ * @param suffix - The deployment's TLD suffix, e.g. `".paseo"`
156
149
  */
157
- export async function isDotNsAvailable(name: string): Promise<boolean> {
158
- const record = await resolveDotNs(name).catch(() => null);
159
- return record === null;
150
+ export function normalizeDotNsName(name: string, suffix: string): string {
151
+ const folded = name.trim().normalize("NFC").toLowerCase();
152
+ const normalized = folded.endsWith(".") ? folded.slice(0, -1) : folded;
153
+ return normalized.includes(".") ? normalized : normalized + suffix;
160
154
  }
161
155
 
156
+ // `resolveDotNs` / `reverseDotNs` / `isDotNsAvailable` now live in
157
+ // `./dotns-registry.ts` (real `Result`-returning registry calls), replacing the
158
+ // throwing skeletons that used to sit here. See that module + the design doc.
159
+
162
160
  /**
163
- * Resolve a People / People Lite username to its owning `AccountId32`.
161
+ * Resolve a People / People Lite username to its owning account.
164
162
  *
165
163
  * Queries `Resources.UsernameOwnerOf` on the caller-supplied typed-api fragment.
166
- * The returned value is the raw 32-byte account id as a `0x`-prefixed hex
167
- * string, or `null` when no owner is registered for that username.
164
+ * The returned value is the SS58 address the storage yields, or `null` when no
165
+ * owner is registered for that username.
166
+ *
167
+ * Returns SS58 rather than hex because that is both the form the storage yields
168
+ * and the form `Resources.Consumers` is keyed by, so reading an account's
169
+ * usernames from this result needs no conversion. Callers that want the raw
170
+ * 32-byte key use `accountIdBytes` from `@parity/product-sdk-address`, and
171
+ * {@link accountIdToHex} for the hex form.
168
172
  *
169
173
  * The `username` is UTF-8 encoded as-is — no normalization is applied. Pass
170
174
  * the exact byte string the chain stores (typically with the `.dot` suffix).
@@ -176,13 +180,11 @@ export async function isDotNsAvailable(name: string): Promise<boolean> {
176
180
  export async function resolvePeopleUsernameOwner(
177
181
  username: string,
178
182
  peopleApi: PeopleUsernameQueryApi,
179
- ): Promise<`0x${string}` | null> {
183
+ ): Promise<SS58String | null> {
180
184
  const owner = await peopleApi.query.Resources.UsernameOwnerOf.getValue(
181
185
  new TextEncoder().encode(username),
182
186
  );
183
- if (!owner) return null;
184
-
185
- return accountIdBytesToHex(accountIdBytes(owner));
187
+ return owner ?? null;
186
188
  }
187
189
 
188
190
  function assertHex(value: string): `0x${string}` {
@@ -200,9 +202,20 @@ export function accountIdHexToBytes(accountId: `0x${string}`): Uint8Array {
200
202
  return bytes;
201
203
  }
202
204
 
203
- function accountIdBytesToHex(bytes: Uint8Array): `0x${string}` {
205
+ /** Throws on any input that is not exactly 32 bytes, rather than padding it. */
206
+ export function accountIdBytesToHex(bytes: Uint8Array): `0x${string}` {
204
207
  if (bytes.length !== 32) {
205
208
  throw new Error(`Expected 32-byte AccountId, got ${bytes.length} bytes`);
206
209
  }
207
210
  return `0x${bytesToHex(bytes)}`;
208
211
  }
212
+
213
+ /**
214
+ * The inverse of {@link accountIdHexToBytes}.
215
+ *
216
+ * No in-repo caller: this is the migration path for consumers, after
217
+ * `resolvePeopleUsernameOwner` changed from hex to SS58. Not dead code.
218
+ */
219
+ export function accountIdToHex(address: string): `0x${string}` {
220
+ return accountIdBytesToHex(accountIdBytes(address));
221
+ }
@@ -0,0 +1,43 @@
1
+ // Copyright 2026 Parity Technologies (UK) Ltd.
2
+ // SPDX-License-Identifier: Apache-2.0
3
+ /**
4
+ * Guards the identity export surface: what must be there, and what must stay gone.
5
+ */
6
+ import { describe, expect, it } from "vitest";
7
+ import * as identity from "./index.js";
8
+
9
+ // The check below is a runtime one, so it cannot see a removed type. If this
10
+ // type comes back, the suppression goes unused and typecheck fails.
11
+ // @ts-expect-error must stay removed
12
+ import type { ContextAliasInfo } from "./types.js";
13
+
14
+ describe("the identity export surface", () => {
15
+ // Both sets threw or misled on every call, so no working consumer could
16
+ // exist. Deleting turns a runtime problem into a compile error.
17
+ it("no longer exports the ring stubs or the context-alias helpers", () => {
18
+ for (const name of [
19
+ "deriveAnonymousAlias",
20
+ "createRingProof",
21
+ "verifyRingProof",
22
+ "deriveContextAlias",
23
+ "verifyContextAlias",
24
+ ]) {
25
+ expect(name in identity).toBe(false);
26
+ }
27
+ });
28
+
29
+ it("still exports the DotNS helpers", () => {
30
+ for (const name of [
31
+ "resolveDotNs",
32
+ "reverseDotNs",
33
+ "isDotNsAvailable",
34
+ "resolvePeopleUsernameOwner",
35
+ "isValidDotNsName",
36
+ "normalizeDotNsName",
37
+ "accountIdHexToBytes",
38
+ "accountIdToHex",
39
+ ]) {
40
+ expect(name in identity).toBe(true);
41
+ }
42
+ });
43
+ });
@@ -3,37 +3,63 @@
3
3
  /**
4
4
  * @parity/product-sdk/identity
5
5
  *
6
- * Identity utilities: DotNS name resolution, context-alias derivation,
7
- * and Ring VRF anonymous aliases.
6
+ * Identity utilities: DotNS name resolution and registry access.
7
+ *
8
+ * For Ring VRF aliases and proofs, use `SignerManager`'s
9
+ * `getProductAccountAlias` and `createRingVRFProof` from
10
+ * `@parity/product-sdk-signer`.
8
11
  */
9
12
 
10
- // DotNS utilities
13
+ // DotNS utilities (pure helpers + People-chain username path)
11
14
  export {
12
15
  isValidDotNsName,
16
+ isResolvableDotNsName,
13
17
  normalizeDotNsName,
14
- resolveDotNs,
15
- reverseDotNs,
16
- isDotNsAvailable,
17
18
  accountIdHexToBytes,
19
+ accountIdToHex,
18
20
  resolvePeopleUsernameOwner,
19
21
  } from "./dotns.js";
20
22
  export type { PeopleUsernameChain, PeopleUsernameQueryApi } from "./dotns.js";
21
23
 
22
- // Context alias utilities
24
+ // DotNS registry reads + writes (Revive contract)
25
+ export {
26
+ resolveDotNs,
27
+ reverseDotNs,
28
+ isDotNsAvailable,
29
+ setDotNsRecord,
30
+ prepareDotNsRegistration,
31
+ } from "./dotns-registry.js";
32
+ export type {
33
+ DotNsClientOptions,
34
+ RegisterDotNsArgs,
35
+ SetRecordArgs,
36
+ DotNsRegistration,
37
+ } from "./dotns-registry.js";
38
+ export { DotNsError } from "./dotns-errors.js";
39
+ export type { DotNsErrorReason } from "./dotns-errors.js";
40
+ export {
41
+ namehash,
42
+ dotNsTld,
43
+ isConsistentDotNsTld,
44
+ stripSuffix,
45
+ DOT_NODE,
46
+ DOT_TLD,
47
+ } from "./dotns-namehash.js";
48
+ export type { DotNsTld } from "./dotns-namehash.js";
49
+ export { POP_STATUS, DOTNS_ADDRESSES } from "./dotns-abis.js";
50
+
51
+ // Where those addresses come from: the pinned table, or the gateway walk.
23
52
  export {
24
- deriveContextAlias,
25
- verifyContextAlias,
26
- deriveAnonymousAlias,
27
- createRingProof,
28
- verifyRingProof,
29
- } from "./product-account.js";
53
+ DOTNS_REGISTRY_KEYS,
54
+ discoverDotNsAddresses,
55
+ resolveDotNsAddresses,
56
+ verifyDotNsAddresses,
57
+ } from "./dotns-addresses.js";
58
+ export type { DotNsAddresses, DotNsGatewayQueryApi } from "./dotns-addresses.js";
30
59
 
31
60
  // Types
32
61
  export type {
33
62
  DotNsRecord,
34
- ContextAliasInfo,
35
- AnonymousAliasInfo,
36
- RingLocation,
37
63
  VerificationResult,
38
64
  OnChainIdentity,
39
65
  } from "./types.js";
@@ -2,52 +2,43 @@
2
2
  // SPDX-License-Identifier: Apache-2.0
3
3
  /**
4
4
  * Identity module types
5
- *
6
- * Types for DotNS name resolution and context-alias derivation
7
5
  */
8
6
 
9
7
  /** DotNS name resolution result */
10
8
  export interface DotNsRecord {
11
- /** Resolved SS58 address */
12
- address: string;
13
- /** Name that was resolved */
9
+ /**
10
+ * H160 the name resolves to, `0x` and 20 bytes. Not SS58: DotNS is a set of
11
+ * Revive contracts and both address fields come back as EVM addresses.
12
+ * Convert with `h160ToSs58` from `@parity/product-sdk-address` if a
13
+ * Substrate-shaped address is needed.
14
+ *
15
+ * Absent when the name is registered but has no forward record yet, the
16
+ * state of every name just after registration. An unregistered name is
17
+ * `null` from `resolveDotNs`, not a record.
18
+ */
19
+ address?: `0x${string}`;
20
+ /**
21
+ * Name that was resolved, normalized: lowercased, and carrying the
22
+ * deployment's own TLD suffix — `.paseo` on Paseo Asset Hub Next V2, `.dot`
23
+ * on Previewnet. A bare label passed in comes back suffixed.
24
+ *
25
+ * Note for a **lite-person** registrant: the registry stores their label
26
+ * flattened, so `alice.42` is registered as `alice42` and this field reads
27
+ * `alice42.paseo`. Pass the flattened spelling when resolving; the dotted
28
+ * one derives a different node and finds nothing.
29
+ */
14
30
  name: string;
15
- /** Owner address */
16
- owner: string;
17
- /** Expiration timestamp (if applicable) */
31
+ /** H160 of the node's owner. Not SS58, same as {@link DotNsRecord.address}. */
32
+ owner: `0x${string}`;
33
+ /**
34
+ * Expiration timestamp, if the deployment has one.
35
+ *
36
+ * Always absent today: the Paseo Asset Hub registrar exposes no expiry
37
+ * getter, so nothing populates this.
38
+ */
18
39
  expiresAt?: number;
19
40
  }
20
41
 
21
- /** Context alias info: a deterministic, context-bound alias derived from a parent account */
22
- export interface ContextAliasInfo {
23
- /** Alias SS58 address */
24
- address: string;
25
- /** H160 EVM address */
26
- h160Address: `0x${string}`;
27
- /** Parent account address */
28
- parentAddress: string;
29
- /** Context string used for derivation */
30
- context: string;
31
- }
32
-
33
- /** Ring VRF alias info */
34
- export interface AnonymousAliasInfo {
35
- /** Anonymous alias identifier */
36
- alias: string;
37
- /** Ring location for proof generation */
38
- ringLocation: RingLocation;
39
- /** Context used for alias derivation */
40
- context: string;
41
- }
42
-
43
- /** Ring location for VRF proofs */
44
- export interface RingLocation {
45
- /** Ring index */
46
- ringIndex: number;
47
- /** Member index within ring */
48
- memberIndex: number;
49
- }
50
-
51
42
  /** Identity verification result */
52
43
  export interface VerificationResult {
53
44
  /** Whether identity is verified */