feat: pair search combobox with relevance + liquidity ranking (#314) #792

Merged
PlasticDigits merged 6 commits from cursor/gitlab-issue-workflow-da3d into main 2026-06-05 10:39:15 +00:00
PlasticDigits commented 2026-06-05 10:13:15 +00:00 (Migrated from gitlab.com)

Summary

Implements GitLab #314 — searchable pair combobox on Trade and Limit Orders with indexer-backed relevance ranking and 24h volume tie-break.

https://gitlab.com/PlasticDigits/cl8y-dex-terraclassic/-/work_items/314

Indexer

  • Tiered relevance scoring (sort=relevance, default when q present): exact pair address / pair-symbol match (5) → token contract/denom (4) → symbol (3) → name (2) → substring (1)
  • ORDER BY relevance DESC, volume_quote DESC, id
  • Filters extended for token names and two-token queries (LUNC USTC, LUNC/USTC)
  • Integration test list_pairs_relevance_ordering

Frontend

  • New PairSearchSelect combobox (role=combobox, debounced ≥300ms, min 2 chars unless terra1… address)
  • Trade + Limits replace full factory MenuSelect dropdown
  • Factory-pair gate, indexer outage fallback (local label filter), volume badge in results
  • Empty query shows high-liquidity pairs (volume_24h desc)

Docs

  • docs/frontend.md § Pair search combobox invariants

Acceptance checklist

Criterion Verification Result
Trade + Limits use search combobox Code review + unit tests PASS
Five search modes rank sensibly Indexer integration test covers address, token addr, symbol, name, pair symbols PASS
Same relevance bucket → higher volume first list_pairs_relevance_ordering (LUNC query) PASS
Empty query → high-liquidity pairs PairSearchSelect uses sort=volume_24h when q empty PASS
Indexer tests for relevance ordering cargo test --test api_pairs list_pairs_relevance_ordering PASS
make test-frontend green make test-frontend (832 tests) PASS
Manual QA matrix on LocalTerra (≥6 pairs) Not run in cloud agent SKIP
Lighthouse/a11y spot check on combobox Not run in cloud agent SKIP

Verification for third parties

cd indexer && cargo test --test api_pairs list_pairs_relevance_ordering -- --test-threads=1
make test-frontend
make lint-frontend

Manual: deploy LocalTerra stack, open /trade and /limits, search by pair address, token address, symbol, name, and SYMBOL_A SYMBOL_B; confirm volume-ordered results within tier.

Blockers

Manual LocalTerra matrix and Lighthouse/a11y spot check were not executed in the cloud agent environment. Issue stays open until manual QA on a deploy with ≥6 pairs.


Note

Medium Risk
Touches primary trading routes and a new indexer sort/query path; behavior depends on indexer availability with a documented client fallback, but ranking and factory gating need regression coverage.

Overview
Replaces the full factory MenuSelect pair dropdown on /trade and /limits with a new PairSearchSelect combobox: debounced indexer search, factory-only results, optional 24h volume badges, and local label fallback when the indexer fails.

The combobox calls GET /api/v1/pairs with sort=relevance when the user types (empty query defaults to volume_24h desc). Shared helpers in pairSearchQuery.ts enforce min query length (≥2 chars, or terra1… address). Charts is unchanged.

Indexer: adds sort=relevance with tiered match scoring (exact pair / two-token symbol → token contract → symbol → name → substring), tie-break by 24h volume; default sort is relevance when q is set. Broader q filters (token names, LUNC USTC / slash pairs). Integration test list_pairs_relevance_ordering.

Tests/docs: Vitest mocks getPairs on Trade/Limits pages; E2E limit helpers select pairs by contract address (volume-ordered list, not factory index); docs/frontend.md documents combobox invariants.

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

## Summary Implements GitLab #314 — searchable pair combobox on **Trade** and **Limit Orders** with indexer-backed relevance ranking and 24h volume tie-break. https://gitlab.com/PlasticDigits/cl8y-dex-terraclassic/-/work_items/314 ### Indexer - Tiered relevance scoring (`sort=relevance`, default when `q` present): exact pair address / pair-symbol match (5) → token contract/denom (4) → symbol (3) → name (2) → substring (1) - `ORDER BY relevance DESC, volume_quote DESC, id` - Filters extended for token names and two-token queries (`LUNC USTC`, `LUNC/USTC`) - Integration test `list_pairs_relevance_ordering` ### Frontend - New `PairSearchSelect` combobox (`role=combobox`, debounced ≥300ms, min 2 chars unless `terra1…` address) - Trade + Limits replace full factory `MenuSelect` dropdown - Factory-pair gate, indexer outage fallback (local label filter), volume badge in results - Empty query shows high-liquidity pairs (`volume_24h desc`) ### Docs - `docs/frontend.md` § Pair search combobox invariants ## Acceptance checklist | Criterion | Verification | Result | |-----------|--------------|--------| | Trade + Limits use search combobox | Code review + unit tests | PASS | | Five search modes rank sensibly | Indexer integration test covers address, token addr, symbol, name, pair symbols | PASS | | Same relevance bucket → higher volume first | `list_pairs_relevance_ordering` (LUNC query) | PASS | | Empty query → high-liquidity pairs | `PairSearchSelect` uses `sort=volume_24h` when `q` empty | PASS | | Indexer tests for relevance ordering | `cargo test --test api_pairs list_pairs_relevance_ordering` | PASS | | `make test-frontend` green | `make test-frontend` (832 tests) | PASS | | Manual QA matrix on LocalTerra (≥6 pairs) | Not run in cloud agent | SKIP | | Lighthouse/a11y spot check on combobox | Not run in cloud agent | SKIP | ## Verification for third parties ```bash cd indexer && cargo test --test api_pairs list_pairs_relevance_ordering -- --test-threads=1 make test-frontend make lint-frontend ``` Manual: deploy LocalTerra stack, open `/trade` and `/limits`, search by pair address, token address, symbol, name, and `SYMBOL_A SYMBOL_B`; confirm volume-ordered results within tier. ## Blockers Manual LocalTerra matrix and Lighthouse/a11y spot check were not executed in the cloud agent environment. Issue stays open until manual QA on a deploy with ≥6 pairs. <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **Medium Risk** > Touches primary trading routes and a new indexer sort/query path; behavior depends on indexer availability with a documented client fallback, but ranking and factory gating need regression coverage. > > **Overview** > Replaces the full factory **`MenuSelect`** pair dropdown on **`/trade`** and **`/limits`** with a new **`PairSearchSelect`** combobox: debounced indexer search, factory-only results, optional 24h volume badges, and local label fallback when the indexer fails. > > The combobox calls **`GET /api/v1/pairs`** with **`sort=relevance`** when the user types (empty query defaults to **`volume_24h` desc**). Shared helpers in **`pairSearchQuery.ts`** enforce min query length (≥2 chars, or **`terra1…`** address). **`Charts`** is unchanged. > > **Indexer:** adds **`sort=relevance`** with tiered match scoring (exact pair / two-token symbol → token contract → symbol → name → substring), tie-break by 24h volume; default sort is relevance when **`q`** is set. Broader **`q`** filters (token names, **`LUNC USTC`** / slash pairs). Integration test **`list_pairs_relevance_ordering`**. > > **Tests/docs:** Vitest mocks **`getPairs`** on Trade/Limits pages; E2E limit helpers select pairs by **contract address** (volume-ordered list, not factory index); **`docs/frontend.md`** documents combobox invariants. > > <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit 0aab8a7abd6af4795e4de19fd79b176dd1c7244e. Bugbot is set up for automated code reviews on this repo. Configure [here](https://www.cursor.com/dashboard/bugbot).</sup> <!-- /CURSOR_SUMMARY -->
PlasticDigits commented 2026-06-05 10:13:22 +00:00 (Migrated from gitlab.com)

changed the description

changed the description
ghost1 commented 2026-06-05 10:13:24 +00:00 (Migrated from gitlab.com)

changed the description

changed the description
PlasticDigits commented 2026-06-05 10:13:29 +00:00 (Migrated from gitlab.com)

mentioned in issue #314

mentioned in issue #314
ghost1 commented 2026-06-05 10:13:33 +00:00 (Migrated from gitlab.com)

changed the description

changed the description
ghost1 commented 2026-06-05 10:14:46 +00:00 (Migrated from gitlab.com)
Stale Security Review comment
Stale Security Review comment

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

Reviewed by Cursor Bugbot for commit 5a873ad3d2. Configure here.

<details> <summary>Stale Security Review comment</summary> <details> <summary>Stale Security Review comment</summary> <!-- BUGBOT_REVIEW --> Cursor Bugbot has reviewed your changes and found 2 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 5a873ad3d2c35639e731b389cc06a91459154675. Configure [here](https://www.cursor.com/dashboard/bugbot).</sup> </details> </details>
ghost1 commented 2026-06-05 10:14:47 +00:00 (Migrated from gitlab.com)

E2E pair index order mismatch

Medium Severity

selectLimitPairByFactoryIndex clicks getByRole('option').nth(factoryIndex), but factoryIndex is the factory LCD pairs array index while the combobox lists options by indexer 24h volume. With multiple factory pairs, E2E can select the wrong market.

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 5a873ad3d2. Configure here.

### E2E pair index order mismatch **Medium Severity** <!-- DESCRIPTION START --> `selectLimitPairByFactoryIndex` clicks `getByRole('option').nth(factoryIndex)`, but `factoryIndex` is the factory LCD `pairs` array index while the combobox lists options by indexer 24h volume. With multiple factory pairs, E2E can select the wrong market. <!-- DESCRIPTION END --> <!-- BUGBOT_BUG_ID: 9947a1cf-8cc8-4c21-a2bc-39e65db09aca --> <!-- LOCATIONS START frontend-dapp/e2e/helpers/limit-e2e.ts#L29-L35 LOCATIONS END --> <div><a href="https://cursor.com/open?link=eyJ2ZXJzaW9uIjoxLCJ0eXBlIjoiQlVHQk9UX0ZJWF9JTl9DVVJTT1IiLCJkYXRhIjp7InJlZGlzS2V5IjoiYnVnYm90OjQ5NzhkZDZhLTQxODgtNDVkYS1hYWVjLTZhOGFlNzczZDg4NiIsImVuY3J5cHRpb25LZXkiOiJQNXVGNlBhWTVSVzhuQ1F2dmhGWjFycmJXY2dKMnhqQjgzdEJqN0V2VTNjIiwiYnJhbmNoIjoiY3Vyc29yL2dpdGxhYi1pc3N1ZS13b3JrZmxvdy1kYTNkIiwicmVwb093bmVyIjoiUGxhc3RpY0RpZ2l0cyIsInJlcG9OYW1lIjoiY2w4eS1kZXgtdGVycmFjbGFzc2ljIn19" 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=eyJ2ZXJzaW9uIjoxLCJ0eXBlIjoiQlVHQk9UX0ZJWF9JTl9XRUIiLCJkYXRhIjp7InJlZGlzS2V5IjoiYnVnYm90OjQ5NzhkZDZhLTQxODgtNDVkYS1hYWVjLTZhOGFlNzczZDg4NiIsImVuY3J5cHRpb25LZXkiOiJQNXVGNlBhWTVSVzhuQ1F2dmhGWjFycmJXY2dKMnhqQjgzdEJqN0V2VTNjIiwiYnJhbmNoIjoiY3Vyc29yL2dpdGxhYi1pc3N1ZS13b3JrZmxvdy1kYTNkIiwicmVwb093bmVyIjoiUGxhc3RpY0RpZ2l0cyIsInJlcG9OYW1lIjoiY2w4eS1kZXgtdGVycmFjbGFzc2ljIiwicHJOdW1iZXIiOjc0LCJjb21taXRTaGEiOiI1YTg3M2FkM2QyYzM1NjM5ZTczMWIzODljYzA2YTkxNDU5MTU0Njc1IiwicHJvdmlkZXIiOiJnaXRsYWIiLCJob3N0bmFtZSI6ImdpdGxhYi5jb20ifX0" 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 5a873ad3d2c35639e731b389cc06a91459154675. Configure [here](https://www.cursor.com/dashboard/bugbot).</sup>
ghost1 commented 2026-06-05 10:14:47 +00:00 (Migrated from gitlab.com)

Premature no-match empty state

Low Severity

The list shows “No pairs match your search” whenever debouncedSearch is non-empty and options is empty, even when isPairSearchQueryReady is false so the indexer query is disabled. A single-character query never runs but still gets the no-results message.

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 5a873ad3d2. Configure here.

### Premature no-match empty state **Low Severity** <!-- DESCRIPTION START --> The list shows “No pairs match your search” whenever `debouncedSearch` is non-empty and `options` is empty, even when `isPairSearchQueryReady` is false so the indexer query is disabled. A single-character query never runs but still gets the no-results message. <!-- DESCRIPTION END --> <!-- BUGBOT_BUG_ID: dcb7b20b-9e0e-4e59-b3c3-e06ff6475268 --> <!-- LOCATIONS START frontend-dapp/src/components/trade/PairSearchSelect.tsx#L222-L284 LOCATIONS END --> <div><a href="https://cursor.com/open?link=eyJ2ZXJzaW9uIjoxLCJ0eXBlIjoiQlVHQk9UX0ZJWF9JTl9DVVJTT1IiLCJkYXRhIjp7InJlZGlzS2V5IjoiYnVnYm90OjU3YTNjYWIwLTRmZTUtNGYzNS04NjQwLTc2ZDJmMmZjYWE5NCIsImVuY3J5cHRpb25LZXkiOiJjY2VRMlNZOHptb1dwa1FmMExXYWhiQVF4SlR3WjcwRDNOYkQteDlaOU9FIiwiYnJhbmNoIjoiY3Vyc29yL2dpdGxhYi1pc3N1ZS13b3JrZmxvdy1kYTNkIiwicmVwb093bmVyIjoiUGxhc3RpY0RpZ2l0cyIsInJlcG9OYW1lIjoiY2w4eS1kZXgtdGVycmFjbGFzc2ljIn19" 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=eyJ2ZXJzaW9uIjoxLCJ0eXBlIjoiQlVHQk9UX0ZJWF9JTl9XRUIiLCJkYXRhIjp7InJlZGlzS2V5IjoiYnVnYm90OjU3YTNjYWIwLTRmZTUtNGYzNS04NjQwLTc2ZDJmMmZjYWE5NCIsImVuY3J5cHRpb25LZXkiOiJjY2VRMlNZOHptb1dwa1FmMExXYWhiQVF4SlR3WjcwRDNOYkQteDlaOU9FIiwiYnJhbmNoIjoiY3Vyc29yL2dpdGxhYi1pc3N1ZS13b3JrZmxvdy1kYTNkIiwicmVwb093bmVyIjoiUGxhc3RpY0RpZ2l0cyIsInJlcG9OYW1lIjoiY2w4eS1kZXgtdGVycmFjbGFzc2ljIiwicHJOdW1iZXIiOjc0LCJjb21taXRTaGEiOiI1YTg3M2FkM2QyYzM1NjM5ZTczMWIzODljYzA2YTkxNDU5MTU0Njc1IiwicHJvdmlkZXIiOiJnaXRsYWIiLCJob3N0bmFtZSI6ImdpdGxhYi5jb20ifX0" 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 5a873ad3d2c35639e731b389cc06a91459154675. Configure [here](https://www.cursor.com/dashboard/bugbot).</sup>
PlasticDigits commented 2026-06-05 10:15:05 +00:00 (Migrated from gitlab.com)

Security review

Commit reviewed: 5a873ad3d2c35639e731b389cc06a91459154675
Scope: Pair search combobox (PairSearchSelect) on Trade/Limits; indexer sort=relevance + expanded q filtering; docs and tests.

Outcome: FINDINGS: 0 medium+

Areas reviewed

Area Result
SQL injection (indexer/src/db/queries/pairs.rs, indexer/src/api/pairs.rs) User-controlled q / asset / sort values are passed only via sqlx::QueryBuilder::push_bind; SQL identifiers (a0, a1, p) are hardcoded. No injection path found.
XSS (PairSearchSelect.tsx) Pair labels and volume badges render as React text nodes ({opt.label}, formatNum(...)); no dangerouslySetInnerHTML or HTML interpolation.
Authz / pair selection onChange fires only from listbox selectIndex on factory-gated options (factorySet.has(p.pair_address)). Non-factory indexer rows are dropped before display.
DoS / amplification q truncated to 128 chars; limit clamped (frontend uses 20); global indexer rate limiting applies to /api/v1/pairs; combobox debounces ≥300ms. Relevance ORDER BY is heavier than prior sorts but remains bounded public read traffic.
SSRF / secrets / deserialization Not introduced by this diff.
Supply chain No new runtime dependencies.

Inline threads

None — no medium+ issues to anchor on specific diff lines.


Automated security review (MR open webhook).

## Security review **Commit reviewed:** `5a873ad3d2c35639e731b389cc06a91459154675` **Scope:** Pair search combobox (`PairSearchSelect`) on Trade/Limits; indexer `sort=relevance` + expanded `q` filtering; docs and tests. **Outcome:** `FINDINGS: 0` medium+ ### Areas reviewed | Area | Result | |------|--------| | **SQL injection** (`indexer/src/db/queries/pairs.rs`, `indexer/src/api/pairs.rs`) | User-controlled `q` / `asset` / sort values are passed only via `sqlx::QueryBuilder::push_bind`; SQL identifiers (`a0`, `a1`, `p`) are hardcoded. No injection path found. | | **XSS** (`PairSearchSelect.tsx`) | Pair labels and volume badges render as React text nodes (`{opt.label}`, `formatNum(...)`); no `dangerouslySetInnerHTML` or HTML interpolation. | | **Authz / pair selection** | `onChange` fires only from listbox `selectIndex` on factory-gated options (`factorySet.has(p.pair_address)`). Non-factory indexer rows are dropped before display. | | **DoS / amplification** | `q` truncated to 128 chars; `limit` clamped (frontend uses 20); global indexer rate limiting applies to `/api/v1/pairs`; combobox debounces ≥300ms. Relevance `ORDER BY` is heavier than prior sorts but remains bounded public read traffic. | | **SSRF / secrets / deserialization** | Not introduced by this diff. | | **Supply chain** | No new runtime dependencies. | ### Inline threads None — no medium+ issues to anchor on specific diff lines. --- *Automated security review (MR open webhook).*
ghost1 commented 2026-06-05 10:16:53 +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/74/diffs?diff_id=1836427274&start_sha=5a873ad3d2c35639e731b389cc06a91459154675#80dbc8411f89b0bb1654656e32c6118a168fe44c_35_35)
ghost1 commented 2026-06-05 10:16:53 +00:00 (Migrated from gitlab.com)

added 1 commit

  • eea6b346 - Fix pair search E2E selection and premature empty state

Compare with previous version

added 1 commit <ul><li>eea6b346 - Fix pair search E2E selection and premature empty state</li></ul> [Compare with previous version](/PlasticDigits/cl8y-dex-terraclassic/-/merge_requests/74/diffs?diff_id=1836427274&start_sha=5a873ad3d2c35639e731b389cc06a91459154675)
ghost1 commented 2026-06-05 10:17:16 +00:00 (Migrated from gitlab.com)

changed the description

changed the description
ghost1 commented 2026-06-05 10:17:24 +00:00 (Migrated from gitlab.com)

resolved all threads

resolved all threads
ghost1 commented 2026-06-05 10:17:24 +00:00 (Migrated from gitlab.com)

resolved all threads

resolved all threads
ghost1 commented 2026-06-05 10:18:52 +00:00 (Migrated from gitlab.com)
Stale Security Review comment

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

Reviewed by Cursor Bugbot for commit eea6b34662. Configure here.

<details> <summary>Stale Security Review comment</summary> <!-- BUGBOT_REVIEW --> Cursor Bugbot has reviewed your changes and found 1 potential issue.<!-- 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 eea6b346622e4bf66c2dc50aff5698f2c359b7c5. Configure [here](https://www.cursor.com/dashboard/bugbot).</sup> </details>
ghost1 commented 2026-06-05 10:18:53 +00:00 (Migrated from gitlab.com)

Label treated as search query

Medium Severity

When a pair is selected, closing the combobox copies the full menu label into searchText/debouncedSearch, and useIndexerSearch stays enabled because debouncedSearch.length > 0 even while closed. Reopening calls getPairs with that label as q (relevance sort) instead of an empty high-liquidity list, which can show wrong results or “No pairs match your search.”

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit eea6b34662. Configure here.

### Label treated as search query **Medium Severity** <!-- DESCRIPTION START --> When a pair is selected, closing the combobox copies the full menu label into `searchText`/`debouncedSearch`, and `useIndexerSearch` stays enabled because `debouncedSearch.length > 0` even while closed. Reopening calls `getPairs` with that label as `q` (relevance sort) instead of an empty high-liquidity list, which can show wrong results or “No pairs match your search.” <!-- DESCRIPTION END --> <!-- BUGBOT_BUG_ID: 1063cf38-0763-4c23-b852-dff0f3210f47 --> <!-- LOCATIONS START frontend-dapp/src/components/trade/PairSearchSelect.tsx#L93-L116 LOCATIONS END --> <div><a href="https://cursor.com/open?link=eyJ2ZXJzaW9uIjoxLCJ0eXBlIjoiQlVHQk9UX0ZJWF9JTl9DVVJTT1IiLCJkYXRhIjp7InJlZGlzS2V5IjoiYnVnYm90OjBlNDg2MWViLWMxZmQtNDM2ZS04NjE0LTM4MThhYjNkMjRiMiIsImVuY3J5cHRpb25LZXkiOiJJMFdJT0RSdXBnMjVyZTlMUzZZOUpuWERsWXkyTTRhM21MbDBMaVhOaklnIiwiYnJhbmNoIjoiY3Vyc29yL2dpdGxhYi1pc3N1ZS13b3JrZmxvdy1kYTNkIiwicmVwb093bmVyIjoiUGxhc3RpY0RpZ2l0cyIsInJlcG9OYW1lIjoiY2w4eS1kZXgtdGVycmFjbGFzc2ljIn19" 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=eyJ2ZXJzaW9uIjoxLCJ0eXBlIjoiQlVHQk9UX0ZJWF9JTl9XRUIiLCJkYXRhIjp7InJlZGlzS2V5IjoiYnVnYm90OjBlNDg2MWViLWMxZmQtNDM2ZS04NjE0LTM4MThhYjNkMjRiMiIsImVuY3J5cHRpb25LZXkiOiJJMFdJT0RSdXBnMjVyZTlMUzZZOUpuWERsWXkyTTRhM21MbDBMaVhOaklnIiwiYnJhbmNoIjoiY3Vyc29yL2dpdGxhYi1pc3N1ZS13b3JrZmxvdy1kYTNkIiwicmVwb093bmVyIjoiUGxhc3RpY0RpZ2l0cyIsInJlcG9OYW1lIjoiY2w4eS1kZXgtdGVycmFjbGFzc2ljIiwicHJOdW1iZXIiOjc0LCJjb21taXRTaGEiOiJlZWE2YjM0NjYyMmU0YmY2NmMyZGM1MGFmZjU2OThmMmMzNTliN2M1IiwicHJvdmlkZXIiOiJnaXRsYWIiLCJob3N0bmFtZSI6ImdpdGxhYi5jb20ifX0" 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 eea6b346622e4bf66c2dc50aff5698f2c359b7c5. Configure [here](https://www.cursor.com/dashboard/bugbot).</sup>
ghost1 commented 2026-06-05 10:20:56 +00:00 (Migrated from gitlab.com)

added 1 commit

  • e30c3eeb - fix: stop pair combobox label from triggering indexer search when closed

Compare with previous version

added 1 commit <ul><li>e30c3eeb - fix: stop pair combobox label from triggering indexer search when closed</li></ul> [Compare with previous version](/PlasticDigits/cl8y-dex-terraclassic/-/merge_requests/74/diffs?diff_id=1836435248&start_sha=eea6b346622e4bf66c2dc50aff5698f2c359b7c5)
ghost1 commented 2026-06-05 10:21:11 +00:00 (Migrated from gitlab.com)

changed the description

changed the description
ghost1 commented 2026-06-05 10:21:16 +00:00 (Migrated from gitlab.com)

resolved all threads

resolved all threads
ghost1 commented 2026-06-05 10:22:44 +00:00 (Migrated from gitlab.com)

Cursor Bugbot has reviewed your changes and found 2 potential issues.

Fix All in Cursor

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

Reviewed by Cursor Bugbot for commit e30c3eebe7. Configure here.

<!-- BUGBOT_REVIEW --> Cursor Bugbot has reviewed your changes and found 2 potential issues. <!-- BUGBOT_FIX_ALL --> <a href="https://cursor.com/open?link=eyJ2ZXJzaW9uIjoxLCJ0eXBlIjoiQlVHQk9UX0ZJWF9BTExfSU5fQ1VSU09SIiwiZGF0YSI6eyJyZWRpc0tleSI6ImJ1Z2JvdC1tdWx0aTpkOTQ5ODNiMy0wMWE4LTRhMTgtOTVhNS01YjkxNDQzZDIyMzMiLCJlbmNyeXB0aW9uS2V5IjoieEl0NjI1VnRYclRRLTdDU3RLQ0lvalpVY2FZTjhpLUd6Z2QzMjhLR0hEYyIsImJyYW5jaCI6ImN1cnNvci9naXRsYWItaXNzdWUtd29ya2Zsb3ctZGEzZCIsInJlcG9Pd25lciI6IlBsYXN0aWNEaWdpdHMiLCJyZXBvTmFtZSI6ImNsOHktZGV4LXRlcnJhY2xhc3NpYyJ9fQ" 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 issues. <!-- BUGBOT_AUTOFIX_AGENT_LINK --></sup> <!-- BUGBOT_AUTOFIX_REVIEW_FOOTNOTE_END --> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit e30c3eebe78ed728fb5db7adb9a6b4f103d6b8db. Configure [here](https://www.cursor.com/dashboard/bugbot).</sup>
ghost1 commented 2026-06-05 10:22:45 +00:00 (Migrated from gitlab.com)

Empty query shows factory order

Medium Severity

With an empty search query, the list shows the first factory pairs while the indexer request is in flight, instead of waiting for volume-sorted results. Users can pick from that interim list before high-liquidity ordering arrives, contradicting the empty-query volume default.

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit e30c3eebe7. Configure here.

### Empty query shows factory order **Medium Severity** <!-- DESCRIPTION START --> With an empty search query, the list shows the first factory pairs while the indexer request is in flight, instead of waiting for volume-sorted results. Users can pick from that interim list before high-liquidity ordering arrives, contradicting the empty-query volume default. <!-- DESCRIPTION END --> <!-- BUGBOT_BUG_ID: 844c07d8-f54b-4330-9d97-709831eb9f51 --> <!-- LOCATIONS START frontend-dapp/src/components/trade/PairSearchSelect.tsx#L132-L136 LOCATIONS END --> <div><a href="https://cursor.com/open?link=eyJ2ZXJzaW9uIjoxLCJ0eXBlIjoiQlVHQk9UX0ZJWF9JTl9DVVJTT1IiLCJkYXRhIjp7InJlZGlzS2V5IjoiYnVnYm90OjQ5NmFiODllLWI0ZjEtNGNiMS1hOWYyLTg4MTZkZWZjYjI2NSIsImVuY3J5cHRpb25LZXkiOiJxNkR1d1gybjBzNXZ3Sy01cHJJenRHTVlrRTNDOVdWMEZGV1BaMWltRzVFIiwiYnJhbmNoIjoiY3Vyc29yL2dpdGxhYi1pc3N1ZS13b3JrZmxvdy1kYTNkIiwicmVwb093bmVyIjoiUGxhc3RpY0RpZ2l0cyIsInJlcG9OYW1lIjoiY2w4eS1kZXgtdGVycmFjbGFzc2ljIn19" 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=eyJ2ZXJzaW9uIjoxLCJ0eXBlIjoiQlVHQk9UX0ZJWF9JTl9XRUIiLCJkYXRhIjp7InJlZGlzS2V5IjoiYnVnYm90OjQ5NmFiODllLWI0ZjEtNGNiMS1hOWYyLTg4MTZkZWZjYjI2NSIsImVuY3J5cHRpb25LZXkiOiJxNkR1d1gybjBzNXZ3Sy01cHJJenRHTVlrRTNDOVdWMEZGV1BaMWltRzVFIiwiYnJhbmNoIjoiY3Vyc29yL2dpdGxhYi1pc3N1ZS13b3JrZmxvdy1kYTNkIiwicmVwb093bmVyIjoiUGxhc3RpY0RpZ2l0cyIsInJlcG9OYW1lIjoiY2w4eS1kZXgtdGVycmFjbGFzc2ljIiwicHJOdW1iZXIiOjc0LCJjb21taXRTaGEiOiJlMzBjM2VlYmU3OGVkNzI4ZmI1ZGI3YWRiOWE2YjRmMTAzZDZiOGRiIiwicHJvdmlkZXIiOiJnaXRsYWIiLCJob3N0bmFtZSI6ImdpdGxhYi5jb20ifX0" 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 e30c3eebe78ed728fb5db7adb9a6b4f103d6b8db. Configure [here](https://www.cursor.com/dashboard/bugbot).</sup>
ghost1 commented 2026-06-05 10:22:45 +00:00 (Migrated from gitlab.com)

Enter picks wrong pair

High Severity

When the active pair is not among the combobox options (e.g. deep-linked low-volume pair outside the top 20 indexer results), selectedIndex is -1 and keyboard focus defaults to index 0. Pressing Enter always calls onChange for that row, so Trade can navigate away from the intended pair without an explicit user choice.

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit e30c3eebe7. Configure here.

### Enter picks wrong pair **High Severity** <!-- DESCRIPTION START --> When the active pair is not among the combobox options (e.g. deep-linked low-volume pair outside the top 20 indexer results), `selectedIndex` is -1 and keyboard focus defaults to index 0. Pressing Enter always calls `onChange` for that row, so Trade can navigate away from the intended pair without an explicit user choice. <!-- DESCRIPTION END --> <!-- BUGBOT_BUG_ID: 4f0925b0-8c8e-4aaa-87eb-524e6f74576e --> <!-- LOCATIONS START frontend-dapp/src/components/trade/PairSearchSelect.tsx#L149-L208 LOCATIONS END --> <div><a href="https://cursor.com/open?link=eyJ2ZXJzaW9uIjoxLCJ0eXBlIjoiQlVHQk9UX0ZJWF9JTl9DVVJTT1IiLCJkYXRhIjp7InJlZGlzS2V5IjoiYnVnYm90OjU4ODE1OTNkLWNlYWEtNGU1Ni04YmRlLTMwODMyMWMxMzc1MSIsImVuY3J5cHRpb25LZXkiOiJPdzVkOUNBTE5TTnVQbXFNUVB4cndOX0J1Zmp0OHBPeDY3UDFSWl9XeXlBIiwiYnJhbmNoIjoiY3Vyc29yL2dpdGxhYi1pc3N1ZS13b3JrZmxvdy1kYTNkIiwicmVwb093bmVyIjoiUGxhc3RpY0RpZ2l0cyIsInJlcG9OYW1lIjoiY2w4eS1kZXgtdGVycmFjbGFzc2ljIn19" 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=eyJ2ZXJzaW9uIjoxLCJ0eXBlIjoiQlVHQk9UX0ZJWF9JTl9XRUIiLCJkYXRhIjp7InJlZGlzS2V5IjoiYnVnYm90OjU4ODE1OTNkLWNlYWEtNGU1Ni04YmRlLTMwODMyMWMxMzc1MSIsImVuY3J5cHRpb25LZXkiOiJPdzVkOUNBTE5TTnVQbXFNUVB4cndOX0J1Zmp0OHBPeDY3UDFSWl9XeXlBIiwiYnJhbmNoIjoiY3Vyc29yL2dpdGxhYi1pc3N1ZS13b3JrZmxvdy1kYTNkIiwicmVwb093bmVyIjoiUGxhc3RpY0RpZ2l0cyIsInJlcG9OYW1lIjoiY2w4eS1kZXgtdGVycmFjbGFzc2ljIiwicHJOdW1iZXIiOjc0LCJjb21taXRTaGEiOiJlMzBjM2VlYmU3OGVkNzI4ZmI1ZGI3YWRiOWE2YjRmMTAzZDZiOGRiIiwicHJvdmlkZXIiOiJnaXRsYWIiLCJob3N0bmFtZSI6ImdpdGxhYi5jb20ifX0" 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 e30c3eebe78ed728fb5db7adb9a6b4f103d6b8db. Configure [here](https://www.cursor.com/dashboard/bugbot).</sup>
ghost1 commented 2026-06-05 10:24:15 +00:00 (Migrated from gitlab.com)

added 1 commit

  • 0aab8a7a - fix(PairSearchSelect): keep current pair on Enter and wait for volume-sorted results

Compare with previous version

added 1 commit <ul><li>0aab8a7a - fix(PairSearchSelect): keep current pair on Enter and wait for volume-sorted results</li></ul> [Compare with previous version](/PlasticDigits/cl8y-dex-terraclassic/-/merge_requests/74/diffs?diff_id=1836441982&start_sha=e30c3eebe78ed728fb5db7adb9a6b4f103d6b8db)
ghost1 commented 2026-06-05 10:24:28 +00:00 (Migrated from gitlab.com)

changed the description

changed the description
ghost1 commented 2026-06-05 10:24:49 +00:00 (Migrated from gitlab.com)

resolved all threads

resolved all threads
ghost1 commented 2026-06-05 10:24:49 +00:00 (Migrated from gitlab.com)

resolved all threads

resolved all threads
PlasticDigits commented 2026-06-05 10:25:55 +00:00 (Migrated from gitlab.com)

Security review

Commit reviewed: 0aab8a7abd6af4795e4de19fd79b176dd1c7244e
Scope: Pair search combobox (PairSearchSelect) on Trade/Limits; indexer GET /api/v1/pairs relevance sort and expanded q filtering; follow-up fix for Enter-key / empty-query loading behavior.

Outcome: FINDINGS: 0 medium+

Areas reviewed

Area Result
SQL injection (indexer/src/db/queries/pairs.rs, indexer/src/api/pairs.rs) Search/sort inputs use sqlx::QueryBuilder::push_bind only; sort is allowlisted; q truncated to 128 chars. No injection path.
XSS (PairSearchSelect.tsx) Labels and volume badges render as React text nodes; no dangerouslySetInnerHTML.
Authz / pair selection onChange only via selectIndex on options built from factory-gated indexer rows (factorySet.has) or factory fallback; current pair prepend requires factorySet.has(value).
Enter / keyboard selection (commit 0aab8a7) Active pair is injected at list head when missing from indexer hits, so Enter does not silently jump to the first volume-ranked row. Residual risk is limited to explicit user choice among factory-registered pairs (not an authz bypass).
DoS / amplification limit clamped server-side; combobox uses limit=20, 300ms debounce; global indexer rate limits apply. Relevance ORDER BY is heavier but bounded public read traffic.
SSRF / secrets / deserialization Not introduced by this diff.
Supply chain No new runtime dependencies in the pair-search surface.

Prior review

Re-checked against the earlier review on 5a873ad3 (also FINDINGS: 0). Bugbot threads on Enter-key and empty-query ordering are UX/safety fixes, not medium+ security issues on re-test at 0aab8a7.

Inline threads

None — no medium+ issues to anchor on specific diff lines.


Automated security review (MR update webhook).

## Security review **Commit reviewed:** `0aab8a7abd6af4795e4de19fd79b176dd1c7244e` **Scope:** Pair search combobox (`PairSearchSelect`) on Trade/Limits; indexer `GET /api/v1/pairs` relevance sort and expanded `q` filtering; follow-up fix for Enter-key / empty-query loading behavior. **Outcome:** `FINDINGS: 0` medium+ ### Areas reviewed | Area | Result | |------|--------| | **SQL injection** (`indexer/src/db/queries/pairs.rs`, `indexer/src/api/pairs.rs`) | Search/sort inputs use `sqlx::QueryBuilder::push_bind` only; sort is allowlisted; `q` truncated to 128 chars. No injection path. | | **XSS** (`PairSearchSelect.tsx`) | Labels and volume badges render as React text nodes; no `dangerouslySetInnerHTML`. | | **Authz / pair selection** | `onChange` only via `selectIndex` on options built from factory-gated indexer rows (`factorySet.has`) or factory fallback; current pair prepend requires `factorySet.has(value)`. | | **Enter / keyboard selection** (commit `0aab8a7`) | Active pair is injected at list head when missing from indexer hits, so Enter does not silently jump to the first volume-ranked row. Residual risk is limited to explicit user choice among factory-registered pairs (not an authz bypass). | | **DoS / amplification** | `limit` clamped server-side; combobox uses `limit=20`, 300ms debounce; global indexer rate limits apply. Relevance `ORDER BY` is heavier but bounded public read traffic. | | **SSRF / secrets / deserialization** | Not introduced by this diff. | | **Supply chain** | No new runtime dependencies in the pair-search surface. | ### Prior review Re-checked against the earlier review on `5a873ad3` (also `FINDINGS: 0`). Bugbot threads on Enter-key and empty-query ordering are UX/safety fixes, not medium+ security issues on re-test at `0aab8a7`. ### Inline threads None — no medium+ issues to anchor on specific diff lines. --- *Automated security review (MR update webhook).*
PlasticDigits commented 2026-06-05 10:28:49 +00:00 (Migrated from gitlab.com)

Security review

Commit reviewed: 0aab8a7abd6af4795e4de19fd79b176dd1c7244e
Scope: Pair search combobox (PairSearchSelect) on Trade/Limits; indexer GET /api/v1/pairs relevance sort and expanded q filtering; follow-up fixes for Enter-key selection, closed-label query gating, and empty-query loading.

Outcome: FINDINGS: 0 medium+

Areas reviewed

Area Result
SQL injection (indexer/src/db/queries/pairs.rs, indexer/src/api/pairs.rs) User q / asset / sort values use sqlx::QueryBuilder::push_bind only; SQL identifiers (a0, a1, p) are hardcoded; sort is allowlisted; q truncated to 128 chars. No injection path.
XSS (PairSearchSelect.tsx, pairMenuOptions.ts) Labels and volume badges render as React text nodes; no dangerouslySetInnerHTML. Indexer-returned symbols/names are escaped by React.
Authz / pair selection onChange only via selectIndex on options built from factory-gated indexer rows (factorySet.has) or factory fallback; active pair prepend requires factorySet.has(value). Trade deep links validated via isKnownFactoryTradePair; limit placement requires selectedPair from factory list.
Enter / keyboard selection (0aab8a7) Current factory pair injected at list head when absent from indexer hits, preventing silent jump to first volume-ranked row on Enter. Residual risk is explicit user choice among factory-registered pairs only.
DoS / amplification limit clamped server-side (frontend uses 20); q capped at 128 chars; combobox debounces ≥300ms; global indexer rate limits apply. Relevance ORDER BY is heavier but bounded public read traffic.
SSRF / secrets / deserialization Not introduced by this diff.
Supply chain No new runtime dependencies in the pair-search surface.

Prior review

Re-checked against earlier reviews on 5a873ad3 and 0aab8a7 (both FINDINGS: 0). No new medium+ issues on this MR update.

Inline threads

None — no medium+ issues to anchor on specific diff lines.


Automated security review (MR update webhook).

## Security review **Commit reviewed:** `0aab8a7abd6af4795e4de19fd79b176dd1c7244e` **Scope:** Pair search combobox (`PairSearchSelect`) on Trade/Limits; indexer `GET /api/v1/pairs` relevance sort and expanded `q` filtering; follow-up fixes for Enter-key selection, closed-label query gating, and empty-query loading. **Outcome:** `FINDINGS: 0` medium+ ### Areas reviewed | Area | Result | |------|--------| | **SQL injection** (`indexer/src/db/queries/pairs.rs`, `indexer/src/api/pairs.rs`) | User `q` / `asset` / sort values use `sqlx::QueryBuilder::push_bind` only; SQL identifiers (`a0`, `a1`, `p`) are hardcoded; `sort` is allowlisted; `q` truncated to 128 chars. No injection path. | | **XSS** (`PairSearchSelect.tsx`, `pairMenuOptions.ts`) | Labels and volume badges render as React text nodes; no `dangerouslySetInnerHTML`. Indexer-returned symbols/names are escaped by React. | | **Authz / pair selection** | `onChange` only via `selectIndex` on options built from factory-gated indexer rows (`factorySet.has`) or factory fallback; active pair prepend requires `factorySet.has(value)`. Trade deep links validated via `isKnownFactoryTradePair`; limit placement requires `selectedPair` from factory list. | | **Enter / keyboard selection** (`0aab8a7`) | Current factory pair injected at list head when absent from indexer hits, preventing silent jump to first volume-ranked row on Enter. Residual risk is explicit user choice among factory-registered pairs only. | | **DoS / amplification** | `limit` clamped server-side (frontend uses 20); `q` capped at 128 chars; combobox debounces ≥300ms; global indexer rate limits apply. Relevance `ORDER BY` is heavier but bounded public read traffic. | | **SSRF / secrets / deserialization** | Not introduced by this diff. | | **Supply chain** | No new runtime dependencies in the pair-search surface. | ### Prior review Re-checked against earlier reviews on `5a873ad3` and `0aab8a7` (both `FINDINGS: 0`). No new medium+ issues on this MR update. ### Inline threads None — no medium+ issues to anchor on specific diff lines. --- *Automated security review (MR update webhook).*
PlasticDigits commented 2026-06-05 10:33:59 +00:00 (Migrated from gitlab.com)

Security review

Commit reviewed: 0aab8a7abd6af4795e4de19fd79b176dd1c7244e (MR head; webhook referenced e30c3eeb)
Scope: Pair search combobox (PairSearchSelect) on Trade/Limits; indexer GET /api/v1/pairs relevance sort and expanded q filtering; follow-up fixes (e30c3eeb, 0aab8a7) for closed-label query gating, Enter-key selection, and empty-query loading.

Outcome: FINDINGS: 0 medium+

Areas reviewed

Area Result
SQL injection (indexer/src/db/queries/pairs.rs, indexer/src/api/pairs.rs) User q / asset / sort use sqlx::QueryBuilder::push_bind only; table aliases (a0, a1, p) are hardcoded; sort is allowlisted; q truncated to 128 chars. No injection path.
XSS (PairSearchSelect.tsx, pairMenuOptions.ts) Labels and volume badges are React text nodes; no dangerouslySetInnerHTML.
Authz / pair selection onChange only from listbox selectIndex on factory-gated options (factorySet.has); active pair prepend requires factorySet.has(value). Trade routes still gated by isKnownFactoryTradePair.
Enter / keyboard (0aab8a7) Current factory pair injected at list head when absent from indexer hits, so Enter does not silently switch to the first volume-ranked row.
DoS / amplification Server limit clamped (max 100; UI uses 20); q capped; combobox debounces ≥300ms; global indexer rate limits apply. Relevance ORDER BY is heavier but remains bounded public read traffic.
SSRF / secrets / deserialization Not introduced by this diff.
Supply chain No new runtime dependencies in the pair-search surface.

Prior reviews

Re-checked prior security reviews on 5a873ad3 and 0aab8a7 (both FINDINGS: 0). Bugbot threads on E2E ordering, label-as-query, Enter-key, and empty-query loading are UX/correctness fixes, not exploitable authz or injection issues at current head.

Inline threads

None — no medium+ issues to anchor on specific diff lines.


Automated security review (MR update webhook).

## Security review **Commit reviewed:** `0aab8a7abd6af4795e4de19fd79b176dd1c7244e` (MR head; webhook referenced `e30c3eeb`) **Scope:** Pair search combobox (`PairSearchSelect`) on Trade/Limits; indexer `GET /api/v1/pairs` relevance sort and expanded `q` filtering; follow-up fixes (`e30c3eeb`, `0aab8a7`) for closed-label query gating, Enter-key selection, and empty-query loading. **Outcome:** `FINDINGS: 0` medium+ ### Areas reviewed | Area | Result | |------|--------| | **SQL injection** (`indexer/src/db/queries/pairs.rs`, `indexer/src/api/pairs.rs`) | User `q` / `asset` / sort use `sqlx::QueryBuilder::push_bind` only; table aliases (`a0`, `a1`, `p`) are hardcoded; `sort` is allowlisted; `q` truncated to 128 chars. No injection path. | | **XSS** (`PairSearchSelect.tsx`, `pairMenuOptions.ts`) | Labels and volume badges are React text nodes; no `dangerouslySetInnerHTML`. | | **Authz / pair selection** | `onChange` only from listbox `selectIndex` on factory-gated options (`factorySet.has`); active pair prepend requires `factorySet.has(value)`. Trade routes still gated by `isKnownFactoryTradePair`. | | **Enter / keyboard** (`0aab8a7`) | Current factory pair injected at list head when absent from indexer hits, so Enter does not silently switch to the first volume-ranked row. | | **DoS / amplification** | Server `limit` clamped (max 100; UI uses 20); `q` capped; combobox debounces ≥300ms; global indexer rate limits apply. Relevance `ORDER BY` is heavier but remains bounded public read traffic. | | **SSRF / secrets / deserialization** | Not introduced by this diff. | | **Supply chain** | No new runtime dependencies in the pair-search surface. | ### Prior reviews Re-checked prior security reviews on `5a873ad3` and `0aab8a7` (both `FINDINGS: 0`). Bugbot threads on E2E ordering, label-as-query, Enter-key, and empty-query loading are UX/correctness fixes, not exploitable authz or injection issues at current head. ### Inline threads None — no medium+ issues to anchor on specific diff lines. --- *Automated security review (MR update webhook).*
PlasticDigits commented 2026-06-05 10:39:16 +00:00 (Migrated from gitlab.com)

mentioned in commit 43c56c4ea5

mentioned in commit 43c56c4ea59d64dfdcf18d2a17017d3e569ed256
PlasticDigits (Migrated from gitlab.com) merged commit 43c56c4ea5 into main 2026-06-05 10:39:16 +00:00
PlasticDigits commented 2026-06-05 13:44:12 +00:00 (Migrated from gitlab.com)

mentioned in issue #328

mentioned in issue #328
PlasticDigits commented 2026-06-05 13:55:37 +00:00 (Migrated from gitlab.com)

mentioned in merge request !811

mentioned in merge request !811
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!792
No description provided.