Skip to main content
The core instructions module enables vault managers and allocators to strip base tokens (e.g., LSTs) into PT (Principal Tokens) and YT (Yield Tokens), and merge them back. All interactions are executed as Squads sync transactions validated against onchain policies. For background on how stripping and merging works, see Core Concepts.

Transaction Structure

Every core interaction goes through createVaultSyncTransaction, which returns three parts:
const { preInstructions, instruction, postInstructions } =
  await createVaultSyncTransaction({
    instructions,   // Array of VaultInstruction descriptors
    owner,          // Vault PDA (the Squads smart account)
    connection,
    policyPda,      // Policy authorizing this execution
    vaultPda,       // Squads vault PDA
    signer,         // The allocator or manager wallet
    vaultAddress,   // ExponentStrategyVault PDA (auto-resolves hook accounts)
  });

// Send all three parts in order
const tx = new Transaction().add(...preInstructions, instruction, ...postInstructions);
await sendAndConfirmTransaction(connection, tx, [wallet]);
PartWhat it containsWhy it’s separate
preInstructionsAny permissionless setup instructionsMust be top-level instructions
instructionSquads sync transaction wrapping all vault-signed instructionsExecutes with the vault’s smart account as signer
postInstructionsAny post-operation instructionsMust be top-level instructions

Initialize Yield Position

Before the vault can strip or merge tokens, a yield position account must exist on the Exponent Core program. coreAction.initializeYieldPosition creates this account.
Orderbook and CLMM operations automatically initialize the yield position if it doesn’t exist. You only need to call this manually if strip or merge is your first Core interaction for a given vault.
import {
  coreAction,
  createVaultSyncTransaction,
} from "@exponent-labs/exponent-sdk";

const { preInstructions, instruction, postInstructions } =
  await createVaultSyncTransaction({
    instructions: [
      coreAction.initializeYieldPosition({
        vault: new PublicKey("..."),       // Exponent Core vault address
      }),
    ],
    owner: vaultPda,
    connection,
    policyPda,
    vaultPda,
    signer: wallet.publicKey,
    vaultAddress,
  });

const tx = new Transaction().add(...preInstructions, instruction, ...postInstructions);
await sendAndConfirmTransaction(connection, tx, [wallet]);

Parameters

ParameterTypeDescription
vaultPublicKeyThe Exponent Core vault address (the yield-stripping vault, not the strategy vault)
A matching policy must exist before executing. See Policy Builders.

Strip

coreAction.strip strips a base token (e.g., an LST like JitoSOL) into equal amounts of PT and YT through the Exponent Core program.
import {
  coreAction,
  createVaultSyncTransaction,
} from "@exponent-labs/exponent-sdk";

const { preInstructions, instruction, postInstructions } =
  await createVaultSyncTransaction({
    instructions: [
      coreAction.strip({
        vault: new PublicKey("..."),       // Exponent Core vault address
        amountBase: 1_000_000_000n,       // 1 token in native units
      }),
    ],
    owner: vaultPda,
    connection,
    policyPda,
    vaultPda,
    signer: wallet.publicKey,
    vaultAddress,
  });

const tx = new Transaction().add(...preInstructions, instruction, ...postInstructions);
await sendAndConfirmTransaction(connection, tx, [wallet]);

Parameters

ParameterTypeDescription
vaultPublicKeyThe Exponent Core vault address (the yield-stripping vault, not the strategy vault)
amountBasebigintAmount of base token to strip, in native units
A matching policy must exist before executing. See Policy Builders.

Merge

coreAction.merge merges equal amounts of PT and YT back into the base token.
const { preInstructions, instruction, postInstructions } =
  await createVaultSyncTransaction({
    instructions: [
      coreAction.merge({
        vault: new PublicKey("..."),
        amountPy: 1_000_000_000n,       // Must hold equal PT and YT
      }),
    ],
    owner: vaultPda,
    connection,
    policyPda,
    vaultPda,
    signer: wallet.publicKey,
    vaultAddress,
  });

const tx = new Transaction().add(...preInstructions, instruction, ...postInstructions);
await sendAndConfirmTransaction(connection, tx, [wallet]);

Parameters

ParameterTypeDescription
vaultPublicKeyThe Exponent Core vault address
amountPybigintAmount of PT/YT to merge — must hold equal amounts of both
The merge operation requires the vault to hold equal amounts of PT and YT. If the vault holds 100 PT and 80 YT, you can merge at most 80.
A matching policy must exist before executing. See Policy Builders.

Full Flow Example

This example demonstrates stripping a base token into PT + YT, then merging them back.

Step 1: Strip Base Token into PT + YT

import {
  coreAction,
  createVaultSyncTransaction,
} from "@exponent-labs/exponent-sdk";
import { Connection, PublicKey, Transaction, sendAndConfirmTransaction } from "@solana/web3.js";

const connection = new Connection("https://api.mainnet-beta.solana.com");

const EXPONENT_VAULT = new PublicKey("..."); // Exponent Core vault

const { preInstructions, instruction, postInstructions } =
  await createVaultSyncTransaction({
    instructions: [
      coreAction.strip({
        vault: EXPONENT_VAULT,
        amountBase: 2_000_000_000n,   // 2 tokens
      }),
    ],
    owner: vaultPda,
    connection,
    policyPda,
    vaultPda,
    signer: wallet.publicKey,
    vaultAddress,
  });

const tx = new Transaction().add(...preInstructions, instruction, ...postInstructions);
await sendAndConfirmTransaction(connection, tx, [wallet]);

Step 2: Merge PT + YT Back to Base Token

const { preInstructions, instruction, postInstructions } =
  await createVaultSyncTransaction({
    instructions: [
      coreAction.merge({
        vault: EXPONENT_VAULT,
        amountPy: 2_000_000_000n,
      }),
    ],
    owner: vaultPda,
    connection,
    policyPda,
    vaultPda,
    signer: wallet.publicKey,
    vaultAddress,
  });

const tx = new Transaction().add(...preInstructions, instruction, ...postInstructions);
await sendAndConfirmTransaction(connection, tx, [wallet]);