From 1929812d95890ab0b32a4090647153cb9821c06f Mon Sep 17 00:00:00 2001 From: Christopher Ferreira Date: Mon, 11 Nov 2024 13:22:21 +0000 Subject: [PATCH 1/4] feat: adds improved logic for chain switching in MetaMask --- packages/connectors/src/metaMask.ts | 123 +++++++++++++++------------- 1 file changed, 66 insertions(+), 57 deletions(-) diff --git a/packages/connectors/src/metaMask.ts b/packages/connectors/src/metaMask.ts index fc4e19f55a..e9d9bfd2ed 100644 --- a/packages/connectors/src/metaMask.ts +++ b/packages/connectors/src/metaMask.ts @@ -18,12 +18,17 @@ import type { RemoveUndefined, UnionCompute, } from '@wagmi/core/internal' +import { + mainnet, + sepolia, + linea, + lineaSepolia +} from '@wagmi/core/chains' import { type AddEthereumChainParameter, type Address, type Hex, type ProviderConnectInfo, - type ProviderRpcError, ResourceUnavailableRpcError, type RpcError, SwitchChainError, @@ -308,6 +313,66 @@ export function metaMask(parameters: MetaMaskParameters = {}) { const chain = config.chains.find((x) => x.id === chainId) if (!chain) throw new SwitchChainError(new ChainNotConfiguredError()) + // MetaMask default chains + // This avoids the need to react to the "unrecognized chain" error + // and consequent back and forth between MetaMask and Wagmi. + const metaMaskDefaultChains = [ + mainnet.id, + sepolia.id, + linea.id, + lineaSepolia.id + ]; + const isDefaultChain = metaMaskDefaultChains.find((x) => x === chainId) + + if (!isDefaultChain) { + try { + const { default: blockExplorer, ...blockExplorers } = + chain.blockExplorers ?? {} + let blockExplorerUrls: string[] | undefined + if (addEthereumChainParameter?.blockExplorerUrls) + blockExplorerUrls = addEthereumChainParameter.blockExplorerUrls + else if (blockExplorer) + blockExplorerUrls = [ + blockExplorer.url, + ...Object.values(blockExplorers).map((x) => x.url), + ] + + let rpcUrls: readonly string[] + if (addEthereumChainParameter?.rpcUrls?.length) + rpcUrls = addEthereumChainParameter.rpcUrls + else rpcUrls = [chain.rpcUrls.default?.http[0] ?? ''] + + const addEthereumChain = { + blockExplorerUrls, + chainId: numberToHex(chainId), + chainName: addEthereumChainParameter?.chainName ?? chain.name, + iconUrls: addEthereumChainParameter?.iconUrls, + nativeCurrency: + addEthereumChainParameter?.nativeCurrency ?? + chain.nativeCurrency, + rpcUrls, + } satisfies AddEthereumChainParameter + + await provider.request({ + method: 'wallet_addEthereumChain', + params: [addEthereumChain], + }) + + const currentChainId = hexToNumber( + // Call `'eth_chainId'` directly to guard against `this.state.chainId` (via `provider.getChainId`) being stale. + (await provider.request({ method: 'eth_chainId' })) as Hex, + ) + if (currentChainId !== chainId) + throw new UserRejectedRequestError( + new Error('User rejected switch after adding network.'), + ) + + return chain + } catch (error) { + throw new UserRejectedRequestError(error as Error) + } + } + try { await Promise.all([ provider @@ -339,62 +404,6 @@ export function metaMask(parameters: MetaMaskParameters = {}) { } catch (err) { const error = err as RpcError - // Indicates chain is not added to provider - if ( - error.code === 4902 || - // Unwrapping for MetaMask Mobile - // https://github.com/MetaMask/metamask-mobile/issues/2944#issuecomment-976988719 - (error as ProviderRpcError<{ originalError?: { code: number } }>) - ?.data?.originalError?.code === 4902 - ) { - try { - const { default: blockExplorer, ...blockExplorers } = - chain.blockExplorers ?? {} - let blockExplorerUrls: string[] | undefined - if (addEthereumChainParameter?.blockExplorerUrls) - blockExplorerUrls = addEthereumChainParameter.blockExplorerUrls - else if (blockExplorer) - blockExplorerUrls = [ - blockExplorer.url, - ...Object.values(blockExplorers).map((x) => x.url), - ] - - let rpcUrls: readonly string[] - if (addEthereumChainParameter?.rpcUrls?.length) - rpcUrls = addEthereumChainParameter.rpcUrls - else rpcUrls = [chain.rpcUrls.default?.http[0] ?? ''] - - const addEthereumChain = { - blockExplorerUrls, - chainId: numberToHex(chainId), - chainName: addEthereumChainParameter?.chainName ?? chain.name, - iconUrls: addEthereumChainParameter?.iconUrls, - nativeCurrency: - addEthereumChainParameter?.nativeCurrency ?? - chain.nativeCurrency, - rpcUrls, - } satisfies AddEthereumChainParameter - - await provider.request({ - method: 'wallet_addEthereumChain', - params: [addEthereumChain], - }) - - const currentChainId = hexToNumber( - // Call `'eth_chainId'` directly to guard against `this.state.chainId` (via `provider.getChainId`) being stale. - (await provider.request({ method: 'eth_chainId' })) as Hex, - ) - if (currentChainId !== chainId) - throw new UserRejectedRequestError( - new Error('User rejected switch after adding network.'), - ) - - return chain - } catch (error) { - throw new UserRejectedRequestError(error as Error) - } - } - if (error.code === UserRejectedRequestError.code) throw new UserRejectedRequestError(error) throw new SwitchChainError(error) From 2736070405b3055f8ff9da6e4abc71b59c193e29 Mon Sep 17 00:00:00 2001 From: Christopher Ferreira Date: Mon, 11 Nov 2024 13:24:25 +0000 Subject: [PATCH 2/4] fix lint --- packages/connectors/src/metaMask.ts | 111 ++++++++++++++-------------- 1 file changed, 55 insertions(+), 56 deletions(-) diff --git a/packages/connectors/src/metaMask.ts b/packages/connectors/src/metaMask.ts index e9d9bfd2ed..64532f36cc 100644 --- a/packages/connectors/src/metaMask.ts +++ b/packages/connectors/src/metaMask.ts @@ -11,6 +11,12 @@ import { createConnector, extractRpcUrls, } from '@wagmi/core' +import { + linea, + lineaSepolia, + mainnet, + sepolia +} from '@wagmi/core/chains' import type { Compute, ExactPartial, @@ -18,12 +24,6 @@ import type { RemoveUndefined, UnionCompute, } from '@wagmi/core/internal' -import { - mainnet, - sepolia, - linea, - lineaSepolia -} from '@wagmi/core/chains' import { type AddEthereumChainParameter, type Address, @@ -317,60 +317,59 @@ export function metaMask(parameters: MetaMaskParameters = {}) { // This avoids the need to react to the "unrecognized chain" error // and consequent back and forth between MetaMask and Wagmi. const metaMaskDefaultChains = [ - mainnet.id, - sepolia.id, - linea.id, - lineaSepolia.id - ]; + mainnet.id, + sepolia.id, + linea.id, + lineaSepolia.id, + ] const isDefaultChain = metaMaskDefaultChains.find((x) => x === chainId) if (!isDefaultChain) { - try { - const { default: blockExplorer, ...blockExplorers } = - chain.blockExplorers ?? {} - let blockExplorerUrls: string[] | undefined - if (addEthereumChainParameter?.blockExplorerUrls) - blockExplorerUrls = addEthereumChainParameter.blockExplorerUrls - else if (blockExplorer) - blockExplorerUrls = [ - blockExplorer.url, - ...Object.values(blockExplorers).map((x) => x.url), - ] - - let rpcUrls: readonly string[] - if (addEthereumChainParameter?.rpcUrls?.length) - rpcUrls = addEthereumChainParameter.rpcUrls - else rpcUrls = [chain.rpcUrls.default?.http[0] ?? ''] - - const addEthereumChain = { - blockExplorerUrls, - chainId: numberToHex(chainId), - chainName: addEthereumChainParameter?.chainName ?? chain.name, - iconUrls: addEthereumChainParameter?.iconUrls, - nativeCurrency: - addEthereumChainParameter?.nativeCurrency ?? - chain.nativeCurrency, - rpcUrls, - } satisfies AddEthereumChainParameter - - await provider.request({ - method: 'wallet_addEthereumChain', - params: [addEthereumChain], - }) + try { + const { default: blockExplorer, ...blockExplorers } = + chain.blockExplorers ?? {} + let blockExplorerUrls: string[] | undefined + if (addEthereumChainParameter?.blockExplorerUrls) + blockExplorerUrls = addEthereumChainParameter.blockExplorerUrls + else if (blockExplorer) + blockExplorerUrls = [ + blockExplorer.url, + ...Object.values(blockExplorers).map((x) => x.url), + ] - const currentChainId = hexToNumber( - // Call `'eth_chainId'` directly to guard against `this.state.chainId` (via `provider.getChainId`) being stale. - (await provider.request({ method: 'eth_chainId' })) as Hex, - ) - if (currentChainId !== chainId) - throw new UserRejectedRequestError( - new Error('User rejected switch after adding network.'), - ) - - return chain - } catch (error) { - throw new UserRejectedRequestError(error as Error) - } + let rpcUrls: readonly string[] + if (addEthereumChainParameter?.rpcUrls?.length) + rpcUrls = addEthereumChainParameter.rpcUrls + else rpcUrls = [chain.rpcUrls.default?.http[0] ?? ''] + + const addEthereumChain = { + blockExplorerUrls, + chainId: numberToHex(chainId), + chainName: addEthereumChainParameter?.chainName ?? chain.name, + iconUrls: addEthereumChainParameter?.iconUrls, + nativeCurrency: + addEthereumChainParameter?.nativeCurrency ?? chain.nativeCurrency, + rpcUrls, + } satisfies AddEthereumChainParameter + + await provider.request({ + method: 'wallet_addEthereumChain', + params: [addEthereumChain], + }) + + const currentChainId = hexToNumber( + // Call `'eth_chainId'` directly to guard against `this.state.chainId` (via `provider.getChainId`) being stale. + (await provider.request({ method: 'eth_chainId' })) as Hex, + ) + if (currentChainId !== chainId) + throw new UserRejectedRequestError( + new Error('User rejected switch after adding network.'), + ) + + return chain + } catch (error) { + throw new UserRejectedRequestError(error as Error) + } } try { From 078e2479babdcac8379d4d42cd0903dd60cbf9ca Mon Sep 17 00:00:00 2001 From: Christopher Ferreira Date: Mon, 11 Nov 2024 13:24:53 +0000 Subject: [PATCH 3/4] fix: fixes lint --- packages/connectors/src/metaMask.ts | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/packages/connectors/src/metaMask.ts b/packages/connectors/src/metaMask.ts index 64532f36cc..668208b0eb 100644 --- a/packages/connectors/src/metaMask.ts +++ b/packages/connectors/src/metaMask.ts @@ -11,12 +11,7 @@ import { createConnector, extractRpcUrls, } from '@wagmi/core' -import { - linea, - lineaSepolia, - mainnet, - sepolia -} from '@wagmi/core/chains' +import { linea, lineaSepolia, mainnet, sepolia } from '@wagmi/core/chains' import type { Compute, ExactPartial, From c539b0acb6079d160f2b5d53c056f19a82707f1a Mon Sep 17 00:00:00 2001 From: abretonc7s <107169956+abretonc7s@users.noreply.github.com> Date: Mon, 25 Nov 2024 10:00:29 +0800 Subject: [PATCH 4/4] Create thirty-icons-work.md --- .changeset/thirty-icons-work.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/thirty-icons-work.md diff --git a/.changeset/thirty-icons-work.md b/.changeset/thirty-icons-work.md new file mode 100644 index 0000000000..7de94ac356 --- /dev/null +++ b/.changeset/thirty-icons-work.md @@ -0,0 +1,5 @@ +--- +"@wagmi/connectors": patch +--- + +feat: Improve chain switching via MetaMask connector