SellFee is not calculated correctly, which leads to on-chain data incorrectly recorded.
Description
-
_beforeSwap calculates sellFee with the wrong denominator.
-
However, while the fee returned by the function is correct, the feeAmount emitted in the ReFiSold event is incorrect.
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:
Impact:
Proof of Concept
The test case test_BuyReFi_ZeroFeeserves as a proof of concept for this issue, as the logic inversion causes a "buy" to be processed by the "sell" logic branch. The log trace shows the ReFiSold event being emitted with an incorrect fee amount:
│ │ │ │ ├─ [7225] ReFiSwapRebateHook::beforeSwap(PoolSwapTest: [0x2e234DAe75C793f67A35089C9d99245E1C58470b], PoolKey({ currency0: 0x0000000000000000000000000000000000000000, currency1: 0x212224D2F2d262cd093eE13240ca4873fcCBbA3C, fee: 8388608 [8.388e6], tickSpacing: 60, hooks: 0xF398DeAF12Ba47830ECA5a881175a3690A90F080 }), SwapParams({ zeroForOne: true, amountSpecified: -10000000000000000 [-1e16], sqrtPriceLimitX96: 4295128740 [4.295e9] }), 0x)
│ │ │ │ │ ├─ emit ReFiSold(seller: PoolSwapTest: [0x2e234DAe75C793f67A35089C9d99245E1C58470b], amount: 10000000000000000 [1e16], fee: 300000000000000 [3e14])
│ │ │ │ │ └─ ← [Return] 0x575e24b4, 0, 4197304 [4.197e6]
Let's analyze the emitted values:
The sellFee is 3000 (representing 0.3%), but the code calculates the feeAmount using an incorrect denominator of 100,000:
feeAmount = (swapAmount * sellFee) / 100000
feeAmount = (1e16 * 3000) / 100000 = 3e14
This calculation results in a 3% fee, not the intended 0.3%. The correct calculation requires a denominator of 1,000,000:
correctFeeAmount = (1e16 * 3000) / 1000000 = 3e13
The emitted feeAmount (3e14) is ten times larger than the correct amount (3e13), confirming the bug.
Recommended Mitigation
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) / 1000000;
emit ReFiSold(sender, swapAmount, feeAmount);
}
return (BaseHook.beforeSwap.selector, BeforeSwapDeltaLibrary.ZERO_DELTA, fee | LPFeeLibrary.OVERRIDE_FEE_FLAG);
}