feat(wrap): consume fee_wrap_bps / fee_unwrap_bps for ≈2% unwrap all-in (ustr-cmm#9) #516

Closed
opened 2026-08-11 01:32:51 +00:00 by PlasticDigits · 31 comments
PlasticDigits commented 2026-08-11 01:32:51 +00:00 (Migrated from gitlab.com)

Summary

Consume wrap-mapper fee_wrap_bps / fee_unwrap_bps on the DEX (frontend + docs + ops probes) after ustr-cmm#9 migrates mainnet to 200 / 51, so unwrap quotes show user all-in ≈ 2% (fee + Classic burn tax) without InstantWithdraw gross-up.

Upstream (contracts): PlasticDigits2/ustr-cmm#9 — fee split migration + retune rule.
Supersedes gross-up follow-up called out in #512 / skills/AGENTS_WRAP_UNWRAP_BURN_TAX.md for the “make unwrap 2%” product goal (disclosure from #512 stays until fees land).


Current codebase

Live / product context

  • Wrap-mapper (columbus-5): terra1xuuuhpmyd5t29ry7mydg7ra2q2phrwhx7j28nx7x9sjw6zznkumsz0nmd2 — today single fee_bps=200.
  • Burn tax: 1.5% on treasury InstantWithdraw BankMsg::Send.
  • Unwrap all-in today: ~3.47% (2% fee + 1.5% of post-fee) — #512.
  • DEX already implements W8–W11 (#512): wrap = fee only; unwrap You Receive = post-fee then burn tax; fee note + exchange-deposit warning.

Relevant files (cl8y-dex-terraclassic)

Path Role
frontend-dapp/src/services/terraclassic/wrapMapper.ts queryWrapMapperConfig, wrapUnwrapFeeNote, config cache
frontend-dapp/src/services/terraclassic/router.ts netCw20AfterNativeWrap, netNativeAfterUnwrap, simulate native swap
frontend-dapp/src/utils/nativeTransferTax.ts LCD burn tax fetch + multiply tax
frontend-dapp/src/pages/WrapPage.tsx Wrap/Unwrap UI fee note + quotes
frontend-dapp/src/pages/SwapPage.tsx Native wrap/unwrap legs + notes
frontend-dapp/src/utils/poolProvideCounterpart.ts Provide auto-fill fee-only wrap net
frontend-dapp/src/types/index.ts Types mentioning mapper fee
skills/AGENTS_WRAP_UNWRAP_BURN_TAX.md W8–W11 + gross-up follow-up
skills/AGENTS_MAINNET_WRAP_ENABLEMENT.md W1–W7 Coolify / fee UX
NATIVE_TOKEN_WRAPPING.md Architecture + fee narrative
docs/qa-templates/wrap-unwrap-test-pass.md QA expectations (9800 vs 9653)
docs/runbooks/ust1-wrap-production-ops.md Ops fee_bps observations
deployments/mainnet-ust1-wrap/REGISTRY.md Registry fee notes
scripts/check-ust1-wrap-ops-health.sh Read-only health (fee_bps=200 checks)

Indexer: no change expected unless it indexes mapper config events/fields (verify; out of scope if unused).


Why this is needed

  • Contract change alone does not update quotes, fee copy, QA templates, or ops health probes that assume a single fee_bps.
  • After unwrap fee → 51, UI must use fee_unwrap_bps for unwrap / unwrap_output and fee_wrap_bps for wrap / wrap-input — otherwise quotes stay wrong or fall back incorrectly.
  • Docs still describe “fee_bps=200 both ways” and optional gross-up; product decision is asymmetric fees, no gross-up, with a retune rule when tax changes.
  • Coolify frontend is often behind main — ship must include consumer release + redeploy checklist.

Constraints / guardrails

  1. Blocked on ustr-cmm#9 migrate + mainnet 200/51 (or dual-read compat window documented there).
  2. Keep W8: wrap quotes never apply burn tax.
  3. Keep W9: unwrap You Receive = post-unwrap-fee then burn tax; routerMinReceiveBase stays post-fee pre-tax for router minimum_receive (R3).
  4. Keep W10/W11: single-line tax disclosure + exchange-deposit warning.
  5. Do not hardcode 51 or 200 in UI — always query on-chain config (W3 / enablement rules).
  6. No gross-up simulation in the dApp to fake 2% if chain still has old single fee — show truthful stack until config is live.
  7. Compat: during rollout, support either new fields only, or transitional { fee_bps } fallback (wrap=unwrap=fee_bps) if ustr-cmm MR provides it — match upstream choice exactly.
  8. Retune docs must live in DEX playbooks too (pointer to formula); operators may only read this repo.
  9. Do not change ust1-window fee_bps (different contract).

  1. Extend wrap-mapper config types + queryWrapMapperConfig for fee_wrap_bps / fee_unwrap_bps (compat per upstream).
  2. Thread wrap fee into wrap / wrap-input helpers; unwrap fee into unwrap / native-output helpers and fee notes.
  3. Update wrapUnwrapFeeNote examples/tests: e.g. unwrap 51 bps + 1.5% tax → all-in ≈ 2% copy still honest (“fee; You Receive after burn tax”).
  4. Refresh #512 skill: replace “gross-up follow-up” with ustr-cmm#9 asymmetric fees; keep tax math helpers.
  5. Update QA template numbers: unwrap 10 000 @ 51 bps + 1.5% → ~9 800 (not 9 653); wrap still 9 800 @ 200.
  6. Health script / REGISTRY / ops runbook: assert or display both fees; retune rule section.
  7. Extend make verify-issue-512 or add make verify-issue-NNN for dual-fee unit tests once this issue is numbered.
  8. After Coolify frontend redeploy: smoke Wrap page wrap + unwrap quotes vs LCD.

Retune rule (mirror upstream)

fee_unwrap_bps = round(10000 - 9800 / (1 - burn_tax_rate))

Example: 0.015 → 51. Goal: user unwrap all-in ≈ 2% (receive/A = 0.98), prefer ≤2% when rounding. If tax ≥ ~2%, escalate — cannot hit 2% all-in without subsidy/gross-up.


Acceptance criteria

  • Frontend queries and applies fee_wrap_bps / fee_unwrap_bps correctly on all wrap/unwrap paths (Wrap page, Swap native in/out, pool provide wrap auto-fill).
  • With mainnet 200/51 and tax 1.5%, unwrap quote for 10 000 ≈ 9 800 native You Receive (not 9 653).
  • Wrap quote for 10 000 @ 200 = 9 800 CW20; no burn tax on wrap.
  • Fee notes remain accurate (no false 1:1); exchange warning retained on unwrap.
  • Skills + NATIVE_TOKEN_WRAPPING + QA template + ops/registry/health updated for split fees + retune rule; gross-up no longer the prescribed fix for 2% all-in.
  • Unit tests updated/green; verify script for this issue passes.
  • Production checklist: Coolify frontend redeploy after chain migrate.

Test plan (all paths)

Unit

  • Config parse: both fees present; transitional fee_bps fallback if supported.
  • netCw20AfterNativeWrap uses wrap fee only.
  • netNativeAfterUnwrap uses unwrap fee then tax.
  • wrapUnwrapFeeNote for wrap vs unwrap with distinct bps + tax rate.
  • Pool provide counterpart wrap fee only.
  • WrapPage / SwapPage tests mock dual fees.

Manual / QA (docs/qa-templates/wrap-unwrap-test-pass.md)

  • Direct wrap LUNC→cLUNC and USTC→cUSTC.
  • Direct unwrap cLUNC→LUNC and cUSTC→USTC (quote = wallet delta).
  • Swap wrap_input / unwrap_output / both.
  • Fee notes + exchange-deposit warning on unwrap.
  • Paused mapper still surfaces clear errors.

Ops

  • scripts/check-ust1-wrap-ops-health.sh (or successor checks) understands split fees.
  • REGISTRY / runbook match on-chain 200/51.

Test plan (attack / hack / abuse)

  • Stale config cache after gov fee change — cache TTL/invalidation so UI cannot quote old 200 unwrap fee for long.
  • Field confusion — malicious/malformed LCD JSON missing one fee: fail closed (no quote / unavailable), not silent 0% or wrong field.
  • Hardcoded bps regression — grep/tests ensure UI does not assume 200/51 constants for math.
  • minimum_receive (R3) — cannot be set to post-tax in a way that bricks unwrap vs router expectations; abuse via tiny min receive still user-signed.
  • Exchange-deposit recipient — warning still shown; no UX that encourages contract→exchange unwrap.
  • Phishing copy — fee note must not claim “2% flat” if that implies tax-free; keep “after burn tax” when tax applies.
  • Mixed old indexer/new UI — N/A unless indexer exposes fees; ensure no dependency on indexer for fee bps.

Verification criteria

Check Pass
LCD config wrap-mapper reports fee_wrap_bps=200, fee_unwrap_bps=51
UI unwrap quote Matches post-51bps then 1.5% tax ≈ 2% all-in
UI wrap quote Fee-only 2%
Verify make target Green
Docs Retune rule discoverable from DEX skills/runbooks
Coolify Frontend assets newer than chain migrate; Wrap page smoke OK

Depends on: ustr-cmm#9.

## Summary Consume wrap-mapper **`fee_wrap_bps` / `fee_unwrap_bps`** on the DEX (frontend + docs + ops probes) after [ustr-cmm#9](https://gitlab.com/PlasticDigits2/ustr-cmm/-/work_items/9) migrates mainnet to **`200` / `51`**, so unwrap quotes show **user all-in ≈ 2%** (fee + Classic burn tax) **without InstantWithdraw gross-up**. **Upstream (contracts):** PlasticDigits2/ustr-cmm#9 — fee split migration + retune rule. **Supersedes gross-up follow-up** called out in [#512](https://gitlab.com/PlasticDigits/cl8y-dex-terraclassic/-/issues/512) / `skills/AGENTS_WRAP_UNWRAP_BURN_TAX.md` for the “make unwrap 2%” product goal (disclosure from #512 stays until fees land). --- ## Current codebase ### Live / product context - Wrap-mapper (columbus-5): `terra1xuuuhpmyd5t29ry7mydg7ra2q2phrwhx7j28nx7x9sjw6zznkumsz0nmd2` — today single **`fee_bps=200`**. - Burn tax: **1.5%** on treasury `InstantWithdraw` `BankMsg::Send`. - Unwrap all-in today: **~3.47%** (2% fee + 1.5% of post-fee) — #512. - DEX already implements **W8–W11** (#512): wrap = fee only; unwrap You Receive = post-fee then burn tax; fee note + exchange-deposit warning. ### Relevant files (cl8y-dex-terraclassic) | Path | Role | |------|------| | `frontend-dapp/src/services/terraclassic/wrapMapper.ts` | `queryWrapMapperConfig`, `wrapUnwrapFeeNote`, config cache | | `frontend-dapp/src/services/terraclassic/router.ts` | `netCw20AfterNativeWrap`, `netNativeAfterUnwrap`, simulate native swap | | `frontend-dapp/src/utils/nativeTransferTax.ts` | LCD burn tax fetch + multiply tax | | `frontend-dapp/src/pages/WrapPage.tsx` | Wrap/Unwrap UI fee note + quotes | | `frontend-dapp/src/pages/SwapPage.tsx` | Native wrap/unwrap legs + notes | | `frontend-dapp/src/utils/poolProvideCounterpart.ts` | Provide auto-fill fee-only wrap net | | `frontend-dapp/src/types/index.ts` | Types mentioning mapper fee | | `skills/AGENTS_WRAP_UNWRAP_BURN_TAX.md` | W8–W11 + gross-up follow-up | | `skills/AGENTS_MAINNET_WRAP_ENABLEMENT.md` | W1–W7 Coolify / fee UX | | `NATIVE_TOKEN_WRAPPING.md` | Architecture + fee narrative | | `docs/qa-templates/wrap-unwrap-test-pass.md` | QA expectations (9800 vs 9653) | | `docs/runbooks/ust1-wrap-production-ops.md` | Ops fee_bps observations | | `deployments/mainnet-ust1-wrap/REGISTRY.md` | Registry fee notes | | `scripts/check-ust1-wrap-ops-health.sh` | Read-only health (fee_bps=200 checks) | Indexer: no change expected unless it indexes mapper config events/fields (verify; out of scope if unused). --- ## Why this is needed - Contract change alone does not update quotes, fee copy, QA templates, or ops health probes that assume a **single** `fee_bps`. - After unwrap fee → **51**, UI must use **`fee_unwrap_bps`** for unwrap / `unwrap_output` and **`fee_wrap_bps`** for wrap / wrap-input — otherwise quotes stay wrong or fall back incorrectly. - Docs still describe “fee_bps=200 both ways” and optional gross-up; product decision is **asymmetric fees, no gross-up**, with a **retune rule** when tax changes. - Coolify frontend is often behind main — ship must include consumer release + redeploy checklist. --- ## Constraints / guardrails 1. **Blocked on** ustr-cmm#9 migrate + mainnet `200/51` (or dual-read compat window documented there). 2. **Keep W8:** wrap quotes never apply burn tax. 3. **Keep W9:** unwrap You Receive = post-**unwrap**-fee then burn tax; `routerMinReceiveBase` stays post-fee pre-tax for router `minimum_receive` (**R3**). 4. **Keep W10/W11:** single-line tax disclosure + exchange-deposit warning. 5. **Do not hardcode 51 or 200 in UI** — always query on-chain config (W3 / enablement rules). 6. **No gross-up simulation** in the dApp to fake 2% if chain still has old single fee — show truthful stack until config is live. 7. **Compat:** during rollout, support either new fields only, or transitional `{ fee_bps }` fallback (wrap=unwrap=fee_bps) if ustr-cmm MR provides it — match upstream choice exactly. 8. **Retune docs** must live in DEX playbooks too (pointer to formula); operators may only read this repo. 9. Do not change ust1-window `fee_bps` (different contract). --- ## Recommended direction 1. Extend wrap-mapper config types + `queryWrapMapperConfig` for `fee_wrap_bps` / `fee_unwrap_bps` (compat per upstream). 2. Thread **wrap fee** into wrap / wrap-input helpers; **unwrap fee** into unwrap / native-output helpers and fee notes. 3. Update `wrapUnwrapFeeNote` examples/tests: e.g. unwrap 51 bps + 1.5% tax → all-in ≈ 2% copy still honest (“fee; You Receive after burn tax”). 4. Refresh #512 skill: replace “gross-up follow-up” with **ustr-cmm#9 asymmetric fees**; keep tax math helpers. 5. Update QA template numbers: unwrap 10 000 @ 51 bps + 1.5% → **~9 800** (not 9 653); wrap still 9 800 @ 200. 6. Health script / REGISTRY / ops runbook: assert or display both fees; retune rule section. 7. Extend `make verify-issue-512` or add `make verify-issue-NNN` for dual-fee unit tests once this issue is numbered. 8. After Coolify frontend redeploy: smoke Wrap page wrap + unwrap quotes vs LCD. ### Retune rule (mirror upstream) ```text fee_unwrap_bps = round(10000 - 9800 / (1 - burn_tax_rate)) ``` Example: `0.015` → **51**. Goal: user unwrap all-in **≈ 2%** (`receive/A = 0.98`), prefer ≤2% when rounding. If tax ≥ ~2%, escalate — cannot hit 2% all-in without subsidy/gross-up. --- ## Acceptance criteria - [ ] Frontend queries and applies `fee_wrap_bps` / `fee_unwrap_bps` correctly on all wrap/unwrap paths (Wrap page, Swap native in/out, pool provide wrap auto-fill). - [ ] With mainnet 200/51 and tax 1.5%, unwrap quote for 10 000 ≈ **9 800** native You Receive (not 9 653). - [ ] Wrap quote for 10 000 @ 200 = **9 800** CW20; no burn tax on wrap. - [ ] Fee notes remain accurate (no false 1:1); exchange warning retained on unwrap. - [ ] Skills + NATIVE_TOKEN_WRAPPING + QA template + ops/registry/health updated for split fees + retune rule; gross-up no longer the prescribed fix for 2% all-in. - [ ] Unit tests updated/green; verify script for this issue passes. - [ ] Production checklist: Coolify frontend redeploy after chain migrate. --- ## Test plan (all paths) ### Unit - [ ] Config parse: both fees present; transitional `fee_bps` fallback if supported. - [ ] `netCw20AfterNativeWrap` uses wrap fee only. - [ ] `netNativeAfterUnwrap` uses unwrap fee then tax. - [ ] `wrapUnwrapFeeNote` for wrap vs unwrap with distinct bps + tax rate. - [ ] Pool provide counterpart wrap fee only. - [ ] WrapPage / SwapPage tests mock dual fees. ### Manual / QA (`docs/qa-templates/wrap-unwrap-test-pass.md`) - [ ] Direct wrap LUNC→cLUNC and USTC→cUSTC. - [ ] Direct unwrap cLUNC→LUNC and cUSTC→USTC (quote = wallet delta). - [ ] Swap `wrap_input` / `unwrap_output` / both. - [ ] Fee notes + exchange-deposit warning on unwrap. - [ ] Paused mapper still surfaces clear errors. ### Ops - [ ] `scripts/check-ust1-wrap-ops-health.sh` (or successor checks) understands split fees. - [ ] REGISTRY / runbook match on-chain 200/51. --- ## Test plan (attack / hack / abuse) - [ ] **Stale config cache** after gov fee change — cache TTL/invalidation so UI cannot quote old 200 unwrap fee for long. - [ ] **Field confusion** — malicious/malformed LCD JSON missing one fee: fail closed (no quote / unavailable), not silent 0% or wrong field. - [ ] **Hardcoded bps regression** — grep/tests ensure UI does not assume 200/51 constants for math. - [ ] **minimum_receive (R3)** — cannot be set to post-tax in a way that bricks unwrap vs router expectations; abuse via tiny min receive still user-signed. - [ ] **Exchange-deposit recipient** — warning still shown; no UX that encourages contract→exchange unwrap. - [ ] **Phishing copy** — fee note must not claim “2% flat” if that implies tax-free; keep “after burn tax” when tax applies. - [ ] **Mixed old indexer/new UI** — N/A unless indexer exposes fees; ensure no dependency on indexer for fee bps. --- ## Verification criteria | Check | Pass | |-------|------| | LCD config | wrap-mapper reports `fee_wrap_bps=200`, `fee_unwrap_bps=51` | | UI unwrap quote | Matches post-51bps then 1.5% tax ≈ 2% all-in | | UI wrap quote | Fee-only 2% | | Verify make target | Green | | Docs | Retune rule discoverable from DEX skills/runbooks | | Coolify | Frontend assets newer than chain migrate; Wrap page smoke OK | Depends on: [ustr-cmm#9](https://gitlab.com/PlasticDigits2/ustr-cmm/-/work_items/9).
PlasticDigits commented 2026-08-11 01:33:02 +00:00 (Migrated from gitlab.com)

marked as related to PlasticDigits2/ustr-cmm#9

marked as related to PlasticDigits2/ustr-cmm#9
PlasticDigits commented 2026-08-11 01:33:10 +00:00 (Migrated from gitlab.com)

mentioned in issue PlasticDigits2/ustr-cmm#9

mentioned in issue PlasticDigits2/ustr-cmm#9
PlasticDigits commented 2026-08-11 01:33:11 +00:00 (Migrated from gitlab.com)

Upstream contracts issue: https://gitlab.com/PlasticDigits2/ustr-cmm/-/work_items/9

Blocked on wrap-mapper migrate + gov set fee_wrap_bps=200 / fee_unwrap_bps=51 before production UI verification.

Upstream contracts issue: https://gitlab.com/PlasticDigits2/ustr-cmm/-/work_items/9 Blocked on wrap-mapper migrate + gov set `fee_wrap_bps=200` / `fee_unwrap_bps=51` before production UI verification.
PlasticDigits commented 2026-08-11 01:43:42 +00:00 (Migrated from gitlab.com)

mentioned in merge request PlasticDigits2/ustr-cmm!727

mentioned in merge request PlasticDigits2/ustr-cmm!727
PlasticDigits commented 2026-08-15 09:57:08 +00:00 (Migrated from gitlab.com)

mentioned in issue PlasticDigits2/ustr-cmm#13

mentioned in issue PlasticDigits2/ustr-cmm#13
PlasticDigits commented 2026-08-15 09:57:16 +00:00 (Migrated from gitlab.com)

ustr-cmm ops tracker for the bundled mainnet rollout: https://gitlab.com/PlasticDigits2/ustr-cmm/-/work_items/13

#9 code is merged; wrap-mapper is still live 11565 / fee_bps=200. Implement this issue (#516) before or in the same window as migrate — Config drops fee_bps (no dual-read).

ustr-cmm ops tracker for the bundled mainnet rollout: https://gitlab.com/PlasticDigits2/ustr-cmm/-/work_items/13 #9 code is merged; wrap-mapper is still live `11565` / `fee_bps=200`. Implement this issue (#516) before or in the same window as migrate — `Config` drops `fee_bps` (no dual-read).
PlasticDigits commented 2026-08-15 10:03:46 +00:00 (Migrated from gitlab.com)

marked as related to #521

marked as related to #521
PlasticDigits commented 2026-08-15 10:19:47 +00:00 (Migrated from gitlab.com)

mentioned in issue #521

mentioned in issue #521
PlasticDigits commented 2026-08-15 10:19:51 +00:00 (Migrated from gitlab.com)

Factory #518 upgrade on columbus-5 is done (unrelated contract). Full tx/code-id record and remaining #516 ops order: https://gitlab.com/PlasticDigits/cl8y-dex-terraclassic/-/work_items/521#note_3690047839

Re-queried wrap-mapper just now: still code 11565, { fee_bps: 200 }. Admin remains cl8y2_admin (terra1xsecn4snv94ezcez0z3vq8an9j4h4kxxcydp8l). DEX 2-of-3 was not used and must not be used for mapper migrate / SetFees.

#516 code in this repo is still outstanding. Ship it (or the Coolify artifact) before or in the same window as ustr-cmm#13 store + migrate + set_fees 200/51 — Config drops fee_bps (no dual-read).

Factory #518 upgrade on columbus-5 is **done** (unrelated contract). Full tx/code-id record and remaining #516 ops order: https://gitlab.com/PlasticDigits/cl8y-dex-terraclassic/-/work_items/521#note_3690047839 Re-queried wrap-mapper just now: still code **11565**, `{ fee_bps: 200 }`. Admin remains `cl8y2_admin` (`terra1xsecn4snv94ezcez0z3vq8an9j4h4kxxcydp8l`). DEX 2-of-3 was not used and must not be used for mapper migrate / `SetFees`. #516 code in this repo is still outstanding. Ship it (or the Coolify artifact) **before or in the same window** as [ustr-cmm#13](https://gitlab.com/PlasticDigits2/ustr-cmm/-/work_items/13) store + migrate + `set_fees` 200/51 — `Config` drops `fee_bps` (no dual-read).
PlasticDigits commented 2026-08-15 10:31:07 +00:00 (Migrated from gitlab.com)

mentioned in commit 75d9cf16d0

mentioned in commit 75d9cf16d053ed392f5de6f9018ebed2e59a9bc9
PlasticDigits commented 2026-08-15 10:31:09 +00:00 (Migrated from gitlab.com)

mentioned in merge request !1054

mentioned in merge request !1054
PlasticDigits commented 2026-08-15 10:31:20 +00:00 (Migrated from gitlab.com)

Implementation shipped in !1054 (feat/516-wrap-mapper-split-fees).

Frontend consumes fee_wrap_bps / fee_unwrap_bps (legacy { fee_bps } mapped to both sides until migrate). make verify-issue-516 green. Coolify rebuild still needed in the ustr-cmm#13 window.

DEX router wasm still deserializes wrap-mapper Config.fee_bps for unwrap_output R3 — upgrade that before or with mapper migrate (called out on the MR).

Implementation shipped in !1054 (`feat/516-wrap-mapper-split-fees`). Frontend consumes `fee_wrap_bps` / `fee_unwrap_bps` (legacy `{ fee_bps }` mapped to both sides until migrate). `make verify-issue-516` green. Coolify rebuild still needed in the ustr-cmm#13 window. DEX router wasm still deserializes wrap-mapper `Config.fee_bps` for unwrap_output R3 — upgrade that before or with mapper migrate (called out on the MR).
PlasticDigits commented 2026-08-15 11:16:10 +00:00 (Migrated from gitlab.com)

Merge review (!1054) — 2026-08-15

Verified !1054 (feat/516-wrap-mapper-split-fees @ 75d9cf1) against this issue’s acceptance criteria. No merge conflicts with current main. Merging via glab mr merge (not auto-merge; not waiting on CI).

Acceptance criteria

AC Result
Frontend applies fee_wrap_bps / fee_unwrap_bps on Wrap, Swap native in/out, pool provide wrap auto-fill Pass
Unwrap 10 000 @ 51 bps + 1.5% tax ≈ 9 800 (not 9 653) Pass (router.test.ts)
Wrap 10 000 @ 200 = 9 800 CW20; no burn tax Pass
Fee notes honest; exchange-deposit warning on unwrap Pass
Skills / NATIVE_TOKEN_WRAPPING / QA / registry / health + retune rule; gross-up no longer the 2% fix Pass
Unit tests + make verify-issue-516 Pass locally (15/15; 104 unit tests in review)
Coolify frontend redeploy after chain migrate Not done — production checklist still open

W8–W15 / fail-closed / { fee_bps } fallback / no hardcoded quote math: pass. ust1-window fee_bps untouched.

Problems / remaining work (not blocking this MR)

  1. CI on !1054 failed with ci_quota_exceeded (frontend, frontend-build, gitleaks) — not a code failure. Did not wait to re-run.
  2. DEX router wasm still deserializes wrap-mapper Config.fee_bps for on-chain unwrap_output R3. After ustr-cmm#9 migrate (Config drops fee_bps), unwrap_output settlement will fail unless router is upgraded in the same window. Already called out on the MR.
  3. Production verification still blocked on ustr-cmm#13 store + migrate + set_fees 200/51 and Coolify frontend rebuild. Until then live LCD is still { fee_bps: 200 } and UI will truthfully show ~9 653 unwrap, not 9 800.
  4. Coverage gaps (non-blocking): SwapPage has no 200/51 dual-fee UI assertion (WrapPage does). E2E wrap-mapper LCD mock still returns legacy { fee_bps: 0 } (transitional parser covers it; split-fee E2E not exercised).

Not this MR

Local uncommitted smartcontracts/artifacts/checksums.txt on main is leftover wasm-build residue (factory/pair hashes + extra ignored wasm names). Unrelated to #516; will not be committed with this merge.

## Merge review (!1054) — 2026-08-15 Verified !1054 (`feat/516-wrap-mapper-split-fees` @ `75d9cf1`) against this issue’s acceptance criteria. **No merge conflicts** with current `main`. Merging via `glab mr merge` (not auto-merge; not waiting on CI). ### Acceptance criteria | AC | Result | |----|--------| | Frontend applies `fee_wrap_bps` / `fee_unwrap_bps` on Wrap, Swap native in/out, pool provide wrap auto-fill | Pass | | Unwrap 10 000 @ 51 bps + 1.5% tax ≈ **9 800** (not 9 653) | Pass (`router.test.ts`) | | Wrap 10 000 @ 200 = **9 800** CW20; no burn tax | Pass | | Fee notes honest; exchange-deposit warning on unwrap | Pass | | Skills / NATIVE_TOKEN_WRAPPING / QA / registry / health + retune rule; gross-up no longer the 2% fix | Pass | | Unit tests + `make verify-issue-516` | Pass locally (15/15; 104 unit tests in review) | | Coolify frontend redeploy after chain migrate | **Not done** — production checklist still open | W8–W15 / fail-closed / `{ fee_bps }` fallback / no hardcoded quote math: pass. ust1-window `fee_bps` untouched. ### Problems / remaining work (not blocking this MR) 1. **CI on !1054 failed** with `ci_quota_exceeded` (frontend, frontend-build, gitleaks) — not a code failure. Did not wait to re-run. 2. **DEX router wasm** still deserializes wrap-mapper `Config.fee_bps` for on-chain `unwrap_output` R3. After ustr-cmm#9 migrate (`Config` drops `fee_bps`), unwrap_output settlement will fail unless router is upgraded in the same window. Already called out on the MR. 3. **Production verification still blocked** on [ustr-cmm#13](https://gitlab.com/PlasticDigits2/ustr-cmm/-/work_items/13) store + migrate + `set_fees` 200/51 **and** Coolify frontend rebuild. Until then live LCD is still `{ fee_bps: 200 }` and UI will truthfully show ~9 653 unwrap, not 9 800. 4. **Coverage gaps (non-blocking):** SwapPage has no 200/51 dual-fee UI assertion (WrapPage does). E2E wrap-mapper LCD mock still returns legacy `{ fee_bps: 0 }` (transitional parser covers it; split-fee E2E not exercised). ### Not this MR Local uncommitted `smartcontracts/artifacts/checksums.txt` on `main` is leftover wasm-build residue (factory/pair hashes + extra ignored wasm names). Unrelated to #516; will not be committed with this merge.
PlasticDigits commented 2026-08-15 11:16:15 +00:00 (Migrated from gitlab.com)

mentioned in commit 248b144a67

mentioned in commit 248b144a67bede2f503417df5b80f670d017dcdb
PlasticDigits (Migrated from gitlab.com) closed this issue 2026-08-15 11:16:15 +00:00
PlasticDigits commented 2026-08-15 12:02:20 +00:00 (Migrated from gitlab.com)

Upstream chain unblocked (ustr-cmm#13)

columbus-5 wrap-mapper is now the breaking Config this issue was waiting on:

!1054 frontend can quote 200/51 from LCD. Still open (not this issue’s code): Coolify rebuild + /wrap smoke, and router wasm #523 store+migrate (old router unwrap_output still expects fee_bps). Tracker: ustr-cmm#13.

Leaving closed — consumer code shipped; prod checklist is ops.

## Upstream chain unblocked (ustr-cmm#13) columbus-5 wrap-mapper is now the breaking `Config` this issue was waiting on: - code **`11574`**, cw2 `0.3.0` - `{ fee_wrap_bps: 200, fee_unwrap_bps: 51 }` — **no** `fee_bps` - txs: store [`9B305800…`](https://finder.terraclassic.community/columbus-5/tx/9B30580007763DB44DA215975D25B8046C134A46436217D462354655B5B9DA40) / migrate [`8F05225E…`](https://finder.terraclassic.community/columbus-5/tx/8F05225E53D67C3666C1E9B0929EB69A172FA3EDD2F1B750F456995820ACD107) / `SetFees` [`740CB152…`](https://finder.terraclassic.community/columbus-5/tx/740CB152259CE5D02E225064CEEFB09870FD1D07779926391B2E81FA4B5FBDF3) !1054 frontend can quote 200/51 from LCD. **Still open (not this issue’s code):** Coolify rebuild + `/wrap` smoke, and router wasm [#523](https://gitlab.com/PlasticDigits/cl8y-dex-terraclassic/-/work_items/523) store+migrate (old router `unwrap_output` still expects `fee_bps`). Tracker: [ustr-cmm#13](https://gitlab.com/PlasticDigits2/ustr-cmm/-/work_items/13). Leaving **closed** — consumer code shipped; prod checklist is ops.
PlasticDigits commented 2026-08-15 12:02:23 +00:00 (Migrated from gitlab.com)

mentioned in issue #512

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

mentioned in issue #523

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

Direct wrap/unwrap smoke (cl8ydeploy) — 2026-08-15

Live mapper 200 / 51 confirmed. This is direct treasury wrap_deposit + CW20 send unwrap — not router unwrap_output.

Wallet terra1hu4zggf3f8yw6jw3rxrjxn2drwad675gq5k2lv had 0 uusd; used 10 000 uluna (0.01 LUNC).

Step Tx Height Result
Wrap C5DDA278…D493B7 29959037 wrap_deposit 10000 uluna → mapper notify_deposit fee_wrap_bps=200 fee=200 mint=9800 cLUNC
Unwrap 58FEE7CE…F08526 29959038 send 9800 cLUNC → mapper fee_unwrap_bps=51 fee=49 withdraw=9751; InstantWithdraw; user received 9605 uluna after 1.5% tax (floor(9751×0.015)=146)

Terminal bal after wrap still showed 0 cLUNC because it ran on the sync ack before inclusion. After both included: cLUNC 0, round-trip complete.

Note: QA “unwrap 10 000 → 9 800 native” is for unwrapping 10 000 CW20. This smoke unwrapped the wrap output (9 800), so native back is 9 605, which matches 51 bps + tax on 9800.

Router unwrap_output on 1.1.0 (11576) still needs a CW20→native Swap to prove #523 settlement.

## Direct wrap/unwrap smoke (cl8ydeploy) — 2026-08-15 Live mapper **200 / 51** confirmed. This is **direct** treasury `wrap_deposit` + CW20 `send` unwrap — not router `unwrap_output`. Wallet `terra1hu4zggf3f8yw6jw3rxrjxn2drwad675gq5k2lv` had **0 uusd**; used **10 000 uluna** (0.01 LUNC). | Step | Tx | Height | Result | |------|----|--------|--------| | Wrap | [`C5DDA278…D493B7`](https://finder.terraclassic.community/mainnet/tx/C5DDA278F953B54EB7912FC9DFAF021EB056E28EB48411290F065012D9D493B7) | 29959037 | `wrap_deposit` 10000 uluna → mapper `notify_deposit` **fee_wrap_bps=200 fee=200 mint=9800** cLUNC | | Unwrap | [`58FEE7CE…F08526`](https://finder.terraclassic.community/mainnet/tx/58FEE7CEA9B1B0FB63CDF85F7F10C2578BB0D85ADBF0AC3D0F6D23FED2F08526) | 29959038 | send 9800 cLUNC → mapper **fee_unwrap_bps=51 fee=49 withdraw=9751**; InstantWithdraw; user received **9605 uluna** after 1.5% tax (`floor(9751×0.015)=146`) | Terminal `bal` after wrap still showed 0 cLUNC because it ran on the sync ack before inclusion. After both included: cLUNC **0**, round-trip complete. Note: QA “unwrap 10 000 → 9 800 native” is for unwrapping **10 000** CW20. This smoke unwrapped the wrap output (**9 800**), so native back is **9 605**, which matches 51 bps + tax on 9800. Router `unwrap_output` on 1.1.0 (`11576`) still needs a CW20→native Swap to prove #523 settlement.
PlasticDigits commented 2026-08-15 12:35:42 +00:00 (Migrated from gitlab.com)

mentioned in issue #525

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

marked as related to #525

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

marked as related to #526

marked as related to #526
PlasticDigits commented 2026-08-16 09:55:49 +00:00 (Migrated from gitlab.com)

mentioned in issue #533

mentioned in issue #533
PlasticDigits commented 2026-08-17 03:42:25 +00:00 (Migrated from gitlab.com)

mentioned in issue #539

mentioned in issue #539
PlasticDigits commented 2026-08-17 10:32:47 +00:00 (Migrated from gitlab.com)

mentioned in issue #549

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

mentioned in issue #586

mentioned in issue #586
PlasticDigits commented 2026-08-21 11:29:50 +00:00 (Migrated from gitlab.com)

mentioned in issue #587

mentioned in issue #587
PlasticDigits commented 2026-08-24 00:30:13 +00:00 (Migrated from gitlab.com)

mentioned in issue #613

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

marked as related to #613

marked as related to #613
PlasticDigits commented 2026-08-25 06:07:22 +00:00 (Migrated from gitlab.com)

mentioned in issue #614

mentioned in issue #614
PlasticDigits commented 2026-08-26 04:12:48 +00:00 (Migrated from gitlab.com)

mentioned in issue #661

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

mentioned in issue #690

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