OpenBook V2

repository·master·Indexed 42 days ago

https://github.com/openbook-dex/openbook-v2

A central-limit order-book (CLOB) program for Solana, based on Mango V4 and a fork of Serum. It provides core infrastructure for decentralized trading, including a TypeScript client (v0.3.0) and Rust-based tools for account fetching, orderbook simulation, and real-time data processing via account update streams.

Tokens
40.7K
Snippets
120
Records
173
Agent score
53%

What's inside OpenBook V2

  1. OpenBook V2 Licensing and GPL usage

    master

    The majority of the repository is MIT-licensed. However, some components required for compiling the Solana program are under GPL.

    Using as a dependency: If you use the openbook-v2 crate with the client or cpi features, you are only using the MIT-licensed parts. This allows you to build closed-source tools and integrations, including other Solana programs that call into OpenBook.

    GPL Restriction: Deriving a new Solana program with similar functionality to OpenBook from this codebase requires that changes and improvements remain publicly available under the GPL. All GPL code is gated behind the enable-gpl feature.

  2. Run OpenBook V2 tests

    master

    Use just to execute the test suite:

    • Run all tests: just test-all
    • Run a specific test: just test <test_name> (e.g., just test test_expired_order)
    • Development mode (auto-run on file change): If you have entr installed, run just test-dev to automatically re-run tests when files are edited.
    just test-all
  3. Install OpenBook V2

    master

    To install the repository, clone it recursively to ensure all submodules are included:

    git clone https://github.com/openbook-dex/openbook-v2.git --recursive

    If you have already cloned the repository without the --recursive flag, initialize and update the submodules manually:

    git submodule init
    git submodule update

    To ensure submodules are always handled automatically in the future, you can configure git globally:

    git config --global submodule.recurse true
  4. Build and test the TypeScript Client

    master

    To work with the TypeScript client, follow these steps:

    Build the client:

    yarn build

    Run TypeScript tests: You must export the SOL_RPC_URL and a KEYPAIR environment variable before running specific test files.

    Example for testing markets:

    export SOL_RPC_URL=https://a.b.c
    export KEYPAIR="[1,2,3,4,...]"
    yarn ts/client/src/test/market.ts

    Example for testing open orders:

    export SOL_RPC_URL=https://a.b.c
    export KEYPAIR="[1,2,3,4,...]"
    yarn ts/client/src/test/openOrders.ts
  5. How the OpenBook 'Crank' system works (Event Consumption)

    master

    OpenBook uses a 'crank' system to handle token settlement. Because place_order instructions (specifically 'take' orders) do not know which market maker they are executing against, they only emit events rather than moving tokens immediately.

    To settle trades, a user or bot must call consumeEvents or consumeGivenEvents.

    • consumeEvents: Processes up to a specified limit of AnyEvent.
      • FillEvent: Handles debits/credits to a user's Position when an order is filled. No actual tokens move; only position balances are updated.
      • OutEvent: Handles cases where a limit order must be removed from the book during a place_order invocation.
    • consumeGivenEvents: Processes events at specific provided slots.
  6. Manage slot and account state with ChainData

    master

    The ChainData struct is used to track the state of Solana slots and account writes. It maintains a history of slots and account updates, allowing you to retrieve the most recent 'live' data for an account while automatically pruning data that is no longer relevant (e.g., slots that are no longer part of the main chain or are older than the newest rooted slot).

    Key Capabilities

    • Track Slot Status: Monitor slots through SlotStatus (Rooted, Confirmed, or Processed).
    • Retrieve Account Data: Access the most recent valid account state using account() or account_and_slot().
    • Handle Updates: Update state from RPC calls via update_from_rpc() or manual updates via update_slot() and update_account().
    • Snapshotting: Generate a HashMap<Pubkey, AccountAndSlot> containing the latest live write for every tracked account via accounts_snapshot().

    Mental Model

    ChainData acts as a local cache of the blockchain state. It uses a 'live' check to ensure that when you request an account, you aren't receiving data from a fork that has been abandoned or a slot that has been superseded by a newer rooted slot.

    // Example usage pattern
    let mut chain_data = ChainData::new();
    
    // Update with new slot information
    chain_data.update_slot(SlotData {
        slot: 12345,
        parent: Some(12344),
        status: SlotStatus::Confirmed,
        chain: 12345,
    });
    
    // Update with account data
    chain_data.update_account(pubkey, AccountAndSlot {
        slot: 12345,
        account: account_shared_data,
    });
    
    // Retrieve the latest live account data
    if let Ok(account_data) = chain_data.account(&pubkey) {
        // Use account_data
    }
  7. Understand the BookSide and OrderTree structure

    master

    The bookSide account stores the order book using a binary tree of nodes.

    • roots: An array of OrderTreeRoot objects.
    • nodes: An OrderTreeNodes struct containing the actual tree data.

    OrderTreeNodes contains:

    • orderTreeType: The type of tree.
    • nodes: An array of up to 1024 AnyNode structures.

    Nodes can be:

    • InnerNode: Contains prefixLen, key, and children (indexes into BookSide::nodes).
    • LeafNode: Represents an actual order, containing owner, quantity, timestamp, clientOrderId, and pegLimit (for oracle-pegged orders).
  8. Understand the OpenBook event 'crank' system

    master

    OpenBook uses a 'crank' system for token settlement. When a user places a 'take' order, they do not know which market maker's OpenOrdersAccount will be executed against. Therefore, place_order only emits events, and a separate instruction must be called to handle settlement.

    Event Types:

    • FillEvent: Emitted when an order is filled. Handled by debiting/crediting the relevant Position for both taker and maker. Note that no actual tokens are moved during this step; it only updates position balances.
    • OutEvent: Emitted when a limit order needs to be removed from the book during a place_order invocation. Handled by crediting the maker with the tokens they would have sold.

    Settlement Instructions:

    • consumeEvents: Processes up to a specified limit of events.
    • consumeGivenEvents: Processes events at specific provided slots (u64 vector).
  9. Use AccountReader and KeyedAccountReader to abstract account access

    master

    To make functions compatible with both on-chain program logic and client-side code, use the AccountReader and KeyedAccountReader traits instead of concrete AccountInfo types.

    • AccountReader: Provides access to the account's owner() and data().
    • KeyedAccountReader: Inherits from AccountReader and adds access to the account's key().

    Implementations are provided for AccountInfoRef, AccountInfoRefMut, and (when the solana-sdk feature is enabled) KeyedAccount and KeyedAccountSharedData.