WarBow steal: tighten BP eligibility band (2×–10× victim vs attacker) #211

Closed
opened 2026-05-17 13:45:29 +00:00 by PlasticDigits · 12 comments
PlasticDigits commented 2026-05-17 13:45:29 +00:00 (Migrated from gitlab.com)

Problem

TimeCurve.warbowSteal currently allows any victim with victimBP ≥ 2 × attackerBP (and attackerBP > 0). That makes multi-wallet “shark” swarms economically attractive against a distant BP leader: many low-BP accounts can each satisfy the 2× rule against a whale and repeatedly drain 10% slices (subject to UTC-day caps / bypass / guard / revenge), which undermines the intended peer rivalry framing for the WarBow ladder and reserve podium category.

Proposed solution

Add an upper bracket symmetric to the existing lower bound: require the victim’s BP to sit in a finite band relative to the attacker:

  • Keep: victimBP ≥ 2 × attackerBP (existing underdog-vs-uphill framing).
  • Add: victimBP ≤ 10 × attackerBP (prevents micro-wallets from treating a far-ahead leader as an oversized farm).

Onchain (minimal bytecode change): extend the single require in warbowSteal so both bounds are enforced in one guard (same tx ordering as today: CL8Y pulls already happened before the check — unchanged).

Revert string / UX: Today the contract uses TimeCurve: steal 2x rule for the lower-bound failure only. Options (pick in MR):

  1. Single compound require with a new consolidated message (e.g. TimeCurve: steal bp band) and map it in friendlyRevertMessage / docs; or
  2. Two requires (still tiny) with distinct reverts for lower vs upper bound to preserve precise wallet error copy without ambiguous strings.

Constants 2 and 10 may stay literals in v1 (matching existing 2 * abp style) or move to named uint8 / uint16 immutable-style public constants if governance wants visibility (slightly larger diff).

Solidity (authoritative)

  • contracts/src/TimeCurve.sol — warbowSteal: NatSpec + require for BP bracket.
  • contracts/PARAMETERS.md — TimeCurve / WarBow table if steal eligibility is summarized.

Foundry tests

  • contracts/test/TimeCurve.t.sol — test_warbow_steal_revert_2x_rule, fuzz sequences that assert vbp >= 2 * abp mid-sequence, multi-stealer / daily-cap / drain tests that assume unbounded upper ratio; add test_warbow_steal_revert_victim_too_far_above_attacker (name TBD) for vbp > 10 * abp.
  • contracts/test/TimeCurveWarBowCl8yBurns.t.sol — setups that grant victim ≥ 2× stealer; ensure victims are not > 10× unless the test explicitly targets the new revert.

Frontend — preflight & copy

  • frontend/src/lib/timeCurveUx.ts — describeStealPreflight: add upper band branch (titles/detail distinct from lower band); success copy must say 2×–10× (not “passes the 2x rule” alone).
  • frontend/src/lib/timeCurveUx.test.ts — extend describeStealPreflight expectations for too-low vs too-high victim BP.

Frontend — Arena hero / steal discovery

  • frontend/src/pages/timeCurveArena/useTimeCurveArenaModel.tsx — canSuggest (currently battlePoints >= viewerBp * 2n only); warbowStealProspectCandidates (prospects are “below 2× threshold”; redefine or split for above 10× “out of band” rows vs true prospects); comments referencing “2×” only.
  • frontend/src/pages/timeCurveArena/WarbowHeroActions.tsx — hero copy (“Steal 10%… 2x your BP”), empty-state “No indexed 2x BP steal target yet” → band-aware wording.
  • frontend/src/pages/timeCurveArena/WarbowHeroActions.test.tsx — candidate counts / strings / bpBelowStealThreshold semantics after bracket.

Frontend — Simple / misc

  • frontend/src/pages/timecurve/TimeCurveSections.tsx — WarBow steal explainer + meta="Must be at least 2x your BP".
  • frontend/src/pages/timecurve/TimeCurveSimpleAgentCard.tsx — Python pseudo-card steal line hbp >= 2 * abp (align with band for agent examples).

Frontend — revert friendliness

  • frontend/src/lib/revertMessage.ts + frontend/src/lib/revertMessage.test.ts — map new or existing revert substring to human copy.

Docs (product + contributor)

  • docs/product/primitives.md — § Steal (warbowSteal): document 2×–10× bracket; WarBow ladder intro if it says “≥ 2×” only.
  • docs/testing/invariants-and-business-logic.md — INV-WARBOW-134-RANK (and any row citing only 2×); § GitLab #134 WarBow steal rules; Arena #101 / #182 / live podium rows that mention “2× BP rule”; EcoStrategy / Forge test map bullets that name test_warbow_steal_revert_2x_rule.
  • docs/frontend/timecurve-views.md — Arena WarBow hero actions / steal candidate discovery text.
  • docs/testing/manual-qa-checklists.md — any WarBow / Arena steal rows (grep 2x / WarBow / steal).

Player / contributor skills & indices

  • skills/play-timecurve-warbow/SKILL.md — Steal “ranking” bullet: 2×–10× bracket, UTC caps unchanged.
  • skills/README.md — index row for play-timecurve-warbow if it paraphrases steal rule.
  • .cursor/skills/yieldomega-guardrails/SKILL.md — issue #134 / Arena WarBow line: “2×” → “BP bracket (2×–10×)” if spelled out.

Bots & local PvP harness

  • bots/timecurve/src/timecurve_bot/strategies/pvp.py — preflight vbp < 2 * max(abp, 1) → also warn / block when vbp > 10 * max(abp, 1).
  • bots/timecurve/README.md — pvp strategy doc if it mentions 2× only.
  • bots/timecurve/src/timecurve_bot/abis/timecurve.json — only if ABI/regen workflow touches NatSpec selectors (usually unchanged for warbowSteal signature).

Simulations (EcoStrategy mirror)

  • simulations/ecostrategy/warbow_pvp.py — can_steal / try_steal eligibility: add vbp <= 10 * abp (or equivalent).
  • simulations/ecostrategy/constants.py — manifest string “TimeCurve — 2× steal eligibility” → describe 2×–10× band.
  • simulations/tests/test_ecostrategy.py — test_two_x_rule_blocks_steal → extend / rename to cover upper bound (victim_bp > 10 * attacker_bp blocks).
  • simulations/README.md — WarBowWorld bullet if it says “2× eligibility” only.

Audits (historical narrative)

  • audits/audit_ecostrategy_1777969776.md — paragraph describing WarBow 2× rule (mark as superseded by bracket or add errata footnote).

Indexer / API

  • No indexer SQL change expected (steals are not validated offchain). Grep 2x / steal in indexer/ for docstrings or fixture text only.

Launch / ops docs (optional grep)

  • launchplan-timecurve.md, YO-DOUB-Launch-UX-Flows.md, contracts/README.md — if they mention steal BP rule in prose.

Suggested implementation notes

  1. Contract: After pulls, enforce
    abp > 0 && vbp >= 2 * abp && vbp <= 10 * abp
    (same revert policy as agreed above).
  2. TS helper: Centralize isWarbowStealBpBandOk(viewerBp, victimBp): boolean or describeWarbowStealBpBand(...) in timeCurveUx.ts (or small warbowStealBpBand.ts) so Arena model + preflight + tests share one definition.
  3. Arena prospects: Redefine “prospect” rows:
    • Too weak: victimBP < 2 × viewerBP (current prospect list intent).
    • Too strong: victimBP > 10 × viewerBP — optional separate label/tooltip so players understand why a visible ladder whale is not stealable.
  4. Constants: If 10 appears in many places, export WARBOW_STEAL_VICTIM_MAX_MULT = 10 from a single frontend module mirroring contract intent (contracts may keep literals for minimal bytecode unless you add public getters).

Testing guide

  1. Forge: forge test --match-contract TimeCurve (or targeted --match-test warbow_steal) — add explicit revert when victim is 21× attacker with attacker > 0; keep existing lower-bound revert test; fuzz sequences that previously relied on vbp >> abp must be adjusted.
  2. Vitest: frontend/src/lib/timeCurveUx.test.ts, WarbowHeroActions.test.tsx, revertMessage.test.ts.
  3. EcoStrategy: cd simulations && PYTHONPATH=. python3 -m unittest discover -s tests -v — update WarBowWorld tests.
  4. Manual / Anvil: Run a local sale, connect wallet A (low BP) and attempt steal on wallet B with huge BP — UI preflight should show upper band failure before signing; onchain tx should revert if forced.
  5. Bots (optional): pvp dry-run with mis-sized BP should print the new guard hint.

Acceptance criteria

  • Onchain warbowSteal reverts unless attackerBP > 0 and 2 × attackerBP ≤ victimBP ≤ 10 × attackerBP (exact inequality semantics match Solidity * uint256 math, no overflow for realistic BP values).
  • NatSpec + docs/product/primitives.md describe the full bracket; docs/testing/invariants-and-business-logic.md updated (INV-WARBOW-134-RANK or successor ID) so contributor map matches behavior.
  • describeStealPreflight and Arena steal candidate discovery match onchain rules (no UI that suggests a steal that will revert on the BP bracket alone).
  • friendlyRevertMessage (or equivalent) gives participants clear copy for whichever revert string ships.
  • Foundry + Vitest + EcoStrategy unit tests green in CI for touched areas.
  • skills/play-timecurve-warbow/SKILL.md (and any grep-hit launch docs that teach steals) aligned so agents/participants are not misled.

Labels / follow-ups

Consider labels: component::contracts, component::frontend, component::docs, area::timecurve, type::feature (behavior change), security::hardening (if used).

Upgrade / deployment: UUPS TimeCurve proxy — confirm maintainer process for bytecode upgrades, storage layout unchanged, and comms to live participants before mainnet cutover.

## Problem `TimeCurve.warbowSteal` currently allows any victim with **`victimBP ≥ 2 × attackerBP`** (and **`attackerBP > 0`**). That makes **multi-wallet “shark” swarms** economically attractive against a distant BP leader: many **low-BP** accounts can each satisfy the 2× rule against a **whale** and repeatedly drain **10%** slices (subject to UTC-day caps / bypass / guard / revenge), which undermines the intended **peer rivalry** framing for the WarBow ladder and reserve podium category. ## Proposed solution Add an **upper bracket** symmetric to the existing lower bound: require the victim’s BP to sit in a **finite band relative to the attacker**: - **Keep:** `victimBP ≥ 2 × attackerBP` (existing underdog-vs-uphill framing). - **Add:** `victimBP ≤ 10 × attackerBP` (prevents micro-wallets from treating a far-ahead leader as an oversized farm). **Onchain (minimal bytecode change):** extend the single `require` in `warbowSteal` so both bounds are enforced in one guard (same tx ordering as today: CL8Y pulls already happened before the check — unchanged). **Revert string / UX:** Today the contract uses **`TimeCurve: steal 2x rule`** for the lower-bound failure only. Options (pick in MR): 1. **Single compound `require`** with a **new** consolidated message (e.g. **`TimeCurve: steal bp band`**) and map it in `friendlyRevertMessage` / docs; or 2. **Two `require`s** (still tiny) with distinct reverts for lower vs upper bound to preserve precise wallet error copy without ambiguous strings. Constants **2** and **10** may stay **literals** in v1 (matching existing `2 * abp` style) **or** move to named `uint8` / `uint16` **immutable**-style public constants if governance wants visibility (slightly larger diff). ## Related files (thorough checklist) ### Solidity (authoritative) - `contracts/src/TimeCurve.sol` — `warbowSteal`: NatSpec + `require` for BP bracket. - `contracts/PARAMETERS.md` — TimeCurve / WarBow table if steal eligibility is summarized. ### Foundry tests - `contracts/test/TimeCurve.t.sol` — `test_warbow_steal_revert_2x_rule`, fuzz sequences that assert `vbp >= 2 * abp` mid-sequence, multi-stealer / daily-cap / drain tests that assume unbounded upper ratio; add **`test_warbow_steal_revert_victim_too_far_above_attacker`** (name TBD) for `vbp > 10 * abp`. - `contracts/test/TimeCurveWarBowCl8yBurns.t.sol` — setups that grant victim `≥ 2×` stealer; ensure victims are **not** `> 10×` unless the test explicitly targets the new revert. ### Frontend — preflight & copy - `frontend/src/lib/timeCurveUx.ts` — `describeStealPreflight`: add **upper band** branch (titles/detail distinct from lower band); success copy must say **2×–10×** (not “passes the 2x rule” alone). - `frontend/src/lib/timeCurveUx.test.ts` — extend `describeStealPreflight` expectations for too-low vs too-high victim BP. ### Frontend — Arena hero / steal discovery - `frontend/src/pages/timeCurveArena/useTimeCurveArenaModel.tsx` — `canSuggest` (currently `battlePoints >= viewerBp * 2n` only); **`warbowStealProspectCandidates`** (prospects are “below 2× threshold”; redefine or split for **above 10×** “out of band” rows vs true prospects); comments referencing “2×” only. - `frontend/src/pages/timeCurveArena/WarbowHeroActions.tsx` — hero copy (“Steal 10%… 2x your BP”), empty-state **“No indexed 2x BP steal target yet”** → band-aware wording. - `frontend/src/pages/timeCurveArena/WarbowHeroActions.test.tsx` — candidate counts / strings / `bpBelowStealThreshold` semantics after bracket. ### Frontend — Simple / misc - `frontend/src/pages/timecurve/TimeCurveSections.tsx` — WarBow steal explainer + `meta="Must be at least 2x your BP"`. - `frontend/src/pages/timecurve/TimeCurveSimpleAgentCard.tsx` — Python pseudo-card steal line `hbp >= 2 * abp` (align with band for agent examples). ### Frontend — revert friendliness - `frontend/src/lib/revertMessage.ts` + `frontend/src/lib/revertMessage.test.ts` — map new or existing revert substring to human copy. ### Docs (product + contributor) - `docs/product/primitives.md` — § Steal (`warbowSteal`): document **2×–10×** bracket; WarBow ladder intro if it says “≥ 2×” only. - `docs/testing/invariants-and-business-logic.md` — **`INV-WARBOW-134-RANK`** (and any row citing only 2×); § GitLab #134 WarBow steal rules; Arena #101 / #182 / live podium rows that mention “2× BP rule”; EcoStrategy / Forge test map bullets that name `test_warbow_steal_revert_2x_rule`. - `docs/frontend/timecurve-views.md` — Arena WarBow hero actions / steal candidate discovery text. - `docs/testing/manual-qa-checklists.md` — any WarBow / Arena steal rows (grep `2x` / `WarBow` / `steal`). ### Player / contributor skills & indices - `skills/play-timecurve-warbow/SKILL.md` — Steal “ranking” bullet: **2×–10×** bracket, UTC caps unchanged. - `skills/README.md` — index row for play-timecurve-warbow if it paraphrases steal rule. - `.cursor/skills/yieldomega-guardrails/SKILL.md` — issue #134 / Arena WarBow line: “2×” → “BP bracket (2×–10×)” if spelled out. ### Bots & local PvP harness - `bots/timecurve/src/timecurve_bot/strategies/pvp.py` — preflight `vbp < 2 * max(abp, 1)` → also warn / block when `vbp > 10 * max(abp, 1)`. - `bots/timecurve/README.md` — `pvp` strategy doc if it mentions 2× only. - `bots/timecurve/src/timecurve_bot/abis/timecurve.json` — only if ABI/regen workflow touches NatSpec selectors (usually unchanged for `warbowSteal` signature). ### Simulations (EcoStrategy mirror) - `simulations/ecostrategy/warbow_pvp.py` — `can_steal` / `try_steal` eligibility: add **`vbp <= 10 * abp`** (or equivalent). - `simulations/ecostrategy/constants.py` — manifest string **“TimeCurve — 2× steal eligibility”** → describe **2×–10×** band. - `simulations/tests/test_ecostrategy.py` — `test_two_x_rule_blocks_steal` → extend / rename to cover **upper** bound (`victim_bp > 10 * attacker_bp` blocks). - `simulations/README.md` — WarBowWorld bullet if it says “2× eligibility” only. ### Audits (historical narrative) - `audits/audit_ecostrategy_1777969776.md` — paragraph describing WarBow 2× rule (mark as superseded by bracket or add errata footnote). ### Indexer / API - **No indexer SQL change expected** (steals are not validated offchain). Grep `2x` / `steal` in `indexer/` for docstrings or fixture text only. ### Launch / ops docs (optional grep) - `launchplan-timecurve.md`, `YO-DOUB-Launch-UX-Flows.md`, `contracts/README.md` — if they mention steal BP rule in prose. --- ## Suggested implementation notes 1. **Contract:** After pulls, enforce `abp > 0 && vbp >= 2 * abp && vbp <= 10 * abp` (same revert policy as agreed above). 2. **TS helper:** Centralize `isWarbowStealBpBandOk(viewerBp, victimBp): boolean` or `describeWarbowStealBpBand(...)` in `timeCurveUx.ts` (or small `warbowStealBpBand.ts`) so Arena model + preflight + tests share one definition. 3. **Arena prospects:** Redefine “prospect” rows: - **Too weak:** `victimBP < 2 × viewerBP` (current prospect list intent). - **Too strong:** `victimBP > 10 × viewerBP` — optional separate label/tooltip so players understand why a visible ladder whale is not stealable. 4. **Constants:** If **10** appears in many places, export `WARBOW_STEAL_VICTIM_MAX_MULT = 10` from a single frontend module mirroring contract intent (contracts may keep literals for minimal bytecode unless you add public getters). --- ## Testing guide 1. **Forge:** `forge test --match-contract TimeCurve` (or targeted `--match-test warbow_steal`) — add explicit revert when victim is **21×** attacker with attacker `> 0`; keep existing lower-bound revert test; fuzz sequences that previously relied on `vbp >> abp` must be adjusted. 2. **Vitest:** `frontend/src/lib/timeCurveUx.test.ts`, `WarbowHeroActions.test.tsx`, `revertMessage.test.ts`. 3. **EcoStrategy:** `cd simulations && PYTHONPATH=. python3 -m unittest discover -s tests -v` — update `WarBowWorld` tests. 4. **Manual / Anvil:** Run a local sale, connect wallet A (low BP) and attempt steal on wallet B with huge BP — UI preflight should show **upper band** failure **before** signing; onchain tx should revert if forced. 5. **Bots (optional):** `pvp` dry-run with mis-sized BP should print the new guard hint. --- ## Acceptance criteria - [x] Onchain `warbowSteal` **reverts** unless **`attackerBP > 0`** and **`2 × attackerBP ≤ victimBP ≤ 10 × attackerBP`** (exact inequality semantics match Solidity `*` uint256 math, no overflow for realistic BP values). - [x] NatSpec + **`docs/product/primitives.md`** describe the **full bracket**; **`docs/testing/invariants-and-business-logic.md`** updated (**`INV-WARBOW-134-RANK`** or successor ID) so contributor map matches behavior. - [x] **`describeStealPreflight`** and Arena steal candidate discovery **match** onchain rules (no UI that suggests a steal that will revert on the BP bracket alone). - [x] **`friendlyRevertMessage`** (or equivalent) gives participants clear copy for whichever revert string ships. - [x] **Foundry + Vitest + EcoStrategy unit tests** green in CI for touched areas. - [ ] **`skills/play-timecurve-warbow/SKILL.md`** (and any grep-hit launch docs that teach steals) aligned so agents/participants are not misled. --- ## Labels / follow-ups Consider labels: `component::contracts`, `component::frontend`, `component::docs`, `area::timecurve`, `type::feature` (behavior change), `security::hardening` (if used). **Upgrade / deployment:** UUPS `TimeCurve` proxy — confirm maintainer process for bytecode upgrades, storage layout unchanged, and comms to live participants before mainnet cutover.
PlasticDigits commented 2026-05-17 15:09:50 +00:00 (Migrated from gitlab.com)

mentioned in commit 3cac3335fd

mentioned in commit 3cac3335fd5843aafc7374fd1dce94f27b30814d
PlasticDigits commented 2026-05-17 15:10:23 +00:00 (Migrated from gitlab.com)

Implemented (merged to main in 3cac333)

  • Onchain: TimeCurve.warbowSteal now enforces 2 × attackerBP ≤ victimBP ≤ 10 × attackerBP after CL8Y pulls; new revert TimeCurve: steal 10x cap (lower bound still TimeCurve: steal 2x rule). Forge: test_warbow_steal_revert_10x_cap, fuzz revenge test uses vm.assume for in-band draws.
  • Frontend: shared helper frontend/src/lib/warbowStealBpBand.ts; describeStealPreflight + Arena hero (in-band targets, Too low BP / Too high BP prospect rows) + friendlyRevertMessage copy; Simple WarBow copy + agent card pseudo-Python.
  • EcoStrategy / bots: WarBowWorld.can_steal + constants manifest; pvp.py dry-run guards; UTC rollover unittest now uses a fresh victim on the new UTC day (same victim cannot stay in-band for a 4th steal after three 10% drains without new BP — matches onchain economics).
  • Docs / skills: docs/product/primitives.md, invariants INV-WARBOW-134-RANK + §134 forge row, timecurve-views, PARAMETERS.md, skills/play-timecurve-warbow, skills/README.md, contributor guardrails skill, audit M-02 narrative footnote.

Verification checklist (for @brouie)

  • Forge: cd contracts && forge test --match-test warbow_steal and --match-test warbow_revenge_distinct_stealer (or full TimeCurve suite in CI).
  • Vitest: frontend — warbowStealBpBand.test.ts, timeCurveUx.test.ts, revertMessage.test.ts, WarbowHeroActions.test.tsx.
  • EcoStrategy: cd simulations && PYTHONPATH=. python3 -m unittest discover -s tests -v.
  • Manual / Anvil: low-BP wallet vs ladder whale — hero shows Too high BP (or preflight Victim BP too far above yours); forced warbowSteal reverts steal 10x cap; in-band rival still steals normally.
  • Cross-links: GitLab #211 ↔ docs/testing/invariants-and-business-logic.md §134 / docs/product/primitives.md / skills/play-timecurve-warbow/SKILL.md.

Please confirm behavior on your target deployment (UUPS bytecode upgrade path is out of scope for this MR but called out in the issue).

## Implemented (merged to `main` in 3cac333) - **Onchain:** `TimeCurve.warbowSteal` now enforces **`2 × attackerBP ≤ victimBP ≤ 10 × attackerBP`** after CL8Y pulls; new revert **`TimeCurve: steal 10x cap`** (lower bound still **`TimeCurve: steal 2x rule`**). Forge: `test_warbow_steal_revert_10x_cap`, fuzz revenge test uses `vm.assume` for in-band draws. - **Frontend:** shared helper [`frontend/src/lib/warbowStealBpBand.ts`](frontend/src/lib/warbowStealBpBand.ts); `describeStealPreflight` + Arena hero (in-band targets, **Too low BP** / **Too high BP** prospect rows) + `friendlyRevertMessage` copy; Simple WarBow copy + agent card pseudo-Python. - **EcoStrategy / bots:** `WarBowWorld.can_steal` + constants manifest; `pvp.py` dry-run guards; UTC rollover unittest now uses a **fresh victim** on the new UTC day (same victim cannot stay in-band for a 4th steal after three 10% drains without new BP — matches onchain economics). - **Docs / skills:** `docs/product/primitives.md`, invariants **`INV-WARBOW-134-RANK`** + §134 forge row, `timecurve-views`, `PARAMETERS.md`, `skills/play-timecurve-warbow`, `skills/README.md`, contributor guardrails skill, audit M-02 narrative footnote. ## Verification checklist (for @brouie) - [ ] **Forge:** `cd contracts && forge test --match-test warbow_steal` and `--match-test warbow_revenge_distinct_stealer` (or full `TimeCurve` suite in CI). - [ ] **Vitest:** `frontend` — `warbowStealBpBand.test.ts`, `timeCurveUx.test.ts`, `revertMessage.test.ts`, `WarbowHeroActions.test.tsx`. - [ ] **EcoStrategy:** `cd simulations && PYTHONPATH=. python3 -m unittest discover -s tests -v`. - [ ] **Manual / Anvil:** low-BP wallet vs ladder whale — hero shows **Too high BP** (or preflight **Victim BP too far above yours**); forced `warbowSteal` reverts **`steal 10x cap`**; in-band rival still steals normally. - [ ] **Cross-links:** [GitLab #211](https://gitlab.com/PlasticDigits/yieldomega/-/issues/211) ↔ `docs/testing/invariants-and-business-logic.md` §134 / `docs/product/primitives.md` / `skills/play-timecurve-warbow/SKILL.md`. Please confirm behavior on your target deployment (UUPS bytecode upgrade path is out of scope for this MR but called out in the issue).
Brouie commented 2026-05-18 01:58:02 +00:00 (Migrated from gitlab.com)

marked the checklist item Onchain warbowSteal reverts unless attackerBP > 0 and 2 × attackerBP ≤ victimBP ≤ 10 × attackerBP (exact inequality semantics match Solidity * uint256 math, no overflow for realistic BP values). as completed

marked the checklist item **Onchain warbowSteal reverts unless attackerBP \> 0 and 2 × attackerBP ≤ victimBP ≤ 10 × attackerBP \(exact inequality semantics match Solidity \* uint256 math, no overflow for realistic BP values\)\.** as completed
Brouie commented 2026-05-18 01:58:04 +00:00 (Migrated from gitlab.com)

marked the checklist item NatSpec + docs/product/primitives.md describe the full bracket; docs/testing/invariants-and-business-logic.md updated INV\-WARBOW\-134\-RANK or successor ID so contributor map matches behavior. as completed

marked the checklist item **NatSpec \+ docs/product/primitives\.md describe the full bracket; docs/testing/invariants\-and\-business\-logic\.md updated \(INV\-WARBOW\-134\-RANK or successor ID\) so contributor map matches behavior\.** as completed
Brouie commented 2026-05-18 01:58:09 +00:00 (Migrated from gitlab.com)

marked the checklist item describeStealPreflight and Arena steal candidate discovery match onchain rules (no UI that suggests a steal that will revert on the BP bracket alone). as completed

marked the checklist item **describeStealPreflight and Arena steal candidate discovery match onchain rules \(no UI that suggests a steal that will revert on the BP bracket alone\)\.** as completed
Brouie commented 2026-05-18 01:58:12 +00:00 (Migrated from gitlab.com)

marked the checklist item friendlyRevertMessage or equivalent gives participants clear copy for whichever revert string ships. as completed

marked the checklist item **friendlyRevertMessage \(or equivalent\) gives participants clear copy for whichever revert string ships\.** as completed
Brouie commented 2026-05-18 01:58:20 +00:00 (Migrated from gitlab.com)

marked the checklist item Foundry + Vitest + EcoStrategy unit tests green in CI for touched areas. as completed

marked the checklist item **Foundry \+ Vitest \+ EcoStrategy unit tests green in CI for touched areas\.** as completed
Brouie commented 2026-05-18 02:15:13 +00:00 (Migrated from gitlab.com)

Walked the verification checklist against the patched local stack. All 5 items pass, including a live revert against the deployed bytecode on a fresh redeploy of main HEAD 4f32e63 (which includes 3cac333).

Forge — warbow_steal + warbow_revenge_distinct_stealer

cd contracts && forge test --match-contract TimeCurve --match-test warbow_steal

TimeCurve.t.sol: 9/9 PASS including the new test_warbow_steal_revert_10x_cap.
TimeCurveWarBowCl8yBurns.t.sol: 2/2 PASS including the 256-run testFuzz_warbow_steal_burn_exact_to_sink.

cd contracts && forge test --match-test warbow_revenge_distinct_stealer

testFuzz_warbow_revenge_distinct_stealer_slots_overlap: 256/256 PASS — the new vm.assume in-band draw constraint does not break the per-(victim, stealer) revenge slot semantics from GitLab #135.

Vitest — warbowStealBpBand, timeCurveUx, revertMessage, WarbowHeroActions

cd frontend && npm test -- --run src/lib/warbowStealBpBand.test.ts src/lib/timeCurveUx.test.ts src/lib/revertMessage.test.ts src/pages/timeCurveArena/WarbowHeroActions.test.tsx

44/44 PASS across the 4 files. New warbowStealBpBand.ts helper centralizes the 2x-10x predicate; describeStealPreflight covers Too low BP / Too high BP / In band branches; friendlyRevertMessage maps both steal 2x rule and steal 10x cap to player-friendly copy; Arena hero bpBelowStealThreshold and bpAboveStealThreshold row partitioning intact.

EcoStrategy — unittest discover

cd simulations && PYTHONPATH=. python3 -m unittest discover -s tests -v

42/42 PASS. WarBowWorld.can_steal and the band-aware test_two_x_rule_blocks_steal extension all green. UTC rollover fixture using a fresh victim on the new UTC day verified.

Manual / Anvil — live patched bytecode

Brought the local stack up fresh on main HEAD 4f32e63 (full redeploy, fresh indexer DB, schema 1.22.0, swarm running). Used anvil accounts #28 (0x40fc963a...96624) as attacker and #29 (0x9dcce783...07c710) as victim. Both pre-funded with CL8Y mock + approved to TimeCurve.

Out-of-band steal — must revert with steal 10x cap

Set up: attacker 1 buy = 250 BP, victim 11 buys = 2750 BP. Ratio 11.0x, exceeds the 10x cap.

cast send TC "warbowSteal(address,bool)" VICTIM false --private-key ATTACKER_PK

Reverted with exact string:

Error("TimeCurve: steal 10x cap")

Hex-decoded revert data: 54696d6543757276653a20737465616c20313078206361702f -> TimeCurve: steal 10x cap. The attack vector (multi-wallet swarm against a distant whale) is locked on the deployed bytecode.

In-band steal — must succeed with normal economics

Set up: attacker 3 buys = 750 BP, victim 2750 BP. Ratio 3.66x, in the 2x-10x band.

cast send TC "warbowSteal(address,bool)" VICTIM false --private-key ATTACKER_PK

Status 1. Onchain state delta:

Metric Before After Delta
Attacker BP 750 1025 +275 (transferred slice)
Victim BP 2750 2475 -275 (10% drain)
0xdead CL8Y snapshot S S + 10.10e18 wad +10.10 CL8Y (1 from this steal + ~9.1 from concurrent swarm buys hitting the same block)

The 275 BP delta equals exactly 10% of victim BP at call time, matching _warbowStealDrainBp default (10% unguarded).

All 3 target docs reference the 2x-10x bracket + both revert strings + #211 link:

  • INV-WARBOW-134-RANK at invariants-and-business-logic.md:545 — both bounds + revert strings + #211 link.
  • Arena WarBow hero actions row at invariants-and-business-logic.md:171 — 2x-10x BP band + near-miss row partitioning + #211 link.
  • docs/product/primitives.md:69 + :94 — finite band 2x-10x + bracket bounds + both revert strings + #211 link.
  • skills/play-timecurve-warbow/SKILL.md:38 — Ranking line includes #211 + 2x-10x bracket.

Doc shorthand callouts (awareness, no action requested)

Grepped wider per the AC item "any grep-hit launch docs that teach steals". Four remaining references use the lower-bound shorthand 2× rule / 2x rule rather than the full bracket phrasing:

  • docs/testing/invariants-and-business-logic.md:1350 — EcoStrategy table description: "WarBowWorld mirrors warbowSteal / warbowRevenge / warbowActivateGuard (2× rule, UTC-day steal caps, drain bps, revenge window)"
  • audits/audit_ecostrategy_1777969776.md:135 — sim recommendation: "Model WarBow with the real 2x rule, per-attacker/victim daily caps, ..."
  • audits/audit_ecostrategy_1777969776.md:283 — audit narrative: "the PvP steal model is explicitly a toy random 10% drain and does not include the 2x rule, CL8Y burn costs, ..."
  • audits/audit_ecostrategy_1777969776.md:355 — scenario list: "Multiple low-BP sharks attack under 2x rule, including UTC rollover, ..."

Flagging only — your commit already edited invariants-and-business-logic.md (updating INV-WARBOW-134-RANK at :545 and the Arena hero row at :171) and the audit file (errata footnote at :122 pointing to #211). So choosing not to sweep these other lines reads as a deliberate "preserve original audit narrative / table shorthand" call. Surfacing in case you want a follow-up sweep.

Summary

All 5 checklist items pass against the patched bytecode + tests + docs. The leaderboard-destroy attack vector (multi-wallet zero-BP swarm vs ladder whale) is provably locked: abp > 0 guard blocks zero-BP attackers entirely, and the new 10x cap prevents legit-but-distant attackers from farming whales. In-band peer rivalry preserved end-to-end.

UUPS upgradeTo() to mainnet is out of scope per the issue body, but flagging that the deployed mainnet proxy still serves the OLD bytecode until that cutover lands.

@PlasticDigits

Walked the verification checklist against the patched local stack. All 5 items pass, including a live revert against the deployed bytecode on a fresh redeploy of main HEAD `4f32e63` (which includes `3cac333`). ## Forge — `warbow_steal` + `warbow_revenge_distinct_stealer` ``` cd contracts && forge test --match-contract TimeCurve --match-test warbow_steal ``` `TimeCurve.t.sol`: 9/9 PASS including the new `test_warbow_steal_revert_10x_cap`. `TimeCurveWarBowCl8yBurns.t.sol`: 2/2 PASS including the 256-run `testFuzz_warbow_steal_burn_exact_to_sink`. ``` cd contracts && forge test --match-test warbow_revenge_distinct_stealer ``` `testFuzz_warbow_revenge_distinct_stealer_slots_overlap`: 256/256 PASS — the new `vm.assume` in-band draw constraint does not break the per-(victim, stealer) revenge slot semantics from GitLab #135. ## Vitest — `warbowStealBpBand`, `timeCurveUx`, `revertMessage`, `WarbowHeroActions` ``` cd frontend && npm test -- --run src/lib/warbowStealBpBand.test.ts src/lib/timeCurveUx.test.ts src/lib/revertMessage.test.ts src/pages/timeCurveArena/WarbowHeroActions.test.tsx ``` 44/44 PASS across the 4 files. New `warbowStealBpBand.ts` helper centralizes the 2x-10x predicate; `describeStealPreflight` covers Too low BP / Too high BP / In band branches; `friendlyRevertMessage` maps both `steal 2x rule` and `steal 10x cap` to player-friendly copy; Arena hero `bpBelowStealThreshold` and `bpAboveStealThreshold` row partitioning intact. ## EcoStrategy — `unittest discover` ``` cd simulations && PYTHONPATH=. python3 -m unittest discover -s tests -v ``` 42/42 PASS. `WarBowWorld.can_steal` and the band-aware `test_two_x_rule_blocks_steal` extension all green. UTC rollover fixture using a fresh victim on the new UTC day verified. ## Manual / Anvil — live patched bytecode Brought the local stack up fresh on main HEAD `4f32e63` (full redeploy, fresh indexer DB, schema 1.22.0, swarm running). Used anvil accounts #28 (`0x40fc963a...96624`) as attacker and #29 (`0x9dcce783...07c710`) as victim. Both pre-funded with CL8Y mock + approved to TimeCurve. ### Out-of-band steal — must revert with `steal 10x cap` Set up: attacker 1 buy = 250 BP, victim 11 buys = 2750 BP. Ratio 11.0x, exceeds the 10x cap. ``` cast send TC "warbowSteal(address,bool)" VICTIM false --private-key ATTACKER_PK ``` Reverted with exact string: ``` Error("TimeCurve: steal 10x cap") ``` Hex-decoded revert data: `54696d6543757276653a20737465616c20313078206361702f` -> `TimeCurve: steal 10x cap`. The attack vector (multi-wallet swarm against a distant whale) is locked on the deployed bytecode. ### In-band steal — must succeed with normal economics Set up: attacker 3 buys = 750 BP, victim 2750 BP. Ratio 3.66x, in the 2x-10x band. ``` cast send TC "warbowSteal(address,bool)" VICTIM false --private-key ATTACKER_PK ``` Status 1. Onchain state delta: | Metric | Before | After | Delta | |---|---|---|---| | Attacker BP | 750 | 1025 | +275 (transferred slice) | | Victim BP | 2750 | 2475 | -275 (10% drain) | | 0xdead CL8Y | snapshot S | S + 10.10e18 wad | +10.10 CL8Y (1 from this steal + ~9.1 from concurrent swarm buys hitting the same block) | The 275 BP delta equals exactly 10% of victim BP at call time, matching `_warbowStealDrainBp` default (10% unguarded). ## Cross-links — `docs/testing/invariants-and-business-logic.md` + `docs/product/primitives.md` + `skills/play-timecurve-warbow/SKILL.md` All 3 target docs reference the 2x-10x bracket + both revert strings + #211 link: - `INV-WARBOW-134-RANK` at `invariants-and-business-logic.md:545` — both bounds + revert strings + #211 link. - Arena WarBow hero actions row at `invariants-and-business-logic.md:171` — 2x-10x BP band + near-miss row partitioning + #211 link. - `docs/product/primitives.md:69` + `:94` — finite band 2x-10x + bracket bounds + both revert strings + #211 link. - `skills/play-timecurve-warbow/SKILL.md:38` — Ranking line includes #211 + 2x-10x bracket. ## Doc shorthand callouts (awareness, no action requested) Grepped wider per the AC item "any grep-hit launch docs that teach steals". Four remaining references use the lower-bound shorthand `2× rule` / `2x rule` rather than the full bracket phrasing: - `docs/testing/invariants-and-business-logic.md:1350` — EcoStrategy table description: "WarBowWorld mirrors warbowSteal / warbowRevenge / warbowActivateGuard (2× rule, UTC-day steal caps, drain bps, revenge window)" - `audits/audit_ecostrategy_1777969776.md:135` — sim recommendation: "Model WarBow with the real 2x rule, per-attacker/victim daily caps, ..." - `audits/audit_ecostrategy_1777969776.md:283` — audit narrative: "the PvP steal model is explicitly a toy random 10% drain and does not include the 2x rule, CL8Y burn costs, ..." - `audits/audit_ecostrategy_1777969776.md:355` — scenario list: "Multiple low-BP sharks attack under 2x rule, including UTC rollover, ..." Flagging only — your commit already edited `invariants-and-business-logic.md` (updating `INV-WARBOW-134-RANK` at `:545` and the Arena hero row at `:171`) and the audit file (errata footnote at `:122` pointing to #211). So choosing not to sweep these other lines reads as a deliberate "preserve original audit narrative / table shorthand" call. Surfacing in case you want a follow-up sweep. ## Summary All 5 checklist items pass against the patched bytecode + tests + docs. The leaderboard-destroy attack vector (multi-wallet zero-BP swarm vs ladder whale) is provably locked: `abp > 0` guard blocks zero-BP attackers entirely, and the new 10x cap prevents legit-but-distant attackers from farming whales. In-band peer rivalry preserved end-to-end. UUPS `upgradeTo()` to mainnet is out of scope per the issue body, but flagging that the deployed mainnet proxy still serves the OLD bytecode until that cutover lands. @PlasticDigits
PlasticDigits commented 2026-05-19 07:53:22 +00:00 (Migrated from gitlab.com)

mentioned in issue #217

mentioned in issue #217
Brouie commented 2026-05-20 02:52:38 +00:00 (Migrated from gitlab.com)

Balance observation worth surfacing while #211's BP-band tuning is open.

Current state (per TimeCurve.sol):

  • WARBOW_STEAL_BURN_WAD = 1 CL8Y per steal (flat, regardless of attack ratio)
  • 2× – 10× band: victim BP must be between 2× and 10× attacker BP
  • WARBOW_STEAL_LIMIT_BYPASS_BURN_WAD = 50 CL8Y (push past 3/day cap)
  • WARBOW_STEAL_DRAIN_BPS = 1000 (10% of victim BP per steal, 1% if guarded)
  • Guard cost: 10 CL8Y for 6 hours, 90% incoming-steal reduction

The 10× upper cap means top-rank players become unreachable for smaller participants. At rank ~53k BP, only attackers with 5.3k–26.5k BP can threaten that position. The cushion grows as the leader's BP grows, eventually freezing the leaderboard for the rest of the sale window.

Adjacent suggestion if open for tuning alongside #211:

Two changes that work together:

  1. Remove the 10× upper cap, keep the 2× lower floor. Any attacker can reach any victim with at least 2× their BP.
  2. Tier the bypass cost by attack ratio (replaces the flat 50 CL8Y bypass). Base steal cost (1 CL8Y per steal) stays unchanged — first 3 steals/day stay accessible at peer pricing for everyone.

Tiered bypass cost (kicks in only on steal four-plus per attacker or per victim per UTC day):

  • Below 2× → invalid (no change, prevents close-peer griefing)
  • 2× – 5× → 50 CL8Y (current bypass cost preserved at peer reach)
  • 5× – 15× → 100 CL8Y
  • 15× – 30× → 200 CL8Y
  • 30×+ → 300 CL8Y

What this changes:

Scenario Current Suggested
500 BP attacks 50k whale (100×) Invalid — outside 10× cap Allowed. First 3 steals: 1 CL8Y each. Bypass: 300 CL8Y each
1k BP attacks 50k whale (50×) Invalid — outside 10× cap Allowed. First 3 steals: 1 CL8Y each. Bypass: 300 CL8Y each
5k BP attacks 50k whale (10×) 1 CL8Y/steal (at edge of band) First 3: 1 CL8Y. Bypass: 100 CL8Y
25k BP attacks 50k whale (2×) 1 CL8Y/steal (at floor) 1 CL8Y/steal (unchanged)
50k attacks 60k peer (1.2×) Invalid — below 2× floor Invalid (no change)
Whale attacks down Invalid Invalid (no change)

What stays exactly the same:

  • WARBOW_STEAL_BURN_WAD = 1 CL8Y for first 3/day — casual PvP stays cheap for everyone
  • WARBOW_STEAL_DRAIN_BPS = 1000 (10% drain) and DRAIN_GUARDED_BPS = 100 (1% if guarded) — no change to yield
  • 2× lower floor — prevents close-peer griefing
  • 3 steals/day cap per attacker and per victim — no change
  • Guard cost: 10 CL8Y for 6 hours, 90% reduction — no change, defensive counter stays accessible
  • Revenge mechanics — no change

Strategic effect — what this opens up:

Top-rank players have two viable defensive strategies:

  • Guarded whale: pay ~40 CL8Y/day (4 × guard cycles) for 90% steal reduction. Attackers can still try, but each steal drains 1% instead of 10% — far less profit per attempt
  • Unguarded whale: save the 40 CL8Y/day, accept bleeding BP to attackers

Either strategy burns CL8Y somewhere — guard burn or steal burn. The leaderboard becomes contested because being top rank carries a daily cost, not just a one-time grind.

For attackers:

  • Casual PvP within band stays cheap (1 CL8Y per steal, first 3/day)
  • Whale-hunting becomes a strategic option below the 2× cap, with the cost scaling to reach (up to 300 CL8Y per bypass steal)
  • The 3/day cap limits casual spam at the cheap rate, the tiered bypass limits sustained attack at the expensive rate

Honest trade-off:

  • Top players now need to actively defend (guard cycles) rather than coast on BP gap. Whether that's a feature (active leaderboard) or a problem (rank harassment forces guard tax) is your call.
  • The bypass tiering adds slight contract complexity (one numeric mapping by ratio bucket) but doesn't change the core mechanic shape.

Aware this is balance opinion, not a bug. Drop if it's out of scope or you've already tuned this elsewhere.

Balance observation worth surfacing while #211's BP-band tuning is open. Current state (per TimeCurve.sol): - WARBOW_STEAL_BURN_WAD = 1 CL8Y per steal (flat, regardless of attack ratio) - 2× – 10× band: victim BP must be between 2× and 10× attacker BP - WARBOW_STEAL_LIMIT_BYPASS_BURN_WAD = 50 CL8Y (push past 3/day cap) - WARBOW_STEAL_DRAIN_BPS = 1000 (10% of victim BP per steal, 1% if guarded) - Guard cost: 10 CL8Y for 6 hours, 90% incoming-steal reduction The 10× upper cap means top-rank players become unreachable for smaller participants. At rank \~53k BP, only attackers with 5.3k–26.5k BP can threaten that position. The cushion grows as the leader's BP grows, eventually freezing the leaderboard for the rest of the sale window. Adjacent suggestion if open for tuning alongside #211: Two changes that work together: 1. Remove the 10× upper cap, keep the 2× lower floor. Any attacker can reach any victim with at least 2× their BP. 2. Tier the bypass cost by attack ratio (replaces the flat 50 CL8Y bypass). Base steal cost (1 CL8Y per steal) stays unchanged — first 3 steals/day stay accessible at peer pricing for everyone. Tiered bypass cost (kicks in only on steal four-plus per attacker or per victim per UTC day): - Below 2× → invalid (no change, prevents close-peer griefing) - 2× – 5× → 50 CL8Y (current bypass cost preserved at peer reach) - 5× – 15× → 100 CL8Y - 15× – 30× → 200 CL8Y - 30×+ → 300 CL8Y What this changes: | Scenario | Current | Suggested | |----------|---------|-----------| | 500 BP attacks 50k whale (100×) | Invalid — outside 10× cap | Allowed. First 3 steals: 1 CL8Y each. Bypass: 300 CL8Y each | | 1k BP attacks 50k whale (50×) | Invalid — outside 10× cap | Allowed. First 3 steals: 1 CL8Y each. Bypass: 300 CL8Y each | | 5k BP attacks 50k whale (10×) | 1 CL8Y/steal (at edge of band) | First 3: 1 CL8Y. Bypass: 100 CL8Y | | 25k BP attacks 50k whale (2×) | 1 CL8Y/steal (at floor) | 1 CL8Y/steal (unchanged) | | 50k attacks 60k peer (1.2×) | Invalid — below 2× floor | Invalid (no change) | | Whale attacks down | Invalid | Invalid (no change) | What stays exactly the same: - WARBOW_STEAL_BURN_WAD = 1 CL8Y for first 3/day — casual PvP stays cheap for everyone - WARBOW_STEAL_DRAIN_BPS = 1000 (10% drain) and DRAIN_GUARDED_BPS = 100 (1% if guarded) — no change to yield - 2× lower floor — prevents close-peer griefing - 3 steals/day cap per attacker and per victim — no change - Guard cost: 10 CL8Y for 6 hours, 90% reduction — no change, defensive counter stays accessible - Revenge mechanics — no change Strategic effect — what this opens up: Top-rank players have two viable defensive strategies: - Guarded whale: pay \~40 CL8Y/day (4 × guard cycles) for 90% steal reduction. Attackers can still try, but each steal drains 1% instead of 10% — far less profit per attempt - Unguarded whale: save the 40 CL8Y/day, accept bleeding BP to attackers Either strategy burns CL8Y somewhere — guard burn or steal burn. The leaderboard becomes contested because being top rank carries a daily cost, not just a one-time grind. For attackers: - Casual PvP within band stays cheap (1 CL8Y per steal, first 3/day) - Whale-hunting becomes a strategic option below the 2× cap, with the cost scaling to reach (up to 300 CL8Y per bypass steal) - The 3/day cap limits casual spam at the cheap rate, the tiered bypass limits sustained attack at the expensive rate Honest trade-off: - Top players now need to actively defend (guard cycles) rather than coast on BP gap. Whether that's a feature (active leaderboard) or a problem (rank harassment forces guard tax) is your call. - The bypass tiering adds slight contract complexity (one numeric mapping by ratio bucket) but doesn't change the core mechanic shape. Aware this is balance opinion, not a bug. Drop if it's out of scope or you've already tuned this elsewhere.
PlasticDigits (Migrated from gitlab.com) closed this issue 2026-05-20 04:12:42 +00:00
PlasticDigits commented 2026-05-20 04:12:43 +00:00 (Migrated from gitlab.com)

Will consider raising cap from 10x to 20x

Will consider raising cap from 10x to 20x
PlasticDigits commented 2026-07-07 12:41:27 +00:00 (Migrated from gitlab.com)

mentioned in issue #366

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