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

Feat: custom ENS lookup for Sepolia #2894

Merged
merged 3 commits into from
Nov 28, 2023
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
6 changes: 6 additions & 0 deletions src/services/ens/config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
/**
* @see https://docs.ens.domains/ens-deployments
*/
export const CUSTOM_REGISTRIES: Record<string, string> = {
'11155111': '0x00000000000C2E074eC69A0dFb2997BA6C7d2e1e', // ENS on Sepolia
}
25 changes: 25 additions & 0 deletions src/services/ens/custom.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import { type JsonRpcProvider } from '@ethersproject/providers'
import { Contract, utils, constants } from 'ethers'

// ENS Registry ABI (simplified version)
const ensRegistryAbi = ['function resolver(bytes32 node) external view returns (address)']
const resolverAbi = ['function addr(bytes32 node) external view returns (address)']

export const customResolveName = async (
registryAddress: string,
rpcProvider: JsonRpcProvider,
name: string,
): Promise<string | undefined> => {
const ensRegistry = new Contract(registryAddress, ensRegistryAbi, rpcProvider)
const namehash = utils.namehash(name)
const resolverAddress = await ensRegistry.resolver(namehash)

if (resolverAddress === constants.AddressZero) {
return undefined
}

const resolver = new Contract(resolverAddress, resolverAbi, rpcProvider)
const address = await resolver.addr(namehash)

return address || undefined
}
Original file line number Diff line number Diff line change
@@ -1,23 +1,29 @@
import { type JsonRpcProvider } from '@ethersproject/providers'
import { resolveName, lookupAddress, isDomain } from '../ens'
import { resolveName, lookupAddress, isDomain } from '.'
import { logError } from '../exceptions'

// mock rpcProvider
const rpcProvider = {
resolveName: jest.fn(() => Promise.resolve('0x0000000000000000000000000000000000000000')),
lookupAddress: jest.fn(() => Promise.resolve('safe.eth')),
getNetwork: jest.fn(() => Promise.resolve({ chainId: 1 })),
} as unknown as JsonRpcProvider

const badRpcProvider = {
resolveName: jest.fn(() => Promise.reject(new Error('bad resolveName'))),
lookupAddress: jest.fn(() => Promise.reject(new Error('bad lookupAddress'))),
getNetwork: jest.fn(() => Promise.resolve({ chainId: 1 })),
} as unknown as JsonRpcProvider

// mock logError
jest.mock('../exceptions', () => ({
logError: jest.fn(),
}))

jest.mock('./custom', () => ({
customResolveName: jest.fn(() => Promise.resolve('0x0000001111111111111111111111111111111111')),
}))

describe('domains', () => {
describe('isDomain', () => {
it('should check the domain format', async () => {
Expand All @@ -39,6 +45,15 @@ describe('domains', () => {
expect(address).toBe(undefined)
expect(logError).toHaveBeenCalledWith('101: Failed to resolve the address', 'bad resolveName')
})

it('should look up names on Sepolia', async () => {
// mock rpcProvider
const rpcProvider = {
getNetwork: jest.fn(() => Promise.resolve({ chainId: 11155111 })),
} as unknown as JsonRpcProvider

expect(await resolveName(rpcProvider, 'sepolia.eth')).toBe('0x0000001111111111111111111111111111111111')
})
})

describe('lookupAddress', () => {
Expand Down
17 changes: 15 additions & 2 deletions src/services/ens.ts → src/services/ens/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import { type JsonRpcProvider } from '@ethersproject/providers'
import { logError } from './exceptions'
import ErrorCodes from './exceptions/ErrorCodes'
import { logError } from '../exceptions'
import ErrorCodes from '../exceptions/ErrorCodes'
import { CUSTOM_REGISTRIES } from './config'
import { customResolveName } from './custom'

type EthersError = Error & {
reason?: string
Expand All @@ -14,7 +16,18 @@ export function isDomain(domain: string): boolean {
}

export const resolveName = async (rpcProvider: JsonRpcProvider, name: string): Promise<string | undefined> => {
let chainId = ''
try {
chainId = (await rpcProvider.getNetwork()).chainId.toString()
} catch {}

try {
// Try custom resolvers first
if (chainId && CUSTOM_REGISTRIES[chainId]) {
return await customResolveName(CUSTOM_REGISTRIES[chainId], rpcProvider, name)
}

// The default ENS resolver
return (await rpcProvider.resolveName(name)) || undefined
} catch (e) {
const err = e as EthersError
Expand Down
Loading