Part 2

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

Unsafe Market Delisting Can Temporarily Lock User Funds

Description

The pauseMarket function in MarketMakingEngineConfigurationBranch lacks critical safety checks that are explicitly required by the protocol's documentation. The function allows markets to be delisted before being disabled at the engine level, which can lead to a temporary state where users cannot access their funds.

The current implementation:

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

This contradicts the documentation requirement:

/// In order to delist a market and allow Vaults to fully undelegate the provided credit,
/// it first must be disabled at the engine level in order to prevent users from being
/// able to fulfill their expected profits.

When a market is delisted without proper sequencing:

  1. Users with open profitable positions can't claim their profits

  2. The credit delegation system becomes temporarily unusable

  3. Funds become inaccessible until the market is unpaused

Impact

  1. Temporary Fund Inaccessibility:

    • Users cannot claim their unrealized profits until market is unpaused

    • Affects all users with open profitable positions

    • Recovery is possible through admin action (unpausing)

  2. Protocol Impact:

    • Temporary credit system imbalance

    • User experience degradation

    • Potential trust issues if situation persists

Recommended Mitigation

Add Safety Checks to pauseMarket:

function pauseMarket(uint128 marketId) external onlyOwner returns (bool success) {
Market.Data storage market = Market.load(marketId);
address engine = market.engine;
// Verify market is disabled in PerpsEngine first
require(
!IPerpsEngine(engine).isMarketEnabled(marketId),
"Market still active in perps"
);
// Verify no unrealized debt before pausing
require(
IEngine(engine).getUnrealizedDebt(marketId) == 0,
"Has unrealized debt"
);
success = LiveMarkets.load().removeMarket(marketId);
if (success) emit LogMarketPaused(marketId);
}
Updates

Lead Judging Commences

inallhonesty Lead Judge 3 months ago
Submission Judgement Published
Invalidated
Reason: Non-acceptable severity

Support

FAQs

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