Indexer: distinguish parked-expired limit orders from active (post-#120) #142

Closed
opened 2026-05-07 05:17:31 +00:00 by Brouie · 12 comments
Brouie commented 2026-05-07 05:17:31 +00:00 (Migrated from gitlab.com)

split out from #120 follow-up — @PlasticDigits asked for an indexer issue covering the parked-expired vs active order distinction.

context

after the #120 contract fix (commit 5c744ee), expired limit orders encountered during a match walk get parked instead of silently dropped — the maker can claim back their escrow via the new parked-expired entrypoint. but the indexer today does not distinguish parked-expired orders from active ones in its tracked state, so the frontend (#141 maker recovery path) has no way to surface them with the right UX.

proposed scope

  1. Decode the new contract events emitted by the parked-expired flow. the #120 fix adds attribute-tagged events when the match walk parks an order (instead of silently dropping). indexer needs to recognize these and write a row to track the parked state. confirm exact event/attribute names against contract source post-#120.

  2. Order status enum. today the order schema tracks active / cancelled / filled-style states. add parked_expired as a distinct state. transition rule: any order whose match-walk encounters expiry moves from active to parked_expired with the same remaining carried forward.

  3. Refund claim event handling. when the maker eventually calls the claim entrypoint, indexer should see that event and transition the row to a final refunded state (or whatever is consistent with the existing terminal-state vocabulary).

  4. API surface. existing /orders (or equivalent) endpoint needs the new state visible. consider a ?status=parked_expired filter and/or include the state inline on every order row. document on the indexer API spec.

  5. Migration. schema migration for the new state column or expanded enum. include a .down.sql (per the team rule that all migrations ship paired up/down).

acceptance

  • Indexer decodes the parked-expired event(s) emitted by the contract
  • Order schema has a distinct parked_expired state with clean transitions from active
  • Claim refund event transitions the row to a terminal refunded state
  • API exposes the state on read paths the frontend can consume
  • Migration ships paired .up.sql + .down.sql
  • Integration test: post bid → expire → match walk → verify indexer row state = parked_expired with full remaining
  • Integration test: claim refund → verify state = refunded

blocks

  • #141 (frontend maker-facing recovery path) — frontend reads the new state from the indexer to drive the parked-row UX

cc @PlasticDigits

split out from #120 follow-up — @PlasticDigits asked for an indexer issue covering the parked-expired vs active order distinction. ## context after the #120 contract fix (commit `5c744ee`), expired limit orders encountered during a match walk get parked instead of silently dropped — the maker can claim back their escrow via the new parked-expired entrypoint. but the indexer today does not distinguish parked-expired orders from active ones in its tracked state, so the frontend (#141 maker recovery path) has no way to surface them with the right UX. ## proposed scope 1. **Decode the new contract events emitted by the parked-expired flow.** the #120 fix adds attribute-tagged events when the match walk parks an order (instead of silently dropping). indexer needs to recognize these and write a row to track the parked state. confirm exact event/attribute names against contract source post-#120. 2. **Order status enum.** today the order schema tracks `active` / `cancelled` / `filled`-style states. add `parked_expired` as a distinct state. transition rule: any order whose match-walk encounters expiry moves from `active` to `parked_expired` with the same `remaining` carried forward. 3. **Refund claim event handling.** when the maker eventually calls the claim entrypoint, indexer should see that event and transition the row to a final `refunded` state (or whatever is consistent with the existing terminal-state vocabulary). 4. **API surface.** existing `/orders` (or equivalent) endpoint needs the new state visible. consider a `?status=parked_expired` filter and/or include the state inline on every order row. document on the indexer API spec. 5. **Migration.** schema migration for the new state column or expanded enum. include a `.down.sql` (per the team rule that all migrations ship paired up/down). ## acceptance - [ ] Indexer decodes the parked-expired event(s) emitted by the contract - [ ] Order schema has a distinct `parked_expired` state with clean transitions from `active` - [ ] Claim refund event transitions the row to a terminal `refunded` state - [ ] API exposes the state on read paths the frontend can consume - [ ] Migration ships paired `.up.sql` + `.down.sql` - [ ] Integration test: post bid → expire → match walk → verify indexer row state = `parked_expired` with full `remaining` - [ ] Integration test: claim refund → verify state = `refunded` ## blocks - #141 (frontend maker-facing recovery path) — frontend reads the new state from the indexer to drive the parked-row UX cc @PlasticDigits
Brouie commented 2026-05-07 05:17:52 +00:00 (Migrated from gitlab.com)

mentioned in issue #141

mentioned in issue #141
PlasticDigits commented 2026-05-07 12:05:02 +00:00 (Migrated from gitlab.com)

Scope is approved.

Scope is approved.
PlasticDigits commented 2026-05-09 05:13:46 +00:00 (Migrated from gitlab.com)

mentioned in commit b28a990eed

mentioned in commit b28a990eed3dc5aa88570b55d816507c979d7975
PlasticDigits commented 2026-05-09 05:14:18 +00:00 (Migrated from gitlab.com)

Delivered (GitLab #142)

Indexer now tracks parked-expired vs active limit placements and terminal refunded after claim.

What shipped

  • DB: limit_order_placements gains lifecycle_status (active / parked_expired / refunded), remaining_escrow, park/refund metadata. Forward migration: indexer/migrations/20260509160000_limit_order_placement_lifecycle.sql; manual rollback: indexer/migrations/revert/20260509160000_limit_order_placement_lifecycle.down.sql.
  • Ingestion: Parser handles wasm limit_order_expired_parked (with remaining) and claim_expired_limit_order (contract attrs match pair orderbook.rs / contract.rs).
  • HTTP: GET /api/v1/pairs/{addr}/limit-placements returns lifecycle_status and escrow fields on each row; default listing = active + parked_expired (hides refunded); ?status= accepts active, parked_expired, refunded, or all.
  • Docs: docs/indexer-invariants.md, docs/limit-orders.md, docs/testing.md, skills/AGENTS_LOCALNET_TRADING_SWARM.md cross-linked to #142.

Merged to main (commit b28a990).

Verification checklist

  • Apply migrations (sqlx migrate run / deploy pipeline) and confirm new columns exist.
  • cd indexer && cargo test --lib (parser unit tests incl. park/claim parsing).
  • With Postgres: TEST_DATABASE_URL=postgres://... cargo test --test limit_order_parked_lifecycle --test api_pairs.
  • Manual: indexer ingests a real/harness tx that emits limit_order_expired_parked, then row shows lifecycle_status=parked_expired and remaining_escrow matches chain.
  • After maker ClaimExpiredLimitOrder, row becomes refunded; default limit-placements no longer lists it; ?status=refunded shows it.

cc @brouie — please confirm against acceptance criteria on your side when you can (issue stays open per request).

## Delivered (GitLab #142) Indexer now tracks **parked-expired** vs **active** limit placements and terminal **refunded** after claim. ### What shipped - **DB:** `limit_order_placements` gains `lifecycle_status` (`active` / `parked_expired` / `refunded`), `remaining_escrow`, park/refund metadata. Forward migration: `indexer/migrations/20260509160000_limit_order_placement_lifecycle.sql`; manual rollback: `indexer/migrations/revert/20260509160000_limit_order_placement_lifecycle.down.sql`. - **Ingestion:** Parser handles wasm **`limit_order_expired_parked`** (with `remaining`) and **`claim_expired_limit_order`** (contract attrs match pair `orderbook.rs` / `contract.rs`). - **HTTP:** `GET /api/v1/pairs/{addr}/limit-placements` returns `lifecycle_status` and escrow fields on each row; **default** listing = **active + parked_expired** (hides **refunded**); **`?status=`** accepts `active`, `parked_expired`, `refunded`, or `all`. - **Docs:** `docs/indexer-invariants.md`, `docs/limit-orders.md`, `docs/testing.md`, `skills/AGENTS_LOCALNET_TRADING_SWARM.md` cross-linked to **#142**. Merged to `main` (commit `b28a990`). ### Verification checklist - [ ] Apply migrations (`sqlx migrate run` / deploy pipeline) and confirm new columns exist. - [ ] `cd indexer && cargo test --lib` (parser unit tests incl. park/claim parsing). - [ ] With Postgres: `TEST_DATABASE_URL=postgres://... cargo test --test limit_order_parked_lifecycle --test api_pairs`. - [ ] Manual: indexer ingests a real/harness tx that emits `limit_order_expired_parked`, then row shows `lifecycle_status=parked_expired` and `remaining_escrow` matches chain. - [ ] After maker **ClaimExpiredLimitOrder**, row becomes `refunded`; default `limit-placements` no longer lists it; `?status=refunded` shows it. cc @brouie — please confirm against acceptance criteria on your side when you can (issue stays open per request).
PlasticDigits commented 2026-05-27 02:45:23 +00:00 (Migrated from gitlab.com)

Verification complete (GitLab #142)

Verified on main @ 7f37096 — no code changes required; implementation from b28a990 meets all acceptance criteria.

Acceptance criteria

  • Indexer decodes limit_order_expired_parked and claim_expired_limit_order wasm events (parser unit tests + contract attrs match orderbook.rs / contract.rs)
  • Order schema has distinct parked_expired with active → parked_expired → refunded transitions (limit_order_lifecycle.rs)
  • Claim refund event transitions row to terminal refunded
  • API exposes lifecycle_status, remaining_escrow, park/refund metadata on GET /api/v1/pairs/{addr}/limit-placements; ?status= filter (active | parked_expired | refunded | all)
  • Migration 20260509160000_limit_order_placement_lifecycle.sql + paired revert/...down.sql
  • Integration test limit_order_parked_lifecycle::park_event_then_claim_updates_db_and_api_filters
  • Contract test expired_bid_parked_on_hybrid_walk_claim_refunds_maker

Verification checklist (delivered comment)

  • Migrations applied — confirmed columns lifecycle_status, remaining_escrow, parked_*, refunded_* on limit_order_placements
  • cargo test --lib — 38 passed (incl. park/claim parser tests)
  • TEST_DATABASE_URL=... cargo test --test limit_order_parked_lifecycle --test api_pairs — 15 passed
  • Live indexer API — lifecycle_status: "active" on real row; invalid ?status= → HTTP 400
  • Swagger UI (/swagger-ui) documents limit-placements + LimitPlacementResponse lifecycle fields
  • Park → claim flow covered by integration test (mock wasm txs through process_block_txs)

Infra: shared LocalTerra + Postgres from repo root; indexer running on :3001.

Closing as verified.

## Verification complete (GitLab #142) Verified on `main` @ `7f37096` — no code changes required; implementation from `b28a990` meets all acceptance criteria. ### Acceptance criteria - [x] Indexer decodes `limit_order_expired_parked` and `claim_expired_limit_order` wasm events (parser unit tests + contract attrs match `orderbook.rs` / `contract.rs`) - [x] Order schema has distinct `parked_expired` with `active → parked_expired → refunded` transitions (`limit_order_lifecycle.rs`) - [x] Claim refund event transitions row to terminal `refunded` - [x] API exposes `lifecycle_status`, `remaining_escrow`, park/refund metadata on `GET /api/v1/pairs/{addr}/limit-placements`; `?status=` filter (`active` | `parked_expired` | `refunded` | `all`) - [x] Migration `20260509160000_limit_order_placement_lifecycle.sql` + paired `revert/...down.sql` - [x] Integration test `limit_order_parked_lifecycle::park_event_then_claim_updates_db_and_api_filters` - [x] Contract test `expired_bid_parked_on_hybrid_walk_claim_refunds_maker` ### Verification checklist (delivered comment) - [x] Migrations applied — confirmed columns `lifecycle_status`, `remaining_escrow`, `parked_*`, `refunded_*` on `limit_order_placements` - [x] `cargo test --lib` — 38 passed (incl. park/claim parser tests) - [x] `TEST_DATABASE_URL=... cargo test --test limit_order_parked_lifecycle --test api_pairs` — 15 passed - [x] Live indexer API — `lifecycle_status: "active"` on real row; invalid `?status=` → HTTP 400 - [x] Swagger UI (`/swagger-ui`) documents `limit-placements` + `LimitPlacementResponse` lifecycle fields - [x] Park → claim flow covered by integration test (mock wasm txs through `process_block_txs`) Infra: shared LocalTerra + Postgres from repo root; indexer running on `:3001`. Closing as verified.
PlasticDigits (Migrated from gitlab.com) closed this issue 2026-05-27 02:45:25 +00:00
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 02:30:56 +00:00 (Migrated from gitlab.com)

mentioned in issue #263

mentioned in issue #263
PlasticDigits commented 2026-06-01 02:30:58 +00:00 (Migrated from gitlab.com)

marked as related to #263

marked as related to #263
PlasticDigits commented 2026-06-07 12:14:14 +00:00 (Migrated from gitlab.com)

mentioned in issue #337

mentioned in issue #337
PlasticDigits commented 2026-06-08 08:14:17 +00:00 (Migrated from gitlab.com)

mentioned in issue #339

mentioned in issue #339
PlasticDigits commented 2026-08-16 07:14:04 +00:00 (Migrated from gitlab.com)

mentioned in issue #530

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