<!-- canonical: https://0xsimao.com/findings/cork-protocol-attributed-withdrawals-untracked-expires -->

# `VaultPoolLib::reserve()` will store the `Pa` not attributed to user withdrawals incorrectly and leave in untracked once it expires again

Crit/High · Sherlock · Derivatives · 29th August 2024

Finding H-11 of the Cork Protocol competition.

- Protocol: https://audits.sherlock.xyz/contests/506
- Codebase: https://github.com/0xsimao/2024-08-cork-protocol/tree/db23bf67e45781b00ee6de5f6f23e621af16bd7e
- Source: https://github.com/sherlock-audit/2024-08-cork-protocol-judging/issues/191

---

### Summary

[VaultPoolLib::reserve()](https://github.com/sherlock-audit/2024-08-cork-protocol/blob/main/Depeg-swap/contracts/libraries/VaultPoolLib.sol#L12) stores the `Pa` attributed to withdrawals in [self.withdrawalPool.stagnatedPaBalance](https://github.com/sherlock-audit/2024-08-cork-protocol/blob/main/Depeg-swap/contracts/libraries/VaultPoolLib.sol#L31) 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 
```solidity
    // 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()](https://github.com/sherlock-audit/2024-08-cork-protocol/blob/main/Depeg-swap/contracts/libraries/VaultPoolLib.sol#L170) function only uses the `Ra` [balance](https://github.com/sherlock-audit/2024-08-cork-protocol/blob/main/Depeg-swap/contracts/libraries/VaultPoolLib.sol#L171), 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

1. `VaultPoolLib::reserve()` is called when liquidating the lp position of the `Vault` via `VaultLib::_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`.
```solidity
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.

---

Related findings:

- [Liquidator will leave a pool with unassigned earnings on `Market::clearBadDebt()` free to claim for anyone when the repaid maturity is not the last](https://0xsimao.com/findings/exactly-protocol-update-staking-contract-ii-liquidator-clear-debt-repaid): Exactly Protocol Update - Staking Contract
- [Adapters could store the index instead of true in the `VaultV2` to remove the O(n) search](https://0xsimao.com/findings/morpho-vault-v2-adapters-store-index-search): Morpho Vault V2
- [`totalCdsDepositedAmountWithOptionFees` is incorrectly reduced in `CDSLib::withdrawUser()`, leading to stuck option fees](https://0xsimao.com/findings/autonomint-fees-reduced-withdraw-stuck): Autonomint
- [`CDSLib::calculateCumulativeRate()` incorrectly only increment the local option fees when there are cds deposits](https://0xsimao.com/findings/autonomint-increment-local-fees-deposits): Autonomint
