@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.
- package/dist/cjs/GqlManager.d.ts +5 -3
- package/dist/cjs/GqlManager.js +21 -13
- package/dist/cjs/functions/burnFuses.d.ts +8 -7
- package/dist/cjs/functions/getFuses.js +2 -2
- package/dist/cjs/functions/getOwner.js +4 -2
- package/dist/cjs/index.d.ts +3 -1
- package/dist/esm/GqlManager.d.ts +5 -3
- package/dist/esm/GqlManager.js +21 -13
- package/dist/esm/functions/burnFuses.d.ts +8 -7
- package/dist/esm/functions/getFuses.js +2 -2
- package/dist/esm/functions/getOwner.js +4 -2
- package/dist/esm/index.d.ts +3 -1
- package/package.json +2 -1
- package/src/GqlManager.test.ts +5 -4
- package/src/GqlManager.ts +54 -36
- package/src/functions/burnFuses.ts +12 -11
- package/src/functions/getFuses.test.ts +4 -4
- package/src/functions/getFuses.ts +2 -2
- package/src/functions/getOwner.test.ts +13 -0
- package/src/functions/getOwner.ts +8 -2
- package/src/index.ts +3 -0
package/dist/cjs/GqlManager.d.ts
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
export declare const
|
|
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;
|
package/dist/cjs/GqlManager.js
CHANGED
|
@@ -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
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
if (
|
|
45
|
-
|
|
46
|
-
|
|
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, {
|
|
56
|
-
|
|
60
|
+
const updatedQuery = visit(parsedQuery, {
|
|
61
|
+
SelectionSet: {
|
|
62
|
+
enter: exports.enter,
|
|
63
|
+
},
|
|
64
|
+
});
|
|
57
65
|
return {
|
|
58
66
|
...request,
|
|
59
|
-
body: JSON.stringify(
|
|
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
|
|
22
|
-
|
|
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
|
|
31
|
-
export default function
|
|
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.
|
|
23
|
+
fuseObj.CAN_DO_EVERYTHING = true;
|
|
24
24
|
}
|
|
25
25
|
else {
|
|
26
|
-
fuseObj.
|
|
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',
|
package/dist/cjs/index.d.ts
CHANGED
|
@@ -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/dist/esm/GqlManager.d.ts
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
export declare const
|
|
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;
|
package/dist/esm/GqlManager.js
CHANGED
|
@@ -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
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
if (
|
|
19
|
-
|
|
20
|
-
|
|
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, {
|
|
29
|
-
|
|
33
|
+
const updatedQuery = visit(parsedQuery, {
|
|
34
|
+
SelectionSet: {
|
|
35
|
+
enter,
|
|
36
|
+
},
|
|
37
|
+
});
|
|
30
38
|
return {
|
|
31
39
|
...request,
|
|
32
|
-
body: JSON.stringify(
|
|
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
|
|
22
|
-
|
|
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
|
|
31
|
-
export default function
|
|
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.
|
|
21
|
+
fuseObj.CAN_DO_EVERYTHING = true;
|
|
22
22
|
}
|
|
23
23
|
else {
|
|
24
|
-
fuseObj.
|
|
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',
|
package/dist/esm/index.d.ts
CHANGED
|
@@ -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.
|
|
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",
|
package/src/GqlManager.test.ts
CHANGED
|
@@ -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
|
|
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
|
-
|
|
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
|
-
|
|
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:
|
|
17
|
-
|
|
18
|
-
|
|
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
|
-
|
|
22
|
-
|
|
23
|
-
|
|
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 =
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
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
|
-
|
|
36
|
-
|
|
37
|
-
|
|
52
|
+
return {
|
|
53
|
+
...request,
|
|
54
|
+
body: JSON.stringify({ ...requestBody, query: print(updatedQuery) }),
|
|
55
|
+
}
|
|
38
56
|
}
|
|
39
|
-
}
|
|
40
57
|
|
|
41
|
-
export const responseMiddleware =
|
|
42
|
-
traverse
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
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
|
-
|
|
50
|
-
|
|
51
|
-
|
|
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
|
-
|
|
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
|
|
44
|
-
|
|
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
|
|
56
|
-
| (Partial<FusePropsNamedArray
|
|
57
|
-
| (FusePropsNamedArray
|
|
56
|
+
export type FuseProps =
|
|
57
|
+
| (Partial<FusePropsNamedArray> & FusePropsUnnamedArray)
|
|
58
|
+
| (FusePropsNamedArray & Partial<FusePropsUnnamedArray>)
|
|
58
59
|
| FusePropsNumber
|
|
59
60
|
|
|
60
|
-
export default async function
|
|
61
|
+
export default async function (
|
|
61
62
|
{ contracts, signer }: ENSArgs<'contracts' | 'signer'>,
|
|
62
63
|
name: string,
|
|
63
|
-
props: FuseProps
|
|
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
|
-
|
|
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
|
|
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.
|
|
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
|
-
|
|
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.
|
|
36
|
+
fuseObj.CAN_DO_EVERYTHING = true
|
|
37
37
|
} else {
|
|
38
|
-
fuseObj.
|
|
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 (
|
|
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 (
|
|
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
|