Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.exponent.finance/llms.txt

Use this file to discover all available pages before exploring further.

Use these instructions when your strategy vault should deposit underlying tokens into Jupiter Lend Earn jlToken vaults. For Jupiter’s collateralized borrowing product, see Jupiter Lend Borrow instructions. Jupiter Earn exposes eight on-chain operations split into two account groups:
  • Asset-in (deposit / mint variants) — vault sends the underlying token, receives jlTokens.
  • Asset-out (withdraw / redeem variants) — vault sends jlTokens, receives the underlying token.
The SDK provides one raw createJupiterEarn*Instruction(...) per op and matching jupiterEarnAction.<method>(...) wrappers that register the op as a vault step.

Transaction structure

Every Jupiter Earn action goes through createVaultSyncTransaction.
import {
  createVaultSyncTransaction,
  createJupiterEarnDepositInstruction,
  jupiterEarnAction,
} from "@exponent-labs/exponent-sdk";
import { Transaction, sendAndConfirmTransaction } from "@solana/web3.js";

const depositIx = createJupiterEarnDepositInstruction(assetInAccounts, 50_000_000n);

const { setupInstructions, preInstructions, instruction, postInstructions } =
  await createVaultSyncTransaction({
    instructions: [
      jupiterEarnAction.deposit({ instruction: depositIx }),
    ],
    owner: vaultPda,
    connection,
    policyPda,
    vaultPda,
    signer: wallet.publicKey,
    vaultAddress,
  });

const tx = new Transaction().add(
  ...setupInstructions,
  ...preInstructions,
  instruction,
  ...postInstructions,
);
await sendAndConfirmTransaction(connection, tx, [wallet]);
PartWhat it contains
setupInstructionsSetup instructions that must run before refreshes or the sync step
preInstructionsPermissionless refresh instructions that must run before the sync step
instructionThe Squads sync transaction instruction wrapping the vault-signed Jupiter Earn action
postInstructionsPermissionless refresh instructions that must run after the sync step

Asset-in accounts

All four asset-in operations (deposit, depositWithMinAmountOut, mint, mintWithMaxAssets) share the same JupiterEarnAssetInAccounts shape. Build it once and pass it into each instruction builder.
import type { JupiterEarnAssetInAccounts } from "@exponent-labs/exponent-sdk";
import { TOKEN_PROGRAM_ID } from "@solana/spl-token";

const assetInAccounts: JupiterEarnAssetInAccounts = {
  signer: vaultPda,                          // Squads vault PDA — the trader signing through the policy
  depositorTokenAccount: vaultUnderlyingAta, // Vault's underlying token ATA (e.g., USDC)
  recipientTokenAccount: vaultJlTokenAta,    // Vault's jlToken ATA (will receive the receipt)
  mint: USDC_MINT,                           // Underlying token mint
  lendingAdmin: JUPITER_LENDING_ADMIN,
  lending: JUPITER_EARN_USDC_LENDING_ID,
  fTokenMint: JUPITER_EARN_USDC_JL_TOKEN_MINT_ID,
  supplyTokenReservesLiquidity: JUPITER_LEND_SUPPLY_TOKEN_RESERVES_LIQUIDITY_ID,
  lendingSupplyPositionOnLiquidity: JUPITER_LEND_LENDING_SUPPLY_POSITION_ON_LIQUIDITY_ID,
  rateModel: JUPITER_LEND_RATE_MODEL_ID,
  vault: JUPITER_LEND_VAULT_ID,
  liquidity: JUPITER_LEND_LIQUIDITY_ID,
  liquidityProgram: JUPITER_LENDING_POOLS_PROGRAM_ID,
  rewardsRateModel: JUPITER_LEND_REWARDS_RATE_MODEL_ID,
  tokenProgram: TOKEN_PROGRAM_ID,
};
buildJupiterLendPriceInterfaceAccounts(accounts) returns the price-interface AccountMeta[] Jupiter expects for downstream price reads, derived from the same accounts struct.

Deposit

createJupiterEarnDepositInstruction(accounts, assets) deposits an exact amount of underlying tokens and receives jlTokens at the current rate. createJupiterEarnDepositWithMinAmountOutInstruction(accounts, assets, minAmountOut) is the same operation with a slippage floor on the jlTokens received.
import {
  createJupiterEarnDepositInstruction,
  createJupiterEarnDepositWithMinAmountOutInstruction,
  jupiterEarnAction,
} from "@exponent-labs/exponent-sdk";

// Plain deposit
const depositIx = createJupiterEarnDepositInstruction(assetInAccounts, 50_000_000n);

// Deposit with slippage floor
const depositMinIx = createJupiterEarnDepositWithMinAmountOutInstruction(
  assetInAccounts,
  50_000_000n,   // assets to deposit
  49_500_000n,   // minimum jlTokens to receive
);

// Wrap as a vault step
jupiterEarnAction.deposit({ instruction: depositIx });
jupiterEarnAction.depositWithMinAmountOut({ instruction: depositMinIx });

Parameters

NameTypeDescription
accountsJupiterEarnAssetInAccountsAsset-in account set
assetsbigint | number | string | BNUnderlying token amount in atomic units
minAmountOutbigint | number | string | BNWith-min variant only. Minimum jlTokens to receive — slippage floor

Mint

createJupiterEarnMintInstruction(accounts, shares) mints an exact amount of jlTokens, paying the current required underlying. createJupiterEarnMintWithMaxAssetsInstruction(accounts, shares, maxAssets) adds a cap on the underlying spent.
import {
  createJupiterEarnMintInstruction,
  createJupiterEarnMintWithMaxAssetsInstruction,
  jupiterEarnAction,
} from "@exponent-labs/exponent-sdk";

const mintIx = createJupiterEarnMintInstruction(assetInAccounts, 5_000_000n);

const mintMaxIx = createJupiterEarnMintWithMaxAssetsInstruction(
  assetInAccounts,
  5_000_000n,    // jlTokens to mint
  5_100_000n,    // maximum underlying to spend
);

jupiterEarnAction.mint({ instruction: mintIx });
jupiterEarnAction.mintWithMaxAssets({ instruction: mintMaxIx });

Parameters

NameTypeDescription
accountsJupiterEarnAssetInAccountsAsset-in account set
sharesbigint | number | string | BNjlToken amount to mint, in atomic units
maxAssetsbigint | number | string | BNWith-max variant only. Maximum underlying spend cap

Asset-out accounts

The four asset-out operations (withdraw, withdrawWithMaxSharesBurn, redeem, redeemWithMinAmountOut) share JupiterEarnAssetOutAccounts. The shape mirrors asset-in, with the source/recipient roles flipped.
import type { JupiterEarnAssetOutAccounts } from "@exponent-labs/exponent-sdk";

const assetOutAccounts: JupiterEarnAssetOutAccounts = {
  signer: vaultPda,                          // Squads vault PDA
  ownerTokenAccount: vaultJlTokenAta,        // Vault's jlToken ATA — the source
  recipientTokenAccount: vaultUnderlyingAta, // Vault's underlying ATA — receives the unwound underlying
  lendingAdmin: JUPITER_LENDING_ADMIN,
  lending: JUPITER_EARN_USDC_LENDING_ID,
  mint: USDC_MINT,
  fTokenMint: JUPITER_EARN_USDC_JL_TOKEN_MINT_ID,
  supplyTokenReservesLiquidity: JUPITER_LEND_SUPPLY_TOKEN_RESERVES_LIQUIDITY_ID,
  lendingSupplyPositionOnLiquidity: JUPITER_LEND_LENDING_SUPPLY_POSITION_ON_LIQUIDITY_ID,
  rateModel: JUPITER_LEND_RATE_MODEL_ID,
  vault: JUPITER_LEND_VAULT_ID,
  liquidity: JUPITER_LEND_LIQUIDITY_ID,
  liquidityProgram: JUPITER_LENDING_POOLS_PROGRAM_ID,
  rewardsRateModel: JUPITER_LEND_REWARDS_RATE_MODEL_ID,
  claimAccount: JUPITER_CLAIM_ACCOUNT,
  tokenProgram: TOKEN_PROGRAM_ID,
};

Withdraw

createJupiterEarnWithdrawInstruction(accounts, amount) withdraws an exact amount of underlying by burning the implied jlTokens at the current rate. createJupiterEarnWithdrawWithMaxSharesBurnInstruction(accounts, amount, maxSharesBurn) adds a cap on the jlTokens burned.
import {
  createJupiterEarnWithdrawInstruction,
  createJupiterEarnWithdrawWithMaxSharesBurnInstruction,
  jupiterEarnAction,
} from "@exponent-labs/exponent-sdk";

const withdrawIx = createJupiterEarnWithdrawInstruction(assetOutAccounts, 25_000_000n);

const withdrawMaxIx = createJupiterEarnWithdrawWithMaxSharesBurnInstruction(
  assetOutAccounts,
  25_000_000n,   // underlying to withdraw
  26_000_000n,   // maximum jlTokens to burn
);

jupiterEarnAction.withdraw({ instruction: withdrawIx });
jupiterEarnAction.withdrawWithMaxSharesBurn({ instruction: withdrawMaxIx });

Parameters

NameTypeDescription
accountsJupiterEarnAssetOutAccountsAsset-out account set
amountbigint | number | string | BNUnderlying amount to withdraw, in atomic units
maxSharesBurnbigint | number | string | BNWith-max variant only. Maximum jlTokens burn cap

Redeem

createJupiterEarnRedeemInstruction(accounts, shares) redeems an exact amount of jlTokens for underlying at the current rate. createJupiterEarnRedeemWithMinAmountOutInstruction(accounts, shares, minAmountOut) adds a slippage floor on the underlying received.
import {
  createJupiterEarnRedeemInstruction,
  createJupiterEarnRedeemWithMinAmountOutInstruction,
  jupiterEarnAction,
} from "@exponent-labs/exponent-sdk";

const redeemIx = createJupiterEarnRedeemInstruction(assetOutAccounts, 5_000_000n);

const redeemMinIx = createJupiterEarnRedeemWithMinAmountOutInstruction(
  assetOutAccounts,
  5_000_000n,    // jlTokens to redeem
  4_950_000n,    // minimum underlying to receive
);

jupiterEarnAction.redeem({ instruction: redeemIx });
jupiterEarnAction.redeemWithMinAmountOut({ instruction: redeemMinIx });

Parameters

NameTypeDescription
accountsJupiterEarnAssetOutAccountsAsset-out account set
sharesbigint | number | string | BNjlTokens to redeem, in atomic units
minAmountOutbigint | number | string | BNWith-min variant only. Minimum underlying floor

Action wrappers

Every Earn op has a matching jupiterEarnAction.<method> that registers the raw instruction as a vault step. All wrappers take a single { instruction } object.
WrapperPairs with
jupiterEarnAction.depositcreateJupiterEarnDepositInstruction
jupiterEarnAction.depositWithMinAmountOutcreateJupiterEarnDepositWithMinAmountOutInstruction
jupiterEarnAction.mintcreateJupiterEarnMintInstruction
jupiterEarnAction.mintWithMaxAssetscreateJupiterEarnMintWithMaxAssetsInstruction
jupiterEarnAction.withdrawcreateJupiterEarnWithdrawInstruction
jupiterEarnAction.withdrawWithMaxSharesBurncreateJupiterEarnWithdrawWithMaxSharesBurnInstruction
jupiterEarnAction.redeemcreateJupiterEarnRedeemInstruction
jupiterEarnAction.redeemWithMinAmountOutcreateJupiterEarnRedeemWithMinAmountOutInstruction

Constants

ConstantDescription
JUPITER_LEND_EARN_PROGRAM_IDJupiter Lend Earn program: jup3YeL8QhtSx1e253b2FDvsMNC87fDrgQZivbrndc9
For policy authoring or custom data-constraint work, the SDK also exports JUPITER_EARN_DISCRIMINATORS (per-action discriminators) and JUPITER_EARN_ACCOUNT_INDICES (account-index maps for asset-in and asset-out paths). A matching policy must exist before executing. See Jupiter Lend Earn Policy.

Full flow example

This example deposits underlying into a Jupiter Earn vault, then unwinds with a redeem.
import {
  createVaultSyncTransaction,
  createJupiterEarnDepositInstruction,
  createJupiterEarnRedeemInstruction,
  jupiterEarnAction,
} from "@exponent-labs/exponent-sdk";
import { Transaction, sendAndConfirmTransaction } from "@solana/web3.js";

// Step 1: Deposit 50 USDC into the jlUSDC vault.
{
  const depositIx = createJupiterEarnDepositInstruction(assetInAccounts, 50_000_000n);
  const { setupInstructions, preInstructions, instruction, postInstructions } =
    await createVaultSyncTransaction({
      instructions: [jupiterEarnAction.deposit({ instruction: depositIx })],
      owner: vaultPda,
      connection,
      policyPda,
      vaultPda,
      signer: wallet.publicKey,
      vaultAddress,
    });
  const tx = new Transaction().add(
    ...setupInstructions,
    ...preInstructions,
    instruction,
    ...postInstructions,
  );
  await sendAndConfirmTransaction(connection, tx, [wallet]);
}

// Step 2: Redeem 5 jlUSDC back to underlying.
{
  const redeemIx = createJupiterEarnRedeemInstruction(assetOutAccounts, 5_000_000n);
  const { setupInstructions, preInstructions, instruction, postInstructions } =
    await createVaultSyncTransaction({
      instructions: [jupiterEarnAction.redeem({ instruction: redeemIx })],
      owner: vaultPda,
      connection,
      policyPda,
      vaultPda,
      signer: wallet.publicKey,
      vaultAddress,
    });
  const tx = new Transaction().add(
    ...setupInstructions,
    ...preInstructions,
    instruction,
    ...postInstructions,
  );
  await sendAndConfirmTransaction(connection, tx, [wallet]);
}