Skip to content

Commit f95d2dd

Browse files
feat/network switch component (#311)
* Add <NetworkSwitch/> component * Add story for `<NetworkSwitch />` component * feat(hooks): add `useChainId()` * feat(utils): add `switchNetwork()` * refactor(useWallet): use util method `switchNetwork()` * Add changeset Co-authored-by: Dhaiwat Pandya <[email protected]>
1 parent 37f0c87 commit f95d2dd

File tree

8 files changed

+88
-25
lines changed

8 files changed

+88
-25
lines changed

.changeset/angry-pianos-destroy.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
---
2+
'@web3-ui/core': minor
3+
'@web3-ui/hooks': minor
4+
---
5+
6+
Add `NetworkSwitch` component and `useChainId` hook
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
import React from 'react';
2+
import { NetworkSwitch } from '.';
3+
import { NETWORKS } from '@web3-ui/core';
4+
5+
const { mainnet, rinkeby, ropsten, polygon } = NETWORKS;
6+
7+
const networks = [mainnet, rinkeby, ropsten, polygon];
8+
9+
export default {
10+
title: 'Core/NetworkSwitch',
11+
component: NetworkSwitch,
12+
};
13+
14+
export const Default = () => {
15+
return <NetworkSwitch networks={networks} />;
16+
};
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
import React from 'react';
2+
import { CHAIN_ID_TO_NETWORK } from '@web3-ui/hooks';
3+
import { Select, SelectProps } from '@chakra-ui/react';
4+
import { useChainId } from '@web3-ui/hooks/src/hooks';
5+
import { switchNetwork } from '@web3-ui/hooks/src/utils';
6+
7+
export interface NetworkSwitchProps {
8+
/**
9+
* The chain IDs (in base 10) that the component should display as options
10+
*/
11+
networks: number[];
12+
}
13+
14+
/**
15+
* A component to switch between a number of specified networks.
16+
*/
17+
export const NetworkSwitch: React.FC<NetworkSwitchProps & SelectProps> = ({
18+
networks,
19+
...props
20+
}) => {
21+
const chainId = useChainId();
22+
const handleChange = (e: React.ChangeEvent<HTMLSelectElement>): void => {
23+
const networkNum = Number(e.target.value);
24+
switchNetwork(networkNum);
25+
};
26+
return (
27+
<Select {...props} value={Number(chainId)} onChange={handleChange}>
28+
{networks.map((network) => (
29+
<option value={network}>{CHAIN_ID_TO_NETWORK[network]}</option>
30+
))}
31+
</Select>
32+
);
33+
};
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export { NetworkSwitch } from './NetworkSwitch';

packages/hooks/src/hooks/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,3 +5,4 @@ export { useTokenBalance } from './useTokenBalance';
55
export { useReadOnlyProvider } from './useReadOnlyProvider';
66
export { useReadOnlyContract } from './useReadOnlyContract';
77
export { usePoller } from './usePoller';
8+
export { useChainId } from './useChainId';
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
import { useState, useEffect } from 'react';
2+
3+
export const useChainId = (): string | undefined => {
4+
const [chainId, setChainId] = useState<string | undefined>();
5+
useEffect(() => {
6+
window.ethereum.on('chainChanged', setChainId);
7+
window.ethereum.request({ method: 'eth_chainId' }).then(setChainId);
8+
}, []);
9+
return chainId;
10+
};

packages/hooks/src/hooks/useWallet.ts

Lines changed: 2 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { useContext, useEffect, useState } from 'react';
22
import { CHAIN_ID_TO_NETWORK, NETWORKS } from '..';
33
import { Web3Context } from '../Provider';
4+
import { switchNetwork } from '../utils';
45

56
/**
67
* @dev Hook to get the current web3 context including information about the connection and other helper methods.
@@ -36,31 +37,7 @@ export function useWallet() {
3637
}, [userAddress, provider]);
3738

3839
const switchToCorrectNetwork = async () => {
39-
if (window.ethereum) {
40-
try {
41-
console.log('chainId', { chainId });
42-
console.log('requiredNetwork', { network });
43-
const hexNetwork = network?.toString(16);
44-
// check if the chain to connect to is installed
45-
await window.ethereum.request({
46-
method: 'wallet_switchEthereumChain',
47-
params: [{ chainId: `0x${hexNetwork}` }], // chainId must be in hexadecimal numbers
48-
});
49-
} catch (error) {
50-
console.error(error);
51-
// This error code indicates that the chain has not been added to MetaMask.
52-
// If it is not, then install it into the user's MetaMask
53-
// @ts-expect-error unknown error type
54-
if (error.code === 4902) {
55-
alert('Please add the network to your MetaMask');
56-
}
57-
}
58-
} else {
59-
// if window.ethereum is undefined then MetaMask is not installed
60-
alert(
61-
'Switching networks automatically is only supported in MetaMask. Please consider installing it: https://metamask.io/download.html'
62-
);
63-
}
40+
if (network) switchNetwork(network);
6441
};
6542

6643
return {

packages/hooks/src/utils.ts

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
export const convertToHexStr = (num: number) => num.toString(16);
2+
3+
export const switchNetwork = async (networkId: number) => {
4+
const networkHex = `0x${convertToHexStr(networkId)}`;
5+
if (window.ethereum) {
6+
try {
7+
await window.ethereum.request({
8+
method: 'wallet_switchEthereumChain',
9+
params: [{ chainId: networkHex }],
10+
});
11+
} catch (error) {
12+
console.log(error);
13+
}
14+
} else {
15+
alert(
16+
'Switching networks automatically is only supported in MetaMask. Please consider installing it: https://metamask.io/download.html'
17+
);
18+
}
19+
};

0 commit comments

Comments
 (0)