# Pool is griefed if tickBin is equal to (1 << splits) - 1

Swapping on an empty/low-liquidity InfinityPool pushes tickBin to its max value, making every subsequent advance() revert and permanently bricking the pool.

- Payout: Contest reward
- Severity: medium
- Program: InfinityPools
- Credited: ktl
- Disclosed: 2025-01-13
- Write-up quality: 6/10
- Original: https://cdn.cantina.xyz/reports/cantina_competition_infinitypools_october2024.pdf#3.2.3
- Library page: https://bugbountylibrary.com/r/cantina%3Ainfinitypools_october2024%3A3.2.3
- Tags: domain:web3 impact:dos kind:contest platform:cantina sev:medium tech:evm tech:solidity technique:source-review vuln:business-logic vuln:dos

**Target:** InfinityPool swap/advance tick accounting (EraBoxcarMidSum)
**Root cause:** EraBoxcarMidSum.sol#L30 reverts with OffsetOutOfRange when tickBin equals (1 << splits) - 1; since advance() runs at the start of every state-changing function and tickBin can only move via advance(), reaching the max value permanently locks the pool.
**Steps:**
1. Deploy/use an empty or low-liquidity InfinityPool for a token pair.
2. Call `infinityPool.swap(swap_params, address(this), "")` pushing 5e18 token1 with limitPrice POSITIVE_INFINITY; tickBin moves from 16384 to 32767 (== (1<<splits)-1).
3. Advance the block (`vm.warp(block.timestamp + 15)`) and call `infinityPool.advance()`.
4. advance() delegatecalls EraBoxcarMidSum which reverts `OffsetOutOfRange()`, so all state-changing functions now revert.
**How found:** Code reading of EraBoxcarMidSum.sol#L30 boundary check combined with the observation that advance() is invoked at the start of every state-changing function and tickBin has no other movement path; PoC on empty pool confirmed tickBin hitting 32767.
**Exploitation:** Attacker cheaply swaps on an empty/low-liquidity pool to drive tickBin to its maximum; every subsequent advance() reverts, bricking the pool. Factory prevents redeploying the same token pair/splits, forcing a protocol upgrade.
**Insight:** When a state variable is only mutated inside a function called at the top of every entrypoint, check its boundary values: if the max/min value makes that function revert, the whole contract becomes permanently unusable and cheap griefing on low-liquidity instances is enough.
