@x1id/resolve 0.11.0 → 0.12.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.
- package/README.md +74 -5
- package/dist/adminConfig.d.ts +63 -0
- package/dist/adminConfig.js +113 -0
- package/dist/adminMarket.d.ts +67 -0
- package/dist/adminMarket.js +134 -0
- package/dist/attestation.d.ts +103 -1
- package/dist/attestation.js +124 -0
- package/dist/gateClient.d.ts +98 -0
- package/dist/gateClient.js +118 -0
- package/dist/index.d.ts +19 -0
- package/dist/index.js +137 -2
- package/dist/namespaceOverride.d.ts +123 -0
- package/dist/namespaceOverride.js +204 -0
- package/dist/register.d.ts +30 -0
- package/dist/register.js +37 -0
- package/dist/scoped.d.ts +84 -0
- package/dist/scoped.js +126 -0
- package/dist/types.d.ts +23 -4
- package/dist/types.js +2 -1
- package/dist/universal.d.ts +58 -0
- package/dist/universal.js +67 -0
- package/dist/universalDetect.d.ts +44 -0
- package/dist/universalDetect.js +105 -0
- package/dist/universalEns.d.ts +44 -0
- package/dist/universalEns.js +138 -0
- package/dist/universalNative.d.ts +13 -0
- package/dist/universalNative.js +43 -0
- package/dist/universalSns.d.ts +95 -0
- package/dist/universalSns.js +223 -0
- package/dist/universalTypes.d.ts +117 -0
- package/dist/universalTypes.js +24 -0
- package/dist/wasm.d.ts +17 -0
- package/dist/wasm.js +38 -0
- package/package.json +1 -1
- package/wasm/x1_resolve_wasm.wasm +0 -0
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Per-handle namespace overrides — `create_namespace_override` /
|
|
3
|
+
* `update_namespace_override` / `close_namespace_override` (#8138 family).
|
|
4
|
+
*
|
|
5
|
+
* A namespace override lets a handle's owner redirect `<handle>.<namespace>`
|
|
6
|
+
* (e.g. `jack.xnt`) to a DIFFERENT address than the handle's default, per
|
|
7
|
+
* namespace label. It is a record-edit-authority action (the handle owner, or a
|
|
8
|
+
* record delegate, signs — NOT an admin action), in the same family as the
|
|
9
|
+
* address `Record` writers: an optional `record_delegate` named slot plus the
|
|
10
|
+
* tokenized-handle holder-ATA proof in `remaining_accounts[0]`.
|
|
11
|
+
*
|
|
12
|
+
* NOTE: this capability is built but NOT yet wired into public resolution —
|
|
13
|
+
* `resolve()` does not read overrides yet (that is the cutover switch). These
|
|
14
|
+
* builders + the decoder are the on-chain-write + read-decode half, ready for
|
|
15
|
+
* when namespaced resolution goes live.
|
|
16
|
+
*
|
|
17
|
+
* Hand-rolled like the rest of the package — no Anchor client, no web3.js. PDAs
|
|
18
|
+
* are not derived here: derive `["handle", name]`, `["namespace", label]`,
|
|
19
|
+
* `["namespace_override", handlePubkey, label]`, `["delegate", handlePubkey]`
|
|
20
|
+
* with your runtime and pass them in, same convention as records.ts / subname.ts.
|
|
21
|
+
*/
|
|
22
|
+
import type { AddressLike, BuiltInstruction } from "./delegate.js";
|
|
23
|
+
import type { RpcFn } from "./accounts.js";
|
|
24
|
+
/** sha256("global:create_namespace_override")[..8]. */
|
|
25
|
+
export declare const CREATE_NAMESPACE_OVERRIDE_DISCRIMINATOR: Uint8Array;
|
|
26
|
+
/** sha256("global:update_namespace_override")[..8]. */
|
|
27
|
+
export declare const UPDATE_NAMESPACE_OVERRIDE_DISCRIMINATOR: Uint8Array;
|
|
28
|
+
/** sha256("global:close_namespace_override")[..8]. */
|
|
29
|
+
export declare const CLOSE_NAMESPACE_OVERRIDE_DISCRIMINATOR: Uint8Array;
|
|
30
|
+
/** The Anchor ACCOUNT discriminator for a `NamespaceOverride` — sha256("account:NamespaceOverride")[..8]. */
|
|
31
|
+
export declare const NAMESPACE_OVERRIDE_ACCOUNT_DISCRIMINATOR: Uint8Array;
|
|
32
|
+
/** The record-edit-authority tail every writer here shares: an optional named
|
|
33
|
+
* `record_delegate` slot (None = the program-id placeholder), then the
|
|
34
|
+
* tokenized-handle holder-ATA proof in remaining_accounts[0]. Own copy per
|
|
35
|
+
* module, matching recordWrite.ts's convention. */
|
|
36
|
+
interface AuthorityTail {
|
|
37
|
+
/** `["delegate", handle]` PDA — pass when a record delegate (not the owner) signs. */
|
|
38
|
+
readonly recordDelegate?: AddressLike;
|
|
39
|
+
/** The owner's pNFT token account — REQUIRED for a tokenized handle (proves
|
|
40
|
+
* the signer holds the capability NFT); omit for an untokenized handle. */
|
|
41
|
+
readonly holderTokenAccount?: AddressLike;
|
|
42
|
+
}
|
|
43
|
+
export interface CreateNamespaceOverrideParams extends AuthorityTail {
|
|
44
|
+
readonly programId: AddressLike;
|
|
45
|
+
/** Rent payer for the new override account; signs. */
|
|
46
|
+
readonly payer: AddressLike;
|
|
47
|
+
/** The handle owner (or delegate signer); signs. */
|
|
48
|
+
readonly owner: AddressLike;
|
|
49
|
+
/** `["handle", name]` PDA. */
|
|
50
|
+
readonly handle: AddressLike;
|
|
51
|
+
/** `["namespace", label]` PDA — must be Active for a create. */
|
|
52
|
+
readonly namespace: AddressLike;
|
|
53
|
+
/** `["namespace_override", handle, label]` PDA (init). */
|
|
54
|
+
readonly namespaceOverride: AddressLike;
|
|
55
|
+
/** The namespace label (e.g. "xnt"), an instruction ARG (== the seed). */
|
|
56
|
+
readonly namespaceLabel: string;
|
|
57
|
+
/** The address `<handle>.<label>` should resolve to. */
|
|
58
|
+
readonly value: AddressLike;
|
|
59
|
+
}
|
|
60
|
+
/** Build `create_namespace_override`. Args: namespace_label (String) + value (Pubkey). */
|
|
61
|
+
export declare function buildCreateNamespaceOverrideIx(p: CreateNamespaceOverrideParams): BuiltInstruction;
|
|
62
|
+
export interface UpdateNamespaceOverrideParams extends AuthorityTail {
|
|
63
|
+
readonly programId: AddressLike;
|
|
64
|
+
readonly owner: AddressLike;
|
|
65
|
+
readonly handle: AddressLike;
|
|
66
|
+
/** `["namespace_override", handle, label]` PDA (self-seeds from its stored label). */
|
|
67
|
+
readonly namespaceOverride: AddressLike;
|
|
68
|
+
/** The new target address. */
|
|
69
|
+
readonly value: AddressLike;
|
|
70
|
+
}
|
|
71
|
+
/** Build `update_namespace_override` — change the target address. Arg: value (Pubkey). */
|
|
72
|
+
export declare function buildUpdateNamespaceOverrideIx(p: UpdateNamespaceOverrideParams): BuiltInstruction;
|
|
73
|
+
export interface CloseNamespaceOverrideParams extends AuthorityTail {
|
|
74
|
+
readonly programId: AddressLike;
|
|
75
|
+
readonly owner: AddressLike;
|
|
76
|
+
readonly handle: AddressLike;
|
|
77
|
+
/** `["namespace_override", handle, label]` PDA (closed to recipient). */
|
|
78
|
+
readonly namespaceOverride: AddressLike;
|
|
79
|
+
/** Lamports recipient for the closed override's rent; need not sign. */
|
|
80
|
+
readonly recipient: AddressLike;
|
|
81
|
+
}
|
|
82
|
+
/** Build `close_namespace_override` — close the override, rent to recipient. No args. */
|
|
83
|
+
export declare function buildCloseNamespaceOverrideIx(p: CloseNamespaceOverrideParams): BuiltInstruction;
|
|
84
|
+
export interface NamespaceOverride {
|
|
85
|
+
/** The handle PDA this override belongs to. */
|
|
86
|
+
readonly handle: string;
|
|
87
|
+
/** The namespace label it applies to (e.g. "xnt"). */
|
|
88
|
+
readonly namespace: string;
|
|
89
|
+
/** The address `<handle>.<namespace>` resolves to instead of the default. */
|
|
90
|
+
readonly value: string;
|
|
91
|
+
/** Unix seconds last stamped. Trust ONLY while `updatedAt >= handle.registeredAt`
|
|
92
|
+
* (the universal epoch-staleness rule — a release+re-register reuses the PDA). */
|
|
93
|
+
readonly updatedAt: bigint;
|
|
94
|
+
readonly bump: number;
|
|
95
|
+
}
|
|
96
|
+
/** Decode a `NamespaceOverride` account. Layout: disc(8) | handle(32) |
|
|
97
|
+
* namespace(String: u32 len + bytes) | value(32) | updated_at(i64) | bump(1).
|
|
98
|
+
* Returns null if the data is too short / malformed. */
|
|
99
|
+
export declare function decodeNamespaceOverride(data: Uint8Array): NamespaceOverride | null;
|
|
100
|
+
/**
|
|
101
|
+
* Fetch + decode a handle's namespace override for one label, applying the
|
|
102
|
+
* universal epoch-staleness rule — a `NamespaceOverride` PDA is reused across a
|
|
103
|
+
* release + re-register of the same handle, so an override from a PREVIOUS owner
|
|
104
|
+
* (stamped before `handleRegisteredAt`) must NOT count. Returns the live
|
|
105
|
+
* override, or null when there is none / it is stale / the account is malformed.
|
|
106
|
+
*
|
|
107
|
+
* GATED read path: this is NOT called by `resolve()` — namespaced resolution does
|
|
108
|
+
* not honor overrides yet (that is the cutover switch). Derive `overrideAccount`
|
|
109
|
+
* with `WasmResolver.deriveNamespaceOverrideAccount(handle, label, programId)`.
|
|
110
|
+
*/
|
|
111
|
+
export declare function fetchNamespaceOverride(rpc: RpcFn, overrideAccount: string, handleRegisteredAt: bigint): Promise<NamespaceOverride | null>;
|
|
112
|
+
/**
|
|
113
|
+
* List all LIVE namespace overrides for one handle (a getProgramAccounts scan
|
|
114
|
+
* filtered by the account discriminator + the `handle` field at offset 8), with
|
|
115
|
+
* the epoch-staleness rule applied. Each entry includes its account address.
|
|
116
|
+
*
|
|
117
|
+
* GATED read path — not used by `resolve()` yet. Pass the handle's
|
|
118
|
+
* `registeredAt` so previous-owner overrides are dropped.
|
|
119
|
+
*/
|
|
120
|
+
export declare function fetchNamespaceOverridesForHandle(rpc: RpcFn, programId: string, handleAccount: string, handleRegisteredAt: bigint): Promise<Array<NamespaceOverride & {
|
|
121
|
+
account: string;
|
|
122
|
+
}>>;
|
|
123
|
+
export {};
|
|
@@ -0,0 +1,204 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Per-handle namespace overrides — `create_namespace_override` /
|
|
3
|
+
* `update_namespace_override` / `close_namespace_override` (#8138 family).
|
|
4
|
+
*
|
|
5
|
+
* A namespace override lets a handle's owner redirect `<handle>.<namespace>`
|
|
6
|
+
* (e.g. `jack.xnt`) to a DIFFERENT address than the handle's default, per
|
|
7
|
+
* namespace label. It is a record-edit-authority action (the handle owner, or a
|
|
8
|
+
* record delegate, signs — NOT an admin action), in the same family as the
|
|
9
|
+
* address `Record` writers: an optional `record_delegate` named slot plus the
|
|
10
|
+
* tokenized-handle holder-ATA proof in `remaining_accounts[0]`.
|
|
11
|
+
*
|
|
12
|
+
* NOTE: this capability is built but NOT yet wired into public resolution —
|
|
13
|
+
* `resolve()` does not read overrides yet (that is the cutover switch). These
|
|
14
|
+
* builders + the decoder are the on-chain-write + read-decode half, ready for
|
|
15
|
+
* when namespaced resolution goes live.
|
|
16
|
+
*
|
|
17
|
+
* Hand-rolled like the rest of the package — no Anchor client, no web3.js. PDAs
|
|
18
|
+
* are not derived here: derive `["handle", name]`, `["namespace", label]`,
|
|
19
|
+
* `["namespace_override", handlePubkey, label]`, `["delegate", handlePubkey]`
|
|
20
|
+
* with your runtime and pass them in, same convention as records.ts / subname.ts.
|
|
21
|
+
*/
|
|
22
|
+
import { encodeBase58, decodeBase58_32 } from "./base58.js";
|
|
23
|
+
import { recordDelegateNonePlaceholder, recordDelegateSomeSlot } from "./delegate.js";
|
|
24
|
+
const SYSTEM_PROGRAM = "11111111111111111111111111111111";
|
|
25
|
+
/** sha256("global:create_namespace_override")[..8]. */
|
|
26
|
+
export const CREATE_NAMESPACE_OVERRIDE_DISCRIMINATOR = Uint8Array.from([86, 74, 181, 245, 1, 190, 77, 128]);
|
|
27
|
+
/** sha256("global:update_namespace_override")[..8]. */
|
|
28
|
+
export const UPDATE_NAMESPACE_OVERRIDE_DISCRIMINATOR = Uint8Array.from([6, 194, 181, 7, 155, 17, 115, 224]);
|
|
29
|
+
/** sha256("global:close_namespace_override")[..8]. */
|
|
30
|
+
export const CLOSE_NAMESPACE_OVERRIDE_DISCRIMINATOR = Uint8Array.from([95, 135, 159, 93, 70, 49, 213, 188]);
|
|
31
|
+
/** The Anchor ACCOUNT discriminator for a `NamespaceOverride` — sha256("account:NamespaceOverride")[..8]. */
|
|
32
|
+
export const NAMESPACE_OVERRIDE_ACCOUNT_DISCRIMINATOR = Uint8Array.from([53, 237, 118, 139, 3, 149, 13, 148]);
|
|
33
|
+
function toBytes32(v, what) {
|
|
34
|
+
if (typeof v === "string") {
|
|
35
|
+
const b = decodeBase58_32(v);
|
|
36
|
+
if (!b)
|
|
37
|
+
throw new Error(`${what} is not a valid base58 address`);
|
|
38
|
+
return b;
|
|
39
|
+
}
|
|
40
|
+
if (v.length !== 32)
|
|
41
|
+
throw new Error(`${what} must be exactly 32 bytes`);
|
|
42
|
+
return v;
|
|
43
|
+
}
|
|
44
|
+
function toBase58(v, what) {
|
|
45
|
+
return encodeBase58(toBytes32(v, what));
|
|
46
|
+
}
|
|
47
|
+
function encString(s) {
|
|
48
|
+
const bytes = new TextEncoder().encode(s);
|
|
49
|
+
const out = new Uint8Array(4 + bytes.length);
|
|
50
|
+
new DataView(out.buffer).setUint32(0, bytes.length, true);
|
|
51
|
+
out.set(bytes, 4);
|
|
52
|
+
return out;
|
|
53
|
+
}
|
|
54
|
+
function concat(parts) {
|
|
55
|
+
const len = parts.reduce((n, p) => n + p.length, 0);
|
|
56
|
+
const out = new Uint8Array(len);
|
|
57
|
+
let o = 0;
|
|
58
|
+
for (const p of parts) {
|
|
59
|
+
out.set(p, o);
|
|
60
|
+
o += p.length;
|
|
61
|
+
}
|
|
62
|
+
return out;
|
|
63
|
+
}
|
|
64
|
+
function pushAuthorityTail(keys, programId, p) {
|
|
65
|
+
if (p.recordDelegate !== undefined) {
|
|
66
|
+
keys.push(recordDelegateSomeSlot(p.recordDelegate));
|
|
67
|
+
}
|
|
68
|
+
else if (p.holderTokenAccount !== undefined) {
|
|
69
|
+
keys.push(recordDelegateNonePlaceholder(programId));
|
|
70
|
+
}
|
|
71
|
+
if (p.holderTokenAccount !== undefined) {
|
|
72
|
+
keys.push({ pubkey: toBase58(p.holderTokenAccount, "holderTokenAccount"), isSigner: false, isWritable: false });
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
/** Build `create_namespace_override`. Args: namespace_label (String) + value (Pubkey). */
|
|
76
|
+
export function buildCreateNamespaceOverrideIx(p) {
|
|
77
|
+
const data = concat([CREATE_NAMESPACE_OVERRIDE_DISCRIMINATOR, encString(p.namespaceLabel), toBytes32(p.value, "value")]);
|
|
78
|
+
const keys = [
|
|
79
|
+
{ pubkey: toBase58(p.payer, "payer"), isSigner: true, isWritable: true },
|
|
80
|
+
{ pubkey: toBase58(p.owner, "owner"), isSigner: true, isWritable: false },
|
|
81
|
+
{ pubkey: toBase58(p.handle, "handle"), isSigner: false, isWritable: false },
|
|
82
|
+
{ pubkey: toBase58(p.namespace, "namespace"), isSigner: false, isWritable: false },
|
|
83
|
+
{ pubkey: toBase58(p.namespaceOverride, "namespaceOverride"), isSigner: false, isWritable: true },
|
|
84
|
+
{ pubkey: SYSTEM_PROGRAM, isSigner: false, isWritable: false },
|
|
85
|
+
];
|
|
86
|
+
pushAuthorityTail(keys, p.programId, p);
|
|
87
|
+
return { programId: toBase58(p.programId, "programId"), keys, data };
|
|
88
|
+
}
|
|
89
|
+
/** Build `update_namespace_override` — change the target address. Arg: value (Pubkey). */
|
|
90
|
+
export function buildUpdateNamespaceOverrideIx(p) {
|
|
91
|
+
const data = concat([UPDATE_NAMESPACE_OVERRIDE_DISCRIMINATOR, toBytes32(p.value, "value")]);
|
|
92
|
+
const keys = [
|
|
93
|
+
{ pubkey: toBase58(p.owner, "owner"), isSigner: true, isWritable: false },
|
|
94
|
+
{ pubkey: toBase58(p.handle, "handle"), isSigner: false, isWritable: false },
|
|
95
|
+
{ pubkey: toBase58(p.namespaceOverride, "namespaceOverride"), isSigner: false, isWritable: true },
|
|
96
|
+
];
|
|
97
|
+
pushAuthorityTail(keys, p.programId, p);
|
|
98
|
+
return { programId: toBase58(p.programId, "programId"), keys, data };
|
|
99
|
+
}
|
|
100
|
+
/** Build `close_namespace_override` — close the override, rent to recipient. No args. */
|
|
101
|
+
export function buildCloseNamespaceOverrideIx(p) {
|
|
102
|
+
const keys = [
|
|
103
|
+
{ pubkey: toBase58(p.owner, "owner"), isSigner: true, isWritable: false },
|
|
104
|
+
{ pubkey: toBase58(p.handle, "handle"), isSigner: false, isWritable: false },
|
|
105
|
+
{ pubkey: toBase58(p.namespaceOverride, "namespaceOverride"), isSigner: false, isWritable: true },
|
|
106
|
+
{ pubkey: toBase58(p.recipient, "recipient"), isSigner: false, isWritable: true },
|
|
107
|
+
];
|
|
108
|
+
pushAuthorityTail(keys, p.programId, p);
|
|
109
|
+
return { programId: toBase58(p.programId, "programId"), keys, data: CLOSE_NAMESPACE_OVERRIDE_DISCRIMINATOR.slice() };
|
|
110
|
+
}
|
|
111
|
+
/** Decode a `NamespaceOverride` account. Layout: disc(8) | handle(32) |
|
|
112
|
+
* namespace(String: u32 len + bytes) | value(32) | updated_at(i64) | bump(1).
|
|
113
|
+
* Returns null if the data is too short / malformed. */
|
|
114
|
+
export function decodeNamespaceOverride(data) {
|
|
115
|
+
if (data.length < 8 + 32 + 4)
|
|
116
|
+
return null;
|
|
117
|
+
const dv = new DataView(data.buffer, data.byteOffset, data.byteLength);
|
|
118
|
+
const handle = encodeBase58(data.subarray(8, 40));
|
|
119
|
+
const labelLen = dv.getUint32(40, true);
|
|
120
|
+
const labelStart = 44;
|
|
121
|
+
const labelEnd = labelStart + labelLen;
|
|
122
|
+
const valueEnd = labelEnd + 32;
|
|
123
|
+
const updatedEnd = valueEnd + 8;
|
|
124
|
+
if (data.length < updatedEnd + 1)
|
|
125
|
+
return null;
|
|
126
|
+
let namespace;
|
|
127
|
+
try {
|
|
128
|
+
namespace = new TextDecoder().decode(data.subarray(labelStart, labelEnd));
|
|
129
|
+
}
|
|
130
|
+
catch {
|
|
131
|
+
return null;
|
|
132
|
+
}
|
|
133
|
+
const value = encodeBase58(data.subarray(labelEnd, valueEnd));
|
|
134
|
+
const updatedAt = dv.getBigInt64(valueEnd, true);
|
|
135
|
+
const bump = data[updatedEnd];
|
|
136
|
+
return { handle, namespace, value, updatedAt, bump };
|
|
137
|
+
}
|
|
138
|
+
/**
|
|
139
|
+
* Fetch + decode a handle's namespace override for one label, applying the
|
|
140
|
+
* universal epoch-staleness rule — a `NamespaceOverride` PDA is reused across a
|
|
141
|
+
* release + re-register of the same handle, so an override from a PREVIOUS owner
|
|
142
|
+
* (stamped before `handleRegisteredAt`) must NOT count. Returns the live
|
|
143
|
+
* override, or null when there is none / it is stale / the account is malformed.
|
|
144
|
+
*
|
|
145
|
+
* GATED read path: this is NOT called by `resolve()` — namespaced resolution does
|
|
146
|
+
* not honor overrides yet (that is the cutover switch). Derive `overrideAccount`
|
|
147
|
+
* with `WasmResolver.deriveNamespaceOverrideAccount(handle, label, programId)`.
|
|
148
|
+
*/
|
|
149
|
+
export async function fetchNamespaceOverride(rpc, overrideAccount, handleRegisteredAt) {
|
|
150
|
+
const res = (await rpc("getAccountInfo", [
|
|
151
|
+
overrideAccount,
|
|
152
|
+
{ encoding: "base64", commitment: "confirmed" },
|
|
153
|
+
]));
|
|
154
|
+
const data0 = res?.value?.data?.[0];
|
|
155
|
+
if (!data0)
|
|
156
|
+
return null;
|
|
157
|
+
const bin = atob(data0);
|
|
158
|
+
const raw = new Uint8Array(bin.length);
|
|
159
|
+
for (let i = 0; i < bin.length; i++)
|
|
160
|
+
raw[i] = bin.charCodeAt(i);
|
|
161
|
+
const decoded = decodeNamespaceOverride(raw);
|
|
162
|
+
if (!decoded)
|
|
163
|
+
return null;
|
|
164
|
+
// Epoch-staleness: ignore an override left by a previous owner.
|
|
165
|
+
if (decoded.updatedAt < handleRegisteredAt)
|
|
166
|
+
return null;
|
|
167
|
+
return decoded;
|
|
168
|
+
}
|
|
169
|
+
/**
|
|
170
|
+
* List all LIVE namespace overrides for one handle (a getProgramAccounts scan
|
|
171
|
+
* filtered by the account discriminator + the `handle` field at offset 8), with
|
|
172
|
+
* the epoch-staleness rule applied. Each entry includes its account address.
|
|
173
|
+
*
|
|
174
|
+
* GATED read path — not used by `resolve()` yet. Pass the handle's
|
|
175
|
+
* `registeredAt` so previous-owner overrides are dropped.
|
|
176
|
+
*/
|
|
177
|
+
export async function fetchNamespaceOverridesForHandle(rpc, programId, handleAccount, handleRegisteredAt) {
|
|
178
|
+
const res = (await rpc("getProgramAccounts", [
|
|
179
|
+
programId,
|
|
180
|
+
{
|
|
181
|
+
encoding: "base64",
|
|
182
|
+
commitment: "confirmed",
|
|
183
|
+
filters: [
|
|
184
|
+
{ memcmp: { offset: 0, bytes: encodeBase58(NAMESPACE_OVERRIDE_ACCOUNT_DISCRIMINATOR) } },
|
|
185
|
+
{ memcmp: { offset: 8, bytes: handleAccount } },
|
|
186
|
+
],
|
|
187
|
+
},
|
|
188
|
+
]));
|
|
189
|
+
const out = [];
|
|
190
|
+
for (const a of res ?? []) {
|
|
191
|
+
const bin = atob(a.account.data[0]);
|
|
192
|
+
const raw = new Uint8Array(bin.length);
|
|
193
|
+
for (let i = 0; i < bin.length; i++)
|
|
194
|
+
raw[i] = bin.charCodeAt(i);
|
|
195
|
+
const decoded = decodeNamespaceOverride(raw);
|
|
196
|
+
// Defence in depth + staleness: the memcmp should guarantee the handle, but
|
|
197
|
+
// skip a mismatch or a previous-owner override.
|
|
198
|
+
if (decoded && decoded.handle === handleAccount && decoded.updatedAt >= handleRegisteredAt) {
|
|
199
|
+
out.push({ ...decoded, account: a.pubkey });
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
out.sort((x, y) => x.namespace.localeCompare(y.namespace));
|
|
203
|
+
return out;
|
|
204
|
+
}
|
package/dist/register.d.ts
CHANGED
|
@@ -58,6 +58,36 @@ export interface RegisterParams {
|
|
|
58
58
|
* payer a price before they sign.
|
|
59
59
|
*/
|
|
60
60
|
export declare function buildRegisterIx(p: RegisterParams): BuiltInstruction;
|
|
61
|
+
/** Anchor instruction discriminator: `sha256("global:register_reserved")[0..8]`. */
|
|
62
|
+
export declare const REGISTER_RESERVED_DISCRIMINATOR: Uint8Array;
|
|
63
|
+
export interface RegisterReservedParams {
|
|
64
|
+
/** The registry program id. */
|
|
65
|
+
readonly programId: AddressLike;
|
|
66
|
+
/** `Config.admin` — the ONLY key this instruction accepts (the program's
|
|
67
|
+
* `has_one = admin` constraint). Signs AND pays the new `Handle` account's
|
|
68
|
+
* rent. On x1id today admin == treasury == the deploy key. */
|
|
69
|
+
readonly admin: AddressLike;
|
|
70
|
+
/** The `["config"]` PDA. */
|
|
71
|
+
readonly config: AddressLike;
|
|
72
|
+
/** The `["handle", name]` PDA being claimed — must not already exist
|
|
73
|
+
* (`init`). On success the handle's owner is set to `Config.treasury`. */
|
|
74
|
+
readonly handle: AddressLike;
|
|
75
|
+
/** Canonical form (`parseName(...).canonical`), MIN_LEN..=32 bytes. */
|
|
76
|
+
readonly name: string;
|
|
77
|
+
readonly handleType: HandleTypeValue;
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Build `register_reserved` — the admin-only, free registration of a reserved
|
|
81
|
+
* name INTO THE TREASURY (owner is set on-chain to `Config.treasury`, not to an
|
|
82
|
+
* arbitrary target). Admin-gated: the `admin` account must equal `Config.admin`
|
|
83
|
+
* and must sign. No price, no treasury-payment account — reserved registration
|
|
84
|
+
* is free; the admin just pays the new account's rent.
|
|
85
|
+
*
|
|
86
|
+
* Same hand-rolled shape as {@link buildRegisterIx}. Returns unsigned
|
|
87
|
+
* instruction data for the caller's runtime to assemble, sign (with the admin
|
|
88
|
+
* key) and submit.
|
|
89
|
+
*/
|
|
90
|
+
export declare function buildRegisterReservedIx(p: RegisterReservedParams): BuiltInstruction;
|
|
61
91
|
/** The `Config` fields `register_with_forti` needs beyond what
|
|
62
92
|
* {@link fetchConfigTreasury} already reads. `fortiRatePerLamport === 0n`
|
|
63
93
|
* means FORTI payment is not enabled on this deployment — the same
|
package/dist/register.js
CHANGED
|
@@ -103,6 +103,43 @@ export function buildRegisterIx(p) {
|
|
|
103
103
|
}
|
|
104
104
|
return { programId: toBase58(p.programId, "programId"), keys, data };
|
|
105
105
|
}
|
|
106
|
+
// ============================= register_reserved (#8404) =============================
|
|
107
|
+
/** Anchor instruction discriminator: `sha256("global:register_reserved")[0..8]`. */
|
|
108
|
+
export const REGISTER_RESERVED_DISCRIMINATOR = Uint8Array.from([
|
|
109
|
+
37, 151, 239, 242, 251, 26, 205, 224,
|
|
110
|
+
]);
|
|
111
|
+
/**
|
|
112
|
+
* Build `register_reserved` — the admin-only, free registration of a reserved
|
|
113
|
+
* name INTO THE TREASURY (owner is set on-chain to `Config.treasury`, not to an
|
|
114
|
+
* arbitrary target). Admin-gated: the `admin` account must equal `Config.admin`
|
|
115
|
+
* and must sign. No price, no treasury-payment account — reserved registration
|
|
116
|
+
* is free; the admin just pays the new account's rent.
|
|
117
|
+
*
|
|
118
|
+
* Same hand-rolled shape as {@link buildRegisterIx}. Returns unsigned
|
|
119
|
+
* instruction data for the caller's runtime to assemble, sign (with the admin
|
|
120
|
+
* key) and submit.
|
|
121
|
+
*/
|
|
122
|
+
export function buildRegisterReservedIx(p) {
|
|
123
|
+
if (!Number.isInteger(p.handleType) || p.handleType < 0 || p.handleType > 3) {
|
|
124
|
+
throw new Error("handleType must be 0 (Human), 1 (Merchant), 2 (Org) or 3 (Agent)");
|
|
125
|
+
}
|
|
126
|
+
const nameBytes = new TextEncoder().encode(p.name);
|
|
127
|
+
if (nameBytes.length < 1 || nameBytes.length > 32) {
|
|
128
|
+
throw new Error("name must be 1..=32 bytes (UTF-8)");
|
|
129
|
+
}
|
|
130
|
+
const data = new Uint8Array(8 + 4 + nameBytes.length + 1);
|
|
131
|
+
data.set(REGISTER_RESERVED_DISCRIMINATOR, 0);
|
|
132
|
+
new DataView(data.buffer).setUint32(8, nameBytes.length, true);
|
|
133
|
+
data.set(nameBytes, 12);
|
|
134
|
+
data[12 + nameBytes.length] = p.handleType;
|
|
135
|
+
const keys = [
|
|
136
|
+
{ pubkey: toBase58(p.admin, "admin"), isSigner: true, isWritable: true },
|
|
137
|
+
{ pubkey: toBase58(p.config, "config"), isSigner: false, isWritable: true },
|
|
138
|
+
{ pubkey: toBase58(p.handle, "handle"), isSigner: false, isWritable: true },
|
|
139
|
+
{ pubkey: SYSTEM_PROGRAM, isSigner: false, isWritable: false },
|
|
140
|
+
];
|
|
141
|
+
return { programId: toBase58(p.programId, "programId"), keys, data };
|
|
142
|
+
}
|
|
106
143
|
// ============================= register_with_forti (#8136, WP #8200) =============================
|
|
107
144
|
/** Byte offsets of the `Config` fields `register_with_forti` needs, verbatim
|
|
108
145
|
* from state.rs's field order (confirmed against `migrate_config_v4`'s own
|
package/dist/scoped.d.ts
ADDED
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Scoped customer-TLD names (`alices.testtld`) — the SDK last-mile of the
|
|
3
|
+
* namespace-registrar feature (#8484/#8485).
|
|
4
|
+
*
|
|
5
|
+
* A launched X1ID namespace `.tld` is a program-owned `Namespace` account at
|
|
6
|
+
* `["namespace", tld]` with `status == Active`. A name registered under it is a
|
|
7
|
+
* (always-tokenized) `Handle` at the TWO-SEED-plus-prefix PDA
|
|
8
|
+
* `["handle", tld, name]` — a DIFFERENT account from the bare `@name`'s
|
|
9
|
+
* `["handle", name]`, so `alices.testtld` and `@alices` can have different
|
|
10
|
+
* owners. This module is the shape classifier, the `Namespace` status reader and
|
|
11
|
+
* the injected PDA deriver the resolver uses to answer a scoped name; the
|
|
12
|
+
* owner/tokenization/verification read reuses the bare-handle authority path
|
|
13
|
+
* verbatim (see `createResolver` in index.ts).
|
|
14
|
+
*
|
|
15
|
+
* The resolution CONTRACT is `tools/api`'s `resolve_scoped` (Rust, the
|
|
16
|
+
* authority): canonicalize both halves exactly as the program does, confirm
|
|
17
|
+
* `.tld` is a launched Active namespace, then derive `["handle", tld, name]` and
|
|
18
|
+
* resolve its current authority — with `namespace` set to the TLD label.
|
|
19
|
+
*
|
|
20
|
+
* # Why the deriver is injected (not hand-rolled, not WASM)
|
|
21
|
+
*
|
|
22
|
+
* The WASM module exposes `["namespace", label]` (`deriveNamespaceAccount`) but
|
|
23
|
+
* NO two-seed scoped-handle derivation, and this package's one rule is to never
|
|
24
|
+
* hand-roll `find_program_address`'s ed25519 on-curve check in TypeScript (see
|
|
25
|
+
* wasm.ts). So `["handle", tld, name]` is derived through an INJECTED
|
|
26
|
+
* {@link ScopedHandleDeriver} — exactly the pattern the SNS adapter uses for its
|
|
27
|
+
* `.sol` name-account PDA. Build the default with {@link makeScopedHandleDeriver}
|
|
28
|
+
* (which uses `@solana/web3.js`), or inject your own (a test fake, or a runtime
|
|
29
|
+
* that already owns a `findProgramAddress`).
|
|
30
|
+
*/
|
|
31
|
+
/** Max byte length of a TLD label (`NAMESPACE_MAX_LEN`, the program's state.rs). */
|
|
32
|
+
export declare const NAMESPACE_MAX_LEN = 16;
|
|
33
|
+
/** A `name.tld` split, when `input` is SHAPED like a scoped customer-TLD name. */
|
|
34
|
+
export interface ScopedCandidate {
|
|
35
|
+
/** The sub-name half (`"alices"`), lowercased; validated for real at resolve. */
|
|
36
|
+
readonly sub: string;
|
|
37
|
+
/** The TLD-label half (`"testtld"`), lowercased and label-charset-checked. */
|
|
38
|
+
readonly tld: string;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Classify `input` as a scoped customer-TLD candidate by SHAPE ONLY — no chain
|
|
42
|
+
* read. Returns the split, or null when the input is not that shape.
|
|
43
|
+
*
|
|
44
|
+
* The shape is a single interior dot with non-empty halves, no leading `@`, and
|
|
45
|
+
* a `tld` that is a plausible namespace label (the program's charset + the
|
|
46
|
+
* 1..=`NAMESPACE_MAX_LEN` length rule) and is NOT one of the reserved suffixes.
|
|
47
|
+
* Whether `.tld` is actually a launched namespace is a chain fact the resolver
|
|
48
|
+
* establishes separately — this only decides whether it is worth asking.
|
|
49
|
+
* Mirrors `app/src/lib/x1/namespaceRegister.ts`'s `namespaceSublabelShape` and
|
|
50
|
+
* the shape gate in `tools/api`'s `resolve`.
|
|
51
|
+
*/
|
|
52
|
+
export declare function scopedTldCandidate(input: string): ScopedCandidate | null;
|
|
53
|
+
/**
|
|
54
|
+
* Whether a raw `Namespace` account's bytes say it is `Active`, byte-for-byte
|
|
55
|
+
* the authority's `namespace_active_from_bytes` (tools/api). Layout: disc(8) |
|
|
56
|
+
* label(Borsh `String`: u32 LE length + UTF-8 bytes) | status(u8), and
|
|
57
|
+
* `NamespaceStatus::Active` is the first enum variant (Borsh tag 0). Only the
|
|
58
|
+
* length prefix and the one status byte are parsed — nothing past it. `false`
|
|
59
|
+
* for any buffer too short to hold disc + length prefix + the status byte (a
|
|
60
|
+
* malformed/wrong account is never read as Active). The CALLER must also check
|
|
61
|
+
* the account is owned by the registry program — this reads bytes only.
|
|
62
|
+
*/
|
|
63
|
+
export declare function namespaceIsActive(data: Uint8Array): boolean;
|
|
64
|
+
/**
|
|
65
|
+
* The one `find_program_address` derivation scoped resolution needs: the
|
|
66
|
+
* two-seed-plus-prefix scoped handle PDA `["handle", tld, name]`. Injected so
|
|
67
|
+
* the SDK core stays free of curve math (and of a hard `@solana/web3.js`
|
|
68
|
+
* dependency), and so tests can supply a deterministic fake.
|
|
69
|
+
*/
|
|
70
|
+
export interface ScopedHandleDeriver {
|
|
71
|
+
/** The `["handle", label, name]` PDA under `programId`, base58. */
|
|
72
|
+
scopedHandleKey(label: string, name: string, programId: string): Promise<string> | string;
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Build the default scoped-handle deriver using `@solana/web3.js`.
|
|
76
|
+
*
|
|
77
|
+
* Seeds are `["handle", label, name]` under the registry program — exactly the
|
|
78
|
+
* order `tools/api`'s `scoped_handle_pda` and the program's
|
|
79
|
+
* `register_under_namespace` use, so the derived PDA is the account the name
|
|
80
|
+
* actually lives at. Prefers an INJECTED web3 module (robust under `file:` /
|
|
81
|
+
* `npm link`, where a bare specifier resolves from THIS package's realpath, not
|
|
82
|
+
* the consumer's); falls back to a dynamic import for a normal install.
|
|
83
|
+
*/
|
|
84
|
+
export declare function makeScopedHandleDeriver(web3Module?: unknown): Promise<ScopedHandleDeriver>;
|
package/dist/scoped.js
ADDED
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Scoped customer-TLD names (`alices.testtld`) — the SDK last-mile of the
|
|
3
|
+
* namespace-registrar feature (#8484/#8485).
|
|
4
|
+
*
|
|
5
|
+
* A launched X1ID namespace `.tld` is a program-owned `Namespace` account at
|
|
6
|
+
* `["namespace", tld]` with `status == Active`. A name registered under it is a
|
|
7
|
+
* (always-tokenized) `Handle` at the TWO-SEED-plus-prefix PDA
|
|
8
|
+
* `["handle", tld, name]` — a DIFFERENT account from the bare `@name`'s
|
|
9
|
+
* `["handle", name]`, so `alices.testtld` and `@alices` can have different
|
|
10
|
+
* owners. This module is the shape classifier, the `Namespace` status reader and
|
|
11
|
+
* the injected PDA deriver the resolver uses to answer a scoped name; the
|
|
12
|
+
* owner/tokenization/verification read reuses the bare-handle authority path
|
|
13
|
+
* verbatim (see `createResolver` in index.ts).
|
|
14
|
+
*
|
|
15
|
+
* The resolution CONTRACT is `tools/api`'s `resolve_scoped` (Rust, the
|
|
16
|
+
* authority): canonicalize both halves exactly as the program does, confirm
|
|
17
|
+
* `.tld` is a launched Active namespace, then derive `["handle", tld, name]` and
|
|
18
|
+
* resolve its current authority — with `namespace` set to the TLD label.
|
|
19
|
+
*
|
|
20
|
+
* # Why the deriver is injected (not hand-rolled, not WASM)
|
|
21
|
+
*
|
|
22
|
+
* The WASM module exposes `["namespace", label]` (`deriveNamespaceAccount`) but
|
|
23
|
+
* NO two-seed scoped-handle derivation, and this package's one rule is to never
|
|
24
|
+
* hand-roll `find_program_address`'s ed25519 on-curve check in TypeScript (see
|
|
25
|
+
* wasm.ts). So `["handle", tld, name]` is derived through an INJECTED
|
|
26
|
+
* {@link ScopedHandleDeriver} — exactly the pattern the SNS adapter uses for its
|
|
27
|
+
* `.sol` name-account PDA. Build the default with {@link makeScopedHandleDeriver}
|
|
28
|
+
* (which uses `@solana/web3.js`), or inject your own (a test fake, or a runtime
|
|
29
|
+
* that already owns a `findProgramAddress`).
|
|
30
|
+
*/
|
|
31
|
+
import { ResolveError } from "./types.js";
|
|
32
|
+
/** Max byte length of a TLD label (`NAMESPACE_MAX_LEN`, the program's state.rs). */
|
|
33
|
+
export const NAMESPACE_MAX_LEN = 16;
|
|
34
|
+
/** The suffixes that are NEVER a scoped X1ID TLD: the native X1NS namespaces
|
|
35
|
+
* and the external ones the universal resolver owns. A scoped candidate whose
|
|
36
|
+
* suffix is one of these is refused here so `.x1`/`.xnt`/`.xen` stay on the
|
|
37
|
+
* X1NS path and `.sol`/`.eth` stay with their own adapters — the whole
|
|
38
|
+
* never-conflate-a-namespace rule. */
|
|
39
|
+
const RESERVED_SUFFIXES = new Set(["x1", "xnt", "xen", "sol", "eth"]);
|
|
40
|
+
/**
|
|
41
|
+
* Classify `input` as a scoped customer-TLD candidate by SHAPE ONLY — no chain
|
|
42
|
+
* read. Returns the split, or null when the input is not that shape.
|
|
43
|
+
*
|
|
44
|
+
* The shape is a single interior dot with non-empty halves, no leading `@`, and
|
|
45
|
+
* a `tld` that is a plausible namespace label (the program's charset + the
|
|
46
|
+
* 1..=`NAMESPACE_MAX_LEN` length rule) and is NOT one of the reserved suffixes.
|
|
47
|
+
* Whether `.tld` is actually a launched namespace is a chain fact the resolver
|
|
48
|
+
* establishes separately — this only decides whether it is worth asking.
|
|
49
|
+
* Mirrors `app/src/lib/x1/namespaceRegister.ts`'s `namespaceSublabelShape` and
|
|
50
|
+
* the shape gate in `tools/api`'s `resolve`.
|
|
51
|
+
*/
|
|
52
|
+
export function scopedTldCandidate(input) {
|
|
53
|
+
const t = input.trim().toLowerCase();
|
|
54
|
+
if (!t || t.startsWith("@"))
|
|
55
|
+
return null;
|
|
56
|
+
const dot = t.lastIndexOf(".");
|
|
57
|
+
if (dot <= 0 || dot === t.length - 1)
|
|
58
|
+
return null;
|
|
59
|
+
const sub = t.slice(0, dot);
|
|
60
|
+
const tld = t.slice(dot + 1);
|
|
61
|
+
if (sub.includes("."))
|
|
62
|
+
return null; // a deeper dotted name is a true sub-subname
|
|
63
|
+
if (RESERVED_SUFFIXES.has(tld))
|
|
64
|
+
return null; // never conflate with X1NS / external
|
|
65
|
+
if (tld.length > NAMESPACE_MAX_LEN)
|
|
66
|
+
return null;
|
|
67
|
+
if (!/^[a-z0-9-]+$/.test(tld))
|
|
68
|
+
return null;
|
|
69
|
+
if (tld.startsWith("-") || tld.endsWith("-") || tld.includes("--") || /^[0-9]+$/.test(tld)) {
|
|
70
|
+
return null;
|
|
71
|
+
}
|
|
72
|
+
return { sub, tld };
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Whether a raw `Namespace` account's bytes say it is `Active`, byte-for-byte
|
|
76
|
+
* the authority's `namespace_active_from_bytes` (tools/api). Layout: disc(8) |
|
|
77
|
+
* label(Borsh `String`: u32 LE length + UTF-8 bytes) | status(u8), and
|
|
78
|
+
* `NamespaceStatus::Active` is the first enum variant (Borsh tag 0). Only the
|
|
79
|
+
* length prefix and the one status byte are parsed — nothing past it. `false`
|
|
80
|
+
* for any buffer too short to hold disc + length prefix + the status byte (a
|
|
81
|
+
* malformed/wrong account is never read as Active). The CALLER must also check
|
|
82
|
+
* the account is owned by the registry program — this reads bytes only.
|
|
83
|
+
*/
|
|
84
|
+
export function namespaceIsActive(data) {
|
|
85
|
+
if (data.length < 12)
|
|
86
|
+
return false;
|
|
87
|
+
const labelLen = new DataView(data.buffer, data.byteOffset, data.byteLength).getUint32(8, true);
|
|
88
|
+
const statusOff = 12 + labelLen;
|
|
89
|
+
if (data.length <= statusOff)
|
|
90
|
+
return false;
|
|
91
|
+
return data[statusOff] === 0;
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Build the default scoped-handle deriver using `@solana/web3.js`.
|
|
95
|
+
*
|
|
96
|
+
* Seeds are `["handle", label, name]` under the registry program — exactly the
|
|
97
|
+
* order `tools/api`'s `scoped_handle_pda` and the program's
|
|
98
|
+
* `register_under_namespace` use, so the derived PDA is the account the name
|
|
99
|
+
* actually lives at. Prefers an INJECTED web3 module (robust under `file:` /
|
|
100
|
+
* `npm link`, where a bare specifier resolves from THIS package's realpath, not
|
|
101
|
+
* the consumer's); falls back to a dynamic import for a normal install.
|
|
102
|
+
*/
|
|
103
|
+
export async function makeScopedHandleDeriver(web3Module) {
|
|
104
|
+
let web3;
|
|
105
|
+
if (web3Module) {
|
|
106
|
+
web3 = web3Module;
|
|
107
|
+
}
|
|
108
|
+
else {
|
|
109
|
+
const spec = "@solana/web3.js";
|
|
110
|
+
try {
|
|
111
|
+
web3 = (await import(spec));
|
|
112
|
+
}
|
|
113
|
+
catch {
|
|
114
|
+
throw new ResolveError("not-configured", "scoped TLD resolution needs a deriver: install @solana/web3.js, pass the web3 module to makeScopedHandleDeriver, or inject `scopedHandleDeriver` in the resolver config");
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
const enc = new TextEncoder();
|
|
118
|
+
const handleSeed = enc.encode("handle");
|
|
119
|
+
return {
|
|
120
|
+
scopedHandleKey(label, name, programId) {
|
|
121
|
+
const program = new web3.PublicKey(programId);
|
|
122
|
+
const [key] = web3.PublicKey.findProgramAddressSync([handleSeed, enc.encode(label), enc.encode(name)], program);
|
|
123
|
+
return key.toBase58();
|
|
124
|
+
},
|
|
125
|
+
};
|
|
126
|
+
}
|
package/dist/types.d.ts
CHANGED
|
@@ -1,8 +1,18 @@
|
|
|
1
|
-
/**
|
|
2
|
-
|
|
1
|
+
/**
|
|
2
|
+
* Which naming system produced a result.
|
|
3
|
+
*
|
|
4
|
+
* The first four are the fixed native namespaces. A SCOPED customer-TLD name
|
|
5
|
+
* (`alices.testtld`, #8484/#8485) carries its TLD LABEL here — an arbitrary,
|
|
6
|
+
* launch-time string — so the union is widened with `(string & {})`: literal
|
|
7
|
+
* autocomplete for the fixed four is preserved, while a scoped result can set
|
|
8
|
+
* `namespace` to its `.tld`. Compare against the literals as before; a value
|
|
9
|
+
* that is none of them is a scoped TLD label.
|
|
10
|
+
*/
|
|
11
|
+
export type Namespace = "handle" | "x1" | "xnt" | "xen" | (string & {});
|
|
3
12
|
/**
|
|
4
13
|
* Display label for a namespace. **Must be shown** next to any resolved
|
|
5
|
-
* address — see the module docs on why this is not optional.
|
|
14
|
+
* address — see the module docs on why this is not optional. A scoped TLD label
|
|
15
|
+
* renders as `.<label>` (e.g. `.testtld`), the same as an X1NS suffix.
|
|
6
16
|
*/
|
|
7
17
|
export declare function namespaceLabel(ns: Namespace): string;
|
|
8
18
|
/** Confidence in the address a name resolves to. */
|
|
@@ -83,7 +93,16 @@ export interface Resolved {
|
|
|
83
93
|
/** Chains a handle can carry a record for. SLIP-44 based. */
|
|
84
94
|
export type Chain = "X1" | "SOL" | "ETH" | "BTC";
|
|
85
95
|
export declare const CHAIN_COIN_TYPE: Readonly<Record<Chain, number>>;
|
|
86
|
-
export type ResolveErrorCode = "unrecognized" | "ambiguous" | "invalid-handle" | "invalid-domain" | "not-found" | "no-record-for-chain" | "rpc-error"
|
|
96
|
+
export type ResolveErrorCode = "unrecognized" | "ambiguous" | "invalid-handle" | "invalid-domain" | "not-found" | "no-record-for-chain" | "rpc-error"
|
|
97
|
+
/**
|
|
98
|
+
* A reachable namespace exists for this name, but the adapter that would
|
|
99
|
+
* resolve it is not configured on this deployment (e.g. no `ETH_RPC_URL` for
|
|
100
|
+
* ENS, or no Solana mainnet RPC for SNS). Distinct from `unrecognized`: the
|
|
101
|
+
* name IS a known namespace — we just cannot reach its chain from here. A UI
|
|
102
|
+
* should surface "this namespace isn't enabled", not "unknown name", and the
|
|
103
|
+
* universal resolver NEVER fabricates an address to paper over it.
|
|
104
|
+
*/
|
|
105
|
+
| "not-configured";
|
|
87
106
|
/**
|
|
88
107
|
* Finer-grained cause for a `ResolveError`, when the code alone is not
|
|
89
108
|
* enough for a UI to explain what happened.
|