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]);
| Part | What it contains |
|---|
setupInstructions | Setup instructions that must run before refreshes or the sync step |
preInstructions | Permissionless refresh instructions that must run before the sync step |
instruction | The Squads sync transaction instruction wrapping the vault-signed Jupiter Earn action |
postInstructions | Permissionless 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
| Name | Type | Description |
|---|
accounts | JupiterEarnAssetInAccounts | Asset-in account set |
assets | bigint | number | string | BN | Underlying token amount in atomic units |
minAmountOut | bigint | number | string | BN | With-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
| Name | Type | Description |
|---|
accounts | JupiterEarnAssetInAccounts | Asset-in account set |
shares | bigint | number | string | BN | jlToken amount to mint, in atomic units |
maxAssets | bigint | number | string | BN | With-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
| Name | Type | Description |
|---|
accounts | JupiterEarnAssetOutAccounts | Asset-out account set |
amount | bigint | number | string | BN | Underlying amount to withdraw, in atomic units |
maxSharesBurn | bigint | number | string | BN | With-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
| Name | Type | Description |
|---|
accounts | JupiterEarnAssetOutAccounts | Asset-out account set |
shares | bigint | number | string | BN | jlTokens to redeem, in atomic units |
minAmountOut | bigint | number | string | BN | With-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.
| Wrapper | Pairs with |
|---|
jupiterEarnAction.deposit | createJupiterEarnDepositInstruction |
jupiterEarnAction.depositWithMinAmountOut | createJupiterEarnDepositWithMinAmountOutInstruction |
jupiterEarnAction.mint | createJupiterEarnMintInstruction |
jupiterEarnAction.mintWithMaxAssets | createJupiterEarnMintWithMaxAssetsInstruction |
jupiterEarnAction.withdraw | createJupiterEarnWithdrawInstruction |
jupiterEarnAction.withdrawWithMaxSharesBurn | createJupiterEarnWithdrawWithMaxSharesBurnInstruction |
jupiterEarnAction.redeem | createJupiterEarnRedeemInstruction |
jupiterEarnAction.redeemWithMinAmountOut | createJupiterEarnRedeemWithMinAmountOutInstruction |
Constants
| Constant | Description |
|---|
JUPITER_LEND_EARN_PROGRAM_ID | Jupiter 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]);
}