Skip to content

Latest commit

 

History

History
66 lines (48 loc) · 3.42 KB

File metadata and controls

66 lines (48 loc) · 3.42 KB

Cheerful Taffy Dolphin

Medium

Minimum Oracle Timestamp Selection Leads to Price Staleness and Settlement Manipulation in Multi-Market Vault

Summary

In multi-market vault systems, oracle timestamp synchronization is critical for maintaining accurate pricing, risk assessment, and settlement operations. The current implementation in the Vault contract uses a minimum timestamp strategy across all registered markets to coordinate oracle data. This architecture reveals significant vulnerabilities when examining the interaction between timestamp selection and core vault operations.s

The core vulnerability stems from the vault's timestamp selection mechanism:

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

context.latestTimestamp = Math.min(context.latestTimestamp, oracleVersion.timestamp);

This design creates a cascading series of technical issues affecting critical vault operations. When processing oracle data, the vault forces synchronization to the oldest timestamp across all registered markets. Consider a scenario where Market A reports t=1000, Market B t=800, and Market C t=950 - the vault anchors all operations to t=800.

The most immediate impact manifests in the settlement logic:

while (context.global.current > context.global.latest &&
    context.latestTimestamp >= (nextCheckpoint = _checkpoints[context.global.latest + 1].read()).timestamp)

Here, the settlement pipeline stalls until all markets advance beyond the checkpoint timestamp. A malicious actor could exploit this by manipulating oracle update delays, effectively controlling the settlement cadence across all markets.

This timestamp anchoring propagates into the risk management system through the strategy calculation:

Target[] memory targets = _strategy(context, deposit, withdrawal, _ineligible(context, deposit, withdrawal));

The vault calculates positions and collateral requirements using potentially stale price data, leading to mispriced risk. During high volatility periods, the price differential between current and stale markets creates arbitrage vectors. For example, with Market A at $100 (current) and Market B at $80 (stale), the vault operates with a 25% price discrepancy.

The risk compounds in position management:

registration.market.update(
    address(this),
    shouldRebalance ? target.maker : Fixed6Lib.ZERO,
    shouldRebalance ? target.taker : Fixed6Lib.ZERO,
    target.collateral,
    address(0)
);

Position adjustments execute using outdated data, potentially leading to suboptimal collateral utilization and increased liquidation risk.

Fix

Implement a multi-layered timestamp validation:

// Staleness check
if (block.timestamp - oracleVersion.timestamp > MAX_STALENESS) revert StaleOracleError();

// Deviation boundary
uint256 maxDiff = timestamps[i] > timestamps[j] ? timestamps[i] - timestamps[j] : timestamps[j] - timestamps[i];
if (maxDiff > MAX_TIMESTAMP_DEVIATION) revert TimestampDeviationError();

// Median selection
function getMedianTimestamp(uint256[] memory timestamps) private pure returns (uint256) {
    // Sort and select median
    return sortedTimestamps[timestamps.length / 2];
}

This approach enforces freshness guarantees while maintaining cross-market synchronization boundaries, significantly reducing the attack surface for oracle manipulation and settlement gaming strategies.