@ensdomains/ensjs 3.0.0-alpha.2 → 3.0.0-alpha.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.
- package/dist/cjs/functions/getDNSOwner.d.ts +7 -0
- package/dist/cjs/functions/getDNSOwner.js +81 -0
- package/dist/cjs/index.d.ts +1 -0
- package/dist/cjs/index.js +4 -0
- package/dist/esm/functions/getDNSOwner.d.ts +7 -0
- package/dist/esm/functions/getDNSOwner.js +51 -0
- package/dist/esm/index.d.ts +1 -0
- package/dist/esm/index.js +4 -0
- package/package.json +10 -5
- package/src/@types/dns-packet/index.d.ts +114 -0
- package/src/{tests → functions}/batch.test.ts +1 -1
- package/src/{tests → functions}/batchWrappers.test.ts +1 -1
- package/src/{tests → functions}/burnFuses.test.ts +1 -1
- package/src/{tests → functions}/createSubname.test.ts +1 -1
- package/src/{tests → functions}/deleteSubname.test.ts +1 -1
- package/src/functions/getDNSOwner.test.ts +122 -0
- package/src/functions/getDNSOwner.ts +61 -0
- package/src/{tests → functions}/getExpiry.test.ts +1 -1
- package/src/{tests → functions}/getFuses.test.ts +1 -1
- package/src/{tests → functions}/getHistory.test.ts +1 -1
- package/src/{tests → functions}/getName.test.ts +1 -1
- package/src/{tests → functions}/getNames.test.ts +1 -1
- package/src/{tests → functions}/getOwner.test.ts +1 -1
- package/src/{tests → functions}/getProfile.test.ts +1 -1
- package/src/{tests → functions}/getResolver.test.ts +1 -1
- package/src/{tests → functions}/getSpecificRecord.test.ts +1 -1
- package/src/{tests → functions}/getSubnames.test.ts +1 -1
- package/src/{tests → functions}/makeCommitment.test.ts +1 -1
- package/src/{tests → functions}/normalise.test.ts +0 -0
- package/src/{tests → functions}/setName.test.ts +1 -1
- package/src/{tests → functions}/setRecords.test.ts +1 -1
- package/src/{tests → functions}/setResolver.test.ts +1 -1
- package/src/{tests → functions}/transferName.test.ts +1 -1
- package/src/{tests → functions}/transferSubname.test.ts +1 -1
- package/src/{tests → functions}/unwrapName.test.ts +1 -1
- package/src/{tests → functions}/wrapName.test.ts +1 -1
- package/src/index.ts +9 -0
- package/src/tests/withProvider.test.ts +1 -1
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import * as packet from 'dns-packet';
|
|
2
|
+
export declare function encodeURLParams(p: {
|
|
3
|
+
[key: string]: string;
|
|
4
|
+
}): string;
|
|
5
|
+
export declare const getDNS: (q: packet.Packet) => Promise<packet.Packet>;
|
|
6
|
+
export declare const dnsQuery: (qtype: string, qname: string) => Promise<packet.Packet>;
|
|
7
|
+
export default function (dnsName: string): Promise<any>;
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || function (mod) {
|
|
19
|
+
if (mod && mod.__esModule) return mod;
|
|
20
|
+
var result = {};
|
|
21
|
+
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
22
|
+
__setModuleDefault(result, mod);
|
|
23
|
+
return result;
|
|
24
|
+
};
|
|
25
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
26
|
+
exports.dnsQuery = exports.getDNS = exports.encodeURLParams = void 0;
|
|
27
|
+
const packet = __importStar(require("dns-packet"));
|
|
28
|
+
function encodeURLParams(p) {
|
|
29
|
+
return Object.entries(p)
|
|
30
|
+
.map((kv) => kv.map(encodeURIComponent).join('='))
|
|
31
|
+
.join('&');
|
|
32
|
+
}
|
|
33
|
+
exports.encodeURLParams = encodeURLParams;
|
|
34
|
+
const getDNS = async (q) => {
|
|
35
|
+
const response = await global.fetch(`https://cloudflare-dns.com/dns-query?${encodeURLParams({
|
|
36
|
+
ct: 'application/dns-udpwireformat',
|
|
37
|
+
dns: packet.encode(q)?.toString('base64'),
|
|
38
|
+
ts: Date.now().toString(),
|
|
39
|
+
})}`);
|
|
40
|
+
const arrayBuffer = await response.arrayBuffer();
|
|
41
|
+
// @ts-ignore:next-line
|
|
42
|
+
const fromArrayBuffer = Buffer.from(arrayBuffer);
|
|
43
|
+
return packet.decode(fromArrayBuffer);
|
|
44
|
+
};
|
|
45
|
+
exports.getDNS = getDNS;
|
|
46
|
+
const dnsQuery = async (qtype, qname) => {
|
|
47
|
+
const query = {
|
|
48
|
+
type: 'query',
|
|
49
|
+
id: 1,
|
|
50
|
+
flags: packet.RECURSION_DESIRED,
|
|
51
|
+
questions: [
|
|
52
|
+
{
|
|
53
|
+
type: qtype,
|
|
54
|
+
class: 'IN',
|
|
55
|
+
name: qname,
|
|
56
|
+
},
|
|
57
|
+
],
|
|
58
|
+
additionals: [
|
|
59
|
+
{
|
|
60
|
+
type: 'OPT',
|
|
61
|
+
class: 'IN',
|
|
62
|
+
name: '.',
|
|
63
|
+
udpPayloadSize: 4096,
|
|
64
|
+
flags: packet.DNSSEC_OK,
|
|
65
|
+
},
|
|
66
|
+
],
|
|
67
|
+
answers: [],
|
|
68
|
+
};
|
|
69
|
+
const response = await (0, exports.getDNS)(query);
|
|
70
|
+
if (response.rcode !== 'NOERROR') {
|
|
71
|
+
throw new Error(`DNS query failed: ${response.rcode}`);
|
|
72
|
+
}
|
|
73
|
+
return response;
|
|
74
|
+
};
|
|
75
|
+
exports.dnsQuery = dnsQuery;
|
|
76
|
+
async function default_1(dnsName) {
|
|
77
|
+
const result = await (0, exports.dnsQuery)('TXT', `_ens.${dnsName}`);
|
|
78
|
+
const address = result?.answers?.[0]?.data?.[0]?.toString()?.split('=')?.[1];
|
|
79
|
+
return address;
|
|
80
|
+
}
|
|
81
|
+
exports.default = default_1;
|
package/dist/cjs/index.d.ts
CHANGED
|
@@ -466,5 +466,6 @@ export declare class ENS {
|
|
|
466
466
|
transferSubname: (name: string, contract: "nameWrapper" | "registry", address: string, options?: {
|
|
467
467
|
addressOrIndex?: string | number | undefined;
|
|
468
468
|
} | undefined) => Promise<ethers.ContractTransaction>;
|
|
469
|
+
getDNSOwner: () => Promise<any>;
|
|
469
470
|
}
|
|
470
471
|
export {};
|
package/dist/cjs/index.js
CHANGED
|
@@ -96,6 +96,9 @@ class ENS {
|
|
|
96
96
|
if (subFunc !== 'combine') {
|
|
97
97
|
// get the function to call
|
|
98
98
|
const func = subFunc ? mod[exportName][subFunc] : mod[exportName];
|
|
99
|
+
if (dependencies.length === 0) {
|
|
100
|
+
return func(...args);
|
|
101
|
+
}
|
|
99
102
|
// get the dependencies to forward to the function as the first arg
|
|
100
103
|
const dependenciesToForward = thisRef.forwardDependenciesFromArray(dependencies);
|
|
101
104
|
// return the function with the dependencies forwarded
|
|
@@ -220,5 +223,6 @@ class ENS {
|
|
|
220
223
|
createSubname = this.generateFunction('createSubname', ['contracts', 'provider']);
|
|
221
224
|
deleteSubname = this.generateFunction('deleteSubname', ['contracts', 'provider', 'transferSubname']);
|
|
222
225
|
transferSubname = this.generateFunction('transferSubname', ['contracts', 'provider']);
|
|
226
|
+
getDNSOwner = this.generateFunction('getDNSOwner', []);
|
|
223
227
|
}
|
|
224
228
|
exports.ENS = ENS;
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import * as packet from 'dns-packet';
|
|
2
|
+
export declare function encodeURLParams(p: {
|
|
3
|
+
[key: string]: string;
|
|
4
|
+
}): string;
|
|
5
|
+
export declare const getDNS: (q: packet.Packet) => Promise<packet.Packet>;
|
|
6
|
+
export declare const dnsQuery: (qtype: string, qname: string) => Promise<packet.Packet>;
|
|
7
|
+
export default function (dnsName: string): Promise<any>;
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import * as packet from 'dns-packet';
|
|
2
|
+
export function encodeURLParams(p) {
|
|
3
|
+
return Object.entries(p)
|
|
4
|
+
.map((kv) => kv.map(encodeURIComponent).join('='))
|
|
5
|
+
.join('&');
|
|
6
|
+
}
|
|
7
|
+
export const getDNS = async (q) => {
|
|
8
|
+
const response = await global.fetch(`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 arrayBuffer = await response.arrayBuffer();
|
|
14
|
+
// @ts-ignore:next-line
|
|
15
|
+
const fromArrayBuffer = Buffer.from(arrayBuffer);
|
|
16
|
+
return packet.decode(fromArrayBuffer);
|
|
17
|
+
};
|
|
18
|
+
export const dnsQuery = async (qtype, qname) => {
|
|
19
|
+
const query = {
|
|
20
|
+
type: 'query',
|
|
21
|
+
id: 1,
|
|
22
|
+
flags: packet.RECURSION_DESIRED,
|
|
23
|
+
questions: [
|
|
24
|
+
{
|
|
25
|
+
type: qtype,
|
|
26
|
+
class: 'IN',
|
|
27
|
+
name: qname,
|
|
28
|
+
},
|
|
29
|
+
],
|
|
30
|
+
additionals: [
|
|
31
|
+
{
|
|
32
|
+
type: 'OPT',
|
|
33
|
+
class: 'IN',
|
|
34
|
+
name: '.',
|
|
35
|
+
udpPayloadSize: 4096,
|
|
36
|
+
flags: packet.DNSSEC_OK,
|
|
37
|
+
},
|
|
38
|
+
],
|
|
39
|
+
answers: [],
|
|
40
|
+
};
|
|
41
|
+
const response = await getDNS(query);
|
|
42
|
+
if (response.rcode !== 'NOERROR') {
|
|
43
|
+
throw new Error(`DNS query failed: ${response.rcode}`);
|
|
44
|
+
}
|
|
45
|
+
return response;
|
|
46
|
+
};
|
|
47
|
+
export default async function (dnsName) {
|
|
48
|
+
const result = await dnsQuery('TXT', `_ens.${dnsName}`);
|
|
49
|
+
const address = result?.answers?.[0]?.data?.[0]?.toString()?.split('=')?.[1];
|
|
50
|
+
return address;
|
|
51
|
+
}
|
package/dist/esm/index.d.ts
CHANGED
|
@@ -466,5 +466,6 @@ export declare class ENS {
|
|
|
466
466
|
transferSubname: (name: string, contract: "nameWrapper" | "registry", address: string, options?: {
|
|
467
467
|
addressOrIndex?: string | number | undefined;
|
|
468
468
|
} | undefined) => Promise<ethers.ContractTransaction>;
|
|
469
|
+
getDNSOwner: () => Promise<any>;
|
|
469
470
|
}
|
|
470
471
|
export {};
|
package/dist/esm/index.js
CHANGED
|
@@ -59,6 +59,9 @@ export class ENS {
|
|
|
59
59
|
if (subFunc !== 'combine') {
|
|
60
60
|
// get the function to call
|
|
61
61
|
const func = subFunc ? mod[exportName][subFunc] : mod[exportName];
|
|
62
|
+
if (dependencies.length === 0) {
|
|
63
|
+
return func(...args);
|
|
64
|
+
}
|
|
62
65
|
// get the dependencies to forward to the function as the first arg
|
|
63
66
|
const dependenciesToForward = thisRef.forwardDependenciesFromArray(dependencies);
|
|
64
67
|
// return the function with the dependencies forwarded
|
|
@@ -183,6 +186,7 @@ export class ENS {
|
|
|
183
186
|
this.createSubname = this.generateFunction('createSubname', ['contracts', 'provider']);
|
|
184
187
|
this.deleteSubname = this.generateFunction('deleteSubname', ['contracts', 'provider', 'transferSubname']);
|
|
185
188
|
this.transferSubname = this.generateFunction('transferSubname', ['contracts', 'provider']);
|
|
189
|
+
this.getDNSOwner = this.generateFunction('getDNSOwner', []);
|
|
186
190
|
this.options = options;
|
|
187
191
|
this.getContractAddress = options?.getContractAddress || _getContractAddress;
|
|
188
192
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ensdomains/ensjs",
|
|
3
|
-
"version": "3.0.0-alpha.
|
|
3
|
+
"version": "3.0.0-alpha.3",
|
|
4
4
|
"description": "ENS javascript library for contract interaction",
|
|
5
5
|
"main": "./dist/cjs/index.js",
|
|
6
6
|
"types": "./dist/cjs/index.d.ts",
|
|
@@ -27,13 +27,16 @@
|
|
|
27
27
|
"generate-types": "ts-node scripts/runTypechain.ts",
|
|
28
28
|
"generate-abis": "hardhat export-abi",
|
|
29
29
|
"start": "ts-node --files src/index.test.ts",
|
|
30
|
-
"test": "jest --run-in-band
|
|
30
|
+
"test": "jest --run-in-band",
|
|
31
|
+
"test:watch": "jest --watch --run-in-band",
|
|
31
32
|
"test:specific": "ts-node --files ",
|
|
32
33
|
"clean": "rm -rf ./dist ./README.md ./LICENSE",
|
|
33
34
|
"build:esm": "tsc --project tsconfig.esm.json",
|
|
34
35
|
"build:cjs": "tsc --project tsconfig.cjs.json",
|
|
35
36
|
"build": "yarn clean && yarn build:esm && yarn build:cjs",
|
|
36
|
-
"prepublish": "yarn build && cp ../../{README.md,LICENSE} ./"
|
|
37
|
+
"prepublish": "yarn build && cp ../../{README.md,LICENSE} ./",
|
|
38
|
+
"remove-stableVersion": "ex -c '%s/,\\n\\s\\+\"stableVersion\".*\"//g' -cwq ./package.json",
|
|
39
|
+
"version:create": "yarn remove-stableVersion && yarn version"
|
|
37
40
|
},
|
|
38
41
|
"packageManager": "yarn@3.2.0",
|
|
39
42
|
"dependencies": {
|
|
@@ -48,7 +51,7 @@
|
|
|
48
51
|
},
|
|
49
52
|
"devDependencies": {
|
|
50
53
|
"@ensdomains/buffer": "^0.0.13",
|
|
51
|
-
"@ensdomains/ens-test-env": "0.
|
|
54
|
+
"@ensdomains/ens-test-env": "0.1.0",
|
|
52
55
|
"@ethersproject/abi": "^5.6.0",
|
|
53
56
|
"@ethersproject/providers": "^5.6.2",
|
|
54
57
|
"@nomiclabs/hardhat-ethers": "^2.0.5",
|
|
@@ -66,6 +69,8 @@
|
|
|
66
69
|
"jest": "^27.5.1",
|
|
67
70
|
"jest-environment-node": "^27.5.1",
|
|
68
71
|
"jest-localstorage-mock": "^2.4.21",
|
|
72
|
+
"nock": "^13.2.8",
|
|
73
|
+
"node-fetch": "^3.2.6",
|
|
69
74
|
"solc": "^0.8.13",
|
|
70
75
|
"ts-jest": "^27.1.4",
|
|
71
76
|
"ts-node": "^10.7.0",
|
|
@@ -76,5 +81,5 @@
|
|
|
76
81
|
"peerDependencies": {
|
|
77
82
|
"ethers": "*"
|
|
78
83
|
},
|
|
79
|
-
"stableVersion": "3.0.0-alpha.
|
|
84
|
+
"stableVersion": "3.0.0-alpha.2"
|
|
80
85
|
}
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
declare module 'dns-packet' {
|
|
2
|
+
const AUTHORITATIVE_ANSWER: number
|
|
3
|
+
const TRUNCATED_RESPONSE: number
|
|
4
|
+
const RECURSION_DESIRED: number
|
|
5
|
+
const RECURSION_AVAILABLE: number
|
|
6
|
+
const AUTHENTIC_DATA: number
|
|
7
|
+
const CHECKING_DISABLED: number
|
|
8
|
+
const DNSSEC_OK: number
|
|
9
|
+
|
|
10
|
+
interface decoder<T> {
|
|
11
|
+
(buf: Buffer, offset?: number): T
|
|
12
|
+
bytes: number;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
const decode: decoder<Packet>;
|
|
16
|
+
|
|
17
|
+
interface encoder<T> {
|
|
18
|
+
(packet: T, buf?: Buffer, offset?: number): Buffer
|
|
19
|
+
bytes: number;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
const encode: encoder<Packet>;
|
|
23
|
+
|
|
24
|
+
interface Packet {
|
|
25
|
+
id?: number
|
|
26
|
+
type: 'query' | 'response'
|
|
27
|
+
flags?: number
|
|
28
|
+
rcode?: string
|
|
29
|
+
questions: Question[]
|
|
30
|
+
answers?: Answer[]
|
|
31
|
+
authorities?: Answer[]
|
|
32
|
+
additionals?: Answer[]
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
interface Question {
|
|
36
|
+
type: string
|
|
37
|
+
class: string
|
|
38
|
+
name: string
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
interface AnswerBase {
|
|
42
|
+
type: string
|
|
43
|
+
class: string
|
|
44
|
+
name: string
|
|
45
|
+
ttl?: number
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
interface A extends AnswerBase {
|
|
49
|
+
type: 'A'
|
|
50
|
+
data: string
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
interface Dnskey extends AnswerBase {
|
|
54
|
+
type: 'DNSKEY'
|
|
55
|
+
data: {
|
|
56
|
+
flags: number
|
|
57
|
+
algorithm: number
|
|
58
|
+
key: Buffer
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
interface Ds extends AnswerBase {
|
|
63
|
+
type: 'DS'
|
|
64
|
+
data: {
|
|
65
|
+
keyTag: number
|
|
66
|
+
algorithm: number
|
|
67
|
+
digestType: number
|
|
68
|
+
digest: Buffer
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
interface Opt extends AnswerBase {
|
|
73
|
+
type: 'OPT'
|
|
74
|
+
udpPayloadSize?: number
|
|
75
|
+
extendedRcode?: number
|
|
76
|
+
ednsVersion?: number
|
|
77
|
+
flags?: number
|
|
78
|
+
data?: any
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
interface Rrsig extends AnswerBase {
|
|
82
|
+
type: 'RRSIG'
|
|
83
|
+
data: {
|
|
84
|
+
typeCovered: string
|
|
85
|
+
algorithm: number
|
|
86
|
+
labels: number
|
|
87
|
+
originalTTL: number
|
|
88
|
+
expiration: number
|
|
89
|
+
inception: number
|
|
90
|
+
keyTag: number
|
|
91
|
+
signersName: string
|
|
92
|
+
signature: Buffer
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
interface Rtxt extends AnswerBase {
|
|
97
|
+
type: 'TXT'
|
|
98
|
+
data: Buffer[]
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
type Answer = A|Dnskey|Ds|Opt|Rrsig|Rtxt
|
|
102
|
+
|
|
103
|
+
interface Encodable<T> {
|
|
104
|
+
decode: decoder<T>
|
|
105
|
+
encode: encoder<T>
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
const record: (type: string) => Encodable<Answer>
|
|
109
|
+
const answer: Encodable<Answer>
|
|
110
|
+
const dnskey: Encodable<Dnskey['data']>
|
|
111
|
+
const name: Encodable<string>
|
|
112
|
+
const rrsig: Encodable<Rrsig['data']>
|
|
113
|
+
}
|
|
114
|
+
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { BigNumber, ethers } from 'ethers'
|
|
2
2
|
import { ENS } from '..'
|
|
3
3
|
import { namehash } from '../utils/normalise'
|
|
4
|
-
import setup from '
|
|
4
|
+
import setup from '../tests/setup'
|
|
5
5
|
|
|
6
6
|
let ENSInstance: ENS
|
|
7
7
|
let revert: Awaited<ReturnType<typeof setup>>['revert']
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
import * as packet from 'dns-packet'
|
|
2
|
+
import fetch from 'node-fetch'
|
|
3
|
+
import nock from 'nock'
|
|
4
|
+
|
|
5
|
+
import getDNSOwner, { encodeURLParams } from './getDNSOwner'
|
|
6
|
+
|
|
7
|
+
function hex_decode(string: string) {
|
|
8
|
+
let bytes: any[] = []
|
|
9
|
+
string.replace(/../g, function (pair) {
|
|
10
|
+
bytes.push(parseInt(pair, 16))
|
|
11
|
+
})
|
|
12
|
+
return new Uint8Array(bytes).buffer
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
describe('encodeURLParams', () => {
|
|
16
|
+
it('should encodeURLParams', () => {
|
|
17
|
+
const p: { [key: string]: string } = {
|
|
18
|
+
a: 'b',
|
|
19
|
+
c: 'd',
|
|
20
|
+
}
|
|
21
|
+
const expected = 'a=b&c=d'
|
|
22
|
+
const actual = encodeURLParams(p)
|
|
23
|
+
expect(actual).toEqual(expected)
|
|
24
|
+
})
|
|
25
|
+
})
|
|
26
|
+
|
|
27
|
+
describe('getDNSOwner', () => {
|
|
28
|
+
beforeAll(() => {
|
|
29
|
+
global.fetch = fetch
|
|
30
|
+
})
|
|
31
|
+
afterAll(() => {
|
|
32
|
+
global.fetch = undefined
|
|
33
|
+
})
|
|
34
|
+
it('should return the address from the result of a dnsQuery', async () => {
|
|
35
|
+
const dnsName = 'brantly.xyz'
|
|
36
|
+
|
|
37
|
+
const scope = nock('https://cloudflare-dns.com:443', {
|
|
38
|
+
encodedQueryParams: true,
|
|
39
|
+
})
|
|
40
|
+
.get('/dns-query')
|
|
41
|
+
.query((queryObject) => {
|
|
42
|
+
console.log('queryObject: ', queryObject)
|
|
43
|
+
return (
|
|
44
|
+
queryObject.ct === 'application/dns-udpwireformat' &&
|
|
45
|
+
queryObject.dns ===
|
|
46
|
+
'AAEBAAABAAAAAAABBF9lbnMHYnJhbnRseQN4eXoAABAAAQAAKRAAAACAAAAA'
|
|
47
|
+
)
|
|
48
|
+
})
|
|
49
|
+
.reply(
|
|
50
|
+
200,
|
|
51
|
+
Buffer.from(
|
|
52
|
+
hex_decode(
|
|
53
|
+
'000181a00001000200000001045f656e73076272616e746c790378797a0000100001c00c0010000100000e10002d2c613d307839383331313033303936323044393131373331416330393332323139616630363039316236373434c00c002e000100000e10009f0010080300000e1062df366962c23569d89d076272616e746c790378797a0039c894ca1d7a60c1356e478066d39961a78ec1edbe62e1eb0f13d7947bb72097654648dc79be075ca32625f02e60267f45e88d7c05e9c3ec0cf21ab2dca67a8fbeb8e995644726357628446b888a144cafef5cbfca120c6511fe36de9d3c62dee27680825190c5404ca503904b98dbf62d9122f6fda393dc04b14a89ceb68c7a00002904d0000080000000',
|
|
54
|
+
),
|
|
55
|
+
),
|
|
56
|
+
[
|
|
57
|
+
'Server',
|
|
58
|
+
'cloudflare',
|
|
59
|
+
'Date',
|
|
60
|
+
'Wed, 06 Jul 2022 23:37:28 GMT',
|
|
61
|
+
'Content-Type',
|
|
62
|
+
'application/dns-message',
|
|
63
|
+
'Connection',
|
|
64
|
+
'close',
|
|
65
|
+
'Access-Control-Allow-Origin',
|
|
66
|
+
'*',
|
|
67
|
+
'Content-Length',
|
|
68
|
+
'273',
|
|
69
|
+
'CF-RAY',
|
|
70
|
+
'726c2b1d3bab6b74-TPE',
|
|
71
|
+
],
|
|
72
|
+
)
|
|
73
|
+
expect(await getDNSOwner(dnsName)).toEqual(
|
|
74
|
+
'0x983110309620D911731Ac0932219af06091b6744',
|
|
75
|
+
)
|
|
76
|
+
})
|
|
77
|
+
it('should throw if there is an error in the DNS query', async () => {
|
|
78
|
+
const dnsName = 'nick.xyz'
|
|
79
|
+
|
|
80
|
+
const scope = nock('https://cloudflare-dns.com:443', {
|
|
81
|
+
encodedQueryParams: true,
|
|
82
|
+
})
|
|
83
|
+
.get('/dns-query')
|
|
84
|
+
.query((queryObject) => {
|
|
85
|
+
console.log('queryObject: ', queryObject)
|
|
86
|
+
return (
|
|
87
|
+
queryObject.ct === 'application/dns-udpwireformat' &&
|
|
88
|
+
queryObject.dns ===
|
|
89
|
+
'AAEBAAABAAAAAAABBF9lbnMEbmljawN4eXoAABAAAQAAKRAAAACAAAAA'
|
|
90
|
+
)
|
|
91
|
+
})
|
|
92
|
+
.reply(
|
|
93
|
+
200,
|
|
94
|
+
Buffer.from(
|
|
95
|
+
hex_decode(
|
|
96
|
+
'000181830001000000010001045f656e73046e69636b0378797a0000100001c0110006000100000258003b046e7337310d646f6d61696e636f6e74726f6c03636f6d0003646e73056a6f6d6178036e6574007876d1800000708000001c2000093a800000025800002904d0000080000000',
|
|
97
|
+
),
|
|
98
|
+
),
|
|
99
|
+
[
|
|
100
|
+
'Server',
|
|
101
|
+
'cloudflare',
|
|
102
|
+
'Date',
|
|
103
|
+
'Wed, 06 Jul 2022 23:37:28 GMT',
|
|
104
|
+
'Content-Type',
|
|
105
|
+
'application/dns-message',
|
|
106
|
+
'Connection',
|
|
107
|
+
'close',
|
|
108
|
+
'Access-Control-Allow-Origin',
|
|
109
|
+
'*',
|
|
110
|
+
'Content-Length',
|
|
111
|
+
'273',
|
|
112
|
+
'CF-RAY',
|
|
113
|
+
'726c2b1d3bab6b74-TPE',
|
|
114
|
+
],
|
|
115
|
+
)
|
|
116
|
+
try {
|
|
117
|
+
await getDNSOwner(dnsName)
|
|
118
|
+
} catch (error) {
|
|
119
|
+
expect(error.message).toEqual('DNS query failed: NXDOMAIN')
|
|
120
|
+
}
|
|
121
|
+
})
|
|
122
|
+
})
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import * as packet from 'dns-packet'
|
|
2
|
+
|
|
3
|
+
export function encodeURLParams(p: { [key: string]: string }): string {
|
|
4
|
+
return Object.entries(p)
|
|
5
|
+
.map((kv) => kv.map(encodeURIComponent).join('='))
|
|
6
|
+
.join('&')
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export const getDNS = async (q: packet.Packet): Promise<packet.Packet> => {
|
|
10
|
+
const response = await global.fetch(
|
|
11
|
+
`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
|
+
)
|
|
17
|
+
const arrayBuffer = await response.arrayBuffer()
|
|
18
|
+
// @ts-ignore:next-line
|
|
19
|
+
const fromArrayBuffer = Buffer.from(arrayBuffer);
|
|
20
|
+
return packet.decode(fromArrayBuffer)
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export const dnsQuery = async (
|
|
24
|
+
qtype: string,
|
|
25
|
+
qname: string,
|
|
26
|
+
): Promise<packet.Packet> => {
|
|
27
|
+
const query: packet.Packet = {
|
|
28
|
+
type: 'query',
|
|
29
|
+
id: 1,
|
|
30
|
+
flags: packet.RECURSION_DESIRED,
|
|
31
|
+
questions: [
|
|
32
|
+
{
|
|
33
|
+
type: qtype,
|
|
34
|
+
class: 'IN',
|
|
35
|
+
name: qname,
|
|
36
|
+
},
|
|
37
|
+
],
|
|
38
|
+
additionals: [
|
|
39
|
+
{
|
|
40
|
+
type: 'OPT',
|
|
41
|
+
class: 'IN',
|
|
42
|
+
name: '.',
|
|
43
|
+
udpPayloadSize: 4096,
|
|
44
|
+
flags: packet.DNSSEC_OK,
|
|
45
|
+
},
|
|
46
|
+
],
|
|
47
|
+
answers: [],
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
const response = await getDNS(query)
|
|
51
|
+
if (response.rcode !== 'NOERROR') {
|
|
52
|
+
throw new Error(`DNS query failed: ${response.rcode}`)
|
|
53
|
+
}
|
|
54
|
+
return response
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export default async function (dnsName: string) {
|
|
58
|
+
const result = await dnsQuery('TXT', `_ens.${dnsName}`)
|
|
59
|
+
const address = result?.answers?.[0]?.data?.[0]?.toString()?.split('=')?.[1]
|
|
60
|
+
return address
|
|
61
|
+
}
|
|
File without changes
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { ethers } from 'ethers'
|
|
2
2
|
import { ENS } from '..'
|
|
3
3
|
import { hexEncodeName } from '../utils/hexEncodedName'
|
|
4
|
-
import setup from '
|
|
4
|
+
import setup from '../tests/setup'
|
|
5
5
|
|
|
6
6
|
let ENSInstance: ENS
|
|
7
7
|
let revert: Awaited<ReturnType<typeof setup>>['revert']
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { ENS } from '..'
|
|
2
2
|
import { hexEncodeName } from '../utils/hexEncodedName'
|
|
3
3
|
import { namehash } from '../utils/normalise'
|
|
4
|
-
import setup from '
|
|
4
|
+
import setup from '../tests/setup'
|
|
5
5
|
|
|
6
6
|
let ENSInstance: ENS
|
|
7
7
|
let revert: Awaited<ReturnType<typeof setup>>['revert']
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { ethers } from 'ethers'
|
|
2
2
|
import { ENS } from '..'
|
|
3
3
|
import { hexEncodeName } from '../utils/hexEncodedName'
|
|
4
|
-
import setup from '
|
|
4
|
+
import setup from '../tests/setup'
|
|
5
5
|
|
|
6
6
|
let ENSInstance: ENS
|
|
7
7
|
let revert: Awaited<ReturnType<typeof setup>>['revert']
|
|
@@ -2,7 +2,7 @@ import { BigNumber, ethers } from 'ethers'
|
|
|
2
2
|
import { ENS } from '..'
|
|
3
3
|
import { hexEncodeName } from '../utils/hexEncodedName'
|
|
4
4
|
import { namehash } from '../utils/normalise'
|
|
5
|
-
import setup from '
|
|
5
|
+
import setup from '../tests/setup'
|
|
6
6
|
|
|
7
7
|
let ENSInstance: ENS
|
|
8
8
|
let revert: Awaited<ReturnType<typeof setup>>['revert']
|
package/src/index.ts
CHANGED
|
@@ -41,6 +41,7 @@ import type transferName from './functions/transferName'
|
|
|
41
41
|
import type transferSubname from './functions/transferSubname'
|
|
42
42
|
import type unwrapName from './functions/unwrapName'
|
|
43
43
|
import type wrapName from './functions/wrapName'
|
|
44
|
+
import type getDNSOwner from './functions/getDNSOwner'
|
|
44
45
|
import GqlManager from './GqlManager'
|
|
45
46
|
import singleCall from './utils/singleCall'
|
|
46
47
|
|
|
@@ -194,6 +195,9 @@ export class ENS {
|
|
|
194
195
|
if (subFunc !== 'combine') {
|
|
195
196
|
// get the function to call
|
|
196
197
|
const func = subFunc ? mod[exportName][subFunc] : mod[exportName]
|
|
198
|
+
if(dependencies.length === 0) {
|
|
199
|
+
return func(...args)
|
|
200
|
+
}
|
|
197
201
|
// get the dependencies to forward to the function as the first arg
|
|
198
202
|
const dependenciesToForward =
|
|
199
203
|
thisRef.forwardDependenciesFromArray<F>(dependencies)
|
|
@@ -504,4 +508,9 @@ export class ENS {
|
|
|
504
508
|
'transferSubname',
|
|
505
509
|
['contracts', 'provider'],
|
|
506
510
|
)
|
|
511
|
+
|
|
512
|
+
public getDNSOwner = this.generateFunction<typeof getDNSOwner>(
|
|
513
|
+
'getDNSOwner',
|
|
514
|
+
[],
|
|
515
|
+
)
|
|
507
516
|
}
|