Skip to content

fix: stop wiping stored connections when a connector registers late - #5746

Merged
0xmkh merged 15 commits into
mainfrom
fix/tron-late-connector-sync
Aug 27, 2026
Merged

fix: stop wiping stored connections when a connector registers late#5746
0xmkh merged 15 commits into
mainfrom
fix/tron-late-connector-sync

Conversation

@santgr11

Copy link
Copy Markdown
Contributor

Description

useAppKitAccount could stay permanently disconnected after a reload if the namespace's adapter registers its connectors asynchronously after boot (e.g. an injected wallet extension whose readyState resolves later, such as
TronLink). Solana, Bitcoin, and Wagmi adapters share the same async-registration shape, so this affects them too, not just TRON.

Root cause: syncAdapterConnection couldn't tell "connector hasn't registered with the adapter yet" apart from "the user disconnected," so it wiped the stored connection (onDisconnectNamespace) the moment boot-time
sync ran ahead of the connector showing up. Nothing ever retried once it did.

Fix, entirely in packages/appkit/src/client/appkit-base-client.ts (no adapter package touched, so every adapter with this shape benefits, not just TRON):

  • syncAdapterConnection no longer disconnects when a connector hasn't registered yet. It leaves storage intact and schedules a bounded (10s) cleanup in case the connector genuinely never shows up (e.g. the wallet extension was uninstalled).
  • setConnectors now retries the namespace sync when a connector matching the stored connector id registers late, while explicitly respecting enableReconnect: false and not racing the normal boot-time sync (a real
    gap the whole-branch review caught: every adapter mock in the test suite no-ops syncConnectors, so this exact race had no prior test coverage).

Type of change

  • Chore (non-breaking change that addresses non-functional tasks, maintenance, or code quality improvements)
  • [ x] Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change that adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to not work as expected)

Associated Issues

Closes REOWN-4797

Checklist

  • Code in this PR is covered by automated tests (Unit tests, E2E tests)
  • My changes generate no new warnings
  • I have reviewed my own code
  • I have filled out all required sections
  • I have tested my changes on the preview link
  • Approver of this PR confirms that the changes are tested on the preview link

… sibling tests

The setConnectors retry tests mock ConnectorController.getConnectorId and
ChainController.getAccountData at the singleton level. A stray, un-awaited
background init promise from an unrelated earlier test can read those mocks
mid-test (before afterEach restores them), find a matching connector the
retry test just registered for real, and drive a full connect flow that
permanently mutates shared controller/provider state, breaking
'should set connected wallet info' several tests later.

Flush pending background work before each retry test sets up its mocks,
restore the mocks in afterEach, and drain each test's own readyPromise
so nothing is left dangling for a later test to pick up.
… sync

`setConnectors` also emits synchronously during the adapter's initial
`syncConnectors()` call, which runs before `syncExistingConnection()`. The
retry therefore fired on ordinary boots too, bypassing `enableReconnect: false`
and starting a duplicate concurrent `syncNamespaceConnection` alongside the one
the normal boot path already runs.

`syncNamespaceConnection` sets status to 'connecting' synchronously before its
first await, so requiring status === 'disconnected' (rather than merely
!== 'connected') means a retry can only fire after `syncAdapterConnection`'s
own guard already ran and found no connector. Also check `enableReconnect`
explicitly.

Additionally, if a connector never registers (e.g. the extension was
uninstalled), the guard used to leave the stale stored connector id forever,
permanently breaking `ConnectorController.isConnected()` and silently no-oping
`AppKitCore.open()`. A 10s cleanup timer now clears the stale connection, and
a successful retry cancels it.
Adds two `setConnectors retry` tests (initial 'connecting' status at boot,
`enableReconnect: false`) and two `syncAdapterConnection` tests for the
cleanup timer firing and being cancellable.

The retry block's afterEach keeps targeted `mockRestore` calls rather than
`vi.restoreAllMocks()`: the latter also resets the module-level `vi.fn()`
mocks in tests/mocks/Adapter.ts to no-op implementations, and the outer
beforeEach only calls `vi.clearAllMocks()`, so five later tests in the file
stayed broken. It also resets `OptionsController.enableReconnect`, which the
AppKit constructor writes into shared state.
@linear

linear Bot commented Aug 12, 2026

Copy link
Copy Markdown

REOWN-4797

@cursor

cursor Bot commented Aug 12, 2026

Copy link
Copy Markdown

Bugbot is not enabled for your account, so this pull request was not reviewed.

Enable Bugbot in the Cursor dashboard to get automatic reviews on future PRs.

@changeset-bot

changeset-bot Bot commented Aug 12, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 60aec0e

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

This PR includes changesets to release 27 packages
Name Type
@reown/appkit-adapter-tron Patch
@reown/appkit Patch
pay-test-exchange Patch
@reown/appkit-adapter-bitcoin Patch
@reown/appkit-adapter-ethers Patch
@reown/appkit-adapter-ethers5 Patch
@reown/appkit-adapter-solana Patch
@reown/appkit-adapter-ton Patch
@reown/appkit-adapter-wagmi Patch
@reown/appkit-utils Patch
@reown/appkit-cdn Patch
@reown/appkit-cli Patch
@reown/appkit-codemod Patch
@reown/appkit-common Patch
@reown/appkit-controllers Patch
@reown/appkit-core Patch
@reown/appkit-experimental Patch
@reown/appkit-pay Patch
@reown/appkit-polyfills Patch
@reown/appkit-scaffold-ui Patch
@reown/appkit-siwe Patch
@reown/appkit-siwx Patch
@reown/appkit-testing Patch
@reown/appkit-ui Patch
@reown/appkit-universal-connector Patch
@reown/appkit-wallet Patch
@reown/appkit-wallet-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

@vercel

vercel Bot commented Aug 12, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
appkit-demo Ready Ready Preview Aug 26, 2026 6:45pm
appkit-gallery Ready Ready Preview Aug 26, 2026 6:45pm
appkit-headless-sample-app Ready Ready Preview Aug 26, 2026 6:45pm
appkit-laboratory Ready Ready Preview Aug 26, 2026 6:45pm
9 Skipped Deployments
Project Deployment Actions Updated (UTC)
appkit-basic-example Ignored Ignored Aug 26, 2026 6:45pm
appkit-basic-sign-client-example Ignored Ignored Aug 26, 2026 6:45pm
appkit-basic-up-example Ignored Ignored Aug 26, 2026 6:45pm
appkit-ethers5-bera Ignored Ignored Aug 26, 2026 6:45pm
appkit-nansen-demo Ignored Ignored Aug 26, 2026 6:45pm
appkit-wagmi-cdn-example Ignored Ignored Aug 26, 2026 6:45pm
ethereum-provider-wagmi-example Ignored Ignored Aug 26, 2026 6:45pm
next-wagmi-solana-bitcoin-example Ignored Ignored Aug 26, 2026 6:45pm
vue-wagmi-example Ignored Ignored Aug 26, 2026 6:45pm

Request Review

@github-actions

github-actions Bot commented Aug 12, 2026

Copy link
Copy Markdown
Contributor

Visual Regression Test Results ✅ Passed

⚠️ 20 visual change(s) detected

Chromatic Build: undefined
Storybook Preview: undefined

👉 Please review the visual changes in Chromatic and accept or reject them.

@github-actions

github-actions Bot commented Aug 12, 2026

Copy link
Copy Markdown
Contributor

📦 Bundle Size Check

All bundles are within size limits

📊 View detailed bundle sizes

> @reown/appkit-monorepo@1.7.1 size /home/runner/work/appkit/appkit


> size-limit

@reown/appkit - Main Entry
Size limit:   80 kB
Size:         76.04 kB with all dependencies, minified and gzipped
Loading time: 1.5 s    on slow 3G
Running time: 1.1 s    on Snapdragon 410
Total time:   2.6 s
@reown/appkit/react
Size limit:   236 kB
Size:         235.39 kB with all dependencies, minified and gzipped
Loading time: 4.6 s     on slow 3G
Running time: 2.4 s     on Snapdragon 410
Total time:   7 s
@reown/appkit/vue
Size limit:   80 kB
Size:         76.04 kB with all dependencies, minified and gzipped
Loading time: 1.5 s    on slow 3G
Running time: 798 ms   on Snapdragon 410
Total time:   2.3 s
@reown/appkit-scaffold-ui
Size limit:   220 kB
Size:         214.66 kB with all dependencies, minified and gzipped
Loading time: 4.2 s     on slow 3G
Running time: 1.6 s     on Snapdragon 410
Total time:   5.8 s
@reown/appkit-ui
Size limit:   500 kB
Size:         13.16 kB with all dependencies, minified and gzipped
Loading time: 258 ms   on slow 3G
Running time: 147 ms   on Snapdragon 410
Total time:   404 ms

@github-actions

github-actions Bot commented Aug 12, 2026

Copy link
Copy Markdown
Contributor

Coverage Report

Status Category Percentage Covered / Total
🔵 Lines 77.92% 40345 / 51774
🔵 Statements 77.92% 40345 / 51774
🔵 Functions 75.58% 4301 / 5690
🔵 Branches 86.71% 9869 / 11381
File Coverage
File Stmts Branches Functions Lines Uncovered Lines
Changed Files
packages/adapters/tron/src/adapter.ts 12.42% 50% 8.33% 12.42% 65, 72-136, 139-140, 143-146, 149-163, 166-167, 170-171, 174-209, 212-231, 234-290, 293-313, 316-348, 351-352, 355-356, 359-405, 408-421, 424-427, 430-433, 436-439, 442-445, 448-451, 454-457, 460-468
packages/adapters/tron/src/utils/TronConnectUtil.ts 41.46% 92.3% 50% 41.46% 15-53, 113, 117-143
Generated in workflow #17270 for commit 60aec0e by the Vitest Coverage Report Action

Comment thread packages/appkit/src/client/appkit-base-client.ts Outdated
Per PR review, revert the generic pending-cleanup/retry mechanism in
appkit-base-client.ts and instead have TronAdapter.syncConnectors await
pending wallet adapters (e.g. TronLink resolving readyState async)
before boot connection sync runs, avoiding the race at its source
instead of papering over it generically for every adapter/namespace.
Comment thread packages/adapters/tron/src/utils/TronConnectUtil.ts Outdated
Some wallet adapters may not reliably emit readyStateChanged, so waitForLoadingAdapters now polls adapter.readyState every 200ms via HelpersUtil.withRetry (same pattern as SatsConnectConnector), resolving as soon as the state settles instead of only on the event or the full 3s timeout.
…ion to restore

waitForLoadingAdapters previously blocked boot sync on every loading wallet
adapter regardless of whether it had anything to restore, adding a multi-second
delay to every page load (e.g. TronLink's default readyState check) even when
the active session was established via WalletConnect or the adapter isn't
installed. Now it only waits for an adapter with an actual stored,
non-disconnected TRON connection.
@0xmkh
0xmkh merged commit d8263cb into main Aug 27, 2026
96 of 102 checks passed
@0xmkh
0xmkh deleted the fix/tron-late-connector-sync branch August 27, 2026 08:58
@github-actions github-actions Bot locked and limited conversation to collaborators Aug 27, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants