# Rounding direction favors attacker in share math

Per-share or per-token rounding that lands on the user side, exploitable by repeated ops or dust supply

_Area: DeFi accounting and math bugs. Seen in 3 disclosed reports; latest 2026-03-07. Updated 2026-11-01._

## How it works
Share, rate and per-token conversions turn integer division into value. When the division rounds toward the user (up on payout, down on charge), each operation leaves a sliver of value on the user's side. Repeated operations, or a supply so small that one unit rounds up to a whole balance, turn those slivers into real withdrawals. The broken assumption is that rounding error is negligible; it is only negligible when supply and index magnitudes are normal, and both can be pushed to extremes by permissionless actions.

## Where it shows up
- Share-to-asset or asset-to-share helpers with an explicit rounding argument (Ceil/Floor) chosen per call site [E1](https://bugbountylibrary.com/r/cantina%3Avii_finance_jan2026%3A3.1.1.md).
- Per-token distribution loops that normalize a total across tokenIds or shares [E1](https://bugbountylibrary.com/r/cantina%3Avii_finance_jan2026%3A3.1.1.md).
- Aave-fork `rayDiv`/`rayMul` and index math where the index can be inflated [E2](https://bugbountylibrary.com/r/dhl%3A20240102-radiantcapital.md).
- Wrapper contracts that re-implement an underlying market's conversion instead of calling it [E3](https://bugbountylibrary.com/r/sherlock%3A2025-06-notional-exponent%3AM-7.md).
- Missing virtual assets/shares offsets that the underlying market uses [E3](https://bugbountylibrary.com/r/sherlock%3A2025-06-notional-exponent%3AM-7.md).
- Paths where a flash loan is sized from one conversion and repaid through another [E3](https://bugbountylibrary.com/r/sherlock%3A2025-06-notional-exponent%3AM-7.md).

## How to review
The invariant: for every conversion, the protocol must never pay out more than the exact rational value, and must never accept less than it. Check each call site's rounding direction against who benefits: payouts and seizures round down, charges and debt round up. Check that dust supply (1 wei) cannot make a per-unit round-up equal a full balance [E1](https://bugbountylibrary.com/r/cantina%3Avii_finance_jan2026%3A3.1.1.md). Check that any value used to size a repayment is computed with the same rounding and virtual offsets as the repayment itself [E3](https://bugbountylibrary.com/r/sherlock%3A2025-06-notional-exponent%3AM-7.md). Test round-trips at pathological index magnitudes [E2](https://bugbountylibrary.com/r/dhl%3A20240102-radiantcapital.md).

## Variants seen
- Ceil rounding in per-token value distribution over dust supply, letting a tiny repayment seize an inflated position [E1](https://bugbountylibrary.com/r/cantina%3Avii_finance_jan2026%3A3.1.1.md).
- Precision loss in `rayDiv` under an artificially inflated liquidity index, draining a lending pool [E2](https://bugbountylibrary.com/r/dhl%3A20240102-radiantcapital.md).
- Rounding mismatch between a wrapper's health factor (down) and the underlying's repay (up), breaking migration [E3](https://bugbountylibrary.com/r/sherlock%3A2025-06-notional-exponent%3AM-7.md).

## Impact and severity
E1 socialized bad debt via over-seizure; E2 drained roughly $4.5M. Severity rises when permissionless actions (liquidity adds, recursive flash loans) can push supply or index to the extreme where rounding dominates, and when the loss is socialized to other depositors.

## Why fixes fail
E3 shows a wrapper that fixed nothing but diverged from the underlying's rounding and virtual offsets, so a correct underlying still produced a broken path.

## Evidence
- E1: https://bugbountylibrary.com/r/cantina%3Avii_finance_jan2026%3A3.1.1.md
- E2: https://bugbountylibrary.com/r/dhl%3A20240102-radiantcapital.md
- E3: https://bugbountylibrary.com/r/sherlock%3A2025-06-notional-exponent%3AM-7.md
