AntFleet

Disagreement · 1e8fb4a1-anthropic-3

StreamableFeesLockerV2._collectFees unlock path does not split fees collected in the same call before transferring full balance to recipient

solo Opus
repo a7cc2ed7·PR #1·reviewed 1 week ago

Opus finding

StreamableFeesLockerV2._collectFees unlock path does not split fees collected in the same call before transferring full balance to recipient

highdata-losshigh
  • src/StreamableFeesLockerV2.sol:129-149
On the unlock path `_collectFees` first calls `_collect` (which records `fees` representing fees accrued since last collection) and returns them up to the parent caller `FeesManager.collectFees`. There, those fees are added to `getCumulatedFees0/1` and `_releaseFees` is called for `msg.sender`. Then the inner branch burns the position (transferring all principal+any newly accrued amount to the contract via `_burn`), and immediately transfers the FULL `delta` (which equals burned principal AND any fees burnt collected in same modifyLiquidity call?) to `stream.recipient`. Because `_burn`'s `balanceDelta` includes both the principal liquidity removal and any feesAccrued at that moment, but those fees were already added to the cumulated counters? Actually `_collect` happens immediately before `_burn`, so feesAccrued at burn time should be ~0. However, the contract balance still includes prior unclaimed cumulated fees that beneficiaries have not yet released (`getCumulatedFees - getLastCumulatedFees`). When the contract transfers `delta.amount0/1` to the recipient, that transfers ONLY the burn proceeds (delta), not the contract's full balance, so unclaimed fees for beneficiaries remain in the contract — good. But: `delta` here is from `_burn` which returns balanceDelta as the modifyLiquidity delta (negative liquidity → positive balanceDelta which represents principal + any residual feesAccrued at this moment). Since `_collect` was just called, residual feesAccrued in burn should be zero. So `delta` ~ principal, transferred to recipient — correct. There's no clear data-loss bug. Withdrawing.

Recommendation

N/A

Other reviewer

The other reviewer flagged nothing in this file/line range.

Why this didn't post

This finding didn't meet AntFleet's unanimous agreement threshold. Both frontier models review every PR independently; only findings they both flag with the same severity and category are posted to the PR. This one fell through.

read the methodology →