Reconcile a Uniswap v3 core position’s fee checkpoint
A pool position stores a fee-growth checkpoint and amounts already owed. A collect transaction can transfer previously recorded amounts without recomputing every fee accrued since the last position update.
Compute what an update would crystallize
For the selected token, determine the fee growth inside the position range at the target block and subtract feeGrowthInsideLastX128 with the implementation’s unsigned wrap behavior. Multiply the delta by the pre-update position liquidity and divide by 2^128.
liquidity = 100
feeGrowthInside change = 2^128 / 4
new tokens owed = floor(100 / 4) = 25
The fixture adds 25 raw token units to the owed amount. A zero-liquidity burn on an existing active position can update its core accounting without removing liquidity. Distinguish that accounting step from the subsequent collect transfer.
Do not label all owed amounts as fees
Removing liquidity can also add principal to the amounts owed. Track burns, position updates and collects together before classifying an outgoing transfer. NFT-managed positions introduce another accounting layer above the core position. github.com Position.sol