feat(frontend): treasury available-supply accounting, protocol-token CR haircut, and gated color tiers #16

Closed
opened 2026-08-17 01:06:20 +00:00 by PlasticDigits · 13 comments
PlasticDigits commented 2026-08-17 01:06:20 +00:00 (Migrated from gitlab.com)

Summary

Fix /treasury so collateralization cannot be inflated by ecosystem-issued tokens (UST1, USTR, cUSTC, cLUNC) — the same distortion as a company counting treasury stock as an asset. Haircut those legs out of LP NAV used for CR. Replace issuance mint/burn/circ with + Outstanding − CMM-owned liquidity = Available Supply, and use UST1 available supply as the CR denominator. Gate Key Ratios: show numbered ratios and the ECONOMICS color only when every CR-relevant price is loaded; otherwise the section is only the message prices not loaded, cannot display key ratios.

Depends on #11 (liability CR) and #14 (LP reserve NAV). This issue revises both: UST1/USTR LP legs leave the CR numerator; the CR denominator becomes available supply, not raw total_supply.


Current codebase

Component Path Behavior today
Treasury page frontend/src/pages/TreasuryPage.tsx Assets grid + UST1/USTR/cLUNC/cUSTC IssuanceCards + RatiosCard. Copy still says wrap LP legs are omitted because native already counts — UST1/USTR LP legs still enter CR.
Holdings skip frontend/src/utils/constants.ts TREASURY_HOLDING_SKIP_SYMBOLS Exact USTR|UST1|CLUNC|CUSTC. Raw protocol CW20s are not treasury asset rows (#11/#14).
Fetch loop frontend/src/hooks/useTreasury.ts Skips raw protocol tokens via isRawProtocolHolding — does not even query treasury balances of UST1/USTR/cLUNC/cUSTC. Issuance is CW20 token_info.total_supply only (minted = supply, burned = 0). CR denominator = full outstanding UST1.
LP NAV frontend/src/utils/lpNav.ts, lpEligibility.ts isCrEligibleLeg: ust1, ustr, other = yes; wrap/unknown = no. UST1 LP leg valued at $1 (UST1_LIABILITY_USD). Wrap legs haircut from crUsd but still in displayUsd. Fixture: UST1/USTR 10% → CR $200; UST1/cUSTC → CR $100 (UST1 kept).
Ratio math frontend/src/utils/treasuryRatios.ts CR% = (priced assets USD + LP crUsd) / whole outstanding UST1 × 100. Incomplete prices: omit + banner, still render numbers. ∞ iff outstanding UST1 query succeeded and supply === 0.
Issuance UI frontend/src/components/treasury/IssuanceCard.tsx Three rows: Outstanding (as minted) / Burned (not tracked) / Circulating Supply. Circulating === total_supply. No CMM-owned line.
Ratios UI frontend/src/components/treasury/RatiosCard.tsx Collateralization (already color-banded via CR_TIERS), USTC per UST1, Assets/Liabilities, USTR Backing. Incomplete banner + N/A. No named RED/YELLOW/GREEN/BLUE status or operational copy. Color still paints the CR number even when prices are incomplete.
USTR backing useTreasury.ts whole USTC / whole USTR outstanding — not priced assets, not available USTR.
Tiers constant CR_TIERS redBelow: 95, yellowBelow: 110, greenAtMost: 190. Matches ECONOMICS bands, not the swap/staking copy below.
Economics SSoT docs/ECONOMICS.md Same 95/110/190 bands, but describes auction lockout / minting, not the treasury-page swap + staking-reward copy in this issue.
Skills skills/frontend-ust1-ratios/SKILL.md, skills/frontend-treasury-lp-nav/SKILL.md Explicitly require UST1 LP legs in CR at $1 and USTR-in-LP as collateral. Those invariants are superseded by this issue.

Mainnet pins (do not invent):

Name Address Decimals Role
Treasury terra16j5u6ey7a84g40sr3gd94nzg5w5fm45046k9s2347qhfpwm5fr6sem3lr2 — CMM holder for “owned liquidity”
UST1 terra1f0eqgy9w7e5e7up97vjudqwx38tesf8ylx75x2lv3nwm0clry0pqmgfy72 6 Liability; not a CR asset
USTR terra1vy3kc0swag2rhn7jz6n72jp0l2ns0p6r6ez5grxq5uhj2rvs97fqfsetxv 18 Ecosystem equity-like; not a CR asset
cLUNC terra1437qslye72t7qmmahn4t5chz50r8a62g45phwkquwpyu2l62u6ksqssgdg 6 Wrap receipt; native LUNC already in treasury
cUSTC terra1nap4dxh9tv35v0ynd9m4k6zt6c0dq6weszc4j5m564kjls56hu7qcr56ch 6 Wrap receipt; native USTC already in treasury
Finder https://finder.terraclassic.community/columbus-5 — Token / treasury links

Why this is needed

  1. Treasury stock distortion. Counting UST1 (the liability) or USTR (ecosystem-issued) as assets, including the UST1/USTR share of an LP, inflates CR the same way a company booking its own shares as assets inflates equity ratios. #14 currently intends that netting (UST1 leg at $1 vs circulating supply). That still books protocol tokens on the asset side and uses gross outstanding as the liability. If CMM owns a large LP, CR looks healthier than the float available to the market.

  2. Wrap / native double-count is only half-fixed. Raw cLUNC/cUSTC are skipped and wrap LP legs are haircut, but UST1/USTR LP legs still enter crUsd. A UST1/cUSTC pool today contributes the UST1 side to CR. Under this issue it must contribute neither protocol leg — only a true external quote (vFDUSD, LUNC, ALPHA, …).

  3. Issuance cards lie about float. CW20 has no lifetime mint/burn. Showing Outstanding / Burned=0 / Circulating=total_supply hides how much of that supply sits in CMM (treasury spot + LP claims). Operators and users need Available Supply = outstanding − CMM-owned liquidity. That available UST1 is the CR denominator.

  4. Key Ratios are unsafe when prices are partial. Incomplete mode still paints a colored CR from a partial numerator. A missing ALPHA/vFDUSD/LUNC print can show GREEN/BLUE while real CR is RED. If any CR-relevant price is missing, do not display ratios at all.

  5. Tier meaning on the page must match product behavior (swap + staking rewards), not only a number color:

Color CR UST1 ↔ collateral swap Staking rewards System
RED < 95% Cannot swap UST1 for collateral No new staking rewards Recovery
YELLOW 95% ≤ CR < 110% Can swap UST1 for collateral No staking rewards Stable
GREEN 110% ≤ CR ≤ 190% Can swap UST1 for collateral Partial staking rewards issuance Healthy
BLUE > 190% (incl. ∞) Can swap UST1 for collateral Full staking rewards issuance Optimal

Constraints / guardrails

  • Not CR assets (spot or LP leg): UST1, USTR, cUSTC, cLUNC, identified by pinned addresses (and native wraps’ CW20 pins). Do not haircut a lookalike symbol. Native uluna / uusd are assets (they are not ecosystem-issued CW20s).
  • LP CR numerator = reserve NAV of legs whose kind is other only (LUNC, USTC, ALPHA, vFDUSD, other tokenlist underlyings). ust1, ustr, wrap, unknown → out of crUsd. unknown still fail-closed for that LP (crUsd = null, incomplete — which then hides Key Ratios per the price gate).
  • Display NAV may still show full LP USD (including protocol legs) so the grid is honest about what the treasury holds. Label CR-excluded legs. Protocol tokens must not appear as their own asset rows.
  • CMM-owned liquidity (per token) = treasury spot CW20 balance + pro-rata LP claims floor(reserve_i × lp_balance / total_share) across allowlisted type: "lp" pins only. Holder address = pinned treasury. Do not crawl window / wrap-mapper / airdrop / all_accounts / LCD txs (quota + abuse). Do not invent other “CMM” wallets.
  • Available Supply = outstanding − cmm_owned, clamp display at 0 if a bug would go negative; fail closed (issuance + CR incomplete / hidden), never a negative float. Outstanding = CW20 token_info.total_supply via getTokenInfoStrict (never swallow errors as supply 0).
  • CR denominator = UST1 available supply (whole tokens), not raw outstanding, not USTR, not window volume. ∞ only when UST1 supply query and CMM-owned query succeeded and available supply === 0. Query failure → Key Ratios hidden or N/A path under the price/data gate — never ∞.
  • Liability unit remains 1 UST1 = $1 for the ratio (CR% = assetsUsd / available_UST1 × 100). Do not put UST1 into the numerator at $1 anymore.
  • Price gate (hard): Key Ratios renders the four tiles + color only if every CR-relevant holding is priced (spot non-protocol balances with balance > 0, and every LP other leg that would enter crUsd). Price queries still loading, CEX/DEX/oracle miss, or incomplete === true → replace the entire Key Ratios card body with exactly: prices not loaded, cannot display key ratios. No CR number, no N/A tiles, no incomplete banner, no color, no USTC-per-UST1, no A/L, no USTR backing.
  • Do not treat missing USD as $0 or $1. vFDUSD still session oracle (#10). Do not simulate_swap LP mints.
  • Decimals: UST1/wraps/native 6; USTR 18; CL8Y LP mint 18. rawToWholeNumber only.
  • Skip-list exactness: UST1-USTR is not UST1. type: "lp" never uses the raw-protocol skip.
  • This issue is frontend accounting / UX. Do not change on-chain mint/swap/staking gates unless a follow-up issue says so. Page copy describes intended system state; it must not claim the contracts already enforce these tiers if they do not.
  • Docs: amend frontend-ust1-ratios and frontend-treasury-lp-nav skills (UST1/USTR legs out of CR; available supply). Align docs/ECONOMICS.md treasury-facing tier copy with the table above or explicitly mark auction wording as historical — do not leave the page saying “healthy GREEN” while ECONOMICS still says GREEN is “redemption auctions” without a pointer.
  • Reuse contractService LCD spacing; no faster poll than current treasury refetch.

Relevant files

File Role
frontend/src/hooks/useTreasury.ts Fetch protocol-token treasury balances + LP claims; compute available supply; new CR inputs
frontend/src/utils/treasuryRatios.ts (+ .test.ts) Denominator = available UST1; numerator excludes protocol tokens
frontend/src/utils/lpEligibility.ts (+ .test.ts) isCrEligibleLeg → other only
frontend/src/utils/lpNav.ts (+ .test.ts) Haircut ust1/ustr/wrap; optional claim amounts for CMM-owned
frontend/src/services/treasuryLp.ts Already has legs/shares — reuse for CMM-owned claims
frontend/src/types/treasury.ts Issuance: outstanding, cmmOwned, availableSupply; ratios: pricesReady, tier
frontend/src/components/treasury/IssuanceCard.tsx +Outstanding / −CMM-owned / Available Supply
frontend/src/components/treasury/RatiosCard.tsx Price gate; named color + operational copy
frontend/src/components/treasury/TreasuryAssetsCard.tsx LP CR note: protocol legs omitted (not only wraps)
frontend/src/pages/TreasuryPage.tsx Copy for available supply + CR haircut
frontend/src/utils/constants.ts CR_TIERS + skip list (keep); drop/repurpose UST1_LIABILITY_USD for CR legs
frontend/src/hooks/usePrices.ts Surface “all CR prices ready” (or derive in useTreasury)
skills/frontend-ust1-ratios/SKILL.md, skills/frontend-treasury-lp-nav/SKILL.md Supersede UST1/USTR-in-CR invariants
docs/ECONOMICS.md, docs/ARCHITECTURE.md Available-supply CR + tier copy

  1. Protocol inventory (not asset rows) — in fetchTreasuryData, query treasury CW20 balances for pinned UST1, USTR, cLUNC, cUSTC. Keep them out of assets / the holdings grid.

  2. CMM-owned from LPs — for each allowlisted LP with lp_balance > 0 and valid reserves, add claim_raw of each protocol leg to that token’s cmmOwned. Fail closed if pool query fails but LP balance > 0 (cannot certify available supply).

  3. IssuanceCard — replace the three mint/burn/circ rows with:

    • + Outstanding = total_supply
    • − CMM-owned liquidity = spot + LP claims
    • Available Supply = outstanding − CMM-owned (emphasized; footnote: UST1 available supply is the CR denominator). Same card for UST1, USTR, cLUNC, cUSTC. Drop the dishonest “Burned (not tracked)” row.
  4. isCrEligibleLeg — return true only for kind === 'other'. Update lpNav fixtures: UST1/USTR → crUsd = 0 (display may still be $200); UST1/cUSTC → crUsd = 0; UST1/vFDUSD → CR = vFDUSD side only; cLUNC/LUNC → CR = LUNC side only (unchanged).

  5. computeTreasuryRatios — take ust1AvailableRaw. Numerator = spot non-protocol USD + LP crUsd. Denominator = whole available UST1. Keep ∞ / NaN rules with available supply. Redefine or remove USTR Backing: do not keep USTC/USTR outstanding as a “backing” number. Prefer dropping that tile in favor of the named CR color + operational lines (swap / rewards / system state). Keep USTC per available UST1 and Assets/Liabilities x.

  6. RatiosCard price gate — pricesReady && !incomplete && ust1SupplyStatus !== 'unknown' (and CMM-owned known). Else single message, nothing else. When ready: color the CR number and show the tier name (RED/YELLOW/GREEN/BLUE) with the three operational bullets from the table. ∞ → BLUE.

  7. Boundaries (inclusive as implemented today): < 95 RED; [95, 110) YELLOW; [110, 190] GREEN; > 190 BLUE.


Acceptance criteria

  • Raw UST1 / USTR / cLUNC / cUSTC still absent from Treasury Assets rows.
  • LP crUsd excludes UST1, USTR, cUSTC, and cLUNC legs; only non-protocol (other) legs enter CR.
  • UST1/USTR LP does not increase CR (both legs protocol). UST1/vFDUSD (or USTR/LUNC) increases CR by the external leg only.
  • Each issuance card shows + Outstanding, − CMM-owned liquidity, Available Supply (not minted/burned/circ).
  • CMM-owned = treasury spot + allowlisted LP claims; matches independent pool {} + balance math.
  • CR denominator = UST1 available supply; CR numerator = priced non-protocol assets + LP other NAV.
  • Available UST1 0 (queries succeeded) → ratios ∞ and BLUE only if prices are fully loaded.
  • If any CR-relevant price is missing or still loading: Key Ratios shows only prices not loaded, cannot display key ratios.
  • When prices are fully loaded: Key Ratios shows CR (colored), named tier, and the swap / staking-rewards / system-state copy for that band; YELLOW/GREEN/BLUE allow swap-for-collateral copy; RED says cannot swap; GREEN partial rewards; BLUE full rewards.
  • Unpriced = not $0 / $1; no LP mint simulate_swap; skip-list still exact.
  • Skills + ECONOMICS/ARCHITECTURE updated so #11/#14 “UST1/USTR LP legs are CR collateral” is no longer the invariant.

Test plan (all paths)

Holdings / haircut

  • Raw protocol tokens never appear in the asset grid; ALPHA/vFDUSD/LUNC/USTC still do.
  • UST1-USTR LP row still appears when treasury LP balance > 0; crUsd = 0.
  • UST1/cUSTC: display may include both; crUsd = 0.
  • cLUNC/LUNC: crUsd = LUNC claim USD only.
  • USTR/LUNC: crUsd = LUNC only (USTR out — regression vs #14).
  • UST1/vFDUSD: crUsd = vFDUSD claim USD only; vFDUSD from session oracle.
  • Fake cUSTC address in an unlisted pair: not in CR. Unknown leg on a pinned LP → crUsd = null → Key Ratios hidden.
  • total_share == 0 / lp_balance > total_share / failed pool: fail closed for that LP and for CMM-owned of its protocol legs.

Available supply

  • Outstanding matches token_info.total_supply.
  • Spot-only: treasury holds X UST1, no LP → CMM-owned X, available supply − X.
  • LP-only: 10% of pool with 1000 UST1 reserve → CMM-owned UST1 100 (floor).
  • Spot + LP: owned is the sum; available uses the sum once (no double-subtract of the same LP token mint).
  • CMM-owned 0 → available = outstanding.
  • CMM-owned would exceed outstanding → no negative available; fail closed.
  • Same three-line card for USTR (18dp), cLUNC, cUSTC.
  • UST1 getTokenInfo failure → no fake ∞; Key Ratios hidden or gated.
  • Testnet empty addresses: no query storm.

CR math

  • Fixture: 1e6 outstanding, 0 CMM-owned, $2e6 non-protocol assets → 200% / 2.00x / BLUE.
  • Same assets, treasury owns 500k UST1 (spot or LP claim) → denominator 500k → 400% (assets unchanged; UST1 not in numerator).
  • Add UST1/USTR LP with display $200 → CR unchanged.
  • Add UST1/vFDUSD LP crUsd = 100_000 → CR numerator +100k only.
  • USTC per UST1 uses available UST1.
  • Decimals: USTR 18 vs UST1 6 claims; rawToWholeNumber only.

Key Ratios UI

  • Prices loading → only the not-loaded message.
  • LUNC/USTC CEX fail while those assets (or LP other legs) are in the numerator → only the not-loaded message.
  • vFDUSD oracle miss with vFDUSD in treasury → only the not-loaded message.
  • ALPHA unpriced, ALPHA balance > 0 → only the not-loaded message (no partial GREEN CR).
  • All CR prices present → tiles + named color + three operational lines.
  • CR 94.99 RED; 95 YELLOW; 109.99 YELLOW; 110 GREEN; 190 GREEN; 190.01 BLUE; ∞ BLUE.
  • RED copy: cannot swap, no new staking rewards, recovery. YELLOW: can swap, no rewards, stable. GREEN: can swap, partial rewards, healthy. BLUE: can swap, full rewards, optimal.
  • Loading skeleton for issuance/assets may remain; Key Ratios must not flash a colored % then hide.

Integration

  • cd frontend && npm test — update #14 fixtures that expected UST1/USTR in crUsd.
  • LCD spacing unchanged; treasury refetch updates available supply when LP reserves move.

Test plan (attack, hack, abuse)

Vector Risk Test / guard
Treasury stock as asset UST1/USTR in numerator inflates CR Unit: protocol legs never in crUsd; grep isCrEligibleLeg only other
Gross outstanding denominator CMM-owned UST1 still treated as public liability (or double-counted with old $1 leg) Available supply only; UST1 not in numerator
Wrap + native double-count cUSTC LP + treasury uusd Wrap legs out of CR; native USTC still in
Lookalike wrap/UST1 Fake CW20 named cUSTC/UST1 Pin addresses only
Skip-list substring UST1-USTR skipped as holding Exact symbol set; LP type never skipped
Unlisted LP donation Worthless LP sent to treasury Tokenlist pins only
Factory crawl / pairs dump LCD ban + attacker pairs No pairs pagination
Simulate-swap LP mint Manipulable spot ≠ NAV No getTokenPriceUsd(lpAddress)
Partial prices → fake GREEN Hide undercollateralization Entire Key Ratios replaced by not-loaded message
Unpriced = $0 Fake RED / panic Gate, do not sum as 0
Unpriced = $1 Fake BLUE Never invent $1 except leftover display of UST1 quantity, not CR USD
CMM-owned undercount Ignore LP claims → available too high → CR too low (or opposite if also in assets) Fixture spot+LP sum; fail closed on bad pool
CMM-owned overcount Count LP mint and both reserves, or other contracts Owned is token claims, not LP CW20 amount as UST1; treasury address only
Negative available Overflow / bad math Clamp + fail closed
getTokenInfo swallow 0 Fake ∞ / BLUE getTokenInfoStrict; failure hides ratios
Number(bigint) >2^53 lie rawToWholeNumber
Decimal mix 18 vs 6 → 10^12 CR error USTR-18 + UST1-6 fixtures
Query-string pair Wrong contract Pins + isTerraContractAddress
vFDUSD DEX path Oracle bypass Session oracle only
Over-share LP Claim > 100% of pool Fail closed
Double-count same LP Duplicate tokenlist rows One row per LP address
Finder / message spoof Phishing Pinned finder; exact not-loaded string; noopener
LCD MITM garbage Huge reserves Non-finite / negative → fail closed + ratios hidden
Tier copy vs contracts UI claims swaps/rewards locked when chain still allows (or vice versa) Copy is status display; do not imply on-chain enforcement without a contract issue

Verification criteria

  1. Independent calculator on live mainnet: CR = (Σ non-protocol spot USD + Σ LP other-leg NAV) / whole(UST1 available) × 100 matches the page when prices are complete.
  2. UST1 available = total_supply − treasury_spot_UST1 − Σ LP UST1 claims; same for USTR/cLUNC/cUSTC on their cards.
  3. Grep: isCrEligibleLeg does not return true for ust1 or ustr; no protocol symbol in the CR asset loop except as LP display / CMM-owned inventory.
  4. With network throttled / CEX down: Key Ratios is only prices not loaded, cannot display key ratios — no colored %, no N/A grid.
  5. With prices complete: visible named color matches 95/110/190 table including ∞ → BLUE.
  6. Skills #11/#14 no longer require UST1/USTR LP legs in CR; ECONOMICS/ARCHITECTURE mention available-supply CR.
  7. cd frontend && npm test green with updated fixtures.
## Summary Fix `/treasury` so collateralization cannot be inflated by ecosystem-issued tokens (UST1, USTR, cUSTC, cLUNC) — the same distortion as a company counting treasury stock as an asset. Haircut those legs out of LP NAV used for CR. Replace issuance mint/burn/circ with **+ Outstanding − CMM-owned liquidity = Available Supply**, and use **UST1 available supply** as the CR denominator. Gate Key Ratios: show numbered ratios and the ECONOMICS color **only when every CR-relevant price is loaded**; otherwise the section is **only** the message `prices not loaded, cannot display key ratios`. Depends on [#11](https://gitlab.com/PlasticDigits2/ustr-cmm/-/issues/11) (liability CR) and [#14](https://gitlab.com/PlasticDigits2/ustr-cmm/-/issues/14) (LP reserve NAV). This issue **revises** both: UST1/USTR LP legs leave the CR numerator; the CR denominator becomes available supply, not raw `total_supply`. --- ## Current codebase | Component | Path | Behavior today | |-----------|------|----------------| | Treasury page | `frontend/src/pages/TreasuryPage.tsx` | Assets grid + UST1/USTR/cLUNC/cUSTC `IssuanceCard`s + `RatiosCard`. Copy still says wrap LP legs are omitted because native already counts — **UST1/USTR LP legs still enter CR**. | | Holdings skip | `frontend/src/utils/constants.ts` `TREASURY_HOLDING_SKIP_SYMBOLS` | Exact `USTR\|UST1\|CLUNC\|CUSTC`. Raw protocol CW20s are **not** treasury asset rows (#11/#14). | | Fetch loop | `frontend/src/hooks/useTreasury.ts` | Skips raw protocol tokens via `isRawProtocolHolding` — **does not even query** treasury balances of UST1/USTR/cLUNC/cUSTC. Issuance is CW20 `token_info.total_supply` only (`minted = supply`, `burned = 0`). CR denominator = full outstanding UST1. | | LP NAV | `frontend/src/utils/lpNav.ts`, `lpEligibility.ts` | `isCrEligibleLeg`: **ust1, ustr, other = yes**; wrap/unknown = no. UST1 LP leg valued at `$1` (`UST1_LIABILITY_USD`). Wrap legs haircut from `crUsd` but still in `displayUsd`. Fixture: UST1/USTR 10% → **CR $200**; UST1/cUSTC → **CR $100** (UST1 kept). | | Ratio math | `frontend/src/utils/treasuryRatios.ts` | `CR% = (priced assets USD + LP crUsd) / whole outstanding UST1 × 100`. Incomplete prices: omit + banner, **still render numbers**. `∞` iff outstanding UST1 query succeeded and supply `=== 0`. | | Issuance UI | `frontend/src/components/treasury/IssuanceCard.tsx` | Three rows: Outstanding (as minted) / Burned (not tracked) / Circulating Supply. Circulating === `total_supply`. No CMM-owned line. | | Ratios UI | `frontend/src/components/treasury/RatiosCard.tsx` | Collateralization (already color-banded via `CR_TIERS`), USTC per UST1, Assets/Liabilities, USTR Backing. Incomplete banner + N/A. **No named RED/YELLOW/GREEN/BLUE status or operational copy.** Color still paints the CR number even when prices are incomplete. | | USTR backing | `useTreasury.ts` | `whole USTC / whole USTR outstanding` — **not** priced assets, **not** available USTR. | | Tiers constant | `CR_TIERS` | `redBelow: 95`, `yellowBelow: 110`, `greenAtMost: 190`. Matches ECONOMICS bands, **not** the swap/staking copy below. | | Economics SSoT | `docs/ECONOMICS.md` | Same 95/110/190 bands, but describes **auction lockout / minting**, not the treasury-page swap + staking-reward copy in this issue. | | Skills | `skills/frontend-ust1-ratios/SKILL.md`, `skills/frontend-treasury-lp-nav/SKILL.md` | Explicitly require UST1 LP legs in CR at $1 and USTR-in-LP as collateral. **Those invariants are superseded by this issue.** | **Mainnet pins (do not invent):** | Name | Address | Decimals | Role | |------|---------|----------|------| | Treasury | `terra16j5u6ey7a84g40sr3gd94nzg5w5fm45046k9s2347qhfpwm5fr6sem3lr2` | — | CMM holder for “owned liquidity” | | UST1 | `terra1f0eqgy9w7e5e7up97vjudqwx38tesf8ylx75x2lv3nwm0clry0pqmgfy72` | 6 | Liability; **not** a CR asset | | USTR | `terra1vy3kc0swag2rhn7jz6n72jp0l2ns0p6r6ez5grxq5uhj2rvs97fqfsetxv` | 18 | Ecosystem equity-like; **not** a CR asset | | cLUNC | `terra1437qslye72t7qmmahn4t5chz50r8a62g45phwkquwpyu2l62u6ksqssgdg` | 6 | Wrap receipt; native LUNC already in treasury | | cUSTC | `terra1nap4dxh9tv35v0ynd9m4k6zt6c0dq6weszc4j5m564kjls56hu7qcr56ch` | 6 | Wrap receipt; native USTC already in treasury | | Finder | `https://finder.terraclassic.community/columbus-5` | — | Token / treasury links | --- ## Why this is needed 1. **Treasury stock distortion.** Counting UST1 (the liability) or USTR (ecosystem-issued) as assets, including the UST1/USTR **share of an LP**, inflates CR the same way a company booking its own shares as assets inflates equity ratios. #14 currently **intends** that netting (UST1 leg at $1 vs circulating supply). That still books protocol tokens on the asset side and uses **gross** outstanding as the liability. If CMM owns a large LP, CR looks healthier than the float available to the market. 2. **Wrap / native double-count is only half-fixed.** Raw cLUNC/cUSTC are skipped and wrap LP legs are haircut, but UST1/USTR LP legs still enter `crUsd`. A `UST1/cUSTC` pool today contributes the **UST1** side to CR. Under this issue it must contribute **neither** protocol leg — only a true external quote (vFDUSD, LUNC, ALPHA, …). 3. **Issuance cards lie about float.** CW20 has no lifetime mint/burn. Showing Outstanding / Burned=0 / Circulating=`total_supply` hides how much of that supply sits in CMM (treasury spot + LP claims). Operators and users need **Available Supply** = outstanding − CMM-owned liquidity. That available UST1 is the CR denominator. 4. **Key Ratios are unsafe when prices are partial.** Incomplete mode still paints a colored CR from a **partial** numerator. A missing ALPHA/vFDUSD/LUNC print can show GREEN/BLUE while real CR is RED. If any CR-relevant price is missing, **do not display ratios at all**. 5. **Tier meaning on the page must match product behavior** (swap + staking rewards), not only a number color: | Color | CR | UST1 ↔ collateral swap | Staking rewards | System | |-------|----|------------------------|-----------------|--------| | **RED** | `< 95%` | Cannot swap UST1 for collateral | No new staking rewards | Recovery | | **YELLOW** | `95% ≤ CR < 110%` | Can swap UST1 for collateral | No staking rewards | Stable | | **GREEN** | `110% ≤ CR ≤ 190%` | Can swap UST1 for collateral | Partial staking rewards issuance | Healthy | | **BLUE** | `> 190%` (incl. `∞`) | Can swap UST1 for collateral | Full staking rewards issuance | Optimal | --- ## Constraints / guardrails - **Not CR assets (spot or LP leg):** UST1, USTR, cUSTC, cLUNC, identified by **pinned addresses** (and native wraps’ CW20 pins). Do not haircut a lookalike symbol. Native `uluna` / `uusd` **are** assets (they are not ecosystem-issued CW20s). - **LP CR numerator** = reserve NAV of legs whose kind is **`other` only** (LUNC, USTC, ALPHA, vFDUSD, other tokenlist underlyings). `ust1`, `ustr`, `wrap`, `unknown` → **out of `crUsd`**. `unknown` still fail-closed for that LP (`crUsd = null`, incomplete — which then **hides Key Ratios** per the price gate). - **Display NAV** may still show full LP USD (including protocol legs) so the grid is honest about what the treasury holds. Label CR-excluded legs. Protocol tokens must **not** appear as their own asset rows. - **CMM-owned liquidity** (per token) = treasury **spot CW20 balance** + **pro-rata LP claims** `floor(reserve_i × lp_balance / total_share)` across allowlisted `type: "lp"` pins only. Holder address = pinned **treasury**. Do **not** crawl window / wrap-mapper / airdrop / `all_accounts` / LCD txs (quota + abuse). Do not invent other “CMM” wallets. - **Available Supply** = `outstanding − cmm_owned`, clamp display at `0` if a bug would go negative; **fail closed** (issuance + CR incomplete / hidden), never a negative float. Outstanding = CW20 `token_info.total_supply` via `getTokenInfoStrict` (never swallow errors as supply `0`). - **CR denominator** = **UST1 available supply** (whole tokens), not raw outstanding, not USTR, not window volume. `∞` only when UST1 supply query **and** CMM-owned query succeeded **and** available supply `=== 0`. Query failure → Key Ratios hidden or N/A path under the price/data gate — **never** `∞`. - **Liability unit** remains 1 UST1 = `$1` for the **ratio** (`CR% = assetsUsd / available_UST1 × 100`). Do **not** put UST1 into the numerator at $1 anymore. - **Price gate (hard):** Key Ratios renders the four tiles + color **only if** every CR-relevant holding is priced (spot non-protocol balances with `balance > 0`, and every LP `other` leg that would enter `crUsd`). Price queries still loading, CEX/DEX/oracle miss, or `incomplete === true` → **replace the entire Key Ratios card body** with exactly: `prices not loaded, cannot display key ratios`. No CR number, no N/A tiles, no incomplete banner, no color, no USTC-per-UST1, no A/L, no USTR backing. - **Do not** treat missing USD as `$0` or `$1`. vFDUSD still session oracle (#10). Do not `simulate_swap` LP mints. - **Decimals:** UST1/wraps/native 6; USTR 18; CL8Y LP mint 18. `rawToWholeNumber` only. - **Skip-list exactness:** `UST1-USTR` is not `UST1`. `type: "lp"` never uses the raw-protocol skip. - **This issue is frontend accounting / UX.** Do not change on-chain mint/swap/staking gates unless a follow-up issue says so. Page copy describes intended system state; it must not claim the contracts already enforce these tiers if they do not. - **Docs:** amend `frontend-ust1-ratios` and `frontend-treasury-lp-nav` skills (UST1/USTR legs **out** of CR; available supply). Align `docs/ECONOMICS.md` treasury-facing tier **copy** with the table above or explicitly mark auction wording as historical — do not leave the page saying “healthy GREEN” while ECONOMICS still says GREEN is “redemption auctions” without a pointer. - Reuse `contractService` LCD spacing; no faster poll than current treasury refetch. --- ## Relevant files | File | Role | |------|------| | `frontend/src/hooks/useTreasury.ts` | Fetch protocol-token treasury balances + LP claims; compute available supply; new CR inputs | | `frontend/src/utils/treasuryRatios.ts` (+ `.test.ts`) | Denominator = available UST1; numerator excludes protocol tokens | | `frontend/src/utils/lpEligibility.ts` (+ `.test.ts`) | `isCrEligibleLeg` → **`other` only** | | `frontend/src/utils/lpNav.ts` (+ `.test.ts`) | Haircut ust1/ustr/wrap; optional claim amounts for CMM-owned | | `frontend/src/services/treasuryLp.ts` | Already has legs/shares — reuse for CMM-owned claims | | `frontend/src/types/treasury.ts` | Issuance: outstanding, cmmOwned, availableSupply; ratios: pricesReady, tier | | `frontend/src/components/treasury/IssuanceCard.tsx` | +Outstanding / −CMM-owned / Available Supply | | `frontend/src/components/treasury/RatiosCard.tsx` | Price gate; named color + operational copy | | `frontend/src/components/treasury/TreasuryAssetsCard.tsx` | LP CR note: protocol legs omitted (not only wraps) | | `frontend/src/pages/TreasuryPage.tsx` | Copy for available supply + CR haircut | | `frontend/src/utils/constants.ts` | `CR_TIERS` + skip list (keep); drop/repurpose `UST1_LIABILITY_USD` for CR legs | | `frontend/src/hooks/usePrices.ts` | Surface “all CR prices ready” (or derive in `useTreasury`) | | `skills/frontend-ust1-ratios/SKILL.md`, `skills/frontend-treasury-lp-nav/SKILL.md` | Supersede UST1/USTR-in-CR invariants | | `docs/ECONOMICS.md`, `docs/ARCHITECTURE.md` | Available-supply CR + tier copy | --- ## Recommended direction 1. **Protocol inventory (not asset rows)** — in `fetchTreasuryData`, query treasury CW20 balances for pinned UST1, USTR, cLUNC, cUSTC. Keep them **out** of `assets` / the holdings grid. 2. **CMM-owned from LPs** — for each allowlisted LP with `lp_balance > 0` and valid reserves, add `claim_raw` of each protocol leg to that token’s `cmmOwned`. Fail closed if pool query fails but LP balance `> 0` (cannot certify available supply). 3. **IssuanceCard** — replace the three mint/burn/circ rows with: - `+ Outstanding` = `total_supply` - `− CMM-owned liquidity` = spot + LP claims - **Available Supply** = outstanding − CMM-owned (emphasized; footnote: UST1 available supply is the CR denominator). Same card for UST1, USTR, cLUNC, cUSTC. Drop the dishonest “Burned (not tracked)” row. 4. **`isCrEligibleLeg`** — return true **only** for `kind === 'other'`. Update `lpNav` fixtures: UST1/USTR → `crUsd = 0` (display may still be $200); UST1/cUSTC → `crUsd = 0`; UST1/vFDUSD → CR = vFDUSD side only; cLUNC/LUNC → CR = LUNC side only (unchanged). 5. **`computeTreasuryRatios`** — take `ust1AvailableRaw`. Numerator = spot non-protocol USD + LP `crUsd`. Denominator = whole available UST1. Keep `∞` / `NaN` rules with available supply. Redefine or **remove** USTR Backing: do not keep USTC/USTR outstanding as a “backing” number. Prefer dropping that tile in favor of the named CR color + operational lines (swap / rewards / system state). Keep USTC per **available** UST1 and Assets/Liabilities `x`. 6. **`RatiosCard` price gate** — `pricesReady && !incomplete && ust1SupplyStatus !== 'unknown'` (and CMM-owned known). Else single message, nothing else. When ready: color the CR number **and** show the tier name (RED/YELLOW/GREEN/BLUE) with the three operational bullets from the table. `∞` → BLUE. 7. **Boundaries** (inclusive as implemented today): `< 95` RED; `[95, 110)` YELLOW; `[110, 190]` GREEN; `> 190` BLUE. --- ## Acceptance criteria - [ ] Raw UST1 / USTR / cLUNC / cUSTC still **absent** from Treasury Assets rows. - [ ] LP `crUsd` excludes UST1, USTR, cUSTC, and cLUNC legs; only non-protocol (`other`) legs enter CR. - [ ] UST1/USTR LP does **not** increase CR (both legs protocol). UST1/vFDUSD (or USTR/LUNC) increases CR by the **external** leg only. - [ ] Each issuance card shows `+ Outstanding`, `− CMM-owned liquidity`, **Available Supply** (not minted/burned/circ). - [ ] CMM-owned = treasury spot + allowlisted LP claims; matches independent `pool {}` + balance math. - [ ] CR denominator = UST1 **available** supply; CR numerator = priced non-protocol assets + LP `other` NAV. - [ ] Available UST1 `0` (queries succeeded) → ratios `∞` and BLUE **only if** prices are fully loaded. - [ ] If any CR-relevant price is missing or still loading: Key Ratios shows **only** `prices not loaded, cannot display key ratios`. - [ ] When prices are fully loaded: Key Ratios shows CR (colored), named tier, and the swap / staking-rewards / system-state copy for that band; YELLOW/GREEN/BLUE allow swap-for-collateral copy; RED says cannot swap; GREEN partial rewards; BLUE full rewards. - [ ] Unpriced = not `$0` / `$1`; no LP mint `simulate_swap`; skip-list still exact. - [ ] Skills + ECONOMICS/ARCHITECTURE updated so #11/#14 “UST1/USTR LP legs are CR collateral” is no longer the invariant. --- ## Test plan (all paths) **Holdings / haircut** - [ ] Raw protocol tokens never appear in the asset grid; ALPHA/vFDUSD/LUNC/USTC still do. - [ ] `UST1-USTR` LP row still appears when treasury LP balance `> 0`; `crUsd = 0`. - [ ] `UST1/cUSTC`: display may include both; `crUsd = 0`. - [ ] `cLUNC/LUNC`: `crUsd` = LUNC claim USD only. - [ ] `USTR/LUNC`: `crUsd` = LUNC only (USTR **out** — regression vs #14). - [ ] `UST1/vFDUSD`: `crUsd` = vFDUSD claim USD only; vFDUSD from session oracle. - [ ] Fake `cUSTC` address in an unlisted pair: not in CR. Unknown leg on a **pinned** LP → `crUsd = null` → Key Ratios hidden. - [ ] `total_share == 0` / `lp_balance > total_share` / failed pool: fail closed for that LP and for CMM-owned of its protocol legs. **Available supply** - [ ] Outstanding matches `token_info.total_supply`. - [ ] Spot-only: treasury holds `X` UST1, no LP → CMM-owned `X`, available `supply − X`. - [ ] LP-only: 10% of pool with 1000 UST1 reserve → CMM-owned UST1 `100` (floor). - [ ] Spot + LP: owned is the **sum**; available uses the sum once (no double-subtract of the same LP token mint). - [ ] CMM-owned `0` → available = outstanding. - [ ] CMM-owned would exceed outstanding → no negative available; fail closed. - [ ] Same three-line card for USTR (18dp), cLUNC, cUSTC. - [ ] UST1 `getTokenInfo` failure → no fake `∞`; Key Ratios hidden or gated. - [ ] Testnet empty addresses: no query storm. **CR math** - [ ] Fixture: 1e6 outstanding, 0 CMM-owned, $2e6 non-protocol assets → 200% / 2.00x / BLUE. - [ ] Same assets, treasury owns 500k UST1 (spot or LP claim) → denominator 500k → 400% (assets unchanged; UST1 not in numerator). - [ ] Add UST1/USTR LP with display $200 → CR **unchanged**. - [ ] Add UST1/vFDUSD LP `crUsd = 100_000` → CR numerator +100k only. - [ ] USTC per UST1 uses **available** UST1. - [ ] Decimals: USTR 18 vs UST1 6 claims; `rawToWholeNumber` only. **Key Ratios UI** - [ ] Prices loading → only the not-loaded message. - [ ] LUNC/USTC CEX fail while those assets (or LP other legs) are in the numerator → only the not-loaded message. - [ ] vFDUSD oracle miss with vFDUSD in treasury → only the not-loaded message. - [ ] ALPHA unpriced, ALPHA balance `> 0` → only the not-loaded message (no partial GREEN CR). - [ ] All CR prices present → tiles + named color + three operational lines. - [ ] CR `94.99` RED; `95` YELLOW; `109.99` YELLOW; `110` GREEN; `190` GREEN; `190.01` BLUE; `∞` BLUE. - [ ] RED copy: cannot swap, no new staking rewards, recovery. YELLOW: can swap, no rewards, stable. GREEN: can swap, partial rewards, healthy. BLUE: can swap, full rewards, optimal. - [ ] Loading skeleton for issuance/assets may remain; Key Ratios must not flash a colored % then hide. **Integration** - [ ] `cd frontend && npm test` — update #14 fixtures that expected UST1/USTR in `crUsd`. - [ ] LCD spacing unchanged; treasury refetch updates available supply when LP reserves move. --- ## Test plan (attack, hack, abuse) | Vector | Risk | Test / guard | |--------|------|----------------| | **Treasury stock as asset** | UST1/USTR in numerator inflates CR | Unit: protocol legs never in `crUsd`; grep `isCrEligibleLeg` only `other` | | **Gross outstanding denominator** | CMM-owned UST1 still treated as public liability (or double-counted with old $1 leg) | Available supply only; UST1 not in numerator | | **Wrap + native double-count** | cUSTC LP + treasury `uusd` | Wrap legs out of CR; native USTC still in | | **Lookalike wrap/UST1** | Fake CW20 named `cUSTC`/`UST1` | Pin addresses only | | **Skip-list substring** | `UST1-USTR` skipped as holding | Exact symbol set; LP type never skipped | | **Unlisted LP donation** | Worthless LP sent to treasury | Tokenlist pins only | | **Factory crawl / pairs dump** | LCD ban + attacker pairs | No `pairs` pagination | | **Simulate-swap LP mint** | Manipulable spot ≠ NAV | No `getTokenPriceUsd(lpAddress)` | | **Partial prices → fake GREEN** | Hide undercollateralization | Entire Key Ratios replaced by not-loaded message | | **Unpriced = $0** | Fake RED / panic | Gate, do not sum as 0 | | **Unpriced = $1** | Fake BLUE | Never invent $1 except leftover display of UST1 **quantity**, not CR USD | | **CMM-owned undercount** | Ignore LP claims → available too high → CR too low (or opposite if also in assets) | Fixture spot+LP sum; fail closed on bad pool | | **CMM-owned overcount** | Count LP mint **and** both reserves, or other contracts | Owned is token **claims**, not LP CW20 amount as UST1; treasury address only | | **Negative available** | Overflow / bad math | Clamp + fail closed | | **`getTokenInfo` swallow 0** | Fake `∞` / BLUE | `getTokenInfoStrict`; failure hides ratios | | **`Number(bigint)`** | >2^53 lie | `rawToWholeNumber` | | **Decimal mix** | 18 vs 6 → 10^12 CR error | USTR-18 + UST1-6 fixtures | | **Query-string pair** | Wrong contract | Pins + `isTerraContractAddress` | | **vFDUSD DEX path** | Oracle bypass | Session oracle only | | **Over-share LP** | Claim > 100% of pool | Fail closed | | **Double-count same LP** | Duplicate tokenlist rows | One row per LP address | | **Finder / message spoof** | Phishing | Pinned finder; exact not-loaded string; `noopener` | | **LCD MITM garbage** | Huge reserves | Non-finite / negative → fail closed + ratios hidden | | **Tier copy vs contracts** | UI claims swaps/rewards locked when chain still allows (or vice versa) | Copy is status **display**; do not imply on-chain enforcement without a contract issue | --- ## Verification criteria 1. Independent calculator on live mainnet: `CR = (Σ non-protocol spot USD + Σ LP other-leg NAV) / whole(UST1 available) × 100` matches the page when prices are complete. 2. UST1 available = `total_supply − treasury_spot_UST1 − Σ LP UST1 claims`; same for USTR/cLUNC/cUSTC on their cards. 3. Grep: `isCrEligibleLeg` does not return true for `ust1` or `ustr`; no protocol symbol in the CR asset loop except as LP **display** / CMM-owned inventory. 4. With network throttled / CEX down: Key Ratios is **only** `prices not loaded, cannot display key ratios` — no colored %, no N/A grid. 5. With prices complete: visible named color matches 95/110/190 table including `∞` → BLUE. 6. Skills #11/#14 no longer require UST1/USTR LP legs in CR; ECONOMICS/ARCHITECTURE mention available-supply CR. 7. `cd frontend && npm test` green with updated fixtures.
PlasticDigits commented 2026-08-17 01:06:21 +00:00 (Migrated from gitlab.com)

marked as related to #11

marked as related to #11
PlasticDigits commented 2026-08-17 01:06:36 +00:00 (Migrated from gitlab.com)

marked as related to #14

marked as related to #14
PlasticDigits commented 2026-08-24 00:10:51 +00:00 (Migrated from gitlab.com)

Also need to check treasury holdings as its receiving tokens from cl8y dex, so should load token list and possibly use indexer data from cl8y dex to speed up page loads and reduce lcd/rpc calls. Protocol tokens such as cUSTC, cLUNC, USTR and UST1 held by treasury should not be included in the CR in either numerator or denominator to prevent double counting

Also need to check treasury holdings as its receiving tokens from cl8y dex, so should load token list and possibly use indexer data from cl8y dex to speed up page loads and reduce lcd/rpc calls. Protocol tokens such as cUSTC, cLUNC, USTR and UST1 held by treasury should not be included in the CR in either numerator or denominator to prevent double counting
PlasticDigits commented 2026-08-24 00:18:39 +00:00 (Migrated from gitlab.com)

mentioned in commit 77c4a4ea0d

mentioned in commit 77c4a4ea0d29b24fb959e71354c7d1d6f6353927
PlasticDigits commented 2026-08-24 00:18:42 +00:00 (Migrated from gitlab.com)

mentioned in merge request !34

mentioned in merge request !34
PlasticDigits commented 2026-08-24 00:19:07 +00:00 (Migrated from gitlab.com)

mentioned in merge request !35

mentioned in merge request !35
PlasticDigits commented 2026-08-24 00:32:38 +00:00 (Migrated from gitlab.com)

mentioned in commit f4319ae280

mentioned in commit f4319ae28074a3ab6b54adb684cd6e1e5ea233e2
PlasticDigits (Migrated from gitlab.com) closed this issue 2026-08-24 00:32:39 +00:00
PlasticDigits commented 2026-08-24 00:33:09 +00:00 (Migrated from gitlab.com)

mentioned in commit c121ff58ea

mentioned in commit c121ff58ea04bc108ea35cd98681a18f56f96c17
PlasticDigits commented 2026-08-24 00:33:52 +00:00 (Migrated from gitlab.com)

Merge verification for !35 (merged into master as f4319ae).

Acceptance criteria (code + unit tests): all 11 PASS. Combined tree after stacking !36 is 80/80 frontend tests green (availableSupply, treasuryRatios, lpNav, lpEligibility, crTiers).

Problems / leftover (not merge-blocking):

  1. Live mainnet independent CR calculator was not run in this merge pass. Verification criterion 1 (page CR matches (non-protocol spot USD + LP other NAV) / available UST1) still needs a post-deploy check on ust1cmm.com.
  2. CL8Y DEX holdings / indexer from the earlier note on this issue is out of scope of !35. Treasury still depends on tokenlist pins + LCD; no indexer ingest. Tracked as a follow-up issue.
  3. Cosmetic: if UST1 inventory/query is unknown (not just a missing price), Key Ratios still shows exactly prices not loaded, cannot display key ratios. Matches the skill, but the string is imprecise for inventory failures.
  4. No RatiosCard/IssuanceCard component or Playwright coverage — gates are unit-tested + wired, not rendered in E2E.

On-chain CR / swap / staking-reward enforcement remains explicitly out of scope (page copy is status display only).

Merge verification for !35 (merged into `master` as `f4319ae`). **Acceptance criteria (code + unit tests): all 11 PASS.** Combined tree after stacking !36 is `80/80` frontend tests green (`availableSupply`, `treasuryRatios`, `lpNav`, `lpEligibility`, `crTiers`). **Problems / leftover (not merge-blocking):** 1. **Live mainnet independent CR calculator was not run in this merge pass.** Verification criterion 1 (page CR matches `(non-protocol spot USD + LP other NAV) / available UST1`) still needs a post-deploy check on `ust1cmm.com`. 2. **CL8Y DEX holdings / indexer** from the earlier note on this issue is out of scope of !35. Treasury still depends on tokenlist pins + LCD; no indexer ingest. Tracked as a follow-up issue. 3. **Cosmetic:** if UST1 inventory/query is unknown (not just a missing price), Key Ratios still shows exactly `prices not loaded, cannot display key ratios`. Matches the skill, but the string is imprecise for inventory failures. 4. **No RatiosCard/IssuanceCard component or Playwright coverage** — gates are unit-tested + wired, not rendered in E2E. On-chain CR / swap / staking-reward enforcement remains explicitly out of scope (page copy is status display only).
PlasticDigits commented 2026-08-24 00:34:02 +00:00 (Migrated from gitlab.com)

mentioned in issue #18

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

marked as related to #18

marked as related to #18
PlasticDigits commented 2026-08-24 00:34:09 +00:00 (Migrated from gitlab.com)

Post-merge leftovers tracked in #18 (live CR calculator, CL8Y holdings/indexer, Key Ratios copy nit).

Post-merge leftovers tracked in #18 (live CR calculator, CL8Y holdings/indexer, Key Ratios copy nit).
PlasticDigits commented 2026-08-27 10:22:15 +00:00 (Migrated from gitlab.com)

mentioned in merge request !39

mentioned in merge request !39
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/ustr-cmm#16
No description provided.