@ensdomains/ensjs 3.0.0-alpha.1 → 3.0.0-alpha.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -0
- package/dist/cjs/functions/burnFuses.d.ts +1 -2
- package/dist/cjs/functions/burnFuses.js +3 -3
- package/dist/cjs/functions/createSubname.js +2 -1
- package/dist/cjs/functions/getFuses.js +3 -2
- package/dist/cjs/functions/getOwner.js +7 -6
- package/dist/cjs/functions/getProfile.d.ts +1 -1
- package/dist/cjs/functions/getProfile.js +49 -15
- package/dist/cjs/functions/getSpecificRecord.js +22 -5
- package/dist/cjs/functions/getSubnames.js +6 -6
- package/dist/cjs/functions/setRecords.d.ts +1 -2
- package/dist/cjs/functions/setRecords.js +3 -3
- package/dist/cjs/functions/setResolver.d.ts +1 -2
- package/dist/cjs/functions/setResolver.js +3 -3
- package/dist/cjs/functions/transferName.js +3 -2
- package/dist/cjs/functions/transferSubname.js +2 -1
- package/dist/cjs/functions/unwrapName.js +2 -1
- package/dist/cjs/index.js +1 -0
- package/dist/cjs/utils/makeHashIndexes.js +2 -2
- package/dist/cjs/utils/normalise.d.ts +1 -0
- package/dist/cjs/utils/normalise.js +20 -1
- package/dist/cjs/utils/registerHelpers.js +3 -4
- package/dist/esm/functions/burnFuses.d.ts +1 -2
- package/dist/esm/functions/burnFuses.js +3 -3
- package/dist/esm/functions/createSubname.js +2 -1
- package/dist/esm/functions/getFuses.js +4 -3
- package/dist/esm/functions/getOwner.js +7 -6
- package/dist/esm/functions/getProfile.d.ts +1 -1
- package/dist/esm/functions/getProfile.js +49 -15
- package/dist/esm/functions/getSpecificRecord.js +22 -5
- package/dist/esm/functions/getSubnames.js +3 -3
- package/dist/esm/functions/setRecords.d.ts +1 -2
- package/dist/esm/functions/setRecords.js +3 -3
- package/dist/esm/functions/setResolver.d.ts +1 -2
- package/dist/esm/functions/setResolver.js +3 -3
- package/dist/esm/functions/transferName.js +3 -2
- package/dist/esm/functions/transferSubname.js +2 -1
- package/dist/esm/functions/unwrapName.js +2 -1
- package/dist/esm/index.js +1 -0
- package/dist/esm/utils/makeHashIndexes.js +2 -2
- package/dist/esm/utils/normalise.d.ts +1 -0
- package/dist/esm/utils/normalise.js +18 -0
- package/dist/esm/utils/registerHelpers.js +3 -4
- package/package.json +3 -2
- package/src/functions/burnFuses.ts +3 -3
- package/src/functions/createSubname.ts +2 -1
- package/src/functions/getFuses.ts +4 -3
- package/src/functions/getOwner.ts +7 -7
- package/src/functions/getProfile.ts +77 -13
- package/src/functions/getSpecificRecord.ts +28 -8
- package/src/functions/getSubnames.ts +68 -66
- package/src/functions/setRecords.ts +3 -3
- package/src/functions/setResolver.ts +3 -3
- package/src/functions/transferName.ts +3 -2
- package/src/functions/transferSubname.ts +2 -1
- package/src/functions/unwrapName.ts +2 -1
- package/src/index.ts +1 -0
- package/src/tests/burnFuses.test.ts +3 -2
- package/src/tests/createSubname.test.ts +4 -5
- package/src/tests/deleteSubname.test.ts +4 -5
- package/src/tests/getOwner.test.ts +10 -0
- package/src/tests/getProfile.test.ts +28 -10
- package/src/tests/normalise.test.ts +22 -0
- package/src/tests/setRecords.test.ts +3 -3
- package/src/tests/transferName.test.ts +3 -2
- package/src/tests/transferSubname.test.ts +4 -5
- package/src/tests/unwrapName.test.ts +2 -1
- package/src/tests/wrapName.test.ts +4 -7
- package/src/utils/makeHashIndexes.ts +4 -4
- package/src/utils/normalise.ts +23 -0
- package/src/utils/registerHelpers.ts +3 -4
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { ethers } from 'ethers';
|
|
2
2
|
import generateFuseInput from '../utils/generateFuseInput';
|
|
3
|
+
import { namehash } from '../utils/normalise';
|
|
3
4
|
export default async function ({ contracts, provider }, { name, owner, resolverAddress, contract, options, ...wrapperArgs }) {
|
|
4
5
|
const signer = provider?.getSigner(options?.addressOrIndex);
|
|
5
6
|
if (!signer) {
|
|
@@ -17,7 +18,7 @@ export default async function ({ contracts, provider }, { name, owner, resolverA
|
|
|
17
18
|
}
|
|
18
19
|
const label = labels.shift();
|
|
19
20
|
const labelhash = ethers.utils.solidityKeccak256(['string'], [label]);
|
|
20
|
-
const parentNodehash =
|
|
21
|
+
const parentNodehash = namehash(labels.join('.'));
|
|
21
22
|
switch (contract) {
|
|
22
23
|
case 'registry': {
|
|
23
24
|
const registry = (await contracts?.getRegistry()).connect(signer);
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { utils } from 'ethers';
|
|
2
2
|
import { testable as fuseEnums } from '../utils/fuses';
|
|
3
|
+
import { namehash } from '../utils/normalise';
|
|
3
4
|
const NameSafety = [
|
|
4
5
|
'Safe',
|
|
5
6
|
'RegistrantNotWrapped',
|
|
@@ -12,7 +13,7 @@ const raw = async ({ contracts }, name) => {
|
|
|
12
13
|
return {
|
|
13
14
|
to: nameWrapper.address,
|
|
14
15
|
data: nameWrapper.interface.encodeFunctionData('getFuses', [
|
|
15
|
-
|
|
16
|
+
namehash(name),
|
|
16
17
|
]),
|
|
17
18
|
};
|
|
18
19
|
};
|
|
@@ -36,7 +37,7 @@ const decode = async ({ contracts }, data, name) => {
|
|
|
36
37
|
if (utils.hexStripZeros(vulnerableNode) !== '0x') {
|
|
37
38
|
name.split('.').forEach((label, index, arr) => {
|
|
38
39
|
const node = arr.slice(index).join('.');
|
|
39
|
-
const nodehash =
|
|
40
|
+
const nodehash = namehash(node);
|
|
40
41
|
if (nodehash === vulnerableNode) {
|
|
41
42
|
returnVulnerableNode = node;
|
|
42
43
|
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { ethers } from 'ethers';
|
|
2
2
|
import { labelhash } from '../utils/labels';
|
|
3
|
+
import { namehash as makeNamehash } from '../utils/normalise';
|
|
3
4
|
const singleContractOwnerRaw = async ({ contracts }, contract, namehash, labels) => {
|
|
4
5
|
switch (contract) {
|
|
5
6
|
case 'nameWrapper': {
|
|
@@ -28,10 +29,10 @@ const singleContractOwnerRaw = async ({ contracts }, contract, namehash, labels)
|
|
|
28
29
|
}
|
|
29
30
|
};
|
|
30
31
|
const raw = async ({ contracts, multicallWrapper }, name, contract) => {
|
|
31
|
-
const namehash =
|
|
32
|
+
const namehash = makeNamehash(name);
|
|
32
33
|
const labels = name.split('.');
|
|
33
|
-
if (contract) {
|
|
34
|
-
return await singleContractOwnerRaw({ contracts }, contract, namehash, labels);
|
|
34
|
+
if (contract || labels.length === 1) {
|
|
35
|
+
return await singleContractOwnerRaw({ contracts }, contract || 'registry', namehash, labels);
|
|
35
36
|
}
|
|
36
37
|
const registryData = await singleContractOwnerRaw({ contracts }, 'registry', namehash, labels);
|
|
37
38
|
const nameWrapperData = await singleContractOwnerRaw({ contracts }, 'nameWrapper', namehash, labels);
|
|
@@ -46,10 +47,11 @@ const singleContractOwnerDecode = (data) => ethers.utils.defaultAbiCoder.decode(
|
|
|
46
47
|
const decode = async ({ contracts, multicallWrapper }, data, name, contract) => {
|
|
47
48
|
if (data === null)
|
|
48
49
|
return;
|
|
49
|
-
|
|
50
|
+
const labels = name.split('.');
|
|
51
|
+
if (contract || labels.length === 1) {
|
|
50
52
|
const singleOwner = singleContractOwnerDecode(data);
|
|
51
53
|
let obj = {
|
|
52
|
-
ownershipLevel: contract,
|
|
54
|
+
ownershipLevel: contract || 'registry',
|
|
53
55
|
};
|
|
54
56
|
if (contract === 'registrar') {
|
|
55
57
|
return {
|
|
@@ -74,7 +76,6 @@ const decode = async ({ contracts, multicallWrapper }, data, name, contract) =>
|
|
|
74
76
|
const registryOwner = decodedData[0][0];
|
|
75
77
|
const nameWrapperOwner = decodedData[1][0];
|
|
76
78
|
const registrarOwner = decodedData[2]?.[0];
|
|
77
|
-
const labels = name.split('.');
|
|
78
79
|
// check for only .eth names
|
|
79
80
|
if (labels[labels.length - 1] === 'eth') {
|
|
80
81
|
// if the owner on the registrar is the namewrapper, then the namewrapper owner is the owner
|
|
@@ -26,5 +26,5 @@ declare type ProfileOptions = {
|
|
|
26
26
|
texts?: boolean | string[];
|
|
27
27
|
coinTypes?: boolean | string[];
|
|
28
28
|
};
|
|
29
|
-
export default function ({ contracts, gqlInstance, getName, _getAddr, _getContentHash, _getText, resolverMulticallWrapper, }: ENSArgs<'contracts' | 'gqlInstance' | 'getName' | '_getText' | '_getAddr' | '_getContentHash' | 'resolverMulticallWrapper'>, nameOrAddress: string, options?: ProfileOptions): Promise<ResolvedProfile | undefined>;
|
|
29
|
+
export default function ({ contracts, gqlInstance, getName, _getAddr, _getContentHash, _getText, resolverMulticallWrapper, multicallWrapper, }: ENSArgs<'contracts' | 'gqlInstance' | 'getName' | '_getText' | '_getAddr' | '_getContentHash' | 'resolverMulticallWrapper' | 'multicallWrapper'>, nameOrAddress: string, options?: ProfileOptions): Promise<ResolvedProfile | undefined>;
|
|
30
30
|
export {};
|
|
@@ -40,23 +40,39 @@ const makeMulticallData = async ({ _getAddr, _getContentHash, _getText, resolver
|
|
|
40
40
|
const prRawData = await resolverMulticallWrapper.raw(calls.map((x) => x.data));
|
|
41
41
|
return { data: prRawData.data, calls };
|
|
42
42
|
};
|
|
43
|
-
const
|
|
44
|
-
const
|
|
43
|
+
const fetchWithoutResolverMulticall = async ({ multicallWrapper }, calls, resolverAddress) => {
|
|
44
|
+
const callsWithResolver = calls.map((call) => ({
|
|
45
|
+
to: resolverAddress,
|
|
46
|
+
data: call.data.data,
|
|
47
|
+
}));
|
|
48
|
+
return (await multicallWrapper(callsWithResolver)).map((x) => x[1]);
|
|
49
|
+
};
|
|
50
|
+
const getDataForName = async ({ contracts, _getAddr, _getContentHash, _getText, resolverMulticallWrapper, multicallWrapper, }, name, options, fallbackResolver) => {
|
|
45
51
|
const universalResolver = await contracts?.getUniversalResolver();
|
|
46
52
|
const { data, calls } = await makeMulticallData({ _getAddr, _getContentHash, _getText, resolverMulticallWrapper }, name, options);
|
|
47
|
-
let
|
|
53
|
+
let resolvedData;
|
|
54
|
+
let useFallbackResolver = false;
|
|
48
55
|
try {
|
|
49
|
-
|
|
56
|
+
resolvedData = await universalResolver?.resolve(hexEncodeName(name), data);
|
|
50
57
|
}
|
|
51
58
|
catch {
|
|
52
|
-
|
|
59
|
+
useFallbackResolver = true;
|
|
60
|
+
}
|
|
61
|
+
let resolverAddress;
|
|
62
|
+
let recordData;
|
|
63
|
+
if (useFallbackResolver) {
|
|
64
|
+
resolverAddress = fallbackResolver;
|
|
65
|
+
recordData = await fetchWithoutResolverMulticall({ multicallWrapper }, calls, resolverAddress);
|
|
66
|
+
}
|
|
67
|
+
else {
|
|
68
|
+
resolverAddress = resolvedData['1'];
|
|
69
|
+
[recordData] = await resolverMulticallWrapper.decode(resolvedData['0']);
|
|
53
70
|
}
|
|
54
|
-
const [recordData] = await resolverMulticallWrapper.decode(resolver['0']);
|
|
55
71
|
const matchAddress = recordData[calls.findIndex((x) => x.key === '60')];
|
|
56
72
|
return {
|
|
57
73
|
address: matchAddress && (await _getAddr.decode(matchAddress)),
|
|
58
74
|
records: await formatRecords({ _getAddr, _getContentHash, _getText }, recordData, calls, options),
|
|
59
|
-
resolverAddress
|
|
75
|
+
resolverAddress,
|
|
60
76
|
};
|
|
61
77
|
};
|
|
62
78
|
const formatRecords = async ({ _getText, _getAddr, _getContentHash, }, data, calls, options) => {
|
|
@@ -66,7 +82,7 @@ const formatRecords = async ({ _getText, _getAddr, _getContentHash, }, data, cal
|
|
|
66
82
|
key: calls[i].key,
|
|
67
83
|
type: calls[i].type,
|
|
68
84
|
};
|
|
69
|
-
if (itemRet.type === '
|
|
85
|
+
if (itemRet.type === 'contenthash') {
|
|
70
86
|
decodedFromAbi = ethers.utils.defaultAbiCoder.decode(['bytes'], item)[0];
|
|
71
87
|
if (ethers.utils.hexStripZeros(decodedFromAbi) === '0x') {
|
|
72
88
|
return;
|
|
@@ -155,6 +171,7 @@ const graphFetch = async ({ gqlInstance }, name, wantedRecords) => {
|
|
|
155
171
|
addr {
|
|
156
172
|
id
|
|
157
173
|
}
|
|
174
|
+
address
|
|
158
175
|
}
|
|
159
176
|
}
|
|
160
177
|
}
|
|
@@ -165,8 +182,14 @@ const graphFetch = async ({ gqlInstance }, name, wantedRecords) => {
|
|
|
165
182
|
return;
|
|
166
183
|
const [{ resolver: resolverResponse, isMigrated, createdAt }] = domains;
|
|
167
184
|
let returnedRecords = {};
|
|
168
|
-
if (!
|
|
185
|
+
if (!resolverResponse)
|
|
169
186
|
return { isMigrated, createdAt };
|
|
187
|
+
if (!wantedRecords)
|
|
188
|
+
return {
|
|
189
|
+
isMigrated,
|
|
190
|
+
createdAt,
|
|
191
|
+
graphResolverAddress: resolverResponse.address,
|
|
192
|
+
};
|
|
170
193
|
Object.keys(wantedRecords).forEach((key) => {
|
|
171
194
|
const data = wantedRecords[key];
|
|
172
195
|
if (typeof data === 'boolean' && data) {
|
|
@@ -178,28 +201,36 @@ const graphFetch = async ({ gqlInstance }, name, wantedRecords) => {
|
|
|
178
201
|
}
|
|
179
202
|
}
|
|
180
203
|
});
|
|
181
|
-
return {
|
|
204
|
+
return {
|
|
205
|
+
...returnedRecords,
|
|
206
|
+
isMigrated,
|
|
207
|
+
createdAt,
|
|
208
|
+
graphResolverAddress: resolverResponse.address,
|
|
209
|
+
};
|
|
182
210
|
};
|
|
183
|
-
const getProfileFromName = async ({ contracts, gqlInstance, _getAddr, _getContentHash, _getText, resolverMulticallWrapper, }, name, options) => {
|
|
211
|
+
const getProfileFromName = async ({ contracts, gqlInstance, _getAddr, _getContentHash, _getText, resolverMulticallWrapper, multicallWrapper, }, name, options) => {
|
|
184
212
|
const usingOptions = !options || options?.texts === true || options?.coinTypes === true
|
|
185
213
|
? options || { contentHash: true, texts: true, coinTypes: true }
|
|
186
214
|
: undefined;
|
|
187
215
|
const graphResult = await graphFetch({ gqlInstance }, name, usingOptions);
|
|
188
216
|
if (!graphResult)
|
|
189
217
|
return;
|
|
190
|
-
const { isMigrated, createdAt, ...wantedRecords } = graphResult;
|
|
218
|
+
const { isMigrated, createdAt, graphResolverAddress, ...wantedRecords } = graphResult;
|
|
219
|
+
if (!graphResolverAddress)
|
|
220
|
+
return { isMigrated, createdAt, message: "Name doesn't have a resolver" };
|
|
191
221
|
const result = await getDataForName({
|
|
192
222
|
contracts,
|
|
193
223
|
_getAddr,
|
|
194
224
|
_getContentHash,
|
|
195
225
|
_getText,
|
|
196
226
|
resolverMulticallWrapper,
|
|
197
|
-
|
|
227
|
+
multicallWrapper,
|
|
228
|
+
}, name, usingOptions ? wantedRecords : options, graphResolverAddress);
|
|
198
229
|
if (!result)
|
|
199
230
|
return { isMigrated, createdAt, message: "Records fetch didn't complete" };
|
|
200
231
|
return { ...result, isMigrated, createdAt, message: undefined };
|
|
201
232
|
};
|
|
202
|
-
const getProfileFromAddress = async ({ contracts, gqlInstance, getName, _getAddr, _getContentHash, _getText, resolverMulticallWrapper, }, address, options) => {
|
|
233
|
+
const getProfileFromAddress = async ({ contracts, gqlInstance, getName, _getAddr, _getContentHash, _getText, resolverMulticallWrapper, multicallWrapper, }, address, options) => {
|
|
203
234
|
let name;
|
|
204
235
|
try {
|
|
205
236
|
name = await getName(address);
|
|
@@ -218,6 +249,7 @@ const getProfileFromAddress = async ({ contracts, gqlInstance, getName, _getAddr
|
|
|
218
249
|
_getContentHash,
|
|
219
250
|
_getText,
|
|
220
251
|
resolverMulticallWrapper,
|
|
252
|
+
multicallWrapper,
|
|
221
253
|
}, name.name, options);
|
|
222
254
|
if (!result || result.message)
|
|
223
255
|
return;
|
|
@@ -228,7 +260,7 @@ const getProfileFromAddress = async ({ contracts, gqlInstance, getName, _getAddr
|
|
|
228
260
|
message: undefined,
|
|
229
261
|
};
|
|
230
262
|
};
|
|
231
|
-
export default async function ({ contracts, gqlInstance, getName, _getAddr, _getContentHash, _getText, resolverMulticallWrapper, }, nameOrAddress, options) {
|
|
263
|
+
export default async function ({ contracts, gqlInstance, getName, _getAddr, _getContentHash, _getText, resolverMulticallWrapper, multicallWrapper, }, nameOrAddress, options) {
|
|
232
264
|
if (options && options.coinTypes && typeof options.coinTypes !== 'boolean') {
|
|
233
265
|
options.coinTypes = options.coinTypes.map((coin) => {
|
|
234
266
|
if (!isNaN(parseInt(coin))) {
|
|
@@ -252,6 +284,7 @@ export default async function ({ contracts, gqlInstance, getName, _getAddr, _get
|
|
|
252
284
|
_getContentHash,
|
|
253
285
|
_getText,
|
|
254
286
|
resolverMulticallWrapper,
|
|
287
|
+
multicallWrapper,
|
|
255
288
|
}, nameOrAddress, options);
|
|
256
289
|
}
|
|
257
290
|
return getProfileFromName({
|
|
@@ -261,5 +294,6 @@ export default async function ({ contracts, gqlInstance, getName, _getAddr, _get
|
|
|
261
294
|
_getContentHash,
|
|
262
295
|
_getText,
|
|
263
296
|
resolverMulticallWrapper,
|
|
297
|
+
multicallWrapper,
|
|
264
298
|
}, nameOrAddress, options);
|
|
265
299
|
}
|
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
import { formatsByCoinType, formatsByName } from '@ensdomains/address-encoder';
|
|
2
2
|
import { ethers } from 'ethers';
|
|
3
3
|
import { decodeContenthash } from '../utils/contentHash';
|
|
4
|
+
import { namehash } from '../utils/normalise';
|
|
4
5
|
export const _getContentHash = {
|
|
5
6
|
raw: async ({ contracts }, name) => {
|
|
6
7
|
const publicResolver = await contracts?.getPublicResolver();
|
|
7
8
|
return {
|
|
8
9
|
to: '0x0000000000000000000000000000000000000000',
|
|
9
10
|
data: publicResolver.interface.encodeFunctionData('contenthash', [
|
|
10
|
-
|
|
11
|
+
namehash(name),
|
|
11
12
|
]),
|
|
12
13
|
};
|
|
13
14
|
},
|
|
@@ -45,7 +46,7 @@ export const _getText = {
|
|
|
45
46
|
return {
|
|
46
47
|
to: '0x0000000000000000000000000000000000000000',
|
|
47
48
|
data: publicResolver.interface.encodeFunctionData('text', [
|
|
48
|
-
|
|
49
|
+
namehash(name),
|
|
49
50
|
key,
|
|
50
51
|
]),
|
|
51
52
|
};
|
|
@@ -77,10 +78,18 @@ export const _getAddr = {
|
|
|
77
78
|
coinType = 60;
|
|
78
79
|
}
|
|
79
80
|
const publicResolver = await contracts?.getPublicResolver();
|
|
81
|
+
if (coinType === 60 || coinType === '60') {
|
|
82
|
+
return {
|
|
83
|
+
to: '0x0000000000000000000000000000000000000000',
|
|
84
|
+
data: publicResolver.interface.encodeFunctionData('addr(bytes32)', [
|
|
85
|
+
namehash(name),
|
|
86
|
+
]),
|
|
87
|
+
};
|
|
88
|
+
}
|
|
80
89
|
if (bypassFormat) {
|
|
81
90
|
return {
|
|
82
91
|
to: '0x0000000000000000000000000000000000000000',
|
|
83
|
-
data: publicResolver.interface.encodeFunctionData('addr(bytes32,uint256)', [
|
|
92
|
+
data: publicResolver.interface.encodeFunctionData('addr(bytes32,uint256)', [namehash(name), coinType]),
|
|
84
93
|
};
|
|
85
94
|
}
|
|
86
95
|
const formatter = typeof coinType === 'string' && isNaN(parseInt(coinType))
|
|
@@ -91,7 +100,7 @@ export const _getAddr = {
|
|
|
91
100
|
}
|
|
92
101
|
return {
|
|
93
102
|
to: '0x0000000000000000000000000000000000000000',
|
|
94
|
-
data: publicResolver.interface.encodeFunctionData('addr(bytes32,uint256)', [
|
|
103
|
+
data: publicResolver.interface.encodeFunctionData('addr(bytes32,uint256)', [namehash(name), formatter.coinType]),
|
|
95
104
|
};
|
|
96
105
|
},
|
|
97
106
|
decode: async ({ contracts }, data, _name, coinType) => {
|
|
@@ -104,7 +113,15 @@ export const _getAddr = {
|
|
|
104
113
|
const formatter = typeof coinType === 'string' && isNaN(parseInt(coinType))
|
|
105
114
|
? formatsByName[coinType]
|
|
106
115
|
: formatsByCoinType[typeof coinType === 'number' ? coinType : parseInt(coinType)];
|
|
107
|
-
|
|
116
|
+
let response;
|
|
117
|
+
if (coinType === 60 || coinType === '60') {
|
|
118
|
+
;
|
|
119
|
+
[response] = publicResolver.interface.decodeFunctionResult('addr(bytes32)', data);
|
|
120
|
+
}
|
|
121
|
+
else {
|
|
122
|
+
;
|
|
123
|
+
[response] = publicResolver.interface.decodeFunctionResult('addr(bytes32,uint256)', data);
|
|
124
|
+
}
|
|
108
125
|
if (!response)
|
|
109
126
|
return;
|
|
110
127
|
if (ethers.utils.hexStripZeros(response) === '0x') {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { namehash } from 'ethers/lib/utils';
|
|
2
1
|
import { truncateFormat } from '../utils/format';
|
|
3
2
|
import { decryptName } from '../utils/labels';
|
|
3
|
+
import { namehash } from '../utils/normalise';
|
|
4
4
|
const largeQuery = async ({ gqlInstance }, { name, page, pageSize = 10, orderDirection, orderBy, lastSubnames }) => {
|
|
5
5
|
const client = gqlInstance.client;
|
|
6
6
|
let finalQuery = gqlInstance.gql `
|
|
@@ -53,7 +53,7 @@ const largeQuery = async ({ gqlInstance }, { name, page, pageSize = 10, orderDir
|
|
|
53
53
|
});
|
|
54
54
|
return {
|
|
55
55
|
subnames: subdomains,
|
|
56
|
-
subnameCount: domain.subdomainCount
|
|
56
|
+
subnameCount: domain.subdomainCount,
|
|
57
57
|
};
|
|
58
58
|
};
|
|
59
59
|
const smallQuery = async ({ gqlInstance }, { name, page, pageSize = 10, orderDirection, orderBy }) => {
|
|
@@ -140,7 +140,7 @@ const smallQuery = async ({ gqlInstance }, { name, page, pageSize = 10, orderDir
|
|
|
140
140
|
});
|
|
141
141
|
return {
|
|
142
142
|
subnames: subdomains,
|
|
143
|
-
subnameCount: domain.subdomainCount
|
|
143
|
+
subnameCount: domain.subdomainCount,
|
|
144
144
|
};
|
|
145
145
|
};
|
|
146
146
|
const getSubnames = (injected, functionArgs) => {
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { ethers } from 'ethers';
|
|
2
1
|
import { ENSArgs } from '..';
|
|
3
2
|
import { RecordOptions } from '../utils/recordHelpers';
|
|
4
|
-
export default function ({ contracts, provider, getResolver, }: ENSArgs<'contracts' | 'provider' | 'getResolver'>, name: string, records: RecordOptions): Promise<ethers.ContractTransaction | undefined>;
|
|
3
|
+
export default function ({ contracts, provider, getResolver, }: ENSArgs<'contracts' | 'provider' | 'getResolver'>, name: string, records: RecordOptions): Promise<import("ethers").ContractTransaction | undefined>;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { namehash } from '../utils/normalise';
|
|
2
2
|
import { generateRecordCallArray } from '../utils/recordHelpers';
|
|
3
3
|
export default async function ({ contracts, provider, getResolver, }, name, records) {
|
|
4
4
|
if (!name.includes('.')) {
|
|
@@ -13,7 +13,7 @@ export default async function ({ contracts, provider, getResolver, }, name, reco
|
|
|
13
13
|
throw new Error('No signer found');
|
|
14
14
|
}
|
|
15
15
|
const resolver = (await contracts?.getPublicResolver(provider, resolverAddress))?.connect(provider?.getSigner());
|
|
16
|
-
const
|
|
17
|
-
const calls = generateRecordCallArray(
|
|
16
|
+
const hash = namehash(name);
|
|
17
|
+
const calls = generateRecordCallArray(hash, records, resolver);
|
|
18
18
|
return resolver?.multicall(calls);
|
|
19
19
|
}
|
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
import { ethers } from 'ethers';
|
|
2
1
|
import { ENSArgs } from '..';
|
|
3
2
|
export default function ({ contracts, provider }: ENSArgs<'contracts' | 'provider'>, name: string, contract: 'registry' | 'nameWrapper', resolver?: string, options?: {
|
|
4
3
|
addressOrIndex?: string | number;
|
|
5
|
-
}): Promise<ethers.ContractTransaction>;
|
|
4
|
+
}): Promise<import("ethers").ContractTransaction>;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { namehash } from '../utils/normalise';
|
|
2
2
|
export default async function ({ contracts, provider }, name, contract, resolver, options) {
|
|
3
3
|
const address = await provider
|
|
4
4
|
?.getSigner(options?.addressOrIndex)
|
|
@@ -12,11 +12,11 @@ export default async function ({ contracts, provider }, name, contract, resolver
|
|
|
12
12
|
switch (contract) {
|
|
13
13
|
case 'registry': {
|
|
14
14
|
const registry = (await contracts?.getRegistry()).connect(provider?.getSigner(options?.addressOrIndex));
|
|
15
|
-
return registry.setResolver(
|
|
15
|
+
return registry.setResolver(namehash(name), resolver);
|
|
16
16
|
}
|
|
17
17
|
case 'nameWrapper': {
|
|
18
18
|
const nameWrapper = (await contracts?.getNameWrapper()).connect(provider?.getSigner(options?.addressOrIndex));
|
|
19
|
-
return nameWrapper.setResolver(
|
|
19
|
+
return nameWrapper.setResolver(namehash(name), resolver);
|
|
20
20
|
}
|
|
21
21
|
default: {
|
|
22
22
|
throw new Error(`Unknown contract: ${contract}`);
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { ethers } from 'ethers';
|
|
2
|
+
import { namehash } from '../utils/normalise';
|
|
2
3
|
export default async function ({ contracts, provider }, name, newOwner, contract, options) {
|
|
3
4
|
const address = await provider
|
|
4
5
|
?.getSigner(options?.addressOrIndex)
|
|
@@ -9,7 +10,7 @@ export default async function ({ contracts, provider }, name, newOwner, contract
|
|
|
9
10
|
switch (contract) {
|
|
10
11
|
case 'registry': {
|
|
11
12
|
const registry = (await contracts?.getRegistry()).connect(provider?.getSigner(options?.addressOrIndex));
|
|
12
|
-
return registry.setOwner(
|
|
13
|
+
return registry.setOwner(namehash(name), newOwner);
|
|
13
14
|
}
|
|
14
15
|
case 'baseRegistrar': {
|
|
15
16
|
const baseRegistrar = (await contracts?.getBaseRegistrar()).connect(provider?.getSigner(options?.addressOrIndex));
|
|
@@ -21,7 +22,7 @@ export default async function ({ contracts, provider }, name, newOwner, contract
|
|
|
21
22
|
}
|
|
22
23
|
case 'nameWrapper': {
|
|
23
24
|
const nameWrapper = (await contracts?.getNameWrapper()).connect(provider?.getSigner(options?.addressOrIndex));
|
|
24
|
-
return nameWrapper.safeTransferFrom(address, newOwner,
|
|
25
|
+
return nameWrapper.safeTransferFrom(address, newOwner, namehash(name), 1, '0x');
|
|
25
26
|
}
|
|
26
27
|
default: {
|
|
27
28
|
throw new Error(`Unknown contract: ${contract}`);
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { ethers } from 'ethers';
|
|
2
|
+
import { namehash } from '../utils/normalise';
|
|
2
3
|
export default async function ({ contracts, provider }, name, contract, address, options) {
|
|
3
4
|
const signer = provider?.getSigner(options?.addressOrIndex);
|
|
4
5
|
if (!signer) {
|
|
@@ -7,7 +8,7 @@ export default async function ({ contracts, provider }, name, contract, address,
|
|
|
7
8
|
const labels = name.split('.');
|
|
8
9
|
const label = labels.shift();
|
|
9
10
|
const labelhash = ethers.utils.solidityKeccak256(['string'], [label]);
|
|
10
|
-
const parentNodehash =
|
|
11
|
+
const parentNodehash = namehash(labels.join('.'));
|
|
11
12
|
switch (contract) {
|
|
12
13
|
case 'registry': {
|
|
13
14
|
const registry = (await contracts?.getRegistry()).connect(signer);
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { utils } from 'ethers';
|
|
2
|
+
import { namehash } from '../utils/normalise';
|
|
2
3
|
export default async function ({ contracts, provider }, name, newController, newRegistrant, options) {
|
|
3
4
|
const signer = provider?.getSigner(options?.addressOrIndex);
|
|
4
5
|
const address = await signer?.getAddress();
|
|
@@ -7,7 +8,7 @@ export default async function ({ contracts, provider }, name, newController, new
|
|
|
7
8
|
}
|
|
8
9
|
const labels = name.split('.');
|
|
9
10
|
const labelhash = utils.solidityKeccak256(['string'], [labels[0]]);
|
|
10
|
-
const parentNodehash =
|
|
11
|
+
const parentNodehash = namehash(labels.slice(1).join('.'));
|
|
11
12
|
const nameWrapper = (await contracts?.getNameWrapper()).connect(signer);
|
|
12
13
|
if (labels.length === 2 && labels[1] === 'eth') {
|
|
13
14
|
if (!newRegistrant) {
|
package/dist/esm/index.js
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { namehash } from './normalise';
|
|
2
2
|
export const makeOtherIndexes = (data, findStr) => Array.from(data.matchAll(findStr)).map((x) => x.index / 2 - 1);
|
|
3
|
-
export const makeNamehashIndexes = (data, name) => Array.from(data.matchAll(
|
|
3
|
+
export const makeNamehashIndexes = (data, name) => Array.from(data.matchAll(namehash(name).substring(2))).map((x) => x.index / 2 - 1);
|
|
@@ -1,2 +1,20 @@
|
|
|
1
|
+
import { concat, hexlify, keccak256, toUtf8Bytes } from 'ethers/lib/utils';
|
|
1
2
|
import uts46 from 'idna-uts46-hx/uts46bundle.js';
|
|
3
|
+
const zeros = new Uint8Array(32);
|
|
4
|
+
zeros.fill(0);
|
|
2
5
|
export const normalise = (name) => name ? uts46.toUnicode(name, { useStd3ASCII: true }) : name;
|
|
6
|
+
export const namehash = (inputName) => {
|
|
7
|
+
let result = zeros;
|
|
8
|
+
const name = normalise(inputName);
|
|
9
|
+
if (name) {
|
|
10
|
+
const labels = name.split('.');
|
|
11
|
+
for (var i = labels.length - 1; i >= 0; i--) {
|
|
12
|
+
const labelSha = keccak256(toUtf8Bytes(labels[i]));
|
|
13
|
+
result = keccak256(concat([result, labelSha]));
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
else {
|
|
17
|
+
result = hexlify(zeros);
|
|
18
|
+
}
|
|
19
|
+
return result;
|
|
20
|
+
};
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { utils } from 'ethers';
|
|
2
2
|
import generateFuseInput from './generateFuseInput';
|
|
3
3
|
import { labelhash } from './labels';
|
|
4
|
+
import { namehash } from './normalise';
|
|
4
5
|
import { generateRecordCallArray } from './recordHelpers';
|
|
5
6
|
export const randomSecret = () => {
|
|
6
7
|
const bytes = Buffer.allocUnsafe(32);
|
|
@@ -8,11 +9,9 @@ export const randomSecret = () => {
|
|
|
8
9
|
};
|
|
9
10
|
export const makeCommitment = ({ name, owner, duration, resolver, records, reverseRecord, fuses, }) => {
|
|
10
11
|
const label = labelhash(name.split('.')[0]);
|
|
11
|
-
const
|
|
12
|
+
const hash = namehash(name);
|
|
12
13
|
const resolverAddress = resolver.address;
|
|
13
|
-
const data = records
|
|
14
|
-
? generateRecordCallArray(namehash, records, resolver)
|
|
15
|
-
: [];
|
|
14
|
+
const data = records ? generateRecordCallArray(hash, records, resolver) : [];
|
|
16
15
|
const secret = randomSecret();
|
|
17
16
|
const fuseData = fuses ? generateFuseInput(fuses) : '0';
|
|
18
17
|
const commitment = _makeCommitment({
|
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.2",
|
|
4
4
|
"description": "ENS javascript library for contract interaction",
|
|
5
5
|
"main": "./dist/cjs/index.js",
|
|
6
6
|
"types": "./dist/cjs/index.d.ts",
|
|
@@ -75,5 +75,6 @@
|
|
|
75
75
|
},
|
|
76
76
|
"peerDependencies": {
|
|
77
77
|
"ethers": "*"
|
|
78
|
-
}
|
|
78
|
+
},
|
|
79
|
+
"stableVersion": "3.0.0-alpha.1"
|
|
79
80
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { ethers } from 'ethers'
|
|
2
1
|
import { ENSArgs } from '..'
|
|
3
2
|
import { FuseOptions } from '../@types/FuseOptions'
|
|
4
3
|
import generateFuseInput from '../utils/generateFuseInput'
|
|
4
|
+
import { namehash } from '../utils/normalise'
|
|
5
5
|
|
|
6
6
|
export default async function (
|
|
7
7
|
{ contracts, provider }: ENSArgs<'contracts' | 'provider'>,
|
|
@@ -15,9 +15,9 @@ export default async function (
|
|
|
15
15
|
}
|
|
16
16
|
|
|
17
17
|
const nameWrapper = (await contracts?.getNameWrapper()!).connect(signer)
|
|
18
|
-
const
|
|
18
|
+
const hash = namehash(name)
|
|
19
19
|
|
|
20
20
|
const encodedFuses = generateFuseInput(fusesToBurn)
|
|
21
21
|
|
|
22
|
-
return nameWrapper.burnFuses(
|
|
22
|
+
return nameWrapper.burnFuses(hash, encodedFuses)
|
|
23
23
|
}
|
|
@@ -2,6 +2,7 @@ import { ethers } from 'ethers'
|
|
|
2
2
|
import { ENSArgs } from '..'
|
|
3
3
|
import { FuseOptions } from '../@types/FuseOptions'
|
|
4
4
|
import generateFuseInput from '../utils/generateFuseInput'
|
|
5
|
+
import { namehash } from '../utils/normalise'
|
|
5
6
|
|
|
6
7
|
type BaseArgs = {
|
|
7
8
|
name: string
|
|
@@ -44,7 +45,7 @@ export default async function (
|
|
|
44
45
|
|
|
45
46
|
const label = labels.shift() as string
|
|
46
47
|
const labelhash = ethers.utils.solidityKeccak256(['string'], [label])
|
|
47
|
-
const parentNodehash =
|
|
48
|
+
const parentNodehash = namehash(labels.join('.'))
|
|
48
49
|
|
|
49
50
|
switch (contract) {
|
|
50
51
|
case 'registry': {
|
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import { BigNumber,
|
|
1
|
+
import { BigNumber, utils } from 'ethers'
|
|
2
2
|
import { ENSArgs } from '..'
|
|
3
3
|
import { testable as fuseEnums } from '../utils/fuses'
|
|
4
|
+
import { namehash } from '../utils/normalise'
|
|
4
5
|
|
|
5
6
|
const NameSafety = [
|
|
6
7
|
'Safe',
|
|
@@ -15,7 +16,7 @@ const raw = async ({ contracts }: ENSArgs<'contracts'>, name: string) => {
|
|
|
15
16
|
return {
|
|
16
17
|
to: nameWrapper.address,
|
|
17
18
|
data: nameWrapper.interface.encodeFunctionData('getFuses', [
|
|
18
|
-
|
|
19
|
+
namehash(name),
|
|
19
20
|
]),
|
|
20
21
|
}
|
|
21
22
|
}
|
|
@@ -51,7 +52,7 @@ const decode = async (
|
|
|
51
52
|
if (utils.hexStripZeros(vulnerableNode) !== '0x') {
|
|
52
53
|
name.split('.').forEach((label, index, arr) => {
|
|
53
54
|
const node = arr.slice(index).join('.')
|
|
54
|
-
const nodehash =
|
|
55
|
+
const nodehash = namehash(node)
|
|
55
56
|
if (nodehash === vulnerableNode) {
|
|
56
57
|
returnVulnerableNode = node
|
|
57
58
|
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { ethers } from 'ethers'
|
|
2
2
|
import { ENSArgs } from '..'
|
|
3
3
|
import { labelhash } from '../utils/labels'
|
|
4
|
+
import { namehash as makeNamehash } from '../utils/normalise'
|
|
4
5
|
|
|
5
6
|
type Owner = {
|
|
6
7
|
registrant?: string
|
|
@@ -49,13 +50,13 @@ const raw = async (
|
|
|
49
50
|
name: string,
|
|
50
51
|
contract?: 'nameWrapper' | 'registry' | 'registrar',
|
|
51
52
|
) => {
|
|
52
|
-
const namehash =
|
|
53
|
+
const namehash = makeNamehash(name)
|
|
53
54
|
const labels = name.split('.')
|
|
54
55
|
|
|
55
|
-
if (contract) {
|
|
56
|
+
if (contract || labels.length === 1) {
|
|
56
57
|
return await singleContractOwnerRaw(
|
|
57
58
|
{ contracts },
|
|
58
|
-
contract,
|
|
59
|
+
contract || 'registry',
|
|
59
60
|
namehash,
|
|
60
61
|
labels,
|
|
61
62
|
)
|
|
@@ -99,10 +100,11 @@ const decode = async (
|
|
|
99
100
|
contract?: 'nameWrapper' | 'registry' | 'registrar',
|
|
100
101
|
): Promise<Owner | undefined> => {
|
|
101
102
|
if (data === null) return
|
|
102
|
-
|
|
103
|
+
const labels = name.split('.')
|
|
104
|
+
if (contract || labels.length === 1) {
|
|
103
105
|
const singleOwner = singleContractOwnerDecode(data)
|
|
104
106
|
let obj = {
|
|
105
|
-
ownershipLevel: contract,
|
|
107
|
+
ownershipLevel: contract || 'registry',
|
|
106
108
|
}
|
|
107
109
|
if (contract === 'registrar') {
|
|
108
110
|
return {
|
|
@@ -133,8 +135,6 @@ const decode = async (
|
|
|
133
135
|
decodedData[2] as ethers.utils.Result | undefined
|
|
134
136
|
)?.[0]
|
|
135
137
|
|
|
136
|
-
const labels = name.split('.')
|
|
137
|
-
|
|
138
138
|
// check for only .eth names
|
|
139
139
|
if (labels[labels.length - 1] === 'eth') {
|
|
140
140
|
// if the owner on the registrar is the namewrapper, then the namewrapper owner is the owner
|