Deposit
Send USDC to the ksUSD vault and get ksUSD back at the current share price. How many tokens you get depends on that price, so a deposit made later buys fewer tokens, each worth more.
New here? Read What is ksUSD? first.
The instruction
deposit(usdc_amount: u64)One transaction does all three steps, or none of them:
Moves your USDC into the vault's USDC account
Mints
ksUSDto you at the current share priceUpdates the vault's record of what it holds
The accounts below use two Solana conventions. A PDA is an account the program controls directly, with no private key behind it. An ATA is the standard token account a wallet holds a given token in.
vault
mut
Vault PDA (seeds: [b"vault"])
vault_usdc_account
mut
Vault's USDC ATA — receives the deposit
ksusd_mint
mut
ksUSD share mint — vault PDA is authority
user_usdc_account
mut
Depositor's USDC source ATA
user_ksusd_account
mut
Depositor's ksUSD destination ATA
user
signer
Depositor
phoenix_trader
—
Phoenix trader account — read to true up the venue's contribution to NAV before pricing. Pinned to vault.phoenix_trader
sol_oracle
—
Pyth SOL/USD — values the perp leg for that same correction. Pinned to vault.sol_oracle
token_program
—
SPL token program
phoenix_trader and sol_oracle are required on every deposit, not only in Normal mode. While the vault is Parked they are read and ignored; in Normal mode the deposit re-books the venue's real equity into NAV first, so the shares you mint are priced against the position as it actually stands.
Share-price math
In plain terms, one division:
Deposit $100 while a share is worth $1.03 and you get 97.09 ksUSD. Deposit $100 while it's worth $1.00 and you get 100. Either way you own $100 of the vault the moment the transaction lands — the price only decides how many tokens that is.
The same thing in the integers the program actually stores:
share_price_1e9 is dollars scaled by 1e9, so 1_030_000_000 reads as $1.03. Multiplying by 1e9 before dividing by it cancels the scale out, which is why usdc_amount and shares_to_mint are both plain 6-decimal amounts. The division truncates, so any fraction of a base unit is left in the vault rather than minted — it can never round in the depositor's favour at other holders' expense.
deposit calls accrue_perf_fees before it prices your mint. That advances the high-water mark to the current price first, so you're never charged a performance fee on gains the vault made before you arrived.
The first deposit into an empty vault mints shares 1:1 at $1.00, since the starting share_price_1e9 is 1_000_000_000. Every deposit after that mints fewer shares, because the share price has drifted up with the carry earned so far. Full derivation and a worked example in NAV & share pricing.
Capacity
The vault ships with a $500k deposit cap. That isn't a demand estimate — it's roughly the largest short Phoenix's book can absorb, and it re-sizes as the venue grows.
It's a hard cap rather than a soft target because the vault only earns while its dollars are in the hedge. Whatever it can't short sits in USDC lending instead. A cap set above what the venue can hold doesn't add yield, then — it dilutes the part that does, until ksUSD is a Kamino deposit wearing a wrapper, carrying all of the operational risk for none of the carry.
So the cap tracks the venue:
On current Phoenix numbers the volume limb binds, by roughly a factor of two, because exit is harder than entry — a clean unwind is about a quarter of a day's flow.
The word median is load-bearing. The 30-day mean runs well above the median, since a few spike days sit inside any window, and sizing off the mean would imply a short the venue couldn't absorb on an ordinary day.
The ramp
Launch
$500k
roughly today's book
Private beta
$1M
roughly twice today's open interest
Public
$5M → $25M
a far deeper book, or a second venue to split the short across
Tiers open against the live book, not on a date. Drift went down in January 2025, so there's no second Solana perp venue wired into v1 to split across yet.
Reading the cap live
deposit_cap_usdc is a u64 on the Vault account. 0 pauses deposits outright, u64::MAX means uncapped, anything else is a hard ceiling.
Admins move the cap with update_params. Recompute it against the live book first, rather than trusting a constant, since both inputs move week to week.
Guardrails
A deposit can be blocked by any of three things:
The vault is paused. The admin can pause it with
set_pausein an emergency.The deposit cap is hit. A deposit reverts with
DepositCapExceededifcached_nav_usdc + usdc_amount > deposit_cap_usdc. See Capacity above.The amount is zero.
usdc_amountmust be greater than 0.
TypeScript example
Events
DepositEvent is emitted on success:
Related
Withdraw — instant vs. queued paths
Last updated