BaseOracleFactory
Inherits: Policy, PolicyEnabler, IOracleFactory, IVersioned, ReentrancyGuard
Title: BaseOracleFactory
Author: OlympusDAO
forge-lint: disable-start(mixed-case-function,mixed-case-variable)
Abstract base contract for oracle factories with common functionality
Uses ClonesWithImmutableArgs for gas-efficient oracle deployment
State Variables
_ROLES_KEYCODE
bytes5 internal constant _ROLES_KEYCODE = "ROLES"
priceCache
The pair cache policy
IPriceCache public priceCache
_tokensToOracle
Mapping from base token to quote token to maxAge to oracle address
mapping(address baseToken => mapping(address quoteToken => mapping(uint48 maxAge => address oracle))) internal
_tokensToOracle
_oraclePairVariantCounts
Mapping from an ordered base/quote pair to the number of deployed oracle variants
Updated when oracles are created. Factory-level re-enable uses this count to reject unknown pairs before checking whether any deployed variant is enabled.
mapping(bytes32 pairKey => uint256 variantCount) internal _oraclePairVariantCounts
_enabledOraclePairVariantCounts
Mapping from an ordered base/quote pair to the number of enabled oracle variants
Updated when oracles are created, enabled, or disabled. Factory-level re-enable recaching uses this count to skip pairs that currently have no enabled oracle.
mapping(bytes32 pairKey => uint256 variantCount) internal _enabledOraclePairVariantCounts
_oracles
Internal array of all deployed oracles
address[] internal _oracles
isOracle
Mapping to validate deployed oracles
mapping(address => bool) public isOracle
_oracleToBaseToken
Mapping from oracle to base token
mapping(address oracle => address baseToken) internal _oracleToBaseToken
_oracleToQuoteToken
Mapping from oracle to quote token
mapping(address oracle => address quoteToken) internal _oracleToQuoteToken
_oracleToMaxAge
Mapping from oracle to maxAge
mapping(address oracle => uint48 maxAge) internal _oracleToMaxAge
_isOracleEnabled
Mapping to track if an oracle is enabled
mapping(address => bool) internal _isOracleEnabled
isCreationEnabled
Whether new oracle creation is enabled
bool public isCreationEnabled
Functions
constructor
Constructs a new BaseOracleFactory
Reverts if priceCache_ is not a valid IPriceCache policy for this Kernel.
constructor(Kernel kernel_, address priceCache_) Policy(kernel_);
Parameters
| Name | Type | Description |
|---|---|---|
kernel_ | Kernel | The Kernel address |
priceCache_ | address | The price cache policy address |
configureDependencies
Define module dependencies for this policy.
Reverts if the configured ROLES module major version is unsupported.
function configureDependencies() external override returns (Keycode[] memory dependencies);
Returns
| Name | Type | Description |
|---|---|---|
dependencies | Keycode[] | - Keycode array of module dependencies. |
requestPermissions
Function called by kernel to set module function permissions.
Does not revert.
function requestPermissions() external pure override returns (Permissions[] memory requests);
Returns
| Name | Type | Description |
|---|---|---|
requests | Permissions[] | - Array of keycodes and function selectors for requested permissions. |
VERSION
Returns the version of the contract
Does not revert.
function VERSION() external pure virtual override returns (uint8 major, uint8 minor);
Returns
| Name | Type | Description |
|---|---|---|
major | uint8 | - Major version upgrade indicates breaking change to the interface. |
minor | uint8 | - Minor version change retains backward-compatible interface. |
onlyPolicyActive
Reverts if this policy is not active in the Kernel.
modifier onlyPolicyActive() ;
_onlyPolicyActive
function _onlyPolicyActive() internal view;
_onlyOracleManagerOrAdminRole
Checks if the caller has the oracle_manager or admin role
function _onlyOracleManagerOrAdminRole() internal view;
_onlyOracleManagerOrAdminOrEmergencyRole
Checks if the caller has the oracle_manager, admin, or emergency role
function _onlyOracleManagerOrAdminOrEmergencyRole() internal view;
onlyOracleManagerOrAdminRole
Modifier that reverts if the caller does not have the oracle_manager or admin role
modifier onlyOracleManagerOrAdminRole() ;
onlyOracleManagerOrAdminOrEmergencyRole
Modifier that reverts if the caller does not have the oracle_manager, admin, or emergency role
modifier onlyOracleManagerOrAdminOrEmergencyRole() ;
_getOracleImplementation
Returns the oracle implementation address for cloning
function _getOracleImplementation() internal view virtual returns (address);
Returns
| Name | Type | Description |
|---|---|---|
<none> | address | address The address of the oracle implementation contract to be cloned |
_encodeOracleData
Encodes oracle-specific data for cloning
This function should perform service-specific validation, calculate parameters, and encode the immutable args for the clone
function _encodeOracleData(address baseToken_, address quoteToken_, uint48 maxAge_, bytes calldata customParams_)
internal
view
virtual
returns (bytes memory);
Parameters
| Name | Type | Description |
|---|---|---|
baseToken_ | address | The base token address |
quoteToken_ | address | The quote token address |
maxAge_ | uint48 | The maximum age (in seconds) of cached prices used by the oracle |
customParams_ | bytes | Service-specific custom parameters (can be empty) |
Returns
| Name | Type | Description |
|---|---|---|
<none> | bytes | bytes The encoded bytes for cloning |
createOracle
Creates a new oracle for a base/quote token pair
Creates an enabled oracle only after the initial cache write succeeds.
Reverts if:
- The factory is disabled
- The caller is not admin or oracle manager
- Oracle creation is disabled
- An oracle for
(baseToken_, quoteToken_, maxAge_)already exists - Either token is the zero address or both tokens are the same
- Service-specific validation in
_encodeOracleDatafails - Initial cache population fails in the configured price cache policy
function createOracle(address baseToken_, address quoteToken_, uint48 maxAge_, bytes calldata customParams_)
external
override
onlyEnabled
onlyOracleManagerOrAdminRole
nonReentrant
returns (address oracle);
Parameters
| Name | Type | Description |
|---|---|---|
baseToken_ | address | The base token address |
quoteToken_ | address | The quote token address |
maxAge_ | uint48 | The maximum age (in seconds) of cached prices used by the oracle |
customParams_ | bytes | Service-specific custom parameters (can be empty) |
Returns
| Name | Type | Description |
|---|---|---|
oracle | address | The address of the created oracle |
getOracle
Gets the oracle address for a base/quote token pair
Does not revert.
function getOracle(address baseToken_, address quoteToken_, uint48 maxAge_)
external
view
override
returns (address oracle);
Parameters
| Name | Type | Description |
|---|---|---|
baseToken_ | address | The base token address |
quoteToken_ | address | The quote token address |
maxAge_ | uint48 | The maximum age (in seconds) of cached prices used by the oracle |
Returns
| Name | Type | Description |
|---|---|---|
oracle | address | The address of the oracle, or address(0) if not found |
getPriceCache
Gets the configured price cache policy
Does not revert.
function getPriceCache() external view override returns (address);
Returns
| Name | Type | Description |
|---|---|---|
<none> | address | policy The price cache policy address |
getOracles
Gets all deployed oracle addresses
Does not revert.
function getOracles() external view override returns (address[] memory);
Returns
| Name | Type | Description |
|---|---|---|
<none> | address[] | oracles Array of all oracle addresses |
enableCreation
Enables oracle creation
Reverts if:
- The factory is disabled
- The caller is not admin or oracle manager
- Creation is already enabled
function enableCreation() external override onlyEnabled onlyOracleManagerOrAdminRole nonReentrant;
disableCreation
Disables oracle creation
Reverts if:
- The factory is disabled
- The caller is not admin, oracle manager, or emergency
- Creation is already disabled
function disableCreation() external override onlyEnabled onlyOracleManagerOrAdminOrEmergencyRole nonReentrant;
setPriceCache
Sets the configured price cache policy
Reverts if:
- The factory is disabled
- The caller is not admin
policy_is zero, not IPriceCache-compatible, or bound to a different Kernel
function setPriceCache(address policy_) external override onlyEnabled onlyAdminRole nonReentrant;
Parameters
| Name | Type | Description |
|---|---|---|
policy_ | address | The price cache policy address |
enableOracle
Enables a specific oracle
Refreshes the oracle pair cache if stale before marking the oracle enabled.
Reverts if:
- The caller does not have the required role
- The contract is disabled
- The oracle is not created by the factory
- The oracle is already enabled
function enableOracle(address oracle_) external override onlyEnabled onlyOracleManagerOrAdminRole nonReentrant;
Parameters
| Name | Type | Description |
|---|---|---|
oracle_ | address | The oracle address to enable |
disableOracle
Disables a specific oracle
Decrements the enabled variant count for the oracle pair so factory-level re-enable skips the pair when no enabled variants remain.
Reverts if:
- The caller does not have the required role
- The contract is disabled
- The oracle is not created by the factory
- The oracle is already disabled
function disableOracle(address oracle_)
external
override
onlyEnabled
onlyOracleManagerOrAdminOrEmergencyRole
nonReentrant;
Parameters
| Name | Type | Description |
|---|---|---|
oracle_ | address | The oracle address to disable |
isOracleEnabled
Checks if a specific oracle is enabled
Reverts if:
- The policy is deactivated in Kernel Determines if a given oracle is enabled, using the following logic:
- Factory must be enabled
- Oracle must be created by the factory
- Oracle must be enabled
function isOracleEnabled(address oracle_) external view override onlyPolicyActive returns (bool);
Parameters
| Name | Type | Description |
|---|---|---|
oracle_ | address | The oracle address to check |
Returns
| Name | Type | Description |
|---|---|---|
<none> | bool | enabled True if the oracle is enabled, false otherwise |
getOracleContext
Checks if a factory-created oracle is enabled and returns the configured price cache
Reverts if:
- The policy is deactivated in Kernel
oracle_was not created by this factory
function getOracleContext(address oracle_)
external
view
override
onlyPolicyActive
returns (bool enabled, address policy);
Parameters
| Name | Type | Description |
|---|---|---|
oracle_ | address | The oracle address to check |
Returns
| Name | Type | Description |
|---|---|---|
enabled | bool | True if the oracle is enabled, false otherwise |
policy | address | The configured price cache policy address |
cachePrice
Caches the provided base/quote pair
Reverts if:
- The policy is deactivated in Kernel
- The factory is disabled
- The caller is not a factory-created oracle
- The caller oracle is disabled
(baseToken_, quoteToken_)does not match the caller oracle pair- Underlying cache write fails
function cachePrice(address baseToken_, address quoteToken_)
external
override
onlyPolicyActive
onlyEnabled
nonReentrant;
Parameters
| Name | Type | Description |
|---|---|---|
baseToken_ | address | The base token address |
quoteToken_ | address | The quote token address |
cachePriceIfNecessary
Caches the provided base/quote pair only when stale
Reverts if:
- The policy is deactivated in Kernel
- The factory is disabled
- The caller is not a factory-created oracle
- The caller oracle is disabled
(baseToken_, quoteToken_)does not match the caller oracle pair- Underlying cache evaluation/write fails
function cachePriceIfNecessary(address baseToken_, address quoteToken_)
external
override
onlyPolicyActive
onlyEnabled
nonReentrant;
Parameters
| Name | Type | Description |
|---|---|---|
baseToken_ | address | The base token address |
quoteToken_ | address | The quote token address |
_cacheOraclePrices
Caches prices for the configured oracle token pair
function _cacheOraclePrices(address oracle_) internal;
Parameters
| Name | Type | Description |
|---|---|---|
oracle_ | address | The oracle whose base/quote tokens should be cached |
_cachePriceIfNecessary
Conditionally caches prices for the token pair based on direct pair staleness
function _cachePriceIfNecessary(address oracle_, address baseToken_, address quoteToken_) internal;
_enable
Implementation-specific enable function
_enable optionally re-caches caller-specified direct pairs from enableData_
before the factory-level isEnabled flag flips back to true. enableData_ can
be empty for a no-op. Pairs with deployed variants are recached only when at
least one variant is currently enabled; disabled oracles validate and refresh
their own pair cache when individually re-enabled.
When enableData_ is non-empty, it must encode:
(address[] baseTokens, address[] quoteTokens).
Reverts if enableData_ is non-empty and:
enableData_cannot be decoded into(address[] baseTokens, address[] quoteTokens)- The decoded base and quote token arrays have different lengths
- A requested pair has no deployed oracle variant for that exact ordering
- The price cache rejects a requested pair that has an enabled oracle variant
function _enable(bytes calldata enableData_) internal virtual override;
Parameters
| Name | Type | Description |
|---|---|---|
enableData_ | bytes | Custom data that can be used by the implementation. The format of this data is left to the discretion of the implementation. |
_hasOracleVariant
Returns whether the factory has a deployed oracle for the provided pair.
function _hasOracleVariant(bytes32 pairKey_) internal view returns (bool);
_hasEnabledOracleVariant
Returns whether the factory has an enabled oracle for the provided pair.
function _hasEnabledOracleVariant(bytes32 pairKey_) internal view returns (bool);
_oraclePairKey
Returns the storage key for an ordered oracle base/quote pair.
function _oraclePairKey(address baseToken_, address quoteToken_) internal pure returns (bytes32);
_setPriceCache
function _setPriceCache(address policy_) internal;
_implementsIPriceCache
function _implementsIPriceCache(address policy_) internal view returns (bool);
_hasSameKernel
function _hasSameKernel(address policy_) internal view returns (bool);
_validateCachingCaller
function _validateCachingCaller(address caller_) internal view;
_validateCachingPair
function _validateCachingPair(address caller_, address baseToken_, address quoteToken_) internal view;
supportsInterface
Query if a contract implements an interface
Does not revert.
function supportsInterface(bytes4 interfaceId_) public view virtual override returns (bool);
Parameters
| Name | Type | Description |
|---|---|---|
interfaceId_ | bytes4 | The interface identifier, as specified in ERC-165 |
Returns
| Name | Type | Description |
|---|---|---|
<none> | bool | bool True if the contract implements interfaceId_ and false otherwise |