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;
@> uint256 feeAmount = (swapAmount * sellFee) / 100000;
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;
uint256 sellFee = 3000;
uint256 actualFee = (swapAmount * sellFee) / 100000;
uint256 expectedFee = (swapAmount * sellFee) / 1000000;
assertEq(actualFee, 30e18);
assertEq(expectedFee, 3e18);
assertEq(actualFee, expectedFee * 10);
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);
uint256 actualLoss = balanceBefore - balanceAfter;
assertGt(actualLoss, expectedFee * 9);
}
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);
}
// ...
}