Router unwrap_output fails after wrap-mapper drops Config.fee_bps #523

Closed
opened 2026-08-15 11:51:27 +00:00 by PlasticDigits · 19 comments
PlasticDigits commented 2026-08-15 11:51:27 +00:00 (Migrated from gitlab.com)

Problem

!1054 taught the frontend to dual-read wrap-mapper fee_wrap_bps / fee_unwrap_bps (legacy { fee_bps } only before migrate). The router wasm still deserializes dex_common::wrap_mapper::ConfigResponse.fee_bps on unwrap_output settlement (R3).

After ustr-cmm#9 migrate, mapper Config drops fee_bps (no contract dual-read). query_wasm_smart then fails, reply_swap_hop aborts, and native-out Swap reverts.

Called out as follow-up on !1054 / skills/AGENTS_WRAP_MAPPER_SPLIT_FEES.md.

Fix

  • Dual-read mapper Config in dex-common (same W13 rules as the dApp).
  • Router R3 uses fee_unwrap_bps (legacy fee_bps only when both split fields are absent).
  • Store + migrate router wasm in the same window as wrap-mapper migrate (ustr-cmm#13).

Verify

make verify-issue-NNN (unit + unwrap settlement against post-migrate Config JSON).

## Problem !1054 taught the **frontend** to dual-read wrap-mapper `fee_wrap_bps` / `fee_unwrap_bps` (legacy `{ fee_bps }` only before migrate). The **router wasm** still deserializes `dex_common::wrap_mapper::ConfigResponse.fee_bps` on `unwrap_output` settlement (**R3**). After [ustr-cmm#9](https://gitlab.com/PlasticDigits2/ustr-cmm/-/work_items/9) migrate, mapper `Config` drops `fee_bps` (no contract dual-read). `query_wasm_smart` then fails, `reply_swap_hop` aborts, and native-out Swap reverts. Called out as follow-up on !1054 / `skills/AGENTS_WRAP_MAPPER_SPLIT_FEES.md`. ## Fix - Dual-read mapper `Config` in `dex-common` (same W13 rules as the dApp). - Router R3 uses `fee_unwrap_bps` (legacy `fee_bps` only when both split fields are absent). - Store + migrate router wasm in the same window as wrap-mapper migrate ([ustr-cmm#13](https://gitlab.com/PlasticDigits2/ustr-cmm/-/work_items/13)). ## Verify `make verify-issue-NNN` (unit + unwrap settlement against post-migrate Config JSON).
PlasticDigits commented 2026-08-15 11:54:25 +00:00 (Migrated from gitlab.com)

mentioned in commit f120f2daf8

mentioned in commit f120f2daf842fe058d7a5092fa13535465af9ae3
PlasticDigits commented 2026-08-15 11:54:29 +00:00 (Migrated from gitlab.com)

mentioned in merge request !1056

mentioned in merge request !1056
PlasticDigits commented 2026-08-15 11:59:55 +00:00 (Migrated from gitlab.com)

Merge review (!1056) — residual gaps

Local sanity: make verify-issue-523 5/5 PASS (dex-common wrap_mapper dual-read, unwrap_output split Config + R3, docs/router 1.1.0, retest). GitLab CI on !1056 did not run tests — jobs failed with ci_quota_exceeded (no runner).

Code review vs #523 / W13 / R3: PASS. Dual-read matches dApp rules; post-migrate Config without fee_bps is covered by test_unwrap_output_split_fee_config_no_fee_bps.

Acceptance still open (ops)

  • Store + migrate router wasm 1.1.0 in the same window as wrap-mapper migrate + set_fees 200/51 (ustr-cmm#13). If mapper migrates first, old router unwrap_output still reverts.
  • New router + legacy { fee_bps } mapper remains compatible.

CI quota is an infra problem, not a test failure. Merging !1056 without waiting for CI per review request.

## Merge review (!1056) — residual gaps Local sanity: `make verify-issue-523` **5/5 PASS** (dex-common wrap_mapper dual-read, unwrap_output split Config + R3, docs/router 1.1.0, retest). GitLab CI on !1056 did **not** run tests — jobs failed with `ci_quota_exceeded` (no runner). Code review vs #523 / W13 / R3: **PASS**. Dual-read matches dApp rules; post-migrate Config without `fee_bps` is covered by `test_unwrap_output_split_fee_config_no_fee_bps`. ### Acceptance still open (ops) - **Store + migrate router wasm 1.1.0** in the same window as wrap-mapper migrate + `set_fees` 200/51 ([ustr-cmm#13](https://gitlab.com/PlasticDigits2/ustr-cmm/-/work_items/13)). If mapper migrates first, old router `unwrap_output` still reverts. - New router + legacy `{ fee_bps }` mapper remains compatible. CI quota is an infra problem, not a test failure. Merging !1056 without waiting for CI per review request.
PlasticDigits commented 2026-08-15 12:01:39 +00:00 (Migrated from gitlab.com)

mentioned in commit 18af28792c

mentioned in commit 18af28792cda07f1fae750c7faa92e75698598ab
PlasticDigits (Migrated from gitlab.com) closed this issue 2026-08-15 12:01:40 +00:00
PlasticDigits commented 2026-08-15 12:02:15 +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 12:02:16 +00:00 (Migrated from gitlab.com)

mentioned in issue PlasticDigits2/ustr-cmm#9

mentioned in issue PlasticDigits2/ustr-cmm#9
PlasticDigits commented 2026-08-15 12:02:20 +00:00 (Migrated from gitlab.com)

mentioned in issue #516

mentioned in issue #516
PlasticDigits commented 2026-08-15 12:02:21 +00:00 (Migrated from gitlab.com)

Wrap-mapper already migrated — router store/migrate is now live-blocking

ustr-cmm#13 store + migrate + SetFees already landed (2026-08-15). Live mapper terra1xuuuh…nmd2 is code 11574 / { fee_wrap_bps: 200, fee_unwrap_bps: 51 } with no fee_bps.

So the “same window” gate in this issue is late on the mapper side. Until router 1.1.0 (!1056) is stored and migrated, on-chain unwrap_output / native-out Swap can still revert on the old Config.fee_bps deserialize.

Leaving closed (code merged). Remaining AC is human wasm store + migrate — do that next, then Coolify smoke on ustr-cmm#13.

## Wrap-mapper already migrated — router store/migrate is now live-blocking ustr-cmm#13 store + migrate + `SetFees` **already landed** (2026-08-15). Live mapper `terra1xuuuh…nmd2` is code `11574` / `{ fee_wrap_bps: 200, fee_unwrap_bps: 51 }` with **no** `fee_bps`. So the “same window” gate in this issue is **late on the mapper side**. Until router **1.1.0** (!1056) is stored and migrated, on-chain `unwrap_output` / native-out Swap can still revert on the old `Config.fee_bps` deserialize. Leaving **closed** (code merged). Remaining AC is human wasm store + migrate — do that next, then Coolify smoke on [ustr-cmm#13](https://gitlab.com/PlasticDigits2/ustr-cmm/-/work_items/13).
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)

Preflight (columbus-5) — router migrate rollback record

Recorded 2026-08-15T12:05:33Z from operator host. Repo main @ bc61fe6.

Router (save for rollback)

Field Value
Address terra1e7s0h9ftxakwca5gxspyt4haeuaqxds6swr08ul3tsepq7el924sprrsrw
Current code_id 11507
Wasm admin terra1zlmv2xydxcusurtr6rl78wsvytdc6mfex6hep7 (DEX 2-of-3)
{"code_id":"11507","admin":"terra1zlmv2xydxcusurtr6rl78wsvytdc6mfex6hep7"}

Migrate target: store new router wasm (cw2 1.1.0) then wasm migrate with '{}' signed by that admin. Rollback = migrate back to 11507 if that code stays on chain.

Wrap-mapper (already split — #516 / ustr-cmm#13)

./scripts/check-ust1-wrap-ops-health.sh — 12 PASS / 4 WARN / 0 FAIL

Check Result
Mapper paused false
fee_wrap_bps / fee_unwrap_bps 200 / 51 (fee_bps empty)
Treasury terra16j5u6ey7a84g40sr3gd94nzg5w5fm45046k9s2347qhfpwm5fr6sem3lr2 (CMM)
Mapper governance terra1xsecn4snv94ezcez0z3vq8an9j4h4kxxcydp8l (wrap stack — do not use for router migrate)
Treasury wrapping_paused false
Solvency treasury native ≥ cLUNC / cUSTC supply
Rate limits uluna + uusd configured

Native-out Swap is unsafe on router 11507 until 1.1.0 migrate: mapper no longer returns fee_bps.

Health WARNs (not a router-migrate blocker)

From the same #503 probe:

  • ust1-window oracle stale — last_update_sec=1786769540 (2026-08-15T04:52:20Z), age 25954s vs max_oracle_age_sec=21600. Silence threshold 21600s exceeded (pager should have fired). Window/oracle not paused; fee_bps=100; rate 1225611462101223983.
  • vFDUSD inventory — treasury balance 8186501 (warn < 1e9); allowance treasury→window 0 (warn < 1e9). /ust1 redeem capacity is constrained until topped up / spender limit set.

These are wrap-window ops (#503), not DEX router wasm admin.

## Preflight (columbus-5) — router migrate rollback record Recorded 2026-08-15T12:05:33Z from operator host. Repo `main` @ `bc61fe6`. ### Router (save for rollback) | Field | Value | |-------|--------| | Address | `terra1e7s0h9ftxakwca5gxspyt4haeuaqxds6swr08ul3tsepq7el924sprrsrw` | | **Current `code_id`** | **`11507`** | | Wasm admin | `terra1zlmv2xydxcusurtr6rl78wsvytdc6mfex6hep7` (DEX 2-of-3) | ```json {"code_id":"11507","admin":"terra1zlmv2xydxcusurtr6rl78wsvytdc6mfex6hep7"} ``` Migrate target: store new router wasm (cw2 **1.1.0**) then `wasm migrate` with `'{}'` signed by that admin. Rollback = migrate back to **`11507`** if that code stays on chain. ### Wrap-mapper (already split — #516 / ustr-cmm#13) `./scripts/check-ust1-wrap-ops-health.sh` — **12 PASS / 4 WARN / 0 FAIL** | Check | Result | |-------|--------| | Mapper paused | false | | `fee_wrap_bps` / `fee_unwrap_bps` | **200 / 51** (`fee_bps` empty) | | Treasury | `terra16j5u6ey7a84g40sr3gd94nzg5w5fm45046k9s2347qhfpwm5fr6sem3lr2` (CMM) | | Mapper governance | `terra1xsecn4snv94ezcez0z3vq8an9j4h4kxxcydp8l` (wrap stack — do **not** use for router migrate) | | Treasury wrapping_paused | false | | Solvency | treasury native ≥ cLUNC / cUSTC supply | | Rate limits | uluna + uusd configured | Native-out Swap is unsafe on router **11507** until 1.1.0 migrate: mapper no longer returns `fee_bps`. ### Health WARNs (not a router-migrate blocker) From the same #503 probe: - **ust1-window oracle stale** — `last_update_sec=1786769540` (2026-08-15T04:52:20Z), age **25954s** vs `max_oracle_age_sec=21600`. Silence threshold 21600s exceeded (pager should have fired). Window/oracle not paused; `fee_bps=100`; rate `1225611462101223983`. - **vFDUSD inventory** — treasury balance `8186501` (warn &lt; 1e9); allowance treasury→window **`0`** (warn &lt; 1e9). `/ust1` redeem capacity is constrained until topped up / spender limit set. These are wrap-window ops ([#503](https://gitlab.com/PlasticDigits/cl8y-dex-terraclassic/-/issues/503)), not DEX router wasm admin.
PlasticDigits commented 2026-08-15 12:12:57 +00:00 (Migrated from gitlab.com)

Router wasm stored (columbus-5) — not migrated yet

Recorded 2026-08-15T12:12:50Z. Repo main @ bc61fe6.

Field Value
Store tx CE71DA4892CEB7DC6848449DAD9DB468E39BD5FC38A44CF95E2C010F9289E436
Height 29958940
New code_id 11576
Creator terra1hu4zggf3f8yw6jw3rxrjxn2drwad675gq5k2lv (cl8ydeploy)
data_hash 6B038FD75742A3CF99C41B712B7B7B1F0A4C5320FCA1B77A8CDDD6D26E886491 (matches local cl8y_dex_router.wasm)
Gas wanted 3320040 / used 2236001

Live router is still 11507 / admin DEX 2-of-3 terra1zlmv2xydxcusurtr6rl78wsvytdc6mfex6hep7.

Next: 2-of-3 wasm migrate router → 11576 with '{}'. Rollback target remains 11507.

## Router wasm stored (columbus-5) — not migrated yet Recorded 2026-08-15T12:12:50Z. Repo `main` @ `bc61fe6`. | Field | Value | |-------|--------| | Store tx | [`CE71DA4892CEB7DC6848449DAD9DB468E39BD5FC38A44CF95E2C010F9289E436`](https://finder.terraclassic.community/mainnet/tx/CE71DA4892CEB7DC6848449DAD9DB468E39BD5FC38A44CF95E2C010F9289E436) | | Height | `29958940` | | New **code_id** | **`11576`** | | Creator | `terra1hu4zggf3f8yw6jw3rxrjxn2drwad675gq5k2lv` (`cl8ydeploy`) | | `data_hash` | `6B038FD75742A3CF99C41B712B7B7B1F0A4C5320FCA1B77A8CDDD6D26E886491` (matches local `cl8y_dex_router.wasm`) | | Gas | wanted `3320040` / used `2236001` | Live router is still **`11507`** / admin DEX 2-of-3 `terra1zlmv2xydxcusurtr6rl78wsvytdc6mfex6hep7`. Next: 2-of-3 `wasm migrate` router → `11576` with `'{}'`. Rollback target remains **`11507`**.
PlasticDigits commented 2026-08-15 12:17:57 +00:00 (Migrated from gitlab.com)

Router migrated to 1.1.0 (columbus-5)

Recorded 2026-08-15T12:17Z. Repo main @ bc61fe6.

Field Value
Migrate tx 0D9FBBFBB7E0B9E0719EDA9B17263696103762EB943D7717FE8C37FBEE61B7D9
Height 29958992
Msg MsgMigrateContract '{}'
Sender DEX 2-of-3 terra1zlmv2xydxcusurtr6rl78wsvytdc6mfex6hep7
Router terra1e7s0h9ftxakwca5gxspyt4haeuaqxds6swr08ul3tsepq7el924sprrsrw
code_id 11507 → 11576
Admin (unchanged) terra1zlmv2xydxcusurtr6rl78wsvytdc6mfex6hep7
Gas wanted 463290 / used 157454

LCD contract_info after include: code_id=11576, admin still 2-of-3.

On-chain #523 wasm step is done. Remaining: Coolify indexer + frontend for #522, then smoke native-out unwrap/swap (mapper already 200/51). Rollback = migrate back to 11507.

## Router migrated to 1.1.0 (columbus-5) Recorded 2026-08-15T12:17Z. Repo `main` @ `bc61fe6`. | Field | Value | |-------|--------| | Migrate tx | [`0D9FBBFBB7E0B9E0719EDA9B17263696103762EB943D7717FE8C37FBEE61B7D9`](https://finder.terraclassic.community/mainnet/tx/0D9FBBFBB7E0B9E0719EDA9B17263696103762EB943D7717FE8C37FBEE61B7D9) | | Height | `29958992` | | Msg | `MsgMigrateContract` `'{}'` | | Sender | DEX 2-of-3 `terra1zlmv2xydxcusurtr6rl78wsvytdc6mfex6hep7` | | Router | `terra1e7s0h9ftxakwca5gxspyt4haeuaqxds6swr08ul3tsepq7el924sprrsrw` | | **code_id** | **`11507` → `11576`** | | Admin (unchanged) | `terra1zlmv2xydxcusurtr6rl78wsvytdc6mfex6hep7` | | Gas | wanted `463290` / used `157454` | LCD `contract_info` after include: `code_id=11576`, admin still 2-of-3. On-chain `#523` wasm step is done. Remaining: Coolify indexer + frontend for `#522`, then smoke native-out unwrap/swap (mapper already `200`/`51`). Rollback = migrate back to **`11507`**.
PlasticDigits commented 2026-08-15 12:22:59 +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:25:24 +00:00 (Migrated from gitlab.com)

Router unwrap_output smoke (columbus-5) — PASS

Router 11576 settled a native-out swap against post-migrate mapper Config (no fee_bps). This is the #523 path.

Field Value
Tx 4B3BC4B7DDAB89272CBA8EA6077E73B59617E3BF2B9A6001D91FF55A024B31E9
Height 29959066
Wallet terra1hu4zggf3f8yw6jw3rxrjxn2drwad675gq5k2lv
Route 100 000 UST1 → UST1/cUSTC pair → cUSTC → mapper unwrap → uusd
Pair hop return_amount=19924864 cUSTC (matches pre-tx router simulate)
Mapper unwrap fee_unwrap_bps=51 fee=101616 withdraw=19823248
R3 floor minimum_receive=19823248 (post-fee pre-tax) — did not revert
Tax 297348 uusd (1.5% of 19823248)
User received 19 525 900 uusd (~19.53 USTC)
Residual cUSTC 0
UST1 left 2 026 179 (was 2 126 179)
Gas wanted 2411329 / used 1630384

Old router (required Config.fee_bps) would have aborted reply_swap_hop after ustr-cmm#13. Live native-out Swap on 11576 is good.

## Router unwrap_output smoke (columbus-5) — PASS Router **11576** settled a native-out swap against post-migrate mapper Config (no `fee_bps`). This is the #523 path. | Field | Value | |-------|--------| | Tx | [`4B3BC4B7DDAB89272CBA8EA6077E73B59617E3BF2B9A6001D91FF55A024B31E9`](https://finder.terraclassic.community/mainnet/tx/4B3BC4B7DDAB89272CBA8EA6077E73B59617E3BF2B9A6001D91FF55A024B31E9) | | Height | `29959066` | | Wallet | `terra1hu4zggf3f8yw6jw3rxrjxn2drwad675gq5k2lv` | | Route | 100 000 UST1 → UST1/cUSTC pair → cUSTC → mapper unwrap → `uusd` | | Pair hop | `return_amount=19924864` cUSTC (matches pre-tx router simulate) | | Mapper | `unwrap` **fee_unwrap_bps=51** fee=101616 withdraw=**19823248** | | R3 floor | `minimum_receive=19823248` (post-fee pre-tax) — **did not revert** | | Tax | 297348 uusd (1.5% of 19823248) | | User received | **19 525 900 uusd** (~19.53 USTC) | | Residual cUSTC | 0 | | UST1 left | 2 026 179 (was 2 126 179) | | Gas | wanted 2411329 / used 1630384 | Old router (required `Config.fee_bps`) would have aborted `reply_swap_hop` after ustr-cmm#13. Live native-out Swap on `11576` is good.
PlasticDigits commented 2026-08-15 12:27:04 +00:00 (Migrated from gitlab.com)

Ops complete on columbus-5. Issue already closed by !1056.

  • Router stored 11576, migrated from 11507 (tx 0D9FBBFB…B7D9)
  • Direct wrap/unwrap 200/51 smoke passed
  • Router unwrap_output UST1→native USTC passed (tx 4B3BC4B7…31E9, fee_unwrap_bps=51, R3 floor held)

Details: https://gitlab.com/PlasticDigits/cl8y-dex-terraclassic/-/work_items/523#note_3690141115

Ops complete on columbus-5. Issue already closed by !1056. - Router stored **11576**, migrated from **11507** (tx `0D9FBBFB…B7D9`) - Direct wrap/unwrap 200/51 smoke passed - Router `unwrap_output` UST1→native USTC passed (tx `4B3BC4B7…31E9`, `fee_unwrap_bps=51`, R3 floor held) Details: https://gitlab.com/PlasticDigits/cl8y-dex-terraclassic/-/work_items/523#note_3690141115
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-22 03:10:04 +00:00 (Migrated from gitlab.com)

mentioned in issue #589

mentioned in issue #589
PlasticDigits commented 2026-08-27 11:52:22 +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#523
No description provided.