# Checked arithmetic revert blocks reachable path

Unsigned delta or cast that goes negative on a live path, reverting it under Solidity 0.8 checks

_Area: Smart contract access control and control flow. Seen in 3 disclosed reports; latest 2024-03-30. Updated 2026-10-23._

## How it works
Solidity 0.8 reverts on any unsigned underflow or overflow. When a value that a live path depends on is computed as a subtraction or a cast that can go negative, the revert is not a safety net but a denial of service: the path becomes permanently uncallable. The assumption that breaks is "this arithmetic only ever moves in one direction." Attackers or ordinary admin actions can push it the other way, and the checked revert turns that into a hard block.

## Where it shows up
- Deltas written as `a - b` or `total += (x * new) - (x * old)` inside unsigned accumulators, where `new < old` is legal input.
- Casts of `int256` returns (e.g. Uniswap `swap()`, which is negative for exact-input) straight to `uint256`/`uint128` without negation.
- Forked library overrides that change sentinel semantics (e.g. `delegates()` returning `account` instead of `address(0)`), letting a caller repeatedly subtract from a checkpoint.
- Admin "decrease" or "reduce" functions, commonly untested in both directions.
- Any subtraction whose operand is attacker-influenced (weights, counters, vote units).

## How to review
For every unsigned subtraction and narrowing cast, ask: can the subtrahend exceed the minuend on any reachable path, including repeated calls and admin decreases? The invariant to confirm: for all reachable inputs, the intermediate value stays within `[0, type.max]`, or the code explicitly guards the direction (compare before subtracting, use signed math, or clamp). Test both directions of every delta. When a fork overrides a library's default return, re-audit every caller that relied on the original sentinel [E1](https://bugbountylibrary.com/r/c4%3A2023-12-revolutionprotocol%3AH-04.md). When wrapping an external call, diff return-value handling against the reference implementation [E2](https://bugbountylibrary.com/r/c4%3A2023-05-maia%3AM-38.md).

## Variants seen
- Repeated subtraction from a vote checkpoint via a sentinel-returning `delegates()` override, underflowing permanently [E1](https://bugbountylibrary.com/r/c4%3A2023-12-revolutionprotocol%3AH-04.md).
- Missing negation of a negative `int256` swap return before a `uint128` cast, reverting all gas-swap paths [E2](https://bugbountylibrary.com/r/c4%3A2023-05-maia%3AM-38.md).
- Weight-decrease delta computed as `new - old` in an unsigned accumulator, reverting the admin call [E3](https://bugbountylibrary.com/r/cantina%3Aopal_feb2024%3A3.3.13.md).

## Impact and severity
In the evidence this blocked delegators from redelegating or transferring NFTs [E1](https://bugbountylibrary.com/r/c4%3A2023-12-revolutionprotocol%3AH-04.md), disabled all bridge gas-swap paths [E2](https://bugbountylibrary.com/r/c4%3A2023-05-maia%3AM-38.md), and made gauge weight decreases impossible [E3](https://bugbountylibrary.com/r/cantina%3Aopal_feb2024%3A3.3.13.md). Severity rises when the blocked path is user-facing and permanent, or when no alternate route exists; admin-only blocks are lower but still break governance.

## Evidence
- E1: https://bugbountylibrary.com/r/c4%3A2023-12-revolutionprotocol%3AH-04.md
- E2: https://bugbountylibrary.com/r/c4%3A2023-05-maia%3AM-38.md
- E3: https://bugbountylibrary.com/r/cantina%3Aopal_feb2024%3A3.3.13.md
