The PerpetualVault contract has a significant flaw in its withdrawal mechanism where users withdrawing in parallel can receive incorrect amounts of funds due to stale position data being used in calculations. This directly violates the protocol's core invariant of "Fair Share of Funding Fees" and "Depositor Share Value Preservation" as stated in the documentation.
According to the documentation: "Depositor Share Value Preservation: The value of a depositor's shares should never decrease due to the actions of other depositors. Any losses or gains should be distributed proportionally based on share ownership."
However, the current implementation fails to maintain this invariant during parallel withdrawals, leading to disproportionate fund distribution.
The vulnerability lies in the _withdraw
function, where position data used for calculating withdrawal amounts isn't properly synchronized with the actual state of the vault:
Consider this scenario:
The vault has 5000 USDC total collateral
Alice, Bob, Charlie, David, and Eve each deposit 1000 USDC (20% shares each)
Alice initiates withdrawal
Before Alice's withdrawal processes:
Bob withdraws successfully (800 USDC received after fees)
Charlie withdraws successfully (800 USDC received after fees)
David withdraws successfully (800 USDC received after fees)
When Alice's withdrawal finally processes, it uses the original position data (5000 USDC), calculating her share as 1000 USDC instead of 320 USDC (20% of remaining 1600 USDC)
Eve, the last user, is left with significantly less than their fair share
This is particularly concerning because the documentation explicitly states: "There could be delays in claiming some funding fees. If the user withdraws prior to the ability to claim, then it would be ok not to receive his fair share." However, this vulnerability causes early withdrawers to receive MORE than their fair share, leaving later withdrawers with less than they deserve.
This scenario better demonstrates the real-world impact because:
It shows how multiple withdrawals can compound the issue
It demonstrates how later users can be significantly impacted
It's more realistic with 5 users instead of just 2
It accounts for protocol fees in the calculations
It shows how the total withdrawn amount can exceed what should be available
Manual Review
Foundry
Implement a withdrawal queue system that captures position state at the time of withdrawal request:
This ensures that withdrawal amounts are calculated based on the position state at the time of request, maintaining fair distribution of funds among users.
There is no real proof, concrete root cause, specific impact, or enough details in those submissions. Examples include: "It could happen" without specifying when, "If this impossible case happens," "Unexpected behavior," etc. Make a Proof of Concept (PoC) using external functions and realistic parameters. Do not test only the internal function where you think you found something.
The contest is live. Earn rewards by submitting a finding.
This is your time to appeal against judgements on your submissions.
Appeals are being carefully reviewed by our judges.