From f386d8e4f4705c432aaa6439ab6f0b3c563fce86 Mon Sep 17 00:00:00 2001 From: michael1011 Date: Fri, 9 Aug 2024 03:44:41 +0200 Subject: [PATCH] feat: detect and switch network --- src/components/ConnectMetamask.tsx | 83 ++++++++++++++---------- src/components/ContractTransaction.tsx | 87 +++++++++++++++----------- src/config.ts | 1 + src/configs/regtest.json | 9 +++ src/configs/testnet.json | 9 +++ src/context/Web3.tsx | 78 +++++++++++++++++++---- src/i18n/i18n.ts | 1 + src/utils/boltzClient.ts | 1 + 8 files changed, 186 insertions(+), 83 deletions(-) diff --git a/src/components/ConnectMetamask.tsx b/src/components/ConnectMetamask.tsx index f5e34eb9..93d809f3 100644 --- a/src/components/ConnectMetamask.tsx +++ b/src/components/ConnectMetamask.tsx @@ -149,26 +149,45 @@ export const ConnectAddress = ({ address }: { address: string }) => { const { connectProviderForAddress } = useWeb3Signer(); return ( - <> - - + + ); +}; + +export const SwitchNetwork = () => { + const { t, notify } = useGlobalContext(); + const { switchNetwork } = useWeb3Signer(); + + return ( + ); }; @@ -186,21 +205,17 @@ const ConnectMetamask = () => { }); return ( - <> - 0} - fallback={ - - }> - }> - - + 0} + fallback={ + + }> + }> + - + ); }; diff --git a/src/components/ContractTransaction.tsx b/src/components/ContractTransaction.tsx index d8ea438c..eceade95 100644 --- a/src/components/ContractTransaction.tsx +++ b/src/components/ContractTransaction.tsx @@ -1,10 +1,10 @@ import log from "loglevel"; -import { Show, createSignal } from "solid-js"; +import { Show, createEffect, createSignal } from "solid-js"; import { useGlobalContext } from "../context/Global"; import { useWeb3Signer } from "../context/Web3"; import { formatError } from "../utils/errors"; -import { ConnectAddress } from "./ConnectMetamask"; +import { ConnectAddress, SwitchNetwork } from "./ConnectMetamask"; import LoadingSpinner from "./LoadingSpinner"; const ContractTransaction = ({ @@ -23,49 +23,62 @@ const ContractTransaction = ({ waitingText?: string; }) => { const { notify } = useGlobalContext(); - const { signer } = useWeb3Signer(); + const { signer, getContracts } = useWeb3Signer(); const [txSent, setTxSent] = createSignal(false); const [clicked, setClicked] = createSignal(false); + const [signerNetwork, setSignerNetwork] = createSignal( + undefined, + ); + + createEffect(async () => { + const network = await signer()?.provider?.getNetwork(); + setSignerNetwork(Number(network?.chainId)); + }); + return ( }> - -

{waitingText}

-
- - - }> - -

{promptText}

-
- - -
+ when={getContracts().network.chainId === signerNetwork()} + fallback={}> + + +

{waitingText}

+
+ + + }> + +

{promptText}

+
+ + +
+
diff --git a/src/config.ts b/src/config.ts index 5ad6a80f..98ceb9eb 100644 --- a/src/config.ts +++ b/src/config.ts @@ -28,6 +28,7 @@ const defaults = { type Asset = { apiUrl?: Url; + network?: any; blockExplorerUrl?: Url; rifRelay?: string; diff --git a/src/configs/regtest.json b/src/configs/regtest.json index e53c7af2..434b18d1 100644 --- a/src/configs/regtest.json +++ b/src/configs/regtest.json @@ -19,6 +19,15 @@ "blockExplorerUrl": { "normal": "http://localhost:5100" }, + "network": { + "chainName": "Anvil", + "rpcUrls": ["http://localhost:8545"], + "nativeCurrency": { + "name": "RBTC", + "symbol": "RBTC", + "decimals": 18 + } + }, "rifRelay": "http://localhost:8090", "contracts": { "smartWalletFactory": "0x59b670e9fA9D0A427751Af201D676719a970857b", diff --git a/src/configs/testnet.json b/src/configs/testnet.json index 20ffc27a..151626ae 100644 --- a/src/configs/testnet.json +++ b/src/configs/testnet.json @@ -19,6 +19,15 @@ "blockExplorerUrl": { "normal": "https://explorer.testnet.rsk.co" }, + "network": { + "chainName": "Rootstock Testnet", + "rpcUrls": ["https://public-node.testnet.rsk.co"], + "nativeCurrency": { + "name": "RBTC", + "symbol": "RBTC", + "decimals": 18 + } + }, "rifRelay": "https://boltz.testnet.relay.rifcomputing.net", "contracts": { "smartWalletFactory": "0xaa67dEDd76f9b540d3c136b1F9095696ac92A5A7", diff --git a/src/context/Web3.tsx b/src/context/Web3.tsx index 05ab2f92..04177ce1 100644 --- a/src/context/Web3.tsx +++ b/src/context/Web3.tsx @@ -5,6 +5,7 @@ import log from "loglevel"; import { Accessor, JSXElement, + Resource, createContext, createResource, createSignal, @@ -13,7 +14,7 @@ import { import { config } from "../config"; import { RBTC } from "../consts/Assets"; -import { getContracts } from "../utils/boltzClient"; +import { Contracts, getContracts } from "../utils/boltzClient"; import { useGlobalContext } from "./Global"; declare global { @@ -45,6 +46,8 @@ type EIP1193Provider = { method: string; params?: Array; }) => Promise; + on: (event: "chainChanged", cb: () => void) => void; + removeAllListeners: (event: "chainChanged") => void; }; export type EIP6963ProviderDetail = { @@ -60,9 +63,6 @@ export type Signer = JsonRpcSigner & { rdns: string; }; -// TODO: check network and add option to add RSK as network -// TODO: handle network and account change events - const Web3SignerContext = createContext<{ providers: Accessor>; connectProvider: (rdns: string) => Promise; @@ -70,6 +70,9 @@ const Web3SignerContext = createContext<{ signer: Accessor; clearSigner: () => void; + switchNetwork: () => Promise; + + getContracts: Resource; getEtherSwap: () => EtherSwap; }>(); @@ -84,7 +87,10 @@ const Web3SignerProvider = (props: { const [providers, setProviders] = createSignal< Record >({}); - const [signer, setSigner] = createSignal(); + const [signer, setSigner] = createSignal(undefined); + const [rawProvider, setRawProvider] = createSignal< + EIP1193Provider | undefined + >(undefined); window.addEventListener( "eip6963:announceProvider", @@ -105,9 +111,17 @@ const Web3SignerProvider = (props: { return undefined; } - return await getContracts(RBTC); + return (await getContracts(RBTC))["rsk"]; }); + const getEtherSwap = () => { + return new Contract( + contracts().swapContracts.EtherSwap, + EtherSwapAbi, + signer(), + ) as unknown as EtherSwap; + }; + const connectProviderForAddress = async (address: string) => connectProvider(await getRdnsForAddress(address)); @@ -127,6 +141,11 @@ const Web3SignerProvider = (props: { log.info(`Connected address from ${wallet.info.rdns}: ${addresses[0]}`); + wallet.provider.on("chainChanged", () => { + window.location.reload(); + }); + setRawProvider(wallet.provider); + const signer = new JsonRpcSigner( new BrowserProvider(wallet.provider), addresses[0], @@ -138,12 +157,40 @@ const Web3SignerProvider = (props: { setSigner(signer); }; - const getEtherSwap = () => { - return new Contract( - contracts()["rsk"].swapContracts.EtherSwap, - EtherSwapAbi, - signer(), - ) as unknown as EtherSwap; + const switchNetwork = async () => { + if (rawProvider() === undefined) { + return; + } + + const sanitizedChainId = `0x${contracts().network.chainId.toString(16)}`; + + try { + await rawProvider().request({ + method: "wallet_switchEthereumChain", + params: [ + { + chainId: sanitizedChainId, + }, + ], + }); + } catch (switchError) { + if (switchError.code === 4902) { + await rawProvider().request({ + method: "wallet_addEthereumChain", + params: [ + { + chainId: sanitizedChainId, + blockExplorerUrls: [ + config.assets[RBTC].blockExplorerUrl.normal, + ], + ...config.assets[RBTC].network, + }, + ], + }); + } + + throw switchError; + } }; return ( @@ -152,11 +199,18 @@ const Web3SignerProvider = (props: { signer, providers, getEtherSwap, + switchNetwork, connectProvider, connectProviderForAddress, + getContracts: contracts, clearSigner: () => { log.info(`Clearing connected signer`); + if (rawProvider()) { + rawProvider().removeAllListeners("chainChanged"); + } + setSigner(undefined); + setRawProvider(undefined); }, }}> {props.children} diff --git a/src/i18n/i18n.ts b/src/i18n/i18n.ts index 8ae91dfa..496a78e7 100644 --- a/src/i18n/i18n.ts +++ b/src/i18n/i18n.ts @@ -210,6 +210,7 @@ const dict = { insufficient_balance_line: "You do not have enough balance in your wallet for this swap.", select_wallet: "Select wallet", + switch_network: "Switch network", }, de: { language: "Deutsch", diff --git a/src/utils/boltzClient.ts b/src/utils/boltzClient.ts index 60e6a060..1dfe6997 100644 --- a/src/utils/boltzClient.ts +++ b/src/utils/boltzClient.ts @@ -88,6 +88,7 @@ type PartialSignature = { type Contracts = { network: { + name: string; chainId: number; }; tokens: Record;