mcpField
D
drift

drift

github.com/sendaifun开发13179 次安装14 周前更新
代码仓库

关于 drift

drift 是一份使用 Drift Protocol SDK 构建 Solana 应用的开发指南,面向集成交易操作和市场数据的开发者。指南包含 TypeScript 和 Python 示例,并介绍协议概念。

主要功能

  1. 01提供 TypeScript 和 Python 配置示例
  2. 02执行永续合约与现货订单操作
  3. 03管理存款、提款和子账户
  4. 04查询持仓、保证金和盈亏
  5. 05访问市场与预言机数据
  6. 06使用 Jupiter 兑换和 Swift 订单签名

适用场景

  1. 01在 Solana 应用中实现永续或现货交易
  2. 02读取持仓、抵押品和清算价格
  3. 03查询市场账户和预言机价格
  4. 04构建使用子账户或 Jupiter 兑换的集成

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/sendaifun/skills --skill drift

安装后在 Claude Code 中输入/drift确认已加载。

包含的文件

除 SKILL.md 外,安装时一起下载的参考资料和脚本。

docs/
market-making.md
troubleshooting.md
vaults.md
examples/basic-setup/
README.md
examples/deposits-withdrawals/
README.md
examples/events/
README.md
examples/jupiter-swaps/
README.md
examples/orders/
README.md
examples/positions/
README.md
examples/vaults/
README.md
resources/
drift-client-api.md
precision-constants.md
types-reference.md
user-api.md
templates/
trading-bot-template.ts

详细介绍

Drift Protocol SDK 开发指南

使用 Drift Protocol SDK 构建 Solana 应用的综合指南。Drift Protocol 是 Solana 上领先的永续期货和现货交易协议。

概述

Drift Protocol 是 Solana 上的去中心化交易所,提供:

  • 永续期货:加密资产最高支持 20 倍杠杆
  • 现货交易:借贷和保证金交易
  • 交叉抵押:使用多种资产作为抵押品
  • 金库:委托交易池
  • Jupiter 集成:直接进行现货兑换

快速开始

安装
npm install @drift-labs/sdk @solana/web3.js @coral-xyz/anchor

Python 安装方式:

pip install driftpy
基本设置(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();
}
基本设置(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())

核心概念

1. 精度和 BN(BigNumber)

由于代币精度超出 JavaScript 浮点数的表示范围,Drift 使用 BN.js 表示所有数值。所有金额都是具有指定精度的整数。

主要精度常量:

常量值用途
QUOTE_PRECISION10^6USDC 金额
BASE_PRECISION10^9永续市场基础资产金额
PRICE_PRECISION10^6价格
SPOT_MARKET_BALANCE_PRECISION10^9现货代币余额
FUNDING_RATE_PRECISION10^9资金费率
MARGIN_PRECISION10,000保证金比率
PEG_PRECISION10^6AMM 锚定价格
AMM_RESERVE_PRECISION10^9AMM 储备金

转换辅助函数:

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. 市场类型

永续市场(MarketType.PERP):

  • 无到期日的衍生品
  • 通过 baseAssetAmount 跟踪仓位
  • 正数 = 多头,负数 = 空头

现货市场(MarketType.SPOT):

  • 实际代币存入/借入
  • 通过 scaledBalance 跟踪仓位
  • SpotBalanceType.DEPOSIT 或 SpotBalanceType.BORROW

常见市场索引:

  • 0 - USDC(报价资产)
  • 1 - SOL
  • 市场索引各不相同,可查询 getPerpMarketAccounts() / getSpotMarketAccounts()
3. 订单类型
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. 仅挂单参数
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

交易操作

下达永续订单
// 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
});
下达现货订单
// 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),
});
多个订单
// 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),
  },
]);
订单管理
// 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 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();

存款和取款

存款
// 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
);
取款
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);
子账户之间的转账
// 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),
});

仓位管理

读取仓位
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();
抵押品和保证金
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);
盈亏计算
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
);
清算价格
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();

市场数据

市场账户
// 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();
预言机数据
// 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);
根据 AMM 计算价格
import { calculateBidAskPrice } from '@drift-labs/sdk';

const perpMarket = driftClient.getPerpMarketAccount(0);
const oracleData = driftClient.getOracleDataForPerpMarket(0);

const [bidPrice, askPrice] = calculateBidAskPrice(
  perpMarket.amm,
  oracleData
);

事件

事件订阅器
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 兑换

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,
});

子账户

// 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);

高级:Swift Protocol(无订单交易)

Swift 支持在链下签署订单,无需 Solana 交易:

// 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(),
});

高级:构建器代码(DBC)

适用于通过 Drift 路由交易以赚取费用的平台:

// 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)
);

错误处理

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;
  }
}

资源

技能结构

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

评论

支持 Markdown