# Oracle request timestamp and pending position timestamp mismatch can make most position updates invalid

Perennial oracle request timestamp (block.timestamp) mismatches pending position timestamp (rounded-up future), so committed prices never match positions, invalidating most updates and breaking accounting.

- Payout: Contest reward
- Severity: high
- Program: Perennial
- Credited: KingNFT
- Disclosed: 2023-07-17
- Write-up quality: 8/10
- Original: https://github.com/sherlock-audit/2023-07-perennial-judging/issues/42
- Library page: https://bugbountylibrary.com/r/sherlock%3A2023-07-perennial%3AH-1
- Tags: domain:web3 impact:funds-loss impact:integrity kind:contest platform:sherlock sev:high tech:evm tech:solidity technique:source-review vuln:accounting-error vuln:oracle-manipulation

**Target:** Perennial v2 Market / PythOracle settlement flow
**Root cause:** Pending position timestamp uses oracle.status() which ceilDivs to a future granularity timestamp, while oracle.request() stores block.timestamp; commitRequested() commits price at the request timestamp, so settlement at the position timestamp finds no valid price.
**Steps:**
1. Set PythOracle granularity=100.
2. User opens position at block.timestamp=101; pending position timestamp = ceilDiv(101,100)*100 = 200.
3. Same tx calls oracle.request() storing versionList=[101].
4. commitRequested() writes price at _prices[101].
5. Settlement calls oracle.at(200) which has no price -> invalid version, position not settled.
**How found:** Code reading of Oracle.status()/PythFactory.current() ceilDiv rounding vs PythOracle.request() storing block.timestamp, then tracing Market.sol setting pending position timestamp from context.currentTimestamp.
**Exploitation:** No attacker action needed; normal protocol flow causes most pending positions to be invalid, delaying settlement until a later trade and mispricing fills (e.g. user A filled at $110 instead of $100). Combined with global/local position desync, collateral accounting inflates ($210 vs $200 deposited), enabling bank run and last-user fund loss.
**Escalation:** Chained with global/local position desync during invalid oracles to inflate collateral and cause insolvency.
**Insight:** When a protocol derives a settlement timestamp from a rounded oracle status but records requests at block.timestamp, audit every place the two timestamps are compared or keyed into storage; granularity rounding creates a systematic future-skew that silently invalidates lookups.
