@ensdomains/ensjs 3.0.0-alpha.34 → 3.0.0-alpha.36
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/getAvailable.js +55 -0
- package/dist/cjs/functions/getDNSOwner.js +10 -7
- package/dist/cjs/functions/getNames.js +6 -6
- package/dist/cjs/functions/getProfile.js +27 -16
- package/dist/cjs/index.js +4 -0
- package/dist/esm/functions/getAvailable.mjs +36 -0
- package/dist/esm/functions/getDNSOwner.mjs +10 -7
- package/dist/esm/functions/getNames.mjs +6 -6
- package/dist/esm/functions/getProfile.mjs +27 -16
- package/dist/esm/index.mjs +4 -0
- package/dist/types/functions/getAvailable.d.ts +9 -0
- package/dist/types/functions/getProfile.d.ts +1 -0
- package/dist/types/functions/getRecords.d.ts +1 -0
- package/dist/types/functions/getSpecificRecord.d.ts +2 -2
- package/dist/types/index.d.ts +19 -4
- package/package.json +1 -1
- package/src/functions/getAvailable.test.ts +21 -0
- package/src/functions/getAvailable.ts +37 -0
- package/src/functions/getDNSOwner.test.ts +0 -7
- package/src/functions/getDNSOwner.ts +10 -8
- 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/getSpecificRecord.ts +1 -1
- package/src/index.ts +22 -2
|
@@ -0,0 +1,55 @@
|
|
|
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 getAvailable_exports = {};
|
|
20
|
+
__export(getAvailable_exports, {
|
|
21
|
+
default: () => getAvailable_default
|
|
22
|
+
});
|
|
23
|
+
module.exports = __toCommonJS(getAvailable_exports);
|
|
24
|
+
var import_labels = require("../utils/labels");
|
|
25
|
+
const raw = async ({ contracts }, name) => {
|
|
26
|
+
const baseRegistrar = await contracts?.getBaseRegistrar();
|
|
27
|
+
const labels = name.split(".");
|
|
28
|
+
if (labels.length !== 2 || labels[1] !== "eth") {
|
|
29
|
+
throw new Error("Currently only .eth names can be checked for availability");
|
|
30
|
+
}
|
|
31
|
+
return {
|
|
32
|
+
to: baseRegistrar.address,
|
|
33
|
+
data: baseRegistrar.interface.encodeFunctionData("available", [
|
|
34
|
+
(0, import_labels.labelhash)(labels[0])
|
|
35
|
+
])
|
|
36
|
+
};
|
|
37
|
+
};
|
|
38
|
+
const decode = async ({ contracts }, data) => {
|
|
39
|
+
if (data === null)
|
|
40
|
+
return;
|
|
41
|
+
const baseRegistrar = await contracts?.getBaseRegistrar();
|
|
42
|
+
try {
|
|
43
|
+
const result = baseRegistrar.interface.decodeFunctionResult(
|
|
44
|
+
"available",
|
|
45
|
+
data
|
|
46
|
+
);
|
|
47
|
+
return result["0"];
|
|
48
|
+
} catch {
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
};
|
|
52
|
+
var getAvailable_default = {
|
|
53
|
+
raw,
|
|
54
|
+
decode
|
|
55
|
+
};
|
|
@@ -31,18 +31,21 @@ __export(getDNSOwner_exports, {
|
|
|
31
31
|
});
|
|
32
32
|
module.exports = __toCommonJS(getDNSOwner_exports);
|
|
33
33
|
var packet = __toESM(require("dns-packet"));
|
|
34
|
+
var import_utils = require("ethers/lib/utils");
|
|
34
35
|
function encodeURLParams(p) {
|
|
35
36
|
return Object.entries(p).map((kv) => kv.map(encodeURIComponent).join("=")).join("&");
|
|
36
37
|
}
|
|
37
38
|
const getDNS = async (q) => {
|
|
38
|
-
const
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
39
|
+
const url = `https://cloudflare-dns.com/dns-query?${encodeURLParams({
|
|
40
|
+
ct: "application/dns-udpwireformat",
|
|
41
|
+
dns: packet.encode(q)?.toString("base64"),
|
|
42
|
+
ts: Date.now().toString()
|
|
43
|
+
})}`;
|
|
44
|
+
const response = await (0, import_utils._fetchData)(url, void 0);
|
|
45
|
+
const arrayBuffer = response.buffer.slice(
|
|
46
|
+
response.byteOffset,
|
|
47
|
+
response.byteLength + response.byteOffset
|
|
44
48
|
);
|
|
45
|
-
const arrayBuffer = await response.arrayBuffer();
|
|
46
49
|
const fromArrayBuffer = Buffer.from(arrayBuffer);
|
|
47
50
|
return packet.decode(fromArrayBuffer);
|
|
48
51
|
};
|
|
@@ -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,
|
package/dist/cjs/index.js
CHANGED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
// src/functions/getAvailable.ts
|
|
2
|
+
import { labelhash } from "../utils/labels.mjs";
|
|
3
|
+
var raw = async ({ contracts }, name) => {
|
|
4
|
+
const baseRegistrar = await contracts?.getBaseRegistrar();
|
|
5
|
+
const labels = name.split(".");
|
|
6
|
+
if (labels.length !== 2 || labels[1] !== "eth") {
|
|
7
|
+
throw new Error("Currently only .eth names can be checked for availability");
|
|
8
|
+
}
|
|
9
|
+
return {
|
|
10
|
+
to: baseRegistrar.address,
|
|
11
|
+
data: baseRegistrar.interface.encodeFunctionData("available", [
|
|
12
|
+
labelhash(labels[0])
|
|
13
|
+
])
|
|
14
|
+
};
|
|
15
|
+
};
|
|
16
|
+
var decode = async ({ contracts }, data) => {
|
|
17
|
+
if (data === null)
|
|
18
|
+
return;
|
|
19
|
+
const baseRegistrar = await contracts?.getBaseRegistrar();
|
|
20
|
+
try {
|
|
21
|
+
const result = baseRegistrar.interface.decodeFunctionResult(
|
|
22
|
+
"available",
|
|
23
|
+
data
|
|
24
|
+
);
|
|
25
|
+
return result["0"];
|
|
26
|
+
} catch {
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
29
|
+
};
|
|
30
|
+
var getAvailable_default = {
|
|
31
|
+
raw,
|
|
32
|
+
decode
|
|
33
|
+
};
|
|
34
|
+
export {
|
|
35
|
+
getAvailable_default as default
|
|
36
|
+
};
|
|
@@ -1,17 +1,20 @@
|
|
|
1
1
|
// src/functions/getDNSOwner.ts
|
|
2
2
|
import * as packet from "dns-packet";
|
|
3
|
+
import { _fetchData } from "ethers/lib/utils.js";
|
|
3
4
|
function encodeURLParams(p) {
|
|
4
5
|
return Object.entries(p).map((kv) => kv.map(encodeURIComponent).join("=")).join("&");
|
|
5
6
|
}
|
|
6
7
|
var getDNS = async (q) => {
|
|
7
|
-
const
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
8
|
+
const url = `https://cloudflare-dns.com/dns-query?${encodeURLParams({
|
|
9
|
+
ct: "application/dns-udpwireformat",
|
|
10
|
+
dns: packet.encode(q)?.toString("base64"),
|
|
11
|
+
ts: Date.now().toString()
|
|
12
|
+
})}`;
|
|
13
|
+
const response = await _fetchData(url, void 0);
|
|
14
|
+
const arrayBuffer = response.buffer.slice(
|
|
15
|
+
response.byteOffset,
|
|
16
|
+
response.byteLength + response.byteOffset
|
|
13
17
|
);
|
|
14
|
-
const arrayBuffer = await response.arrayBuffer();
|
|
15
18
|
const fromArrayBuffer = Buffer.from(arrayBuffer);
|
|
16
19
|
return packet.decode(fromArrayBuffer);
|
|
17
20
|
};
|
|
@@ -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,
|
package/dist/esm/index.mjs
CHANGED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { ENSArgs } from '..';
|
|
2
|
+
declare const _default: {
|
|
3
|
+
raw: ({ contracts }: ENSArgs<"contracts">, name: string) => Promise<{
|
|
4
|
+
to: string;
|
|
5
|
+
data: string;
|
|
6
|
+
}>;
|
|
7
|
+
decode: ({ contracts }: ENSArgs<"contracts">, data: string) => Promise<boolean | undefined>;
|
|
8
|
+
};
|
|
9
|
+
export default _default;
|
|
@@ -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 {};
|
|
@@ -42,14 +42,14 @@ export declare const _getText: {
|
|
|
42
42
|
to: string;
|
|
43
43
|
data: string;
|
|
44
44
|
}>;
|
|
45
|
-
decode: ({ contracts }: ENSArgs<'contracts'>, data: string) => Promise<
|
|
45
|
+
decode: ({ contracts }: ENSArgs<'contracts'>, data: string) => Promise<string | undefined>;
|
|
46
46
|
};
|
|
47
47
|
export declare const getText: {
|
|
48
48
|
raw: ({ contracts, universalWrapper }: ENSArgs<'contracts' | 'universalWrapper'>, name: string, key: string) => Promise<{
|
|
49
49
|
to: string;
|
|
50
50
|
data: string;
|
|
51
51
|
}>;
|
|
52
|
-
decode: ({ contracts, universalWrapper }: ENSArgs<'contracts' | 'universalWrapper'>, data: string) => Promise<
|
|
52
|
+
decode: ({ contracts, universalWrapper }: ENSArgs<'contracts' | 'universalWrapper'>, data: string) => Promise<string | undefined>;
|
|
53
53
|
};
|
|
54
54
|
export declare const _getAddr: {
|
|
55
55
|
raw: ({ contracts }: ENSArgs<'contracts'>, name: string, coinType?: string | number, bypassFormat?: boolean) => Promise<{
|
package/dist/types/index.d.ts
CHANGED
|
@@ -7,7 +7,7 @@ import type burnFuses from './functions/burnFuses';
|
|
|
7
7
|
import type commitName from './functions/commitName';
|
|
8
8
|
import type createSubname from './functions/createSubname';
|
|
9
9
|
import type deleteSubname from './functions/deleteSubname';
|
|
10
|
-
import importDNSSECName from './functions/importDNSSECName';
|
|
10
|
+
import type importDNSSECName from './functions/importDNSSECName';
|
|
11
11
|
import type registerName from './functions/registerName';
|
|
12
12
|
import type { default as renewNames, renewNameWithData } from './functions/renewNames';
|
|
13
13
|
import type setName from './functions/setName';
|
|
@@ -69,6 +69,12 @@ interface GeneratedRawFunction<F extends RawFunction> extends Function, RawFunct
|
|
|
69
69
|
}
|
|
70
70
|
export interface GenericGeneratedRawFunction extends Function, RawFunctionWithBatch {
|
|
71
71
|
}
|
|
72
|
+
interface GeneratedBatchFunction<F extends RawFunction> extends Function, RawFunction {
|
|
73
|
+
<I extends BatchFunctionResult<RawFunction>[]>(...args: I): Promise<{
|
|
74
|
+
[N in keyof I]: I[N] extends BatchFunctionResult<infer U> ? Awaited<ReturnType<U['decode']>> : never;
|
|
75
|
+
} | undefined>;
|
|
76
|
+
batch: BatchFunction<F>;
|
|
77
|
+
}
|
|
72
78
|
export declare class ENS {
|
|
73
79
|
[x: string]: any;
|
|
74
80
|
protected options?: ENSOptions;
|
|
@@ -135,7 +141,7 @@ export declare class ENS {
|
|
|
135
141
|
* @returns {ENS} - A new ENS instance with the given provider
|
|
136
142
|
*/
|
|
137
143
|
withProvider: (provider: ethers.providers.JsonRpcProvider) => ENS;
|
|
138
|
-
batch:
|
|
144
|
+
batch: GeneratedBatchFunction<{
|
|
139
145
|
raw: ({ multicallWrapper }: ENSArgs<"multicallWrapper">, ...items: BatchFunctionResult<RawFunction>[]) => Promise<{
|
|
140
146
|
to: string;
|
|
141
147
|
data: string;
|
|
@@ -176,6 +182,7 @@ export declare class ENS {
|
|
|
176
182
|
}[] | undefined;
|
|
177
183
|
} | undefined;
|
|
178
184
|
resolverAddress?: string | undefined;
|
|
185
|
+
isInvalidResolverAddress?: boolean | undefined;
|
|
179
186
|
reverseResolverAddress?: string | undefined;
|
|
180
187
|
} | undefined>;
|
|
181
188
|
getRecords: (name: string, options?: {
|
|
@@ -206,6 +213,7 @@ export declare class ENS {
|
|
|
206
213
|
}[] | undefined;
|
|
207
214
|
} | undefined;
|
|
208
215
|
resolverAddress?: string | undefined;
|
|
216
|
+
isInvalidResolverAddress?: boolean | undefined;
|
|
209
217
|
reverseResolverAddress?: string | undefined;
|
|
210
218
|
} | undefined>;
|
|
211
219
|
getName: GeneratedRawFunction<{
|
|
@@ -330,14 +338,14 @@ export declare class ENS {
|
|
|
330
338
|
to: string;
|
|
331
339
|
data: string;
|
|
332
340
|
}>;
|
|
333
|
-
decode: ({ contracts, universalWrapper }: ENSArgs<"contracts" | "universalWrapper">, data: string) => Promise<
|
|
341
|
+
decode: ({ contracts, universalWrapper }: ENSArgs<"contracts" | "universalWrapper">, data: string) => Promise<string | undefined>;
|
|
334
342
|
}>;
|
|
335
343
|
_getText: GeneratedRawFunction<{
|
|
336
344
|
raw: ({ contracts }: ENSArgs<"contracts">, name: string, key: string) => Promise<{
|
|
337
345
|
to: string;
|
|
338
346
|
data: string;
|
|
339
347
|
}>;
|
|
340
|
-
decode: ({ contracts }: ENSArgs<"contracts">, data: string) => Promise<
|
|
348
|
+
decode: ({ contracts }: ENSArgs<"contracts">, data: string) => Promise<string | undefined>;
|
|
341
349
|
}>;
|
|
342
350
|
getOwner: GeneratedRawFunction<{
|
|
343
351
|
raw: ({ contracts, multicallWrapper }: ENSArgs<"contracts" | "multicallWrapper">, name: string, contract?: "nameWrapper" | "registrar" | "registry" | undefined) => Promise<{
|
|
@@ -421,6 +429,13 @@ export declare class ENS {
|
|
|
421
429
|
} | undefined>;
|
|
422
430
|
}>;
|
|
423
431
|
getDNSOwner: (dnsName: string) => Promise<any>;
|
|
432
|
+
getAvailable: GeneratedRawFunction<{
|
|
433
|
+
raw: ({ contracts }: ENSArgs<"contracts">, name: string) => Promise<{
|
|
434
|
+
to: string;
|
|
435
|
+
data: string;
|
|
436
|
+
}>;
|
|
437
|
+
decode: ({ contracts }: ENSArgs<"contracts">, data: string) => Promise<boolean | undefined>;
|
|
438
|
+
}>;
|
|
424
439
|
universalWrapper: GeneratedRawFunction<{
|
|
425
440
|
raw: ({ contracts }: ENSArgs<"contracts">, name: string, data: string) => Promise<{
|
|
426
441
|
to: string;
|
package/package.json
CHANGED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { ENS } from '..'
|
|
2
|
+
import setup from '../tests/setup'
|
|
3
|
+
|
|
4
|
+
let ensInstance: ENS
|
|
5
|
+
|
|
6
|
+
beforeAll(async () => {
|
|
7
|
+
;({ ensInstance } = await setup())
|
|
8
|
+
})
|
|
9
|
+
|
|
10
|
+
describe('getAvailable', () => {
|
|
11
|
+
it('should return false for a name that is unavailable', async () => {
|
|
12
|
+
const result = await ensInstance.getAvailable('test123.eth')
|
|
13
|
+
expect(typeof result).toBe('boolean')
|
|
14
|
+
expect(result).toBe(false)
|
|
15
|
+
})
|
|
16
|
+
it('should return true for a name that is available', async () => {
|
|
17
|
+
const result = await ensInstance.getAvailable('available-name.eth')
|
|
18
|
+
expect(typeof result).toBe('boolean')
|
|
19
|
+
expect(result).toBe(true)
|
|
20
|
+
})
|
|
21
|
+
})
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { ENSArgs } from '..'
|
|
2
|
+
import { labelhash } from '../utils/labels'
|
|
3
|
+
|
|
4
|
+
const raw = async ({ contracts }: ENSArgs<'contracts'>, name: string) => {
|
|
5
|
+
const baseRegistrar = await contracts?.getBaseRegistrar()!
|
|
6
|
+
|
|
7
|
+
const labels = name.split('.')
|
|
8
|
+
if (labels.length !== 2 || labels[1] !== 'eth') {
|
|
9
|
+
throw new Error('Currently only .eth names can be checked for availability')
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
return {
|
|
13
|
+
to: baseRegistrar.address,
|
|
14
|
+
data: baseRegistrar.interface.encodeFunctionData('available', [
|
|
15
|
+
labelhash(labels[0]),
|
|
16
|
+
]),
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
const decode = async ({ contracts }: ENSArgs<'contracts'>, data: string) => {
|
|
21
|
+
if (data === null) return
|
|
22
|
+
const baseRegistrar = await contracts?.getBaseRegistrar()!
|
|
23
|
+
try {
|
|
24
|
+
const result = baseRegistrar.interface.decodeFunctionResult(
|
|
25
|
+
'available',
|
|
26
|
+
data,
|
|
27
|
+
)
|
|
28
|
+
return result['0'] as boolean
|
|
29
|
+
} catch {
|
|
30
|
+
return
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export default {
|
|
35
|
+
raw,
|
|
36
|
+
decode,
|
|
37
|
+
}
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import nock from 'nock'
|
|
2
|
-
import fetch from 'node-fetch'
|
|
3
2
|
import getDNSOwner, { encodeURLParams } from './getDNSOwner'
|
|
4
3
|
|
|
5
4
|
function hexDecode(string: string) {
|
|
@@ -24,12 +23,6 @@ describe('encodeURLParams', () => {
|
|
|
24
23
|
})
|
|
25
24
|
|
|
26
25
|
describe('getDNSOwner', () => {
|
|
27
|
-
beforeAll(() => {
|
|
28
|
-
global.fetch = fetch as any
|
|
29
|
-
})
|
|
30
|
-
afterAll(() => {
|
|
31
|
-
global.fetch = undefined as any
|
|
32
|
-
})
|
|
33
26
|
it('should return the address from the result of a dnsQuery', async () => {
|
|
34
27
|
const dnsName = 'brantly.xyz'
|
|
35
28
|
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import * as packet from 'dns-packet'
|
|
2
|
+
import { _fetchData } from 'ethers/lib/utils'
|
|
2
3
|
|
|
3
4
|
export function encodeURLParams(p: { [key: string]: string }): string {
|
|
4
5
|
return Object.entries(p)
|
|
@@ -7,15 +8,16 @@ export function encodeURLParams(p: { [key: string]: string }): string {
|
|
|
7
8
|
}
|
|
8
9
|
|
|
9
10
|
export const getDNS = async (q: packet.Packet): Promise<packet.Packet> => {
|
|
10
|
-
const
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
11
|
+
const url = `https://cloudflare-dns.com/dns-query?${encodeURLParams({
|
|
12
|
+
ct: 'application/dns-udpwireformat',
|
|
13
|
+
dns: packet.encode(q)?.toString('base64'),
|
|
14
|
+
ts: Date.now().toString(),
|
|
15
|
+
})}`
|
|
16
|
+
const response = await _fetchData(url, undefined)
|
|
17
|
+
const arrayBuffer = response.buffer.slice(
|
|
18
|
+
response.byteOffset,
|
|
19
|
+
response.byteLength + response.byteOffset,
|
|
16
20
|
)
|
|
17
|
-
const arrayBuffer = await response.arrayBuffer()
|
|
18
|
-
// @ts-ignore:next-line
|
|
19
21
|
const fromArrayBuffer = Buffer.from(arrayBuffer)
|
|
20
22
|
return packet.decode(fromArrayBuffer)
|
|
21
23
|
}
|
|
@@ -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
|
package/src/index.ts
CHANGED
|
@@ -13,6 +13,7 @@ import type burnFuses from './functions/burnFuses'
|
|
|
13
13
|
import type commitName from './functions/commitName'
|
|
14
14
|
import type createSubname from './functions/createSubname'
|
|
15
15
|
import type deleteSubname from './functions/deleteSubname'
|
|
16
|
+
import type getAvailable from './functions/getAvailable'
|
|
16
17
|
import type getDNSOwner from './functions/getDNSOwner'
|
|
17
18
|
import type getExpiry from './functions/getExpiry'
|
|
18
19
|
import type { getHistory } from './functions/getHistory'
|
|
@@ -33,7 +34,7 @@ import type {
|
|
|
33
34
|
} from './functions/getSpecificRecord'
|
|
34
35
|
import type getSubnames from './functions/getSubnames'
|
|
35
36
|
import type getWrapperData from './functions/getWrapperData'
|
|
36
|
-
import importDNSSECName from './functions/importDNSSECName'
|
|
37
|
+
import type importDNSSECName from './functions/importDNSSECName'
|
|
37
38
|
import type registerName from './functions/registerName'
|
|
38
39
|
import type {
|
|
39
40
|
// eslint-disable-next-line import/no-named-default
|
|
@@ -165,6 +166,20 @@ export interface GenericGeneratedRawFunction
|
|
|
165
166
|
extends Function,
|
|
166
167
|
RawFunctionWithBatch {}
|
|
167
168
|
|
|
169
|
+
interface GeneratedBatchFunction<F extends RawFunction>
|
|
170
|
+
extends Function,
|
|
171
|
+
RawFunction {
|
|
172
|
+
<I extends BatchFunctionResult<RawFunction>[]>(...args: I): Promise<
|
|
173
|
+
| {
|
|
174
|
+
[N in keyof I]: I[N] extends BatchFunctionResult<infer U>
|
|
175
|
+
? Awaited<ReturnType<U['decode']>>
|
|
176
|
+
: never
|
|
177
|
+
}
|
|
178
|
+
| undefined
|
|
179
|
+
>
|
|
180
|
+
batch: BatchFunction<F>
|
|
181
|
+
}
|
|
182
|
+
|
|
168
183
|
export class ENS {
|
|
169
184
|
[x: string]: any
|
|
170
185
|
|
|
@@ -417,7 +432,7 @@ export class ENS {
|
|
|
417
432
|
'initialGetters',
|
|
418
433
|
['multicallWrapper'],
|
|
419
434
|
'batch',
|
|
420
|
-
)
|
|
435
|
+
) as GeneratedBatchFunction<typeof batch>
|
|
421
436
|
|
|
422
437
|
public getProfile = this.generateFunction<typeof getProfile>(
|
|
423
438
|
'initialGetters',
|
|
@@ -533,6 +548,11 @@ export class ENS {
|
|
|
533
548
|
[],
|
|
534
549
|
)
|
|
535
550
|
|
|
551
|
+
public getAvailable = this.generateRawFunction<typeof getAvailable>(
|
|
552
|
+
'getAvailable',
|
|
553
|
+
['contracts'],
|
|
554
|
+
)
|
|
555
|
+
|
|
536
556
|
public universalWrapper = this.generateRawFunction<typeof universalWrapper>(
|
|
537
557
|
'initialGetters',
|
|
538
558
|
['contracts'],
|