RebateFi Hook

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

RebateFi Hook Bug Submission

Root + Impact

Description

  • With the ReFi token as Currency1 of the Liquidity Pool, ReFi buying swaps should be incentivized with low or no LPFees involved for the transaction and ReFi selling swaps should be detered with 0.3% LPFees involved for the swap

  • Most critically, in the beforeSwap hook function, the ReFi buy LPFees logic is wrapped in an if statement that depends on the wrong boolean value from the isReFiBuy function.

    Inside the isReFiBuy function, the return value is true only when ReFi is currency0, which will always return a false when ReFi isnt currency0, and result into application of the correct zeroForOne= false logic to a zeroForOne=true swap, according to the pool currency setup, charging 0.3% on every Buy Swap of ReFi token

function beforeSwap(...) internal override returns(...){
@> bool isReFiBuy = _isReFiBuy(key, params.zeroForOne);
...
@> if (isReFiBuy) {
fee = buyFee;
emit ReFiBought(sender, swapAmount);
} else {
fee = sellFee;
uint256 feeAmount = (swapAmount * sellFee) / 100000;
emit ReFiSold(sender, swapAmount, feeAmount);
}
...
}
function isReFiBuy(...) internal view returns(bool){
...
@> bool IsReFiCurrency0 = Currency.unwrap(key.currency0) == ReFi;
...
@> if (IsReFiCurrency0) {
return zeroForOne;
} else {
return !zeroForOne;
}
}

Risk

Likelihood:

  • When a user initiates a swap from Currency0 to Currency1 ( ReFi Token)

  • When user intitates a swap from Currency1 ( ReFi Token) to Currency0

Impact:

  • User will be charged 0.3% LPFees for Buying ReFi Tokens which is contradictory to the Hook's purpose

  • User will be charged close to no fees for selling ReFi Token, incentive to liquiadate ReFi token assets

Proof of Concept

/// @dev _beforeSwap hypothetical invocation with a ReFi Buy Swap
_beforeSwap(
0x3.....,
key,
params,
calldata
) internal override returns (bytes4, BeforeSwapDelta, uint24) {
//is false
bool isReFiBuy = _isReFiBuy(key, params.zeroForOne);
...
if (isReFiBuy) {
...
}
// this section runs
else {
fee = sellFee;
uint256 feeAmount = (swapAmount * sellFee) / 100000;
emit ReFiSold(sender, swapAmount, feeAmount);
}
return (
BaseHook.beforeSwap.selector,
BeforeSwapDeltaLibrary.ZERO_DELTA,
fee | LPFeeLibrary.OVERRIDE_FEE_FLAG
);
}
//Swap occurs with 0.3% LPFees incurred

Recommended Mitigation

- remove this code
//entire function is futile, as params.zeroForOne in beforeSwap will suffice
function _isReFiBuy(PoolKey calldata key, bool zeroForOne) internal view returns (bool) {
bool IsReFiCurrency0 = Currency.unwrap(key.currency0) == ReFi;
// @> Following up that the requirement for this pool to be initlalizedis if ReFi is currency1
// this if statement is problematic, since the true variant of the bool isReFiCurrency0, implies
// that ReFi is actually being sold, not bought. The entire purpose of the Hook is reversed
// A deterent to Buy Refi and incentive to sell is instead established
if (IsReFiCurrency0) {
return zeroForOne;
} else {
return !zeroForOne;
}
}
function beforeSwap(...)...{
...
@> bool isReFiBuy = _isReFiBuy(key, params.zeroForOne);
...
}
+ add this code
function beforeSwap(...)...{
...
@> bool isReFiBuy = params.zeroForOne;
...
}
Updates

Lead Judging Commences

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

Inverted buy/sell logic when ReFi is currency0, leading to incorrect fee application.

Support

FAQs

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

Give us feedback!