Skip to content

Commit b23d01b

Browse files
fix: Handle connection error and expose in useWallet (#284)
* fix: Handle connection error and expose in useWallet * desctructure react lib * add changeset
1 parent 7e1f969 commit b23d01b

File tree

3 files changed

+90
-82
lines changed

3 files changed

+90
-82
lines changed

.changeset/metal-pets-remain.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@web3-ui/hooks': minor
3+
---
4+
5+
Catch errors in connectWallet and expose them, correct type for connectWallet

packages/hooks/src/Provider.tsx

Lines changed: 79 additions & 78 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,17 @@
11
import { JsonRpcSigner } from '@ethersproject/providers/src.ts/json-rpc-provider';
22
import WalletConnectProvider from '@walletconnect/web3-provider';
33
import { ethers } from 'ethers';
4-
import React from 'react';
4+
import React, { createContext, useCallback, useMemo, useState } from 'react';
55
import Web3Modal, { IProviderOptions } from 'web3modal';
66
import { StaticJsonRpcProvider } from '@ethersproject/providers';
77
import { useReadOnlyProvider } from './hooks';
88

99
export interface Web3ContextType {
10-
connectWallet?: () => void;
10+
connectWallet?: () => Promise<void>;
1111
signer?: JsonRpcSigner | null;
1212
userAddress?: string | null;
1313
disconnectWallet?: () => void;
14+
error?: string;
1415
chainId?: number | null;
1516
connected: boolean;
1617
provider?: ethers.providers.Web3Provider | null;
@@ -19,7 +20,7 @@ export interface Web3ContextType {
1920
readOnlyProvider?: StaticJsonRpcProvider;
2021
}
2122

22-
export const Web3Context = React.createContext<Web3ContextType | undefined>(
23+
export const Web3Context = createContext<Web3ContextType | undefined>(
2324
undefined
2425
);
2526

@@ -68,71 +69,43 @@ export const Provider: React.FC<ProviderProps> = ({
6869
extraWalletProviders = [],
6970
rpcUrl = '',
7071
}) => {
71-
const [signer, setSigner] = React.useState<null | JsonRpcSigner>();
72+
const [web3Modal, setWeb3Modal] = useState<Web3Modal>();
73+
const [signer, setSigner] = useState<null | JsonRpcSigner>();
74+
const [error, setError] = useState<string>();
7275
const [provider, setProvider] =
73-
React.useState<ethers.providers.Web3Provider | null>();
74-
const [userAddress, setUserAddress] = React.useState<null | string>();
75-
const [web3Modal, setWeb3Modal] = React.useState<Web3Modal>();
76-
const [chainId, setChainId] = React.useState<number | null>();
77-
const [connected, setConnected] = React.useState<boolean>(false);
78-
const [correctNetwork, setCorrectNetwork] = React.useState<boolean>(true);
76+
useState<ethers.providers.Web3Provider | null>();
77+
const [userAddress, setUserAddress] = useState<null | string>();
78+
const [chainId, setChainId] = useState<number | null>();
79+
const [connected, setConnected] = useState<boolean>(false);
80+
const [correctNetwork, setCorrectNetwork] = useState<boolean>(true);
7981
const readOnlyProvider = useReadOnlyProvider(rpcUrl);
8082

81-
const connectWallet = React.useCallback(async () => {
82-
const defaulProviderOptions = {
83-
walletconnect: {
84-
package: WalletConnectProvider,
85-
options: {
86-
bridge: 'https://polygon.bridge.walletconnect.org',
87-
infuraId,
88-
rpc: {
89-
1: `https://mainnet.infura.io/v3/${infuraId}`, // mainnet // For more WalletConnect providers: https://docs.walletconnect.org/quick-start/dapps/web3-provider#required
90-
4: `https://rinkeby.infura.io/v3/${infuraId}`,
91-
42: `https://kovan.infura.io/v3/${infuraId}`,
92-
100: 'https://dai.poa.network', // xDai
93-
},
83+
const defaulProviderOptions = {
84+
walletconnect: {
85+
package: WalletConnectProvider,
86+
options: {
87+
bridge: 'https://polygon.bridge.walletconnect.org',
88+
infuraId,
89+
rpc: {
90+
1: `https://mainnet.infura.io/v3/${infuraId}`, // mainnet // For more WalletConnect providers: https://docs.walletconnect.org/quick-start/dapps/web3-provider#required
91+
4: `https://rinkeby.infura.io/v3/${infuraId}`,
92+
42: `https://kovan.infura.io/v3/${infuraId}`,
93+
100: 'https://dai.poa.network', // xDai
9494
},
9595
},
96-
};
97-
const web3Modal = new Web3Modal({
98-
providerOptions: Object.assign(
99-
defaulProviderOptions,
100-
...extraWalletProviders
101-
),
102-
});
103-
setWeb3Modal(web3Modal);
104-
const connection = await web3Modal.connect();
105-
const provider = new ethers.providers.Web3Provider(connection);
106-
setProvider(provider);
107-
const chainId = await provider
108-
.getNetwork()
109-
.then((network) => network.chainId);
110-
setChainId(chainId);
111-
setCorrectNetwork(chainId === network);
112-
const signer = provider.getSigner();
113-
setSigner(signer);
114-
setUserAddress(await signer.getAddress());
115-
setConnected(true);
96+
},
97+
};
11698

117-
connection.on('chainChanged', async (newChainId: string) => {
118-
const formattedChainId = +newChainId.split('0x')[1];
119-
setChainId(formattedChainId);
120-
setCorrectNetwork(formattedChainId === network);
121-
const provider = new ethers.providers.Web3Provider(connection);
122-
setProvider(provider);
123-
const signer = provider.getSigner();
124-
setSigner(signer);
125-
setUserAddress(await signer.getAddress());
126-
setConnected(true);
127-
});
128-
129-
connection.on('accountsChanged', async (accounts: string[]) => {
130-
if (accounts.length === 0) {
131-
// The user has disconnected their account from Metamask
132-
web3Modal?.clearCachedProvider();
133-
disconnectWallet();
134-
return;
135-
}
99+
const connectWallet = useCallback(async () => {
100+
try {
101+
const web3Modal = new Web3Modal({
102+
providerOptions: Object.assign(
103+
defaulProviderOptions,
104+
...extraWalletProviders
105+
),
106+
});
107+
setWeb3Modal(web3Modal);
108+
const connection = await web3Modal.connect();
136109
const provider = new ethers.providers.Web3Provider(connection);
137110
setProvider(provider);
138111
const chainId = await provider
@@ -144,36 +117,63 @@ export const Provider: React.FC<ProviderProps> = ({
144117
setSigner(signer);
145118
setUserAddress(await signer.getAddress());
146119
setConnected(true);
147-
});
148120

149-
connection.on('disconnect', async () => {
150-
web3Modal?.clearCachedProvider();
151-
disconnectWallet();
152-
});
153-
}, [
154-
Web3Modal,
155-
web3Modal,
156-
WalletConnectProvider,
157-
network,
158-
infuraId,
159-
ethers,
160-
correctNetwork,
161-
]);
121+
connection.on('chainChanged', async (newChainId: string) => {
122+
const formattedChainId = +newChainId.split('0x')[1];
123+
setChainId(formattedChainId);
124+
setCorrectNetwork(formattedChainId === network);
125+
const provider = new ethers.providers.Web3Provider(connection);
126+
setProvider(provider);
127+
const signer = provider.getSigner();
128+
setSigner(signer);
129+
setUserAddress(await signer.getAddress());
130+
setConnected(true);
131+
});
132+
133+
connection.on('accountsChanged', async (accounts: string[]) => {
134+
if (accounts.length === 0) {
135+
// The user has disconnected their account from Metamask
136+
web3Modal?.clearCachedProvider();
137+
disconnectWallet();
138+
return;
139+
}
140+
const provider = new ethers.providers.Web3Provider(connection);
141+
setProvider(provider);
142+
const chainId = await provider
143+
.getNetwork()
144+
.then((network) => network.chainId);
145+
setChainId(chainId);
146+
setCorrectNetwork(chainId === network);
147+
const signer = provider.getSigner();
148+
setSigner(signer);
149+
setUserAddress(await signer.getAddress());
150+
setConnected(true);
151+
});
152+
153+
connection.on('disconnect', async () => {
154+
web3Modal?.clearCachedProvider();
155+
disconnectWallet();
156+
});
157+
} catch (err: any) {
158+
setError(err?.message || err.toString());
159+
}
160+
}, [network, correctNetwork, infuraId, extraWalletProviders]);
162161

163-
const disconnectWallet = React.useCallback(() => {
162+
const disconnectWallet = useCallback(() => {
164163
web3Modal?.clearCachedProvider();
165164
setSigner(null);
166165
setUserAddress(null);
167166
setConnected(false);
168167
}, [web3Modal]);
169168

170-
const value = React.useMemo(
169+
const value = useMemo(
171170
() => ({
172171
connectWallet,
173172
signer,
174173
userAddress,
175174
disconnectWallet,
176175
connected,
176+
error,
177177
provider,
178178
network,
179179
chainId,
@@ -184,6 +184,7 @@ export const Provider: React.FC<ProviderProps> = ({
184184
connectWallet,
185185
signer,
186186
userAddress,
187+
error,
187188
web3Modal,
188189
connected,
189190
provider,

packages/hooks/src/hooks/useWallet.ts

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
1-
import React from 'react';
1+
import { useContext, useEffect, useState } from 'react';
22
import { CHAIN_ID_TO_NETWORK, NETWORKS } from '..';
33
import { Web3Context } from '../Provider';
44

55
/**
66
* @dev Hook to get the current web3 context including information about the connection and other helper methods.
77
*/
88
export function useWallet() {
9-
const context = React.useContext(Web3Context);
10-
const [ens, setEns] = React.useState<string>();
9+
const context = useContext(Web3Context);
10+
const [ens, setEns] = useState<string>();
1111

1212
if (!context) {
1313
throw new Error('No Web3Context found');
@@ -18,6 +18,7 @@ export function useWallet() {
1818
disconnectWallet,
1919
userAddress,
2020
chainId,
21+
error,
2122
signer,
2223
connected,
2324
provider,
@@ -26,7 +27,7 @@ export function useWallet() {
2627
readOnlyProvider,
2728
} = context;
2829

29-
React.useEffect(() => {
30+
useEffect(() => {
3031
if (userAddress && provider && chainId === NETWORKS.mainnet) {
3132
provider.lookupAddress(userAddress).then((address) => {
3233
setEns(address as string);
@@ -76,6 +77,7 @@ export function useWallet() {
7677
return {
7778
connectWallet,
7879
disconnectWallet,
80+
error,
7981
connection: {
8082
userAddress,
8183
network: CHAIN_ID_TO_NETWORK[chainId as number],

0 commit comments

Comments
 (0)