feat(#506): /ust1 oracle window mint/redeem UI #1045

Merged
PlasticDigits merged 3 commits from feat/506-ust1-window-ui into main 2026-08-09 07:03:25 +00:00
PlasticDigits commented 2026-08-08 13:42:35 +00:00 (Migrated from gitlab.com)

Summary

  • Adds dedicated /ust1 Deposit/Withdraw UI for vFDUSD ↔ UST1 via ust1-window CW20 Send + on-chain effective_swap quotes/gates (not AMM router, not faucet /mint).
  • Wires nav label UST1, Coolify/VITE_UST1_* env, token registry + logos, and UST1_WINDOW_SEND_GAS_LIMIT retail gas inventory.
  • Documents invariants U1–U8 in docs/runbooks/ust1-window-ui.md and agent playbook skills/AGENTS_UST1_WINDOW_UI.md (cross-linked from AGENTS.md / shell-nav / soft-launch / gas skills).

Closes #506

Test plan

  • make verify-issue-506 (math, gates, client, page, nav, retail gas + source guards)
  • Restest of Ust1Page / gates / ust1Window unit suites
  • make lint-frontend (no new errors)
  • Coolify rebuild with columbus-5 VITE_UST1_* (Dockerfile defaults present)
  • Production smoke: small deposit + withdraw; record tx hashes; LCD effective_swap vs UI quote
  • Confirm nav UST1 ≠ Mint on dex.cl8y.com
## Summary - Adds dedicated `/ust1` Deposit/Withdraw UI for vFDUSD ↔ UST1 via ust1-window CW20 `Send` + on-chain `effective_swap` quotes/gates (not AMM router, not faucet `/mint`). - Wires nav label **UST1**, Coolify/`VITE_UST1_*` env, token registry + logos, and `UST1_WINDOW_SEND_GAS_LIMIT` retail gas inventory. - Documents invariants **U1–U8** in `docs/runbooks/ust1-window-ui.md` and agent playbook `skills/AGENTS_UST1_WINDOW_UI.md` (cross-linked from AGENTS.md / shell-nav / soft-launch / gas skills). Closes #506 ## Test plan - [x] `make verify-issue-506` (math, gates, client, page, nav, retail gas + source guards) - [x] Restest of Ust1Page / gates / ust1Window unit suites - [x] `make lint-frontend` (no new errors) - [ ] Coolify rebuild with columbus-5 `VITE_UST1_*` (Dockerfile defaults present) - [ ] Production smoke: small deposit + withdraw; record tx hashes; LCD `effective_swap` vs UI quote - [ ] Confirm nav **UST1** ≠ **Mint** on dex.cl8y.com
PlasticDigits commented 2026-08-08 13:42:41 +00:00 (Migrated from gitlab.com)

mentioned in issue #506

mentioned in issue #506
PlasticDigits commented 2026-08-09 06:51:36 +00:00 (Migrated from gitlab.com)

RECOMMEND: FIX

Thorough review of MR !1045 (feat(#506): /ust1 oracle window mint/redeem UI) against issue #506 acceptance criteria, attack/abuse table, verification checklist, and a security/gap pass over the changed surface (frontend-only; no indexer/DB/Rust/smart-contract code in this MR).

Verified locally: make verify-issue-506 → PASS (5/5 checks, 58 unit tests). Branch tip reviewed: 962fe51.


Verdict

Ship-quality core: dedicated /ust1, CW20 Send to ust1-window only, LCD effective_swap quote/gates, faucet separation, Coolify env docs, retail gas inventory (UST1_WINDOW_SEND_GAS_LIMIT 800k), and solid unit coverage.

Not ACCEPT yet because #506 ACs / test plan still have material gaps (on-page logos, Playwright disabled-state coverage, mainnet smoke, withdraw min-out disclosure). Not BLOCK: no medium+/critical security findings; chain remains the authority for pause/stale/limits/economics.


Issue #506 acceptance criteria

AC Status Evidence
/ust1 mint/redeem UI ≠ faucet Met App.tsx /ust1 → Ust1Page; Deposit/Withdraw; copy distinguishes AMM/faucet
Nav discovers without confusing /mint Met UST1_NAV_ITEM label UST1; includeUst1: isUst1WindowEnabled(); source guards in verify-issue-506
Quotes from effective_swap; CTA pause/stale/per-tx/24h Met getUst1EffectiveSwap + evaluateUst1SubmitGate; submit re-check with fresh nowSec
Deposit/withdraw succeed; txs recorded Missing Runbook smoke present; MR test plan unchecked; no hashes on #506
Only vFDUSD deposit / UST1 withdraw Met No token picker; payTokenForDirection hardcodes env addresses
Metadata/logos visible Partial Registry + tokenlist/ + PNGs; Ust1Page does not render TokenLogo/TokenDisplay
Coolify VITE_* documented Met Dockerfile columbus-5 defaults, .env.example, docs/runbooks/ust1-window-ui.md
lint/test green Met verify-issue-506 + lint reported green in MR

Verification checklist (#506)

  • Production smoke tx hashes — open
  • LCD effective_swap vs UI quote — open (unit math mirrors INV-SWAP; live side-by-side not done)
  • Nav UST1 ≠ Mint — covered by unit/source guards
  • Coolify env keys documented
  • Unblocks #502 remaining window ACs — pending smoke

Attack / abuse vectors from #506

Vector Result
Submit while oracle stale / window paused CTA blocked; mutation re-evaluates gates
Exceed per-tx / 24h Client block + chain enforce
AMM router used for “mint” Never — CW20 Send to window only
Wrong token for window send Hardcoded per direction
LocalTerra env on prod Dockerfile defaults are columbus-5; local .env.example empty
XSS / malicious token metadata Page does not render chain HTML; logos allowlisted elsewhere
Faucet /mint spoofing UST1 Separate route/label; UST1/vFDUSD not in soft-launch mintables
Confused AMM vs oracle mint Explicit “not an AMM swap” + Swap/Trade links

Security audit (changed code)

Scope: Frontend UI/client/docs/tokenlist only. No Rust indexer, Postgres, or CosmWasm contract changes in this MR — database-leak and on-chain privilege reviews are N/A for the diff (upstream ust1-window/oracle assumed already deployed).

Findings

Severity Location Finding
Low ust1Window.ts (~96–103), Ust1Page.tsx Withdraw applies silent 1% min_vfdusd_out haircut (UST1_WITHDRAW_MIN_OUT_SLIPPAGE_BPS=100) not shown in UI — trust/UX surprise, not theft
Low ust1Window.ts deposit path Deposit has no min_out; rate can move between quote display and inclusion (contract design). UI should set expectations
Low Ust1Page.tsx nowSec Oracle Fresh/Stale badge can lag until refetch; submit uses fresh wall-clock — OK for safety
Info ust1Window.ts getUst1WindowConfig Config query exists but unused — no runtime cross-check that env token/window addresses match on-chain config
Info terraGas.ts deposit/withdraw hook names Any CW20 send with those inner keys gets 800k gas — overpay-safe, not underpay
Info Dockerfile ARG defaults Mainnet addresses baked — correct for Coolify prod (U7); staging without overrides also hits mainnet window

No medium/high/critical issues found for: authorization bypass, XSS, CW20 hook injection, wrong-token UI path, faucet conflation, prompt injection in runtime paths, or client-gate bypass that enables fund theft (chain still enforces).

Threat areas requested

Area Assessment
Common DeFi attacks (sandwich/MEV on this path) Window is oracle mint/redeem, not AMM pool; withdraw min-out haircut helps; deposit lacks min-out by contract
Smart-contract attacks Out of MR scope (no contract changes). UI correctly targets window via CW20 Send
Database leaks N/A — no indexer/DB changes
Access control / privileges Wallet-scoped executes only; no admin UI; pause/limits from chain view
Oracle manipulation UI gates on pause/stale/zero rate; malicious LCD can mislead quotes but execute hits real chain
Tokenomic / economic Fee %, per-tx, 24h remaining surfaced; fee split fields (fee_chain_tax_bps / fee_cmm_protocol_bps) unused
E2E Gap — no Playwright under frontend-dapp/e2e for /ust1 (issue asked for disabled-state coverage)

Gap analysis

Features / retail expectations

Present: Deposit/Withdraw tabs, fee %, per-tx max, 24h remaining, oracle Fresh/Stale/Paused, Max balance, receive quote debounce, broadcast pending link, gas footnote, unavailable state when env incomplete.

Missing / weak (user-expected):

  1. Token logos on Pay/Receive rows (AC #6)
  2. Withdraw 1% minimum output disclosure
  3. Oracle rate / last-update age (“updated Xm ago”)
  4. Success explorer link (getExplorerTxUrl / TxResultAlert pattern used elsewhere)
  5. Estimated LUNC gas before submit
  6. Page tests for oracle_paused / per_tx_limit / rolling_limit UI (gates unit-tested; page only covers pause/stale/happy)

UI/UX

Aligned with retail copy / shell-panel patterns and low cognitive load. Weaker token identity vs Swap/Trade (no logos). Clear faucet/AMM disambiguation — good.

Testing

Layer Status
Unit math / gates / client / nav / gas Strong (58 tests via verify script)
Page component Partial (5 tests; not all block reasons)
Playwright E2E Absent (issue recommended)
LocalTerra round-trip Optional / not in MR
Mainnet smoke Unchecked
Happy + bad path Good unit happy/bad for gates; UI bad-path incomplete

Packages / DRY / gas / practices

  • Packages: frontend-dapp, tokenlist, docker/frontend, docs, skills, Makefile — appropriate scope.
  • DRY: Clean split (ust1WindowMath / Gates / client / page).
  • Gas: Retail inventory fixture + 800k constant — follows #475 discipline.
  • Best practices: Pure gate evaluator is excellent; bigint INV-SWAP math; env triple-gate isUst1WindowEnabled.
  • Minor: Refetch-at-submit for effective_swap would reduce quote/execute drift (defense-in-depth).

Required fixes before ACCEPT (or track tightly before closing #506)

  1. Render TokenLogo / token display on Pay & Receive (satisfies AC #6 on-page).
  2. Add Playwright (or equivalent e2e) for /ust1 disabled CTA: paused, stale, over per-tx/24h; enabled when healthy.
  3. Disclose withdraw min-out slippage (1% default) near Receive/CTA.
  4. Mainnet smoke per runbook; record tx hashes on #506 / #502; LCD vs UI quote probe.
  5. Page-level tests for oracle_paused, per_tx_limit, rolling_limit block copy.

Nice-to-have

  • Oracle rate + age; success explorer link; estimated gas; env↔on-chain config cross-check in QA script; fresh effective_swap at submit.

Summary

Core #506 implementation is sound and security posture is appropriate for a frontend oracle window. Recommend FIX for logos, Playwright/disabled-state coverage, slippage disclosure, and completing mainnet verification before treating #506 as closed. No BLOCK-level security defects in the MR diff.

RECOMMEND: FIX Thorough review of MR !1045 (`feat(#506): /ust1 oracle window mint/redeem UI`) against issue **#506** acceptance criteria, attack/abuse table, verification checklist, and a security/gap pass over the changed surface (frontend-only; no indexer/DB/Rust/smart-contract code in this MR). **Verified locally:** `make verify-issue-506` → **PASS** (5/5 checks, **58** unit tests). Branch tip reviewed: `962fe51`. --- ## Verdict Ship-quality core: dedicated `/ust1`, CW20 `Send` to ust1-window only, LCD `effective_swap` quote/gates, faucet separation, Coolify env docs, retail gas inventory (`UST1_WINDOW_SEND_GAS_LIMIT` 800k), and solid unit coverage. **Not ACCEPT yet** because #506 ACs / test plan still have material gaps (on-page logos, Playwright disabled-state coverage, mainnet smoke, withdraw min-out disclosure). **Not BLOCK**: no medium+/critical security findings; chain remains the authority for pause/stale/limits/economics. --- ## Issue #506 acceptance criteria | AC | Status | Evidence | |----|--------|----------| | `/ust1` mint/redeem UI ≠ faucet | **Met** | `App.tsx` `/ust1` → `Ust1Page`; Deposit/Withdraw; copy distinguishes AMM/faucet | | Nav discovers without confusing `/mint` | **Met** | `UST1_NAV_ITEM` label **UST1**; `includeUst1: isUst1WindowEnabled()`; source guards in `verify-issue-506` | | Quotes from `effective_swap`; CTA pause/stale/per-tx/24h | **Met** | `getUst1EffectiveSwap` + `evaluateUst1SubmitGate`; submit re-check with fresh `nowSec` | | Deposit/withdraw succeed; txs recorded | **Missing** | Runbook smoke present; MR test plan unchecked; no hashes on #506 | | Only vFDUSD deposit / UST1 withdraw | **Met** | No token picker; `payTokenForDirection` hardcodes env addresses | | Metadata/logos visible | **Partial** | Registry + `tokenlist/` + PNGs; **`Ust1Page` does not render `TokenLogo`/`TokenDisplay`** | | Coolify `VITE_*` documented | **Met** | Dockerfile columbus-5 defaults, `.env.example`, `docs/runbooks/ust1-window-ui.md` | | lint/test green | **Met** | `verify-issue-506` + lint reported green in MR | ### Verification checklist (#506) - [ ] Production smoke tx hashes — **open** - [ ] LCD `effective_swap` vs UI quote — **open** (unit math mirrors INV-SWAP; live side-by-side not done) - [x] Nav UST1 ≠ Mint — covered by unit/source guards - [x] Coolify env keys documented - [ ] Unblocks #502 remaining window ACs — pending smoke ### Attack / abuse vectors from #506 | Vector | Result | |--------|--------| | Submit while oracle stale / window paused | CTA blocked; mutation re-evaluates gates | | Exceed per-tx / 24h | Client block + chain enforce | | AMM router used for “mint” | Never — CW20 `Send` to window only | | Wrong token for window send | Hardcoded per direction | | LocalTerra env on prod | Dockerfile defaults are columbus-5; local `.env.example` empty | | XSS / malicious token metadata | Page does not render chain HTML; logos allowlisted elsewhere | | Faucet `/mint` spoofing UST1 | Separate route/label; UST1/vFDUSD not in soft-launch mintables | | Confused AMM vs oracle mint | Explicit “not an AMM swap” + Swap/Trade links | --- ## Security audit (changed code) **Scope:** Frontend UI/client/docs/tokenlist only. No Rust indexer, Postgres, or CosmWasm contract changes in this MR — database-leak and on-chain privilege reviews are **N/A for the diff** (upstream ust1-window/oracle assumed already deployed). ### Findings | Severity | Location | Finding | |----------|----------|---------| | Low | `ust1Window.ts` (~96–103), `Ust1Page.tsx` | Withdraw applies silent **1%** `min_vfdusd_out` haircut (`UST1_WITHDRAW_MIN_OUT_SLIPPAGE_BPS=100`) not shown in UI — trust/UX surprise, not theft | | Low | `ust1Window.ts` deposit path | Deposit has no `min_out`; rate can move between quote display and inclusion (contract design). UI should set expectations | | Low | `Ust1Page.tsx` `nowSec` | Oracle Fresh/Stale badge can lag until refetch; **submit** uses fresh wall-clock — OK for safety | | Info | `ust1Window.ts` `getUst1WindowConfig` | Config query exists but unused — no runtime cross-check that env token/window addresses match on-chain `config` | | Info | `terraGas.ts` deposit/withdraw hook names | Any CW20 `send` with those inner keys gets 800k gas — overpay-safe, not underpay | | Info | Dockerfile ARG defaults | Mainnet addresses baked — correct for Coolify prod (U7); staging without overrides also hits mainnet window | **No medium/high/critical** issues found for: authorization bypass, XSS, CW20 hook injection, wrong-token UI path, faucet conflation, prompt injection in runtime paths, or client-gate bypass that enables fund theft (chain still enforces). ### Threat areas requested | Area | Assessment | |------|------------| | Common DeFi attacks (sandwich/MEV on this path) | Window is oracle mint/redeem, not AMM pool; withdraw min-out haircut helps; deposit lacks min-out by contract | | Smart-contract attacks | Out of MR scope (no contract changes). UI correctly targets window via CW20 Send | | Database leaks | N/A — no indexer/DB changes | | Access control / privileges | Wallet-scoped executes only; no admin UI; pause/limits from chain view | | Oracle manipulation | UI gates on pause/stale/zero rate; malicious LCD can mislead quotes but execute hits real chain | | Tokenomic / economic | Fee %, per-tx, 24h remaining surfaced; fee split fields (`fee_chain_tax_bps` / `fee_cmm_protocol_bps`) unused | | E2E | **Gap** — no Playwright under `frontend-dapp/e2e` for `/ust1` (issue asked for disabled-state coverage) | --- ## Gap analysis ### Features / retail expectations **Present:** Deposit/Withdraw tabs, fee %, per-tx max, 24h remaining, oracle Fresh/Stale/Paused, Max balance, receive quote debounce, broadcast pending link, gas footnote, unavailable state when env incomplete. **Missing / weak (user-expected):** 1. Token logos on Pay/Receive rows (AC #6) 2. Withdraw **1% minimum output** disclosure 3. Oracle rate / last-update age (“updated Xm ago”) 4. Success explorer link (`getExplorerTxUrl` / `TxResultAlert` pattern used elsewhere) 5. Estimated LUNC gas before submit 6. Page tests for `oracle_paused` / `per_tx_limit` / `rolling_limit` UI (gates unit-tested; page only covers pause/stale/happy) ### UI/UX Aligned with retail copy / shell-panel patterns and low cognitive load. Weaker token identity vs Swap/Trade (no logos). Clear faucet/AMM disambiguation — good. ### Testing | Layer | Status | |-------|--------| | Unit math / gates / client / nav / gas | Strong (58 tests via verify script) | | Page component | Partial (5 tests; not all block reasons) | | Playwright E2E | **Absent** (issue recommended) | | LocalTerra round-trip | Optional / not in MR | | Mainnet smoke | Unchecked | | Happy + bad path | Good unit happy/bad for gates; UI bad-path incomplete | ### Packages / DRY / gas / practices - **Packages:** frontend-dapp, tokenlist, docker/frontend, docs, skills, Makefile — appropriate scope. - **DRY:** Clean split (`ust1WindowMath` / `Gates` / client / page). - **Gas:** Retail inventory fixture + 800k constant — follows #475 discipline. - **Best practices:** Pure gate evaluator is excellent; bigint INV-SWAP math; env triple-gate `isUst1WindowEnabled`. - **Minor:** Refetch-at-submit for `effective_swap` would reduce quote/execute drift (defense-in-depth). --- ## Required fixes before ACCEPT (or track tightly before closing #506) 1. **Render `TokenLogo` / token display** on Pay & Receive (satisfies AC #6 on-page). 2. **Add Playwright** (or equivalent e2e) for `/ust1` disabled CTA: paused, stale, over per-tx/24h; enabled when healthy. 3. **Disclose withdraw min-out slippage** (1% default) near Receive/CTA. 4. **Mainnet smoke** per runbook; record tx hashes on #506 / #502; LCD vs UI quote probe. 5. **Page-level tests** for `oracle_paused`, `per_tx_limit`, `rolling_limit` block copy. ### Nice-to-have - Oracle rate + age; success explorer link; estimated gas; env↔on-chain `config` cross-check in QA script; fresh `effective_swap` at submit. --- ## Summary Core #506 implementation is sound and security posture is appropriate for a frontend oracle window. Recommend **FIX** for logos, Playwright/disabled-state coverage, slippage disclosure, and completing mainnet verification before treating #506 as closed. No BLOCK-level security defects in the MR diff.
PlasticDigits commented 2026-08-09 06:55:09 +00:00 (Migrated from gitlab.com)

added 1 commit

  • cfd6f13d - fix(#506): logos, withdraw min-out disclosure, and /ust1 gate e2e

Compare with previous version

added 1 commit <ul><li>cfd6f13d - fix(#506): logos, withdraw min-out disclosure, and /ust1 gate e2e</li></ul> [Compare with previous version](/PlasticDigits/cl8y-dex-terraclassic/-/merge_requests/327/diffs?diff_id=1950754184&start_sha=962fe5151285fb6df68fdc74afdfb9f2ff11bece)
PlasticDigits commented 2026-08-09 07:03:11 +00:00 (Migrated from gitlab.com)

added 4 commits

  • cfd6f13d...8fa03d6f - 3 commits from branch main
  • 12be42ce - merge(main): integrate #507 wrap UX into #506 branch

Compare with previous version

added 4 commits <ul><li>cfd6f13d...8fa03d6f - 3 commits from branch <code>main</code></li><li>12be42ce - merge(main): integrate #507 wrap UX into #506 branch</li></ul> [Compare with previous version](/PlasticDigits/cl8y-dex-terraclassic/-/merge_requests/327/diffs?diff_id=1950756620&start_sha=cfd6f13d590f3bf0e55c678ac365950e9976eebc)
PlasticDigits commented 2026-08-09 07:03:26 +00:00 (Migrated from gitlab.com)

mentioned in commit 361cd8083c

mentioned in commit 361cd8083c9b7a4a019c7f8e291cc46c04dc2954
PlasticDigits (Migrated from gitlab.com) merged commit 361cd8083c into main 2026-08-09 07:03:26 +00:00
PlasticDigits commented 2026-08-09 07:05:01 +00:00 (Migrated from gitlab.com)

mentioned in issue #508

mentioned in issue #508
Sign in to join this conversation.
No reviewers
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!1045
No description provided.