RebateFi Hook

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

Admin-controlled fee values can break fee encoding and block all swaps

Summary

The contract allows the owner to arbitrarily set buyFee and sellFee to any uint24 value. These values are later combined with Uniswap’s fee override flag using bitwise OR:

https://github.com/CodeHawks-Contests/2025-11-rebatefi-hook/blob/main/src/RebateFiHook.sol#L165-L173

return (
BaseHook.beforeSwap.selector,
BeforeSwapDeltaLibrary.ZERO_DELTA,
fee | LPFeeLibrary.OVERRIDE_FEE_FLAG
);

Uniswap V4 expects fee values to remain within a specific bit range. The fee override flag occupies the most significant bit of the 24-bit fee field. If the owner sets a fee that already uses that bit (or uses overly large values), the resulting encoded fee becomes invalid. The pool manager may interpret the fee incorrectly or revert internally, effectively preventing swaps.

This gives the owner the ability to unintentionally or intentionally brick swaps through misconfiguration. Since this hook advertises a fee-override mechanism and will likely be used with UI-controlled dynamic fees, misconfiguration is realistic.

Technical Details

Fees are stored as uint24:
https://github.com/CodeHawks-Contests/2025-11-rebatefi-hook/blob/main/src/RebateFiHook.sol#L41-L42

uint24 public buyFee;
uint24 public sellFee;

The owner can set any values up to 16,777,215:
https://github.com/CodeHawks-Contests/2025-11-rebatefi-hook/blob/main/src/RebateFiHook.sol#L99-L113

function ChangeFee(...) external onlyOwner {
if (_isBuyFee) buyFee = _buyFee;
if (_isSellFee) sellFee = _sellFee;
}

No range check is applied.

In _beforeSwap the fee is OR-ed with the override flag:
https://github.com/CodeHawks-Contests/2025-11-rebatefi-hook/blob/main/src/RebateFiHook.sol#L165-L173

fee | LPFeeLibrary.OVERRIDE_FEE_FLAG

Uniswap defines fee encoding so that the override flag sits on the highest bit. Valid fee values must not collide with it. If the owner sets any fee where the top bit is already 1 (for example anything above approximately 2^23), the final encoded fee becomes invalid.

As a result, the pool manager may revert or interpret the fee as corrupted. Swap calls will fail even though the pool itself is otherwise valid.

This constitutes a centralized DoS vector for any pool using the hook.

Example Scenario

A frontend lets the admin update fees.

Admin mistakenly sets sellFee = 10000000.

This value overlaps with the override-flag bit.

Next _beforeSwap produces an invalid encoded fee.

Pool manager fails to process the swap and reverts.

All swaps through this hook are now blocked until the admin corrects the mistake.

There is no on-chain safeguard preventing this.

Why Impact Is High

The hook overrides every swap in the pool.

A malformed fee value breaks the encoded fee, blocking swapping entirely.

The system depends on dynamic fee override, making the correct encoding essential.

A single bad admin change is enough to stop trading.

Even though the threat originates from configuration rather than an external attacker, it is still a harmful vulnerability because a misconfigured upgrade or UI can cause a live pool to stop functioning.

Recommended Fix

Add explicit range checks to ensure fees remain inside the valid, non-overlapping portion of the 24-bit fee space.

For example:

uint24 MAX_UNISWAP_FEE = 1_000_000; // or the appropriate upper safe bound

require(_buyFee < MAX_UNISWAP_FEE, "Fee too large");
require(_sellFee < MAX_UNISWAP_FEE, "Fee too large");

Alternatively, mask out the override flag:

fee = fee & ~LPFeeLibrary.OVERRIDE_FEE_FLAG;

This ensures the final encoded fee remains valid and cannot break swap execution.

Updates

Lead Judging Commences

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