The liquidation eligibility check is performed after the premiums provided by the trader are decreased by liquidation rewards. This poses a risk for traders and could lead to a condition where a trader's position unexpectedly becomes eligible for liquidation.
Proof of Concept
It can be observed that currently, the liquidation eligibility check is performed after decreasing closeCache.tokenFromPremium and closeCache.tokenToPremium by liquidateCache.liquidationRewardFrom and liquidateCache.liquidationRewardTo.
/// @inheritdoc IParticlePositionManager
function liquidatePosition(
DataStruct.ClosePositionParams calldata params,
address borrower
) external override nonReentrant {
bytes32 lienKey = keccak256(abi.encodePacked(borrower, params.lienId));
Lien.Info memory lien = liens.getInfo(lienKey);
// check lien is valid
if (lien.liquidity == 0) revert Errors.RecordEmpty();
// local cache to avoid stack too deep
DataCache.ClosePositionCache memory closeCache;
DataCache.LiquidatePositionCache memory liquidateCache;
// get liquidation parameters
///@dev calculate premium outside of _closePosition to allow liquidatePosition to take reward from premium
(
closeCache.tokenFrom,
closeCache.tokenTo,
liquidateCache.tokenFromOwed,
liquidateCache.tokenToOwed,
closeCache.tokenFromPremium,
closeCache.tokenToPremium,
closeCache.collateralFrom,
) = Base.getOwedInfoConverted(
DataStruct.OwedInfoParams({
tokenId: lien.tokenId,
liquidity: lien.liquidity,
feeGrowthInside0LastX128: lien.feeGrowthInside0LastX128,
feeGrowthInside1LastX128: lien.feeGrowthInside1LastX128,
token0PremiumPortion: lien.token0PremiumPortion,
token1PremiumPortion: lien.token1PremiumPortion
}),
lien.zeroForOne
);
// calculate liquidation reward
liquidateCache.liquidationRewardFrom =
((closeCache.tokenFromPremium) * LIQUIDATION_REWARD_FACTOR) /
uint128(Base.BASIS_POINT);
liquidateCache.liquidationRewardTo =
((closeCache.tokenToPremium) * LIQUIDATION_REWARD_FACTOR) /
uint128(Base.BASIS_POINT);
>>> closeCache.tokenFromPremium -= liquidateCache.liquidationRewardFrom;
>>> closeCache.tokenToPremium -= liquidateCache.liquidationRewardTo;
// check for liquidation condition
///@dev the liquidation condition is that
/// (EITHER premium is not enough) OR (cutOffTime > startTime AND currentTime > startTime + LOAN_TERM)
>>> if (
!((closeCache.tokenFromPremium < liquidateCache.tokenFromOwed ||
closeCache.tokenToPremium < liquidateCache.tokenToOwed) ||
(lien.startTime < lps.getRenewalCutoffTime(lien.tokenId) &&
lien.startTime + LOAN_TERM < block.timestamp))
) {
revert Errors.LiquidationNotMet();
}
...
With this design, when the protocol decides to increase the LIQUIDATION_REWARD_FACTOR, it could directly impact traders' positions and potentially cause them to become liquidatable.
function updateLiquidationRewardFactor(uint128 liquidationRewardFactor) external override onlyOwner {
if (liquidationRewardFactor > _LIQUIDATION_REWARD_FACTOR_MAX) revert Errors.InvalidValue();
LIQUIDATION_REWARD_FACTOR = liquidationRewardFactor;
emit UpdateLiquidationRewardFactor(liquidationRewardFactor);
}
Tools Used
Manual review
Recommended Mitigation Steps
Perform the check before decreasing closeCache.tokenFromPremium and closeCache.tokenToPremium so that traders' position condition is easier to predict and maintain.
Lines of code
https://github.com/code-423n4/2023-12-particle/blob/main/contracts/protocol/ParticlePositionManager.sol#L349-L368
Vulnerability details
Impact
The liquidation eligibility check is performed after the premiums provided by the trader are decreased by liquidation rewards. This poses a risk for traders and could lead to a condition where a trader's position unexpectedly becomes eligible for liquidation.
Proof of Concept
It can be observed that currently, the liquidation eligibility check is performed after decreasing
closeCache.tokenFromPremium
andcloseCache.tokenToPremium
byliquidateCache.liquidationRewardFrom
andliquidateCache.liquidationRewardTo
.https://github.com/code-423n4/2023-12-particle/blob/main/contracts/protocol/ParticlePositionManager.sol#L349-L368
With this design, when the protocol decides to increase the
LIQUIDATION_REWARD_FACTOR
, it could directly impact traders' positions and potentially cause them to become liquidatable.https://github.com/code-423n4/2023-12-particle/blob/main/contracts/protocol/ParticlePositionManager.sol#L567-L571
Tools Used
Manual review
Recommended Mitigation Steps
Perform the check before decreasing
closeCache.tokenFromPremium
andcloseCache.tokenToPremium
so that traders' position condition is easier to predict and maintain.Assessed type
Context