The PerpetualVault contract mints shares for depositors based on incomplete valuation of the vault's assets. When a position is open (leveraged or spot), the calculation does not fully account for the current market value of the position, leading to unfair share distribution.
https://github.com/CodeHawks-Contests/2025-02-gamma/blob/e5b98627a4c965e203dbb616a5f43ec194e7631a/contracts/PerpetualVault.sol#L762
Faulty Code Snippet:
Incomplete Valuation: When the vault has an open position, _totalAmount(prices) includes the position's value. However, subtracting the new deposit (amount) from it ignores the proportional impact of the new funds on the position’s value.
Spot Position Handling: For 1x leverage (spot), the code uses the raw indexToken balance instead of its USD value, leading to incorrect valuations if the token’s price changes.
Example Scenario
Assumptions:
Existing Vault Value:
100k(includes50k collateral + $50k open position profit).
New Deposit: $50k.
Faulty Calculation:
Result:
New depositor gets 100 shares for 50k,but the true pre−deposit value was 100k. Their fair share should be 50 shares (50k/100k * 100 shares).
Dilution: New depositors receive more shares than deserved, diluting existing shareholders.
Losses for Existing Users: Profits from open positions are not factored into share price, allowing new users to claim a disproportionate share of gains.
Manual review
Shares must be minted based on the Net Asset Value (NAV) of the vault, which includes:
Collateral balance.
Current value of open positions (mark-to-market).
Pending fees or rebates.
Why the fix works:
Accurate NAV Calculation:
Use _calculateNAV to get the true value of collateral + open positions.
Fetch position value from vaultReader using current market prices.
Proportional Shares:
New shares = (depositAmount * totalShares) / NAVBeforeDeposit.
Verification
Test Case 1 (Open Position with Profit):
NAV before deposit: $100k (existing shares = 100).
Deposit: $50k.
New shares = ($50k * 100) / $100k = 50 (correct ✅).
Test Case 2 (Spot Position, Price Increase):
indexToken balance: 10 ETH (price:
2k→20k).
Deposit: $10k.
NAV before deposit: $20k (existing shares = 100).
New shares = ($10k * 100) / $20k = 50 (correct ✅).
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.