Arena buys API: full BuyItem log identity parity (#283) #410

Merged
PlasticDigits merged 2 commits from cursor/arena-buys-parity-283-7d54 into main 2026-06-03 12:52:43 +00:00
PlasticDigits commented 2026-06-03 12:28:15 +00:00 (Migrated from gitlab.com)

Summary

Closes the HTTP/frontend gap left after #282 by exposing new_deadline, buy_index, log_index, and block_timestamp on GET /v1/arena/buys, matching persisted idx_arena_buy rows (onchain Buy log projection only — no client recomputation).

  • Indexer: extend arena_buys SELECT/JSON in api_arena.rs (same EXTRACT(EPOCH …)::text pattern as vault-funding / donate-pools).
  • Frontend: extend ArenaBuyItem + mapArenaBuyToBuyItem so live-buy React keys, buy detail, and protocol audit rows receive real values instead of stubs.
  • Tests / verify: extend integration_stage2 buy smoke + verify-wallet-profile-anvil.sh DB/API parity for all four fields.
  • Docs: INV-INDEXER-283-ARENA-BUYS-PARITY, indexer design, arena-views, guardrails + play skill cross-links.

Related: #282 (prerequisite actual_seconds_added), #258 (wallet profile / buy detail UX).

Acceptance checklist

Criterion Verification Result
GET /v1/arena/buys includes new_deadline, buy_index, log_index, block_timestamp cd indexer && cargo test --test integration_stage2 PASS
After Anvil DOUB buy, API fields match idx_arena_buy for tx_hash/log_index export PATH="$HOME/.foundry/bin:$PATH" && source /usr/local/cargo/env 2>/dev/null; bash scripts/verify-wallet-profile-anvil.sh PASS
fetchArenaBuysAsBuyItems surfaces all four on BuyItem cd frontend && npm run typecheck && npm test -- indexerApi PASS
Live-buy lists use stable tx_hash + log_index keys (mapper no longer forces 0) Code review mapArenaBuyToBuyItem + indexerApi.test.ts PASS
Buy detail modal shows new_deadline when present Existing UnixTimestampDisplay path in ArenaBuyModals.tsx (manual QA below) PASS (code path)
Hermetic verify script exits 0 with parity assertions bash scripts/verify-wallet-profile-anvil.sh (Foundry + Cargo ≥ 1.85 + Postgres on :5433) PASS
Invariants/docs updated with verify command docs/testing/invariants-and-business-logic.md, docs/indexer/design.md, .cursor/skills/yieldomega-guardrails/SKILL.md PASS

Blockers: none.

Third-party verification

export PATH="$HOME/.foundry/bin:$PATH"
source /usr/local/cargo/env 2>/dev/null || true
# Postgres 16 on 127.0.0.1:5433 per AGENTS.md if not already running

cd indexer && cargo clippy --all-targets -- -D warnings && cargo test
cd ../frontend && npm run typecheck && npm test -- indexerApi
bash scripts/verify-wallet-profile-anvil.sh

curl -s 'http://127.0.0.1:3103/v1/arena/buys?limit=1' | jq '.items[0] | {new_deadline,buy_index,log_index,block_timestamp,actual_seconds_added}'

Manual (optional): start full stack, open /arena, open buy detail from live buys — New deadline should show real unix time (not 0).

Notes

  • block_timestamp JSON uses Postgres EXTRACT(EPOCH FROM timestamptz)::text (may include a .000000 suffix); API and DB comparisons use the same projection.
  • Issue #283 left open per workflow.
## Summary Closes the HTTP/frontend gap left after #282 by exposing **`new_deadline`**, **`buy_index`**, **`log_index`**, and **`block_timestamp`** on **`GET /v1/arena/buys`**, matching persisted **`idx_arena_buy`** rows (onchain **`Buy`** log projection only — no client recomputation). - **Indexer:** extend `arena_buys` SELECT/JSON in `api_arena.rs` (same `EXTRACT(EPOCH …)::text` pattern as vault-funding / donate-pools). - **Frontend:** extend `ArenaBuyItem` + `mapArenaBuyToBuyItem` so live-buy React keys, buy detail, and protocol audit rows receive real values instead of stubs. - **Tests / verify:** extend `integration_stage2` buy smoke + `verify-wallet-profile-anvil.sh` DB/API parity for all four fields. - **Docs:** `INV-INDEXER-283-ARENA-BUYS-PARITY`, indexer design, arena-views, guardrails + play skill cross-links. Related: #282 (prerequisite `actual_seconds_added`), #258 (wallet profile / buy detail UX). ## Acceptance checklist | Criterion | Verification | Result | |-----------|--------------|--------| | `GET /v1/arena/buys` includes `new_deadline`, `buy_index`, `log_index`, `block_timestamp` | `cd indexer && cargo test --test integration_stage2` | PASS | | After Anvil DOUB buy, API fields match `idx_arena_buy` for `tx_hash`/`log_index` | `export PATH="$HOME/.foundry/bin:$PATH" && source /usr/local/cargo/env 2>/dev/null; bash scripts/verify-wallet-profile-anvil.sh` | PASS | | `fetchArenaBuysAsBuyItems` surfaces all four on `BuyItem` | `cd frontend && npm run typecheck && npm test -- indexerApi` | PASS | | Live-buy lists use stable `tx_hash` + `log_index` keys (mapper no longer forces `0`) | Code review `mapArenaBuyToBuyItem` + `indexerApi.test.ts` | PASS | | Buy detail modal shows `new_deadline` when present | Existing `UnixTimestampDisplay` path in `ArenaBuyModals.tsx` (manual QA below) | PASS (code path) | | Hermetic verify script exits 0 with parity assertions | `bash scripts/verify-wallet-profile-anvil.sh` (Foundry + Cargo ≥ 1.85 + Postgres on `:5433`) | PASS | | Invariants/docs updated with verify command | `docs/testing/invariants-and-business-logic.md`, `docs/indexer/design.md`, `.cursor/skills/yieldomega-guardrails/SKILL.md` | PASS | **Blockers:** none. ## Third-party verification ```bash export PATH="$HOME/.foundry/bin:$PATH" source /usr/local/cargo/env 2>/dev/null || true # Postgres 16 on 127.0.0.1:5433 per AGENTS.md if not already running cd indexer && cargo clippy --all-targets -- -D warnings && cargo test cd ../frontend && npm run typecheck && npm test -- indexerApi bash scripts/verify-wallet-profile-anvil.sh curl -s 'http://127.0.0.1:3103/v1/arena/buys?limit=1' | jq '.items[0] | {new_deadline,buy_index,log_index,block_timestamp,actual_seconds_added}' ``` Manual (optional): start full stack, open `/arena`, open buy detail from live buys — **New deadline** should show real unix time (not `0`). ## Notes - `block_timestamp` JSON uses Postgres `EXTRACT(EPOCH FROM timestamptz)::text` (may include a `.000000` suffix); API and DB comparisons use the same projection. - Issue #283 left open per workflow.
PlasticDigits commented 2026-06-03 12:28:24 +00:00 (Migrated from gitlab.com)

changed the description

changed the description
PlasticDigits commented 2026-06-03 12:29:39 +00:00 (Migrated from gitlab.com)

marked this merge request as ready

marked this merge request as **ready**
ghost1 commented 2026-06-03 12:31:48 +00:00 (Migrated from gitlab.com)

Security review

Commit reviewed: 11f72eb04238bc6cb5d84238dbbfc3c1023c48ed
Scope: Arena buys API parity (#283) — expose new_deadline, buy_index, log_index, and block_timestamp on GET /v1/arena/buys; frontend ArenaBuyItem / mapArenaBuyToBuyItem mapping; integration + verify script parity assertions; docs/invariants.

Outcome: FINDINGS: 0 medium+

Inline threads: none (no findings to anchor)

Summary

Reviewed added/modified code paths for injection, authn/authz, XSS, and information-disclosure risks:

  • Indexer (api_arena.rs): New columns are selected from idx_arena_buy via the existing parameterized query (LIMIT/OFFSET bound as $1/$2). No attacker-controlled input reaches SQL. Endpoint remains an unauthenticated public read API; added fields are onchain Buy log projections already persisted at ingest.
  • Frontend (indexerApi.ts): Mapper passes through numeric/string fields from indexer JSON into BuyItem. UI rendering paths (ArenaBuyModals, formatBuyAge, UnixTimestampDisplay) gate display with digit-only / BigInt validation; React text rendering avoids HTML injection.
  • Verify script (verify-wallet-profile-anvil.sh): parity_field uses interpolated BUY_TX in local psql calls; value is Anvil cast send output (hex tx hash), dev-only hermetic smoke — not production attack surface.
  • No new secrets, auth changes, SSRF, deserialization, or dependency updates in this diff.

Security review: no medium+ findings on this diff.

## Security review **Commit reviewed:** `11f72eb04238bc6cb5d84238dbbfc3c1023c48ed` **Scope:** Arena buys API parity (#283) — expose `new_deadline`, `buy_index`, `log_index`, and `block_timestamp` on `GET /v1/arena/buys`; frontend `ArenaBuyItem` / `mapArenaBuyToBuyItem` mapping; integration + verify script parity assertions; docs/invariants. **Outcome:** `FINDINGS: 0` medium+ **Inline threads:** none (no findings to anchor) ### Summary Reviewed added/modified code paths for injection, authn/authz, XSS, and information-disclosure risks: - **Indexer (`api_arena.rs`):** New columns are selected from `idx_arena_buy` via the existing parameterized query (`LIMIT`/`OFFSET` bound as `$1`/`$2`). No attacker-controlled input reaches SQL. Endpoint remains an unauthenticated public read API; added fields are onchain `Buy` log projections already persisted at ingest. - **Frontend (`indexerApi.ts`):** Mapper passes through numeric/string fields from indexer JSON into `BuyItem`. UI rendering paths (`ArenaBuyModals`, `formatBuyAge`, `UnixTimestampDisplay`) gate display with digit-only / `BigInt` validation; React text rendering avoids HTML injection. - **Verify script (`verify-wallet-profile-anvil.sh`):** `parity_field` uses interpolated `BUY_TX` in local `psql` calls; value is Anvil `cast send` output (hex tx hash), dev-only hermetic smoke — not production attack surface. - **No new secrets, auth changes, SSRF, deserialization, or dependency updates** in this diff. Security review: **no medium+ findings** on this diff.
PlasticDigits commented 2026-06-03 12:52:44 +00:00 (Migrated from gitlab.com)

mentioned in commit 6d520e7a98

mentioned in commit 6d520e7a988b307c8e0a7b0a1a88da3dbd7dbeb5
PlasticDigits (Migrated from gitlab.com) merged commit 6d520e7a98 into main 2026-06-03 12:52:44 +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!410
No description provided.