# Truncated fraction dropped from limit tracking

Integer division truncates a fractional remainder before it is added to a cap, counter, or price step

_Area: DeFi accounting and math bugs. Seen in 2 disclosed reports; latest 2024-10-17. Updated 2026-10-29._

## How it works
A quantity is converted to whole units by integer division, and the fractional remainder is discarded before it is recorded against a limit, counter, or pricing step. The tracked total is therefore always slightly smaller than the true total. Each operation under-counts by up to one unit, so cumulative usage can drift past the intended cap even though every individual check passes. The assumption that breaks is that "rounding down once is negligible"; when the same truncated value feeds a cap comparison, the error accumulates and the cap is no longer enforced.

## Where it shows up
- Division by `10**decimals` (or any scale factor) whose result is stored in a limit/flow variable.
- A round-up guard that only fires when the result is exactly zero (`if (x==0) x=1`), leaving other fractional results truncated [E1](https://bugbountylibrary.com/r/sherlock%3A2024-10-mento-update%3AM-4.md).
- Linear-decrease or step formulas comparing a truncated quotient against elapsed time [E2](https://bugbountylibrary.com/r/c4%3A2023-10-nextgen%3AM-09.md).
- Fixed-point libraries choosing a storage format from exponent alone, ignoring mantissa digit count [E3](https://bugbountylibrary.com/r/c4%3A2025-04-forte-float128-solidity-library%3AH-05.md).
- Any counter, cap, or price step updated from a division result.

## How to review
Identify every place a division result is written to a limit, counter, or price. The invariant: the recorded value must never be less than the true value when it is compared against a cap (round up for usage tracking; round consistently for pricing). Check that rounding direction is applied to all fractional remainders, not just the zero case [E1](https://bugbountylibrary.com/r/sherlock%3A2024-10-mento-update%3AM-4.md). For step formulas, test the exact boundary where numerator/denominator truncates [E2](https://bugbountylibrary.com/r/c4%3A2023-10-nextgen%3AM-09.md). For multi-width fixed-point, confirm format selection considers mantissa digits, not only exponent [E3](https://bugbountylibrary.com/r/c4%3A2025-04-forte-float128-solidity-library%3AH-05.md).

## Variants seen
- Sub-unit trades truncated in `TradingLimits.update()`, letting swaps exceed the configured limit by up to 2x [E1](https://bugbountylibrary.com/r/sherlock%3A2024-10-mento-update%3AM-4.md).
- Price-decrease condition truncating the quotient, skipping the final period and jumping to end price [E2](https://bugbountylibrary.com/r/c4%3A2023-10-nextgen%3AM-09.md).
- `toPackedFloat` downcasting mantissas between M and L thresholds, corrupting downstream arithmetic [E3](https://bugbountylibrary.com/r/c4%3A2025-04-forte-float128-solidity-library%3AH-05.md).

## Impact and severity
Medium to high: caps silently exceeded [E1](https://bugbountylibrary.com/r/sherlock%3A2024-10-mento-update%3AM-4.md), pricing steps skipped [E2](https://bugbountylibrary.com/r/c4%3A2023-10-nextgen%3AM-09.md), and downstream math corrupted [E3](https://bugbountylibrary.com/r/c4%3A2025-04-forte-float128-solidity-library%3AH-05.md). Severity rises when the truncated value gates a financial limit or price, and when many small operations compound the error.

## Why fixes fail
A guard that only rounds up on a zero result still truncates 1.999 to 1, so the cap remains exceedable [E1](https://bugbountylibrary.com/r/sherlock%3A2024-10-mento-update%3AM-4.md).

## Evidence
- E1: https://bugbountylibrary.com/r/sherlock%3A2024-10-mento-update%3AM-4.md
- E2: https://bugbountylibrary.com/r/c4%3A2023-10-nextgen%3AM-09.md
- E3: https://bugbountylibrary.com/r/c4%3A2025-04-forte-float128-solidity-library%3AH-05.md
