PositionManager's moveLiquidity can freeze funds by removing destination index even when the move was partial #503
Labels
3 (High Risk)
Assets can be stolen/lost/compromised directly
bug
Something isn't working
H-01
primary issue
Highest quality submission among a set of duplicates
satisfactory
satisfies C4 submission criteria; eligible for awards
selected for report
This submission will be included/highlighted in the audit report
sponsor confirmed
Sponsor agrees this is a problem and intends to fix it (OK to use w/ "disagree with severity")
Lines of code
https://github.com/code-423n4/2023-05-ajna/blob/276942bc2f97488d07b887c8edceaaab7a5c3964/ajna-core/src/PositionManager.sol#L262-L323
Vulnerability details
positionIndex.remove(params_.fromIndex)
removes the PositionManager entry even when it is only partial removal as a result ofIPool(params_.pool).moveQuoteToken(...)
call.I.e. it is correct to do
fromPosition.lps -= vars.lpbAmountFrom
, but the resulting amount might not be zero, moveQuoteToken() are not guaranteed to clear the position as it has available liquidity constraint. In the case of partial quote funds removalpositionIndex.remove(params_.fromIndex)
operation will freeze the remaining position.Impact
Permanent fund freeze for the remaining position of LP beneficiary.
Proof of Concept
While
positions[params_.tokenId][params_.fromIndex]
LP shares are correctly reduced by the amount returned by pool's moveQuoteToken(), the position itself is unconditionally removed from thepositionIndexes[params_.tokenId]
, making any remaining funds unavailable:https://github.com/code-423n4/2023-05-ajna/blob/276942bc2f97488d07b887c8edceaaab7a5c3964/ajna-core/src/PositionManager.sol#L262-L323
Bucket can contain a mix of quote and collateral tokens, but moveLiquidity() aims to retrieve
vars.maxQuote = _lpToQuoteToken(...)
quote funds per current exchange rate:https://github.com/code-423n4/2023-05-ajna/blob/276942bc2f97488d07b887c8edceaaab7a5c3964/ajna-core/src/libraries/helpers/PoolHelper.sol#L222-L236
There might be not enough quote deposit funds available to redeem the whole quote amount requested, which is controlled by the corresponding liquidity constraint:
https://github.com/code-423n4/2023-05-ajna/blob/276942bc2f97488d07b887c8edceaaab7a5c3964/ajna-core/src/libraries/external/LenderActions.sol#L711-L719
Recommended Mitigation Steps
As a most straightforward solution consider reverting when there is a remainder, i.e. when
fromPosition.lps > dust_threshold
:https://github.com/code-423n4/2023-05-ajna/blob/276942bc2f97488d07b887c8edceaaab7a5c3964/ajna-core/src/PositionManager.sol#L262-L323
Assessed type
Error
The text was updated successfully, but these errors were encountered: