XP earned should scale with CHARM bought (1× at min band → 10× at 10 CHARM), not flat per buy #304
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#304
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
Player XP is perceived / documented as flat per buy (one progression tick per transaction), which rewards many small buys the same as fewer large buys. XP should scale with how much CHARM the player clears in that buy — same economic intent as
CRED_PER_CHARM_WAD(burn scales with weight) rather thanCRED_PER_BUY(flat epoch pool tranche per tx).Desired rule: at the minimum allowed CHARM band, award the base XP; at 10 CHARM (
CHARM_MAX_WAD), award up to 10× that base (integer floor, documented rounding).Example targets (band ends):
CHARM_MIN_WAD)CHARM_MAX_WAD)Formula (integer floor):
Applies to both
buy(charmWad)(DOUB) andbuyWithCred(charmWad)— XP must followcharmWadpassed into_finishBuy, notbuyCountor a flat constant.Related closed work: #250 (XP accrual), #265 (cached buy-path progression), #299 (level cap + onboarding). This issue tracks CHARM-weight scaling explicitly and end-to-end verification.
Acceptance criteria
_finishBuyawardsxpGain = ArenaXp.xpForCharm(charmWad); min band → 1 XP, max band → 10 XP; no code path awards a flat+1regardless ofcharmWad.buyandbuyWithCredproduce identical XP for the samecharmWad(only payment rail differs).XpGained(player, amount, newLevel)emits the charm-scaledamount;xp,level,xpTowardNext,xpToNextLevelreflect cumulative charm-scaled gains.+Xxpchip updates live with the CHARM slider / cleared weight (usesxpForCharm, not a constant).idx_player_xp.xp_gainedstores the eventamount; wallet statsxpisSUM(xp_gained)and matches onchainxp()after sync.INV-TIME-ARENA-XP-CHARM-SCALE(or tightenINV-TIME-ARENA-XP) with min/mid/max band table tests.Verification criteria
cd contracts && forge test --match-contract ArenaXp -vvxpForCharm(99e16)==1,xpForCharm(10e18)==10, mid-band spot checkscd contracts && forge test --match-test test_xp_ -vvtest_xp_emits_XpGained(10 CHARM → 10 XP),test_xp_buy_with_cred_same_as_doub,test_xp_max_charm_first_buycd frontend && npm test -- --run src/lib/arenaXpMath.test.tscd frontend && npm test -- --run src/pages/arena/arenaBuyProjectedEffects.test.ts+XxptracksxpForCharm(charmWad)cd indexer && cargo test arena_wallet_stats+integration_stage2XP fixturesxpaggregate matches summedXpGainedbash scripts/verify-evm-dev-wallet-seed-anvil.sh+ buy min vs max CHARMcast call TimeArena xp(address)differs by ~10× between min and max single buys;XpGainedlogamountmatchesRecommended fixes
_finishBuyusesArenaXp.xpForCharm(charmWad)— seeTimeArena.sol~L547. Remove any legacy flat-per-buy XP constant if present on deployed branches.xpForCharm(charmWadSelected)(orcharmWeightTotalWadwhen referral/presale weight bonuses apply) viaformatBuyProjectedXpLine/buildArenaBuyProjectedEffectLines.XpGained.amount→xp_gained; wallet stats must not derive XP fromCOUNT(buys).docs/product/time-arena.md/arena-v2.mdwith “per buy, scaled 1–10 by CHARM weight”.CHARM_MIN_WAD/CHARM_MAX_WADXP mapping incontracts/PARAMETERS.mdalongside CRED constants.Relevant files
Contracts
contracts/src/arena/libraries/ArenaXp.sol—xpForCharm,applyXpGain, band constantscontracts/src/arena/TimeArena.sol—_finishBuy,XpGainedemit,buy/buyWithCredcontracts/test/ArenaXp.t.sol,contracts/test/TimeArena.t.sol—test_xp_*Frontend
frontend/src/lib/arenaXpMath.ts— TS mirror ofArenaXpfrontend/src/pages/arena/arenaBuyProjectedEffects.ts— checkout+Xxpchipfrontend/src/components/ArenaXpHero.tsx— level / XP progress barfrontend/src/lib/arenaProgression.ts— level gates (#299)Indexer
indexer/src/decoder.rs—XpGaineddecodeindexer/src/persist.rs—idx_player_xpinsertindexer/src/arena_wallet_stats.rs—SUM(xp_gained)for profile APIDocs / invariants
docs/product/arena-v2.md(§ XP),docs/product/time-arena.md(§ XP)docs/testing/invariants-and-business-logic.md—INV-TIME-ARENA-XP,INV-TIME-ARENA-XP-GASskills/play-time-arena-doub/SKILL.mdNotes
min(20 + (L-1)×5, 100)per level (#250).xpTowardNextat level cap (#265, #299).CRED_PER_BUYepoch pool (still flat 35 CRED/buy) — separate from XP scaling.mentioned in commit
f0a6a6a90fmentioned in merge request !452
Implementation summary (MR !452)
CHARM-scaled XP was already wired onchain (
ArenaXp.xpForCharmin_finishBuy), frontend (arenaXpMath.ts, buy preview+Xxp), and indexer (XpGained.amount→idx_player_xp.xp_gained). MR !452 documents and verifies the full stack.Changes:
INV-TIME-ARENA-XP-CHARM-SCALE+ detail section ininvariants-and-business-logic.mdarena-v2.md,time-arena.md,PARAMETERS.md,skills/play-time-arena-doub/SKILL.mdtest_xp_min_vs_max_charm_single_buy(1 XP min band vs 10 XP max band)arenaXpMath.test.tsVerification checklist
cd contracts && forge test --match-contract ArenaXp -vv— min/mid/max bandcd contracts && forge test --match-test test_xp_ -vv— emit, CRED parity, min vs maxcd frontend && npm test -- --run src/lib/arenaXpMath.test.ts src/pages/arena/arenaBuyProjectedEffects.test.tscd indexer && cargo test arena_wallet_statscast call TimeArena xp(address)differs ~10×;XpGainedlogamountmatchesMR: https://gitlab.com/PlasticDigits/yieldomega/-/merge_requests/82
mentioned in commit
cd85e51056mentioned in merge request !475
mentioned in commit
09937b3d34