Skip to main content

Overview

Drift Protocol v2 uses BN.js (BigNum) to represent numerical values with high precision. This is essential because Solana tokens use levels of precision that exceed JavaScript’s standard floating-point number capabilities.
All numbers in BN are represented as integers. The precision value indicates how to convert them back to decimal numbers.

How Precision Works

A BigNum value combined with a precision represents a decimal number:
// Example:
// BigNum: 10,500,000 with precision 10^6 = 10.5
// Because: 10,500,000 / 10^6 = 10.5

Standard Precision Constants

Drift uses consistent precision values across the protocol:
ConstantValueExponentUsage
QUOTE_PRECISION1,000,00010^6Quote asset amounts (USDC)
PRICE_PRECISION1,000,00010^6Asset prices
PEG_PRECISION1,000,00010^6AMM peg multiplier
BASE_PRECISION1,000,000,00010^9Base asset amounts
AMM_RESERVE_PRECISION1,000,000,00010^9AMM reserve values
FUNDING_RATE_BUFFER_PRECISION1,00010^3Funding rate buffer
FUNDING_RATE_PRECISION1,000,000,00010^9Full funding rate precision
PERCENTAGE_PRECISION1,000,00010^6Percentage values
MARGIN_PRECISION10,00010^4Margin ratios
BID_ASK_SPREAD_PRECISION1,000,00010^6Bid-ask spreads

Precision Relationships

// From numericConstants.ts
const AMM_TO_QUOTE_PRECISION_RATIO = 
  AMM_RESERVE_PRECISION.div(QUOTE_PRECISION); // 10^3

const PRICE_DIV_PEG = 
  PRICE_PRECISION.div(PEG_PRECISION); // 10^0 = 1

const AMM_TIMES_PEG_TO_QUOTE_PRECISION_RATIO = 
  AMM_RESERVE_PRECISION.mul(PEG_PRECISION).div(QUOTE_PRECISION); // 10^9

The BigNum Class

Drift provides a BigNum class that wraps BN with precision-aware operations:

Creating BigNum Values

import { BigNum } from '@drift-labs/sdk';
import { BN } from '@coral-xyz/anchor';

// Create from BN and precision
const price = BigNum.from(new BN(10500000), new BN(6)); // 10.5

// Create from printed string
const amount = BigNum.fromPrint('10.5', new BN(6)); // 10,500,000 with precision 10^6

Arithmetic Operations

const a = BigNum.from(new BN(10000000), new BN(6)); // 10.0
const b = BigNum.from(new BN(5000000), new BN(6));  // 5.0

// Addition/Subtraction (requires same precision)
const sum = a.add(b);  // 15.0
const diff = a.sub(b); // 5.0

// Multiplication (precisions add)
const product = a.mul(b); // precision = 10^12

// Scalar multiplication (maintains precision)
const scaled = a.scalarMul(b); // 50.0, precision = 10^6

// Division
const quotient = a.div(b); // 2.0

Shifting Precision

const value = BigNum.from(new BN(1000000), new BN(6)); // 1.0

// Shift up (multiply by 10^3)
const shifted = value.shift(new BN(3)); // 1000.0, precision 10^9

// Shift to specific precision
const converted = value.shiftTo(new BN(9)); // Same as shift(3)

Display & Formatting

const amount = BigNum.from(new BN(1234567890), new BN(6)); // 1234.56789

// Print full precision
amount.print();           // "1234.56789"

// Print without trailing zeros
amount.printShort();      // "1234.56789"

// Fixed decimal places
amount.toFixed(2);        // "1234.56"

// Significant figures
amount.toPrecision(4);    // "1234"

// Pretty print with thousand separators
amount.prettyPrint();     // "1,234.56789"

// Format as dollar amount
amount.toNotional();      // "$1,234.56"

// Millified (K, M, B, T)
amount.toMillified(3);    // "1.23K"

Division Precision Handling

BN division returns the floor value by default. For exact division, you must handle the modulus.
import { BN } from '@coral-xyz/anchor';
import { convertToNumber } from '@drift-labs/sdk';

// INCORRECT - Gets floor value only
const bad = new BN(10500).div(new BN(1000)).toNumber(); 
// Result: 10

// CORRECT - Manual handling
const good = new BN(10500).div(new BN(1000)).toNumber() + 
             new BN(10500).mod(new BN(1000)).toNumber() / 1000;
// Result: 10.5

// BEST - Use helper function
const best = convertToNumber(new BN(10500), new BN(1000));
// Result: 10.5

convertToNumber Helper

The SDK provides a convertToNumber function for safe BN to number conversion:
import { convertToNumber, PRICE_PRECISION, QUOTE_PRECISION } from '@drift-labs/sdk';

// Convert price from BN to number
const priceBN = new BN(10500000); // 10.5 with PRICE_PRECISION
const priceNum = convertToNumber(priceBN, PRICE_PRECISION);
// Result: 10.5

// Convert quote amount
const quoteBN = new BN(1000000000); // 1000 with QUOTE_PRECISION  
const quoteNum = convertToNumber(quoteBN, QUOTE_PRECISION);
// Result: 1000.0

Implementation

export const convertToNumber = (
  bigNumber: BN,
  precision: BN = PRICE_PRECISION
) => {
  if (!bigNumber) return 0;
  return (
    bigNumber.div(precision).toNumber() +
    bigNumber.mod(precision).toNumber() / precision.toNumber()
  );
};

convertToBN Helper

Convert JavaScript numbers to BN with proper precision:
import { convertToBN, QUOTE_PRECISION } from '@drift-labs/sdk';

const amount = 10.5;
const amountBN = convertToBN(amount, QUOTE_PRECISION);
// Result: BN(10500000)

Implementation

export function convertToBN(value: number, precision: BN): BN {
  const wholePart = Math.floor(value);
  const decimalPart = Math.round((value - wholePart) * precision.toNumber());
  return new BN(wholePart).mul(precision).add(new BN(decimalPart));
}

Common Patterns

Working with Prices

import { PRICE_PRECISION, convertToNumber } from '@drift-labs/sdk';

// Oracle price is in PRICE_PRECISION
const oraclePrice = driftClient.getOracleDataForPerpMarket(0).price;
const priceDecimal = convertToNumber(oraclePrice, PRICE_PRECISION);
console.log(`SOL-PERP price: $${priceDecimal}`);

Working with Position Sizes

import { BASE_PRECISION, QUOTE_PRECISION } from '@drift-labs/sdk';

// Position size in BASE_PRECISION (10^9)
const baseSize = new BN(1).mul(BASE_PRECISION); // 1 SOL

// Convert to decimal
const sizeDecimal = convertToNumber(baseSize, BASE_PRECISION);
// Result: 1.0

Calculating Notional Value

import { 
  BASE_PRECISION, 
  PRICE_PRECISION, 
  QUOTE_PRECISION,
  convertToNumber 
} from '@drift-labs/sdk';

const baseAmount = new BN(5).mul(BASE_PRECISION); // 5 SOL
const price = new BN(100).mul(PRICE_PRECISION);   // $100

// notional = baseAmount * price / BASE_PRECISION
const notionalBN = baseAmount.mul(price).div(BASE_PRECISION);
const notionalUSD = convertToNumber(notionalBN, PRICE_PRECISION);
// Result: $500

Best Practices

  1. Always use BN for calculations - Never convert to numbers until the final display step
  2. Match precisions - Ensure values have the same precision before adding/subtracting
  3. Use helper functions - Prefer convertToNumber() over manual division
  4. Be careful with multiplication - Precision accumulates, so adjust accordingly
  5. Handle division carefully - Remember BN division truncates by default

Examples from SDK

Trading Example

import { 
  DriftClient, 
  BASE_PRECISION, 
  PRICE_PRECISION,
  convertToNumber,
  calculateBidAskPrice 
} from '@drift-labs/sdk';

// Get market data
const marketIndex = 0; // SOL-PERP
const market = driftClient.getPerpMarketAccount(marketIndex);
const oracleData = driftClient.getOracleDataForPerpMarket(marketIndex);

// Get bid/ask prices (returns BN with PRICE_PRECISION)
const [bid, ask] = calculateBidAskPrice(market.amm, oracleData);

const bidPrice = convertToNumber(bid, PRICE_PRECISION);
const askPrice = convertToNumber(ask, PRICE_PRECISION);

console.log(`Bid: $${bidPrice}, Ask: $${askPrice}`);

// Place order for 1 SOL
const orderSize = new BN(1).mul(BASE_PRECISION);

Build docs developers (and LLMs) love