DeFiFoundry
50,000 USDC
View results
Submission Details
Severity: high
Invalid

Indefinite Deposite Pause on Liquidation

Summary

The afterLiquidationExecution function in the PerpetualVault contract pauses deposits indefinitely upon liquidation, requiring manual intervention to resume operations.

Vulnerability Details

When a liquidation occurs during vault rebalancing, the afterLiquidationExecution function sets depositPaused to true, effectively pausing all deposits. There is no automatic mechanism to unpause deposits, which means that the protocol requires manual intervention by the owner to resume normal operations. This can lead to a situation where all subsequent operations are blocked until the owner manually resets the state.

Root Cause:
The root cause of this issue is the lack of an automatic unpause mechanism in the afterLiquidationExecution function. The function sets depositPaused to true without providing a way to automatically resume deposits.

Proof of Concept: Copy and paste this test into PerpetualVault.t.sol

function test_IndefinitePauseOnLiquidation() public {
// Setup deposit
address alice = makeAddr("alice");
uint256 depositAmount = 1e10;
depositFixture(alice, depositAmount);
// Simulate liquidation
address keeper = PerpetualVault(vault).keeper();
vm.prank(keeper);
PerpetualVault(vault).afterLiquidationExecution();
// Verify deposits are paused
bool depositPaused = PerpetualVault(vault).depositPaused();
assertTrue(depositPaused, "Deposits are not paused");
// Attempt to deposit funds
vm.startPrank(alice);
IERC20 collateralToken = PerpetualVault(vault).collateralToken();
collateralToken.approve(vault, depositAmount);
uint256 executionFee = PerpetualVault(vault).getExecutionGasLimit(true);
vm.expectRevert(Error.Paused.selector);
PerpetualVault(vault).deposit{value: executionFee * tx.gasprice}(depositAmount);
vm.stopPrank();
// Manually unpause deposits
address owner = PerpetualVault(vault).owner();
vm.prank(owner);
PerpetualVault(vault).setDepositPaused(false);
// Verify deposits are unpaused
depositPaused = PerpetualVault(vault).depositPaused();
assertFalse(depositPaused, "Deposits are still paused");
// Attempt to deposit funds again
vm.startPrank(alice);
collateralToken.approve(vault, depositAmount);
PerpetualVault(vault).deposit{value: executionFee * tx.gasprice}(depositAmount);
vm.stopPrank();
}

Impact

  • Protocol pauses deposits indefinitely: Deposits are paused indefinitely until manually unpaused by the owner.

  • All subsequent operations blocked: All subsequent deposit operations are blocked until manual reset.

  • Potential disruption of user experience: Users may be unable to deposit funds, leading to potential disruption and dissatisfaction.

Tools Used

Manual

Recommendations

To mitigate this issue, implement an automatic unpause mechanism or provide a way to resume deposits after a certain condition is met. Here are some recommendations:

  1. Automatic Unpause Mechanism: Implement logic to automatically unpause deposits after a certain condition is met, such as after a certain time period or after a successful rebalance.

  2. Manual Unpause with Notification: Provide a way to manually unpause deposits with a notification to the owner to take action.

function afterLiquidationExecution() external {
if (msg.sender != address(gmxProxy)) {
revert Error.InvalidCall();
}
depositPaused = true;
uint256 sizeInTokens = vaultReader.getPositionSizeInTokens(curPositionKey);
if (sizeInTokens == 0) {
delete curPositionKey;
}
if (flow == FLOW.NONE) {
flow = FLOW.LIQUIDATION;
nextAction.selector = NextActionSelector.FINALIZE;
} else if (flow == FLOW.DEPOSIT) {
flowData = sizeInTokens;
} else if (flow == FLOW.WITHDRAW) {
// restart the withdraw flow even though current step is FINALIZE.
nextAction.selector = NextActionSelector.WITHDRAW_ACTION;
}
// Automatically unpause deposits after a certain condition is met
if (positionIsClosed) {
depositPaused = false;
}
}
Updates

Lead Judging Commences

n0kto Lead Judge 8 months ago
Submission Judgement Published
Invalidated
Reason: Design choice

Support

FAQs

Can't find an answer? Chat with us on Discord, Twitter or Linkedin.