들어가며
메타마스크 지갑 연결 부분은 아래 포스팅에 설명되어 있습니다. 본 글은 전 글에 이어 chain id를 가지고 네트워크를 변경 및 추가하는 내용만을 정리하였습니다.
https://3d-yeju.tistory.com/90
BSC (chain id: 56), Binance Smart Contract의 네트워크를 추가해 보겠습니다. 네트워크를 추가하는 작업은 사용자가 직접 메타마스크 지갑 안에서 추가할 수도 있지만 서비스 내에서 사용하는 네트워크를 추가하기 위해 사용자가 직접 설정한다는 것은 사용자 경험이 매우 떨어질 겁니다.🤔
💡지갑 연결 및 네트워크 설정 프로세스
지갑연결 ➡️ 네트워크가 일치하지 않다면, 네트워크 변경 ➡️ 변경할 네트워크가 추가되어있지 않다면, 네트워크 추가 ➡️ 네트워크 설정을 맞힌 뒤 지갑재연결
에러코드에 네트워크 설정 로직 추가하기
각 지갑에 맞는 connector을 activate 메소드에 전달하면서, 현재 지갑에 연결되어 있는 네트워크가 설정한 값과 일치하다면 지갑 연결 및 서명을 진행하고 일치하지 않다면 네트워크를 변경하거나 추가하는 과정이 필요합니다.
메타마스크 지갑에 네트워크가 추가되어 있을 때는 네트워크를 변경하는 프로세스를 진행하고, 추가되어있지 않을 때에는 네트워크를 추가하는 프로세스를 진행합니다.
// src > utils > web3 > web3Connector.ts
import { InjectedConnector } from '@web3-react/injected-connector';
const chainId = 56; // BSC mainnet network
const injected = new InjectedConnector({ supportedChainIds: [chainId] });
export const connectors = {
injected: injected, // metamask용 connector
};
// src > hooks > useAuth.ts
import { useCallback } from 'react';
import { UnsupportedChainIdError, useWeb3React } from '@web3-react/core';
import {
NoEthereumProviderError,
UserRejectedRequestError as UserRejectedRequestErrorInjected,
} from '@web3-react/injected-connector';
import { connectors } from '../utils/web3/web3Connector';
const useAuth = () => {
const { activate, deactivate } = useWeb3React();
const login = useCallback(() => {
if (connectors.injected) {
activate(connectors.injected, async (error: Error) => {
if (error instanceof NoEthereumProviderError) {
// 지갑이 설치되어있지 않은 경우
} else if (error instanceof UnsupportedChainIdError) {
// 지원하지 않는 네트워크일 경우
const hasSetup = await setupNetwork();
if (hasSetup) {
activate(connectors.injected);
}
} else if (error instanceof UserRejectedRequestErrorInjected) {
// 유저가 지갑 연결을 거부한 경우
} else {
console.log('otherError', error);
}
});
}
}, []);
return { login };
};
export default useAuth;
UnsupportedChainIdError 에러에서 네트워크를 변경하고 추가하는 util 함수인 setupNetwork() 에서 프로세스 진행 시에 true 값을 반환하여 다시 지갑 연결을 시도하는 로직을 추가해 줍니다.
네트워크 변경 및 추가
// src > utils > web3 > setupNetwork.ts
import Web3 from 'web3';
const web3 = new Web3(window.ethereum);
const getNetworkId = async () => {
const currentChainId = await web3.eth.net.getId();
return currentChainId;
};
export const setupNetwork = async () => {
const provider = window.ethereum;
if (provider) {
const chainId = 56;
const currentChainId = await getNetworkId();
if (currentChainId !== chainId) {
try {
await provider.request({
method: 'wallet_switchEthereumChain',
params: [{ chainId: Web3.utils.toHex(chainId) }],
});
return true;
} catch (switchError: any) {
console.log('switchError', switchError);
if (switchError.code === 4902 || switchError.code === -32603) {
if (chainId === 56) {
try {
await provider.request({
method: 'wallet_addEthereumChain',
params: [
{
chainId: '0x38',
chainName: 'BSC Mainnet',
nativeCurrency: {
name: 'Binance Coin',
symbol: 'BNB',
decimals: 18,
},
rpcUrls: ['https://bsc-dataseed1.binance.org/'],
blockExplorerUrls: ['https://bscscan.com'],
},
],
});
return true;
} catch (addError) {
console.log('addError', addError);
}
} else {
alert(`add this chain id: ${chainId}`);
}
}
}
}
} else {
console.error(
"Can't setup the BSC network on metamask because window.ethereum is undefined"
);
return false;
}
};
1. web3 인스턴스를 생성해 줍니다.
const web3 = new Web3(window.ethereum);
2. 현재 지갑과 연결되어 있는 네트워크 chainId를 가져와 변경하려는 chainId 값을 비교합니다.
const getNetworkId = async () => {
const currentChainId = await web3.eth.net.getId();
return currentChainId;
};
*이 이후 과정은 try ~ catch를 사용하여 에러처리가 필요합니다.
3. 값이 다르다면 네트워크 변경을 요청합니다.
await provider.request({
method: 'wallet_switchEthereumChain',
params: [{ chainId: Web3.utils.toHex(chainId) }],
});
4. 네트워크를 변경하는 과정에서 지갑에 추가되어있지 않는 네트워크라면 에러코드를 4902 , -32603으로 전달합니다. 위 두 코드를 분기처리하여 BSC mainnet 네트워크를 추가하여 줍니다.
'Unrecognized chain ID "0x38". Try adding the chain using wallet_addEthereumChain first.' 에러코드를 잘 읽어보면 해당하는 chain id를 찾을 수 없으니 wallet_addEthereumChain를 먼저 실행하여야 한다고 친절하게 알려줍니다.
BSC data 설정값: https://academy.binance.com/en/articles/connecting-metamask-to-binance-smart-chain
if (switchError.code === 4902 || switchError.code === -32603) {
if (chainId === 56) {
try {
await provider.request({
method: 'wallet_addEthereumChain',
params: [
{
chainId: '0x38',
chainName: 'BSC Mainnet',
nativeCurrency: {
name: 'Binance Coin',
symbol: 'BNB',
decimals: 18,
},
rpcUrls: ['https://bsc-dataseed1.binance.org/'],
blockExplorerUrls: ['https://bscscan.com'],
},
],
});
return true;
} catch (addError) {
console.log('addError', addError);
}
} else {
alert(`add this chain id: ${chainId}`);
}
}
📌 모바일로 메타마스크 앱을 사용하는 경우에는, 에러코드가 -32603으로 전달하기 때문에 꼭 추가해주어야 합니다.
https://github.com/MetaMask/metamask-mobile/issues/3629
https://academy.binance.com/en/articles/connecting-metamask-to-binance-smart-chain
https://ethereum.stackexchange.com/questions/93594/add-custom-networkbnb-in-meta-mask-using-web3
'Web > React & Next.js' 카테고리의 다른 글
Next.js | Next.js + Styled-Components 초기 세팅 (next 13) (0) | 2023.02.14 |
---|---|
Next.js | Next.js + typescript 초기 세팅 (next 13) (0) | 2023.02.14 |
React | axios interceptors header에 token값 설정&추가하기, 삭제하기 (0) | 2023.01.17 |
React | web3-react를 사용하여 메타마스크(Metamask) 서명 요청하기 (0) | 2023.01.17 |
React | web3-react를 사용하여 메타마스크(Metamask) 지갑연결하기 (0) | 2023.01.16 |