> 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/reference/security.md).

# Security Model

ksUSD is one Anchor program, one PDA-owned vault, one share mint. The security surface is correspondingly narrow.

***

## Access control

| Role          | Capabilities                                                                                                                                                                                                                                                                              |
| ------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **Admin**     | `initialize`, `enable_phoenix`, `enable_reverse`, `enable_lending`, `set_oracles`, `set_pause`, `update_params`, `collect_fees`, `transfer_admin`, `accept_admin`, `reset_peak`, `pay_from_reserve`, `init_wind_down`                                                                     |
| **Keeper**    | `settle`, `attest_nav`, `open_position`, `close_position`, `open_reverse`, `close_reverse`, `lend_idle_usdc`, `unlend_usdc`, `lend_reserve`, `unlend_reserve`, `emergency_close` (once tripped). Permissionless when `authorized_keeper == default()`; otherwise gated to the pinned key. |
| **Any user**  | `deposit`, `withdraw_instant`, `request_withdrawal`, `process_withdrawal`, `claim_wind_down` (during wind-down). `process_withdrawal` is permissionless even when a keeper allowlist is set.                                                                                              |
| **Vault PDA** | Signs all token operations on behalf of the vault — program-derived, no private key                                                                                                                                                                                                       |

* Admin authority is transferable via the two-step `transfer_admin` + `accept_admin` flow
* End-state: a multisig (Squads / similar) once mainnet is live

***

## Protections

| Protection               | Mechanism                                                                                                                                            |
| ------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------- |
| Emergency pause          | Admin halt of new deposits + new positions; instant withdrawals stay open                                                                            |
| Wind-down                | Terminal `init_wind_down` blocks new state; users redeem pro-rata via `claim_wind_down`                                                              |
| Deposit cap              | `cached_nav_usdc + usdc_amount > deposit_cap_usdc` reverts; `0` fully pauses deposits                                                                |
| Bootstrap residual guard | First deposit reverts if vault USDC ATA is non-empty (`BootstrapResidualUsdc`) — prevents dilution griefing                                          |
| Oracle validation        | Pyth staleness (5 min) + confidence (2%) checks; revert on either                                                                                    |
| LST depeg auto-pause     | `settle` reverts AND pauses the vault if jitoSOL/SOL deviates beyond `lst_depeg_bps`                                                                 |
| Integer arithmetic       | `checked_add` / `checked_mul` everywhere; 128-bit intermediates for NAV math; no floating point                                                      |
| Slippage protection      | Jupiter swaps gated by `max_swap_slippage_bps` (default 0.5%) plus explicit `min_*_out` arguments                                                    |
| HWM monotonicity         | Performance fees never charged twice on the same gains; HWM only goes up                                                                             |
| Drawdown guard           | `emergency_close` is callable by anyone once `peak − current ≥ emergency_close_dd_bps` AND observed across `consecutive_dd_settles_required` settles |
| Drawdown latency         | Single-tick drawdown reverts with `DrawdownTriggerLatent`                                                                                            |
| Mode-switch dwell        | `min_dwell_seconds` (default 12 h) between mode transitions — prevents ping-pong                                                                     |
| Funding signal staleness | Opens revert with `FundingSignalStale` if the EMA hasn't been refreshed within `funding_max_staleness_seconds`                                       |
| Funding rate sanity      | Venue-reported rates outside a hard sanity band revert with `FundingRateInsane`                                                                      |
| NAV change cap           | `attest_nav` deltas bounded by `max_nav_change_bps_per_hour`                                                                                         |
| Withdrawal FIFO          | Strict FIFO order via `WithdrawalNotNextInQueue` guard; per-request price-at-process haircut so depositors never extract more than pro-rata          |
| Reserve fund segregation | Reserve USDC sits in its own ATA, lent under a distinct cToken ATA; excluded from `effective_nav_usdc`                                               |

***

## Repay tightening (`close_reverse`)

* `close_reverse` passes `u64::MAX` as the borrow-amount argument
* Kamino auto-clamps to the actual outstanding debt
* Avoids round-up edge cases that could leave dust borrow open
* Reverts the transaction cleanly if the swap leg shortfalls

***

## Account-context layering (strategy instructions)

`open_position`, `close_position`, `emergency_close` (and the dormant `open_reverse` / `close_reverse`) pack multiple CPIs into one transaction — Phoenix, Ember, Kamino, and Jupiter. The handler:

1. Receives per-group account counts as u8 instruction arguments.
2. Splits `remaining_accounts` via `checked_add(...).ok_or(InvalidParams)` — overflow on the cumulative offset reverts safely.
3. Passes each slice to the relevant CPI helper, which validates its own account expectations.

**Trust surface bounded:**

* Program never indexes past the supplied accounts, even with malicious arguments
* Downstream venues (Phoenix, Ember, Kamino, Jupiter) own their own account validation

***

## Audit status

* **Currently unaudited**
* Pre-mainnet audit planned with a top-tier Solana firm (Ottersec / Sec3 / Neodyme)
* Scope: one Anchor crate, one state struct — tractable
* Internal pre-audit notes: [`docs/PRE_MAINNET_AUDIT.md`](https://github.com/kamwithak/keystone-contracts/blob/main/docs/PRE_MAINNET_AUDIT.md)
* **Do not deploy significant capital pre-audit.**

***

## Reporting

Suspected vulnerabilities:

* Open a private GitHub security advisory on [github.com/kamwithak/keystone-contracts](https://github.com/kamwithak/keystone-contracts/security/advisories), **or**
* Contact the maintainer directly

A formal bug bounty stands up alongside the mainnet audit.

***

## Related

* [Whitepaper — Risk](/reference/whitepaper.md#risk)
* [Fees](/reference/fees.md) · [NAV & share pricing](/reference/nav-calculation.md)
* [Errors](/for-developers/errors.md) — every revert path enumerated
