Part 2

Zaros
PerpetualsDEXFoundrySolidity
70,000 USDC
View results
Submission Details
Severity: medium
Invalid

LiquidationBranch Contract Expose Users to Increased Losses Without an Emergency Pause Mechanism

Summary

The LiquidationBranch.sol contract lacks an "emergency pause" mechanism, a crucial security feature in DeFi projects. While the MarketMakingEngineConfigurationBranch contract provides functions to pause and unpause specific markets, it may not be sufficient to address the need for a comprehensive pause system in the liquidation process, particularly during emergencies, market anomalies, or system upgrades.

Vulnerability Details

The absence of an emergency pause mechanism in the LiquidationBranch.sol contract exposes the platform to risks in case of a critical bug or unexpected market behavior. Without this feature, an attacker might continue exploiting vulnerabilities, and users may continue to lose funds.

src/perpetuals/branches/LiquidationBranch.sol#L21

The pauseMarket and unpauseMarket functions in the MarketMakingEngineConfigurationBranch contract only apply to specific markets, leaving the broader liquidation process exposed. If a vulnerability is detected in the liquidation system, pausing individual markets may not be sufficient to stop the liquidation of positions in other markets.

src/market-making/branches/MarketMakingEngineConfigurationBranch.sol#L570-L578

function unpauseMarket(uint128 marketId) external onlyOwner returns (bool success) {
success = LiveMarkets.load().addMarket(marketId);
if (success) emit LogMarketUnpaused(marketId);
}
function pauseMarket(uint128 marketId) external onlyOwner returns (bool success) {
success = LiveMarkets.load().removeMarket(marketId);
if (success) emit LogMarketPaused(marketId);
}

Impact

  1. Exploitation of Vulnerabilities: If a significant bug is discovered, but there is no way to pause the liquidation system, attackers could exploit the vulnerability and continue extracting user funds.

  2. User Losses: Without the ability to pause all liquidations, users may continue to suffer from ongoing liquidation processes during critical situations.

  3. Inability to Safely Upgrade: The lack of a pause mechanism prevents safe upgrades of the liquidation system, as critical changes or fixes could be applied while the system is still active.

Tools Used

Manual Code Review

Recommendations

It is recommended to implement a liquidation pause mechanism and introduce a flag to pause all liquidation operations across the system. Add checks within the liquidation functions to ensure that no liquidations occur if the system or market is paused.
For example:

contract LiquidationBranch {
// State variables for liquidation control
bool public isLiquidationPaused;
mapping(uint128 => bool) public isMarketLiquidationPaused;
// Events for pause/unpause actions
event AllLiquidationsPaused(address indexed admin);
event AllLiquidationsUnpaused(address indexed admin);
event MarketLiquidationPaused(uint128 indexed marketId, address indexed admin);
event MarketLiquidationUnpaused(uint128 indexed marketId, address indexed admin);
// Pause all liquidation operations globally
function pauseAllLiquidations() external onlyAdmin {
isLiquidationPaused = true;
emit AllLiquidationsPaused(msg.sender);
}
// Resume all liquidation operations globally
function unpauseAllLiquidations() external onlyAdmin {
isLiquidationPaused = false;
emit AllLiquidationsUnpaused(msg.sender);
}
// Pause liquidation for a specific market
function pauseMarketLiquidation(uint128 marketId) external onlyAdmin {
isMarketLiquidationPaused[marketId] = true;
emit MarketLiquidationPaused(marketId, msg.sender);
}
// Resume liquidation for a specific market
function unpauseMarketLiquidation(uint128 marketId) external onlyAdmin {
isMarketLiquidationPaused[marketId] = false;
emit MarketLiquidationUnpaused(marketId, msg.sender);
}
// Batch resume liquidations for multiple markets
function batchUnpauseMarketLiquidations(uint128[] calldata marketIds) external onlyAdmin {
for (uint256 i = 0; i < marketIds.length; i++) {
isMarketLiquidationPaused[marketIds[i]] = false;
emit MarketLiquidationUnpaused(marketIds[i], msg.sender);
}
}
// Main liquidation function with pause checks
function liquidateAccounts(uint128[] calldata accountsIds) external {
require(!isLiquidationPaused, "Liquidation is paused");
for (uint256 i; i < accountsIds.length; i++) {
uint128 marketId = // ... get market ID
require(!isMarketLiquidationPaused[marketId], "Market liquidation is paused");
// ... continue with liquidation logic
}
}
}
Updates

Lead Judging Commences

inallhonesty Lead Judge 4 months ago
Submission Judgement Published
Invalidated
Reason: Incorrect statement

Support

FAQs

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