# Fee skipped by zero basis

Fee math keyed off a zeroable balance, unset field, or early return while value still settles

_Area: DeFi accounting and math bugs. Seen in 4 disclosed reports; one confirmed bounty: $250; latest 2025-07-17. Updated 2026-10-23._

## How it works
A fee is computed from a quantity that is zero, unset, or bypassed at the moment of calculation, while the value it should tax still moves. The fee formula itself looks correct; the input to it is wrong. Three shapes: a multiplier with a zero floor, a variable read before assignment, and an early return that skips the only path doing the bookkeeping. In each case the fee silently evaluates to zero and nothing reverts.

## Where it shows up
- Fee or tax proration using a balance, share count, or cost basis that is assigned later in the same function [E2](https://bugbountylibrary.com/r/sherlock%3A2025-04-burve%3AH-6.md).
- Named return variables or struct fields used before assignment; Solidity defaults them to zero [E2](https://bugbountylibrary.com/r/sherlock%3A2025-04-burve%3AH-6.md).
- Fee terms multiplied by a congestion or adjustment factor whose floor is zero [E1](https://bugbountylibrary.com/r/blog%3Amudit-blog-free-blockchain-storage-bug-substrate.md).
- Hooks that derive amounts from balance deltas when the underlying shares were burned in an earlier step [E3](https://bugbountylibrary.com/r/cantina%3Asuperform_may2025%3A3.1.5.md).
- Early returns on `feePercent == 0` or similar shortcuts that skip a callee which also updates accumulators [E4](https://bugbountylibrary.com/r/cantina%3Asuperform_may2025%3A3.2.2.md).

## How to review
For every fee computation, trace each input back to where it is set and confirm it is nonzero and current at the point of use. The invariant: the basis used for the fee must equal the value actually settled in that call. Check that no multiplier in a fee term can reach zero unless the spec says the fee should be zero. Check that any early return skips only the fee, not shared state updates. For hooks, confirm the share burn and the fee measurement happen in the same accounting window.

## Variants seen
- Zero-floor multiplier nullifies size and weight fees on idle chains [E1](https://bugbountylibrary.com/r/blog%3Amudit-blog-free-blockchain-storage-bug-substrate.md).
- Fee numerator read from an uninitialized variable, always zero [E2](https://bugbountylibrary.com/r/sherlock%3A2025-04-burve%3AH-6.md).
- Share burn in a prior step makes the delta zero, so cost basis and fee vanish [E3](https://bugbountylibrary.com/r/cantina%3Asuperform_may2025%3A3.1.5.md).
- Zero-fee early return leaves accumulators stale, corrupting later fees [E4](https://bugbountylibrary.com/r/cantina%3Asuperform_may2025%3A3.2.2.md).

## Why fixes fail
E4 shows a shortcut that is harmless while fees are zero but corrupts accounting once fees are enabled; the skipped callee did bookkeeping unrelated to the zeroed quantity.

## Impact and severity
Fees go uncollected: free large transactions [E1](https://bugbountylibrary.com/r/blog%3Amudit-blog-free-blockchain-storage-bug-substrate.md), zero protocol fee on removals [E2](https://bugbountylibrary.com/r/sherlock%3A2025-04-burve%3AH-6.md), untaxed yield [E3](https://bugbountylibrary.com/r/cantina%3Asuperform_may2025%3A3.1.5.md), and stale accumulators that misprice later fees [E4](https://bugbountylibrary.com/r/cantina%3Asuperform_may2025%3A3.2.2.md). Severity is high where the bypass is repeatable and unbounded; worse when the zero path also skips state updates, so the error compounds.

## Evidence
- E1: https://bugbountylibrary.com/r/blog%3Amudit-blog-free-blockchain-storage-bug-substrate.md
- E2: https://bugbountylibrary.com/r/sherlock%3A2025-04-burve%3AH-6.md
- E3: https://bugbountylibrary.com/r/cantina%3Asuperform_may2025%3A3.1.5.md
- E4: https://bugbountylibrary.com/r/cantina%3Asuperform_may2025%3A3.2.2.md
