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

# Quickstart

> Make your first trade.

Go from an empty wallet to a resting ETH-PERP order on **testnet** in five steps.

If you're using an **agent**, point it at our [SKILL.MD](https://v3.docs.derive.xyz/skill.md).

<CodeGroup>
  ```bash TypeScript (SDK) theme={null}
  npm install @derivexyz/derive-ts ethers ws
  ```

  ```bash Python (SDK) theme={null}
  pip install derive-py
  ```

  ```bash Rust (SDK) theme={null}
  cargo add derive-rs tokio bigdecimal
  ```
</CodeGroup>

<Steps>
  <Step title="Get a wallet">
    Create an Ethereum wallet and set `PRIVATE_KEY` in your environment before running
    the snippets below. The examples use a public Sepolia RPC endpoint, so no RPC
    setup is needed.

    If you don't have a wallet, you can use the Foundry CLI for this.

    `curl -L https://foundry.paradigm.xyz | bash`
    `foundryup`
    `cast wallet new`

    which outputs something like:

    ```
    Address: 0x...
    Private Key: 0x...
    ```
  </Step>

  <Step title="Get Sepolia ETH for gas">
    Your wallet pays gas for the on-chain deposit. Grab testnet ETH from the
    [Google Cloud Sepolia faucet](https://cloud.google.com/application/web3/faucet/ethereum/sepolia).
  </Step>

  <Step title="Mint testnet USDC">
    Open [testnet.app.derive.xyz/developers](https://testnet.app.derive.xyz/developers),
    connect your wallet, and click **Mint** to receive testnet USDC — the collateral
    you'll deposit in the next step.
  </Step>

  <Step title="Choose a manager and risk universe">
    Every subaccount lives under a **manager** in a **risk universe** — together they
    set the margin model and which instruments you can trade. See
    [Managers & risk universes](/trading/managers-and-risk-universes) for more.

    <CodeGroup>
      ```typescript TypeScript (SDK) theme={null}
      import { DeriveClient } from '@derivexyz/derive-ts';
      import { JsonRpcProvider, Wallet } from 'ethers';

      const client = new DeriveClient({
        network: 'testnet',
        wallet: process.env.PRIVATE_KEY!,
      });

      // Pick the manager that trades what you want (ETH perps) and accepts the
      // collateral you'll post (USDC).
      const universes = await client.marketData.getRiskUniverses();
      const manager = universes
        .flatMap((u) => u.managers)
        .find((m) => m.instruments.includes('ETH-PERP') && m.collaterals.some((c) => c.name === 'USDC'))!;
      const usdc = manager.collaterals.find((c) => c.name === 'USDC')!;
      ```

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

      from derive_py import WebSocketClient


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

          # Pick the manager that trades what you want (ETH perps) and accepts the
          # collateral you'll post (USDC).
          universes = await client.markets.get_risk_universes()
          manager = next(
              m
              for u in universes
              for m in u.managers
              if "ETH-PERP" in m.instruments and any(c.name == "USDC" for c in m.collaterals)
          )
          usdc = next(c for c in manager.collaterals if c.name == "USDC")
          print(manager.manager_id, usdc.address)

          await client.disconnect()


      asyncio.run(main())
      ```

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

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

          // Pick the manager that trades what you want (ETH perps) and accepts the
          // collateral you'll post (USDC).
          let universes = client.rpc().market_data().get_risk_universes().await?;
          let manager = universes
              .iter()
              .flat_map(|u| &u.managers)
              .find(|m| {
                  m.instruments.contains(&"ETH-PERP".to_string())
                      && m.collaterals.iter().any(|c| c.name == "USDC")
              })
              .expect("no manager trades ETH perps against USDC");
          let usdc = manager
              .collaterals
              .iter()
              .find(|c| c.name == "USDC")
              .expect("USDC collateral missing");

          println!("{} {}", manager.manager_id, usdc.address);
          Ok(())
      }
      ```
    </CodeGroup>
  </Step>

  <Step title="Deposit to create your account">
    Your first deposit creates your Derive account and its first subaccount under the
    manager you chose — there is no separate "create account" call. Your wallet
    submits the on-chain deposit.

    <CodeGroup>
      ```typescript TypeScript (SDK) theme={null}
      // Snapshot subaccounts so we can spot the new one after depositing.
      const knownSubaccountIds = await client.subaccounts.list();

      // Your wallet signs the on-chain ActionManager tx (ERC-20 approve + deposit).
      const rpcUrl = 'https://ethereum-sepolia-rpc.publicnode.com';
      const signer = new Wallet(
        process.env.PRIVATE_KEY!,
        new JsonRpcProvider(rpcUrl),
      );
      await client.deposits.contractCall.depositToNewSubaccount({
        signer,
        asset: usdc.address,
        amount: '100',
        managerId: manager.manager_id,
      });

      // The exchange assigns the subaccount id once it sees the deposit (~2 min).
      const subaccountId = await client.deposits.awaitNewSubaccount({
        knownSubaccountIds,
      });
      console.log(`account ready: subaccount ${subaccountId}`);
      ```

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

      from derive_py import WebSocketClient
      from derive_py.data_types import D, MarginType, RiskUniverseID


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

          # Snapshot subaccounts so we can spot the new one after depositing.
          known = {s.id for s in await client.fetch_subaccounts()}

          # plan_deposit_to_new_subaccount yields one step per on-chain tx (an ERC-20
          # approve, if needed, then the ActionManager deposit). Your wallet signs each.
          steps = client.plan_deposit_to_new_subaccount(
              risk_universe_id=RiskUniverseID.PRIME,
              margin_type=MarginType.SM,
              asset_name="USDC",
              amount=D("100"),
          )
          async for step in steps:
              print(f"[{step.kind}] {step.description}")
              await step.submit()
              await step.wait_for_finality()

          # The exchange assigns the subaccount id once it sees the deposit (~2 min).
          subaccount_id = None
          while subaccount_id is None:
              await asyncio.sleep(5)
              new = {s.id for s in await client.fetch_subaccounts()} - known
              subaccount_id = next(iter(new), None)
          print(f"account ready: subaccount {subaccount_id}")

          await client.disconnect()


      asyncio.run(main())
      ```

      ```rust Rust (SDK) theme={null}
      use std::str::FromStr;

      use alloy::primitives::Address;
      use bigdecimal::BigDecimal;
      use derive_rs::{
          Environment, WsClient,
          actions::{DepositArgs, DepositTypes, DirectDepositType, SupportDepositAssets},
          models::GetSubaccountsRequest,
      };

      #[tokio::main]
      async fn main() -> Result<(), Box<dyn std::error::Error>> {
          let manager_id: u32 = 2; // manager.manager_id from the previous step
          let wallet: Address = std::env::var("DERIVE_WALLET")?.parse()?;
          let client = WsClient::new(
              Environment::Testnet,
              Some(std::env::var("DERIVE_PRIVATE_KEY")?),
              Some(wallet.to_string()),
              None, // no subaccount yet — this deposit creates one
          )
          .await?;

          // Snapshot subaccounts so we can spot the new one after depositing.
          let params = GetSubaccountsRequest::builder().wallet(wallet.to_string()).try_into()?;
          let known = client.rpc().subaccounts().get_subaccounts(params).await?.subaccount_ids;

          // Your wallet signs the on-chain ActionManager txs (ERC-20 approve + deposit).
          let args = DepositArgs::builder()
              .asset(SupportDepositAssets::USDC)
              .amount(BigDecimal::from_str("100")?)
              .recepient_address(wallet)
              .manager_id(manager_id)
              .deposit_type(DepositTypes::Direct(
                  DirectDepositType::DepositToNewSubaccount,
              ))
              .build();
          client.fund_movements().deposit(args).await?;

          // The exchange assigns the subaccount id once it sees the deposit (~2 min).
          let subaccount_id = loop {
              tokio::time::sleep(std::time::Duration::from_secs(5)).await;
              let params = GetSubaccountsRequest::builder().wallet(wallet.to_string()).try_into()?;
              let current = client.rpc().subaccounts().get_subaccounts(params).await?.subaccount_ids;
              if let Some(id) = current.into_iter().find(|id| !known.contains(id)) {
                  break id;
              }
          };
          println!("account ready: subaccount {subaccount_id}");
          Ok(())
      }
      ```
    </CodeGroup>
  </Step>

  <Step title="Place an ETH-PERP order">
    Open the WebSocket, log in, and place a limit order. `place()` encodes the trade
    action, EIP-712-signs it locally with your key, and submits `private/order` — the
    exchange only ever settles what you signed.

    <CodeGroup>
      ```typescript TypeScript (SDK) theme={null}
      await client.connect(); // open the websocket
      await client.login(); // authenticate the session — required for private/*

      const { order } = await client.orders.place({
        subaccountId,
        instrumentName: 'ETH-PERP',
        direction: 'buy',
        amount: '1',
        limitPrice: '3100', // rests below market
      });
      console.log(`${order.order_id}: ${order.order_status} @ ${order.limit_price}`);

      await client.close();
      ```

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

      from derive_py import WebSocketClient
      from derive_py.data_types import Direction


      async def main():
          client = WebSocketClient.from_env()
          # connect() opens the websocket and authenticates the session,
          # which private/* calls require.
          await client.connect()

          response = await client.orders.create(
              instrument_name="ETH-PERP",
              direction=Direction.buy,
              amount=Decimal("1"),
              limit_price=Decimal("3100"),  # rests below market
          )
          order = response.order
          print(f"{order.order_id}: {order.order_status} @ {order.limit_price}")

          await client.disconnect()


      asyncio.run(main())
      ```

      ```rust Rust (SDK) theme={null}
      use bigdecimal::BigDecimal;
      use derive_rs::{
          Environment, WsClient,
          actions::OrderArgs,
          models::{Direction, OrderType, TimeInForce},
      };

      #[tokio::main]
      async fn main() -> Result<(), Box<dyn std::error::Error>> {
          let client = WsClient::new(
              Environment::Testnet,
              Some(std::env::var("DERIVE_PRIVATE_KEY")?),
              Some(std::env::var("DERIVE_WALLET")?),
              Some(std::env::var("DERIVE_SUBACCOUNT_ID")?.parse()?),
          )
          .await?;
          client.login().await?; // authenticate the session — required for private/*

          let order = OrderArgs::builder()
              .instrument_name("ETH-PERP".to_string())
              .direction(Direction::Buy)
              .order_type(OrderType::Limit)
              .time_in_force(TimeInForce::Gtc)
              .amount(BigDecimal::from(1))
              .limit_price(BigDecimal::from(3100)) // rests below market
              .build();

          let response = client.orders().place(order).await?;
          let order = response.order;
          println!("{}: {:?} @ {}", order.order_id, order.order_status, order.limit_price);
          Ok(())
      }
      ```
    </CodeGroup>

    <Tip>
      `maxFee` caps the fee baked into the signature; omit it and the SDK defaults
      to 3× the current taker cost. To stream your fills as they happen, subscribe
      to the `{subaccountId}.trades` channel — see [Subscriptions](/subscriptions).
    </Tip>
  </Step>
</Steps>

## Next steps

<CardGroup cols={2}>
  <Card title="Authentication" href="/authentication/session-login">
    Session login, JWT, and the wallet-vs-session-key auth paths.
  </Card>

  <Card title="Action signing" href="/authentication/action-signing">
    The full EIP-712 `Action` envelope, per-module `data` layouts, and nonces.
  </Card>

  <Card title="Session keys" href="/authentication/session-keys">
    Delegate a signing key so you never hot-wire your wallet into a bot.
  </Card>

  <Card title="Contracts" href="/getting-started/contracts">
    On-chain contract addresses per deployment (action manager, vApp, outbox,
    spot vault).
  </Card>
</CardGroup>


## Related topics

- [Programmatic Onboarding](/getting-started/depositing.md)
- [Introduction](/getting-started/introduction.md)
