RebateFi Hook

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

Unbounded Fee Configuration Allows Owner to Set Fees Above 100%

Root + Impact

Description

  • The ChangeFee function allows the contract owner to update buy and sell fees that are applied during swaps. According to Uniswap V4 documentation [1, 2], fees must not exceed 100% (represented as 1,000,000 in the fee basis point system).

  • The ChangeFee function lacks validation to ensure that fee values remain within acceptable bounds. This allows the owner to set fees above 100% (greater than 1,000,000), which violates Uniswap V4's fee constraints and will cause all swap transactions to revert.

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

Risk

Likelihood:

  • The owner has unrestricted access to call ChangeFee at any time with any value

No on-chain validation prevents setting fees above the maximum allowed value

  • Accidental misconfiguration (e.g., entering 3000000 instead of 3000) will immediately break the pool

Impact:

  • All swaps in the pool will revert when fees exceed 100%, causing a complete denial of service

Users cannot buy or sell the ReFi token until the owner corrects the fee configuration

  • Pool liquidity becomes locked and unusable during the period of misconfiguration

  • Loss of user trust and potential financial losses due to inability to exit positions

Proof of Concept

Add this test to RebateFiHookTest.t.sol:

function test_ChangeFee_ExceedsMaximum_CausesSwapsToRevert() public {
// Owner sets fee above 100% (either accidentally or intentionally)
uint24 invalidFee = 1_000_001; // Just above the max of 1_000_000
rebateHook.ChangeFee(true, invalidFee, true, invalidFee);
// Verify the invalid fee was set
(, uint24 sellFee) = rebateHook.getFeeConfig();
assertEq(sellFee, invalidFee, "Invalid fee should be set");
// Now attempt a swap -> it should revert
vm.startPrank(user1);
reFiToken.approve(address(swapRouter), type(uint256).max);
SwapParams memory params = SwapParams({
zeroForOne: false, // ReFi -> ETH
amountSpecified: -int256(0.01 ether),
sqrtPriceLimitX96: TickMath.MAX_SQRT_PRICE - 1
});
PoolSwapTest.TestSettings memory testSettings =
PoolSwapTest.TestSettings({takeClaims: false, settleUsingBurn: false});
// Swap will revert due to invalid fee
vm.expectRevert(); // Uniswap's LPFeeLibrary.validate() will revert
swapRouter.swap(key, params, testSettings, ZERO_BYTES);
vm.stopPrank();
}

Recommended Mitigation

function ChangeFee(
bool _isBuyFee,
uint24 _buyFee,
bool _isSellFee,
uint24 _sellFee
) external onlyOwner {
+ require(_buyFee <= 1_000_000, "Buy fee exceeds maximum");
+ require(_sellFee <= 1_000_000, "Sell fee exceeds maximum");
if(_isBuyFee) buyFee = _buyFee;
if(_isSellFee) sellFee = _sellFee;
}
Updates

Lead Judging Commences

chaossr Lead Judge 11 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!