RebateFi Hook

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

_beforeInitialize checks currency1 twice

Root + Impact

Description

  • _beforeInitialize checks currency1 twice. Any pool initialization reverts unless currency1 == ReFi (which is almost never the case).
    This makes the entire hook completely unusable on any real deployment.

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 function intends to validate that either currency0 or currency1 of the pool equals the ReFi token address. The code checks currency1 twice and never checks currency0. The net condition simplifies to if (currency1 != ReFi) revert; - meaning initialization only succeeds when currency1 == ReFi.

Impact:

  • Pools where the ReFi token is token0 (i.e., currency0 == ReFi) fail to initialize with the hook attached. This prevents legitimate pool creation for half of token-pair orderings.

  • If tooling or scripts assume ReFi may be currency0 (common if tokens are listed by address ordering), automated pool launches will fail.

Proof of Concept

The hook’s _beforeInitialize checks only key.currency1 twice:

if (Currency.unwrap(key.currency1) != ReFi &&
Currency.unwrap(key.currency1) != ReFi) {
revert ReFiNotInPool();
}

  • When reFiToken is currency0, the condition becomes:

    solidity

    if (token != reFiToken && token != reFiToken) -> true -> revert!

  • So even though ReFi is in the pool, it reverts → bug confirmed.

function test_InitializationRevertsWhenReFiIsCurrency0() public {
// Arrange: ReFi token is currency0 (very common after address sorting!)
PoolKey memory key = PoolKey({
currency0: Currency.wrap(address(reFiToken)), // ReFi is currency0
currency1: Currency.wrap(address(token)), // Normal token is currency1
fee: LPFeeLibrary.DYNAMIC_FEE_FLAG, // Required by hook
tickSpacing: 60,
hooks: rebateHook
});
// Act & Assert: Pool initialization MUST revert due to double currency1 check
vm.expectRevert(ReFiSwapRebateHook.ReFiNotInPool.selector);
manager.initialize(key, SQRT_PRICE_1_1_s, "");
}

Recommended Mitigation

Patch _beforeInitialize as shown below, then run the provided Forge PoC. Update tests to expect success for both token orderings.

- if (Currency.unwrap(key.currency1) != ReFi &&
- Currency.unwrap(key.currency1) != ReFi) {
- revert ReFiNotInPool();
- }
+ if (Currency.unwrap(key.currency0) != ReFi &&
+ Currency.unwrap(key.currency1) != ReFi) {
+ revert ReFiNotInPool();
+ }
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!