@ensdomains/ensjs 3.0.0-alpha.35 → 3.0.0-alpha.37
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/dist/cjs/functions/getNames.js +6 -6
- package/dist/cjs/functions/getProfile.js +27 -16
- package/dist/cjs/functions/initialGetters.js +3 -1
- package/dist/cjs/functions/supportsTLD.js +48 -0
- package/dist/cjs/index.js +5 -0
- package/dist/esm/functions/getNames.mjs +6 -6
- package/dist/esm/functions/getProfile.mjs +27 -16
- package/dist/esm/functions/initialGetters.mjs +3 -1
- package/dist/esm/functions/supportsTLD.mjs +29 -0
- package/dist/esm/index.mjs +5 -0
- package/dist/types/functions/getProfile.d.ts +1 -0
- package/dist/types/functions/getRecords.d.ts +1 -0
- package/dist/types/functions/initialGetters.d.ts +1 -0
- package/dist/types/functions/supportsTLD.d.ts +2 -0
- package/dist/types/index.d.ts +8 -1
- package/package.json +1 -1
- package/src/functions/getNames.ts +6 -6
- package/src/functions/getProfile.test.ts +73 -0
- package/src/functions/getProfile.ts +32 -19
- package/src/functions/initialGetters.ts +1 -0
- package/src/functions/supportsTLD.test.ts +45 -0
- package/src/functions/supportsTLD.ts +38 -0
- package/src/index.ts +7 -0
|
@@ -303,9 +303,9 @@ const getNames = async ({ gqlInstance }, {
|
|
|
303
303
|
const { account } = await client.request(finalQuery, queryVars);
|
|
304
304
|
if (type === "all") {
|
|
305
305
|
return [
|
|
306
|
-
...account
|
|
307
|
-
...account
|
|
308
|
-
...account
|
|
306
|
+
...account?.domains.map(mapDomain) || [],
|
|
307
|
+
...account?.registrations.map(mapRegistration) || [],
|
|
308
|
+
...account?.wrappedDomains.map(mapWrappedDomain) || []
|
|
309
309
|
].sort((a, b) => {
|
|
310
310
|
if (orderDirection === "desc") {
|
|
311
311
|
if (orderBy === "labelName") {
|
|
@@ -320,11 +320,11 @@ const getNames = async ({ gqlInstance }, {
|
|
|
320
320
|
});
|
|
321
321
|
}
|
|
322
322
|
if (type === "owner") {
|
|
323
|
-
return account
|
|
323
|
+
return account?.domains.map(mapDomain) || [];
|
|
324
324
|
}
|
|
325
325
|
if (type === "wrappedOwner") {
|
|
326
|
-
return account
|
|
326
|
+
return account?.wrappedDomains.map(mapWrappedDomain) || [];
|
|
327
327
|
}
|
|
328
|
-
return account
|
|
328
|
+
return account?.registrations.map(mapRegistration) || [];
|
|
329
329
|
};
|
|
330
330
|
var getNames_default = getNames;
|
|
@@ -202,34 +202,45 @@ const getDataForName = async ({
|
|
|
202
202
|
);
|
|
203
203
|
}
|
|
204
204
|
} else {
|
|
205
|
-
|
|
206
|
-
(
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
205
|
+
try {
|
|
206
|
+
const resolvedData = await universalResolver["resolve(bytes,bytes[])"](
|
|
207
|
+
(0, import_hexEncodedName.hexEncodeName)(name),
|
|
208
|
+
data,
|
|
209
|
+
{
|
|
210
|
+
ccipReadEnabled: true
|
|
211
|
+
}
|
|
212
|
+
);
|
|
213
|
+
recordData = [...resolvedData["0"]];
|
|
214
|
+
resolverAddress = resolvedData["1"];
|
|
215
|
+
for (let i = 0; i < recordData.length; i += 1) {
|
|
216
|
+
if (recordData[i].startsWith("0x0d1947a9")) {
|
|
217
|
+
calls[i] = null;
|
|
218
|
+
recordData[i] = null;
|
|
219
|
+
}
|
|
218
220
|
}
|
|
221
|
+
} catch {
|
|
222
|
+
const registryContract = await contracts?.getRegistry();
|
|
223
|
+
resolverAddress = await registryContract?.resolver((0, import_normalise.namehash)(name));
|
|
224
|
+
return {
|
|
225
|
+
address: void 0,
|
|
226
|
+
records: {},
|
|
227
|
+
resolverAddress,
|
|
228
|
+
isInvalidResolverAddress: true
|
|
229
|
+
};
|
|
219
230
|
}
|
|
220
231
|
}
|
|
221
232
|
if (!resolverAddress || !recordData || (0, import_utils.hexStripZeros)(resolverAddress) === "0x") {
|
|
222
233
|
return {
|
|
223
|
-
address:
|
|
234
|
+
address: void 0,
|
|
224
235
|
records: {},
|
|
225
|
-
resolverAddress:
|
|
236
|
+
resolverAddress: void 0
|
|
226
237
|
};
|
|
227
238
|
}
|
|
228
239
|
const filteredCalls = calls.filter((x) => x);
|
|
229
240
|
const filteredRecordData = recordData.filter((x) => x);
|
|
230
241
|
const matchAddress = filteredRecordData[filteredCalls.findIndex((x) => x.key === "60")];
|
|
231
242
|
return {
|
|
232
|
-
address: matchAddress && await _getAddr.decode(matchAddress),
|
|
243
|
+
address: matchAddress && await _getAddr.decode(matchAddress).catch(() => false),
|
|
233
244
|
records: await formatRecords(
|
|
234
245
|
{ _getAddr, _getContentHash, _getText },
|
|
235
246
|
filteredRecordData,
|
|
@@ -33,7 +33,8 @@ __export(initialGetters_exports, {
|
|
|
33
33
|
getPrice: () => import_getPrice.default,
|
|
34
34
|
getProfile: () => import_getProfile.default,
|
|
35
35
|
getRecords: () => import_getRecords.default,
|
|
36
|
-
getSubnames: () => import_getSubnames.default
|
|
36
|
+
getSubnames: () => import_getSubnames.default,
|
|
37
|
+
supportsTLD: () => import_supportsTLD.default
|
|
37
38
|
});
|
|
38
39
|
module.exports = __toCommonJS(initialGetters_exports);
|
|
39
40
|
var import_batch = __toESM(require("./batch"));
|
|
@@ -47,3 +48,4 @@ var import_getProfile = __toESM(require("./getProfile"));
|
|
|
47
48
|
var import_getRecords = __toESM(require("./getRecords"));
|
|
48
49
|
__reExport(initialGetters_exports, require("./getSpecificRecord"), module.exports);
|
|
49
50
|
var import_getSubnames = __toESM(require("./getSubnames"));
|
|
51
|
+
var import_supportsTLD = __toESM(require("./supportsTLD"));
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
var supportsTLD_exports = {};
|
|
20
|
+
__export(supportsTLD_exports, {
|
|
21
|
+
default: () => supportsTLD_default
|
|
22
|
+
});
|
|
23
|
+
module.exports = __toCommonJS(supportsTLD_exports);
|
|
24
|
+
var import_DNSRegistrar_factory = require("../generated/factories/DNSRegistrar__factory");
|
|
25
|
+
const DNSSEC_CLAIM_INTERFACE_IDS = ["0x2f435428", "0x17d8f49b", "0x1aa2e641"];
|
|
26
|
+
async function supportsTLD_default({ getOwner, provider }, name) {
|
|
27
|
+
try {
|
|
28
|
+
const labels = name.split(".");
|
|
29
|
+
const tld = labels[labels.length - 1];
|
|
30
|
+
if (tld === "eth")
|
|
31
|
+
return true;
|
|
32
|
+
const tldOwner = await getOwner(tld, "registry");
|
|
33
|
+
if (!tldOwner?.owner)
|
|
34
|
+
return false;
|
|
35
|
+
const dnsRegistrar = import_DNSRegistrar_factory.DNSRegistrar__factory.connect(
|
|
36
|
+
tldOwner.owner,
|
|
37
|
+
provider
|
|
38
|
+
);
|
|
39
|
+
const supports = await Promise.all(
|
|
40
|
+
DNSSEC_CLAIM_INTERFACE_IDS.map(
|
|
41
|
+
(interfaceId) => dnsRegistrar.supportsInterface(interfaceId)
|
|
42
|
+
)
|
|
43
|
+
);
|
|
44
|
+
return supports.some((s) => !!s);
|
|
45
|
+
} catch {
|
|
46
|
+
return false;
|
|
47
|
+
}
|
|
48
|
+
}
|
package/dist/cjs/index.js
CHANGED
|
@@ -261,6 +261,11 @@ class ENS {
|
|
|
261
261
|
"getDNSOwner",
|
|
262
262
|
[]
|
|
263
263
|
);
|
|
264
|
+
supportsTLD = this.generateFunction(
|
|
265
|
+
"initialGetters",
|
|
266
|
+
["getOwner", "provider"],
|
|
267
|
+
"supportsTLD"
|
|
268
|
+
);
|
|
264
269
|
getAvailable = this.generateRawFunction(
|
|
265
270
|
"getAvailable",
|
|
266
271
|
["contracts"]
|
|
@@ -281,9 +281,9 @@ var getNames = async ({ gqlInstance }, {
|
|
|
281
281
|
const { account } = await client.request(finalQuery, queryVars);
|
|
282
282
|
if (type === "all") {
|
|
283
283
|
return [
|
|
284
|
-
...account
|
|
285
|
-
...account
|
|
286
|
-
...account
|
|
284
|
+
...account?.domains.map(mapDomain) || [],
|
|
285
|
+
...account?.registrations.map(mapRegistration) || [],
|
|
286
|
+
...account?.wrappedDomains.map(mapWrappedDomain) || []
|
|
287
287
|
].sort((a, b) => {
|
|
288
288
|
if (orderDirection === "desc") {
|
|
289
289
|
if (orderBy === "labelName") {
|
|
@@ -298,12 +298,12 @@ var getNames = async ({ gqlInstance }, {
|
|
|
298
298
|
});
|
|
299
299
|
}
|
|
300
300
|
if (type === "owner") {
|
|
301
|
-
return account
|
|
301
|
+
return account?.domains.map(mapDomain) || [];
|
|
302
302
|
}
|
|
303
303
|
if (type === "wrappedOwner") {
|
|
304
|
-
return account
|
|
304
|
+
return account?.wrappedDomains.map(mapWrappedDomain) || [];
|
|
305
305
|
}
|
|
306
|
-
return account
|
|
306
|
+
return account?.registrations.map(mapRegistration) || [];
|
|
307
307
|
};
|
|
308
308
|
var getNames_default = getNames;
|
|
309
309
|
export {
|
|
@@ -180,34 +180,45 @@ var getDataForName = async ({
|
|
|
180
180
|
);
|
|
181
181
|
}
|
|
182
182
|
} else {
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
183
|
+
try {
|
|
184
|
+
const resolvedData = await universalResolver["resolve(bytes,bytes[])"](
|
|
185
|
+
hexEncodeName(name),
|
|
186
|
+
data,
|
|
187
|
+
{
|
|
188
|
+
ccipReadEnabled: true
|
|
189
|
+
}
|
|
190
|
+
);
|
|
191
|
+
recordData = [...resolvedData["0"]];
|
|
192
|
+
resolverAddress = resolvedData["1"];
|
|
193
|
+
for (let i = 0; i < recordData.length; i += 1) {
|
|
194
|
+
if (recordData[i].startsWith("0x0d1947a9")) {
|
|
195
|
+
calls[i] = null;
|
|
196
|
+
recordData[i] = null;
|
|
197
|
+
}
|
|
196
198
|
}
|
|
199
|
+
} catch {
|
|
200
|
+
const registryContract = await contracts?.getRegistry();
|
|
201
|
+
resolverAddress = await registryContract?.resolver(namehash(name));
|
|
202
|
+
return {
|
|
203
|
+
address: void 0,
|
|
204
|
+
records: {},
|
|
205
|
+
resolverAddress,
|
|
206
|
+
isInvalidResolverAddress: true
|
|
207
|
+
};
|
|
197
208
|
}
|
|
198
209
|
}
|
|
199
210
|
if (!resolverAddress || !recordData || hexStripZeros(resolverAddress) === "0x") {
|
|
200
211
|
return {
|
|
201
|
-
address:
|
|
212
|
+
address: void 0,
|
|
202
213
|
records: {},
|
|
203
|
-
resolverAddress:
|
|
214
|
+
resolverAddress: void 0
|
|
204
215
|
};
|
|
205
216
|
}
|
|
206
217
|
const filteredCalls = calls.filter((x) => x);
|
|
207
218
|
const filteredRecordData = recordData.filter((x) => x);
|
|
208
219
|
const matchAddress = filteredRecordData[filteredCalls.findIndex((x) => x.key === "60")];
|
|
209
220
|
return {
|
|
210
|
-
address: matchAddress && await _getAddr.decode(matchAddress),
|
|
221
|
+
address: matchAddress && await _getAddr.decode(matchAddress).catch(() => false),
|
|
211
222
|
records: await formatRecords(
|
|
212
223
|
{ _getAddr, _getContentHash, _getText },
|
|
213
224
|
filteredRecordData,
|
|
@@ -10,6 +10,7 @@ import { default as default8 } from "./getProfile.mjs";
|
|
|
10
10
|
import { default as default9 } from "./getRecords.mjs";
|
|
11
11
|
export * from "./getSpecificRecord.mjs";
|
|
12
12
|
import { default as default10 } from "./getSubnames.mjs";
|
|
13
|
+
import { default as default11 } from "./supportsTLD.mjs";
|
|
13
14
|
export {
|
|
14
15
|
default2 as batch,
|
|
15
16
|
default3 as getExpiry,
|
|
@@ -19,5 +20,6 @@ export {
|
|
|
19
20
|
default7 as getPrice,
|
|
20
21
|
default8 as getProfile,
|
|
21
22
|
default9 as getRecords,
|
|
22
|
-
default10 as getSubnames
|
|
23
|
+
default10 as getSubnames,
|
|
24
|
+
default11 as supportsTLD
|
|
23
25
|
};
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
// src/functions/supportsTLD.ts
|
|
2
|
+
import { DNSRegistrar__factory } from "../generated/factories/DNSRegistrar__factory.mjs";
|
|
3
|
+
var DNSSEC_CLAIM_INTERFACE_IDS = ["0x2f435428", "0x17d8f49b", "0x1aa2e641"];
|
|
4
|
+
async function supportsTLD_default({ getOwner, provider }, name) {
|
|
5
|
+
try {
|
|
6
|
+
const labels = name.split(".");
|
|
7
|
+
const tld = labels[labels.length - 1];
|
|
8
|
+
if (tld === "eth")
|
|
9
|
+
return true;
|
|
10
|
+
const tldOwner = await getOwner(tld, "registry");
|
|
11
|
+
if (!tldOwner?.owner)
|
|
12
|
+
return false;
|
|
13
|
+
const dnsRegistrar = DNSRegistrar__factory.connect(
|
|
14
|
+
tldOwner.owner,
|
|
15
|
+
provider
|
|
16
|
+
);
|
|
17
|
+
const supports = await Promise.all(
|
|
18
|
+
DNSSEC_CLAIM_INTERFACE_IDS.map(
|
|
19
|
+
(interfaceId) => dnsRegistrar.supportsInterface(interfaceId)
|
|
20
|
+
)
|
|
21
|
+
);
|
|
22
|
+
return supports.some((s) => !!s);
|
|
23
|
+
} catch {
|
|
24
|
+
return false;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
export {
|
|
28
|
+
supportsTLD_default as default
|
|
29
|
+
};
|
package/dist/esm/index.mjs
CHANGED
|
@@ -233,6 +233,11 @@ var ENS = class {
|
|
|
233
233
|
"getDNSOwner",
|
|
234
234
|
[]
|
|
235
235
|
);
|
|
236
|
+
supportsTLD = this.generateFunction(
|
|
237
|
+
"initialGetters",
|
|
238
|
+
["getOwner", "provider"],
|
|
239
|
+
"supportsTLD"
|
|
240
|
+
);
|
|
236
241
|
getAvailable = this.generateRawFunction(
|
|
237
242
|
"getAvailable",
|
|
238
243
|
["contracts"]
|
|
@@ -28,6 +28,7 @@ export default function ({ getProfile }: ENSArgs<'getProfile'>, name: string, op
|
|
|
28
28
|
}[] | undefined;
|
|
29
29
|
} | undefined;
|
|
30
30
|
resolverAddress?: string | undefined;
|
|
31
|
+
isInvalidResolverAddress?: boolean | undefined;
|
|
31
32
|
reverseResolverAddress?: string | undefined;
|
|
32
33
|
} | undefined>;
|
|
33
34
|
export {};
|
package/dist/types/index.d.ts
CHANGED
|
@@ -182,6 +182,7 @@ export declare class ENS {
|
|
|
182
182
|
}[] | undefined;
|
|
183
183
|
} | undefined;
|
|
184
184
|
resolverAddress?: string | undefined;
|
|
185
|
+
isInvalidResolverAddress?: boolean | undefined;
|
|
185
186
|
reverseResolverAddress?: string | undefined;
|
|
186
187
|
} | undefined>;
|
|
187
188
|
getRecords: (name: string, options?: {
|
|
@@ -212,6 +213,7 @@ export declare class ENS {
|
|
|
212
213
|
}[] | undefined;
|
|
213
214
|
} | undefined;
|
|
214
215
|
resolverAddress?: string | undefined;
|
|
216
|
+
isInvalidResolverAddress?: boolean | undefined;
|
|
215
217
|
reverseResolverAddress?: string | undefined;
|
|
216
218
|
} | undefined>;
|
|
217
219
|
getName: GeneratedRawFunction<{
|
|
@@ -354,7 +356,11 @@ export declare class ENS {
|
|
|
354
356
|
registrant?: string | undefined;
|
|
355
357
|
owner?: string | undefined;
|
|
356
358
|
ownershipLevel: "nameWrapper" | "registrar" | "registry";
|
|
357
|
-
} | undefined>;
|
|
359
|
+
} | undefined>; /**
|
|
360
|
+
* Creates an object of ENS properties from an array
|
|
361
|
+
* @param {FunctionDeps} dependencies - An array of ENS properties
|
|
362
|
+
* @returns {Object} - An object of ENS properties
|
|
363
|
+
*/
|
|
358
364
|
}>;
|
|
359
365
|
getExpiry: GeneratedRawFunction<{
|
|
360
366
|
raw: (ensArgs: ENSArgs<"contracts" | "multicallWrapper">, name: string, { contract }?: {
|
|
@@ -427,6 +433,7 @@ export declare class ENS {
|
|
|
427
433
|
} | undefined>;
|
|
428
434
|
}>;
|
|
429
435
|
getDNSOwner: (dnsName: string) => Promise<any>;
|
|
436
|
+
supportsTLD: (name: string) => Promise<boolean>;
|
|
430
437
|
getAvailable: GeneratedRawFunction<{
|
|
431
438
|
raw: ({ contracts }: ENSArgs<"contracts">, name: string) => Promise<{
|
|
432
439
|
to: string;
|
package/package.json
CHANGED
|
@@ -350,9 +350,9 @@ const getNames = async (
|
|
|
350
350
|
const { account } = await client.request(finalQuery, queryVars)
|
|
351
351
|
if (type === 'all') {
|
|
352
352
|
return [
|
|
353
|
-
...account
|
|
354
|
-
...account
|
|
355
|
-
...account
|
|
353
|
+
...(account?.domains.map(mapDomain) || []),
|
|
354
|
+
...(account?.registrations.map(mapRegistration) || []),
|
|
355
|
+
...(account?.wrappedDomains.map(mapWrappedDomain) || []),
|
|
356
356
|
].sort((a, b) => {
|
|
357
357
|
if (orderDirection === 'desc') {
|
|
358
358
|
if (orderBy === 'labelName') {
|
|
@@ -367,12 +367,12 @@ const getNames = async (
|
|
|
367
367
|
}) as Name[]
|
|
368
368
|
}
|
|
369
369
|
if (type === 'owner') {
|
|
370
|
-
return account
|
|
370
|
+
return (account?.domains.map(mapDomain) || []) as Name[]
|
|
371
371
|
}
|
|
372
372
|
if (type === 'wrappedOwner') {
|
|
373
|
-
return account
|
|
373
|
+
return (account?.wrappedDomains.map(mapWrappedDomain) || []) as Name[]
|
|
374
374
|
}
|
|
375
|
-
return account
|
|
375
|
+
return (account?.registrations.map(mapRegistration) || []) as Name[]
|
|
376
376
|
}
|
|
377
377
|
|
|
378
378
|
export default getNames
|
|
@@ -15,6 +15,10 @@ beforeAll(async () => {
|
|
|
15
15
|
accounts = await provider.listAccounts()
|
|
16
16
|
})
|
|
17
17
|
|
|
18
|
+
beforeEach(async () => {
|
|
19
|
+
await revert()
|
|
20
|
+
})
|
|
21
|
+
|
|
18
22
|
afterAll(async () => {
|
|
19
23
|
await revert()
|
|
20
24
|
})
|
|
@@ -143,4 +147,73 @@ describe('getProfile', () => {
|
|
|
143
147
|
}
|
|
144
148
|
})
|
|
145
149
|
})
|
|
150
|
+
describe('with invalid resolver', () => {
|
|
151
|
+
it('should fail gracefully for a name with invalid resolver', async () => {
|
|
152
|
+
const tx = await ensInstance.setResolver('test123.eth', {
|
|
153
|
+
contract: 'registry',
|
|
154
|
+
resolver: '0xb794F5eA0ba39494cE839613fffBA74279579268',
|
|
155
|
+
addressOrIndex: 1,
|
|
156
|
+
})
|
|
157
|
+
expect(tx).toBeTruthy()
|
|
158
|
+
await tx.wait()
|
|
159
|
+
const result = await ensInstance.getProfile('test123.eth')
|
|
160
|
+
expect(result).toBeDefined()
|
|
161
|
+
if (result) {
|
|
162
|
+
expect(result.address).toBeUndefined()
|
|
163
|
+
expect(Object.keys(result.records!).length).toBe(0)
|
|
164
|
+
expect(result.resolverAddress).toBe(
|
|
165
|
+
'0xb794F5eA0ba39494cE839613fffBA74279579268',
|
|
166
|
+
)
|
|
167
|
+
expect(result.isInvalidResolverAddress).toBe(true)
|
|
168
|
+
}
|
|
169
|
+
})
|
|
170
|
+
|
|
171
|
+
it('should fail gracefully for a wrapped name with invalid resolver', async () => {
|
|
172
|
+
const tx = await ensInstance.setResolver('wrapped.eth', {
|
|
173
|
+
contract: 'nameWrapper',
|
|
174
|
+
resolver: '0xb794F5eA0ba39494cE839613fffBA74279579268',
|
|
175
|
+
addressOrIndex: 1,
|
|
176
|
+
})
|
|
177
|
+
expect(tx).toBeTruthy()
|
|
178
|
+
await tx.wait()
|
|
179
|
+
const result = await ensInstance.getProfile('wrapped.eth')
|
|
180
|
+
expect(result).toBeDefined()
|
|
181
|
+
if (result) {
|
|
182
|
+
expect(result.address).toBeUndefined()
|
|
183
|
+
expect(Object.keys(result.records!).length).toBe(0)
|
|
184
|
+
expect(result.resolverAddress).toBe(
|
|
185
|
+
'0xb794F5eA0ba39494cE839613fffBA74279579268',
|
|
186
|
+
)
|
|
187
|
+
expect(result.isInvalidResolverAddress).toBe(true)
|
|
188
|
+
}
|
|
189
|
+
})
|
|
190
|
+
|
|
191
|
+
it('should fail gracefully for name with invalid resolver option', async () => {
|
|
192
|
+
const result = await ensInstance.getProfile('test123.eth', {
|
|
193
|
+
resolverAddress: '0xb794F5eA0ba39494cE839613fffBA74279579268',
|
|
194
|
+
})
|
|
195
|
+
expect(result).toBeDefined()
|
|
196
|
+
if (result) {
|
|
197
|
+
expect(result.address).toBeFalsy()
|
|
198
|
+
expect(Object.keys(result.records!).length).toBe(0)
|
|
199
|
+
expect(result.resolverAddress).toBe(
|
|
200
|
+
'0xb794F5eA0ba39494cE839613fffBA74279579268',
|
|
201
|
+
)
|
|
202
|
+
}
|
|
203
|
+
})
|
|
204
|
+
|
|
205
|
+
it('should fail gracefully for wrapped name with invalid resolver option', async () => {
|
|
206
|
+
const result = await ensInstance.getProfile('wrapped.eth', {
|
|
207
|
+
resolverAddress: '0xb794F5eA0ba39494cE839613fffBA74279579268',
|
|
208
|
+
})
|
|
209
|
+
expect(result).toBeDefined()
|
|
210
|
+
if (result) {
|
|
211
|
+
expect(result.address).toBeFalsy()
|
|
212
|
+
expect(Object.keys(result.records!).length).toBe(0)
|
|
213
|
+
expect(result.resolverAddress).toBe(
|
|
214
|
+
'0xb794F5eA0ba39494cE839613fffBA74279579268',
|
|
215
|
+
)
|
|
216
|
+
}
|
|
217
|
+
})
|
|
218
|
+
})
|
|
146
219
|
})
|
|
@@ -45,6 +45,7 @@ type ResolvedProfile = {
|
|
|
45
45
|
coinTypes?: DataItem[]
|
|
46
46
|
}
|
|
47
47
|
resolverAddress?: string
|
|
48
|
+
isInvalidResolverAddress?: boolean
|
|
48
49
|
reverseResolverAddress?: string
|
|
49
50
|
}
|
|
50
51
|
|
|
@@ -293,21 +294,32 @@ const getDataForName = async (
|
|
|
293
294
|
)
|
|
294
295
|
}
|
|
295
296
|
} else {
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
297
|
+
try {
|
|
298
|
+
const resolvedData = await universalResolver['resolve(bytes,bytes[])'](
|
|
299
|
+
hexEncodeName(name),
|
|
300
|
+
data,
|
|
301
|
+
{
|
|
302
|
+
ccipReadEnabled: true,
|
|
303
|
+
},
|
|
304
|
+
)
|
|
305
|
+
recordData = [...resolvedData['0']]
|
|
306
|
+
resolverAddress = resolvedData['1']
|
|
307
|
+
for (let i = 0; i < recordData.length; i += 1) {
|
|
308
|
+
// error code for reverted call in batch
|
|
309
|
+
// this is expected when using offchain resolvers, so should be ignored
|
|
310
|
+
if (recordData[i]!.startsWith('0x0d1947a9')) {
|
|
311
|
+
calls[i] = null
|
|
312
|
+
recordData[i] = null
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
} catch {
|
|
316
|
+
const registryContract = await contracts?.getRegistry()
|
|
317
|
+
resolverAddress = await registryContract?.resolver(namehash(name))
|
|
318
|
+
return {
|
|
319
|
+
address: undefined,
|
|
320
|
+
records: {},
|
|
321
|
+
resolverAddress,
|
|
322
|
+
isInvalidResolverAddress: true,
|
|
311
323
|
}
|
|
312
324
|
}
|
|
313
325
|
}
|
|
@@ -317,9 +329,9 @@ const getDataForName = async (
|
|
|
317
329
|
hexStripZeros(resolverAddress) === '0x'
|
|
318
330
|
) {
|
|
319
331
|
return {
|
|
320
|
-
address:
|
|
332
|
+
address: undefined,
|
|
321
333
|
records: {},
|
|
322
|
-
resolverAddress:
|
|
334
|
+
resolverAddress: undefined,
|
|
323
335
|
}
|
|
324
336
|
}
|
|
325
337
|
|
|
@@ -330,7 +342,8 @@ const getDataForName = async (
|
|
|
330
342
|
filteredRecordData[filteredCalls.findIndex((x) => x.key === '60')]
|
|
331
343
|
|
|
332
344
|
return {
|
|
333
|
-
address:
|
|
345
|
+
address:
|
|
346
|
+
matchAddress && (await _getAddr.decode(matchAddress).catch(() => false)),
|
|
334
347
|
records: await formatRecords(
|
|
335
348
|
{ _getAddr, _getContentHash, _getText },
|
|
336
349
|
filteredRecordData,
|
|
@@ -456,7 +469,7 @@ const getProfileFromName = async (
|
|
|
456
469
|
>,
|
|
457
470
|
name: string,
|
|
458
471
|
options?: InputProfileOptions,
|
|
459
|
-
) => {
|
|
472
|
+
): Promise<ResolvedProfile | undefined> => {
|
|
460
473
|
const { resolverAddress, fallback, ..._options } = options || {}
|
|
461
474
|
const optsLength = Object.keys(_options).length
|
|
462
475
|
let usingOptions: InputProfileOptions | undefined
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { ENS } from '..'
|
|
2
|
+
import setup from '../tests/setup'
|
|
3
|
+
|
|
4
|
+
let ensInstance: ENS
|
|
5
|
+
let revert: Awaited<ReturnType<typeof setup>>['revert']
|
|
6
|
+
|
|
7
|
+
beforeAll(async () => {
|
|
8
|
+
;({ ensInstance, revert } = await setup())
|
|
9
|
+
})
|
|
10
|
+
|
|
11
|
+
afterAll(async () => {
|
|
12
|
+
await revert()
|
|
13
|
+
})
|
|
14
|
+
|
|
15
|
+
describe('supportsTLD', () => {
|
|
16
|
+
it('should return true for .eth tld', async () => {
|
|
17
|
+
const result = await ensInstance.supportsTLD('eth')
|
|
18
|
+
expect(result).toBeTruthy()
|
|
19
|
+
})
|
|
20
|
+
|
|
21
|
+
it('should return true for .xyz tld', async () => {
|
|
22
|
+
const result = await ensInstance.supportsTLD('xyz')
|
|
23
|
+
expect(result).toBeTruthy()
|
|
24
|
+
})
|
|
25
|
+
|
|
26
|
+
it('should return false for .com tld', async () => {
|
|
27
|
+
const result = await ensInstance.supportsTLD('com')
|
|
28
|
+
expect(result).toBeFalsy()
|
|
29
|
+
})
|
|
30
|
+
|
|
31
|
+
it('should return true for .eth name', async () => {
|
|
32
|
+
const result = await ensInstance.supportsTLD('test123.eth')
|
|
33
|
+
expect(result).toBeTruthy()
|
|
34
|
+
})
|
|
35
|
+
|
|
36
|
+
it('should return true for .xyz name', async () => {
|
|
37
|
+
const result = await ensInstance.supportsTLD('test123.xyz')
|
|
38
|
+
expect(result).toBeTruthy()
|
|
39
|
+
})
|
|
40
|
+
|
|
41
|
+
it('should return false for .com name', async () => {
|
|
42
|
+
const result = await ensInstance.supportsTLD('test123.com')
|
|
43
|
+
expect(result).toBeFalsy()
|
|
44
|
+
})
|
|
45
|
+
})
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { DNSRegistrar__factory } from '../generated/factories/DNSRegistrar__factory'
|
|
2
|
+
import { ENSArgs } from '..'
|
|
3
|
+
|
|
4
|
+
/*
|
|
5
|
+
* 0x2f435428 -> interfaceId for latest IDNSRegistrar
|
|
6
|
+
* 0x17d8f49b, 0x1aa2e641 -> interfaceId for claims method of older DNSRegistrar
|
|
7
|
+
* */
|
|
8
|
+
const DNSSEC_CLAIM_INTERFACE_IDS = ['0x2f435428', '0x17d8f49b', '0x1aa2e641']
|
|
9
|
+
|
|
10
|
+
export default async function (
|
|
11
|
+
{ getOwner, provider }: ENSArgs<'getOwner' | 'provider'>,
|
|
12
|
+
name: string,
|
|
13
|
+
): Promise<boolean> {
|
|
14
|
+
try {
|
|
15
|
+
const labels = name.split('.')
|
|
16
|
+
const tld = labels[labels.length - 1]
|
|
17
|
+
|
|
18
|
+
if (tld === 'eth') return true
|
|
19
|
+
|
|
20
|
+
const tldOwner = await getOwner(tld, 'registry')
|
|
21
|
+
if (!tldOwner?.owner) return false
|
|
22
|
+
|
|
23
|
+
const dnsRegistrar = DNSRegistrar__factory.connect(
|
|
24
|
+
tldOwner.owner,
|
|
25
|
+
provider!,
|
|
26
|
+
)
|
|
27
|
+
|
|
28
|
+
const supports = await Promise.all(
|
|
29
|
+
DNSSEC_CLAIM_INTERFACE_IDS.map((interfaceId) =>
|
|
30
|
+
dnsRegistrar.supportsInterface(interfaceId),
|
|
31
|
+
),
|
|
32
|
+
)
|
|
33
|
+
|
|
34
|
+
return supports.some((s) => !!s)
|
|
35
|
+
} catch {
|
|
36
|
+
return false
|
|
37
|
+
}
|
|
38
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -15,6 +15,7 @@ import type createSubname from './functions/createSubname'
|
|
|
15
15
|
import type deleteSubname from './functions/deleteSubname'
|
|
16
16
|
import type getAvailable from './functions/getAvailable'
|
|
17
17
|
import type getDNSOwner from './functions/getDNSOwner'
|
|
18
|
+
import type supportsTLD from './functions/supportsTLD'
|
|
18
19
|
import type getExpiry from './functions/getExpiry'
|
|
19
20
|
import type { getHistory } from './functions/getHistory'
|
|
20
21
|
import type getName from './functions/getName'
|
|
@@ -548,6 +549,12 @@ export class ENS {
|
|
|
548
549
|
[],
|
|
549
550
|
)
|
|
550
551
|
|
|
552
|
+
public supportsTLD = this.generateFunction<typeof supportsTLD>(
|
|
553
|
+
'initialGetters',
|
|
554
|
+
['getOwner', 'provider'],
|
|
555
|
+
'supportsTLD',
|
|
556
|
+
)
|
|
557
|
+
|
|
551
558
|
public getAvailable = this.generateRawFunction<typeof getAvailable>(
|
|
552
559
|
'getAvailable',
|
|
553
560
|
['contracts'],
|