> ## Documentation Index
> Fetch the complete documentation index at: https://docs.derive.xyz/llms.txt
> Use this file to discover all available pages before exploring further.

# Create a Vault

> Launch a vault in 3 minutes via the UX or SDK.

A **vault** is a managed subaccount that outside depositors ("shareholders")
buy into. Shareholders deposit a spot asset and receive **shares**; you — the
**curator** — trade the vault's balance like any other subaccount. You earn
management and performance fees on what you run.

<Check>A vault can be managed end-to-end via both UX or programmatically.</Check>

Vaults can trade any instrument and on any venue that subaccounts can:

* Orderbook, RFQ, lending
* Spot, perpetuals, options

<video autoPlay muted loop playsInline className="w-full aspect-video rounded-xl" src="https://mintcdn.com/derive-a0490cef/BhszcT-bQHpTuFnc/vaults/vault-intro.mp4?fit=max&auto=format&n=BhszcT-bQHpTuFnc&q=85&s=71fd65e91d816c7139decdc6d15883f5" data-path="vaults/vault-intro.mp4" />

You can fund and launch a vault that will show up in the Derive Vaults page instantly
without manual approval!

<video autoPlay muted loop playsInline className="w-full aspect-video rounded-xl" src="https://mintcdn.com/derive-a0490cef/BhszcT-bQHpTuFnc/vaults/create-vault.mp4?fit=max&auto=format&n=BhszcT-bQHpTuFnc&q=85&s=47d0e1d8af39dc9ee6354288835e4ee4" data-path="vaults/create-vault.mp4" />

## How a vault works

A vault is one subaccount with extra protocol state on top:

* **Shares** — `total_shares` outstanding across all holders (you included). A deposit
  mints shares; a withdrawal burns them.
* **NAV** — the vault subaccount's live mark-to-market value in USD, from the risk
  engine. `share price ≈ NAV / total_shares`.
* **High-water mark (HWM)** — the highest share price the vault has reached.
  Performance fees only accrue on new gains above it — see [Fees](/vaults/fees).

Running a vault breaks into four jobs, each with its own page:

<CardGroup cols={2}>
  <Card title="Fees" icon="percent" href="/vaults/fees">
    How management and performance fees accrue, the high-water mark, and the protocol's share.
  </Card>

  <Card title="Process Deposits & Withdrawals" icon="rotate" href="/vaults/deposits-withdrawals">
    The settle loop: poll queued shareholder intents and settle each at a quoted price.
  </Card>

  <Card title="Trade" icon="chart-line" href="/vaults/trade">
    Run your strategy on the vault subaccount with the normal trading API.
  </Card>

  <Card title="Winddowns" icon="door-open" href="/vaults/winddowns">
    Exit every holder, take total shares to zero, and close the vault.
  </Card>
</CardGroup>

## Prerequisites

1. Create and fund an account on Derive.
2. Create a session key with proper scopes.

<Tip>
  Running the vault from a multi-sig or smart contract? See [Smart Contract & Multi-sig Accounts](/authentication/contract-owned-accounts) to setup an account and session key from the L1. You can continue to next steps once that step is complete.
</Tip>

### Required Session Key Scopes

| Role    | SDK methods                                                                                         | Scope                         |
| ------- | --------------------------------------------------------------------------------------------------- | ----------------------------- |
| Curator | `createVault`, `updateInfo`                                                                         | `vault:curator_create`        |
| Curator | `mintShares`, `burnShares`, `forceBurn`, `rejectDepositRequest`, and the live mint/burn queue reads | `vault:curator_mint_and_burn` |

## Choose your immutable parameters

You fix these when you create the vault. They shape what shareholders pay and what you
earn.

<CardGroup cols={3}>
  <Card title="managerId">
    Choose between Standard vs Portfolio Manager. Managers also determine the risk universe — see [Managers & Risk Universes](/trading/managers-and-risk-universes).
  </Card>

  <Card title="depositSpotAsset">
    Spot asset shareholders deposit and withdraw in.
  </Card>

  <Card title="initialSharePriceUsd">
    Initial share price. See [Choosing the Initial Share
    Price](#choosing-the-initial-share-price).
  </Card>

  <Card title="managementFeeBps">
    Annualised management fee, in basis points, accrued pro-rata over time on NAV regardless of performance.
  </Card>

  <Card title="performanceFeeBps">
    Performance fee, in basis points, charged only on gains above the high-water mark relative to a benchmark.
  </Card>

  <Card title="benchmarkAsset">
    Performance fees charge only on **outperformance versus that currency**. Default benchmarks against USD.
  </Card>

  <Card title="maxSlippageBps">
    Maximum deviation of the share price during deposits / withdrawals from the oracle mark-to-market value of the vault.
  </Card>

  <Card title="cooldownSec">
    Minimum seconds between a holder's last deposit and a withdrawal (prevents excessive churn).
  </Card>

  <Card title="maxFeeUsd">
    Maximum sequencer fee you authorise for this action, in USD. This fee covers the vault-creation fee (\$1000).
  </Card>
</CardGroup>

### Choosing the Initial Share Price

For most vaults, `initialSharePriceUsd: '1'` is the natural choice: shares start at
\$1.00, and the share price thereafter reads directly as the vault's cumulative USD
performance.

If your vault tracks a benchmark, consider seeding the share price at the benchmark's
**current spot price** instead. One share then starts worth exactly one unit of the
benchmark, and the share-price-to-benchmark ratio becomes a live measure of relative
performance that shareholders can read at a glance. For example, launch an
ETH-benchmarked vault while ETH trades at \$1,950 with `initialSharePriceUsd: '1950'`:
a share is worth 1.0 ETH at inception, and if the vault outperforms ETH by 10%, a
share is worth 1.1 ETH — visible directly in the price, with no reference to when
anyone entered.

<Note>
  The seed price must lie between 0.01 and 1,000,000. When `benchmarkAsset` is set, it must additionally be within 1000×
  of the benchmark's spot price in either direction.
</Note>

### Global limits

Your config is bounds-checked at creation against a protocol-wide, **deployment-set**
global config:

| Global cap                   | Value            | Constrains                                                                      |
| ---------------------------- | ---------------- | ------------------------------------------------------------------------------- |
| `min_creation_deposit_usd`   | \$10,000         | Minimum `initialDeposit` (USD) to open a vault                                  |
| `min_curator_stake_usd`      | \$10,000         | Flat floor on curator skin-in-the-game, checked on your own withdrawals         |
| `min_curator_stake_frac_bps` | 100 (1%)         | Fractional stake floor on vault value — the **greater** of the two floors binds |
| `global_max_slippage_bps`    | 300 (3%)         | Ceiling on `maxSlippageBps`                                                     |
| `max_management_fee_bps`     | 300 (3%)         | Ceiling on `managementFeeBps`                                                   |
| `max_performance_fee_bps`    | 5,000 (50%)      | Ceiling on `performanceFeeBps`                                                  |
| `min_cooldown_sec`           | 60 (1 min)       | Floor on `cooldownSec`                                                          |
| `max_cooldown_sec`           | 604,800 (7 days) | Ceiling on `cooldownSec`                                                        |
| `vault_creation_fee`         | \$1,000          | One-time fee paid from depositing account. Reach out for custom arrangements.   |

## Create the vault and resolve its id

<CodeGroup>
  ```typescript TypeScript (SDK) theme={null}
  const curator = client.vaults.curator;

  // Snapshot the vaults you already curate, to diff against below.
  const before = new Set((await curator.getCuratedVaults()).subaccount_ids);

  await curator.createVault({
    subaccountId: 1234, // funding subaccount — the seed deposit leaves here
    managerId: 1,
    depositSpotAsset: '0x…', // your environment's USDC spot-asset address
    initialDeposit: '15000',
    initialSharePriceUsd: '1',
    managementFeeBps: 100, // 1% p.a.
    performanceFeeBps: 1000, // 10% of gains above the high-water mark
    maxSlippageBps: 50,
    cooldownSec: 86400, // 24h between a holder's deposit and their withdrawal
    maxFeeUsd: '1000', // must cover the deployment-set creation fee
    // benchmarkAsset: '0x…', // optional: denominate the HWM in a spot asset
  });

  let vaultId: number | undefined;
  while (vaultId === undefined) {
    await new Promise((resolve) => setTimeout(resolve, 500));
    const { subaccount_ids } = await curator.getCuratedVaults();
    vaultId = subaccount_ids.find((id) => !before.has(id));
  }
  ```

  ```python Python (SDK) theme={null}
  import asyncio
  from decimal import Decimal

  from derive_py import WebSocketClient


  async def main():
      client = WebSocketClient.from_env()
      await client.connect()

      # The funding subaccount you act as — the seed deposit leaves here.
      curator = await client.fetch_subaccount(1234)

      # Snapshot the vaults you already curate, to diff against below.
      before = set((await client.vaults.list_curated()).subaccount_ids)

      await curator.vaults.create(
          manager_id=1,
          deposit_spot_asset="0x…",  # your environment's USDC spot-asset address
          initial_deposit=Decimal("15000"),
          initial_share_price_usd=Decimal("1"),
          management_fee_bps=100,  # 1% p.a.
          performance_fee_bps=1000,  # 10% of gains above the high-water mark (the global cap)
          max_slippage_bps=50,
          cooldown_sec=86400,  # 24h between a holder's deposit and their withdrawal
          max_fee_usd=Decimal("1000"),  # must cover the deployment-set creation fee
          # benchmark_asset="0x…",  # optional: denominate the HWM in a spot asset
      )

      vault_id = None
      while vault_id is None:
          await asyncio.sleep(0.5)
          after = set((await client.vaults.list_curated()).subaccount_ids)
          vault_id = next(iter(after - before), None)
      print(vault_id)

      await client.disconnect()


  asyncio.run(main())
  ```

  ```rust Rust (SDK) theme={null}
  use std::collections::HashSet;

  use bigdecimal::BigDecimal;
  use derive_rs::{Environment, WsClient, actions::CreateVaultArgs, models::GetCuratedVaultsRequest};

  #[tokio::main]
  async fn main() -> Result<(), Box<dyn std::error::Error>> {
      let wallet = std::env::var("DERIVE_WALLET")?;
      let client = WsClient::new(
          Environment::Mainnet,
          Some(std::env::var("DERIVE_PRIVATE_KEY")?),
          Some(wallet.clone()),
          Some(1234), // funding subaccount — the seed deposit leaves here
      )
      .await?;
      client.login().await?;

      let curated = || GetCuratedVaultsRequest::builder().wallet(&wallet).try_into();

      // Snapshot the vaults you already curate, to diff against below.
      let before: HashSet<u64> = client
          .rpc()
          .vault_curators()
          .get_curated_vaults(curated()?)
          .await?
          .subaccount_ids
          .into_iter()
          .collect();

      client
          .vaults()
          .create(
              CreateVaultArgs::builder()
                  .subaccount_id(1234)
                  .manager_id(1)
                  .deposit_spot_asset("0x…".to_string()) // your environment's USDC spot-asset address
                  .initial_deposit(BigDecimal::from(15_000))
                  .initial_share_price_usd(BigDecimal::from(1))
                  .management_fee_bps(100) // 1% p.a.
                  .performance_fee_bps(1000) // 10% of gains above the high-water mark (the global cap)
                  .max_slippage_bps(50)
                  .cooldown_sec(86_400) // 24h between a holder's deposit and their withdrawal
                  .max_fee_usd(BigDecimal::from(1000)) // must cover the deployment-set creation fee
                  // .benchmark_asset("0x…".to_string()) // optional: denominate the HWM in a spot asset
                  .build(),
          )
          .await?;

      let vault_id = loop {
          tokio::time::sleep(std::time::Duration::from_millis(500)).await;
          let after = client.rpc().vault_curators().get_curated_vaults(curated()?).await?;
          if let Some(id) = after.subaccount_ids.into_iter().find(|id| !before.contains(id)) {
              break id;
          }
      };

      println!("{vault_id}");
      Ok(())
  }
  ```
</CodeGroup>

That `vaultId` is the `vaultSubaccountId` every other vault call takes.

## Read it back

`getVault` is public — anyone can read any vault's config and live pricing:

<CodeGroup>
  ```typescript TypeScript (SDK) theme={null}
  const vault = await client.vaults.getVault(vaultId);

  console.log(vault.protocol.config); // the immutable economics you set above
  // nav_usd / simulated_share_price_usd are null when the vault cannot be
  // priced right now, so never assume they are set.
  console.log(
    `NAV $${vault.nav_usd ?? '?'}, share price $${
      vault.simulated_share_price_usd ?? '?'
    }`
  );
  ```

  ```python Python (SDK) theme={null}
  import asyncio

  from derive_py import WebSocketClient


  async def main():
      client = WebSocketClient.from_env()
      await client.connect()

      vault = await client.vaults.get(vault_subaccount_id=vault_id)

      print(vault.protocol.config)  # the immutable economics you set above
      # nav_usd / simulated_share_price_usd are unset when the vault cannot be
      # priced right now, so never assume they are set.
      print(f"NAV ${vault.nav_usd or '?'}, share price ${vault.simulated_share_price_usd or '?'}")

      await client.disconnect()


  asyncio.run(main())
  ```

  ```rust Rust (SDK) theme={null}
  use derive_rs::{Environment, WsClient, models::GetVaultRequest};

  #[tokio::main]
  async fn main() -> Result<(), Box<dyn std::error::Error>> {
      let client = WsClient::new_public(Environment::Mainnet).await?;
      let vault_id = 5678;

      let params = GetVaultRequest::builder().subaccount_id(vault_id).try_into()?;
      let vault = client.rpc().vault_shareholders().get_vault(params).await?;

      println!("{:?}", vault.protocol.config); // the immutable economics
      // nav_usd / simulated_share_price_usd are null when the vault cannot be
      // priced right now, so never assume they are set.
      println!("{:?} {:?}", vault.nav_usd, vault.simulated_share_price_usd);
      Ok(())
  }
  ```

  ```bash cURL theme={null}
  curl -X POST https://api.derive.xyz/v3/public/get_vault \
    -H "Content-Type: application/json" \
    -d '{ "subaccount_id": 42 }'
  ```
</CodeGroup>

`client.vaults.listVaults({ page, pageSize })` pages every vault on the exchange —
that is how shareholders will discover yours.

## Set the metadata

`updateInfo` patches only the **off-chain** fields — the economics stay immutable.
Supply just the fields you want to change; the caller must be the vault's curator.

<CodeGroup>
  ```typescript TypeScript (SDK) theme={null}
  await client.vaults.curator.updateInfo({
    vaultSubaccountId: vaultId,
    name: 'Delta-Neutral ETH',
    description: 'Short vol, delta-hedged hourly.',
    mtmCap: '1000000', // advisory NAV soft-cap in USD — a signal to shareholders
    whitelistOnly: false, // restrict who may deposit
  });
  ```

  ```python Python (SDK) theme={null}
  import asyncio
  from decimal import Decimal

  from derive_py import WebSocketClient


  async def main():
      client = WebSocketClient.from_env()
      await client.connect()

      await client.vaults.update_info(
          vault_subaccount_id=vault_id,
          name="Delta-Neutral ETH",
          description="Short vol, delta-hedged hourly.",
          mtm_cap=Decimal("1000000"),  # advisory NAV soft-cap in USD — a signal to shareholders
          whitelist_only=False,  # restrict who may deposit
      )

      await client.disconnect()


  asyncio.run(main())
  ```

  ```rust Rust (SDK) theme={null}
  use bigdecimal::BigDecimal;
  use derive_rs::{Environment, WsClient, models::UpdateVaultInfoRequest};

  #[tokio::main]
  async fn main() -> Result<(), Box<dyn std::error::Error>> {
      let client = WsClient::new(
          Environment::Mainnet,
          Some(std::env::var("DERIVE_PRIVATE_KEY")?),
          Some(std::env::var("DERIVE_WALLET")?),
          Some(1234),
      )
      .await?;
      client.login().await?;

      // Off-chain metadata, so no action signing.
      let params = UpdateVaultInfoRequest::builder()
          .subaccount_id(5678)
          .name("Delta-Neutral ETH".to_string())
          .description("Short vol, delta-hedged hourly.".to_string())
          .mtm_cap(Some(BigDecimal::from(1_000_000))) // advisory NAV soft-cap in USD
          .whitelist_only(true)
          .try_into()?;

      client.rpc().vault_curators().update_vault_info(params).await?;
      Ok(())
  }
  ```

  ```bash cURL theme={null}
  # Unsigned (ownership-checked); X-Derive* headers: session auth (see /json-rpc).
  curl -X POST https://api.derive.xyz/v3/private/update_vault_info \
    -H "Content-Type: application/json" \
    -H "X-DeriveWallet: $WALLET_ADDRESS" \
    -H "X-DeriveTimestamp: $TS" \
    -H "X-DeriveSignature: $SIG" \
    -d '{
      "subaccount_id": 42,
      "name": "Delta-Neutral ETH",
      "description": "Short vol, delta-hedged hourly.",
      "mtm_cap": "1000000",
      "whitelist_only": false
    }'
  ```
</CodeGroup>

## Next steps

<CardGroup cols={2}>
  <Card title="Process Deposits & Withdrawals" icon="rotate" href="/vaults/deposits-withdrawals">
    Your first shareholder is waiting: run the settle loop.
  </Card>

  <Card title="Fees" icon="percent" href="/vaults/fees">
    When and how the fees you just configured are actually paid.
  </Card>

  <Card title="Session keys" href="/authentication/session-keys" icon="key">
    Run the settle loop from a scoped key, not the raw wallet.
  </Card>
</CardGroup>


## Related topics

- [private/create_vault](/api-reference/vault-curators/privatecreate_vault.md)
- [Smart Contracts & Multi-sigs](/authentication/contract-owned-accounts.md)
- [Fees](/vaults/fees.md)
