Oracle Hub

TL;DR: XCCY uses two oracle systems — OracleHub for asset prices (USD valuation) and AprOracle for yield rates (VY tracking). These power margin calculations and settlements.

Overview

OracleHub is responsible for pricing collateral in USD with safety guards (staleness / validity checks). AprOracle is responsible for tracking variable yield over time and returning an accumulated rate factor over a term.

spinner

OracleHub (Price Oracle)

Purpose

Provides USD prices for all supported assets. Used for:

  • Collateral valuation

  • Margin calculations

  • Cross-asset comparisons

Interface

interface IOracleHub {
    function getPriceUsdWad(address asset) 
        external view 
        returns (
            uint256 priceWad,    // Price in WAD (18 decimals)
            uint256 timestamp,   // Last update time
            bool valid           // Is price reliable
        );
}

Supported Sources

Source
Use Case
Update Frequency

Chainlink

Major assets (ETH, BTC, stablecoins)

Heartbeat + deviation

Pendle TWAP

Yield-bearing tokens

Continuous

Custom

Protocol-specific assets

Configurable

Price Flow Example

A user deposits 10 ETH as margin. CollateralEngine values the collateral in USD by querying OracleHub:

  • OracleHub.getPriceUsdWad(WETH)

Example response fields:

  • priceWad = 2,000e18 (2,000 USD with 18 decimals)

  • updatedAt = 1,704,067,200 (unix timestamp)

  • isValid = true (passed staleness and source guards)

Collateral value uses a discount factor (haircut):

Collateral value (USD) = balance * priceUsd * discountFactor

Example with discountFactor(ETH) = 0.90:

10 * 2,000 * 0.90 = 18,000 USD

Source Architecture

AprOracle (Yield Oracle)

Purpose

Tracks Variable Yield rates for yield-bearing tokens. Used for:

  • Settlement calculations

  • Margin requirement estimation

  • VY exposure tracking

Interface

Rate Calculation

AprOracle returns an accumulated variable-yield factor over a time range:

Variable factor = getRateFromTo(termStart, termEnd)

Interpretation:

  • This is accumulated yield over the period (a factor), not a spot APY.

Example approximation:

  • Term: 90 days

  • Average VY: 5% APY

variableFactor ≈ (90 / 365) * 0.05 = 0.01233

APR Adapters

Each yield source has a dedicated adapter:

Adapter
Token Type
Source

AaveAprAdapter

aTokens (aUSDC, aETH)

Aave lending rates

Erc4626AprAdapter

ERC-4626 vaults

Share price growth

WstEthAprAdapter

wstETH

Lido staking rates

WeEthAprAdapter

weETH

EtherFi rates

PendleAprAdapter

PT/YT tokens

Pendle yield

Adapter Interface

Rate Accumulation

How VY is Tracked

AprOracle stores periodic rate snapshots and integrates them over time:

  1. The oracle records VY snapshots at different timestamps.

  2. getRateFromTo(t0, t1) computes the accumulated factor across the interval based on those snapshots.

Example snapshot series:

  • t = 0d: 5.2%

  • t = 1d: 5.4%

  • t = 2d: 4.8%

  • t = 3d: 5.1%

  • t = 4d: 5.3%

Calling getRateFromTo(t = 0d, t = 4d) returns the accumulated rate factor over 4 days derived from these snapshots.

Oracle Buffer

Rates are stored in a circular buffer for gas efficiency:

Integration with CollateralEngine

Settlement calculation

At maturity, CollateralEngine computes final cashflow using:

  1. Variable factor from AprOracle

  • variableFactor = AprOracle.getRateFromTo(termStart, termEnd)

  1. Fixed factor from time

  • fixedFactor = (termEnd - termStart) / SECONDS_IN_YEAR

  1. Cashflow

  • cashflow = fixedTokens * fixedFactor + variableTokens * variableFactor

Then cashflow is applied to margin:

  • If cashflow > 0: credit margin

  • If cashflow < 0: debit margin (or trigger forced handling if insufficient)

Margin requirement (worst case)

For margin checks, the Risk Engine combines worst-case VY bounds with USD pricing:

  1. Worst-case VY factors (admin-configured, per pool)

  • worstCaseVariableFactorPositive: used when receiving VY (worst case is VY drops)

  • worstCaseVariableFactorNegative: used when paying VY (worst case is VY rises)

  1. Compute maximum potential loss in underlying units based on position direction and the selected worst-case factor.

  2. Convert loss to USD using OracleHub pricing

  • usdPrice = OracleHub.getPriceUsdWad(underlyingAsset)

  1. Final requirement

  • marginRequiredUsd = worstCaseLoss * usdPrice

Adding New Sources

New Price Source

New APR Adapter

Error Handling

Price Validation

Rate Validation

Security Considerations

Oracle Manipulation Protection

Protection
Description

Multiple sources

Cross-reference prices where possible

Staleness checks

Reject old data

Deviation bounds

Reject extreme price movements

TWAP

Time-weighted averages resist flash manipulation

Admin Controls

Current Deployments (Polygon)

Contract
Address

OracleHub

0x7a5084DEc5Fd89Ee1079005cE9cEa094c2A66E8E

AprOracle

0xA192144F89edC9fBB3D225856FaF284d9287EDb8

Key Takeaways

  1. Two oracle types — Prices (OracleHub) and yields (AprOracle)

  2. Multiple sources — Chainlink, Pendle, protocol-specific

  3. Adapter pattern — Easy to add new yield sources

  4. Validation built-in — Staleness and validity checks

  5. Gas optimized — Circular buffers for rate storage

Next Steps

  • Margin System — How oracles power margin

  • Smart Contracts — Contract references

  • Deployed Contracts — All addresses

Last updated