diff --git a/apps/godwoken-bridge/src/contexts/LightGodwokenContext.tsx b/apps/godwoken-bridge/src/contexts/LightGodwokenContext.tsx index 60296730..4c012334 100644 --- a/apps/godwoken-bridge/src/contexts/LightGodwokenContext.tsx +++ b/apps/godwoken-bridge/src/contexts/LightGodwokenContext.tsx @@ -1,4 +1,5 @@ import { isMainnet } from "../utils/environment"; +import { providers } from "ethers"; import { useLocation } from "react-router-dom"; import detectEthereumProvider from "@metamask/detect-provider"; import React, { createContext, useEffect, useState } from "react"; @@ -14,39 +15,41 @@ export const Provider: React.FC = (props) => { const network = isMainnet ? GodwokenNetwork.Mainnet : GodwokenNetwork.Testnet; + async function updateLightGodwokenByAccounts(ethereum: providers.ExternalProvider, accounts?: string[]) { + if (!accounts || accounts.length === 0) { + setLightGodwoken(void 0); + return; + } + if (location.pathname.startsWith("/v0") && lightGodwoken?.getVersion() !== GodwokenVersion.V0) { + setLightGodwoken(createLightGodwokenV0(accounts[0], network, ethereum)); + return; + } + if (location.pathname.startsWith("/v1") && lightGodwoken?.getVersion() !== GodwokenVersion.V1) { + setLightGodwoken(createLightGodwokenV1(accounts[0], network, ethereum)); + return; + } + } + async function updateLightGodwokenByEthereum(ethereum: providers.ExternalProvider) { + const accounts = await ethereum.request?.({ method: "eth_accounts" }); + return updateLightGodwokenByAccounts(ethereum, accounts); + } + useEffect(() => { detectEthereumProvider().then((ethereum: any) => { if (ethereum) { - ethereum.request({ method: "eth_accounts" }).then((accounts: string[]) => { - if (accounts.length === 0) { - return setLightGodwoken(void 0); - } + updateLightGodwokenByEthereum(ethereum); - if (location.pathname.startsWith("/v0") && lightGodwoken?.getVersion() !== GodwokenVersion.V0) { - setLightGodwoken(createLightGodwokenV0(accounts[0], network, ethereum)); - } else if (location.pathname.startsWith("/v1") && lightGodwoken?.getVersion() !== GodwokenVersion.V1) { - setLightGodwoken(createLightGodwokenV1(accounts[0], network, ethereum)); - } + ethereum.on("chainChanged", () => { + updateLightGodwokenByEthereum(ethereum); }); - - ethereum.on("accountsChanged", (accounts: string[] | undefined) => { - if (!accounts || accounts.length === 0) { - return setLightGodwoken(void 0); - } - - let instance: LightGodwoken; - if (location.pathname.startsWith("/v0")) { - instance = createLightGodwokenV0(accounts[0], network, ethereum); - } else { - instance = createLightGodwokenV1(accounts[0], network, ethereum); - } - - setLightGodwoken(instance); + ethereum.on("accountsChanged", (accounts?: string[]) => { + updateLightGodwokenByAccounts(ethereum, accounts); }); } else { alert("Please install MetaMask to use Godwoken Bridge!"); } }); + // eslint-disable-next-line react-hooks/exhaustive-deps }, [lightGodwoken, location.pathname, network]); return ( diff --git a/apps/godwoken-bridge/src/hooks/useL2CKBBalance.ts b/apps/godwoken-bridge/src/hooks/useL2CKBBalance.ts index 609767f1..98407c47 100644 --- a/apps/godwoken-bridge/src/hooks/useL2CKBBalance.ts +++ b/apps/godwoken-bridge/src/hooks/useL2CKBBalance.ts @@ -1,16 +1,32 @@ import { useQuery, UseQueryResult } from "react-query"; import { useLightGodwoken } from "./useLightGodwoken"; +import { useUpdateEffect } from "ahooks"; +import { useState } from "react"; export const useL2CKBBalance = (): UseQueryResult => { + const [id, setId] = useState(Math.random()); const lightGodwoken = useLightGodwoken(); - return useQuery( - ["queryL2CKBBalance", { version: lightGodwoken?.getVersion(), l2Address: lightGodwoken?.provider.getL2Address() }], + const query = useQuery( + [ + "queryL2CKBBalance", + { + id, + version: lightGodwoken?.getVersion(), + l2Address: lightGodwoken?.provider.getL2Address(), + }, + ], () => { - return lightGodwoken?.getL2CkbBalance(); + return lightGodwoken!.getL2CkbBalance(); }, { enabled: !!lightGodwoken, }, ); + + useUpdateEffect(() => { + setId(Math.random()); + }, [lightGodwoken]); + + return query as UseQueryResult; }; diff --git a/apps/godwoken-bridge/src/utils/addNetwork.ts b/apps/godwoken-bridge/src/utils/addNetwork.ts index d83f30fd..4bb51a80 100644 --- a/apps/godwoken-bridge/src/utils/addNetwork.ts +++ b/apps/godwoken-bridge/src/utils/addNetwork.ts @@ -2,26 +2,38 @@ import { LightGodwokenV1, EthereumProvider } from "light-godwoken"; export const addNetwork = async (ethereum: EthereumProvider, lightGodwokenV1: LightGodwokenV1) => { const chainId = await lightGodwokenV1.getChainId(); - const layer2Config = lightGodwokenV1.getConfig().layer2Config; - const nativeToken = lightGodwokenV1.getNativeAsset(); - - const params = [ - { - chainId: chainId, - chainName: layer2Config.CHAIN_NAME, - nativeCurrency: { - name: nativeToken.name, - symbol: nativeToken.symbol, - decimals: nativeToken.decimals, - }, - rpcUrls: [layer2Config.GW_POLYJUICE_RPC_URL], - blockExplorerUrls: [layer2Config.SCANNER_URL], - }, - ]; try { - await ethereum.send("wallet_addEthereumChain", params); + await ethereum.send("wallet_switchEthereumChain", [ + { + chainId, + }, + ]); } catch (error: any) { - console.log("Error", error.message); + console.log("wallet_switchEthereumChain", error.message); + + // If the network doesn't exist + if (error?.code === 4902) { + const layer2Config = lightGodwokenV1.getConfig().layer2Config; + const nativeToken = lightGodwokenV1.getNativeAsset(); + + try { + await ethereum.send("wallet_addEthereumChain", [ + { + chainId: chainId, + chainName: layer2Config.CHAIN_NAME, + nativeCurrency: { + name: nativeToken.name, + symbol: nativeToken.symbol, + decimals: nativeToken.decimals, + }, + rpcUrls: [layer2Config.GW_POLYJUICE_RPC_URL], + blockExplorerUrls: [layer2Config.SCANNER_URL], + }, + ]); + } catch (error: any) { + console.log("wallet_addEthereumChain", error.message); + } + } } }; diff --git a/apps/godwoken-bridge/src/views/GodwokenBridge.tsx b/apps/godwoken-bridge/src/views/GodwokenBridge.tsx index 27f9d8d5..a83ed57e 100644 --- a/apps/godwoken-bridge/src/views/GodwokenBridge.tsx +++ b/apps/godwoken-bridge/src/views/GodwokenBridge.tsx @@ -1,5 +1,5 @@ import "antd/dist/antd.css"; -import React from "react"; +import React, { useEffect } from "react"; import { Navigate, Outlet, useParams } from "react-router-dom"; import Page from "../components/Layout/Page"; import PageHeader from "../components/Layout/PageHeader"; @@ -11,12 +11,20 @@ import { availableVersions } from "../utils/environment"; export default function GodwokenBridge() { const lightGodwoken = useLightGodwoken(); - if (lightGodwoken instanceof LightGodwokenV1) { - addNetwork(lightGodwoken.provider.ethereum, lightGodwoken); - } const params = useParams(); const version = params.version; + + useEffect(() => { + if (lightGodwoken instanceof LightGodwokenV1) { + const ethereum = lightGodwoken.provider.ethereum; + addNetwork(ethereum, lightGodwoken); + (ethereum.provider as any).provider.on?.("chainChanged", () => { + addNetwork(ethereum, lightGodwoken); + }); + } + }, [lightGodwoken, params]); + if (!version || !availableVersions.includes(version as GodwokenVersion)) { return ; }