From 32c52e2eb1cc4c929316615d1a80fa75ddbf5ea8 Mon Sep 17 00:00:00 2001 From: Manan Tank Date: Fri, 10 Nov 2023 18:12:37 +0530 Subject: [PATCH 01/20] Connect Embed + allow hiding the connection --- .../providers/thirdweb-wallet-provider.tsx | 161 ++++++++++++++---- packages/react/src/evm/index.ts | 2 + .../providers/wallet-ui-states-provider.tsx | 3 + .../ConnectWallet/Modal/ConnectEmbed.tsx | 142 +++++++++++++++ .../ConnectWallet/Modal/ConnectModal.tsx | 1 + .../Modal/ConnectModalInline.tsx | 2 +- .../wallet/ConnectWallet/WalletSelector.tsx | 58 +++++-- .../src/wallet/wallets/safe/SelectAccount.tsx | 56 +++--- .../src/wallet/wallets/safe/safeWallet.tsx | 58 ++++--- .../smartWallet/SmartWalletConnecting.tsx | 54 +++--- .../wallets/smartWallet/smartWallet.tsx | 22 ++- 11 files changed, 429 insertions(+), 130 deletions(-) create mode 100644 packages/react/src/wallet/ConnectWallet/Modal/ConnectEmbed.tsx diff --git a/packages/react-core/src/core/providers/thirdweb-wallet-provider.tsx b/packages/react-core/src/core/providers/thirdweb-wallet-provider.tsx index 8bdf757f0ba..20e79139959 100644 --- a/packages/react-core/src/core/providers/thirdweb-wallet-provider.tsx +++ b/packages/react-core/src/core/providers/thirdweb-wallet-provider.tsx @@ -1,3 +1,4 @@ +/* eslint-disable prefer-const */ import { DAppMetaData } from "../types/dAppMeta"; import type { WalletConfig, @@ -59,6 +60,15 @@ type ConnectFnArgs = connectParams: NonNullable>, ]; +type HiddenConnection = { + connectionStatus: ConnectionStatus; + signer: Signer | undefined; + wallet: WalletInstance | undefined; + walletConfig: WalletConfig | undefined; + chainId?: number; + switchChain: (chainId: number) => Promise; +}; + // maps wallet instance to it's wallet config const walletInstanceToConfig: Map< WalletInstance, @@ -92,6 +102,25 @@ type ThirdwebWalletContextData = { getWalletConfig: (walletInstance: WalletInstance) => WalletConfig | undefined; activeChainSetExplicitly: boolean; clientId?: string; + /** + * when this flag is set to true, all wallet connection related states like signer, activeWallet, connectionStatus, activeWalletConfig + * will be set to reflect a "disconnected" state + * - signer, activeWallet, activeWalletConfig will be set to `undefined` + * - connectionStatus will be set to "disconnected" + * + * the actual values will be stored in `hiddenConnection` object + * + * This is only useful for connecting wallets like Safe or Smart Wallet + */ + isConnectionHidden: boolean; + /** + * Set value of `isConnectionHidden` flag + */ + setIsConnectionHidden: (value: boolean) => void; + /** + * Stores the values of `signer`, `activeWallet`, `activeWalletConfig`, `connectionStatus` when `isConnectionHidden` is set to true + */ + hiddenConnection?: HiddenConnection; }; const ThirdwebWalletContext = /* @__PURE__ */ createContext< @@ -113,21 +142,26 @@ export function ThirdwebWalletProvider( signerWallet?: WalletConfig; }>, ) { - const [signer, setSigner] = useState(undefined); - const [connectionStatus, setConnectionStatus] = + let [isConnectionHidden, setIsConnectionHidden] = useState(false); + const [hiddenConnectionChainId, setHiddenConnectionChainId] = useState< + number | undefined + >(undefined); + + let hiddenConnection: HiddenConnection | undefined; + + let [signer, setSigner] = useState(undefined); + let [connectionStatus, setConnectionStatus] = useState("unknown"); const autoConnectTimeout = props.autoConnectTimeout || 15000; - const [activeWallet, setActiveWallet] = useState< - WalletInstance | undefined - >(); + let [activeWallet, setActiveWallet] = useState(); const [createdWalletInstance, setCreatedWalletInstance] = useState< WalletInstance | undefined >(); - const [activeWalletConfig, setActiveWalletConfig] = useState< + let [activeWalletConfig, setActiveWalletConfig] = useState< WalletConfig | undefined >(); @@ -136,6 +170,79 @@ export function ThirdwebWalletProvider( props.createWalletStorage("coordinatorStorage"); } + const storeLastActiveChainId = useCallback(async (chainId: number) => { + const lastConnectedWallet = await lastConnectedWalletStorage.getItem( + LAST_CONNECTED_WALLET_STORAGE_KEY, + ); + + if (!lastConnectedWallet) { + return; + } + + try { + const parsedWallet = JSON.parse(lastConnectedWallet as string); + if (parsedWallet.connectParams) { + parsedWallet.connectParams.chainId = chainId; + } else { + parsedWallet.connectParams = { chainId }; + } + await lastConnectedWalletStorage.setItem( + LAST_CONNECTED_WALLET_STORAGE_KEY, + JSON.stringify(parsedWallet), + ); + } catch (error) { + console.error(`Error saving the last active chain: ${error}`); + } + }, []); + + const hiddenConnectionWallet = isConnectionHidden ? activeWallet : undefined; + + const switchChainHiddenConnection = useCallback( + async (chainId: number) => { + if (!hiddenConnectionWallet) { + throw new Error("No hidden wallet"); + } + + await hiddenConnectionWallet.switchChain(chainId); + const _signer = await hiddenConnectionWallet.getSigner(); + await storeLastActiveChainId(chainId); + + setSigner(_signer); + }, + [hiddenConnectionWallet, storeLastActiveChainId], + ); + + useEffect(() => { + if (hiddenConnectionWallet) { + const update = () => { + hiddenConnectionWallet.getChainId().then((_chainId) => { + setHiddenConnectionChainId(_chainId); + }); + }; + + update(); + hiddenConnectionWallet.addListener("change", update); + } else { + setHiddenConnectionChainId(undefined); + } + }, [hiddenConnectionWallet]); + + if (isConnectionHidden) { + hiddenConnection = { + connectionStatus, + signer, + wallet: activeWallet, + walletConfig: activeWalletConfig, + switchChain: switchChainHiddenConnection, + chainId: hiddenConnectionChainId, + }; + + connectionStatus = "disconnected"; + signer = undefined; + activeWallet = undefined; + activeWalletConfig = undefined; + } + // if autoSwitch is enabled - enforce connection to activeChain const chainToConnect = props.autoSwitch ? props.activeChain : undefined; @@ -223,31 +330,6 @@ export function ThirdwebWalletProvider( [], ); - const storeLastActiveChainId = useCallback(async (chainId: number) => { - const lastConnectedWallet = await lastConnectedWalletStorage.getItem( - LAST_CONNECTED_WALLET_STORAGE_KEY, - ); - - if (!lastConnectedWallet) { - return; - } - - try { - const parsedWallet = JSON.parse(lastConnectedWallet as string); - if (parsedWallet.connectParams) { - parsedWallet.connectParams.chainId = chainId; - } else { - parsedWallet.connectParams = { chainId }; - } - await lastConnectedWalletStorage.setItem( - LAST_CONNECTED_WALLET_STORAGE_KEY, - JSON.stringify(parsedWallet), - ); - } catch (error) { - console.error(`Error saving the last active chain: ${error}`); - } - }, []); - const switchChain = useCallback( async (chainId: number) => { if (!activeWallet) { @@ -447,26 +529,28 @@ export function ThirdwebWalletProvider( // when wallet's network or account is changed using the extension, update UI useEffect(() => { - if (!activeWallet) { + const wallet = activeWallet; + + if (!wallet) { return; } const update = async () => { - const _signer = await activeWallet.getSigner(); + const _signer = await wallet.getSigner(); setSigner(_signer); }; - activeWallet.addListener("change", () => { + wallet.addListener("change", () => { update(); }); - activeWallet.addListener("disconnect", () => { + wallet.addListener("disconnect", () => { onWalletDisconnect(); }); return () => { - activeWallet.removeListener("change"); - activeWallet.removeListener("disconnect"); + wallet.removeListener("change"); + wallet.removeListener("disconnect"); }; }, [activeWallet, onWalletDisconnect]); @@ -520,6 +604,9 @@ export function ThirdwebWalletProvider( }, activeChainSetExplicitly: props.activeChainSetExplicitly, clientId: props.clientId, + hiddenConnection: hiddenConnection, + isConnectionHidden: isConnectionHidden, + setIsConnectionHidden: setIsConnectionHidden, }} > {props.children} diff --git a/packages/react/src/evm/index.ts b/packages/react/src/evm/index.ts index 095fe2a61d1..c74e5327db8 100644 --- a/packages/react/src/evm/index.ts +++ b/packages/react/src/evm/index.ts @@ -1,3 +1,5 @@ +export { ConnectEmbed } from "../wallet/ConnectWallet/Modal/ConnectEmbed"; + export { useIsWalletModalOpen, useSetIsWalletModalOpen, diff --git a/packages/react/src/evm/providers/wallet-ui-states-provider.tsx b/packages/react/src/evm/providers/wallet-ui-states-provider.tsx index dfe0156bef7..828a39c82bc 100644 --- a/packages/react/src/evm/providers/wallet-ui-states-provider.tsx +++ b/packages/react/src/evm/providers/wallet-ui-states-provider.tsx @@ -20,6 +20,7 @@ export type ModalConfig = { onLogin?: (token: string) => void; onLogout?: () => void; }; + isEmbed?: boolean; }; const WalletModalOpen = /* @__PURE__ */ createContext(false); @@ -47,6 +48,7 @@ export const WalletUIStatesProvider = ( termsOfServiceUrl?: string; privacyPolicyUrl?: string; welcomeScreen?: WelcomeScreen; + isEmbed?: boolean; }>, ) => { const [isWalletModalOpen, setIsWalletModalOpen] = useState(false); @@ -62,6 +64,7 @@ export const WalletUIStatesProvider = ( privacyPolicyUrl: props.privacyPolicyUrl, welcomeScreen: props.welcomeScreen, titleIconUrl: props.titleIconUrl, + isEmbed: props.isEmbed, }); return ( diff --git a/packages/react/src/wallet/ConnectWallet/Modal/ConnectEmbed.tsx b/packages/react/src/wallet/ConnectWallet/Modal/ConnectEmbed.tsx new file mode 100644 index 00000000000..ea4c115a702 --- /dev/null +++ b/packages/react/src/wallet/ConnectWallet/Modal/ConnectEmbed.tsx @@ -0,0 +1,142 @@ +import { Theme, radius } from "../../../design-system"; +import styled from "@emotion/styled"; +import { + SetModalConfigCtx, + WalletUIStatesProvider, +} from "../../../evm/providers/wallet-ui-states-provider"; +import { + wideModalMaxHeight, + modalMaxWidthCompact, + modalMaxWidthWide, + defaultTheme, +} from "../constants"; +import { ConnectModalContent } from "./ConnectModal"; +import { useScreen } from "./screen"; +import { isMobile } from "../../../evm/utils/isMobile"; +import { useConnectionStatus, useWallets } from "@thirdweb-dev/react-core"; +import { DynamicHeight } from "../../../components/DynamicHeight"; +import { CustomThemeProvider } from "../../../design-system/CustomThemeProvider"; +import { ComponentProps, useContext, useEffect } from "react"; +import { ConnectWalletProps } from "../ConnectWallet"; +import { useTWLocale } from "../../../evm/providers/locale-provider"; + +export const ConnectEmbed = ( + props: Omit< + ConnectWalletProps, + | "detailsBtn" + | "dropdownPosition" + | "auth" + | "networkSelector" + | "hideTestnetFaucet" + | "switchToActiveChain" + | "supportedTokens" + | "hideSwitchToPersonalWallet" + >, +) => { + const connectionStatus = useConnectionStatus(); + + const { screen, setScreen, initialScreen } = useScreen(); + const walletConfigs = useWallets(); + const modalSize = + (isMobile() || walletConfigs.length === 1 ? "compact" : props.modalSize) || + "compact"; + + const content = ( + { + // no op + }} + /> + ); + + const walletUIStatesProps = { + theme: props.theme || defaultTheme, + modalSize: modalSize, + title: props.modalTitle, + termsOfServiceUrl: props.termsOfServiceUrl, + privacyPolicyUrl: props.privacyPolicyUrl, + welcomeScreen: props.welcomeScreen, + titleIconUrl: props.modalTitleIconUrl, + isEmbed: true, + }; + + if (connectionStatus === "connected") { + return; + } + + return ( + + + + {modalSize === "compact" ? ( + {content} + ) : ( + content + )} + + + + + ); +}; + +function SyncedWalletUIStates( + props: ComponentProps, +) { + const setModalConfig = useContext(SetModalConfigCtx); + const locale = useTWLocale(); + + // update modalConfig on props change + useEffect(() => { + setModalConfig((c) => ({ + ...c, + title: props.title || locale.connectWallet.defaultModalTitle, + theme: props.theme || "dark", + modalSize: (isMobile() ? "compact" : props.modalSize) || "wide", + termsOfServiceUrl: props.termsOfServiceUrl, + privacyPolicyUrl: props.privacyPolicyUrl, + welcomeScreen: props.welcomeScreen, + titleIconUrl: props.titleIconUrl, + })); + }, [ + props.title, + props.theme, + props.modalSize, + props.termsOfServiceUrl, + props.privacyPolicyUrl, + props.welcomeScreen, + props.titleIconUrl, + setModalConfig, + locale.connectWallet.defaultModalTitle, + ]); + + return ; +} + +const EmbedContainer = styled.div<{ theme?: Theme }>` + color: ${(p) => p.theme.colors.primaryText}; + width: 100%; + box-sizing: border-box; + position: relative; + line-height: normal; + border-radius: ${radius.xl}; + border: 1px solid ${(p) => p.theme.colors.borderColor}; + overflow: hidden; + font-family: ${(p) => p.theme.fontFamily}; + & *::selection { + background-color: ${(p) => p.theme.colors.primaryText}; + color: ${(p) => p.theme.colors.modalBg}; + } +`; diff --git a/packages/react/src/wallet/ConnectWallet/Modal/ConnectModal.tsx b/packages/react/src/wallet/ConnectWallet/Modal/ConnectModal.tsx index 225bb9b1397..554d7218801 100644 --- a/packages/react/src/wallet/ConnectWallet/Modal/ConnectModal.tsx +++ b/packages/react/src/wallet/ConnectWallet/Modal/ConnectModal.tsx @@ -64,6 +64,7 @@ export const ConnectModalContent = (props: { }; const { setHideModal } = props; + const handleConnected = useCallback(() => { const requiresSignIn = modalConfig.auth?.loginOptional ? false diff --git a/packages/react/src/wallet/ConnectWallet/Modal/ConnectModalInline.tsx b/packages/react/src/wallet/ConnectWallet/Modal/ConnectModalInline.tsx index a87ac899a30..1ec5033862b 100644 --- a/packages/react/src/wallet/ConnectWallet/Modal/ConnectModalInline.tsx +++ b/packages/react/src/wallet/ConnectWallet/Modal/ConnectModalInline.tsx @@ -95,7 +95,7 @@ export const ConnectModalInline = ( : modalMaxWidthWide, }} > - {props.modalSize === "compact" ? ( + {modalSize === "compact" ? ( {content} ) : ( content diff --git a/packages/react/src/wallet/ConnectWallet/WalletSelector.tsx b/packages/react/src/wallet/ConnectWallet/WalletSelector.tsx index db0b8b144f5..df8fc169d92 100644 --- a/packages/react/src/wallet/ConnectWallet/WalletSelector.tsx +++ b/packages/react/src/wallet/ConnectWallet/WalletSelector.tsx @@ -8,7 +8,7 @@ import { Line, } from "../../components/basic"; import { Button } from "../../components/buttons"; -import { ModalTitle } from "../../components/modalElements"; +import { BackButton, ModalTitle } from "../../components/modalElements"; import { iconSize, radius, spacing, Theme } from "../../design-system"; import styled from "@emotion/styled"; import { @@ -342,28 +342,54 @@ export const WalletSelector: React.FC<{ return ( {/* Header */} - - {isWalletGroupExpanded ? ( - { - setIsWalletGroupExpanded(false); - }} - /> - ) : ( - twTitle - )} - + {!modalConfig.isEmbed && ( + + {isWalletGroupExpanded ? ( + { + setIsWalletGroupExpanded(false); + }} + /> + ) : ( + twTitle + )} + + )} {/* Body */} + {modalConfig.isEmbed && isWalletGroupExpanded && ( + + { + setIsWalletGroupExpanded(false); + }} + /> + {"Back"} + + )} + {topSection} diff --git a/packages/react/src/wallet/wallets/safe/SelectAccount.tsx b/packages/react/src/wallet/wallets/safe/SelectAccount.tsx index 850b6ffbd56..1a2e72e684f 100644 --- a/packages/react/src/wallet/wallets/safe/SelectAccount.tsx +++ b/packages/react/src/wallet/wallets/safe/SelectAccount.tsx @@ -11,13 +11,9 @@ import { ExclamationTriangleIcon, } from "@radix-ui/react-icons"; import { - useChain, - useChainId, useConnect, - useConnectionStatus, useSupportedChains, - useSwitchChain, - useWallet, + useWalletContext, } from "@thirdweb-dev/react-core"; import { SafeSupportedChainsSet } from "@thirdweb-dev/wallets"; import { utils } from "ethers"; @@ -36,22 +32,24 @@ export const SelectAccount: React.FC<{ renderBackButton?: boolean; }> = (props) => { const locale = useTWLocale().wallets.safeWallet.accountDetailsScreen; - const activeWallet = useWallet(); - const connect = useConnect(); - const activeChain = useChain(); - const connectedChainId = useChainId(); - const [safeAddress, setSafeAddress] = useState(""); - const [safeChainId, setSafeChainId] = useState(-1); - - const [safeConnectError, setSafeConnectError] = useState(false); + // personal wallet + const { setIsConnectionHidden, hiddenConnection } = useWalletContext(); + const personalWallet = hiddenConnection?.wallet; + const personalWalletChainId = hiddenConnection?.chainId; const [switchError, setSwitchError] = useState(false); const [switchingNetwork, setSwitchingNetwork] = useState(false); - const connectionStatus = useConnectionStatus(); + // safe + const connectSafe = useConnect(); + const [safeAddress, setSafeAddress] = useState(""); + const [safeChainId, setSafeChainId] = useState(-1); + const [safeConnectError, setSafeConnectError] = useState(false); + const [safeConnectionStatus, setSafeConnectionStatus] = useState< + "idle" | "connecting" | "failed" + >("idle"); const chains = useSupportedChains(); - // put supported chains first const supportedChains = chains.filter((c) => SafeSupportedChainsSet.has(c.chainId), ); @@ -67,30 +65,36 @@ export const SelectAccount: React.FC<{ const useOptGroup = mainnets.length > 0 && testnets.length > 0; const handleSubmit = async () => { - if (!selectedSafeChain || !activeWallet || !activeChain) { + if (!selectedSafeChain || !personalWallet) { return; } setSafeConnectError(false); - + setSafeConnectionStatus("connecting"); try { - await connect(props.safeWalletConfig, { + await connectSafe(props.safeWalletConfig, { chain: selectedSafeChain, - personalWallet: activeWallet, + personalWallet: personalWallet, safeAddress, }); + setIsConnectionHidden(false); props.onConnect(); } catch (e) { + setSafeConnectionStatus("failed"); console.error(e); setSafeConnectError(true); } }; - const mismatch = safeChainId !== -1 && connectedChainId !== safeChainId; + console.log({ + personalWalletChainId, + safeChainId, + }); + + const mismatch = safeChainId !== -1 && personalWalletChainId !== safeChainId; const isValidAddress = utils.isAddress(safeAddress); const disableNetworkSelection = supportedChains.length === 1; - const switchChain = useSwitchChain(); const modalConfig = useContext(ModalConfigCtx); return ( @@ -324,14 +328,14 @@ export const SelectAccount: React.FC<{ width: modalConfig.modalSize === "compact" ? "100%" : undefined, }} onClick={async () => { - if (!activeWallet) { + if (!personalWallet) { throw new Error("No active wallet"); } setSafeConnectError(false); setSwitchError(false); setSwitchingNetwork(true); try { - await switchChain(safeChainId); + await hiddenConnection.switchChain(safeChainId); } catch (e) { setSwitchError(true); } finally { @@ -351,7 +355,7 @@ export const SelectAccount: React.FC<{ diff --git a/packages/react/src/wallet/wallets/safe/safeWallet.tsx b/packages/react/src/wallet/wallets/safe/safeWallet.tsx index 870386180ee..84eef355dd0 100644 --- a/packages/react/src/wallet/wallets/safe/safeWallet.tsx +++ b/packages/react/src/wallet/wallets/safe/safeWallet.tsx @@ -3,11 +3,10 @@ import { WalletConfig, ConnectUIProps, WalletOptions, - useDisconnect, - useWallet, + useWalletContext, } from "@thirdweb-dev/react-core"; import { defaultWallets } from "../defaultWallets"; -import { useState } from "react"; +import { useEffect, useRef, useState } from "react"; import { SelectpersonalWallet } from "./SelectPersonalWallet"; import type { SafeWalletConfigOptions, SafeWalletConfig } from "./types"; import { SelectAccount } from "./SelectAccount"; @@ -44,19 +43,49 @@ export const safeWallet = ( export const SafeConnectUI = ( props: ConnectUIProps & { personalWallets: WalletConfig[] }, ) => { - const activeWallet = useWallet(); + // selected personal wallet config const [personalWalletConfig, setPersonalWalletConfig] = useState< WalletConfig | undefined >(); - const disconnect = useDisconnect(); - if (personalWalletConfig) { + const [isPersonalWalletConnected, setIsPersonalWalletConnected] = + useState(false); + + const { setIsConnectionHidden: setIgnoreWalletConnection } = + useWalletContext(); + + // ignore wallet connection for personal wallet; + const mounted = useRef(false); + useEffect(() => { + if (mounted.current) { + return; + } + mounted.current = true; + setIgnoreWalletConnection(true); + }, [setIgnoreWalletConnection]); + + // if personal wallet is not selected + if (!personalWalletConfig) { + return ( + 1} + /> + ); + } + + // if the personal wallet is selected, but not connected + if (!isPersonalWalletConnected) { const _props: ConnectUIProps = { goBack: () => { + setIsPersonalWalletConnected(false); setPersonalWalletConfig(undefined); }, connected() { - setPersonalWalletConfig(undefined); + setIsPersonalWalletConnected(true); }, isOpen: props.isOpen, hide: props.hide, @@ -76,23 +105,12 @@ export const SafeConnectUI = ( return ; } - if (!activeWallet) { - return ( - 1} - /> - ); - } - + // if personal wallet is selected and connected return ( 1} onBack={() => { - disconnect(); + setIsPersonalWalletConnected(false); props.goBack(); }} onConnect={props.connected} diff --git a/packages/react/src/wallet/wallets/smartWallet/SmartWalletConnecting.tsx b/packages/react/src/wallet/wallets/smartWallet/SmartWalletConnecting.tsx index 5d8bb7efcdc..9536eaf3eef 100644 --- a/packages/react/src/wallet/wallets/smartWallet/SmartWalletConnecting.tsx +++ b/packages/react/src/wallet/wallets/smartWallet/SmartWalletConnecting.tsx @@ -4,13 +4,8 @@ import { Button } from "../../../components/buttons"; import { iconSize, spacing, fontSize } from "../../../design-system"; import { ExclamationTriangleIcon } from "@radix-ui/react-icons"; import { - useChain, useConnect, - useConnectionStatus, - useNetworkMismatch, useWalletContext, - useWallet, - useSwitchChain, WalletConfig, } from "@thirdweb-dev/react-core"; import { useCallback, useContext, useEffect, useRef, useState } from "react"; @@ -24,54 +19,63 @@ export const SmartWalletConnecting: React.FC<{ onBack: () => void; onConnect: () => void; smartWallet: SmartWalletConfig; - personalWallet: WalletConfig; + personalWalletConfig: WalletConfig; }> = (props) => { const locale = useTWLocale().wallets.smartWallet; - const activeWallet = useWallet(); // personal wallet - const connect = useConnect(); - const connectedChain = useChain(); - const targetChain = useWalletContext().activeChain; - - const mismatch = useNetworkMismatch(); - - const [connectError, setConnectError] = useState(false); + // personal wallet + const { setIsConnectionHidden, hiddenConnection } = useWalletContext(); + const personalWallet = hiddenConnection?.wallet; + const personalWalletChainId = hiddenConnection?.chainId; const [switchError, setSwitchError] = useState(false); const [switchingNetwork, setSwitchingNetwork] = useState(false); - const connectionStatus = useConnectionStatus(); + // smart wallet + const connect = useConnect(); + const targetChain = useWalletContext().activeChain; + const mismatch = targetChain.chainId !== personalWalletChainId; + const [connectError, setConnectError] = useState(false); + const [isConnectingSafe, setIsConnectingSafe] = useState(false); const { onConnect } = props; const connectStarted = useRef(false); - const switchChain = useSwitchChain(); const modalSize = useContext(ModalConfigCtx).modalSize; const handleConnect = useCallback(async () => { - if (!activeWallet || !connectedChain || connectStarted.current) { + if (!personalWallet || !personalWalletChainId || connectStarted.current) { return; } setConnectError(false); + setIsConnectingSafe(true); try { connectStarted.current = true; await connect(props.smartWallet, { - personalWallet: activeWallet, + personalWallet: personalWallet, }); + setIsConnectionHidden(false); onConnect(); } catch (e) { console.error(e); setConnectError(true); } - }, [activeWallet, connectedChain, connect, props.smartWallet, onConnect]); + }, [ + personalWallet, + personalWalletChainId, + connect, + props.smartWallet, + onConnect, + setIsConnectionHidden, + ]); useEffect(() => { if (!mismatch) { handleConnect(); } - }, [mismatch, handleConnect, activeWallet, connectedChain]); + }, [mismatch, handleConnect, personalWallet, personalWalletChainId]); - if (!connectError && (connectionStatus === "connecting" || !mismatch)) { + if (!connectError && (isConnectingSafe || !mismatch)) { return ( @@ -150,14 +154,14 @@ export const SmartWalletConnecting: React.FC<{ gap: spacing.sm, }} onClick={async () => { - if (!activeWallet) { + if (!personalWallet) { throw new Error("No active wallet"); } setConnectError(false); setSwitchError(false); setSwitchingNetwork(true); try { - await switchChain(targetChain.chainId); + await hiddenConnection.switchChain(targetChain.chainId); } catch (e) { setSwitchError(true); } finally { diff --git a/packages/react/src/wallet/wallets/smartWallet/smartWallet.tsx b/packages/react/src/wallet/wallets/smartWallet/smartWallet.tsx index 989ef59ce02..0313f44fbdd 100644 --- a/packages/react/src/wallet/wallets/smartWallet/smartWallet.tsx +++ b/packages/react/src/wallet/wallets/smartWallet/smartWallet.tsx @@ -2,12 +2,13 @@ import { WalletConfig, ConnectUIProps, WalletOptions, - useWallet, + useWalletContext, } from "@thirdweb-dev/react-core"; import { SmartWallet } from "@thirdweb-dev/wallets"; import { SmartWalletConfig, SmartWalletConfigOptions } from "./types"; import { SmartWalletConnecting } from "./SmartWalletConnecting"; import { HeadlessConnectUI } from "../headlessConnectUI"; +import { useRef, useEffect, useState } from "react"; export const smartWallet = ( wallet: WalletConfig, @@ -34,17 +35,28 @@ export const smartWallet = ( export const SmartConnectUI = ( props: ConnectUIProps & { personalWallet: WalletConfig }, ) => { - const activeWallet = useWallet(); + const { setIsConnectionHidden } = useWalletContext(); const { walletConfig } = props; + const [isPersonalWalletConnected, setIsPersonalWalletConnected] = + useState(false); + + // hide the connection of personal wallet + const mounted = useRef(false); + useEffect(() => { + if (!mounted.current) { + setIsConnectionHidden(true); + mounted.current = true; + } + }, [setIsConnectionHidden]); const PersonalWalletConfig = props.personalWallet; - if (!activeWallet) { + if (!isPersonalWalletConnected) { const _props: ConnectUIProps = { ...props, walletConfig: PersonalWalletConfig, connected: () => { - // override to no-op + setIsPersonalWalletConnected(true); }, }; @@ -60,7 +72,7 @@ export const SmartConnectUI = ( onBack={props.goBack} onConnect={props.connected} smartWallet={walletConfig} - personalWallet={props.personalWallet} + personalWalletConfig={props.personalWallet} /> ); }; From e1ef9b4009d67702ad32a3e2e3541550e9eb4538 Mon Sep 17 00:00:00 2001 From: Manan Tank Date: Wed, 15 Nov 2023 19:53:28 +0530 Subject: [PATCH 02/20] fixes --- .../providers/thirdweb-wallet-provider.tsx | 2 +- packages/react/src/evm/locales/en.ts | 1 + packages/react/src/evm/locales/es.ts | 1 + packages/react/src/evm/locales/ja.ts | 1 + .../ConnectWallet/Modal/ConnectModal.tsx | 3 +++ .../wallet/ConnectWallet/WalletSelector.tsx | 19 ++++++++++++++----- .../src/wallet/wallets/safe/SelectAccount.tsx | 5 ----- .../src/wallet/wallets/safe/safeWallet.tsx | 19 ++++++++++--------- .../wallets/smartWallet/smartWallet.tsx | 4 ++++ 9 files changed, 35 insertions(+), 20 deletions(-) diff --git a/packages/react-core/src/core/providers/thirdweb-wallet-provider.tsx b/packages/react-core/src/core/providers/thirdweb-wallet-provider.tsx index 20e79139959..0c0405ed20a 100644 --- a/packages/react-core/src/core/providers/thirdweb-wallet-provider.tsx +++ b/packages/react-core/src/core/providers/thirdweb-wallet-provider.tsx @@ -142,7 +142,7 @@ export function ThirdwebWalletProvider( signerWallet?: WalletConfig; }>, ) { - let [isConnectionHidden, setIsConnectionHidden] = useState(false); + const [isConnectionHidden, setIsConnectionHidden] = useState(false); const [hiddenConnectionChainId, setHiddenConnectionChainId] = useState< number | undefined >(undefined); diff --git a/packages/react/src/evm/locales/en.ts b/packages/react/src/evm/locales/en.ts index 8381f164d7c..2523053dc15 100644 --- a/packages/react/src/evm/locales/en.ts +++ b/packages/react/src/evm/locales/en.ts @@ -52,6 +52,7 @@ export function enDefault() { personalWallet: "Personal Wallet", smartWallet: "Smart Wallet", or: "OR", + goBackButton: "Back", download: { chrome: "Download Chrome Extension", android: "Download on Google Play", diff --git a/packages/react/src/evm/locales/es.ts b/packages/react/src/evm/locales/es.ts index 4049dcdbad4..9494ee4914d 100644 --- a/packages/react/src/evm/locales/es.ts +++ b/packages/react/src/evm/locales/es.ts @@ -54,6 +54,7 @@ export function esDefault(): ThirdwebLocale { personalWallet: "Cartera personal", smartWallet: "Cartera inteligente", or: "O", + goBackButton: "Back", // TODO download: { chrome: "Descargar extensión para Chrome", android: "Descargar en Google Play", diff --git a/packages/react/src/evm/locales/ja.ts b/packages/react/src/evm/locales/ja.ts index 7ee1a290393..6955b470ed5 100644 --- a/packages/react/src/evm/locales/ja.ts +++ b/packages/react/src/evm/locales/ja.ts @@ -53,6 +53,7 @@ export function jaDefault(): ThirdwebLocale { personalWallet: "パーソナルウォレット", smartWallet: "スマートウォレット", or: "または", + goBackButton: "Back", // TODO download: { chrome: "Chrome拡張をダウンロード", android: "Google Playでダウンロード", diff --git a/packages/react/src/wallet/ConnectWallet/Modal/ConnectModal.tsx b/packages/react/src/wallet/ConnectWallet/Modal/ConnectModal.tsx index 554d7218801..7349c7409e7 100644 --- a/packages/react/src/wallet/ConnectWallet/Modal/ConnectModal.tsx +++ b/packages/react/src/wallet/ConnectWallet/Modal/ConnectModal.tsx @@ -7,6 +7,7 @@ import { useThirdwebAuthContext, useUser, useWallet, + useWalletContext, useWallets, } from "@thirdweb-dev/react-core"; import { @@ -41,6 +42,7 @@ export const ConnectModalContent = (props: { const walletConfigs = useWallets(); const connectionStatus = useConnectionStatus(); const disconnect = useDisconnect(); + const { setIsConnectionHidden } = useWalletContext(); const isWalletModalOpen = useIsWalletModalOpen(); const setIsWalletModalOpen = useSetIsWalletModalOpen(); @@ -57,6 +59,7 @@ export const ConnectModalContent = (props: { const authConfig = useThirdwebAuthContext(); const closeModal = () => { + setIsConnectionHidden(false); setIsWalletModalOpen(false); onModalUnmount(() => { setScreen(initialScreen); diff --git a/packages/react/src/wallet/ConnectWallet/WalletSelector.tsx b/packages/react/src/wallet/ConnectWallet/WalletSelector.tsx index df8fc169d92..b0bce757c8d 100644 --- a/packages/react/src/wallet/ConnectWallet/WalletSelector.tsx +++ b/packages/react/src/wallet/ConnectWallet/WalletSelector.tsx @@ -7,8 +7,8 @@ import { ScreenBottomContainer, Line, } from "../../components/basic"; -import { Button } from "../../components/buttons"; -import { BackButton, ModalTitle } from "../../components/modalElements"; +import { Button, IconButton } from "../../components/buttons"; +import { ModalTitle } from "../../components/modalElements"; import { iconSize, radius, spacing, Theme } from "../../design-system"; import styled from "@emotion/styled"; import { @@ -27,6 +27,7 @@ import { Spacer } from "../../components/Spacer"; import { TextDivider } from "../../components/TextDivider"; import { TOS } from "./Modal/TOS"; import { useTWLocale } from "../../evm/providers/locale-provider"; +import { ChevronLeftIcon } from "@radix-ui/react-icons"; export const WalletSelector: React.FC<{ walletConfigs: WalletConfig[]; @@ -381,12 +382,20 @@ export const WalletSelector: React.FC<{ paddingTop: 0, }} > - { setIsWalletGroupExpanded(false); }} - /> - {"Back"} + style={{ + gap: spacing.xxs, + transform: `translateX(-${spacing.xs})`, + paddingBlock: spacing.xxs, + paddingRight: spacing.xs, + }} + > + + {locale.goBackButton} + )} diff --git a/packages/react/src/wallet/wallets/safe/SelectAccount.tsx b/packages/react/src/wallet/wallets/safe/SelectAccount.tsx index 1a2e72e684f..8722394d133 100644 --- a/packages/react/src/wallet/wallets/safe/SelectAccount.tsx +++ b/packages/react/src/wallet/wallets/safe/SelectAccount.tsx @@ -85,11 +85,6 @@ export const SelectAccount: React.FC<{ } }; - console.log({ - personalWalletChainId, - safeChainId, - }); - const mismatch = safeChainId !== -1 && personalWalletChainId !== safeChainId; const isValidAddress = utils.isAddress(safeAddress); diff --git a/packages/react/src/wallet/wallets/safe/safeWallet.tsx b/packages/react/src/wallet/wallets/safe/safeWallet.tsx index 84eef355dd0..bdb3156e422 100644 --- a/packages/react/src/wallet/wallets/safe/safeWallet.tsx +++ b/packages/react/src/wallet/wallets/safe/safeWallet.tsx @@ -51,8 +51,12 @@ export const SafeConnectUI = ( const [isPersonalWalletConnected, setIsPersonalWalletConnected] = useState(false); - const { setIsConnectionHidden: setIgnoreWalletConnection } = - useWalletContext(); + const { setIsConnectionHidden } = useWalletContext(); + + const goBackToMain = () => { + setIsConnectionHidden(false); + props.goBack(); + }; // ignore wallet connection for personal wallet; const mounted = useRef(false); @@ -61,15 +65,15 @@ export const SafeConnectUI = ( return; } mounted.current = true; - setIgnoreWalletConnection(true); - }, [setIgnoreWalletConnection]); + setIsConnectionHidden(true); + }, [setIsConnectionHidden]); // if personal wallet is not selected if (!personalWalletConfig) { return ( 1} @@ -109,10 +113,7 @@ export const SafeConnectUI = ( return ( 1} - onBack={() => { - setIsPersonalWalletConnected(false); - props.goBack(); - }} + onBack={goBackToMain} onConnect={props.connected} safeWalletConfig={props.walletConfig} /> diff --git a/packages/react/src/wallet/wallets/smartWallet/smartWallet.tsx b/packages/react/src/wallet/wallets/smartWallet/smartWallet.tsx index 0313f44fbdd..319b474b1f1 100644 --- a/packages/react/src/wallet/wallets/smartWallet/smartWallet.tsx +++ b/packages/react/src/wallet/wallets/smartWallet/smartWallet.tsx @@ -58,6 +58,10 @@ export const SmartConnectUI = ( connected: () => { setIsPersonalWalletConnected(true); }, + goBack() { + setIsConnectionHidden(false); + props.goBack(); + }, }; if (PersonalWalletConfig.connectUI) { From e45e929ffc227cf0017d544d453746885fa9eeea Mon Sep 17 00:00:00 2001 From: Manan Tank Date: Wed, 15 Nov 2023 19:59:07 +0530 Subject: [PATCH 03/20] add changeset --- .changeset/khaki-queens-check.md | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 .changeset/khaki-queens-check.md diff --git a/.changeset/khaki-queens-check.md b/.changeset/khaki-queens-check.md new file mode 100644 index 00000000000..b01692228cf --- /dev/null +++ b/.changeset/khaki-queens-check.md @@ -0,0 +1,8 @@ +--- +"@thirdweb-dev/react-core": patch +"@thirdweb-dev/react": patch +--- + +- Added APIs in react-core to be able to "hide" a connection temporarily to avoid setting a intermediate wallet as "connected wallet" - For example: connecting a Safe requires connecting a personal wallet first and then connecting to Safe. Because of this - the app will show the personal wallet as connected for a brief moment. This API allows to hide the intermediate connection + +- Add ConnectEmbed component to embed the ConnectWallet's Modal UI directly in page From a70b4d950275dcd32fb41d5fefefba655b795102 Mon Sep 17 00:00:00 2001 From: Manan Tank Date: Wed, 15 Nov 2023 21:53:23 +0530 Subject: [PATCH 04/20] make embed a valid component --- packages/react/src/wallet/ConnectWallet/Modal/ConnectEmbed.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/react/src/wallet/ConnectWallet/Modal/ConnectEmbed.tsx b/packages/react/src/wallet/ConnectWallet/Modal/ConnectEmbed.tsx index ea4c115a702..3a84e2a893c 100644 --- a/packages/react/src/wallet/ConnectWallet/Modal/ConnectEmbed.tsx +++ b/packages/react/src/wallet/ConnectWallet/Modal/ConnectEmbed.tsx @@ -64,7 +64,7 @@ export const ConnectEmbed = ( }; if (connectionStatus === "connected") { - return; + return null; } return ( From e4a4e308ab67ae3e7b2ba1a2108a08fdb70b3d38 Mon Sep 17 00:00:00 2001 From: Manan Tank Date: Wed, 15 Nov 2023 22:50:33 +0530 Subject: [PATCH 05/20] add API to disconnect hidden connection --- .../src/core/providers/thirdweb-wallet-provider.tsx | 12 ++++++++++++ .../src/wallet/ConnectWallet/Modal/ConnectModal.tsx | 7 ++++++- .../react/src/wallet/wallets/safe/safeWallet.tsx | 3 ++- .../src/wallet/wallets/smartWallet/smartWallet.tsx | 9 +++++++-- 4 files changed, 27 insertions(+), 4 deletions(-) diff --git a/packages/react-core/src/core/providers/thirdweb-wallet-provider.tsx b/packages/react-core/src/core/providers/thirdweb-wallet-provider.tsx index 0c0405ed20a..1ff51e6a3f2 100644 --- a/packages/react-core/src/core/providers/thirdweb-wallet-provider.tsx +++ b/packages/react-core/src/core/providers/thirdweb-wallet-provider.tsx @@ -67,6 +67,7 @@ type HiddenConnection = { walletConfig: WalletConfig | undefined; chainId?: number; switchChain: (chainId: number) => Promise; + disconnect: () => void; }; // maps wallet instance to it's wallet config @@ -227,6 +228,16 @@ export function ThirdwebWalletProvider( } }, [hiddenConnectionWallet]); + /** + * Clear the states of hidden connection + */ + const disconnectHiddenConnection = useCallback(() => { + setSigner(undefined); + setActiveWallet(undefined); + setActiveWalletConfig(undefined); + setConnectionStatus("disconnected"); + }, []); + if (isConnectionHidden) { hiddenConnection = { connectionStatus, @@ -235,6 +246,7 @@ export function ThirdwebWalletProvider( walletConfig: activeWalletConfig, switchChain: switchChainHiddenConnection, chainId: hiddenConnectionChainId, + disconnect: disconnectHiddenConnection, }; connectionStatus = "disconnected"; diff --git a/packages/react/src/wallet/ConnectWallet/Modal/ConnectModal.tsx b/packages/react/src/wallet/ConnectWallet/Modal/ConnectModal.tsx index 7349c7409e7..775bb2f0f10 100644 --- a/packages/react/src/wallet/ConnectWallet/Modal/ConnectModal.tsx +++ b/packages/react/src/wallet/ConnectWallet/Modal/ConnectModal.tsx @@ -42,7 +42,7 @@ export const ConnectModalContent = (props: { const walletConfigs = useWallets(); const connectionStatus = useConnectionStatus(); const disconnect = useDisconnect(); - const { setIsConnectionHidden } = useWalletContext(); + const { setIsConnectionHidden, hiddenConnection } = useWalletContext(); const isWalletModalOpen = useIsWalletModalOpen(); const setIsWalletModalOpen = useSetIsWalletModalOpen(); @@ -59,6 +59,7 @@ export const ConnectModalContent = (props: { const authConfig = useThirdwebAuthContext(); const closeModal = () => { + hiddenConnection?.disconnect(); setIsConnectionHidden(false); setIsWalletModalOpen(false); onModalUnmount(() => { @@ -263,6 +264,8 @@ export const ConnectModal = () => { wallet, ]); + const { setIsConnectionHidden, hiddenConnection } = useWalletContext(); + return ( { setOpen={(value) => { setIsWalletModalOpen(value); if (!value) { + setIsConnectionHidden(false); + hiddenConnection?.disconnect(); const requiresSignIn = auth?.loginOptional ? false : !!authConfig?.authUrl && !user?.address; diff --git a/packages/react/src/wallet/wallets/safe/safeWallet.tsx b/packages/react/src/wallet/wallets/safe/safeWallet.tsx index bdb3156e422..19ca8d732c9 100644 --- a/packages/react/src/wallet/wallets/safe/safeWallet.tsx +++ b/packages/react/src/wallet/wallets/safe/safeWallet.tsx @@ -51,9 +51,10 @@ export const SafeConnectUI = ( const [isPersonalWalletConnected, setIsPersonalWalletConnected] = useState(false); - const { setIsConnectionHidden } = useWalletContext(); + const { setIsConnectionHidden, hiddenConnection } = useWalletContext(); const goBackToMain = () => { + hiddenConnection?.disconnect(); setIsConnectionHidden(false); props.goBack(); }; diff --git a/packages/react/src/wallet/wallets/smartWallet/smartWallet.tsx b/packages/react/src/wallet/wallets/smartWallet/smartWallet.tsx index 319b474b1f1..97e350fc2a9 100644 --- a/packages/react/src/wallet/wallets/smartWallet/smartWallet.tsx +++ b/packages/react/src/wallet/wallets/smartWallet/smartWallet.tsx @@ -35,7 +35,7 @@ export const smartWallet = ( export const SmartConnectUI = ( props: ConnectUIProps & { personalWallet: WalletConfig }, ) => { - const { setIsConnectionHidden } = useWalletContext(); + const { setIsConnectionHidden, hiddenConnection } = useWalletContext(); const { walletConfig } = props; const [isPersonalWalletConnected, setIsPersonalWalletConnected] = useState(false); @@ -59,6 +59,7 @@ export const SmartConnectUI = ( setIsPersonalWalletConnected(true); }, goBack() { + hiddenConnection?.disconnect(); setIsConnectionHidden(false); props.goBack(); }, @@ -73,7 +74,11 @@ export const SmartConnectUI = ( return ( { + hiddenConnection?.disconnect(); + setIsConnectionHidden(false); + props.goBack(); + }} onConnect={props.connected} smartWallet={walletConfig} personalWalletConfig={props.personalWallet} From e31b4e1ec75a4999cb80e6cde8eb86987e4e43a3 Mon Sep 17 00:00:00 2001 From: Manan Tank Date: Fri, 17 Nov 2023 03:29:50 +0530 Subject: [PATCH 06/20] update --- .../providers/thirdweb-wallet-provider.tsx | 223 +++++++++++------- .../ConnectWallet/Modal/ConnectEmbed.tsx | 42 ++-- .../ConnectWallet/Modal/ConnectModal.tsx | 14 +- .../wallet/ConnectWallet/WalletSelector.tsx | 2 +- .../src/wallet/wallets/safe/SelectAccount.tsx | 11 +- .../src/wallet/wallets/safe/safeWallet.tsx | 17 +- .../smartWallet/SmartWalletConnecting.tsx | 11 +- .../wallets/smartWallet/smartWallet.tsx | 36 ++- 8 files changed, 216 insertions(+), 140 deletions(-) diff --git a/packages/react-core/src/core/providers/thirdweb-wallet-provider.tsx b/packages/react-core/src/core/providers/thirdweb-wallet-provider.tsx index e979765ac9a..89295f35071 100644 --- a/packages/react-core/src/core/providers/thirdweb-wallet-provider.tsx +++ b/packages/react-core/src/core/providers/thirdweb-wallet-provider.tsx @@ -60,16 +60,6 @@ type ConnectFnArgs = connectParams: NonNullable>, ]; -type HiddenConnection = { - connectionStatus: ConnectionStatus; - signer: Signer | undefined; - wallet: WalletInstance | undefined; - walletConfig: WalletConfig | undefined; - chainId?: number; - switchChain: (chainId: number) => Promise; - disconnect: () => void; -}; - // maps wallet instance to it's wallet config const walletInstanceToConfig: Map< WalletInstance, @@ -104,24 +94,25 @@ type ThirdwebWalletContextData = { activeChainSetExplicitly: boolean; clientId?: string; /** - * when this flag is set to true, all wallet connection related states like signer, activeWallet, connectionStatus, activeWalletConfig - * will be set to reflect a "disconnected" state - * - signer, activeWallet, activeWalletConfig will be set to `undefined` - * - connectionStatus will be set to "disconnected" - * - * the actual values will be stored in `hiddenConnection` object - * - * This is only useful for connecting wallets like Safe or Smart Wallet + * flag indicating whether to treat any connection that happens as a personal wallet connection or not */ - isConnectionHidden: boolean; + isConnectingToPersonalWallet: boolean; /** - * Set value of `isConnectionHidden` flag + * Set value of `connectingToPersonalWallet` flag */ - setIsConnectionHidden: (value: boolean) => void; + setIsConnectingToPersonalWallet: (value: boolean) => void; /** - * Stores the values of `signer`, `activeWallet`, `activeWalletConfig`, `connectionStatus` when `isConnectionHidden` is set to true + * wallet connection states of personal wallet */ - hiddenConnection?: HiddenConnection; + personalWalletInfo: { + signer?: Signer; + wallet?: WalletInstance; + walletConfig?: WalletConfig; + connectionStatus: ConnectionStatus; + chainId?: number; + disconnect: () => Promise; + switchChain: (chain: number) => Promise; + }; }; const ThirdwebWalletContext = /* @__PURE__ */ createContext< @@ -143,26 +134,43 @@ export function ThirdwebWalletProvider( signerWallet?: WalletConfig; }>, ) { - const [isConnectionHidden, setIsConnectionHidden] = useState(false); - const [hiddenConnectionChainId, setHiddenConnectionChainId] = useState< + const [isConnectingToPersonalWallet, setIsConnectingToPersonalWallet] = + useState(false); + + // personal wallet + let [personalWalletSigner, setPersonalWalletSigner] = useState< + Signer | undefined + >(undefined); + + const [personalWalletConnectionStatus, setPersonalWalletConnectionStatus] = + useState("unknown"); + + let [personalWallet, setPersonalWallet] = useState< + WalletInstance | undefined + >(); + + const [personalWalletConfig, setPersonalWalletConfig] = useState< + WalletConfig | undefined + >(); + + const [personalWalletChainId, setPersonalWalletChainId] = useState< number | undefined >(undefined); - let hiddenConnection: HiddenConnection | undefined; + let [signer, _setSigner] = useState(undefined); - let [signer, setSigner] = useState(undefined); - let [connectionStatus, setConnectionStatus] = + const [connectionStatus, _setConnectionStatus] = useState("unknown"); const autoConnectTimeout = props.autoConnectTimeout || 15000; - let [activeWallet, setActiveWallet] = useState(); + let [activeWallet, _setActiveWallet] = useState(); const [createdWalletInstance, setCreatedWalletInstance] = useState< WalletInstance | undefined >(); - let [activeWalletConfig, setActiveWalletConfig] = useState< + const [activeWalletConfig, _setActiveWalletConfig] = useState< WalletConfig | undefined >(); @@ -196,64 +204,64 @@ export function ThirdwebWalletProvider( } }, []); - const hiddenConnectionWallet = isConnectionHidden ? activeWallet : undefined; + const setSigner = useCallback( + (_signer: Signer | undefined) => { + if (isConnectingToPersonalWallet) { + setPersonalWalletSigner(_signer); + } else { + _setSigner(_signer); + } + }, + [isConnectingToPersonalWallet], + ); - const switchChainHiddenConnection = useCallback( - async (chainId: number) => { - if (!hiddenConnectionWallet) { - throw new Error("No hidden wallet"); + const setConnectionStatus = useCallback( + (status: ConnectionStatus) => { + if (isConnectingToPersonalWallet) { + setPersonalWalletConnectionStatus(status); + } else { + _setConnectionStatus(status); } + }, + [isConnectingToPersonalWallet], + ); - await hiddenConnectionWallet.switchChain(chainId); - const _signer = await hiddenConnectionWallet.getSigner(); - await storeLastActiveChainId(chainId); + const setActiveWalletConfig = useCallback( + (_walletConfig: WalletConfig | undefined) => { + if (isConnectingToPersonalWallet) { + setPersonalWalletConfig(_walletConfig); + } else { + _setActiveWalletConfig(_walletConfig); + } + }, + [isConnectingToPersonalWallet], + ); - setSigner(_signer); + const setActiveWallet = useCallback( + (wallet: WalletInstance | undefined) => { + if (isConnectingToPersonalWallet) { + setPersonalWallet(wallet); + } else { + _setActiveWallet(wallet); + } }, - [hiddenConnectionWallet, storeLastActiveChainId], + [isConnectingToPersonalWallet], ); useEffect(() => { - if (hiddenConnectionWallet) { + if (personalWallet) { const update = () => { - hiddenConnectionWallet.getChainId().then((_chainId) => { - setHiddenConnectionChainId(_chainId); + personalWallet?.getChainId().then((_chainId) => { + setPersonalWalletChainId(_chainId); }); }; update(); - hiddenConnectionWallet.addListener("change", update); + personalWallet.addListener("change", update); } else { - setHiddenConnectionChainId(undefined); + setPersonalWalletChainId(undefined); } - }, [hiddenConnectionWallet]); - - /** - * Clear the states of hidden connection - */ - const disconnectHiddenConnection = useCallback(() => { - setSigner(undefined); - setActiveWallet(undefined); - setActiveWalletConfig(undefined); - setConnectionStatus("disconnected"); - }, []); - - if (isConnectionHidden) { - hiddenConnection = { - connectionStatus, - signer, - wallet: activeWallet, - walletConfig: activeWalletConfig, - switchChain: switchChainHiddenConnection, - chainId: hiddenConnectionChainId, - disconnect: disconnectHiddenConnection, - }; - - connectionStatus = "disconnected"; - signer = undefined; - activeWallet = undefined; - activeWalletConfig = undefined; - } + }, [personalWallet]); // if autoSwitch is enabled - enforce connection to activeChain const chainToConnect = props.autoSwitch ? props.activeChain : undefined; @@ -309,7 +317,7 @@ export function ThirdwebWalletProvider( const _signer = await wallet.getSigner(); setSigner(_signer); - // it autoconnected, then the details is already saved in storage, no need to store again + // it auto-connected, then the details is already saved in storage, no need to store again if (isAutoConnect) { return; } @@ -322,15 +330,16 @@ export function ThirdwebWalletProvider( }; // if personal wallet exists, we need to replace the connectParams.personalWallet to a stringifiable version - const personalWallet = wallet.getPersonalWallet() as AbstractClientWallet; - const personalWalletConfig = walletInstanceToConfig.get(personalWallet); + const _personalWallet = + wallet.getPersonalWallet() as AbstractClientWallet; + const _personalWalletConfig = walletInstanceToConfig.get(_personalWallet); - if (personalWallet && personalWalletConfig) { + if (_personalWallet && _personalWalletConfig) { walletInfo.connectParams = { ...walletInfo.connectParams, personalWallet: { - walletId: personalWalletConfig.id, - connectParams: personalWallet.getConnectParams(), + walletId: _personalWalletConfig.id, + connectParams: _personalWallet.getConnectParams(), }, }; @@ -339,7 +348,7 @@ export function ThirdwebWalletProvider( saveLastConnectedWalletInfo(walletInfo); } }, - [], + [setActiveWallet, setActiveWalletConfig, setConnectionStatus, setSigner], ); const switchChain = useCallback( @@ -354,7 +363,20 @@ export function ThirdwebWalletProvider( setSigner(_signer); }, - [activeWallet, storeLastActiveChainId], + [activeWallet, setSigner, storeLastActiveChainId], + ); + + const switchChainPersonalWallet = useCallback( + async (chainId: number) => { + if (!personalWallet) { + throw new Error("No active wallet"); + } + + await personalWallet.switchChain(chainId); + const _signer = await personalWallet.getSigner(); + setPersonalWalletSigner(_signer); + }, + [personalWallet], ); const autoConnectTriggered = useRef(false); @@ -482,6 +504,7 @@ export function ThirdwebWalletProvider( connectionStatus, autoConnectTimeout, props.signerWallet, + setConnectionStatus, ]); const connectWallet = useCallback( @@ -514,7 +537,12 @@ export function ThirdwebWalletProvider( return wallet; }, - [createWalletInstance, setConnectedWallet, chainToConnect], + [ + chainToConnect?.chainId, + createWalletInstance, + setConnectionStatus, + setConnectedWallet, + ], ); const onWalletDisconnect = useCallback(async () => { @@ -525,7 +553,7 @@ export function ThirdwebWalletProvider( setSigner(undefined); setActiveWallet(undefined); setActiveWalletConfig(undefined); - }, []); + }, [setActiveWallet, setActiveWalletConfig, setConnectionStatus, setSigner]); const disconnectWallet = useCallback(async () => { // if disconnect is called before the wallet is connected @@ -534,16 +562,23 @@ export function ThirdwebWalletProvider( return; } - const personalWallet = activeWallet.getPersonalWallet(); + const _personalWallet = activeWallet.getPersonalWallet(); await activeWallet.disconnect(); - if (personalWallet) { - await (personalWallet as AbstractClientWallet)?.disconnect(); + if (_personalWallet) { + await (_personalWallet as AbstractClientWallet)?.disconnect(); } onWalletDisconnect(); }, [activeWallet, onWalletDisconnect]); + const disconnectPersonalWallet = useCallback(async () => { + setConnectionStatus("disconnected"); + setSigner(undefined); + setActiveWallet(undefined); + setActiveWalletConfig(undefined); + }, [setActiveWallet, setActiveWalletConfig, setConnectionStatus, setSigner]); + // when wallet's network or account is changed using the extension, update UI useEffect(() => { const wallet = activeWallet; @@ -569,7 +604,7 @@ export function ThirdwebWalletProvider( wallet.removeListener("change"); wallet.removeListener("disconnect"); }; - }, [activeWallet, onWalletDisconnect]); + }, [activeWallet, onWalletDisconnect, setSigner]); // connect signerWallet immediately if it's passed // and disconnect it if it's not passed @@ -621,9 +656,17 @@ export function ThirdwebWalletProvider( }, activeChainSetExplicitly: props.activeChainSetExplicitly, clientId: props.clientId, - hiddenConnection: hiddenConnection, - isConnectionHidden: isConnectionHidden, - setIsConnectionHidden: setIsConnectionHidden, + isConnectingToPersonalWallet, + setIsConnectingToPersonalWallet, + personalWalletInfo: { + signer: personalWalletSigner, + wallet: personalWallet, + walletConfig: personalWalletConfig, + connectionStatus: personalWalletConnectionStatus, + chainId: personalWalletChainId, + disconnect: disconnectPersonalWallet, + switchChain: switchChainPersonalWallet, + }, }} > {props.children} diff --git a/packages/react/src/wallet/ConnectWallet/Modal/ConnectEmbed.tsx b/packages/react/src/wallet/ConnectWallet/Modal/ConnectEmbed.tsx index 3a84e2a893c..9fc2fa3e0ae 100644 --- a/packages/react/src/wallet/ConnectWallet/Modal/ConnectEmbed.tsx +++ b/packages/react/src/wallet/ConnectWallet/Modal/ConnectEmbed.tsx @@ -1,5 +1,3 @@ -import { Theme, radius } from "../../../design-system"; -import styled from "@emotion/styled"; import { SetModalConfigCtx, WalletUIStatesProvider, @@ -15,10 +13,15 @@ import { useScreen } from "./screen"; import { isMobile } from "../../../evm/utils/isMobile"; import { useConnectionStatus, useWallets } from "@thirdweb-dev/react-core"; import { DynamicHeight } from "../../../components/DynamicHeight"; -import { CustomThemeProvider } from "../../../design-system/CustomThemeProvider"; +import { + CustomThemeProvider, + useCustomTheme, +} from "../../../design-system/CustomThemeProvider"; import { ComponentProps, useContext, useEffect } from "react"; import { ConnectWalletProps } from "../ConnectWallet"; import { useTWLocale } from "../../../evm/providers/locale-provider"; +import { StyledDiv } from "../../../design-system/elements"; +import { radius } from "../../../design-system"; export const ConnectEmbed = ( props: Omit< @@ -125,18 +128,21 @@ function SyncedWalletUIStates( return ; } -const EmbedContainer = styled.div<{ theme?: Theme }>` - color: ${(p) => p.theme.colors.primaryText}; - width: 100%; - box-sizing: border-box; - position: relative; - line-height: normal; - border-radius: ${radius.xl}; - border: 1px solid ${(p) => p.theme.colors.borderColor}; - overflow: hidden; - font-family: ${(p) => p.theme.fontFamily}; - & *::selection { - background-color: ${(p) => p.theme.colors.primaryText}; - color: ${(p) => p.theme.colors.modalBg}; - } -`; +const EmbedContainer = /* @__PURE__ */ StyledDiv(() => { + const theme = useCustomTheme(); + return { + color: theme.colors.primaryText, + width: "100%", + boxSizing: "border-box", + position: "relative", + lineHeight: "normal", + borderRadius: radius.xl, + border: `1px solid ${theme.colors.borderColor}`, + overflow: "hidden", + fontFamily: theme.fontFamily, + "& *::selection": { + backgroundColor: theme.colors.primaryText, + color: theme.colors.modalBg, + }, + }; +}); diff --git a/packages/react/src/wallet/ConnectWallet/Modal/ConnectModal.tsx b/packages/react/src/wallet/ConnectWallet/Modal/ConnectModal.tsx index 08f3a7174e3..18d0976b9e2 100644 --- a/packages/react/src/wallet/ConnectWallet/Modal/ConnectModal.tsx +++ b/packages/react/src/wallet/ConnectWallet/Modal/ConnectModal.tsx @@ -44,7 +44,8 @@ export const ConnectModalContent = (props: { const walletConfigs = useWallets(); const connectionStatus = useConnectionStatus(); const disconnect = useDisconnect(); - const { setIsConnectionHidden, hiddenConnection } = useWalletContext(); + const { setIsConnectingToPersonalWallet, personalWalletInfo } = + useWalletContext(); const isWalletModalOpen = useIsWalletModalOpen(); const setIsWalletModalOpen = useSetIsWalletModalOpen(); @@ -61,8 +62,8 @@ export const ConnectModalContent = (props: { const authConfig = useThirdwebAuthContext(); const closeModal = () => { - hiddenConnection?.disconnect(); - setIsConnectionHidden(false); + personalWalletInfo?.disconnect(); + setIsConnectingToPersonalWallet(false); setIsWalletModalOpen(false); onModalUnmount(() => { setScreen(initialScreen); @@ -266,7 +267,8 @@ export const ConnectModal = () => { wallet, ]); - const { setIsConnectionHidden, hiddenConnection } = useWalletContext(); + const { setIsConnectingToPersonalWallet, personalWalletInfo } = + useWalletContext(); return ( @@ -277,8 +279,8 @@ export const ConnectModal = () => { setOpen={(value) => { setIsWalletModalOpen(value); if (!value) { - setIsConnectionHidden(false); - hiddenConnection?.disconnect(); + setIsConnectingToPersonalWallet(false); + personalWalletInfo?.disconnect(); const requiresSignIn = auth?.loginOptional ? false : !!authConfig?.authUrl && !user?.address; diff --git a/packages/react/src/wallet/ConnectWallet/WalletSelector.tsx b/packages/react/src/wallet/ConnectWallet/WalletSelector.tsx index 78979a4b445..57aafdd542c 100644 --- a/packages/react/src/wallet/ConnectWallet/WalletSelector.tsx +++ b/packages/react/src/wallet/ConnectWallet/WalletSelector.tsx @@ -27,7 +27,7 @@ import { TextDivider } from "../../components/TextDivider"; import { TOS } from "./Modal/TOS"; import { useTWLocale } from "../../evm/providers/locale-provider"; import { ChevronLeftIcon } from "@radix-ui/react-icons"; -import { StyledButton, StyledUl, StyledUl } from "../../design-system/elements"; +import { StyledButton, StyledUl } from "../../design-system/elements"; import { useCustomTheme } from "../../design-system/CustomThemeProvider"; export const WalletSelector: React.FC<{ diff --git a/packages/react/src/wallet/wallets/safe/SelectAccount.tsx b/packages/react/src/wallet/wallets/safe/SelectAccount.tsx index 821d06c5dd4..496e80b51fb 100644 --- a/packages/react/src/wallet/wallets/safe/SelectAccount.tsx +++ b/packages/react/src/wallet/wallets/safe/SelectAccount.tsx @@ -36,9 +36,10 @@ export const SelectAccount: React.FC<{ const locale = useTWLocale().wallets.safeWallet.accountDetailsScreen; // personal wallet - const { setIsConnectionHidden, hiddenConnection } = useWalletContext(); - const personalWallet = hiddenConnection?.wallet; - const personalWalletChainId = hiddenConnection?.chainId; + const { personalWalletInfo } = useWalletContext(); + const personalWallet = personalWalletInfo?.wallet; + const personalWalletChainId = personalWalletInfo?.chainId; + const switchChainPersonalWallet = personalWalletInfo?.switchChain; const [switchError, setSwitchError] = useState(false); const [switchingNetwork, setSwitchingNetwork] = useState(false); @@ -72,13 +73,13 @@ export const SelectAccount: React.FC<{ } setSafeConnectError(false); setSafeConnectionStatus("connecting"); + console.log("not connection to personal wallet"); try { await connectSafe(props.safeWalletConfig, { chain: selectedSafeChain, personalWallet: personalWallet, safeAddress, }); - setIsConnectionHidden(false); props.onConnect(); } catch (e) { setSafeConnectionStatus("failed"); @@ -332,7 +333,7 @@ export const SelectAccount: React.FC<{ setSwitchError(false); setSwitchingNetwork(true); try { - await hiddenConnection.switchChain(safeChainId); + await switchChainPersonalWallet(safeChainId); } catch (e) { setSwitchError(true); } finally { diff --git a/packages/react/src/wallet/wallets/safe/safeWallet.tsx b/packages/react/src/wallet/wallets/safe/safeWallet.tsx index 19ca8d732c9..35a7be195dd 100644 --- a/packages/react/src/wallet/wallets/safe/safeWallet.tsx +++ b/packages/react/src/wallet/wallets/safe/safeWallet.tsx @@ -51,23 +51,23 @@ export const SafeConnectUI = ( const [isPersonalWalletConnected, setIsPersonalWalletConnected] = useState(false); - const { setIsConnectionHidden, hiddenConnection } = useWalletContext(); + const { setIsConnectingToPersonalWallet, personalWalletInfo } = + useWalletContext(); const goBackToMain = () => { - hiddenConnection?.disconnect(); - setIsConnectionHidden(false); + personalWalletInfo.disconnect(); + setIsConnectingToPersonalWallet(false); props.goBack(); }; - // ignore wallet connection for personal wallet; const mounted = useRef(false); useEffect(() => { if (mounted.current) { return; } mounted.current = true; - setIsConnectionHidden(true); - }, [setIsConnectionHidden]); + setIsConnectingToPersonalWallet(true); + }, [setIsConnectingToPersonalWallet]); // if personal wallet is not selected if (!personalWalletConfig) { @@ -76,7 +76,9 @@ export const SafeConnectUI = ( personalWallets={props.personalWallets} onBack={goBackToMain} safeWallet={props.walletConfig} - selectWallet={setPersonalWalletConfig} + selectWallet={(walletConfig) => { + setPersonalWalletConfig(walletConfig); + }} renderBackButton={props.supportedWallets.length > 1} /> ); @@ -91,6 +93,7 @@ export const SafeConnectUI = ( }, connected() { setIsPersonalWalletConnected(true); + setIsConnectingToPersonalWallet(false); }, isOpen: props.isOpen, hide: props.hide, diff --git a/packages/react/src/wallet/wallets/smartWallet/SmartWalletConnecting.tsx b/packages/react/src/wallet/wallets/smartWallet/SmartWalletConnecting.tsx index 9536eaf3eef..2ef95c59f9b 100644 --- a/packages/react/src/wallet/wallets/smartWallet/SmartWalletConnecting.tsx +++ b/packages/react/src/wallet/wallets/smartWallet/SmartWalletConnecting.tsx @@ -24,10 +24,11 @@ export const SmartWalletConnecting: React.FC<{ const locale = useTWLocale().wallets.smartWallet; // personal wallet - const { setIsConnectionHidden, hiddenConnection } = useWalletContext(); - const personalWallet = hiddenConnection?.wallet; - const personalWalletChainId = hiddenConnection?.chainId; + const { personalWalletInfo } = useWalletContext(); + const personalWallet = personalWalletInfo?.wallet; + const personalWalletChainId = personalWalletInfo?.chainId; const [switchError, setSwitchError] = useState(false); + const switchPersonalWalletChain = personalWalletInfo.switchChain; const [switchingNetwork, setSwitchingNetwork] = useState(false); // smart wallet @@ -54,7 +55,6 @@ export const SmartWalletConnecting: React.FC<{ await connect(props.smartWallet, { personalWallet: personalWallet, }); - setIsConnectionHidden(false); onConnect(); } catch (e) { console.error(e); @@ -66,7 +66,6 @@ export const SmartWalletConnecting: React.FC<{ connect, props.smartWallet, onConnect, - setIsConnectionHidden, ]); useEffect(() => { @@ -161,7 +160,7 @@ export const SmartWalletConnecting: React.FC<{ setSwitchError(false); setSwitchingNetwork(true); try { - await hiddenConnection.switchChain(targetChain.chainId); + await switchPersonalWalletChain(targetChain.chainId); } catch (e) { setSwitchError(true); } finally { diff --git a/packages/react/src/wallet/wallets/smartWallet/smartWallet.tsx b/packages/react/src/wallet/wallets/smartWallet/smartWallet.tsx index 97e350fc2a9..67e269b4814 100644 --- a/packages/react/src/wallet/wallets/smartWallet/smartWallet.tsx +++ b/packages/react/src/wallet/wallets/smartWallet/smartWallet.tsx @@ -9,6 +9,8 @@ import { SmartWalletConfig, SmartWalletConfigOptions } from "./types"; import { SmartWalletConnecting } from "./SmartWalletConnecting"; import { HeadlessConnectUI } from "../headlessConnectUI"; import { useRef, useEffect, useState } from "react"; +import { Container } from "../../../components/basic"; +import { Spinner } from "../../../components/Spinner"; export const smartWallet = ( wallet: WalletConfig, @@ -35,7 +37,11 @@ export const smartWallet = ( export const SmartConnectUI = ( props: ConnectUIProps & { personalWallet: WalletConfig }, ) => { - const { setIsConnectionHidden, hiddenConnection } = useWalletContext(); + const { + setIsConnectingToPersonalWallet, + personalWalletInfo, + isConnectingToPersonalWallet, + } = useWalletContext(); const { walletConfig } = props; const [isPersonalWalletConnected, setIsPersonalWalletConnected] = useState(false); @@ -44,23 +50,39 @@ export const SmartConnectUI = ( const mounted = useRef(false); useEffect(() => { if (!mounted.current) { - setIsConnectionHidden(true); + setIsConnectingToPersonalWallet(true); mounted.current = true; } - }, [setIsConnectionHidden]); + }, [setIsConnectingToPersonalWallet]); const PersonalWalletConfig = props.personalWallet; if (!isPersonalWalletConnected) { + // if the isConnectingToPersonalWallet is not yet updated + if (!isConnectingToPersonalWallet) { + return ( + + + + ); + } + const _props: ConnectUIProps = { ...props, walletConfig: PersonalWalletConfig, connected: () => { setIsPersonalWalletConnected(true); + setIsConnectingToPersonalWallet(false); }, goBack() { - hiddenConnection?.disconnect(); - setIsConnectionHidden(false); + personalWalletInfo?.disconnect(); + setIsConnectingToPersonalWallet(false); props.goBack(); }, }; @@ -75,8 +97,8 @@ export const SmartConnectUI = ( return ( { - hiddenConnection?.disconnect(); - setIsConnectionHidden(false); + personalWalletInfo?.disconnect(); + setIsConnectingToPersonalWallet(false); props.goBack(); }} onConnect={props.connected} From 4fda0f3bac51c507b6c5025f87b40fb8a95b928f Mon Sep 17 00:00:00 2001 From: Manan Tank Date: Fri, 17 Nov 2023 17:20:41 +0530 Subject: [PATCH 07/20] update --- .../providers/thirdweb-wallet-provider.tsx | 407 ++++++++++-------- .../wallets/smartWallet/smartWallet.tsx | 4 +- 2 files changed, 239 insertions(+), 172 deletions(-) diff --git a/packages/react-core/src/core/providers/thirdweb-wallet-provider.tsx b/packages/react-core/src/core/providers/thirdweb-wallet-provider.tsx index 89295f35071..c0a230fde98 100644 --- a/packages/react-core/src/core/providers/thirdweb-wallet-provider.tsx +++ b/packages/react-core/src/core/providers/thirdweb-wallet-provider.tsx @@ -66,6 +66,16 @@ const walletInstanceToConfig: Map< WalletConfig > = new Map(); +type PersonalWalletInfo = { + signer?: Signer; + wallet?: WalletInstance; + walletConfig?: WalletConfig; + connectionStatus: ConnectionStatus; + chainId?: number; + disconnect: () => Promise; + switchChain: (chainId: number) => Promise; +}; + type ThirdwebWalletContextData = { wallets: WalletConfig[]; signer?: Signer; @@ -104,15 +114,7 @@ type ThirdwebWalletContextData = { /** * wallet connection states of personal wallet */ - personalWalletInfo: { - signer?: Signer; - wallet?: WalletInstance; - walletConfig?: WalletConfig; - connectionStatus: ConnectionStatus; - chainId?: number; - disconnect: () => Promise; - switchChain: (chain: number) => Promise; - }; + personalWalletInfo: PersonalWalletInfo; }; const ThirdwebWalletContext = /* @__PURE__ */ createContext< @@ -134,51 +136,45 @@ export function ThirdwebWalletProvider( signerWallet?: WalletConfig; }>, ) { - const [isConnectingToPersonalWallet, setIsConnectingToPersonalWallet] = - useState(false); - - // personal wallet - let [personalWalletSigner, setPersonalWalletSigner] = useState< - Signer | undefined - >(undefined); + const autoConnectTimeout = props.autoConnectTimeout || 15000; - const [personalWalletConnectionStatus, setPersonalWalletConnectionStatus] = - useState("unknown"); + if (!lastConnectedWalletStorage) { + lastConnectedWalletStorage = + props.createWalletStorage("coordinatorStorage"); + } - let [personalWallet, setPersonalWallet] = useState< - WalletInstance | undefined - >(); + // if autoSwitch is enabled - enforce connection to activeChain + const chainToConnect = props.autoSwitch ? props.activeChain : undefined; - const [personalWalletConfig, setPersonalWalletConfig] = useState< - WalletConfig | undefined - >(); + const [isConnectingToPersonalWallet, setIsConnectingToPersonalWallet] = + useState(false); - const [personalWalletChainId, setPersonalWalletChainId] = useState< - number | undefined - >(undefined); + const personalWalletConnection = usePersonalWalletConnection(); - let [signer, _setSigner] = useState(undefined); + const { + wallet: personalWallet, + setWallet: setPersonalWallet, + setSigner: setPersonalWalletSigner, + setConnectionStatus: setPersonalWalletConnectionStatus, + setWalletConfig: setPersonalWalletConfig, + } = personalWalletConnection; - const [connectionStatus, _setConnectionStatus] = + const [signer, setSigner] = useState(undefined); + const [connectionStatus, setConnectionStatus] = useState("unknown"); - const autoConnectTimeout = props.autoConnectTimeout || 15000; - - let [activeWallet, _setActiveWallet] = useState(); + const [activeWallet, setActiveWallet] = useState< + WalletInstance | undefined + >(); const [createdWalletInstance, setCreatedWalletInstance] = useState< WalletInstance | undefined >(); - const [activeWalletConfig, _setActiveWalletConfig] = useState< + const [activeWalletConfig, setActiveWalletConfig] = useState< WalletConfig | undefined >(); - if (!lastConnectedWalletStorage) { - lastConnectedWalletStorage = - props.createWalletStorage("coordinatorStorage"); - } - const storeLastActiveChainId = useCallback(async (chainId: number) => { const lastConnectedWallet = await lastConnectedWalletStorage.getItem( LAST_CONNECTED_WALLET_STORAGE_KEY, @@ -204,68 +200,6 @@ export function ThirdwebWalletProvider( } }, []); - const setSigner = useCallback( - (_signer: Signer | undefined) => { - if (isConnectingToPersonalWallet) { - setPersonalWalletSigner(_signer); - } else { - _setSigner(_signer); - } - }, - [isConnectingToPersonalWallet], - ); - - const setConnectionStatus = useCallback( - (status: ConnectionStatus) => { - if (isConnectingToPersonalWallet) { - setPersonalWalletConnectionStatus(status); - } else { - _setConnectionStatus(status); - } - }, - [isConnectingToPersonalWallet], - ); - - const setActiveWalletConfig = useCallback( - (_walletConfig: WalletConfig | undefined) => { - if (isConnectingToPersonalWallet) { - setPersonalWalletConfig(_walletConfig); - } else { - _setActiveWalletConfig(_walletConfig); - } - }, - [isConnectingToPersonalWallet], - ); - - const setActiveWallet = useCallback( - (wallet: WalletInstance | undefined) => { - if (isConnectingToPersonalWallet) { - setPersonalWallet(wallet); - } else { - _setActiveWallet(wallet); - } - }, - [isConnectingToPersonalWallet], - ); - - useEffect(() => { - if (personalWallet) { - const update = () => { - personalWallet?.getChainId().then((_chainId) => { - setPersonalWalletChainId(_chainId); - }); - }; - - update(); - personalWallet.addListener("change", update); - } else { - setPersonalWalletChainId(undefined); - } - }, [personalWallet]); - - // if autoSwitch is enabled - enforce connection to activeChain - const chainToConnect = props.autoSwitch ? props.activeChain : undefined; - const walletParams: WalletOptions = useMemo(() => { return { chains: props.chains, @@ -292,12 +226,25 @@ export function ThirdwebWalletProvider( [walletParams], ); - // if props.chains is updated, update the active wallet's chains + // if props.chains is updated, update the wallet's chains useEffect(() => { if (activeWallet) { activeWallet.updateChains(props.chains); + const _personalWallet = activeWallet.getPersonalWallet(); + if (_personalWallet instanceof AbstractClientWallet) { + _personalWallet.updateChains(props.chains); + } } - }, [activeWallet, props.chains]); + + if (isConnectingToPersonalWallet && personalWallet) { + personalWallet.updateChains(props.chains); + } + }, [ + activeWallet, + props.chains, + personalWallet, + isConnectingToPersonalWallet, + ]); const setConnectedWallet = useCallback( async ( @@ -305,23 +252,45 @@ export function ThirdwebWalletProvider( connectParams?: ConnectParams>, isAutoConnect = false, ) => { - setActiveWallet(wallet); + if (isConnectingToPersonalWallet) { + setPersonalWallet(wallet); + } else { + setActiveWallet(wallet); + } + const walletConfig = walletInstanceToConfig.get(wallet); if (!walletConfig) { throw new Error( "Wallet config not found for given wallet instance. Do not create a wallet instance manually - use the useCreateWalletInstance() hook instead", ); } - setActiveWalletConfig(walletConfig); - setConnectionStatus("connected"); + + if (isConnectingToPersonalWallet) { + setPersonalWalletConfig(walletConfig); + setPersonalWalletConnectionStatus("connected"); + } else { + setActiveWalletConfig(walletConfig); + setConnectionStatus("connected"); + } + const _signer = await wallet.getSigner(); - setSigner(_signer); + + if (isConnectingToPersonalWallet) { + setPersonalWalletSigner(_signer); + } else { + setSigner(_signer); + } // it auto-connected, then the details is already saved in storage, no need to store again if (isAutoConnect) { return; } + // do not save connection details for personal wallet + if (isConnectingToPersonalWallet) { + return; + } + // save to storage const walletInfo: LastConnectedWalletInfo = { @@ -329,9 +298,10 @@ export function ThirdwebWalletProvider( connectParams: connectParams || wallet.getConnectParams(), }; - // if personal wallet exists, we need to replace the connectParams.personalWallet to a stringifiable version + // if personal wallet exists, we need to replace the connectParams.personalWallet to a serializable version const _personalWallet = wallet.getPersonalWallet() as AbstractClientWallet; + const _personalWalletConfig = walletInstanceToConfig.get(_personalWallet); if (_personalWallet && _personalWalletConfig) { @@ -348,40 +318,46 @@ export function ThirdwebWalletProvider( saveLastConnectedWalletInfo(walletInfo); } }, - [setActiveWallet, setActiveWalletConfig, setConnectionStatus, setSigner], + [ + isConnectingToPersonalWallet, + setPersonalWallet, + setPersonalWalletConfig, + setPersonalWalletConnectionStatus, + setPersonalWalletSigner, + ], ); const switchChain = useCallback( async (chainId: number) => { - if (!activeWallet) { + const wallet = isConnectingToPersonalWallet + ? personalWallet + : activeWallet; + + if (!wallet) { throw new Error("No active wallet"); } - await activeWallet.switchChain(chainId); - const _signer = await activeWallet.getSigner(); - await storeLastActiveChainId(chainId); - - setSigner(_signer); - }, - [activeWallet, setSigner, storeLastActiveChainId], - ); + await wallet.switchChain(chainId); + const _signer = await wallet.getSigner(); - const switchChainPersonalWallet = useCallback( - async (chainId: number) => { - if (!personalWallet) { - throw new Error("No active wallet"); + if (!isConnectingToPersonalWallet) { + await storeLastActiveChainId(chainId); + setSigner(_signer); + } else { + setPersonalWalletSigner(_signer); } - - await personalWallet.switchChain(chainId); - const _signer = await personalWallet.getSigner(); - setPersonalWalletSigner(_signer); }, - [personalWallet], + [ + isConnectingToPersonalWallet, + personalWallet, + activeWallet, + storeLastActiveChainId, + setPersonalWalletSigner, + ], ); - const autoConnectTriggered = useRef(false); - // Auto Connect + const autoConnectTriggered = useRef(false); useEffect(() => { // do not auto connect if signerWallet is given if (props.signerWallet) { @@ -410,7 +386,7 @@ export function ThirdwebWalletProvider( autoConnectTriggered.current = true; - async function autoconnect() { + async function autoConnect() { const walletInfo = await getLastConnectedWalletInfo(); if (!walletInfo) { @@ -433,12 +409,13 @@ export function ThirdwebWalletProvider( if (personalWalletInfo) { const personalWallets = walletObj.personalWallets || []; - const personalWalleObj = personalWallets.find( + const personalWalletObj = personalWallets.find( (W) => W.id === personalWalletInfo.walletId, ); - if (personalWalleObj) { + if (personalWalletObj) { // create a personal wallet instance and auto connect it - const personalWalletInstance = createWalletInstance(personalWalleObj); + const personalWalletInstance = + createWalletInstance(personalWalletObj); try { await timeoutPromise( @@ -494,7 +471,7 @@ export function ThirdwebWalletProvider( } } - autoconnect(); + autoConnect(); }, [ createWalletInstance, props.supportedWallets, @@ -517,7 +494,12 @@ export function ThirdwebWalletProvider( }; const wallet = createWalletInstance(WalletObj); - setConnectionStatus("connecting"); + if (isConnectingToPersonalWallet) { + setPersonalWalletConnectionStatus("connecting"); + } else { + setConnectionStatus("connecting"); + } + try { // if magic is using social login - it will redirect the page - so need to save walletInfo before connecting // TODO: find a better way to handle this @@ -531,7 +513,11 @@ export function ThirdwebWalletProvider( setConnectedWallet(wallet, _connectedParams); } catch (e: any) { console.error(`Error connecting to wallet: ${e}`); - setConnectionStatus("disconnected"); + if (isConnectingToPersonalWallet) { + setPersonalWalletConnectionStatus("disconnected"); + } else { + setConnectionStatus("disconnected"); + } throw e; } @@ -540,7 +526,8 @@ export function ThirdwebWalletProvider( [ chainToConnect?.chainId, createWalletInstance, - setConnectionStatus, + isConnectingToPersonalWallet, + setPersonalWalletConnectionStatus, setConnectedWallet, ], ); @@ -549,39 +536,47 @@ export function ThirdwebWalletProvider( await lastConnectedWalletStorage.removeItem( LAST_CONNECTED_WALLET_STORAGE_KEY, ); - setConnectionStatus("disconnected"); - setSigner(undefined); - setActiveWallet(undefined); - setActiveWalletConfig(undefined); - }, [setActiveWallet, setActiveWalletConfig, setConnectionStatus, setSigner]); - - const disconnectWallet = useCallback(async () => { - // if disconnect is called before the wallet is connected - if (!activeWallet) { - onWalletDisconnect(); - return; + if (isConnectingToPersonalWallet) { + setPersonalWalletConnectionStatus("disconnected"); + setPersonalWalletSigner(undefined); + setPersonalWallet(undefined); + setPersonalWalletConfig(undefined); + } else { + setConnectionStatus("disconnected"); + setSigner(undefined); + setActiveWallet(undefined); + setActiveWalletConfig(undefined); } + }, [ + isConnectingToPersonalWallet, + setPersonalWallet, + setPersonalWalletConnectionStatus, + setPersonalWalletSigner, + setPersonalWalletConfig, + ]); - const _personalWallet = activeWallet.getPersonalWallet(); - await activeWallet.disconnect(); + const disconnectWallet = useCallback(async () => { + const wallet = isConnectingToPersonalWallet ? personalWallet : activeWallet; - if (_personalWallet) { - await (_personalWallet as AbstractClientWallet)?.disconnect(); + if (wallet) { + const _personalWallet = wallet.getPersonalWallet(); + await wallet.disconnect(); + if (_personalWallet instanceof AbstractClientWallet) { + await _personalWallet.disconnect(); + } } - + console.log("disconnect the", { wallet, isConnectingToPersonalWallet }); onWalletDisconnect(); - }, [activeWallet, onWalletDisconnect]); - - const disconnectPersonalWallet = useCallback(async () => { - setConnectionStatus("disconnected"); - setSigner(undefined); - setActiveWallet(undefined); - setActiveWalletConfig(undefined); - }, [setActiveWallet, setActiveWalletConfig, setConnectionStatus, setSigner]); + }, [ + activeWallet, + isConnectingToPersonalWallet, + onWalletDisconnect, + personalWallet, + ]); // when wallet's network or account is changed using the extension, update UI useEffect(() => { - const wallet = activeWallet; + const wallet = isConnectingToPersonalWallet ? personalWallet : activeWallet; if (!wallet) { return; @@ -589,7 +584,11 @@ export function ThirdwebWalletProvider( const update = async () => { const _signer = await wallet.getSigner(); - setSigner(_signer); + if (isConnectingToPersonalWallet) { + setPersonalWalletSigner(_signer); + } else { + setSigner(_signer); + } }; wallet.addListener("change", () => { @@ -604,7 +603,14 @@ export function ThirdwebWalletProvider( wallet.removeListener("change"); wallet.removeListener("disconnect"); }; - }, [activeWallet, onWalletDisconnect, setSigner]); + }, [ + activeWallet, + isConnectingToPersonalWallet, + onWalletDisconnect, + personalWallet, + setPersonalWalletSigner, + setSigner, + ]); // connect signerWallet immediately if it's passed // and disconnect it if it's not passed @@ -659,13 +665,13 @@ export function ThirdwebWalletProvider( isConnectingToPersonalWallet, setIsConnectingToPersonalWallet, personalWalletInfo: { - signer: personalWalletSigner, - wallet: personalWallet, - walletConfig: personalWalletConfig, - connectionStatus: personalWalletConnectionStatus, - chainId: personalWalletChainId, - disconnect: disconnectPersonalWallet, - switchChain: switchChainPersonalWallet, + wallet: personalWalletConnection.wallet, + signer: personalWalletConnection.signer, + walletConfig: personalWalletConnection.walletConfig, + connectionStatus: personalWalletConnection.connectionStatus, + chainId: personalWalletConnection.chainId, + disconnect: personalWalletConnection.disconnect, + switchChain: personalWalletConnection.switchChain, }, }} > @@ -745,3 +751,64 @@ function timeoutPromise( } const autoConnectTimeoutErrorMessage = `Failed to Auto connect. Auto connect timed out. You can increase the timeout duration using the autoConnectTimeout prop on `; + +function usePersonalWalletConnection() { + const [signer, setSigner] = useState(undefined); + const [connectionStatus, setConnectionStatus] = + useState("unknown"); + const [wallet, setWallet] = useState(); + const [walletConfig, setWalletConfig] = useState(); + const [chainId, setChainId] = useState(undefined); + + useEffect(() => { + if (wallet) { + const update = () => { + wallet?.getChainId().then((_chainId) => { + setChainId(_chainId); + }); + }; + + update(); + wallet.addListener("change", update); + } else { + setChainId(undefined); + } + }, [wallet]); + + const disconnect = useCallback(async () => { + setConnectionStatus("disconnected"); + setSigner(undefined); + setWallet(undefined); + setWalletConfig(undefined); + if (wallet) { + await wallet.disconnect(); + } + }, [wallet]); + + const switchChain = useCallback( + async (_chainId: number) => { + if (!wallet) { + throw new Error("No active wallet"); + } + + await wallet.switchChain(_chainId); + const _signer = await wallet.getSigner(); + setSigner(_signer); + }, + [wallet], + ); + + return { + signer: signer, + setSigner: setSigner, + wallet: wallet, + setWallet: setWallet, + walletConfig: walletConfig, + setWalletConfig: setWalletConfig, + connectionStatus: connectionStatus, + setConnectionStatus: setConnectionStatus, + chainId: chainId, + disconnect, + switchChain, + }; +} diff --git a/packages/react/src/wallet/wallets/smartWallet/smartWallet.tsx b/packages/react/src/wallet/wallets/smartWallet/smartWallet.tsx index 67e269b4814..812c0cf122f 100644 --- a/packages/react/src/wallet/wallets/smartWallet/smartWallet.tsx +++ b/packages/react/src/wallet/wallets/smartWallet/smartWallet.tsx @@ -81,7 +81,7 @@ export const SmartConnectUI = ( setIsConnectingToPersonalWallet(false); }, goBack() { - personalWalletInfo?.disconnect(); + personalWalletInfo.disconnect(); setIsConnectingToPersonalWallet(false); props.goBack(); }, @@ -97,7 +97,7 @@ export const SmartConnectUI = ( return ( { - personalWalletInfo?.disconnect(); + personalWalletInfo.disconnect(); setIsConnectingToPersonalWallet(false); props.goBack(); }} From 4a24f6e2184447d598152e0b467bace35ceac105 Mon Sep 17 00:00:00 2001 From: Manan Tank Date: Fri, 17 Nov 2023 17:25:36 +0530 Subject: [PATCH 08/20] update --- .../providers/thirdweb-wallet-provider.tsx | 55 ++++++++++--------- 1 file changed, 28 insertions(+), 27 deletions(-) diff --git a/packages/react-core/src/core/providers/thirdweb-wallet-provider.tsx b/packages/react-core/src/core/providers/thirdweb-wallet-provider.tsx index c0a230fde98..2d59ce8c515 100644 --- a/packages/react-core/src/core/providers/thirdweb-wallet-provider.tsx +++ b/packages/react-core/src/core/providers/thirdweb-wallet-provider.tsx @@ -108,11 +108,12 @@ type ThirdwebWalletContextData = { */ isConnectingToPersonalWallet: boolean; /** - * Set value of `connectingToPersonalWallet` flag + * Set value of `isConnectingToPersonalWallet` flag */ setIsConnectingToPersonalWallet: (value: boolean) => void; /** - * wallet connection states of personal wallet + * object containing info about the connected personal wallet + * When `isConnectingToPersonalWallet` is set to true, and a wallet is connected after that, all the info about the connected wallet will be available here instead */ personalWalletInfo: PersonalWalletInfo; }; @@ -175,31 +176,6 @@ export function ThirdwebWalletProvider( WalletConfig | undefined >(); - const storeLastActiveChainId = useCallback(async (chainId: number) => { - const lastConnectedWallet = await lastConnectedWalletStorage.getItem( - LAST_CONNECTED_WALLET_STORAGE_KEY, - ); - - if (!lastConnectedWallet) { - return; - } - - try { - const parsedWallet = JSON.parse(lastConnectedWallet as string); - if (parsedWallet.connectParams) { - parsedWallet.connectParams.chainId = chainId; - } else { - parsedWallet.connectParams = { chainId }; - } - await lastConnectedWalletStorage.setItem( - LAST_CONNECTED_WALLET_STORAGE_KEY, - JSON.stringify(parsedWallet), - ); - } catch (error) { - console.error(`Error saving the last active chain: ${error}`); - } - }, []); - const walletParams: WalletOptions = useMemo(() => { return { chains: props.chains, @@ -327,6 +303,31 @@ export function ThirdwebWalletProvider( ], ); + const storeLastActiveChainId = useCallback(async (chainId: number) => { + const lastConnectedWallet = await lastConnectedWalletStorage.getItem( + LAST_CONNECTED_WALLET_STORAGE_KEY, + ); + + if (!lastConnectedWallet) { + return; + } + + try { + const parsedWallet = JSON.parse(lastConnectedWallet as string); + if (parsedWallet.connectParams) { + parsedWallet.connectParams.chainId = chainId; + } else { + parsedWallet.connectParams = { chainId }; + } + await lastConnectedWalletStorage.setItem( + LAST_CONNECTED_WALLET_STORAGE_KEY, + JSON.stringify(parsedWallet), + ); + } catch (error) { + console.error(`Error saving the last active chain: ${error}`); + } + }, []); + const switchChain = useCallback( async (chainId: number) => { const wallet = isConnectingToPersonalWallet From 5f090fc5986c91c0565ab3d2de59ad0e0472725e Mon Sep 17 00:00:00 2001 From: Manan Tank Date: Fri, 17 Nov 2023 17:40:23 +0530 Subject: [PATCH 09/20] update --- .../src/core/providers/thirdweb-wallet-provider.tsx | 7 +++---- packages/react/src/wallet/wallets/safe/SelectAccount.tsx | 1 - 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/packages/react-core/src/core/providers/thirdweb-wallet-provider.tsx b/packages/react-core/src/core/providers/thirdweb-wallet-provider.tsx index 2d59ce8c515..a788e1e7353 100644 --- a/packages/react-core/src/core/providers/thirdweb-wallet-provider.tsx +++ b/packages/react-core/src/core/providers/thirdweb-wallet-provider.tsx @@ -1,4 +1,3 @@ -/* eslint-disable prefer-const */ import { DAppMetaData } from "../types/dAppMeta"; import type { WalletConfig, @@ -104,7 +103,8 @@ type ThirdwebWalletContextData = { activeChainSetExplicitly: boolean; clientId?: string; /** - * flag indicating whether to treat any connection that happens as a personal wallet connection or not + * flag indicating whether to treat any wallet that gets connected after setting this flag as a "personal" wallet + * If a wallet is treated as a "personal" wallet, It's details like signer, connectionStatus, wallet, walletConfig will be saved in `personalWalletInfo` object instead of the main context */ isConnectingToPersonalWallet: boolean; /** @@ -113,7 +113,7 @@ type ThirdwebWalletContextData = { setIsConnectingToPersonalWallet: (value: boolean) => void; /** * object containing info about the connected personal wallet - * When `isConnectingToPersonalWallet` is set to true, and a wallet is connected after that, all the info about the connected wallet will be available here instead + * When `isConnectingToPersonalWallet` is set to true, and a wallet is connected after that, all the info about the connected wallet will be stored in this object */ personalWalletInfo: PersonalWalletInfo; }; @@ -566,7 +566,6 @@ export function ThirdwebWalletProvider( await _personalWallet.disconnect(); } } - console.log("disconnect the", { wallet, isConnectingToPersonalWallet }); onWalletDisconnect(); }, [ activeWallet, diff --git a/packages/react/src/wallet/wallets/safe/SelectAccount.tsx b/packages/react/src/wallet/wallets/safe/SelectAccount.tsx index 496e80b51fb..f229374d66a 100644 --- a/packages/react/src/wallet/wallets/safe/SelectAccount.tsx +++ b/packages/react/src/wallet/wallets/safe/SelectAccount.tsx @@ -73,7 +73,6 @@ export const SelectAccount: React.FC<{ } setSafeConnectError(false); setSafeConnectionStatus("connecting"); - console.log("not connection to personal wallet"); try { await connectSafe(props.safeWalletConfig, { chain: selectedSafeChain, From 9f5cd6206f8af609684ebdbc7b19da27e936991b Mon Sep 17 00:00:00 2001 From: Manan Tank Date: Fri, 17 Nov 2023 17:56:58 +0530 Subject: [PATCH 10/20] update --- .../providers/thirdweb-wallet-provider.tsx | 68 ++++++++++--------- 1 file changed, 36 insertions(+), 32 deletions(-) diff --git a/packages/react-core/src/core/providers/thirdweb-wallet-provider.tsx b/packages/react-core/src/core/providers/thirdweb-wallet-provider.tsx index a788e1e7353..995fee141da 100644 --- a/packages/react-core/src/core/providers/thirdweb-wallet-provider.tsx +++ b/packages/react-core/src/core/providers/thirdweb-wallet-provider.tsx @@ -576,32 +576,20 @@ export function ThirdwebWalletProvider( // when wallet's network or account is changed using the extension, update UI useEffect(() => { - const wallet = isConnectingToPersonalWallet ? personalWallet : activeWallet; - - if (!wallet) { + if (!activeWallet) { return; } const update = async () => { - const _signer = await wallet.getSigner(); - if (isConnectingToPersonalWallet) { - setPersonalWalletSigner(_signer); - } else { - setSigner(_signer); - } + const _signer = await activeWallet.getSigner(); + setSigner(_signer); }; - wallet.addListener("change", () => { - update(); - }); - - wallet.addListener("disconnect", () => { - onWalletDisconnect(); - }); - + activeWallet.addListener("change", update); + activeWallet.addListener("disconnect", onWalletDisconnect); return () => { - wallet.removeListener("change"); - wallet.removeListener("disconnect"); + activeWallet.removeListener("change", update); + activeWallet.removeListener("disconnect", onWalletDisconnect); }; }, [ activeWallet, @@ -760,30 +748,46 @@ function usePersonalWalletConnection() { const [walletConfig, setWalletConfig] = useState(); const [chainId, setChainId] = useState(undefined); + const handleDisconnect = useCallback(async () => { + setConnectionStatus("disconnected"); + setSigner(undefined); + setWallet(undefined); + setWalletConfig(undefined); + }, []); + + const disconnect = useCallback(async () => { + handleDisconnect(); + if (wallet) { + await wallet.disconnect(); + } + }, [wallet, handleDisconnect]); + useEffect(() => { if (wallet) { - const update = () => { + const update = async () => { wallet?.getChainId().then((_chainId) => { setChainId(_chainId); }); + wallet.getSigner().then((_signer) => { + setSigner(_signer); + }); }; - update(); + wallet?.getChainId().then((_chainId) => { + setChainId(_chainId); + }); + wallet.addListener("change", update); + wallet.addListener("disconnect", handleDisconnect); + + return () => { + wallet.removeListener("change", update); + wallet.removeListener("disconnect", handleDisconnect); + }; } else { setChainId(undefined); } - }, [wallet]); - - const disconnect = useCallback(async () => { - setConnectionStatus("disconnected"); - setSigner(undefined); - setWallet(undefined); - setWalletConfig(undefined); - if (wallet) { - await wallet.disconnect(); - } - }, [wallet]); + }, [disconnect, handleDisconnect, wallet]); const switchChain = useCallback( async (_chainId: number) => { From 53ca0c9d1e6078be12814b21be90164df06ddcd9 Mon Sep 17 00:00:00 2001 From: Manan Tank Date: Fri, 17 Nov 2023 18:00:54 +0530 Subject: [PATCH 11/20] cleanup --- .../core/providers/thirdweb-wallet-provider.tsx | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/packages/react-core/src/core/providers/thirdweb-wallet-provider.tsx b/packages/react-core/src/core/providers/thirdweb-wallet-provider.tsx index 995fee141da..0fb6f8a6994 100644 --- a/packages/react-core/src/core/providers/thirdweb-wallet-provider.tsx +++ b/packages/react-core/src/core/providers/thirdweb-wallet-provider.tsx @@ -756,27 +756,27 @@ function usePersonalWalletConnection() { }, []); const disconnect = useCallback(async () => { - handleDisconnect(); if (wallet) { await wallet.disconnect(); } + handleDisconnect(); }, [wallet, handleDisconnect]); useEffect(() => { if (wallet) { - const update = async () => { + const updateChainId = () => { wallet?.getChainId().then((_chainId) => { setChainId(_chainId); }); - wallet.getSigner().then((_signer) => { - setSigner(_signer); - }); }; - wallet?.getChainId().then((_chainId) => { - setChainId(_chainId); - }); + const update = async () => { + updateChainId(); + const _signer = await wallet.getSigner(); + setSigner(_signer); + }; + updateChainId(); wallet.addListener("change", update); wallet.addListener("disconnect", handleDisconnect); From aeba1835665b044cdd737bb3dfb368d74e02a4d9 Mon Sep 17 00:00:00 2001 From: Manan Tank Date: Fri, 17 Nov 2023 18:08:16 +0530 Subject: [PATCH 12/20] update --- .../ConnectWallet/Modal/ConnectEmbed.tsx | 2 +- .../Modal/ConnectModalInline.tsx | 41 +------------------ 2 files changed, 3 insertions(+), 40 deletions(-) diff --git a/packages/react/src/wallet/ConnectWallet/Modal/ConnectEmbed.tsx b/packages/react/src/wallet/ConnectWallet/Modal/ConnectEmbed.tsx index 9fc2fa3e0ae..07d68673a1a 100644 --- a/packages/react/src/wallet/ConnectWallet/Modal/ConnectEmbed.tsx +++ b/packages/react/src/wallet/ConnectWallet/Modal/ConnectEmbed.tsx @@ -95,7 +95,7 @@ export const ConnectEmbed = ( ); }; -function SyncedWalletUIStates( +export function SyncedWalletUIStates( props: ComponentProps, ) { const setModalConfig = useContext(SetModalConfigCtx); diff --git a/packages/react/src/wallet/ConnectWallet/Modal/ConnectModalInline.tsx b/packages/react/src/wallet/ConnectWallet/Modal/ConnectModalInline.tsx index f86fa8518c1..44e617efda6 100644 --- a/packages/react/src/wallet/ConnectWallet/Modal/ConnectModalInline.tsx +++ b/packages/react/src/wallet/ConnectWallet/Modal/ConnectModalInline.tsx @@ -2,10 +2,7 @@ import { Cross2Icon } from "@radix-ui/react-icons"; import { CrossContainer } from "../../../components/Modal"; import { IconButton } from "../../../components/buttons"; import { iconSize, radius, shadow } from "../../../design-system"; -import { - SetModalConfigCtx, - WalletUIStatesProvider, -} from "../../../evm/providers/wallet-ui-states-provider"; +import { WalletUIStatesProvider } from "../../../evm/providers/wallet-ui-states-provider"; import { wideModalMaxHeight, modalMaxWidthCompact, @@ -20,10 +17,9 @@ import { CustomThemeProvider, useCustomTheme, } from "../../../design-system/CustomThemeProvider"; -import { ComponentProps, useContext, useEffect } from "react"; import { ConnectWalletProps } from "../ConnectWallet"; -import { useTWLocale } from "../../../evm/providers/locale-provider"; import { StyledDiv } from "../../../design-system/elements"; +import { SyncedWalletUIStates } from "./ConnectEmbed"; export const ConnectModalInline = ( props: Omit< @@ -109,39 +105,6 @@ export const ConnectModalInline = ( ); }; -function SyncedWalletUIStates( - props: ComponentProps, -) { - const setModalConfig = useContext(SetModalConfigCtx); - const locale = useTWLocale(); - - // update modalConfig on props change - useEffect(() => { - setModalConfig((c) => ({ - ...c, - title: props.title || locale.connectWallet.defaultModalTitle, - theme: props.theme || "dark", - modalSize: (isMobile() ? "compact" : props.modalSize) || "wide", - termsOfServiceUrl: props.termsOfServiceUrl, - privacyPolicyUrl: props.privacyPolicyUrl, - welcomeScreen: props.welcomeScreen, - titleIconUrl: props.titleIconUrl, - })); - }, [ - props.title, - props.theme, - props.modalSize, - props.termsOfServiceUrl, - props.privacyPolicyUrl, - props.welcomeScreen, - props.titleIconUrl, - setModalConfig, - locale.connectWallet.defaultModalTitle, - ]); - - return ; -} - const ConnectModalInlineContainer = /* @__PURE__ */ StyledDiv(() => { const theme = useCustomTheme(); return { From 1ccf9224d197386a852d0d895eb094a157143504 Mon Sep 17 00:00:00 2001 From: Manan Tank Date: Fri, 17 Nov 2023 18:12:54 +0530 Subject: [PATCH 13/20] update changeset --- .changeset/khaki-queens-check.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.changeset/khaki-queens-check.md b/.changeset/khaki-queens-check.md index b01692228cf..20477daad69 100644 --- a/.changeset/khaki-queens-check.md +++ b/.changeset/khaki-queens-check.md @@ -3,6 +3,6 @@ "@thirdweb-dev/react": patch --- -- Added APIs in react-core to be able to "hide" a connection temporarily to avoid setting a intermediate wallet as "connected wallet" - For example: connecting a Safe requires connecting a personal wallet first and then connecting to Safe. Because of this - the app will show the personal wallet as connected for a brief moment. This API allows to hide the intermediate connection +- Add `ConnectEmbed`` component to embed the ConnectWallet's Modal UI directly in page -- Add ConnectEmbed component to embed the ConnectWallet's Modal UI directly in page +- Fix `ConnectWallet` component setting personal wallet as "connected" wallet when connecting a Safe / Smart Wallet From 6bed01c5036207b4da129f0f21fba55c06e5f72a Mon Sep 17 00:00:00 2001 From: Manan Tank Date: Fri, 17 Nov 2023 18:29:19 +0530 Subject: [PATCH 14/20] update --- packages/react/src/evm/index.ts | 10 ++- .../ConnectWallet/Modal/ConnectEmbed.tsx | 67 ++++++++--------- .../Modal/ConnectModalInline.tsx | 72 +++++++++++++------ 3 files changed, 88 insertions(+), 61 deletions(-) diff --git a/packages/react/src/evm/index.ts b/packages/react/src/evm/index.ts index 282d23688cd..60765da8ccf 100644 --- a/packages/react/src/evm/index.ts +++ b/packages/react/src/evm/index.ts @@ -1,4 +1,7 @@ -export { ConnectEmbed } from "../wallet/ConnectWallet/Modal/ConnectEmbed"; +export { + ConnectEmbed, + type ConnectEmbedProps, +} from "../wallet/ConnectWallet/Modal/ConnectEmbed"; export { useIsWalletModalOpen, @@ -12,7 +15,10 @@ export { ConnectWallet, type ConnectWalletProps, } from "../wallet/ConnectWallet/ConnectWallet"; -export { ConnectModalInline } from "../wallet/ConnectWallet/Modal/ConnectModalInline"; +export { + ConnectModalInline, + type ConnectModalInlineProps, +} from "../wallet/ConnectWallet/Modal/ConnectModalInline"; export { NetworkSelector } from "../wallet/ConnectWallet/NetworkSelector"; export type { NetworkSelectorProps } from "../wallet/ConnectWallet/NetworkSelector"; diff --git a/packages/react/src/wallet/ConnectWallet/Modal/ConnectEmbed.tsx b/packages/react/src/wallet/ConnectWallet/Modal/ConnectEmbed.tsx index 07d68673a1a..542f445ec09 100644 --- a/packages/react/src/wallet/ConnectWallet/Modal/ConnectEmbed.tsx +++ b/packages/react/src/wallet/ConnectWallet/Modal/ConnectEmbed.tsx @@ -2,47 +2,43 @@ import { SetModalConfigCtx, WalletUIStatesProvider, } from "../../../evm/providers/wallet-ui-states-provider"; -import { - wideModalMaxHeight, - modalMaxWidthCompact, - modalMaxWidthWide, - defaultTheme, -} from "../constants"; +import { modalMaxWidthCompact, defaultTheme } from "../constants"; import { ConnectModalContent } from "./ConnectModal"; import { useScreen } from "./screen"; import { isMobile } from "../../../evm/utils/isMobile"; -import { useConnectionStatus, useWallets } from "@thirdweb-dev/react-core"; +import { useConnectionStatus } from "@thirdweb-dev/react-core"; import { DynamicHeight } from "../../../components/DynamicHeight"; import { CustomThemeProvider, useCustomTheme, } from "../../../design-system/CustomThemeProvider"; import { ComponentProps, useContext, useEffect } from "react"; -import { ConnectWalletProps } from "../ConnectWallet"; import { useTWLocale } from "../../../evm/providers/locale-provider"; import { StyledDiv } from "../../../design-system/elements"; -import { radius } from "../../../design-system"; +import { Theme, radius } from "../../../design-system"; + +export type ConnectEmbedProps = { + className?: string; + theme?: "dark" | "light" | Theme; + + style?: React.CSSProperties; + + /** + * If provided, Embed will show a Terms of Service message at the bottom with below link + */ + termsOfServiceUrl?: string; + + /** + * If provided, Embed will show a Privacy Policy message at the bottom with below link + */ + privacyPolicyUrl?: string; +}; -export const ConnectEmbed = ( - props: Omit< - ConnectWalletProps, - | "detailsBtn" - | "dropdownPosition" - | "auth" - | "networkSelector" - | "hideTestnetFaucet" - | "switchToActiveChain" - | "supportedTokens" - | "hideSwitchToPersonalWallet" - >, -) => { +export const ConnectEmbed = (props: ConnectEmbedProps) => { const connectionStatus = useConnectionStatus(); const { screen, setScreen, initialScreen } = useScreen(); - const walletConfigs = useWallets(); - const modalSize = - (isMobile() || walletConfigs.length === 1 ? "compact" : props.modalSize) || - "compact"; + const modalSize = "compact" as const; const content = ( - {modalSize === "compact" ? ( - {content} - ) : ( - content - )} + {content} @@ -132,6 +120,7 @@ const EmbedContainer = /* @__PURE__ */ StyledDiv(() => { const theme = useCustomTheme(); return { color: theme.colors.primaryText, + background: theme.colors.modalBg, width: "100%", boxSizing: "border-box", position: "relative", diff --git a/packages/react/src/wallet/ConnectWallet/Modal/ConnectModalInline.tsx b/packages/react/src/wallet/ConnectWallet/Modal/ConnectModalInline.tsx index 44e617efda6..0452eeb0fcc 100644 --- a/packages/react/src/wallet/ConnectWallet/Modal/ConnectModalInline.tsx +++ b/packages/react/src/wallet/ConnectWallet/Modal/ConnectModalInline.tsx @@ -1,7 +1,7 @@ import { Cross2Icon } from "@radix-ui/react-icons"; import { CrossContainer } from "../../../components/Modal"; import { IconButton } from "../../../components/buttons"; -import { iconSize, radius, shadow } from "../../../design-system"; +import { Theme, iconSize, radius, shadow } from "../../../design-system"; import { WalletUIStatesProvider } from "../../../evm/providers/wallet-ui-states-provider"; import { wideModalMaxHeight, @@ -17,25 +17,59 @@ import { CustomThemeProvider, useCustomTheme, } from "../../../design-system/CustomThemeProvider"; -import { ConnectWalletProps } from "../ConnectWallet"; import { StyledDiv } from "../../../design-system/elements"; import { SyncedWalletUIStates } from "./ConnectEmbed"; +import { WelcomeScreen } from "../screens/types"; -export const ConnectModalInline = ( - props: Omit< - ConnectWalletProps, - | "detailsBtn" - | "dropdownPosition" - | "auth" - | "networkSelector" - | "hideTestnetFaucet" - | "switchToActiveChain" - | "supportedTokens" - | "hideSwitchToPersonalWallet" - > & { - onModalHide?: () => void; - }, -) => { +export type ConnectModalInlineProps = { + className?: string; + theme?: "dark" | "light" | Theme; + + /** + * Set a custom title for the modal + * @defaultValue "Connect" + */ + modalTitle?: string; + + /** + * Replace the thirdweb icon next to modalTitle and set your own iconUrl + * + * Set to empty string to hide the icon + */ + modalTitleIconUrl?: string; + + style?: React.CSSProperties; + + /** + * Set the size of the modal - `compact` or `wide` on desktop + * + * Modal size is always `compact` on mobile + * + * @defaultValue "wide" + */ + modalSize?: "compact" | "wide"; + + /** + * If provided, Modal will show a Terms of Service message at the bottom with below link + */ + termsOfServiceUrl?: string; + + /** + * If provided, Modal will show a Privacy Policy message at the bottom with below link + */ + privacyPolicyUrl?: string; + + /** + * Customize the welcome screen + * + * Either provide a component to replace the default screen entirely + * + * or an object with title, subtitle and imgSrc to change the content of the default screen + */ + welcomeScreen?: WelcomeScreen; +}; + +export const ConnectModalInline = (props: ConnectModalInlineProps) => { const { screen, setScreen, initialScreen } = useScreen(); const walletConfigs = useWallets(); const modalSize = @@ -49,9 +83,7 @@ export const ConnectModalInline = ( screen={screen} setScreen={setScreen} setHideModal={() => { - if (props.onModalHide) { - props.onModalHide(); - } + // no op }} /> From 70c1ddb44d7b17ad6c602c5976bf40a7f06edd34 Mon Sep 17 00:00:00 2001 From: Manan Tank Date: Fri, 17 Nov 2023 18:32:01 +0530 Subject: [PATCH 15/20] update --- .../react/src/wallet/ConnectWallet/Modal/ConnectModalInline.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/react/src/wallet/ConnectWallet/Modal/ConnectModalInline.tsx b/packages/react/src/wallet/ConnectWallet/Modal/ConnectModalInline.tsx index 0452eeb0fcc..ae1bcc977c8 100644 --- a/packages/react/src/wallet/ConnectWallet/Modal/ConnectModalInline.tsx +++ b/packages/react/src/wallet/ConnectWallet/Modal/ConnectModalInline.tsx @@ -123,6 +123,7 @@ export const ConnectModalInline = (props: ConnectModalInlineProps) => { modalSize === "compact" ? modalMaxWidthCompact : modalMaxWidthWide, + ...props.style, }} > {modalSize === "compact" ? ( From 138ba73e0ecf16949f0524e7218ab07714e0cc32 Mon Sep 17 00:00:00 2001 From: Manan Tank Date: Fri, 17 Nov 2023 19:01:01 +0530 Subject: [PATCH 16/20] update --- .../wallet/ConnectWallet/Modal/ConnectModal.tsx | 6 ++++-- .../src/wallet/wallets/safe/SelectAccount.tsx | 16 +++++++--------- .../smartWallet/SmartWalletConnecting.tsx | 6 +++--- 3 files changed, 14 insertions(+), 14 deletions(-) diff --git a/packages/react/src/wallet/ConnectWallet/Modal/ConnectModal.tsx b/packages/react/src/wallet/ConnectWallet/Modal/ConnectModal.tsx index 18d0976b9e2..5d532b17aed 100644 --- a/packages/react/src/wallet/ConnectWallet/Modal/ConnectModal.tsx +++ b/packages/react/src/wallet/ConnectWallet/Modal/ConnectModal.tsx @@ -62,8 +62,9 @@ export const ConnectModalContent = (props: { const authConfig = useThirdwebAuthContext(); const closeModal = () => { - personalWalletInfo?.disconnect(); + personalWalletInfo.disconnect(); setIsConnectingToPersonalWallet(false); + setIsWalletModalOpen(false); onModalUnmount(() => { setScreen(initialScreen); @@ -280,7 +281,8 @@ export const ConnectModal = () => { setIsWalletModalOpen(value); if (!value) { setIsConnectingToPersonalWallet(false); - personalWalletInfo?.disconnect(); + personalWalletInfo.disconnect(); + const requiresSignIn = auth?.loginOptional ? false : !!authConfig?.authUrl && !user?.address; diff --git a/packages/react/src/wallet/wallets/safe/SelectAccount.tsx b/packages/react/src/wallet/wallets/safe/SelectAccount.tsx index f229374d66a..19f92a8f977 100644 --- a/packages/react/src/wallet/wallets/safe/SelectAccount.tsx +++ b/packages/react/src/wallet/wallets/safe/SelectAccount.tsx @@ -12,6 +12,7 @@ import { } from "@radix-ui/react-icons"; import { useConnect, + useConnectionStatus, useSupportedChains, useWalletContext, } from "@thirdweb-dev/react-core"; @@ -48,9 +49,8 @@ export const SelectAccount: React.FC<{ const [safeAddress, setSafeAddress] = useState(""); const [safeChainId, setSafeChainId] = useState(-1); const [safeConnectError, setSafeConnectError] = useState(false); - const [safeConnectionStatus, setSafeConnectionStatus] = useState< - "idle" | "connecting" | "failed" - >("idle"); + const connectionStatus = useConnectionStatus(); + const chains = useSupportedChains(); const supportedChains = chains.filter((c) => @@ -72,7 +72,6 @@ export const SelectAccount: React.FC<{ return; } setSafeConnectError(false); - setSafeConnectionStatus("connecting"); try { await connectSafe(props.safeWalletConfig, { chain: selectedSafeChain, @@ -81,7 +80,6 @@ export const SelectAccount: React.FC<{ }); props.onConnect(); } catch (e) { - setSafeConnectionStatus("failed"); console.error(e); setSafeConnectError(true); } @@ -326,7 +324,7 @@ export const SelectAccount: React.FC<{ }} onClick={async () => { if (!personalWallet) { - throw new Error("No active wallet"); + throw new Error("No personal wallet connected"); } setSafeConnectError(false); setSwitchError(false); @@ -352,7 +350,7 @@ export const SelectAccount: React.FC<{ diff --git a/packages/react/src/wallet/wallets/smartWallet/SmartWalletConnecting.tsx b/packages/react/src/wallet/wallets/smartWallet/SmartWalletConnecting.tsx index 2ef95c59f9b..b3f775fb8f9 100644 --- a/packages/react/src/wallet/wallets/smartWallet/SmartWalletConnecting.tsx +++ b/packages/react/src/wallet/wallets/smartWallet/SmartWalletConnecting.tsx @@ -5,6 +5,7 @@ import { iconSize, spacing, fontSize } from "../../../design-system"; import { ExclamationTriangleIcon } from "@radix-ui/react-icons"; import { useConnect, + useConnectionStatus, useWalletContext, WalletConfig, } from "@thirdweb-dev/react-core"; @@ -36,7 +37,7 @@ export const SmartWalletConnecting: React.FC<{ const targetChain = useWalletContext().activeChain; const mismatch = targetChain.chainId !== personalWalletChainId; const [connectError, setConnectError] = useState(false); - const [isConnectingSafe, setIsConnectingSafe] = useState(false); + const connectionStatus = useConnectionStatus(); const { onConnect } = props; const connectStarted = useRef(false); @@ -48,7 +49,6 @@ export const SmartWalletConnecting: React.FC<{ return; } setConnectError(false); - setIsConnectingSafe(true); try { connectStarted.current = true; @@ -74,7 +74,7 @@ export const SmartWalletConnecting: React.FC<{ } }, [mismatch, handleConnect, personalWallet, personalWalletChainId]); - if (!connectError && (isConnectingSafe || !mismatch)) { + if (!connectError && (connectionStatus === "connecting" || !mismatch)) { return ( Date: Fri, 17 Nov 2023 19:48:14 +0530 Subject: [PATCH 17/20] fix connection status --- .../providers/thirdweb-wallet-provider.tsx | 73 +++++++++++-------- 1 file changed, 41 insertions(+), 32 deletions(-) diff --git a/packages/react-core/src/core/providers/thirdweb-wallet-provider.tsx b/packages/react-core/src/core/providers/thirdweb-wallet-provider.tsx index 0fb6f8a6994..c1d22853c7a 100644 --- a/packages/react-core/src/core/providers/thirdweb-wallet-provider.tsx +++ b/packages/react-core/src/core/providers/thirdweb-wallet-provider.tsx @@ -156,13 +156,12 @@ export function ThirdwebWalletProvider( wallet: personalWallet, setWallet: setPersonalWallet, setSigner: setPersonalWalletSigner, - setConnectionStatus: setPersonalWalletConnectionStatus, + setStatus: setPersonalWalletStatus, setWalletConfig: setPersonalWalletConfig, } = personalWalletConnection; const [signer, setSigner] = useState(undefined); - const [connectionStatus, setConnectionStatus] = - useState("unknown"); + const [status, setStatus] = useState("unknown"); const [activeWallet, setActiveWallet] = useState< WalletInstance | undefined @@ -243,10 +242,10 @@ export function ThirdwebWalletProvider( if (isConnectingToPersonalWallet) { setPersonalWalletConfig(walletConfig); - setPersonalWalletConnectionStatus("connected"); + setPersonalWalletStatus("connected"); } else { setActiveWalletConfig(walletConfig); - setConnectionStatus("connected"); + setStatus("connected"); } const _signer = await wallet.getSigner(); @@ -298,7 +297,7 @@ export function ThirdwebWalletProvider( isConnectingToPersonalWallet, setPersonalWallet, setPersonalWalletConfig, - setPersonalWalletConnectionStatus, + setPersonalWalletStatus, setPersonalWalletSigner, ], ); @@ -371,7 +370,7 @@ export function ThirdwebWalletProvider( // if explicitly set to false, don't auto connect // by default, auto connect if (props.shouldAutoConnect === false) { - setConnectionStatus("disconnected"); + setStatus("disconnected"); return; } @@ -380,7 +379,7 @@ export function ThirdwebWalletProvider( return; } - if (connectionStatus !== "unknown") { + if (status !== "unknown") { // only try to auto connect if we're in the unknown state return; } @@ -391,7 +390,7 @@ export function ThirdwebWalletProvider( const walletInfo = await getLastConnectedWalletInfo(); if (!walletInfo) { - setConnectionStatus("disconnected"); + setStatus("disconnected"); return; } @@ -401,7 +400,7 @@ export function ThirdwebWalletProvider( if (!walletObj) { // last connected wallet is no longer present in the supported wallets - setConnectionStatus("disconnected"); + setStatus("disconnected"); return; } @@ -431,7 +430,7 @@ export function ThirdwebWalletProvider( } catch (e) { console.error("Failed to auto connect personal wallet"); console.error(e); - setConnectionStatus("disconnected"); + setStatus("disconnected"); return; } @@ -442,7 +441,7 @@ export function ThirdwebWalletProvider( }; } else { // last used personal wallet is no longer present in the supported wallets - setConnectionStatus("disconnected"); + setStatus("disconnected"); return; } } @@ -451,7 +450,7 @@ export function ThirdwebWalletProvider( const wallet = createWalletInstance(walletObj); try { - setConnectionStatus("connecting"); + setStatus("connecting"); await timeoutPromise(wallet.autoConnect(walletInfo.connectParams), { ms: autoConnectTimeout, message: autoConnectTimeoutErrorMessage, @@ -468,7 +467,7 @@ export function ThirdwebWalletProvider( LAST_CONNECTED_WALLET_STORAGE_KEY, ); } - setConnectionStatus("disconnected"); + setStatus("disconnected"); } } @@ -479,10 +478,10 @@ export function ThirdwebWalletProvider( setConnectedWallet, props.shouldAutoConnect, activeWallet, - connectionStatus, + status, autoConnectTimeout, props.signerWallet, - setConnectionStatus, + setStatus, ]); const connectWallet = useCallback( @@ -496,9 +495,9 @@ export function ThirdwebWalletProvider( const wallet = createWalletInstance(WalletObj); if (isConnectingToPersonalWallet) { - setPersonalWalletConnectionStatus("connecting"); + setPersonalWalletStatus("connecting"); } else { - setConnectionStatus("connecting"); + setStatus("connecting"); } try { @@ -515,9 +514,9 @@ export function ThirdwebWalletProvider( } catch (e: any) { console.error(`Error connecting to wallet: ${e}`); if (isConnectingToPersonalWallet) { - setPersonalWalletConnectionStatus("disconnected"); + setPersonalWalletStatus("disconnected"); } else { - setConnectionStatus("disconnected"); + setStatus("disconnected"); } throw e; } @@ -528,7 +527,7 @@ export function ThirdwebWalletProvider( chainToConnect?.chainId, createWalletInstance, isConnectingToPersonalWallet, - setPersonalWalletConnectionStatus, + setPersonalWalletStatus, setConnectedWallet, ], ); @@ -538,12 +537,12 @@ export function ThirdwebWalletProvider( LAST_CONNECTED_WALLET_STORAGE_KEY, ); if (isConnectingToPersonalWallet) { - setPersonalWalletConnectionStatus("disconnected"); + setPersonalWalletStatus("disconnected"); setPersonalWalletSigner(undefined); setPersonalWallet(undefined); setPersonalWalletConfig(undefined); } else { - setConnectionStatus("disconnected"); + setStatus("disconnected"); setSigner(undefined); setActiveWallet(undefined); setActiveWalletConfig(undefined); @@ -551,7 +550,7 @@ export function ThirdwebWalletProvider( }, [ isConnectingToPersonalWallet, setPersonalWallet, - setPersonalWalletConnectionStatus, + setPersonalWalletStatus, setPersonalWalletSigner, setPersonalWalletConfig, ]); @@ -627,6 +626,17 @@ export function ThirdwebWalletProvider( disconnectWallet, ]); + const setConnectionStatus = useCallback( + (value: ConnectionStatus) => { + if (isConnectingToPersonalWallet) { + setPersonalWalletStatus(value); + } else { + setStatus(value); + } + }, + [isConnectingToPersonalWallet, setPersonalWalletStatus], + ); + return ( (undefined); - const [connectionStatus, setConnectionStatus] = - useState("unknown"); + const [status, setStatus] = useState("unknown"); const [wallet, setWallet] = useState(); const [walletConfig, setWalletConfig] = useState(); const [chainId, setChainId] = useState(undefined); const handleDisconnect = useCallback(async () => { - setConnectionStatus("disconnected"); + setStatus("disconnected"); setSigner(undefined); setWallet(undefined); setWalletConfig(undefined); @@ -809,8 +818,8 @@ function usePersonalWalletConnection() { setWallet: setWallet, walletConfig: walletConfig, setWalletConfig: setWalletConfig, - connectionStatus: connectionStatus, - setConnectionStatus: setConnectionStatus, + status: status, + setStatus: setStatus, chainId: chainId, disconnect, switchChain, From 83dd80eb581feb10dffd4d0a82baed55f16f1994 Mon Sep 17 00:00:00 2001 From: Manan Tank Date: Mon, 20 Nov 2023 22:47:43 +0530 Subject: [PATCH 18/20] update translations --- packages/react/src/evm/locales/es.ts | 2 +- packages/react/src/evm/locales/ja.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/react/src/evm/locales/es.ts b/packages/react/src/evm/locales/es.ts index 7f6a21b0ea9..0139f31ca72 100644 --- a/packages/react/src/evm/locales/es.ts +++ b/packages/react/src/evm/locales/es.ts @@ -54,7 +54,7 @@ export function esDefault(): ThirdwebLocale { personalWallet: "Cartera personal", smartWallet: "Cartera inteligente", or: "O", - goBackButton: "Back", // TODO + goBackButton: "Atras", download: { chrome: "Descargar extensión para Chrome", android: "Descargar en Google Play", diff --git a/packages/react/src/evm/locales/ja.ts b/packages/react/src/evm/locales/ja.ts index 0a8a81f365f..c83adfc364a 100644 --- a/packages/react/src/evm/locales/ja.ts +++ b/packages/react/src/evm/locales/ja.ts @@ -53,7 +53,7 @@ export function jaDefault(): ThirdwebLocale { personalWallet: "パーソナルウォレット", smartWallet: "スマートウォレット", or: "または", - goBackButton: "Back", // TODO + goBackButton: "戻る", // TODO - check translation download: { chrome: "Chrome拡張をダウンロード", android: "Google Playでダウンロード", From ec68a563732add8b7495bbb63146c1618aeef977 Mon Sep 17 00:00:00 2001 From: Manan Tank Date: Mon, 20 Nov 2023 22:52:47 +0530 Subject: [PATCH 19/20] mark ConnectModalInline as internal --- .../src/wallet/ConnectWallet/Modal/ConnectModalInline.tsx | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/packages/react/src/wallet/ConnectWallet/Modal/ConnectModalInline.tsx b/packages/react/src/wallet/ConnectWallet/Modal/ConnectModalInline.tsx index ae1bcc977c8..336e31b3a9f 100644 --- a/packages/react/src/wallet/ConnectWallet/Modal/ConnectModalInline.tsx +++ b/packages/react/src/wallet/ConnectWallet/Modal/ConnectModalInline.tsx @@ -21,6 +21,9 @@ import { StyledDiv } from "../../../design-system/elements"; import { SyncedWalletUIStates } from "./ConnectEmbed"; import { WelcomeScreen } from "../screens/types"; +/** + * @internal + */ export type ConnectModalInlineProps = { className?: string; theme?: "dark" | "light" | Theme; @@ -69,6 +72,9 @@ export type ConnectModalInlineProps = { welcomeScreen?: WelcomeScreen; }; +/** + * @internal + */ export const ConnectModalInline = (props: ConnectModalInlineProps) => { const { screen, setScreen, initialScreen } = useScreen(); const walletConfigs = useWallets(); From 8b9ca27deb9fe174e83d67b530b803577ea7e4ad Mon Sep 17 00:00:00 2001 From: Manan Tank Date: Mon, 20 Nov 2023 23:16:23 +0530 Subject: [PATCH 20/20] reset states on connect in connect embed --- .../src/wallet/ConnectWallet/Modal/ConnectEmbed.tsx | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/packages/react/src/wallet/ConnectWallet/Modal/ConnectEmbed.tsx b/packages/react/src/wallet/ConnectWallet/Modal/ConnectEmbed.tsx index 542f445ec09..5aa645c2391 100644 --- a/packages/react/src/wallet/ConnectWallet/Modal/ConnectEmbed.tsx +++ b/packages/react/src/wallet/ConnectWallet/Modal/ConnectEmbed.tsx @@ -33,10 +33,17 @@ export type ConnectEmbedProps = { */ privacyPolicyUrl?: string; }; - export const ConnectEmbed = (props: ConnectEmbedProps) => { const connectionStatus = useConnectionStatus(); + if (connectionStatus === "connected") { + return null; + } + + return ; +}; + +const ConnectEmbedContent = (props: ConnectEmbedProps) => { const { screen, setScreen, initialScreen } = useScreen(); const modalSize = "compact" as const; @@ -60,10 +67,6 @@ export const ConnectEmbed = (props: ConnectEmbedProps) => { isEmbed: true, }; - if (connectionStatus === "connected") { - return null; - } - return (