Skip to content

Commit

Permalink
Use chainId instead of chain
Browse files Browse the repository at this point in the history
  • Loading branch information
cpcramer committed Aug 2, 2024
1 parent 9a16b9a commit b0d6c89
Show file tree
Hide file tree
Showing 10 changed files with 66 additions and 48 deletions.
26 changes: 16 additions & 10 deletions src/identity/hooks/useName.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
* @vitest-environment jsdom
*/
import { renderHook, waitFor } from '@testing-library/react';
import { base, optimism } from 'viem/chains';
import { base, mainnet, optimism } from 'viem/chains';
import { beforeEach, describe, expect, it, vi } from 'vitest';
import type { Mock } from 'vitest';
import { publicClient } from '../../network/client';
Expand Down Expand Up @@ -31,9 +31,12 @@ describe('useName', () => {
mockGetEnsName.mockResolvedValue(testEnsName);

// Use the renderHook function to create a test harness for the useName hook
const { result } = renderHook(() => useName({ address: testAddress }), {
wrapper: getNewReactQueryTestProvider(),
});
const { result } = renderHook(
() => useName({ address: testAddress, chainId: mainnet.id }),
{
wrapper: getNewReactQueryTestProvider(),
},
);

// Wait for the hook to finish fetching the ENS name
await waitFor(() => {
Expand All @@ -45,9 +48,12 @@ describe('useName', () => {

it('returns the loading state true while still fetching from ens action', async () => {
// Use the renderHook function to create a test harness for the useName hook
const { result } = renderHook(() => useName({ address: testAddress }), {
wrapper: getNewReactQueryTestProvider(),
});
const { result } = renderHook(
() => useName({ address: testAddress, chainId: mainnet.id }),
{
wrapper: getNewReactQueryTestProvider(),
},
);

// Wait for the hook to finish fetching the ENS name
await waitFor(() => {
Expand All @@ -65,7 +71,7 @@ describe('useName', () => {

// Use the renderHook function to create a test harness for the useName hook
const { result } = renderHook(
() => useName({ address: testAddress, chain: base }),
() => useName({ address: testAddress, chainId: base.id }),
{
wrapper: getNewReactQueryTestProvider(),
},
Expand All @@ -89,7 +95,7 @@ describe('useName', () => {

// Use the renderHook function to create a test harness for the useName hook
const { result } = renderHook(
() => useName({ address: testAddress, chain: base }),
() => useName({ address: testAddress, chainId: base.id }),
{
wrapper: getNewReactQueryTestProvider(),
},
Expand All @@ -106,7 +112,7 @@ describe('useName', () => {
it('returns error for unsupported chain ', async () => {
// Use the renderHook function to create a test harness for the useName hook
const { result } = renderHook(
() => useName({ address: testAddress, chain: optimism }),
() => useName({ address: testAddress, chainId: optimism.id }),
{
wrapper: getNewReactQueryTestProvider(),
},
Expand Down
6 changes: 3 additions & 3 deletions src/identity/hooks/useName.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,15 +14,15 @@ import { getName } from '../utils/getName';
* - `{UseQueryResult}`: The rest of useQuery return values. including isLoading, isError, error, isFetching, refetch, etc.
*/
export const useName = (
{ address, chain = mainnet }: UseNameOptions,
{ address, chainId = mainnet.id }: UseNameOptions,
queryOptions?: UseNameQueryOptions,
) => {
const { enabled = true, cacheTime } = queryOptions ?? {};
const ensActionKey = `ens-name-${address}-${chain.id}`;
const ensActionKey = `ens-name-${address}-${chainId}`;
return useQuery<GetNameReturnType>({
queryKey: ['useName', ensActionKey],
queryFn: async () => {
return await getName({ address, chain });
return await getName({ address, chainId });
},
gcTime: cacheTime,
enabled,
Expand Down
4 changes: 2 additions & 2 deletions src/identity/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ export type GetAvatarReturnType = string | null;
*/
export type GetName = {
address: Address;
chain?: Chain;
chainId?: number; // Optional chainId for domain resolution
};

/**
Expand Down Expand Up @@ -184,7 +184,7 @@ export type UseAttestations = {
*/
export type UseNameOptions = {
address: Address; // The Ethereum address for which the ENS name is to be fetched.
chain?: Chain; // Optional chain for domain resolution
chainId: number; // chainId for domain resolution
};

/**
Expand Down
30 changes: 15 additions & 15 deletions src/identity/utils/getName.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -58,60 +58,60 @@ describe('getName', () => {
it('should return mainnet username', async () => {
const expectedEnsName = 'leo.eth';
mockGetEnsName.mockResolvedValue(expectedEnsName);
const name = await getName({ address: walletAddress, chain: mainnet });
const name = await getName({ address: walletAddress, chainId: mainnet.id });
expect(name).toBe(expectedEnsName);
expect(getChainPublicClient).toHaveBeenCalledWith(mainnet);
expect(getChainPublicClient).toHaveBeenCalledWith(mainnet.id);
});

it('should return sepolia username', async () => {
const expectedEnsName = 'leo.test.eth';
mockGetEnsName.mockResolvedValue(expectedEnsName);
const name = await getName({ address: walletAddress, chain: sepolia });
const name = await getName({ address: walletAddress, chainId: sepolia.id });
expect(name).toBe(expectedEnsName);
expect(getChainPublicClient).toHaveBeenCalledWith(sepolia);
expect(getChainPublicClient).toHaveBeenCalledWith(sepolia.id);
});

it('should return custom testnet chain username', async () => {
const expectedEnsName = 'leo.customtestnet.eth';
mockReadContract.mockResolvedValue(expectedEnsName);
const name = await getName({
address: walletAddress,
chain: baseSepolia,
chainId: baseSepolia.id,
});
expect(name).toBe(expectedEnsName);
expect(getChainPublicClient).toHaveBeenCalledWith(baseSepolia);
expect(getChainPublicClient).toHaveBeenCalledWith(baseSepolia.id);
});

it('should return custom mainnet username', async () => {
const expectedEnsName = 'leo.custommainnet.eth';
mockReadContract.mockResolvedValue(expectedEnsName);
const name = await getName({ address: walletAddress, chain: base });
const name = await getName({ address: walletAddress, chainId: base.id });
expect(name).toBe(expectedEnsName);
expect(getChainPublicClient).toHaveBeenCalledWith(base);
expect(getChainPublicClient).toHaveBeenCalledWith(base.id);
});

it('should return null if user is not registered', async () => {
const expectedEnsName = null;
mockReadContract.mockResolvedValue(expectedEnsName);
mockGetEnsName.mockResolvedValue(expectedEnsName);
const name = await getName({ address: walletAddress, chain: base });
const name = await getName({ address: walletAddress, chainId: base.id });
expect(name).toBe(expectedEnsName);
expect(getChainPublicClient).toHaveBeenCalledWith(base);
expect(getChainPublicClient).toHaveBeenCalledWith(base.id);
});

it('should default to ENS name if custom chain name is not registered', async () => {
const expectedBaseName = null;
const expectedEnsName = 'registered.eth';
mockReadContract.mockResolvedValue(expectedBaseName);
mockGetEnsName.mockResolvedValue(expectedEnsName);
const name = await getName({ address: walletAddress, chain: base });
const name = await getName({ address: walletAddress, chainId: base.id });
expect(name).toBe(expectedEnsName);
expect(getChainPublicClient).toHaveBeenCalledWith(base);
expect(getChainPublicClient).toHaveBeenCalledWith(base.id);
});

it('should throw an error on unsupported chain', async () => {
await expect(
getName({ address: walletAddress, chain: optimism }),
getName({ address: walletAddress, chainId: optimism.id }),
).rejects.toBe(
'ChainId not supported, name resolution is only supported on Ethereum and Base.',
);
Expand All @@ -121,8 +121,8 @@ describe('getName', () => {
const expectedEnsName = 'zizzamia.eth';
mockReadContract.mockRejectedValue(new Error('This is an error'));
mockGetEnsName.mockResolvedValue(expectedEnsName);
const name = await getName({ address: walletAddress, chain: base });
const name = await getName({ address: walletAddress, chainId: base.id });
expect(name).toBe(expectedEnsName);
expect(getChainPublicClient).toHaveBeenCalledWith(base);
expect(getChainPublicClient).toHaveBeenCalledWith(base.id);
});
});
12 changes: 6 additions & 6 deletions src/identity/utils/getName.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,10 @@ import { convertReverseNodeToBytes } from './convertReverseNodeToBytes';

export const getName = async ({
address,
chain = mainnet,
chainId = mainnet.id,
}: GetName): Promise<GetNameReturnType> => {
const chainIsBase = isBase({ chainId: chain.id });
const chainIsEthereum = isEthereum({ chainId: chain.id });
const chainIsBase = isBase({ chainId });
const chainIsEthereum = isEthereum({ chainId });
const chainSupportsUniversalResolver = chainIsEthereum || chainIsBase;

if (!chainSupportsUniversalResolver) {
Expand All @@ -27,14 +27,14 @@ export const getName = async ({
);
}

let client = getChainPublicClient(chain);
let client = getChainPublicClient(chainId);

if (chainIsBase) {
const addressReverseNode = convertReverseNodeToBytes(address, base.id);
try {
const baseName = await client.readContract({
abi: L2ResolverAbi,
address: RESOLVER_ADDRESSES_BY_CHAIN_ID[chain.id],
address: RESOLVER_ADDRESSES_BY_CHAIN_ID[chainId],
functionName: 'name',
args: [addressReverseNode],
});
Expand All @@ -47,7 +47,7 @@ export const getName = async ({
}

// Default to mainnet
client = getChainPublicClient(mainnet);
client = getChainPublicClient(mainnet.id);
// ENS username
const ensName = await client.getEnsName({
address,
Expand Down
2 changes: 1 addition & 1 deletion src/network/getChainPublicClient.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ describe('getChainPublicClient', () => {
});

it('should return a public client matching the given chain', async () => {
const publicClient = getChainPublicClient(base);
const publicClient = getChainPublicClient(base.id);
expect(publicClient.chain.id).toBe(base.id);
});
});
16 changes: 14 additions & 2 deletions src/network/getChainPublicClient.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,19 @@
import { http, createPublicClient } from 'viem';
import type { Chain } from 'viem/chains';
import { type Chain, base, baseSepolia, goerli, mainnet } from 'viem/chains';

const supportedChains = [mainnet, goerli, base, baseSepolia];

function getChainFromId(chainId: number): Chain | undefined {
return supportedChains.find((chain) => chain.id === chainId);
}

export function getChainPublicClient(chainId: number) {
const chain = getChainFromId(chainId);

if (!chain) {
throw new Error(`Unsupported chain ID: ${chainId}`);
}

export function getChainPublicClient(chain: Chain) {
return createPublicClient({
chain: chain,
transport: http(),
Expand Down
8 changes: 4 additions & 4 deletions src/wallet/components/WalletDropdownBaseName.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ describe('WalletDropdownBaseName', () => {
isConnected: true,
});
(useWalletContext as vi.Mock).mockReturnValue({
chain: base,
chainId: base.id,
});
(
useName as vi.Mock<[], Partial<UseQueryResult<string | null, Error>>>
Expand All @@ -49,7 +49,7 @@ describe('WalletDropdownBaseName', () => {
isConnected: true,
});
(useWalletContext as vi.Mock).mockReturnValue({
chain: base,
chainId: base.id,
});
(
useName as vi.Mock<[], Partial<UseQueryResult<string | null, Error>>>
Expand All @@ -71,7 +71,7 @@ describe('WalletDropdownBaseName', () => {
isConnected: true,
});
(useWalletContext as vi.Mock).mockReturnValue({
chain: base,
chainId: base.id,
});
(
useName as vi.Mock<[], Partial<UseQueryResult<string | null, Error>>>
Expand All @@ -95,7 +95,7 @@ describe('WalletDropdownBaseName', () => {
isConnected: false,
});
(useWalletContext as vi.Mock).mockReturnValue({
chain: base,
chainId: base.id,
});

const { container } = render(<WalletDropdownBaseName />);
Expand Down
6 changes: 3 additions & 3 deletions src/wallet/components/WalletDropdownBaseName.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,15 @@ export function WalletDropdownBaseName({
className,
}: WalletDropdownBaseNameReact) {
const { address } = useAccount();
const { chain } = useWalletContext();
const { chainId } = useWalletContext();

if (!address || !chain) {
if (!address || !chainId) {
return null;
}

const { data: baseName, isLoading } = useName({
address,
chain,
chainId,
});

const hasBaseUserName = !!baseName;
Expand Down
4 changes: 2 additions & 2 deletions src/wallet/types.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import type { UserOperation } from 'permissionless';
import type { Dispatch, ReactNode, SetStateAction } from 'react';
import type { Address, Chain, PublicClient } from 'viem';
import type { Address, PublicClient } from 'viem';
import type { UseBalanceReturnType, UseReadContractReturnType } from 'wagmi';
import type { SwapError } from '../swap';

Expand Down Expand Up @@ -61,7 +61,7 @@ export type UseGetTokenBalanceResponse = {
*/
export type WalletContextType = {
address?: Address | null; // The Ethereum address to fetch the avatar and name for.
chain?: Chain; // Optional chain for domain resolution
chainId?: number; // Optional chainId for domain resolution
isOpen: boolean;
setIsOpen: Dispatch<SetStateAction<boolean>>;
};
Expand Down

0 comments on commit b0d6c89

Please sign in to comment.