RebateFi Hook

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

Validation in `_beforeInitialize()` checks `currency1` twice instead of checking both currencies, allowing pools without ReFi token to use the hook

[H-1] Validation in _beforeInitialize() checks currency1 twice instead of checking both currencies, allowing pools without ReFi token to use the hook

Root + Impact

Description

The _beforeInitialize() function is designed to validate that the ReFi token exists in the pool as either currency0 or currency1 before pool initialization. The validation should check both currencies to ensure at least one matches the designated ReFi token address.

Due to a copy-paste error, the function checks currency1 twice instead of checking both currency0 and currency1. This allows pools that have ReFi as currency0 but not currency1 to bypass validation, and vice versa.

function _beforeInitialize(address, PoolKey calldata key, uint160) internal view override returns (bytes4) {
if (Currency.unwrap(key.currency1) != ReFi &&
@> Currency.unwrap(key.currency1) != ReFi) { // @audit should be currency0
revert ReFiNotInPool();
}
return BaseHook.beforeInitialize.selector;
}

Risk

Likelihood:

  • Any pool initialization where ReFi is currency0 will incorrectly pass validation even if currency1 is not ReFi

  • The condition currency1 != ReFi && currency1 != ReFi is always equivalent to currency1 != ReFi, making the check incomplete

  • Pool creators can initialize pools with arbitrary token pairs that don't include ReFi

Impact:

  • Pools without the ReFi token can be initialized with this hook, breaking the fundamental protocol assumption

  • The asymmetric fee logic (0% buy, 0.3% sell) will be incorrectly applied to non-ReFi token pairs

  • Protocol revenue model is compromised as fees are collected on wrong tokens

  • Users will be confused about which tokens are actually "ReFi" tokens

  • The hook's core functionality of incentivizing ReFi token accumulation is defeated

Proof of Concept

A simple test in Solidity that shows the steps to reporduce in the real world

function test_InitializePoolWithoutReFi() public {
// Create two random tokens (not ReFi)
Currency currency0 = Currency.wrap(address(0x1234));
Currency currency1 = Currency.wrap(address(0x5678));
// Create pool key without ReFi token
PoolKey memory wrongKey = PoolKey({
currency0: currency0,
currency1: currency1,
fee: LPFeeLibrary.DYNAMIC_FEE_FLAG,
tickSpacing: 60,
hooks: IHooks(address(hook))
});
// This should revert with ReFiNotInPool() but doesn't
poolManager.initialize(wrongKey, SQRT_PRICE_1_1);
// Pool initialized successfully despite not containing ReFi token
assertTrue(true); // Test passes, proving the bug
}

Recommended Mitigation

Using the correct Refi token, this would fix it immediately

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!