Deposit USDC into a PRISM tranche (Prime, Core, or Alpha) and receive tranche tokens at the current NAV. Includes withdraw, AMM exit, and strategy presets.
Each PRISM vault is partitioned into three tranches with different risk profiles. Investors choose a tranche, deposit USDC, and receive tranche tokens (pPRIME, pCORE, or pALPHA) at the current NAV. Yield accrues by lifting NAV; credit losses absorb in reverse priority by lowering the junior tranche’s NAV first.
Choose by risk tolerance, not nominal yield. A 15% APY target on Alpha only realizes if the underlying credit performs; if it doesn’t, Alpha takes the entire loss before any other tranche is touched.
Deposits push USDC into the reserve and credit the chosen tranche. Withdrawals pull USDC out and decrement that tranche. Yield events increase one or more tranche balances. Loss events move USDC out of the reserve into a loss bucket account so the invariant always holds.This means every deposit you make grows exactly one tranche’s total_assets, and your tranche tokens represent a proportional claim on that tranche’s slice of the reserve.
Before invoking deposit, verify four conditions client-side. The on-chain handler enforces all of them — your transaction reverts with a typed PrismError if any fails — but failing fast on the client gives a better UX:
Requirement
How to verify
Vault state is Active
vault.state enum equals { active: {} }
Protocol not paused
config.paused === false
Tranche not wiped
tranche.navPerShareQ > 0n (or tranche.totalSupply === 0n for first deposit)
User has enough USDC
userUsdcAta.amount >= amount
import { getConfigPda, getTranchePda, getVaultPda, TrancheKind } from 'prismprotocol-sdk';const [config] = getConfigPda();const [vault] = getVaultPda(0);const [tranchePda] = getTranchePda(vault, TrancheKind.Prime);const [configAcc, vaultAcc, trancheAcc] = await Promise.all([ core.account.globalConfig.fetch(config), core.account.vault.fetch(vault), core.account.tranche.fetch(tranchePda),]);if (configAcc.paused) throw new Error('Protocol is paused');if (!('active' in vaultAcc.state)) throw new Error('Vault is not Active');const supply = BigInt(trancheAcc.totalSupply.toString());const navQ = BigInt(trancheAcc.navPerShareQ.toString());if (supply > 0n && navQ === 0n) { throw new Error('Tranche has been wiped — deposits blocked');}
The init_if_needed constraint on the userTrancheAta account means a brand-new user — one who has never held this tranche — does not need a separate ATA-creation transaction. The deposit creates the ATA in the same instruction.
PRISM uses NAV-per-share accounting in Q64.64 fixed-point math. On deposit:
shares_minted = first deposit? → usdc_amount (1:1 at NAV = 1.0) otherwise → usdc_amount × Q64_ONE / nav_per_share_q
The handler atomically:
Validates pre-flight conditions (vault active, not paused, tranche not wiped).
Computes shares_minted using the formula above.
Transfers usdc_amount from your USDC ATA to the vault reserve.
Mints shares_minted of the tranche token to your tranche ATA.
Updates tranche.total_assets and tranche.total_supply.
Recomputes tranche.nav_per_share_q from the updated assets and supply.
Updates tranche.last_nav_update_ts to the current Solana clock.
NAV is unchanged after a deposit — the numerator and denominator increase proportionally. Yield events are what move NAV up; credit events are what move it down.
User A and B’s tokens are now worth more (NAV 1.10), but no new tokens were minted to them. User C entered at the higher NAV and got proportionally fewer tokens. NAV stays at 1.10 after C’s deposit.
Payout = shares × nav_per_share_q / Q64_ONE. After a credit event, NAV may be lower than at deposit — withdraw still settles at current NAV. After Alpha is wiped, an Alpha withdrawal returns 0 USDC; the burn still succeeds.
If the vault reserve does not have enough USDC to cover your withdrawal — for example, after capital has been disbursed to a borrower and not yet repaid — the transaction reverts with InsufficientLiquidity. Two recovery paths:
Wait and retry. The reserve grows with every yield event and repayment.
Exit through the AMM. Sell tranche tokens for USDC at market price (which may be at a discount or premium to NAV).
The PRISM frontend surfaces this fork automatically — when withdraw fails, an “AMM Exit” button appears.
Three deposit instructions fit comfortably under Solana’s 1232-byte transaction limit. If you ever need more (e.g., depositing across multiple vaults in one tx), use Versioned Transactions with Address Lookup Tables.