Open code423n4 opened 1 year ago
asselstine marked the issue as sponsor confirmed
Picodes marked the issue as satisfactory
I don't entirely understand the issue here, to me it looks like this is the intended behavior. Users knowingly deposited in a Vault relying on a YieldVault that employs Lossy Strategies to generate yield, let's say for example an option protocol, the position of the Vault loses value so all shares are backed by less underlying assets. When withdrawing, people will only be able to withdraw their shares of deposits which indeed socializes the loss. I think for this kind of YieldVaults, we will need to develop custom Vaults cause it's a pretty specific use case.
Working PR here: https://github.com/GenerationSoftware/pt-v5-vault/pull/37
Lines of code
https://github.com/GenerationSoftware/pt-v5-vault/blob/b1deb5d494c25f885c34c83f014c8a855c5e2749/src/Vault.sol#L509-L521
Vulnerability details
For Yield Vaults that use Lossy Strategies, the PT Vault will burn more Yield Vault Shares than intended when processing a withdrawal, socializing a loss at the advantage of early withdrawers
withdraw
calls_convertToShares
https://github.com/GenerationSoftware/pt-v5-vault/blob/b1deb5d494c25f885c34c83f014c8a855c5e2749/src/Vault.sol#L517
Which uses the
_currentExchangeRate()
This in turn computes the
withdrawableAssets
by fetchingyieldVault.maxWithdraw
and then mapping the principal vs the totalSupplyhttps://github.com/GenerationSoftware/pt-v5-vault/blob/b1deb5d494c25f885c34c83f014c8a855c5e2749/src/Vault.sol#L1169C1-L1187C4
This calculation is based on
maxWithdraw
, which is aview
functionMost implementation of
maxWithdraw
will simply map the available tokens to the shares owned by the owner, see OZ for example:https://github.com/OpenZeppelin/openzeppelin-contracts/blob/121be5dd09caa2f7ce731f0806b0e14761023bd6/contracts/token/ERC20/extensions/ERC4626.sol#L141-L143
Or similarly, Yearn V3
Due to the implementation, losses can be applied during
YieldVault.withdraw
, causing the burning of more shares than intendedBecause the PT Vault computes the shares to burn before accounting for a potential loss:
No loss will be accounted for in
maxWithdraw
(since it will use static value for assets in the vault and assets in the strategy)The loss will be locked during
_withdraw
, but it will not be checked, the specifics of the loss are that it will cause burning of more shares in order to receive the intendedassets
This will cause the user to pay
shares
from PT VaultBut it will cause PT Vault to pay more
yieldVault Shares
than intended, effectively diluting everyone else and socializing the losses on the laggardsProof Of Concept
_convertToShares
Mitigation
Ensures that the PPFS of the Yield Vault doesn't decrease, or add functions to handle lossy withdrawals
Assessed type
ERC4626