Indexer: GET /route/solve defaults to hybrid; default max hops = 3 #191

Closed
opened 2026-05-26 07:59:19 +00:00 by PlasticDigits · 8 comments
PlasticDigits commented 2026-05-26 07:59:19 +00:00 (Migrated from gitlab.com)

Problem statement

GET /api/v1/route/solve returns pool-only terra_swap.hybrid: null unless callers pass hybrid_optimize=true. Retail and integrator defaults should assume hybrid-aware routing with a 3-hop cap on GET (per ADR 0001).

Evidence / context

Proposed solution

  1. Change GET default behavior to run hybrid optimization (or equivalent) so router_operations include merged hybrid params without hybrid_optimize=true.
  2. Document 3 hops as the default GET cap; keep POST at 4 only if product requires — align docs and OpenAPI/utoipa schemas.
  3. Add pool_only=true (or similar) escape hatch for backward-compatible integrators during migration.

Acceptance criteria

  • GET /api/v1/route/solve returns hybrid-merged ops by default when amount_in is set and LCD/router configured.
  • Default hop limit for GET is 3 (tests + docs/indexer-invariants.md).
  • Frontend swap/trade paths use default GET without manual hybrid_optimize flag.
  • Integration tests in indexer/tests/api_route_solve.rs (or successor) cover default hybrid GET.

Priority

P1

## Problem statement `GET /api/v1/route/solve` returns **pool-only** `terra_swap.hybrid: null` unless callers pass `hybrid_optimize=true`. Retail and integrator defaults should assume **hybrid-aware routing** with a **3-hop** cap on GET (per ADR 0001). ## Evidence / context - [`indexer/src/api/route_solver.rs`](indexer/src/api/route_solver.rs) — GET default `hybrid: null`; `hybrid_optimize` opt-in; GET max **3** hops, POST max **4**. - [ADR 0001](docs/adr/0001-hybrid-quoting-and-routing.md). ## Proposed solution 1. Change **GET** default behavior to run hybrid optimization (or equivalent) so `router_operations` include merged `hybrid` params without `hybrid_optimize=true`. 2. Document **3 hops** as the default GET cap; keep POST at 4 only if product requires — align docs and OpenAPI/utoipa schemas. 3. Add `pool_only=true` (or similar) escape hatch for backward-compatible integrators during migration. ## Acceptance criteria - [ ] GET `/api/v1/route/solve` returns hybrid-merged ops by default when `amount_in` is set and LCD/router configured. - [ ] Default hop limit for GET is **3** (tests + [`docs/indexer-invariants.md`](docs/indexer-invariants.md)). - [ ] Frontend swap/trade paths use default GET without manual `hybrid_optimize` flag. - [ ] Integration tests in `indexer/tests/api_route_solve.rs` (or successor) cover default hybrid GET. ## Priority **P1**
PlasticDigits commented 2026-05-26 09:29:55 +00:00 (Migrated from gitlab.com)

Product does not required 4 hops, 3 is sufficient.

Product does not required 4 hops, 3 is sufficient.
PlasticDigits commented 2026-05-26 09:42:23 +00:00 (Migrated from gitlab.com)

mentioned in commit 7d54939437

mentioned in commit 7d54939437c3252eedc48ba9a094319d55a3a572
PlasticDigits commented 2026-05-26 09:42:23 +00:00 (Migrated from gitlab.com)

mentioned in commit 392dd8253d

mentioned in commit 392dd8253d61077b83f7b6134f24a803070a9105
PlasticDigits commented 2026-05-26 09:42:49 +00:00 (Migrated from gitlab.com)

Implementation complete (pushed to main)

Summary: GET /api/v1/route/solve now runs hybrid per-hop optimization by default when amount_in is set (max 3 hops). Legacy integrators can pass pool_only=true (or hybrid_optimize=false) for pool-only ops (max 4 hops, hybrid: null). GET /route/solve/best remains an alias requiring amount_in.

Changes

  • Indexer: route_solver.rs — default hybrid GET path reuses execute_hybrid_route_solve; GET_DEFAULT_MAX_HOPS / GET_POOL_ONLY_MAX_HOPS constants; helper fns for pool-only vs hybrid routing.
  • Tests: route_solve_get_default_hybrid_two_hops, route_solve_pool_only_escape_hatch; updated route_solve_best_matches_hybrid_optimize to compare /best vs default GET.
  • Frontend: SwapPage + getRouteSolve client — no longer sends hybrid_optimize=true; added poolOnly option.
  • Docs: ADR 0001, indexer-invariants.md, integrators.md, limit-orders.md, contracts-security-audit.md (L8), testing.md.
  • Agent skills: AGENTS_INDEXER_HYBRID_BEST_EXECUTION.md, AGENTS_TESTING_MULTIHOP_HYBRID.md, AGENTS_FRONTEND_SWAP_ROUTE_DISPLAY.md, AGENTS_LOCALNET_TRADING_SWARM.md.

Verification checklist

  • cd indexer && cargo test --test api_route_solve -j 1 -- --test-threads=1 (Postgres + TEST_DATABASE_URL)
  • GET /api/v1/route/solve?token_in=…&token_out=…&amount_in=… returns non-null terra_swap.hybrid on hops when LCD/router configured
  • Same request with pool_only=true returns hybrid: null and quote_kind: indexer_pool_lcd
  • GET /route/solve/best matches default GET with amount_in (see route_solve_best_matches_hybrid_optimize)
  • Swap page CW20 multihop quotes without hybrid_optimize query param (npm test -- client.test.ts)
  • Localnet: small multihop swap — displayed route matches submitted ops

@brouie — please verify on your indexer deployment when convenient. Leaving issue open until sign-off.

GitLab #191 | merge 7d54939

## Implementation complete (pushed to `main`) **Summary:** `GET /api/v1/route/solve` now runs hybrid per-hop optimization **by default** when `amount_in` is set (max **3 hops**). Legacy integrators can pass `pool_only=true` (or `hybrid_optimize=false`) for pool-only ops (max 4 hops, `hybrid: null`). `GET /route/solve/best` remains an alias requiring `amount_in`. ### Changes - **Indexer:** `route_solver.rs` — default hybrid GET path reuses `execute_hybrid_route_solve`; `GET_DEFAULT_MAX_HOPS` / `GET_POOL_ONLY_MAX_HOPS` constants; helper fns for pool-only vs hybrid routing. - **Tests:** `route_solve_get_default_hybrid_two_hops`, `route_solve_pool_only_escape_hatch`; updated `route_solve_best_matches_hybrid_optimize` to compare `/best` vs default GET. - **Frontend:** `SwapPage` + `getRouteSolve` client — no longer sends `hybrid_optimize=true`; added `poolOnly` option. - **Docs:** ADR 0001, `indexer-invariants.md`, `integrators.md`, `limit-orders.md`, `contracts-security-audit.md` (L8), `testing.md`. - **Agent skills:** `AGENTS_INDEXER_HYBRID_BEST_EXECUTION.md`, `AGENTS_TESTING_MULTIHOP_HYBRID.md`, `AGENTS_FRONTEND_SWAP_ROUTE_DISPLAY.md`, `AGENTS_LOCALNET_TRADING_SWARM.md`. ### Verification checklist - [ ] `cd indexer && cargo test --test api_route_solve -j 1 -- --test-threads=1` (Postgres + `TEST_DATABASE_URL`) - [ ] `GET /api/v1/route/solve?token_in=…&token_out=…&amount_in=…` returns non-null `terra_swap.hybrid` on hops when LCD/router configured - [ ] Same request with `pool_only=true` returns `hybrid: null` and `quote_kind: indexer_pool_lcd` - [ ] `GET /route/solve/best` matches default GET with `amount_in` (see `route_solve_best_matches_hybrid_optimize`) - [ ] Swap page CW20 multihop quotes without `hybrid_optimize` query param (`npm test -- client.test.ts`) - [ ] Localnet: small multihop swap — displayed route matches submitted ops @brouie — please verify on your indexer deployment when convenient. Leaving issue **open** until sign-off. GitLab **#191** | merge `7d54939`
PlasticDigits commented 2026-05-27 07:13:25 +00:00 (Migrated from gitlab.com)

Verification complete — closing GitLab #191

Verified on local stack (LocalTerra healthy, host Postgres :5432, indexer :3001, frontend :5173, bot swarm 30/30).

Checklist

  • cargo test --test api_route_solve -j 1 -- --test-threads=1 — 14/14 passed (includes route_solve_get_default_hybrid_two_hops, route_solve_pool_only_escape_hatch, route_solve_best_matches_hybrid_optimize, degraded fallback)
  • Live GET /api/v1/route/solve?…&amount_in=… returns hybrid optimizer output (hybrid_notes set, non-null terra_swap.hybrid when book leg optimal; e.g. EMBER→CORAL)
  • Same with pool_only=true → quote_kind: indexer_pool_lcd, hybrid: null, no hybrid_notes
  • GET /route/solve/best matches default GET (estimated_amount_out + router_operations identical for 2-hop)
  • npm test -- client.test.ts — default GET omits hybrid_optimize; poolOnly adds pool_only=true
  • Swap UI (browser @ :5173): multihop quote EMBER→COBALT→SLATE uses default GET without hybrid_optimize; shows Execution: Indexer hybrid and route path

Implementation on main: 392dd82 (default hybrid GET, 3-hop cap, pool_only escape hatch) + 3f99e68 (degraded LCD fallback via pool simulation when HybridSimulation unavailable).

No additional code changes required from this verification pass.

## Verification complete — closing GitLab #191 Verified on local stack (LocalTerra healthy, host Postgres :5432, indexer :3001, frontend :5173, bot swarm 30/30). ### Checklist - [x] `cargo test --test api_route_solve -j 1 -- --test-threads=1` — **14/14 passed** (includes `route_solve_get_default_hybrid_two_hops`, `route_solve_pool_only_escape_hatch`, `route_solve_best_matches_hybrid_optimize`, degraded fallback) - [x] Live `GET /api/v1/route/solve?…&amount_in=…` returns hybrid optimizer output (`hybrid_notes` set, non-null `terra_swap.hybrid` when book leg optimal; e.g. EMBER→CORAL) - [x] Same with `pool_only=true` → `quote_kind: indexer_pool_lcd`, `hybrid: null`, no `hybrid_notes` - [x] `GET /route/solve/best` matches default GET (`estimated_amount_out` + `router_operations` identical for 2-hop) - [x] `npm test -- client.test.ts` — default GET omits `hybrid_optimize`; `poolOnly` adds `pool_only=true` - [x] Swap UI (browser @ :5173): multihop quote EMBER→COBALT→SLATE uses default GET without `hybrid_optimize`; shows **Execution: Indexer hybrid** and route path Implementation on `main`: `392dd82` (default hybrid GET, 3-hop cap, `pool_only` escape hatch) + `3f99e68` (degraded LCD fallback via pool `simulation` when `HybridSimulation` unavailable). No additional code changes required from this verification pass.
PlasticDigits (Migrated from gitlab.com) closed this issue 2026-05-27 07:13:26 +00:00
PlasticDigits commented 2026-05-29 03:09:57 +00:00 (Migrated from gitlab.com)

mentioned in issue #209

mentioned in issue #209
PlasticDigits commented 2026-05-29 03:10:00 +00:00 (Migrated from gitlab.com)

marked as related to #209

marked as related to #209
Brouie commented 2026-06-05 08:23:02 +00:00 (Migrated from gitlab.com)

mentioned in issue #323

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