ux: Terms hint says Keplr-only though Station / Cosmostation / Lunc Dash / Galaxy Station also sign #658

Closed
opened 2026-08-26 04:07:59 +00:00 by PlasticDigits · 9 comments
PlasticDigits commented 2026-08-26 04:07:59 +00:00 (Migrated from gitlab.com)

Summary

Community report (anonymized): after connect, the Accept terms path tells the user to open the site in Keplr, even though multiple Terra Classic wallets can finish signing.

The DEX string is hardcoded:

Open this site in the Keplr browser to accept terms.

That copy was added for #554 WC-M12 when the Legal portal could only call window.keplr.signArbitrary. The portal has since shipped a full wallet matrix (cl8y-ecosystem-legal#11 / !731): Station, Keplr, Leap, Cosmostation, LUNC Dash, Galaxy Station. DEX Connect already offers Station / Keplr / Cosmostation / LuncDash / Galaxy Station (#566). Telling a Station or Lunc Dash user to switch to Keplr is now false and blocks the happy path.

This issue is DEX retail copy + hint visibility + docs. Do not reimplement ADR-036 in this repo (C1). Portal leftover QA/ops stay on legal#13. Do not add Leap to the DEX Connect list (#159).


Current codebase

Hint surface

ConnectedTermsGate wraps <Outlet> after wallet connect (#517). It always mounts LegalKeplrInAppHint above SDK TermsGate. Accept still navigates to Legal sign_urls.terra_classic — the DEX does not sign.

legalKeplrInAppHint.ts:

  • Show when signedLatest === false and !isBrowserWalletExtensionDetected(WalletName.KEPLR) (i.e. only !!window.keplr).
  • Copy: LEGAL_KEPLR_INAPP_HINT = Open this site in the Keplr browser to accept terms.
  • Station (window.station / window.station.keplr) and Cosmostation (window.cosmostation?.providers?.keplr) do not hide the hint. A user already in Station or Cosmostation in-app still sees “use Keplr.”
  • After WalletConnect (no injector), every wallet — including Station / Cosmostation / Lunc Dash / Galaxy Station — sees the Keplr-only line.

getKeplrLikeExtension already knows the three injectors. The hint ignores that helper and only checks Keplr.

Connect list vs hint

resolveConnectWalletOptions offers:

Wallet Desktop Mobile without extension
Station Extension WalletConnect (#566)
Keplr Extension WalletConnect (#554)
Cosmostation Extension WalletConnect (#566)
LuncDash WalletConnect WalletConnect
Galaxy Station WalletConnect WalletConnect

Leap is absent on the DEX (#159). The Legal portal still lists Leap (ustr-cmm matrix). DEX copy must not advertise Leap.

Docs locked to Keplr-only

WC-M12 / C1 still require the Keplr-browser sentence:

Tests pin the old wording:

make verify-issue-554 still requires WC-M12 + the hint unit tests. Update that target in the same MR so it asserts the new invariant, not the Keplr-only sentence.

TermsGate already receives account={address} (Legal #13 integrator leftover does not apply to this DEX).


Why this is needed

  1. The portal is no longer Keplr-only. After legal !731, /sign/terra-classic can sign with Station, Keplr, Cosmostation, LUNC Dash, and Galaxy Station (and Leap on the portal). DEX users who connected those wallets are told to abandon them.
  2. The hint is shown in the wrong browsers. Station / Cosmostation in-app already inject a Keplr-compatible provider. Showing “open Keplr” there is incorrect and may send the user out of a working signer.
  3. WalletConnect is a first-class DEX path. After #554 / #566, mobile Chrome connect is WC for every listed wallet. The next-step line must match that list, or users think T&C is Keplr-gated.
  4. Retail trust. Misleading wallet requirements on a legal gate look like a lock-in or a broken product.

Constraints / guardrails

  1. C1 — no ADR-036 in the DEX. Keep @plasticdigits/cl8y-clickwrap + full navigation to the portal. Do not verify signArbitrary here.
  2. C2–C10 unchanged (property dex.cl8y.com, TERRA_CLASSIC only, fail closed, redirect allowlist, CSP, no admin secrets, Playwright hatch, NFA footer).
  3. WC-M1–WC-M11 unchanged. This ticket only retargets WC-M12 (Legal next-step copy / visibility). Do not regress pairing, deep-link allowlist, or desktop QR.
  4. Do not add Leap to Connect or to DEX hint copy (#159). Portal Leap is Legal’s matrix, not this dApp.
  5. Do not claim WalletConnect can sign terms inside the DEX tab. Portal still needs an injected provider or its own in-page WC. The hint may still show after WC with no injector — it must name the supported wallets, not Keplr alone.
  6. Hide the hint when any signer-capable injector is present — window.keplr, window.station?.keplr, or window.cosmostation?.providers?.keplr (reuse getKeplrLikeExtension / isBrowserWalletExtensionDetected for Station + Cosmostation + Keplr). Do not treat 'station' in window alone as enough if the Keplr shim is missing.
  7. #489 copy. One short sentence. No “ADR-036”, no wallet-architecture essay, no always-on banner on Swap after signed_latest.
  8. Do not iframe the portal. Full navigation only.
  9. Do not widen CSP connect-src to https:.
  10. Do not treat cl8y-dex-risk-ack as Legal proof.
  11. Address binding stays on the portal. A signature for a different terra1… must not unlock this connected wallet.
  12. Simulated / Playwright hatch (VITE_PLAYWRIGHT_E2E) still skips the gate; do not enable it on production.

Relevant files

Area Paths
Hint copy + visibility frontend-dapp/src/utils/legalKeplrInAppHint.ts, frontend-dapp/src/components/legal/LegalKeplrInAppHint.tsx
Gate frontend-dapp/src/components/legal/ConnectedTermsGate.tsx
Injector detect frontend-dapp/src/services/terraclassic/keplrLikeExtension.ts, frontend-dapp/src/services/terraclassic/walletExtensionInstall.ts
Connect list (copy must match) frontend-dapp/src/components/wallet/connectWalletOptions.ts
Optional UA (do not UA-sniff as the only fix) frontend-dapp/src/utils/detectWalletInAppBrowser.ts
Styles frontend-dapp/src/index.css (.app-connected-terms-keplr-hint — rename class if the copy is no longer Keplr-only)
Tests frontend-dapp/src/utils/__tests__/legalKeplrInAppHint.test.ts, frontend-dapp/src/components/legal/__tests__/ConnectedTermsGate.test.tsx
Docs / skills docs/frontend.md (WC-M12, C1), skills/AGENTS_FRONTEND_CLICKWRAP.md, skills/AGENTS_FRONTEND_WALLETCONNECT_MOBILE.md
Verify scripts/qa/verify-issue-554.sh (update WC-M12 assertion), new scripts/qa/verify-issue-<this>.sh + make verify-issue-<this>
QA QA_TEMPLATE.md (add a multi-wallet terms-hint row next to 1.2.11 / 1.2.12)

Ship copy + visibility in one MR. Do not wait on Legal #13 manual QA.

  1. Rename the helper conceptually (keep file if churn is high): shouldShowLegalWalletInAppHint / LEGAL_TERMS_WALLET_HINT. Detection input should be hasSignerInjector (Keplr or Station shim or Cosmostation keplr provider), not hasKeplrExtension alone.
  2. Copy (retail-short, pick one and test): e.g. Open this site in your Terra Classic wallet browser to accept terms. or Sign terms with the same wallet you connected (Station, Keplr, Cosmostation, Lunc Dash, or Galaxy Station). Name the DEX Connect set. Do not say “Keplr only” or “install Keplr.”
  3. Optional polish: if walletType / last-connected name is known, a one-wallet sentence is OK (Open this site in Station to accept terms.) plus the same hide rule when that wallet’s injector is already present. Fallback to the multi-wallet sentence when the type is unknown.
  4. Keep Accept. TermsGate CTA still goes to terms.cl8y.com/sign/terra-classic?property=dex.cl8y.com with account + sanitized redirect_uri. The hint is next-step copy, not a second signer.
  5. Update WC-M12 / C1 to: after WC without a signer injector, show the multi-wallet (or connected-wallet) hint; hide when any keplr-like injector exists; portal signing stays in cl8y-ecosystem-legal.
  6. Tests + make verify-issue-<this>. Update #554’s verify script so it does not require the old Keplr-only sentence.

Acceptance criteria

  • Unsigned + no signer injector: hint is visible and does not say Keplr is the only accepted wallet.
  • Hint names the DEX-supported Terra Classic wallets (Station, Keplr, Cosmostation, Lunc Dash, Galaxy Station) or the single connected wallet. Leap is not named on the DEX.
  • Unsigned + window.keplr: hint hidden (existing #554 behavior).
  • Unsigned + Station window.station.keplr only (no window.keplr): hint hidden.
  • Unsigned + Cosmostation window.cosmostation.providers.keplr only: hint hidden.
  • signed_latest === true or status null / loading: hint hidden.
  • Disconnected browse: no hint, no gate (C5).
  • Accept Terms still navigates to the Legal portal; DEX still does not implement ADR-036.
  • Fail-closed unknown/error Legal status still blocks transactional children.
  • WC-M12 / C1 docs and skills match the new copy and hide rule.
  • make verify-issue-554 still passes (updated assertions).
  • #489: no extra essay on Swap after the user is signed.

Test plan (all paths)

Unit — visibility

Setup Expect
signedLatest: false, no injector Show hint
signedLatest: false, window.keplr Hide
signedLatest: false, Station keplr shim only Hide
signedLatest: false, Cosmostation keplr provider only Hide
signedLatest: true, any injector Hide
signedLatest: null (loading / error) Hide
'station' in window but no station.keplr Show (shim missing — user still needs a signer or portal WC)

Unit — copy

  • Hint text must not match /Keplr browser/ as the sole instruction.
  • Must mention more than one DEX wallet or the connected wallet name.
  • Must not mention Leap, ADR-036, or window.keplr.

Component — ConnectedTermsGate

  • Disconnected: children render; no hint.
  • Unsigned WC (walletType luncdash / galaxystation / station / cosmostation / keplr) without injector: Accept visible + multi-wallet (or named) hint.
  • Unsigned + mocked window.keplr: Accept visible, hint absent.
  • Unsigned + mocked Station / Cosmostation injector: Accept visible, hint absent.
  • signed_latest: true: children render, no hint.
  • Legal status reject: fail-closed alert, no transactional children.

Docs / verify scripts

  • AGENTS_FRONTEND_CLICKWRAP.md C1 and AGENTS_FRONTEND_WALLETCONNECT_MOBILE.md WC-M12 no longer mandate the Keplr-only sentence.
  • docs/frontend.md WC-M12 + C1 updated.
  • scripts/qa/verify-issue-554.sh greps the new WC-M12 wording (or a stable token like WC-M12 + “not Keplr-only”).
  • New make verify-issue-<this> runs the hint + gate tests + doc greps.

Manual (columbus-5 / https://dex.cl8y.com, unsigned wallet)

  1. Desktop Chrome + Keplr extension: connect → Accept Terms, no Keplr-only hint.
  2. Desktop Chrome + Station extension: connect → Accept, no “open Keplr” hint.
  3. Desktop Chrome + Cosmostation extension: same.
  4. Android Chrome + Keplr WC: connect → hint (if no injector) names multiple wallets or Keplr, not “Keplr only”; Accept opens portal wallet list.
  5. Android Chrome + Station WC / Cosmostation WC / Lunc Dash / Galaxy Station: same; user must not be told Keplr is required.
  6. Keplr / Station / Cosmostation in-app browser: connect via Extension → hint hidden; Accept works in that browser.
  7. Already signed: no hint; Swap/Pool children render.
  8. Disconnect: browse OK; hint gone.
  9. Legal API down: fail-closed; no spoofed signed state.

Playwright e2e/legal-clickwrap-517.spec.ts still only proves the automation hatch (no Accept in smoke). Do not require live portal signing in CI.


Test plan (attack / hack / abuse)

Vector Expectation
Page script sets window.keplr = {} (or fake Station/Cosmostation) to hide the hint Hide is UX only. TermsGate still queries Legal status. Fake injector cannot produce signed_latest. Portal / API still verify ADR-036.
Attacker site copies the hint and deep-links to a phishing “Keplr browser” New copy must not instruct users to install a random APK or open a non-allowlisted URL. Hint is text, not an <a href> to a wallet download.
Open redirect via redirect_uri sanitizeRedirectUri + portal allowlist unchanged. Hint must not append a user-controlled URL.
Hint tells user to switch wallets so a different terra1 signs If named-wallet copy is used, it must be the connected address’s wallet. A signature for another account must not satisfy this gate.
XSS in wallet name / walletType Render as text. Do not dangerouslySetInnerHTML.
Clickjack / iframe the DEX gate over the portal Existing: do not embed the portal. CSP + full navigation stay.
VITE_PLAYWRIGHT_E2E=true on a production build Still forbidden (C9). This ticket must not add a new skip flag.
User “accepts” by dismissing the hint only Hint is not a control. Unsigned + fail-closed still blocks swap/LP/limits/wrap/create.
Social-engineering: “Keplr support asked me to sign a different message” DEX still does not present a custom ADR-036 payload. All signing stays on terms.cl8y.com.
Property confusion (cl8y.com vs dex.cl8y.com) Status + sign URL stay C2 dex.cl8y.com.

Verification criteria

# Hint + gate
bash scripts/with-node.sh --cwd frontend-dapp -- npm test -- --run \
  src/utils/__tests__/legalKeplrInAppHint.test.ts \
  src/components/legal/__tests__/ConnectedTermsGate.test.tsx \
  src/utils/__tests__/legalClickwrap.test.ts

# Do not regress mobile connect / clickwrap
make verify-issue-554
make verify-issue-517
make verify-issue-566

# This issue (add Makefile target)
make verify-issue-<this>

Done when:

  1. A reviewer connecting Station, Cosmostation, Lunc Dash, or Galaxy Station never sees copy that implies only Keplr can accept terms.
  2. Keplr / Station / Cosmostation injected browsers do not show a “switch wallet” hint.
  3. Accept still lands on the Legal Terra Classic sign page; DEX still has no ADR-036 verify.
  4. Docs WC-M12 / C1 match the shipped string and hide rule.
  5. make verify-issue-554 and make verify-issue-<this> are green.

Related: #517 clickwrap, #554 WC-M12 origin, #566 Station/Cosmostation WC, #159 no Leap, legal#11 portal matrix (closed), legal#13 portal QA leftovers (out of scope).

## Summary Community report (anonymized): after connect, the **Accept terms** path tells the user to open the site in **Keplr**, even though multiple Terra Classic wallets can finish signing. The DEX string is hardcoded: `Open this site in the Keplr browser to accept terms.` That copy was added for [#554](https://gitlab.com/PlasticDigits/cl8y-dex-terraclassic/-/issues/554) **WC-M12** when the Legal portal could only call `window.keplr.signArbitrary`. The portal has since shipped a full wallet matrix ([cl8y-ecosystem-legal#11](https://gitlab.com/PlasticDigits/cl8y-ecosystem-legal/-/issues/11) / [!731](https://gitlab.com/PlasticDigits/cl8y-ecosystem-legal/-/merge_requests/13)): **Station, Keplr, Leap, Cosmostation, LUNC Dash, Galaxy Station**. DEX Connect already offers Station / Keplr / Cosmostation / LuncDash / Galaxy Station ([#566](https://gitlab.com/PlasticDigits/cl8y-dex-terraclassic/-/issues/566)). Telling a Station or Lunc Dash user to switch to Keplr is now false and blocks the happy path. This issue is **DEX retail copy + hint visibility + docs**. Do **not** reimplement ADR-036 in this repo (**C1**). Portal leftover QA/ops stay on [legal#13](https://gitlab.com/PlasticDigits/cl8y-ecosystem-legal/-/issues/13). Do **not** add Leap to the DEX Connect list ([#159](https://gitlab.com/PlasticDigits/cl8y-dex-terraclassic/-/issues/159)). --- ## Current codebase ### Hint surface [`ConnectedTermsGate`](frontend-dapp/src/components/legal/ConnectedTermsGate.tsx) wraps `<Outlet>` after wallet connect ([#517](https://gitlab.com/PlasticDigits/cl8y-dex-terraclassic/-/issues/517)). It always mounts [`LegalKeplrInAppHint`](frontend-dapp/src/components/legal/LegalKeplrInAppHint.tsx) above SDK `TermsGate`. Accept still **navigates** to Legal `sign_urls.terra_classic` — the DEX does not sign. [`legalKeplrInAppHint.ts`](frontend-dapp/src/utils/legalKeplrInAppHint.ts): - Show when `signedLatest === false` **and** `!isBrowserWalletExtensionDetected(WalletName.KEPLR)` (i.e. only `!!window.keplr`). - Copy: `LEGAL_KEPLR_INAPP_HINT` = **Open this site in the Keplr browser to accept terms.** - Station (`window.station` / `window.station.keplr`) and Cosmostation (`window.cosmostation?.providers?.keplr`) do **not** hide the hint. A user already in Station or Cosmostation in-app still sees “use Keplr.” - After WalletConnect (no injector), every wallet — including Station / Cosmostation / Lunc Dash / Galaxy Station — sees the Keplr-only line. [`getKeplrLikeExtension`](frontend-dapp/src/services/terraclassic/keplrLikeExtension.ts) already knows the three injectors. The hint ignores that helper and only checks Keplr. ### Connect list vs hint [`resolveConnectWalletOptions`](frontend-dapp/src/components/wallet/connectWalletOptions.ts) offers: | Wallet | Desktop | Mobile without extension | |--------|---------|--------------------------| | Station | Extension | WalletConnect (#566) | | Keplr | Extension | WalletConnect (#554) | | Cosmostation | Extension | WalletConnect (#566) | | LuncDash | WalletConnect | WalletConnect | | Galaxy Station | WalletConnect | WalletConnect | Leap is **absent** on the DEX ([#159](https://gitlab.com/PlasticDigits/cl8y-dex-terraclassic/-/issues/159)). The Legal portal still lists Leap (ustr-cmm matrix). DEX copy must not advertise Leap. ### Docs locked to Keplr-only **WC-M12** / **C1** still require the Keplr-browser sentence: - [`skills/AGENTS_FRONTEND_WALLETCONNECT_MOBILE.md`](skills/AGENTS_FRONTEND_WALLETCONNECT_MOBILE.md) **WC-M12** - [`skills/AGENTS_FRONTEND_CLICKWRAP.md`](skills/AGENTS_FRONTEND_CLICKWRAP.md) **C1** - [`docs/frontend.md`](docs/frontend.md) WalletConnect table + Legal clickwrap **C1** Tests pin the old wording: - [`legalKeplrInAppHint.test.ts`](frontend-dapp/src/utils/__tests__/legalKeplrInAppHint.test.ts) — show/hide only on `hasKeplrExtension` - [`ConnectedTermsGate.test.tsx`](frontend-dapp/src/components/legal/__tests__/ConnectedTermsGate.test.tsx) — `toHaveTextContent(/Keplr browser/i)` `make verify-issue-554` still requires WC-M12 + the hint unit tests. Update that target in the same MR so it asserts the new invariant, not the Keplr-only sentence. `TermsGate` already receives `account={address}` (Legal #13 integrator leftover does **not** apply to this DEX). --- ## Why this is needed 1. **The portal is no longer Keplr-only.** After legal !731, `/sign/terra-classic` can sign with Station, Keplr, Cosmostation, LUNC Dash, and Galaxy Station (and Leap on the portal). DEX users who connected those wallets are told to abandon them. 2. **The hint is shown in the wrong browsers.** Station / Cosmostation in-app already inject a Keplr-compatible provider. Showing “open Keplr” there is incorrect and may send the user out of a working signer. 3. **WalletConnect is a first-class DEX path.** After #554 / #566, mobile Chrome connect is WC for every listed wallet. The next-step line must match that list, or users think T&C is Keplr-gated. 4. **Retail trust.** Misleading wallet requirements on a legal gate look like a lock-in or a broken product. --- ## Constraints / guardrails 1. **C1 — no ADR-036 in the DEX.** Keep `@plasticdigits/cl8y-clickwrap` + full navigation to the portal. Do not verify `signArbitrary` here. 2. **C2–C10 unchanged** (property `dex.cl8y.com`, `TERRA_CLASSIC` only, fail closed, redirect allowlist, CSP, no admin secrets, Playwright hatch, NFA footer). 3. **WC-M1–WC-M11 unchanged.** This ticket only retargets **WC-M12** (Legal next-step copy / visibility). Do not regress pairing, deep-link allowlist, or desktop QR. 4. **Do not add Leap** to Connect or to DEX hint copy (#159). Portal Leap is Legal’s matrix, not this dApp. 5. **Do not claim WalletConnect can sign terms inside the DEX tab.** Portal still needs an injected provider or its own in-page WC. The hint may still show after WC with no injector — it must name the **supported wallets**, not Keplr alone. 6. **Hide the hint when any signer-capable injector is present** — `window.keplr`, `window.station?.keplr`, or `window.cosmostation?.providers?.keplr` (reuse `getKeplrLikeExtension` / `isBrowserWalletExtensionDetected` for Station + Cosmostation + Keplr). Do not treat `'station' in window` alone as enough if the Keplr shim is missing. 7. **#489 copy.** One short sentence. No “ADR-036”, no wallet-architecture essay, no always-on banner on Swap after `signed_latest`. 8. **Do not iframe the portal.** Full navigation only. 9. **Do not widen CSP** `connect-src` to `https:`. 10. **Do not treat `cl8y-dex-risk-ack` as Legal proof.** 11. **Address binding stays on the portal.** A signature for a different `terra1…` must not unlock this connected wallet. 12. **Simulated / Playwright hatch** (`VITE_PLAYWRIGHT_E2E`) still skips the gate; do not enable it on production. --- ## Relevant files | Area | Paths | |------|--------| | Hint copy + visibility | `frontend-dapp/src/utils/legalKeplrInAppHint.ts`, `frontend-dapp/src/components/legal/LegalKeplrInAppHint.tsx` | | Gate | `frontend-dapp/src/components/legal/ConnectedTermsGate.tsx` | | Injector detect | `frontend-dapp/src/services/terraclassic/keplrLikeExtension.ts`, `frontend-dapp/src/services/terraclassic/walletExtensionInstall.ts` | | Connect list (copy must match) | `frontend-dapp/src/components/wallet/connectWalletOptions.ts` | | Optional UA (do not UA-sniff as the only fix) | `frontend-dapp/src/utils/detectWalletInAppBrowser.ts` | | Styles | `frontend-dapp/src/index.css` (`.app-connected-terms-keplr-hint` — rename class if the copy is no longer Keplr-only) | | Tests | `frontend-dapp/src/utils/__tests__/legalKeplrInAppHint.test.ts`, `frontend-dapp/src/components/legal/__tests__/ConnectedTermsGate.test.tsx` | | Docs / skills | `docs/frontend.md` (WC-M12, C1), `skills/AGENTS_FRONTEND_CLICKWRAP.md`, `skills/AGENTS_FRONTEND_WALLETCONNECT_MOBILE.md` | | Verify | `scripts/qa/verify-issue-554.sh` (update WC-M12 assertion), new `scripts/qa/verify-issue-<this>.sh` + `make verify-issue-<this>` | | QA | `QA_TEMPLATE.md` (add a multi-wallet terms-hint row next to 1.2.11 / 1.2.12) | --- ## Recommended direction Ship **copy + visibility** in one MR. Do not wait on Legal #13 manual QA. 1. **Rename the helper conceptually** (keep file if churn is high): `shouldShowLegalWalletInAppHint` / `LEGAL_TERMS_WALLET_HINT`. Detection input should be `hasSignerInjector` (Keplr **or** Station shim **or** Cosmostation keplr provider), not `hasKeplrExtension` alone. 2. **Copy (retail-short, pick one and test):** e.g. `Open this site in your Terra Classic wallet browser to accept terms.` or `Sign terms with the same wallet you connected (Station, Keplr, Cosmostation, Lunc Dash, or Galaxy Station).` Name the DEX Connect set. Do **not** say “Keplr only” or “install Keplr.” 3. **Optional polish:** if `walletType` / last-connected name is known, a one-wallet sentence is OK (`Open this site in Station to accept terms.`) **plus** the same hide rule when that wallet’s injector is already present. Fallback to the multi-wallet sentence when the type is unknown. 4. **Keep Accept.** `TermsGate` CTA still goes to `terms.cl8y.com/sign/terra-classic?property=dex.cl8y.com` with `account` + sanitized `redirect_uri`. The hint is next-step copy, not a second signer. 5. **Update WC-M12 / C1** to: after WC without a signer injector, show the **multi-wallet** (or connected-wallet) hint; hide when any keplr-like injector exists; portal signing stays in `cl8y-ecosystem-legal`. 6. **Tests + `make verify-issue-<this>`.** Update #554’s verify script so it does not require the old Keplr-only sentence. --- ## Acceptance criteria - [ ] Unsigned + no signer injector: hint is visible and does **not** say Keplr is the only accepted wallet. - [ ] Hint names the DEX-supported Terra Classic wallets (Station, Keplr, Cosmostation, Lunc Dash, Galaxy Station) **or** the single connected wallet. Leap is not named on the DEX. - [ ] Unsigned + `window.keplr`: hint hidden (existing #554 behavior). - [ ] Unsigned + Station `window.station.keplr` only (no `window.keplr`): hint hidden. - [ ] Unsigned + Cosmostation `window.cosmostation.providers.keplr` only: hint hidden. - [ ] `signed_latest === true` or status `null` / loading: hint hidden. - [ ] Disconnected browse: no hint, no gate (**C5**). - [ ] Accept Terms still navigates to the Legal portal; DEX still does not implement ADR-036. - [ ] Fail-closed unknown/error Legal status still blocks transactional children. - [ ] WC-M12 / C1 docs and skills match the new copy and hide rule. - [ ] `make verify-issue-554` still passes (updated assertions). - [ ] `#489`: no extra essay on Swap after the user is signed. --- ## Test plan (all paths) ### Unit — visibility | Setup | Expect | |-------|--------| | `signedLatest: false`, no injector | Show hint | | `signedLatest: false`, `window.keplr` | Hide | | `signedLatest: false`, Station keplr shim only | Hide | | `signedLatest: false`, Cosmostation keplr provider only | Hide | | `signedLatest: true`, any injector | Hide | | `signedLatest: null` (loading / error) | Hide | | `'station' in window` but **no** `station.keplr` | Show (shim missing — user still needs a signer or portal WC) | ### Unit — copy - Hint text must not match `/Keplr browser/` as the sole instruction. - Must mention more than one DEX wallet **or** the connected wallet name. - Must not mention Leap, ADR-036, or `window.keplr`. ### Component — `ConnectedTermsGate` - Disconnected: children render; no hint. - Unsigned WC (`walletType` luncdash / galaxystation / station / cosmostation / keplr) without injector: Accept visible + multi-wallet (or named) hint. - Unsigned + mocked `window.keplr`: Accept visible, hint absent. - Unsigned + mocked Station / Cosmostation injector: Accept visible, hint absent. - `signed_latest: true`: children render, no hint. - Legal status reject: fail-closed alert, no transactional children. ### Docs / verify scripts - `AGENTS_FRONTEND_CLICKWRAP.md` **C1** and `AGENTS_FRONTEND_WALLETCONNECT_MOBILE.md` **WC-M12** no longer mandate the Keplr-only sentence. - `docs/frontend.md` WC-M12 + C1 updated. - `scripts/qa/verify-issue-554.sh` greps the new WC-M12 wording (or a stable token like `WC-M12` + “not Keplr-only”). - New `make verify-issue-<this>` runs the hint + gate tests + doc greps. ### Manual (columbus-5 / `https://dex.cl8y.com`, unsigned wallet) 1. **Desktop Chrome + Keplr extension:** connect → Accept Terms, **no** Keplr-only hint. 2. **Desktop Chrome + Station extension:** connect → Accept, **no** “open Keplr” hint. 3. **Desktop Chrome + Cosmostation extension:** same. 4. **Android Chrome + Keplr WC:** connect → hint (if no injector) names multiple wallets or Keplr, not “Keplr only”; Accept opens portal wallet list. 5. **Android Chrome + Station WC / Cosmostation WC / Lunc Dash / Galaxy Station:** same; user must not be told Keplr is required. 6. **Keplr / Station / Cosmostation in-app browser:** connect via Extension → hint hidden; Accept works in that browser. 7. **Already signed:** no hint; Swap/Pool children render. 8. **Disconnect:** browse OK; hint gone. 9. **Legal API down:** fail-closed; no spoofed signed state. Playwright `e2e/legal-clickwrap-517.spec.ts` still only proves the automation hatch (no Accept in smoke). Do not require live portal signing in CI. --- ## Test plan (attack / hack / abuse) | Vector | Expectation | |--------|-------------| | Page script sets `window.keplr = {}` (or fake Station/Cosmostation) to hide the hint | Hide is UX only. `TermsGate` still queries Legal status. Fake injector cannot produce `signed_latest`. Portal / API still verify ADR-036. | | Attacker site copies the hint and deep-links to a phishing “Keplr browser” | New copy must not instruct users to install a random APK or open a non-allowlisted URL. Hint is text, not an `<a href>` to a wallet download. | | Open redirect via `redirect_uri` | `sanitizeRedirectUri` + portal allowlist unchanged. Hint must not append a user-controlled URL. | | Hint tells user to switch wallets so a different `terra1` signs | If named-wallet copy is used, it must be the **connected** address’s wallet. A signature for another account must not satisfy this gate. | | XSS in wallet name / `walletType` | Render as text. Do not `dangerouslySetInnerHTML`. | | Clickjack / iframe the DEX gate over the portal | Existing: do not embed the portal. CSP + full navigation stay. | | `VITE_PLAYWRIGHT_E2E=true` on a production build | Still forbidden (**C9**). This ticket must not add a new skip flag. | | User “accepts” by dismissing the hint only | Hint is not a control. Unsigned + fail-closed still blocks swap/LP/limits/wrap/create. | | Social-engineering: “Keplr support asked me to sign a different message” | DEX still does not present a custom ADR-036 payload. All signing stays on `terms.cl8y.com`. | | Property confusion (`cl8y.com` vs `dex.cl8y.com`) | Status + sign URL stay **C2** `dex.cl8y.com`. | --- ## Verification criteria ```bash # Hint + gate bash scripts/with-node.sh --cwd frontend-dapp -- npm test -- --run \ src/utils/__tests__/legalKeplrInAppHint.test.ts \ src/components/legal/__tests__/ConnectedTermsGate.test.tsx \ src/utils/__tests__/legalClickwrap.test.ts # Do not regress mobile connect / clickwrap make verify-issue-554 make verify-issue-517 make verify-issue-566 # This issue (add Makefile target) make verify-issue-<this> ``` **Done when:** 1. A reviewer connecting Station, Cosmostation, Lunc Dash, or Galaxy Station never sees copy that implies **only Keplr** can accept terms. 2. Keplr / Station / Cosmostation injected browsers do not show a “switch wallet” hint. 3. Accept still lands on the Legal Terra Classic sign page; DEX still has no ADR-036 verify. 4. Docs **WC-M12** / **C1** match the shipped string and hide rule. 5. `make verify-issue-554` and `make verify-issue-<this>` are green. Related: [#517](https://gitlab.com/PlasticDigits/cl8y-dex-terraclassic/-/issues/517) clickwrap, [#554](https://gitlab.com/PlasticDigits/cl8y-dex-terraclassic/-/issues/554) WC-M12 origin, [#566](https://gitlab.com/PlasticDigits/cl8y-dex-terraclassic/-/issues/566) Station/Cosmostation WC, [#159](https://gitlab.com/PlasticDigits/cl8y-dex-terraclassic/-/issues/159) no Leap, [legal#11](https://gitlab.com/PlasticDigits/cl8y-ecosystem-legal/-/issues/11) portal matrix (closed), [legal#13](https://gitlab.com/PlasticDigits/cl8y-ecosystem-legal/-/issues/13) portal QA leftovers (out of scope).
PlasticDigits commented 2026-08-26 04:08:00 +00:00 (Migrated from gitlab.com)

marked as related to #517

marked as related to #517
PlasticDigits commented 2026-08-26 04:08:01 +00:00 (Migrated from gitlab.com)

marked as related to #554

marked as related to #554
PlasticDigits commented 2026-08-26 04:08:02 +00:00 (Migrated from gitlab.com)

marked as related to #566

marked as related to #566
PlasticDigits commented 2026-08-26 06:53:11 +00:00 (Migrated from gitlab.com)

mentioned in commit 494c066f01

mentioned in commit 494c066f01413f97ec995332c8f16305bbc40bb0
PlasticDigits commented 2026-08-26 06:54:45 +00:00 (Migrated from gitlab.com)

mentioned in merge request !1157

mentioned in merge request !1157
PlasticDigits commented 2026-08-26 08:09:23 +00:00 (Migrated from gitlab.com)

mentioned in commit c2a6592da5

mentioned in commit c2a6592da5cc84ac3fcfbf1d36a6dad0df4d2d09
PlasticDigits (Migrated from gitlab.com) closed this issue 2026-08-26 08:09:23 +00:00
PlasticDigits commented 2026-08-26 09:30:50 +00:00 (Migrated from gitlab.com)

Merged to main via !1157. Makefile help-line union with later verifies.

Leftover: connected Legal hint still names DEX wallets (not Keplr-only) after frontend rebuild. make verify-issue-658.

Merged to `main` via !1157. Makefile help-line union with later verifies. Leftover: connected Legal hint still names DEX wallets (not Keplr-only) after frontend rebuild. `make verify-issue-658`.
PlasticDigits commented 2026-08-26 09:31:34 +00:00 (Migrated from gitlab.com)

mentioned in issue #673

mentioned in issue #673
PlasticDigits commented 2026-08-30 02:48:10 +00:00 (Migrated from gitlab.com)

mentioned in issue #706

mentioned in issue #706
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#658
No description provided.