The logic for determining the amountToPay, the current implementation assumes that one of the deltas (amount0Delta or amount1Delta) will always be positive and the other will be negative or zero. However, this assumption may not always hold.
If both amount0Delta and amount1Delta are negative, the amountToPay will be incorrectly set to the absolute value of amount1Delta, even though no tokens need to be paid. This can lead to unintended token transfers and potential loss of funds for the payer.
Consider the following scenario:
The Uniswap V3 pool executes a swap that results in both amount0Delta and amount1Delta being negative, indicating that the pool should receive tokens from the payer.
The uniswapV3SwapCallback function is called with these negative deltas.
The current implementation of the function incorrectly determines the amountToPay as the absolute value of amount1Delta.
The function proceeds to transfer the amountToPay from the payer to the pool, even though no tokens should be transferred in this case.
As a result, the payer may lose funds unnecessarily, and the pool may receive tokens that it shouldn't have received.
// Transform the amount to pay to uint256 (take positive one from amount0 and amount1)
// the pool will always pass one delta with a positive sign and one with a negative sign or zero,
// so this logic always picks the correct delta to pay
uint256 amountToPay = amount0Delta > 0 ? uint256(amount0Delta) : uint256(amount1Delta);
// Pay the required token from the payer to the caller of this contract
SafeTransferLib.safeTransferFrom(token, decoded.payer, msg.sender, amountToPay);
As mentioned earlier, the assumption that one of the deltas will always be positive and the other negative or zero is not always true. This can lead to the incorrect determination of amountToPay when both deltas are negative.
Proof of Concept
Let's consider an example:
The Uniswap V3 pool executes a swap that results in amount0Delta = -100 and amount1Delta = -50, indicating that the pool should receive 100 tokens of token0 and 50 tokens of token1 from the payer.
The uniswapV3SwapCallback function is called with these deltas.
The current implementation incorrectly sets amountToPay to uint256(amount1Delta), which is equivalent to uint256(-50). Due to the unsigned integer conversion, amountToPay becomes a large positive value.
The function proceeds to transfer this large amount of tokens from the payer to the pool, even though no tokens should be transferred.
This how the incorrect determination of amountToPay can lead to unintended token transfers and potential loss of funds for the payer.
Tools Used
Vs Code
Recommended Mitigation Steps
Modify the logic to handle the case when both deltas are negative.
// Transform the amount to pay to uint256 (take positive one from amount0 and amount1)
uint256 amountToPay;
if (amount0Delta > 0) {
amountToPay = uint256(amount0Delta);
} else if (amount1Delta > 0) {
amountToPay = uint256(amount1Delta);
} else {
// Both deltas are negative, no need to pay
return;
}
// Pay the required token from the payer to the caller of this contract
SafeTransferLib.safeTransferFrom(token, decoded.payer, msg.sender, amountToPay);
Lines of code
https://github.com/code-423n4/2024-06-panoptic/blob/153f0d82440b7e63075d55b0659706531431145f/contracts/SemiFungiblePositionManager.sol#L452-L459
Vulnerability details
Impact
The logic for determining the
amountToPay
, the current implementation assumes that one of the deltas (amount0Delta
oramount1Delta
) will always be positive and the other will be negative or zero. However, this assumption may not always hold.If both
amount0Delta
andamount1Delta
are negative, theamountToPay
will be incorrectly set to the absolute value ofamount1Delta
, even though no tokens need to be paid. This can lead to unintended token transfers and potential loss of funds for the payer.Consider the following scenario:
amount0Delta
andamount1Delta
being negative, indicating that the pool should receive tokens from the payer.uniswapV3SwapCallback
function is called with these negative deltas.amountToPay
as the absolute value ofamount1Delta
.amountToPay
from the payer to the pool, even though no tokens should be transferred in this case.As a result, the payer may lose funds unnecessarily, and the pool may receive tokens that it shouldn't have received.
SemiFungiblePositionManager Contract (@contracts/SemiFungiblePositionManager.sol:452-459)
As mentioned earlier, the assumption that one of the deltas will always be positive and the other negative or zero is not always true. This can lead to the incorrect determination of
amountToPay
when both deltas are negative.Proof of Concept
Let's consider an example:
amount0Delta = -100
andamount1Delta = -50
, indicating that the pool should receive 100 tokens of token0 and 50 tokens of token1 from the payer.uniswapV3SwapCallback
function is called with these deltas.amountToPay
touint256(amount1Delta)
, which is equivalent touint256(-50)
. Due to the unsigned integer conversion,amountToPay
becomes a large positive value.This how the incorrect determination of
amountToPay
can lead to unintended token transfers and potential loss of funds for the payer.Tools Used
Vs Code
Recommended Mitigation Steps
Modify the logic to handle the case when both deltas are negative.
Assessed type
Error