The documentation mentions that execution fees are for GMX operations. But when the position is closed, the code doesn't refund the excess fee. In GMX, creating orders requires paying gas, and the execution fee is meant to cover that. However, if the vault immediately processes the deposit without needing a GMX order (because the position is closed), the full fee isn't used. But the code doesn't refund the difference
The Issue arises in the PerpetualVault::deposit
function through a fundamental design error where the refundFee
parameter is set to false
when positionIsClosed
is true
, despite the protocol's intention to handle immediate deposits differently.
This leads to incorrect fee behavior, preventing expected refunds. The fee collection mechanism calculates minimum execution fees based on gas limits, verifies that users provide sufficient funds, stores the exact fee amount in depositInfo
, and transfers the fees to the GMX Proxy. However, while the _mint
includes refund logic, it is never executed, resulting in excess fees being retained. The protocol maintains detailed tracking of execution fees, and the depositInfo
structure stores these amounts, but the absence of a refund process contradicts the intended design.
The impact of this vulnerability is significant, it indicates a disconnect between design and implementation cos users lose excess ETH sent as execution fees, leading to unnecessary fee retention by the protocol
Place the following test in test/PerpetualVault.t.sol
run with -vvv;
This test is meant to fail if the vault were to refund the extra fee—but given the design (with refundFee
set to false
for closed positions), it should pass by demonstrating that the entire fee is deducted and never refunded.
Manual review
change refundfee
to true
Fees are not collected during that scenario, so no refund needed.
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.