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.jsonInstall
npm i @drift-labs/sdkCreate 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 ↗
Method DriftClient.subscribeReference ↗| Returns |
|---|
Promise<boolean> |
await driftClient.unsubscribe();Method DriftClient.unsubscribeReference ↗
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 ↗
Class BulkAccountLoaderReference ↗| Property | Type | Required |
|---|---|---|
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 ↗
Example Polling subscriptionReference ↗TypeScript docs unavailable for
Polling subscription.Multiple Subaccounts
if (!driftClient.hasUser(1)) {
await driftClient.addUser(1);
}Method DriftClient.hasUserReference ↗
Method DriftClient.hasUserReference ↗| Parameter | Type | Required |
|---|---|---|
subAccountId | number | No |
authority | PublicKey | No |
| Returns |
|---|
boolean |
await driftClient.addUser(1);Method DriftClient.addUserReference ↗
Method DriftClient.addUserReference ↗| Parameter | Type | Required |
|---|---|---|
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 ↗
Variable DRIFT_PROGRAM_IDReference ↗| Property | Type | Required |
|---|---|---|
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 ↗
Function getHighLeverageModeConfigPublicKeyReference ↗| Parameter | Type | Required |
|---|---|---|
programId | PublicKey | Yes |
| Returns |
|---|
PublicKey |
Last updated on