Bug: Fuzz test failure — max spread assertion off by rounding at extreme pool imbalance #53

Closed
opened 2026-04-06 04:44:28 +00:00 by Brouie · 4 comments
Brouie commented 2026-04-06 04:44:28 +00:00 (Migrated from gitlab.com)

Current behavior: fuzz test prop_interleaved_provide_swap_withdraw fails. actual spread (1.000012258707768751) exceeds max allowed (1.0). minimal failing input: init_a=869183, init_b=100000, add_a=10000, add_b=10000, swap_amount=99710. the spread check rejects a swap that exceeds max_spread=1.0 by 0.001% due to precision rounding at extreme reserve ratios.

Expected behavior: spread assertion should account for rounding precision at extreme ratios, or the spread calculation should handle this edge case gracefully. a swap at max_spread=1.0 (100% tolerance) should not fail due to sub-basis-point rounding error.

Acceptance criteria:

  • prop_interleaved_provide_swap_withdraw fuzz test passes (all 256 cases)
  • no regression in other spread assertion tests
  • 286/286 contract tests pass

commit 671e72f.

**Current behavior:** fuzz test prop_interleaved_provide_swap_withdraw fails. actual spread (1.000012258707768751) exceeds max allowed (1.0). minimal failing input: init_a=869183, init_b=100000, add_a=10000, add_b=10000, swap_amount=99710. the spread check rejects a swap that exceeds max_spread=1.0 by 0.001% due to precision rounding at extreme reserve ratios. **Expected behavior:** spread assertion should account for rounding precision at extreme ratios, or the spread calculation should handle this edge case gracefully. a swap at max_spread=1.0 (100% tolerance) should not fail due to sub-basis-point rounding error. **Acceptance criteria:** - [ ] prop_interleaved_provide_swap_withdraw fuzz test passes (all 256 cases) - [ ] no regression in other spread assertion tests - [ ] 286/286 contract tests pass commit 671e72f.
Brouie commented 2026-04-06 05:38:51 +00:00 (Migrated from gitlab.com)

mentioned in issue #50

mentioned in issue #50
PlasticDigits commented 2026-04-06 12:29:29 +00:00 (Migrated from gitlab.com)

mentioned in commit 9152da1bb7

mentioned in commit 9152da1bb78d0ba488a2ee5d805775fd4b9fd246
PlasticDigits commented 2026-04-06 12:29:39 +00:00 (Migrated from gitlab.com)

Pushed a fix in 9152da1 on main.

Cause: With belief_price: None, spread is floor(offer × out / in) − gross while gross comes from the CP path with ceil_div. At very skewed reserves that integer mismatch can make raw spread_amount larger than return + commission, so Decimal::from_ratio(spread, total_return) goes slightly over 1.0 even when the user asked for 100% tolerance.

Fix: assert_max_spread now compares min(spread_amount, total_return) to max_spread only for this check (attributes/hooks still emit the raw spread). Shared helper spot_linear_spread_over_gross is used for swap execution, Simulation, and ReverseSimulation. Unit tests added on the pair crate; prop_interleaved_provide_swap_withdraw runs 256 cases; all 286 contract tests pass.

@brouie can you confirm this matches what you saw on the fuzz failure? Leaving the issue open until verified.

Pushed a fix in 9152da1 on `main`. **Cause:** With `belief_price: None`, spread is `floor(offer × out / in) − gross` while `gross` comes from the CP path with `ceil_div`. At very skewed reserves that integer mismatch can make raw `spread_amount` *larger* than `return + commission`, so `Decimal::from_ratio(spread, total_return)` goes slightly over `1.0` even when the user asked for 100% tolerance. **Fix:** `assert_max_spread` now compares `min(spread_amount, total_return)` to `max_spread` only for this check (attributes/hooks still emit the raw spread). Shared helper `spot_linear_spread_over_gross` is used for swap execution, `Simulation`, and `ReverseSimulation`. Unit tests added on the pair crate; `prop_interleaved_provide_swap_withdraw` runs 256 cases; all 286 contract tests pass. @brouie can you confirm this matches what you saw on the fuzz failure? Leaving the issue open until verified.
Brouie commented 2026-04-07 03:36:04 +00:00 (Migrated from gitlab.com)

Verified on 38afbf8. New spot_linear_spread_over_gross helper caps spread at total_return so the ratio never exceeds 1.0 at extreme pool imbalance. Contracts 286/286 (was 285/286). Fuzz test that was failing now passes.

Verified on 38afbf8. New spot_linear_spread_over_gross helper caps spread at total_return so the ratio never exceeds 1.0 at extreme pool imbalance. Contracts 286/286 (was 285/286). Fuzz test that was failing now passes.
Brouie (Migrated from gitlab.com) closed this issue 2026-04-07 03:36:21 +00:00
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/cl8y-dex-terraclassic#53
No description provided.