Extend arena activity API with state transition events (#345) #516

Merged
PlasticDigits merged 1 commit from issue-345-activity-transitions into main 2026-06-25 21:53:17 +00:00
PlasticDigits commented 2026-06-25 20:49:07 +00:00 (Migrated from gitlab.com)

Summary

Extends GET /v1/arena/activity with five state-transition event kinds already persisted by the indexer but previously omitted from the unified feed (#345):

  • level_up — idx_arena_level_up (bp_delta = new level)
  • cred_claim — idx_play_cred_claim (amount_doub_wad = CRED wad, seconds_delta = epoch)
  • podium_epoch — idx_arena_podium_epoch (actor = 1st place, target = epoch, amount_doub_wad = pool_paid, seconds_delta = category)
  • epoch_started — idx_arena_last_buy_epoch_started (actor = zero address for global events, bp_delta = epoch, seconds_delta = deadline)
  • feature_unlocked — idx_arena_feature_unlocked (bp_delta = feature level)

Schema version bumped to 2.19.0. Frontend ArenaActivityKind union updated for TypeScript consumers; celebration/toast UI wiring remains a follow-up.

Acceptance checklist

Criterion Command / step Result
Activity feed returns all five new kinds when present in DB cd indexer && YIELDOMEGA_PG_TEST_URL=postgres://yieldomega:password@127.0.0.1:5433/yieldomega_indexer_test cargo test postgres_stage2_persist_all_events_and_rollback_after PASS
Cursor pagination works across mixed kinds integration_stage2.rs::api_activity_cursor_smoke (same test run) PASS
OpenAPI/docs or invariants entry for new kind values docs/indexer/design.md, INV-INDEXER-345-ACTIVITY-TRANSITIONS in docs/testing/invariants-and-business-logic.md PASS
No SQL injection — parameterized cursor pattern api_arena.rs uses existing $1/$2/$3 binds PASS
Indexer clippy + unit tests cd indexer && cargo clippy --all-targets -- -D warnings && cargo test PASS
Frontend types (additive) cd frontend && npm run typecheck && npm run lint && npm test PASS

Verification checklist (third parties)

  1. Bootstrap Postgres: bash scripts/bootstrap-cloud-postgres-native.sh
  2. Run integration test: export YIELDOMEGA_PG_TEST_URL=postgres://yieldomega:password@127.0.0.1:5433/yieldomega_indexer_test && cd indexer && cargo test postgres_stage2_persist_all_events_and_rollback_after
  3. Optional Anvil smoke (level history baseline): bash scripts/verify-wallet-profile-anvil.sh
  4. With a live indexer stack, curl -sf 'http://127.0.0.1:3100/v1/arena/activity?limit=25' | jq '.items[].kind' | sort -u should include transition kinds after scripted level-up / roll / claim txs.

Test plan

cd indexer && cargo clippy --all-targets -- -D warnings && cargo test
cd frontend && npm run typecheck && npm run lint && npm test
## Summary Extends `GET /v1/arena/activity` with five state-transition event kinds already persisted by the indexer but previously omitted from the unified feed ([#345](https://gitlab.com/PlasticDigits/yieldomega/-/issues/345)): - `level_up` — `idx_arena_level_up` (`bp_delta` = new level) - `cred_claim` — `idx_play_cred_claim` (`amount_doub_wad` = CRED wad, `seconds_delta` = epoch) - `podium_epoch` — `idx_arena_podium_epoch` (`actor` = 1st place, `target` = epoch, `amount_doub_wad` = pool_paid, `seconds_delta` = category) - `epoch_started` — `idx_arena_last_buy_epoch_started` (`actor` = zero address for global events, `bp_delta` = epoch, `seconds_delta` = deadline) - `feature_unlocked` — `idx_arena_feature_unlocked` (`bp_delta` = feature level) Schema version bumped to **2.19.0**. Frontend `ArenaActivityKind` union updated for TypeScript consumers; celebration/toast UI wiring remains a follow-up. ## Acceptance checklist | Criterion | Command / step | Result | |-----------|----------------|--------| | Activity feed returns all five new kinds when present in DB | `cd indexer && YIELDOMEGA_PG_TEST_URL=postgres://yieldomega:password@127.0.0.1:5433/yieldomega_indexer_test cargo test postgres_stage2_persist_all_events_and_rollback_after` | PASS | | Cursor pagination works across mixed kinds | `integration_stage2.rs::api_activity_cursor_smoke` (same test run) | PASS | | OpenAPI/docs or invariants entry for new `kind` values | `docs/indexer/design.md`, `INV-INDEXER-345-ACTIVITY-TRANSITIONS` in `docs/testing/invariants-and-business-logic.md` | PASS | | No SQL injection — parameterized cursor pattern | `api_arena.rs` uses existing `$1`/`$2`/`$3` binds | PASS | | Indexer clippy + unit tests | `cd indexer && cargo clippy --all-targets -- -D warnings && cargo test` | PASS | | Frontend types (additive) | `cd frontend && npm run typecheck && npm run lint && npm test` | PASS | ## Verification checklist (third parties) 1. Bootstrap Postgres: `bash scripts/bootstrap-cloud-postgres-native.sh` 2. Run integration test: `export YIELDOMEGA_PG_TEST_URL=postgres://yieldomega:password@127.0.0.1:5433/yieldomega_indexer_test && cd indexer && cargo test postgres_stage2_persist_all_events_and_rollback_after` 3. Optional Anvil smoke (level history baseline): `bash scripts/verify-wallet-profile-anvil.sh` 4. With a live indexer stack, `curl -sf 'http://127.0.0.1:3100/v1/arena/activity?limit=25' | jq '.items[].kind' | sort -u` should include transition kinds after scripted level-up / roll / claim txs. ## Test plan ``` cd indexer && cargo clippy --all-targets -- -D warnings && cargo test cd frontend && npm run typecheck && npm run lint && npm test ```
PlasticDigits commented 2026-06-25 20:51:34 +00:00 (Migrated from gitlab.com)

Security review

Commit reviewed: 22b102f63c840238441ebe259b4b7086ed257289
Scope: GET /v1/arena/activity — five new UNION ALL branches (level_up, cred_claim, podium_epoch, epoch_started, feature_unlocked); schema bump to 2.19.0; additive ArenaActivityKind TypeScript union; integration tests.
Outcome: FINDINGS: 0 medium+

Method

Traced attacker-controlled inputs (limit, offset, cursor) through arena_activity → ListPageParams / BlockLogCursor::decode → parameterized sqlx::query binds ($1–$3). Reviewed new SQL fragments in ACTIVITY_UNION_SQL (static constant; no string interpolation of user input). Checked frontend consumption (ArenaLiveBuysActivitySection, AddressInline) for XSS sinks. No smart-contract or auth-layer changes in this diff.

Areas reviewed (no issues)

Area Result
SQL injection Cursor decoded to i64/i32 and bound; ACTIVITY_UNION_SQL is compile-time constant
Authn/authz Unchanged public read endpoint; no new routes or privilege boundaries
SSRF / shell / path traversal Not applicable to this diff
Secret leakage / logging No new logging or credential handling
XSS API fields rendered via React text nodes / validated AddressInline; no dangerouslySetInnerHTML
EVM / onchain Indexer projection only; no contract changes
DoS limit clamped 1–200; five additional union arms follow existing pattern

Inline threads

None — no medium+ findings to annotate on the diff.


Security review: no medium+ findings on this diff.

## Security review **Commit reviewed:** `22b102f63c840238441ebe259b4b7086ed257289` **Scope:** `GET /v1/arena/activity` — five new `UNION ALL` branches (`level_up`, `cred_claim`, `podium_epoch`, `epoch_started`, `feature_unlocked`); schema bump to 2.19.0; additive `ArenaActivityKind` TypeScript union; integration tests. **Outcome:** **FINDINGS: 0** medium+ ### Method Traced attacker-controlled inputs (`limit`, `offset`, `cursor`) through `arena_activity` → `ListPageParams` / `BlockLogCursor::decode` → parameterized `sqlx::query` binds (`$1`–`$3`). Reviewed new SQL fragments in `ACTIVITY_UNION_SQL` (static constant; no string interpolation of user input). Checked frontend consumption (`ArenaLiveBuysActivitySection`, `AddressInline`) for XSS sinks. No smart-contract or auth-layer changes in this diff. ### Areas reviewed (no issues) | Area | Result | |------|--------| | SQL injection | Cursor decoded to `i64`/`i32` and bound; `ACTIVITY_UNION_SQL` is compile-time constant | | Authn/authz | Unchanged public read endpoint; no new routes or privilege boundaries | | SSRF / shell / path traversal | Not applicable to this diff | | Secret leakage / logging | No new logging or credential handling | | XSS | API fields rendered via React text nodes / validated `AddressInline`; no `dangerouslySetInnerHTML` | | EVM / onchain | Indexer projection only; no contract changes | | DoS | `limit` clamped 1–200; five additional union arms follow existing pattern | ### Inline threads None — no medium+ findings to annotate on the diff. --- Security review: **no medium+ findings** on this diff.
PlasticDigits commented 2026-06-25 21:53:18 +00:00 (Migrated from gitlab.com)

mentioned in commit 5507efc596

mentioned in commit 5507efc5967cd8d18ed0c1be645f24c0087e9b92
PlasticDigits (Migrated from gitlab.com) merged commit 5507efc596 into main 2026-06-25 21:53:18 +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!516
No description provided.