RebateFi Hook

First Flight #53
Beginner FriendlyDeFi
100 EXP
View results
Submission Details
Severity: high
Valid

Improper validation of REFI tokens in the before "_beforeInitialize" function leading to denail of pools being created using tokens with addresses Higher than that of ReFi token address

Improper validation of REFI tokens in the before "_beforeInitialize" function leading to denail of pools being created using tokens with addresses Higher than that of ReFi token address

Description

  • RebateFi Hook is a Uniswap V4 hook implementation that enables asymmetric fee structures for designated ReFi (Rebate Finance) tokens. Provided that any one of the tokens should be ReFi Token

  • ReFi hook has an IF condition to check if one of the tokens is REFI but the if condition just checks the same currency1 twice to see if its ReFi. In case if the other Token has higher address than ReFi then it has to be passed as currency1

  • In Uniswap v4, the PoolKey must always have currency0 < currency1 by address, otherwise PoolManager reverts with CurrenciesOutOfOrderOrEqual(currency0, currency1) so here Its not possible to use pools where the address of the other token is higher than that of ReFi.

// Root cause in the codebase with @> marks to highlight the relevant section
/// @notice Validates that ReFi token is in the pool before initialization
/// @param key The pool key containing currency pair information
/// @return Function selector for success
function _beforeInitialize(address, PoolKey calldata key, uint160) internal view override returns (bytes4) {
@> if (Currency.unwrap(key.currency1) != ReFi &&
Currency.unwrap(key.currency1) != ReFi) {
revert ReFiNotInPool();
}
return BaseHook.beforeInitialize.selector;
}
/// @notice Validates that the pool uses dynamic fees after initialization
/// @param key The pool key to validate
/// @return Function selector for success
function _afterInitialize(address, PoolKey calldata key, uint160, int24) internal pure override returns (bytes4) {
if (!key.fee.isDynamicFee()) {
revert MustUseDynamicFee();
}

Risk

Likelihood:

  • Can occur to anyone trying to create a LP with ReFi and another token whose address is higher than that of ReFi Token.

Impact:

  • Most tokens in the market wont be able to utilize this hook.as it is denying the creation of most LPs .

Proof of Concept

User tries to create a pool with where the tokenCurrency has higher address than the RefiCurrency so have to pass tokenCurrency as currency1 and ReFi as currency0. This will revert with ReFiNotInPool error message

function testFuzz_BeforeInitializeReFiCurrency0Bug() public {
// Create PoolKey with ReFi as currency0, token as currency1
PoolKey memory keyReFiCurrency0 = PoolKey({
currency1: tokenCurrency, // token as currency1
currency0: reFiCurrency, // ReFi as currency0
fee: LPFeeLibrary.DYNAMIC_FEE_FLAG,
tickSpacing: 60,
hooks: IHooks(address(rebateHook))
});
vm.startPrank(address(manager));
// This should REVERT with ReFiNotInPool() due to the IF condition
// (it only checks currency1, ignores currency0)
rebateHook.beforeInitialize(address(0), keyReFiCurrency0, 0);
vm.expectRevert(ReFiSwapRebateHook.ReFiNotInPool.selector);
vm.stopPrank();
}

Recommended Mitigation

The mitigation is simply to change the IF statement to check if either one the currency1 or currency0 is ReFi instead of just checking the currency1 alone.

function _beforeInitialize(address, PoolKey calldata key, uint160) internal view override returns (bytes4) {
if (Currency.unwrap(key.currency1) != ReFi &&
- Currency.unwrap(key.currency1) != ReFi) {
+ Currency.unwrap(key.currency0) != ReFi) {
revert ReFiNotInPool();
}
return BaseHook.beforeInitialize.selector;
}
+ add this code
- remove this code
Updates

Lead Judging Commences

chaossr Lead Judge 12 days ago
Submission Judgement Published
Validated
Assigned finding tags:

Faulty pool check; only checks currency1 twice, omitting currency0.

Support

FAQs

Can't find an answer? Chat with us on Discord, Twitter or Linkedin.

Give us feedback!