### Install Drift Protocol SDK Source: https://github.com/drift-labs/protocol-v2/blob/master/sdk/README.md Install the Drift Protocol v2 SDK using npm. This is the first step for integrating with Drift. ```bash npm i @drift-labs/sdk ``` -------------------------------- ### Generate Solana Keypair and Set Environment Variable Source: https://github.com/drift-labs/protocol-v2/blob/master/sdk/README.md Generate a new Solana keypair for your program's wallet. After generating, get the public key and set the private key in your .env file for bot usage. Note that USDC is required for deposits on mainnet. ```bash # Generate a keypair solana-keygen new # Get the pubkey for the new wallet (You will need to send USDC to this address to Deposit into Drift (only on mainnet - devnet has a faucet for USDC)) solana address # Put the private key into your .env to be used by your bot cd {projectLocation} echo BOT_PRIVATE_KEY=`cat ~/.config/solana/id.json` >> .env ``` -------------------------------- ### Compile Drift Protocol v2 Programs Source: https://github.com/drift-labs/protocol-v2/blob/master/README.md Commands to build the v2 programs, install yarn packages, and build the SDK. Ensure you are in the project root directory. ```bash # build v2 anchor build # install packages yarn # build sdk cd sdk/ && yarn && yarn build && cd .. ``` -------------------------------- ### Initialize Drift SDK, Wallet, and User Account Source: https://github.com/drift-labs/protocol-v2/blob/master/sdk/README.md Sets up the Drift SDK, wallet, and provider, then initializes a user account with a collateral deposit if one doesn't exist. Ensure ANCHOR_WALLET and ANCHOR_PROVIDER_URL environment variables are set. ```typescript import * as anchor from '@coral-xyz/anchor'; import { AnchorProvider } from '@coral-xyz/anchor'; import { getAssociatedTokenAddress, TOKEN_PROGRAM_ID } from '@solana/spl-token'; import { Connection, Keypair, PublicKey } from '@solana/web3.js'; import { calculateReservePrice, DriftClient, User, initialize, PositionDirection, convertToNumber, calculateTradeSlippage, PRICE_PRECISION, QUOTE_PRECISION, Wallet, PerpMarkets, BASE_PRECISION, getMarketOrderParams, BulkAccountLoader, BN, calculateBidAskPrice, getMarketsAndOraclesForSubscription, calculateEstimatedPerpEntryPrice, } from '../sdk'; export const getTokenAddress = ( mintAddress: string, userPubKey: string ): Promise => { return getAssociatedTokenAddress( new PublicKey(mintAddress), new PublicKey(userPubKey) ); }; const main = async () => { const env = 'devnet'; // const env = 'mainnet-beta'; // Initialize Drift SDK const sdkConfig = initialize({ env }); // Set up the Wallet and Provider if (!process.env.ANCHOR_WALLET) { throw new Error('ANCHOR_WALLET env var must be set.'); } if (!process.env.ANCHOR_PROVIDER_URL) { throw new Error('ANCHOR_PROVIDER_URL env var must be set.'); } const provider = anchor.AnchorProvider.local( process.env.ANCHOR_PROVIDER_URL, { preflightCommitment: 'confirmed', skipPreflight: false, commitment: 'confirmed', } ); // Check SOL Balance const lamportsBalance = await provider.connection.getBalance( provider.wallet.publicKey ); console.log( provider.wallet.publicKey.toString(), env, 'SOL balance:', lamportsBalance / 10 ** 9 ); // Misc. other things to set up const usdcTokenAddress = await getTokenAddress( sdkConfig.USDC_MINT_ADDRESS, provider.wallet.publicKey.toString() ); // Set up the Drift Client const driftPublicKey = new PublicKey(sdkConfig.DRIFT_PROGRAM_ID); const bulkAccountLoader = new BulkAccountLoader( provider.connection, 'confirmed', 1000 ); const driftClient = new DriftClient({ connection: provider.connection, wallet: provider.wallet, programID: driftPublicKey, accountSubscription: { type: 'polling', accountLoader: bulkAccountLoader, }, }); await driftClient.subscribe(); console.log('subscribed to driftClient'); // Set up user client const user = new User({ driftClient: driftClient, userAccountPublicKey: await driftClient.getUserAccountPublicKey(), accountSubscription: { type: 'polling', accountLoader: bulkAccountLoader, }, }); //// Check if user account exists for the current wallet const userAccountExists = await user.exists(); if (!userAccountExists) { console.log( 'initializing to', env, ' drift account for', provider.wallet.publicKey.toString() ); //// Create a Drift V2 account by Depositing some USDC ($10,000 in this case) const depositAmount = new BN(10000).mul(QUOTE_PRECISION); await driftClient.initializeUserAccountAndDepositCollateral( depositAmount, await getTokenAddress( usdcTokenAddress.toString(), provider.wallet.publicKey.toString() ) ); } await user.subscribe(); // Get current price const solMarketInfo = PerpMarkets[env].find( (market) => market.baseAssetSymbol === 'SOL' ); const marketIndex = solMarketInfo.marketIndex; // Get vAMM bid and ask price const [bid, ask] = calculateBidAskPrice( driftClient.getPerpMarketAccount(marketIndex).amm, driftClient.getOracleDataForPerpMarket(marketIndex) ); const formattedBidPrice = convertToNumber(bid, PRICE_PRECISION); const formattedAskPrice = convertToNumber(ask, PRICE_PRECISION); console.log( env, `vAMM bid: $${formattedBidPrice} and ask: $${formattedAskPrice}` ); const solMarketAccount = driftClient.getPerpMarketAccount( solMarketInfo.marketIndex ); console.log(env, `Placing a 1 SOL-PERP LONG order`); const txSig = await driftClient.placePerpOrder( getMarketOrderParams({ baseAssetAmount: new BN(1).mul(BASE_PRECISION), direction: PositionDirection.LONG, marketIndex: solMarketAccount.marketIndex, }) ); console.log( env, `Placed a 1 SOL-PERP LONG order. Tranaction signature: $${txSig}` ); }; main(); ``` -------------------------------- ### Run Openbook V2 Integration Test Source: https://github.com/drift-labs/protocol-v2/blob/master/programs/openbook_v2/README.md Use these commands to build and run the integration tests for the Openbook V2 light client. Note that these tests may fail on Apple M x chips due to deserialization issues with SpotMarket data. ```bash anchor build cargo test-sbf --package openbook-v2-light --test integration ``` -------------------------------- ### Instantiate and Subscribe to Account Changes Source: https://github.com/drift-labs/protocol-v2/blob/master/sdk/src/accounts/README_WebSocketAccountSubscriberV2.md Demonstrates how to instantiate WebSocketAccountSubscriberV2 and subscribe to account updates. Ensure you have the necessary imports and program instance. ```typescript import { WebSocketAccountSubscriberV2 } from './accounts/webSocketAccountSubscriberV2'; const subscriber = new WebSocketAccountSubscriberV2( 'userAccount', // account name program, // Anchor program instance userAccountPublicKey, // PublicKey of the account to subscribe to decodeBuffer, // optional custom decode function resubOpts, // optional resubscription options commitment // optional commitment level ); // Subscribe to account changes await subscriber.subscribe((data) => { console.log('Account updated:', data); }); // Unsubscribe when done await subscriber.unsubscribe(); ``` -------------------------------- ### Migrating to WebSocketProgramAccountSubscriberV2 Source: https://github.com/drift-labs/protocol-v2/blob/master/sdk/src/accounts/README_WebSocketProgramAccountSubscriberV2.md Demonstrates the straightforward migration from V1 to V2, showing that the constructor interface remains the same. Also illustrates the new capability to pass accounts for polling directly to the V2 constructor. ```typescript // V1 const subscriber = new WebSocketProgramAccountSubscriber(...); // V2 (same interface) const subscriber = new WebSocketProgramAccountSubscriberV2(...); // V2 with polling (new feature) const subscriber = new WebSocketProgramAccountSubscriberV2(..., accountsToPoll); ``` -------------------------------- ### Initialize WebSocketProgramAccountSubscriberV2 Source: https://github.com/drift-labs/protocol-v2/blob/master/sdk/src/accounts/README_WebSocketProgramAccountSubscriberV2.md Instantiate the subscriber with account details, program, decode function, options, resubscription options, and an optional list of accounts to poll. ```typescript import { WebSocketProgramAccountSubscriberV2 } from './accounts/webSocketProgramAccountSubscriberV2'; // Create subscriber with optional accounts to poll const subscriber = new WebSocketProgramAccountSubscriberV2( 'perpMarket', // account name 'perpMarket', // account discriminator program, // Anchor program instance decodeBuffer, // decode function { filters: [] }, // options resubOpts, // optional resubscription options [longTailMarket1, longTailMarket2] // optional list of accounts to poll ); // Subscribe to program account changes await subscriber.subscribe((accountId, data, context, buffer) => { console.log('Account updated:', accountId.toBase58(), data); }); // Add more accounts to poll dynamically subscriber.addAccountToPoll(newMarketPublicKey); // Remove accounts from polling subscriber.removeAccountFromPoll(oldMarketPublicKey); // Change polling interval subscriber.setPollingInterval(60000); // 60 seconds // Unsubscribe when done await subscriber.unsubscribe(); ``` -------------------------------- ### Build Drift Devcontainer Source: https://github.com/drift-labs/protocol-v2/blob/master/README.md Build the Docker container for development and tag it as 'drift-dev'. This image includes the necessary versions of Rust, Solana, and Anchor. ```bash cd .devcontainer && docker build -t drift-dev . ``` -------------------------------- ### Initialize Gill Solana Client Source: https://github.com/drift-labs/protocol-v2/blob/master/sdk/src/accounts/README_WebSocketAccountSubscriberV2.md Illustrates how to create RPC and WebSocket clients using gill's createSolanaClient function. This is a foundational step for interacting with the Solana blockchain via gill. ```typescript import { createSolanaClient } from 'gill'; const { rpc, rpcSubscriptions } = createSolanaClient({ urlOrMoniker: rpcUrl, // or "mainnet", "devnet", etc. }); ``` -------------------------------- ### Run Javascript Tests Source: https://github.com/drift-labs/protocol-v2/blob/master/README.md Execute the provided script to run Javascript tests for the project. ```bash bash test-scripts/run-anchor-tests.sh ``` -------------------------------- ### User Class Margin Calculation Entrypoint Source: https://github.com/drift-labs/protocol-v2/blob/master/sdk/src/margin/README.md The `User` class serves as the primary entrypoint for obtaining margin calculations. It allows specifying the margin category and optional parameters for strictness, open orders inclusion, high leverage mode, and liquidation buffers. ```typescript public getMarginCalculation( marginCategory: MarginCategory = 'Initial', opts?: { strict?: boolean; // mirror StrictOraclePrice application includeOpenOrders?: boolean; // include open orders in margin calc enteringHighLeverage?: boolean; // entering high leverage mode liquidationBufferMap?: Map; // margin buffer for liquidation mode } ): MarginCalculation; ``` -------------------------------- ### Set Rust Toolchain for M1 Macs Source: https://github.com/drift-labs/protocol-v2/blob/master/README.md If building on an Apple computer with an M1 chip, set the default Rust toolchain to stable-x86_64-apple-darwin. ```bash rustup default stable-x86_64-apple-darwin ``` -------------------------------- ### IDE Devcontainer Integration Source: https://github.com/drift-labs/protocol-v2/blob/master/README.md Instructions for reopening your IDE (like VS Code or Cursor) in the devcontainer. This ensures your development environment has the correct tool versions. ```bash 1. Press Ctrl+Shift+P (or Cmd+Shift+P on Mac) 2. Type "Dev Containers: Reopen in Container" 3. Select it and wait for the container to build 4. The IDE terminal should be targeting the dev container now ``` -------------------------------- ### Configure Polling for Infrequently Updated Accounts Source: https://github.com/drift-labs/protocol-v2/blob/master/sdk/src/accounts/README_WebSocketAccountSubscriberV2.md Shows how to configure WebSocketAccountSubscriberV2 to use polling instead of resubscribing for accounts that update rarely. This reduces resource usage by periodically checking for updates. ```typescript const resubOpts = { resubTimeoutMs: 30000, // 30 seconds logResubMessages: true, usePollingInsteadOfResub: true, // Enable polling mode pollingIntervalMs: 30000, // Poll every 30 seconds (optional, defaults to 30000) }; const subscriber = new WebSocketAccountSubscriberV2( 'perpMarket', // account name program, marketPublicKey, undefined, // decodeBuffer resubOpts ); ``` -------------------------------- ### Development Commands within Devcontainer Source: https://github.com/drift-labs/protocol-v2/blob/master/README.md Common development commands to run inside the Drift devcontainer, including building programs, updating the IDL, and running tests. ```bash # 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 ``` -------------------------------- ### Set Rust Version for Cargo Tests Source: https://github.com/drift-labs/protocol-v2/blob/master/README.md Set the Rust toolchain override to version 1.70 for running cargo tests. Solana CLI version 1.16.27 is also recommended. ```bash rustup override set 1.70 cargo test ``` -------------------------------- ### getMarginCalculation Source: https://github.com/drift-labs/protocol-v2/blob/master/sdk/src/margin/README.md Computes and returns a margin calculation snapshot for a user. ```APIDOC ## getMarginCalculation ### Description Computes and returns a margin calculation snapshot for a user. This snapshot mirrors the on-chain `MarginCalculation` and related semantics, providing an immutable view of the user's margin status. ### Method ```ts getMarginCalculation( marginCategory: MarginCategory = 'Initial', opts?: { strict?: boolean; // mirror StrictOraclePrice application includeOpenOrders?: boolean; // include open orders in margin calc enteringHighLeverage?: boolean; // entering high leverage mode liquidationBufferMap?: Map; // margin buffer for liquidation mode } ): MarginCalculation; ``` ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body None ### Parameters - **marginCategory**: ('Initial' | 'Maintenance' | 'Fill') - Optional - The category of margin to calculate. Defaults to 'Initial'. - **opts**: (object) - Optional - Additional options for the calculation. - **strict**: (boolean) - Optional - If true, mirrors StrictOraclePrice application. - **includeOpenOrders**: (boolean) - Optional - If true, includes open orders in the margin calculation. - **enteringHighLeverage**: (boolean) - Optional - If true, indicates entering high leverage mode. - **liquidationBufferMap**: (Map) - Optional - A map specifying margin buffers for liquidation mode. ### Request Example ```ts // Example usage: const marginCalcSnapshot = user.getMarginCalculation('Initial', { includeOpenOrders: true, liquidationBufferMap: new Map([ [0, new BN(10000)], // Example buffer for market index 0 ['cross', new BN(5000)] // Example cross margin buffer ]) }); ``` ### Response #### Success Response (MarginCalculation) - **context**: (MarginContext) - The margin calculation context. - **totalCollateral**: (BN) - The total collateral (i128). - **totalCollateralBuffer**: (BN) - The total collateral buffer (i128). - **marginRequirement**: (BN) - The margin requirement (u128). - **marginRequirementPlusBuffer**: (BN) - The margin requirement plus buffer (u128). - **isolatedMarginCalculations**: (Map) - A map of isolated margin calculations keyed by market index. - **totalPerpLiabilityValue**: (BN) - The total value of open perpetual futures liabilities (u128). #### Response Example ```json { "context": { "marginType": "Initial", "mode": {"type": "Standard"}, "strict": false, "ignoreInvalidDepositOracles": false, "isolatedMarginBuffers": {}, "crossMarginBuffer": "0" }, "totalCollateral": "100000000000000000000", "totalCollateralBuffer": "95000000000000000000", "marginRequirement": "50000000000000000000", "marginRequirementPlusBuffer": "145000000000000000000", "isolatedMarginCalculations": { "0": { "marginRequirement": "20000000000000000000", "totalCollateral": "30000000000000000000", "totalCollateralBuffer": "25000000000000000000", "marginRequirementPlusBuffer": "45000000000000000000" } }, "totalPerpLiabilityValue": "70000000000000000000" } ``` ``` -------------------------------- ### Open Shell in Drift Devcontainer Source: https://github.com/drift-labs/protocol-v2/blob/master/README.md Commands to open a bash shell within the running Drift development container. First, find the container ID using 'docker ps', then use 'docker exec'. ```bash # Find the container ID first docker ps # Then exec into it docker exec -it /bin/bash ``` -------------------------------- ### BigNum Division with Exact Value Source: https://github.com/drift-labs/protocol-v2/blob/master/sdk/README.md Demonstrates how to perform exact division with BigNum objects in TypeScript, accounting for remainders. Use the `convertToNumber` helper function from the SDK for precise calculations. ```typescript 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 ``` -------------------------------- ### Core SDK Margin Types Source: https://github.com/drift-labs/protocol-v2/blob/master/sdk/src/margin/README.md Defines the TypeScript types for margin calculation, including categories, modes, market identification, and detailed margin calculation structures. These types mirror on-chain names and numeric signs. ```typescript import { MarketType } from './types'; export type MarginCategory = 'Initial' | 'Maintenance' | 'Fill'; export type MarginCalculationMode = | { type: 'Standard' } | { type: 'Liquidation' }; export class MarketIdentifier { marketType: MarketType; marketIndex: number; static spot(marketIndex: number): MarketIdentifier; static perp(marketIndex: number): MarketIdentifier; equals(other: MarketIdentifier | undefined): boolean; } export class MarginContext { marginType: MarginCategory; mode: MarginCalculationMode; strict: boolean; ignoreInvalidDepositOracles: boolean; isolatedMarginBuffers: Map; crossMarginBuffer: BN; // Factory methods static standard(marginType: MarginCategory): MarginContext; static liquidation( crossMarginBuffer: BN, isolatedMarginBuffers: Map ): MarginContext; // Builder methods (return this for chaining) strictMode(strict: boolean): this; ignoreInvalidDeposits(ignore: boolean): this; setCrossMarginBuffer(crossMarginBuffer: BN): this; setIsolatedMarginBuffers(isolatedMarginBuffers: Map): this; setIsolatedMarginBuffer(marketIndex: number, isolatedMarginBuffer: BN): this; } export class IsolatedMarginCalculation { marginRequirement: BN; // u128 totalCollateral: BN; // i128 (deposit + pnl) totalCollateralBuffer: BN; // i128 marginRequirementPlusBuffer: BN; // u128 getTotalCollateralPlusBuffer(): BN; meetsMarginRequirement(): boolean; meetsMarginRequirementWithBuffer(): boolean; marginShortage(): BN; } export class MarginCalculation { context: MarginContext; totalCollateral: BN; // i128 totalCollateralBuffer: BN; // i128 marginRequirement: BN; // u128 marginRequirementPlusBuffer: BN; // u128 isolatedMarginCalculations: Map; totalPerpLiabilityValue: BN; // u128 // Cross margin helpers getCrossTotalCollateralPlusBuffer(): BN; meetsCrossMarginRequirement(): boolean; meetsCrossMarginRequirementWithBuffer(): boolean; getCrossFreeCollateral(): BN; // Combined (cross + isolated) helpers meetsMarginRequirement(): boolean; meetsMarginRequirementWithBuffer(): boolean; // Isolated margin helpers getIsolatedFreeCollateral(marketIndex: number): BN; getIsolatedMarginCalculation(marketIndex: number): IsolatedMarginCalculation | undefined; hasIsolatedMarginCalculation(marketIndex: number): boolean; } ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.