feat(#293): route-based expected slippage + Expert Mode retail guard #828

Merged
PlasticDigits merged 4 commits from cursor/gitlab-issue-workflow-3ed3 into main 2026-06-06 08:27:15 +00:00
PlasticDigits commented 2026-06-06 07:15:36 +00:00 (Migrated from gitlab.com)

Summary

Implements GitLab #293 follow-up: classify excessive route slippage as a retail UX bug, show expected slippage from best-route token valuations, and gate high-slippage swaps behind Expert Mode (default off).

Indexer

  • New route_slippage module values each token via global best-execution solve → USTC-C/LUNC-C quote asset (30s cache).
  • GET/POST /api/v1/route/solve responses now include optional spot_amount_out, slippage_percent, token_in_price_quote, token_out_price_quote.

Frontend (Swap)

  • Trade summary shows Expected slippage (indexer route slippage when present; hop spread fallback).
  • Expert Mode toggle in Settings (default off, persisted in localStorage).
  • Swaps with expected slippage > 30% blocked with Slippage is too high + Enable Expert Mode affordance (modal warning).
  • ≥ 99% extreme-slippage alert always shown (even with Expert Mode).

Docs

  • docs/swap-max-spread-ux.md invariant #7 + cross-links.
  • skills/AGENTS_FRONTEND_SWAP_ROUTE_DISPLAY.md updated.

Acceptance checklist

Item Command / step Result
Indexer slippage unit tests cd indexer && cargo test --lib route_slippage PASS
Indexer lib regression cd indexer && cargo test --lib PASS
Frontend slippage + Swap tests cd frontend-dapp && npm run test:run -- src/utils/swapRouteSlippage.test.ts src/pages/SwapPage.test.tsx PASS
Expert Mode blocks >30% slippage SwapPage.test.tsx blocks swap above 30% route slippage PASS
Live EMBER→CORAL extreme slippage UI LocalTerra + indexer + make dev, enter 1 EMBER→CORAL SKIP (no full stack in agent VM)
make verify-issue-293 swarm quotes make verify-issue-293 SKIP (no LocalTerra)

Verification for third parties

  1. make setup-cloud-localterra (or existing LocalTerra + indexer).
  2. Open Swap, select EMBER → CORAL, amount 1.
  3. Confirm Expected slippage shows ≥ 99% and swap is blocked (Expert Mode off).
  4. Settings → enable Expert Mode via modal → submit unblocks (extreme warning remains).
  5. curl 'http://127.0.0.1:3001/api/v1/route/solve?token_in=<EMBER>&token_out=<CORAL>&amount_in=1000000' includes slippage_percent and spot_amount_out.

Issue left open pending live QA on LocalTerra.


Note

Medium Risk
Changes quote/solve latency (extra nested solves for slippage) and adds a client-side submit gate that does not replace on-chain max-spread checks; mispriced reference routes could affect when Expert Mode is required.

Overview
Implements GitLab #293: route quotes are compared to fair cross-rates from best-route token valuations, and retail Swap submit is gated when deviation is extreme.

Indexer adds route_slippage to derive token prices via global best-execution (1 whole token → USTC/LUNC quote) with a 30s cache, then attach spot_amount_out, slippage_percent, and quote-denominated token prices on GET/POST /api/v1/route/solve (and best execution when enrich_slippage is on). Nested price lookups call the solver with enrich_slippage: false to avoid recursion; hybrid route cache hits re-run enrichment with amount scaling for bucketed amounts.

Swap dApp renames the primary metric to Expected slippage (indexer route slippage when present, hop spread fallback), surfaces hop spread as secondary context, and blocks submit above 30% unless Expert Mode is enabled (Settings toggle, localStorage, confirmation modal). ≥99% always shows an extreme-slippage alert. Docs and agent skills are updated accordingly.

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

## Summary Implements GitLab [#293](https://gitlab.com/PlasticDigits/cl8y-dex-terraclassic/-/work_items/293) follow-up: classify excessive route slippage as a retail UX bug, show **expected slippage** from best-route token valuations, and gate high-slippage swaps behind **Expert Mode** (default off). ### Indexer - New `route_slippage` module values each token via global best-execution solve → USTC-C/LUNC-C quote asset (30s cache). - `GET/POST /api/v1/route/solve` responses now include optional `spot_amount_out`, `slippage_percent`, `token_in_price_quote`, `token_out_price_quote`. ### Frontend (Swap) - Trade summary shows **Expected slippage** (indexer route slippage when present; hop spread fallback). - **Expert Mode** toggle in Settings (default off, persisted in localStorage). - Swaps with expected slippage **> 30%** blocked with **Slippage is too high** + **Enable Expert Mode** affordance (modal warning). - **≥ 99%** extreme-slippage alert always shown (even with Expert Mode). ### Docs - `docs/swap-max-spread-ux.md` invariant **#7** + cross-links. - `skills/AGENTS_FRONTEND_SWAP_ROUTE_DISPLAY.md` updated. ## Acceptance checklist | Item | Command / step | Result | |------|----------------|--------| | Indexer slippage unit tests | `cd indexer && cargo test --lib route_slippage` | **PASS** | | Indexer lib regression | `cd indexer && cargo test --lib` | **PASS** | | Frontend slippage + Swap tests | `cd frontend-dapp && npm run test:run -- src/utils/swapRouteSlippage.test.ts src/pages/SwapPage.test.tsx` | **PASS** | | Expert Mode blocks >30% slippage | SwapPage.test.tsx `blocks swap above 30% route slippage` | **PASS** | | Live EMBER→CORAL extreme slippage UI | LocalTerra + indexer + `make dev`, enter 1 EMBER→CORAL | **SKIP** (no full stack in agent VM) | | `make verify-issue-293` swarm quotes | `make verify-issue-293` | **SKIP** (no LocalTerra) | ## Verification for third parties 1. `make setup-cloud-localterra` (or existing LocalTerra + indexer). 2. Open Swap, select EMBER → CORAL, amount `1`. 3. Confirm **Expected slippage** shows **≥ 99%** and swap is blocked (Expert Mode off). 4. Settings → enable **Expert Mode** via modal → submit unblocks (extreme warning remains). 5. `curl 'http://127.0.0.1:3001/api/v1/route/solve?token_in=<EMBER>&token_out=<CORAL>&amount_in=1000000'` includes `slippage_percent` and `spot_amount_out`. Issue left **open** pending live QA on LocalTerra. <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **Medium Risk** > Changes quote/solve latency (extra nested solves for slippage) and adds a client-side submit gate that does not replace on-chain max-spread checks; mispriced reference routes could affect when Expert Mode is required. > > **Overview** > Implements GitLab **#293**: route quotes are compared to fair cross-rates from best-route token valuations, and retail Swap submit is gated when deviation is extreme. > > **Indexer** adds `route_slippage` to derive token prices via global best-execution (1 whole token → USTC/LUNC quote) with a 30s cache, then attach `spot_amount_out`, `slippage_percent`, and quote-denominated token prices on `GET/POST /api/v1/route/solve` (and best execution when `enrich_slippage` is on). Nested price lookups call the solver with `enrich_slippage: false` to avoid recursion; hybrid route cache hits re-run enrichment with amount scaling for bucketed amounts. > > **Swap dApp** renames the primary metric to **Expected slippage** (indexer route slippage when present, hop spread fallback), surfaces hop spread as secondary context, and blocks submit above **30%** unless **Expert Mode** is enabled (Settings toggle, `localStorage`, confirmation modal). **≥99%** always shows an extreme-slippage alert. Docs and agent skills are updated accordingly. > > <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit 443e8af85f2ceb4985494bed3bcbff4d4344d4ca. 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-06 07:15:43 +00:00 (Migrated from gitlab.com)

changed the description

changed the description
PlasticDigits commented 2026-06-06 07:15:43 +00:00 (Migrated from gitlab.com)

mentioned in issue #293

mentioned in issue #293
ghost1 commented 2026-06-06 07:15:52 +00:00 (Migrated from gitlab.com)

changed the description

changed the description
ghost1 commented 2026-06-06 07:17:17 +00:00 (Migrated from gitlab.com)
Stale Security Review comment

Cursor Bugbot has reviewed your changes and found 4 potential issues.
Bugbot Autofix is ON. A cloud agent has been kicked off to fix the reported issues.

Reviewed by Cursor Bugbot for commit 081e80e940. Configure here.

<details> <summary>Stale Security Review comment</summary> <!-- BUGBOT_REVIEW --> Cursor Bugbot has reviewed your changes and found 4 potential issues.<!-- BUGBOT_AUTOFIX_REVIEW_FOOTNOTE_BEGIN --> <sup>Bugbot Autofix is [ON](https://www.cursor.com/dashboard/bugbot). A cloud agent has been kicked off to fix the reported issues. <!-- BUGBOT_AUTOFIX_AGENT_LINK --></sup> <!-- BUGBOT_AUTOFIX_REVIEW_FOOTNOTE_END --> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit 081e80e9403f3171322ed060a6c66614c0a2f3e5. Configure [here](https://www.cursor.com/dashboard/bugbot).</sup> </details>
ghost1 commented 2026-06-06 07:17:18 +00:00 (Migrated from gitlab.com)

Token price cache ignores trader

Medium Severity

Reference token prices are cached under only token→quote, but token_price_in_quote runs best-execution with the request quote_trader (fee tier / discount). Later requests with a different trader reuse the first price for 30s, so slippage_percent and Expert Mode blocking can be wrong for discounted wallets.

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 081e80e940. Configure here.

### Token price cache ignores trader **Medium Severity** <!-- DESCRIPTION START --> Reference token prices are cached under only `token→quote`, but `token_price_in_quote` runs best-execution with the request `quote_trader` (fee tier / discount). Later requests with a different trader reuse the first price for 30s, so `slippage_percent` and Expert Mode blocking can be wrong for discounted wallets. <!-- DESCRIPTION END --> <!-- BUGBOT_BUG_ID: 5e9b525e-c470-4c45-b14d-b047e1bb22a9 --> <!-- LOCATIONS START indexer/src/api/route_slippage.rs#L133-L167 LOCATIONS END --> <div><a href="https://cursor.com/open?link=eyJ2ZXJzaW9uIjoxLCJ0eXBlIjoiQlVHQk9UX0ZJWF9JTl9DVVJTT1IiLCJkYXRhIjp7InJlZGlzS2V5IjoiYnVnYm90OmI3MzU5MmM1LTc5NDMtNDAwNC1hZWEyLTQ1ZDU3MmMyNzAzMyIsImVuY3J5cHRpb25LZXkiOiJCY190Rm5VZ2F2dFgtWHpEazFUUXE4anR1bG1OQ2ViM1lKc0dRVEk0UjVFIiwiYnJhbmNoIjoiY3Vyc29yL2dpdGxhYi1pc3N1ZS13b3JrZmxvdy0zZWQzIiwicmVwb093bmVyIjoiUGxhc3RpY0RpZ2l0cyIsInJlcG9OYW1lIjoiY2w4eS1kZXgtdGVycmFjbGFzc2ljIn19" target="_blank" rel="noopener noreferrer"><picture><source media="(prefers-color-scheme: dark)" srcset="https://cursor.com/assets/images/fix-in-cursor-dark.png"><source media="(prefers-color-scheme: light)" srcset="https://cursor.com/assets/images/fix-in-cursor-light.png"><img alt="Fix in Cursor" width="115" height="28" src="https://cursor.com/assets/images/fix-in-cursor-dark.png"></picture></a>&nbsp;<a href="https://cursor.com/agents?link=eyJ2ZXJzaW9uIjoxLCJ0eXBlIjoiQlVHQk9UX0ZJWF9JTl9XRUIiLCJkYXRhIjp7InJlZGlzS2V5IjoiYnVnYm90OmI3MzU5MmM1LTc5NDMtNDAwNC1hZWEyLTQ1ZDU3MmMyNzAzMyIsImVuY3J5cHRpb25LZXkiOiJCY190Rm5VZ2F2dFgtWHpEazFUUXE4anR1bG1OQ2ViM1lKc0dRVEk0UjVFIiwiYnJhbmNoIjoiY3Vyc29yL2dpdGxhYi1pc3N1ZS13b3JrZmxvdy0zZWQzIiwicmVwb093bmVyIjoiUGxhc3RpY0RpZ2l0cyIsInJlcG9OYW1lIjoiY2w4eS1kZXgtdGVycmFjbGFzc2ljIiwicHJOdW1iZXIiOjExMCwiY29tbWl0U2hhIjoiMDgxZTgwZTk0MDNmMzE3MTMyMmVkMDYwYTZjNjY2MTRjMGEyZjNlNSIsInByb3ZpZGVyIjoiZ2l0bGFiIiwiaG9zdG5hbWUiOiJnaXRsYWIuY29tIn19" target="_blank" rel="noopener noreferrer"><picture><source media="(prefers-color-scheme: dark)" srcset="https://cursor.com/assets/images/fix-in-web-dark.png"><source media="(prefers-color-scheme: light)" srcset="https://cursor.com/assets/images/fix-in-web-light.png"><img alt="Fix in Web" width="99" height="28" src="https://cursor.com/assets/images/fix-in-web-dark.png"></picture></a></div> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit 081e80e9403f3171322ed060a6c66614c0a2f3e5. Configure [here](https://www.cursor.com/dashboard/bugbot).</sup>
ghost1 commented 2026-06-06 07:17:18 +00:00 (Migrated from gitlab.com)

Indexer slippage, wallet receive

Medium Severity

The trade summary shows return_amount from wallet simulateMultiHopSwap, but Expected slippage and Expert Mode blocking use idx.slippage_percent from the indexer, which is computed against the indexer’s estimated_amount_out. If LCD wallet sim and indexer output diverge, users see one receive amount while guards and labels reflect another quote.

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 081e80e940. Configure here.

### Indexer slippage, wallet receive **Medium Severity** <!-- DESCRIPTION START --> The trade summary shows `return_amount` from wallet `simulateMultiHopSwap`, but Expected slippage and Expert Mode blocking use `idx.slippage_percent` from the indexer, which is computed against the indexer’s `estimated_amount_out`. If LCD wallet sim and indexer output diverge, users see one receive amount while guards and labels reflect another quote. <!-- DESCRIPTION END --> <!-- BUGBOT_BUG_ID: 4e673ae6-a28a-4130-992d-534c87a281c3 --> <!-- LOCATIONS START frontend-dapp/src/pages/SwapPage.tsx#L474-L490 LOCATIONS END --> <div><a href="https://cursor.com/open?link=eyJ2ZXJzaW9uIjoxLCJ0eXBlIjoiQlVHQk9UX0ZJWF9JTl9DVVJTT1IiLCJkYXRhIjp7InJlZGlzS2V5IjoiYnVnYm90OjQzZWY4ZDU3LTk5NTUtNDE5ZC1iOTBiLWVmNmUxMjllZmMxNyIsImVuY3J5cHRpb25LZXkiOiJsZVRSNVRYbWpwNHZmdHZRaGl1MUFVNFFDMnBoM2tCYll2STBJLVQwUnlNIiwiYnJhbmNoIjoiY3Vyc29yL2dpdGxhYi1pc3N1ZS13b3JrZmxvdy0zZWQzIiwicmVwb093bmVyIjoiUGxhc3RpY0RpZ2l0cyIsInJlcG9OYW1lIjoiY2w4eS1kZXgtdGVycmFjbGFzc2ljIn19" target="_blank" rel="noopener noreferrer"><picture><source media="(prefers-color-scheme: dark)" srcset="https://cursor.com/assets/images/fix-in-cursor-dark.png"><source media="(prefers-color-scheme: light)" srcset="https://cursor.com/assets/images/fix-in-cursor-light.png"><img alt="Fix in Cursor" width="115" height="28" src="https://cursor.com/assets/images/fix-in-cursor-dark.png"></picture></a>&nbsp;<a href="https://cursor.com/agents?link=eyJ2ZXJzaW9uIjoxLCJ0eXBlIjoiQlVHQk9UX0ZJWF9JTl9XRUIiLCJkYXRhIjp7InJlZGlzS2V5IjoiYnVnYm90OjQzZWY4ZDU3LTk5NTUtNDE5ZC1iOTBiLWVmNmUxMjllZmMxNyIsImVuY3J5cHRpb25LZXkiOiJsZVRSNVRYbWpwNHZmdHZRaGl1MUFVNFFDMnBoM2tCYll2STBJLVQwUnlNIiwiYnJhbmNoIjoiY3Vyc29yL2dpdGxhYi1pc3N1ZS13b3JrZmxvdy0zZWQzIiwicmVwb093bmVyIjoiUGxhc3RpY0RpZ2l0cyIsInJlcG9OYW1lIjoiY2w4eS1kZXgtdGVycmFjbGFzc2ljIiwicHJOdW1iZXIiOjExMCwiY29tbWl0U2hhIjoiMDgxZTgwZTk0MDNmMzE3MTMyMmVkMDYwYTZjNjY2MTRjMGEyZjNlNSIsInByb3ZpZGVyIjoiZ2l0bGFiIiwiaG9zdG5hbWUiOiJnaXRsYWIuY29tIn19" target="_blank" rel="noopener noreferrer"><picture><source media="(prefers-color-scheme: dark)" srcset="https://cursor.com/assets/images/fix-in-web-dark.png"><source media="(prefers-color-scheme: light)" srcset="https://cursor.com/assets/images/fix-in-web-light.png"><img alt="Fix in Web" width="99" height="28" src="https://cursor.com/assets/images/fix-in-web-dark.png"></picture></a></div> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit 081e80e9403f3171322ed060a6c66614c0a2f3e5. Configure [here](https://www.cursor.com/dashboard/bugbot).</sup>
ghost1 commented 2026-06-06 07:17:18 +00:00 (Migrated from gitlab.com)

Token prices use fixed makers

Low Severity

Token reference prices always call best execution with max_maker_fills hardcoded to 8, while the user’s swap solve uses hybridMaxMakers from Settings. Different maker-fill limits change hybrid quotes, so expected slippage can disagree with the route actually being priced.

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 081e80e940. Configure here.

### Token prices use fixed makers **Low Severity** <!-- DESCRIPTION START --> Token reference prices always call best execution with `max_maker_fills` hardcoded to `8`, while the user’s swap solve uses `hybridMaxMakers` from Settings. Different maker-fill limits change hybrid quotes, so expected slippage can disagree with the route actually being priced. <!-- DESCRIPTION END --> <!-- BUGBOT_BUG_ID: 71377f71-2e9e-49c1-b4ec-a2ba7b61548c --> <!-- LOCATIONS START indexer/src/api/route_slippage.rs#L144-L154 LOCATIONS END --> <div><a href="https://cursor.com/open?link=eyJ2ZXJzaW9uIjoxLCJ0eXBlIjoiQlVHQk9UX0ZJWF9JTl9DVVJTT1IiLCJkYXRhIjp7InJlZGlzS2V5IjoiYnVnYm90OjViNDc4NjY1LTRkZmItNDY2Ni04YWI3LWIxYTljMDdkNTM0MyIsImVuY3J5cHRpb25LZXkiOiIzSTBNTDN6Um9TR1IzSTd3Y1FIMWlXSXlXWTNjU2tRTmtoS3owVVI0WFNZIiwiYnJhbmNoIjoiY3Vyc29yL2dpdGxhYi1pc3N1ZS13b3JrZmxvdy0zZWQzIiwicmVwb093bmVyIjoiUGxhc3RpY0RpZ2l0cyIsInJlcG9OYW1lIjoiY2w4eS1kZXgtdGVycmFjbGFzc2ljIn19" target="_blank" rel="noopener noreferrer"><picture><source media="(prefers-color-scheme: dark)" srcset="https://cursor.com/assets/images/fix-in-cursor-dark.png"><source media="(prefers-color-scheme: light)" srcset="https://cursor.com/assets/images/fix-in-cursor-light.png"><img alt="Fix in Cursor" width="115" height="28" src="https://cursor.com/assets/images/fix-in-cursor-dark.png"></picture></a>&nbsp;<a href="https://cursor.com/agents?link=eyJ2ZXJzaW9uIjoxLCJ0eXBlIjoiQlVHQk9UX0ZJWF9JTl9XRUIiLCJkYXRhIjp7InJlZGlzS2V5IjoiYnVnYm90OjViNDc4NjY1LTRkZmItNDY2Ni04YWI3LWIxYTljMDdkNTM0MyIsImVuY3J5cHRpb25LZXkiOiIzSTBNTDN6Um9TR1IzSTd3Y1FIMWlXSXlXWTNjU2tRTmtoS3owVVI0WFNZIiwiYnJhbmNoIjoiY3Vyc29yL2dpdGxhYi1pc3N1ZS13b3JrZmxvdy0zZWQzIiwicmVwb093bmVyIjoiUGxhc3RpY0RpZ2l0cyIsInJlcG9OYW1lIjoiY2w4eS1kZXgtdGVycmFjbGFzc2ljIiwicHJOdW1iZXIiOjExMCwiY29tbWl0U2hhIjoiMDgxZTgwZTk0MDNmMzE3MTMyMmVkMDYwYTZjNjY2MTRjMGEyZjNlNSIsInByb3ZpZGVyIjoiZ2l0bGFiIiwiaG9zdG5hbWUiOiJnaXRsYWIuY29tIn19" target="_blank" rel="noopener noreferrer"><picture><source media="(prefers-color-scheme: dark)" srcset="https://cursor.com/assets/images/fix-in-web-dark.png"><source media="(prefers-color-scheme: light)" srcset="https://cursor.com/assets/images/fix-in-web-light.png"><img alt="Fix in Web" width="99" height="28" src="https://cursor.com/assets/images/fix-in-web-dark.png"></picture></a></div> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit 081e80e9403f3171322ed060a6c66614c0a2f3e5. Configure [here](https://www.cursor.com/dashboard/bugbot).</sup>
ghost1 commented 2026-06-06 07:17:18 +00:00 (Migrated from gitlab.com)

Cached slippage wrong trade size

Medium Severity

Hybrid GET /api/v1/route/solve caches the full solve JSON (including new slippage_percent / spot_amount_out) by coarse amount_in bucket. Cache hits return slippage computed for a different raw amount than the request, so Expected slippage and the >30% Expert Mode block can be incorrect.

Additional Locations (1)
Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 081e80e940. Configure here.

### Cached slippage wrong trade size **Medium Severity** <!-- DESCRIPTION START --> Hybrid `GET /api/v1/route/solve` caches the full solve JSON (including new `slippage_percent` / `spot_amount_out`) by coarse `amount_in` bucket. Cache hits return slippage computed for a different raw amount than the request, so Expected slippage and the &gt;30% Expert Mode block can be incorrect. <!-- DESCRIPTION END --> <!-- BUGBOT_BUG_ID: f2bbbd3c-e563-46bb-b26a-369dab6bcc2e --> <!-- LOCATIONS START indexer/src/api/best_execution.rs#L695-L698 indexer/src/api/route_solver.rs#L725-L727 LOCATIONS END --> <details> <summary>Additional Locations (1)</summary> - [`indexer/src/api/route_solver.rs#L725-L727`](https://gitlab.com/PlasticDigits/cl8y-dex-terraclassic/-//blob/081e80e9403f3171322ed060a6c66614c0a2f3e5/indexer/src/api/route_solver.rs#L725-L727) </details> <div><a href="https://cursor.com/open?link=eyJ2ZXJzaW9uIjoxLCJ0eXBlIjoiQlVHQk9UX0ZJWF9JTl9DVVJTT1IiLCJkYXRhIjp7InJlZGlzS2V5IjoiYnVnYm90OmQ2YWUyZTliLWRlNzYtNDYyMS05MzNiLTViODMxNWNhMzIzYyIsImVuY3J5cHRpb25LZXkiOiJGcjZ1dnpFa2hwbDkyaTVZWm10ZVMzLWJ4OGxweGVoZXpmTWx0OHdvS21nIiwiYnJhbmNoIjoiY3Vyc29yL2dpdGxhYi1pc3N1ZS13b3JrZmxvdy0zZWQzIiwicmVwb093bmVyIjoiUGxhc3RpY0RpZ2l0cyIsInJlcG9OYW1lIjoiY2w4eS1kZXgtdGVycmFjbGFzc2ljIn19" target="_blank" rel="noopener noreferrer"><picture><source media="(prefers-color-scheme: dark)" srcset="https://cursor.com/assets/images/fix-in-cursor-dark.png"><source media="(prefers-color-scheme: light)" srcset="https://cursor.com/assets/images/fix-in-cursor-light.png"><img alt="Fix in Cursor" width="115" height="28" src="https://cursor.com/assets/images/fix-in-cursor-dark.png"></picture></a>&nbsp;<a href="https://cursor.com/agents?link=eyJ2ZXJzaW9uIjoxLCJ0eXBlIjoiQlVHQk9UX0ZJWF9JTl9XRUIiLCJkYXRhIjp7InJlZGlzS2V5IjoiYnVnYm90OmQ2YWUyZTliLWRlNzYtNDYyMS05MzNiLTViODMxNWNhMzIzYyIsImVuY3J5cHRpb25LZXkiOiJGcjZ1dnpFa2hwbDkyaTVZWm10ZVMzLWJ4OGxweGVoZXpmTWx0OHdvS21nIiwiYnJhbmNoIjoiY3Vyc29yL2dpdGxhYi1pc3N1ZS13b3JrZmxvdy0zZWQzIiwicmVwb093bmVyIjoiUGxhc3RpY0RpZ2l0cyIsInJlcG9OYW1lIjoiY2w4eS1kZXgtdGVycmFjbGFzc2ljIiwicHJOdW1iZXIiOjExMCwiY29tbWl0U2hhIjoiMDgxZTgwZTk0MDNmMzE3MTMyMmVkMDYwYTZjNjY2MTRjMGEyZjNlNSIsInByb3ZpZGVyIjoiZ2l0bGFiIiwiaG9zdG5hbWUiOiJnaXRsYWIuY29tIn19" target="_blank" rel="noopener noreferrer"><picture><source media="(prefers-color-scheme: dark)" srcset="https://cursor.com/assets/images/fix-in-web-dark.png"><source media="(prefers-color-scheme: light)" srcset="https://cursor.com/assets/images/fix-in-web-light.png"><img alt="Fix in Web" width="99" height="28" src="https://cursor.com/assets/images/fix-in-web-dark.png"></picture></a></div> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit 081e80e9403f3171322ed060a6c66614c0a2f3e5. Configure [here](https://www.cursor.com/dashboard/bugbot).</sup>
PlasticDigits commented 2026-06-06 07:17:54 +00:00 (Migrated from gitlab.com)

Security review

Commit reviewed: 081e80e9403f3171322ed060a6c66614c0a2f3e5

Scope: MR !828 — route-based expected slippage (indexer/src/api/route_slippage.rs, route_solver.rs, best_execution.rs) and Swap Expert Mode retail guard (SwapPage.tsx, expertMode.ts, swapRouteSlippage.ts).

Outcome: FINDINGS: 0 medium+

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

Reviewed areas:

  • Indexer nested solves: enrich_route_slippage adds up to two cached (30s) solve_global_best_execution_inner calls per /api/v1/route/solve request (enrich_slippage: false prevents recursion). This increases LCD work within the existing LCD-heavy rate limit (RATE_LIMIT_LCD_HEAVY_RPS, default 10) already applied to route solve; no bypass or unbounded amplification path found.
  • Expert Mode / slippage block: Client-side UX guard only; on-chain max_spread / min_return enforcement unchanged. Not a security boundary — direct contract interaction remains possible by design.
  • API → UI data flow: slippage_percent is parsed with parseFloat + Number.isFinite before display; React text rendering (no dangerouslySetInnerHTML). No XSS or injection sink.
  • Secrets / error leakage: New response fields are pricing metadata only; no LCD URLs, internal paths, or credential exposure added.
  • Dependencies: No Cargo.toml / package.json changes in this diff.

Inline threads: None (no findings to anchor).

Prior security-review comments on this MR: none to re-report.

## Security review **Commit reviewed:** `081e80e9403f3171322ed060a6c66614c0a2f3e5` **Scope:** MR !828 — route-based expected slippage (`indexer/src/api/route_slippage.rs`, `route_solver.rs`, `best_execution.rs`) and Swap Expert Mode retail guard (`SwapPage.tsx`, `expertMode.ts`, `swapRouteSlippage.ts`). **Outcome:** `FINDINGS: 0` medium+ **Summary:** No medium, high, or critical vulnerabilities identified on this diff. Reviewed areas: - **Indexer nested solves:** `enrich_route_slippage` adds up to two cached (`30s`) `solve_global_best_execution_inner` calls per `/api/v1/route/solve` request (`enrich_slippage: false` prevents recursion). This increases LCD work within the existing LCD-heavy rate limit (`RATE_LIMIT_LCD_HEAVY_RPS`, default 10) already applied to route solve; no bypass or unbounded amplification path found. - **Expert Mode / slippage block:** Client-side UX guard only; on-chain `max_spread` / `min_return` enforcement unchanged. Not a security boundary — direct contract interaction remains possible by design. - **API → UI data flow:** `slippage_percent` is parsed with `parseFloat` + `Number.isFinite` before display; React text rendering (no `dangerouslySetInnerHTML`). No XSS or injection sink. - **Secrets / error leakage:** New response fields are pricing metadata only; no LCD URLs, internal paths, or credential exposure added. - **Dependencies:** No `Cargo.toml` / `package.json` changes in this diff. **Inline threads:** None (no findings to anchor). Prior security-review comments on this MR: none to re-report.
ghost1 commented 2026-06-06 07:21:33 +00:00 (Migrated from gitlab.com)

changed this line in version 2 of the diff

changed this line in [version 2 of the diff](/PlasticDigits/cl8y-dex-terraclassic/-/merge_requests/110/diffs?diff_id=1837860604&start_sha=081e80e9403f3171322ed060a6c66614c0a2f3e5#b15023e39a0ac993be6d71725f8fcbff5724339e_698_697)
ghost1 commented 2026-06-06 07:21:33 +00:00 (Migrated from gitlab.com)

added 1 commit

  • 977adae9 - Fix slippage cache keys, cache-hit recomputation, and wallet-aligned UI

Compare with previous version

added 1 commit <ul><li>977adae9 - Fix slippage cache keys, cache-hit recomputation, and wallet-aligned UI</li></ul> [Compare with previous version](/PlasticDigits/cl8y-dex-terraclassic/-/merge_requests/110/diffs?diff_id=1837860604&start_sha=081e80e9403f3171322ed060a6c66614c0a2f3e5)
ghost1 commented 2026-06-06 07:21:46 +00:00 (Migrated from gitlab.com)

changed the description

changed the description
ghost1 commented 2026-06-06 07:22:23 +00:00 (Migrated from gitlab.com)

resolved all threads

resolved all threads
ghost1 commented 2026-06-06 07:23:15 +00:00 (Migrated from gitlab.com)

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Fix All in Cursor

Bugbot Autofix is ON. A cloud agent has been kicked off to fix the reported issue.

Reviewed by Cursor Bugbot for commit 977adae9c8. Configure here.

<!-- BUGBOT_REVIEW --> Cursor Bugbot has reviewed your changes and found 1 potential issue. <!-- BUGBOT_FIX_ALL --> <a href="https://cursor.com/open?link=eyJ2ZXJzaW9uIjoxLCJ0eXBlIjoiQlVHQk9UX0ZJWF9BTExfSU5fQ1VSU09SIiwiZGF0YSI6eyJyZWRpc0tleSI6ImJ1Z2JvdC1tdWx0aTowMmYyYWUzMC02NTViLTRjYzQtYWVhYi02ODlhMWQ2NjhmMDYiLCJlbmNyeXB0aW9uS2V5IjoieGgxa2lhbHdrNEtLMmprdFh2VzFZQThrUTdOamJJRVNnY3pkY3Q1OHd2dyIsImJyYW5jaCI6ImN1cnNvci9naXRsYWItaXNzdWUtd29ya2Zsb3ctM2VkMyIsInJlcG9Pd25lciI6IlBsYXN0aWNEaWdpdHMiLCJyZXBvTmFtZSI6ImNsOHktZGV4LXRlcnJhY2xhc3NpYyJ9fQ" target="_blank" rel="noopener noreferrer"><picture><source media="(prefers-color-scheme: dark)" srcset="https://cursor.com/assets/images/fix-in-cursor-dark.png"><source media="(prefers-color-scheme: light)" srcset="https://cursor.com/assets/images/fix-in-cursor-light.png"><img alt="Fix All in Cursor" width="115" height="28" src="https://cursor.com/assets/images/fix-in-cursor-dark.png"></picture></a> <!-- /BUGBOT_FIX_ALL --> <!-- BUGBOT_AUTOFIX_REVIEW_FOOTNOTE_BEGIN --> <sup>Bugbot Autofix is [ON](https://www.cursor.com/dashboard/bugbot). A cloud agent has been kicked off to fix the reported issue. <!-- BUGBOT_AUTOFIX_AGENT_LINK --></sup> <!-- BUGBOT_AUTOFIX_REVIEW_FOOTNOTE_END --> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit 977adae9c8dc97179a4de04849f25a6f0be04c68. Configure [here](https://www.cursor.com/dashboard/bugbot).</sup>
ghost1 commented 2026-06-06 07:23:16 +00:00 (Migrated from gitlab.com)

Cached route slippage amount mismatch

Medium Severity

On a hybrid GET cache hit, enrich_route_slippage runs with the caller’s amount_in but still uses the cached estimated_amount_out from an earlier solve. Amounts in the same coarse bucket (e.g. 1.5M vs 1.9M raw) share a cache key, so slippage_percent can disagree with spot_amount_out and misstate route slippage for API consumers.

Additional Locations (1)
Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 977adae9c8. Configure here.

### Cached route slippage amount mismatch **Medium Severity** <!-- DESCRIPTION START --> On a hybrid GET cache hit, `enrich_route_slippage` runs with the caller’s `amount_in` but still uses the cached `estimated_amount_out` from an earlier solve. Amounts in the same coarse bucket (e.g. 1.5M vs 1.9M raw) share a cache key, so `slippage_percent` can disagree with `spot_amount_out` and misstate route slippage for API consumers. <!-- DESCRIPTION END --> <!-- BUGBOT_BUG_ID: 0d64c5cd-1362-422d-9d0c-903e3e810fed --> <!-- LOCATIONS START indexer/src/api/route_solver.rs#L725-L736 indexer/src/api/route_slippage.rs#L188-L253 LOCATIONS END --> <details> <summary>Additional Locations (1)</summary> - [`indexer/src/api/route_slippage.rs#L188-L253`](https://gitlab.com/PlasticDigits/cl8y-dex-terraclassic/-//blob/977adae9c8dc97179a4de04849f25a6f0be04c68/indexer/src/api/route_slippage.rs#L188-L253) </details> <div><a href="https://cursor.com/open?link=eyJ2ZXJzaW9uIjoxLCJ0eXBlIjoiQlVHQk9UX0ZJWF9JTl9DVVJTT1IiLCJkYXRhIjp7InJlZGlzS2V5IjoiYnVnYm90OjczOWY3NTFhLTc2NWQtNDk0MS04YTk1LTMxZjE0OTZjZTY3ZiIsImVuY3J5cHRpb25LZXkiOiI3SkNKeVFLaXdpblVpa2NHSmRhUjZPV3huemhRbmt3UUlEdkVvS0lQRU9rIiwiYnJhbmNoIjoiY3Vyc29yL2dpdGxhYi1pc3N1ZS13b3JrZmxvdy0zZWQzIiwicmVwb093bmVyIjoiUGxhc3RpY0RpZ2l0cyIsInJlcG9OYW1lIjoiY2w4eS1kZXgtdGVycmFjbGFzc2ljIn19" target="_blank" rel="noopener noreferrer"><picture><source media="(prefers-color-scheme: dark)" srcset="https://cursor.com/assets/images/fix-in-cursor-dark.png"><source media="(prefers-color-scheme: light)" srcset="https://cursor.com/assets/images/fix-in-cursor-light.png"><img alt="Fix in Cursor" width="115" height="28" src="https://cursor.com/assets/images/fix-in-cursor-dark.png"></picture></a>&nbsp;<a href="https://cursor.com/agents?link=eyJ2ZXJzaW9uIjoxLCJ0eXBlIjoiQlVHQk9UX0ZJWF9JTl9XRUIiLCJkYXRhIjp7InJlZGlzS2V5IjoiYnVnYm90OjczOWY3NTFhLTc2NWQtNDk0MS04YTk1LTMxZjE0OTZjZTY3ZiIsImVuY3J5cHRpb25LZXkiOiI3SkNKeVFLaXdpblVpa2NHSmRhUjZPV3huemhRbmt3UUlEdkVvS0lQRU9rIiwiYnJhbmNoIjoiY3Vyc29yL2dpdGxhYi1pc3N1ZS13b3JrZmxvdy0zZWQzIiwicmVwb093bmVyIjoiUGxhc3RpY0RpZ2l0cyIsInJlcG9OYW1lIjoiY2w4eS1kZXgtdGVycmFjbGFzc2ljIiwicHJOdW1iZXIiOjExMCwiY29tbWl0U2hhIjoiOTc3YWRhZTljOGRjOTcxNzlhNGRlMDQ4NDlmMjVhNmYwYmUwNGM2OCIsInByb3ZpZGVyIjoiZ2l0bGFiIiwiaG9zdG5hbWUiOiJnaXRsYWIuY29tIn19" target="_blank" rel="noopener noreferrer"><picture><source media="(prefers-color-scheme: dark)" srcset="https://cursor.com/assets/images/fix-in-web-dark.png"><source media="(prefers-color-scheme: light)" srcset="https://cursor.com/assets/images/fix-in-web-light.png"><img alt="Fix in Web" width="99" height="28" src="https://cursor.com/assets/images/fix-in-web-dark.png"></picture></a></div> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit 977adae9c8dc97179a4de04849f25a6f0be04c68. Configure [here](https://www.cursor.com/dashboard/bugbot).</sup>
PlasticDigits commented 2026-06-06 07:23:24 +00:00 (Migrated from gitlab.com)

Security review

Commit reviewed: 977adae9c8dc97179a4de04849f25a6f0be04c68

Scope: MR !828 (re-review after fix commit) — route-based expected slippage (indexer/src/api/route_slippage.rs, route_solver.rs, best_execution.rs) and Swap Expert Mode retail guard (SwapPage.tsx, expertMode.ts, swapRouteSlippage.ts).

Outcome: FINDINGS: 0 medium+

Summary: Security review: no medium, high, or critical vulnerabilities identified on this diff.

Changes since prior review (081e80e):

  • Token price cache keys now include discount_bps and max_maker_fills (route_slippage.rs:137).
  • Hybrid route cache hits re-run enrich_route_slippage with the request amount_in (route_solver.rs:729-735).
  • Swap expected slippage prefers wallet simulateMultiHopSwap receive vs indexer spot_amount_out (swapRouteSlippage.ts:26-36, SwapPage.tsx:486-490).

These address correctness/UX alignment; they do not introduce new attacker-controlled sinks or bypass on-chain enforcement.

Reviewed areas (unchanged from prior pass):

  • Indexer nested solves: enrich_route_slippage adds up to two cached (30s) solve_global_best_execution_inner calls per /api/v1/route/solve request (enrich_slippage: false prevents recursion). Work stays within existing LCD-heavy rate limit (RATE_LIMIT_LCD_HEAVY_RPS, default 10).
  • Expert Mode / slippage block: Client-side UX guard only; on-chain max_spread / min_return unchanged. Direct contract interaction remains possible by design — not a security boundary.
  • API → UI data flow: slippage_percent parsed with parseFloat + Number.isFinite; React text rendering only (no dangerouslySetInnerHTML). No XSS or injection sink.
  • Secrets / error leakage: New fields are pricing metadata; enrich failures fail silently (no new 502 bodies or internal paths).
  • Dependencies: No Cargo.toml / package.json changes in this MR.

Inline threads: None (no findings to anchor).

Prior security-review comment on 081e80e: superseded by this re-review; no prior medium+ findings to re-report.

## Security review **Commit reviewed:** `977adae9c8dc97179a4de04849f25a6f0be04c68` **Scope:** MR !828 (re-review after fix commit) — route-based expected slippage (`indexer/src/api/route_slippage.rs`, `route_solver.rs`, `best_execution.rs`) and Swap Expert Mode retail guard (`SwapPage.tsx`, `expertMode.ts`, `swapRouteSlippage.ts`). **Outcome:** `FINDINGS: 0` medium+ **Summary:** Security review: no medium, high, or critical vulnerabilities identified on this diff. Changes since prior review (`081e80e`): - Token price cache keys now include `discount_bps` and `max_maker_fills` (`route_slippage.rs:137`). - Hybrid route cache hits re-run `enrich_route_slippage` with the request `amount_in` (`route_solver.rs:729-735`). - Swap expected slippage prefers wallet `simulateMultiHopSwap` receive vs indexer `spot_amount_out` (`swapRouteSlippage.ts:26-36`, `SwapPage.tsx:486-490`). These address correctness/UX alignment; they do not introduce new attacker-controlled sinks or bypass on-chain enforcement. Reviewed areas (unchanged from prior pass): - **Indexer nested solves:** `enrich_route_slippage` adds up to two cached (`30s`) `solve_global_best_execution_inner` calls per `/api/v1/route/solve` request (`enrich_slippage: false` prevents recursion). Work stays within existing LCD-heavy rate limit (`RATE_LIMIT_LCD_HEAVY_RPS`, default 10). - **Expert Mode / slippage block:** Client-side UX guard only; on-chain `max_spread` / `min_return` unchanged. Direct contract interaction remains possible by design — not a security boundary. - **API → UI data flow:** `slippage_percent` parsed with `parseFloat` + `Number.isFinite`; React text rendering only (no `dangerouslySetInnerHTML`). No XSS or injection sink. - **Secrets / error leakage:** New fields are pricing metadata; enrich failures fail silently (no new 502 bodies or internal paths). - **Dependencies:** No `Cargo.toml` / `package.json` changes in this MR. **Inline threads:** None (no findings to anchor). Prior security-review comment on `081e80e`: superseded by this re-review; no prior medium+ findings to re-report.
ghost1 commented 2026-06-06 07:28:40 +00:00 (Migrated from gitlab.com)

added 1 commit

  • 443e8af8 - Fix cached hybrid route slippage when amount differs within bucket

Compare with previous version

added 1 commit <ul><li>443e8af8 - Fix cached hybrid route slippage when amount differs within bucket</li></ul> [Compare with previous version](/PlasticDigits/cl8y-dex-terraclassic/-/merge_requests/110/diffs?diff_id=1837863259&start_sha=977adae9c8dc97179a4de04849f25a6f0be04c68)
ghost1 commented 2026-06-06 07:28:53 +00:00 (Migrated from gitlab.com)

changed the description

changed the description
ghost1 commented 2026-06-06 07:29:03 +00:00 (Migrated from gitlab.com)

resolved all threads

resolved all threads
PlasticDigits commented 2026-06-06 07:30:25 +00:00 (Migrated from gitlab.com)

Security review

Commit reviewed: 443e8af85f2ceb4985494bed3bcbff4d4344d4ca

Scope: MR !828 — route-based expected slippage (indexer/src/api/route_slippage.rs, route_solver.rs, best_execution.rs) and Swap Expert Mode retail guard (SwapPage.tsx, expertMode.ts, swapRouteSlippage.ts).

Outcome: FINDINGS: 0 medium+

Summary: Security review: no medium, high, or critical vulnerabilities identified on this diff.

Changes since prior review (977adae9):

  • Hybrid GET cache now stores amount_in and scales estimated_amount_out linearly when enriching slippage on bucket cache hits (route_solver.rs, route_slippage.rs). Correctness fix only; no new attacker-controlled sinks.

Reviewed areas:

  • Indexer nested solves: enrich_route_slippage adds up to two cached (30s) solve_global_best_execution_inner calls per /api/v1/route/solve request (enrich_slippage: false prevents recursion). Work stays within existing LCD-heavy rate limit (RATE_LIMIT_LCD_HEAVY_RPS, default 10). Price cache keys include discount_bps and max_maker_fills.
  • Expert Mode / slippage block: Client-side UX guard only; on-chain max_spread / min_return enforcement unchanged. Direct contract interaction remains possible by design — not a security boundary.
  • API → UI data flow: slippage_percent parsed with parseFloat + Number.isFinite; displayed via React text nodes (no dangerouslySetInnerHTML). No XSS or injection sink.
  • Input validation: Token addresses validated as terra1 bech32; amounts parsed as u128. Enrich failures fail silently (no new error bodies or internal path leakage).
  • Dependencies: No Cargo.toml / package.json changes in this MR.

Inline threads: None (no findings to anchor).

Prior security-review comments on 081e80e / 977adae9: superseded; no medium+ findings to re-report.

## Security review **Commit reviewed:** `443e8af85f2ceb4985494bed3bcbff4d4344d4ca` **Scope:** MR !828 — route-based expected slippage (`indexer/src/api/route_slippage.rs`, `route_solver.rs`, `best_execution.rs`) and Swap Expert Mode retail guard (`SwapPage.tsx`, `expertMode.ts`, `swapRouteSlippage.ts`). **Outcome:** `FINDINGS: 0` medium+ **Summary:** Security review: no medium, high, or critical vulnerabilities identified on this diff. Changes since prior review (`977adae9`): - Hybrid GET cache now stores `amount_in` and scales `estimated_amount_out` linearly when enriching slippage on bucket cache hits (`route_solver.rs`, `route_slippage.rs`). Correctness fix only; no new attacker-controlled sinks. Reviewed areas: - **Indexer nested solves:** `enrich_route_slippage` adds up to two cached (`30s`) `solve_global_best_execution_inner` calls per `/api/v1/route/solve` request (`enrich_slippage: false` prevents recursion). Work stays within existing LCD-heavy rate limit (`RATE_LIMIT_LCD_HEAVY_RPS`, default 10). Price cache keys include `discount_bps` and `max_maker_fills`. - **Expert Mode / slippage block:** Client-side UX guard only; on-chain `max_spread` / `min_return` enforcement unchanged. Direct contract interaction remains possible by design — not a security boundary. - **API → UI data flow:** `slippage_percent` parsed with `parseFloat` + `Number.isFinite`; displayed via React text nodes (no `dangerouslySetInnerHTML`). No XSS or injection sink. - **Input validation:** Token addresses validated as `terra1` bech32; amounts parsed as `u128`. Enrich failures fail silently (no new error bodies or internal path leakage). - **Dependencies:** No `Cargo.toml` / `package.json` changes in this MR. **Inline threads:** None (no findings to anchor). Prior security-review comments on `081e80e` / `977adae9`: superseded; no medium+ findings to re-report.
PlasticDigits (Migrated from gitlab.com) merged commit 494f5bb626 into main 2026-06-06 08:27:15 +00:00
PlasticDigits commented 2026-06-06 08:27:16 +00:00 (Migrated from gitlab.com)

mentioned in commit 494f5bb626

mentioned in commit 494f5bb6261c282ea42530e7142d51ecd931d7cc
PlasticDigits commented 2026-06-08 08:43:13 +00:00 (Migrated from gitlab.com)

mentioned in commit 3221d74949

mentioned in commit 3221d74949c3437aca112922b8a06a2183bcf792
PlasticDigits commented 2026-06-08 13:42:28 +00:00 (Migrated from gitlab.com)

mentioned in commit 666dcf105e

mentioned in commit 666dcf105e7228963eb38e2464db12f3bec8d7fc
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!828
No description provided.