Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions .changeset/walletconnect-connect-timeout.md
Original file line number Diff line number Diff line change
@@ -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.
6 changes: 6 additions & 0 deletions packages/connect/src/config/defaultConnectors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ export interface DefaultV3ConnectorOptions extends CommonConnectorOptions {
| false
| {
projectId: string
customStoragePrefix?: string
}
additionalWallets?: Wallet[]
/**
Expand Down Expand Up @@ -135,6 +136,7 @@ export interface DefaultWaasConnectorOptions extends CommonConnectorOptions {
| false
| {
projectId: string
customStoragePrefix?: string
}
additionalWallets?: Wallet[]

Expand Down Expand Up @@ -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
})
)
Expand Down Expand Up @@ -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
})
)
Expand Down
59 changes: 36 additions & 23 deletions packages/connect/src/connectors/walletConnect/walletConnect.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,27 @@ interface WalletConnectOptions extends WalletConnectParameters {
defaultNetwork?: number
}

const SWITCH_CHAIN_ON_CONNECT_TIMEOUT_MS = 1500

const withTimeout = <T>(promise: Promise<T>, timeoutMs: number): Promise<T> => {
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,
Expand All @@ -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,
Expand Down
Loading