# Incorrect inside fees calculation for uninitialized uniswap ticks causes positions funds being stuck in the contract

Bug Deep Dive #17 · 13 December 2025

Bug Deep Dives · [The Contest Academy](https://0xsimao.com/the-contest-academy) · 0xSimao

---

| Title | Incorrect inside fees calculation for uninitialized uniswap ticks causes positions funds being stuck in the contract |
| Reward | $4432, Unique |
| Contest | Ammplify - 2 Sep 2025 on Sherlock |
| Author | panprog |
| Context | Uniswap Fee Logic |

`PoolLib.getInsideFees` calculates the inside fees, when the current price sits within the position range, as:

```solidity
(, , uint256 lowerFeeGrowthOutside0X128, uint256 lowerFeeGrowthOutside1X128, , , , ) = poolContract.ticks(
        lowerTick
    );
    (, , uint256 upperFeeGrowthOutside0X128, uint256 upperFeeGrowthOutside1X128, , , , ) = poolContract.ticks(
        upperTick
    );
...
            uint256 feeGrowthGlobal0X128 = poolContract.feeGrowthGlobal0X128();
            uint256 feeGrowthGlobal1X128 = poolContract.feeGrowthGlobal1X128();
            feeGrowthInside0X128 = feeGrowthGlobal0X128 - lowerFeeGrowthOutside0X128 - upperFeeGrowthOutside0X128;
            feeGrowthInside1X128 = feeGrowthGlobal1X128 - lowerFeeGrowthOutside1X128 - upperFeeGrowthOutside1X128;
```

The issue is that this code does not handle uninitialized ticks. `poolContract.ticks` returns correct `lowerFeeGrowthOutside` amounts only for initialized ticks; for uninitialized ones it returns 0. That makes the `feeGrowthInside` amounts equal to `feeGrowthGlobal`.

As a result:

- If a maker position is created on uninitialized Uniswap ticks while the current price is inside the position range, any further action on that position reverts, and the funds in it are stuck permanently.
- An attacker can steal all the contract's funds by collecting inflated fees.

The first scenario happens when `node.liq.feeGrowthInside0X128` and `1X128` were set to inflated values while the ticks were uninitialized, but `newFeeGrowthInside0X128` and `1X128` return the post-initialization values of 0. The subtraction underflows and the position is stuck.

```solidity
(uint256 newFeeGrowthInside0X128, uint256 newFeeGrowthInside1X128) = PoolLib.getInsideFees(
        data.poolAddr,
        iter.lowTick,
        iter.highTick
    );
    uint256 feeDiffInside0X128 = newFeeGrowthInside0X128 - node.liq.feeGrowthInside0X128;
    uint256 feeDiffInside1X128 = newFeeGrowthInside1X128 - node.liq.feeGrowthInside1X128;
```

**Alpha:** study Uniswap properly before integrating with it. Here, the fact that uninitialized ticks return zero fee-growth values was not handled, and the consequences are severe.

**Conclusion**

This finding would earn you **\$4432**, and deep Uniswap knowledge is what gets you there.

[**Full Report**](https://audits.sherlock.xyz/contests/1054/report)\
[**Codebase**](https://github.com/itos-finance/AmmplifyPublic/tree/beb942cfbd54990fc9434fbfa99a1fc251d73689)

---

Newer: [Takers pay significantly higher fees than expected due to borrow amounts being split across segments](https://0xsimao.com/the-contest-academy/bug-deep-dive-18) · Older: [All taker collateral and collected fees can be stolen by re-entering via RFTLib.settle to manipulate uniswap spot price](https://0xsimao.com/the-contest-academy/bug-deep-dive-16)
