Pendle Operations

Updated

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:

ConstantType StringPurpose
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

pendle-add-liquidity.ts
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

pendle-remove-liquidity.ts
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).

pendle-mint-pt-yt.ts
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.

pendle-swap-to-pt.ts
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.

pendle-swap-to-yt.ts
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.

pendle-redeem.ts
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.

pendle-filter-all.ts
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']
[@portabletext/react] Unknown block type "callout", specify a component for it in the `components.types` prop

Reference

Constants

ConstantValue
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_PRIMITIVESArray of all six constants above

Type Guards

FunctionNarrows 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:

FieldTypeRequiredDescription
marketstringYesPendle market address
amountstring | numberYesAmount to deposit, mint, redeem, or swap
assetstring | nullNoUnderlying asset symbol (e.g., 'stETH', 'eETH')
maturitystring | nullNoMaturity date (ISO format or timestamp)
slippagenumber | nullNoSlippage tolerance percentage (0–50%)
chainstringNoTarget chain
chain_idnumberNoNumeric chain ID
asset_addressstringNoToken address of the underlying asset
token_in_addressstringNoInput token contract address
token_out_addressstringNoOutput token contract address
router_contractstringNoPendle router contract address
market_contractstringNoPendle market contract address
pool_contractstringNoPool contract address
vault_contractstringNoVault contract address
contractstringNoGeneral contract address
methodstringNoContract method name
call_paramsobjectNoAdditional call parameters
Was this helpful?