@ensdomains/ensjs 3.0.0-alpha.12 → 3.0.0-alpha.13

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 (41) hide show
  1. package/dist/cjs/functions/commitName.d.ts +26 -0
  2. package/dist/cjs/functions/commitName.js +24 -0
  3. package/dist/cjs/functions/getProfile.js +1 -1
  4. package/dist/cjs/functions/registerName.d.ts +11 -0
  5. package/dist/cjs/functions/registerName.js +19 -0
  6. package/dist/cjs/functions/renewName.d.ts +6 -0
  7. package/dist/cjs/functions/renewName.js +10 -0
  8. package/dist/cjs/index.d.ts +10 -2
  9. package/dist/cjs/index.js +6 -1
  10. package/dist/cjs/utils/registerHelpers.d.ts +44 -16
  11. package/dist/cjs/utils/registerHelpers.js +43 -15
  12. package/dist/cjs/utils/writeTx.d.ts +18 -1
  13. package/dist/cjs/utils/writeTx.js +4 -1
  14. package/dist/esm/functions/commitName.d.ts +26 -0
  15. package/dist/esm/functions/commitName.js +21 -0
  16. package/dist/esm/functions/getProfile.js +1 -1
  17. package/dist/esm/functions/registerName.d.ts +11 -0
  18. package/dist/esm/functions/registerName.js +16 -0
  19. package/dist/esm/functions/renewName.d.ts +6 -0
  20. package/dist/esm/functions/renewName.js +7 -0
  21. package/dist/esm/index.d.ts +10 -2
  22. package/dist/esm/index.js +6 -1
  23. package/dist/esm/utils/registerHelpers.d.ts +44 -16
  24. package/dist/esm/utils/registerHelpers.js +40 -14
  25. package/dist/esm/utils/writeTx.d.ts +18 -1
  26. package/dist/esm/utils/writeTx.js +4 -1
  27. package/package.json +19 -22
  28. package/src/functions/commitName.test.ts +61 -0
  29. package/src/functions/commitName.ts +36 -0
  30. package/src/functions/getProfile.ts +1 -1
  31. package/src/functions/registerName.test.ts +59 -0
  32. package/src/functions/registerName.ts +38 -0
  33. package/src/functions/renewName.test.ts +44 -0
  34. package/src/functions/renewName.ts +22 -0
  35. package/src/index.ts +25 -4
  36. package/src/utils/registerHelpers.ts +107 -49
  37. package/src/utils/writeTx.ts +12 -2
  38. package/src/tests/populateTransaction.test.ts +0 -40
  39. package/src/tests/setup.ts +0 -57
  40. package/src/tests/signerInjection.test.ts +0 -46
  41. package/src/tests/withProvider.test.ts +0 -28
@@ -7,37 +7,63 @@ export const randomSecret = () => {
7
7
  const bytes = Buffer.allocUnsafe(32);
8
8
  return '0x' + crypto.getRandomValues(bytes).toString('hex');
9
9
  };
10
- export const makeCommitment = ({ name, owner, duration, resolver, records, reverseRecord, fuses, }) => {
10
+ export const makeCommitmentData = ({ name, owner, duration, resolver, records, reverseRecord, fuses, wrapperExpiry, secret, }) => {
11
11
  const label = labelhash(name.split('.')[0]);
12
12
  const hash = namehash(name);
13
13
  const resolverAddress = resolver.address;
14
- const data = records ? generateRecordCallArray(hash, records, resolver) : [];
15
- const secret = randomSecret();
16
14
  const fuseData = fuses ? generateFuseInput(fuses) : '0';
17
- const commitment = _makeCommitment({
18
- labelhash: label,
15
+ if (reverseRecord) {
16
+ if (!records) {
17
+ records = { coinTypes: [{ key: 'ETH', value: owner }] };
18
+ }
19
+ else if (!records.coinTypes?.find((c) => c.key === 'ETH')) {
20
+ if (!records.coinTypes)
21
+ records.coinTypes = [];
22
+ records.coinTypes.push({ key: 'ETH', value: owner });
23
+ }
24
+ }
25
+ const data = records ? generateRecordCallArray(hash, records, resolver) : [];
26
+ return [
27
+ label,
19
28
  owner,
20
29
  duration,
21
- secret,
22
- resolver: resolverAddress,
30
+ resolverAddress,
23
31
  data,
24
- reverseRecord: !!reverseRecord,
25
- fuses: fuseData,
32
+ secret,
33
+ !!reverseRecord,
34
+ fuseData,
35
+ wrapperExpiry || Math.floor(Date.now() / 1000) + duration,
36
+ ];
37
+ };
38
+ export const makeRegistrationData = (params) => {
39
+ const commitmentData = makeCommitmentData(params);
40
+ commitmentData[0] = params.name.split('.')[0];
41
+ const secret = commitmentData.splice(5, 1)[0];
42
+ commitmentData.splice(3, 0, secret);
43
+ return commitmentData;
44
+ };
45
+ export const makeCommitment = ({ secret = randomSecret(), ...inputParams }) => {
46
+ const generatedParams = makeCommitmentData({
47
+ ...inputParams,
48
+ secret,
26
49
  });
50
+ const commitment = _makeCommitment(generatedParams);
27
51
  return {
28
52
  secret,
29
53
  commitment,
54
+ wrapperExpiry: generatedParams[8],
30
55
  };
31
56
  };
32
- export const _makeCommitment = ({ labelhash, owner, duration, secret, resolver, data, reverseRecord, fuses, }) => {
33
- return utils.solidityKeccak256([
57
+ export const _makeCommitment = (params) => {
58
+ return utils.keccak256(utils.defaultAbiCoder.encode([
34
59
  'bytes32',
35
60
  'address',
36
61
  'uint256',
37
- 'bytes32',
38
62
  'address',
39
63
  'bytes[]',
64
+ 'bytes32',
40
65
  'bool',
41
- 'uint96',
42
- ], [labelhash, owner, duration, secret, resolver, data, reverseRecord, fuses]);
66
+ 'uint32',
67
+ 'uint64',
68
+ ], params));
43
69
  };
@@ -1,4 +1,21 @@
1
1
  import { JsonRpcSigner } from '@ethersproject/providers';
2
2
  import type { PopulatedTransaction } from 'ethers';
3
- declare const _default: (signer: JsonRpcSigner, populate: boolean) => (tx: PopulatedTransaction) => PopulatedTransaction | Promise<import("@ethersproject/abstract-provider").TransactionResponse>;
3
+ declare type CustomData = Record<string, any>;
4
+ declare const _default: (signer: JsonRpcSigner, populate: boolean) => ({ customData, ...tx }: PopulatedTransaction) => {
5
+ to?: string | undefined;
6
+ from?: string | undefined;
7
+ nonce?: number | undefined;
8
+ gasLimit?: import("ethers").BigNumber | undefined;
9
+ gasPrice?: import("ethers").BigNumber | undefined;
10
+ data?: string | undefined;
11
+ value?: import("ethers").BigNumber | undefined;
12
+ chainId?: number | undefined;
13
+ type?: number | undefined;
14
+ accessList?: import("ethers/lib/utils").AccessList | undefined;
15
+ maxFeePerGas?: import("ethers").BigNumber | undefined;
16
+ maxPriorityFeePerGas?: import("ethers").BigNumber | undefined;
17
+ ccipReadEnabled?: boolean | undefined;
18
+ } | Promise<import("@ethersproject/providers").TransactionResponse | (import("@ethersproject/providers").TransactionResponse & {
19
+ customData: CustomData;
20
+ })>;
4
21
  export default _default;
@@ -1 +1,4 @@
1
- export default (signer, populate) => (tx) => populate ? tx : signer.sendTransaction(tx);
1
+ const withCustomData = (tx, customData) => customData ? { ...tx, customData } : tx;
2
+ export default (signer, populate) => ({ customData, ...tx }) => populate
3
+ ? withCustomData(tx, customData)
4
+ : signer.sendTransaction(tx).then((r) => withCustomData(r, customData));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ensdomains/ensjs",
3
- "version": "3.0.0-alpha.12",
3
+ "version": "3.0.0-alpha.13",
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.11"
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
  }
@@ -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
+ }
@@ -362,7 +362,7 @@ const graphFetch = async (
362
362
  ;({ domain } = await client.request(query, { id }))
363
363
  resolverResponse = domain?.resolver
364
364
  } else {
365
- const resolverId = `${resolverAddress}-${id}`
365
+ const resolverId = `${resolverAddress.toLowerCase()}-${id}`
366
366
  ;({ resolver: resolverResponse, domain } = await client.request(
367
367
  customResolverQuery,
368
368
  { id, resolverId },
@@ -0,0 +1,59 @@
1
+ import { ethers } from 'ethers'
2
+ import { ENS } from '..'
3
+ import setup from '../tests/setup'
4
+ import { namehash } from '../utils/normalise'
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
+ await provider.send('anvil_removeBlockTimestampInterval', [])
19
+ })
20
+
21
+ describe('registerName', () => {
22
+ beforeEach(async () => {
23
+ await revert()
24
+ })
25
+ it('should return a registration transaction and succeed', async () => {
26
+ const name = 'cool-swag.eth'
27
+ const duration = 31536000
28
+ const { customData, ...commitPopTx } =
29
+ await ENSInstance.commitName.populateTransaction(name, {
30
+ duration,
31
+ owner: accounts[1],
32
+ addressOrIndex: accounts[1],
33
+ })
34
+ const commitTx = await provider.getSigner().sendTransaction(commitPopTx)
35
+ await commitTx.wait()
36
+
37
+ await provider.send('evm_increaseTime', [60])
38
+ await provider.send('evm_mine', [])
39
+
40
+ const { secret, wrapperExpiry } = customData!
41
+
42
+ const controller = await ENSInstance.contracts!.getEthRegistrarController()!
43
+ const [price] = await controller.rentPrice(name, duration)
44
+
45
+ const tx = await ENSInstance.registerName(name, {
46
+ secret,
47
+ wrapperExpiry,
48
+ duration,
49
+ owner: accounts[1],
50
+ addressOrIndex: accounts[1],
51
+ value: price,
52
+ })
53
+ await tx.wait()
54
+
55
+ const nameWrapper = await ENSInstance.contracts!.getNameWrapper()!
56
+ const owner = await nameWrapper.ownerOf(namehash(name))
57
+ expect(owner).toBe(accounts[1])
58
+ })
59
+ })
@@ -0,0 +1,38 @@
1
+ import { BigNumber } from 'ethers'
2
+ import { ENSArgs } from '..'
3
+ import {
4
+ CommitmentParams,
5
+ makeRegistrationData,
6
+ } from '../utils/registerHelpers'
7
+
8
+ type Params = Omit<CommitmentParams, 'name' | 'resolver'> & {
9
+ resolverAddress?: string
10
+ secret: string
11
+ wrapperExpiry: number
12
+ value: BigNumber
13
+ }
14
+
15
+ export default async function (
16
+ { contracts }: ENSArgs<'contracts'>,
17
+ name: string,
18
+ { resolverAddress, value, ...params }: Params,
19
+ ) {
20
+ const labels = name.split('.')
21
+ if (labels.length !== 2 || labels[1] !== 'eth')
22
+ throw new Error('Currently only .eth TLD registrations are supported')
23
+
24
+ const controller = await contracts!.getEthRegistrarController()
25
+ const _resolver = await contracts!.getPublicResolver(
26
+ undefined,
27
+ resolverAddress,
28
+ )
29
+ const generatedParams = makeRegistrationData({
30
+ name,
31
+ resolver: _resolver,
32
+ ...params,
33
+ })
34
+
35
+ return controller.populateTransaction.register(...generatedParams, {
36
+ value,
37
+ })
38
+ }
@@ -0,0 +1,44 @@
1
+ import { ethers } from 'ethers'
2
+ import { ENS } from '..'
3
+ import setup from '../tests/setup'
4
+ import { labelhash } from '../utils/labels'
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('registerName', () => {
21
+ beforeEach(async () => {
22
+ await revert()
23
+ })
24
+ it('should return a renew transaction and succeed', async () => {
25
+ const name = 'to-be-renewed.eth'
26
+ const label = name.split('.')[0]
27
+ const duration = 31536000
28
+ const baseRegistrar = await ENSInstance.contracts!.getBaseRegistrar()!
29
+ const oldExpiry = await baseRegistrar.nameExpires(labelhash(label))
30
+
31
+ const controller = await ENSInstance.contracts!.getEthRegistrarController()!
32
+ const [price] = await controller.rentPrice(label, duration)
33
+
34
+ const tx = await ENSInstance.renewName(name, {
35
+ value: price.mul(2),
36
+ duration,
37
+ addressOrIndex: accounts[1],
38
+ })
39
+ await tx.wait()
40
+
41
+ const newExpiry = await baseRegistrar.nameExpires(labelhash(label))
42
+ expect(newExpiry.toNumber()).toBe(oldExpiry.add(31536000).toNumber())
43
+ })
44
+ })
@@ -0,0 +1,22 @@
1
+ import type { BigNumber } from 'ethers'
2
+ import { ENSArgs } from '..'
3
+
4
+ export default async function (
5
+ { contracts }: ENSArgs<'contracts'>,
6
+ name: string,
7
+ {
8
+ duration,
9
+ value,
10
+ }: {
11
+ duration: number
12
+ value: BigNumber
13
+ },
14
+ ) {
15
+ const labels = name.split('.')
16
+ if (labels.length !== 2 || labels[1] !== 'eth')
17
+ throw new Error('Currently only .eth TLD renewals are supported')
18
+
19
+ const controller = await contracts!.getEthRegistrarController()
20
+
21
+ return controller.populateTransaction.renew(labels[0], duration, { value })
22
+ }
package/src/index.ts CHANGED
@@ -10,6 +10,7 @@ import type {
10
10
  universalWrapper,
11
11
  } from './functions/batchWrappers'
12
12
  import type burnFuses from './functions/burnFuses'
13
+ import type commitName from './functions/commitName'
13
14
  import type createSubname from './functions/createSubname'
14
15
  import type deleteSubname from './functions/deleteSubname'
15
16
  import type getDNSOwner from './functions/getDNSOwner'
@@ -32,6 +33,8 @@ import type {
32
33
  _getText,
33
34
  } from './functions/getSpecificRecord'
34
35
  import type getSubnames from './functions/getSubnames'
36
+ import registerName from './functions/registerName'
37
+ import renewName from './functions/renewName'
35
38
  import type setName from './functions/setName'
36
39
  import type setRecord from './functions/setRecord'
37
40
  import type setRecords from './functions/setRecords'
@@ -92,7 +95,11 @@ type OptionalWriteOptions<F> = F extends (
92
95
  : never
93
96
 
94
97
  interface WriteFunction<F extends (...args: any) => any> extends Function {
95
- (...args: Parameters<OptionalWriteOptions<F>>): Promise<ContractTransaction>
98
+ (...args: Parameters<OptionalWriteOptions<F>>): Promise<
99
+ ContractTransaction & {
100
+ customData?: Record<string, any>
101
+ }
102
+ >
96
103
  populateTransaction: (
97
104
  ...args: Parameters<OptionalWriteOptions<F>>
98
105
  ) => Promise<PopulatedTransaction>
@@ -499,6 +506,11 @@ export class ENS {
499
506
  'getPrice',
500
507
  )
501
508
 
509
+ public getDNSOwner = this.generateFunction<typeof getDNSOwner>(
510
+ 'getDNSOwner',
511
+ [],
512
+ )
513
+
502
514
  public universalWrapper = this.generateRawFunction<typeof universalWrapper>(
503
515
  'initialGetters',
504
516
  ['contracts'],
@@ -569,8 +581,17 @@ export class ENS {
569
581
  ['contracts', 'getExpiry'],
570
582
  )
571
583
 
572
- public getDNSOwner = this.generateFunction<typeof getDNSOwner>(
573
- 'getDNSOwner',
574
- [],
584
+ public commitName = this.generateWriteFunction<typeof commitName>(
585
+ 'commitName',
586
+ ['contracts'],
587
+ )
588
+
589
+ public registerName = this.generateWriteFunction<typeof registerName>(
590
+ 'registerName',
591
+ ['contracts'],
575
592
  )
593
+
594
+ public renewName = this.generateWriteFunction<typeof renewName>('renewName', [
595
+ 'contracts',
596
+ ])
576
597
  }