Referrals: flat 5 CRED per side (replace 5% of epoch CRED tranche) #272

Closed
opened 2026-05-30 14:44:46 +00:00 by PlasticDigits · 5 comments
PlasticDigits commented 2026-05-30 14:44:46 +00:00 (Migrated from gitlab.com)

Summary

Replace the current percentage-based referral Play CRED reward (5% of CRED_PER_BUY = 1.75 CRED per side) with a fixed flat bonus of 5 CRED minted to referrer and buyer on every qualifying referred buy. CRED remains immediately minted (not epoch-pooled). Parent context: Arena v2 referrals (#240), CRED-not-CHARM migration (#253).


Current codebase

Onchain (authority)

TimeArena.sol:

  • CRED_PER_BUY = 35e18 — epoch pool CRED added on every DOUB/CRED buy path that accrues charm.
  • REFERRAL_CRED_BPS = 500 — referral side uses 5% of CRED_PER_BUY, not a fixed amount.
  • _accrueCharmAndCred(buyer, charmWad, codeHash) on DOUB buys (buy, buy(charm, codeHash), router buyFor):
    • Accrues charmWad only to charmWeight (no referral CHARM bonus).
    • If codeHash != 0 and referralRegistry wired: resolves referrer via ReferralRegistry.ownerOfCode, blocks self-referral, mints each = CRED_PER_BUY × REFERRAL_CRED_BPS / 10_000 to referrer and buyer via playCred.mint, emits ReferralCredApplied(buyer, referrer, codeHash, each, each).
  • buyWithCred uses _accrueCharmOnly — no referral path today (no codeHash param).

ReferralRegistry.sol: unchanged registration model (1 CL8Y burn, codeHash → owner).

Forge coverage: TimeArena.t.sol::test_referred_buy_mints_cred_not_charm, test_self_referral_reverts assert 1.75e18 per side.

Indexer (derived)

  • Decodes ReferralCredApplied → idx_arena_referral_cred (referrer_cred, buyer_cred).
  • HTTP (schema ≥ 2.3.0): GET /v1/referrals/applied, referrer-leaderboard, wallet-cred-summary — sums referrer_cred (indexer/src/api.rs).

Frontend (derived)

Docs / invariants


Why change

Product wants a simple, legible rule: “Referred buy → 5 CRED to guide, 5 CRED to buyer, right away.”

Problems with the current 5%-of-35 design:

  1. UX/math friction — guides and buyers must understand epoch tranche (35 CRED) and BPS (500) to know they earn 1.75 CRED, not “5”.
  2. Silent coupling — if CRED_PER_BUY is retuned for epoch economics, referral payouts move unintentionally.
  3. Frontend drift — arena buy preview still speaks in BPS/CHARM-era patterns; /referrals copy references “5% of the 35 CRED mint”.
  4. Spec debt — #240 open decision #3 locked the BPS basis; this issue supersedes that decision with governance/product sign-off.

Non-goals (unless explicitly expanded in implementation):

  • Changing registration burn (still 1 CL8Y).
  • Reintroducing CHARM weight referral bonuses.
  • Changing epoch CRED_PER_BUY pool mechanics (still 35 CRED per buy into epoch pool).

Constraints & guardrails

  • Onchain authority — payout amount enforced only in TimeArena + PlayCred.mint; indexer/frontend are derived (#253).
  • AGPL — follow docs/licensing.md.
  • No CHARM inflation — referral must not increase charmWeight beyond purchased charmWad.
  • Self-referral — must still revert (TimeArena: self-referral).
  • Invalid/unregistered code — must still revert (no silent zero-code fallback).
  • Immediate mint — flat 5 CRED per side via playCred.mint, same as today (not added to epochCredPool).
  • Scope of qualifying buys — default: same as today (referred DOUB buy with non-zero codeHash). Document explicitly if buyWithCred + referral is out of scope.
  • Constant naming — prefer explicit REFERRAL_CRED_FLAT_WAD = 5e18 (or similar); remove or deprecate REFERRAL_CRED_BPS from product path (avoid dual formulas).
  • Event shape — keep ReferralCredApplied unless a breaking ABI change is justified; indexer table columns unchanged (amounts differ).
  • Supersedes — update INV-REFERRAL-253-CRED, guardrails 6f, time-arena.md decision #3, manual QA §253.
  • Third-party agents — crosslink skills/README.md / play skills if referral economics are referenced.

Relevant files

Layer Files
Contracts TimeArena.sol, TimeArena.t.sol, DevStackIntegration.t.sol
Indexer decoder.rs, persist.rs, api.rs, integration_stage2.rs
Frontend useArenaSaleSession.ts, arenaV2SaleSessionBridge.test.ts, ReferralProgramEarningsSection.tsx, ReferralLeaderboardSection.tsx, indexerApi.ts
Docs referrals.md, time-arena.md, glossary.md, invariants-and-business-logic.md, manual-qa-checklists.md, guardrails skill

  1. Contracts

    • Add uint256 public constant REFERRAL_CRED_FLAT_WAD = 5e18; (name TBD).
    • In _accrueCharmAndCred, replace Math.mulDiv(CRED_PER_BUY, REFERRAL_CRED_BPS, 10_000) with REFERRAL_CRED_FLAT_WAD for both mints and event fields.
    • Remove REFERRAL_CRED_BPS from public API or leave deprecated with NatSpec “unused; flat CRED per #___” — pick one, don’t keep both active.
    • Confirm PlayCred minter role unchanged.
  2. Forge tests

    • Update existing referral tests to expect 5e18 each side.
    • Add test: changing CRED_PER_BUY in a fork/mock does not change referral mint amount (documents decoupling).
  3. Frontend

    • Replace BPS-based buy preview with flat “+5 CRED” (read constant from chain or hardcode with ABI read of REFERRAL_CRED_FLAT_WAD).
    • Update /referrals lede/copy (“5 CRED per referred buy per side”).
  4. Indexer

    • No schema migration required if event fields unchanged; integration fixtures expecting 1.75e18 → 5e18.
    • Optional: bump x-schema-version patch + release note if response semantics documented.
  5. Docs / invariants

    • Supersede #240 decision #3 row with flat 5 CRED per side.
    • Rename or extend INV-REFERRAL-253-CRED → flat-amount invariant.

Acceptance criteria

  • On referred DOUB buy with valid codeHash: playCred.mint(referrer, 5e18) and playCred.mint(buyer, 5e18); ReferralCredApplied emits 5e18, 5e18.
  • Referral mint amount independent of CRED_PER_BUY (35 CRED epoch tranche unchanged).
  • charmWeight increases by charmWad only (no referral CHARM).
  • Self-referral and invalid code behaviors unchanged (revert).
  • No-referral buy (codeHash == 0) mints zero referral CRED.
  • Indexer persists and serves referrer_cred / buyer_cred = 5e18` on qualifying rows.
  • /referrals and /arena copy/preview show flat 5 CRED, not “5%” or “1.75”.
  • Docs + INV-REFERRAL-* + guardrails updated; #253 QA checklist revised.

Test plan — functional paths

Path Expected
DOUB buy(charm) no code Epoch +35 CRED pool; no referral mint
DOUB buy(charm, validCode) Referrer + buyer each +5 CRED mint; epoch pool still +35
DOUB buy(charm, invalidCode) Revert invalid referral
DOUB buy(charm, ownCode) Revert self-referral
Router buyFor(buyer, charm, code, flag) Referral CRED to buyer + referrer, not router
buyWithCred(charm) (if unchanged scope) No referral CRED (document)
Indexer ingest + replay Idempotent row in idx_arena_referral_cred
GET /v1/referrals/applied referrer_cred / buyer_cred = 5000000000000000000
Leaderboard / wallet summary Totals reflect 5 CRED × buy count

Automated: forge test --match-contract TimeArenaTest (referral tests), cargo test integration_stage2 (if PG URL set), npm test referral/arena session tests, Playwright referrals-surface.spec.ts.


Test plan — attack, hack & abuse vectors

Vector Mitigation to verify
Self-referral / same-wallet guide+buyer Still reverts; no double 5+5 on one wallet
Sybil: many buyer wallets, one guide Each buy pays guide 5 CRED — economic acceptance; verify no extra mint beyond once per tx
Sybil: one buyer, rotating codes Each valid code pays that guide 5 CRED; buyer always gets 5 CRED — product risk, not exploit if intentional
Unregistered / garbage codeHash Revert; no mint
Referral on zero/min buy spam Each qualifying buy mints 10 CRED total (5+5) — confirm bounded by buy cooldown + min charm; assess CRED inflation vs product
CRED mint without PlayCred minter Arena must hold minter role (DeployDev wiring test)
Indexer forged amounts UI must not invent totals; chain event is source
Frontend wrong-network buy Write gating still blocks (INV-FRONTEND-95)
Reorg / duplicate log index ON CONFLICT DO NOTHING idempotency on idx_arena_referral_cred

Document any accepted inflation tradeoff (flat 5 > old 1.75) for treasury/ops.


Verification criteria (issue close)

  • Forge referral tests green with 5e18 assertions
  • Manual or Anvil: one referred buy → wallet PlayCred.balanceOf +5 for referrer and buyer
  • Indexer row + HTTP /v1/referrals/applied show 5e18 per side
  • /referrals UI shows CRED totals consistent with indexed data
  • Docs crosslinked; superseded BPS decision noted in time-arena.md
  • No remaining product references to “5% of 35 CRED” or REFERRAL_CRED_BPS in live Arena v2 paths (except legacy TimeCurve sections)

  • Epic: #240
  • CRED-not-CHARM baseline: #253 (closed — this issue modifies payout math only)
## Summary Replace the current **percentage-based** referral Play CRED reward (**5% of `CRED_PER_BUY` = 1.75 CRED per side**) with a **fixed flat bonus of 5 CRED** minted to **referrer** and **buyer** on every qualifying referred buy. CRED remains **immediately minted** (not epoch-pooled). Parent context: Arena v2 referrals ([#240](https://gitlab.com/PlasticDigits/yieldomega/-/issues/240)), CRED-not-CHARM migration ([#253](https://gitlab.com/PlasticDigits/yieldomega/-/issues/253)). --- ## Current codebase ### Onchain (authority) [`TimeArena.sol`](contracts/src/arena/TimeArena.sol): - `CRED_PER_BUY = 35e18` — epoch pool CRED added on every DOUB/CRED buy path that accrues charm. - `REFERRAL_CRED_BPS = 500` — referral side uses **5% of `CRED_PER_BUY`**, not a fixed amount. - `_accrueCharmAndCred(buyer, charmWad, codeHash)` on **DOUB buys** (`buy`, `buy(charm, codeHash)`, router `buyFor`): - Accrues **`charmWad`** only to `charmWeight` (no referral CHARM bonus). - If `codeHash != 0` and `referralRegistry` wired: resolves referrer via `ReferralRegistry.ownerOfCode`, blocks self-referral, mints **`each = CRED_PER_BUY × REFERRAL_CRED_BPS / 10_000`** to referrer and buyer via `playCred.mint`, emits **`ReferralCredApplied(buyer, referrer, codeHash, each, each)`**. - **`buyWithCred`** uses `_accrueCharmOnly` — **no referral path today** (no `codeHash` param). [`ReferralRegistry.sol`](contracts/src/ReferralRegistry.sol): unchanged registration model (1 CL8Y burn, `codeHash → owner`). Forge coverage: [`TimeArena.t.sol::test_referred_buy_mints_cred_not_charm`](contracts/test/TimeArena.t.sol), [`test_self_referral_reverts`](contracts/test/TimeArena.t.sol) assert **1.75e18** per side. ### Indexer (derived) - Decodes **`ReferralCredApplied`** → [`idx_arena_referral_cred`](indexer/migrations/20240601000000_arena_v2.up.sql) (`referrer_cred`, `buyer_cred`). - HTTP (schema **≥ 2.3.0**): `GET /v1/referrals/applied`, `referrer-leaderboard`, `wallet-cred-summary` — sums **`referrer_cred`** ([`indexer/src/api.rs`](indexer/src/api.rs)). ### Frontend (derived) - **`/referrals`**: leaderboard + earnings from indexer CRED fields ([`ReferralProgramEarningsSection.tsx`](frontend/src/pages/referrals/ReferralProgramEarningsSection.tsx), [`ReferralLeaderboardSection.tsx`](frontend/src/pages/referrals/ReferralLeaderboardSection.tsx)). - **`/arena` buy session**: still reads onchain **`REFERRAL_CRED_BPS`** via `referralEachBpsR` and computes preview bonus as % of something ([`useArenaSaleSession.ts`](frontend/src/pages/arena/useArenaSaleSession.ts)) — **misaligned with flat CRED product intent**. ### Docs / invariants - [`docs/product/referrals.md`](docs/product/referrals.md) · [`docs/product/time-arena.md#referrals`](docs/product/time-arena.md#referrals) — documents **5% of 35 CRED**. - **`INV-REFERRAL-253-CRED`** ([`invariants-and-business-logic.md`](docs/testing/invariants-and-business-logic.md)) — encodes BPS formula. - Guardrails item **6f** ([`.cursor/skills/yieldomega-guardrails/SKILL.md`](.cursor/skills/yieldomega-guardrails/SKILL.md)). --- ## Why change Product wants a **simple, legible rule**: *“Referred buy → **5 CRED** to guide, **5 CRED** to buyer, right away.”* Problems with the current **5%-of-35** design: 1. **UX/math friction** — guides and buyers must understand epoch tranche (`35 CRED`) and BPS (`500`) to know they earn **1.75 CRED**, not “5”. 2. **Silent coupling** — if `CRED_PER_BUY` is retuned for epoch economics, referral payouts move unintentionally. 3. **Frontend drift** — arena buy preview still speaks in **BPS/CHARM-era patterns**; `/referrals` copy references “5% of the 35 CRED mint”. 4. **Spec debt** — [#240 open decision #3](docs/product/time-arena.md#resolved-open-decisions-gitlab-240) locked the BPS basis; this issue **supersedes** that decision with governance/product sign-off. **Non-goals (unless explicitly expanded in implementation):** - Changing **registration burn** (still **1 CL8Y**). - Reintroducing **CHARM weight** referral bonuses. - Changing **epoch `CRED_PER_BUY` pool** mechanics (still 35 CRED per buy into epoch pool). --- ## Constraints & guardrails - **Onchain authority** — payout amount enforced only in `TimeArena` + `PlayCred.mint`; indexer/frontend are derived ([#253](https://gitlab.com/PlasticDigits/yieldomega/-/issues/253)). - **AGPL** — follow [`docs/licensing.md`](docs/licensing.md). - **No CHARM inflation** — referral must **not** increase `charmWeight` beyond purchased `charmWad`. - **Self-referral** — must still revert (`TimeArena: self-referral`). - **Invalid/unregistered code** — must still revert (no silent zero-code fallback). - **Immediate mint** — flat 5 CRED per side via **`playCred.mint`**, same as today (not added to `epochCredPool`). - **Scope of qualifying buys** — default: **same as today** (referred **DOUB** buy with non-zero `codeHash`). Document explicitly if `buyWithCred` + referral is out of scope. - **Constant naming** — prefer explicit `REFERRAL_CRED_FLAT_WAD = 5e18` (or similar); **remove or deprecate** `REFERRAL_CRED_BPS` from product path (avoid dual formulas). - **Event shape** — keep **`ReferralCredApplied`** unless a breaking ABI change is justified; indexer table columns unchanged (amounts differ). - **Supersedes** — update **`INV-REFERRAL-253-CRED`**, guardrails **6f**, [`time-arena.md` decision #3](docs/product/time-arena.md#resolved-open-decisions-gitlab-240), manual QA §253. - **Third-party agents** — crosslink [`skills/README.md`](skills/README.md) / play skills if referral economics are referenced. --- ## Relevant files | Layer | Files | |-------|--------| | **Contracts** | [`TimeArena.sol`](contracts/src/arena/TimeArena.sol), [`TimeArena.t.sol`](contracts/test/TimeArena.t.sol), [`DevStackIntegration.t.sol`](contracts/test/DevStackIntegration.t.sol) | | **Indexer** | [`decoder.rs`](indexer/src/decoder.rs), [`persist.rs`](indexer/src/persist.rs), [`api.rs`](indexer/src/api.rs), [`integration_stage2.rs`](indexer/tests/integration_stage2.rs) | | **Frontend** | [`useArenaSaleSession.ts`](frontend/src/pages/arena/useArenaSaleSession.ts), [`arenaV2SaleSessionBridge.test.ts`](frontend/src/pages/arena/arenaV2SaleSessionBridge.test.ts), [`ReferralProgramEarningsSection.tsx`](frontend/src/pages/referrals/ReferralProgramEarningsSection.tsx), [`ReferralLeaderboardSection.tsx`](frontend/src/pages/referrals/ReferralLeaderboardSection.tsx), [`indexerApi.ts`](frontend/src/lib/indexerApi.ts) | | **Docs** | [`referrals.md`](docs/product/referrals.md), [`time-arena.md`](docs/product/time-arena.md), [`glossary.md`](docs/glossary.md), [`invariants-and-business-logic.md`](docs/testing/invariants-and-business-logic.md), [`manual-qa-checklists.md`](docs/testing/manual-qa-checklists.md), guardrails skill | --- ## Recommended direction 1. **Contracts** - Add `uint256 public constant REFERRAL_CRED_FLAT_WAD = 5e18;` (name TBD). - In `_accrueCharmAndCred`, replace `Math.mulDiv(CRED_PER_BUY, REFERRAL_CRED_BPS, 10_000)` with **`REFERRAL_CRED_FLAT_WAD`** for both mints and event fields. - Remove **`REFERRAL_CRED_BPS`** from public API **or** leave deprecated with NatSpec “unused; flat CRED per #___” — pick one, don’t keep both active. - Confirm **`PlayCred` minter role** unchanged. 2. **Forge tests** - Update existing referral tests to expect **`5e18`** each side. - Add test: changing `CRED_PER_BUY` in a fork/mock **does not** change referral mint amount (documents decoupling). 3. **Frontend** - Replace BPS-based buy preview with **flat “+5 CRED”** (read constant from chain or hardcode with ABI read of `REFERRAL_CRED_FLAT_WAD`). - Update `/referrals` lede/copy (“5 CRED per referred buy per side”). 4. **Indexer** - No schema migration required if event fields unchanged; integration fixtures expecting `1.75e18` → **`5e18`**. - Optional: bump `x-schema-version` patch + release note if response semantics documented. 5. **Docs / invariants** - Supersede [#240 decision #3](docs/product/time-arena.md#resolved-open-decisions-gitlab-240) row with **flat 5 CRED per side**. - Rename or extend **`INV-REFERRAL-253-CRED`** → flat-amount invariant. --- ## Acceptance criteria - [ ] On referred **DOUB** buy with valid `codeHash`: **`playCred.mint(referrer, 5e18)`** and **`playCred.mint(buyer, 5e18)`**; **`ReferralCredApplied`** emits **`5e18, 5e18`**. - [ ] Referral mint amount **independent** of `CRED_PER_BUY` (35 CRED epoch tranche unchanged). - [ ] **`charmWeight`** increases by **`charmWad` only** (no referral CHARM). - [ ] Self-referral and invalid code behaviors **unchanged** (revert). - [ ] No-referral buy (`codeHash == 0`) mints **zero** referral CRED. - [ ] Indexer persists and serves **`referrer_cred` / `buyer_cred` = 5e18`** on qualifying rows. - [ ] **`/referrals`** and **`/arena`** copy/preview show **flat 5 CRED**, not “5%” or “1.75”. - [ ] Docs + **`INV-REFERRAL-*`** + guardrails updated; [#253](https://gitlab.com/PlasticDigits/yieldomega/-/issues/253) QA checklist revised. --- ## Test plan — functional paths | Path | Expected | |------|----------| | DOUB `buy(charm)` no code | Epoch +35 CRED pool; **no** referral mint | | DOUB `buy(charm, validCode)` | Referrer + buyer each **+5 CRED** mint; epoch pool still +35 | | DOUB `buy(charm, invalidCode)` | Revert invalid referral | | DOUB `buy(charm, ownCode)` | Revert self-referral | | Router `buyFor(buyer, charm, code, flag)` | Referral CRED to **buyer** + **referrer**, not router | | `buyWithCred(charm)` (if unchanged scope) | **No** referral CRED (document) | | Indexer ingest + replay | Idempotent row in `idx_arena_referral_cred` | | `GET /v1/referrals/applied` | `referrer_cred` / `buyer_cred` = `5000000000000000000` | | Leaderboard / wallet summary | Totals reflect **5 CRED × buy count** | **Automated:** `forge test --match-contract TimeArenaTest` (referral tests), `cargo test integration_stage2` (if PG URL set), `npm test` referral/arena session tests, Playwright `referrals-surface.spec.ts`. --- ## Test plan — attack, hack & abuse vectors | Vector | Mitigation to verify | |--------|---------------------| | **Self-referral / same-wallet guide+buyer** | Still reverts; no double 5+5 on one wallet | | **Sybil: many buyer wallets, one guide** | Each buy pays guide **5 CRED** — economic acceptance; verify no extra mint beyond **once per tx** | | **Sybil: one buyer, rotating codes** | Each valid code pays that guide **5 CRED**; buyer always gets **5 CRED** — product risk, not exploit if intentional | | **Unregistered / garbage `codeHash`** | Revert; no mint | | **Referral on zero/min buy spam** | Each qualifying buy mints **10 CRED total** (5+5) — confirm bounded by buy cooldown + min charm; assess CRED inflation vs product | | **CRED mint without `PlayCred` minter** | Arena must hold minter role (DeployDev wiring test) | | **Indexer forged amounts** | UI must not invent totals; chain event is source | | **Frontend wrong-network buy** | Write gating still blocks (`INV-FRONTEND-95`) | | **Reorg / duplicate log index** | `ON CONFLICT DO NOTHING` idempotency on `idx_arena_referral_cred` | Document any **accepted** inflation tradeoff (flat 5 > old 1.75) for treasury/ops. --- ## Verification criteria (issue close) - [ ] Forge referral tests green with **`5e18`** assertions - [ ] Manual or Anvil: one referred buy → wallet **`PlayCred.balanceOf`** +5 for referrer and buyer - [ ] Indexer row + HTTP **`/v1/referrals/applied`** show **5e18** per side - [ ] `/referrals` UI shows CRED totals consistent with indexed data - [ ] Docs crosslinked; superseded BPS decision noted in `time-arena.md` - [ ] No remaining product references to **“5% of 35 CRED”** or **`REFERRAL_CRED_BPS`** in live Arena v2 paths (except legacy TimeCurve sections) --- ## Related issues - Epic: [#240](https://gitlab.com/PlasticDigits/yieldomega/-/issues/240) - CRED-not-CHARM baseline: [#253](https://gitlab.com/PlasticDigits/yieldomega/-/issues/253) (closed — this issue **modifies** payout math only)
PlasticDigits commented 2026-05-30 14:49:29 +00:00 (Migrated from gitlab.com)

mentioned in commit dbbfeba2df

mentioned in commit dbbfeba2df4c9c4f3c04bc7a62c25e56214ee648
PlasticDigits commented 2026-05-30 14:50:02 +00:00 (Migrated from gitlab.com)

Implementation landed on main (dbbfeba)

Replaced percentage-based referral Play CRED (5% of CRED_PER_BUY → 1.75 CRED/side) with a flat 5 CRED per side on qualifying referred DOUB buys (#272).

What changed

Contracts

  • TimeArena: added REFERRAL_CRED_FLAT_WAD = 5e18; removed REFERRAL_CRED_BPS from the product path
  • _accrueCharmAndCred: mints 5e18 to referrer and buyer; CRED_PER_BUY epoch pool unchanged
  • Forge: test_referred_buy_mints_cred_not_charm expects 5e18; asserts decoupling from epoch tranche

Frontend

  • Reads REFERRAL_CRED_FLAT_WAD via multicall bridge; /arena buy preview shows +5 CRED Referral (no CHARM % bonus)
  • /referrals copy updated (quest strip + earnings lede)

Indexer

  • No schema change (ReferralCredApplied shape unchanged); persisted amounts will be 5e18 on new rows

Docs / invariants / skills

  • New INV-REFERRAL-272-FLAT-CRED; INV-REFERRAL-253-CRED aliased
  • Updated: referrals.md, time-arena.md (decision #3 superseded), arena-v2.md, glossary.md, manual QA §253
  • Guardrails 6f + skills/play-time-arena-doub/SKILL.md crosslinked

Verification checklist

  • cd contracts && forge test --match-test 'test_referred_buy_mints_cred_not_charm|test_self_referral_reverts' — green
  • Anvil/devnet: referred TimeArena.buy(charm, codeHash) → PlayCred.balanceOf +5 for referrer and buyer
  • Event: ReferralCredApplied emits 5e18, 5e18
  • No-referral buy (codeHash == 0) → zero referral mint
  • Self-referral / invalid code still revert
  • buyWithCred → no referral CRED (documented out of scope)
  • Indexer ingest + GET /v1/referrals/applied → referrer_cred / buyer_cred = 5000000000000000000
  • /referrals leaderboard + wallet summary totals reflect 5 CRED × buy count
  • /arena pending referral preview shows +5 CRED, not +5% or inflated CHARM CTA
  • Docs: no live Arena v2 references to 1.75 CRED or REFERRAL_CRED_BPS

Automated on branch: Forge referral tests ✅ · arenaV2SaleSessionBridge.test.ts ✅

@brouie — please verify on your stack when convenient. Leaving issue open until checklist sign-off.

## Implementation landed on `main` (dbbfeba) Replaced percentage-based referral Play CRED (**5% of `CRED_PER_BUY` → 1.75 CRED/side**) with a **flat 5 CRED per side** on qualifying referred **DOUB** buys ([#272](https://gitlab.com/PlasticDigits/yieldomega/-/issues/272)). ### What changed **Contracts** - `TimeArena`: added `REFERRAL_CRED_FLAT_WAD = 5e18`; removed `REFERRAL_CRED_BPS` from the product path - `_accrueCharmAndCred`: mints `5e18` to referrer and buyer; **`CRED_PER_BUY` epoch pool unchanged** - Forge: `test_referred_buy_mints_cred_not_charm` expects `5e18`; asserts decoupling from epoch tranche **Frontend** - Reads `REFERRAL_CRED_FLAT_WAD` via multicall bridge; `/arena` buy preview shows **+5 CRED Referral** (no CHARM % bonus) - `/referrals` copy updated (quest strip + earnings lede) **Indexer** - No schema change (`ReferralCredApplied` shape unchanged); persisted amounts will be `5e18` on new rows **Docs / invariants / skills** - New **`INV-REFERRAL-272-FLAT-CRED`**; **`INV-REFERRAL-253-CRED`** aliased - Updated: `referrals.md`, `time-arena.md` (decision #3 superseded), `arena-v2.md`, `glossary.md`, manual QA §253 - Guardrails **6f** + `skills/play-time-arena-doub/SKILL.md` crosslinked ### Verification checklist - [ ] `cd contracts && forge test --match-test 'test_referred_buy_mints_cred_not_charm|test_self_referral_reverts'` — green - [ ] Anvil/devnet: referred `TimeArena.buy(charm, codeHash)` → `PlayCred.balanceOf` **+5** for referrer and buyer - [ ] Event: `ReferralCredApplied` emits **`5e18, 5e18`** - [ ] No-referral buy (`codeHash == 0`) → **zero** referral mint - [ ] Self-referral / invalid code still **revert** - [ ] `buyWithCred` → **no** referral CRED (documented out of scope) - [ ] Indexer ingest + `GET /v1/referrals/applied` → `referrer_cred` / `buyer_cred` = `5000000000000000000` - [ ] `/referrals` leaderboard + wallet summary totals reflect **5 CRED × buy count** - [ ] `/arena` pending referral preview shows **+5 CRED**, not **+5%** or inflated CHARM CTA - [ ] Docs: no live Arena v2 references to **1.75 CRED** or **`REFERRAL_CRED_BPS`** Automated on branch: Forge referral tests ✅ · `arenaV2SaleSessionBridge.test.ts` ✅ @brouie — please verify on your stack when convenient. Leaving issue **open** until checklist sign-off.
PlasticDigits commented 2026-06-01 11:59:52 +00:00 (Migrated from gitlab.com)

mentioned in commit c7ca1393f5

mentioned in commit c7ca1393f535dfbb675bb4bf806d5a14559346c6
PlasticDigits commented 2026-06-01 12:00:01 +00:00 (Migrated from gitlab.com)

QA verification complete (agent)

Verified GitLab #272 (flat 5 CRED per side on referred DOUB buys) on branch issue/272-verify, merged to main as c7ca139.

What was verified (already on main before this pass)

Layer Result
Contracts REFERRAL_CRED_FLAT_WAD = 5e18; _accrueCharmAndCred mints flat amount; REFERRAL_CRED_BPS removed from product path
Forge test_referred_buy_mints_cred_not_charm, test_self_referral_reverts — expect 5e18 each side; decoupling assert vs CRED_PER_BUY
Indexer integration_stage2.rs fixture uses 5e18 for referrer_cred / buyer_cred (CI when PG URL set)
Frontend Arena session reads REFERRAL_CRED_FLAT_WAD; /referrals lede shows flat 5 CRED; arenaV2SaleSessionBridge.test.ts green

Fixes / additions in c7ca139

  1. scripts/verify-referral-flat-cred-anvil.sh — fresh Anvil DeployDev smoke: register code → referred buy → +5 CRED referrer & buyer; buyWithCred does not mint referral CRED; re-runs Forge referral tests.
  2. Home card copy — surfaceContent.ts no longer says “Earn 5% … TimeCurve”.
  3. Docs / skills — INV-REFERRAL-272-FLAT-CRED + manual QA §253 crosslink Anvil script; play-time-arena-doub skill links script.

Commands run (all passed)

bash scripts/verify-referral-flat-cred-anvil.sh
FOUNDRY_PROFILE=ci forge test --match-test 'test_referred_buy_mints_cred_not_charm|test_self_referral_reverts'
cd frontend && npm test -- --run arenaV2SaleSessionBridge

Indexer integration_stage2 referral persist smoke was not re-run here (no DATABASE_URL in this environment); CI should cover it.


Checklist for follow-up verification

  • bash scripts/verify-referral-flat-cred-anvil.sh
  • FOUNDRY_PROFILE=ci forge test --match-test test_referred_buy_mints_cred_not_charm
  • FOUNDRY_PROFILE=ci forge test --match-test test_self_referral_reverts
  • With local stack: referred TimeArena.buy(charm, codeHash) → PlayCred.balanceOf +5e18 for referrer and buyer
  • Indexer ingest → GET /v1/referrals/applied shows referrer_cred / buyer_cred = 5000000000000000000
  • /referrals earnings + leaderboard CRED totals match indexer
  • /arena buy preview bonus line shows +5 CRED (not 5% / 1.75)
  • Home / referrals card blurb mentions flat Play CRED (not TimeCurve 5%)
  • buyWithCred path still has no referral mint
  • No live Arena v2 docs/UI reference REFERRAL_CRED_BPS or “5% of 35 CRED”

Closing as issue acceptance criteria and verification criteria are satisfied on main.

## QA verification complete (agent) Verified GitLab **#272** (flat **5 CRED** per side on referred DOUB buys) on branch `issue/272-verify`, merged to `main` as **c7ca139**. ### What was verified (already on `main` before this pass) | Layer | Result | |-------|--------| | **Contracts** | `REFERRAL_CRED_FLAT_WAD = 5e18`; `_accrueCharmAndCred` mints flat amount; `REFERRAL_CRED_BPS` removed from product path | | **Forge** | `test_referred_buy_mints_cred_not_charm`, `test_self_referral_reverts` — expect **5e18** each side; decoupling assert vs `CRED_PER_BUY` | | **Indexer** | `integration_stage2.rs` fixture uses **5e18** for `referrer_cred` / `buyer_cred` (CI when PG URL set) | | **Frontend** | Arena session reads `REFERRAL_CRED_FLAT_WAD`; `/referrals` lede shows flat 5 CRED; `arenaV2SaleSessionBridge.test.ts` green | ### Fixes / additions in **c7ca139** 1. **`scripts/verify-referral-flat-cred-anvil.sh`** — fresh Anvil DeployDev smoke: register code → referred `buy` → +5 CRED referrer & buyer; `buyWithCred` does not mint referral CRED; re-runs Forge referral tests. 2. **Home card copy** — `surfaceContent.ts` no longer says “Earn 5% … TimeCurve”. 3. **Docs / skills** — `INV-REFERRAL-272-FLAT-CRED` + manual QA §253 crosslink Anvil script; `play-time-arena-doub` skill links script. ### Commands run (all passed) ```bash bash scripts/verify-referral-flat-cred-anvil.sh FOUNDRY_PROFILE=ci forge test --match-test 'test_referred_buy_mints_cred_not_charm|test_self_referral_reverts' cd frontend && npm test -- --run arenaV2SaleSessionBridge ``` Indexer `integration_stage2` referral persist smoke was **not** re-run here (no `DATABASE_URL` in this environment); CI should cover it. --- ### Checklist for follow-up verification - [ ] `bash scripts/verify-referral-flat-cred-anvil.sh` - [ ] `FOUNDRY_PROFILE=ci forge test --match-test test_referred_buy_mints_cred_not_charm` - [ ] `FOUNDRY_PROFILE=ci forge test --match-test test_self_referral_reverts` - [ ] With local stack: referred `TimeArena.buy(charm, codeHash)` → `PlayCred.balanceOf` +5e18 for referrer and buyer - [ ] Indexer ingest → `GET /v1/referrals/applied` shows `referrer_cred` / `buyer_cred` = `5000000000000000000` - [ ] `/referrals` earnings + leaderboard CRED totals match indexer - [ ] `/arena` buy preview bonus line shows **+5 CRED** (not 5% / 1.75) - [ ] Home `/` referrals card blurb mentions flat Play CRED (not TimeCurve 5%) - [ ] `buyWithCred` path still has **no** referral mint - [ ] No live Arena v2 docs/UI reference `REFERRAL_CRED_BPS` or “5% of 35 CRED” Closing as issue acceptance criteria and verification criteria are satisfied on `main`.
PlasticDigits (Migrated from gitlab.com) closed this issue 2026-06-01 12:00:06 +00:00
PlasticDigits commented 2026-06-13 07:02:54 +00:00 (Migrated from gitlab.com)

mentioned in issue #309

mentioned in issue #309
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#272
No description provided.