The function ReFiSwapRebateHook::ChangeFee allows the contract owner (onlyOwner) to update the variables buyFee and sellFee. However, there is no validation on the values passed in. This means buyFee and sellFee can be set to extreme or invalid amounts. If sellFee is set too high, users selling tokens could lose all of their swap value, and if buyFee is set too high, buyers could be charged unrealistic fees. This creates a serious risk of economic loss, broken pool math, and loss of trust in the system.
The ReFiSwapRebateHook::ChangeFee function lets the contract owner update the state variables buyFee and sellFee, but it does not validate the values being set. Because of this, buyFee and sellFee can be assigned extreme numbers like 1_000_000 (100% fee) or even uint24.max, which could cause users to lose all of their swap value, break pool math, or destabilize liquidity. The issue is that the function directly assigns _buyFee and _sellFee without any require checks or limits, relying only on onlyOwner for access control, which restricts who can call the function but not what values can be set
Likelihood:
There are no checks or caps on buyFee or sellFee, so any owner call to ChangeFee with extreme values (e.g., 1,000,000) will always succeed. This means the bug can be triggered intentionally or accidentally every time without restriction.
Impact:
Users can lose 100% of their trade value, as swaps deduct the entire amount as fees.
The pool’s fee logic is broken, preventing normal trading and destroying intended economics.
It acts as a denial‑of‑service and confiscation vector, undermining confidence in the protocol and exposing users to total loss.
Step 1
At deployment, the contract initializes buyFee = 0 and sellFee = 3000.
These values represent normal fee percentages (for example, 3000 is intended to mean 0.3%).
Swaps are expected to deduct only a small fraction of the trade as a fee.
Step 2
The owner calls RebateFiHook::ChangeFee with _isSellFee = true and _sellFee = 1,000,000.
Because there are no checks, the state variable sellFee is updated directly to 1,000,000.
Step 3
When a user performs a sell operation, the contract calculates the fee using sellFee.
With sellFee = 1,000,000, the math interprets this as a 100% fee.
That means the entire output amount from the swap can be taken as a fee, leaving the user with nothing.
Step 4
Similarly, if _isBuyFee = true and _buyFee = 1,000,000, then buyFee is set to 100%.
Any buy operation would charge the full amount as a fee, effectively confiscating the buyer’s tokens.
Step 5
The flags _isBuyFee and _isSellFee only control whether the assignment happens, not whether the values are safe.
By allowing 1,000,000 (or even larger values like uint24.max), the contract logic is altered from “take a small fee” to “take everything.”
This breaks the intended economics of the pool and exposes users to total loss.
Adding 1,000,000 to buyFee or sellFee flips the fee logic from a fractional deduction into a confiscatory 100% charge, because the function does not validate or cap the values being set.
Add validation in ReFiSwapRebateHook::ChangeFee so that:
buyFee and sellFee must be greater than or equal to 0.
The contest is live. Earn rewards by submitting a finding.
This is your time to appeal against judgements on your submissions.
Appeals are being carefully reviewed by our judges.