@ensdomains/ensjs 3.0.0-alpha.3 → 3.0.0-alpha.6

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 (81) hide show
  1. package/dist/cjs/functions/burnFuses.d.ts +3 -1
  2. package/dist/cjs/functions/burnFuses.js +2 -6
  3. package/dist/cjs/functions/createSubname.d.ts +1 -5
  4. package/dist/cjs/functions/createSubname.js +3 -7
  5. package/dist/cjs/functions/deleteSubname.d.ts +3 -3
  6. package/dist/cjs/functions/deleteSubname.js +5 -2
  7. package/dist/cjs/functions/getDNSOwner.d.ts +1 -1
  8. package/dist/cjs/functions/getDNSOwner.js +1 -1
  9. package/dist/cjs/functions/setName.d.ts +4 -3
  10. package/dist/cjs/functions/setName.js +5 -10
  11. package/dist/cjs/functions/setRecords.d.ts +4 -1
  12. package/dist/cjs/functions/setRecords.js +11 -9
  13. package/dist/cjs/functions/setResolver.d.ts +4 -3
  14. package/dist/cjs/functions/setResolver.js +5 -11
  15. package/dist/cjs/functions/transferName.d.ts +4 -3
  16. package/dist/cjs/functions/transferName.js +8 -13
  17. package/dist/cjs/functions/transferSubname.d.ts +4 -3
  18. package/dist/cjs/functions/transferSubname.js +3 -7
  19. package/dist/cjs/functions/unwrapName.d.ts +4 -3
  20. package/dist/cjs/functions/unwrapName.js +3 -8
  21. package/dist/cjs/functions/wrapName.d.ts +5 -3
  22. package/dist/cjs/functions/wrapName.js +8 -12
  23. package/dist/cjs/index.d.ts +41 -45
  24. package/dist/cjs/index.js +39 -25
  25. package/dist/cjs/utils/writeTx.d.ts +4 -0
  26. package/dist/cjs/utils/writeTx.js +3 -0
  27. package/dist/esm/functions/burnFuses.d.ts +3 -1
  28. package/dist/esm/functions/burnFuses.js +2 -6
  29. package/dist/esm/functions/createSubname.d.ts +1 -5
  30. package/dist/esm/functions/createSubname.js +3 -7
  31. package/dist/esm/functions/deleteSubname.d.ts +3 -3
  32. package/dist/esm/functions/deleteSubname.js +5 -2
  33. package/dist/esm/functions/getDNSOwner.d.ts +1 -1
  34. package/dist/esm/functions/getDNSOwner.js +1 -1
  35. package/dist/esm/functions/setName.d.ts +4 -3
  36. package/dist/esm/functions/setName.js +5 -10
  37. package/dist/esm/functions/setRecords.d.ts +4 -1
  38. package/dist/esm/functions/setRecords.js +11 -9
  39. package/dist/esm/functions/setResolver.d.ts +4 -3
  40. package/dist/esm/functions/setResolver.js +5 -11
  41. package/dist/esm/functions/transferName.d.ts +4 -3
  42. package/dist/esm/functions/transferName.js +8 -13
  43. package/dist/esm/functions/transferSubname.d.ts +4 -3
  44. package/dist/esm/functions/transferSubname.js +3 -7
  45. package/dist/esm/functions/unwrapName.d.ts +4 -3
  46. package/dist/esm/functions/unwrapName.js +3 -8
  47. package/dist/esm/functions/wrapName.d.ts +5 -3
  48. package/dist/esm/functions/wrapName.js +8 -12
  49. package/dist/esm/index.d.ts +41 -45
  50. package/dist/esm/index.js +39 -25
  51. package/dist/esm/utils/writeTx.d.ts +4 -0
  52. package/dist/esm/utils/writeTx.js +1 -0
  53. package/package.json +3 -3
  54. package/src/functions/burnFuses.test.ts +9 -8
  55. package/src/functions/burnFuses.ts +7 -9
  56. package/src/functions/createSubname.test.ts +8 -11
  57. package/src/functions/createSubname.ts +5 -12
  58. package/src/functions/deleteSubname.test.ts +28 -27
  59. package/src/functions/deleteSubname.ts +9 -12
  60. package/src/functions/getDNSOwner.test.ts +2 -2
  61. package/src/functions/getDNSOwner.ts +1 -1
  62. package/src/functions/getFuses.test.ts +11 -9
  63. package/src/functions/getOwner.test.ts +3 -1
  64. package/src/functions/setName.test.ts +3 -2
  65. package/src/functions/setName.ts +15 -17
  66. package/src/functions/setRecords.test.ts +7 -5
  67. package/src/functions/setRecords.ts +19 -13
  68. package/src/functions/setResolver.test.ts +12 -15
  69. package/src/functions/setResolver.ts +14 -19
  70. package/src/functions/transferName.test.ts +27 -29
  71. package/src/functions/transferName.ts +17 -21
  72. package/src/functions/transferSubname.test.ts +30 -29
  73. package/src/functions/transferSubname.ts +19 -12
  74. package/src/functions/unwrapName.test.ts +22 -22
  75. package/src/functions/unwrapName.ts +18 -14
  76. package/src/functions/wrapName.test.ts +15 -12
  77. package/src/functions/wrapName.ts +20 -22
  78. package/src/index.ts +105 -33
  79. package/src/tests/populateTransaction.test.ts +40 -0
  80. package/src/tests/signerInjection.test.ts +46 -0
  81. package/src/utils/writeTx.ts +6 -0
@@ -1,8 +1,8 @@
1
1
  import { BigNumber, ethers } from 'ethers'
2
2
  import { ENS } from '..'
3
+ import setup from '../tests/setup'
3
4
  import { hexEncodeName } from '../utils/hexEncodedName'
4
5
  import { namehash } from '../utils/normalise'
5
- import setup from '../tests/setup'
6
6
 
7
7
  let ENSInstance: ENS
8
8
  let revert: Awaited<ReturnType<typeof setup>>['revert']
@@ -24,7 +24,9 @@ describe('wrapName', () => {
24
24
  await revert()
25
25
  })
26
26
  it('should return a wrap name transaction and succeed', async () => {
27
- const tx = await ENSInstance.wrapName('parthtejpal.eth', accounts[0])
27
+ const tx = await ENSInstance.wrapName('parthtejpal.eth', {
28
+ wrappedOwner: accounts[0],
29
+ })
28
30
  expect(tx).toBeTruthy()
29
31
  await tx.wait()
30
32
 
@@ -33,24 +35,25 @@ describe('wrapName', () => {
33
35
  expect((result as BigNumber).toHexString()).toBe('0x40')
34
36
  })
35
37
  it('should allow initial fuses', async () => {
36
- const tx = await ENSInstance.wrapName('parthtejpal.eth', accounts[0], {
37
- cannotUnwrap: true,
38
- cannotSetTtl: true,
38
+ const tx = await ENSInstance.wrapName('parthtejpal.eth', {
39
+ wrappedOwner: accounts[0],
40
+ fuseOptions: {
41
+ cannotUnwrap: true,
42
+ cannotSetTtl: true,
43
+ },
39
44
  })
40
45
  expect(tx).toBeTruthy()
41
46
  await tx.wait()
42
47
 
43
48
  const nameWrapper = await ENSInstance.contracts!.getNameWrapper()!
44
49
  const [result] = await nameWrapper.getFuses(namehash('parthtejpal.eth'))
45
- expect((result as BigNumber).toHexString()).toBe('0x51')
50
+ expect((result as BigNumber).toHexString()).toBe('0x40')
46
51
  })
47
52
  it('should allow an initial resolver address', async () => {
48
- const tx = await ENSInstance.wrapName(
49
- 'parthtejpal.eth',
50
- accounts[0],
51
- undefined,
52
- '0x42D63ae25990889E35F215bC95884039Ba354115',
53
- )
53
+ const tx = await ENSInstance.wrapName('parthtejpal.eth', {
54
+ wrappedOwner: accounts[0],
55
+ resolverAddress: '0x42D63ae25990889E35F215bC95884039Ba354115',
56
+ })
54
57
  expect(tx).toBeTruthy()
55
58
  await tx.wait()
56
59
 
@@ -19,16 +19,13 @@ async function wrapETH(
19
19
  const labelhash = ethers.utils.solidityKeccak256(['string'], [labels[0]])
20
20
 
21
21
  const data = ethers.utils.defaultAbiCoder.encode(
22
- ['string', 'address', 'uint96', 'address'],
23
- [labels[0], wrappedOwner, decodedFuses, resolverAddress],
22
+ ['string', 'address', 'uint32', 'uint64', 'address'],
23
+ [labels[0], wrappedOwner, '0x0', decodedFuses, resolverAddress],
24
24
  )
25
25
 
26
- return baseRegistrar['safeTransferFrom(address,address,uint256,bytes)'](
27
- address,
28
- nameWrapper.address,
29
- labelhash,
30
- data,
31
- )
26
+ return baseRegistrar.populateTransaction[
27
+ 'safeTransferFrom(address,address,uint256,bytes)'
28
+ ](address, nameWrapper.address, labelhash, data)
32
29
  }
33
30
 
34
31
  async function wrapOther(
@@ -38,8 +35,9 @@ async function wrapOther(
38
35
  decodedFuses: string,
39
36
  resolverAddress: string,
40
37
  address: string,
38
+ signer: ethers.Signer,
41
39
  ) {
42
- const nameWrapper = await contracts?.getNameWrapper()!
40
+ const nameWrapper = (await contracts?.getNameWrapper()!).connect(signer)
43
41
  const registry = await contracts?.getRegistry()!
44
42
 
45
43
  const hasApproval = await registry.isApprovedForAll(
@@ -53,7 +51,7 @@ async function wrapOther(
53
51
  )
54
52
  }
55
53
 
56
- return nameWrapper.wrap(
54
+ return nameWrapper.populateTransaction.wrap(
57
55
  hexEncodeName(name),
58
56
  wrappedOwner,
59
57
  decodedFuses,
@@ -62,20 +60,19 @@ async function wrapOther(
62
60
  }
63
61
 
64
62
  export default async function (
65
- { contracts, provider }: ENSArgs<'contracts' | 'provider'>,
63
+ { contracts, signer, populate }: ENSArgs<'contracts' | 'signer' | 'populate'>,
66
64
  name: string,
67
- wrappedOwner: string,
68
- fuseOptions?: FuseOptions | string | number,
69
- resolverAddress?: string,
70
- options?: { addressOrIndex?: string | number },
65
+ {
66
+ wrappedOwner,
67
+ fuseOptions,
68
+ resolverAddress,
69
+ }: {
70
+ wrappedOwner: string
71
+ fuseOptions?: FuseOptions | string | number
72
+ resolverAddress?: string
73
+ },
71
74
  ) {
72
- const signer = provider?.getSigner(options?.addressOrIndex)
73
-
74
- const address = await signer?.getAddress()
75
-
76
- if (!signer || !address) {
77
- throw new Error('No signer found')
78
- }
75
+ const address = await signer.getAddress()
79
76
 
80
77
  let decodedFuses: string
81
78
 
@@ -123,6 +120,7 @@ export default async function (
123
120
  decodedFuses,
124
121
  resolverAddress,
125
122
  address,
123
+ signer,
126
124
  )
127
125
  }
128
126
  }
package/src/index.ts CHANGED
@@ -1,4 +1,5 @@
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'
@@ -11,6 +12,7 @@ import type {
11
12
  import type burnFuses from './functions/burnFuses'
12
13
  import type createSubname from './functions/createSubname'
13
14
  import type deleteSubname from './functions/deleteSubname'
15
+ import type getDNSOwner from './functions/getDNSOwner'
14
16
  import type getExpiry from './functions/getExpiry'
15
17
  import type getFuses from './functions/getFuses'
16
18
  import type {
@@ -41,9 +43,9 @@ import type transferName from './functions/transferName'
41
43
  import type transferSubname from './functions/transferSubname'
42
44
  import type unwrapName from './functions/unwrapName'
43
45
  import type wrapName from './functions/wrapName'
44
- import type getDNSOwner from './functions/getDNSOwner'
45
46
  import GqlManager from './GqlManager'
46
47
  import singleCall from './utils/singleCall'
48
+ import writeTx from './utils/writeTx'
47
49
 
48
50
  type ENSOptions = {
49
51
  graphURI?: string | null
@@ -53,6 +55,7 @@ type ENSOptions = {
53
55
  export type InternalENS = {
54
56
  options?: ENSOptions
55
57
  provider?: ethers.providers.Provider
58
+ signer: JsonRpcSigner
56
59
  graphURI?: string | null
57
60
  } & ENS
58
61
 
@@ -76,6 +79,28 @@ type FirstArg<F> = F extends (x: infer A, ...args: any[]) => any ? A : never
76
79
 
77
80
  type FunctionDeps<F> = Extract<keyof FirstArg<F>, string>[]
78
81
 
82
+ type WriteOptions = {
83
+ addressOrIndex?: string | number
84
+ signer?: JsonRpcSigner
85
+ }
86
+
87
+ type OptionalWriteOptions<F> = F extends (
88
+ x: any,
89
+ arg_0: infer Z,
90
+ options?: infer P,
91
+ ) => infer R
92
+ ? (name: Z, options?: P & WriteOptions) => R
93
+ : F extends (x: any, arg_0: infer Z, options: infer P) => infer R
94
+ ? (name: Z, options: P & WriteOptions) => R
95
+ : never
96
+
97
+ interface WriteFunction<F extends (...args: any) => any> extends Function {
98
+ (...args: Parameters<OptionalWriteOptions<F>>): Promise<ContractTransaction>
99
+ populateTransaction: (
100
+ ...args: Parameters<OptionalWriteOptions<F>>
101
+ ) => Promise<PopulatedTransaction>
102
+ }
103
+
79
104
  const graphURIEndpoints: Record<string, string> = {
80
105
  1: 'https://api.thegraph.com/subgraphs/name/ensdomains/ens',
81
106
  3: 'https://api.thegraph.com/subgraphs/name/ensdomains/ensropsten',
@@ -172,7 +197,13 @@ export class ENS {
172
197
  path: string,
173
198
  dependencies: FunctionDeps<F>,
174
199
  exportName: string = 'default',
175
- subFunc?: 'raw' | 'decode' | 'combine' | 'batch',
200
+ subFunc?:
201
+ | 'raw'
202
+ | 'decode'
203
+ | 'combine'
204
+ | 'batch'
205
+ | 'write'
206
+ | 'populateTransaction',
176
207
  passthrough?: RawFunction,
177
208
  ): Function => {
178
209
  // if batch is specified, create batch func
@@ -193,14 +224,33 @@ export class ENS {
193
224
  // if combine isn't specified, run normally
194
225
  // otherwise, create a function from the raw and decode functions
195
226
  if (subFunc !== 'combine') {
227
+ const writeable =
228
+ subFunc === 'write' || subFunc === 'populateTransaction'
196
229
  // get the function to call
197
- const func = subFunc ? mod[exportName][subFunc] : mod[exportName]
198
- if(dependencies.length === 0) {
199
- return func(...args)
200
- }
230
+ const func =
231
+ subFunc && !writeable ? mod[exportName][subFunc] : mod[exportName]
201
232
  // get the dependencies to forward to the function as the first arg
202
- const dependenciesToForward =
233
+ let dependenciesToForward =
203
234
  thisRef.forwardDependenciesFromArray<F>(dependencies)
235
+
236
+ // if func is write func, inject signer into dependencies
237
+ if (writeable) {
238
+ const options = (args[1] || {}) as WriteOptions
239
+ const signer =
240
+ options.signer ||
241
+ thisRef.provider?.getSigner(options.addressOrIndex)
242
+ const populate = subFunc === 'populateTransaction'
243
+ if (!signer) {
244
+ throw new Error('No signer specified')
245
+ }
246
+ delete options.addressOrIndex
247
+ delete options.signer
248
+ dependenciesToForward = { ...dependenciesToForward, signer }
249
+ return func(dependenciesToForward, args[0], options).then(
250
+ writeTx(signer, populate),
251
+ )
252
+ }
253
+
204
254
  // return the function with the dependencies forwarded
205
255
  return func(dependenciesToForward, ...args)
206
256
  } else {
@@ -240,6 +290,13 @@ export class ENS {
240
290
  'batch',
241
291
  { raw: mainFunc.raw as any, decode: mainFunc.decode as any },
242
292
  )
293
+ } else if (subFunc === 'write') {
294
+ mainFunc.populateTransaction = this.importGenerator<F>(
295
+ path,
296
+ dependencies,
297
+ exportName,
298
+ 'populateTransaction',
299
+ )
243
300
  }
244
301
 
245
302
  return mainFunc as Function
@@ -259,6 +316,25 @@ export class ENS {
259
316
  ): OmitFirstArg<F> =>
260
317
  this.importGenerator<F>(path, dependencies, exportName) as OmitFirstArg<F>
261
318
 
319
+ /**
320
+ * Generates a write wrapped function
321
+ * @param {string} path - The path of the exported function
322
+ * @param {FunctionDeps} dependencies - An array of ENS properties
323
+ * @param {string} exportName - The export name of the target function
324
+ * @returns {OmitFirstArg} - The generated wrapped function
325
+ */
326
+ private generateWriteFunction = <F extends (...args: any) => any>(
327
+ path: string,
328
+ dependencies: FunctionDeps<F>,
329
+ exportName: string = 'default',
330
+ ): WriteFunction<F> =>
331
+ this.importGenerator<F>(
332
+ path,
333
+ dependencies,
334
+ exportName,
335
+ 'write',
336
+ ) as WriteFunction<F>
337
+
262
338
  /**
263
339
  * Generates a wrapped function from raw and decode exports
264
340
  * @param {string} path - The path of the exported function
@@ -458,55 +534,51 @@ export class ENS {
458
534
  'multicallWrapper',
459
535
  )
460
536
 
461
- public setName = this.generateFunction<typeof setName>('setName', [
537
+ public setName = this.generateWriteFunction<typeof setName>('setName', [
462
538
  'contracts',
463
- 'provider',
464
539
  ])
465
540
 
466
- public setRecords = this.generateFunction<typeof setRecords>('setRecords', [
467
- 'contracts',
468
- 'provider',
469
- 'getResolver',
470
- ])
541
+ public setRecords = this.generateWriteFunction<typeof setRecords>(
542
+ 'setRecords',
543
+ ['contracts', 'provider', 'getResolver'],
544
+ )
471
545
 
472
- public setResolver = this.generateFunction<typeof setResolver>(
546
+ public setResolver = this.generateWriteFunction<typeof setResolver>(
473
547
  'setResolver',
474
- ['contracts', 'provider'],
548
+ ['contracts'],
475
549
  )
476
550
 
477
- public transferName = this.generateFunction<typeof transferName>(
551
+ public transferName = this.generateWriteFunction<typeof transferName>(
478
552
  'transferName',
479
- ['contracts', 'provider'],
553
+ ['contracts'],
480
554
  )
481
555
 
482
- public wrapName = this.generateFunction<typeof wrapName>('wrapName', [
556
+ public wrapName = this.generateWriteFunction<typeof wrapName>('wrapName', [
483
557
  'contracts',
484
- 'provider',
485
558
  ])
486
559
 
487
- public unwrapName = this.generateFunction<typeof unwrapName>('unwrapName', [
488
- 'contracts',
489
- 'provider',
490
- ])
560
+ public unwrapName = this.generateWriteFunction<typeof unwrapName>(
561
+ 'unwrapName',
562
+ ['contracts'],
563
+ )
491
564
 
492
- public burnFuses = this.generateFunction<typeof burnFuses>('burnFuses', [
565
+ public burnFuses = this.generateWriteFunction<typeof burnFuses>('burnFuses', [
493
566
  'contracts',
494
- 'provider',
495
567
  ])
496
568
 
497
- public createSubname = this.generateFunction<typeof createSubname>(
569
+ public createSubname = this.generateWriteFunction<typeof createSubname>(
498
570
  'createSubname',
499
- ['contracts', 'provider'],
571
+ ['contracts'],
500
572
  )
501
573
 
502
- public deleteSubname = this.generateFunction<typeof deleteSubname>(
574
+ public deleteSubname = this.generateWriteFunction<typeof deleteSubname>(
503
575
  'deleteSubname',
504
- ['contracts', 'provider', 'transferSubname'],
576
+ ['transferSubname'],
505
577
  )
506
578
 
507
- public transferSubname = this.generateFunction<typeof transferSubname>(
579
+ public transferSubname = this.generateWriteFunction<typeof transferSubname>(
508
580
  'transferSubname',
509
- ['contracts', 'provider'],
581
+ ['contracts'],
510
582
  )
511
583
 
512
584
  public getDNSOwner = this.generateFunction<typeof getDNSOwner>(
@@ -0,0 +1,40 @@
1
+ import { ethers } from 'ethers'
2
+ import { ENS } from '..'
3
+ import setup from '../tests/setup'
4
+
5
+ let ENSInstance: ENS
6
+ let revert: Awaited<ReturnType<typeof setup>>['revert']
7
+ let provider: ethers.providers.JsonRpcProvider
8
+ let accounts: string[]
9
+
10
+ beforeAll(async () => {
11
+ ;({ ENSInstance, revert, provider } = await setup())
12
+ accounts = await provider.listAccounts()
13
+ })
14
+
15
+ afterAll(async () => {
16
+ await revert()
17
+ })
18
+
19
+ jest.setTimeout(20000)
20
+
21
+ describe('populateTransaction', () => {
22
+ beforeEach(async () => {
23
+ await revert()
24
+ })
25
+ it('should return a transaction successfully', async () => {
26
+ const tx = await ENSInstance.setName('fleek.eth')
27
+ expect(tx).toBeTruthy()
28
+ if (tx) {
29
+ await tx.wait()
30
+ expect(tx.hash).toBeTruthy()
31
+ }
32
+ })
33
+ it('should return a populated transaction successfully', async () => {
34
+ const tx = await ENSInstance.setName.populateTransaction('fleek.eth')
35
+ expect(tx).toBeTruthy()
36
+ if (tx) {
37
+ expect(tx).not.toHaveProperty('hash')
38
+ }
39
+ })
40
+ })
@@ -0,0 +1,46 @@
1
+ import { ContractTransaction, ethers } from 'ethers'
2
+ import { ENS } from '..'
3
+ import setup from '../tests/setup'
4
+
5
+ let ENSInstance: ENS
6
+ let revert: Awaited<ReturnType<typeof setup>>['revert']
7
+ let provider: ethers.providers.JsonRpcProvider
8
+ let accounts: string[]
9
+
10
+ beforeAll(async () => {
11
+ ;({ ENSInstance, revert, provider } = await setup())
12
+ accounts = await provider.listAccounts()
13
+ })
14
+
15
+ afterAll(async () => {
16
+ await revert()
17
+ })
18
+
19
+ jest.setTimeout(20000)
20
+
21
+ describe('Signer Injection', () => {
22
+ beforeEach(async () => {
23
+ await revert()
24
+ })
25
+ it('should return a transaction successfully for a custom signer', async () => {
26
+ const signer = provider.getSigner(accounts[3])
27
+ const tx = await ENSInstance.setName('fleek.eth', {
28
+ signer,
29
+ })
30
+ expect(tx).toBeTruthy()
31
+ if (tx) {
32
+ await tx.wait()
33
+ expect(tx.from).toBe(accounts[3])
34
+ }
35
+ })
36
+ it('should return a transaction succesfully for a custom signer index', async () => {
37
+ const tx = (await ENSInstance.setName('fleek.eth', {
38
+ addressOrIndex: 3,
39
+ })) as ContractTransaction
40
+ expect(tx).toBeTruthy()
41
+ if (tx) {
42
+ await tx.wait()
43
+ expect(tx.from).toBe(accounts[3])
44
+ }
45
+ })
46
+ })
@@ -0,0 +1,6 @@
1
+ import { JsonRpcSigner } from '@ethersproject/providers'
2
+ import type { PopulatedTransaction } from 'ethers'
3
+
4
+ export default (signer: JsonRpcSigner, populate: boolean) =>
5
+ (tx: PopulatedTransaction) =>
6
+ populate ? tx : signer.sendTransaction(tx)