RebateFi Hook

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

Incorrect Pool Validation Logic Allows Non-ReFi Pools

Root + Impact

Description

  • The _beforeInitialize function is designed to validate that the ReFi token is present in the pool before initialization. According to the protocol's design, every pool should contain the ReFi token as either currency0 or currency1 to enable the rebate mechanism.

  • However, the validation logic contains a critical bug where it checks currency1 twice instead of checking both currency0 and currency1. As a result, any pool where ReFi appears in currency0 will incorrectly revert during initialization, even though such a pool is valid and should be allowed.

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;
}

Risk

Likelihood:

  • The vulnerability triggers whenever a pool is initialized with the ReFi token as currency0 and any other token as currency1

Users attempting to create legitimate ReFi pools with ReFi as the first token will inadvertently create invalid pools that pass validation

Impact:

  • The hook's core functionality (applying fees and managing rebates) will fail since swap direction logic depends on ReFi token position

Users will experience unexpected reverts or incorrect fee calculations when attempting to swap in these pools

  • Protocol reputation damage as pools appear to work during initialization but fail during actual usage

Proof of Concept

Add this test to RebateFiHookTest.t.sol:

function test_Revert_WhenReFiIsCurrency0() public {
// Deploy a new pool with ReFi as currency0 instead of currency1
MockERC20 otherToken = new MockERC20("OTHER", "OTH", 18);
Currency otherCurrency = Currency.wrap(address(otherToken));
// Mint to avoid zero balances
reFiToken.mint(address(this), 1 ether);
otherToken.mint(address(this), 1 ether);
// Expect revert because ReFi is currency0 and hook incorrectly checks only currency1
vm.expectRevert();
initPool(
reFiCurrency, // ReFi is currency0
otherCurrency,
rebateHook,
LPFeeLibrary.DYNAMIC_FEE_FLAG,
SQRT_PRICE_1_1_s
);
}

Recommended Mitigation

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

Lead Judging Commences

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