From 61ae42d1a144608fbe380edf6d947e30000e449c Mon Sep 17 00:00:00 2001 From: Matt Rintoul Date: Fri, 26 Jun 2026 09:48:42 -0400 Subject: [PATCH] fix(connect): bound walletconnect chain switch on connect --- .changeset/walletconnect-connect-timeout.md | 9 +++ .../connect/src/config/defaultConnectors.ts | 6 ++ .../connectors/walletConnect/walletConnect.ts | 59 +++++++++++-------- 3 files changed, 51 insertions(+), 23 deletions(-) create mode 100644 .changeset/walletconnect-connect-timeout.md diff --git a/.changeset/walletconnect-connect-timeout.md b/.changeset/walletconnect-connect-timeout.md new file mode 100644 index 000000000..6ea7eafbf --- /dev/null +++ b/.changeset/walletconnect-connect-timeout.md @@ -0,0 +1,9 @@ +--- +'@0xsequence/connect': patch +--- + +Fix WalletConnect connections that can hang when the connector tries to switch to the configured default chain during connect. + +WalletConnect now establishes the session on the wallet's current chain before attempting a best-effort switch to the requested or default chain. Requested chain IDs are applied after the base WalletConnect session opens, and the automatic switch is bounded by a short timeout so wallets that do not settle `switchChain` can still finish connecting. + +Default connector configuration also accepts `walletConnect.customStoragePrefix`, allowing apps that run another WalletConnect core to opt into an isolated WalletConnect storage namespace without changing the default storage behavior for existing sessions. diff --git a/packages/connect/src/config/defaultConnectors.ts b/packages/connect/src/config/defaultConnectors.ts index 0a52b8fdb..d118502d4 100644 --- a/packages/connect/src/config/defaultConnectors.ts +++ b/packages/connect/src/config/defaultConnectors.ts @@ -64,6 +64,7 @@ export interface DefaultV3ConnectorOptions extends CommonConnectorOptions { | false | { projectId: string + customStoragePrefix?: string } additionalWallets?: Wallet[] /** @@ -135,6 +136,7 @@ export interface DefaultWaasConnectorOptions extends CommonConnectorOptions { | false | { projectId: string + customStoragePrefix?: string } additionalWallets?: Wallet[] @@ -278,10 +280,12 @@ export const getDefaultWaasConnectors = (options: DefaultWaasConnectorOptions): if (options.walletConnect || options.walletConnectProjectId) { const projectId = (options.walletConnect && options.walletConnect?.projectId) || options.walletConnectProjectId! + const customStoragePrefix = options.walletConnect && options.walletConnect.customStoragePrefix wallets.push( walletConnect({ projectId, + ...(customStoragePrefix && { customStoragePrefix }), defaultNetwork: defaultChainId }) ) @@ -424,10 +428,12 @@ export const getDefaultV3Connectors = (options: DefaultV3ConnectorOptions): Crea if (options.walletConnect || options.walletConnectProjectId) { const projectId = (options.walletConnect && options.walletConnect?.projectId) || options.walletConnectProjectId! + const customStoragePrefix = options.walletConnect && options.walletConnect.customStoragePrefix wallets.push( walletConnect({ projectId, + ...(customStoragePrefix && { customStoragePrefix }), defaultNetwork: defaultChainId }) ) diff --git a/packages/connect/src/connectors/walletConnect/walletConnect.ts b/packages/connect/src/connectors/walletConnect/walletConnect.ts index f0b3dc316..8e44f835e 100644 --- a/packages/connect/src/connectors/walletConnect/walletConnect.ts +++ b/packages/connect/src/connectors/walletConnect/walletConnect.ts @@ -9,6 +9,27 @@ interface WalletConnectOptions extends WalletConnectParameters { defaultNetwork?: number } +const SWITCH_CHAIN_ON_CONNECT_TIMEOUT_MS = 1500 + +const withTimeout = (promise: Promise, timeoutMs: number): Promise => { + return new Promise((resolve, reject) => { + const timeout = setTimeout(() => { + reject(new Error('WalletConnect switchChain timed out')) + }, timeoutMs) + + promise.then( + value => { + clearTimeout(timeout) + resolve(value) + }, + error => { + clearTimeout(timeout) + reject(error) + } + ) + }) +} + export const walletConnect = (options: WalletConnectOptions): Wallet => ({ id: 'wallet-connect', logoDark: WalletConnectLogo, @@ -27,36 +48,28 @@ export const walletConnect = (options: WalletConnectOptions): Wallet => ({ isReconnecting?: boolean withCapabilities?: withCapabilities | boolean }) => { - const targetChainId = params?.chainId ?? defaultNetwork ?? config.chains[0]?.id - if (!targetChainId) { - throw new Error('No target chain ID available') - } - - if (!connector.connect || !connector.switchChain) { + if (!connector.connect) { throw new Error('WalletConnect connector not properly initialized') } - // First establish the basic connection - const result = await connector.connect({ ...params, chainId: targetChainId }) + const { chainId, ...connectParams } = params ?? {} + const result = await connector.connect(connectParams) + const targetChainId = chainId ?? defaultNetwork - // Only attempt to switch chains if we're not already on the target chain - if (result.chainId !== targetChainId) { - try { - // Switch to the target chain - await connector.switchChain({ chainId: targetChainId }) + if (!targetChainId || result.chainId === targetChainId || !connector.switchChain) { + return result + } - // Return the connection with the updated chain - return { - accounts: result.accounts, - chainId: targetChainId - } - } catch (error) { - console.warn('Failed to switch chain:', error) - return result + try { + await withTimeout(connector.switchChain({ chainId: targetChainId }), SWITCH_CHAIN_ON_CONNECT_TIMEOUT_MS) + + return { + accounts: result.accounts, + chainId: targetChainId } + } catch { + return result } - - return result } return { ...connector,