feat(arena): epoch DOUB/CHARM anchor + 10%/day growth (#305) #453

Merged
PlasticDigits merged 2 commits from local1/305-impl-epoch-charm-price into main 2026-06-10 11:00:12 +00:00
PlasticDigits commented 2026-06-10 09:36:30 +00:00 (Migrated from gitlab.com)

Summary

Implements GitLab #305 — Last Buy epoch–scoped DOUB/CHARM pricing:

  • Onchain: effectiveCharmPriceWad() grows epoch anchor at ~10%/day; hard-reset buy re-samples TWAP/Anvil spot before DOUB pull; emits LastBuyEpochCharmAnchored; CRED path unchanged
  • Indexer: head poller reads effective + anchor fields; decodes anchor event; GET /v1/arena/last-buy-epoch-pricing
  • Frontend: buy sizing, Kumbaya quoter, and protocol copy use effective price (indexer-first)
  • Docs: INV-TIME-ARENA-EPOCH-CHARM-GROWTH, INV-TIME-ARENA-CRED-FLAT, product/skill crosslinks

Test plan

  • cd contracts && forge test --match-contract TimeArenaEpochCharmPrice
  • cd contracts && forge test --match-contract TimeArenaTest
  • cd indexer && cargo clippy --all-targets -- -D warnings && cargo test
  • cd frontend && npm run typecheck && npm test -- --run src/pages/arena/arenaV2SaleSessionBridge.test.ts src/lib/timeArenaBuySubmitSizing.test.ts
  • bash scripts/verify-podium-live-anvil.sh — timers charm_price_wad = effective
  • Manual: warp +1 day on Anvil → cast call effectiveCharmPriceWad ≈ anchor × 1.1

Note

High Risk
Changes core DOUB pricing, hard-reset epoch boundaries, and on-chain TWAP/spot re-anchoring before pulls—direct economic and integrator impact. UUPS storage and router doubOwedForBuy (stateful preview) add upgrade and quoting edge cases.

Overview
DOUB buys no longer use a flat charmPriceWad. Pricing is effectiveCharmPriceWad() = Last Buy epoch anchor compounded at ~10%/day via TimeMath.growWad, with doubOwedForBuy / TimeArenaBuyRouter sized off that (including a preview when a hard reset would re-anchor).

On a Last Buy hard-reset band buy, the contract re-samples the anchor (Anvil Kumbaya spot or MegaETH ArenaCharmPriceTwap) in _prepareBuyBeforeTimer before the DOUB pull, bumps lastBuyEpoch, resets the growth clock, and emits LastBuyEpochCharmAnchored. Post-start governance moves from setCharmPriceWad to setEpochCharmAnchorWad + optional setCharmAnchorOracle. buyWithCred stays on flat CRED burn only.

Adds TimeArenaEpochCharmPrice.t.sol, adjusts existing arena/router tests (e.g. _freezeCharmPrice), and updates PARAMETERS, product, and invariant docs for INV-TIME-ARENA-EPOCH-CHARM-GROWTH.

Reviewed by Cursor Bugbot for commit 8118e98dda. Bugbot is set up for automated code reviews on this repo. Configure here.

## Summary Implements GitLab #305 — Last Buy epoch–scoped DOUB/CHARM pricing: - **Onchain:** `effectiveCharmPriceWad()` grows epoch anchor at ~10%/day; hard-reset buy re-samples TWAP/Anvil spot **before** DOUB pull; emits `LastBuyEpochCharmAnchored`; CRED path unchanged - **Indexer:** head poller reads effective + anchor fields; decodes anchor event; `GET /v1/arena/last-buy-epoch-pricing` - **Frontend:** buy sizing, Kumbaya quoter, and protocol copy use effective price (indexer-first) - **Docs:** `INV-TIME-ARENA-EPOCH-CHARM-GROWTH`, `INV-TIME-ARENA-CRED-FLAT`, product/skill crosslinks ## Test plan - [x] `cd contracts && forge test --match-contract TimeArenaEpochCharmPrice` - [x] `cd contracts && forge test --match-contract TimeArenaTest` - [x] `cd indexer && cargo clippy --all-targets -- -D warnings && cargo test` - [x] `cd frontend && npm run typecheck && npm test -- --run src/pages/arena/arenaV2SaleSessionBridge.test.ts src/lib/timeArenaBuySubmitSizing.test.ts` - [ ] `bash scripts/verify-podium-live-anvil.sh` — timers `charm_price_wad` = effective - [ ] Manual: warp +1 day on Anvil → `cast call effectiveCharmPriceWad` ≈ anchor × 1.1 <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **High Risk** > Changes core DOUB pricing, hard-reset epoch boundaries, and on-chain TWAP/spot re-anchoring before pulls—direct economic and integrator impact. UUPS storage and router `doubOwedForBuy` (stateful preview) add upgrade and quoting edge cases. > > **Overview** > **DOUB buys** no longer use a flat `charmPriceWad`. Pricing is **`effectiveCharmPriceWad()`** = Last Buy **epoch anchor** compounded at **~10%/day** via `TimeMath.growWad`, with **`doubOwedForBuy`** / **`TimeArenaBuyRouter`** sized off that (including a preview when a hard reset would re-anchor). > > On a **Last Buy hard-reset band** buy, the contract **re-samples** the anchor (Anvil Kumbaya spot or MegaETH **`ArenaCharmPriceTwap`**) in **`_prepareBuyBeforeTimer`** **before** the DOUB pull, bumps **`lastBuyEpoch`**, resets the growth clock, and emits **`LastBuyEpochCharmAnchored`**. Post-start governance moves from **`setCharmPriceWad`** to **`setEpochCharmAnchorWad`** + optional **`setCharmAnchorOracle`**. **`buyWithCred`** stays on flat CRED burn only. > > Adds **`TimeArenaEpochCharmPrice.t.sol`**, adjusts existing arena/router tests (e.g. **`_freezeCharmPrice`**), and updates **PARAMETERS**, product, and invariant docs for **`INV-TIME-ARENA-EPOCH-CHARM-GROWTH`**. > > <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit 8118e98dda5d2163be197c4fbf9eec5a8d2e0b65. Bugbot is set up for automated code reviews on this repo. Configure [here](https://www.cursor.com/dashboard/bugbot).</sup> <!-- /CURSOR_SUMMARY -->
PlasticDigits commented 2026-06-10 09:36:34 +00:00 (Migrated from gitlab.com)

mentioned in issue #305

mentioned in issue #305
project_80561744_bot_5118c68a88bff95eacb6ab1c47c19cae commented 2026-06-10 09:36:56 +00:00 (Migrated from gitlab.com)

changed the description

changed the description
project_80561744_bot_5118c68a88bff95eacb6ab1c47c19cae commented 2026-06-10 09:37:06 +00:00 (Migrated from gitlab.com)

changed the description

changed the description
project_80561744_bot_5118c68a88bff95eacb6ab1c47c19cae commented 2026-06-10 09:38:06 +00:00 (Migrated from gitlab.com)

Cursor Bugbot has reviewed your changes and found 2 potential issues.

Fix All in Cursor

Bugbot Autofix is ON. A cloud agent has been kicked off to fix the reported issues.

Reviewed by Cursor Bugbot for commit fc4fc99173. Configure here.

<!-- BUGBOT_REVIEW --> Cursor Bugbot has reviewed your changes and found 2 potential issues. <!-- BUGBOT_FIX_ALL --> <a href="https://cursor.com/open?link=eyJ2ZXJzaW9uIjoxLCJ0eXBlIjoiQlVHQk9UX0ZJWF9BTExfSU5fQ1VSU09SIiwiZGF0YSI6eyJyZWRpc0tleSI6ImJ1Z2JvdC1tdWx0aTo3ZTc3OTk4MC01MWRjLTQ1ZTctYTlhNC0yZDlkOWVjY2Q2OGMiLCJlbmNyeXB0aW9uS2V5IjoiVmlDRWR0RUZmZktIUzhobUpyOE5QWnVvdXB1UFZTanFaeU9LSFhGbFBiZyIsImJyYW5jaCI6ImxvY2FsMS8zMDUtaW1wbC1lcG9jaC1jaGFybS1wcmljZSIsInJlcG9Pd25lciI6IlBsYXN0aWNEaWdpdHMiLCJyZXBvTmFtZSI6InlpZWxkb21lZ2EifX0" target="_blank" rel="noopener noreferrer"><picture><source media="(prefers-color-scheme: dark)" srcset="https://cursor.com/assets/images/fix-in-cursor-dark.png"><source media="(prefers-color-scheme: light)" srcset="https://cursor.com/assets/images/fix-in-cursor-light.png"><img alt="Fix All in Cursor" width="115" height="28" src="https://cursor.com/assets/images/fix-in-cursor-dark.png"></picture></a> <!-- /BUGBOT_FIX_ALL --> <!-- BUGBOT_AUTOFIX_REVIEW_FOOTNOTE_BEGIN --> <sup>Bugbot Autofix is [ON](https://www.cursor.com/dashboard/bugbot). A cloud agent has been kicked off to fix the reported issues. <!-- BUGBOT_AUTOFIX_AGENT_LINK --></sup> <!-- BUGBOT_AUTOFIX_REVIEW_FOOTNOTE_END --> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit fc4fc99173ecf8ab9de6f3f37f25a081449541fa. Configure [here](https://www.cursor.com/dashboard/bugbot).</sup>
project_80561744_bot_5118c68a88bff95eacb6ab1c47c19cae commented 2026-06-10 09:38:07 +00:00 (Migrated from gitlab.com)

Fee-stable oracle uses wrong token

Low Severity

In deployBuyRouterFixtureFeeStable, the charm anchor spot uses feeStable but setCharmAnchorOracle stores unset usdm (zero). Any hard-reset re-anchor on that fixture would call spot pricing with a zero USD leg instead of feeStable.

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit fc4fc99173. Configure here.

### Fee-stable oracle uses wrong token **Low Severity** <!-- DESCRIPTION START --> In `deployBuyRouterFixtureFeeStable`, the charm anchor spot uses `feeStable` but `setCharmAnchorOracle` stores unset `usdm` (zero). Any hard-reset re-anchor on that fixture would call spot pricing with a zero USD leg instead of `feeStable`. <!-- DESCRIPTION END --> <!-- BUGBOT_BUG_ID: ac5c1135-7b27-4eb3-bbcc-d8bb4438f76c --> <!-- LOCATIONS START contracts/test/TimeArenaBuyRouter.t.sol#L146-L149 LOCATIONS END --> <div><a href="https://cursor.com/open?link=eyJ2ZXJzaW9uIjoxLCJ0eXBlIjoiQlVHQk9UX0ZJWF9JTl9DVVJTT1IiLCJkYXRhIjp7InJlZGlzS2V5IjoiYnVnYm90OjU2NjZmZTJjLTdmZTgtNDIxYy05NWZiLTViZWFhNzMxODY3MiIsImVuY3J5cHRpb25LZXkiOiJRcVdZcGJQWmZnNHk1X2Y2SHlTNWJhUWtEdE1IbGswMW1pQ1dhUnNLVGtvIiwiYnJhbmNoIjoibG9jYWwxLzMwNS1pbXBsLWVwb2NoLWNoYXJtLXByaWNlIiwicmVwb093bmVyIjoiUGxhc3RpY0RpZ2l0cyIsInJlcG9OYW1lIjoieWllbGRvbWVnYSJ9fQ" target="_blank" rel="noopener noreferrer"><picture><source media="(prefers-color-scheme: dark)" srcset="https://cursor.com/assets/images/fix-in-cursor-dark.png"><source media="(prefers-color-scheme: light)" srcset="https://cursor.com/assets/images/fix-in-cursor-light.png"><img alt="Fix in Cursor" width="115" height="28" src="https://cursor.com/assets/images/fix-in-cursor-dark.png"></picture></a>&nbsp;<a href="https://cursor.com/agents?link=eyJ2ZXJzaW9uIjoxLCJ0eXBlIjoiQlVHQk9UX0ZJWF9JTl9XRUIiLCJkYXRhIjp7InJlZGlzS2V5IjoiYnVnYm90OjU2NjZmZTJjLTdmZTgtNDIxYy05NWZiLTViZWFhNzMxODY3MiIsImVuY3J5cHRpb25LZXkiOiJRcVdZcGJQWmZnNHk1X2Y2SHlTNWJhUWtEdE1IbGswMW1pQ1dhUnNLVGtvIiwiYnJhbmNoIjoibG9jYWwxLzMwNS1pbXBsLWVwb2NoLWNoYXJtLXByaWNlIiwicmVwb093bmVyIjoiUGxhc3RpY0RpZ2l0cyIsInJlcG9OYW1lIjoieWllbGRvbWVnYSIsInByTnVtYmVyIjo4MywiY29tbWl0U2hhIjoiZmM0ZmM5OTE3M2VjZjhhYjlkZTZmM2YzN2YyNWEwODE0NDk1NDFmYSIsInByb3ZpZGVyIjoiZ2l0bGFiIiwiaG9zdG5hbWUiOiJnaXRsYWIuY29tIn19" target="_blank" rel="noopener noreferrer"><picture><source media="(prefers-color-scheme: dark)" srcset="https://cursor.com/assets/images/fix-in-web-dark.png"><source media="(prefers-color-scheme: light)" srcset="https://cursor.com/assets/images/fix-in-web-light.png"><img alt="Fix in Web" width="99" height="28" src="https://cursor.com/assets/images/fix-in-web-dark.png"></picture></a></div> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit fc4fc99173ecf8ab9de6f3f37f25a081449541fa. Configure [here](https://www.cursor.com/dashboard/bugbot).</sup>
project_80561744_bot_5118c68a88bff95eacb6ab1c47c19cae commented 2026-06-10 09:38:07 +00:00 (Migrated from gitlab.com)

Router hard-reset price mismatch

High Severity

buyViaKumbaya sizes the Kumbaya swap from effectiveCharmPriceWad() before the arena runs _prepareBuyBeforeTimer() on hard-reset buys. Re-anchoring inside buyFor can change the DOUB owed versus grossDoub, so pulls can revert or users overpay while surplus goes to the router recipient.

Additional Locations (1)
Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit fc4fc99173. Configure here.

### Router hard-reset price mismatch **High Severity** <!-- DESCRIPTION START --> `buyViaKumbaya` sizes the Kumbaya swap from `effectiveCharmPriceWad()` before the arena runs `_prepareBuyBeforeTimer()` on hard-reset buys. Re-anchoring inside `buyFor` can change the DOUB owed versus `grossDoub`, so pulls can revert or users overpay while surplus goes to the router recipient. <!-- DESCRIPTION END --> <!-- BUGBOT_BUG_ID: 21731972-cacc-44e9-a4be-59cfe4c70aa3 --> <!-- LOCATIONS START contracts/src/arena/TimeArenaBuyRouter.sol#L100-L130 contracts/src/arena/TimeArena.sol#L530-L533 LOCATIONS END --> <details> <summary>Additional Locations (1)</summary> - [`contracts/src/arena/TimeArena.sol#L530-L533`](https://gitlab.com/PlasticDigits/yieldomega/-//blob/fc4fc99173ecf8ab9de6f3f37f25a081449541fa/contracts/src/arena/TimeArena.sol#L530-L533) </details> <div><a href="https://cursor.com/open?link=eyJ2ZXJzaW9uIjoxLCJ0eXBlIjoiQlVHQk9UX0ZJWF9JTl9DVVJTT1IiLCJkYXRhIjp7InJlZGlzS2V5IjoiYnVnYm90OjM4YWU2Y2I0LTY0NTctNGVmZC04NTdjLTUxNjQyMDc5NjA1OSIsImVuY3J5cHRpb25LZXkiOiJWZHVBUm13UW4wOU5PYnBTYVpJa1VjSlpzNTRKQWZjWXpEVVZtal90NEtBIiwiYnJhbmNoIjoibG9jYWwxLzMwNS1pbXBsLWVwb2NoLWNoYXJtLXByaWNlIiwicmVwb093bmVyIjoiUGxhc3RpY0RpZ2l0cyIsInJlcG9OYW1lIjoieWllbGRvbWVnYSJ9fQ" target="_blank" rel="noopener noreferrer"><picture><source media="(prefers-color-scheme: dark)" srcset="https://cursor.com/assets/images/fix-in-cursor-dark.png"><source media="(prefers-color-scheme: light)" srcset="https://cursor.com/assets/images/fix-in-cursor-light.png"><img alt="Fix in Cursor" width="115" height="28" src="https://cursor.com/assets/images/fix-in-cursor-dark.png"></picture></a>&nbsp;<a href="https://cursor.com/agents?link=eyJ2ZXJzaW9uIjoxLCJ0eXBlIjoiQlVHQk9UX0ZJWF9JTl9XRUIiLCJkYXRhIjp7InJlZGlzS2V5IjoiYnVnYm90OjM4YWU2Y2I0LTY0NTctNGVmZC04NTdjLTUxNjQyMDc5NjA1OSIsImVuY3J5cHRpb25LZXkiOiJWZHVBUm13UW4wOU5PYnBTYVpJa1VjSlpzNTRKQWZjWXpEVVZtal90NEtBIiwiYnJhbmNoIjoibG9jYWwxLzMwNS1pbXBsLWVwb2NoLWNoYXJtLXByaWNlIiwicmVwb093bmVyIjoiUGxhc3RpY0RpZ2l0cyIsInJlcG9OYW1lIjoieWllbGRvbWVnYSIsInByTnVtYmVyIjo4MywiY29tbWl0U2hhIjoiZmM0ZmM5OTE3M2VjZjhhYjlkZTZmM2YzN2YyNWEwODE0NDk1NDFmYSIsInByb3ZpZGVyIjoiZ2l0bGFiIiwiaG9zdG5hbWUiOiJnaXRsYWIuY29tIn19" target="_blank" rel="noopener noreferrer"><picture><source media="(prefers-color-scheme: dark)" srcset="https://cursor.com/assets/images/fix-in-web-dark.png"><source media="(prefers-color-scheme: light)" srcset="https://cursor.com/assets/images/fix-in-web-light.png"><img alt="Fix in Web" width="99" height="28" src="https://cursor.com/assets/images/fix-in-web-dark.png"></picture></a></div> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit fc4fc99173ecf8ab9de6f3f37f25a081449541fa. Configure [here](https://www.cursor.com/dashboard/bugbot).</sup>
project_80561744_bot_5118c68a88bff95eacb6ab1c47c19cae commented 2026-06-10 09:42:08 +00:00 (Migrated from gitlab.com)

changed this line in version 2 of the diff

changed this line in [version 2 of the diff](/PlasticDigits/yieldomega/-/merge_requests/83/diffs?diff_id=1844049279&start_sha=fc4fc99173ecf8ab9de6f3f37f25a081449541fa#84fe0c27f2c3fcfa05d24785efd793d2d8bf0466_149_149)
project_80561744_bot_5118c68a88bff95eacb6ab1c47c19cae commented 2026-06-10 09:42:09 +00:00 (Migrated from gitlab.com)

changed this line in version 2 of the diff

changed this line in [version 2 of the diff](/PlasticDigits/yieldomega/-/merge_requests/83/diffs?diff_id=1844049279&start_sha=fc4fc99173ecf8ab9de6f3f37f25a081449541fa#278e5b3a70a2b245923c5f7fe59d552a4df8c7f6_101_101)
project_80561744_bot_5118c68a88bff95eacb6ab1c47c19cae commented 2026-06-10 09:42:09 +00:00 (Migrated from gitlab.com)

added 1 commit

  • 8118e98d - fix: align router hard-reset quoting and fee-stable oracle (#305)

Compare with previous version

added 1 commit <ul><li>8118e98d - fix: align router hard-reset quoting and fee-stable oracle (#305)</li></ul> [Compare with previous version](/PlasticDigits/yieldomega/-/merge_requests/83/diffs?diff_id=1844049279&start_sha=fc4fc99173ecf8ab9de6f3f37f25a081449541fa)
project_80561744_bot_5118c68a88bff95eacb6ab1c47c19cae commented 2026-06-10 09:42:28 +00:00 (Migrated from gitlab.com)

changed the description

changed the description
project_80561744_bot_5118c68a88bff95eacb6ab1c47c19cae commented 2026-06-10 09:42:51 +00:00 (Migrated from gitlab.com)

resolved all threads

resolved all threads
PlasticDigits commented 2026-06-10 11:00:12 +00:00 (Migrated from gitlab.com)

mentioned in commit 168d8de150

mentioned in commit 168d8de150d3053bcf8145384e8b4125ac8de260
PlasticDigits (Migrated from gitlab.com) merged commit 168d8de150 into main 2026-06-10 11:00:12 +00:00
Sign in to join this conversation.
No reviewers
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!453
No description provided.