-
-
Notifications
You must be signed in to change notification settings - Fork 821
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
15 changed files
with
239 additions
and
129 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
import { expect, test } from 'vitest' | ||
|
||
import { publicClient } from '../../_test' | ||
import { getEnsAddress } from './getEnsAddress' | ||
|
||
test('gets address for name', async () => { | ||
await expect( | ||
getEnsAddress(publicClient, { | ||
name: 'awkweb.eth', | ||
universalResolverAddress: '0x74E20Bd2A1fE0cdbe45b9A1d89cb7e0a45b36376', | ||
}), | ||
).resolves.toMatchInlineSnapshot( | ||
'"0xA0Cf798816D4b9b9866b5330EEa46a18382f251e"', | ||
) | ||
}) | ||
|
||
test('gets address for name', async () => { | ||
await expect( | ||
getEnsAddress(publicClient, { | ||
name: 'awkweb.eth', | ||
universalResolverAddress: '0x74E20Bd2A1fE0cdbe45b9A1d89cb7e0a45b36376', | ||
}), | ||
).resolves.toMatchInlineSnapshot( | ||
'"0xA0Cf798816D4b9b9866b5330EEa46a18382f251e"', | ||
) | ||
}) | ||
|
||
test('name without address', async () => { | ||
await expect( | ||
getEnsAddress(publicClient, { | ||
name: 'unregistered-name.eth', | ||
universalResolverAddress: '0x74E20Bd2A1fE0cdbe45b9A1d89cb7e0a45b36376', | ||
}), | ||
).resolves.toMatchInlineSnapshot( | ||
'"0x0000000000000000000000000000000000000000"', | ||
) | ||
}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,65 +1,82 @@ | ||
import { PublicClient } from '../../clients' | ||
import type { Address } from '../../types' | ||
import { readContract } from '../public' | ||
import type { Address, Hex, Prettify } from '../../types' | ||
import { decodeFunctionResult, encodeFunctionData } from '../../utils' | ||
import { namehash, packetToBuffer } from '../../utils/ens' | ||
import { readContract, ReadContractArgs } from '../public' | ||
|
||
export type GetEnsNameArgs = { | ||
/** Address to get ENS name for. */ | ||
address: Address | ||
// TODO: Add block number, etc. | ||
} | ||
export type GetEnsAddressArgs = Prettify< | ||
Pick<ReadContractArgs, 'blockNumber' | 'blockTag'> & { | ||
/** ENS name to get address. */ | ||
name: string | ||
/** Address of ENS Universal Resolver Contract */ | ||
universalResolverAddress: Address | ||
} | ||
> | ||
|
||
/** | ||
* @description Gets primary name for specified address. | ||
* @description Gets address for ENS name. | ||
* | ||
* - Calls `resolve(bytes, bytes)` on ENS Universal Resolver Contract. | ||
* | ||
* @example | ||
* const ensAddress = await getEnsAddress(publicClient, { | ||
* name: 'wagmi-dev.eth', | ||
* universalResolverAddress: '0x74E20Bd2A1fE0cdbe45b9A1d89cb7e0a45b36376', | ||
* }) | ||
* console.log(ensAddress) // '0xd2135CfB216b74109775236E36d4b433F1DF507B' | ||
*/ | ||
export async function getEnsName( | ||
export async function getEnsAddress( | ||
client: PublicClient, | ||
{ address }: GetEnsNameArgs, | ||
{ blockNumber, blockTag, name, universalResolverAddress }: GetEnsAddressArgs, | ||
) { | ||
const abi = [ | ||
{ | ||
name: 'reverse', | ||
type: 'function', | ||
stateMutability: 'view', | ||
inputs: [{ type: 'bytes', name: 'reverseName' }], | ||
outputs: [ | ||
{ type: 'string', name: 'resolvedName' }, | ||
{ type: 'address', name: 'resolvedAddress' }, | ||
{ type: 'address', name: 'reverseResolver' }, | ||
{ type: 'address', name: 'resolver' }, | ||
], | ||
}, | ||
] as const | ||
const reverseNode = `${address.toLowerCase().substring(2)}.addr.reverse` | ||
const res = await readContract(client, { | ||
abi, | ||
address: '0x74E20Bd2A1fE0cdbe45b9A1d89cb7e0a45b36376', | ||
functionName: 'reverse', | ||
args: [`0x${encode(reverseNode).toString('hex')}`], | ||
address: universalResolverAddress, | ||
abi: [ | ||
{ | ||
name: 'resolve', | ||
type: 'function', | ||
stateMutability: 'view', | ||
inputs: [ | ||
{ name: 'name', type: 'bytes' }, | ||
{ name: 'data', type: 'bytes' }, | ||
], | ||
outputs: [ | ||
{ name: '', type: 'bytes' }, | ||
{ name: 'address', type: 'address' }, | ||
], | ||
}, | ||
], | ||
functionName: 'resolve', | ||
args: [ | ||
`0x${packetToBuffer(name).toString('hex')}`, | ||
encodeFunctionData({ | ||
abi: [ | ||
{ | ||
name: 'addr', | ||
type: 'function', | ||
stateMutability: 'view', | ||
inputs: [{ name: 'name', type: 'bytes32' }], | ||
outputs: [], | ||
}, | ||
], | ||
functionName: 'addr', | ||
args: [namehash(name)], | ||
}), | ||
], | ||
blockNumber, | ||
blockTag, | ||
}) | ||
return decodeFunctionResult({ | ||
abi: [ | ||
{ | ||
name: 'addr', | ||
type: 'function', | ||
stateMutability: 'view', | ||
inputs: [], | ||
outputs: [{ name: 'name', type: 'address' }], | ||
}, | ||
], | ||
functionName: 'addr', | ||
data: res[0], | ||
}) | ||
return res[0] | ||
} | ||
|
||
// adapted from https://github.com/mafintosh/dns-packet | ||
function encode(str: string) { | ||
function encodingLength(n: string) { | ||
if (n === '.' || n === '..') return 1 | ||
return Buffer.byteLength(n.replace(/^\.|\.$/gm, '')) + 2 | ||
} | ||
|
||
const buf = Buffer.alloc(encodingLength(str)) | ||
let offset = 0 | ||
|
||
// strip leading and trailing . | ||
const n = str.replace(/^\.|\.$/gm, '') | ||
if (n.length) { | ||
const list = n.split('.') | ||
|
||
for (let i = 0; i < list.length; i++) { | ||
const len = buf.write(list[i], offset + 1) | ||
buf[offset] = len | ||
offset += len + 1 | ||
} | ||
} | ||
|
||
return buf | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,28 +1,32 @@ | ||
import { expect, test } from 'vitest' | ||
|
||
import { publicClient } from '../../_test' | ||
import { address, publicClient } from '../../_test' | ||
|
||
import { getEnsName } from './getEnsName' | ||
|
||
test('default', async () => { | ||
test('gets primary name for address', async () => { | ||
await expect( | ||
getEnsName(publicClient, { | ||
address: '0xA0Cf798816D4b9b9866b5330EEa46a18382f251e', | ||
universalResolverAddress: '0x74E20Bd2A1fE0cdbe45b9A1d89cb7e0a45b36376', | ||
}), | ||
).resolves.toMatchInlineSnapshot('"awkweb.eth"') | ||
}) | ||
|
||
// await expect( | ||
// getEnsName(publicClient, { | ||
// address: '0x5FE6C3F8d12D5Ad1480F6DC01D8c7864Aa58C523', | ||
// }), | ||
// ).rejects.toThrowErrorMatchingInlineSnapshot(` | ||
// "execution reverted | ||
|
||
// Contract: 0x0000000000000000000000000000000000000000 | ||
// Function: reverse(bytes address) | ||
// Arguments: (0x28356665366333663864313264356164313438306636646330316438633738363461613538633532330461646472077265766572736500) | ||
test('address with no primary name', async () => { | ||
await expect( | ||
getEnsName(publicClient, { | ||
address: address.burn, | ||
universalResolverAddress: '0x74E20Bd2A1fE0cdbe45b9A1d89cb7e0a45b36376', | ||
}), | ||
).resolves.toMatchInlineSnapshot('null') | ||
}) | ||
|
||
// Details: execution reverted | ||
// Version: [email protected]" | ||
// `) | ||
test('invalid universal resolver address', async () => { | ||
await expect( | ||
getEnsName(publicClient, { | ||
address: '0xA0Cf798816D4b9b9866b5330EEa46a18382f251e', | ||
universalResolverAddress: '0x00000000000C2E074eC69A0dFb2997BA6C7d2e1e', | ||
}), | ||
).resolves.toMatchInlineSnapshot('null') | ||
}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,65 +1,58 @@ | ||
import { PublicClient } from '../../clients' | ||
import type { Address } from '../../types' | ||
import { readContract } from '../public' | ||
import type { Address, Prettify } from '../../types' | ||
import { packetToBuffer } from '../../utils/ens' | ||
import { readContract, ReadContractArgs } from '../public' | ||
|
||
export type GetEnsNameArgs = { | ||
/** Address to get ENS name for. */ | ||
address: Address | ||
/** Universal Resolver address */ | ||
universalResolverAddress: Address | ||
// TODO: Add block number, etc. | ||
} | ||
export type GetEnsNameArgs = Prettify< | ||
Pick<ReadContractArgs, 'blockNumber' | 'blockTag'> & { | ||
/** Address to get ENS name for. */ | ||
address: Address | ||
/** Address of ENS Universal Resolver Contract */ | ||
universalResolverAddress: Address | ||
} | ||
> | ||
|
||
/** | ||
* @description Gets primary name for specified address. | ||
* | ||
* - Calls `reverse(bytes)` on ENS Universal Resolver Contract. | ||
* | ||
* @example | ||
* const ensName = await getEnsName(publicClient, { | ||
* address: '0xd2135CfB216b74109775236E36d4b433F1DF507B', | ||
* universalResolverAddress: '0x74E20Bd2A1fE0cdbe45b9A1d89cb7e0a45b36376', | ||
* }) | ||
* console.log(ensName) // 'wagmi-dev.eth' | ||
*/ | ||
export async function getEnsName( | ||
client: PublicClient, | ||
{ address }: GetEnsNameArgs, | ||
{ address, blockNumber, blockTag, universalResolverAddress }: GetEnsNameArgs, | ||
) { | ||
const abi = [ | ||
{ | ||
name: 'reverse', | ||
type: 'function', | ||
stateMutability: 'view', | ||
inputs: [{ type: 'bytes', name: 'reverseName' }], | ||
outputs: [ | ||
{ type: 'string', name: 'resolvedName' }, | ||
{ type: 'address', name: 'resolvedAddress' }, | ||
{ type: 'address', name: 'reverseResolver' }, | ||
{ type: 'address', name: 'resolver' }, | ||
], | ||
}, | ||
] as const | ||
const reverseNode = `${address.toLowerCase().substring(2)}.addr.reverse` | ||
const res = await readContract(client, { | ||
abi, | ||
address: '0x74E20Bd2A1fE0cdbe45b9A1d89cb7e0a45b36376', | ||
functionName: 'reverse', | ||
args: [`0x${encode(reverseNode).toString('hex')}`], | ||
}) | ||
return res[0] | ||
} | ||
|
||
// Adapted from https://github.com/mafintosh/dns-packet | ||
function encode(packet: string) { | ||
function length(value: string) { | ||
if (value === '.' || value === '..') return 1 | ||
return Buffer.byteLength(value.replace(/^\.|\.$/gm, '')) + 2 | ||
} | ||
|
||
const buffer = Buffer.alloc(length(packet)) | ||
// strip leading and trailing `.` | ||
const value = packet.replace(/^\.|\.$/gm, '') | ||
if (!value.length) return buffer | ||
|
||
let offset = 0 | ||
const list = value.split('.') | ||
for (let i = 0; i < list.length; i++) { | ||
const len = buffer.write(list[i], offset + 1) | ||
buffer[offset] = len | ||
offset += len + 1 | ||
try { | ||
const res = await readContract(client, { | ||
address: universalResolverAddress, | ||
abi: [ | ||
{ | ||
name: 'reverse', | ||
type: 'function', | ||
stateMutability: 'view', | ||
inputs: [{ type: 'bytes', name: 'reverseName' }], | ||
outputs: [ | ||
{ type: 'string', name: 'resolvedName' }, | ||
{ type: 'address', name: 'resolvedAddress' }, | ||
{ type: 'address', name: 'reverseResolver' }, | ||
{ type: 'address', name: 'resolver' }, | ||
], | ||
}, | ||
], | ||
functionName: 'reverse', | ||
args: [`0x${packetToBuffer(reverseNode).toString('hex')}`], | ||
blockNumber, | ||
blockTag, | ||
}) | ||
return res[0] | ||
} catch (error) { | ||
return null | ||
} | ||
|
||
return buffer | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
import { expect, test } from 'vitest' | ||
|
||
import * as actions from './index' | ||
|
||
test('exports actions', () => { | ||
expect(actions).toMatchInlineSnapshot(` | ||
{ | ||
"getEnsAddress": [Function], | ||
"getEnsName": [Function], | ||
} | ||
`) | ||
}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1,3 @@ | ||
export { getEnsAddress } from './getEnsAddress' | ||
|
||
export { getEnsName } from './getEnsName' |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
import { expect, test } from 'vitest' | ||
|
||
import * as ens from './ens' | ||
|
||
test('exports ens', () => { | ||
expect(ens).toMatchInlineSnapshot(` | ||
{ | ||
"getEnsAddress": [Function], | ||
"getEnsName": [Function], | ||
"labelhash": [Function], | ||
"namehash": [Function], | ||
"normalize": [Function], | ||
} | ||
`) | ||
}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.