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.