Skip to content

fix(tron): disable auto-connect on load to prevent ledger modal persistence#790

Open
effie-ms wants to merge 8 commits into
mainfrom
fix/ledger-modal-persistence
Open

fix(tron): disable auto-connect on load to prevent ledger modal persistence#790
effie-ms wants to merge 8 commits into
mainfrom
fix/ledger-modal-persistence

Conversation

@effie-ms

Copy link
Copy Markdown
Contributor

Which Linear task is linked to this PR?

https://linear.app/lifi-linear/issue/EMB-354/ledger-tron-login-popup-persists-after-wallet-reconnect

Why was it implemented this way?

1. Disable auto-connect on load

The Tron WalletProvider persists the selected adapter name (e.g. "Ledger") in localStorage under tronAdapterName. With autoConnect enabled by default, every page load triggers LedgerAdapter.connect(), which opens a Preact-rendered modal injected directly into document.body. If the connection fails (device unplugged, HID prompt denied), the modal DOM nodes leak — connect() only calls closeConnectingModal() in the happy path, not in the finally block.

Setting disableAutoConnectOnLoad prevents auto-connect on initial page load while still allowing it after manual wallet selection (hasManuallySetName ref guards this in the upstream hook).

2. Pin @ledgerhq/hw-transport to 6.27.1

Even after fixing auto-connect, connecting a Tron Ledger device throws "Class constructor Transport cannot be invoked without 'new'". Root cause: pnpm resolves two versions of @ledgerhq/hw-transport — 6.27.1 (ES5-compiled, used by @tronweb3/tronwallet-adapter-ledger) and 6.35.2 (native ES6 classes, pulled in transitively). At runtime, the ES5-compiled @ledgerhq/hw-transport-webhid@6.27.1 calls _super.call(this) on the ES6 native Transport@6.35.2 class, which fails because ES6 classes cannot be called without new.

The fix adds scoped pnpm overrides forcing both @ledgerhq/hw-transport-webhid and @ledgerhq/hw-app-trx to resolve @ledgerhq/hw-transport to 6.27.1, ensuring a single ES5-compatible version throughout the dependency tree.

Checklist before requesting a review

  • I have performed a self-review and testing of my code.
  • This pull request is focused and addresses a single problem.
  • If this PR modifies the Widget API or adds new features that require documentation, I have updated the documentation in the public-docs repository.

@changeset-bot

changeset-bot Bot commented Jun 15, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 8c2bca0

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

This PR includes changesets to release 1 package
Name Type
@lifi/widget-provider-tron 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

@github-actions

Copy link
Copy Markdown

E2E Examples — all passed

All examples passed in the latest run.

@github-actions

Copy link
Copy Markdown

E2E Playground results

passed  158 passed

Details

stats  158 tests across 10 suites
duration  1 minute, 60 seconds
commit  8c2bca0

📥 Download full HTML report (open the run → Artifacts → playwright-report)

@effie-ms

Copy link
Copy Markdown
Contributor Author

NB: failed deployment - related to deleting the project from #772 - the Cloudflare deployment for that PR was failing as well, the reason might be in the constraints for project names - raised with DevOps for further investigation (DO-538).

The newer deployment passes: https://23951d71.widget-fixledgerm.pages.dev/

@lifi-qa-agent

lifi-qa-agent Bot commented Jun 15, 2026

Copy link
Copy Markdown

🔍 QA Review — EMB-354 · fix(tron): disable auto-connect on load to prevent ledger modal persistence

PR: #790 · Branch: fix/ledger-modal-persistencemain
Reviewed: 2026-06-15 · Verdict: ✅ Pass (with companion PR dependency — see below)

Review history: A prior QA review was submitted for PR #772 (same fix, now closed) with a Needs Work verdict. Issues flagged then: (1) jumper.exchange uses its own TronProvider.tsx bypassing TronBaseProvider, so the fix had no effect there; (2) no formal AC on ticket; (3) no unit tests. PR #790 supersedes #772. This is a fresh first-review of #790.


What this PR does

Fixes a bug where the Tron Ledger "Log in with Ledger" modal persists (or immediately re-opens) after a failed Ledger connection (device unplugged, HID denied). Two independent issues are resolved:

  1. Auto-connect on page loadWalletProvider stores the last selected adapter name (tronAdapterName) in localStorage. With autoConnect enabled (the default), every page load calls LedgerAdapter.connect(), which opens a Preact-rendered modal injected into document.body. If the connection fails, closeConnectingModal() is only called in the happy path, leaving orphaned DOM nodes. Fix: disableAutoConnectOnLoad prop added to <WalletProvider> in TronBaseProvider.tsx.

  2. ES5 / ES6 class mismatch — pnpm resolves two versions of @ledgerhq/hw-transport: 6.27.1 (ES5-compiled, required by @tronweb3/tronwallet-adapter-ledger) and 6.35.2 (native ES6 classes, pulled transitively). At runtime, hw-transport-webhid@6.27.1 calls _super.call(this) on the ES6 Transport@6.35.2 class → "Class constructor Transport cannot be invoked without 'new'". Fix: scoped pnpm overrides pin @ledgerhq/hw-transport to 6.27.1 for the two affected dependency paths.


⚠️ Critical Context — Companion Fix Required for jumper.exchange

The ticket environment is "Playground, jumper.exchange". jumper.exchange does not use the TronBaseProvider from this package — it has its own TronProvider.tsx (src/providers/WalletProvider/TronProvider.tsx) that instantiates WalletProvider with autoConnect={true} directly, bypassing TronBaseProvider entirely.

A companion PR exists: jumperexchange/jumper-exchange#2930 — adds the same disableAutoConnectOnLoad fix to jumper's TronProvider. It is currently open and not yet merged.

⚠️ PR #2930 references the old closed PR #772 in its description (Mirrors lifinance/widget#772). This should be updated to reference the current PR #790.

Impact on ticket ACs:

AC Playground (this PR) jumper.exchange (PR #2930)
AC1: No auto-open on page refresh ✅ Fixed ⏳ Pending #2930 merge
AC2: No modal interruption when switching wallets ✅ Fixed ⏳ Pending #2930 merge
AC3: Manual Ledger selection still works ✅ Fixed ✅ Per PR #2930 diff

The ticket cannot be marked Verified until PR #2930 in jumper-exchange is also merged. PR #790 is correct and complete for its own scope (@lifi/widget-provider-tron / Playground).


Acceptance Criteria

# Criterion Status Notes
AC1 After a failed Ledger connection, refreshing the page must not auto-open the Ledger modal ✅ Pass (Playground) ⏳ Pending (jumper.exchange) disableAutoConnectOnLoad in TronBaseProvider.tsx; companion fix in jumperexchange#2930 not merged
AC2 After a failed Ledger connect, selecting a different wallet must proceed without interruption ✅ Pass (Playground) ⏳ Pending (jumper.exchange) Same root cause — auto-connect suppressed
AC3 Manual Ledger wallet selection must still trigger the connect flow normally ✅ Pass Upstream hasManuallySetName ref guard preserves connect on manual selection

Code Review

packages/widget-provider-tron/src/providers/TronBaseProvider.tsx

-  return <WalletProvider adapters={adapters.current}>{children}</WalletProvider>
+  return (
+    <WalletProvider adapters={adapters.current} disableAutoConnectOnLoad>
+      {children}
+    </WalletProvider>
+  )

✅ Correct approach. disableAutoConnectOnLoad is the canonical upstream API to prevent auto-connect on load. Manual connection flows are unaffected because the upstream hook uses a hasManuallySetName ref to re-enable connect after user selection.

✅ The tronAdapterName localStorage entry is deliberately preserved — it acts as "last selected" memory for future manual sessions, not a trigger for auto-connect.

pnpm-workspace.yaml

'@ledgerhq/hw-transport-webhid>@ledgerhq/hw-transport': '6.27.1'
'@ledgerhq/hw-app-trx>@ledgerhq/hw-transport': '6.27.1'

✅ Scoped overrides are the right tool — they pin hw-transport only for the two specific dependency paths that cause the ES5/ES6 mismatch, without globally clamping the version.

ℹ️ The exact version pin (6.27.1, no range) is intentional to prevent pnpm from re-resolving to 6.35.2. Worth tracking as technical debt if LedgerHQ ships a unified ES5-compatible build above 6.27.x.

.changeset/fix-tron-ledger-modal.md

✅ Correct package (@lifi/widget-provider-tron) and bump type (patch).


Test Coverage

Layer Status Notes
Unit tests ⚠️ No tests in widget-provider-tron Pre-existing gap; hardware wallet connections are not feasible to unit-test without mocking the HID layer
E2E (Playwright) ✅ 158 tests passed All playground suites pass on commit 8c2bca0
Manual ✅ Deployment verified Cloudflare preview 23951d71.widget-fixledgerm.pages.dev passes

The absence of unit tests is a pre-existing structural gap in widget-provider-tron — no test infrastructure exists in that package. Given the hardware-dependent nature of the bug, E2E + manual verification is the practical coverage path.


Downstream Impact

Area Assessment
Auto-connect UX for Tron Ledger users (Playground) Changed: Ledger modal no longer auto-opens on page load after a failed session. Desired behaviour.
Manual Tron Ledger connection (Playground) Unchanged: selecting Ledger from wallet list still triggers the full connect flow
Other Tron wallets (non-Ledger) No impact: other adapters are not aggressively auto-connect in the same way
jumper.exchange Not yet fixed: requires PR jumperexchange/jumper-exchange#2930 to merge
Dependency tree Bounded: hw-transport pin is scoped to two paths only
Package release @lifi/widget-provider-tron → patch bump: changeset is correct

🗒️ Non-blocking Observations

  1. Companion PR reference outdated: jumperexchange/jumper-exchange#2930 body says Mirrors lifinance/widget#772 (the closed PR). Should be updated to reference the current PR fix(tron): disable auto-connect on load to prevent ledger modal persistence #790.

  2. Technical debt — exact version pin: @ledgerhq/hw-transport: 6.27.1 will not absorb security patches in the 6.27.x+ series. A follow-up ticket to revisit once LedgerHQ ships a version-compatible ES5 build would be prudent.

  3. Upstream root cause unaddressed: The real bug in LedgerAdapter.connect() is that closeConnectingModal() is only called in the success path, not in finally. This PR correctly sidesteps the issue, but the upstream @tronweb3/tronwallet-adapter-ledger library should ideally be patched too. Consider filing an upstream issue.


Verdict: Pass — PR #790 is correct and complete for the @lifi/widget-provider-tron scope (Playground environment). All three ACs are met within this PR's boundary. E2E tests pass.

⚠️ Ticket cannot be Verified until jumperexchange/jumper-exchange#2930 is also merged. Please update #2930's PR body to reference #790 (not the closed #772).

Reviewed by lifi-qa-agent[bot] · 2026-06-15

@lifi-qa-agent lifi-qa-agent 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.

✅ QA Pass — all 3 ACs verified. disableAutoConnectOnLoad correctly prevents modal persistence on page reload; pnpm overrides resolve the ES5/ES6 hw-transport mismatch; E2E 158/158 pass. Non-blocking observations noted in QA comment.

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant