feat(frontend): preserve mixed-case tickers on /protocol oracle #1240

Closed
opened 2026-09-11 21:48:56 +00:00 by PlasticDigits · 8 comments

Summary

On /protocol, product ticker strings in the DEX hub prices card and the CEX oracle card are flattened by Tailwind uppercase. Canonical mixed-case identities (cUSTC, vFDUSD) render as CUSTC and VFDUSD, so the hub wrap mark sits next to a CEX USTC / USD heading that no longer looks like a different asset, and the vFDUSD tab undoes the #571 / #572 visual distinction from FDUSD.

Bundle into one issue: stop text-transform: uppercase on ticker-bearing labels (hub <dt>, oracle heading, oracle tabs). Keep uppercase on chrome-only headings (DEX hub prices, table column headers, page H1). Do not merge hub and CEX cards, rename CEX USTC to cUSTC, or change indexer ticker ids (custc, ustc, vfdusd).

Related (closed, shipped the cards — do not reopen): #550 (unified oracle card), #556 / #570 (DEX hub + cUSTC / LUNC columns), #571 / #572 (vFDUSD tab = FDUSD CEX reference + Venus 1 vFDUSD Price). Copy length: #489. Token picker casing: #630 (different surface).

Current codebase

Hub labels are correct in source, then CSS uppercases them

ProtocolDexHubPrices.tsx prints HUB_PRICE_TICKER_LABEL[ticker] / USD on a <dt className="text-xs uppercase tracking-wide">. hubPriceTicker.ts already maps:

id label (source) on-screen today
custc cUSTC CUSTC
lunc LUNC LUNC
ust1 UST1 UST1
ustr USTR USTR

The card H2 DEX hub prices also uses uppercase — that chrome is fine. Wrap AddressRow aria already says cUSTC token / cLUNC wrap. Disclaimer stays DEX reference — not CEX, not settlement.

Oracle tabs and heading use the same uppercase class

ProtocolOracleCard.tsx (data-testid="protocol-oracle"):

  • H2 {heading} is uppercase. For ustc / lunc that is ${label} / USD. For vfdusd, heading is vFDUSD only (no / USD, #571). CSS turns it into VFDUSD.
  • Tabs map PROTOCOL_ORACLE_TICKER_LABEL (protocolOracleTicker.ts: USTC, LUNC, vFDUSD) with font-semibold uppercase tracking-wide. vFDUSD → VFDUSD.
  • StatBox for the CEX print is FDUSD reference price when ticker === 'vfdusd', else Reference price. Venus block heading is 1 vFDUSD Price (also uppercase — vFDUSD becomes VFDUSD there too).
  • Disclaimer (not uppercase): Indexer CEX/aggregator reference — not swap settlement, TWAP, or the UST1 window rate. vFDUSD variant: CEX FDUSD reference and Venus redeem rate — not settlement.

ProtocolPage.tsx page H1 is Protocol + lead DEX USD stats, DEX hub marks, and CEX reference prices. Not settlement. Query ?ticker= allowlist is unchanged (ustc | lunc | vfdusd).

Tests do not catch the flattening

ProtocolPage.test.tsx asserts getByRole('heading', { name: /^vFDUSD$/i }) (case-insensitive) and hub copy/explorer aria (cUSTC, cLUNC) — not the visible <dt> / tab text. jsdom does not apply text-transform, so CI never sees CUSTC / VFDUSD.

Why the new implementation is needed

Retail on /protocol must tell cUSTC (wrap hub) from USTC (CEX) and vFDUSD from FDUSD at a glance. Uppercasing mixed-case product tickers collapses those identities. Source maps and #571 copy already have the right strings; the chrome class fights them.

Constraints / guardrails

  • Do not change indexer paths, GET /api/v1/oracle/price/{ticker}, GET /api/v1/hub-prices, Venus poller, or wrap address resolution.
  • Do not add a fourth CEX tab (ustr / ust1 / custc). Hub vs CEX stay two cards.
  • Do not retitle CEX USTC as cUSTC or hub LUNC as cLUNC. Hub lunc is the CEX LUNC mark with a cLUNC wrap contract row (#570). Oracle lunc is the CEX LUNC feed with sources/history.
  • Do not drop the anti-settlement disclaimers (P550-11). Do not claim TWAP, swap, or UST1 window.
  • Do not share window.location.href or leak host:port on 502 (existing outage banner).
  • uppercase may remain on non-ticker chrome (page H1, DEX hub prices, On-chain contracts, table SOURCE / USD / TIME, StatBox labels that are not tickers).
  • No wallet, auth, keys, wasm, deploy, or 2-of-3 work.

Relevant files

  1. Remove uppercase from hub <dt> ticker lines, oracle H2, oracle tab buttons, and the Venus 1 vFDUSD Price heading (or any other node that interpolates cUSTC / cLUNC / vFDUSD). Keep tracking-wide / font-semibold if useful.
  2. Leave ticker maps as-is. Visible text must equal those maps character-for-character.
  3. Tighten RTL: exact-case substring / name match (no /i on vFDUSD / cUSTC). Assert hub cUSTC / USD and oracle tab vFDUSD. jsdom will pass; that is still the contract for future CSS.

Definition of Ready

Given / When / Then

Given /protocol with hub prices and the CEX oracle card rendered
When a reader looks at hub column labels and oracle tabs (including the vFDUSD tab and Venus heading)
Then visible product tickers match the maps: hub cUSTC / USD, LUNC / USD, UST1 / USD, USTR / USD; oracle tabs USTC, LUNC, vFDUSD; vFDUSD H2 is vFDUSD (not vFDUSD / USD); Venus heading retains lowercase v in vFDUSD; CEX USTC heading remains USTC / USD (not cUSTC).

Given the vFDUSD tab
When the CEX StatBox and Venus block render
Then the CEX print stays labeled FDUSD reference price; Venus stays 1 vFDUSD Price with mixed-case vFDUSD; disclaimers still deny settlement / TWAP / UST1 window.

Acceptance criteria

  • Hub <dt> shows cUSTC / USD (not CUSTC / USD). LUNC / UST1 / USTR unchanged besides no extra transform.
  • Oracle tabs show USTC, LUNC, vFDUSD (not VFDUSD).
  • Oracle H2: USTC / USD, LUNC / USD, or vFDUSD per #571 (vFDUSD heading has no / USD).
  • Venus heading 1 vFDUSD Price keeps mixed-case vFDUSD.
  • CEX vs hub identity unchanged: wrap hub is cUSTC; CEX tab is USTC; hub LUNC still has cLUNC wrap AddressRow; oracle LUNC still loads CEX sources/history.
  • Disclaimers and ?ticker= allowlist unchanged. No new CEX tickers.
  • RTL asserts exact casing; existing keyboard / deep-link / 502 tests still pass.

Test plan (functional paths)

  • Hub card: within(hub).getByText('cUSTC / USD'); must not match CUSTC / USD. Same for absence of VFDUSD on oracle tabs.
  • Oracle: default USTC heading USTC / USD; click / keyboard to vFDUSD → heading vFDUSD with case-sensitive accessible name; tab text vFDUSD.
  • vFDUSD: FDUSD reference price + Venus 1 vFDUSD Price still present; CEX query still vfdusd; Venus query still separate.
  • Regression: ?ticker=vfdusd deep link; unknown ?ticker= still falls back to ustc; P550-11 disclaimer; hub wrap copy aria still cUSTC / cLUNC.

Test plan (attack, hack, and abuse)

Not a wallet / auth / keys / wasm / deploy / 2-of-3 surface. Keep existing ticker parser tests: fdusd, javascript:, ../, HTML, and custc must not become CEX oracle tickers. No extra DeFi attack suite.

Verification criteria

  • frontend-dapp Protocol page unit tests pass, including new exact-case assertions.
  • Manual /protocol: hub cUSTC / USD next to oracle USTC / USD is readable as wrap vs CEX; vFDUSD tab shows vFDUSD not VFDUSD.
  • Chrome headings may still render as DEX HUB PRICES / PROTOCOL.
  • No indexer, hub-price, or Venus API change in the diff.

Out of scope

  • Renaming the oracle card in UI copy to/from “Oracle” vs “CEX reference” beyond ticker strings.
  • Token pickers, Charts hero, CG/CMC listing fields, indexer log lines (#580), or wallet balance row casing (already cUSTC / cLUNC).
  • New oracle sources (Bitget #520) or vFDUSD CEX identity in the API.

First-pass model recommendation

Recommendation: composer

Rationale: First pass, low/medium risk, chrome-only class change on two production files in the protocol UI (ProtocolOracleCard.tsx, ProtocolDexHubPrices.tsx) plus focused assertions in ProtocolPage.test.tsx. Ticker maps, indexer, and Venus stay untouched. No shared protocol/state, migration, or founder-required surface (contracts, auth, keys, wasm, deploy, wallet / 2-of-3). Acceptance is deterministic RTL exact-case text. File count alone is not the reason; the edit is a known local CSS vs label-map mismatch with a clear non-goal list.

## Summary On `/protocol`, product ticker strings in the **DEX hub prices** card and the **CEX oracle** card are flattened by Tailwind `uppercase`. Canonical mixed-case identities (`cUSTC`, `vFDUSD`) render as `CUSTC` and `VFDUSD`, so the hub wrap mark sits next to a CEX `USTC / USD` heading that no longer looks like a different asset, and the vFDUSD tab undoes the #571 / #572 visual distinction from FDUSD. Bundle into **one** issue: stop `text-transform: uppercase` on **ticker-bearing** labels (hub `<dt>`, oracle heading, oracle tabs). Keep uppercase on **chrome-only** headings (`DEX hub prices`, table column headers, page H1). Do **not** merge hub and CEX cards, rename CEX `USTC` to `cUSTC`, or change indexer ticker ids (`custc`, `ustc`, `vfdusd`). Related (closed, shipped the cards — do not reopen): [#550](https://git.cl8y.com/code/cl8y-dex-terraclassic/issues/550) (unified oracle card), [#556](https://git.cl8y.com/code/cl8y-dex-terraclassic/issues/556) / [#570](https://git.cl8y.com/code/cl8y-dex-terraclassic/issues/570) (DEX hub + `cUSTC` / `LUNC` columns), [#571](https://git.cl8y.com/code/cl8y-dex-terraclassic/issues/571) / [#572](https://git.cl8y.com/code/cl8y-dex-terraclassic/issues/572) (vFDUSD tab = FDUSD CEX reference + Venus `1 vFDUSD Price`). Copy length: [#489](https://git.cl8y.com/code/cl8y-dex-terraclassic/issues/489). Token picker casing: [#630](https://git.cl8y.com/code/cl8y-dex-terraclassic/issues/630) (different surface). ## Current codebase ### Hub labels are correct in source, then CSS uppercases them [`ProtocolDexHubPrices.tsx`](frontend-dapp/src/components/protocol/ProtocolDexHubPrices.tsx) prints `HUB_PRICE_TICKER_LABEL[ticker] / USD` on a `<dt className="text-xs uppercase tracking-wide">`. [`hubPriceTicker.ts`](frontend-dapp/src/utils/hubPriceTicker.ts) already maps: | id | label (source) | on-screen today | |----|-----------------|-----------------| | `custc` | `cUSTC` | **CUSTC** | | `lunc` | `LUNC` | LUNC | | `ust1` | `UST1` | UST1 | | `ustr` | `USTR` | USTR | The card H2 `DEX hub prices` also uses `uppercase` — that chrome is fine. Wrap `AddressRow` aria already says `cUSTC token` / `cLUNC wrap`. Disclaimer stays **DEX reference — not CEX, not settlement.** ### Oracle tabs and heading use the same `uppercase` class [`ProtocolOracleCard.tsx`](frontend-dapp/src/components/protocol/ProtocolOracleCard.tsx) (`data-testid="protocol-oracle"`): - H2 `{heading}` is `uppercase`. For `ustc` / `lunc` that is `${label} / USD`. For `vfdusd`, heading is **`vFDUSD`** only (no `/ USD`, #571). CSS turns it into **VFDUSD**. - Tabs map `PROTOCOL_ORACLE_TICKER_LABEL` ([`protocolOracleTicker.ts`](frontend-dapp/src/utils/protocolOracleTicker.ts): `USTC`, `LUNC`, `vFDUSD`) with `font-semibold uppercase tracking-wide`. **vFDUSD → VFDUSD**. - StatBox for the CEX print is `FDUSD reference price` when `ticker === 'vfdusd'`, else `Reference price`. Venus block heading is `1 vFDUSD Price` (also `uppercase` — `vFDUSD` becomes `VFDUSD` there too). - Disclaimer (not uppercase): **Indexer CEX/aggregator reference — not swap settlement, TWAP, or the UST1 window rate.** vFDUSD variant: **CEX FDUSD reference and Venus redeem rate — not settlement.** [`ProtocolPage.tsx`](frontend-dapp/src/pages/ProtocolPage.tsx) page H1 is `Protocol` + lead **DEX USD stats, DEX hub marks, and CEX reference prices. Not settlement.** Query `?ticker=` allowlist is unchanged (`ustc` \| `lunc` \| `vfdusd`). ### Tests do not catch the flattening [`ProtocolPage.test.tsx`](frontend-dapp/src/pages/ProtocolPage.test.tsx) asserts `getByRole('heading', { name: /^vFDUSD$/i })` (case-insensitive) and hub copy/explorer aria (`cUSTC`, `cLUNC`) — not the visible `<dt>` / tab text. jsdom does not apply `text-transform`, so CI never sees `CUSTC` / `VFDUSD`. ## Why the new implementation is needed Retail on `/protocol` must tell **cUSTC (wrap hub)** from **USTC (CEX)** and **vFDUSD** from **FDUSD** at a glance. Uppercasing mixed-case product tickers collapses those identities. Source maps and #571 copy already have the right strings; the chrome class fights them. ## Constraints / guardrails - Do **not** change indexer paths, `GET /api/v1/oracle/price/{ticker}`, `GET /api/v1/hub-prices`, Venus poller, or wrap address resolution. - Do **not** add a fourth CEX tab (`ustr` / `ust1` / `custc`). Hub vs CEX stay two cards. - Do **not** retitle CEX USTC as cUSTC or hub LUNC as cLUNC. Hub `lunc` is the CEX LUNC mark with a **cLUNC wrap** contract row (#570). Oracle `lunc` is the CEX LUNC feed with sources/history. - Do **not** drop the anti-settlement disclaimers (P550-11). Do not claim TWAP, swap, or UST1 window. - Do **not** share `window.location.href` or leak host:port on 502 (existing outage banner). - `uppercase` may remain on non-ticker chrome (page H1, **DEX hub prices**, **On-chain contracts**, table `SOURCE` / `USD` / `TIME`, StatBox labels that are not tickers). - No wallet, auth, keys, wasm, deploy, or 2-of-3 work. ## Relevant files - [`frontend-dapp/src/components/protocol/ProtocolOracleCard.tsx`](frontend-dapp/src/components/protocol/ProtocolOracleCard.tsx) - [`frontend-dapp/src/components/protocol/ProtocolDexHubPrices.tsx`](frontend-dapp/src/components/protocol/ProtocolDexHubPrices.tsx) - [`frontend-dapp/src/pages/ProtocolPage.test.tsx`](frontend-dapp/src/pages/ProtocolPage.test.tsx) - Labels already correct (expect **no** id remap): [`protocolOracleTicker.ts`](frontend-dapp/src/utils/protocolOracleTicker.ts), [`hubPriceTicker.ts`](frontend-dapp/src/utils/hubPriceTicker.ts) ## Recommended direction 1. Remove `uppercase` from hub `<dt>` ticker lines, oracle H2, oracle tab buttons, and the Venus `1 vFDUSD Price` heading (or any other node that interpolates `cUSTC` / `cLUNC` / `vFDUSD`). Keep `tracking-wide` / `font-semibold` if useful. 2. Leave ticker **maps** as-is. Visible text must equal those maps character-for-character. 3. Tighten RTL: exact-case substring / `name` match (no `/i` on `vFDUSD` / `cUSTC`). Assert hub `cUSTC / USD` and oracle tab `vFDUSD`. jsdom will pass; that is still the contract for future CSS. ## Definition of Ready ### Given / When / Then **Given** `/protocol` with hub prices and the CEX oracle card rendered **When** a reader looks at hub column labels and oracle tabs (including the vFDUSD tab and Venus heading) **Then** visible product tickers match the maps: hub `cUSTC / USD`, `LUNC / USD`, `UST1 / USD`, `USTR / USD`; oracle tabs `USTC`, `LUNC`, `vFDUSD`; vFDUSD H2 is `vFDUSD` (not `vFDUSD / USD`); Venus heading retains lowercase `v` in `vFDUSD`; CEX USTC heading remains `USTC / USD` (not `cUSTC`). **Given** the vFDUSD tab **When** the CEX StatBox and Venus block render **Then** the CEX print stays labeled **FDUSD reference price**; Venus stays **1 vFDUSD Price** with mixed-case `vFDUSD`; disclaimers still deny settlement / TWAP / UST1 window. ## Acceptance criteria - [ ] Hub `<dt>` shows `cUSTC / USD` (not `CUSTC / USD`). `LUNC` / `UST1` / `USTR` unchanged besides no extra transform. - [ ] Oracle tabs show `USTC`, `LUNC`, `vFDUSD` (not `VFDUSD`). - [ ] Oracle H2: `USTC / USD`, `LUNC / USD`, or `vFDUSD` per #571 (vFDUSD heading has no `/ USD`). - [ ] Venus heading `1 vFDUSD Price` keeps mixed-case `vFDUSD`. - [ ] CEX vs hub identity unchanged: wrap hub is `cUSTC`; CEX tab is `USTC`; hub `LUNC` still has cLUNC wrap `AddressRow`; oracle `LUNC` still loads CEX sources/history. - [ ] Disclaimers and `?ticker=` allowlist unchanged. No new CEX tickers. - [ ] RTL asserts exact casing; existing keyboard / deep-link / 502 tests still pass. ## Test plan (functional paths) - Hub card: `within(hub).getByText('cUSTC / USD')`; must **not** match `CUSTC / USD`. Same for absence of `VFDUSD` on oracle tabs. - Oracle: default USTC heading `USTC / USD`; click / keyboard to vFDUSD → heading `vFDUSD` with **case-sensitive** accessible name; tab text `vFDUSD`. - vFDUSD: `FDUSD reference price` + Venus `1 vFDUSD Price` still present; CEX query still `vfdusd`; Venus query still separate. - Regression: `?ticker=vfdusd` deep link; unknown `?ticker=` still falls back to `ustc`; P550-11 disclaimer; hub wrap copy aria still `cUSTC` / `cLUNC`. ## Test plan (attack, hack, and abuse) Not a wallet / auth / keys / wasm / deploy / 2-of-3 surface. Keep existing ticker parser tests: `fdusd`, `javascript:`, `../`, HTML, and `custc` must **not** become CEX oracle tickers. No extra DeFi attack suite. ## Verification criteria - [ ] `frontend-dapp` Protocol page unit tests pass, including new exact-case assertions. - [ ] Manual `/protocol`: hub `cUSTC / USD` next to oracle `USTC / USD` is readable as wrap vs CEX; vFDUSD tab shows `vFDUSD` not `VFDUSD`. - [ ] Chrome headings may still render as `DEX HUB PRICES` / `PROTOCOL`. - [ ] No indexer, hub-price, or Venus API change in the diff. ## Out of scope - Renaming the oracle card in UI copy to/from “Oracle” vs “CEX reference” beyond ticker strings. - Token pickers, Charts hero, CG/CMC listing fields, indexer log lines (#580), or wallet balance row casing (already `cUSTC` / `cLUNC`). - New oracle sources (Bitget #520) or vFDUSD CEX identity in the API. ## First-pass model recommendation Recommendation: composer Rationale: First pass, low/medium risk, chrome-only class change on two production files in the protocol UI (`ProtocolOracleCard.tsx`, `ProtocolDexHubPrices.tsx`) plus focused assertions in `ProtocolPage.test.tsx`. Ticker maps, indexer, and Venus stay untouched. No shared protocol/state, migration, or founder-required surface (contracts, auth, keys, wasm, deploy, wallet / 2-of-3). Acceptance is deterministic RTL exact-case text. File count alone is not the reason; the edit is a known local CSS vs label-map mismatch with a clear non-goal list.
Author
Owner

cl8y-agent-control: queued implement job 93b530a6-3f65-438b-8178-3d1504ae2a41 (not executed; no Hetzner VM).

cl8y-agent-control: queued `implement` job `93b530a6-3f65-438b-8178-3d1504ae2a41` (not executed; no Hetzner VM).
Author
Owner

Merged onto origin/main via #1241. make verify-issue-1240 was 8/8. /protocol hub/oracle tickers keep mixed case (cUSTC, vFDUSD). Frontend-only; no wasm leftover.

CI: Woodpecker did not post live statuses; merge used local gitleaks + Forgejo status ci/woodpecker/pr/woodpecker.

Merged onto `origin/main` via #1241. `make verify-issue-1240` was 8/8. `/protocol` hub/oracle tickers keep mixed case (`cUSTC`, `vFDUSD`). Frontend-only; no wasm leftover. CI: Woodpecker did not post live statuses; merge used local gitleaks + Forgejo status `ci/woodpecker/pr/woodpecker`.
Author
Owner

Woodpecker enablement follow-up: #1247 (frontend already on main; Coolify bake is optional).

Woodpecker enablement follow-up: #1247 (frontend already on main; Coolify bake is optional).
Author
Owner

Also there is inconsistency with naming on some pages, for instance """DEX hub prices

DEX reference — not CEX, not settlement.

cUSTC / USD
$0.00516100
terra1…56ch
LUNC / USD
$0.0000510433
terra1…sgdg
UST1 / USD
$0.996903
terra1…w55f
USTR / USD
$0.00956560
terra1…hgqy
"""
Should be cLUNC not LUNC

Also there is inconsistency with naming on some pages, for instance """DEX hub prices DEX reference — not CEX, not settlement. cUSTC / USD $0.00516100 terra1…56ch LUNC / USD $0.0000510433 terra1…sgdg UST1 / USD $0.996903 terra1…w55f USTR / USD $0.00956560 terra1…hgqy """ Should be cLUNC not LUNC
Author
Owner

/agent implement

/agent implement
Author
Owner

also not naming is inconsistent on /protocol oracle, it says cUSTC/USD and LUNC/USD, it shoudl be USTC/USD and LUNC/USD

also not naming is inconsistent on /protocol oracle, it says cUSTC/USD and LUNC/USD, it shoudl be USTC/USD and LUNC/USD
Author
Owner

Merged as PR #1290. Hub wrap dts are cUSTC / cLUNC; CEX tabs stay USTC / LUNC / vFDUSD.

Leftover: production /protocol glance-check after Coolify. Tracked on #1300.

Merged as PR #1290. Hub wrap dts are cUSTC / cLUNC; CEX tabs stay USTC / LUNC / vFDUSD. Leftover: production /protocol glance-check after Coolify. Tracked on #1300.
Author
Owner

Post-merge note vs the original issue text: mixed-case already shipped in #1241. PR #1290 rewrote hub wrap from LUNC / USD to cLUNC / USD (CEX tabs stay native LUNC). That contradicts the original GWT/P1240-5 “do not retitle hub LUNC as cLUNC”; treat the merged leftover as the product choice, not a faithful close of the first AC wording. Production /protocol glance-check still on #1300.

Post-merge note vs the original issue text: mixed-case already shipped in #1241. PR #1290 **rewrote** hub wrap from `LUNC / USD` to `cLUNC / USD` (CEX tabs stay native LUNC). That contradicts the original GWT/P1240-5 “do not retitle hub LUNC as cLUNC”; treat the merged leftover as the product choice, not a faithful close of the first AC wording. Production `/protocol` glance-check still on #1300.
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#1240
No description provided.