diff --git a/src/components/arbitrum/Connect.tsx b/src/components/arbitrum/Connect.tsx index c819893..3c24704 100644 --- a/src/components/arbitrum/Connect.tsx +++ b/src/components/arbitrum/Connect.tsx @@ -1,11 +1,11 @@ -import { useState } from 'react'; +import { useEffect, useState } from 'react'; import { MetamaskConnect } from './MetamaskConnect'; import { Project } from './Project'; import { Client } from '@remixproject/plugin'; import { Api } from '@remixproject/plugin-utils'; import { IRemixApi } from '@remixproject/plugin-api'; import { Connect as CommonConnect } from '../common/Connect'; -import { ARBITRUM_SEPOLIA_CHAIN } from './const'; +import { ARBITRUM_ONE_CHAIN, ARBITRUM_SEPOLIA_CHAIN } from './const'; interface InterfaceProps { client: Client>; @@ -39,7 +39,7 @@ export const Connect: React.FunctionComponent = ({ client }) => setInjectedProvider={setInjectedProvider} setProviderNetwork={setProviderNetwork} /> - {providerNetwork === ARBITRUM_SEPOLIA_CHAIN.chainId ? ( + {[ARBITRUM_SEPOLIA_CHAIN.chainId, ARBITRUM_ONE_CHAIN.chainId].includes(providerNetwork) ? ( = ({ client, active, @@ -31,154 +68,239 @@ export const MetamaskConnect: React.FunctionComponent = ({ setActive, }) => { const [balance, setBalance] = useState(''); - const [error, setError] = useState(''); - const [network, setNetwork] = useState(''); + const [error, setError] = useState(''); + const [network, setNetwork] = useState(null); + + const networks: INetworkInfo[] = useMemo( + () => [ + { + chainName: ARBITRUM_ONE_CHAIN.chainName, + value: ARBITRUM_ONE_CHAIN.chainId, + rpcUrls: ['https://arb1.arbitrum.io/rpc'], + blockExplorerUrls: ['https://arbiscan.io/'], + }, + { + chainName: ARBITRUM_SEPOLIA_CHAIN.chainName, + value: ARBITRUM_SEPOLIA_CHAIN.chainId, + rpcUrls: ['https://sepolia-rollup.arbitrum.io/rpc'], + blockExplorerUrls: ['https://sepolia-rollup-explorer.arbitrum.io/'], + }, + ], + [], + ); const ethereum = (window as any).ethereum; - let networkName = ''; - if (network === ARBITRUM_SEPOLIA_CHAIN.chainId) { - networkName = ARBITRUM_SEPOLIA_CHAIN.chainName; - } - // Establish a connection to the Aptos blockchain on component mount - useEffect(() => { - const switchNetwork = async () => { - try { - await ethereum.request({ - method: 'wallet_switchEthereumChain', - params: [{ chainId: ARBITRUM_SEPOLIA_CHAIN.chainId }], - }); - } catch (error) { - if (typeof error === 'object' && error !== null && 'code' in error) { - const err = error as { code: number }; - if (err.code === 4902) { - await ethereum.request({ - method: 'wallet_addEthereumChain', - params: [ - { - chainName: 'Arbitrum Sepolia', - chainId: ARBITRUM_SEPOLIA_CHAIN.chainId, - nativeCurrency: { name: 'Arbitrum', symbol: 'ETH', decimals: 18 }, - rpcUrls: ['https://sepolia-rollup.arbitrum.io/rpc'], - blockExplorerUrls: ['https://sepolia.arbiscan.io'], - }, - ], - }); - } - } - } - }; - const fetchAndSetBalance = async (account: string) => { + + const getAccount = async () => { + try { + const accounts = await ethereum.request({ method: 'eth_requestAccounts' }); + return accounts[0]; + } catch (error) { + setError('Failed to fetch accounts'); + return null; + } + }; + + const getChainId = async () => { + try { + const chainId = await ethereum.request({ method: 'eth_chainId' }); + return chainId; + } catch (error) { + setError('Failed to fetch chainId'); + return null; + } + }; + + const getBalances = async (userAccount: string): Promise => { + try { const balance = await ethereum.request({ method: 'eth_getBalance', - params: [account, 'latest'], + params: [userAccount, 'latest'], }); const formattedBalance = web3.utils.fromWei(balance, 'ether'); - setBalance(parseFloat(formattedBalance).toFixed(4)); - }; - const connectMetamask = async () => { - if (!ethereum) { - setError('Please install MetaMask'); - return; - } + return parseFloat(formattedBalance).toFixed(4); + } catch (error) { + setError('Failed to fetch balance'); + return '0'; + } + }; + + const setInfo = async (currentAccount: string, targetNetwork: INetworkInfo) => { + const balance = await getBalances(currentAccount); + // general + setInjectedProvider(ethereum); + setProviderNetwork(targetNetwork.value); + // local + setNetwork(targetNetwork); + setBalance(balance); + setActive(true); + }; + + const handleNetwork = (event: React.ChangeEvent) => { + const targetNetwork = networks.find((net) => net.value === event.target.value); + if (!targetNetwork) return; + setActive(false); + setNetwork(targetNetwork); + setBalance(''); + }; - try { - ethereum.on('chainChanged', (_chainId: string) => { - if (_chainId !== ARBITRUM_SEPOLIA_CHAIN.chainId) window.location.reload(); - else { - setNetwork(_chainId); - setProviderNetwork(_chainId); - setInjectedProvider(ethereum); - } - }); - ethereum.on('accountsChanged', (accounts: string[]) => { - if (accounts.length === 0) { - setAccount(''); - setBalance(''); - setActive(false); - } else { - setAccount(accounts[0]); - fetchAndSetBalance(accounts[0]); - } - }); - const chainId = await ethereum.request({ method: 'eth_chainId' }); - if (chainId !== ARBITRUM_SEPOLIA_CHAIN.chainId) await switchNetwork(); - setNetwork(chainId); - setInjectedProvider(ethereum); - setProviderNetwork(chainId); - if (active) { - const accounts = await ethereum.request({ method: 'eth_requestAccounts' }); - setAccount(accounts[0]); - fetchAndSetBalance(accounts[0]); + const switchNetwork = async (chainId: string = ARBITRUM_ONE_CHAIN.chainId) => { + const targetNetwork = networks.find((net) => net.value === chainId); + if (!targetNetwork) return null; + try { + await ethereum.request({ + method: 'wallet_switchEthereumChain', + params: [{ chainId }], + }); + + return targetNetwork; + } catch (error) { + if (typeof error === 'object' && error !== null && 'code' in error) { + const err = error as { code: number }; + if (err.code === 4902) { + await ethereum.request({ + method: 'wallet_addEthereumChain', + params: [ + { + chainId: targetNetwork.value, + chainName: targetNetwork.chainName, + rpcUrls: targetNetwork.rpcUrls, + blockExplorerUrls: targetNetwork.blockExplorerUrls, + nativeCurrency: { name: 'Arbitrum', symbol: 'ETH', decimals: 18 }, + }, + ], + }); + return targetNetwork; } - } catch (error: any) { - if (error.message.includes('wallet_addEthereumChain')) return; - setError(error.message); - log.error(error); - await client.terminal.log({ type: 'error', value: error.message }); } - }; - - connectMetamask(); + return null; + } + }; - return () => { - ethereum.removeListener('chainChanged', () => window.location.reload()); - ethereum.removeListener('accountsChanged', () => setAccount('')); + useEffect(() => { + const activateMetamask = async () => { + if (!network) return null; + await switchNetwork(network.value); }; + if (active) activateMetamask(); }, [active]); + useEffect(() => { + const init = async () => { + const chainId = await getChainId(); + const targetNetwork = networks.find((net) => net.value === chainId); + if (!targetNetwork) await switchNetwork(); + else { + const currentAccount = await getAccount(); + setAccount(currentAccount); + setInfo(currentAccount, targetNetwork); + } + }; + + init(); + + ethereum.on('chainChanged', async (_chainId: string) => { + const targetNetwork = networks.find((net) => net.value === _chainId); + if (!targetNetwork) window.location.reload(); + else { + const currentAccount = await getAccount(); + setAccount(currentAccount); + setInfo(currentAccount, targetNetwork); + } + }); + + ethereum.on('accountsChanged', async (accounts: string[]) => { + if (accounts.length === 0) { + setAccount(''); + setBalance(''); + } else { + const currentAccount = await getAccount(); + setAccount(currentAccount); + setBalance(''); + setActive(false); + } + }); + }, []); + return (
- {network === ARBITRUM_SEPOLIA_CHAIN.chainId ? ( - + {!network ? ( + ) : ( - - {ARBITRUM_SEPOLIA_CHAIN.chainName} network is supported currently. -
- Please switch to the network below and reconnect your wallet. -
- Chain ID: 421614 -
- RPC URL: https://sepolia-rollup.arbitrum.io/rpc -
+ + {/* */} +
+ + Network + + {networks.map((network, idx) => ( + + ))} + + + + + ACCOUNT + + + + + + BALANCE + + + + + +
+
)} - {network === ARBITRUM_SEPOLIA_CHAIN.chainId ? ( -
- - - ACCOUNT - - - - - - BALANCE - - - - - -
- ) : null}
); }; +const NetworkInfo = () => ( + + {ARBITRUM_ONE_CHAIN.chainName} and {ARBITRUM_SEPOLIA_CHAIN.chainName} network is supported + currently. +
+ Please switch to the network below and reconnect your wallet. +
+
+ Arbitrum One +
+ Chain ID: 42161 +
+ RPC URL: https://arb1.arbitrum.io/rpc +
+
+ Arbitrum Sepolia +
+ Chain ID: 421614 +
+ RPC URL: https://sepolia-rollup.arbitrum.io/rpc +
+
+); + const mb4 = { marginBottom: '4px', }; diff --git a/src/components/arbitrum/const.ts b/src/components/arbitrum/const.ts index 0630752..d98a096 100644 --- a/src/components/arbitrum/const.ts +++ b/src/components/arbitrum/const.ts @@ -7,3 +7,8 @@ export const ARBITRUM_SEPOLIA_CHAIN = { chainId: '0x66eee', chainName: 'Arbitrum Sepolia (Testnet)', }; + +export const ARBITRUM_ONE_CHAIN = { + chainId: '0xa4b1', + chainName: 'Arbitrum One', +};