The absence of slippage control in liquidity-related functions could result in users receiving significantly less output (tokens) in their transactions than expected. Malicious actors, such as MEV bots, can monitor pending transactions and manipulate the market (e.g., by front-running) to capitalize on this vulnerability.
Proof of Concept
Scenario:
A user intends to swap 1 ETH for Token X on a decentralized exchange using a function that lacks slippage control.
A MEV bot observes the pending transaction in the mempool.
The MEV bot strategically executes a large trade that depletes the immediate liquidity for Token X, causing its price to spike within the pool.
The user's original transaction executes when the price of Token X is significantly higher.
The user receives far less Token X than initially anticipated due to the price manipulation.
Technical Explanation:
The vulnerable function relies on the spot price from the liquidity pool at the time of execution. This spot price can be highly volatile.
Without limits, the transaction proceeds even if the price drastically changes between submission and execution.
This creates an opportunity for malicious actors to front-run and profit at the expense of the user.
function _mintFullRange(
IUniswapV3Pool v3Pool,
address token0,
address token1,
uint24 fee
) internal returns (uint256, uint256) {
(uint160 currentSqrtPriceX96, , , , , , ) = v3Pool.slot0();
// For full range: L = Δx * sqrt(P) = Δy / sqrt(P)
// We start with fixed token amounts and apply this equation to calculate the liquidity
// Note that for pools with a tickSpacing that is not a power of 2 or greater than 8 (887272 % ts != 0),
// a position at the maximum and minimum allowable ticks will be wide, but not necessarily full-range.
// In this case, the `fullRangeLiquidity` will always be an underestimate in respect to the token amounts required to mint.
uint128 fullRangeLiquidity;
unchecked {
// Since we know one of the tokens is WETH, we simply add 0.1 ETH + worth in tokens
if (token0 == WETH) {
fullRangeLiquidity = uint128(
Math.mulDiv96RoundingUp(FULL_RANGE_LIQUIDITY_AMOUNT_WETH, currentSqrtPriceX96)
);
} else if (token1 == WETH) {
fullRangeLiquidity = uint128(
Math.mulDivRoundingUp(
FULL_RANGE_LIQUIDITY_AMOUNT_WETH,
Constants.FP96,
currentSqrtPriceX96
)
);
} else {
// Find the resulting liquidity for providing 1e6 of both tokens
uint128 liquidity0 = uint128(
Math.mulDiv96RoundingUp(FULL_RANGE_LIQUIDITY_AMOUNT_TOKEN, currentSqrtPriceX96)
);
uint128 liquidity1 = uint128(
Math.mulDivRoundingUp(
FULL_RANGE_LIQUIDITY_AMOUNT_TOKEN,
Constants.FP96,
currentSqrtPriceX96
)
);
// Pick the greater of the liquidities - i.e the more "expensive" option
// This ensures that the liquidity added is sufficiently large
fullRangeLiquidity = liquidity0 > liquidity1 ? liquidity0 : liquidity1;
}
}
Tools Used
in-house tool
Recommended Mitigation Steps
Allow users to specify a percentage-based slippage tolerance within relevant functions (e.g., 0.5%, 1%).
Calculate a minimum acceptable output or maximum acceptable price based on this tolerance.
If the liquidity operation would result in outputs or prices outside the tolerance, revert the transaction.
Lines of code
https://github.com/code-423n4/2024-04-panoptic/blob/main/contracts/PanopticFactory.sol#L335-L380
Vulnerability details
Impact
The absence of slippage control in liquidity-related functions could result in users receiving significantly less output (tokens) in their transactions than expected. Malicious actors, such as MEV bots, can monitor pending transactions and manipulate the market (e.g., by front-running) to capitalize on this vulnerability.
Proof of Concept
Scenario:
A user intends to swap 1 ETH for Token X on a decentralized exchange using a function that lacks slippage control. A MEV bot observes the pending transaction in the mempool. The MEV bot strategically executes a large trade that depletes the immediate liquidity for Token X, causing its price to spike within the pool. The user's original transaction executes when the price of Token X is significantly higher. The user receives far less Token X than initially anticipated due to the price manipulation.
Technical Explanation:
The vulnerable function relies on the spot price from the liquidity pool at the time of execution. This spot price can be highly volatile. Without limits, the transaction proceeds even if the price drastically changes between submission and execution. This creates an opportunity for malicious actors to front-run and profit at the expense of the user.
function _mintFullRange:
Tools Used
in-house tool
Recommended Mitigation Steps
Allow users to specify a percentage-based slippage tolerance within relevant functions (e.g., 0.5%, 1%).
Calculate a minimum acceptable output or maximum acceptable price based on this tolerance.
If the liquidity operation would result in outputs or prices outside the tolerance, revert the transaction.
Assessed type
MEV