Arena: TWAP-derived initial charmPriceWad (#303) #447

Merged
PlasticDigits merged 1 commit from cursor/gitlab-issue-workflow-696a into main 2026-06-08 08:39:30 +00:00
PlasticDigits commented 2026-06-08 08:38:42 +00:00 (Migrated from gitlab.com)

Summary

Implements GitLab #303: production TimeArena.charmPriceWad is derived from Kumbaya V3 TWAP (Sir 15-minute window) on DOUB/WETH (fee 100) and WETH/USDm (fee 3000), anchored so ~$1 DOUB notional buys 1 CHARM (charmPriceWad = floor(1e36 / doubUsdTwap)). DeployDev / Anvil remain 1000e18.

Changes

  • ArenaCharmPriceTwap library + minimal V3 oracle helpers (observe, getQuoteAtTick)
  • DeployProduction computes TWAP on chain 4326 unless ARENA_CHARM_PRICE_WAD override is set (fail-closed; no silent 1000e18)
  • bash scripts/compute-arena-charm-price-twap.sh ops dry-run
  • Unit + optional fork tests; INV-TIME-ARENA-CHARM-TWAP-INIT in invariants
  • Docs: PARAMETERS.md, deployment guide, arena product docs, kumbaya.md

Blocker note

MegaETH mainnet currently has no DOUB/WETH pool at fee 100 — TWAP dry-run and production deploy will revert until that pool exists (or ops sets ARENA_CHARM_PRICE_WAD for rehearsal).

Acceptance checklist

Criterion Command / step Result
Sir/Kumbaya TWAP recipe documented docs/integrations/kumbaya.md, PARAMETERS.md, INV-TIME-ARENA-CHARM-TWAP-INIT PASS
Production sets ~$1/CHARM via TWAP DeployProduction._resolveCharmPriceWad + formula in ArenaCharmPriceTwap PASS (code); live deploy SKIP until DOUB/WETH pool exists
DOUB spend band derived minDoubSpend = 0.99×charmPriceWad, max = 10× in library + tests PASS
ARENA_CHARM_PRICE_WAD override DeployProduction + deploy-megaeth-contracts.sh PASS
TWAP failure → abort / override No silent 1000e18 on 4326; script exits non-zero PASS
DeployDev / Anvil unchanged DeployDev.s.sol still 1000e18 PASS
INV-TIME-ARENA-DOUB-PRICE updated invariants row + dev default note PASS
Product docs updated arena-v2.md, time-arena.md PASS
Contracts unit tests cd contracts && forge test --match-contract ArenaCharmPriceTwap PASS (5/5)
Full forge (non-fork) cd contracts && forge test --no-match-contract DoubAirdropMegaethFork PASS (146+; 4 doub.csv fork tests SKIP/FAIL without csv)
TWAP script bash scripts/compute-arena-charm-price-twap.sh FAIL (expected: missing DOUB/WETH pool on mainnet head)
Buy router bash scripts/verify-time-arena-buy-router-anvil.sh PASS
Frontend cd frontend && npm run typecheck && npm test PASS
Fork TWAP when pool exists FORK_URL=… forge test --match-contract ArenaCharmPriceTwapFork SKIP (pool missing on fork head)

Verification for reviewers

export PATH="$HOME/.foundry/bin:$PATH"
cd contracts && forge test --match-contract ArenaCharmPriceTwap
bash scripts/compute-arena-charm-price-twap.sh   # expect FAIL until DOUB/WETH pool live
bash scripts/verify-time-arena-buy-router-anvil.sh
cd frontend && npm run typecheck && npm test

Note

Medium Risk
Changes the initial economic parameter at production deploy and depends on live V3 oracle reads; mitigated by TWAP guards, USD band checks, explicit override, and deploy abort when pools/TWAP are unavailable (no silent 1000e18 on mainnet).

Overview
Production TimeArena deploy on MegaETH (4326) no longer hard-codes charmPriceWad = 1000e18. DeployProduction resolves the initial price via ArenaCharmPriceTwap: 15-minute Kumbaya V3 TWAP on DOUB/WETH and WETH/USDm, then charmPriceWad = floor(1e36 / doubUsdTwap) so ~$1 DOUB notional maps to 1 CHARM. ARENA_CHARM_PRICE_WAD still overrides; without it on non-4326 chains deploy reverts instead of silently using the old default.

The PR adds minimal Uniswap V3 oracle helpers, fail-closed checks (pool existence, observation cardinality, spot/TWAP deviation, DOUB/USD band), unit tests with mocks, optional fork smoke, ComputeArenaCharmPriceTwap + compute-arena-charm-price-twap.sh for ops dry-runs, and updates deploy-megaeth-contracts.sh so the TWAP override env is only exported when explicitly set. DeployDev / Anvil stay at 1000e18. Docs and INV-TIME-ARENA-CHARM-TWAP-INIT document the new init path.

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

## Summary Implements GitLab [#303](https://gitlab.com/PlasticDigits/yieldomega/-/work_items/303): production **`TimeArena.charmPriceWad`** is derived from **Kumbaya V3 TWAP** (Sir **15-minute** window) on **DOUB/WETH (fee 100)** and **WETH/USDm (fee 3000)**, anchored so **~$1 DOUB notional buys 1 CHARM** (`charmPriceWad = floor(1e36 / doubUsdTwap)`). **DeployDev / Anvil** remain **`1000e18`**. ### Changes - `ArenaCharmPriceTwap` library + minimal V3 oracle helpers (`observe`, `getQuoteAtTick`) - `DeployProduction` computes TWAP on chain **4326** unless **`ARENA_CHARM_PRICE_WAD`** override is set (fail-closed; no silent `1000e18`) - `bash scripts/compute-arena-charm-price-twap.sh` ops dry-run - Unit + optional fork tests; **`INV-TIME-ARENA-CHARM-TWAP-INIT`** in invariants - Docs: `PARAMETERS.md`, deployment guide, arena product docs, `kumbaya.md` ### Blocker note MegaETH mainnet currently has **no DOUB/WETH pool** at fee **100** — TWAP dry-run and production deploy will revert until that pool exists (or ops sets **`ARENA_CHARM_PRICE_WAD`** for rehearsal). ## Acceptance checklist | Criterion | Command / step | Result | |-----------|----------------|--------| | Sir/Kumbaya TWAP recipe documented | `docs/integrations/kumbaya.md`, `PARAMETERS.md`, `INV-TIME-ARENA-CHARM-TWAP-INIT` | PASS | | Production sets ~$1/CHARM via TWAP | `DeployProduction._resolveCharmPriceWad` + formula in `ArenaCharmPriceTwap` | PASS (code); **live deploy SKIP** until DOUB/WETH pool exists | | DOUB spend band derived | `minDoubSpend = 0.99×charmPriceWad`, `max = 10×` in library + tests | PASS | | `ARENA_CHARM_PRICE_WAD` override | `DeployProduction` + `deploy-megaeth-contracts.sh` | PASS | | TWAP failure → abort / override | No silent `1000e18` on 4326; script exits non-zero | PASS | | DeployDev / Anvil unchanged | `DeployDev.s.sol` still `1000e18` | PASS | | `INV-TIME-ARENA-DOUB-PRICE` updated | invariants row + dev default note | PASS | | Product docs updated | `arena-v2.md`, `time-arena.md` | PASS | | Contracts unit tests | `cd contracts && forge test --match-contract ArenaCharmPriceTwap` | PASS (5/5) | | Full forge (non-fork) | `cd contracts && forge test --no-match-contract DoubAirdropMegaethFork` | PASS (146+; 4 `doub.csv` fork tests SKIP/FAIL without csv) | | TWAP script | `bash scripts/compute-arena-charm-price-twap.sh` | **FAIL** (expected: missing DOUB/WETH pool on mainnet head) | | Buy router | `bash scripts/verify-time-arena-buy-router-anvil.sh` | PASS | | Frontend | `cd frontend && npm run typecheck && npm test` | PASS | | Fork TWAP when pool exists | `FORK_URL=… forge test --match-contract ArenaCharmPriceTwapFork` | SKIP (pool missing on fork head) | ## Verification for reviewers ```bash export PATH="$HOME/.foundry/bin:$PATH" cd contracts && forge test --match-contract ArenaCharmPriceTwap bash scripts/compute-arena-charm-price-twap.sh # expect FAIL until DOUB/WETH pool live bash scripts/verify-time-arena-buy-router-anvil.sh cd frontend && npm run typecheck && npm test ``` <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **Medium Risk** > Changes the initial economic parameter at production deploy and depends on live V3 oracle reads; mitigated by TWAP guards, USD band checks, explicit override, and deploy abort when pools/TWAP are unavailable (no silent 1000e18 on mainnet). > > **Overview** > Production **`TimeArena`** deploy on MegaETH (**4326**) no longer hard-codes **`charmPriceWad = 1000e18`**. **`DeployProduction`** resolves the initial price via **`ArenaCharmPriceTwap`**: 15-minute Kumbaya V3 TWAP on **DOUB/WETH** and **WETH/USDm**, then **`charmPriceWad = floor(1e36 / doubUsdTwap)`** so ~**$1** DOUB notional maps to 1 CHARM. **`ARENA_CHARM_PRICE_WAD`** still overrides; without it on non-4326 chains deploy **reverts** instead of silently using the old default. > > The PR adds minimal Uniswap V3 oracle helpers, fail-closed checks (pool existence, observation cardinality, spot/TWAP deviation, DOUB/USD band), unit tests with mocks, optional fork smoke, **`ComputeArenaCharmPriceTwap`** + **`compute-arena-charm-price-twap.sh`** for ops dry-runs, and updates **`deploy-megaeth-contracts.sh`** so the TWAP override env is only exported when explicitly set. **DeployDev / Anvil** stay at **`1000e18`**. Docs and **`INV-TIME-ARENA-CHARM-TWAP-INIT`** document the new init path. > > <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit 69e05c9ac07628cea8f0e700d67dd529c59cfb28. 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-08 08:38:51 +00:00 (Migrated from gitlab.com)

mentioned in issue #303

mentioned in issue #303
project_80561744_bot_5118c68a88bff95eacb6ab1c47c19cae commented 2026-06-08 08:38:53 +00:00 (Migrated from gitlab.com)

changed the description

changed the description
project_80561744_bot_5118c68a88bff95eacb6ab1c47c19cae commented 2026-06-08 08:39:03 +00:00 (Migrated from gitlab.com)

changed the description

changed the description
PlasticDigits (Migrated from gitlab.com) merged commit 69e05c9ac0 into main 2026-06-08 08:39:30 +00:00
project_80561744_bot_5118c68a88bff95eacb6ab1c47c19cae commented 2026-06-08 08:45:11 +00:00 (Migrated from gitlab.com)

Security review (automated)

Commit reviewed: 69e05c9ac07628cea8f0e700d67dd529c59cfb28
Scope: GitLab #303 — ArenaCharmPriceTwap library, DeployProduction TWAP init, V3 oracle helpers, dry-run script, deploy script + docs/invariants (20 files in MR diff).

Outcome

FINDINGS: 0 medium+

Security review: no medium+ findings on this diff.

Summary

Reviewed deploy-time TWAP derivation for production charmPriceWad, fail-closed guards (ARENA_CHARM_PRICE_WAD override, chain-id gate, missing-pool revert), and ops dry-run script. ArenaCharmPriceTwap is consumed only by the Foundry deploy/dry-run path — not linked into runtime TimeArena bytecode — so there is no post-deploy user-callable oracle sink.

Controls traced:

  • 15-minute Kumbaya V3 TWAP (SIR_TWAP_SECONDS = 900)
  • Minimum observation cardinality check
  • 500 bps spot/TWAP deviation cap
  • DOUB/USD plausibility band (MIN_DOUB_USD_WAD–MAX_DOUB_USD_WAD)
  • Non-zero price requires; deploy aborts without silent 1000e18 fallback on mainnet

Deploy-time pool manipulation / thin-liquidity TWAP bias is an operational deployment concern mitigated by dry-run (scripts/compute-arena-charm-price-twap.sh), documented override, and post-deploy setCharmPriceWad governance — not an exploitable production authn/authz or injection path introduced here.

Inline threads

None (zero medium+ findings).


Cursor security-review automation · MR !447

## Security review (automated) **Commit reviewed:** `69e05c9ac07628cea8f0e700d67dd529c59cfb28` **Scope:** GitLab #303 — `ArenaCharmPriceTwap` library, `DeployProduction` TWAP init, V3 oracle helpers, dry-run script, deploy script + docs/invariants (20 files in MR diff). ### Outcome **FINDINGS: 0** medium+ Security review: **no medium+ findings** on this diff. ### Summary Reviewed deploy-time TWAP derivation for production `charmPriceWad`, fail-closed guards (`ARENA_CHARM_PRICE_WAD` override, chain-id gate, missing-pool revert), and ops dry-run script. `ArenaCharmPriceTwap` is consumed only by the Foundry deploy/dry-run path — not linked into runtime `TimeArena` bytecode — so there is no post-deploy user-callable oracle sink. Controls traced: - 15-minute Kumbaya V3 TWAP (`SIR_TWAP_SECONDS = 900`) - Minimum observation cardinality check - 500 bps spot/TWAP deviation cap - DOUB/USD plausibility band (`MIN_DOUB_USD_WAD`–`MAX_DOUB_USD_WAD`) - Non-zero price requires; deploy aborts without silent `1000e18` fallback on mainnet Deploy-time pool manipulation / thin-liquidity TWAP bias is an operational deployment concern mitigated by dry-run (`scripts/compute-arena-charm-price-twap.sh`), documented override, and post-deploy `setCharmPriceWad` governance — not an exploitable production authn/authz or injection path introduced here. ### Inline threads None (zero medium+ findings). --- *Cursor security-review automation · MR !447*
PlasticDigits commented 2026-06-09 07:13:59 +00:00 (Migrated from gitlab.com)

mentioned in merge request !450

mentioned in merge request !450
PlasticDigits commented 2026-06-09 09:58:08 +00:00 (Migrated from gitlab.com)

mentioned in merge request !451

mentioned in merge request !451
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!447
No description provided.