Arena: improve WarBow revenge hero card (BP preview, live Valid To countdown) #236

Closed
opened 2026-05-22 00:14:55 +00:00 by PlasticDigits · 7 comments
PlasticDigits commented 2026-05-22 00:14:55 +00:00 (Migrated from gitlab.com)

Summary

The Revenge hero card on /timecurve/arena (WarbowHeroActions) lists open per-stealer counter-hit windows (GitLab #135) but the copy and timestamps are hard to scan at a glance. Improve the card so each row shows stealer BP, expected BP gained on revenge (humanized), and a live Valid To: HH:MM:SS countdown — and remove redundant summary text.

Primary file: frontend/src/pages/timeCurveArena/WarbowHeroActions.tsx

Related (lower section, optional parity): frontend/src/pages/timecurve/TimeCurveSections.tsx — WarbowSection revenge list (orphaned on Arena but still used elsewhere).

Current behavior

When hasRevengeOpen:

  1. A muted paragraph repeats the list length: “You have {n} open counter-hit(s). Earliest expiry {UTC}.”
  2. Each <li> shows stealer address + “· until {UTC}” via UnixTimestampDisplay + Take revenge CTA.

Problems:

  • Summary duplicates information already visible in the list (count + earliest expiry).
  • UTC timestamps are not actionable during play; users want time remaining ticking every second.
  • Rows do not surface how much BP the stealer currently has or how much BP revenge would return before signing.

UX requirements

1. Remove redundant summary

  • Delete the paragraph: You have {x} open counter-hit(s). Earliest expiry … (including the word “Earliest expiry”).
  • When revenge windows exist, show only the per-stealer list (no duplicate count line above it).
  • Empty state copy unchanged (No revenge available / indexer env hint).

2. Per-row BP context (humanized)

For each open revenge row (each pendingRevengeTargets entry / stealer):

Field Meaning Source
Target BP Stealer’s current Battle Points Live battlePoints(stealer) read (indexer leaderboard BP when configured — same display policy as Arena WarBow elsewhere; no authoritative BP off-indexer overlay per #216)
Gain BP the victim would reclaim on successful warbowRevenge(stealer) Onchain preview: _warbowStealDrainBp(stealerBp, WARBOW_STEAL_DRAIN_BPS) — revenge always uses the 10% drain branch (TimeCurve.warbowRevenge, WARBOW_STEAL_DRAIN_BPS = 1000)

Formatting: Reuse existing Arena BP humanization — formatWarbowViewerBattlePointsDisplay / formatLocaleInteger with comma grouping (same sigfig policy as hero YOUR BP is acceptable). Suggested row copy pattern (tweak for layout):

  • Target: {humanBp} BP · Gain: +{humanBp} BP

Show — or a muted loading state while stealer BP reads are in flight. If preview gain computes to 0, surface the same preflight narrative users would see on submit (TimeCurve: revenge zero) rather than a misleading +0.

Implementation note: Stealer BP reads for N open windows may require batched useReadContracts / multicall (watch stable deps — see steal discovery batching in useTimeCurveArenaModel.tsx). Consider a small shared helper (e.g. warbowRevengeRowPreview.ts) for drain math mirroring onchain _warbowStealDrainBp.

3. Live Valid To: HH:MM:SS (not UTC)

Replace per-row “· until {UTC}” with a label that counts down to expiry_exclusive:

  • Label: Valid To: {HH:MM:SS} where the clock is remaining time until the window closes (not wall-clock time of day).
  • Tick: Update every second on the same ledger/interpolated-now basis as other Arena hero timers (ledgerSecInt / effectiveLedgerSec from hero timer when available — #48).
  • Expired in-list edge: If a row slips past expiry before the 8s indexer poll removes it, show Valid To: 00:00:00 (or drop the row client-side — already filtered by expiry_exclusive > now in pendingRevengeTargets).

Reuse: formatCountdown (same helper as claim-flag / guard silence — #218).

Do not use UnixTimestampDisplay for this hero revenge list after the change.

4. Layout / responsive

Preserve #201 wrapping for .warbow-hero-revenge-list li when adding BP + countdown fields (stack on narrow widths; no horizontal overflow).

Onchain reference

From TimeCurve.sol:

  • Revenge window: WARBOW_REVENGE_WINDOW_SEC (24h); expiry stored in warbowPendingRevengeExpiryExclusive[victim][stealer].
  • Revenge drain: 10% of stealer BP (WARBOW_STEAL_DRAIN_BPS), floor via _warbowStealDrainBp.
  • Indexer list: GET /v1/timecurve/warbow/pending-revenge → WarbowPendingRevengeItem (stealer, expiry_exclusive, …).

Acceptance criteria

  • With ≥1 open revenge window, hero card shows no “You have {n} open counter-hit” / “Earliest expiry” summary line.
  • Each list row shows stealer address, Target BP (humanized), Gain (humanized preview), and Valid To: HH:MM:SS counting down every second until expiry.
  • Countdown uses Arena ledger/interpolated now (not Date.now() alone).
  • UTC UnixTimestampDisplay removed from hero revenge rows.
  • Vitest coverage in WarbowHeroActions.test.tsx for: no summary paragraph; row copy includes BP fields + Valid To:; countdown string changes when ledgerNowSec advances (fake timers).
  • Manual QA on /timecurve/arena with VITE_INDEXER_URL and a wallet holding multiple open stealers (#135 scenario).

Docs / invariants (follow-up in implementation PR)

## Summary The **Revenge** hero card on `/timecurve/arena` (`WarbowHeroActions`) lists open per-stealer counter-hit windows ([GitLab #135](https://gitlab.com/PlasticDigits/yieldomega/-/issues/135)) but the copy and timestamps are hard to scan at a glance. Improve the card so each row shows **stealer BP**, **expected BP gained on revenge** (humanized), and a **live `Valid To: HH:MM:SS`** countdown — and remove redundant summary text. **Primary file:** [`frontend/src/pages/timeCurveArena/WarbowHeroActions.tsx`](frontend/src/pages/timeCurveArena/WarbowHeroActions.tsx) **Related (lower section, optional parity):** [`frontend/src/pages/timecurve/TimeCurveSections.tsx`](frontend/src/pages/timecurve/TimeCurveSections.tsx) — `WarbowSection` revenge list (orphaned on Arena but still used elsewhere). ## Current behavior When `hasRevengeOpen`: 1. A muted paragraph repeats the list length: **“You have {n} open counter-hit(s). Earliest expiry {UTC}.”** 2. Each `<li>` shows stealer address + **“· until {UTC}”** via [`UnixTimestampDisplay`](frontend/src/components/UnixTimestampDisplay.tsx) + **Take revenge** CTA. Problems: - Summary duplicates information already visible in the list (count + earliest expiry). - UTC timestamps are not actionable during play; users want **time remaining** ticking every second. - Rows do not surface **how much BP the stealer currently has** or **how much BP revenge would return** before signing. ## UX requirements ### 1. Remove redundant summary - **Delete** the paragraph: `You have {x} open counter-hit(s). Earliest expiry …` (including the word **“Earliest expiry”**). - When revenge windows exist, show **only** the per-stealer list (no duplicate count line above it). - Empty state copy unchanged (`No revenge available` / indexer env hint). ### 2. Per-row BP context (humanized) For **each** open revenge row (each `pendingRevengeTargets` entry / stealer): | Field | Meaning | Source | |-------|---------|--------| | **Target BP** | Stealer’s current Battle Points | Live `battlePoints(stealer)` read (indexer leaderboard BP when configured — same display policy as Arena WarBow elsewhere; **no** authoritative BP off-indexer overlay per [#216](https://gitlab.com/PlasticDigits/yieldomega/-/issues/216)) | | **Gain** | BP the victim would reclaim on successful `warbowRevenge(stealer)` | Onchain preview: `_warbowStealDrainBp(stealerBp, WARBOW_STEAL_DRAIN_BPS)` — revenge always uses the **10%** drain branch ([`TimeCurve.warbowRevenge`](contracts/src/TimeCurve.sol), `WARBOW_STEAL_DRAIN_BPS = 1000`) | **Formatting:** Reuse existing Arena BP humanization — [`formatWarbowViewerBattlePointsDisplay`](frontend/src/pages/timeCurveArena/arenaPageHelpers.ts) / [`formatLocaleInteger`](frontend/src/lib/formatAmount.ts) with comma grouping (same sigfig policy as hero **YOUR BP** is acceptable). Suggested row copy pattern (tweak for layout): - `Target: {humanBp} BP · Gain: +{humanBp} BP` Show `—` or a muted loading state while stealer BP reads are in flight. If preview gain computes to **0**, surface the same preflight narrative users would see on submit (`TimeCurve: revenge zero`) rather than a misleading **+0**. **Implementation note:** Stealer BP reads for **N** open windows may require batched `useReadContracts` / multicall (watch stable deps — see steal discovery batching in [`useTimeCurveArenaModel.tsx`](frontend/src/pages/timeCurveArena/useTimeCurveArenaModel.tsx)). Consider a small shared helper (e.g. `warbowRevengeRowPreview.ts`) for drain math mirroring onchain `_warbowStealDrainBp`. ### 3. Live `Valid To: HH:MM:SS` (not UTC) Replace per-row **“· until {UTC}”** with a label that counts down to `expiry_exclusive`: - **Label:** `Valid To: {HH:MM:SS}` where the clock is **remaining time** until the window closes (not wall-clock time of day). - **Tick:** Update **every second** on the same ledger/interpolated-now basis as other Arena hero timers (`ledgerSecInt` / `effectiveLedgerSec` from hero timer when available — [#48](https://gitlab.com/PlasticDigits/yieldomega/-/issues/48)). - **Expired in-list edge:** If a row slips past expiry before the 8s indexer poll removes it, show `Valid To: 00:00:00` (or drop the row client-side — already filtered by `expiry_exclusive > now` in `pendingRevengeTargets`). **Reuse:** [`formatCountdown`](frontend/src/pages/timecurve/formatTimer.ts) (same helper as claim-flag / guard silence — [#218](https://gitlab.com/PlasticDigits/yieldomega/-/issues/218)). **Do not** use [`UnixTimestampDisplay`](frontend/src/components/UnixTimestampDisplay.tsx) for this hero revenge list after the change. ### 4. Layout / responsive Preserve [#201](https://gitlab.com/PlasticDigits/yieldomega/-/issues/201) wrapping for `.warbow-hero-revenge-list li` when adding BP + countdown fields (stack on narrow widths; no horizontal overflow). ## Onchain reference From [`TimeCurve.sol`](contracts/src/TimeCurve.sol): - Revenge window: `WARBOW_REVENGE_WINDOW_SEC` (**24h**); expiry stored in `warbowPendingRevengeExpiryExclusive[victim][stealer]`. - Revenge drain: **10%** of stealer BP (`WARBOW_STEAL_DRAIN_BPS`), floor via `_warbowStealDrainBp`. - Indexer list: `GET /v1/timecurve/warbow/pending-revenge` → [`WarbowPendingRevengeItem`](frontend/src/lib/indexerApi.ts) (`stealer`, `expiry_exclusive`, …). ## Acceptance criteria - [ ] With ≥1 open revenge window, hero card shows **no** “You have {n} open counter-hit” / “Earliest expiry” summary line. - [ ] Each list row shows stealer address, **Target BP** (humanized), **Gain** (humanized preview), and **`Valid To: HH:MM:SS`** counting down every second until expiry. - [ ] Countdown uses Arena ledger/interpolated now (not `Date.now()` alone). - [ ] UTC `UnixTimestampDisplay` removed from hero revenge rows. - [ ] Vitest coverage in [`WarbowHeroActions.test.tsx`](frontend/src/pages/timeCurveArena/WarbowHeroActions.test.tsx) for: no summary paragraph; row copy includes BP fields + `Valid To:`; countdown string changes when `ledgerNowSec` advances (fake timers). - [ ] Manual QA on `/timecurve/arena` with `VITE_INDEXER_URL` and a wallet holding multiple open stealers ([#135](https://gitlab.com/PlasticDigits/yieldomega/-/issues/135) scenario). ## Docs / invariants (follow-up in implementation PR) - Cross-link from [`docs/frontend/timecurve-views.md`](docs/frontend/timecurve-views.md) § Arena WarBow hero (#101). - Optional invariant row `INV-FRONTEND-*-REVENGE-HERO` in [`docs/testing/invariants-and-business-logic.md`](docs/testing/invariants-and-business-logic.md).
PlasticDigits commented 2026-05-22 00:14:56 +00:00 (Migrated from gitlab.com)

marked as related to #135

marked as related to #135
PlasticDigits commented 2026-05-22 00:14:57 +00:00 (Migrated from gitlab.com)

marked as related to #101

marked as related to #101
Brouie commented 2026-05-22 02:16:47 +00:00 (Migrated from gitlab.com)

Walked the current-state baseline for #236 on production /timecurve/arena.

All four problems listed in "Current behavior" are reproducible in the visible REVENGE hero card:

  1. Redundant summary paragraph present: "You have 3 open counter-hits. Earliest expiry {LOCAL/UTC stack}" — duplicates the count + earliest expiry already inferable from the list below.
  2. UTC timestamps not actionable during play: each row shows "· until {LOCAL date} / UTC {ISO string}" via UnixTimestampDisplay. Static, not a countdown.
  3. No BP context per row: stealer addresses + UTC stamps + Take revenge CTA only. No Target BP, no Gain preview.
  4. No live tick: confirmed by holding the page for ~10s — UTC fields don't update, no per-second countdown anywhere on the row.

image.png{width=635 height=274}

Pre-refactor baseline locked. Ready to re-walk against the new BP preview + Valid To: countdown when the refactor lands.

Automated baseline from yesterday's session (current code, pre-refactor): full Vitest suite 534/534 PASS including existing WarbowHeroActions.test.tsx. The new test cases listed in acceptance criteria (no summary paragraph, row copy includes BP fields + Valid To, countdown ticks under fake timers) need to be added by dev as part of the refactor PR.

Walked the current-state baseline for #236 on production /timecurve/arena. All four problems listed in "Current behavior" are reproducible in the visible REVENGE hero card: 1. **Redundant summary paragraph present:** "You have 3 open counter-hits. Earliest expiry {LOCAL/UTC stack}" — duplicates the count + earliest expiry already inferable from the list below. 2. **UTC timestamps not actionable during play:** each row shows "· until {LOCAL date} / UTC {ISO string}" via UnixTimestampDisplay. Static, not a countdown. 3. **No BP context per row:** stealer addresses + UTC stamps + Take revenge CTA only. No Target BP, no Gain preview. 4. **No live tick:** confirmed by holding the page for \~10s — UTC fields don't update, no per-second countdown anywhere on the row. ![image.png](/uploads/2e7ca7b8e239914405460ff494d9f7b6/image.png){width=635 height=274} Pre-refactor baseline locked. Ready to re-walk against the new BP preview + Valid To: countdown when the refactor lands. Automated baseline from yesterday's session (current code, pre-refactor): full Vitest suite 534/534 PASS including existing `WarbowHeroActions.test.tsx`. The new test cases listed in acceptance criteria (no summary paragraph, row copy includes BP fields + Valid To, countdown ticks under fake timers) need to be added by dev as part of the refactor PR.
Brouie commented 2026-05-22 04:53:09 +00:00 (Migrated from gitlab.com)

mentioned in commit 261e7b474d

mentioned in commit 261e7b474dec5bc747276f361d2959a2d448a20c
Brouie commented 2026-05-22 04:53:56 +00:00 (Migrated from gitlab.com)

mentioned in merge request !394

mentioned in merge request !394
Brouie commented 2026-05-22 04:57:29 +00:00 (Migrated from gitlab.com)

Opened MR !394 — implements all 5 acceptance criteria (manual QA on live sale with multiple stealers left for reviewer). Full frontend suite 586/586 passing. Ready for review when you're free @PlasticDigits

Opened MR !394 — implements all 5 acceptance criteria (manual QA on live sale with multiple stealers left for reviewer). Full frontend suite 586/586 passing. Ready for review when you're free @PlasticDigits
PlasticDigits (Migrated from gitlab.com) closed this issue 2026-05-22 05:21:38 +00:00
PlasticDigits commented 2026-05-22 05:22:02 +00:00 (Migrated from gitlab.com)

mentioned in commit d348a7e38b

mentioned in commit d348a7e38b48ffe9f04642244d7a8134c7b49583
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/yieldomega#236
No description provided.