Frontend: maker-facing recovery path for parked-expired limit orders (post-#120) #141

Closed
opened 2026-05-07 05:16:36 +00:00 by Brouie · 18 comments
Brouie commented 2026-05-07 05:16:36 +00:00 (Migrated from gitlab.com)

split out from #120 follow-up — @PlasticDigits asked for a frontend issue covering the maker-facing recovery path for parked-expired limit orders.

context

after the #120 contract fix landed (commit 5c744ee), expired limit orders encountered during a match walk are no longer silently dropped — they get parked and the maker can claim back their escrowed tokens via the parked-expired claim path. but the frontend dapp has no UX surface for this today. the maker has to know to call the claim path manually via cosmes / cli, which is not realistic for non-technical users.

proposed scope

  1. My Limits panel: surface parked-expired orders alongside active ones. today the panel shows active orders only. needs a status: "parked-expired" row state with a clear "Claim refund" CTA.

  2. Claim refund button. wires up the contract ClaimExpiredOrder { id } (or whatever the new entrypoint is named — confirm against contract source post-#120 fix) for the row owner. surfaces friendly revert messages on failure.

  3. Empty-state copy. if a wallet has parked expirations but no active orders, the panel should still render the parked-expired list with the recovery affordance — not an empty "no orders" message.

  4. Indexer integration. depends on the indexer-side ticket (sister #__) that distinguishes parked-expired from active. frontend reads the new field/endpoint to drive the row state.

acceptance

  • My Limits panel renders rows in parked-expired state with distinguishable visual treatment vs active
  • Claim refund button wires the contract entrypoint and surfaces friendly errors via the existing revert handler
  • Empty-state copy updated to mention "expired orders awaiting refund" if any exist for the connected wallet
  • Vitest coverage on the new row state + claim handler
  • Visual smoke against LocalTerra: post bid with expires_at = T+30s, wait for expiry, run a match walk, confirm parked row + claim button work in the dapp

blocked-by

  • indexer-side ticket distinguishing parked-expired from active (sister ticket — see #__ once filed)

cc @PlasticDigits

split out from #120 follow-up — @PlasticDigits asked for a frontend issue covering the maker-facing recovery path for parked-expired limit orders. ## context after the #120 contract fix landed (commit `5c744ee`), expired limit orders encountered during a match walk are no longer silently dropped — they get parked and the maker can claim back their escrowed tokens via the parked-expired claim path. but the frontend dapp has no UX surface for this today. the maker has to know to call the claim path manually via cosmes / cli, which is not realistic for non-technical users. ## proposed scope 1. **My Limits panel: surface parked-expired orders alongside active ones.** today the panel shows active orders only. needs a `status: "parked-expired"` row state with a clear "Claim refund" CTA. 2. **Claim refund button.** wires up the contract `ClaimExpiredOrder { id }` (or whatever the new entrypoint is named — confirm against contract source post-#120 fix) for the row owner. surfaces friendly revert messages on failure. 3. **Empty-state copy.** if a wallet has parked expirations but no active orders, the panel should still render the parked-expired list with the recovery affordance — not an empty "no orders" message. 4. **Indexer integration.** depends on the indexer-side ticket (sister #__) that distinguishes parked-expired from active. frontend reads the new field/endpoint to drive the row state. ## acceptance - [ ] My Limits panel renders rows in `parked-expired` state with distinguishable visual treatment vs active - [ ] Claim refund button wires the contract entrypoint and surfaces friendly errors via the existing revert handler - [ ] Empty-state copy updated to mention "expired orders awaiting refund" if any exist for the connected wallet - [ ] Vitest coverage on the new row state + claim handler - [ ] Visual smoke against LocalTerra: post bid with `expires_at = T+30s`, wait for expiry, run a match walk, confirm parked row + claim button work in the dapp ## blocked-by - indexer-side ticket distinguishing parked-expired from active (sister ticket — see #__ once filed) cc @PlasticDigits
Brouie commented 2026-05-07 05:17:31 +00:00 (Migrated from gitlab.com)

mentioned in issue #142

mentioned in issue #142
Brouie commented 2026-05-07 05:17:52 +00:00 (Migrated from gitlab.com)

blocked-by ticket filed: #142 (indexer parked-expired distinction).

blocked-by ticket filed: #142 (indexer parked-expired distinction).
PlasticDigits commented 2026-05-09 05:33:07 +00:00 (Migrated from gitlab.com)

mentioned in commit 98d3e53d48

mentioned in commit 98d3e53d481fec4ee345dc9c10bbe961d4ca3b28
PlasticDigits commented 2026-05-09 05:33:32 +00:00 (Migrated from gitlab.com)

Update — frontend landed on main (GitLab #141)

Implemented maker-facing recovery for parked-expired limits now that indexer #142 is on main:

Verification checklist (for QA)

  • Indexer returns lifecycle_status: parked_expired + remaining_escrow on GET .../limit-placements after a taker tx emits limit_order_expired_parked (#142).
  • /limits with wallet connected: parked row shows Claim refund; active rows unchanged; empty state mentions parked/expired path.
  • Trade tab: same panel (compact) lists parked row + claim.
  • Paused pair: place/cancel blocked; Claim refund still submits successfully for parked row (L6).
  • Successful claim removes row from default placements feed (→ refunded, excluded from default listing).
  • Vitest: npm test -- --run in frontend-dapp (new tests: limitPlacementLifecycle, limitClaimUserMessage, pair claim, transactions gas, indexer client status param).

LocalTerra smoke (from issue acceptance): post bid with expires_at = T+30s, wait, run hybrid match walk so order parks, confirm row + claim in dApp.


/cc @brouie — please verify when you have a moment; leaving #141 open until QA signs off.

## Update — frontend landed on `main` (GitLab #141) Implemented maker-facing recovery for **parked-expired** limits now that indexer **#142** is on `main`: - **`LimitOrderMyPlacementsPanel`** on **`/limits`** and the **Trade** ticket: separates **Active on book** vs **Expired — refund pending**, amber styling for parked rows, **Claim refund** → pair **`claim_expired_limit_order`** ([`pair.ts`](https://gitlab.com/PlasticDigits/cl8y-dex-terraclassic/-/blob/main/frontend-dapp/src/services/terraclassic/pair.ts)). - **Pause (L6):** claim stays available; copy updated on paused pairs. Place/cancel remain gated as before. - **Errors:** `No claimable expired-limit refund…` humanized via [`limitClaimUserMessage.ts`](https://gitlab.com/PlasticDigits/cl8y-dex-terraclassic/-/blob/main/frontend-dapp/src/utils/limitClaimUserMessage.ts) + [`tryHumanizeTerraTxMessage`](https://gitlab.com/PlasticDigits/cl8y-dex-terraclassic/-/blob/main/frontend-dapp/src/utils/humanizeTerraTxError.ts). - **Gas:** `CLAIM_EXPIRED_LIMIT_ORDER_GAS_LIMIT` (450k) in [`transactions.ts`](https://gitlab.com/PlasticDigits/cl8y-dex-terraclassic/-/blob/main/frontend-dapp/src/services/terraclassic/transactions.ts). - **Docs / agents:** [`docs/limit-orders.md`](https://gitlab.com/PlasticDigits/cl8y-dex-terraclassic/-/blob/main/docs/limit-orders.md) (#141 invariants + wiring), [`docs/frontend.md`](https://gitlab.com/PlasticDigits/cl8y-dex-terraclassic/-/blob/main/docs/frontend.md), [`skills/AGENTS_FRONTEND_LIMIT_PARKED_EXPIRED.md`](https://gitlab.com/PlasticDigits/cl8y-dex-terraclassic/-/blob/main/skills/AGENTS_FRONTEND_LIMIT_PARKED_EXPIRED.md), crosslinks in [`AGENTS_LOCALNET_TRADING_SWARM.md`](https://gitlab.com/PlasticDigits/cl8y-dex-terraclassic/-/blob/main/skills/AGENTS_LOCALNET_TRADING_SWARM.md) / [`AGENTS_TERRACLASSIC_GAS.md`](https://gitlab.com/PlasticDigits/cl8y-dex-terraclassic/-/blob/main/skills/AGENTS_TERRACLASSIC_GAS.md). ### Verification checklist (for QA) - [ ] Indexer returns **`lifecycle_status: parked_expired`** + **`remaining_escrow`** on **`GET .../limit-placements`** after a taker tx emits **`limit_order_expired_parked`** (#142). - [ ] **`/limits`** with wallet connected: parked row shows **Claim refund**; active rows unchanged; empty state mentions parked/expired path. - [ ] **Trade** tab: same panel (compact) lists parked row + claim. - [ ] **Paused pair:** place/cancel blocked; **Claim refund** still submits successfully for parked row (L6). - [ ] Successful claim removes row from default placements feed (→ **`refunded`**, excluded from default listing). - [ ] Vitest: `npm test -- --run` in **`frontend-dapp`** (new tests: `limitPlacementLifecycle`, `limitClaimUserMessage`, `pair` claim, `transactions` gas, indexer client **`status`** param). LocalTerra smoke (from issue acceptance): post bid with **`expires_at = T+30s`**, wait, run hybrid match walk so order parks, confirm row + claim in dApp. --- /cc @brouie — please verify when you have a moment; leaving **#141** open until QA signs off.
Brouie commented 2026-05-13 03:13:33 +00:00 (Migrated from gitlab.com)

mentioned in issue #120

mentioned in issue #120
Brouie commented 2026-05-13 07:23:04 +00:00 (Migrated from gitlab.com)

walked the maker-recovery frontend ship at HEAD 94adb5f. Source CLEAN, but found a state/event discrepancy that blocks the UI checklist — flagging for your call.

Source verified

  • frontend-dapp/src/services/terraclassic/pair.ts — claimExpiredLimitOrder wires to pair claim_expired_limit_order ExecuteMsg, friendly errors via limitClaimUserMessage.ts + tryHumanizeTerraTxMessage.
  • frontend-dapp/src/services/terraclassic/transactions.ts — CLAIM_EXPIRED_LIMIT_ORDER_GAS_LIMIT (450k) wired into getGasLimitForTx for claim_expired_limit_order shape (covered by existing transactions test).
  • LimitOrderMyPlacementsPanel separates Active vs "Expired — refund pending" with amber styling per the ship note.
  • Frontend reads lifecycle_status + remaining_escrow from indexer per #142 integration.

Checklist walk at HEAD 94adb5f

(6) Vitest npm test -- --run in frontend-dapp — 441/441 PASS across 62 files. Includes limitClaimUserMessage, pair claim, transactions gas, indexer client status param coverage. Verified earlier today during the #156 MR flow.

(1) Indexer returns lifecycle_status: parked_expired + remaining_escrow on /limit-placements after a taker tx emits limit_order_expired_parked — FAIL on the fresh stack, see "Discovery" below.

(2) /limits parked row shows Claim refund — blocked by (1).

(3) Trade tab compact panel — blocked by (1).

(4) Paused-pair behavior on Claim refund — policy note: the #141 ship text says claim "stays available" during pause, but the #120 reversal (b03152d / merged 2026-05-12) flipped this to claim is blocked during pause (the new assert_not_paused gate at contract.rs:551). The LimitOrderMyPlacementsPanel shipped here per the ship note pipes isPairPaused into the Claim button's disabled state with copy "Unavailable (pair paused)" — that matches the post-#120 policy correctly. Worth updating the #141 ship-note wording on item 4 since it predates the policy reversal.

(5) Successful claim removes row from default feed (→ refunded) — blocked by (1).

Discovery: parked-expired event not indexed

Repro on a fresh stack (volumes wiped, make start-qa against 94adb5f) plus is_paused query returning real {"paused":false} (so the new contract IS deployed):

  1. Placed bid order_id=1 at price=1.0, expires_at=now+90s, 10000 CORAL escrow on EMBER/CORAL (terra146y...c9mjav). Tx 32078F76B8A93652BE6945005681677C396E400F157235AACA8E599B251A9FA1, place_limit_order event present and correct.
  2. Waited past expiry (delta -5s confirmed via terrad query block).
  3. Triggered hybrid walk with hybrid:{pool_input:"0", book_input:"5000", max_maker_fills:8} (5000 EMBER from test1). Tx EBA6DECB081245B5F7823A84D404C41388DC05710A74220D78C1E573D504DEBB.
  4. Walk tx wasm events: only send / swap / transfer / transfer. No limit_order_expired_parked event. Swap event has limit_book_offer_consumed=0 and book_return_amount=0 — book leg consumed nothing.
  5. But contract state says the order IS parked:
    • limit_order:{order_id:1} → not found (removed from active book)
    • expired_limit_refund:{order_id:1} → {"order_id":1,"owner":"terra1x46r...","side":"bid","remaining":"9910","expires_at":1778646273} — escrow row present, fee 90 deducted from initial 10000
  6. Indexer disagrees with contract:
    • GET /api/v1/pairs/.../limit-placements?status=all returns the order with lifecycle_status: "active", no remaining_escrow field
    • GET ?status=parked_expired returns []
    • Sweep confirmed no other walk tx hit the pair between place (block 6890) and our walk (block 12592)

The indexer parser at indexer/src/indexer/parser.rs:714-750 is correct in shape (looks for wasm event with action=limit_order_expired_parked, reads _contract_address + order_id + remaining). The issue is the contract didn't emit the event at all in this walk, even though the order was moved to EXPIRED_LIMIT_CLAIMS.

Worth investigating:

  • whether the hybrid walk with pool_input=0, book_input=5000 enters match_bids/match_asks at all when the head bid is far below pool price (our bid at 1.0 vs pool effective ratio ~0.96 from the swap output)
  • whether there's a separate code path that moves orders into EXPIRED_LIMIT_CLAIMS without going through park_expired_limit_order_for_claim (orderbook.rs:540) — but I only found one write site at orderbook.rs:566, so this would point to some out-of-band mechanism
  • whether the hybrid book_input walk parks but elides the event when no actual fill happens (looks like an event-emission gap in that branch)

This blocks (2)(3)(5) of the UI checklist because there's nothing for the dapp to show. The frontend gate logic for parked rows is source-clean; the data simply isn't reaching it via the indexer.

Happy to file as a sister ticket if you want to keep #141 scoped to the frontend ship and track the event-emission gap separately.

source + Vitest CLEAN, UI walks blocked on indexer/contract-event discrepancy.

/cc @PlasticDigits

walked the maker-recovery frontend ship at HEAD 94adb5f. Source CLEAN, but found a state/event discrepancy that blocks the UI checklist — flagging for your call. **Source verified** - `frontend-dapp/src/services/terraclassic/pair.ts` — `claimExpiredLimitOrder` wires to pair `claim_expired_limit_order` ExecuteMsg, friendly errors via `limitClaimUserMessage.ts` + `tryHumanizeTerraTxMessage`. - `frontend-dapp/src/services/terraclassic/transactions.ts` — `CLAIM_EXPIRED_LIMIT_ORDER_GAS_LIMIT` (450k) wired into `getGasLimitForTx` for `claim_expired_limit_order` shape (covered by existing transactions test). - `LimitOrderMyPlacementsPanel` separates Active vs "Expired — refund pending" with amber styling per the ship note. - Frontend reads `lifecycle_status` + `remaining_escrow` from indexer per #142 integration. **Checklist walk at HEAD 94adb5f** (6) Vitest `npm test -- --run` in frontend-dapp — **441/441 PASS across 62 files**. Includes `limitClaimUserMessage`, `pair` claim, `transactions` gas, indexer client `status` param coverage. Verified earlier today during the #156 MR flow. (1) Indexer returns `lifecycle_status: parked_expired` + `remaining_escrow` on `/limit-placements` after a taker tx emits `limit_order_expired_parked` — **FAIL on the fresh stack**, see "Discovery" below. (2) `/limits` parked row shows Claim refund — **blocked** by (1). (3) Trade tab compact panel — **blocked** by (1). (4) Paused-pair behavior on Claim refund — **policy note**: the #141 ship text says claim "stays available" during pause, but the #120 reversal (b03152d / merged 2026-05-12) flipped this to **claim is blocked during pause** (the new `assert_not_paused` gate at contract.rs:551). The `LimitOrderMyPlacementsPanel` shipped here per the ship note pipes `isPairPaused` into the Claim button's disabled state with copy "Unavailable (pair paused)" — that matches the post-#120 policy correctly. Worth updating the #141 ship-note wording on item 4 since it predates the policy reversal. (5) Successful claim removes row from default feed (→ `refunded`) — **blocked** by (1). **Discovery: parked-expired event not indexed** Repro on a fresh stack (volumes wiped, `make start-qa` against 94adb5f) plus `is_paused` query returning real `{"paused":false}` (so the new contract IS deployed): 1. Placed bid order_id=1 at price=1.0, expires_at=now+90s, 10000 CORAL escrow on EMBER/CORAL (`terra146y...c9mjav`). Tx `32078F76B8A93652BE6945005681677C396E400F157235AACA8E599B251A9FA1`, place_limit_order event present and correct. 2. Waited past expiry (delta -5s confirmed via `terrad query block`). 3. Triggered hybrid walk with `hybrid:{pool_input:"0", book_input:"5000", max_maker_fills:8}` (5000 EMBER from test1). Tx `EBA6DECB081245B5F7823A84D404C41388DC05710A74220D78C1E573D504DEBB`. 4. **Walk tx wasm events: only `send / swap / transfer / transfer`. No `limit_order_expired_parked` event.** Swap event has `limit_book_offer_consumed=0` and `book_return_amount=0` — book leg consumed nothing. 5. **But contract state says the order IS parked:** - `limit_order:{order_id:1}` → `not found` (removed from active book) - `expired_limit_refund:{order_id:1}` → `{"order_id":1,"owner":"terra1x46r...","side":"bid","remaining":"9910","expires_at":1778646273}` — escrow row present, fee 90 deducted from initial 10000 6. **Indexer disagrees with contract:** - `GET /api/v1/pairs/.../limit-placements?status=all` returns the order with `lifecycle_status: "active"`, no `remaining_escrow` field - `GET ?status=parked_expired` returns `[]` - Sweep confirmed no other walk tx hit the pair between place (block 6890) and our walk (block 12592) The indexer parser at `indexer/src/indexer/parser.rs:714-750` is correct in shape (looks for `wasm` event with `action=limit_order_expired_parked`, reads `_contract_address` + `order_id` + `remaining`). The issue is **the contract didn't emit the event at all** in this walk, even though the order was moved to `EXPIRED_LIMIT_CLAIMS`. Worth investigating: - whether the hybrid walk with `pool_input=0, book_input=5000` enters `match_bids`/`match_asks` at all when the head bid is far below pool price (our bid at 1.0 vs pool effective ratio ~0.96 from the swap output) - whether there's a separate code path that moves orders into `EXPIRED_LIMIT_CLAIMS` without going through `park_expired_limit_order_for_claim` (`orderbook.rs:540`) — but I only found one write site at `orderbook.rs:566`, so this would point to some out-of-band mechanism - whether the hybrid `book_input` walk parks but elides the event when no actual fill happens (looks like an event-emission gap in that branch) This blocks (2)(3)(5) of the UI checklist because there's nothing for the dapp to show. The frontend gate logic for parked rows is source-clean; the data simply isn't reaching it via the indexer. Happy to file as a sister ticket if you want to keep #141 scoped to the frontend ship and track the event-emission gap separately. source + Vitest CLEAN, UI walks blocked on indexer/contract-event discrepancy. /cc @PlasticDigits
PlasticDigits commented 2026-05-13 10:58:37 +00:00 (Migrated from gitlab.com)

mentioned in commit d75a3e0783

mentioned in commit d75a3e078351a3fa92899b9931e3501d1c4e2001
PlasticDigits commented 2026-05-13 10:59:36 +00:00 (Migrated from gitlab.com)

Indexer / #141 follow-up (parked-expired visibility)

Pushed d75a3e0 on main: indexer now ingests limit_order_expired_parked (and claim_expired_limit_order) when LCD wasm logs flatten multiple logical CosmWasm actions into one attribute stream — previously we only looked at wasm_attr_last(..., "action"), so if action=swap appeared after the parked attrs, the parked transition was skipped while on-chain state still had ExpiredLimitRefund (matches your repro: contract parked, indexer stayed active).

Investigation (note 3342749920)

  • Contract: park_expired_limit_order_for_claim is the sole EXPIRED_LIMIT_CLAIMS write; it always builds the limit_order_expired_parked wasm event. expired_bid_parked_on_hybrid_walk_claim_refunds_maker (same hybrid template as your QA) asserts the event in cw-multi-test — so “no event on-chain” is unlikely for correctly decoded tx logs.
  • Off-chain / LCD: the discrepancy is consistent with REST flattening (one wasm blob, last action wins for naive whole-slice parsers). Fix: scan every action key per wasm event and parse order_id / remaining from the segment after each matching action.

Docs / agents

Verification checklist (QA)

  • Re-run your parked flow (make start-qa, place bid with expires_at, wait, hybrid walk pool_input=0 / book_input>0). After the walk tx is indexed, GET .../limit-placements?status=parked_expired includes the order with remaining_escrow.
  • Default GET .../limit-placements lists lifecycle_status: parked_expired for that order_id.
  • cargo test --lib indexer::parser::tests (or full indexer lib tests) passes locally.
  • Optional: compare raw tx (/cosmos/tx/v1beta1/txs/{hash}) — confirm whether limit_order_expired_parked attrs appear before action=swap in the same wasm event; that shape is what the fix targets.

/cc @brouie — please re-verify the #141 UI checklist on a fresh QA stack with this indexer build; leaving the issue open per prior QA sign-off policy.

## Indexer / #141 follow-up (parked-expired visibility) Pushed **`d75a3e0`** on **`main`**: indexer now ingests **`limit_order_expired_parked`** (and **`claim_expired_limit_order`**) when LCD wasm logs **flatten multiple logical CosmWasm actions into one attribute stream** — previously we only looked at **`wasm_attr_last(..., "action")`**, so if **`action=swap` appeared after** the parked attrs, the parked transition was skipped while on-chain state still had **`ExpiredLimitRefund`** (matches your repro: contract parked, indexer stayed **`active`**). **Investigation (note 3342749920)** - **Contract:** `park_expired_limit_order_for_claim` is the sole `EXPIRED_LIMIT_CLAIMS` write; it always builds the **`limit_order_expired_parked`** wasm event. `expired_bid_parked_on_hybrid_walk_claim_refunds_maker` (same hybrid template as your QA) asserts the event in cw-multi-test — so “no event on-chain” is **unlikely** for correctly decoded tx logs. - **Off-chain / LCD:** the discrepancy is consistent with **REST flattening** (one `wasm` blob, **last `action` wins** for naive whole-slice parsers). Fix: **scan every `action` key** per `wasm` event and parse **`order_id` / `remaining`** from the segment after each matching action. **Docs / agents** - [`docs/indexer-invariants.md`](https://gitlab.com/PlasticDigits/cl8y-dex-terraclassic/-/blob/main/docs/indexer-invariants.md) (lifecycle row + wasm row), [`docs/limit-orders.md`](https://gitlab.com/PlasticDigits/cl8y-dex-terraclassic/-/blob/main/docs/limit-orders.md) (indexer LCD note), [`skills/AGENTS_FRONTEND_LIMIT_PARKED_EXPIRED.md`](https://gitlab.com/PlasticDigits/cl8y-dex-terraclassic/-/blob/main/skills/AGENTS_FRONTEND_LIMIT_PARKED_EXPIRED.md), [`skills/AGENTS_LOCALNET_TRADING_SWARM.md`](https://gitlab.com/PlasticDigits/cl8y-dex-terraclassic/-/blob/main/skills/AGENTS_LOCALNET_TRADING_SWARM.md). **Verification checklist (QA)** - [ ] Re-run your parked flow (`make start-qa`, place bid with `expires_at`, wait, hybrid walk `pool_input=0` / `book_input>0`). After the walk tx is indexed, **`GET .../limit-placements?status=parked_expired`** includes the order with **`remaining_escrow`**. - [ ] Default **`GET .../limit-placements`** lists **`lifecycle_status: parked_expired`** for that `order_id`. - [ ] `cargo test --lib indexer::parser::tests` (or full indexer lib tests) passes locally. - [ ] Optional: compare raw tx (`/cosmos/tx/v1beta1/txs/{hash}`) — confirm whether **`limit_order_expired_parked`** attrs appear **before** **`action=swap`** in the same `wasm` event; that shape is what the fix targets. /cc @brouie — please re-verify the #141 UI checklist on a fresh QA stack with this indexer build; leaving the issue **open** per prior QA sign-off policy.
PlasticDigits commented 2026-05-27 03:22:21 +00:00 (Migrated from gitlab.com)

mentioned in commit b0c390b4f4

mentioned in commit b0c390b4f4f4015b920d74b776d3af8df7378f12
PlasticDigits commented 2026-05-27 03:22:33 +00:00 (Migrated from gitlab.com)

QA verification complete (GitLab #141)

Verified on LocalTerra + indexer after fixing a remaining ingestion gap.

Root cause found

The prior #141 indexer fix (merged wasm attribute-stream scanning) did not cover LocalTerra LCD wasm-wasm events. On hybrid walks that park an expired limit, limit_order_expired_parked attrs appear in a standalone wasm-wasm row (not in the flattened wasm slice with action=swap). The indexer skipped those rows, so GET .../limit-placements stayed active while on-chain ExpiredLimitRefund existed.

Fix (main b0c390b → merged cdfcbd0)

  • Parse lifecycle actions from wasm and wasm-wasm event types.
  • Stop treating duplicate contract_address keys as segment boundaries when reading attrs after lifecycle actions.
  • Added parser unit test for the wasm-wasm shape.

Checklist

  • Indexer returns lifecycle_status: parked_expired + remaining_escrow after hybrid walk parks order
  • /limits — parked row amber styling, Claim refund CTA, empty-state copy mentions recovery path
  • /trade compact panel — same parked row + claim button
  • Claim refund submits claim_expired_limit_order; success tx shown; row drops from default feed after indexer ingests refund
  • Vitest: limitPlacementLifecycle, limitClaimUserMessage, pair claim, indexer client status param — pass
  • Indexer: cargo test --lib parser::tests — 17/17 pass

Closing #141 — frontend ship was already correct; blocker was indexer LCD event-type coverage.

## QA verification complete (GitLab #141) Verified on LocalTerra + indexer after fixing a remaining ingestion gap. ### Root cause found The prior #141 indexer fix (merged `wasm` attribute-stream scanning) did not cover **LocalTerra LCD `wasm-wasm` events**. On hybrid walks that park an expired limit, `limit_order_expired_parked` attrs appear in a standalone `wasm-wasm` row (not in the flattened `wasm` slice with `action=swap`). The indexer skipped those rows, so `GET .../limit-placements` stayed `active` while on-chain `ExpiredLimitRefund` existed. ### Fix (main `b0c390b` → merged `cdfcbd0`) - Parse lifecycle actions from **`wasm` and `wasm-wasm`** event types. - Stop treating duplicate `contract_address` keys as segment boundaries when reading attrs after lifecycle `action`s. - Added parser unit test for the `wasm-wasm` shape. ### Checklist - [x] Indexer returns `lifecycle_status: parked_expired` + `remaining_escrow` after hybrid walk parks order - [x] `/limits` — parked row amber styling, **Claim refund** CTA, empty-state copy mentions recovery path - [x] `/trade` compact panel — same parked row + claim button - [x] Claim refund submits `claim_expired_limit_order`; success tx shown; row drops from default feed after indexer ingests refund - [x] Vitest: `limitPlacementLifecycle`, `limitClaimUserMessage`, `pair` claim, indexer client `status` param — pass - [x] Indexer: `cargo test --lib parser::tests` — 17/17 pass Closing #141 — frontend ship was already correct; blocker was indexer LCD event-type coverage.
PlasticDigits (Migrated from gitlab.com) closed this issue 2026-05-27 03:22:35 +00:00
PlasticDigits commented 2026-05-27 04:45:10 +00:00 (Migrated from gitlab.com)

QA re-verification (2026-05-27)

Re-verified #141 on the live LocalTerra stack (indexer :3001, frontend :3000, host Postgres).

Checklist (all pass)

  • Indexer: after hybrid walk parks an expired bid, GET .../limit-placements returns lifecycle_status: parked_expired + remaining_escrow (order #3 on EMBER/CORAL; parked tx 0EE1FEBB…).
  • Default feed: same order appears in default listing while parked; excluded after claim (refunded).
  • /limits: amber parked row, Claim refund CTA, active rows separate; empty-state copy mentions recovery path.
  • /trade compact panel: same parked row + claim button.
  • Claim: dApp submitted claim_expired_limit_order; success tx F895BE3C…D58DD1; row dropped from default feed once indexer ingested refund.
  • Vitest: limitPlacementLifecycle, limitClaimUserMessage, LimitOrderMyPlacementsPanel, pair claim — 27/27 pass.
  • Indexer tests: parser::tests 17/17; limit_order_parked_lifecycle integration pass.

No new code changes required on main (3f6a2e5); prior indexer fix (wasm-wasm LCD lifecycle parsing, cdfcbd0) resolves the blocked QA from note 3342749920.

Issue remains closed — frontend ship was correct; blocker was indexer event-type coverage, now verified end-to-end.

## QA re-verification (2026-05-27) Re-verified #141 on the live LocalTerra stack (indexer :3001, frontend :3000, host Postgres). ### Checklist (all pass) - [x] **Indexer:** after hybrid walk parks an expired bid, `GET .../limit-placements` returns `lifecycle_status: parked_expired` + `remaining_escrow` (order #3 on EMBER/CORAL; parked tx `0EE1FEBB…`). - [x] **Default feed:** same order appears in default listing while parked; excluded after claim (`refunded`). - [x] **/limits:** amber parked row, **Claim refund** CTA, active rows separate; empty-state copy mentions recovery path. - [x] **/trade** compact panel: same parked row + claim button. - [x] **Claim:** dApp submitted `claim_expired_limit_order`; success tx `F895BE3C…D58DD1`; row dropped from default feed once indexer ingested refund. - [x] **Vitest:** limitPlacementLifecycle, limitClaimUserMessage, LimitOrderMyPlacementsPanel, pair claim — 27/27 pass. - [x] **Indexer tests:** `parser::tests` 17/17; `limit_order_parked_lifecycle` integration pass. No new code changes required on `main` (`3f6a2e5`); prior indexer fix (`wasm-wasm` LCD lifecycle parsing, `cdfcbd0`) resolves the blocked QA from note 3342749920. Issue remains **closed** — frontend ship was correct; blocker was indexer event-type coverage, now verified end-to-end.
PlasticDigits commented 2026-05-27 14:45:00 +00:00 (Migrated from gitlab.com)

mentioned in issue #206

mentioned in issue #206
PlasticDigits commented 2026-05-31 13:07:56 +00:00 (Migrated from gitlab.com)

mentioned in issue #253

mentioned in issue #253
PlasticDigits commented 2026-05-31 13:52:01 +00:00 (Migrated from gitlab.com)

mentioned in issue #259

mentioned in issue #259
PlasticDigits commented 2026-06-01 05:31:24 +00:00 (Migrated from gitlab.com)

mentioned in issue #269

mentioned in issue #269
PlasticDigits commented 2026-06-01 05:40:53 +00:00 (Migrated from gitlab.com)

mentioned in commit d6701c4b00

mentioned in commit d6701c4b00eeb7693f762c8f708711ac9ef2109e
PlasticDigits commented 2026-08-16 07:14:03 +00:00 (Migrated from gitlab.com)

mentioned in issue #530

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

mentioned in issue #613

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