drift
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseDrift Protocol SDK Development Guide
Drift Protocol SDK 开发指南
A comprehensive guide for building Solana applications with the Drift Protocol SDK - the leading perpetual futures and spot trading protocol on Solana.
这是一份使用Drift Protocol SDK构建Solana应用的综合指南——Drift Protocol是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
Drift Protocol是Solana上的去中心化交易所,提供以下功能:
- 永续期货(Perpetual Futures):加密资产最高20倍杠杆
- 现货交易(Spot Trading):借贷与保证金交易
- 跨抵押(Cross-Collateral):支持多资产作为抵押品
- 金库(Vaults):委托交易池
- Jupiter集成:直接现货兑换
Quick Start
快速开始
Installation
安装
bash
npm install @drift-labs/sdk @solana/web3.js @coral-xyz/anchorFor Python:
bash
pip install driftpybash
npm install @drift-labs/sdk @solana/web3.js @coral-xyz/anchorPython版本安装:
bash
pip install driftpyBasic Setup (TypeScript)
基础配置(TypeScript)
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();
}typescript
import { Connection, Keypair } from '@solana/web3.js';
import { Wallet } from '@coral-xyz/anchor';
import {
DriftClient,
initialize,
DriftEnv,
BulkAccountLoader
} from '@drift-labs/sdk';
// 1. 配置连接与钱包
const connection = new Connection('https://api.mainnet-beta.solana.com');
const keypair = Keypair.fromSecretKey(/* 你的密钥 */);
const wallet = new Wallet(keypair);
// 2. 初始化SDK
const sdkConfig = initialize({ env: 'mainnet-beta' as DriftEnv });
// 3. 创建DriftClient实例
const driftClient = new DriftClient({
connection,
wallet,
env: 'mainnet-beta',
accountSubscription: {
type: 'polling',
accountLoader: new BulkAccountLoader(connection, 'confirmed', 1000),
},
});
// 4. 订阅更新
await driftClient.subscribe();
// 5. 检查用户账户是否存在
const user = driftClient.getUser();
const userExists = await user.exists();
if (!userExists) {
// 初始化用户账户(约需0.035 SOL租金)
await driftClient.initializeUserAccount();
}Basic Setup (Python)
基础配置(Python)
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())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)
1. 精度与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:
typescript
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由于代币精度超出JavaScript浮点数限制,Drift使用BN.js处理所有数值。所有金额均为带指定精度级别的整数。
关键精度常量:
| 常量 | 数值 | 适用场景 |
|---|---|---|
| 10^6 | USDC金额 |
| 10^9 | 永续合约基础资产金额 |
| 10^6 | 价格 |
| 10^9 | 现货代币余额 |
| 10^9 | 资金费率 |
| 10,000 | 保证金比率 |
| 10^6 | AMM挂钩价 |
| 10^9 | AMM储备金 |
转换工具函数:
typescript
import { convertToNumber } from '@drift-labs/sdk';
// BN除法返回向下取整结果 - 使用工具函数实现精确除法
const result = convertToNumber(new BN(10500), new BN(1000)); // = 10.5
// 金额转换
const perpAmount = driftClient.convertToPerpPrecision(100); // 100个基础单位
const spotAmount = driftClient.convertToSpotPrecision(0, 100); // 100 USDC
const price = driftClient.convertToPricePrecision(21.23); // $21.232. Market Types
2. 市场类型
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 - or
SpotBalanceType.DEPOSITSpotBalanceType.BORROW
Common Market Indexes:
- - USDC (quote asset)
0 - - SOL
1 - Market indexes vary - query /
getPerpMarketAccounts()getSpotMarketAccounts()
永续合约市场 ():
MarketType.PERP- 无到期日的衍生品
- 仓位通过追踪
baseAssetAmount - 正数=多头,负数=空头
现货市场 ():
MarketType.SPOT- 真实代币存入/借出
- 仓位通过追踪
scaledBalance - 类型为(存入)或
SpotBalanceType.DEPOSIT(借出)SpotBalanceType.BORROW
常见市场索引:
- - USDC(计价资产)
0 - - SOL
1 - 市场索引可能变动 - 调用/
getPerpMarketAccounts()查询getSpotMarketAccounts()
3. Order Types
3. 订单类型
typescript
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 < thresholdtypescript
import { OrderType, PositionDirection, OrderTriggerCondition } from '@drift-labs/sdk';
// 可用订单类型
OrderType.MARKET // 立即成交
OrderType.LIMIT // 指定价格订单
OrderType.TRIGGER_MARKET // 止损/止盈市价单
OrderType.TRIGGER_LIMIT // 止损/止盈限价单
OrderType.ORACLE // 基于预言机定价的订单
// 仓位方向
PositionDirection.LONG // 买入/做多
PositionDirection.SHORT // 卖出/做空
// 触发条件(止损单适用)
OrderTriggerCondition.ABOVE // 价格高于阈值时触发
OrderTriggerCondition.BELOW // 价格低于阈值时触发4. Post-Only Parameters
4. 只做市商参数
typescript
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-onlytypescript
import { PostOnlyParams } from '@drift-labs/sdk';
PostOnlyParams.NONE // 无限制(可作为吃单者)
PostOnlyParams.MUST_POST_ONLY // 若订单会穿透买卖价差则失败
PostOnlyParams.TRY_POST_ONLY // 若订单会穿透买卖价差则跳过
PostOnlyParams.SLIDE // 调整价格以满足只做市商要求Trading Operations
交易操作
Placing Perpetual Orders
下单永续合约
typescript
// 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
});typescript
// 市价单
await driftClient.placePerpOrder({
orderType: OrderType.MARKET,
marketIndex: 0, // SOL永续合约
direction: PositionDirection.LONG,
baseAssetAmount: driftClient.convertToPerpPrecision(1), // 1 SOL
});
// 限价单
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,
});
// 止损单
await driftClient.placePerpOrder({
orderType: OrderType.TRIGGER_MARKET,
marketIndex: 0,
direction: PositionDirection.SHORT, // 平仓多头
baseAssetAmount: driftClient.convertToPerpPrecision(1),
triggerPrice: driftClient.convertToPricePrecision(90),
triggerCondition: OrderTriggerCondition.BELOW,
reduceOnly: true,
});
// 止盈单
await driftClient.placePerpOrder({
orderType: OrderType.TRIGGER_LIMIT,
marketIndex: 0,
direction: PositionDirection.SHORT, // 平仓多头
baseAssetAmount: driftClient.convertToPerpPrecision(1),
price: driftClient.convertToPricePrecision(120),
triggerPrice: driftClient.convertToPricePrecision(120),
triggerCondition: OrderTriggerCondition.ABOVE,
reduceOnly: true,
});
// 预言机订单(基于预言机价格)
await driftClient.placePerpOrder({
orderType: OrderType.ORACLE,
marketIndex: 0,
direction: PositionDirection.LONG,
baseAssetAmount: driftClient.convertToPerpPrecision(1),
oraclePriceOffset: -100000, // 比预言机价格低$0.10(以PRICE_PRECISION为单位)
auctionDuration: 10,
auctionStartPrice: new BN(-200000), // 起始价低于预言机$0.20
auctionEndPrice: new BN(-50000), // 结束价低于预言机$0.05
});Placing Spot Orders
下单现货
typescript
// 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),
});typescript
// 现货市价单
await driftClient.placeSpotOrder({
orderType: OrderType.MARKET,
marketIndex: 1, // SOL
direction: PositionDirection.LONG, // 买入
baseAssetAmount: driftClient.convertToSpotPrecision(1, 1), // 1 SOL
});
// 现货限价单
await driftClient.placeSpotOrder({
orderType: OrderType.LIMIT,
marketIndex: 1,
direction: PositionDirection.LONG,
baseAssetAmount: driftClient.convertToSpotPrecision(1, 1),
price: driftClient.convertToPricePrecision(100),
});Multiple Orders
批量下单
typescript
// 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),
},
]);typescript
// 原子化批量下单
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
订单管理
typescript
// 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),
}],
});typescript
// 按订单ID取消
await driftClient.cancelOrder(orderId);
// 按用户订单ID取消
await driftClient.cancelOrderByUserOrderId(userOrderId);
// 取消某市场的所有订单
await driftClient.cancelOrders(MarketType.PERP, 0); // 所有SOL永续合约订单
// 取消所有订单
await driftClient.cancelOrders();
// 修改现有订单
await driftClient.modifyOrder(orderId, {
price: driftClient.convertToPricePrecision(102),
});
// 原子化取消并下单
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
查询订单
typescript
// 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();typescript
// 查询指定订单
const order = driftClient.getOrder(orderId);
// 按用户ID查询订单
const order = driftClient.getOrderByUserId(userOrderId);
// 查询所有未成交订单
const user = driftClient.getUser();
const openOrders = user.getOpenOrders();Deposits and Withdrawals
存入与提取
Deposits
存入资产
typescript
// 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
);typescript
// 获取关联代币账户
const associatedTokenAccount = await driftClient.getAssociatedTokenAccount(0); // USDC
// 存入USDC
const amount = driftClient.convertToSpotPrecision(0, 100); // 100 USDC
await driftClient.deposit(amount, 0, associatedTokenAccount);
// 存入SOL
const solAccount = await driftClient.getAssociatedTokenAccount(1);
const solAmount = driftClient.convertToSpotPrecision(1, 1); // 1 SOL
await driftClient.deposit(solAmount, 1, solAccount);
// 一次性完成用户初始化与资产存入
const [txSig, userPubkey] = await driftClient.initializeUserAccountAndDepositCollateral(
driftClient.convertToSpotPrecision(0, 100),
await driftClient.getAssociatedTokenAccount(0),
0, // 市场索引
0, // 子账户ID
'MyAccount', // 账户名称
);Withdrawals
提取资产
typescript
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);typescript
const associatedTokenAccount = await driftClient.getAssociatedTokenAccount(0);
const amount = driftClient.convertToSpotPrecision(0, 50); // 50 USDC
// 提取资产(若存入不足可能产生借贷)
await driftClient.withdraw(amount, 0, associatedTokenAccount);
// 仅平仓提取(禁止产生借贷)
await driftClient.withdraw(amount, 0, associatedTokenAccount, undefined, true);Transfers Between Sub-Accounts
子账户间转账
typescript
// 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),
});typescript
// 转账存入资产
await driftClient.transferDeposit(
driftClient.convertToSpotPrecision(0, 100),
0, // 市场索引
0, // 转出子账户
1, // 转入子账户
);
// 转账永续合约仓位
await driftClient.transferPerpPosition({
fromSubAccountId: 0,
toSubAccountId: 1,
marketIndex: 0,
amount: driftClient.convertToPerpPrecision(1),
});Position Management
仓位管理
Reading Positions
查询仓位
typescript
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();typescript
const user = driftClient.getUser();
// 永续合约仓位
const perpPosition = user.getPerpPosition(0); // SOL永续合约
if (perpPosition) {
const baseAmount = perpPosition.baseAssetAmount;
const isLong = baseAmount.gt(new BN(0));
const isShort = baseAmount.lt(new BN(0));
console.log('仓位大小:', convertToNumber(baseAmount, BASE_PRECISION));
}
// 所有活跃永续合约仓位
const activePerpPositions = user.getActivePerpPositions();
// 现货仓位
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));
// 所有活跃现货仓位
const activeSpotPositions = user.getActiveSpotPositions();Collateral and Margin
抵押品与保证金
typescript
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);typescript
const user = driftClient.getUser();
// 总抵押品价值
const totalCollateral = user.getTotalCollateral();
// 可用抵押品(可用于开新仓)
const freeCollateral = user.getFreeCollateral();
// 保证金要求
const initialMargin = user.getInitialMarginRequirement();
const maintenanceMargin = user.getMaintenanceMarginRequirement();
// 当前杠杆
const leverage = user.getLeverage();
// 账户健康度(0-100,0时触发清算)
const health = user.getHealth();
// 某市场的最大杠杆
const maxLeverage = user.getMaxLeverageForPerp(0); // SOL永续合约
// 购买力
const buyingPower = user.getPerpBuyingPower(0);PnL Calculations
盈亏计算
typescript
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
);typescript
const user = driftClient.getUser();
// 未实现盈亏(所有仓位)
const unrealizedPnl = user.getUnrealizedPNL();
// 包含资金费的未实现盈亏
const unrealizedPnlWithFunding = user.getUnrealizedPNL(true);
// 某市场的未实现盈亏
const marketPnl = user.getUnrealizedPNL(false, 0);
// 未实现资金费盈亏
const fundingPnl = user.getUnrealizedFundingPNL();
// 结算盈亏
await driftClient.settlePNL(
user.getUserAccountPublicKey(),
user.getUserAccount(),
0 // 市场索引
);Liquidation Price
清算价格
typescript
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();typescript
const user = driftClient.getUser();
// 获取永续合约仓位的清算价格
const liqPrice = user.liquidationPrice(0); // SOL永续合约
// 检查是否可被清算
const canBeLiquidated = user.canBeLiquidated();Market Data
市场数据
Market Accounts
市场账户
typescript
// 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();typescript
// 永续合约市场
const perpMarket = driftClient.getPerpMarketAccount(0);
console.log('市场索引:', perpMarket.marketIndex);
console.log('AMM基础资产储备:', perpMarket.amm.baseAssetReserve.toString());
// 所有永续合约市场
const allPerpMarkets = driftClient.getPerpMarketAccounts();
// 现货市场
const spotMarket = driftClient.getSpotMarketAccount(0);
console.log('小数位数:', spotMarket.decimals);
// 所有现货市场
const allSpotMarkets = driftClient.getSpotMarketAccounts();Oracle Data
预言机数据
typescript
// 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);typescript
// 获取永续合约市场的预言机价格
const oracleData = driftClient.getOracleDataForPerpMarket(0);
const price = oracleData.price; // 以PRICE_PRECISION为单位的BN值
console.log('预言机价格:', convertToNumber(price, PRICE_PRECISION));
// 获取现货市场的预言机数据
const spotOracleData = driftClient.getOracleDataForSpotMarket(1);Calculate Prices from AMM
通过AMM计算价格
typescript
import { calculateBidAskPrice } from '@drift-labs/sdk';
const perpMarket = driftClient.getPerpMarketAccount(0);
const oracleData = driftClient.getOracleDataForPerpMarket(0);
const [bidPrice, askPrice] = calculateBidAskPrice(
perpMarket.amm,
oracleData
);typescript
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
事件订阅器
typescript
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();typescript
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();
// 监听事件
eventSubscriber.eventEmitter.on('newEvent', (event) => {
console.log('事件类型:', event.eventType);
console.log('事件数据:', event);
});
// 按类型查询事件
const depositEvents = eventSubscriber.getEventsReceived()
.filter(e => e.eventType === 'DepositRecord');
// 取消订阅
await eventSubscriber.unsubscribe();Jupiter Swaps
Jupiter兑换
typescript
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,
});typescript
import { JupiterClient } from '@drift-labs/sdk';
// 初始化Jupiter客户端
const jupiterClient = new JupiterClient({ connection });
// 获取报价预览
const quote = await jupiterClient.getQuote({
inputMint: /* USDC铸币地址 */,
outputMint: /* SOL铸币地址 */,
amount: driftClient.convertToSpotPrecision(0, 100),
slippageBps: 50,
});
// 通过Drift执行兑换
const txSig = await driftClient.swap({
jupiterClient,
inMarketIndex: 0, // USDC
outMarketIndex: 1, // SOL
amount: driftClient.convertToSpotPrecision(0, 100),
slippageBps: 50,
onlyDirectRoutes: false,
});Sub-Accounts
子账户
typescript
// 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);typescript
// 创建新子账户
const [txSig, userPubkey] = await driftClient.initializeUserAccount(
1, // 子账户ID
'SubAccount1' // 账户名称
);
// 切换活跃子账户
await driftClient.switchActiveUser(1);
// 获取指定子账户的用户实例
const user = driftClient.getUser(1);
// 删除子账户(需无任何仓位)
await driftClient.deleteUser(1);
// 更新委托账户(允许其他密钥进行交易)
await driftClient.updateUserDelegate(delegatePublicKey, 0);Advanced: Swift Protocol (Orderless Trades)
进阶:Swift协议(无订单交易)
Swift allows off-chain order signing without Solana transactions:
typescript
// 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(),
});Swift协议支持链下签名订单,无需Solana交易:
typescript
// 签名订单消息
const orderMessage = {
marketIndex: 0,
marketType: MarketType.PERP,
direction: PositionDirection.LONG,
baseAssetAmount: driftClient.convertToPerpPrecision(1),
price: driftClient.convertToPricePrecision(100),
};
const signature = driftClient.signSignedMsgOrderParamsMessage(orderMessage);
// 提交至Swift服务器
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)
进阶:Builder Codes(DBC)
For platforms routing trades through Drift to earn fees:
typescript
// 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)
);适用于通过Drift路由交易以赚取手续费的平台:
typescript
// 初始化为Builder
await driftClient.initializeRevenueShare(builderAuthority);
// 初始化用户托管账户
await driftClient.initializeRevenueShareEscrow(userAuthority, numOrders);
// 授权Builder
await driftClient.changeApprovedBuilder(
builderAuthority,
maxFeeTenthBps, // 最高手续费(万分之零点一)
true // 添加(false为移除)
);Error Handling
错误处理
typescript
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;
}
}typescript
try {
await driftClient.placePerpOrder(orderParams);
} catch (error) {
if (error.message.includes('InsufficientCollateral')) {
console.error('抵押品不足,无法进行此交易');
} else if (error.message.includes('MaxLeverageExceeded')) {
console.error('超出最大杠杆限制');
} else if (error.message.includes('OrderWouldCrossMaker')) {
console.error('只做市商订单会穿透买卖价差');
} 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 starterdrift-protocol/
├── SKILL.md # 本文档
├── resources/
│ ├── precision-constants.md # 所有精度常量
│ ├── types-reference.md # TypeScript类型与枚举
│ ├── drift-client-api.md # DriftClient方法参考
│ └── user-api.md # User类方法参考
├── examples/
│ ├── basic-setup/ # 客户端初始化示例
│ ├── orders/ # 下单示例
│ ├── deposits-withdrawals/ # 抵押品管理示例
│ ├── positions/ # 仓位查询示例
│ ├── jupiter-swaps/ # 兑换集成示例
│ ├── vaults/ # 金库管理示例
│ └── events/ # 事件订阅示例
├── docs/
│ ├── vaults.md # 金库文档
│ ├── market-making.md # 做市指南
│ └── troubleshooting.md # 常见问题排查
└── templates/
└── trading-bot-template.ts # 可直接复用的交易机器人模板