fix: /pool Manage provide uses token name (symbol) and defaults auto-wrap on #661

Closed
opened 2026-08-26 04:12:47 +00:00 by PlasticDigits · 7 comments
PlasticDigits commented 2026-08-26 04:12:47 +00:00 (Migrated from gitlab.com)

Summary

On /pool → Manage → Advanced, two-sided Provide Liquidity still labels the amount fields Asset A / Asset B (CSS uppercase paints them as ASSET A AMOUNT / ASSET B AMOUNT). Those fields must show the pair-leg name (symbol) instead. On wrap-equivalent legs (cLUNC / cUSTC), Use native … (auto-wrap) is unchecked (useState(false)). Auto-wrap must default on when a native equivalent exists.

Bundle labels + auto-wrap default in one issue. Same component, same tests, same wrap execute path. Do not split “rename the label” vs “flip the checkbox default.”

Related: #547 (Manage expand + Advanced), #533 (retail one-sided — out of scope), #630 (LUNC/USTC/cLUNC/cUSTC tickers), #489 (short labels), #480 (counterpart auto-fill), #147 (CW20 vs wrap gas), #512 / #516 (wrap fee net), #201 (wrap-pool E2E).

Current codebase

/pool retail add/withdraw is one-sided (OneSidedAddCard / OneSidedWithdrawCard). Two-sided provide/withdraw lives under table Manage → PoolAdvancedManage → <details data-testid="pool-card-advanced"> (Provide Liquidity / Withdraw Liquidity). LCD getPool / getPairFeeConfig run only on expand (P547-9 / A8).

Layer Behavior today
Provide labels PoolAdvancedManage.tsx hard-codes visible Asset A Amount / Asset B Amount plus a normal-case parenthetical ({displayA.displayLabel}). Inputs use aria-label="Asset A amount" / "Asset B amount". .label-glass is uppercase tracking-wide, so the user sees ASSET A AMOUNT (cLUNC).
Token identity already loaded Same file already calls useTokenDisplayInfo(pair.asset_infos[0|1]) (displayLabel + symbol). Registry product tickers beat indexer/on-chain text (N630-1–N630-4). tokenRegistry.ts also has name (Terra Luna Classic, Wrapped Luna Classic, …) but useTokenDisplayInfo does not expose name — displayLabel === symbol.
Auto-wrap default useNativeA / useNativeB initialize to false. Checkbox Use native {LUNC|USTC} (auto-wrap) renders only when getNativeEquivalent(tokenId) is set (cLUNC → uluna, cUSTC → uusd). Checked → balance query switches to native denom; execute is wrap_deposit + allowances + provide_liquidity (executeTerraContractMulti). Unchecked → CW20 balances + three sequential txs (gas gate #147).
Withdraw No Asset A/B amount fields. Expected receive / pre-sign already use displayA.displayLabel / native ticker when unwrap is on. receiveWrapped defaults true (keep wrapped). That is not the provide auto-wrap checkbox.
Retail one-sided No wrap checkbox (Z533-1). Native pick implies wrap. Do not change.
Counterpart / fees Empty counterpart auto-fills from pool ratio (#480). Wrap-on path uses net after mapper fee (provideRawAdd*). Max/50% forceSync. Empty pool: no auto-fill.
Wrap gates wrapProvideBlocked when mapper address set and config missing or treasury ≠ env. Pause / code-id freeze / blacklist still disable CTAs.
Tests that lock the old copy PoolPage.test.tsx uses getByLabelText('Asset A amount') / 'Asset B amount' throughout. e2e/pool.spec.ts and e2e/pool-lp-howto-531.spec.ts match /Asset A|Amount/i. e2e/wrap-pool.spec.ts E7 clicks auto-wrap to enable; E8 fills amounts without clicking (assumes wrap off). Those invert if the default flips.
Docs docs/frontend.md § pool still says “editing Asset A or B”. docs/design-system.md glossary: “Use native LUNC (auto-wrap)”. skills/AGENTS_FRONTEND_POOL_PROVIDE_WITHDRAW_PREVIEW.md same Asset A/B wording.

Why this is needed

  1. Retail cannot tell which token they are depositing. “ASSET A” is an implementation leftover (asset_infos[0]). #489 forbids token0 / generic slot names. The pair header already shows TokenDisplay symbols; the amount fields must match.
  2. The identity is already in memory. useTokenDisplayInfo + registry name/symbol exist. The UI ignores them and prints Asset A/B.
  3. Auto-wrap off is the wrong default for wrap pairs. Pools hold cLUNC / cUSTC. Typical LPs hold bank LUNC / USTC. An unchecked box makes them provide CW20 (or fail “exceeds wallet”) when the intended path is native + wrap in the same multi-msg. Retail one-sided already auto-wraps when the token is native; Advanced should not invert that.
  4. Leaving wrap off also mis-labels the spend. If wrap defaults on, the field must show LUNC / USTC (what leaves the wallet), not cLUNC with a hidden wrap. Today the label stays the pool CW20 even when the checkbox is checked.

Constraints / guardrails

  1. Frontend-only. No pair/router/mapper migrate. No fee-bps / treasury / mint math changes.
  2. Do not touch retail one-sided (OneSidedAddCard / OneSidedWithdrawCard). No wrap checkbox there (Z533-1 / Z533-2).
  3. Product tickers, not bank denoms. Visible text for uluna / uusd is LUNC / USTC; wrap CW20s stay cLUNC / cUSTC (N630-1–N630-2). Execute / React Query ids stay uluna / uusd / CW20 address (N630-3). Registry wins over indexer spoof (N630-4). Unknown natives fail closed as raw denom (N630-5).
  4. Label = selected input asset, not always the pool CW20. Wrap checked → native name (symbol) (LUNC). Wrap unchecked → pair-leg CW20 name (symbol) (cLUNC). Unchecking must switch label + balance + execute path immediately.
  5. NAME (SYMBOL) without redundancy or essays. Prefer {registry-or-indexer name} ({product symbol}) when name is distinct and short (≤ ~5 words, #489). Collapse to {symbol} when name is missing, equals the symbol, or is a long/HTML/spoofed indexer string. Never cLUNC (cLUNC). Never uluna / uusd as the visible name.
  6. .label-glass is uppercase. A raw cLUNC in that class becomes CLUNC. Keep tickers in a normal-case (or non-label-glass) node. Mixed-case product tickers must survive CSS.
  7. Auto-wrap default on only when getNativeEquivalent is non-null. Non-wrap pairs (UST1/USTR, CL8Y/UST1, gems) must not show the checkbox and must not take the wrap execute path.
  8. Default is on-mount, not persisted. No localStorage for wrap preference. Uncheck is session-only until remount.
  9. Do not flip withdraw receiveWrapped. Report is provide auto-wrap. Withdraw stays default receive wrapped unless a later issue says otherwise. Do not unwrap the rest of the wallet (Z533-8).
  10. Users who only hold CW20 must still provide. Default-on wrap can show native balance 0 / Exceeds wallet. Uncheck → CW20 balance + #147 gas gate. If mapper config is missing or treasury mismatches, wrapProvideBlocked must not trap the user — uncheck must restore the CW20 CTA (subject to other gates).
  11. Keep all existing safety gates: pause, code-id freeze, blacklist, clickwrap/NFA, wrap treasury match, IL notice, pre-sign summary (#462), counterpart ratio warning, Max gas reserve on native uluna.
  12. No N+1 LCD on default /pool paint (A8). Labels use data already on the expanded Manage instance (useTokenDisplayInfo / registry). Do not add per-row LCD for names.
  13. XSS / spoof: indexer name / symbol are text only. No dangerouslySetInnerHTML. Registry allowlist still wins for known natives/wraps.
  14. Do not add an always-on “uluna means LUNC” or wrap-architecture essay (#489).

Relevant files

File Role
frontend-dapp/src/components/pool/PoolAdvancedManage.tsx Labels, useNativeA/useNativeB defaults, aria-labels, wrap execute
frontend-dapp/src/hooks/useTokenDisplayInfo.ts Shared displayLabel / symbol; extend only if name is needed
frontend-dapp/src/utils/tokenRegistry.ts name + registryProductSymbol
frontend-dapp/src/utils/tokenDisplay.ts getTokenDisplaySymbol
frontend-dapp/src/types/index.ts getNativeEquivalent / WRAPPED_NATIVE_PAIRS
frontend-dapp/src/pages/PoolPage.test.tsx Vitest locked to Asset A amount
frontend-dapp/e2e/pool.spec.ts /Asset A|Amount/i
frontend-dapp/e2e/pool-lp-howto-531.spec.ts same
frontend-dapp/e2e/wrap-pool.spec.ts E7 click-to-enable / E8 assume wrap off
frontend-dapp/e2e/helpers/wrap-e2e.ts requirePoolCardWithNativeWrap
docs/frontend.md “Asset A or B” pool provide copy
docs/design-system.md auto-wrap glossary
skills/AGENTS_FRONTEND_POOL_PROVIDE_WITHDRAW_PREVIEW.md Asset A/B wording
scripts/qa/verify-issue-NNN.sh + Makefile new make verify-issue-NNN
  1. Helper (keep in tokenDisplay / useTokenDisplayInfo, not inline JSX): formatPoolAssetFieldLabel({ name, symbol }) → Name (SYMBOL) or SYMBOL. Registry name/symbol first; indexer name only if it passes a short allowlist (no HTML, no uluna/uusd as name).
  2. Provide field label + aria-label: use that helper on the selected AssetInfo (balanceInfoA / balanceInfoB, which already flip with wrap). Example: wrap on → Terra Luna Classic (LUNC) / aria LUNC amount; wrap off → Wrapped Luna Classic (cLUNC) / aria cLUNC amount. Drop every Asset A / Asset B string from UI, aria, and tests.
  3. Initialize wrap: useState(() => !!getNativeEquivalent(assetInfoLabel(pair.asset_infos[0]))) (same for B). Do not useEffect to flip after first paint (avoids balance flash / counterpart recalc).
  4. Update tests: Vitest queries by product ticker aria (or /LUNC amount/i on wrap-capable fixtures). Wrap-capable fixture: assert checkbox checked and native balance query key. Uncheck → CW20 key. wrap-pool E7: assert checked, do not click (click would turn wrap off). E8: uncheck before CW20 provide.
  5. Docs / skill / make verify-issue-NNN (Vitest + grep no Asset A amount in PoolAdvancedManage + wrap-default unit). Playwright smoke optional; tx E7/E8 when LocalTerra wrap pairs exist.

Do not default both wrap checkboxes on for a pair with only one wrap leg. Do not send native coins into the pair contract.

Acceptance criteria

  • AC1. Manage → Provide: visible labels are {Name} ({SYMBOL}) or {SYMBOL} for each leg. No Asset A / Asset B / ASSET A / ASSET B in the provide form (including uppercase CSS).
  • AC2. aria-label on the two amount inputs uses the selected product ticker (LUNC amount, cLUNC amount, UST1 amount, …), not Asset A amount.
  • AC3. Known wrap / native / listed CW20 tickers follow #630 (LUNC/USTC/cLUNC/cUSTC/UST1/…). Never uluna / uusd as the visible label.
  • AC4. When name is absent or equals symbol, label is symbol only (no UST1 (UST1)).
  • AC5. cLUNC/cUSTC leg: auto-wrap checkbox is checked on first paint. Uncheck stays available and is not persisted.
  • AC6. Wrap checked → balance + Max/50% + execute use native denom; label shows native name/symbol. Wrap unchecked → CW20 path + #147 gas gate; label shows CW20 name/symbol.
  • AC7. Pair with no native equivalent: no auto-wrap checkbox; provide stays CW20/CW20; labels still use name/symbol (not Asset A/B).
  • AC8. Dual wrap pair (cLUNC/cUSTC if present): both checkboxes default on independently; user can uncheck one side.
  • AC9. Withdraw expected receive / pre-sign still use product tickers (already). No new Asset A/B copy. receiveWrapped default unchanged.
  • AC10. Existing gates still hold: pause, freeze, blacklist, wrap treasury mismatch, IL notice, pre-sign, counterpart auto-fill, empty-pool no auto-fill.
  • AC11. Retail one-sided cards unchanged (no wrap checkbox, no Asset A/B).
  • AC12. Docs/skills + make verify-issue-NNN land with the implementation. PoolPage.test.tsx / e2e selectors updated.

Test plan (all paths)

Labels

ID Path Expect
L1 Manage provide on UST1/USTR (no wrap) Labels UST1 / USTR or Name (UST1) — not Asset A/B
L2 Manage provide on cLUNC/UST1 Field A shows LUNC name/symbol while wrap default on; field B shows UST1
L3 Uncheck wrap on cLUNC leg Label switches to cLUNC name/symbol; aria follows
L4 Re-check wrap Label back to LUNC; no Asset A regression
L5 Indexer symbol spoof uluna on wrap CW20 Registry still shows cLUNC, not uluna
L6 Unknown factory CW20 Shortened address or indexer symbol — never Asset A; never HTML
L7 Name === symbol (UST1) UST1 only
L8 .label-glass Visible ticker remains mixed-case cLUNC / LUNC, not CLUNC forced by CSS
L9 Light + dark, 375px / 1280px Labels readable; no extra essay
L10 Withdraw open No Asset A/B; expected receive tickers unchanged vs today
L11 One-sided add/withdraw Still no Asset A/B and no wrap checkbox

Auto-wrap default

ID Path Expect
W1 First open Provide on cLUNC pair Auto-wrap checkbox present and checked
W2 First open Provide on UST1/USTR Zero auto-wrap checkboxes
W3 Default-on wrap tokenBalance query key uses uluna/uusd; Max uses provide_liquidity_native_side reserve
W4 Uncheck Query key flips to CW20; #147 gas gate can appear; wrap multi-msg not built
W5 Counterpart auto-fill with wrap on Uses net after wrap fee (#480 / #516)
W6 Empty pool No counterpart auto-fill (unchanged)
W7 Mapper config null / treasury mismatch, wrap still checked CTA disabled (Wrap config unavailable / misconfigured); uncheck re-enables CW20 path if other gates pass
W8 Wallet holds CW20 only, wrap default on Exceeds wallet / insufficient on native; uncheck allows CW20 provide
W9 Wallet holds native, wrap default on Native balance shown; provide uses wrap_deposit + allowances + provide
W10 Remount Manage (collapse/expand) Default on again (no persistence)
W11 Pause / freeze / blacklist CTA still blocked regardless of wrap
W12 Pre-sign summary Amount lines use display tickers of the selected input (native vs CW20), not Asset A/B

E2E / LocalTerra

ID Path Expect
E1 PLAYWRIGHT_SKIP_CHAIN=1 /pool Manage provide No Asset A / Asset B text; wrap pair checkbox checked
E2 wrap-pool E7 Native provide without clicking wrap on (click would disable)
E3 wrap-pool E8 Explicit uncheck, then CW20 provide
E4 One-sided 533 smoke Still no auto-wrap checkbox on retail add

Test plan (attack, hack, abuse)

ID Vector Expect
A1 Indexer XSS name/symbol = <img onerror=…> / javascript: Rendered as text; no HTML / no script
A2 Symbol spoof wrap CW20 listed as LUNC or uluna Registry cLUNC; execute id remains wrap CW20 / native denom as selected
A3 Default wrap drains wrong asset Wrap on spends bank uluna/uusd only; never sends native into the pair; pair still receives CW20 net-of-fee
A4 User unchecks wrap but UI still wraps Execute path must match checkbox; no wrap_deposit when unchecked
A5 User leaves wrap on with 0 native Exceeds wallet / disabled CTA — no unsigned wrap of empty coins
A6 Mapper pause / treasury mismatch Cannot broadcast wrap path; uncheck is the escape hatch
A7 Double-wrap both legs native nativeWrapDepositCount === 2; Max gas reserve covers both deposits; still one multi-msg
A8 N+1 LCD (A8) Default /pool table paint still does not getPool per row
A9 Aria spoof aria-label is our product ticker, not raw indexer HTML
A10 localStorage / query param ?wrap=1 forcing wrap on non-wrap pair Forbidden — only getNativeEquivalent
A11 Withdraw default flip Must not start auto-unwrapping wallet remainder
A12 Clickjack wrap Checkbox is a normal labeled control; no hidden default that cannot be unchecked
A13 Cognitive-load dump No new always-on wrap essay; checkbox copy can stay Use native LUNC (auto-wrap)
A14 Gem / production hide Unrelated; do not list gems to “demo” labels (#562)

Verification criteria

Ship is done when all of the following hold:

  1. make verify-issue-NNN (new) is green: Vitest PoolPage / token label helper / wrap-default init; static grep that PoolAdvancedManage.tsx has no Asset A / Asset B / Asset A amount strings.
  2. make test-frontend scoped files above stay green. Existing #480 counterpart tests still pass with wrap default on (or fixtures explicitly uncheck).
  3. Playwright: e2e/pool.spec.ts and pool-lp-howto-531.spec.ts no longer require Asset A. wrap-pool E7/E8 match the new default (E7 no click-to-enable; E8 unchecks).
  4. Manual /pool Manage on a cLUNC pair: first paint shows LUNC (or Terra Luna Classic (LUNC)), wrap checked; uncheck shows cLUNC; UST1/USTR pair never shows wrap chrome and never says Asset A/B.
  5. Docs updated: docs/frontend.md pool provide (drop “Asset A or B”; document wrap default on), docs/design-system.md if glossary needs “defaults on”, skills/AGENTS_FRONTEND_POOL_PROVIDE_WITHDRAW_PREVIEW.md same. AGENTS.md verify one-liner if that is house style.
  6. Retail one-sided + #533 / #547 / #630 invariants unchanged.

Out of scope: one-sided zap UI, withdraw auto-unwrap default, pair/router wasm, wrap-mapper fee bps, /pool table columns (#655), persisting wrap preference.

## Summary On `/pool` → **Manage** → Advanced, two-sided **Provide Liquidity** still labels the amount fields **Asset A** / **Asset B** (CSS `uppercase` paints them as **ASSET A AMOUNT** / **ASSET B AMOUNT**). Those fields must show the pair-leg **name (symbol)** instead. On wrap-equivalent legs (cLUNC / cUSTC), **Use native … (auto-wrap)** is unchecked (`useState(false)`). Auto-wrap must default **on** when a native equivalent exists. Bundle **labels + auto-wrap default** in **one** issue. Same component, same tests, same wrap execute path. Do **not** split “rename the label” vs “flip the checkbox default.” Related: [#547](https://gitlab.com/PlasticDigits/cl8y-dex-terraclassic/-/issues/547) (Manage expand + Advanced), [#533](https://gitlab.com/PlasticDigits/cl8y-dex-terraclassic/-/issues/533) (retail one-sided — **out of scope**), [#630](https://gitlab.com/PlasticDigits/cl8y-dex-terraclassic/-/issues/630) (LUNC/USTC/cLUNC/cUSTC tickers), [#489](https://gitlab.com/PlasticDigits/cl8y-dex-terraclassic/-/issues/489) (short labels), [#480](https://gitlab.com/PlasticDigits/cl8y-dex-terraclassic/-/issues/480) (counterpart auto-fill), [#147](https://gitlab.com/PlasticDigits/cl8y-dex-terraclassic/-/issues/147) (CW20 vs wrap gas), [#512](https://gitlab.com/PlasticDigits/cl8y-dex-terraclassic/-/issues/512) / [#516](https://gitlab.com/PlasticDigits/cl8y-dex-terraclassic/-/issues/516) (wrap fee net), [#201](https://gitlab.com/PlasticDigits/cl8y-dex-terraclassic/-/issues/201) (wrap-pool E2E). ## Current codebase `/pool` retail add/withdraw is **one-sided** (`OneSidedAddCard` / `OneSidedWithdrawCard`). Two-sided provide/withdraw lives under table **Manage** → `PoolAdvancedManage` → `<details data-testid="pool-card-advanced">` (**Provide Liquidity** / **Withdraw Liquidity**). LCD `getPool` / `getPairFeeConfig` run **only** on expand (**P547-9** / A8). | Layer | Behavior today | |-------|----------------| | **Provide labels** | [`PoolAdvancedManage.tsx`](https://gitlab.com/PlasticDigits/cl8y-dex-terraclassic/-/blob/main/frontend-dapp/src/components/pool/PoolAdvancedManage.tsx) hard-codes visible `Asset A Amount` / `Asset B Amount` plus a `normal-case` parenthetical `({displayA.displayLabel})`. Inputs use `aria-label="Asset A amount"` / `"Asset B amount"`. `.label-glass` is `uppercase tracking-wide`, so the user sees **ASSET A AMOUNT (cLUNC)**. | | **Token identity already loaded** | Same file already calls `useTokenDisplayInfo(pair.asset_infos[0\|1])` (`displayLabel` + `symbol`). Registry product tickers beat indexer/on-chain text (**N630-1–N630-4**). [`tokenRegistry.ts`](https://gitlab.com/PlasticDigits/cl8y-dex-terraclassic/-/blob/main/frontend-dapp/src/utils/tokenRegistry.ts) also has `name` (`Terra Luna Classic`, `Wrapped Luna Classic`, …) but `useTokenDisplayInfo` does **not** expose `name` — `displayLabel === symbol`. | | **Auto-wrap default** | `useNativeA` / `useNativeB` initialize to **`false`**. Checkbox **Use native {LUNC\|USTC} (auto-wrap)** renders only when `getNativeEquivalent(tokenId)` is set (cLUNC → `uluna`, cUSTC → `uusd`). Checked → balance query switches to native denom; execute is wrap_deposit + allowances + `provide_liquidity` (`executeTerraContractMulti`). Unchecked → CW20 balances + three sequential txs (gas gate **#147**). | | **Withdraw** | No Asset A/B amount fields. Expected receive / pre-sign already use `displayA.displayLabel` / native ticker when unwrap is on. `receiveWrapped` defaults **`true`** (keep wrapped). That is **not** the provide auto-wrap checkbox. | | **Retail one-sided** | No wrap checkbox (**Z533-1**). Native pick implies wrap. Do not change. | | **Counterpart / fees** | Empty counterpart auto-fills from pool ratio (**#480**). Wrap-on path uses **net** after mapper fee (`provideRawAdd*`). Max/50% `forceSync`. Empty pool: no auto-fill. | | **Wrap gates** | `wrapProvideBlocked` when mapper address set and config missing or treasury ≠ env. Pause / code-id freeze / blacklist still disable CTAs. | | **Tests that lock the old copy** | [`PoolPage.test.tsx`](https://gitlab.com/PlasticDigits/cl8y-dex-terraclassic/-/blob/main/frontend-dapp/src/pages/PoolPage.test.tsx) uses `getByLabelText('Asset A amount')` / `'Asset B amount'` throughout. [`e2e/pool.spec.ts`](https://gitlab.com/PlasticDigits/cl8y-dex-terraclassic/-/blob/main/frontend-dapp/e2e/pool.spec.ts) and [`e2e/pool-lp-howto-531.spec.ts`](https://gitlab.com/PlasticDigits/cl8y-dex-terraclassic/-/blob/main/frontend-dapp/e2e/pool-lp-howto-531.spec.ts) match `/Asset A\|Amount/i`. [`e2e/wrap-pool.spec.ts`](https://gitlab.com/PlasticDigits/cl8y-dex-terraclassic/-/blob/main/frontend-dapp/e2e/wrap-pool.spec.ts) **E7 clicks** auto-wrap to enable; **E8** fills amounts without clicking (assumes wrap **off**). Those invert if the default flips. | | **Docs** | [`docs/frontend.md`](https://gitlab.com/PlasticDigits/cl8y-dex-terraclassic/-/blob/main/docs/frontend.md) § pool still says “editing Asset A or B”. [`docs/design-system.md`](https://gitlab.com/PlasticDigits/cl8y-dex-terraclassic/-/blob/main/docs/design-system.md) glossary: “Use native LUNC (auto-wrap)”. [`skills/AGENTS_FRONTEND_POOL_PROVIDE_WITHDRAW_PREVIEW.md`](https://gitlab.com/PlasticDigits/cl8y-dex-terraclassic/-/blob/main/skills/AGENTS_FRONTEND_POOL_PROVIDE_WITHDRAW_PREVIEW.md) same Asset A/B wording. | ## Why this is needed 1. **Retail cannot tell which token they are depositing.** “ASSET A” is an implementation leftover (`asset_infos[0]`). `#489` forbids `token0` / generic slot names. The pair header already shows `TokenDisplay` symbols; the amount fields must match. 2. **The identity is already in memory.** `useTokenDisplayInfo` + registry `name`/`symbol` exist. The UI ignores them and prints Asset A/B. 3. **Auto-wrap off is the wrong default for wrap pairs.** Pools hold **cLUNC / cUSTC**. Typical LPs hold **bank LUNC / USTC**. An unchecked box makes them provide CW20 (or fail “exceeds wallet”) when the intended path is native + wrap in the same multi-msg. Retail one-sided already auto-wraps when the token is native; Advanced should not invert that. 4. **Leaving wrap off also mis-labels the spend.** If wrap defaults on, the field must show **LUNC / USTC** (what leaves the wallet), not **cLUNC** with a hidden wrap. Today the label stays the pool CW20 even when the checkbox is checked. ## Constraints / guardrails 1. **Frontend-only.** No pair/router/mapper migrate. No fee-bps / treasury / mint math changes. 2. **Do not touch retail one-sided** (`OneSidedAddCard` / `OneSidedWithdrawCard`). No wrap checkbox there (**Z533-1 / Z533-2**). 3. **Product tickers, not bank denoms.** Visible text for `uluna` / `uusd` is **LUNC** / **USTC**; wrap CW20s stay **cLUNC** / **cUSTC** (**N630-1–N630-2**). Execute / React Query ids stay `uluna` / `uusd` / CW20 address (**N630-3**). Registry wins over indexer spoof (**N630-4**). Unknown natives fail closed as raw denom (**N630-5**). 4. **Label = selected input asset, not always the pool CW20.** Wrap checked → native **name (symbol)** (LUNC). Wrap unchecked → pair-leg CW20 **name (symbol)** (cLUNC). Unchecking must switch label + balance + execute path immediately. 5. **`NAME (SYMBOL)` without redundancy or essays.** Prefer `{registry-or-indexer name} ({product symbol})` when name is distinct and short (≤ ~5 words, **#489**). Collapse to `{symbol}` when name is missing, equals the symbol, or is a long/HTML/spoofed indexer string. Never `cLUNC (cLUNC)`. Never `uluna` / `uusd` as the visible name. 6. **`.label-glass` is `uppercase`.** A raw `cLUNC` in that class becomes **CLUNC**. Keep tickers in a `normal-case` (or non-`label-glass`) node. Mixed-case product tickers must survive CSS. 7. **Auto-wrap default on only when `getNativeEquivalent` is non-null.** Non-wrap pairs (UST1/USTR, CL8Y/UST1, gems) must **not** show the checkbox and must **not** take the wrap execute path. 8. **Default is on-mount, not persisted.** No `localStorage` for wrap preference. Uncheck is session-only until remount. 9. **Do not flip withdraw `receiveWrapped`.** Report is provide auto-wrap. Withdraw stays default **receive wrapped** unless a later issue says otherwise. Do not unwrap the rest of the wallet (**Z533-8**). 10. **Users who only hold CW20 must still provide.** Default-on wrap can show native balance `0` / Exceeds wallet. Uncheck → CW20 balance + `#147` gas gate. If mapper config is missing or treasury mismatches, `wrapProvideBlocked` must not trap the user — uncheck must restore the CW20 CTA (subject to other gates). 11. **Keep all existing safety gates:** pause, code-id freeze, blacklist, clickwrap/NFA, wrap treasury match, IL notice, pre-sign summary (**#462**), counterpart ratio warning, Max gas reserve on native uluna. 12. **No N+1 LCD on default `/pool` paint (A8).** Labels use data already on the expanded Manage instance (`useTokenDisplayInfo` / registry). Do not add per-row LCD for names. 13. **XSS / spoof:** indexer `name` / `symbol` are text only. No `dangerouslySetInnerHTML`. Registry allowlist still wins for known natives/wraps. 14. **Do not add an always-on “uluna means LUNC” or wrap-architecture essay (#489).** ## Relevant files | File | Role | |------|------| | `frontend-dapp/src/components/pool/PoolAdvancedManage.tsx` | Labels, `useNativeA`/`useNativeB` defaults, aria-labels, wrap execute | | `frontend-dapp/src/hooks/useTokenDisplayInfo.ts` | Shared `displayLabel` / `symbol`; extend only if `name` is needed | | `frontend-dapp/src/utils/tokenRegistry.ts` | `name` + `registryProductSymbol` | | `frontend-dapp/src/utils/tokenDisplay.ts` | `getTokenDisplaySymbol` | | `frontend-dapp/src/types/index.ts` | `getNativeEquivalent` / `WRAPPED_NATIVE_PAIRS` | | `frontend-dapp/src/pages/PoolPage.test.tsx` | Vitest locked to `Asset A amount` | | `frontend-dapp/e2e/pool.spec.ts` | `/Asset A\|Amount/i` | | `frontend-dapp/e2e/pool-lp-howto-531.spec.ts` | same | | `frontend-dapp/e2e/wrap-pool.spec.ts` | E7 click-to-enable / E8 assume wrap off | | `frontend-dapp/e2e/helpers/wrap-e2e.ts` | `requirePoolCardWithNativeWrap` | | `docs/frontend.md` | “Asset A or B” pool provide copy | | `docs/design-system.md` | auto-wrap glossary | | `skills/AGENTS_FRONTEND_POOL_PROVIDE_WITHDRAW_PREVIEW.md` | Asset A/B wording | | `scripts/qa/verify-issue-NNN.sh` + `Makefile` | new `make verify-issue-NNN` | ## Recommended direction 1. **Helper** (keep in `tokenDisplay` / `useTokenDisplayInfo`, not inline JSX): `formatPoolAssetFieldLabel({ name, symbol })` → `Name (SYMBOL)` or `SYMBOL`. Registry name/symbol first; indexer name only if it passes a short allowlist (no HTML, no `uluna`/`uusd` as name). 2. **Provide field label + `aria-label`:** use that helper on the **selected** `AssetInfo` (`balanceInfoA` / `balanceInfoB`, which already flip with wrap). Example: wrap on → `Terra Luna Classic (LUNC)` / aria `LUNC amount`; wrap off → `Wrapped Luna Classic (cLUNC)` / aria `cLUNC amount`. Drop every `Asset A` / `Asset B` string from UI, aria, and tests. 3. **Initialize wrap:** `useState(() => !!getNativeEquivalent(assetInfoLabel(pair.asset_infos[0])))` (same for B). Do not `useEffect` to flip after first paint (avoids balance flash / counterpart recalc). 4. **Update tests:** Vitest queries by product ticker aria (or `/LUNC amount/i` on wrap-capable fixtures). Wrap-capable fixture: assert checkbox **checked** and native balance query key. Uncheck → CW20 key. `wrap-pool` E7: assert checked, **do not click** (click would turn wrap **off**). E8: **uncheck** before CW20 provide. 5. **Docs / skill / `make verify-issue-NNN`** (Vitest + grep no `Asset A amount` in `PoolAdvancedManage` + wrap-default unit). Playwright smoke optional; tx E7/E8 when LocalTerra wrap pairs exist. Do **not** default both wrap checkboxes on for a pair with only one wrap leg. Do **not** send native coins into the pair contract. ## Acceptance criteria - [ ] **AC1.** Manage → Provide: visible labels are `{Name} ({SYMBOL})` or `{SYMBOL}` for each leg. **No** `Asset A` / `Asset B` / `ASSET A` / `ASSET B` in the provide form (including uppercase CSS). - [ ] **AC2.** `aria-label` on the two amount inputs uses the **selected** product ticker (`LUNC amount`, `cLUNC amount`, `UST1 amount`, …), not `Asset A amount`. - [ ] **AC3.** Known wrap / native / listed CW20 tickers follow **#630** (LUNC/USTC/cLUNC/cUSTC/UST1/…). Never `uluna` / `uusd` as the visible label. - [ ] **AC4.** When name is absent or equals symbol, label is **symbol only** (no `UST1 (UST1)`). - [ ] **AC5.** cLUNC/cUSTC leg: auto-wrap checkbox is **checked on first paint**. Uncheck stays available and is not persisted. - [ ] **AC6.** Wrap checked → balance + Max/50% + execute use **native** denom; label shows native name/symbol. Wrap unchecked → CW20 path + `#147` gas gate; label shows CW20 name/symbol. - [ ] **AC7.** Pair with **no** native equivalent: no auto-wrap checkbox; provide stays CW20/CW20; labels still use name/symbol (not Asset A/B). - [ ] **AC8.** Dual wrap pair (cLUNC/cUSTC if present): **both** checkboxes default on independently; user can uncheck one side. - [ ] **AC9.** Withdraw expected receive / pre-sign still use product tickers (already). **No** new Asset A/B copy. `receiveWrapped` default **unchanged**. - [ ] **AC10.** Existing gates still hold: pause, freeze, blacklist, wrap treasury mismatch, IL notice, pre-sign, counterpart auto-fill, empty-pool no auto-fill. - [ ] **AC11.** Retail one-sided cards unchanged (no wrap checkbox, no Asset A/B). - [ ] **AC12.** Docs/skills + `make verify-issue-NNN` land with the implementation. `PoolPage.test.tsx` / e2e selectors updated. ## Test plan (all paths) ### Labels | ID | Path | Expect | |----|------|--------| | L1 | Manage provide on UST1/USTR (no wrap) | Labels `UST1` / `USTR` or `Name (UST1)` — **not** Asset A/B | | L2 | Manage provide on cLUNC/UST1 | Field A shows **LUNC** name/symbol while wrap default on; field B shows UST1 | | L3 | Uncheck wrap on cLUNC leg | Label switches to **cLUNC** name/symbol; aria follows | | L4 | Re-check wrap | Label back to LUNC; no Asset A regression | | L5 | Indexer symbol spoof `uluna` on wrap CW20 | Registry still shows **cLUNC**, not `uluna` | | L6 | Unknown factory CW20 | Shortened address or indexer symbol — never Asset A; never HTML | | L7 | Name === symbol (UST1) | `UST1` only | | L8 | `.label-glass` | Visible ticker remains mixed-case `cLUNC` / `LUNC`, not `CLUNC` forced by CSS | | L9 | Light + dark, 375px / 1280px | Labels readable; no extra essay | | L10 | Withdraw open | No Asset A/B; expected receive tickers unchanged vs today | | L11 | One-sided add/withdraw | Still no Asset A/B and no wrap checkbox | ### Auto-wrap default | ID | Path | Expect | |----|------|--------| | W1 | First open Provide on cLUNC pair | Auto-wrap checkbox present and **checked** | | W2 | First open Provide on UST1/USTR | **Zero** auto-wrap checkboxes | | W3 | Default-on wrap | `tokenBalance` query key uses `uluna`/`uusd`; Max uses `provide_liquidity_native_side` reserve | | W4 | Uncheck | Query key flips to CW20; `#147` gas gate can appear; wrap multi-msg **not** built | | W5 | Counterpart auto-fill with wrap on | Uses **net** after wrap fee (**#480** / **#516**) | | W6 | Empty pool | No counterpart auto-fill (unchanged) | | W7 | Mapper config null / treasury mismatch, wrap still checked | CTA disabled (`Wrap config unavailable` / `misconfigured`); uncheck re-enables CW20 path if other gates pass | | W8 | Wallet holds CW20 only, wrap default on | Exceeds wallet / insufficient on native; uncheck allows CW20 provide | | W9 | Wallet holds native, wrap default on | Native balance shown; provide uses wrap_deposit + allowances + provide | | W10 | Remount Manage (collapse/expand) | Default on again (no persistence) | | W11 | Pause / freeze / blacklist | CTA still blocked regardless of wrap | | W12 | Pre-sign summary | Amount lines use **display** tickers of the selected input (native vs CW20), not Asset A/B | ### E2E / LocalTerra | ID | Path | Expect | |----|------|--------| | E1 | `PLAYWRIGHT_SKIP_CHAIN=1` `/pool` Manage provide | No `Asset A` / `Asset B` text; wrap pair checkbox checked | | E2 | `wrap-pool` E7 | Native provide **without** clicking wrap on (click would disable) | | E3 | `wrap-pool` E8 | Explicit uncheck, then CW20 provide | | E4 | One-sided 533 smoke | Still no auto-wrap checkbox on retail add | ## Test plan (attack, hack, abuse) | ID | Vector | Expect | |----|--------|--------| | A1 | **Indexer XSS** `name`/`symbol` = `<img onerror=…>` / `javascript:` | Rendered as text; no HTML / no script | | A2 | **Symbol spoof** wrap CW20 listed as `LUNC` or `uluna` | Registry **cLUNC**; execute id remains wrap CW20 / native denom as selected | | A3 | **Default wrap drains wrong asset** | Wrap on spends **bank** `uluna`/`uusd` only; never sends native into the pair; pair still receives CW20 net-of-fee | | A4 | **User unchecks wrap but UI still wraps** | Execute path must match checkbox; no wrap_deposit when unchecked | | A5 | **User leaves wrap on with 0 native** | Exceeds wallet / disabled CTA — no unsigned wrap of empty coins | | A6 | **Mapper pause / treasury mismatch** | Cannot broadcast wrap path; uncheck is the escape hatch | | A7 | **Double-wrap** both legs native | `nativeWrapDepositCount === 2`; Max gas reserve covers both deposits; still one multi-msg | | A8 | **N+1 LCD (A8)** | Default `/pool` table paint still does not `getPool` per row | | A9 | **Aria spoof** | `aria-label` is our product ticker, not raw indexer HTML | | A10 | **localStorage / query param** `?wrap=1` forcing wrap on non-wrap pair | **Forbidden** — only `getNativeEquivalent` | | A11 | **Withdraw default flip** | Must not start auto-unwrapping wallet remainder | | A12 | **Clickjack wrap** | Checkbox is a normal labeled control; no hidden default that cannot be unchecked | | A13 | **Cognitive-load dump** | No new always-on wrap essay; checkbox copy can stay `Use native LUNC (auto-wrap)` | | A14 | **Gem / production hide** | Unrelated; do not list gems to “demo” labels (**#562**) | ## Verification criteria Ship is done when **all** of the following hold: 1. `make verify-issue-NNN` (new) is green: Vitest PoolPage / token label helper / wrap-default init; static grep that `PoolAdvancedManage.tsx` has **no** `Asset A` / `Asset B` / `Asset A amount` strings. 2. `make test-frontend` scoped files above stay green. Existing `#480` counterpart tests still pass with wrap default on (or fixtures explicitly uncheck). 3. Playwright: `e2e/pool.spec.ts` and `pool-lp-howto-531.spec.ts` no longer require `Asset A`. `wrap-pool` E7/E8 match the new default (E7 no click-to-enable; E8 unchecks). 4. Manual `/pool` Manage on a cLUNC pair: first paint shows **LUNC** (or `Terra Luna Classic (LUNC)`), wrap **checked**; uncheck shows **cLUNC**; UST1/USTR pair never shows wrap chrome and never says Asset A/B. 5. Docs updated: `docs/frontend.md` pool provide (drop “Asset A or B”; document wrap default on), `docs/design-system.md` if glossary needs “defaults on”, `skills/AGENTS_FRONTEND_POOL_PROVIDE_WITHDRAW_PREVIEW.md` same. `AGENTS.md` verify one-liner if that is house style. 6. Retail one-sided + `#533` / `#547` / `#630` invariants unchanged. **Out of scope:** one-sided zap UI, withdraw auto-unwrap default, pair/router wasm, wrap-mapper fee bps, `/pool` table columns (#655), persisting wrap preference.
PlasticDigits commented 2026-08-26 07:00:50 +00:00 (Migrated from gitlab.com)

mentioned in commit 6f74c2ce97

mentioned in commit 6f74c2ce97f1d3462bd8a9377d72f7a2136f3464
PlasticDigits commented 2026-08-26 07:02:25 +00:00 (Migrated from gitlab.com)

mentioned in merge request !1161

mentioned in merge request !1161
PlasticDigits commented 2026-08-26 08:13:34 +00:00 (Migrated from gitlab.com)

mentioned in commit fe0ff4bf63

mentioned in commit fe0ff4bf63abad071f71d9dab9c95e3a56e890fa
PlasticDigits (Migrated from gitlab.com) closed this issue 2026-08-26 08:13:35 +00:00
PlasticDigits commented 2026-08-26 09:19:18 +00:00 (Migrated from gitlab.com)

mentioned in commit 7c5e693383

mentioned in commit 7c5e693383657e00d9977cb91781890ec312a930
PlasticDigits commented 2026-08-26 09:30:55 +00:00 (Migrated from gitlab.com)

Merged to main via !1161, then stacked under !1175 (#660 four-tab Manage). Provide still uses name/symbol labels and wrap default on; there is no pool-card-advanced disclosure anymore.

Leftover: /pool Manage → Provide Liquidity: no Asset A/B; wrap checkboxes default on for cLUNC/cUSTC. make verify-issue-661 (and #660).

Merged to `main` via !1161, then stacked under !1175 (#660 four-tab Manage). Provide still uses name/symbol labels and wrap default on; there is no `pool-card-advanced` disclosure anymore. Leftover: `/pool` Manage → Provide Liquidity: no Asset A/B; wrap checkboxes default on for cLUNC/cUSTC. `make verify-issue-661` (and #660).
PlasticDigits commented 2026-08-26 09:31:08 +00:00 (Migrated from gitlab.com)

mentioned in issue #660

mentioned in issue #660
PlasticDigits commented 2026-08-26 09:31:35 +00:00 (Migrated from gitlab.com)

mentioned in issue #673

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