Hook Fails to Accumulate Fees, Preventing Owner From Earning.
Description
function _beforeSwap(
address sender,
PoolKey calldata key,
SwapParams calldata params,
bytes calldata
) internal override returns (bytes4, BeforeSwapDelta, uint24) {
bool isReFiBuy = _isReFiBuy(key, params.zeroForOne);
uint256 swapAmount = params.amountSpecified < 0
? uint256(-params.amountSpecified)
: uint256(params.amountSpecified);
uint24 fee;
if (isReFiBuy) {
fee = buyFee;
emit ReFiBought(sender, swapAmount);
} else {
fee = sellFee;
uint256 feeAmount = (swapAmount * sellFee) / 100000;
emit ReFiSold(sender, swapAmount, feeAmount);
}
return (
BaseHook.beforeSwap.selector,
@> BeforeSwapDeltaLibrary.ZERO_DELTA,
fee | LPFeeLibrary.OVERRIDE_FEE_FLAG
);
}
Risk
Likelihood:
Impact:
Proof of Concept
<details>
<summary>POC</summary>
1 . Add this test to `RebateFiHookTest.t.sol` test file.
```javascript
function test_HookDoesNotAccumulateFees_OwnerCannotEarn() public {
vm.startPrank(user1);
reFiToken.approve(address(swapRouter), type(uint256).max);
uint256 initialHookBalance = reFiToken.balanceOf(address(rebateHook));
assertEq(initialHookBalance, 0, "Hook should start empty");
uint256 sellAmount = 0.01 ether;
PoolSwapTest.TestSettings memory testSettings =
PoolSwapTest.TestSettings(false, false);
for (uint i = 0; i < 3; i++) {
SwapParams memory params = SwapParams({
zeroForOne: false,
amountSpecified: -int256(sellAmount),
sqrtPriceLimitX96: TickMath.MAX_SQRT_PRICE - 1
});
swapRouter.swap(key, params, testSettings, ZERO_BYTES);
}
vm.stopPrank();
uint256 hookBalanceAfter = reFiToken.balanceOf(address(rebateHook));
console.log("Hook balance after sells:", hookBalanceAfter);
console.log("Expected > 0 (fees), actual = 0");
assertEq(
hookBalanceAfter,
0,
"BUG: hook does NOT accumulate fees, owner cannot earn"
);
}
```
</details>
Recommended Mitigation
1. Introduce a separate hook-owner fee independent from LP fees.
2. Add internal accounting to track fees meant for the hook owner.
3. Modify the _beforeSwap logic so a portion of each swap is redirected to the hook.
4. Replace ZERO_DELTA with a swap delta that transfers the hook fee to the hook contract.
5. Ensure collected fees accumulate as real token balances inside the hook contract.
6. Emit a dedicated event when the hook collects a fee for transparency.
7. Keep LP fee distribution unchanged; hook fee must be an additional fee layer.