Podium epoch timer should arm on first buy, not at epoch open #330
Labels
No labels
agent:fix_bugfix
agent:fix_conflicts
agent:fix_security
agent:gap_analysis
agent:implement
agent:open_issues
agents
agent:security_audit
agent:verify
area
timecurve
arena
arena-v2
audit
block:feature_review
block:security
bug
contracts
design
devops
docs
documentation
enhancement
epic
feature
frontend
indexer
low priority
megaeth
operations
ops
performance
QA
qa checklist
referrals
removal
security
smart-contracts
tech-debt
testing
time-arena
timecurve
visual-qa
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set
Reference
code/yieldomega#330
Loading…
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Problem
Per-category podium settlement timers (
podiumDeadline[cat]/podiumEpoch[cat]) currently begin counting down immediately when:startArena()runs — all four deadlines are set toblock.timestamp + podiumInitialTimerSec[cat](TimeArena.solstartArena).rollPodiumEpoch(category)completes — the rolled category’s deadline is reset toblock.timestamp + podiumInitialTimerSec[category](_rollPodiumEpoch).That means a fresh epoch can expire and autoroll (via
_autorollExpiredPodiumson buys/WarBow — #312) before any participant has bought in that epoch. The play UI, AUDIT accordion, and indexer head poll all surface a livedd:HH:MM:SScountdown from day one.Desired behavior: For each podium category, the epoch N settlement timer should not tick until the first qualifying buy has occurred in that epoch (for that category’s scoring window). Until then, display should read as not started / awaiting first buy, not a shrinking countdown.
Product clarification needed (assignee)
Confirm scope with product:
buy/buyWithCredarms all four category timers for their current epochs simultaneously.cattimer arms only on the first buy that materially participates in that category’s epoch (e.g. adds timer/score for cat 1/2, WarBow action for cat 3, Last Buy placement for cat 0).Document the chosen rule in
docs/product/arena-v2.mdbefore implementation.Acceptance criteria
startArena()orrollPodiumEpoch(cat),podiumDeadline[cat]is not a live countdown until the epoch’s first qualifying buy (per product decision above).catsets the deadline using existing extension / hard-reset / cap rules (initial timer band applies at arm time, not at epoch open).rollPodiumEpoch(cat)/_autorollExpiredPodiumscannot settle an epoch whose timer was never armed (no empty-entrant payout roll from idle countdown).deadlinestays consistent with cat 0 semantics when cat 0 uses the new arm model.GET /v1/arena/timersexposes enough state for clients to distinguish armed vs awaiting-first-buy per category (e.g. boolean flags and/or sentinel deadline handling). Schema version bump + design doc update.00:00:…counting down) until armed; then showdd:HH:MM:SScountdown.Verification checklist
cd contracts && forge test --match-contract TimeArenaTestbash scripts/verify-podium-timers-anvil.shcd indexer && cargo clippy --all-targets -- -D warnings && cargo testbash scripts/verify-podium-live-anvil.shcd frontend && npm run typecheck && npm testcurl -s http://127.0.0.1:3100/v1/arena/timers | jq/and/arena/protocolRecommended fixes
1. Contracts (canonical)
Introduce an explicit armed state per category per epoch, e.g.:
mapping(uint8 => bool) podiumTimerArmedorpodiumDeadline[cat] == type(uint256).maxas sentinel unarmed.startArena/_rollPodiumEpoch: set unarmed, notnow + initial.!armed[cat], setpodiumDeadline[cat] = block.timestamp + podiumInitialTimerSec[cat](then apply normal extension for that buy); setarmed[cat] = true.rollPodiumEpochguard: require armed and expired (replace"TimeArena: timer live"semantics)._autorollExpiredPodiumsto skip unarmed categories.PodiumTimerArmed(uint8 category, uint256 epoch)for indexer/UI.Review interaction with #312 autoroll and #247 diverging rolls.
2. Indexer
chain_timer.rs.GET /v1/arena/timerswithpodium_timer_armed: bool[](or equivalent).idx_arena_podium_epochfor audit history.useArenaProtocolPodiumAuditconsumers via API types inindexerApi.ts.3. Frontend
useTimerPodiumSlideMeta.ts,ArenaTimerChips.tsx,useArenaHeroTimer.ts: returnundefined/"awaiting first buy"when unarmed.ProtocolPodiumParamsCards.tsx: same for AUDIT accordion.4. Documentation & skills
docs/product/arena-v2.mdanddocs/product/time-arena.md.INV-TIME-ARENA-PODIUM-TIMER-ARM-*indocs/testing/invariants-and-business-logic.md.docs/testing/manual-qa-checklists.md§271.skills/play-time-arena-doub/SKILL.md,skills/play-active-time-arena/SKILL.md.Likely files to touch
Contracts
contracts/src/arena/TimeArena.solcontracts/src/arena/libraries/ArenaPodiumTimerConfig.solcontracts/test/TimeArena.t.solcontracts/PARAMETERS.mdIndexer
indexer/src/chain_timer.rsindexer/src/api_arena.rsindexer/src/decoder.rsindexer/src/persist.rs(if persisting arm events)indexer/src/arena_podium_live.rsindexer/tests/integration_stage2.rsindexer/README.mddocs/indexer/design.mdFrontend
frontend/src/lib/indexerApi.tsfrontend/src/pages/arena/useArenaHeroTimer.tsfrontend/src/pages/arena/useTimerPodiumSlideMeta.tsfrontend/src/pages/arena/ArenaTimerChips.tsxfrontend/src/pages/arena/ArenaTimerHero.tsxfrontend/src/pages/arena/useArenaProtocolPodiumAudit.tsfrontend/src/pages/arena/ProtocolPodiumParamsCards.tsxfrontend/src/pages/arena/ArenaSimplePage.tsxfrontend/src/pages/arena/arenaSimplePhase.tsArenaTimerChips.test.tsx,useArenaProtocolPodiumAudit.test.ts,arenaV2SaleSessionBridge.test.tsScripts / bots
scripts/verify-podium-timers-anvil.shscripts/verify-podium-live-anvil.shbots/timearena/src/timearena_bot/state.py(if bot gates on deadlines)Docs & skills
docs/product/arena-v2.mddocs/product/time-arena.mddocs/testing/invariants-and-business-logic.mddocs/testing/manual-qa-checklists.mddocs/frontend/arena-views.mdskills/play-time-arena-doub/SKILL.mdskills/play-active-time-arena/SKILL.mdContext / motivation
Observed on AUDIT (Time remaining per podium): epochs 0/1/2 prize pools can be non-zero while countdowns run from
startArenaor post-roll even with no buys yet in that epoch — creating pressure to roll empty leaderboards. Aligns with operator expectation that competition clock starts on participation, not on epoch index increment alone.Related: #271 (per-category timer params), #247 (diverging rolls), #312 (autoroll).
Reminder that for buys to update timer/be qualifying, the wallet has to be high enough level for the podium.
mentioned in commit
cc9a848987mentioned in merge request !504
Implementation complete — MR !504
Merge request: https://gitlab.com/PlasticDigits/yieldomega/-/merge_requests/134
Per-category podium timers (Option B) now arm on the first qualifying buy in each category, not at epoch open.
Verified (PASS)
cd contracts && forge test --match-contract TimeArenaTest— 118 testsbash scripts/verify-podium-timers-anvil.shcd indexer && cargo clippy --all-targets -- -D warnings && cargo testbash scripts/verify-podium-live-anvil.shcd frontend && npm run typecheckarenaPodiumTimerDisplay,useArenaProtocolPodiumAudit,ArenaTimerChipsSKIP (manual / stack)
npm run lint/npm testsuitecurlon running stack + Rabby UI on/and/arena/protocolIssue left open for merge via !504.
mentioned in commit
71d56404bcVerification complete — MR !504 merged
Third-party QA re-verified #330 on
mainafter merge of !504 (per-category arm-on-first-qualifying-buy, Option B).Results
cd contracts && forge test --match-contract TimeArenaTestbash scripts/verify-podium-timers-anvil.shcargo clippy --all-targets -- -D warnings && cargo testbash scripts/verify-podium-live-anvil.shnpm run typecheck+ timer unit tests (arenaPodiumTimerDisplay,useArenaProtocolPodiumAudit,ArenaTimerChips)curl -s http://127.0.0.1:3100/v1/arena/timers | jq '{podium_timer_armed, podium_deadlines_sec}'false/ zeros (schema 2.17.0)podium_timer_armed[0]=true, live deadline; cats 1–3 still unarmedhttp://127.0.0.1:5173/(fresh arena)dd:HH:MM:SScountdown/arena/protocol(accordions expanded)/after first buy1 d 00:01:56; other categories still awaitingINV-TIME-ARENA-PODIUM-TIMER-ARM,arena-v2.md, manual QA §330, play skillsHow verified
glab issue view 330 --comments+ MR !504 description for acceptance mapping.:5433).bash scripts/start-qa-local-full-stack.sh --live-sale --no-swarm --no-frontend+npm run dev; headed Playwright checks on/and/arena/protocol; on-chain buy viacast send(Anvil #0, level-gated L1 → cat 0 only).Follow-ups
verify-podium-timers-anvil.sh: first-buy step can flake whenYIELDOMEGA_DEPLOY_NO_COOLDOWN=1leavesbuyCooldownSec=1and deploy/seed txs land in the same second — consideranvil_increaseTimebefore the firstbuy(same pattern asverify-podium-live-anvil.shwarp_past_cooldown).npm run lint: unrelated pre-existingprefer-consterror inuseArenaPendingRevengeTargets.ts(#135); not blocking #330 acceptance (checklist targets typecheck + timer tests).Closing — implementation verified on main.