For the complete documentation index, see llms.txt. This page is also available as Markdown.

Admin Operations

Admin-only instructions on the ksUSD vault. All signed by the vault.admin keypair (or successor after transfer_admin + accept_admin).

Source: the admin instructions · wind-down · lending setup · oracle setup


One-time setup

Instruction
When

initialize(params)

First deploy. Creates the vault PDA, ksUSD mint, reserve USDC ATA.

enable_phoenix(subaccount_id, name)

After init, before opening any perp position.

enable_lending()

After init, before any lend_idle_usdc / lend_reserve. Pins Kamino USDC reserve + the two cToken ATAs.

set_oracles()

After init, before strategy paths that read SOL/USD or jitoSOL/USD.


set_pause(paused: bool)

  • Halts new deposits and new positions

  • Instant withdrawals and claim_wind_down stay open by design — depositors should always be able to exit

  • Cannot un-pause while position_mode == WindDown (reverts with WindDownActive)

When to use:

  • Pre-audit incident response

  • Investigating an oracle / venue anomaly

  • During an admin handover (briefly, to flush in-flight state)

Emits PauseToggled.


update_params(args)

  • Adjust risk parameters in place

  • Each field on UpdateParamsArgs is Option<T> — only the fields you pass get written

Field
Bounds

liquidity_buffer_bps

0–5_000 (≤ 50% of NAV)

funding_threshold_normal_bps

i32; expected positive

perf_fee_bps

0–5_000 (≤ 50%)

reserve_skim_bps

0–10_000 (of perf fee)

min_dwell_seconds

0–u32::MAX

max_swap_slippage_bps

0–1_000 (≤ 10%)

emergency_close_dd_bps

0–10_000

deposit_cap_usdc

u64::MAX = uncapped, 0 = pause new deposits, else USDC base units

authorized_keeper

Pubkey; exact match required. Pubkey::default() (the post-init state) blocks all keeper-gated ix until admin sets a real key

min_request_shares

u64

max_pending_queue_usdc

u64::MAX = disabled

max_nav_change_bps_per_hour

0–10_000

funding_max_staleness_seconds

u32

consecutive_dd_settles_required

≥ 1

  • Invalid bounds → InvalidParams

  • Mints, admin, oracles, Phoenix / Kamino refs are immutable through this instruction — set once at initialize / enable_* / set_oracles


transfer_admin(new_admin) + accept_admin()

Two-step admin handover:

  • Step 1 — records new_admin as a pending successor (signed by current admin)

  • Step 2 — finalizes (signed by the new admin)

  • Prevents accidentally transferring to a dead key

Target end-state: a multisig (Squads / similar) once mainnet is live.

Errors: NoPendingAdmin (step 2 called without a pending), NotPendingAdmin (step 2 signer mismatch).


collect_fees()

  • Pays the performance fee in USDC (no dilutive share mint)

  • Only callable when position_mode == Idle (Parked) — fees crystallize on realized gains

  • See Fees for the math

  • Admin share → admin_usdc_account

  • Reserve skim → reserve_ata

  • HWM bumps to the post-fee share price (monotonic)

When to call:

  • On a regular cadence (monthly is conventional; weekly is fine)

  • Before any planned parameter change that affects share-price computation

  • Before mainnet upgrade events (clean accounting boundary)

Idempotent when share price ≤ HWM (no transfer, no state change). Emits FeesCollected.


reset_peak()

  • Clears peak_share_price_1e9 and consecutive_dd_settles_observed to current share price

  • Use after legitimate recovery — prevents a stale peak from keeping the drawdown guard armed against routine volatility

Emits PeakReset.


pay_from_reserve(amount)

  • Moves USDC out of reserve_ata into the vault's main USDC ATA → socializes a reserve draw into NAV

  • Caller must invoke unlend_reserve first if part of the reserve is currently lent at Kamino

Emits ReservePaidOut.


init_wind_down()

Terminal mode switch. Sets position_mode = WindDown and pauses the vault. After this:

  • deposit reverts (WindDownActive)

  • Strategy open_* reverts (WindDownActive)

  • Existing positions must be closed via close_position / emergency_close

  • Users redeem pro-rata via claim_wind_down(shares) against the vault's idle USDC

Cannot be undone via set_pause(false).

Both preconditions, and why they are enforced

init_wind_down requires position_mode == Idle and usdc_lent_kamino == 0 && reserve_lent_kamino == 0 (WindDownRequiresUnlent). The lending one matters because claim_wind_down pays out of the vault's USDC ATA but sizes each payout off effective_nav_usdc(), which counts the Kamino basis — so entering with USDC lent would make the lent fraction permanently unclaimable. unlend_usdc and unlend_reserve are keeper-only, and WindDown is exactly when the keeper stands down, so nothing would be left that could recover it.

So run the drain first, and wait for it to finish:

Then close any position, then init_wind_down.

Emits WindDownInitiated.


Operational checklist

Cadence
Action

Daily

Verify cached_nav_usdc against on-chain Phoenix / Kamino reads (off-chain script).

Weekly

collect_fees if share price has crossed HWM. Refresh keeper bot keys if rotated.

Monthly

Review peak_share_price_1e9 vs. live share price; reset_peak if a stale peak is dragging the drawdown guard.

On incident

set_pause(true), investigate, then either resolve and unpause or invoke emergency_close.

On admin rotation

transfer_admin + accept_admin (two transactions).

On legitimate retirement

KEEPER_DRAIN_LENDING=1 until both lent figures read 0, close any open position, init_wind_down, broadcast claim_wind_down instructions to depositors.


Last updated