@ensdomains/ensjs 3.0.0-alpha.14 → 3.0.0-alpha.17

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.
@@ -1,6 +1,8 @@
1
- export declare const enter: (node: any) => any;
2
- export declare const requestMiddleware: (visit: any, parse: any) => (request: any) => any;
3
- export declare const responseMiddleware: (traverse: any) => (response: any) => any;
1
+ import type { parse as Parse, print as Print, SelectionSetNode, visit as Visit } from 'graphql';
2
+ import type Traverse from 'traverse';
3
+ export declare const enter: (node: SelectionSetNode) => SelectionSetNode | undefined;
4
+ export declare const requestMiddleware: (visit: typeof Visit, parse: typeof Parse, print: typeof Print) => (request: any) => any;
5
+ export declare const responseMiddleware: (traverse: typeof Traverse) => (response: any) => any;
4
6
  export default class GqlManager {
5
7
  gql: any;
6
8
  client?: any | null;
@@ -24,7 +24,6 @@ var __importStar = (this && this.__importStar) || function (mod) {
24
24
  };
25
25
  Object.defineProperty(exports, "__esModule", { value: true });
26
26
  exports.responseMiddleware = exports.requestMiddleware = exports.enter = void 0;
27
- // @ts-nocheck
28
27
  const normalise_1 = require("./utils/normalise");
29
28
  const generateSelection = (selection) => ({
30
29
  kind: 'Field',
@@ -38,25 +37,34 @@ const generateSelection = (selection) => ({
38
37
  selectionSet: undefined,
39
38
  });
40
39
  const enter = (node) => {
41
- if (node.kind === 'SelectionSet') {
42
- const id = node.selections.find((x) => x.name && x.name.value === 'id');
43
- const name = node.selections.find((x) => x.name && x.name.value === 'name');
44
- if (!id && name) {
45
- node.selections = [...node.selections, generateSelection('id')];
46
- return node;
40
+ let hasName = false;
41
+ let hasId = false;
42
+ for (const selection of node.selections) {
43
+ if ('name' in selection) {
44
+ if (selection.name.value === 'name')
45
+ hasName = true;
46
+ else if (selection.name.value === 'id')
47
+ hasId = true;
47
48
  }
48
49
  }
50
+ if (hasName && !hasId) {
51
+ node.selections = [...node.selections, generateSelection('id')];
52
+ return node;
53
+ }
49
54
  };
50
55
  exports.enter = enter;
51
- const requestMiddleware = (visit, parse) => (request) => {
56
+ const requestMiddleware = (visit, parse, print) => (request) => {
52
57
  const requestBody = JSON.parse(request.body);
53
58
  const rawQuery = requestBody.query;
54
59
  const parsedQuery = parse(rawQuery);
55
- const updatedQuery = visit(parsedQuery, { enter: exports.enter });
56
- const updatedBody = { ...requestBody, query: updatedQuery.loc.source.body };
60
+ const updatedQuery = visit(parsedQuery, {
61
+ SelectionSet: {
62
+ enter: exports.enter,
63
+ },
64
+ });
57
65
  return {
58
66
  ...request,
59
- body: JSON.stringify(updatedBody),
67
+ body: JSON.stringify({ ...requestBody, query: print(updatedQuery) }),
60
68
  };
61
69
  };
62
70
  exports.requestMiddleware = requestMiddleware;
@@ -81,13 +89,13 @@ class GqlManager {
81
89
  client = null;
82
90
  setUrl = async (url) => {
83
91
  if (url) {
84
- const [imported, traverse, { visit, parse }] = await Promise.all([
92
+ const [imported, traverse, { visit, parse, print }] = await Promise.all([
85
93
  Promise.resolve().then(() => __importStar(require('graphql-request'))),
86
94
  Promise.resolve().then(() => __importStar(require('traverse'))),
87
95
  Promise.resolve().then(() => __importStar(require('graphql/language'))),
88
96
  ]);
89
97
  this.client = new imported.GraphQLClient(url, {
90
- requestMiddleware: (0, exports.requestMiddleware)(visit, parse),
98
+ requestMiddleware: (0, exports.requestMiddleware)(visit, parse, print),
91
99
  responseMiddleware: (0, exports.responseMiddleware)(traverse.default),
92
100
  });
93
101
  this.gql = imported.gql;
@@ -4,7 +4,7 @@ declare type FuseObj = typeof fuseEnum;
4
4
  declare type UnnamedFuseType = typeof unnamedFuses;
5
5
  declare type Fuse = keyof FuseObj;
6
6
  declare type UnnamedFuseValues = UnnamedFuseType[number];
7
- declare type FuseArrayPossibilities = [Fuse] | [Fuse, Fuse] | [Fuse, Fuse, Fuse] | [Fuse, Fuse, Fuse, Fuse] | [Fuse, Fuse, Fuse, Fuse, Fuse] | [Fuse, Fuse, Fuse, Fuse, Fuse, Fuse] | [Fuse, Fuse, Fuse, Fuse, Fuse, Fuse, Fuse];
7
+ export declare type FuseArrayPossibilities = [Fuse] | [Fuse, Fuse] | [Fuse, Fuse, Fuse] | [Fuse, Fuse, Fuse, Fuse] | [Fuse, Fuse, Fuse, Fuse, Fuse] | [Fuse, Fuse, Fuse, Fuse, Fuse, Fuse] | [Fuse, Fuse, Fuse, Fuse, Fuse, Fuse, Fuse];
8
8
  /**
9
9
  * This type creates a type error if there are any duplicate fuses.
10
10
  * It effectively works like a reduce function, starting with 0 included types, adding a type each time, and then checking for duplicates.
@@ -18,15 +18,16 @@ declare type FusesWithoutDuplicates<A, B = never> = A extends FuseArrayPossibili
18
18
  ...FusesWithoutDuplicates<Tail, Head | B>
19
19
  ] : A : [
20
20
  ];
21
- declare type FusePropsNamedArray<A extends FuseArrayPossibilities> = {
22
- namedFusesToBurn: FusesWithoutDuplicates<A>;
21
+ export declare type NamedFusesToBurn = FusesWithoutDuplicates<FuseArrayPossibilities>;
22
+ export declare type FusePropsNamedArray = {
23
+ namedFusesToBurn: NamedFusesToBurn;
23
24
  };
24
- declare type FusePropsUnnamedArray = {
25
+ export declare type FusePropsUnnamedArray = {
25
26
  unnamedFusesToBurn: UnnamedFuseValues[];
26
27
  };
27
- declare type FusePropsNumber = {
28
+ export declare type FusePropsNumber = {
28
29
  fuseNumberToBurn: number;
29
30
  };
30
- declare type FuseProps<A extends FuseArrayPossibilities> = (Partial<FusePropsNamedArray<A>> & FusePropsUnnamedArray) | (FusePropsNamedArray<A> & Partial<FusePropsUnnamedArray>) | FusePropsNumber;
31
- export default function <A extends FuseArrayPossibilities>({ contracts, signer }: ENSArgs<'contracts' | 'signer'>, name: string, props: FuseProps<A>): Promise<import("ethers").PopulatedTransaction>;
31
+ export declare type FuseProps = (Partial<FusePropsNamedArray> & FusePropsUnnamedArray) | (FusePropsNamedArray & Partial<FusePropsUnnamedArray>) | FusePropsNumber;
32
+ export default function ({ contracts, signer }: ENSArgs<'contracts' | 'signer'>, name: string, props: FuseProps): Promise<import("ethers").PopulatedTransaction>;
32
33
  export {};
@@ -20,10 +20,10 @@ const decode = async ({ contracts }, data) => {
20
20
  fuses.and(fuses_1.fuseEnum[fuse]).gt(0),
21
21
  ]));
22
22
  if (fuses.eq(0)) {
23
- fuseObj.canDoEverything = true;
23
+ fuseObj.CAN_DO_EVERYTHING = true;
24
24
  }
25
25
  else {
26
- fuseObj.canDoEverything = false;
26
+ fuseObj.CAN_DO_EVERYTHING = false;
27
27
  }
28
28
  const expiryDate = new Date(expiry * 1000);
29
29
  return {
@@ -102,7 +102,8 @@ const decode = async ({ contracts, multicallWrapper }, data, name, contract) =>
102
102
  if (labels.length > 2 &&
103
103
  ethers_1.ethers.utils.hexStripZeros(registryOwner) !== '0x') {
104
104
  // this means that the subname is wrapped
105
- if (registryOwner === nameWrapper.address) {
105
+ if (registryOwner === nameWrapper.address &&
106
+ ethers_1.ethers.utils.hexStripZeros(nameWrapperOwner) !== '0x') {
106
107
  return {
107
108
  owner: nameWrapperOwner,
108
109
  ownershipLevel: 'nameWrapper',
@@ -121,7 +122,8 @@ const decode = async ({ contracts, multicallWrapper }, data, name, contract) =>
121
122
  // there will only ever be an owner for non .eth names, not a registrant
122
123
  // this is because for unwrapped names, there is no associated NFT
123
124
  // and for wrapped names, owner and registrant are the same thing
124
- if (registryOwner == nameWrapper.address) {
125
+ if (registryOwner == nameWrapper.address &&
126
+ ethers_1.ethers.utils.hexStripZeros(nameWrapperOwner) !== '0x') {
125
127
  return {
126
128
  owner: nameWrapperOwner,
127
129
  ownershipLevel: 'nameWrapper',
@@ -18,6 +18,9 @@ import type transferSubname from './functions/transferSubname';
18
18
  import type unwrapName from './functions/unwrapName';
19
19
  import type wrapName from './functions/wrapName';
20
20
  import GqlManager from './GqlManager';
21
+ import fuseEnum from './utils/fuses';
22
+ export type { FusePropsNamedArray, FusePropsUnnamedArray, FusePropsNumber, FuseProps, NamedFusesToBurn } from './functions/burnFuses';
23
+ export declare type FuseEnum = typeof fuseEnum;
21
24
  declare type ENSOptions = {
22
25
  graphURI?: string | null;
23
26
  getContractAddress?: typeof _getContractAddress;
@@ -464,4 +467,3 @@ export declare class ENS {
464
467
  registerName: WriteFunction<typeof registerName>;
465
468
  renewName: WriteFunction<typeof renewName>;
466
469
  }
467
- export {};
@@ -1,6 +1,8 @@
1
- export declare const enter: (node: any) => any;
2
- export declare const requestMiddleware: (visit: any, parse: any) => (request: any) => any;
3
- export declare const responseMiddleware: (traverse: any) => (response: any) => any;
1
+ import type { parse as Parse, print as Print, SelectionSetNode, visit as Visit } from 'graphql';
2
+ import type Traverse from 'traverse';
3
+ export declare const enter: (node: SelectionSetNode) => SelectionSetNode | undefined;
4
+ export declare const requestMiddleware: (visit: typeof Visit, parse: typeof Parse, print: typeof Print) => (request: any) => any;
5
+ export declare const responseMiddleware: (traverse: typeof Traverse) => (response: any) => any;
4
6
  export default class GqlManager {
5
7
  gql: any;
6
8
  client?: any | null;
@@ -1,4 +1,3 @@
1
- // @ts-nocheck
2
1
  import { namehash } from './utils/normalise';
3
2
  const generateSelection = (selection) => ({
4
3
  kind: 'Field',
@@ -12,24 +11,33 @@ const generateSelection = (selection) => ({
12
11
  selectionSet: undefined,
13
12
  });
14
13
  export const enter = (node) => {
15
- if (node.kind === 'SelectionSet') {
16
- const id = node.selections.find((x) => x.name && x.name.value === 'id');
17
- const name = node.selections.find((x) => x.name && x.name.value === 'name');
18
- if (!id && name) {
19
- node.selections = [...node.selections, generateSelection('id')];
20
- return node;
14
+ let hasName = false;
15
+ let hasId = false;
16
+ for (const selection of node.selections) {
17
+ if ('name' in selection) {
18
+ if (selection.name.value === 'name')
19
+ hasName = true;
20
+ else if (selection.name.value === 'id')
21
+ hasId = true;
21
22
  }
22
23
  }
24
+ if (hasName && !hasId) {
25
+ node.selections = [...node.selections, generateSelection('id')];
26
+ return node;
27
+ }
23
28
  };
24
- export const requestMiddleware = (visit, parse) => (request) => {
29
+ export const requestMiddleware = (visit, parse, print) => (request) => {
25
30
  const requestBody = JSON.parse(request.body);
26
31
  const rawQuery = requestBody.query;
27
32
  const parsedQuery = parse(rawQuery);
28
- const updatedQuery = visit(parsedQuery, { enter });
29
- const updatedBody = { ...requestBody, query: updatedQuery.loc.source.body };
33
+ const updatedQuery = visit(parsedQuery, {
34
+ SelectionSet: {
35
+ enter,
36
+ },
37
+ });
30
38
  return {
31
39
  ...request,
32
- body: JSON.stringify(updatedBody),
40
+ body: JSON.stringify({ ...requestBody, query: print(updatedQuery) }),
33
41
  };
34
42
  };
35
43
  export const responseMiddleware = (traverse) => (response) => {
@@ -53,13 +61,13 @@ export default class GqlManager {
53
61
  this.client = null;
54
62
  this.setUrl = async (url) => {
55
63
  if (url) {
56
- const [imported, traverse, { visit, parse }] = await Promise.all([
64
+ const [imported, traverse, { visit, parse, print }] = await Promise.all([
57
65
  import('graphql-request'),
58
66
  import('traverse'),
59
67
  import('graphql/language'),
60
68
  ]);
61
69
  this.client = new imported.GraphQLClient(url, {
62
- requestMiddleware: requestMiddleware(visit, parse),
70
+ requestMiddleware: requestMiddleware(visit, parse, print),
63
71
  responseMiddleware: responseMiddleware(traverse.default),
64
72
  });
65
73
  this.gql = imported.gql;
@@ -4,7 +4,7 @@ declare type FuseObj = typeof fuseEnum;
4
4
  declare type UnnamedFuseType = typeof unnamedFuses;
5
5
  declare type Fuse = keyof FuseObj;
6
6
  declare type UnnamedFuseValues = UnnamedFuseType[number];
7
- declare type FuseArrayPossibilities = [Fuse] | [Fuse, Fuse] | [Fuse, Fuse, Fuse] | [Fuse, Fuse, Fuse, Fuse] | [Fuse, Fuse, Fuse, Fuse, Fuse] | [Fuse, Fuse, Fuse, Fuse, Fuse, Fuse] | [Fuse, Fuse, Fuse, Fuse, Fuse, Fuse, Fuse];
7
+ export declare type FuseArrayPossibilities = [Fuse] | [Fuse, Fuse] | [Fuse, Fuse, Fuse] | [Fuse, Fuse, Fuse, Fuse] | [Fuse, Fuse, Fuse, Fuse, Fuse] | [Fuse, Fuse, Fuse, Fuse, Fuse, Fuse] | [Fuse, Fuse, Fuse, Fuse, Fuse, Fuse, Fuse];
8
8
  /**
9
9
  * This type creates a type error if there are any duplicate fuses.
10
10
  * It effectively works like a reduce function, starting with 0 included types, adding a type each time, and then checking for duplicates.
@@ -18,15 +18,16 @@ declare type FusesWithoutDuplicates<A, B = never> = A extends FuseArrayPossibili
18
18
  ...FusesWithoutDuplicates<Tail, Head | B>
19
19
  ] : A : [
20
20
  ];
21
- declare type FusePropsNamedArray<A extends FuseArrayPossibilities> = {
22
- namedFusesToBurn: FusesWithoutDuplicates<A>;
21
+ export declare type NamedFusesToBurn = FusesWithoutDuplicates<FuseArrayPossibilities>;
22
+ export declare type FusePropsNamedArray = {
23
+ namedFusesToBurn: NamedFusesToBurn;
23
24
  };
24
- declare type FusePropsUnnamedArray = {
25
+ export declare type FusePropsUnnamedArray = {
25
26
  unnamedFusesToBurn: UnnamedFuseValues[];
26
27
  };
27
- declare type FusePropsNumber = {
28
+ export declare type FusePropsNumber = {
28
29
  fuseNumberToBurn: number;
29
30
  };
30
- declare type FuseProps<A extends FuseArrayPossibilities> = (Partial<FusePropsNamedArray<A>> & FusePropsUnnamedArray) | (FusePropsNamedArray<A> & Partial<FusePropsUnnamedArray>) | FusePropsNumber;
31
- export default function <A extends FuseArrayPossibilities>({ contracts, signer }: ENSArgs<'contracts' | 'signer'>, name: string, props: FuseProps<A>): Promise<import("ethers").PopulatedTransaction>;
31
+ export declare type FuseProps = (Partial<FusePropsNamedArray> & FusePropsUnnamedArray) | (FusePropsNamedArray & Partial<FusePropsUnnamedArray>) | FusePropsNumber;
32
+ export default function ({ contracts, signer }: ENSArgs<'contracts' | 'signer'>, name: string, props: FuseProps): Promise<import("ethers").PopulatedTransaction>;
32
33
  export {};
@@ -18,10 +18,10 @@ const decode = async ({ contracts }, data) => {
18
18
  fuses.and(fuseEnum[fuse]).gt(0),
19
19
  ]));
20
20
  if (fuses.eq(0)) {
21
- fuseObj.canDoEverything = true;
21
+ fuseObj.CAN_DO_EVERYTHING = true;
22
22
  }
23
23
  else {
24
- fuseObj.canDoEverything = false;
24
+ fuseObj.CAN_DO_EVERYTHING = false;
25
25
  }
26
26
  const expiryDate = new Date(expiry * 1000);
27
27
  return {
@@ -100,7 +100,8 @@ const decode = async ({ contracts, multicallWrapper }, data, name, contract) =>
100
100
  if (labels.length > 2 &&
101
101
  ethers.utils.hexStripZeros(registryOwner) !== '0x') {
102
102
  // this means that the subname is wrapped
103
- if (registryOwner === nameWrapper.address) {
103
+ if (registryOwner === nameWrapper.address &&
104
+ ethers.utils.hexStripZeros(nameWrapperOwner) !== '0x') {
104
105
  return {
105
106
  owner: nameWrapperOwner,
106
107
  ownershipLevel: 'nameWrapper',
@@ -119,7 +120,8 @@ const decode = async ({ contracts, multicallWrapper }, data, name, contract) =>
119
120
  // there will only ever be an owner for non .eth names, not a registrant
120
121
  // this is because for unwrapped names, there is no associated NFT
121
122
  // and for wrapped names, owner and registrant are the same thing
122
- if (registryOwner == nameWrapper.address) {
123
+ if (registryOwner == nameWrapper.address &&
124
+ ethers.utils.hexStripZeros(nameWrapperOwner) !== '0x') {
123
125
  return {
124
126
  owner: nameWrapperOwner,
125
127
  ownershipLevel: 'nameWrapper',
@@ -18,6 +18,9 @@ import type transferSubname from './functions/transferSubname';
18
18
  import type unwrapName from './functions/unwrapName';
19
19
  import type wrapName from './functions/wrapName';
20
20
  import GqlManager from './GqlManager';
21
+ import fuseEnum from './utils/fuses';
22
+ export type { FusePropsNamedArray, FusePropsUnnamedArray, FusePropsNumber, FuseProps, NamedFusesToBurn } from './functions/burnFuses';
23
+ export declare type FuseEnum = typeof fuseEnum;
21
24
  declare type ENSOptions = {
22
25
  graphURI?: string | null;
23
26
  getContractAddress?: typeof _getContractAddress;
@@ -464,4 +467,3 @@ export declare class ENS {
464
467
  registerName: WriteFunction<typeof registerName>;
465
468
  renewName: WriteFunction<typeof renewName>;
466
469
  }
467
- export {};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ensdomains/ensjs",
3
- "version": "3.0.0-alpha.14",
3
+ "version": "3.0.0-alpha.17",
4
4
  "description": "ENS javascript library for contract interaction",
5
5
  "main": "./dist/cjs/index.js",
6
6
  "types": "./dist/cjs/index.d.ts",
@@ -69,6 +69,7 @@
69
69
  },
70
70
  "scripts": {
71
71
  "tenv": "ens-test-env -a",
72
+ "denv": "pnpm tenv start -ns -nb",
72
73
  "generate-types": "ts-node scripts/runTypechain.ts",
73
74
  "generate-abis": "hardhat export-abi",
74
75
  "start": "ts-node --files src/index.test.ts",
@@ -1,7 +1,7 @@
1
+ import { parse, print, visit } from 'graphql'
1
2
  import traverse from 'traverse'
2
- import { visit, parse } from 'graphql'
3
3
 
4
- import { requestMiddleware, responseMiddleware, enter } from './GqlManager'
4
+ import { requestMiddleware, responseMiddleware } from './GqlManager'
5
5
  import { namehash } from './utils/normalise'
6
6
 
7
7
  describe('GqlManager', () => {
@@ -153,8 +153,9 @@ query getNames($id: ID!, $expiryDate: Int) {
153
153
 
154
154
  describe('requestMiddleware', () => {
155
155
  it('should add id to a SelectionSet if name is present and id is not', () => {
156
- const result = requestMiddleware(visit, parse)(mockRequest)
157
- expect(result.body.includes('id')).toBe(true)
156
+ const result = requestMiddleware(visit, parse, print)(mockRequest)
157
+ const body = result.body as string
158
+ expect(body.match(/domain.*id.*id.*domains.*id.*id/)?.length).toBe(1)
158
159
  })
159
160
  })
160
161
  describe('responseMiddleware', () => {
package/src/GqlManager.ts CHANGED
@@ -1,10 +1,17 @@
1
- // @ts-nocheck
1
+ import type {
2
+ Kind,
3
+ parse as Parse,
4
+ print as Print,
5
+ SelectionSetNode,
6
+ visit as Visit,
7
+ } from 'graphql'
8
+ import type Traverse from 'traverse'
2
9
  import { namehash } from './utils/normalise'
3
10
 
4
11
  const generateSelection = (selection: any) => ({
5
- kind: 'Field',
12
+ kind: 'Field' as Kind.FIELD,
6
13
  name: {
7
- kind: 'Name',
14
+ kind: 'Name' as Kind.NAME,
8
15
  value: selection,
9
16
  },
10
17
  arguments: [],
@@ -13,47 +20,58 @@ const generateSelection = (selection: any) => ({
13
20
  selectionSet: undefined,
14
21
  })
15
22
 
16
- export const enter = (node: any) => {
17
- if (node.kind === 'SelectionSet') {
18
- const id = node.selections.find((x) => x.name && x.name.value === 'id')
19
- const name = node.selections.find((x) => x.name && x.name.value === 'name')
23
+ export const enter = (node: SelectionSetNode) => {
24
+ let hasName = false
25
+ let hasId = false
20
26
 
21
- if (!id && name) {
22
- node.selections = [...node.selections, generateSelection('id')]
23
- return node
27
+ for (const selection of node.selections) {
28
+ if ('name' in selection) {
29
+ if (selection.name.value === 'name') hasName = true
30
+ else if (selection.name.value === 'id') hasId = true
24
31
  }
25
32
  }
33
+
34
+ if (hasName && !hasId) {
35
+ node.selections = [...node.selections, generateSelection('id')]
36
+ return node
37
+ }
26
38
  }
27
39
 
28
- export const requestMiddleware = (visit, parse) => (request: any) => {
29
- const requestBody = JSON.parse(request.body)
30
- const rawQuery = requestBody.query
31
- const parsedQuery = parse(rawQuery)
32
- const updatedQuery = visit(parsedQuery, { enter })
33
- const updatedBody = { ...requestBody, query: updatedQuery.loc.source.body }
40
+ export const requestMiddleware =
41
+ (visit: typeof Visit, parse: typeof Parse, print: typeof Print) =>
42
+ (request: any) => {
43
+ const requestBody = JSON.parse(request.body)
44
+ const rawQuery = requestBody.query
45
+ const parsedQuery = parse(rawQuery)
46
+ const updatedQuery = visit(parsedQuery, {
47
+ SelectionSet: {
48
+ enter,
49
+ },
50
+ })
34
51
 
35
- return {
36
- ...request,
37
- body: JSON.stringify(updatedBody),
52
+ return {
53
+ ...request,
54
+ body: JSON.stringify({ ...requestBody, query: print(updatedQuery) }),
55
+ }
38
56
  }
39
- }
40
57
 
41
- export const responseMiddleware = (traverse) => (response: any) => {
42
- traverse(response).forEach(function (responseItem: any) {
43
- if (responseItem instanceof Object && responseItem.name) {
44
- //Name already in hashed form
45
- if (responseItem.name && responseItem.name.includes('[')) {
46
- return
47
- }
58
+ export const responseMiddleware =
59
+ (traverse: typeof Traverse) => (response: any) => {
60
+ traverse(response).forEach(function (responseItem: any) {
61
+ if (responseItem instanceof Object && responseItem.name) {
62
+ //Name already in hashed form
63
+ if (responseItem.name && responseItem.name.includes('[')) {
64
+ return
65
+ }
48
66
 
49
- const hashedName = namehash(responseItem.name)
50
- if (responseItem.id !== hashedName) {
51
- this.update({ ...responseItem, name: hashedName, invalidName: true })
67
+ const hashedName = namehash(responseItem.name)
68
+ if (responseItem.id !== hashedName) {
69
+ this.update({ ...responseItem, name: hashedName, invalidName: true })
70
+ }
52
71
  }
53
- }
54
- })
55
- return response
56
- }
72
+ })
73
+ return response
74
+ }
57
75
 
58
76
  export default class GqlManager {
59
77
  public gql: any = () => null
@@ -61,14 +79,14 @@ export default class GqlManager {
61
79
 
62
80
  public setUrl = async (url: string | null) => {
63
81
  if (url) {
64
- const [imported, traverse, { visit, parse }] = await Promise.all([
82
+ const [imported, traverse, { visit, parse, print }] = await Promise.all([
65
83
  import('graphql-request'),
66
84
  import('traverse'),
67
85
  import('graphql/language'),
68
86
  ])
69
87
 
70
88
  this.client = new imported.GraphQLClient(url, {
71
- requestMiddleware: requestMiddleware(visit, parse),
89
+ requestMiddleware: requestMiddleware(visit, parse, print),
72
90
  responseMiddleware: responseMiddleware(traverse.default),
73
91
  })
74
92
  this.gql = imported.gql
@@ -5,11 +5,10 @@ import { namehash } from '../utils/normalise'
5
5
  type FuseObj = typeof fuseEnum
6
6
  type UnnamedFuseType = typeof unnamedFuses
7
7
  type Fuse = keyof FuseObj
8
- type NamedFuseValues = FuseObj[Fuse]
9
8
  type UnnamedFuseValues = UnnamedFuseType[number]
10
9
 
11
10
  // We need this type so that the following type isn't infinite. This type limits the max length of the fuse array to 7.
12
- type FuseArrayPossibilities =
11
+ export type FuseArrayPossibilities =
13
12
  | [Fuse]
14
13
  | [Fuse, Fuse]
15
14
  | [Fuse, Fuse, Fuse]
@@ -40,27 +39,29 @@ type FusesWithoutDuplicates<A, B = never> = A extends FuseArrayPossibilities
40
39
  : // CLAUSE A > FALSE: Return an empty array as it isn't a fuse tuple.
41
40
  []
42
41
 
43
- type FusePropsNamedArray<A extends FuseArrayPossibilities> = {
44
- namedFusesToBurn: FusesWithoutDuplicates<A>
42
+ export type NamedFusesToBurn = FusesWithoutDuplicates<FuseArrayPossibilities>
43
+
44
+ export type FusePropsNamedArray = {
45
+ namedFusesToBurn: NamedFusesToBurn
45
46
  }
46
47
 
47
- type FusePropsUnnamedArray = {
48
+ export type FusePropsUnnamedArray = {
48
49
  unnamedFusesToBurn: UnnamedFuseValues[]
49
50
  }
50
51
 
51
- type FusePropsNumber = {
52
+ export type FusePropsNumber = {
52
53
  fuseNumberToBurn: number
53
54
  }
54
55
 
55
- type FuseProps<A extends FuseArrayPossibilities> =
56
- | (Partial<FusePropsNamedArray<A>> & FusePropsUnnamedArray)
57
- | (FusePropsNamedArray<A> & Partial<FusePropsUnnamedArray>)
56
+ export type FuseProps =
57
+ | (Partial<FusePropsNamedArray> & FusePropsUnnamedArray)
58
+ | (FusePropsNamedArray & Partial<FusePropsUnnamedArray>)
58
59
  | FusePropsNumber
59
60
 
60
- export default async function <A extends FuseArrayPossibilities>(
61
+ export default async function (
61
62
  { contracts, signer }: ENSArgs<'contracts' | 'signer'>,
62
63
  name: string,
63
- props: FuseProps<A>,
64
+ props: FuseProps,
64
65
  ) {
65
66
  const isNumber = 'fuseNumberToBurn' in props
66
67
  const hasNamedArray = 'namedFusesToBurn' in props
@@ -19,7 +19,7 @@ const unwrappedNameDefault = {
19
19
  CANNOT_TRANSFER: false,
20
20
  CANNOT_UNWRAP: false,
21
21
  PARENT_CANNOT_CONTROL: false,
22
- canDoEverything: true,
22
+ CAN_DO_EVERYTHING: true,
23
23
  },
24
24
  owner: '0x0000000000000000000000000000000000000000',
25
25
  rawFuses: BigNumber.from(0),
@@ -48,12 +48,12 @@ describe('getFuses', () => {
48
48
  unwrappedNameDefault,
49
49
  )
50
50
  })
51
- it('should return with canDoEverything set to true for a name with no fuses burned', async () => {
51
+ it('should return with CAN_DO_EVERYTHING set to true for a name with no fuses burned', async () => {
52
52
  const nameWrapper = await ENSInstance.contracts!.getNameWrapper()!
53
53
  const result = await ENSInstance.getFuses('test.wrapped-with-subnames.eth')
54
54
  expect(result).toBeTruthy()
55
55
  if (result) {
56
- expect(result.fuseObj.canDoEverything).toBe(true)
56
+ expect(result.fuseObj.CAN_DO_EVERYTHING).toBe(true)
57
57
  expect(
58
58
  Object.values(result.fuseObj).reduce(
59
59
  (prev, curr) => (curr ? prev + 1 : prev),
@@ -85,7 +85,7 @@ describe('getFuses', () => {
85
85
  CANNOT_SET_TTL: true,
86
86
  CANNOT_CREATE_SUBDOMAIN: true,
87
87
  PARENT_CANNOT_CONTROL: true,
88
- canDoEverything: false,
88
+ CAN_DO_EVERYTHING: false,
89
89
  })
90
90
  expect(result.rawFuses.toHexString()).toBe('0x71')
91
91
  }
@@ -33,9 +33,9 @@ const decode = async (
33
33
  )
34
34
 
35
35
  if (fuses.eq(0)) {
36
- fuseObj.canDoEverything = true
36
+ fuseObj.CAN_DO_EVERYTHING = true
37
37
  } else {
38
- fuseObj.canDoEverything = false
38
+ fuseObj.CAN_DO_EVERYTHING = false
39
39
  }
40
40
 
41
41
  const expiryDate = new Date(expiry * 1000)
@@ -55,4 +55,17 @@ describe('getOwner', () => {
55
55
  expect(result?.ownershipLevel).toBe('registry')
56
56
  expect(result?.owner).toBe('0x3C44CdDdB6a900fa2b585dd299e03d12FA4293BC')
57
57
  })
58
+ it('should return registry ownership for a pseudo-wrapped name', async () => {
59
+ const nameWrapper = await ENSInstance.contracts!.getNameWrapper()
60
+ const tx = await ENSInstance.transferSubname('test.with-subnames.eth', {
61
+ contract: 'registry',
62
+ owner: nameWrapper.address,
63
+ addressOrIndex: 1,
64
+ })
65
+ await tx.wait()
66
+
67
+ const result = await ENSInstance.getOwner('test.with-subnames.eth')
68
+ expect(result?.ownershipLevel).toBe('registry')
69
+ expect(result?.owner).toBe(nameWrapper.address)
70
+ })
58
71
  })
@@ -161,7 +161,10 @@ const decode = async (
161
161
  ethers.utils.hexStripZeros(registryOwner) !== '0x'
162
162
  ) {
163
163
  // this means that the subname is wrapped
164
- if (registryOwner === nameWrapper.address) {
164
+ if (
165
+ registryOwner === nameWrapper.address &&
166
+ ethers.utils.hexStripZeros(nameWrapperOwner) !== '0x'
167
+ ) {
165
168
  return {
166
169
  owner: nameWrapperOwner,
167
170
  ownershipLevel: 'nameWrapper',
@@ -181,7 +184,10 @@ const decode = async (
181
184
  // there will only ever be an owner for non .eth names, not a registrant
182
185
  // this is because for unwrapped names, there is no associated NFT
183
186
  // and for wrapped names, owner and registrant are the same thing
184
- if (registryOwner == nameWrapper.address) {
187
+ if (
188
+ registryOwner == nameWrapper.address &&
189
+ ethers.utils.hexStripZeros(nameWrapperOwner) !== '0x'
190
+ ) {
185
191
  return {
186
192
  owner: nameWrapperOwner,
187
193
  ownershipLevel: 'nameWrapper',
package/src/index.ts CHANGED
@@ -48,6 +48,9 @@ import singleCall from './utils/singleCall'
48
48
  import writeTx from './utils/writeTx'
49
49
  import fuseEnum from './utils/fuses'
50
50
 
51
+ export type { FusePropsNamedArray, FusePropsUnnamedArray, FusePropsNumber, FuseProps, NamedFusesToBurn } from './functions/burnFuses'
52
+ export type FuseEnum = typeof fuseEnum
53
+
51
54
  type ENSOptions = {
52
55
  graphURI?: string | null
53
56
  getContractAddress?: typeof _getContractAddress