In PerpetualVault.sol, when a user withdraws funds or closes a leveraged position, the contract incorrectly transfers collateralToken instead of the actual borrowed token.
This issue occurs when self-lending pods are used, where the borrowed token differs from the collateral token. Since collateralToken.safeTransfer() is called in _transferToken(), it assumes that the collateral token is the correct asset, which is not always true for leveraged positions.
If a user attempts to withdraw or close a leveraged position, the contract may:
Fail the transaction, preventing withdrawals.
Send the wrong token, resulting in fund loss or incorrect settlements.
When a user withdraws funds or closes a leveraged position in PerpetualVault.sol, the contract incorrectly transfers collateralToken instead of the actual borrowed token.
Root Cause
The contract always assumes collateralToken is the correct asset, even when a position was opened with leverage.
If self-lending pods were used, the actual borrowed token should be returned instead.
The incorrect assumption leads to failed withdrawals or incorrect token settlements.
** Affected Code:** _transferToken() (Incorrect Token Transfer)
This assumes collateralToken is correct, but for leveraged positions, the borrowed token should be used instead.
Affected Code: _withdraw() (Fails for Leveraged Positions)
If the position was opened with a self-lending pod, the wrong token is used for withdrawal calculations.
Scenario 1: User Cannot Withdraw from a Leveraged Position
Context:
Trader Alice wants to go long on ETH/USD with 3x leverage.
She deposits 1,000 USDC into the PerpetualVault.
The vault borrows 2,000 USDC and swaps it to ETH, opening a 3,000 USDC long position on GMX.
Alice's position is now collateralized in ETH, but she originally deposited USDC.
The Issue:
After some time, Alice wants to withdraw her funds.
The vault only knows about the original deposit token (USDC) and attempts to transfer USDC back to Alice.
Since Alice’s collateral is in ETH, there is no USDC in the vault to return.
The withdrawal fails, preventing Alice from exiting her position.
** Impact:**
Alice is locked in the vault and cannot reclaim her funds unless the vault swaps ETH back into USDC manually.
If ETH drops in value while she’s unable to exit, Alice could be liquidated and lose everything.
Scenario 2: Wrong Token Sent to the User
Context:
Trader Bob opens a 2x short position on BTC/USD.
He deposits 5,000 USDC into the PerpetualVault.
The vault borrows BTC using a self-lending protocol and opens a 10,000 USDC BTC short on GMX.
Since Bob's collateral is BTC, he expects to receive BTC when withdrawing.
The Issue:
Bob decides to close his position and withdraw funds.
The vault mistakenly tries to send USDC instead of BTC.
Since the vault doesn't have USDC (it was used to borrow BTC), Bob's withdrawal fails.
Alternatively, the vault might wrongly send other users' USDC, causing a fund imbalance.
Impact:
If the vault incorrectly sends USDC instead of BTC, Bob receives an incorrect amount.
Bob loses money because he expected BTC at a certain price, but he was given an incorrect amount of USDC instead.
This issue directly affects user withdrawals, liquidations, and overall vault solvency.
| Impact Area | Effect | Severity |
|---|---|---|
| Users Cannot Withdraw Funds | Locked positions prevent users from exiting | 🔴 High |
| Incorrect Token Sent to Users | Unexpected losses due to mispricing | 🔴 High |
| Malicious Exploits in Liquidations | Attackers drain vault funds | 🔴 High |
| Vault Insolvency | The vault ends up owing more than it holds | 🔴 High |
Manual Review
Introduce _getBorrowTokenForVault() to correctly identify whether to return collateral or borrowed assets.
Use _getBorrowTokenForVault() in _transferToken() and _withdraw() to ensure users receive the right token.
Modify _createIncreasePosition() to store the borrowed token when a leveraged position is opened.
** Fix for** _transferToken()
Implement _getBorrowTokenForVault()
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.