Normal Behavior: The RebateFiHook is made to encourage people to get ReFi tokens. It does this by charging a small fee (or no fee at all) when someone Buys ReFi (trades another token for ReFi). It charges a higher fee when someone Sells ReFi (trades ReFi for another token). The _isReFiBuy function is supposed to figure out if a trade is a buy or a sell based on Uniswap V4's zeroForOne setting and the order of the tokens.
Specific Issue: The way _isReFiBuy decides if something is a buy or sell is wrong. It knows if ReFi is token0 or token1, but it gets mixed up when it uses the zeroForOne flag. For example, if ReFi is token0, and zeroForOne = true, that means someone is Selling token0 (selling ReFi). But the code says it's a Buy. Because of this, the _beforeSwap function uses the wrong fee.
Likelihood:
This occurs on every single swap executed through the hook. The logic is fundamental to the contract and does not depend on specific external states or complex conditions. It is broken by default upon deployment.
Impact:
Direct Financial Loss to Buyers: Users engaging in the incentivized behavior (Buying ReFi) are charged the punitive "Sell Fee" (e.g., 10%), significantly reducing their output amount.
Economic Exploit for Sellers: Users "dumping" the token (Selling ReFi) bypass the intended sell tax completely, paying the 0% "Buy Fee".
Protocol Broken: The entire game-theoretic model of the protocol is inverted, incentivizing selling and penalizing buying.
I have developed a deterministic test case using Foundry. The test sets up a pool, configures a 10% Sell Fee and 0% Buy Fee, and then executes a BUY transaction. The logs confirm the user is charged the 10% fee.
Step-by-Step Exploit:
Deploy ReFi token and RebateFiHook.
Initialize a V4 Pool with ReFi and another token.
Admin sets Sell Fee to 10% (100,000 pips) and Buy Fee to 0%.
User attempts to BUY 1 ETH worth of ReFi.
The hook incorrectly flags this as a "Sell", applies the 10% fee, and emits ReFiSold.
POC Code:
(Paste this into test/RebateFiRealExploit.t.sol)
Console Output:
Invert the boolean return values in the _isReFiBuy function to correctly map the swap direction.
Redundant Currency Check Causes Denial of Service for 50% of Pools
Medium
Medium - Prevents permissionless pool creation for a significant subset of token pairs. While pools can still be created if the token addresses happen to sort correctly, this creates an arbitrary and frustrating limitation for integrators.
High - Deterministic failure for any pair where address(ReFi) < address(OtherToken).
Normal Behavior: The _beforeInitialize hook is responsible for ensuring that the pool being created actually involves the ReFi token designated by the protocol. It should check both currency0 and currency1 to see if either matches the immutable ReFi address.
Specific Issue: Due to a copy-paste error, the function checks currency1 twice and never checks currency0. If ReFi is currency0 (which happens when its address is numerically smaller than the paired token), the condition fails, and the transaction reverts.
Likelihood:
This occurs whenever a user attempts to initialize a pool where address(ReFi) < address(PairedToken). Since token addresses are essentially random hex strings, this affects approximately 50% of all potential trading pairs.
Impact:
Denial of Service: Valid pools cannot be initialized.
Integration Friction: Integrators or users trying to create a pool for ReFi / USDC (or any other token) will face unexplained reverts if the address sorting places ReFi first.
The following test attempts to initialize a pool where ReFi is currency0. It fails.
Step-by-Step Exploit:
Deploy ReFi.
Deploy a second token, ensuring its address is greater than ReFi's address.
This forces Uniswap V4 to sort ReFi as currency0.
Call manager.initialize().
Transaction reverts with ReFiNotInPool.
POC Code:
Update the first condition to check currency0.
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.