feat(frontend): compact vs full number display in Settings #1259
Labels
No labels
agent:fix_bugfix
agent:fix_conflicts
agent:fix_security
agent:gap_analysis
agent:implement
agent:implement
agent:implement
agent:open_issues
agent:ready
agent:research
agent:security_audit
agent:verify
architecture
backend
blocker:hybrid
blocker:launch
blocker:limit-orders
blocker:v2
block:log_only
block:security
bug
ci
contracts
correctness
deploy
dev
devops
docs
documentation
duplicate
e2e
enhancement
epic
feature
frontend
functional-completion
gas
good first issue
governance
help wanted
high-risk
hooks
hybrid
indexer
infra
infrastructure
integrators
invalid
launch-blocker
limit-orders
localnet
localterra
low priority
missing-implementation
needs-design
ops
performance
priority
high
priority
medium
product
qa
QA
question
ready
ready
research
scripts
security
security-hardening
smartcontracts
tech-debt
testing
ux
UX
v2
verification
wontfix
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
code/cl8y-dex-terraclassic#1259
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Summary
Retail chrome hard-codes compact
K/M/B/TviaformatNum/formatTokenAmount/formatTokenAmountAbbrev. There is no Settings control to pick another display format. Traders who need full grouped digits (or who find compact suffixes misleading next to 18-decimal human amounts) have no supported switch.Bundle (do not split):
K/M/B/T.Do not reopen closed #46 (tiers-page consistency; verified with K/M remaining). Do not reopen closed #413 (hybrid/indexer Advanced disclosure). Those are not this ticket.
Swap Settings has no number-format control
Retail Settings (
#swap-slippage-settingsinSwapPage.tsx) is slippage presets, transaction deadline, and Expert Mode.SwapAdvancedSettings(#413) is hybrid book-leg override + indexer route debug. Neither exposes a display-format choice.swapSettingsAdvanced.tsonly persistscl8y-dex-swap-settings-advanced-open.Compact is the only chrome path
frontend-dapp/src/utils/formatAmount.ts:formatNumalways abbreviates at 1e3 / 1e6 / 1e9 / 1e12 with significant figures.formatTokenAmount/formatTokenAmountAbbrevhumanize withfromRawAmountthen compact.formatPairPriceis already non-compact (GitLab #522) — that exception stays.formatTokenAmountGrouped()existed for #46 then was withdrawn for/tiers; it is not onmain.Callers include Swap, Charts pair stats / overview, Pool vol/TVL, Protocol USD headlines (
formatProtocolStats.ts), Trade tape (tradeTapeDisplay.ts/ T557), Trader volume (#553), Tiers, Portfolio, wallet LUNC chip. There is no preference argument today.Execute and inputs are a different path
toRawAmount/fromRawAmountand amount<input>values must stay plain decimal strings. Display mode must not rewrite typed You Pay / book-leg / limit-price fields, and must not change simulate/execute JSON.Why the new implementation is needed
1,234,567.89without teaching them K/M/T.This is frontend chrome only. No contract migrate, no indexer JSON change, no Coolify env.
Constraints / guardrails
toRawAmount,fromRawAmount, quote/simulate/execute payloads, min-received raw, or walletMsgamounts. Mode is string rendering after humanize.isDecimalAmountDraft/fromRawAmount). Do not inject grouping commas into controlled inputs (W10-C4 / #169).SwapPreSubmitSummary, limit pre-submit, pool provide/withdraw summary): always Full grouped (orfromRawAmount+ grouping), never compact, regardless of Settings mode. Confirmation digits must match what will be signed.formatPairPricestays non-compact in both modes (#522 / T557-6 / P551-4). Spot, TWAP, limit avg-entry, tape Price: noT/B/M/Kfrom a raw ratio.formatNum(raw)on indexer integers (#534 / #540 / #553 / #557 / #564 / P565-2 / P534-4). Preference applies only after pair-leg /token_infodecimals (0…18). Unresolved decimals still—(do not guess 6). Do not expand #1255 here.PAIR_STATS_VOLUME_DISPLAY_CAP(24) and hostile-length /<>/ non-integer guards stay. Full grouped of an adversarial integer must still return—, not a megabyte text node. Do not raise the cap to “make grouped work.”navigator.language. That fights amount parsers (#169) and Vitest. No i18n library.?format=,?locale=,?compact=(#596: Settings execution prefs are not inbound query). PersistlocalStorageonly, same failure mode aswriteSwapSettingsAdvancedOpen(quota / private mode → Compact default).from/to/exactAmount). Display mode is not shareable.?showGems=1or reveal hidden ids in formatted strings.#swap-slippage-settingscard-glass. No newshell-panel*/ extracard-glass.python3 scripts/check_chrome_nesting.pystays green.1e-18into an input or broadcast.localStoragevalues (HTML,javascript:, unknown keys) → Compact. Text nodes only; nodangerouslySetInnerHTML; noeval.Relevant files
frontend-dapp/src/utils/formatAmount.tsformatNum/formatTokenAmount/formatTokenAmountAbbrev; add mode; keepformatPairPricenon-compactfrontend-dapp/src/utils/__tests__/formatAmount.test.tsfrontend-dapp/src/utils/numberDisplayPreference.ts(new)compact|fullenum;localStoragekey; read/write likeswapSettingsAdvanced.tsfrontend-dapp/src/utils/numberDisplayPreference.test.ts(new)frontend-dapp/src/pages/SwapPage.tsxfrontend-dapp/src/pages/SwapPage.test.tsxfrontend-dapp/src/utils/formatProtocolStats.tsfrontend-dapp/src/utils/tradeTapeDisplay.tsformatPairPricefrontend-dapp/src/utils/chartsPairStats.ts/chartsOverviewStats.tsdocs/frontend.mdskills/AGENTS_FRONTEND_CHROME_NESTING.mdA React context or tiny store is OK if
formatNumcannot readlocalStorageduring SSR; do not add a second formatter family. Prefer one dispatcher used byformatTokenAmountandformatProtocolUsd.Recommended direction
NumberDisplayMode = 'compact' | 'full'. Default'compact'(today’sformatNum). Key e.g.cl8y-dex-number-display-mode. Unknown stored values → compact.formatNum(val, sigfigs, mode?)and token helpers take an explicit mode or read the preference once per call.full:toLocaleString('en-US')after humanize, no suffix; BigInt-safe path for whole tokens aboveMAX_SAFE_INTEGER(reuseformatWholeTokensAbbrevinteger grouping without suffix).formatPairPriceignores mode.formatPairStatsVolumestill humanizes + length-cap; infullit groups instead of K/M, still—when over cap.#swap-slippage-settings(role="group",aria-label="Number display"),data-testid="swap-number-display-compact"/swap-number-display-full.sounds.playButtonPress. 44px hit target. Live preview of a fixture (e.g.1,234,567vs1.235M) as text, not a new card.setSearchParams.Acceptance criteria
13.23K,1.235M, …).K/M/B/Ton Swap balances / Receive chrome, Charts 24h Vol (after humanize),/poolVol USD, Protocol USD headlines, tape Amount in/out,/tiersCL8Y thresholds.formatPairPrice(no compactT) in both modes.1000.5stilltoRawAmounts the same raw.—.PAIR_STATS_VOLUME_DISPLAY_CAPstill fail-closes.shell-panel/ nestedcard-glass.check_chrome_nesting.pygreen.Test plan (functional paths)
formatNum(1234567, 4, 'full')1,234,567(or1,234,567.00only if tests pick a fixed-dp rule — prefer no trailing zeros for integers)formatPairPricewith mode fullTformatNum(raw)1000in You Pay under Full1000; raw10^(decimals)unchanged/tiersFull$+ grouped; non-finite still—make test-frontend+ existing verify-issue-522/553/557/564/565PLAYWRIGHT_SKIP_CHAIN=1OK)/Vitest: table-driven
formatNum/formatTokenAmount/ preference parser. RTL: Settings chips + persistence mock. 5 workers.Test plan (attack, hack, and abuse)
Display-only; not a DeFi drain suite. Still isolate money chrome from execute.
localStoragevalue<img>/javascript:?format=full/?compact=0on/—(cap / bigint guards); tab stays responsiveBigIntthrow (#169)Verification criteria
make verify-issue-*greps: Compact default, Full grouped helper, Settings testids,formatPairPriceignores mode, noformatNum(raw)regressions, chrome nesting script green.make test-frontendincludes preference + formatAmount tables.make dev→ Settings → Full → Charts / Pool / Protocol / Trade tape still priced correctly; flip back to Compact; Expert Mode still blocks >30% route slippage.Out of scope
navigator.language.SwapAdvancedSettings(integrator dump).First-pass model recommendation
Recommendation: grok-high
Rationale: Display-only and low/medium product risk, but it is a cross-cutting chrome preference:
formatNum/formatTokenAmountfeed Swap, Charts, Pool, Protocol, Trade tape, Trader, Tiers, and Portfolio. A correct pass must keepformatPairPricenon-compact, confirmation summaries full, inputs ungrouped, and volume length-caps fail-closed. That exceeds a local three-file edit in one subsystem and is not a known isolated helper change. Verification is the existing formatAmount / Charts / tape suites plus Settings persistence — deterministic, but the blast radius is dApp-wide. Composer’s first-pass bar fails on file/subsystem count and cross-cutting display state.+1 Compact (K/M/B/T, e.g. 9.12K) remains the first-visit default; Full grouped stays opt-in via retail Settings.