@ensdomains/ensjs 3.0.0-alpha.2 → 3.0.0-alpha.5
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/burnFuses.d.ts +3 -1
- package/dist/cjs/functions/burnFuses.js +1 -5
- package/dist/cjs/functions/createSubname.d.ts +1 -5
- package/dist/cjs/functions/createSubname.js +1 -5
- package/dist/cjs/functions/deleteSubname.d.ts +2 -2
- package/dist/cjs/functions/deleteSubname.js +5 -2
- package/dist/cjs/functions/getDNSOwner.d.ts +7 -0
- package/dist/cjs/functions/getDNSOwner.js +81 -0
- package/dist/cjs/functions/setName.d.ts +3 -2
- package/dist/cjs/functions/setName.js +3 -8
- package/dist/cjs/functions/setRecords.d.ts +4 -1
- package/dist/cjs/functions/setRecords.js +10 -8
- package/dist/cjs/functions/setResolver.d.ts +3 -2
- package/dist/cjs/functions/setResolver.js +3 -9
- package/dist/cjs/functions/transferName.d.ts +3 -2
- package/dist/cjs/functions/transferName.js +5 -10
- package/dist/cjs/functions/transferSubname.d.ts +3 -2
- package/dist/cjs/functions/transferSubname.js +1 -5
- package/dist/cjs/functions/unwrapName.d.ts +3 -2
- package/dist/cjs/functions/unwrapName.js +1 -6
- package/dist/cjs/functions/wrapName.d.ts +4 -2
- package/dist/cjs/functions/wrapName.js +6 -10
- package/dist/cjs/index.d.ts +52 -34
- package/dist/cjs/index.js +36 -22
- package/dist/esm/functions/burnFuses.d.ts +3 -1
- package/dist/esm/functions/burnFuses.js +1 -5
- package/dist/esm/functions/createSubname.d.ts +1 -5
- package/dist/esm/functions/createSubname.js +1 -5
- package/dist/esm/functions/deleteSubname.d.ts +2 -2
- package/dist/esm/functions/deleteSubname.js +5 -2
- package/dist/esm/functions/getDNSOwner.d.ts +7 -0
- package/dist/esm/functions/getDNSOwner.js +51 -0
- package/dist/esm/functions/setName.d.ts +3 -2
- package/dist/esm/functions/setName.js +3 -8
- package/dist/esm/functions/setRecords.d.ts +4 -1
- package/dist/esm/functions/setRecords.js +10 -8
- package/dist/esm/functions/setResolver.d.ts +3 -2
- package/dist/esm/functions/setResolver.js +3 -9
- package/dist/esm/functions/transferName.d.ts +3 -2
- package/dist/esm/functions/transferName.js +5 -10
- package/dist/esm/functions/transferSubname.d.ts +3 -2
- package/dist/esm/functions/transferSubname.js +1 -5
- package/dist/esm/functions/unwrapName.d.ts +3 -2
- package/dist/esm/functions/unwrapName.js +1 -6
- package/dist/esm/functions/wrapName.d.ts +4 -2
- package/dist/esm/functions/wrapName.js +6 -10
- package/dist/esm/index.d.ts +52 -34
- package/dist/esm/index.js +36 -22
- 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 +9 -8
- package/src/functions/burnFuses.ts +6 -8
- package/src/{tests → functions}/createSubname.test.ts +8 -11
- package/src/functions/createSubname.ts +3 -10
- package/src/{tests → functions}/deleteSubname.test.ts +28 -27
- package/src/functions/deleteSubname.ts +9 -12
- 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 +12 -10
- 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 +4 -2
- 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 +3 -2
- package/src/functions/setName.ts +10 -12
- package/src/{tests → functions}/setRecords.test.ts +7 -5
- package/src/functions/setRecords.ts +18 -12
- package/src/{tests → functions}/setResolver.test.ts +12 -15
- package/src/functions/setResolver.ts +10 -18
- package/src/{tests → functions}/transferName.test.ts +27 -29
- package/src/functions/transferName.ts +12 -18
- package/src/{tests → functions}/transferSubname.test.ts +30 -29
- package/src/functions/transferSubname.ts +8 -10
- package/src/{tests → functions}/unwrapName.test.ts +22 -22
- package/src/functions/unwrapName.ts +8 -12
- package/src/{tests → functions}/wrapName.test.ts +15 -12
- package/src/functions/wrapName.ts +16 -15
- package/src/index.ts +85 -29
- package/src/tests/signerInjection.test.ts +42 -0
- package/src/tests/withProvider.test.ts +1 -1
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.5",
|
|
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.2
|
|
54
|
+
"@ensdomains/ens-test-env": "0.1.2",
|
|
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.4"
|
|
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
|
+
import setup from '../tests/setup'
|
|
3
4
|
import { namehash } from '../utils/normalise'
|
|
4
|
-
import setup from './setup'
|
|
5
5
|
|
|
6
6
|
let ENSInstance: ENS
|
|
7
7
|
let revert: Awaited<ReturnType<typeof setup>>['revert']
|
|
@@ -22,16 +22,17 @@ describe('burnFuses', () => {
|
|
|
22
22
|
await revert()
|
|
23
23
|
})
|
|
24
24
|
it('should return a burnFuses transaction and succeed', async () => {
|
|
25
|
-
const wrapNameTx = await ENSInstance.wrapName(
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
)
|
|
25
|
+
const wrapNameTx = await ENSInstance.wrapName('parthtejpal.eth', {
|
|
26
|
+
wrappedOwner: accounts[0],
|
|
27
|
+
})
|
|
29
28
|
await wrapNameTx.wait()
|
|
30
29
|
|
|
31
30
|
const tx = await ENSInstance.burnFuses('parthtejpal.eth', {
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
31
|
+
fusesToBurn: {
|
|
32
|
+
cannotUnwrap: true,
|
|
33
|
+
cannotCreateSubdomain: true,
|
|
34
|
+
cannotSetTtl: true,
|
|
35
|
+
},
|
|
35
36
|
})
|
|
36
37
|
expect(tx).toBeTruthy()
|
|
37
38
|
await tx.wait()
|
|
@@ -4,16 +4,14 @@ import generateFuseInput from '../utils/generateFuseInput'
|
|
|
4
4
|
import { namehash } from '../utils/normalise'
|
|
5
5
|
|
|
6
6
|
export default async function (
|
|
7
|
-
{ contracts,
|
|
7
|
+
{ contracts, signer }: ENSArgs<'contracts' | 'signer'>,
|
|
8
8
|
name: string,
|
|
9
|
-
|
|
9
|
+
{
|
|
10
|
+
fusesToBurn,
|
|
11
|
+
}: {
|
|
12
|
+
fusesToBurn: FuseOptions
|
|
13
|
+
},
|
|
10
14
|
) {
|
|
11
|
-
const signer = provider?.getSigner()
|
|
12
|
-
|
|
13
|
-
if (!signer) {
|
|
14
|
-
throw new Error('No signer found')
|
|
15
|
-
}
|
|
16
|
-
|
|
17
15
|
const nameWrapper = (await contracts?.getNameWrapper()!).connect(signer)
|
|
18
16
|
const hash = namehash(name)
|
|
19
17
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { ethers } from 'ethers'
|
|
2
2
|
import { ENS } from '..'
|
|
3
|
+
import setup from '../tests/setup'
|
|
3
4
|
import { namehash } from '../utils/normalise'
|
|
4
|
-
import setup from './setup'
|
|
5
5
|
|
|
6
6
|
let ENSInstance: ENS
|
|
7
7
|
let revert: Awaited<ReturnType<typeof setup>>['revert']
|
|
@@ -23,11 +23,10 @@ describe('createSubname', () => {
|
|
|
23
23
|
await revert()
|
|
24
24
|
})
|
|
25
25
|
it('should allow creating a subname on the registry', async () => {
|
|
26
|
-
const tx = await ENSInstance.createSubname({
|
|
26
|
+
const tx = await ENSInstance.createSubname('test.parthtejpal.eth', {
|
|
27
27
|
contract: 'registry',
|
|
28
|
-
name: 'test.parthtejpal.eth',
|
|
29
28
|
owner: accounts[0],
|
|
30
|
-
|
|
29
|
+
addressOrIndex: 0,
|
|
31
30
|
})
|
|
32
31
|
expect(tx).toBeTruthy()
|
|
33
32
|
await tx.wait()
|
|
@@ -37,16 +36,14 @@ describe('createSubname', () => {
|
|
|
37
36
|
expect(result).toBe(accounts[0])
|
|
38
37
|
})
|
|
39
38
|
it('should allow creating a subname on the namewrapper', async () => {
|
|
40
|
-
const wrapNameTx = await ENSInstance.wrapName(
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
)
|
|
39
|
+
const wrapNameTx = await ENSInstance.wrapName('parthtejpal.eth', {
|
|
40
|
+
wrappedOwner: accounts[0],
|
|
41
|
+
})
|
|
44
42
|
await wrapNameTx.wait()
|
|
45
|
-
const tx = await ENSInstance.createSubname({
|
|
43
|
+
const tx = await ENSInstance.createSubname('test.parthtejpal.eth', {
|
|
46
44
|
contract: 'nameWrapper',
|
|
47
|
-
name: 'test.parthtejpal.eth',
|
|
48
45
|
owner: accounts[0],
|
|
49
|
-
|
|
46
|
+
addressOrIndex: 0,
|
|
50
47
|
})
|
|
51
48
|
expect(tx).toBeTruthy()
|
|
52
49
|
await tx.wait()
|
|
@@ -5,11 +5,9 @@ import generateFuseInput from '../utils/generateFuseInput'
|
|
|
5
5
|
import { namehash } from '../utils/normalise'
|
|
6
6
|
|
|
7
7
|
type BaseArgs = {
|
|
8
|
-
name: string
|
|
9
8
|
owner: string
|
|
10
9
|
resolverAddress?: string
|
|
11
10
|
contract: 'registry' | 'nameWrapper'
|
|
12
|
-
options?: { addressOrIndex?: string | number }
|
|
13
11
|
}
|
|
14
12
|
|
|
15
13
|
type NameWrapperArgs = {
|
|
@@ -20,15 +18,10 @@ type NameWrapperArgs = {
|
|
|
20
18
|
type Args = BaseArgs | NameWrapperArgs
|
|
21
19
|
|
|
22
20
|
export default async function (
|
|
23
|
-
{ contracts,
|
|
24
|
-
|
|
21
|
+
{ contracts, signer }: ENSArgs<'contracts' | 'signer'>,
|
|
22
|
+
name: string,
|
|
23
|
+
{ owner, resolverAddress, contract, ...wrapperArgs }: Args,
|
|
25
24
|
) {
|
|
26
|
-
const signer = provider?.getSigner(options?.addressOrIndex)
|
|
27
|
-
|
|
28
|
-
if (!signer) {
|
|
29
|
-
throw new Error('No signer found')
|
|
30
|
-
}
|
|
31
|
-
|
|
32
25
|
const labels = name.split('.')
|
|
33
26
|
|
|
34
27
|
if (labels.length === 1) {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { ethers } from 'ethers'
|
|
2
2
|
import { ENS } from '..'
|
|
3
|
+
import setup from '../tests/setup'
|
|
3
4
|
import { namehash } from '../utils/normalise'
|
|
4
|
-
import setup from './setup'
|
|
5
5
|
|
|
6
6
|
let ENSInstance: ENS
|
|
7
7
|
let revert: Awaited<ReturnType<typeof setup>>['revert']
|
|
@@ -22,19 +22,20 @@ describe('deleteSubname', () => {
|
|
|
22
22
|
await revert()
|
|
23
23
|
})
|
|
24
24
|
it('should allow deleting a subname on the registry', async () => {
|
|
25
|
-
const createSubnameTx = await ENSInstance.createSubname(
|
|
26
|
-
contract: 'registry',
|
|
27
|
-
name: 'test.parthtejpal.eth',
|
|
28
|
-
owner: accounts[0],
|
|
29
|
-
options: { addressOrIndex: 0 },
|
|
30
|
-
})
|
|
31
|
-
await createSubnameTx.wait()
|
|
32
|
-
|
|
33
|
-
const tx = await ENSInstance.deleteSubname(
|
|
25
|
+
const createSubnameTx = await ENSInstance.createSubname(
|
|
34
26
|
'test.parthtejpal.eth',
|
|
35
|
-
|
|
36
|
-
|
|
27
|
+
{
|
|
28
|
+
contract: 'registry',
|
|
29
|
+
owner: accounts[0],
|
|
30
|
+
addressOrIndex: 0,
|
|
31
|
+
},
|
|
37
32
|
)
|
|
33
|
+
await createSubnameTx.wait()
|
|
34
|
+
|
|
35
|
+
const tx = await ENSInstance.deleteSubname('test.parthtejpal.eth', {
|
|
36
|
+
contract: 'registry',
|
|
37
|
+
addressOrIndex: 0,
|
|
38
|
+
})
|
|
38
39
|
expect(tx).toBeTruthy()
|
|
39
40
|
await tx.wait()
|
|
40
41
|
|
|
@@ -43,24 +44,24 @@ describe('deleteSubname', () => {
|
|
|
43
44
|
expect(result).toBe('0x0000000000000000000000000000000000000000')
|
|
44
45
|
})
|
|
45
46
|
it('should allow deleting a subname on the nameWrapper', async () => {
|
|
46
|
-
const wrapNameTx = await ENSInstance.wrapName(
|
|
47
|
-
|
|
48
|
-
accounts[0],
|
|
49
|
-
)
|
|
50
|
-
await wrapNameTx.wait()
|
|
51
|
-
const createSubnameTx = await ENSInstance.createSubname({
|
|
52
|
-
contract: 'nameWrapper',
|
|
53
|
-
name: 'test.parthtejpal.eth',
|
|
54
|
-
owner: accounts[0],
|
|
55
|
-
options: { addressOrIndex: 0 },
|
|
47
|
+
const wrapNameTx = await ENSInstance.wrapName('parthtejpal.eth', {
|
|
48
|
+
wrappedOwner: accounts[0],
|
|
56
49
|
})
|
|
57
|
-
await
|
|
58
|
-
|
|
59
|
-
const tx = await ENSInstance.deleteSubname(
|
|
50
|
+
await wrapNameTx.wait()
|
|
51
|
+
const createSubnameTx = await ENSInstance.createSubname(
|
|
60
52
|
'test.parthtejpal.eth',
|
|
61
|
-
|
|
62
|
-
|
|
53
|
+
{
|
|
54
|
+
contract: 'nameWrapper',
|
|
55
|
+
owner: accounts[0],
|
|
56
|
+
addressOrIndex: 0,
|
|
57
|
+
},
|
|
63
58
|
)
|
|
59
|
+
await createSubnameTx.wait()
|
|
60
|
+
|
|
61
|
+
const tx = await ENSInstance.deleteSubname('test.parthtejpal.eth', {
|
|
62
|
+
contract: 'nameWrapper',
|
|
63
|
+
addressOrIndex: 0,
|
|
64
|
+
})
|
|
64
65
|
expect(tx).toBeTruthy()
|
|
65
66
|
await tx.wait()
|
|
66
67
|
|
|
@@ -1,19 +1,16 @@
|
|
|
1
1
|
import { ENSArgs } from '..'
|
|
2
2
|
|
|
3
3
|
export default async function (
|
|
4
|
-
{
|
|
5
|
-
contracts,
|
|
6
|
-
provider,
|
|
7
|
-
transferSubname,
|
|
8
|
-
}: ENSArgs<'contracts' | 'provider' | 'transferSubname'>,
|
|
4
|
+
{ transferSubname }: ENSArgs<'transferSubname'>,
|
|
9
5
|
name: string,
|
|
10
|
-
|
|
11
|
-
|
|
6
|
+
{
|
|
7
|
+
contract,
|
|
8
|
+
}: {
|
|
9
|
+
contract: 'registry' | 'nameWrapper'
|
|
10
|
+
},
|
|
12
11
|
) {
|
|
13
|
-
return transferSubname(
|
|
14
|
-
name,
|
|
12
|
+
return transferSubname(name, {
|
|
15
13
|
contract,
|
|
16
|
-
'0x0000000000000000000000000000000000000000',
|
|
17
|
-
|
|
18
|
-
)
|
|
14
|
+
address: '0x0000000000000000000000000000000000000000',
|
|
15
|
+
})
|
|
19
16
|
}
|
|
@@ -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 (_: any, 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
|
+
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { ethers } from 'ethers'
|
|
2
2
|
import { ENS } from '..'
|
|
3
|
-
import setup from '
|
|
3
|
+
import setup from '../tests/setup'
|
|
4
4
|
|
|
5
5
|
let ENSInstance: ENS
|
|
6
6
|
let revert: Awaited<ReturnType<typeof setup>>['revert']
|
|
@@ -12,7 +12,9 @@ let withWrappedSnapshot: any
|
|
|
12
12
|
beforeAll(async () => {
|
|
13
13
|
;({ ENSInstance, revert, provider, createSnapshot } = await setup())
|
|
14
14
|
accounts = await provider.listAccounts()
|
|
15
|
-
const tx = await ENSInstance.wrapName('parthtejpal.eth',
|
|
15
|
+
const tx = await ENSInstance.wrapName('parthtejpal.eth', {
|
|
16
|
+
wrappedOwner: accounts[0],
|
|
17
|
+
})
|
|
16
18
|
await tx.wait()
|
|
17
19
|
|
|
18
20
|
withWrappedSnapshot = await createSnapshot()
|
|
@@ -33,11 +35,10 @@ describe('getFuses', () => {
|
|
|
33
35
|
expect(result).toBeUndefined()
|
|
34
36
|
})
|
|
35
37
|
it('should return with canDoEverything set to true for a name with no fuses burned', async () => {
|
|
36
|
-
const tx = await ENSInstance.createSubname({
|
|
38
|
+
const tx = await ENSInstance.createSubname('test.parthtejpal.eth', {
|
|
37
39
|
contract: 'nameWrapper',
|
|
38
|
-
name: 'test.parthtejpal.eth',
|
|
39
40
|
owner: accounts[0],
|
|
40
|
-
|
|
41
|
+
addressOrIndex: 0,
|
|
41
42
|
})
|
|
42
43
|
await tx.wait()
|
|
43
44
|
|
|
@@ -56,9 +57,11 @@ describe('getFuses', () => {
|
|
|
56
57
|
})
|
|
57
58
|
it('should return with other correct fuses', async () => {
|
|
58
59
|
const tx = await ENSInstance.burnFuses('parthtejpal.eth', {
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
60
|
+
fusesToBurn: {
|
|
61
|
+
cannotUnwrap: true,
|
|
62
|
+
cannotSetTtl: true,
|
|
63
|
+
cannotCreateSubdomain: true,
|
|
64
|
+
},
|
|
62
65
|
})
|
|
63
66
|
await tx.wait()
|
|
64
67
|
const result = await ENSInstance.getFuses('parthtejpal.eth')
|
|
@@ -86,8 +89,7 @@ describe('getFuses', () => {
|
|
|
86
89
|
}
|
|
87
90
|
})
|
|
88
91
|
it('should return correct vulnerability data for a vulnerable node', async () => {
|
|
89
|
-
const tx = await ENSInstance.createSubname({
|
|
90
|
-
name: 'test.parthtejpal.eth',
|
|
92
|
+
const tx = await ENSInstance.createSubname('test.parthtejpal.eth', {
|
|
91
93
|
owner: accounts[0],
|
|
92
94
|
contract: 'nameWrapper',
|
|
93
95
|
})
|