@ensdomains/ensjs 3.0.0-alpha.43 → 3.0.0-alpha.45

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.
Files changed (50) hide show
  1. package/dist/cjs/contracts/getContractAddress.js +3 -3
  2. package/dist/cjs/functions/batch.js +14 -6
  3. package/dist/cjs/functions/getExpiry.js +2 -1
  4. package/dist/cjs/functions/getHistory.js +16 -9
  5. package/dist/cjs/functions/getOwner.js +2 -1
  6. package/dist/cjs/functions/getWrapperData.js +1 -1
  7. package/dist/cjs/functions/unwrapName.js +2 -1
  8. package/dist/cjs/functions/wrapName.js +2 -1
  9. package/dist/cjs/index.js +1 -1
  10. package/dist/cjs/utils/ccip.js +1 -1
  11. package/dist/cjs/utils/fuses.js +3 -2
  12. package/dist/cjs/utils/singleCall.js +9 -1
  13. package/dist/cjs/utils/validation.js +2 -0
  14. package/dist/esm/contracts/getContractAddress.mjs +3 -3
  15. package/dist/esm/functions/batch.mjs +14 -6
  16. package/dist/esm/functions/getExpiry.mjs +2 -1
  17. package/dist/esm/functions/getHistory.mjs +16 -9
  18. package/dist/esm/functions/getOwner.mjs +2 -1
  19. package/dist/esm/functions/getWrapperData.mjs +1 -1
  20. package/dist/esm/functions/unwrapName.mjs +2 -1
  21. package/dist/esm/functions/wrapName.mjs +2 -1
  22. package/dist/esm/index.mjs +1 -1
  23. package/dist/esm/utils/ccip.mjs +1 -1
  24. package/dist/esm/utils/fuses.mjs +3 -2
  25. package/dist/esm/utils/singleCall.mjs +9 -1
  26. package/dist/esm/utils/validation.mjs +2 -0
  27. package/dist/types/functions/batch.d.ts +8 -1
  28. package/dist/types/functions/getHistory.d.ts +16 -0
  29. package/dist/types/index.d.ts +23 -1
  30. package/dist/types/utils/fuses.d.ts +1 -0
  31. package/dist/types/utils/singleCall.d.ts +1 -0
  32. package/dist/types/utils/validation.d.ts +1 -0
  33. package/package.json +10 -6
  34. package/src/contracts/getContractAddress.ts +3 -3
  35. package/src/functions/batch.ts +15 -5
  36. package/src/functions/ccip.test.ts +62 -0
  37. package/src/functions/getExpiry.ts +2 -1
  38. package/src/functions/getHistory.test.ts +11 -0
  39. package/src/functions/getHistory.ts +16 -9
  40. package/src/functions/getOwner.ts +2 -1
  41. package/src/functions/getWrapperData.test.ts +3 -0
  42. package/src/functions/getWrapperData.ts +1 -1
  43. package/src/functions/unwrapName.ts +2 -1
  44. package/src/functions/wrapName.ts +2 -1
  45. package/src/index.ts +1 -1
  46. package/src/utils/ccip.ts +1 -1
  47. package/src/utils/fuses.ts +4 -4
  48. package/src/utils/singleCall.ts +11 -6
  49. package/src/utils/validation.ts +3 -0
  50. package/src/functions/getProfile-ccip.test.ts +0 -29
@@ -37,19 +37,19 @@ const addresses = {
37
37
  "1": "0x283af0b28c62c092c9727f1ee09c02ca627eb7f5",
38
38
  "3": "0xa5627AB7Ae47063B533622C34FEBDb52d3281dF8",
39
39
  "4": "0x283af0b28c62c092c9727f1ee09c02ca627eb7f5",
40
- "5": "0xb7A1f9e633fdeaAa2ec44bE00a61a7Db9a733D70"
40
+ "5": "0x603A4F2e7615d0099244496883062bA2eFBbeaf0"
41
41
  },
42
42
  Multicall: "0xcA11bde05977b3631167028862bE2a173976CA11",
43
43
  NameWrapper: {
44
44
  "1": "0x0000000000000000000000000000000000000000",
45
45
  "3": "0xF82155e2a43Be0871821E9654Fc8Ae894FB8307C",
46
46
  "4": "0x0000000000000000000000000000000000000000",
47
- "5": "0xEe1F756aCde7E81B2D8cC6aB3c8A1E2cE6db0F39"
47
+ "5": "0x060f1546642E67c485D56248201feA2f9AB1803C"
48
48
  },
49
49
  PublicResolver: {
50
50
  "1": "0x4976fb03C32e5B8cfe2b6cCB31c09Ba78EBaBa41",
51
51
  "3": "0x13F0659Ee6bb7484C884FEeFb7F75C93951ef837",
52
- "5": "0x2800Ec5BAB9CE9226d19E0ad5BC607e3cfC4347E"
52
+ "5": "0x19c2d5D0f035563344dBB7bE5fD09c8dad62b001"
53
53
  },
54
54
  ENSRegistry: {
55
55
  "1": "0x00000000000c2e074ec69a0dfb2997ba6c7d2e1e",
@@ -30,16 +30,24 @@ const raw = async ({ multicallWrapper }, ...items) => {
30
30
  return rawRef(...args);
31
31
  })
32
32
  );
33
- return multicallWrapper.raw(rawDataArr);
33
+ const response = await multicallWrapper.raw(rawDataArr);
34
+ return { ...response, passthrough: rawDataArr };
34
35
  };
35
- const decode = async ({ multicallWrapper }, data, ...items) => {
36
- const response = await multicallWrapper.decode(data);
36
+ const decode = async ({ multicallWrapper }, data, passthrough, ...items) => {
37
+ const response = await multicallWrapper.decode(data, passthrough);
37
38
  if (!response)
38
39
  return;
39
40
  return Promise.all(
40
- response.map(
41
- (ret, i) => items[i].decode(ret.returnData, ...items[i].args)
42
- )
41
+ response.map((ret, i) => {
42
+ if (passthrough[i].passthrough) {
43
+ return items[i].decode(
44
+ ret.returnData,
45
+ passthrough[i].passthrough,
46
+ ...items[i].args
47
+ );
48
+ }
49
+ return items[i].decode(ret.returnData, ...items[i].args);
50
+ })
43
51
  );
44
52
  };
45
53
  var batch_default = {
@@ -23,6 +23,7 @@ __export(getExpiry_exports, {
23
23
  module.exports = __toCommonJS(getExpiry_exports);
24
24
  var import_solidity = require("@ethersproject/solidity");
25
25
  var import_normalise = require("../utils/normalise");
26
+ var import_validation = require("../utils/validation");
26
27
  const getRegistrarExpiry = async ({ contracts, multicallWrapper }, labels) => {
27
28
  if (labels.length > 2 || labels[1] !== "eth") {
28
29
  throw new Error("Only .eth names have expiry dates on the registrar");
@@ -56,7 +57,7 @@ const getWrapperExpiry = async ({ contracts }, labels) => {
56
57
  const getContractToUse = (contract, labels) => {
57
58
  if (contract)
58
59
  return contract;
59
- if (labels.length === 2 && labels[1] === "eth") {
60
+ if ((0, import_validation.checkIsDotEth)(labels)) {
60
61
  return "registrar";
61
62
  }
62
63
  return "nameWrapper";
@@ -24,8 +24,8 @@ module.exports = __toCommonJS(getHistory_exports);
24
24
  var import_address_encoder = require("@ensdomains/address-encoder");
25
25
  var import_bytes = require("@ethersproject/bytes");
26
26
  var import_contentHash = require("../utils/contentHash");
27
- var import_labels = require("../utils/labels");
28
27
  var import_normalise = require("../utils/normalise");
28
+ var import_validation = require("../utils/validation");
29
29
  const eventFormat = {
30
30
  Domain: {
31
31
  NewOwner: (args) => ({ owner: args.owner.id }),
@@ -106,7 +106,7 @@ const mapEvents = (eventArray, type) => eventArray.map(
106
106
  async function getHistory({ gqlInstance }, name) {
107
107
  const { client } = gqlInstance;
108
108
  const query = gqlInstance.gql`
109
- query getHistory($namehash: String!, $labelhash: String!) {
109
+ query getHistory($namehash: String!) {
110
110
  domain(id: $namehash) {
111
111
  events {
112
112
  id
@@ -226,32 +226,39 @@ async function getHistory({ gqlInstance }, name) {
226
226
  }
227
227
  }
228
228
  `;
229
- const label = name.split(".")[0];
230
229
  const nameHash = (0, import_normalise.namehash)(name);
231
- const labelHash = (0, import_labels.labelhash)(label);
230
+ const labels = name.split(".");
231
+ const is2ldEth = (0, import_validation.checkIsDotEth)(labels);
232
232
  const response = await client.request(query, {
233
- namehash: nameHash,
234
- labelhash: labelHash
233
+ namehash: nameHash
235
234
  });
236
235
  const domain = response == null ? void 0 : response.domain;
237
236
  if (!domain)
238
237
  return;
239
238
  const {
240
239
  events: domainEvents,
241
- registration: { events: registrationEvents },
242
240
  resolver: { events: resolverEvents }
243
241
  } = domain;
244
242
  const domainHistory = mapEvents(domainEvents, "Domain");
245
- const registrationHistory = mapEvents(registrationEvents, "Registration");
246
243
  const resolverHistory = mapEvents(
247
244
  resolverEvents.filter(
248
245
  (event) => !event.coinType || event.coinType !== "60"
249
246
  ),
250
247
  "Resolver"
251
248
  );
249
+ if (is2ldEth) {
250
+ const {
251
+ registration: { events: registrationEvents }
252
+ } = domain;
253
+ const registrationHistory = mapEvents(registrationEvents, "Registration");
254
+ return {
255
+ domain: domainHistory,
256
+ registration: registrationHistory,
257
+ resolver: resolverHistory
258
+ };
259
+ }
252
260
  return {
253
261
  domain: domainHistory,
254
- registration: registrationHistory,
255
262
  resolver: resolverHistory
256
263
  };
257
264
  }
@@ -25,6 +25,7 @@ var import_abi = require("@ethersproject/abi");
25
25
  var import_bytes = require("@ethersproject/bytes");
26
26
  var import_labels = require("../utils/labels");
27
27
  var import_normalise = require("../utils/normalise");
28
+ var import_validation = require("../utils/validation");
28
29
  const singleContractOwnerRaw = async ({ contracts }, contract, namehash, labels) => {
29
30
  switch (contract) {
30
31
  case "nameWrapper": {
@@ -82,7 +83,7 @@ const raw = async ({ contracts, multicallWrapper }, name, contract) => {
82
83
  labels
83
84
  );
84
85
  const data = [registryData, nameWrapperData];
85
- if (labels.length === 2 && labels[1] === "eth") {
86
+ if ((0, import_validation.checkIsDotEth)(labels)) {
86
87
  data.push(registrarData);
87
88
  }
88
89
  return multicallWrapper.raw(data);
@@ -39,7 +39,7 @@ const decode = async ({ contracts }, data) => {
39
39
  data
40
40
  );
41
41
  const fuseObj = (0, import_fuses.decodeFuses)(fuses);
42
- const expiryDate = expiry.gt(0) && expiry.lt(import_bignumber.BigNumber.from(2).pow(32)) ? new Date(expiry.mul(1e3).toString()) : void 0;
42
+ const expiryDate = expiry.gt(0) && expiry.lt(import_bignumber.BigNumber.from(2).pow(32)) ? new Date(expiry.mul(1e3).toNumber()) : void 0;
43
43
  return {
44
44
  ...fuseObj,
45
45
  expiryDate,
@@ -23,6 +23,7 @@ __export(unwrapName_exports, {
23
23
  module.exports = __toCommonJS(unwrapName_exports);
24
24
  var import_solidity = require("@ethersproject/solidity");
25
25
  var import_normalise = require("../utils/normalise");
26
+ var import_validation = require("../utils/validation");
26
27
  async function unwrapName_default({ contracts, signer }, name, {
27
28
  newController,
28
29
  newRegistrant
@@ -31,7 +32,7 @@ async function unwrapName_default({ contracts, signer }, name, {
31
32
  const labelhash = (0, import_solidity.keccak256)(["string"], [labels[0]]);
32
33
  const parentNodehash = (0, import_normalise.namehash)(labels.slice(1).join("."));
33
34
  const nameWrapper = (await contracts.getNameWrapper()).connect(signer);
34
- if (labels.length === 2 && labels[1] === "eth") {
35
+ if ((0, import_validation.checkIsDotEth)(labels)) {
35
36
  if (!newRegistrant) {
36
37
  throw new Error("newRegistrant must be specified for .eth names");
37
38
  }
@@ -25,6 +25,7 @@ var import_abi = require("@ethersproject/abi");
25
25
  var import_solidity = require("@ethersproject/solidity");
26
26
  var import_fuses = require("../utils/fuses");
27
27
  var import_hexEncodedName = require("../utils/hexEncodedName");
28
+ var import_validation = require("../utils/validation");
28
29
  var import_wrapper = require("../utils/wrapper");
29
30
  async function wrapETH({ contracts }, labels, wrappedOwner, decodedFuses, resolverAddress, signer, address) {
30
31
  const nameWrapper = await (contracts == null ? void 0 : contracts.getNameWrapper());
@@ -67,7 +68,7 @@ async function wrapName_default({ contracts, signer }, name, {
67
68
  resolverAddress = publicResolver.address;
68
69
  const labels = name.split(".");
69
70
  (0, import_wrapper.wrappedLabelLengthCheck)(labels[0]);
70
- if (labels.length === 2 && labels[1] === "eth") {
71
+ if ((0, import_validation.checkIsDotEth)(labels)) {
71
72
  switch (typeof fuseOptions) {
72
73
  case "object": {
73
74
  decodedFuses = (0, import_fuses.encodeFuses)(fuseOptions);
package/dist/cjs/index.js CHANGED
@@ -281,7 +281,7 @@ class ENS {
281
281
  this.getDecryptedName = this.generateRawFunction("getDecryptedName", ["contracts", "gqlInstance"]);
282
282
  this.universalWrapper = this.generateRawFunction("initialGetters", ["contracts"], "universalWrapper");
283
283
  this.resolverMulticallWrapper = this.generateRawFunction("initialGetters", ["contracts"], "resolverMulticallWrapper");
284
- this.multicallWrapper = this.generateRawFunction("initialGetters", ["contracts"], "multicallWrapper");
284
+ this.multicallWrapper = this.generateRawFunction("initialGetters", ["contracts", "provider"], "multicallWrapper");
285
285
  this.setName = this.generateWriteFunction(
286
286
  "setName",
287
287
  ["contracts"]
@@ -115,7 +115,7 @@ const ccipLookup = async (provider, transaction, result) => {
115
115
  throw new Error("CCIP Read disabled or provided no URLs");
116
116
  }
117
117
  const tx = {
118
- to: sender,
118
+ to: txSender,
119
119
  data: (0, import_bytes.hexConcat)([
120
120
  callbackSelector,
121
121
  encodeBytes([ccipResult, extraData])
@@ -74,6 +74,7 @@ const userSettableFuseEnum = {
74
74
  };
75
75
  const fullFuseEnum = {
76
76
  ...userSettableFuseEnum,
77
+ ...fullParentFuseEnum,
77
78
  CAN_DO_EVERYTHING
78
79
  };
79
80
  const unnamedChildFuses = [
@@ -256,14 +257,14 @@ const decodeNamedFuses = (fuses, arr) => {
256
257
  const fuseObj = Object.fromEntries(
257
258
  arr.map((fuse) => [
258
259
  fuse,
259
- (fuses & userSettableFuseEnum[fuse]) > 0
260
+ (fuses & fullFuseEnum[fuse]) === fullFuseEnum[fuse]
260
261
  ])
261
262
  );
262
263
  return fuseObj;
263
264
  };
264
265
  const decodeUnnamedFuses = (fuses, arr) => {
265
266
  const fuseObj = Object.fromEntries(
266
- arr.map((fuse) => [fuse, (fuses & fuse) > 0])
267
+ arr.map((fuse) => [fuse, (fuses & fuse) === fuse])
267
268
  );
268
269
  return fuseObj;
269
270
  };
@@ -21,4 +21,12 @@ __export(singleCall_exports, {
21
21
  default: () => singleCall_default
22
22
  });
23
23
  module.exports = __toCommonJS(singleCall_exports);
24
- var singleCall_default = async (provider, ensData, func, ...data) => func.raw(ensData, ...data).then((rawData) => provider.call({ ...rawData, ccipReadEnabled: true })).catch(() => null).then((ret) => func.decode(ensData, ret, ...data));
24
+ var singleCall_default = async (provider, ensData, func, ...data) => {
25
+ const { passthrough, ...rawData } = await func.raw(ensData, ...data);
26
+ const result = await provider.call({ ...rawData, ccipReadEnabled: true }).catch(() => null);
27
+ if (!result)
28
+ return;
29
+ if (passthrough)
30
+ return func.decode(ensData, result, passthrough, ...data);
31
+ return func.decode(ensData, result, ...data);
32
+ };
@@ -18,6 +18,7 @@ var __copyProps = (to, from, except, desc) => {
18
18
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
19
  var validation_exports = {};
20
20
  __export(validation_exports, {
21
+ checkIsDotEth: () => checkIsDotEth,
21
22
  parseInputType: () => parseInputType,
22
23
  validateName: () => validateName,
23
24
  validateTLD: () => validateTLD
@@ -84,3 +85,4 @@ const parseInputType = (input) => {
84
85
  type: "label"
85
86
  };
86
87
  };
88
+ const checkIsDotEth = (labels) => labels.length === 2 && labels[1] === "eth";
@@ -15,19 +15,19 @@ var addresses = {
15
15
  "1": "0x283af0b28c62c092c9727f1ee09c02ca627eb7f5",
16
16
  "3": "0xa5627AB7Ae47063B533622C34FEBDb52d3281dF8",
17
17
  "4": "0x283af0b28c62c092c9727f1ee09c02ca627eb7f5",
18
- "5": "0xb7A1f9e633fdeaAa2ec44bE00a61a7Db9a733D70"
18
+ "5": "0x603A4F2e7615d0099244496883062bA2eFBbeaf0"
19
19
  },
20
20
  Multicall: "0xcA11bde05977b3631167028862bE2a173976CA11",
21
21
  NameWrapper: {
22
22
  "1": "0x0000000000000000000000000000000000000000",
23
23
  "3": "0xF82155e2a43Be0871821E9654Fc8Ae894FB8307C",
24
24
  "4": "0x0000000000000000000000000000000000000000",
25
- "5": "0xEe1F756aCde7E81B2D8cC6aB3c8A1E2cE6db0F39"
25
+ "5": "0x060f1546642E67c485D56248201feA2f9AB1803C"
26
26
  },
27
27
  PublicResolver: {
28
28
  "1": "0x4976fb03C32e5B8cfe2b6cCB31c09Ba78EBaBa41",
29
29
  "3": "0x13F0659Ee6bb7484C884FEeFb7F75C93951ef837",
30
- "5": "0x2800Ec5BAB9CE9226d19E0ad5BC607e3cfC4347E"
30
+ "5": "0x19c2d5D0f035563344dBB7bE5fD09c8dad62b001"
31
31
  },
32
32
  ENSRegistry: {
33
33
  "1": "0x00000000000c2e074ec69a0dfb2997ba6c7d2e1e",
@@ -8,16 +8,24 @@ var raw = async ({ multicallWrapper }, ...items) => {
8
8
  return rawRef(...args);
9
9
  })
10
10
  );
11
- return multicallWrapper.raw(rawDataArr);
11
+ const response = await multicallWrapper.raw(rawDataArr);
12
+ return { ...response, passthrough: rawDataArr };
12
13
  };
13
- var decode = async ({ multicallWrapper }, data, ...items) => {
14
- const response = await multicallWrapper.decode(data);
14
+ var decode = async ({ multicallWrapper }, data, passthrough, ...items) => {
15
+ const response = await multicallWrapper.decode(data, passthrough);
15
16
  if (!response)
16
17
  return;
17
18
  return Promise.all(
18
- response.map(
19
- (ret, i) => items[i].decode(ret.returnData, ...items[i].args)
20
- )
19
+ response.map((ret, i) => {
20
+ if (passthrough[i].passthrough) {
21
+ return items[i].decode(
22
+ ret.returnData,
23
+ passthrough[i].passthrough,
24
+ ...items[i].args
25
+ );
26
+ }
27
+ return items[i].decode(ret.returnData, ...items[i].args);
28
+ })
21
29
  );
22
30
  };
23
31
  var batch_default = {
@@ -1,6 +1,7 @@
1
1
  // src/functions/getExpiry.ts
2
2
  import { keccak256 as solidityKeccak256 } from "@ethersproject/solidity";
3
3
  import { namehash } from "../utils/normalise.mjs";
4
+ import { checkIsDotEth } from "../utils/validation.mjs";
4
5
  var getRegistrarExpiry = async ({ contracts, multicallWrapper }, labels) => {
5
6
  if (labels.length > 2 || labels[1] !== "eth") {
6
7
  throw new Error("Only .eth names have expiry dates on the registrar");
@@ -34,7 +35,7 @@ var getWrapperExpiry = async ({ contracts }, labels) => {
34
35
  var getContractToUse = (contract, labels) => {
35
36
  if (contract)
36
37
  return contract;
37
- if (labels.length === 2 && labels[1] === "eth") {
38
+ if (checkIsDotEth(labels)) {
38
39
  return "registrar";
39
40
  }
40
41
  return "nameWrapper";
@@ -2,8 +2,8 @@
2
2
  import { formatsByCoinType } from "@ensdomains/address-encoder";
3
3
  import { hexStripZeros } from "@ethersproject/bytes";
4
4
  import { decodeContenthash } from "../utils/contentHash.mjs";
5
- import { labelhash } from "../utils/labels.mjs";
6
5
  import { namehash } from "../utils/normalise.mjs";
6
+ import { checkIsDotEth } from "../utils/validation.mjs";
7
7
  var eventFormat = {
8
8
  Domain: {
9
9
  NewOwner: (args) => ({ owner: args.owner.id }),
@@ -84,7 +84,7 @@ var mapEvents = (eventArray, type) => eventArray.map(
84
84
  async function getHistory({ gqlInstance }, name) {
85
85
  const { client } = gqlInstance;
86
86
  const query = gqlInstance.gql`
87
- query getHistory($namehash: String!, $labelhash: String!) {
87
+ query getHistory($namehash: String!) {
88
88
  domain(id: $namehash) {
89
89
  events {
90
90
  id
@@ -204,32 +204,39 @@ async function getHistory({ gqlInstance }, name) {
204
204
  }
205
205
  }
206
206
  `;
207
- const label = name.split(".")[0];
208
207
  const nameHash = namehash(name);
209
- const labelHash = labelhash(label);
208
+ const labels = name.split(".");
209
+ const is2ldEth = checkIsDotEth(labels);
210
210
  const response = await client.request(query, {
211
- namehash: nameHash,
212
- labelhash: labelHash
211
+ namehash: nameHash
213
212
  });
214
213
  const domain = response?.domain;
215
214
  if (!domain)
216
215
  return;
217
216
  const {
218
217
  events: domainEvents,
219
- registration: { events: registrationEvents },
220
218
  resolver: { events: resolverEvents }
221
219
  } = domain;
222
220
  const domainHistory = mapEvents(domainEvents, "Domain");
223
- const registrationHistory = mapEvents(registrationEvents, "Registration");
224
221
  const resolverHistory = mapEvents(
225
222
  resolverEvents.filter(
226
223
  (event) => !event.coinType || event.coinType !== "60"
227
224
  ),
228
225
  "Resolver"
229
226
  );
227
+ if (is2ldEth) {
228
+ const {
229
+ registration: { events: registrationEvents }
230
+ } = domain;
231
+ const registrationHistory = mapEvents(registrationEvents, "Registration");
232
+ return {
233
+ domain: domainHistory,
234
+ registration: registrationHistory,
235
+ resolver: resolverHistory
236
+ };
237
+ }
230
238
  return {
231
239
  domain: domainHistory,
232
- registration: registrationHistory,
233
240
  resolver: resolverHistory
234
241
  };
235
242
  }
@@ -3,6 +3,7 @@ import { defaultAbiCoder } from "@ethersproject/abi";
3
3
  import { hexStripZeros } from "@ethersproject/bytes";
4
4
  import { labelhash } from "../utils/labels.mjs";
5
5
  import { namehash as makeNamehash } from "../utils/normalise.mjs";
6
+ import { checkIsDotEth } from "../utils/validation.mjs";
6
7
  var singleContractOwnerRaw = async ({ contracts }, contract, namehash, labels) => {
7
8
  switch (contract) {
8
9
  case "nameWrapper": {
@@ -60,7 +61,7 @@ var raw = async ({ contracts, multicallWrapper }, name, contract) => {
60
61
  labels
61
62
  );
62
63
  const data = [registryData, nameWrapperData];
63
- if (labels.length === 2 && labels[1] === "eth") {
64
+ if (checkIsDotEth(labels)) {
64
65
  data.push(registrarData);
65
66
  }
66
67
  return multicallWrapper.raw(data);
@@ -17,7 +17,7 @@ var decode = async ({ contracts }, data) => {
17
17
  data
18
18
  );
19
19
  const fuseObj = decodeFuses(fuses);
20
- const expiryDate = expiry.gt(0) && expiry.lt(BigNumber.from(2).pow(32)) ? new Date(expiry.mul(1e3).toString()) : void 0;
20
+ const expiryDate = expiry.gt(0) && expiry.lt(BigNumber.from(2).pow(32)) ? new Date(expiry.mul(1e3).toNumber()) : void 0;
21
21
  return {
22
22
  ...fuseObj,
23
23
  expiryDate,
@@ -1,6 +1,7 @@
1
1
  // src/functions/unwrapName.ts
2
2
  import { keccak256 as solidityKeccak256 } from "@ethersproject/solidity";
3
3
  import { namehash } from "../utils/normalise.mjs";
4
+ import { checkIsDotEth } from "../utils/validation.mjs";
4
5
  async function unwrapName_default({ contracts, signer }, name, {
5
6
  newController,
6
7
  newRegistrant
@@ -9,7 +10,7 @@ async function unwrapName_default({ contracts, signer }, name, {
9
10
  const labelhash = solidityKeccak256(["string"], [labels[0]]);
10
11
  const parentNodehash = namehash(labels.slice(1).join("."));
11
12
  const nameWrapper = (await contracts.getNameWrapper()).connect(signer);
12
- if (labels.length === 2 && labels[1] === "eth") {
13
+ if (checkIsDotEth(labels)) {
13
14
  if (!newRegistrant) {
14
15
  throw new Error("newRegistrant must be specified for .eth names");
15
16
  }
@@ -3,6 +3,7 @@ import { defaultAbiCoder } from "@ethersproject/abi";
3
3
  import { keccak256 as solidityKeccak256 } from "@ethersproject/solidity";
4
4
  import { encodeFuses } from "../utils/fuses.mjs";
5
5
  import { hexEncodeName } from "../utils/hexEncodedName.mjs";
6
+ import { checkIsDotEth } from "../utils/validation.mjs";
6
7
  import { wrappedLabelLengthCheck } from "../utils/wrapper.mjs";
7
8
  async function wrapETH({ contracts }, labels, wrappedOwner, decodedFuses, resolverAddress, signer, address) {
8
9
  const nameWrapper = await contracts?.getNameWrapper();
@@ -45,7 +46,7 @@ async function wrapName_default({ contracts, signer }, name, {
45
46
  resolverAddress = publicResolver.address;
46
47
  const labels = name.split(".");
47
48
  wrappedLabelLengthCheck(labels[0]);
48
- if (labels.length === 2 && labels[1] === "eth") {
49
+ if (checkIsDotEth(labels)) {
49
50
  switch (typeof fuseOptions) {
50
51
  case "object": {
51
52
  decodedFuses = encodeFuses(fuseOptions);
@@ -258,7 +258,7 @@ var ENS = class {
258
258
  getDecryptedName = this.generateRawFunction("getDecryptedName", ["contracts", "gqlInstance"]);
259
259
  universalWrapper = this.generateRawFunction("initialGetters", ["contracts"], "universalWrapper");
260
260
  resolverMulticallWrapper = this.generateRawFunction("initialGetters", ["contracts"], "resolverMulticallWrapper");
261
- multicallWrapper = this.generateRawFunction("initialGetters", ["contracts"], "multicallWrapper");
261
+ multicallWrapper = this.generateRawFunction("initialGetters", ["contracts", "provider"], "multicallWrapper");
262
262
  setName = this.generateWriteFunction(
263
263
  "setName",
264
264
  ["contracts"]
@@ -97,7 +97,7 @@ var ccipLookup = async (provider, transaction, result) => {
97
97
  throw new Error("CCIP Read disabled or provided no URLs");
98
98
  }
99
99
  const tx = {
100
- to: sender,
100
+ to: txSender,
101
101
  data: hexConcat([
102
102
  callbackSelector,
103
103
  encodeBytes([ccipResult, extraData])
@@ -34,6 +34,7 @@ var userSettableFuseEnum = {
34
34
  };
35
35
  var fullFuseEnum = {
36
36
  ...userSettableFuseEnum,
37
+ ...fullParentFuseEnum,
37
38
  CAN_DO_EVERYTHING
38
39
  };
39
40
  var unnamedChildFuses = [
@@ -216,14 +217,14 @@ var decodeNamedFuses = (fuses, arr) => {
216
217
  const fuseObj = Object.fromEntries(
217
218
  arr.map((fuse) => [
218
219
  fuse,
219
- (fuses & userSettableFuseEnum[fuse]) > 0
220
+ (fuses & fullFuseEnum[fuse]) === fullFuseEnum[fuse]
220
221
  ])
221
222
  );
222
223
  return fuseObj;
223
224
  };
224
225
  var decodeUnnamedFuses = (fuses, arr) => {
225
226
  const fuseObj = Object.fromEntries(
226
- arr.map((fuse) => [fuse, (fuses & fuse) > 0])
227
+ arr.map((fuse) => [fuse, (fuses & fuse) === fuse])
227
228
  );
228
229
  return fuseObj;
229
230
  };
@@ -1,5 +1,13 @@
1
1
  // src/utils/singleCall.ts
2
- var singleCall_default = async (provider, ensData, func, ...data) => func.raw(ensData, ...data).then((rawData) => provider.call({ ...rawData, ccipReadEnabled: true })).catch(() => null).then((ret) => func.decode(ensData, ret, ...data));
2
+ var singleCall_default = async (provider, ensData, func, ...data) => {
3
+ const { passthrough, ...rawData } = await func.raw(ensData, ...data);
4
+ const result = await provider.call({ ...rawData, ccipReadEnabled: true }).catch(() => null);
5
+ if (!result)
6
+ return;
7
+ if (passthrough)
8
+ return func.decode(ensData, result, passthrough, ...data);
9
+ return func.decode(ensData, result, ...data);
10
+ };
3
11
  export {
4
12
  singleCall_default as default
5
13
  };
@@ -60,7 +60,9 @@ var parseInputType = (input) => {
60
60
  type: "label"
61
61
  };
62
62
  };
63
+ var checkIsDotEth = (labels) => labels.length === 2 && labels[1] === "eth";
63
64
  export {
65
+ checkIsDotEth,
64
66
  parseInputType,
65
67
  validateName,
66
68
  validateTLD
@@ -1,9 +1,16 @@
1
+ import { TransactionRequest } from '@ethersproject/abstract-provider';
1
2
  import { BatchFunctionResult, ENSArgs, RawFunction } from '..';
2
3
  declare const _default: {
3
4
  raw: ({ multicallWrapper }: ENSArgs<"multicallWrapper">, ...items: BatchFunctionResult<RawFunction>[]) => Promise<{
5
+ passthrough: {
6
+ to: string;
7
+ data: string;
8
+ }[];
4
9
  to: string;
5
10
  data: string;
6
11
  }>;
7
- decode: ({ multicallWrapper }: ENSArgs<"multicallWrapper">, data: string, ...items: BatchFunctionResult<RawFunction>[]) => Promise<any[] | undefined>;
12
+ decode: ({ multicallWrapper }: ENSArgs<"multicallWrapper">, data: string, passthrough: TransactionRequest & {
13
+ passthrough?: any;
14
+ }[], ...items: BatchFunctionResult<RawFunction>[]) => Promise<any[] | undefined>;
8
15
  };
9
16
  export default _default;
@@ -24,5 +24,21 @@ export declare function getHistory({ gqlInstance }: ENSArgs<'gqlInstance'>, name
24
24
  id: string;
25
25
  data: object;
26
26
  }[];
27
+ } | {
28
+ domain: {
29
+ type: DomainEvent;
30
+ blockNumber: number;
31
+ transactionHash: string;
32
+ id: string;
33
+ data: object;
34
+ }[];
35
+ resolver: {
36
+ type: ResolverEvent;
37
+ blockNumber: number;
38
+ transactionHash: string;
39
+ id: string;
40
+ data: object;
41
+ }[];
42
+ registration?: undefined;
27
43
  } | undefined>;
28
44
  export {};
@@ -133,10 +133,16 @@ export declare class ENS {
133
133
  withProvider: (provider: JsonRpcProvider) => ENS;
134
134
  batch: GeneratedBatchFunction<{
135
135
  raw: ({ multicallWrapper }: ENSArgs<"multicallWrapper">, ...items: BatchFunctionResult<RawFunction>[]) => Promise<{
136
+ passthrough: {
137
+ to: string;
138
+ data: string;
139
+ }[];
136
140
  to: string;
137
141
  data: string;
138
142
  }>;
139
- decode: ({ multicallWrapper }: ENSArgs<"multicallWrapper">, data: string, ...items: BatchFunctionResult<RawFunction>[]) => Promise<any[] | undefined>;
143
+ decode: ({ multicallWrapper }: ENSArgs<"multicallWrapper">, data: string, passthrough: import("@ethersproject/abstract-provider").TransactionRequest & {
144
+ passthrough?: any;
145
+ }[], ...items: BatchFunctionResult<RawFunction>[]) => Promise<any[] | undefined>;
140
146
  }>;
141
147
  getProfile: (nameOrAddress: string, options?: ({
142
148
  contentHash?: boolean | undefined;
@@ -306,6 +312,22 @@ export declare class ENS {
306
312
  id: string;
307
313
  data: object;
308
314
  }[];
315
+ } | {
316
+ domain: {
317
+ type: "Transfer" | "NewOwner" | "NewResolver" | "NewTTL" | "ExpiryExtended" | "FusesSet" | "NameUnwrapped" | "NameWrapped" | "WrappedTransfer";
318
+ blockNumber: number;
319
+ transactionHash: string;
320
+ id: string;
321
+ data: object;
322
+ }[];
323
+ resolver: {
324
+ type: "AddrChanged" | "ContenthashChanged" | "InterfaceChanged" | "NameChanged" | "PubkeyChanged" | "TextChanged" | "VersionChanged" | "MulticoinAddrChanged" | "AbiChanged" | "AuthorisationChanged";
325
+ blockNumber: number;
326
+ transactionHash: string;
327
+ id: string;
328
+ data: object;
329
+ }[];
330
+ registration?: undefined;
309
331
  } | undefined>;
310
332
  getContentHash: GeneratedRawFunction<{
311
333
  raw: ({ contracts, universalWrapper }: ENSArgs<"contracts" | "universalWrapper">, name: string) => Promise<{
@@ -30,6 +30,7 @@ export declare const userSettableFuseEnum: {
30
30
  };
31
31
  export declare const fullFuseEnum: {
32
32
  CAN_DO_EVERYTHING: number;
33
+ IS_DOT_ETH: 131072;
33
34
  PARENT_CANNOT_CONTROL: number;
34
35
  CAN_EXTEND_EXPIRY: number;
35
36
  CANNOT_UNWRAP: 1;
@@ -3,6 +3,7 @@ declare const _default: (provider: Provider, ensData: any, func: {
3
3
  raw: (...args: any[]) => Promise<{
4
4
  to: string;
5
5
  data: string;
6
+ passthrough?: any;
6
7
  }>;
7
8
  decode: (...args: any[]) => Promise<any>;
8
9
  }, ...data: any[]) => Promise<any>;
@@ -5,4 +5,5 @@ declare type InputType = {
5
5
  info?: 'short' | 'supported' | 'unsupported';
6
6
  };
7
7
  export declare const parseInputType: (input: string) => InputType;
8
+ export declare const checkIsDotEth: (labels: string[]) => boolean;
8
9
  export {};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ensdomains/ensjs",
3
- "version": "3.0.0-alpha.43",
3
+ "version": "3.0.0-alpha.45",
4
4
  "description": "ENS javascript library for contract interaction",
5
5
  "main": "./dist/cjs/index.js",
6
6
  "module": "./dist/esm/index.mjs",
@@ -9,22 +9,26 @@
9
9
  ".": {
10
10
  "import": "./dist/esm/index.mjs",
11
11
  "require": "./dist/cjs/index.js",
12
- "default": "./dist/esm/index.mjs"
12
+ "default": "./dist/esm/index.mjs",
13
+ "types": "./dist/types/index.d.ts"
13
14
  },
14
15
  "./*.js": {
15
16
  "import": "./dist/esm/*.mjs",
16
17
  "require": "./dist/cjs/*.js",
17
- "default": "./dist/esm/*.mjs"
18
+ "default": "./dist/esm/*.mjs",
19
+ "types": "./dist/types/*.d.ts"
18
20
  },
19
21
  "./*.mjs": {
20
22
  "import": "./dist/esm/*.mjs",
21
23
  "require": "./dist/cjs/*.js",
22
- "default": "./dist/esm/*.mjs"
24
+ "default": "./dist/esm/*.mjs",
25
+ "types": "./dist/types/*.d.ts"
23
26
  },
24
27
  "./*": {
25
28
  "import": "./dist/esm/*.mjs",
26
29
  "require": "./dist/cjs/*.js",
27
- "default": "./dist/esm/*.mjs"
30
+ "default": "./dist/esm/*.mjs",
31
+ "types": "./dist/types/*.d.ts"
28
32
  }
29
33
  },
30
34
  "typesVersions": {
@@ -69,7 +73,7 @@
69
73
  },
70
74
  "devDependencies": {
71
75
  "@ensdomains/buffer": "^0.0.13",
72
- "@ensdomains/ens-contracts": "^0.0.16",
76
+ "@ensdomains/ens-contracts": "^0.0.17",
73
77
  "@ensdomains/ens-test-env": "0.3.7",
74
78
  "@ethersproject/abi": "^5.6.4",
75
79
  "@ethersproject/abstract-provider": "^5.7.0",
@@ -20,19 +20,19 @@ const addresses: Record<
20
20
  '1': '0x283af0b28c62c092c9727f1ee09c02ca627eb7f5',
21
21
  '3': '0xa5627AB7Ae47063B533622C34FEBDb52d3281dF8',
22
22
  '4': '0x283af0b28c62c092c9727f1ee09c02ca627eb7f5',
23
- '5': '0xb7A1f9e633fdeaAa2ec44bE00a61a7Db9a733D70',
23
+ '5': '0x603A4F2e7615d0099244496883062bA2eFBbeaf0',
24
24
  },
25
25
  Multicall: '0xcA11bde05977b3631167028862bE2a173976CA11',
26
26
  NameWrapper: {
27
27
  '1': '0x0000000000000000000000000000000000000000',
28
28
  '3': '0xF82155e2a43Be0871821E9654Fc8Ae894FB8307C',
29
29
  '4': '0x0000000000000000000000000000000000000000',
30
- '5': '0xEe1F756aCde7E81B2D8cC6aB3c8A1E2cE6db0F39',
30
+ '5': '0x060f1546642E67c485D56248201feA2f9AB1803C',
31
31
  },
32
32
  PublicResolver: {
33
33
  '1': '0x4976fb03C32e5B8cfe2b6cCB31c09Ba78EBaBa41',
34
34
  '3': '0x13F0659Ee6bb7484C884FEeFb7F75C93951ef837',
35
- '5': '0x2800Ec5BAB9CE9226d19E0ad5BC607e3cfC4347E',
35
+ '5': '0x19c2d5D0f035563344dBB7bE5fD09c8dad62b001',
36
36
  },
37
37
  ENSRegistry: {
38
38
  '1': '0x00000000000c2e074ec69a0dfb2997ba6c7d2e1e',
@@ -1,3 +1,4 @@
1
+ import { TransactionRequest } from '@ethersproject/abstract-provider'
1
2
  import { BatchFunctionResult, ENSArgs, RawFunction } from '..'
2
3
 
3
4
  const raw = async (
@@ -12,21 +13,30 @@ const raw = async (
12
13
  return rawRef(...args)
13
14
  }),
14
15
  )
15
- return multicallWrapper.raw(rawDataArr)
16
+ const response = await multicallWrapper.raw(rawDataArr)
17
+ return { ...response, passthrough: rawDataArr }
16
18
  }
17
19
 
18
20
  const decode = async (
19
21
  { multicallWrapper }: ENSArgs<'multicallWrapper'>,
20
22
  data: string,
23
+ passthrough: TransactionRequest & { passthrough?: any }[],
21
24
  ...items: BatchFunctionResult<RawFunction>[]
22
25
  ): Promise<any[] | undefined> => {
23
- const response = await multicallWrapper.decode(data)
26
+ const response = await multicallWrapper.decode(data, passthrough)
24
27
  if (!response) return
25
28
 
26
29
  return Promise.all(
27
- response.map((ret: any, i: number) =>
28
- items[i].decode(ret.returnData, ...items[i].args),
29
- ),
30
+ response.map((ret: any, i: number) => {
31
+ if (passthrough[i].passthrough) {
32
+ return items[i].decode(
33
+ ret.returnData,
34
+ passthrough[i].passthrough,
35
+ ...items[i].args,
36
+ )
37
+ }
38
+ return items[i].decode(ret.returnData, ...items[i].args)
39
+ }),
30
40
  )
31
41
  }
32
42
 
@@ -0,0 +1,62 @@
1
+ import dotenv from 'dotenv'
2
+ import { ENS } from '..'
3
+ import setup from '../tests/setup'
4
+
5
+ dotenv.config()
6
+
7
+ let ensInstance: ENS
8
+
9
+ beforeAll(async () => {
10
+ ;({ ensInstance } = await setup(true))
11
+ })
12
+
13
+ jest.setTimeout(20000)
14
+
15
+ describe('CCIP', () => {
16
+ describe('getProfile', () => {
17
+ it('should return a profile from a ccip-read name', async () => {
18
+ const result = await ensInstance.getProfile('1.offchainexample.eth', {
19
+ fallback: {
20
+ texts: ['email', 'description'],
21
+ contentHash: true,
22
+ coinTypes: ['LTC', '60'],
23
+ },
24
+ })
25
+ expect(result).toBeTruthy()
26
+ if (result) {
27
+ expect(result.address).toBe(
28
+ '0x41563129cDbbD0c5D3e1c86cf9563926b243834d',
29
+ )
30
+ }
31
+ })
32
+ })
33
+ describe('batch', () => {
34
+ it('allows batch ccip', async () => {
35
+ const result = await ensInstance.batch(
36
+ ensInstance.getAddr.batch('1.offchainexample.eth'),
37
+ ensInstance.getAddr.batch('1.offchainexample.eth', 'LTC'),
38
+ ensInstance.getText.batch('1.offchainexample.eth', 'email'),
39
+ )
40
+ expect(result).toBeTruthy()
41
+ if (result) {
42
+ expect(result[0]).toBe('0x41563129cDbbD0c5D3e1c86cf9563926b243834d')
43
+ expect(result[1]).toStrictEqual({
44
+ coin: 'LTC',
45
+ addr: 'MQMcJhpWHYVeQArcZR3sBgyPZxxRtnH441',
46
+ })
47
+ expect(result[2]).toBe('nick@ens.domains')
48
+ }
49
+ })
50
+ it('allows nested batch ccip', async () => {
51
+ const result = await ensInstance.batch(
52
+ ensInstance.batch.batch(
53
+ ensInstance.getAddr.batch('1.offchainexample.eth'),
54
+ ),
55
+ )
56
+ expect(result).toBeTruthy()
57
+ if (result) {
58
+ expect(result[0]![0]).toBe('0x41563129cDbbD0c5D3e1c86cf9563926b243834d')
59
+ }
60
+ })
61
+ })
62
+ })
@@ -2,6 +2,7 @@ import { BigNumber } from '@ethersproject/bignumber'
2
2
  import { keccak256 as solidityKeccak256 } from '@ethersproject/solidity'
3
3
  import { ENSArgs } from '..'
4
4
  import { namehash } from '../utils/normalise'
5
+ import { checkIsDotEth } from '../utils/validation'
5
6
 
6
7
  type ContractOption = 'registrar' | 'nameWrapper'
7
8
 
@@ -56,7 +57,7 @@ const getContractToUse = (
56
57
  labels: string[],
57
58
  ) => {
58
59
  if (contract) return contract
59
- if (labels.length === 2 && labels[1] === 'eth') {
60
+ if (checkIsDotEth(labels)) {
60
61
  return 'registrar'
61
62
  }
62
63
  return 'nameWrapper'
@@ -35,4 +35,15 @@ describe('getHistory', () => {
35
35
  expect(result).toHaveProperty('registration')
36
36
  }
37
37
  })
38
+ it('should return the history of a subname', async () => {
39
+ const result = await ensInstance.getHistory(
40
+ 'test.wrapped-with-subnames.eth',
41
+ )
42
+ expect(result).toBeTruthy()
43
+ if (result) {
44
+ expect(result).toHaveProperty('domain')
45
+ expect(result).toHaveProperty('resolver')
46
+ expect(result).not.toHaveProperty('registration')
47
+ }
48
+ })
38
49
  })
@@ -2,7 +2,6 @@ import { formatsByCoinType } from '@ensdomains/address-encoder'
2
2
  import { hexStripZeros } from '@ethersproject/bytes'
3
3
  import { ENSArgs } from '..'
4
4
  import { decodeContenthash } from '../utils/contentHash'
5
- import { labelhash } from '../utils/labels'
6
5
  import { namehash } from '../utils/normalise'
7
6
  import {
8
7
  AbiChanged,
@@ -28,6 +27,7 @@ import {
28
27
  VersionChanged,
29
28
  WrappedTransfer,
30
29
  } from '../utils/subgraph-types'
30
+ import { checkIsDotEth } from '../utils/validation'
31
31
 
32
32
  type DomainEvent =
33
33
  | 'NewOwner'
@@ -154,7 +154,7 @@ export async function getHistory(
154
154
  ) {
155
155
  const { client } = gqlInstance
156
156
  const query = gqlInstance.gql`
157
- query getHistory($namehash: String!, $labelhash: String!) {
157
+ query getHistory($namehash: String!) {
158
158
  domain(id: $namehash) {
159
159
  events {
160
160
  id
@@ -275,14 +275,12 @@ export async function getHistory(
275
275
  }
276
276
  `
277
277
 
278
- const label = name.split('.')[0]
279
-
280
278
  const nameHash = namehash(name)
281
- const labelHash = labelhash(label)
279
+ const labels = name.split('.')
280
+ const is2ldEth = checkIsDotEth(labels)
282
281
 
283
282
  const response = await client.request(query, {
284
283
  namehash: nameHash,
285
- labelhash: labelHash,
286
284
  })
287
285
  const domain = response?.domain
288
286
 
@@ -290,12 +288,10 @@ export async function getHistory(
290
288
 
291
289
  const {
292
290
  events: domainEvents,
293
- registration: { events: registrationEvents },
294
291
  resolver: { events: resolverEvents },
295
292
  } = domain
296
293
 
297
294
  const domainHistory = mapEvents(domainEvents, 'Domain')
298
- const registrationHistory = mapEvents(registrationEvents, 'Registration')
299
295
  const resolverHistory = mapEvents(
300
296
  // remove duplicate events for ETH cointype
301
297
  resolverEvents.filter(
@@ -304,9 +300,20 @@ export async function getHistory(
304
300
  'Resolver',
305
301
  )
306
302
 
303
+ if (is2ldEth) {
304
+ const {
305
+ registration: { events: registrationEvents },
306
+ } = domain
307
+ const registrationHistory = mapEvents(registrationEvents, 'Registration')
308
+ return {
309
+ domain: domainHistory,
310
+ registration: registrationHistory,
311
+ resolver: resolverHistory,
312
+ }
313
+ }
314
+
307
315
  return {
308
316
  domain: domainHistory,
309
- registration: registrationHistory,
310
317
  resolver: resolverHistory,
311
318
  }
312
319
  }
@@ -4,6 +4,7 @@ import { hexStripZeros } from '@ethersproject/bytes'
4
4
  import { ENSArgs } from '..'
5
5
  import { labelhash } from '../utils/labels'
6
6
  import { namehash as makeNamehash } from '../utils/normalise'
7
+ import { checkIsDotEth } from '../utils/validation'
7
8
 
8
9
  type Owner = {
9
10
  registrant?: string
@@ -87,7 +88,7 @@ const raw = async (
87
88
 
88
89
  const data: { to: string; data: string }[] = [registryData, nameWrapperData]
89
90
 
90
- if (labels.length === 2 && labels[1] === 'eth') {
91
+ if (checkIsDotEth(labels)) {
91
92
  data.push(registrarData)
92
93
  }
93
94
 
@@ -52,13 +52,16 @@ describe('getWrapperData', () => {
52
52
  expect(result.child.CANNOT_UNWRAP).toBe(true)
53
53
  expect(result.child.CANNOT_CREATE_SUBDOMAIN).toBe(true)
54
54
  expect(result.child.CANNOT_SET_TTL).toBe(true)
55
+ expect(result.parent.IS_DOT_ETH).toBe(true)
55
56
  }
56
57
  })
57
58
  it('should return correct expiry', async () => {
58
59
  const result = await ensInstance.getWrapperData('wrapped.eth')
59
60
  expect(result).toBeTruthy()
60
61
  if (result) {
62
+ console.log(result.expiryDate)
61
63
  expect(result.expiryDate).toBeInstanceOf(Date)
64
+ expect(Number.isNaN(result.expiryDate?.getTime())).toBe(false)
62
65
  }
63
66
  })
64
67
  })
@@ -23,7 +23,7 @@ const decode = async ({ contracts }: ENSArgs<'contracts'>, data: string) => {
23
23
 
24
24
  const expiryDate =
25
25
  expiry.gt(0) && expiry.lt(BigNumber.from(2).pow(32))
26
- ? new Date(expiry.mul(1000).toString())
26
+ ? new Date(expiry.mul(1000).toNumber())
27
27
  : undefined
28
28
 
29
29
  return {
@@ -2,6 +2,7 @@ import { keccak256 as solidityKeccak256 } from '@ethersproject/solidity'
2
2
 
3
3
  import { ENSArgs } from '..'
4
4
  import { namehash } from '../utils/normalise'
5
+ import { checkIsDotEth } from '../utils/validation'
5
6
 
6
7
  export default async function (
7
8
  { contracts, signer }: ENSArgs<'contracts' | 'signer'>,
@@ -20,7 +21,7 @@ export default async function (
20
21
 
21
22
  const nameWrapper = (await contracts!.getNameWrapper()!).connect(signer)
22
23
 
23
- if (labels.length === 2 && labels[1] === 'eth') {
24
+ if (checkIsDotEth(labels)) {
24
25
  if (!newRegistrant) {
25
26
  throw new Error('newRegistrant must be specified for .eth names')
26
27
  }
@@ -4,6 +4,7 @@ import { keccak256 as solidityKeccak256 } from '@ethersproject/solidity'
4
4
  import { ENSArgs } from '..'
5
5
  import { CombinedFuseInput, encodeFuses } from '../utils/fuses'
6
6
  import { hexEncodeName } from '../utils/hexEncodedName'
7
+ import { checkIsDotEth } from '../utils/validation'
7
8
  import { Expiry, wrappedLabelLengthCheck } from '../utils/wrapper'
8
9
 
9
10
  async function wrapETH(
@@ -84,7 +85,7 @@ export default async function (
84
85
  const labels = name.split('.')
85
86
  wrappedLabelLengthCheck(labels[0])
86
87
 
87
- if (labels.length === 2 && labels[1] === 'eth') {
88
+ if (checkIsDotEth(labels)) {
88
89
  switch (typeof fuseOptions) {
89
90
  case 'object': {
90
91
  decodedFuses = encodeFuses(fuseOptions)
package/src/index.ts CHANGED
@@ -562,7 +562,7 @@ export class ENS {
562
562
 
563
563
  public multicallWrapper = this.generateRawFunction<
564
564
  FunctionTypes['multicallWrapper']
565
- >('initialGetters', ['contracts'], 'multicallWrapper')
565
+ >('initialGetters', ['contracts', 'provider'], 'multicallWrapper')
566
566
 
567
567
  public setName = this.generateWriteFunction<FunctionTypes['setName']>(
568
568
  'setName',
package/src/utils/ccip.ts CHANGED
@@ -133,7 +133,7 @@ const ccipLookup = async (
133
133
  }
134
134
 
135
135
  const tx = {
136
- to: sender,
136
+ to: txSender,
137
137
  data: hexConcat([
138
138
  callbackSelector,
139
139
  encodeBytes([ccipResult, extraData!]),
@@ -45,6 +45,7 @@ export const userSettableFuseEnum = {
45
45
 
46
46
  export const fullFuseEnum = {
47
47
  ...userSettableFuseEnum,
48
+ ...fullParentFuseEnum,
48
49
  CAN_DO_EVERYTHING,
49
50
  }
50
51
 
@@ -303,9 +304,8 @@ const decodeNamedFuses = (fuses: number, arr: readonly string[]) => {
303
304
  const fuseObj = Object.fromEntries(
304
305
  arr.map((fuse) => [
305
306
  fuse,
306
- (fuses &
307
- userSettableFuseEnum[fuse as keyof typeof userSettableFuseEnum]) >
308
- 0,
307
+ (fuses & fullFuseEnum[fuse as keyof typeof fullFuseEnum]) ===
308
+ fullFuseEnum[fuse as keyof typeof fullFuseEnum],
309
309
  ]),
310
310
  )
311
311
 
@@ -314,7 +314,7 @@ const decodeNamedFuses = (fuses: number, arr: readonly string[]) => {
314
314
 
315
315
  const decodeUnnamedFuses = (fuses: number, arr: readonly number[]) => {
316
316
  const fuseObj = Object.fromEntries(
317
- arr.map((fuse) => [fuse, (fuses & fuse) > 0]),
317
+ arr.map((fuse) => [fuse, (fuses & fuse) === fuse]),
318
318
  )
319
319
 
320
320
  return fuseObj
@@ -4,13 +4,18 @@ export default async (
4
4
  provider: Provider,
5
5
  ensData: any,
6
6
  func: {
7
- raw: (...args: any[]) => Promise<{ to: string; data: string }>
7
+ raw: (
8
+ ...args: any[]
9
+ ) => Promise<{ to: string; data: string; passthrough?: any }>
8
10
  decode: (...args: any[]) => Promise<any>
9
11
  },
10
12
  ...data: any[]
11
- ) =>
12
- func
13
- .raw(ensData, ...data)
14
- .then((rawData) => provider.call({ ...rawData, ccipReadEnabled: true }))
13
+ ) => {
14
+ const { passthrough, ...rawData } = await func.raw(ensData, ...data)
15
+ const result = await provider
16
+ .call({ ...rawData, ccipReadEnabled: true })
15
17
  .catch(() => null)
16
- .then((ret) => func.decode(ensData, ret, ...data))
18
+ if (!result) return
19
+ if (passthrough) return func.decode(ensData, result, passthrough, ...data)
20
+ return func.decode(ensData, result, ...data)
21
+ }
@@ -70,3 +70,6 @@ export const parseInputType = (input: string): InputType => {
70
70
  type: 'label',
71
71
  }
72
72
  }
73
+
74
+ export const checkIsDotEth = (labels: string[]) =>
75
+ labels.length === 2 && labels[1] === 'eth'
@@ -1,29 +0,0 @@
1
- import dotenv from 'dotenv'
2
- import { ENS } from '..'
3
- import setup from '../tests/setup'
4
-
5
- dotenv.config()
6
-
7
- let ensInstance: ENS
8
-
9
- beforeAll(async () => {
10
- ;({ ensInstance } = await setup(true))
11
- })
12
-
13
- jest.setTimeout(20000)
14
-
15
- describe('getProfile', () => {
16
- it('should return a profile from a ccip-read name', async () => {
17
- const result = await ensInstance.getProfile('1.offchainexample.eth', {
18
- fallback: {
19
- texts: ['email', 'description'],
20
- contentHash: true,
21
- coinTypes: ['0', '60'],
22
- },
23
- })
24
- expect(result).toBeTruthy()
25
- if (result) {
26
- expect(result.address).toBe('0x41563129cDbbD0c5D3e1c86cf9563926b243834d')
27
- }
28
- })
29
- })