Shares in PerpetualVault fails to maintain consistency between totalShares and the sum of individual deposit shares. This breaks the fundamental accounting of the vault, potentially leading to incorrect share calculations during deposits and withdrawals. The core economic principle of share-based accounting is compromised.
The issue centers around the PerpetualVault's share accounting system. The vault tracks user deposits through shares, similar to how a traditional LP token works. It requires that totalShares always equals the sum of all individual deposit shares, which is crucial for maintaining fair value distribution among depositors.
But looking at the PerpetualVault contract, we see share minting occurs in the _mint () function during deposits
The issue flows through these functions:
GMX position updates trigger afterOrderExecution() function
Which calls _mint during deposits
Which relies on _totalAmount function for share calculation
But position values from VaultReader can change asynchronously
This creates the share accounting desynchronization vulnerability.
The path where the invariant can break is in the share calculation logic. See how the share calculation depends on _totalAmount() which involves complex GMX position calculations through VaultReader. This creates multiple states where share accounting can become inconsistent.
During position updates through GMX callbacks
When handling liquidations
During the compound flow where new shares are minted
The root cause is the lack of atomic updates between position value changes and share recalculations. When GMX positions change in value, the total vault value changes, but share accounting may not immediately reflect this.
This inconsistency means users could receive incorrect amounts during withdrawals since the withdrawal amount calculation relies on the share ratio: PerpetualVault.sol#L1137
The error is in how the PerpetualVault handles share accounting during complex trading operations. The contract maintains a critical invariant, totalShares must equal the sum of all deposit shares, but this can break during asynchronous GMX operations.
When users deposit into the vault, they receive shares representing their ownership. The share calculation happens in _mint()
This means that share minting depends on _totalAmount(), which involves complex GMX position valuations through VaultReader. The asynchronous nature of GMX operations creates a timing gap between position value changes and share updates.
Like a ledger that doesn't immediately reflect all pending transactions, when GMX executes trades through callbacks, the vault's total value changes, but share accounting may lag behind. This desynchronization breaks our core invariant.
During withdrawals, users could receive incorrect amounts because the withdrawal calculation uses potentially stale share ratios
In the PerpetualVault, users deposit USDC to gain exposure to leveraged trading positions through GMX. The vault tracks these deposits using shares, similar to how a mutual fund works. Each vault maintains a specific leverage ratio (1x-3x) and can take long or short positions through GMX perpetuals.
The share calculation in _mint() relies on _totalAmount(), which includes the value of GMX positions
When GMX executes trades through its keeper system, position values change asynchronously through callbacks. This creates a timing mismatch, the vault's share accounting doesn't immediately reflect these position value changes.
Manual
Implement atomic share reconciliation after GMX position updates, ensuring the vault maintains accurate ownership accounting throughout all trading operations.
So that we ensure
Position values are captured immediately after GMX updates
Share values are reconciled before any new mints/burns
Total shares maintain consistency with actual vault value
This creates atomic updates between GMX position changes and vault share accounting
Shares represent a part of the vault. Even if someone performs a frontrun or sandwich attack, you will still have the corresponding amount of shares representing your deposit. A user could add liquidity two days later, and you would still have the same amount of shares.
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.