Repository navigation
fix(bridge-core): signing out over WalletConnect no longer offers a dead session to resume - #102
Conversation
…ead session to resume disconnect() fired resetWalletConnectProvider() without awaiting it, and the reset only dropped the WC registry entry after the session delete crossed the relay. In that window the silent eth_accounts read reached the dying provider, got the signed-out address back and set canResume; WC emits no disconnect for a self-initiated delete, so it never cleared. Resume then sent personal_sign to the deleted session: no wallet popup, stuck until the 120s sign timeout. A reload was the only way back, because the WC entry was only registered at mount. - resetWalletConnectProvider drops the singleton and the registry entry synchronously, before awaiting the delete; a module-level teardown promise makes the next getWalletConnectProvider() wait for it, so a new provider can't rehydrate the session being deleted. A failed init only clears the singleton if it is still the current one. - disconnect() refreshes the picker as the reset starts, then re-registers a fresh WC entry once the teardown settles, so WC sign-in works without a reload. - No new latch: same-address logout->login and A->B need no extra state (tested). Tests: WalletProvider.wc-logout-relogin.test.tsx (5, red before the fix) runs the real WalletProvider against the e2e WC provider with the relay delete held open; getWalletConnectProvider.test.ts pins the drop-before-await ordering. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
PR SummaryMedium Risk Overview
New Reviewed by Cursor Bugbot for commit a663adc. Bugbot is set up for automated code reviews on this repo. Configure here. |
This stack of pull requests is managed by Graphite. Learn more about stacking. |

Bug (reported from offmarket on a phone): sign out over WalletConnect, then sign straight back in without a reload. The app offers "Resume session", the identity
personal_signgoes to the deleted WC session, no wallet popup appears, and the UI is stuck until the 120s sign timeout. Desktop extensions are unaffected because their provider stays alive. Only a WC connection actually dies on sign-out.Root cause
disconnect()firedresetWalletConnectProvider()without awaiting it. The reset only dropped the WC registry entry after the session delete crossed the relay.eth_accountsread, which reached the dying provider and got the signed-out address back, socanResumebecame true.disconnectfor a self-initiated delete, soonDisconnectnever cleared it.personal_signinto the deleted session. A reload was the only way back, because the WC entry was only registered at mount.Fix
resetWalletConnectProviderdrops the singleton and the registry entry synchronously, before awaiting the delete.getWalletConnectProvider()wait for it, so a new provider can't rehydrate the session being deleted. A failed init only clears the singleton if it is still the current one.disconnect()refreshes the picker as the reset starts. Once the teardown settles it re-registers a fresh WC entry, so WC sign-in works without a reload. The refresh logic is now one sharedrefreshProviderscallback.apps/bridgecallssetActiveNetworkbeforedisconnect(), so the fresh provider is built from the new network's RPC map.Tests
WalletProvider.wc-logout-relogin.test.tsx(5 tests) runs the realWalletProvider, registry and WC singleton against the e2e WC provider with the relay delete held open. All 5 were red before the fix:canResumeduring teardown;personal_signsent to the dead session;getWalletConnectProvider.test.tspins the drop-before-await ordering (red before).npx vitest run src/react/wallet: 10 files, 60 tests pass. Packagetsc --noEmitand eslint on the wallet dir pass.Not verified / residual risk
canResumecould return. That is narrower than today's bug; a disconnect-scoped latch could close it if wanted.main); it merges cleanly.Release: offmarket needs
0.1.24(the usualchore(release): bump bridge-corePR) to pick this up.🤖 Generated with Claude Code
This change is