From 96dcf227b750440407d9a6729580ee803b8993de Mon Sep 17 00:00:00 2001 From: Zach Pomerantz Date: Tue, 11 Oct 2022 11:49:50 -0700 Subject: [PATCH] feat: allow null provider (#262) --- src/components/Widget.tsx | 2 +- src/hooks/swap/useSwapInfo.tsx | 31 ++++++++++++++++++++++++------- src/hooks/web3/index.tsx | 17 +++++++++++------ 3 files changed, 36 insertions(+), 14 deletions(-) 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)) {