Skip to content

Commit 8eca158

Browse files
authored
Merge pull request #8 from Gearbox-protocol/pricefeed-optimisation
feat: pricefeed optimisation
2 parents cfa38c9 + 944b1c8 commit 8eca158

34 files changed

+2235
-2761
lines changed
Lines changed: 13 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,25 @@
11
// SPDX-License-Identifier: MIT
22
// Gearbox Protocol. Generalized leverage for DeFi protocols
33
// (c) Gearbox Foundation, 2023.
4-
pragma solidity ^0.8.10;
4+
pragma solidity ^0.8.17;
55

6-
import {AggregatorV3Interface} from "@chainlink/contracts/src/v0.8/interfaces/AggregatorV3Interface.sol";
7-
import {IPriceFeedType} from "./IPriceFeedType.sol";
6+
import {IPriceFeed} from "./IPriceFeed.sol";
87

98
interface ILPPriceFeedEvents {
10-
/// @dev Emits on updating the virtual price bounds
11-
event NewLimiterParams(uint256 lowerBound, uint256 upperBound);
9+
/// @notice Emitted when new LP token exchange rate bounds are set
10+
event SetBounds(uint256 lowerBound, uint256 upperBound);
1211
}
1312

14-
/// @title Interface for LP PriceFeeds with limiter
15-
interface ILPPriceFeed is AggregatorV3Interface, IPriceFeedType, ILPPriceFeedEvents {
16-
/// @dev Sets the lower and upper bounds for virtual price.
17-
/// @param _lowerBound The new lower bound
18-
/// @notice The upper bound is computed automatically
19-
function setLimiter(uint256 _lowerBound) external;
20-
21-
/// @dev Returns the lower bound
13+
/// @title LP price feed interface
14+
interface ILPPriceFeed is IPriceFeed, ILPPriceFeedEvents {
15+
function lpToken() external view returns (address);
2216
function lowerBound() external view returns (uint256);
23-
24-
/// @dev Returns the upper bound
2517
function upperBound() external view returns (uint256);
26-
27-
/// @dev Returns the pre-defined window between the lower and upper bounds
28-
/// @notice In bp format
2918
function delta() external view returns (uint256);
19+
20+
// ------------- //
21+
// CONFIGURATION //
22+
// ------------- //
23+
24+
function setLimiter(uint256 newLowerBound) external;
3025
}
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,13 @@
11
// SPDX-License-Identifier: MIT
22
// Gearbox Protocol. Generalized leverage for DeFi protocols
33
// (c) Gearbox Foundation, 2023.
4-
pragma solidity ^0.8.0;
4+
pragma solidity ^0.8.17;
55

66
import {PriceFeedType} from "@gearbox-protocol/sdk/contracts/PriceFeedType.sol";
7+
import {AggregatorV3Interface} from "@chainlink/contracts/src/v0.8/interfaces/AggregatorV3Interface.sol";
78

8-
interface IPriceFeedType {
9-
/// @dev Returns the price feed type
9+
/// @title Price feed interface
10+
interface IPriceFeed is AggregatorV3Interface {
1011
function priceFeedType() external view returns (PriceFeedType);
11-
12-
/// @dev Returns whether sanity checks on price feed result should be skipped
1312
function skipPriceCheck() external view returns (bool);
1413
}

contracts/interfaces/IPriceOracleV2.sol

Lines changed: 0 additions & 77 deletions
This file was deleted.
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
// SPDX-License-Identifier: BUSL-1.1
2+
// Gearbox Protocol. Generalized leverage for DeFi protocols
3+
// (c) Gearbox Foundation, 2023.
4+
pragma solidity ^0.8.17;
5+
6+
import {IPriceFeed} from "../interfaces/IPriceFeed.sol";
7+
import {AggregatorV3Interface} from "@chainlink/contracts/src/v0.8/interfaces/AggregatorV3Interface.sol";
8+
import {PriceFeedValidationTrait} from "@gearbox-protocol/core-v3/contracts/traits/PriceFeedValidationTrait.sol";
9+
import {NotImplementedException} from "@gearbox-protocol/core-v3/contracts/interfaces/IExceptions.sol";
10+
11+
struct PriceFeedParams {
12+
address priceFeed;
13+
uint32 stalenessPeriod;
14+
}
15+
16+
/// @title Abstract price feed
17+
/// @notice Base contract for all price feeds
18+
abstract contract AbstractPriceFeed is IPriceFeed, PriceFeedValidationTrait {
19+
/// @notice Answer precision (always 8 decimals for USD price feeds)
20+
uint8 public constant override decimals = 8;
21+
22+
/// @notice Indicates that price oracle can skip checks for this price feed's answers
23+
bool public constant override skipPriceCheck = true;
24+
25+
/// @dev Returns answer from a price feed with optional sanity and staleness checks
26+
/// @dev When computing LP token price, this MUST be used to get prices of underlying tokens
27+
function _getValidatedPrice(address priceFeed, uint32 stalenessPeriod, bool skipCheck)
28+
internal
29+
view
30+
returns (int256 answer, uint256 updatedAt)
31+
{
32+
(, answer,, updatedAt,) = AggregatorV3Interface(priceFeed).latestRoundData();
33+
if (!skipCheck) _checkAnswer(answer, updatedAt, stalenessPeriod);
34+
}
35+
36+
/// @dev Not implemented since Gearbox price feeds don't provide historical data
37+
function getRoundData(uint80) external pure override returns (uint80, int256, uint256, uint256, uint80) {
38+
revert NotImplementedException();
39+
}
40+
}

contracts/oracles/BoundedPriceFeed.sol

Lines changed: 35 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -1,98 +1,71 @@
11
// SPDX-License-Identifier: BUSL-1.1
22
// Gearbox Protocol. Generalized leverage for DeFi protocols
33
// (c) Gearbox Foundation, 2023.
4-
pragma solidity ^0.8.10;
4+
pragma solidity ^0.8.17;
55

6+
import {AbstractPriceFeed} from "./AbstractPriceFeed.sol";
7+
import {PriceFeedType} from "../interfaces/IPriceFeed.sol";
68
import {AggregatorV3Interface} from "@chainlink/contracts/src/v0.8/interfaces/AggregatorV3Interface.sol";
79
import {AggregatorV2V3Interface} from "@chainlink/contracts/src/v0.8/interfaces/AggregatorV2V3Interface.sol";
8-
import {PERCENTAGE_FACTOR} from "@gearbox-protocol/core-v2/contracts/libraries/Constants.sol";
9-
import {PriceFeedType, IPriceFeedType} from "../interfaces/IPriceFeedType.sol";
10-
11-
// EXCEPTIONS
12-
import {NotImplementedException} from "@gearbox-protocol/core-v3/contracts/interfaces/IExceptions.sol";
1310

1411
interface ChainlinkReadableAggregator {
1512
function aggregator() external view returns (address);
16-
1713
function phaseAggregators(uint16 idx) external view returns (AggregatorV2V3Interface);
18-
1914
function phaseId() external view returns (uint16);
2015
}
2116

22-
/// @title Price feed with an upper bound on price
23-
/// @notice Used to limit prices on assets that should not rise above
24-
/// a certain level, such as stablecoins and other pegged assets
25-
contract BoundedPriceFeed is ChainlinkReadableAggregator, AggregatorV3Interface, IPriceFeedType {
26-
/// @dev Chainlink price feed for the Vault's underlying
27-
AggregatorV3Interface public immutable priceFeed;
28-
29-
/// @dev The upper bound on Chainlink price for the asset
30-
int256 public immutable upperBound;
31-
32-
/// @dev Decimals of the returned result.
33-
uint8 public immutable override decimals;
34-
35-
/// @dev Price feed description
36-
string public override description;
37-
38-
uint256 public constant override version = 1;
39-
17+
/// @title Bounded price feed
18+
/// @notice Can be used to provide upper-bounded answers for assets that are
19+
/// expected to have the price in a certain range, e.g. stablecoins
20+
contract BoundedPriceFeed is AbstractPriceFeed, ChainlinkReadableAggregator {
21+
/// @notice Contract version
22+
uint256 public constant override version = 3_00;
4023
PriceFeedType public constant override priceFeedType = PriceFeedType.BOUNDED_ORACLE;
4124

42-
bool public constant override skipPriceCheck = false;
25+
/// @notice Underlying price feed
26+
address public immutable priceFeed;
27+
uint32 public immutable stalenessPeriod;
28+
bool public immutable skipCheck;
4329

44-
/// @dev Constructor
45-
/// @param _priceFeed Chainlink price feed to receive results from
46-
/// @param _upperBound Initial upper bound for the Chainlink price
47-
constructor(address _priceFeed, int256 _upperBound) {
48-
priceFeed = AggregatorV3Interface(_priceFeed);
49-
description = string(abi.encodePacked(priceFeed.description(), " Bounded"));
50-
decimals = priceFeed.decimals();
51-
upperBound = _upperBound;
52-
}
30+
/// @notice Upper bound for underlying price feed answers
31+
int256 public immutable upperBound;
5332

54-
/// @dev Implemented for compatibility, but reverts since Gearbox's price feeds
55-
/// do not store historical data.
56-
function getRoundData(uint80)
57-
external
58-
pure
59-
virtual
60-
override
61-
returns (
62-
uint80, // roundId,
63-
int256, // answer,
64-
uint256, // startedAt,
65-
uint256, // updatedAt,
66-
uint80 // answeredInRound
67-
)
68-
{
69-
revert NotImplementedException(); // F:[LPF-2]
33+
/// @notice Constructor
34+
/// @param _priceFeed Underlying price feed
35+
/// @param _stalenessPeriod Underlying price feed staleness period, must be non-zero unless it performs own checks
36+
/// @param _upperBound Upper bound for underlying price feed answers
37+
constructor(address _priceFeed, uint32 _stalenessPeriod, int256 _upperBound) {
38+
priceFeed = _priceFeed;
39+
stalenessPeriod = _stalenessPeriod;
40+
skipCheck = _validatePriceFeed(priceFeed, stalenessPeriod);
41+
upperBound = _upperBound;
7042
}
7143

72-
/// @dev Returns the value if it is below the upper bound, otherwise returns the upper bound
73-
/// @param value Value to be checked and bounded
74-
function _upperBoundValue(int256 value) internal view returns (int256) {
75-
return (value > upperBound) ? upperBound : value;
44+
/// @notice Price feed description
45+
function description() external view override returns (string memory) {
46+
return string(abi.encodePacked("Bounded ", AggregatorV3Interface(priceFeed).description(), " price feed"));
7647
}
7748

78-
/// @dev Returns the upper-bounded USD price of the token
49+
/// @notice Returns the upper-bounded USD price of the token
7950
function latestRoundData()
8051
external
8152
view
8253
override
83-
returns (uint80 roundId, int256 answer, uint256 startedAt, uint256 updatedAt, uint80 answeredInRound)
54+
returns (uint80, int256 answer, uint256, uint256 updatedAt, uint80)
8455
{
85-
(roundId, answer, startedAt, updatedAt, answeredInRound) = priceFeed.latestRoundData(); // F:[OYPF-4]
56+
(answer, updatedAt) = _getValidatedPrice(priceFeed, stalenessPeriod, skipCheck);
57+
return (0, _upperBoundValue(answer), 0, updatedAt, 0);
58+
}
8659

87-
answer = _upperBoundValue(answer);
60+
/// @dev Upper-bounds given value
61+
function _upperBoundValue(int256 value) internal view returns (int256) {
62+
return (value > upperBound) ? upperBound : value;
8863
}
8964

90-
/// @dev Returns the current phase's aggregator address
9165
function aggregator() external view returns (address) {
9266
return ChainlinkReadableAggregator(address(priceFeed)).aggregator();
9367
}
9468

95-
/// @dev Returns a phase aggregator by index
9669
function phaseAggregators(uint16 idx) external view returns (AggregatorV2V3Interface) {
9770
return ChainlinkReadableAggregator(address(priceFeed)).phaseAggregators(idx);
9871
}

0 commit comments

Comments
 (0)