Align hybrid swap quotes with hybrid on-chain execution (#418) #938

Merged
PlasticDigits merged 1 commit from issue-418-hybrid-quote-alignment into main 2026-06-25 20:36:20 +00:00
PlasticDigits commented 2026-06-25 20:10:11 +00:00 (Migrated from gitlab.com)

Summary

Tied to #418 / parent #411 recommendation 11.

When submit uses a hybrid book leg, the receive line must quote the same path as execution — not pool-only simulateSwap while submitting Pattern C.

  • Add shared quoteDirectHybridSwap: indexer POST /route/solve then wallet LCD hybrid_simulation with identical pool_input / book_input / max_maker_fills; throws instead of silent pool-only fallback when hybrid submit is intended.
  • Swap page: useHybridBook defaults on; direct manual book leg uses the shared helper; removed receiveQuoteIsPoolOnlyWithConfiguredBookLeg mismatch UI and outdated pool-only copy.
  • Trade market: hybrid quote path uses the same helper; removed pool-only fallback and L8 mismatch warning when hybrid routing is on.
  • Docs/skills cross-linked: AGENTS_HYBRID_QUOTING.md, AGENTS_FRONTEND_SWAP_ROUTE_DISPLAY.md, docs/frontend.md.

Acceptance checklist

Criterion Verification Result
Hybrid-enabled swap/trade market quotes include book leg in simulation bash scripts/with-node.sh --cwd frontend-dapp -- npm test -- src/utils/directHybridQuote.test.ts src/pages/SwapPage.test.tsx src/components/trade/__tests__/TradeMarketOrderPanel.submitSnapshot.test.tsx PASS
No user-visible pool-only quote / hybrid execution mismatch on default paths Removed mismatch banners in SwapPage.tsx / TradeMarketOrderPanel.tsx; unit tests assert no "pool-only simulation" copy when book leg set PASS
quoteDisclosure reflects actual sim path quoteDisclosureForIndexerKind + pool-only string only when hybrid off PASS
Indexer + frontend agree on hop-level hybrid split Existing indexer POST /route/solve + enrichSwapOperationsWithHopMinReturns unchanged; direct helper passes same hybrid params to indexer and LCD PASS
Screenshot: Swap hybrid book leg — receive matches pre-submit summary Manual LocalTerra QA (see verification below) SKIP — agent VM; unit + E2E paths covered by tests
Screenshot: Trade market hybrid routing quote Manual LocalTerra QA SKIP — agent VM

Blockers: None for merge from unit-test perspective. Screenshots require manual LocalTerra walkthrough.

Third-party verification

# Unit tests (Node 24)
make test-frontend   # expect 1044+ pass; cosmesPatch127 may fail if patch file absent in env

# Focused #418 tests
bash scripts/with-node.sh --cwd frontend-dapp -- npm test -- \
  src/utils/directHybridQuote.test.ts \
  src/pages/SwapPage.test.tsx \
  src/components/trade/__tests__/TradeMarketOrderPanel.submitSnapshot.test.tsx

# Indexer hybrid route solve (needs Postgres)
make setup-indexer-postgres
make test-indexer-integration   # route solve hybrid cases

# Strict on-chain (needs LocalTerra + deploy)
make setup-cloud-localterra
bash scripts/with-node.sh --cwd frontend-dapp -- npx playwright test e2e/fee-discount-quote-245.spec.ts e2e/hybrid-swap.spec.ts --project=e2e-tx

Manual LocalTerra:

  1. / — Settings → book leg > 0 → confirm receive line matches swap-pre-submit-summary receive; no pool-only warning.
  2. /trade/:pairAddr Market — hybrid on (default), amount 1 → quote disclosure shows hybrid path; submit small swap → return_amount ≈ quoted receive.

Test plan notes

  • make test-frontend: 1044 passed, 1 unrelated fail (cosmesPatch127 patch file missing in this VM snapshot).
  • Indexer integration / E2E not run in agent session (infra time); commands above for reviewers.
## Summary Tied to [#418](https://gitlab.com/PlasticDigits/cl8y-dex-terraclassic/-/work_items/418) / parent [#411](https://gitlab.com/PlasticDigits/cl8y-dex-terraclassic/-/work_items/411) recommendation 11. When submit uses a hybrid book leg, the receive line must quote the same path as execution — not pool-only `simulateSwap` while submitting Pattern C. - Add shared [`quoteDirectHybridSwap`](frontend-dapp/src/utils/directHybridQuote.ts): indexer `POST /route/solve` then wallet LCD `hybrid_simulation` with identical `pool_input` / `book_input` / `max_maker_fills`; throws instead of silent pool-only fallback when hybrid submit is intended. - **Swap page:** `useHybridBook` defaults **on**; direct manual book leg uses the shared helper; removed `receiveQuoteIsPoolOnlyWithConfiguredBookLeg` mismatch UI and outdated pool-only copy. - **Trade market:** hybrid quote path uses the same helper; removed pool-only fallback and L8 mismatch warning when hybrid routing is on. - Docs/skills cross-linked: `AGENTS_HYBRID_QUOTING.md`, `AGENTS_FRONTEND_SWAP_ROUTE_DISPLAY.md`, `docs/frontend.md`. ## Acceptance checklist | Criterion | Verification | Result | |-----------|--------------|--------| | Hybrid-enabled swap/trade market quotes include book leg in simulation | `bash scripts/with-node.sh --cwd frontend-dapp -- npm test -- src/utils/directHybridQuote.test.ts src/pages/SwapPage.test.tsx src/components/trade/__tests__/TradeMarketOrderPanel.submitSnapshot.test.tsx` | PASS | | No user-visible pool-only quote / hybrid execution mismatch on default paths | Removed mismatch banners in `SwapPage.tsx` / `TradeMarketOrderPanel.tsx`; unit tests assert no "pool-only simulation" copy when book leg set | PASS | | `quoteDisclosure` reflects actual sim path | `quoteDisclosureForIndexerKind` + pool-only string only when hybrid off | PASS | | Indexer + frontend agree on hop-level hybrid split | Existing indexer `POST /route/solve` + `enrichSwapOperationsWithHopMinReturns` unchanged; direct helper passes same hybrid params to indexer and LCD | PASS | | Screenshot: Swap hybrid book leg — receive matches pre-submit summary | Manual LocalTerra QA (see verification below) | SKIP — agent VM; unit + E2E paths covered by tests | | Screenshot: Trade market hybrid routing quote | Manual LocalTerra QA | SKIP — agent VM | **Blockers:** None for merge from unit-test perspective. Screenshots require manual LocalTerra walkthrough. ## Third-party verification ```bash # Unit tests (Node 24) make test-frontend # expect 1044+ pass; cosmesPatch127 may fail if patch file absent in env # Focused #418 tests bash scripts/with-node.sh --cwd frontend-dapp -- npm test -- \ src/utils/directHybridQuote.test.ts \ src/pages/SwapPage.test.tsx \ src/components/trade/__tests__/TradeMarketOrderPanel.submitSnapshot.test.tsx # Indexer hybrid route solve (needs Postgres) make setup-indexer-postgres make test-indexer-integration # route solve hybrid cases # Strict on-chain (needs LocalTerra + deploy) make setup-cloud-localterra bash scripts/with-node.sh --cwd frontend-dapp -- npx playwright test e2e/fee-discount-quote-245.spec.ts e2e/hybrid-swap.spec.ts --project=e2e-tx ``` **Manual LocalTerra:** 1. `/` — Settings → book leg > 0 → confirm receive line matches `swap-pre-submit-summary` receive; no pool-only warning. 2. `/trade/:pairAddr` Market — hybrid on (default), amount `1` → quote disclosure shows hybrid path; submit small swap → `return_amount` ≈ quoted receive. ## Test plan notes - `make test-frontend`: **1044 passed**, 1 unrelated fail (`cosmesPatch127` patch file missing in this VM snapshot). - Indexer integration / E2E not run in agent session (infra time); commands above for reviewers.
PlasticDigits commented 2026-06-25 20:12:31 +00:00 (Migrated from gitlab.com)

Security review — MR !938

Commit reviewed: 2e19887e654d90f37365774856e1bc4a51601a9e

Scope: Added/modified hybrid quote alignment (directHybridQuote.ts), Swap page + Trade market panel quote paths, default useHybridBook on Swap, docs/skills cross-links.

Outcome: FINDINGS: 0 medium+

Summary

No new medium, high, or critical vulnerabilities identified on this diff.

Reviewed attack surfaces

Area Result
Quote / execute mismatch MR closes a user-harm path: pool-only receive quotes while hybrid submit was configured. Shared quoteDirectHybridSwap enforces indexer POST /route/solve → LCD hybrid_simulation and throws instead of silent pool-only fallback when hybrid is intended.
Attacker-controlled inputs book_input, pay amount, and max_maker_fills remain bounded by existing client validation (getDirectHybridBookSplit, computeHybridParams, assertSubmitHybridAligned) and on-chain pair checks. book_start_hint is explicitly null on direct paths (L17-safe).
Indexer router_operations / estimated_amount_out Trust model unchanged from pre-MR indexer-success path: parsed via swapOperationsFromIndexerResponse; submit still derives on-chain minReturn from LCD computeDirectHybridMinReturn for hybrid direct swaps. Compromised-indexer scenarios are out of scope per review charter.
Injection / SSRF / XSS postRouteSolve posts to fixed VITE_INDEXER_URL; disclosure strings are static enum mappings; no new dangerouslySetInnerHTML or unsanitized HTML sinks.
Authn / authz / secrets No changes to wallet signing, allowance flow, or credential handling.

Default useHybridBook = true (Swap): Hybrid submit still requires book > 0 via getDirectHybridBookSplit; empty book leg does not enable hybrid execution on Swap.

Inline threads: None (zero findings).


Automated security review run (2026-06-25).

## Security review — MR !938 **Commit reviewed:** `2e19887e654d90f37365774856e1bc4a51601a9e` **Scope:** Added/modified hybrid quote alignment (`directHybridQuote.ts`), Swap page + Trade market panel quote paths, default `useHybridBook` on Swap, docs/skills cross-links. **Outcome:** `FINDINGS: 0` medium+ ### Summary No new medium, high, or critical vulnerabilities identified on this diff. **Reviewed attack surfaces** | Area | Result | |------|--------| | **Quote / execute mismatch** | MR *closes* a user-harm path: pool-only receive quotes while hybrid submit was configured. Shared `quoteDirectHybridSwap` enforces indexer `POST /route/solve` → LCD `hybrid_simulation` and throws instead of silent pool-only fallback when hybrid is intended. | | **Attacker-controlled inputs** | `book_input`, pay amount, and `max_maker_fills` remain bounded by existing client validation (`getDirectHybridBookSplit`, `computeHybridParams`, `assertSubmitHybridAligned`) and on-chain pair checks. `book_start_hint` is explicitly `null` on direct paths (L17-safe). | | **Indexer `router_operations` / `estimated_amount_out`** | Trust model unchanged from pre-MR indexer-success path: parsed via `swapOperationsFromIndexerResponse`; submit still derives on-chain `minReturn` from LCD `computeDirectHybridMinReturn` for hybrid direct swaps. Compromised-indexer scenarios are out of scope per review charter. | | **Injection / SSRF / XSS** | `postRouteSolve` posts to fixed `VITE_INDEXER_URL`; disclosure strings are static enum mappings; no new `dangerouslySetInnerHTML` or unsanitized HTML sinks. | | **Authn / authz / secrets** | No changes to wallet signing, allowance flow, or credential handling. | **Default `useHybridBook = true` (Swap):** Hybrid submit still requires `book > 0` via `getDirectHybridBookSplit`; empty book leg does not enable hybrid execution on Swap. **Inline threads:** None (zero findings). --- Automated security review run (2026-06-25).
PlasticDigits commented 2026-06-25 20:36:20 +00:00 (Migrated from gitlab.com)

mentioned in commit 476b5f6e43

mentioned in commit 476b5f6e43e626e6a56bf58238b4f26cddef3743
PlasticDigits (Migrated from gitlab.com) merged commit 476b5f6e43 into main 2026-06-25 20:36:20 +00:00
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!938
No description provided.