Skip to main content

PT Oracle

The Principal Token (PT) is an ERC20 token bearing the value of a certain amount of asset which can be redeemed at maturity. For example, 100 PT-stETH-25DEC2025 can be redeemed for 100 stETH on the 25th of December 2025.

In Pendle system, PTPT can be freely traded from and to SYSY (EIP-5115 token) ultilizing our AMM. With the built-in TWAP oracle library, the geometric mean price of PTPT in terms of asset (please refer to the definition of asset here) can be derived from our PendleMarket contracts fully on-chain.

About Our Oracles

Pendle's oracle implementation is inspired from the idea of UniswapV3 Oracle (see here) with a slight difference in how we define the cumulative rate. In short, our oracle stores the cumulative logarithm of implied APY (the interest rate implied by PT/assetPT/asset pricing). From the cumulative logarithm of Implied APY, we can calculate the geometric mean of Implied APY, which will used to derive the mean PTPT price.

In a way, the Pendle AMM contract has a built-in oracle of interest rate, which can used to derive PTPT prices.

EIP5115 Asset

Although the AMMs hold their positions and execute trades in PTPT and SYSY, their underlying logics assume all their SYSY balances are converted to assets. As a result, the exchange rate returned by our oracles are between PTPT and AssetAsset, which should make pricing PTPT more straightforward.

Let's take PT-stETH-25DEC2025 as an example. We have:

  1. AssetAsset in this case is stETH
  2. oraclePtToAssetRate=0.9oraclePtToAssetRate = 0.9
  3. stETHPrice=$2000stETHPrice = \$2000

Thus, the price of PT-stETH-25DEC2025 should be 0.9×2000=$18000.9 \times 2000 = \$1800

Formulas

Our oracle storage is in the following form:

struct Observation {
// the block timestamp of the observation
uint32 blockTimestamp;
// the tick logarithm accumulator, i.e., ln(impliedRate) * time elapsed since the pool was first initialized
uint216 lnImpliedRateCumulative;
// whether or not the observation is initialized
bool initialized;
}

The geometric mean price of PTPT for the time interval of [t0,t1][t_0, t_1] is:

lnImpliedRate=lnImpliedRateCumulative1lnImpliedRateCumulative0t1t0lnImpliedRate = \frac{lnImpliedRateCumulative_1 - lnImpliedRateCumulative_0}{t_1 - t_0}
impliedRate=elnImpliedRateimpliedRate = e^{lnImpliedRate}
assetToPtPrice=impliedRatetimeToMaturityoneYearassetToPtPrice = impliedRate^{\frac{timeToMaturity}{oneYear}}
ptToAssetPrice=1/assetToPtPriceptToAssetPrice = 1 / assetToPtPrice

Oracle Preparation

Since our AMMs use TWAP oracles, firstly, we must define a durationduration for the pricing interval. Same as UniswapV3 oracles, each PTPT oracle has its own limitation on how far in the past the pricing data can be accessed. To check the validity of a duration for each a market, please query the following function from our PendlePtOracle contract:

function getOracleState(
address market,
uint32 duration
)
external
view
returns (
bool increaseCardinalityRequired,
uint16 cardinalityRequired,
bool oldestObservationSatisfied
);

If increaseCardinalityRequired is returned True, it means the oracle's size of tracked observations must be expanded to cardinalityRequired before any price usage.

If oldestObservationSatisfied is returned False, it means the oldest observations was recorded less than durationduration seconds ago. In this case, the oracle needs more time to fill its observations to satisfy this specific durationduration.

info

To sum up, please make sure you have increaseCardinalityRequired = False and oldestObservationSatisfied = True before using our oracle on production.

Fetch price

First of all, the rate returned from Pendle PTPT oracles is the exchange rate between PTPT and AssetAsset. This implies your oracle implementation should take care of the conversion between AssetAsset and the quote asset of your oracle system.

There are two ways to derive the exchange rate between PTPT and AssetAsset from our oracle:

  1. Calling getPtToAssetRate(address market, uint32 duration) function from our PendlePtOracle contract
  2. Using our contract library in your own contract

Compared to the first method, using a library reduce one external call from your contract to PendlePtOracle, making the implementation more gas saving.

note

We recommend using the contract library to get the PT price to save on gas, especially on Ethereum.

As an example, here's how we calculate PT-GLP price in US dollar:

// You can install npm package @pendle/core-v2 to directly import Pendle V2 contracts
import "@pendle/core-v2/contracts/oracles/PendlePtOracleLib.sol";
contract PendlePtGlpOracle {
//...
function getPtPrice() external view virtual returns (uint256) {
uint256 ptRate = IPMarket(market).getPtToAssetRate(twapDuration);
uint256 assetPrice = IGlpManager(glpManager).getPrice(true);
return (assetPrice * ptRate) / (10 ** 30);
}
}

For implementation details, please refer to our sample contracts for GLP and ChainlinkAsset oracles here.

PT Oracle Addresses

NetworkAddress
Ethereum0x14030836AEc15B2ad48bB097bd57032559339c92
Arbitrum0x1f6Cee6740e1492C279532348137FF40E0f23D05
BNBChain0xA48A88EbF6683324bAf17aEB51A6d89294D4bedc

The PT-GLP oracle has also been deployed here.