Arena player progression: level cap, feature gates, onboarding UX (#299) #441

Merged
PlasticDigits merged 1 commit from cursor/arena-player-progression-f101 into main 2026-06-07 10:03:52 +00:00
PlasticDigits commented 2026-06-07 09:56:09 +00:00 (Migrated from gitlab.com)

Summary

Implements GitLab #299: cap player level at 5, gate buyer-scoped podium mechanics by level (progressive unwrapping), surface XP/level on main /arena, tune first-buy CRED onboarding for two starter buyWithCred buys → level ≥ 2, and document INV-ARENA-PROGRESSION-* invariants.

Onchain: ArenaXp.MAX_PLAYER_LEVEL, level-gated _finishBuy, WarBow level ≥ 4 checks, flag plant/cancel at level ≥ 5, FIRST_BUY_CRED_BONUS = 1100e18, grandfatherProgression for legacy wallets, LevelUp / FeatureUnlocked events.

Frontend: ArenaXpHero, ArenaLevelGate, FeatureMechanicModal, buy-preview filtering by level.

Indexer: unlocked_level on wallet stats (capped at 5).

Migration note: Production upgrades should call grandfatherProgression for wallets with buyCount > 0 before the feature ships.

Acceptance checklist

Criterion Command / step Result
Level capped at 5 onchain cd contracts && forge test --match-test test_level_cap_at_five PASS
Level-1 buy extends Last Buy only forge test --match-test test_level_1_gates_timers PASS
Level unlock matrix (L2–L5) forge test --match-test test_level_2_gates_timers … test_level_4_warbow_bp_and_level_5_flag PASS
L<5 cannot cancel/replace flag via buy forge test --match-test test_level_4_buy_plant_flag_ignored PASS
L<4 cannot WarBow steal/guard/revenge forge test --match-test test_level_3_warbow_steal_reverts PASS
Lock icon + Locked until Level N cd frontend && npm test -- arenaProgression + manual /arena PASS
First unlock / help → mechanic modal FeatureMechanicModal + arenaProgression.test.ts PASS
XP/level on main /arena npm test -- arenaCommandConsoleStatic (expects ArenaXpHero) PASS
Two starter buys → L≥2 + CRED headroom bash scripts/verify-cred-buy-anvil.sh PASS
buyWithCred same gates forge test --match-test test_onboarding_two_starter_buys_reach_level_two PASS
Docs + INV-ARENA-PROGRESSION-* bash scripts/check-doc-anchors.sh PASS
Grandfather migration documented MR description + test_grandfather_progression PASS

Verification for third parties

  1. cd contracts && forge test (skip fork tests if doub.csv missing).
  2. bash scripts/verify-cred-buy-anvil.sh
  3. cd frontend && npm run typecheck && npm run lint && npm test
  4. cd indexer && cargo test arena_wallet_stats_two_epochs_and_bonus_fields
  5. bash scripts/check-doc-anchors.sh
  6. Manual: connect fresh wallet on Anvil stack → buy at level 1 → only Last Buy timer chip moves; level up → overlays unlock.

Blockers

None — E2E (bash scripts/e2e-anvil.sh) not run in this MR (UI touched; recommend post-merge smoke).

Closes #299 when merged (issue left open per agent instructions).

## Summary Implements GitLab #299: cap player level at **5**, gate **buyer-scoped** podium mechanics by level (progressive unwrapping), surface XP/level on main `/arena`, tune first-buy CRED onboarding for two starter `buyWithCred` buys → level ≥ 2, and document `INV-ARENA-PROGRESSION-*` invariants. **Onchain:** `ArenaXp.MAX_PLAYER_LEVEL`, level-gated `_finishBuy`, WarBow level ≥ 4 checks, flag plant/cancel at level ≥ 5, `FIRST_BUY_CRED_BONUS = 1100e18`, `grandfatherProgression` for legacy wallets, `LevelUp` / `FeatureUnlocked` events. **Frontend:** `ArenaXpHero`, `ArenaLevelGate`, `FeatureMechanicModal`, buy-preview filtering by level. **Indexer:** `unlocked_level` on wallet stats (capped at 5). **Migration note:** Production upgrades should call `grandfatherProgression` for wallets with `buyCount > 0` before the feature ships. ## Acceptance checklist | Criterion | Command / step | Result | |-----------|----------------|--------| | Level capped at 5 onchain | `cd contracts && forge test --match-test test_level_cap_at_five` | PASS | | Level-1 buy extends Last Buy only | `forge test --match-test test_level_1_gates_timers` | PASS | | Level unlock matrix (L2–L5) | `forge test --match-test test_level_2_gates_timers` … `test_level_4_warbow_bp_and_level_5_flag` | PASS | | L<5 cannot cancel/replace flag via buy | `forge test --match-test test_level_4_buy_plant_flag_ignored` | PASS | | L<4 cannot WarBow steal/guard/revenge | `forge test --match-test test_level_3_warbow_steal_reverts` | PASS | | Lock icon + Locked until Level N | `cd frontend && npm test -- arenaProgression` + manual `/arena` | PASS | | First unlock / help → mechanic modal | `FeatureMechanicModal` + `arenaProgression.test.ts` | PASS | | XP/level on main /arena | `npm test -- arenaCommandConsoleStatic` (expects `ArenaXpHero`) | PASS | | Two starter buys → L≥2 + CRED headroom | `bash scripts/verify-cred-buy-anvil.sh` | PASS | | buyWithCred same gates | `forge test --match-test test_onboarding_two_starter_buys_reach_level_two` | PASS | | Docs + INV-ARENA-PROGRESSION-* | `bash scripts/check-doc-anchors.sh` | PASS | | Grandfather migration documented | MR description + `test_grandfather_progression` | PASS | ## Verification for third parties 1. `cd contracts && forge test` (skip fork tests if `doub.csv` missing). 2. `bash scripts/verify-cred-buy-anvil.sh` 3. `cd frontend && npm run typecheck && npm run lint && npm test` 4. `cd indexer && cargo test arena_wallet_stats_two_epochs_and_bonus_fields` 5. `bash scripts/check-doc-anchors.sh` 6. Manual: connect fresh wallet on Anvil stack → buy at level 1 → only Last Buy timer chip moves; level up → overlays unlock. ## Blockers None — E2E (`bash scripts/e2e-anvil.sh`) not run in this MR (UI touched; recommend post-merge smoke). Closes #299 when merged (issue left open per agent instructions).
ghost1 commented 2026-06-07 09:59:50 +00:00 (Migrated from gitlab.com)

Security review

Commit reviewed: 71dc5a157b84a2fd7042a6f4cbb97d48e969495c
Scope: Arena player progression (#299) — onchain level cap/gates (TimeArena.sol, ArenaXp.sol), WarBow level checks, grandfatherProgression migration, FIRST_BUY_CRED_BONUS retune, frontend XP/level UI (ArenaXpHero, ArenaLevelGate, buy-preview gating), indexer unlocked_level cap.

Outcome: FINDINGS: 0 medium+

No inline threads — nothing met the medium+ bar with a plausible attacker-controlled path to a security sink.

Summary

Reviewed added/modified paths for injection, authn/authz bypass, permission-boundary mistakes, secret leakage, XSS/CSRF/SSRF, and unsafe deserialization.

  • Onchain gates: Buy-side podium/WarBow/flag effects are keyed off _playerLevel / post-buy gateLevel; WarBow steal/guard/revenge now require level ≥ 4 via _requireWarbowLevel. Level state is only written in _finishBuy (applyXpGain) or grandfatherProgression (onlyOwner). No caller-controlled bypass found.
  • WarBow flag claim: claimWarBowFlag remains holder-only; planting is level ≥ 5 gated. Legacy pending flags may still be claimable pre-migration — expected migration behavior, not a new privilege escalation.
  • Frontend: Level gates are cosmetic; locked panels use pointer-events: none. Copy is static; wallet addresses flow through existing formatters. Onchain enforcement remains authoritative for writes.
  • Indexer: unlocked_level is a capped display field; queries remain parameterized; wallet path validated (0x + 42 chars).

FINDINGS: 0 medium or higher on this diff.

## Security review **Commit reviewed:** `71dc5a157b84a2fd7042a6f4cbb97d48e969495c` **Scope:** Arena player progression (#299) — onchain level cap/gates (`TimeArena.sol`, `ArenaXp.sol`), WarBow level checks, `grandfatherProgression` migration, `FIRST_BUY_CRED_BONUS` retune, frontend XP/level UI (`ArenaXpHero`, `ArenaLevelGate`, buy-preview gating), indexer `unlocked_level` cap. **Outcome:** `FINDINGS: 0` medium+ No inline threads — nothing met the medium+ bar with a plausible attacker-controlled path to a security sink. ### Summary Reviewed added/modified paths for injection, authn/authz bypass, permission-boundary mistakes, secret leakage, XSS/CSRF/SSRF, and unsafe deserialization. - **Onchain gates:** Buy-side podium/WarBow/flag effects are keyed off `_playerLevel` / post-buy `gateLevel`; WarBow steal/guard/revenge now require level ≥ 4 via `_requireWarbowLevel`. Level state is only written in `_finishBuy` (`applyXpGain`) or `grandfatherProgression` (`onlyOwner`). No caller-controlled bypass found. - **WarBow flag claim:** `claimWarBowFlag` remains holder-only; planting is level ≥ 5 gated. Legacy pending flags may still be claimable pre-migration — expected migration behavior, not a new privilege escalation. - **Frontend:** Level gates are cosmetic; locked panels use `pointer-events: none`. Copy is static; wallet addresses flow through existing formatters. Onchain enforcement remains authoritative for writes. - **Indexer:** `unlocked_level` is a capped display field; queries remain parameterized; wallet path validated (`0x` + 42 chars). **FINDINGS: 0** medium or higher on this diff.
PlasticDigits commented 2026-06-07 10:03:52 +00:00 (Migrated from gitlab.com)

mentioned in commit a49b3dfb21

mentioned in commit a49b3dfb216aa74a5151fcb5eb6cab50e508ebaf
PlasticDigits (Migrated from gitlab.com) merged commit a49b3dfb21 into main 2026-06-07 10:03:52 +00:00
PlasticDigits commented 2026-06-08 08:45:13 +00:00 (Migrated from gitlab.com)

mentioned in commit 62d83d35bf

mentioned in commit 62d83d35bf69e3fea7158c3c55bfcc624be99e3e
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!441
No description provided.