RebateFi Hook

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

Owner can accidentally set fees above maximum, causing permanent DoS of all swaps

Missing fee validation in ChangeFee() allows owner to DoS protocol by exceeding Uniswap v4's maximum fee limit

Description

  • The RebateFi hook allows the owner to update buy and sell fees through the ChangeFee() function. Uniswap v4 requires all LP fees returned by hooks to be ≤ 1,000,000 (100%), and validates this during swap execution by reverting with LPFeeTooLarge if exceeded.

  • The ChangeFee() function lacks input validation on the new fee values. Since uint24 allows values up to 16,777,215 (16.7× the maximum), the owner can accidentally set fees above 1,000,000, causing all subsequent swaps to revert and rendering the protocol completely unusable until the fee is corrected.

    Retry

function ChangeFee(
bool _isBuyFee,
uint24 _buyFee,
bool _isSellFee,
uint24 _sellFee
) external onlyOwner {
@> if (_isBuyFee) buyFee = _buyFee;
@> if (_isSellFee) sellFee = _sellFee;
}

Risk

Likelihood:

  • The owner needs to update fees through ChangeFee() as part of normal protocol operations to adjust economic parameters. The owner accidentally passes a value > 1,000,000 (e.g., using wrong units, typo like 3_000_000 instead of 3_000, or misunderstanding the denominator).

  • uint24 allows values up to 16,777,215 with no compiler or runtime warnings, making invalid values easy to set unintentionally.

Impact:

  • All swap transactions through the hook revert with LPFeeTooLarge, causing complete protocol DoS until the owner corrects the fee. Protocol becomes unusable for all users (both buyers and sellers) during the period between setting invalid fees and correcting them.

  • Loss of user trust and potential migration to competing protocols during downtime.

Proof of Concept

The following test demonstrates how setting fees above Uniswap v4's maximum of 1,000,000 causes all swaps to revert. The ChangeFee() function accepts any uint24 value (up to 16,777,215) without validation. When a fee exceeding 1,000,000 is set and returned from the beforeSwap hook with the OVERRIDE_FEE_FLAG, Uniswap v4's core validates it and reverts with LPFeeTooLarge, making the protocol completely unusable until the owner corrects the fee.

function test_ChangeFee_BuyAboveMax_RevertsBuy() public {
rebateHook.ChangeFee(true, 2_000_000, false, 0);
vm.startPrank(user1);
reFiToken.approve(address(swapRouter), type(uint256).max);
bool isReFiCurrency0 = Currency.unwrap(key.currency0) ==
address(reFiToken);
vm.expectRevert();
swapRouter.swap(
key,
SwapParams({
zeroForOne: !isReFiCurrency0,
amountSpecified: -0.01 ether,
sqrtPriceLimitX96: isReFiCurrency0
? TickMath.MAX_SQRT_PRICE - 1
: TickMath.MIN_SQRT_PRICE + 1
}),
PoolSwapTest.TestSettings(false, false),
ZERO_BYTES
);
vm.stopPrank();
}
function test_ChangeFee_SellAboveMax_RevertsSell() public {
rebateHook.ChangeFee(false, 0, true, 2_000_000);
vm.startPrank(user1);
reFiToken.approve(address(swapRouter), type(uint256).max);
bool isReFiCurrency0 = Currency.unwrap(key.currency0) ==
address(reFiToken);
vm.expectRevert();
swapRouter.swap(
key,
SwapParams({
zeroForOne: !isReFiCurrency0,
amountSpecified: -0.01 ether,
sqrtPriceLimitX96: !isReFiCurrency0
? TickMath.MIN_SQRT_PRICE + 1
: TickMath.MAX_SQRT_PRICE - 1
}),
PoolSwapTest.TestSettings(false, false),
ZERO_BYTES
);
vm.stopPrank();
}

Recommended Mitigation

Use Uniswap v4's built-in LPFeeLibrary.validate() function to validate fees before setting them. This function checks that the fee does not exceed MAX_LP_FEE (1,000,000) and reverts with LPFeeTooLarge if invalid. This prevents the owner from accidentally setting invalid fees that would brick the protocol, providing immediate feedback at configuration time rather than during swap execution.

- if(_isBuyFee) buyFee = _buyFee;
- if(_isSellFee) sellFee = _sellFee;
+ if (_isBuyFee) {
+ LPFeeLibrary.validate(_buyFee);
+ buyFee = _buyFee;
+ }
+ if (_isSellFee) {
+ LPFeeLibrary.validate(_sellFee);
+ sellFee = _sellFee;
+ }
Updates

Lead Judging Commences

chaossr Lead Judge 12 days ago
Submission Judgement Published
Invalidated
Reason: Design choice

Support

FAQs

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

Give us feedback!