COMMON_UTILS
TheCOMMON_UTILS object contains a collection of helper functions for market data, math operations, and data manipulation.
Market Data Utilities
Getting Open Interest
import { COMMON_UTILS } from '@drift-labs/common';
import { MarketType, DriftClient } from '@drift-labs/sdk';
const marketIndex = 0; // SOL-PERP
const marketType = MarketType.PERP;
// Get current open interest in quote currency (USD)
const openInterest = COMMON_UTILS.getCurrentOpenInterestForMarket(
marketIndex,
marketType,
driftClient
);
console.log(`Open Interest: $${openInterest.toLocaleString()}`);
Getting Deposit APR
import { MarketType } from '@drift-labs/sdk';
// Get deposit APR for a spot market (in percent)
const marketIndex = 1; // USDC spot market
const depositApr = COMMON_UTILS.getDepositAprForMarket(
marketIndex,
MarketType.SPOT,
driftClient
);
console.log(`Deposit APR: ${depositApr.toFixed(2)}%`);
Getting Borrow APR
// Get borrow APR for a spot market (in percent)
const borrowApr = COMMON_UTILS.getBorrowAprForMarket(
marketIndex,
MarketType.SPOT,
driftClient
);
console.log(`Borrow APR: ${borrowApr.toFixed(2)}%`);
Getting Total Borrows and Deposits
import { MainnetSpotMarkets } from '@drift-labs/sdk';
const usdcMarket = MainnetSpotMarkets[1]; // USDC
// Get total borrows
const totalBorrows = COMMON_UTILS.getTotalBorrowsForMarket(
usdcMarket,
driftClient
);
console.log(`Total Borrows: $${totalBorrows.toLocaleString()}`);
// Get total deposits
const { totalDepositsBase, totalDepositsQuote } =
COMMON_UTILS.getTotalDepositsForMarket(usdcMarket, driftClient);
console.log(`Total Deposits: ${totalDepositsBase} USDC ($${totalDepositsQuote})`);
Mathematical Utilities
Number Math
const values = [10, 20, 30, 40, 50];
// Calculate mean
const mean = COMMON_UTILS.MATH.NUM.mean(values);
console.log('Mean:', mean); // 30
// Calculate median
const median = COMMON_UTILS.MATH.NUM.median(values);
console.log('Median:', median); // 30
BN (BigNumber) Math
import { BN } from '@drift-labs/sdk';
const bnValues = [
new BN(100),
new BN(200),
new BN(300),
new BN(400),
new BN(500),
];
// Calculate max
const max = COMMON_UTILS.MATH.BN.bnMax(bnValues);
console.log('Max:', max.toString()); // "500"
// Calculate min
const min = COMMON_UTILS.MATH.BN.bnMin(bnValues);
console.log('Min:', min.toString()); // "100"
// Calculate mean
const bnMean = COMMON_UTILS.MATH.BN.bnMean(bnValues);
console.log('Mean:', bnMean.toString()); // "300"
// Calculate median
const bnMedian = COMMON_UTILS.MATH.BN.bnMedian(bnValues);
console.log('Median:', bnMedian.toString()); // "300"
Z-Score Calculation
// Calculate how many standard deviations a value is from the mean
const historicalPrices = [100, 102, 98, 105, 97, 103, 99, 101];
const currentPrice = 110;
const zScore = COMMON_UTILS.calculateZScore(currentPrice, historicalPrices);
console.log(`Z-Score: ${zScore.toFixed(2)}`);
// Positive = above mean, Negative = below mean
Data Manipulation Utilities
Chunking Arrays
const items = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
// Split into chunks of 3
const chunks = COMMON_UTILS.chunks(items, 3);
console.log(chunks);
// [[1, 2, 3], [4, 5, 6], [7, 8, 9], [10]]
Gluing Arrays
const elements = [1, 2, 3, 4, 5, 6];
// Group every 2 elements together
const glued = COMMON_UTILS.glueArray(2, elements);
console.log(glued);
// [[1, 2], [3, 4], [5, 6]]
Fetching Multiple Accounts
import { Connection, PublicKey } from '@solana/web3.js';
const connection = new Connection('https://api.mainnet-beta.solana.com');
const accounts = [
new PublicKey('...'),
new PublicKey('...'),
// ... many more accounts
];
// Automatically chunks requests to avoid RPC limits
const accountInfos = await COMMON_UTILS.getMultipleAccountsInfoChunked(
connection,
accounts
);
accountInfos.forEach((info, index) => {
if (info) {
console.log(`Account ${index}:`, info.data.length, 'bytes');
}
});
String Utilities
// Convert to snake_case
const snakeCase = COMMON_UTILS.toSnakeCase('myVariableName');
console.log(snakeCase); // "my_variable_name"
// Convert to camelCase
const camelCase = COMMON_UTILS.toCamelCase('my_variable_name');
console.log(camelCase); // "myVariableName"
// Normalize base asset symbols
const normalized = COMMON_UTILS.normalizeBaseAssetSymbol('1MSOL');
console.log(normalized); // "SOL"
Validation Utilities
// Check if numbers divide exactly (accounting for floating point)
const dividesExactly = COMMON_UTILS.dividesExactly(10, 5);
console.log(dividesExactly); // true
const doesNotDivide = COMMON_UTILS.dividesExactly(10, 3);
console.log(doesNotDivide); // false
ENUM_UTILS
Utilities for working with Anchor-style enums (objects with a single key).Enum Comparison
import { ENUM_UTILS } from '@drift-labs/common';
import { OrderType } from '@drift-labs/sdk';
const orderType1 = { market: {} };
const orderType2 = { market: {} };
const orderType3 = { limit: {} };
// Compare enums
const isMatch = ENUM_UTILS.match(orderType1, orderType2);
console.log(isMatch); // true
const isDifferent = ENUM_UTILS.match(orderType1, orderType3);
console.log(isDifferent); // false
Enum Conversion
// Convert string to enum object
const enumObj = ENUM_UTILS.toObj('market');
console.log(enumObj); // { market: {} }
// Convert enum object to string
const enumStr = ENUM_UTILS.toStr({ market: {} });
console.log(enumStr); // "market"
COMMON_MATH
Math utilities for orderbook calculations.Calculating Spread, Bid, Ask, and Mark Price
import { COMMON_MATH } from '@drift-labs/common';
import { BN, PRICE_PRECISION } from '@drift-labs/sdk';
// Mock L2 orderbook
const l2 = {
bids: [
{ price: new BN(100).mul(PRICE_PRECISION), size: new BN(10) },
{ price: new BN(99).mul(PRICE_PRECISION), size: new BN(20) },
],
asks: [
{ price: new BN(101).mul(PRICE_PRECISION), size: new BN(15) },
{ price: new BN(102).mul(PRICE_PRECISION), size: new BN(25) },
],
};
const oraclePrice = new BN(100.5).mul(PRICE_PRECISION);
// Calculate all orderbook metrics
const {
bestBidPrice,
bestAskPrice,
markPrice,
spreadQuote,
spreadPct,
} = COMMON_MATH.calculateSpreadBidAskMark(l2, oraclePrice);
console.log({
bestBid: bestBidPrice?.div(PRICE_PRECISION).toString(),
bestAsk: bestAskPrice?.div(PRICE_PRECISION).toString(),
mark: markPrice?.div(PRICE_PRECISION).toString(),
spread: spreadQuote?.div(PRICE_PRECISION).toString(),
spreadPercent: spreadPct?.toString(),
});
Token Utilities
Utilities for working with SPL tokens.Getting Token Addresses
import {
getTokenAddress,
getTokenAddressForDepositAndWithdraw,
} from '@drift-labs/common';
import { PublicKey } from '@solana/web3.js';
import { WRAPPED_SOL_MINT } from '@drift-labs/sdk';
// Get associated token address
const tokenAddress = await getTokenAddress(
'EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v', // USDC mint
userPublicKey.toString()
);
console.log('USDC Token Account:', tokenAddress.toString());
// Get token address for deposits/withdrawals (handles SOL specially)
const depositAddress = await getTokenAddressForDepositAndWithdraw(
WRAPPED_SOL_MINT,
userPublicKey
);
// For SOL, returns the user's public key
// For other tokens, returns the associated token account
console.log('Deposit Address:', depositAddress.toString());
Creating Token Accounts
import { createTokenAccountIx, TOKEN_PROGRAM_ID } from '@drift-labs/common';
import { PublicKey } from '@solana/web3.js';
const owner = new PublicKey('...');
const mintAddress = new PublicKey('EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v'); // USDC
// Create instruction to create associated token account
const createAtaIx = await createTokenAccountIx(owner, mintAddress);
// Add to transaction
transaction.add(createAtaIx);
Getting Token Account Info
import { getTokenAccount } from '@drift-labs/common';
import { Connection } from '@solana/web3.js';
const connection = new Connection('https://api.mainnet-beta.solana.com');
const tokenAccount = await getTokenAccount(
connection,
'EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v', // USDC mint
userPublicKey.toString()
);
if (tokenAccount) {
console.log('Token Account:', tokenAccount.pubkey.toString());
console.log('Balance:', tokenAccount.account.data.parsed.info.tokenAmount.uiAmount);
}
Helper Classes
Counter
Simple counter utility:import { Counter } from '@drift-labs/common';
const counter = new Counter();
counter.increment();
counter.increment(5);
console.log(counter.get()); // 6
counter.reset();
console.log(counter.get()); // 0
Ref
Reference wrapper for mutable values:import { Ref } from '@drift-labs/common';
const ref = new Ref<number>(10);
console.log(ref.get()); // 10
ref.set(20);
console.log(ref.get()); // 20
MultiSwitch
Manage multiple boolean switches with a single aggregated state:import { MultiSwitch } from '@drift-labs/common';
// Base state is 'off'
const multiSwitch = new MultiSwitch('off');
// Turn on individual switches
multiSwitch.switchOn('feature1');
console.log(multiSwitch.isOn); // true
multiSwitch.switchOn('feature2');
console.log(multiSwitch.isOn); // true
// Turn off one switch
multiSwitch.switchOff('feature1');
console.log(multiSwitch.isOn); // true (feature2 still on)
// Turn off all switches
multiSwitch.switchOff('feature2');
console.log(multiSwitch.isOn); // false
Stopwatch
Simple timing utility:import { Stopwatch } from '@drift-labs/common';
const stopwatch = new Stopwatch();
stopwatch.start();
// ... do some work
const elapsedMs = stopwatch.getElapsedTime();
console.log(`Operation took ${elapsedMs}ms`);
stopwatch.stop();
Serialization Utilities
Utilities for serializing/deserializing objects with BN and PublicKey:Encoding Objects
import {
encodeStringifiableObject,
decodeStringifiableObject,
} from '@drift-labs/common';
import { BN, PublicKey } from '@drift-labs/sdk';
const obj = {
amount: new BN(1000000),
account: new PublicKey('...'),
name: 'Test',
};
// Encode for JSON stringification
const encoded = encodeStringifiableObject(obj);
console.log(JSON.stringify(encoded));
// { "_bgnm_amount": "1000000", "_pbky_account": "...", "name": "Test" }
// Decode back to original types
const decoded = decodeStringifiableObject(JSON.parse(JSON.stringify(encoded)));
console.log(decoded.amount instanceof BN); // true
console.log(decoded.account instanceof PublicKey); // true
Promise Utilities
Timed Promises
import { COMMON_UTILS } from '@drift-labs/common';
const fetchData = async () => {
// Simulate API call
await new Promise(resolve => setTimeout(resolve, 1000));
return { data: 'result' };
};
const { promiseResult, promiseTime } = await COMMON_UTILS.timedPromise(
fetchData()
);
console.log('Result:', promiseResult);
console.log('Took:', promiseTime, 'ms');
Sleep
import { sleep } from '@drift-labs/common';
// Wait for 1 second
await sleep(1000);
console.log('1 second has passed');
Best Practices
Working with BN
Working with BN
Always use BigNum utilities for precise calculations:
import { BigNum, BASE_PRECISION_EXP } from '@drift-labs/sdk';
// Use BigNum for precise math
const amount = BigNum.from(100, BASE_PRECISION_EXP);
const doubled = amount.mul(new BigNum(2));
Performance Optimization
Performance Optimization
Use chunking for batch operations:
// Instead of fetching all at once
const chunks = COMMON_UTILS.chunks(accounts, 100);
for (const chunk of chunks) {
await processChunk(chunk);
await sleep(100); // Rate limiting
}
Type Safety
Type Safety
Use TypeScript types for better safety:
import type { MarketId, UIEnv } from '@drift-labs/common';
const marketId: MarketId = {
marketIndex: 0,
isPerp: true,
key: 'perp-0',
};
Next Steps
Client Modules
Learn about client modules
API Reference
View complete API documentation