feat: /trade UST1 pair invert — default other-side Price (USD), pair pill, ticket flip #524

Closed
opened 2026-08-15 12:19:47 +00:00 by PlasticDigits · 42 comments
PlasticDigits commented 2026-08-15 12:19:47 +00:00 (Migrated from gitlab.com)

Summary

On /trade, UST1 pairs (UST1/cUSTC, UST1/USTR, and any future UST1/* factory pair) currently chart and headline Price (USD) as the USD of 1 UST1 (~$1 after #522). Traders opening those markets need the other token’s USD price by default (cUSTC or USTR), a pair-orientation pill that inverts pricing on click, and a ticket heading that drops the unused Order ticket eyebrow in favor of Buy {token} plus a swap/invert control that flips which token is being bought.

This is one product surface: display + ticket orientation. Do not split into separate issues.

Related: #522 (USD of factory asset_0), #466 (indexer quote-per-base), #508 (UST1 secondary AMM), #489 / #412 (Buy {base} copy), #154 / #155 (limit price + escrow USD), #151 (non-negative USD scale).

Current codebase

Factory pairs store a fixed base/quote (asset_0 / asset_1). Indexer and UI treat that as canonical:

Layer Behavior today
Factory / pair wasm create_pair keeps caller asset_infos order. UST1 secondary scripts pass UST1 first, so columbus-5 UST1/cUSTC and UST1/USTR have UST1 = asset_0.
Indexer #466 / #522 swap_events.price = human quote per base. price_usd = USD of 1 human asset_0. Candles OHLC use COALESCE(price_usd, price). Quote catalog: UST1=$1, cUSTC=#515 USTC, USTR=2.5× USTC.
/trade chart TradePage → resolveTapeLastPriceUsd → PriceChart Price (USD) + Last headline. For UST1-as-base pairs this is ~$1, not the cUSTC/USTR print traders care about.
Pair chrome PairSearchSelect / pairInfoMenuLabel always render asset_0 / asset_1 (e.g. UST1 / cUSTC). The closed control is a search combobox — click opens search, it does not invert. There is no pair-orientation pill.
Order ticket TradeOrderTicket eyebrow Order ticket + heading Buy {token0} / Sell {token0} via tradeDirectionSideLabels(token0). Bid = buy factory base (pay quote); ask = sell factory base. LimitOrderSideFlipButton already flips bid ↔ ask, not pair orientation.
Limit / market submit Prices and sides are factory token1/token0. Book Edit prefills that same convention (#178). Crossing preflight compares typed factory price to book head (#154).
/charts Same PriceChart + resolveTapeLastPriceUsd — UST1 pairs also show ~$1.

Live pairs (columbus-5):

Pair Address
UST1/cUSTC terra1ceprjsxp86ggftf5e38wwt34l83e5gq7penkdnv4wsatkwcs8v6qccw55f
UST1/USTR terra16vxrhpvpcucu05y0nr862vf9hnqeh274uaff4s7hz4n0ea74006qf5hgqy

Why this is needed

After #522, the chart is correct as “USD of 1 UST1” and useless as a trading chart: UST1 is the $1 peg unit. Retail flow for these markets is “what is cUSTC (or USTR) worth?” — the other side.

Without a first-class invert:

  1. Traders misread a flat ~$1 candle as the market they came to trade.
  2. Ticket Buy UST1 is the opposite of the usual intent on a UST1-quoted pair (buy the floating token, pay UST1).
  3. Order ticket is leftover chrome (#489 cognitive-load rule: labels ≤ ~5 words; silence over instructional fluff).

Constraints / guardrails

  1. Indexer and CG/CMC stay factory-oriented. Do not change #466 / #522 price / price_usd, candle storage, or aggregator last_price. Invert is a frontend display of the same series (reciprocal + high/low swap).
  2. On-chain messages stay factory-oriented. place_limit_order price is still token1 per token0. Market swap still buys/sells factory base vs quote. Display invert must convert before simulate/submit and when applying book Edit prefills.
  3. Do not reuse LimitOrderSideFlipButton as pair invert. Bid/ask (Buy/Sell the displayed base) and pair invert (which token is the displayed base) are different. Keep the existing radiogroup (#153 / #412).
  4. Do not steal PairSearchSelect click. Combobox click/focus must still open pair search (#181, #180). Pair invert is a separate pill (chart header and/or ticket). Selected-pair label text may follow display order (cUSTC / UST1).
  5. UST1 default only when factory base is UST1. If UST1 is already asset_1, factory orientation already shows the other token — do not invert by default. Detect UST1 by symbol UST1 (case-insensitive) and/or known mainnet/local contract, not a substring that matches cUSTC.
  6. Reciprocal safety. Drop or refuse invert of a candle/tape print when price ≤ 0 or not finite. After invert, high/low swap. Y-axis remains non-negative (#151). Never pass Infinity / NaN into lightweight-charts (#226).
  7. One orientation state for chart headline, candle series, pair pill, ticket Buy {token}, Buy/Sell labels, limit “When 1 {token} is worth”, and (if book prices are inverted for display) book column titles. Do not let chart and ticket disagree.
  8. Pair switch clears or re-keys invert. Stale invert from pair A must not apply to pair B (#180 / #226). Persist per pairAddr if you persist at all.
  9. Route unchanged. /trade/:pairAddr still identifies the factory pair. Do not invent a second pair contract or swap asset_infos on chain.
  10. Copy. No token0 / token1 / bid / ask in retail chrome. No “ORDER TICKET”. Invert control needs an aria-label (e.g. Show UST1 / cUSTC pricing). Keep U1: never describe AMM invert as mint/redeem (#508).
  11. /limits standalone is out of scope unless it shares the new helper; do not silently invert limit prices there without the same convert-on-submit rule.
  12. /charts should use the same default + pill on PriceChart so UST1 pairs are not ~$1 there either. Ticket chrome is /trade only.

Relevant files

Must touch

  • frontend-dapp/src/pages/TradePage.tsx — orientation state; pass invert into chart + ticket; pair-pill placement
  • frontend-dapp/src/components/trade/TradeOrderTicket.tsx — remove Order ticket; Buy {displayBase} + invert icon; map display side ↔ factory bid/ask
  • frontend-dapp/src/components/charts/PriceChart.tsx — pair pill + inverted headline/series
  • frontend-dapp/src/components/charts/priceChartCandles.ts / chartHeadlinePrice.ts — reciprocal OHLC + finite drop
  • frontend-dapp/src/utils/pairPriceUsd.ts — USD of displayed base (factory price_usd or price_usd / human_price / quote catalog)
  • frontend-dapp/src/utils/tradeDirectionSideLabels.ts — labels follow display base
  • frontend-dapp/src/utils/pairMenuOptions.ts — optional display-order labels
  • frontend-dapp/src/components/trade/PairSearchSelect.tsx — selected label may follow display order; do not invert on combobox click
  • frontend-dapp/src/utils/limitOrderPriceReference.ts — display rate vs factory token1/token0 convert
  • frontend-dapp/src/components/trade/LimitOrderPriceField.tsx — “When 1 {displayBase} is worth”
  • frontend-dapp/src/components/trade/TradeMarketOrderPanel.tsx — pay/receive + quote/submit follow factory side after mapping
  • frontend-dapp/src/components/trade/OrderBookPanel.tsx — if book prices follow invert, convert Edit prefill back
  • frontend-dapp/src/pages/ChartsPage.tsx — same default + pill
  • docs/frontend.md — new invariants section
  • skills/AGENTS_FRONTEND_PRICE_CHART.md, skills/AGENTS_FRONTEND_TRADE_PAGE_LAYOUT.md, skills/AGENTS_INDEXER_PAIR_PRICE_USD.md (UI invert note; indexer math unchanged)

New helper (recommended)

  • frontend-dapp/src/utils/tradePairDisplayOrientation.ts (name flexible) — isUst1Leg, defaultInverted, displayAssets, invertUsd, invertOhlc, displayPriceToFactoryToken1PerToken0, factorySideFromDisplay

Tests / QA

  • frontend-dapp/src/pages/TradePage.test.tsx
  • frontend-dapp/src/components/charts/__tests__/PriceChart.test.tsx
  • frontend-dapp/src/utils/__tests__/pairPriceUsd.test.ts
  • frontend-dapp/src/utils/__tests__/tradeDirectionSideLabels.test.ts
  • frontend-dapp/e2e/trade-page-responsive.spec.ts / price-chart smoke
  • New scripts/qa/verify-issue-NNN.sh + make verify-issue-NNN

Do not change for this issue

  • indexer/src/indexer/swap_orientation.rs, pair_price_usd.rs, candle migrations
  • Pair wasm place_limit_order / swap execute
  • CG/CMC ticker orientation
  1. Introduce a display orientation flag per selected pair (factory | inverted), defaulting to inverted iff asset_0 is UST1 and asset_1 is not.
  2. Render a compact pair pill {displayBase}/{displayQuote} (e.g. cUSTC/UST1) in the chart header next to Price (USD). Click toggles orientation. Same toggle from a swap icon beside the ticket heading Buy {displayBase}.
  3. Remove the Order ticket eyebrow. Heading + invert is enough.
  4. When inverted:
    • Headline / candles / Last = USD of 1 display base (cUSTC or USTR), via quote catalog or price_usd / human_quote_per_base.
    • OHLC = reciprocal of factory USD series; swap high ↔ low; drop non-finite.
    • Ticket Buy cUSTC maps to factory ask (sell UST1 / buy quote) when UST1 is asset_0. Buy UST1 maps to factory bid.
    • Limit typed price is display quote per display base; convert to factory token1/token0 at gate + submit. Crossing preflight and % chips use the same space as the typed field.
    • Escrow token still follows factory bid/ask after mapping (#155).
  5. Persist invert per pairAddr in sessionStorage (or localStorage) so refresh keeps the user’s last choice; first visit uses the UST1 default.
  6. Keep LimitOrderSideFlipButton as bid/ask of the displayed base (Pay ↔ Receive).

Acceptance criteria

  • AC1 — UST1 default. Opening /trade on UST1/cUSTC or UST1/USTR (UST1 = asset_0) shows pair pill cUSTC/UST1 or USTR/UST1, Price (USD) / Last / candles ≈ USD of 1 cUSTC or 1 USTR (not ~$1 UST1), and ticket heading Buy cUSTC / Buy USTR.
  • AC2 — Pair pill invert. Clicking the pair pill swaps the label (UST1/cUSTC), chart + Last to USD of 1 UST1 (~$1), and ticket heading to Buy UST1. Second click restores AC1. Combobox still opens pair search and does not invert.
  • AC3 — Ticket invert icon. Swap control next to Buy {token} performs the same orientation toggle as the pill (one state). Visible focus + aria-label. Not the existing bid/ask flip.
  • AC4 — No Order ticket. The uppercase Order ticket / ORDER TICKET string is gone from /trade (desktop + sub-lg).
  • AC5 — Buy/Sell still works. Radiogroup remains Buy {displayBase} / Sell {displayBase} and still maps to factory bid/ask after orientation. Escrow pay/receive tokens stay correct.
  • AC6 — Submit correctness. Market quote/swap and limit place/update-price broadcast factory amounts and token1/token0 prices. Book Edit → ticket does not place at 1/P. Crossing gate uses one orientation end-to-end.
  • AC7 — Non-UST1 pairs. Default factory orientation. Pill + ticket icon still invert. No UST1-only dead-end.
  • AC8 — UST1 already quote. If UST1 is asset_1, default is factory (other token already base).
  • AC9 — Pair switch / /charts. Invert does not leak across pair addresses. /charts UST1 pairs use the same default + pill.
  • AC10 — Docs/skills. docs/frontend.md + listed skills record invert as UI-only and the convert-on-submit rule.
  • AC11 — A11y. Pill and icon are keyboard-reachable; axe on /trade + /charts stays clean (#214). Chart aria-live summary names the displayed token, not a stale UST1 price.

Test plan — functional paths

Unit / Vitest

  1. Default invert helper — UST1/cUSTC, UST1/USTR, UST1/vFDUSD → inverted; cUSTC/UST1 (UST1 already quote) → not inverted; CL8Y/cLUNC → not inverted; both legs UST1 or unknown → not inverted; symbol custc must not match UST1.
  2. USD invert — factory price_usd ≈ 1, human price ≈ 206 cUSTC/UST1 → displayed USD ≈ 1/206 (or catalog USTC). Inverted-back equals factory price_usd within float tolerance. Missing price_usd uses existing resolveTapeLastPriceUsd fallback then invert.
  3. OHLC invert — {o,h,l,c} → {1/o, 1/l, 1/h, 1/c} (high/low swap). 0, NaN, Infinity dropped.
  4. Side mapping — UST1=asset_0, inverted, display Buy → factory ask; display Sell → factory bid. Non-inverted: Buy → bid.
  5. Price convert — display 0.00485 UST1 per cUSTC → factory token1/token0 ≈ 206.2. Reverse convert for book prefill.
  6. Ticket chrome — no Order ticket text; heading Buy cUSTC; invert data-testid present.
  7. PairSearchSelect — click/focus still opens listbox; invert testid is a different node.
  8. Pair switch — invert pair A, select pair B → B uses B’s default, not A’s flag.
  9. Existing regressions — #152 tabs, #500 sticky CTA, #178 book Edit, #154/#155 gates, #412 Buy/Sell verbs, #226 stale candles, #151 non-negative scale, #522 never pass raw trades[].price as USD.

Integration / Playwright

  1. /trade/{UST1-cUSTC}: pill cUSTC/UST1 (or CUSTC/UST1), Last not ≈ 1.00 when USTC oracle is ~0.005; ticket Buy matches pill base.
  2. Click pill → Last ≈ 1; heading Buy UST1; click again restores.
  3. Click ticket invert icon → same as (11); pill and heading stay in sync.
  4. Limit: inverted Buy cUSTC, type a display price, place (sim wallet) → on-chain/indexer price is factory quote-per-base, not the display reciprocal.
  5. Market: inverted Buy cUSTC quotes paying UST1 / receiving cUSTC (factory ask path).
  6. Book Edit on inverted view prefills a display price that re-submits as the original factory price.
  7. Non-UST1 pair: default factory labels; invert still works.
  8. Sub-lg and desktop workspaces both hide Order ticket and show one invert icon (single ticket mount, #178).
  9. /charts UST1 pair: same default + pill.
  10. Pair search: type + select another pair still works after invert clicks.
  11. Keyboard: Tab to pill and icon, Enter/Space toggles; screen-reader name includes both symbols.

Manual / LocalTerra

  1. make has-localterra / make setup-cloud-localterra if needed. Seed or use existing UST1-like pair.
  2. Hard reload /trade/:pair — UST1 default holds; after invert + reload, persisted choice holds.
  3. Disconnect + connect wallet — invert state unchanged; blacklist/pause gates still block CTA.

Test plan — attack, hack, and abuse

Treat invert as a trust-boundary transform. A bug here is equivalent to signing the wrong price.

ID Vector Expected defense How to test
H1 Submit display reciprocal as factory token1/token0 (order at 1/P, taker/maker grief or self-drain) Convert in one helper used by place, update-price, market simulate/swap, and book Edit. Unit tests with mixed 6/18 decimals (UST1/USTR). Vitest + one sim-wallet limit place; indexer fill/placement price ≠ display string
H2 Crossing preflight in factory space while user types display space (false allow → crossing book walk / unexpected fill) Gate compares apples-to-apples; document which space. Bid that is safe in display space but crossing in factory must still block
H3 Escrow USD / headline USD uses factory UST1 $1 while user buys cUSTC (size confusion) Escrow USD follows display notional or clearly the pay token; never label UST1 $1 as the cUSTC price #155 helper tests with invert on
H4 Stale invert after pair switch / fast click (chart A + ticket B) State keyed by pairAddr; chart key includes orientation or remaps in render TradePage test: switch pair mid-invert
H5 Reciprocal of dust/0/1e-18 → Infinity candles or Y-axis explode Drop non-finite; keep #151 clamp priceChartCandles invert cases
H6 Spoofed indexer symbol UST1 / Ust1 / cUST1 forces invert on a random pair Prefer contract allowlist when known; symbol match exact UST1 after trim/casefold only Helper tests
H7 XSS / HTML in pair symbol rendered in pill or aria-label React text nodes only; no dangerouslySetInnerHTML Render symbol <img onerror=…>
H8 Invert during in-flight market quote then submit (quote for Buy cUSTC, broadcast Buy UST1) Submit path re-derives factory side + amounts from current orientation + pay raw; existing #501 submit-align asserts still hold Race: toggle invert after quote, before click
H9 Book row Edit while inverted writes inverted price into LimitBookTicketDraft without convert Draft stays factory; UI converts at the edge #178 test with invert=true
H10 Deep-link share: Alice inverted, Bob opens same /trade/:addr and thinks Last is UST1 Default is product default (other-side for UST1), not Alice’s storage. Optional ?inv= only if documented; never required Two browsers / cleared storage
H11 Cognitive / phishing copy: invert marketed as mint/redeem or “unwrap to USTC” U1 copy assertions (ust1SecondaryMarket.ts) String tests
H12 Blacklist / pause bypass by flipping orientation useTradingBlacklist + pause still keyed by pair contract, not display symbols Existing blacklist tests + invert toggle
H13 /limits or CSV export accidentally emit inverted prices as if factory Out of scope must not regress; if helper is shared, export stays factory Grep + existing history tests

Verification criteria

Close only when all of the following are true:

  1. AC1–AC11 checked on columbus-5 UST1/cUSTC + UST1/USTR or LocalTerra stand-ins with UST1 as asset_0.
  2. make test-frontend (or scoped Vitest listed above) green, including new invert helper tests and no #522 raw-price-as-USD regression.
  3. Playwright smoke: /trade UST1 default + pill toggle + ticket icon sync; pair search still opens; a11y critical routes pass.
  4. One on-chain or sim-wallet proof that an inverted Buy {other} limit/market does not submit 1/P as factory price (tx + indexer row or mocked placeLimitOrder args).
  5. docs/frontend.md section exists; skills updated; make verify-issue-NNN (or documented equivalent) added and run.
  6. Reviewer can open /trade on UST1/cUSTC and see cUSTC dollars on the chart without opening DevTools.

Labels / owner

  • Area: frontend (indexer unchanged)
  • Type: enhancement + UX + correctness
  • Owner: frontend
  • Priority: P1 (priority::medium) — live UST1 markets already show a correct-but-wrong-token ~$1 chart
## Summary On `/trade`, UST1 pairs (UST1/cUSTC, UST1/USTR, and any future UST1/* factory pair) currently chart and headline **Price (USD)** as the USD of **1 UST1** (~$1 after [#522](https://gitlab.com/PlasticDigits/cl8y-dex-terraclassic/-/issues/522)). Traders opening those markets need the **other token’s** USD price by default (cUSTC or USTR), a **pair-orientation pill** that inverts pricing on click, and a ticket heading that drops the unused **Order ticket** eyebrow in favor of **Buy {token}** plus a **swap/invert** control that flips which token is being bought. This is one product surface: **display + ticket orientation**. Do not split into separate issues. Related: [#522](https://gitlab.com/PlasticDigits/cl8y-dex-terraclassic/-/issues/522) (USD of factory `asset_0`), [#466](https://gitlab.com/PlasticDigits/cl8y-dex-terraclassic/-/issues/466) (indexer quote-per-base), [#508](https://gitlab.com/PlasticDigits/cl8y-dex-terraclassic/-/issues/508) (UST1 secondary AMM), [#489](https://gitlab.com/PlasticDigits/cl8y-dex-terraclassic/-/issues/489) / [#412](https://gitlab.com/PlasticDigits/cl8y-dex-terraclassic/-/issues/412) (Buy {base} copy), [#154](https://gitlab.com/PlasticDigits/cl8y-dex-terraclassic/-/issues/154) / [#155](https://gitlab.com/PlasticDigits/cl8y-dex-terraclassic/-/issues/155) (limit price + escrow USD), [#151](https://gitlab.com/PlasticDigits/cl8y-dex-terraclassic/-/issues/151) (non-negative USD scale). ## Current codebase Factory pairs store a fixed **base/quote** (`asset_0` / `asset_1`). Indexer and UI treat that as canonical: | Layer | Behavior today | |-------|----------------| | Factory / pair wasm | `create_pair` keeps caller `asset_infos` order. UST1 secondary scripts pass **UST1 first**, so columbus-5 UST1/cUSTC and UST1/USTR have **UST1 = `asset_0`**. | | Indexer [#466](https://gitlab.com/PlasticDigits/cl8y-dex-terraclassic/-/issues/466) / [#522](https://gitlab.com/PlasticDigits/cl8y-dex-terraclassic/-/issues/522) | `swap_events.price` = human **quote per base**. `price_usd` = USD of **1 human `asset_0`**. Candles OHLC use `COALESCE(price_usd, price)`. Quote catalog: UST1=`$1`, cUSTC=#515 USTC, USTR=`2.5×` USTC. | | `/trade` chart | `TradePage` → `resolveTapeLastPriceUsd` → `PriceChart` **Price (USD)** + **Last** headline. For UST1-as-base pairs this is **~$1**, not the cUSTC/USTR print traders care about. | | Pair chrome | `PairSearchSelect` / `pairInfoMenuLabel` always render `asset_0 / asset_1` (e.g. `UST1 / cUSTC`). The closed control is a search combobox — click opens search, it does **not** invert. There is no pair-orientation pill. | | Order ticket | `TradeOrderTicket` eyebrow **Order ticket** + heading **Buy {token0}** / **Sell {token0}** via `tradeDirectionSideLabels(token0)`. Bid = buy factory base (pay quote); ask = sell factory base. `LimitOrderSideFlipButton` already flips **bid ↔ ask**, not pair orientation. | | Limit / market submit | Prices and sides are factory `token1/token0`. Book **Edit** prefills that same convention ([#178](https://gitlab.com/PlasticDigits/cl8y-dex-terraclassic/-/issues/178)). Crossing preflight compares typed factory price to book head ([#154](https://gitlab.com/PlasticDigits/cl8y-dex-terraclassic/-/issues/154)). | | `/charts` | Same `PriceChart` + `resolveTapeLastPriceUsd` — UST1 pairs also show ~$1. | **Live pairs (columbus-5):** | Pair | Address | |------|---------| | UST1/cUSTC | `terra1ceprjsxp86ggftf5e38wwt34l83e5gq7penkdnv4wsatkwcs8v6qccw55f` | | UST1/USTR | `terra16vxrhpvpcucu05y0nr862vf9hnqeh274uaff4s7hz4n0ea74006qf5hgqy` | ## Why this is needed After [#522](https://gitlab.com/PlasticDigits/cl8y-dex-terraclassic/-/issues/522), the chart is **correct** as “USD of 1 UST1” and useless as a trading chart: UST1 is the $1 peg unit. Retail flow for these markets is “what is cUSTC (or USTR) worth?” — the **other side**. Without a first-class invert: 1. Traders misread a flat ~$1 candle as the market they came to trade. 2. Ticket **Buy UST1** is the opposite of the usual intent on a UST1-quoted pair (buy the floating token, pay UST1). 3. **Order ticket** is leftover chrome ([#489](https://gitlab.com/PlasticDigits/cl8y-dex-terraclassic/-/issues/489) cognitive-load rule: labels ≤ ~5 words; silence over instructional fluff). ## Constraints / guardrails 1. **Indexer and CG/CMC stay factory-oriented.** Do not change `#466` / `#522` `price` / `price_usd`, candle storage, or aggregator `last_price`. Invert is a **frontend display** of the same series (reciprocal + high/low swap). 2. **On-chain messages stay factory-oriented.** `place_limit_order` price is still **token1 per token0**. Market swap still buys/sells factory base vs quote. Display invert must **convert** before simulate/submit and when applying book **Edit** prefills. 3. **Do not reuse `LimitOrderSideFlipButton` as pair invert.** Bid/ask (Buy/Sell the *displayed* base) and pair invert (which token *is* the displayed base) are different. Keep the existing radiogroup ([#153](https://gitlab.com/PlasticDigits/cl8y-dex-terraclassic/-/issues/153) / [#412](https://gitlab.com/PlasticDigits/cl8y-dex-terraclassic/-/issues/412)). 4. **Do not steal `PairSearchSelect` click.** Combobox click/focus must still open pair search ([#181](https://gitlab.com/PlasticDigits/cl8y-dex-terraclassic/-/issues/181), [#180](https://gitlab.com/PlasticDigits/cl8y-dex-terraclassic/-/issues/180)). Pair invert is a **separate pill** (chart header and/or ticket). Selected-pair *label text* may follow display order (`cUSTC / UST1`). 5. **UST1 default only when factory base is UST1.** If UST1 is already `asset_1`, factory orientation already shows the other token — do not invert by default. Detect UST1 by **symbol `UST1` (case-insensitive) and/or known mainnet/local contract**, not a substring that matches `cUSTC`. 6. **Reciprocal safety.** Drop or refuse invert of a candle/tape print when price ≤ 0 or not finite. After invert, **high/low swap**. Y-axis remains non-negative ([#151](https://gitlab.com/PlasticDigits/cl8y-dex-terraclassic/-/issues/151)). Never pass `Infinity` / `NaN` into lightweight-charts ([#226](https://gitlab.com/PlasticDigits/cl8y-dex-terraclassic/-/issues/226)). 7. **One orientation state** for chart headline, candle series, pair pill, ticket **Buy {token}**, Buy/Sell labels, limit “When 1 {token} is worth”, and (if book prices are inverted for display) book column titles. Do not let chart and ticket disagree. 8. **Pair switch clears or re-keys invert.** Stale invert from pair A must not apply to pair B ([#180](https://gitlab.com/PlasticDigits/cl8y-dex-terraclassic/-/issues/180) / [#226](https://gitlab.com/PlasticDigits/cl8y-dex-terraclassic/-/issues/226)). Persist per `pairAddr` if you persist at all. 9. **Route unchanged.** `/trade/:pairAddr` still identifies the factory pair. Do not invent a second pair contract or swap `asset_infos` on chain. 10. **Copy.** No `token0` / `token1` / `bid` / `ask` in retail chrome. No “ORDER TICKET”. Invert control needs an `aria-label` (e.g. `Show UST1 / cUSTC pricing`). Keep U1: never describe AMM invert as mint/redeem ([#508](https://gitlab.com/PlasticDigits/cl8y-dex-terraclassic/-/issues/508)). 11. **`/limits` standalone** is out of scope unless it shares the new helper; do not silently invert limit prices there without the same convert-on-submit rule. 12. **`/charts`** should use the **same default + pill** on `PriceChart` so UST1 pairs are not ~$1 there either. Ticket chrome is `/trade` only. ## Relevant files **Must touch** - `frontend-dapp/src/pages/TradePage.tsx` — orientation state; pass invert into chart + ticket; pair-pill placement - `frontend-dapp/src/components/trade/TradeOrderTicket.tsx` — remove **Order ticket**; **Buy {displayBase}** + invert icon; map display side ↔ factory `bid`/`ask` - `frontend-dapp/src/components/charts/PriceChart.tsx` — pair pill + inverted headline/series - `frontend-dapp/src/components/charts/priceChartCandles.ts` / `chartHeadlinePrice.ts` — reciprocal OHLC + finite drop - `frontend-dapp/src/utils/pairPriceUsd.ts` — USD of displayed base (factory `price_usd` or `price_usd / human_price` / quote catalog) - `frontend-dapp/src/utils/tradeDirectionSideLabels.ts` — labels follow **display** base - `frontend-dapp/src/utils/pairMenuOptions.ts` — optional display-order labels - `frontend-dapp/src/components/trade/PairSearchSelect.tsx` — selected label may follow display order; **do not** invert on combobox click - `frontend-dapp/src/utils/limitOrderPriceReference.ts` — display rate vs factory `token1/token0` convert - `frontend-dapp/src/components/trade/LimitOrderPriceField.tsx` — “When 1 {displayBase} is worth” - `frontend-dapp/src/components/trade/TradeMarketOrderPanel.tsx` — pay/receive + quote/submit follow factory side after mapping - `frontend-dapp/src/components/trade/OrderBookPanel.tsx` — if book prices follow invert, convert Edit prefill back - `frontend-dapp/src/pages/ChartsPage.tsx` — same default + pill - `docs/frontend.md` — new invariants section - `skills/AGENTS_FRONTEND_PRICE_CHART.md`, `skills/AGENTS_FRONTEND_TRADE_PAGE_LAYOUT.md`, `skills/AGENTS_INDEXER_PAIR_PRICE_USD.md` (UI invert note; indexer math unchanged) **New helper (recommended)** - `frontend-dapp/src/utils/tradePairDisplayOrientation.ts` (name flexible) — `isUst1Leg`, `defaultInverted`, `displayAssets`, `invertUsd`, `invertOhlc`, `displayPriceToFactoryToken1PerToken0`, `factorySideFromDisplay` **Tests / QA** - `frontend-dapp/src/pages/TradePage.test.tsx` - `frontend-dapp/src/components/charts/__tests__/PriceChart.test.tsx` - `frontend-dapp/src/utils/__tests__/pairPriceUsd.test.ts` - `frontend-dapp/src/utils/__tests__/tradeDirectionSideLabels.test.ts` - `frontend-dapp/e2e/trade-page-responsive.spec.ts` / price-chart smoke - New `scripts/qa/verify-issue-NNN.sh` + `make verify-issue-NNN` **Do not change for this issue** - `indexer/src/indexer/swap_orientation.rs`, `pair_price_usd.rs`, candle migrations - Pair wasm `place_limit_order` / swap execute - CG/CMC ticker orientation ## Recommended direction 1. Introduce a **display orientation** flag per selected pair (`factory` | `inverted`), defaulting to **inverted iff `asset_0` is UST1 and `asset_1` is not**. 2. Render a compact **pair pill** `{displayBase}/{displayQuote}` (e.g. `cUSTC/UST1`) in the chart header next to **Price (USD)**. Click toggles orientation. Same toggle from a **swap icon** beside the ticket heading **Buy {displayBase}**. 3. Remove the **Order ticket** eyebrow. Heading + invert is enough. 4. When inverted: - Headline / candles / Last = USD of **1 display base** (cUSTC or USTR), via quote catalog or `price_usd / human_quote_per_base`. - OHLC = reciprocal of factory USD series; swap high ↔ low; drop non-finite. - Ticket **Buy cUSTC** maps to factory **ask** (sell UST1 / buy quote) when UST1 is `asset_0`. **Buy UST1** maps to factory **bid**. - Limit typed price is **display quote per display base**; convert to factory `token1/token0` at gate + submit. Crossing preflight and % chips use the **same** space as the typed field. - Escrow token still follows **factory** bid/ask after mapping ([#155](https://gitlab.com/PlasticDigits/cl8y-dex-terraclassic/-/issues/155)). 5. Persist invert per `pairAddr` in `sessionStorage` (or `localStorage`) so refresh keeps the user’s last choice; first visit uses the UST1 default. 6. Keep `LimitOrderSideFlipButton` as bid/ask of the displayed base (Pay ↔ Receive). ## Acceptance criteria - [ ] **AC1 — UST1 default.** Opening `/trade` on UST1/cUSTC or UST1/USTR (UST1 = `asset_0`) shows pair pill `cUSTC/UST1` or `USTR/UST1`, **Price (USD)** / Last / candles ≈ USD of 1 cUSTC or 1 USTR (not ~$1 UST1), and ticket heading **Buy cUSTC** / **Buy USTR**. - [ ] **AC2 — Pair pill invert.** Clicking the pair pill swaps the label (`UST1/cUSTC`), chart + Last to USD of 1 UST1 (~$1), and ticket heading to **Buy UST1**. Second click restores AC1. Combobox still opens pair search and does not invert. - [ ] **AC3 — Ticket invert icon.** Swap control next to **Buy {token}** performs the **same** orientation toggle as the pill (one state). Visible focus + `aria-label`. Not the existing bid/ask flip. - [ ] **AC4 — No Order ticket.** The uppercase **Order ticket** / **ORDER TICKET** string is gone from `/trade` (desktop + sub-`lg`). - [ ] **AC5 — Buy/Sell still works.** Radiogroup remains **Buy {displayBase}** / **Sell {displayBase}** and still maps to factory bid/ask after orientation. Escrow pay/receive tokens stay correct. - [ ] **AC6 — Submit correctness.** Market quote/swap and limit place/update-price broadcast **factory** amounts and `token1/token0` prices. Book Edit → ticket does not place at `1/P`. Crossing gate uses one orientation end-to-end. - [ ] **AC7 — Non-UST1 pairs.** Default factory orientation. Pill + ticket icon still invert. No UST1-only dead-end. - [ ] **AC8 — UST1 already quote.** If UST1 is `asset_1`, default is factory (other token already base). - [ ] **AC9 — Pair switch / `/charts`.** Invert does not leak across pair addresses. `/charts` UST1 pairs use the same default + pill. - [ ] **AC10 — Docs/skills.** `docs/frontend.md` + listed skills record invert as UI-only and the convert-on-submit rule. - [ ] **AC11 — A11y.** Pill and icon are keyboard-reachable; axe on `/trade` + `/charts` stays clean ([#214](https://gitlab.com/PlasticDigits/cl8y-dex-terraclassic/-/issues/214)). Chart `aria-live` summary names the displayed token, not a stale UST1 price. ## Test plan — functional paths ### Unit / Vitest 1. **Default invert helper** — UST1/`cUSTC`, UST1/`USTR`, UST1/`vFDUSD` → inverted; `cUSTC`/UST1 (UST1 already quote) → not inverted; `CL8Y`/`cLUNC` → not inverted; both legs UST1 or unknown → not inverted; symbol `custc` must not match UST1. 2. **USD invert** — factory `price_usd` ≈ 1, human price ≈ 206 cUSTC/UST1 → displayed USD ≈ `1/206` (or catalog USTC). Inverted-back equals factory `price_usd` within float tolerance. Missing `price_usd` uses existing `resolveTapeLastPriceUsd` fallback then invert. 3. **OHLC invert** — `{o,h,l,c}` → `{1/o, 1/l, 1/h, 1/c}` (high/low swap). `0`, `NaN`, `Infinity` dropped. 4. **Side mapping** — UST1=`asset_0`, inverted, display Buy → factory `ask`; display Sell → factory `bid`. Non-inverted: Buy → `bid`. 5. **Price convert** — display `0.00485` UST1 per cUSTC → factory `token1/token0` ≈ `206.2`. Reverse convert for book prefill. 6. **Ticket chrome** — no `Order ticket` text; heading `Buy cUSTC`; invert `data-testid` present. 7. **PairSearchSelect** — click/focus still opens listbox; invert testid is a different node. 8. **Pair switch** — invert pair A, select pair B → B uses B’s default, not A’s flag. 9. **Existing regressions** — `#152` tabs, `#500` sticky CTA, `#178` book Edit, `#154`/`#155` gates, `#412` Buy/Sell verbs, `#226` stale candles, `#151` non-negative scale, `#522` never pass raw `trades[].price` as USD. ### Integration / Playwright 10. `/trade/{UST1-cUSTC}`: pill `cUSTC/UST1` (or `CUSTC/UST1`), Last not ≈ `1.00` when USTC oracle is ~0.005; ticket **Buy** matches pill base. 11. Click pill → Last ≈ `1`; heading **Buy UST1**; click again restores. 12. Click ticket invert icon → same as (11); pill and heading stay in sync. 13. Limit: inverted Buy cUSTC, type a display price, place (sim wallet) → on-chain/indexer price is factory quote-per-base, not the display reciprocal. 14. Market: inverted Buy cUSTC quotes **paying UST1** / receiving cUSTC (factory ask path). 15. Book Edit on inverted view prefills a display price that re-submits as the original factory price. 16. Non-UST1 pair: default factory labels; invert still works. 17. Sub-`lg` and desktop workspaces both hide **Order ticket** and show one invert icon (single ticket mount, [#178](https://gitlab.com/PlasticDigits/cl8y-dex-terraclassic/-/issues/178)). 18. `/charts` UST1 pair: same default + pill. 19. Pair search: type + select another pair still works after invert clicks. 20. Keyboard: Tab to pill and icon, Enter/Space toggles; screen-reader name includes both symbols. ### Manual / LocalTerra 21. `make has-localterra` / `make setup-cloud-localterra` if needed. Seed or use existing UST1-like pair. 22. Hard reload `/trade/:pair` — UST1 default holds; after invert + reload, persisted choice holds. 23. Disconnect + connect wallet — invert state unchanged; blacklist/pause gates still block CTA. ## Test plan — attack, hack, and abuse Treat invert as a **trust-boundary transform**. A bug here is equivalent to signing the wrong price. | ID | Vector | Expected defense | How to test | |----|--------|------------------|-------------| | **H1** | Submit display reciprocal as factory `token1/token0` (order at `1/P`, taker/maker grief or self-drain) | Convert in one helper used by place, update-price, market simulate/swap, and book Edit. Unit tests with mixed 6/18 decimals (UST1/USTR). | Vitest + one sim-wallet limit place; indexer fill/placement price ≠ display string | | **H2** | Crossing preflight in factory space while user types display space (false allow → crossing book walk / unexpected fill) | Gate compares apples-to-apples; document which space. | Bid that is safe in display space but crossing in factory must still block | | **H3** | Escrow USD / headline USD uses factory UST1 $1 while user buys cUSTC (size confusion) | Escrow USD follows **display** notional or clearly the pay token; never label UST1 $1 as the cUSTC price | `#155` helper tests with invert on | | **H4** | Stale invert after pair switch / fast click (chart A + ticket B) | State keyed by `pairAddr`; chart `key` includes orientation or remaps in render | TradePage test: switch pair mid-invert | | **H5** | Reciprocal of dust/`0`/`1e-18` → `Infinity` candles or Y-axis explode | Drop non-finite; keep `#151` clamp | `priceChartCandles` invert cases | | **H6** | Spoofed indexer symbol `UST1` / `Ust1 ` / `cUST1` forces invert on a random pair | Prefer contract allowlist when known; symbol match exact `UST1` after trim/casefold only | Helper tests | | **H7** | XSS / HTML in pair symbol rendered in pill or `aria-label` | React text nodes only; no `dangerouslySetInnerHTML` | Render symbol `<img onerror=…>` | | **H8** | Invert during in-flight market quote then submit (quote for Buy cUSTC, broadcast Buy UST1) | Submit path re-derives factory side + amounts from **current** orientation + pay raw; existing `#501` submit-align asserts still hold | Race: toggle invert after quote, before click | | **H9** | Book row Edit while inverted writes inverted price into `LimitBookTicketDraft` without convert | Draft stays factory; UI converts at the edge | `#178` test with invert=true | | **H10** | Deep-link share: Alice inverted, Bob opens same `/trade/:addr` and thinks Last is UST1 | Default is product default (other-side for UST1), not Alice’s storage. Optional `?inv=` only if documented; never required | Two browsers / cleared storage | | **H11** | Cognitive / phishing copy: invert marketed as mint/redeem or “unwrap to USTC” | U1 copy assertions (`ust1SecondaryMarket.ts`) | String tests | | **H12** | Blacklist / pause bypass by flipping orientation | `useTradingBlacklist` + pause still keyed by **pair contract**, not display symbols | Existing blacklist tests + invert toggle | | **H13** | `/limits` or CSV export accidentally emit inverted prices as if factory | Out of scope must not regress; if helper is shared, export stays factory | Grep + existing history tests | ## Verification criteria Close only when **all** of the following are true: 1. AC1–AC11 checked on columbus-5 UST1/cUSTC + UST1/USTR **or** LocalTerra stand-ins with UST1 as `asset_0`. 2. `make test-frontend` (or scoped Vitest listed above) green, including new invert helper tests and no `#522` raw-price-as-USD regression. 3. Playwright smoke: `/trade` UST1 default + pill toggle + ticket icon sync; pair search still opens; a11y critical routes pass. 4. One **on-chain or sim-wallet** proof that an inverted **Buy {other}** limit/market does **not** submit `1/P` as factory price (tx + indexer row or mocked `placeLimitOrder` args). 5. `docs/frontend.md` section exists; skills updated; `make verify-issue-NNN` (or documented equivalent) added and run. 6. Reviewer can open `/trade` on UST1/cUSTC and see **cUSTC** dollars on the chart without opening DevTools. ## Labels / owner - Area: **frontend** (indexer unchanged) - Type: **enhancement** + **UX** + **correctness** - Owner: frontend - Priority: **P1** (`priority::medium`) — live UST1 markets already show a correct-but-wrong-token ~$1 chart
PlasticDigits commented 2026-08-15 12:19:48 +00:00 (Migrated from gitlab.com)

marked as related to #522

marked as related to #522
PlasticDigits commented 2026-08-15 12:19:49 +00:00 (Migrated from gitlab.com)

marked as related to #508

marked as related to #508
PlasticDigits commented 2026-08-15 12:19:50 +00:00 (Migrated from gitlab.com)

marked as related to #489

marked as related to #489
PlasticDigits commented 2026-08-15 12:19:50 +00:00 (Migrated from gitlab.com)

marked as related to #412

marked as related to #412
PlasticDigits commented 2026-08-15 12:19:51 +00:00 (Migrated from gitlab.com)

marked as related to #466

marked as related to #466
PlasticDigits commented 2026-08-15 12:19:52 +00:00 (Migrated from gitlab.com)

marked as related to #154

marked as related to #154
PlasticDigits commented 2026-08-15 12:19:52 +00:00 (Migrated from gitlab.com)

marked as related to #155

marked as related to #155
PlasticDigits commented 2026-08-15 12:19:53 +00:00 (Migrated from gitlab.com)

marked as related to #151

marked as related to #151
PlasticDigits commented 2026-08-15 12:58:15 +00:00 (Migrated from gitlab.com)

mentioned in merge request !1057

mentioned in merge request !1057
PlasticDigits commented 2026-08-15 13:04:28 +00:00 (Migrated from gitlab.com)

MR !1057 merge review (no automerge, did not wait for CI)

Merge conflicts: none. feat/524-trade-ust1-pair-invert was already based on current main (887696c). Local git merge-tree was clean.

CI: pipeline 2762610231 failed gitleaks, test-frontend, and test-frontend-build with ci_quota_exceeded (jobs never started). Not a product test failure. Local make verify-issue-524 is green (9/9), including the H1 pill-price test added before merge.

H1 fix landed on the MR (96efefd): chart pill previously called toggleInverted without reciprocating the typed limit price; ticket icon did reciprocate. After a typed display price + pill toggle, submit could broadcast factory 1/P. Ticket now reciprocates on any same-pair orientation change (pill or icon).

AC vs !1057

AC Status
AC1 UST1 default Pass (Vitest TradePage + helper)
AC2 pair pill Pass
AC3 ticket invert icon Pass after H1 fix (shared state + shared price reciprocal)
AC4 no Order ticket Pass
AC5 Buy/Sell mapping Pass (code + helper tests)
AC6 submit correctness Pass on happy path + pill toggle after fix; no mocked placeLimitOrderWithAllowance spy / sim-wallet tx proof
AC7 non-UST1 invert Partial — default factory tested; click-to-invert on AAA/BBB not covered
AC8 UST1 already quote Pass at helper; no page-level test
AC9 pair switch /charts Partial — pair-switch isolation tested; no ChartsPage Vitest
AC10 docs/skills Pass
AC11 a11y Partial — buttons + aria-live covered; no new Playwright axe/keyboard on UST1 default

Still open vs issue close checklist

  1. Playwright smoke from the issue test plan (UST1 default, pill/icon, book Edit, /charts, keyboard) was not added.
  2. No on-chain / sim-wallet proof that inverted Buy {other} does not submit 1/P (verification item 4). TradeOrderTicket.invert.test.tsx still asserts helper math only.
  3. Targeted tests still missing for H2 (display-safe bid that is factory-crossing), H8 (invert during in-flight market quote), H9 (book Edit with invert on).
  4. Reviewer columbus-5 walkthrough (Last is cUSTC dollars, not ~$1) is still a human check.

Do not close #524 on merge alone until the remaining verification items above are done or explicitly waived.

## MR !1057 merge review (no automerge, did not wait for CI) **Merge conflicts:** none. `feat/524-trade-ust1-pair-invert` was already based on current `main` (`887696c`). Local `git merge-tree` was clean. **CI:** pipeline [2762610231](https://gitlab.com/PlasticDigits/cl8y-dex-terraclassic/-/pipelines/2762610231) failed `gitleaks`, `test-frontend`, and `test-frontend-build` with `ci_quota_exceeded` (jobs never started). Not a product test failure. Local `make verify-issue-524` is green (9/9), including the H1 pill-price test added before merge. **H1 fix landed on the MR** (`96efefd`): chart pill previously called `toggleInverted` without reciprocating the typed limit price; ticket icon did reciprocate. After a typed display price + pill toggle, submit could broadcast factory `1/P`. Ticket now reciprocates on any same-pair orientation change (pill or icon). ### AC vs !1057 | AC | Status | |----|--------| | AC1 UST1 default | Pass (Vitest TradePage + helper) | | AC2 pair pill | Pass | | AC3 ticket invert icon | Pass after H1 fix (shared state + shared price reciprocal) | | AC4 no Order ticket | Pass | | AC5 Buy/Sell mapping | Pass (code + helper tests) | | AC6 submit correctness | Pass on happy path + pill toggle after fix; no mocked `placeLimitOrderWithAllowance` spy / sim-wallet tx proof | | AC7 non-UST1 invert | Partial — default factory tested; click-to-invert on AAA/BBB not covered | | AC8 UST1 already quote | Pass at helper; no page-level test | | AC9 pair switch /charts | Partial — pair-switch isolation tested; no ChartsPage Vitest | | AC10 docs/skills | Pass | | AC11 a11y | Partial — buttons + aria-live covered; no new Playwright axe/keyboard on UST1 default | ### Still open vs issue close checklist 1. Playwright smoke from the issue test plan (UST1 default, pill/icon, book Edit, `/charts`, keyboard) was not added. 2. No on-chain / sim-wallet proof that inverted Buy {other} does not submit `1/P` (verification item 4). `TradeOrderTicket.invert.test.tsx` still asserts helper math only. 3. Targeted tests still missing for H2 (display-safe bid that is factory-crossing), H8 (invert during in-flight market quote), H9 (book Edit with invert on). 4. Reviewer columbus-5 walkthrough (Last is cUSTC dollars, not ~$1) is still a human check. Do not close #524 on merge alone until the remaining verification items above are done or explicitly waived.
PlasticDigits commented 2026-08-15 13:04:40 +00:00 (Migrated from gitlab.com)

mentioned in commit a0a75d5d61

mentioned in commit a0a75d5d6116f409bfe088263881c47703e900d0
PlasticDigits (Migrated from gitlab.com) closed this issue 2026-08-15 13:04:41 +00:00
PlasticDigits commented 2026-08-15 13:05:26 +00:00 (Migrated from gitlab.com)

GitLab auto-closed this issue via Closes #524 on merged !1057. Remaining gaps from the merge-review note still apply (Playwright smoke, sim-wallet/on-chain 1/P proof, H2/H8/H9 tests, columbus-5 Last-is-cUSTC walkthrough). Reopen if those are still required before calling #524 done.

GitLab auto-closed this issue via `Closes #524` on merged !1057. Remaining gaps from the merge-review note still apply (Playwright smoke, sim-wallet/on-chain 1/P proof, H2/H8/H9 tests, columbus-5 Last-is-cUSTC walkthrough). Reopen if those are still required before calling #524 done.
PlasticDigits commented 2026-08-15 13:18:35 +00:00 (Migrated from gitlab.com)

mentioned in issue #527

mentioned in issue #527
PlasticDigits commented 2026-08-15 21:45:48 +00:00 (Migrated from gitlab.com)

mentioned in issue #528

mentioned in issue #528
PlasticDigits commented 2026-08-16 07:14:04 +00:00 (Migrated from gitlab.com)

mentioned in issue #530

mentioned in issue #530
PlasticDigits commented 2026-08-17 03:45:39 +00:00 (Migrated from gitlab.com)

mentioned in issue #541

mentioned in issue #541
PlasticDigits commented 2026-08-17 03:51:34 +00:00 (Migrated from gitlab.com)

mentioned in issue #543

mentioned in issue #543
PlasticDigits commented 2026-08-17 03:51:35 +00:00 (Migrated from gitlab.com)

marked as related to #543

marked as related to #543
PlasticDigits commented 2026-08-17 03:52:29 +00:00 (Migrated from gitlab.com)

mentioned in issue #544

mentioned in issue #544
PlasticDigits commented 2026-08-17 04:13:12 +00:00 (Migrated from gitlab.com)

mentioned in commit 7dd968c4e1

mentioned in commit 7dd968c4e192549e19cc4f951a1f705469d7360f
PlasticDigits commented 2026-08-17 04:19:20 +00:00 (Migrated from gitlab.com)

mentioned in merge request !1070

mentioned in merge request !1070
PlasticDigits commented 2026-08-17 10:26:07 +00:00 (Migrated from gitlab.com)

mentioned in issue #547

mentioned in issue #547
PlasticDigits commented 2026-08-17 10:29:11 +00:00 (Migrated from gitlab.com)

mentioned in issue #548

mentioned in issue #548
PlasticDigits commented 2026-08-18 00:28:53 +00:00 (Migrated from gitlab.com)

mentioned in issue #556

mentioned in issue #556
PlasticDigits commented 2026-08-18 00:29:03 +00:00 (Migrated from gitlab.com)

mentioned in issue #557

mentioned in issue #557
PlasticDigits commented 2026-08-18 02:30:14 +00:00 (Migrated from gitlab.com)

mentioned in merge request !1083

mentioned in merge request !1083
PlasticDigits commented 2026-08-18 12:08:53 +00:00 (Migrated from gitlab.com)

mentioned in issue #561

mentioned in issue #561
PlasticDigits commented 2026-08-18 12:09:32 +00:00 (Migrated from gitlab.com)

mentioned in issue #563

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

mentioned in issue #564

mentioned in issue #564
PlasticDigits commented 2026-08-18 12:13:08 +00:00 (Migrated from gitlab.com)

mentioned in issue #565

mentioned in issue #565
PlasticDigits commented 2026-08-19 00:57:40 +00:00 (Migrated from gitlab.com)

mentioned in issue #568

mentioned in issue #568
PlasticDigits commented 2026-08-19 00:57:42 +00:00 (Migrated from gitlab.com)

marked as related to #568

marked as related to #568
PlasticDigits commented 2026-08-19 01:02:56 +00:00 (Migrated from gitlab.com)

mentioned in merge request !1089

mentioned in merge request !1089
PlasticDigits commented 2026-08-19 01:09:55 +00:00 (Migrated from gitlab.com)

mentioned in merge request !1092

mentioned in merge request !1092
PlasticDigits commented 2026-08-26 04:15:27 +00:00 (Migrated from gitlab.com)

mentioned in issue #664

mentioned in issue #664
PlasticDigits commented 2026-08-26 04:17:22 +00:00 (Migrated from gitlab.com)

mentioned in issue #666

mentioned in issue #666
PlasticDigits commented 2026-08-27 00:20:53 +00:00 (Migrated from gitlab.com)

mentioned in issue #680

mentioned in issue #680
PlasticDigits commented 2026-08-27 00:40:56 +00:00 (Migrated from gitlab.com)

mentioned in merge request !1183

mentioned in merge request !1183
PlasticDigits commented 2026-08-28 05:22:09 +00:00 (Migrated from gitlab.com)

mentioned in issue #692

mentioned in issue #692
PlasticDigits commented 2026-08-28 05:28:47 +00:00 (Migrated from gitlab.com)

mentioned in issue #693

mentioned in issue #693
PlasticDigits commented 2026-08-29 14:16:59 +00:00 (Migrated from gitlab.com)

mentioned in issue #705

mentioned in issue #705
PlasticDigits commented 2026-09-01 08:14:37 +00:00 (Migrated from gitlab.com)

mentioned in issue #717

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