Claude-skill-registry drift
Complete Drift Protocol SDK for building perpetual futures, spot trading, and DeFi applications on Solana. Use when building trading bots, integrating Drift markets, managing positions, or working with vaults.
git clone https://github.com/majiayu000/claude-skill-registry
T=$(mktemp -d) && git clone --depth=1 https://github.com/majiayu000/claude-skill-registry "$T" && mkdir -p ~/.claude/skills && cp -r "$T/skills/data/drift" ~/.claude/skills/majiayu000-claude-skill-registry-drift && rm -rf "$T"
skills/data/drift/SKILL.mdDrift Protocol SDK Development Guide
A comprehensive guide for building Solana applications with the Drift Protocol SDK - the leading perpetual futures and spot trading protocol on Solana.
Overview
Drift Protocol is a decentralized exchange on Solana offering:
- Perpetual Futures: Up to 20x leverage on crypto assets
- Spot Trading: Borrow/lend and margin trading
- Cross-Collateral: Use multiple assets as collateral
- Vaults: Delegated trading pools
- Jupiter Integration: Direct spot swaps
Quick Start
Installation
npm install @drift-labs/sdk @solana/web3.js @coral-xyz/anchor
For Python:
pip install driftpy
Basic Setup (TypeScript)
import { Connection, Keypair } from '@solana/web3.js'; import { Wallet } from '@coral-xyz/anchor'; import { DriftClient, initialize, DriftEnv, BulkAccountLoader } from '@drift-labs/sdk'; // 1. Setup connection and wallet const connection = new Connection('https://api.mainnet-beta.solana.com'); const keypair = Keypair.fromSecretKey(/* your secret key */); const wallet = new Wallet(keypair); // 2. Initialize SDK const sdkConfig = initialize({ env: 'mainnet-beta' as DriftEnv }); // 3. Create DriftClient const driftClient = new DriftClient({ connection, wallet, env: 'mainnet-beta', accountSubscription: { type: 'polling', accountLoader: new BulkAccountLoader(connection, 'confirmed', 1000), }, }); // 4. Subscribe to updates await driftClient.subscribe(); // 5. Check if user account exists const user = driftClient.getUser(); const userExists = await user.exists(); if (!userExists) { // Initialize user account (costs ~0.035 SOL rent) await driftClient.initializeUserAccount(); }
Basic Setup (Python)
import asyncio from solana.rpc.async_api import AsyncClient from solders.keypair import Keypair from driftpy.drift_client import DriftClient from driftpy.account_subscription_config import AccountSubscriptionConfig from anchorpy import Wallet async def main(): connection = AsyncClient("https://api.mainnet-beta.solana.com") keypair = Keypair.from_bytes(secret_key_bytes) wallet = Wallet(keypair) drift_client = DriftClient( connection, wallet, "mainnet", account_subscription=AccountSubscriptionConfig("polling"), ) await drift_client.subscribe() user = drift_client.get_user() if not await user.exists(): await drift_client.initialize_user_account() asyncio.run(main())
Core Concepts
1. Precision and BN (BigNumber)
Drift uses BN.js for all numerical values due to token precision exceeding JavaScript float limits. All amounts are integers with designated precision levels.
Key Precision Constants:
| Constant | Value | Use Case |
|---|---|---|
| 10^6 | USDC amounts |
| 10^9 | Perp base asset amounts |
| 10^6 | Prices |
| 10^9 | Spot token balances |
| 10^9 | Funding rates |
| 10,000 | Margin ratios |
| 10^6 | AMM peg |
| 10^9 | AMM reserves |
Conversion Helper:
import { convertToNumber } from '@drift-labs/sdk'; // BN division returns floor - use helper for precise division const result = convertToNumber(new BN(10500), new BN(1000)); // = 10.5 // Converting amounts const perpAmount = driftClient.convertToPerpPrecision(100); // 100 base units const spotAmount = driftClient.convertToSpotPrecision(0, 100); // 100 USDC const price = driftClient.convertToPricePrecision(21.23); // $21.23
2. Market Types
Perpetual Markets (
MarketType.PERP):
- Derivatives with no expiry
- Positions tracked via
baseAssetAmount - Positive = Long, Negative = Short
Spot Markets (
MarketType.SPOT):
- Real token deposits/borrows
- Positions tracked via
scaledBalance
orSpotBalanceType.DEPOSITSpotBalanceType.BORROW
Common Market Indexes:
- USDC (quote asset)0
- SOL1- Market indexes vary - query
/getPerpMarketAccounts()getSpotMarketAccounts()
3. Order Types
import { OrderType, PositionDirection, OrderTriggerCondition } from '@drift-labs/sdk'; // Available order types OrderType.MARKET // Immediate execution OrderType.LIMIT // Price-specific orders OrderType.TRIGGER_MARKET // Stop-loss/take-profit market OrderType.TRIGGER_LIMIT // Stop-loss/take-profit limit OrderType.ORACLE // Oracle-based pricing // Position directions PositionDirection.LONG // Buy/bid PositionDirection.SHORT // Sell/ask // Trigger conditions (for stop orders) OrderTriggerCondition.ABOVE // Trigger when price > threshold OrderTriggerCondition.BELOW // Trigger when price < threshold
4. Post-Only Parameters
import { PostOnlyParams } from '@drift-labs/sdk'; PostOnlyParams.NONE // No enforcement (can be taker) PostOnlyParams.MUST_POST_ONLY // Fail if order would cross spread PostOnlyParams.TRY_POST_ONLY // Skip order if would cross spread PostOnlyParams.SLIDE // Adjust price to be post-only
Trading Operations
Placing Perpetual Orders
// Market Order await driftClient.placePerpOrder({ orderType: OrderType.MARKET, marketIndex: 0, // SOL-PERP direction: PositionDirection.LONG, baseAssetAmount: driftClient.convertToPerpPrecision(1), // 1 SOL }); // Limit Order await driftClient.placePerpOrder({ orderType: OrderType.LIMIT, marketIndex: 0, direction: PositionDirection.LONG, baseAssetAmount: driftClient.convertToPerpPrecision(1), price: driftClient.convertToPricePrecision(100), // $100 postOnly: PostOnlyParams.MUST_POST_ONLY, }); // Stop-Loss Order await driftClient.placePerpOrder({ orderType: OrderType.TRIGGER_MARKET, marketIndex: 0, direction: PositionDirection.SHORT, // Close long baseAssetAmount: driftClient.convertToPerpPrecision(1), triggerPrice: driftClient.convertToPricePrecision(90), triggerCondition: OrderTriggerCondition.BELOW, reduceOnly: true, }); // Take-Profit Order await driftClient.placePerpOrder({ orderType: OrderType.TRIGGER_LIMIT, marketIndex: 0, direction: PositionDirection.SHORT, // Close long baseAssetAmount: driftClient.convertToPerpPrecision(1), price: driftClient.convertToPricePrecision(120), triggerPrice: driftClient.convertToPricePrecision(120), triggerCondition: OrderTriggerCondition.ABOVE, reduceOnly: true, }); // Oracle Order (price relative to oracle) await driftClient.placePerpOrder({ orderType: OrderType.ORACLE, marketIndex: 0, direction: PositionDirection.LONG, baseAssetAmount: driftClient.convertToPerpPrecision(1), oraclePriceOffset: -100000, // $0.10 below oracle (PRICE_PRECISION) auctionDuration: 10, auctionStartPrice: new BN(-200000), // Start $0.20 below auctionEndPrice: new BN(-50000), // End $0.05 below });
Placing Spot Orders
// Spot Market Order await driftClient.placeSpotOrder({ orderType: OrderType.MARKET, marketIndex: 1, // SOL direction: PositionDirection.LONG, // Buy baseAssetAmount: driftClient.convertToSpotPrecision(1, 1), // 1 SOL }); // Spot Limit Order await driftClient.placeSpotOrder({ orderType: OrderType.LIMIT, marketIndex: 1, direction: PositionDirection.LONG, baseAssetAmount: driftClient.convertToSpotPrecision(1, 1), price: driftClient.convertToPricePrecision(100), });
Multiple Orders
// Place multiple orders atomically await driftClient.placeOrders([ { orderType: OrderType.LIMIT, marketType: MarketType.PERP, marketIndex: 0, direction: PositionDirection.LONG, baseAssetAmount: driftClient.convertToPerpPrecision(1), price: driftClient.convertToPricePrecision(99), }, { orderType: OrderType.LIMIT, marketType: MarketType.PERP, marketIndex: 0, direction: PositionDirection.SHORT, baseAssetAmount: driftClient.convertToPerpPrecision(1), price: driftClient.convertToPricePrecision(101), }, ]);
Order Management
// Cancel by order ID await driftClient.cancelOrder(orderId); // Cancel by user order ID await driftClient.cancelOrderByUserOrderId(userOrderId); // Cancel all orders for a market await driftClient.cancelOrders(MarketType.PERP, 0); // All SOL-PERP orders // Cancel all orders await driftClient.cancelOrders(); // Modify existing order await driftClient.modifyOrder(orderId, { price: driftClient.convertToPricePrecision(102), }); // Cancel and place atomically await driftClient.cancelAndPlaceOrders({ cancelOrderParams: { orderId: existingOrderId }, placeOrderParams: [{ orderType: OrderType.LIMIT, marketType: MarketType.PERP, marketIndex: 0, direction: PositionDirection.LONG, baseAssetAmount: driftClient.convertToPerpPrecision(1), price: driftClient.convertToPricePrecision(100), }], });
Get Orders
// Get specific order const order = driftClient.getOrder(orderId); // Get order by user ID const order = driftClient.getOrderByUserId(userOrderId); // Get all open orders const user = driftClient.getUser(); const openOrders = user.getOpenOrders();
Deposits and Withdrawals
Deposits
// Get associated token account const associatedTokenAccount = await driftClient.getAssociatedTokenAccount(0); // USDC // Deposit USDC const amount = driftClient.convertToSpotPrecision(0, 100); // 100 USDC await driftClient.deposit(amount, 0, associatedTokenAccount); // Deposit SOL const solAccount = await driftClient.getAssociatedTokenAccount(1); const solAmount = driftClient.convertToSpotPrecision(1, 1); // 1 SOL await driftClient.deposit(solAmount, 1, solAccount); // Initialize user and deposit in one transaction const [txSig, userPubkey] = await driftClient.initializeUserAccountAndDepositCollateral( driftClient.convertToSpotPrecision(0, 100), await driftClient.getAssociatedTokenAccount(0), 0, // market index 0, // sub account ID 'MyAccount', // name );
Withdrawals
const associatedTokenAccount = await driftClient.getAssociatedTokenAccount(0); const amount = driftClient.convertToSpotPrecision(0, 50); // 50 USDC // Withdraw (may create borrow if insufficient deposits) await driftClient.withdraw(amount, 0, associatedTokenAccount); // Withdraw with reduce-only (prevents creating borrow) await driftClient.withdraw(amount, 0, associatedTokenAccount, undefined, true);
Transfers Between Sub-Accounts
// Transfer deposits await driftClient.transferDeposit( driftClient.convertToSpotPrecision(0, 100), 0, // market index 0, // from sub-account 1, // to sub-account ); // Transfer perp positions await driftClient.transferPerpPosition({ fromSubAccountId: 0, toSubAccountId: 1, marketIndex: 0, amount: driftClient.convertToPerpPrecision(1), });
Position Management
Reading Positions
const user = driftClient.getUser(); // Perpetual Position const perpPosition = user.getPerpPosition(0); // SOL-PERP if (perpPosition) { const baseAmount = perpPosition.baseAssetAmount; const isLong = baseAmount.gt(new BN(0)); const isShort = baseAmount.lt(new BN(0)); console.log('Position size:', convertToNumber(baseAmount, BASE_PRECISION)); } // All active perp positions const activePerpPositions = user.getActivePerpPositions(); // Spot Position const spotPosition = user.getSpotPosition(0); // USDC const tokenAmount = user.getTokenAmount(0); const isDeposit = tokenAmount.gt(new BN(0)); const isBorrow = tokenAmount.lt(new BN(0)); // All active spot positions const activeSpotPositions = user.getActiveSpotPositions();
Collateral and Margin
const user = driftClient.getUser(); // Total collateral value const totalCollateral = user.getTotalCollateral(); // Free collateral (available for new positions) const freeCollateral = user.getFreeCollateral(); // Margin requirements const initialMargin = user.getInitialMarginRequirement(); const maintenanceMargin = user.getMaintenanceMarginRequirement(); // Current leverage const leverage = user.getLeverage(); // Account health (0-100, liquidation at 0) const health = user.getHealth(); // Max leverage for a market const maxLeverage = user.getMaxLeverageForPerp(0); // SOL-PERP // Buying power const buyingPower = user.getPerpBuyingPower(0);
PnL Calculations
const user = driftClient.getUser(); // Unrealized PnL (all positions) const unrealizedPnl = user.getUnrealizedPNL(); // Unrealized PnL with funding const unrealizedPnlWithFunding = user.getUnrealizedPNL(true); // PnL for specific market const marketPnl = user.getUnrealizedPNL(false, 0); // Unrealized funding PnL const fundingPnl = user.getUnrealizedFundingPNL(); // Settle PnL await driftClient.settlePNL( user.getUserAccountPublicKey(), user.getUserAccount(), 0 // market index );
Liquidation Price
const user = driftClient.getUser(); // Get liquidation price for perp position const liqPrice = user.liquidationPrice(0); // SOL-PERP // Check if can be liquidated const canBeLiquidated = user.canBeLiquidated();
Market Data
Market Accounts
// Perpetual market const perpMarket = driftClient.getPerpMarketAccount(0); console.log('Market index:', perpMarket.marketIndex); console.log('AMM base reserves:', perpMarket.amm.baseAssetReserve.toString()); // All perp markets const allPerpMarkets = driftClient.getPerpMarketAccounts(); // Spot market const spotMarket = driftClient.getSpotMarketAccount(0); console.log('Decimals:', spotMarket.decimals); // All spot markets const allSpotMarkets = driftClient.getSpotMarketAccounts();
Oracle Data
// Get oracle price for perp market const oracleData = driftClient.getOracleDataForPerpMarket(0); const price = oracleData.price; // BN in PRICE_PRECISION console.log('Oracle price:', convertToNumber(price, PRICE_PRECISION)); // Get oracle for spot market const spotOracleData = driftClient.getOracleDataForSpotMarket(1);
Calculate Prices from AMM
import { calculateBidAskPrice } from '@drift-labs/sdk'; const perpMarket = driftClient.getPerpMarketAccount(0); const oracleData = driftClient.getOracleDataForPerpMarket(0); const [bidPrice, askPrice] = calculateBidAskPrice( perpMarket.amm, oracleData );
Events
Event Subscriber
import { EventSubscriber } from '@drift-labs/sdk'; const eventSubscriber = new EventSubscriber(connection, driftClient.program, { eventTypes: [ 'DepositRecord', 'FundingPaymentRecord', 'LiquidationRecord', 'OrderRecord', 'OrderActionRecord', 'FundingRateRecord', 'SettlePnlRecord', 'LPRecord', 'InsuranceFundRecord', 'SpotInterestRecord', ], maxTx: 4096, maxEventsPerType: 4096, commitment: 'confirmed', logProviderConfig: { type: 'websocket' }, }); await eventSubscriber.subscribe(); // Listen for events eventSubscriber.eventEmitter.on('newEvent', (event) => { console.log('Event type:', event.eventType); console.log('Event data:', event); }); // Get events by type const depositEvents = eventSubscriber.getEventsReceived() .filter(e => e.eventType === 'DepositRecord'); // Unsubscribe await eventSubscriber.unsubscribe();
Jupiter Swaps
import { JupiterClient } from '@drift-labs/sdk'; // Initialize Jupiter client const jupiterClient = new JupiterClient({ connection }); // Get quote preview const quote = await jupiterClient.getQuote({ inputMint: /* USDC mint */, outputMint: /* SOL mint */, amount: driftClient.convertToSpotPrecision(0, 100), slippageBps: 50, }); // Execute swap through Drift const txSig = await driftClient.swap({ jupiterClient, inMarketIndex: 0, // USDC outMarketIndex: 1, // SOL amount: driftClient.convertToSpotPrecision(0, 100), slippageBps: 50, onlyDirectRoutes: false, });
Sub-Accounts
// Create new sub-account const [txSig, userPubkey] = await driftClient.initializeUserAccount( 1, // sub-account ID 'SubAccount1' // name ); // Switch active sub-account await driftClient.switchActiveUser(1); // Get user for specific sub-account const user = driftClient.getUser(1); // Delete sub-account (must have no positions) await driftClient.deleteUser(1); // Update delegate (allow another key to trade) await driftClient.updateUserDelegate(delegatePublicKey, 0);
Advanced: Swift Protocol (Orderless Trades)
Swift allows off-chain order signing without Solana transactions:
// Sign order message const orderMessage = { marketIndex: 0, marketType: MarketType.PERP, direction: PositionDirection.LONG, baseAssetAmount: driftClient.convertToPerpPrecision(1), price: driftClient.convertToPricePrecision(100), }; const signature = driftClient.signSignedMsgOrderParamsMessage(orderMessage); // Submit to Swift server await axios.post('https://swift.drift.trade/orders', { market_index: 0, message: signature.message, signature: signature.signature, taker_authority: wallet.publicKey.toString(), });
Advanced: Builder Codes (DBC)
For platforms routing trades through Drift to earn fees:
// Initialize as builder await driftClient.initializeRevenueShare(builderAuthority); // Initialize user's escrow await driftClient.initializeRevenueShareEscrow(userAuthority, numOrders); // Approve builder await driftClient.changeApprovedBuilder( builderAuthority, maxFeeTenthBps, // max fee in tenth basis points true // add (false to remove) );
Error Handling
try { await driftClient.placePerpOrder(orderParams); } catch (error) { if (error.message.includes('InsufficientCollateral')) { console.error('Not enough collateral for this trade'); } else if (error.message.includes('MaxLeverageExceeded')) { console.error('Would exceed maximum leverage'); } else if (error.message.includes('OrderWouldCrossMaker')) { console.error('Post-only order would cross spread'); } else { throw error; } }
Resources
Skill Structure
drift-protocol/ ├── SKILL.md # This file ├── resources/ │ ├── precision-constants.md # All precision constants │ ├── types-reference.md # TypeScript types and enums │ ├── drift-client-api.md # DriftClient method reference │ └── user-api.md # User class method reference ├── examples/ │ ├── basic-setup/ # Client initialization │ ├── orders/ # Order placement examples │ ├── deposits-withdrawals/ # Collateral management │ ├── positions/ # Position queries │ ├── jupiter-swaps/ # Swap integration │ ├── vaults/ # Vault management │ └── events/ # Event subscription ├── docs/ │ ├── vaults.md # Vault documentation │ ├── market-making.md # Market making guide │ └── troubleshooting.md # Common issues └── templates/ └── trading-bot-template.ts # Copy-paste starter