Part 3 β Module 3: Yield Tokenization
Difficulty: Advanced
Estimated reading time: ~35 minutes | Exercises: ~3-4 hours
π Table of Contents
The Fixed-Rate Problem
Core Mechanism: The PT/YT Split
- How Splitting Works
- Deep Dive: Implied Rate Math
- Deep Dive: YT Yield Accumulator
- Build Exercise: Yield Tokenizer
ERC-5115: Standardized Yield
Pendle Architecture
- System Overview
- YieldContractFactory: Minting PT + YT
- PendleYieldToken: Yield Tracking
- PendlePrincipalToken: Maturity Redemption
- Code Reading Strategy
The Pendle AMM
- Why Constant Product Fails for PT
- Rate-Space Trading: The Key Insight
- Deep Dive: The AMM Curve
- LP Considerations
- Build Exercise: PT Rate Oracle
Strategies & Composability
- Fixed Income: Buy PT
- Yield Speculation: Buy YT
- LP in Pendle Pool
- PT as Collateral
- The LST + Pendle Pipeline
Wrap Up
π‘ The Fixed-Rate Problem
π‘ Concept: Why Yield Tokenization?
The problem: All yield in DeFi is variable. Staking APR fluctuates daily. Aave supply rates change every block. Vault yields swing with market conditions. There is no native way to lock in a fixed rate.
This matters for everyone:
- Treasuries need predictable income (DAOs, protocols with runway)
- Risk-averse users want staking yield without rate uncertainty
- Speculators want leveraged exposure to yield direction
- Market makers want to trade yield as a separate asset
Traditional finance solved this decades ago with zero-coupon bonds and interest rate swaps. DeFi had no equivalent β until yield tokenization.
The solution: Split any yield-bearing asset into two components:
- PT (Principal Token) β claim on the underlying asset at maturity
- YT (Yield Token) β claim on all yield generated until maturity
This separation creates a fixed-rate market: buying PT at a discount locks in a known return at maturity, regardless of what happens to variable rates.
Traditional Finance DeFi Equivalent (Pendle)
βββββββββββββββββββββ βββββββββββββββββββββββββ
Zero-coupon bond ββ PT (Principal Token)
Floating-rate note ββ YT (Yield Token)
Bond yield ββ Implied rate
Maturity date ββ Maturity date
Coupon stripping ββ Tokenization (splitting)
π The Zero-Coupon Bond Analogy
A zero-coupon bond pays no interest during its life. You buy it at a discount ($970 for a $1000 face value) and receive $1000 at maturity. The difference IS your return, locked at purchase.
PT works identically:
- Buy 1 PT-wstETH for 0.97 wstETH today
- At maturity, redeem 1 PT for 1 wstETH
- Return: 0.03 / 0.97 = 3.09% for the period (fixed, locked at purchase)
- Variable rates can crash to 0% or spike to 20% β your return is fixed
YT is the complement β it captures whatever variable yield actually materializes:
- Buy 1 YT-wstETH for 0.03 wstETH today
- Until maturity, receive ALL staking yield on 1 wstETH
- If actual yield > 3.09% β profit (you paid 0.03 for more than 0.03 worth of yield)
- If actual yield < 3.09% β loss
- This is leveraged yield exposure: ~33x leverage for 0.03 cost
1 wstETH deposited
β
ββββ 1 PT-wstETH (buy at 0.97, redeem at 1.00)
β β
β ββββ Fixed 3.09% return β buyer locks this in
β
ββββ 1 YT-wstETH (buy at 0.03, receive variable yield)
β
ββββ Variable staking yield β speculator bets on direction
(could be 2%, 5%, 10%...)
Invariant: PT price + YT price = 1 underlying (arbitrage-enforced)
π‘ Key insight: Yield tokenization doesnβt create yield β it separates existing yield into fixed and variable components, letting each participant take the side they prefer.
π‘ Core Mechanism: The PT/YT Split
π‘ Concept: How Splitting Works
The mechanism is elegant in its simplicity:
Minting (splitting):
- User deposits 1 yield-bearing token (e.g., 1 wstETH via SY wrapper)
- Contract mints 1 PT + 1 YT, both with the same maturity date
- The yield-bearing token stays locked in the contract
Before maturity:
- PT trades at a discount (< 1 underlying) β the discount IS the implied fixed rate
- YT has positive value β it represents remaining yield entitlement
- Users can βunsplitβ: return 1 PT + 1 YT β get back 1 yield-bearing token
At maturity:
- PT is redeemable 1:1 for the underlying
- YT stops accruing yield and becomes worthless (value β 0)
- The βunsplitβ option is no longer needed
After maturity:
- PT can still be redeemed for 1 underlying (no expiry on redemption)
- Any unclaimed YT yield can still be collected
Timeline for PT-wstETH (6-month maturity):
Time βββββββββββββββββββββββββββββββββββββββββββββββ
T=0 (Mint) T=3mo T=6mo (Maturity)
PT price: 0.970 PT price: 0.985 PT price: 1.000
YT price: 0.030 YT price: 0.010 YT price: 0.000
β
βββ PT redeemable for 1 wstETH
βββ YT has paid out all yield
(worthless now)
Sum always = 1.000 Sum always = 1.000 Sum = 1.000
π‘ Time decay: YT loses value as maturity approaches because thereβs less time remaining to earn yield. This is exactly like options time decay (theta). The yield that hasnβt been earned yet decreases as the earning window shrinks.
π Deep Dive: Implied Rate Math
The implied rate is the annualized fixed return you lock in by buying PT at a discount. Understanding this math is fundamental to yield tokenization.
The basic relationship:
- PT trades at a discount to the underlying
- At maturity, PT = 1 underlying
- The return = (1 - ptPrice) / ptPrice for the remaining period
- Annualize to get the implied rate
Simple compounding formula (used in most DeFi implementations):
(1 - ptPrice) YEAR
impliedRate = βββββββββββββββββ Γ ββββββββββββββββββ
ptPrice timeToMaturity
Or equivalently:
1 YEAR
impliedRate = ( βββββββ - 1 ) Γ ββββββββββββββββββ
ptPrice timeToMaturity
Step-by-step example:
Given:
PT price = 0.97 underlying (3% discount)
Maturity = 6 months (182.5 days)
Step 1: Period return
periodReturn = (1 - 0.97) / 0.97
= 0.03 / 0.97
= 0.03093 (3.09% for 6 months)
Step 2: Annualize
impliedRate = 0.03093 Γ (365 / 182.5)
= 0.03093 Γ 2.0
= 0.06186 (6.19% annual)
Verification: if you invest 0.97 at 6.19% for 6 months:
0.97 Γ (1 + 0.0619 Γ 182.5/365) = 0.97 Γ 1.03093 = 1.0 β
The inverse β PT price from a target rate:
YEAR
ptPrice = βββββββββββββββββββββββββββββββββββββββ
YEAR + (impliedRate Γ timeToMaturity)
Example: What PT price gives a 5% annual rate with 3 months to maturity?
ptPrice = 365 / (365 + 0.05 Γ 91.25)
= 365 / 369.5625
= 0.98766
Check: (1 - 0.98766) / 0.98766 Γ 365/91.25 = 0.01249 Γ 4.0 = 5.0% β
In Solidity (18-decimal fixed-point):
uint256 constant WAD = 1e18;
uint256 constant SECONDS_PER_YEAR = 365 days; // 31_536_000
/// @notice Calculate implied annual rate from PT price and time to maturity.
/// @param ptPriceWad PT price in WAD (e.g., 0.97e18)
/// @param timeToMaturity Seconds until maturity
function getImpliedRate(uint256 ptPriceWad, uint256 timeToMaturity)
public pure returns (uint256)
{
// rate = (WAD - ptPrice) * YEAR / (ptPrice * timeToMaturity / WAD)
// Rearranged to avoid overflow:
// rate = (WAD - ptPrice) * YEAR * WAD / (ptPrice * timeToMaturity)
return (WAD - ptPriceWad) * SECONDS_PER_YEAR * WAD
/ (ptPriceWad * timeToMaturity);
}
π» Quick Try:
Deploy this in Remix to build intuition for PT pricing:
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
contract PTCalculator {
uint256 constant WAD = 1e18;
uint256 constant YEAR = 365 days;
/// @notice PT price β implied annual rate
function getRate(uint256 ptPrice, uint256 timeToMaturity) external pure returns (uint256) {
return (WAD - ptPrice) * YEAR * WAD / (ptPrice * timeToMaturity);
}
/// @notice Target annual rate β PT fair price
function getPrice(uint256 annualRate, uint256 timeToMaturity) external pure returns (uint256) {
return YEAR * WAD / (YEAR + annualRate * timeToMaturity / WAD);
}
}
Deploy and try:
getRate(0.97e18, 182.5 days)β should return ~6.19% (0.0619e18)getPrice(0.05e18, 91.25 days)β should return ~0.9877e18 (PT at 5% with 3 months left)getRate(0.9999e18, 1 days)β see how even a tiny discount implies a big annualized rate- Try
getPrice(0.05e18, 1 days)β PT price β 0.99986e18 (nearly 1.0 β convergence!)
This is the math that drives every Pendle market. Notice how the same rate produces wildly different prices depending on time to maturity.
Multiple maturities β same underlying, different rates:
wstETH Yield Tokenization Markets (hypothetical):
Maturity PT Price Implied Rate Interpretation
βββββββββββββ ββββββββ ββββββββββββ βββββββββββββββββββ
3 months 0.9876 5.02% Market expects ~5% staking yield
6 months 0.9700 6.19% Higher rate = yield might increase
1 year 0.9300 7.53% Even higher = bullish on staking yield
A rising term structure (short < long) suggests the market expects
yields to increase over time. Sound familiar? It's a yield curve β
the same concept from bond markets, now in DeFi.
π‘ Continuous compounding note: Pendle internally uses a continuous compounding model:
ptPrice = e^(-rate Γ timeToMaturity). This requiresln()andexp()functions in Solidity (Pendle has custom implementations). For exercise purposes, simple compounding is accurate enough for short maturities (< 1 year) and avoids complex math libraries.
π Deep Dive: YT Yield Accumulator β The Pattern Returns
If you completed Module 2βs FundingRateEngine exercise, this will feel familiar. The YT yield tracking uses the exact same accumulator pattern β a global counter that grows over time, with per-user snapshots at entry.
The pattern across DeFi:
Protocol Global Accumulator Per-User Snapshot
ββββββββββββββββ ββββββββββββββββββββββ ββββββββββββββββββββββ
Compound borrowIndex borrowIndex at borrow
Aave liquidityIndex userIndex at deposit
ERC-4626 share price (assets/shares) shares at deposit
Module 2 (Perps) cumulativeFundingPerUnit entryFundingIndex
Pendle (YT) pyIndex (yield index) userIndex at purchase
How YT yield tracking works:
The yield-bearing tokenβs exchange rate naturally increases over time (thatβs what βyield-bearingβ means). This exchange rate IS the accumulator:
Time Exchange Rate Yield Accrued (per unit)
ββββ ββββββββββββββ ββββββββββββββββββββββββ
T=0 1.000 β
T=1mo 1.004 0.4% (1 month of staking yield)
T=2mo 1.008 0.8%
T=3mo 1.013 1.3%
T=6mo 1.027 2.7%
The exchange rate only goes up. Each snapshot lets us compute
the yield earned between any two points in time.
Per-user yield calculation:
Alice buys YT when exchange rate = 1.004 (T=1mo)
β entryRate = 1.004
At T=4mo, exchange rate = 1.017
β yield per unit = (1.017 - 1.004) / 1.004 = 0.01295 = 1.29%
β For 100 YT: yield = 100 Γ 0.01295 = 1.295 underlying
Bob buys YT when exchange rate = 1.013 (T=3mo)
β entryRate = 1.013
At T=4mo, exchange rate = 1.017
β yield per unit = (1.017 - 1.013) / 1.013 = 0.00395 = 0.39%
β For 100 YT: yield = 100 Γ 0.00395 = 0.395 underlying
Each user's yield depends on WHEN they entered β captured by their
snapshot of the exchange rate. O(1) per calculation, no iteration.
In Solidity:
// The vault exchange rate IS the yield accumulator
// No separate index needed β it's already there!
function getAccruedYield(address user) public view returns (uint256) {
Position memory pos = positions[user];
uint256 currentRate = vault.convertToAssets(1e18); // current exchange rate
// yield = ytBalance Γ (currentRate - entryRate) / entryRate
// This is: how much each unit has grown since user's entry
uint256 yieldPerUnit = (currentRate - pos.entryRate) * WAD / pos.entryRate;
return pos.ytBalance * yieldPerUnit / WAD;
}
π‘ The insight: In Module 2βs FundingRateEngine, you built the accumulator from scratch (computing rate Γ time, accumulating it). Here, the vaultβs exchange rate IS the accumulator β itβs already maintained by the underlying protocol (Lido, Aave, etc.). YT yield tracking simply snapshots this existing accumulator. Same pattern, different source.
What happens to the locked shares?
When yield is claimed from YT, the contract needs to pay out actual tokens. The math works elegantly:
At tokenization:
100 vault shares deposited (rate = 1.0)
β 100 underlying worth of principal (PT claim)
β 100 underlying worth of yield entitlement (YT claim)
β Contract holds: 100 shares
Later (rate = 1.05):
100 shares now worth 105 underlying
PT claim: 100 underlying = 100/1.05 = 95.24 shares
YT yield: 5 underlying = 5/1.05 = 4.76 shares
Total: 95.24 + 4.76 = 100 shares β
The yield comes from the shares becoming MORE valuable.
Fewer shares are needed to cover the fixed principal,
and the "excess" shares fund the yield payout.
πΌ Job Market Context
What DeFi teams expect you to know:
-
βExplain how Pendle creates fixed-rate products in DeFi.β
- Good answer: βPendle splits yield-bearing tokens into PT (principal) and YT (yield). PT trades at a discount and can be redeemed at par at maturity, giving buyers a fixed rate.β
- Great answer: βPendle wraps yield-bearing tokens into SY (ERC-5115), then splits them into PT and YT with a shared maturity. PT is a zero-coupon bond β buying at a discount locks in a fixed rate calculated as
(1/ptPrice - 1) * year/timeToMaturity. YT captures variable yield using a global exchange rate accumulator with per-user snapshots, the same O(1) pattern as Compoundβs borrowIndex. The custom AMM trades in rate-space rather than price-space, which is essential because PT must converge to 1.0 at maturity β something constant-product AMMs canβt handle.β
-
βHow does Pendleβs YT track yield?β
- Good answer: βIt uses the SY exchange rate to calculate accrued yield per holder.β
- Great answer: βPendle uses the same accumulator pattern as Compound/Aave. The global
pyIndexStoredtracks the latest SY exchange rate. Each user has auserIndexsnapshotted at purchase or last claim. Accrued yield isytBalance * (pyIndexStored - userIndex) / userIndexβ an O(1) calculation. Critically, YT overrides_beforeTokenTransferto settle yield before any transfer. Without this, transferring YT would incorrectly shift accumulated yield to the recipient. This settlement-on-transfer pattern appears in every token that tracks per-holder rewards.β
Interview Red Flags:
- π© Confusing PT and YT roles (which one gives fixed rate vs variable yield exposure?)
- π© Not recognizing the accumulator pattern as the same O(1) mechanism used in Compound and Aave
- π© Thinking yield tokenization creates yield (it only separates existing yield into two components)
Pro tip: When explaining PT/YT splitting, connect it to the accumulator pattern across protocols β Compoundβs borrowIndex, Aaveβs liquidityIndex, Pendleβs pyIndex. Showing you see the same mathematical pattern in three different contexts signals deep DeFi fluency.
π― Build Exercise: Yield Tokenizer
Exercise 1: YieldTokenizer
Workspace:
- Scaffold:
workspace/src/part3/module3/exercise1-yield-tokenizer/YieldTokenizer.sol - Tests:
workspace/test/part3/module3/exercise1-yield-tokenizer/YieldTokenizer.t.sol
Build the core PT/YT splitting mechanism from an ERC-4626 vault:
- Accept vault shares β internally mint PT + YT balances
- Track yield using the vaultβs exchange rate as the accumulator
- YT holders claim accrued yield (paid out in vault shares)
- PT holders redeem at maturity (principal value in vault shares)
- Before maturity: βunsplitβ by burning PT + YT balances
5 TODOs: tokenize(), getAccruedYield(), claimYield(), redeemAtMaturity(), redeemBeforeMaturity()
π― Goal: Implement the same accumulator pattern from Module 2βs FundingRateEngine, but now driven by an external exchange rate instead of an internal calculation.
Run: forge test --match-contract YieldTokenizerTest -vvv
π Summary: Yield Tokenization Fundamentals
Covered:
- The fixed-rate problem in DeFi and why variable yields create uncertainty
- Zero-coupon bond analogy: buy at a discount, redeem at par at maturity
- PT/YT split mechanism β separating principal and yield into tradable tokens
- Implied rate math: how PT price and time-to-maturity determine the fixed rate
- YT yield accumulator pattern: tracking accrued yield via exchange rate snapshots
- Maturity mechanics: PT redemption, YT expiry, and pre-maturity unsplitting
Next: ERC-5115 (Standardized Yield) β Pendleβs generalization of ERC-4626 for wrapping arbitrary yield sources.
π‘ ERC-5115: Standardized Yield
π‘ Concept: SY vs ERC-4626
Pendle introduced ERC-5115 (Standardized Yield) because ERC-4626 wasnβt general enough for all yield sources.
ERC-4626 limitations:
- Requires a single underlying
asset()for deposit/withdraw - Assumes the vault IS the yield source
- Some yield-bearing tokens donβt fit the vault model (e.g., stETH rebases, GLP has custom minting)
ERC-5115 (SY) extends this:
- Supports multiple input tokens (deposit with ETH, stETH, or wstETH β same SY)
- Supports multiple output tokens (redeem to ETH or wstETH)
- Works with any yield-bearing token regardless of its native interface
- Standard
exchangeRate()function for yield tracking
ERC-4626 (Vault): ERC-5115 (SY):
βββββββββββββββββ βββββββββββββββββ
One asset in/out Multiple tokens in/out
deposit(assets) β shares deposit(tokenIn, amount) β syAmount
redeem(shares) β assets redeem(tokenOut, syAmount) β amount
asset() β address yieldToken() β address
convertToAssets(shares) exchangeRate() β uint256
Example: SY-wstETH accepts:
βββ ETH (auto-stakes via Lido)
βββ stETH (wraps to wstETH)
βββ wstETH (direct wrap)
All produce the same SY-wstETH token.
Why SY matters for developers:
- SY is the universal adapter layer β write one integration, support any yield source
- All PT/YT markets are denominated in SY, not the raw yield token
exchangeRate()is the single function that drives the entire yield tokenization math
π Exchange Rate Mechanics
The SY exchange rate is the foundation of all yield calculations:
// SY-wstETH exchange rate example
function exchangeRate() external view returns (uint256) {
// 1 SY = how much underlying?
// For wstETH: returns stETH per wstETH (increases over time)
return IWstETH(wstETH).stEthPerToken(); // e.g., 1.156e18
}
The exchange rate ONLY increases (for non-rebasing tokens). This monotonic growth is what makes it a natural accumulator. Note the contrast with Module 2βs cumulativeFundingPerUnit, which can move in both directions (positive during net-long skew, negative during net-short). The exchange rate is strictly monotonic β a simpler accumulator that never reverses.
SY-wstETH Exchange Rate Over Time:
Rate
1.20 β β±
1.18 β β±βββ±
1.16 β β±βββ±β
1.14 β β±βββ±β
1.12 β β±βββ±β
1.10 β β±βββ±β
1.08 β β±βββ±β
1.06 β β±βββ±β
1.04 β β±βββ±β
1.02 ββ±ββ±β
1.00 ββ
ββββββββββββββββββββββββββββββββββββββββββββ Time
T=0 3mo 6mo 9mo 12mo 15mo
Each point on this curve is a "snapshot" opportunity.
YT yield = the vertical distance between entry and exit.
π‘ Pendle Architecture
π‘ Concept: System Overview
Pendle V2 (current version) has a clean layered architecture:
User Layer: PendleRouter (single entry point)
β
ββββββ΄βββββ
β β
Split Layer: YieldContractFactory PendleMarket (AMM)
β β
βββββ΄ββββ ββββββ΄βββββ
β β β β
Token Layer: PT YT PT SY
β β β β
βββββ¬ββββ ββββββ¬βββββ
β β
Yield Layer: SY (ERC-5115 wrapper) β
β β
βββββββββββββββββββββββββ
β
Raw Asset: Yield-bearing token
(wstETH, aUSDC, sDAI...)
The flow:
- User deposits yield-bearing token β SY wrapper creates SY token
- SY token β YieldContractFactory splits into PT + YT (same maturity)
- PT trades against SY in the PendleMarket (AMM)
- YT accrues yield from the underlying via the SY exchange rate
- At maturity: PT redeemable for SY β unwrap to yield-bearing token
ποΈ YieldContractFactory: Minting PT + YT
The factory creates PT/YT pairs for each (SY, maturity) combination:
// Simplified from Pendle's YieldContractFactory
function createYieldContract(address SY, uint256 expiry)
external returns (address PT, address YT)
{
// Each (SY, expiry) pair gets exactly one PT and one YT
// PT address is deterministic (CREATE2)
PT = _deployPT(SY, expiry);
YT = _deployYT(SY, expiry, PT);
}
Maturity encoding: Pendle uses quarterly maturities (March, June, September, December) for major markets. Each maturity creates a separate market with its own implied rate. As one market approaches maturity, liquidity migrates to the next (βrollingβ β same as futures markets in TradFi).
ποΈ PendleYieldToken: Yield Tracking
The YT contract maintains the yield accumulator that we discussed above:
// Simplified from PendleYieldToken
contract PendleYieldToken {
uint256 public pyIndexStored; // Global: last recorded exchange rate
mapping(address => uint256) public userIndex; // Per-user: rate at last claim
function _updateAndDistributeYield(address user) internal {
uint256 currentIndex = SY.exchangeRate();
if (currentIndex > pyIndexStored) {
// Yield has accrued since last global update
pyIndexStored = currentIndex;
}
uint256 userIdx = userIndex[user];
if (userIdx == 0) userIdx = pyIndexStored; // first interaction
if (pyIndexStored > userIdx) {
// User has unclaimed yield
uint256 yieldPerUnit = (pyIndexStored - userIdx) * WAD / userIdx;
uint256 yield = balanceOf(user) * yieldPerUnit / WAD;
// Transfer yield to user...
userIndex[user] = pyIndexStored;
}
}
// CRITICAL: yield must be settled on every transfer
function _beforeTokenTransfer(address from, address to, uint256) internal {
if (from != address(0)) _updateAndDistributeYield(from);
if (to != address(0)) _updateAndDistributeYield(to);
}
}
π‘ Why settle on transfer? If Alice transfers YT to Bob without settling, the yield Alice earned would incorrectly flow to Bob (his entry index would be lower than it should be). By settling before every transfer, each userβs accumulated yield is correctly attributed. This is the same reason Compound settles interest before any borrow/repay operation.
ποΈ PendlePrincipalToken: Maturity Redemption
PT is simpler β itβs essentially a zero-coupon bond token:
// Simplified from PendlePrincipalToken
contract PendlePrincipalToken {
uint256 public expiry;
address public SY;
address public YT;
function redeem(uint256 amount) external {
require(block.timestamp >= expiry, "Not matured");
_burn(msg.sender, amount);
// 1 PT = 1 underlying at maturity
// Convert to SY amount using current exchange rate
uint256 syAmount = amount * WAD / SY.exchangeRate();
SY.transfer(msg.sender, syAmount);
}
}
Post-maturity behavior: PT can be redeemed at any time after maturity. Thereβs no penalty for late redemption. However, the PT holder foregoes any yield earned between maturity and redemption β that yield effectively belongs to the protocol or is distributed to other participants.
π Code Reading Strategy for Pendle
Repository: pendle-core-v2-public
Reading order:
- Start with SY β
SYBase.soland one concrete implementation (e.g.,SYWstETH.sol). UnderstandexchangeRate(),deposit(),redeem(). This is the yield abstraction layer. - Read PT/YT minting β
YieldContractFactory.sol. See howcreateYieldContract()deploys PT + YT with deterministic addresses. - Study YT yield tracking β
PendleYieldToken.sol. Focus onpyIndexStored,userIndex, and_updateAndDistributeYield(). This is the accumulator. - Trace a swap β
PendleMarketV7.sol. Start withswapExactPtForSy(). Follow the AMM curve math. - Read the Router β
PendleRouter.sol. See how user-facing functions compose the lower-level operations.
Donβt get stuck on: The AMM curve math internals (MarketMathCore.sol). The formulas involve ln() and exp() approximations that are dense. Understand the CONCEPT (rate-space trading) first, then optionally deep-dive into the math.
Key test files: test/core/Market/ β tests for AMM operations, especially around maturity edge cases.
π‘ The Pendle AMM
π‘ Concept: Why Constant Product Fails for PT
Standard AMMs (Uniswapβs x Γ y = k) assume the two tokens have an independent, freely floating price relationship. PT breaks this assumption because PT has a known future value: at maturity, 1 PT = 1 underlying. Always.
The problem with x Γ y = k:
Standard AMM pool: PT / Underlying
At T=0 (6 months to maturity):
Pool: 1000 PT + 970 underlying (PT at 3% discount)
Works fine β normal trading, reasonable slippage
At T=5.5 months (2 weeks to maturity):
PT should trade at ~0.998 (0.2% discount for 2 weeks)
But x*y=k still allows wide price swings
A moderate swap could move PT price to 0.95 β absurd for a near-maturity asset
At maturity:
PT MUST trade at exactly 1.0
But x*y=k has no concept of time or convergence
The pool would still allow trades at 0.90 or 1.10
Massive arbitrage opportunities, broken pricing
Price
1.10 β
β
1.05 β x*y=k range at maturity
β βββββββββββββββ
1.00 β Β· Β· Β· Β· Β· Β· Β· Β· Β· Β·βΒ· Β· SHOULD Β· βΒ· Β· Β· Β· Β· β PT = 1.0 here
β β BE HERE! β
0.95 β βββββββββββββββ
β
0.90 β
ββββββββββββββββββββββββββββββββββββββββ Time
T=0 Maturity
Problem: x*y=k doesn't know about maturity.
It allows prices that make no economic sense.
π‘ Analogy: Imagine a bond market where the exchange allows a 1-year Treasury to trade at 50 cents on the dollar with 1 day until maturity. No rational market would allow this. But a standard AMM has no mechanism to prevent it.
π‘ Concept: Rate-Space Trading: The Key Insight
Pendleβs AMM (inspired by Notional Finance) solves this by trading in rate space instead of price space.
The insight: Instead of asking βwhat price should PT trade at?β, ask βwhat implied interest rate should the market express?β Then derive the price from the rate.
Price-space trading (standard AMM):
"1 PT costs 0.97 underlying"
β No concept of time decay
β Wide price range even near maturity
Rate-space trading (Pendle AMM):
"The market implies a 6.19% annual rate"
β Rate naturally has bounded behavior
β Near maturity, even large rate changes produce tiny price changes
β At maturity, any finite rate maps to price β 1.0
Why rate-space works:
Rate = 6.19% Rate = 6.19% Rate = 6.19%
Time = 6 months Time = 1 month Time = 1 day
ββββββββββββββββ ββββββββββββββββ ββββββββββββββββ
PT price = 0.970 PT price = 0.995 PT price = 0.99983
Same rate, but:
- 6mo out β 3% price discount (meaningful)
- 1mo out β 0.5% discount (small)
- 1 day out β 0.002% discount (negligible)
As maturity approaches, rate-space naturally compresses
the price range toward 1.0. The AMM doesn't need special
logic for convergence β it falls out of the math.
π Deep Dive: The AMM Curve
Pendleβs AMM uses a modified logit curve with time-dependent parameters. The pool contains PT and SY (not PT and underlying directly).
Conceptual formula (simplified):
ln(ptProportion / syProportion)
impliedRate = ββββββββββββββββββββββββββββββββββββ Γ scalar
timeToMaturity
Where:
ptProportion = ptReserve / totalLiquidity
syProportion = syReserve / totalLiquidity
scalar = amplification parameter (like Curve's A)
timeToMaturity = seconds remaining (decreases over time)
Key properties:
-
Time-to-maturity in the denominator: As maturity approaches, the same reserve change produces a larger rate movement. But since price = f(rate, time), and time is shrinking, the net effect is that price movements get SMALLER. The curve βflattensβ near maturity.
-
Scalar (amplification): Controls rate sensitivity. Higher scalar β more concentrated liquidity around the current rate β lower slippage for normal trades, but larger slippage for rate-moving trades. Similar to Curve Financeβs A parameter.
-
Anchor rate: The initial implied rate at pool creation. The curve is centered around this rate. LPs implicitly express a view on rates by providing liquidity.
Pendle AMM Curve at Different Times to Maturity:
PT Price
β
1.000 βΒ·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·β±ββ T=1 day
β β± (very flat, price β 1.0)
0.998 βΒ·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·β±ββββββββ±
β β±βββ T=1 month
0.990 βΒ·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·β±βββββββββ± (flatter, price β 0.99)
β β±βββββ±
0.980 βΒ·Β·Β·Β·Β·Β·Β·Β·Β·β±βββββββββ±
β β±βββ± T=3 months
0.970 ββββ±βββ± (moderate curve)
β β±β±
0.960 ββ± T=6 months
β (widest curve)
ββββββββββββββββββββββββββββββββββββββββββββ Pool Imbalance
More SY Balanced More PT
As maturity approaches:
- Curve FLATTENS (less price sensitivity)
- Price CONVERGES to 1.0
- Any finite implied rate maps to PT β 1.0
Comparison with standard AMMs:
Feature Uniswap V2 (x*y=k) Curve (StableSwap) Pendle
βββββββββββββββββ βββββββββββββββββββ ββββββββββββββββββ ββββββββββββββ
Curve shape Hyperbola Flat near peg Time-dependent
Time awareness None None Built-in
Price convergence No No Yes (at maturity)
Rate discovery No No Yes
Best for Independent tokens Pegged assets Time-decaying assets
ποΈ LP Considerations
LPing in Pendle pools has unique properties compared to standard AMMs:
Impermanent loss dynamics:
- In standard AMMs, IL is permanent if prices diverge
- In Pendle pools, PT converges to 1.0 at maturity
- This means IL DECREASES over time as the pool naturally rebalances
- LPs in Pendle pools near maturity have almost zero IL
Triple yield for Pendle LPs:
- Swap fees β from traders buying/selling PT
- PT discount β the SY side of the pool earns yield from the underlying
- Underlying yield β the PT side also implicitly earns (it converges to 1.0)
When LP is most attractive:
- High trading volume (fees)
- Moderate time to maturity (enough fee income, declining IL)
- Volatile rates (more trading, more fees)
π‘ LP convergence insight: A Pendle LP position held to maturity essentially has zero IL because both sides of the pool converge to the same value (1 SY = 1 PT = 1 underlying). This is unique among AMM designs.
πΌ Job Market Context
What DeFi teams expect you to know:
-
βWhy canβt you use Uniswapβs x*y=k AMM for PT trading?β
- Good answer: βPT converges to 1.0 at maturity, and standard AMMs donβt account for time.β
- Great answer: βx*y=k treats both assets as having independent, freely floating prices. PT has a deterministic future value β it equals 1 underlying at maturity. Near maturity, a standard AMM would still allow wide price swings, enabling trades at absurd discounts or premiums. Pendleβs AMM operates in rate-space: the curve uses
ln(ptProportion/syProportion) / timeToMaturity * scalar, which naturally flattens as maturity approaches. This is inspired by Notional Financeβs logit curve, and the scalar parameter plays a role analogous to Curveβs amplification factor A.β
-
βHow does PT pricing change as maturity approaches?β
- Good answer: βPT price converges to 1.0 as maturity approaches.β
- Great answer: βUsing simple compounding,
ptPrice = year / (year + rate * timeToMaturity). As timeToMaturity approaches 0, ptPrice approaches 1.0 regardless of the implied rate. Even at a 100% implied rate, with 1 day to maturity, PT trades at 0.99726. This convergence is built into Pendleβs AMM curve β thetimeToMaturityin the denominator of the rate formula means the curve naturally flattens, reducing price sensitivity of swaps. This is why Pendle LPs experience decreasing IL over time, unlike standard AMMs where IL is path-dependent and potentially permanent.β
Interview Red Flags:
- π© Not knowing why a constant-product AMM fails for PT (the time-convergence problem)
- π© Thinking Pendleβs AMM is just a Uniswap fork with different parameters
- π© Unable to explain how the scalar parameter relates to Curveβs amplification factor A
Pro tip: Pendleβs AMM is one of the most sophisticated in DeFi β understanding rate-space trading and the logit curve (inspired by Notional Finance) shows you can reason about purpose-built AMMs, not just x*y=k variations.
π― Build Exercise: PT Rate Oracle
Exercise 2: PTRateOracle
Workspace:
- Scaffold:
workspace/src/part3/module3/exercise2-pt-rate-oracle/PTRateOracle.sol - Tests:
workspace/test/part3/module3/exercise2-pt-rate-oracle/PTRateOracle.t.sol
Build a rate oracle that computes and tracks implied rates from PT prices:
- Calculate implied annual rate from PT price and time-to-maturity
- Calculate PT fair value from a target annual rate
- Record rate observations with timestamps
- Compute Time-Weighted Average Rate (TWAR) β same accumulator pattern as Uniswap V2βs TWAP oracle
- Calculate YT break-even rate for profitability analysis
5 TODOs: getImpliedRate(), getPTPrice(), recordObservation(), getTimeWeightedRate(), getYTBreakEven()
π― Goal: Master the implied rate math and connect rate-oracle tracking to the TWAP accumulator pattern from Part 2 Module 3 (Oracles).
Run: forge test --match-contract PTRateOracleTest -vvv
π Summary: Pendle Architecture & AMM
Covered:
- ERC-5115 Standardized Yield (SY) β wrapping diverse yield sources into a common interface
- SY vs ERC-4626: reward token handling, multi-asset support, and exchange rate mechanics
- Pendle system overview: SY wrapping, YieldContractFactory, PT/YT minting
- Why constant-product AMMs fail for yield tokens (PT converges to 1:1 at maturity)
- Rate-space trading: Pendleβs key insight of trading implied rates instead of prices
- TWAR oracle: time-weighted average rate using the cumulative accumulator pattern
- LP considerations: impermanent loss profile and the fee/rate trade-off
Next: Yield tokenization strategies and composability β how to use PT/YT for fixed income, leveraged yield, and structured products.
π‘ Strategies & Composability
π‘ Concept: Strategy 1: Fixed Income β Buy PT
Mechanism: Buy PT at a discount β hold to maturity β redeem at 1:1.
Worked example:
Scenario: Lock in a fixed staking yield on wstETH
Step 1: Buy 100 PT-wstETH at 0.97 price
Cost: 97 wstETH
Step 2: Hold until maturity (6 months)
Step 3: Redeem 100 PT for 100 wstETH
Result:
Paid: 97 wstETH
Received: 100 wstETH
Profit: 3 wstETH (3.09% over 6 months = 6.19% annualized)
Rate locked at purchase β doesn't matter if staking yield drops to 2%
Risk analysis:
- Smart contract risk: Pendle or underlying protocol bug
- Underlying failure: If the yield source (e.g., Lido) has a slashing event, PT may not be worth 1.0
- Opportunity cost: If rates spike to 20%, youβre locked at 6.19%
- Liquidity risk: Selling PT before maturity incurs AMM slippage
- No impermanent loss: This isnβt an LP position β just a buy and hold
Use cases: DAO treasury management, yield hedging, risk-off positioning.
π‘ Concept: Strategy 2: Yield Speculation β Buy YT
Mechanism: Buy YT β receive all yield on the underlying until maturity.
Worked example:
Scenario: Bet that wstETH staking yield increases
Step 1: Buy 100 YT-wstETH at 0.03 price
Cost: 3 wstETH (for yield entitlement on 100 wstETH!)
β This is ~33x leverage on yield
Step 2: Over 6 months, actual average staking yield = 4.5%
Step 3: Yield received = 100 wstETH Γ 4.5% Γ 0.5 year = 2.25 wstETH
Result:
Cost: 3 wstETH
Received: 2.25 wstETH
Loss: 0.75 wstETH
Break-even analysis:
Need actual yield to equal implied rate: 6.19% annual = 3.09% over 6 months
Need 100 Γ 3.09% = 3.09 wstETH in yield to break even on 3 wstETH cost
Any average yield above ~6.19% annual β profit
The points/airdrop meta: In 2024, YT became hugely popular for airdrop farming. If an underlying protocol distributes points or airdrops to holders, YT holders receive them (since YT represents yield entitlement). Buying 100 YT for 3 wstETH gives airdrop exposure on 100 wstETH β massive leverage on potential airdrops.
π‘ Concept: Strategy 3: LP in Pendle Pool
LPing in Pendle pools provides exposure to both sides with unique IL characteristics:
Pendle LP Yield Sources:
1. Swap fees β From traders (PT buyers/sellers)
2. SY yield β The SY portion of pool earns yield
3. PENDLE rewards β Gauge emissions (vePENDLE-boosted)
4. PT convergence β IL decreases over time (free yield!)
Total APY can be attractive: 5-15% on stable pools, higher on volatile ones
π‘ Concept: PT as Collateral
The insight: PT has a known minimum value at maturity (1 underlying). This makes it excellent collateral β lenders know exactly what itβs worth at a specific date.
Morpho Blue + Pendle PT:
- Morpho accepts Pendle PT tokens as collateral for borrowing
- The PT discount provides a built-in safety margin
- Example: Borrow 0.95 USDC against 1 PT-aUSDC (LTV ~97%)
- At maturity, PT = 1.0 β comfortable collateral ratio
Looping strategy:
- Deposit yield-bearing asset β get SY β split to PT + YT
- Use PT as collateral on Morpho β borrow more underlying
- Repeat β leveraged fixed-rate exposure
π The LST + Pendle Pipeline
Combining Module 1 (LSTs) with yield tokenization creates a full-stack yield management system:
ETH β Lido β stETH β wrap β wstETH β Pendle SY β PT + YT
β β β
β β βββ YT: speculate on
β β staking yield direction
β β
β βββββ PT: lock in fixed
β staking yield
β
βββ Originally earning variable ~3-4% staking yield
Now separated into fixed and variable components
DeFi composability at its finest:
- Ethereum staking (L1)
- Lido (liquid staking)
- Pendle (yield tokenization)
- Morpho (lending against PT)
Each layer adds a new financial primitive.
πΌ Job Market Context
What DeFi teams expect you to know:
- βWhat are the risks of buying YT?β
- Good answer: βTime decay β YT loses value as maturity approaches. If actual yield is lower than implied, you lose money.β
- Great answer: βYT is leveraged long yield exposure with time decay. The break-even rate equals the implied rate at purchase β if average actual yield stays below that, YT is unprofitable. Key risks: (1) Time decay β shorter remaining period means less yield to capture, (2) Rate compression β if staking yields fall, YT can lose most of its value rapidly, (3) Smart contract risk on both Pendle and the underlying protocol, (4) Liquidity risk β YT markets are thinner than PT markets, so exiting a position can have high slippage. The leverage works both ways β a small cost buys yield exposure on a large notional, but the maximum loss is 100% of the YT purchase price.β
Interview Red Flags:
- π© Ignoring time decay when analyzing YT profitability (treating it like a spot position)
- π© Not knowing the break-even condition: average actual yield must exceed implied rate at purchase
- π© Overlooking PT-as-collateral composability with lending protocols like Morpho
Pro tip: Yield tokenization is one of the most innovative DeFi primitives of 2023-2024. Understanding it deeply signals you follow cutting-edge DeFi. Bonus points for knowing how PT-as-collateral works in Morpho and for connecting the accumulator pattern across Compound, Aave, and Pendle.
π Summary: Yield Tokenization
β Covered:
- The fixed-rate problem and zero-coupon bond analogy
- PT/YT splitting mechanics and invariant (PT + YT = 1 underlying)
- Implied rate math with worked examples (annualization, inverse formula)
- YT yield accumulator β same O(1) pattern as Compound, Aave, Module 2 funding rate
- ERC-5115 (Standardized Yield) vs ERC-4626
- Pendle architecture: SY β Factory β PT/YT β AMM β Router
- Why x*y=k fails for time-decaying assets
- Rate-space trading and the Pendle AMM curve
- Strategies: fixed income (PT), yield speculation (YT), LP, PT as collateral
- LST + Pendle pipeline (Module 1 integration)
Key insight: The accumulator pattern appears for the third time in this curriculum. Whether itβs vault share pricing (P2M7), funding rates (P3M2), or yield tracking (P3M3), the math is identical: global growing counter + per-user snapshot + delta = amount owed.
Next: Cross-module concept links and resources.
π Cross-Module Concept Links
The accumulator pattern (3rd appearance):
| Module | Accumulator | What it tracks | Update trigger |
|---|---|---|---|
| P2M7 | ERC-4626 share price | Vault yield per share | Deposit/withdraw |
| P3M2 | cumulativeFundingPerUnit | Funding payments per unit | Position open/close |
| P3M3 | Exchange rate (pyIndex) | Yield per unit of SY | YT claim/transfer |
Each is the SAME mathematical pattern: a global counter that grows, per-user snapshots at entry, delta = amount owed. The only difference is whatβs being accumulated (vault yield, funding payments, staking yield).
Time-decaying assets (new pattern):
- PT value converges to 1.0 at maturity
- Options value decays (theta) as expiry approaches
- Bond price converges to par at maturity
- Any AMM for time-decaying assets needs a time-aware curve
Fixed rate from variable rate (financial engineering pattern):
- PT/YT splitting in Pendle
- Interest rate swaps in TradFi
- Notional Finance (fixed-rate lending)
- All achieve the same goal: converting floating exposure to fixed
π Production Study Order
Study these codebases in order β each builds on the previous oneβs patterns:
| # | Repository | Why Study This | Key Files |
|---|---|---|---|
| 1 | Pendle SYBase.sol | ERC-5115 standardized yield implementation β the abstraction layer that wraps any yield source | contracts/core/StandardizedYield/SYBase.sol, contracts/core/StandardizedYield/implementations/ |
| 2 | Pendle PendleYieldToken.sol | Yield accumulator pattern, reward tracking, per-user snapshot math β the core accounting | contracts/core/YieldContracts/PendleYieldToken.sol |
| 3 | Pendle PendlePrincipalToken.sol | Maturity redemption, PT value convergence, mint/burn tied to YT lifecycle | contracts/core/YieldContracts/PendlePrincipalToken.sol |
| 4 | Pendle MarketMathCore.sol | Rate-space AMM math β the time-decaying curve that makes PT/YT trading work | contracts/core/Market/MarketMathCore.sol |
| 5 | Pendle PendleMarketV7.sol | AMM pool implementation, LP mechanics, fee structure, swap execution | contracts/core/Market/PendleMarketV7.sol |
| 6 | Spectra (formerly APWine) | Alternative yield tokenization β compare design choices with Pendle | Core contracts |
Reading strategy: Start with SYBase.sol to understand the yield abstraction layer β this is the adapter pattern that makes Pendle protocol-agnostic. Then read PendleYieldToken.sol for the accumulator math (compare with P2M7 ERC-4626 and P3M2 funding accumulators β same pattern). Study PendlePrincipalToken.sol to see how PT and YT are coupled. Only then tackle MarketMathCore.sol β this is the hardest file, focus on the rate-space transformation before the implementation details. Finally, read the market contract to see the AMM in action.
π Resources
Production Code
- Pendle V2 Core (GitHub) β full protocol implementation
- PendleYieldToken.sol β yield accumulator implementation
- PendleMarketV7.sol β AMM with rate-space trading
Standards
- ERC-5115: Standardized Yield (EIP) β the SY token standard
- ERC-4626: Tokenized Vault (EIP) β comparison reference
Documentation
- Pendle Documentation β official protocol docs
- Pendle Academy β educational resources from the team (note: Pendle Academy may have been deprecated or merged into main docs; if the link is dead, see Pendle Docs instead)
- Notional Finance Docs β AMM curve inspiration
Further Reading
- Pendle Documentation β includes AMM curve details (navigate to Developers β Contracts)
- Dan Robinson & Allan Niemerg: Yield Protocol β foundational research on yield tokenization
Navigation: β Module 2: Perpetuals & Derivatives | Part 3 Overview | Next: Module 4 β DEX Aggregation & Intents β