> For the complete documentation index, see [llms.txt](https://docs.keystonefi.xyz/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.keystonefi.xyz/for-operators/admin-ops.md).

# Admin Operations

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

> Source: [`programs/keystone-finance/src/instructions/admin.rs`](https://github.com/kamwithak/keystone-contracts/blob/main/programs/keystone-finance/src/instructions/admin.rs) · [`init_wind_down.rs`](https://github.com/kamwithak/keystone-contracts/blob/main/programs/keystone-finance/src/instructions/init_wind_down.rs) · [`enable_lending.rs`](https://github.com/kamwithak/keystone-contracts/blob/main/programs/keystone-finance/src/instructions/enable_lending.rs) · [`set_oracles.rs`](https://github.com/kamwithak/keystone-contracts/blob/main/programs/keystone-finance/src/instructions/set_oracles.rs)

***

## 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)

```ts
await program.methods.setPause(true).accountsStrict({
  vault: vaultPda,
  admin: adminWallet.publicKey,
}).rpc();
```

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`

```ts
await program.methods.updateParams({
  liquidityBufferBps: 800,            // tighten buffer to 8%
  emergencyCloseDdBps: 400,           // tighten drawdown guard to 4%
  // omit other fields to leave them unchanged
}).accountsStrict({
  vault: vaultPda,
  admin: adminWallet.publicKey,
}).rpc();
```

***

## `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.

```ts
// Step 1 — current admin proposes
await program.methods.transferAdmin(squadsMultisig).accountsStrict({
  vault: vaultPda,
  admin: currentAdmin.publicKey,
}).rpc();

// Step 2 — new admin accepts
await program.methods.acceptAdmin().accountsStrict({
  vault: vaultPda,
  newAdmin: squadsMultisig,
}).rpc();
```

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](/reference/fees.md) 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)

```ts
await program.methods.collectFees().accountsStrict({
  vault: vaultPda,
  vaultUsdcAccount: vaultUsdcAta,
  reserveUsdcAccount: vault.reserveAta,
  adminUsdcAccount: adminUsdcAta,
  admin: adminWallet.publicKey,
  tokenProgram: TOKEN_PROGRAM_ID,
}).rpc();
```

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

```ts
await program.methods.resetPeak().accountsStrict({
  vault: vaultPda,
  admin: adminWallet.publicKey,
}).rpc();
```

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

```ts
await program.methods.payFromReserve(new BN(amount)).accountsStrict({
  vault: vaultPda,
  reserveUsdcAccount: vault.reserveAta,
  vaultUsdcAccount: vaultUsdcAta,
  admin: adminWallet.publicKey,
  tokenProgram: TOKEN_PROGRAM_ID,
}).rpc();
```

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)`.

```ts
await program.methods.initWindDown().accountsStrict({
  vault: vaultPda,
  admin: adminWallet.publicKey,
}).rpc();
```

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** | `init_wind_down`, close any open position, broadcast `claim_wind_down` instructions to depositors.               |

***

## Related

* [Keeper bot](/for-operators/keeper-bot.md) — non-admin strategy operations
* [Monitoring](/for-operators/monitoring.md) — what to watch
* [Errors](/for-developers/errors.md) — what reverts look like
* [Fees](/reference/fees.md) — `collect_fees` math
