Skip to content

Commit 1c966a1

Browse files
committed
chore: up
1 parent 2a540d2 commit 1c966a1

File tree

3 files changed

+5
-49
lines changed

3 files changed

+5
-49
lines changed

.changeset/walletconnect-switchchain-listener-leak.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,4 @@
22
"@wagmi/connectors": patch
33
---
44

5-
Fixed a listener leak in the WalletConnect connector's `switchChain` implementation. When a chain switch failed (user rejection, network error, or any other RPC error), the `change` event listener registered on the connector's emitter was not removed, causing it to accumulate across repeated failed attempts.
5+
Fixed listener leak in WalletConnect connector `switchChain` when chain switch fails.

packages/connectors/src/walletConnect.test.ts

Lines changed: 0 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -13,12 +13,6 @@ import {
1313

1414
import { walletConnect } from './walletConnect.js'
1515

16-
vi.mock('@walletconnect/ethereum-provider', () => ({
17-
EthereumProvider: {
18-
init: vi.fn(),
19-
},
20-
}))
21-
2216
const handlers = [
2317
http.get('https://relay.walletconnect.com', async () =>
2418
HttpResponse.json(
@@ -71,36 +65,3 @@ test('setup', () => {
7165
string | undefined
7266
>()
7367
})
74-
75-
test('behavior: removes change listener from emitter after switchChain fails', async () => {
76-
const { EthereumProvider } = await import('@walletconnect/ethereum-provider')
77-
78-
const mockProvider = {
79-
events: { setMaxListeners: vi.fn() },
80-
on: vi.fn(),
81-
off: vi.fn(),
82-
once: vi.fn(),
83-
removeListener: vi.fn(),
84-
request: vi
85-
.fn()
86-
.mockRejectedValue(
87-
Object.assign(new Error('User rejected the request.'), { code: 4001 }),
88-
),
89-
}
90-
vi.mocked(EthereumProvider.init).mockResolvedValue(mockProvider as any)
91-
92-
const connectorFn = walletConnect({ projectId: walletConnectProjectId })
93-
const connector = config._internal.connectors.setup(connectorFn)
94-
95-
// Force provider initialization
96-
await connector.getProvider()
97-
98-
const listenersBefore = connector.emitter.listenerCount('change')
99-
100-
await expect(
101-
connector.switchChain!({ chainId: 1 }),
102-
).rejects.toThrow()
103-
104-
// The listener registered inside switchChain must be cleaned up on failure
105-
expect(connector.emitter.listenerCount('change')).toBe(listenersBefore)
106-
})

packages/connectors/src/walletConnect.ts

Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -338,21 +338,16 @@ export function walletConnect(parameters: WalletConnectParameters) {
338338
const chain = config.chains.find((x) => x.id === chainId)
339339
if (!chain) throw new SwitchChainError(new ChainNotConfiguredError())
340340

341-
let removeChangeListener: (() => void) | undefined
341+
let listener: (opts: { chainId?: number | undefined }) => void = () => {}
342342
try {
343343
await Promise.all([
344344
new Promise<void>((resolve) => {
345-
const listener = ({
346-
chainId: currentChainId,
347-
}: {
348-
chainId?: number | undefined
349-
}) => {
350-
if (currentChainId === chainId) {
345+
listener = (opts) => {
346+
if (opts.chainId === chainId) {
351347
config.emitter.off('change', listener)
352348
resolve()
353349
}
354350
}
355-
removeChangeListener = () => config.emitter.off('change', listener)
356351
config.emitter.on('change', listener)
357352
}),
358353
provider.request({
@@ -366,7 +361,7 @@ export function walletConnect(parameters: WalletConnectParameters) {
366361

367362
return chain
368363
} catch (err) {
369-
removeChangeListener?.()
364+
config.emitter.off('change', listener)
370365
const error = err as RpcError
371366

372367
if (/(user rejected)/i.test(error.message))

0 commit comments

Comments
 (0)