@ensdomains/ensjs 3.0.0-alpha.1 → 3.0.0-alpha.10

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 (147) hide show
  1. package/README.md +2 -0
  2. package/dist/cjs/GqlManager.d.ts +3 -0
  3. package/dist/cjs/GqlManager.js +62 -2
  4. package/dist/cjs/functions/burnFuses.d.ts +3 -2
  5. package/dist/cjs/functions/burnFuses.js +4 -8
  6. package/dist/cjs/functions/createSubname.d.ts +1 -5
  7. package/dist/cjs/functions/createSubname.js +5 -8
  8. package/dist/cjs/functions/deleteSubname.d.ts +3 -3
  9. package/dist/cjs/functions/deleteSubname.js +5 -2
  10. package/dist/cjs/functions/getDNSOwner.d.ts +7 -0
  11. package/dist/cjs/functions/getDNSOwner.js +81 -0
  12. package/dist/cjs/functions/getFuses.js +3 -2
  13. package/dist/cjs/functions/getOwner.js +7 -6
  14. package/dist/cjs/functions/getProfile.d.ts +4 -1
  15. package/dist/cjs/functions/getProfile.js +102 -24
  16. package/dist/cjs/functions/getRecords.d.ts +1 -0
  17. package/dist/cjs/functions/getSpecificRecord.js +22 -5
  18. package/dist/cjs/functions/getSubnames.js +6 -6
  19. package/dist/cjs/functions/setName.d.ts +4 -3
  20. package/dist/cjs/functions/setName.js +5 -10
  21. package/dist/cjs/functions/setRecord.d.ts +18 -0
  22. package/dist/cjs/functions/setRecord.js +27 -0
  23. package/dist/cjs/functions/setRecords.d.ts +4 -2
  24. package/dist/cjs/functions/setRecords.js +14 -12
  25. package/dist/cjs/functions/setResolver.d.ts +4 -4
  26. package/dist/cjs/functions/setResolver.js +6 -12
  27. package/dist/cjs/functions/transferName.d.ts +4 -3
  28. package/dist/cjs/functions/transferName.js +9 -13
  29. package/dist/cjs/functions/transferSubname.d.ts +4 -3
  30. package/dist/cjs/functions/transferSubname.js +5 -8
  31. package/dist/cjs/functions/unwrapName.d.ts +4 -3
  32. package/dist/cjs/functions/unwrapName.js +5 -9
  33. package/dist/cjs/functions/wrapName.d.ts +5 -3
  34. package/dist/cjs/functions/wrapName.js +8 -12
  35. package/dist/cjs/index.d.ts +48 -46
  36. package/dist/cjs/index.js +43 -19
  37. package/dist/cjs/utils/labels.js +5 -4
  38. package/dist/cjs/utils/makeHashIndexes.js +2 -2
  39. package/dist/cjs/utils/normalise.d.ts +1 -0
  40. package/dist/cjs/utils/normalise.js +27 -1
  41. package/dist/cjs/utils/recordHelpers.d.ts +3 -0
  42. package/dist/cjs/utils/recordHelpers.js +42 -15
  43. package/dist/cjs/utils/registerHelpers.js +3 -4
  44. package/dist/cjs/utils/writeTx.d.ts +4 -0
  45. package/dist/cjs/utils/writeTx.js +3 -0
  46. package/dist/esm/GqlManager.d.ts +3 -0
  47. package/dist/esm/GqlManager.js +58 -2
  48. package/dist/esm/functions/burnFuses.d.ts +3 -2
  49. package/dist/esm/functions/burnFuses.js +4 -8
  50. package/dist/esm/functions/createSubname.d.ts +1 -5
  51. package/dist/esm/functions/createSubname.js +5 -8
  52. package/dist/esm/functions/deleteSubname.d.ts +3 -3
  53. package/dist/esm/functions/deleteSubname.js +5 -2
  54. package/dist/esm/functions/getDNSOwner.d.ts +7 -0
  55. package/dist/esm/functions/getDNSOwner.js +51 -0
  56. package/dist/esm/functions/getFuses.js +4 -3
  57. package/dist/esm/functions/getOwner.js +7 -6
  58. package/dist/esm/functions/getProfile.d.ts +4 -1
  59. package/dist/esm/functions/getProfile.js +102 -24
  60. package/dist/esm/functions/getRecords.d.ts +1 -0
  61. package/dist/esm/functions/getSpecificRecord.js +22 -5
  62. package/dist/esm/functions/getSubnames.js +3 -3
  63. package/dist/esm/functions/setName.d.ts +4 -3
  64. package/dist/esm/functions/setName.js +5 -10
  65. package/dist/esm/functions/setRecord.d.ts +18 -0
  66. package/dist/esm/functions/setRecord.js +24 -0
  67. package/dist/esm/functions/setRecords.d.ts +4 -2
  68. package/dist/esm/functions/setRecords.js +14 -12
  69. package/dist/esm/functions/setResolver.d.ts +4 -4
  70. package/dist/esm/functions/setResolver.js +6 -12
  71. package/dist/esm/functions/transferName.d.ts +4 -3
  72. package/dist/esm/functions/transferName.js +9 -13
  73. package/dist/esm/functions/transferSubname.d.ts +4 -3
  74. package/dist/esm/functions/transferSubname.js +5 -8
  75. package/dist/esm/functions/unwrapName.d.ts +4 -3
  76. package/dist/esm/functions/unwrapName.js +5 -9
  77. package/dist/esm/functions/wrapName.d.ts +5 -3
  78. package/dist/esm/functions/wrapName.js +8 -12
  79. package/dist/esm/index.d.ts +48 -46
  80. package/dist/esm/index.js +43 -19
  81. package/dist/esm/utils/labels.js +5 -4
  82. package/dist/esm/utils/makeHashIndexes.js +2 -2
  83. package/dist/esm/utils/normalise.d.ts +1 -0
  84. package/dist/esm/utils/normalise.js +25 -0
  85. package/dist/esm/utils/recordHelpers.d.ts +3 -0
  86. package/dist/esm/utils/recordHelpers.js +40 -14
  87. package/dist/esm/utils/registerHelpers.js +3 -4
  88. package/dist/esm/utils/writeTx.d.ts +4 -0
  89. package/dist/esm/utils/writeTx.js +1 -0
  90. package/package.json +15 -7
  91. package/src/@types/dns-packet/index.d.ts +114 -0
  92. package/src/GqlManager.test.ts +170 -0
  93. package/src/GqlManager.ts +67 -2
  94. package/src/{tests → functions}/batch.test.ts +1 -1
  95. package/src/{tests → functions}/batchWrappers.test.ts +1 -1
  96. package/src/{tests → functions}/burnFuses.test.ts +12 -10
  97. package/src/functions/burnFuses.ts +9 -11
  98. package/src/{tests → functions}/createSubname.test.ts +12 -16
  99. package/src/functions/createSubname.ts +7 -13
  100. package/src/{tests → functions}/deleteSubname.test.ts +32 -32
  101. package/src/functions/deleteSubname.ts +9 -12
  102. package/src/functions/getDNSOwner.test.ts +122 -0
  103. package/src/functions/getDNSOwner.ts +61 -0
  104. package/src/{tests → functions}/getExpiry.test.ts +1 -1
  105. package/src/{tests → functions}/getFuses.test.ts +12 -10
  106. package/src/functions/getFuses.ts +4 -3
  107. package/src/{tests → functions}/getHistory.test.ts +1 -1
  108. package/src/{tests → functions}/getName.test.ts +1 -1
  109. package/src/{tests → functions}/getNames.test.ts +1 -1
  110. package/src/{tests → functions}/getOwner.test.ts +14 -2
  111. package/src/functions/getOwner.ts +7 -7
  112. package/src/{tests → functions}/getProfile.test.ts +45 -12
  113. package/src/functions/getProfile.ts +151 -24
  114. package/src/functions/getRecords.ts +1 -0
  115. package/src/{tests → functions}/getResolver.test.ts +1 -1
  116. package/src/{tests → functions}/getSpecificRecord.test.ts +1 -1
  117. package/src/functions/getSpecificRecord.ts +28 -8
  118. package/src/{tests → functions}/getSubnames.test.ts +1 -1
  119. package/src/functions/getSubnames.ts +68 -66
  120. package/src/{tests → functions}/makeCommitment.test.ts +1 -1
  121. package/src/functions/normalise.test.ts +22 -0
  122. package/src/{tests → functions}/setName.test.ts +3 -2
  123. package/src/functions/setName.ts +15 -17
  124. package/src/functions/setRecord.test.ts +100 -0
  125. package/src/functions/setRecord.ts +63 -0
  126. package/src/{tests → functions}/setRecords.test.ts +12 -10
  127. package/src/functions/setRecords.ts +22 -16
  128. package/src/{tests → functions}/setResolver.test.ts +12 -15
  129. package/src/functions/setResolver.ts +15 -20
  130. package/src/{tests → functions}/transferName.test.ts +30 -31
  131. package/src/functions/transferName.ts +19 -22
  132. package/src/{tests → functions}/transferSubname.test.ts +34 -34
  133. package/src/functions/transferSubname.ts +21 -13
  134. package/src/{tests → functions}/unwrapName.test.ts +24 -23
  135. package/src/functions/unwrapName.ts +20 -15
  136. package/src/{tests → functions}/wrapName.test.ts +19 -19
  137. package/src/functions/wrapName.ts +20 -22
  138. package/src/index.ts +115 -26
  139. package/src/tests/populateTransaction.test.ts +40 -0
  140. package/src/tests/signerInjection.test.ts +46 -0
  141. package/src/tests/withProvider.test.ts +1 -1
  142. package/src/utils/labels.ts +6 -4
  143. package/src/utils/makeHashIndexes.ts +4 -4
  144. package/src/utils/normalise.ts +29 -0
  145. package/src/utils/recordHelpers.ts +52 -18
  146. package/src/utils/registerHelpers.ts +3 -4
  147. package/src/utils/writeTx.ts +6 -0
@@ -1,6 +1,8 @@
1
1
  import { ethers } from 'ethers';
2
2
  import { ENSArgs } from '..';
3
3
  import type { FuseOptions } from '../@types/FuseOptions';
4
- export default function ({ contracts, provider }: ENSArgs<'contracts' | 'provider'>, name: string, wrappedOwner: string, fuseOptions?: FuseOptions | string | number, resolverAddress?: string, options?: {
5
- addressOrIndex?: string | number;
6
- }): Promise<ethers.ContractTransaction>;
4
+ export default function ({ contracts, signer, populate }: ENSArgs<'contracts' | 'signer' | 'populate'>, name: string, { wrappedOwner, fuseOptions, resolverAddress, }: {
5
+ wrappedOwner: string;
6
+ fuseOptions?: FuseOptions | string | number;
7
+ resolverAddress?: string;
8
+ }): Promise<ethers.PopulatedTransaction>;
@@ -5,24 +5,20 @@ async function wrapETH({ contracts }, labels, wrappedOwner, decodedFuses, resolv
5
5
  const nameWrapper = await contracts?.getNameWrapper();
6
6
  const baseRegistrar = (await contracts?.getBaseRegistrar()).connect(signer);
7
7
  const labelhash = ethers.utils.solidityKeccak256(['string'], [labels[0]]);
8
- const data = ethers.utils.defaultAbiCoder.encode(['string', 'address', 'uint96', 'address'], [labels[0], wrappedOwner, decodedFuses, resolverAddress]);
9
- return baseRegistrar['safeTransferFrom(address,address,uint256,bytes)'](address, nameWrapper.address, labelhash, data);
8
+ const data = ethers.utils.defaultAbiCoder.encode(['string', 'address', 'uint32', 'uint64', 'address'], [labels[0], wrappedOwner, '0x0', decodedFuses, resolverAddress]);
9
+ return baseRegistrar.populateTransaction['safeTransferFrom(address,address,uint256,bytes)'](address, nameWrapper.address, labelhash, data);
10
10
  }
11
- async function wrapOther({ contracts }, name, wrappedOwner, decodedFuses, resolverAddress, address) {
12
- const nameWrapper = await contracts?.getNameWrapper();
11
+ async function wrapOther({ contracts }, name, wrappedOwner, decodedFuses, resolverAddress, address, signer) {
12
+ const nameWrapper = (await contracts?.getNameWrapper()).connect(signer);
13
13
  const registry = await contracts?.getRegistry();
14
14
  const hasApproval = await registry.isApprovedForAll(address, nameWrapper.address);
15
15
  if (!hasApproval) {
16
16
  throw new Error('NameWrapper must have approval to wrap a name from this address.');
17
17
  }
18
- return nameWrapper.wrap(hexEncodeName(name), wrappedOwner, decodedFuses, resolverAddress);
18
+ return nameWrapper.populateTransaction.wrap(hexEncodeName(name), wrappedOwner, decodedFuses, resolverAddress);
19
19
  }
20
- export default async function ({ contracts, provider }, name, wrappedOwner, fuseOptions, resolverAddress, options) {
21
- const signer = provider?.getSigner(options?.addressOrIndex);
22
- const address = await signer?.getAddress();
23
- if (!signer || !address) {
24
- throw new Error('No signer found');
25
- }
20
+ export default async function ({ contracts, signer, populate }, name, { wrappedOwner, fuseOptions, resolverAddress, }) {
21
+ const address = await signer.getAddress();
26
22
  let decodedFuses;
27
23
  switch (typeof fuseOptions) {
28
24
  case 'object': {
@@ -53,6 +49,6 @@ export default async function ({ contracts, provider }, name, wrappedOwner, fuse
53
49
  return wrapETH({ contracts }, labels, wrappedOwner, decodedFuses, resolverAddress, signer, address);
54
50
  }
55
51
  else {
56
- return wrapOther({ contracts }, name, wrappedOwner, decodedFuses, resolverAddress, address);
52
+ return wrapOther({ contracts }, name, wrappedOwner, decodedFuses, resolverAddress, address, signer);
57
53
  }
58
54
  }
@@ -1,7 +1,19 @@
1
- import { ethers } from 'ethers';
1
+ import { JsonRpcSigner } from '@ethersproject/providers';
2
+ import { ContractTransaction, ethers, PopulatedTransaction } from 'ethers';
2
3
  import ContractManager from './contracts';
3
4
  import { getContractAddress as _getContractAddress } from './contracts/getContractAddress';
4
5
  import { SupportedNetworkId } from './contracts/types';
6
+ import type burnFuses from './functions/burnFuses';
7
+ import type createSubname from './functions/createSubname';
8
+ import type deleteSubname from './functions/deleteSubname';
9
+ import type setName from './functions/setName';
10
+ import type setRecord from './functions/setRecord';
11
+ import type setRecords from './functions/setRecords';
12
+ import type setResolver from './functions/setResolver';
13
+ import type transferName from './functions/transferName';
14
+ import type transferSubname from './functions/transferSubname';
15
+ import type unwrapName from './functions/unwrapName';
16
+ import type wrapName from './functions/wrapName';
5
17
  import GqlManager from './GqlManager';
6
18
  declare type ENSOptions = {
7
19
  graphURI?: string | null;
@@ -10,6 +22,7 @@ declare type ENSOptions = {
10
22
  export declare type InternalENS = {
11
23
  options?: ENSOptions;
12
24
  provider?: ethers.providers.Provider;
25
+ signer: JsonRpcSigner;
13
26
  graphURI?: string | null;
14
27
  } & ENS;
15
28
  export declare type ENSArgs<K extends keyof InternalENS> = {
@@ -17,6 +30,15 @@ export declare type ENSArgs<K extends keyof InternalENS> = {
17
30
  };
18
31
  declare type OmitFirstArg<F> = F extends (x: any, ...args: infer P) => infer R ? (...args: P) => R : never;
19
32
  declare type OmitFirstTwoArgs<F> = F extends (x: any, y: any, ...args: infer P) => infer R ? (...args: P) => R : never;
33
+ declare type WriteOptions = {
34
+ addressOrIndex?: string | number;
35
+ signer?: JsonRpcSigner;
36
+ };
37
+ declare type OptionalWriteOptions<F> = F extends (x: any, arg_0: infer Z, options?: infer P) => infer R ? (name: Z, options?: P & WriteOptions) => R : F extends (x: any, arg_0: infer Z, options: infer P) => infer R ? (name: Z, options: P & WriteOptions) => R : never;
38
+ interface WriteFunction<F extends (...args: any) => any> extends Function {
39
+ (...args: Parameters<OptionalWriteOptions<F>>): Promise<ContractTransaction>;
40
+ populateTransaction: (...args: Parameters<OptionalWriteOptions<F>>) => Promise<PopulatedTransaction>;
41
+ }
20
42
  export declare type RawFunction = {
21
43
  raw: (...args: any[]) => Promise<{
22
44
  to: string;
@@ -77,6 +99,14 @@ export declare class ENS {
77
99
  * @returns {OmitFirstArg} - The generated wrapped function
78
100
  */
79
101
  private generateFunction;
102
+ /**
103
+ * Generates a write wrapped function
104
+ * @param {string} path - The path of the exported function
105
+ * @param {FunctionDeps} dependencies - An array of ENS properties
106
+ * @param {string} exportName - The export name of the target function
107
+ * @returns {OmitFirstArg} - The generated wrapped function
108
+ */
109
+ private generateWriteFunction;
80
110
  /**
81
111
  * Generates a wrapped function from raw and decode exports
82
112
  * @param {string} path - The path of the exported function
@@ -104,11 +134,13 @@ export declare class ENS {
104
134
  }>;
105
135
  decode: ({ multicallWrapper }: ENSArgs<"multicallWrapper">, data: string, ...items: BatchFunctionResult<RawFunction>[]) => Promise<any[] | undefined>;
106
136
  }>;
107
- getProfile: (nameOrAddress: string, options?: {
137
+ getProfile: (nameOrAddress: string, options?: ({
108
138
  contentHash?: boolean | undefined;
109
139
  texts?: boolean | string[] | undefined;
110
140
  coinTypes?: boolean | string[] | undefined;
111
- } | undefined) => Promise<{
141
+ } & {
142
+ resolverAddress?: string | undefined;
143
+ }) | undefined) => Promise<{
112
144
  isMigrated: boolean | null;
113
145
  createdAt: string | null;
114
146
  address?: string | undefined;
@@ -137,6 +169,7 @@ export declare class ENS {
137
169
  contentHash?: boolean | undefined;
138
170
  texts?: boolean | string[] | undefined;
139
171
  coinTypes?: boolean | string[] | undefined;
172
+ resolverAddress?: string | undefined;
140
173
  } | undefined) => Promise<{
141
174
  isMigrated: boolean | null;
142
175
  createdAt: string | null;
@@ -423,48 +456,17 @@ export declare class ENS {
423
456
  }>;
424
457
  decode: ({ contracts }: ENSArgs<"contracts">, data: string) => Promise<any>;
425
458
  }>;
426
- setName: (name: string, address?: string | undefined, resolver?: string | undefined, options?: {
427
- addressOrIndex?: string | number | undefined;
428
- } | undefined) => Promise<ethers.ContractTransaction | undefined>;
429
- setRecords: (name: string, records: import("./utils/recordHelpers").RecordOptions) => Promise<ethers.ContractTransaction | undefined>;
430
- setResolver: (name: string, contract: "nameWrapper" | "registry", resolver?: string | undefined, options?: {
431
- addressOrIndex?: string | number | undefined;
432
- } | undefined) => Promise<ethers.ContractTransaction>;
433
- transferName: (name: string, newOwner: string, contract: "nameWrapper" | "registry" | "baseRegistrar", options?: {
434
- addressOrIndex?: string | number | undefined;
435
- } | undefined) => Promise<ethers.ContractTransaction>;
436
- wrapName: (name: string, wrappedOwner: string, fuseOptions?: string | number | import("./@types/FuseOptions").FuseOptions | undefined, resolverAddress?: string | undefined, options?: {
437
- addressOrIndex?: string | number | undefined;
438
- } | undefined) => Promise<ethers.ContractTransaction>;
439
- unwrapName: (name: string, newController: string, newRegistrant?: string | undefined, options?: {
440
- addressOrIndex?: string | number | undefined;
441
- } | undefined) => Promise<ethers.ContractTransaction>;
442
- burnFuses: (name: string, fusesToBurn: import("./@types/FuseOptions").FuseOptions) => Promise<ethers.ContractTransaction>;
443
- createSubname: (args_0: {
444
- name: string;
445
- owner: string;
446
- resolverAddress?: string | undefined;
447
- contract: "nameWrapper" | "registry";
448
- options?: {
449
- addressOrIndex?: string | number | undefined;
450
- } | undefined;
451
- } | ({
452
- contract: "nameWrapper";
453
- fuses?: import("./@types/FuseOptions").FuseOptions | undefined;
454
- } & {
455
- name: string;
456
- owner: string;
457
- resolverAddress?: string | undefined;
458
- contract: "nameWrapper" | "registry";
459
- options?: {
460
- addressOrIndex?: string | number | undefined;
461
- } | undefined;
462
- })) => Promise<ethers.ContractTransaction>;
463
- deleteSubname: (name: string, contract: "nameWrapper" | "registry", options?: {
464
- addressOrIndex?: string | number | undefined;
465
- } | undefined) => Promise<ethers.ContractTransaction>;
466
- transferSubname: (name: string, contract: "nameWrapper" | "registry", address: string, options?: {
467
- addressOrIndex?: string | number | undefined;
468
- } | undefined) => Promise<ethers.ContractTransaction>;
459
+ setName: WriteFunction<typeof setName>;
460
+ setRecords: WriteFunction<typeof setRecords>;
461
+ setRecord: WriteFunction<typeof setRecord>;
462
+ setResolver: WriteFunction<typeof setResolver>;
463
+ transferName: WriteFunction<typeof transferName>;
464
+ wrapName: WriteFunction<typeof wrapName>;
465
+ unwrapName: WriteFunction<typeof unwrapName>;
466
+ burnFuses: WriteFunction<typeof burnFuses>;
467
+ createSubname: WriteFunction<typeof createSubname>;
468
+ deleteSubname: WriteFunction<typeof deleteSubname>;
469
+ transferSubname: WriteFunction<typeof transferSubname>;
470
+ getDNSOwner: (dnsName: string) => Promise<any>;
469
471
  }
470
472
  export {};
package/dist/esm/index.js CHANGED
@@ -2,6 +2,7 @@ import ContractManager from './contracts';
2
2
  import { getContractAddress as _getContractAddress } from './contracts/getContractAddress';
3
3
  import GqlManager from './GqlManager';
4
4
  import singleCall from './utils/singleCall';
5
+ import writeTx from './utils/writeTx';
5
6
  const graphURIEndpoints = {
6
7
  1: 'https://api.thegraph.com/subgraphs/name/ensdomains/ens',
7
8
  3: 'https://api.thegraph.com/subgraphs/name/ensdomains/ensropsten',
@@ -52,15 +53,30 @@ export class ENS {
52
53
  await thisRef.checkInitialProvider();
53
54
  // import the module dynamically
54
55
  const mod = await import(
55
- /* webpackMode: "lazy", webpackChunkName: "[request]", webpackPreload: true */
56
+ /* webpackMode: "lazy", webpackChunkName: "[request]", webpackPreload: true, webpackExclude: /.*\.ts$/ */
56
57
  `./functions/${path}`);
57
58
  // if combine isn't specified, run normally
58
59
  // otherwise, create a function from the raw and decode functions
59
60
  if (subFunc !== 'combine') {
61
+ const writeable = subFunc === 'write' || subFunc === 'populateTransaction';
60
62
  // get the function to call
61
- const func = subFunc ? mod[exportName][subFunc] : mod[exportName];
63
+ const func = subFunc && !writeable ? mod[exportName][subFunc] : mod[exportName];
62
64
  // get the dependencies to forward to the function as the first arg
63
- const dependenciesToForward = thisRef.forwardDependenciesFromArray(dependencies);
65
+ let dependenciesToForward = thisRef.forwardDependenciesFromArray(dependencies);
66
+ // if func is write func, inject signer into dependencies
67
+ if (writeable) {
68
+ const options = (args[1] || {});
69
+ const signer = options.signer ||
70
+ thisRef.provider?.getSigner(options.addressOrIndex);
71
+ const populate = subFunc === 'populateTransaction';
72
+ if (!signer) {
73
+ throw new Error('No signer specified');
74
+ }
75
+ delete options.addressOrIndex;
76
+ delete options.signer;
77
+ dependenciesToForward = { ...dependenciesToForward, signer };
78
+ return func(dependenciesToForward, args[0], options).then(writeTx(signer, populate));
79
+ }
64
80
  // return the function with the dependencies forwarded
65
81
  return func(dependenciesToForward, ...args);
66
82
  }
@@ -77,6 +93,9 @@ export class ENS {
77
93
  mainFunc.decode = this.importGenerator(path, dependencies, exportName, 'decode');
78
94
  mainFunc.batch = this.importGenerator(path, dependencies, exportName, 'batch', { raw: mainFunc.raw, decode: mainFunc.decode });
79
95
  }
96
+ else if (subFunc === 'write') {
97
+ mainFunc.populateTransaction = this.importGenerator(path, dependencies, exportName, 'populateTransaction');
98
+ }
80
99
  return mainFunc;
81
100
  };
82
101
  /**
@@ -87,6 +106,14 @@ export class ENS {
87
106
  * @returns {OmitFirstArg} - The generated wrapped function
88
107
  */
89
108
  this.generateFunction = (path, dependencies, exportName = 'default') => this.importGenerator(path, dependencies, exportName);
109
+ /**
110
+ * Generates a write wrapped function
111
+ * @param {string} path - The path of the exported function
112
+ * @param {FunctionDeps} dependencies - An array of ENS properties
113
+ * @param {string} exportName - The export name of the target function
114
+ * @returns {OmitFirstArg} - The generated wrapped function
115
+ */
116
+ this.generateWriteFunction = (path, dependencies, exportName = 'default') => this.importGenerator(path, dependencies, exportName, 'write');
90
117
  /**
91
118
  * Generates a wrapped function from raw and decode exports
92
119
  * @param {string} path - The path of the exported function
@@ -129,6 +156,7 @@ export class ENS {
129
156
  'gqlInstance',
130
157
  'getName',
131
158
  'resolverMulticallWrapper',
159
+ 'multicallWrapper',
132
160
  '_getAddr',
133
161
  '_getContentHash',
134
162
  '_getText',
@@ -156,32 +184,28 @@ export class ENS {
156
184
  this.universalWrapper = this.generateRawFunction('initialGetters', ['contracts'], 'universalWrapper');
157
185
  this.resolverMulticallWrapper = this.generateRawFunction('initialGetters', ['contracts'], 'resolverMulticallWrapper');
158
186
  this.multicallWrapper = this.generateRawFunction('initialGetters', ['contracts'], 'multicallWrapper');
159
- this.setName = this.generateFunction('setName', [
187
+ this.setName = this.generateWriteFunction('setName', [
160
188
  'contracts',
161
- 'provider',
162
189
  ]);
163
- this.setRecords = this.generateFunction('setRecords', [
190
+ this.setRecords = this.generateWriteFunction('setRecords', ['contracts', 'provider', 'getResolver']);
191
+ this.setRecord = this.generateWriteFunction('setRecord', [
164
192
  'contracts',
165
193
  'provider',
166
194
  'getResolver',
167
195
  ]);
168
- this.setResolver = this.generateFunction('setResolver', ['contracts', 'provider']);
169
- this.transferName = this.generateFunction('transferName', ['contracts', 'provider']);
170
- this.wrapName = this.generateFunction('wrapName', [
196
+ this.setResolver = this.generateWriteFunction('setResolver', ['contracts']);
197
+ this.transferName = this.generateWriteFunction('transferName', ['contracts']);
198
+ this.wrapName = this.generateWriteFunction('wrapName', [
171
199
  'contracts',
172
- 'provider',
173
200
  ]);
174
- this.unwrapName = this.generateFunction('unwrapName', [
201
+ this.unwrapName = this.generateWriteFunction('unwrapName', ['contracts']);
202
+ this.burnFuses = this.generateWriteFunction('burnFuses', [
175
203
  'contracts',
176
- 'provider',
177
- ]);
178
- this.burnFuses = this.generateFunction('burnFuses', [
179
- 'contracts',
180
- 'provider',
181
204
  ]);
182
- this.createSubname = this.generateFunction('createSubname', ['contracts', 'provider']);
183
- this.deleteSubname = this.generateFunction('deleteSubname', ['contracts', 'provider', 'transferSubname']);
184
- this.transferSubname = this.generateFunction('transferSubname', ['contracts', 'provider']);
205
+ this.createSubname = this.generateWriteFunction('createSubname', ['contracts']);
206
+ this.deleteSubname = this.generateWriteFunction('deleteSubname', ['transferSubname']);
207
+ this.transferSubname = this.generateWriteFunction('transferSubname', ['contracts']);
208
+ this.getDNSOwner = this.generateFunction('getDNSOwner', []);
185
209
  this.options = options;
186
210
  this.getContractAddress = options?.getContractAddress || _getContractAddress;
187
211
  }
@@ -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) {
@@ -9,7 +10,7 @@ export function decodeLabelhash(hash) {
9
10
  if (hash.length !== 66) {
10
11
  throw Error('Expected encoded labelhash to have a length of 66');
11
12
  }
12
- return `${hash.slice(1, -1)}`;
13
+ return `0x${hash.slice(1, -1)}`;
13
14
  }
14
15
  export function encodeLabelhash(hash) {
15
16
  if (!hash.startsWith('0x')) {
@@ -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 localStorage
28
+ return hasLocalStorage
28
29
  ? JSON.parse(localStorage.getItem('ensjs:labels')) || {}
29
30
  : {};
30
31
  }
31
32
  function _saveLabel(hash, label) {
32
- if (!localStorage)
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 (!localStorage)
85
+ if (!hasLocalStorage)
85
86
  return 'Empty (0 KB)';
86
87
  let allStrings = '';
87
88
  for (const key in window.localStorage) {
@@ -1,3 +1,3 @@
1
- import { ethers } from 'ethers';
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(ethers.utils.namehash(name).substring(2))).map((x) => x.index / 2 - 1);
3
+ export const makeNamehashIndexes = (data, name) => Array.from(data.matchAll(namehash(name).substring(2))).map((x) => x.index / 2 - 1);
@@ -1 +1,2 @@
1
1
  export declare const normalise: (name: string) => any;
2
+ export declare const namehash: (name: string) => string;
@@ -1,2 +1,27 @@
1
+ import { concat, hexlify, keccak256, toUtf8Bytes } from 'ethers/lib/utils';
1
2
  import uts46 from 'idna-uts46-hx/uts46bundle.js';
3
+ import { decodeLabelhash, isEncodedLabelhash } from './labels';
4
+ const zeros = new Uint8Array(32);
5
+ zeros.fill(0);
2
6
  export const normalise = (name) => name ? uts46.toUnicode(name, { useStd3ASCII: true }) : name;
7
+ export const namehash = (name) => {
8
+ let result = zeros;
9
+ if (name) {
10
+ const labels = name.split('.');
11
+ for (var i = labels.length - 1; i >= 0; i--) {
12
+ let labelSha;
13
+ if (isEncodedLabelhash(labels[i])) {
14
+ labelSha = decodeLabelhash(labels[i]);
15
+ }
16
+ else {
17
+ const normalised = normalise(labels[i]);
18
+ labelSha = keccak256(toUtf8Bytes(normalised));
19
+ }
20
+ result = keccak256(concat([result, labelSha]));
21
+ }
22
+ }
23
+ else {
24
+ result = hexlify(zeros);
25
+ }
26
+ return result;
27
+ };
@@ -9,5 +9,8 @@ export declare type RecordOptions = {
9
9
  coinTypes?: RecordItem[];
10
10
  };
11
11
  export declare const generateSetAddr: (namehash: string, coinType: string, address: string, resolver: PublicResolver) => string;
12
+ export declare type RecordTypes = 'contentHash' | 'text' | 'addr';
13
+ export declare type RecordInput<T extends RecordTypes> = T extends 'contentHash' ? string : RecordItem;
14
+ export declare function generateSingleRecordCall<T extends RecordTypes>(namehash: string, resolver: PublicResolver, type: T): (record: RecordInput<T>) => string;
12
15
  export declare const generateRecordCallArray: (namehash: string, records: RecordOptions, resolver: PublicResolver) => string[];
13
16
  export {};
@@ -12,28 +12,54 @@ export const generateSetAddr = (namehash, coinType, address, resolver) => {
12
12
  const encodedAddress = coinTypeInstance.decoder(address);
13
13
  return resolver?.interface.encodeFunctionData('setAddr(bytes32,uint256,bytes)', [namehash, inputCoinType, encodedAddress]);
14
14
  };
15
+ export function generateSingleRecordCall(namehash, resolver, type) {
16
+ if (type === 'contentHash') {
17
+ return (_r) => {
18
+ const record = _r;
19
+ let _contentHash = '';
20
+ if (record !== _contentHash) {
21
+ const encoded = encodeContenthash(record);
22
+ if (encoded.error)
23
+ throw new Error(encoded.error);
24
+ _contentHash = encoded.encoded;
25
+ }
26
+ return resolver.interface.encodeFunctionData('setContenthash', [
27
+ namehash,
28
+ _contentHash,
29
+ ]);
30
+ };
31
+ }
32
+ else {
33
+ return (_r) => {
34
+ const record = _r;
35
+ if (type === 'text') {
36
+ return resolver.interface.encodeFunctionData('setText', [
37
+ namehash,
38
+ record.key,
39
+ record.value,
40
+ ]);
41
+ }
42
+ else {
43
+ return generateSetAddr(namehash, record.key, record.value, resolver);
44
+ }
45
+ };
46
+ }
47
+ }
15
48
  export const generateRecordCallArray = (namehash, records, resolver) => {
16
49
  const calls = [];
17
50
  if (records.contentHash) {
18
- const contentHash = records.contentHash === '' ? '' : encodeContenthash(records.contentHash);
19
- const data = resolver?.interface.encodeFunctionData('setContenthash', [namehash, contentHash]);
51
+ const data = generateSingleRecordCall(namehash, resolver, 'contentHash')(records.contentHash);
20
52
  data && calls.push(data);
21
53
  }
22
54
  if (records.texts && records.texts.length > 0) {
23
- records.texts.forEach(({ key, value }) => {
24
- const data = resolver?.interface.encodeFunctionData('setText', [
25
- namehash,
26
- key,
27
- value,
28
- ]);
29
- data && calls.push(data);
30
- });
55
+ records.texts
56
+ .map(generateSingleRecordCall(namehash, resolver, 'text'))
57
+ .forEach((call) => calls.push(call));
31
58
  }
32
59
  if (records.coinTypes && records.coinTypes.length > 0) {
33
- records.coinTypes.forEach(({ key, value }) => {
34
- const data = generateSetAddr(namehash, key, value, resolver);
35
- data && calls.push(data);
36
- });
60
+ records.coinTypes
61
+ .map(generateSingleRecordCall(namehash, resolver, 'addr'))
62
+ .forEach((call) => calls.push(call));
37
63
  }
38
64
  return calls;
39
65
  };
@@ -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 namehash = utils.namehash(name);
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({
@@ -0,0 +1,4 @@
1
+ import { JsonRpcSigner } from '@ethersproject/providers';
2
+ import type { PopulatedTransaction } from 'ethers';
3
+ declare const _default: (signer: JsonRpcSigner, populate: boolean) => (tx: PopulatedTransaction) => PopulatedTransaction | Promise<import("@ethersproject/abstract-provider").TransactionResponse>;
4
+ export default _default;
@@ -0,0 +1 @@
1
+ export default (signer, populate) => (tx) => populate ? tx : signer.sendTransaction(tx);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ensdomains/ensjs",
3
- "version": "3.0.0-alpha.1",
3
+ "version": "3.0.0-alpha.10",
4
4
  "description": "ENS javascript library for contract interaction",
5
5
  "main": "./dist/cjs/index.js",
6
6
  "types": "./dist/cjs/index.d.ts",
@@ -27,13 +27,16 @@
27
27
  "generate-types": "ts-node scripts/runTypechain.ts",
28
28
  "generate-abis": "hardhat export-abi",
29
29
  "start": "ts-node --files src/index.test.ts",
30
- "test": "jest --run-in-band src/tests",
30
+ "test": "jest --run-in-band",
31
+ "test:watch": "jest --watch --run-in-band",
31
32
  "test:specific": "ts-node --files ",
32
33
  "clean": "rm -rf ./dist ./README.md ./LICENSE",
33
34
  "build:esm": "tsc --project tsconfig.esm.json",
34
35
  "build:cjs": "tsc --project tsconfig.cjs.json",
35
36
  "build": "yarn clean && yarn build:esm && yarn build:cjs",
36
- "prepublish": "yarn build && cp ../../{README.md,LICENSE} ./"
37
+ "prepublish": "yarn build && cp ../../{README.md,LICENSE} ./",
38
+ "remove-stableVersion": "ex -c '%s/,\\n\\s\\+\"stableVersion\".*\"//g' -cwq ./package.json",
39
+ "version:create": "yarn remove-stableVersion && yarn version"
37
40
  },
38
41
  "packageManager": "yarn@3.2.0",
39
42
  "dependencies": {
@@ -43,12 +46,13 @@
43
46
  "dns-packet": "^5.3.1",
44
47
  "ethers": "^5.6.1",
45
48
  "graphql": "^16.3.0",
46
- "graphql-request": "^4.1.0",
47
- "idna-uts46-hx": "3.4.0"
49
+ "graphql-request": "next",
50
+ "idna-uts46-hx": "3.4.0",
51
+ "traverse": "^0.6.6"
48
52
  },
49
53
  "devDependencies": {
50
54
  "@ensdomains/buffer": "^0.0.13",
51
- "@ensdomains/ens-test-env": "0.2.0",
55
+ "@ensdomains/ens-test-env": "0.1.5",
52
56
  "@ethersproject/abi": "^5.6.0",
53
57
  "@ethersproject/providers": "^5.6.2",
54
58
  "@nomiclabs/hardhat-ethers": "^2.0.5",
@@ -58,6 +62,7 @@
58
62
  "@typechain/ethers-v5": "^10.0.0",
59
63
  "@types/bn.js": "^5.1.0",
60
64
  "@types/jest": "^27.4.1",
65
+ "@types/traverse": "^0.6.32",
61
66
  "dotenv": "^16.0.0",
62
67
  "ens-contracts": "github:ensdomains/ens-contracts#head=master&commit=3ecc56b14beb4aae8296f8a94f7c0d095e62fd93",
63
68
  "hardhat": "^2.9.3",
@@ -66,6 +71,8 @@
66
71
  "jest": "^27.5.1",
67
72
  "jest-environment-node": "^27.5.1",
68
73
  "jest-localstorage-mock": "^2.4.21",
74
+ "nock": "^13.2.8",
75
+ "node-fetch": "^3.2.6",
69
76
  "solc": "^0.8.13",
70
77
  "ts-jest": "^27.1.4",
71
78
  "ts-node": "^10.7.0",
@@ -75,5 +82,6 @@
75
82
  },
76
83
  "peerDependencies": {
77
84
  "ethers": "*"
78
- }
85
+ },
86
+ "stableVersion": "3.0.0-alpha.9"
79
87
  }