Debounce hybrid book leg for submit snapshot alignment (#360) #866

Merged
PlasticDigits merged 1 commit from fix/360-hybrid-book-submit-snapshot into main 2026-06-11 15:34:17 +00:00
PlasticDigits commented 2026-06-11 15:31:32 +00:00 (Migrated from gitlab.com)

Summary

Follow-up to #356: hybrid book leg and max makers now participate in the same debounced submit snapshot as pay amount.

  • Debounce bookInputHuman and hybridMaxMakers (350ms) for sim query keys on Swap and Trade market
  • Extend isSubmitQuoteStale + assertSubmitHybridAligned for book leg / max makers stale detection and mutation defense
  • Wire buildSubmitAlignedSimPayload into useSubmitAlignedSimQuote (single snapshot builder)
  • Swap mutation uses submitDirectHybrid from debounced inputs instead of live bookInputHuman
  • Docs/skills updated for #360 hybrid snapshot invariant

Acceptance criteria

Criterion Verification Result
Submit allowed → pay, book, max makers, minReceived, indexer ops, hybrid params share one settled sim key Code review + unit/component tests PASS
isSubmitReady false while live book ≠ debounced book (pay stable) useSubmitAlignedSimQuote.test.ts, SwapPage + Trade market component tests PASS
mutationFn asserts hybrid alignment before broadcast assertSubmitHybridAligned in Swap + Trade mutations; quoteDebounce.test.ts PASS
Swap direct hybrid quote + mutation use debounced book input SwapPage.tsx sim key + submitDirectHybrid PASS
buildSubmitAlignedSimPayload used by hook (not orphaned) rg buildSubmitAlignedSimPayload frontend-dapp/src PASS
Docs/skills mention debounced book leg docs/frontend.md, skills/AGENTS_FRONTEND_SWAP_ROUTE_DISPLAY.md PASS

Test plan

cd frontend-dapp && npx vitest run src/utils/quoteDebounce.test.ts src/hooks/useSubmitAlignedSimQuote.test.ts src/utils/swapDisclosure.test.ts
cd frontend-dapp && npx vitest run src/pages/SwapPage.test.tsx src/components/trade/__tests__/TradeMarketOrderPanel.submitSnapshot.test.tsx
make test-frontend

All commands: PASS

Manual (LocalTerra + make dev) — SKIP on agent VM

  1. Swap → Settings → limit book leg → pay 10, book 2 → change book to 5 → submit disabled until refresh
  2. Trade market hybrid → repeat (1)
  3. Change max maker fills with stable pay/book → submit disabled during refetch
  4. Pool-only fallback disclosure when indexer unavailable

Verification checklist (third parties)

  • make test-frontend green on MR pipeline
  • Swap: enable book leg, stable pay, edit book → Calculating… until debounce settles
  • Trade market: same book-leg stale gate
  • On submit, on-chain book_input matches displayed hybrid split
  • rg buildSubmitAlignedSimPayload frontend-dapp/src shows hook + tests only (plus definition)

Closes #360


Note

Medium Risk
Changes when swap and market orders can submit and which hybrid params hit the chain; misalignment could cause wrong book splits, but UI stale gates and mutation asserts reduce that risk.

Overview
Extends submit–quote alignment (#356) so hybrid book leg and max maker fills use the same 350ms debounced snapshot as pay amount on Swap and Trade market.

Sim keys now include debounced bookInputHuman and hybridMaxMakers; isSubmitQuoteStale treats live vs snapshotted hybrid fields as stale (submit shows Calculating… / disabled). useSubmitAlignedSimQuote exposes snapshottedHybrid and builds submitPayload via buildSubmitAlignedSimPayload. assertSubmitHybridAligned runs in swapMutation before broadcast. Swap direct hybrid submit uses submitDirectHybrid from debounced inputs instead of rebuilding from live book fields.

Docs/skills and Vitest/component tests cover book-leg and max-makers stale gates.

Reviewed by Cursor Bugbot for commit c1bea72d0c. Bugbot is set up for automated code reviews on this repo. Configure here.

## Summary Follow-up to #356: hybrid book leg and max makers now participate in the same debounced submit snapshot as pay amount. - Debounce `bookInputHuman` and `hybridMaxMakers` (350ms) for sim query keys on Swap and Trade market - Extend `isSubmitQuoteStale` + `assertSubmitHybridAligned` for book leg / max makers stale detection and mutation defense - Wire `buildSubmitAlignedSimPayload` into `useSubmitAlignedSimQuote` (single snapshot builder) - Swap mutation uses `submitDirectHybrid` from debounced inputs instead of live `bookInputHuman` - Docs/skills updated for #360 hybrid snapshot invariant ## Acceptance criteria | Criterion | Verification | Result | |-----------|--------------|--------| | Submit allowed → pay, book, max makers, minReceived, indexer ops, hybrid params share one settled sim key | Code review + unit/component tests | PASS | | `isSubmitReady` false while live book ≠ debounced book (pay stable) | `useSubmitAlignedSimQuote.test.ts`, SwapPage + Trade market component tests | PASS | | `mutationFn` asserts hybrid alignment before broadcast | `assertSubmitHybridAligned` in Swap + Trade mutations; `quoteDebounce.test.ts` | PASS | | Swap direct hybrid quote + mutation use debounced book input | `SwapPage.tsx` sim key + `submitDirectHybrid` | PASS | | `buildSubmitAlignedSimPayload` used by hook (not orphaned) | `rg buildSubmitAlignedSimPayload frontend-dapp/src` | PASS | | Docs/skills mention debounced book leg | `docs/frontend.md`, `skills/AGENTS_FRONTEND_SWAP_ROUTE_DISPLAY.md` | PASS | ## Test plan ```bash cd frontend-dapp && npx vitest run src/utils/quoteDebounce.test.ts src/hooks/useSubmitAlignedSimQuote.test.ts src/utils/swapDisclosure.test.ts cd frontend-dapp && npx vitest run src/pages/SwapPage.test.tsx src/components/trade/__tests__/TradeMarketOrderPanel.submitSnapshot.test.tsx make test-frontend ``` All commands: **PASS** ### Manual (LocalTerra + `make dev`) — SKIP on agent VM 1. Swap → Settings → limit book leg → pay `10`, book `2` → change book to `5` → submit disabled until refresh 2. Trade market hybrid → repeat (1) 3. Change max maker fills with stable pay/book → submit disabled during refetch 4. Pool-only fallback disclosure when indexer unavailable ## Verification checklist (third parties) - [ ] `make test-frontend` green on MR pipeline - [ ] Swap: enable book leg, stable pay, edit book → **Calculating…** until debounce settles - [ ] Trade market: same book-leg stale gate - [ ] On submit, on-chain `book_input` matches displayed hybrid split - [ ] `rg buildSubmitAlignedSimPayload frontend-dapp/src` shows hook + tests only (plus definition) Closes #360 <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **Medium Risk** > Changes when swap and market orders can submit and which hybrid params hit the chain; misalignment could cause wrong book splits, but UI stale gates and mutation asserts reduce that risk. > > **Overview** > Extends **submit–quote alignment** ([#356](https://gitlab.com/PlasticDigits/cl8y-dex-terraclassic/-/issues/356)) so hybrid **book leg** and **max maker fills** use the same **350ms** debounced snapshot as pay amount on **Swap** and **Trade market**. > > **Sim keys** now include debounced `bookInputHuman` and `hybridMaxMakers`; **`isSubmitQuoteStale`** treats live vs snapshotted hybrid fields as stale (submit shows **Calculating…** / disabled). **`useSubmitAlignedSimQuote`** exposes **`snapshottedHybrid`** and builds **`submitPayload`** via **`buildSubmitAlignedSimPayload`**. **`assertSubmitHybridAligned`** runs in **`swapMutation`** before broadcast. Swap direct hybrid submit uses **`submitDirectHybrid`** from debounced inputs instead of rebuilding from live book fields. > > Docs/skills and Vitest/component tests cover book-leg and max-makers stale gates. > > <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit c1bea72d0ca073739a682effb7aa8fbe92122781. Bugbot is set up for automated code reviews on this repo. Configure [here](https://www.cursor.com/dashboard/bugbot).</sup> <!-- /CURSOR_SUMMARY -->
ghost1 commented 2026-06-11 15:31:41 +00:00 (Migrated from gitlab.com)

changed the description

changed the description
ghost1 commented 2026-06-11 15:31:50 +00:00 (Migrated from gitlab.com)

changed the description

changed the description
PlasticDigits commented 2026-06-11 15:33:54 +00:00 (Migrated from gitlab.com)

Security review

Commit reviewed: c1bea72d0ca073739a682effb7aa8fbe92122781

Scope: MR !866 — debounced hybrid book leg / max-makers submit snapshot alignment (quoteDebounce.ts, useSubmitAlignedSimQuote, SwapPage, TradeMarketOrderPanel, tests, docs). Prior security-review threads: none on this MR.

Method: Diff review + trace of attacker-controlled inputs (bookInputHuman, hybridMaxMakers, pay amount) through sim query keys, isSubmitQuoteStale / isSubmitReady gates, and swapMutation sinks (assertSubmitHybridAligned, submitDirectHybrid, debouncedHybrid).

Outcome: FINDINGS: 0 medium+

Security review: no medium+ findings on this diff.

This change hardens submit–quote alignment for hybrid swaps: sim keys and on-chain submit now share debounced book/max-makers snapshots, UI blocks stale hybrid input, and mutationFn re-checks live vs snapshotted hybrid params before broadcast. Reviewed paths include injection/XSS (controlled React inputs + isDecimalAmountDraft), TOCTOU between debounce settle and submit (assertSubmitHybridAligned at mutation time), and indexer-hybrid precedence (hybridFromSingleHopIndexerOps) — the latter is unchanged trust model from #356, not a new exposure.

Inline threads: none (no findings to anchor).

## Security review **Commit reviewed:** `c1bea72d0ca073739a682effb7aa8fbe92122781` **Scope:** MR !866 — debounced hybrid book leg / max-makers submit snapshot alignment (`quoteDebounce.ts`, `useSubmitAlignedSimQuote`, `SwapPage`, `TradeMarketOrderPanel`, tests, docs). Prior security-review threads: none on this MR. **Method:** Diff review + trace of attacker-controlled inputs (`bookInputHuman`, `hybridMaxMakers`, pay amount) through sim query keys, `isSubmitQuoteStale` / `isSubmitReady` gates, and `swapMutation` sinks (`assertSubmitHybridAligned`, `submitDirectHybrid`, `debouncedHybrid`). **Outcome:** `FINDINGS: 0` medium+ Security review: **no medium+ findings** on this diff. This change **hardens** submit–quote alignment for hybrid swaps: sim keys and on-chain submit now share debounced book/max-makers snapshots, UI blocks stale hybrid input, and `mutationFn` re-checks live vs snapshotted hybrid params before broadcast. Reviewed paths include injection/XSS (controlled React inputs + `isDecimalAmountDraft`), TOCTOU between debounce settle and submit (`assertSubmitHybridAligned` at mutation time), and indexer-hybrid precedence (`hybridFromSingleHopIndexerOps`) — the latter is unchanged trust model from #356, not a new exposure. **Inline threads:** none (no findings to anchor).
PlasticDigits commented 2026-06-11 15:34:18 +00:00 (Migrated from gitlab.com)

mentioned in commit 16e0656c37

mentioned in commit 16e0656c376eb60f2b327823847aca37e02c5dce
PlasticDigits (Migrated from gitlab.com) merged commit 16e0656c37 into main 2026-06-11 15:34:18 +00:00
Brouie commented 2026-06-12 03:05:56 +00:00 (Migrated from gitlab.com)

mentioned in merge request !868

mentioned in merge request !868
Brouie commented 2026-06-12 03:11:48 +00:00 (Migrated from gitlab.com)

mentioned in issue #360

mentioned in issue #360
Sign in to join this conversation.
No reviewers
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!866
No description provided.