RebateFi Hook

First Flight #53
Beginner FriendlyDeFi
100 EXP
View results
Submission Details
Impact: medium
Likelihood: medium
Invalid

M02. Missing Fee Bounds Validation in ChangeFee Function

Root + Impact:

Description

In normal behavior, the ChangeFee function allows the contract owner to update the buy and sell fees for the ReFiSwapRebateHook. These fees are used in _beforeSwap to calculate LP fee overrides, encoded with a bitmask in combination with the LPFeeLibrary.OVERRIDE_FEE_FLAG.

The issue is that there is no validation ensuring that the provided buyFee or sellFee values fit within safe numeric bounds. Without checks:

  • Fees exceeding the expected maximum can break LP fee encoding.

  • OR'ing the fee with the OVERRIDE_FEE_FLAG may unintentionally overwrite high bits, causing incorrect fee behavior or encoding invalid data that the Uniswap V4 pool cannot process.

// Root cause in the codebase with @> marks to highlight the relevant section
function ChangeFee(bool updateBuy, uint24 _buyFee, bool updateSell, uint24 _sellFee) external onlyOwner {
// @> no validation that _buyFee <= MAX_FEE or _sellFee <= MAX_FEE
if (updateBuy) buyFee = _buyFee;
if (updateSell) sellFee = _sellFee;
}

Risk

Likelihood:

  • Medium, because the owner can directly call ChangeFee with arbitrary values.

  • Medium, if the function is misconfigured or automated scripts accidentally provide excessive values.

Impact:

  • The hook may encode fee values incorrectly, potentially causing swap computations to revert or misapply fees.

  • Users may be overcharged or undercharged, and pool invariants may break.

Proof of Concept

Explanation

By calling ChangeFee with a sellFee value larger than expected, the hook can produce an LP fee override that exceeds the bit-width of the LPFeeLibrary field. This can break swaps or result in undefined fee application.

function test_ChangeFee_Overflow() public {
uint24 dangerousFee = 500_000; // beyond safe 18-bit field expected by LPFeeLibrary
vm.prank(rebateHook.owner());
rebateHook.ChangeFee(false, 0, true, dangerousFee);
// Swap parameters
SwapParams memory params = SwapParams({
zeroForOne: false,
amountSpecified: -int256(1 ether),
sqrtPriceLimitX96: TickMath.MAX_SQRT_PRICE - 1
});
vm.expectRevert(); // swap may revert due to invalid fee encoding
swapRouter.swap(key, params, PoolSwapTest.TestSettings({takeClaims: false, settleUsingBurn: false}), ZERO_BYTES);
}

Written explanation:

  • The test demonstrates that setting a fee larger than the safe maximum can break the swap due to invalid LP fee bit-packing.

  • This proves the absence of fee bounds validation is exploitable.

Recommended Mitigation

  • Define constants:

uint24 constant MAX_FEE = 100_000; // 100%
  • Validate fees in ChangeFee:

function ChangeFee(bool updateBuy, uint24 _buyFee, bool updateSell, uint24 _sellFee)
- if (updateBuy) buyFee = _buyFee;
- if (updateSell) sellFee = _sellFee;
+ if (updateBuy) {
+ require(_buyFee <= MAX_FEE, "Buy fee exceeds maximum");
+ buyFee = _buyFee;
+ }
+ if (updateSell) {
+ require(_sellFee <= MAX_FEE, "Sell fee exceeds maximum");
+ sellFee = _sellFee;
+ }
Updates

Lead Judging Commences

chaossr Lead Judge 12 days ago
Submission Judgement Published
Invalidated
Reason: Incorrect statement

Support

FAQs

Can't find an answer? Chat with us on Discord, Twitter or Linkedin.

Give us feedback!