Connect modal does not distinguish installed vs not-installed wallets, all options appear identical before clicking #139

Closed
opened 2026-05-06 16:03:31 +00:00 by totdking · 15 comments
totdking commented 2026-05-06 16:03:31 +00:00 (Migrated from gitlab.com)
No description provided.
totdking (Migrated from gitlab.com) closed this issue 2026-05-06 16:07:31 +00:00
totdking commented 2026-05-06 16:07:32 +00:00 (Migrated from gitlab.com)

Issue Summary

The connect wallet modal lists all wallet options (Station, Keplr, WalletConnect, Leap, etc.) identically regardless of whether the extension is installed in the browser. No "installed" badge, label, or visual treatment differentiates available wallets from unavailable ones before the user clicks. Clicking an uninstalled wallet does return an error (e.g. "Failed to connect Leap: Leap extension is not installed"), so the failure is not silent, but the user has no way to know which wallets are ready without clicking each one.


Reproduction Steps

  1. Open the app at http://127.0.0.1:3000 in a browser profile that does not have all wallet extensions installed
  2. Click the Connect Wallet button in the header
  3. Observe the wallet list in the modal — all options appear visually identical
  4. Click an uninstalled wallet (e.g. Leap) — observe the error toast/message
  5. Note that no pre-click visual distinction indicated the wallet was unavailable

Expected Behavior

Wallet options that are not installed should be visually distinct before the user clicks — for example, grayed out, with a label like "Not installed", or with an "Install" CTA. This lets users immediately identify which wallets are ready to use without a trial-and-error click cycle.


Actual Behavior

All wallet options look identical regardless of install state. Clicking an uninstalled wallet (e.g. Leap) returns "Failed to connect Leap: Leap extension is not installed" — error handling is present, but the modal gives no pre-click signal about which wallets are available.


Environment Details

Field Value
OS macOS (Apple M1 Pro, 14-inch)
Browser Google Chrome (desktop)
Viewport 1470×864
Network localterra (local Docker)
Frontend VITE_NETWORK=local npm run dev

Wallet / Device Details

  • Wallet state: Disconnected (testing connect modal)

Screenshot

  • list of available wallets on my host system

    image.png{width="381" height="600"}

  • when i try to click on one of the wallet connect extensions, you can also see that the wallets that are installed are not distinguished from those that aren't installed.

    image.png{width="458" height="600"}


Severity / Impact

P2 Polish. No funds are at risk, but the missing install/not-installed differentiation is a standard UX pattern on every multi-wallet dapp. A CEX-migrant unfamiliar with browser extensions has no way to know which wallets work and no path to install a missing one. Found under W2-C2 (Wallet selection UX Display dimension).

cc: @PlasticDigits

### Issue Summary The connect wallet modal lists all wallet options (Station, Keplr, WalletConnect, Leap, etc.) identically regardless of whether the extension is installed in the browser. No "installed" badge, label, or visual treatment differentiates available wallets from unavailable ones before the user clicks. Clicking an uninstalled wallet does return an error (e.g. _"Failed to connect Leap: Leap extension is not installed"_), so the failure is not silent, but the user has no way to know which wallets are ready without clicking each one. --- ### Reproduction Steps 1. Open the app at `http://127.0.0.1:3000` in a browser profile that does **not** have all wallet extensions installed 2. Click the **Connect Wallet** button in the header 3. Observe the wallet list in the modal — all options appear visually identical 4. Click an uninstalled wallet (e.g. Leap) — observe the error toast/message 5. Note that no pre-click visual distinction indicated the wallet was unavailable --- ### Expected Behavior Wallet options that are not installed should be visually distinct before the user clicks — for example, grayed out, with a label like "Not installed", or with an "Install" CTA. This lets users immediately identify which wallets are ready to use without a trial-and-error click cycle. --- ### Actual Behavior All wallet options look identical regardless of install state. Clicking an uninstalled wallet (e.g. Leap) returns _"Failed to connect Leap: Leap extension is not installed"_ — error handling is present, but the modal gives no pre-click signal about which wallets are available. --- ### Environment Details | Field | Value | |-------|-------| | OS | macOS (Apple M1 Pro, 14-inch) | | Browser | Google Chrome (desktop) | | Viewport | 1470×864 | | Network | `localterra` (local Docker) | | Frontend | `VITE_NETWORK=local npm run dev` | --- ### Wallet / Device Details - **Wallet state:** Disconnected (testing connect modal) --- ### Screenshot * list of available wallets on my host system ![image.png](/uploads/d3db045becd0bfb7c136fffc7514e198/image.png){width="381" height="600"} * when i try to click on one of the wallet connect extensions, you can also see that the wallets that are installed are not distinguished from those that aren't installed. ![image.png](/uploads/3a49a8e6b5dcd2db9c86f06412eaea8b/image.png){width="458" height="600"} --- ### Severity / Impact **P2 Polish.** No funds are at risk, but the missing install/not-installed differentiation is a standard UX pattern on every multi-wallet dapp. A CEX-migrant unfamiliar with browser extensions has no way to know which wallets work and no path to install a missing one. Found under W2-C2 (Wallet selection UX Display dimension). cc: @PlasticDigits
totdking (Migrated from gitlab.com) reopened this issue 2026-05-06 16:07:35 +00:00
totdking commented 2026-05-06 16:19:15 +00:00 (Migrated from gitlab.com)

mentioned in issue #116

mentioned in issue #116
Brouie commented 2026-05-07 06:31:37 +00:00 (Migrated from gitlab.com)

@totdking @PlasticDigits — source-level audit found additional gaps in the connect modal beyond the installed-vs-not-installed differentiation this ticket covers. flagging for scope-decision: extend here vs file siblings.

Additional gaps found at frontend-dapp/src/components/wallet/WalletModal.tsx

HIGH

  • Lines 81-94 — wallet rows are text-only ({option.name} + {option.connectionLabel}); no per-wallet brand logo or icon. Sister gap to the installed-badge issue this ticket scopes — distinguishing wallets visually with their brand mark also helps a CEX-migrant identify Station vs Keplr vs Leap before clicking.
  • Lines 97-101 — generic "Connecting..." indicator does not say WHICH wallet is connecting. If the user clicks Keplr and Keplr's prompt is hidden behind another window or the user dismisses it, the modal just sits in "Connecting..." with no indication. Easy to leave a stuck wallet prompt while the user thinks the click did nothing.

POLISH

  • No description / one-line help per wallet option (e.g., "Browser extension — recommended" vs "Mobile via WalletConnect QR"). Title-only rows are easy to misread for a first-time user.
  • Modal does not visibly reset the failed-row state after error — user has to click the same wallet again to retry. An explicit "Retry" button on the failing row would be clearer.
  • Modal title "Connect Wallet" has no subhead explaining what permissions are requested or what the dapp will see. Trust signal for first-time visitors.

Line 65 — error rendered raw via <div className="alert-error">{error}</div>. Covered separately in the off-chain error humanization pile (filing a sibling ticket for that).

Suggestion

either:

A. expand this ticket to cover all connect modal display gaps (logos + connecting copy + descriptions + retry + subhead) plus the existing installed differentiation
B. keep this ticket scoped to installed-vs-not-installed and file siblings for logos and connecting-state

either works. defer to your call on which is cleaner for tracking.

cc @PlasticDigits

@totdking @PlasticDigits — source-level audit found additional gaps in the connect modal beyond the installed-vs-not-installed differentiation this ticket covers. flagging for scope-decision: extend here vs file siblings. ## Additional gaps found at `frontend-dapp/src/components/wallet/WalletModal.tsx` ### HIGH - **Lines 81-94** — wallet rows are text-only (`{option.name}` + `{option.connectionLabel}`); no per-wallet brand logo or icon. Sister gap to the installed-badge issue this ticket scopes — distinguishing wallets visually with their brand mark also helps a CEX-migrant identify Station vs Keplr vs Leap before clicking. - **Lines 97-101** — generic "Connecting..." indicator does not say WHICH wallet is connecting. If the user clicks Keplr and Keplr's prompt is hidden behind another window or the user dismisses it, the modal just sits in "Connecting..." with no indication. Easy to leave a stuck wallet prompt while the user thinks the click did nothing. ### POLISH - No description / one-line help per wallet option (e.g., "Browser extension — recommended" vs "Mobile via WalletConnect QR"). Title-only rows are easy to misread for a first-time user. - Modal does not visibly reset the failed-row state after error — user has to click the same wallet again to retry. An explicit "Retry" button on the failing row would be clearer. - Modal title "Connect Wallet" has no subhead explaining what permissions are requested or what the dapp will see. Trust signal for first-time visitors. ### Cross-link `Line 65` — error rendered raw via `<div className="alert-error">{error}</div>`. Covered separately in the off-chain error humanization pile (filing a sibling ticket for that). ## Suggestion either: **A. expand this ticket** to cover all connect modal display gaps (logos + connecting copy + descriptions + retry + subhead) plus the existing installed differentiation **B. keep this ticket scoped to installed-vs-not-installed** and file siblings for logos and connecting-state either works. defer to your call on which is cleaner for tracking. cc @PlasticDigits
Brouie commented 2026-05-07 06:38:59 +00:00 (Migrated from gitlab.com)

mentioned in issue #145

mentioned in issue #145
PlasticDigits commented 2026-05-07 12:12:56 +00:00 (Migrated from gitlab.com)

For wallet icons & branding they can be copied from the gitlab.com/plasticdigits/cl8y-bridge-monorepo
B is approved - file sibling issues for logos and connecting state.

For wallet icons & branding they can be copied from the gitlab.com/plasticdigits/cl8y-bridge-monorepo B is approved - file sibling issues for logos and connecting state.
PlasticDigits commented 2026-05-11 09:07:53 +00:00 (Migrated from gitlab.com)

mentioned in commit fcbd77c81a

mentioned in commit fcbd77c81a24f6324268fcc2ace582724e1cfe03
PlasticDigits commented 2026-05-11 09:08:16 +00:00 (Migrated from gitlab.com)

Implemented #139 (scope B: installed vs not-installed only; logos / “which wallet is connecting” remain sibling tickets per thread).

What changed

  • Connect modal extension rows show Ready vs Not installed, muted styling when missing, and an Install link (official download/setup URLs).
  • Detection is centralized in frontend-dapp/src/services/terraclassic/walletExtensionInstall.ts, aligned with getKeplrLikeExtension for Leap/Cosmostation and 'station' in window for Station. WalletConnect options are unchanged (no “not installed” label).
  • useWalletExtensionInstallSnapshot re-reads install state on window focus and document visibilitychange so returning from a store tab can refresh badges without a full reload.
  • Docs / agents: docs/frontend.md § Connect modal: extension install detection (anchor #connect-modal-extension-install); cross-links in skills/AGENTS_BUNDLE_DEV_WALLET.md.
  • Tests: walletExtensionInstall.test.ts. Modal.test.tsx now passes required children so tsc -b / npm run build succeeds (was failing on main before this change).

Checklist for QA

  1. In a browser with mixed extensions (e.g. Keplr installed, Leap not): Ready / Not installed badges and dimmed row match reality before clicking.
  2. LuncDash / Galaxy Station rows: only the WalletConnect pill — no false “Not installed”.
  3. Open Install in a new tab, complete or cancel, return and focus the dApp tab: badges refresh (focus / visibility path).
  4. npm run build and npx vitest run in frontend-dapp pass on latest main.

@brouie could you confirm the above on your side when you have a moment? Leaving the issue open until verified.

(Agent push: latest main includes commit fcbd77c.)

Implemented **#139** (scope **B**: installed vs not-installed only; logos / “which wallet is connecting” remain sibling tickets per thread). ### What changed - Connect modal **extension** rows show **Ready** vs **Not installed**, muted styling when missing, and an **Install** link (official download/setup URLs). - Detection is centralized in `frontend-dapp/src/services/terraclassic/walletExtensionInstall.ts`, **aligned with `getKeplrLikeExtension`** for Leap/Cosmostation and **`'station' in window`** for Station. **WalletConnect** options are unchanged (no “not installed” label). - `useWalletExtensionInstallSnapshot` re-reads install state on **window focus** and **document visibilitychange** so returning from a store tab can refresh badges without a full reload. - **Docs / agents:** `docs/frontend.md` § *Connect modal: extension install detection* (anchor `#connect-modal-extension-install`); cross-links in `skills/AGENTS_BUNDLE_DEV_WALLET.md`. - **Tests:** `walletExtensionInstall.test.ts`. **`Modal.test.tsx`** now passes required `children` so `tsc -b` / `npm run build` succeeds (was failing on `main` before this change). ### Checklist for QA 1. [ ] In a browser with **mixed** extensions (e.g. Keplr installed, Leap not): **Ready** / **Not installed** badges and dimmed row match reality **before** clicking. 2. [ ] **LuncDash** / **Galaxy Station** rows: only the WalletConnect pill — no false “Not installed”. 3. [ ] Open **Install** in a new tab, complete or cancel, return and **focus** the dApp tab: badges refresh (focus / visibility path). 4. [ ] `npm run build` and `npx vitest run` in `frontend-dapp` pass on latest `main`. @brouie could you confirm the above on your side when you have a moment? Leaving the issue **open** until verified. *(Agent push: latest `main` includes commit `fcbd77c`.)*
totdking commented 2026-05-26 13:02:39 +00:00 (Migrated from gitlab.com)

Checklist for QA

  1. In a browser with mixed extensions (e.g. Keplr installed, Leap not): Ready / Not installed badges and dimmed row match reality before clicking.
  2. LuncDash / Galaxy Station rows: only the WalletConnect pill — no false “Not installed”.
  3. Open Install in a new tab, complete or cancel, return and focus the dApp tab: badges refresh (focus / visibility path).
  4. npm run build and npx vitest run in frontend-dapp pass on latest main.

Issues noticed

Build & Test Gate Failures

npm run build — Failed (3 TypeScript errors) The production build was blocked by type errors introduced when the patch and test files were last updated. No code was changed at runtime but tsc strict checking caught three mismatches: an unsafe index access in PriceChart.test.tsx, an incomplete MediaQueryList mock signature in TradePage.test.tsx, and a string | undefined passed where string is required in TradePage.tsx. These must be resolved before a production build is possible.

npx vitest run — 1 test failed out of 594 The only failure is cosmesPatch127.test.ts — a stale test asserting symbol names (EXTENSION_SIGNED_FEE_MIN_PERCENT, gasFromAminoFee, gasFromDirectSignedAuthInfoBytes) that no longer exist in the patched file. The patch itself is correctly applied and functioning — 6 of the 9 assertions pass. The test needs to be updated to reflect the renamed symbols.

Status: Both gates are currently red. Neither failure affects runtime behaviour but both block CI and the build checklist.

cc: @PlasticDigits similar to comment https://gitlab.com/PlasticDigits/cl8y-dex-terraclassic/-/work_items/138#note_3385130841

### Checklist for QA 1. [x] In a browser with **mixed** extensions (e.g. Keplr installed, Leap not): **Ready** / **Not installed** badges and dimmed row match reality **before** clicking. 2. [x] **LuncDash** / **Galaxy Station** rows: only the WalletConnect pill — no false “Not installed”. 3. [x] Open **Install** in a new tab, complete or cancel, return and **focus** the dApp tab: badges refresh (focus / visibility path). 4. [ ] `npm run build` and `npx vitest run` in `frontend-dapp` pass on latest `main`. ### Issues noticed **Build & Test Gate Failures** **`npm run build`** — Failed (3 TypeScript errors) The production build was blocked by type errors introduced when the patch and test files were last updated. No code was changed at runtime but `tsc` strict checking caught three mismatches: an unsafe index access in `PriceChart.test.tsx`, an incomplete `MediaQueryList` mock signature in `TradePage.test.tsx`, and a `string | undefined` passed where `string` is required in `TradePage.tsx`. These must be resolved before a production build is possible. **`npx vitest run`** — 1 test failed out of 594 The only failure is `cosmesPatch127.test.ts` — a stale test asserting symbol names (`EXTENSION_SIGNED_FEE_MIN_PERCENT`, `gasFromAminoFee`, `gasFromDirectSignedAuthInfoBytes`) that no longer exist in the patched file. The patch itself is correctly applied and functioning — 6 of the 9 assertions pass. The test needs to be updated to reflect the renamed symbols. **Status:** Both gates are currently red. Neither failure affects runtime behaviour but both block CI and the build checklist. cc: @PlasticDigits similar to comment https://gitlab.com/PlasticDigits/cl8y-dex-terraclassic/-/work_items/138#note_3385130841
PlasticDigits commented 2026-05-26 13:16:22 +00:00 (Migrated from gitlab.com)

mentioned in commit ec5dac88f2

mentioned in commit ec5dac88f25d01a4ae5af369229984d5dc89b33c
PlasticDigits commented 2026-05-26 13:16:57 +00:00 (Migrated from gitlab.com)

Build & test gates — resolved

Commit: ec5dac8 on main

The three TypeScript errors blocking npm run build are fixed:

  1. PriceChart.test.tsx — getCandles mock now handles optional interval before indexing the close-price map (strict tsc -b over test files).
  2. TradePage.test.tsx — matchMedia stub uses as unknown as MediaQueryList with a typed MediaQueryListEvent listener (aligned with useMediaQuery.test.tsx).
  3. TradePage.tsx — isKnownFactoryTradePair is now a type predicate (addr is string) so setPairAddr(routePair) narrows correctly after the guard.

Docs / agents: docs/frontend.md § tsc -b invariant and connect-modal Build gate row; cross-links in skills/AGENTS_FRONTEND_PRODUCTION_BUILD.md, AGENTS_FRONTEND_WALLET_CONNECT_MODAL.md, AGENTS_FRONTEND_TRADE_INVALID_PAIR_LINK.md.

Verification

cd frontend-dapp
npm run build          # tsc -b + vite build — pass
npx vitest run         # 96 files, 594 tests — pass

QA checklist item 4 is now green. Closing #139 — install-detection UX was already verified in browser (items 1–3).

### Build & test gates — resolved **Commit:** `ec5dac8` on `main` The three TypeScript errors blocking `npm run build` are fixed: 1. **`PriceChart.test.tsx`** — `getCandles` mock now handles optional `interval` before indexing the close-price map (strict `tsc -b` over test files). 2. **`TradePage.test.tsx`** — `matchMedia` stub uses `as unknown as MediaQueryList` with a typed `MediaQueryListEvent` listener (aligned with `useMediaQuery.test.tsx`). 3. **`TradePage.tsx`** — `isKnownFactoryTradePair` is now a **type predicate** (`addr is string`) so `setPairAddr(routePair)` narrows correctly after the guard. **Docs / agents:** `docs/frontend.md` § [`tsc -b` invariant](#vite-production-sourcemaps) and connect-modal **Build gate** row; cross-links in `skills/AGENTS_FRONTEND_PRODUCTION_BUILD.md`, `AGENTS_FRONTEND_WALLET_CONNECT_MODAL.md`, `AGENTS_FRONTEND_TRADE_INVALID_PAIR_LINK.md`. ### Verification ```bash cd frontend-dapp npm run build # tsc -b + vite build — pass npx vitest run # 96 files, 594 tests — pass ``` QA checklist item 4 is now green. Closing #139 — install-detection UX was already verified in browser (items 1–3).
PlasticDigits (Migrated from gitlab.com) closed this issue 2026-05-26 13:16:59 +00:00
PlasticDigits commented 2026-06-07 12:14:13 +00:00 (Migrated from gitlab.com)

mentioned in issue #337

mentioned in issue #337
PlasticDigits commented 2026-07-14 11:12:36 +00:00 (Migrated from gitlab.com)

mentioned in issue #490

mentioned in issue #490
PlasticDigits commented 2026-08-18 00:20:44 +00:00 (Migrated from gitlab.com)

mentioned in issue #554

mentioned in issue #554
PlasticDigits commented 2026-08-18 15:21:51 +00:00 (Migrated from gitlab.com)

mentioned in issue PlasticDigits2/ustr-cmm#17

mentioned in issue PlasticDigits2/ustr-cmm#17
PlasticDigits commented 2026-08-18 15:22:40 +00:00 (Migrated from gitlab.com)

mentioned in issue #566

mentioned in issue #566
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
code/cl8y-dex-terraclassic#139
No description provided.