VaultPoolLib::reserve() will store the Pa not attributed to user withdrawals incorrectly and leave in untracked once it expires again
Summary
VaultPoolLib::reserve() stores the Pa attributed to withdrawals in self.withdrawalPool.stagnatedPaBalance instead of storing the amount attributedToAmm. Additionally, this amount of Pa, the one attributed to the Amm is never dealt with and leads to stuck PA.
The comment in the code mentions
// FIXME : this is only temporary, for now
// we trate PA the same as RA, thus we also separate PA
// the difference is the PA here isn't being used as anything
// and for now will just sit there until rationed again at next expiry.But it is incorrect as it is never rationed again, just forgotten. The VaultPoolLib::rationedToAmm() function only uses the Ra balance, not the Pa, which is effectively left untracked.
Root Cause
In VaultPoolLib:170, the leftover non attributed Pa is not dealt with.
Internal pre-conditions
None.
External pre-conditions
None.
Attack Path
VaultPoolLib::reserve()is called when liquidating the lp position of theVaultviaVaultLib::_liquidatedLP(), triggered by users when redeeming expired liquidity vault shares or on the admin trigerring a new issuance.
Impact
The Pa in the Vault is stuck.
PoC
VaultPoolLib::rationedToAmm() does not deal with the Pa.
function rationedToAmm(VaultPool storage self, uint256 ratio) internal view returns (uint256 ra, uint256 ct) {
uint256 amount = self.ammLiquidityPool.balance;
(ra, ct) = MathHelper.calculateProvideLiquidityAmountBasedOnCtPrice(amount, ratio);
}Mitigation
Distributed the Pa to users based on their LV shares or redeem the Pa for Ra and add liquidity to the new issued Ds or similar.