Oracle Manager
Overview
OracleManager is Curvance's protocol-level price hub. Market contracts call it to price underlying assets, cToken shares, collateral positions, and debt positions through a single interface.
The manager does not maintain price feeds itself. It routes each supported asset to one or more approved oracle adaptors, normalizes price results, applies cToken exchange-rate conversion when the queried asset is a Curvance cToken, and returns an error code that downstream contracts use as a safety signal.
Prices are returned with 18-decimal precision. A price can be denominated in USD or in the chain's native gas token, depending on the inUSD argument.
Architecture
OracleManager is built around three registries:
Approved adaptors
isApprovedAdaptor(address)
Controls which adaptor contracts may be used by the manager.
Asset pricing config
getPricingAdaptors(address)
Lists the adaptor dependencies for an underlying asset.
Curvance cTokens
cTokens(address)
Maps a supported cToken to its underlying asset.
The constructor stores the protocol centralRegistry, and every configuration function checks centralRegistry.hasElevatedPermissions(msg.sender) before changing oracle state.
constructor(ICentralRegistry cr);Supported Asset Model
An asset is supported when it has at least one configured pricing adaptor. A Curvance cToken is supported when it has been registered in cTokens and its underlying asset has at least one configured adaptor.
The manager supports up to two adaptor dependencies per asset. Current developer-facing integrations should treat normal pricing as single-source, with adaptor-level freshness and guard checks handled inside the configured adaptor. The two-adaptor code path exists for assets that are configured with two adaptor dependencies, where the manager can compare returned prices against configured deviation bounds.
Adaptors return IOracleAdaptor.PricingResult:
price
The adaptor's price value.
inUSD
Whether price is USD-denominated.
hadError
Whether the adaptor encountered a pricing issue.
When an adaptor's denomination does not match the requested denomination, the manager converts through the configured price of the native gas token.
cToken Pricing
For registered cTokens, getPrice() first prices the underlying asset, then multiplies by the cToken exchange rate:
getPrice(cToken, ..., true)
exchangeRate()
Down
getPrice(cToken, ..., false)
exchangeRate()
Up
getPriceIsolatedPair() collateral side
exchangeRateUpdated()
Down
getPricesForMarket() collateral side
getSnapshotUpdated() then exchangeRate()
Down
The market helper functions use updated cToken reads because they support liquidity checks that need current account and exchange-rate data.
Price Query Flow
The caller requests a price through
getPrice(asset, inUSD, getLower)or through a market helper.The manager checks the optional
SEQUENCER_ORACLE()uptime feed from the central registry. If no feed is configured, the check returns true.If
assetis a registered cToken, the manager replaces it with its underlying asset for adaptor pricing.The manager loads the asset's adaptor list and reverts if no adaptor is configured.
With one adaptor, it calls
IOracleAdaptor.getPrice(asset, inUSD, getLower).With two adaptors, it calls both adaptors, handles adaptor errors, checks deviation bounds, and returns either the lower or higher price based on
getLower.If the original query was for a cToken, the manager converts the underlying price into a cToken share price.
If the resulting price is zero, the manager escalates the result to
BAD_SOURCE.
Use getLower = true when valuing collateral conservatively. Use getLower = false when valuing debt conservatively.
Error Code Handling
OracleManager uses numeric error codes from ConstantsLib:
0
NO_ERROR
The price was returned without an oracle-manager error signal.
1
CAUTION
One source failed in a two-adaptor configuration, or the two adaptor prices exceeded the configured caution bound.
2
BAD_SOURCE
No usable price was available, the returned price was zero, the optional uptime-feed check failed, or the two adaptor prices exceeded the configured bad-source bound.
getPrice() returns the error code to the caller. Market helper functions take an errorCodeBreakpoint and revert with OracleManager__ErrorCodeFlagged() when the observed code is greater than or equal to that breakpoint.
This makes the caller's tolerance explicit. For example, a caller that passes BAD_SOURCE accepts CAUTION but rejects BAD_SOURCE; a caller that passes CAUTION rejects both CAUTION and BAD_SOURCE.
Market Query Helpers
Market-facing helpers price cTokens and account positions in the form used by liquidity checks.
getPriceIsolatedPair()
Prices the collateral cToken's underlying with getLower = true, then converts to share value with exchangeRateUpdated().
Prices the debt cToken's underlying with getLower = false.
Updates the collateral cToken exchange rate.
getPricesForMarket()
For snapshots marked isCollateral, prices the underlying with getLower = true, then converts to share value.
For non-collateral snapshots, prices the underlying with getLower = false.
Calls getSnapshotUpdated(account) on each asset.
Both helpers require each provided cToken to be registered in cTokens. If a cToken is not registered, the helper reverts with OracleManager__NotSupported().
Permissions and Configuration
Only addresses with elevated permissions in the central registry can configure the manager. These functions add or remove approved adaptors, attach approved adaptors to assets, configure two-adaptor deviation bounds, and register cTokens.
Dual adaptor infrastructure exists on live deployments, but are unused in practice.
Deviation bounds are configured in basis points. The manager enforces:
MIN_DEVIATION_BOUND
20
Minimum allowed caution bound, equal to 0.20%.
MAX_DEVIATION_BOUND
350
Maximum allowed bad-source bound, equal to 3.50%.
MIN_CAUTION_TO_BAD_SOURCE_DELTA
20
Minimum gap between caution and bad-source bounds, equal to 0.20%.
When bounds are stored, the manager adds BPS internally. For example, an input of 200 is stored as 10200 so _checkBounds() can compare price ratios directly.
Configuration emits:
AdaptorDependencyAdded(address asset, address adaptor)
An adaptor dependency is added for an asset.
AdaptorDependencyRemoved(address asset, address adaptor)
An adaptor dependency is removed from an asset.
AssetDeviationBoundsSet(address asset, uint256 badSourceBoundUSD, uint256 cautionBoundUSD, uint256 badSourceBoundNative, uint256 cautionBoundNative)
Two-adaptor deviation bounds are set.
Integration Considerations
Read real contract addresses from the deployment registry for the chain you are integrating with. Use placeholder addresses in examples and application config templates.
Treat returned prices as 18-decimal values.
Check both
priceanderrorCodewhen callinggetPrice()directly. A non-reverting call can still returnCAUTIONorBAD_SOURCE.Use the same conservative direction as protocol liquidity checks: lower prices for collateral, higher prices for debt.
Use market helpers when reproducing market health checks, because they update snapshots and exchange rates where the protocol expects updated values.
Do not assume a cToken can be priced directly until
cTokens(cToken)returns a nonzero underlying and the underlying is supported.Do not hardcode adaptor behavior in integrations. The manager exposes adaptor addresses, but source-specific checks are implemented inside each adaptor.
User Interaction Functions
Price Reads
getPrice()
Description: Returns the price of an asset or registered cToken and an oracle-manager error code. This is a view function and does not update cToken exchange rates.
Function signature:
Inputs:
address
asset
Underlying asset or registered cToken to price.
bool
inUSD
true for USD-denominated price, false for native-token-denominated price.
bool
getLower
true to return the lower value in a two-adaptor setup, false to return the higher value.
Return data:
uint256
price
18-decimal price.
uint256
errorCode
0, 1, or 2.
Reverts with
OracleManager__NotSupported()if the asset has no configured adaptor.Returns
(0, BAD_SOURCE)if the optionalSEQUENCER_ORACLE()uptime-feed check fails.Converts registered cToken prices using
exchangeRate().
getPriceIsolatedPair()
Description: Returns conservative prices for a collateral cToken and debt cToken pair. This function is used by market logic that needs collateral value in share terms and debt value in underlying terms.
Function signature:
Inputs:
address
collateralToken
Registered cToken used as collateral.
address
debtToken
Registered cToken used for debt.
uint256
errorCodeBreakpoint
Error code threshold that causes a revert.
Return data:
uint256
collateralSharesPrice
Collateral cToken share price after applying exchangeRateUpdated().
uint256
debtUnderlyingPrice
Debt token underlying price.
Reverts with
OracleManager__ErrorCodeFlagged()when an observed error code is greater than or equal toerrorCodeBreakpoint.Reverts with
OracleManager__NotSupported()if either cToken is not registered.
getPricesForMarket()
Description: Returns updated account snapshots and conservative prices for a list of cTokens in a market.
Function signature:
Inputs:
address
account
Account to snapshot.
address[] calldata
assets
cToken addresses to price.
uint256
errorCodeBreakpoint
Error code threshold that causes a revert.
Return data:
AccountSnapshot[] memory
Updated cToken snapshots for account.
uint256[] memory
Prices aligned to assets.
uint256
Number of assets processed.
Calls getSnapshotUpdated(account) on each asset. Prices collateral snapshots in cToken share terms and debt snapshots in underlying terms.
Support and Status Reads
getPricingAdaptors()
Description: Returns the adaptor addresses currently configured for an asset.
Function signature:
Inputs:
address
asset
Underlying asset whose pricing adaptors should be returned.
Return data:
address[] memory
result
Current adaptor dependencies for asset.
Events: None.
This returns the dynamic adaptor array that the generated assetPricingConfig() getter omits.
isSupportedAsset()
Description: Returns whether an underlying asset or registered cToken is supported by the manager.
Function signature:
Inputs:
address
asset
Underlying asset or registered cToken to check.
Return data:
bool
true if the asset has at least one configured pricing adaptor. For cTokens, support is checked through the registered underlying asset.
Events: None.
isSequencerValid()
Description: Returns whether the optional central-registry uptime-feed check currently permits pricing.
Function signature:
Inputs: None.
Return data:
bool
true when no uptime feed is configured or the configured feed currently passes the manager's check.
Events: None.
getPrice() returns (0, BAD_SOURCE) when this check fails. Market helper functions revert with OracleManager__ErrorCodeFlagged() when this check fails.
isApprovedAdaptor()
Description: Returns whether an adaptor address is approved for manager use.
Function signature:
Inputs:
address
adaptor
Adaptor address to check.
Return data:
bool
true if the adaptor is approved for manager use.
Events: None.
cTokens()
Description: Returns the underlying asset for a registered Curvance cToken, or address(0) if the token is not registered.
Function signature:
Inputs:
address
cToken
Curvance cToken address to inspect.
Return data:
address
Registered underlying asset, or address(0) when cToken is not registered.
Events: None.
OracleManager uses this mapping to decide whether getPrice() should price the input as a cToken share.
assetPricingConfig()
Description: Returns the stored deviation-bound fields for an asset. The generated getter does not return the dynamic adaptor array; use getPricingAdaptors(asset) for adaptor addresses.
Function signature:
Inputs:
address
asset
Underlying asset whose stored deviation bounds should be read.
Return data:
uint16
Stored USD bad-source bound.
uint16
Stored USD caution bound.
uint16
Stored native-token bad-source bound.
uint16
Stored native-token caution bound.
Events: None.
The stored values include the BPS offset added by _setDeviationBounds(). Use getPricingAdaptors(asset) to read the configured adaptor addresses.
centralRegistry()
Description: Returns the central registry used for permission checks and optional uptime-oracle lookup.
Function signature:
Inputs: None.
Return data:
ICentralRegistry
Central registry used by the manager.
Events: None.
native()
Description: Returns the sentinel address used for the chain's native gas token.
Function signature:
Inputs: None.
Return data:
address
Sentinel address used to price the chain's native gas token.
Events: None.
The sentinel is 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE.
Constant Getters
Description: Return immutable oracle-manager configuration limits.
Function signatures:
Inputs: None.
Return data:
GRACE_PERIOD_TIME()
uint256
Uptime-feed grace period, in seconds.
MAX_DEVIATION_BOUND()
uint256
Maximum allowed deviation bound, in BPS.
MIN_DEVIATION_BOUND()
uint256
Minimum allowed deviation bound, in BPS.
MIN_CAUTION_TO_BAD_SOURCE_DELTA()
uint256
Minimum gap between caution and bad-source bounds, in BPS.
Last updated
Was this helpful?