Skip to content

Latest commit

 

History

History
65 lines (43 loc) · 3.23 KB

File metadata and controls

65 lines (43 loc) · 3.23 KB

High Neon Llama

Medium

The RiskParameter.liquidationFee variable is not treated and validated as a percentage value, leading to breaking protocol invariants.

Summary

In Perennial v2.2, the RiskParameter.liquidationFee variable held a fixed amount. In Perennial v2.3, it became a percentage value. However, this change is not fully reflected in the code.

In RiskParameterStorageLib, it is incorrectly validated and compared to fixed values from the ProtocolParameter struct, leading to incorrect assumptions, particularly regarding the protocol-wide maxFeeAbsolute setting, as well as per-market minMaintenance values.

Vulnerability Detail

As stated in the README in the section, "Please list any known issues and explicitly state the acceptable risks for each known issue.":

Coordinators are given broad control over the parameters of the markets they coordinate. The protocol parameter is designed to prevent situations where parameters are set to maliciously steal funds. If the coordinator can operate within the bounds of reasonable protocol parameters to negatively affect markets, we would like to know about it.

There is theoretically no limitation on the liquidationFee value. The liquidation fee that can be paid by the account can exceed the maxFeeAbsolute value, breaking assumptions and negatively affecting the markets.

For example, if the maxFeeAbsolute value is set to $50, then the liquidationFee can be up to 5000% of the settlement fee, calculated using this equation:

File: VersionLib.sol
246:     function _accumulateLiquidationFee(
247:         Version memory next,
248:         VersionAccumulationContext memory context
249:     ) private pure returns (UFixed6 liquidationFee) {
250:         liquidationFee = context.toOracleVersion.valid ?
251:@>           context.toOracleReceipt.settlementFee.mul(context.riskParameter.liquidationFee) :
252:             UFixed6Lib.ZERO;

Here are the places where the liquidationFee percentage value is incorrectly validated against fixed values:

File: RiskParameter.sol
139:         if (self.liquidationFee.gt(protocolParameter.maxFeeAbsolute)) revert RiskParameterStorageInvalidError();
File: RiskParameter.sol
155:         if (self.minMaintenance.lt(self.liquidationFee)) revert RiskParameterStorageInvalidError();

Impact

  • Coordinators can negatively affect markets while operating within the bounds of reasonable protocol parameters.

Code Snippet

https://github.com/sherlock-audit/2024-08-perennial-v2-update-3/blob/main/perennial-v2/packages/perennial/contracts/types/RiskParameter.sol#L32-L33
https://github.com/sherlock-audit/2024-08-perennial-v2-update-3/blob/main/perennial-v2/packages/perennial/contracts/types/RiskParameter.sol#L139
https://github.com/sherlock-audit/2024-08-perennial-v2-update-3/blob/main/perennial-v2/packages/perennial/contracts/types/RiskParameter.sol#L155
https://github.com/sherlock-audit/2024-08-perennial-v2-update-3/blob/main/perennial-v2/packages/perennial/contracts/libs/VersionLib.sol#L250-L252

Tool Used

Manual Review

Recommendation

The protocol-wide maxFeeAbsolute value needs to be enforced across the markets. The liquidationFee should be validated as a percentage value.