Contracts: Play CRED ledger, epoch CHARM, pro-rata CRED yield, claim on Last Buy reset #248

Closed
opened 2026-05-27 07:07:17 +00:00 by PlasticDigits · 6 comments
PlasticDigits commented 2026-05-27 07:07:17 +00:00 (Migrated from gitlab.com)

Context

Play CRED non-transferable token, epoch CHARM, and CRED claim flow. Parent epic: #238.

Relevant files

  • New: contracts/src/PlayCred.sol
  • contracts/src/TimeArena.sol — epoch CHARM mappings charmWad[epoch][user]
  • New: contracts/src/interfaces/IPlayCred.sol

Acceptance criteria

  • PlayCred — no transfer; MINTER_ROLE for TimeArena + admin grantor
  • Optional CredGrantor contract admin can authorize
  • buyWithCred(charmWad) burns 70 CRED from buyer; same min/max CHARM rules
  • Each DOUB buy accrues 35 CRED to distribute: pro-rata by epoch CHARM weight
  • claimCred(epoch) callable after Last Buy epoch ends; zeros charmWad[epoch][user]; transfers accrued CRED
  • Buys still accrue CHARM into current Last Buy epoch (for CRED weighting)

Verification checklist

  • Forge: two holders 1:2 CHARM → 35 CRED splits correctly
  • Claim zeros epoch CHARM; cannot double-claim
  • CRED buy respects charm min/max
## Context Play CRED non-transferable token, epoch CHARM, and CRED claim flow. Parent epic: #238. ## Relevant files - New: `contracts/src/PlayCred.sol` - `contracts/src/TimeArena.sol` — epoch CHARM mappings `charmWad[epoch][user]` - New: `contracts/src/interfaces/IPlayCred.sol` ## Acceptance criteria - [ ] `PlayCred` — no transfer; `MINTER_ROLE` for TimeArena + admin grantor - [ ] Optional `CredGrantor` contract admin can authorize - [ ] `buyWithCred(charmWad)` burns **70 CRED** from buyer; same min/max CHARM rules - [ ] Each DOUB buy accrues **35 CRED** to distribute: pro-rata by epoch CHARM weight - [ ] `claimCred(epoch)` callable after Last Buy epoch ends; zeros `charmWad[epoch][user]`; transfers accrued CRED - [ ] Buys still accrue **CHARM** into current Last Buy epoch (for CRED weighting) ## Verification checklist - [ ] Forge: two holders 1:2 CHARM → 35 CRED splits correctly - [ ] Claim zeros epoch CHARM; cannot double-claim - [ ] CRED buy respects charm min/max
PlasticDigits commented 2026-05-27 07:07:18 +00:00 (Migrated from gitlab.com)

marked as related to #238

marked as related to #238
PlasticDigits commented 2026-05-27 07:08:00 +00:00 (Migrated from gitlab.com)

mentioned in issue #238

mentioned in issue #238
PlasticDigits commented 2026-05-28 13:58:41 +00:00 (Migrated from gitlab.com)

Implementation summary

  • PlayCred.sol, epoch CHARM mappings, buyWithCred, claimCred, 35 CRED pool per DOUB buy.

Acceptance criteria

  • PlayCred non-transferable, MINTER on TimeArena
  • buyWithCred burns 70 CRED
  • Pro-rata CRED accrual + claim after epoch

Verification checklist

  • test_cred_pro_rata_claim, test_buy_with_cred
## Implementation summary - `PlayCred.sol`, epoch CHARM mappings, `buyWithCred`, `claimCred`, 35 CRED pool per DOUB buy. ## Acceptance criteria - [x] PlayCred non-transferable, MINTER on TimeArena - [x] `buyWithCred` burns 70 CRED - [x] Pro-rata CRED accrual + claim after epoch ## Verification checklist - [x] `test_cred_pro_rata_claim`, `test_buy_with_cred`
PlasticDigits commented 2026-05-29 08:14:57 +00:00 (Migrated from gitlab.com)

mentioned in issue #268

mentioned in issue #268
PlasticDigits commented 2026-05-30 14:03:58 +00:00 (Migrated from gitlab.com)

mentioned in commit 89682a35f6

mentioned in commit 89682a35f6c75e050e76da9ff6c18ec3351dc11a
PlasticDigits commented 2026-05-30 14:04:04 +00:00 (Migrated from gitlab.com)

Verification complete (#248)

Verified Play CRED ledger, epoch CHARM weighting, pro-rata CRED yield, and claimCred on Last Buy epoch reset. Worktree: issue/248-play-cred-verify → merged to main @ 89682a3.

What was verified

Criterion Result Evidence
PlayCred non-transferable; MINTER_ROLE for TimeArena ✅ PlayCred.sol, PlayCred.t.sol::test_non_transferable, deploy wiring in TimeArena.t.sol setUp
Optional CredGrantor ⏭️ N/A (optional; not implemented — documented in docs/product/time-arena.md)
buyWithCred burns CRED; same CHARM min/max ✅ 100 CRED / 1e18 CHARM per #268 (supersedes issue-body “70 CRED” draft); test_buy_with_cred, test_buyWithCred_reverts_charm_bounds
DOUB buy accrues 35 CRED to epoch pool ✅ test_cred_accrue_on_doub_buy
claimCred(epoch) after epoch ends; zeros CHARM; mints pro-rata ✅ claimCred in TimeArena.sol, test_cred_pro_rata_claim
Buys accrue CHARM into current Last Buy epoch ✅ _accrueCharmAndCred / _accrueCharmOnly use lastBuyEpoch

Added in this verification pass

  • PlayCred.t.sol — non-transfer + minter role guards
  • test_cred_pro_rata_exact_1_2_split — two DOUB buyers at 1:2 CHARM split 70 CRED pool (≤1 wei rounding dust)
  • test_claimCred_cannot_double_claim
  • test_buyWithCred_reverts_charm_bounds
  • Invariant crosslinks: INV-PLAY-CRED-NON-TRANSFER, expanded INV-TIME-ARENA-CRED-* in docs/testing/invariants-and-business-logic.md
  • Play skill: Play CRED yield + claim section in skills/play-time-arena-doub/SKILL.md

Manual verification checklist

  • cd contracts && forge test --match-contract "TimeArenaTest|PlayCredTest" — all green
  • PlayCred.transfer / transferFrom revert with "PlayCred: non-transferable"
  • Two wallets DOUB-buy at 1:2 CHARM in same epoch → claimCred mints ~23.33 / ~46.67 CRED from 70 CRED pool
  • Second claimCred for same epoch reverts "TimeArena: nothing to claim"
  • buyWithCred below 0.99 CHARM or above 10 CHARM reverts "TimeArena: charm bounds"
  • buyWithCred accrues epoch CHARM but does not increment epochCredPool

All automated criteria from the issue body and verification checklist pass. Closing.

## Verification complete (#248) Verified Play CRED ledger, epoch CHARM weighting, pro-rata CRED yield, and `claimCred` on Last Buy epoch reset. Worktree: `issue/248-play-cred-verify` → merged to `main` @ `89682a3`. ### What was verified | Criterion | Result | Evidence | |-----------|--------|----------| | `PlayCred` non-transferable; `MINTER_ROLE` for TimeArena | ✅ | `PlayCred.sol`, `PlayCred.t.sol::test_non_transferable`, deploy wiring in `TimeArena.t.sol` setUp | | Optional `CredGrantor` | ⏭️ N/A (optional; not implemented — documented in `docs/product/time-arena.md`) | | | `buyWithCred` burns CRED; same CHARM min/max | ✅ | **100 CRED / 1e18 CHARM** per [#268](https://gitlab.com/PlasticDigits/yieldomega/-/issues/268) (supersedes issue-body “70 CRED” draft); `test_buy_with_cred`, `test_buyWithCred_reverts_charm_bounds` | | DOUB buy accrues **35 CRED** to epoch pool | ✅ | `test_cred_accrue_on_doub_buy` | | `claimCred(epoch)` after epoch ends; zeros CHARM; mints pro-rata | ✅ | `claimCred` in `TimeArena.sol`, `test_cred_pro_rata_claim` | | Buys accrue CHARM into current Last Buy epoch | ✅ | `_accrueCharmAndCred` / `_accrueCharmOnly` use `lastBuyEpoch` | ### Added in this verification pass - `PlayCred.t.sol` — non-transfer + minter role guards - `test_cred_pro_rata_exact_1_2_split` — two DOUB buyers at 1:2 CHARM split **70 CRED** pool (≤1 wei rounding dust) - `test_claimCred_cannot_double_claim` - `test_buyWithCred_reverts_charm_bounds` - Invariant crosslinks: `INV-PLAY-CRED-NON-TRANSFER`, expanded `INV-TIME-ARENA-CRED-*` in `docs/testing/invariants-and-business-logic.md` - Play skill: **Play CRED yield + claim** section in `skills/play-time-arena-doub/SKILL.md` ### Manual verification checklist - [ ] `cd contracts && forge test --match-contract "TimeArenaTest|PlayCredTest"` — all green - [ ] `PlayCred.transfer` / `transferFrom` revert with `"PlayCred: non-transferable"` - [ ] Two wallets DOUB-buy at 1:2 CHARM in same epoch → `claimCred` mints ~23.33 / ~46.67 CRED from 70 CRED pool - [ ] Second `claimCred` for same epoch reverts `"TimeArena: nothing to claim"` - [ ] `buyWithCred` below 0.99 CHARM or above 10 CHARM reverts `"TimeArena: charm bounds"` - [ ] `buyWithCred` accrues epoch CHARM but does **not** increment `epochCredPool` All automated criteria from the issue body and verification checklist pass. Closing.
PlasticDigits (Migrated from gitlab.com) closed this issue 2026-05-30 14:04:07 +00:00
Sign in to join this conversation.
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#248
No description provided.