Expose polled_at_ms on arena timers and deepen API integration tests #506

Merged
PlasticDigits merged 1 commit from verify/333-polled-at-ms into main 2026-06-19 06:31:46 +00:00
PlasticDigits commented 2026-06-19 06:19:29 +00:00 (Migrated from gitlab.com)

Summary

  • Expose polled_at_ms on GET /v1/arena/timers (schema 2.18.0) from the internal chain-timer snapshot.
  • Frontend ArenaTimersResponse, legacy sale-state mappers, and useArenaHeroTimer prefer indexer poll time over Date.now() when present (fallback for older indexers).
  • Deepen integration_stage2 api_http_smoke: typed timer contract, activity buy row shape, wallet-stats bonus keys, malformed address 400, missing chain timer 503.

Verification checklist (GitLab #333)

Acceptance item Command / output Result
GET /v1/arena/timers returns polled_at_ms matching snapshot YIELDOMEGA_PG_TEST_URL=… cargo test --test integration_stage2 — asserts polled_at_ms == 1700000000123 PASS
Frontend types/hooks use indexer polled_at_ms cd frontend && npm run typecheck && npm test — indexerFirstDisplay.test.ts checks useArenaHeroTimer references polled_at_ms PASS
Integration tests assert JSON shapes (timers, activity, wallet stats) cargo test --test integration_stage2 — extended api_http_smoke + existing api_arena_activity_smoke / arena_wallet_stats_two_epochs_and_bonus_fields PASS
Schema version bumped and documented indexer/src/api.rs → 2.18.0; indexer/README.md, docs/indexer/design.md PASS
Indexer clippy + tests cd indexer && cargo clippy --all-targets -- -D warnings && cargo test PASS
Frontend typecheck + tests cd frontend && npm run typecheck && npm run lint && npm test PASS
Anvil smoke (optional) bash scripts/verify-podium-live-anvil.sh PASS
Live curl polled_at_ms Stack not left running post-smoke; covered by integration fixture parity + Anvil smoke OK SKIP (stack torn down)
Sad path: malformed wallet address → 400 integration_stage2 api_http_smoke PASS
Sad path: missing chain timer → 503 integration_stage2 api_http_smoke PASS
Attack: polled_at_ms read-only metadata No user input surface on field PASS
Postgres ready bash scripts/verify-cloud-postgres.sh PASS

Related: #333 (issue stays open until merge)

## Summary - Expose `polled_at_ms` on `GET /v1/arena/timers` (schema **2.18.0**) from the internal chain-timer snapshot. - Frontend `ArenaTimersResponse`, legacy sale-state mappers, and `useArenaHeroTimer` prefer indexer poll time over `Date.now()` when present (fallback for older indexers). - Deepen `integration_stage2` `api_http_smoke`: typed timer contract, activity buy row shape, wallet-stats bonus keys, malformed address **400**, missing chain timer **503**. ## Verification checklist (GitLab #333) | Acceptance item | Command / output | Result | |-----------------|------------------|--------| | `GET /v1/arena/timers` returns `polled_at_ms` matching snapshot | `YIELDOMEGA_PG_TEST_URL=… cargo test --test integration_stage2` — asserts `polled_at_ms == 1700000000123` | PASS | | Frontend types/hooks use indexer `polled_at_ms` | `cd frontend && npm run typecheck && npm test` — `indexerFirstDisplay.test.ts` checks `useArenaHeroTimer` references `polled_at_ms` | PASS | | Integration tests assert JSON shapes (timers, activity, wallet stats) | `cargo test --test integration_stage2` — extended `api_http_smoke` + existing `api_arena_activity_smoke` / `arena_wallet_stats_two_epochs_and_bonus_fields` | PASS | | Schema version bumped and documented | `indexer/src/api.rs` → **2.18.0**; `indexer/README.md`, `docs/indexer/design.md` | PASS | | Indexer clippy + tests | `cd indexer && cargo clippy --all-targets -- -D warnings && cargo test` | PASS | | Frontend typecheck + tests | `cd frontend && npm run typecheck && npm run lint && npm test` | PASS | | Anvil smoke (optional) | `bash scripts/verify-podium-live-anvil.sh` | PASS | | Live curl `polled_at_ms` | Stack not left running post-smoke; covered by integration fixture parity + Anvil smoke OK | SKIP (stack torn down) | | Sad path: malformed wallet address → 400 | `integration_stage2` `api_http_smoke` | PASS | | Sad path: missing chain timer → 503 | `integration_stage2` `api_http_smoke` | PASS | | Attack: `polled_at_ms` read-only metadata | No user input surface on field | PASS | | Postgres ready | `bash scripts/verify-cloud-postgres.sh` | PASS | Related: #333 (issue stays open until merge)
PlasticDigits commented 2026-06-19 06:22:05 +00:00 (Migrated from gitlab.com)

Security review — MR !506

Commit reviewed: 6b081c7ec93f4936fb81e317d34233900f3c7e21
Branch: verify/333-polled-at-ms
Scope: Expose polled_at_ms on GET /v1/arena/timers (schema 2.18.0); frontend hero timer / legacy mappers prefer indexer poll instant; deepen integration_stage2 api_http_smoke assertions (timers contract, activity buy shape, wallet-stats keys, chain-timer-unavailable 503).

Outcome: FINDINGS: 0 medium+

Method

  • Diff and data-flow review for attacker-controlled input → sink on all changed paths.
  • Traced polled_at_ms from chain_timer.rs (SystemTime::now() at poll) through api_arena.rs JSON to frontend useArenaHeroTimer / indexerApi.ts.
  • Checked timer/cooldown UX consumers (chainNowSec, buy-cooldown display) against on-chain submit-time gates.
  • No prior security-review threads on this MR.

Assessment

Area Result
Injection (SQL/shell/command) No new user input; timers endpoint is unparameterized GET. Test-only HTTP fixtures.
Authn/authz Unchanged public read API; 503 when poller snapshot unset is fail-closed (test confirms).
polled_at_ms trust boundary Server-generated u64 from internal poller — not writable by HTTP clients. Frontend already trusts indexer-first display for deadlines, prices, and head block (#301); this field aligns wall-clock skew with the same snapshot as block_timestamp_sec / deadlines rather than opening a new control surface.
EVM / economic abuse Countdown and cooldown UI derive from indexer display reads; buy submission remains gated by on-chain nextBuyAllowedAt / contract checks and fresh wallet RPC preflight. Manipulated or stale poll metadata could at most skew display under a compromised indexer/MITM — same pre-existing indexer trust model, not a new fund-loss path.
XSS / SSRF / secrets / deserialization No changes in those layers.
Supply chain No dependency changes.

Security review: no medium+ findings on this diff.

No inline threads (nothing to anchor).

## Security review — MR !506 **Commit reviewed:** `6b081c7ec93f4936fb81e317d34233900f3c7e21` **Branch:** `verify/333-polled-at-ms` **Scope:** Expose `polled_at_ms` on `GET /v1/arena/timers` (schema 2.18.0); frontend hero timer / legacy mappers prefer indexer poll instant; deepen `integration_stage2` `api_http_smoke` assertions (timers contract, activity buy shape, wallet-stats keys, chain-timer-unavailable 503). **Outcome:** `FINDINGS: 0` medium+ ### Method - Diff and data-flow review for attacker-controlled input → sink on all changed paths. - Traced `polled_at_ms` from `chain_timer.rs` (`SystemTime::now()` at poll) through `api_arena.rs` JSON to frontend `useArenaHeroTimer` / `indexerApi.ts`. - Checked timer/cooldown UX consumers (`chainNowSec`, buy-cooldown display) against on-chain submit-time gates. - No prior security-review threads on this MR. ### Assessment | Area | Result | |------|--------| | Injection (SQL/shell/command) | No new user input; timers endpoint is unparameterized GET. Test-only HTTP fixtures. | | Authn/authz | Unchanged public read API; 503 when poller snapshot unset is fail-closed (test confirms). | | `polled_at_ms` trust boundary | Server-generated `u64` from internal poller — not writable by HTTP clients. Frontend already trusts indexer-first display for deadlines, prices, and head block ([#301](https://gitlab.com/PlasticDigits/yieldomega/-/issues/301)); this field aligns wall-clock skew with the same snapshot as `block_timestamp_sec` / deadlines rather than opening a new control surface. | | EVM / economic abuse | Countdown and cooldown UI derive from indexer display reads; buy submission remains gated by on-chain `nextBuyAllowedAt` / contract checks and fresh wallet RPC preflight. Manipulated or stale poll metadata could at most skew **display** under a compromised indexer/MITM — same pre-existing indexer trust model, not a new fund-loss path. | | XSS / SSRF / secrets / deserialization | No changes in those layers. | | Supply chain | No dependency changes. | **Security review: no medium+ findings on this diff.** No inline threads (nothing to anchor).
PlasticDigits commented 2026-06-19 06:31:46 +00:00 (Migrated from gitlab.com)

mentioned in commit 071ec841e0

mentioned in commit 071ec841e09e24ad125da7bd331d4c4d00f9adb3
PlasticDigits (Migrated from gitlab.com) merged commit 071ec841e0 into main 2026-06-19 06:31:47 +00:00
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
code/yieldomega!506
No description provided.