RebateFi Hook

First Flight #53
Beginner FriendlyDeFi
100 EXP
View results
Submission Details
Impact: high
Likelihood: high
Invalid

Incorrect Fee Calculation Leading to 10x fee Overcharge.

Incorrect Fee Calculation Leading to 10x fee Overcharge.

Description

/// @notice Applies dynamic fees before each swap based on buy/sell direction
/// @param sender Address initiating the swap
/// @param key The pool key for the swap
/// @param params Swap parameters including direction and amount
/// @return Function selector, delta (always zero), and the dynamic fee to apply
function _beforeSwap(
address sender,
PoolKey calldata key,
SwapParams calldata params,
bytes calldata
) internal override returns (bytes4, BeforeSwapDelta, uint24) {
bool isReFiBuy = _isReFiBuy(key, params.zeroForOne);
uint256 swapAmount = params.amountSpecified < 0
? uint256(-params.amountSpecified)
: uint256(params.amountSpecified);
uint24 fee;
if (isReFiBuy) {
fee = buyFee;
emit ReFiBought(sender, swapAmount);
} 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
);
}

Risk

Likelihood:

  • It occurs on every swap


Impact:

  • The contract charges 10× higher fees.

Proof of Concept

<details>
<summary>POC</summary>
1. Add this test to `RebateFiHookTest.t.sol` test file.
```javascript
function test_SellFeeMiscomputed_MultipliedBy10() public {
address user = user1;
uint256 sellAmount = 1 ether;
reFiToken.mint(user, sellAmount);
vm.startPrank(user);
reFiToken.approve(address(swapRouter), type(uint256).max);
SwapParams memory params = SwapParams({
zeroForOne: false,
amountSpecified: -int256(sellAmount),
sqrtPriceLimitX96: TickMath.MAX_SQRT_PRICE - 1
});
PoolSwapTest.TestSettings memory settings = PoolSwapTest.TestSettings({
takeClaims: false,
settleUsingBurn: false
});
(, uint24 sellFee) = rebateHook.getFeeConfig();
uint256 correctFee = (sellAmount * sellFee) / 1_000_000;
uint256 wrongFee = (sellAmount * sellFee) / 100_000;
console.log("==============================");
console.log("Expected correct fee:", correctFee);
console.log("Expected wrong fee: ", wrongFee);
console.log("Sell fee (PIPs):", sellFee);
console.log("==============================");
// Run the swap WITHOUT expectEmit
swapRouter.swap(key, params, settings, ZERO_BYTES);
vm.stopPrank();
}
```
</details>

Recommended Mitigation

1.Modify the `_beforeSwap` function to work correctly.
```diff
/// @notice Applies dynamic fees before each swap based on buy/sell direction
/// @param sender Address initiating the swap
/// @param key The pool key for the swap
/// @param params Swap parameters including direction and amount
/// @return Function selector, delta (always zero), and the dynamic fee to apply
function _beforeSwap(
address sender,
PoolKey calldata key,
SwapParams calldata params,
bytes calldata
) internal override returns (bytes4, BeforeSwapDelta, uint24) {
bool isReFiBuy = _isReFiBuy(key, params.zeroForOne);
uint256 swapAmount = params.amountSpecified < 0
? uint256(-params.amountSpecified)
: uint256(params.amountSpecified);
uint24 fee;
if (isReFiBuy) {
fee = buyFee;
emit ReFiBought(sender, swapAmount);
} else {
fee = sellFee;
- uint256 feeAmount = (swapAmount * sellFee) / 100000;
+ uint256 feeAmount = (swapAmount * sellFee) / 1_000_000;
emit ReFiSold(sender, swapAmount, feeAmount);
}
return (
BaseHook.beforeSwap.selector,
BeforeSwapDeltaLibrary.ZERO_DELTA,
fee | LPFeeLibrary.OVERRIDE_FEE_FLAG
);
}
```
Updates

Lead Judging Commences

chaossr Lead Judge 12 days ago
Submission Judgement Published
Invalidated
Reason: Lack of quality

Appeal created

chain__warden Submitter
11 days ago
chaossr Lead Judge
10 days ago
chaossr Lead Judge 8 days ago
Submission Judgement Published
Invalidated
Reason: Lack of quality

Support

FAQs

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

Give us feedback!