Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Cheerful Taffy Dolphin - Lack of LEVERAGE_BUFFER Check in updateLeverage() Causes Position Operations to Revert Due to Storage-Execution Mismatch #45

Open
sherlock-admin4 opened this issue Jan 31, 2025 · 0 comments
Labels
Sponsor Disputed The sponsor disputed this issue's validity

Comments

@sherlock-admin4
Copy link
Contributor

Cheerful Taffy Dolphin

Medium

Lack of LEVERAGE_BUFFER Check in updateLeverage() Causes Position Operations to Revert Due to Storage-Execution Mismatch

Description

The updateLeverage function in Vault.sol allows setting leverage values without validating against the LEVERAGE_BUFFER constraint (1.2e6) defined in MakerStrategyLib.sol. While MakerStrategyLib enforces this constraint during strategy execution, the lack of validation at the leverage update level creates a potential mismatch between stored leverage values and what can be safely executed.

https://github.com/sherlock-audit/2025-01-perennial-v2-4-update/blob/main/perennial-v2/packages/vault/contracts/Vault.sol#L215

// Vault.sol
function updateLeverage(uint256 marketId, UFixed6 newLeverage) external onlyOwner {
    rebalance(address(0));
    if (marketId >= totalMarkets) revert VaultMarketDoesNotExistError();
    _updateMarket(marketId, UFixed6Lib.MAX, newLeverage);
}
// MakerStrategyLib.sol
UFixed6 public constant LEVERAGE_BUFFER = UFixed6.wrap(1.2e6);

function _allocateMarket(...) private pure returns (Target memory target, UFixed6 marketCollateral) {
    marketCollateral = marketContext.margin
        .add(collateral.sub(totalMargin).mul(marketContext.registration.weight));

    // LEVERAGE_BUFFER enforcement
    UFixed6 marketAssets = assets
        .mul(marketContext.registration.weight)
        .min(marketCollateral.mul(LEVERAGE_BUFFER));
}

Scenario:

  1. Owner calls updateLeverage with a leverage value > 1.2e6
  2. The update succeeds and stores the high leverage value
  3. When strategy executes, operations fail due to LEVERAGE_BUFFER check in MakerStrategyLib
  4. Results in positions that cannot be properly adjusted

Impact

When updateLeverage() allows setting leverage values above LEVERAGE_BUFFER (1.2e6), it creates a critical state inconsistency since MakerStrategyLib.allocate() enforces this limit during position calculations and strategy execution. This leads to a scenario where the stored leverage value in Registration.leverage is higher than what allocate() will allow during position adjustments, causing allocate() to calculate invalid position sizes based on unusable leverage values

Subsequent calls to update() or rebalance() will fail when MakerStrategyLib attempts to execute positions with the stored leverage, as the calculations in _allocateMarket() involving marketContext.registration.leverage will exceed LEVERAGE_BUFFER constraints.

This temporarily locks vault funds in existing positions, as any attempt to modify positions through the strategy will revert due to the leverage mismatch between storage and execution constraints - until an owner updates the leverage to a value within LEVERAGE_BUFFER limits.

Recommendation

Add validation in updateLeverage to enforce the LEVERAGE_BUFFER constraint:

function updateLeverage(uint256 marketId, UFixed6 newLeverage) external onlyOwner {
    rebalance(address(0));
    if (marketId >= totalMarkets) revert VaultMarketDoesNotExistError();
    if (newLeverage.gt(LEVERAGE_BUFFER)) revert InvalidLeverageError();
    _updateMarket(marketId, UFixed6Lib.MAX, newLeverage);
}
@sherlock-admin3 sherlock-admin3 added the Sponsor Disputed The sponsor disputed this issue's validity label Feb 5, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Sponsor Disputed The sponsor disputed this issue's validity
Projects
None yet
Development

No branches or pull requests

2 participants