You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Missing Position Size Validation in updateLeverage() Causes Forced Position Adjustments Across Pooled Vault Assets
Description
The updateLeverage function in Vault.sol calls rebalance(address(0)) but does not validate whether positions would remain valid under the new leverage settings. While rebalance settles current positions, it does not verify if those positions would be safely maintainable under the new leverage value.
When a new leverage value is set, the positions held in marketContext.currentAccountPosition are immediately subjected to different minAssets calculations in _allocateMarket(), where newMinAssets = marketContext.riskParameter.minMargin.unsafeDiv(newLeverage.mul(marketContext.riskParameter.maintenance))
This causes existing maker positions to become misaligned with market risk parameters since _allocateMarket() will calculate new collateral requirements against these positions using the updated leverage value, potentially pushing them below minPosition or above maxPosition bounds.
The next call to rebalance() or update() will attempt to force adjust these positions through MakerStrategyLib.allocate(), as the strategy recalculates targets based on the new leverage parameters without consideration for position size transitions.
Since the vault manages pooled positions, any forced adjustments affect all users' proportional share of the vault's total assets, as position modifications are executed at the vault level rather than per individual deposit.
Recommendation:
Add a validation function to MakerStrategyLib.sol:
/// @notice Validates if positions would remain valid under new leverage/// @param registrations Current market registrations array/// @param marketId Market to validate/// @param newLeverage Proposed new leverage value/// @return isValid True if positions would remain valid under new leveragefunction validatePositionsForLeverage(
Registration[] memoryregistrations,
uint256marketId,
UFixed6 newLeverage
) publicviewreturns (boolisValid) {
MarketMakerStrategyContext memory marketContext =_loadContext(registrations[marketId]);
// Skip validation if no current positionif (marketContext.currentAccountPosition.maker.isZero()) returntrue;
// Calculate minimum required assets with new leverage
UFixed6 newMinAssets = marketContext.riskParameter.minMargin
.unsafeDiv(newLeverage.mul(marketContext.riskParameter.maintenance));
// Check if current positions would remain valid
UFixed6 newPositionTarget = newMinAssets
.muldiv(newLeverage, marketContext.latestPrice.abs());
return newPositionTarget.gte(marketContext.minPosition) &&
newPositionTarget.lte(marketContext.maxPosition);
}
Modify Vault.sol updateLeverage function:
error InvalidPositionLeverageError();
function updateLeverage(uint256marketId, UFixed6 newLeverage) external onlyOwner {
rebalance(address(0));
if (marketId >= totalMarkets) revertVaultMarketDoesNotExistError();
// Build registrations array for validation
Registration[] memory registrations =newRegistration[](totalMarkets);
for (uint256 i =0; i < totalMarkets; i++) {
registrations[i] = _registrations[i].read();
}
// Validate positions would remain valid with new leverageif (!MakerStrategyLib.validatePositionsForLeverage(registrations, marketId, newLeverage))
revertInvalidPositionLeverageError();
_updateMarket(marketId, UFixed6Lib.MAX, newLeverage);
}
The text was updated successfully, but these errors were encountered:
Cheerful Taffy Dolphin
Medium
Missing Position Size Validation in updateLeverage() Causes Forced Position Adjustments Across Pooled Vault Assets
Description
The updateLeverage function in Vault.sol calls rebalance(address(0)) but does not validate whether positions would remain valid under the new leverage settings. While rebalance settles current positions, it does not verify if those positions would be safely maintainable under the new leverage value.
https://github.com/sherlock-audit/2025-01-perennial-v2-4-update/blob/main/perennial-v2/packages/vault/contracts/Vault.sol#L215
Impact
When a new leverage value is set, the positions held in marketContext.currentAccountPosition are immediately subjected to different minAssets calculations in _allocateMarket(), where newMinAssets = marketContext.riskParameter.minMargin.unsafeDiv(newLeverage.mul(marketContext.riskParameter.maintenance))
This causes existing maker positions to become misaligned with market risk parameters since _allocateMarket() will calculate new collateral requirements against these positions using the updated leverage value, potentially pushing them below minPosition or above maxPosition bounds.
The next call to rebalance() or update() will attempt to force adjust these positions through MakerStrategyLib.allocate(), as the strategy recalculates targets based on the new leverage parameters without consideration for position size transitions.
Since the vault manages pooled positions, any forced adjustments affect all users' proportional share of the vault's total assets, as position modifications are executed at the vault level rather than per individual deposit.
Recommendation:
Add a validation function to
MakerStrategyLib.sol
:Modify
Vault.sol
updateLeverage function:The text was updated successfully, but these errors were encountered: