Drift Protocol v2 Documentation

repository·master·Indexed 19 days ago

https://github.com/velocity-exchange/protocol-v2

Open-source repository providing the Drift V2 TypeScript SDK and Solana Programs. Designed for developers building on the Drift ecosystem, including makers, liquidators, and fillers. Includes guides on installing the Drift CLI, building Solana programs with Anchor, configuring development environments via Devcontainers, and using the @drift-labs/sdk for account management and perpetual trading.

Tokens
65.1K
Snippets
186
Records
263
Agent score
64%

What's inside Drift Protocol v2

  1. Understand BN and Precision in the Drift SDK

    master

    The Drift SDK uses BigNum (BN) from the bn.js library to handle the high precision required by Solana tokens. All numerical values are represented as integers. To convert these to human-readable numbers, you must account for the precision constant.

    Example Calculation: A BigNum of 10,500,000 with a precision of 10^6 equals 10.5 (10,500,000 / 1,000,000).

    Common Precision Constants

    Precision NameValue
    FUNDING_RATE_BUFFER10^3
    QUOTE_PRECISION10^6
    PEG_PRECISION10^6
    PRICE_PRECISION10^6
    AMM_RESERVE_PRECISION10^9
    BASE_PRECISION10^9

    Handling Division

    Because BN only supports integer division (returning the floor), use the convertToNumber helper function to get exact decimal values.

    import { convertToNumber } from '@drift-labs/sdk';
    import { BN } from 'bn.js'; // or from @drift-labs/sdk
    
    // Using standard BN division (returns floor)
    new BN(10500).div(new BN(1000)).toNumber(); // Result: 10
    
    // Manual exact division
    new BN(10500).div(new BN(1000)).toNumber() + new BN(10500).mod(new BN(1000)).toNumber(); // Result: 10.5
    
    // Recommended: Use the SDK helper for exact values
    convertToNumber(new BN(10500), new BN(1000)); // Result: 10.5
    import {convertToNumber} from @drift-labs/sdk
    
    // Gets the floor value
    new BN(10500).div(new BN(1000)).toNumber(); // = 10
    
    // Gets the exact value
    new BN(10500).div(new BN(1000)).toNumber() + BN(10500).mod(new BN(1000)).toNumber(); // = 10.5
    
    // Also gets the exact value
    convertToNumber(new BN(10500), new BN(1000)); // = 10.5
  2. Understand the SDK Margin Calculation Snapshot

    master
    The SDK implements a single-source-of-truth margin engine that mirrors the on-chain MarginCalculation logic. Instead of calculating margin values individually for every getter, the SDK computes an immutable snapshot in a single pass. This snapshot provides a complete view of collateral, liabilities, and margin requirements (both cross and isolated) to ensure parity with the Drift program and improve performance by eliminating duplicative work.
  3. How WebSocketAccountSubscriberV2 differs from the original

    master

    The WebSocketAccountSubscriberV2 introduces several architectural improvements over the original implementation:

    • RPC Client: Utilizes gill's rpc client for account fetching.
    • WebSocket Subscriptions: Utilizes gill's rpcSubscriptions for real-time updates.
    • Address Handling: Automatically converts PublicKey to gill's Address type.
    • Response Formatting: Converts gill responses into the expected AccountInfo<Buffer> format.
    • Shutdown Mechanism: Uses the AbortSignal (Node.js/Web class) to shut down WebSocket connections synchronously.
    • Polling Mode: Adds an optional polling mechanism to handle accounts with low update frequency.
  4. How smart polling works in WebSocketProgramAccountSubscriberV2

    master

    Smart polling is designed to prevent missing updates for accounts that do not trigger WebSocket notifications frequently.

    The Logic Flow:

    1. Monitoring Period: After an account is added, the subscriber waits for a default of 30 seconds before starting to poll it.
    2. WebSocket Tracking: The subscriber tracks the timestamp of the last WebSocket notification received for each account.
    3. Conditional Polling: Polling only occurs for accounts that have not received a WebSocket notification within the last 30 seconds.
    4. Batching: To optimize RPC usage, the subscriber uses getMultipleAccounts to poll all active accounts in a single call.
    5. Dynamic Management: If a WebSocket notification is received for an account, the subscriber automatically stops polling that specific account.
    6. Missed Update Detection: The subscriber compares the current slot and buffer content against cached data. If a discrepancy is found, it triggers an automatic resubscription of the entire subscription to ensure state consistency.
  5. How to implement isomorphic code in the SDK

    master

    To add features that are only compatible with specific environments (like Node.js) without breaking the SDK for other environments (like browsers), you must implement the code using an isomorphic pattern. This ensures that incompatible libraries are not imported into the final compiled .js output for environments where they would fail.

    The Isomorphic Pattern Workflow

    1. File Structure: Create three files for your feature:

      • [your-package-name].d.ts: The definition file containing only types.
      • [your-package-name].browser.ts: The implementation for browser environments.
      • [your-package-name].node.ts: The implementation for Node.js environments.
    2. Type-Only Imports: In your logic, remove direct imports of offending libraries. Instead, use import type { ... } to import only the necessary types and place them in the .d.ts file. This prevents the actual library code from being bundled.

    3. Definition File: The .d.ts file should export types only. Other files should import from this definition file. If TypeScript flags errors because it treats the definition file as "just a type," you may use @ts-ignore, provided the types remain correct.

    4. Environment Implementations:

      • Place concrete classes, methods, and constants in the .browser.ts and .node.ts files.
      • Ensure the .d.ts file has matching types for these exports.
      • Best Practice: In the "bad" environment file (e.g., the .browser.ts file for a Node-only feature), throw an error so consumers are alerted if they attempt to use the incompatible feature.
    5. Handling Enums: Follow the pattern used by the CommitmentLevel enum in the grpc package to ensure compatibility.

    6. Build Integration: Add your package name to postbuild.js to ensure the separation is handled correctly during the build process.

  6. Build Drift Protocol v2 locally

    master

    To compile the Solana programs, install dependencies, and build the TypeScript SDK, follow these steps in order:

    1. Compile Programs: Use anchor build to compile the Solana programs.
    2. Install Dependencies: Run yarn at the root to install package dependencies.
    3. Build SDK: Navigate to the sdk/ directory, install its specific dependencies, and run the build command.

    Note for Apple M1 users: If you are on an M1 chip, you must set your default Rust toolchain to stable-x86_64-apple-darwin before building:

    rustup default stable-x86_64-apple-darwin
    # build v2
    anchor build
    # install packages
    yarn
    # build sdk
    cd sdk/ && yarn && yarn build && cd ..
  7. Set up a wallet for your program

    master

    Before interacting with the Drift SDK, you need a Solana keypair to act as your bot/program wallet. Follow these steps:

    1. Generate a new keypair using the Solana CLI:
      solana-keygen new
    2. **Retrieve the public key** to identify your address:
       ```bash
    solana address

    Note: On mainnet, you must send USDC to this address to deposit into Drift. On devnet, you can use a faucet. 3. Configure your environment by adding the private key to a .env file in your project directory:

    echo BOT_PRIVATE_KEY=`cat ~/.config/solana/id.json` >> .env
  8. Install the Drift CLI

    master

    To install and initialize the Drift CLI, run the following sequence of commands to install dependencies, compile the TypeScript source, link the package locally, and initialize the configuration.

    Note: This process requires yarn, tsc (TypeScript compiler), and npm to be installed on your system.

    yarn &&
    tsc &&
    npm link &&
    drift config init
  9. Set up a development environment with Devcontainers

    master

    The repository includes a Dockerfile in the .devcontainer directory to provide a pre-configured environment with the correct versions of Rust, Solana, and Anchor.

    1. Build the container

    Build and tag the image as drift-dev:

    cd .devcontainer && docker build -t drift-dev .

    2. Access the container

    Via CLI: First, find the container ID using docker ps, then execute a bash shell:

    docker ps
    docker exec -it <CONTAINER_ID> /bin/bash

    Via IDE (VS Code/Cursor):

    1. Press Ctrl+Shift+P (or Cmd+Shift+P on Mac).
    2. Select Dev Containers: Reopen in Container.
    3. Wait for the build to complete. The IDE terminal will automatically target the container.

    3. Common tasks inside the Devcontainer

    Once inside, you can run standard development commands:

    • Build program: anchor build
    • Update IDL: anchor build -- --features anchor-test && cp target/idl/drift.json sdk/src/idl/drift.json
    • Run cargo tests: cargo test
    • Run typescript tests: bash test-scripts/run-anchor-tests.sh
    # Build the container
    cd .devcontainer && docker build -t drift-dev .
    
    # Exec into it
    docker ps
    docker exec -it <CONTAINER_ID> /bin/bash
  10. Run integration tests for openbook-v2-light

    master

    To run the integration tests for the openbook-v2-light package, you must first build the Anchor programs and then execute the specific integration test suite using cargo test-sbf.

    Note: Integration tests are located in integration.rs within the package.

    ```bash
    anchor build
    cargo test-sbf --package openbook-v2-light --test integration
    ```埋