Skip to content

Commit

Permalink
Merge pull request #111 from ensdomains/fet896-update-ensjs-for-pcc-b…
Browse files Browse the repository at this point in the history
…urned

update deleteSubname and transferSubname
  • Loading branch information
storywithoutend authored Feb 10, 2023
2 parents 608f7c9 + e9a2ef8 commit 81013d1
Show file tree
Hide file tree
Showing 11 changed files with 1,515 additions and 383 deletions.
9 changes: 7 additions & 2 deletions packages/ensjs/deploy/00_register_wrapped.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { HardhatRuntimeEnvironment } from 'hardhat/types'
import { encodeFuses } from '../src/utils/fuses'
import { namehash } from '../src/utils/normalise'

const names: {
export const names: {
label: string
namedOwner: string
data?: any[]
Expand All @@ -29,7 +29,12 @@ const names: {
{
label: 'wrapped-with-subnames',
namedOwner: 'owner',
subnames: [{ label: 'test', namedOwner: 'owner2' }],
subnames: [
{ label: 'test', namedOwner: 'owner2' },
{ label: 'legacy', namedOwner: 'owner2' },
{ label: 'xyz', namedOwner: 'owner2' },
{ label: 'addr', namedOwner: 'owner2' },
],
},
{
label: 'expired-wrapped',
Expand Down
145 changes: 139 additions & 6 deletions packages/ensjs/src/functions/deleteSubname.test.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,20 @@
import { ethers } from 'ethers'
import { ENS } from '..'
import setup from '../tests/setup'
import { namehash } from '../utils/normalise'

let ensInstance: ENS
let revert: Awaited<ReturnType<typeof setup>>['revert']
let provider: ethers.providers.JsonRpcProvider
let accounts: string[]

beforeAll(async () => {
;({ ensInstance, revert } = await setup())
;({ ensInstance, revert, provider } = await setup())
accounts = await provider.listAccounts()
})

beforeEach(async () => {
await revert()
})

afterAll(async () => {
Expand All @@ -17,27 +25,34 @@ describe('deleteSubname', () => {
beforeEach(async () => {
await revert()
})
it('should allow deleting a subname on the registry', async () => {
it('should allow deleting a subname on the registry by parent owner', async () => {
const registry = await ensInstance.contracts!.getRegistry()!
const parentOwner = await registry.owner(namehash('with-subnames.eth'))

const tx = await ensInstance.deleteSubname('test.with-subnames.eth', {
contract: 'registry',
addressOrIndex: 1,
addressOrIndex: parentOwner,
})
expect(tx).toBeTruthy()
await tx.wait()

const registry = await ensInstance.contracts!.getRegistry()!
const result = await registry.owner(namehash('test.with-subnames.eth'))
expect(result).toBe('0x0000000000000000000000000000000000000000')
})

it('should allow deleting a subname on the nameWrapper', async () => {
it('should allow deleting a subname on the nameWrapper by parent owner', async () => {
const nameWrapper = await ensInstance.contracts!.getNameWrapper()!

const parentOwner = await nameWrapper.ownerOf(
namehash('wrapped-with-subnames.eth'),
)

const tx = await ensInstance.deleteSubname(
'test.wrapped-with-subnames.eth',
{
contract: 'nameWrapper',
addressOrIndex: 1,
method: 'setSubnodeOwner',
addressOrIndex: parentOwner,
},
)
expect(tx).toBeTruthy()
Expand All @@ -49,10 +64,128 @@ describe('deleteSubname', () => {
expect(result).toBe('0x0000000000000000000000000000000000000000')
})

it('should allow deleting a subname on the nameWrapper by name owner', async () => {
const nameWrapper = await ensInstance.contracts!.getNameWrapper()!

const nameOwner = await nameWrapper.ownerOf(
namehash('addr.wrapped-with-subnames.eth'),
)

await ensInstance.deleteSubname('addr.wrapped-with-subnames.eth', {
contract: 'nameWrapper',
method: 'setRecord',
addressOrIndex: nameOwner,
})

const result = await nameWrapper.ownerOf(
namehash('addr.wrapped-with-subnames.eth'),
)
expect(result).toBe('0x0000000000000000000000000000000000000000')
})

it('should allow deleting a subname on the nameWrapper with PCC burned by name owner', async () => {
const nameWrapper = await ensInstance.contracts!.getNameWrapper()!

const parentOwner = await nameWrapper.ownerOf(
namehash('wrapped-with-subnames.eth'),
)

const tx0 = await ensInstance.setFuses('wrapped-with-subnames.eth', {
named: ['CANNOT_UNWRAP'],
addressOrIndex: parentOwner,
})
expect(tx0).toBeTruthy()
await tx0.wait()

const tx1 = await ensInstance.setChildFuses(
'xyz.wrapped-with-subnames.eth',
{
fuses: {
parent: {
named: ['PARENT_CANNOT_CONTROL'],
},
},
addressOrIndex: parentOwner,
},
)
expect(tx1).toBeTruthy()
await tx1.wait()

const nameOwner = await nameWrapper.ownerOf(
namehash('xyz.wrapped-with-subnames.eth'),
)

expect(parentOwner === nameOwner).toBe(false)

const tx = await ensInstance.deleteSubname(
'xyz.wrapped-with-subnames.eth',
{
contract: 'nameWrapper',
method: 'setRecord',
addressOrIndex: nameOwner,
},
)
expect(tx).toBeTruthy()
await tx.wait()

const result = await nameWrapper.ownerOf(
namehash('xyz.wrapped-with-subnames.eth'),
)
expect(result).toBe('0x0000000000000000000000000000000000000000')
})

it('should NOT allow deleting a subname on the nameWrapper with PCC burned by parent owner', async () => {
const nameWrapper = await ensInstance.contracts!.getNameWrapper()!

const parentOwner = await nameWrapper.ownerOf(
namehash('wrapped-with-subnames.eth'),
)

const tx0 = await ensInstance.setFuses('wrapped-with-subnames.eth', {
named: ['CANNOT_UNWRAP'],
addressOrIndex: parentOwner,
})
expect(tx0).toBeTruthy()
await tx0.wait()

const tx1 = await ensInstance.setChildFuses(
'legacy.wrapped-with-subnames.eth',
{
fuses: {
parent: {
named: ['PARENT_CANNOT_CONTROL'],
},
},
addressOrIndex: parentOwner,
},
)
expect(tx1).toBeTruthy()
await tx1.wait()

const checkOwner = await nameWrapper.ownerOf(
namehash('legacy.wrapped-with-subnames.eth'),
)
expect(checkOwner).toBe(accounts[2])

await expect(
ensInstance.deleteSubname('legacy.wrapped-with-subnames.eth', {
contract: 'nameWrapper',
method: 'setSubnodeOwner',
addressOrIndex: parentOwner,
}),
).rejects.toThrow()

const result = await nameWrapper.ownerOf(
namehash('legacy.wrapped-with-subnames.eth'),
)
expect(result).toBe(accounts[2])
})

it('should not allow deleting 1LD', async () => {
await expect(
ensInstance.deleteSubname('eth', {
contract: 'nameWrapper',
method: 'setRecord',
addressOrIndex: 1,
}),
).rejects.toThrow()
Expand Down
39 changes: 28 additions & 11 deletions packages/ensjs/src/functions/deleteSubname.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,28 +2,34 @@ import { keccak256 as solidityKeccak256 } from '@ethersproject/solidity'
import { ENSArgs } from '..'
import { namehash } from '../utils/normalise'

type Args = {
type BaseArgs = {
contract: 'registry' | 'nameWrapper'
method?: 'setRecord' | 'setSubnodeOwner'
}

type NameWrapperArgs = {
contract: 'nameWrapper'
method: 'setRecord' | 'setSubnodeOwner'
}

type Args = BaseArgs | NameWrapperArgs

export default async function (
{ contracts, signer }: ENSArgs<'contracts' | 'signer' | 'getExpiry'>,
{ contracts, signer }: ENSArgs<'contracts' | 'signer'>,
name: string,
{ contract }: Args,
{ contract, ...args }: Args,
) {
const labels = name.split('.')

if (labels.length < 3) {
throw new Error(`${name} is not a valid subname`)
}

const label = labels.shift() as string
const labelhash = solidityKeccak256(['string'], [label])
const parentNodehash = namehash(labels.join('.'))

switch (contract) {
case 'registry': {
const registry = (await contracts!.getRegistry()!).connect(signer)
const label = labels.shift() as string
const labelhash = solidityKeccak256(['string'], [label])
const parentNodehash = namehash(labels.join('.'))

return registry.populateTransaction.setSubnodeRecord(
parentNodehash,
Expand All @@ -35,13 +41,24 @@ export default async function (
}
case 'nameWrapper': {
const nameWrapper = (await contracts!.getNameWrapper()!).connect(signer)
const { method } = args as NameWrapperArgs

if (method === 'setRecord') {
const node = namehash(name)
return nameWrapper.populateTransaction.setRecord(
node,
'0x0000000000000000000000000000000000000000',
'0x0000000000000000000000000000000000000000',
0,
)
}

return nameWrapper.populateTransaction.setSubnodeRecord(
const label = labels.shift() as string
const parentNodehash = namehash(labels.join('.'))
return nameWrapper.populateTransaction.setSubnodeOwner(
parentNodehash,
label,
'0x0000000000000000000000000000000000000000',
'0x0000000000000000000000000000000000000000',
0,
0,
0,
)
Expand Down
12 changes: 11 additions & 1 deletion packages/ensjs/src/functions/getNames.test.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { ENS } from '..'
import setup from '../tests/setup'
import { Name } from './getNames'
import { names as wrappedNames } from '../../deploy/00_register_wrapped'

let ensInstance: ENS

Expand Down Expand Up @@ -172,10 +173,19 @@ describe('getNames', () => {
type: 'wrappedOwner',
page: 0,
})

const nameCout = wrappedNames.reduce<number>((count, name) => {
if (name.namedOwner === 'owner2') count += 1
;(name.subnames || []).forEach((subname: any) => {
if (subname.namedOwner === 'owner2') count += 1
})
return count
}, 0)

// length of page one should be all the names on 0x3C44CdDdB6a900fa2b585dd299e03d12FA4293BC
// minus 1 for the PCC expired name.
// the result here implies that the PCC expired name is not returned
expect(pageOne).toHaveLength(4)
expect(pageOne).toHaveLength(nameCout - 1)
})
describe('orderBy', () => {
describe('registrations', () => {
Expand Down
Loading

0 comments on commit 81013d1

Please sign in to comment.