Route buy prize remainder to Last Buy category (#313) #458

Merged
PlasticDigits merged 1 commit from issue-313-buy-remainder-last-buy into main 2026-06-13 09:27:29 +00:00
PlasticDigits commented 2026-06-13 07:59:32 +00:00 (Migrated from gitlab.com)

Summary

Routes the cross-category buy prize remainder (amount % 4 wei) to Last Buy (category 0) instead of WarBow (category 3), per approved economics from #309. Tied to #313.

  • ArenaBuyRouting.splitBuyAmount: remainder assignment moved from i == 3 to i == 0.
  • Tests: updated unit + fuzz assertions; added explicit fuzz check that non-zero remainder lands on cat 0.
  • Docs: PARAMETERS.md, product specs, onchain routing docs, invariants, and skills/play-time-arena-doub/SKILL.md now document Last Buy remainder rule.

100% podium routing invariant (#300) unchanged — only the remainder bucket moves.

Acceptance checklist

Criterion Verification Result
amount % 4 wei routes to Last Buy vault/tranche cd contracts && forge test --match-contract ArenaPrizeRouting -vv (test_split_remainder_to_last_buy_and_t10_tranche, testFuzz_epoch_split_per_category_bps) PASS
All Forge routing tests updated and pass cd contracts && forge test --match-test buy_routes -vv PASS
Product docs reflect Last Buy remainder rule Review PARAMETERS.md, docs/product/arena-v2.md, docs/product/time-arena.md, docs/onchain/fee-routing-and-governance.md PASS

Verification for third parties

export PATH="$HOME/.foundry/bin:$PATH"
cd contracts
forge test --match-contract ArenaPrizeRouting -vv
forge test --match-test buy_routes -vv

Confirm contracts/src/arena/libraries/ArenaBuyRouting.sol assigns catRem when i == 0 and docs cite Last Buy for category remainder.

  • Parent gap analysis: #309
  • Unchanged: 100% podium routing (#300), within-category remainder → epoch+2 tranche

Note

Medium Risk
Onchain prize split behavior changes for every DOUB buy when amount is not divisible by 4, shifting up to 3 wei per buy to Last Buy vaults; scope is small but economically documented and live for TimeArena.

Overview
Per #313, ArenaBuyRouting.splitBuyAmount now assigns the amount % 4 cross-category remainder to Last Buy (category 0) instead of category 3. The 100% podium / 25% × 4 / 70·20·10 buy routing (#300) is unchanged; only which bucket gets the extra 0–3 wei moves.

Tests in ArenaPrizeRouting.t.sol rename and flip the remainder case (e.g. 1003 → cat 0 gets 253), align fuzz with i == 0, and assert non-zero remainder lands on Last Buy.

Docs (PARAMETERS.md, product/onchain specs, threat model, invariants §300, skills/play-time-arena-doub) now describe Last Buy as the remainder target; splitPrizeTopUpAmount is untouched.

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

## Summary Routes the cross-category buy prize remainder (`amount % 4` wei) to **Last Buy (category 0)** instead of WarBow (category 3), per approved economics from #309. Tied to #313. - **`ArenaBuyRouting.splitBuyAmount`**: remainder assignment moved from `i == 3` to `i == 0`. - **Tests**: updated unit + fuzz assertions; added explicit fuzz check that non-zero remainder lands on cat 0. - **Docs**: `PARAMETERS.md`, product specs, onchain routing docs, invariants, and `skills/play-time-arena-doub/SKILL.md` now document Last Buy remainder rule. 100% podium routing invariant (#300) unchanged — only the remainder bucket moves. ## Acceptance checklist | Criterion | Verification | Result | |-----------|--------------|--------| | `amount % 4` wei routes to Last Buy vault/tranche | `cd contracts && forge test --match-contract ArenaPrizeRouting -vv` (`test_split_remainder_to_last_buy_and_t10_tranche`, `testFuzz_epoch_split_per_category_bps`) | PASS | | All Forge routing tests updated and pass | `cd contracts && forge test --match-test buy_routes -vv` | PASS | | Product docs reflect Last Buy remainder rule | Review `PARAMETERS.md`, `docs/product/arena-v2.md`, `docs/product/time-arena.md`, `docs/onchain/fee-routing-and-governance.md` | PASS | ## Verification for third parties ```bash export PATH="$HOME/.foundry/bin:$PATH" cd contracts forge test --match-contract ArenaPrizeRouting -vv forge test --match-test buy_routes -vv ``` Confirm `contracts/src/arena/libraries/ArenaBuyRouting.sol` assigns `catRem` when `i == 0` and docs cite **Last Buy** for category remainder. ## Related - Parent gap analysis: #309 - Unchanged: 100% podium routing (#300), within-category remainder → epoch+2 tranche <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **Medium Risk** > Onchain prize split behavior changes for every DOUB buy when amount is not divisible by 4, shifting up to 3 wei per buy to Last Buy vaults; scope is small but economically documented and live for TimeArena. > > **Overview** > Per **#313**, **`ArenaBuyRouting.splitBuyAmount`** now assigns the **`amount % 4`** cross-category remainder to **Last Buy (category 0)** instead of category 3. The **100% podium / 25% × 4 / 70·20·10** buy routing (**#300**) is unchanged; only which bucket gets the extra 0–3 wei moves. > > **Tests** in **`ArenaPrizeRouting.t.sol`** rename and flip the remainder case (e.g. 1003 → cat 0 gets 253), align fuzz with **`i == 0`**, and assert non-zero remainder lands on Last Buy. > > **Docs** (**`PARAMETERS.md`**, product/onchain specs, threat model, invariants **§300**, **`skills/play-time-arena-doub`**) now describe **Last Buy** as the remainder target; **`splitPrizeTopUpAmount`** is untouched. > > <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit d034ca7be7d74fdbfa64621544734c053b786617. 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 07:59:41 +00:00 (Migrated from gitlab.com)

changed the description

changed the description
project_80561744_bot_5118c68a88bff95eacb6ab1c47c19cae commented 2026-06-13 07:59:49 +00:00 (Migrated from gitlab.com)

changed the description

changed the description
PlasticDigits commented 2026-06-13 08:01:24 +00:00 (Migrated from gitlab.com)

Security review — MR !458

Commit reviewed: d034ca7be7d74fdbfa64621544734c053b786617
Scope: ArenaBuyRouting.splitBuyAmount remainder bucket (cat 3 → cat 0), associated Forge tests, and documentation updates for #313.

Method

  • Diff and call-site trace: splitBuyAmount → TimeArena._routeDoubPrizeSplit (unchanged transfer/notify loop).
  • Verified conservation invariant (testFuzz_splitBuy_no_dust: Σ tranches == amount) still holds; only the remainder recipient index changes.
  • Checked for attacker-controlled input → exploitable sink (reentrancy, auth bypass, dust theft, rounding drift, category-index confusion).
  • No prior security-review threads on this MR to reconcile.

Outcome

FINDINGS: 0 medium+

No inline threads — nothing met the reporting bar.

Notes (informational, not findings)

  • Intended economics change: at most 3 wei per buy (amount % 4) moves from category 3 (WarBow) to category 0 (Last Buy). Callers cannot redirect remainder elsewhere; fuzz tests enforce exact allocation and zero dust.
  • Unchanged attack surface: buy path still uses balance-delta parity, CEI-style routing, and 0% admin take on buys. splitPrizeTopUpAmount untouched.
  • Offchain: no indexer/frontend/runtime code in this diff — docs only.

Security review: no medium+ findings on this diff.

## Security review — MR !458 **Commit reviewed:** `d034ca7be7d74fdbfa64621544734c053b786617` **Scope:** `ArenaBuyRouting.splitBuyAmount` remainder bucket (cat 3 → cat 0), associated Forge tests, and documentation updates for #313. ### Method - Diff and call-site trace: `splitBuyAmount` → `TimeArena._routeDoubPrizeSplit` (unchanged transfer/notify loop). - Verified conservation invariant (`testFuzz_splitBuy_no_dust`: Σ tranches == `amount`) still holds; only the remainder recipient index changes. - Checked for attacker-controlled input → exploitable sink (reentrancy, auth bypass, dust theft, rounding drift, category-index confusion). - No prior security-review threads on this MR to reconcile. ### Outcome **FINDINGS: 0** medium+ No inline threads — nothing met the reporting bar. ### Notes (informational, not findings) - **Intended economics change:** at most **3 wei** per buy (`amount % 4`) moves from category 3 (WarBow) to category 0 (Last Buy). Callers cannot redirect remainder elsewhere; fuzz tests enforce exact allocation and zero dust. - **Unchanged attack surface:** buy path still uses balance-delta parity, CEI-style routing, and 0% admin take on buys. `splitPrizeTopUpAmount` untouched. - **Offchain:** no indexer/frontend/runtime code in this diff — docs only. **Security review: no medium+ findings on this diff.**
PlasticDigits (Migrated from gitlab.com) merged commit 729570edf4 into main 2026-06-13 09:27:29 +00:00
PlasticDigits commented 2026-06-13 09:27:30 +00:00 (Migrated from gitlab.com)

mentioned in commit 729570edf4

mentioned in commit 729570edf4be55afe9565278e752a735e645508b
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!458
No description provided.