Skip to content

Commit

Permalink
error handling
Browse files Browse the repository at this point in the history
  • Loading branch information
TateB committed Jul 10, 2023
1 parent 5e0f47b commit 4cf3b75
Show file tree
Hide file tree
Showing 33 changed files with 387 additions and 137 deletions.
Binary file modified packages/ensjs/archive.tar.lz4
Binary file not shown.
2 changes: 1 addition & 1 deletion packages/ensjs/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@
},
"devDependencies": {
"@ensdomains/buffer": "^0.0.13",
"@ensdomains/ens-contracts": "0.0.17",
"@ensdomains/ens-contracts": "0.0.22",
"@ensdomains/ens-test-env": "workspace:*",
"@nomiclabs/hardhat-ethers": "npm:hardhat-deploy-ethers",
"@openzeppelin/contracts": "^4.5.0",
Expand Down
2 changes: 2 additions & 0 deletions packages/ensjs/src/functions/public/_getAbi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,8 @@ const decode = async (
_client: ClientWithEns,
data: Hex,
): Promise<InternalGetAbiReturnType> => {
if (data === '0x') return null

const [bigintContentType, encodedAbiData] = decodeFunctionResult({
abi: publicResolverAbiSnippet,
functionName: 'ABI',
Expand Down
1 change: 1 addition & 0 deletions packages/ensjs/src/functions/public/_getAddr.ts
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ const decode = async (
data: Hex,
{ coin }: InternalGetAddrParameters,
): Promise<InternalGetAddrReturnType> => {
if (data === '0x') return null
if (!coin) {
coin = 60
}
Expand Down
2 changes: 2 additions & 0 deletions packages/ensjs/src/functions/public/_getContentHash.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@ const decode = async (
_client: ClientWithEns,
data: Hex,
): Promise<InternalGetContentHashReturnType> => {
if (data === '0x') return null

const response = decodeFunctionResult({
abi: publicResolverContenthashSnippet,
functionName: 'contenthash',
Expand Down
2 changes: 2 additions & 0 deletions packages/ensjs/src/functions/public/_getText.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@ const decode = async (
_client: ClientWithEns,
data: Hex,
): Promise<InternalGetTextReturnType> => {
if (data === '0x') return null

const response = decodeFunctionResult({
abi: publicResolverTextSnippet,
functionName: 'text',
Expand Down
9 changes: 6 additions & 3 deletions packages/ensjs/src/functions/public/batch.test.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
import { createPublicClient, http } from 'viem'
import { mainnet } from 'viem/chains'
import { addEnsContracts } from '../../contracts/addEnsContracts.js'
import { publicClient } from '../../tests/addTestContracts.js'
import {
deploymentAddresses,
publicClient,
} from '../../tests/addTestContracts.js'
import batch from './batch.js'
import getAddressRecord from './getAddressRecord.js'
import getName from './getName.js'
Expand Down Expand Up @@ -31,8 +34,8 @@ describe('batch', () => {
{
"match": true,
"name": "with-profile.eth",
"resolverAddress": "0x84eA74d481Ee0A5332c457a4d796187F6Ba67fEB",
"reverseResolverAddress": "0x70e0bA845a1A0F2DA3359C97E0285013525FFC49",
"resolverAddress": "${deploymentAddresses.LegacyPublicResolver}",
"reverseResolverAddress": "${deploymentAddresses.PublicResolver}",
},
]
`)
Expand Down
10 changes: 7 additions & 3 deletions packages/ensjs/src/functions/public/getAbiRecord.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
import type { Hex } from 'viem'
import type { ClientWithEns } from '../../contracts/consts.js'
import type { Prettify, SimpleTransactionRequest } from '../../types.js'
import type {
GenericPassthrough,
Prettify,
SimpleTransactionRequest,
} from '../../types.js'
import {
generateFunction,
type GeneratedFunction,
Expand All @@ -26,9 +30,9 @@ const encode = (
const decode = async (
client: ClientWithEns,
data: Hex,
passthrough: GenericPassthrough,
): Promise<GetAbiRecordReturnType> => {
const urData = await universalWrapper.decode(client, data)
if (!urData) return null
const urData = await universalWrapper.decode(client, data, passthrough)
return _getAbi.decode(client, urData.data)
}

Expand Down
10 changes: 7 additions & 3 deletions packages/ensjs/src/functions/public/getAddressRecord.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
import type { Hex } from 'viem'
import type { ClientWithEns } from '../../contracts/consts.js'
import type { Prettify, SimpleTransactionRequest } from '../../types.js'
import type {
GenericPassthrough,
Prettify,
SimpleTransactionRequest,
} from '../../types.js'
import {
generateFunction,
type GeneratedFunction,
Expand All @@ -26,10 +30,10 @@ const encode = (
const decode = async (
client: ClientWithEns,
data: Hex,
passthrough: GenericPassthrough,
args: GetAddressRecordParameters,
): Promise<GetAddressRecordReturnType> => {
const urData = await universalWrapper.decode(client, data)
if (!urData) return null
const urData = await universalWrapper.decode(client, data, passthrough)
return _getAddr.decode(client, urData.data, args)
}

Expand Down
4 changes: 3 additions & 1 deletion packages/ensjs/src/functions/public/getAvailable.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import {
BaseError,
decodeFunctionResult,
encodeFunctionData,
labelhash,
Expand Down Expand Up @@ -50,8 +51,9 @@ const encode = (

const decode = async (
_client: ClientWithEns,
data: Hex,
data: Hex | BaseError,
): Promise<GetAvailableReturnType> => {
if (typeof data === 'object') throw data
const result = decodeFunctionResult({
abi: baseRegistrarAvailableSnippet,
functionName: 'available',
Expand Down
16 changes: 10 additions & 6 deletions packages/ensjs/src/functions/public/getContentHashRecord.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
import type { Hex } from 'viem'
import type { BaseError, Hex } from 'viem'
import type { ClientWithEns } from '../../contracts/consts.js'
import type { Prettify, SimpleTransactionRequest } from '../../types.js'
import type {
GenericPassthrough,
Prettify,
TransactionRequestWithPassthrough,
} from '../../types.js'
import {
generateFunction,
type GeneratedFunction,
Expand All @@ -20,17 +24,17 @@ export type GetContentHashRecordReturnType =
const encode = (
client: ClientWithEns,
{ name }: GetContentHashRecordParameters,
): SimpleTransactionRequest => {
): TransactionRequestWithPassthrough => {
const prData = _getContentHash.encode(client, { name })
return universalWrapper.encode(client, { name, data: prData.data })
}

const decode = async (
client: ClientWithEns,
data: Hex,
data: Hex | BaseError,
passthrough: GenericPassthrough,
): Promise<GetContentHashRecordReturnType> => {
const urData = await universalWrapper.decode(client, data)
if (!urData) return null
const urData = await universalWrapper.decode(client, data, passthrough)
return _getContentHash.decode(client, urData.data)
}

Expand Down
4 changes: 3 additions & 1 deletion packages/ensjs/src/functions/public/getExpiry.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import {
BaseError,
decodeFunctionResult,
encodeFunctionData,
labelhash,
Expand Down Expand Up @@ -110,9 +111,10 @@ const encode = (

const decode = async (
client: ClientWithEns,
data: Hex,
data: Hex | BaseError,
{ name, contract }: GetExpiryParameters,
): Promise<GetExpiryReturnType> => {
if (typeof data === 'object') throw data
const labels = name.split('.')
const result = await multicallWrapper.decode(client, data, [])

Expand Down
80 changes: 50 additions & 30 deletions packages/ensjs/src/functions/public/getName.test.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,29 @@
import { publicClient } from '../../tests/addTestContracts.js'
import type { Address, Hex } from 'viem'
import {
deploymentAddresses,
publicClient,
testClient,
waitForTransaction,
walletClient,
} from '../../tests/addTestContracts.js'
import setPrimaryName from '../wallet/setPrimaryName.js'
import getName from './getName.js'

let snapshot: Hex
let accounts: Address[]

beforeAll(async () => {
accounts = await walletClient.getAddresses()
})

beforeEach(async () => {
snapshot = await testClient.snapshot()
})

afterEach(async () => {
await testClient.revert({ id: snapshot })
})

describe('getName', () => {
it('should get a primary name from an address', async () => {
const result = await getName(publicClient, {
Expand All @@ -10,37 +33,34 @@ describe('getName', () => {
{
"match": true,
"name": "with-profile.eth",
"resolverAddress": "0x84eA74d481Ee0A5332c457a4d796187F6Ba67fEB",
"reverseResolverAddress": "0x70e0bA845a1A0F2DA3359C97E0285013525FFC49",
"resolverAddress": "${deploymentAddresses.LegacyPublicResolver}",
"reverseResolverAddress": "${deploymentAddresses.PublicResolver}",
}
`)
// expect(result).toBeTruthy()
// if (result) {
// expect(result.name).toBe('with-profile.eth')
// expect(result.match).toBeTruthy()
// }
})
it.todo(
'should return null for an address with no primary name',
// async () => {
// const result = await getName(testClient, {
// address: '0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0',
// })
// expect(result).toMatchInlineSnapshot(``)
// },
)
it.todo(
'should return with a false match for a name with no forward resolution',
// async () => {
// const tx = await ensInstance.setName('with-profile.eth')
// await tx?.wait()
it('should return null for an address with no primary name', async () => {
const result = await getName(publicClient, {
address: '0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0',
})
expect(result).toBeNull()
})
it('should return with a false match for a name with no forward resolution', async () => {
const tx = await setPrimaryName(walletClient, {
name: 'with-profile.eth',
account: accounts[0],
})
await waitForTransaction(tx)

// const result = await ensInstance.getName(accounts[0])
// expect(result).toBeTruthy()
// if (result) {
// expect(result.name).toBe('with-profile.eth')
// expect(result.match).toBeFalsy()
// }
// },
)
const result = await getName(publicClient, {
address: accounts[0],
})
expect(result).toMatchInlineSnapshot(`
{
"match": false,
"name": "with-profile.eth",
"resolverAddress": "${deploymentAddresses.LegacyPublicResolver}",
"reverseResolverAddress": "${deploymentAddresses.PublicResolver}",
}
`)
})
})
44 changes: 39 additions & 5 deletions packages/ensjs/src/functions/public/getName.ts
Original file line number Diff line number Diff line change
@@ -1,18 +1,25 @@
import {
BaseError,
decodeErrorResult,
decodeFunctionResult,
encodeFunctionData,
getContractError,
toHex,
type Address,
type Hex,
} from 'viem'
import type { ClientWithEns } from '../../contracts/consts.js'
import { getChainContractAddress } from '../../contracts/getChainContractAddress.js'
import { universalResolverReverseSnippet } from '../../contracts/universalResolver.js'
import type { SimpleTransactionRequest } from '../../types.js'
import type {
GenericPassthrough,
TransactionRequestWithPassthrough,
} from '../../types.js'
import {
generateFunction,
type GeneratedFunction,
} from '../../utils/generateFunction.js'
import { getRevertErrorData } from '../../utils/getRevertErrorData.js'
import { packetToBytes } from '../../utils/hexEncodedName.js'

export type GetNameParameters = {
Expand All @@ -34,23 +41,50 @@ export type GetNameReturnType = {
const encode = (
client: ClientWithEns,
{ address }: GetNameParameters,
): SimpleTransactionRequest => {
): TransactionRequestWithPassthrough => {
const reverseNode = `${address.toLowerCase().substring(2)}.addr.reverse`
const to = getChainContractAddress({
client,
contract: 'ensUniversalResolver',
})
const args = [toHex(packetToBytes(reverseNode))] as const
return {
to: getChainContractAddress({ client, contract: 'ensUniversalResolver' }),
to,
data: encodeFunctionData({
abi: universalResolverReverseSnippet,
functionName: 'reverse',
args: [toHex(packetToBytes(reverseNode))],
args,
}),
passthrough: { address, args },
}
}

const decode = async (
_client: ClientWithEns,
data: Hex,
data: Hex | BaseError,
passthrough: GenericPassthrough,
{ address }: GetNameParameters,
): Promise<GetNameReturnType | null> => {
if (typeof data === 'object') {
const errorData = getRevertErrorData(data)
if (errorData) {
const decodedError = decodeErrorResult({
abi: universalResolverReverseSnippet,
data: errorData,
})
if (
decodedError.errorName === 'ResolverNotFound' ||
decodedError.errorName === 'ResolverWildcardNotSupported'
)
return null
}
throw getContractError(data, {
abi: universalResolverReverseSnippet,
functionName: 'reverse',
args: passthrough.args,
address: passthrough.address,
})
}
const result = decodeFunctionResult({
abi: universalResolverReverseSnippet,
functionName: 'reverse',
Expand Down
7 changes: 5 additions & 2 deletions packages/ensjs/src/functions/public/getOwner.test.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
import { publicClient } from '../../tests/addTestContracts.js'
import {
deploymentAddresses,
publicClient,
} from '../../tests/addTestContracts.js'
import getOwner from './getOwner.js'

describe('getOwner', () => {
Expand All @@ -15,7 +18,7 @@ describe('getOwner', () => {
const result = await getOwner(publicClient, { name: 'expired-wrapped.eth' })
expect(result).toMatchInlineSnapshot(`
{
"owner": "0xE6E340D132b5f46d1e472DebcD681B2aBc16e57E",
"owner": "${deploymentAddresses.NameWrapper}",
"ownershipLevel": "registrar",
"registrant": null,
}
Expand Down
5 changes: 3 additions & 2 deletions packages/ensjs/src/functions/public/getOwner.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { decodeAbiParameters, type Address, type Hex } from 'viem'
import { BaseError, decodeAbiParameters, type Address, type Hex } from 'viem'
import type { ClientWithEns } from '../../contracts/consts.js'
import { getChainContractAddress } from '../../contracts/getChainContractAddress.js'
import type { SimpleTransactionRequest } from '../../types.js'
Expand Down Expand Up @@ -106,9 +106,10 @@ const addressDecode = (data: Hex) =>

const decode = async (
client: ClientWithEns,
data: Hex,
data: Hex | BaseError,
{ name, contract }: GetOwnerParameters,
): Promise<GetOwnerReturnType> => {
if (typeof data === 'object') throw data
const labels = name.split('.')
if (contract || labels.length === 1) {
const singleOwner = addressDecode(data)
Expand Down
Loading

0 comments on commit 4cf3b75

Please sign in to comment.