@ensdomains/ensjs 3.0.0-alpha.11 → 3.0.0-alpha.14

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 (76) hide show
  1. package/dist/cjs/contracts/index.d.ts +8 -8
  2. package/dist/cjs/functions/burnFuses.d.ts +31 -4
  3. package/dist/cjs/functions/burnFuses.js +36 -6
  4. package/dist/cjs/functions/commitName.d.ts +26 -0
  5. package/dist/cjs/functions/commitName.js +24 -0
  6. package/dist/cjs/functions/getFuses.d.ts +2 -1
  7. package/dist/cjs/functions/getFuses.js +9 -18
  8. package/dist/cjs/functions/getHistory.d.ts +0 -30
  9. package/dist/cjs/functions/getHistory.js +3 -99
  10. package/dist/cjs/functions/getName.d.ts +2 -2
  11. package/dist/cjs/functions/getName.js +1 -1
  12. package/dist/cjs/functions/getProfile.js +1 -1
  13. package/dist/cjs/functions/getSpecificRecord.d.ts +4 -4
  14. package/dist/cjs/functions/registerName.d.ts +11 -0
  15. package/dist/cjs/functions/registerName.js +19 -0
  16. package/dist/cjs/functions/renewName.d.ts +6 -0
  17. package/dist/cjs/functions/renewName.js +10 -0
  18. package/dist/cjs/index.d.ts +24 -35
  19. package/dist/cjs/index.js +8 -3
  20. package/dist/cjs/utils/fuses.d.ts +18 -17
  21. package/dist/cjs/utils/fuses.js +10 -4
  22. package/dist/cjs/utils/registerHelpers.d.ts +44 -16
  23. package/dist/cjs/utils/registerHelpers.js +43 -15
  24. package/dist/cjs/utils/wrapperExpiry.d.ts +1 -1
  25. package/dist/cjs/utils/writeTx.d.ts +18 -1
  26. package/dist/cjs/utils/writeTx.js +4 -1
  27. package/dist/esm/contracts/index.d.ts +8 -8
  28. package/dist/esm/functions/burnFuses.d.ts +31 -4
  29. package/dist/esm/functions/burnFuses.js +36 -3
  30. package/dist/esm/functions/commitName.d.ts +26 -0
  31. package/dist/esm/functions/commitName.js +21 -0
  32. package/dist/esm/functions/getFuses.d.ts +2 -1
  33. package/dist/esm/functions/getFuses.js +10 -19
  34. package/dist/esm/functions/getHistory.d.ts +0 -30
  35. package/dist/esm/functions/getHistory.js +2 -96
  36. package/dist/esm/functions/getName.d.ts +2 -2
  37. package/dist/esm/functions/getName.js +1 -1
  38. package/dist/esm/functions/getProfile.js +1 -1
  39. package/dist/esm/functions/getSpecificRecord.d.ts +4 -4
  40. package/dist/esm/functions/registerName.d.ts +11 -0
  41. package/dist/esm/functions/registerName.js +16 -0
  42. package/dist/esm/functions/renewName.d.ts +6 -0
  43. package/dist/esm/functions/renewName.js +7 -0
  44. package/dist/esm/index.d.ts +24 -35
  45. package/dist/esm/index.js +8 -3
  46. package/dist/esm/utils/fuses.d.ts +18 -17
  47. package/dist/esm/utils/fuses.js +9 -3
  48. package/dist/esm/utils/registerHelpers.d.ts +44 -16
  49. package/dist/esm/utils/registerHelpers.js +40 -14
  50. package/dist/esm/utils/wrapperExpiry.d.ts +1 -1
  51. package/dist/esm/utils/writeTx.d.ts +18 -1
  52. package/dist/esm/utils/writeTx.js +4 -1
  53. package/package.json +19 -22
  54. package/src/functions/burnFuses.test.ts +123 -15
  55. package/src/functions/burnFuses.ts +101 -10
  56. package/src/functions/commitName.test.ts +61 -0
  57. package/src/functions/commitName.ts +36 -0
  58. package/src/functions/getFuses.test.ts +33 -15
  59. package/src/functions/getFuses.ts +13 -25
  60. package/src/functions/getHistory.test.ts +0 -84
  61. package/src/functions/getHistory.ts +2 -127
  62. package/src/functions/getName.test.ts +1 -1
  63. package/src/functions/getName.ts +1 -1
  64. package/src/functions/getProfile.ts +1 -1
  65. package/src/functions/registerName.test.ts +59 -0
  66. package/src/functions/registerName.ts +38 -0
  67. package/src/functions/renewName.test.ts +44 -0
  68. package/src/functions/renewName.ts +22 -0
  69. package/src/index.ts +28 -25
  70. package/src/utils/fuses.ts +12 -4
  71. package/src/utils/registerHelpers.ts +107 -49
  72. package/src/utils/writeTx.ts +12 -2
  73. package/src/tests/populateTransaction.test.ts +0 -40
  74. package/src/tests/setup.ts +0 -58
  75. package/src/tests/signerInjection.test.ts +0 -46
  76. package/src/tests/withProvider.test.ts +0 -28
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ensdomains/ensjs",
3
- "version": "3.0.0-alpha.11",
3
+ "version": "3.0.0-alpha.14",
4
4
  "description": "ENS javascript library for contract interaction",
5
5
  "main": "./dist/cjs/index.js",
6
6
  "types": "./dist/cjs/index.d.ts",
@@ -22,26 +22,8 @@
22
22
  "repository": "git@github.com:ensdomains/ensjs-v3.git",
23
23
  "author": "TateB <yo@taytems.xyz>",
24
24
  "license": "MIT",
25
- "scripts": {
26
- "env": "yarn ens-test-env",
27
- "generate-types": "ts-node scripts/runTypechain.ts",
28
- "generate-abis": "hardhat export-abi",
29
- "start": "ts-node --files src/index.test.ts",
30
- "test": "jest --run-in-band",
31
- "test:watch": "jest --watch --run-in-band",
32
- "test:specific": "ts-node --files ",
33
- "clean": "rm -rf ./dist ./README.md ./LICENSE",
34
- "build:esm": "tsc --project tsconfig.esm.json",
35
- "build:cjs": "tsc --project tsconfig.cjs.json",
36
- "build": "yarn clean && yarn build:esm && yarn build:cjs",
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",
40
- "enode": "ganache --wallet.mnemonic=\"test test test test test test test test test test test junk\" --chain.chainId 1337 --chain.networkId 1337 --chain.time 1659500634000"
41
- },
42
- "packageManager": "yarn@3.2.0",
43
25
  "dependencies": {
44
- "@ensdomains/address-encoder": "^0.2.16",
26
+ "@ensdomains/address-encoder": "0.2.16",
45
27
  "@ensdomains/content-hash": "^2.5.7",
46
28
  "dns-packet": "^5.3.1",
47
29
  "ethers": "^5.6.1",
@@ -53,7 +35,7 @@
53
35
  "devDependencies": {
54
36
  "@ensdomains/buffer": "^0.0.13",
55
37
  "@ensdomains/ens-contracts": "^0.0.12",
56
- "@ensdomains/ens-test-env": "0.1.5",
38
+ "@ensdomains/ens-test-env": "0.2.2",
57
39
  "@ethersproject/abi": "^5.6.0",
58
40
  "@ethersproject/providers": "^5.6.2",
59
41
  "@nomiclabs/hardhat-ethers": "npm:hardhat-deploy-ethers",
@@ -85,5 +67,20 @@
85
67
  "peerDependencies": {
86
68
  "ethers": "*"
87
69
  },
88
- "stableVersion": "3.0.0-alpha.10"
70
+ "scripts": {
71
+ "tenv": "ens-test-env -a",
72
+ "generate-types": "ts-node scripts/runTypechain.ts",
73
+ "generate-abis": "hardhat export-abi",
74
+ "start": "ts-node --files src/index.test.ts",
75
+ "test": "jest --run-in-band",
76
+ "test:watch": "jest --watch --run-in-band",
77
+ "test:specific": "ts-node --files ",
78
+ "clean": "rm -rf ./dist ./README.md ./LICENSE",
79
+ "build:esm": "tsc --project tsconfig.esm.json",
80
+ "build:cjs": "tsc --project tsconfig.cjs.json",
81
+ "build": "pnpm clean && pnpm build:esm && pnpm build:cjs",
82
+ "prepublish": "pnpm build && cp ../../README.md ../../LICENSE ./",
83
+ "enode": "ganache --wallet.mnemonic=\"test test test test test test test test test test test junk\" --chain.chainId 1337 --chain.networkId 1337 --chain.time 1659500634000",
84
+ "ver": "pnpm version --no-workspaces-update"
85
+ }
89
86
  }
@@ -21,20 +21,128 @@ describe('burnFuses', () => {
21
21
  beforeEach(async () => {
22
22
  await revert()
23
23
  })
24
- it('should return a burnFuses transaction and succeed', async () => {
25
- const tx = await ENSInstance.burnFuses('wrapped.eth', {
26
- fusesToBurn: {
27
- cannotUnwrap: true,
28
- cannotCreateSubdomain: true,
29
- cannotSetTtl: true,
30
- },
31
- addressOrIndex: accounts[1],
32
- })
33
- expect(tx).toBeTruthy()
34
- await tx.wait()
35
-
36
- const nameWrapper = await ENSInstance.contracts!.getNameWrapper()!
37
- const [fuses] = await nameWrapper.getFuses(namehash('wrapped.eth'))
38
- expect(fuses).toBe(113)
24
+ describe('Array', () => {
25
+ it('should return a burnFuses transaction from a named fuse array and succeed', async () => {
26
+ const tx = await ENSInstance.burnFuses('wrapped.eth', {
27
+ namedFusesToBurn: [
28
+ 'CANNOT_UNWRAP',
29
+ 'CANNOT_CREATE_SUBDOMAIN',
30
+ 'CANNOT_SET_TTL',
31
+ ],
32
+ addressOrIndex: accounts[1],
33
+ })
34
+ expect(tx).toBeTruthy()
35
+ await tx.wait()
36
+
37
+ const nameWrapper = await ENSInstance.contracts!.getNameWrapper()!
38
+ const [fuses] = await nameWrapper.getFuses(namehash('wrapped.eth'))
39
+ expect(fuses).toBe(113)
40
+ })
41
+ it('should return a burnFuses transaction from an unnamed fuse array and succeed', async () => {
42
+ const tx0 = await ENSInstance.burnFuses('wrapped.eth', {
43
+ namedFusesToBurn: ['CANNOT_UNWRAP'],
44
+ addressOrIndex: accounts[1],
45
+ })
46
+ expect(tx0).toBeTruthy()
47
+ await tx0.wait()
48
+
49
+ const tx = await ENSInstance.burnFuses('wrapped.eth', {
50
+ unnamedFusesToBurn: [128, 256, 512],
51
+ addressOrIndex: accounts[1],
52
+ })
53
+ expect(tx).toBeTruthy()
54
+ await tx.wait()
55
+
56
+ const nameWrapper = await ENSInstance.contracts!.getNameWrapper()!
57
+ const [fuses] = await nameWrapper.getFuses(namehash('wrapped.eth'))
58
+ expect(fuses).toBe(961)
59
+ })
60
+ it('should return a burnFuses transaction from both an unnamed and named fuse array and succeed', async () => {
61
+ const tx = await ENSInstance.burnFuses('wrapped.eth', {
62
+ namedFusesToBurn: [
63
+ 'CANNOT_UNWRAP',
64
+ 'CANNOT_CREATE_SUBDOMAIN',
65
+ 'CANNOT_SET_TTL',
66
+ ],
67
+ unnamedFusesToBurn: [128, 256, 512],
68
+ addressOrIndex: accounts[1],
69
+ })
70
+ expect(tx).toBeTruthy()
71
+ await tx.wait()
72
+
73
+ const nameWrapper = await ENSInstance.contracts!.getNameWrapper()!
74
+ const [fuses] = await nameWrapper.getFuses(namehash('wrapped.eth'))
75
+ expect(fuses).toBe(1009)
76
+ })
77
+ it('should throw an error when trying to burn a named fuse in an unnamed fuse array', async () => {
78
+ try {
79
+ await ENSInstance.burnFuses('wrapped.eth', {
80
+ unnamedFusesToBurn: [64] as any,
81
+ })
82
+ expect(false).toBeTruthy()
83
+ } catch (e: any) {
84
+ expect(e.message).toBe(
85
+ '64 is not a valid unnamed fuse. If you are trying to burn a named fuse, use the namedFusesToBurn property.',
86
+ )
87
+ }
88
+ })
89
+ it('should throw an error when trying to burn an unnamed fuse in a named fuse array', async () => {
90
+ try {
91
+ await ENSInstance.burnFuses('wrapped.eth', {
92
+ namedFusesToBurn: ['COOL_SWAG_FUSE'] as any,
93
+ })
94
+ expect(false).toBeTruthy()
95
+ } catch (e: any) {
96
+ expect(e.message).toBe('COOL_SWAG_FUSE is not a valid named fuse.')
97
+ }
98
+ })
99
+ })
100
+ describe('Number', () => {
101
+ it('should return a burnFuses transaction from a number and succeed', async () => {
102
+ const tx = await ENSInstance.burnFuses('wrapped.eth', {
103
+ fuseNumberToBurn: 49,
104
+ addressOrIndex: accounts[1],
105
+ })
106
+ expect(tx).toBeTruthy()
107
+ await tx.wait()
108
+
109
+ const nameWrapper = await ENSInstance.contracts!.getNameWrapper()!
110
+ const [fuses] = await nameWrapper.getFuses(namehash('wrapped.eth'))
111
+ expect(fuses).toBe(113)
112
+ })
113
+ it('should throw an error if the number is too high', async () => {
114
+ try {
115
+ await ENSInstance.burnFuses('wrapped.eth', {
116
+ fuseNumberToBurn: 4294967297,
117
+ })
118
+ expect(false).toBeTruthy()
119
+ } catch (e: any) {
120
+ expect(e.message).toBe(
121
+ 'Fuse number must be limited to uint32, 4294967297 was too high.',
122
+ )
123
+ }
124
+ })
125
+ it('should throw an error if the number is too low', async () => {
126
+ try {
127
+ await ENSInstance.burnFuses('wrapped.eth', {
128
+ fuseNumberToBurn: -1,
129
+ })
130
+ expect(false).toBeTruthy()
131
+ } catch (e: any) {
132
+ expect(e.message).toBe(
133
+ 'Fuse number must be limited to uint32, -1 was too low.',
134
+ )
135
+ }
136
+ })
137
+ it('should throw an error if the number is not an integer', async () => {
138
+ try {
139
+ await ENSInstance.burnFuses('wrapped.eth', {
140
+ fuseNumberToBurn: 7.5,
141
+ })
142
+ expect(false).toBeTruthy()
143
+ } catch (e: any) {
144
+ expect(e.message).toBe('Fuse number must be an integer, 7.5 was not.')
145
+ }
146
+ })
39
147
  })
40
148
  })
@@ -1,21 +1,112 @@
1
1
  import { ENSArgs } from '..'
2
- import { FuseOptions } from '../@types/FuseOptions'
3
- import generateFuseInput from '../utils/generateFuseInput'
2
+ import { fuseEnum, unnamedFuses } from '../utils/fuses'
4
3
  import { namehash } from '../utils/normalise'
5
4
 
6
- export default async function (
5
+ type FuseObj = typeof fuseEnum
6
+ type UnnamedFuseType = typeof unnamedFuses
7
+ type Fuse = keyof FuseObj
8
+ type NamedFuseValues = FuseObj[Fuse]
9
+ type UnnamedFuseValues = UnnamedFuseType[number]
10
+
11
+ // We need this type so that the following type isn't infinite. This type limits the max length of the fuse array to 7.
12
+ type FuseArrayPossibilities =
13
+ | [Fuse]
14
+ | [Fuse, Fuse]
15
+ | [Fuse, Fuse, Fuse]
16
+ | [Fuse, Fuse, Fuse, Fuse]
17
+ | [Fuse, Fuse, Fuse, Fuse, Fuse]
18
+ | [Fuse, Fuse, Fuse, Fuse, Fuse, Fuse]
19
+ | [Fuse, Fuse, Fuse, Fuse, Fuse, Fuse, Fuse]
20
+
21
+ /**
22
+ * This type creates a type error if there are any duplicate fuses.
23
+ * It effectively works like a reduce function, starting with 0 included types, adding a type each time, and then checking for duplicates.
24
+ *
25
+ * @template A The array to check for duplicates.
26
+ * @template B The union of all checked existing types.
27
+ */
28
+ // CLAUSE A: This extension unwraps the type as a fuse tuple.
29
+ type FusesWithoutDuplicates<A, B = never> = A extends FuseArrayPossibilities
30
+ ? // CLAUSE A > TRUE: CLAUSE B: Pick out the first item in the current array, separating the current item from the rest.
31
+ A extends [infer Head, ...infer Tail]
32
+ ? // CLAUSE B > TRUE: CLAUSE C: Check if the current item is a duplicate based on the input union.
33
+ Head extends B
34
+ ? // CLAUSE C > TRUE: Duplicate found, return an empty array to throw a type error.
35
+ []
36
+ : // CLAUSE C > FALSE: Return a new array to continue the recursion, adds the current item type to the union.
37
+ [Head, ...FusesWithoutDuplicates<Tail, Head | B>]
38
+ : // CLAUSE B > FALSE: Return the input array as there is no more array elements to check.
39
+ A
40
+ : // CLAUSE A > FALSE: Return an empty array as it isn't a fuse tuple.
41
+ []
42
+
43
+ type FusePropsNamedArray<A extends FuseArrayPossibilities> = {
44
+ namedFusesToBurn: FusesWithoutDuplicates<A>
45
+ }
46
+
47
+ type FusePropsUnnamedArray = {
48
+ unnamedFusesToBurn: UnnamedFuseValues[]
49
+ }
50
+
51
+ type FusePropsNumber = {
52
+ fuseNumberToBurn: number
53
+ }
54
+
55
+ type FuseProps<A extends FuseArrayPossibilities> =
56
+ | (Partial<FusePropsNamedArray<A>> & FusePropsUnnamedArray)
57
+ | (FusePropsNamedArray<A> & Partial<FusePropsUnnamedArray>)
58
+ | FusePropsNumber
59
+
60
+ export default async function <A extends FuseArrayPossibilities>(
7
61
  { contracts, signer }: ENSArgs<'contracts' | 'signer'>,
8
62
  name: string,
9
- {
10
- fusesToBurn,
11
- }: {
12
- fusesToBurn: FuseOptions
13
- },
63
+ props: FuseProps<A>,
14
64
  ) {
65
+ const isNumber = 'fuseNumberToBurn' in props
66
+ const hasNamedArray = 'namedFusesToBurn' in props
67
+ const hasUnnamedArray = 'unnamedFusesToBurn' in props
68
+
69
+ let encodedFuses: number = 0
70
+
71
+ if (isNumber) {
72
+ if (props.fuseNumberToBurn > 2 ** 32 || props.fuseNumberToBurn < 1) {
73
+ throw new Error(
74
+ `Fuse number must be limited to uint32, ${
75
+ props.fuseNumberToBurn
76
+ } was too ${props.fuseNumberToBurn < 1 ? 'low' : 'high'}.`,
77
+ )
78
+ } else if (props.fuseNumberToBurn % 1 !== 0) {
79
+ throw new Error(
80
+ `Fuse number must be an integer, ${props.fuseNumberToBurn} was not.`,
81
+ )
82
+ }
83
+ encodedFuses = props.fuseNumberToBurn
84
+ } else {
85
+ if (!hasNamedArray && !hasUnnamedArray) {
86
+ throw new Error('Please provide fuses to burn')
87
+ }
88
+ if (hasNamedArray) {
89
+ for (const fuse of props.namedFusesToBurn!) {
90
+ if (!(fuse in fuseEnum)) {
91
+ throw new Error(`${fuse} is not a valid named fuse.`)
92
+ }
93
+ encodedFuses |= fuseEnum[fuse]
94
+ }
95
+ }
96
+ if (hasUnnamedArray) {
97
+ for (const fuse of props.unnamedFusesToBurn!) {
98
+ if (!unnamedFuses.includes(fuse)) {
99
+ throw new Error(
100
+ `${fuse} is not a valid unnamed fuse. If you are trying to burn a named fuse, use the namedFusesToBurn property.`,
101
+ )
102
+ }
103
+ encodedFuses |= fuse
104
+ }
105
+ }
106
+ }
107
+
15
108
  const nameWrapper = (await contracts?.getNameWrapper()!).connect(signer)
16
109
  const hash = namehash(name)
17
110
 
18
- const encodedFuses = generateFuseInput(fusesToBurn)
19
-
20
111
  return nameWrapper.populateTransaction.setFuses(hash, encodedFuses)
21
112
  }
@@ -0,0 +1,61 @@
1
+ import { ethers } from 'ethers'
2
+ import { ENS } from '..'
3
+ import setup from '../tests/setup'
4
+ import { randomSecret } from '../utils/registerHelpers'
5
+
6
+ let ENSInstance: ENS
7
+ let revert: Awaited<ReturnType<typeof setup>>['revert']
8
+ let provider: ethers.providers.JsonRpcProvider
9
+ let accounts: string[]
10
+
11
+ beforeAll(async () => {
12
+ ;({ ENSInstance, revert, provider } = await setup())
13
+ accounts = await provider.listAccounts()
14
+ })
15
+
16
+ afterAll(async () => {
17
+ await revert()
18
+ })
19
+
20
+ describe('commitName', () => {
21
+ beforeEach(async () => {
22
+ await revert()
23
+ })
24
+ it('should return a populated commit transaction with extra data and succeed', async () => {
25
+ const { customData, ...popTx } =
26
+ await ENSInstance.commitName.populateTransaction('commitment.eth', {
27
+ duration: 31536000,
28
+ owner: accounts[1],
29
+ addressOrIndex: accounts[1],
30
+ })
31
+ expect(popTx).toBeTruthy()
32
+ expect(customData).toHaveProperty('secret')
33
+ expect(customData).toHaveProperty('commitment')
34
+ expect(customData).toHaveProperty('wrapperExpiry')
35
+
36
+ const tx = await provider.getSigner().sendTransaction(popTx)
37
+ await tx.wait()
38
+
39
+ const controller = await ENSInstance.contracts!.getEthRegistrarController()!
40
+ const commitment = await controller.commitments(customData!.commitment)
41
+ expect(commitment).toBeTruthy()
42
+ })
43
+ it('should return a customised commmit transaction and succeed', async () => {
44
+ const secret = randomSecret()
45
+ const tx = await ENSInstance.commitName('commitment.eth', {
46
+ duration: 31536000,
47
+ owner: accounts[1],
48
+ addressOrIndex: accounts[1],
49
+ secret,
50
+ wrapperExpiry: 100000,
51
+ })
52
+ await tx.wait()
53
+ expect(tx.customData).toBeTruthy()
54
+ expect(tx.customData!.wrapperExpiry).toBe(100000)
55
+ expect(tx.customData!.secret).toBe(secret)
56
+
57
+ const controller = await ENSInstance.contracts!.getEthRegistrarController()!
58
+ const commitment = await controller.commitments(tx.customData!.commitment)
59
+ expect(commitment).toBeTruthy()
60
+ })
61
+ })
@@ -0,0 +1,36 @@
1
+ import { ENSArgs } from '..'
2
+ import { CommitmentParams, makeCommitment } from '../utils/registerHelpers'
3
+
4
+ type Params = Omit<CommitmentParams, 'resolver' | 'name'> & {
5
+ resolverAddress?: string
6
+ }
7
+
8
+ export default async function (
9
+ { contracts }: ENSArgs<'contracts'>,
10
+ name: string,
11
+ { resolverAddress, ...params }: Params,
12
+ ) {
13
+ const labels = name.split('.')
14
+ if (labels.length !== 2 || labels[1] !== 'eth')
15
+ throw new Error('Currently only .eth TLD registrations are supported')
16
+
17
+ const controller = await contracts!.getEthRegistrarController()
18
+ const resolver = await contracts!.getPublicResolver(
19
+ undefined,
20
+ resolverAddress,
21
+ )
22
+ const { secret, commitment, wrapperExpiry } = makeCommitment({
23
+ name,
24
+ resolver,
25
+ ...params,
26
+ })
27
+
28
+ return {
29
+ ...(await controller.populateTransaction.commit(commitment)),
30
+ customData: {
31
+ secret,
32
+ commitment,
33
+ wrapperExpiry,
34
+ },
35
+ }
36
+ }
@@ -1,4 +1,4 @@
1
- import { ethers } from 'ethers'
1
+ import { BigNumber, ethers } from 'ethers'
2
2
  import { ENS } from '..'
3
3
  import setup from '../tests/setup'
4
4
 
@@ -9,6 +9,22 @@ let provider: ethers.providers.JsonRpcProvider
9
9
  let accounts: string[]
10
10
  let withWrappedSnapshot: any
11
11
 
12
+ const unwrappedNameDefault = {
13
+ expiryDate: new Date(0).toString(),
14
+ fuseObj: {
15
+ CANNOT_BURN_FUSES: false,
16
+ CANNOT_CREATE_SUBDOMAIN: false,
17
+ CANNOT_SET_RESOLVER: false,
18
+ CANNOT_SET_TTL: false,
19
+ CANNOT_TRANSFER: false,
20
+ CANNOT_UNWRAP: false,
21
+ PARENT_CANNOT_CONTROL: false,
22
+ canDoEverything: true,
23
+ },
24
+ owner: '0x0000000000000000000000000000000000000000',
25
+ rawFuses: BigNumber.from(0),
26
+ }
27
+
12
28
  beforeAll(async () => {
13
29
  ;({ ENSInstance, revert, provider, createSnapshot } = await setup())
14
30
  accounts = await provider.listAccounts()
@@ -26,9 +42,11 @@ afterAll(async () => {
26
42
  })
27
43
 
28
44
  describe('getFuses', () => {
29
- it('should return null for an unwrapped name', async () => {
45
+ it('should return default data for an unwrapped name', async () => {
30
46
  const result = await ENSInstance.getFuses('with-profile.eth')
31
- expect(result).toBeUndefined()
47
+ expect({ ...result, expiryDate: result?.expiryDate.toString() }).toEqual(
48
+ unwrappedNameDefault,
49
+ )
32
50
  })
33
51
  it('should return with canDoEverything set to true for a name with no fuses burned', async () => {
34
52
  const nameWrapper = await ENSInstance.contracts!.getNameWrapper()!
@@ -47,11 +65,11 @@ describe('getFuses', () => {
47
65
  })
48
66
  it('should return with other correct fuses', async () => {
49
67
  const tx = await ENSInstance.burnFuses('wrapped.eth', {
50
- fusesToBurn: {
51
- cannotUnwrap: true,
52
- cannotSetTtl: true,
53
- cannotCreateSubdomain: true,
54
- },
68
+ namedFusesToBurn: [
69
+ 'CANNOT_UNWRAP',
70
+ 'CANNOT_CREATE_SUBDOMAIN',
71
+ 'CANNOT_SET_TTL',
72
+ ],
55
73
  addressOrIndex: 1,
56
74
  })
57
75
  await tx.wait()
@@ -60,13 +78,13 @@ describe('getFuses', () => {
60
78
  expect(result).toBeTruthy()
61
79
  if (result) {
62
80
  expect(result.fuseObj).toMatchObject({
63
- cannotUnwrap: true,
64
- cannotBurnFuses: false,
65
- cannotTransfer: false,
66
- cannotSetResolver: false,
67
- cannotSetTtl: true,
68
- cannotCreateSubdomain: true,
69
- parentCannotControl: true,
81
+ CANNOT_UNWRAP: true,
82
+ CANNOT_BURN_FUSES: false,
83
+ CANNOT_TRANSFER: false,
84
+ CANNOT_SET_RESOLVER: false,
85
+ CANNOT_SET_TTL: true,
86
+ CANNOT_CREATE_SUBDOMAIN: true,
87
+ PARENT_CANNOT_CONTROL: true,
70
88
  canDoEverything: false,
71
89
  })
72
90
  expect(result.rawFuses.toHexString()).toBe('0x71')
@@ -1,48 +1,34 @@
1
1
  import { BigNumber } from 'ethers'
2
2
  import { ENSArgs } from '..'
3
- import { testable as fuseEnums } from '../utils/fuses'
3
+ import { fuseEnum } from '../utils/fuses'
4
4
  import { namehash } from '../utils/normalise'
5
5
 
6
- const NameSafety = [
7
- 'Safe',
8
- 'RegistrantNotWrapped',
9
- 'ControllerNotWrapped',
10
- 'SubdomainReplacementAllowed',
11
- 'Expired',
12
- ]
13
-
14
6
  const raw = async ({ contracts }: ENSArgs<'contracts'>, name: string) => {
15
7
  const nameWrapper = await contracts?.getNameWrapper()!
16
8
  return {
17
9
  to: nameWrapper.address,
18
- data: nameWrapper.interface.encodeFunctionData('getFuses', [
19
- namehash(name),
20
- ]),
10
+ data: nameWrapper.interface.encodeFunctionData('getData', [namehash(name)]),
21
11
  }
22
12
  }
23
13
 
24
14
  const decode = async (
25
15
  { contracts }: ENSArgs<'contracts'>,
26
16
  data: string,
27
- name: string,
28
17
  ) => {
29
18
  const nameWrapper = await contracts?.getNameWrapper()!
30
19
  try {
31
- const [_fuses, expiry] = nameWrapper.interface.decodeFunctionResult(
32
- 'getFuses',
33
- data,
34
- )
20
+ const {
21
+ owner,
22
+ fuses: _fuses,
23
+ expiry,
24
+ } = nameWrapper.interface.decodeFunctionResult('getData', data)
35
25
 
36
26
  const fuses = BigNumber.from(_fuses)
37
27
 
38
28
  const fuseObj = Object.fromEntries(
39
- Object.keys(fuseEnums).map((fuseEnum) => [
40
- fuseEnum
41
- .toLowerCase()
42
- .replace(/([-_][a-z])/g, (group: string) =>
43
- group.toUpperCase().replace('-', '').replace('_', ''),
44
- ),
45
- fuses.and(fuseEnums[fuseEnum as keyof typeof fuseEnums]).gt(0),
29
+ Object.keys(fuseEnum).map((fuse) => [
30
+ fuse,
31
+ fuses.and(fuseEnum[fuse as keyof typeof fuseEnum]).gt(0),
46
32
  ]),
47
33
  )
48
34
 
@@ -58,8 +44,10 @@ const decode = async (
58
44
  fuseObj,
59
45
  expiryDate,
60
46
  rawFuses: fuses,
47
+ owner,
61
48
  }
62
- } catch {
49
+ } catch (e) {
50
+ console.error('Error decoding fuses data: ', e)
63
51
  return
64
52
  }
65
53
  }
@@ -13,8 +13,6 @@ afterAll(async () => {
13
13
  })
14
14
 
15
15
  describe('getHistory', () => {
16
- let textEventsWithValue: any[]
17
-
18
16
  it('should return null for a non-existent name', async () => {
19
17
  const result = await ENSInstance.getHistory('test123123cool.eth')
20
18
  expect(result).toBeUndefined()
@@ -28,86 +26,4 @@ describe('getHistory', () => {
28
26
  expect(result).toHaveProperty('registration')
29
27
  }
30
28
  })
31
- describe('getHistoryWithDetail', () => {
32
- it('should return null for a non-existent name', async () => {
33
- const result = await ENSInstance.getHistoryWithDetail(
34
- 'test123123cool.eth',
35
- )
36
- expect(result).toBeUndefined()
37
- })
38
- it('should return the history of a name with TextChanged event detail', async () => {
39
- const result = await ENSInstance.getHistoryWithDetail('with-profile.eth')
40
- expect(result).toBeTruthy()
41
- if (result) {
42
- const textEvents = result.resolver.filter(
43
- (x) => x.type === 'TextChanged',
44
- )
45
- textEvents.forEach((event) =>
46
- expect(event.data).toHaveProperty('value'),
47
- )
48
- textEventsWithValue = textEvents
49
- }
50
- })
51
- })
52
- describe('getHistoryDetailForTransactionHash', () => {
53
- it('should throw an error for an invalid transaction hash', async () => {
54
- try {
55
- await ENSInstance.getHistoryDetailForTransactionHash('0x234')
56
- expect(false).toBeTruthy()
57
- } catch (error) {
58
- expect((error as any).message).toContain('invalid hash')
59
- }
60
- })
61
- it('should return null for a transaction hash with no text events', async () => {
62
- const result = await ENSInstance.getHistoryDetailForTransactionHash(
63
- '0x0fd7b555e3076ef38dbbe2e40deefe44c9a0530d43f6b3f60dbed4ba49d229b7',
64
- )
65
- expect(result).toBeUndefined()
66
- })
67
- it('should return single item for a given transaction hash with one event', async () => {
68
- const eventToUse = textEventsWithValue[0]
69
- const result = (await ENSInstance.getHistoryDetailForTransactionHash(
70
- eventToUse.transactionHash,
71
- )) as { key: any; value: any }[]
72
- expect(result).toHaveLength(1)
73
- if (result) {
74
- expect(result[0]).toMatchObject(eventToUse.data)
75
- }
76
- })
77
- let hash: string = ''
78
- it('should return multiple items for a given transaction hash with multiple events', async () => {
79
- const dataArr = [
80
- { key: 'foo', value: 'bar' },
81
- { key: 'swag', value: 'cool' },
82
- ]
83
- const tx = await ENSInstance.setRecords('test123.eth', {
84
- records: {
85
- texts: dataArr,
86
- },
87
- addressOrIndex: 1,
88
- })
89
- await tx.wait()
90
-
91
- hash = tx.hash
92
-
93
- const result = (await ENSInstance.getHistoryDetailForTransactionHash(
94
- hash,
95
- )) as { key: any; value: any }[]
96
- expect(result).toHaveLength(dataArr.length)
97
- if (result) {
98
- result.forEach((item, index) =>
99
- expect(item).toMatchObject(dataArr[index]),
100
- )
101
- }
102
- })
103
- it('should return a single item when an index is specified for a hash', async () => {
104
- const data = { key: 'swag', value: 'cool' }
105
-
106
- const result = (await ENSInstance.getHistoryDetailForTransactionHash(
107
- hash,
108
- 1,
109
- )) as { key: any; value: any }
110
- expect(result).toMatchObject(data)
111
- })
112
- })
113
29
  })