How do I mint and redeem JupUSD?

This documentation explains how to mint and redeem JupUSD through the underlying Solana program.

It covers three supported integration methods: the TypeScript SDK for developers, a web-based UI for manual operations, and a Web API for direct service integrations.

Choose the approach that best fits your operational and technical requirements.

SDK

Developers can easily integrate JupUSD functionality into their applications using the provided TypeScript SDK. For those preferring other languages, an IDL is also available: https://solscan.io/account/JUPUSDecMzAVgztLe6eGhwUBj1Pn3j9WAXwmtHmfbRr#programIdl 

Note
The Mint & Redeem Solana program is source-available under the BSL licence. Take a look at the code in order to better understand how it works: https://github.com/jup-ag/jupusd-program/tree/main/programs/jup-stable 

Installation

The SDK is available under the npm package ‘jup-stable-sdk’. You can install it with your favorite node package manager: 

npm install '@jup-ag/jup-usd-sdk'
yarn install '@jup-ag/jup-usd-sdk'
pnpm install '@jup-ag/jup-usd-sdk'

Alternatively, you can install it using the GitHub repo available here: https://github.com/jup-ag/jupusd-program/tree/main/packages/sdk 

Mint

To mint JupUSD, you must invoke the Mint instruction of our Solana Program. This instruction:

  • Transfers the selected collateral from your wallet to the JupUSD custodian
  • Mints newly issued JupUSD tokens to the provided token account

Below is a reference implementation demonstrating how to construct a mint instruction.

Important Parameters

When building the mint instruction, pay close attention to the following parameters:

  • amountIn
    The amount of collateral you want to deposit.
  • minAmountOut
    The minimum amount of JupUSD you are willing to receive.
    If the minted amount is below this value, the transaction will fail with the error: SlippageToleranceExceeded

To mint JupUSD using the SDK, you will need to call the Mint instruction. This instruction will transfer collateral from your wallet to the JupUSD custodian and mint brand new JupUSD. 

You can use the following code as a reference on how to implement a mint transaction.

Oracle Accounts Requirements

Each vault requires a specific set of oracle accounts:

  • Always include all non-empty oracle accounts
  • Preserve the exact order in which the oracles are stored on the vault
  • Passing incorrect or incomplete oracle accounts will cause the transaction to fail

Rate Limiting

If you encounter repeated rate-limit errors: wait for the current rate-limit window to reset, or reach out to us to request higher limits. 

Example: Creating a Mint Instruction

import { AccountRole, address } from "@solana/kit";

import {
  findConfig,
  fetchVault,
  fetchConfig,
  findVault,
  getMintInstructionAsync,
  JUP_STABLE_PROGRAM_ADDRESS,
} from "jup-stable-sdk";

import { findAssociatedTokenPda } from "@solana-program/token";

// ⚠️ Wallet must be whitelisted
const userSigner = /* your wallet signer */;
const feePayerSigner = userSigner;

// --- Derive program accounts ---
// Config PDA
const configAddress = await findConfig();
const configAccount = await fetchConfig(rpc, configAddress);

// Vault PDA (derived from collateral mint, e.g. USDC)
const vaultAddress = await findVault(USDC);
const vaultAccount = await fetchVault(rpc, vaultAddress);

// --- Collect required oracle accounts ---
const remainingAccounts = vaultAccount.data.oracles
  .filter((oracle) => oracle.__kind !== "Empty")
  .map((oracle) => ({
    role: AccountRole.READONLY,
    address: address(oracle.fields[0].account),
  }));

// --- Mint instruction (deposit collateral → receive JupUSD) ---
const mintIx = await getMintInstructionAsync({
  user: userSigner,
  userCollateralTokenAccount,
  userLpTokenAccount,
  config: configAddress,
  authority: configAccount.data.authority,
  lpMint: configAccount.data.mint,
  vault: vaultAddress,
  vaultMint: configAccount.data.mint,
  custodian: vaultAccount.data.custodian,
  custodianTokenAccount: await findAssociatedTokenPda({
    mint: vaultAccount.data.mint,
    owner: vaultAccount.data.custodian,
    tokenProgram: vaultAccount.data.token_program,
  }),
  benefactor: benefactorAddress,
  lpTokenProgram: configAccount.data.tokenProgram,
  vaultTokenProgram: configAccount.data.tokenProgram,
  program: JUP_STABLE_PROGRAM_ADDRESS,
  amount: amountIn, // Collateral amount
  minAmountOut, // Slippage protection
});

// Append oracle accounts in the correct order
mintIx.accounts.push(...remainingAccounts);

Redeem

To redeem JupUSD, you must invoke the Redeem instruction of our Solana Program. This instruction:

  • Burns JupUSD from your token account
  • Withdraws the corresponding collateral from the vault back to your wallet

The example below shows how to construct a redeem instruction and include all required accounts.

Important Parameters

When building the redeem instruction, the following parameters are critical:

  • amountIn
    The amount of JupUSD you want to redeem (burn).
  • minAmountOut
    The minimum amount of collateral you are willing to receive.
    If the amount returned is below this value, the transaction will fail with: SlippageToleranceExceeded
import { AccountRole, address } from "@solana/kit";

import {
  findConfig,
  fetchVault,
  fetchConfig,
  findVault,
  getRedeemInstructionAsync,
  JUP_STABLE_PROGRAM_ADDRESS,
} from "jup-stable-sdk";

// ⚠️ Wallet must be whitelisted
const userSigner = /* your wallet signer */;
const feePayerSigner = userSigner;

// --- Derive program accounts ---
// Config PDA
const configAddress = await findConfig();
const configAccount = await fetchConfig(rpc, configAddress);

// Vault PDA (derived from collateral mint, e.g. USDC)
const vaultAddress = await findVault(USDC);
const vaultAccount = await fetchVault(rpc, vaultAddress);

// --- Collect required oracle accounts ---
const remainingAccounts = vaultAccount.data.oracles
  .filter((oracle) => oracle.__kind !== "Empty")
  .map((oracle) => ({
    role: AccountRole.READONLY,
    address: address(oracle.fields[0].account),
  }));

// --- Redeem instruction (burn JupUSD → receive collateral) ---
const redeemIx = await getRedeemInstructionAsync({
  user: userSigner,
  userLpTokenAccount, // JupUSD token account
  userCollateralTokenAccount, // Destination collateral account
  config: configAddress,
  authority: configAccount.data.authority,
  lpMint: configAccount.data.mint,
  vault: vaultAddress,
  vaultTokenAccount, // Vault collateral token account
  vaultMint: vaultAccount.data.mint,
  benefactor: benefactorAddress,
  lpTokenProgram: configAccount.data.tokenProgram,
  vaultTokenProgram: configAccount.data.tokenProgram,
  program: JUP_STABLE_PROGRAM_ADDRESS,
  amount: amountIn, // Amount of JupUSD to burn
  minAmountOut, // Slippage protection
});

// Append oracle accounts in the correct order
redeemIx.accounts.push(...remainingAccounts);

Errors

Error Code When it happens How to fix
InvalidLPMint / InvalidVaultMint The JupUSD or vault’s mint account does not match what is stored in the config or vault state. Fetch the config and vault onchain accounts and pass the exact mint accounts recorded there.
InvalidAuthority The authority PDA passed does not match the authority stored in the config. Pass the correct authority account stored in the config account.
InvalidVaultTokenAccount The vault (custodian) token account does not match the vault state. Pass the vault or custodian token account recorded on the vault.
InvalidCustodian The custodian account does not match the vault’s configured custodian. Use the custodian pubkey stored on the vault account.
BenefactorDisabled The benefactor is currently disabled. Your benefactor account is disabled. This means you are correctly whitelisted but are not currently approved to mint, or your access has been disabled.
VaultDisabled The vault is not enabled for minting or redeeming. Wait for operators/admins to enable the vault.
ProtocolPaused Global mint/redeem operations are paused in the config. Wait for protocol admins to re-enable mint/redeem.
MintLimitExceeded / RedeemLimitExceeded A per-window rate limit was exceeded (config, vault, or benefactor level). Retry after the rate-limit window resets, or request higher limits from admins.
ZeroAmount The input amount is zero, or the computed mint/redeem output rounds to zero. Submit a non-zero amount and ensure it is large enough after fees.
SlippageToleranceExceeded The computed output amount is lower than min_amount_out. Lower min_amount_out or retry when pricing moves in your favor.
PriceConfidenceTooWide Oracle confidence intervals or spread across oracles is too wide. Retry once oracle confidence tightens; verify correct oracle accounts were supplied.
NoValidPrice No oracle price passed validation after filtering. Check oracle health and retry once price feeds are reporting valid data.
MathOverflow An arithmetic overflow occurred during price or amount calculation. This should never happen. If it does reach out to us.
VaultIsDry A redeem request exceeds the vault’s available collateral balance. The program vault balance is too low to execute the redeem instruction. Please wait for the vault to be replenished or reach out to us.

UI

The JupUSD User Interface provides a simple, graphical way for users to interact with the protocol without writing code. It can be found at the following URL: https://jupusd.money/mint.

Please make sure you were correctly onboarded before using our UI. If you see the following warning, it means you are either using the wrong wallet address or that there was an issue during the onboarding process. 

Mint

The Mint page within the UI allows users to input the desired amount of JupUSD and select the collateral asset. A step-by-step process is followed to complete the minting. 

  • Step 1: Connect your Solana wallet (e.g., Jupiter Wallet, Phantom, Solflare).
  • Step 2: Enter the desired USDC amount to provide as collateral. The UI will compute a quote and display the expected amount of JupUSD you will receive.
  • Step 3: Click the "Approve & Mint" button. Your wallet will prompt you to confirm the transaction.
  • Step 4: Confirm the transaction in your wallet. A transaction receipt link will be provided.

Redeem

The Redeem page is used to burn JupUSD and retrieve the corresponding collateral. 

  • Step 1: Ensure your wallet is connected.
  • Step 2: Navigate to the "Redeem" tab.
  • Step 3: Enter the amount of JupUSD you wish to burn. The UI will calculate the expected collateral return.
  • Step 4: Click the "Redeem" button.
  • Step 5: Approve the transaction in your wallet. Confirmation of the redemption will appear, along with a link to the transaction on the explorer.