@hybrd/xmtp 1.0.0 → 1.0.3

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 (45) hide show
  1. package/.cache/tsbuildinfo.json +1 -1
  2. package/.turbo/turbo-build.log +5 -0
  3. package/.turbo/turbo-lint$colon$fix.log +6 -0
  4. package/dist/scripts/generate-keys.d.ts +1 -0
  5. package/dist/scripts/generate-keys.js +19 -0
  6. package/dist/scripts/refresh-identity.d.ts +1 -0
  7. package/dist/scripts/refresh-identity.js +93 -0
  8. package/dist/scripts/register-wallet.d.ts +1 -0
  9. package/dist/scripts/register-wallet.js +75 -0
  10. package/dist/scripts/revoke-all-installations.d.ts +2 -0
  11. package/dist/scripts/revoke-all-installations.js +68 -0
  12. package/dist/scripts/revoke-installations.d.ts +2 -0
  13. package/dist/scripts/revoke-installations.js +62 -0
  14. package/dist/src/abi/l2_resolver.d.ts +992 -0
  15. package/dist/src/abi/l2_resolver.js +699 -0
  16. package/dist/src/client.d.ts +76 -0
  17. package/dist/src/client.js +709 -0
  18. package/dist/src/constants.d.ts +3 -0
  19. package/dist/src/constants.js +6 -0
  20. package/dist/src/index.d.ts +22 -0
  21. package/dist/src/index.js +46 -0
  22. package/dist/src/lib/message-listener.d.ts +69 -0
  23. package/dist/src/lib/message-listener.js +235 -0
  24. package/dist/src/lib/message-listener.test.d.ts +1 -0
  25. package/dist/src/lib/message-listener.test.js +303 -0
  26. package/dist/src/lib/subjects.d.ts +24 -0
  27. package/dist/src/lib/subjects.js +68 -0
  28. package/dist/src/resolver/address-resolver.d.ts +57 -0
  29. package/dist/src/resolver/address-resolver.js +168 -0
  30. package/dist/src/resolver/basename-resolver.d.ts +134 -0
  31. package/dist/src/resolver/basename-resolver.js +409 -0
  32. package/dist/src/resolver/ens-resolver.d.ts +95 -0
  33. package/dist/src/resolver/ens-resolver.js +249 -0
  34. package/dist/src/resolver/index.d.ts +1 -0
  35. package/dist/src/resolver/index.js +1 -0
  36. package/dist/src/resolver/resolver.d.ts +162 -0
  37. package/dist/src/resolver/resolver.js +238 -0
  38. package/dist/src/resolver/xmtp-resolver.d.ts +95 -0
  39. package/dist/src/resolver/xmtp-resolver.js +297 -0
  40. package/dist/src/service-client.d.ts +77 -0
  41. package/dist/src/service-client.js +198 -0
  42. package/dist/src/types.d.ts +123 -0
  43. package/dist/src/types.js +5 -0
  44. package/package.json +5 -4
  45. package/tsconfig.json +3 -1
@@ -0,0 +1,134 @@
1
+ import { type Address, PublicClient } from "viem";
2
+ export declare const BasenameTextRecordKeys: {
3
+ readonly Email: "email";
4
+ readonly Url: "url";
5
+ readonly Avatar: "avatar";
6
+ readonly Description: "description";
7
+ readonly Notice: "notice";
8
+ readonly Keywords: "keywords";
9
+ readonly Twitter: "com.twitter";
10
+ readonly Github: "com.github";
11
+ readonly Discord: "com.discord";
12
+ readonly Telegram: "org.telegram";
13
+ readonly Snapshot: "snapshot";
14
+ readonly Location: "location";
15
+ };
16
+ export type BasenameTextRecordKey = (typeof BasenameTextRecordKeys)[keyof typeof BasenameTextRecordKeys];
17
+ export type BaseName = string;
18
+ interface BasenameResolverOptions {
19
+ /**
20
+ * Maximum number of basenames to cache
21
+ * @default 500
22
+ */
23
+ maxCacheSize?: number;
24
+ /**
25
+ * Cache TTL in milliseconds
26
+ * @default 3600000 (1 hour)
27
+ */
28
+ cacheTtl?: number;
29
+ /**
30
+ * Public client
31
+ * @default null
32
+ */
33
+ publicClient: PublicClient;
34
+ }
35
+ /**
36
+ * Convert an chainId to a coinType hex for reverse chain resolution
37
+ */
38
+ export declare const convertChainIdToCoinType: (chainId: number) => string;
39
+ /**
40
+ * Helper function to convert an address to its reverse node for ENS lookups
41
+ */
42
+ export declare const convertReverseNodeToBytes: (address: Address, chainId: number) => `0x${string}`;
43
+ export declare class BasenameResolver {
44
+ private cache;
45
+ private textRecordCache;
46
+ private readonly maxCacheSize;
47
+ private readonly cacheTtl;
48
+ private readonly baseClient;
49
+ private resolverAddress;
50
+ private chainId;
51
+ constructor(options: BasenameResolverOptions);
52
+ /**
53
+ * Initialize the resolver address based on the client's chain ID
54
+ */
55
+ private initializeResolver;
56
+ /**
57
+ * Get the resolver address, initializing if necessary
58
+ */
59
+ private getResolverAddress;
60
+ /**
61
+ * Resolve a basename from an Ethereum address
62
+ */
63
+ getBasename(address: Address): Promise<string | null>;
64
+ /**
65
+ * Get the avatar URL for a basename
66
+ */
67
+ getBasenameAvatar(basename: BaseName): Promise<string | null>;
68
+ /**
69
+ * Get a text record for a basename
70
+ */
71
+ getBasenameTextRecord(basename: BaseName, key: BasenameTextRecordKey): Promise<string | null>;
72
+ /**
73
+ * Get the Ethereum address that owns a basename
74
+ */
75
+ getBasenameAddress(basename: BaseName): Promise<Address | null>;
76
+ /**
77
+ * Get all basic metadata for a basename
78
+ */
79
+ getBasenameMetadata(basename: BaseName): Promise<{
80
+ basename: string;
81
+ avatar: string | null;
82
+ description: string | null;
83
+ twitter: string | null;
84
+ github: string | null;
85
+ url: string | null;
86
+ } | null>;
87
+ /**
88
+ * Resolve a full basename profile (name + metadata) from an address
89
+ */
90
+ resolveBasenameProfile(address: Address): Promise<{
91
+ basename?: string | undefined;
92
+ avatar?: string | null | undefined;
93
+ description?: string | null | undefined;
94
+ twitter?: string | null | undefined;
95
+ github?: string | null | undefined;
96
+ url?: string | null | undefined;
97
+ address: `0x${string}`;
98
+ } | null>;
99
+ /**
100
+ * Get cached basename if not expired
101
+ */
102
+ private getCachedBasename;
103
+ /**
104
+ * Cache basename with LRU eviction
105
+ */
106
+ private setCachedBasename;
107
+ /**
108
+ * Get cached text record if not expired
109
+ */
110
+ private getCachedTextRecord;
111
+ /**
112
+ * Cache text record
113
+ */
114
+ private setCachedTextRecord;
115
+ /**
116
+ * Clear all caches
117
+ */
118
+ clearCache(): void;
119
+ /**
120
+ * Get cache statistics
121
+ */
122
+ getCacheStats(): {
123
+ basenameCache: {
124
+ size: number;
125
+ maxSize: number;
126
+ };
127
+ textRecordCache: {
128
+ size: number;
129
+ };
130
+ chainId: number | null;
131
+ resolverAddress: Address | null;
132
+ };
133
+ }
134
+ export {};
@@ -0,0 +1,409 @@
1
+ import { encodePacked, keccak256, namehash } from "viem";
2
+ import { mainnet } from "viem/chains";
3
+ import { L2ResolverAbi } from "../abi/l2_resolver";
4
+ // Base L2 Resolver Address mapping by chain ID
5
+ // const BASENAME_L2_RESOLVER_ADDRESSES: Record<number, Address> = {
6
+ // [mainnet.id]: "0x0000000000000000000000000000000000000000", // Mainnet (1)
7
+ // [base.id]: "0xC6d566A56A1aFf6508b41f6c90ff131615583BCD", // Base Mainnet (8453)
8
+ // [baseSepolia.id]: "0x6533C94869D28fAA8dF77cc63f9e2b2D6Cf77eBA" // Base Sepolia (84532)
9
+ // } as const
10
+ const BASENAME_L2_RESOLVER_ADDRESS = "0xC6d566A56A1aFf6508b41f6c90ff131615583BCD";
11
+ // Basename text record keys for metadata
12
+ export const BasenameTextRecordKeys = {
13
+ Email: "email",
14
+ Url: "url",
15
+ Avatar: "avatar",
16
+ Description: "description",
17
+ Notice: "notice",
18
+ Keywords: "keywords",
19
+ Twitter: "com.twitter",
20
+ Github: "com.github",
21
+ Discord: "com.discord",
22
+ Telegram: "org.telegram",
23
+ Snapshot: "snapshot",
24
+ Location: "location"
25
+ };
26
+ /**
27
+ * Convert an chainId to a coinType hex for reverse chain resolution
28
+ */
29
+ export const convertChainIdToCoinType = (chainId) => {
30
+ // L1 resolvers to addr
31
+ if (chainId === mainnet.id) {
32
+ return "addr";
33
+ }
34
+ const cointype = (0x80000000 | chainId) >>> 0;
35
+ return cointype.toString(16).toLocaleUpperCase();
36
+ };
37
+ /**
38
+ * Helper function to convert an address to its reverse node for ENS lookups
39
+ */
40
+ export const convertReverseNodeToBytes = (address, chainId) => {
41
+ const addressFormatted = address.toLocaleLowerCase();
42
+ const addressNode = keccak256(addressFormatted.substring(2));
43
+ const chainCoinType = convertChainIdToCoinType(chainId);
44
+ const baseReverseNode = namehash(`${chainCoinType.toLocaleUpperCase()}.reverse`);
45
+ const addressReverseNode = keccak256(encodePacked(["bytes32", "bytes32"], [baseReverseNode, addressNode]));
46
+ return addressReverseNode;
47
+ };
48
+ /**
49
+ * Helper function to convert a basename to its node hash
50
+ */
51
+ function convertBasenameToNode(basename) {
52
+ return namehash(basename);
53
+ }
54
+ /**
55
+ * Get the resolver address for a given chain ID
56
+ */
57
+ function getResolverAddress() {
58
+ const resolverAddress = BASENAME_L2_RESOLVER_ADDRESS;
59
+ return resolverAddress;
60
+ }
61
+ export class BasenameResolver {
62
+ constructor(options) {
63
+ this.cache = new Map();
64
+ this.textRecordCache = new Map();
65
+ this.resolverAddress = null;
66
+ this.chainId = null;
67
+ this.maxCacheSize = options.maxCacheSize ?? 500;
68
+ this.cacheTtl = options.cacheTtl ?? 3600000; // 1 hour
69
+ // Create a public client for Base network
70
+ this.baseClient = options.publicClient;
71
+ // Initialize resolver address lazily on first use
72
+ this.initializeResolver();
73
+ }
74
+ /**
75
+ * Initialize the resolver address based on the client's chain ID
76
+ */
77
+ async initializeResolver() {
78
+ if (this.resolverAddress && this.chainId) {
79
+ console.log(`🔄 BasenameResolver already initialized for chain ${this.chainId} with resolver ${this.resolverAddress}`);
80
+ return;
81
+ }
82
+ try {
83
+ console.log("🔄 Initializing BasenameResolver...");
84
+ this.chainId = await this.baseClient.getChainId();
85
+ console.log(`🔗 Chain ID detected: ${this.chainId}`);
86
+ this.resolverAddress = getResolverAddress();
87
+ console.log(`📍 Resolver address for chain ${this.chainId}: ${this.resolverAddress}`);
88
+ console.log(`✅ Initialized BasenameResolver for chain ${this.chainId} with resolver ${this.resolverAddress}`);
89
+ }
90
+ catch (error) {
91
+ console.error("❌ Failed to initialize BasenameResolver:", error);
92
+ throw error;
93
+ }
94
+ }
95
+ /**
96
+ * Get the resolver address, initializing if necessary
97
+ */
98
+ async getResolverAddress() {
99
+ await this.initializeResolver();
100
+ if (!this.resolverAddress) {
101
+ throw new Error("Failed to initialize resolver address");
102
+ }
103
+ return this.resolverAddress;
104
+ }
105
+ /**
106
+ * Resolve a basename from an Ethereum address
107
+ */
108
+ async getBasename(address) {
109
+ console.log(`🔍 Starting basename resolution for address: ${address}`);
110
+ try {
111
+ // Check cache first
112
+ const cached = this.getCachedBasename(address);
113
+ if (cached) {
114
+ console.log(`✅ Resolved basename from cache: ${cached}`);
115
+ return cached;
116
+ }
117
+ console.log(`📭 No cached basename found for address: ${address}`);
118
+ console.log("🔄 Getting resolver address...");
119
+ const resolverAddress = await this.getResolverAddress();
120
+ console.log(`📍 Using resolver address: ${resolverAddress}`);
121
+ console.log("🔄 Getting chain ID...");
122
+ const chainId = await this.baseClient.getChainId();
123
+ console.log(`🔗 Chain ID: ${chainId}`);
124
+ console.log("🔄 Converting address to reverse node...");
125
+ const addressReverseNode = convertReverseNodeToBytes(
126
+ // address.toUpperCase() as `0x${string}`,
127
+ address, chainId);
128
+ console.log(`🔗 Reverse node: ${addressReverseNode}`);
129
+ console.log("🔄 Reading contract to resolve basename...");
130
+ const basename = await this.baseClient.readContract({
131
+ abi: L2ResolverAbi,
132
+ address: resolverAddress,
133
+ functionName: "name",
134
+ args: [addressReverseNode]
135
+ });
136
+ console.log(`📋 Contract returned basename: "${basename}" (length: ${basename?.length || 0})`);
137
+ if (basename && basename.length > 0) {
138
+ this.setCachedBasename(address, basename);
139
+ console.log(`✅ Resolved basename: ${basename} for address: ${address}`);
140
+ return basename;
141
+ }
142
+ console.log(`❌ No basename found for address: ${address} (empty or null response)`);
143
+ return null;
144
+ }
145
+ catch (error) {
146
+ console.error(`❌ Error resolving basename for address ${address}:`, error);
147
+ if (error instanceof Error) {
148
+ console.error(`❌ Error details: ${error.message}`);
149
+ console.error(`❌ Error stack:`, error.stack);
150
+ }
151
+ return null;
152
+ }
153
+ }
154
+ /**
155
+ * Get the avatar URL for a basename
156
+ */
157
+ async getBasenameAvatar(basename) {
158
+ console.log(`🖼️ Getting avatar for basename: ${basename}`);
159
+ return this.getBasenameTextRecord(basename, BasenameTextRecordKeys.Avatar);
160
+ }
161
+ /**
162
+ * Get a text record for a basename
163
+ */
164
+ async getBasenameTextRecord(basename, key) {
165
+ console.log(`📝 Getting text record "${key}" for basename: ${basename}`);
166
+ try {
167
+ // Check cache first
168
+ const cached = this.getCachedTextRecord(basename, key);
169
+ if (cached) {
170
+ console.log(`✅ Resolved text record from cache: ${key}=${cached}`);
171
+ return cached;
172
+ }
173
+ console.log(`📭 No cached text record found for ${basename}.${key}`);
174
+ console.log("🔄 Getting resolver address...");
175
+ const resolverAddress = await this.getResolverAddress();
176
+ console.log(`📍 Using resolver address: ${resolverAddress}`);
177
+ console.log("🔄 Converting basename to node...");
178
+ const node = convertBasenameToNode(basename);
179
+ console.log(`🔗 Node hash: ${node}`);
180
+ console.log(`🔄 Reading contract for text record "${key}"...`);
181
+ const textRecord = await this.baseClient.readContract({
182
+ abi: L2ResolverAbi,
183
+ address: resolverAddress,
184
+ functionName: "text",
185
+ args: [node, key]
186
+ });
187
+ console.log(`📋 Contract returned text record: "${textRecord}" (length: ${textRecord?.length || 0})`);
188
+ if (textRecord && textRecord.length > 0) {
189
+ this.setCachedTextRecord(basename, key, textRecord);
190
+ console.log(`✅ Resolved text record: ${key}=${textRecord}`);
191
+ return textRecord;
192
+ }
193
+ console.log(`❌ No text record found for ${basename}.${key} (empty or null response)`);
194
+ return null;
195
+ }
196
+ catch (error) {
197
+ console.error(`❌ Error resolving text record ${key} for ${basename}:`, error);
198
+ if (error instanceof Error) {
199
+ console.error(`❌ Error details: ${error.message}`);
200
+ console.error(`❌ Error stack:`, error.stack);
201
+ }
202
+ return null;
203
+ }
204
+ }
205
+ /**
206
+ * Get the Ethereum address that owns a basename
207
+ */
208
+ async getBasenameAddress(basename) {
209
+ console.log(`🔍 Getting address for basename: ${basename}`);
210
+ try {
211
+ console.log("🔄 Getting resolver address...");
212
+ const resolverAddress = await this.getResolverAddress();
213
+ console.log(`📍 Using resolver address: ${resolverAddress}`);
214
+ console.log("🔄 Converting basename to node...");
215
+ const node = convertBasenameToNode(basename);
216
+ console.log(`🔗 Node hash: ${node}`);
217
+ console.log("🔄 Reading contract to resolve address...");
218
+ const address = await this.baseClient.readContract({
219
+ abi: L2ResolverAbi,
220
+ address: resolverAddress,
221
+ functionName: "addr",
222
+ args: [node]
223
+ });
224
+ console.log(`📋 Contract returned address: "${address}"`);
225
+ if (address && address !== "0x0000000000000000000000000000000000000000") {
226
+ console.log(`✅ Resolved address: ${address} for basename: ${basename}`);
227
+ return address;
228
+ }
229
+ console.log(`❌ No address found for basename: ${basename} (zero address or null response)`);
230
+ return null;
231
+ }
232
+ catch (error) {
233
+ console.error(`❌ Error resolving address for basename ${basename}:`, error);
234
+ if (error instanceof Error) {
235
+ console.error(`❌ Error details: ${error.message}`);
236
+ console.error(`❌ Error stack:`, error.stack);
237
+ }
238
+ return null;
239
+ }
240
+ }
241
+ /**
242
+ * Get all basic metadata for a basename
243
+ */
244
+ async getBasenameMetadata(basename) {
245
+ console.log(`📊 Getting metadata for basename: ${basename}`);
246
+ try {
247
+ const [avatar, description, twitter, github, url] = await Promise.all([
248
+ this.getBasenameTextRecord(basename, BasenameTextRecordKeys.Avatar),
249
+ this.getBasenameTextRecord(basename, BasenameTextRecordKeys.Description),
250
+ this.getBasenameTextRecord(basename, BasenameTextRecordKeys.Twitter),
251
+ this.getBasenameTextRecord(basename, BasenameTextRecordKeys.Github),
252
+ this.getBasenameTextRecord(basename, BasenameTextRecordKeys.Url)
253
+ ]);
254
+ const metadata = {
255
+ basename,
256
+ avatar,
257
+ description,
258
+ twitter,
259
+ github,
260
+ url
261
+ };
262
+ console.log(`✅ Resolved metadata for ${basename}:`, metadata);
263
+ return metadata;
264
+ }
265
+ catch (error) {
266
+ console.error(`❌ Error resolving metadata for basename ${basename}:`, error);
267
+ if (error instanceof Error) {
268
+ console.error(`❌ Error details: ${error.message}`);
269
+ console.error(`❌ Error stack:`, error.stack);
270
+ }
271
+ return null;
272
+ }
273
+ }
274
+ /**
275
+ * Resolve a full basename profile (name + metadata) from an address
276
+ */
277
+ async resolveBasenameProfile(address) {
278
+ console.log(`👤 Resolving full basename profile for address: ${address}`);
279
+ try {
280
+ const basename = await this.getBasename(address);
281
+ if (!basename) {
282
+ console.log(`❌ No basename found for address: ${address}`);
283
+ return null;
284
+ }
285
+ console.log(`🔄 Getting metadata for resolved basename: ${basename}`);
286
+ const metadata = await this.getBasenameMetadata(basename);
287
+ const profile = {
288
+ address,
289
+ ...metadata
290
+ };
291
+ console.log(`✅ Resolved full profile for ${address}:`, profile);
292
+ return profile;
293
+ }
294
+ catch (error) {
295
+ console.error(`❌ Error resolving basename profile for ${address}:`, error);
296
+ if (error instanceof Error) {
297
+ console.error(`❌ Error details: ${error.message}`);
298
+ console.error(`❌ Error stack:`, error.stack);
299
+ }
300
+ return null;
301
+ }
302
+ }
303
+ /**
304
+ * Get cached basename if not expired
305
+ */
306
+ getCachedBasename(address) {
307
+ const entry = this.cache.get(address.toLowerCase());
308
+ if (!entry) {
309
+ console.log(`📭 No cache entry found for address: ${address.toLowerCase()}`);
310
+ return null;
311
+ }
312
+ const now = Date.now();
313
+ const age = now - entry.timestamp;
314
+ console.log(`🕐 Cache entry age: ${age}ms (TTL: ${this.cacheTtl}ms)`);
315
+ if (age > this.cacheTtl) {
316
+ console.log(`⏰ Cache entry expired for address: ${address.toLowerCase()}`);
317
+ this.cache.delete(address.toLowerCase());
318
+ return null;
319
+ }
320
+ console.log(`✅ Valid cache entry found for ${address.toLowerCase()}: "${entry.basename}"`);
321
+ return entry.basename;
322
+ }
323
+ /**
324
+ * Cache basename with LRU eviction
325
+ */
326
+ setCachedBasename(address, basename) {
327
+ // Simple LRU: if cache is full, remove oldest entry
328
+ if (this.cache.size >= this.maxCacheSize) {
329
+ const firstKey = this.cache.keys().next().value;
330
+ if (firstKey) {
331
+ console.log(`🗑️ Cache full, removing oldest entry: ${firstKey}`);
332
+ this.cache.delete(firstKey);
333
+ }
334
+ }
335
+ console.log(`💾 Caching basename "${basename}" for address: ${address.toLowerCase()}`);
336
+ this.cache.set(address.toLowerCase(), {
337
+ basename,
338
+ timestamp: Date.now()
339
+ });
340
+ }
341
+ /**
342
+ * Get cached text record if not expired
343
+ */
344
+ getCachedTextRecord(basename, key) {
345
+ const basenameCache = this.textRecordCache.get(basename);
346
+ if (!basenameCache) {
347
+ console.log(`📭 No text record cache found for basename: ${basename}`);
348
+ return null;
349
+ }
350
+ const entry = basenameCache.get(key);
351
+ if (!entry) {
352
+ console.log(`📭 No cached text record found for ${basename}.${key}`);
353
+ return null;
354
+ }
355
+ const now = Date.now();
356
+ const age = now - entry.timestamp;
357
+ console.log(`🕐 Text record cache entry age: ${age}ms (TTL: ${this.cacheTtl}ms)`);
358
+ if (age > this.cacheTtl) {
359
+ console.log(`⏰ Text record cache entry expired for ${basename}.${key}`);
360
+ basenameCache.delete(key);
361
+ return null;
362
+ }
363
+ console.log(`✅ Valid text record cache entry found for ${basename}.${key}: "${entry.value}"`);
364
+ return entry.value;
365
+ }
366
+ /**
367
+ * Cache text record
368
+ */
369
+ setCachedTextRecord(basename, key, value) {
370
+ let basenameCache = this.textRecordCache.get(basename);
371
+ if (!basenameCache) {
372
+ console.log(`📝 Creating new text record cache for basename: ${basename}`);
373
+ basenameCache = new Map();
374
+ this.textRecordCache.set(basename, basenameCache);
375
+ }
376
+ console.log(`💾 Caching text record "${key}" = "${value}" for basename: ${basename}`);
377
+ basenameCache.set(key, {
378
+ value,
379
+ timestamp: Date.now()
380
+ });
381
+ }
382
+ /**
383
+ * Clear all caches
384
+ */
385
+ clearCache() {
386
+ const basenameCount = this.cache.size;
387
+ const textRecordCount = this.textRecordCache.size;
388
+ this.cache.clear();
389
+ this.textRecordCache.clear();
390
+ console.log(`🗑️ Basename cache cleared (${basenameCount} entries removed)`);
391
+ console.log(`🗑️ Text record cache cleared (${textRecordCount} basename caches removed)`);
392
+ }
393
+ /**
394
+ * Get cache statistics
395
+ */
396
+ getCacheStats() {
397
+ return {
398
+ basenameCache: {
399
+ size: this.cache.size,
400
+ maxSize: this.maxCacheSize
401
+ },
402
+ textRecordCache: {
403
+ size: this.textRecordCache.size
404
+ },
405
+ chainId: this.chainId,
406
+ resolverAddress: this.resolverAddress
407
+ };
408
+ }
409
+ }
@@ -0,0 +1,95 @@
1
+ import { type Address, PublicClient } from "viem";
2
+ interface ENSResolverOptions {
3
+ /**
4
+ * Maximum number of ENS names to cache
5
+ * @default 500
6
+ */
7
+ maxCacheSize?: number;
8
+ /**
9
+ * Cache TTL in milliseconds
10
+ * @default 3600000 (1 hour)
11
+ */
12
+ cacheTtl?: number;
13
+ /**
14
+ * Mainnet public client for ENS resolution
15
+ */
16
+ mainnetClient: PublicClient;
17
+ }
18
+ /**
19
+ * ENS Resolver for mainnet .eth names
20
+ * Handles resolution of ENS names to addresses and reverse resolution
21
+ */
22
+ export declare class ENSResolver {
23
+ private cache;
24
+ private reverseCache;
25
+ private readonly maxCacheSize;
26
+ private readonly cacheTtl;
27
+ private readonly mainnetClient;
28
+ constructor(options: ENSResolverOptions);
29
+ /**
30
+ * Resolve an ENS name to an Ethereum address
31
+ */
32
+ resolveENSName(ensName: string): Promise<Address | null>;
33
+ /**
34
+ * Resolve an address to its primary ENS name (reverse resolution)
35
+ */
36
+ resolveAddressToENS(address: Address): Promise<string | null>;
37
+ /**
38
+ * Get ENS avatar for a name
39
+ */
40
+ getENSAvatar(ensName: string): Promise<string | null>;
41
+ /**
42
+ * Get ENS text record
43
+ */
44
+ getENSTextRecord(ensName: string, key: string): Promise<string | null>;
45
+ /**
46
+ * Get comprehensive ENS profile
47
+ */
48
+ getENSProfile(ensName: string): Promise<{
49
+ ensName: string;
50
+ address: `0x${string}` | null;
51
+ avatar: string | null;
52
+ description: string | null;
53
+ twitter: string | null;
54
+ github: string | null;
55
+ url: string | null;
56
+ } | null>;
57
+ /**
58
+ * Check if a name is a valid ENS name (.eth)
59
+ */
60
+ isENSName(name: string): boolean;
61
+ /**
62
+ * Get cached address if not expired
63
+ */
64
+ private getCachedAddress;
65
+ /**
66
+ * Cache address with LRU eviction
67
+ */
68
+ private setCachedAddress;
69
+ /**
70
+ * Get cached ENS name if not expired
71
+ */
72
+ private getCachedENSName;
73
+ /**
74
+ * Cache ENS name with LRU eviction
75
+ */
76
+ private setCachedENSName;
77
+ /**
78
+ * Clear all caches
79
+ */
80
+ clearCache(): void;
81
+ /**
82
+ * Get cache statistics
83
+ */
84
+ getCacheStats(): {
85
+ addressCache: {
86
+ size: number;
87
+ maxSize: number;
88
+ };
89
+ reverseCache: {
90
+ size: number;
91
+ maxSize: number;
92
+ };
93
+ };
94
+ }
95
+ export {};