Set up the Exponent SDK and walk through the complete Core lifecycle, from stripping yield assets into PT and YT, to collecting yield, and merging back.
Installation
yarn add @exponent-labs/exponent-sdk
Setup
import { Vault, YtPosition, LOCAL_ENV } from "@exponent-labs/exponent-sdk";
import {
Connection,
PublicKey,
Transaction,
sendAndConfirmTransaction,
Keypair,
} from "@solana/web3.js";
const connection = new Connection("https://api.mainnet-beta.solana.com");
const wallet = Keypair.fromSecretKey(/* your keypair */);
const vaultAddress = new PublicKey("...");
const vault = await Vault.load(LOCAL_ENV, connection, vaultAddress);
1. Initialize a Yield Position
Before stripping, you need to create a YieldTokenPosition account for your wallet. This is a one-time setup per vault.
YT is just an SPL token — the protocol can’t track yield for tokens sitting in your wallet. The YieldTokenPosition account escrows your YT and records the SY exchange rate at entry, which is needed to compute your earned yield. ixStripFromBase automatically deposits YT into this position, so it must exist before you strip.
const initIx = vault.ixInitializeYieldPosition({
owner: wallet.publicKey,
});
const tx = new Transaction().add(initIx);
await sendAndConfirmTransaction(connection, tx, [wallet]);
2. Strip Base Tokens into PT and YT
Use ixStripFromBase to convert a base asset (e.g., USDC) directly into PT and YT. This wraps the base into SY, strips it into PT and YT, and deposits the YT into your yield position — all in a single atomic instruction. Your position begins accruing interest and emissions immediately.
const ix = await vault.ixStripFromBase({
owner: wallet.publicKey,
amountBase: 1_000_000n, // e.g., 1 USDC (6 decimals)
});
const tx = new Transaction().add(ix);
await sendAndConfirmTransaction(connection, tx, [wallet]);
const ytPosition = await YtPosition.loadByOwner(
LOCAL_ENV,
connection,
wallet.publicKey,
vault,
);
If you already hold SY tokens, use vault.ixStrip() instead — it skips the base-to-SY wrapping step but does not auto-deposit YT. You would then need to call ytPosition.ixDepositYt() separately.
3. Stage Yield
Before collecting, you need to stage yield. This computes your earned interest and emissions based on the current SY exchange rate.
const stageIx = ytPosition.ixStageYield({
payer: wallet.publicKey,
});
const tx = new Transaction().add(stageIx);
await sendAndConfirmTransaction(connection, tx, [wallet]);
4. Collect Interest
After staging, collect your earned interest (paid in SY tokens).
const collectIx = ytPosition.ixCollectInterest({
signer: wallet.publicKey,
});
const tx = new Transaction().add(collectIx);
await sendAndConfirmTransaction(connection, tx, [wallet]);
5. Withdraw YT
Before merging, withdraw your YT from the yield position back to your wallet. The merge instruction burns YT directly from your token account.
const withdrawIx = ytPosition.ixWithdrawYt({
amount: 1_000_000n, // amount of YT to withdraw
});
const tx = new Transaction().add(withdrawIx);
await sendAndConfirmTransaction(connection, tx, [wallet]);
6. Merge PT and YT Back to Base
When you’re ready to exit, merge your PT and YT back into the base asset.
const { ixs, setupIxs } = await vault.ixMergeToBase({
owner: wallet.publicKey,
amountPy: 1_000_000n, // amount of PT & YT to merge
});
const tx = new Transaction().add(...setupIxs, ...ixs);
await sendAndConfirmTransaction(connection, tx, [wallet]);
Reading State
Query vault and position state without sending transactions:
// Current SY exchange rate
const rate = vault.currentSyExchangeRate;
// Vault expiration
const expiresAt = vault.expirationDate;
// Claimable interest (in base token units)
const claimable = ytPosition.getClaimableInterest(rate);
// Claimable emissions
const emissions = ytPosition.getClaimableEmissions();
Next Steps