Skip to Content
DevelopersDrift SDKSetup

Setup

The examples below use placeholders like <RPC_URL> and <KEYPAIR_PATH>.

Program Addresses

The Drift program id is environment-specific. In most cases you’ll use the default program id baked into the SDK config for devnet or mainnet-beta.

Wallet / Authentication

To interact with Solana you need a keypair. One common approach for bots is to point ANCHOR_WALLET (or your own env var) at a JSON keypair file.

solana-keygen new --outfile ~/.config/solana/my-keypair.json export ANCHOR_WALLET=~/.config/solana/my-keypair.json

Install

npm i @drift-labs/sdk

Create a Drift Client

At a minimum you provide a Solana connection, a wallet, and the env. Then call subscribe() to start receiving account updates.

import { Connection } from "@solana/web3.js"; import { DriftClient, Wallet, loadKeypair } from "@drift-labs/sdk"; const connection = new Connection("<RPC_URL>", "confirmed"); const wallet = new Wallet(loadKeypair("<KEYPAIR_PATH>")); const driftClient = new DriftClient({ connection, wallet, env: "mainnet-beta", }); await driftClient.subscribe();
await driftClient.subscribe();
Method DriftClient.subscribeReference ↗
Returns
Promise<boolean>
await driftClient.unsubscribe();
Method DriftClient.unsubscribeReference ↗
Returns
Promise<void>

Account Subscriptions (WebSocket vs Polling)

For most bots, websocket subscriptions are the easiest way to keep markets and users up to date. For read-only workflows or when you need tighter control over RPC load, you can switch to polling with a BulkAccountLoader.

import { BulkAccountLoader } from "@drift-labs/sdk";
Class BulkAccountLoaderReference ↗
PropertyTypeRequired
connection
Connection
Yes
commitment
Commitment
Yes
pollingFrequency
number
Yes
accountsToLoad
Map<string, AccountToLoad>
Yes
bufferAndSlotMap
Map<string, BufferAndSlot>
Yes
errorCallbacks
Map<string, (e: any) => void>
Yes
intervalId
Timeout
No
loadPromise
Promise<void>
No
loadPromiseResolver
() => void
Yes
lastTimeLoadingPromiseCleared
number
Yes
mostRecentSlot
number
Yes
addAccount
(publicKey: PublicKey, callback: (buffer: Buffer, slot: number) => void) => Promise<string>
Yes
removeAccount
(publicKey: PublicKey, callbackId: string) => void
Yes
addErrorCallbacks
(callback: (error: Error) => void) => string
Yes
removeErrorCallbacks
(callbackId: string) => void
Yes
chunks
<T>(array: readonly T[], size: number) => T[][]
Yes
load
() => Promise<void>
Yes
loadChunk
(accountsToLoadChunks: AccountToLoad[][]) => Promise<void>
Yes
handleAccountCallbacks
(accountToLoad: AccountToLoad, buffer: Buffer, slot: number) => void
Yes
getBufferAndSlot
(publicKey: PublicKey) => BufferAndSlot | undefined
Yes
getSlot
() => number
Yes
startPolling
() => void
Yes
stopPolling
() => void
Yes
log
(msg: string) => void
Yes
updatePollingFrequency
(pollingFrequency: number) => void
Yes
import { BulkAccountLoader } from "@drift-labs/sdk"; const accountLoader = new BulkAccountLoader(connection, "confirmed", 0); const driftClient = new DriftClient({ connection, wallet, env: "mainnet-beta", accountSubscription: { type: "polling", accountLoader, }, // Optional: explicitly list markets/oracles to load. // perpMarketIndexes: [0, 1], // spotMarketIndexes: [0], // oracleInfos: [{ publicKey: ORACLE_PUBKEY, source: ORACLE_SOURCE }], });
Example Polling subscriptionReference ↗
TypeScript docs unavailable for Polling subscription.

Multiple Subaccounts

if (!driftClient.hasUser(1)) { await driftClient.addUser(1); }
Method DriftClient.hasUserReference ↗
ParameterTypeRequired
subAccountId
number
No
authority
PublicKey
No
Returns
boolean
await driftClient.addUser(1);
Method DriftClient.addUserReference ↗
ParameterTypeRequired
subAccountId
number
Yes
authority
PublicKey
No
userAccount
UserAccount
No
Returns
Promise<boolean>

Program ID

import { DRIFT_PROGRAM_ID } from "@drift-labs/sdk"; // The Drift program's public key on mainnet-beta. // Use this when deriving PDAs or referencing the program directly. console.log(DRIFT_PROGRAM_ID.toBase58());
Variable DRIFT_PROGRAM_IDReference ↗
PropertyTypeRequired
toString
() => string
Yes
charAt
(pos: number) => string
Yes
charCodeAt
(index: number) => number
Yes
concat
(...strings: string[]) => string
Yes
indexOf
(searchString: string, position?: number | undefined) => number
Yes
lastIndexOf
(searchString: string, position?: number | undefined) => number
Yes
localeCompare
{ (that: string): number; (that: string, locales?: string | string[] | undefined, options?: CollatorOptions | undefined): number; (that: string, locales?: LocalesArgument, options?: CollatorOptions | undefined): number; }
Yes
match
{ (regexp: string | RegExp): RegExpMatchArray | null; (matcher: { [Symbol.match](string: string): RegExpMatchArray | null; }): RegExpMatchArray | null; }
Yes
replace
{ (searchValue: string | RegExp, replaceValue: string): string; (searchValue: string | RegExp, replacer: (substring: string, ...args: any[]) => string): string; (searchValue: { ...; }, replaceValue: string): string; (searchValue: { ...; }, replacer: (substring: string, ...args: any[]) => string): string; }
Yes
search
{ (regexp: string | RegExp): number; (searcher: { [Symbol.search](string: string): number; }): number; }
Yes
slice
(start?: number | undefined, end?: number | undefined) => string
Yes
split
{ (separator: string | RegExp, limit?: number | undefined): string[]; (splitter: { [Symbol.split](string: string, limit?: number | undefined): string[]; }, limit?: number | undefined): string[]; }
Yes
substring
(start: number, end?: number | undefined) => string
Yes
toLowerCase
() => string
Yes
toLocaleLowerCase
{ (locales?: string | string[] | undefined): string; (locales?: LocalesArgument): string; }
Yes
toUpperCase
() => string
Yes
toLocaleUpperCase
{ (locales?: string | string[] | undefined): string; (locales?: LocalesArgument): string; }
Yes
trim
() => string
Yes
length
number
Yes
substr
(from: number, length?: number | undefined) => string
Yes
valueOf
() => string
Yes
codePointAt
(pos: number) => number | undefined
Yes
includes
(searchString: string, position?: number | undefined) => boolean
Yes
endsWith
(searchString: string, endPosition?: number | undefined) => boolean
Yes
normalize
{ (form: "NFC" | "NFD" | "NFKC" | "NFKD"): string; (form?: string | undefined): string; }
Yes
repeat
(count: number) => string
Yes
startsWith
(searchString: string, position?: number | undefined) => boolean
Yes
anchor
(name: string) => string
Yes
big
() => string
Yes
blink
() => string
Yes
bold
() => string
Yes
fixed
() => string
Yes
fontcolor
(color: string) => string
Yes
fontsize
{ (size: number): string; (size: string): string; }
Yes
italics
() => string
Yes
link
(url: string) => string
Yes
small
() => string
Yes
strike
() => string
Yes
sub
() => string
Yes
sup
() => string
Yes
padStart
(maxLength: number, fillString?: string | undefined) => string
Yes
padEnd
(maxLength: number, fillString?: string | undefined) => string
Yes
trimEnd
() => string
Yes
trimStart
() => string
Yes
trimLeft
() => string
Yes
trimRight
() => string
Yes
matchAll
(regexp: RegExp) => RegExpStringIterator<RegExpExecArray>
Yes
replaceAll
{ (searchValue: string | RegExp, replaceValue: string): string; (searchValue: string | RegExp, replacer: (substring: string, ...args: any[]) => string): string; }
Yes
at
(index: number) => string | undefined
Yes
isWellFormed
() => boolean
Yes
toWellFormed
() => string
Yes
__@iterator@671
() => StringIterator<string>
Yes

High Leverage Mode

import { getHighLeverageModeConfigPublicKey } from "@drift-labs/sdk"; const pda = getHighLeverageModeConfigPublicKey(driftClient.program.programId); const config = await driftClient.program.account.highLeverageModeConfig.fetch(pda);
Function getHighLeverageModeConfigPublicKeyReference ↗
ParameterTypeRequired
programId
PublicKey
Yes
Returns
PublicKey
Last updated on