@ensdomains/ensjs 3.0.0-alpha.62 → 3.0.0-alpha.64
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/README.md +0 -16
- package/dist/cjs/GqlManager.js +4 -0
- package/dist/cjs/functions/batch.js +23 -1
- package/dist/cjs/functions/getHistory.js +11 -9
- package/dist/cjs/functions/getNames.js +10 -2
- package/dist/cjs/functions/getOwner.js +64 -17
- package/dist/cjs/functions/getProfile.js +66 -26
- package/dist/cjs/functions/getSubnames.js +11 -2
- package/dist/cjs/functions/supportsTLD.js +1 -1
- package/dist/cjs/utils/errors.js +67 -0
- package/dist/esm/GqlManager.mjs +4 -0
- package/dist/esm/functions/batch.mjs +23 -1
- package/dist/esm/functions/getHistory.mjs +14 -9
- package/dist/esm/functions/getNames.mjs +14 -2
- package/dist/esm/functions/getOwner.mjs +68 -17
- package/dist/esm/functions/getProfile.mjs +70 -26
- package/dist/esm/functions/getSubnames.mjs +15 -2
- package/dist/esm/functions/supportsTLD.mjs +1 -1
- package/dist/esm/utils/errors.mjs +49 -0
- package/dist/types/functions/getHistory.d.ts +19 -0
- package/dist/types/functions/getOwner.d.ts +7 -3
- package/dist/types/functions/getProfile.d.ts +1 -0
- package/dist/types/functions/getSubnames.d.ts +5 -4
- package/dist/types/index.d.ts +9 -7
- package/dist/types/utils/errors.d.ts +14 -0
- package/package.json +1 -1
- package/src/GqlManager.test.ts +17 -0
- package/src/GqlManager.ts +7 -0
- package/src/functions/batch.test.ts +41 -0
- package/src/functions/batch.ts +31 -1
- package/src/functions/getHistory.test.ts +25 -0
- package/src/functions/getHistory.ts +28 -11
- package/src/functions/getNames.test.ts +28 -0
- package/src/functions/getNames.ts +19 -2
- package/src/functions/getOwner.test.ts +161 -2
- package/src/functions/getOwner.ts +90 -18
- package/src/functions/getProfile.test.ts +129 -2
- package/src/functions/getProfile.ts +89 -32
- package/src/functions/getSubnames.test.ts +35 -0
- package/src/functions/getSubnames.ts +25 -3
- package/src/functions/supportsTLD.ts +1 -1
- package/src/utils/errors.ts +68 -0
package/dist/types/index.d.ts
CHANGED
|
@@ -155,6 +155,7 @@ export declare class ENS {
|
|
|
155
155
|
texts?: string[] | undefined;
|
|
156
156
|
coinTypes?: string[] | undefined;
|
|
157
157
|
} | undefined;
|
|
158
|
+
skipGraph?: boolean | undefined;
|
|
158
159
|
}) | undefined) => Promise<{
|
|
159
160
|
isMigrated: boolean | null;
|
|
160
161
|
createdAt: string | null;
|
|
@@ -392,16 +393,17 @@ export declare class ENS {
|
|
|
392
393
|
} | undefined>;
|
|
393
394
|
}>;
|
|
394
395
|
getOwner: GeneratedRawFunction<{
|
|
395
|
-
raw: ({ contracts, multicallWrapper }: ENSArgs<"contracts" | "multicallWrapper">, name: string,
|
|
396
|
+
raw: ({ contracts, multicallWrapper }: ENSArgs<"contracts" | "multicallWrapper">, name: string, options?: {
|
|
397
|
+
contract?: "nameWrapper" | "registrar" | "registry" | undefined;
|
|
398
|
+
skipGraph?: boolean | undefined;
|
|
399
|
+
}) => Promise<{
|
|
396
400
|
to: string;
|
|
397
401
|
data: string;
|
|
398
402
|
}>;
|
|
399
|
-
decode: ({ contracts, multicallWrapper, gqlInstance, }: ENSArgs<"contracts" | "gqlInstance" | "multicallWrapper">, data: string, name: string,
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
expired?: boolean | undefined;
|
|
404
|
-
} | undefined>;
|
|
403
|
+
decode: ({ contracts, multicallWrapper, gqlInstance, }: ENSArgs<"contracts" | "gqlInstance" | "multicallWrapper">, data: string, name: string, options?: {
|
|
404
|
+
contract?: "nameWrapper" | "registrar" | "registry" | undefined;
|
|
405
|
+
skipGraph?: boolean | undefined;
|
|
406
|
+
}) => Promise<import("./functions/getOwner").Owner | undefined>;
|
|
405
407
|
}>;
|
|
406
408
|
getExpiry: GeneratedRawFunction<{
|
|
407
409
|
raw: (ensArgs: ENSArgs<"contracts" | "multicallWrapper">, name: string, { contract }?: {
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { GraphQLError } from 'graphql';
|
|
2
|
+
export declare type ENSJSErrorName = 'ENSJSSubgraphError';
|
|
3
|
+
export declare class ENSJSError<T> extends Error {
|
|
4
|
+
name: string;
|
|
5
|
+
errors?: GraphQLError[];
|
|
6
|
+
data?: T;
|
|
7
|
+
constructor({ data, errors }: {
|
|
8
|
+
data?: T;
|
|
9
|
+
errors?: GraphQLError[];
|
|
10
|
+
});
|
|
11
|
+
}
|
|
12
|
+
export declare const getClientErrors: (e: unknown) => GraphQLError[];
|
|
13
|
+
export declare const debugSubgraphError: (request: any) => void;
|
|
14
|
+
export declare const debugSubgraphLatency: () => Promise<void> | undefined;
|
package/package.json
CHANGED
package/src/GqlManager.test.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { parse, print, visit } from 'graphql'
|
|
2
2
|
import traverse from 'traverse'
|
|
3
|
+
import { ClientError } from 'graphql-request'
|
|
3
4
|
|
|
4
5
|
import { requestMiddleware, responseMiddleware } from './GqlManager'
|
|
5
6
|
import { namehash } from './utils/normalise'
|
|
@@ -170,4 +171,20 @@ query getNames($id: ID!, $expiryDate: Int) {
|
|
|
170
171
|
)
|
|
171
172
|
})
|
|
172
173
|
})
|
|
174
|
+
|
|
175
|
+
describe('errors', () => {
|
|
176
|
+
beforeAll(() => {
|
|
177
|
+
process.env.NEXT_PUBLIC_ENSJS_DEBUG = 'on'
|
|
178
|
+
localStorage.setItem('ensjs-debug', 'ENSJSSubgraphError')
|
|
179
|
+
})
|
|
180
|
+
|
|
181
|
+
afterAll(() => {
|
|
182
|
+
process.env.NEXT_PUBLIC_ENSJS_DEBUG = ''
|
|
183
|
+
localStorage.removeItem('ensjs-debug')
|
|
184
|
+
})
|
|
185
|
+
|
|
186
|
+
it('should throw error when reqest middleware is run', async () => {
|
|
187
|
+
expect(requestMiddleware(visit, parse, print)).toThrow(ClientError)
|
|
188
|
+
})
|
|
189
|
+
})
|
|
173
190
|
})
|
package/src/GqlManager.ts
CHANGED
|
@@ -7,6 +7,7 @@ import type {
|
|
|
7
7
|
} from 'graphql'
|
|
8
8
|
import type { gql, GraphQLClient } from 'graphql-request'
|
|
9
9
|
import type Traverse from 'traverse'
|
|
10
|
+
import { debugSubgraphError } from './utils/errors'
|
|
10
11
|
import { namehash } from './utils/normalise'
|
|
11
12
|
|
|
12
13
|
const generateSelection = (selection: any) => ({
|
|
@@ -42,6 +43,9 @@ export const enter = (node: SelectionSetNode) => {
|
|
|
42
43
|
export const requestMiddleware =
|
|
43
44
|
(visit: typeof Visit, parse: typeof Parse, print: typeof Print) =>
|
|
44
45
|
(request: any) => {
|
|
46
|
+
// Debug here because response middleware will resolve any error thrown
|
|
47
|
+
debugSubgraphError(request)
|
|
48
|
+
|
|
45
49
|
const requestBody = JSON.parse(request.body)
|
|
46
50
|
const rawQuery = requestBody.query
|
|
47
51
|
const parsedQuery = parse(rawQuery)
|
|
@@ -60,6 +64,9 @@ export const requestMiddleware =
|
|
|
60
64
|
|
|
61
65
|
export const responseMiddleware =
|
|
62
66
|
(traverse: typeof Traverse) => (response: any) => {
|
|
67
|
+
// If response is of type error, we do not need to further process it
|
|
68
|
+
if (response instanceof Error) return response
|
|
69
|
+
|
|
63
70
|
// eslint-disable-next-line func-names
|
|
64
71
|
traverse(response).forEach(function (responseItem: any) {
|
|
65
72
|
if (responseItem instanceof Object && responseItem.name) {
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { ENS } from '..'
|
|
2
2
|
import setup from '../tests/setup'
|
|
3
|
+
import { ENSJSError } from '../utils/errors'
|
|
3
4
|
|
|
4
5
|
let ensInstance: ENS
|
|
5
6
|
|
|
@@ -33,4 +34,44 @@ describe('batch', () => {
|
|
|
33
34
|
expect(result[0]).toBe('Hello2')
|
|
34
35
|
}
|
|
35
36
|
})
|
|
37
|
+
|
|
38
|
+
describe('errors', () => {
|
|
39
|
+
beforeAll(() => {
|
|
40
|
+
process.env.NEXT_PUBLIC_ENSJS_DEBUG = 'on'
|
|
41
|
+
localStorage.setItem('ensjs-debug', 'ENSJSSubgraphError')
|
|
42
|
+
})
|
|
43
|
+
|
|
44
|
+
afterAll(() => {
|
|
45
|
+
process.env.NEXT_PUBLIC_ENSJS_DEBUG = ''
|
|
46
|
+
localStorage.removeItem('ensjs-debug')
|
|
47
|
+
})
|
|
48
|
+
|
|
49
|
+
it('should throw a single error if there is an indexing error', async () => {
|
|
50
|
+
try {
|
|
51
|
+
await ensInstance.batch(
|
|
52
|
+
ensInstance.getText.batch('with-profile.eth', 'description'),
|
|
53
|
+
ensInstance.getOwner.batch('expired.eth', { skipGraph: false }),
|
|
54
|
+
ensInstance.getName.batch(
|
|
55
|
+
'0x3C44CdDdB6a900fa2b585dd299e03d12FA4293BC',
|
|
56
|
+
),
|
|
57
|
+
)
|
|
58
|
+
expect(true).toBe(false)
|
|
59
|
+
} catch (e) {
|
|
60
|
+
expect(e).toBeInstanceOf(ENSJSError)
|
|
61
|
+
const error = e as ENSJSError<any[]>
|
|
62
|
+
expect(error.name).toBe('ENSJSSubgraphError')
|
|
63
|
+
const result = error.data as any[]
|
|
64
|
+
expect(result[0]).toBe('Hello2')
|
|
65
|
+
expect(result[1]).toEqual({
|
|
66
|
+
expired: true,
|
|
67
|
+
owner: '0x70997970C51812dc3A010C7d01b50e0d17dc79C8',
|
|
68
|
+
ownershipLevel: 'registrar',
|
|
69
|
+
})
|
|
70
|
+
expect(result[2]).toMatchObject({
|
|
71
|
+
name: 'with-profile.eth',
|
|
72
|
+
match: true,
|
|
73
|
+
})
|
|
74
|
+
}
|
|
75
|
+
})
|
|
76
|
+
})
|
|
36
77
|
})
|
package/src/functions/batch.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { TransactionRequest } from '@ethersproject/abstract-provider'
|
|
2
2
|
import { BatchFunctionResult, ENSArgs, RawFunction } from '..'
|
|
3
|
+
import { ENSJSError } from '../utils/errors'
|
|
3
4
|
|
|
4
5
|
const raw = async (
|
|
5
6
|
{ multicallWrapper }: ENSArgs<'multicallWrapper'>,
|
|
@@ -26,7 +27,7 @@ const decode = async (
|
|
|
26
27
|
const response = await multicallWrapper.decode(data, passthrough)
|
|
27
28
|
if (!response) return
|
|
28
29
|
|
|
29
|
-
|
|
30
|
+
const results = await Promise.allSettled(
|
|
30
31
|
response.map((ret: any, i: number) => {
|
|
31
32
|
if (passthrough[i].passthrough) {
|
|
32
33
|
return items[i].decode(
|
|
@@ -38,6 +39,35 @@ const decode = async (
|
|
|
38
39
|
return items[i].decode(ret.returnData, ...items[i].args)
|
|
39
40
|
}),
|
|
40
41
|
)
|
|
42
|
+
|
|
43
|
+
const reducedResults = results.reduce<{
|
|
44
|
+
errors: any[]
|
|
45
|
+
data: any[]
|
|
46
|
+
}>(
|
|
47
|
+
(acc, result) => {
|
|
48
|
+
if (result.status === 'fulfilled') {
|
|
49
|
+
return { ...acc, data: [...acc.data, result.value] }
|
|
50
|
+
}
|
|
51
|
+
const error =
|
|
52
|
+
result.reason instanceof ENSJSError
|
|
53
|
+
? (result.reason as ENSJSError<any>)
|
|
54
|
+
: undefined
|
|
55
|
+
const itemData = error?.data
|
|
56
|
+
const itemErrors = error?.errors || [{ message: 'unknown_error' }]
|
|
57
|
+
return {
|
|
58
|
+
errors: [...acc.errors, ...itemErrors],
|
|
59
|
+
data: [...acc.data, itemData],
|
|
60
|
+
}
|
|
61
|
+
},
|
|
62
|
+
{ data: [], errors: [] },
|
|
63
|
+
)
|
|
64
|
+
|
|
65
|
+
if (reducedResults.errors.length)
|
|
66
|
+
throw new ENSJSError({
|
|
67
|
+
data: reducedResults.data,
|
|
68
|
+
errors: reducedResults.errors,
|
|
69
|
+
})
|
|
70
|
+
return reducedResults.data
|
|
41
71
|
}
|
|
42
72
|
|
|
43
73
|
export default {
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { ENS } from '..'
|
|
2
2
|
import setup from '../tests/setup'
|
|
3
|
+
import { ENSJSError } from '../utils/errors'
|
|
4
|
+
import { ReturnData } from './getHistory'
|
|
3
5
|
|
|
4
6
|
let ensInstance: ENS
|
|
5
7
|
let revert: Awaited<ReturnType<typeof setup>>['revert']
|
|
@@ -46,4 +48,27 @@ describe('getHistory', () => {
|
|
|
46
48
|
expect(result).not.toHaveProperty('registration')
|
|
47
49
|
}
|
|
48
50
|
})
|
|
51
|
+
|
|
52
|
+
describe('errors', () => {
|
|
53
|
+
beforeAll(() => {
|
|
54
|
+
process.env.NEXT_PUBLIC_ENSJS_DEBUG = 'on'
|
|
55
|
+
localStorage.setItem('ensjs-debug', 'ENSJSSubgraphError')
|
|
56
|
+
})
|
|
57
|
+
|
|
58
|
+
afterAll(() => {
|
|
59
|
+
process.env.NEXT_PUBLIC_ENSJS_DEBUG = ''
|
|
60
|
+
localStorage.removeItem('ensjs-debug')
|
|
61
|
+
})
|
|
62
|
+
|
|
63
|
+
it('should throw an error with no data', async () => {
|
|
64
|
+
try {
|
|
65
|
+
await ensInstance.getHistory('with-profile.eth')
|
|
66
|
+
expect(true).toBeFalsy()
|
|
67
|
+
} catch (e) {
|
|
68
|
+
expect(e).toBeInstanceOf(ENSJSError)
|
|
69
|
+
const error = e as ENSJSError<ReturnData>
|
|
70
|
+
expect(error.data).toBeUndefined()
|
|
71
|
+
}
|
|
72
|
+
})
|
|
73
|
+
})
|
|
49
74
|
})
|
|
@@ -2,6 +2,11 @@ import { formatsByCoinType } from '@ensdomains/address-encoder'
|
|
|
2
2
|
import { hexStripZeros } from '@ethersproject/bytes'
|
|
3
3
|
import { ENSArgs } from '..'
|
|
4
4
|
import { decodeContenthash } from '../utils/contentHash'
|
|
5
|
+
import {
|
|
6
|
+
debugSubgraphLatency,
|
|
7
|
+
ENSJSError,
|
|
8
|
+
getClientErrors,
|
|
9
|
+
} from '../utils/errors'
|
|
5
10
|
import { namehash } from '../utils/normalise'
|
|
6
11
|
import {
|
|
7
12
|
AbiChanged,
|
|
@@ -148,6 +153,14 @@ const mapEvents = <T extends EventTypes>(eventArray: any[], type: T) =>
|
|
|
148
153
|
}),
|
|
149
154
|
)
|
|
150
155
|
|
|
156
|
+
type MappedEvents = ReturnType<typeof mapEvents>
|
|
157
|
+
|
|
158
|
+
export type ReturnData = {
|
|
159
|
+
domain: MappedEvents
|
|
160
|
+
registration?: MappedEvents
|
|
161
|
+
resolver: MappedEvents
|
|
162
|
+
}
|
|
163
|
+
|
|
151
164
|
export async function getHistory(
|
|
152
165
|
{ gqlInstance }: ENSArgs<'gqlInstance'>,
|
|
153
166
|
name: string,
|
|
@@ -279,17 +292,23 @@ export async function getHistory(
|
|
|
279
292
|
const labels = name.split('.')
|
|
280
293
|
const is2ldEth = checkIsDotEth(labels)
|
|
281
294
|
|
|
282
|
-
const response = await client
|
|
283
|
-
|
|
284
|
-
|
|
295
|
+
const response = await client
|
|
296
|
+
.request(query, {
|
|
297
|
+
namehash: nameHash,
|
|
298
|
+
})
|
|
299
|
+
.catch((e: unknown) => {
|
|
300
|
+
throw new ENSJSError({
|
|
301
|
+
errors: getClientErrors(e),
|
|
302
|
+
})
|
|
303
|
+
})
|
|
304
|
+
.finally(debugSubgraphLatency)
|
|
305
|
+
|
|
285
306
|
const domain = response?.domain
|
|
286
307
|
|
|
287
|
-
if (!domain) return
|
|
308
|
+
if (!domain) return undefined
|
|
288
309
|
|
|
289
|
-
const
|
|
290
|
-
|
|
291
|
-
resolver: { events: resolverEvents },
|
|
292
|
-
} = domain
|
|
310
|
+
const domainEvents = domain.events || []
|
|
311
|
+
const resolverEvents = domain.resolver?.events || []
|
|
293
312
|
|
|
294
313
|
const domainHistory = mapEvents(domainEvents, 'Domain')
|
|
295
314
|
const resolverHistory = mapEvents(
|
|
@@ -301,9 +320,7 @@ export async function getHistory(
|
|
|
301
320
|
)
|
|
302
321
|
|
|
303
322
|
if (is2ldEth) {
|
|
304
|
-
const
|
|
305
|
-
registration: { events: registrationEvents },
|
|
306
|
-
} = domain
|
|
323
|
+
const registrationEvents = domain.registration?.events || []
|
|
307
324
|
const registrationHistory = mapEvents(registrationEvents, 'Registration')
|
|
308
325
|
return {
|
|
309
326
|
domain: domainHistory,
|
|
@@ -4,6 +4,7 @@ import { ENS } from '..'
|
|
|
4
4
|
import setup from '../tests/setup'
|
|
5
5
|
import { Name } from './getNames'
|
|
6
6
|
import { names as wrappedNames } from '../../deploy/00_register_wrapped'
|
|
7
|
+
import { ENSJSError } from '../utils/errors'
|
|
7
8
|
|
|
8
9
|
let ensInstance: ENS
|
|
9
10
|
let provider: ethers.providers.JsonRpcProvider
|
|
@@ -390,4 +391,31 @@ describe('getNames', () => {
|
|
|
390
391
|
})
|
|
391
392
|
})
|
|
392
393
|
})
|
|
394
|
+
|
|
395
|
+
describe('error', () => {
|
|
396
|
+
beforeAll(() => {
|
|
397
|
+
process.env.NEXT_PUBLIC_ENSJS_DEBUG = 'on'
|
|
398
|
+
localStorage.setItem('ensjs-debug', 'ENSJSSubgraphError')
|
|
399
|
+
})
|
|
400
|
+
|
|
401
|
+
afterAll(() => {
|
|
402
|
+
process.env.NEXT_PUBLIC_ENSJS_DEBUG = ''
|
|
403
|
+
localStorage.removeItem('ensjs-debug')
|
|
404
|
+
})
|
|
405
|
+
|
|
406
|
+
it('should throw an ENSJSError for type "all"', async () => {
|
|
407
|
+
try {
|
|
408
|
+
await ensInstance.getNames({
|
|
409
|
+
address: '0x3C44CdDdB6a900fa2b585dd299e03d12FA4293BC',
|
|
410
|
+
type: 'all',
|
|
411
|
+
})
|
|
412
|
+
expect(true).toBeFalsy()
|
|
413
|
+
} catch (e) {
|
|
414
|
+
expect(e).toBeInstanceOf(ENSJSError)
|
|
415
|
+
const error = e as ENSJSError<Name[]>
|
|
416
|
+
expect(error.name).toBe('ENSJSSubgraphError')
|
|
417
|
+
expect(error.data?.length).toBe(0)
|
|
418
|
+
}
|
|
419
|
+
})
|
|
420
|
+
})
|
|
393
421
|
})
|
|
@@ -1,4 +1,9 @@
|
|
|
1
1
|
import { ENSArgs } from '..'
|
|
2
|
+
import {
|
|
3
|
+
getClientErrors,
|
|
4
|
+
ENSJSError,
|
|
5
|
+
debugSubgraphLatency,
|
|
6
|
+
} from '../utils/errors'
|
|
2
7
|
import { truncateFormat } from '../utils/format'
|
|
3
8
|
import { AllCurrentFuses, checkPCCBurned, decodeFuses } from '../utils/fuses'
|
|
4
9
|
import { decryptName } from '../utils/labels'
|
|
@@ -466,10 +471,20 @@ const getNames = async (
|
|
|
466
471
|
}
|
|
467
472
|
}
|
|
468
473
|
|
|
469
|
-
const response = await client
|
|
474
|
+
const response = await client
|
|
475
|
+
.request(finalQuery, queryVars)
|
|
476
|
+
.catch((e: unknown) => {
|
|
477
|
+
console.error(e)
|
|
478
|
+
throw new ENSJSError({
|
|
479
|
+
errors: getClientErrors(e),
|
|
480
|
+
data: [],
|
|
481
|
+
})
|
|
482
|
+
})
|
|
483
|
+
.finally(debugSubgraphLatency)
|
|
470
484
|
const account = response?.account
|
|
485
|
+
|
|
471
486
|
if (type === 'all') {
|
|
472
|
-
|
|
487
|
+
const data = [
|
|
473
488
|
...(account?.domains.map(mapDomain) || []),
|
|
474
489
|
...(account?.registrations.map(mapRegistration) || []),
|
|
475
490
|
...(account?.wrappedDomains.map(mapWrappedDomain).filter((d: any) => d) ||
|
|
@@ -486,6 +501,7 @@ const getNames = async (
|
|
|
486
501
|
}
|
|
487
502
|
return a.createdAt.getTime() - b.createdAt.getTime()
|
|
488
503
|
}) as Name[]
|
|
504
|
+
return data
|
|
489
505
|
}
|
|
490
506
|
if (type === 'resolvedAddress') {
|
|
491
507
|
return (response?.domains.map(mapResolvedAddress).filter((d: any) => d) ||
|
|
@@ -499,6 +515,7 @@ const getNames = async (
|
|
|
499
515
|
.map(mapWrappedDomain)
|
|
500
516
|
.filter((d: any) => d) || []) as Name[]
|
|
501
517
|
}
|
|
518
|
+
|
|
502
519
|
return (account?.registrations.map(mapRegistration) || []) as Name[]
|
|
503
520
|
}
|
|
504
521
|
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { JsonRpcProvider } from '@ethersproject/providers'
|
|
2
2
|
import { ENS } from '..'
|
|
3
3
|
import setup from '../tests/setup'
|
|
4
|
+
import { ENSJSError } from '../utils/errors'
|
|
5
|
+
import { Owner } from './getOwner'
|
|
4
6
|
|
|
5
7
|
let ensInstance: ENS
|
|
6
8
|
let revert: Awaited<ReturnType<typeof setup>>['revert']
|
|
@@ -17,6 +19,13 @@ afterAll(async () => {
|
|
|
17
19
|
})
|
|
18
20
|
|
|
19
21
|
describe('getOwner', () => {
|
|
22
|
+
it('should return undefined for an nonexistent .eth name', async () => {
|
|
23
|
+
const result = await ensInstance.getOwner('nonexistent.eth', {
|
|
24
|
+
skipGraph: false,
|
|
25
|
+
})
|
|
26
|
+
expect(result).toBeUndefined()
|
|
27
|
+
})
|
|
28
|
+
|
|
20
29
|
it('should return correct ownership level and values for a wrapped .eth name', async () => {
|
|
21
30
|
const result = await ensInstance.getOwner('wrapped.eth')
|
|
22
31
|
expect(result).toEqual({
|
|
@@ -26,7 +35,9 @@ describe('getOwner', () => {
|
|
|
26
35
|
})
|
|
27
36
|
})
|
|
28
37
|
it('should return correct ownership level and values for an expired wrapped .eth name', async () => {
|
|
29
|
-
const result = await ensInstance.getOwner('expired-wrapped.eth'
|
|
38
|
+
const result = await ensInstance.getOwner('expired-wrapped.eth', {
|
|
39
|
+
skipGraph: false,
|
|
40
|
+
})
|
|
30
41
|
expect(result).toEqual({
|
|
31
42
|
ownershipLevel: 'nameWrapper',
|
|
32
43
|
owner: '0x0000000000000000000000000000000000000000',
|
|
@@ -43,7 +54,9 @@ describe('getOwner', () => {
|
|
|
43
54
|
})
|
|
44
55
|
})
|
|
45
56
|
it('should return correct ownership level and values for an expired unwrapped .eth name', async () => {
|
|
46
|
-
const result = await ensInstance.getOwner('expired.eth'
|
|
57
|
+
const result = await ensInstance.getOwner('expired.eth', {
|
|
58
|
+
skipGraph: false,
|
|
59
|
+
})
|
|
47
60
|
expect(result).toEqual({
|
|
48
61
|
ownershipLevel: 'registrar',
|
|
49
62
|
owner: accounts[1],
|
|
@@ -51,6 +64,7 @@ describe('getOwner', () => {
|
|
|
51
64
|
expired: true,
|
|
52
65
|
})
|
|
53
66
|
})
|
|
67
|
+
|
|
54
68
|
describe('subname', () => {
|
|
55
69
|
it('should return correct ownership level and values for a unwrapped name', async () => {
|
|
56
70
|
const result = await ensInstance.getOwner('test.with-subnames.eth')
|
|
@@ -68,6 +82,7 @@ describe('getOwner', () => {
|
|
|
68
82
|
owner: accounts[2],
|
|
69
83
|
})
|
|
70
84
|
})
|
|
85
|
+
|
|
71
86
|
it('should return correct ownership level and values for an expired wrapped name', async () => {
|
|
72
87
|
const result = await ensInstance.getOwner('test.expired-wrapped.eth')
|
|
73
88
|
expect(result).toEqual({
|
|
@@ -76,4 +91,148 @@ describe('getOwner', () => {
|
|
|
76
91
|
})
|
|
77
92
|
})
|
|
78
93
|
})
|
|
94
|
+
|
|
95
|
+
// Only 2LDEth names need to be tested
|
|
96
|
+
describe('skipGraph', () => {
|
|
97
|
+
it('should return undefined for an nonexistent .eth name', async () => {
|
|
98
|
+
const result = await ensInstance.getOwner('nonexistent.eth', {
|
|
99
|
+
skipGraph: true,
|
|
100
|
+
})
|
|
101
|
+
expect(result).toBeUndefined()
|
|
102
|
+
})
|
|
103
|
+
|
|
104
|
+
it('should return correct ownership level and values for a wrapped .eth name', async () => {
|
|
105
|
+
const result = await ensInstance.getOwner('wrapped.eth', {
|
|
106
|
+
skipGraph: true,
|
|
107
|
+
})
|
|
108
|
+
expect(result).toEqual({
|
|
109
|
+
ownershipLevel: 'nameWrapper',
|
|
110
|
+
owner: accounts[1],
|
|
111
|
+
expired: false,
|
|
112
|
+
})
|
|
113
|
+
})
|
|
114
|
+
|
|
115
|
+
it('should return correct ownership level and values for an expired wrapped .eth name', async () => {
|
|
116
|
+
const result = await ensInstance.getOwner('expired-wrapped.eth', {
|
|
117
|
+
skipGraph: true,
|
|
118
|
+
})
|
|
119
|
+
|
|
120
|
+
expect(result).toEqual({
|
|
121
|
+
ownershipLevel: 'nameWrapper',
|
|
122
|
+
owner: '0x0000000000000000000000000000000000000000',
|
|
123
|
+
expired: true,
|
|
124
|
+
})
|
|
125
|
+
})
|
|
126
|
+
|
|
127
|
+
it('should return correct ownership level and values for an unwrapped .eth name', async () => {
|
|
128
|
+
const result = await ensInstance.getOwner('test123.eth', {
|
|
129
|
+
skipGraph: true,
|
|
130
|
+
})
|
|
131
|
+
expect(result).toEqual({
|
|
132
|
+
ownershipLevel: 'registrar',
|
|
133
|
+
owner: accounts[1],
|
|
134
|
+
registrant: accounts[1],
|
|
135
|
+
expired: false,
|
|
136
|
+
})
|
|
137
|
+
})
|
|
138
|
+
|
|
139
|
+
it('should return registrant undefined if skipGraph is true for an unwrapped .eth name', async () => {
|
|
140
|
+
const result = await ensInstance.getOwner('expired.eth', {
|
|
141
|
+
skipGraph: true,
|
|
142
|
+
})
|
|
143
|
+
expect(result).toEqual({
|
|
144
|
+
ownershipLevel: 'registrar',
|
|
145
|
+
owner: accounts[1],
|
|
146
|
+
expired: true,
|
|
147
|
+
})
|
|
148
|
+
})
|
|
149
|
+
|
|
150
|
+
it('should return correct ownership level and values for a unwrapped subname', async () => {
|
|
151
|
+
const result = await ensInstance.getOwner('test.with-subnames.eth', {
|
|
152
|
+
skipGraph: true,
|
|
153
|
+
})
|
|
154
|
+
expect(result).toEqual({
|
|
155
|
+
ownershipLevel: 'registry',
|
|
156
|
+
owner: accounts[2],
|
|
157
|
+
})
|
|
158
|
+
})
|
|
159
|
+
|
|
160
|
+
it('should return correct ownership level and values for a wrapped subname', async () => {
|
|
161
|
+
const result = await ensInstance.getOwner(
|
|
162
|
+
'test.wrapped-with-subnames.eth',
|
|
163
|
+
{ skipGraph: true },
|
|
164
|
+
)
|
|
165
|
+
expect(result).toEqual({
|
|
166
|
+
ownershipLevel: 'nameWrapper',
|
|
167
|
+
owner: accounts[2],
|
|
168
|
+
})
|
|
169
|
+
})
|
|
170
|
+
})
|
|
171
|
+
|
|
172
|
+
describe('errors', () => {
|
|
173
|
+
beforeAll(() => {
|
|
174
|
+
process.env.NEXT_PUBLIC_ENSJS_DEBUG = 'on'
|
|
175
|
+
localStorage.setItem('ensjs-debug', 'ENSJSSubgraphError')
|
|
176
|
+
})
|
|
177
|
+
afterAll(() => {
|
|
178
|
+
process.env.NEXT_PUBLIC_ENS_DEBUG = 'on'
|
|
179
|
+
localStorage.removeItem('ensjs-debug')
|
|
180
|
+
})
|
|
181
|
+
|
|
182
|
+
it('should return correct ownership level and values for an expired wrapped .eth name', async () => {
|
|
183
|
+
try {
|
|
184
|
+
await ensInstance.getOwner('expired-wrapped.eth', {
|
|
185
|
+
skipGraph: false,
|
|
186
|
+
})
|
|
187
|
+
expect(true).toBeFalsy()
|
|
188
|
+
} catch (e: unknown) {
|
|
189
|
+
const error = e as ENSJSError<Owner>
|
|
190
|
+
expect(error).toBeInstanceOf(ENSJSError)
|
|
191
|
+
expect(error.name).toBe('ENSJSSubgraphError')
|
|
192
|
+
expect(error.data).toEqual({
|
|
193
|
+
owner: '0x0000000000000000000000000000000000000000',
|
|
194
|
+
ownershipLevel: 'nameWrapper',
|
|
195
|
+
expired: true,
|
|
196
|
+
})
|
|
197
|
+
}
|
|
198
|
+
})
|
|
199
|
+
|
|
200
|
+
it('should return registrant undefined for an expired unwrapped .eth name', async () => {
|
|
201
|
+
try {
|
|
202
|
+
await ensInstance.getOwner('expired.eth', { skipGraph: false })
|
|
203
|
+
expect(true).toBeFalsy()
|
|
204
|
+
} catch (e) {
|
|
205
|
+
const error = e as ENSJSError<Owner>
|
|
206
|
+
expect(error).toBeInstanceOf(ENSJSError)
|
|
207
|
+
expect(error.name).toBe('ENSJSSubgraphError')
|
|
208
|
+
expect(error.data).toEqual({
|
|
209
|
+
owner: '0x70997970C51812dc3A010C7d01b50e0d17dc79C8',
|
|
210
|
+
ownershipLevel: 'registrar',
|
|
211
|
+
expired: true,
|
|
212
|
+
})
|
|
213
|
+
}
|
|
214
|
+
})
|
|
215
|
+
|
|
216
|
+
it('should return undefined for a name that does not exist', async () => {
|
|
217
|
+
try {
|
|
218
|
+
await ensInstance.getOwner('notexistent.eth', {
|
|
219
|
+
skipGraph: false,
|
|
220
|
+
})
|
|
221
|
+
expect(true).toBeFalsy()
|
|
222
|
+
} catch (e) {
|
|
223
|
+
const error = e as ENSJSError<Owner>
|
|
224
|
+
expect(error).toBeInstanceOf(ENSJSError)
|
|
225
|
+
expect(error.name).toBe('ENSJSSubgraphError')
|
|
226
|
+
expect(error.data).toBeUndefined()
|
|
227
|
+
}
|
|
228
|
+
})
|
|
229
|
+
|
|
230
|
+
it('should not throw error for subname eth', async () => {
|
|
231
|
+
await expect(
|
|
232
|
+
ensInstance.getOwner('test.expired-wrapped.eth', {
|
|
233
|
+
skipGraph: false,
|
|
234
|
+
}),
|
|
235
|
+
).resolves.toBeDefined()
|
|
236
|
+
})
|
|
237
|
+
})
|
|
79
238
|
})
|