@@ -12,6 +12,7 @@ import {IncorrectPriceException} from "@gearbox-protocol/core-v3/contracts/inter
1212
1313import {IPyth} from "@pythnetwork/pyth-sdk-solidity/IPyth.sol " ;
1414import {PythStructs} from "@pythnetwork/pyth-sdk-solidity/PythStructs.sol " ;
15+ import {PERCENTAGE_FACTOR} from "@gearbox-protocol/core-v3/contracts/libraries/Constants.sol " ;
1516
1617/// @dev Max period that the payload can be backward in time relative to the block
1718uint256 constant MAX_DATA_TIMESTAMP_DELAY_SECONDS = 10 minutes ;
@@ -28,13 +29,16 @@ interface IPythExtended {
2829interface IPythPriceFeedExceptions {
2930 /// @notice Thrown when the timestamp sent with the payload for early stop does not match
3031 /// the payload's internal timestamp
31- error IncorrectExpectedPublishTimestamp ();
32+ error IncorrectExpectedPublishTimestampException ();
3233
3334 /// @notice Thrown when a retrieved price's publish time is too far ahead in the future
34- error PriceTimestampTooFarAhead ();
35+ error PriceTimestampTooFarAheadException ();
3536
3637 /// @notice Thrown when a retrieved price's publish time is too far behind the curent block timestamp
37- error PriceTimestampTooFarBehind ();
38+ error PriceTimestampTooFarBehindException ();
39+
40+ /// @notice Thrown when the the ratio between the confidence interval and price is higher than max allowed
41+ error ConfToPriceRatioTooHighException ();
3842}
3943
4044/// @title Pyth price feed
@@ -59,17 +63,31 @@ contract PythPriceFeed is IUpdatablePriceFeed, IPythPriceFeedExceptions {
5963 /// @dev Price feed description
6064 string public description;
6165
62- constructor (address _token , bytes32 _priceFeedId , address _pyth , string memory _descriptionTicker ) {
66+ /// @notice The max ratio of p.conf to p.price that would trigger the price feed to revert
67+ uint256 public immutable maxConfToPriceRatio;
68+
69+ constructor (
70+ address _token ,
71+ bytes32 _priceFeedId ,
72+ address _pyth ,
73+ string memory _descriptionTicker ,
74+ uint256 _maxConfToPriceRatio
75+ ) {
6376 token = _token;
6477 priceFeedId = _priceFeedId;
6578 pyth = _pyth;
6679 description = string (abi.encodePacked (_descriptionTicker, " Pyth price feed " ));
80+ maxConfToPriceRatio = _maxConfToPriceRatio;
6781 }
6882
6983 /// @notice Returns the USD price of the token with 8 decimals and the last update timestamp
7084 function latestRoundData () external view override returns (uint80 , int256 , uint256 , uint256 , uint80 ) {
7185 PythStructs.Price memory priceData = IPyth (pyth).getPriceUnsafe (priceFeedId);
7286
87+ if (uint256 (priceData.conf) * PERCENTAGE_FACTOR > uint256 (int256 (priceData.price)) * maxConfToPriceRatio) {
88+ revert ConfToPriceRatioTooHighException ();
89+ }
90+
7391 _validatePublishTimestamp (priceData.publishTime);
7492
7593 int256 price = _getDecimalAdjustedPrice (priceData);
@@ -98,7 +116,7 @@ contract PythPriceFeed is IUpdatablePriceFeed, IPythPriceFeedExceptions {
98116
99117 PythStructs.Price memory priceData = IPyth (pyth).getPriceUnsafe (priceFeedId);
100118
101- if (priceData.publishTime != expectedPublishTimestamp) revert IncorrectExpectedPublishTimestamp ();
119+ if (priceData.publishTime != expectedPublishTimestamp) revert IncorrectExpectedPublishTimestampException ();
102120 if (priceData.price == 0 ) revert IncorrectPriceException ();
103121 }
104122
@@ -121,10 +139,10 @@ contract PythPriceFeed is IUpdatablePriceFeed, IPythPriceFeedExceptions {
121139 function _validatePublishTimestamp (uint256 publishTimestamp ) internal view {
122140 if ((block .timestamp < publishTimestamp)) {
123141 if ((publishTimestamp - block .timestamp ) > MAX_DATA_TIMESTAMP_AHEAD_SECONDS) {
124- revert PriceTimestampTooFarAhead ();
142+ revert PriceTimestampTooFarAheadException ();
125143 }
126144 } else if ((block .timestamp - publishTimestamp) > MAX_DATA_TIMESTAMP_DELAY_SECONDS) {
127- revert PriceTimestampTooFarBehind ();
145+ revert PriceTimestampTooFarBehindException ();
128146 }
129147 }
130148
0 commit comments