The execution fee and governance fee calculations in the Perpetual Vault Protocol may introduce rounding errors and fee skimming, leading to potential losses for users.
The execution fee is not always refunded if excess gas is sent.
The governance fee rounding may cause users to pay slightly more than expected.
Fee skimming occurs silently, meaning users are unaware of small losses over time.
1. Execution Fee Skimming in PerpetualVault.sol::_payExecutionFee
The execution fee is calculated based on estimated gas costs, but excess ETH may not be refunded.
Users may overpay without receiving a refund for unused execution gas.
1.1 PerpetualVault.sol::_payExecutionFee() does not refund excess ETH
Code Snippet:
This function sends the entire msg.value to gmxProxy, even if it is more than required.
No refund logic exists within this function.
1.2. There is a Refund Function (GmxProxy.sol::refundExecutionFee), But It’s Not Always Triggered
Code Snippet:
Refunds are only processed when refundExecutionFee() is called.
The function is a callback from GMX, meaning refunds only happen when an order is canceled or fails execution.
If no explicit refund request is made, excess ETH remains with the protocol.
1.3. Manual Refund Call from PerpetualVault.sol::_handleReturn() and PerpetualVault.sol::_cancelFlow()
Function: PerpetualVault.sol::_handleReturn() (called at the end of a withdrawal).
Function: PerpetualVault.sol::_cancelFlow() (called if a deposit or withdrawal fails).
Both attempt to refund any remaining execution fee, but they use a try-catch block, meaning if the call fails, the refund never happens.
2. Rounding Errors in Governance Fee Calculation (PerpetualVault.sol::_transferToken)
The governance fee is calculated using integer division, which can result in rounding errors where users are charged slightly more than intended.
Impacted Code:
Users Lose Funds Due to Silent Fee Skimming
No refund mechanism exists for excess execution fees.
Small rounding errors result in unclaimed amounts being transferred to the treasury.
Cumulative Rounding Losses Over Time
Since users repeatedly deposit and withdraw, small rounding errors accumulate, resulting in long-term user losses.
As per previous findings I used OpenAi as part of my research into the code vulnerabilities.
1. Ensure Proper Execution Fee Refund Mechanism:
Modify _payExecutionFee() to refund unused gas fees to the user.
2. Fix Governance Fee Calculation to Reduce Rounding Errors:
Recalculate the fee calculation itself by using rounding up logic:
Adding BASIS_POINTS_DIVISOR - 1 ensures rounding up rather than rounding down.
Prevents users from overpaying due to integer division.
Please read the CodeHawks documentation to know which submissions are valid. If you disagree, provide a coded PoC and explain the real likelihood and the detailed impact on the mainnet without any supposition (if, it could, etc) to prove your point.
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.