ResilientOracle
The Resilient Oracle is the main contract that the protocol uses to fetch prices of assets.
DeFi protocols are vulnerable to price oracle failures including oracle manipulation and incorrectly reported prices. If only one oracle is used, this creates a single point of failure and opens a vector for attacking the protocol.
The Resilient Oracle uses multiple sources and fallback mechanisms to provide accurate prices and protect the protocol from oracle attacks. Currently it includes integrations with Chainlink, Pyth, Binance Oracle and TWAP (Time-Weighted Average Price) oracles. TWAP uses PancakeSwap as the on-chain price source.
For every market (vToken) we configure the main, pivot and fallback oracles. The oracles are configured per vToken's underlying asset address. The main oracle oracle is the most trustworthy price source, the pivot oracle is used as a loose sanity checker and the fallback oracle is used as a backup price source.
To validate prices returned from two oracles, we use an upper and lower bound ratio that is set for every market. The upper bound ratio represents the deviation between reported price (the price that’s being validated) and the anchor price (the price we are validating against) above which the reported price will be invalidated. The lower bound ratio presents the deviation between reported price and anchor price below which the reported price will be invalidated. So for oracle price to be considered valid the below statement should be true:
anchorRatio = anchorPrice/reporterPrice
isValid = anchorRatio <= upperBoundAnchorRatio && anchorRatio >= lowerBoundAnchorRatio
In most cases, Chainlink is used as the main oracle, TWAP or Pyth oracles are used as the pivot oracle depending on which supports the given market and Binance oracle is used as the fallback oracle. For some markets we may use Pyth or TWAP as the main oracle if the token price is not supported by Chainlink or Binance oracles.
For a fetched price to be valid it must be positive and not stagnant. If the price is invalid then we consider the oracle to be stagnant and treat it like it's disabled.
enum OracleRole {
MAIN,
PIVOT,
FALLBACK
}
struct TokenConfig {
address asset;
address[3] oracles;
bool[3] enableFlagsForOracles;
}
vBNB address
address vBnb
VAI address
address vai
Set this as asset address for BNB. This is the underlying for vBNB
address BNB_ADDR
Bound validator contract address
contract BoundValidatorInterface boundValidator
Constructor for the implementation contract. Sets immutable variables.
constructor(address vBnbAddress, address vaiAddress, contract BoundValidatorInterface _boundValidator) public
Parameters
Name | Type | Description |
---|---|---|
vBnbAddress | address | The address of the vBNB |
vaiAddress | address | The address of the VAI |
_boundValidator | contract BoundValidatorInterface | Address of the bound validator contract |
Initializes the contract admin and sets the BoundValidator contract address
function initialize(address accessControlManager_) external
Parameters
Name | Type | Description |
---|---|---|
accessControlManager_ | address | Address of the access control manager contract |
Pauses oracle
function pause() external
⛔️ Access Requirements
- Only Governance
Unpauses oracle
function unpause() external
⛔️ Access Requirements
- Only Governance
Batch sets token configs
function setTokenConfigs(struct ResilientOracle.TokenConfig[] tokenConfigs_) external
Parameters
Name | Type | Description |
---|---|---|
tokenConfigs_ | struct ResilientOracle.TokenConfig[] | Token config array |
⛔️ Access Requirements
- Only Governance
❌ Errors
- Throws a length error if the length of the token configs array is 0
Sets oracle for a given asset and role.
function setOracle(address asset, address oracle, enum ResilientOracle.OracleRole role) external
Parameters
Name | Type | Description |
---|---|---|
asset | address | Asset address |
oracle | address | Oracle address |
role | enum ResilientOracle.OracleRole | Oracle role |
📅 Events
- Emits OracleSet event with asset address, oracle address and role of the oracle for the asset
⛔️ Access Requirements
- Only Governance
❌ Errors
- Null address error if main-role oracle address is null
- NotNullAddress error is thrown if asset address is null
- TokenConfigExistance error is thrown if token config is not set
Enables/ disables oracle for the input asset. Token config for the input asset must exist
function enableOracle(address asset, enum ResilientOracle.OracleRole role, bool enable) external
Parameters
Name | Type | Description |
---|---|---|
asset | address | Asset address |
role | enum ResilientOracle.OracleRole | Oracle role |
enable | bool | Enabled boolean of the oracle |
⛔️ Access Requirements
- Only Governance
❌ Errors
- NotNullAddress error is thrown if asset address is null
- TokenConfigExistance error is thrown if token config is not set
Updates the TWAP pivot oracle price.
function updatePrice(address vToken) external
Parameters
Name | Type | Description |
---|---|---|
vToken | address | vToken address |
Updates the pivot oracle price. Currently using TWAP
function updateAssetPrice(address asset) external
Parameters
Name | Type | Description |
---|---|---|
asset | address | asset address |
Gets price of the underlying asset for a given vToken. Validation flow:
- Check if the oracle is paused globally
- Validate price from main oracle against pivot oracle
- Validate price from fallback oracle against pivot oracle if the first validation failed
- Validate price from main oracle against fallback oracle if the second validation failed In the case that the pivot oracle is not available but main price is available and validation is successful, main oracle price is returned.
function getUnderlyingPrice(address vToken) external view returns (uint256)
Parameters
Name | Type | Description |
---|---|---|
vToken | address | vToken address |
Return Values
Name | Type | Description |
---|---|---|
[0] | uint256 | price USD price in scaled decimal places. |
❌ Errors
- Paused error is thrown when resilent oracle is paused
- Invalid resilient oracle price error is thrown if fetched prices from oracle is invalid
Gets price of the asset
function getPrice(address asset) external view returns (uint256)
Parameters
Name | Type | Description |
---|---|---|
asset | address | asset address |
Return Values
Name | Type | Description |
---|---|---|
[0] | uint256 | price USD price in scaled decimal places. |
❌ Errors
- Paused error is thrown when resilent oracle is paused
- Invalid resilient oracle price error is thrown if fetched prices from oracle is invalid
Sets/resets single token configs.
function setTokenConfig(struct ResilientOracle.TokenConfig tokenConfig) public
Parameters
Name | Type | Description |
---|---|---|
tokenConfig | struct ResilientOracle.TokenConfig | Token config struct |
📅 Events
- Emits TokenConfigAdded event when the asset config is set successfully by the authorized account
⛔️ Access Requirements
- Only Governance
❌ Errors
- NotNullAddress is thrown if asset address is null
- NotNullAddress is thrown if main-role oracle address for asset is null
Gets oracle and enabled status by asset address
function getOracle(address asset, enum ResilientOracle.OracleRole role) public view returns (address oracle, bool enabled)
Parameters
Name | Type | Description |
---|---|---|
asset | address | asset address |
role | enum ResilientOracle.OracleRole | Oracle role |
Return Values
Name | Type | Description |
---|---|---|
oracle | address | Oracle address based on role |
enabled | bool | Enabled flag of the oracle based on token config |
Last modified 2mo ago