Skip to content

Commit 2237290

Browse files
authored
Fix/ens resolve (#2895)
1 parent f076cbb commit 2237290

File tree

8 files changed

+64
-73
lines changed

8 files changed

+64
-73
lines changed

src/components/WalletConnection/ReadOnlyModal.tsx

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,13 +15,15 @@ import { ModalType, useModalContext } from 'src/hooks/useModal';
1515
import { useWeb3Context } from 'src/libs/hooks/useWeb3Context';
1616
import { useRootStore } from 'src/store/root';
1717
import { AUTH } from 'src/utils/events';
18-
import { getENSProvider } from 'src/utils/marketsAndNetworksConfig';
18+
import { getENSClient } from 'src/utils/marketsAndNetworksConfig';
1919
import { normalize } from 'viem/ens';
2020
import { useAccount, useDisconnect } from 'wagmi';
2121

2222
import { BasicModal } from '../primitives/BasicModal';
2323
import { TxModalTitle } from '../transactions/FlowCommons/TxModalTitle';
2424

25+
const viemClient = getENSClient();
26+
2527
export const ReadOnlyModal = () => {
2628
const { disconnectAsync } = useDisconnect();
2729
const { isConnected } = useAccount();
@@ -31,7 +33,6 @@ export const ReadOnlyModal = () => {
3133
const { type, close } = useModalContext();
3234
const { breakpoints } = useTheme();
3335
const sm = useMediaQuery(breakpoints.down('sm'));
34-
const mainnetProvider = getENSProvider();
3536
const trackEvent = useRootStore((store) => store.trackEvent);
3637

3738
const handleReadAddress = async (inputMockWalletAddress: string): Promise<void> => {
@@ -43,7 +44,7 @@ export const ReadOnlyModal = () => {
4344
if (inputMockWalletAddress.slice(-4) === '.eth') {
4445
const normalizedENS = normalize(inputMockWalletAddress);
4546
// Attempt to resolve ENS name and use resolved address if valid
46-
const resolvedAddress = await mainnetProvider.resolveName(normalizedENS);
47+
const resolvedAddress = await viemClient.getEnsAddress({ name: normalizedENS });
4748
if (resolvedAddress && utils.isAddress(resolvedAddress)) {
4849
saveAndClose(resolvedAddress);
4950
} else {

src/components/transactions/Bridge/BridgeDestinationInput.tsx

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,9 @@ import {
1010
import { isAddress } from 'ethers/lib/utils';
1111
import { useEffect, useState } from 'react';
1212
import { useIsContractAddress } from 'src/hooks/useIsContractAddress';
13-
import { getENSProvider } from 'src/utils/marketsAndNetworksConfig';
13+
import { getENSClient } from 'src/utils/marketsAndNetworksConfig';
14+
15+
const viemClient = getENSClient();
1416

1517
export const BridgeDestinationInput = ({
1618
connectedAccount,
@@ -49,7 +51,7 @@ export const BridgeDestinationInput = ({
4951
useEffect(() => {
5052
const checkENS = async () => {
5153
setValidatingENS(true);
52-
const resolvedAddress = await getENSProvider().resolveName(destinationAccount);
54+
const resolvedAddress = await viemClient.getEnsAddress({ name: destinationAccount });
5355
if (resolvedAddress) {
5456
setDestinationAccount(resolvedAddress.toLowerCase());
5557
}

src/hooks/governance/useGovernanceProposals.ts

Lines changed: 14 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { ChainId } from '@aave/contract-helpers';
22
import { normalizeBN } from '@aave/math-utils';
33
import { useInfiniteQuery, useQuery } from '@tanstack/react-query';
4-
import { constants, Contract } from 'ethers';
4+
import { constants } from 'ethers';
55
import { gql } from 'graphql-request';
66
import {
77
adaptCacheProposalToDetail,
@@ -26,7 +26,7 @@ import {
2626
import { useRootStore } from 'src/store/root';
2727
import { governanceV3Config } from 'src/ui-config/governanceConfig';
2828
import { useSharedDependencies } from 'src/ui-config/SharedDependenciesProvider';
29-
import { getProvider } from 'src/utils/marketsAndNetworksConfig';
29+
import { getENSClient } from 'src/utils/marketsAndNetworksConfig';
3030
import { subgraphRequest } from 'src/utils/subgraphRequest';
3131

3232
import { getProposal } from './useProposal';
@@ -42,7 +42,7 @@ const USE_GOVERNANCE_CACHE = process.env.NEXT_PUBLIC_USE_GOVERNANCE_CACHE === 't
4242
const PAGE_SIZE = 10;
4343
const VOTES_PAGE_SIZE = 50;
4444
const SEARCH_RESULTS_LIMIT = 10;
45-
export const ENS_REVERSE_REGISTRAR = '0x3671aE578E63FdF66ad4F3E12CC0c0d71Ac7510C';
45+
const viemClient = getENSClient();
4646

4747
// ============================================
4848
// Subgraph search query
@@ -78,16 +78,6 @@ const getProposalVotesQuery = gql`
7878
}
7979
`;
8080

81-
const ensAbi = [
82-
{
83-
inputs: [{ internalType: 'address[]', name: 'addresses', type: 'address[]' }],
84-
name: 'getNames',
85-
outputs: [{ internalType: 'string[]', name: 'r', type: 'string[]' }],
86-
stateMutability: 'view',
87-
type: 'function',
88-
},
89-
];
90-
9181
type SubgraphVote = {
9282
proposalId: string;
9383
support: boolean;
@@ -335,13 +325,14 @@ export const useGovernanceVotersSplit = (
335325
queryFn: async () => {
336326
const votes = await fetchSubgraphVotes(proposalId, votingChainId as ChainId);
337327
try {
338-
const provider = getProvider(governanceV3Config.coreChainId);
339-
const contract = new Contract(ENS_REVERSE_REGISTRAR, ensAbi);
340-
const connectedContract = contract.connect(provider);
341-
const ensNames: string[] = await connectedContract.getNames(votes.map((v) => v.voter));
328+
const ensNames = await Promise.all(
329+
votes.map((v) =>
330+
viemClient.getEnsName({ address: v.voter as `0x${string}` }).catch(() => null)
331+
)
332+
);
342333
return votes.map((vote, i) => ({
343334
...vote,
344-
ensName: ensNames[i] || undefined,
335+
ensName: ensNames[i] ?? undefined,
345336
}));
346337
} catch {
347338
return votes;
@@ -364,10 +355,11 @@ export const useGovernanceVotersSplit = (
364355

365356
const { data: cacheEnsNames } = useQuery({
366357
queryFn: async () => {
367-
const provider = getProvider(governanceV3Config.coreChainId);
368-
const contract = new Contract(ENS_REVERSE_REGISTRAR, ensAbi);
369-
const connectedContract = contract.connect(provider);
370-
const names: string[] = await connectedContract.getNames(cacheVoterAddresses);
358+
const names = await Promise.all(
359+
cacheVoterAddresses.map((addr) =>
360+
viemClient.getEnsName({ address: addr as `0x${string}` }).catch(() => null)
361+
)
362+
);
371363
const map: Record<string, string> = {};
372364
cacheVoterAddresses.forEach((addr, i) => {
373365
if (names[i]) map[addr.toLowerCase()] = names[i];

src/hooks/governance/useProposalVotes.ts

Lines changed: 9 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,11 @@
11
import { ChainId } from '@aave/contract-helpers';
22
import { normalizeBN } from '@aave/math-utils';
33
import { useQuery, UseQueryResult } from '@tanstack/react-query';
4-
import { Contract } from 'ethers';
54
import { gql } from 'graphql-request';
65
import { governanceV3Config } from 'src/ui-config/governanceConfig';
7-
import { getProvider } from 'src/utils/marketsAndNetworksConfig';
6+
import { getENSClient } from 'src/utils/marketsAndNetworksConfig';
87
import { subgraphRequest } from 'src/utils/subgraphRequest';
98

10-
import { ENS_REVERSE_REGISTRAR } from './useGovernanceProposals';
11-
129
export type ProposalVote = {
1310
proposalId: string;
1411
support: boolean;
@@ -27,20 +24,7 @@ export interface ProposalVotes {
2724
isFetching: boolean;
2825
}
2926

30-
const abi = [
31-
{
32-
inputs: [{ internalType: 'contract ENS', name: '_ens', type: 'address' }],
33-
stateMutability: 'nonpayable',
34-
type: 'constructor',
35-
},
36-
{
37-
inputs: [{ internalType: 'address[]', name: 'addresses', type: 'address[]' }],
38-
name: 'getNames',
39-
outputs: [{ internalType: 'string[]', name: 'r', type: 'string[]' }],
40-
stateMutability: 'view',
41-
type: 'function',
42-
},
43-
];
27+
const viemClient = getENSClient();
4428

4529
const getProposalVotes = gql`
4630
query getProposalVotes($proposalId: Int!) {
@@ -71,11 +55,13 @@ const fetchProposalVotes = async (
7155
}));
7256
};
7357

74-
const fetchProposalVotesEnsNames = async (addresses: string[]) => {
75-
const provider = getProvider(governanceV3Config.coreChainId);
76-
const contract = new Contract(ENS_REVERSE_REGISTRAR, abi);
77-
const connectedContract = contract.connect(provider);
78-
return connectedContract.getNames(addresses) as Promise<string[]>;
58+
const fetchProposalVotesEnsNames = async (addresses: string[]): Promise<string[]> => {
59+
const names = await Promise.all(
60+
addresses.map((addr) =>
61+
viemClient.getEnsName({ address: addr as `0x${string}` }).catch(() => null)
62+
)
63+
);
64+
return names.map((name) => name ?? '');
7965
};
8066

8167
export const useProposalVotesQuery = ({

src/libs/hooks/use-get-ens.tsx

Lines changed: 7 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,8 @@
11
import { blo } from 'blo';
2-
import { utils } from 'ethers';
32
import { useEffect, useState } from 'react';
4-
import { getENSProvider } from 'src/utils/marketsAndNetworksConfig';
3+
import { getENSClient } from 'src/utils/marketsAndNetworksConfig';
54

6-
const mainnetProvider = getENSProvider();
5+
const viemClient = getENSClient();
76

87
interface EnsResponse {
98
name?: string;
@@ -13,26 +12,20 @@ interface EnsResponse {
1312
const useGetEns = (address: string): EnsResponse => {
1413
const [ensName, setEnsName] = useState<string | undefined>(undefined);
1514
const [ensAvatar, setEnsAvatar] = useState<string | undefined>(undefined);
15+
1616
const getName = async (address: string) => {
1717
try {
18-
const name = await mainnetProvider.lookupAddress(address);
19-
setEnsName(name ? name : undefined);
18+
const name = await viemClient.getEnsName({ address: address as `0x${string}` });
19+
setEnsName(name ?? undefined);
2020
} catch (error) {
2121
console.error('ENS name lookup error', error);
2222
}
2323
};
2424

2525
const getAvatar = async (name: string) => {
2626
try {
27-
const labelHash = utils.keccak256(utils.toUtf8Bytes(name?.replace('.eth', '')));
28-
const result: { background_image: string } = await (
29-
await fetch(
30-
`https://metadata.ens.domains/mainnet/0x57f1887a8BF19b14fC0dF6Fd9B2acc9Af147eA85/${labelHash}/`
31-
)
32-
).json();
33-
setEnsAvatar(
34-
result && result.background_image ? result.background_image : blo(address as `0x${string}`)
35-
);
27+
const avatar = await viemClient.getEnsAvatar({ name });
28+
setEnsAvatar(avatar ?? blo(address as `0x${string}`));
3629
} catch (error) {
3730
console.error('ENS avatar lookup error', error);
3831
}

src/modules/governance/proposal/VotersListItem.tsx

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { ExternalLinkIcon } from '@heroicons/react/solid';
22
import { Avatar, Box, SvgIcon, Typography } from '@mui/material';
33
import { blo } from 'blo';
4+
import React, { useEffect, useState } from 'react';
45
import { FormattedNumber } from 'src/components/primitives/FormattedNumber';
56
import { Link } from 'src/components/primitives/Link';
67
import { VoteDisplay } from 'src/modules/governance/types';
@@ -21,6 +22,13 @@ type VotersListItemProps = {
2122
export const VotersListItem = ({ compact, voter }: VotersListItemProps): JSX.Element | null => {
2223
const { voter: address, ensName } = voter;
2324
const blockieAvatar = blo(address !== '' ? (address as `0x${string}`) : '0x');
25+
const [avatar, setAvatar] = useState(blockieAvatar);
26+
27+
useEffect(() => {
28+
if (ensName) {
29+
setAvatar(`https://metadata.ens.domains/mainnet/avatar/${ensName}`);
30+
}
31+
}, [ensName]);
2432
const trackEvent = useRootStore((store) => store.trackEvent);
2533

2634
const displayName = (name?: string) => {
@@ -55,7 +63,11 @@ export const VotersListItem = ({ compact, voter }: VotersListItemProps): JSX.Ele
5563
<Box sx={{ my: 6, '&:first-of-type': { mt: 0 }, '&:last-of-type': { mb: 0 } }}>
5664
<Box sx={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between' }}>
5765
<Box sx={{ display: 'flex', justifyContent: 'flex-start', alignItems: 'center' }}>
58-
<Avatar src={blockieAvatar} sx={{ width: 24, height: 24, mr: 2 }} />
66+
<Avatar
67+
src={avatar}
68+
sx={{ width: 24, height: 24, mr: 2 }}
69+
slotProps={{ img: { onError: () => setAvatar(blockieAvatar) } }}
70+
/>
5971
<Link
6072
href={`https://etherscan.io/address/${address}`}
6173
onClick={() =>

src/store/utils/domain-fetchers/ens.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
import { DomainType, WalletDomain } from 'src/store/walletDomains';
2-
import { getENSProvider } from 'src/utils/marketsAndNetworksConfig';
2+
import { getENSClient } from 'src/utils/marketsAndNetworksConfig';
33
import { tFetch } from 'src/utils/tFetch';
44

5-
const mainnetProvider = getENSProvider();
5+
const viemClient = getENSClient();
66

77
const getEnsName = async (address: string): Promise<string | null> => {
88
try {
9-
const name = await mainnetProvider.lookupAddress(address);
10-
return name;
9+
const name = await viemClient.getEnsName({ address: address as `0x${string}` });
10+
return name ?? null;
1111
} catch (error) {
1212
console.error('ENS name lookup error', error);
1313
}

src/utils/marketsAndNetworksConfig.ts

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
import { ChainId, ChainIdToNetwork } from '@aave/contract-helpers';
22
import { StaticJsonRpcProvider } from '@ethersproject/providers';
33
import { ProviderWithSend } from 'src/components/transactions/GovVote/temporary/VotingMachineService';
4+
import { createPublicClient, http, PublicClient } from 'viem';
5+
import { mainnet } from 'viem/chains';
46

57
import {
68
CustomMarket,
@@ -188,10 +190,13 @@ export const getProvider = (chainId: ChainId): ProviderWithSend => {
188190
return providers[chainId];
189191
};
190192

191-
export const getENSProvider = () => {
192-
const chainId = 1;
193-
const config = getNetworkConfig(chainId);
194-
return new StaticJsonRpcProvider(config.publicJsonRPCUrl[0], chainId);
193+
export const getENSClient = (): PublicClient => {
194+
const config = getNetworkConfig(ChainId.mainnet);
195+
return createPublicClient({
196+
chain: mainnet,
197+
transport: http(config.publicJsonRPCUrl[0]),
198+
batch: { multicall: true },
199+
});
195200
};
196201

197202
const ammDisableProposal = 'https://governance-v2.aave.com/governance/proposal/44';

0 commit comments

Comments
 (0)