Skip to content

fix: clear restored walletconnect connections on disconnect - #2688

Open
o-mid wants to merge 5 commits into
rainbow-me:mainfrom
o-mid:fix/walletconnect-disconnect-after-refresh
Open

fix: clear restored walletconnect connections on disconnect#2688
o-mid wants to merge 5 commits into
rainbow-me:mainfrom
o-mid:fix/walletconnect-disconnect-after-refresh

Conversation

@o-mid

@o-mid o-mid commented Aug 4, 2026

Copy link
Copy Markdown

Summary

  • After WalletConnect connect + refresh, wagmi can keep multiple restored walletConnect connections.
  • A single Disconnect only drops the current one, so the UI stays connected until the user clicks again.
  • Disconnect now clears every active connection in one click (useDisconnectAll).

Fixes #2401

Problem

RainbowKit registers multiple WalletConnect connectors that share id: "walletConnect". After refresh, reconnect can restore more than one. Wagmi's default disconnect() only removes the current connection and switches to the next, so the account UI remains connected.

Reproduction

  1. Connect with WalletConnect (QR / mobile wallet)
  2. Refresh
  3. Wait for restore
  4. Click Disconnect once
  5. UI stays connected until another click (or refresh)

Root cause

Multi-wrapper WalletConnect connectors + wagmi disconnect-current semantics after reconnect.

Fix

Add useDisconnectAll and use it from Account / Chain / Connect disconnect paths.

Tests

  • Regression: bare disconnect() leaves restored WC connections connected
  • Regression: useDisconnectAll() clears all in one click
  • pnpm test:unit run packages/rainbowkit/src/hooks/useDisconnectAll.test.tsx
  • pnpm --filter @rainbow-me/rainbowkit typecheck

Compatibility

  • No public API changes
  • Disconnect still means "log out" for RainbowKit's single-account UI
  • Does not attempt to address issue 2232 (duplicate connector/provider sync) unless proven separately

Test plan

  • Connect via WalletConnect, disconnect without refresh → disconnects once
  • Connect via WalletConnect, refresh, disconnect once → UI + wagmi disconnected
  • Refresh after disconnect → does not restore the removed session
  • Injected wallet connect/disconnect still works
  • Unit tests above pass in CI

@o-mid
o-mid requested a review from a team as a code owner August 4, 2026 14:15
@vercel

vercel Bot commented Aug 4, 2026

Copy link
Copy Markdown

@o-mid is attempting to deploy a commit to the rainbowdotme Team on Vercel.

A member of the Team first needs to authorize it.

@changeset-bot

changeset-bot Bot commented Aug 4, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 1b81bb6

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 18 packages
Name Type
@rainbow-me/rainbowkit Patch
example Patch
@rainbow-me/rainbow-button Patch
rainbowkit-next-app Patch
site Patch
with-create-react-app Patch
with-next-app-i18n Patch
with-next-app Patch
with-next-custom-button Patch
with-next-mint-nft Patch
with-next-siwe-iron-session Patch
with-next-siwe-next-auth Patch
with-next-wallet-button Patch
with-next Patch
with-react-router Patch
with-remix Patch
with-vite Patch
with-next-rainbow-button Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 1236816c4e

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

// the user closes it, we need to know the wallet isn't connecting anymore.
// So if it's connecting, we disconnect it.
if (isConnecting) disconnect();
if (isConnecting) void disconnectAll();

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Keep cancelling pending wallet connections

When the WalletButton QR flow is still pending and the user closes the connect modal, wagmi has isConnecting set but has not added anything to config.state.connections yet; useDisconnectAll therefore snapshots an empty list and this call becomes a no-op. The previous no-argument disconnect() still forced wagmi's status back to disconnected, which is exactly what the comment above this line says the close handler needs, so this can leave the custom WalletButton stuck in its loading/disabled connecting state until the pending connect promise settles. Preserve the old no-connection fallback when cancelling an in-flight connect.

Useful? React with 👍 / 👎.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 3ce83e754e

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment on lines +20 to +21
for (const { connector } of connections) {
await disconnectAsync({ connector });

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Keep disconnecting after a failed connector

When there are multiple restored connections and any connector's disconnectAsync rejects (for example a provider teardown error before wagmi deletes that connection), this loop exits before trying the remaining connectors; the current call sites all invoke void disconnectAll(), so the rejection is also unhandled and the user can remain connected through another restored connection after clicking Disconnect. Isolate/catch per-connector failures so one stale connection cannot prevent clearing the rest.

Useful? React with 👍 / 👎.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 44be001ae0

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment on lines +23 to +24
} catch {
// One stale provider teardown must not block clearing the rest.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Clear the connector that fails to disconnect

When one connector in the snapshot rejects from disconnectAsync({ connector }) (for example a restored WalletConnect provider hits a teardown error), wagmi leaves that connection in config.state.connections because the connection is removed only after the connector disconnect succeeds. This catch now swallows the rejection and continues, so after the remaining connectors are cleared the failed connection can become/stay current and the user is still connected after pressing Disconnect; the new regression test only checks that the remaining connectors were called, not that the failing connection was removed.

Useful? React with 👍 / 👎.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 1b81bb68e8

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

await disconnectAsync({ connector });
} catch {
// wagmi only drops the connection after connector.disconnect succeeds.
removeConnection(config, connector);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Restore listeners when forcing failed disconnects

When a connector's disconnectAsync({ connector }) rejects, this fallback only removes its entry from wagmi state. Wagmi's normal disconnect path also removes the connector's change/disconnect emitter listeners and re-adds the connect listener; skipping that cleanup leaves a connector that RainbowKit now treats as disconnected still wired as connected, so wallet-initiated reconnects are ignored and a later manual reconnect can attach duplicate handlers. The fresh evidence is this forced-removal path bypasses that listener cleanup entirely; mirror wagmi's disconnect cleanup before deleting the connection.

Useful? React with 👍 / 👎.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

1 participant