diff --git a/packages/ensjs/src/functions/burnFuses.test.ts b/packages/ensjs/src/functions/burnFuses.test.ts index 32f74376..bfae28ba 100644 --- a/packages/ensjs/src/functions/burnFuses.test.ts +++ b/packages/ensjs/src/functions/burnFuses.test.ts @@ -1,7 +1,7 @@ import { BigNumber, ethers } from 'ethers' import { ENS } from '..' -import { namehash } from '../utils/normalise' import setup from '../tests/setup' +import { namehash } from '../utils/normalise' let ENSInstance: ENS let revert: Awaited>['revert'] @@ -22,16 +22,17 @@ describe('burnFuses', () => { await revert() }) it('should return a burnFuses transaction and succeed', async () => { - const wrapNameTx = await ENSInstance.wrapName( - 'parthtejpal.eth', - accounts[0], - ) + const wrapNameTx = await ENSInstance.wrapName('parthtejpal.eth', { + wrappedOwner: accounts[0], + }) await wrapNameTx.wait() const tx = await ENSInstance.burnFuses('parthtejpal.eth', { - cannotUnwrap: true, - cannotCreateSubdomain: true, - cannotSetTtl: true, + fusesToBurn: { + cannotUnwrap: true, + cannotCreateSubdomain: true, + cannotSetTtl: true, + }, }) expect(tx).toBeTruthy() await tx.wait() diff --git a/packages/ensjs/src/functions/burnFuses.ts b/packages/ensjs/src/functions/burnFuses.ts index 7c2eb610..2021b6e9 100644 --- a/packages/ensjs/src/functions/burnFuses.ts +++ b/packages/ensjs/src/functions/burnFuses.ts @@ -1,21 +1,17 @@ -import { Signer } from 'ethers' import { ENSArgs } from '..' import { FuseOptions } from '../@types/FuseOptions' import generateFuseInput from '../utils/generateFuseInput' import { namehash } from '../utils/normalise' export default async function ( - { contracts, provider }: ENSArgs<'contracts' | 'provider'>, + { contracts, signer }: ENSArgs<'contracts' | 'signer'>, name: string, - fusesToBurn: FuseOptions, - options?: { addressOrIndex?: string | number; signer?: Signer }, + { + fusesToBurn, + }: { + fusesToBurn: FuseOptions + }, ) { - const signer = options?.signer || provider?.getSigner(options?.addressOrIndex) - - if (!signer) { - throw new Error('No signer found') - } - const nameWrapper = (await contracts?.getNameWrapper()!).connect(signer) const hash = namehash(name) diff --git a/packages/ensjs/src/functions/createSubname.test.ts b/packages/ensjs/src/functions/createSubname.test.ts index be1acdc3..64a88454 100644 --- a/packages/ensjs/src/functions/createSubname.test.ts +++ b/packages/ensjs/src/functions/createSubname.test.ts @@ -1,7 +1,7 @@ import { ethers } from 'ethers' import { ENS } from '..' -import { namehash } from '../utils/normalise' import setup from '../tests/setup' +import { namehash } from '../utils/normalise' let ENSInstance: ENS let revert: Awaited>['revert'] @@ -23,11 +23,10 @@ describe('createSubname', () => { await revert() }) it('should allow creating a subname on the registry', async () => { - const tx = await ENSInstance.createSubname({ + const tx = await ENSInstance.createSubname('test.parthtejpal.eth', { contract: 'registry', - name: 'test.parthtejpal.eth', owner: accounts[0], - options: { addressOrIndex: 0 }, + addressOrIndex: 0, }) expect(tx).toBeTruthy() await tx.wait() @@ -37,16 +36,14 @@ describe('createSubname', () => { expect(result).toBe(accounts[0]) }) it('should allow creating a subname on the namewrapper', async () => { - const wrapNameTx = await ENSInstance.wrapName( - 'parthtejpal.eth', - accounts[0], - ) + const wrapNameTx = await ENSInstance.wrapName('parthtejpal.eth', { + wrappedOwner: accounts[0], + }) await wrapNameTx.wait() - const tx = await ENSInstance.createSubname({ + const tx = await ENSInstance.createSubname('test.parthtejpal.eth', { contract: 'nameWrapper', - name: 'test.parthtejpal.eth', owner: accounts[0], - options: { addressOrIndex: 0 }, + addressOrIndex: 0, }) expect(tx).toBeTruthy() await tx.wait() diff --git a/packages/ensjs/src/functions/createSubname.ts b/packages/ensjs/src/functions/createSubname.ts index 2cf1bfe8..74583d56 100644 --- a/packages/ensjs/src/functions/createSubname.ts +++ b/packages/ensjs/src/functions/createSubname.ts @@ -1,15 +1,13 @@ -import { ethers, Signer } from 'ethers' +import { ethers } from 'ethers' import { ENSArgs } from '..' import { FuseOptions } from '../@types/FuseOptions' import generateFuseInput from '../utils/generateFuseInput' import { namehash } from '../utils/normalise' type BaseArgs = { - name: string owner: string resolverAddress?: string contract: 'registry' | 'nameWrapper' - options?: { addressOrIndex?: string | number; signer?: Signer } } type NameWrapperArgs = { @@ -20,15 +18,10 @@ type NameWrapperArgs = { type Args = BaseArgs | NameWrapperArgs export default async function ( - { contracts, provider }: ENSArgs<'contracts' | 'provider'>, - { name, owner, resolverAddress, contract, options, ...wrapperArgs }: Args, + { contracts, signer }: ENSArgs<'contracts' | 'signer'>, + name: string, + { owner, resolverAddress, contract, ...wrapperArgs }: Args, ) { - const signer = options?.signer || provider?.getSigner(options?.addressOrIndex) - - if (!signer) { - throw new Error('No signer found') - } - const labels = name.split('.') if (labels.length === 1) { diff --git a/packages/ensjs/src/functions/deleteSubname.test.ts b/packages/ensjs/src/functions/deleteSubname.test.ts index e661cab0..e4c8ee3a 100644 --- a/packages/ensjs/src/functions/deleteSubname.test.ts +++ b/packages/ensjs/src/functions/deleteSubname.test.ts @@ -1,7 +1,7 @@ import { ethers } from 'ethers' import { ENS } from '..' -import { namehash } from '../utils/normalise' import setup from '../tests/setup' +import { namehash } from '../utils/normalise' let ENSInstance: ENS let revert: Awaited>['revert'] @@ -22,19 +22,20 @@ describe('deleteSubname', () => { await revert() }) it('should allow deleting a subname on the registry', async () => { - const createSubnameTx = await ENSInstance.createSubname({ - contract: 'registry', - name: 'test.parthtejpal.eth', - owner: accounts[0], - options: { addressOrIndex: 0 }, - }) - await createSubnameTx.wait() - - const tx = await ENSInstance.deleteSubname( + const createSubnameTx = await ENSInstance.createSubname( 'test.parthtejpal.eth', - 'registry', - { addressOrIndex: 0 }, + { + contract: 'registry', + owner: accounts[0], + addressOrIndex: 0, + }, ) + await createSubnameTx.wait() + + const tx = await ENSInstance.deleteSubname('test.parthtejpal.eth', { + contract: 'registry', + addressOrIndex: 0, + }) expect(tx).toBeTruthy() await tx.wait() @@ -43,24 +44,24 @@ describe('deleteSubname', () => { expect(result).toBe('0x0000000000000000000000000000000000000000') }) it('should allow deleting a subname on the nameWrapper', async () => { - const wrapNameTx = await ENSInstance.wrapName( - 'parthtejpal.eth', - accounts[0], - ) - await wrapNameTx.wait() - const createSubnameTx = await ENSInstance.createSubname({ - contract: 'nameWrapper', - name: 'test.parthtejpal.eth', - owner: accounts[0], - options: { addressOrIndex: 0 }, + const wrapNameTx = await ENSInstance.wrapName('parthtejpal.eth', { + wrappedOwner: accounts[0], }) - await createSubnameTx.wait() - - const tx = await ENSInstance.deleteSubname( + await wrapNameTx.wait() + const createSubnameTx = await ENSInstance.createSubname( 'test.parthtejpal.eth', - 'nameWrapper', - { addressOrIndex: 0 }, + { + contract: 'nameWrapper', + owner: accounts[0], + addressOrIndex: 0, + }, ) + await createSubnameTx.wait() + + const tx = await ENSInstance.deleteSubname('test.parthtejpal.eth', { + contract: 'nameWrapper', + addressOrIndex: 0, + }) expect(tx).toBeTruthy() await tx.wait() diff --git a/packages/ensjs/src/functions/deleteSubname.ts b/packages/ensjs/src/functions/deleteSubname.ts index 78527db7..4e8b92e5 100644 --- a/packages/ensjs/src/functions/deleteSubname.ts +++ b/packages/ensjs/src/functions/deleteSubname.ts @@ -1,20 +1,16 @@ -import { Signer } from 'ethers' import { ENSArgs } from '..' export default async function ( - { - contracts, - provider, - transferSubname, - }: ENSArgs<'contracts' | 'provider' | 'transferSubname'>, + { transferSubname }: ENSArgs<'transferSubname'>, name: string, - contract: 'registry' | 'nameWrapper', - options?: { addressOrIndex?: string | number; signer?: Signer }, + { + contract, + }: { + contract: 'registry' | 'nameWrapper' + }, ) { - return transferSubname( - name, + return transferSubname(name, { contract, - '0x0000000000000000000000000000000000000000', - options, - ) + address: '0x0000000000000000000000000000000000000000', + }) } diff --git a/packages/ensjs/src/functions/getFuses.test.ts b/packages/ensjs/src/functions/getFuses.test.ts index 19115c84..12a95f69 100644 --- a/packages/ensjs/src/functions/getFuses.test.ts +++ b/packages/ensjs/src/functions/getFuses.test.ts @@ -12,7 +12,9 @@ let withWrappedSnapshot: any beforeAll(async () => { ;({ ENSInstance, revert, provider, createSnapshot } = await setup()) accounts = await provider.listAccounts() - const tx = await ENSInstance.wrapName('parthtejpal.eth', accounts[0]) + const tx = await ENSInstance.wrapName('parthtejpal.eth', { + wrappedOwner: accounts[0], + }) await tx.wait() withWrappedSnapshot = await createSnapshot() @@ -33,11 +35,10 @@ describe('getFuses', () => { expect(result).toBeUndefined() }) it('should return with canDoEverything set to true for a name with no fuses burned', async () => { - const tx = await ENSInstance.createSubname({ + const tx = await ENSInstance.createSubname('test.parthtejpal.eth', { contract: 'nameWrapper', - name: 'test.parthtejpal.eth', owner: accounts[0], - options: { addressOrIndex: 0 }, + addressOrIndex: 0, }) await tx.wait() @@ -56,9 +57,11 @@ describe('getFuses', () => { }) it('should return with other correct fuses', async () => { const tx = await ENSInstance.burnFuses('parthtejpal.eth', { - cannotUnwrap: true, - cannotSetTtl: true, - cannotCreateSubdomain: true, + fusesToBurn: { + cannotUnwrap: true, + cannotSetTtl: true, + cannotCreateSubdomain: true, + }, }) await tx.wait() const result = await ENSInstance.getFuses('parthtejpal.eth') @@ -86,8 +89,7 @@ describe('getFuses', () => { } }) it('should return correct vulnerability data for a vulnerable node', async () => { - const tx = await ENSInstance.createSubname({ - name: 'test.parthtejpal.eth', + const tx = await ENSInstance.createSubname('test.parthtejpal.eth', { owner: accounts[0], contract: 'nameWrapper', }) diff --git a/packages/ensjs/src/functions/getOwner.test.ts b/packages/ensjs/src/functions/getOwner.test.ts index ebac4161..6cabaa83 100644 --- a/packages/ensjs/src/functions/getOwner.test.ts +++ b/packages/ensjs/src/functions/getOwner.test.ts @@ -10,7 +10,9 @@ let accounts: string[] beforeAll(async () => { ;({ ENSInstance, revert, provider } = await setup()) accounts = await provider.listAccounts() - const tx = await ENSInstance.wrapName('parthtejpal.eth', accounts[0]) + const tx = await ENSInstance.wrapName('parthtejpal.eth', { + wrappedOwner: accounts[0], + }) await tx.wait() }) diff --git a/packages/ensjs/src/functions/setName.test.ts b/packages/ensjs/src/functions/setName.test.ts index 4dc914d2..5081e8b9 100644 --- a/packages/ensjs/src/functions/setName.test.ts +++ b/packages/ensjs/src/functions/setName.test.ts @@ -1,7 +1,7 @@ import { ethers } from 'ethers' import { ENS } from '..' -import { hexEncodeName } from '../utils/hexEncodedName' import setup from '../tests/setup' +import { hexEncodeName } from '../utils/hexEncodedName' let ENSInstance: ENS let revert: Awaited>['revert'] @@ -43,7 +43,8 @@ describe('setName', () => { ) await setApprovedForAllTx?.wait() - const tx = await ENSInstance.setName('fleek.eth', accounts[0], undefined, { + const tx = await ENSInstance.setName('fleek.eth', { + address: accounts[0], addressOrIndex: 1, }) expect(tx).toBeTruthy() diff --git a/packages/ensjs/src/functions/setName.ts b/packages/ensjs/src/functions/setName.ts index 48a45ff4..1d293aba 100644 --- a/packages/ensjs/src/functions/setName.ts +++ b/packages/ensjs/src/functions/setName.ts @@ -1,23 +1,20 @@ -import { Signer } from 'ethers' import { ENSArgs } from '..' export default async function ( - { contracts, provider }: ENSArgs<'contracts' | 'provider'>, + { contracts, signer }: ENSArgs<'contracts' | 'signer'>, name: string, - address?: string, - resolver?: string, - options?: { addressOrIndex?: string | number; signer?: Signer }, + { + address, + resolver, + }: { + address?: string + resolver?: string + } = {}, ) { - const signer = options?.signer || provider?.getSigner(options?.addressOrIndex) - - if (!signer) { - throw new Error('No signer found') - } - const signerAddress = await signer.getAddress() const reverseRegistrar = (await contracts?.getReverseRegistrar())?.connect( - provider?.getSigner()!, + signer, ) if (address) { diff --git a/packages/ensjs/src/functions/setRecords.test.ts b/packages/ensjs/src/functions/setRecords.test.ts index 204f58dd..95558e62 100644 --- a/packages/ensjs/src/functions/setRecords.test.ts +++ b/packages/ensjs/src/functions/setRecords.test.ts @@ -1,7 +1,7 @@ import { ENS } from '..' +import setup from '../tests/setup' import { hexEncodeName } from '../utils/hexEncodedName' import { namehash } from '../utils/normalise' -import setup from '../tests/setup' let ENSInstance: ENS let revert: Awaited>['revert'] @@ -17,10 +17,12 @@ afterAll(async () => { describe('setRecords', () => { it('should return a transaction to the resolver and set successfully', async () => { const tx = await ENSInstance.setRecords('parthtejpal.eth', { - coinTypes: [ - { key: 'ETC', value: '0x42D63ae25990889E35F215bC95884039Ba354115' }, - ], - texts: [{ key: 'foo', value: 'bar' }], + records: { + coinTypes: [ + { key: 'ETC', value: '0x42D63ae25990889E35F215bC95884039Ba354115' }, + ], + texts: [{ key: 'foo', value: 'bar' }], + }, }) expect(tx).toBeTruthy() await tx.wait() diff --git a/packages/ensjs/src/functions/setRecords.ts b/packages/ensjs/src/functions/setRecords.ts index f57e83d2..0592947b 100644 --- a/packages/ensjs/src/functions/setRecords.ts +++ b/packages/ensjs/src/functions/setRecords.ts @@ -1,4 +1,3 @@ -import type { Signer } from 'ethers' import { ENSArgs } from '..' import { namehash } from '../utils/normalise' import { generateRecordCallArray, RecordOptions } from '../utils/recordHelpers' @@ -8,13 +7,15 @@ export default async function ( contracts, provider, getResolver, - }: ENSArgs<'contracts' | 'provider' | 'getResolver'>, + signer, + }: ENSArgs<'contracts' | 'provider' | 'getResolver' | 'signer'>, name: string, - records: RecordOptions, - resolverAddress?: string, - options?: { - signer?: Signer - addressOrIndex?: string | number + { + records, + resolverAddress, + }: { + records: RecordOptions + resolverAddress?: string }, ) { if (!name.includes('.')) { @@ -32,12 +33,6 @@ export default async function ( throw new Error('No resolver found for input address') } - const signer = options?.signer || provider?.getSigner(options?.addressOrIndex) - - if (!signer) { - throw new Error('No signer found') - } - const resolver = ( await contracts?.getPublicResolver(provider, resolverToUse) )?.connect(signer) diff --git a/packages/ensjs/src/functions/setResolver.test.ts b/packages/ensjs/src/functions/setResolver.test.ts index 8c93cc34..3b78ee8c 100644 --- a/packages/ensjs/src/functions/setResolver.test.ts +++ b/packages/ensjs/src/functions/setResolver.test.ts @@ -1,7 +1,7 @@ import { ethers } from 'ethers' import { ENS } from '..' -import { hexEncodeName } from '../utils/hexEncodedName' import setup from '../tests/setup' +import { hexEncodeName } from '../utils/hexEncodedName' let ENSInstance: ENS let revert: Awaited>['revert'] @@ -20,11 +20,10 @@ describe('setResolver', () => { await revert() }) it('should return a transaction to the registry and set successfully', async () => { - const tx = await ENSInstance.setResolver( - 'parthtejpal.eth', - 'registry', - '0xAEfF4f4d8e2cB51854BEa2244B3C5Fb36b41C7fC', - ) + const tx = await ENSInstance.setResolver('parthtejpal.eth', { + contract: 'registry', + resolver: '0xAEfF4f4d8e2cB51854BEa2244B3C5Fb36b41C7fC', + }) expect(tx).toBeTruthy() await tx.wait() @@ -37,16 +36,14 @@ describe('setResolver', () => { }) it('should return a transaction to the namewrapper and set successfully', async () => { const accounts = await provider.listAccounts() - const wrapNameTx = await ENSInstance.wrapName( - 'parthtejpal.eth', - accounts[0], - ) + const wrapNameTx = await ENSInstance.wrapName('parthtejpal.eth', { + wrappedOwner: accounts[0], + }) await wrapNameTx.wait() - const tx = await ENSInstance.setResolver( - 'parthtejpal.eth', - 'nameWrapper', - '0xAEfF4f4d8e2cB51854BEa2244B3C5Fb36b41C7fC', - ) + const tx = await ENSInstance.setResolver('parthtejpal.eth', { + contract: 'nameWrapper', + resolver: '0xAEfF4f4d8e2cB51854BEa2244B3C5Fb36b41C7fC', + }) expect(tx).toBeTruthy() await tx.wait() diff --git a/packages/ensjs/src/functions/setResolver.ts b/packages/ensjs/src/functions/setResolver.ts index 8c4a2348..6d30479a 100644 --- a/packages/ensjs/src/functions/setResolver.ts +++ b/packages/ensjs/src/functions/setResolver.ts @@ -1,35 +1,28 @@ -import { Signer } from 'ethers' import { ENSArgs } from '..' import { namehash } from '../utils/normalise' export default async function ( - { contracts, provider }: ENSArgs<'contracts' | 'provider'>, + { contracts, signer }: ENSArgs<'contracts' | 'signer'>, name: string, - contract: 'registry' | 'nameWrapper', - resolver?: string, - options?: { addressOrIndex?: string | number; signer?: Signer }, + { + contract, + resolver, + }: { + contract: 'registry' | 'nameWrapper' + resolver?: string + }, ) { - const signer = options?.signer || provider?.getSigner(options?.addressOrIndex) - - if (!signer) { - throw new Error('No signer found') - } - if (!resolver) { resolver = (await contracts?.getPublicResolver()!).address } switch (contract) { case 'registry': { - const registry = (await contracts?.getRegistry())!.connect( - provider?.getSigner(options?.addressOrIndex)!, - ) + const registry = (await contracts?.getRegistry())!.connect(signer) return registry.setResolver(namehash(name), resolver) } case 'nameWrapper': { - const nameWrapper = (await contracts?.getNameWrapper())!.connect( - provider?.getSigner(options?.addressOrIndex)!, - ) + const nameWrapper = (await contracts?.getNameWrapper())!.connect(signer) return nameWrapper.setResolver(namehash(name), resolver) } default: { diff --git a/packages/ensjs/src/functions/transferName.test.ts b/packages/ensjs/src/functions/transferName.test.ts index 306dd05a..7338fd2f 100644 --- a/packages/ensjs/src/functions/transferName.test.ts +++ b/packages/ensjs/src/functions/transferName.test.ts @@ -1,7 +1,7 @@ import { ethers, utils } from 'ethers' import { ENS } from '..' -import { namehash } from '../utils/normalise' import setup from '../tests/setup' +import { namehash } from '../utils/normalise' let ENSInstance: ENS let revert: Awaited>['revert'] @@ -22,12 +22,11 @@ describe('transferName', () => { await revert() }) it('should allow a transfer on the registrar', async () => { - const tx = await ENSInstance.transferName( - 'parthtejpal.eth', - accounts[1], - 'baseRegistrar', - { addressOrIndex: 0 }, - ) + const tx = await ENSInstance.transferName('parthtejpal.eth', { + contract: 'baseRegistrar', + newOwner: accounts[1], + addressOrIndex: 0, + }) expect(tx).toBeTruthy() await tx.wait() @@ -38,17 +37,15 @@ describe('transferName', () => { expect(result).toBe(accounts[1]) }) it('should allow a transfer on the namewrapper', async () => { - const wrapNameTx = await ENSInstance.wrapName( - 'parthtejpal.eth', - accounts[0], - ) + const wrapNameTx = await ENSInstance.wrapName('parthtejpal.eth', { + wrappedOwner: accounts[0], + }) await wrapNameTx.wait() - const tx = await ENSInstance.transferName( - 'parthtejpal.eth', - accounts[1], - 'nameWrapper', - { addressOrIndex: 0 }, - ) + const tx = await ENSInstance.transferName('parthtejpal.eth', { + newOwner: accounts[1], + contract: 'nameWrapper', + addressOrIndex: 0, + }) expect(tx).toBeTruthy() await tx.wait() @@ -57,20 +54,21 @@ describe('transferName', () => { expect(result).toBe(accounts[1]) }) it('should allow a transfer on the registry', async () => { - const createSubnameTx = await ENSInstance.createSubname({ - name: 'test.parthtejpal.eth', - contract: 'registry', - owner: accounts[0], - options: { addressOrIndex: accounts[0] }, - }) - await createSubnameTx.wait() - - const tx = await ENSInstance.transferName( + const createSubnameTx = await ENSInstance.createSubname( 'test.parthtejpal.eth', - accounts[1], - 'registry', - { addressOrIndex: accounts[0] }, + { + contract: 'registry', + owner: accounts[0], + addressOrIndex: accounts[0], + }, ) + await createSubnameTx.wait() + + const tx = await ENSInstance.transferName('test.parthtejpal.eth', { + newOwner: accounts[1], + contract: 'registry', + addressOrIndex: accounts[0], + }) expect(tx).toBeTruthy() await tx.wait() diff --git a/packages/ensjs/src/functions/transferName.ts b/packages/ensjs/src/functions/transferName.ts index 63d52acc..0d7eb79e 100644 --- a/packages/ensjs/src/functions/transferName.ts +++ b/packages/ensjs/src/functions/transferName.ts @@ -1,20 +1,18 @@ -import { ethers, Signer } from 'ethers' +import { ethers } from 'ethers' import { ENSArgs } from '..' import { namehash } from '../utils/normalise' export default async function ( - { contracts, provider }: ENSArgs<'contracts' | 'provider'>, + { contracts, signer }: ENSArgs<'contracts' | 'signer'>, name: string, - newOwner: string, - contract: 'registry' | 'nameWrapper' | 'baseRegistrar', - options?: { addressOrIndex?: string | number; signer?: Signer }, + { + newOwner, + contract, + }: { + newOwner: string + contract: 'registry' | 'nameWrapper' | 'baseRegistrar' + }, ) { - const signer = options?.signer || provider?.getSigner(options?.addressOrIndex) - - if (!signer) { - throw new Error('No signer found') - } - const address = await signer.getAddress() switch (contract) { diff --git a/packages/ensjs/src/functions/transferSubname.test.ts b/packages/ensjs/src/functions/transferSubname.test.ts index 564265f2..96bbe8ef 100644 --- a/packages/ensjs/src/functions/transferSubname.test.ts +++ b/packages/ensjs/src/functions/transferSubname.test.ts @@ -1,7 +1,7 @@ import { ethers } from 'ethers' import { ENS } from '..' -import { namehash } from '../utils/normalise' import setup from '../tests/setup' +import { namehash } from '../utils/normalise' let ENSInstance: ENS let revert: Awaited>['revert'] @@ -22,20 +22,21 @@ describe('transferSubname', () => { await revert() }) it('should allow transferring a subname on the registry', async () => { - const createSubnameTx = await ENSInstance.createSubname({ - contract: 'registry', - name: 'test.parthtejpal.eth', - owner: accounts[0], - options: { addressOrIndex: 0 }, - }) - await createSubnameTx.wait() - - const tx = await ENSInstance.transferSubname( + const createSubnameTx = await ENSInstance.createSubname( 'test.parthtejpal.eth', - 'registry', - accounts[1], - { addressOrIndex: 0 }, + { + contract: 'registry', + owner: accounts[0], + addressOrIndex: 0, + }, ) + await createSubnameTx.wait() + + const tx = await ENSInstance.transferSubname('test.parthtejpal.eth', { + contract: 'registry', + address: accounts[1], + addressOrIndex: 0, + }) expect(tx).toBeTruthy() await tx.wait() @@ -44,25 +45,25 @@ describe('transferSubname', () => { expect(result).toBe(accounts[1]) }) it('should allow transferring a subname on the nameWrapper', async () => { - const wrapNameTx = await ENSInstance.wrapName( - 'parthtejpal.eth', - accounts[0], - ) - await wrapNameTx.wait() - const createSubnameTx = await ENSInstance.createSubname({ - contract: 'nameWrapper', - name: 'test.parthtejpal.eth', - owner: accounts[0], - options: { addressOrIndex: 0 }, + const wrapNameTx = await ENSInstance.wrapName('parthtejpal.eth', { + wrappedOwner: accounts[0], }) - await createSubnameTx.wait() - - const tx = await ENSInstance.transferSubname( + await wrapNameTx.wait() + const createSubnameTx = await ENSInstance.createSubname( 'test.parthtejpal.eth', - 'nameWrapper', - accounts[1], - { addressOrIndex: 0 }, + { + contract: 'nameWrapper', + owner: accounts[0], + addressOrIndex: 0, + }, ) + await createSubnameTx.wait() + + const tx = await ENSInstance.transferSubname('test.parthtejpal.eth', { + contract: 'nameWrapper', + address: accounts[1], + addressOrIndex: 0, + }) expect(tx).toBeTruthy() await tx.wait() diff --git a/packages/ensjs/src/functions/transferSubname.ts b/packages/ensjs/src/functions/transferSubname.ts index dc4f1b4e..7d04c1c7 100644 --- a/packages/ensjs/src/functions/transferSubname.ts +++ b/packages/ensjs/src/functions/transferSubname.ts @@ -1,20 +1,18 @@ -import { ethers, Signer } from 'ethers' +import { ethers } from 'ethers' import { ENSArgs } from '..' import { namehash } from '../utils/normalise' export default async function ( - { contracts, provider }: ENSArgs<'contracts' | 'provider'>, + { contracts, signer }: ENSArgs<'contracts' | 'signer'>, name: string, - contract: 'registry' | 'nameWrapper', - address: string, - options?: { addressOrIndex?: string | number; signer?: Signer }, + { + contract, + address, + }: { + contract: 'registry' | 'nameWrapper' + address: string + }, ) { - const signer = options?.signer || provider?.getSigner(options?.addressOrIndex) - - if (!signer) { - throw new Error('No signer found') - } - const labels = name.split('.') const label = labels.shift() as string const labelhash = ethers.utils.solidityKeccak256(['string'], [label]) diff --git a/packages/ensjs/src/functions/unwrapName.test.ts b/packages/ensjs/src/functions/unwrapName.test.ts index 276efdad..ce40eaa9 100644 --- a/packages/ensjs/src/functions/unwrapName.test.ts +++ b/packages/ensjs/src/functions/unwrapName.test.ts @@ -1,7 +1,7 @@ import { ethers, utils } from 'ethers' import { ENS } from '..' -import { namehash } from '../utils/normalise' import setup from '../tests/setup' +import { namehash } from '../utils/normalise' let ENSInstance: ENS let revert: Awaited>['revert'] @@ -22,17 +22,15 @@ describe('unwrapName', () => { await revert() }) it('should return a .eth unwrap name transaction and succeed', async () => { - const wrapNameTx = await ENSInstance.wrapName( - 'parthtejpal.eth', - accounts[0], - ) + const wrapNameTx = await ENSInstance.wrapName('parthtejpal.eth', { + wrappedOwner: accounts[0], + }) await wrapNameTx.wait() - const tx = await ENSInstance.unwrapName( - 'parthtejpal.eth', - accounts[0], - accounts[0], - ) + const tx = await ENSInstance.unwrapName('parthtejpal.eth', { + newController: accounts[0], + newRegistrant: accounts[0], + }) expect(tx).toBeTruthy() await tx.wait() @@ -43,21 +41,23 @@ describe('unwrapName', () => { expect(result).toBe(accounts[0]) }) it('should return a regular unwrap name transaction and succeed', async () => { - const wrapNameTx = await ENSInstance.wrapName( - 'parthtejpal.eth', - accounts[0], - ) - await wrapNameTx.wait() - const createSubnameTx = await ENSInstance.createSubname({ - contract: 'nameWrapper', - name: 'test.parthtejpal.eth', - owner: accounts[0], - shouldWrap: true, - options: { addressOrIndex: 0 }, + const wrapNameTx = await ENSInstance.wrapName('parthtejpal.eth', { + wrappedOwner: accounts[0], }) + await wrapNameTx.wait() + const createSubnameTx = await ENSInstance.createSubname( + 'test.parthtejpal.eth', + { + contract: 'nameWrapper', + owner: accounts[0], + addressOrIndex: 0, + }, + ) await createSubnameTx.wait() - const tx = await ENSInstance.unwrapName('test.parthtejpal.eth', accounts[0]) + const tx = await ENSInstance.unwrapName('test.parthtejpal.eth', { + newController: accounts[0], + }) expect(tx).toBeTruthy() await tx.wait() diff --git a/packages/ensjs/src/functions/unwrapName.ts b/packages/ensjs/src/functions/unwrapName.ts index 6e544626..2552475c 100644 --- a/packages/ensjs/src/functions/unwrapName.ts +++ b/packages/ensjs/src/functions/unwrapName.ts @@ -1,22 +1,18 @@ -import { Signer, utils } from 'ethers' +import { utils } from 'ethers' import { ENSArgs } from '..' import { namehash } from '../utils/normalise' export default async function ( - { contracts, provider }: ENSArgs<'contracts' | 'provider'>, + { contracts, signer }: ENSArgs<'contracts' | 'signer'>, name: string, - newController: string, - newRegistrant?: string, - options?: { addressOrIndex?: string | number; signer?: Signer }, + { + newController, + newRegistrant, + }: { + newController: string + newRegistrant?: string + }, ) { - const signer = options?.signer || provider?.getSigner(options?.addressOrIndex) - - const address = await signer?.getAddress() - - if (!signer || !address) { - throw new Error('No signer found') - } - const labels = name.split('.') const labelhash = utils.solidityKeccak256(['string'], [labels[0]]) const parentNodehash = namehash(labels.slice(1).join('.')) diff --git a/packages/ensjs/src/functions/wrapName.test.ts b/packages/ensjs/src/functions/wrapName.test.ts index 69184ae3..9291daa5 100644 --- a/packages/ensjs/src/functions/wrapName.test.ts +++ b/packages/ensjs/src/functions/wrapName.test.ts @@ -24,7 +24,9 @@ describe('wrapName', () => { await revert() }) it('should return a wrap name transaction and succeed', async () => { - const tx = await ENSInstance.wrapName('parthtejpal.eth', accounts[0]) + const tx = await ENSInstance.wrapName('parthtejpal.eth', { + wrappedOwner: accounts[0], + }) expect(tx).toBeTruthy() await tx.wait() @@ -33,9 +35,12 @@ describe('wrapName', () => { expect((result as BigNumber).toHexString()).toBe('0x40') }) it('should allow initial fuses', async () => { - const tx = await ENSInstance.wrapName('parthtejpal.eth', accounts[0], { - cannotUnwrap: true, - cannotSetTtl: true, + const tx = await ENSInstance.wrapName('parthtejpal.eth', { + wrappedOwner: accounts[0], + fuseOptions: { + cannotUnwrap: true, + cannotSetTtl: true, + }, }) expect(tx).toBeTruthy() await tx.wait() @@ -45,12 +50,10 @@ describe('wrapName', () => { expect((result as BigNumber).toHexString()).toBe('0x40') }) it('should allow an initial resolver address', async () => { - const tx = await ENSInstance.wrapName( - 'parthtejpal.eth', - accounts[0], - undefined, - '0x42D63ae25990889E35F215bC95884039Ba354115', - ) + const tx = await ENSInstance.wrapName('parthtejpal.eth', { + wrappedOwner: accounts[0], + resolverAddress: '0x42D63ae25990889E35F215bC95884039Ba354115', + }) expect(tx).toBeTruthy() await tx.wait() diff --git a/packages/ensjs/src/functions/wrapName.ts b/packages/ensjs/src/functions/wrapName.ts index 15b5f7fa..3eda6c28 100644 --- a/packages/ensjs/src/functions/wrapName.ts +++ b/packages/ensjs/src/functions/wrapName.ts @@ -1,4 +1,4 @@ -import { ethers, Signer } from 'ethers' +import { ethers } from 'ethers' import { ENSArgs } from '..' import type { FuseOptions } from '../@types/FuseOptions' import generateFuseInput from '../utils/generateFuseInput' @@ -38,8 +38,9 @@ async function wrapOther( decodedFuses: string, resolverAddress: string, address: string, + signer: ethers.Signer, ) { - const nameWrapper = await contracts?.getNameWrapper()! + const nameWrapper = (await contracts?.getNameWrapper()!).connect(signer) const registry = await contracts?.getRegistry()! const hasApproval = await registry.isApprovedForAll( @@ -62,22 +63,18 @@ async function wrapOther( } export default async function ( - { contracts, provider }: ENSArgs<'contracts' | 'provider'>, + { contracts, signer }: ENSArgs<'contracts' | 'signer'>, name: string, - wrappedOwner: string, - fuseOptions?: FuseOptions | string | number, - resolverAddress?: string, - options?: { - signer?: Signer - addressOrIndex?: string | number + { + wrappedOwner, + fuseOptions, + resolverAddress, + }: { + wrappedOwner: string + fuseOptions?: FuseOptions | string | number + resolverAddress?: string }, ) { - const signer = options?.signer || provider?.getSigner(options?.addressOrIndex) - - if (!signer) { - throw new Error('No signer found') - } - const address = await signer.getAddress() let decodedFuses: string @@ -126,6 +123,7 @@ export default async function ( decodedFuses, resolverAddress, address, + signer, ) } } diff --git a/packages/ensjs/src/index.ts b/packages/ensjs/src/index.ts index 29f9777b..a79d4258 100644 --- a/packages/ensjs/src/index.ts +++ b/packages/ensjs/src/index.ts @@ -1,4 +1,4 @@ -import { ethers } from 'ethers' +import { ethers, Signer } from 'ethers' import ContractManager from './contracts' import { getContractAddress as _getContractAddress } from './contracts/getContractAddress' import { SupportedNetworkId } from './contracts/types' @@ -11,6 +11,7 @@ import type { import type burnFuses from './functions/burnFuses' import type createSubname from './functions/createSubname' import type deleteSubname from './functions/deleteSubname' +import type getDNSOwner from './functions/getDNSOwner' import type getExpiry from './functions/getExpiry' import type getFuses from './functions/getFuses' import type { @@ -41,7 +42,6 @@ import type transferName from './functions/transferName' import type transferSubname from './functions/transferSubname' import type unwrapName from './functions/unwrapName' import type wrapName from './functions/wrapName' -import type getDNSOwner from './functions/getDNSOwner' import GqlManager from './GqlManager' import singleCall from './utils/singleCall' @@ -53,6 +53,7 @@ type ENSOptions = { export type InternalENS = { options?: ENSOptions provider?: ethers.providers.Provider + signer: Signer graphURI?: string | null } & ENS @@ -76,6 +77,21 @@ type FirstArg = F extends (x: infer A, ...args: any[]) => any ? A : never type FunctionDeps = Extract, string>[] +type WriteOptions = { + addressOrIndex?: string | number + signer?: Signer +} + +type WriteFunction = 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 + const graphURIEndpoints: Record = { 1: 'https://api.thegraph.com/subgraphs/name/ensdomains/ens', 3: 'https://api.thegraph.com/subgraphs/name/ensdomains/ensropsten', @@ -172,7 +188,7 @@ export class ENS { path: string, dependencies: FunctionDeps, exportName: string = 'default', - subFunc?: 'raw' | 'decode' | 'combine' | 'batch', + subFunc?: 'raw' | 'decode' | 'combine' | 'batch' | 'write', passthrough?: RawFunction, ): Function => { // if batch is specified, create batch func @@ -194,10 +210,29 @@ export class ENS { // otherwise, create a function from the raw and decode functions if (subFunc !== 'combine') { // get the function to call - const func = subFunc ? mod[exportName][subFunc] : mod[exportName] + const func = + subFunc && subFunc !== 'write' + ? mod[exportName][subFunc] + : mod[exportName] // get the dependencies to forward to the function as the first arg - const dependenciesToForward = + let dependenciesToForward = thisRef.forwardDependenciesFromArray(dependencies) + + // if func is write func, inject signer into dependencies + if (subFunc === 'write') { + const options = (args[1] || {}) as WriteOptions + const signer = + options.signer || + thisRef.provider?.getSigner(options.addressOrIndex) + if (!signer) { + throw new Error('No signer specified') + } + delete options.addressOrIndex + delete options.signer + dependenciesToForward = { ...dependenciesToForward, signer } + return func(dependenciesToForward, args[0], options) + } + // return the function with the dependencies forwarded return func(dependenciesToForward, ...args) } else { @@ -256,6 +291,25 @@ export class ENS { ): OmitFirstArg => this.importGenerator(path, dependencies, exportName) as OmitFirstArg + /** + * Generates a write wrapped function + * @param {string} path - The path of the exported function + * @param {FunctionDeps} dependencies - An array of ENS properties + * @param {string} exportName - The export name of the target function + * @returns {OmitFirstArg} - The generated wrapped function + */ + private generateWriteFunction = ( + path: string, + dependencies: FunctionDeps, + exportName: string = 'default', + ): WriteFunction => + this.importGenerator( + path, + dependencies, + exportName, + 'write', + ) as WriteFunction + /** * Generates a wrapped function from raw and decode exports * @param {string} path - The path of the exported function @@ -455,55 +509,51 @@ export class ENS { 'multicallWrapper', ) - public setName = this.generateFunction('setName', [ + public setName = this.generateWriteFunction('setName', [ 'contracts', - 'provider', ]) - public setRecords = this.generateFunction('setRecords', [ - 'contracts', - 'provider', - 'getResolver', - ]) + public setRecords = this.generateWriteFunction( + 'setRecords', + ['contracts', 'provider', 'getResolver'], + ) - public setResolver = this.generateFunction( + public setResolver = this.generateWriteFunction( 'setResolver', - ['contracts', 'provider'], + ['contracts'], ) - public transferName = this.generateFunction( + public transferName = this.generateWriteFunction( 'transferName', - ['contracts', 'provider'], + ['contracts'], ) - public wrapName = this.generateFunction('wrapName', [ + public wrapName = this.generateWriteFunction('wrapName', [ 'contracts', - 'provider', ]) - public unwrapName = this.generateFunction('unwrapName', [ - 'contracts', - 'provider', - ]) + public unwrapName = this.generateWriteFunction( + 'unwrapName', + ['contracts'], + ) - public burnFuses = this.generateFunction('burnFuses', [ + public burnFuses = this.generateWriteFunction('burnFuses', [ 'contracts', - 'provider', ]) - public createSubname = this.generateFunction( + public createSubname = this.generateWriteFunction( 'createSubname', - ['contracts', 'provider'], + ['contracts'], ) - public deleteSubname = this.generateFunction( + public deleteSubname = this.generateWriteFunction( 'deleteSubname', - ['contracts', 'provider', 'transferSubname'], + ['transferSubname'], ) - public transferSubname = this.generateFunction( + public transferSubname = this.generateWriteFunction( 'transferSubname', - ['contracts', 'provider'], + ['contracts'], ) public getDNSOwner = this.generateFunction( diff --git a/packages/ensjs/src/tests/signerInjection.test.ts b/packages/ensjs/src/tests/signerInjection.test.ts new file mode 100644 index 00000000..38bec31c --- /dev/null +++ b/packages/ensjs/src/tests/signerInjection.test.ts @@ -0,0 +1,42 @@ +import { ethers } from 'ethers' +import { ENS } from '..' +import setup from '../tests/setup' + +let ENSInstance: ENS +let revert: Awaited>['revert'] +let provider: ethers.providers.JsonRpcProvider +let accounts: string[] + +beforeAll(async () => { + ;({ ENSInstance, revert, provider } = await setup()) + accounts = await provider.listAccounts() +}) + +afterAll(async () => { + await revert() +}) + +jest.setTimeout(20000) + +describe('Signer Injection', () => { + beforeEach(async () => { + await revert() + }) + it('should return a transaction successfully for a custom signer', async () => { + const signer = provider.getSigner(accounts[3]) + const tx = await ENSInstance.setName('fleek.eth', { signer }) + expect(tx).toBeTruthy() + if (tx) { + await tx.wait() + expect(tx.from).toBe(accounts[3]) + } + }) + it('should return a transaction succesfully for a custom signer index', async () => { + const tx = await ENSInstance.setName('fleek.eth', { addressOrIndex: 3 }) + expect(tx).toBeTruthy() + if (tx) { + await tx.wait() + expect(tx.from).toBe(accounts[3]) + } + }) +}) diff --git a/packages/ensjs/tsconfig.cjs.json b/packages/ensjs/tsconfig.cjs.json index 109a268e..c29e106d 100644 --- a/packages/ensjs/tsconfig.cjs.json +++ b/packages/ensjs/tsconfig.cjs.json @@ -8,4 +8,5 @@ "declaration": true }, "include": ["./src"], + "exclude": ["src/**/*.test.ts", "src/tests/**/*"] } diff --git a/packages/ensjs/tsconfig.esm.json b/packages/ensjs/tsconfig.esm.json index 9bac713f..28b34d10 100644 --- a/packages/ensjs/tsconfig.esm.json +++ b/packages/ensjs/tsconfig.esm.json @@ -7,4 +7,5 @@ "declaration": true }, "include": ["./src"], + "exclude": ["src/**/*.test.ts", "src/tests/**/*"] } diff --git a/packages/ensjs/tsconfig.json b/packages/ensjs/tsconfig.json index 154b1bd5..f27c6faf 100644 --- a/packages/ensjs/tsconfig.json +++ b/packages/ensjs/tsconfig.json @@ -15,5 +15,5 @@ "importsNotUsedAsValues": "remove", "lib": ["ES2021", "DOM"] }, - "exclude": ["src/**/*.test.ts", "**/tests"] + "include": ["src/**/*.ts"] }