Pendle Operations
Pendle is a yield tokenization protocol that splits yield-bearing assets into two components:
- PT (Principal Token) — represents the principal value, redeemable at maturity for the underlying asset. Trading at a discount before maturity, PT lets you lock in a fixed yield.
- YT (Yield Token) — represents the right to all yield generated by the underlying asset until maturity. Buying YT is a leveraged bet on rising yields.
The SDK provides six Pendle primitives covering the full lifecycle of Pendle positions:
| Constant | Type String | Purpose |
|---|---|---|
PRIMITIVE_PENDLE_ADD_LIQUIDITY | "pendle_add_liquidity" | Add liquidity to a Pendle market |
PRIMITIVE_PENDLE_REMOVE_LIQUIDITY | "pendle_remove_liquidity" | Remove liquidity from a Pendle market |
PRIMITIVE_PENDLE_MINT_PT_YT | "pendle_mint_pt_yt" | Mint PT and YT from an underlying asset |
PRIMITIVE_PENDLE_REDEEM | "pendle_redeem" | Redeem PT/YT back to the underlying asset |
PRIMITIVE_PENDLE_SWAP_TO_PT | "pendle_swap_to_pt" | Swap into PT (lock in fixed yield) |
PRIMITIVE_PENDLE_SWAP_TO_YT | "pendle_swap_to_yt" | Swap into YT (go long on yield) |
All Pendle params share a common shape with required fields market (the Pendle market address) and amount, plus optional fields like asset, maturity, slippage, chain, and contract addresses.
Add Liquidity
import {
Chaos,
WALLET_MODEL,
extractPrimitives,
isPendleAddLiquidityPrimitive,
} from '@chaoslabs/ai-sdk';
const chaos = new Chaos({ apiKey: process.env.CHAOS_API_KEY! });
const response = await chaos.chat.responses.create({
model: WALLET_MODEL,
input: [
{
type: 'message',
role: 'user',
content: 'Add 10 stETH liquidity to the Pendle stETH market expiring Dec 2025',
},
],
metadata: {
user_id: 'user-1',
session_id: 'session-1',
wallets: [{ address: '0xYourWallet', chain: 'ethereum' }],
},
});
const primitives = extractPrimitives(response);
for (const primitive of primitives) {
if (isPendleAddLiquidityPrimitive(primitive)) {
// TypeScript knows this is PendleAddLiquidityPrimitive
console.log('Add liquidity:');
console.log(' Market:', primitive.params.market);
console.log(' Amount:', primitive.params.amount);
console.log(' Asset:', primitive.params.asset);
console.log(' Maturity:', primitive.params.maturity);
console.log(' Slippage:', primitive.params.slippage);
}
}Remove Liquidity
import {
Chaos,
WALLET_MODEL,
extractPrimitives,
isPendleRemoveLiquidityPrimitive,
} from '@chaoslabs/ai-sdk';
const chaos = new Chaos({ apiKey: process.env.CHAOS_API_KEY! });
const response = await chaos.chat.responses.create({
model: WALLET_MODEL,
input: [
{
type: 'message',
role: 'user',
content: 'Remove all my liquidity from the Pendle stETH market',
},
],
metadata: {
user_id: 'user-1',
session_id: 'session-1',
wallets: [{ address: '0xYourWallet', chain: 'ethereum' }],
},
});
for (const primitive of extractPrimitives(response)) {
if (isPendleRemoveLiquidityPrimitive(primitive)) {
console.log('Remove liquidity:');
console.log(' Market:', primitive.params.market);
console.log(' Amount:', primitive.params.amount);
console.log(' Asset:', primitive.params.asset);
}
}Mint PT & YT
Minting splits an underlying yield-bearing asset into its PT and YT components. This is useful when you want to sell one side (e.g., sell YT to lock in fixed yield via PT, or sell PT to go leveraged long on yield via YT).
import {
Chaos,
WALLET_MODEL,
extractPrimitives,
isPendleMintPtYtPrimitive,
} from '@chaoslabs/ai-sdk';
const chaos = new Chaos({ apiKey: process.env.CHAOS_API_KEY! });
const response = await chaos.chat.responses.create({
model: WALLET_MODEL,
input: [
{
type: 'message',
role: 'user',
content: 'Mint PT and YT from 5 eETH on the Pendle eETH market',
},
],
metadata: {
user_id: 'user-1',
session_id: 'session-1',
wallets: [{ address: '0xYourWallet', chain: 'ethereum' }],
},
});
for (const primitive of extractPrimitives(response)) {
if (isPendleMintPtYtPrimitive(primitive)) {
console.log('Mint PT & YT:');
console.log(' Market:', primitive.params.market);
console.log(' Amount:', primitive.params.amount);
console.log(' Asset:', primitive.params.asset);
console.log(' Maturity:', primitive.params.maturity);
}
}Swap to PT
Swapping to PT locks in a fixed yield. You receive PT at a discount that is redeemable 1:1 for the underlying asset at maturity.
import {
Chaos,
WALLET_MODEL,
extractPrimitives,
isPendleSwapToPtPrimitive,
} from '@chaoslabs/ai-sdk';
const chaos = new Chaos({ apiKey: process.env.CHAOS_API_KEY! });
const response = await chaos.chat.responses.create({
model: WALLET_MODEL,
input: [
{
type: 'message',
role: 'user',
content: 'Swap 10 stETH to PT on the Pendle stETH Dec 2025 market with 0.5% slippage',
},
],
metadata: {
user_id: 'user-1',
session_id: 'session-1',
wallets: [{ address: '0xYourWallet', chain: 'ethereum' }],
},
});
for (const primitive of extractPrimitives(response)) {
if (isPendleSwapToPtPrimitive(primitive)) {
console.log('Swap to PT:');
console.log(' Market:', primitive.params.market);
console.log(' Amount:', primitive.params.amount);
console.log(' Asset:', primitive.params.asset);
console.log(' Slippage:', primitive.params.slippage);
console.log(' Chain:', primitive.params.chain);
}
}Swap to YT
Swapping to YT gives you leveraged exposure to the yield of the underlying asset until maturity. YT value comes entirely from accumulated yield, so it goes to zero at maturity if held.
import {
Chaos,
WALLET_MODEL,
extractPrimitives,
isPendleSwapToYtPrimitive,
} from '@chaoslabs/ai-sdk';
const chaos = new Chaos({ apiKey: process.env.CHAOS_API_KEY! });
const response = await chaos.chat.responses.create({
model: WALLET_MODEL,
input: [
{
type: 'message',
role: 'user',
content: 'Swap 5 eETH to YT on the Pendle eETH market',
},
],
metadata: {
user_id: 'user-1',
session_id: 'session-1',
wallets: [{ address: '0xYourWallet', chain: 'ethereum' }],
},
});
for (const primitive of extractPrimitives(response)) {
if (isPendleSwapToYtPrimitive(primitive)) {
console.log('Swap to YT:');
console.log(' Market:', primitive.params.market);
console.log(' Amount:', primitive.params.amount);
console.log(' Asset:', primitive.params.asset);
console.log(' Maturity:', primitive.params.maturity);
}
}Redeem
Redeem converts PT (at or after maturity) or YT back into the underlying asset.
import {
Chaos,
WALLET_MODEL,
extractPrimitives,
isPendleRedeemPrimitive,
} from '@chaoslabs/ai-sdk';
const chaos = new Chaos({ apiKey: process.env.CHAOS_API_KEY! });
const response = await chaos.chat.responses.create({
model: WALLET_MODEL,
input: [
{
type: 'message',
role: 'user',
content: 'Redeem my matured PT-stETH from the Pendle stETH market',
},
],
metadata: {
user_id: 'user-1',
session_id: 'session-1',
wallets: [{ address: '0xYourWallet', chain: 'ethereum' }],
},
});
for (const primitive of extractPrimitives(response)) {
if (isPendleRedeemPrimitive(primitive)) {
console.log('Redeem:');
console.log(' Market:', primitive.params.market);
console.log(' Amount:', primitive.params.amount);
console.log(' Asset:', primitive.params.asset);
}
}Filter All Pendle Primitives
Use the category-level helpers when you want to handle all Pendle operations at once, regardless of the specific operation type.
import {
Chaos,
WALLET_MODEL,
extractPrimitives,
isPendlePrimitive,
PENDLE_PRIMITIVES,
} from '@chaoslabs/ai-sdk';
const chaos = new Chaos({ apiKey: process.env.CHAOS_API_KEY! });
const response = await chaos.chat.responses.create({
model: WALLET_MODEL,
input: [
{
type: 'message',
role: 'user',
content: 'Add 10 stETH liquidity and swap 5 stETH to PT on the Pendle stETH market',
},
],
metadata: {
user_id: 'user-1',
session_id: 'session-1',
wallets: [{ address: '0xYourWallet', chain: 'ethereum' }],
},
});
// Category check: is this any Pendle primitive?
const allPrimitives = extractPrimitives(response);
const pendlePrimitives = allPrimitives.filter(p => isPendlePrimitive(p.type));
console.log(`Found ${pendlePrimitives.length} Pendle primitives:`);
for (const p of pendlePrimitives) {
console.log(` ${p.type} — market: ${p.params.market}, amount: ${p.params.amount}`);
}
// Available Pendle primitive types for reference
console.log('\nAll Pendle primitive types:', PENDLE_PRIMITIVES);
// => ['pendle_add_liquidity', 'pendle_remove_liquidity', 'pendle_mint_pt_yt',
// 'pendle_redeem', 'pendle_swap_to_pt', 'pendle_swap_to_yt']Reference
Constants
| Constant | Value |
|---|---|
PRIMITIVE_PENDLE_ADD_LIQUIDITY | "pendle_add_liquidity" |
PRIMITIVE_PENDLE_REMOVE_LIQUIDITY | "pendle_remove_liquidity" |
PRIMITIVE_PENDLE_MINT_PT_YT | "pendle_mint_pt_yt" |
PRIMITIVE_PENDLE_REDEEM | "pendle_redeem" |
PRIMITIVE_PENDLE_SWAP_TO_PT | "pendle_swap_to_pt" |
PRIMITIVE_PENDLE_SWAP_TO_YT | "pendle_swap_to_yt" |
PENDLE_PRIMITIVES | Array of all six constants above |
Type Guards
| Function | Narrows To |
|---|---|
isPendleAddLiquidityPrimitive(p) | PendleAddLiquidityPrimitive |
isPendleRemoveLiquidityPrimitive(p) | PendleRemoveLiquidityPrimitive |
isPendleMintPtYtPrimitive(p) | PendleMintPtYtPrimitive |
isPendleRedeemPrimitive(p) | PendleRedeemPrimitive |
isPendleSwapToPtPrimitive(p) | PendleSwapToPtPrimitive |
isPendleSwapToYtPrimitive(p) | PendleSwapToYtPrimitive |
isPendlePrimitive(type) | Category check (returns boolean) |
Common Params Fields
All Pendle params types share the same shape:
| Field | Type | Required | Description |
|---|---|---|---|
market | string | Yes | Pendle market address |
amount | string | number | Yes | Amount to deposit, mint, redeem, or swap |
asset | string | null | No | Underlying asset symbol (e.g., 'stETH', 'eETH') |
maturity | string | null | No | Maturity date (ISO format or timestamp) |
slippage | number | null | No | Slippage tolerance percentage (0–50%) |
chain | string | No | Target chain |
chain_id | number | No | Numeric chain ID |
asset_address | string | No | Token address of the underlying asset |
token_in_address | string | No | Input token contract address |
token_out_address | string | No | Output token contract address |
router_contract | string | No | Pendle router contract address |
market_contract | string | No | Pendle market contract address |
pool_contract | string | No | Pool contract address |
vault_contract | string | No | Vault contract address |
contract | string | No | General contract address |
method | string | No | Contract method name |
call_params | object | No | Additional call parameters |