Market can't get valid price while oracle's granularity > 1
Summary
The timestamp used in position is not equal to timestamp used for requesting oracle price. Orders would not be settled in the correct price while PythFactory.effectiveGranularity > 1.
Vulnerability Detail
First, let's see how PythFactory and PythOracle contracts calculate current() timestamp. Please pay attention on L76 of PythFactory.sol, the result is rounded up. For example, if the current block.timestamp = 101 and effectiveGranularity = 100, the calculated result would be 200. Market contract loads this timestamp as context.currentTimestamp (L312 of market.sol:_loadContext()) and uses in positions.
Next, we check request() function, please focus on L79 of PythOracle.sol, block.timestamp is pushed to versionList. And the oracle keepers submit price according to block.timestamp.
KingNFT
high
Market
can't get valid price while oracle'sgranularity > 1
Summary
The
timestamp
used in position is not equal totimestamp
used for requesting oracle price. Orders would not be settled in the correct price whilePythFactory.effectiveGranularity > 1
.Vulnerability Detail
First, let's see how
PythFactory
andPythOracle
contracts calculatecurrent()
timestamp. Please pay attention on L76 ofPythFactory.sol
, the result is rounded up. For example, if the currentblock.timestamp = 101
andeffectiveGranularity = 100
, the calculated result would be200
.Market
contract loads this timestamp ascontext.currentTimestamp
(L312 ofmarket.sol:_loadContext()
) and uses in positions.Next, we check
request()
function, please focus on L79 ofPythOracle.sol
,block.timestamp
is pushed toversionList
. And the oracle keepers submit price according toblock.timestamp
.While
PythFactory.effectiveGranularity > 1
, there is a high probability of failing to obtain the price. For example, let's sayThen
Obviously, the
Market
contract can't query valid price withtimestamp = 200
.Impact
The return of a invalid price will trigger the order executing on
context.global.latestPrice
, which may cause unintended loss to users.Code Snippet
https://github.com/sherlock-audit/2023-07-perennial/blob/main/perennial-v2/packages/perennial-oracle/contracts/pyth/PythOracle.sol#L79
Tool used
Manual Review
Recommendation
using
current()
instead ofblock.timestamp
Duplicate of #42