Implement always-live autoroll and onchain-enforced WarBow podium finalize #312

Closed
opened 2026-06-13 07:34:18 +00:00 by PlasticDigits · 18 comments
PlasticDigits commented 2026-06-13 07:34:18 +00:00 (Migrated from gitlab.com)

Parent

Gap analysis follow-up from #309.

Current codebase

  • _requireLive() blocks all buys and WarBow when block.timestamp > deadline until rollPodiumEpoch(0) (TimeArena.sol L831–835).
  • finalizeWarbowPodium(epoch, first, second, third) is onlyOwner with off-chain winner addresses; no on-chain BP ranking enforcement (TimeArena.sol L404–418).
  • WarBow epoch roll skips auto-pay; finalize pays current active pool balance.
  • Product spec (arena-v2.md) expects always-live when not paused.

Why needed

Approved: After last-buy deadline, buys/WarBow should autoroll (not block) unless paused. finalizeWarbowPodium must be replaced/enforced by on-chain autoroll with cheap ranking for up to ~10k players. Benchmark required.

Constraints / guardrails

  • Pause still blocks all actions including flag claim (docs will be fixed separately).
  • Gas budget: design must benchmark 10k-player ranking cost on Anvil (--code-size-limit 524288).
  • UUPS upgrade path; avoid breaking existing epoch/podium state.
  • Coordinate with indexer ingest for WarbowPodiumFinalized projection (#112 bundle).

Relevant files

  • contracts/src/arena/TimeArena.sol — _requireLive, rollPodiumEpoch, finalizeWarbowPodium, _updateTopThree
  • contracts/src/arena/libraries/ArenaPodiumSettlement.sol
  • contracts/test/TimeArena.t.sol
  • docs/product/arena-v2.md, docs/product/time-arena.md
  • simulations/ WarBow ranking references
  1. Remove deadline hard-block from _requireLive; trigger epoch autoroll when timer expires (in buy/WarBow path or dedicated keeper hook).
  2. Replace owner-trusted finalize with on-chain top-3 derivation from stored BP (heap/top-N or incremental ranking).
  3. Benchmark ranking with 10k synthetic players; document gas in issue/MR.
  4. Deprecate or gate finalizeWarbowPodium if autoroll supersedes it.

Acceptance criteria

  • Buys and WarBow succeed after last-buy deadline when not paused (autoroll advances epoch).
  • WarBow podium winners determined on-chain from BP rankings.
  • Gas benchmark for 10k players documented with Anvil numbers.
  • Forge tests cover autoroll trigger and ranking payout.

Test plan

  • cd contracts && forge test --match-contract TimeArena.
  • Anvil benchmark script or Forge gas snapshot with 10k player setup.
  • bash scripts/verify-podium-live-anvil.sh after indexer alignment.

Attack / abuse test plan

  • Owner cannot pick arbitrary winners post-fix.
  • Ranking manipulation: tie-break rules deterministic and tested.
  • Autoroll reentrancy: epoch roll cannot be triggered twice in one tx for double payout.

Verification criteria

  • No "TimeArena: timer expired" on buy when unpaused and autoroll enabled.
  • Benchmark results attached to MR.
  • On-chain top-3 matches brute-force sort in test harness for ≤100 players.
## Parent Gap analysis follow-up from [#309](https://gitlab.com/PlasticDigits/yieldomega/-/issues/309). ## Current codebase - `_requireLive()` blocks all buys and WarBow when `block.timestamp > deadline` until `rollPodiumEpoch(0)` (`TimeArena.sol` L831–835). - `finalizeWarbowPodium(epoch, first, second, third)` is `onlyOwner` with off-chain winner addresses; no on-chain BP ranking enforcement (`TimeArena.sol` L404–418). - WarBow epoch roll skips auto-pay; finalize pays current active pool balance. - Product spec (`arena-v2.md`) expects always-live when not paused. ## Why needed Approved: After last-buy deadline, buys/WarBow should **autoroll** (not block) unless paused. `finalizeWarbowPodium` must be replaced/enforced by on-chain autoroll with cheap ranking for up to ~10k players. Benchmark required. ## Constraints / guardrails - Pause still blocks **all** actions including flag claim (docs will be fixed separately). - Gas budget: design must benchmark 10k-player ranking cost on Anvil (`--code-size-limit 524288`). - UUPS upgrade path; avoid breaking existing epoch/podium state. - Coordinate with indexer ingest for `WarbowPodiumFinalized` projection (#112 bundle). ## Relevant files - `contracts/src/arena/TimeArena.sol` — `_requireLive`, `rollPodiumEpoch`, `finalizeWarbowPodium`, `_updateTopThree` - `contracts/src/arena/libraries/ArenaPodiumSettlement.sol` - `contracts/test/TimeArena.t.sol` - `docs/product/arena-v2.md`, `docs/product/time-arena.md` - `simulations/` WarBow ranking references ## Recommended direction 1. Remove deadline hard-block from `_requireLive`; trigger epoch autoroll when timer expires (in buy/WarBow path or dedicated keeper hook). 2. Replace owner-trusted finalize with on-chain top-3 derivation from stored BP (heap/top-N or incremental ranking). 3. Benchmark ranking with 10k synthetic players; document gas in issue/MR. 4. Deprecate or gate `finalizeWarbowPodium` if autoroll supersedes it. ## Acceptance criteria - [ ] Buys and WarBow succeed after last-buy deadline when not paused (autoroll advances epoch). - [ ] WarBow podium winners determined on-chain from BP rankings. - [ ] Gas benchmark for 10k players documented with Anvil numbers. - [ ] Forge tests cover autoroll trigger and ranking payout. ## Test plan - `cd contracts && forge test --match-contract TimeArena`. - Anvil benchmark script or Forge gas snapshot with 10k player setup. - `bash scripts/verify-podium-live-anvil.sh` after indexer alignment. ## Attack / abuse test plan - Owner cannot pick arbitrary winners post-fix. - Ranking manipulation: tie-break rules deterministic and tested. - Autoroll reentrancy: epoch roll cannot be triggered twice in one tx for double payout. ## Verification criteria - No `"TimeArena: timer expired"` on buy when unpaused and autoroll enabled. - Benchmark results attached to MR. - On-chain top-3 matches brute-force sort in test harness for ≤100 players.
PlasticDigits commented 2026-06-13 07:34:43 +00:00 (Migrated from gitlab.com)

mentioned in issue #309

mentioned in issue #309
PlasticDigits commented 2026-06-13 08:15:43 +00:00 (Migrated from gitlab.com)

mentioned in merge request !463

mentioned in merge request !463
PlasticDigits commented 2026-06-13 12:58:16 +00:00 (Migrated from gitlab.com)

mentioned in commit a80b465b34

mentioned in commit a80b465b34f0ba82622d1853026b6f5dcacf3be3
project_80561744_bot_5118c68a88bff95eacb6ab1c47c19cae commented 2026-06-13 13:03:56 +00:00 (Migrated from gitlab.com)

mentioned in commit b01baa52c6

mentioned in commit b01baa52c6e7af7945906746ef5f2804dbd50159
PlasticDigits commented 2026-06-13 13:33:07 +00:00 (Migrated from gitlab.com)

mentioned in commit a1e35f6915

mentioned in commit a1e35f6915c8f2d1ace655232272ea740f6d9181
PlasticDigits commented 2026-06-13 13:33:17 +00:00 (Migrated from gitlab.com)

Verification — GitLab #312 (agent:verify)

Independent verification on branch issue-312-autoroll-warbow-finalize (MR !463).

Acceptance criteria

Criterion Result How verified
Buys succeed after Last Buy deadline (autoroll) PASS cd contracts && forge test --match-test test_buy_autorolls_after_last_buy_deadline
WarBow succeeds after Last Buy deadline (autoroll) PASS cd contracts && forge test --match-test test_warbow_steal_autorolls_after_last_buy_deadline
WarBow winners on-chain from BP rankings PASS test_warbow_roll_auto_pays_onchain_winners; finalizeWarbowPodium reverts "TimeArena: superseded"
Gas benchmark 10k players documented PASS forge test --match-contract TimeArenaWarbowBenchmark -vv → update 368,100, roll 125,594; doc docs/testing/warbow-ranking-benchmark-312.md
Forge tests: autoroll + ranking payout PASS forge test --match-contract TimeArena — 126 tests, 0 failed
No TimeArena: timer expired on buy when unpaused PASS _requireLive() no longer checks deadline; _requireLiveAndAutoroll() rolls expired podiums
On-chain top-3 vs brute-force ≤100 PASS test_warbow_ranking_matches_brute_force
Tie-break deterministic PASS test_warbow_tie_break_lower_address_wins
Autoroll no double payout PASS test_autoroll_no_double_payout_same_tx
Owner cannot pick arbitrary winners PASS finalizeWarbowPodium always reverts
Indexer podium live (verify-podium-live-anvil.sh) SKIP Podium HTTP parity steps reach head; script exits on pre-existing arena_wallet_stats_two_epochs_and_bonus_fields failure (1000 vs 750 BP) — same on main, unrelated to #312

Pushed commit a1e35f69: skills/README.md WarBow index, docs/product/time-arena.md autoroll copy, benchmark gas range in docs/testing/warbow-ranking-benchmark-312.md.

Invariants

INV-TIME-ARENA-AUTOROLL-312, INV-TIME-ARENA-WARBOW-RANK-312, updated INV-TIME-ARENA-WARBOW-EPOCH-RESET — present in docs/testing/invariants-and-business-logic.md.

Follow-ups

  • Merge MR !463.
  • Indexer durable WarbowPodiumFinalized projection (#112 bundle).
  • Fix pre-existing arena_wallet_stats_two_epochs_and_bonus_fields expectation (out of #312 scope).
  • Deprecate frontend warbowLeaderboardFinalizeAutofill admin tooling.

Issue left open pending MR merge.

## Verification — GitLab #312 (agent:verify) Independent verification on branch `issue-312-autoroll-warbow-finalize` ([MR !463](https://gitlab.com/PlasticDigits/yieldomega/-/merge_requests/93)). ### Acceptance criteria | Criterion | Result | How verified | |-----------|--------|--------------| | Buys succeed after Last Buy deadline (autoroll) | **PASS** | `cd contracts && forge test --match-test test_buy_autorolls_after_last_buy_deadline` | | WarBow succeeds after Last Buy deadline (autoroll) | **PASS** | `cd contracts && forge test --match-test test_warbow_steal_autorolls_after_last_buy_deadline` | | WarBow winners on-chain from BP rankings | **PASS** | `test_warbow_roll_auto_pays_onchain_winners`; `finalizeWarbowPodium` reverts `"TimeArena: superseded"` | | Gas benchmark 10k players documented | **PASS** | `forge test --match-contract TimeArenaWarbowBenchmark -vv` → update **368,100**, roll **125,594**; doc [`docs/testing/warbow-ranking-benchmark-312.md`](docs/testing/warbow-ranking-benchmark-312.md) | | Forge tests: autoroll + ranking payout | **PASS** | `forge test --match-contract TimeArena` — **126** tests, 0 failed | | No `TimeArena: timer expired` on buy when unpaused | **PASS** | `_requireLive()` no longer checks `deadline`; `_requireLiveAndAutoroll()` rolls expired podiums | | On-chain top-3 vs brute-force ≤100 | **PASS** | `test_warbow_ranking_matches_brute_force` | | Tie-break deterministic | **PASS** | `test_warbow_tie_break_lower_address_wins` | | Autoroll no double payout | **PASS** | `test_autoroll_no_double_payout_same_tx` | | Owner cannot pick arbitrary winners | **PASS** | `finalizeWarbowPodium` always reverts | | Indexer podium live (`verify-podium-live-anvil.sh`) | **SKIP** | Podium HTTP parity steps reach head; script exits on pre-existing `arena_wallet_stats_two_epochs_and_bonus_fields` failure (**1000** vs **750** BP) — same on `main`, unrelated to #312 | ### Doc cross-links (verify loop) Pushed commit `a1e35f69`: `skills/README.md` WarBow index, `docs/product/time-arena.md` autoroll copy, benchmark gas range in `docs/testing/warbow-ranking-benchmark-312.md`. ### Invariants `INV-TIME-ARENA-AUTOROLL-312`, `INV-TIME-ARENA-WARBOW-RANK-312`, updated `INV-TIME-ARENA-WARBOW-EPOCH-RESET` — present in `docs/testing/invariants-and-business-logic.md`. ### Follow-ups - Merge [MR !463](https://gitlab.com/PlasticDigits/yieldomega/-/merge_requests/93). - Indexer durable `WarbowPodiumFinalized` projection ([#112](https://gitlab.com/PlasticDigits/yieldomega/-/issues/112) bundle). - Fix pre-existing `arena_wallet_stats_two_epochs_and_bonus_fields` expectation (out of #312 scope). - Deprecate frontend `warbowLeaderboardFinalizeAutofill` admin tooling. Issue left **open** pending MR merge.
PlasticDigits commented 2026-06-14 04:57:09 +00:00 (Migrated from gitlab.com)

Verify new wallet when top 6 already filled can enter top 6

Verify new wallet when top 6 already filled can enter top 6
PlasticDigits commented 2026-06-14 05:02:48 +00:00 (Migrated from gitlab.com)

mentioned in commit 082d27f3a0

mentioned in commit 082d27f3a08929eca7e48c992cafd35dcf5827e9
PlasticDigits commented 2026-06-14 05:08:59 +00:00 (Migrated from gitlab.com)

mentioned in commit e84483343f

mentioned in commit e84483343f723b70071161455ef0d23813b62ef9
PlasticDigits commented 2026-06-14 05:33:23 +00:00 (Migrated from gitlab.com)

mentioned in commit 0388c86b3b

mentioned in commit 0388c86b3b4e7bec991356513de6c04ad168f408
PlasticDigits commented 2026-06-14 05:34:02 +00:00 (Migrated from gitlab.com)

mentioned in merge request !484

mentioned in merge request !484
PlasticDigits commented 2026-06-14 05:46:13 +00:00 (Migrated from gitlab.com)

mentioned in commit 862964dbc7

mentioned in commit 862964dbc72db7b7fb78fb31451e989b7184ed9e
PlasticDigits commented 2026-06-14 14:14:58 +00:00 (Migrated from gitlab.com)

Verification — GitLab #312 (agent:verify)

Independent verification on main after MR !463 merge (862964db).

Acceptance criteria

Criterion Result How verified
Buys succeed after Last Buy deadline (autoroll) PASS cd contracts && forge test --match-test test_buy_autorolls_after_last_buy_deadline
WarBow succeeds after Last Buy deadline (autoroll) PASS cd contracts && forge test --match-test test_warbow_steal_autorolls_after_last_buy_deadline
WarBow winners on-chain from BP rankings PASS test_warbow_roll_auto_pays_onchain_winners; finalizeWarbowPodium reverts "TimeArena: superseded"
Gas benchmark 10k players documented PASS forge test --match-contract TimeArenaWarbowBenchmark -vv → update 466,535, roll 127,536; doc docs/testing/warbow-ranking-benchmark-312.md
Forge tests: autoroll + ranking payout PASS cd contracts && forge test --match-contract TimeArena — 137 tests (incl. fork/router suites), 0 failed
No TimeArena: timer expired on buy when unpaused PASS _requireLive() checks only arenaStart + paused; _requireLiveAndAutoroll() rolls expired podiums
On-chain top-3 vs brute-force ≤100 PASS test_warbow_ranking_matches_brute_force
Tie-break deterministic PASS test_warbow_tie_break_lower_address_wins
Autoroll no double payout PASS test_autoroll_no_double_payout_same_tx
Owner cannot pick arbitrary winners PASS finalizeWarbowPodium always reverts; test_finalize_warbow_podium_reverts_*
Indexer podium live (verify-podium-live-anvil.sh) PASS bash scripts/verify-podium-live-anvil.sh — integration_stage2 4/4, live_rows=12

Comment follow-up (2026-06-14): new wallet enters top-6 when buffer full

Check Result How verified
Untracked wallet enters ≤6 merge set when global top-3 + off-podium buffer are full PASS test_warbow_off_podium_tie_break_promotes_to_global — greg untracked (battlePoints == 0) with alice/bob/carol/d/e/f occupying six slots; first WarBow buy promotes greg into global top-3 via off-podium merge
Higher-BP new entrant displaces weaker podium slot PASS test_warbow_higher_bp_buy_enters_podium

Invariants

INV-TIME-ARENA-AUTOROLL-312, INV-TIME-ARENA-WARBOW-RANK-312, updated INV-TIME-ARENA-WARBOW-EPOCH-RESET — present in docs/testing/invariants-and-business-logic.md.

Follow-ups

  • Indexer durable WarbowPodiumFinalized projection (#112 bundle).
  • Deprecate frontend warbowLeaderboardFinalizeAutofill admin tooling.

Closing — implementation merged and verified on main.

## Verification — GitLab #312 (agent:verify) Independent verification on **`main`** after [MR !463](https://gitlab.com/PlasticDigits/yieldomega/-/merge_requests/93) merge (`862964db`). ### Acceptance criteria | Criterion | Result | How verified | |-----------|--------|--------------| | Buys succeed after Last Buy deadline (autoroll) | **PASS** | `cd contracts && forge test --match-test test_buy_autorolls_after_last_buy_deadline` | | WarBow succeeds after Last Buy deadline (autoroll) | **PASS** | `cd contracts && forge test --match-test test_warbow_steal_autorolls_after_last_buy_deadline` | | WarBow winners on-chain from BP rankings | **PASS** | `test_warbow_roll_auto_pays_onchain_winners`; `finalizeWarbowPodium` reverts `"TimeArena: superseded"` | | Gas benchmark 10k players documented | **PASS** | `forge test --match-contract TimeArenaWarbowBenchmark -vv` → update **466,535**, roll **127,536**; doc [`docs/testing/warbow-ranking-benchmark-312.md`](docs/testing/warbow-ranking-benchmark-312.md) | | Forge tests: autoroll + ranking payout | **PASS** | `cd contracts && forge test --match-contract TimeArena` — **137** tests (incl. fork/router suites), 0 failed | | No `TimeArena: timer expired` on buy when unpaused | **PASS** | `_requireLive()` checks only `arenaStart` + `paused`; `_requireLiveAndAutoroll()` rolls expired podiums | | On-chain top-3 vs brute-force ≤100 | **PASS** | `test_warbow_ranking_matches_brute_force` | | Tie-break deterministic | **PASS** | `test_warbow_tie_break_lower_address_wins` | | Autoroll no double payout | **PASS** | `test_autoroll_no_double_payout_same_tx` | | Owner cannot pick arbitrary winners | **PASS** | `finalizeWarbowPodium` always reverts; `test_finalize_warbow_podium_reverts_*` | | Indexer podium live (`verify-podium-live-anvil.sh`) | **PASS** | `bash scripts/verify-podium-live-anvil.sh` — `integration_stage2` 4/4, `live_rows=12` | ### Comment follow-up (2026-06-14): new wallet enters top-6 when buffer full | Check | Result | How verified | |-------|--------|--------------| | Untracked wallet enters ≤6 merge set when global top-3 + off-podium buffer are full | **PASS** | `test_warbow_off_podium_tie_break_promotes_to_global` — greg untracked (`battlePoints == 0`) with alice/bob/carol/d/e/f occupying six slots; first WarBow buy promotes greg into global top-3 via off-podium merge | | Higher-BP new entrant displaces weaker podium slot | **PASS** | `test_warbow_higher_bp_buy_enters_podium` | ### Invariants `INV-TIME-ARENA-AUTOROLL-312`, `INV-TIME-ARENA-WARBOW-RANK-312`, updated `INV-TIME-ARENA-WARBOW-EPOCH-RESET` — present in `docs/testing/invariants-and-business-logic.md`. ### Follow-ups - Indexer durable `WarbowPodiumFinalized` projection ([#112](https://gitlab.com/PlasticDigits/yieldomega/-/issues/112) bundle). - Deprecate frontend `warbowLeaderboardFinalizeAutofill` admin tooling. Closing — implementation merged and verified on `main`.
PlasticDigits (Migrated from gitlab.com) closed this issue 2026-06-14 14:14:59 +00:00
PlasticDigits commented 2026-06-16 05:49:43 +00:00 (Migrated from gitlab.com)

mentioned in issue #330

mentioned in issue #330
PlasticDigits commented 2026-06-25 14:28:40 +00:00 (Migrated from gitlab.com)

mentioned in issue #342

mentioned in issue #342
PlasticDigits commented 2026-06-25 20:07:24 +00:00 (Migrated from gitlab.com)

mentioned in issue #349

mentioned in issue #349
PlasticDigits commented 2026-06-25 20:07:33 +00:00 (Migrated from gitlab.com)

mentioned in issue #353

mentioned in issue #353
PlasticDigits commented 2026-06-26 03:50:38 +00:00 (Migrated from gitlab.com)

mentioned in merge request !524

mentioned in merge request !524
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#312
No description provided.