diff --git a/libs/wallet/src/updaters/WidgetStandaloneMode.updater.test.tsx b/libs/wallet/src/updaters/WidgetStandaloneMode.updater.test.tsx index 18f54dc3a8f..c13ce0cd2d7 100644 --- a/libs/wallet/src/updaters/WidgetStandaloneMode.updater.test.tsx +++ b/libs/wallet/src/updaters/WidgetStandaloneMode.updater.test.tsx @@ -1,6 +1,6 @@ -import { useConnection } from 'wagmi' +import { ConnectorAlreadyConnectedError, useConnection } from 'wagmi' -import { isInjectedWidget } from '@cowprotocol/common-utils' +import { isInjectedWidget, logWallet } from '@cowprotocol/common-utils' import { ConnectorController, OptionsController } from '@reown/appkit-controllers' import { render, RenderResult, waitFor } from '@testing-library/react' @@ -15,10 +15,13 @@ import { useDisconnectWallet } from '../wagmi/hooks/useDisconnectWallet' jest.mock('@cowprotocol/common-utils', () => ({ isInjectedWidget: jest.fn(), + logWallet: { error: jest.fn() }, + normalizeError: (err: unknown) => (err instanceof Error ? err : new Error(String(err))), })) jest.mock('wagmi', () => ({ useConnection: jest.fn(), + ConnectorAlreadyConnectedError: class MockConnectorAlreadyConnectedError extends Error {}, })) jest.mock('../utils/connectWalletById', () => ({ @@ -63,6 +66,7 @@ const wagmiAdapterSyncConnectionsMock = wagmiAdapter.syncConnections as jest.Moc const wagmiAdapterSyncConnectorsMock = wagmiAdapter.syncConnectors as jest.Mock const optionsControllerSetEIP6963EnabledMock = OptionsController.setEIP6963Enabled as jest.Mock const connectorControllerSubscribeMock = ConnectorController.subscribe as jest.Mock +const logWalletErrorMock = logWallet.error as jest.Mock const disconnectMock = jest.fn() @@ -150,6 +154,28 @@ describe('WidgetStandaloneModeUpdater', () => { expect(connectWalletByIdMock).toHaveBeenCalledTimes(1) }) + + it('swallows ConnectorAlreadyConnectedError without logging (auto-reconnect or the bridge beat us to it)', async () => { + connectWalletByIdMock.mockRejectedValue(new ConnectorAlreadyConnectedError()) + + renderUpdater(DAPP_MODE) + + await waitFor(() => { + expect(connectWalletByIdMock).toHaveBeenCalledTimes(1) + }) + + expect(logWalletErrorMock).not.toHaveBeenCalled() + }) + + it('logs unexpected connect errors', async () => { + connectWalletByIdMock.mockRejectedValue(new Error('provider unavailable')) + + renderUpdater(DAPP_MODE) + + await waitFor(() => { + expect(logWalletErrorMock).toHaveBeenCalledTimes(1) + }) + }) }) describe('standalone mode: injected wallet discovery', () => { diff --git a/libs/wallet/src/updaters/WidgetStandaloneMode.updater.tsx b/libs/wallet/src/updaters/WidgetStandaloneMode.updater.tsx index ac744267f4d..fb87b83ecc6 100644 --- a/libs/wallet/src/updaters/WidgetStandaloneMode.updater.tsx +++ b/libs/wallet/src/updaters/WidgetStandaloneMode.updater.tsx @@ -1,9 +1,9 @@ import { useSetAtom } from 'jotai' import { useEffect, useRef } from 'react' -import { useConnection } from 'wagmi' +import { ConnectorAlreadyConnectedError, useConnection } from 'wagmi' -import { isInjectedWidget } from '@cowprotocol/common-utils' +import { isInjectedWidget, logWallet, normalizeError } from '@cowprotocol/common-utils' import { ConnectorController, OptionsController } from '@reown/appkit-controllers' @@ -71,7 +71,18 @@ export function WidgetStandaloneModeUpdater({ standaloneMode }: WidgetStandalone console.debug('[WidgetStandaloneModeUpdater] connect widget connector') await reownAppKit.disconnect() - connectWalletById(COW_WIDGET_CONNECTOR_ID, 'injected') + + try { + await connectWalletById(COW_WIDGET_CONNECTOR_ID, 'injected') + } catch (err: unknown) { + const error = normalizeError(err) + + // Auto-reconnect or the bridged provider's own connect event can beat us to it - + // wagmi is already connected to this connector, nothing left to do. + if (error instanceof ConnectorAlreadyConnectedError) return + + logWallet.error(new Error('Failed to connect widget connector', { cause: error })) + } })() } }, [isDappMode, isSafeApp])