Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: introduce safeNamehash #2925

Merged
merged 3 commits into from
Dec 3, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 5 additions & 9 deletions src/hooks/useENSAddress.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { namehash } from '@ethersproject/hash'
import { useMemo } from 'react'
import { safeNamehash } from 'utils/safeNamehash'

import { useSingleCallResult } from '../state/multicall/hooks'
import isZero from '../utils/isZero'
Expand All @@ -11,14 +11,10 @@ import useDebounce from './useDebounce'
*/
export default function useENSAddress(ensName?: string | null): { loading: boolean; address: string | null } {
const debouncedName = useDebounce(ensName, 200)
const ensNodeArgument = useMemo(() => {
if (!debouncedName) return [undefined]
try {
return debouncedName ? [namehash(debouncedName)] : [undefined]
} catch (error) {
return [undefined]
}
}, [debouncedName])
const ensNodeArgument = useMemo(
() => [debouncedName === null ? undefined : safeNamehash(debouncedName)],
[debouncedName]
)
const registrarContract = useENSRegistrarContract(false)
const resolverAddress = useSingleCallResult(registrarContract, 'resolver', ensNodeArgument)
const resolverAddressResult = resolverAddress.result?.[0]
Expand Down
10 changes: 4 additions & 6 deletions src/hooks/useENSAvatar.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { namehash } from '@ethersproject/hash'
import { useEffect, useMemo, useState } from 'react'
import { safeNamehash } from 'utils/safeNamehash'
import uriToHttp from 'utils/uriToHttp'

import { useSingleCallResult } from '../state/multicall/hooks'
Expand All @@ -21,15 +22,12 @@ export default function useENSAvatar(
const debouncedAddress = useDebounce(address, 200)
const node = useMemo(() => {
if (!debouncedAddress || !isAddress(debouncedAddress)) return undefined
try {
return debouncedAddress ? namehash(`${debouncedAddress.toLowerCase().substr(2)}.addr.reverse`) : undefined
} catch (error) {
return undefined
}
return namehash(`${debouncedAddress.toLowerCase().substr(2)}.addr.reverse`)
}, [debouncedAddress])

const addressAvatar = useAvatarFromNode(node)
const nameAvatar = useAvatarFromNode(namehash(useENSName(address).ENSName ?? ''))
const ENSName = useENSName(address).ENSName
const nameAvatar = useAvatarFromNode(ENSName === null ? undefined : safeNamehash(ENSName))
let avatar = addressAvatar.avatar || nameAvatar.avatar

const nftAvatar = useAvatarFromNFT(avatar, enforceOwnership)
Expand Down
11 changes: 2 additions & 9 deletions src/hooks/useENSContentHash.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { namehash } from '@ethersproject/hash'
import { useMemo } from 'react'
import { safeNamehash } from 'utils/safeNamehash'

import { useSingleCallResult } from '../state/multicall/hooks'
import isZero from '../utils/isZero'
Expand All @@ -9,14 +9,7 @@ import { useENSRegistrarContract, useENSResolverContract } from './useContract'
* Does a lookup for an ENS name to find its contenthash.
*/
export default function useENSContentHash(ensName?: string | null): { loading: boolean; contenthash: string | null } {
const ensNodeArgument = useMemo(() => {
if (!ensName) return [undefined]
try {
return ensName ? [namehash(ensName)] : [undefined]
} catch (error) {
return [undefined]
}
}, [ensName])
const ensNodeArgument = useMemo(() => [ensName === null ? undefined : safeNamehash(ensName)], [ensName])
const registrarContract = useENSRegistrarContract(false)
const resolverAddressResult = useSingleCallResult(registrarContract, 'resolver', ensNodeArgument)
const resolverAddress = resolverAddressResult.result?.[0]
Expand Down
6 changes: 1 addition & 5 deletions src/hooks/useENSName.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,7 @@ export default function useENSName(address?: string): { ENSName: string | null;
const debouncedAddress = useDebounce(address, 200)
const ensNodeArgument = useMemo(() => {
if (!debouncedAddress || !isAddress(debouncedAddress)) return [undefined]
try {
return debouncedAddress ? [namehash(`${debouncedAddress.toLowerCase().substr(2)}.addr.reverse`)] : [undefined]
} catch (error) {
return [undefined]
}
return [namehash(`${debouncedAddress.toLowerCase().substr(2)}.addr.reverse`)]
}, [debouncedAddress])
const registrarContract = useENSRegistrarContract(false)
const resolverAddress = useSingleCallResult(registrarContract, 'resolver', ensNodeArgument)
Expand Down
21 changes: 21 additions & 0 deletions src/utils/safeNamehash.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { namehash } from '@ethersproject/hash'

import { safeNamehash } from './safeNamehash'

describe('#safeNamehash', () => {
const emoji = '🤔'

it('#namehash fails', () => {
expect(() => namehash(emoji)).toThrow('STRINGPREP_CONTAINS_UNASSIGNED')
})

// suppress console.debug for the next test
beforeEach(() => {
// eslint-disable-next-line @typescript-eslint/no-empty-function
jest.spyOn(console, 'debug').mockImplementation(() => {})
})

it('works', () => {
expect(safeNamehash(emoji)).toEqual(undefined)
})
})
12 changes: 12 additions & 0 deletions src/utils/safeNamehash.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { namehash } from '@ethersproject/hash'

export function safeNamehash(name?: string): string | undefined {
if (name === undefined) return undefined

try {
return namehash(name)
NoahZinsmeister marked this conversation as resolved.
Show resolved Hide resolved
} catch (error) {
console.debug(error)
return undefined
}
}