diff --git a/src/components/Widget.tsx b/src/components/Widget.tsx
index 4a5f2b7cf..7f2779239 100644
--- a/src/components/Widget.tsx
+++ b/src/components/Widget.tsx
@@ -98,7 +98,7 @@ export const DialogWrapper = styled.div`
export interface WidgetProps extends BrandingSettings, TransactionEventHandlers {
theme?: Theme
locale?: SupportedLocale
- provider?: Eip1193Provider | JsonRpcProvider
+ provider?: Eip1193Provider | JsonRpcProvider | null
jsonRpcUrlMap?: JsonRpcConnectionMap
defaultChainId?: SupportedChainId
tokenList?: string | TokenInfo[]
diff --git a/src/hooks/swap/useSwapInfo.tsx b/src/hooks/swap/useSwapInfo.tsx
index 3635beb71..e11ca40cc 100644
--- a/src/hooks/swap/useSwapInfo.tsx
+++ b/src/hooks/swap/useSwapInfo.tsx
@@ -5,7 +5,9 @@ import { useCurrencyBalances } from 'hooks/useCurrencyBalance'
import useOnSupportedNetwork from 'hooks/useOnSupportedNetwork'
import { PriceImpact, usePriceImpact } from 'hooks/usePriceImpact'
import useSlippage, { DEFAULT_SLIPPAGE, Slippage } from 'hooks/useSlippage'
+import useSwitchChain from 'hooks/useSwitchChain'
import { useUSDCValue } from 'hooks/useUSDCPrice'
+import useConnectors from 'hooks/web3/useConnectors'
import { useAtomValue } from 'jotai/utils'
import { createContext, PropsWithChildren, useContext, useMemo } from 'react'
import { InterfaceTrade, TradeState } from 'state/routing/types'
@@ -50,19 +52,16 @@ function useComputeSwapInfo(routerUrl?: string): SwapInfo {
const { type, amount, [Field.INPUT]: currencyIn, [Field.OUTPUT]: currencyOut } = useAtomValue(swapAtom)
const isWrap = useIsWrap()
+ const chainIn = currencyIn?.chainId
+ const chainOut = currencyOut?.chainId
+ const tokenChainId = chainIn || chainOut
const error = useMemo(() => {
if (!isActive) return isActivating ? ChainError.ACTIVATING_CHAIN : ChainError.UNCONNECTED_CHAIN
if (!isSupported) return ChainError.UNSUPPORTED_CHAIN
-
- const chainIn = currencyIn?.chainId
- const chainOut = currencyOut?.chainId
if (chainIn && chainOut && chainIn !== chainOut) return ChainError.MISMATCHED_TOKEN_CHAINS
-
- const tokenChainId = chainIn || chainOut
if (chainId && tokenChainId && chainId !== tokenChainId) return ChainError.MISMATCHED_CHAINS
-
return
- }, [chainId, currencyIn?.chainId, currencyOut?.chainId, isActivating, isActive, isSupported])
+ }, [chainId, chainIn, chainOut, isActivating, isActive, isSupported, tokenChainId])
const parsedAmount = useMemo(
() => tryParseCurrencyAmount(amount, (isExactInput(type) ? currencyIn : currencyOut) ?? undefined),
@@ -146,6 +145,24 @@ const SwapInfoContext = createContext(DEFAULT_SWAP_INFO)
export function SwapInfoProvider({ children, routerUrl }: PropsWithChildren<{ routerUrl?: string }>) {
const swapInfo = useComputeSwapInfo(routerUrl)
+
+ const {
+ error,
+ [Field.INPUT]: { currency: currencyIn },
+ [Field.OUTPUT]: { currency: currencyOut },
+ } = swapInfo
+ const { connector } = useWeb3React()
+ const switchChain = useSwitchChain()
+ const chainIn = currencyIn?.chainId
+ const chainOut = currencyOut?.chainId
+ const tokenChainId = chainIn || chainOut
+ const { network } = useConnectors()
+ // The network connector should be auto-switched, as it is a read-only interface that should "just work".
+ if (error === ChainError.MISMATCHED_CHAINS && tokenChainId && connector === network) {
+ delete swapInfo.error // avoids flashing an error whilst switching
+ switchChain(tokenChainId)
+ }
+
return {children}
}
diff --git a/src/hooks/web3/index.tsx b/src/hooks/web3/index.tsx
index 1d44c3bbb..11df30a5d 100644
--- a/src/hooks/web3/index.tsx
+++ b/src/hooks/web3/index.tsx
@@ -20,7 +20,7 @@ import {
type Web3ReactConnector = [T, Web3ReactHooks]
interface Web3ReactConnectors {
- user: Web3ReactConnector | undefined
+ user: Web3ReactConnector | null | undefined
metaMask: Web3ReactConnector
walletConnect: Web3ReactConnector
walletConnectQR: Web3ReactConnector
@@ -28,7 +28,11 @@ interface Web3ReactConnectors {
}
interface ProviderProps {
- provider?: Eip1193Provider | JsonRpcProvider
+ /**
+ * If null, no auto-connection (MetaMask or WalletConnect) will be attempted.
+ * This is appropriate for integrations which wish to control the connected provider.
+ */
+ provider?: Eip1193Provider | JsonRpcProvider | null
jsonRpcMap?: JsonRpcConnectionMap
defaultChainId?: SupportedChainId
}
@@ -47,7 +51,7 @@ export function Provider({
// referentially static.
key.current += 1
- const prioritizedConnectors: (Web3ReactConnector | undefined)[] = [
+ const prioritizedConnectors: (Web3ReactConnector | null | undefined)[] = [
web3ReactConnectors.user,
web3ReactConnectors.metaMask,
web3ReactConnectors.walletConnect,
@@ -74,9 +78,10 @@ export function Provider({
if (connectors.user) {
connectors.user.activate().catch(() => undefined)
return
+ } else if (connectors.user !== null) {
+ const eagerConnectors = [connectors.metaMask, connectors.walletConnect]
+ eagerConnectors.forEach((connector) => connector.connectEagerly().catch(() => undefined))
}
- const eagerConnectors = [connectors.metaMask, connectors.walletConnect]
- eagerConnectors.forEach((connector) => connector.connectEagerly().catch(() => undefined))
connectors.network.activate().catch(() => undefined)
}, [connectors.metaMask, connectors.network, connectors.user, connectors.walletConnect])
@@ -106,7 +111,7 @@ function useWeb3ReactConnectors({ defaultChainId, provider, jsonRpcMap }: Provid
)
const user = useMemo(() => {
- if (!provider) return
+ if (!provider) return provider
if (JsonRpcProvider.isProvider(provider)) {
return initializeWeb3ReactConnector(JsonRpcConnector, { provider })
} else if (JsonRpcProvider.isProvider((provider as any).provider)) {