From 2e54593bba6788f9b19a6c309e164e7f40af2305 Mon Sep 17 00:00:00 2001 From: Charlie McKenzie Date: Mon, 29 Apr 2024 22:50:39 +1000 Subject: [PATCH] Added the ability to auto connect to a provider based on wallet rdns --- packages/checkout/sdk/src/types/provider.ts | 2 + .../widgets/definitions/parameters/connect.ts | 4 +- .../widgets-lib/src/lib/walletConnect.ts | 2 +- .../src/widgets/connect/ConnectWidget.tsx | 2 + .../src/widgets/connect/ConnectWidgetRoot.tsx | 1 + .../connect/components/WalletConnectItem.tsx | 34 ++++++----- .../widgets/connect/components/WalletList.tsx | 26 +++++++-- .../widgets/connect/views/ConnectWallet.tsx | 9 ++- .../src/components/ui/connect/connect.tsx | 58 +++++++++++++++---- 9 files changed, 107 insertions(+), 31 deletions(-) diff --git a/packages/checkout/sdk/src/types/provider.ts b/packages/checkout/sdk/src/types/provider.ts index d1a5004465..e8175a0836 100644 --- a/packages/checkout/sdk/src/types/provider.ts +++ b/packages/checkout/sdk/src/types/provider.ts @@ -6,6 +6,7 @@ import { Web3Provider } from '@ethersproject/providers'; export enum WalletProviderName { PASSPORT = 'passport', METAMASK = 'metamask', + WALLETCONNECT = 'walletconnect', } /** @@ -14,6 +15,7 @@ export enum WalletProviderName { export enum WalletProviderRdns { PASSPORT = 'com.immutable.passport', METAMASK = 'io.metamask', + WALLETCONNECT = 'walletconnect', } /** diff --git a/packages/checkout/sdk/src/widgets/definitions/parameters/connect.ts b/packages/checkout/sdk/src/widgets/definitions/parameters/connect.ts index 8caa01f79f..22794cb1fb 100644 --- a/packages/checkout/sdk/src/widgets/definitions/parameters/connect.ts +++ b/packages/checkout/sdk/src/widgets/definitions/parameters/connect.ts @@ -1,4 +1,4 @@ -import { ChainId } from '../../../types'; +import { ChainId, WalletProviderRdns } from '../../../types'; import { WidgetLanguage } from '../configurations'; export enum ConnectTargetLayer { @@ -11,6 +11,8 @@ export type ConnectWidgetParams = { language?: WidgetLanguage; /** The target chain to connect to as part of the connection process (defaults to Immutable zkEVM / Immutable zkEVM Testnet) */ targetChainId?: ChainId; + /** The target wallet to establish a connection with */ + targetWalletRdns?: string | WalletProviderRdns; /** List of wallets rdns to exclude from the connect widget */ blocklistWalletRdns?: string[]; }; diff --git a/packages/checkout/widgets-lib/src/lib/walletConnect.ts b/packages/checkout/widgets-lib/src/lib/walletConnect.ts index a57f0faf0a..5c65f947fb 100644 --- a/packages/checkout/widgets-lib/src/lib/walletConnect.ts +++ b/packages/checkout/widgets-lib/src/lib/walletConnect.ts @@ -8,7 +8,7 @@ export const walletConnectProviderInfo = { rdns: 'walletconnect', // eslint-disable-next-line max-len icon: 'data:image/svg+xml;base64,PHN2ZyB2aWV3Qm94PSIwIDAgNDggNDgiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+PGc+PHBhdGggZD0iTTEwLjQyMzYgMTQuODY4NkMxNy45NTA3IDcuNTIzNzcgMzAuMTY5NCA3LjUyMzc3IDM3LjY5NjQgMTQuODY4NkwzOC42MDI2IDE1Ljc1OTNDMzguOTgyNiAxNi4xMjQ0IDM4Ljk4MjYgMTYuNzIzMSAzOC42MDI2IDE3LjA4ODFMMzUuNTA0MSAyMC4xMTA4QzM1LjMxNDEgMjAuMzAwNiAzNS4wMDcxIDIwLjMwMDYgMzQuODE3MSAyMC4xMTA4TDMzLjU3NDggMTguODk4OEMyOC4zMTMyIDEzLjc3MzUgMTkuODA2OSAxMy43NzM1IDE0LjU0NTIgMTguODk4OEwxMy4yMTUyIDIwLjE5ODRDMTMuMDI1MiAyMC4zODgyIDEyLjcxODMgMjAuMzg4MiAxMi41MjgzIDIwLjE5ODRMOS40Mjk3OCAxNy4xNzU3QzkuMDQ5NzcgMTYuODEwNyA5LjA0OTc3IDE2LjIxMiA5LjQyOTc4IDE1Ljg0N0wxMC40MjM2IDE0Ljg2ODZaTTQ0LjExMjcgMjEuMTE4M0w0Ni44NzUgMjMuODA1MUM0Ny4yNTUgMjQuMTcwMSA0Ny4yNTUgMjQuNzY4OCA0Ni44NzUgMjUuMTMzOUwzNC40MzcxIDM3LjI2ODJDMzQuMDU3MSAzNy42MzMyIDMzLjQ0MzMgMzcuNjMzMiAzMy4wNzc5IDM3LjI2ODJMMjQuMjUgMjguNjUzQzI0LjE2MjMgMjguNTY1NCAyNC4wMDE2IDI4LjU2NTQgMjMuOTEzOSAyOC42NTNMMTUuMDg2IDM3LjI2ODJDMTQuNzA2IDM3LjYzMzIgMTQuMDkyMiAzNy42MzMyIDEzLjcyNjggMzcuMjY4MkwxLjI0NTAzIDI1LjEzMzlDMC44NjUwMiAyNC43Njg4IDAuODY1MDIgMjQuMTcwMSAxLjI0NTAzIDIzLjgwNTFMNC4wMDczOCAyMS4xMTgzQzQuMzg3MzkgMjAuNzUzMyA1LjAwMTI1IDIwLjc1MzMgNS4zNjY2NCAyMS4xMTgzTDE0LjE5NDUgMjkuNzMzNUMxNC4yODIyIDI5LjgyMTEgMTQuNDQyOSAyOS44MjExIDE0LjUzMDYgMjkuNzMzNUwyMy4zNTg1IDIxLjExODNDMjMuNzM4NSAyMC43NTMzIDI0LjM1MjMgMjAuNzUzMyAyNC43MTc3IDIxLjExODNMMzMuNTQ1NiAyOS43MzM1QzMzLjYzMzMgMjkuODIxMSAzMy43OTQgMjkuODIxMSAzMy44ODE3IDI5LjczMzVMNDIuNzA5NiAyMS4xMTgzQzQzLjExODggMjAuNzUzMyA0My43MzI3IDIwLjc1MzMgNDQuMTEyNyAyMS4xMTgzWiIgZmlsbD0iIzM2OEFGQSI+PC9wYXRoPjwvZz48L3N2Zz4=', - uuid: 'wallet-connect', + uuid: 'walletconnect', } as EIP6963ProviderInfo; export type WalletConnectConfiguration = { diff --git a/packages/checkout/widgets-lib/src/widgets/connect/ConnectWidget.tsx b/packages/checkout/widgets-lib/src/widgets/connect/ConnectWidget.tsx index 3a62c2b8d0..62b89cfe09 100644 --- a/packages/checkout/widgets-lib/src/widgets/connect/ConnectWidget.tsx +++ b/packages/checkout/widgets-lib/src/widgets/connect/ConnectWidget.tsx @@ -65,6 +65,7 @@ export default function ConnectWidget({ sendCloseEventOverride, web3Provider, checkout, + targetWalletRdns, targetChainId, allowedChains, blocklistWalletRdns, @@ -206,6 +207,7 @@ export default function ConnectWidget({ )} {view.type === ConnectWidgetViews.CONNECT_WALLET && ( { diff --git a/packages/checkout/widgets-lib/src/widgets/connect/components/WalletConnectItem.tsx b/packages/checkout/widgets-lib/src/widgets/connect/components/WalletConnectItem.tsx index 434e2b6a9d..5f53e13cc6 100644 --- a/packages/checkout/widgets-lib/src/widgets/connect/components/WalletConnectItem.tsx +++ b/packages/checkout/widgets-lib/src/widgets/connect/components/WalletConnectItem.tsx @@ -1,6 +1,6 @@ import { useTranslation } from 'react-i18next'; import { MenuItem } from '@biom3/react'; -import { useState } from 'react'; +import { forwardRef, useImperativeHandle, useState } from 'react'; import { useWalletConnect } from '../../../lib/hooks/useWalletConnect'; export type WalletConnectItemProps = { @@ -8,30 +8,36 @@ export type WalletConnectItemProps = { loading?: boolean; }; -export function WalletConnectItem({ +export const WalletConnectItem = forwardRef(({ onConnect, loading = false, -}: WalletConnectItemProps) { +}: WalletConnectItemProps, ref) => { const { t } = useTranslation(); const { walletConnectBusy } = useWalletConnect(); const [busy, setBusy] = useState(false); + const connect = async () => { + if (loading) return; + setBusy(true); + // let the parent handle errors + try { + await onConnect(); + } finally { + setBusy(false); + } + }; + + useImperativeHandle(ref, () => ({ + connect, + })); + return ( { - if (loading) return; - setBusy(true); - // let the parent handle errors - try { - await onConnect(); - } finally { - setBusy(false); - } - }} + onClick={connect} sx={{ marginBottom: 'base.spacing.x1' }} > ); -} +}); diff --git a/packages/checkout/widgets-lib/src/widgets/connect/components/WalletList.tsx b/packages/checkout/widgets-lib/src/widgets/connect/components/WalletList.tsx index e4b7f0fbc7..60d46700d1 100644 --- a/packages/checkout/widgets-lib/src/widgets/connect/components/WalletList.tsx +++ b/packages/checkout/widgets-lib/src/widgets/connect/components/WalletList.tsx @@ -5,7 +5,7 @@ import { WalletProviderName, WalletProviderRdns, } from '@imtbl/checkout-sdk'; import { - useCallback, useContext, useMemo, useState, + useCallback, useContext, useEffect, useMemo, useRef, useState, } from 'react'; import { motion } from 'framer-motion'; import { useTranslation } from 'react-i18next'; @@ -39,6 +39,7 @@ import { BrowserWalletItem } from './BrowserWalletItem'; import { identifyUser } from '../../../lib/analytics/identifyUser'; export interface WalletListProps { + targetWalletRdns?: string; targetChainId: ChainId; allowedChains: ChainId[]; blocklistWalletRdns?: string[]; @@ -46,7 +47,7 @@ export interface WalletListProps { export function WalletList(props: WalletListProps) { const { t } = useTranslation(); - const { targetChainId, allowedChains } = props; + const { targetWalletRdns, targetChainId, allowedChains } = props; const blocklistWalletRdns = props?.blocklistWalletRdns || []; const { connectDispatch, @@ -57,7 +58,7 @@ export function WalletList(props: WalletListProps) { const { providers } = useInjectedProviders({ checkout }); const [showWalletDrawer, setShowWalletDrawer] = useState(false); const { isWalletConnectEnabled, openWalletConnectModal } = useWalletConnect(); - + const walletConnectItemRef = useRef(null); const [showChangedYourMindDrawer, setShowChangedYourMindDrawer] = useState(false); const [showUnableToConnectDrawer, setShowUnableToConnectDrawer] = useState(false); const [chosenProviderDetail, setChosenProviderDetail] = useState(); @@ -261,6 +262,23 @@ export function WalletList(props: WalletListProps) { setShowWalletDrawer(true); }, [track]); + useEffect(() => { + // Auto-trigger wallet connection via rdns + if (targetWalletRdns && targetWalletRdns?.length > 0) { + if (targetWalletRdns === WalletProviderRdns.PASSPORT && passportProviderDetail) { + handleWalletItemClick(passportProviderDetail); + } if (targetWalletRdns === WalletProviderRdns.WALLETCONNECT && walletConnectItemRef.current) { + (walletConnectItemRef.current as any).connect(); + } else { + const targetProviderDetail = filteredProviders + .find((providerDetail) => providerDetail.info.rdns === targetWalletRdns); + if (targetProviderDetail) { + handleWalletItemClick(targetProviderDetail); + } + } + } + }, [filteredProviders, targetWalletRdns]); + return ( - + )} diff --git a/packages/checkout/widgets-lib/src/widgets/connect/views/ConnectWallet.tsx b/packages/checkout/widgets-lib/src/widgets/connect/views/ConnectWallet.tsx index 504a81fda7..6824856beb 100644 --- a/packages/checkout/widgets-lib/src/widgets/connect/views/ConnectWallet.tsx +++ b/packages/checkout/widgets-lib/src/widgets/connect/views/ConnectWallet.tsx @@ -10,12 +10,18 @@ import { ConnectContext } from '../context/ConnectContext'; import { UserJourney, useAnalytics } from '../../../context/analytics-provider/SegmentAnalyticsProvider'; export interface ConnectWalletProps { + targetWalletRdns?: string, targetChainId: ChainId; allowedChains: ChainId[]; blocklistWalletRdns?: string[]; } -export function ConnectWallet({ targetChainId, allowedChains, blocklistWalletRdns }: ConnectWalletProps) { +export function ConnectWallet({ + targetWalletRdns, + targetChainId, + allowedChains, + blocklistWalletRdns, +}: ConnectWalletProps) { const { t } = useTranslation(); const { connectState: { sendCloseEvent }, @@ -69,6 +75,7 @@ export function ConnectWallet({ targetChainId, allowedChains, blocklistWalletRdn { (async () => { - setFactory(new WidgetsFactory(checkout, {theme: WidgetTheme.DARK})); + setFactory(new WidgetsFactory(checkout, { + theme: WidgetTheme.DARK, + walletConnect: { + projectId: '938b553484e344b1e0b4bb80edf8c362', + metadata: { + name: 'Checkout Marketplace', + description: 'Checkout Marketplace', + url: 'http://localhost:3000/marketplace-orchestrator', + icons: [] + } + } + })); })() }, [checkout]); @@ -34,7 +40,35 @@ function ConnectUI() { connect.addListener(ConnectEventType.CLOSE_WIDGET, (data: any) => { connect.unmount(); }) - }, [connect]) + }, [connect]); + + const connectWC = useCallback(async () => { + if(!connect && !provider) return; + connect!.mount(CONNECT_TARGET_ID, { + targetWalletRdns: WalletProviderRdns.WALLETCONNECT, + }); + }, [connect, provider, checkout]); + + const connectMetaMask = useCallback(async () => { + if(!connect && !provider) return; + connect!.mount(CONNECT_TARGET_ID, { + targetWalletRdns: WalletProviderRdns.METAMASK, + }); + }, [connect, provider, checkout]); + + const connectPassport = useCallback(async () => { + if(!connect && !provider) return; + connect!.mount(CONNECT_TARGET_ID, { + targetWalletRdns: WalletProviderRdns.PASSPORT, + }); + }, [connect, provider, checkout]); + + const connectCoinbase = useCallback(async () => { + if(!connect && !provider) return; + connect!.mount(CONNECT_TARGET_ID, { + targetWalletRdns: 'com.coinbase.wallet' + }); + }, [connect, provider, checkout]); return (
@@ -46,6 +80,10 @@ function ConnectUI() { + + + +
); }