@ensdomains/ensjs 3.0.0-alpha.7 → 3.0.0-alpha.8
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/getProfile.d.ts +4 -1
- package/dist/cjs/functions/getProfile.js +62 -18
- package/dist/cjs/functions/getRecords.d.ts +1 -0
- package/dist/cjs/index.d.ts +5 -2
- package/dist/cjs/index.js +1 -1
- package/dist/cjs/utils/labels.js +4 -3
- package/dist/esm/functions/getProfile.d.ts +4 -1
- package/dist/esm/functions/getProfile.js +62 -18
- package/dist/esm/functions/getRecords.d.ts +1 -0
- package/dist/esm/index.d.ts +5 -2
- package/dist/esm/index.js +1 -1
- package/dist/esm/utils/labels.js +4 -3
- package/package.json +3 -3
- package/src/functions/getProfile.test.ts +16 -1
- package/src/functions/getProfile.ts +82 -19
- package/src/functions/getRecords.ts +1 -0
- package/src/index.ts +1 -1
- package/src/utils/labels.ts +5 -3
|
@@ -26,5 +26,8 @@ declare type ProfileOptions = {
|
|
|
26
26
|
texts?: boolean | string[];
|
|
27
27
|
coinTypes?: boolean | string[];
|
|
28
28
|
};
|
|
29
|
-
|
|
29
|
+
declare type InputProfileOptions = ProfileOptions & {
|
|
30
|
+
resolverAddress?: string;
|
|
31
|
+
};
|
|
32
|
+
export default function ({ contracts, gqlInstance, getName, _getAddr, _getContentHash, _getText, resolverMulticallWrapper, multicallWrapper, }: ENSArgs<'contracts' | 'gqlInstance' | 'getName' | '_getText' | '_getAddr' | '_getContentHash' | 'resolverMulticallWrapper' | 'multicallWrapper'>, nameOrAddress: string, options?: InputProfileOptions): Promise<ResolvedProfile | undefined>;
|
|
30
33
|
export {};
|
|
@@ -4,6 +4,7 @@ const address_encoder_1 = require("@ensdomains/address-encoder");
|
|
|
4
4
|
const ethers_1 = require("ethers");
|
|
5
5
|
const contentHash_1 = require("../utils/contentHash");
|
|
6
6
|
const hexEncodedName_1 = require("../utils/hexEncodedName");
|
|
7
|
+
const normalise_1 = require("../utils/normalise");
|
|
7
8
|
const validation_1 = require("../utils/validation");
|
|
8
9
|
const makeMulticallData = async ({ _getAddr, _getContentHash, _getText, resolverMulticallWrapper, }, name, options) => {
|
|
9
10
|
let calls = [];
|
|
@@ -49,13 +50,19 @@ const fetchWithoutResolverMulticall = async ({ multicallWrapper }, calls, resolv
|
|
|
49
50
|
}));
|
|
50
51
|
return (await multicallWrapper(callsWithResolver)).map((x) => x[1]);
|
|
51
52
|
};
|
|
52
|
-
const getDataForName = async ({ contracts, _getAddr, _getContentHash, _getText, resolverMulticallWrapper, multicallWrapper, }, name, options, fallbackResolver) => {
|
|
53
|
+
const getDataForName = async ({ contracts, _getAddr, _getContentHash, _getText, resolverMulticallWrapper, multicallWrapper, }, name, options, fallbackResolver, specificResolver) => {
|
|
53
54
|
const universalResolver = await contracts?.getUniversalResolver();
|
|
54
55
|
const { data, calls } = await makeMulticallData({ _getAddr, _getContentHash, _getText, resolverMulticallWrapper }, name, options);
|
|
55
56
|
let resolvedData;
|
|
56
57
|
let useFallbackResolver = false;
|
|
57
58
|
try {
|
|
58
|
-
|
|
59
|
+
if (specificResolver) {
|
|
60
|
+
const publicResolver = await contracts?.getPublicResolver(undefined, specificResolver);
|
|
61
|
+
resolvedData = await publicResolver?.callStatic.multicall(calls.map((x) => x.data));
|
|
62
|
+
}
|
|
63
|
+
else {
|
|
64
|
+
resolvedData = await universalResolver?.resolve((0, hexEncodedName_1.hexEncodeName)(name), data);
|
|
65
|
+
}
|
|
59
66
|
}
|
|
60
67
|
catch {
|
|
61
68
|
useFallbackResolver = true;
|
|
@@ -63,12 +70,18 @@ const getDataForName = async ({ contracts, _getAddr, _getContentHash, _getText,
|
|
|
63
70
|
let resolverAddress;
|
|
64
71
|
let recordData;
|
|
65
72
|
if (useFallbackResolver) {
|
|
66
|
-
resolverAddress = fallbackResolver;
|
|
73
|
+
resolverAddress = specificResolver || fallbackResolver;
|
|
67
74
|
recordData = await fetchWithoutResolverMulticall({ multicallWrapper }, calls, resolverAddress);
|
|
68
75
|
}
|
|
69
76
|
else {
|
|
70
|
-
resolverAddress = resolvedData['1'];
|
|
71
|
-
|
|
77
|
+
resolverAddress = specificResolver || resolvedData['1'];
|
|
78
|
+
if (specificResolver) {
|
|
79
|
+
recordData = resolvedData;
|
|
80
|
+
}
|
|
81
|
+
else {
|
|
82
|
+
;
|
|
83
|
+
[recordData] = await resolverMulticallWrapper.decode(resolvedData['0']);
|
|
84
|
+
}
|
|
72
85
|
}
|
|
73
86
|
const matchAddress = recordData[calls.findIndex((x) => x.key === '60')];
|
|
74
87
|
return {
|
|
@@ -160,10 +173,10 @@ const formatRecords = async ({ _getText, _getAddr, _getContentHash, }, data, cal
|
|
|
160
173
|
}
|
|
161
174
|
return returnedResponse;
|
|
162
175
|
};
|
|
163
|
-
const graphFetch = async ({ gqlInstance }, name, wantedRecords) => {
|
|
176
|
+
const graphFetch = async ({ gqlInstance }, name, wantedRecords, resolverAddress) => {
|
|
164
177
|
const query = gqlInstance.gql `
|
|
165
|
-
query getRecords($
|
|
166
|
-
|
|
178
|
+
query getRecords($id: String!) {
|
|
179
|
+
domain(id: $id) {
|
|
167
180
|
isMigrated
|
|
168
181
|
createdAt
|
|
169
182
|
resolver {
|
|
@@ -177,12 +190,39 @@ const graphFetch = async ({ gqlInstance }, name, wantedRecords) => {
|
|
|
177
190
|
}
|
|
178
191
|
}
|
|
179
192
|
}
|
|
193
|
+
`;
|
|
194
|
+
const customResolverQuery = gqlInstance.gql `
|
|
195
|
+
query getRecordsWithCustomResolver($id: String!, $resolverId: String!) {
|
|
196
|
+
domain(id: $id) {
|
|
197
|
+
isMigrated
|
|
198
|
+
createdAt
|
|
199
|
+
}
|
|
200
|
+
resolver(id: $resolverId) {
|
|
201
|
+
texts
|
|
202
|
+
coinTypes
|
|
203
|
+
contentHash
|
|
204
|
+
addr {
|
|
205
|
+
id
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
}
|
|
180
209
|
`;
|
|
181
210
|
const client = gqlInstance.client;
|
|
182
|
-
const
|
|
183
|
-
|
|
211
|
+
const id = (0, normalise_1.namehash)(name);
|
|
212
|
+
let domain;
|
|
213
|
+
let resolverResponse;
|
|
214
|
+
if (!resolverAddress) {
|
|
215
|
+
;
|
|
216
|
+
({ domain } = await client.request(query, { id }));
|
|
217
|
+
resolverResponse = domain?.resolver;
|
|
218
|
+
}
|
|
219
|
+
else {
|
|
220
|
+
const resolverId = `${resolverAddress}-${id}`;
|
|
221
|
+
({ resolver: resolverResponse, domain } = await client.request(customResolverQuery, { id, resolverId }));
|
|
222
|
+
}
|
|
223
|
+
if (!domain)
|
|
184
224
|
return;
|
|
185
|
-
const
|
|
225
|
+
const { isMigrated, createdAt } = domain;
|
|
186
226
|
let returnedRecords = {};
|
|
187
227
|
if (!resolverResponse)
|
|
188
228
|
return { isMigrated, createdAt };
|
|
@@ -190,7 +230,7 @@ const graphFetch = async ({ gqlInstance }, name, wantedRecords) => {
|
|
|
190
230
|
return {
|
|
191
231
|
isMigrated,
|
|
192
232
|
createdAt,
|
|
193
|
-
graphResolverAddress: resolverResponse.address,
|
|
233
|
+
graphResolverAddress: resolverResponse.address || resolverAddress,
|
|
194
234
|
};
|
|
195
235
|
Object.keys(wantedRecords).forEach((key) => {
|
|
196
236
|
const data = wantedRecords[key];
|
|
@@ -207,18 +247,22 @@ const graphFetch = async ({ gqlInstance }, name, wantedRecords) => {
|
|
|
207
247
|
...returnedRecords,
|
|
208
248
|
isMigrated,
|
|
209
249
|
createdAt,
|
|
210
|
-
graphResolverAddress: resolverResponse.address,
|
|
250
|
+
graphResolverAddress: resolverResponse.address || resolverAddress,
|
|
211
251
|
};
|
|
212
252
|
};
|
|
213
253
|
const getProfileFromName = async ({ contracts, gqlInstance, _getAddr, _getContentHash, _getText, resolverMulticallWrapper, multicallWrapper, }, name, options) => {
|
|
214
|
-
const
|
|
215
|
-
|
|
254
|
+
const { resolverAddress, ..._options } = options || {};
|
|
255
|
+
const optsLength = Object.keys(_options).length;
|
|
256
|
+
const usingOptions = !optsLength || _options?.texts === true || _options?.coinTypes === true
|
|
257
|
+
? optsLength
|
|
258
|
+
? _options
|
|
259
|
+
: { contentHash: true, texts: true, coinTypes: true }
|
|
216
260
|
: undefined;
|
|
217
|
-
const graphResult = await graphFetch({ gqlInstance }, name, usingOptions);
|
|
261
|
+
const graphResult = await graphFetch({ gqlInstance }, name, usingOptions, resolverAddress);
|
|
218
262
|
if (!graphResult)
|
|
219
263
|
return;
|
|
220
264
|
const { isMigrated, createdAt, graphResolverAddress, ...wantedRecords } = graphResult;
|
|
221
|
-
if (!graphResolverAddress)
|
|
265
|
+
if (!graphResolverAddress && !options?.resolverAddress)
|
|
222
266
|
return { isMigrated, createdAt, message: "Name doesn't have a resolver" };
|
|
223
267
|
const result = await getDataForName({
|
|
224
268
|
contracts,
|
|
@@ -227,7 +271,7 @@ const getProfileFromName = async ({ contracts, gqlInstance, _getAddr, _getConten
|
|
|
227
271
|
_getText,
|
|
228
272
|
resolverMulticallWrapper,
|
|
229
273
|
multicallWrapper,
|
|
230
|
-
}, name, usingOptions ? wantedRecords : options, graphResolverAddress);
|
|
274
|
+
}, name, usingOptions ? wantedRecords : options, graphResolverAddress, options?.resolverAddress);
|
|
231
275
|
if (!result)
|
|
232
276
|
return { isMigrated, createdAt, message: "Records fetch didn't complete" };
|
|
233
277
|
return { ...result, isMigrated, createdAt, message: undefined };
|
|
@@ -3,6 +3,7 @@ declare type ProfileOptions = {
|
|
|
3
3
|
contentHash?: boolean;
|
|
4
4
|
texts?: boolean | string[];
|
|
5
5
|
coinTypes?: boolean | string[];
|
|
6
|
+
resolverAddress?: string;
|
|
6
7
|
};
|
|
7
8
|
export default function ({ getProfile }: ENSArgs<'getProfile'>, name: string, options?: ProfileOptions): Promise<{
|
|
8
9
|
isMigrated: boolean | null;
|
package/dist/cjs/index.d.ts
CHANGED
|
@@ -133,11 +133,13 @@ export declare class ENS {
|
|
|
133
133
|
}>;
|
|
134
134
|
decode: ({ multicallWrapper }: ENSArgs<"multicallWrapper">, data: string, ...items: BatchFunctionResult<RawFunction>[]) => Promise<any[] | undefined>;
|
|
135
135
|
}>;
|
|
136
|
-
getProfile: (nameOrAddress: string, options?: {
|
|
136
|
+
getProfile: (nameOrAddress: string, options?: ({
|
|
137
137
|
contentHash?: boolean | undefined;
|
|
138
138
|
texts?: boolean | string[] | undefined;
|
|
139
139
|
coinTypes?: boolean | string[] | undefined;
|
|
140
|
-
}
|
|
140
|
+
} & {
|
|
141
|
+
resolverAddress?: string | undefined;
|
|
142
|
+
}) | undefined) => Promise<{
|
|
141
143
|
isMigrated: boolean | null;
|
|
142
144
|
createdAt: string | null;
|
|
143
145
|
address?: string | undefined;
|
|
@@ -166,6 +168,7 @@ export declare class ENS {
|
|
|
166
168
|
contentHash?: boolean | undefined;
|
|
167
169
|
texts?: boolean | string[] | undefined;
|
|
168
170
|
coinTypes?: boolean | string[] | undefined;
|
|
171
|
+
resolverAddress?: string | undefined;
|
|
169
172
|
} | undefined) => Promise<{
|
|
170
173
|
isMigrated: boolean | null;
|
|
171
174
|
createdAt: string | null;
|
package/dist/cjs/index.js
CHANGED
|
@@ -90,7 +90,7 @@ class ENS {
|
|
|
90
90
|
await thisRef.checkInitialProvider();
|
|
91
91
|
// import the module dynamically
|
|
92
92
|
const mod = await Promise.resolve().then(() => __importStar(require(
|
|
93
|
-
/* webpackMode: "lazy", webpackChunkName: "[request]", webpackPreload: true */
|
|
93
|
+
/* webpackMode: "lazy", webpackChunkName: "[request]", webpackPreload: true, webpackExclude: /.*\.ts$/ */
|
|
94
94
|
`./functions/${path}`)));
|
|
95
95
|
// if combine isn't specified, run normally
|
|
96
96
|
// otherwise, create a function from the raw and decode functions
|
package/dist/cjs/utils/labels.js
CHANGED
|
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.checkLocalStorageSize = exports.truncateUndecryptedName = exports.decryptName = exports.checkIsDecrypted = exports.parseName = exports.encodeLabel = exports.checkLabel = exports.saveName = exports.saveLabel = exports.isEncodedLabelhash = exports.encodeLabelhash = exports.decodeLabelhash = exports.keccakFromString = exports.labelhash = void 0;
|
|
4
4
|
const utils_1 = require("ethers/lib/utils");
|
|
5
5
|
const format_1 = require("./format");
|
|
6
|
+
const hasLocalStorage = typeof localStorage !== 'undefined';
|
|
6
7
|
const labelhash = (input) => (0, utils_1.solidityKeccak256)(['string'], [input]);
|
|
7
8
|
exports.labelhash = labelhash;
|
|
8
9
|
const keccakFromString = (input) => (0, exports.labelhash)(input);
|
|
@@ -32,12 +33,12 @@ function isEncodedLabelhash(hash) {
|
|
|
32
33
|
}
|
|
33
34
|
exports.isEncodedLabelhash = isEncodedLabelhash;
|
|
34
35
|
function getLabels() {
|
|
35
|
-
return
|
|
36
|
+
return hasLocalStorage
|
|
36
37
|
? JSON.parse(localStorage.getItem('ensjs:labels')) || {}
|
|
37
38
|
: {};
|
|
38
39
|
}
|
|
39
40
|
function _saveLabel(hash, label) {
|
|
40
|
-
if (!
|
|
41
|
+
if (!hasLocalStorage)
|
|
41
42
|
return hash;
|
|
42
43
|
const labels = getLabels();
|
|
43
44
|
localStorage.setItem('ensjs:labels', JSON.stringify({
|
|
@@ -97,7 +98,7 @@ exports.decryptName = decryptName;
|
|
|
97
98
|
const truncateUndecryptedName = (name) => (0, format_1.truncateFormat)(name);
|
|
98
99
|
exports.truncateUndecryptedName = truncateUndecryptedName;
|
|
99
100
|
function checkLocalStorageSize() {
|
|
100
|
-
if (!
|
|
101
|
+
if (!hasLocalStorage)
|
|
101
102
|
return 'Empty (0 KB)';
|
|
102
103
|
let allStrings = '';
|
|
103
104
|
for (const key in window.localStorage) {
|
|
@@ -26,5 +26,8 @@ declare type ProfileOptions = {
|
|
|
26
26
|
texts?: boolean | string[];
|
|
27
27
|
coinTypes?: boolean | string[];
|
|
28
28
|
};
|
|
29
|
-
|
|
29
|
+
declare type InputProfileOptions = ProfileOptions & {
|
|
30
|
+
resolverAddress?: string;
|
|
31
|
+
};
|
|
32
|
+
export default function ({ contracts, gqlInstance, getName, _getAddr, _getContentHash, _getText, resolverMulticallWrapper, multicallWrapper, }: ENSArgs<'contracts' | 'gqlInstance' | 'getName' | '_getText' | '_getAddr' | '_getContentHash' | 'resolverMulticallWrapper' | 'multicallWrapper'>, nameOrAddress: string, options?: InputProfileOptions): Promise<ResolvedProfile | undefined>;
|
|
30
33
|
export {};
|
|
@@ -2,6 +2,7 @@ import { formatsByName } from '@ensdomains/address-encoder';
|
|
|
2
2
|
import { ethers } from 'ethers';
|
|
3
3
|
import { decodeContenthash } from '../utils/contentHash';
|
|
4
4
|
import { hexEncodeName } from '../utils/hexEncodedName';
|
|
5
|
+
import { namehash } from '../utils/normalise';
|
|
5
6
|
import { parseInputType } from '../utils/validation';
|
|
6
7
|
const makeMulticallData = async ({ _getAddr, _getContentHash, _getText, resolverMulticallWrapper, }, name, options) => {
|
|
7
8
|
let calls = [];
|
|
@@ -47,13 +48,19 @@ const fetchWithoutResolverMulticall = async ({ multicallWrapper }, calls, resolv
|
|
|
47
48
|
}));
|
|
48
49
|
return (await multicallWrapper(callsWithResolver)).map((x) => x[1]);
|
|
49
50
|
};
|
|
50
|
-
const getDataForName = async ({ contracts, _getAddr, _getContentHash, _getText, resolverMulticallWrapper, multicallWrapper, }, name, options, fallbackResolver) => {
|
|
51
|
+
const getDataForName = async ({ contracts, _getAddr, _getContentHash, _getText, resolverMulticallWrapper, multicallWrapper, }, name, options, fallbackResolver, specificResolver) => {
|
|
51
52
|
const universalResolver = await contracts?.getUniversalResolver();
|
|
52
53
|
const { data, calls } = await makeMulticallData({ _getAddr, _getContentHash, _getText, resolverMulticallWrapper }, name, options);
|
|
53
54
|
let resolvedData;
|
|
54
55
|
let useFallbackResolver = false;
|
|
55
56
|
try {
|
|
56
|
-
|
|
57
|
+
if (specificResolver) {
|
|
58
|
+
const publicResolver = await contracts?.getPublicResolver(undefined, specificResolver);
|
|
59
|
+
resolvedData = await publicResolver?.callStatic.multicall(calls.map((x) => x.data));
|
|
60
|
+
}
|
|
61
|
+
else {
|
|
62
|
+
resolvedData = await universalResolver?.resolve(hexEncodeName(name), data);
|
|
63
|
+
}
|
|
57
64
|
}
|
|
58
65
|
catch {
|
|
59
66
|
useFallbackResolver = true;
|
|
@@ -61,12 +68,18 @@ const getDataForName = async ({ contracts, _getAddr, _getContentHash, _getText,
|
|
|
61
68
|
let resolverAddress;
|
|
62
69
|
let recordData;
|
|
63
70
|
if (useFallbackResolver) {
|
|
64
|
-
resolverAddress = fallbackResolver;
|
|
71
|
+
resolverAddress = specificResolver || fallbackResolver;
|
|
65
72
|
recordData = await fetchWithoutResolverMulticall({ multicallWrapper }, calls, resolverAddress);
|
|
66
73
|
}
|
|
67
74
|
else {
|
|
68
|
-
resolverAddress = resolvedData['1'];
|
|
69
|
-
|
|
75
|
+
resolverAddress = specificResolver || resolvedData['1'];
|
|
76
|
+
if (specificResolver) {
|
|
77
|
+
recordData = resolvedData;
|
|
78
|
+
}
|
|
79
|
+
else {
|
|
80
|
+
;
|
|
81
|
+
[recordData] = await resolverMulticallWrapper.decode(resolvedData['0']);
|
|
82
|
+
}
|
|
70
83
|
}
|
|
71
84
|
const matchAddress = recordData[calls.findIndex((x) => x.key === '60')];
|
|
72
85
|
return {
|
|
@@ -158,10 +171,10 @@ const formatRecords = async ({ _getText, _getAddr, _getContentHash, }, data, cal
|
|
|
158
171
|
}
|
|
159
172
|
return returnedResponse;
|
|
160
173
|
};
|
|
161
|
-
const graphFetch = async ({ gqlInstance }, name, wantedRecords) => {
|
|
174
|
+
const graphFetch = async ({ gqlInstance }, name, wantedRecords, resolverAddress) => {
|
|
162
175
|
const query = gqlInstance.gql `
|
|
163
|
-
query getRecords($
|
|
164
|
-
|
|
176
|
+
query getRecords($id: String!) {
|
|
177
|
+
domain(id: $id) {
|
|
165
178
|
isMigrated
|
|
166
179
|
createdAt
|
|
167
180
|
resolver {
|
|
@@ -175,12 +188,39 @@ const graphFetch = async ({ gqlInstance }, name, wantedRecords) => {
|
|
|
175
188
|
}
|
|
176
189
|
}
|
|
177
190
|
}
|
|
191
|
+
`;
|
|
192
|
+
const customResolverQuery = gqlInstance.gql `
|
|
193
|
+
query getRecordsWithCustomResolver($id: String!, $resolverId: String!) {
|
|
194
|
+
domain(id: $id) {
|
|
195
|
+
isMigrated
|
|
196
|
+
createdAt
|
|
197
|
+
}
|
|
198
|
+
resolver(id: $resolverId) {
|
|
199
|
+
texts
|
|
200
|
+
coinTypes
|
|
201
|
+
contentHash
|
|
202
|
+
addr {
|
|
203
|
+
id
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
}
|
|
178
207
|
`;
|
|
179
208
|
const client = gqlInstance.client;
|
|
180
|
-
const
|
|
181
|
-
|
|
209
|
+
const id = namehash(name);
|
|
210
|
+
let domain;
|
|
211
|
+
let resolverResponse;
|
|
212
|
+
if (!resolverAddress) {
|
|
213
|
+
;
|
|
214
|
+
({ domain } = await client.request(query, { id }));
|
|
215
|
+
resolverResponse = domain?.resolver;
|
|
216
|
+
}
|
|
217
|
+
else {
|
|
218
|
+
const resolverId = `${resolverAddress}-${id}`;
|
|
219
|
+
({ resolver: resolverResponse, domain } = await client.request(customResolverQuery, { id, resolverId }));
|
|
220
|
+
}
|
|
221
|
+
if (!domain)
|
|
182
222
|
return;
|
|
183
|
-
const
|
|
223
|
+
const { isMigrated, createdAt } = domain;
|
|
184
224
|
let returnedRecords = {};
|
|
185
225
|
if (!resolverResponse)
|
|
186
226
|
return { isMigrated, createdAt };
|
|
@@ -188,7 +228,7 @@ const graphFetch = async ({ gqlInstance }, name, wantedRecords) => {
|
|
|
188
228
|
return {
|
|
189
229
|
isMigrated,
|
|
190
230
|
createdAt,
|
|
191
|
-
graphResolverAddress: resolverResponse.address,
|
|
231
|
+
graphResolverAddress: resolverResponse.address || resolverAddress,
|
|
192
232
|
};
|
|
193
233
|
Object.keys(wantedRecords).forEach((key) => {
|
|
194
234
|
const data = wantedRecords[key];
|
|
@@ -205,18 +245,22 @@ const graphFetch = async ({ gqlInstance }, name, wantedRecords) => {
|
|
|
205
245
|
...returnedRecords,
|
|
206
246
|
isMigrated,
|
|
207
247
|
createdAt,
|
|
208
|
-
graphResolverAddress: resolverResponse.address,
|
|
248
|
+
graphResolverAddress: resolverResponse.address || resolverAddress,
|
|
209
249
|
};
|
|
210
250
|
};
|
|
211
251
|
const getProfileFromName = async ({ contracts, gqlInstance, _getAddr, _getContentHash, _getText, resolverMulticallWrapper, multicallWrapper, }, name, options) => {
|
|
212
|
-
const
|
|
213
|
-
|
|
252
|
+
const { resolverAddress, ..._options } = options || {};
|
|
253
|
+
const optsLength = Object.keys(_options).length;
|
|
254
|
+
const usingOptions = !optsLength || _options?.texts === true || _options?.coinTypes === true
|
|
255
|
+
? optsLength
|
|
256
|
+
? _options
|
|
257
|
+
: { contentHash: true, texts: true, coinTypes: true }
|
|
214
258
|
: undefined;
|
|
215
|
-
const graphResult = await graphFetch({ gqlInstance }, name, usingOptions);
|
|
259
|
+
const graphResult = await graphFetch({ gqlInstance }, name, usingOptions, resolverAddress);
|
|
216
260
|
if (!graphResult)
|
|
217
261
|
return;
|
|
218
262
|
const { isMigrated, createdAt, graphResolverAddress, ...wantedRecords } = graphResult;
|
|
219
|
-
if (!graphResolverAddress)
|
|
263
|
+
if (!graphResolverAddress && !options?.resolverAddress)
|
|
220
264
|
return { isMigrated, createdAt, message: "Name doesn't have a resolver" };
|
|
221
265
|
const result = await getDataForName({
|
|
222
266
|
contracts,
|
|
@@ -225,7 +269,7 @@ const getProfileFromName = async ({ contracts, gqlInstance, _getAddr, _getConten
|
|
|
225
269
|
_getText,
|
|
226
270
|
resolverMulticallWrapper,
|
|
227
271
|
multicallWrapper,
|
|
228
|
-
}, name, usingOptions ? wantedRecords : options, graphResolverAddress);
|
|
272
|
+
}, name, usingOptions ? wantedRecords : options, graphResolverAddress, options?.resolverAddress);
|
|
229
273
|
if (!result)
|
|
230
274
|
return { isMigrated, createdAt, message: "Records fetch didn't complete" };
|
|
231
275
|
return { ...result, isMigrated, createdAt, message: undefined };
|
|
@@ -3,6 +3,7 @@ declare type ProfileOptions = {
|
|
|
3
3
|
contentHash?: boolean;
|
|
4
4
|
texts?: boolean | string[];
|
|
5
5
|
coinTypes?: boolean | string[];
|
|
6
|
+
resolverAddress?: string;
|
|
6
7
|
};
|
|
7
8
|
export default function ({ getProfile }: ENSArgs<'getProfile'>, name: string, options?: ProfileOptions): Promise<{
|
|
8
9
|
isMigrated: boolean | null;
|
package/dist/esm/index.d.ts
CHANGED
|
@@ -133,11 +133,13 @@ export declare class ENS {
|
|
|
133
133
|
}>;
|
|
134
134
|
decode: ({ multicallWrapper }: ENSArgs<"multicallWrapper">, data: string, ...items: BatchFunctionResult<RawFunction>[]) => Promise<any[] | undefined>;
|
|
135
135
|
}>;
|
|
136
|
-
getProfile: (nameOrAddress: string, options?: {
|
|
136
|
+
getProfile: (nameOrAddress: string, options?: ({
|
|
137
137
|
contentHash?: boolean | undefined;
|
|
138
138
|
texts?: boolean | string[] | undefined;
|
|
139
139
|
coinTypes?: boolean | string[] | undefined;
|
|
140
|
-
}
|
|
140
|
+
} & {
|
|
141
|
+
resolverAddress?: string | undefined;
|
|
142
|
+
}) | undefined) => Promise<{
|
|
141
143
|
isMigrated: boolean | null;
|
|
142
144
|
createdAt: string | null;
|
|
143
145
|
address?: string | undefined;
|
|
@@ -166,6 +168,7 @@ export declare class ENS {
|
|
|
166
168
|
contentHash?: boolean | undefined;
|
|
167
169
|
texts?: boolean | string[] | undefined;
|
|
168
170
|
coinTypes?: boolean | string[] | undefined;
|
|
171
|
+
resolverAddress?: string | undefined;
|
|
169
172
|
} | undefined) => Promise<{
|
|
170
173
|
isMigrated: boolean | null;
|
|
171
174
|
createdAt: string | null;
|
package/dist/esm/index.js
CHANGED
|
@@ -53,7 +53,7 @@ export class ENS {
|
|
|
53
53
|
await thisRef.checkInitialProvider();
|
|
54
54
|
// import the module dynamically
|
|
55
55
|
const mod = await import(
|
|
56
|
-
/* webpackMode: "lazy", webpackChunkName: "[request]", webpackPreload: true */
|
|
56
|
+
/* webpackMode: "lazy", webpackChunkName: "[request]", webpackPreload: true, webpackExclude: /.*\.ts$/ */
|
|
57
57
|
`./functions/${path}`);
|
|
58
58
|
// if combine isn't specified, run normally
|
|
59
59
|
// otherwise, create a function from the raw and decode functions
|
package/dist/esm/utils/labels.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { solidityKeccak256 } from 'ethers/lib/utils';
|
|
2
2
|
import { truncateFormat } from './format';
|
|
3
|
+
const hasLocalStorage = typeof localStorage !== 'undefined';
|
|
3
4
|
export const labelhash = (input) => solidityKeccak256(['string'], [input]);
|
|
4
5
|
export const keccakFromString = (input) => labelhash(input);
|
|
5
6
|
export function decodeLabelhash(hash) {
|
|
@@ -24,12 +25,12 @@ export function isEncodedLabelhash(hash) {
|
|
|
24
25
|
return hash.startsWith('[') && hash.endsWith(']') && hash.length === 66;
|
|
25
26
|
}
|
|
26
27
|
function getLabels() {
|
|
27
|
-
return
|
|
28
|
+
return hasLocalStorage
|
|
28
29
|
? JSON.parse(localStorage.getItem('ensjs:labels')) || {}
|
|
29
30
|
: {};
|
|
30
31
|
}
|
|
31
32
|
function _saveLabel(hash, label) {
|
|
32
|
-
if (!
|
|
33
|
+
if (!hasLocalStorage)
|
|
33
34
|
return hash;
|
|
34
35
|
const labels = getLabels();
|
|
35
36
|
localStorage.setItem('ensjs:labels', JSON.stringify({
|
|
@@ -81,7 +82,7 @@ export function decryptName(name) {
|
|
|
81
82
|
}
|
|
82
83
|
export const truncateUndecryptedName = (name) => truncateFormat(name);
|
|
83
84
|
export function checkLocalStorageSize() {
|
|
84
|
-
if (!
|
|
85
|
+
if (!hasLocalStorage)
|
|
85
86
|
return 'Empty (0 KB)';
|
|
86
87
|
let allStrings = '';
|
|
87
88
|
for (const key in window.localStorage) {
|
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.8",
|
|
4
4
|
"description": "ENS javascript library for contract interaction",
|
|
5
5
|
"main": "./dist/cjs/index.js",
|
|
6
6
|
"types": "./dist/cjs/index.d.ts",
|
|
@@ -52,7 +52,7 @@
|
|
|
52
52
|
},
|
|
53
53
|
"devDependencies": {
|
|
54
54
|
"@ensdomains/buffer": "^0.0.13",
|
|
55
|
-
"@ensdomains/ens-test-env": "0.1.
|
|
55
|
+
"@ensdomains/ens-test-env": "0.1.5",
|
|
56
56
|
"@ethersproject/abi": "^5.6.0",
|
|
57
57
|
"@ethersproject/providers": "^5.6.2",
|
|
58
58
|
"@nomiclabs/hardhat-ethers": "^2.0.5",
|
|
@@ -83,5 +83,5 @@
|
|
|
83
83
|
"peerDependencies": {
|
|
84
84
|
"ethers": "*"
|
|
85
85
|
},
|
|
86
|
-
"stableVersion": "3.0.0-alpha.
|
|
86
|
+
"stableVersion": "3.0.0-alpha.7"
|
|
87
87
|
}
|
|
@@ -2,9 +2,14 @@ import { ENS } from '..'
|
|
|
2
2
|
import setup from '../tests/setup'
|
|
3
3
|
|
|
4
4
|
let ENSInstance: ENS
|
|
5
|
+
let revert: Awaited<ReturnType<typeof setup>>['revert']
|
|
5
6
|
|
|
6
7
|
beforeAll(async () => {
|
|
7
|
-
;({ ENSInstance } = await setup())
|
|
8
|
+
;({ ENSInstance, revert } = await setup())
|
|
9
|
+
})
|
|
10
|
+
|
|
11
|
+
afterAll(async () => {
|
|
12
|
+
await revert()
|
|
8
13
|
})
|
|
9
14
|
|
|
10
15
|
const checkRecords = (
|
|
@@ -88,6 +93,16 @@ describe('getProfile', () => {
|
|
|
88
93
|
})
|
|
89
94
|
checkRecords(result)
|
|
90
95
|
})
|
|
96
|
+
it('should return a profile object for a specified resolver', async () => {
|
|
97
|
+
const result = await ENSInstance.getProfile('saganaki.xyz', {
|
|
98
|
+
resolverAddress: '0x12299799a50340fb860d276805e78550cbad3de3',
|
|
99
|
+
})
|
|
100
|
+
expect(result).toBeDefined()
|
|
101
|
+
expect(result?.address).toBe('0x157545BfD441453921049998128Ff090c1c11230')
|
|
102
|
+
expect(result?.resolverAddress).toBe(
|
|
103
|
+
'0x12299799a50340fb860d276805e78550cbad3de3',
|
|
104
|
+
)
|
|
105
|
+
})
|
|
91
106
|
it('should return undefined for an unregistered name', async () => {
|
|
92
107
|
const result = await ENSInstance.getProfile('test123123123cool.eth')
|
|
93
108
|
expect(result).toBeUndefined()
|
|
@@ -3,6 +3,7 @@ import { ethers } from 'ethers'
|
|
|
3
3
|
import { ENSArgs } from '..'
|
|
4
4
|
import { decodeContenthash, DecodedContentHash } from '../utils/contentHash'
|
|
5
5
|
import { hexEncodeName } from '../utils/hexEncodedName'
|
|
6
|
+
import { namehash } from '../utils/normalise'
|
|
6
7
|
import { parseInputType } from '../utils/validation'
|
|
7
8
|
|
|
8
9
|
type InternalProfileOptions = {
|
|
@@ -136,7 +137,8 @@ const getDataForName = async (
|
|
|
136
137
|
>,
|
|
137
138
|
name: string,
|
|
138
139
|
options: InternalProfileOptions,
|
|
139
|
-
fallbackResolver
|
|
140
|
+
fallbackResolver?: string,
|
|
141
|
+
specificResolver?: string,
|
|
140
142
|
) => {
|
|
141
143
|
const universalResolver = await contracts?.getUniversalResolver()
|
|
142
144
|
|
|
@@ -149,7 +151,17 @@ const getDataForName = async (
|
|
|
149
151
|
let resolvedData: any
|
|
150
152
|
let useFallbackResolver = false
|
|
151
153
|
try {
|
|
152
|
-
|
|
154
|
+
if (specificResolver) {
|
|
155
|
+
const publicResolver = await contracts?.getPublicResolver(
|
|
156
|
+
undefined,
|
|
157
|
+
specificResolver,
|
|
158
|
+
)
|
|
159
|
+
resolvedData = await publicResolver?.callStatic.multicall(
|
|
160
|
+
calls.map((x) => x.data),
|
|
161
|
+
)
|
|
162
|
+
} else {
|
|
163
|
+
resolvedData = await universalResolver?.resolve(hexEncodeName(name), data)
|
|
164
|
+
}
|
|
153
165
|
} catch {
|
|
154
166
|
useFallbackResolver = true
|
|
155
167
|
}
|
|
@@ -158,15 +170,19 @@ const getDataForName = async (
|
|
|
158
170
|
let recordData: any
|
|
159
171
|
|
|
160
172
|
if (useFallbackResolver) {
|
|
161
|
-
resolverAddress = fallbackResolver
|
|
173
|
+
resolverAddress = specificResolver || fallbackResolver!
|
|
162
174
|
recordData = await fetchWithoutResolverMulticall(
|
|
163
175
|
{ multicallWrapper },
|
|
164
176
|
calls,
|
|
165
177
|
resolverAddress,
|
|
166
178
|
)
|
|
167
179
|
} else {
|
|
168
|
-
resolverAddress = resolvedData['1']
|
|
169
|
-
|
|
180
|
+
resolverAddress = specificResolver || resolvedData['1']
|
|
181
|
+
if (specificResolver) {
|
|
182
|
+
recordData = resolvedData
|
|
183
|
+
} else {
|
|
184
|
+
;[recordData] = await resolverMulticallWrapper.decode(resolvedData['0'])
|
|
185
|
+
}
|
|
170
186
|
}
|
|
171
187
|
|
|
172
188
|
const matchAddress = recordData[calls.findIndex((x) => x.key === '60')]
|
|
@@ -298,10 +314,11 @@ const graphFetch = async (
|
|
|
298
314
|
{ gqlInstance }: ENSArgs<'gqlInstance'>,
|
|
299
315
|
name: string,
|
|
300
316
|
wantedRecords?: ProfileOptions,
|
|
317
|
+
resolverAddress?: string,
|
|
301
318
|
) => {
|
|
302
319
|
const query = gqlInstance.gql`
|
|
303
|
-
query getRecords($
|
|
304
|
-
|
|
320
|
+
query getRecords($id: String!) {
|
|
321
|
+
domain(id: $id) {
|
|
305
322
|
isMigrated
|
|
306
323
|
createdAt
|
|
307
324
|
resolver {
|
|
@@ -317,13 +334,44 @@ const graphFetch = async (
|
|
|
317
334
|
}
|
|
318
335
|
`
|
|
319
336
|
|
|
337
|
+
const customResolverQuery = gqlInstance.gql`
|
|
338
|
+
query getRecordsWithCustomResolver($id: String!, $resolverId: String!) {
|
|
339
|
+
domain(id: $id) {
|
|
340
|
+
isMigrated
|
|
341
|
+
createdAt
|
|
342
|
+
}
|
|
343
|
+
resolver(id: $resolverId) {
|
|
344
|
+
texts
|
|
345
|
+
coinTypes
|
|
346
|
+
contentHash
|
|
347
|
+
addr {
|
|
348
|
+
id
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
`
|
|
353
|
+
|
|
320
354
|
const client = gqlInstance.client
|
|
321
355
|
|
|
322
|
-
const
|
|
356
|
+
const id = namehash(name)
|
|
323
357
|
|
|
324
|
-
|
|
358
|
+
let domain: any
|
|
359
|
+
let resolverResponse: any
|
|
325
360
|
|
|
326
|
-
|
|
361
|
+
if (!resolverAddress) {
|
|
362
|
+
;({ domain } = await client.request(query, { id }))
|
|
363
|
+
resolverResponse = domain?.resolver
|
|
364
|
+
} else {
|
|
365
|
+
const resolverId = `${resolverAddress}-${id}`
|
|
366
|
+
;({ resolver: resolverResponse, domain } = await client.request(
|
|
367
|
+
customResolverQuery,
|
|
368
|
+
{ id, resolverId },
|
|
369
|
+
))
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
if (!domain) return
|
|
373
|
+
|
|
374
|
+
const { isMigrated, createdAt } = domain
|
|
327
375
|
|
|
328
376
|
let returnedRecords: ProfileResponse = {}
|
|
329
377
|
|
|
@@ -333,7 +381,7 @@ const graphFetch = async (
|
|
|
333
381
|
return {
|
|
334
382
|
isMigrated,
|
|
335
383
|
createdAt,
|
|
336
|
-
graphResolverAddress: resolverResponse.address,
|
|
384
|
+
graphResolverAddress: resolverResponse.address || resolverAddress,
|
|
337
385
|
}
|
|
338
386
|
|
|
339
387
|
Object.keys(wantedRecords).forEach((key: string) => {
|
|
@@ -351,7 +399,7 @@ const graphFetch = async (
|
|
|
351
399
|
...returnedRecords,
|
|
352
400
|
isMigrated,
|
|
353
401
|
createdAt,
|
|
354
|
-
graphResolverAddress: resolverResponse.address,
|
|
402
|
+
graphResolverAddress: resolverResponse.address || resolverAddress,
|
|
355
403
|
}
|
|
356
404
|
}
|
|
357
405
|
|
|
@@ -361,6 +409,10 @@ type ProfileOptions = {
|
|
|
361
409
|
coinTypes?: boolean | string[]
|
|
362
410
|
}
|
|
363
411
|
|
|
412
|
+
type InputProfileOptions = ProfileOptions & {
|
|
413
|
+
resolverAddress?: string
|
|
414
|
+
}
|
|
415
|
+
|
|
364
416
|
const getProfileFromName = async (
|
|
365
417
|
{
|
|
366
418
|
contracts,
|
|
@@ -380,13 +432,23 @@ const getProfileFromName = async (
|
|
|
380
432
|
| 'multicallWrapper'
|
|
381
433
|
>,
|
|
382
434
|
name: string,
|
|
383
|
-
options?:
|
|
435
|
+
options?: InputProfileOptions,
|
|
384
436
|
) => {
|
|
437
|
+
const { resolverAddress, ..._options } = options || {}
|
|
438
|
+
const optsLength = Object.keys(_options).length
|
|
385
439
|
const usingOptions =
|
|
386
|
-
!
|
|
387
|
-
?
|
|
440
|
+
!optsLength || _options?.texts === true || _options?.coinTypes === true
|
|
441
|
+
? optsLength
|
|
442
|
+
? _options
|
|
443
|
+
: { contentHash: true, texts: true, coinTypes: true }
|
|
388
444
|
: undefined
|
|
389
|
-
|
|
445
|
+
|
|
446
|
+
const graphResult = await graphFetch(
|
|
447
|
+
{ gqlInstance },
|
|
448
|
+
name,
|
|
449
|
+
usingOptions,
|
|
450
|
+
resolverAddress,
|
|
451
|
+
)
|
|
390
452
|
if (!graphResult) return
|
|
391
453
|
const {
|
|
392
454
|
isMigrated,
|
|
@@ -398,7 +460,7 @@ const getProfileFromName = async (
|
|
|
398
460
|
createdAt: string
|
|
399
461
|
graphResolverAddress?: string
|
|
400
462
|
} & InternalProfileOptions = graphResult
|
|
401
|
-
if (!graphResolverAddress)
|
|
463
|
+
if (!graphResolverAddress && !options?.resolverAddress)
|
|
402
464
|
return { isMigrated, createdAt, message: "Name doesn't have a resolver" }
|
|
403
465
|
const result = await getDataForName(
|
|
404
466
|
{
|
|
@@ -412,6 +474,7 @@ const getProfileFromName = async (
|
|
|
412
474
|
name,
|
|
413
475
|
usingOptions ? wantedRecords : (options as InternalProfileOptions),
|
|
414
476
|
graphResolverAddress,
|
|
477
|
+
options?.resolverAddress!,
|
|
415
478
|
)
|
|
416
479
|
if (!result)
|
|
417
480
|
return { isMigrated, createdAt, message: "Records fetch didn't complete" }
|
|
@@ -439,7 +502,7 @@ const getProfileFromAddress = async (
|
|
|
439
502
|
| 'multicallWrapper'
|
|
440
503
|
>,
|
|
441
504
|
address: string,
|
|
442
|
-
options?:
|
|
505
|
+
options?: InputProfileOptions,
|
|
443
506
|
) => {
|
|
444
507
|
let name
|
|
445
508
|
try {
|
|
@@ -492,7 +555,7 @@ export default async function (
|
|
|
492
555
|
| 'multicallWrapper'
|
|
493
556
|
>,
|
|
494
557
|
nameOrAddress: string,
|
|
495
|
-
options?:
|
|
558
|
+
options?: InputProfileOptions,
|
|
496
559
|
): Promise<ResolvedProfile | undefined> {
|
|
497
560
|
if (options && options.coinTypes && typeof options.coinTypes !== 'boolean') {
|
|
498
561
|
options.coinTypes = options.coinTypes.map((coin: string) => {
|
package/src/index.ts
CHANGED
|
@@ -217,7 +217,7 @@ export class ENS {
|
|
|
217
217
|
await thisRef.checkInitialProvider()
|
|
218
218
|
// import the module dynamically
|
|
219
219
|
const mod = await import(
|
|
220
|
-
/* webpackMode: "lazy", webpackChunkName: "[request]", webpackPreload: true */
|
|
220
|
+
/* webpackMode: "lazy", webpackChunkName: "[request]", webpackPreload: true, webpackExclude: /.*\.ts$/ */
|
|
221
221
|
`./functions/${path}`
|
|
222
222
|
)
|
|
223
223
|
|
package/src/utils/labels.ts
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { solidityKeccak256 } from 'ethers/lib/utils'
|
|
2
2
|
import { truncateFormat } from './format'
|
|
3
3
|
|
|
4
|
+
const hasLocalStorage = typeof localStorage !== 'undefined'
|
|
5
|
+
|
|
4
6
|
export const labelhash = (input: string) =>
|
|
5
7
|
solidityKeccak256(['string'], [input])
|
|
6
8
|
|
|
@@ -37,13 +39,13 @@ export function isEncodedLabelhash(hash: string) {
|
|
|
37
39
|
}
|
|
38
40
|
|
|
39
41
|
function getLabels() {
|
|
40
|
-
return
|
|
42
|
+
return hasLocalStorage
|
|
41
43
|
? JSON.parse(localStorage.getItem('ensjs:labels') as string) || {}
|
|
42
44
|
: {}
|
|
43
45
|
}
|
|
44
46
|
|
|
45
47
|
function _saveLabel(hash: string, label: any) {
|
|
46
|
-
if (!
|
|
48
|
+
if (!hasLocalStorage) return hash
|
|
47
49
|
const labels = getLabels()
|
|
48
50
|
localStorage.setItem(
|
|
49
51
|
'ensjs:labels',
|
|
@@ -106,7 +108,7 @@ export function decryptName(name: string) {
|
|
|
106
108
|
export const truncateUndecryptedName = (name: string) => truncateFormat(name)
|
|
107
109
|
|
|
108
110
|
export function checkLocalStorageSize() {
|
|
109
|
-
if (!
|
|
111
|
+
if (!hasLocalStorage) return 'Empty (0 KB)'
|
|
110
112
|
let allStrings = ''
|
|
111
113
|
for (const key in window.localStorage) {
|
|
112
114
|
if (Object.prototype.hasOwnProperty.call(window.localStorage, key)) {
|