# Understanding the fee growth mechanism (why nearestTick is unsuitable)

Sushi Trident used nearestTick instead of pool tick for fee growth, misinitializing feeGrowthOutside and misclassifying tick cases, causing incorrect fee accounting.

- Payout: Audit contest
- Severity: high
- Program: Sushi
- Found by: hickuphh3
- Disclosed: 2021-11-30
- Write-up quality: 8/10
- Original: https://github.com/code-423n4/2021-09-sushitrident-2-findings/issues/1
- Library page: https://bugbountylibrary.com/r/c4%3A2021-09-sushitrident-2%3AH-17
- Tags: area:web3 domain:web3 impact:funds-loss kind:contest platform:code4rena sev:high tech:evm tech:solidity technique:source-review vuln:accounting-error vuln:business-logic

**Target:** Concentrated liquidity pool fee growth accounting (Tick.cross, feeGrowthOutside, secondsPerLiquidityOutside)
**Root cause:** Fee growth calculations reference nearestTick rather than the actual pool tick, so when a lower/upper tick equals nearestTick its feeGrowthOutside is initialized to 0 instead of feeGrowthGlobal, and case 1 vs case 2 classification becomes ambiguous.
**Steps:**
1. Read Tick.cross() flipping logic: `tick.feeGrowthOutside = feeGrowthGlobal - tick.feeGrowthOutside`
2. Observe feeGrowthOutside is defined relative to pool tick (case 1: init tick <= pool tick -> feeGrowthGlobal; case 2: > pool tick -> 0)
3. Note pool contract sets `state.tick = zeroForOne ? step.tickNext - 1 : step.tickNext` to handle boundary case
4. Replace nearestTick reference with poolTick in fee growth init/calc and observe misinitialized feeGrowthOutside when lower/upper tick == nearestTick
5. Show position fee accounting treats tick as case 1 when it should be case 2
**How found:** Author derived the fee growth mechanism from Uniswap V3 whitepaper, reasoned about feeGrowthOutside being relative to pool tick, and noticed nearestTick as reference makes case 1/case 2 ambiguous and misinitializes feeGrowthOutside on tick insertion.
**Insight:** When porting Uniswap V3-style concentrated liquidity, any substitute for the true pool tick (like nearestTick) breaks the relative feeGrowthOutside convention; check tick initialization and boundary handling (`step.tickNext - 1`) for off-by-one case flips.

