Document doubOwedForBuy view semantics and hard-reset preview parity #474

Merged
PlasticDigits merged 2 commits from verify/issue-315-doub-owed-preview into main 2026-06-14 02:36:19 +00:00
PlasticDigits commented 2026-06-13 13:29:29 +00:00 (Migrated from gitlab.com)

Summary

  • Make TimeArena.doubOwedForBuy view (staticcall-safe) — external TWAP/spot reads in _sampleCharmAnchor do not mutate state.
  • Document hard-reset boundary vs effectiveCharmPriceWad() in NatSpec, PARAMETERS.md, kumbaya.md, and invariants (INV-TIME-ARENA-DOUB-OWED-PREVIEW).
  • Add Forge tests asserting doubOwedForBuy(charm) equals immediate buy DOUB pull within epoch and at hard-reset boundary.
  • Sync TimeArena ABI JSON (doubOwedForBuy → stateMutability: view).

Verification checklist (issue #315)

Acceptance item Command / evidence Result
Documented when external calls occur and why NatSpec on doubOwedForBuy / _sampleCharmAnchor; PARAMETERS.md; kumbaya.md § doubOwedForBuy; invariants §315 PASS
Integrators have staticcall-safe preview path doubOwedForBuy is view; ABI stateMutability: view PASS
Forge test: hard-reset boundary pricing cd contracts && forge test --match-contract TimeArenaEpochCharmPrice — test_doubOwedForBuy_matches_buy_at_hard_reset_boundary, test_doubOwedForBuy_matches_buy_within_epoch PASS (9/9)
NatSpec + PARAMETERS explain non-view → view decision Contract NatSpec + PARAMETERS.md row PASS
doubOwedForBuy(charm) == actual DOUB on immediate buy test_doubOwedForBuy_matches_buy_* PASS
Router ABI unchanged (router calls view fn) bash scripts/verify-time-arena-buy-router-anvil.sh PASS
TWAP sandwich assumption documented kumbaya.md + invariants §315 manipulation note PASS

Note

Low Risk
Pricing-preview and documentation change with parity tests; buy execution path unchanged aside from explicit view mutability on an existing helper.

Overview
TimeArena.doubOwedForBuy is now view so integrators can staticcall/eth_call a DOUB preview without mutating state. TWAP/spot reads in _sampleCharmAnchor stay read-only on that path; at the Last Buy hard-reset band the preview uses the same sampled anchor as an immediate buy, not effectiveCharmPriceWad() alone.

NatSpec on doubOwedForBuy / _sampleCharmAnchor, PARAMETERS.md, kumbaya.md, and invariants INV-TIME-ARENA-DOUB-OWED-PREVIEW document when external oracle calls happen and why preview differs from stale effective price. Forge adds test_doubOwedForBuy_matches_buy_within_epoch and test_doubOwedForBuy_matches_buy_at_hard_reset_boundary in TimeArenaEpochCharmPrice.t.sol. TimeArena ABI JSON (and bot ABI) set doubOwedForBuy to stateMutability: view.

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

## Summary - Make `TimeArena.doubOwedForBuy` **`view`** (staticcall-safe) — external TWAP/spot reads in `_sampleCharmAnchor` do not mutate state. - Document hard-reset boundary vs `effectiveCharmPriceWad()` in NatSpec, `PARAMETERS.md`, `kumbaya.md`, and invariants (`INV-TIME-ARENA-DOUB-OWED-PREVIEW`). - Add Forge tests asserting `doubOwedForBuy(charm)` equals immediate `buy` DOUB pull within epoch and at hard-reset boundary. - Sync `TimeArena` ABI JSON (`doubOwedForBuy` → `stateMutability: view`). ## Verification checklist (issue #315) | Acceptance item | Command / evidence | Result | |-----------------|-------------------|--------| | Documented when external calls occur and why | NatSpec on `doubOwedForBuy` / `_sampleCharmAnchor`; `PARAMETERS.md`; `kumbaya.md` § doubOwedForBuy; invariants §315 | **PASS** | | Integrators have staticcall-safe preview path | `doubOwedForBuy` is `view`; ABI `stateMutability: view` | **PASS** | | Forge test: hard-reset boundary pricing | `cd contracts && forge test --match-contract TimeArenaEpochCharmPrice` — `test_doubOwedForBuy_matches_buy_at_hard_reset_boundary`, `test_doubOwedForBuy_matches_buy_within_epoch` | **PASS** (9/9) | | NatSpec + PARAMETERS explain non-view → view decision | Contract NatSpec + `PARAMETERS.md` row | **PASS** | | `doubOwedForBuy(charm) ==` actual DOUB on immediate `buy` | `test_doubOwedForBuy_matches_buy_*` | **PASS** | | Router ABI unchanged (router calls view fn) | `bash scripts/verify-time-arena-buy-router-anvil.sh` | **PASS** | | TWAP sandwich assumption documented | `kumbaya.md` + invariants §315 manipulation note | **PASS** | <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **Low Risk** > Pricing-preview and documentation change with parity tests; buy execution path unchanged aside from explicit view mutability on an existing helper. > > **Overview** > **`TimeArena.doubOwedForBuy`** is now **`view`** so integrators can **`staticcall`/`eth_call`** a DOUB preview without mutating state. TWAP/spot reads in **`_sampleCharmAnchor`** stay read-only on that path; at the Last Buy hard-reset band the preview uses the same sampled anchor as an immediate **`buy`**, not **`effectiveCharmPriceWad()`** alone. > > NatSpec on **`doubOwedForBuy`** / **`_sampleCharmAnchor`**, **`PARAMETERS.md`**, **`kumbaya.md`**, and invariants **`INV-TIME-ARENA-DOUB-OWED-PREVIEW`** document when external oracle calls happen and why preview differs from stale effective price. **Forge** adds **`test_doubOwedForBuy_matches_buy_within_epoch`** and **`test_doubOwedForBuy_matches_buy_at_hard_reset_boundary`** in **`TimeArenaEpochCharmPrice.t.sol`**. **`TimeArena`** ABI JSON (and bot ABI) set **`doubOwedForBuy`** to **`stateMutability: view`**. > > <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit 1a4c39440bea263030dec905967bbabf7b5c2e0f. Bugbot is set up for automated code reviews on this repo. Configure [here](https://www.cursor.com/dashboard/bugbot).</sup> <!-- /CURSOR_SUMMARY -->
project_80561744_bot_5118c68a88bff95eacb6ab1c47c19cae commented 2026-06-13 13:29:37 +00:00 (Migrated from gitlab.com)

changed the description

changed the description
project_80561744_bot_5118c68a88bff95eacb6ab1c47c19cae commented 2026-06-13 13:29:46 +00:00 (Migrated from gitlab.com)

changed the description

changed the description
PlasticDigits commented 2026-06-13 13:33:11 +00:00 (Migrated from gitlab.com)

Security review — MR !474

Commit reviewed: 0722599ccd5598148b1ec4fa2f33ca5b6b888692
Scope: TimeArena.doubOwedForBuy / _sampleCharmAnchor view mutability; NatSpec + docs (PARAMETERS.md, kumbaya.md, invariants); parity Forge tests; ABI JSON sync; router comment only.

Outcome: FINDINGS: 0 medium+

Summary

Reviewed attacker-controlled inputs through pricing sinks (doubOwedForBuy → _sampleCharmAnchor / effectiveCharmPriceWad; TimeArenaBuyRouter.buyViaKumbaya → buyFor → _buyDoub → _pullDoubExact). This MR does not alter buy routing, DOUB pull math, re-anchor logic, or oracle libraries — it correctly marks already read-only preview paths as view and documents hard-reset preview parity.

Checked (no exploitable path on this diff):

  • Preview vs execution parity: Hard-reset band preview samples _sampleCharmAnchor() before state writes; _buyDoub calls _prepareBuyBeforeTimer() → _reanchorEpochCharmPrice() (same anchor) then effectiveCharmPriceWad() at epochAnchorTimestamp == block.timestamp. Parity tests pass (TimeArenaEpochCharmPrice.t.sol::test_doubOwedForBuy_matches_buy_*).
  • Router atomicity: buyViaKumbaya reads doubOwedForBuy and calls buyFor in one nonReentrant tx — no cross-tx preview/execution gap for router sizing.
  • Oracle / TWAP manipulation: Production anchor uses 15-minute V3 TWAP with spot/TWAP deviation bounds (ArenaCharmPriceTwap); documented same-block preview assumption is consistent with in-tx reads. Not introduced by this MR.
  • Reentrancy / access control: No new external mutating calls; buyFor remains router-gated; view does not weaken nonReentrant on buy paths.
  • Offchain surfaces: Docs/ABI only — no SQL/shell/SSRF/XSS/deserialization changes.

Prior security threads: None on this MR.

Inline findings: None (no medium+ issues to thread).

## Security review — MR !474 **Commit reviewed:** `0722599ccd5598148b1ec4fa2f33ca5b6b888692` **Scope:** `TimeArena.doubOwedForBuy` / `_sampleCharmAnchor` `view` mutability; NatSpec + docs (`PARAMETERS.md`, `kumbaya.md`, invariants); parity Forge tests; ABI JSON sync; router comment only. **Outcome:** `FINDINGS: 0` medium+ ### Summary Reviewed attacker-controlled inputs through pricing sinks (`doubOwedForBuy` → `_sampleCharmAnchor` / `effectiveCharmPriceWad`; `TimeArenaBuyRouter.buyViaKumbaya` → `buyFor` → `_buyDoub` → `_pullDoubExact`). This MR does **not** alter buy routing, DOUB pull math, re-anchor logic, or oracle libraries — it correctly marks already read-only preview paths as `view` and documents hard-reset preview parity. **Checked (no exploitable path on this diff):** - **Preview vs execution parity:** Hard-reset band preview samples `_sampleCharmAnchor()` before state writes; `_buyDoub` calls `_prepareBuyBeforeTimer()` → `_reanchorEpochCharmPrice()` (same anchor) then `effectiveCharmPriceWad()` at `epochAnchorTimestamp == block.timestamp`. Parity tests pass (`TimeArenaEpochCharmPrice.t.sol::test_doubOwedForBuy_matches_buy_*`). - **Router atomicity:** `buyViaKumbaya` reads `doubOwedForBuy` and calls `buyFor` in one `nonReentrant` tx — no cross-tx preview/execution gap for router sizing. - **Oracle / TWAP manipulation:** Production anchor uses 15-minute V3 TWAP with spot/TWAP deviation bounds (`ArenaCharmPriceTwap`); documented same-block preview assumption is consistent with in-tx reads. Not introduced by this MR. - **Reentrancy / access control:** No new external mutating calls; `buyFor` remains router-gated; `view` does not weaken `nonReentrant` on `buy` paths. - **Offchain surfaces:** Docs/ABI only — no SQL/shell/SSRF/XSS/deserialization changes. **Prior security threads:** None on this MR. **Inline findings:** None (no medium+ issues to thread).
PlasticDigits commented 2026-06-13 14:14:42 +00:00 (Migrated from gitlab.com)

Resolved merge conflicts with main (4 files):

  • contracts/PARAMETERS.md — kept main's expanded doubOwedForBuy row (780s band + router sizing note).
  • contracts/src/arena/TimeArena.sol — merged NatSpec from both sides; retained _sampleCharmAnchor preview comment.
  • docs/testing/invariants-and-business-logic.md — kept main's §315 section (timearena-doub-owed-preview-gitlab-315).
  • frontend/public/abis/TimeArena.json — rebased on main ABI (drops stale adminSellVault / initialize args) with doubOwedForBuy → view.

Also deduped auto-merged TimeArenaEpochCharmPrice.t.sol tests and duplicate kumbaya.md §315 paragraph.

Sanity: forge test --match-contract TimeArenaEpochCharmPrice — 9/9 PASS.

Resolved merge conflicts with `main` (4 files): - **`contracts/PARAMETERS.md`** — kept main's expanded `doubOwedForBuy` row (780s band + router sizing note). - **`contracts/src/arena/TimeArena.sol`** — merged NatSpec from both sides; retained `_sampleCharmAnchor` preview comment. - **`docs/testing/invariants-and-business-logic.md`** — kept main's §315 section (`timearena-doub-owed-preview-gitlab-315`). - **`frontend/public/abis/TimeArena.json`** — rebased on main ABI (drops stale `adminSellVault` / `initialize` args) with `doubOwedForBuy` → `view`. Also deduped auto-merged `TimeArenaEpochCharmPrice.t.sol` tests and duplicate `kumbaya.md` §315 paragraph. Sanity: `forge test --match-contract TimeArenaEpochCharmPrice` — 9/9 PASS.
PlasticDigits commented 2026-06-13 14:14:42 +00:00 (Migrated from gitlab.com)

added 31 commits

  • 0722599c...8dd57052 - 30 commits from branch main
  • 1a4c3944 - Merge branch 'main' into verify/issue-315-doub-owed-preview

Compare with previous version

added 31 commits <ul><li>0722599c...8dd57052 - 30 commits from branch <code>main</code></li><li>1a4c3944 - Merge branch &#39;main&#39; into verify/issue-315-doub-owed-preview</li></ul> [Compare with previous version](/PlasticDigits/yieldomega/-/merge_requests/104/diffs?diff_id=1850345853&start_sha=0722599ccd5598148b1ec4fa2f33ca5b6b888692)
project_80561744_bot_5118c68a88bff95eacb6ab1c47c19cae commented 2026-06-13 14:15:04 +00:00 (Migrated from gitlab.com)

changed the description

changed the description
PlasticDigits commented 2026-06-13 14:17:07 +00:00 (Migrated from gitlab.com)

Security review — MR !474

Commit reviewed: 1a4c39440bea263030dec905967bbabf7b5c2e0f
Diff base: 8dd5705214196809a61134461e8b737f83eae5b7 (post-merge with main)
Scope: NatSpec on TimeArena.doubOwedForBuy / _sampleCharmAnchor; router comment; kumbaya.md whitespace; TimeArena ABI JSON sync (doubOwedForBuy → stateMutability: view). No Solidity logic changes vs base.

Outcome: FINDINGS: 0 medium+

Summary

Re-reviewed attacker-controlled inputs through pricing sinks (doubOwedForBuy → _sampleCharmAnchor / effectiveCharmPriceWad; TimeArenaBuyRouter.buyViaKumbaya → buyFor → _buyDoub → _pullDoubExact). This MR delta is documentation and ABI metadata only — buy routing, DOUB pull math, re-anchor logic, and oracle libraries are unchanged from base.

Checked (no exploitable path on this diff):

  • Preview vs execution parity: Hard-reset band preview samples _sampleCharmAnchor() before state writes; _buyDoub calls _prepareBuyBeforeTimer() → _reanchorEpochCharmPrice() (same anchor) then effectiveCharmPriceWad() at epochAnchorTimestamp == block.timestamp. Covered by TimeArenaEpochCharmPrice.t.sol::test_doubOwedForBuy_matches_buy_* (on branch; not in this delta).
  • Router atomicity: buyViaKumbaya reads doubOwedForBuy and calls buyFor in one nonReentrant tx — no cross-tx preview/execution gap for router sizing.
  • Oracle / TWAP manipulation: Production anchor uses 15-minute V3 TWAP with spot/TWAP deviation bounds (ArenaCharmPriceTwap); documented same-block preview assumption is consistent with in-tx reads. Not introduced by this MR.
  • Reentrancy / access control: No new external mutating calls; buyFor remains router-gated; view mutability unchanged from base.
  • Offchain surfaces: Docs/ABI only — no SQL/shell/SSRF/XSS/deserialization changes.

Prior security threads: Top-level review at 0722599c (pre-merge) — same outcome; no inline findings. Re-validated after merge commit 1a4c3944.

Inline findings: None (no medium+ issues to thread).

## Security review — MR !474 **Commit reviewed:** `1a4c39440bea263030dec905967bbabf7b5c2e0f` **Diff base:** `8dd5705214196809a61134461e8b737f83eae5b7` (post-merge with `main`) **Scope:** NatSpec on `TimeArena.doubOwedForBuy` / `_sampleCharmAnchor`; router comment; `kumbaya.md` whitespace; `TimeArena` ABI JSON sync (`doubOwedForBuy` → `stateMutability: view`). No Solidity logic changes vs base. **Outcome:** `FINDINGS: 0` medium+ ### Summary Re-reviewed attacker-controlled inputs through pricing sinks (`doubOwedForBuy` → `_sampleCharmAnchor` / `effectiveCharmPriceWad`; `TimeArenaBuyRouter.buyViaKumbaya` → `buyFor` → `_buyDoub` → `_pullDoubExact`). This MR delta is documentation and ABI metadata only — buy routing, DOUB pull math, re-anchor logic, and oracle libraries are unchanged from base. **Checked (no exploitable path on this diff):** - **Preview vs execution parity:** Hard-reset band preview samples `_sampleCharmAnchor()` before state writes; `_buyDoub` calls `_prepareBuyBeforeTimer()` → `_reanchorEpochCharmPrice()` (same anchor) then `effectiveCharmPriceWad()` at `epochAnchorTimestamp == block.timestamp`. Covered by `TimeArenaEpochCharmPrice.t.sol::test_doubOwedForBuy_matches_buy_*` (on branch; not in this delta). - **Router atomicity:** `buyViaKumbaya` reads `doubOwedForBuy` and calls `buyFor` in one `nonReentrant` tx — no cross-tx preview/execution gap for router sizing. - **Oracle / TWAP manipulation:** Production anchor uses 15-minute V3 TWAP with spot/TWAP deviation bounds (`ArenaCharmPriceTwap`); documented same-block preview assumption is consistent with in-tx reads. Not introduced by this MR. - **Reentrancy / access control:** No new external mutating calls; `buyFor` remains router-gated; `view` mutability unchanged from base. - **Offchain surfaces:** Docs/ABI only — no SQL/shell/SSRF/XSS/deserialization changes. **Prior security threads:** Top-level review at `0722599c` (pre-merge) — same outcome; no inline findings. Re-validated after merge commit `1a4c3944`. **Inline findings:** None (no medium+ issues to thread).
PlasticDigits (Migrated from gitlab.com) merged commit 2f53f814df into main 2026-06-14 02:36:19 +00:00
PlasticDigits commented 2026-06-14 02:36:20 +00:00 (Migrated from gitlab.com)

mentioned in commit 2f53f814df

mentioned in commit 2f53f814df33dbb4070575ad56833f8e119eb6fd
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!474
No description provided.