Contracts: per-podium timer params (extension, initial, hard-reset bands) #271
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#271
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?
Context
GitLab #247 landed independent
podiumDeadline[4]/podiumEpoch[4]storage androllPodiumEpoch, but all four categories still share one set of timer parameters at runtime:timerExtensionSec,initialTimerSec,timerCapSecTIMER_RESET_BELOW_REMAINING_SEC(780) /TIMER_RESET_TO_REMAINING_SEC(900)The product spec already defines per-podium values in
docs/product/time-arena.md(see “Onchain implementation note” — currently marked as not enforced). This issue closes that gap immediately so onchain behavior matches the spec table.Parent epic: #238.
Product target (authoritative)
86_400)780)900)43_200)240)300)64_800)510)600)172_800)3300)3600)Timer cap: default 96h (
4 × 86_400) for Last Buy today. Recommended default for this issue:timerCapSec[cat] = 4 × initialTimerSec[cat](preserves ratio; WarBow cap = 192h). Document final choice inPARAMETERS.md.Unchanged:
lastBuyEpoch/ CHARM / CRED accrual still roll only on Last Buy (cat 0) hard reset during_finishBuy, not on other podium rolls (#247).Relevant files
Contracts (primary)
contracts/src/arena/TimeArena.sol_finishBuy/_extendOtherPodiumTimers; per-category roll reset inrollPodiumEpoch; fix scoring hooks that currently use Last Buy timer deltascontracts/src/libraries/TimeMath.solextendDeadlineOrResetBelowThresholdalready parameterized)contracts/src/arena/libraries/ArenaPodiumTimerConfig.sol(recommended)TimeArenareadable)contracts/script/UUPSDeployLib.solinitializecontracts/script/DeployProduction.s.solcontracts/script/DeployDev.s.solcontracts/test/TimeArena.t.solcontracts/PARAMETERS.mdDocs & invariants
docs/product/time-arena.mddocs/product/arena-v2.mddocs/testing/invariants-and-business-logic.md.cursor/skills/yieldomega-guardrails/SKILL.mdskills/play-time-arena-doub/SKILL.mdDerived layers (follow-on in same issue or sub-issues — list for visibility)
frontend/src/lib/abis.tspodiumTimerExtensionSec(uint8), etc.)frontend/src/pages/arena/useArenaSaleSession.tstimerExtensionSecfrontend/src/lib/timeArenaBuyPreview.ts120defaultfrontend/src/pages/arena/ArenaTimerChips.tsxindexer/src/chain_timer.rsGET /v1/arena/timersfor UI previewbots/timearena/Recommended changes
1. Storage & initialization (UUPS-safe)
Append per-category arrays (do not repurpose existing scalar slots on upgraded proxies):
initialize: accept arrays (or struct[4]) validated byArenaPodiumTimerConfig.validate(...).startArena: setpodiumDeadline[i] = block.timestamp + podiumInitialTimerSec[i](categories no longer share the same initial deadline).rollPodiumEpoch(cat): reset withpodiumInitialTimerSec[cat], not globalinitialTimerSec.timerExtensionSec&initialTimerSecfor new logic; keep getters shimmed to cat 0 for one release if needed for ABI compat.2. Buy path — per-category
TimeMathRefactor
_finishBuy:hardReseton cat 0 only driveslastBuyEpoch._extendOtherPodiumTimersloop body to usepodium*Sec[c]for each category independently (each may hard-reset on its own remaining band).Return per-category
(actualSecondsAdded[c], hardReset[c])for downstream scoring.3. Fix scoring hooks (currently Last Buy–coupled)
totalEffectiveTimerSecAddedactualSecondsAdded_processDefendedStreakremainingBefore/secondsAdded_applyBuyWarBowBpclutch (remainingBefore < 30)hardReset4. Deploy defaults
Wire product table into
DeployProduction/DeployDev(env overrides e.g.ARENA_PODIUM_1_TIMER_EXTENSION_SEC). Anvil may use compressed timers only behindDeployDevguard with explicit comment — production must use spec table.5. Upgrade path
If a
TimeArenaproxy is already live with shared params: addreinitializePodiumTimers(...)(owner-only, once) or document fresh redeploy only per Arena v2 “no backwards compatibility” policy (#238). Pick one approach in implementation PR and document inPARAMETERS.md.Acceptance criteria
extension,initial,cap,resetBelow,resetTovalues onchain matching the product table (or documented dev-compressed Anvil subset).startArenaseeds different initialpodiumDeadline[i]per category.rollPodiumEpoch(cat)resets deadline to that category’s initial timer.lastBuyEpochstill increments only on Last Buy (cat 0) hard reset; unaffected by other categories’ hard resets.DeployProduction,DeployDev) andPARAMETERS.mdupdated.time-arena.mdimplementation note removed/updated;arena-v2.mdtable aligned).Verification checklist
Forge
FOUNDRY_PROFILE=ci forge test --match-contract TimeArenaTesttest_start_arena_initial_deadlines_differ_by_categorytest_multi_podium_deadline_extend— assert cat-specific deltas (+120 / +60 / +90 / +300), not uniform +120test_time_booster_hard_reset_band_240_to_300(warp near cat 1 deadline)test_warbow_bp_bonus_uses_warbow_hard_reset_not_last_buy(Last Buy extend without WarBow hard reset → no WarBow reset bonus)test_defended_streak_uses_streak_timer_not_last_buyIntegration / UI (manual or automated)
GET /v1/arena/timersshows four different initial deadlines afterstartArena/arenatimer chips show distinct countdowns at arena startDocs / agents
skills/play-time-arena-doub/SKILL.mdreferences per-podium tableOut of scope (unless blocking)
setPodiumTimerConfig— nice-to-have, not required for “immediate” spec alignment)marked as related to #238
marked as related to #247
marked as related to #240
Time booster, defended streak, and warbow clutch/bonus all should be based on last buy category timer. The podium specific timers are for making prizes distribution only not scoring
We do not need to upgrade contracts, this is part of a backwards compatibiltiy breaking full reimplementation.
mentioned in commit
9326963277Implementation landed on
main(9326963)Per-podium timer params are now enforced onchain via
ArenaPodiumTimerConfig+ per-category storage arrays onTimeArena. Product table matches time-arena.md.What changed
contracts/src/arena/libraries/ArenaPodiumTimerConfig.sol— canonical defaults + validationpodiumTimerExtensionSec[4],podiumInitialTimerSec[4],podiumTimerCapSec[4],podiumResetBelowRemainingSec[4],podiumResetToRemainingSec[4](cat-0 shims kept fortimerExtensionSec/initialTimerSec/timerCapSec)startArena: seeds different initialpodiumDeadline[i]per category_finishBuy/_extendOtherPodiumTimers: per-categoryTimeMathextension/hard-resetrollPodiumEpoch(cat): resets to that category's initial timerDeployDev/DeployProduction+UUPSDeployLib.deployTimeArenaProductionDefaultsVerification checklist
FOUNDRY_PROFILE=ci forge test --match-contract TimeArenaTest— 54 tests passstartArena, fourpodiumDeadline[i]differ (24h / 12h / 18h / 48h offsets)test_time_booster_hard_reset_band_240_to_300)lastBuyEpochstill bumps only on Last Buy hard resetDeployProduction/ AnvilDeployDevwires production table/arenatimer chips show distinct countdowns at arena start (manual/E2E)INV-TIME-ARENA-PODIUM-TIMER-PARAMS,INV-TIME-ARENA-SCORING-LAST-BUY-TIMER@brouie — please verify on your side when convenient. Leaving issue open until sign-off.
mentioned in issue #252
mentioned in commit
479448d90aQA verification complete (
479448donmain)Verified GitLab #271 per-podium timer params against the issue body, implementation comment (scoring uses Last Buy timer only; per-category timers govern prize settlement), and the verification checklist in the implementation note.
What was verified
Contracts (Forge)
FOUNDRY_PROFILE=ci forge test --match-contract TimeArenaTest— 64/64 pass, including:test_start_arena_initial_deadlines_differ_by_categorytest_multi_podium_deadline_extend(+120 / +60 / +90 / +300)test_time_booster_hard_reset_band_240_to_300test_warbow_bp_bonus_uses_last_buy_hard_reset_not_warbow_timertest_defended_streak_uses_last_buy_timer_not_other_podiumtest_last_buy_epoch_on_hard_reset_not_on_other_podium_roll#247divergence tests still pass.Anvil smoke (new)
bash scripts/verify-podium-timers-anvil.sh— freshDeployDev: distinct initialpodiumDeadline[i], product table getters, per-category buy extensions, Time Booster 240→300s hard-reset band.Docs / agents
play-time-arena-doubcrosslinks.Frontend
ArenaTimerChips.test.tsx,arenaBuyProjectedEffects.test.tspass.ArenaTimerChipsreads per-categorypodiumDeadline(indexerpodium_deadlines_secor RPC).Sign-off checklist (for re-run)
FOUNDRY_PROFILE=ci forge test --match-contract TimeArenaTestbash scripts/verify-podium-timers-anvil.shstartArena, fourpodiumDeadline[i]differ (24h / 12h / 18h / 48h)block.timestamplastBuyEpochbumps only on Last Buy hard reset/arenatimer chips show distinct secondary countdownsINV-TIME-ARENA-PODIUM-TIMER-PARAMS,INV-TIME-ARENA-SCORING-LAST-BUY-TIMERImplementation commit:
9326963. QA automation/docs:479448d.Closing — all acceptance criteria and verification items pass.
mentioned in issue #309
mentioned in issue #330
mentioned in commit
980e96f814