From 5cf474dec9ad80d8424febfc6fd8430de0d24648 Mon Sep 17 00:00:00 2001 From: MK Date: Tue, 30 Jul 2024 18:30:54 +0100 Subject: [PATCH 1/3] chore: walletconnect optimization --- .github/workflows/ci.yml | 2 +- package.json | 2 + packages/rainbowkit/package.json | 4 +- .../components/ConnectModal/ConnectModal.tsx | 8 +- .../ConnectOptions/ConnectDetails.tsx | 10 +- .../ConnectOptions/ConnectOptions.tsx | 3 + .../ConnectOptions/DesktopOptions.tsx | 6 +- .../ConnectOptions/MobileOptions.tsx | 32 +- .../RainbowKitProvider/RainbowKitProvider.tsx | 111 ++-- .../WalletConnectStoreProvider.tsx | 73 +++ .../WalletButton/WalletButtonRenderer.tsx | 2 +- .../walletConnect/walletConnectStore.test.tsx | 139 +++++ .../core/walletConnect/walletConnectStore.ts | 139 +++++ .../src/hooks/useRequestWalletConnectUri.ts | 52 ++ packages/rainbowkit/src/utils/ens.test.ts | 58 +-- packages/rainbowkit/src/utils/strings.ts | 2 + packages/rainbowkit/src/utils/wallets.ts | 38 ++ packages/rainbowkit/src/wallets/Wallet.ts | 10 +- .../src/wallets/connectorsForWallets.ts | 54 +- .../src/wallets/getWalletConnectConnector.ts | 23 +- .../rainbowkit/src/wallets/groupedWallets.ts | 13 - .../src/wallets/useWalletConnectModal.ts | 71 +++ .../src/wallets/useWalletConnectors.ts | 133 +++-- pnpm-lock.yaml | 488 ++++++++++++++++-- vitest.config.ts | 7 + 25 files changed, 1177 insertions(+), 303 deletions(-) create mode 100644 packages/rainbowkit/src/components/RainbowKitProvider/WalletConnectStoreProvider.tsx create mode 100644 packages/rainbowkit/src/core/walletConnect/walletConnectStore.test.tsx create mode 100644 packages/rainbowkit/src/core/walletConnect/walletConnectStore.ts create mode 100644 packages/rainbowkit/src/hooks/useRequestWalletConnectUri.ts create mode 100644 packages/rainbowkit/src/utils/strings.ts create mode 100644 packages/rainbowkit/src/utils/wallets.ts create mode 100644 packages/rainbowkit/src/wallets/useWalletConnectModal.ts diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index ddf6c74b68..3347f6a2c4 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -37,4 +37,4 @@ jobs: - name: Lint and format run: pnpm lint - name: Run tests - run: pnpm test && pnpm test:cli + run: pnpm exec playwright install && pnpm test && pnpm test:cli diff --git a/package.json b/package.json index cc9fb53cd3..791db7aa5f 100644 --- a/package.json +++ b/package.json @@ -55,6 +55,7 @@ "@types/react-dom": "^18.3.0", "@vanilla-extract/esbuild-plugin": "^2.3.5", "@vanilla-extract/vite-plugin": "^4.0.9", + "@vitest/browser": "2.0.4", "autoprefixer": "^10.4.16", "dotenv": "^16.4.5", "esbuild": "^0.20.2", @@ -65,6 +66,7 @@ "lokijs": "^1.5.12", "next": "^14.2.3", "next-auth": "4.24.5", + "playwright": "1.45.3", "postcss": "^8.4.32", "postcss-prefix-selector": "^1.16.0", "react": "^18.3.0", diff --git a/packages/rainbowkit/package.json b/packages/rainbowkit/package.json index ff82838744..43336d62b4 100644 --- a/packages/rainbowkit/package.json +++ b/packages/rainbowkit/package.json @@ -62,7 +62,9 @@ "postcss": "^8.4.32", "react": "^18.3.0", "vitest": "2.0.4", - "dotenv": "^16.4.5" + "dotenv": "^16.4.5", + "@vitest/browser": "2.0.4", + "playwright": "1.45.3" }, "dependencies": { "@vanilla-extract/css": "1.14.0", diff --git a/packages/rainbowkit/src/components/ConnectModal/ConnectModal.tsx b/packages/rainbowkit/src/components/ConnectModal/ConnectModal.tsx index 3a8ed45c69..ec6f1a6781 100644 --- a/packages/rainbowkit/src/components/ConnectModal/ConnectModal.tsx +++ b/packages/rainbowkit/src/components/ConnectModal/ConnectModal.tsx @@ -4,6 +4,7 @@ import { useConnectionStatus } from '../../hooks/useConnectionStatus'; import ConnectOptions from '../ConnectOptions/ConnectOptions'; import { Dialog } from '../Dialog/Dialog'; import { DialogContent } from '../Dialog/DialogContent'; +import { useWalletConnectStore } from '../RainbowKitProvider/WalletConnectStoreProvider'; import { SignIn } from '../SignIn/SignIn'; export interface ConnectModalProps { @@ -15,9 +16,10 @@ export function ConnectModal({ onClose, open }: ConnectModalProps) { const titleId = 'rk_connect_title'; const connectionStatus = useConnectionStatus(); + const { resetWalletConnectUri } = useWalletConnectStore(); + const { disconnect } = useDisconnect(); const { isConnecting } = useAccount(); - // when a user cancels or dismisses the SignIn modal for SIWE, disconnect and call onClose const onAuthCancel = React.useCallback(() => { onClose(); @@ -29,9 +31,9 @@ export function ConnectModal({ onClose, open }: ConnectModalProps) { // the user closes it, we need to know the wallet isn't connecting anymore. // So if it's connecting, we disconnect it. if (isConnecting) disconnect(); - + resetWalletConnectUri(); onClose(); - }, [onClose, disconnect, isConnecting]); + }, [onClose, disconnect, resetWalletConnectUri, isConnecting]); if (connectionStatus === 'disconnected') { return ( diff --git a/packages/rainbowkit/src/components/ConnectOptions/ConnectDetails.tsx b/packages/rainbowkit/src/components/ConnectOptions/ConnectDetails.tsx index fe9b15524e..cf95e930d1 100644 --- a/packages/rainbowkit/src/components/ConnectOptions/ConnectDetails.tsx +++ b/packages/rainbowkit/src/components/ConnectOptions/ConnectDetails.tsx @@ -5,6 +5,7 @@ import { BrowserType, getBrowser, isSafari } from '../../utils/browsers'; import { getGradientRGBAs } from '../../utils/colors'; import { PlatformType, getPlatform } from '../../utils/platforms'; import { InstructionStepName } from '../../wallets/Wallet'; +import { useWalletConnectModal } from '../../wallets/useWalletConnectModal'; import { WalletConnector, useWalletConnectors, @@ -212,12 +213,15 @@ export function ConnectDetail({ name, qrCode, ready, - showWalletConnectModal, getDesktopUri, } = wallet; const isDesktopDeepLinkAvailable = !!getDesktopUri; const safari = isSafari(); + const isWalletConnectWallet = wallet.id === 'walletConnect'; + + const { openWalletConnectModal } = useWalletConnectModal(); + const { i18n } = useContext(I18nContext); const hasExtension = !!wallet.extensionDownloadUrl; @@ -236,7 +240,7 @@ export function ConnectDetail({ label: string; onClick?: () => void; href?: string; - } | null = showWalletConnectModal + } | null = isWalletConnectWallet ? { description: !compactModeEnabled ? i18n.t('connect.walletconnect.description.full') @@ -244,7 +248,7 @@ export function ConnectDetail({ label: i18n.t('connect.walletconnect.open.label'), onClick: () => { onClose(); - showWalletConnectModal(); + openWalletConnectModal(); }, } : hasQrCode diff --git a/packages/rainbowkit/src/components/ConnectOptions/ConnectOptions.tsx b/packages/rainbowkit/src/components/ConnectOptions/ConnectOptions.tsx index ca084c1c6e..83136f3fe4 100644 --- a/packages/rainbowkit/src/components/ConnectOptions/ConnectOptions.tsx +++ b/packages/rainbowkit/src/components/ConnectOptions/ConnectOptions.tsx @@ -1,4 +1,5 @@ import React, { useContext } from 'react'; +import { useRequestWalletConnectUri } from '../../hooks/useRequestWalletConnectUri'; import { isMobile } from '../../utils/isMobile'; import { WalletButtonContext } from '../RainbowKitProvider/WalletButtonContext'; import { DesktopOptions } from './DesktopOptions'; @@ -7,6 +8,8 @@ import { MobileStatus } from './MobileStatus'; export default function ConnectOptions({ onClose }: { onClose: () => void }) { const { connector } = useContext(WalletButtonContext); + // Prefetch WalletConnect URI + useRequestWalletConnectUri(); return isMobile() ? ( connector ? ( diff --git a/packages/rainbowkit/src/components/ConnectOptions/DesktopOptions.tsx b/packages/rainbowkit/src/components/ConnectOptions/DesktopOptions.tsx index c78b5703aa..75d71b0eeb 100644 --- a/packages/rainbowkit/src/components/ConnectOptions/DesktopOptions.tsx +++ b/packages/rainbowkit/src/components/ConnectOptions/DesktopOptions.tsx @@ -30,6 +30,7 @@ import { WalletButtonContext } from '../RainbowKitProvider/WalletButtonContext'; import { Text } from '../Text/Text'; import { addLatestWalletId } from '../../wallets/latestWalletId'; +import { useWalletConnectStore } from '../RainbowKitProvider/WalletConnectStoreProvider'; import { ConnectDetail, DownloadDetail, @@ -75,6 +76,7 @@ export function DesktopOptions({ onClose }: { onClose: () => void }) { const initialized = useRef(false); const { connector } = useContext(WalletButtonContext); + const { onWalletConnectUri } = useWalletConnectStore(); // The `WalletButton` component made the connect modal appear empty when trying to connect. // This happened because of a mix up between EIP-6963 and RainbowKit connectors. @@ -87,6 +89,8 @@ export function DesktopOptions({ onClose }: { onClose: () => void }) { .filter((wallet) => wallet.ready || !!wallet.extensionDownloadUrl) .sort((a, b) => a.groupIndex - b.groupIndex); + useEffect(() => onWalletConnectUri(setQrCodeUri), [onWalletConnectUri]); + const groupedWallets = groupBy(wallets, (wallet) => wallet.groupName); const supportedI18nGroupNames = [ @@ -111,7 +115,7 @@ export function DesktopOptions({ onClose }: { onClose: () => void }) { const connectToWallet = (wallet: WalletConnector) => { setConnectionError(false); if (wallet.ready) { - wallet?.connect?.()?.catch(() => { + wallet?.connectWallet?.()?.catch(() => { setConnectionError(true); }); } diff --git a/packages/rainbowkit/src/components/ConnectOptions/MobileOptions.tsx b/packages/rainbowkit/src/components/ConnectOptions/MobileOptions.tsx index 276b3ba651..347fd82669 100644 --- a/packages/rainbowkit/src/components/ConnectOptions/MobileOptions.tsx +++ b/packages/rainbowkit/src/components/ConnectOptions/MobileOptions.tsx @@ -7,6 +7,7 @@ import React, { } from 'react'; import { touchableStyles } from '../../css/touchableStyles'; import { isIOS } from '../../utils/isMobile'; +import { useWalletConnectModal } from '../../wallets/useWalletConnectModal'; import { WalletConnector, useWalletConnectors, @@ -65,8 +66,12 @@ export function WalletButton({ onClose: () => void; connecting?: boolean; }) { + const isWalletConnectWallet = wallet.id === 'walletConnect'; + + const { openWalletConnectModal } = useWalletConnectModal(); + const { - connect, + connectWallet, iconBackground, iconUrl, id, @@ -74,7 +79,6 @@ export function WalletButton({ getMobileUri, ready, shortName, - showWalletConnectModal, } = wallet; const coolModeRef = useCoolMode(iconUrl); @@ -112,17 +116,21 @@ export function WalletButton({ } }; - if (id !== 'walletConnect') onMobileUri(); - - // If the id is "walletConnect" then "showWalletConnectModal" will always be true - if (showWalletConnectModal) { - showWalletConnectModal(); - onClose?.(); - return; + if (isWalletConnectWallet) { + onClose(); + openWalletConnectModal(); + } else { + onMobileUri(); + connectWallet(); } - - connect?.(); - }, [connect, getMobileUri, showWalletConnectModal, onClose, name, id]); + }, [ + connectWallet, + isWalletConnectWallet, + openWalletConnectModal, + getMobileUri, + onClose, + name, + ]); useEffect(() => { // When using `reactStrictMode: true` in development mode the useEffect hook diff --git a/packages/rainbowkit/src/components/RainbowKitProvider/RainbowKitProvider.tsx b/packages/rainbowkit/src/components/RainbowKitProvider/RainbowKitProvider.tsx index fde6e7d5b6..54b51518d2 100644 --- a/packages/rainbowkit/src/components/RainbowKitProvider/RainbowKitProvider.tsx +++ b/packages/rainbowkit/src/components/RainbowKitProvider/RainbowKitProvider.tsx @@ -20,6 +20,7 @@ import { RainbowKitChainProvider } from './RainbowKitChainContext'; import { ShowBalanceProvider } from './ShowBalanceContext'; import { ShowRecentTransactionsContext } from './ShowRecentTransactionsContext'; import { WalletButtonProvider } from './WalletButtonContext'; +import { WalletConnectStoreProvider } from './WalletConnectStoreProvider'; import { useFingerprint } from './useFingerprint'; import { usePreloadImages } from './usePreloadImages'; import { clearWalletConnectDeepLink } from './walletConnectDeepLink'; @@ -103,60 +104,62 @@ export function RainbowKitProvider({ return ( - - - - - - - - - - - - {theme ? ( -
-