TimeArena: CRED buy at 100 CRED/CHARM + first-buy 150 CRED bonus (next epoch) #268
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#268
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?
Summary
Update TimeArena CRED-buy economics and add a one-time first-buy CRED bonus. Today
buyWithCredburns a flat 70 CRED per buy regardless of CHARM size; product requires 100 CRED per 1e18 CHARM (WAD). Separately, each wallet’s first arena buy ever (not reset by timer hard-resets or epoch rolls) should credit 150 CRED toward claimable balance for the next Last Buy epoch.Parent context: Arena v2 epic #238, Play CRED #248.
Current codebase
TimeArena.buyWithCredCRED_BUY_BURN = 70e18; accrues CHARM/XP/timers via_accrueCharmOnly; no DOUB prize routing, noepochCredPoolaccrual, no referral CRED mint.TimeArena.buy(DOUB)epochCredPool[lastBuyEpoch], referral mints 5%+5% of that tranche.PlayCredTimeArena(MINTER) mints/burns.pendingCred(user, epoch)epochCredPool[epoch] * epochCharmWad / epochCharmTotal(zero if no CHARM weight).claimCred(epoch)epochCharmWad[epoch][user].buyCount[user]INV-TIME-ARENA-CRED-BURN-BUYexpects 70 CRED;docs/product/arena-v2.mddocuments 70 CRED burn.BuywithpaidWithCred; no dedicated first-buy bonus event today.Relevant files
contracts/src/arena/TimeArena.solcontracts/src/PlayCred.solcontracts/src/interfaces/IPlayCred.solcontracts/test/TimeArena.t.soldocs/product/arena-v2.mddocs/testing/invariants-and-business-logic.mdindexer/src/decoder.rs(if new events)contracts/script/DeployDev.s.sol,DeployProduction.s.sol(no deploy change unless new immutables)Why this is needed
charmWadso CRED and DOUB buys align on CHARM intent.Constraints and guardrails
TimeArena; indexer/frontend derived only (guardrails).TimeArenaonly; no peer transfers.totalDoubRaised/epochCredPoolaccrual on CRED path unless explicitly scoped (default: unchanged).buyCount == 0before increment, or dedicatedboolset once); must not reset onlastBuyEpochhard-reset orrollPodiumEpoch._finishBuy); document if routerbuyForcounts for the buyer address only.Math.mulDiv(charmWad, 100e18, WAD)(or equivalent) for burn; revert on zero burn.nonReentranton external entrypoints; no external calls before state updates in bonus path.Recommended direction
1) Variable CRED burn (100 per CHARM)
credBurn = Math.mulDiv(charmWad, 100e18, WAD)in_buyCred.CRED_BUY_BURNconstant; addCRED_PER_CHARM_WAD = 100e18(name TBD).credBurn == 0orbalanceOf(buyer) < credBurnbefore burn.2) First-buy 150 CRED → next epoch pending
buyCount[buyer] == 0before_finishBuyincrement):lastBuyEpoch + 1(if hard-reset increments epoch in same tx, use post-resetlastBuyEpoch + 1— document chosen rule in NatSpec).mapping(uint256 => mapping(address => uint256)) epochFixedCredBonus.pendingCred(user, epoch)to returnproRata + epochFixedCredBonus[epoch][user](when user has bonus and/or weight).claimCred(epoch)to mint pro-rata + bonus, clear bonus and epoch CHARM weight as today.FirstBuyCredScheduled(address indexed buyer, uint256 indexed targetEpoch, uint256 amount)for indexer/audit.3) Docs and invariants
arena-v2.md, invariant tableINV-TIME-ARENA-CRED-BURN-BUY, addINV-TIME-ARENA-FIRST-BUY-CRED-BONUS.Acceptance criteria
buyWithCred(cw)burns exactlycw * 100e18 / 1e18(18-decimal CRED)._finishBuyschedules 150e18 CRED for next epoch per spec; second buy from same wallet does not schedule again.lastBuyEpochdoes not reset first-buy consumption flag.pendingCredandclaimCredinclude fixed bonus; claim afterepoch < lastBuyEpochworks with zero pro-rata but non-zero bonus.PlayCredremains non-transferable; no new transfer paths.forge testgreen.Test plan — functional paths
buyWithCred(1e18)buyWithCred(10e18)buyWithCred(99e16)buyCountbecomes 1pendingCred→ 0claimCredrevertspaidWithCredonBuyeventTest plan — attack vectors / abuse
PlayCredhas no hooks; keepnonReentranton arenabuyForbuyer, not router; testbuyFordoes not grant routermulDivon max CHARM (10e18) * 100e18 within uint256Verification criteria
forge test --match-contract TimeArenapasses including updated CRED tests.pendingCredforlastBuyEpoch+1shows 150e18 (or post-claim behavior documented).buyWithCredwith known balance decreases by100 * charm.Out of scope (link separately)
Depends / blocks
mentioned in issue #269
marked as related to #269
mentioned in commit
9342e71046mentioned in commit
41a911bd91Implementation complete (merged to
main)@brouie — please verify when you have a moment. Issue left open until sign-off.
Summary
buyWithCred: burnscharmWad × 100e18 / 1e18CRED (CRED_PER_CHARM_WAD); reverts on zero burn / insufficient balance._finishBuy(DOUB or CRED) schedules 150e18 CRED inepochFixedCredBonus[lastBuyEpoch + 1]after any same-tx hard-reset; emitsFirstBuyCredScheduled.pendingCred/claimCred: return/mint pro-rata pool share plus fixed bonus; bonus-only claim allowed (no CHARM weight required).epochFixedCredBonusmapping (UUPS-safe).arena-v2.md,invariants-and-business-logic.md(INV-TIME-ARENA-CRED-BURN-BUY,INV-TIME-ARENA-FIRST-BUY-CRED-BONUS), guardrails +skills/play-time-arena-doub/SKILL.md.Merge:
41a911bonmain.Verification checklist
cd contracts && forge test --match-contract TimeArena— 28/28 greenbuyWithCred(1e18)burns exactly 100e18 CREDbuyWithCred(10e18)burns 1000e18 CREDbuyWithCred(99e16)burns 99e18 CRED (min CHARM band)epochFixedCredBonus[lastBuyEpoch+1][wallet] == 150e18lastBuyEpoch + 1pendingCred/claimCredinclude bonus; claim clears bonus + epoch CHARM weightclaimCredreverts whileepoch >= lastBuyEpochbuyCount/ first-buy flag not reset on epoch roll (seetest_first_buy_flag_survives_epoch_roll)Out of scope (unchanged)
FirstBuyCredScheduled(optional follow-up)mentioned in commit
84ba60048amentioned in issue #248
mentioned in commit
096c6f953bQA verification complete (GitLab #268)
Verified on
main@096c6f9in worktreeissue/268-verify.What was verified
Onchain (already merged in
41a911b; re-verified on currentmain):buyWithCred(cw)burnscw × 100e18 / 1e18CRED (CRED_PER_CHARM_WAD)_finishBuyper wallet schedules 150e18 inepochFixedCredBonus[lastBuyEpoch + 1](post same-tx hard-reset)pendingCred/claimCredinclude pro-rata + fixed bonus; bonus-only claim worksFirstBuyCredScheduledemitted;buyCount/ first-buy flag survives epoch rollThis QA pass added:
bash scripts/verify-cred-buy-anvil.sh— fresh Anvil DeployDev smoke (burn scaling + first-buy bonus viacast)§268§268skills/play-time-arena-doub/SKILL.mdVerification checklist (all passed)
cd contracts && forge test --match-contract TimeArena— 64/64 greenbash scripts/verify-cred-buy-anvil.sh— Anvil burn + first-buy bonus smoke OKbuyWithCred(1e18)burns 100e18 CREDbuyWithCred(10e18)burns 1000e18 CREDbuyWithCred(99e16)burns 99e18 CRED (min CHARM band)test_buyWithCred_reverts_insufficient_cred)epochFixedCredBonus[lastBuyEpoch+1] == 150e18; second buy does not add another 150test_first_buy_hard_reset_targets_post_epoch)pendingCred/claimCredinclude bonus; claim clears bonus + epoch CHARM weighttest_claim_cred_bonus_only_no_charm)claimCredreverts whileepoch >= lastBuyEpochnpm test -- --run src/lib/arenaCredBurn.test.ts— 5/5 greenCRED_PER_CHARM_WAD,FIRST_BUY_CRED_BONUS,epochFixedCredBonus,FirstBuyCredScheduledOut of scope (unchanged)
FirstBuyCredScheduled— optional follow-upClosing — contract acceptance criteria and verification checklist satisfied.
mentioned in issue #257
mentioned in issue #299
mentioned in issue #300
mentioned in issue #305
marked as related to #305
mentioned in issue #309