The ReFiSwapRebateHook is designed to apply asymmetric fees: 0% for buying ReFi (to incentivize purchases) and a configurable sell fee (default 0.3%) to discourage selling. The _isReFiBuy function determines swap direction to apply the correct fee.
The logic in _isReFiBuy is inverted. In Uniswap V4, zeroForOne = true means swapping currency0 for currency1 (sending currency0, receiving currency1). When ReFi is currency0, zeroForOne = true means the user is sending ReFi (selling), but the function incorrectly returns true (indicating a buy). This causes buy fees to be applied on sells and sell fees to be applied on buys.
Likelihood:
Every swap on any ReFi pool triggers this inverted logic
The bug is deterministic and occurs 100% of the time regardless of swap size or user
Impact:
Buyers are penalized with the sell fee instead of enjoying 0% fee, discouraging token purchases
Sellers pay 0% fee instead of the configured sell fee, enabling fee-free dumps
Protocol loses all intended sell fee revenue
Economic model is completely inverted, the protocol incentivizes selling and penalizes buying
The following test demonstrates the inverted fee logic by performing two swaps with the same input amounts: a buy (ETH → ReFi) and a sell (ReFi → ETH).
With the configured fees of 0% for buys and 5% for sells, the expected behavior is that buyers receive more output tokens than sellers (since buyers pay no fee while sellers pay 5%). However, due to the inverted logic, the opposite occurs: buyers receive less output because the 5% sell fee is incorrectly applied to their transaction, while sellers receive more output because the 0% buy fee is incorrectly applied to theirs.
The final assertion assertLt(reFiReceivedFromBuy, ethReceivedFromSell) proves this inversion, it should fail in a correctly implemented system but passes here, confirming the bug.
The fix requires inverting the return values in both branches of the conditional.
When ReFi is currency0:
zeroForOne = true means sending ReFi → selling → should return false
zeroForOne = false means receiving ReFi → buying → should return true
Therefore, return !zeroForOne instead of zeroForOne
When ReFi is currency1:
zeroForOne = true means receiving ReFi → buying → should return true
zeroForOne = false means sending ReFi → selling → should return false
Therefore, return zeroForOne instead of !zeroForOne
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.