Security: SwapPage and PoolPage do not query pair pause -- no frontend disabled-state for swap or LP actions under pair pause [SEC-B05] #395

Closed
opened 2026-06-19 10:36:29 +00:00 by totdking · 10 comments
totdking commented 2026-06-19 10:36:29 +00:00 (Migrated from gitlab.com)
No description provided.
totdking commented 2026-06-19 10:38:08 +00:00 (Migrated from gitlab.com)

Checklist Item

SEC-B05: Verify pair pause blocks swap, hybrid swap, limit place/cancel/claim/update, and LP actions according to intended policy. Verify: contract tests and frontend disabled-state tests match the documented policy.


Summary

The pair pause contract tests and the TradePage frontend test confirm that pair pause is enforced on-chain and that the Trade page shows a banner with disabled limit actions. However, SwapPage and PoolPage do not call getPairPaused at all. When a pair is paused, neither the swap submit CTA on SwapPage nor the provide/withdraw CTAs on PoolPage are proactively disabled in the frontend. Users submitting through those pages would receive an on-chain rejection with no prior UI indication.


What Was Checked

  • frontend-dapp/src/pages/TradePage.test.tsx lines 656-668 -- pair pause banner confirmed, limit Place CTAs disabled -- PASSES for trade path
  • frontend-dapp/src/pages/TradePage.tsx line 259 -- calls getPairPaused -- CONFIRMED
  • frontend-dapp/src/components/trade/TradeOrderTicket.tsx line 256 -- calls getPairPaused -- CONFIRMED
  • frontend-dapp/src/pages/LimitOrdersPage.tsx line 140 -- calls getPairPaused -- CONFIRMED
  • frontend-dapp/src/pages/SwapPage.tsx lines 364-385 -- only queries wrap-mapper pause (isWrapPaused), no call to getPairPaused
  • frontend-dapp/src/pages/PoolPage.tsx -- no call to getPairPaused found
  • Grep for getPairPaused across all non-test frontend source files: only found in TradeOrderTicket, TradePage, LimitOrdersPage
  • frontend-dapp/src/pages/SwapPage.test.tsx -- no test for pair pause disabled swap CTA

Expected (per checklist)

Frontend disabled-state tests must match the documented policy for pair pause. The policy (contracts-security-audit.md invariant L6) states pair pause blocks swaps and LP actions. The frontend should proactively disable the swap submit CTA on SwapPage and the provide/withdraw CTAs on PoolPage when the selected pair is paused, and tests should assert this.


Actual

getPairPaused is not called in SwapPage or PoolPage. No frontend disabled-state test exists for pair pause on SwapPage or PoolPage. The contract-level enforcement exists, but users on those pages receive no proactive UI indication before submitting a transaction that will be rejected on-chain.


Evidence

  • frontend-dapp/src/pages/SwapPage.tsx line 364-385: only wrap-mapper pause queried (isWrapPaused); no getPairPaused call
  • frontend-dapp/src/pages/PoolPage.tsx: no getPairPaused import or call
  • frontend-dapp/src/pages/SwapPage.test.tsx: no test for pair pause state on swap submit button
  • frontend-dapp/src/pages/TradePage.test.tsx lines 656-668: pair pause correctly tested on trade/limit path
  • Grep for getPairPaused in non-test frontend source: only 3 files (TradeOrderTicket, TradePage, LimitOrdersPage)

Suggested Fix

Add getPairPaused queries to SwapPage and PoolPage for the currently selected pair, and disable the swap submit and LP provide/withdraw CTAs respectively when the pair is paused, consistent with how TradePage handles it. Add unit tests asserting:

  • SwapPage: when getPairPaused returns { paused: true } for the selected pair, the swap submit button is disabled
  • PoolPage: when getPairPaused returns { paused: true } for the selected pair, the provide and withdraw CTAs are disabled

Verification Checklist

  • SwapPage queries getPairPaused for the selected pair
  • SwapPage disables the swap submit CTA when the selected pair is paused
  • PoolPage queries getPairPaused for the selected pair
  • PoolPage disables provide and withdraw CTAs when the selected pair is paused
  • SwapPage unit test asserts swap submit is disabled under pair pause
  • PoolPage unit test asserts provide and withdraw CTAs disabled under pair pause
  • All new tests pass in CI

Labels

security, pre-launch

Cc: @PlasticDigits

### Checklist Item SEC-B05: Verify pair pause blocks swap, hybrid swap, limit place/cancel/claim/update, and LP actions according to intended policy. Verify: contract tests and frontend disabled-state tests match the documented policy. --- ### Summary The pair pause contract tests and the TradePage frontend test confirm that pair pause is enforced on-chain and that the Trade page shows a banner with disabled limit actions. However, SwapPage and PoolPage do not call `getPairPaused` at all. When a pair is paused, neither the swap submit CTA on SwapPage nor the provide/withdraw CTAs on PoolPage are proactively disabled in the frontend. Users submitting through those pages would receive an on-chain rejection with no prior UI indication. --- ### What Was Checked - `frontend-dapp/src/pages/TradePage.test.tsx` lines 656-668 -- pair pause banner confirmed, limit Place CTAs disabled -- PASSES for trade path - `frontend-dapp/src/pages/TradePage.tsx` line 259 -- calls `getPairPaused` -- CONFIRMED - `frontend-dapp/src/components/trade/TradeOrderTicket.tsx` line 256 -- calls `getPairPaused` -- CONFIRMED - `frontend-dapp/src/pages/LimitOrdersPage.tsx` line 140 -- calls `getPairPaused` -- CONFIRMED - `frontend-dapp/src/pages/SwapPage.tsx` lines 364-385 -- only queries wrap-mapper pause (`isWrapPaused`), no call to `getPairPaused` - `frontend-dapp/src/pages/PoolPage.tsx` -- no call to `getPairPaused` found - Grep for `getPairPaused` across all non-test frontend source files: only found in TradeOrderTicket, TradePage, LimitOrdersPage - `frontend-dapp/src/pages/SwapPage.test.tsx` -- no test for pair pause disabled swap CTA --- ### Expected (per checklist) Frontend disabled-state tests must match the documented policy for pair pause. The policy (contracts-security-audit.md invariant L6) states pair pause blocks swaps and LP actions. The frontend should proactively disable the swap submit CTA on SwapPage and the provide/withdraw CTAs on PoolPage when the selected pair is paused, and tests should assert this. --- ### Actual `getPairPaused` is not called in SwapPage or PoolPage. No frontend disabled-state test exists for pair pause on SwapPage or PoolPage. The contract-level enforcement exists, but users on those pages receive no proactive UI indication before submitting a transaction that will be rejected on-chain. --- ### Evidence - `frontend-dapp/src/pages/SwapPage.tsx` line 364-385: only wrap-mapper pause queried (`isWrapPaused`); no `getPairPaused` call - `frontend-dapp/src/pages/PoolPage.tsx`: no `getPairPaused` import or call - `frontend-dapp/src/pages/SwapPage.test.tsx`: no test for pair pause state on swap submit button - `frontend-dapp/src/pages/TradePage.test.tsx` lines 656-668: pair pause correctly tested on trade/limit path - Grep for `getPairPaused` in non-test frontend source: only 3 files (TradeOrderTicket, TradePage, LimitOrdersPage) --- ### Suggested Fix Add `getPairPaused` queries to SwapPage and PoolPage for the currently selected pair, and disable the swap submit and LP provide/withdraw CTAs respectively when the pair is paused, consistent with how TradePage handles it. Add unit tests asserting: - SwapPage: when `getPairPaused` returns `{ paused: true }` for the selected pair, the swap submit button is disabled - PoolPage: when `getPairPaused` returns `{ paused: true }` for the selected pair, the provide and withdraw CTAs are disabled --- ### Verification Checklist - [ ] SwapPage queries `getPairPaused` for the selected pair - [ ] SwapPage disables the swap submit CTA when the selected pair is paused - [ ] PoolPage queries `getPairPaused` for the selected pair - [ ] PoolPage disables provide and withdraw CTAs when the selected pair is paused - [ ] SwapPage unit test asserts swap submit is disabled under pair pause - [ ] PoolPage unit test asserts provide and withdraw CTAs disabled under pair pause - [ ] All new tests pass in CI --- ### Labels `security`, `pre-launch` Cc: @PlasticDigits
PlasticDigits commented 2026-06-19 10:48:15 +00:00 (Migrated from gitlab.com)

Paused state should be tracked by indexer.

Paused state should be tracked by indexer.
totdking commented 2026-06-19 10:57:16 +00:00 (Migrated from gitlab.com)

mentioned in issue #381

mentioned in issue #381
PlasticDigits commented 2026-06-19 10:59:31 +00:00 (Migrated from gitlab.com)

mentioned in merge request !925

mentioned in merge request !925
PlasticDigits commented 2026-06-19 12:45:51 +00:00 (Migrated from gitlab.com)

mentioned in commit d487a0cd94

mentioned in commit d487a0cd949ed7ca3d95f46d9e99d6eecc69f62d
PlasticDigits commented 2026-06-25 11:33:56 +00:00 (Migrated from gitlab.com)

Verification — GitLab #395 / SEC-B05 (PASS)

Verified on main (clean working tree). No code or docs changes required; closing issue.

Checklist results

Item Result How verified
SwapPage queries pair pause for selected route pair(s) PASS SwapPage.tsx uses usePairPaused (LCD getPairPaused via is_paused query) for single- and multi-hop route pairs
SwapPage disables swap submit CTA when pair paused PASS buttonDisabled when isPairPaused; label Pair is paused; data-testid="swap-pair-paused-banner"
PoolPage queries pair pause for selected pair PASS PoolPage.tsx uses usePairPaused({ pairAddress: pair.contract_addr })
PoolPage disables provide and withdraw CTAs when paused PASS Both submit buttons set disabled + Pair is paused label when isPairPaused; banner pool-pair-paused-banner
SwapPage unit test — swap submit disabled under pause PASS SwapPage.test.tsx → pair pause disabled swap CTA (SEC-B05 / GitLab #395)
PoolPage unit test — provide/withdraw disabled under pause PASS PoolPage.test.tsx → pair pause disabled LP CTAs (SEC-B05 / GitLab #395)
All new tests pass PASS See commands below

Commands / output

bash scripts/with-node.sh --cwd frontend-dapp -- npm run test:run -- \
  src/pages/SwapPage.test.tsx src/pages/PoolPage.test.tsx -t "SEC-B05"
# 3 passed (swap + provide + withdraw pause cases)

bash scripts/with-node.sh --cwd frontend-dapp -- npm test -- --run \
  src/pages/SwapPage.test.tsx src/pages/PoolPage.test.tsx
# 34 passed (2 files)

Policy alignment

  • On-chain L6 enforcement: contract test pause_blocks_swap_and_place_cancel_refunds_escrow in smartcontracts/tests/src/limit_order_tests.rs (GitLab #87).
  • Frontend policy documented in docs/testing.md § SEC-B05 and skills/AGENTS_FRONTEND_SWAP_SAFETY_CTA.md.
  • Trade/limit paths unchanged (already covered by TradePage.test.tsx).

Follow-ups (optional)

  • Issue comment suggested indexer-backed pause state instead of per-page LCD polling; current implementation uses shared usePairPaused with 15s stale cache. Consider indexer exposure if LCD load or consistency becomes a concern.
## Verification — GitLab #395 / SEC-B05 (PASS) Verified on `main` (clean working tree). No code or docs changes required; closing issue. ### Checklist results | Item | Result | How verified | |------|--------|--------------| | SwapPage queries pair pause for selected route pair(s) | **PASS** | `SwapPage.tsx` uses `usePairPaused` (LCD `getPairPaused` via `is_paused` query) for single- and multi-hop route pairs | | SwapPage disables swap submit CTA when pair paused | **PASS** | `buttonDisabled` when `isPairPaused`; label `Pair is paused`; `data-testid="swap-pair-paused-banner"` | | PoolPage queries pair pause for selected pair | **PASS** | `PoolPage.tsx` uses `usePairPaused({ pairAddress: pair.contract_addr })` | | PoolPage disables provide and withdraw CTAs when paused | **PASS** | Both submit buttons set `disabled` + `Pair is paused` label when `isPairPaused`; banner `pool-pair-paused-banner` | | SwapPage unit test — swap submit disabled under pause | **PASS** | `SwapPage.test.tsx` → `pair pause disabled swap CTA (SEC-B05 / GitLab #395)` | | PoolPage unit test — provide/withdraw disabled under pause | **PASS** | `PoolPage.test.tsx` → `pair pause disabled LP CTAs (SEC-B05 / GitLab #395)` | | All new tests pass | **PASS** | See commands below | ### Commands / output ```text bash scripts/with-node.sh --cwd frontend-dapp -- npm run test:run -- \ src/pages/SwapPage.test.tsx src/pages/PoolPage.test.tsx -t "SEC-B05" # 3 passed (swap + provide + withdraw pause cases) bash scripts/with-node.sh --cwd frontend-dapp -- npm test -- --run \ src/pages/SwapPage.test.tsx src/pages/PoolPage.test.tsx # 34 passed (2 files) ``` ### Policy alignment - On-chain **L6** enforcement: contract test `pause_blocks_swap_and_place_cancel_refunds_escrow` in `smartcontracts/tests/src/limit_order_tests.rs` (GitLab #87). - Frontend policy documented in `docs/testing.md` § SEC-B05 and `skills/AGENTS_FRONTEND_SWAP_SAFETY_CTA.md`. - Trade/limit paths unchanged (already covered by `TradePage.test.tsx`). ### Follow-ups (optional) - Issue comment suggested **indexer-backed pause state** instead of per-page LCD polling; current implementation uses shared `usePairPaused` with 15s stale cache. Consider indexer exposure if LCD load or consistency becomes a concern.
PlasticDigits (Migrated from gitlab.com) closed this issue 2026-06-25 11:34:00 +00:00
PlasticDigits commented 2026-06-25 14:12:46 +00:00 (Migrated from gitlab.com)

mentioned in issue #414

mentioned in issue #414
PlasticDigits commented 2026-06-25 14:12:50 +00:00 (Migrated from gitlab.com)

mentioned in issue #417

mentioned in issue #417
PlasticDigits commented 2026-06-25 22:53:55 +00:00 (Migrated from gitlab.com)

mentioned in merge request !945

mentioned in merge request !945
PlasticDigits commented 2026-08-18 12:08:53 +00:00 (Migrated from gitlab.com)

mentioned in issue #561

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