RebateFi Hook

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

[M-1] Wrong divisor in fee calculation causes users to pay 10x higher fees than intended

Root + Impact

Description

The protocol intends to charge a 0.3% fee on ReFi token sales, represented by sellFee = 3000. To calculate 0.3% of a swap amount, the formula should be (amount * 3000) / 1,000,000.

The _beforeSwap() function uses 100000 as the divisor instead of 1000000, resulting in fees that are 10x higher than intended (3% instead of 0.3%).

function _beforeSwap(...) internal override returns (bytes4, BeforeSwapDelta, uint24) {
// ...
if (isReFiBuy) {
fee = buyFee;
emit ReFiBought(sender, swapAmount);
} else {
fee = sellFee; // sellFee = 3000 (intended to be 0.3%)
@> uint256 feeAmount = (swapAmount * sellFee) / 100000; // @audit results in 3% not 0.3%
emit ReFiSold(sender, swapAmount, feeAmount);
}
// ...
}

Risk

Likelihood:

  • Every sell transaction will calculate fees using the wrong divisor

  • The issue affects 100% of ReFi token sales

  • Users will immediately notice they're paying significantly higher fees than advertised

Impact:

  • Users pay 3% fees instead of the intended 0.3% when selling ReFi tokens

  • This is 10x higher than the designed fee structure

  • Makes the protocol economically uncompetitive compared to other DEXs

  • Users will avoid using pools with this hook due to excessive fees

  • Protocol reputation will be damaged

  • Liquidity providers may not be able to attract traders due to high fees

Proof of Concept

function test_FeeCalculationTooHigh() public {
uint256 swapAmount = 1000e18; // 1000 tokens
uint256 sellFee = 3000; // Intended 0.3%
// Current (incorrect) calculation
uint256 actualFee = (swapAmount * sellFee) / 100000;
// actualFee = (1000e18 * 3000) / 100000 = 30e18 = 30 tokens = 3%
// Expected (correct) calculation
uint256 expectedFee = (swapAmount * sellFee) / 1000000;
// expectedFee = (1000e18 * 3000) / 1000000 = 3e18 = 3 tokens = 0.3%
assertEq(actualFee, 30e18); // 3% fee - 30 tokens
assertEq(expectedFee, 3e18); // 0.3% fee - 3 tokens
// Users pay 10x more than intended
assertEq(actualFee, expectedFee * 10);
// Demonstrate in a real swap
SwapParams memory params = SwapParams({
zeroForOne: false,
amountSpecified: -int256(swapAmount),
sqrtPriceLimitX96: MAX_PRICE_LIMIT
});
uint256 balanceBefore = IERC20(token).balanceOf(swapper);
vm.prank(swapper);
swap(key, params, ZERO_BYTES);
uint256 balanceAfter = IERC20(token).balanceOf(swapper);
// User lost 30 tokens instead of 3 tokens
uint256 actualLoss = balanceBefore - balanceAfter;
assertGt(actualLoss, expectedFee * 9); // Lost way more than expected
}

Recommended Mitigation

function _beforeSwap(...) internal override returns (bytes4, BeforeSwapDelta, uint24) {
// ...
} else {
fee = sellFee;
- uint256 feeAmount = (swapAmount * sellFee) / 100000;
+ uint256 feeAmount = (swapAmount * sellFee) / 1000000;
emit ReFiSold(sender, swapAmount, feeAmount);
}
// ...
}
Updates

Lead Judging Commences

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