OE-3 UI: Limit Ladder — Placed orders appear in "My Limits" but not in Order Book until hard refresh #298

Closed
opened 2026-06-03 16:57:36 +00:00 by totdking · 8 comments
totdking commented 2026-06-03 16:57:36 +00:00 (Migrated from gitlab.com)
No description provided.
totdking commented 2026-06-03 16:58:48 +00:00 (Migrated from gitlab.com)

Found during: OE-3 checklist testing — Limit ladder placement and order book display

Summary:

After a successful ladder placement, the placed orders appear immediately in the "My Limits (Indexer) — Active on Book" panel but are absent from the Order Book depth display until the page is hard-refreshed. The order book query is not invalidated on ladder placement success, causing a stale-data split where the user sees their orders confirmed in one panel but missing from the book.


Reproduction steps

  1. Navigate to /limits, connect Keplr wallet, select a pair
  2. Open the Limit Ladder panel, configure a valid ladder, and submit
  3. Wait for placement success confirmation
  4. Observe: "My Limits (Indexer)" panel shows the new orders as "Active on Book" ✓
  5. Observe: the Order Book (ASKS / BIDS panels above) does not show the new orders ✗
  6. Hard-refresh the page (Cmd+Shift+R / F5)
  7. Observe: the Order Book now shows the orders correctly ✓

Expected behavior

After a successful ladder placement, both the "My Limits" panel and the Order Book should update simultaneously without requiring a page reload.


Actual behavior

  • "My Limits (Indexer)" updates immediately (correct)
  • Order Book panel remains stale — placed orders are invisible in the book until hard refresh
  • This creates a split-state where the user's confirmed orders exist on-chain and in the indexer but are not reflected in the book depth display

Verified root cause (code read and confirmed)

LimitOrderLadderPanel.tsx onSuccess handler (lines 164–181) only invalidates one query key:

onSuccess: async (txHash) => {
  void queryClient.invalidateQueries({ queryKey: ['limitPlacements', pairAddress] })
  // ... polling loop for My Limits panel
}

This drives the "My Limits" panel only. The Order Book depth display is driven by separate query keys that are never invalidated:

Query key Drives Invalidated on ladder success?
['limitPlacements', pairAddress] My Limits / Active on Book ✓ Yes
['limitBookPage', pairAddress] Order Book depth (bids/asks) ✗ No
['tradeBestBook', pairAddress] Best bid/ask price display ✗ No

Compare to TradeOrderTicket.tsx single-order onSuccess (lines 447–451) which invalidates all five keys including limitBookPage and tradeBestBook:

queryClient.invalidateQueries({ queryKey: ['limitPlacements'] })
queryClient.invalidateQueries({ queryKey: ['tokenBalance'] })
queryClient.invalidateQueries({ queryKey: ['limitBookPage', pairAddr] })
queryClient.invalidateQueries({ queryKey: ['tradeBestBook', pairAddr] })
queryClient.invalidateQueries({ queryKey: ['limitOrderPricePoolRef', pairAddr] })

The ladder onSuccess is missing limitBookPage and tradeBestBook invalidation, so the order book panel displays stale data until its natural staleTime expires or the user forces a reload.


Impact assessment

  • User-facing: After placing a ladder, the user sees a blank or unchanged order book. Combined with ISSUE-005 (crossing orders placed silently), a user has no way to verify their ladder positions in the book without reloading.
  • Trust: The post-placement UX state is inconsistent and misleading — "Active on Book" says orders are live but the book itself does not show them.
  • OE-3 result: Fail — resting orders do not display correctly in the order book immediately after placement.

Environment

  • Chain: localterra
  • LCD: http://localhost:1317
  • Wallet: Keplr (Terra Classic)
  • Browser: Chrome
  • Page: /limits — Limit Ladder panel + Order Book
  • Pair tested: CORAL/EMBER
  • Network throttle applied: No

Severity: Medium — orders are placed correctly on-chain; the display failure is a UI sync issue. However it directly undermines confidence in the placement result.

Suggested GitLab label/title prefix: fix(ladder):

Related checklist items: OE-3, OE-2

cc: @PlasticDigits

**Found during:** OE-3 checklist testing — Limit ladder placement and order book display ## **Summary:** After a successful ladder placement, the placed orders appear immediately in the "My Limits (Indexer) — Active on Book" panel but are absent from the Order Book depth display until the page is hard-refreshed. The order book query is not invalidated on ladder placement success, causing a stale-data split where the user sees their orders confirmed in one panel but missing from the book. --- ### Reproduction steps 1. Navigate to `/limits`, connect Keplr wallet, select a pair 2. Open the Limit Ladder panel, configure a valid ladder, and submit 3. Wait for placement success confirmation 4. Observe: "My Limits (Indexer)" panel shows the new orders as "Active on Book" ✓ 5. Observe: the Order Book (ASKS / BIDS panels above) does **not** show the new orders ✗ 6. Hard-refresh the page (Cmd+Shift+R / F5) 7. Observe: the Order Book now shows the orders correctly ✓ --- ### Expected behavior After a successful ladder placement, both the "My Limits" panel and the Order Book should update simultaneously without requiring a page reload. --- ### Actual behavior - "My Limits (Indexer)" updates immediately (correct) - Order Book panel remains stale — placed orders are invisible in the book until hard refresh - This creates a split-state where the user's confirmed orders exist on-chain and in the indexer but are not reflected in the book depth display --- ### Verified root cause (code read and confirmed) `LimitOrderLadderPanel.tsx` `onSuccess` handler (lines 164–181) only invalidates one query key: ```js onSuccess: async (txHash) => { void queryClient.invalidateQueries({ queryKey: ['limitPlacements', pairAddress] }) // ... polling loop for My Limits panel } ``` This drives the "My Limits" panel only. The Order Book depth display is driven by separate query keys that are never invalidated: | Query key | Drives | Invalidated on ladder success? | |-----------|--------|--------------------------------| | `['limitPlacements', pairAddress]` | My Limits / Active on Book | ✓ Yes | | `['limitBookPage', pairAddress]` | Order Book depth (bids/asks) | ✗ No | | `['tradeBestBook', pairAddress]` | Best bid/ask price display | ✗ No | Compare to `TradeOrderTicket.tsx` single-order `onSuccess` (lines 447–451) which invalidates all five keys including `limitBookPage` and `tradeBestBook`: ```js queryClient.invalidateQueries({ queryKey: ['limitPlacements'] }) queryClient.invalidateQueries({ queryKey: ['tokenBalance'] }) queryClient.invalidateQueries({ queryKey: ['limitBookPage', pairAddr] }) queryClient.invalidateQueries({ queryKey: ['tradeBestBook', pairAddr] }) queryClient.invalidateQueries({ queryKey: ['limitOrderPricePoolRef', pairAddr] }) ``` The ladder `onSuccess` is missing `limitBookPage` and `tradeBestBook` invalidation, so the order book panel displays stale data until its natural `staleTime` expires or the user forces a reload. --- ### Impact assessment - **User-facing:** After placing a ladder, the user sees a blank or unchanged order book. Combined with ISSUE-005 (crossing orders placed silently), a user has no way to verify their ladder positions in the book without reloading. - **Trust:** The post-placement UX state is inconsistent and misleading — "Active on Book" says orders are live but the book itself does not show them. - **OE-3 result:** Fail — resting orders do not display correctly in the order book immediately after placement. --- ### Environment - Chain: localterra - LCD: [http://localhost:1317](http://localhost:1317) - Wallet: Keplr (Terra Classic) - Browser: Chrome - Page: `/limits` — Limit Ladder panel + Order Book - Pair tested: CORAL/EMBER - Network throttle applied: No --- **Severity:** Medium — orders are placed correctly on-chain; the display failure is a UI sync issue. However it directly undermines confidence in the placement result. **Suggested GitLab label/title prefix:** `fix(ladder):` **Related checklist items:** OE-3, OE-2 cc: @PlasticDigits
totdking commented 2026-06-03 17:36:44 +00:00 (Migrated from gitlab.com)

mentioned in issue #291

mentioned in issue #291
Brouie commented 2026-06-04 07:09:23 +00:00 (Migrated from gitlab.com)

Confirmed — and it's a frontend cache gap, not indexer lag. LimitOrderLadderPanel.tsx:164-181 onSuccess invalidates only ['limitPlacements', pairAddress], but the visible book is driven by useLimitBookInfinite keyed ['limitBookPage', pairAddress, side] and the best bid/ask by ['tradeBestBook', pairAddress] — neither is invalidated, so the book shows stale until its staleTime or a hard refresh. The single-order TradeOrderTicket.tsx onSuccess already invalidates all five keys (incl. limitBookPage + tradeBestBook); the ladder path just needs the same two added. I verified the indexer returns the placed ladder orders promptly (so it's the react-query cache, not the indexer). Real, medium, frontend-only. @totdking

Confirmed — and it's a frontend cache gap, **not** indexer lag. `LimitOrderLadderPanel.tsx:164-181` `onSuccess` invalidates only `['limitPlacements', pairAddress]`, but the visible book is driven by `useLimitBookInfinite` keyed `['limitBookPage', pairAddress, side]` and the best bid/ask by `['tradeBestBook', pairAddress]` — neither is invalidated, so the book shows stale until its `staleTime` or a hard refresh. The single-order `TradeOrderTicket.tsx` `onSuccess` already invalidates all five keys (incl. `limitBookPage` + `tradeBestBook`); the ladder path just needs the same two added. I verified the indexer returns the placed ladder orders promptly (so it's the react-query cache, not the indexer). Real, medium, frontend-only. @totdking
Brouie commented 2026-06-05 03:21:48 +00:00 (Migrated from gitlab.com)

mentioned in merge request !757

mentioned in merge request !757
Brouie commented 2026-06-05 03:23:14 +00:00 (Migrated from gitlab.com)

Fixed in MR !757. The place onSuccess only invalidated ['limitPlacements'] (the My Limits feed), so the Order Book didn't update until a hard refresh. Added invalidation of the order-book / best-book query keys (limitBookPage, limitBookPagePreview, tradeBestBook) in the same onSuccess. Browser check (ladder shows in the book without refresh) is yours. @PlasticDigits

Fixed in MR !757. The place onSuccess only invalidated ['limitPlacements'] (the My Limits feed), so the Order Book didn't update until a hard refresh. Added invalidation of the order-book / best-book query keys (limitBookPage, limitBookPagePreview, tradeBestBook) in the same onSuccess. Browser check (ladder shows in the book without refresh) is yours. @PlasticDigits
PlasticDigits commented 2026-06-05 03:24:33 +00:00 (Migrated from gitlab.com)

mentioned in commit 6e42a5b6f6

mentioned in commit 6e42a5b6f6a8a5b91735b5ad60d68168450254b0
PlasticDigits commented 2026-06-05 04:31:44 +00:00 (Migrated from gitlab.com)

Verification complete — GitLab #298

Verified fix from MR !757 (qa/295-298-limit-ladder-ux, merged to main at 6e42a5b).

Acceptance criteria

Item Result How verified
Root cause: ladder onSuccess only invalidated limitPlacements, not order-book keys PASS Code read: LimitOrderLadderPanel.tsx:228-232 now invalidates limitPlacements, limitBookPage, limitBookPagePreview, and tradeBestBook (parity with single-order path in TradeOrderTicket.tsx:447-451)
Fix merged on default branch PASS glab mr view 39 — state: merged
After ladder placement, My Limits updates immediately PASS Browser: 5 "Active on book" rows in My limits (indexer) after 5-rung ladder TX
After ladder placement, Order Book updates without hard refresh PASS Browser: Order Book bids 1 → 6 (original seed bid + 5 ladder rungs @ 0.95–1.05) with no reload
OE-3: resting orders visible in book immediately after placement PASS Same browser session; ladder prices visible in Bids panel immediately
Frontend unit tests (ladder / book pagination) PASS npm test -- limitOrderLadder limitBookInsertHint useLimitLadderPlacementPlan LimitOrdersPage — 19/19 passed
Frontend lint PASS npm run lint — 0 errors (6 pre-existing warnings)
Strict E2E limit-orders-tx.spec.ts ladder test SKIP Blocked: scripts/deploy-dex-local.sh / e2e-seed-wrap-pairs.sh omit --amount 100000000uluna on create_pair (pair-creation fee #276); global setup fails before specs run. Manual browser verification used instead.

Browser verification details

  • URL: http://127.0.0.1:5173/limits
  • Wallet: Simulated Wallet (LocalTerra dev mnemonic)
  • Pair: EMBER/CORAL
  • Ladder: bid side, start 0.95 → end 1.05, 5 rungs, 100 CORAL total
  • TX: 54E3936F…12E8QB (truncated in UI)
  • Before: Order Book showed 1 bid (hybrid seed)
  • After (no refresh): Order Book showed 6 bids including ladder rungs; My Limits showed 5 active placements

Conclusion

Issue #298 is fixed on main. Closing as verified.

Follow-ups

  • scripts/deploy-dex-local.sh: attach 100000000uluna on every create_pair execute (and wrap-pair seed scripts) so local deploy + strict Playwright global setup succeed under the pair-creation fee invariant (#276).
## Verification complete — GitLab #298 Verified fix from MR !757 (`qa/295-298-limit-ladder-ux`, merged to `main` at `6e42a5b`). ### Acceptance criteria | Item | Result | How verified | |------|--------|--------------| | Root cause: ladder `onSuccess` only invalidated `limitPlacements`, not order-book keys | **PASS** | Code read: `LimitOrderLadderPanel.tsx:228-232` now invalidates `limitPlacements`, `limitBookPage`, `limitBookPagePreview`, and `tradeBestBook` (parity with single-order path in `TradeOrderTicket.tsx:447-451`) | | Fix merged on default branch | **PASS** | `glab mr view 39` — state: merged | | After ladder placement, My Limits updates immediately | **PASS** | Browser: 5 "Active on book" rows in My limits (indexer) after 5-rung ladder TX | | After ladder placement, Order Book updates **without hard refresh** | **PASS** | Browser: Order Book bids 1 → 6 (original seed bid + 5 ladder rungs @ 0.95–1.05) with no reload | | OE-3: resting orders visible in book immediately after placement | **PASS** | Same browser session; ladder prices visible in Bids panel immediately | | Frontend unit tests (ladder / book pagination) | **PASS** | `npm test -- limitOrderLadder limitBookInsertHint useLimitLadderPlacementPlan LimitOrdersPage` — 19/19 passed | | Frontend lint | **PASS** | `npm run lint` — 0 errors (6 pre-existing warnings) | | Strict E2E `limit-orders-tx.spec.ts` ladder test | **SKIP** | Blocked: `scripts/deploy-dex-local.sh` / `e2e-seed-wrap-pairs.sh` omit `--amount 100000000uluna` on `create_pair` (pair-creation fee #276); global setup fails before specs run. Manual browser verification used instead. | ### Browser verification details - **URL:** `http://127.0.0.1:5173/limits` - **Wallet:** Simulated Wallet (LocalTerra dev mnemonic) - **Pair:** EMBER/CORAL - **Ladder:** bid side, start 0.95 → end 1.05, 5 rungs, 100 CORAL total - **TX:** `54E3936F…12E8QB` (truncated in UI) - **Before:** Order Book showed 1 bid (hybrid seed) - **After (no refresh):** Order Book showed 6 bids including ladder rungs; My Limits showed 5 active placements ### Conclusion Issue **#298 is fixed** on `main`. Closing as verified. ### Follow-ups - **`scripts/deploy-dex-local.sh`**: attach `100000000uluna` on every `create_pair` execute (and wrap-pair seed scripts) so local deploy + strict Playwright global setup succeed under the pair-creation fee invariant (#276).
PlasticDigits (Migrated from gitlab.com) closed this issue 2026-06-05 04:31:45 +00:00
totdking commented 2026-06-16 10:36:17 +00:00 (Migrated from gitlab.com)

Verification

  • order shows immediately in order book when orders are placed.
  • This updates concurrently with the order book and My Limits

Good to close

### Verification * order shows immediately in order book when orders are placed. * This updates concurrently with the order book and My Limits Good to close
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#298
No description provided.