diff --git a/src/components/walletconnect/HeaderWidget/Icon.tsx b/src/components/walletconnect/HeaderWidget/Icon.tsx index d47393067a..c2b8c7915e 100644 --- a/src/components/walletconnect/HeaderWidget/Icon.tsx +++ b/src/components/walletconnect/HeaderWidget/Icon.tsx @@ -1,10 +1,32 @@ -import { ButtonBase, SvgIcon } from '@mui/material' +import { Badge, ButtonBase, SvgIcon } from '@mui/material' import WalletConnectIcon from '@/public/images/common/walletconnect.svg' +import SafeAppIconCard from '@/components/safe-apps/SafeAppIconCard' -const Icon = (props: { onClick: () => void }) => ( +type IconProps = { + onClick: () => void + sessionCount: number + sessionInfo?: { + name: string + iconUrl: string + } +} + +const Icon = ({ sessionCount, sessionInfo, ...props }: IconProps): React.ReactElement => ( - + 1 + ? sessionCount + : sessionInfo && + } + anchorOrigin={{ + vertical: 'bottom', + horizontal: 'right', + }} + > + + ) diff --git a/src/components/walletconnect/HeaderWidget/index.tsx b/src/components/walletconnect/HeaderWidget/index.tsx index 6b2af8c27a..96f26df263 100644 --- a/src/components/walletconnect/HeaderWidget/index.tsx +++ b/src/components/walletconnect/HeaderWidget/index.tsx @@ -2,6 +2,7 @@ import { useCallback, useContext, useRef, useState } from 'react' import { Badge, Box } from '@mui/material' import { WalletConnectContext } from '@/services/walletconnect/WalletConnectContext' +import useWalletConnectSessions from '@/services/walletconnect/useWalletConnectSessions' import Icon from './Icon' import SessionManager from '../SessionManager' import Popup from '../Popup' @@ -10,18 +11,28 @@ const WalletConnectHeaderWidget = () => { const { error } = useContext(WalletConnectContext) const [popupOpen, setPopupOpen] = useState(false) const iconRef = useRef(null) + const sessions = useWalletConnectSessions() + const onOpen = useCallback(() => setPopupOpen(true), []) const onClose = useCallback(() => setPopupOpen(false), []) return (
- +
- +
) diff --git a/src/components/walletconnect/SessionManager/index.tsx b/src/components/walletconnect/SessionManager/index.tsx index 8852ae9833..d0e1881b76 100644 --- a/src/components/walletconnect/SessionManager/index.tsx +++ b/src/components/walletconnect/SessionManager/index.tsx @@ -4,24 +4,22 @@ import type { SessionTypes } from '@walletconnect/types' import useSafeInfo from '@/hooks/useSafeInfo' import { WalletConnectContext } from '@/services/walletconnect/WalletConnectContext' -import useWalletConnectSessions from '@/services/walletconnect/useWalletConnectSessions' import { asError } from '@/services/exceptions/utils' import ProposalForm from '../ProposalForm' import WcInput from '../WcInput' import ErrorMessage from '@/components/tx/ErrorMessage' import SessionList from '../SessionList' -const SessionManager = () => { +const SessionManager = ({ sessions }: { sessions: SessionTypes.Struct[] }) => { const { safe, safeAddress } = useSafeInfo() const { chainId } = safe const { walletConnect, error: walletConnectError } = useContext(WalletConnectContext) - const sessions = useWalletConnectSessions() const [proposal, setProposal] = useState() const [error, setError] = useState() // On session approve const onApprove = useCallback(async () => { - if (!chainId || !safeAddress || !proposal) return + if (!walletConnect || !chainId || !safeAddress || !proposal) return try { await walletConnect.approveSession(proposal, chainId, safeAddress) @@ -35,7 +33,7 @@ const SessionManager = () => { // On session reject const onReject = useCallback(async () => { - if (!proposal) return + if (!walletConnect || !proposal) return try { await walletConnect.rejectSession(proposal) @@ -49,6 +47,7 @@ const SessionManager = () => { // On session disconnect const onDisconnect = async (session: SessionTypes.Struct) => { + if (!walletConnect) return try { await walletConnect.disconnectSession(session) } catch (error) { @@ -58,6 +57,7 @@ const SessionManager = () => { // Subscribe to session proposals useEffect(() => { + if (!walletConnect) return return walletConnect.onSessionPropose(setProposal) }, [walletConnect]) diff --git a/src/components/walletconnect/WcInput/index.tsx b/src/components/walletconnect/WcInput/index.tsx index 2ecdf2c473..19d29d68ba 100644 --- a/src/components/walletconnect/WcInput/index.tsx +++ b/src/components/walletconnect/WcInput/index.tsx @@ -1,6 +1,6 @@ -import { TextField, Typography } from '@mui/material' -import { useContext, useState } from 'react' +import { useCallback, useContext, useState } from 'react' import type { ChangeEvent } from 'react' +import { TextField, Typography } from '@mui/material' import { WalletConnectContext } from '@/services/walletconnect/WalletConnectContext' import { asError } from '@/services/exceptions/utils' @@ -10,18 +10,27 @@ const WcInput = () => { const [error, setError] = useState() const [connecting, setConnecting] = useState(false) - const onInput = async (e: ChangeEvent) => { - const uri = e.target.value - - try { - await walletConnect.connect(uri) - } catch (e) { - setError(asError(e)) - return - } - - setConnecting(true) - } + const onInput = useCallback( + async (e: ChangeEvent) => { + if (!walletConnect) return + + const uri = e.target.value + if (!uri) { + setError(undefined) + return + } + + try { + await walletConnect.connect(uri) + } catch (e) { + setError(asError(e)) + return + } + + setConnecting(true) + }, + [walletConnect], + ) return ( <> diff --git a/src/services/walletconnect/WalletConnectContext.tsx b/src/services/walletconnect/WalletConnectContext.tsx index a89be49c19..481bcb8361 100644 --- a/src/services/walletconnect/WalletConnectContext.tsx +++ b/src/services/walletconnect/WalletConnectContext.tsx @@ -6,13 +6,13 @@ import WalletConnectWallet from './WalletConnectWallet' import { asError } from '../exceptions/utils' import { stripEip155Prefix } from './utils' -const walletConnect = new WalletConnectWallet() +const walletConnectSingleton = new WalletConnectWallet() export const WalletConnectContext = createContext<{ - walletConnect: WalletConnectWallet + walletConnect: WalletConnectWallet | null error: Error | null }>({ - walletConnect, + walletConnect: null, error: null, }) @@ -21,31 +21,35 @@ export const WalletConnectProvider = ({ children }: { children: ReactNode }) => safe: { chainId }, safeAddress, } = useSafeInfo() + const [walletConnect, setWalletConnect] = useState(null) const [error, setError] = useState(null) const safeWalletProvider = useSafeWalletProvider() // Init WalletConnect useEffect(() => { - walletConnect.init().catch(setError) + walletConnectSingleton + .init() + .then(() => setWalletConnect(walletConnectSingleton)) + .catch(setError) }, []) // Update chainId useEffect(() => { - if (chainId) { - walletConnect.chainChanged(chainId).catch(setError) - } - }, [chainId]) + if (!walletConnect || !chainId) return + + walletConnect.chainChanged(chainId).catch(setError) + }, [walletConnect, chainId]) // Update accounts useEffect(() => { - if (safeAddress && chainId) { - walletConnect.accountsChanged(chainId, safeAddress).catch(setError) - } - }, [chainId, safeAddress]) + if (!walletConnect || !chainId || !safeAddress) return + + walletConnect.accountsChanged(chainId, safeAddress).catch(setError) + }, [walletConnect, chainId, safeAddress]) // Subscribe to requests useEffect(() => { - if (!safeWalletProvider || !chainId) return + if (!walletConnect || !safeWalletProvider || !chainId) return return walletConnect.onRequest(async (event) => { const { topic } = event @@ -69,7 +73,7 @@ export const WalletConnectProvider = ({ children }: { children: ReactNode }) => setError(asError(e)) } }) - }, [chainId, safeWalletProvider]) + }, [walletConnect, chainId, safeWalletProvider]) return {children} } diff --git a/src/services/walletconnect/useWalletConnectSessions.ts b/src/services/walletconnect/useWalletConnectSessions.ts index 5958b06467..1b9d1138d7 100644 --- a/src/services/walletconnect/useWalletConnectSessions.ts +++ b/src/services/walletconnect/useWalletConnectSessions.ts @@ -7,6 +7,7 @@ function useWalletConnectSessions(): SessionTypes.Struct[] { const [sessions, setSessions] = useState([]) const updateSessions = useCallback(() => { + if (!walletConnect) return setSessions(walletConnect.getActiveSessions()) }, [walletConnect]) @@ -15,11 +16,13 @@ function useWalletConnectSessions(): SessionTypes.Struct[] { // On session add useEffect(() => { + if (!walletConnect) return return walletConnect.onSessionAdd(updateSessions) }, [walletConnect, updateSessions]) // On session delete useEffect(() => { + if (!walletConnect) return return walletConnect.onSessionDelete(updateSessions) }, [walletConnect, updateSessions])