Oracles
TLDR
Napier Oracle: A time-weighted average logarithmic implied rate (lnImpliedRate) oracle for fixed-rate markets. Adapted from Uniswap V3’s oracle architecture, it enables reliable yield and price discovery while maintaining strong resistance to manipulation.
PT Oracle: Based on the time-weighted geometric mean (TWAP) of the implied APY internally tracked by the AMM, it returns the PT price (in terms of the underlying asset) for a specified observation window.
LP Oracle: Returns the estimated TWAP exchange rate between the LP token and the underlying asset. It simulates a hypothetical zero-fee swap to align the PT spot price with the PT Oracle’s price, constructs a virtual pool state, and evaluates the LP price from that adjusted state.
Napier Oracle
The Napier oracle provides time-weighted average logarithmic implied rate (lnImpliedRate) data for fixed-rate markets. Adapted from Uniswap V3's oracle design, it enables reliable yield and price discovery while maintaining resistance to manipulation.
Mechanics
The oracle works by storing cumulative implied rate data in a circular array. This data is automatically updated with every market interaction, allowing anyone to calculate time-weighted average rates over arbitrary periods.
Observations
Every fixed-rate pool tracks oracle observations in an array:
Each pool is initialized with an oracle array length of 1
Anyone can pay the gas costs to increase the oracle array up to a maximum of 65,535 slots
The oracle array is treated as a circular buffer - old observations are overwritten once the array is full
The observation recorded includes three values:
blockTimestamp
uint32
The block timestamp of the observation
lnImpliedRateCumulative
uint216
The logarithmic implied rate accumulator up to this point
initialized
bool
Whether or not the observation has been initialized
Accumulators
The lnImpliedRate accumulator stores the sum of the logarithmic implied rate at the beginning of each block, multiplied by the time elapsed since the previous block. The value can be stored as a uint216
, as it is only updated once per block.
lnImpliedRateCumulative[i] = lnImpliedRateCumulative[i-1] + lnImpliedRate * ΔT
Where lnImpliedRate
is the current logarithmic implied rate and ΔT
is the time elapsed since the last observation.
Deriving Yield Values
The accumulator value can be used to derive the time-weighted average implied rate over any period. The implied rate is derived from the logarithmic value using the formula:
impliedRate = e^(lnImpliedRate)
The geometric mean rate over a period can be calculated as:
impliedRate = e^((lnImpliedRateCumulative[t2] - lnImpliedRateCumulative[t1]) / (t2 - t1))
Technical Details
Oracle Initialization and Data Availability
Important: The oracle must be initialized before use and requires time to accumulate meaningful data:
Initialization: Each pool starts with a single observation at deployment time with
lnImpliedRateCumulative = 0
Waiting Period: For meaningful averages, wait for your desired time window to elapse (e.g., wait 1 hour for accurate 1-hour averages)
Observations Array
The oracle array is structured to minimize gas costs:
The array acts as a circular buffer, with the oldest observation overwritten by the newest
Observations are written at most once per block
Linear interpolation is used when exact timestamp matches aren't available
Increasing Cardinality
The grow
function allows anyone to increase the maximum number of observations:
function grow(Observation[65535] storage self, uint16 current, uint16 next) internal returns (uint16)
This is useful for applications requiring longer historical windows or more granular data.
Consulting the Oracle
The observe
function retrieves historical implied rate data:
function observe(
Observation[65535] storage self,
uint32 time,
uint32[] memory secondsAgos,
uint96 lnImpliedRate,
uint16 index,
uint16 cardinality
) internal view returns (uint216[] memory lnImpliedRateCumulative)
The function accepts an array of secondsAgo
values and returns the corresponding cumulative values. If no observation exists at the exact timestamp, the oracle interpolates between surrounding observations.
Last updated
Was this helpful?